From 623485f80d5243893dc2d491839e730aecb3a24d Mon Sep 17 00:00:00 2001 From: Robbie Date: Wed, 25 Oct 2023 11:48:16 +0100 Subject: [PATCH 01/21] feat(web-analytics): Add alpha notice (#18176) * Add alpha notice * Hide support options if not on cloud * Add link to github issue --- .../lib/components/Support/supportLogic.ts | 2 ++ .../src/scenes/web-analytics/WebDashboard.tsx | 35 ++++++++++++++++++- 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/frontend/src/lib/components/Support/supportLogic.ts b/frontend/src/lib/components/Support/supportLogic.ts index ea9b146e7d777..4a9016acce670 100644 --- a/frontend/src/lib/components/Support/supportLogic.ts +++ b/frontend/src/lib/components/Support/supportLogic.ts @@ -57,6 +57,7 @@ export const TARGET_AREA_TO_NAME = { session_replay: 'Session Replay (Recordings)', toolbar: 'Toolbar & heatmaps', surveys: 'Surveys', + web_analytics: 'Web Analytics', } export const SUPPORT_KIND_TO_SUBJECT = { @@ -85,6 +86,7 @@ export const URL_PATH_TO_TARGET_AREA: Record = toolbar: 'session_replay', warehouse: 'data_warehouse', surveys: 'surveys', + web: 'web_analytics', } export function getURLPathToTargetArea(pathname: string): SupportTicketTargetArea | null { diff --git a/frontend/src/scenes/web-analytics/WebDashboard.tsx b/frontend/src/scenes/web-analytics/WebDashboard.tsx index fb0c247e79e55..1d07f69b5d61e 100644 --- a/frontend/src/scenes/web-analytics/WebDashboard.tsx +++ b/frontend/src/scenes/web-analytics/WebDashboard.tsx @@ -9,6 +9,10 @@ import { QueryContext, QueryContextColumnComponent, QueryContextColumnTitleCompo import { useCallback } from 'react' import { UnexpectedNeverError } from 'lib/utils' import { DateFilter } from 'lib/components/DateFilter/DateFilter' +import { LemonBanner } from 'lib/lemon-ui/LemonBanner' +import { supportLogic } from 'lib/components/Support/supportLogic' +import { IconBugReport, IconFeedback, IconGithub } from 'lib/lemon-ui/icons' +import { preflightLogic } from 'scenes/PreflightCheck/preflightLogic' const PercentageCell: QueryContextColumnComponent = ({ value }) => { if (typeof value === 'number') { @@ -209,9 +213,38 @@ const Tiles = (): JSX.Element => { ) } +export const Notice = (): JSX.Element => { + const { openSupportForm } = useActions(supportLogic) + const { preflight } = useValues(preflightLogic) + + const showSupportOptions = preflight?.cloud + + return ( + +

PostHog Web Analytics is in closed Alpha. Thanks for taking part! We'd love to hear what you think.

+ {showSupportOptions ? ( +

+ openSupportForm('bug')}> + Report a bug + {' '} + -{' '} + openSupportForm('feedback')}> + Give feedback + {' '} + -{' '} + + View GitHub issue + +

+ ) : null} +
+ ) +} + export const WebAnalyticsDashboard = (): JSX.Element => { return ( -
+
+
From 46c0750c76e5c7c5c418b1b186f8714000afbece Mon Sep 17 00:00:00 2001 From: Robbie Date: Wed, 25 Oct 2023 12:53:24 +0100 Subject: [PATCH 02/21] feat(web-analytics): Hide incomplete insights (#18178) Hide incomplete insights --- .../scenes/web-analytics/webAnalyticsLogic.ts | 123 +++++++++--------- 1 file changed, 58 insertions(+), 65 deletions(-) diff --git a/frontend/src/scenes/web-analytics/webAnalyticsLogic.ts b/frontend/src/scenes/web-analytics/webAnalyticsLogic.ts index 613b919f1483f..04c7bf786508b 100644 --- a/frontend/src/scenes/web-analytics/webAnalyticsLogic.ts +++ b/frontend/src/scenes/web-analytics/webAnalyticsLogic.ts @@ -2,14 +2,7 @@ import { actions, connect, kea, listeners, path, reducers, selectors, sharedList import type { webAnalyticsLogicType } from './webAnalyticsLogicType' import { NodeKind, QuerySchema, WebAnalyticsPropertyFilters, WebStatsBreakdown } from '~/queries/schema' -import { - BaseMathType, - ChartDisplayType, - EventPropertyFilter, - HogQLPropertyFilter, - PropertyFilterType, - PropertyOperator, -} from '~/types' +import { EventPropertyFilter, HogQLPropertyFilter, PropertyFilterType, PropertyOperator } from '~/types' import { isNotNil } from 'lib/utils' interface Layout { @@ -363,63 +356,63 @@ export const webAnalyticsLogic = kea([ }, ], }, - { - title: 'Unique users', - layout: { - colSpan: 6, - }, - query: { - kind: NodeKind.InsightVizNode, - source: { - kind: NodeKind.TrendsQuery, - dateRange, - interval: 'day', - series: [ - { - event: '$pageview', - kind: NodeKind.EventsNode, - math: BaseMathType.UniqueUsers, - name: '$pageview', - }, - ], - trendsFilter: { - compare: true, - display: ChartDisplayType.ActionsLineGraph, - }, - filterTestAccounts: true, - properties: webAnalyticsFilters, - }, - }, - }, - { - title: 'World Map (Unique Users)', - layout: { - colSpan: 6, - }, - query: { - kind: NodeKind.InsightVizNode, - source: { - kind: NodeKind.TrendsQuery, - breakdown: { - breakdown: '$geoip_country_code', - breakdown_type: 'person', - }, - dateRange, - series: [ - { - event: '$pageview', - kind: NodeKind.EventsNode, - math: BaseMathType.UniqueUsers, - }, - ], - trendsFilter: { - display: ChartDisplayType.WorldMap, - }, - filterTestAccounts: true, - properties: webAnalyticsFilters, - }, - }, - }, + // { + // title: 'Unique visitors', + // layout: { + // colSpan: 6, + // }, + // query: { + // kind: NodeKind.InsightVizNode, + // source: { + // kind: NodeKind.TrendsQuery, + // dateRange, + // interval: 'day', + // series: [ + // { + // event: '$pageview', + // kind: NodeKind.EventsNode, + // math: BaseMathType.UniqueUsers, + // name: '$pageview', + // }, + // ], + // trendsFilter: { + // compare: true, + // display: ChartDisplayType.ActionsLineGraph, + // }, + // filterTestAccounts: true, + // properties: webAnalyticsFilters, + // }, + // }, + // }, + // { + // title: 'World Map (Unique Users)', + // layout: { + // colSpan: 6, + // }, + // query: { + // kind: NodeKind.InsightVizNode, + // source: { + // kind: NodeKind.TrendsQuery, + // breakdown: { + // breakdown: '$geoip_country_code', + // breakdown_type: 'person', + // }, + // dateRange, + // series: [ + // { + // event: '$pageview', + // kind: NodeKind.EventsNode, + // math: BaseMathType.UniqueUsers, + // }, + // ], + // trendsFilter: { + // display: ChartDisplayType.WorldMap, + // }, + // filterTestAccounts: true, + // properties: webAnalyticsFilters, + // }, + // }, + // }, ] }, ], From 29382cbd29a3ad2e5d585d7ac8354f77c5fb4904 Mon Sep 17 00:00:00 2001 From: Ben White Date: Wed, 25 Oct 2023 15:00:44 +0200 Subject: [PATCH 03/21] feat: Added Canvas mode and node-children (#18129) --- ...nes-app-notebooks--recordings-playlist.png | Bin 84062 -> 84057 bytes frontend/src/lib/constants.tsx | 1 + .../queries/nodes/DataTable/renderColumn.tsx | 44 ++-- frontend/src/scenes/appScenes.ts | 1 + .../scenes/notebooks/Nodes/NodeWrapper.scss | 24 +-- .../scenes/notebooks/Nodes/NodeWrapper.tsx | 204 ++++++++++-------- .../notebooks/Nodes/NotebookNodePerson.tsx | 9 +- .../notebooks/Nodes/NotebookNodePlaylist.tsx | 15 +- .../notebooks/Nodes/NotebookNodeRecording.tsx | 2 +- .../notebooks/Nodes/notebookNodeLogic.ts | 97 ++++++--- .../src/scenes/notebooks/Notebook/Editor.tsx | 4 +- .../scenes/notebooks/Notebook/Notebook.scss | 70 ++++-- .../scenes/notebooks/Notebook/Notebook.tsx | 54 +++-- ...bookSidebar.tsx => NotebookColumnLeft.tsx} | 19 +- .../Notebook/NotebookColumnRight.tsx | 50 +++++ .../notebooks/Notebook/NotebookPopover.scss | 2 +- .../notebooks/Notebook/NotebookPopover.tsx | 4 +- .../notebooks/Notebook/notebookLogic.ts | 110 +++++++--- .../src/scenes/notebooks/Notebook/utils.ts | 4 +- .../scenes/notebooks/NotebookCanvasScene.tsx | 54 +++++ .../notebooks/NotebookSidebarPlaceholder.tsx | 25 --- frontend/src/scenes/persons/PersonDisplay.tsx | 59 +++-- .../src/scenes/persons/PersonFeedCanvas.tsx | 52 +++++ frontend/src/scenes/sceneTypes.ts | 1 + frontend/src/scenes/scenes.ts | 6 + .../player/SessionRecordingPlayer.tsx | 9 +- frontend/src/scenes/urls.ts | 1 + frontend/src/styles/vars.scss | 3 +- 28 files changed, 646 insertions(+), 278 deletions(-) rename frontend/src/scenes/notebooks/Notebook/{NotebookSidebar.tsx => NotebookColumnLeft.tsx} (70%) create mode 100644 frontend/src/scenes/notebooks/Notebook/NotebookColumnRight.tsx create mode 100644 frontend/src/scenes/notebooks/NotebookCanvasScene.tsx delete mode 100644 frontend/src/scenes/notebooks/NotebookSidebarPlaceholder.tsx create mode 100644 frontend/src/scenes/persons/PersonFeedCanvas.tsx diff --git a/frontend/__snapshots__/scenes-app-notebooks--recordings-playlist.png b/frontend/__snapshots__/scenes-app-notebooks--recordings-playlist.png index fc45aca0387a32d8a478460c6992a26bf91b669b..44e5a61e789a25d3d0eedceb7303b89374a9e0e4 100644 GIT binary patch literal 84057 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

_+I;lNIT@ zO+H{c`i!(gLPDOXRT&PlT zTKZVbto%~C+4(Tz;B=H~;NsD6hm|lyNEd1E`N~``tw*dimP()#HwAh`14@$>hqjt1 zJGPe${S)u%{rhXnK>bepKc77}ezi@+h($q2Ooll|630ep#o5&#Sby2Fc(Om1(^V@F z9=OsHz!H_(ifhlb-O$tXWsj$M$uRoVnG&sOmreL?n}+q6+-(2l?`4uw+uhlKYYgwX z4-|VghGE5g4E$@QcU}R9-dY(OTPK@nSZXb#M`@jUW;~cNE0?42S7%j%ufh-xO|R|N zgnP6TptaXJ92YZ`fA3~ZhAs3DiKOFk``h|yeY7ijaNzCu`YG<<2u-O->K)sx{zw}{4 zKf&>>(e5-LNYZWR8Y`@)VqE9EV@F0t1Uravp(iIN#s`ak>aTX|&abY9;Zk_2g&M|A zvTyhNpm#Sspt;8n95)BZwPoYk0|37tO4*hQy^S{?&K|6?*1SC4Fg!e9kB*P;JY4DC zm}?TTo~kkicfUTJvV}0|Hj;to1dY(+6(C#>D=ub9trl z;N|Td62Ze^>jwfXH0)zM^1#Fdv2R5MCwzyE%{4eYe6>A{bbG3r($`{i8Up(K4_sVa zDr|0Y8?WIJ!e5e;$=CXl8J$SkIm*GoW6+h|7026acR)0n4QGe>XdbQhs+Z^qQ%hpA z9AEh32dr&xe+#R`fr5rm6Ii7Yp3EzsJXtAoET~=Q@~5{q>|_hERju9RlMJ*i9B%vb zf-7fxbN$iuN@imP#FWr$Hn{{&{jO+wGT!e;dBElT01>IlX)zM)ezZDRYA7Xqy)SmU zJz=P<25^gEM>q|@!89^4^Sdb=yR6jIet^}27k~TqO|;q=%-wx-0deT)po20B^kBad zFn+zMxtXhjuTM@?{}%Q?Jr3F|DjCwlgg4nVFO;*EDa;<$;WAQYYI1*Jp%W`d?dq?? zTZ^9XeA@1fB3D13?>c`lwm+*@vV^zvYw_{IMjk#Xnx!ymgazLfd&T!?gKJnim+)+4 zmDMyFN2Ah%l7J{G88ngjTQXB4%~wvx5Ak@`&w~#gZRU!QD@h3DKjR8Z@8ySGVd`dQ zK0Vd(sl_z8g&-wIpK|@gdLr@}zUJ7)bb~`-{$Q>Vtxv_FDzVP>DxyV(12*fWEB_^B zM}LxMzfIB@ilg@FH2v@fE(hDoUmkWhIY6~@^;4h~y_sa)(L|5(`2`n*M?iG29>e_cTX4(O@YChK0LC~6vUO^9UVaru?Xka*Wa0$y#mRaHjISJ zpf8EfX=f5PQEpo9b>VQs2K+_+@YZN^8YEC-Anv`7L?9O!SXy>(j^<<42O4+BC^mRF zoAf1x#Ksa)dLKVp>t|GWBQuLeC!h3pr8_pB+nVGFt?WGDGrf)nr3gg=MQ)Ct067G> z%n)!Hliq|sV}+W%F}n3`Y)5PTIi~$7J;?&Gs5m67&YQ~eDT41)g}nj$BiY2UJyDJZ z`hO{Iix{DkQFABC`Kof1gjE)!U%~UEqM@OM7J~vqd`0<%BjmyF_E~Cv{)CYcWl>R= z2LqWQ)r#>wJ+h!aExMa%Zx2j+Zp>?KVDJLK15gidoaHMsBqb$*`kvXz)4;&sTi?lY z)D1DKp6~4%@NG+EaC8bsA>cb{v!VYnyJhl!;?Q@w~*+a8ULR&nm ziekjusvs{`=3LjV-V)&9o!V10x+-6aDDYM(t~{7IZPWav83>Md zP{MKT=F*g;v|fDkqP(p|)@<_C7!B(`Iw4tM6p5)=$>|-)NdJf$U4^2>*7OPWRYO`U zwcZ$GSAWA)+lX!SP710*>@Nz|yWS*^eqBGBM5iJeFrhWFK?Hy6W zCcWygJXuor@Mb38Y-M-#hY7(bbb|WcOs#fR36twhhPqFg?aq4FO4pt_&O!+GYbdXu zz$-Sgo|lxX^kH;0%}jnTJ{4xYp;_^4%9dv78i<-7&NVx$dR}Sy%YHuMh)jT3zoH>V zO68Z6na=Uo-dCLn_GVIQy{)%dJj+!9?q@{D37vblPn~SbM~iWe+8O6eMb=_%6j$jg zGJ#)xzD^BA*t9kmu`ai`3y3_Z;{M~|_Bpb_6!33rJJoYzclB-u1__+ztpIc?<|%`| zUkGrZQkNZ#8?V~``c%{PAr`Yn#X$ee3`jJub?QIOQ(jM1n73uVkAh_JXaT$Dby~;o zP2{Ow_hw~hk8Ey!lj3#w9&&wiQ(D;@j|JA-@%8iJh?N6Kd(?tPxxUo|R7s4g1!=k> z!`h#v!pYu)OmHG}0J_kBK|17f*?txweEG`9#|OAl&{~Qo?uQ4>9h6WqDX9)GN;H|G zj=sL|*V?}z1GSE(H)jA%-OfleK>$I*gEdK|8#a3VT8>H9AL8x8-MH((~co&HF4 zxoxgVC@6w#bzniH_TUT$B&Y-HlXoGgz7Rh&Jd=%~EU=Jnpa}})ww;x2^0_G~?YyGj zX$`;vKrUUC5hGX!N+T#`tX~ z%GLDE6jsFeUVT_ zTbOiMNEjj%D@4T%BgZsZA2Kl@UiD+HLE!K?quD|9!Rhsv z?rYBc)Fba?G;-%Cif__PT@97LgWo129aHHsNBpcm6s6qWk$x`34$su-<|c_dqs2}^ znJeh6n~Owz4d3z zh1nyuBCT|QeeRQq6lE{5`v_283a$xyUsfo32WnK?SReZ&Cx(V%VPIf*U2fz6?dYZ_ zqe;YfOmuWTfE9kXw?C$&><8=m+?K+44!yCl37mw0If~oRBsc&G5H2Gl<4?8X!23ly zH(Zt;169_ff0f7WA%XV;IUiZUjpJ)4>Q91AA+T&FUR<^%Z4&gf_q-=KPr&+Giqqb%FTAz*qMJxuivh2;q2G7Epqtj zzLPJz)NG&F03)IzqH+etP0a6Bwr|}zw1V?$;e`X8=!`jEKzEs}EfqpFTb z_CQ)eoI4EVMyN|5J2r!R=EGF#CeNIYZ|h=M zS0=t}mHMj)M`b)+nblwrK&ih_u*wUB(%fjE(kzpl=-vJnZs&`XC?Ne85+>VE#L^mflNd)cSBB2!1E z58kyV!U=$cuICPy$MJg0XJj;9kKItd9dH_Z(L(>=Pu8 zd{@1-t<4WC^s?Wde|x$o@+MWdff&^HV9TEfk=u8Gac5~m!wWP39q}lIQyzX{AYA|` z>ihTa?>rM`R>s`8S_F9ruj6_Z_Ig$_+o6kg6Re3O`m zO>8|eP}B3nv7K_!l;v}~vtw&+ENaX7BYYRkSD1Y>TYoEI^j( z6IE4}k8|2AyWofKwH{zed(sLfm){%_ba6?{^~M`+yA`>Qg{P?g?aLOZ63^69@iiotTR%7k78~q4c-g%3K1y{JwJZRSzL@A z>Vxcd$M~tV!3{~ze3s*b$Ml91KL|sGP&@&*{j|aFh%d8iOzu$jEJe5^SWVVtrnxKe z3o}3MtOZC5aVdpmqiE&s2N;wu#=w?9$u3VBw{q*JWm7xlb-4V#zMh>CCx?`BnfxZy~2M7Mv54HZN?`c#6Q2>5cM@|+VuFB7W zG#~G2%eZH7by1*q4THm}0q@$!as77yi>1E#9=Ed@qSm?YnShd3TwI*h!>Mn4=$A$fgVsaK=d4j?bsls zw}Ha0*5}3}z2Ep1Ab%1EU1e6dtOGT|GF{P}GJD25Bqe9)R^wRt zF0VqFmJtGj-)lY3Ha{2-{y?lUAg)&!+z!OXYY^vd5f)trYyzRB&2IX8){4=p=V}SX z#vgX?3e=8ls+YNtv-cvh&Q8Z>k}l`8(h6jSCiR}?(pZ;NBU1f^|7t^^2xG4&$xhdmtqK#}$ktTFg0 z@|vIj*C&M1z*QPpu|HX1E}O*r1JIuPTg6Rfu6wf&+N8x0McRg7rnYAr63^zKsrQov zVnZUcZn=q^&)tn{mCa1o<;hk&yRmeN&Nn0^B>%ubhs$I02M-?fj6}y~A(nP``}Ugd z`Wn5nDqchb;sG;D+yeqmT@;PAcXV8uvTb6URIPKd4qa`ub9FTZq0Qt>bBJQatI}K-rbYJr+L>P3D@7O+e@6${Rki(;NgsbI>3Z(2X!6PJAiyx0`_^oNZ-xF zgWYyk5KdJOP@HkgmxoLm6~W*iK7jHj4pfa`VEUC(tE+jy*-PMEvjG!EOGH60uL*cH zNkAolRiy^tGAJl0tXAW!KIaQ)q5V;bfE^1J=D54FvLBydaQss^Vea!8^F!dc_X)07 z=>s1D$cY8L2q|vE)<$sw$<+m>@wip51?v^pda^46UBYM(k5nt&ou7|(v;;Df@q5kN zC+KHS^d|_jdH~#Kz;9$PZ+>T&TlW3Uu8yN{SoBUy`u?%4c2#FdZ3hG+gWddMqt}tEFCGbScx-l^4VAyysCFWIG!WkPmw^IH8DPP5X^g z_%!r=SJyzX7mB`2OM}Hiad`<~$LM>bsj4}TObGsfrpAwG5A*R|GMbI!G{h4HKj)sMPl0)|zm6OR8++4ymSYzO5C-3_wE^1x=t1E%U)kwM#=gBEHdw{1~v})u!Z$ejFEZS zgfTMvr1nry?PL_@RT*dOZvGJ+y`$JqJ@}>iz`+X{X#WhaVH@JTY zAGJ`pe8qxy<9HWyOQ43Cn&6iE3oa5&V%g&(B7>TP`yV^4gjpZ2K&bQvWL121`rg^W zgK|&4vIaI2x?W- z%|*Jh>+`cloJTM1o}*XGRvZ8`OgppNhJ`n=JO7~EG-&@eTT+WOVw)e!+}LSYZd
e*z5#~;k=2&OEoiBrcpy?!uj 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

5tdpWUC*wMj%OLn8fhI(NYUnt*x&0`LR9OUQ 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 z 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 - } else if (key === 'person' && isEventsQuery(query.source)) { - const personRecord = value as EventsQueryPersonColumn - return personRecord.distinct_id ? ( - - ) : ( - - ) - } else if (key === 'person' && isPersonsNode(query.source)) { + } else if (key === 'person') { const personRecord = record as PersonType - return ( - - - - ) - } else if (key === 'person' && isPersonsQuery(query.source)) { - const personRecord = value as PersonType - return ( - - - - ) + + const displayProps: PersonDisplayProps = { + withIcon: true, + person: record as PersonType, + noPopover: true, + } + + if (isEventsQuery(query.source)) { + displayProps.person = value.distinct_id ? (value as EventsQueryPersonColumn) : value + displayProps.noPopover = false // If we are in an events list, the popover experience is better + } + + if (isPersonsNode(query.source) && personRecord.distinct_ids) { + displayProps.href = urls.personByDistinctId(personRecord.distinct_ids[0]) + } + + if (isPersonsQuery(query.source)) { + displayProps.href = urls.personByUUID(personRecord.id ?? '-') + } + + return } else if (key === 'person.$delete' && (isPersonsNode(query.source) || isPersonsQuery(query.source))) { const personRecord = record as PersonType return diff --git a/frontend/src/scenes/appScenes.ts b/frontend/src/scenes/appScenes.ts index 93c78f7a96e69..494f7668f4bfe 100644 --- a/frontend/src/scenes/appScenes.ts +++ b/frontend/src/scenes/appScenes.ts @@ -79,6 +79,7 @@ export const appScenes: Record any> = { [Scene.Feedback]: () => import('./feedback/Feedback'), [Scene.Notebooks]: () => import('./notebooks/NotebooksScene'), [Scene.Notebook]: () => import('./notebooks/NotebookScene'), + [Scene.Canvas]: () => import('./notebooks/NotebookCanvasScene'), [Scene.Products]: () => import('./products/Products'), [Scene.Onboarding]: () => import('./onboarding/Onboarding'), } diff --git a/frontend/src/scenes/notebooks/Nodes/NodeWrapper.scss b/frontend/src/scenes/notebooks/Nodes/NodeWrapper.scss index 58572fec9bd99..8a96021abd209 100644 --- a/frontend/src/scenes/notebooks/Nodes/NodeWrapper.scss +++ b/frontend/src/scenes/notebooks/Nodes/NodeWrapper.scss @@ -4,7 +4,6 @@ --border-color: var(--border); transform: translate3d(0, 0, 0); - margin: 0.65rem 0px 0.35rem 0px; .NotebookNode__box { transform: translate3d(0, 0, 0); @@ -12,6 +11,7 @@ border-radius: var(--radius); background-color: var(--bg-light); transition: border 150ms linear, margin-bottom 150ms linear; + overflow: hidden; .NotebookNode__meta { display: flex; @@ -33,24 +33,24 @@ } } - .NotebookNode__actions { + .NotebookNode__gap { display: flex; gap: 0.25rem; overflow: hidden; - transition: all 150ms linear 1000ms; opacity: 0; - height: 0; - margin-top: 0; + height: 1rem; + align-items: center; } - &:hover, - &--selected { - .NotebookNode__actions { - opacity: 1; - height: 2rem; - margin-top: 0.5rem; - transition: all 150ms linear; + &--has-actions { + &:hover, + &--selected { + .NotebookNode__gap { + opacity: 1; + height: 2.5rem; + transition: all 150ms linear; + } } } diff --git a/frontend/src/scenes/notebooks/Nodes/NodeWrapper.tsx b/frontend/src/scenes/notebooks/Nodes/NodeWrapper.tsx index da6c679877f03..fea1b437f3d21 100644 --- a/frontend/src/scenes/notebooks/Nodes/NodeWrapper.tsx +++ b/frontend/src/scenes/notebooks/Nodes/NodeWrapper.tsx @@ -8,7 +8,7 @@ import { NodeViewProps, getExtensionField, } from '@tiptap/react' -import { memo, useCallback, useRef } from 'react' +import { memo, useCallback, useEffect, useRef } from 'react' import clsx from 'clsx' import { IconClose, @@ -22,10 +22,10 @@ import { import { LemonButton } from '@posthog/lemon-ui' import './NodeWrapper.scss' import { LemonSkeleton } from 'lib/lemon-ui/LemonSkeleton' -import { BindLogic, useActions, useMountedLogic, useValues } from 'kea' +import { BindLogic, BuiltLogic, useActions, useMountedLogic, useValues } from 'kea' import { notebookLogic } from '../Notebook/notebookLogic' import { useInView } from 'react-intersection-observer' -import { NotebookNodeType } from '~/types' +import { NotebookNodeResource } from '~/types' import { ErrorBoundary } from '~/layout/ErrorBoundary' import { NotebookNodeContext, NotebookNodeLogicProps, notebookNodeLogic } from './notebookNodeLogic' import { posthogNodePasteRule, useSyncedAttributes } from './utils' @@ -37,45 +37,38 @@ import { } from '../Notebook/utils' import { useWhyDidIRender } from 'lib/hooks/useWhyDidIRender' import { NotebookNodeTitle } from './components/NotebookNodeTitle' +import { notebookNodeLogicType } from './notebookNodeLogicType' + +// TODO: fix the typing of string to NotebookNodeType +const KNOWN_NODES: Record> = {} + +type NodeWrapperProps = Omit & + NotebookNodeProps & { + Component: (props: NotebookNodeProps) => JSX.Element | null + + // View only props + href?: string | ((attributes: NotebookNodeAttributes) => string | undefined) + expandable?: boolean + selected?: boolean + heightEstimate?: number | string + minHeight?: number | string + /** If true the metadata area will only show when hovered if in editing mode */ + autoHideMetadata?: boolean + /** Expand the node if the component is clicked */ + expandOnClick?: boolean + } -export interface NodeWrapperProps { - nodeType: NotebookNodeType - Component: (props: NotebookNodeProps) => JSX.Element | null - - // Meta properties - these should never be too advanced - more advanced should be done via updateAttributes in the component - titlePlaceholder: string - href?: string | ((attributes: NotebookNodeAttributes) => string | undefined) - - // Sizing - expandable?: boolean - startExpanded?: boolean - resizeable?: boolean | ((attributes: CustomNotebookNodeAttributes) => boolean) - heightEstimate?: number | string - minHeight?: number | string - /** If true the metadata area will only show when hovered if in editing mode */ - autoHideMetadata?: boolean - /** Expand the node if the component is clicked */ - expandOnClick?: boolean - settings?: NotebookNodeSettings -} - -function NodeWrapper( - props: NodeWrapperProps & NotebookNodeProps & Omit -): JSX.Element { +function NodeWrapper(props: NodeWrapperProps): JSX.Element { const { - titlePlaceholder, nodeType, Component, selected, href, heightEstimate = '4rem', - resizeable: resizeableOrGenerator = true, - startExpanded = false, expandable = true, expandOnClick = true, autoHideMetadata = false, minHeight, - node, getPos, attributes, updateAttributes, @@ -85,27 +78,23 @@ function NodeWrapper( useWhyDidIRender('NodeWrapper.props', props) const mountedNotebookLogic = useMountedLogic(notebookLogic) - const { isEditable, editingNodeId } = useValues(notebookLogic) - const { setTextSelection } = useActions(notebookLogic) + const { isEditable, editingNodeId } = useValues(mountedNotebookLogic) + const { unregisterNodeLogic } = useActions(notebookLogic) - // nodeId can start null, but should then immediately be generated - const nodeId = attributes.nodeId - const nodeLogicProps: NotebookNodeLogicProps = { - node, - nodeType, - attributes, - updateAttributes, - nodeId, + const logicProps: NotebookNodeLogicProps = { + ...props, notebookLogic: mountedNotebookLogic, - getPos, - resizeable: resizeableOrGenerator, - settings, - startExpanded, - titlePlaceholder, } - const nodeLogic = useMountedLogic(notebookNodeLogic(nodeLogicProps)) - const { resizeable, expanded, actions } = useValues(nodeLogic) - const { setExpanded, deleteNode, toggleEditing } = useActions(nodeLogic) + + // nodeId can start null, but should then immediately be generated + const nodeLogic = useMountedLogic(notebookNodeLogic(logicProps)) + const { resizeable, expanded, actions, nodeId } = useValues(nodeLogic) + const { setExpanded, deleteNode, toggleEditing, insertOrSelectNextLine } = useActions(nodeLogic) + + useEffect(() => { + // TRICKY: child nodes mount the parent logic so we need to control the mounting / unmounting directly in this component + return () => unregisterNodeLogic(nodeId) + }, []) useWhyDidIRender('NodeWrapper.logicProps', { resizeable, @@ -142,20 +131,29 @@ function NodeWrapper( window.addEventListener('mouseup', onResizedEnd) }, [resizeable, updateAttributes]) + const onActionsAreaClick = (): void => { + // Clicking in the area of the actions without selecting a specific action likely indicates the user wants to + // add new content below. If we are in editing mode, we should select the next line if there is one, otherwise + insertOrSelectNextLine() + // setTextSelection(getPos() + 1) + } + const parsedHref = typeof href === 'function' ? href(attributes) : href // Element is resizable if resizable is set to true. If expandable is set to true then is is only resizable if expanded is true const isResizeable = resizeable && (!expandable || expanded) + const isDraggable = !!(isEditable && getPos) return ( - +

@@ -172,7 +170,7 @@ function NodeWrapper( <>
- {isEditable && ( + {isDraggable && ( )} @@ -229,29 +227,31 @@ function NodeWrapper( )}
- {isEditable && actions.length ? ( -
setTextSelection(getPos() + 1)} - > - {actions.map((x, i) => ( - } - onClick={(e) => { - e.stopPropagation() - x.onClick() - }} - > - {x.text} - - ))} -
- ) : null} +
onActionsAreaClick()} + > + {getPos && isEditable && actions.length ? ( + <> + {actions.map((x, i) => ( + } + onClick={(e) => { + e.stopPropagation() + x.onClick() + }} + > + {x.text} + + ))} + + ) : null} +
@@ -259,10 +259,12 @@ function NodeWrapper( ) } -const MemoizedNodeWrapper = memo(NodeWrapper) as typeof NodeWrapper +export const MemoizedNodeWrapper = memo(NodeWrapper) as typeof NodeWrapper -export type CreatePostHogWidgetNodeOptions = NodeWrapperProps & { - nodeType: NotebookNodeType +export type CreatePostHogWidgetNodeOptions = Omit< + NodeWrapperProps, + 'updateAttributes' +> & { Component: (props: NotebookNodeProps) => JSX.Element | null pasteOptions?: { find: string @@ -273,13 +275,13 @@ export type CreatePostHogWidgetNodeOptions) => string } -export function createPostHogWidgetNode({ - Component, - pasteOptions, - attributes, - serializedText, - ...wrapperProps -}: CreatePostHogWidgetNodeOptions): Node { +export function createPostHogWidgetNode( + options: CreatePostHogWidgetNodeOptions +): Node { + const { Component, pasteOptions, attributes, serializedText, ...wrapperProps } = options + + KNOWN_NODES[wrapperProps.nodeType] = options + // NOTE: We use NodeViewProps here as we convert them to NotebookNodeProps const WrappedComponent = (props: NodeViewProps): JSX.Element => { useWhyDidIRender('NodeWrapper(WrappedComponent)', props) @@ -330,6 +332,7 @@ export function createPostHogWidgetNode( default: null, }, __init: { default: null }, + children: {}, ...attributes, } }, @@ -363,3 +366,36 @@ export function createPostHogWidgetNode( }, }) } + +export const NotebookNodeChildRenderer = ({ + nodeLogic, + content, +}: { + nodeLogic: BuiltLogic + content: NotebookNodeResource +}): JSX.Element => { + const options = KNOWN_NODES[content.type] + + // eslint-disable-next-line no-console + console.log(nodeLogic) + // TODO: Respect attr changes + + // TODO: Allow deletion + + return ( + { + // eslint-disable-next-line no-console + console.log('updated called (TODO)', newAttrs) + }} + selected={false} + /> + ) + // return +} diff --git a/frontend/src/scenes/notebooks/Nodes/NotebookNodePerson.tsx b/frontend/src/scenes/notebooks/Nodes/NotebookNodePerson.tsx index 56d31294ccc07..bdc635d3282c5 100644 --- a/frontend/src/scenes/notebooks/Nodes/NotebookNodePerson.tsx +++ b/frontend/src/scenes/notebooks/Nodes/NotebookNodePerson.tsx @@ -103,7 +103,12 @@ const Component = ({ attributes }: NotebookNodeProps -
+
{personLoading ? ( ) : ( @@ -152,7 +157,7 @@ export const NotebookNodePerson = createPostHogWidgetNode urls.personByDistinctId(attrs.id), resizeable: true, attributes: { diff --git a/frontend/src/scenes/notebooks/Nodes/NotebookNodePlaylist.tsx b/frontend/src/scenes/notebooks/Nodes/NotebookNodePlaylist.tsx index 06f018a156c3d..20509743f3ca9 100644 --- a/frontend/src/scenes/notebooks/Nodes/NotebookNodePlaylist.tsx +++ b/frontend/src/scenes/notebooks/Nodes/NotebookNodePlaylist.tsx @@ -6,7 +6,7 @@ import { getDefaultFilters, sessionRecordingsPlaylistLogic, } from 'scenes/session-recordings/playlist/sessionRecordingsPlaylistLogic' -import { useActions, useValues } from 'kea' +import { BuiltLogic, useActions, useValues } from 'kea' import { useEffect, useMemo, useState } from 'react' import { fromParamsGivenUrl } from 'lib/utils' import { urls } from 'scenes/urls' @@ -17,6 +17,7 @@ import { ErrorBoundary } from '@sentry/react' import { SessionRecordingsPlaylist } from 'scenes/session-recordings/playlist/SessionRecordingsPlaylist' import { sessionRecordingPlayerLogic } from 'scenes/session-recordings/player/sessionRecordingPlayerLogic' import { IconComment } from 'lib/lemon-ui/icons' +import { sessionRecordingPlayerLogicType } from 'scenes/session-recordings/player/sessionRecordingPlayerLogicType' const Component = ({ attributes, @@ -55,6 +56,11 @@ const Component = ({ const { activeSessionRecording } = useValues(logic) const { setSelectedRecordingId } = useActions(logic) + const getReplayLogic = ( + sessionRecordingId?: string + ): BuiltLogic | null | undefined => + sessionRecordingId ? sessionRecordingPlayerLogic.findMounted({ playerKey, sessionRecordingId }) : null + useEffect(() => { setActions( activeSessionRecording @@ -62,10 +68,15 @@ const Component = ({ { text: 'View replay', onClick: () => { + getReplayLogic(activeSessionRecording.id)?.actions.setPause() + insertAfter({ type: NotebookNodeType.Recording, attrs: { id: String(activeSessionRecording.id), + __init: { + expanded: true, + }, }, }) }, @@ -93,7 +104,7 @@ const Component = ({ setTimeout(() => { // NOTE: This is a hack but we need a delay to give time for the player to mount - sessionRecordingPlayerLogic.findMounted({ playerKey, sessionRecordingId })?.actions.seekToTime(time) + getReplayLogic(sessionRecordingId)?.actions.seekToTime(time) }, 100) }, }) diff --git a/frontend/src/scenes/notebooks/Nodes/NotebookNodeRecording.tsx b/frontend/src/scenes/notebooks/Nodes/NotebookNodeRecording.tsx index 245a52e07dfd5..a104932395c83 100644 --- a/frontend/src/scenes/notebooks/Nodes/NotebookNodeRecording.tsx +++ b/frontend/src/scenes/notebooks/Nodes/NotebookNodeRecording.tsx @@ -25,7 +25,7 @@ import { IconComment, IconPerson } from 'lib/lemon-ui/icons' import { NotFound } from 'lib/components/NotFound' const HEIGHT = 500 -const MIN_HEIGHT = 400 +const MIN_HEIGHT = '20rem' const Component = ({ attributes }: NotebookNodeProps): JSX.Element => { const { id, noInspector } = attributes diff --git a/frontend/src/scenes/notebooks/Nodes/notebookNodeLogic.ts b/frontend/src/scenes/notebooks/Nodes/notebookNodeLogic.ts index 27ee45c70b083..44853bd6777bf 100644 --- a/frontend/src/scenes/notebooks/Nodes/notebookNodeLogic.ts +++ b/frontend/src/scenes/notebooks/Nodes/notebookNodeLogic.ts @@ -19,38 +19,30 @@ import { CustomNotebookNodeAttributes, JSONContent, Node, - NotebookNode, NotebookNodeAction, NotebookNodeAttributeProperties, NotebookNodeAttributes, NotebookNodeSettings, } from '../Notebook/utils' -import { NotebookNodeType } from '~/types' +import { NotebookNodeResource, NotebookNodeType } from '~/types' import posthog from 'posthog-js' import { NotebookNodeMessages, NotebookNodeMessagesListeners } from './messaging/notebook-node-messages' export type NotebookNodeLogicProps = { - node: NotebookNode - nodeId: string nodeType: NotebookNodeType notebookLogic: BuiltLogic - getPos: () => number - resizeable: boolean | ((attributes: CustomNotebookNodeAttributes) => boolean) - settings: NotebookNodeSettings + getPos?: () => number + resizeable?: boolean | ((attributes: CustomNotebookNodeAttributes) => boolean) + settings?: NotebookNodeSettings messageListeners?: NotebookNodeMessagesListeners - startExpanded: boolean + startExpanded?: boolean titlePlaceholder: string } & NotebookNodeAttributeProperties -const computeResizeable = ( - resizeable: NotebookNodeLogicProps['resizeable'], - attrs: NotebookNodeLogicProps['attributes'] -): boolean => (typeof resizeable === 'function' ? resizeable(attrs) : resizeable) - export const notebookNodeLogic = kea([ props({} as NotebookNodeLogicProps), path((key) => ['scenes', 'notebooks', 'Notebook', 'Nodes', 'notebookNodeLogic', key]), - key(({ nodeId }) => nodeId || 'no-node-id-set'), + key(({ attributes }) => attributes.nodeId || 'no-node-id-set'), actions({ setExpanded: (expanded: boolean) => ({ expanded }), setResizeable: (resizeable: boolean) => ({ resizeable }), @@ -62,6 +54,7 @@ export const notebookNodeLogic = kea([ timestamp, sessionRecordingId, }), + insertOrSelectNextLine: true, setPreviousNode: (node: Node | null) => ({ node }), setNextNode: (node: Node | null) => ({ node }), deleteNode: true, @@ -74,13 +67,13 @@ export const notebookNodeLogic = kea([ }), connect((props: NotebookNodeLogicProps) => ({ - actions: [props.notebookLogic, ['onUpdateEditor']], - values: [props.notebookLogic, ['editor']], + actions: [props.notebookLogic, ['onUpdateEditor', 'setTextSelection']], + values: [props.notebookLogic, ['editor', 'isEditable']], })), reducers(({ props }) => ({ expanded: [ - props.startExpanded, + props.startExpanded ?? true, { setExpanded: (_, { expanded }) => expanded, }, @@ -127,11 +120,15 @@ export const notebookNodeLogic = kea([ selectors({ notebookLogic: [(_, p) => [p.notebookLogic], (notebookLogic) => notebookLogic], nodeAttributes: [(_, p) => [p.attributes], (nodeAttributes) => nodeAttributes], - settings: [(_, p) => [p.settings], (settings) => settings], + nodeId: [(_, p) => [p.attributes], (nodeAttributes): string => nodeAttributes.nodeId], + settings: [() => [(_, props) => props], (props): NotebookNodeSettings | null => props.settings ?? null], + title: [ (s) => [s.titlePlaceholder, s.nodeAttributes], (titlePlaceholder, nodeAttributes) => nodeAttributes.title || titlePlaceholder, ], + // TODO: Fix the typing of nodeAttributes + children: [(s) => [s.nodeAttributes], (nodeAttributes): NotebookNodeResource[] => nodeAttributes.children], sendMessage: [ (s) => [s.messageListeners], @@ -153,29 +150,42 @@ export const notebookNodeLogic = kea([ listeners(({ actions, values, props }) => ({ onUpdateEditor: async () => { + if (!props.getPos) { + return + } const editor = values.notebookLogic.values.editor if (editor) { - const pos = props.getPos() - const { previous, next } = editor.getAdjacentNodes(pos) + const { previous, next } = editor.getAdjacentNodes(props.getPos()) actions.setPreviousNode(previous) actions.setNextNode(next) } }, insertAfter: ({ content }) => { + if (!props.getPos) { + return + } const logic = values.notebookLogic logic.values.editor?.insertContentAfterNode(props.getPos(), content) }, deleteNode: () => { + if (!props.getPos) { + // TODO: somehow make this delete from the parent + return + } + const logic = values.notebookLogic - logic.values.editor?.deleteRange({ from: props.getPos(), to: props.getPos() + props.node.nodeSize }).run() - if (values.notebookLogic.values.editingNodeId === props.nodeId) { + logic.values.editor?.deleteRange({ from: props.getPos(), to: props.getPos() + 1 }).run() + if (values.notebookLogic.values.editingNodeId === values.nodeId) { values.notebookLogic.actions.setEditingNodeId(null) } }, selectNode: () => { + if (!props.getPos) { + return + } const editor = values.notebookLogic.values.editor if (editor) { @@ -185,23 +195,45 @@ export const notebookNodeLogic = kea([ }, scrollIntoView: () => { + if (!props.getPos) { + return + } values.editor?.scrollToPosition(props.getPos()) }, insertAfterLastNodeOfType: ({ nodeType, content }) => { + if (!props.getPos) { + return + } const insertionPosition = props.getPos() values.notebookLogic.actions.insertAfterLastNodeOfType(nodeType, content, insertionPosition) }, insertReplayCommentByTimestamp: ({ timestamp, sessionRecordingId }) => { + if (!props.getPos) { + return + } const insertionPosition = props.getPos() values.notebookLogic.actions.insertReplayCommentByTimestamp({ timestamp, sessionRecordingId, knownStartingPosition: insertionPosition, - nodeId: props.nodeId, + nodeId: values.nodeId, }) }, + insertOrSelectNextLine: () => { + if (!props.getPos || !values.isEditable) { + return + } + + if (!values.nextNode || !values.nextNode.isTextblock) { + actions.insertAfter({ + type: 'paragraph', + }) + } else { + actions.setTextSelection(props.getPos() + 1) + } + }, setExpanded: ({ expanded }) => { if (expanded) { @@ -217,7 +249,7 @@ export const notebookNodeLogic = kea([ }, toggleEditing: () => { props.notebookLogic.actions.setEditingNodeId( - props.notebookLogic.values.editingNodeId === props.nodeId ? null : props.nodeId + props.notebookLogic.values.editingNodeId === values.nodeId ? null : values.nodeId ) }, initializeNode: () => { @@ -236,14 +268,19 @@ export const notebookNodeLogic = kea([ })), afterMount(async (logic) => { - logic.props.notebookLogic.actions.registerNodeLogic(logic as any) - const resizeable = computeResizeable(logic.props.resizeable, logic.props.attributes) - logic.actions.setResizeable(resizeable) - logic.actions.initializeNode() + const { props, actions, values } = logic + props.notebookLogic.actions.registerNodeLogic(values.nodeId, logic as any) + + const isResizeable = + typeof props.resizeable === 'function' ? props.resizeable(props.attributes) : props.resizeable ?? true + + actions.setResizeable(isResizeable) + actions.initializeNode() }), - beforeUnmount((logic) => { - logic.props.notebookLogic.actions.unregisterNodeLogic(logic as any) + beforeUnmount(({ props, values }) => { + // Note this doesn't work as there may be other places where this is used. The NodeWrapper should be in charge of somehow unmounting this + props.notebookLogic.actions.unregisterNodeLogic(values.nodeId) }), ]) diff --git a/frontend/src/scenes/notebooks/Notebook/Editor.tsx b/frontend/src/scenes/notebooks/Notebook/Editor.tsx index 39c6c29115958..5c43d377d1674 100644 --- a/frontend/src/scenes/notebooks/Notebook/Editor.tsx +++ b/frontend/src/scenes/notebooks/Notebook/Editor.tsx @@ -46,7 +46,7 @@ const PLACEHOLDER_TITLES = ['Release notes', 'Product roadmap', 'Meeting notes', export function Editor(): JSX.Element { const editorRef = useRef() - const { shortId } = useValues(notebookLogic) + const { shortId, mode } = useValues(notebookLogic) const { setEditor, onEditorUpdate, onEditorSelectionUpdate } = useActions(notebookLogic) const { resetSuggestions, setPreviousNode } = useActions(insertionSuggestionsLogic) @@ -62,7 +62,7 @@ export function Editor(): JSX.Element { const _editor = useEditor({ extensions: [ - CustomDocument, + mode === 'notebook' ? CustomDocument : ExtensionDocument, StarterKit.configure({ document: false, gapcursor: false, diff --git a/frontend/src/scenes/notebooks/Notebook/Notebook.scss b/frontend/src/scenes/notebooks/Notebook/Notebook.scss index eba73b22bf1a3..a3b6159c07566 100644 --- a/frontend/src/scenes/notebooks/Notebook/Notebook.scss +++ b/frontend/src/scenes/notebooks/Notebook/Notebook.scss @@ -2,6 +2,7 @@ flex: 1; display: flex; flex-direction: column; + width: 100%; .NotebookEditor { flex: 1; @@ -123,47 +124,76 @@ } } - .NotebookSidebar { + .NotebookColumn { position: relative; width: 0px; transition: width var(--notebook-popover-transition-properties); --notebook-sidebar-height: calc(100vh - 9rem); - .NotebookScene & { - --notebook-sidebar-height: calc(100vh - 11rem); - } - - .NotebookSidebar__content { + .NotebookColumn__content { position: sticky; align-self: flex-start; top: 0px; - width: var(--notebook-sidebar-width); + transform: translateX(-100%); transition: transform var(--notebook-popover-transition-properties); + } - .NotebookScene & { - // Account for sticky header + .NotebookScene &, + .NotebookPopover & { + --notebook-sidebar-height: calc(100vh - 11rem); + + .NotebookColumn__padding { + // Account for fixed title + height: 4rem; + } + } + + .NotebookScene & { + .NotebookColumn__content { + // Account for static header top: 4rem; } } + &--left { + .NotebookColumn__content { + width: var(--notebook-column-left-width); + transform: translateX(-100%); + } + } + + &--right { + .NotebookColumn__content { + width: var(--notebook-column-right-width); + transform: translateX(100%); + } + } + &--showing { - width: var(--notebook-sidebar-width); - margin-right: 1rem; + &.NotebookColumn--left { + width: var(--notebook-column-left-width); + margin-right: 1rem; + } - .NotebookSidebar__content { + &.NotebookColumn--right { + width: var(--notebook-column-right-width); + margin-left: 1rem; + } + + .NotebookColumn__content { transform: translateX(0); } } + } - .NotebookHistory { - flex: 1; - display: flex; - flex-direction: column; - height: var(--notebook-sidebar-height); - overflow: hidden; - } + .NotebookHistory { + flex: 1; + display: flex; + flex-direction: column; + height: var(--notebook-sidebar-height); + overflow: hidden; } .NotebookInlineMenu { @@ -176,7 +206,7 @@ } } - .NotebookSidebar__widget { + .NotebookColumnLeft__widget { > .LemonWidget__content { max-height: calc(100vh - 220px); overflow: auto; diff --git a/frontend/src/scenes/notebooks/Notebook/Notebook.tsx b/frontend/src/scenes/notebooks/Notebook/Notebook.tsx index 43146b75b270f..f320808bf90c9 100644 --- a/frontend/src/scenes/notebooks/Notebook/Notebook.tsx +++ b/frontend/src/scenes/notebooks/Notebook/Notebook.tsx @@ -1,5 +1,5 @@ import { useEffect } from 'react' -import { notebookLogic } from 'scenes/notebooks/Notebook/notebookLogic' +import { NotebookLogicProps, notebookLogic } from 'scenes/notebooks/Notebook/notebookLogic' import { BindLogic, useActions, useValues } from 'kea' import './Notebook.scss' @@ -11,24 +11,39 @@ import { SCRATCHPAD_NOTEBOOK } from '~/models/notebooksModel' import { NotebookConflictWarning } from './NotebookConflictWarning' import { NotebookLoadingState } from './NotebookLoadingState' import { Editor } from './Editor' -import { EditorFocusPosition } from './utils' -import { NotebookSidebar } from './NotebookSidebar' +import { EditorFocusPosition, JSONContent } from './utils' +import { NotebookColumnLeft } from './NotebookColumnLeft' import { ErrorBoundary } from '~/layout/ErrorBoundary' import { NotebookHistoryWarning } from './NotebookHistory' import { useWhyDidIRender } from 'lib/hooks/useWhyDidIRender' +import { NotebookColumnRight } from './NotebookColumnRight' -export type NotebookProps = { - shortId: string - editable?: boolean +export type NotebookProps = NotebookLogicProps & { initialAutofocus?: EditorFocusPosition + initialContent?: JSONContent + editable?: boolean } -export function Notebook({ shortId, editable = false, initialAutofocus = 'start' }: NotebookProps): JSX.Element { - const logic = notebookLogic({ shortId }) - const { notebook, notebookLoading, editor, conflictWarningVisible, isEditable } = useValues(logic) - const { duplicateNotebook, loadNotebook, setEditable } = useActions(logic) +export function Notebook({ + shortId, + mode, + editable = true, + initialAutofocus = 'start', + initialContent, +}: NotebookProps): JSX.Element { + const logicProps: NotebookLogicProps = { shortId, mode } + const logic = notebookLogic(logicProps) + const { notebook, notebookLoading, editor, conflictWarningVisible, isEditable, isTemplate, notebookMissing } = + useValues(logic) + const { duplicateNotebook, loadNotebook, setEditable, setLocalContent } = useActions(logic) const { isExpanded } = useValues(notebookSettingsLogic) + useEffect(() => { + if (initialContent && mode === 'canvas') { + setLocalContent(initialContent) + } + }, [notebook]) + useWhyDidIRender('Notebook', { notebook, notebookLoading, @@ -36,7 +51,6 @@ export function Notebook({ shortId, editable = false, initialAutofocus = 'start' conflictWarningVisible, isEditable, shortId, - editable, initialAutofocus, }) @@ -66,14 +80,21 @@ export function Notebook({ shortId, editable = false, initialAutofocus = 'start' return } else if (!notebook && notebookLoading) { return - } else if (!notebook) { + } else if (notebookMissing) { return } return ( - -
- {notebook.is_template && ( + +
+ {isTemplate && ( - + +
diff --git a/frontend/src/scenes/notebooks/Notebook/NotebookSidebar.tsx b/frontend/src/scenes/notebooks/Notebook/NotebookColumnLeft.tsx similarity index 70% rename from frontend/src/scenes/notebooks/Notebook/NotebookSidebar.tsx rename to frontend/src/scenes/notebooks/Notebook/NotebookColumnLeft.tsx index d321be5d743c1..d3edc6569eb6b 100644 --- a/frontend/src/scenes/notebooks/Notebook/NotebookSidebar.tsx +++ b/frontend/src/scenes/notebooks/Notebook/NotebookColumnLeft.tsx @@ -7,19 +7,20 @@ import { LemonButton } from '@posthog/lemon-ui' import { IconEyeVisible } from 'lib/lemon-ui/icons' import { NotebookHistory } from './NotebookHistory' -export const NotebookSidebar = (): JSX.Element | null => { - const { editingNodeLogic, isShowingSidebar, showHistory } = useValues(notebookLogic) +export const NotebookColumnLeft = (): JSX.Element | null => { + const { editingNodeLogic, isShowingLeftColumn, showHistory } = useValues(notebookLogic) return (
-
- {isShowingSidebar ? ( +
+
+ {isShowingLeftColumn ? ( editingNodeLogic ? ( - + ) : showHistory ? ( ) : null @@ -29,7 +30,7 @@ export const NotebookSidebar = (): JSX.Element | null => { ) } -const Widgets = ({ logic }: { logic: BuiltLogic }): JSX.Element => { +const NodeSettings = ({ logic }: { logic: BuiltLogic }): JSX.Element => { const { setEditingNodeId } = useActions(notebookLogic) const { settings: Settings, nodeAttributes, title } = useValues(logic) const { updateAttributes, selectNode } = useActions(logic) @@ -37,7 +38,7 @@ const Widgets = ({ logic }: { logic: BuiltLogic }): JSX.E return ( } size="small" status="primary" onClick={() => selectNode()} /> diff --git a/frontend/src/scenes/notebooks/Notebook/NotebookColumnRight.tsx b/frontend/src/scenes/notebooks/Notebook/NotebookColumnRight.tsx new file mode 100644 index 0000000000000..6ccb797affb76 --- /dev/null +++ b/frontend/src/scenes/notebooks/Notebook/NotebookColumnRight.tsx @@ -0,0 +1,50 @@ +import { BuiltLogic, useValues } from 'kea' +import clsx from 'clsx' +import { notebookLogic } from './notebookLogic' +import { notebookNodeLogicType } from '../Nodes/notebookNodeLogicType' +import { NotebookNodeChildRenderer } from '../Nodes/NodeWrapper' +import { uuid } from 'lib/utils' + +export const NotebookColumnRight = (): JSX.Element | null => { + const { isShowingLeftColumn, nodeLogicsWithChildren } = useValues(notebookLogic) + const isShowing = nodeLogicsWithChildren.length && !isShowingLeftColumn + + return ( +
+
+
+ {isShowing ? ( + <> + {nodeLogicsWithChildren.map((x, i) => ( + + ))} + + ) : null} +
+
+ ) +} + +const Widgets = ({ nodeLogic }: { nodeLogic: BuiltLogic }): JSX.Element => { + const { children } = useValues(nodeLogic) + + // TODO: IMPORTANT: The nodeId is basically now required, so we should be checking that in the logic + // otherwise we end up in horrible re-rendering loops + children.forEach((content) => { + if (!content.attrs.nodeId) { + content.attrs.nodeId = uuid() + } + }) + + return ( + <> + {children?.map((child) => ( + + ))} + + ) +} diff --git a/frontend/src/scenes/notebooks/Notebook/NotebookPopover.scss b/frontend/src/scenes/notebooks/Notebook/NotebookPopover.scss index db98f2d008427..b191950decce5 100644 --- a/frontend/src/scenes/notebooks/Notebook/NotebookPopover.scss +++ b/frontend/src/scenes/notebooks/Notebook/NotebookPopover.scss @@ -80,7 +80,7 @@ &--with-sidebar { // TODO: Sync this with the sidebar width itself .NotebookPopover__content { - width: calc(50rem + var(--notebook-sidebar-width)); + width: calc(50rem + var(--notebook-column-left-width)); } } diff --git a/frontend/src/scenes/notebooks/Notebook/NotebookPopover.tsx b/frontend/src/scenes/notebooks/Notebook/NotebookPopover.tsx index 65679bd924778..f820f876cce36 100644 --- a/frontend/src/scenes/notebooks/Notebook/NotebookPopover.tsx +++ b/frontend/src/scenes/notebooks/Notebook/NotebookPopover.tsx @@ -111,7 +111,7 @@ export function NotebookPopoverCard(): JSX.Element | null { export function NotebookPopover(): JSX.Element { const { visibility, fullScreen, selectedNotebook, dropProperties } = useValues(notebookPopoverLogic) const { setVisibility, setFullScreen, setElementRef } = useActions(notebookPopoverLogic) - const { isShowingSidebar } = useValues(notebookLogic({ shortId: selectedNotebook })) + const { isShowingLeftColumn } = useValues(notebookLogic({ shortId: selectedNotebook })) const ref = useRef(null) @@ -145,7 +145,7 @@ export function NotebookPopover(): JSX.Element { 'NotebookPopover', `NotebookPopover--${visibility}`, fullScreen && 'NotebookPopover--full-screen', - isShowingSidebar && 'NotebookPopover--with-sidebar' + isShowingLeftColumn && 'NotebookPopover--with-sidebar' )} >
boolean, fn: () => any): Promise { @@ -59,7 +63,7 @@ async function runWhenEditorIsReady(waitForEditor: () => boolean, fn: () => any) export const notebookLogic = kea([ props({} as NotebookLogicProps), path((key) => ['scenes', 'notebooks', 'Notebook', 'notebookLogic', key]), - key(({ shortId }) => shortId), + key(({ shortId, mode }) => `${shortId}-${mode}`), connect(() => ({ values: [notebooksModel, ['scratchpadNotebook', 'notebookTemplates']], actions: [notebooksModel, ['receiveNotebookUpdate']], @@ -79,8 +83,8 @@ export const notebookLogic = kea([ exportJSON: true, showConflictWarning: true, onUpdateEditor: true, - registerNodeLogic: (nodeLogic: BuiltLogic) => ({ nodeLogic }), - unregisterNodeLogic: (nodeLogic: BuiltLogic) => ({ nodeLogic }), + registerNodeLogic: (nodeId: string, nodeLogic: BuiltLogic) => ({ nodeId, nodeLogic }), + unregisterNodeLogic: (nodeId: string) => ({ nodeId }), setEditable: (editable: boolean) => ({ editable }), scrollToSelection: true, pasteAfterLastNode: (content: string) => ({ @@ -104,10 +108,10 @@ export const notebookLogic = kea([ setShowHistory: (showHistory: boolean) => ({ showHistory }), setTextSelection: (selection: number | EditorRange) => ({ selection }), }), - reducers({ + reducers(({ props }) => ({ localContent: [ null as JSONContent | null, - { persist: true, prefix: NOTEBOOKS_VERSION }, + { persist: props.mode === 'notebook', prefix: NOTEBOOKS_VERSION }, { setLocalContent: (_, { jsonContent }) => jsonContent, clearLocalContent: () => null, @@ -148,20 +152,20 @@ export const notebookLogic = kea([ nodeLogics: [ {} as Record>, { - registerNodeLogic: (state, { nodeLogic }) => { - if (nodeLogic.props.nodeId === null) { + registerNodeLogic: (state, { nodeId, nodeLogic }) => { + if (nodeId === null) { return state } else { return { ...state, - [nodeLogic.props.nodeId]: nodeLogic, + [nodeId]: nodeLogic, } } }, - unregisterNodeLogic: (state, { nodeLogic }) => { + unregisterNodeLogic: (state, { nodeId }) => { const newState = { ...state } - if (nodeLogic.props.nodeId !== null) { - delete newState[nodeLogic.props.nodeId] + if (nodeId !== null) { + delete newState[nodeId] } return newState }, @@ -179,13 +183,17 @@ export const notebookLogic = kea([ setShowHistory: (_, { showHistory }) => showHistory, }, ], - }), + })), loaders(({ values, props, actions }) => ({ notebook: [ null as NotebookType | null, { loadNotebook: async () => { - let response: NotebookType | null + let response: NotebookType | null = null + + if (values.mode !== 'notebook') { + return null + } if (props.shortId === SCRATCHPAD_NOTEBOOK.short_id) { response = { @@ -250,25 +258,30 @@ export const notebookLogic = kea([ null as NotebookType | null, { duplicateNotebook: async () => { - if (!values.notebook) { + if (!values.content) { return null } // We use the local content if set otherwise the notebook content. That way it supports templates, scratchpad etc. const response = await api.notebooks.create({ - content: values.content || values.notebook.content, + content: values.content, text_content: values.editor?.getText() || '', - title: values.title || values.notebook.title, + title: values.title, }) posthog.capture(`notebook duplicated`, { short_id: response.short_id, }) - const source = values.notebook.short_id === 'scratchpad' ? 'Scratchpad' : 'Template' + const source = + values.mode === 'canvas' + ? 'Canvas' + : values.notebook?.short_id === 'scratchpad' + ? 'Scratchpad' + : 'Template' lemonToast.success(`Notebook created from ${source}!`) - if (values.notebook.short_id === 'scratchpad') { + if (values.notebook?.short_id === 'scratchpad') { // If duplicating the scratchpad, we assume they don't want the scratchpad content anymore actions.clearLocalContent() } @@ -282,7 +295,20 @@ export const notebookLogic = kea([ })), selectors({ shortId: [() => [(_, props) => props], (props): string => props.shortId], - isLocalOnly: [() => [(_, props) => props], (props): boolean => props.shortId === 'scratchpad'], + mode: [() => [(_, props) => props], (props): NotebookLogicMode => props.mode ?? 'notebook'], + isTemplate: [(s) => [s.shortId], (shortId): boolean => shortId.startsWith('template-')], + isLocalOnly: [ + () => [(_, props) => props], + (props): boolean => { + return props.shortId === 'scratchpad' || props.mode === 'canvas' + }, + ], + notebookMissing: [ + (s) => [s.notebook, s.notebookLoading, s.mode], + (notebook, notebookLoading, mode): boolean => { + return (['notebook', 'template'].includes(mode) && !notebook && !notebookLoading) ?? false + }, + ], content: [ (s) => [s.notebook, s.localContent, s.previewContent], (notebook, localContent, previewContent): JSONContent => { @@ -321,7 +347,7 @@ export const notebookLogic = kea([ editingNodeLogic: [ (s) => [s.editingNodeId, s.nodeLogics], (editingNodeId, nodeLogics) => - Object.values(nodeLogics).find((nodeLogic) => nodeLogic.props.nodeId === editingNodeId), + Object.values(nodeLogics).find((nodeLogic) => nodeLogic.values.nodeId === editingNodeId), ], findNodeLogic: [ (s) => [s.nodeLogics], @@ -344,13 +370,22 @@ export const notebookLogic = kea([ findNodeLogicById: [ (s) => [s.nodeLogics], (nodeLogics) => { - return (id: string): notebookNodeLogicType | null => { - return Object.values(nodeLogics).find((nodeLogic) => nodeLogic.props.nodeId === id) ?? null + return (id: string) => { + return Object.values(nodeLogics).find((nodeLogic) => nodeLogic.values.nodeId === id) ?? null } }, ], - isShowingSidebar: [ + nodeLogicsWithChildren: [ + (s) => [s.nodeLogics, s.content], + // eslint-disable-next-line @typescript-eslint/no-unused-vars + (nodeLogics, _content) => { + // NOTE: _content is not but is needed to retrigger as it could mean the children have changed + return Object.values(nodeLogics).filter((nodeLogic) => nodeLogic.props.attributes?.children) + }, + ], + + isShowingLeftColumn: [ (s) => [s.editingNodeId, s.showHistory], (editingNodeId, showHistory) => !!editingNodeId || showHistory, ], @@ -368,7 +403,7 @@ export const notebookLogic = kea([ } }, })), - listeners(({ values, actions, sharedListeners }) => ({ + listeners(({ values, actions, sharedListeners, cache }) => ({ insertAfterLastNode: async ({ content }) => { await runWhenEditorIsReady( () => !!values.editor, @@ -449,6 +484,19 @@ export const notebookLogic = kea([ await breakpoint(SYNC_DELAY) + if (values.mode === 'canvas') { + // TODO: We probably want this to be configurable + cache.lastState = btoa(JSON.stringify(jsonContent)) + router.actions.replace( + router.values.currentLocation.pathname, + router.values.currentLocation.searchParams, + { + ...router.values.currentLocation.hashParams, + state: cache.lastState, + } + ) + } + posthog.capture('notebook content changed', { short_id: values.notebook?.short_id, }) @@ -474,7 +522,7 @@ export const notebookLogic = kea([ }, onEditorUpdate: () => { - if (!values.editor || !values.notebook) { + if (!values.editor) { return } const jsonContent = values.editor.getJSON() @@ -519,4 +567,16 @@ export const notebookLogic = kea([ }) }, })), + + urlToAction(({ values, actions, cache }) => ({ + '*': (_, _search, hashParams) => { + if (values.mode === 'canvas' && hashParams?.state) { + if (cache.lastState === hashParams.state) { + return + } + + actions.setLocalContent(JSON.parse(atob(hashParams.state))) + } + }, + })), ]) diff --git a/frontend/src/scenes/notebooks/Notebook/utils.ts b/frontend/src/scenes/notebooks/Notebook/utils.ts index 2d0427b2a2ca4..b21ff74c82db7 100644 --- a/frontend/src/scenes/notebooks/Notebook/utils.ts +++ b/frontend/src/scenes/notebooks/Notebook/utils.ts @@ -10,7 +10,7 @@ import { TextSerializer, } from '@tiptap/core' import { Node as PMNode } from '@tiptap/pm/model' -import { NotebookNodeType } from '~/types' +import { NotebookNodeResource, NotebookNodeType } from '~/types' export interface Node extends PMNode {} export interface JSONContent extends TTJSONContent {} @@ -31,6 +31,8 @@ export type NotebookNodeAttributes = T & expanded?: boolean showSettings?: boolean } + // TODO: Type this more specifically to be our supported nodes only + children?: NotebookNodeResource[] } // NOTE: Pushes users to use the parsed "attributes" instead diff --git a/frontend/src/scenes/notebooks/NotebookCanvasScene.tsx b/frontend/src/scenes/notebooks/NotebookCanvasScene.tsx new file mode 100644 index 0000000000000..894d00344a1b8 --- /dev/null +++ b/frontend/src/scenes/notebooks/NotebookCanvasScene.tsx @@ -0,0 +1,54 @@ +import { SceneExport } from 'scenes/sceneTypes' +import { NotebookLogicProps, notebookLogic } from './Notebook/notebookLogic' +import { Notebook } from './Notebook/Notebook' +import './NotebookScene.scss' +import { useMemo } from 'react' +import { uuid } from 'lib/utils' +import { useActions } from 'kea' +import { LemonBanner } from '@posthog/lemon-ui' +import { useFeatureFlag } from 'lib/hooks/useFeatureFlag' +import { NotFound } from 'lib/components/NotFound' + +export const scene: SceneExport = { + component: NotebookCanvas, +} + +export function NotebookCanvas(): JSX.Element { + const id = useMemo(() => uuid(), []) + + const logicProps: NotebookLogicProps = { + shortId: `canvas-${id}`, + mode: 'canvas', + } + + const { duplicateNotebook } = useActions(notebookLogic(logicProps)) + + const is3000 = useFeatureFlag('POSTHOG_3000') + + if (!is3000) { + return Canvas mode requires PostHog 3000} /> + } + + // TODO: The absolute positioning doesn't work so well in non-3000 mode + + return ( +
+ + This is a canvas. You can change anything you like and it is persisted to the URL for easy + sharing. + +
+
+ +
+
+
+ ) +} diff --git a/frontend/src/scenes/notebooks/NotebookSidebarPlaceholder.tsx b/frontend/src/scenes/notebooks/NotebookSidebarPlaceholder.tsx deleted file mode 100644 index d726210f17cc4..0000000000000 --- a/frontend/src/scenes/notebooks/NotebookSidebarPlaceholder.tsx +++ /dev/null @@ -1,25 +0,0 @@ -import { LemonButton } from '@posthog/lemon-ui' -import { useActions } from 'kea' -import { notebookPopoverLogic } from './Notebook/notebookPopoverLogic' -import { IconArrowRight } from 'lib/lemon-ui/icons' - -export function NotebookSidebarPlaceholder(): JSX.Element { - const { setVisibility } = useActions(notebookPopoverLogic) - - return ( -
-

- This Notebook is open in the sidebar -

- -

- You can navigate around PostHog and drag and drop thing into it. Or you can close the sidebar and - it will be full screen here instead. -

- - setVisibility('hidden')}> - Open it here instead - -
- ) -} diff --git a/frontend/src/scenes/persons/PersonDisplay.tsx b/frontend/src/scenes/persons/PersonDisplay.tsx index d93766c080205..06b3e4b2158ad 100644 --- a/frontend/src/scenes/persons/PersonDisplay.tsx +++ b/frontend/src/scenes/persons/PersonDisplay.tsx @@ -7,6 +7,8 @@ import { PersonPreview } from './PersonPreview' import { useMemo, useState } from 'react' import { router } from 'kea-router' import { asDisplay, asLink } from './person-utils' +import { useNotebookNode } from 'scenes/notebooks/Nodes/notebookNodeLogic' +import { NotebookNodeType } from '~/types' type PersonPropType = | { properties?: Record; distinct_ids?: string[]; distinct_id?: never } @@ -15,6 +17,7 @@ type PersonPropType = export interface PersonDisplayProps { person?: PersonPropType | null withIcon?: boolean | ProfilePictureProps['size'] + href?: string noLink?: boolean noEllipsis?: boolean noPopover?: boolean @@ -45,11 +48,13 @@ export function PersonDisplay({ noPopover, noLink, isCentered, + href = asLink(person), }: PersonDisplayProps): JSX.Element { - const href = asLink(person) const display = asDisplay(person) const [visible, setVisible] = useState(false) + const notebookNode = useNotebookNode() + let content = ( {withIcon && } @@ -67,6 +72,19 @@ export function PersonDisplay({ router.actions.push(href) } else { setVisible(true) + + if (notebookNode && person) { + notebookNode.actions.updateAttributes({ + children: [ + { + type: NotebookNodeType.Person, + attrs: { + id: person.distinct_id || person.distinct_ids?.[0], + }, + }, + ], + }) + } } } : undefined @@ -91,25 +109,26 @@ export function PersonDisplay({ ) - content = noPopover ? ( - content - ) : ( - setVisible(false)} - /> - } - visible={visible} - onClickOutside={() => setVisible(false)} - placement="right" - fallbackPlacements={['bottom', 'top']} - showArrow - > - {content} - - ) + content = + noPopover || notebookNode ? ( + content + ) : ( + setVisible(false)} + /> + } + visible={visible} + onClickOutside={() => setVisible(false)} + placement="right" + fallbackPlacements={['bottom', 'top']} + showArrow + > + {content} + + ) return content } diff --git a/frontend/src/scenes/persons/PersonFeedCanvas.tsx b/frontend/src/scenes/persons/PersonFeedCanvas.tsx new file mode 100644 index 0000000000000..d2de1646a62d5 --- /dev/null +++ b/frontend/src/scenes/persons/PersonFeedCanvas.tsx @@ -0,0 +1,52 @@ +import { PersonType } from '~/types' +import { Notebook } from 'scenes/notebooks/Notebook/Notebook' +import { uuid } from 'lib/utils' + +type PersonFeedCanvasProps = { + person: PersonType +} + +const PersonFeedCanvas = ({ person }: PersonFeedCanvasProps): JSX.Element => { + const id = person.id + + const personId = person.distinct_ids[0] + + return ( + + ) +} + +export default PersonFeedCanvas diff --git a/frontend/src/scenes/sceneTypes.ts b/frontend/src/scenes/sceneTypes.ts index 5922d6e36bd2a..0e35998cd8887 100644 --- a/frontend/src/scenes/sceneTypes.ts +++ b/frontend/src/scenes/sceneTypes.ts @@ -82,6 +82,7 @@ export enum Scene { Feedback = 'Feedback', Notebooks = 'Notebooks', Notebook = 'Notebook', + Canvas = 'Canvas', Products = 'Products', Onboarding = 'Onboarding', } diff --git a/frontend/src/scenes/scenes.ts b/frontend/src/scenes/scenes.ts index 3f4964bdeffbf..d8f43290d737f 100644 --- a/frontend/src/scenes/scenes.ts +++ b/frontend/src/scenes/scenes.ts @@ -327,6 +327,11 @@ export const sceneConfigurations: Partial> = { projectBased: true, name: 'Notebooks', }, + [Scene.Canvas]: { + projectBased: true, + name: 'Canvas', + layout: 'app-raw', + }, } const preserveParams = (url: string) => (_params: Params, searchParams: Params, hashParams: Params) => { @@ -498,4 +503,5 @@ export const routes: Record = { [urls.feedback() + '/*']: Scene.Feedback, [urls.notebook(':shortId')]: Scene.Notebook, [urls.notebooks()]: Scene.Notebooks, + [urls.canvas()]: Scene.Canvas, } diff --git a/frontend/src/scenes/session-recordings/player/SessionRecordingPlayer.tsx b/frontend/src/scenes/session-recordings/player/SessionRecordingPlayer.tsx index 3097dbe5e7119..d95fc4bdaee0a 100644 --- a/frontend/src/scenes/session-recordings/player/SessionRecordingPlayer.tsx +++ b/frontend/src/scenes/session-recordings/player/SessionRecordingPlayer.tsx @@ -125,7 +125,8 @@ export function SessionRecordingPlayer(props: SessionRecordingPlayerProps): JSX. const { size } = useResizeBreakpoints( { - 0: 'small', + 0: 'tiny', + 400: 'small', 1000: 'medium', }, playerRef @@ -148,9 +149,9 @@ export function SessionRecordingPlayer(props: SessionRecordingPlayerProps): JSX. className={clsx('SessionRecordingPlayer', { 'SessionRecordingPlayer--fullscreen': isFullScreen, 'SessionRecordingPlayer--no-border': noBorder, - 'SessionRecordingPlayer--widescreen': !isFullScreen && size !== 'small', + 'SessionRecordingPlayer--widescreen': !isFullScreen && size === 'medium', 'SessionRecordingPlayer--inspector-focus': inspectorFocus, - 'SessionRecordingPlayer--inspector-hidden': noInspector, + 'SessionRecordingPlayer--inspector-hidden': noInspector || size === 'tiny', 'SessionRecordingPlayer--buffering': isBuffering, })} onClick={incrementClickCount} @@ -160,7 +161,7 @@ export function SessionRecordingPlayer(props: SessionRecordingPlayerProps): JSX. ) : ( <>
- {!noMeta || isFullScreen ? : null} + {(!noMeta || isFullScreen) && size !== 'tiny' ? : null}
diff --git a/frontend/src/scenes/urls.ts b/frontend/src/scenes/urls.ts index 40ac033a7576c..930aa0c14d6a1 100644 --- a/frontend/src/scenes/urls.ts +++ b/frontend/src/scenes/urls.ts @@ -186,4 +186,5 @@ export const urls = { issues: (): string => '/issues', notebooks: (): string => '/notebooks', notebook: (shortId: string): string => `/notebooks/${shortId}`, + canvas: (): string => `/canvas`, } diff --git a/frontend/src/styles/vars.scss b/frontend/src/styles/vars.scss index 7f18952abf6f0..45adf1ab8d342 100644 --- a/frontend/src/styles/vars.scss +++ b/frontend/src/styles/vars.scss @@ -323,5 +323,6 @@ $_lifecycle_dormant: $_danger; // Notebooks --notebook-popover-transition-properties: 150ms cubic-bezier(0, 0.5, 0.5, 1); - --notebook-sidebar-width: 27rem; + --notebook-column-left-width: 27rem; + --notebook-column-right-width: 20rem; } From ccdc2ae9b588fabd1b2ec64ecb5cf541fc5753d5 Mon Sep 17 00:00:00 2001 From: Tom Owers Date: Wed, 25 Oct 2023 14:22:45 +0100 Subject: [PATCH 04/21] feat: Adding session duration lazy join (#18132) * Added session duration as a lazy join * Moved the session field within events * Moved session duration logic to the join itself * More improvements * Updated the extractor to not use a traverser * Fixed unused var * Fixed broken join func and removed unused join func * Update query snapshots * Resolve aliased table field properly and clean the field chain * Update query snapshots * Update query snapshots * Update query snapshots --------- Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com> --- .../__snapshots__/test_dashboard.ambr | 18 ++ posthog/hogql/database/database.py | 23 -- posthog/hogql/database/models.py | 3 +- .../hogql/database/schema/event_sessions.py | 166 ++++++++++++++ posthog/hogql/database/schema/events.py | 7 + posthog/hogql/database/schema/groups.py | 8 +- .../database/schema/person_distinct_ids.py | 8 +- .../hogql/database/schema/person_overrides.py | 4 +- posthog/hogql/database/schema/persons.py | 6 +- posthog/hogql/database/schema/persons_pdi.py | 4 +- .../schema/test/test_event_sessions.py | 205 ++++++++++++++++++ .../test/__snapshots__/test_database.ambr | 18 ++ posthog/hogql/printer.py | 3 +- posthog/hogql/resolver.py | 28 +-- posthog/hogql/resolver_utils.py | 47 ++++ posthog/hogql/transforms/lazy_tables.py | 30 +-- posthog/warehouse/models/view_link.py | 5 +- 17 files changed, 501 insertions(+), 82 deletions(-) create mode 100644 posthog/hogql/database/schema/event_sessions.py create mode 100644 posthog/hogql/database/schema/test/test_event_sessions.py create mode 100644 posthog/hogql/resolver_utils.py diff --git a/posthog/api/test/dashboards/__snapshots__/test_dashboard.ambr b/posthog/api/test/dashboards/__snapshots__/test_dashboard.ambr index 33832fe5073e2..b6b14a9dfbd34 100644 --- a/posthog/api/test/dashboards/__snapshots__/test_dashboard.ambr +++ b/posthog/api/test/dashboards/__snapshots__/test_dashboard.ambr @@ -11232,6 +11232,24 @@ 5 /* ... */) /*controller='project_dashboards-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/dashboards/%3F%24'*/ ' --- +# name: TestDashboard.test_retrieve_dashboard_list.33 + ' + SELECT "posthog_sharingconfiguration"."id", + "posthog_sharingconfiguration"."team_id", + "posthog_sharingconfiguration"."dashboard_id", + "posthog_sharingconfiguration"."insight_id", + "posthog_sharingconfiguration"."recording_id", + "posthog_sharingconfiguration"."created_at", + "posthog_sharingconfiguration"."enabled", + "posthog_sharingconfiguration"."access_token" + FROM "posthog_sharingconfiguration" + WHERE "posthog_sharingconfiguration"."dashboard_id" IN (1, + 2, + 3, + 4, + 5 /* ... */) /*controller='project_dashboards-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/dashboards/%3F%24'*/ + ' +--- # name: TestDashboard.test_retrieve_dashboard_list.4 ' SELECT "posthog_dashboardtile"."id" diff --git a/posthog/hogql/database/database.py b/posthog/hogql/database/database.py index 1e5b8dd2cc390..dc898dde6924e 100644 --- a/posthog/hogql/database/database.py +++ b/posthog/hogql/database/database.py @@ -164,29 +164,6 @@ def create_hogql_database(team_id: int, modifiers: Optional[HogQLQueryModifiers] return database -def determine_join_function(view): - def join_function(from_table: str, to_table: str, requested_fields: Dict[str, Any]): - from posthog.hogql import ast - from posthog.hogql.parser import parse_select - - if not requested_fields: - raise HogQLException(f"No fields requested from {to_table}") - - join_expr = ast.JoinExpr(table=parse_select(view.saved_query.query["query"])) - join_expr.join_type = "INNER JOIN" - join_expr.alias = to_table - join_expr.constraint = ast.JoinConstraint( - expr=ast.CompareOperation( - op=ast.CompareOperationOp.Eq, - left=ast.Field(chain=[from_table, view.from_join_key]), - right=ast.Field(chain=[to_table, view.to_join_key]), - ) - ) - return join_expr - - return join_function - - class _SerializedFieldBase(TypedDict): key: str type: Literal[ diff --git a/posthog/hogql/database/models.py b/posthog/hogql/database/models.py index 9c7fcac1e8703..91a3b436a5df0 100644 --- a/posthog/hogql/database/models.py +++ b/posthog/hogql/database/models.py @@ -6,6 +6,7 @@ if TYPE_CHECKING: from posthog.hogql.context import HogQLContext + from posthog.hogql.ast import SelectQuery class FieldOrTable(BaseModel): @@ -101,7 +102,7 @@ def get_asterisk(self): class LazyJoin(FieldOrTable): model_config = ConfigDict(extra="forbid") - join_function: Callable[[str, str, Dict[str, Any], HogQLQueryModifiers], Any] + join_function: Callable[[str, str, Dict[str, Any], "HogQLContext", "SelectQuery"], Any] join_table: Table from_field: str diff --git a/posthog/hogql/database/schema/event_sessions.py b/posthog/hogql/database/schema/event_sessions.py new file mode 100644 index 0000000000000..3ccb665540476 --- /dev/null +++ b/posthog/hogql/database/schema/event_sessions.py @@ -0,0 +1,166 @@ +from copy import deepcopy +from typing import Any, Dict, List, Optional +from posthog.hogql import ast +from posthog.hogql.context import HogQLContext +from posthog.hogql.database.models import FieldOrTable, IntegerDatabaseField, StringDatabaseField, VirtualTable +from posthog.hogql.parser import parse_select +from posthog.hogql.resolver_utils import get_long_table_name, lookup_field_by_name +from posthog.hogql.visitor import CloningVisitor, TraversingVisitor + + +class EventsSessionSubTable(VirtualTable): + fields: Dict[str, FieldOrTable] = { + "$session_id": StringDatabaseField(name="$session_id"), + "session_duration": IntegerDatabaseField(name="session_duration"), + } + + def to_printed_clickhouse(self, context): + return "events" + + def to_printed_hogql(self): + return "events" + + +class GetFieldsTraverser(TraversingVisitor): + fields: List[ast.Field] + + def __init__(self, expr: ast.Expr): + super().__init__() + self.fields = [] + super().visit(expr) + + def visit_field(self, node: ast.Field): + self.fields.append(node) + + +class CleanTableNameFromChain(CloningVisitor): + def __init__(self, table_name: str, select_query_type: ast.SelectQueryType): + super().__init__() + self.table_name = table_name + self.select_query_type = select_query_type + + def visit_field(self, node: ast.Field): + if len(node.chain) > 1 and str(node.chain[0]) in self.select_query_type.tables: + type = self.select_query_type.tables[str(node.chain[0])] + + name = get_long_table_name(self.select_query_type, type) + if name == self.table_name: + node.chain.pop(0) + + return super().visit_field(node) + + +class WhereClauseExtractor: + compare_operators: List[ast.Expr] + + def __init__(self, where_expression: ast.Expr, from_table_name: str, select_query_type: ast.SelectQueryType): + self.table_name = from_table_name + self.select_query_type = select_query_type + self.compare_operators = self.run(deepcopy(where_expression)) + + def _is_field_on_table(self, field: ast.Field) -> bool: + if len(field.chain) == 0: + return False + + type: Optional[ast.Type] = None + + # If the field contains at least two parts, the first might be a table. + if len(field.chain) > 1 and str(field.chain[0]) in self.select_query_type.tables: + type = self.select_query_type.tables[str(field.chain[0])] + + name = get_long_table_name(self.select_query_type, type) + if name != self.table_name: + return False + + # Field in scope + if not type: + type = lookup_field_by_name(self.select_query_type, str(field.chain[0])) + + if not type: + return False + + # Recursively resolve the rest of the chain until we can point to the deepest node. + loop_type = type + chain_to_parse = field.chain[1:] + while True: + if isinstance(loop_type, ast.FieldTraverserType): + chain_to_parse = loop_type.chain + chain_to_parse + loop_type = loop_type.table_type + continue + if len(chain_to_parse) == 0: + break + next_chain = chain_to_parse.pop(0) + loop_type = loop_type.get_child(str(next_chain)) + if loop_type is None: + return False + + return True + + def run(self, expr: ast.Expr) -> List[ast.Expr]: + exprs_to_apply: List[ast.Expr] = [] + + if isinstance(expr, ast.And): + for expression in expr.exprs: + if not isinstance(expression, ast.CompareOperation): + continue + + fields = GetFieldsTraverser(expression).fields + res = [self._is_field_on_table(field) for field in fields] + if all(res): + exprs_to_apply.append(expression) + elif isinstance(expr, ast.CompareOperation): + exprs_to_apply.extend(self.run(ast.And(exprs=[expr]))) + elif isinstance(expr, ast.Or): + pass # Ignore for now + + # Clone field nodes and remove table name from field chains + return [ + CleanTableNameFromChain(self.table_name, self.select_query_type).visit( + CloningVisitor(clear_types=True, clear_locations=True).visit(e) + ) + for e in exprs_to_apply + ] + + +def join_with_events_table_session_duration( + from_table: str, + to_table: str, + requested_fields: Dict[str, Any], + context: HogQLContext, + node: ast.SelectQuery, +): + select_query = parse_select( + """ + select "$session_id", dateDiff('second', min(timestamp), max(timestamp)) as session_duration + from events + group by "$session_id" + """ + ) + + if isinstance(select_query, ast.SelectQuery): + compare_operators = ( + WhereClauseExtractor(node.where, from_table, node.type).compare_operators + if node.where and node.type + else [] + ) + select_query.where = ast.And( + exprs=[ + *compare_operators, + ast.CompareOperation( + left=ast.Field(chain=["$session_id"]), op=ast.CompareOperationOp.NotEq, right=ast.Constant(value="") + ), + ] + ) + + join_expr = ast.JoinExpr(table=select_query) + join_expr.join_type = "INNER JOIN" + join_expr.alias = to_table + join_expr.constraint = ast.JoinConstraint( + expr=ast.CompareOperation( + op=ast.CompareOperationOp.Eq, + left=ast.Field(chain=[from_table, "$session_id"]), + right=ast.Field(chain=[to_table, "$session_id"]), + ) + ) + + return join_expr diff --git a/posthog/hogql/database/schema/events.py b/posthog/hogql/database/schema/events.py index ba27ff7c5e158..06cab31fca940 100644 --- a/posthog/hogql/database/schema/events.py +++ b/posthog/hogql/database/schema/events.py @@ -11,6 +11,7 @@ FieldTraverser, FieldOrTable, ) +from posthog.hogql.database.schema.event_sessions import EventsSessionSubTable, join_with_events_table_session_duration from posthog.hogql.database.schema.groups import GroupsTable, join_with_group_n_table from posthog.hogql.database.schema.person_distinct_ids import ( PersonDistinctIdsTable, @@ -54,6 +55,7 @@ def to_printed_hogql(self): class EventsTable(Table): + fields: Dict[str, FieldOrTable] = { "uuid": StringDatabaseField(name="uuid"), "event": StringDatabaseField(name="event"), @@ -97,6 +99,11 @@ class EventsTable(Table): "group_3": LazyJoin(from_field="$group_3", join_table=GroupsTable(), join_function=join_with_group_n_table(3)), "$group_4": StringDatabaseField(name="$group_4"), "group_4": LazyJoin(from_field="$group_4", join_table=GroupsTable(), join_function=join_with_group_n_table(4)), + "session": LazyJoin( + from_field="$session_id", + join_table=EventsSessionSubTable(), + join_function=join_with_events_table_session_duration, + ), } def to_printed_clickhouse(self, context): diff --git a/posthog/hogql/database/schema/groups.py b/posthog/hogql/database/schema/groups.py index 9b3fc1f28c176..251be8a11b243 100644 --- a/posthog/hogql/database/schema/groups.py +++ b/posthog/hogql/database/schema/groups.py @@ -1,4 +1,6 @@ from typing import Any, Dict, List +from posthog.hogql.ast import SelectQuery +from posthog.hogql.context import HogQLContext from posthog.hogql.database.argmax import argmax_select from posthog.hogql.database.models import ( @@ -34,7 +36,11 @@ def select_from_groups_table(requested_fields: Dict[str, List[str]]): def join_with_group_n_table(group_index: int): def join_with_group_table( - from_table: str, to_table: str, requested_fields: Dict[str, Any], modifiers: HogQLQueryModifiers + from_table: str, + to_table: str, + requested_fields: Dict[str, Any], + context: HogQLContext, + node: SelectQuery, ): from posthog.hogql import ast diff --git a/posthog/hogql/database/schema/person_distinct_ids.py b/posthog/hogql/database/schema/person_distinct_ids.py index 3765c44673890..963f0bdd24db8 100644 --- a/posthog/hogql/database/schema/person_distinct_ids.py +++ b/posthog/hogql/database/schema/person_distinct_ids.py @@ -1,4 +1,6 @@ from typing import Dict, List +from posthog.hogql.ast import SelectQuery +from posthog.hogql.context import HogQLContext from posthog.hogql.database.argmax import argmax_select from posthog.hogql.database.models import ( @@ -36,7 +38,11 @@ def select_from_person_distinct_ids_table(requested_fields: Dict[str, List[str]] def join_with_person_distinct_ids_table( - from_table: str, to_table: str, requested_fields: Dict[str, List[str]], modifiers: HogQLQueryModifiers + from_table: str, + to_table: str, + requested_fields: Dict[str, List[str]], + context: HogQLContext, + node: SelectQuery, ): from posthog.hogql import ast diff --git a/posthog/hogql/database/schema/person_overrides.py b/posthog/hogql/database/schema/person_overrides.py index 9e2e92656867c..1dc15126a6ebc 100644 --- a/posthog/hogql/database/schema/person_overrides.py +++ b/posthog/hogql/database/schema/person_overrides.py @@ -1,4 +1,6 @@ from typing import Any, Dict, List +from posthog.hogql.ast import SelectQuery +from posthog.hogql.context import HogQLContext from posthog.hogql.database.argmax import argmax_select from posthog.hogql.database.models import ( @@ -32,7 +34,7 @@ def select_from_person_overrides_table(requested_fields: Dict[str, List[str]]): def join_with_person_overrides_table( - from_table: str, to_table: str, requested_fields: Dict[str, Any], modifiers: HogQLQueryModifiers + from_table: str, to_table: str, requested_fields: Dict[str, Any], context: HogQLContext, node: SelectQuery ): from posthog.hogql import ast diff --git a/posthog/hogql/database/schema/persons.py b/posthog/hogql/database/schema/persons.py index 6df5513f316cf..67a36b747d279 100644 --- a/posthog/hogql/database/schema/persons.py +++ b/posthog/hogql/database/schema/persons.py @@ -1,6 +1,8 @@ from typing import Dict, List +from posthog.hogql.ast import SelectQuery from posthog.hogql.constants import HogQLQuerySettings +from posthog.hogql.context import HogQLContext from posthog.hogql.database.argmax import argmax_select from posthog.hogql.database.models import ( Table, @@ -81,13 +83,13 @@ def select_from_persons_table(requested_fields: Dict[str, List[str]], modifiers: def join_with_persons_table( - from_table: str, to_table: str, requested_fields: Dict[str, List[str]], modifiers: HogQLQueryModifiers + from_table: str, to_table: str, requested_fields: Dict[str, List[str]], context: HogQLContext, node: SelectQuery ): from posthog.hogql import ast if not requested_fields: raise HogQLException("No fields requested from persons table") - join_expr = ast.JoinExpr(table=select_from_persons_table(requested_fields, modifiers)) + join_expr = ast.JoinExpr(table=select_from_persons_table(requested_fields, context.modifiers)) join_expr.join_type = "INNER JOIN" join_expr.alias = to_table join_expr.constraint = ast.JoinConstraint( diff --git a/posthog/hogql/database/schema/persons_pdi.py b/posthog/hogql/database/schema/persons_pdi.py index 8f83234b6bed3..33d21d4efed04 100644 --- a/posthog/hogql/database/schema/persons_pdi.py +++ b/posthog/hogql/database/schema/persons_pdi.py @@ -1,4 +1,6 @@ from typing import Dict, List +from posthog.hogql.ast import SelectQuery +from posthog.hogql.context import HogQLContext from posthog.hogql.database.argmax import argmax_select from posthog.hogql.database.models import ( @@ -29,7 +31,7 @@ def persons_pdi_select(requested_fields: Dict[str, List[str]]): # :NOTE: We already have person_distinct_ids.py, which most tables link to. This persons_pdi.py is a hack to # make "select persons.pdi.distinct_id from persons" work while avoiding circular imports. Don't use directly. def persons_pdi_join( - from_table: str, to_table: str, requested_fields: Dict[str, List[str]], modifiers: HogQLQueryModifiers + from_table: str, to_table: str, requested_fields: Dict[str, List[str]], context: HogQLContext, node: SelectQuery ): from posthog.hogql import ast diff --git a/posthog/hogql/database/schema/test/test_event_sessions.py b/posthog/hogql/database/schema/test/test_event_sessions.py new file mode 100644 index 0000000000000..34cb2c2bbba6c --- /dev/null +++ b/posthog/hogql/database/schema/test/test_event_sessions.py @@ -0,0 +1,205 @@ +from typing import List, cast +from posthog.hogql import ast +from posthog.hogql.context import HogQLContext +from posthog.hogql.database.database import create_hogql_database +from posthog.hogql.database.schema.event_sessions import CleanTableNameFromChain, WhereClauseExtractor +from posthog.hogql.parser import parse_expr, parse_select +from posthog.hogql.resolver import resolve_types +from posthog.hogql.visitor import clone_expr +from posthog.test.base import BaseTest + + +class TestWhereClauseExtractor(BaseTest): + def setUp(self): + self.database = create_hogql_database(self.team.pk) + self.context = HogQLContext(database=self.database, team_id=self.team.pk) + + def _select(self, query: str) -> ast.SelectQuery: + select_query = cast(ast.SelectQuery, clone_expr(parse_select(query), clear_locations=True)) + return cast(ast.SelectQuery, resolve_types(select_query, self.context)) + + def _compare_operators(self, query: ast.SelectQuery, table_name: str) -> List[ast.Expr]: + assert query.where is not None and query.type is not None + return WhereClauseExtractor(query.where, table_name, query.type).compare_operators + + def test_with_simple_equality_clause(self): + query = self._select( + """ + SELECT event + FROM events + WHERE event = '$pageview' + """ + ) + + compare_operators = self._compare_operators(query, "events") + + assert len(compare_operators) == 1 + assert compare_operators[0] == ast.CompareOperation( + left=ast.Field(chain=["event"]), op=ast.CompareOperationOp.Eq, right=ast.Constant(value="$pageview") + ) + + def test_with_timestamps(self): + query = self._select( + """ + SELECT event + FROM events + WHERE timestamp > '2023-01-01' + """ + ) + + compare_operators = self._compare_operators(query, "events") + + assert len(compare_operators) == 1 + assert compare_operators[0] == ast.CompareOperation( + left=ast.Field(chain=["timestamp"]), op=ast.CompareOperationOp.Gt, right=ast.Constant(value="2023-01-01") + ) + + def test_with_alias_table(self): + query = self._select( + """ + SELECT e.event + FROM events e + WHERE e.event = '$pageview' + """ + ) + + compare_operators = self._compare_operators(query, "e") + + assert len(compare_operators) == 1 + assert compare_operators[0] == ast.CompareOperation( + left=ast.Field(chain=["event"]), op=ast.CompareOperationOp.Eq, right=ast.Constant(value="$pageview") + ) + + def test_with_multiple_clauses(self): + query = self._select( + """ + SELECT event + FROM events + WHERE event = '$pageview' AND timestamp > '2023-01-01' + """ + ) + + compare_operators = self._compare_operators(query, "events") + + assert len(compare_operators) == 2 + assert compare_operators[0] == ast.CompareOperation( + left=ast.Field(chain=["event"]), op=ast.CompareOperationOp.Eq, right=ast.Constant(value="$pageview") + ) + assert compare_operators[1] == ast.CompareOperation( + left=ast.Field(chain=["timestamp"]), op=ast.CompareOperationOp.Gt, right=ast.Constant(value="2023-01-01") + ) + + def test_with_join(self): + query = self._select( + """ + SELECT e.event, p.id + FROM events e + LEFT JOIN persons p + ON e.person_id = p.id + WHERE e.event = '$pageview' and p.is_identified = 0 + """ + ) + + compare_operators = self._compare_operators(query, "e") + + assert len(compare_operators) == 1 + assert compare_operators[0] == ast.CompareOperation( + left=ast.Field(chain=["event"]), op=ast.CompareOperationOp.Eq, right=ast.Constant(value="$pageview") + ) + + def test_with_ignoring_ors(self): + query = self._select( + """ + SELECT event + FROM events + WHERE event = '$pageleave' OR event = '$pageview' + """ + ) + + compare_operators = self._compare_operators(query, "events") + + assert len(compare_operators) == 0 + + +class TestCleanTableNameFromChain(BaseTest): + def setUp(self): + self.database = create_hogql_database(self.team.pk) + self.context = HogQLContext(database=self.database, team_id=self.team.pk) + + def _select(self, query: str) -> ast.SelectQuery: + select_query = cast(ast.SelectQuery, clone_expr(parse_select(query), clear_locations=True)) + return cast(ast.SelectQuery, resolve_types(select_query, self.context)) + + def _clean(self, table_name: str, query: ast.SelectQuery, expr: ast.Expr) -> ast.Expr: + assert query.type is not None + return CleanTableNameFromChain(table_name, query.type).visit(expr) + + def test_table_with_no_alias(self): + query = self._select( + """ + SELECT event + FROM events + """ + ) + + expr = parse_expr('event = "$pageview"') + cleaned_expr = cast(ast.CompareOperation, self._clean("events", query, expr)) + expr_left = cast(ast.Field, cleaned_expr.left) + + assert expr_left.chain == ["event"] + + def test_table_with_alias(self): + query = self._select( + """ + SELECT e.event + FROM events e + """ + ) + + expr = parse_expr('e.event = "$pageview"') + cleaned_expr = cast(ast.CompareOperation, self._clean("e", query, expr)) + expr_left = cast(ast.Field, cleaned_expr.left) + + assert expr_left.chain == ["event"] + + def test_field_with_properties(self): + query = self._select( + """ + SELECT event + FROM events + """ + ) + + expr = parse_expr('properties.$browser = "Chrome"') + cleaned_expr = cast(ast.CompareOperation, self._clean("events", query, expr)) + expr_left = cast(ast.Field, cleaned_expr.left) + + assert expr_left.chain == ["properties", "$browser"] + + def test_table_alias_and_field_with_properties(self): + query = self._select( + """ + SELECT e.event + FROM events e + """ + ) + + expr = parse_expr('e.properties.$browser = "Chrome"') + cleaned_expr = cast(ast.CompareOperation, self._clean("e", query, expr)) + expr_left = cast(ast.Field, cleaned_expr.left) + + assert expr_left.chain == ["properties", "$browser"] + + def test_with_incorrect_alias(self): + query = self._select( + """ + SELECT e.event + FROM events e + """ + ) + + expr = parse_expr('e.event = "$pageview"') + cleaned_expr = cast(ast.CompareOperation, self._clean("some_other_alias", query, expr)) + expr_left = cast(ast.Field, cleaned_expr.left) + + assert expr_left.chain == ["e", "event"] diff --git a/posthog/hogql/database/test/__snapshots__/test_database.ambr b/posthog/hogql/database/test/__snapshots__/test_database.ambr index 1a0efafd1a4c6..90bc08c457891 100644 --- a/posthog/hogql/database/test/__snapshots__/test_database.ambr +++ b/posthog/hogql/database/test/__snapshots__/test_database.ambr @@ -226,6 +226,15 @@ "updated_at", "properties" ] + }, + { + "key": "session", + "type": "lazy_table", + "table": "events", + "fields": [ + "$session_id", + "session_duration" + ] } ], "groups": [ @@ -1007,6 +1016,15 @@ "updated_at", "properties" ] + }, + { + "key": "session", + "type": "lazy_table", + "table": "events", + "fields": [ + "$session_id", + "session_duration" + ] } ], "groups": [ diff --git a/posthog/hogql/printer.py b/posthog/hogql/printer.py index 3108c31d05124..dae5a1a0c610c 100644 --- a/posthog/hogql/printer.py +++ b/posthog/hogql/printer.py @@ -30,7 +30,8 @@ escape_hogql_string, ) from posthog.hogql.functions.mapping import validate_function_args -from posthog.hogql.resolver import ResolverException, lookup_field_by_name, resolve_types +from posthog.hogql.resolver import ResolverException, resolve_types +from posthog.hogql.resolver_utils import lookup_field_by_name from posthog.hogql.transforms.in_cohort import resolve_in_cohorts from posthog.hogql.transforms.lazy_tables import resolve_lazy_tables from posthog.hogql.transforms.property_types import resolve_property_types diff --git a/posthog/hogql/resolver.py b/posthog/hogql/resolver.py index 48ea712bb9e13..b2e94b4c6893d 100644 --- a/posthog/hogql/resolver.py +++ b/posthog/hogql/resolver.py @@ -11,6 +11,7 @@ from posthog.hogql.functions.mapping import validate_function_args from posthog.hogql.functions.sparkline import sparkline from posthog.hogql.parser import parse_select +from posthog.hogql.resolver_utils import lookup_cte_by_name, lookup_field_by_name from posthog.hogql.visitor import CloningVisitor, clone_expr from posthog.models.utils import UUIDT from posthog.hogql.database.schema.events import EventsTable @@ -563,30 +564,3 @@ def _is_next_s3(self, node: Optional[ast.JoinExpr]): if isinstance(node.type, ast.TableAliasType): return isinstance(node.type.table_type.table, S3Table) return False - - -def lookup_field_by_name(scope: ast.SelectQueryType, name: str) -> Optional[ast.Type]: - """Looks for a field in the scope's list of aliases and children for each joined table.""" - if name in scope.aliases: - return scope.aliases[name] - else: - named_tables = [table for table in scope.tables.values() if table.has_child(name)] - anonymous_tables = [table for table in scope.anonymous_tables if table.has_child(name)] - tables_with_field = named_tables + anonymous_tables - - if len(tables_with_field) > 1: - raise ResolverException(f"Ambiguous query. Found multiple sources for field: {name}") - elif len(tables_with_field) == 1: - return tables_with_field[0].get_child(name) - - if scope.parent: - return lookup_field_by_name(scope.parent, name) - - return None - - -def lookup_cte_by_name(scopes: List[ast.SelectQueryType], name: str) -> Optional[ast.CTE]: - for scope in reversed(scopes): - if scope and scope.ctes and name in scope.ctes: - return scope.ctes[name] - return None diff --git a/posthog/hogql/resolver_utils.py b/posthog/hogql/resolver_utils.py new file mode 100644 index 0000000000000..2fb8fd6d814f7 --- /dev/null +++ b/posthog/hogql/resolver_utils.py @@ -0,0 +1,47 @@ +from typing import List, Optional +from posthog.hogql import ast +from posthog.hogql.errors import HogQLException, ResolverException + + +def lookup_field_by_name(scope: ast.SelectQueryType, name: str) -> Optional[ast.Type]: + """Looks for a field in the scope's list of aliases and children for each joined table.""" + if name in scope.aliases: + return scope.aliases[name] + else: + named_tables = [table for table in scope.tables.values() if table.has_child(name)] + anonymous_tables = [table for table in scope.anonymous_tables if table.has_child(name)] + tables_with_field = named_tables + anonymous_tables + + if len(tables_with_field) > 1: + raise ResolverException(f"Ambiguous query. Found multiple sources for field: {name}") + elif len(tables_with_field) == 1: + return tables_with_field[0].get_child(name) + + if scope.parent: + return lookup_field_by_name(scope.parent, name) + + return None + + +def lookup_cte_by_name(scopes: List[ast.SelectQueryType], name: str) -> Optional[ast.CTE]: + for scope in reversed(scopes): + if scope and scope.ctes and name in scope.ctes: + return scope.ctes[name] + return None + + +def get_long_table_name(select: ast.SelectQueryType, type: ast.Type) -> str: + if isinstance(type, ast.TableType): + return select.get_alias_for_table_type(type) or "" + elif isinstance(type, ast.LazyTableType): + return type.table.to_printed_hogql() + elif isinstance(type, ast.TableAliasType): + return type.alias + elif isinstance(type, ast.SelectQueryAliasType): + return type.alias + elif isinstance(type, ast.LazyJoinType): + return f"{get_long_table_name(select, type.table_type)}__{type.field}" + elif isinstance(type, ast.VirtualTableType): + return f"{get_long_table_name(select, type.table_type)}__{type.field}" + else: + raise HogQLException(f"Unknown table type in LazyTableResolver: {type.__class__.__name__}") diff --git a/posthog/hogql/transforms/lazy_tables.py b/posthog/hogql/transforms/lazy_tables.py index d2bd4c1398aa9..543035f843460 100644 --- a/posthog/hogql/transforms/lazy_tables.py +++ b/posthog/hogql/transforms/lazy_tables.py @@ -6,6 +6,7 @@ from posthog.hogql.database.models import LazyJoin, LazyTable from posthog.hogql.errors import HogQLException from posthog.hogql.resolver import resolve_types +from posthog.hogql.resolver_utils import get_long_table_name from posthog.hogql.visitor import TraversingVisitor @@ -33,22 +34,6 @@ def __init__(self, stack: Optional[List[ast.SelectQuery]] = None, context: HogQL self.stack_of_fields: List[List[ast.FieldType | ast.PropertyType]] = [[]] if stack else [] self.context = context - def _get_long_table_name(self, select: ast.SelectQueryType, type: ast.BaseTableType) -> str: - if isinstance(type, ast.TableType): - return select.get_alias_for_table_type(type) - elif isinstance(type, ast.LazyTableType): - return type.table.to_printed_hogql() - elif isinstance(type, ast.TableAliasType): - return type.alias - elif isinstance(type, ast.SelectQueryAliasType): - return type.alias - elif isinstance(type, ast.LazyJoinType): - return f"{self._get_long_table_name(select, type.table_type)}__{type.field}" - elif isinstance(type, ast.VirtualTableType): - return f"{self._get_long_table_name(select, type.table_type)}__{type.field}" - else: - raise HogQLException(f"Unknown table type in LazyTableResolver: {type.__class__.__name__}") - def visit_property_type(self, node: ast.PropertyType): if node.joined_subquery is not None: # we have already visited this property @@ -110,7 +95,7 @@ def visit_select_query(self, node: ast.SelectQuery): if field_or_property.field_type.table_type == join.table.type: fields.append(field_or_property) if len(fields) == 0: - table_name = join.alias or self._get_long_table_name(select_type, join.table.type) + table_name = join.alias or get_long_table_name(select_type, join.table.type) tables_to_add[table_name] = TableToAdd(fields_accessed={}, lazy_table=join.table.type.table) join = join.next_join @@ -139,8 +124,8 @@ def visit_select_query(self, node: ast.SelectQuery): # Loop over the collected lazy tables in reverse order to create the joins for table_type in reversed(table_types): if isinstance(table_type, ast.LazyJoinType): - from_table = self._get_long_table_name(select_type, table_type.table_type) - to_table = self._get_long_table_name(select_type, table_type) + from_table = get_long_table_name(select_type, table_type.table_type) + to_table = get_long_table_name(select_type, table_type) if to_table not in joins_to_add: joins_to_add[to_table] = JoinToAdd( fields_accessed={}, # collect here all fields accessed on this table @@ -159,7 +144,7 @@ def visit_select_query(self, node: ast.SelectQuery): else: new_join.fields_accessed[field.name] = chain elif isinstance(table_type, ast.LazyTableType): - table_name = self._get_long_table_name(select_type, table_type) + table_name = get_long_table_name(select_type, table_type) if table_name not in tables_to_add: tables_to_add[table_name] = TableToAdd( fields_accessed={}, # collect here all fields accessed on this table @@ -203,9 +188,10 @@ def visit_select_query(self, node: ast.SelectQuery): # For all the collected joins, create the join subqueries, and add them to the table. for to_table, join_scope in joins_to_add.items(): join_to_add: ast.JoinExpr = join_scope.lazy_join.join_function( - join_scope.from_table, join_scope.to_table, join_scope.fields_accessed, self.context.modifiers + join_scope.from_table, join_scope.to_table, join_scope.fields_accessed, self.context, node ) join_to_add = cast(ast.JoinExpr, resolve_types(join_to_add, self.context, [node.type])) + select_type.tables[to_table] = join_to_add.type join_ptr = node.select_from @@ -239,7 +225,7 @@ def visit_select_query(self, node: ast.SelectQuery): else: raise HogQLException("Should not be reachable") - table_name = self._get_long_table_name(select_type, table_type) + table_name = get_long_table_name(select_type, table_type) table_type = select_type.tables[table_name] if isinstance(field_or_property, ast.FieldType): diff --git a/posthog/warehouse/models/view_link.py b/posthog/warehouse/models/view_link.py index 978afb1b390a6..a989c07a74b06 100644 --- a/posthog/warehouse/models/view_link.py +++ b/posthog/warehouse/models/view_link.py @@ -1,10 +1,11 @@ +from posthog.hogql.ast import SelectQuery +from posthog.hogql.context import HogQLContext from posthog.models.utils import UUIDModel, CreatedMetaFields, DeletedMetaFields from django.db import models from posthog.models.team import Team from .datawarehouse_saved_query import DataWarehouseSavedQuery from typing import Dict, Any from posthog.hogql.errors import HogQLException -from ...schema import HogQLQueryModifiers class DataWarehouseViewLink(CreatedMetaFields, UUIDModel, DeletedMetaFields): @@ -18,7 +19,7 @@ class DataWarehouseViewLink(CreatedMetaFields, UUIDModel, DeletedMetaFields): @property def join_function(self): def _join_function( - from_table: str, to_table: str, requested_fields: Dict[str, Any], modifiers: HogQLQueryModifiers + from_table: str, to_table: str, requested_fields: Dict[str, Any], context: HogQLContext, node: SelectQuery ): from posthog.hogql import ast from posthog.hogql.parser import parse_select From fe1ce5a5565ee268b709dd8c67076a981c65b79a Mon Sep 17 00:00:00 2001 From: David Newell Date: Wed, 25 Oct 2023 16:43:09 +0100 Subject: [PATCH 05/21] feat: nested task lists (#18151) --- .../src/scenes/notebooks/Notebook/Editor.tsx | 6 ++++ .../scenes/notebooks/Notebook/Notebook.scss | 34 +++++++++++++++++-- package.json | 2 ++ pnpm-lock.yaml | 26 +++++++++++++- 4 files changed, 64 insertions(+), 4 deletions(-) diff --git a/frontend/src/scenes/notebooks/Notebook/Editor.tsx b/frontend/src/scenes/notebooks/Notebook/Editor.tsx index 5c43d377d1674..4b5cdaa3d8eda 100644 --- a/frontend/src/scenes/notebooks/Notebook/Editor.tsx +++ b/frontend/src/scenes/notebooks/Notebook/Editor.tsx @@ -8,6 +8,8 @@ import { FloatingMenu } from '@tiptap/extension-floating-menu' import StarterKit from '@tiptap/starter-kit' import ExtensionPlaceholder from '@tiptap/extension-placeholder' import ExtensionDocument from '@tiptap/extension-document' +import TaskItem from '@tiptap/extension-task-item' +import TaskList from '@tiptap/extension-task-list' import { NotebookNodeFlagCodeExample } from '../Nodes/NotebookNodeFlagCodeExample' import { NotebookNodeFlag } from '../Nodes/NotebookNodeFlag' @@ -94,6 +96,10 @@ export function Editor(): JSX.Element { } }, }), + TaskList, + TaskItem.configure({ + nested: true, + }), NotebookMarkLink, NotebookNodeBacklink, NotebookNodeQuery, diff --git a/frontend/src/scenes/notebooks/Notebook/Notebook.scss b/frontend/src/scenes/notebooks/Notebook/Notebook.scss index a3b6159c07566..3adb654c29b47 100644 --- a/frontend/src/scenes/notebooks/Notebook/Notebook.scss +++ b/frontend/src/scenes/notebooks/Notebook/Notebook.scss @@ -37,12 +37,40 @@ height: 0; } - > ul { + > ol { + list-style-type: decimal; + } + + ul { list-style-type: disc; } - > ol { - list-style-type: decimal; + > ul[data-type='taskList'] { + list-style-type: none; + padding-left: 0px; + + li { + display: flex; + + > label { + flex: 0 0 auto; + margin-right: 0.5rem; + user-select: none; + } + + > div { + flex: 1 1 auto; + } + + ul li, + ol li { + display: list-item; + } + + ul[data-type='taskList'] > li { + display: flex; + } + } } > ul, diff --git a/package.json b/package.json index 3ffa52cc67565..fcc8195b58513 100644 --- a/package.json +++ b/package.json @@ -84,6 +84,8 @@ "@tiptap/extension-document": "^2.1.0-rc.12", "@tiptap/extension-floating-menu": "^2.1.0-rc.12", "@tiptap/extension-placeholder": "^2.1.0-rc.12", + "@tiptap/extension-task-item": "^2.1.11", + "@tiptap/extension-task-list": "^2.1.11", "@tiptap/pm": "^2.1.0-rc.12", "@tiptap/react": "^2.1.0-rc.12", "@tiptap/starter-kit": "^2.1.0-rc.12", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4877b89c3edb9..4c20f9d5853c4 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1,4 +1,4 @@ -lockfileVersion: '6.1' +lockfileVersion: '6.0' settings: autoInstallPeers: true @@ -65,6 +65,12 @@ dependencies: '@tiptap/extension-placeholder': specifier: ^2.1.0-rc.12 version: 2.1.0-rc.12(@tiptap/core@2.1.0-rc.12)(@tiptap/pm@2.1.0-rc.12) + '@tiptap/extension-task-item': + specifier: ^2.1.11 + version: 2.1.11(@tiptap/core@2.1.0-rc.12)(@tiptap/pm@2.1.0-rc.12) + '@tiptap/extension-task-list': + specifier: ^2.1.11 + version: 2.1.11(@tiptap/core@2.1.0-rc.12) '@tiptap/pm': specifier: ^2.1.0-rc.12 version: 2.1.0-rc.12 @@ -5505,6 +5511,24 @@ packages: '@tiptap/core': 2.1.0-rc.12(@tiptap/pm@2.1.0-rc.12) dev: false + /@tiptap/extension-task-item@2.1.11(@tiptap/core@2.1.0-rc.12)(@tiptap/pm@2.1.0-rc.12): + resolution: {integrity: sha512-721inc/MAZkljPup/EWCpNho4nf+XrYVKWRixqgX+AjikusTJefylbiZ5OeRn+71osTA7SdnXiKkM2ZbHtAsYA==} + peerDependencies: + '@tiptap/core': ^2.0.0 + '@tiptap/pm': ^2.0.0 + dependencies: + '@tiptap/core': 2.1.0-rc.12(@tiptap/pm@2.1.0-rc.12) + '@tiptap/pm': 2.1.0-rc.12 + dev: false + + /@tiptap/extension-task-list@2.1.11(@tiptap/core@2.1.0-rc.12): + resolution: {integrity: sha512-9C1M9N3jbNjm4001mPkgwUH19b6ZvKj5nnRT3zib/gFIQLOnSHE3VErDPHP/lkkjH84LgOMrm69cm8chQpgNsA==} + peerDependencies: + '@tiptap/core': ^2.0.0 + dependencies: + '@tiptap/core': 2.1.0-rc.12(@tiptap/pm@2.1.0-rc.12) + dev: false + /@tiptap/extension-text@2.1.0-rc.12(@tiptap/core@2.1.0-rc.12): resolution: {integrity: sha512-6rJvPkpypaEW+jM6oB9kMXg+wy7xbDnGBFLRvCuA4Tr5Y+S+i34CzcihyARr90p+scYkOl+6QYVww4oisRFskA==} peerDependencies: From 886c80454a9dd3cf74d2e9b45eb6b0ca85eae765 Mon Sep 17 00:00:00 2001 From: Xavier Vello Date: Wed, 25 Oct 2023 17:58:12 +0200 Subject: [PATCH 06/21] chore(compose): add capture-rs profile with containerised capture for testing (#18140) --- docker-compose.base.yml | 12 ++++++++++++ docker-compose.dev-full.yml | 9 +++++++++ docker-compose.dev.yml | 11 +++++++++++ 3 files changed, 32 insertions(+) diff --git a/docker-compose.base.yml b/docker-compose.base.yml index dba92a0046034..f1d1a3f658e64 100644 --- a/docker-compose.base.yml +++ b/docker-compose.base.yml @@ -89,6 +89,18 @@ services: command: ./bin/start-backend & ./bin/start-frontend restart: on-failure + capture: + image: ghcr.io/posthog/capture:main + restart: on-failure + environment: + ADDRESS: '0.0.0.0:3000' + KAFKA_TOPIC: 'events_plugin_ingestion' + KAFKA_HOSTS: 'kafka:9092' + REDIS_URL: 'redis://redis:6379/' + depends_on: + - redis + - kafka + plugins: command: ./bin/plugin-server --no-restart-loop restart: on-failure diff --git a/docker-compose.dev-full.yml b/docker-compose.dev-full.yml index ba4a40185c7d6..6d62266e6b8a1 100644 --- a/docker-compose.dev-full.yml +++ b/docker-compose.dev-full.yml @@ -89,6 +89,15 @@ services: environment: - DEBUG=1 + capture: + extends: + file: docker-compose.base.yml + service: capture + ports: + - 3000:3000 + environment: + - DEBUG=1 + plugins: extends: file: docker-compose.base.yml diff --git a/docker-compose.dev.yml b/docker-compose.dev.yml index 2045dee0804c5..365ec2c5b452d 100644 --- a/docker-compose.dev.yml +++ b/docker-compose.dev.yml @@ -72,6 +72,17 @@ services: - '1080:1080' - '1025:1025' + # Optional capture + capture: + profiles: ['capture-rs'] + extends: + file: docker-compose.base.yml + service: capture + ports: + - 3000:3000 + environment: + - DEBUG=1 + # Temporal containers elasticsearch: extends: From 8b8cedf0524aa61de37a17074da869f0f4bbb31c Mon Sep 17 00:00:00 2001 From: David Newell Date: Wed, 25 Oct 2023 17:08:29 +0100 Subject: [PATCH 07/21] chore: update LemonUI types (#17755) --- .../src/lib/lemon-ui/LemonMenu/LemonMenu.tsx | 4 ++-- .../lib/lemon-ui/LemonSelect/LemonSelect.tsx | 2 +- .../src/lib/lemon-ui/LemonTable/TableRow.tsx | 4 +++- frontend/src/lib/lemon-ui/hooks.ts | 2 +- .../scenes/persons/RelatedFeatureFlags.tsx | 19 +++++++++++-------- 5 files changed, 18 insertions(+), 13 deletions(-) diff --git a/frontend/src/lib/lemon-ui/LemonMenu/LemonMenu.tsx b/frontend/src/lib/lemon-ui/LemonMenu/LemonMenu.tsx index 44e0a952e9646..c00145d40f449 100644 --- a/frontend/src/lib/lemon-ui/LemonMenu/LemonMenu.tsx +++ b/frontend/src/lib/lemon-ui/LemonMenu/LemonMenu.tsx @@ -98,7 +98,7 @@ export function LemonMenu({ ) const _onVisibilityChange = useCallback( - (visible) => { + (visible: boolean) => { onVisibilityChange?.(visible) if (visible && activeItemIndex && activeItemIndex > -1) { // Scroll the active item into view once the menu is open (i.e. in the next tick) @@ -256,7 +256,7 @@ const LemonMenuItemButton: FunctionComponent - {label} + {label as string | JSX.Element} {keyboardShortcut && (
{/* Show the keyboard shortcut on the right */} diff --git a/frontend/src/lib/lemon-ui/LemonSelect/LemonSelect.tsx b/frontend/src/lib/lemon-ui/LemonSelect/LemonSelect.tsx index 8b5c6ab2cdf70..5686b6af19412 100644 --- a/frontend/src/lib/lemon-ui/LemonSelect/LemonSelect.tsx +++ b/frontend/src/lib/lemon-ui/LemonSelect/LemonSelect.tsx @@ -93,7 +93,7 @@ export interface LemonSelectPropsNonClearable extends LemonSelectPropsBase export type LemonSelectProps = LemonSelectPropsClearable | LemonSelectPropsNonClearable -export function LemonSelect({ +export function LemonSelect({ value = null, onChange, onSelect, diff --git a/frontend/src/lib/lemon-ui/LemonTable/TableRow.tsx b/frontend/src/lib/lemon-ui/LemonTable/TableRow.tsx index e67c574711ec9..6071cc7b08183 100644 --- a/frontend/src/lib/lemon-ui/LemonTable/TableRow.tsx +++ b/frontend/src/lib/lemon-ui/LemonTable/TableRow.tsx @@ -132,6 +132,8 @@ function TableRowRaw>({ // of a class indicating that scrollability to `table` caused the component to lag due to unneded rerendering of rows. export const TableRow = React.memo(TableRowRaw) as typeof TableRowRaw -function isTableCellRepresentation(contents: React.ReactNode): contents is TableCellRepresentation { +function isTableCellRepresentation( + contents: React.ReactNode | TableCellRepresentation +): contents is TableCellRepresentation { return !!contents && typeof contents === 'object' && !React.isValidElement(contents) } diff --git a/frontend/src/lib/lemon-ui/hooks.ts b/frontend/src/lib/lemon-ui/hooks.ts index ba4afca720d23..32625c2d499bd 100644 --- a/frontend/src/lib/lemon-ui/hooks.ts +++ b/frontend/src/lib/lemon-ui/hooks.ts @@ -6,7 +6,7 @@ import { useLayoutEffect, useRef, useState } from 'react' * @private */ export function useSliderPositioning( - currentValue: string | number | null | undefined, + currentValue: React.Key | null | undefined, transitionMs: number ): { containerRef: React.RefObject diff --git a/frontend/src/scenes/persons/RelatedFeatureFlags.tsx b/frontend/src/scenes/persons/RelatedFeatureFlags.tsx index 08a3d1e23dc6f..ffef288d633f5 100644 --- a/frontend/src/scenes/persons/RelatedFeatureFlags.tsx +++ b/frontend/src/scenes/persons/RelatedFeatureFlags.tsx @@ -117,6 +117,16 @@ export function RelatedFeatureFlags({ distinctId, groups }: Props): JSX.Element }, }, ] + + const options = [ + { label: 'All types', value: 'all' }, + { + label: FeatureFlagReleaseType.ReleaseToggle, + value: FeatureFlagReleaseType.ReleaseToggle, + }, + { label: FeatureFlagReleaseType.Variants, value: FeatureFlagReleaseType.Variants }, + ] + return ( <>
@@ -131,14 +141,7 @@ export function RelatedFeatureFlags({ distinctId, groups }: Props): JSX.Element Type { if (type) { if (type === 'all') { From 4fc05e34c38062f7f73f9cc4d69fea874b3ac3e2 Mon Sep 17 00:00:00 2001 From: David Newell Date: Wed, 25 Oct 2023 17:13:59 +0100 Subject: [PATCH 08/21] chore: upgrade eslint (#18186) --- .../LemonCalendarRangeInline.tsx | 1 + .../src/scenes/billing/BillingLimitInput.tsx | 14 +- .../src/scenes/billing/billingProductLogic.ts | 12 +- .../scenes/experiments/experimentLogic.tsx | 2 +- .../scenes/feature-flags/featureFlagLogic.ts | 7 +- frontend/src/scenes/trends/trendsDataLogic.ts | 2 +- package.json | 18 +- pnpm-lock.yaml | 1273 +++++++++++------ 8 files changed, 890 insertions(+), 439 deletions(-) diff --git a/frontend/src/lib/lemon-ui/LemonCalendarRange/LemonCalendarRangeInline.tsx b/frontend/src/lib/lemon-ui/LemonCalendarRange/LemonCalendarRangeInline.tsx index 698d891ac33cf..8a25fd4d1fae1 100644 --- a/frontend/src/lib/lemon-ui/LemonCalendarRange/LemonCalendarRangeInline.tsx +++ b/frontend/src/lib/lemon-ui/LemonCalendarRange/LemonCalendarRangeInline.tsx @@ -33,6 +33,7 @@ export function LemonCalendarRangeInline({ // How many months fit on the screen, capped between 1..2 function getMonthCount(): number { const width = + // eslint-disable-next-line valid-typeof typeof window === undefined ? WIDTH_OF_ONE_CALENDAR_MONTH * CALENDARS_IF_NO_WINDOW : window.innerWidth return Math.min(Math.max(1, Math.floor(width / WIDTH_OF_ONE_CALENDAR_MONTH)), 2) } diff --git a/frontend/src/scenes/billing/BillingLimitInput.tsx b/frontend/src/scenes/billing/BillingLimitInput.tsx index f644f22dd8f86..6f1dd652a4acb 100644 --- a/frontend/src/scenes/billing/BillingLimitInput.tsx +++ b/frontend/src/scenes/billing/BillingLimitInput.tsx @@ -25,12 +25,14 @@ export const BillingLimitInput = ({ product }: { product: BillingProductV2Type } if (value === undefined) { return actuallyUpdateLimit() } - const productAndAddonTiers: BillingV2TierType[][] = [ - product.tiers, - ...product.addons - ?.filter((addon: BillingProductV2AddonType) => addon.subscribed) - ?.map((addon: BillingProductV2AddonType) => addon.tiers), - ].filter(Boolean) as BillingV2TierType[][] + + const addonTiers = product.addons + ?.filter((addon: BillingProductV2AddonType) => addon.subscribed) + ?.map((addon: BillingProductV2AddonType) => addon.tiers) + + const productAndAddonTiers: BillingV2TierType[][] = [product.tiers, ...addonTiers].filter( + Boolean + ) as BillingV2TierType[][] const newAmountAsUsage = product.tiers ? convertAmountToUsage(`${value}`, productAndAddonTiers, billing?.discount_percent) diff --git a/frontend/src/scenes/billing/billingProductLogic.ts b/frontend/src/scenes/billing/billingProductLogic.ts index 7b26b0562f68f..07641dbb725c6 100644 --- a/frontend/src/scenes/billing/billingProductLogic.ts +++ b/frontend/src/scenes/billing/billingProductLogic.ts @@ -101,12 +101,12 @@ export const billingProductLogic = kea([ (billing, product, isEditingBillingLimit, billingLimitInput, customLimitUsd) => { // cast the product as a product, not an addon, to avoid TS errors. This is fine since we're just getting the tiers. product = product as BillingProductV2Type - const productAndAddonTiers: BillingV2TierType[][] = [ - product.tiers, - ...product.addons - ?.filter((addon: BillingProductV2AddonType) => addon.subscribed) - ?.map((addon: BillingProductV2AddonType) => addon.tiers), - ].filter(Boolean) as BillingV2TierType[][] + const addonTiers = product.addons + ?.filter((addon: BillingProductV2AddonType) => addon.subscribed) + ?.map((addon: BillingProductV2AddonType) => addon.tiers) + const productAndAddonTiers: BillingV2TierType[][] = [product.tiers, ...addonTiers].filter( + Boolean + ) as BillingV2TierType[][] return product.tiers ? isEditingBillingLimit ? convertAmountToUsage(`${billingLimitInput}`, productAndAddonTiers, billing?.discount_percent) diff --git a/frontend/src/scenes/experiments/experimentLogic.tsx b/frontend/src/scenes/experiments/experimentLogic.tsx index 9e9068689e1fc..b75e1c68251a0 100644 --- a/frontend/src/scenes/experiments/experimentLogic.tsx +++ b/frontend/src/scenes/experiments/experimentLogic.tsx @@ -802,7 +802,7 @@ export const experimentLogic = kea([ let index = -1 if (insightType === InsightType.FUNNELS) { // Funnel Insight is displayed in order of decreasing count - index = ([...experimentResults?.insight] as FunnelStep[][]) + index = ([...experimentResults.insight] as FunnelStep[][]) .sort((a, b) => b[0]?.count - a[0]?.count) .findIndex( (variantFunnel: FunnelStep[]) => variantFunnel[0]?.breakdown_value?.[0] === variant diff --git a/frontend/src/scenes/feature-flags/featureFlagLogic.ts b/frontend/src/scenes/feature-flags/featureFlagLogic.ts index 0ea7e1154bbcf..172ca75db8329 100644 --- a/frontend/src/scenes/feature-flags/featureFlagLogic.ts +++ b/frontend/src/scenes/feature-flags/featureFlagLogic.ts @@ -266,7 +266,10 @@ export const featureFlagLogic = kea([ if (!state) { return state } - const groups = [...state?.filters.groups, { properties: [], rollout_percentage: 0, variant: null }] + const groups = [ + ...(state?.filters?.groups || []), + { properties: [], rollout_percentage: 0, variant: null }, + ] return { ...state, filters: { ...state.filters, groups } } }, addRollbackCondition: (state) => { @@ -291,7 +294,7 @@ export const featureFlagLogic = kea([ return state } - const groups = [...state?.filters.groups] + const groups = [...(state?.filters?.groups || [])] if (newRolloutPercentage !== undefined) { groups[index] = { ...groups[index], rollout_percentage: newRolloutPercentage } } diff --git a/frontend/src/scenes/trends/trendsDataLogic.ts b/frontend/src/scenes/trends/trendsDataLogic.ts index 06e95485b8e80..5ee67ec453f4e 100644 --- a/frontend/src/scenes/trends/trendsDataLogic.ts +++ b/frontend/src/scenes/trends/trendsDataLogic.ts @@ -143,7 +143,7 @@ export const trendsDataLogic = kea([ actions.setInsightData({ ...values.insightData, - result: [...values.insightData?.result, ...(response.result ? response.result : [])], + result: [...values.insightData.result, ...(response.result ? response.result : [])], next: response.next, }) diff --git a/package.json b/package.json index fcc8195b58513..c9e9da96b221d 100644 --- a/package.json +++ b/package.json @@ -229,8 +229,8 @@ "@types/react-virtualized": "^9.21.14", "@types/testing-library__jest-dom": "^5.14.5", "@types/zxcvbn": "^4.4.0", - "@typescript-eslint/eslint-plugin": "^6.4.0", - "@typescript-eslint/parser": "^6.4.0", + "@typescript-eslint/eslint-plugin": "^6.9.0", + "@typescript-eslint/parser": "^6.9.0", "autoprefixer": "^10.4.7", "axe-core": "^4.4.3", "babel-loader": "^8.0.6", @@ -241,15 +241,15 @@ "cypress": "^13.3.0", "cypress-axe": "^1.5.0", "cypress-terminal-report": "^5.3.7", - "eslint": "^7.8.0", - "eslint-config-prettier": "^8.8.0", + "eslint": "^8.52.0", + "eslint-config-prettier": "^9.0.0", "eslint-plugin-compat": "^4.2.0", - "eslint-plugin-cypress": "^2.13.3", + "eslint-plugin-cypress": "^2.15.1", "eslint-plugin-eslint-comments": "^3.2.0", - "eslint-plugin-jest": "^27.2.3", - "eslint-plugin-no-only-tests": "^3.0.0", - "eslint-plugin-prettier": "^3.1.4", - "eslint-plugin-react": "^7.32.2", + "eslint-plugin-jest": "^27.4.3", + "eslint-plugin-no-only-tests": "^3.1.0", + "eslint-plugin-prettier": "^5.0.1", + "eslint-plugin-react": "^7.33.2", "eslint-plugin-storybook": "^0.6.15", "file-loader": "^6.1.0", "givens": "^1.3.6", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4c20f9d5853c4..d3710208675fd 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -487,11 +487,11 @@ devDependencies: specifier: ^4.4.0 version: 4.4.1 '@typescript-eslint/eslint-plugin': - specifier: ^6.4.0 - version: 6.4.0(@typescript-eslint/parser@6.4.0)(eslint@7.32.0)(typescript@4.9.5) + specifier: ^6.9.0 + version: 6.9.0(@typescript-eslint/parser@6.9.0)(eslint@8.52.0)(typescript@4.9.5) '@typescript-eslint/parser': - specifier: ^6.4.0 - version: 6.4.0(eslint@7.32.0)(typescript@4.9.5) + specifier: ^6.9.0 + version: 6.9.0(eslint@8.52.0)(typescript@4.9.5) autoprefixer: specifier: ^10.4.7 version: 10.4.13(postcss@8.4.31) @@ -523,35 +523,35 @@ devDependencies: specifier: ^5.3.7 version: 5.3.7(cypress@13.3.0) eslint: - specifier: ^7.8.0 - version: 7.32.0 + specifier: ^8.52.0 + version: 8.52.0 eslint-config-prettier: - specifier: ^8.8.0 - version: 8.8.0(eslint@7.32.0) + specifier: ^9.0.0 + version: 9.0.0(eslint@8.52.0) eslint-plugin-compat: specifier: ^4.2.0 - version: 4.2.0(eslint@7.32.0) + version: 4.2.0(eslint@8.52.0) eslint-plugin-cypress: - specifier: ^2.13.3 - version: 2.13.3(eslint@7.32.0) + specifier: ^2.15.1 + version: 2.15.1(eslint@8.52.0) eslint-plugin-eslint-comments: specifier: ^3.2.0 - version: 3.2.0(eslint@7.32.0) + version: 3.2.0(eslint@8.52.0) eslint-plugin-jest: - specifier: ^27.2.3 - version: 27.2.3(@typescript-eslint/eslint-plugin@6.4.0)(eslint@7.32.0)(jest@29.3.1)(typescript@4.9.5) + specifier: ^27.4.3 + version: 27.4.3(@typescript-eslint/eslint-plugin@6.9.0)(eslint@8.52.0)(jest@29.3.1)(typescript@4.9.5) eslint-plugin-no-only-tests: - specifier: ^3.0.0 + specifier: ^3.1.0 version: 3.1.0 eslint-plugin-prettier: - specifier: ^3.1.4 - version: 3.4.1(eslint-config-prettier@8.8.0)(eslint@7.32.0)(prettier@2.8.8) + specifier: ^5.0.1 + version: 5.0.1(eslint-config-prettier@9.0.0)(eslint@8.52.0)(prettier@2.8.8) eslint-plugin-react: - specifier: ^7.32.2 - version: 7.32.2(eslint@7.32.0) + specifier: ^7.33.2 + version: 7.33.2(eslint@8.52.0) eslint-plugin-storybook: specifier: ^0.6.15 - version: 0.6.15(eslint@7.32.0)(typescript@4.9.5) + version: 0.6.15(eslint@8.52.0)(typescript@4.9.5) file-loader: specifier: ^6.1.0 version: 6.2.0(webpack@5.88.2) @@ -663,6 +663,11 @@ devDependencies: packages: + /@aashutoshrathi/word-wrap@1.2.6: + resolution: {integrity: sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==} + engines: {node: '>=0.10.0'} + dev: true + /@adobe/css-tools@4.0.1: resolution: {integrity: sha512-+u76oB43nOHrF4DDWRLWDCtci7f3QJoEBigemIdIeTi1ODqjx6Tad9NCVnPRwewWlKkVab5PlK8DCtPTyX7S8g==} dev: true @@ -720,12 +725,6 @@ packages: default-browser-id: 3.0.0 dev: true - /@babel/code-frame@7.12.11: - resolution: {integrity: sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==} - dependencies: - '@babel/highlight': 7.22.10 - dev: true - /@babel/code-frame@7.22.10: resolution: {integrity: sha512-/KKIMG4UEL35WmI9OlvMhurwtytjvXoFcGNrOvyG9zIzA8YmPjVtIZUf7b05+TPO7G7/GEmLHDaoCgACHl9hhA==} engines: {node: '>=6.9.0'} @@ -830,7 +829,7 @@ packages: '@babel/helper-plugin-utils': 7.22.5 debug: 4.3.4(supports-color@8.1.1) lodash.debounce: 4.0.8 - resolve: 1.22.1 + resolve: 1.22.8 transitivePeerDependencies: - supports-color @@ -2432,38 +2431,43 @@ packages: dev: true optional: true - /@eslint-community/eslint-utils@4.4.0(eslint@7.32.0): + /@eslint-community/eslint-utils@4.4.0(eslint@8.52.0): resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 dependencies: - eslint: 7.32.0 + eslint: 8.52.0 eslint-visitor-keys: 3.4.3 dev: true - /@eslint-community/regexpp@4.6.2: - resolution: {integrity: sha512-pPTNuaAG3QMH+buKyBIGJs3g/S5y0caxw0ygM3YyE6yJFySwiGGSzA+mM3KJ8QQvzeLh3blwgSonkFjgQdxzMw==} + /@eslint-community/regexpp@4.9.1: + resolution: {integrity: sha512-Y27x+MBLjXa+0JWDhykM3+JE+il3kHKAEqabfEWq3SDhZjLYb6/BHL/JKFnH3fe207JaXkyDo685Oc2Glt6ifA==} engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} dev: true - /@eslint/eslintrc@0.4.3: - resolution: {integrity: sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw==} - engines: {node: ^10.12.0 || >=12.0.0} + /@eslint/eslintrc@2.1.2: + resolution: {integrity: sha512-+wvgpDsrB1YqAMdEUCcnTlpfVBH7Vqn6A/NT3D8WVXFIaKMlErPIZT3oCIAVCOtarRpMtelZLqJeU3t7WY6X6g==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dependencies: ajv: 6.12.6 debug: 4.3.4(supports-color@8.1.1) - espree: 7.3.1 - globals: 13.17.0 - ignore: 4.0.6 + espree: 9.6.1 + globals: 13.23.0 + ignore: 5.2.4 import-fresh: 3.3.0 - js-yaml: 3.14.1 + js-yaml: 4.1.0 minimatch: 3.1.2 strip-json-comments: 3.1.1 transitivePeerDependencies: - supports-color dev: true + /@eslint/js@8.52.0: + resolution: {integrity: sha512-mjZVbpaeMZludF2fsWLD0Z9gCref1Tk4i9+wddjRvpUNqqcndPkBD09N/Mapey0b3jaXbLm2kICwFv2E64QinA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dev: true + /@fal-works/esbuild-plugin-global-externals@2.1.2: resolution: {integrity: sha512-cEee/Z+I12mZcFJshKcCqC8tuX5hG3s+d+9nZ3LabqKF1vKdF41B92pJVCBggjAGORAeOzyyDDKrZwIkLffeOQ==} dev: true @@ -2541,19 +2545,24 @@ packages: scheduler: 0.19.1 dev: true - /@humanwhocodes/config-array@0.5.0: - resolution: {integrity: sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg==} + /@humanwhocodes/config-array@0.11.13: + resolution: {integrity: sha512-JSBDMiDKSzQVngfRjOdFXgFfklaXI4K9nLF49Auh21lmBWRLIK3+xTErTWD4KU54pb6coM6ESE7Awz/FNU3zgQ==} engines: {node: '>=10.10.0'} dependencies: - '@humanwhocodes/object-schema': 1.2.1 + '@humanwhocodes/object-schema': 2.0.1 debug: 4.3.4(supports-color@8.1.1) minimatch: 3.1.2 transitivePeerDependencies: - supports-color dev: true - /@humanwhocodes/object-schema@1.2.1: - resolution: {integrity: sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==} + /@humanwhocodes/module-importer@1.0.1: + resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} + engines: {node: '>=12.22'} + dev: true + + /@humanwhocodes/object-schema@2.0.1: + resolution: {integrity: sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==} dev: true /@isaacs/cliui@8.0.2: @@ -3207,7 +3216,7 @@ packages: engines: {node: '>= 8'} dependencies: '@nodelib/fs.scandir': 2.1.5 - fastq: 1.13.0 + fastq: 1.15.0 dev: true /@open-draft/until@1.0.3: @@ -3221,6 +3230,18 @@ packages: dev: true optional: true + /@pkgr/utils@2.4.2: + resolution: {integrity: sha512-POgTXhjrTfbTV63DiFXav4lBHiICLKKwDeaKn9Nphwj7WH6m0hMMCaJkMyRWjgtPFyRKRVoMXXjczsTQRDEhYw==} + engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} + dependencies: + cross-spawn: 7.0.3 + fast-glob: 3.3.1 + is-glob: 4.0.3 + open: 9.1.0 + picocolors: 1.0.0 + tslib: 2.6.2 + dev: true + /@playwright/test@1.29.2: resolution: {integrity: sha512-+3/GPwOgcoF0xLz/opTnahel1/y42PdcgZ4hs+BZGIUjtmEFSXGg+nFoaH3NSmuc7a6GSFwXDJ5L7VXpqzigNg==} engines: {node: '>=14'} @@ -4903,7 +4924,7 @@ packages: flat-cache: 3.0.4 micromatch: 4.0.5 react-docgen-typescript: 2.2.2(typescript@4.9.5) - tslib: 2.4.1 + tslib: 2.6.2 typescript: 4.9.5 webpack: 5.88.2(@swc/core@1.3.93)(esbuild@0.14.54)(webpack-cli@5.1.4) transitivePeerDependencies: @@ -6059,6 +6080,10 @@ packages: resolution: {integrity: sha512-Hr5Jfhc9eYOQNPYO5WLDq/n4jqijdHNlDXjuAQkkt+mWdQR+XJToOHrsD4cPaMXpn6KO7y2+wM8AZEs8VpBLVA==} dev: true + /@types/json-schema@7.0.14: + resolution: {integrity: sha512-U3PUjAudAdJBeC2pgN8uTIKgxrb4nlDF3SF0++EldXQvQBGkpFZMSnwQiIoDU77tv45VgNkl/L4ouD+rEomujw==} + dev: true + /@types/less@3.0.3: resolution: {integrity: sha512-1YXyYH83h6We1djyoUEqTlVyQtCfJAFXELSKW2ZRtjHD4hQ82CC4lvrv5D0l0FLcKBaiPbXyi3MpMsI9ZRgKsw==} dev: false @@ -6248,6 +6273,10 @@ packages: resolution: {integrity: sha512-G8hZ6XJiHnuhQKR7ZmysCeJWE08o8T0AXtk5darsCaTVsYZhhgUrq53jizaR2FvsoeCwJhlmwTjkXBY5Pn/ZHw==} dev: true + /@types/semver@7.5.4: + resolution: {integrity: sha512-MMzuxN3GdFwskAnb6fz0orFvhfqi752yjaXylr0Rp4oDg5H0Zn1IuyRhDVvYOwAXoJirx2xuS16I3WjxnAIHiQ==} + dev: true + /@types/send@0.17.3: resolution: {integrity: sha512-/7fKxvKUoETxjFUsuFlPB9YndePpxxRAOfGC/yJdc9kTjTeP5kRCTzfnE8kPUKCeyiyIZu0YQ76s50hCedI1ug==} dependencies: @@ -6336,8 +6365,8 @@ packages: resolution: {integrity: sha512-3NoqvZC2W5gAC5DZbTpCeJ251vGQmgcWIHQJGq2J240HY6ErQ9aWKkwfoKJlHLx+A83WPNTZ9+3cd2ILxbvr1w==} dev: true - /@typescript-eslint/eslint-plugin@6.4.0(@typescript-eslint/parser@6.4.0)(eslint@7.32.0)(typescript@4.9.5): - resolution: {integrity: sha512-62o2Hmc7Gs3p8SLfbXcipjWAa6qk2wZGChXG2JbBtYpwSRmti/9KHLqfbLs9uDigOexG+3PaQ9G2g3201FWLKg==} + /@typescript-eslint/eslint-plugin@6.9.0(@typescript-eslint/parser@6.9.0)(eslint@8.52.0)(typescript@4.9.5): + resolution: {integrity: sha512-lgX7F0azQwRPB7t7WAyeHWVfW1YJ9NIgd9mvGhfQpRY56X6AVf8mwM8Wol+0z4liE7XX3QOt8MN1rUKCfSjRIA==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: '@typescript-eslint/parser': ^6.0.0 || ^6.0.0-alpha @@ -6347,26 +6376,26 @@ packages: typescript: optional: true dependencies: - '@eslint-community/regexpp': 4.6.2 - '@typescript-eslint/parser': 6.4.0(eslint@7.32.0)(typescript@4.9.5) - '@typescript-eslint/scope-manager': 6.4.0 - '@typescript-eslint/type-utils': 6.4.0(eslint@7.32.0)(typescript@4.9.5) - '@typescript-eslint/utils': 6.4.0(eslint@7.32.0)(typescript@4.9.5) - '@typescript-eslint/visitor-keys': 6.4.0 + '@eslint-community/regexpp': 4.9.1 + '@typescript-eslint/parser': 6.9.0(eslint@8.52.0)(typescript@4.9.5) + '@typescript-eslint/scope-manager': 6.9.0 + '@typescript-eslint/type-utils': 6.9.0(eslint@8.52.0)(typescript@4.9.5) + '@typescript-eslint/utils': 6.9.0(eslint@8.52.0)(typescript@4.9.5) + '@typescript-eslint/visitor-keys': 6.9.0 debug: 4.3.4(supports-color@8.1.1) - eslint: 7.32.0 + eslint: 8.52.0 graphemer: 1.4.0 ignore: 5.2.4 natural-compare: 1.4.0 semver: 7.5.4 - ts-api-utils: 1.0.2(typescript@4.9.5) + ts-api-utils: 1.0.3(typescript@4.9.5) typescript: 4.9.5 transitivePeerDependencies: - supports-color dev: true - /@typescript-eslint/parser@6.4.0(eslint@7.32.0)(typescript@4.9.5): - resolution: {integrity: sha512-I1Ah1irl033uxjxO9Xql7+biL3YD7w9IU8zF+xlzD/YxY6a4b7DYA08PXUUCbm2sEljwJF6ERFy2kTGAGcNilg==} + /@typescript-eslint/parser@6.9.0(eslint@8.52.0)(typescript@4.9.5): + resolution: {integrity: sha512-GZmjMh4AJ/5gaH4XF2eXA8tMnHWP+Pm1mjQR2QN4Iz+j/zO04b9TOvJYOX2sCNIQHtRStKTxRY1FX7LhpJT4Gw==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: eslint: ^7.0.0 || ^8.0.0 @@ -6375,12 +6404,12 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/scope-manager': 6.4.0 - '@typescript-eslint/types': 6.4.0 - '@typescript-eslint/typescript-estree': 6.4.0(typescript@4.9.5) - '@typescript-eslint/visitor-keys': 6.4.0 + '@typescript-eslint/scope-manager': 6.9.0 + '@typescript-eslint/types': 6.9.0 + '@typescript-eslint/typescript-estree': 6.9.0(typescript@4.9.5) + '@typescript-eslint/visitor-keys': 6.9.0 debug: 4.3.4(supports-color@8.1.1) - eslint: 7.32.0 + eslint: 8.52.0 typescript: 4.9.5 transitivePeerDependencies: - supports-color @@ -6394,16 +6423,16 @@ packages: '@typescript-eslint/visitor-keys': 5.55.0 dev: true - /@typescript-eslint/scope-manager@6.4.0: - resolution: {integrity: sha512-TUS7vaKkPWDVvl7GDNHFQMsMruD+zhkd3SdVW0d7b+7Zo+bd/hXJQ8nsiUZMi1jloWo6c9qt3B7Sqo+flC1nig==} + /@typescript-eslint/scope-manager@6.9.0: + resolution: {integrity: sha512-1R8A9Mc39n4pCCz9o79qRO31HGNDvC7UhPhv26TovDsWPBDx+Sg3rOZdCELIA3ZmNoWAuxaMOT7aWtGRSYkQxw==} engines: {node: ^16.0.0 || >=18.0.0} dependencies: - '@typescript-eslint/types': 6.4.0 - '@typescript-eslint/visitor-keys': 6.4.0 + '@typescript-eslint/types': 6.9.0 + '@typescript-eslint/visitor-keys': 6.9.0 dev: true - /@typescript-eslint/type-utils@6.4.0(eslint@7.32.0)(typescript@4.9.5): - resolution: {integrity: sha512-TvqrUFFyGY0cX3WgDHcdl2/mMCWCDv/0thTtx/ODMY1QhEiyFtv/OlLaNIiYLwRpAxAtOLOY9SUf1H3Q3dlwAg==} + /@typescript-eslint/type-utils@6.9.0(eslint@8.52.0)(typescript@4.9.5): + resolution: {integrity: sha512-XXeahmfbpuhVbhSOROIzJ+b13krFmgtc4GlEuu1WBT+RpyGPIA4Y/eGnXzjbDj5gZLzpAXO/sj+IF/x2GtTMjQ==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: eslint: ^7.0.0 || ^8.0.0 @@ -6412,11 +6441,11 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/typescript-estree': 6.4.0(typescript@4.9.5) - '@typescript-eslint/utils': 6.4.0(eslint@7.32.0)(typescript@4.9.5) + '@typescript-eslint/typescript-estree': 6.9.0(typescript@4.9.5) + '@typescript-eslint/utils': 6.9.0(eslint@8.52.0)(typescript@4.9.5) debug: 4.3.4(supports-color@8.1.1) - eslint: 7.32.0 - ts-api-utils: 1.0.2(typescript@4.9.5) + eslint: 8.52.0 + ts-api-utils: 1.0.3(typescript@4.9.5) typescript: 4.9.5 transitivePeerDependencies: - supports-color @@ -6427,8 +6456,8 @@ packages: engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dev: true - /@typescript-eslint/types@6.4.0: - resolution: {integrity: sha512-+FV9kVFrS7w78YtzkIsNSoYsnOtrYVnKWSTVXoL1761CsCRv5wpDOINgsXpxD67YCLZtVQekDDyaxfjVWUJmmg==} + /@typescript-eslint/types@6.9.0: + resolution: {integrity: sha512-+KB0lbkpxBkBSiVCuQvduqMJy+I1FyDbdwSpM3IoBS7APl4Bu15lStPjgBIdykdRqQNYqYNMa8Kuidax6phaEw==} engines: {node: ^16.0.0 || >=18.0.0} dev: true @@ -6453,8 +6482,8 @@ packages: - supports-color dev: true - /@typescript-eslint/typescript-estree@6.4.0(typescript@4.9.5): - resolution: {integrity: sha512-iDPJArf/K2sxvjOR6skeUCNgHR/tCQXBsa+ee1/clRKr3olZjZ/dSkXPZjG6YkPtnW6p5D1egeEPMCW6Gn4yLA==} + /@typescript-eslint/typescript-estree@6.9.0(typescript@4.9.5): + resolution: {integrity: sha512-NJM2BnJFZBEAbCfBP00zONKXvMqihZCrmwCaik0UhLr0vAgb6oguXxLX1k00oQyD+vZZ+CJn3kocvv2yxm4awQ==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: typescript: '*' @@ -6462,31 +6491,31 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/types': 6.4.0 - '@typescript-eslint/visitor-keys': 6.4.0 + '@typescript-eslint/types': 6.9.0 + '@typescript-eslint/visitor-keys': 6.9.0 debug: 4.3.4(supports-color@8.1.1) globby: 11.1.0 is-glob: 4.0.3 semver: 7.5.4 - ts-api-utils: 1.0.2(typescript@4.9.5) + ts-api-utils: 1.0.3(typescript@4.9.5) typescript: 4.9.5 transitivePeerDependencies: - supports-color dev: true - /@typescript-eslint/utils@5.55.0(eslint@7.32.0)(typescript@4.9.5): + /@typescript-eslint/utils@5.55.0(eslint@8.52.0)(typescript@4.9.5): resolution: {integrity: sha512-FkW+i2pQKcpDC3AY6DU54yl8Lfl14FVGYDgBTyGKB75cCwV3KpkpTMFi9d9j2WAJ4271LR2HeC5SEWF/CZmmfw==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@7.32.0) + '@eslint-community/eslint-utils': 4.4.0(eslint@8.52.0) '@types/json-schema': 7.0.12 '@types/semver': 7.5.0 '@typescript-eslint/scope-manager': 5.55.0 '@typescript-eslint/types': 5.55.0 '@typescript-eslint/typescript-estree': 5.55.0(typescript@4.9.5) - eslint: 7.32.0 + eslint: 8.52.0 eslint-scope: 5.1.1 semver: 7.5.4 transitivePeerDependencies: @@ -6494,19 +6523,19 @@ packages: - typescript dev: true - /@typescript-eslint/utils@6.4.0(eslint@7.32.0)(typescript@4.9.5): - resolution: {integrity: sha512-BvvwryBQpECPGo8PwF/y/q+yacg8Hn/2XS+DqL/oRsOPK+RPt29h5Ui5dqOKHDlbXrAeHUTnyG3wZA0KTDxRZw==} + /@typescript-eslint/utils@6.9.0(eslint@8.52.0)(typescript@4.9.5): + resolution: {integrity: sha512-5Wf+Jsqya7WcCO8me504FBigeQKVLAMPmUzYgDbWchINNh1KJbxCgVya3EQ2MjvJMVeXl3pofRmprqX6mfQkjQ==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: eslint: ^7.0.0 || ^8.0.0 dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@7.32.0) - '@types/json-schema': 7.0.12 - '@types/semver': 7.5.0 - '@typescript-eslint/scope-manager': 6.4.0 - '@typescript-eslint/types': 6.4.0 - '@typescript-eslint/typescript-estree': 6.4.0(typescript@4.9.5) - eslint: 7.32.0 + '@eslint-community/eslint-utils': 4.4.0(eslint@8.52.0) + '@types/json-schema': 7.0.14 + '@types/semver': 7.5.4 + '@typescript-eslint/scope-manager': 6.9.0 + '@typescript-eslint/types': 6.9.0 + '@typescript-eslint/typescript-estree': 6.9.0(typescript@4.9.5) + eslint: 8.52.0 semver: 7.5.4 transitivePeerDependencies: - supports-color @@ -6521,14 +6550,18 @@ packages: eslint-visitor-keys: 3.4.3 dev: true - /@typescript-eslint/visitor-keys@6.4.0: - resolution: {integrity: sha512-yJSfyT+uJm+JRDWYRYdCm2i+pmvXJSMtPR9Cq5/XQs4QIgNoLcoRtDdzsLbLsFM/c6um6ohQkg/MLxWvoIndJA==} + /@typescript-eslint/visitor-keys@6.9.0: + resolution: {integrity: sha512-dGtAfqjV6RFOtIP8I0B4ZTBRrlTT8NHHlZZSchQx3qReaoDeXhYM++M4So2AgFK9ZB0emRPA6JI1HkafzA2Ibg==} engines: {node: ^16.0.0 || >=18.0.0} dependencies: - '@typescript-eslint/types': 6.4.0 + '@typescript-eslint/types': 6.9.0 eslint-visitor-keys: 3.4.3 dev: true + /@ungap/structured-clone@1.2.0: + resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==} + dev: true + /@webassemblyjs/ast@1.11.6: resolution: {integrity: sha512-IN1xI7PwOvLPgjcf180gC1bqn3q/QaOCwYUahIOhbYUu8KA/3tw2RT/T0Gidi1l7Hhj5D/INhJxiICObqpMu4Q==} dependencies: @@ -6700,7 +6733,7 @@ packages: esbuild: '>=0.10.0' dependencies: esbuild: 0.18.20 - tslib: 2.4.1 + tslib: 2.6.2 dev: true /@yarnpkg/fslib@2.10.3: @@ -6759,6 +6792,14 @@ packages: acorn: 7.4.1 dev: true + /acorn-jsx@5.3.2(acorn@8.10.0): + resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} + peerDependencies: + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + dependencies: + acorn: 8.10.0 + dev: true + /acorn-walk@7.2.0: resolution: {integrity: sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==} engines: {node: '>=0.4.0'} @@ -6874,7 +6915,7 @@ packages: resolution: {integrity: sha512-IG23inYII3dWlU2EyiAiGj6Bwal5GzsgPMwjYGvc1HPE2dgbj4ZB5ToWBKSquKw74nB3TIuOwaI6/jSULzfgrw==} engines: {node: '>=14.16'} dependencies: - type-fest: 3.5.3 + type-fest: 3.13.1 dev: true /ansi-html-community@0.0.8: @@ -7020,7 +7061,6 @@ packages: /argparse@2.0.1: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} - dev: false /aria-hidden@1.2.1(@types/react@16.14.34)(react@16.14.0): resolution: {integrity: sha512-PN344VAf9j1EAi+jyVHOJ8XidQdPVssGco39eNcsGdM4wcsILtxrKLkbuiMfLWYROK1FjRQasMWCBttrhjnr6A==} @@ -7041,17 +7081,24 @@ packages: dependencies: deep-equal: 2.1.0 + /array-buffer-byte-length@1.0.0: + resolution: {integrity: sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==} + dependencies: + call-bind: 1.0.5 + is-array-buffer: 3.0.2 + dev: true + /array-flatten@1.1.1: resolution: {integrity: sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==} - /array-includes@3.1.6: - resolution: {integrity: sha512-sgTbLvL6cNnw24FnbaDyjmvddQ2ML8arZsgaJhoABMoplz/4QRhtrYS+alr1BUM1Bwp6dhx8vVCBSLG+StwOFw==} + /array-includes@3.1.7: + resolution: {integrity: sha512-dlcsNBIiWhPkHdOEEKnehA+RNUWDc4UqFtnIXU4uuYDPtA4LDkr7qip2p0VvFAEXNDr0yWZ9PJyIRiGjRLQzwQ==} engines: {node: '>= 0.4'} dependencies: - call-bind: 1.0.2 - define-properties: 1.1.4 - es-abstract: 1.20.4 - get-intrinsic: 1.1.3 + call-bind: 1.0.5 + define-properties: 1.2.1 + es-abstract: 1.22.3 + get-intrinsic: 1.2.2 is-string: 1.0.7 dev: true @@ -7064,35 +7111,58 @@ packages: engines: {node: '>=8'} dev: true - /array.prototype.flatmap@1.3.1: - resolution: {integrity: sha512-8UGn9O1FDVvMNB0UlLv4voxRMze7+FpHyF5mSMRjWHUMlpoDViniy05870VlxhfgTnLbpuwTzvD76MTtWxB/mQ==} + /array.prototype.flat@1.3.2: + resolution: {integrity: sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==} engines: {node: '>= 0.4'} dependencies: - call-bind: 1.0.2 - define-properties: 1.1.4 - es-abstract: 1.20.4 - es-shim-unscopables: 1.0.0 + call-bind: 1.0.5 + define-properties: 1.2.1 + es-abstract: 1.22.3 + es-shim-unscopables: 1.0.2 + dev: true + + /array.prototype.flatmap@1.3.2: + resolution: {integrity: sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.5 + define-properties: 1.2.1 + es-abstract: 1.22.3 + es-shim-unscopables: 1.0.2 dev: true /array.prototype.reduce@1.0.5: resolution: {integrity: sha512-kDdugMl7id9COE8R7MHF5jWk7Dqt/fs4Pv+JXoICnYwqpjjjbUurz6w5fT5IG6brLdJhv6/VoHB0H7oyIBXd+Q==} engines: {node: '>= 0.4'} dependencies: - call-bind: 1.0.2 - define-properties: 1.1.4 - es-abstract: 1.20.4 + call-bind: 1.0.5 + define-properties: 1.2.1 + es-abstract: 1.22.3 es-array-method-boxes-properly: 1.0.0 is-string: 1.0.7 dev: true - /array.prototype.tosorted@1.1.1: - resolution: {integrity: sha512-pZYPXPRl2PqWcsUs6LOMn+1f1532nEoPTYowBtqLwAW+W8vSVhkIGnmOX1t/UQjD6YGI0vcD2B1U7ZFGQH9jnQ==} + /array.prototype.tosorted@1.1.2: + resolution: {integrity: sha512-HuQCHOlk1Weat5jzStICBCd83NxiIMwqDg/dHEsoefabn/hJRj5pVdWcPUSpRrwhwxZOsQassMpgN/xRYFBMIg==} + dependencies: + call-bind: 1.0.5 + define-properties: 1.2.1 + es-abstract: 1.22.3 + es-shim-unscopables: 1.0.2 + get-intrinsic: 1.2.2 + dev: true + + /arraybuffer.prototype.slice@1.0.2: + resolution: {integrity: sha512-yMBKppFur/fbHu9/6USUe03bZ4knMYiwFBcyiaXB8Go0qNehwX6inYPzK9U0NeQvGxKthcmHcaR8P5MStSRBAw==} + engines: {node: '>= 0.4'} dependencies: - call-bind: 1.0.2 - define-properties: 1.1.4 - es-abstract: 1.20.4 - es-shim-unscopables: 1.0.0 - get-intrinsic: 1.1.3 + array-buffer-byte-length: 1.0.0 + call-bind: 1.0.5 + define-properties: 1.2.1 + es-abstract: 1.22.3 + get-intrinsic: 1.2.2 + is-array-buffer: 3.0.2 + is-shared-array-buffer: 1.0.2 dev: true /asap@2.0.6: @@ -7128,14 +7198,14 @@ packages: resolution: {integrity: sha512-O0yuUDnZeQDL+ncNGlJ78BiO4jnYI3bvMsD5prT0/nsgijG/LpNBIr63gTjVTNsiGkgQhiyCShTgxt8oXOrklA==} engines: {node: '>=4'} dependencies: - tslib: 2.4.1 + tslib: 2.6.2 dev: true /ast-types@0.15.2: resolution: {integrity: sha512-c27loCv9QkZinsa5ProX751khO9DJl/AcB5c2KNtA6NRvHKS0PgLfcftz72KVq504vB0Gku5s2kUZzDBvQWvHg==} engines: {node: '>=4'} dependencies: - tslib: 2.4.1 + tslib: 2.6.2 dev: true /ast-types@0.16.1: @@ -7162,6 +7232,12 @@ packages: resolution: {integrity: sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==} dev: true + /asynciterator.prototype@1.0.0: + resolution: {integrity: sha512-wwHYEIS0Q80f5mosx3L/dfG5t5rjEa9Ft51GTaNt862EnpyGHpgz2RkZvLPp1oF5TnAiTohkEKVEu8pQPJI7Vg==} + dependencies: + has-symbols: 1.0.3 + dev: true + /asynckit@0.4.0: resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} dev: true @@ -7583,6 +7659,13 @@ packages: ieee754: 1.2.1 dev: true + /bundle-name@3.0.0: + resolution: {integrity: sha512-PKA4BeSvBpQKQ8iPOGCSiell+N8P+Tf1DlwqmYhpe2gAhKPHn8EYOxVT+ShuGmhg8lN8XiSlS80yiExKXrURlw==} + engines: {node: '>=12'} + dependencies: + run-applescript: 5.0.0 + dev: true + /bytes@3.0.0: resolution: {integrity: sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==} engines: {node: '>= 0.8'} @@ -7626,11 +7709,12 @@ packages: write-file-atomic: 3.0.3 dev: true - /call-bind@1.0.2: - resolution: {integrity: sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==} + /call-bind@1.0.5: + resolution: {integrity: sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ==} dependencies: - function-bind: 1.1.1 - get-intrinsic: 1.1.3 + function-bind: 1.1.2 + get-intrinsic: 1.2.2 + set-function-length: 1.1.1 /caller-callsite@2.0.0: resolution: {integrity: sha512-JuG3qI4QOftFsZyOn1qq87fq5grLIyk1JYd5lJmdA+fG7aQ9pA/i3JIJGcO3q0MrRcHlOt1U+ZeHW8Dq9axALQ==} @@ -7660,7 +7744,7 @@ packages: resolution: {integrity: sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==} dependencies: pascal-case: 3.1.2 - tslib: 2.4.1 + tslib: 2.6.2 dev: true /camelcase-keys@7.0.2: @@ -8911,9 +8995,9 @@ packages: /deep-equal@2.1.0: resolution: {integrity: sha512-2pxgvWu3Alv1PoWEyVg7HS8YhGlUFUV7N5oOvfL6d+7xAmLSemMwv/c8Zv/i9KFzxV5Kt5CAvQc70fLwVuf4UA==} dependencies: - call-bind: 1.0.2 + call-bind: 1.0.5 es-get-iterator: 1.1.2 - get-intrinsic: 1.1.3 + get-intrinsic: 1.2.2 is-arguments: 1.1.1 is-date-object: 1.0.5 is-regex: 1.1.4 @@ -8943,6 +9027,16 @@ packages: untildify: 4.0.0 dev: true + /default-browser@4.0.0: + resolution: {integrity: sha512-wX5pXO1+BrhMkSbROFsyxUm0i/cJEScyNhA4PPxc41ICuv05ZZB/MX28s8aZx6xjmatvebIapF6hLEKEcpneUA==} + engines: {node: '>=14.16'} + dependencies: + bundle-name: 3.0.0 + default-browser-id: 3.0.0 + execa: 7.2.0 + titleize: 3.0.0 + dev: true + /default-require-extensions@3.0.1: resolution: {integrity: sha512-eXTJmRbm2TIt9MgWTsOH1wEuhew6XGZcMeGKCtLedIg/NCsg1iBePXkceTdK4Fii7pzmN9tGsZhKzZ4h7O/fxw==} engines: {node: '>=8'} @@ -8956,16 +9050,30 @@ packages: clone: 1.0.4 dev: true + /define-data-property@1.1.1: + resolution: {integrity: sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ==} + engines: {node: '>= 0.4'} + dependencies: + get-intrinsic: 1.2.2 + gopd: 1.0.1 + has-property-descriptors: 1.0.1 + /define-lazy-prop@2.0.0: resolution: {integrity: sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==} engines: {node: '>=8'} dev: true - /define-properties@1.1.4: - resolution: {integrity: sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==} + /define-lazy-prop@3.0.0: + resolution: {integrity: sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==} + engines: {node: '>=12'} + dev: true + + /define-properties@1.2.1: + resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} engines: {node: '>= 0.4'} dependencies: - has-property-descriptors: 1.0.0 + define-data-property: 1.1.1 + has-property-descriptors: 1.0.1 object-keys: 1.1.1 /defu@6.1.2: @@ -9191,7 +9299,7 @@ packages: resolution: {integrity: sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==} dependencies: no-case: 3.0.4 - tslib: 2.4.1 + tslib: 2.6.2 dev: true /dot-prop@5.3.0: @@ -9347,34 +9455,49 @@ packages: dependencies: stackframe: 1.3.4 - /es-abstract@1.20.4: - resolution: {integrity: sha512-0UtvRN79eMe2L+UNEF1BwRe364sj/DXhQ/k5FmivgoSdpM90b8Jc0mDzKMGo7QS0BVbOP/bTwBKNnDc9rNzaPA==} + /es-abstract@1.22.3: + resolution: {integrity: sha512-eiiY8HQeYfYH2Con2berK+To6GrK2RxbPawDkGq4UiCQQfZHb6wX9qQqkbpPqaxQFcl8d9QzZqo0tGE0VcrdwA==} engines: {node: '>= 0.4'} dependencies: - call-bind: 1.0.2 + array-buffer-byte-length: 1.0.0 + arraybuffer.prototype.slice: 1.0.2 + available-typed-arrays: 1.0.5 + call-bind: 1.0.5 + es-set-tostringtag: 2.0.2 es-to-primitive: 1.2.1 - function-bind: 1.1.1 - function.prototype.name: 1.1.5 - get-intrinsic: 1.1.3 + function.prototype.name: 1.1.6 + get-intrinsic: 1.2.2 get-symbol-description: 1.0.0 - has: 1.0.3 - has-property-descriptors: 1.0.0 + globalthis: 1.0.3 + gopd: 1.0.1 + has-property-descriptors: 1.0.1 + has-proto: 1.0.1 has-symbols: 1.0.3 - internal-slot: 1.0.3 + hasown: 2.0.0 + internal-slot: 1.0.6 + is-array-buffer: 3.0.2 is-callable: 1.2.7 is-negative-zero: 2.0.2 is-regex: 1.1.4 is-shared-array-buffer: 1.0.2 is-string: 1.0.7 + is-typed-array: 1.1.12 is-weakref: 1.0.2 - object-inspect: 1.12.2 + object-inspect: 1.13.1 object-keys: 1.1.1 object.assign: 4.1.4 - regexp.prototype.flags: 1.4.3 + regexp.prototype.flags: 1.5.1 + safe-array-concat: 1.0.1 safe-regex-test: 1.0.0 - string.prototype.trimend: 1.0.5 - string.prototype.trimstart: 1.0.5 + string.prototype.trim: 1.2.8 + string.prototype.trimend: 1.0.7 + string.prototype.trimstart: 1.0.7 + typed-array-buffer: 1.0.0 + typed-array-byte-length: 1.0.0 + typed-array-byte-offset: 1.0.0 + typed-array-length: 1.0.4 unbox-primitive: 1.0.2 + which-typed-array: 1.1.13 dev: true /es-array-method-boxes-properly@1.0.0: @@ -9384,8 +9507,8 @@ packages: /es-get-iterator@1.1.2: resolution: {integrity: sha512-+DTO8GYwbMCwbywjimwZMHp8AuYXOS2JZFWoi2AlPOS3ebnII9w/NLpNZtA7A0YLaVDw+O7KFCeoIV7OPvM7hQ==} dependencies: - call-bind: 1.0.2 - get-intrinsic: 1.1.3 + call-bind: 1.0.5 + get-intrinsic: 1.2.2 has-symbols: 1.0.3 is-arguments: 1.1.1 is-map: 2.0.2 @@ -9393,14 +9516,42 @@ packages: is-string: 1.0.7 isarray: 2.0.5 + /es-iterator-helpers@1.0.15: + resolution: {integrity: sha512-GhoY8uYqd6iwUl2kgjTm4CZAf6oo5mHK7BPqx3rKgx893YSsy0LGHV6gfqqQvZt/8xM8xeOnfXBCfqclMKkJ5g==} + dependencies: + asynciterator.prototype: 1.0.0 + call-bind: 1.0.5 + define-properties: 1.2.1 + es-abstract: 1.22.3 + es-set-tostringtag: 2.0.2 + function-bind: 1.1.2 + get-intrinsic: 1.2.2 + globalthis: 1.0.3 + has-property-descriptors: 1.0.1 + has-proto: 1.0.1 + has-symbols: 1.0.3 + internal-slot: 1.0.6 + iterator.prototype: 1.1.2 + safe-array-concat: 1.0.1 + dev: true + /es-module-lexer@1.3.0: resolution: {integrity: sha512-vZK7T0N2CBmBOixhmjdqx2gWVbFZ4DXZ/NyRMZVlJXPa7CyFS+/a4QQsDGDQy9ZfEzxFuNEsMLeQJnKP2p5/JA==} dev: true - /es-shim-unscopables@1.0.0: - resolution: {integrity: sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==} + /es-set-tostringtag@2.0.2: + resolution: {integrity: sha512-BuDyupZt65P9D2D2vA/zqcI3G5xRsklm5N3xCwuiy+/vKy8i0ifdsQP1sLgO4tZDSCaQUSnmC48khknGMV3D2Q==} + engines: {node: '>= 0.4'} + dependencies: + get-intrinsic: 1.2.2 + has-tostringtag: 1.0.0 + hasown: 2.0.0 + dev: true + + /es-shim-unscopables@1.0.2: + resolution: {integrity: sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==} dependencies: - has: 1.0.3 + hasown: 2.0.0 dev: true /es-to-primitive@1.2.1: @@ -9706,16 +9857,16 @@ packages: source-map: 0.6.1 dev: true - /eslint-config-prettier@8.8.0(eslint@7.32.0): - resolution: {integrity: sha512-wLbQiFre3tdGgpDv67NQKnJuTlcUVYHas3k+DZCc2U2BadthoEY4B7hLPvAxaqdyOGCzuLfii2fqGph10va7oA==} + /eslint-config-prettier@9.0.0(eslint@8.52.0): + resolution: {integrity: sha512-IcJsTkJae2S35pRsRAwoCE+925rJJStOdkKnLVgtE+tEpqU0EVVM7OqrwxqgptKdX29NUwC82I5pXsGFIgSevw==} hasBin: true peerDependencies: eslint: '>=7.0.0' dependencies: - eslint: 7.32.0 + eslint: 8.52.0 dev: true - /eslint-plugin-compat@4.2.0(eslint@7.32.0): + /eslint-plugin-compat@4.2.0(eslint@8.52.0): resolution: {integrity: sha512-RDKSYD0maWy5r7zb5cWQS+uSPc26mgOzdORJ8hxILmWM7S/Ncwky7BcAtXVY5iRbKjBdHsWU8Yg7hfoZjtkv7w==} engines: {node: '>=14.x'} peerDependencies: @@ -9725,34 +9876,34 @@ packages: ast-metadata-inferer: 0.8.0 browserslist: 4.21.10 caniuse-lite: 1.0.30001538 - eslint: 7.32.0 + eslint: 8.52.0 find-up: 5.0.0 lodash.memoize: 4.1.2 semver: 7.5.4 dev: true - /eslint-plugin-cypress@2.13.3(eslint@7.32.0): - resolution: {integrity: sha512-nAPjZE5WopCsgJwl3vHm5iafpV+ZRO76Z9hMyRygWhmg5ODXDPd+9MaPl7kdJ2azj+sO87H3P1PRnggIrz848g==} + /eslint-plugin-cypress@2.15.1(eslint@8.52.0): + resolution: {integrity: sha512-eLHLWP5Q+I4j2AWepYq0PgFEei9/s5LvjuSqWrxurkg1YZ8ltxdvMNmdSf0drnsNo57CTgYY/NIHHLRSWejR7w==} peerDependencies: eslint: '>= 3.2.1' dependencies: - eslint: 7.32.0 - globals: 11.12.0 + eslint: 8.52.0 + globals: 13.23.0 dev: true - /eslint-plugin-eslint-comments@3.2.0(eslint@7.32.0): + /eslint-plugin-eslint-comments@3.2.0(eslint@8.52.0): resolution: {integrity: sha512-0jkOl0hfojIHHmEHgmNdqv4fmh7300NdpA9FFpF7zaoLvB/QeXOGNLIo86oAveJFrfB1p05kC8hpEMHM8DwWVQ==} engines: {node: '>=6.5.0'} peerDependencies: eslint: '>=4.19.1' dependencies: escape-string-regexp: 1.0.5 - eslint: 7.32.0 + eslint: 8.52.0 ignore: 5.2.4 dev: true - /eslint-plugin-jest@27.2.3(@typescript-eslint/eslint-plugin@6.4.0)(eslint@7.32.0)(jest@29.3.1)(typescript@4.9.5): - resolution: {integrity: sha512-sRLlSCpICzWuje66Gl9zvdF6mwD5X86I4u55hJyFBsxYOsBCmT5+kSUjf+fkFWVMMgpzNEupjW8WzUqi83hJAQ==} + /eslint-plugin-jest@27.4.3(@typescript-eslint/eslint-plugin@6.9.0)(eslint@8.52.0)(jest@29.3.1)(typescript@4.9.5): + resolution: {integrity: sha512-7S6SmmsHsgIm06BAGCAxL+ABd9/IB3MWkz2pudj6Qqor2y1qQpWPfuFU4SG9pWj4xDjF0e+D7Llh5useuSzAZw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} peerDependencies: '@typescript-eslint/eslint-plugin': ^5.0.0 || ^6.0.0 @@ -9764,9 +9915,9 @@ packages: jest: optional: true dependencies: - '@typescript-eslint/eslint-plugin': 6.4.0(@typescript-eslint/parser@6.4.0)(eslint@7.32.0)(typescript@4.9.5) - '@typescript-eslint/utils': 5.55.0(eslint@7.32.0)(typescript@4.9.5) - eslint: 7.32.0 + '@typescript-eslint/eslint-plugin': 6.9.0(@typescript-eslint/parser@6.9.0)(eslint@8.52.0)(typescript@4.9.5) + '@typescript-eslint/utils': 5.55.0(eslint@8.52.0)(typescript@4.9.5) + eslint: 8.52.0 jest: 29.3.1(@types/node@18.11.9)(ts-node@10.9.1) transitivePeerDependencies: - supports-color @@ -9778,56 +9929,61 @@ packages: engines: {node: '>=5.0.0'} dev: true - /eslint-plugin-prettier@3.4.1(eslint-config-prettier@8.8.0)(eslint@7.32.0)(prettier@2.8.8): - resolution: {integrity: sha512-htg25EUYUeIhKHXjOinK4BgCcDwtLHjqaxCDsMy5nbnUMkKFvIhMVCp+5GFUXQ4Nr8lBsPqtGAqBenbpFqAA2g==} - engines: {node: '>=6.0.0'} + /eslint-plugin-prettier@5.0.1(eslint-config-prettier@9.0.0)(eslint@8.52.0)(prettier@2.8.8): + resolution: {integrity: sha512-m3u5RnR56asrwV/lDC4GHorlW75DsFfmUcjfCYylTUs85dBRnB7VM6xG8eCMJdeDRnppzmxZVf1GEPJvl1JmNg==} + engines: {node: ^14.18.0 || >=16.0.0} peerDependencies: - eslint: '>=5.0.0' + '@types/eslint': '>=8.0.0' + eslint: '>=8.0.0' eslint-config-prettier: '*' - prettier: '>=1.13.0' + prettier: '>=3.0.0' peerDependenciesMeta: + '@types/eslint': + optional: true eslint-config-prettier: optional: true dependencies: - eslint: 7.32.0 - eslint-config-prettier: 8.8.0(eslint@7.32.0) + eslint: 8.52.0 + eslint-config-prettier: 9.0.0(eslint@8.52.0) prettier: 2.8.8 prettier-linter-helpers: 1.0.0 + synckit: 0.8.5 dev: true - /eslint-plugin-react@7.32.2(eslint@7.32.0): - resolution: {integrity: sha512-t2fBMa+XzonrrNkyVirzKlvn5RXzzPwRHtMvLAtVZrt8oxgnTQaYbU6SXTOO1mwQgp1y5+toMSKInnzGr0Knqg==} + /eslint-plugin-react@7.33.2(eslint@8.52.0): + resolution: {integrity: sha512-73QQMKALArI8/7xGLNI/3LylrEYrlKZSb5C9+q3OtOewTnMQi5cT+aE9E41sLCmli3I9PGGmD1yiZydyo4FEPw==} engines: {node: '>=4'} peerDependencies: eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 dependencies: - array-includes: 3.1.6 - array.prototype.flatmap: 1.3.1 - array.prototype.tosorted: 1.1.1 + array-includes: 3.1.7 + array.prototype.flatmap: 1.3.2 + array.prototype.tosorted: 1.1.2 doctrine: 2.1.0 - eslint: 7.32.0 + es-iterator-helpers: 1.0.15 + eslint: 8.52.0 estraverse: 5.3.0 - jsx-ast-utils: 3.3.3 + jsx-ast-utils: 3.3.5 minimatch: 3.1.2 - object.entries: 1.1.6 - object.fromentries: 2.0.6 - object.hasown: 1.1.2 - object.values: 1.1.6 + object.entries: 1.1.7 + object.fromentries: 2.0.7 + object.hasown: 1.1.3 + object.values: 1.1.7 prop-types: 15.8.1 - resolve: 2.0.0-next.4 + resolve: 2.0.0-next.5 semver: 6.3.1 - string.prototype.matchall: 4.0.8 + string.prototype.matchall: 4.0.10 dev: true - /eslint-plugin-storybook@0.6.15(eslint@7.32.0)(typescript@4.9.5): + /eslint-plugin-storybook@0.6.15(eslint@8.52.0)(typescript@4.9.5): resolution: {integrity: sha512-lAGqVAJGob47Griu29KXYowI4G7KwMoJDOkEip8ujikuDLxU+oWJ1l0WL6F2oDO4QiyUFXvtDkEkISMOPzo+7w==} engines: {node: 12.x || 14.x || >= 16} peerDependencies: eslint: '>=6' dependencies: '@storybook/csf': 0.0.1 - '@typescript-eslint/utils': 5.55.0(eslint@7.32.0)(typescript@4.9.5) - eslint: 7.32.0 + '@typescript-eslint/utils': 5.55.0(eslint@8.52.0)(typescript@4.9.5) + eslint: 8.52.0 requireindex: 1.2.0 ts-dedent: 2.2.0 transitivePeerDependencies: @@ -9843,21 +9999,12 @@ packages: estraverse: 4.3.0 dev: true - /eslint-utils@2.1.0: - resolution: {integrity: sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==} - engines: {node: '>=6'} + /eslint-scope@7.2.2: + resolution: {integrity: sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dependencies: - eslint-visitor-keys: 1.3.0 - dev: true - - /eslint-visitor-keys@1.3.0: - resolution: {integrity: sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==} - engines: {node: '>=4'} - dev: true - - /eslint-visitor-keys@2.1.0: - resolution: {integrity: sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==} - engines: {node: '>=10'} + esrecurse: 4.3.0 + estraverse: 5.3.0 dev: true /eslint-visitor-keys@3.4.3: @@ -9865,62 +10012,60 @@ packages: engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dev: true - /eslint@7.32.0: - resolution: {integrity: sha512-VHZ8gX+EDfz+97jGcgyGCyRia/dPOd6Xh9yPv8Bl1+SoaIwD+a/vlrOmGRUyOYu7MwUhc7CxqeaDZU13S4+EpA==} - engines: {node: ^10.12.0 || >=12.0.0} + /eslint@8.52.0: + resolution: {integrity: sha512-zh/JHnaixqHZsolRB/w9/02akBk9EPrOs9JwcTP2ek7yL5bVvXuRariiaAjjoJ5DvuwQ1WAE/HsMz+w17YgBCg==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} hasBin: true dependencies: - '@babel/code-frame': 7.12.11 - '@eslint/eslintrc': 0.4.3 - '@humanwhocodes/config-array': 0.5.0 + '@eslint-community/eslint-utils': 4.4.0(eslint@8.52.0) + '@eslint-community/regexpp': 4.9.1 + '@eslint/eslintrc': 2.1.2 + '@eslint/js': 8.52.0 + '@humanwhocodes/config-array': 0.11.13 + '@humanwhocodes/module-importer': 1.0.1 + '@nodelib/fs.walk': 1.2.8 + '@ungap/structured-clone': 1.2.0 ajv: 6.12.6 chalk: 4.1.2 cross-spawn: 7.0.3 debug: 4.3.4(supports-color@8.1.1) doctrine: 3.0.0 - enquirer: 2.3.6 escape-string-regexp: 4.0.0 - eslint-scope: 5.1.1 - eslint-utils: 2.1.0 - eslint-visitor-keys: 2.1.0 - espree: 7.3.1 - esquery: 1.4.0 + eslint-scope: 7.2.2 + eslint-visitor-keys: 3.4.3 + espree: 9.6.1 + esquery: 1.5.0 esutils: 2.0.3 fast-deep-equal: 3.1.3 file-entry-cache: 6.0.1 - functional-red-black-tree: 1.0.1 - glob-parent: 5.1.2 - globals: 13.17.0 - ignore: 4.0.6 - import-fresh: 3.3.0 + find-up: 5.0.0 + glob-parent: 6.0.2 + globals: 13.23.0 + graphemer: 1.4.0 + ignore: 5.2.4 imurmurhash: 0.1.4 is-glob: 4.0.3 - js-yaml: 3.14.1 + is-path-inside: 3.0.3 + js-yaml: 4.1.0 json-stable-stringify-without-jsonify: 1.0.1 levn: 0.4.1 lodash.merge: 4.6.2 minimatch: 3.1.2 natural-compare: 1.4.0 - optionator: 0.9.1 - progress: 2.0.3 - regexpp: 3.2.0 - semver: 7.5.4 + optionator: 0.9.3 strip-ansi: 6.0.1 - strip-json-comments: 3.1.1 - table: 6.8.1 text-table: 0.2.0 - v8-compile-cache: 2.3.0 transitivePeerDependencies: - supports-color dev: true - /espree@7.3.1: - resolution: {integrity: sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==} - engines: {node: ^10.12.0 || >=12.0.0} + /espree@9.6.1: + resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dependencies: - acorn: 7.4.1 - acorn-jsx: 5.3.2(acorn@7.4.1) - eslint-visitor-keys: 1.3.0 + acorn: 8.10.0 + acorn-jsx: 5.3.2(acorn@8.10.0) + eslint-visitor-keys: 3.4.3 dev: true /esprima@4.0.1: @@ -9929,8 +10074,8 @@ packages: hasBin: true dev: true - /esquery@1.4.0: - resolution: {integrity: sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==} + /esquery@1.5.0: + resolution: {integrity: sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==} engines: {node: '>=0.10'} dependencies: estraverse: 5.3.0 @@ -10012,6 +10157,21 @@ packages: strip-final-newline: 2.0.0 dev: true + /execa@7.2.0: + resolution: {integrity: sha512-UduyVP7TLB5IcAQl+OzLyLcS/l32W/GLg+AhHJ+ow40FOk2U3SAllPwR44v4vmdFwIWqpdwxxpQbF1n5ta9seA==} + engines: {node: ^14.18.0 || ^16.14.0 || >=18.0.0} + dependencies: + cross-spawn: 7.0.3 + get-stream: 6.0.1 + human-signals: 4.3.1 + is-stream: 3.0.0 + merge-stream: 2.0.0 + npm-run-path: 5.1.0 + onetime: 6.0.0 + signal-exit: 3.0.7 + strip-final-newline: 3.0.0 + dev: true + /executable@4.1.1: resolution: {integrity: sha512-8iA79xD3uAch729dUG8xaaBBFGaEa0wdD2VkYLFHwlqosEj/jT66AzcreRDSgV7ehnNLBW2WR5jIXwGKjVdTLg==} engines: {node: '>=4'} @@ -10148,12 +10308,12 @@ packages: /fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} - /fast-diff@1.2.0: - resolution: {integrity: sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==} + /fast-diff@1.3.0: + resolution: {integrity: sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==} dev: true - /fast-glob@3.2.12: - resolution: {integrity: sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==} + /fast-glob@3.3.1: + resolution: {integrity: sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==} engines: {node: '>=8.6.0'} dependencies: '@nodelib/fs.stat': 2.0.5 @@ -10188,8 +10348,8 @@ packages: resolution: {integrity: sha512-bijHueCGd0LqqNK9b5oCMHc0MluJAx0cwqASgbWMvkO01lCYgIhacVRLcaDz3QnyYIRNJRDwMb41VuT6pHJ91Q==} dev: false - /fastq@1.13.0: - resolution: {integrity: sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==} + /fastq@1.15.0: + resolution: {integrity: sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==} dependencies: reusify: 1.0.4 dev: true @@ -10260,7 +10420,7 @@ packages: resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==} engines: {node: ^10.12.0 || >=12.0.0} dependencies: - flat-cache: 3.0.4 + flat-cache: 3.1.1 dev: true /file-loader@6.2.0(webpack@5.88.2): @@ -10284,7 +10444,7 @@ packages: /filelist@1.0.4: resolution: {integrity: sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==} dependencies: - minimatch: 5.1.1 + minimatch: 5.1.6 dev: true /fill-range@7.0.1: @@ -10398,10 +10558,23 @@ packages: rimraf: 3.0.2 dev: true + /flat-cache@3.1.1: + resolution: {integrity: sha512-/qM2b3LUIaIgviBQovTLvijfyOQXPtSRnRK26ksj2J7rzPIecePUIpJsZ4T02Qg+xiAEKIs5K8dsHEd+VaKa/Q==} + engines: {node: '>=12.0.0'} + dependencies: + flatted: 3.2.9 + keyv: 4.5.4 + rimraf: 3.0.2 + dev: true + /flatted@3.2.7: resolution: {integrity: sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==} dev: true + /flatted@3.2.9: + resolution: {integrity: sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==} + dev: true + /flow-parser@0.214.0: resolution: {integrity: sha512-RW1Dh6BuT14DA7+gtNRKzgzvG3GTPdrceHCi4ddZ9VFGQ9HtO5L8wzxMGsor7XtInIrbWZZCSak0oxnBF7tApw==} engines: {node: '>=0.4.0'} @@ -10582,23 +10755,19 @@ packages: requiresBuild: true optional: true - /function-bind@1.1.1: - resolution: {integrity: sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==} + /function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} - /function.prototype.name@1.1.5: - resolution: {integrity: sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==} + /function.prototype.name@1.1.6: + resolution: {integrity: sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==} engines: {node: '>= 0.4'} dependencies: - call-bind: 1.0.2 - define-properties: 1.1.4 - es-abstract: 1.20.4 + call-bind: 1.0.5 + define-properties: 1.2.1 + es-abstract: 1.22.3 functions-have-names: 1.2.3 dev: true - /functional-red-black-tree@1.0.1: - resolution: {integrity: sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==} - dev: true - /functions-have-names@1.2.3: resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} @@ -10616,12 +10785,13 @@ packages: engines: {node: 6.* || 8.* || >= 10.*} dev: true - /get-intrinsic@1.1.3: - resolution: {integrity: sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==} + /get-intrinsic@1.2.2: + resolution: {integrity: sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA==} dependencies: - function-bind: 1.1.1 - has: 1.0.3 + function-bind: 1.1.2 + has-proto: 1.0.1 has-symbols: 1.0.3 + hasown: 2.0.0 /get-nonce@1.0.1: resolution: {integrity: sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==} @@ -10668,8 +10838,8 @@ packages: resolution: {integrity: sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==} engines: {node: '>= 0.4'} dependencies: - call-bind: 1.0.2 - get-intrinsic: 1.1.3 + call-bind: 1.0.5 + get-intrinsic: 1.2.2 dev: true /getos@3.2.1: @@ -10713,6 +10883,13 @@ packages: dependencies: is-glob: 4.0.3 + /glob-parent@6.0.2: + resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} + engines: {node: '>=10.13.0'} + dependencies: + is-glob: 4.0.3 + dev: true + /glob-to-regexp@0.4.1: resolution: {integrity: sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==} dev: true @@ -10791,20 +10968,27 @@ packages: resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==} engines: {node: '>=4'} - /globals@13.17.0: - resolution: {integrity: sha512-1C+6nQRb1GwGMKm2dH/E7enFAMxGTmGI7/dEdhy/DNelv85w9B72t3uc5frtMNXIbzrarJJ/lTCjcaZwbLJmyw==} + /globals@13.23.0: + resolution: {integrity: sha512-XAmF0RjlrjY23MA51q3HltdlGxUpXPvg0GioKiD9X6HD28iMjo2dKC8Vqwm7lne4GNr78+RHTfliktR6ZH09wA==} engines: {node: '>=8'} dependencies: type-fest: 0.20.2 dev: true + /globalthis@1.0.3: + resolution: {integrity: sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==} + engines: {node: '>= 0.4'} + dependencies: + define-properties: 1.2.1 + dev: true + /globby@11.1.0: resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==} engines: {node: '>=10'} dependencies: array-union: 2.1.0 dir-glob: 3.0.1 - fast-glob: 3.2.12 + fast-glob: 3.3.1 ignore: 5.2.4 merge2: 1.4.1 slash: 3.0.0 @@ -10816,7 +11000,7 @@ packages: /gopd@1.0.1: resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==} dependencies: - get-intrinsic: 1.1.3 + get-intrinsic: 1.2.2 /graceful-fs@4.2.11: resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} @@ -10866,10 +11050,14 @@ packages: resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} engines: {node: '>=8'} - /has-property-descriptors@1.0.0: - resolution: {integrity: sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==} + /has-property-descriptors@1.0.1: + resolution: {integrity: sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg==} dependencies: - get-intrinsic: 1.1.3 + get-intrinsic: 1.2.2 + + /has-proto@1.0.1: + resolution: {integrity: sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==} + engines: {node: '>= 0.4'} /has-symbols@1.0.3: resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==} @@ -10885,7 +11073,8 @@ packages: resolution: {integrity: sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==} engines: {node: '>= 0.4.0'} dependencies: - function-bind: 1.1.1 + function-bind: 1.1.2 + dev: true /hasha@5.2.2: resolution: {integrity: sha512-Hrp5vIK/xr5SkeN2onO32H0MgNZ0f17HRNH39WfL0SYUNOTZ5Lz1TJ8Pajo/87dYGEFlLMm7mIc/k/s6Bvz9HQ==} @@ -10895,6 +11084,12 @@ packages: type-fest: 0.8.1 dev: true + /hasown@2.0.0: + resolution: {integrity: sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==} + engines: {node: '>= 0.4'} + dependencies: + function-bind: 1.1.2 + /hast-util-parse-selector@2.2.5: resolution: {integrity: sha512-7j6mrk/qqkSehsM92wQjdIgWM2/BW61u/53G6xmC8i1OmEdKLHbk419QKQUjz6LglWsfqoiHmyMRkP1BGjecNQ==} @@ -11115,6 +11310,11 @@ packages: engines: {node: '>=10.17.0'} dev: true + /human-signals@4.3.1: + resolution: {integrity: sha512-nZXjEF2nbo7lIw3mgYjItAfgQXog3OjJogSbKa2CQIIvSGWcKgeJnQlNXip6NglNzYH45nSRiEVimMvYL8DDqQ==} + engines: {node: '>=14.18.0'} + dev: true + /humps@2.0.1: resolution: {integrity: sha512-E0eIbrFWUhwfXJmsbdjRQFQPrl5pTEoKlz163j1mTqqUnU9PgR4AgB8AIITzuB3vLBdxZXyZ9TDIrwB2OASz4g==} dev: false @@ -11161,11 +11361,6 @@ packages: resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} dev: true - /ignore@4.0.6: - resolution: {integrity: sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==} - engines: {node: '>= 4'} - dev: true - /ignore@5.2.4: resolution: {integrity: sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==} engines: {node: '>= 4'} @@ -11272,12 +11467,12 @@ packages: wrap-ansi: 7.0.0 dev: true - /internal-slot@1.0.3: - resolution: {integrity: sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==} + /internal-slot@1.0.6: + resolution: {integrity: sha512-Xj6dv+PsbtwyPpEflsejS+oIZxmMlV44zAhG479uYu89MsjcYOhCFnNyKrkJrihbsiasQyY0afoCl/9BLR65bg==} engines: {node: '>= 0.4'} dependencies: - get-intrinsic: 1.1.3 - has: 1.0.3 + get-intrinsic: 1.2.2 + hasown: 2.0.0 side-channel: 1.0.4 dev: true @@ -11334,9 +11529,17 @@ packages: resolution: {integrity: sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==} engines: {node: '>= 0.4'} dependencies: - call-bind: 1.0.2 + call-bind: 1.0.5 has-tostringtag: 1.0.0 + /is-array-buffer@3.0.2: + resolution: {integrity: sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==} + dependencies: + call-bind: 1.0.5 + get-intrinsic: 1.2.2 + is-typed-array: 1.1.12 + dev: true + /is-arrayish@0.2.1: resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} dev: true @@ -11345,6 +11548,13 @@ packages: resolution: {integrity: sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==} dev: true + /is-async-function@2.0.0: + resolution: {integrity: sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA==} + engines: {node: '>= 0.4'} + dependencies: + has-tostringtag: 1.0.0 + dev: true + /is-bigint@1.0.4: resolution: {integrity: sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==} dependencies: @@ -11360,7 +11570,7 @@ packages: resolution: {integrity: sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==} engines: {node: '>= 0.4'} dependencies: - call-bind: 1.0.2 + call-bind: 1.0.5 has-tostringtag: 1.0.0 /is-buffer@1.1.6: @@ -11394,10 +11604,10 @@ packages: rgba-regex: 1.0.0 dev: true - /is-core-module@2.11.0: - resolution: {integrity: sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==} + /is-core-module@2.13.1: + resolution: {integrity: sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==} dependencies: - has: 1.0.3 + hasown: 2.0.0 /is-date-object@1.0.5: resolution: {integrity: sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==} @@ -11423,6 +11633,12 @@ packages: hasBin: true dev: true + /is-docker@3.0.0: + resolution: {integrity: sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + hasBin: true + dev: true + /is-extendable@1.0.1: resolution: {integrity: sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==} engines: {node: '>=0.10.0'} @@ -11434,6 +11650,12 @@ packages: resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} engines: {node: '>=0.10.0'} + /is-finalizationregistry@1.0.2: + resolution: {integrity: sha512-0by5vtUJs8iFQb5TYUHHPudOR+qXYIMKtiUzvLIZITZUjknFmziyBJuLhVRc+Ds0dREFlskDNJKYIdIzu/9pfw==} + dependencies: + call-bind: 1.0.5 + dev: true + /is-fullwidth-code-point@2.0.0: resolution: {integrity: sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==} engines: {node: '>=4'} @@ -11470,6 +11692,14 @@ packages: /is-hexadecimal@1.0.4: resolution: {integrity: sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw==} + /is-inside-container@1.0.0: + resolution: {integrity: sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==} + engines: {node: '>=14.16'} + hasBin: true + dependencies: + is-docker: 3.0.0 + dev: true + /is-installed-globally@0.4.0: resolution: {integrity: sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ==} engines: {node: '>=10'} @@ -11490,8 +11720,8 @@ packages: resolution: {integrity: sha512-E+zBKpQ2t6MEo1VsonYmluk9NxGrbzpeeLC2xIViuO2EjU2xsXsBPwTr3Ykv9l08UYEVEdWeRZNouaZqF6RN0w==} engines: {node: '>= 0.4'} dependencies: - call-bind: 1.0.2 - define-properties: 1.1.4 + call-bind: 1.0.5 + define-properties: 1.2.1 dev: true /is-negative-zero@2.0.2: @@ -11557,7 +11787,7 @@ packages: resolution: {integrity: sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==} engines: {node: '>= 0.4'} dependencies: - call-bind: 1.0.2 + call-bind: 1.0.5 has-tostringtag: 1.0.0 /is-regexp@1.0.0: @@ -11575,7 +11805,7 @@ packages: /is-shared-array-buffer@1.0.2: resolution: {integrity: sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==} dependencies: - call-bind: 1.0.2 + call-bind: 1.0.5 dev: true /is-stream@2.0.1: @@ -11583,6 +11813,11 @@ packages: engines: {node: '>=8'} dev: true + /is-stream@3.0.0: + resolution: {integrity: sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dev: true + /is-string@1.0.7: resolution: {integrity: sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==} engines: {node: '>= 0.4'} @@ -11600,11 +11835,18 @@ packages: engines: {node: '>= 0.4'} dependencies: available-typed-arrays: 1.0.5 - call-bind: 1.0.2 + call-bind: 1.0.5 for-each: 0.3.3 gopd: 1.0.1 has-tostringtag: 1.0.0 + /is-typed-array@1.1.12: + resolution: {integrity: sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg==} + engines: {node: '>= 0.4'} + dependencies: + which-typed-array: 1.1.13 + dev: true + /is-typedarray@1.0.0: resolution: {integrity: sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==} dev: true @@ -11620,14 +11862,14 @@ packages: /is-weakref@1.0.2: resolution: {integrity: sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==} dependencies: - call-bind: 1.0.2 + call-bind: 1.0.5 dev: true /is-weakset@2.0.2: resolution: {integrity: sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg==} dependencies: - call-bind: 1.0.2 - get-intrinsic: 1.1.3 + call-bind: 1.0.5 + get-intrinsic: 1.2.2 /is-what@3.14.1: resolution: {integrity: sha512-sNxgpk9793nzSs7bA6JQJGeIuRBQhAaNGG77kzYQgMkrID+lS6SlK07K5LaptscDlSaIgH+GPFzf+d75FVxozA==} @@ -11745,6 +11987,16 @@ packages: istanbul-lib-report: 3.0.0 dev: true + /iterator.prototype@1.1.2: + resolution: {integrity: sha512-DR33HMMr8EzwuRL8Y9D3u2BMj8+RqSE850jfGu59kS7tbmPLzGkZmVSfyCFSDxuZiEY6Rzt3T2NA/qU+NwVj1w==} + dependencies: + define-properties: 1.2.1 + get-intrinsic: 1.2.2 + has-symbols: 1.0.3 + reflect.getprototypeof: 1.0.4 + set-function-name: 2.0.1 + dev: true + /jackspeak@2.3.0: resolution: {integrity: sha512-uKmsITSsF4rUWQHzqaRUuyAir3fZfW3f202Ee34lz/gZCi970CPZwyQXLGNgWJvvZbvFyzeyGq0+4fcG/mBKZg==} engines: {node: '>=14'} @@ -12425,7 +12677,7 @@ packages: jest-pnp-resolver: 1.2.2(jest-resolve@28.1.3) jest-util: 28.1.3 jest-validate: 28.1.3 - resolve: 1.22.1 + resolve: 1.22.8 resolve.exports: 1.1.0 slash: 3.0.0 dev: true @@ -12440,7 +12692,7 @@ packages: jest-pnp-resolver: 1.2.2(jest-resolve@29.3.1) jest-util: 29.3.1 jest-validate: 29.3.1 - resolve: 1.22.1 + resolve: 1.22.8 resolve.exports: 1.1.0 slash: 3.0.0 dev: true @@ -12822,6 +13074,13 @@ packages: esprima: 4.0.1 dev: true + /js-yaml@4.1.0: + resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} + hasBin: true + dependencies: + argparse: 2.0.1 + dev: true + /jsbn@0.1.1: resolution: {integrity: sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==} dev: true @@ -12907,6 +13166,10 @@ packages: engines: {node: '>=4'} hasBin: true + /json-buffer@3.0.1: + resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} + dev: true + /json-parse-better-errors@1.0.2: resolution: {integrity: sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==} dev: true @@ -12972,12 +13235,14 @@ packages: json-schema: 0.4.0 verror: 1.10.0 - /jsx-ast-utils@3.3.3: - resolution: {integrity: sha512-fYQHZTZ8jSfmWZ0iyzfwiU4WDX4HpHbMCZ3gPlWYiCl3BoeOTsqKBqnTVfH2rYT7eP5c3sVbeSPHnnJOaTrWiw==} + /jsx-ast-utils@3.3.5: + resolution: {integrity: sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==} engines: {node: '>=4.0'} dependencies: - array-includes: 3.1.6 + array-includes: 3.1.7 + array.prototype.flat: 1.3.2 object.assign: 4.1.4 + object.values: 1.1.7 dev: true /kea-forms@3.0.3(kea@3.1.5): @@ -13075,6 +13340,12 @@ packages: use-sync-external-store: 1.2.0(react@16.14.0) dev: false + /keyv@4.5.4: + resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} + dependencies: + json-buffer: 3.0.1 + dev: true + /kind-of@6.0.3: resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==} engines: {node: '>=0.10.0'} @@ -13142,7 +13413,7 @@ packages: dependencies: copy-anything: 2.0.6 parse-node-version: 1.0.1 - tslib: 2.4.1 + tslib: 2.6.2 optionalDependencies: errno: 0.1.8 graceful-fs: 4.2.11 @@ -13325,10 +13596,6 @@ packages: resolution: {integrity: sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==} dev: true - /lodash.truncate@4.4.2: - resolution: {integrity: sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==} - dev: true - /lodash.uniq@4.5.0: resolution: {integrity: sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==} dev: true @@ -13367,7 +13634,7 @@ packages: /lower-case@2.0.2: resolution: {integrity: sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==} dependencies: - tslib: 2.4.1 + tslib: 2.6.2 dev: true /lowlight@1.20.0: @@ -13403,7 +13670,7 @@ packages: requiresBuild: true dependencies: pify: 4.0.1 - semver: 5.7.1 + semver: 5.7.2 /make-dir@3.1.0: resolution: {integrity: sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==} @@ -13585,6 +13852,11 @@ packages: engines: {node: '>=6'} dev: true + /mimic-fn@4.0.0: + resolution: {integrity: sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==} + engines: {node: '>=12'} + dev: true + /min-indent@1.0.1: resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==} engines: {node: '>=4'} @@ -13603,6 +13875,13 @@ packages: brace-expansion: 2.0.1 dev: true + /minimatch@5.1.6: + resolution: {integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==} + engines: {node: '>=10'} + dependencies: + brace-expansion: 2.0.1 + dev: true + /minimatch@9.0.3: resolution: {integrity: sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==} engines: {node: '>=16 || 14 >=14.17'} @@ -13821,7 +14100,7 @@ packages: resolution: {integrity: sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==} dependencies: lower-case: 2.0.2 - tslib: 2.4.1 + tslib: 2.6.2 dev: true /node-abort-controller@3.1.1: @@ -13868,8 +14147,8 @@ packages: resolution: {integrity: sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==} dependencies: hosted-git-info: 2.8.9 - resolve: 1.22.1 - semver: 5.7.1 + resolve: 1.22.8 + semver: 5.7.2 validate-npm-package-license: 3.0.4 dev: true @@ -13894,6 +14173,13 @@ packages: path-key: 3.1.1 dev: true + /npm-run-path@5.1.0: + resolution: {integrity: sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dependencies: + path-key: 4.0.0 + dev: true + /nth-check@1.0.2: resolution: {integrity: sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg==} dependencies: @@ -13950,15 +14236,15 @@ packages: resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} engines: {node: '>=0.10.0'} - /object-inspect@1.12.2: - resolution: {integrity: sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==} + /object-inspect@1.13.1: + resolution: {integrity: sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==} /object-is@1.1.5: resolution: {integrity: sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==} engines: {node: '>= 0.4'} dependencies: - call-bind: 1.0.2 - define-properties: 1.1.4 + call-bind: 1.0.5 + define-properties: 1.2.1 /object-keys@1.1.1: resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} @@ -13968,27 +14254,27 @@ packages: resolution: {integrity: sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==} engines: {node: '>= 0.4'} dependencies: - call-bind: 1.0.2 - define-properties: 1.1.4 + call-bind: 1.0.5 + define-properties: 1.2.1 has-symbols: 1.0.3 object-keys: 1.1.1 - /object.entries@1.1.6: - resolution: {integrity: sha512-leTPzo4Zvg3pmbQ3rDK69Rl8GQvIqMWubrkxONG9/ojtFE2rD9fjMKfSI5BxW3osRH1m6VdzmqK8oAY9aT4x5w==} + /object.entries@1.1.7: + resolution: {integrity: sha512-jCBs/0plmPsOnrKAfFQXRG2NFjlhZgjjcBLSmTnEhU8U6vVTsVe8ANeQJCHTl3gSsI4J+0emOoCgoKlmQPMgmA==} engines: {node: '>= 0.4'} dependencies: - call-bind: 1.0.2 - define-properties: 1.1.4 - es-abstract: 1.20.4 + call-bind: 1.0.5 + define-properties: 1.2.1 + es-abstract: 1.22.3 dev: true - /object.fromentries@2.0.6: - resolution: {integrity: sha512-VciD13dswC4j1Xt5394WR4MzmAQmlgN72phd/riNp9vtD7tp4QQWJ0R4wvclXcafgcYK8veHRed2W6XeGBvcfg==} + /object.fromentries@2.0.7: + resolution: {integrity: sha512-UPbPHML6sL8PI/mOqPwsH4G6iyXcCGzLin8KvEPenOZN5lpCNBZZQ+V62vdjB1mQHrmqGQt5/OJzemUA+KJmEA==} engines: {node: '>= 0.4'} dependencies: - call-bind: 1.0.2 - define-properties: 1.1.4 - es-abstract: 1.20.4 + call-bind: 1.0.5 + define-properties: 1.2.1 + es-abstract: 1.22.3 dev: true /object.getownpropertydescriptors@2.1.4: @@ -13996,16 +14282,16 @@ packages: engines: {node: '>= 0.8'} dependencies: array.prototype.reduce: 1.0.5 - call-bind: 1.0.2 - define-properties: 1.1.4 - es-abstract: 1.20.4 + call-bind: 1.0.5 + define-properties: 1.2.1 + es-abstract: 1.22.3 dev: true - /object.hasown@1.1.2: - resolution: {integrity: sha512-B5UIT3J1W+WuWIU55h0mjlwaqxiE5vYENJXIXZ4VFe05pNYrkKuK0U/6aFcb0pKywYJh7IhfoqUfKVmrJJHZHw==} + /object.hasown@1.1.3: + resolution: {integrity: sha512-fFI4VcYpRHvSLXxP7yiZOMAd331cPfd2p7PFDVbgUsYOfCT3tICVqXWngbjr4m49OvsBwUBQ6O2uQoJvy3RexA==} dependencies: - define-properties: 1.1.4 - es-abstract: 1.20.4 + define-properties: 1.2.1 + es-abstract: 1.22.3 dev: true /object.omit@3.0.0: @@ -14022,13 +14308,13 @@ packages: isobject: 3.0.1 dev: false - /object.values@1.1.6: - resolution: {integrity: sha512-FVVTkD1vENCsAcwNs9k6jea2uHC/X0+JcjG8YA60FN5CMaJmG95wT9jek/xX9nornqGRrBkKtzuAu2wuHpKqvw==} + /object.values@1.1.7: + resolution: {integrity: sha512-aU6xnDFYT3x17e/f0IiiwlGPTy2jzMySGfUB4fq6z7CV8l85CWHDk5ErhyhpfDHhrOMwGFhSQkhMGHaIotA6Ng==} engines: {node: '>= 0.4'} dependencies: - call-bind: 1.0.2 - define-properties: 1.1.4 - es-abstract: 1.20.4 + call-bind: 1.0.5 + define-properties: 1.2.1 + es-abstract: 1.22.3 dev: true /objectorarray@1.0.5: @@ -14059,6 +14345,13 @@ packages: mimic-fn: 2.1.0 dev: true + /onetime@6.0.0: + resolution: {integrity: sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==} + engines: {node: '>=12'} + dependencies: + mimic-fn: 4.0.0 + dev: true + /open@8.4.2: resolution: {integrity: sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==} engines: {node: '>=12'} @@ -14068,16 +14361,26 @@ packages: is-wsl: 2.2.0 dev: true - /optionator@0.9.1: - resolution: {integrity: sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==} + /open@9.1.0: + resolution: {integrity: sha512-OS+QTnw1/4vrf+9hh1jc1jnYjzSG4ttTBB8UxOwAnInG3Uo4ssetzC1ihqaIHjLJnA5GGlRl6QlZXOTQhRBUvg==} + engines: {node: '>=14.16'} + dependencies: + default-browser: 4.0.0 + define-lazy-prop: 3.0.0 + is-inside-container: 1.0.0 + is-wsl: 2.2.0 + dev: true + + /optionator@0.9.3: + resolution: {integrity: sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==} engines: {node: '>= 0.8.0'} dependencies: + '@aashutoshrathi/word-wrap': 1.2.6 deep-is: 0.1.4 fast-levenshtein: 2.0.6 levn: 0.4.1 prelude-ls: 1.2.1 type-check: 0.4.0 - word-wrap: 1.2.4 dev: true /ora@5.4.1: @@ -14207,7 +14510,7 @@ packages: resolution: {integrity: sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==} dependencies: dot-case: 3.0.4 - tslib: 2.4.1 + tslib: 2.6.2 dev: true /parent-module@1.0.1: @@ -14269,7 +14572,7 @@ packages: resolution: {integrity: sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==} dependencies: no-case: 3.0.4 - tslib: 2.4.1 + tslib: 2.6.2 dev: true /path-browserify@1.0.1: @@ -14301,6 +14604,11 @@ packages: engines: {node: '>=8'} dev: true + /path-key@4.0.0: + resolution: {integrity: sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==} + engines: {node: '>=12'} + dev: true + /path-parse@1.0.7: resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} @@ -14852,7 +15160,7 @@ packages: resolution: {integrity: sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==} engines: {node: '>=6.0.0'} dependencies: - fast-diff: 1.2.0 + fast-diff: 1.3.0 dev: true /prettier@2.8.8: @@ -15955,7 +16263,7 @@ packages: '@types/react': 16.14.34 react: 16.14.0 react-style-singleton: 2.2.1(@types/react@16.14.34)(react@16.14.0) - tslib: 2.4.1 + tslib: 2.6.2 dev: true /react-remove-scroll@2.5.5(@types/react@16.14.34)(react@16.14.0): @@ -15972,7 +16280,7 @@ packages: react: 16.14.0 react-remove-scroll-bar: 2.3.4(@types/react@16.14.34)(react@16.14.0) react-style-singleton: 2.2.1(@types/react@16.14.34)(react@16.14.0) - tslib: 2.4.1 + tslib: 2.6.2 use-callback-ref: 1.3.0(@types/react@16.14.34)(react@16.14.0) use-sidecar: 1.1.2(@types/react@16.14.34)(react@16.14.0) dev: true @@ -16028,7 +16336,7 @@ packages: get-nonce: 1.0.1 invariant: 2.2.4 react: 16.14.0 - tslib: 2.4.1 + tslib: 2.6.2 dev: true /react-syntax-highlighter@15.5.0(react@16.14.0): @@ -16094,14 +16402,14 @@ packages: react-dom: 16.14.0(react@16.14.0) dev: false - /react-universal-interface@0.6.2(react@16.14.0)(tslib@2.4.1): + /react-universal-interface@0.6.2(react@16.14.0)(tslib@2.6.2): resolution: {integrity: sha512-dg8yXdcQmvgR13RIlZbTRQOoUrDciFVoSBZILwjE2LFISxZZ8loVJKAkuzswl5js8BHda79bIb2b84ehU8IjXw==} peerDependencies: react: '*' tslib: '*' dependencies: react: 16.14.0 - tslib: 2.4.1 + tslib: 2.6.2 dev: false /react-use@15.3.8(react-dom@16.14.0)(react@16.14.0): @@ -16119,13 +16427,13 @@ packages: nano-css: 5.3.5(react-dom@16.14.0)(react@16.14.0) react: 16.14.0 react-dom: 16.14.0(react@16.14.0) - react-universal-interface: 0.6.2(react@16.14.0)(tslib@2.4.1) + react-universal-interface: 0.6.2(react@16.14.0)(tslib@2.6.2) resize-observer-polyfill: 1.5.1 screenfull: 5.2.0 set-harmonic-interval: 1.0.1 throttle-debounce: 2.3.0 ts-easing: 0.2.0 - tslib: 2.4.1 + tslib: 2.6.2 dev: false /react-virtualized@9.22.5(react-dom@16.14.0)(react@16.14.0): @@ -16214,7 +16522,7 @@ packages: ast-types: 0.15.2 esprima: 4.0.1 source-map: 0.6.1 - tslib: 2.4.1 + tslib: 2.6.2 dev: true /recast@0.23.4: @@ -16249,6 +16557,18 @@ packages: '@babel/runtime': 7.22.10 dev: false + /reflect.getprototypeof@1.0.4: + resolution: {integrity: sha512-ECkTw8TmJwW60lOTR+ZkODISW6RQ8+2CL3COqtiJKLd6MmB45hN51HprHFziKLGkAuTGQhBb91V8cy+KHlaCjw==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.5 + define-properties: 1.2.1 + es-abstract: 1.22.3 + get-intrinsic: 1.2.2 + globalthis: 1.0.3 + which-builtin-type: 1.1.3 + dev: true + /refractor@3.6.0: resolution: {integrity: sha512-MY9W41IOWxxk31o+YvFCNyNzdkc9M20NoZK5vq6jkv4I/uh2zkWcfudj0Q1fovjUQJrNewS9NMzeTtqPf+n5EA==} dependencies: @@ -16280,13 +16600,17 @@ packages: resolution: {integrity: sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==} engines: {node: '>= 0.4'} dependencies: - call-bind: 1.0.2 - define-properties: 1.1.4 + call-bind: 1.0.5 + define-properties: 1.2.1 functions-have-names: 1.2.3 - /regexpp@3.2.0: - resolution: {integrity: sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==} - engines: {node: '>=8'} + /regexp.prototype.flags@1.5.1: + resolution: {integrity: sha512-sy6TXMN+hnP/wMy+ISxg3krXx7BAtWVO4UouuCN/ziM9UEne0euamVNafDfvC83bRNr95y0V5iijeDQFUNpvrg==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.5 + define-properties: 1.2.1 + set-function-name: 2.0.1 dev: true /regexpu-core@5.3.2: @@ -16431,15 +16755,23 @@ packages: resolution: {integrity: sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==} hasBin: true dependencies: - is-core-module: 2.11.0 + is-core-module: 2.13.1 path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 - /resolve@2.0.0-next.4: - resolution: {integrity: sha512-iMDbmAWtfU+MHpxt/I5iWI7cY6YVEZUQ3MBgPQ++XD1PELuJHIl82xBmObyP2KyQmkNB2dsqF7seoQQiAn5yDQ==} + /resolve@1.22.8: + resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==} hasBin: true dependencies: - is-core-module: 2.11.0 + is-core-module: 2.13.1 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + + /resolve@2.0.0-next.5: + resolution: {integrity: sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==} + hasBin: true + dependencies: + is-core-module: 2.13.1 path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 dev: true @@ -16527,6 +16859,13 @@ packages: '@babel/runtime': 7.22.10 dev: false + /run-applescript@5.0.0: + resolution: {integrity: sha512-XcT5rBksx1QdIhlFOCtgZkB99ZEouFZ1E2Kc2LHqNW13U3/74YGdkQRmThTwxy4QIyookibDKYZOPqX//6BlAg==} + engines: {node: '>=12'} + dependencies: + execa: 5.1.1 + dev: true + /run-async@2.4.1: resolution: {integrity: sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==} engines: {node: '>=0.12.0'} @@ -16552,7 +16891,17 @@ packages: /rxjs@7.5.7: resolution: {integrity: sha512-z9MzKh/UcOqB3i20H6rtrlaE/CgjLOvheWK/9ILrbhROGTweAi1BaFsTT9FbwZi5Trr1qNRs+MXkhmR06awzQA==} dependencies: - tslib: 2.4.1 + tslib: 2.6.2 + dev: true + + /safe-array-concat@1.0.1: + resolution: {integrity: sha512-6XbUAseYE2KtOuGueyeobCySj9L4+66Tn6KQMOPQJrAJEowYKW/YR/MGJZl7FdydUdaFu4LYyDZjxf4/Nmo23Q==} + engines: {node: '>=0.4'} + dependencies: + call-bind: 1.0.5 + get-intrinsic: 1.2.2 + has-symbols: 1.0.3 + isarray: 2.0.5 dev: true /safe-buffer@5.1.2: @@ -16565,8 +16914,8 @@ packages: /safe-regex-test@1.0.0: resolution: {integrity: sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==} dependencies: - call-bind: 1.0.2 - get-intrinsic: 1.1.3 + call-bind: 1.0.5 + get-intrinsic: 1.2.2 is-regex: 1.1.4 dev: true @@ -16671,8 +17020,8 @@ packages: resolution: {integrity: sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow==} dev: true - /semver@5.7.1: - resolution: {integrity: sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==} + /semver@5.7.2: + resolution: {integrity: sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==} hasBin: true /semver@6.3.1: @@ -16732,6 +17081,24 @@ packages: resolution: {integrity: sha512-1jeBGaKNGdEq4FgIrORu/N570dwoPYio8lSoYLWmX7sQ//0JY08Xh9o5pBcgmHQ/MbsYp/aZnOe1s1lIsbLprQ==} dev: true + /set-function-length@1.1.1: + resolution: {integrity: sha512-VoaqjbBJKiWtg4yRcKBQ7g7wnGnLV3M8oLvVWwOk2PdYY6PEFegR1vezXR0tw6fZGF9csVakIRjrJiy2veSBFQ==} + engines: {node: '>= 0.4'} + dependencies: + define-data-property: 1.1.1 + get-intrinsic: 1.2.2 + gopd: 1.0.1 + has-property-descriptors: 1.0.1 + + /set-function-name@2.0.1: + resolution: {integrity: sha512-tMNCiqYVkXIZgc2Hnoy2IvC/f8ezc5koaRFkCjrpWzGpCd3qbZXPzVy9MAZzK1ch/X0jvSkojys3oqJN0qCmdA==} + engines: {node: '>= 0.4'} + dependencies: + define-data-property: 1.1.1 + functions-have-names: 1.2.3 + has-property-descriptors: 1.0.1 + dev: true + /set-harmonic-interval@1.0.1: resolution: {integrity: sha512-AhICkFV84tBP1aWqPwLZqFvAwqEoVA9kxNMniGEUvzOlm4vLmOFLiTT3UZ6bziJTy4bOVpzWGTfSCbmaayGx8g==} engines: {node: '>=6.9'} @@ -16770,9 +17137,9 @@ packages: /side-channel@1.0.4: resolution: {integrity: sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==} dependencies: - call-bind: 1.0.2 - get-intrinsic: 1.1.3 - object-inspect: 1.12.2 + call-bind: 1.0.5 + get-intrinsic: 1.2.2 + object-inspect: 1.13.1 /signal-exit@3.0.7: resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} @@ -17092,33 +17459,43 @@ packages: strip-ansi: 7.0.1 dev: true - /string.prototype.matchall@4.0.8: - resolution: {integrity: sha512-6zOCOcJ+RJAQshcTvXPHoxoQGONa3e/Lqx90wUA+wEzX78sg5Bo+1tQo4N0pohS0erG9qtCqJDjNCQBjeWVxyg==} + /string.prototype.matchall@4.0.10: + resolution: {integrity: sha512-rGXbGmOEosIQi6Qva94HUjgPs9vKW+dkG7Y8Q5O2OYkWL6wFaTRZO8zM4mhP94uX55wgyrXzfS2aGtGzUL7EJQ==} dependencies: - call-bind: 1.0.2 - define-properties: 1.1.4 - es-abstract: 1.20.4 - get-intrinsic: 1.1.3 + call-bind: 1.0.5 + define-properties: 1.2.1 + es-abstract: 1.22.3 + get-intrinsic: 1.2.2 has-symbols: 1.0.3 - internal-slot: 1.0.3 - regexp.prototype.flags: 1.4.3 + internal-slot: 1.0.6 + regexp.prototype.flags: 1.5.1 + set-function-name: 2.0.1 side-channel: 1.0.4 dev: true - /string.prototype.trimend@1.0.5: - resolution: {integrity: sha512-I7RGvmjV4pJ7O3kdf+LXFpVfdNOxtCW/2C8f6jNiW4+PQchwxkCDzlk1/7p+Wl4bqFIZeF47qAHXLuHHWKAxog==} + /string.prototype.trim@1.2.8: + resolution: {integrity: sha512-lfjY4HcixfQXOfaqCvcBuOIapyaroTXhbkfJN3gcB1OtyupngWK4sEET9Knd0cXd28kTUqu/kHoV4HKSJdnjiQ==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.5 + define-properties: 1.2.1 + es-abstract: 1.22.3 + dev: true + + /string.prototype.trimend@1.0.7: + resolution: {integrity: sha512-Ni79DqeB72ZFq1uH/L6zJ+DKZTkOtPIHovb3YZHQViE+HDouuU4mBrLOLDn5Dde3RF8qw5qVETEjhu9locMLvA==} dependencies: - call-bind: 1.0.2 - define-properties: 1.1.4 - es-abstract: 1.20.4 + call-bind: 1.0.5 + define-properties: 1.2.1 + es-abstract: 1.22.3 dev: true - /string.prototype.trimstart@1.0.5: - resolution: {integrity: sha512-THx16TJCGlsN0o6dl2o6ncWUsdgnLRSA23rRE5pyGBw/mLr3Ej/R2LaqCtgP8VNMGZsvMWnf9ooZPyY2bHvUFg==} + /string.prototype.trimstart@1.0.7: + resolution: {integrity: sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg==} dependencies: - call-bind: 1.0.2 - define-properties: 1.1.4 - es-abstract: 1.20.4 + call-bind: 1.0.5 + define-properties: 1.2.1 + es-abstract: 1.22.3 dev: true /string_decoder@1.1.1: @@ -17173,6 +17550,11 @@ packages: engines: {node: '>=6'} dev: true + /strip-final-newline@3.0.0: + resolution: {integrity: sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==} + engines: {node: '>=12'} + dev: true + /strip-indent@3.0.0: resolution: {integrity: sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==} engines: {node: '>=8'} @@ -17282,7 +17664,7 @@ packages: csso: 4.2.0 js-yaml: 3.14.1 mkdirp: 0.5.6 - object.values: 1.1.6 + object.values: 1.1.7 sax: 1.2.4 stable: 0.1.8 unquote: 1.1.1 @@ -17307,21 +17689,18 @@ packages: resolution: {integrity: sha512-AsS729u2RHUfEra9xJrE39peJcc2stq2+poBXX8bcM08Y6g9j/i/PUzwNQqkaJde7Ntg1TO7bSREbR5sdosQ+g==} dev: true + /synckit@0.8.5: + resolution: {integrity: sha512-L1dapNV6vu2s/4Sputv8xGsCdAVlb5nRDMFU/E27D44l5U6cw1g0dGd45uLc+OXjNMmF4ntiMdCimzcjFKQI8Q==} + engines: {node: ^14.18.0 || >=16.0.0} + dependencies: + '@pkgr/utils': 2.4.2 + tslib: 2.6.2 + dev: true + /tabbable@6.1.1: resolution: {integrity: sha512-4kl5w+nCB44EVRdO0g/UGoOp3vlwgycUVtkk/7DPyeLZUCuNFFKCFG6/t/DgHLrUPHjrZg6s5tNm+56Q2B0xyg==} dev: false - /table@6.8.1: - resolution: {integrity: sha512-Y4X9zqrCftUhMeH2EptSSERdVKt/nEdijTOacGD/97EKjhQ/Qs8RTlEGABSJNNN8lac9kheH+af7yAkEWlgneA==} - engines: {node: '>=10.0.0'} - dependencies: - ajv: 8.11.0 - lodash.truncate: 4.4.2 - slice-ansi: 4.0.0 - string-width: 4.2.3 - strip-ansi: 6.0.1 - dev: true - /tapable@2.2.1: resolution: {integrity: sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==} engines: {node: '>=6'} @@ -17507,6 +17886,11 @@ packages: '@popperjs/core': 2.11.6 dev: false + /titleize@3.0.0: + resolution: {integrity: sha512-KxVu8EYHDPBdUYdKZdKtU2aj2XfEx9AfjXxE/Aj0vT06w2icA09Vus1rh6eSu1y01akYg6BjIK/hxyLJINoMLQ==} + engines: {node: '>=12'} + dev: true + /tmp@0.0.33: resolution: {integrity: sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==} engines: {node: '>=0.6.0'} @@ -17576,8 +17960,8 @@ packages: resolution: {integrity: sha512-rvuRbTarPXmMb79SmzEp8aqXNKcK+y0XaB298IXueQ8I2PsrATcPBCSPyK/dDNa2iWOhKlfNnOjdAOTBU/nkFA==} dev: false - /ts-api-utils@1.0.2(typescript@4.9.5): - resolution: {integrity: sha512-Cbu4nIqnEdd+THNEsBdkolnOXhg0I8XteoHaEKgvsxpsbWda4IsUut2c187HxywQCvveojow0Dgw/amxtSKVkQ==} + /ts-api-utils@1.0.3(typescript@4.9.5): + resolution: {integrity: sha512-wNMeqtMz5NtwpT/UZGY5alT+VoKdSsOOP/kqHFcUW1P/VRhH2wJ48+DN2WwUliNbQ976ETwDL0Ifd2VVvgonvg==} engines: {node: '>=16.13.0'} peerDependencies: typescript: '>=4.2.0' @@ -17660,6 +18044,9 @@ packages: /tslib@2.4.1: resolution: {integrity: sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==} + /tslib@2.6.2: + resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==} + /tsutils@3.21.0(typescript@4.9.5): resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==} engines: {node: '>= 6'} @@ -17731,8 +18118,8 @@ packages: resolution: {integrity: sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==} engines: {node: '>=12.20'} - /type-fest@3.5.3: - resolution: {integrity: sha512-V2+og4j/rWReWvaFrse3s9g2xvUv/K9Azm/xo6CjIuq7oeGqsoimC7+9/A3tfvNcbQf8RPSVj/HV81fB4DJrjA==} + /type-fest@3.13.1: + resolution: {integrity: sha512-tLq3bSNx+xSpwvAJnzrK0Ep5CLNWjvFTOp71URMaAEWBfRb9nnJiBoUe0tF8bI4ZFO3omgBR6NvnbzVUT3Ly4g==} engines: {node: '>=14.16'} dev: true @@ -17743,6 +18130,44 @@ packages: media-typer: 0.3.0 mime-types: 2.1.35 + /typed-array-buffer@1.0.0: + resolution: {integrity: sha512-Y8KTSIglk9OZEr8zywiIHG/kmQ7KWyjseXs1CbSo8vC42w7hg2HgYTxSWwP0+is7bWDc1H+Fo026CpHFwm8tkw==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.5 + get-intrinsic: 1.2.2 + is-typed-array: 1.1.12 + dev: true + + /typed-array-byte-length@1.0.0: + resolution: {integrity: sha512-Or/+kvLxNpeQ9DtSydonMxCx+9ZXOswtwJn17SNLvhptaXYDJvkFFP5zbfU/uLmvnBJlI4yrnXRxpdWH/M5tNA==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.5 + for-each: 0.3.3 + has-proto: 1.0.1 + is-typed-array: 1.1.12 + dev: true + + /typed-array-byte-offset@1.0.0: + resolution: {integrity: sha512-RD97prjEt9EL8YgAgpOkf3O4IF9lhJFr9g0htQkm0rchFp/Vx7LW5Q8fSXXub7BXAODyUQohRMyOc3faCPd0hg==} + engines: {node: '>= 0.4'} + dependencies: + available-typed-arrays: 1.0.5 + call-bind: 1.0.5 + for-each: 0.3.3 + has-proto: 1.0.1 + is-typed-array: 1.1.12 + dev: true + + /typed-array-length@1.0.4: + resolution: {integrity: sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==} + dependencies: + call-bind: 1.0.5 + for-each: 0.3.3 + is-typed-array: 1.1.12 + dev: true + /typedarray-to-buffer@3.1.5: resolution: {integrity: sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==} dependencies: @@ -17778,7 +18203,7 @@ packages: /unbox-primitive@1.0.2: resolution: {integrity: sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==} dependencies: - call-bind: 1.0.2 + call-bind: 1.0.5 has-bigints: 1.0.2 has-symbols: 1.0.3 which-boxed-primitive: 1.0.2 @@ -17938,7 +18363,7 @@ packages: dependencies: '@types/react': 16.14.34 react: 16.14.0 - tslib: 2.4.1 + tslib: 2.6.2 dev: true /use-composed-ref@1.3.0(react@16.14.0): @@ -18020,7 +18445,7 @@ packages: '@types/react': 16.14.34 detect-node-es: 1.1.0 react: 16.14.0 - tslib: 2.4.1 + tslib: 2.6.2 dev: true /use-sync-external-store@1.2.0(react@16.14.0): @@ -18038,8 +18463,8 @@ packages: /util.promisify@1.0.1: resolution: {integrity: sha512-g9JpC/3He3bm38zsLupWryXHoEcS22YHthuPQSJdMy6KNrzIRzWqcsHzD/WUnqe45whVou4VIsPew37DoXWNrA==} dependencies: - define-properties: 1.1.4 - es-abstract: 1.20.4 + define-properties: 1.2.1 + es-abstract: 1.22.3 has-symbols: 1.0.3 object.getownpropertydescriptors: 2.1.4 dev: true @@ -18076,10 +18501,6 @@ packages: resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==} dev: true - /v8-compile-cache@2.3.0: - resolution: {integrity: sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==} - dev: true - /v8-to-istanbul@9.0.1: resolution: {integrity: sha512-74Y4LqY74kLE6IFyIjPtkSTWzUZmj8tdHT9Ii/26dvQ6K9Dl2NbEfj0XgU2sHCtKgt5VupqhlO/5aWuqS+IY1w==} engines: {node: '>=10.12.0'} @@ -18366,6 +18787,24 @@ packages: is-string: 1.0.7 is-symbol: 1.0.4 + /which-builtin-type@1.1.3: + resolution: {integrity: sha512-YmjsSMDBYsM1CaFiayOVT06+KJeXf0o5M/CAd4o1lTadFAtacTUM49zoYxr/oroopFDfhvN6iEcBxUyc3gvKmw==} + engines: {node: '>= 0.4'} + dependencies: + function.prototype.name: 1.1.6 + has-tostringtag: 1.0.0 + is-async-function: 2.0.0 + is-date-object: 1.0.5 + is-finalizationregistry: 1.0.2 + is-generator-function: 1.0.10 + is-regex: 1.1.4 + is-weakref: 1.0.2 + isarray: 2.0.5 + which-boxed-primitive: 1.0.2 + which-collection: 1.0.1 + which-typed-array: 1.1.13 + dev: true + /which-collection@1.0.1: resolution: {integrity: sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A==} dependencies: @@ -18378,12 +18817,23 @@ packages: resolution: {integrity: sha512-B+enWhmw6cjfVC7kS8Pj9pCrKSc5txArRyaYGe088shv/FGWH+0Rjx/xPgtsWfsUtS27FkP697E4DDhgrgoc0Q==} dev: true + /which-typed-array@1.1.13: + resolution: {integrity: sha512-P5Nra0qjSncduVPEAr7xhoF5guty49ArDTwzJ/yNuPIbZppyRxFQsRCWrocxIY+CnMVG+qfbU2FmDKyvSGClow==} + engines: {node: '>= 0.4'} + dependencies: + available-typed-arrays: 1.0.5 + call-bind: 1.0.5 + for-each: 0.3.3 + gopd: 1.0.1 + has-tostringtag: 1.0.0 + dev: true + /which-typed-array@1.1.9: resolution: {integrity: sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA==} engines: {node: '>= 0.4'} dependencies: available-typed-arrays: 1.0.5 - call-bind: 1.0.2 + call-bind: 1.0.5 for-each: 0.3.3 gopd: 1.0.1 has-tostringtag: 1.0.0 @@ -18412,11 +18862,6 @@ packages: resolution: {integrity: sha512-JcKqAHLPxcdb9KM49dufGXn2x3ssnfjbcaQdLlfZsL9rH9wgDQjUtDxbo8NE0F6SFvydeu1VhZe7hZuHsB2/pw==} dev: true - /word-wrap@1.2.4: - resolution: {integrity: sha512-2V81OA4ugVo5pRo46hAoD2ivUJx8jXmWXfUkY4KFNw0hEptvN0QfH3K4nHiwzGeKl5rFKedV48QVoqYavy4YpA==} - engines: {node: '>=0.10.0'} - dev: true - /wordwrap@1.0.0: resolution: {integrity: sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==} dev: true From 367b44a8edb744dbef3f680c809a386f19b9754c Mon Sep 17 00:00:00 2001 From: Paul D'Ambra Date: Wed, 25 Oct 2023 17:16:10 +0100 Subject: [PATCH 09/21] feat: remember show advanced filters (#18170) * feat: remember show advanced filters * fix advanced filters check --- .../filters/SessionRecordingsFilters.tsx | 5 +- .../sessionRecordingsPlaylistLogic.ts | 78 ++++++++++++++----- package.json | 1 - 3 files changed, 62 insertions(+), 22 deletions(-) diff --git a/frontend/src/scenes/session-recordings/filters/SessionRecordingsFilters.tsx b/frontend/src/scenes/session-recordings/filters/SessionRecordingsFilters.tsx index 949326b351df8..bc1e108bf7c19 100644 --- a/frontend/src/scenes/session-recordings/filters/SessionRecordingsFilters.tsx +++ b/frontend/src/scenes/session-recordings/filters/SessionRecordingsFilters.tsx @@ -101,8 +101,9 @@ export function SessionRecordingsFilters({ size="small" onClick={() => setShowAdvancedFilters(!showAdvancedFilters)} disabledReason={ - hasAdvancedFilters && - 'You are only allowed person filters and a single pageview event to switch back to simple filters' + hasAdvancedFilters + ? 'You are only allowed person filters and a single pageview event (filtered by current url) to switch back to simple filters' + : undefined } data-attr={`session-recordings-show-${showAdvancedFilters ? 'simple' : 'advanced'}-filters`} > diff --git a/frontend/src/scenes/session-recordings/playlist/sessionRecordingsPlaylistLogic.ts b/frontend/src/scenes/session-recordings/playlist/sessionRecordingsPlaylistLogic.ts index 2c588d43ccf0a..b07d55e3f9d10 100644 --- a/frontend/src/scenes/session-recordings/playlist/sessionRecordingsPlaylistLogic.ts +++ b/frontend/src/scenes/session-recordings/playlist/sessionRecordingsPlaylistLogic.ts @@ -79,30 +79,64 @@ export const getDefaultFilters = (personUUID?: PersonUUID): RecordingFilters => return personUUID ? DEFAULT_PERSON_RECORDING_FILTERS : DEFAULT_RECORDING_FILTERS } +function isPageViewFilter(filter: Record): boolean { + return filter.name === '$pageview' +} +function isCurrentURLPageViewFilter(eventsFilter: Record): boolean { + const hasSingleProperty = Array.isArray(eventsFilter.properties) && eventsFilter.properties?.length === 1 + const isCurrentURLProperty = hasSingleProperty && eventsFilter.properties[0].key === '$current_url' + return isPageViewFilter(eventsFilter) && isCurrentURLProperty +} + +// checks are stored against filter keys so that the type system enforces adding a check when we add new filters +const advancedFilterChecks: Record< + keyof RecordingFilters, + (filters: RecordingFilters, defaultFilters: RecordingFilters) => boolean +> = { + actions: (filters) => (filters.actions ? filters.actions.length > 0 : false), + events: function (filters: RecordingFilters): boolean { + const eventsFilters = filters.events || [] + // simple filters allow a single $pageview event filter with $current_url as the selected property + // anything else is advanced + return ( + eventsFilters.length > 1 || + (!!eventsFilters[0] && + (!isPageViewFilter(eventsFilters[0]) || !isCurrentURLPageViewFilter(eventsFilters[0]))) + ) + }, + properties: function (): boolean { + // TODO is this right? should we ever care about properties for choosing between advanced and simple? + return false + }, + date_from: (filters, defaultFilters) => filters.date_from != defaultFilters.date_from, + date_to: (filters, defaultFilters) => filters.date_to != defaultFilters.date_to, + session_recording_duration: (filters, defaultFilters) => + !equal(filters.session_recording_duration, defaultFilters.session_recording_duration), + duration_type_filter: (filters, defaultFilters) => + filters.duration_type_filter !== defaultFilters.duration_type_filter, + console_search_query: (filters) => + filters.console_search_query ? filters.console_search_query.trim().length > 0 : false, + console_logs: (filters) => (filters.console_logs ? filters.console_logs.length > 0 : false), + filter_test_accounts: (filters) => filters.filter_test_accounts ?? false, +} + export const addedAdvancedFilters = ( filters: RecordingFilters | undefined, defaultFilters: RecordingFilters ): boolean => { - if (!filters) { + // if there are no filters or if some filters are not present then the page is still booting up + if (!filters || filters.session_recording_duration === undefined || filters.date_from === undefined) { return false } - const hasActions = filters.actions ? filters.actions.length > 0 : false - const hasChangedDateFrom = filters.date_from != defaultFilters.date_from - const hasChangedDateTo = filters.date_to != defaultFilters.date_to - const hasConsoleLogsFilters = filters.console_logs ? filters.console_logs.length > 0 : false - const hasChangedDuration = !equal(filters.session_recording_duration, defaultFilters.session_recording_duration) - const eventsFilters = filters.events || [] - const hasAdvancedEvents = eventsFilters.length > 1 || (!!eventsFilters[0] && eventsFilters[0].name != '$pageview') - - return ( - hasActions || - hasAdvancedEvents || - hasChangedDuration || - hasChangedDateFrom || - hasChangedDateTo || - hasConsoleLogsFilters - ) + // keeps results with the keys for printing when debugging + const checkResults = Object.keys(advancedFilterChecks).map((key) => ({ + key, + result: advancedFilterChecks[key](filters, defaultFilters), + })) + + // if any check is true, then this is an advanced filter + return checkResults.some((checkResult) => checkResult.result) } export const defaultPageviewPropertyEntityFilter = ( @@ -348,8 +382,14 @@ export const sessionRecordingsPlaylistLogic = kea - addedAdvancedFilters(filters, getDefaultFilters(props.personUUID)) ? true : showingAdvancedFilters, + persist: true, + }, + { + setFilters: (showingAdvancedFilters, { filters }) => { + return addedAdvancedFilters(filters, getDefaultFilters(props.personUUID)) + ? true + : showingAdvancedFilters + }, setShowAdvancedFilters: (_, { showAdvancedFilters }) => showAdvancedFilters, }, ], diff --git a/package.json b/package.json index c9e9da96b221d..8a718827211fd 100644 --- a/package.json +++ b/package.json @@ -225,7 +225,6 @@ "@types/react-resizable": "^3.0.4", "@types/react-syntax-highlighter": "^15.5.7", "@types/react-textfit": "^1.1.0", - "@types/react-transition-group": "^4.4.4", "@types/react-virtualized": "^9.21.14", "@types/testing-library__jest-dom": "^5.14.5", "@types/zxcvbn": "^4.4.0", From 8a188cc192ffc05ecebc33cefc535fc7761ee19e Mon Sep 17 00:00:00 2001 From: Ben White Date: Thu, 26 Oct 2023 08:45:54 +0200 Subject: [PATCH 10/21] feat: Persons Feed (#18183) --- .../__snapshots__/lemon-ui-icons--shelf-a.png | Bin 35754 -> 56955 bytes .../__snapshots__/lemon-ui-icons--shelf-c.png | Bin 57898 -> 88032 bytes frontend/src/lib/constants.tsx | 1 + frontend/src/lib/lemon-ui/icons/icons.tsx | 22 + .../notebooks/Nodes/NotebookNodePerson.tsx | 1 + .../NotebookNodePersonFeed/EventIcon.tsx | 32 + .../NotebookNodePersonFeed.tsx | 70 + .../Nodes/NotebookNodePersonFeed/Session.tsx | 89 + .../NotebookNodePersonFeed/SessionEvent.tsx | 18 + .../mockSessionsTimelineQueryResponse.json | 27214 ++++++++++++++++ .../notebookNodePersonFeedLogic.ts | 45 + .../src/scenes/notebooks/Notebook/Editor.tsx | 2 + .../src/scenes/notebooks/Notebook/utils.ts | 1 + .../NotebooksTable/ContainsTypeFilter.tsx | 5 +- .../src/scenes/persons/PersonFeedCanvas.tsx | 10 +- frontend/src/scenes/persons/PersonScene.tsx | 9 + frontend/src/scenes/persons/personsLogic.tsx | 14 +- frontend/src/types.ts | 2 + 18 files changed, 27518 insertions(+), 17 deletions(-) create mode 100644 frontend/src/scenes/notebooks/Nodes/NotebookNodePersonFeed/EventIcon.tsx create mode 100644 frontend/src/scenes/notebooks/Nodes/NotebookNodePersonFeed/NotebookNodePersonFeed.tsx create mode 100644 frontend/src/scenes/notebooks/Nodes/NotebookNodePersonFeed/Session.tsx create mode 100644 frontend/src/scenes/notebooks/Nodes/NotebookNodePersonFeed/SessionEvent.tsx create mode 100644 frontend/src/scenes/notebooks/Nodes/NotebookNodePersonFeed/mockSessionsTimelineQueryResponse.json create mode 100644 frontend/src/scenes/notebooks/Nodes/NotebookNodePersonFeed/notebookNodePersonFeedLogic.ts diff --git a/frontend/__snapshots__/lemon-ui-icons--shelf-a.png b/frontend/__snapshots__/lemon-ui-icons--shelf-a.png index 9404063d1c5a84d97e39a201d721c269c6f5a6a3..7637d619130289dfbcb0eaeca81a8929c3a5301f 100644 GIT binary patch literal 56955 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

c3!gqB7)!^Cq8&oBCL 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 literal 57898 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 diff --git a/frontend/src/lib/constants.tsx b/frontend/src/lib/constants.tsx index 4e49a48dbbb7c..6343b341614ef 100644 --- a/frontend/src/lib/constants.tsx +++ b/frontend/src/lib/constants.tsx @@ -167,6 +167,7 @@ export const FEATURE_FLAGS = { PERSONS_HOGQL_QUERY: 'persons-hogql-query', // owner: @mariusandra NOTEBOOK_CANVASES: 'notebook-canvases', // owner: #team-monitoring SESSION_RECORDING_SAMPLING: 'session-recording-sampling', // owner: #team-monitoring + PERSON_FEED_CANVAS: 'person-feed-canvas', // owner: #project-canvas } as const export type FeatureFlagKey = (typeof FEATURE_FLAGS)[keyof typeof FEATURE_FLAGS] diff --git a/frontend/src/lib/lemon-ui/icons/icons.tsx b/frontend/src/lib/lemon-ui/icons/icons.tsx index 55115bab2944b..8d5048e4aad10 100644 --- a/frontend/src/lib/lemon-ui/icons/icons.tsx +++ b/frontend/src/lib/lemon-ui/icons/icons.tsx @@ -2472,3 +2472,25 @@ export function IconNotebook(props: LemonIconProps): JSX.Element { ) } + +export function IconCode(props: LemonIconProps): JSX.Element { + return ( + + + + ) +} + +export function IconAdsClick(props: LemonIconProps): JSX.Element { + return ( + + + + ) +} diff --git a/frontend/src/scenes/notebooks/Nodes/NotebookNodePerson.tsx b/frontend/src/scenes/notebooks/Nodes/NotebookNodePerson.tsx index bdc635d3282c5..d54a338c14b5d 100644 --- a/frontend/src/scenes/notebooks/Nodes/NotebookNodePerson.tsx +++ b/frontend/src/scenes/notebooks/Nodes/NotebookNodePerson.tsx @@ -158,6 +158,7 @@ export const NotebookNodePerson = createPostHogWidgetNode urls.personByDistinctId(attrs.id), resizeable: true, attributes: { diff --git a/frontend/src/scenes/notebooks/Nodes/NotebookNodePersonFeed/EventIcon.tsx b/frontend/src/scenes/notebooks/Nodes/NotebookNodePersonFeed/EventIcon.tsx new file mode 100644 index 0000000000000..abab74d367546 --- /dev/null +++ b/frontend/src/scenes/notebooks/Nodes/NotebookNodePersonFeed/EventIcon.tsx @@ -0,0 +1,32 @@ +import { EventType } from '~/types' + +import { Tooltip } from '@posthog/lemon-ui' +import { IconAdsClick, IconExclamation, IconEyeHidden, IconEyeVisible, IconCode } from 'lib/lemon-ui/icons' +import { KEY_MAPPING } from 'lib/taxonomy' + +type EventIconProps = { event: EventType } + +export const EventIcon = ({ event }: EventIconProps): JSX.Element => { + let Component: React.ComponentType<{ className: string }> + switch (event.event) { + case '$pageview': + Component = IconEyeVisible + break + case '$pageleave': + Component = IconEyeHidden + break + case '$autocapture': + Component = IconAdsClick + break + case '$rageclick': + Component = IconExclamation + break + default: + Component = IconCode + } + return ( + + + + ) +} diff --git a/frontend/src/scenes/notebooks/Nodes/NotebookNodePersonFeed/NotebookNodePersonFeed.tsx b/frontend/src/scenes/notebooks/Nodes/NotebookNodePersonFeed/NotebookNodePersonFeed.tsx new file mode 100644 index 0000000000000..28f71f4493b9a --- /dev/null +++ b/frontend/src/scenes/notebooks/Nodes/NotebookNodePersonFeed/NotebookNodePersonFeed.tsx @@ -0,0 +1,70 @@ +import { useValues } from 'kea' + +import { LemonSkeleton } from '@posthog/lemon-ui' +import { NotFound } from 'lib/components/NotFound' +import { NotebookNodeType, PersonType } from '~/types' +// import { TimelineEntry } from '~/queries/schema' +import { NotebookNodeProps } from 'scenes/notebooks/Notebook/utils' +import { personLogic } from 'scenes/persons/personLogic' +import { createPostHogWidgetNode } from '../NodeWrapper' +import { notebookNodePersonFeedLogic } from './notebookNodePersonFeedLogic' +import { Session } from './Session' + +const FeedSkeleton = (): JSX.Element => ( +

+) + +type FeedProps = { + person: PersonType +} + +const Feed = ({ person }: FeedProps): JSX.Element => { + const id = person.id ?? 'missing' + const { sessions, sessionsLoading } = useValues(notebookNodePersonFeedLogic({ personId: id })) + + if (!sessions && sessionsLoading) { + return + } else if (sessions === null) { + return + } + + return ( +
+ {sessions.map((session: any) => ( + + ))} +
+ ) +} + +const Component = ({ attributes }: NotebookNodeProps): JSX.Element => { + const { id } = attributes + + const logic = personLogic({ id }) + const { person, personLoading } = useValues(logic) + + if (personLoading) { + return + } else if (!person) { + return + } + + return +} + +type NotebookNodePersonFeedAttributes = { + id: string +} + +export const NotebookNodePersonFeed = createPostHogWidgetNode({ + nodeType: NotebookNodeType.PersonFeed, + titlePlaceholder: 'Feed', + Component, + resizeable: false, + expandable: false, + attributes: { + id: {}, + }, +}) diff --git a/frontend/src/scenes/notebooks/Nodes/NotebookNodePersonFeed/Session.tsx b/frontend/src/scenes/notebooks/Nodes/NotebookNodePersonFeed/Session.tsx new file mode 100644 index 0000000000000..e181b27b49bd2 --- /dev/null +++ b/frontend/src/scenes/notebooks/Nodes/NotebookNodePersonFeed/Session.tsx @@ -0,0 +1,89 @@ +import { useState } from 'react' +import { useActions, useValues } from 'kea' + +import { LemonButton } from '@posthog/lemon-ui' +import { IconRewindPlay } from '@posthog/icons' +import { dayjs } from 'lib/dayjs' +// import { TimelineEntry } from '~/queries/schema' +import { NotebookNodeType } from '~/types' +import { IconUnfoldLess, IconUnfoldMore } from 'lib/lemon-ui/icons' +import { humanFriendlyDetailedTime, humanFriendlyDuration } from 'lib/utils' +import { SessionEvent } from './SessionEvent' +import { notebookNodeLogic } from '../notebookNodeLogic' + +type SessionProps = { + session: any // TimelineEntry +} + +export const Session = ({ session }: SessionProps): JSX.Element => { + const { children, nodeId } = useValues(notebookNodeLogic) + const { updateAttributes } = useActions(notebookNodeLogic) + + const startTime = dayjs(session.events[0].timestamp) + const endTime = dayjs(session.events[session.events.length - 1].timestamp) + const durationSeconds = endTime.diff(startTime, 'second') + + const [isFolded, setIsFolded] = useState(false) + + const onOpenReplay = (): void => { + const newChildren = [...children] || [] + + const existingChild = newChildren.find((child) => child.attrs?.nodeId === `${nodeId}-active-replay`) + + if (existingChild) { + existingChild.attrs.id = session.sessionId + } else { + newChildren.splice(0, 0, { + type: NotebookNodeType.Recording, + attrs: { + id: session.sessionId, + nodeId: `${nodeId}-active-replay`, + height: '5rem', + __init: { + expanded: true, + }, + }, + }) + } + + updateAttributes({ + children: newChildren, + }) + } + + return ( +
+
+
+ : } + status="stealth" + onClick={() => setIsFolded((state) => !state)} + /> + {humanFriendlyDetailedTime(startTime)} +
+
+ + {session.events.length} events in {humanFriendlyDuration(durationSeconds)} + + {session.recording_duration_s ? ( + } + onClick={() => onOpenReplay()} + /> + ) : null} +
+
+ {!isFolded && ( +
+ {session.events.map((event: any) => ( + + ))} +
+ )} +
+ ) +} diff --git a/frontend/src/scenes/notebooks/Nodes/NotebookNodePersonFeed/SessionEvent.tsx b/frontend/src/scenes/notebooks/Nodes/NotebookNodePersonFeed/SessionEvent.tsx new file mode 100644 index 0000000000000..00131544c5662 --- /dev/null +++ b/frontend/src/scenes/notebooks/Nodes/NotebookNodePersonFeed/SessionEvent.tsx @@ -0,0 +1,18 @@ +import { EventType } from '~/types' +import { eventToDescription } from 'lib/utils' +import { dayjs } from 'lib/dayjs' +import { EventIcon } from './EventIcon' + +type SessionEventProps = { event: EventType } + +export const SessionEvent = ({ event }: SessionEventProps): JSX.Element => ( +
+
+ + {eventToDescription(event)} +
+
+ {dayjs(event.timestamp).format('h:mm:ss A')} +
+
+) diff --git a/frontend/src/scenes/notebooks/Nodes/NotebookNodePersonFeed/mockSessionsTimelineQueryResponse.json b/frontend/src/scenes/notebooks/Nodes/NotebookNodePersonFeed/mockSessionsTimelineQueryResponse.json new file mode 100644 index 0000000000000..c88078c9cafa0 --- /dev/null +++ b/frontend/src/scenes/notebooks/Nodes/NotebookNodePersonFeed/mockSessionsTimelineQueryResponse.json @@ -0,0 +1,27214 @@ +{ + "hasMore": false, + "hogql": "SELECT e.uuid, e.timestamp, e.event, e.properties, e.distinct_id, e.elements_chain, e.$session_id AS formal_session_id, first_value(e.uuid) OVER (PARTITION BY $session_id ORDER BY divide(__toInt64(timestamp), 60000000.0) ASC RANGE BETWEEN 1800 PRECEDING AND CURRENT ROW) AS informal_session_uuid, dateDiff('s', sre.start_time, sre.end_time) AS recording_duration_s FROM events AS e LEFT JOIN (SELECT start_time, end_time, session_id FROM session_replay_events) AS sre ON equals(e.$session_id, sre.session_id) WHERE equals(e.person_id, '018a92fd-a1c3-0000-4144-fb39888c298e') ORDER BY timestamp DESC LIMIT 100", + "results": [ + { + "events": [ + { + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "elements": [], + "elements_chain": null, + "event": "$pageleave", + "id": "018b4c9d-aef5-789f-81e4-212476c51e92", + "person": null, + "properties": { + "$os": "Mac OS X", + "$os_version": "10.15.7", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/canvas#state=eyJ0eXBlIjoiZG9jIiwiY29udGVudCI6W3sidHlwZSI6ImhlYWRpbmciLCJhdHRycyI6eyJsZXZlbCI6MX0sImNvbnRlbnQiOlt7InR5cGUiOiJ0ZXh0IiwidGV4dCI6IkV2ZW50IEV4cGxvcmVyIn1dfSx7InR5cGUiOiJwaC1xdWVyeSIsImF0dHJzIjp7ImhlaWdodCI6bnVsbCwidGl0bGUiOm51bGwsIm5vZGVJZCI6IjZkNDg1MDY2LWVjOTktNDgzZC04Yjk4LTRkOGEyZGM5Y2M0YiIsIl9faW5pdCI6bnVsbCwiY2hpbGRyZW4iOlt7InR5cGUiOiJwaC1wZXJzb24iLCJhdHRycyI6eyJpZCI6InBsckVZOHBBN3NYMW1GdDg3NGFBVUhlNXRXWmkzbExGOWJ1OWVqUXlHUHkifX0seyJ0eXBlIjoicGgtcmVjb3JkaW5nIiwiYXR0cnMiOnsiaWQiOiIwMThiNDc0MC1kY2JlLTdkNzctYjJlMi05MmJjZTIwYTIzZTMifX1dLCJxdWVyeSI6eyJraW5kIjoiRGF0YVRhYmxlTm9kZSIsInNvdXJjZSI6eyJraW5kIjoiRXZlbnRzUXVlcnkiLCJhZnRlciI6Ii0yNGgiLCJsaW1pdCI6MTAwLCJzZWxlY3QiOlsiKiIsImV2ZW50IiwicGVyc29uIiwiY29hbGVzY2UocHJvcGVydGllcy4kY3VycmVudF91cmwsIHByb3BlcnRpZXMuJHNjcmVlbl9uYW1lKSAtLSBVcmwgLyBTY3JlZW4iLCJwcm9wZXJ0aWVzLiRsaWIiLCJ0aW1lc3RhbXAiXSwicHJvcGVydGllcyI6W119fX19XX0%3D", + "$host": "localhost:8000", + "$pathname": "/canvas", + "$browser_version": 117, + "$browser_language": "en-GB", + "$screen_height": 982, + "$screen_width": 1512, + "$viewport_height": 859, + "$viewport_width": 1512, + "$lib": "web", + "$lib_version": "1.84.0", + "$insert_id": "xumznmndw7ojbqql", + "$time": 1697797484.277, + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$device_id": "018a92fd-7b25-7770-a050-577e94fd148c", + "$console_log_recording_enabled_server_side": true, + "$session_recording_recorder_version_server_side": "v2", + "$autocapture_disabled_server_side": false, + "$active_feature_flags": [ + "signup-page-4.0", + "cmd-k-search", + "posthog-3000", + "funnels-cue-opt-out-7301", + "retention-breakdown", + "smoothing-interval", + "billing-limit", + "kafka-inspector", + "historical-exports-v2", + "person-on-events-enabled", + "region-select", + "ingestion-warnings-enabled", + "session-reset-on-load", + "recordings-on-feature-flags", + "auto-rollback-feature-flags", + "onboarding-v2-demo", + "feature-flag-rollout-ux", + "role-based-access", + "query_running_time", + "query-timings", + "recording-debugging", + "enable-prompts", + "feedback-scene", + "early-access-feature", + "early-access-feature-site-button", + "hedgehog-mode-debug", + "auto-redirect", + "session-recording-blob-replay", + "surveys", + "generic-signup-benefits", + "surveys-positions", + "web-analytics", + "high-frequency-batch-exports", + "exception-autocapture", + "data-warehouse", + "data-warehouse-views", + "ff-dashboard-templates", + "show-product-intro-existing-products", + "artificial-hog", + "cs-dashboards", + "product-specific-onboarding", + "redirect-signups-to-instance", + "apps-and-exports-ui", + "survey-nps-results", + "session-recording-allow-v1-snapshots", + "session-replay-cors-proxy", + "webhooks-denylist", + "surveys-site-app-deprecation", + "surveys-multiple-questions", + "surveys-results-visualizations", + "console-recording-search", + "persons-hogql-query", + "notebooks" + ], + "$feature/file-previews": false, + "$feature/signup-page-4.0": "control", + "$feature/hogql-insights": false, + "$feature/cmd-k-search": true, + "$feature/posthog-3000": true, + "$feature/funnels-cue-opt-out-7301": true, + "$feature/retention-breakdown": true, + "$feature/smoothing-interval": true, + "$feature/billing-limit": true, + "$feature/kafka-inspector": true, + "$feature/historical-exports-v2": true, + "$feature/person-on-events-enabled": true, + "$feature/region-select": true, + "$feature/ingestion-warnings-enabled": true, + "$feature/session-reset-on-load": true, + "$feature/recordings-on-feature-flags": true, + "$feature/auto-rollback-feature-flags": true, + "$feature/onboarding-v2-demo": true, + "$feature/feature-flag-rollout-ux": true, + "$feature/role-based-access": true, + "$feature/query_running_time": true, + "$feature/query-timings": true, + "$feature/recording-debugging": true, + "$feature/enable-prompts": true, + "$feature/feedback-scene": true, + "$feature/early-access-feature": true, + "$feature/early-access-feature-site-button": true, + "$feature/hedgehog-mode-debug": true, + "$feature/auto-redirect": true, + "$feature/session-recording-blob-replay": true, + "$feature/surveys": true, + "$feature/generic-signup-benefits": true, + "$feature/surveys-positions": true, + "$feature/web-analytics": true, + "$feature/high-frequency-batch-exports": true, + "$feature/exception-autocapture": true, + "$feature/data-warehouse": true, + "$feature/data-warehouse-views": true, + "$feature/ff-dashboard-templates": true, + "$feature/show-product-intro-existing-products": true, + "$feature/artificial-hog": true, + "$feature/cs-dashboards": true, + "$feature/product-specific-onboarding": true, + "$feature/redirect-signups-to-instance": true, + "$feature/apps-and-exports-ui": true, + "$feature/survey-nps-results": true, + "$feature/session-recording-allow-v1-snapshots": true, + "$feature/session-replay-cors-proxy": true, + "$feature/webhooks-denylist": true, + "$feature/surveys-site-app-deprecation": true, + "$feature/surveys-multiple-questions": true, + "$feature/surveys-results-visualizations": true, + "$feature/console-recording-search": true, + "$feature/persons-hogql-query": true, + "$feature/notebooks": true, + "$feature_flag_payloads": {}, + "realm": "hosted-clickhouse", + "email_service_available": false, + "slack_service_available": false, + "$user_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "is_demo_project": false, + "$groups": { + "project": "018a92f8-b602-0000-75de-4b9073693531", + "organization": "018a92f8-afff-0000-efec-ca77de39e384", + "customer": "cus_OdSgxxWtHOtq9g", + "instance": "http://localhost:8000" + }, + "has_billing_plan": true, + "customer_deactivated": false, + "current_total_amount_usd": "0.00", + "percentage_usage.product_analytics": 0, + "current_amount_usd.product_analytics": "0.00", + "unit_amount_usd.product_analytics": null, + "usage_limit.product_analytics": null, + "current_usage.product_analytics": 3729, + "projected_usage.product_analytics": 0, + "free_allocation.product_analytics": 0, + "percentage_usage.session_replay": 0, + "current_amount_usd.session_replay": "0.00", + "unit_amount_usd.session_replay": null, + "usage_limit.session_replay": null, + "current_usage.session_replay": 254, + "projected_usage.session_replay": 0, + "free_allocation.session_replay": 0, + "percentage_usage.feature_flags": 0, + "current_amount_usd.feature_flags": "0.00", + "unit_amount_usd.feature_flags": null, + "usage_limit.feature_flags": null, + "current_usage.feature_flags": 0, + "projected_usage.feature_flags": 0, + "free_allocation.feature_flags": 0, + "percentage_usage.integrations": 0, + "current_amount_usd.integrations": null, + "unit_amount_usd.integrations": null, + "usage_limit.integrations": 0, + "current_usage.integrations": 0, + "projected_usage.integrations": 0, + "free_allocation.integrations": 0, + "percentage_usage.platform_and_support": 0, + "current_amount_usd.platform_and_support": null, + "unit_amount_usd.platform_and_support": null, + "usage_limit.platform_and_support": 0, + "current_usage.platform_and_support": 0, + "projected_usage.platform_and_support": 0, + "free_allocation.platform_and_support": 0, + "billing_period_start": "2023-10-14T09:22:33.000Z", + "billing_period_end": "2023-11-14T09:22:33.000Z", + "$referrer": "$direct", + "$referring_domain": "$direct", + "token": "phc_OWGI2wKbfi7rWDZT9wkl8uGcfe0wOGCvflLEZSMiaT0", + "$session_id": "018b4c9d-ab5d-778b-9a9c-57db85a58ec0", + "$window_id": "018b4c9d-ab5d-778b-9a9c-57dc585fb9f0", + "$ip": "127.0.0.1", + "$set": { + "$os": "Mac OS X", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/canvas#state=eyJ0eXBlIjoiZG9jIiwiY29udGVudCI6W3sidHlwZSI6ImhlYWRpbmciLCJhdHRycyI6eyJsZXZlbCI6MX0sImNvbnRlbnQiOlt7InR5cGUiOiJ0ZXh0IiwidGV4dCI6IkV2ZW50IEV4cGxvcmVyIn1dfSx7InR5cGUiOiJwaC1xdWVyeSIsImF0dHJzIjp7ImhlaWdodCI6bnVsbCwidGl0bGUiOm51bGwsIm5vZGVJZCI6IjZkNDg1MDY2LWVjOTktNDgzZC04Yjk4LTRkOGEyZGM5Y2M0YiIsIl9faW5pdCI6bnVsbCwiY2hpbGRyZW4iOlt7InR5cGUiOiJwaC1wZXJzb24iLCJhdHRycyI6eyJpZCI6InBsckVZOHBBN3NYMW1GdDg3NGFBVUhlNXRXWmkzbExGOWJ1OWVqUXlHUHkifX0seyJ0eXBlIjoicGgtcmVjb3JkaW5nIiwiYXR0cnMiOnsiaWQiOiIwMThiNDc0MC1kY2JlLTdkNzctYjJlMi05MmJjZTIwYTIzZTMifX1dLCJxdWVyeSI6eyJraW5kIjoiRGF0YVRhYmxlTm9kZSIsInNvdXJjZSI6eyJraW5kIjoiRXZlbnRzUXVlcnkiLCJhZnRlciI6Ii0yNGgiLCJsaW1pdCI6MTAwLCJzZWxlY3QiOlsiKiIsImV2ZW50IiwicGVyc29uIiwiY29hbGVzY2UocHJvcGVydGllcy4kY3VycmVudF91cmwsIHByb3BlcnRpZXMuJHNjcmVlbl9uYW1lKSAtLSBVcmwgLyBTY3JlZW4iLCJwcm9wZXJ0aWVzLiRsaWIiLCJ0aW1lc3RhbXAiXSwicHJvcGVydGllcyI6W119fX19XX0%3D", + "$pathname": "/canvas", + "$browser_version": 117, + "$referrer": "$direct", + "$referring_domain": "$direct" + }, + "$set_once": { + "$initial_os": "Mac OS X", + "$initial_browser": "Chrome", + "$initial_device_type": "Desktop", + "$initial_current_url": "http://localhost:8000/canvas#state=eyJ0eXBlIjoiZG9jIiwiY29udGVudCI6W3sidHlwZSI6ImhlYWRpbmciLCJhdHRycyI6eyJsZXZlbCI6MX0sImNvbnRlbnQiOlt7InR5cGUiOiJ0ZXh0IiwidGV4dCI6IkV2ZW50IEV4cGxvcmVyIn1dfSx7InR5cGUiOiJwaC1xdWVyeSIsImF0dHJzIjp7ImhlaWdodCI6bnVsbCwidGl0bGUiOm51bGwsIm5vZGVJZCI6IjZkNDg1MDY2LWVjOTktNDgzZC04Yjk4LTRkOGEyZGM5Y2M0YiIsIl9faW5pdCI6bnVsbCwiY2hpbGRyZW4iOlt7InR5cGUiOiJwaC1wZXJzb24iLCJhdHRycyI6eyJpZCI6InBsckVZOHBBN3NYMW1GdDg3NGFBVUhlNXRXWmkzbExGOWJ1OWVqUXlHUHkifX0seyJ0eXBlIjoicGgtcmVjb3JkaW5nIiwiYXR0cnMiOnsiaWQiOiIwMThiNDc0MC1kY2JlLTdkNzctYjJlMi05MmJjZTIwYTIzZTMifX1dLCJxdWVyeSI6eyJraW5kIjoiRGF0YVRhYmxlTm9kZSIsInNvdXJjZSI6eyJraW5kIjoiRXZlbnRzUXVlcnkiLCJhZnRlciI6Ii0yNGgiLCJsaW1pdCI6MTAwLCJzZWxlY3QiOlsiKiIsImV2ZW50IiwicGVyc29uIiwiY29hbGVzY2UocHJvcGVydGllcy4kY3VycmVudF91cmwsIHByb3BlcnRpZXMuJHNjcmVlbl9uYW1lKSAtLSBVcmwgLyBTY3JlZW4iLCJwcm9wZXJ0aWVzLiRsaWIiLCJ0aW1lc3RhbXAiXSwicHJvcGVydGllcyI6W119fX19XX0%3D", + "$initial_pathname": "/canvas", + "$initial_browser_version": 117, + "$initial_referrer": "$direct", + "$initial_referring_domain": "$direct" + }, + "$sent_at": "2023-10-20T10:24:44.284000+00:00", + "$geoip_city_name": "Sydney", + "$geoip_country_name": "Australia", + "$geoip_country_code": "AU", + "$geoip_continent_name": "Oceania", + "$geoip_continent_code": "OC", + "$geoip_postal_code": "2000", + "$geoip_latitude": -33.8715, + "$geoip_longitude": 151.2006, + "$geoip_time_zone": "Australia/Sydney", + "$geoip_subdivision_1_code": "NSW", + "$geoip_subdivision_1_name": "New South Wales", + "$plugins_succeeded": ["GeoIP (1)"], + "$plugins_failed": [], + "$plugins_deferred": [], + "$group_3": "018a92f8-b602-0000-75de-4b9073693531", + "$group_2": "018a92f8-afff-0000-efec-ca77de39e384", + "$group_4": "cus_OdSgxxWtHOtq9g", + "$group_1": "http://localhost:8000" + }, + "timestamp": "2023-10-20T10:24:44.281000+00:00", + "uuid": null + }, + { + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "elements": [], + "elements_chain": null, + "event": "$opt_in", + "id": "018b4ca0-9676-7421-9397-8506bb94ebac", + "person": null, + "properties": { + "$os": "Mac OS X", + "$os_version": "10.15.7", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/", + "$host": "localhost:8000", + "$pathname": "/", + "$browser_version": 117, + "$browser_language": "en-GB", + "$screen_height": 982, + "$screen_width": 1512, + "$viewport_height": 859, + "$viewport_width": 1512, + "$lib": "web", + "$lib_version": "1.84.0", + "$insert_id": "vodqry65n7z97q71", + "$time": 1697797674.614, + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$device_id": "018a92fd-7b25-7770-a050-577e94fd148c", + "$console_log_recording_enabled_server_side": true, + "$session_recording_recorder_version_server_side": "v2", + "$autocapture_disabled_server_side": false, + "$active_feature_flags": [ + "signup-page-4.0", + "cmd-k-search", + "posthog-3000", + "funnels-cue-opt-out-7301", + "retention-breakdown", + "smoothing-interval", + "billing-limit", + "kafka-inspector", + "historical-exports-v2", + "person-on-events-enabled", + "region-select", + "ingestion-warnings-enabled", + "session-reset-on-load", + "recordings-on-feature-flags", + "auto-rollback-feature-flags", + "onboarding-v2-demo", + "feature-flag-rollout-ux", + "role-based-access", + "query_running_time", + "query-timings", + "recording-debugging", + "enable-prompts", + "feedback-scene", + "early-access-feature", + "early-access-feature-site-button", + "hedgehog-mode-debug", + "auto-redirect", + "session-recording-blob-replay", + "surveys", + "generic-signup-benefits", + "surveys-positions", + "web-analytics", + "high-frequency-batch-exports", + "exception-autocapture", + "data-warehouse", + "data-warehouse-views", + "ff-dashboard-templates", + "show-product-intro-existing-products", + "artificial-hog", + "cs-dashboards", + "product-specific-onboarding", + "redirect-signups-to-instance", + "apps-and-exports-ui", + "survey-nps-results", + "session-recording-allow-v1-snapshots", + "session-replay-cors-proxy", + "webhooks-denylist", + "surveys-site-app-deprecation", + "surveys-multiple-questions", + "surveys-results-visualizations", + "console-recording-search", + "persons-hogql-query", + "notebooks" + ], + "$feature/file-previews": false, + "$feature/signup-page-4.0": "control", + "$feature/hogql-insights": false, + "$feature/cmd-k-search": true, + "$feature/posthog-3000": true, + "$feature/funnels-cue-opt-out-7301": true, + "$feature/retention-breakdown": true, + "$feature/smoothing-interval": true, + "$feature/billing-limit": true, + "$feature/kafka-inspector": true, + "$feature/historical-exports-v2": true, + "$feature/person-on-events-enabled": true, + "$feature/region-select": true, + "$feature/ingestion-warnings-enabled": true, + "$feature/session-reset-on-load": true, + "$feature/recordings-on-feature-flags": true, + "$feature/auto-rollback-feature-flags": true, + "$feature/onboarding-v2-demo": true, + "$feature/feature-flag-rollout-ux": true, + "$feature/role-based-access": true, + "$feature/query_running_time": true, + "$feature/query-timings": true, + "$feature/recording-debugging": true, + "$feature/enable-prompts": true, + "$feature/feedback-scene": true, + "$feature/early-access-feature": true, + "$feature/early-access-feature-site-button": true, + "$feature/hedgehog-mode-debug": true, + "$feature/auto-redirect": true, + "$feature/session-recording-blob-replay": true, + "$feature/surveys": true, + "$feature/generic-signup-benefits": true, + "$feature/surveys-positions": true, + "$feature/web-analytics": true, + "$feature/high-frequency-batch-exports": true, + "$feature/exception-autocapture": true, + "$feature/data-warehouse": true, + "$feature/data-warehouse-views": true, + "$feature/ff-dashboard-templates": true, + "$feature/show-product-intro-existing-products": true, + "$feature/artificial-hog": true, + "$feature/cs-dashboards": true, + "$feature/product-specific-onboarding": true, + "$feature/redirect-signups-to-instance": true, + "$feature/apps-and-exports-ui": true, + "$feature/survey-nps-results": true, + "$feature/session-recording-allow-v1-snapshots": true, + "$feature/session-replay-cors-proxy": true, + "$feature/webhooks-denylist": true, + "$feature/surveys-site-app-deprecation": true, + "$feature/surveys-multiple-questions": true, + "$feature/surveys-results-visualizations": true, + "$feature/console-recording-search": true, + "$feature/persons-hogql-query": true, + "$feature/notebooks": true, + "$feature_flag_payloads": {}, + "realm": "hosted-clickhouse", + "email_service_available": false, + "slack_service_available": false, + "$user_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "is_demo_project": false, + "$groups": { + "project": "018a92f8-b602-0000-75de-4b9073693531", + "organization": "018a92f8-afff-0000-efec-ca77de39e384", + "customer": "cus_OdSgxxWtHOtq9g", + "instance": "http://localhost:8000" + }, + "has_billing_plan": true, + "customer_deactivated": false, + "current_total_amount_usd": "0.00", + "percentage_usage.product_analytics": 0, + "current_amount_usd.product_analytics": "0.00", + "unit_amount_usd.product_analytics": null, + "usage_limit.product_analytics": null, + "current_usage.product_analytics": 3729, + "projected_usage.product_analytics": 0, + "free_allocation.product_analytics": 0, + "percentage_usage.session_replay": 0, + "current_amount_usd.session_replay": "0.00", + "unit_amount_usd.session_replay": null, + "usage_limit.session_replay": null, + "current_usage.session_replay": 254, + "projected_usage.session_replay": 0, + "free_allocation.session_replay": 0, + "percentage_usage.feature_flags": 0, + "current_amount_usd.feature_flags": "0.00", + "unit_amount_usd.feature_flags": null, + "usage_limit.feature_flags": null, + "current_usage.feature_flags": 0, + "projected_usage.feature_flags": 0, + "free_allocation.feature_flags": 0, + "percentage_usage.integrations": 0, + "current_amount_usd.integrations": null, + "unit_amount_usd.integrations": null, + "usage_limit.integrations": 0, + "current_usage.integrations": 0, + "projected_usage.integrations": 0, + "free_allocation.integrations": 0, + "percentage_usage.platform_and_support": 0, + "current_amount_usd.platform_and_support": null, + "unit_amount_usd.platform_and_support": null, + "usage_limit.platform_and_support": 0, + "current_usage.platform_and_support": 0, + "projected_usage.platform_and_support": 0, + "free_allocation.platform_and_support": 0, + "billing_period_start": "2023-10-14T09:22:33.000Z", + "billing_period_end": "2023-11-14T09:22:33.000Z", + "$referrer": "$direct", + "$referring_domain": "$direct", + "token": "phc_OWGI2wKbfi7rWDZT9wkl8uGcfe0wOGCvflLEZSMiaT0", + "$session_id": "018b4c9d-ab5d-778b-9a9c-57db85a58ec0", + "$window_id": "018b4ca0-9674-7a84-9e68-ee5996f32986", + "$ip": "127.0.0.1", + "$set": { + "$os": "Mac OS X", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/", + "$pathname": "/", + "$browser_version": 117, + "$referrer": "$direct", + "$referring_domain": "$direct" + }, + "$set_once": { + "$initial_os": "Mac OS X", + "$initial_browser": "Chrome", + "$initial_device_type": "Desktop", + "$initial_current_url": "http://localhost:8000/", + "$initial_pathname": "/", + "$initial_browser_version": 117, + "$initial_referrer": "$direct", + "$initial_referring_domain": "$direct" + }, + "$sent_at": "2023-10-20T10:27:54.616000+00:00", + "$geoip_city_name": "Sydney", + "$geoip_country_name": "Australia", + "$geoip_country_code": "AU", + "$geoip_continent_name": "Oceania", + "$geoip_continent_code": "OC", + "$geoip_postal_code": "2000", + "$geoip_latitude": -33.8715, + "$geoip_longitude": 151.2006, + "$geoip_time_zone": "Australia/Sydney", + "$geoip_subdivision_1_code": "NSW", + "$geoip_subdivision_1_name": "New South Wales", + "$plugins_succeeded": ["GeoIP (1)"], + "$plugins_failed": [], + "$plugins_deferred": [], + "$group_3": "018a92f8-b602-0000-75de-4b9073693531", + "$group_2": "018a92f8-afff-0000-efec-ca77de39e384", + "$group_4": "cus_OdSgxxWtHOtq9g", + "$group_1": "http://localhost:8000" + }, + "timestamp": "2023-10-20T10:27:54.625000+00:00", + "uuid": null + }, + { + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "elements": [], + "elements_chain": null, + "event": "$pageview", + "id": "018b4ca0-9678-732b-a9e0-bfbbd9dbc2ce", + "person": null, + "properties": { + "$os": "Mac OS X", + "$os_version": "10.15.7", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/", + "$host": "localhost:8000", + "$pathname": "/", + "$browser_version": 117, + "$browser_language": "en-GB", + "$screen_height": 982, + "$screen_width": 1512, + "$viewport_height": 859, + "$viewport_width": 1512, + "$lib": "web", + "$lib_version": "1.84.0", + "$insert_id": "tkovmn0505g1e31n", + "$time": 1697797674.616, + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$device_id": "018a92fd-7b25-7770-a050-577e94fd148c", + "$console_log_recording_enabled_server_side": true, + "$session_recording_recorder_version_server_side": "v2", + "$autocapture_disabled_server_side": false, + "$active_feature_flags": [ + "signup-page-4.0", + "cmd-k-search", + "posthog-3000", + "funnels-cue-opt-out-7301", + "retention-breakdown", + "smoothing-interval", + "billing-limit", + "kafka-inspector", + "historical-exports-v2", + "person-on-events-enabled", + "region-select", + "ingestion-warnings-enabled", + "session-reset-on-load", + "recordings-on-feature-flags", + "auto-rollback-feature-flags", + "onboarding-v2-demo", + "feature-flag-rollout-ux", + "role-based-access", + "query_running_time", + "query-timings", + "recording-debugging", + "enable-prompts", + "feedback-scene", + "early-access-feature", + "early-access-feature-site-button", + "hedgehog-mode-debug", + "auto-redirect", + "session-recording-blob-replay", + "surveys", + "generic-signup-benefits", + "surveys-positions", + "web-analytics", + "high-frequency-batch-exports", + "exception-autocapture", + "data-warehouse", + "data-warehouse-views", + "ff-dashboard-templates", + "show-product-intro-existing-products", + "artificial-hog", + "cs-dashboards", + "product-specific-onboarding", + "redirect-signups-to-instance", + "apps-and-exports-ui", + "survey-nps-results", + "session-recording-allow-v1-snapshots", + "session-replay-cors-proxy", + "webhooks-denylist", + "surveys-site-app-deprecation", + "surveys-multiple-questions", + "surveys-results-visualizations", + "console-recording-search", + "persons-hogql-query", + "notebooks" + ], + "$feature/file-previews": false, + "$feature/signup-page-4.0": "control", + "$feature/hogql-insights": false, + "$feature/cmd-k-search": true, + "$feature/posthog-3000": true, + "$feature/funnels-cue-opt-out-7301": true, + "$feature/retention-breakdown": true, + "$feature/smoothing-interval": true, + "$feature/billing-limit": true, + "$feature/kafka-inspector": true, + "$feature/historical-exports-v2": true, + "$feature/person-on-events-enabled": true, + "$feature/region-select": true, + "$feature/ingestion-warnings-enabled": true, + "$feature/session-reset-on-load": true, + "$feature/recordings-on-feature-flags": true, + "$feature/auto-rollback-feature-flags": true, + "$feature/onboarding-v2-demo": true, + "$feature/feature-flag-rollout-ux": true, + "$feature/role-based-access": true, + "$feature/query_running_time": true, + "$feature/query-timings": true, + "$feature/recording-debugging": true, + "$feature/enable-prompts": true, + "$feature/feedback-scene": true, + "$feature/early-access-feature": true, + "$feature/early-access-feature-site-button": true, + "$feature/hedgehog-mode-debug": true, + "$feature/auto-redirect": true, + "$feature/session-recording-blob-replay": true, + "$feature/surveys": true, + "$feature/generic-signup-benefits": true, + "$feature/surveys-positions": true, + "$feature/web-analytics": true, + "$feature/high-frequency-batch-exports": true, + "$feature/exception-autocapture": true, + "$feature/data-warehouse": true, + "$feature/data-warehouse-views": true, + "$feature/ff-dashboard-templates": true, + "$feature/show-product-intro-existing-products": true, + "$feature/artificial-hog": true, + "$feature/cs-dashboards": true, + "$feature/product-specific-onboarding": true, + "$feature/redirect-signups-to-instance": true, + "$feature/apps-and-exports-ui": true, + "$feature/survey-nps-results": true, + "$feature/session-recording-allow-v1-snapshots": true, + "$feature/session-replay-cors-proxy": true, + "$feature/webhooks-denylist": true, + "$feature/surveys-site-app-deprecation": true, + "$feature/surveys-multiple-questions": true, + "$feature/surveys-results-visualizations": true, + "$feature/console-recording-search": true, + "$feature/persons-hogql-query": true, + "$feature/notebooks": true, + "$feature_flag_payloads": {}, + "realm": "hosted-clickhouse", + "email_service_available": false, + "slack_service_available": false, + "$user_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "is_demo_project": false, + "$groups": { + "project": "018a92f8-b602-0000-75de-4b9073693531", + "organization": "018a92f8-afff-0000-efec-ca77de39e384", + "customer": "cus_OdSgxxWtHOtq9g", + "instance": "http://localhost:8000" + }, + "has_billing_plan": true, + "customer_deactivated": false, + "current_total_amount_usd": "0.00", + "percentage_usage.product_analytics": 0, + "current_amount_usd.product_analytics": "0.00", + "unit_amount_usd.product_analytics": null, + "usage_limit.product_analytics": null, + "current_usage.product_analytics": 3729, + "projected_usage.product_analytics": 0, + "free_allocation.product_analytics": 0, + "percentage_usage.session_replay": 0, + "current_amount_usd.session_replay": "0.00", + "unit_amount_usd.session_replay": null, + "usage_limit.session_replay": null, + "current_usage.session_replay": 254, + "projected_usage.session_replay": 0, + "free_allocation.session_replay": 0, + "percentage_usage.feature_flags": 0, + "current_amount_usd.feature_flags": "0.00", + "unit_amount_usd.feature_flags": null, + "usage_limit.feature_flags": null, + "current_usage.feature_flags": 0, + "projected_usage.feature_flags": 0, + "free_allocation.feature_flags": 0, + "percentage_usage.integrations": 0, + "current_amount_usd.integrations": null, + "unit_amount_usd.integrations": null, + "usage_limit.integrations": 0, + "current_usage.integrations": 0, + "projected_usage.integrations": 0, + "free_allocation.integrations": 0, + "percentage_usage.platform_and_support": 0, + "current_amount_usd.platform_and_support": null, + "unit_amount_usd.platform_and_support": null, + "usage_limit.platform_and_support": 0, + "current_usage.platform_and_support": 0, + "projected_usage.platform_and_support": 0, + "free_allocation.platform_and_support": 0, + "billing_period_start": "2023-10-14T09:22:33.000Z", + "billing_period_end": "2023-11-14T09:22:33.000Z", + "$referrer": "$direct", + "$referring_domain": "$direct", + "title": "PostHog", + "token": "phc_OWGI2wKbfi7rWDZT9wkl8uGcfe0wOGCvflLEZSMiaT0", + "$session_id": "018b4c9d-ab5d-778b-9a9c-57db85a58ec0", + "$window_id": "018b4ca0-9674-7a84-9e68-ee5996f32986", + "$ip": "127.0.0.1", + "$set": { + "$os": "Mac OS X", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/", + "$pathname": "/", + "$browser_version": 117, + "$referrer": "$direct", + "$referring_domain": "$direct" + }, + "$set_once": { + "$initial_os": "Mac OS X", + "$initial_browser": "Chrome", + "$initial_device_type": "Desktop", + "$initial_current_url": "http://localhost:8000/", + "$initial_pathname": "/", + "$initial_browser_version": 117, + "$initial_referrer": "$direct", + "$initial_referring_domain": "$direct" + }, + "$sent_at": "2023-10-20T10:27:54.617000+00:00", + "$geoip_city_name": "Sydney", + "$geoip_country_name": "Australia", + "$geoip_country_code": "AU", + "$geoip_continent_name": "Oceania", + "$geoip_continent_code": "OC", + "$geoip_postal_code": "2000", + "$geoip_latitude": -33.8715, + "$geoip_longitude": 151.2006, + "$geoip_time_zone": "Australia/Sydney", + "$geoip_subdivision_1_code": "NSW", + "$geoip_subdivision_1_name": "New South Wales", + "$plugins_succeeded": ["GeoIP (1)"], + "$plugins_failed": [], + "$plugins_deferred": [], + "$group_3": "018a92f8-b602-0000-75de-4b9073693531", + "$group_2": "018a92f8-afff-0000-efec-ca77de39e384", + "$group_4": "cus_OdSgxxWtHOtq9g", + "$group_1": "http://localhost:8000" + }, + "timestamp": "2023-10-20T10:27:54.631000+00:00", + "uuid": null + } + ], + "recording_duration_s": null, + "sessionId": "018b4c9d-ab5d-778b-9a9c-57db85a58ec0" + }, + { + "events": [ + { + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "elements": [], + "elements_chain": null, + "event": "$set", + "id": "018b4ca0-9686-7b75-ba2e-61e8667c6a38", + "person": null, + "properties": { + "$os": "Mac OS X", + "$os_version": "10.15.7", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/", + "$host": "localhost:8000", + "$pathname": "/", + "$browser_version": 117, + "$browser_language": "en-GB", + "$screen_height": 982, + "$screen_width": 1512, + "$viewport_height": 859, + "$viewport_width": 1512, + "$lib": "web", + "$lib_version": "1.84.0", + "$insert_id": "rffzbtlav260619e", + "$time": 1697797674.63, + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$device_id": "018a92fd-7b25-7770-a050-577e94fd148c", + "$console_log_recording_enabled_server_side": true, + "$session_recording_recorder_version_server_side": "v2", + "$autocapture_disabled_server_side": false, + "$active_feature_flags": [ + "signup-page-4.0", + "cmd-k-search", + "posthog-3000", + "funnels-cue-opt-out-7301", + "retention-breakdown", + "smoothing-interval", + "billing-limit", + "kafka-inspector", + "historical-exports-v2", + "person-on-events-enabled", + "region-select", + "ingestion-warnings-enabled", + "session-reset-on-load", + "recordings-on-feature-flags", + "auto-rollback-feature-flags", + "onboarding-v2-demo", + "feature-flag-rollout-ux", + "role-based-access", + "query_running_time", + "query-timings", + "recording-debugging", + "enable-prompts", + "feedback-scene", + "early-access-feature", + "early-access-feature-site-button", + "hedgehog-mode-debug", + "auto-redirect", + "session-recording-blob-replay", + "surveys", + "generic-signup-benefits", + "surveys-positions", + "web-analytics", + "high-frequency-batch-exports", + "exception-autocapture", + "data-warehouse", + "data-warehouse-views", + "ff-dashboard-templates", + "show-product-intro-existing-products", + "artificial-hog", + "cs-dashboards", + "product-specific-onboarding", + "redirect-signups-to-instance", + "apps-and-exports-ui", + "survey-nps-results", + "session-recording-allow-v1-snapshots", + "session-replay-cors-proxy", + "webhooks-denylist", + "surveys-site-app-deprecation", + "surveys-multiple-questions", + "surveys-results-visualizations", + "console-recording-search", + "persons-hogql-query", + "notebooks" + ], + "$feature/file-previews": false, + "$feature/signup-page-4.0": "control", + "$feature/hogql-insights": false, + "$feature/cmd-k-search": true, + "$feature/posthog-3000": true, + "$feature/funnels-cue-opt-out-7301": true, + "$feature/retention-breakdown": true, + "$feature/smoothing-interval": true, + "$feature/billing-limit": true, + "$feature/kafka-inspector": true, + "$feature/historical-exports-v2": true, + "$feature/person-on-events-enabled": true, + "$feature/region-select": true, + "$feature/ingestion-warnings-enabled": true, + "$feature/session-reset-on-load": true, + "$feature/recordings-on-feature-flags": true, + "$feature/auto-rollback-feature-flags": true, + "$feature/onboarding-v2-demo": true, + "$feature/feature-flag-rollout-ux": true, + "$feature/role-based-access": true, + "$feature/query_running_time": true, + "$feature/query-timings": true, + "$feature/recording-debugging": true, + "$feature/enable-prompts": true, + "$feature/feedback-scene": true, + "$feature/early-access-feature": true, + "$feature/early-access-feature-site-button": true, + "$feature/hedgehog-mode-debug": true, + "$feature/auto-redirect": true, + "$feature/session-recording-blob-replay": true, + "$feature/surveys": true, + "$feature/generic-signup-benefits": true, + "$feature/surveys-positions": true, + "$feature/web-analytics": true, + "$feature/high-frequency-batch-exports": true, + "$feature/exception-autocapture": true, + "$feature/data-warehouse": true, + "$feature/data-warehouse-views": true, + "$feature/ff-dashboard-templates": true, + "$feature/show-product-intro-existing-products": true, + "$feature/artificial-hog": true, + "$feature/cs-dashboards": true, + "$feature/product-specific-onboarding": true, + "$feature/redirect-signups-to-instance": true, + "$feature/apps-and-exports-ui": true, + "$feature/survey-nps-results": true, + "$feature/session-recording-allow-v1-snapshots": true, + "$feature/session-replay-cors-proxy": true, + "$feature/webhooks-denylist": true, + "$feature/surveys-site-app-deprecation": true, + "$feature/surveys-multiple-questions": true, + "$feature/surveys-results-visualizations": true, + "$feature/console-recording-search": true, + "$feature/persons-hogql-query": true, + "$feature/notebooks": true, + "$feature_flag_payloads": {}, + "realm": "hosted-clickhouse", + "email_service_available": false, + "slack_service_available": false, + "$user_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "is_demo_project": false, + "$groups": { + "project": "018a92f8-b602-0000-75de-4b9073693531", + "organization": "018a92f8-afff-0000-efec-ca77de39e384", + "customer": "cus_OdSgxxWtHOtq9g", + "instance": "http://localhost:8000" + }, + "has_billing_plan": true, + "customer_deactivated": false, + "current_total_amount_usd": "0.00", + "percentage_usage.product_analytics": 0, + "current_amount_usd.product_analytics": "0.00", + "unit_amount_usd.product_analytics": null, + "usage_limit.product_analytics": null, + "current_usage.product_analytics": 3729, + "projected_usage.product_analytics": 0, + "free_allocation.product_analytics": 0, + "percentage_usage.session_replay": 0, + "current_amount_usd.session_replay": "0.00", + "unit_amount_usd.session_replay": null, + "usage_limit.session_replay": null, + "current_usage.session_replay": 254, + "projected_usage.session_replay": 0, + "free_allocation.session_replay": 0, + "percentage_usage.feature_flags": 0, + "current_amount_usd.feature_flags": "0.00", + "unit_amount_usd.feature_flags": null, + "usage_limit.feature_flags": null, + "current_usage.feature_flags": 0, + "projected_usage.feature_flags": 0, + "free_allocation.feature_flags": 0, + "percentage_usage.integrations": 0, + "current_amount_usd.integrations": null, + "unit_amount_usd.integrations": null, + "usage_limit.integrations": 0, + "current_usage.integrations": 0, + "projected_usage.integrations": 0, + "free_allocation.integrations": 0, + "percentage_usage.platform_and_support": 0, + "current_amount_usd.platform_and_support": null, + "unit_amount_usd.platform_and_support": null, + "usage_limit.platform_and_support": 0, + "current_usage.platform_and_support": 0, + "projected_usage.platform_and_support": 0, + "free_allocation.platform_and_support": 0, + "billing_period_start": "2023-10-14T09:22:33.000Z", + "billing_period_end": "2023-11-14T09:22:33.000Z", + "$referrer": "$direct", + "$referring_domain": "$direct", + "$set": { + "email": "test@posthog.com", + "$os": "Mac OS X", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/", + "$pathname": "/", + "$browser_version": 117, + "$referrer": "$direct", + "$referring_domain": "$direct" + }, + "$set_once": { + "$initial_os": "Mac OS X", + "$initial_browser": "Chrome", + "$initial_device_type": "Desktop", + "$initial_current_url": "http://localhost:8000/", + "$initial_pathname": "/", + "$initial_browser_version": 117, + "$initial_referrer": "$direct", + "$initial_referring_domain": "$direct" + }, + "token": "phc_OWGI2wKbfi7rWDZT9wkl8uGcfe0wOGCvflLEZSMiaT0", + "$session_id": "018b4ca0-9686-7b75-ba2e-61e9c0054b65", + "$window_id": "018b4ca0-9686-7b75-ba2e-61ea857e58f0", + "$ip": "127.0.0.1", + "$sent_at": "2023-10-20T10:27:57.623000+00:00", + "$geoip_city_name": "Sydney", + "$geoip_country_name": "Australia", + "$geoip_country_code": "AU", + "$geoip_continent_name": "Oceania", + "$geoip_continent_code": "OC", + "$geoip_postal_code": "2000", + "$geoip_latitude": -33.8715, + "$geoip_longitude": 151.2006, + "$geoip_time_zone": "Australia/Sydney", + "$geoip_subdivision_1_code": "NSW", + "$geoip_subdivision_1_name": "New South Wales", + "$plugins_succeeded": ["GeoIP (1)"], + "$plugins_failed": [], + "$plugins_deferred": [], + "$group_3": "018a92f8-b602-0000-75de-4b9073693531", + "$group_2": "018a92f8-afff-0000-efec-ca77de39e384", + "$group_4": "cus_OdSgxxWtHOtq9g", + "$group_1": "http://localhost:8000" + }, + "timestamp": "2023-10-20T10:27:54.639000+00:00", + "uuid": null + }, + { + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "elements": [], + "elements_chain": null, + "event": "$groupidentify", + "id": "018b4ca0-9687-7734-890a-7891724ddd1e", + "person": null, + "properties": { + "$os": "Mac OS X", + "$os_version": "10.15.7", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/", + "$host": "localhost:8000", + "$pathname": "/", + "$browser_version": 117, + "$browser_language": "en-GB", + "$screen_height": 982, + "$screen_width": 1512, + "$viewport_height": 859, + "$viewport_width": 1512, + "$lib": "web", + "$lib_version": "1.84.0", + "$insert_id": "8cp3ng6n4b6np5ys", + "$time": 1697797674.631, + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$device_id": "018a92fd-7b25-7770-a050-577e94fd148c", + "$console_log_recording_enabled_server_side": true, + "$session_recording_recorder_version_server_side": "v2", + "$autocapture_disabled_server_side": false, + "$active_feature_flags": [ + "signup-page-4.0", + "cmd-k-search", + "posthog-3000", + "funnels-cue-opt-out-7301", + "retention-breakdown", + "smoothing-interval", + "billing-limit", + "kafka-inspector", + "historical-exports-v2", + "person-on-events-enabled", + "region-select", + "ingestion-warnings-enabled", + "session-reset-on-load", + "recordings-on-feature-flags", + "auto-rollback-feature-flags", + "onboarding-v2-demo", + "feature-flag-rollout-ux", + "role-based-access", + "query_running_time", + "query-timings", + "recording-debugging", + "enable-prompts", + "feedback-scene", + "early-access-feature", + "early-access-feature-site-button", + "hedgehog-mode-debug", + "auto-redirect", + "session-recording-blob-replay", + "surveys", + "generic-signup-benefits", + "surveys-positions", + "web-analytics", + "high-frequency-batch-exports", + "exception-autocapture", + "data-warehouse", + "data-warehouse-views", + "ff-dashboard-templates", + "show-product-intro-existing-products", + "artificial-hog", + "cs-dashboards", + "product-specific-onboarding", + "redirect-signups-to-instance", + "apps-and-exports-ui", + "survey-nps-results", + "session-recording-allow-v1-snapshots", + "session-replay-cors-proxy", + "webhooks-denylist", + "surveys-site-app-deprecation", + "surveys-multiple-questions", + "surveys-results-visualizations", + "console-recording-search", + "persons-hogql-query", + "notebooks" + ], + "$feature/file-previews": false, + "$feature/signup-page-4.0": "control", + "$feature/hogql-insights": false, + "$feature/cmd-k-search": true, + "$feature/posthog-3000": true, + "$feature/funnels-cue-opt-out-7301": true, + "$feature/retention-breakdown": true, + "$feature/smoothing-interval": true, + "$feature/billing-limit": true, + "$feature/kafka-inspector": true, + "$feature/historical-exports-v2": true, + "$feature/person-on-events-enabled": true, + "$feature/region-select": true, + "$feature/ingestion-warnings-enabled": true, + "$feature/session-reset-on-load": true, + "$feature/recordings-on-feature-flags": true, + "$feature/auto-rollback-feature-flags": true, + "$feature/onboarding-v2-demo": true, + "$feature/feature-flag-rollout-ux": true, + "$feature/role-based-access": true, + "$feature/query_running_time": true, + "$feature/query-timings": true, + "$feature/recording-debugging": true, + "$feature/enable-prompts": true, + "$feature/feedback-scene": true, + "$feature/early-access-feature": true, + "$feature/early-access-feature-site-button": true, + "$feature/hedgehog-mode-debug": true, + "$feature/auto-redirect": true, + "$feature/session-recording-blob-replay": true, + "$feature/surveys": true, + "$feature/generic-signup-benefits": true, + "$feature/surveys-positions": true, + "$feature/web-analytics": true, + "$feature/high-frequency-batch-exports": true, + "$feature/exception-autocapture": true, + "$feature/data-warehouse": true, + "$feature/data-warehouse-views": true, + "$feature/ff-dashboard-templates": true, + "$feature/show-product-intro-existing-products": true, + "$feature/artificial-hog": true, + "$feature/cs-dashboards": true, + "$feature/product-specific-onboarding": true, + "$feature/redirect-signups-to-instance": true, + "$feature/apps-and-exports-ui": true, + "$feature/survey-nps-results": true, + "$feature/session-recording-allow-v1-snapshots": true, + "$feature/session-replay-cors-proxy": true, + "$feature/webhooks-denylist": true, + "$feature/surveys-site-app-deprecation": true, + "$feature/surveys-multiple-questions": true, + "$feature/surveys-results-visualizations": true, + "$feature/console-recording-search": true, + "$feature/persons-hogql-query": true, + "$feature/notebooks": true, + "$feature_flag_payloads": {}, + "realm": "hosted-clickhouse", + "email_service_available": false, + "slack_service_available": false, + "$user_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "is_demo_project": false, + "$groups": { + "project": "018a92f8-b602-0000-75de-4b9073693531", + "organization": "018a92f8-afff-0000-efec-ca77de39e384", + "customer": "cus_OdSgxxWtHOtq9g", + "instance": "http://localhost:8000" + }, + "has_billing_plan": true, + "customer_deactivated": false, + "current_total_amount_usd": "0.00", + "percentage_usage.product_analytics": 0, + "current_amount_usd.product_analytics": "0.00", + "unit_amount_usd.product_analytics": null, + "usage_limit.product_analytics": null, + "current_usage.product_analytics": 3729, + "projected_usage.product_analytics": 0, + "free_allocation.product_analytics": 0, + "percentage_usage.session_replay": 0, + "current_amount_usd.session_replay": "0.00", + "unit_amount_usd.session_replay": null, + "usage_limit.session_replay": null, + "current_usage.session_replay": 254, + "projected_usage.session_replay": 0, + "free_allocation.session_replay": 0, + "percentage_usage.feature_flags": 0, + "current_amount_usd.feature_flags": "0.00", + "unit_amount_usd.feature_flags": null, + "usage_limit.feature_flags": null, + "current_usage.feature_flags": 0, + "projected_usage.feature_flags": 0, + "free_allocation.feature_flags": 0, + "percentage_usage.integrations": 0, + "current_amount_usd.integrations": null, + "unit_amount_usd.integrations": null, + "usage_limit.integrations": 0, + "current_usage.integrations": 0, + "projected_usage.integrations": 0, + "free_allocation.integrations": 0, + "percentage_usage.platform_and_support": 0, + "current_amount_usd.platform_and_support": null, + "unit_amount_usd.platform_and_support": null, + "usage_limit.platform_and_support": 0, + "current_usage.platform_and_support": 0, + "projected_usage.platform_and_support": 0, + "free_allocation.platform_and_support": 0, + "billing_period_start": "2023-10-14T09:22:33.000Z", + "billing_period_end": "2023-11-14T09:22:33.000Z", + "$referrer": "$direct", + "$referring_domain": "$direct", + "$group_type": "project", + "$group_key": "018a92f8-b602-0000-75de-4b9073693531", + "$group_set": { + "id": 1, + "uuid": "018a92f8-b602-0000-75de-4b9073693531", + "name": "Hedgebox", + "ingested_event": true, + "is_demo": false, + "timezone": "UTC", + "instance_tag": "none" + }, + "token": "phc_OWGI2wKbfi7rWDZT9wkl8uGcfe0wOGCvflLEZSMiaT0", + "$session_id": "018b4ca0-9686-7b75-ba2e-61e9c0054b65", + "$window_id": "018b4ca0-9686-7b75-ba2e-61ea857e58f0", + "$ip": "127.0.0.1", + "$set": { + "$os": "Mac OS X", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/", + "$pathname": "/", + "$browser_version": 117, + "$referrer": "$direct", + "$referring_domain": "$direct" + }, + "$set_once": { + "$initial_os": "Mac OS X", + "$initial_browser": "Chrome", + "$initial_device_type": "Desktop", + "$initial_current_url": "http://localhost:8000/", + "$initial_pathname": "/", + "$initial_browser_version": 117, + "$initial_referrer": "$direct", + "$initial_referring_domain": "$direct" + }, + "$sent_at": "2023-10-20T10:27:57.623000+00:00", + "$geoip_city_name": "Sydney", + "$geoip_country_name": "Australia", + "$geoip_country_code": "AU", + "$geoip_continent_name": "Oceania", + "$geoip_continent_code": "OC", + "$geoip_postal_code": "2000", + "$geoip_latitude": -33.8715, + "$geoip_longitude": 151.2006, + "$geoip_time_zone": "Australia/Sydney", + "$geoip_subdivision_1_code": "NSW", + "$geoip_subdivision_1_name": "New South Wales", + "$plugins_succeeded": ["GeoIP (1)"], + "$plugins_failed": [], + "$plugins_deferred": [], + "$group_3": "018a92f8-b602-0000-75de-4b9073693531", + "$group_2": "018a92f8-afff-0000-efec-ca77de39e384", + "$group_4": "cus_OdSgxxWtHOtq9g", + "$group_1": "http://localhost:8000" + }, + "timestamp": "2023-10-20T10:27:54.640000+00:00", + "uuid": null + }, + { + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "elements": [], + "elements_chain": null, + "event": "$groupidentify", + "id": "018b4ca0-9688-735f-882b-8dfa30ad146b", + "person": null, + "properties": { + "$os": "Mac OS X", + "$os_version": "10.15.7", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/", + "$host": "localhost:8000", + "$pathname": "/", + "$browser_version": 117, + "$browser_language": "en-GB", + "$screen_height": 982, + "$screen_width": 1512, + "$viewport_height": 859, + "$viewport_width": 1512, + "$lib": "web", + "$lib_version": "1.84.0", + "$insert_id": "l4ypd28525qtjw68", + "$time": 1697797674.632, + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$device_id": "018a92fd-7b25-7770-a050-577e94fd148c", + "$console_log_recording_enabled_server_side": true, + "$session_recording_recorder_version_server_side": "v2", + "$autocapture_disabled_server_side": false, + "$active_feature_flags": [ + "signup-page-4.0", + "cmd-k-search", + "posthog-3000", + "funnels-cue-opt-out-7301", + "retention-breakdown", + "smoothing-interval", + "billing-limit", + "kafka-inspector", + "historical-exports-v2", + "person-on-events-enabled", + "region-select", + "ingestion-warnings-enabled", + "session-reset-on-load", + "recordings-on-feature-flags", + "auto-rollback-feature-flags", + "onboarding-v2-demo", + "feature-flag-rollout-ux", + "role-based-access", + "query_running_time", + "query-timings", + "recording-debugging", + "enable-prompts", + "feedback-scene", + "early-access-feature", + "early-access-feature-site-button", + "hedgehog-mode-debug", + "auto-redirect", + "session-recording-blob-replay", + "surveys", + "generic-signup-benefits", + "surveys-positions", + "web-analytics", + "high-frequency-batch-exports", + "exception-autocapture", + "data-warehouse", + "data-warehouse-views", + "ff-dashboard-templates", + "show-product-intro-existing-products", + "artificial-hog", + "cs-dashboards", + "product-specific-onboarding", + "redirect-signups-to-instance", + "apps-and-exports-ui", + "survey-nps-results", + "session-recording-allow-v1-snapshots", + "session-replay-cors-proxy", + "webhooks-denylist", + "surveys-site-app-deprecation", + "surveys-multiple-questions", + "surveys-results-visualizations", + "console-recording-search", + "persons-hogql-query", + "notebooks" + ], + "$feature/file-previews": false, + "$feature/signup-page-4.0": "control", + "$feature/hogql-insights": false, + "$feature/cmd-k-search": true, + "$feature/posthog-3000": true, + "$feature/funnels-cue-opt-out-7301": true, + "$feature/retention-breakdown": true, + "$feature/smoothing-interval": true, + "$feature/billing-limit": true, + "$feature/kafka-inspector": true, + "$feature/historical-exports-v2": true, + "$feature/person-on-events-enabled": true, + "$feature/region-select": true, + "$feature/ingestion-warnings-enabled": true, + "$feature/session-reset-on-load": true, + "$feature/recordings-on-feature-flags": true, + "$feature/auto-rollback-feature-flags": true, + "$feature/onboarding-v2-demo": true, + "$feature/feature-flag-rollout-ux": true, + "$feature/role-based-access": true, + "$feature/query_running_time": true, + "$feature/query-timings": true, + "$feature/recording-debugging": true, + "$feature/enable-prompts": true, + "$feature/feedback-scene": true, + "$feature/early-access-feature": true, + "$feature/early-access-feature-site-button": true, + "$feature/hedgehog-mode-debug": true, + "$feature/auto-redirect": true, + "$feature/session-recording-blob-replay": true, + "$feature/surveys": true, + "$feature/generic-signup-benefits": true, + "$feature/surveys-positions": true, + "$feature/web-analytics": true, + "$feature/high-frequency-batch-exports": true, + "$feature/exception-autocapture": true, + "$feature/data-warehouse": true, + "$feature/data-warehouse-views": true, + "$feature/ff-dashboard-templates": true, + "$feature/show-product-intro-existing-products": true, + "$feature/artificial-hog": true, + "$feature/cs-dashboards": true, + "$feature/product-specific-onboarding": true, + "$feature/redirect-signups-to-instance": true, + "$feature/apps-and-exports-ui": true, + "$feature/survey-nps-results": true, + "$feature/session-recording-allow-v1-snapshots": true, + "$feature/session-replay-cors-proxy": true, + "$feature/webhooks-denylist": true, + "$feature/surveys-site-app-deprecation": true, + "$feature/surveys-multiple-questions": true, + "$feature/surveys-results-visualizations": true, + "$feature/console-recording-search": true, + "$feature/persons-hogql-query": true, + "$feature/notebooks": true, + "$feature_flag_payloads": {}, + "realm": "hosted-clickhouse", + "email_service_available": false, + "slack_service_available": false, + "$user_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "is_demo_project": false, + "$groups": { + "project": "018a92f8-b602-0000-75de-4b9073693531", + "organization": "018a92f8-afff-0000-efec-ca77de39e384", + "customer": "cus_OdSgxxWtHOtq9g", + "instance": "http://localhost:8000" + }, + "has_billing_plan": true, + "customer_deactivated": false, + "current_total_amount_usd": "0.00", + "percentage_usage.product_analytics": 0, + "current_amount_usd.product_analytics": "0.00", + "unit_amount_usd.product_analytics": null, + "usage_limit.product_analytics": null, + "current_usage.product_analytics": 3729, + "projected_usage.product_analytics": 0, + "free_allocation.product_analytics": 0, + "percentage_usage.session_replay": 0, + "current_amount_usd.session_replay": "0.00", + "unit_amount_usd.session_replay": null, + "usage_limit.session_replay": null, + "current_usage.session_replay": 254, + "projected_usage.session_replay": 0, + "free_allocation.session_replay": 0, + "percentage_usage.feature_flags": 0, + "current_amount_usd.feature_flags": "0.00", + "unit_amount_usd.feature_flags": null, + "usage_limit.feature_flags": null, + "current_usage.feature_flags": 0, + "projected_usage.feature_flags": 0, + "free_allocation.feature_flags": 0, + "percentage_usage.integrations": 0, + "current_amount_usd.integrations": null, + "unit_amount_usd.integrations": null, + "usage_limit.integrations": 0, + "current_usage.integrations": 0, + "projected_usage.integrations": 0, + "free_allocation.integrations": 0, + "percentage_usage.platform_and_support": 0, + "current_amount_usd.platform_and_support": null, + "unit_amount_usd.platform_and_support": null, + "usage_limit.platform_and_support": 0, + "current_usage.platform_and_support": 0, + "projected_usage.platform_and_support": 0, + "free_allocation.platform_and_support": 0, + "billing_period_start": "2023-10-14T09:22:33.000Z", + "billing_period_end": "2023-11-14T09:22:33.000Z", + "$referrer": "$direct", + "$referring_domain": "$direct", + "$group_type": "organization", + "$group_key": "018a92f8-afff-0000-efec-ca77de39e384", + "$group_set": { + "id": "018a92f8-afff-0000-efec-ca77de39e384", + "name": "Hedgebox Inc.", + "slug": "hedgebox-inc", + "created_at": "2023-09-14T09:14:46.145060Z", + "available_features": [ + "zapier", + "slack_integration", + "microsoft_teams_integration", + "discord_integration", + "apps", + "app_metrics", + "boolean_flags", + "multivariate_flags", + "persist_flags_cross_authentication", + "feature_flag_payloads", + "multiple_release_conditions", + "release_condition_overrides", + "targeting_by_group", + "local_evaluation_and_bootstrapping", + "flag_usage_stats", + "experimentation", + "group_experiments", + "funnel_experiments", + "secondary_metrics", + "statistical_analysis", + "console_logs", + "recordings_playlists", + "recordings_performance", + "recordings_file_export", + "group_analytics", + "dashboards", + "funnels", + "graphs_trends", + "paths", + "subscriptions", + "paths_advanced", + "dashboard_permissioning", + "dashboard_collaboration", + "ingestion_taxonomy", + "correlation_analysis", + "tagging", + "behavioral_cohort_filtering", + "tracked_users", + "data_retention", + "team_members", + "organizations_projects", + "api_access", + "project_based_permissioning", + "social_sso", + "sso_enforcement", + "white_labelling", + "community_support", + "dedicated_support", + "email_support", + "terms_and_conditions", + "security_assessment" + ], + "instance_tag": "none" + }, + "token": "phc_OWGI2wKbfi7rWDZT9wkl8uGcfe0wOGCvflLEZSMiaT0", + "$session_id": "018b4ca0-9686-7b75-ba2e-61e9c0054b65", + "$window_id": "018b4ca0-9686-7b75-ba2e-61ea857e58f0", + "$ip": "127.0.0.1", + "$set": { + "$os": "Mac OS X", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/", + "$pathname": "/", + "$browser_version": 117, + "$referrer": "$direct", + "$referring_domain": "$direct" + }, + "$set_once": { + "$initial_os": "Mac OS X", + "$initial_browser": "Chrome", + "$initial_device_type": "Desktop", + "$initial_current_url": "http://localhost:8000/", + "$initial_pathname": "/", + "$initial_browser_version": 117, + "$initial_referrer": "$direct", + "$initial_referring_domain": "$direct" + }, + "$sent_at": "2023-10-20T10:27:57.623000+00:00", + "$geoip_city_name": "Sydney", + "$geoip_country_name": "Australia", + "$geoip_country_code": "AU", + "$geoip_continent_name": "Oceania", + "$geoip_continent_code": "OC", + "$geoip_postal_code": "2000", + "$geoip_latitude": -33.8715, + "$geoip_longitude": 151.2006, + "$geoip_time_zone": "Australia/Sydney", + "$geoip_subdivision_1_code": "NSW", + "$geoip_subdivision_1_name": "New South Wales", + "$plugins_succeeded": ["GeoIP (1)"], + "$plugins_failed": [], + "$plugins_deferred": [], + "$group_3": "018a92f8-b602-0000-75de-4b9073693531", + "$group_2": "018a92f8-afff-0000-efec-ca77de39e384", + "$group_4": "cus_OdSgxxWtHOtq9g", + "$group_1": "http://localhost:8000" + }, + "timestamp": "2023-10-20T10:27:54.641000+00:00", + "uuid": null + }, + { + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "elements": [], + "elements_chain": null, + "event": "$feature_flag_called", + "id": "018b4ca0-96d9-72c4-940e-87b71e722e23", + "person": null, + "properties": { + "$os": "Mac OS X", + "$os_version": "10.15.7", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/home", + "$host": "localhost:8000", + "$pathname": "/home", + "$browser_version": 117, + "$browser_language": "en-GB", + "$screen_height": 982, + "$screen_width": 1512, + "$viewport_height": 859, + "$viewport_width": 1512, + "$lib": "web", + "$lib_version": "1.84.0", + "$insert_id": "xnqcrio4jvhwlgow", + "$time": 1697797674.714, + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$device_id": "018a92fd-7b25-7770-a050-577e94fd148c", + "$console_log_recording_enabled_server_side": true, + "$session_recording_recorder_version_server_side": "v2", + "$autocapture_disabled_server_side": false, + "$active_feature_flags": [ + "signup-page-4.0", + "cmd-k-search", + "posthog-3000", + "funnels-cue-opt-out-7301", + "retention-breakdown", + "smoothing-interval", + "billing-limit", + "kafka-inspector", + "historical-exports-v2", + "person-on-events-enabled", + "region-select", + "ingestion-warnings-enabled", + "session-reset-on-load", + "recordings-on-feature-flags", + "auto-rollback-feature-flags", + "onboarding-v2-demo", + "feature-flag-rollout-ux", + "role-based-access", + "query_running_time", + "query-timings", + "recording-debugging", + "enable-prompts", + "feedback-scene", + "early-access-feature", + "early-access-feature-site-button", + "hedgehog-mode-debug", + "auto-redirect", + "session-recording-blob-replay", + "surveys", + "generic-signup-benefits", + "surveys-positions", + "web-analytics", + "high-frequency-batch-exports", + "exception-autocapture", + "data-warehouse", + "data-warehouse-views", + "ff-dashboard-templates", + "show-product-intro-existing-products", + "artificial-hog", + "cs-dashboards", + "product-specific-onboarding", + "redirect-signups-to-instance", + "apps-and-exports-ui", + "survey-nps-results", + "session-recording-allow-v1-snapshots", + "session-replay-cors-proxy", + "webhooks-denylist", + "surveys-site-app-deprecation", + "surveys-multiple-questions", + "surveys-results-visualizations", + "console-recording-search", + "persons-hogql-query", + "notebooks" + ], + "$feature/file-previews": false, + "$feature/signup-page-4.0": "control", + "$feature/hogql-insights": false, + "$feature/cmd-k-search": true, + "$feature/posthog-3000": true, + "$feature/funnels-cue-opt-out-7301": true, + "$feature/retention-breakdown": true, + "$feature/smoothing-interval": true, + "$feature/billing-limit": true, + "$feature/kafka-inspector": true, + "$feature/historical-exports-v2": true, + "$feature/person-on-events-enabled": true, + "$feature/region-select": true, + "$feature/ingestion-warnings-enabled": true, + "$feature/session-reset-on-load": true, + "$feature/recordings-on-feature-flags": true, + "$feature/auto-rollback-feature-flags": true, + "$feature/onboarding-v2-demo": true, + "$feature/feature-flag-rollout-ux": true, + "$feature/role-based-access": true, + "$feature/query_running_time": true, + "$feature/query-timings": true, + "$feature/recording-debugging": true, + "$feature/enable-prompts": true, + "$feature/feedback-scene": true, + "$feature/early-access-feature": true, + "$feature/early-access-feature-site-button": true, + "$feature/hedgehog-mode-debug": true, + "$feature/auto-redirect": true, + "$feature/session-recording-blob-replay": true, + "$feature/surveys": true, + "$feature/generic-signup-benefits": true, + "$feature/surveys-positions": true, + "$feature/web-analytics": true, + "$feature/high-frequency-batch-exports": true, + "$feature/exception-autocapture": true, + "$feature/data-warehouse": true, + "$feature/data-warehouse-views": true, + "$feature/ff-dashboard-templates": true, + "$feature/show-product-intro-existing-products": true, + "$feature/artificial-hog": true, + "$feature/cs-dashboards": true, + "$feature/product-specific-onboarding": true, + "$feature/redirect-signups-to-instance": true, + "$feature/apps-and-exports-ui": true, + "$feature/survey-nps-results": true, + "$feature/session-recording-allow-v1-snapshots": true, + "$feature/session-replay-cors-proxy": true, + "$feature/webhooks-denylist": true, + "$feature/surveys-site-app-deprecation": true, + "$feature/surveys-multiple-questions": true, + "$feature/surveys-results-visualizations": true, + "$feature/console-recording-search": true, + "$feature/persons-hogql-query": true, + "$feature/notebooks": true, + "$feature_flag_payloads": {}, + "realm": "hosted-clickhouse", + "email_service_available": false, + "slack_service_available": false, + "$user_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "is_demo_project": false, + "$groups": { + "project": "018a92f8-b602-0000-75de-4b9073693531", + "organization": "018a92f8-afff-0000-efec-ca77de39e384", + "customer": "cus_OdSgxxWtHOtq9g", + "instance": "http://localhost:8000" + }, + "has_billing_plan": true, + "customer_deactivated": false, + "current_total_amount_usd": "0.00", + "percentage_usage.product_analytics": 0, + "current_amount_usd.product_analytics": "0.00", + "unit_amount_usd.product_analytics": null, + "usage_limit.product_analytics": null, + "current_usage.product_analytics": 3729, + "projected_usage.product_analytics": 0, + "free_allocation.product_analytics": 0, + "percentage_usage.session_replay": 0, + "current_amount_usd.session_replay": "0.00", + "unit_amount_usd.session_replay": null, + "usage_limit.session_replay": null, + "current_usage.session_replay": 254, + "projected_usage.session_replay": 0, + "free_allocation.session_replay": 0, + "percentage_usage.feature_flags": 0, + "current_amount_usd.feature_flags": "0.00", + "unit_amount_usd.feature_flags": null, + "usage_limit.feature_flags": null, + "current_usage.feature_flags": 0, + "projected_usage.feature_flags": 0, + "free_allocation.feature_flags": 0, + "percentage_usage.integrations": 0, + "current_amount_usd.integrations": null, + "unit_amount_usd.integrations": null, + "usage_limit.integrations": 0, + "current_usage.integrations": 0, + "projected_usage.integrations": 0, + "free_allocation.integrations": 0, + "percentage_usage.platform_and_support": 0, + "current_amount_usd.platform_and_support": null, + "unit_amount_usd.platform_and_support": null, + "usage_limit.platform_and_support": 0, + "current_usage.platform_and_support": 0, + "projected_usage.platform_and_support": 0, + "free_allocation.platform_and_support": 0, + "billing_period_start": "2023-10-14T09:22:33.000Z", + "billing_period_end": "2023-11-14T09:22:33.000Z", + "$referrer": "$direct", + "$referring_domain": "$direct", + "$feature_flag": "posthog-3000", + "$feature_flag_response": true, + "token": "phc_OWGI2wKbfi7rWDZT9wkl8uGcfe0wOGCvflLEZSMiaT0", + "$session_id": "018b4ca0-9686-7b75-ba2e-61e9c0054b65", + "$window_id": "018b4ca0-9686-7b75-ba2e-61ea857e58f0", + "$ip": "127.0.0.1", + "$set": { + "$os": "Mac OS X", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/home", + "$pathname": "/home", + "$browser_version": 117, + "$referrer": "$direct", + "$referring_domain": "$direct" + }, + "$set_once": { + "$initial_os": "Mac OS X", + "$initial_browser": "Chrome", + "$initial_device_type": "Desktop", + "$initial_current_url": "http://localhost:8000/home", + "$initial_pathname": "/home", + "$initial_browser_version": 117, + "$initial_referrer": "$direct", + "$initial_referring_domain": "$direct" + }, + "$sent_at": "2023-10-20T10:27:57.623000+00:00", + "$geoip_city_name": "Sydney", + "$geoip_country_name": "Australia", + "$geoip_country_code": "AU", + "$geoip_continent_name": "Oceania", + "$geoip_continent_code": "OC", + "$geoip_postal_code": "2000", + "$geoip_latitude": -33.8715, + "$geoip_longitude": 151.2006, + "$geoip_time_zone": "Australia/Sydney", + "$geoip_subdivision_1_code": "NSW", + "$geoip_subdivision_1_name": "New South Wales", + "$plugins_succeeded": ["GeoIP (1)"], + "$plugins_failed": [], + "$plugins_deferred": [], + "$group_3": "018a92f8-b602-0000-75de-4b9073693531", + "$group_2": "018a92f8-afff-0000-efec-ca77de39e384", + "$group_4": "cus_OdSgxxWtHOtq9g", + "$group_1": "http://localhost:8000" + }, + "timestamp": "2023-10-20T10:27:54.723000+00:00", + "uuid": null + }, + { + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "elements": [], + "elements_chain": null, + "event": "$feature_flag_called", + "id": "018b4ca0-96da-7ee1-870d-308e41519ca3", + "person": null, + "properties": { + "$os": "Mac OS X", + "$os_version": "10.15.7", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/home", + "$host": "localhost:8000", + "$pathname": "/home", + "$browser_version": 117, + "$browser_language": "en-GB", + "$screen_height": 982, + "$screen_width": 1512, + "$viewport_height": 859, + "$viewport_width": 1512, + "$lib": "web", + "$lib_version": "1.84.0", + "$insert_id": "9hatx583uf4rb4c8", + "$time": 1697797674.714, + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$device_id": "018a92fd-7b25-7770-a050-577e94fd148c", + "$console_log_recording_enabled_server_side": true, + "$session_recording_recorder_version_server_side": "v2", + "$autocapture_disabled_server_side": false, + "$active_feature_flags": [ + "signup-page-4.0", + "cmd-k-search", + "posthog-3000", + "funnels-cue-opt-out-7301", + "retention-breakdown", + "smoothing-interval", + "billing-limit", + "kafka-inspector", + "historical-exports-v2", + "person-on-events-enabled", + "region-select", + "ingestion-warnings-enabled", + "session-reset-on-load", + "recordings-on-feature-flags", + "auto-rollback-feature-flags", + "onboarding-v2-demo", + "feature-flag-rollout-ux", + "role-based-access", + "query_running_time", + "query-timings", + "recording-debugging", + "enable-prompts", + "feedback-scene", + "early-access-feature", + "early-access-feature-site-button", + "hedgehog-mode-debug", + "auto-redirect", + "session-recording-blob-replay", + "surveys", + "generic-signup-benefits", + "surveys-positions", + "web-analytics", + "high-frequency-batch-exports", + "exception-autocapture", + "data-warehouse", + "data-warehouse-views", + "ff-dashboard-templates", + "show-product-intro-existing-products", + "artificial-hog", + "cs-dashboards", + "product-specific-onboarding", + "redirect-signups-to-instance", + "apps-and-exports-ui", + "survey-nps-results", + "session-recording-allow-v1-snapshots", + "session-replay-cors-proxy", + "webhooks-denylist", + "surveys-site-app-deprecation", + "surveys-multiple-questions", + "surveys-results-visualizations", + "console-recording-search", + "persons-hogql-query", + "notebooks" + ], + "$feature/file-previews": false, + "$feature/signup-page-4.0": "control", + "$feature/hogql-insights": false, + "$feature/cmd-k-search": true, + "$feature/posthog-3000": true, + "$feature/funnels-cue-opt-out-7301": true, + "$feature/retention-breakdown": true, + "$feature/smoothing-interval": true, + "$feature/billing-limit": true, + "$feature/kafka-inspector": true, + "$feature/historical-exports-v2": true, + "$feature/person-on-events-enabled": true, + "$feature/region-select": true, + "$feature/ingestion-warnings-enabled": true, + "$feature/session-reset-on-load": true, + "$feature/recordings-on-feature-flags": true, + "$feature/auto-rollback-feature-flags": true, + "$feature/onboarding-v2-demo": true, + "$feature/feature-flag-rollout-ux": true, + "$feature/role-based-access": true, + "$feature/query_running_time": true, + "$feature/query-timings": true, + "$feature/recording-debugging": true, + "$feature/enable-prompts": true, + "$feature/feedback-scene": true, + "$feature/early-access-feature": true, + "$feature/early-access-feature-site-button": true, + "$feature/hedgehog-mode-debug": true, + "$feature/auto-redirect": true, + "$feature/session-recording-blob-replay": true, + "$feature/surveys": true, + "$feature/generic-signup-benefits": true, + "$feature/surveys-positions": true, + "$feature/web-analytics": true, + "$feature/high-frequency-batch-exports": true, + "$feature/exception-autocapture": true, + "$feature/data-warehouse": true, + "$feature/data-warehouse-views": true, + "$feature/ff-dashboard-templates": true, + "$feature/show-product-intro-existing-products": true, + "$feature/artificial-hog": true, + "$feature/cs-dashboards": true, + "$feature/product-specific-onboarding": true, + "$feature/redirect-signups-to-instance": true, + "$feature/apps-and-exports-ui": true, + "$feature/survey-nps-results": true, + "$feature/session-recording-allow-v1-snapshots": true, + "$feature/session-replay-cors-proxy": true, + "$feature/webhooks-denylist": true, + "$feature/surveys-site-app-deprecation": true, + "$feature/surveys-multiple-questions": true, + "$feature/surveys-results-visualizations": true, + "$feature/console-recording-search": true, + "$feature/persons-hogql-query": true, + "$feature/notebooks": true, + "$feature_flag_payloads": {}, + "realm": "hosted-clickhouse", + "email_service_available": false, + "slack_service_available": false, + "$user_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "is_demo_project": false, + "$groups": { + "project": "018a92f8-b602-0000-75de-4b9073693531", + "organization": "018a92f8-afff-0000-efec-ca77de39e384", + "customer": "cus_OdSgxxWtHOtq9g", + "instance": "http://localhost:8000" + }, + "has_billing_plan": true, + "customer_deactivated": false, + "current_total_amount_usd": "0.00", + "percentage_usage.product_analytics": 0, + "current_amount_usd.product_analytics": "0.00", + "unit_amount_usd.product_analytics": null, + "usage_limit.product_analytics": null, + "current_usage.product_analytics": 3729, + "projected_usage.product_analytics": 0, + "free_allocation.product_analytics": 0, + "percentage_usage.session_replay": 0, + "current_amount_usd.session_replay": "0.00", + "unit_amount_usd.session_replay": null, + "usage_limit.session_replay": null, + "current_usage.session_replay": 254, + "projected_usage.session_replay": 0, + "free_allocation.session_replay": 0, + "percentage_usage.feature_flags": 0, + "current_amount_usd.feature_flags": "0.00", + "unit_amount_usd.feature_flags": null, + "usage_limit.feature_flags": null, + "current_usage.feature_flags": 0, + "projected_usage.feature_flags": 0, + "free_allocation.feature_flags": 0, + "percentage_usage.integrations": 0, + "current_amount_usd.integrations": null, + "unit_amount_usd.integrations": null, + "usage_limit.integrations": 0, + "current_usage.integrations": 0, + "projected_usage.integrations": 0, + "free_allocation.integrations": 0, + "percentage_usage.platform_and_support": 0, + "current_amount_usd.platform_and_support": null, + "unit_amount_usd.platform_and_support": null, + "usage_limit.platform_and_support": 0, + "current_usage.platform_and_support": 0, + "projected_usage.platform_and_support": 0, + "free_allocation.platform_and_support": 0, + "billing_period_start": "2023-10-14T09:22:33.000Z", + "billing_period_end": "2023-11-14T09:22:33.000Z", + "$referrer": "$direct", + "$referring_domain": "$direct", + "$feature_flag": "enable-prompts", + "$feature_flag_response": true, + "token": "phc_OWGI2wKbfi7rWDZT9wkl8uGcfe0wOGCvflLEZSMiaT0", + "$session_id": "018b4ca0-9686-7b75-ba2e-61e9c0054b65", + "$window_id": "018b4ca0-9686-7b75-ba2e-61ea857e58f0", + "$ip": "127.0.0.1", + "$set": { + "$os": "Mac OS X", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/home", + "$pathname": "/home", + "$browser_version": 117, + "$referrer": "$direct", + "$referring_domain": "$direct" + }, + "$set_once": { + "$initial_os": "Mac OS X", + "$initial_browser": "Chrome", + "$initial_device_type": "Desktop", + "$initial_current_url": "http://localhost:8000/home", + "$initial_pathname": "/home", + "$initial_browser_version": 117, + "$initial_referrer": "$direct", + "$initial_referring_domain": "$direct" + }, + "$sent_at": "2023-10-20T10:27:57.623000+00:00", + "$geoip_city_name": "Sydney", + "$geoip_country_name": "Australia", + "$geoip_country_code": "AU", + "$geoip_continent_name": "Oceania", + "$geoip_continent_code": "OC", + "$geoip_postal_code": "2000", + "$geoip_latitude": -33.8715, + "$geoip_longitude": 151.2006, + "$geoip_time_zone": "Australia/Sydney", + "$geoip_subdivision_1_code": "NSW", + "$geoip_subdivision_1_name": "New South Wales", + "$plugins_succeeded": ["GeoIP (1)"], + "$plugins_failed": [], + "$plugins_deferred": [], + "$group_3": "018a92f8-b602-0000-75de-4b9073693531", + "$group_2": "018a92f8-afff-0000-efec-ca77de39e384", + "$group_4": "cus_OdSgxxWtHOtq9g", + "$group_1": "http://localhost:8000" + }, + "timestamp": "2023-10-20T10:27:54.724000+00:00", + "uuid": null + }, + { + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "elements": [], + "elements_chain": null, + "event": "$feature_flag_called", + "id": "018b4ca0-96e3-7222-bd72-66e3936e12d4", + "person": null, + "properties": { + "$os": "Mac OS X", + "$os_version": "10.15.7", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/home", + "$host": "localhost:8000", + "$pathname": "/home", + "$browser_version": 117, + "$browser_language": "en-GB", + "$screen_height": 982, + "$screen_width": 1512, + "$viewport_height": 859, + "$viewport_width": 1512, + "$lib": "web", + "$lib_version": "1.84.0", + "$insert_id": "qzz7i4g28jxppet9", + "$time": 1697797674.725, + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$device_id": "018a92fd-7b25-7770-a050-577e94fd148c", + "$console_log_recording_enabled_server_side": true, + "$session_recording_recorder_version_server_side": "v2", + "$autocapture_disabled_server_side": false, + "$active_feature_flags": [ + "signup-page-4.0", + "cmd-k-search", + "posthog-3000", + "funnels-cue-opt-out-7301", + "retention-breakdown", + "smoothing-interval", + "billing-limit", + "kafka-inspector", + "historical-exports-v2", + "person-on-events-enabled", + "region-select", + "ingestion-warnings-enabled", + "session-reset-on-load", + "recordings-on-feature-flags", + "auto-rollback-feature-flags", + "onboarding-v2-demo", + "feature-flag-rollout-ux", + "role-based-access", + "query_running_time", + "query-timings", + "recording-debugging", + "enable-prompts", + "feedback-scene", + "early-access-feature", + "early-access-feature-site-button", + "hedgehog-mode-debug", + "auto-redirect", + "session-recording-blob-replay", + "surveys", + "generic-signup-benefits", + "surveys-positions", + "web-analytics", + "high-frequency-batch-exports", + "exception-autocapture", + "data-warehouse", + "data-warehouse-views", + "ff-dashboard-templates", + "show-product-intro-existing-products", + "artificial-hog", + "cs-dashboards", + "product-specific-onboarding", + "redirect-signups-to-instance", + "apps-and-exports-ui", + "survey-nps-results", + "session-recording-allow-v1-snapshots", + "session-replay-cors-proxy", + "webhooks-denylist", + "surveys-site-app-deprecation", + "surveys-multiple-questions", + "surveys-results-visualizations", + "console-recording-search", + "persons-hogql-query", + "notebooks" + ], + "$feature/file-previews": false, + "$feature/signup-page-4.0": "control", + "$feature/hogql-insights": false, + "$feature/cmd-k-search": true, + "$feature/posthog-3000": true, + "$feature/funnels-cue-opt-out-7301": true, + "$feature/retention-breakdown": true, + "$feature/smoothing-interval": true, + "$feature/billing-limit": true, + "$feature/kafka-inspector": true, + "$feature/historical-exports-v2": true, + "$feature/person-on-events-enabled": true, + "$feature/region-select": true, + "$feature/ingestion-warnings-enabled": true, + "$feature/session-reset-on-load": true, + "$feature/recordings-on-feature-flags": true, + "$feature/auto-rollback-feature-flags": true, + "$feature/onboarding-v2-demo": true, + "$feature/feature-flag-rollout-ux": true, + "$feature/role-based-access": true, + "$feature/query_running_time": true, + "$feature/query-timings": true, + "$feature/recording-debugging": true, + "$feature/enable-prompts": true, + "$feature/feedback-scene": true, + "$feature/early-access-feature": true, + "$feature/early-access-feature-site-button": true, + "$feature/hedgehog-mode-debug": true, + "$feature/auto-redirect": true, + "$feature/session-recording-blob-replay": true, + "$feature/surveys": true, + "$feature/generic-signup-benefits": true, + "$feature/surveys-positions": true, + "$feature/web-analytics": true, + "$feature/high-frequency-batch-exports": true, + "$feature/exception-autocapture": true, + "$feature/data-warehouse": true, + "$feature/data-warehouse-views": true, + "$feature/ff-dashboard-templates": true, + "$feature/show-product-intro-existing-products": true, + "$feature/artificial-hog": true, + "$feature/cs-dashboards": true, + "$feature/product-specific-onboarding": true, + "$feature/redirect-signups-to-instance": true, + "$feature/apps-and-exports-ui": true, + "$feature/survey-nps-results": true, + "$feature/session-recording-allow-v1-snapshots": true, + "$feature/session-replay-cors-proxy": true, + "$feature/webhooks-denylist": true, + "$feature/surveys-site-app-deprecation": true, + "$feature/surveys-multiple-questions": true, + "$feature/surveys-results-visualizations": true, + "$feature/console-recording-search": true, + "$feature/persons-hogql-query": true, + "$feature/notebooks": true, + "$feature_flag_payloads": {}, + "realm": "hosted-clickhouse", + "email_service_available": false, + "slack_service_available": false, + "$user_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "is_demo_project": false, + "$groups": { + "project": "018a92f8-b602-0000-75de-4b9073693531", + "organization": "018a92f8-afff-0000-efec-ca77de39e384", + "customer": "cus_OdSgxxWtHOtq9g", + "instance": "http://localhost:8000" + }, + "has_billing_plan": true, + "customer_deactivated": false, + "current_total_amount_usd": "0.00", + "percentage_usage.product_analytics": 0, + "current_amount_usd.product_analytics": "0.00", + "unit_amount_usd.product_analytics": null, + "usage_limit.product_analytics": null, + "current_usage.product_analytics": 3729, + "projected_usage.product_analytics": 0, + "free_allocation.product_analytics": 0, + "percentage_usage.session_replay": 0, + "current_amount_usd.session_replay": "0.00", + "unit_amount_usd.session_replay": null, + "usage_limit.session_replay": null, + "current_usage.session_replay": 254, + "projected_usage.session_replay": 0, + "free_allocation.session_replay": 0, + "percentage_usage.feature_flags": 0, + "current_amount_usd.feature_flags": "0.00", + "unit_amount_usd.feature_flags": null, + "usage_limit.feature_flags": null, + "current_usage.feature_flags": 0, + "projected_usage.feature_flags": 0, + "free_allocation.feature_flags": 0, + "percentage_usage.integrations": 0, + "current_amount_usd.integrations": null, + "unit_amount_usd.integrations": null, + "usage_limit.integrations": 0, + "current_usage.integrations": 0, + "projected_usage.integrations": 0, + "free_allocation.integrations": 0, + "percentage_usage.platform_and_support": 0, + "current_amount_usd.platform_and_support": null, + "unit_amount_usd.platform_and_support": null, + "usage_limit.platform_and_support": 0, + "current_usage.platform_and_support": 0, + "projected_usage.platform_and_support": 0, + "free_allocation.platform_and_support": 0, + "billing_period_start": "2023-10-14T09:22:33.000Z", + "billing_period_end": "2023-11-14T09:22:33.000Z", + "$referrer": "$direct", + "$referring_domain": "$direct", + "$feature_flag": "notebooks", + "$feature_flag_response": true, + "token": "phc_OWGI2wKbfi7rWDZT9wkl8uGcfe0wOGCvflLEZSMiaT0", + "$session_id": "018b4ca0-9686-7b75-ba2e-61e9c0054b65", + "$window_id": "018b4ca0-9686-7b75-ba2e-61ea857e58f0", + "$ip": "127.0.0.1", + "$set": { + "$os": "Mac OS X", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/home", + "$pathname": "/home", + "$browser_version": 117, + "$referrer": "$direct", + "$referring_domain": "$direct" + }, + "$set_once": { + "$initial_os": "Mac OS X", + "$initial_browser": "Chrome", + "$initial_device_type": "Desktop", + "$initial_current_url": "http://localhost:8000/home", + "$initial_pathname": "/home", + "$initial_browser_version": 117, + "$initial_referrer": "$direct", + "$initial_referring_domain": "$direct" + }, + "$sent_at": "2023-10-20T10:27:57.623000+00:00", + "$geoip_city_name": "Sydney", + "$geoip_country_name": "Australia", + "$geoip_country_code": "AU", + "$geoip_continent_name": "Oceania", + "$geoip_continent_code": "OC", + "$geoip_postal_code": "2000", + "$geoip_latitude": -33.8715, + "$geoip_longitude": 151.2006, + "$geoip_time_zone": "Australia/Sydney", + "$geoip_subdivision_1_code": "NSW", + "$geoip_subdivision_1_name": "New South Wales", + "$plugins_succeeded": ["GeoIP (1)"], + "$plugins_failed": [], + "$plugins_deferred": [], + "$group_3": "018a92f8-b602-0000-75de-4b9073693531", + "$group_2": "018a92f8-afff-0000-efec-ca77de39e384", + "$group_4": "cus_OdSgxxWtHOtq9g", + "$group_1": "http://localhost:8000" + }, + "timestamp": "2023-10-20T10:27:54.734000+00:00", + "uuid": null + }, + { + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "elements": [], + "elements_chain": null, + "event": "$pageview", + "id": "018b4ca0-976b-793a-9471-146bc8d275fa", + "person": null, + "properties": { + "$os": "Mac OS X", + "$os_version": "10.15.7", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/home", + "$host": "localhost:8000", + "$pathname": "/home", + "$browser_version": 117, + "$browser_language": "en-GB", + "$screen_height": 982, + "$screen_width": 1512, + "$viewport_height": 859, + "$viewport_width": 1512, + "$lib": "web", + "$lib_version": "1.84.0", + "$insert_id": "zd3q70dq6xabtyjy", + "$time": 1697797674.859, + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$device_id": "018a92fd-7b25-7770-a050-577e94fd148c", + "$console_log_recording_enabled_server_side": true, + "$session_recording_recorder_version_server_side": "v2", + "$autocapture_disabled_server_side": false, + "$active_feature_flags": [ + "signup-page-4.0", + "cmd-k-search", + "posthog-3000", + "funnels-cue-opt-out-7301", + "retention-breakdown", + "smoothing-interval", + "billing-limit", + "kafka-inspector", + "historical-exports-v2", + "person-on-events-enabled", + "region-select", + "ingestion-warnings-enabled", + "session-reset-on-load", + "recordings-on-feature-flags", + "auto-rollback-feature-flags", + "onboarding-v2-demo", + "feature-flag-rollout-ux", + "role-based-access", + "query_running_time", + "query-timings", + "recording-debugging", + "enable-prompts", + "feedback-scene", + "early-access-feature", + "early-access-feature-site-button", + "hedgehog-mode-debug", + "auto-redirect", + "session-recording-blob-replay", + "surveys", + "generic-signup-benefits", + "surveys-positions", + "web-analytics", + "high-frequency-batch-exports", + "exception-autocapture", + "data-warehouse", + "data-warehouse-views", + "ff-dashboard-templates", + "show-product-intro-existing-products", + "artificial-hog", + "cs-dashboards", + "product-specific-onboarding", + "redirect-signups-to-instance", + "apps-and-exports-ui", + "survey-nps-results", + "session-recording-allow-v1-snapshots", + "session-replay-cors-proxy", + "webhooks-denylist", + "surveys-site-app-deprecation", + "surveys-multiple-questions", + "surveys-results-visualizations", + "console-recording-search", + "persons-hogql-query", + "notebooks" + ], + "$feature/file-previews": false, + "$feature/signup-page-4.0": "control", + "$feature/hogql-insights": false, + "$feature/cmd-k-search": true, + "$feature/posthog-3000": true, + "$feature/funnels-cue-opt-out-7301": true, + "$feature/retention-breakdown": true, + "$feature/smoothing-interval": true, + "$feature/billing-limit": true, + "$feature/kafka-inspector": true, + "$feature/historical-exports-v2": true, + "$feature/person-on-events-enabled": true, + "$feature/region-select": true, + "$feature/ingestion-warnings-enabled": true, + "$feature/session-reset-on-load": true, + "$feature/recordings-on-feature-flags": true, + "$feature/auto-rollback-feature-flags": true, + "$feature/onboarding-v2-demo": true, + "$feature/feature-flag-rollout-ux": true, + "$feature/role-based-access": true, + "$feature/query_running_time": true, + "$feature/query-timings": true, + "$feature/recording-debugging": true, + "$feature/enable-prompts": true, + "$feature/feedback-scene": true, + "$feature/early-access-feature": true, + "$feature/early-access-feature-site-button": true, + "$feature/hedgehog-mode-debug": true, + "$feature/auto-redirect": true, + "$feature/session-recording-blob-replay": true, + "$feature/surveys": true, + "$feature/generic-signup-benefits": true, + "$feature/surveys-positions": true, + "$feature/web-analytics": true, + "$feature/high-frequency-batch-exports": true, + "$feature/exception-autocapture": true, + "$feature/data-warehouse": true, + "$feature/data-warehouse-views": true, + "$feature/ff-dashboard-templates": true, + "$feature/show-product-intro-existing-products": true, + "$feature/artificial-hog": true, + "$feature/cs-dashboards": true, + "$feature/product-specific-onboarding": true, + "$feature/redirect-signups-to-instance": true, + "$feature/apps-and-exports-ui": true, + "$feature/survey-nps-results": true, + "$feature/session-recording-allow-v1-snapshots": true, + "$feature/session-replay-cors-proxy": true, + "$feature/webhooks-denylist": true, + "$feature/surveys-site-app-deprecation": true, + "$feature/surveys-multiple-questions": true, + "$feature/surveys-results-visualizations": true, + "$feature/console-recording-search": true, + "$feature/persons-hogql-query": true, + "$feature/notebooks": true, + "$feature_flag_payloads": {}, + "realm": "hosted-clickhouse", + "email_service_available": false, + "slack_service_available": false, + "$user_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "is_demo_project": false, + "$groups": { + "project": "018a92f8-b602-0000-75de-4b9073693531", + "organization": "018a92f8-afff-0000-efec-ca77de39e384", + "customer": "cus_OdSgxxWtHOtq9g", + "instance": "http://localhost:8000" + }, + "has_billing_plan": true, + "customer_deactivated": false, + "current_total_amount_usd": "0.00", + "percentage_usage.product_analytics": 0, + "current_amount_usd.product_analytics": "0.00", + "unit_amount_usd.product_analytics": null, + "usage_limit.product_analytics": null, + "current_usage.product_analytics": 3729, + "projected_usage.product_analytics": 0, + "free_allocation.product_analytics": 0, + "percentage_usage.session_replay": 0, + "current_amount_usd.session_replay": "0.00", + "unit_amount_usd.session_replay": null, + "usage_limit.session_replay": null, + "current_usage.session_replay": 254, + "projected_usage.session_replay": 0, + "free_allocation.session_replay": 0, + "percentage_usage.feature_flags": 0, + "current_amount_usd.feature_flags": "0.00", + "unit_amount_usd.feature_flags": null, + "usage_limit.feature_flags": null, + "current_usage.feature_flags": 0, + "projected_usage.feature_flags": 0, + "free_allocation.feature_flags": 0, + "percentage_usage.integrations": 0, + "current_amount_usd.integrations": null, + "unit_amount_usd.integrations": null, + "usage_limit.integrations": 0, + "current_usage.integrations": 0, + "projected_usage.integrations": 0, + "free_allocation.integrations": 0, + "percentage_usage.platform_and_support": 0, + "current_amount_usd.platform_and_support": null, + "unit_amount_usd.platform_and_support": null, + "usage_limit.platform_and_support": 0, + "current_usage.platform_and_support": 0, + "projected_usage.platform_and_support": 0, + "free_allocation.platform_and_support": 0, + "billing_period_start": "2023-10-14T09:22:33.000Z", + "billing_period_end": "2023-11-14T09:22:33.000Z", + "$referrer": "$direct", + "$referring_domain": "$direct", + "token": "phc_OWGI2wKbfi7rWDZT9wkl8uGcfe0wOGCvflLEZSMiaT0", + "$session_id": "018b4ca0-9686-7b75-ba2e-61e9c0054b65", + "$window_id": "018b4ca0-9686-7b75-ba2e-61ea857e58f0", + "title": "Homepage \u2022 PostHog", + "$ip": "127.0.0.1", + "$set": { + "$os": "Mac OS X", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/home", + "$pathname": "/home", + "$browser_version": 117, + "$referrer": "$direct", + "$referring_domain": "$direct" + }, + "$set_once": { + "$initial_os": "Mac OS X", + "$initial_browser": "Chrome", + "$initial_device_type": "Desktop", + "$initial_current_url": "http://localhost:8000/home", + "$initial_pathname": "/home", + "$initial_browser_version": 117, + "$initial_referrer": "$direct", + "$initial_referring_domain": "$direct" + }, + "$sent_at": "2023-10-20T10:27:57.623000+00:00", + "$geoip_city_name": "Sydney", + "$geoip_country_name": "Australia", + "$geoip_country_code": "AU", + "$geoip_continent_name": "Oceania", + "$geoip_continent_code": "OC", + "$geoip_postal_code": "2000", + "$geoip_latitude": -33.8715, + "$geoip_longitude": 151.2006, + "$geoip_time_zone": "Australia/Sydney", + "$geoip_subdivision_1_code": "NSW", + "$geoip_subdivision_1_name": "New South Wales", + "$plugins_succeeded": ["GeoIP (1)"], + "$plugins_failed": [], + "$plugins_deferred": [], + "$group_3": "018a92f8-b602-0000-75de-4b9073693531", + "$group_2": "018a92f8-afff-0000-efec-ca77de39e384", + "$group_4": "cus_OdSgxxWtHOtq9g", + "$group_1": "http://localhost:8000" + }, + "timestamp": "2023-10-20T10:27:54.868000+00:00", + "uuid": null + }, + { + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "elements": [], + "elements_chain": null, + "event": "$groupidentify", + "id": "018b4ca0-976e-70e4-9638-9cc06f5ff7ae", + "person": null, + "properties": { + "$os": "Mac OS X", + "$os_version": "10.15.7", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/home", + "$host": "localhost:8000", + "$pathname": "/home", + "$browser_version": 117, + "$browser_language": "en-GB", + "$screen_height": 982, + "$screen_width": 1512, + "$viewport_height": 859, + "$viewport_width": 1512, + "$lib": "web", + "$lib_version": "1.84.0", + "$insert_id": "tr5rt49cwyup64d1", + "$time": 1697797674.863, + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$device_id": "018a92fd-7b25-7770-a050-577e94fd148c", + "$console_log_recording_enabled_server_side": true, + "$session_recording_recorder_version_server_side": "v2", + "$autocapture_disabled_server_side": false, + "$active_feature_flags": [ + "signup-page-4.0", + "cmd-k-search", + "posthog-3000", + "funnels-cue-opt-out-7301", + "retention-breakdown", + "smoothing-interval", + "billing-limit", + "kafka-inspector", + "historical-exports-v2", + "person-on-events-enabled", + "region-select", + "ingestion-warnings-enabled", + "session-reset-on-load", + "recordings-on-feature-flags", + "auto-rollback-feature-flags", + "onboarding-v2-demo", + "feature-flag-rollout-ux", + "role-based-access", + "query_running_time", + "query-timings", + "recording-debugging", + "enable-prompts", + "feedback-scene", + "early-access-feature", + "early-access-feature-site-button", + "hedgehog-mode-debug", + "auto-redirect", + "session-recording-blob-replay", + "surveys", + "generic-signup-benefits", + "surveys-positions", + "web-analytics", + "high-frequency-batch-exports", + "exception-autocapture", + "data-warehouse", + "data-warehouse-views", + "ff-dashboard-templates", + "show-product-intro-existing-products", + "artificial-hog", + "cs-dashboards", + "product-specific-onboarding", + "redirect-signups-to-instance", + "apps-and-exports-ui", + "survey-nps-results", + "session-recording-allow-v1-snapshots", + "session-replay-cors-proxy", + "webhooks-denylist", + "surveys-site-app-deprecation", + "surveys-multiple-questions", + "surveys-results-visualizations", + "console-recording-search", + "persons-hogql-query", + "notebooks" + ], + "$feature/file-previews": false, + "$feature/signup-page-4.0": "control", + "$feature/hogql-insights": false, + "$feature/cmd-k-search": true, + "$feature/posthog-3000": true, + "$feature/funnels-cue-opt-out-7301": true, + "$feature/retention-breakdown": true, + "$feature/smoothing-interval": true, + "$feature/billing-limit": true, + "$feature/kafka-inspector": true, + "$feature/historical-exports-v2": true, + "$feature/person-on-events-enabled": true, + "$feature/region-select": true, + "$feature/ingestion-warnings-enabled": true, + "$feature/session-reset-on-load": true, + "$feature/recordings-on-feature-flags": true, + "$feature/auto-rollback-feature-flags": true, + "$feature/onboarding-v2-demo": true, + "$feature/feature-flag-rollout-ux": true, + "$feature/role-based-access": true, + "$feature/query_running_time": true, + "$feature/query-timings": true, + "$feature/recording-debugging": true, + "$feature/enable-prompts": true, + "$feature/feedback-scene": true, + "$feature/early-access-feature": true, + "$feature/early-access-feature-site-button": true, + "$feature/hedgehog-mode-debug": true, + "$feature/auto-redirect": true, + "$feature/session-recording-blob-replay": true, + "$feature/surveys": true, + "$feature/generic-signup-benefits": true, + "$feature/surveys-positions": true, + "$feature/web-analytics": true, + "$feature/high-frequency-batch-exports": true, + "$feature/exception-autocapture": true, + "$feature/data-warehouse": true, + "$feature/data-warehouse-views": true, + "$feature/ff-dashboard-templates": true, + "$feature/show-product-intro-existing-products": true, + "$feature/artificial-hog": true, + "$feature/cs-dashboards": true, + "$feature/product-specific-onboarding": true, + "$feature/redirect-signups-to-instance": true, + "$feature/apps-and-exports-ui": true, + "$feature/survey-nps-results": true, + "$feature/session-recording-allow-v1-snapshots": true, + "$feature/session-replay-cors-proxy": true, + "$feature/webhooks-denylist": true, + "$feature/surveys-site-app-deprecation": true, + "$feature/surveys-multiple-questions": true, + "$feature/surveys-results-visualizations": true, + "$feature/console-recording-search": true, + "$feature/persons-hogql-query": true, + "$feature/notebooks": true, + "$feature_flag_payloads": {}, + "realm": "hosted-clickhouse", + "email_service_available": false, + "slack_service_available": false, + "$user_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "is_demo_project": false, + "$groups": { + "project": "018a92f8-b602-0000-75de-4b9073693531", + "organization": "018a92f8-afff-0000-efec-ca77de39e384", + "customer": "cus_OdSgxxWtHOtq9g", + "instance": "http://localhost:8000" + }, + "has_billing_plan": true, + "customer_deactivated": false, + "current_total_amount_usd": "0.00", + "percentage_usage.product_analytics": 0, + "current_amount_usd.product_analytics": "0.00", + "unit_amount_usd.product_analytics": null, + "usage_limit.product_analytics": null, + "current_usage.product_analytics": 3729, + "projected_usage.product_analytics": 0, + "free_allocation.product_analytics": 0, + "percentage_usage.session_replay": 0, + "current_amount_usd.session_replay": "0.00", + "unit_amount_usd.session_replay": null, + "usage_limit.session_replay": null, + "current_usage.session_replay": 254, + "projected_usage.session_replay": 0, + "free_allocation.session_replay": 0, + "percentage_usage.feature_flags": 0, + "current_amount_usd.feature_flags": "0.00", + "unit_amount_usd.feature_flags": null, + "usage_limit.feature_flags": null, + "current_usage.feature_flags": 0, + "projected_usage.feature_flags": 0, + "free_allocation.feature_flags": 0, + "percentage_usage.integrations": 0, + "current_amount_usd.integrations": null, + "unit_amount_usd.integrations": null, + "usage_limit.integrations": 0, + "current_usage.integrations": 0, + "projected_usage.integrations": 0, + "free_allocation.integrations": 0, + "percentage_usage.platform_and_support": 0, + "current_amount_usd.platform_and_support": null, + "unit_amount_usd.platform_and_support": null, + "usage_limit.platform_and_support": 0, + "current_usage.platform_and_support": 0, + "projected_usage.platform_and_support": 0, + "free_allocation.platform_and_support": 0, + "billing_period_start": "2023-10-14T09:22:33.000Z", + "billing_period_end": "2023-11-14T09:22:33.000Z", + "$referrer": "$direct", + "$referring_domain": "$direct", + "$group_type": "instance", + "$group_key": "http://localhost:8000", + "$group_set": { + "site_url": "http://localhost:8000" + }, + "token": "phc_OWGI2wKbfi7rWDZT9wkl8uGcfe0wOGCvflLEZSMiaT0", + "$session_id": "018b4ca0-9686-7b75-ba2e-61e9c0054b65", + "$window_id": "018b4ca0-9686-7b75-ba2e-61ea857e58f0", + "$ip": "127.0.0.1", + "$set": { + "$os": "Mac OS X", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/home", + "$pathname": "/home", + "$browser_version": 117, + "$referrer": "$direct", + "$referring_domain": "$direct" + }, + "$set_once": { + "$initial_os": "Mac OS X", + "$initial_browser": "Chrome", + "$initial_device_type": "Desktop", + "$initial_current_url": "http://localhost:8000/home", + "$initial_pathname": "/home", + "$initial_browser_version": 117, + "$initial_referrer": "$direct", + "$initial_referring_domain": "$direct" + }, + "$sent_at": "2023-10-20T10:27:57.623000+00:00", + "$geoip_city_name": "Sydney", + "$geoip_country_name": "Australia", + "$geoip_country_code": "AU", + "$geoip_continent_name": "Oceania", + "$geoip_continent_code": "OC", + "$geoip_postal_code": "2000", + "$geoip_latitude": -33.8715, + "$geoip_longitude": 151.2006, + "$geoip_time_zone": "Australia/Sydney", + "$geoip_subdivision_1_code": "NSW", + "$geoip_subdivision_1_name": "New South Wales", + "$plugins_succeeded": ["GeoIP (1)"], + "$plugins_failed": [], + "$plugins_deferred": [], + "$group_3": "018a92f8-b602-0000-75de-4b9073693531", + "$group_2": "018a92f8-afff-0000-efec-ca77de39e384", + "$group_4": "cus_OdSgxxWtHOtq9g", + "$group_1": "http://localhost:8000" + }, + "timestamp": "2023-10-20T10:27:54.872000+00:00", + "uuid": null + }, + { + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "elements": [], + "elements_chain": null, + "event": "dashboard loading time", + "id": "018b4ca0-9a3d-701d-ae6b-2dd63b414e53", + "person": null, + "properties": { + "$os": "Mac OS X", + "$os_version": "10.15.7", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/home", + "$host": "localhost:8000", + "$pathname": "/home", + "$browser_version": 117, + "$browser_language": "en-GB", + "$screen_height": 982, + "$screen_width": 1512, + "$viewport_height": 859, + "$viewport_width": 1512, + "$lib": "web", + "$lib_version": "1.84.0", + "$insert_id": "bky5j00lf96hy1er", + "$time": 1697797675.581, + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$device_id": "018a92fd-7b25-7770-a050-577e94fd148c", + "$console_log_recording_enabled_server_side": true, + "$session_recording_recorder_version_server_side": "v2", + "$autocapture_disabled_server_side": false, + "$active_feature_flags": [ + "signup-page-4.0", + "cmd-k-search", + "posthog-3000", + "funnels-cue-opt-out-7301", + "retention-breakdown", + "smoothing-interval", + "billing-limit", + "kafka-inspector", + "historical-exports-v2", + "person-on-events-enabled", + "region-select", + "ingestion-warnings-enabled", + "session-reset-on-load", + "recordings-on-feature-flags", + "auto-rollback-feature-flags", + "onboarding-v2-demo", + "feature-flag-rollout-ux", + "role-based-access", + "query_running_time", + "query-timings", + "recording-debugging", + "enable-prompts", + "feedback-scene", + "early-access-feature", + "early-access-feature-site-button", + "hedgehog-mode-debug", + "auto-redirect", + "session-recording-blob-replay", + "surveys", + "generic-signup-benefits", + "surveys-positions", + "web-analytics", + "high-frequency-batch-exports", + "exception-autocapture", + "data-warehouse", + "data-warehouse-views", + "ff-dashboard-templates", + "show-product-intro-existing-products", + "artificial-hog", + "cs-dashboards", + "product-specific-onboarding", + "redirect-signups-to-instance", + "apps-and-exports-ui", + "survey-nps-results", + "session-recording-allow-v1-snapshots", + "session-replay-cors-proxy", + "webhooks-denylist", + "surveys-site-app-deprecation", + "surveys-multiple-questions", + "surveys-results-visualizations", + "console-recording-search", + "persons-hogql-query", + "notebooks" + ], + "$feature/file-previews": false, + "$feature/signup-page-4.0": "control", + "$feature/hogql-insights": false, + "$feature/cmd-k-search": true, + "$feature/posthog-3000": true, + "$feature/funnels-cue-opt-out-7301": true, + "$feature/retention-breakdown": true, + "$feature/smoothing-interval": true, + "$feature/billing-limit": true, + "$feature/kafka-inspector": true, + "$feature/historical-exports-v2": true, + "$feature/person-on-events-enabled": true, + "$feature/region-select": true, + "$feature/ingestion-warnings-enabled": true, + "$feature/session-reset-on-load": true, + "$feature/recordings-on-feature-flags": true, + "$feature/auto-rollback-feature-flags": true, + "$feature/onboarding-v2-demo": true, + "$feature/feature-flag-rollout-ux": true, + "$feature/role-based-access": true, + "$feature/query_running_time": true, + "$feature/query-timings": true, + "$feature/recording-debugging": true, + "$feature/enable-prompts": true, + "$feature/feedback-scene": true, + "$feature/early-access-feature": true, + "$feature/early-access-feature-site-button": true, + "$feature/hedgehog-mode-debug": true, + "$feature/auto-redirect": true, + "$feature/session-recording-blob-replay": true, + "$feature/surveys": true, + "$feature/generic-signup-benefits": true, + "$feature/surveys-positions": true, + "$feature/web-analytics": true, + "$feature/high-frequency-batch-exports": true, + "$feature/exception-autocapture": true, + "$feature/data-warehouse": true, + "$feature/data-warehouse-views": true, + "$feature/ff-dashboard-templates": true, + "$feature/show-product-intro-existing-products": true, + "$feature/artificial-hog": true, + "$feature/cs-dashboards": true, + "$feature/product-specific-onboarding": true, + "$feature/redirect-signups-to-instance": true, + "$feature/apps-and-exports-ui": true, + "$feature/survey-nps-results": true, + "$feature/session-recording-allow-v1-snapshots": true, + "$feature/session-replay-cors-proxy": true, + "$feature/webhooks-denylist": true, + "$feature/surveys-site-app-deprecation": true, + "$feature/surveys-multiple-questions": true, + "$feature/surveys-results-visualizations": true, + "$feature/console-recording-search": true, + "$feature/persons-hogql-query": true, + "$feature/notebooks": true, + "$feature_flag_payloads": {}, + "realm": "hosted-clickhouse", + "email_service_available": false, + "slack_service_available": false, + "$user_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "is_demo_project": false, + "$groups": { + "project": "018a92f8-b602-0000-75de-4b9073693531", + "organization": "018a92f8-afff-0000-efec-ca77de39e384", + "customer": "cus_OdSgxxWtHOtq9g", + "instance": "http://localhost:8000" + }, + "has_billing_plan": true, + "customer_deactivated": false, + "current_total_amount_usd": "0.00", + "percentage_usage.product_analytics": 0, + "current_amount_usd.product_analytics": "0.00", + "unit_amount_usd.product_analytics": null, + "usage_limit.product_analytics": null, + "current_usage.product_analytics": 3729, + "projected_usage.product_analytics": 0, + "free_allocation.product_analytics": 0, + "percentage_usage.session_replay": 0, + "current_amount_usd.session_replay": "0.00", + "unit_amount_usd.session_replay": null, + "usage_limit.session_replay": null, + "current_usage.session_replay": 254, + "projected_usage.session_replay": 0, + "free_allocation.session_replay": 0, + "percentage_usage.feature_flags": 0, + "current_amount_usd.feature_flags": "0.00", + "unit_amount_usd.feature_flags": null, + "usage_limit.feature_flags": null, + "current_usage.feature_flags": 0, + "projected_usage.feature_flags": 0, + "free_allocation.feature_flags": 0, + "percentage_usage.integrations": 0, + "current_amount_usd.integrations": null, + "unit_amount_usd.integrations": null, + "usage_limit.integrations": 0, + "current_usage.integrations": 0, + "projected_usage.integrations": 0, + "free_allocation.integrations": 0, + "percentage_usage.platform_and_support": 0, + "current_amount_usd.platform_and_support": null, + "unit_amount_usd.platform_and_support": null, + "usage_limit.platform_and_support": 0, + "current_usage.platform_and_support": 0, + "projected_usage.platform_and_support": 0, + "free_allocation.platform_and_support": 0, + "billing_period_start": "2023-10-14T09:22:33.000Z", + "billing_period_end": "2023-11-14T09:22:33.000Z", + "$referrer": "$direct", + "$referring_domain": "$direct", + "loadingMilliseconds": 732, + "dashboardId": 1, + "token": "phc_OWGI2wKbfi7rWDZT9wkl8uGcfe0wOGCvflLEZSMiaT0", + "$session_id": "018b4ca0-9686-7b75-ba2e-61e9c0054b65", + "$window_id": "018b4ca0-9686-7b75-ba2e-61ea857e58f0", + "$ip": "127.0.0.1", + "$set": { + "$os": "Mac OS X", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/home", + "$pathname": "/home", + "$browser_version": 117, + "$referrer": "$direct", + "$referring_domain": "$direct" + }, + "$set_once": { + "$initial_os": "Mac OS X", + "$initial_browser": "Chrome", + "$initial_device_type": "Desktop", + "$initial_current_url": "http://localhost:8000/home", + "$initial_pathname": "/home", + "$initial_browser_version": 117, + "$initial_referrer": "$direct", + "$initial_referring_domain": "$direct" + }, + "$sent_at": "2023-10-20T10:27:57.623000+00:00", + "$geoip_city_name": "Sydney", + "$geoip_country_name": "Australia", + "$geoip_country_code": "AU", + "$geoip_continent_name": "Oceania", + "$geoip_continent_code": "OC", + "$geoip_postal_code": "2000", + "$geoip_latitude": -33.8715, + "$geoip_longitude": 151.2006, + "$geoip_time_zone": "Australia/Sydney", + "$geoip_subdivision_1_code": "NSW", + "$geoip_subdivision_1_name": "New South Wales", + "$plugins_succeeded": ["GeoIP (1)"], + "$plugins_failed": [], + "$plugins_deferred": [], + "$group_3": "018a92f8-b602-0000-75de-4b9073693531", + "$group_2": "018a92f8-afff-0000-efec-ca77de39e384", + "$group_4": "cus_OdSgxxWtHOtq9g", + "$group_1": "http://localhost:8000" + }, + "timestamp": "2023-10-20T10:27:55.590000+00:00", + "uuid": null + }, + { + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "elements": [], + "elements_chain": null, + "event": "viewed dashboard", + "id": "018b4ca0-9d0b-7f91-95e6-1e4ca5ee515d", + "person": null, + "properties": { + "$os": "Mac OS X", + "$os_version": "10.15.7", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/home", + "$host": "localhost:8000", + "$pathname": "/home", + "$browser_version": 117, + "$browser_language": "en-GB", + "$screen_height": 982, + "$screen_width": 1512, + "$viewport_height": 859, + "$viewport_width": 1512, + "$lib": "web", + "$lib_version": "1.84.0", + "$insert_id": "r9bc60imc531ktci", + "$time": 1697797676.299, + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$device_id": "018a92fd-7b25-7770-a050-577e94fd148c", + "$console_log_recording_enabled_server_side": true, + "$session_recording_recorder_version_server_side": "v2", + "$autocapture_disabled_server_side": false, + "$active_feature_flags": [ + "signup-page-4.0", + "cmd-k-search", + "posthog-3000", + "funnels-cue-opt-out-7301", + "retention-breakdown", + "smoothing-interval", + "billing-limit", + "kafka-inspector", + "historical-exports-v2", + "person-on-events-enabled", + "region-select", + "ingestion-warnings-enabled", + "session-reset-on-load", + "recordings-on-feature-flags", + "auto-rollback-feature-flags", + "onboarding-v2-demo", + "feature-flag-rollout-ux", + "role-based-access", + "query_running_time", + "query-timings", + "recording-debugging", + "enable-prompts", + "feedback-scene", + "early-access-feature", + "early-access-feature-site-button", + "hedgehog-mode-debug", + "auto-redirect", + "session-recording-blob-replay", + "surveys", + "generic-signup-benefits", + "surveys-positions", + "web-analytics", + "high-frequency-batch-exports", + "exception-autocapture", + "data-warehouse", + "data-warehouse-views", + "ff-dashboard-templates", + "show-product-intro-existing-products", + "artificial-hog", + "cs-dashboards", + "product-specific-onboarding", + "redirect-signups-to-instance", + "apps-and-exports-ui", + "survey-nps-results", + "session-recording-allow-v1-snapshots", + "session-replay-cors-proxy", + "webhooks-denylist", + "surveys-site-app-deprecation", + "surveys-multiple-questions", + "surveys-results-visualizations", + "console-recording-search", + "persons-hogql-query", + "notebooks" + ], + "$feature/file-previews": false, + "$feature/signup-page-4.0": "control", + "$feature/hogql-insights": false, + "$feature/cmd-k-search": true, + "$feature/posthog-3000": true, + "$feature/funnels-cue-opt-out-7301": true, + "$feature/retention-breakdown": true, + "$feature/smoothing-interval": true, + "$feature/billing-limit": true, + "$feature/kafka-inspector": true, + "$feature/historical-exports-v2": true, + "$feature/person-on-events-enabled": true, + "$feature/region-select": true, + "$feature/ingestion-warnings-enabled": true, + "$feature/session-reset-on-load": true, + "$feature/recordings-on-feature-flags": true, + "$feature/auto-rollback-feature-flags": true, + "$feature/onboarding-v2-demo": true, + "$feature/feature-flag-rollout-ux": true, + "$feature/role-based-access": true, + "$feature/query_running_time": true, + "$feature/query-timings": true, + "$feature/recording-debugging": true, + "$feature/enable-prompts": true, + "$feature/feedback-scene": true, + "$feature/early-access-feature": true, + "$feature/early-access-feature-site-button": true, + "$feature/hedgehog-mode-debug": true, + "$feature/auto-redirect": true, + "$feature/session-recording-blob-replay": true, + "$feature/surveys": true, + "$feature/generic-signup-benefits": true, + "$feature/surveys-positions": true, + "$feature/web-analytics": true, + "$feature/high-frequency-batch-exports": true, + "$feature/exception-autocapture": true, + "$feature/data-warehouse": true, + "$feature/data-warehouse-views": true, + "$feature/ff-dashboard-templates": true, + "$feature/show-product-intro-existing-products": true, + "$feature/artificial-hog": true, + "$feature/cs-dashboards": true, + "$feature/product-specific-onboarding": true, + "$feature/redirect-signups-to-instance": true, + "$feature/apps-and-exports-ui": true, + "$feature/survey-nps-results": true, + "$feature/session-recording-allow-v1-snapshots": true, + "$feature/session-replay-cors-proxy": true, + "$feature/webhooks-denylist": true, + "$feature/surveys-site-app-deprecation": true, + "$feature/surveys-multiple-questions": true, + "$feature/surveys-results-visualizations": true, + "$feature/console-recording-search": true, + "$feature/persons-hogql-query": true, + "$feature/notebooks": true, + "$feature_flag_payloads": {}, + "realm": "hosted-clickhouse", + "email_service_available": false, + "slack_service_available": false, + "$user_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "is_demo_project": false, + "$groups": { + "project": "018a92f8-b602-0000-75de-4b9073693531", + "organization": "018a92f8-afff-0000-efec-ca77de39e384", + "customer": "cus_OdSgxxWtHOtq9g", + "instance": "http://localhost:8000" + }, + "has_billing_plan": true, + "customer_deactivated": false, + "current_total_amount_usd": "0.00", + "percentage_usage.product_analytics": 0, + "current_amount_usd.product_analytics": "0.00", + "unit_amount_usd.product_analytics": null, + "usage_limit.product_analytics": null, + "current_usage.product_analytics": 3729, + "projected_usage.product_analytics": 0, + "free_allocation.product_analytics": 0, + "percentage_usage.session_replay": 0, + "current_amount_usd.session_replay": "0.00", + "unit_amount_usd.session_replay": null, + "usage_limit.session_replay": null, + "current_usage.session_replay": 254, + "projected_usage.session_replay": 0, + "free_allocation.session_replay": 0, + "percentage_usage.feature_flags": 0, + "current_amount_usd.feature_flags": "0.00", + "unit_amount_usd.feature_flags": null, + "usage_limit.feature_flags": null, + "current_usage.feature_flags": 0, + "projected_usage.feature_flags": 0, + "free_allocation.feature_flags": 0, + "percentage_usage.integrations": 0, + "current_amount_usd.integrations": null, + "unit_amount_usd.integrations": null, + "usage_limit.integrations": 0, + "current_usage.integrations": 0, + "projected_usage.integrations": 0, + "free_allocation.integrations": 0, + "percentage_usage.platform_and_support": 0, + "current_amount_usd.platform_and_support": null, + "unit_amount_usd.platform_and_support": null, + "usage_limit.platform_and_support": 0, + "current_usage.platform_and_support": 0, + "projected_usage.platform_and_support": 0, + "free_allocation.platform_and_support": 0, + "billing_period_start": "2023-10-14T09:22:33.000Z", + "billing_period_end": "2023-11-14T09:22:33.000Z", + "$referrer": "$direct", + "$referring_domain": "$direct", + "created_at": "2023-09-14T09:15:00.211731Z", + "is_shared": false, + "pinned": true, + "creation_mode": "default", + "sample_items_count": 0, + "item_count": 7, + "created_by_system": true, + "dashboard_id": 1, + "lastRefreshed": "2023-10-20T10:20:11.963Z", + "refreshAge": 464, + "lifecycle_count": 2, + "trends_count": 3, + "funnels_count": 1, + "retention_count": 1, + "token": "phc_OWGI2wKbfi7rWDZT9wkl8uGcfe0wOGCvflLEZSMiaT0", + "$session_id": "018b4ca0-9686-7b75-ba2e-61e9c0054b65", + "$window_id": "018b4ca0-9686-7b75-ba2e-61ea857e58f0", + "$ip": "127.0.0.1", + "$set": { + "$os": "Mac OS X", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/home", + "$pathname": "/home", + "$browser_version": 117, + "$referrer": "$direct", + "$referring_domain": "$direct" + }, + "$set_once": { + "$initial_os": "Mac OS X", + "$initial_browser": "Chrome", + "$initial_device_type": "Desktop", + "$initial_current_url": "http://localhost:8000/home", + "$initial_pathname": "/home", + "$initial_browser_version": 117, + "$initial_referrer": "$direct", + "$initial_referring_domain": "$direct" + }, + "$sent_at": "2023-10-20T10:27:57.623000+00:00", + "$geoip_city_name": "Sydney", + "$geoip_country_name": "Australia", + "$geoip_country_code": "AU", + "$geoip_continent_name": "Oceania", + "$geoip_continent_code": "OC", + "$geoip_postal_code": "2000", + "$geoip_latitude": -33.8715, + "$geoip_longitude": 151.2006, + "$geoip_time_zone": "Australia/Sydney", + "$geoip_subdivision_1_code": "NSW", + "$geoip_subdivision_1_name": "New South Wales", + "$plugins_succeeded": ["GeoIP (1)"], + "$plugins_failed": [], + "$plugins_deferred": [], + "$group_3": "018a92f8-b602-0000-75de-4b9073693531", + "$group_2": "018a92f8-afff-0000-efec-ca77de39e384", + "$group_4": "cus_OdSgxxWtHOtq9g", + "$group_1": "http://localhost:8000" + }, + "timestamp": "2023-10-20T10:27:56.308000+00:00", + "uuid": null + }, + { + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "elements": [ + { + "attr_class": ["Link", "SidebarListItem__link"], + "attr_id": null, + "attributes": { + "attr__class": "Link SidebarListItem__link", + "attr__draggable": "true", + "attr__href": "/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI" + }, + "href": "/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "nth_child": 1.0, + "nth_of_type": 1.0, + "order": 0.0, + "tag_name": "a", + "text": null + }, + { + "attr_class": ["SidebarListItem"], + "attr_id": "sidebar-krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI,018a92fd-7b25-7770-a050-577e94fd148c,018b4715-2fd1-7b9d-b1de-4cf7972a15e3", + "attributes": { + "attr__aria-disabled": "false", + "attr__aria-invalid": "false", + "attr__class": "SidebarListItem", + "attr__id": "sidebar-krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI,018a92fd-7b25-7770-a050-577e94fd148c,018b4715-2fd1-7b9d-b1de-4cf7972a15e3", + "attr__style": "height: 32px; left: 0px; position: absolute; top: 64px; width: 100%;", + "attr__title": "test@posthog.com" + }, + "href": null, + "nth_child": 3.0, + "nth_of_type": 3.0, + "order": 1.0, + "tag_name": "li", + "text": null + }, + { + "attr_class": ["ReactVirtualized__Grid__innerScrollContainer"], + "attr_id": null, + "attributes": { + "attr__class": "ReactVirtualized__Grid__innerScrollContainer", + "attr__role": "rowgroup", + "attr__style": "width: auto; height: 95872px; max-width: 250px; max-height: 95872px; overflow: hidden; position: relative;" + }, + "href": null, + "nth_child": 1.0, + "nth_of_type": 1.0, + "order": 2.0, + "tag_name": "div", + "text": null + }, + { + "attr_class": ["ReactVirtualized__Grid", "ReactVirtualized__List", "SidebarList"], + "attr_id": null, + "attributes": { + "attr__aria-label": "grid", + "attr__aria-readonly": "true", + "attr__class": "ReactVirtualized__Grid ReactVirtualized__List SidebarList", + "attr__role": "grid", + "attr__style": "box-sizing: border-box; direction: ltr; height: 312px; position: relative; width: 250px; will-change: transform; overflow: hidden auto;" + }, + "href": null, + "nth_child": 1.0, + "nth_of_type": 1.0, + "order": 3.0, + "tag_name": "div", + "text": null + }, + { + "attr_class": null, + "attr_id": null, + "attributes": { + "attr__style": "overflow: visible; height: 0px;" + }, + "href": null, + "nth_child": 1.0, + "nth_of_type": 1.0, + "order": 4.0, + "tag_name": "div", + "text": null + }, + { + "attr_class": ["flex-1"], + "attr_id": null, + "attributes": { + "attr__class": "flex-1", + "attr__style": "position: relative;" + }, + "href": null, + "nth_child": 2.0, + "nth_of_type": 2.0, + "order": 5.0, + "tag_name": "div", + "text": null + }, + { + "attr_class": ["Accordion"], + "attr_id": null, + "attributes": { + "attr__aria-busy": "false", + "attr__aria-disabled": "false", + "attr__aria-expanded": "true", + "attr__class": "Accordion" + }, + "href": null, + "nth_child": 1.0, + "nth_of_type": 1.0, + "order": 6.0, + "tag_name": "section", + "text": null + }, + { + "attr_class": ["Sidebar3000__lists"], + "attr_id": null, + "attributes": { + "attr__class": "Sidebar3000__lists" + }, + "href": null, + "nth_child": 2.0, + "nth_of_type": 2.0, + "order": 7.0, + "tag_name": "div", + "text": null + }, + { + "attr_class": ["Sidebar3000__content"], + "attr_id": null, + "attributes": { + "attr__class": "Sidebar3000__content" + }, + "href": null, + "nth_child": 1.0, + "nth_of_type": 1.0, + "order": 8.0, + "tag_name": "div", + "text": null + }, + { + "attr_class": ["Sidebar3000"], + "attr_id": null, + "attributes": { + "attr__aria-hidden": "false", + "attr__class": "Sidebar3000", + "attr__style": "--sidebar-width: 250px;" + }, + "href": null, + "nth_child": 2.0, + "nth_of_type": 1.0, + "order": 9.0, + "tag_name": "div", + "text": null + }, + { + "attr_class": ["Navigation3000"], + "attr_id": null, + "attributes": { + "attr__class": "Navigation3000" + }, + "href": null, + "nth_child": 1.0, + "nth_of_type": 1.0, + "order": 10.0, + "tag_name": "div", + "text": null + }, + { + "attr_class": null, + "attr_id": "root", + "attributes": { + "attr__id": "root" + }, + "href": null, + "nth_child": 4.0, + "nth_of_type": 1.0, + "order": 11.0, + "tag_name": "div", + "text": null + }, + { + "attr_class": ["posthog-3000"], + "attr_id": null, + "attributes": { + "attr__class": "posthog-3000", + "attr__theme": "light" + }, + "href": null, + "nth_child": 2.0, + "nth_of_type": 1.0, + "order": 12.0, + "tag_name": "body", + "text": null + } + ], + "elements_chain": "a.Link.SidebarListItem__link:attr__class=\"Link SidebarListItem__link\"attr__draggable=\"true\"attr__href=\"/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI\"href=\"/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI\"nth-child=\"1\"nth-of-type=\"1\";li.SidebarListItem:attr__aria-disabled=\"false\"attr__aria-invalid=\"false\"attr__class=\"SidebarListItem\"attr__id=\"sidebar-krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI,018a92fd-7b25-7770-a050-577e94fd148c,018b4715-2fd1-7b9d-b1de-4cf7972a15e3\"attr__style=\"height: 32px; left: 0px; position: absolute; top: 64px; width: 100%;\"attr__title=\"test@posthog.com\"attr_id=\"sidebar-krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI,018a92fd-7b25-7770-a050-577e94fd148c,018b4715-2fd1-7b9d-b1de-4cf7972a15e3\"nth-child=\"3\"nth-of-type=\"3\";div.ReactVirtualized__Grid__innerScrollContainer:attr__class=\"ReactVirtualized__Grid__innerScrollContainer\"attr__role=\"rowgroup\"attr__style=\"width: auto; height: 95872px; max-width: 250px; max-height: 95872px; overflow: hidden; position: relative;\"nth-child=\"1\"nth-of-type=\"1\";div.ReactVirtualized__Grid.ReactVirtualized__List.SidebarList:attr__aria-label=\"grid\"attr__aria-readonly=\"true\"attr__class=\"ReactVirtualized__Grid ReactVirtualized__List SidebarList\"attr__role=\"grid\"attr__style=\"box-sizing: border-box; direction: ltr; height: 312px; position: relative; width: 250px; will-change: transform; overflow: hidden auto;\"nth-child=\"1\"nth-of-type=\"1\";div:attr__style=\"overflow: visible; height: 0px;\"nth-child=\"1\"nth-of-type=\"1\";div.flex-1:attr__class=\"flex-1\"attr__style=\"position: relative;\"nth-child=\"2\"nth-of-type=\"2\";section.Accordion:attr__aria-busy=\"false\"attr__aria-disabled=\"false\"attr__aria-expanded=\"true\"attr__class=\"Accordion\"nth-child=\"1\"nth-of-type=\"1\";div.Sidebar3000__lists:attr__class=\"Sidebar3000__lists\"nth-child=\"2\"nth-of-type=\"2\";div.Sidebar3000__content:attr__class=\"Sidebar3000__content\"nth-child=\"1\"nth-of-type=\"1\";div.Sidebar3000:attr__aria-hidden=\"false\"attr__class=\"Sidebar3000\"attr__style=\"--sidebar-width: 250px;\"nth-child=\"2\"nth-of-type=\"1\";div.Navigation3000:attr__class=\"Navigation3000\"nth-child=\"1\"nth-of-type=\"1\";div:attr__id=\"root\"attr_id=\"root\"nth-child=\"4\"nth-of-type=\"1\";body.posthog-3000:attr__class=\"posthog-3000\"attr__theme=\"light\"nth-child=\"2\"nth-of-type=\"1\"", + "event": "$autocapture", + "id": "018b4ca0-a013-7c3d-9cbd-825b3733cec2", + "person": null, + "properties": { + "$os": "Mac OS X", + "$os_version": "10.15.7", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/home", + "$host": "localhost:8000", + "$pathname": "/home", + "$browser_version": 117, + "$browser_language": "en-GB", + "$screen_height": 982, + "$screen_width": 1512, + "$viewport_height": 859, + "$viewport_width": 1512, + "$lib": "web", + "$lib_version": "1.84.0", + "$insert_id": "b99wxvg3x3924y92", + "$time": 1697797677.075, + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$device_id": "018a92fd-7b25-7770-a050-577e94fd148c", + "$console_log_recording_enabled_server_side": true, + "$session_recording_recorder_version_server_side": "v2", + "$autocapture_disabled_server_side": false, + "$active_feature_flags": [ + "signup-page-4.0", + "cmd-k-search", + "posthog-3000", + "funnels-cue-opt-out-7301", + "retention-breakdown", + "smoothing-interval", + "billing-limit", + "kafka-inspector", + "historical-exports-v2", + "person-on-events-enabled", + "region-select", + "ingestion-warnings-enabled", + "session-reset-on-load", + "recordings-on-feature-flags", + "auto-rollback-feature-flags", + "onboarding-v2-demo", + "feature-flag-rollout-ux", + "role-based-access", + "query_running_time", + "query-timings", + "recording-debugging", + "enable-prompts", + "feedback-scene", + "early-access-feature", + "early-access-feature-site-button", + "hedgehog-mode-debug", + "auto-redirect", + "session-recording-blob-replay", + "surveys", + "generic-signup-benefits", + "surveys-positions", + "web-analytics", + "high-frequency-batch-exports", + "exception-autocapture", + "data-warehouse", + "data-warehouse-views", + "ff-dashboard-templates", + "show-product-intro-existing-products", + "artificial-hog", + "cs-dashboards", + "product-specific-onboarding", + "redirect-signups-to-instance", + "apps-and-exports-ui", + "survey-nps-results", + "session-recording-allow-v1-snapshots", + "session-replay-cors-proxy", + "webhooks-denylist", + "surveys-site-app-deprecation", + "surveys-multiple-questions", + "surveys-results-visualizations", + "console-recording-search", + "persons-hogql-query", + "notebooks" + ], + "$feature/file-previews": false, + "$feature/signup-page-4.0": "control", + "$feature/hogql-insights": false, + "$feature/cmd-k-search": true, + "$feature/posthog-3000": true, + "$feature/funnels-cue-opt-out-7301": true, + "$feature/retention-breakdown": true, + "$feature/smoothing-interval": true, + "$feature/billing-limit": true, + "$feature/kafka-inspector": true, + "$feature/historical-exports-v2": true, + "$feature/person-on-events-enabled": true, + "$feature/region-select": true, + "$feature/ingestion-warnings-enabled": true, + "$feature/session-reset-on-load": true, + "$feature/recordings-on-feature-flags": true, + "$feature/auto-rollback-feature-flags": true, + "$feature/onboarding-v2-demo": true, + "$feature/feature-flag-rollout-ux": true, + "$feature/role-based-access": true, + "$feature/query_running_time": true, + "$feature/query-timings": true, + "$feature/recording-debugging": true, + "$feature/enable-prompts": true, + "$feature/feedback-scene": true, + "$feature/early-access-feature": true, + "$feature/early-access-feature-site-button": true, + "$feature/hedgehog-mode-debug": true, + "$feature/auto-redirect": true, + "$feature/session-recording-blob-replay": true, + "$feature/surveys": true, + "$feature/generic-signup-benefits": true, + "$feature/surveys-positions": true, + "$feature/web-analytics": true, + "$feature/high-frequency-batch-exports": true, + "$feature/exception-autocapture": true, + "$feature/data-warehouse": true, + "$feature/data-warehouse-views": true, + "$feature/ff-dashboard-templates": true, + "$feature/show-product-intro-existing-products": true, + "$feature/artificial-hog": true, + "$feature/cs-dashboards": true, + "$feature/product-specific-onboarding": true, + "$feature/redirect-signups-to-instance": true, + "$feature/apps-and-exports-ui": true, + "$feature/survey-nps-results": true, + "$feature/session-recording-allow-v1-snapshots": true, + "$feature/session-replay-cors-proxy": true, + "$feature/webhooks-denylist": true, + "$feature/surveys-site-app-deprecation": true, + "$feature/surveys-multiple-questions": true, + "$feature/surveys-results-visualizations": true, + "$feature/console-recording-search": true, + "$feature/persons-hogql-query": true, + "$feature/notebooks": true, + "$feature_flag_payloads": {}, + "realm": "hosted-clickhouse", + "email_service_available": false, + "slack_service_available": false, + "$user_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "is_demo_project": false, + "$groups": { + "project": "018a92f8-b602-0000-75de-4b9073693531", + "organization": "018a92f8-afff-0000-efec-ca77de39e384", + "customer": "cus_OdSgxxWtHOtq9g", + "instance": "http://localhost:8000" + }, + "has_billing_plan": true, + "customer_deactivated": false, + "current_total_amount_usd": "0.00", + "percentage_usage.product_analytics": 0, + "current_amount_usd.product_analytics": "0.00", + "unit_amount_usd.product_analytics": null, + "usage_limit.product_analytics": null, + "current_usage.product_analytics": 3729, + "projected_usage.product_analytics": 0, + "free_allocation.product_analytics": 0, + "percentage_usage.session_replay": 0, + "current_amount_usd.session_replay": "0.00", + "unit_amount_usd.session_replay": null, + "usage_limit.session_replay": null, + "current_usage.session_replay": 254, + "projected_usage.session_replay": 0, + "free_allocation.session_replay": 0, + "percentage_usage.feature_flags": 0, + "current_amount_usd.feature_flags": "0.00", + "unit_amount_usd.feature_flags": null, + "usage_limit.feature_flags": null, + "current_usage.feature_flags": 0, + "projected_usage.feature_flags": 0, + "free_allocation.feature_flags": 0, + "percentage_usage.integrations": 0, + "current_amount_usd.integrations": null, + "unit_amount_usd.integrations": null, + "usage_limit.integrations": 0, + "current_usage.integrations": 0, + "projected_usage.integrations": 0, + "free_allocation.integrations": 0, + "percentage_usage.platform_and_support": 0, + "current_amount_usd.platform_and_support": null, + "unit_amount_usd.platform_and_support": null, + "usage_limit.platform_and_support": 0, + "current_usage.platform_and_support": 0, + "projected_usage.platform_and_support": 0, + "free_allocation.platform_and_support": 0, + "billing_period_start": "2023-10-14T09:22:33.000Z", + "billing_period_end": "2023-11-14T09:22:33.000Z", + "$referrer": "$direct", + "$referring_domain": "$direct", + "$event_type": "click", + "$ce_version": 1, + "token": "phc_OWGI2wKbfi7rWDZT9wkl8uGcfe0wOGCvflLEZSMiaT0", + "$session_id": "018b4ca0-9686-7b75-ba2e-61e9c0054b65", + "$window_id": "018b4ca0-9686-7b75-ba2e-61ea857e58f0", + "$ip": "127.0.0.1", + "$set": { + "$os": "Mac OS X", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/home", + "$pathname": "/home", + "$browser_version": 117, + "$referrer": "$direct", + "$referring_domain": "$direct" + }, + "$set_once": { + "$initial_os": "Mac OS X", + "$initial_browser": "Chrome", + "$initial_device_type": "Desktop", + "$initial_current_url": "http://localhost:8000/home", + "$initial_pathname": "/home", + "$initial_browser_version": 117, + "$initial_referrer": "$direct", + "$initial_referring_domain": "$direct" + }, + "$sent_at": "2023-10-20T10:27:57.623000+00:00", + "$geoip_city_name": "Sydney", + "$geoip_country_name": "Australia", + "$geoip_country_code": "AU", + "$geoip_continent_name": "Oceania", + "$geoip_continent_code": "OC", + "$geoip_postal_code": "2000", + "$geoip_latitude": -33.8715, + "$geoip_longitude": 151.2006, + "$geoip_time_zone": "Australia/Sydney", + "$geoip_subdivision_1_code": "NSW", + "$geoip_subdivision_1_name": "New South Wales", + "$plugins_succeeded": ["GeoIP (1)"], + "$plugins_failed": [], + "$plugins_deferred": [], + "$group_3": "018a92f8-b602-0000-75de-4b9073693531", + "$group_2": "018a92f8-afff-0000-efec-ca77de39e384", + "$group_4": "cus_OdSgxxWtHOtq9g", + "$group_1": "http://localhost:8000" + }, + "timestamp": "2023-10-20T10:27:57.084000+00:00", + "uuid": null + }, + { + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "elements": [], + "elements_chain": null, + "event": "$feature_flag_called", + "id": "018b4ca0-a01c-769b-aa86-7a1610aba22a", + "person": null, + "properties": { + "$os": "Mac OS X", + "$os_version": "10.15.7", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$host": "localhost:8000", + "$pathname": "/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$browser_version": 117, + "$browser_language": "en-GB", + "$screen_height": 982, + "$screen_width": 1512, + "$viewport_height": 859, + "$viewport_width": 1512, + "$lib": "web", + "$lib_version": "1.84.0", + "$insert_id": "pd0e9vs1h9dseim5", + "$time": 1697797677.084, + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$device_id": "018a92fd-7b25-7770-a050-577e94fd148c", + "$console_log_recording_enabled_server_side": true, + "$session_recording_recorder_version_server_side": "v2", + "$autocapture_disabled_server_side": false, + "$active_feature_flags": [ + "signup-page-4.0", + "cmd-k-search", + "posthog-3000", + "funnels-cue-opt-out-7301", + "retention-breakdown", + "smoothing-interval", + "billing-limit", + "kafka-inspector", + "historical-exports-v2", + "person-on-events-enabled", + "region-select", + "ingestion-warnings-enabled", + "session-reset-on-load", + "recordings-on-feature-flags", + "auto-rollback-feature-flags", + "onboarding-v2-demo", + "feature-flag-rollout-ux", + "role-based-access", + "query_running_time", + "query-timings", + "recording-debugging", + "enable-prompts", + "feedback-scene", + "early-access-feature", + "early-access-feature-site-button", + "hedgehog-mode-debug", + "auto-redirect", + "session-recording-blob-replay", + "surveys", + "generic-signup-benefits", + "surveys-positions", + "web-analytics", + "high-frequency-batch-exports", + "exception-autocapture", + "data-warehouse", + "data-warehouse-views", + "ff-dashboard-templates", + "show-product-intro-existing-products", + "artificial-hog", + "cs-dashboards", + "product-specific-onboarding", + "redirect-signups-to-instance", + "apps-and-exports-ui", + "survey-nps-results", + "session-recording-allow-v1-snapshots", + "session-replay-cors-proxy", + "webhooks-denylist", + "surveys-site-app-deprecation", + "surveys-multiple-questions", + "surveys-results-visualizations", + "console-recording-search", + "persons-hogql-query", + "notebooks" + ], + "$feature/file-previews": false, + "$feature/signup-page-4.0": "control", + "$feature/hogql-insights": false, + "$feature/cmd-k-search": true, + "$feature/posthog-3000": true, + "$feature/funnels-cue-opt-out-7301": true, + "$feature/retention-breakdown": true, + "$feature/smoothing-interval": true, + "$feature/billing-limit": true, + "$feature/kafka-inspector": true, + "$feature/historical-exports-v2": true, + "$feature/person-on-events-enabled": true, + "$feature/region-select": true, + "$feature/ingestion-warnings-enabled": true, + "$feature/session-reset-on-load": true, + "$feature/recordings-on-feature-flags": true, + "$feature/auto-rollback-feature-flags": true, + "$feature/onboarding-v2-demo": true, + "$feature/feature-flag-rollout-ux": true, + "$feature/role-based-access": true, + "$feature/query_running_time": true, + "$feature/query-timings": true, + "$feature/recording-debugging": true, + "$feature/enable-prompts": true, + "$feature/feedback-scene": true, + "$feature/early-access-feature": true, + "$feature/early-access-feature-site-button": true, + "$feature/hedgehog-mode-debug": true, + "$feature/auto-redirect": true, + "$feature/session-recording-blob-replay": true, + "$feature/surveys": true, + "$feature/generic-signup-benefits": true, + "$feature/surveys-positions": true, + "$feature/web-analytics": true, + "$feature/high-frequency-batch-exports": true, + "$feature/exception-autocapture": true, + "$feature/data-warehouse": true, + "$feature/data-warehouse-views": true, + "$feature/ff-dashboard-templates": true, + "$feature/show-product-intro-existing-products": true, + "$feature/artificial-hog": true, + "$feature/cs-dashboards": true, + "$feature/product-specific-onboarding": true, + "$feature/redirect-signups-to-instance": true, + "$feature/apps-and-exports-ui": true, + "$feature/survey-nps-results": true, + "$feature/session-recording-allow-v1-snapshots": true, + "$feature/session-replay-cors-proxy": true, + "$feature/webhooks-denylist": true, + "$feature/surveys-site-app-deprecation": true, + "$feature/surveys-multiple-questions": true, + "$feature/surveys-results-visualizations": true, + "$feature/console-recording-search": true, + "$feature/persons-hogql-query": true, + "$feature/notebooks": true, + "$feature_flag_payloads": {}, + "realm": "hosted-clickhouse", + "email_service_available": false, + "slack_service_available": false, + "$user_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "is_demo_project": false, + "$groups": { + "project": "018a92f8-b602-0000-75de-4b9073693531", + "organization": "018a92f8-afff-0000-efec-ca77de39e384", + "customer": "cus_OdSgxxWtHOtq9g", + "instance": "http://localhost:8000" + }, + "has_billing_plan": true, + "customer_deactivated": false, + "current_total_amount_usd": "0.00", + "percentage_usage.product_analytics": 0, + "current_amount_usd.product_analytics": "0.00", + "unit_amount_usd.product_analytics": null, + "usage_limit.product_analytics": null, + "current_usage.product_analytics": 3729, + "projected_usage.product_analytics": 0, + "free_allocation.product_analytics": 0, + "percentage_usage.session_replay": 0, + "current_amount_usd.session_replay": "0.00", + "unit_amount_usd.session_replay": null, + "usage_limit.session_replay": null, + "current_usage.session_replay": 254, + "projected_usage.session_replay": 0, + "free_allocation.session_replay": 0, + "percentage_usage.feature_flags": 0, + "current_amount_usd.feature_flags": "0.00", + "unit_amount_usd.feature_flags": null, + "usage_limit.feature_flags": null, + "current_usage.feature_flags": 0, + "projected_usage.feature_flags": 0, + "free_allocation.feature_flags": 0, + "percentage_usage.integrations": 0, + "current_amount_usd.integrations": null, + "unit_amount_usd.integrations": null, + "usage_limit.integrations": 0, + "current_usage.integrations": 0, + "projected_usage.integrations": 0, + "free_allocation.integrations": 0, + "percentage_usage.platform_and_support": 0, + "current_amount_usd.platform_and_support": null, + "unit_amount_usd.platform_and_support": null, + "usage_limit.platform_and_support": 0, + "current_usage.platform_and_support": 0, + "projected_usage.platform_and_support": 0, + "free_allocation.platform_and_support": 0, + "billing_period_start": "2023-10-14T09:22:33.000Z", + "billing_period_end": "2023-11-14T09:22:33.000Z", + "$referrer": "$direct", + "$referring_domain": "$direct", + "$feature_flag": "product-specific-onboarding", + "$feature_flag_response": true, + "token": "phc_OWGI2wKbfi7rWDZT9wkl8uGcfe0wOGCvflLEZSMiaT0", + "$session_id": "018b4ca0-9686-7b75-ba2e-61e9c0054b65", + "$window_id": "018b4ca0-9686-7b75-ba2e-61ea857e58f0", + "$ip": "127.0.0.1", + "$set": { + "$os": "Mac OS X", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$pathname": "/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$browser_version": 117, + "$referrer": "$direct", + "$referring_domain": "$direct" + }, + "$set_once": { + "$initial_os": "Mac OS X", + "$initial_browser": "Chrome", + "$initial_device_type": "Desktop", + "$initial_current_url": "http://localhost:8000/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$initial_pathname": "/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$initial_browser_version": 117, + "$initial_referrer": "$direct", + "$initial_referring_domain": "$direct" + }, + "$sent_at": "2023-10-20T10:27:57.623000+00:00", + "$geoip_city_name": "Sydney", + "$geoip_country_name": "Australia", + "$geoip_country_code": "AU", + "$geoip_continent_name": "Oceania", + "$geoip_continent_code": "OC", + "$geoip_postal_code": "2000", + "$geoip_latitude": -33.8715, + "$geoip_longitude": 151.2006, + "$geoip_time_zone": "Australia/Sydney", + "$geoip_subdivision_1_code": "NSW", + "$geoip_subdivision_1_name": "New South Wales", + "$plugins_succeeded": ["GeoIP (1)"], + "$plugins_failed": [], + "$plugins_deferred": [], + "$group_3": "018a92f8-b602-0000-75de-4b9073693531", + "$group_2": "018a92f8-afff-0000-efec-ca77de39e384", + "$group_4": "cus_OdSgxxWtHOtq9g", + "$group_1": "http://localhost:8000" + }, + "timestamp": "2023-10-20T10:27:57.094000+00:00", + "uuid": null + }, + { + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "elements": [], + "elements_chain": null, + "event": "$feature_flag_called", + "id": "018b4ca0-a082-7b23-a908-b488abaaa928", + "person": null, + "properties": { + "$os": "Mac OS X", + "$os_version": "10.15.7", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$host": "localhost:8000", + "$pathname": "/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$browser_version": 117, + "$browser_language": "en-GB", + "$screen_height": 982, + "$screen_width": 1512, + "$viewport_height": 859, + "$viewport_width": 1512, + "$lib": "web", + "$lib_version": "1.84.0", + "$insert_id": "81zsk054pmqq1xc0", + "$time": 1697797677.187, + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$device_id": "018a92fd-7b25-7770-a050-577e94fd148c", + "$console_log_recording_enabled_server_side": true, + "$session_recording_recorder_version_server_side": "v2", + "$autocapture_disabled_server_side": false, + "$active_feature_flags": [ + "signup-page-4.0", + "cmd-k-search", + "posthog-3000", + "funnels-cue-opt-out-7301", + "retention-breakdown", + "smoothing-interval", + "billing-limit", + "kafka-inspector", + "historical-exports-v2", + "person-on-events-enabled", + "region-select", + "ingestion-warnings-enabled", + "session-reset-on-load", + "recordings-on-feature-flags", + "auto-rollback-feature-flags", + "onboarding-v2-demo", + "feature-flag-rollout-ux", + "role-based-access", + "query_running_time", + "query-timings", + "recording-debugging", + "enable-prompts", + "feedback-scene", + "early-access-feature", + "early-access-feature-site-button", + "hedgehog-mode-debug", + "auto-redirect", + "session-recording-blob-replay", + "surveys", + "generic-signup-benefits", + "surveys-positions", + "web-analytics", + "high-frequency-batch-exports", + "exception-autocapture", + "data-warehouse", + "data-warehouse-views", + "ff-dashboard-templates", + "show-product-intro-existing-products", + "artificial-hog", + "cs-dashboards", + "product-specific-onboarding", + "redirect-signups-to-instance", + "apps-and-exports-ui", + "survey-nps-results", + "session-recording-allow-v1-snapshots", + "session-replay-cors-proxy", + "webhooks-denylist", + "surveys-site-app-deprecation", + "surveys-multiple-questions", + "surveys-results-visualizations", + "console-recording-search", + "persons-hogql-query", + "notebooks" + ], + "$feature/file-previews": false, + "$feature/signup-page-4.0": "control", + "$feature/hogql-insights": false, + "$feature/cmd-k-search": true, + "$feature/posthog-3000": true, + "$feature/funnels-cue-opt-out-7301": true, + "$feature/retention-breakdown": true, + "$feature/smoothing-interval": true, + "$feature/billing-limit": true, + "$feature/kafka-inspector": true, + "$feature/historical-exports-v2": true, + "$feature/person-on-events-enabled": true, + "$feature/region-select": true, + "$feature/ingestion-warnings-enabled": true, + "$feature/session-reset-on-load": true, + "$feature/recordings-on-feature-flags": true, + "$feature/auto-rollback-feature-flags": true, + "$feature/onboarding-v2-demo": true, + "$feature/feature-flag-rollout-ux": true, + "$feature/role-based-access": true, + "$feature/query_running_time": true, + "$feature/query-timings": true, + "$feature/recording-debugging": true, + "$feature/enable-prompts": true, + "$feature/feedback-scene": true, + "$feature/early-access-feature": true, + "$feature/early-access-feature-site-button": true, + "$feature/hedgehog-mode-debug": true, + "$feature/auto-redirect": true, + "$feature/session-recording-blob-replay": true, + "$feature/surveys": true, + "$feature/generic-signup-benefits": true, + "$feature/surveys-positions": true, + "$feature/web-analytics": true, + "$feature/high-frequency-batch-exports": true, + "$feature/exception-autocapture": true, + "$feature/data-warehouse": true, + "$feature/data-warehouse-views": true, + "$feature/ff-dashboard-templates": true, + "$feature/show-product-intro-existing-products": true, + "$feature/artificial-hog": true, + "$feature/cs-dashboards": true, + "$feature/product-specific-onboarding": true, + "$feature/redirect-signups-to-instance": true, + "$feature/apps-and-exports-ui": true, + "$feature/survey-nps-results": true, + "$feature/session-recording-allow-v1-snapshots": true, + "$feature/session-replay-cors-proxy": true, + "$feature/webhooks-denylist": true, + "$feature/surveys-site-app-deprecation": true, + "$feature/surveys-multiple-questions": true, + "$feature/surveys-results-visualizations": true, + "$feature/console-recording-search": true, + "$feature/persons-hogql-query": true, + "$feature/notebooks": true, + "$feature_flag_payloads": {}, + "realm": "hosted-clickhouse", + "email_service_available": false, + "slack_service_available": false, + "$user_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "is_demo_project": false, + "$groups": { + "project": "018a92f8-b602-0000-75de-4b9073693531", + "organization": "018a92f8-afff-0000-efec-ca77de39e384", + "customer": "cus_OdSgxxWtHOtq9g", + "instance": "http://localhost:8000" + }, + "has_billing_plan": true, + "customer_deactivated": false, + "current_total_amount_usd": "0.00", + "percentage_usage.product_analytics": 0, + "current_amount_usd.product_analytics": "0.00", + "unit_amount_usd.product_analytics": null, + "usage_limit.product_analytics": null, + "current_usage.product_analytics": 3729, + "projected_usage.product_analytics": 0, + "free_allocation.product_analytics": 0, + "percentage_usage.session_replay": 0, + "current_amount_usd.session_replay": "0.00", + "unit_amount_usd.session_replay": null, + "usage_limit.session_replay": null, + "current_usage.session_replay": 254, + "projected_usage.session_replay": 0, + "free_allocation.session_replay": 0, + "percentage_usage.feature_flags": 0, + "current_amount_usd.feature_flags": "0.00", + "unit_amount_usd.feature_flags": null, + "usage_limit.feature_flags": null, + "current_usage.feature_flags": 0, + "projected_usage.feature_flags": 0, + "free_allocation.feature_flags": 0, + "percentage_usage.integrations": 0, + "current_amount_usd.integrations": null, + "unit_amount_usd.integrations": null, + "usage_limit.integrations": 0, + "current_usage.integrations": 0, + "projected_usage.integrations": 0, + "free_allocation.integrations": 0, + "percentage_usage.platform_and_support": 0, + "current_amount_usd.platform_and_support": null, + "unit_amount_usd.platform_and_support": null, + "usage_limit.platform_and_support": 0, + "current_usage.platform_and_support": 0, + "projected_usage.platform_and_support": 0, + "free_allocation.platform_and_support": 0, + "billing_period_start": "2023-10-14T09:22:33.000Z", + "billing_period_end": "2023-11-14T09:22:33.000Z", + "$referrer": "$direct", + "$referring_domain": "$direct", + "$feature_flag": "cs-dashboards", + "$feature_flag_response": true, + "token": "phc_OWGI2wKbfi7rWDZT9wkl8uGcfe0wOGCvflLEZSMiaT0", + "$session_id": "018b4ca0-9686-7b75-ba2e-61e9c0054b65", + "$window_id": "018b4ca0-9686-7b75-ba2e-61ea857e58f0", + "$ip": "127.0.0.1", + "$set": { + "$os": "Mac OS X", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$pathname": "/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$browser_version": 117, + "$referrer": "$direct", + "$referring_domain": "$direct" + }, + "$set_once": { + "$initial_os": "Mac OS X", + "$initial_browser": "Chrome", + "$initial_device_type": "Desktop", + "$initial_current_url": "http://localhost:8000/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$initial_pathname": "/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$initial_browser_version": 117, + "$initial_referrer": "$direct", + "$initial_referring_domain": "$direct" + }, + "$sent_at": "2023-10-20T10:27:57.623000+00:00", + "$geoip_city_name": "Sydney", + "$geoip_country_name": "Australia", + "$geoip_country_code": "AU", + "$geoip_continent_name": "Oceania", + "$geoip_continent_code": "OC", + "$geoip_postal_code": "2000", + "$geoip_latitude": -33.8715, + "$geoip_longitude": 151.2006, + "$geoip_time_zone": "Australia/Sydney", + "$geoip_subdivision_1_code": "NSW", + "$geoip_subdivision_1_name": "New South Wales", + "$plugins_succeeded": ["GeoIP (1)"], + "$plugins_failed": [], + "$plugins_deferred": [], + "$group_3": "018a92f8-b602-0000-75de-4b9073693531", + "$group_2": "018a92f8-afff-0000-efec-ca77de39e384", + "$group_4": "cus_OdSgxxWtHOtq9g", + "$group_1": "http://localhost:8000" + }, + "timestamp": "2023-10-20T10:27:57.196000+00:00", + "uuid": null + }, + { + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "elements": [], + "elements_chain": null, + "event": "$pageview", + "id": "018b4ca0-a11d-73af-85b8-ed8d0af6f60c", + "person": null, + "properties": { + "$os": "Mac OS X", + "$os_version": "10.15.7", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$host": "localhost:8000", + "$pathname": "/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$browser_version": 117, + "$browser_language": "en-GB", + "$screen_height": 982, + "$screen_width": 1512, + "$viewport_height": 859, + "$viewport_width": 1512, + "$lib": "web", + "$lib_version": "1.84.0", + "$insert_id": "h057ocr0sxdig2et", + "$time": 1697797677.342, + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$device_id": "018a92fd-7b25-7770-a050-577e94fd148c", + "$console_log_recording_enabled_server_side": true, + "$session_recording_recorder_version_server_side": "v2", + "$autocapture_disabled_server_side": false, + "$active_feature_flags": [ + "signup-page-4.0", + "cmd-k-search", + "posthog-3000", + "funnels-cue-opt-out-7301", + "retention-breakdown", + "smoothing-interval", + "billing-limit", + "kafka-inspector", + "historical-exports-v2", + "person-on-events-enabled", + "region-select", + "ingestion-warnings-enabled", + "session-reset-on-load", + "recordings-on-feature-flags", + "auto-rollback-feature-flags", + "onboarding-v2-demo", + "feature-flag-rollout-ux", + "role-based-access", + "query_running_time", + "query-timings", + "recording-debugging", + "enable-prompts", + "feedback-scene", + "early-access-feature", + "early-access-feature-site-button", + "hedgehog-mode-debug", + "auto-redirect", + "session-recording-blob-replay", + "surveys", + "generic-signup-benefits", + "surveys-positions", + "web-analytics", + "high-frequency-batch-exports", + "exception-autocapture", + "data-warehouse", + "data-warehouse-views", + "ff-dashboard-templates", + "show-product-intro-existing-products", + "artificial-hog", + "cs-dashboards", + "product-specific-onboarding", + "redirect-signups-to-instance", + "apps-and-exports-ui", + "survey-nps-results", + "session-recording-allow-v1-snapshots", + "session-replay-cors-proxy", + "webhooks-denylist", + "surveys-site-app-deprecation", + "surveys-multiple-questions", + "surveys-results-visualizations", + "console-recording-search", + "persons-hogql-query", + "notebooks" + ], + "$feature/file-previews": false, + "$feature/signup-page-4.0": "control", + "$feature/hogql-insights": false, + "$feature/cmd-k-search": true, + "$feature/posthog-3000": true, + "$feature/funnels-cue-opt-out-7301": true, + "$feature/retention-breakdown": true, + "$feature/smoothing-interval": true, + "$feature/billing-limit": true, + "$feature/kafka-inspector": true, + "$feature/historical-exports-v2": true, + "$feature/person-on-events-enabled": true, + "$feature/region-select": true, + "$feature/ingestion-warnings-enabled": true, + "$feature/session-reset-on-load": true, + "$feature/recordings-on-feature-flags": true, + "$feature/auto-rollback-feature-flags": true, + "$feature/onboarding-v2-demo": true, + "$feature/feature-flag-rollout-ux": true, + "$feature/role-based-access": true, + "$feature/query_running_time": true, + "$feature/query-timings": true, + "$feature/recording-debugging": true, + "$feature/enable-prompts": true, + "$feature/feedback-scene": true, + "$feature/early-access-feature": true, + "$feature/early-access-feature-site-button": true, + "$feature/hedgehog-mode-debug": true, + "$feature/auto-redirect": true, + "$feature/session-recording-blob-replay": true, + "$feature/surveys": true, + "$feature/generic-signup-benefits": true, + "$feature/surveys-positions": true, + "$feature/web-analytics": true, + "$feature/high-frequency-batch-exports": true, + "$feature/exception-autocapture": true, + "$feature/data-warehouse": true, + "$feature/data-warehouse-views": true, + "$feature/ff-dashboard-templates": true, + "$feature/show-product-intro-existing-products": true, + "$feature/artificial-hog": true, + "$feature/cs-dashboards": true, + "$feature/product-specific-onboarding": true, + "$feature/redirect-signups-to-instance": true, + "$feature/apps-and-exports-ui": true, + "$feature/survey-nps-results": true, + "$feature/session-recording-allow-v1-snapshots": true, + "$feature/session-replay-cors-proxy": true, + "$feature/webhooks-denylist": true, + "$feature/surveys-site-app-deprecation": true, + "$feature/surveys-multiple-questions": true, + "$feature/surveys-results-visualizations": true, + "$feature/console-recording-search": true, + "$feature/persons-hogql-query": true, + "$feature/notebooks": true, + "$feature_flag_payloads": {}, + "realm": "hosted-clickhouse", + "email_service_available": false, + "slack_service_available": false, + "$user_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "is_demo_project": false, + "$groups": { + "project": "018a92f8-b602-0000-75de-4b9073693531", + "organization": "018a92f8-afff-0000-efec-ca77de39e384", + "customer": "cus_OdSgxxWtHOtq9g", + "instance": "http://localhost:8000" + }, + "has_billing_plan": true, + "customer_deactivated": false, + "current_total_amount_usd": "0.00", + "percentage_usage.product_analytics": 0, + "current_amount_usd.product_analytics": "0.00", + "unit_amount_usd.product_analytics": null, + "usage_limit.product_analytics": null, + "current_usage.product_analytics": 3729, + "projected_usage.product_analytics": 0, + "free_allocation.product_analytics": 0, + "percentage_usage.session_replay": 0, + "current_amount_usd.session_replay": "0.00", + "unit_amount_usd.session_replay": null, + "usage_limit.session_replay": null, + "current_usage.session_replay": 254, + "projected_usage.session_replay": 0, + "free_allocation.session_replay": 0, + "percentage_usage.feature_flags": 0, + "current_amount_usd.feature_flags": "0.00", + "unit_amount_usd.feature_flags": null, + "usage_limit.feature_flags": null, + "current_usage.feature_flags": 0, + "projected_usage.feature_flags": 0, + "free_allocation.feature_flags": 0, + "percentage_usage.integrations": 0, + "current_amount_usd.integrations": null, + "unit_amount_usd.integrations": null, + "usage_limit.integrations": 0, + "current_usage.integrations": 0, + "projected_usage.integrations": 0, + "free_allocation.integrations": 0, + "percentage_usage.platform_and_support": 0, + "current_amount_usd.platform_and_support": null, + "unit_amount_usd.platform_and_support": null, + "usage_limit.platform_and_support": 0, + "current_usage.platform_and_support": 0, + "projected_usage.platform_and_support": 0, + "free_allocation.platform_and_support": 0, + "billing_period_start": "2023-10-14T09:22:33.000Z", + "billing_period_end": "2023-11-14T09:22:33.000Z", + "$referrer": "$direct", + "$referring_domain": "$direct", + "token": "phc_OWGI2wKbfi7rWDZT9wkl8uGcfe0wOGCvflLEZSMiaT0", + "$session_id": "018b4ca0-9686-7b75-ba2e-61e9c0054b65", + "$window_id": "018b4ca0-9686-7b75-ba2e-61ea857e58f0", + "title": "Persons \u2022 PostHog", + "$ip": "127.0.0.1", + "$set": { + "$os": "Mac OS X", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$pathname": "/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$browser_version": 117, + "$referrer": "$direct", + "$referring_domain": "$direct" + }, + "$set_once": { + "$initial_os": "Mac OS X", + "$initial_browser": "Chrome", + "$initial_device_type": "Desktop", + "$initial_current_url": "http://localhost:8000/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$initial_pathname": "/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$initial_browser_version": 117, + "$initial_referrer": "$direct", + "$initial_referring_domain": "$direct" + }, + "$sent_at": "2023-10-20T10:27:57.623000+00:00", + "$geoip_city_name": "Sydney", + "$geoip_country_name": "Australia", + "$geoip_country_code": "AU", + "$geoip_continent_name": "Oceania", + "$geoip_continent_code": "OC", + "$geoip_postal_code": "2000", + "$geoip_latitude": -33.8715, + "$geoip_longitude": 151.2006, + "$geoip_time_zone": "Australia/Sydney", + "$geoip_subdivision_1_code": "NSW", + "$geoip_subdivision_1_name": "New South Wales", + "$plugins_succeeded": ["GeoIP (1)"], + "$plugins_failed": [], + "$plugins_deferred": [], + "$group_3": "018a92f8-b602-0000-75de-4b9073693531", + "$group_2": "018a92f8-afff-0000-efec-ca77de39e384", + "$group_4": "cus_OdSgxxWtHOtq9g", + "$group_1": "http://localhost:8000" + }, + "timestamp": "2023-10-20T10:27:57.351000+00:00", + "uuid": null + }, + { + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "elements": [ + { + "attr_class": null, + "attr_id": null, + "attributes": { + "attr__href": "/person/bbf314c9-0877-450e-793a-f33cf151dd96" + }, + "href": "/person/bbf314c9-0877-450e-793a-f33cf151dd96", + "nth_child": 1.0, + "nth_of_type": 1.0, + "order": 0.0, + "tag_name": "h5", + "text": "bbf314c9-0877-450e-793a-f33cf151dd96" + }, + { + "attr_class": ["Link", "SidebarListItem__link"], + "attr_id": null, + "attributes": { + "attr__class": "Link SidebarListItem__link", + "attr__draggable": "true", + "attr__href": "/person/bbf314c9-0877-450e-793a-f33cf151dd96" + }, + "href": "/person/bbf314c9-0877-450e-793a-f33cf151dd96", + "nth_child": 1.0, + "nth_of_type": 1.0, + "order": 1.0, + "tag_name": "a", + "text": null + }, + { + "attr_class": ["SidebarListItem"], + "attr_id": "sidebar-bbf314c9-0877-450e-793a-f33cf151dd96", + "attributes": { + "attr__aria-disabled": "false", + "attr__aria-invalid": "false", + "attr__class": "SidebarListItem", + "attr__id": "sidebar-bbf314c9-0877-450e-793a-f33cf151dd96", + "attr__style": "height: 32px; left: 0px; position: absolute; top: 96px; width: 100%;", + "attr__title": "bbf314c9-0877-450e-793a-f33cf151dd96" + }, + "href": null, + "nth_child": 4.0, + "nth_of_type": 4.0, + "order": 2.0, + "tag_name": "li", + "text": null + }, + { + "attr_class": ["ReactVirtualized__Grid__innerScrollContainer"], + "attr_id": null, + "attributes": { + "attr__class": "ReactVirtualized__Grid__innerScrollContainer", + "attr__role": "rowgroup", + "attr__style": "width: auto; height: 95872px; max-width: 250px; max-height: 95872px; overflow: hidden; position: relative;" + }, + "href": null, + "nth_child": 1.0, + "nth_of_type": 1.0, + "order": 3.0, + "tag_name": "div", + "text": null + }, + { + "attr_class": ["ReactVirtualized__Grid", "ReactVirtualized__List", "SidebarList"], + "attr_id": null, + "attributes": { + "attr__aria-label": "grid", + "attr__aria-readonly": "true", + "attr__class": "ReactVirtualized__Grid ReactVirtualized__List SidebarList", + "attr__role": "grid", + "attr__style": "box-sizing: border-box; direction: ltr; height: 312px; position: relative; width: 250px; will-change: transform; overflow: hidden auto;" + }, + "href": null, + "nth_child": 1.0, + "nth_of_type": 1.0, + "order": 4.0, + "tag_name": "div", + "text": null + }, + { + "attr_class": null, + "attr_id": null, + "attributes": { + "attr__style": "overflow: visible; height: 0px;" + }, + "href": null, + "nth_child": 1.0, + "nth_of_type": 1.0, + "order": 5.0, + "tag_name": "div", + "text": null + }, + { + "attr_class": ["flex-1"], + "attr_id": null, + "attributes": { + "attr__class": "flex-1", + "attr__style": "position: relative;" + }, + "href": null, + "nth_child": 2.0, + "nth_of_type": 2.0, + "order": 6.0, + "tag_name": "div", + "text": null + }, + { + "attr_class": ["Accordion"], + "attr_id": null, + "attributes": { + "attr__aria-busy": "false", + "attr__aria-disabled": "false", + "attr__aria-expanded": "true", + "attr__class": "Accordion" + }, + "href": null, + "nth_child": 1.0, + "nth_of_type": 1.0, + "order": 7.0, + "tag_name": "section", + "text": null + }, + { + "attr_class": ["Sidebar3000__lists"], + "attr_id": null, + "attributes": { + "attr__class": "Sidebar3000__lists" + }, + "href": null, + "nth_child": 2.0, + "nth_of_type": 2.0, + "order": 8.0, + "tag_name": "div", + "text": null + }, + { + "attr_class": ["Sidebar3000__content"], + "attr_id": null, + "attributes": { + "attr__class": "Sidebar3000__content" + }, + "href": null, + "nth_child": 1.0, + "nth_of_type": 1.0, + "order": 9.0, + "tag_name": "div", + "text": null + }, + { + "attr_class": ["Sidebar3000"], + "attr_id": null, + "attributes": { + "attr__aria-hidden": "false", + "attr__class": "Sidebar3000", + "attr__style": "--sidebar-width: 250px;" + }, + "href": null, + "nth_child": 2.0, + "nth_of_type": 1.0, + "order": 10.0, + "tag_name": "div", + "text": null + }, + { + "attr_class": ["Navigation3000"], + "attr_id": null, + "attributes": { + "attr__class": "Navigation3000" + }, + "href": null, + "nth_child": 1.0, + "nth_of_type": 1.0, + "order": 11.0, + "tag_name": "div", + "text": null + }, + { + "attr_class": null, + "attr_id": "root", + "attributes": { + "attr__id": "root" + }, + "href": null, + "nth_child": 4.0, + "nth_of_type": 1.0, + "order": 12.0, + "tag_name": "div", + "text": null + }, + { + "attr_class": ["posthog-3000"], + "attr_id": null, + "attributes": { + "attr__class": "posthog-3000", + "attr__theme": "light" + }, + "href": null, + "nth_child": 2.0, + "nth_of_type": 1.0, + "order": 13.0, + "tag_name": "body", + "text": null + } + ], + "elements_chain": "h5:attr__href=\"/person/bbf314c9-0877-450e-793a-f33cf151dd96\"href=\"/person/bbf314c9-0877-450e-793a-f33cf151dd96\"nth-child=\"1\"nth-of-type=\"1\"text=\"bbf314c9-0877-450e-793a-f33cf151dd96\";a.Link.SidebarListItem__link:attr__class=\"Link SidebarListItem__link\"attr__draggable=\"true\"attr__href=\"/person/bbf314c9-0877-450e-793a-f33cf151dd96\"href=\"/person/bbf314c9-0877-450e-793a-f33cf151dd96\"nth-child=\"1\"nth-of-type=\"1\";li.SidebarListItem:attr__aria-disabled=\"false\"attr__aria-invalid=\"false\"attr__class=\"SidebarListItem\"attr__id=\"sidebar-bbf314c9-0877-450e-793a-f33cf151dd96\"attr__style=\"height: 32px; left: 0px; position: absolute; top: 96px; width: 100%;\"attr__title=\"bbf314c9-0877-450e-793a-f33cf151dd96\"attr_id=\"sidebar-bbf314c9-0877-450e-793a-f33cf151dd96\"nth-child=\"4\"nth-of-type=\"4\";div.ReactVirtualized__Grid__innerScrollContainer:attr__class=\"ReactVirtualized__Grid__innerScrollContainer\"attr__role=\"rowgroup\"attr__style=\"width: auto; height: 95872px; max-width: 250px; max-height: 95872px; overflow: hidden; position: relative;\"nth-child=\"1\"nth-of-type=\"1\";div.ReactVirtualized__Grid.ReactVirtualized__List.SidebarList:attr__aria-label=\"grid\"attr__aria-readonly=\"true\"attr__class=\"ReactVirtualized__Grid ReactVirtualized__List SidebarList\"attr__role=\"grid\"attr__style=\"box-sizing: border-box; direction: ltr; height: 312px; position: relative; width: 250px; will-change: transform; overflow: hidden auto;\"nth-child=\"1\"nth-of-type=\"1\";div:attr__style=\"overflow: visible; height: 0px;\"nth-child=\"1\"nth-of-type=\"1\";div.flex-1:attr__class=\"flex-1\"attr__style=\"position: relative;\"nth-child=\"2\"nth-of-type=\"2\";section.Accordion:attr__aria-busy=\"false\"attr__aria-disabled=\"false\"attr__aria-expanded=\"true\"attr__class=\"Accordion\"nth-child=\"1\"nth-of-type=\"1\";div.Sidebar3000__lists:attr__class=\"Sidebar3000__lists\"nth-child=\"2\"nth-of-type=\"2\";div.Sidebar3000__content:attr__class=\"Sidebar3000__content\"nth-child=\"1\"nth-of-type=\"1\";div.Sidebar3000:attr__aria-hidden=\"false\"attr__class=\"Sidebar3000\"attr__style=\"--sidebar-width: 250px;\"nth-child=\"2\"nth-of-type=\"1\";div.Navigation3000:attr__class=\"Navigation3000\"nth-child=\"1\"nth-of-type=\"1\";div:attr__id=\"root\"attr_id=\"root\"nth-child=\"4\"nth-of-type=\"1\";body.posthog-3000:attr__class=\"posthog-3000\"attr__theme=\"light\"nth-child=\"2\"nth-of-type=\"1\"", + "event": "$autocapture", + "id": "018b4ca0-a7ad-7c7c-95c6-394a4fe1e057", + "person": null, + "properties": { + "$os": "Mac OS X", + "$os_version": "10.15.7", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$host": "localhost:8000", + "$pathname": "/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$browser_version": 117, + "$browser_language": "en-GB", + "$screen_height": 982, + "$screen_width": 1512, + "$viewport_height": 859, + "$viewport_width": 1512, + "$lib": "web", + "$lib_version": "1.84.0", + "$insert_id": "78a5df8y7e77s5ak", + "$time": 1697797679.022, + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$device_id": "018a92fd-7b25-7770-a050-577e94fd148c", + "$console_log_recording_enabled_server_side": true, + "$session_recording_recorder_version_server_side": "v2", + "$autocapture_disabled_server_side": false, + "$active_feature_flags": [ + "signup-page-4.0", + "cmd-k-search", + "posthog-3000", + "funnels-cue-opt-out-7301", + "retention-breakdown", + "smoothing-interval", + "billing-limit", + "kafka-inspector", + "historical-exports-v2", + "person-on-events-enabled", + "region-select", + "ingestion-warnings-enabled", + "session-reset-on-load", + "recordings-on-feature-flags", + "auto-rollback-feature-flags", + "onboarding-v2-demo", + "feature-flag-rollout-ux", + "role-based-access", + "query_running_time", + "query-timings", + "recording-debugging", + "enable-prompts", + "feedback-scene", + "early-access-feature", + "early-access-feature-site-button", + "hedgehog-mode-debug", + "auto-redirect", + "session-recording-blob-replay", + "surveys", + "generic-signup-benefits", + "surveys-positions", + "web-analytics", + "high-frequency-batch-exports", + "exception-autocapture", + "data-warehouse", + "data-warehouse-views", + "ff-dashboard-templates", + "show-product-intro-existing-products", + "artificial-hog", + "cs-dashboards", + "product-specific-onboarding", + "redirect-signups-to-instance", + "apps-and-exports-ui", + "survey-nps-results", + "session-recording-allow-v1-snapshots", + "session-replay-cors-proxy", + "webhooks-denylist", + "surveys-site-app-deprecation", + "surveys-multiple-questions", + "surveys-results-visualizations", + "console-recording-search", + "persons-hogql-query", + "notebooks" + ], + "$feature/file-previews": false, + "$feature/signup-page-4.0": "control", + "$feature/hogql-insights": false, + "$feature/cmd-k-search": true, + "$feature/posthog-3000": true, + "$feature/funnels-cue-opt-out-7301": true, + "$feature/retention-breakdown": true, + "$feature/smoothing-interval": true, + "$feature/billing-limit": true, + "$feature/kafka-inspector": true, + "$feature/historical-exports-v2": true, + "$feature/person-on-events-enabled": true, + "$feature/region-select": true, + "$feature/ingestion-warnings-enabled": true, + "$feature/session-reset-on-load": true, + "$feature/recordings-on-feature-flags": true, + "$feature/auto-rollback-feature-flags": true, + "$feature/onboarding-v2-demo": true, + "$feature/feature-flag-rollout-ux": true, + "$feature/role-based-access": true, + "$feature/query_running_time": true, + "$feature/query-timings": true, + "$feature/recording-debugging": true, + "$feature/enable-prompts": true, + "$feature/feedback-scene": true, + "$feature/early-access-feature": true, + "$feature/early-access-feature-site-button": true, + "$feature/hedgehog-mode-debug": true, + "$feature/auto-redirect": true, + "$feature/session-recording-blob-replay": true, + "$feature/surveys": true, + "$feature/generic-signup-benefits": true, + "$feature/surveys-positions": true, + "$feature/web-analytics": true, + "$feature/high-frequency-batch-exports": true, + "$feature/exception-autocapture": true, + "$feature/data-warehouse": true, + "$feature/data-warehouse-views": true, + "$feature/ff-dashboard-templates": true, + "$feature/show-product-intro-existing-products": true, + "$feature/artificial-hog": true, + "$feature/cs-dashboards": true, + "$feature/product-specific-onboarding": true, + "$feature/redirect-signups-to-instance": true, + "$feature/apps-and-exports-ui": true, + "$feature/survey-nps-results": true, + "$feature/session-recording-allow-v1-snapshots": true, + "$feature/session-replay-cors-proxy": true, + "$feature/webhooks-denylist": true, + "$feature/surveys-site-app-deprecation": true, + "$feature/surveys-multiple-questions": true, + "$feature/surveys-results-visualizations": true, + "$feature/console-recording-search": true, + "$feature/persons-hogql-query": true, + "$feature/notebooks": true, + "$feature_flag_payloads": {}, + "realm": "hosted-clickhouse", + "email_service_available": false, + "slack_service_available": false, + "$user_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "is_demo_project": false, + "$groups": { + "project": "018a92f8-b602-0000-75de-4b9073693531", + "organization": "018a92f8-afff-0000-efec-ca77de39e384", + "customer": "cus_OdSgxxWtHOtq9g", + "instance": "http://localhost:8000" + }, + "has_billing_plan": true, + "customer_deactivated": false, + "current_total_amount_usd": "0.00", + "percentage_usage.product_analytics": 0, + "current_amount_usd.product_analytics": "0.00", + "unit_amount_usd.product_analytics": null, + "usage_limit.product_analytics": null, + "current_usage.product_analytics": 3729, + "projected_usage.product_analytics": 0, + "free_allocation.product_analytics": 0, + "percentage_usage.session_replay": 0, + "current_amount_usd.session_replay": "0.00", + "unit_amount_usd.session_replay": null, + "usage_limit.session_replay": null, + "current_usage.session_replay": 254, + "projected_usage.session_replay": 0, + "free_allocation.session_replay": 0, + "percentage_usage.feature_flags": 0, + "current_amount_usd.feature_flags": "0.00", + "unit_amount_usd.feature_flags": null, + "usage_limit.feature_flags": null, + "current_usage.feature_flags": 0, + "projected_usage.feature_flags": 0, + "free_allocation.feature_flags": 0, + "percentage_usage.integrations": 0, + "current_amount_usd.integrations": null, + "unit_amount_usd.integrations": null, + "usage_limit.integrations": 0, + "current_usage.integrations": 0, + "projected_usage.integrations": 0, + "free_allocation.integrations": 0, + "percentage_usage.platform_and_support": 0, + "current_amount_usd.platform_and_support": null, + "unit_amount_usd.platform_and_support": null, + "usage_limit.platform_and_support": 0, + "current_usage.platform_and_support": 0, + "projected_usage.platform_and_support": 0, + "free_allocation.platform_and_support": 0, + "billing_period_start": "2023-10-14T09:22:33.000Z", + "billing_period_end": "2023-11-14T09:22:33.000Z", + "$referrer": "$direct", + "$referring_domain": "$direct", + "$event_type": "click", + "$ce_version": 1, + "$el_text": "bbf314c9-0877-450e-793a-f33cf151dd96", + "token": "phc_OWGI2wKbfi7rWDZT9wkl8uGcfe0wOGCvflLEZSMiaT0", + "$session_id": "018b4ca0-9686-7b75-ba2e-61e9c0054b65", + "$window_id": "018b4ca0-9686-7b75-ba2e-61ea857e58f0", + "$ip": "127.0.0.1", + "$set": { + "$os": "Mac OS X", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$pathname": "/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$browser_version": 117, + "$referrer": "$direct", + "$referring_domain": "$direct" + }, + "$set_once": { + "$initial_os": "Mac OS X", + "$initial_browser": "Chrome", + "$initial_device_type": "Desktop", + "$initial_current_url": "http://localhost:8000/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$initial_pathname": "/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$initial_browser_version": 117, + "$initial_referrer": "$direct", + "$initial_referring_domain": "$direct" + }, + "$sent_at": "2023-10-20T10:28:00.793000+00:00", + "$geoip_city_name": "Sydney", + "$geoip_country_name": "Australia", + "$geoip_country_code": "AU", + "$geoip_continent_name": "Oceania", + "$geoip_continent_code": "OC", + "$geoip_postal_code": "2000", + "$geoip_latitude": -33.8715, + "$geoip_longitude": 151.2006, + "$geoip_time_zone": "Australia/Sydney", + "$geoip_subdivision_1_code": "NSW", + "$geoip_subdivision_1_name": "New South Wales", + "$plugins_succeeded": ["GeoIP (1)"], + "$plugins_failed": [], + "$plugins_deferred": [], + "$group_3": "018a92f8-b602-0000-75de-4b9073693531", + "$group_2": "018a92f8-afff-0000-efec-ca77de39e384", + "$group_4": "cus_OdSgxxWtHOtq9g", + "$group_1": "http://localhost:8000" + }, + "timestamp": "2023-10-20T10:27:59.029000+00:00", + "uuid": null + }, + { + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "elements": [], + "elements_chain": null, + "event": "$pageview", + "id": "018b4ca0-a7b3-73e0-9616-9a41d3b9f6ec", + "person": null, + "properties": { + "$os": "Mac OS X", + "$os_version": "10.15.7", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/person/bbf314c9-0877-450e-793a-f33cf151dd96", + "$host": "localhost:8000", + "$pathname": "/person/bbf314c9-0877-450e-793a-f33cf151dd96", + "$browser_version": 117, + "$browser_language": "en-GB", + "$screen_height": 982, + "$screen_width": 1512, + "$viewport_height": 859, + "$viewport_width": 1512, + "$lib": "web", + "$lib_version": "1.84.0", + "$insert_id": "xzd3u2auqqufn8xp", + "$time": 1697797679.027, + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$device_id": "018a92fd-7b25-7770-a050-577e94fd148c", + "$console_log_recording_enabled_server_side": true, + "$session_recording_recorder_version_server_side": "v2", + "$autocapture_disabled_server_side": false, + "$active_feature_flags": [ + "signup-page-4.0", + "cmd-k-search", + "posthog-3000", + "funnels-cue-opt-out-7301", + "retention-breakdown", + "smoothing-interval", + "billing-limit", + "kafka-inspector", + "historical-exports-v2", + "person-on-events-enabled", + "region-select", + "ingestion-warnings-enabled", + "session-reset-on-load", + "recordings-on-feature-flags", + "auto-rollback-feature-flags", + "onboarding-v2-demo", + "feature-flag-rollout-ux", + "role-based-access", + "query_running_time", + "query-timings", + "recording-debugging", + "enable-prompts", + "feedback-scene", + "early-access-feature", + "early-access-feature-site-button", + "hedgehog-mode-debug", + "auto-redirect", + "session-recording-blob-replay", + "surveys", + "generic-signup-benefits", + "surveys-positions", + "web-analytics", + "high-frequency-batch-exports", + "exception-autocapture", + "data-warehouse", + "data-warehouse-views", + "ff-dashboard-templates", + "show-product-intro-existing-products", + "artificial-hog", + "cs-dashboards", + "product-specific-onboarding", + "redirect-signups-to-instance", + "apps-and-exports-ui", + "survey-nps-results", + "session-recording-allow-v1-snapshots", + "session-replay-cors-proxy", + "webhooks-denylist", + "surveys-site-app-deprecation", + "surveys-multiple-questions", + "surveys-results-visualizations", + "console-recording-search", + "persons-hogql-query", + "notebooks" + ], + "$feature/file-previews": false, + "$feature/signup-page-4.0": "control", + "$feature/hogql-insights": false, + "$feature/cmd-k-search": true, + "$feature/posthog-3000": true, + "$feature/funnels-cue-opt-out-7301": true, + "$feature/retention-breakdown": true, + "$feature/smoothing-interval": true, + "$feature/billing-limit": true, + "$feature/kafka-inspector": true, + "$feature/historical-exports-v2": true, + "$feature/person-on-events-enabled": true, + "$feature/region-select": true, + "$feature/ingestion-warnings-enabled": true, + "$feature/session-reset-on-load": true, + "$feature/recordings-on-feature-flags": true, + "$feature/auto-rollback-feature-flags": true, + "$feature/onboarding-v2-demo": true, + "$feature/feature-flag-rollout-ux": true, + "$feature/role-based-access": true, + "$feature/query_running_time": true, + "$feature/query-timings": true, + "$feature/recording-debugging": true, + "$feature/enable-prompts": true, + "$feature/feedback-scene": true, + "$feature/early-access-feature": true, + "$feature/early-access-feature-site-button": true, + "$feature/hedgehog-mode-debug": true, + "$feature/auto-redirect": true, + "$feature/session-recording-blob-replay": true, + "$feature/surveys": true, + "$feature/generic-signup-benefits": true, + "$feature/surveys-positions": true, + "$feature/web-analytics": true, + "$feature/high-frequency-batch-exports": true, + "$feature/exception-autocapture": true, + "$feature/data-warehouse": true, + "$feature/data-warehouse-views": true, + "$feature/ff-dashboard-templates": true, + "$feature/show-product-intro-existing-products": true, + "$feature/artificial-hog": true, + "$feature/cs-dashboards": true, + "$feature/product-specific-onboarding": true, + "$feature/redirect-signups-to-instance": true, + "$feature/apps-and-exports-ui": true, + "$feature/survey-nps-results": true, + "$feature/session-recording-allow-v1-snapshots": true, + "$feature/session-replay-cors-proxy": true, + "$feature/webhooks-denylist": true, + "$feature/surveys-site-app-deprecation": true, + "$feature/surveys-multiple-questions": true, + "$feature/surveys-results-visualizations": true, + "$feature/console-recording-search": true, + "$feature/persons-hogql-query": true, + "$feature/notebooks": true, + "$feature_flag_payloads": {}, + "realm": "hosted-clickhouse", + "email_service_available": false, + "slack_service_available": false, + "$user_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "is_demo_project": false, + "$groups": { + "project": "018a92f8-b602-0000-75de-4b9073693531", + "organization": "018a92f8-afff-0000-efec-ca77de39e384", + "customer": "cus_OdSgxxWtHOtq9g", + "instance": "http://localhost:8000" + }, + "has_billing_plan": true, + "customer_deactivated": false, + "current_total_amount_usd": "0.00", + "percentage_usage.product_analytics": 0, + "current_amount_usd.product_analytics": "0.00", + "unit_amount_usd.product_analytics": null, + "usage_limit.product_analytics": null, + "current_usage.product_analytics": 3729, + "projected_usage.product_analytics": 0, + "free_allocation.product_analytics": 0, + "percentage_usage.session_replay": 0, + "current_amount_usd.session_replay": "0.00", + "unit_amount_usd.session_replay": null, + "usage_limit.session_replay": null, + "current_usage.session_replay": 254, + "projected_usage.session_replay": 0, + "free_allocation.session_replay": 0, + "percentage_usage.feature_flags": 0, + "current_amount_usd.feature_flags": "0.00", + "unit_amount_usd.feature_flags": null, + "usage_limit.feature_flags": null, + "current_usage.feature_flags": 0, + "projected_usage.feature_flags": 0, + "free_allocation.feature_flags": 0, + "percentage_usage.integrations": 0, + "current_amount_usd.integrations": null, + "unit_amount_usd.integrations": null, + "usage_limit.integrations": 0, + "current_usage.integrations": 0, + "projected_usage.integrations": 0, + "free_allocation.integrations": 0, + "percentage_usage.platform_and_support": 0, + "current_amount_usd.platform_and_support": null, + "unit_amount_usd.platform_and_support": null, + "usage_limit.platform_and_support": 0, + "current_usage.platform_and_support": 0, + "projected_usage.platform_and_support": 0, + "free_allocation.platform_and_support": 0, + "billing_period_start": "2023-10-14T09:22:33.000Z", + "billing_period_end": "2023-11-14T09:22:33.000Z", + "$referrer": "$direct", + "$referring_domain": "$direct", + "token": "phc_OWGI2wKbfi7rWDZT9wkl8uGcfe0wOGCvflLEZSMiaT0", + "$session_id": "018b4ca0-9686-7b75-ba2e-61e9c0054b65", + "$window_id": "018b4ca0-9686-7b75-ba2e-61ea857e58f0", + "title": "Persons \u2022 PostHog", + "$ip": "127.0.0.1", + "$set": { + "$os": "Mac OS X", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/person/bbf314c9-0877-450e-793a-f33cf151dd96", + "$pathname": "/person/bbf314c9-0877-450e-793a-f33cf151dd96", + "$browser_version": 117, + "$referrer": "$direct", + "$referring_domain": "$direct" + }, + "$set_once": { + "$initial_os": "Mac OS X", + "$initial_browser": "Chrome", + "$initial_device_type": "Desktop", + "$initial_current_url": "http://localhost:8000/person/bbf314c9-0877-450e-793a-f33cf151dd96", + "$initial_pathname": "/person/bbf314c9-0877-450e-793a-f33cf151dd96", + "$initial_browser_version": 117, + "$initial_referrer": "$direct", + "$initial_referring_domain": "$direct" + }, + "$sent_at": "2023-10-20T10:28:00.793000+00:00", + "$geoip_city_name": "Sydney", + "$geoip_country_name": "Australia", + "$geoip_country_code": "AU", + "$geoip_continent_name": "Oceania", + "$geoip_continent_code": "OC", + "$geoip_postal_code": "2000", + "$geoip_latitude": -33.8715, + "$geoip_longitude": 151.2006, + "$geoip_time_zone": "Australia/Sydney", + "$geoip_subdivision_1_code": "NSW", + "$geoip_subdivision_1_name": "New South Wales", + "$plugins_succeeded": ["GeoIP (1)"], + "$plugins_failed": [], + "$plugins_deferred": [], + "$group_3": "018a92f8-b602-0000-75de-4b9073693531", + "$group_2": "018a92f8-afff-0000-efec-ca77de39e384", + "$group_4": "cus_OdSgxxWtHOtq9g", + "$group_1": "http://localhost:8000" + }, + "timestamp": "2023-10-20T10:27:59.034000+00:00", + "uuid": null + }, + { + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "elements": [], + "elements_chain": null, + "event": "$feature_flag_called", + "id": "018b4ca0-a7b5-7ab1-914c-910f91ea3d80", + "person": null, + "properties": { + "$os": "Mac OS X", + "$os_version": "10.15.7", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/person/bbf314c9-0877-450e-793a-f33cf151dd96", + "$host": "localhost:8000", + "$pathname": "/person/bbf314c9-0877-450e-793a-f33cf151dd96", + "$browser_version": 117, + "$browser_language": "en-GB", + "$screen_height": 982, + "$screen_width": 1512, + "$viewport_height": 859, + "$viewport_width": 1512, + "$lib": "web", + "$lib_version": "1.84.0", + "$insert_id": "gztdmqq16s7ax9lr", + "$time": 1697797679.029, + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$device_id": "018a92fd-7b25-7770-a050-577e94fd148c", + "$console_log_recording_enabled_server_side": true, + "$session_recording_recorder_version_server_side": "v2", + "$autocapture_disabled_server_side": false, + "$active_feature_flags": [ + "signup-page-4.0", + "cmd-k-search", + "posthog-3000", + "funnels-cue-opt-out-7301", + "retention-breakdown", + "smoothing-interval", + "billing-limit", + "kafka-inspector", + "historical-exports-v2", + "person-on-events-enabled", + "region-select", + "ingestion-warnings-enabled", + "session-reset-on-load", + "recordings-on-feature-flags", + "auto-rollback-feature-flags", + "onboarding-v2-demo", + "feature-flag-rollout-ux", + "role-based-access", + "query_running_time", + "query-timings", + "recording-debugging", + "enable-prompts", + "feedback-scene", + "early-access-feature", + "early-access-feature-site-button", + "hedgehog-mode-debug", + "auto-redirect", + "session-recording-blob-replay", + "surveys", + "generic-signup-benefits", + "surveys-positions", + "web-analytics", + "high-frequency-batch-exports", + "exception-autocapture", + "data-warehouse", + "data-warehouse-views", + "ff-dashboard-templates", + "show-product-intro-existing-products", + "artificial-hog", + "cs-dashboards", + "product-specific-onboarding", + "redirect-signups-to-instance", + "apps-and-exports-ui", + "survey-nps-results", + "session-recording-allow-v1-snapshots", + "session-replay-cors-proxy", + "webhooks-denylist", + "surveys-site-app-deprecation", + "surveys-multiple-questions", + "surveys-results-visualizations", + "console-recording-search", + "persons-hogql-query", + "notebooks" + ], + "$feature/file-previews": false, + "$feature/signup-page-4.0": "control", + "$feature/hogql-insights": false, + "$feature/cmd-k-search": true, + "$feature/posthog-3000": true, + "$feature/funnels-cue-opt-out-7301": true, + "$feature/retention-breakdown": true, + "$feature/smoothing-interval": true, + "$feature/billing-limit": true, + "$feature/kafka-inspector": true, + "$feature/historical-exports-v2": true, + "$feature/person-on-events-enabled": true, + "$feature/region-select": true, + "$feature/ingestion-warnings-enabled": true, + "$feature/session-reset-on-load": true, + "$feature/recordings-on-feature-flags": true, + "$feature/auto-rollback-feature-flags": true, + "$feature/onboarding-v2-demo": true, + "$feature/feature-flag-rollout-ux": true, + "$feature/role-based-access": true, + "$feature/query_running_time": true, + "$feature/query-timings": true, + "$feature/recording-debugging": true, + "$feature/enable-prompts": true, + "$feature/feedback-scene": true, + "$feature/early-access-feature": true, + "$feature/early-access-feature-site-button": true, + "$feature/hedgehog-mode-debug": true, + "$feature/auto-redirect": true, + "$feature/session-recording-blob-replay": true, + "$feature/surveys": true, + "$feature/generic-signup-benefits": true, + "$feature/surveys-positions": true, + "$feature/web-analytics": true, + "$feature/high-frequency-batch-exports": true, + "$feature/exception-autocapture": true, + "$feature/data-warehouse": true, + "$feature/data-warehouse-views": true, + "$feature/ff-dashboard-templates": true, + "$feature/show-product-intro-existing-products": true, + "$feature/artificial-hog": true, + "$feature/cs-dashboards": true, + "$feature/product-specific-onboarding": true, + "$feature/redirect-signups-to-instance": true, + "$feature/apps-and-exports-ui": true, + "$feature/survey-nps-results": true, + "$feature/session-recording-allow-v1-snapshots": true, + "$feature/session-replay-cors-proxy": true, + "$feature/webhooks-denylist": true, + "$feature/surveys-site-app-deprecation": true, + "$feature/surveys-multiple-questions": true, + "$feature/surveys-results-visualizations": true, + "$feature/console-recording-search": true, + "$feature/persons-hogql-query": true, + "$feature/notebooks": true, + "$feature_flag_payloads": {}, + "realm": "hosted-clickhouse", + "email_service_available": false, + "slack_service_available": false, + "$user_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "is_demo_project": false, + "$groups": { + "project": "018a92f8-b602-0000-75de-4b9073693531", + "organization": "018a92f8-afff-0000-efec-ca77de39e384", + "customer": "cus_OdSgxxWtHOtq9g", + "instance": "http://localhost:8000" + }, + "has_billing_plan": true, + "customer_deactivated": false, + "current_total_amount_usd": "0.00", + "percentage_usage.product_analytics": 0, + "current_amount_usd.product_analytics": "0.00", + "unit_amount_usd.product_analytics": null, + "usage_limit.product_analytics": null, + "current_usage.product_analytics": 3729, + "projected_usage.product_analytics": 0, + "free_allocation.product_analytics": 0, + "percentage_usage.session_replay": 0, + "current_amount_usd.session_replay": "0.00", + "unit_amount_usd.session_replay": null, + "usage_limit.session_replay": null, + "current_usage.session_replay": 254, + "projected_usage.session_replay": 0, + "free_allocation.session_replay": 0, + "percentage_usage.feature_flags": 0, + "current_amount_usd.feature_flags": "0.00", + "unit_amount_usd.feature_flags": null, + "usage_limit.feature_flags": null, + "current_usage.feature_flags": 0, + "projected_usage.feature_flags": 0, + "free_allocation.feature_flags": 0, + "percentage_usage.integrations": 0, + "current_amount_usd.integrations": null, + "unit_amount_usd.integrations": null, + "usage_limit.integrations": 0, + "current_usage.integrations": 0, + "projected_usage.integrations": 0, + "free_allocation.integrations": 0, + "percentage_usage.platform_and_support": 0, + "current_amount_usd.platform_and_support": null, + "unit_amount_usd.platform_and_support": null, + "usage_limit.platform_and_support": 0, + "current_usage.platform_and_support": 0, + "projected_usage.platform_and_support": 0, + "free_allocation.platform_and_support": 0, + "billing_period_start": "2023-10-14T09:22:33.000Z", + "billing_period_end": "2023-11-14T09:22:33.000Z", + "$referrer": "$direct", + "$referring_domain": "$direct", + "$feature_flag": "persons-hogql-query", + "$feature_flag_response": true, + "token": "phc_OWGI2wKbfi7rWDZT9wkl8uGcfe0wOGCvflLEZSMiaT0", + "$session_id": "018b4ca0-9686-7b75-ba2e-61e9c0054b65", + "$window_id": "018b4ca0-9686-7b75-ba2e-61ea857e58f0", + "$ip": "127.0.0.1", + "$set": { + "$os": "Mac OS X", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/person/bbf314c9-0877-450e-793a-f33cf151dd96", + "$pathname": "/person/bbf314c9-0877-450e-793a-f33cf151dd96", + "$browser_version": 117, + "$referrer": "$direct", + "$referring_domain": "$direct" + }, + "$set_once": { + "$initial_os": "Mac OS X", + "$initial_browser": "Chrome", + "$initial_device_type": "Desktop", + "$initial_current_url": "http://localhost:8000/person/bbf314c9-0877-450e-793a-f33cf151dd96", + "$initial_pathname": "/person/bbf314c9-0877-450e-793a-f33cf151dd96", + "$initial_browser_version": 117, + "$initial_referrer": "$direct", + "$initial_referring_domain": "$direct" + }, + "$sent_at": "2023-10-20T10:28:00.793000+00:00", + "$geoip_city_name": "Sydney", + "$geoip_country_name": "Australia", + "$geoip_country_code": "AU", + "$geoip_continent_name": "Oceania", + "$geoip_continent_code": "OC", + "$geoip_postal_code": "2000", + "$geoip_latitude": -33.8715, + "$geoip_longitude": 151.2006, + "$geoip_time_zone": "Australia/Sydney", + "$geoip_subdivision_1_code": "NSW", + "$geoip_subdivision_1_name": "New South Wales", + "$plugins_succeeded": ["GeoIP (1)"], + "$plugins_failed": [], + "$plugins_deferred": [], + "$group_3": "018a92f8-b602-0000-75de-4b9073693531", + "$group_2": "018a92f8-afff-0000-efec-ca77de39e384", + "$group_4": "cus_OdSgxxWtHOtq9g", + "$group_1": "http://localhost:8000" + }, + "timestamp": "2023-10-20T10:27:59.036000+00:00", + "uuid": null + }, + { + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "elements": [], + "elements_chain": null, + "event": "$feature_flag_called", + "id": "018b4ca0-a7b6-7f8c-87d8-47ec71ea6588", + "person": null, + "properties": { + "$os": "Mac OS X", + "$os_version": "10.15.7", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/person/bbf314c9-0877-450e-793a-f33cf151dd96", + "$host": "localhost:8000", + "$pathname": "/person/bbf314c9-0877-450e-793a-f33cf151dd96", + "$browser_version": 117, + "$browser_language": "en-GB", + "$screen_height": 982, + "$screen_width": 1512, + "$viewport_height": 859, + "$viewport_width": 1512, + "$lib": "web", + "$lib_version": "1.84.0", + "$insert_id": "dzmx9uoovohdmidn", + "$time": 1697797679.03, + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$device_id": "018a92fd-7b25-7770-a050-577e94fd148c", + "$console_log_recording_enabled_server_side": true, + "$session_recording_recorder_version_server_side": "v2", + "$autocapture_disabled_server_side": false, + "$active_feature_flags": [ + "signup-page-4.0", + "cmd-k-search", + "posthog-3000", + "funnels-cue-opt-out-7301", + "retention-breakdown", + "smoothing-interval", + "billing-limit", + "kafka-inspector", + "historical-exports-v2", + "person-on-events-enabled", + "region-select", + "ingestion-warnings-enabled", + "session-reset-on-load", + "recordings-on-feature-flags", + "auto-rollback-feature-flags", + "onboarding-v2-demo", + "feature-flag-rollout-ux", + "role-based-access", + "query_running_time", + "query-timings", + "recording-debugging", + "enable-prompts", + "feedback-scene", + "early-access-feature", + "early-access-feature-site-button", + "hedgehog-mode-debug", + "auto-redirect", + "session-recording-blob-replay", + "surveys", + "generic-signup-benefits", + "surveys-positions", + "web-analytics", + "high-frequency-batch-exports", + "exception-autocapture", + "data-warehouse", + "data-warehouse-views", + "ff-dashboard-templates", + "show-product-intro-existing-products", + "artificial-hog", + "cs-dashboards", + "product-specific-onboarding", + "redirect-signups-to-instance", + "apps-and-exports-ui", + "survey-nps-results", + "session-recording-allow-v1-snapshots", + "session-replay-cors-proxy", + "webhooks-denylist", + "surveys-site-app-deprecation", + "surveys-multiple-questions", + "surveys-results-visualizations", + "console-recording-search", + "persons-hogql-query", + "notebooks" + ], + "$feature/file-previews": false, + "$feature/signup-page-4.0": "control", + "$feature/hogql-insights": false, + "$feature/cmd-k-search": true, + "$feature/posthog-3000": true, + "$feature/funnels-cue-opt-out-7301": true, + "$feature/retention-breakdown": true, + "$feature/smoothing-interval": true, + "$feature/billing-limit": true, + "$feature/kafka-inspector": true, + "$feature/historical-exports-v2": true, + "$feature/person-on-events-enabled": true, + "$feature/region-select": true, + "$feature/ingestion-warnings-enabled": true, + "$feature/session-reset-on-load": true, + "$feature/recordings-on-feature-flags": true, + "$feature/auto-rollback-feature-flags": true, + "$feature/onboarding-v2-demo": true, + "$feature/feature-flag-rollout-ux": true, + "$feature/role-based-access": true, + "$feature/query_running_time": true, + "$feature/query-timings": true, + "$feature/recording-debugging": true, + "$feature/enable-prompts": true, + "$feature/feedback-scene": true, + "$feature/early-access-feature": true, + "$feature/early-access-feature-site-button": true, + "$feature/hedgehog-mode-debug": true, + "$feature/auto-redirect": true, + "$feature/session-recording-blob-replay": true, + "$feature/surveys": true, + "$feature/generic-signup-benefits": true, + "$feature/surveys-positions": true, + "$feature/web-analytics": true, + "$feature/high-frequency-batch-exports": true, + "$feature/exception-autocapture": true, + "$feature/data-warehouse": true, + "$feature/data-warehouse-views": true, + "$feature/ff-dashboard-templates": true, + "$feature/show-product-intro-existing-products": true, + "$feature/artificial-hog": true, + "$feature/cs-dashboards": true, + "$feature/product-specific-onboarding": true, + "$feature/redirect-signups-to-instance": true, + "$feature/apps-and-exports-ui": true, + "$feature/survey-nps-results": true, + "$feature/session-recording-allow-v1-snapshots": true, + "$feature/session-replay-cors-proxy": true, + "$feature/webhooks-denylist": true, + "$feature/surveys-site-app-deprecation": true, + "$feature/surveys-multiple-questions": true, + "$feature/surveys-results-visualizations": true, + "$feature/console-recording-search": true, + "$feature/persons-hogql-query": true, + "$feature/notebooks": true, + "$feature_flag_payloads": {}, + "realm": "hosted-clickhouse", + "email_service_available": false, + "slack_service_available": false, + "$user_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "is_demo_project": false, + "$groups": { + "project": "018a92f8-b602-0000-75de-4b9073693531", + "organization": "018a92f8-afff-0000-efec-ca77de39e384", + "customer": "cus_OdSgxxWtHOtq9g", + "instance": "http://localhost:8000" + }, + "has_billing_plan": true, + "customer_deactivated": false, + "current_total_amount_usd": "0.00", + "percentage_usage.product_analytics": 0, + "current_amount_usd.product_analytics": "0.00", + "unit_amount_usd.product_analytics": null, + "usage_limit.product_analytics": null, + "current_usage.product_analytics": 3729, + "projected_usage.product_analytics": 0, + "free_allocation.product_analytics": 0, + "percentage_usage.session_replay": 0, + "current_amount_usd.session_replay": "0.00", + "unit_amount_usd.session_replay": null, + "usage_limit.session_replay": null, + "current_usage.session_replay": 254, + "projected_usage.session_replay": 0, + "free_allocation.session_replay": 0, + "percentage_usage.feature_flags": 0, + "current_amount_usd.feature_flags": "0.00", + "unit_amount_usd.feature_flags": null, + "usage_limit.feature_flags": null, + "current_usage.feature_flags": 0, + "projected_usage.feature_flags": 0, + "free_allocation.feature_flags": 0, + "percentage_usage.integrations": 0, + "current_amount_usd.integrations": null, + "unit_amount_usd.integrations": null, + "usage_limit.integrations": 0, + "current_usage.integrations": 0, + "projected_usage.integrations": 0, + "free_allocation.integrations": 0, + "percentage_usage.platform_and_support": 0, + "current_amount_usd.platform_and_support": null, + "unit_amount_usd.platform_and_support": null, + "usage_limit.platform_and_support": 0, + "current_usage.platform_and_support": 0, + "projected_usage.platform_and_support": 0, + "free_allocation.platform_and_support": 0, + "billing_period_start": "2023-10-14T09:22:33.000Z", + "billing_period_end": "2023-11-14T09:22:33.000Z", + "$referrer": "$direct", + "$referring_domain": "$direct", + "$feature_flag": "hogql-insights", + "$feature_flag_response": false, + "token": "phc_OWGI2wKbfi7rWDZT9wkl8uGcfe0wOGCvflLEZSMiaT0", + "$session_id": "018b4ca0-9686-7b75-ba2e-61e9c0054b65", + "$window_id": "018b4ca0-9686-7b75-ba2e-61ea857e58f0", + "$ip": "127.0.0.1", + "$set": { + "$os": "Mac OS X", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/person/bbf314c9-0877-450e-793a-f33cf151dd96", + "$pathname": "/person/bbf314c9-0877-450e-793a-f33cf151dd96", + "$browser_version": 117, + "$referrer": "$direct", + "$referring_domain": "$direct" + }, + "$set_once": { + "$initial_os": "Mac OS X", + "$initial_browser": "Chrome", + "$initial_device_type": "Desktop", + "$initial_current_url": "http://localhost:8000/person/bbf314c9-0877-450e-793a-f33cf151dd96", + "$initial_pathname": "/person/bbf314c9-0877-450e-793a-f33cf151dd96", + "$initial_browser_version": 117, + "$initial_referrer": "$direct", + "$initial_referring_domain": "$direct" + }, + "$sent_at": "2023-10-20T10:28:00.793000+00:00", + "$geoip_city_name": "Sydney", + "$geoip_country_name": "Australia", + "$geoip_country_code": "AU", + "$geoip_continent_name": "Oceania", + "$geoip_continent_code": "OC", + "$geoip_postal_code": "2000", + "$geoip_latitude": -33.8715, + "$geoip_longitude": 151.2006, + "$geoip_time_zone": "Australia/Sydney", + "$geoip_subdivision_1_code": "NSW", + "$geoip_subdivision_1_name": "New South Wales", + "$plugins_succeeded": ["GeoIP (1)"], + "$plugins_failed": [], + "$plugins_deferred": [], + "$group_3": "018a92f8-b602-0000-75de-4b9073693531", + "$group_2": "018a92f8-afff-0000-efec-ca77de39e384", + "$group_4": "cus_OdSgxxWtHOtq9g", + "$group_1": "http://localhost:8000" + }, + "timestamp": "2023-10-20T10:27:59.037000+00:00", + "uuid": null + }, + { + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "elements": [], + "elements_chain": null, + "event": "query completed", + "id": "018b4ca0-a897-7497-bd78-4c922df74162", + "person": null, + "properties": { + "$os": "Mac OS X", + "$os_version": "10.15.7", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/person/bbf314c9-0877-450e-793a-f33cf151dd96", + "$host": "localhost:8000", + "$pathname": "/person/bbf314c9-0877-450e-793a-f33cf151dd96", + "$browser_version": 117, + "$browser_language": "en-GB", + "$screen_height": 982, + "$screen_width": 1512, + "$viewport_height": 859, + "$viewport_width": 1512, + "$lib": "web", + "$lib_version": "1.84.0", + "$insert_id": "1ox32j426hf22rbq", + "$time": 1697797679.255, + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$device_id": "018a92fd-7b25-7770-a050-577e94fd148c", + "$console_log_recording_enabled_server_side": true, + "$session_recording_recorder_version_server_side": "v2", + "$autocapture_disabled_server_side": false, + "$active_feature_flags": [ + "signup-page-4.0", + "cmd-k-search", + "posthog-3000", + "funnels-cue-opt-out-7301", + "retention-breakdown", + "smoothing-interval", + "billing-limit", + "kafka-inspector", + "historical-exports-v2", + "person-on-events-enabled", + "region-select", + "ingestion-warnings-enabled", + "session-reset-on-load", + "recordings-on-feature-flags", + "auto-rollback-feature-flags", + "onboarding-v2-demo", + "feature-flag-rollout-ux", + "role-based-access", + "query_running_time", + "query-timings", + "recording-debugging", + "enable-prompts", + "feedback-scene", + "early-access-feature", + "early-access-feature-site-button", + "hedgehog-mode-debug", + "auto-redirect", + "session-recording-blob-replay", + "surveys", + "generic-signup-benefits", + "surveys-positions", + "web-analytics", + "high-frequency-batch-exports", + "exception-autocapture", + "data-warehouse", + "data-warehouse-views", + "ff-dashboard-templates", + "show-product-intro-existing-products", + "artificial-hog", + "cs-dashboards", + "product-specific-onboarding", + "redirect-signups-to-instance", + "apps-and-exports-ui", + "survey-nps-results", + "session-recording-allow-v1-snapshots", + "session-replay-cors-proxy", + "webhooks-denylist", + "surveys-site-app-deprecation", + "surveys-multiple-questions", + "surveys-results-visualizations", + "console-recording-search", + "persons-hogql-query", + "notebooks" + ], + "$feature/file-previews": false, + "$feature/signup-page-4.0": "control", + "$feature/hogql-insights": false, + "$feature/cmd-k-search": true, + "$feature/posthog-3000": true, + "$feature/funnels-cue-opt-out-7301": true, + "$feature/retention-breakdown": true, + "$feature/smoothing-interval": true, + "$feature/billing-limit": true, + "$feature/kafka-inspector": true, + "$feature/historical-exports-v2": true, + "$feature/person-on-events-enabled": true, + "$feature/region-select": true, + "$feature/ingestion-warnings-enabled": true, + "$feature/session-reset-on-load": true, + "$feature/recordings-on-feature-flags": true, + "$feature/auto-rollback-feature-flags": true, + "$feature/onboarding-v2-demo": true, + "$feature/feature-flag-rollout-ux": true, + "$feature/role-based-access": true, + "$feature/query_running_time": true, + "$feature/query-timings": true, + "$feature/recording-debugging": true, + "$feature/enable-prompts": true, + "$feature/feedback-scene": true, + "$feature/early-access-feature": true, + "$feature/early-access-feature-site-button": true, + "$feature/hedgehog-mode-debug": true, + "$feature/auto-redirect": true, + "$feature/session-recording-blob-replay": true, + "$feature/surveys": true, + "$feature/generic-signup-benefits": true, + "$feature/surveys-positions": true, + "$feature/web-analytics": true, + "$feature/high-frequency-batch-exports": true, + "$feature/exception-autocapture": true, + "$feature/data-warehouse": true, + "$feature/data-warehouse-views": true, + "$feature/ff-dashboard-templates": true, + "$feature/show-product-intro-existing-products": true, + "$feature/artificial-hog": true, + "$feature/cs-dashboards": true, + "$feature/product-specific-onboarding": true, + "$feature/redirect-signups-to-instance": true, + "$feature/apps-and-exports-ui": true, + "$feature/survey-nps-results": true, + "$feature/session-recording-allow-v1-snapshots": true, + "$feature/session-replay-cors-proxy": true, + "$feature/webhooks-denylist": true, + "$feature/surveys-site-app-deprecation": true, + "$feature/surveys-multiple-questions": true, + "$feature/surveys-results-visualizations": true, + "$feature/console-recording-search": true, + "$feature/persons-hogql-query": true, + "$feature/notebooks": true, + "$feature_flag_payloads": {}, + "realm": "hosted-clickhouse", + "email_service_available": false, + "slack_service_available": false, + "$user_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "is_demo_project": false, + "$groups": { + "project": "018a92f8-b602-0000-75de-4b9073693531", + "organization": "018a92f8-afff-0000-efec-ca77de39e384", + "customer": "cus_OdSgxxWtHOtq9g", + "instance": "http://localhost:8000" + }, + "has_billing_plan": true, + "customer_deactivated": false, + "current_total_amount_usd": "0.00", + "percentage_usage.product_analytics": 0, + "current_amount_usd.product_analytics": "0.00", + "unit_amount_usd.product_analytics": null, + "usage_limit.product_analytics": null, + "current_usage.product_analytics": 3729, + "projected_usage.product_analytics": 0, + "free_allocation.product_analytics": 0, + "percentage_usage.session_replay": 0, + "current_amount_usd.session_replay": "0.00", + "unit_amount_usd.session_replay": null, + "usage_limit.session_replay": null, + "current_usage.session_replay": 254, + "projected_usage.session_replay": 0, + "free_allocation.session_replay": 0, + "percentage_usage.feature_flags": 0, + "current_amount_usd.feature_flags": "0.00", + "unit_amount_usd.feature_flags": null, + "usage_limit.feature_flags": null, + "current_usage.feature_flags": 0, + "projected_usage.feature_flags": 0, + "free_allocation.feature_flags": 0, + "percentage_usage.integrations": 0, + "current_amount_usd.integrations": null, + "unit_amount_usd.integrations": null, + "usage_limit.integrations": 0, + "current_usage.integrations": 0, + "projected_usage.integrations": 0, + "free_allocation.integrations": 0, + "percentage_usage.platform_and_support": 0, + "current_amount_usd.platform_and_support": null, + "unit_amount_usd.platform_and_support": null, + "usage_limit.platform_and_support": 0, + "current_usage.platform_and_support": 0, + "projected_usage.platform_and_support": 0, + "free_allocation.platform_and_support": 0, + "billing_period_start": "2023-10-14T09:22:33.000Z", + "billing_period_end": "2023-11-14T09:22:33.000Z", + "$referrer": "$direct", + "$referring_domain": "$direct", + "query": { + "kind": "HogQLQuery", + "query": "select id, groupArray(pdi.distinct_id) as distinct_ids, properties, is_identified, created_at from persons where pdi.distinct_id={distinct_id} group by id, properties, is_identified, created_at", + "values": { + "distinct_id": "bbf314c9-0877-450e-793a-f33cf151dd96" + } + }, + "duration": 225.0999999642372, + "clickhouse_sql": "SELECT persons.id, groupArray(persons__pdi.distinct_id) AS distinct_ids, persons.properties, persons.is_identified, toTimeZone(persons.created_at, %(hogql_val_0)s) FROM (SELECT person.id, person.properties AS properties, person.is_identified AS is_identified, person.created_at AS created_at FROM person WHERE and(equals(person.team_id, 1), ifNull(in(tuple(person.id, person.version), (SELECT person.id, max(person.version) AS version FROM person WHERE equals(person.team_id, 1) GROUP BY person.id HAVING ifNull(equals(argMax(person.is_deleted, person.version), 0), 0))), 0)) SETTINGS optimize_aggregation_in_order=1) AS persons INNER JOIN (SELECT argMax(person_distinct_id2.person_id, person_distinct_id2.version) AS person_id, person_distinct_id2.distinct_id AS distinct_id FROM person_distinct_id2 WHERE equals(person_distinct_id2.team_id, 1) GROUP BY person_distinct_id2.distinct_id HAVING ifNull(equals(argMax(person_distinct_id2.is_deleted, person_distinct_id2.version), 0), 0)) AS persons__pdi ON equals(persons.id, persons__pdi.person_id) WHERE ifNull(equals(persons__pdi.distinct_id, %(hogql_val_1)s), 0) GROUP BY persons.id, persons.properties, persons.is_identified, toTimeZone(persons.created_at, %(hogql_val_2)s) LIMIT 100 SETTINGS readonly=2, max_execution_time=60, allow_experimental_object_type=1", + "token": "phc_OWGI2wKbfi7rWDZT9wkl8uGcfe0wOGCvflLEZSMiaT0", + "$session_id": "018b4ca0-9686-7b75-ba2e-61e9c0054b65", + "$window_id": "018b4ca0-9686-7b75-ba2e-61ea857e58f0", + "$ip": "127.0.0.1", + "$set": { + "$os": "Mac OS X", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/person/bbf314c9-0877-450e-793a-f33cf151dd96", + "$pathname": "/person/bbf314c9-0877-450e-793a-f33cf151dd96", + "$browser_version": 117, + "$referrer": "$direct", + "$referring_domain": "$direct" + }, + "$set_once": { + "$initial_os": "Mac OS X", + "$initial_browser": "Chrome", + "$initial_device_type": "Desktop", + "$initial_current_url": "http://localhost:8000/person/bbf314c9-0877-450e-793a-f33cf151dd96", + "$initial_pathname": "/person/bbf314c9-0877-450e-793a-f33cf151dd96", + "$initial_browser_version": 117, + "$initial_referrer": "$direct", + "$initial_referring_domain": "$direct" + }, + "$sent_at": "2023-10-20T10:28:00.793000+00:00", + "$geoip_city_name": "Sydney", + "$geoip_country_name": "Australia", + "$geoip_country_code": "AU", + "$geoip_continent_name": "Oceania", + "$geoip_continent_code": "OC", + "$geoip_postal_code": "2000", + "$geoip_latitude": -33.8715, + "$geoip_longitude": 151.2006, + "$geoip_time_zone": "Australia/Sydney", + "$geoip_subdivision_1_code": "NSW", + "$geoip_subdivision_1_name": "New South Wales", + "$plugins_succeeded": ["GeoIP (1)"], + "$plugins_failed": [], + "$plugins_deferred": [], + "$group_3": "018a92f8-b602-0000-75de-4b9073693531", + "$group_2": "018a92f8-afff-0000-efec-ca77de39e384", + "$group_4": "cus_OdSgxxWtHOtq9g", + "$group_1": "http://localhost:8000" + }, + "timestamp": "2023-10-20T10:27:59.262000+00:00", + "uuid": null + }, + { + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "elements": [ + { + "attr_class": null, + "attr_id": null, + "attributes": { + "attr__href": "/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI" + }, + "href": "/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "nth_child": 1.0, + "nth_of_type": 1.0, + "order": 0.0, + "tag_name": "h5", + "text": "test@posthog.com" + }, + { + "attr_class": ["Link", "SidebarListItem__link"], + "attr_id": null, + "attributes": { + "attr__class": "Link SidebarListItem__link", + "attr__draggable": "true", + "attr__href": "/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI" + }, + "href": "/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "nth_child": 1.0, + "nth_of_type": 1.0, + "order": 1.0, + "tag_name": "a", + "text": null + }, + { + "attr_class": ["SidebarListItem"], + "attr_id": "sidebar-krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI,018a92fd-7b25-7770-a050-577e94fd148c,018b4715-2fd1-7b9d-b1de-4cf7972a15e3", + "attributes": { + "attr__aria-disabled": "false", + "attr__aria-invalid": "false", + "attr__class": "SidebarListItem", + "attr__id": "sidebar-krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI,018a92fd-7b25-7770-a050-577e94fd148c,018b4715-2fd1-7b9d-b1de-4cf7972a15e3", + "attr__style": "height: 32px; left: 0px; position: absolute; top: 64px; width: 100%;", + "attr__title": "test@posthog.com" + }, + "href": null, + "nth_child": 3.0, + "nth_of_type": 3.0, + "order": 2.0, + "tag_name": "li", + "text": null + }, + { + "attr_class": ["ReactVirtualized__Grid__innerScrollContainer"], + "attr_id": null, + "attributes": { + "attr__class": "ReactVirtualized__Grid__innerScrollContainer", + "attr__role": "rowgroup", + "attr__style": "width: auto; height: 95872px; max-width: 250px; max-height: 95872px; overflow: hidden; position: relative;" + }, + "href": null, + "nth_child": 1.0, + "nth_of_type": 1.0, + "order": 3.0, + "tag_name": "div", + "text": null + }, + { + "attr_class": ["ReactVirtualized__Grid", "ReactVirtualized__List", "SidebarList"], + "attr_id": null, + "attributes": { + "attr__aria-label": "grid", + "attr__aria-readonly": "true", + "attr__class": "ReactVirtualized__Grid ReactVirtualized__List SidebarList", + "attr__role": "grid", + "attr__style": "box-sizing: border-box; direction: ltr; height: 312px; position: relative; width: 250px; will-change: transform; overflow: hidden auto;" + }, + "href": null, + "nth_child": 1.0, + "nth_of_type": 1.0, + "order": 4.0, + "tag_name": "div", + "text": null + }, + { + "attr_class": null, + "attr_id": null, + "attributes": { + "attr__style": "overflow: visible; height: 0px;" + }, + "href": null, + "nth_child": 1.0, + "nth_of_type": 1.0, + "order": 5.0, + "tag_name": "div", + "text": null + }, + { + "attr_class": ["flex-1"], + "attr_id": null, + "attributes": { + "attr__class": "flex-1", + "attr__style": "position: relative;" + }, + "href": null, + "nth_child": 2.0, + "nth_of_type": 2.0, + "order": 6.0, + "tag_name": "div", + "text": null + }, + { + "attr_class": ["Accordion"], + "attr_id": null, + "attributes": { + "attr__aria-busy": "false", + "attr__aria-disabled": "false", + "attr__aria-expanded": "true", + "attr__class": "Accordion" + }, + "href": null, + "nth_child": 1.0, + "nth_of_type": 1.0, + "order": 7.0, + "tag_name": "section", + "text": null + }, + { + "attr_class": ["Sidebar3000__lists"], + "attr_id": null, + "attributes": { + "attr__class": "Sidebar3000__lists" + }, + "href": null, + "nth_child": 2.0, + "nth_of_type": 2.0, + "order": 8.0, + "tag_name": "div", + "text": null + }, + { + "attr_class": ["Sidebar3000__content"], + "attr_id": null, + "attributes": { + "attr__class": "Sidebar3000__content" + }, + "href": null, + "nth_child": 1.0, + "nth_of_type": 1.0, + "order": 9.0, + "tag_name": "div", + "text": null + }, + { + "attr_class": ["Sidebar3000"], + "attr_id": null, + "attributes": { + "attr__aria-hidden": "false", + "attr__class": "Sidebar3000", + "attr__style": "--sidebar-width: 250px;" + }, + "href": null, + "nth_child": 2.0, + "nth_of_type": 1.0, + "order": 10.0, + "tag_name": "div", + "text": null + }, + { + "attr_class": ["Navigation3000"], + "attr_id": null, + "attributes": { + "attr__class": "Navigation3000" + }, + "href": null, + "nth_child": 1.0, + "nth_of_type": 1.0, + "order": 11.0, + "tag_name": "div", + "text": null + }, + { + "attr_class": null, + "attr_id": "root", + "attributes": { + "attr__id": "root" + }, + "href": null, + "nth_child": 4.0, + "nth_of_type": 1.0, + "order": 12.0, + "tag_name": "div", + "text": null + }, + { + "attr_class": ["posthog-3000"], + "attr_id": null, + "attributes": { + "attr__class": "posthog-3000", + "attr__theme": "light" + }, + "href": null, + "nth_child": 2.0, + "nth_of_type": 1.0, + "order": 13.0, + "tag_name": "body", + "text": null + } + ], + "elements_chain": "h5:attr__href=\"/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI\"href=\"/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI\"nth-child=\"1\"nth-of-type=\"1\"text=\"test@posthog.com\";a.Link.SidebarListItem__link:attr__class=\"Link SidebarListItem__link\"attr__draggable=\"true\"attr__href=\"/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI\"href=\"/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI\"nth-child=\"1\"nth-of-type=\"1\";li.SidebarListItem:attr__aria-disabled=\"false\"attr__aria-invalid=\"false\"attr__class=\"SidebarListItem\"attr__id=\"sidebar-krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI,018a92fd-7b25-7770-a050-577e94fd148c,018b4715-2fd1-7b9d-b1de-4cf7972a15e3\"attr__style=\"height: 32px; left: 0px; position: absolute; top: 64px; width: 100%;\"attr__title=\"test@posthog.com\"attr_id=\"sidebar-krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI,018a92fd-7b25-7770-a050-577e94fd148c,018b4715-2fd1-7b9d-b1de-4cf7972a15e3\"nth-child=\"3\"nth-of-type=\"3\";div.ReactVirtualized__Grid__innerScrollContainer:attr__class=\"ReactVirtualized__Grid__innerScrollContainer\"attr__role=\"rowgroup\"attr__style=\"width: auto; height: 95872px; max-width: 250px; max-height: 95872px; overflow: hidden; position: relative;\"nth-child=\"1\"nth-of-type=\"1\";div.ReactVirtualized__Grid.ReactVirtualized__List.SidebarList:attr__aria-label=\"grid\"attr__aria-readonly=\"true\"attr__class=\"ReactVirtualized__Grid ReactVirtualized__List SidebarList\"attr__role=\"grid\"attr__style=\"box-sizing: border-box; direction: ltr; height: 312px; position: relative; width: 250px; will-change: transform; overflow: hidden auto;\"nth-child=\"1\"nth-of-type=\"1\";div:attr__style=\"overflow: visible; height: 0px;\"nth-child=\"1\"nth-of-type=\"1\";div.flex-1:attr__class=\"flex-1\"attr__style=\"position: relative;\"nth-child=\"2\"nth-of-type=\"2\";section.Accordion:attr__aria-busy=\"false\"attr__aria-disabled=\"false\"attr__aria-expanded=\"true\"attr__class=\"Accordion\"nth-child=\"1\"nth-of-type=\"1\";div.Sidebar3000__lists:attr__class=\"Sidebar3000__lists\"nth-child=\"2\"nth-of-type=\"2\";div.Sidebar3000__content:attr__class=\"Sidebar3000__content\"nth-child=\"1\"nth-of-type=\"1\";div.Sidebar3000:attr__aria-hidden=\"false\"attr__class=\"Sidebar3000\"attr__style=\"--sidebar-width: 250px;\"nth-child=\"2\"nth-of-type=\"1\";div.Navigation3000:attr__class=\"Navigation3000\"nth-child=\"1\"nth-of-type=\"1\";div:attr__id=\"root\"attr_id=\"root\"nth-child=\"4\"nth-of-type=\"1\";body.posthog-3000:attr__class=\"posthog-3000\"attr__theme=\"light\"nth-child=\"2\"nth-of-type=\"1\"", + "event": "$autocapture", + "id": "018b4ca0-a98c-7384-b2e2-769ad052ee0b", + "person": null, + "properties": { + "$os": "Mac OS X", + "$os_version": "10.15.7", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/person/bbf314c9-0877-450e-793a-f33cf151dd96", + "$host": "localhost:8000", + "$pathname": "/person/bbf314c9-0877-450e-793a-f33cf151dd96", + "$browser_version": 117, + "$browser_language": "en-GB", + "$screen_height": 982, + "$screen_width": 1512, + "$viewport_height": 859, + "$viewport_width": 1512, + "$lib": "web", + "$lib_version": "1.84.0", + "$insert_id": "je02qyvh3bhr5mgo", + "$time": 1697797679.501, + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$device_id": "018a92fd-7b25-7770-a050-577e94fd148c", + "$console_log_recording_enabled_server_side": true, + "$session_recording_recorder_version_server_side": "v2", + "$autocapture_disabled_server_side": false, + "$active_feature_flags": [ + "signup-page-4.0", + "cmd-k-search", + "posthog-3000", + "funnels-cue-opt-out-7301", + "retention-breakdown", + "smoothing-interval", + "billing-limit", + "kafka-inspector", + "historical-exports-v2", + "person-on-events-enabled", + "region-select", + "ingestion-warnings-enabled", + "session-reset-on-load", + "recordings-on-feature-flags", + "auto-rollback-feature-flags", + "onboarding-v2-demo", + "feature-flag-rollout-ux", + "role-based-access", + "query_running_time", + "query-timings", + "recording-debugging", + "enable-prompts", + "feedback-scene", + "early-access-feature", + "early-access-feature-site-button", + "hedgehog-mode-debug", + "auto-redirect", + "session-recording-blob-replay", + "surveys", + "generic-signup-benefits", + "surveys-positions", + "web-analytics", + "high-frequency-batch-exports", + "exception-autocapture", + "data-warehouse", + "data-warehouse-views", + "ff-dashboard-templates", + "show-product-intro-existing-products", + "artificial-hog", + "cs-dashboards", + "product-specific-onboarding", + "redirect-signups-to-instance", + "apps-and-exports-ui", + "survey-nps-results", + "session-recording-allow-v1-snapshots", + "session-replay-cors-proxy", + "webhooks-denylist", + "surveys-site-app-deprecation", + "surveys-multiple-questions", + "surveys-results-visualizations", + "console-recording-search", + "persons-hogql-query", + "notebooks" + ], + "$feature/file-previews": false, + "$feature/signup-page-4.0": "control", + "$feature/hogql-insights": false, + "$feature/cmd-k-search": true, + "$feature/posthog-3000": true, + "$feature/funnels-cue-opt-out-7301": true, + "$feature/retention-breakdown": true, + "$feature/smoothing-interval": true, + "$feature/billing-limit": true, + "$feature/kafka-inspector": true, + "$feature/historical-exports-v2": true, + "$feature/person-on-events-enabled": true, + "$feature/region-select": true, + "$feature/ingestion-warnings-enabled": true, + "$feature/session-reset-on-load": true, + "$feature/recordings-on-feature-flags": true, + "$feature/auto-rollback-feature-flags": true, + "$feature/onboarding-v2-demo": true, + "$feature/feature-flag-rollout-ux": true, + "$feature/role-based-access": true, + "$feature/query_running_time": true, + "$feature/query-timings": true, + "$feature/recording-debugging": true, + "$feature/enable-prompts": true, + "$feature/feedback-scene": true, + "$feature/early-access-feature": true, + "$feature/early-access-feature-site-button": true, + "$feature/hedgehog-mode-debug": true, + "$feature/auto-redirect": true, + "$feature/session-recording-blob-replay": true, + "$feature/surveys": true, + "$feature/generic-signup-benefits": true, + "$feature/surveys-positions": true, + "$feature/web-analytics": true, + "$feature/high-frequency-batch-exports": true, + "$feature/exception-autocapture": true, + "$feature/data-warehouse": true, + "$feature/data-warehouse-views": true, + "$feature/ff-dashboard-templates": true, + "$feature/show-product-intro-existing-products": true, + "$feature/artificial-hog": true, + "$feature/cs-dashboards": true, + "$feature/product-specific-onboarding": true, + "$feature/redirect-signups-to-instance": true, + "$feature/apps-and-exports-ui": true, + "$feature/survey-nps-results": true, + "$feature/session-recording-allow-v1-snapshots": true, + "$feature/session-replay-cors-proxy": true, + "$feature/webhooks-denylist": true, + "$feature/surveys-site-app-deprecation": true, + "$feature/surveys-multiple-questions": true, + "$feature/surveys-results-visualizations": true, + "$feature/console-recording-search": true, + "$feature/persons-hogql-query": true, + "$feature/notebooks": true, + "$feature_flag_payloads": {}, + "realm": "hosted-clickhouse", + "email_service_available": false, + "slack_service_available": false, + "$user_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "is_demo_project": false, + "$groups": { + "project": "018a92f8-b602-0000-75de-4b9073693531", + "organization": "018a92f8-afff-0000-efec-ca77de39e384", + "customer": "cus_OdSgxxWtHOtq9g", + "instance": "http://localhost:8000" + }, + "has_billing_plan": true, + "customer_deactivated": false, + "current_total_amount_usd": "0.00", + "percentage_usage.product_analytics": 0, + "current_amount_usd.product_analytics": "0.00", + "unit_amount_usd.product_analytics": null, + "usage_limit.product_analytics": null, + "current_usage.product_analytics": 3729, + "projected_usage.product_analytics": 0, + "free_allocation.product_analytics": 0, + "percentage_usage.session_replay": 0, + "current_amount_usd.session_replay": "0.00", + "unit_amount_usd.session_replay": null, + "usage_limit.session_replay": null, + "current_usage.session_replay": 254, + "projected_usage.session_replay": 0, + "free_allocation.session_replay": 0, + "percentage_usage.feature_flags": 0, + "current_amount_usd.feature_flags": "0.00", + "unit_amount_usd.feature_flags": null, + "usage_limit.feature_flags": null, + "current_usage.feature_flags": 0, + "projected_usage.feature_flags": 0, + "free_allocation.feature_flags": 0, + "percentage_usage.integrations": 0, + "current_amount_usd.integrations": null, + "unit_amount_usd.integrations": null, + "usage_limit.integrations": 0, + "current_usage.integrations": 0, + "projected_usage.integrations": 0, + "free_allocation.integrations": 0, + "percentage_usage.platform_and_support": 0, + "current_amount_usd.platform_and_support": null, + "unit_amount_usd.platform_and_support": null, + "usage_limit.platform_and_support": 0, + "current_usage.platform_and_support": 0, + "projected_usage.platform_and_support": 0, + "free_allocation.platform_and_support": 0, + "billing_period_start": "2023-10-14T09:22:33.000Z", + "billing_period_end": "2023-11-14T09:22:33.000Z", + "$referrer": "$direct", + "$referring_domain": "$direct", + "$event_type": "click", + "$ce_version": 1, + "$el_text": "test@posthog.com", + "token": "phc_OWGI2wKbfi7rWDZT9wkl8uGcfe0wOGCvflLEZSMiaT0", + "$session_id": "018b4ca0-9686-7b75-ba2e-61e9c0054b65", + "$window_id": "018b4ca0-9686-7b75-ba2e-61ea857e58f0", + "$ip": "127.0.0.1", + "$set": { + "$os": "Mac OS X", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/person/bbf314c9-0877-450e-793a-f33cf151dd96", + "$pathname": "/person/bbf314c9-0877-450e-793a-f33cf151dd96", + "$browser_version": 117, + "$referrer": "$direct", + "$referring_domain": "$direct" + }, + "$set_once": { + "$initial_os": "Mac OS X", + "$initial_browser": "Chrome", + "$initial_device_type": "Desktop", + "$initial_current_url": "http://localhost:8000/person/bbf314c9-0877-450e-793a-f33cf151dd96", + "$initial_pathname": "/person/bbf314c9-0877-450e-793a-f33cf151dd96", + "$initial_browser_version": 117, + "$initial_referrer": "$direct", + "$initial_referring_domain": "$direct" + }, + "$sent_at": "2023-10-20T10:28:00.793000+00:00", + "$geoip_city_name": "Sydney", + "$geoip_country_name": "Australia", + "$geoip_country_code": "AU", + "$geoip_continent_name": "Oceania", + "$geoip_continent_code": "OC", + "$geoip_postal_code": "2000", + "$geoip_latitude": -33.8715, + "$geoip_longitude": 151.2006, + "$geoip_time_zone": "Australia/Sydney", + "$geoip_subdivision_1_code": "NSW", + "$geoip_subdivision_1_name": "New South Wales", + "$plugins_succeeded": ["GeoIP (1)"], + "$plugins_failed": [], + "$plugins_deferred": [], + "$group_3": "018a92f8-b602-0000-75de-4b9073693531", + "$group_2": "018a92f8-afff-0000-efec-ca77de39e384", + "$group_4": "cus_OdSgxxWtHOtq9g", + "$group_1": "http://localhost:8000" + }, + "timestamp": "2023-10-20T10:27:59.508000+00:00", + "uuid": null + }, + { + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "elements": [], + "elements_chain": null, + "event": "$pageview", + "id": "018b4ca0-a98f-7b7f-97f9-94db73ef7b5d", + "person": null, + "properties": { + "$os": "Mac OS X", + "$os_version": "10.15.7", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$host": "localhost:8000", + "$pathname": "/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$browser_version": 117, + "$browser_language": "en-GB", + "$screen_height": 982, + "$screen_width": 1512, + "$viewport_height": 859, + "$viewport_width": 1512, + "$lib": "web", + "$lib_version": "1.84.0", + "$insert_id": "rv3lg9ojjqh0bazz", + "$time": 1697797679.504, + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$device_id": "018a92fd-7b25-7770-a050-577e94fd148c", + "$console_log_recording_enabled_server_side": true, + "$session_recording_recorder_version_server_side": "v2", + "$autocapture_disabled_server_side": false, + "$active_feature_flags": [ + "signup-page-4.0", + "cmd-k-search", + "posthog-3000", + "funnels-cue-opt-out-7301", + "retention-breakdown", + "smoothing-interval", + "billing-limit", + "kafka-inspector", + "historical-exports-v2", + "person-on-events-enabled", + "region-select", + "ingestion-warnings-enabled", + "session-reset-on-load", + "recordings-on-feature-flags", + "auto-rollback-feature-flags", + "onboarding-v2-demo", + "feature-flag-rollout-ux", + "role-based-access", + "query_running_time", + "query-timings", + "recording-debugging", + "enable-prompts", + "feedback-scene", + "early-access-feature", + "early-access-feature-site-button", + "hedgehog-mode-debug", + "auto-redirect", + "session-recording-blob-replay", + "surveys", + "generic-signup-benefits", + "surveys-positions", + "web-analytics", + "high-frequency-batch-exports", + "exception-autocapture", + "data-warehouse", + "data-warehouse-views", + "ff-dashboard-templates", + "show-product-intro-existing-products", + "artificial-hog", + "cs-dashboards", + "product-specific-onboarding", + "redirect-signups-to-instance", + "apps-and-exports-ui", + "survey-nps-results", + "session-recording-allow-v1-snapshots", + "session-replay-cors-proxy", + "webhooks-denylist", + "surveys-site-app-deprecation", + "surveys-multiple-questions", + "surveys-results-visualizations", + "console-recording-search", + "persons-hogql-query", + "notebooks" + ], + "$feature/file-previews": false, + "$feature/signup-page-4.0": "control", + "$feature/hogql-insights": false, + "$feature/cmd-k-search": true, + "$feature/posthog-3000": true, + "$feature/funnels-cue-opt-out-7301": true, + "$feature/retention-breakdown": true, + "$feature/smoothing-interval": true, + "$feature/billing-limit": true, + "$feature/kafka-inspector": true, + "$feature/historical-exports-v2": true, + "$feature/person-on-events-enabled": true, + "$feature/region-select": true, + "$feature/ingestion-warnings-enabled": true, + "$feature/session-reset-on-load": true, + "$feature/recordings-on-feature-flags": true, + "$feature/auto-rollback-feature-flags": true, + "$feature/onboarding-v2-demo": true, + "$feature/feature-flag-rollout-ux": true, + "$feature/role-based-access": true, + "$feature/query_running_time": true, + "$feature/query-timings": true, + "$feature/recording-debugging": true, + "$feature/enable-prompts": true, + "$feature/feedback-scene": true, + "$feature/early-access-feature": true, + "$feature/early-access-feature-site-button": true, + "$feature/hedgehog-mode-debug": true, + "$feature/auto-redirect": true, + "$feature/session-recording-blob-replay": true, + "$feature/surveys": true, + "$feature/generic-signup-benefits": true, + "$feature/surveys-positions": true, + "$feature/web-analytics": true, + "$feature/high-frequency-batch-exports": true, + "$feature/exception-autocapture": true, + "$feature/data-warehouse": true, + "$feature/data-warehouse-views": true, + "$feature/ff-dashboard-templates": true, + "$feature/show-product-intro-existing-products": true, + "$feature/artificial-hog": true, + "$feature/cs-dashboards": true, + "$feature/product-specific-onboarding": true, + "$feature/redirect-signups-to-instance": true, + "$feature/apps-and-exports-ui": true, + "$feature/survey-nps-results": true, + "$feature/session-recording-allow-v1-snapshots": true, + "$feature/session-replay-cors-proxy": true, + "$feature/webhooks-denylist": true, + "$feature/surveys-site-app-deprecation": true, + "$feature/surveys-multiple-questions": true, + "$feature/surveys-results-visualizations": true, + "$feature/console-recording-search": true, + "$feature/persons-hogql-query": true, + "$feature/notebooks": true, + "$feature_flag_payloads": {}, + "realm": "hosted-clickhouse", + "email_service_available": false, + "slack_service_available": false, + "$user_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "is_demo_project": false, + "$groups": { + "project": "018a92f8-b602-0000-75de-4b9073693531", + "organization": "018a92f8-afff-0000-efec-ca77de39e384", + "customer": "cus_OdSgxxWtHOtq9g", + "instance": "http://localhost:8000" + }, + "has_billing_plan": true, + "customer_deactivated": false, + "current_total_amount_usd": "0.00", + "percentage_usage.product_analytics": 0, + "current_amount_usd.product_analytics": "0.00", + "unit_amount_usd.product_analytics": null, + "usage_limit.product_analytics": null, + "current_usage.product_analytics": 3729, + "projected_usage.product_analytics": 0, + "free_allocation.product_analytics": 0, + "percentage_usage.session_replay": 0, + "current_amount_usd.session_replay": "0.00", + "unit_amount_usd.session_replay": null, + "usage_limit.session_replay": null, + "current_usage.session_replay": 254, + "projected_usage.session_replay": 0, + "free_allocation.session_replay": 0, + "percentage_usage.feature_flags": 0, + "current_amount_usd.feature_flags": "0.00", + "unit_amount_usd.feature_flags": null, + "usage_limit.feature_flags": null, + "current_usage.feature_flags": 0, + "projected_usage.feature_flags": 0, + "free_allocation.feature_flags": 0, + "percentage_usage.integrations": 0, + "current_amount_usd.integrations": null, + "unit_amount_usd.integrations": null, + "usage_limit.integrations": 0, + "current_usage.integrations": 0, + "projected_usage.integrations": 0, + "free_allocation.integrations": 0, + "percentage_usage.platform_and_support": 0, + "current_amount_usd.platform_and_support": null, + "unit_amount_usd.platform_and_support": null, + "usage_limit.platform_and_support": 0, + "current_usage.platform_and_support": 0, + "projected_usage.platform_and_support": 0, + "free_allocation.platform_and_support": 0, + "billing_period_start": "2023-10-14T09:22:33.000Z", + "billing_period_end": "2023-11-14T09:22:33.000Z", + "$referrer": "$direct", + "$referring_domain": "$direct", + "token": "phc_OWGI2wKbfi7rWDZT9wkl8uGcfe0wOGCvflLEZSMiaT0", + "$session_id": "018b4ca0-9686-7b75-ba2e-61e9c0054b65", + "$window_id": "018b4ca0-9686-7b75-ba2e-61ea857e58f0", + "title": "bbf314c9-0877-450e-793a-f33cf151dd96 \u2022 Persons \u2022 PostHog", + "$ip": "127.0.0.1", + "$set": { + "$os": "Mac OS X", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$pathname": "/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$browser_version": 117, + "$referrer": "$direct", + "$referring_domain": "$direct" + }, + "$set_once": { + "$initial_os": "Mac OS X", + "$initial_browser": "Chrome", + "$initial_device_type": "Desktop", + "$initial_current_url": "http://localhost:8000/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$initial_pathname": "/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$initial_browser_version": 117, + "$initial_referrer": "$direct", + "$initial_referring_domain": "$direct" + }, + "$sent_at": "2023-10-20T10:28:00.793000+00:00", + "$geoip_city_name": "Sydney", + "$geoip_country_name": "Australia", + "$geoip_country_code": "AU", + "$geoip_continent_name": "Oceania", + "$geoip_continent_code": "OC", + "$geoip_postal_code": "2000", + "$geoip_latitude": -33.8715, + "$geoip_longitude": 151.2006, + "$geoip_time_zone": "Australia/Sydney", + "$geoip_subdivision_1_code": "NSW", + "$geoip_subdivision_1_name": "New South Wales", + "$plugins_succeeded": ["GeoIP (1)"], + "$plugins_failed": [], + "$plugins_deferred": [], + "$group_3": "018a92f8-b602-0000-75de-4b9073693531", + "$group_2": "018a92f8-afff-0000-efec-ca77de39e384", + "$group_4": "cus_OdSgxxWtHOtq9g", + "$group_1": "http://localhost:8000" + }, + "timestamp": "2023-10-20T10:27:59.511000+00:00", + "uuid": null + }, + { + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "elements": [], + "elements_chain": null, + "event": "query completed", + "id": "018b4ca0-aa6e-72a0-b88c-a09bd8399999", + "person": null, + "properties": { + "$os": "Mac OS X", + "$os_version": "10.15.7", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$host": "localhost:8000", + "$pathname": "/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$browser_version": 117, + "$browser_language": "en-GB", + "$screen_height": 982, + "$screen_width": 1512, + "$viewport_height": 859, + "$viewport_width": 1512, + "$lib": "web", + "$lib_version": "1.84.0", + "$insert_id": "2zh0feb6n1tf9a1f", + "$time": 1697797679.727, + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$device_id": "018a92fd-7b25-7770-a050-577e94fd148c", + "$console_log_recording_enabled_server_side": true, + "$session_recording_recorder_version_server_side": "v2", + "$autocapture_disabled_server_side": false, + "$active_feature_flags": [ + "signup-page-4.0", + "cmd-k-search", + "posthog-3000", + "funnels-cue-opt-out-7301", + "retention-breakdown", + "smoothing-interval", + "billing-limit", + "kafka-inspector", + "historical-exports-v2", + "person-on-events-enabled", + "region-select", + "ingestion-warnings-enabled", + "session-reset-on-load", + "recordings-on-feature-flags", + "auto-rollback-feature-flags", + "onboarding-v2-demo", + "feature-flag-rollout-ux", + "role-based-access", + "query_running_time", + "query-timings", + "recording-debugging", + "enable-prompts", + "feedback-scene", + "early-access-feature", + "early-access-feature-site-button", + "hedgehog-mode-debug", + "auto-redirect", + "session-recording-blob-replay", + "surveys", + "generic-signup-benefits", + "surveys-positions", + "web-analytics", + "high-frequency-batch-exports", + "exception-autocapture", + "data-warehouse", + "data-warehouse-views", + "ff-dashboard-templates", + "show-product-intro-existing-products", + "artificial-hog", + "cs-dashboards", + "product-specific-onboarding", + "redirect-signups-to-instance", + "apps-and-exports-ui", + "survey-nps-results", + "session-recording-allow-v1-snapshots", + "session-replay-cors-proxy", + "webhooks-denylist", + "surveys-site-app-deprecation", + "surveys-multiple-questions", + "surveys-results-visualizations", + "console-recording-search", + "persons-hogql-query", + "notebooks" + ], + "$feature/file-previews": false, + "$feature/signup-page-4.0": "control", + "$feature/hogql-insights": false, + "$feature/cmd-k-search": true, + "$feature/posthog-3000": true, + "$feature/funnels-cue-opt-out-7301": true, + "$feature/retention-breakdown": true, + "$feature/smoothing-interval": true, + "$feature/billing-limit": true, + "$feature/kafka-inspector": true, + "$feature/historical-exports-v2": true, + "$feature/person-on-events-enabled": true, + "$feature/region-select": true, + "$feature/ingestion-warnings-enabled": true, + "$feature/session-reset-on-load": true, + "$feature/recordings-on-feature-flags": true, + "$feature/auto-rollback-feature-flags": true, + "$feature/onboarding-v2-demo": true, + "$feature/feature-flag-rollout-ux": true, + "$feature/role-based-access": true, + "$feature/query_running_time": true, + "$feature/query-timings": true, + "$feature/recording-debugging": true, + "$feature/enable-prompts": true, + "$feature/feedback-scene": true, + "$feature/early-access-feature": true, + "$feature/early-access-feature-site-button": true, + "$feature/hedgehog-mode-debug": true, + "$feature/auto-redirect": true, + "$feature/session-recording-blob-replay": true, + "$feature/surveys": true, + "$feature/generic-signup-benefits": true, + "$feature/surveys-positions": true, + "$feature/web-analytics": true, + "$feature/high-frequency-batch-exports": true, + "$feature/exception-autocapture": true, + "$feature/data-warehouse": true, + "$feature/data-warehouse-views": true, + "$feature/ff-dashboard-templates": true, + "$feature/show-product-intro-existing-products": true, + "$feature/artificial-hog": true, + "$feature/cs-dashboards": true, + "$feature/product-specific-onboarding": true, + "$feature/redirect-signups-to-instance": true, + "$feature/apps-and-exports-ui": true, + "$feature/survey-nps-results": true, + "$feature/session-recording-allow-v1-snapshots": true, + "$feature/session-replay-cors-proxy": true, + "$feature/webhooks-denylist": true, + "$feature/surveys-site-app-deprecation": true, + "$feature/surveys-multiple-questions": true, + "$feature/surveys-results-visualizations": true, + "$feature/console-recording-search": true, + "$feature/persons-hogql-query": true, + "$feature/notebooks": true, + "$feature_flag_payloads": {}, + "realm": "hosted-clickhouse", + "email_service_available": false, + "slack_service_available": false, + "$user_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "is_demo_project": false, + "$groups": { + "project": "018a92f8-b602-0000-75de-4b9073693531", + "organization": "018a92f8-afff-0000-efec-ca77de39e384", + "customer": "cus_OdSgxxWtHOtq9g", + "instance": "http://localhost:8000" + }, + "has_billing_plan": true, + "customer_deactivated": false, + "current_total_amount_usd": "0.00", + "percentage_usage.product_analytics": 0, + "current_amount_usd.product_analytics": "0.00", + "unit_amount_usd.product_analytics": null, + "usage_limit.product_analytics": null, + "current_usage.product_analytics": 3729, + "projected_usage.product_analytics": 0, + "free_allocation.product_analytics": 0, + "percentage_usage.session_replay": 0, + "current_amount_usd.session_replay": "0.00", + "unit_amount_usd.session_replay": null, + "usage_limit.session_replay": null, + "current_usage.session_replay": 254, + "projected_usage.session_replay": 0, + "free_allocation.session_replay": 0, + "percentage_usage.feature_flags": 0, + "current_amount_usd.feature_flags": "0.00", + "unit_amount_usd.feature_flags": null, + "usage_limit.feature_flags": null, + "current_usage.feature_flags": 0, + "projected_usage.feature_flags": 0, + "free_allocation.feature_flags": 0, + "percentage_usage.integrations": 0, + "current_amount_usd.integrations": null, + "unit_amount_usd.integrations": null, + "usage_limit.integrations": 0, + "current_usage.integrations": 0, + "projected_usage.integrations": 0, + "free_allocation.integrations": 0, + "percentage_usage.platform_and_support": 0, + "current_amount_usd.platform_and_support": null, + "unit_amount_usd.platform_and_support": null, + "usage_limit.platform_and_support": 0, + "current_usage.platform_and_support": 0, + "projected_usage.platform_and_support": 0, + "free_allocation.platform_and_support": 0, + "billing_period_start": "2023-10-14T09:22:33.000Z", + "billing_period_end": "2023-11-14T09:22:33.000Z", + "$referrer": "$direct", + "$referring_domain": "$direct", + "query": { + "kind": "HogQLQuery", + "query": "select id, groupArray(pdi.distinct_id) as distinct_ids, properties, is_identified, created_at from persons where pdi.distinct_id={distinct_id} group by id, properties, is_identified, created_at", + "values": { + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI" + } + }, + "duration": 221.60000002384186, + "clickhouse_sql": "SELECT persons.id, groupArray(persons__pdi.distinct_id) AS distinct_ids, persons.properties, persons.is_identified, toTimeZone(persons.created_at, %(hogql_val_0)s) FROM (SELECT person.id, person.properties AS properties, person.is_identified AS is_identified, person.created_at AS created_at FROM person WHERE and(equals(person.team_id, 1), ifNull(in(tuple(person.id, person.version), (SELECT person.id, max(person.version) AS version FROM person WHERE equals(person.team_id, 1) GROUP BY person.id HAVING ifNull(equals(argMax(person.is_deleted, person.version), 0), 0))), 0)) SETTINGS optimize_aggregation_in_order=1) AS persons INNER JOIN (SELECT argMax(person_distinct_id2.person_id, person_distinct_id2.version) AS person_id, person_distinct_id2.distinct_id AS distinct_id FROM person_distinct_id2 WHERE equals(person_distinct_id2.team_id, 1) GROUP BY person_distinct_id2.distinct_id HAVING ifNull(equals(argMax(person_distinct_id2.is_deleted, person_distinct_id2.version), 0), 0)) AS persons__pdi ON equals(persons.id, persons__pdi.person_id) WHERE ifNull(equals(persons__pdi.distinct_id, %(hogql_val_1)s), 0) GROUP BY persons.id, persons.properties, persons.is_identified, toTimeZone(persons.created_at, %(hogql_val_2)s) LIMIT 100 SETTINGS readonly=2, max_execution_time=60, allow_experimental_object_type=1", + "token": "phc_OWGI2wKbfi7rWDZT9wkl8uGcfe0wOGCvflLEZSMiaT0", + "$session_id": "018b4ca0-9686-7b75-ba2e-61e9c0054b65", + "$window_id": "018b4ca0-9686-7b75-ba2e-61ea857e58f0", + "$ip": "127.0.0.1", + "$set": { + "$os": "Mac OS X", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$pathname": "/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$browser_version": 117, + "$referrer": "$direct", + "$referring_domain": "$direct" + }, + "$set_once": { + "$initial_os": "Mac OS X", + "$initial_browser": "Chrome", + "$initial_device_type": "Desktop", + "$initial_current_url": "http://localhost:8000/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$initial_pathname": "/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$initial_browser_version": 117, + "$initial_referrer": "$direct", + "$initial_referring_domain": "$direct" + }, + "$sent_at": "2023-10-20T10:28:00.793000+00:00", + "$geoip_city_name": "Sydney", + "$geoip_country_name": "Australia", + "$geoip_country_code": "AU", + "$geoip_continent_name": "Oceania", + "$geoip_continent_code": "OC", + "$geoip_postal_code": "2000", + "$geoip_latitude": -33.8715, + "$geoip_longitude": 151.2006, + "$geoip_time_zone": "Australia/Sydney", + "$geoip_subdivision_1_code": "NSW", + "$geoip_subdivision_1_name": "New South Wales", + "$plugins_succeeded": ["GeoIP (1)"], + "$plugins_failed": [], + "$plugins_deferred": [], + "$group_3": "018a92f8-b602-0000-75de-4b9073693531", + "$group_2": "018a92f8-afff-0000-efec-ca77de39e384", + "$group_4": "cus_OdSgxxWtHOtq9g", + "$group_1": "http://localhost:8000" + }, + "timestamp": "2023-10-20T10:27:59.734000+00:00", + "uuid": null + }, + { + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "elements": [], + "elements_chain": null, + "event": "person viewed", + "id": "018b4ca0-ac64-7425-ad3b-067188569418", + "person": null, + "properties": { + "$os": "Mac OS X", + "$os_version": "10.15.7", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$host": "localhost:8000", + "$pathname": "/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$browser_version": 117, + "$browser_language": "en-GB", + "$screen_height": 982, + "$screen_width": 1512, + "$viewport_height": 859, + "$viewport_width": 1512, + "$lib": "web", + "$lib_version": "1.84.0", + "$insert_id": "tsn5j4iw9zo6hbti", + "$time": 1697797680.229, + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$device_id": "018a92fd-7b25-7770-a050-577e94fd148c", + "$console_log_recording_enabled_server_side": true, + "$session_recording_recorder_version_server_side": "v2", + "$autocapture_disabled_server_side": false, + "$active_feature_flags": [ + "signup-page-4.0", + "cmd-k-search", + "posthog-3000", + "funnels-cue-opt-out-7301", + "retention-breakdown", + "smoothing-interval", + "billing-limit", + "kafka-inspector", + "historical-exports-v2", + "person-on-events-enabled", + "region-select", + "ingestion-warnings-enabled", + "session-reset-on-load", + "recordings-on-feature-flags", + "auto-rollback-feature-flags", + "onboarding-v2-demo", + "feature-flag-rollout-ux", + "role-based-access", + "query_running_time", + "query-timings", + "recording-debugging", + "enable-prompts", + "feedback-scene", + "early-access-feature", + "early-access-feature-site-button", + "hedgehog-mode-debug", + "auto-redirect", + "session-recording-blob-replay", + "surveys", + "generic-signup-benefits", + "surveys-positions", + "web-analytics", + "high-frequency-batch-exports", + "exception-autocapture", + "data-warehouse", + "data-warehouse-views", + "ff-dashboard-templates", + "show-product-intro-existing-products", + "artificial-hog", + "cs-dashboards", + "product-specific-onboarding", + "redirect-signups-to-instance", + "apps-and-exports-ui", + "survey-nps-results", + "session-recording-allow-v1-snapshots", + "session-replay-cors-proxy", + "webhooks-denylist", + "surveys-site-app-deprecation", + "surveys-multiple-questions", + "surveys-results-visualizations", + "console-recording-search", + "persons-hogql-query", + "notebooks" + ], + "$feature/file-previews": false, + "$feature/signup-page-4.0": "control", + "$feature/hogql-insights": false, + "$feature/cmd-k-search": true, + "$feature/posthog-3000": true, + "$feature/funnels-cue-opt-out-7301": true, + "$feature/retention-breakdown": true, + "$feature/smoothing-interval": true, + "$feature/billing-limit": true, + "$feature/kafka-inspector": true, + "$feature/historical-exports-v2": true, + "$feature/person-on-events-enabled": true, + "$feature/region-select": true, + "$feature/ingestion-warnings-enabled": true, + "$feature/session-reset-on-load": true, + "$feature/recordings-on-feature-flags": true, + "$feature/auto-rollback-feature-flags": true, + "$feature/onboarding-v2-demo": true, + "$feature/feature-flag-rollout-ux": true, + "$feature/role-based-access": true, + "$feature/query_running_time": true, + "$feature/query-timings": true, + "$feature/recording-debugging": true, + "$feature/enable-prompts": true, + "$feature/feedback-scene": true, + "$feature/early-access-feature": true, + "$feature/early-access-feature-site-button": true, + "$feature/hedgehog-mode-debug": true, + "$feature/auto-redirect": true, + "$feature/session-recording-blob-replay": true, + "$feature/surveys": true, + "$feature/generic-signup-benefits": true, + "$feature/surveys-positions": true, + "$feature/web-analytics": true, + "$feature/high-frequency-batch-exports": true, + "$feature/exception-autocapture": true, + "$feature/data-warehouse": true, + "$feature/data-warehouse-views": true, + "$feature/ff-dashboard-templates": true, + "$feature/show-product-intro-existing-products": true, + "$feature/artificial-hog": true, + "$feature/cs-dashboards": true, + "$feature/product-specific-onboarding": true, + "$feature/redirect-signups-to-instance": true, + "$feature/apps-and-exports-ui": true, + "$feature/survey-nps-results": true, + "$feature/session-recording-allow-v1-snapshots": true, + "$feature/session-replay-cors-proxy": true, + "$feature/webhooks-denylist": true, + "$feature/surveys-site-app-deprecation": true, + "$feature/surveys-multiple-questions": true, + "$feature/surveys-results-visualizations": true, + "$feature/console-recording-search": true, + "$feature/persons-hogql-query": true, + "$feature/notebooks": true, + "$feature_flag_payloads": {}, + "realm": "hosted-clickhouse", + "email_service_available": false, + "slack_service_available": false, + "$user_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "is_demo_project": false, + "$groups": { + "project": "018a92f8-b602-0000-75de-4b9073693531", + "organization": "018a92f8-afff-0000-efec-ca77de39e384", + "customer": "cus_OdSgxxWtHOtq9g", + "instance": "http://localhost:8000" + }, + "has_billing_plan": true, + "customer_deactivated": false, + "current_total_amount_usd": "0.00", + "percentage_usage.product_analytics": 0, + "current_amount_usd.product_analytics": "0.00", + "unit_amount_usd.product_analytics": null, + "usage_limit.product_analytics": null, + "current_usage.product_analytics": 3729, + "projected_usage.product_analytics": 0, + "free_allocation.product_analytics": 0, + "percentage_usage.session_replay": 0, + "current_amount_usd.session_replay": "0.00", + "unit_amount_usd.session_replay": null, + "usage_limit.session_replay": null, + "current_usage.session_replay": 254, + "projected_usage.session_replay": 0, + "free_allocation.session_replay": 0, + "percentage_usage.feature_flags": 0, + "current_amount_usd.feature_flags": "0.00", + "unit_amount_usd.feature_flags": null, + "usage_limit.feature_flags": null, + "current_usage.feature_flags": 0, + "projected_usage.feature_flags": 0, + "free_allocation.feature_flags": 0, + "percentage_usage.integrations": 0, + "current_amount_usd.integrations": null, + "unit_amount_usd.integrations": null, + "usage_limit.integrations": 0, + "current_usage.integrations": 0, + "projected_usage.integrations": 0, + "free_allocation.integrations": 0, + "percentage_usage.platform_and_support": 0, + "current_amount_usd.platform_and_support": null, + "unit_amount_usd.platform_and_support": null, + "usage_limit.platform_and_support": 0, + "current_usage.platform_and_support": 0, + "projected_usage.platform_and_support": 0, + "free_allocation.platform_and_support": 0, + "billing_period_start": "2023-10-14T09:22:33.000Z", + "billing_period_end": "2023-11-14T09:22:33.000Z", + "$referrer": "$direct", + "$referring_domain": "$direct", + "properties_count": 40, + "has_email": true, + "has_name": false, + "custom_properties_count": 15, + "posthog_properties_count": 25, + "token": "phc_OWGI2wKbfi7rWDZT9wkl8uGcfe0wOGCvflLEZSMiaT0", + "$session_id": "018b4ca0-9686-7b75-ba2e-61e9c0054b65", + "$window_id": "018b4ca0-9686-7b75-ba2e-61ea857e58f0", + "$ip": "127.0.0.1", + "$set": { + "$os": "Mac OS X", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$pathname": "/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$browser_version": 117, + "$referrer": "$direct", + "$referring_domain": "$direct" + }, + "$set_once": { + "$initial_os": "Mac OS X", + "$initial_browser": "Chrome", + "$initial_device_type": "Desktop", + "$initial_current_url": "http://localhost:8000/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$initial_pathname": "/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$initial_browser_version": 117, + "$initial_referrer": "$direct", + "$initial_referring_domain": "$direct" + }, + "$sent_at": "2023-10-20T10:28:00.793000+00:00", + "$geoip_city_name": "Sydney", + "$geoip_country_name": "Australia", + "$geoip_country_code": "AU", + "$geoip_continent_name": "Oceania", + "$geoip_continent_code": "OC", + "$geoip_postal_code": "2000", + "$geoip_latitude": -33.8715, + "$geoip_longitude": 151.2006, + "$geoip_time_zone": "Australia/Sydney", + "$geoip_subdivision_1_code": "NSW", + "$geoip_subdivision_1_name": "New South Wales", + "$plugins_succeeded": ["GeoIP (1)"], + "$plugins_failed": [], + "$plugins_deferred": [], + "$group_3": "018a92f8-b602-0000-75de-4b9073693531", + "$group_2": "018a92f8-afff-0000-efec-ca77de39e384", + "$group_4": "cus_OdSgxxWtHOtq9g", + "$group_1": "http://localhost:8000" + }, + "timestamp": "2023-10-20T10:28:00.236000+00:00", + "uuid": null + }, + { + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "elements": [ + { + "attr_class": ["LemonTabs__tab-content"], + "attr_id": null, + "attributes": { + "attr__class": "LemonTabs__tab-content" + }, + "href": null, + "nth_child": 1.0, + "nth_of_type": 1.0, + "order": 0.0, + "tag_name": "div", + "text": null + }, + { + "attr_class": ["LemonTabs__tab"], + "attr_id": null, + "attributes": { + "attr__aria-selected": "false", + "attr__class": "LemonTabs__tab", + "attr__role": "tab", + "attr__tabindex": "0" + }, + "href": null, + "nth_child": 1.0, + "nth_of_type": 1.0, + "order": 1.0, + "tag_name": "li", + "text": null + }, + { + "attr_class": ["LemonTabs__bar"], + "attr_id": null, + "attributes": { + "attr__class": "LemonTabs__bar", + "attr__role": "tablist" + }, + "href": null, + "nth_child": 1.0, + "nth_of_type": 1.0, + "order": 2.0, + "tag_name": "ul", + "text": null + }, + { + "attr_class": ["LemonTabs"], + "attr_id": null, + "attributes": { + "attr__class": "LemonTabs", + "attr__data-attr": "persons-tabs", + "attr__style": "--lemon-tabs-slider-width: 66.671875px; --lemon-tabs-slider-offset: 64.0078125px;" + }, + "href": null, + "nth_child": 3.0, + "nth_of_type": 3.0, + "order": 3.0, + "tag_name": "div", + "text": null + }, + { + "attr_class": ["Navigation3000__scene"], + "attr_id": null, + "attributes": { + "attr__class": "Navigation3000__scene" + }, + "href": null, + "nth_child": 2.0, + "nth_of_type": 2.0, + "order": 4.0, + "tag_name": "div", + "text": null + }, + { + "attr_class": null, + "attr_id": null, + "attributes": {}, + "href": null, + "nth_child": 4.0, + "nth_of_type": 1.0, + "order": 5.0, + "tag_name": "main", + "text": null + }, + { + "attr_class": ["Navigation3000"], + "attr_id": null, + "attributes": { + "attr__class": "Navigation3000" + }, + "href": null, + "nth_child": 1.0, + "nth_of_type": 1.0, + "order": 6.0, + "tag_name": "div", + "text": null + }, + { + "attr_class": null, + "attr_id": "root", + "attributes": { + "attr__id": "root" + }, + "href": null, + "nth_child": 4.0, + "nth_of_type": 1.0, + "order": 7.0, + "tag_name": "div", + "text": null + }, + { + "attr_class": ["posthog-3000"], + "attr_id": null, + "attributes": { + "attr__class": "posthog-3000", + "attr__theme": "light" + }, + "href": null, + "nth_child": 2.0, + "nth_of_type": 1.0, + "order": 8.0, + "tag_name": "body", + "text": null + } + ], + "elements_chain": "div.LemonTabs__tab-content:attr__class=\"LemonTabs__tab-content\"nth-child=\"1\"nth-of-type=\"1\";li.LemonTabs__tab:attr__aria-selected=\"false\"attr__class=\"LemonTabs__tab\"attr__role=\"tab\"attr__tabindex=\"0\"nth-child=\"1\"nth-of-type=\"1\";ul.LemonTabs__bar:attr__class=\"LemonTabs__bar\"attr__role=\"tablist\"nth-child=\"1\"nth-of-type=\"1\";div.LemonTabs:attr__class=\"LemonTabs\"attr__data-attr=\"persons-tabs\"attr__style=\"--lemon-tabs-slider-width: 66.671875px; --lemon-tabs-slider-offset: 64.0078125px;\"nth-child=\"3\"nth-of-type=\"3\";div.Navigation3000__scene:attr__class=\"Navigation3000__scene\"nth-child=\"2\"nth-of-type=\"2\";main:nth-child=\"4\"nth-of-type=\"1\";div.Navigation3000:attr__class=\"Navigation3000\"nth-child=\"1\"nth-of-type=\"1\";div:attr__id=\"root\"attr_id=\"root\"nth-child=\"4\"nth-of-type=\"1\";body.posthog-3000:attr__class=\"posthog-3000\"attr__theme=\"light\"nth-child=\"2\"nth-of-type=\"1\"", + "event": "$autocapture", + "id": "018b4ca0-ae21-7de1-bb5d-02e960372d72", + "person": null, + "properties": { + "$os": "Mac OS X", + "$os_version": "10.15.7", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$host": "localhost:8000", + "$pathname": "/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$browser_version": 117, + "$browser_language": "en-GB", + "$screen_height": 982, + "$screen_width": 1512, + "$viewport_height": 859, + "$viewport_width": 1512, + "$lib": "web", + "$lib_version": "1.84.0", + "$insert_id": "4ibu5gfwqj4wlqr7", + "$time": 1697797680.673, + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$device_id": "018a92fd-7b25-7770-a050-577e94fd148c", + "$console_log_recording_enabled_server_side": true, + "$session_recording_recorder_version_server_side": "v2", + "$autocapture_disabled_server_side": false, + "$active_feature_flags": [ + "signup-page-4.0", + "cmd-k-search", + "posthog-3000", + "funnels-cue-opt-out-7301", + "retention-breakdown", + "smoothing-interval", + "billing-limit", + "kafka-inspector", + "historical-exports-v2", + "person-on-events-enabled", + "region-select", + "ingestion-warnings-enabled", + "session-reset-on-load", + "recordings-on-feature-flags", + "auto-rollback-feature-flags", + "onboarding-v2-demo", + "feature-flag-rollout-ux", + "role-based-access", + "query_running_time", + "query-timings", + "recording-debugging", + "enable-prompts", + "feedback-scene", + "early-access-feature", + "early-access-feature-site-button", + "hedgehog-mode-debug", + "auto-redirect", + "session-recording-blob-replay", + "surveys", + "generic-signup-benefits", + "surveys-positions", + "web-analytics", + "high-frequency-batch-exports", + "exception-autocapture", + "data-warehouse", + "data-warehouse-views", + "ff-dashboard-templates", + "show-product-intro-existing-products", + "artificial-hog", + "cs-dashboards", + "product-specific-onboarding", + "redirect-signups-to-instance", + "apps-and-exports-ui", + "survey-nps-results", + "session-recording-allow-v1-snapshots", + "session-replay-cors-proxy", + "webhooks-denylist", + "surveys-site-app-deprecation", + "surveys-multiple-questions", + "surveys-results-visualizations", + "console-recording-search", + "persons-hogql-query", + "notebooks" + ], + "$feature/file-previews": false, + "$feature/signup-page-4.0": "control", + "$feature/hogql-insights": false, + "$feature/cmd-k-search": true, + "$feature/posthog-3000": true, + "$feature/funnels-cue-opt-out-7301": true, + "$feature/retention-breakdown": true, + "$feature/smoothing-interval": true, + "$feature/billing-limit": true, + "$feature/kafka-inspector": true, + "$feature/historical-exports-v2": true, + "$feature/person-on-events-enabled": true, + "$feature/region-select": true, + "$feature/ingestion-warnings-enabled": true, + "$feature/session-reset-on-load": true, + "$feature/recordings-on-feature-flags": true, + "$feature/auto-rollback-feature-flags": true, + "$feature/onboarding-v2-demo": true, + "$feature/feature-flag-rollout-ux": true, + "$feature/role-based-access": true, + "$feature/query_running_time": true, + "$feature/query-timings": true, + "$feature/recording-debugging": true, + "$feature/enable-prompts": true, + "$feature/feedback-scene": true, + "$feature/early-access-feature": true, + "$feature/early-access-feature-site-button": true, + "$feature/hedgehog-mode-debug": true, + "$feature/auto-redirect": true, + "$feature/session-recording-blob-replay": true, + "$feature/surveys": true, + "$feature/generic-signup-benefits": true, + "$feature/surveys-positions": true, + "$feature/web-analytics": true, + "$feature/high-frequency-batch-exports": true, + "$feature/exception-autocapture": true, + "$feature/data-warehouse": true, + "$feature/data-warehouse-views": true, + "$feature/ff-dashboard-templates": true, + "$feature/show-product-intro-existing-products": true, + "$feature/artificial-hog": true, + "$feature/cs-dashboards": true, + "$feature/product-specific-onboarding": true, + "$feature/redirect-signups-to-instance": true, + "$feature/apps-and-exports-ui": true, + "$feature/survey-nps-results": true, + "$feature/session-recording-allow-v1-snapshots": true, + "$feature/session-replay-cors-proxy": true, + "$feature/webhooks-denylist": true, + "$feature/surveys-site-app-deprecation": true, + "$feature/surveys-multiple-questions": true, + "$feature/surveys-results-visualizations": true, + "$feature/console-recording-search": true, + "$feature/persons-hogql-query": true, + "$feature/notebooks": true, + "$feature_flag_payloads": {}, + "realm": "hosted-clickhouse", + "email_service_available": false, + "slack_service_available": false, + "$user_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "is_demo_project": false, + "$groups": { + "project": "018a92f8-b602-0000-75de-4b9073693531", + "organization": "018a92f8-afff-0000-efec-ca77de39e384", + "customer": "cus_OdSgxxWtHOtq9g", + "instance": "http://localhost:8000" + }, + "has_billing_plan": true, + "customer_deactivated": false, + "current_total_amount_usd": "0.00", + "percentage_usage.product_analytics": 0, + "current_amount_usd.product_analytics": "0.00", + "unit_amount_usd.product_analytics": null, + "usage_limit.product_analytics": null, + "current_usage.product_analytics": 3729, + "projected_usage.product_analytics": 0, + "free_allocation.product_analytics": 0, + "percentage_usage.session_replay": 0, + "current_amount_usd.session_replay": "0.00", + "unit_amount_usd.session_replay": null, + "usage_limit.session_replay": null, + "current_usage.session_replay": 254, + "projected_usage.session_replay": 0, + "free_allocation.session_replay": 0, + "percentage_usage.feature_flags": 0, + "current_amount_usd.feature_flags": "0.00", + "unit_amount_usd.feature_flags": null, + "usage_limit.feature_flags": null, + "current_usage.feature_flags": 0, + "projected_usage.feature_flags": 0, + "free_allocation.feature_flags": 0, + "percentage_usage.integrations": 0, + "current_amount_usd.integrations": null, + "unit_amount_usd.integrations": null, + "usage_limit.integrations": 0, + "current_usage.integrations": 0, + "projected_usage.integrations": 0, + "free_allocation.integrations": 0, + "percentage_usage.platform_and_support": 0, + "current_amount_usd.platform_and_support": null, + "unit_amount_usd.platform_and_support": null, + "usage_limit.platform_and_support": 0, + "current_usage.platform_and_support": 0, + "projected_usage.platform_and_support": 0, + "free_allocation.platform_and_support": 0, + "billing_period_start": "2023-10-14T09:22:33.000Z", + "billing_period_end": "2023-11-14T09:22:33.000Z", + "$referrer": "$direct", + "$referring_domain": "$direct", + "$event_type": "click", + "$ce_version": 1, + "token": "phc_OWGI2wKbfi7rWDZT9wkl8uGcfe0wOGCvflLEZSMiaT0", + "$session_id": "018b4ca0-9686-7b75-ba2e-61e9c0054b65", + "$window_id": "018b4ca0-9686-7b75-ba2e-61ea857e58f0", + "$ip": "127.0.0.1", + "$set": { + "$os": "Mac OS X", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$pathname": "/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$browser_version": 117, + "$referrer": "$direct", + "$referring_domain": "$direct" + }, + "$set_once": { + "$initial_os": "Mac OS X", + "$initial_browser": "Chrome", + "$initial_device_type": "Desktop", + "$initial_current_url": "http://localhost:8000/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$initial_pathname": "/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$initial_browser_version": 117, + "$initial_referrer": "$direct", + "$initial_referring_domain": "$direct" + }, + "$sent_at": "2023-10-20T10:28:00.793000+00:00", + "$geoip_city_name": "Sydney", + "$geoip_country_name": "Australia", + "$geoip_country_code": "AU", + "$geoip_continent_name": "Oceania", + "$geoip_continent_code": "OC", + "$geoip_postal_code": "2000", + "$geoip_latitude": -33.8715, + "$geoip_longitude": 151.2006, + "$geoip_time_zone": "Australia/Sydney", + "$geoip_subdivision_1_code": "NSW", + "$geoip_subdivision_1_name": "New South Wales", + "$plugins_succeeded": ["GeoIP (1)"], + "$plugins_failed": [], + "$plugins_deferred": [], + "$group_3": "018a92f8-b602-0000-75de-4b9073693531", + "$group_2": "018a92f8-afff-0000-efec-ca77de39e384", + "$group_4": "cus_OdSgxxWtHOtq9g", + "$group_1": "http://localhost:8000" + }, + "timestamp": "2023-10-20T10:28:00.680000+00:00", + "uuid": null + }, + { + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "elements": [], + "elements_chain": null, + "event": "$pageview", + "id": "018b4ca0-ae26-7bf7-b0bb-65948958a2b2", + "person": null, + "properties": { + "$os": "Mac OS X", + "$os_version": "10.15.7", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI#activeTab=feed", + "$host": "localhost:8000", + "$pathname": "/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$browser_version": 117, + "$browser_language": "en-GB", + "$screen_height": 982, + "$screen_width": 1512, + "$viewport_height": 859, + "$viewport_width": 1512, + "$lib": "web", + "$lib_version": "1.84.0", + "$insert_id": "gt90ymm7l7vaiptd", + "$time": 1697797680.679, + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$device_id": "018a92fd-7b25-7770-a050-577e94fd148c", + "$console_log_recording_enabled_server_side": true, + "$session_recording_recorder_version_server_side": "v2", + "$autocapture_disabled_server_side": false, + "$active_feature_flags": [ + "signup-page-4.0", + "cmd-k-search", + "posthog-3000", + "funnels-cue-opt-out-7301", + "retention-breakdown", + "smoothing-interval", + "billing-limit", + "kafka-inspector", + "historical-exports-v2", + "person-on-events-enabled", + "region-select", + "ingestion-warnings-enabled", + "session-reset-on-load", + "recordings-on-feature-flags", + "auto-rollback-feature-flags", + "onboarding-v2-demo", + "feature-flag-rollout-ux", + "role-based-access", + "query_running_time", + "query-timings", + "recording-debugging", + "enable-prompts", + "feedback-scene", + "early-access-feature", + "early-access-feature-site-button", + "hedgehog-mode-debug", + "auto-redirect", + "session-recording-blob-replay", + "surveys", + "generic-signup-benefits", + "surveys-positions", + "web-analytics", + "high-frequency-batch-exports", + "exception-autocapture", + "data-warehouse", + "data-warehouse-views", + "ff-dashboard-templates", + "show-product-intro-existing-products", + "artificial-hog", + "cs-dashboards", + "product-specific-onboarding", + "redirect-signups-to-instance", + "apps-and-exports-ui", + "survey-nps-results", + "session-recording-allow-v1-snapshots", + "session-replay-cors-proxy", + "webhooks-denylist", + "surveys-site-app-deprecation", + "surveys-multiple-questions", + "surveys-results-visualizations", + "console-recording-search", + "persons-hogql-query", + "notebooks" + ], + "$feature/file-previews": false, + "$feature/signup-page-4.0": "control", + "$feature/hogql-insights": false, + "$feature/cmd-k-search": true, + "$feature/posthog-3000": true, + "$feature/funnels-cue-opt-out-7301": true, + "$feature/retention-breakdown": true, + "$feature/smoothing-interval": true, + "$feature/billing-limit": true, + "$feature/kafka-inspector": true, + "$feature/historical-exports-v2": true, + "$feature/person-on-events-enabled": true, + "$feature/region-select": true, + "$feature/ingestion-warnings-enabled": true, + "$feature/session-reset-on-load": true, + "$feature/recordings-on-feature-flags": true, + "$feature/auto-rollback-feature-flags": true, + "$feature/onboarding-v2-demo": true, + "$feature/feature-flag-rollout-ux": true, + "$feature/role-based-access": true, + "$feature/query_running_time": true, + "$feature/query-timings": true, + "$feature/recording-debugging": true, + "$feature/enable-prompts": true, + "$feature/feedback-scene": true, + "$feature/early-access-feature": true, + "$feature/early-access-feature-site-button": true, + "$feature/hedgehog-mode-debug": true, + "$feature/auto-redirect": true, + "$feature/session-recording-blob-replay": true, + "$feature/surveys": true, + "$feature/generic-signup-benefits": true, + "$feature/surveys-positions": true, + "$feature/web-analytics": true, + "$feature/high-frequency-batch-exports": true, + "$feature/exception-autocapture": true, + "$feature/data-warehouse": true, + "$feature/data-warehouse-views": true, + "$feature/ff-dashboard-templates": true, + "$feature/show-product-intro-existing-products": true, + "$feature/artificial-hog": true, + "$feature/cs-dashboards": true, + "$feature/product-specific-onboarding": true, + "$feature/redirect-signups-to-instance": true, + "$feature/apps-and-exports-ui": true, + "$feature/survey-nps-results": true, + "$feature/session-recording-allow-v1-snapshots": true, + "$feature/session-replay-cors-proxy": true, + "$feature/webhooks-denylist": true, + "$feature/surveys-site-app-deprecation": true, + "$feature/surveys-multiple-questions": true, + "$feature/surveys-results-visualizations": true, + "$feature/console-recording-search": true, + "$feature/persons-hogql-query": true, + "$feature/notebooks": true, + "$feature_flag_payloads": {}, + "realm": "hosted-clickhouse", + "email_service_available": false, + "slack_service_available": false, + "$user_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "is_demo_project": false, + "$groups": { + "project": "018a92f8-b602-0000-75de-4b9073693531", + "organization": "018a92f8-afff-0000-efec-ca77de39e384", + "customer": "cus_OdSgxxWtHOtq9g", + "instance": "http://localhost:8000" + }, + "has_billing_plan": true, + "customer_deactivated": false, + "current_total_amount_usd": "0.00", + "percentage_usage.product_analytics": 0, + "current_amount_usd.product_analytics": "0.00", + "unit_amount_usd.product_analytics": null, + "usage_limit.product_analytics": null, + "current_usage.product_analytics": 3729, + "projected_usage.product_analytics": 0, + "free_allocation.product_analytics": 0, + "percentage_usage.session_replay": 0, + "current_amount_usd.session_replay": "0.00", + "unit_amount_usd.session_replay": null, + "usage_limit.session_replay": null, + "current_usage.session_replay": 254, + "projected_usage.session_replay": 0, + "free_allocation.session_replay": 0, + "percentage_usage.feature_flags": 0, + "current_amount_usd.feature_flags": "0.00", + "unit_amount_usd.feature_flags": null, + "usage_limit.feature_flags": null, + "current_usage.feature_flags": 0, + "projected_usage.feature_flags": 0, + "free_allocation.feature_flags": 0, + "percentage_usage.integrations": 0, + "current_amount_usd.integrations": null, + "unit_amount_usd.integrations": null, + "usage_limit.integrations": 0, + "current_usage.integrations": 0, + "projected_usage.integrations": 0, + "free_allocation.integrations": 0, + "percentage_usage.platform_and_support": 0, + "current_amount_usd.platform_and_support": null, + "unit_amount_usd.platform_and_support": null, + "usage_limit.platform_and_support": 0, + "current_usage.platform_and_support": 0, + "projected_usage.platform_and_support": 0, + "free_allocation.platform_and_support": 0, + "billing_period_start": "2023-10-14T09:22:33.000Z", + "billing_period_end": "2023-11-14T09:22:33.000Z", + "$referrer": "$direct", + "$referring_domain": "$direct", + "token": "phc_OWGI2wKbfi7rWDZT9wkl8uGcfe0wOGCvflLEZSMiaT0", + "$session_id": "018b4ca0-9686-7b75-ba2e-61e9c0054b65", + "$window_id": "018b4ca0-9686-7b75-ba2e-61ea857e58f0", + "title": "test@posthog.com \u2022 Persons \u2022 PostHog", + "$ip": "127.0.0.1", + "$set": { + "$os": "Mac OS X", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI#activeTab=feed", + "$pathname": "/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$browser_version": 117, + "$referrer": "$direct", + "$referring_domain": "$direct" + }, + "$set_once": { + "$initial_os": "Mac OS X", + "$initial_browser": "Chrome", + "$initial_device_type": "Desktop", + "$initial_current_url": "http://localhost:8000/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI#activeTab=feed", + "$initial_pathname": "/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$initial_browser_version": 117, + "$initial_referrer": "$direct", + "$initial_referring_domain": "$direct" + }, + "$sent_at": "2023-10-20T10:28:00.793000+00:00", + "$geoip_city_name": "Sydney", + "$geoip_country_name": "Australia", + "$geoip_country_code": "AU", + "$geoip_continent_name": "Oceania", + "$geoip_continent_code": "OC", + "$geoip_postal_code": "2000", + "$geoip_latitude": -33.8715, + "$geoip_longitude": 151.2006, + "$geoip_time_zone": "Australia/Sydney", + "$geoip_subdivision_1_code": "NSW", + "$geoip_subdivision_1_name": "New South Wales", + "$plugins_succeeded": ["GeoIP (1)"], + "$plugins_failed": [], + "$plugins_deferred": [], + "$group_3": "018a92f8-b602-0000-75de-4b9073693531", + "$group_2": "018a92f8-afff-0000-efec-ca77de39e384", + "$group_4": "cus_OdSgxxWtHOtq9g", + "$group_1": "http://localhost:8000" + }, + "timestamp": "2023-10-20T10:28:00.686000+00:00", + "uuid": null + }, + { + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "elements": [], + "elements_chain": null, + "event": "$feature_flag_called", + "id": "018b4ca0-ae35-7379-9b8c-431bd55514a9", + "person": null, + "properties": { + "$os": "Mac OS X", + "$os_version": "10.15.7", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI#activeTab=feed", + "$host": "localhost:8000", + "$pathname": "/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$browser_version": 117, + "$browser_language": "en-GB", + "$screen_height": 982, + "$screen_width": 1512, + "$viewport_height": 859, + "$viewport_width": 1512, + "$lib": "web", + "$lib_version": "1.84.0", + "$insert_id": "ogr8hhsl0diyzzrf", + "$time": 1697797680.694, + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$device_id": "018a92fd-7b25-7770-a050-577e94fd148c", + "$console_log_recording_enabled_server_side": true, + "$session_recording_recorder_version_server_side": "v2", + "$autocapture_disabled_server_side": false, + "$active_feature_flags": [ + "signup-page-4.0", + "cmd-k-search", + "posthog-3000", + "funnels-cue-opt-out-7301", + "retention-breakdown", + "smoothing-interval", + "billing-limit", + "kafka-inspector", + "historical-exports-v2", + "person-on-events-enabled", + "region-select", + "ingestion-warnings-enabled", + "session-reset-on-load", + "recordings-on-feature-flags", + "auto-rollback-feature-flags", + "onboarding-v2-demo", + "feature-flag-rollout-ux", + "role-based-access", + "query_running_time", + "query-timings", + "recording-debugging", + "enable-prompts", + "feedback-scene", + "early-access-feature", + "early-access-feature-site-button", + "hedgehog-mode-debug", + "auto-redirect", + "session-recording-blob-replay", + "surveys", + "generic-signup-benefits", + "surveys-positions", + "web-analytics", + "high-frequency-batch-exports", + "exception-autocapture", + "data-warehouse", + "data-warehouse-views", + "ff-dashboard-templates", + "show-product-intro-existing-products", + "artificial-hog", + "cs-dashboards", + "product-specific-onboarding", + "redirect-signups-to-instance", + "apps-and-exports-ui", + "survey-nps-results", + "session-recording-allow-v1-snapshots", + "session-replay-cors-proxy", + "webhooks-denylist", + "surveys-site-app-deprecation", + "surveys-multiple-questions", + "surveys-results-visualizations", + "console-recording-search", + "persons-hogql-query", + "notebooks" + ], + "$feature/file-previews": false, + "$feature/signup-page-4.0": "control", + "$feature/hogql-insights": false, + "$feature/cmd-k-search": true, + "$feature/posthog-3000": true, + "$feature/funnels-cue-opt-out-7301": true, + "$feature/retention-breakdown": true, + "$feature/smoothing-interval": true, + "$feature/billing-limit": true, + "$feature/kafka-inspector": true, + "$feature/historical-exports-v2": true, + "$feature/person-on-events-enabled": true, + "$feature/region-select": true, + "$feature/ingestion-warnings-enabled": true, + "$feature/session-reset-on-load": true, + "$feature/recordings-on-feature-flags": true, + "$feature/auto-rollback-feature-flags": true, + "$feature/onboarding-v2-demo": true, + "$feature/feature-flag-rollout-ux": true, + "$feature/role-based-access": true, + "$feature/query_running_time": true, + "$feature/query-timings": true, + "$feature/recording-debugging": true, + "$feature/enable-prompts": true, + "$feature/feedback-scene": true, + "$feature/early-access-feature": true, + "$feature/early-access-feature-site-button": true, + "$feature/hedgehog-mode-debug": true, + "$feature/auto-redirect": true, + "$feature/session-recording-blob-replay": true, + "$feature/surveys": true, + "$feature/generic-signup-benefits": true, + "$feature/surveys-positions": true, + "$feature/web-analytics": true, + "$feature/high-frequency-batch-exports": true, + "$feature/exception-autocapture": true, + "$feature/data-warehouse": true, + "$feature/data-warehouse-views": true, + "$feature/ff-dashboard-templates": true, + "$feature/show-product-intro-existing-products": true, + "$feature/artificial-hog": true, + "$feature/cs-dashboards": true, + "$feature/product-specific-onboarding": true, + "$feature/redirect-signups-to-instance": true, + "$feature/apps-and-exports-ui": true, + "$feature/survey-nps-results": true, + "$feature/session-recording-allow-v1-snapshots": true, + "$feature/session-replay-cors-proxy": true, + "$feature/webhooks-denylist": true, + "$feature/surveys-site-app-deprecation": true, + "$feature/surveys-multiple-questions": true, + "$feature/surveys-results-visualizations": true, + "$feature/console-recording-search": true, + "$feature/persons-hogql-query": true, + "$feature/notebooks": true, + "$feature_flag_payloads": {}, + "realm": "hosted-clickhouse", + "email_service_available": false, + "slack_service_available": false, + "$user_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "is_demo_project": false, + "$groups": { + "project": "018a92f8-b602-0000-75de-4b9073693531", + "organization": "018a92f8-afff-0000-efec-ca77de39e384", + "customer": "cus_OdSgxxWtHOtq9g", + "instance": "http://localhost:8000" + }, + "has_billing_plan": true, + "customer_deactivated": false, + "current_total_amount_usd": "0.00", + "percentage_usage.product_analytics": 0, + "current_amount_usd.product_analytics": "0.00", + "unit_amount_usd.product_analytics": null, + "usage_limit.product_analytics": null, + "current_usage.product_analytics": 3729, + "projected_usage.product_analytics": 0, + "free_allocation.product_analytics": 0, + "percentage_usage.session_replay": 0, + "current_amount_usd.session_replay": "0.00", + "unit_amount_usd.session_replay": null, + "usage_limit.session_replay": null, + "current_usage.session_replay": 254, + "projected_usage.session_replay": 0, + "free_allocation.session_replay": 0, + "percentage_usage.feature_flags": 0, + "current_amount_usd.feature_flags": "0.00", + "unit_amount_usd.feature_flags": null, + "usage_limit.feature_flags": null, + "current_usage.feature_flags": 0, + "projected_usage.feature_flags": 0, + "free_allocation.feature_flags": 0, + "percentage_usage.integrations": 0, + "current_amount_usd.integrations": null, + "unit_amount_usd.integrations": null, + "usage_limit.integrations": 0, + "current_usage.integrations": 0, + "projected_usage.integrations": 0, + "free_allocation.integrations": 0, + "percentage_usage.platform_and_support": 0, + "current_amount_usd.platform_and_support": null, + "unit_amount_usd.platform_and_support": null, + "usage_limit.platform_and_support": 0, + "current_usage.platform_and_support": 0, + "projected_usage.platform_and_support": 0, + "free_allocation.platform_and_support": 0, + "billing_period_start": "2023-10-14T09:22:33.000Z", + "billing_period_end": "2023-11-14T09:22:33.000Z", + "$referrer": "$direct", + "$referring_domain": "$direct", + "$feature_flag": "debug-react-renders", + "$feature_flag_response": false, + "token": "phc_OWGI2wKbfi7rWDZT9wkl8uGcfe0wOGCvflLEZSMiaT0", + "$session_id": "018b4ca0-9686-7b75-ba2e-61e9c0054b65", + "$window_id": "018b4ca0-9686-7b75-ba2e-61ea857e58f0", + "$ip": "127.0.0.1", + "$set": { + "$os": "Mac OS X", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI#activeTab=feed", + "$pathname": "/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$browser_version": 117, + "$referrer": "$direct", + "$referring_domain": "$direct" + }, + "$set_once": { + "$initial_os": "Mac OS X", + "$initial_browser": "Chrome", + "$initial_device_type": "Desktop", + "$initial_current_url": "http://localhost:8000/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI#activeTab=feed", + "$initial_pathname": "/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$initial_browser_version": 117, + "$initial_referrer": "$direct", + "$initial_referring_domain": "$direct" + }, + "$sent_at": "2023-10-20T10:28:00.793000+00:00", + "$geoip_city_name": "Sydney", + "$geoip_country_name": "Australia", + "$geoip_country_code": "AU", + "$geoip_continent_name": "Oceania", + "$geoip_continent_code": "OC", + "$geoip_postal_code": "2000", + "$geoip_latitude": -33.8715, + "$geoip_longitude": 151.2006, + "$geoip_time_zone": "Australia/Sydney", + "$geoip_subdivision_1_code": "NSW", + "$geoip_subdivision_1_name": "New South Wales", + "$plugins_succeeded": ["GeoIP (1)"], + "$plugins_failed": [], + "$plugins_deferred": [], + "$group_3": "018a92f8-b602-0000-75de-4b9073693531", + "$group_2": "018a92f8-afff-0000-efec-ca77de39e384", + "$group_4": "cus_OdSgxxWtHOtq9g", + "$group_1": "http://localhost:8000" + }, + "timestamp": "2023-10-20T10:28:00.701000+00:00", + "uuid": null + }, + { + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "elements": [], + "elements_chain": null, + "event": "query completed", + "id": "018b4ca0-b109-79b8-98c9-2d69c5db0935", + "person": null, + "properties": { + "$os": "Mac OS X", + "$os_version": "10.15.7", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI#activeTab=feed", + "$host": "localhost:8000", + "$pathname": "/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$browser_version": 117, + "$browser_language": "en-GB", + "$screen_height": 982, + "$screen_width": 1512, + "$viewport_height": 859, + "$viewport_width": 1512, + "$lib": "web", + "$lib_version": "1.84.0", + "$insert_id": "0flk4pc1i44w8cgq", + "$time": 1697797681.417, + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$device_id": "018a92fd-7b25-7770-a050-577e94fd148c", + "$console_log_recording_enabled_server_side": true, + "$session_recording_recorder_version_server_side": "v2", + "$autocapture_disabled_server_side": false, + "$active_feature_flags": [ + "signup-page-4.0", + "cmd-k-search", + "posthog-3000", + "funnels-cue-opt-out-7301", + "retention-breakdown", + "smoothing-interval", + "billing-limit", + "kafka-inspector", + "historical-exports-v2", + "person-on-events-enabled", + "region-select", + "ingestion-warnings-enabled", + "session-reset-on-load", + "recordings-on-feature-flags", + "auto-rollback-feature-flags", + "onboarding-v2-demo", + "feature-flag-rollout-ux", + "role-based-access", + "query_running_time", + "query-timings", + "recording-debugging", + "enable-prompts", + "feedback-scene", + "early-access-feature", + "early-access-feature-site-button", + "hedgehog-mode-debug", + "auto-redirect", + "session-recording-blob-replay", + "surveys", + "generic-signup-benefits", + "surveys-positions", + "web-analytics", + "high-frequency-batch-exports", + "exception-autocapture", + "data-warehouse", + "data-warehouse-views", + "ff-dashboard-templates", + "show-product-intro-existing-products", + "artificial-hog", + "cs-dashboards", + "product-specific-onboarding", + "redirect-signups-to-instance", + "apps-and-exports-ui", + "survey-nps-results", + "session-recording-allow-v1-snapshots", + "session-replay-cors-proxy", + "webhooks-denylist", + "surveys-site-app-deprecation", + "surveys-multiple-questions", + "surveys-results-visualizations", + "console-recording-search", + "persons-hogql-query", + "notebooks" + ], + "$feature/file-previews": false, + "$feature/signup-page-4.0": "control", + "$feature/hogql-insights": false, + "$feature/cmd-k-search": true, + "$feature/posthog-3000": true, + "$feature/funnels-cue-opt-out-7301": true, + "$feature/retention-breakdown": true, + "$feature/smoothing-interval": true, + "$feature/billing-limit": true, + "$feature/kafka-inspector": true, + "$feature/historical-exports-v2": true, + "$feature/person-on-events-enabled": true, + "$feature/region-select": true, + "$feature/ingestion-warnings-enabled": true, + "$feature/session-reset-on-load": true, + "$feature/recordings-on-feature-flags": true, + "$feature/auto-rollback-feature-flags": true, + "$feature/onboarding-v2-demo": true, + "$feature/feature-flag-rollout-ux": true, + "$feature/role-based-access": true, + "$feature/query_running_time": true, + "$feature/query-timings": true, + "$feature/recording-debugging": true, + "$feature/enable-prompts": true, + "$feature/feedback-scene": true, + "$feature/early-access-feature": true, + "$feature/early-access-feature-site-button": true, + "$feature/hedgehog-mode-debug": true, + "$feature/auto-redirect": true, + "$feature/session-recording-blob-replay": true, + "$feature/surveys": true, + "$feature/generic-signup-benefits": true, + "$feature/surveys-positions": true, + "$feature/web-analytics": true, + "$feature/high-frequency-batch-exports": true, + "$feature/exception-autocapture": true, + "$feature/data-warehouse": true, + "$feature/data-warehouse-views": true, + "$feature/ff-dashboard-templates": true, + "$feature/show-product-intro-existing-products": true, + "$feature/artificial-hog": true, + "$feature/cs-dashboards": true, + "$feature/product-specific-onboarding": true, + "$feature/redirect-signups-to-instance": true, + "$feature/apps-and-exports-ui": true, + "$feature/survey-nps-results": true, + "$feature/session-recording-allow-v1-snapshots": true, + "$feature/session-replay-cors-proxy": true, + "$feature/webhooks-denylist": true, + "$feature/surveys-site-app-deprecation": true, + "$feature/surveys-multiple-questions": true, + "$feature/surveys-results-visualizations": true, + "$feature/console-recording-search": true, + "$feature/persons-hogql-query": true, + "$feature/notebooks": true, + "$feature_flag_payloads": {}, + "realm": "hosted-clickhouse", + "email_service_available": false, + "slack_service_available": false, + "$user_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "is_demo_project": false, + "$groups": { + "project": "018a92f8-b602-0000-75de-4b9073693531", + "organization": "018a92f8-afff-0000-efec-ca77de39e384", + "customer": "cus_OdSgxxWtHOtq9g", + "instance": "http://localhost:8000" + }, + "has_billing_plan": true, + "customer_deactivated": false, + "current_total_amount_usd": "0.00", + "percentage_usage.product_analytics": 0, + "current_amount_usd.product_analytics": "0.00", + "unit_amount_usd.product_analytics": null, + "usage_limit.product_analytics": null, + "current_usage.product_analytics": 3729, + "projected_usage.product_analytics": 0, + "free_allocation.product_analytics": 0, + "percentage_usage.session_replay": 0, + "current_amount_usd.session_replay": "0.00", + "unit_amount_usd.session_replay": null, + "usage_limit.session_replay": null, + "current_usage.session_replay": 254, + "projected_usage.session_replay": 0, + "free_allocation.session_replay": 0, + "percentage_usage.feature_flags": 0, + "current_amount_usd.feature_flags": "0.00", + "unit_amount_usd.feature_flags": null, + "usage_limit.feature_flags": null, + "current_usage.feature_flags": 0, + "projected_usage.feature_flags": 0, + "free_allocation.feature_flags": 0, + "percentage_usage.integrations": 0, + "current_amount_usd.integrations": null, + "unit_amount_usd.integrations": null, + "usage_limit.integrations": 0, + "current_usage.integrations": 0, + "projected_usage.integrations": 0, + "free_allocation.integrations": 0, + "percentage_usage.platform_and_support": 0, + "current_amount_usd.platform_and_support": null, + "unit_amount_usd.platform_and_support": null, + "usage_limit.platform_and_support": 0, + "current_usage.platform_and_support": 0, + "projected_usage.platform_and_support": 0, + "free_allocation.platform_and_support": 0, + "billing_period_start": "2023-10-14T09:22:33.000Z", + "billing_period_end": "2023-11-14T09:22:33.000Z", + "$referrer": "$direct", + "$referring_domain": "$direct", + "query": { + "kind": "SessionsTimelineQuery", + "after": "2021-01-01T18:00:00Z", + "before": "2024-01-01T06:00:00Z", + "personId": "018a92fd-a1c3-0000-4144-fb39888c298e" + }, + "duration": 476.5999999642372, + "token": "phc_OWGI2wKbfi7rWDZT9wkl8uGcfe0wOGCvflLEZSMiaT0", + "$session_id": "018b4ca0-9686-7b75-ba2e-61e9c0054b65", + "$window_id": "018b4ca0-9686-7b75-ba2e-61ea857e58f0", + "$ip": "127.0.0.1", + "$set": { + "$os": "Mac OS X", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI#activeTab=feed", + "$pathname": "/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$browser_version": 117, + "$referrer": "$direct", + "$referring_domain": "$direct" + }, + "$set_once": { + "$initial_os": "Mac OS X", + "$initial_browser": "Chrome", + "$initial_device_type": "Desktop", + "$initial_current_url": "http://localhost:8000/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI#activeTab=feed", + "$initial_pathname": "/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$initial_browser_version": 117, + "$initial_referrer": "$direct", + "$initial_referring_domain": "$direct" + }, + "$sent_at": "2023-10-20T10:28:03.798000+00:00", + "$geoip_city_name": "Sydney", + "$geoip_country_name": "Australia", + "$geoip_country_code": "AU", + "$geoip_continent_name": "Oceania", + "$geoip_continent_code": "OC", + "$geoip_postal_code": "2000", + "$geoip_latitude": -33.8715, + "$geoip_longitude": 151.2006, + "$geoip_time_zone": "Australia/Sydney", + "$geoip_subdivision_1_code": "NSW", + "$geoip_subdivision_1_name": "New South Wales", + "$plugins_succeeded": ["GeoIP (1)"], + "$plugins_failed": [], + "$plugins_deferred": [], + "$group_3": "018a92f8-b602-0000-75de-4b9073693531", + "$group_2": "018a92f8-afff-0000-efec-ca77de39e384", + "$group_4": "cus_OdSgxxWtHOtq9g", + "$group_1": "http://localhost:8000" + }, + "timestamp": "2023-10-20T10:28:01.427000+00:00", + "uuid": null + }, + { + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "elements": [], + "elements_chain": null, + "event": "notebook content changed", + "id": "018b4ca0-b25b-74ef-9d18-248c54b956bf", + "person": null, + "properties": { + "$os": "Mac OS X", + "$os_version": "10.15.7", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI#activeTab=feed&state=eyJ0eXBlIjoiZG9jIiwiY29udGVudCI6W3sidHlwZSI6ImhlYWRpbmciLCJhdHRycyI6eyJsZXZlbCI6MX0sImNvbnRlbnQiOlt7InR5cGUiOiJ0ZXh0IiwidGV4dCI6ImtyUmZnb3BzVXkxVHdOVTF5aFNETHFORFRkNk41dE1ackhsbThuTEpJREkifV19LHsidHlwZSI6InBoLXBlcnNvbi1mZWVkIiwiYXR0cnMiOnsiaGVpZ2h0IjpudWxsLCJ0aXRsZSI6bnVsbCwibm9kZUlkIjoiNmQ0ODUwNjYtZWM5OS00ODNkLThiOTgtNGQ4YTJkYzljYzRiIiwiaWQiOiJrclJmZ29wc1V5MVR3TlUxeWhTRExxTkRUZDZONXRNWnJIbG04bkxKSURJIiwiX19pbml0IjpudWxsLCJjaGlsZHJlbiI6W3sidHlwZSI6InBoLXBlcnNvbiIsImF0dHJzIjp7ImlkIjoia3JSZmdvcHNVeTFUd05VMXloU0RMcU5EVGQ2TjV0TVpySGxtOG5MSklESSIsIm5vZGVJZCI6IjNkMzZiZjU3LTFkYjQtNDJlZi1iNzhiLWUyZDNkNGViOWM5NSJ9fSx7InR5cGUiOiJwaC1tYXAiLCJhdHRycyI6eyJpZCI6ImtyUmZnb3BzVXkxVHdOVTF5aFNETHFORFRkNk41dE1ackhsbThuTEpJREkiLCJub2RlSWQiOiI1MzE0ZWI2MS1lYTA2LTQyOGQtYWEzZi0zMDA4OWJjZmUxYjgifX0seyJ0eXBlIjoicGgtcHJvcGVydGllcyIsImF0dHJzIjp7ImlkIjoia3JSZmdvcHNVeTFUd05VMXloU0RMcU5EVGQ2TjV0TVpySGxtOG5MSklESSIsIm5vZGVJZCI6ImUwMjE1NDU5LWY0YTgtNGJjNy04NDhmLTYxODE1NzY1NzlmNyJ9fV19fV19", + "$host": "localhost:8000", + "$pathname": "/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$browser_version": 117, + "$browser_language": "en-GB", + "$screen_height": 982, + "$screen_width": 1512, + "$viewport_height": 859, + "$viewport_width": 1512, + "$lib": "web", + "$lib_version": "1.84.0", + "$insert_id": "qoao0ux8ldt09rzp", + "$time": 1697797681.755, + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$device_id": "018a92fd-7b25-7770-a050-577e94fd148c", + "$console_log_recording_enabled_server_side": true, + "$session_recording_recorder_version_server_side": "v2", + "$autocapture_disabled_server_side": false, + "$active_feature_flags": [ + "signup-page-4.0", + "cmd-k-search", + "posthog-3000", + "funnels-cue-opt-out-7301", + "retention-breakdown", + "smoothing-interval", + "billing-limit", + "kafka-inspector", + "historical-exports-v2", + "person-on-events-enabled", + "region-select", + "ingestion-warnings-enabled", + "session-reset-on-load", + "recordings-on-feature-flags", + "auto-rollback-feature-flags", + "onboarding-v2-demo", + "feature-flag-rollout-ux", + "role-based-access", + "query_running_time", + "query-timings", + "recording-debugging", + "enable-prompts", + "feedback-scene", + "early-access-feature", + "early-access-feature-site-button", + "hedgehog-mode-debug", + "auto-redirect", + "session-recording-blob-replay", + "surveys", + "generic-signup-benefits", + "surveys-positions", + "web-analytics", + "high-frequency-batch-exports", + "exception-autocapture", + "data-warehouse", + "data-warehouse-views", + "ff-dashboard-templates", + "show-product-intro-existing-products", + "artificial-hog", + "cs-dashboards", + "product-specific-onboarding", + "redirect-signups-to-instance", + "apps-and-exports-ui", + "survey-nps-results", + "session-recording-allow-v1-snapshots", + "session-replay-cors-proxy", + "webhooks-denylist", + "surveys-site-app-deprecation", + "surveys-multiple-questions", + "surveys-results-visualizations", + "console-recording-search", + "persons-hogql-query", + "notebooks" + ], + "$feature/file-previews": false, + "$feature/signup-page-4.0": "control", + "$feature/hogql-insights": false, + "$feature/cmd-k-search": true, + "$feature/posthog-3000": true, + "$feature/funnels-cue-opt-out-7301": true, + "$feature/retention-breakdown": true, + "$feature/smoothing-interval": true, + "$feature/billing-limit": true, + "$feature/kafka-inspector": true, + "$feature/historical-exports-v2": true, + "$feature/person-on-events-enabled": true, + "$feature/region-select": true, + "$feature/ingestion-warnings-enabled": true, + "$feature/session-reset-on-load": true, + "$feature/recordings-on-feature-flags": true, + "$feature/auto-rollback-feature-flags": true, + "$feature/onboarding-v2-demo": true, + "$feature/feature-flag-rollout-ux": true, + "$feature/role-based-access": true, + "$feature/query_running_time": true, + "$feature/query-timings": true, + "$feature/recording-debugging": true, + "$feature/enable-prompts": true, + "$feature/feedback-scene": true, + "$feature/early-access-feature": true, + "$feature/early-access-feature-site-button": true, + "$feature/hedgehog-mode-debug": true, + "$feature/auto-redirect": true, + "$feature/session-recording-blob-replay": true, + "$feature/surveys": true, + "$feature/generic-signup-benefits": true, + "$feature/surveys-positions": true, + "$feature/web-analytics": true, + "$feature/high-frequency-batch-exports": true, + "$feature/exception-autocapture": true, + "$feature/data-warehouse": true, + "$feature/data-warehouse-views": true, + "$feature/ff-dashboard-templates": true, + "$feature/show-product-intro-existing-products": true, + "$feature/artificial-hog": true, + "$feature/cs-dashboards": true, + "$feature/product-specific-onboarding": true, + "$feature/redirect-signups-to-instance": true, + "$feature/apps-and-exports-ui": true, + "$feature/survey-nps-results": true, + "$feature/session-recording-allow-v1-snapshots": true, + "$feature/session-replay-cors-proxy": true, + "$feature/webhooks-denylist": true, + "$feature/surveys-site-app-deprecation": true, + "$feature/surveys-multiple-questions": true, + "$feature/surveys-results-visualizations": true, + "$feature/console-recording-search": true, + "$feature/persons-hogql-query": true, + "$feature/notebooks": true, + "$feature_flag_payloads": {}, + "realm": "hosted-clickhouse", + "email_service_available": false, + "slack_service_available": false, + "$user_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "is_demo_project": false, + "$groups": { + "project": "018a92f8-b602-0000-75de-4b9073693531", + "organization": "018a92f8-afff-0000-efec-ca77de39e384", + "customer": "cus_OdSgxxWtHOtq9g", + "instance": "http://localhost:8000" + }, + "has_billing_plan": true, + "customer_deactivated": false, + "current_total_amount_usd": "0.00", + "percentage_usage.product_analytics": 0, + "current_amount_usd.product_analytics": "0.00", + "unit_amount_usd.product_analytics": null, + "usage_limit.product_analytics": null, + "current_usage.product_analytics": 3729, + "projected_usage.product_analytics": 0, + "free_allocation.product_analytics": 0, + "percentage_usage.session_replay": 0, + "current_amount_usd.session_replay": "0.00", + "unit_amount_usd.session_replay": null, + "usage_limit.session_replay": null, + "current_usage.session_replay": 254, + "projected_usage.session_replay": 0, + "free_allocation.session_replay": 0, + "percentage_usage.feature_flags": 0, + "current_amount_usd.feature_flags": "0.00", + "unit_amount_usd.feature_flags": null, + "usage_limit.feature_flags": null, + "current_usage.feature_flags": 0, + "projected_usage.feature_flags": 0, + "free_allocation.feature_flags": 0, + "percentage_usage.integrations": 0, + "current_amount_usd.integrations": null, + "unit_amount_usd.integrations": null, + "usage_limit.integrations": 0, + "current_usage.integrations": 0, + "projected_usage.integrations": 0, + "free_allocation.integrations": 0, + "percentage_usage.platform_and_support": 0, + "current_amount_usd.platform_and_support": null, + "unit_amount_usd.platform_and_support": null, + "usage_limit.platform_and_support": 0, + "current_usage.platform_and_support": 0, + "projected_usage.platform_and_support": 0, + "free_allocation.platform_and_support": 0, + "billing_period_start": "2023-10-14T09:22:33.000Z", + "billing_period_end": "2023-11-14T09:22:33.000Z", + "$referrer": "$direct", + "$referring_domain": "$direct", + "token": "phc_OWGI2wKbfi7rWDZT9wkl8uGcfe0wOGCvflLEZSMiaT0", + "$session_id": "018b4ca0-9686-7b75-ba2e-61e9c0054b65", + "$window_id": "018b4ca0-9686-7b75-ba2e-61ea857e58f0", + "$ip": "127.0.0.1", + "$set": { + "$os": "Mac OS X", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI#activeTab=feed&state=eyJ0eXBlIjoiZG9jIiwiY29udGVudCI6W3sidHlwZSI6ImhlYWRpbmciLCJhdHRycyI6eyJsZXZlbCI6MX0sImNvbnRlbnQiOlt7InR5cGUiOiJ0ZXh0IiwidGV4dCI6ImtyUmZnb3BzVXkxVHdOVTF5aFNETHFORFRkNk41dE1ackhsbThuTEpJREkifV19LHsidHlwZSI6InBoLXBlcnNvbi1mZWVkIiwiYXR0cnMiOnsiaGVpZ2h0IjpudWxsLCJ0aXRsZSI6bnVsbCwibm9kZUlkIjoiNmQ0ODUwNjYtZWM5OS00ODNkLThiOTgtNGQ4YTJkYzljYzRiIiwiaWQiOiJrclJmZ29wc1V5MVR3TlUxeWhTRExxTkRUZDZONXRNWnJIbG04bkxKSURJIiwiX19pbml0IjpudWxsLCJjaGlsZHJlbiI6W3sidHlwZSI6InBoLXBlcnNvbiIsImF0dHJzIjp7ImlkIjoia3JSZmdvcHNVeTFUd05VMXloU0RMcU5EVGQ2TjV0TVpySGxtOG5MSklESSIsIm5vZGVJZCI6IjNkMzZiZjU3LTFkYjQtNDJlZi1iNzhiLWUyZDNkNGViOWM5NSJ9fSx7InR5cGUiOiJwaC1tYXAiLCJhdHRycyI6eyJpZCI6ImtyUmZnb3BzVXkxVHdOVTF5aFNETHFORFRkNk41dE1ackhsbThuTEpJREkiLCJub2RlSWQiOiI1MzE0ZWI2MS1lYTA2LTQyOGQtYWEzZi0zMDA4OWJjZmUxYjgifX0seyJ0eXBlIjoicGgtcHJvcGVydGllcyIsImF0dHJzIjp7ImlkIjoia3JSZmdvcHNVeTFUd05VMXloU0RMcU5EVGQ2TjV0TVpySGxtOG5MSklESSIsIm5vZGVJZCI6ImUwMjE1NDU5LWY0YTgtNGJjNy04NDhmLTYxODE1NzY1NzlmNyJ9fV19fV19", + "$pathname": "/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$browser_version": 117, + "$referrer": "$direct", + "$referring_domain": "$direct" + }, + "$set_once": { + "$initial_os": "Mac OS X", + "$initial_browser": "Chrome", + "$initial_device_type": "Desktop", + "$initial_current_url": "http://localhost:8000/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI#activeTab=feed&state=eyJ0eXBlIjoiZG9jIiwiY29udGVudCI6W3sidHlwZSI6ImhlYWRpbmciLCJhdHRycyI6eyJsZXZlbCI6MX0sImNvbnRlbnQiOlt7InR5cGUiOiJ0ZXh0IiwidGV4dCI6ImtyUmZnb3BzVXkxVHdOVTF5aFNETHFORFRkNk41dE1ackhsbThuTEpJREkifV19LHsidHlwZSI6InBoLXBlcnNvbi1mZWVkIiwiYXR0cnMiOnsiaGVpZ2h0IjpudWxsLCJ0aXRsZSI6bnVsbCwibm9kZUlkIjoiNmQ0ODUwNjYtZWM5OS00ODNkLThiOTgtNGQ4YTJkYzljYzRiIiwiaWQiOiJrclJmZ29wc1V5MVR3TlUxeWhTRExxTkRUZDZONXRNWnJIbG04bkxKSURJIiwiX19pbml0IjpudWxsLCJjaGlsZHJlbiI6W3sidHlwZSI6InBoLXBlcnNvbiIsImF0dHJzIjp7ImlkIjoia3JSZmdvcHNVeTFUd05VMXloU0RMcU5EVGQ2TjV0TVpySGxtOG5MSklESSIsIm5vZGVJZCI6IjNkMzZiZjU3LTFkYjQtNDJlZi1iNzhiLWUyZDNkNGViOWM5NSJ9fSx7InR5cGUiOiJwaC1tYXAiLCJhdHRycyI6eyJpZCI6ImtyUmZnb3BzVXkxVHdOVTF5aFNETHFORFRkNk41dE1ackhsbThuTEpJREkiLCJub2RlSWQiOiI1MzE0ZWI2MS1lYTA2LTQyOGQtYWEzZi0zMDA4OWJjZmUxYjgifX0seyJ0eXBlIjoicGgtcHJvcGVydGllcyIsImF0dHJzIjp7ImlkIjoia3JSZmdvcHNVeTFUd05VMXloU0RMcU5EVGQ2TjV0TVpySGxtOG5MSklESSIsIm5vZGVJZCI6ImUwMjE1NDU5LWY0YTgtNGJjNy04NDhmLTYxODE1NzY1NzlmNyJ9fV19fV19", + "$initial_pathname": "/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$initial_browser_version": 117, + "$initial_referrer": "$direct", + "$initial_referring_domain": "$direct" + }, + "$sent_at": "2023-10-20T10:28:03.798000+00:00", + "$geoip_city_name": "Sydney", + "$geoip_country_name": "Australia", + "$geoip_country_code": "AU", + "$geoip_continent_name": "Oceania", + "$geoip_continent_code": "OC", + "$geoip_postal_code": "2000", + "$geoip_latitude": -33.8715, + "$geoip_longitude": 151.2006, + "$geoip_time_zone": "Australia/Sydney", + "$geoip_subdivision_1_code": "NSW", + "$geoip_subdivision_1_name": "New South Wales", + "$plugins_succeeded": ["GeoIP (1)"], + "$plugins_failed": [], + "$plugins_deferred": [], + "$group_3": "018a92f8-b602-0000-75de-4b9073693531", + "$group_2": "018a92f8-afff-0000-efec-ca77de39e384", + "$group_4": "cus_OdSgxxWtHOtq9g", + "$group_1": "http://localhost:8000" + }, + "timestamp": "2023-10-20T10:28:01.765000+00:00", + "uuid": null + }, + { + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "elements": [], + "elements_chain": null, + "event": "$pageview", + "id": "018b4ca0-b25b-74ef-9d18-248b29df99ce", + "person": null, + "properties": { + "$os": "Mac OS X", + "$os_version": "10.15.7", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI#activeTab=feed&state=eyJ0eXBlIjoiZG9jIiwiY29udGVudCI6W3sidHlwZSI6ImhlYWRpbmciLCJhdHRycyI6eyJsZXZlbCI6MX0sImNvbnRlbnQiOlt7InR5cGUiOiJ0ZXh0IiwidGV4dCI6ImtyUmZnb3BzVXkxVHdOVTF5aFNETHFORFRkNk41dE1ackhsbThuTEpJREkifV19LHsidHlwZSI6InBoLXBlcnNvbi1mZWVkIiwiYXR0cnMiOnsiaGVpZ2h0IjpudWxsLCJ0aXRsZSI6bnVsbCwibm9kZUlkIjoiNmQ0ODUwNjYtZWM5OS00ODNkLThiOTgtNGQ4YTJkYzljYzRiIiwiaWQiOiJrclJmZ29wc1V5MVR3TlUxeWhTRExxTkRUZDZONXRNWnJIbG04bkxKSURJIiwiX19pbml0IjpudWxsLCJjaGlsZHJlbiI6W3sidHlwZSI6InBoLXBlcnNvbiIsImF0dHJzIjp7ImlkIjoia3JSZmdvcHNVeTFUd05VMXloU0RMcU5EVGQ2TjV0TVpySGxtOG5MSklESSIsIm5vZGVJZCI6IjNkMzZiZjU3LTFkYjQtNDJlZi1iNzhiLWUyZDNkNGViOWM5NSJ9fSx7InR5cGUiOiJwaC1tYXAiLCJhdHRycyI6eyJpZCI6ImtyUmZnb3BzVXkxVHdOVTF5aFNETHFORFRkNk41dE1ackhsbThuTEpJREkiLCJub2RlSWQiOiI1MzE0ZWI2MS1lYTA2LTQyOGQtYWEzZi0zMDA4OWJjZmUxYjgifX0seyJ0eXBlIjoicGgtcHJvcGVydGllcyIsImF0dHJzIjp7ImlkIjoia3JSZmdvcHNVeTFUd05VMXloU0RMcU5EVGQ2TjV0TVpySGxtOG5MSklESSIsIm5vZGVJZCI6ImUwMjE1NDU5LWY0YTgtNGJjNy04NDhmLTYxODE1NzY1NzlmNyJ9fV19fV19", + "$host": "localhost:8000", + "$pathname": "/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$browser_version": 117, + "$browser_language": "en-GB", + "$screen_height": 982, + "$screen_width": 1512, + "$viewport_height": 859, + "$viewport_width": 1512, + "$lib": "web", + "$lib_version": "1.84.0", + "$insert_id": "bgnhtkaiu91n6vuo", + "$time": 1697797681.755, + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$device_id": "018a92fd-7b25-7770-a050-577e94fd148c", + "$console_log_recording_enabled_server_side": true, + "$session_recording_recorder_version_server_side": "v2", + "$autocapture_disabled_server_side": false, + "$active_feature_flags": [ + "signup-page-4.0", + "cmd-k-search", + "posthog-3000", + "funnels-cue-opt-out-7301", + "retention-breakdown", + "smoothing-interval", + "billing-limit", + "kafka-inspector", + "historical-exports-v2", + "person-on-events-enabled", + "region-select", + "ingestion-warnings-enabled", + "session-reset-on-load", + "recordings-on-feature-flags", + "auto-rollback-feature-flags", + "onboarding-v2-demo", + "feature-flag-rollout-ux", + "role-based-access", + "query_running_time", + "query-timings", + "recording-debugging", + "enable-prompts", + "feedback-scene", + "early-access-feature", + "early-access-feature-site-button", + "hedgehog-mode-debug", + "auto-redirect", + "session-recording-blob-replay", + "surveys", + "generic-signup-benefits", + "surveys-positions", + "web-analytics", + "high-frequency-batch-exports", + "exception-autocapture", + "data-warehouse", + "data-warehouse-views", + "ff-dashboard-templates", + "show-product-intro-existing-products", + "artificial-hog", + "cs-dashboards", + "product-specific-onboarding", + "redirect-signups-to-instance", + "apps-and-exports-ui", + "survey-nps-results", + "session-recording-allow-v1-snapshots", + "session-replay-cors-proxy", + "webhooks-denylist", + "surveys-site-app-deprecation", + "surveys-multiple-questions", + "surveys-results-visualizations", + "console-recording-search", + "persons-hogql-query", + "notebooks" + ], + "$feature/file-previews": false, + "$feature/signup-page-4.0": "control", + "$feature/hogql-insights": false, + "$feature/cmd-k-search": true, + "$feature/posthog-3000": true, + "$feature/funnels-cue-opt-out-7301": true, + "$feature/retention-breakdown": true, + "$feature/smoothing-interval": true, + "$feature/billing-limit": true, + "$feature/kafka-inspector": true, + "$feature/historical-exports-v2": true, + "$feature/person-on-events-enabled": true, + "$feature/region-select": true, + "$feature/ingestion-warnings-enabled": true, + "$feature/session-reset-on-load": true, + "$feature/recordings-on-feature-flags": true, + "$feature/auto-rollback-feature-flags": true, + "$feature/onboarding-v2-demo": true, + "$feature/feature-flag-rollout-ux": true, + "$feature/role-based-access": true, + "$feature/query_running_time": true, + "$feature/query-timings": true, + "$feature/recording-debugging": true, + "$feature/enable-prompts": true, + "$feature/feedback-scene": true, + "$feature/early-access-feature": true, + "$feature/early-access-feature-site-button": true, + "$feature/hedgehog-mode-debug": true, + "$feature/auto-redirect": true, + "$feature/session-recording-blob-replay": true, + "$feature/surveys": true, + "$feature/generic-signup-benefits": true, + "$feature/surveys-positions": true, + "$feature/web-analytics": true, + "$feature/high-frequency-batch-exports": true, + "$feature/exception-autocapture": true, + "$feature/data-warehouse": true, + "$feature/data-warehouse-views": true, + "$feature/ff-dashboard-templates": true, + "$feature/show-product-intro-existing-products": true, + "$feature/artificial-hog": true, + "$feature/cs-dashboards": true, + "$feature/product-specific-onboarding": true, + "$feature/redirect-signups-to-instance": true, + "$feature/apps-and-exports-ui": true, + "$feature/survey-nps-results": true, + "$feature/session-recording-allow-v1-snapshots": true, + "$feature/session-replay-cors-proxy": true, + "$feature/webhooks-denylist": true, + "$feature/surveys-site-app-deprecation": true, + "$feature/surveys-multiple-questions": true, + "$feature/surveys-results-visualizations": true, + "$feature/console-recording-search": true, + "$feature/persons-hogql-query": true, + "$feature/notebooks": true, + "$feature_flag_payloads": {}, + "realm": "hosted-clickhouse", + "email_service_available": false, + "slack_service_available": false, + "$user_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "is_demo_project": false, + "$groups": { + "project": "018a92f8-b602-0000-75de-4b9073693531", + "organization": "018a92f8-afff-0000-efec-ca77de39e384", + "customer": "cus_OdSgxxWtHOtq9g", + "instance": "http://localhost:8000" + }, + "has_billing_plan": true, + "customer_deactivated": false, + "current_total_amount_usd": "0.00", + "percentage_usage.product_analytics": 0, + "current_amount_usd.product_analytics": "0.00", + "unit_amount_usd.product_analytics": null, + "usage_limit.product_analytics": null, + "current_usage.product_analytics": 3729, + "projected_usage.product_analytics": 0, + "free_allocation.product_analytics": 0, + "percentage_usage.session_replay": 0, + "current_amount_usd.session_replay": "0.00", + "unit_amount_usd.session_replay": null, + "usage_limit.session_replay": null, + "current_usage.session_replay": 254, + "projected_usage.session_replay": 0, + "free_allocation.session_replay": 0, + "percentage_usage.feature_flags": 0, + "current_amount_usd.feature_flags": "0.00", + "unit_amount_usd.feature_flags": null, + "usage_limit.feature_flags": null, + "current_usage.feature_flags": 0, + "projected_usage.feature_flags": 0, + "free_allocation.feature_flags": 0, + "percentage_usage.integrations": 0, + "current_amount_usd.integrations": null, + "unit_amount_usd.integrations": null, + "usage_limit.integrations": 0, + "current_usage.integrations": 0, + "projected_usage.integrations": 0, + "free_allocation.integrations": 0, + "percentage_usage.platform_and_support": 0, + "current_amount_usd.platform_and_support": null, + "unit_amount_usd.platform_and_support": null, + "usage_limit.platform_and_support": 0, + "current_usage.platform_and_support": 0, + "projected_usage.platform_and_support": 0, + "free_allocation.platform_and_support": 0, + "billing_period_start": "2023-10-14T09:22:33.000Z", + "billing_period_end": "2023-11-14T09:22:33.000Z", + "$referrer": "$direct", + "$referring_domain": "$direct", + "token": "phc_OWGI2wKbfi7rWDZT9wkl8uGcfe0wOGCvflLEZSMiaT0", + "$session_id": "018b4ca0-9686-7b75-ba2e-61e9c0054b65", + "$window_id": "018b4ca0-9686-7b75-ba2e-61ea857e58f0", + "title": "test@posthog.com \u2022 Persons \u2022 PostHog", + "$ip": "127.0.0.1", + "$set": { + "$os": "Mac OS X", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI#activeTab=feed&state=eyJ0eXBlIjoiZG9jIiwiY29udGVudCI6W3sidHlwZSI6ImhlYWRpbmciLCJhdHRycyI6eyJsZXZlbCI6MX0sImNvbnRlbnQiOlt7InR5cGUiOiJ0ZXh0IiwidGV4dCI6ImtyUmZnb3BzVXkxVHdOVTF5aFNETHFORFRkNk41dE1ackhsbThuTEpJREkifV19LHsidHlwZSI6InBoLXBlcnNvbi1mZWVkIiwiYXR0cnMiOnsiaGVpZ2h0IjpudWxsLCJ0aXRsZSI6bnVsbCwibm9kZUlkIjoiNmQ0ODUwNjYtZWM5OS00ODNkLThiOTgtNGQ4YTJkYzljYzRiIiwiaWQiOiJrclJmZ29wc1V5MVR3TlUxeWhTRExxTkRUZDZONXRNWnJIbG04bkxKSURJIiwiX19pbml0IjpudWxsLCJjaGlsZHJlbiI6W3sidHlwZSI6InBoLXBlcnNvbiIsImF0dHJzIjp7ImlkIjoia3JSZmdvcHNVeTFUd05VMXloU0RMcU5EVGQ2TjV0TVpySGxtOG5MSklESSIsIm5vZGVJZCI6IjNkMzZiZjU3LTFkYjQtNDJlZi1iNzhiLWUyZDNkNGViOWM5NSJ9fSx7InR5cGUiOiJwaC1tYXAiLCJhdHRycyI6eyJpZCI6ImtyUmZnb3BzVXkxVHdOVTF5aFNETHFORFRkNk41dE1ackhsbThuTEpJREkiLCJub2RlSWQiOiI1MzE0ZWI2MS1lYTA2LTQyOGQtYWEzZi0zMDA4OWJjZmUxYjgifX0seyJ0eXBlIjoicGgtcHJvcGVydGllcyIsImF0dHJzIjp7ImlkIjoia3JSZmdvcHNVeTFUd05VMXloU0RMcU5EVGQ2TjV0TVpySGxtOG5MSklESSIsIm5vZGVJZCI6ImUwMjE1NDU5LWY0YTgtNGJjNy04NDhmLTYxODE1NzY1NzlmNyJ9fV19fV19", + "$pathname": "/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$browser_version": 117, + "$referrer": "$direct", + "$referring_domain": "$direct" + }, + "$set_once": { + "$initial_os": "Mac OS X", + "$initial_browser": "Chrome", + "$initial_device_type": "Desktop", + "$initial_current_url": "http://localhost:8000/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI#activeTab=feed&state=eyJ0eXBlIjoiZG9jIiwiY29udGVudCI6W3sidHlwZSI6ImhlYWRpbmciLCJhdHRycyI6eyJsZXZlbCI6MX0sImNvbnRlbnQiOlt7InR5cGUiOiJ0ZXh0IiwidGV4dCI6ImtyUmZnb3BzVXkxVHdOVTF5aFNETHFORFRkNk41dE1ackhsbThuTEpJREkifV19LHsidHlwZSI6InBoLXBlcnNvbi1mZWVkIiwiYXR0cnMiOnsiaGVpZ2h0IjpudWxsLCJ0aXRsZSI6bnVsbCwibm9kZUlkIjoiNmQ0ODUwNjYtZWM5OS00ODNkLThiOTgtNGQ4YTJkYzljYzRiIiwiaWQiOiJrclJmZ29wc1V5MVR3TlUxeWhTRExxTkRUZDZONXRNWnJIbG04bkxKSURJIiwiX19pbml0IjpudWxsLCJjaGlsZHJlbiI6W3sidHlwZSI6InBoLXBlcnNvbiIsImF0dHJzIjp7ImlkIjoia3JSZmdvcHNVeTFUd05VMXloU0RMcU5EVGQ2TjV0TVpySGxtOG5MSklESSIsIm5vZGVJZCI6IjNkMzZiZjU3LTFkYjQtNDJlZi1iNzhiLWUyZDNkNGViOWM5NSJ9fSx7InR5cGUiOiJwaC1tYXAiLCJhdHRycyI6eyJpZCI6ImtyUmZnb3BzVXkxVHdOVTF5aFNETHFORFRkNk41dE1ackhsbThuTEpJREkiLCJub2RlSWQiOiI1MzE0ZWI2MS1lYTA2LTQyOGQtYWEzZi0zMDA4OWJjZmUxYjgifX0seyJ0eXBlIjoicGgtcHJvcGVydGllcyIsImF0dHJzIjp7ImlkIjoia3JSZmdvcHNVeTFUd05VMXloU0RMcU5EVGQ2TjV0TVpySGxtOG5MSklESSIsIm5vZGVJZCI6ImUwMjE1NDU5LWY0YTgtNGJjNy04NDhmLTYxODE1NzY1NzlmNyJ9fV19fV19", + "$initial_pathname": "/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$initial_browser_version": 117, + "$initial_referrer": "$direct", + "$initial_referring_domain": "$direct" + }, + "$sent_at": "2023-10-20T10:28:03.798000+00:00", + "$geoip_city_name": "Sydney", + "$geoip_country_name": "Australia", + "$geoip_country_code": "AU", + "$geoip_continent_name": "Oceania", + "$geoip_continent_code": "OC", + "$geoip_postal_code": "2000", + "$geoip_latitude": -33.8715, + "$geoip_longitude": 151.2006, + "$geoip_time_zone": "Australia/Sydney", + "$geoip_subdivision_1_code": "NSW", + "$geoip_subdivision_1_name": "New South Wales", + "$plugins_succeeded": ["GeoIP (1)"], + "$plugins_failed": [], + "$plugins_deferred": [], + "$group_3": "018a92f8-b602-0000-75de-4b9073693531", + "$group_2": "018a92f8-afff-0000-efec-ca77de39e384", + "$group_4": "cus_OdSgxxWtHOtq9g", + "$group_1": "http://localhost:8000" + }, + "timestamp": "2023-10-20T10:28:01.765000+00:00", + "uuid": null + }, + { + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "elements": [], + "elements_chain": null, + "event": "$pageleave", + "id": "018b4ca3-104f-7f7f-b9f6-2e4411315c0f", + "person": null, + "properties": { + "$os": "Mac OS X", + "$os_version": "10.15.7", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI#activeTab=feed&state=eyJ0eXBlIjoiZG9jIiwiY29udGVudCI6W3sidHlwZSI6ImhlYWRpbmciLCJhdHRycyI6eyJsZXZlbCI6MX0sImNvbnRlbnQiOlt7InR5cGUiOiJ0ZXh0IiwidGV4dCI6ImtyUmZnb3BzVXkxVHdOVTF5aFNETHFORFRkNk41dE1ackhsbThuTEpJREkifV19LHsidHlwZSI6InBoLXBlcnNvbi1mZWVkIiwiYXR0cnMiOnsiaGVpZ2h0IjpudWxsLCJ0aXRsZSI6bnVsbCwibm9kZUlkIjoiNmQ0ODUwNjYtZWM5OS00ODNkLThiOTgtNGQ4YTJkYzljYzRiIiwiaWQiOiJrclJmZ29wc1V5MVR3TlUxeWhTRExxTkRUZDZONXRNWnJIbG04bkxKSURJIiwiX19pbml0IjpudWxsLCJjaGlsZHJlbiI6W3sidHlwZSI6InBoLXBlcnNvbiIsImF0dHJzIjp7ImlkIjoia3JSZmdvcHNVeTFUd05VMXloU0RMcU5EVGQ2TjV0TVpySGxtOG5MSklESSIsIm5vZGVJZCI6IjNkMzZiZjU3LTFkYjQtNDJlZi1iNzhiLWUyZDNkNGViOWM5NSJ9fSx7InR5cGUiOiJwaC1tYXAiLCJhdHRycyI6eyJpZCI6ImtyUmZnb3BzVXkxVHdOVTF5aFNETHFORFRkNk41dE1ackhsbThuTEpJREkiLCJub2RlSWQiOiI1MzE0ZWI2MS1lYTA2LTQyOGQtYWEzZi0zMDA4OWJjZmUxYjgifX0seyJ0eXBlIjoicGgtcHJvcGVydGllcyIsImF0dHJzIjp7ImlkIjoia3JSZmdvcHNVeTFUd05VMXloU0RMcU5EVGQ2TjV0TVpySGxtOG5MSklESSIsIm5vZGVJZCI6ImUwMjE1NDU5LWY0YTgtNGJjNy04NDhmLTYxODE1NzY1NzlmNyJ9fV19fV19", + "$host": "localhost:8000", + "$pathname": "/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$browser_version": 117, + "$browser_language": "en-GB", + "$screen_height": 982, + "$screen_width": 1512, + "$viewport_height": 859, + "$viewport_width": 1512, + "$lib": "web", + "$lib_version": "1.84.0", + "$insert_id": "5emypqvdlqmzblda", + "$time": 1697797836.88, + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$device_id": "018a92fd-7b25-7770-a050-577e94fd148c", + "$console_log_recording_enabled_server_side": true, + "$session_recording_recorder_version_server_side": "v2", + "$autocapture_disabled_server_side": false, + "$active_feature_flags": [ + "signup-page-4.0", + "cmd-k-search", + "posthog-3000", + "funnels-cue-opt-out-7301", + "retention-breakdown", + "smoothing-interval", + "billing-limit", + "kafka-inspector", + "historical-exports-v2", + "person-on-events-enabled", + "region-select", + "ingestion-warnings-enabled", + "session-reset-on-load", + "recordings-on-feature-flags", + "auto-rollback-feature-flags", + "onboarding-v2-demo", + "feature-flag-rollout-ux", + "role-based-access", + "query_running_time", + "query-timings", + "recording-debugging", + "enable-prompts", + "feedback-scene", + "early-access-feature", + "early-access-feature-site-button", + "hedgehog-mode-debug", + "auto-redirect", + "session-recording-blob-replay", + "surveys", + "generic-signup-benefits", + "surveys-positions", + "web-analytics", + "high-frequency-batch-exports", + "exception-autocapture", + "data-warehouse", + "data-warehouse-views", + "ff-dashboard-templates", + "show-product-intro-existing-products", + "artificial-hog", + "cs-dashboards", + "product-specific-onboarding", + "redirect-signups-to-instance", + "apps-and-exports-ui", + "survey-nps-results", + "session-recording-allow-v1-snapshots", + "session-replay-cors-proxy", + "webhooks-denylist", + "surveys-site-app-deprecation", + "surveys-multiple-questions", + "surveys-results-visualizations", + "console-recording-search", + "persons-hogql-query", + "notebooks" + ], + "$feature/file-previews": false, + "$feature/signup-page-4.0": "control", + "$feature/hogql-insights": false, + "$feature/cmd-k-search": true, + "$feature/posthog-3000": true, + "$feature/funnels-cue-opt-out-7301": true, + "$feature/retention-breakdown": true, + "$feature/smoothing-interval": true, + "$feature/billing-limit": true, + "$feature/kafka-inspector": true, + "$feature/historical-exports-v2": true, + "$feature/person-on-events-enabled": true, + "$feature/region-select": true, + "$feature/ingestion-warnings-enabled": true, + "$feature/session-reset-on-load": true, + "$feature/recordings-on-feature-flags": true, + "$feature/auto-rollback-feature-flags": true, + "$feature/onboarding-v2-demo": true, + "$feature/feature-flag-rollout-ux": true, + "$feature/role-based-access": true, + "$feature/query_running_time": true, + "$feature/query-timings": true, + "$feature/recording-debugging": true, + "$feature/enable-prompts": true, + "$feature/feedback-scene": true, + "$feature/early-access-feature": true, + "$feature/early-access-feature-site-button": true, + "$feature/hedgehog-mode-debug": true, + "$feature/auto-redirect": true, + "$feature/session-recording-blob-replay": true, + "$feature/surveys": true, + "$feature/generic-signup-benefits": true, + "$feature/surveys-positions": true, + "$feature/web-analytics": true, + "$feature/high-frequency-batch-exports": true, + "$feature/exception-autocapture": true, + "$feature/data-warehouse": true, + "$feature/data-warehouse-views": true, + "$feature/ff-dashboard-templates": true, + "$feature/show-product-intro-existing-products": true, + "$feature/artificial-hog": true, + "$feature/cs-dashboards": true, + "$feature/product-specific-onboarding": true, + "$feature/redirect-signups-to-instance": true, + "$feature/apps-and-exports-ui": true, + "$feature/survey-nps-results": true, + "$feature/session-recording-allow-v1-snapshots": true, + "$feature/session-replay-cors-proxy": true, + "$feature/webhooks-denylist": true, + "$feature/surveys-site-app-deprecation": true, + "$feature/surveys-multiple-questions": true, + "$feature/surveys-results-visualizations": true, + "$feature/console-recording-search": true, + "$feature/persons-hogql-query": true, + "$feature/notebooks": true, + "$feature_flag_payloads": {}, + "realm": "hosted-clickhouse", + "email_service_available": false, + "slack_service_available": false, + "$user_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "is_demo_project": false, + "$groups": { + "project": "018a92f8-b602-0000-75de-4b9073693531", + "organization": "018a92f8-afff-0000-efec-ca77de39e384", + "customer": "cus_OdSgxxWtHOtq9g", + "instance": "http://localhost:8000" + }, + "has_billing_plan": true, + "customer_deactivated": false, + "current_total_amount_usd": "0.00", + "percentage_usage.product_analytics": 0, + "current_amount_usd.product_analytics": "0.00", + "unit_amount_usd.product_analytics": null, + "usage_limit.product_analytics": null, + "current_usage.product_analytics": 3729, + "projected_usage.product_analytics": 0, + "free_allocation.product_analytics": 0, + "percentage_usage.session_replay": 0, + "current_amount_usd.session_replay": "0.00", + "unit_amount_usd.session_replay": null, + "usage_limit.session_replay": null, + "current_usage.session_replay": 254, + "projected_usage.session_replay": 0, + "free_allocation.session_replay": 0, + "percentage_usage.feature_flags": 0, + "current_amount_usd.feature_flags": "0.00", + "unit_amount_usd.feature_flags": null, + "usage_limit.feature_flags": null, + "current_usage.feature_flags": 0, + "projected_usage.feature_flags": 0, + "free_allocation.feature_flags": 0, + "percentage_usage.integrations": 0, + "current_amount_usd.integrations": null, + "unit_amount_usd.integrations": null, + "usage_limit.integrations": 0, + "current_usage.integrations": 0, + "projected_usage.integrations": 0, + "free_allocation.integrations": 0, + "percentage_usage.platform_and_support": 0, + "current_amount_usd.platform_and_support": null, + "unit_amount_usd.platform_and_support": null, + "usage_limit.platform_and_support": 0, + "current_usage.platform_and_support": 0, + "projected_usage.platform_and_support": 0, + "free_allocation.platform_and_support": 0, + "billing_period_start": "2023-10-14T09:22:33.000Z", + "billing_period_end": "2023-11-14T09:22:33.000Z", + "$referrer": "$direct", + "$referring_domain": "$direct", + "token": "phc_OWGI2wKbfi7rWDZT9wkl8uGcfe0wOGCvflLEZSMiaT0", + "$session_id": "018b4ca0-9686-7b75-ba2e-61e9c0054b65", + "$window_id": "018b4ca0-9686-7b75-ba2e-61ea857e58f0", + "$ip": "127.0.0.1", + "$set": { + "$os": "Mac OS X", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI#activeTab=feed&state=eyJ0eXBlIjoiZG9jIiwiY29udGVudCI6W3sidHlwZSI6ImhlYWRpbmciLCJhdHRycyI6eyJsZXZlbCI6MX0sImNvbnRlbnQiOlt7InR5cGUiOiJ0ZXh0IiwidGV4dCI6ImtyUmZnb3BzVXkxVHdOVTF5aFNETHFORFRkNk41dE1ackhsbThuTEpJREkifV19LHsidHlwZSI6InBoLXBlcnNvbi1mZWVkIiwiYXR0cnMiOnsiaGVpZ2h0IjpudWxsLCJ0aXRsZSI6bnVsbCwibm9kZUlkIjoiNmQ0ODUwNjYtZWM5OS00ODNkLThiOTgtNGQ4YTJkYzljYzRiIiwiaWQiOiJrclJmZ29wc1V5MVR3TlUxeWhTRExxTkRUZDZONXRNWnJIbG04bkxKSURJIiwiX19pbml0IjpudWxsLCJjaGlsZHJlbiI6W3sidHlwZSI6InBoLXBlcnNvbiIsImF0dHJzIjp7ImlkIjoia3JSZmdvcHNVeTFUd05VMXloU0RMcU5EVGQ2TjV0TVpySGxtOG5MSklESSIsIm5vZGVJZCI6IjNkMzZiZjU3LTFkYjQtNDJlZi1iNzhiLWUyZDNkNGViOWM5NSJ9fSx7InR5cGUiOiJwaC1tYXAiLCJhdHRycyI6eyJpZCI6ImtyUmZnb3BzVXkxVHdOVTF5aFNETHFORFRkNk41dE1ackhsbThuTEpJREkiLCJub2RlSWQiOiI1MzE0ZWI2MS1lYTA2LTQyOGQtYWEzZi0zMDA4OWJjZmUxYjgifX0seyJ0eXBlIjoicGgtcHJvcGVydGllcyIsImF0dHJzIjp7ImlkIjoia3JSZmdvcHNVeTFUd05VMXloU0RMcU5EVGQ2TjV0TVpySGxtOG5MSklESSIsIm5vZGVJZCI6ImUwMjE1NDU5LWY0YTgtNGJjNy04NDhmLTYxODE1NzY1NzlmNyJ9fV19fV19", + "$pathname": "/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$browser_version": 117, + "$referrer": "$direct", + "$referring_domain": "$direct" + }, + "$set_once": { + "$initial_os": "Mac OS X", + "$initial_browser": "Chrome", + "$initial_device_type": "Desktop", + "$initial_current_url": "http://localhost:8000/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI#activeTab=feed&state=eyJ0eXBlIjoiZG9jIiwiY29udGVudCI6W3sidHlwZSI6ImhlYWRpbmciLCJhdHRycyI6eyJsZXZlbCI6MX0sImNvbnRlbnQiOlt7InR5cGUiOiJ0ZXh0IiwidGV4dCI6ImtyUmZnb3BzVXkxVHdOVTF5aFNETHFORFRkNk41dE1ackhsbThuTEpJREkifV19LHsidHlwZSI6InBoLXBlcnNvbi1mZWVkIiwiYXR0cnMiOnsiaGVpZ2h0IjpudWxsLCJ0aXRsZSI6bnVsbCwibm9kZUlkIjoiNmQ0ODUwNjYtZWM5OS00ODNkLThiOTgtNGQ4YTJkYzljYzRiIiwiaWQiOiJrclJmZ29wc1V5MVR3TlUxeWhTRExxTkRUZDZONXRNWnJIbG04bkxKSURJIiwiX19pbml0IjpudWxsLCJjaGlsZHJlbiI6W3sidHlwZSI6InBoLXBlcnNvbiIsImF0dHJzIjp7ImlkIjoia3JSZmdvcHNVeTFUd05VMXloU0RMcU5EVGQ2TjV0TVpySGxtOG5MSklESSIsIm5vZGVJZCI6IjNkMzZiZjU3LTFkYjQtNDJlZi1iNzhiLWUyZDNkNGViOWM5NSJ9fSx7InR5cGUiOiJwaC1tYXAiLCJhdHRycyI6eyJpZCI6ImtyUmZnb3BzVXkxVHdOVTF5aFNETHFORFRkNk41dE1ackhsbThuTEpJREkiLCJub2RlSWQiOiI1MzE0ZWI2MS1lYTA2LTQyOGQtYWEzZi0zMDA4OWJjZmUxYjgifX0seyJ0eXBlIjoicGgtcHJvcGVydGllcyIsImF0dHJzIjp7ImlkIjoia3JSZmdvcHNVeTFUd05VMXloU0RMcU5EVGQ2TjV0TVpySGxtOG5MSklESSIsIm5vZGVJZCI6ImUwMjE1NDU5LWY0YTgtNGJjNy04NDhmLTYxODE1NzY1NzlmNyJ9fV19fV19", + "$initial_pathname": "/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$initial_browser_version": 117, + "$initial_referrer": "$direct", + "$initial_referring_domain": "$direct" + }, + "$sent_at": "2023-10-20T10:30:36.883000+00:00", + "$geoip_city_name": "Sydney", + "$geoip_country_name": "Australia", + "$geoip_country_code": "AU", + "$geoip_continent_name": "Oceania", + "$geoip_continent_code": "OC", + "$geoip_postal_code": "2000", + "$geoip_latitude": -33.8715, + "$geoip_longitude": 151.2006, + "$geoip_time_zone": "Australia/Sydney", + "$geoip_subdivision_1_code": "NSW", + "$geoip_subdivision_1_name": "New South Wales", + "$plugins_succeeded": ["GeoIP (1)"], + "$plugins_failed": [], + "$plugins_deferred": [], + "$group_3": "018a92f8-b602-0000-75de-4b9073693531", + "$group_2": "018a92f8-afff-0000-efec-ca77de39e384", + "$group_4": "cus_OdSgxxWtHOtq9g", + "$group_1": "http://localhost:8000" + }, + "timestamp": "2023-10-20T10:30:36.886000+00:00", + "uuid": null + }, + { + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "elements": [], + "elements_chain": null, + "event": "$opt_in", + "id": "018b4ca3-1cf4-7218-9d6f-0303911c1193", + "person": null, + "properties": { + "$os": "Mac OS X", + "$os_version": "10.15.7", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI#activeTab=feed&state=eyJ0eXBlIjoiZG9jIiwiY29udGVudCI6W3sidHlwZSI6ImhlYWRpbmciLCJhdHRycyI6eyJsZXZlbCI6MX0sImNvbnRlbnQiOlt7InR5cGUiOiJ0ZXh0IiwidGV4dCI6ImtyUmZnb3BzVXkxVHdOVTF5aFNETHFORFRkNk41dE1ackhsbThuTEpJREkifV19LHsidHlwZSI6InBoLXBlcnNvbi1mZWVkIiwiYXR0cnMiOnsiaGVpZ2h0IjpudWxsLCJ0aXRsZSI6bnVsbCwibm9kZUlkIjoiNmQ0ODUwNjYtZWM5OS00ODNkLThiOTgtNGQ4YTJkYzljYzRiIiwiaWQiOiJrclJmZ29wc1V5MVR3TlUxeWhTRExxTkRUZDZONXRNWnJIbG04bkxKSURJIiwiX19pbml0IjpudWxsLCJjaGlsZHJlbiI6W3sidHlwZSI6InBoLXBlcnNvbiIsImF0dHJzIjp7ImlkIjoia3JSZmdvcHNVeTFUd05VMXloU0RMcU5EVGQ2TjV0TVpySGxtOG5MSklESSIsIm5vZGVJZCI6IjNkMzZiZjU3LTFkYjQtNDJlZi1iNzhiLWUyZDNkNGViOWM5NSJ9fSx7InR5cGUiOiJwaC1tYXAiLCJhdHRycyI6eyJpZCI6ImtyUmZnb3BzVXkxVHdOVTF5aFNETHFORFRkNk41dE1ackhsbThuTEpJREkiLCJub2RlSWQiOiI1MzE0ZWI2MS1lYTA2LTQyOGQtYWEzZi0zMDA4OWJjZmUxYjgifX0seyJ0eXBlIjoicGgtcHJvcGVydGllcyIsImF0dHJzIjp7ImlkIjoia3JSZmdvcHNVeTFUd05VMXloU0RMcU5EVGQ2TjV0TVpySGxtOG5MSklESSIsIm5vZGVJZCI6ImUwMjE1NDU5LWY0YTgtNGJjNy04NDhmLTYxODE1NzY1NzlmNyJ9fV19fV19", + "$host": "localhost:8000", + "$pathname": "/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$browser_version": 117, + "$browser_language": "en-GB", + "$screen_height": 982, + "$screen_width": 1512, + "$viewport_height": 859, + "$viewport_width": 1512, + "$lib": "web", + "$lib_version": "1.84.0", + "$insert_id": "dqkiz2bg4xd3ga0h", + "$time": 1697797840.118, + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$device_id": "018a92fd-7b25-7770-a050-577e94fd148c", + "$console_log_recording_enabled_server_side": true, + "$session_recording_recorder_version_server_side": "v2", + "$autocapture_disabled_server_side": false, + "$active_feature_flags": [ + "signup-page-4.0", + "cmd-k-search", + "posthog-3000", + "funnels-cue-opt-out-7301", + "retention-breakdown", + "smoothing-interval", + "billing-limit", + "kafka-inspector", + "historical-exports-v2", + "person-on-events-enabled", + "region-select", + "ingestion-warnings-enabled", + "session-reset-on-load", + "recordings-on-feature-flags", + "auto-rollback-feature-flags", + "onboarding-v2-demo", + "feature-flag-rollout-ux", + "role-based-access", + "query_running_time", + "query-timings", + "recording-debugging", + "enable-prompts", + "feedback-scene", + "early-access-feature", + "early-access-feature-site-button", + "hedgehog-mode-debug", + "auto-redirect", + "session-recording-blob-replay", + "surveys", + "generic-signup-benefits", + "surveys-positions", + "web-analytics", + "high-frequency-batch-exports", + "exception-autocapture", + "data-warehouse", + "data-warehouse-views", + "ff-dashboard-templates", + "show-product-intro-existing-products", + "artificial-hog", + "cs-dashboards", + "product-specific-onboarding", + "redirect-signups-to-instance", + "apps-and-exports-ui", + "survey-nps-results", + "session-recording-allow-v1-snapshots", + "session-replay-cors-proxy", + "webhooks-denylist", + "surveys-site-app-deprecation", + "surveys-multiple-questions", + "surveys-results-visualizations", + "console-recording-search", + "persons-hogql-query", + "notebooks" + ], + "$feature/file-previews": false, + "$feature/signup-page-4.0": "control", + "$feature/hogql-insights": false, + "$feature/cmd-k-search": true, + "$feature/posthog-3000": true, + "$feature/funnels-cue-opt-out-7301": true, + "$feature/retention-breakdown": true, + "$feature/smoothing-interval": true, + "$feature/billing-limit": true, + "$feature/kafka-inspector": true, + "$feature/historical-exports-v2": true, + "$feature/person-on-events-enabled": true, + "$feature/region-select": true, + "$feature/ingestion-warnings-enabled": true, + "$feature/session-reset-on-load": true, + "$feature/recordings-on-feature-flags": true, + "$feature/auto-rollback-feature-flags": true, + "$feature/onboarding-v2-demo": true, + "$feature/feature-flag-rollout-ux": true, + "$feature/role-based-access": true, + "$feature/query_running_time": true, + "$feature/query-timings": true, + "$feature/recording-debugging": true, + "$feature/enable-prompts": true, + "$feature/feedback-scene": true, + "$feature/early-access-feature": true, + "$feature/early-access-feature-site-button": true, + "$feature/hedgehog-mode-debug": true, + "$feature/auto-redirect": true, + "$feature/session-recording-blob-replay": true, + "$feature/surveys": true, + "$feature/generic-signup-benefits": true, + "$feature/surveys-positions": true, + "$feature/web-analytics": true, + "$feature/high-frequency-batch-exports": true, + "$feature/exception-autocapture": true, + "$feature/data-warehouse": true, + "$feature/data-warehouse-views": true, + "$feature/ff-dashboard-templates": true, + "$feature/show-product-intro-existing-products": true, + "$feature/artificial-hog": true, + "$feature/cs-dashboards": true, + "$feature/product-specific-onboarding": true, + "$feature/redirect-signups-to-instance": true, + "$feature/apps-and-exports-ui": true, + "$feature/survey-nps-results": true, + "$feature/session-recording-allow-v1-snapshots": true, + "$feature/session-replay-cors-proxy": true, + "$feature/webhooks-denylist": true, + "$feature/surveys-site-app-deprecation": true, + "$feature/surveys-multiple-questions": true, + "$feature/surveys-results-visualizations": true, + "$feature/console-recording-search": true, + "$feature/persons-hogql-query": true, + "$feature/notebooks": true, + "$feature_flag_payloads": {}, + "realm": "hosted-clickhouse", + "email_service_available": false, + "slack_service_available": false, + "$user_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "is_demo_project": false, + "$groups": { + "project": "018a92f8-b602-0000-75de-4b9073693531", + "organization": "018a92f8-afff-0000-efec-ca77de39e384", + "customer": "cus_OdSgxxWtHOtq9g", + "instance": "http://localhost:8000" + }, + "has_billing_plan": true, + "customer_deactivated": false, + "current_total_amount_usd": "0.00", + "percentage_usage.product_analytics": 0, + "current_amount_usd.product_analytics": "0.00", + "unit_amount_usd.product_analytics": null, + "usage_limit.product_analytics": null, + "current_usage.product_analytics": 3729, + "projected_usage.product_analytics": 0, + "free_allocation.product_analytics": 0, + "percentage_usage.session_replay": 0, + "current_amount_usd.session_replay": "0.00", + "unit_amount_usd.session_replay": null, + "usage_limit.session_replay": null, + "current_usage.session_replay": 254, + "projected_usage.session_replay": 0, + "free_allocation.session_replay": 0, + "percentage_usage.feature_flags": 0, + "current_amount_usd.feature_flags": "0.00", + "unit_amount_usd.feature_flags": null, + "usage_limit.feature_flags": null, + "current_usage.feature_flags": 0, + "projected_usage.feature_flags": 0, + "free_allocation.feature_flags": 0, + "percentage_usage.integrations": 0, + "current_amount_usd.integrations": null, + "unit_amount_usd.integrations": null, + "usage_limit.integrations": 0, + "current_usage.integrations": 0, + "projected_usage.integrations": 0, + "free_allocation.integrations": 0, + "percentage_usage.platform_and_support": 0, + "current_amount_usd.platform_and_support": null, + "unit_amount_usd.platform_and_support": null, + "usage_limit.platform_and_support": 0, + "current_usage.platform_and_support": 0, + "projected_usage.platform_and_support": 0, + "free_allocation.platform_and_support": 0, + "billing_period_start": "2023-10-14T09:22:33.000Z", + "billing_period_end": "2023-11-14T09:22:33.000Z", + "$referrer": "$direct", + "$referring_domain": "$direct", + "token": "phc_OWGI2wKbfi7rWDZT9wkl8uGcfe0wOGCvflLEZSMiaT0", + "$session_id": "018b4ca0-9686-7b75-ba2e-61e9c0054b65", + "$window_id": "018b4ca0-9686-7b75-ba2e-61ea857e58f0", + "$ip": "127.0.0.1", + "$set": { + "$os": "Mac OS X", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI#activeTab=feed&state=eyJ0eXBlIjoiZG9jIiwiY29udGVudCI6W3sidHlwZSI6ImhlYWRpbmciLCJhdHRycyI6eyJsZXZlbCI6MX0sImNvbnRlbnQiOlt7InR5cGUiOiJ0ZXh0IiwidGV4dCI6ImtyUmZnb3BzVXkxVHdOVTF5aFNETHFORFRkNk41dE1ackhsbThuTEpJREkifV19LHsidHlwZSI6InBoLXBlcnNvbi1mZWVkIiwiYXR0cnMiOnsiaGVpZ2h0IjpudWxsLCJ0aXRsZSI6bnVsbCwibm9kZUlkIjoiNmQ0ODUwNjYtZWM5OS00ODNkLThiOTgtNGQ4YTJkYzljYzRiIiwiaWQiOiJrclJmZ29wc1V5MVR3TlUxeWhTRExxTkRUZDZONXRNWnJIbG04bkxKSURJIiwiX19pbml0IjpudWxsLCJjaGlsZHJlbiI6W3sidHlwZSI6InBoLXBlcnNvbiIsImF0dHJzIjp7ImlkIjoia3JSZmdvcHNVeTFUd05VMXloU0RMcU5EVGQ2TjV0TVpySGxtOG5MSklESSIsIm5vZGVJZCI6IjNkMzZiZjU3LTFkYjQtNDJlZi1iNzhiLWUyZDNkNGViOWM5NSJ9fSx7InR5cGUiOiJwaC1tYXAiLCJhdHRycyI6eyJpZCI6ImtyUmZnb3BzVXkxVHdOVTF5aFNETHFORFRkNk41dE1ackhsbThuTEpJREkiLCJub2RlSWQiOiI1MzE0ZWI2MS1lYTA2LTQyOGQtYWEzZi0zMDA4OWJjZmUxYjgifX0seyJ0eXBlIjoicGgtcHJvcGVydGllcyIsImF0dHJzIjp7ImlkIjoia3JSZmdvcHNVeTFUd05VMXloU0RMcU5EVGQ2TjV0TVpySGxtOG5MSklESSIsIm5vZGVJZCI6ImUwMjE1NDU5LWY0YTgtNGJjNy04NDhmLTYxODE1NzY1NzlmNyJ9fV19fV19", + "$pathname": "/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$browser_version": 117, + "$referrer": "$direct", + "$referring_domain": "$direct" + }, + "$set_once": { + "$initial_os": "Mac OS X", + "$initial_browser": "Chrome", + "$initial_device_type": "Desktop", + "$initial_current_url": "http://localhost:8000/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI#activeTab=feed&state=eyJ0eXBlIjoiZG9jIiwiY29udGVudCI6W3sidHlwZSI6ImhlYWRpbmciLCJhdHRycyI6eyJsZXZlbCI6MX0sImNvbnRlbnQiOlt7InR5cGUiOiJ0ZXh0IiwidGV4dCI6ImtyUmZnb3BzVXkxVHdOVTF5aFNETHFORFRkNk41dE1ackhsbThuTEpJREkifV19LHsidHlwZSI6InBoLXBlcnNvbi1mZWVkIiwiYXR0cnMiOnsiaGVpZ2h0IjpudWxsLCJ0aXRsZSI6bnVsbCwibm9kZUlkIjoiNmQ0ODUwNjYtZWM5OS00ODNkLThiOTgtNGQ4YTJkYzljYzRiIiwiaWQiOiJrclJmZ29wc1V5MVR3TlUxeWhTRExxTkRUZDZONXRNWnJIbG04bkxKSURJIiwiX19pbml0IjpudWxsLCJjaGlsZHJlbiI6W3sidHlwZSI6InBoLXBlcnNvbiIsImF0dHJzIjp7ImlkIjoia3JSZmdvcHNVeTFUd05VMXloU0RMcU5EVGQ2TjV0TVpySGxtOG5MSklESSIsIm5vZGVJZCI6IjNkMzZiZjU3LTFkYjQtNDJlZi1iNzhiLWUyZDNkNGViOWM5NSJ9fSx7InR5cGUiOiJwaC1tYXAiLCJhdHRycyI6eyJpZCI6ImtyUmZnb3BzVXkxVHdOVTF5aFNETHFORFRkNk41dE1ackhsbThuTEpJREkiLCJub2RlSWQiOiI1MzE0ZWI2MS1lYTA2LTQyOGQtYWEzZi0zMDA4OWJjZmUxYjgifX0seyJ0eXBlIjoicGgtcHJvcGVydGllcyIsImF0dHJzIjp7ImlkIjoia3JSZmdvcHNVeTFUd05VMXloU0RMcU5EVGQ2TjV0TVpySGxtOG5MSklESSIsIm5vZGVJZCI6ImUwMjE1NDU5LWY0YTgtNGJjNy04NDhmLTYxODE1NzY1NzlmNyJ9fV19fV19", + "$initial_pathname": "/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$initial_browser_version": 117, + "$initial_referrer": "$direct", + "$initial_referring_domain": "$direct" + }, + "$sent_at": "2023-10-20T10:30:40.118000+00:00", + "$geoip_city_name": "Sydney", + "$geoip_country_name": "Australia", + "$geoip_country_code": "AU", + "$geoip_continent_name": "Oceania", + "$geoip_continent_code": "OC", + "$geoip_postal_code": "2000", + "$geoip_latitude": -33.8715, + "$geoip_longitude": 151.2006, + "$geoip_time_zone": "Australia/Sydney", + "$geoip_subdivision_1_code": "NSW", + "$geoip_subdivision_1_name": "New South Wales", + "$plugins_succeeded": ["GeoIP (1)"], + "$plugins_failed": [], + "$plugins_deferred": [], + "$group_3": "018a92f8-b602-0000-75de-4b9073693531", + "$group_2": "018a92f8-afff-0000-efec-ca77de39e384", + "$group_4": "cus_OdSgxxWtHOtq9g", + "$group_1": "http://localhost:8000" + }, + "timestamp": "2023-10-20T10:30:40.133000+00:00", + "uuid": null + }, + { + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "elements": [], + "elements_chain": null, + "event": "$pageview", + "id": "018b4ca3-1cf7-7208-b179-72da3175820e", + "person": null, + "properties": { + "$os": "Mac OS X", + "$os_version": "10.15.7", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI#activeTab=feed&state=eyJ0eXBlIjoiZG9jIiwiY29udGVudCI6W3sidHlwZSI6ImhlYWRpbmciLCJhdHRycyI6eyJsZXZlbCI6MX0sImNvbnRlbnQiOlt7InR5cGUiOiJ0ZXh0IiwidGV4dCI6ImtyUmZnb3BzVXkxVHdOVTF5aFNETHFORFRkNk41dE1ackhsbThuTEpJREkifV19LHsidHlwZSI6InBoLXBlcnNvbi1mZWVkIiwiYXR0cnMiOnsiaGVpZ2h0IjpudWxsLCJ0aXRsZSI6bnVsbCwibm9kZUlkIjoiNmQ0ODUwNjYtZWM5OS00ODNkLThiOTgtNGQ4YTJkYzljYzRiIiwiaWQiOiJrclJmZ29wc1V5MVR3TlUxeWhTRExxTkRUZDZONXRNWnJIbG04bkxKSURJIiwiX19pbml0IjpudWxsLCJjaGlsZHJlbiI6W3sidHlwZSI6InBoLXBlcnNvbiIsImF0dHJzIjp7ImlkIjoia3JSZmdvcHNVeTFUd05VMXloU0RMcU5EVGQ2TjV0TVpySGxtOG5MSklESSIsIm5vZGVJZCI6IjNkMzZiZjU3LTFkYjQtNDJlZi1iNzhiLWUyZDNkNGViOWM5NSJ9fSx7InR5cGUiOiJwaC1tYXAiLCJhdHRycyI6eyJpZCI6ImtyUmZnb3BzVXkxVHdOVTF5aFNETHFORFRkNk41dE1ackhsbThuTEpJREkiLCJub2RlSWQiOiI1MzE0ZWI2MS1lYTA2LTQyOGQtYWEzZi0zMDA4OWJjZmUxYjgifX0seyJ0eXBlIjoicGgtcHJvcGVydGllcyIsImF0dHJzIjp7ImlkIjoia3JSZmdvcHNVeTFUd05VMXloU0RMcU5EVGQ2TjV0TVpySGxtOG5MSklESSIsIm5vZGVJZCI6ImUwMjE1NDU5LWY0YTgtNGJjNy04NDhmLTYxODE1NzY1NzlmNyJ9fV19fV19", + "$host": "localhost:8000", + "$pathname": "/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$browser_version": 117, + "$browser_language": "en-GB", + "$screen_height": 982, + "$screen_width": 1512, + "$viewport_height": 859, + "$viewport_width": 1512, + "$lib": "web", + "$lib_version": "1.84.0", + "$insert_id": "pyv7tc2zaju04w06", + "$time": 1697797840.12, + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$device_id": "018a92fd-7b25-7770-a050-577e94fd148c", + "$console_log_recording_enabled_server_side": true, + "$session_recording_recorder_version_server_side": "v2", + "$autocapture_disabled_server_side": false, + "$active_feature_flags": [ + "signup-page-4.0", + "cmd-k-search", + "posthog-3000", + "funnels-cue-opt-out-7301", + "retention-breakdown", + "smoothing-interval", + "billing-limit", + "kafka-inspector", + "historical-exports-v2", + "person-on-events-enabled", + "region-select", + "ingestion-warnings-enabled", + "session-reset-on-load", + "recordings-on-feature-flags", + "auto-rollback-feature-flags", + "onboarding-v2-demo", + "feature-flag-rollout-ux", + "role-based-access", + "query_running_time", + "query-timings", + "recording-debugging", + "enable-prompts", + "feedback-scene", + "early-access-feature", + "early-access-feature-site-button", + "hedgehog-mode-debug", + "auto-redirect", + "session-recording-blob-replay", + "surveys", + "generic-signup-benefits", + "surveys-positions", + "web-analytics", + "high-frequency-batch-exports", + "exception-autocapture", + "data-warehouse", + "data-warehouse-views", + "ff-dashboard-templates", + "show-product-intro-existing-products", + "artificial-hog", + "cs-dashboards", + "product-specific-onboarding", + "redirect-signups-to-instance", + "apps-and-exports-ui", + "survey-nps-results", + "session-recording-allow-v1-snapshots", + "session-replay-cors-proxy", + "webhooks-denylist", + "surveys-site-app-deprecation", + "surveys-multiple-questions", + "surveys-results-visualizations", + "console-recording-search", + "persons-hogql-query", + "notebooks" + ], + "$feature/file-previews": false, + "$feature/signup-page-4.0": "control", + "$feature/hogql-insights": false, + "$feature/cmd-k-search": true, + "$feature/posthog-3000": true, + "$feature/funnels-cue-opt-out-7301": true, + "$feature/retention-breakdown": true, + "$feature/smoothing-interval": true, + "$feature/billing-limit": true, + "$feature/kafka-inspector": true, + "$feature/historical-exports-v2": true, + "$feature/person-on-events-enabled": true, + "$feature/region-select": true, + "$feature/ingestion-warnings-enabled": true, + "$feature/session-reset-on-load": true, + "$feature/recordings-on-feature-flags": true, + "$feature/auto-rollback-feature-flags": true, + "$feature/onboarding-v2-demo": true, + "$feature/feature-flag-rollout-ux": true, + "$feature/role-based-access": true, + "$feature/query_running_time": true, + "$feature/query-timings": true, + "$feature/recording-debugging": true, + "$feature/enable-prompts": true, + "$feature/feedback-scene": true, + "$feature/early-access-feature": true, + "$feature/early-access-feature-site-button": true, + "$feature/hedgehog-mode-debug": true, + "$feature/auto-redirect": true, + "$feature/session-recording-blob-replay": true, + "$feature/surveys": true, + "$feature/generic-signup-benefits": true, + "$feature/surveys-positions": true, + "$feature/web-analytics": true, + "$feature/high-frequency-batch-exports": true, + "$feature/exception-autocapture": true, + "$feature/data-warehouse": true, + "$feature/data-warehouse-views": true, + "$feature/ff-dashboard-templates": true, + "$feature/show-product-intro-existing-products": true, + "$feature/artificial-hog": true, + "$feature/cs-dashboards": true, + "$feature/product-specific-onboarding": true, + "$feature/redirect-signups-to-instance": true, + "$feature/apps-and-exports-ui": true, + "$feature/survey-nps-results": true, + "$feature/session-recording-allow-v1-snapshots": true, + "$feature/session-replay-cors-proxy": true, + "$feature/webhooks-denylist": true, + "$feature/surveys-site-app-deprecation": true, + "$feature/surveys-multiple-questions": true, + "$feature/surveys-results-visualizations": true, + "$feature/console-recording-search": true, + "$feature/persons-hogql-query": true, + "$feature/notebooks": true, + "$feature_flag_payloads": {}, + "realm": "hosted-clickhouse", + "email_service_available": false, + "slack_service_available": false, + "$user_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "is_demo_project": false, + "$groups": { + "project": "018a92f8-b602-0000-75de-4b9073693531", + "organization": "018a92f8-afff-0000-efec-ca77de39e384", + "customer": "cus_OdSgxxWtHOtq9g", + "instance": "http://localhost:8000" + }, + "has_billing_plan": true, + "customer_deactivated": false, + "current_total_amount_usd": "0.00", + "percentage_usage.product_analytics": 0, + "current_amount_usd.product_analytics": "0.00", + "unit_amount_usd.product_analytics": null, + "usage_limit.product_analytics": null, + "current_usage.product_analytics": 3729, + "projected_usage.product_analytics": 0, + "free_allocation.product_analytics": 0, + "percentage_usage.session_replay": 0, + "current_amount_usd.session_replay": "0.00", + "unit_amount_usd.session_replay": null, + "usage_limit.session_replay": null, + "current_usage.session_replay": 254, + "projected_usage.session_replay": 0, + "free_allocation.session_replay": 0, + "percentage_usage.feature_flags": 0, + "current_amount_usd.feature_flags": "0.00", + "unit_amount_usd.feature_flags": null, + "usage_limit.feature_flags": null, + "current_usage.feature_flags": 0, + "projected_usage.feature_flags": 0, + "free_allocation.feature_flags": 0, + "percentage_usage.integrations": 0, + "current_amount_usd.integrations": null, + "unit_amount_usd.integrations": null, + "usage_limit.integrations": 0, + "current_usage.integrations": 0, + "projected_usage.integrations": 0, + "free_allocation.integrations": 0, + "percentage_usage.platform_and_support": 0, + "current_amount_usd.platform_and_support": null, + "unit_amount_usd.platform_and_support": null, + "usage_limit.platform_and_support": 0, + "current_usage.platform_and_support": 0, + "projected_usage.platform_and_support": 0, + "free_allocation.platform_and_support": 0, + "billing_period_start": "2023-10-14T09:22:33.000Z", + "billing_period_end": "2023-11-14T09:22:33.000Z", + "$referrer": "$direct", + "$referring_domain": "$direct", + "title": "PostHog", + "token": "phc_OWGI2wKbfi7rWDZT9wkl8uGcfe0wOGCvflLEZSMiaT0", + "$session_id": "018b4ca0-9686-7b75-ba2e-61e9c0054b65", + "$window_id": "018b4ca0-9686-7b75-ba2e-61ea857e58f0", + "$ip": "127.0.0.1", + "$set": { + "$os": "Mac OS X", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI#activeTab=feed&state=eyJ0eXBlIjoiZG9jIiwiY29udGVudCI6W3sidHlwZSI6ImhlYWRpbmciLCJhdHRycyI6eyJsZXZlbCI6MX0sImNvbnRlbnQiOlt7InR5cGUiOiJ0ZXh0IiwidGV4dCI6ImtyUmZnb3BzVXkxVHdOVTF5aFNETHFORFRkNk41dE1ackhsbThuTEpJREkifV19LHsidHlwZSI6InBoLXBlcnNvbi1mZWVkIiwiYXR0cnMiOnsiaGVpZ2h0IjpudWxsLCJ0aXRsZSI6bnVsbCwibm9kZUlkIjoiNmQ0ODUwNjYtZWM5OS00ODNkLThiOTgtNGQ4YTJkYzljYzRiIiwiaWQiOiJrclJmZ29wc1V5MVR3TlUxeWhTRExxTkRUZDZONXRNWnJIbG04bkxKSURJIiwiX19pbml0IjpudWxsLCJjaGlsZHJlbiI6W3sidHlwZSI6InBoLXBlcnNvbiIsImF0dHJzIjp7ImlkIjoia3JSZmdvcHNVeTFUd05VMXloU0RMcU5EVGQ2TjV0TVpySGxtOG5MSklESSIsIm5vZGVJZCI6IjNkMzZiZjU3LTFkYjQtNDJlZi1iNzhiLWUyZDNkNGViOWM5NSJ9fSx7InR5cGUiOiJwaC1tYXAiLCJhdHRycyI6eyJpZCI6ImtyUmZnb3BzVXkxVHdOVTF5aFNETHFORFRkNk41dE1ackhsbThuTEpJREkiLCJub2RlSWQiOiI1MzE0ZWI2MS1lYTA2LTQyOGQtYWEzZi0zMDA4OWJjZmUxYjgifX0seyJ0eXBlIjoicGgtcHJvcGVydGllcyIsImF0dHJzIjp7ImlkIjoia3JSZmdvcHNVeTFUd05VMXloU0RMcU5EVGQ2TjV0TVpySGxtOG5MSklESSIsIm5vZGVJZCI6ImUwMjE1NDU5LWY0YTgtNGJjNy04NDhmLTYxODE1NzY1NzlmNyJ9fV19fV19", + "$pathname": "/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$browser_version": 117, + "$referrer": "$direct", + "$referring_domain": "$direct" + }, + "$set_once": { + "$initial_os": "Mac OS X", + "$initial_browser": "Chrome", + "$initial_device_type": "Desktop", + "$initial_current_url": "http://localhost:8000/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI#activeTab=feed&state=eyJ0eXBlIjoiZG9jIiwiY29udGVudCI6W3sidHlwZSI6ImhlYWRpbmciLCJhdHRycyI6eyJsZXZlbCI6MX0sImNvbnRlbnQiOlt7InR5cGUiOiJ0ZXh0IiwidGV4dCI6ImtyUmZnb3BzVXkxVHdOVTF5aFNETHFORFRkNk41dE1ackhsbThuTEpJREkifV19LHsidHlwZSI6InBoLXBlcnNvbi1mZWVkIiwiYXR0cnMiOnsiaGVpZ2h0IjpudWxsLCJ0aXRsZSI6bnVsbCwibm9kZUlkIjoiNmQ0ODUwNjYtZWM5OS00ODNkLThiOTgtNGQ4YTJkYzljYzRiIiwiaWQiOiJrclJmZ29wc1V5MVR3TlUxeWhTRExxTkRUZDZONXRNWnJIbG04bkxKSURJIiwiX19pbml0IjpudWxsLCJjaGlsZHJlbiI6W3sidHlwZSI6InBoLXBlcnNvbiIsImF0dHJzIjp7ImlkIjoia3JSZmdvcHNVeTFUd05VMXloU0RMcU5EVGQ2TjV0TVpySGxtOG5MSklESSIsIm5vZGVJZCI6IjNkMzZiZjU3LTFkYjQtNDJlZi1iNzhiLWUyZDNkNGViOWM5NSJ9fSx7InR5cGUiOiJwaC1tYXAiLCJhdHRycyI6eyJpZCI6ImtyUmZnb3BzVXkxVHdOVTF5aFNETHFORFRkNk41dE1ackhsbThuTEpJREkiLCJub2RlSWQiOiI1MzE0ZWI2MS1lYTA2LTQyOGQtYWEzZi0zMDA4OWJjZmUxYjgifX0seyJ0eXBlIjoicGgtcHJvcGVydGllcyIsImF0dHJzIjp7ImlkIjoia3JSZmdvcHNVeTFUd05VMXloU0RMcU5EVGQ2TjV0TVpySGxtOG5MSklESSIsIm5vZGVJZCI6ImUwMjE1NDU5LWY0YTgtNGJjNy04NDhmLTYxODE1NzY1NzlmNyJ9fV19fV19", + "$initial_pathname": "/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$initial_browser_version": 117, + "$initial_referrer": "$direct", + "$initial_referring_domain": "$direct" + }, + "$sent_at": "2023-10-20T10:30:40.121000+00:00", + "$geoip_city_name": "Sydney", + "$geoip_country_name": "Australia", + "$geoip_country_code": "AU", + "$geoip_continent_name": "Oceania", + "$geoip_continent_code": "OC", + "$geoip_postal_code": "2000", + "$geoip_latitude": -33.8715, + "$geoip_longitude": 151.2006, + "$geoip_time_zone": "Australia/Sydney", + "$geoip_subdivision_1_code": "NSW", + "$geoip_subdivision_1_name": "New South Wales", + "$plugins_succeeded": ["GeoIP (1)"], + "$plugins_failed": [], + "$plugins_deferred": [], + "$group_3": "018a92f8-b602-0000-75de-4b9073693531", + "$group_2": "018a92f8-afff-0000-efec-ca77de39e384", + "$group_4": "cus_OdSgxxWtHOtq9g", + "$group_1": "http://localhost:8000" + }, + "timestamp": "2023-10-20T10:30:40.138000+00:00", + "uuid": null + } + ], + "recording_duration_s": 72.0, + "sessionId": "018b4ca0-9686-7b75-ba2e-61e9c0054b65" + }, + { + "events": [ + { + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "elements": [], + "elements_chain": null, + "event": "dashboard updated", + "id": "018b4cc2-bd56-0000-ed0f-dbd6f467ac8c", + "person": null, + "properties": { + "pinned": true, + "item_count": 7, + "is_shared": false, + "created_at": "2023-09-14T09:15:00.211731+00:00", + "has_description": true, + "tags_count": 0, + "$groups": { + "instance": "http://localhost:8000", + "organization": "018a92f8-afff-0000-efec-ca77de39e384", + "customer": "cus_OdSgxxWtHOtq9g", + "project": "018a92f8-b602-0000-75de-4b9073693531" + }, + "$lib": "posthog-python", + "$lib_version": "3.0.1", + "$geoip_disable": true, + "$ip": "127.0.0.1", + "$plugins_succeeded": ["GeoIP (1)"], + "$plugins_failed": [], + "$plugins_deferred": [], + "$group_1": "http://localhost:8000", + "$group_2": "018a92f8-afff-0000-efec-ca77de39e384", + "$group_4": "cus_OdSgxxWtHOtq9g", + "$group_3": "018a92f8-b602-0000-75de-4b9073693531" + }, + "timestamp": "2023-10-20T11:05:12.306000+00:00", + "uuid": null + } + ], + "recording_duration_s": null, + "sessionId": "" + }, + { + "events": [ + { + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "elements": [], + "elements_chain": null, + "event": "$set", + "id": "018b4cc2-908b-7989-a77a-ae123bc7cbc4", + "person": null, + "properties": { + "$os": "Mac OS X", + "$os_version": "10.15.7", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/", + "$host": "localhost:8000", + "$pathname": "/", + "$browser_version": 117, + "$browser_language": "en-GB", + "$screen_height": 982, + "$screen_width": 1512, + "$viewport_height": 859, + "$viewport_width": 1512, + "$lib": "web", + "$lib_version": "1.84.0", + "$insert_id": "ha0xgsu9f9blyc2m", + "$time": 1697799901.323, + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$device_id": "018a92fd-7b25-7770-a050-577e94fd148c", + "$console_log_recording_enabled_server_side": true, + "$session_recording_recorder_version_server_side": "v2", + "$autocapture_disabled_server_side": false, + "$active_feature_flags": [ + "signup-page-4.0", + "cmd-k-search", + "posthog-3000", + "funnels-cue-opt-out-7301", + "retention-breakdown", + "smoothing-interval", + "billing-limit", + "kafka-inspector", + "historical-exports-v2", + "person-on-events-enabled", + "region-select", + "ingestion-warnings-enabled", + "session-reset-on-load", + "recordings-on-feature-flags", + "auto-rollback-feature-flags", + "onboarding-v2-demo", + "feature-flag-rollout-ux", + "role-based-access", + "query_running_time", + "query-timings", + "recording-debugging", + "enable-prompts", + "feedback-scene", + "early-access-feature", + "early-access-feature-site-button", + "hedgehog-mode-debug", + "auto-redirect", + "session-recording-blob-replay", + "surveys", + "generic-signup-benefits", + "surveys-positions", + "web-analytics", + "high-frequency-batch-exports", + "exception-autocapture", + "data-warehouse", + "data-warehouse-views", + "ff-dashboard-templates", + "show-product-intro-existing-products", + "artificial-hog", + "cs-dashboards", + "product-specific-onboarding", + "redirect-signups-to-instance", + "apps-and-exports-ui", + "survey-nps-results", + "session-recording-allow-v1-snapshots", + "session-replay-cors-proxy", + "webhooks-denylist", + "surveys-site-app-deprecation", + "surveys-multiple-questions", + "surveys-results-visualizations", + "console-recording-search", + "persons-hogql-query", + "notebooks" + ], + "$feature/file-previews": false, + "$feature/signup-page-4.0": "control", + "$feature/hogql-insights": false, + "$feature/cmd-k-search": true, + "$feature/posthog-3000": true, + "$feature/funnels-cue-opt-out-7301": true, + "$feature/retention-breakdown": true, + "$feature/smoothing-interval": true, + "$feature/billing-limit": true, + "$feature/kafka-inspector": true, + "$feature/historical-exports-v2": true, + "$feature/person-on-events-enabled": true, + "$feature/region-select": true, + "$feature/ingestion-warnings-enabled": true, + "$feature/session-reset-on-load": true, + "$feature/recordings-on-feature-flags": true, + "$feature/auto-rollback-feature-flags": true, + "$feature/onboarding-v2-demo": true, + "$feature/feature-flag-rollout-ux": true, + "$feature/role-based-access": true, + "$feature/query_running_time": true, + "$feature/query-timings": true, + "$feature/recording-debugging": true, + "$feature/enable-prompts": true, + "$feature/feedback-scene": true, + "$feature/early-access-feature": true, + "$feature/early-access-feature-site-button": true, + "$feature/hedgehog-mode-debug": true, + "$feature/auto-redirect": true, + "$feature/session-recording-blob-replay": true, + "$feature/surveys": true, + "$feature/generic-signup-benefits": true, + "$feature/surveys-positions": true, + "$feature/web-analytics": true, + "$feature/high-frequency-batch-exports": true, + "$feature/exception-autocapture": true, + "$feature/data-warehouse": true, + "$feature/data-warehouse-views": true, + "$feature/ff-dashboard-templates": true, + "$feature/show-product-intro-existing-products": true, + "$feature/artificial-hog": true, + "$feature/cs-dashboards": true, + "$feature/product-specific-onboarding": true, + "$feature/redirect-signups-to-instance": true, + "$feature/apps-and-exports-ui": true, + "$feature/survey-nps-results": true, + "$feature/session-recording-allow-v1-snapshots": true, + "$feature/session-replay-cors-proxy": true, + "$feature/webhooks-denylist": true, + "$feature/surveys-site-app-deprecation": true, + "$feature/surveys-multiple-questions": true, + "$feature/surveys-results-visualizations": true, + "$feature/console-recording-search": true, + "$feature/persons-hogql-query": true, + "$feature/notebooks": true, + "$feature_flag_payloads": {}, + "realm": "hosted-clickhouse", + "email_service_available": false, + "slack_service_available": false, + "$user_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "is_demo_project": false, + "$groups": { + "project": "018a92f8-b602-0000-75de-4b9073693531", + "organization": "018a92f8-afff-0000-efec-ca77de39e384", + "customer": "cus_OdSgxxWtHOtq9g", + "instance": "http://localhost:8000" + }, + "has_billing_plan": true, + "customer_deactivated": false, + "current_total_amount_usd": "0.00", + "percentage_usage.product_analytics": 0, + "current_amount_usd.product_analytics": "0.00", + "unit_amount_usd.product_analytics": null, + "usage_limit.product_analytics": null, + "current_usage.product_analytics": 3729, + "projected_usage.product_analytics": 0, + "free_allocation.product_analytics": 0, + "percentage_usage.session_replay": 0, + "current_amount_usd.session_replay": "0.00", + "unit_amount_usd.session_replay": null, + "usage_limit.session_replay": null, + "current_usage.session_replay": 254, + "projected_usage.session_replay": 0, + "free_allocation.session_replay": 0, + "percentage_usage.feature_flags": 0, + "current_amount_usd.feature_flags": "0.00", + "unit_amount_usd.feature_flags": null, + "usage_limit.feature_flags": null, + "current_usage.feature_flags": 0, + "projected_usage.feature_flags": 0, + "free_allocation.feature_flags": 0, + "percentage_usage.integrations": 0, + "current_amount_usd.integrations": null, + "unit_amount_usd.integrations": null, + "usage_limit.integrations": 0, + "current_usage.integrations": 0, + "projected_usage.integrations": 0, + "free_allocation.integrations": 0, + "percentage_usage.platform_and_support": 0, + "current_amount_usd.platform_and_support": null, + "unit_amount_usd.platform_and_support": null, + "usage_limit.platform_and_support": 0, + "current_usage.platform_and_support": 0, + "projected_usage.platform_and_support": 0, + "free_allocation.platform_and_support": 0, + "billing_period_start": "2023-10-14T09:22:33.000Z", + "billing_period_end": "2023-11-14T09:22:33.000Z", + "$referrer": "$direct", + "$referring_domain": "$direct", + "$set": { + "email": "test@posthog.com", + "$os": "Mac OS X", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/", + "$pathname": "/", + "$browser_version": 117, + "$referrer": "$direct", + "$referring_domain": "$direct" + }, + "$set_once": { + "$initial_os": "Mac OS X", + "$initial_browser": "Chrome", + "$initial_device_type": "Desktop", + "$initial_current_url": "http://localhost:8000/", + "$initial_pathname": "/", + "$initial_browser_version": 117, + "$initial_referrer": "$direct", + "$initial_referring_domain": "$direct" + }, + "token": "phc_OWGI2wKbfi7rWDZT9wkl8uGcfe0wOGCvflLEZSMiaT0", + "$session_id": "018b4cc2-908b-7989-a77a-ae1396eef1de", + "$window_id": "018b4cc2-908b-7989-a77a-ae1465fa2118", + "$ip": "127.0.0.1", + "$sent_at": "2023-10-20T11:05:04.317000+00:00", + "$geoip_city_name": "Sydney", + "$geoip_country_name": "Australia", + "$geoip_country_code": "AU", + "$geoip_continent_name": "Oceania", + "$geoip_continent_code": "OC", + "$geoip_postal_code": "2000", + "$geoip_latitude": -33.8715, + "$geoip_longitude": 151.2006, + "$geoip_time_zone": "Australia/Sydney", + "$geoip_subdivision_1_code": "NSW", + "$geoip_subdivision_1_name": "New South Wales", + "$plugins_succeeded": ["GeoIP (1)"], + "$plugins_failed": [], + "$plugins_deferred": [], + "$group_3": "018a92f8-b602-0000-75de-4b9073693531", + "$group_2": "018a92f8-afff-0000-efec-ca77de39e384", + "$group_4": "cus_OdSgxxWtHOtq9g", + "$group_1": "http://localhost:8000" + }, + "timestamp": "2023-10-20T11:05:01.338000+00:00", + "uuid": null + }, + { + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "elements": [], + "elements_chain": null, + "event": "$groupidentify", + "id": "018b4cc2-908c-7f15-8890-d2f9975a511c", + "person": null, + "properties": { + "$os": "Mac OS X", + "$os_version": "10.15.7", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/", + "$host": "localhost:8000", + "$pathname": "/", + "$browser_version": 117, + "$browser_language": "en-GB", + "$screen_height": 982, + "$screen_width": 1512, + "$viewport_height": 859, + "$viewport_width": 1512, + "$lib": "web", + "$lib_version": "1.84.0", + "$insert_id": "ud4b8d49iiqqfdil", + "$time": 1697799901.325, + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$device_id": "018a92fd-7b25-7770-a050-577e94fd148c", + "$console_log_recording_enabled_server_side": true, + "$session_recording_recorder_version_server_side": "v2", + "$autocapture_disabled_server_side": false, + "$active_feature_flags": [ + "signup-page-4.0", + "cmd-k-search", + "posthog-3000", + "funnels-cue-opt-out-7301", + "retention-breakdown", + "smoothing-interval", + "billing-limit", + "kafka-inspector", + "historical-exports-v2", + "person-on-events-enabled", + "region-select", + "ingestion-warnings-enabled", + "session-reset-on-load", + "recordings-on-feature-flags", + "auto-rollback-feature-flags", + "onboarding-v2-demo", + "feature-flag-rollout-ux", + "role-based-access", + "query_running_time", + "query-timings", + "recording-debugging", + "enable-prompts", + "feedback-scene", + "early-access-feature", + "early-access-feature-site-button", + "hedgehog-mode-debug", + "auto-redirect", + "session-recording-blob-replay", + "surveys", + "generic-signup-benefits", + "surveys-positions", + "web-analytics", + "high-frequency-batch-exports", + "exception-autocapture", + "data-warehouse", + "data-warehouse-views", + "ff-dashboard-templates", + "show-product-intro-existing-products", + "artificial-hog", + "cs-dashboards", + "product-specific-onboarding", + "redirect-signups-to-instance", + "apps-and-exports-ui", + "survey-nps-results", + "session-recording-allow-v1-snapshots", + "session-replay-cors-proxy", + "webhooks-denylist", + "surveys-site-app-deprecation", + "surveys-multiple-questions", + "surveys-results-visualizations", + "console-recording-search", + "persons-hogql-query", + "notebooks" + ], + "$feature/file-previews": false, + "$feature/signup-page-4.0": "control", + "$feature/hogql-insights": false, + "$feature/cmd-k-search": true, + "$feature/posthog-3000": true, + "$feature/funnels-cue-opt-out-7301": true, + "$feature/retention-breakdown": true, + "$feature/smoothing-interval": true, + "$feature/billing-limit": true, + "$feature/kafka-inspector": true, + "$feature/historical-exports-v2": true, + "$feature/person-on-events-enabled": true, + "$feature/region-select": true, + "$feature/ingestion-warnings-enabled": true, + "$feature/session-reset-on-load": true, + "$feature/recordings-on-feature-flags": true, + "$feature/auto-rollback-feature-flags": true, + "$feature/onboarding-v2-demo": true, + "$feature/feature-flag-rollout-ux": true, + "$feature/role-based-access": true, + "$feature/query_running_time": true, + "$feature/query-timings": true, + "$feature/recording-debugging": true, + "$feature/enable-prompts": true, + "$feature/feedback-scene": true, + "$feature/early-access-feature": true, + "$feature/early-access-feature-site-button": true, + "$feature/hedgehog-mode-debug": true, + "$feature/auto-redirect": true, + "$feature/session-recording-blob-replay": true, + "$feature/surveys": true, + "$feature/generic-signup-benefits": true, + "$feature/surveys-positions": true, + "$feature/web-analytics": true, + "$feature/high-frequency-batch-exports": true, + "$feature/exception-autocapture": true, + "$feature/data-warehouse": true, + "$feature/data-warehouse-views": true, + "$feature/ff-dashboard-templates": true, + "$feature/show-product-intro-existing-products": true, + "$feature/artificial-hog": true, + "$feature/cs-dashboards": true, + "$feature/product-specific-onboarding": true, + "$feature/redirect-signups-to-instance": true, + "$feature/apps-and-exports-ui": true, + "$feature/survey-nps-results": true, + "$feature/session-recording-allow-v1-snapshots": true, + "$feature/session-replay-cors-proxy": true, + "$feature/webhooks-denylist": true, + "$feature/surveys-site-app-deprecation": true, + "$feature/surveys-multiple-questions": true, + "$feature/surveys-results-visualizations": true, + "$feature/console-recording-search": true, + "$feature/persons-hogql-query": true, + "$feature/notebooks": true, + "$feature_flag_payloads": {}, + "realm": "hosted-clickhouse", + "email_service_available": false, + "slack_service_available": false, + "$user_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "is_demo_project": false, + "$groups": { + "project": "018a92f8-b602-0000-75de-4b9073693531", + "organization": "018a92f8-afff-0000-efec-ca77de39e384", + "customer": "cus_OdSgxxWtHOtq9g", + "instance": "http://localhost:8000" + }, + "has_billing_plan": true, + "customer_deactivated": false, + "current_total_amount_usd": "0.00", + "percentage_usage.product_analytics": 0, + "current_amount_usd.product_analytics": "0.00", + "unit_amount_usd.product_analytics": null, + "usage_limit.product_analytics": null, + "current_usage.product_analytics": 3729, + "projected_usage.product_analytics": 0, + "free_allocation.product_analytics": 0, + "percentage_usage.session_replay": 0, + "current_amount_usd.session_replay": "0.00", + "unit_amount_usd.session_replay": null, + "usage_limit.session_replay": null, + "current_usage.session_replay": 254, + "projected_usage.session_replay": 0, + "free_allocation.session_replay": 0, + "percentage_usage.feature_flags": 0, + "current_amount_usd.feature_flags": "0.00", + "unit_amount_usd.feature_flags": null, + "usage_limit.feature_flags": null, + "current_usage.feature_flags": 0, + "projected_usage.feature_flags": 0, + "free_allocation.feature_flags": 0, + "percentage_usage.integrations": 0, + "current_amount_usd.integrations": null, + "unit_amount_usd.integrations": null, + "usage_limit.integrations": 0, + "current_usage.integrations": 0, + "projected_usage.integrations": 0, + "free_allocation.integrations": 0, + "percentage_usage.platform_and_support": 0, + "current_amount_usd.platform_and_support": null, + "unit_amount_usd.platform_and_support": null, + "usage_limit.platform_and_support": 0, + "current_usage.platform_and_support": 0, + "projected_usage.platform_and_support": 0, + "free_allocation.platform_and_support": 0, + "billing_period_start": "2023-10-14T09:22:33.000Z", + "billing_period_end": "2023-11-14T09:22:33.000Z", + "$referrer": "$direct", + "$referring_domain": "$direct", + "$group_type": "project", + "$group_key": "018a92f8-b602-0000-75de-4b9073693531", + "$group_set": { + "id": 1, + "uuid": "018a92f8-b602-0000-75de-4b9073693531", + "name": "Hedgebox", + "ingested_event": true, + "is_demo": false, + "timezone": "UTC", + "instance_tag": "none" + }, + "token": "phc_OWGI2wKbfi7rWDZT9wkl8uGcfe0wOGCvflLEZSMiaT0", + "$session_id": "018b4cc2-908b-7989-a77a-ae1396eef1de", + "$window_id": "018b4cc2-908b-7989-a77a-ae1465fa2118", + "$ip": "127.0.0.1", + "$set": { + "$os": "Mac OS X", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/", + "$pathname": "/", + "$browser_version": 117, + "$referrer": "$direct", + "$referring_domain": "$direct" + }, + "$set_once": { + "$initial_os": "Mac OS X", + "$initial_browser": "Chrome", + "$initial_device_type": "Desktop", + "$initial_current_url": "http://localhost:8000/", + "$initial_pathname": "/", + "$initial_browser_version": 117, + "$initial_referrer": "$direct", + "$initial_referring_domain": "$direct" + }, + "$sent_at": "2023-10-20T11:05:04.317000+00:00", + "$geoip_city_name": "Sydney", + "$geoip_country_name": "Australia", + "$geoip_country_code": "AU", + "$geoip_continent_name": "Oceania", + "$geoip_continent_code": "OC", + "$geoip_postal_code": "2000", + "$geoip_latitude": -33.8715, + "$geoip_longitude": 151.2006, + "$geoip_time_zone": "Australia/Sydney", + "$geoip_subdivision_1_code": "NSW", + "$geoip_subdivision_1_name": "New South Wales", + "$plugins_succeeded": ["GeoIP (1)"], + "$plugins_failed": [], + "$plugins_deferred": [], + "$group_3": "018a92f8-b602-0000-75de-4b9073693531", + "$group_2": "018a92f8-afff-0000-efec-ca77de39e384", + "$group_4": "cus_OdSgxxWtHOtq9g", + "$group_1": "http://localhost:8000" + }, + "timestamp": "2023-10-20T11:05:01.339000+00:00", + "uuid": null + }, + { + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "elements": [], + "elements_chain": null, + "event": "$groupidentify", + "id": "018b4cc2-908d-7164-bff2-c69b5d464e46", + "person": null, + "properties": { + "$os": "Mac OS X", + "$os_version": "10.15.7", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/", + "$host": "localhost:8000", + "$pathname": "/", + "$browser_version": 117, + "$browser_language": "en-GB", + "$screen_height": 982, + "$screen_width": 1512, + "$viewport_height": 859, + "$viewport_width": 1512, + "$lib": "web", + "$lib_version": "1.84.0", + "$insert_id": "czd0chnpamqs1a4c", + "$time": 1697799901.325, + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$device_id": "018a92fd-7b25-7770-a050-577e94fd148c", + "$console_log_recording_enabled_server_side": true, + "$session_recording_recorder_version_server_side": "v2", + "$autocapture_disabled_server_side": false, + "$active_feature_flags": [ + "signup-page-4.0", + "cmd-k-search", + "posthog-3000", + "funnels-cue-opt-out-7301", + "retention-breakdown", + "smoothing-interval", + "billing-limit", + "kafka-inspector", + "historical-exports-v2", + "person-on-events-enabled", + "region-select", + "ingestion-warnings-enabled", + "session-reset-on-load", + "recordings-on-feature-flags", + "auto-rollback-feature-flags", + "onboarding-v2-demo", + "feature-flag-rollout-ux", + "role-based-access", + "query_running_time", + "query-timings", + "recording-debugging", + "enable-prompts", + "feedback-scene", + "early-access-feature", + "early-access-feature-site-button", + "hedgehog-mode-debug", + "auto-redirect", + "session-recording-blob-replay", + "surveys", + "generic-signup-benefits", + "surveys-positions", + "web-analytics", + "high-frequency-batch-exports", + "exception-autocapture", + "data-warehouse", + "data-warehouse-views", + "ff-dashboard-templates", + "show-product-intro-existing-products", + "artificial-hog", + "cs-dashboards", + "product-specific-onboarding", + "redirect-signups-to-instance", + "apps-and-exports-ui", + "survey-nps-results", + "session-recording-allow-v1-snapshots", + "session-replay-cors-proxy", + "webhooks-denylist", + "surveys-site-app-deprecation", + "surveys-multiple-questions", + "surveys-results-visualizations", + "console-recording-search", + "persons-hogql-query", + "notebooks" + ], + "$feature/file-previews": false, + "$feature/signup-page-4.0": "control", + "$feature/hogql-insights": false, + "$feature/cmd-k-search": true, + "$feature/posthog-3000": true, + "$feature/funnels-cue-opt-out-7301": true, + "$feature/retention-breakdown": true, + "$feature/smoothing-interval": true, + "$feature/billing-limit": true, + "$feature/kafka-inspector": true, + "$feature/historical-exports-v2": true, + "$feature/person-on-events-enabled": true, + "$feature/region-select": true, + "$feature/ingestion-warnings-enabled": true, + "$feature/session-reset-on-load": true, + "$feature/recordings-on-feature-flags": true, + "$feature/auto-rollback-feature-flags": true, + "$feature/onboarding-v2-demo": true, + "$feature/feature-flag-rollout-ux": true, + "$feature/role-based-access": true, + "$feature/query_running_time": true, + "$feature/query-timings": true, + "$feature/recording-debugging": true, + "$feature/enable-prompts": true, + "$feature/feedback-scene": true, + "$feature/early-access-feature": true, + "$feature/early-access-feature-site-button": true, + "$feature/hedgehog-mode-debug": true, + "$feature/auto-redirect": true, + "$feature/session-recording-blob-replay": true, + "$feature/surveys": true, + "$feature/generic-signup-benefits": true, + "$feature/surveys-positions": true, + "$feature/web-analytics": true, + "$feature/high-frequency-batch-exports": true, + "$feature/exception-autocapture": true, + "$feature/data-warehouse": true, + "$feature/data-warehouse-views": true, + "$feature/ff-dashboard-templates": true, + "$feature/show-product-intro-existing-products": true, + "$feature/artificial-hog": true, + "$feature/cs-dashboards": true, + "$feature/product-specific-onboarding": true, + "$feature/redirect-signups-to-instance": true, + "$feature/apps-and-exports-ui": true, + "$feature/survey-nps-results": true, + "$feature/session-recording-allow-v1-snapshots": true, + "$feature/session-replay-cors-proxy": true, + "$feature/webhooks-denylist": true, + "$feature/surveys-site-app-deprecation": true, + "$feature/surveys-multiple-questions": true, + "$feature/surveys-results-visualizations": true, + "$feature/console-recording-search": true, + "$feature/persons-hogql-query": true, + "$feature/notebooks": true, + "$feature_flag_payloads": {}, + "realm": "hosted-clickhouse", + "email_service_available": false, + "slack_service_available": false, + "$user_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "is_demo_project": false, + "$groups": { + "project": "018a92f8-b602-0000-75de-4b9073693531", + "organization": "018a92f8-afff-0000-efec-ca77de39e384", + "customer": "cus_OdSgxxWtHOtq9g", + "instance": "http://localhost:8000" + }, + "has_billing_plan": true, + "customer_deactivated": false, + "current_total_amount_usd": "0.00", + "percentage_usage.product_analytics": 0, + "current_amount_usd.product_analytics": "0.00", + "unit_amount_usd.product_analytics": null, + "usage_limit.product_analytics": null, + "current_usage.product_analytics": 3729, + "projected_usage.product_analytics": 0, + "free_allocation.product_analytics": 0, + "percentage_usage.session_replay": 0, + "current_amount_usd.session_replay": "0.00", + "unit_amount_usd.session_replay": null, + "usage_limit.session_replay": null, + "current_usage.session_replay": 254, + "projected_usage.session_replay": 0, + "free_allocation.session_replay": 0, + "percentage_usage.feature_flags": 0, + "current_amount_usd.feature_flags": "0.00", + "unit_amount_usd.feature_flags": null, + "usage_limit.feature_flags": null, + "current_usage.feature_flags": 0, + "projected_usage.feature_flags": 0, + "free_allocation.feature_flags": 0, + "percentage_usage.integrations": 0, + "current_amount_usd.integrations": null, + "unit_amount_usd.integrations": null, + "usage_limit.integrations": 0, + "current_usage.integrations": 0, + "projected_usage.integrations": 0, + "free_allocation.integrations": 0, + "percentage_usage.platform_and_support": 0, + "current_amount_usd.platform_and_support": null, + "unit_amount_usd.platform_and_support": null, + "usage_limit.platform_and_support": 0, + "current_usage.platform_and_support": 0, + "projected_usage.platform_and_support": 0, + "free_allocation.platform_and_support": 0, + "billing_period_start": "2023-10-14T09:22:33.000Z", + "billing_period_end": "2023-11-14T09:22:33.000Z", + "$referrer": "$direct", + "$referring_domain": "$direct", + "$group_type": "organization", + "$group_key": "018a92f8-afff-0000-efec-ca77de39e384", + "$group_set": { + "id": "018a92f8-afff-0000-efec-ca77de39e384", + "name": "Hedgebox Inc.", + "slug": "hedgebox-inc", + "created_at": "2023-09-14T09:14:46.145060Z", + "available_features": [ + "zapier", + "slack_integration", + "microsoft_teams_integration", + "discord_integration", + "apps", + "app_metrics", + "boolean_flags", + "multivariate_flags", + "persist_flags_cross_authentication", + "feature_flag_payloads", + "multiple_release_conditions", + "release_condition_overrides", + "targeting_by_group", + "local_evaluation_and_bootstrapping", + "flag_usage_stats", + "experimentation", + "group_experiments", + "funnel_experiments", + "secondary_metrics", + "statistical_analysis", + "console_logs", + "recordings_playlists", + "recordings_performance", + "recordings_file_export", + "group_analytics", + "dashboards", + "funnels", + "graphs_trends", + "paths", + "subscriptions", + "paths_advanced", + "dashboard_permissioning", + "dashboard_collaboration", + "ingestion_taxonomy", + "correlation_analysis", + "tagging", + "behavioral_cohort_filtering", + "tracked_users", + "data_retention", + "team_members", + "organizations_projects", + "api_access", + "project_based_permissioning", + "social_sso", + "sso_enforcement", + "white_labelling", + "community_support", + "dedicated_support", + "email_support", + "terms_and_conditions", + "security_assessment" + ], + "instance_tag": "none" + }, + "token": "phc_OWGI2wKbfi7rWDZT9wkl8uGcfe0wOGCvflLEZSMiaT0", + "$session_id": "018b4cc2-908b-7989-a77a-ae1396eef1de", + "$window_id": "018b4cc2-908b-7989-a77a-ae1465fa2118", + "$ip": "127.0.0.1", + "$set": { + "$os": "Mac OS X", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/", + "$pathname": "/", + "$browser_version": 117, + "$referrer": "$direct", + "$referring_domain": "$direct" + }, + "$set_once": { + "$initial_os": "Mac OS X", + "$initial_browser": "Chrome", + "$initial_device_type": "Desktop", + "$initial_current_url": "http://localhost:8000/", + "$initial_pathname": "/", + "$initial_browser_version": 117, + "$initial_referrer": "$direct", + "$initial_referring_domain": "$direct" + }, + "$sent_at": "2023-10-20T11:05:04.317000+00:00", + "$geoip_city_name": "Sydney", + "$geoip_country_name": "Australia", + "$geoip_country_code": "AU", + "$geoip_continent_name": "Oceania", + "$geoip_continent_code": "OC", + "$geoip_postal_code": "2000", + "$geoip_latitude": -33.8715, + "$geoip_longitude": 151.2006, + "$geoip_time_zone": "Australia/Sydney", + "$geoip_subdivision_1_code": "NSW", + "$geoip_subdivision_1_name": "New South Wales", + "$plugins_succeeded": ["GeoIP (1)"], + "$plugins_failed": [], + "$plugins_deferred": [], + "$group_3": "018a92f8-b602-0000-75de-4b9073693531", + "$group_2": "018a92f8-afff-0000-efec-ca77de39e384", + "$group_4": "cus_OdSgxxWtHOtq9g", + "$group_1": "http://localhost:8000" + }, + "timestamp": "2023-10-20T11:05:01.340000+00:00", + "uuid": null + }, + { + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "elements": [], + "elements_chain": null, + "event": "$feature_flag_called", + "id": "018b4cc2-90b0-7498-a7ad-d3ff880511c3", + "person": null, + "properties": { + "$os": "Mac OS X", + "$os_version": "10.15.7", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/home", + "$host": "localhost:8000", + "$pathname": "/home", + "$browser_version": 117, + "$browser_language": "en-GB", + "$screen_height": 982, + "$screen_width": 1512, + "$viewport_height": 859, + "$viewport_width": 1512, + "$lib": "web", + "$lib_version": "1.84.0", + "$insert_id": "rwp5rcbgzns63s79", + "$time": 1697799901.36, + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$device_id": "018a92fd-7b25-7770-a050-577e94fd148c", + "$console_log_recording_enabled_server_side": true, + "$session_recording_recorder_version_server_side": "v2", + "$autocapture_disabled_server_side": false, + "$active_feature_flags": [ + "signup-page-4.0", + "cmd-k-search", + "posthog-3000", + "funnels-cue-opt-out-7301", + "retention-breakdown", + "smoothing-interval", + "billing-limit", + "kafka-inspector", + "historical-exports-v2", + "person-on-events-enabled", + "region-select", + "ingestion-warnings-enabled", + "session-reset-on-load", + "recordings-on-feature-flags", + "auto-rollback-feature-flags", + "onboarding-v2-demo", + "feature-flag-rollout-ux", + "role-based-access", + "query_running_time", + "query-timings", + "recording-debugging", + "enable-prompts", + "feedback-scene", + "early-access-feature", + "early-access-feature-site-button", + "hedgehog-mode-debug", + "auto-redirect", + "session-recording-blob-replay", + "surveys", + "generic-signup-benefits", + "surveys-positions", + "web-analytics", + "high-frequency-batch-exports", + "exception-autocapture", + "data-warehouse", + "data-warehouse-views", + "ff-dashboard-templates", + "show-product-intro-existing-products", + "artificial-hog", + "cs-dashboards", + "product-specific-onboarding", + "redirect-signups-to-instance", + "apps-and-exports-ui", + "survey-nps-results", + "session-recording-allow-v1-snapshots", + "session-replay-cors-proxy", + "webhooks-denylist", + "surveys-site-app-deprecation", + "surveys-multiple-questions", + "surveys-results-visualizations", + "console-recording-search", + "persons-hogql-query", + "notebooks" + ], + "$feature/file-previews": false, + "$feature/signup-page-4.0": "control", + "$feature/hogql-insights": false, + "$feature/cmd-k-search": true, + "$feature/posthog-3000": true, + "$feature/funnels-cue-opt-out-7301": true, + "$feature/retention-breakdown": true, + "$feature/smoothing-interval": true, + "$feature/billing-limit": true, + "$feature/kafka-inspector": true, + "$feature/historical-exports-v2": true, + "$feature/person-on-events-enabled": true, + "$feature/region-select": true, + "$feature/ingestion-warnings-enabled": true, + "$feature/session-reset-on-load": true, + "$feature/recordings-on-feature-flags": true, + "$feature/auto-rollback-feature-flags": true, + "$feature/onboarding-v2-demo": true, + "$feature/feature-flag-rollout-ux": true, + "$feature/role-based-access": true, + "$feature/query_running_time": true, + "$feature/query-timings": true, + "$feature/recording-debugging": true, + "$feature/enable-prompts": true, + "$feature/feedback-scene": true, + "$feature/early-access-feature": true, + "$feature/early-access-feature-site-button": true, + "$feature/hedgehog-mode-debug": true, + "$feature/auto-redirect": true, + "$feature/session-recording-blob-replay": true, + "$feature/surveys": true, + "$feature/generic-signup-benefits": true, + "$feature/surveys-positions": true, + "$feature/web-analytics": true, + "$feature/high-frequency-batch-exports": true, + "$feature/exception-autocapture": true, + "$feature/data-warehouse": true, + "$feature/data-warehouse-views": true, + "$feature/ff-dashboard-templates": true, + "$feature/show-product-intro-existing-products": true, + "$feature/artificial-hog": true, + "$feature/cs-dashboards": true, + "$feature/product-specific-onboarding": true, + "$feature/redirect-signups-to-instance": true, + "$feature/apps-and-exports-ui": true, + "$feature/survey-nps-results": true, + "$feature/session-recording-allow-v1-snapshots": true, + "$feature/session-replay-cors-proxy": true, + "$feature/webhooks-denylist": true, + "$feature/surveys-site-app-deprecation": true, + "$feature/surveys-multiple-questions": true, + "$feature/surveys-results-visualizations": true, + "$feature/console-recording-search": true, + "$feature/persons-hogql-query": true, + "$feature/notebooks": true, + "$feature_flag_payloads": {}, + "realm": "hosted-clickhouse", + "email_service_available": false, + "slack_service_available": false, + "$user_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "is_demo_project": false, + "$groups": { + "project": "018a92f8-b602-0000-75de-4b9073693531", + "organization": "018a92f8-afff-0000-efec-ca77de39e384", + "customer": "cus_OdSgxxWtHOtq9g", + "instance": "http://localhost:8000" + }, + "has_billing_plan": true, + "customer_deactivated": false, + "current_total_amount_usd": "0.00", + "percentage_usage.product_analytics": 0, + "current_amount_usd.product_analytics": "0.00", + "unit_amount_usd.product_analytics": null, + "usage_limit.product_analytics": null, + "current_usage.product_analytics": 3729, + "projected_usage.product_analytics": 0, + "free_allocation.product_analytics": 0, + "percentage_usage.session_replay": 0, + "current_amount_usd.session_replay": "0.00", + "unit_amount_usd.session_replay": null, + "usage_limit.session_replay": null, + "current_usage.session_replay": 254, + "projected_usage.session_replay": 0, + "free_allocation.session_replay": 0, + "percentage_usage.feature_flags": 0, + "current_amount_usd.feature_flags": "0.00", + "unit_amount_usd.feature_flags": null, + "usage_limit.feature_flags": null, + "current_usage.feature_flags": 0, + "projected_usage.feature_flags": 0, + "free_allocation.feature_flags": 0, + "percentage_usage.integrations": 0, + "current_amount_usd.integrations": null, + "unit_amount_usd.integrations": null, + "usage_limit.integrations": 0, + "current_usage.integrations": 0, + "projected_usage.integrations": 0, + "free_allocation.integrations": 0, + "percentage_usage.platform_and_support": 0, + "current_amount_usd.platform_and_support": null, + "unit_amount_usd.platform_and_support": null, + "usage_limit.platform_and_support": 0, + "current_usage.platform_and_support": 0, + "projected_usage.platform_and_support": 0, + "free_allocation.platform_and_support": 0, + "billing_period_start": "2023-10-14T09:22:33.000Z", + "billing_period_end": "2023-11-14T09:22:33.000Z", + "$referrer": "$direct", + "$referring_domain": "$direct", + "$feature_flag": "posthog-3000", + "$feature_flag_response": true, + "token": "phc_OWGI2wKbfi7rWDZT9wkl8uGcfe0wOGCvflLEZSMiaT0", + "$session_id": "018b4cc2-908b-7989-a77a-ae1396eef1de", + "$window_id": "018b4cc2-908b-7989-a77a-ae1465fa2118", + "$ip": "127.0.0.1", + "$set": { + "$os": "Mac OS X", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/home", + "$pathname": "/home", + "$browser_version": 117, + "$referrer": "$direct", + "$referring_domain": "$direct" + }, + "$set_once": { + "$initial_os": "Mac OS X", + "$initial_browser": "Chrome", + "$initial_device_type": "Desktop", + "$initial_current_url": "http://localhost:8000/home", + "$initial_pathname": "/home", + "$initial_browser_version": 117, + "$initial_referrer": "$direct", + "$initial_referring_domain": "$direct" + }, + "$sent_at": "2023-10-20T11:05:04.317000+00:00", + "$geoip_city_name": "Sydney", + "$geoip_country_name": "Australia", + "$geoip_country_code": "AU", + "$geoip_continent_name": "Oceania", + "$geoip_continent_code": "OC", + "$geoip_postal_code": "2000", + "$geoip_latitude": -33.8715, + "$geoip_longitude": 151.2006, + "$geoip_time_zone": "Australia/Sydney", + "$geoip_subdivision_1_code": "NSW", + "$geoip_subdivision_1_name": "New South Wales", + "$plugins_succeeded": ["GeoIP (1)"], + "$plugins_failed": [], + "$plugins_deferred": [], + "$group_3": "018a92f8-b602-0000-75de-4b9073693531", + "$group_2": "018a92f8-afff-0000-efec-ca77de39e384", + "$group_4": "cus_OdSgxxWtHOtq9g", + "$group_1": "http://localhost:8000" + }, + "timestamp": "2023-10-20T11:05:01.375000+00:00", + "uuid": null + }, + { + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "elements": [], + "elements_chain": null, + "event": "$feature_flag_called", + "id": "018b4cc2-90b1-7bfb-9f2a-3a35e51991fe", + "person": null, + "properties": { + "$os": "Mac OS X", + "$os_version": "10.15.7", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/home", + "$host": "localhost:8000", + "$pathname": "/home", + "$browser_version": 117, + "$browser_language": "en-GB", + "$screen_height": 982, + "$screen_width": 1512, + "$viewport_height": 859, + "$viewport_width": 1512, + "$lib": "web", + "$lib_version": "1.84.0", + "$insert_id": "rjjli19zqga47ayx", + "$time": 1697799901.361, + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$device_id": "018a92fd-7b25-7770-a050-577e94fd148c", + "$console_log_recording_enabled_server_side": true, + "$session_recording_recorder_version_server_side": "v2", + "$autocapture_disabled_server_side": false, + "$active_feature_flags": [ + "signup-page-4.0", + "cmd-k-search", + "posthog-3000", + "funnels-cue-opt-out-7301", + "retention-breakdown", + "smoothing-interval", + "billing-limit", + "kafka-inspector", + "historical-exports-v2", + "person-on-events-enabled", + "region-select", + "ingestion-warnings-enabled", + "session-reset-on-load", + "recordings-on-feature-flags", + "auto-rollback-feature-flags", + "onboarding-v2-demo", + "feature-flag-rollout-ux", + "role-based-access", + "query_running_time", + "query-timings", + "recording-debugging", + "enable-prompts", + "feedback-scene", + "early-access-feature", + "early-access-feature-site-button", + "hedgehog-mode-debug", + "auto-redirect", + "session-recording-blob-replay", + "surveys", + "generic-signup-benefits", + "surveys-positions", + "web-analytics", + "high-frequency-batch-exports", + "exception-autocapture", + "data-warehouse", + "data-warehouse-views", + "ff-dashboard-templates", + "show-product-intro-existing-products", + "artificial-hog", + "cs-dashboards", + "product-specific-onboarding", + "redirect-signups-to-instance", + "apps-and-exports-ui", + "survey-nps-results", + "session-recording-allow-v1-snapshots", + "session-replay-cors-proxy", + "webhooks-denylist", + "surveys-site-app-deprecation", + "surveys-multiple-questions", + "surveys-results-visualizations", + "console-recording-search", + "persons-hogql-query", + "notebooks" + ], + "$feature/file-previews": false, + "$feature/signup-page-4.0": "control", + "$feature/hogql-insights": false, + "$feature/cmd-k-search": true, + "$feature/posthog-3000": true, + "$feature/funnels-cue-opt-out-7301": true, + "$feature/retention-breakdown": true, + "$feature/smoothing-interval": true, + "$feature/billing-limit": true, + "$feature/kafka-inspector": true, + "$feature/historical-exports-v2": true, + "$feature/person-on-events-enabled": true, + "$feature/region-select": true, + "$feature/ingestion-warnings-enabled": true, + "$feature/session-reset-on-load": true, + "$feature/recordings-on-feature-flags": true, + "$feature/auto-rollback-feature-flags": true, + "$feature/onboarding-v2-demo": true, + "$feature/feature-flag-rollout-ux": true, + "$feature/role-based-access": true, + "$feature/query_running_time": true, + "$feature/query-timings": true, + "$feature/recording-debugging": true, + "$feature/enable-prompts": true, + "$feature/feedback-scene": true, + "$feature/early-access-feature": true, + "$feature/early-access-feature-site-button": true, + "$feature/hedgehog-mode-debug": true, + "$feature/auto-redirect": true, + "$feature/session-recording-blob-replay": true, + "$feature/surveys": true, + "$feature/generic-signup-benefits": true, + "$feature/surveys-positions": true, + "$feature/web-analytics": true, + "$feature/high-frequency-batch-exports": true, + "$feature/exception-autocapture": true, + "$feature/data-warehouse": true, + "$feature/data-warehouse-views": true, + "$feature/ff-dashboard-templates": true, + "$feature/show-product-intro-existing-products": true, + "$feature/artificial-hog": true, + "$feature/cs-dashboards": true, + "$feature/product-specific-onboarding": true, + "$feature/redirect-signups-to-instance": true, + "$feature/apps-and-exports-ui": true, + "$feature/survey-nps-results": true, + "$feature/session-recording-allow-v1-snapshots": true, + "$feature/session-replay-cors-proxy": true, + "$feature/webhooks-denylist": true, + "$feature/surveys-site-app-deprecation": true, + "$feature/surveys-multiple-questions": true, + "$feature/surveys-results-visualizations": true, + "$feature/console-recording-search": true, + "$feature/persons-hogql-query": true, + "$feature/notebooks": true, + "$feature_flag_payloads": {}, + "realm": "hosted-clickhouse", + "email_service_available": false, + "slack_service_available": false, + "$user_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "is_demo_project": false, + "$groups": { + "project": "018a92f8-b602-0000-75de-4b9073693531", + "organization": "018a92f8-afff-0000-efec-ca77de39e384", + "customer": "cus_OdSgxxWtHOtq9g", + "instance": "http://localhost:8000" + }, + "has_billing_plan": true, + "customer_deactivated": false, + "current_total_amount_usd": "0.00", + "percentage_usage.product_analytics": 0, + "current_amount_usd.product_analytics": "0.00", + "unit_amount_usd.product_analytics": null, + "usage_limit.product_analytics": null, + "current_usage.product_analytics": 3729, + "projected_usage.product_analytics": 0, + "free_allocation.product_analytics": 0, + "percentage_usage.session_replay": 0, + "current_amount_usd.session_replay": "0.00", + "unit_amount_usd.session_replay": null, + "usage_limit.session_replay": null, + "current_usage.session_replay": 254, + "projected_usage.session_replay": 0, + "free_allocation.session_replay": 0, + "percentage_usage.feature_flags": 0, + "current_amount_usd.feature_flags": "0.00", + "unit_amount_usd.feature_flags": null, + "usage_limit.feature_flags": null, + "current_usage.feature_flags": 0, + "projected_usage.feature_flags": 0, + "free_allocation.feature_flags": 0, + "percentage_usage.integrations": 0, + "current_amount_usd.integrations": null, + "unit_amount_usd.integrations": null, + "usage_limit.integrations": 0, + "current_usage.integrations": 0, + "projected_usage.integrations": 0, + "free_allocation.integrations": 0, + "percentage_usage.platform_and_support": 0, + "current_amount_usd.platform_and_support": null, + "unit_amount_usd.platform_and_support": null, + "usage_limit.platform_and_support": 0, + "current_usage.platform_and_support": 0, + "projected_usage.platform_and_support": 0, + "free_allocation.platform_and_support": 0, + "billing_period_start": "2023-10-14T09:22:33.000Z", + "billing_period_end": "2023-11-14T09:22:33.000Z", + "$referrer": "$direct", + "$referring_domain": "$direct", + "$feature_flag": "enable-prompts", + "$feature_flag_response": true, + "token": "phc_OWGI2wKbfi7rWDZT9wkl8uGcfe0wOGCvflLEZSMiaT0", + "$session_id": "018b4cc2-908b-7989-a77a-ae1396eef1de", + "$window_id": "018b4cc2-908b-7989-a77a-ae1465fa2118", + "$ip": "127.0.0.1", + "$set": { + "$os": "Mac OS X", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/home", + "$pathname": "/home", + "$browser_version": 117, + "$referrer": "$direct", + "$referring_domain": "$direct" + }, + "$set_once": { + "$initial_os": "Mac OS X", + "$initial_browser": "Chrome", + "$initial_device_type": "Desktop", + "$initial_current_url": "http://localhost:8000/home", + "$initial_pathname": "/home", + "$initial_browser_version": 117, + "$initial_referrer": "$direct", + "$initial_referring_domain": "$direct" + }, + "$sent_at": "2023-10-20T11:05:04.317000+00:00", + "$geoip_city_name": "Sydney", + "$geoip_country_name": "Australia", + "$geoip_country_code": "AU", + "$geoip_continent_name": "Oceania", + "$geoip_continent_code": "OC", + "$geoip_postal_code": "2000", + "$geoip_latitude": -33.8715, + "$geoip_longitude": 151.2006, + "$geoip_time_zone": "Australia/Sydney", + "$geoip_subdivision_1_code": "NSW", + "$geoip_subdivision_1_name": "New South Wales", + "$plugins_succeeded": ["GeoIP (1)"], + "$plugins_failed": [], + "$plugins_deferred": [], + "$group_3": "018a92f8-b602-0000-75de-4b9073693531", + "$group_2": "018a92f8-afff-0000-efec-ca77de39e384", + "$group_4": "cus_OdSgxxWtHOtq9g", + "$group_1": "http://localhost:8000" + }, + "timestamp": "2023-10-20T11:05:01.375000+00:00", + "uuid": null + }, + { + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "elements": [], + "elements_chain": null, + "event": "$feature_flag_called", + "id": "018b4cc2-90bd-745c-b4b0-f90272791844", + "person": null, + "properties": { + "$os": "Mac OS X", + "$os_version": "10.15.7", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/home", + "$host": "localhost:8000", + "$pathname": "/home", + "$browser_version": 117, + "$browser_language": "en-GB", + "$screen_height": 982, + "$screen_width": 1512, + "$viewport_height": 859, + "$viewport_width": 1512, + "$lib": "web", + "$lib_version": "1.84.0", + "$insert_id": "vx58g66m43l6t6f3", + "$time": 1697799901.373, + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$device_id": "018a92fd-7b25-7770-a050-577e94fd148c", + "$console_log_recording_enabled_server_side": true, + "$session_recording_recorder_version_server_side": "v2", + "$autocapture_disabled_server_side": false, + "$active_feature_flags": [ + "signup-page-4.0", + "cmd-k-search", + "posthog-3000", + "funnels-cue-opt-out-7301", + "retention-breakdown", + "smoothing-interval", + "billing-limit", + "kafka-inspector", + "historical-exports-v2", + "person-on-events-enabled", + "region-select", + "ingestion-warnings-enabled", + "session-reset-on-load", + "recordings-on-feature-flags", + "auto-rollback-feature-flags", + "onboarding-v2-demo", + "feature-flag-rollout-ux", + "role-based-access", + "query_running_time", + "query-timings", + "recording-debugging", + "enable-prompts", + "feedback-scene", + "early-access-feature", + "early-access-feature-site-button", + "hedgehog-mode-debug", + "auto-redirect", + "session-recording-blob-replay", + "surveys", + "generic-signup-benefits", + "surveys-positions", + "web-analytics", + "high-frequency-batch-exports", + "exception-autocapture", + "data-warehouse", + "data-warehouse-views", + "ff-dashboard-templates", + "show-product-intro-existing-products", + "artificial-hog", + "cs-dashboards", + "product-specific-onboarding", + "redirect-signups-to-instance", + "apps-and-exports-ui", + "survey-nps-results", + "session-recording-allow-v1-snapshots", + "session-replay-cors-proxy", + "webhooks-denylist", + "surveys-site-app-deprecation", + "surveys-multiple-questions", + "surveys-results-visualizations", + "console-recording-search", + "persons-hogql-query", + "notebooks" + ], + "$feature/file-previews": false, + "$feature/signup-page-4.0": "control", + "$feature/hogql-insights": false, + "$feature/cmd-k-search": true, + "$feature/posthog-3000": true, + "$feature/funnels-cue-opt-out-7301": true, + "$feature/retention-breakdown": true, + "$feature/smoothing-interval": true, + "$feature/billing-limit": true, + "$feature/kafka-inspector": true, + "$feature/historical-exports-v2": true, + "$feature/person-on-events-enabled": true, + "$feature/region-select": true, + "$feature/ingestion-warnings-enabled": true, + "$feature/session-reset-on-load": true, + "$feature/recordings-on-feature-flags": true, + "$feature/auto-rollback-feature-flags": true, + "$feature/onboarding-v2-demo": true, + "$feature/feature-flag-rollout-ux": true, + "$feature/role-based-access": true, + "$feature/query_running_time": true, + "$feature/query-timings": true, + "$feature/recording-debugging": true, + "$feature/enable-prompts": true, + "$feature/feedback-scene": true, + "$feature/early-access-feature": true, + "$feature/early-access-feature-site-button": true, + "$feature/hedgehog-mode-debug": true, + "$feature/auto-redirect": true, + "$feature/session-recording-blob-replay": true, + "$feature/surveys": true, + "$feature/generic-signup-benefits": true, + "$feature/surveys-positions": true, + "$feature/web-analytics": true, + "$feature/high-frequency-batch-exports": true, + "$feature/exception-autocapture": true, + "$feature/data-warehouse": true, + "$feature/data-warehouse-views": true, + "$feature/ff-dashboard-templates": true, + "$feature/show-product-intro-existing-products": true, + "$feature/artificial-hog": true, + "$feature/cs-dashboards": true, + "$feature/product-specific-onboarding": true, + "$feature/redirect-signups-to-instance": true, + "$feature/apps-and-exports-ui": true, + "$feature/survey-nps-results": true, + "$feature/session-recording-allow-v1-snapshots": true, + "$feature/session-replay-cors-proxy": true, + "$feature/webhooks-denylist": true, + "$feature/surveys-site-app-deprecation": true, + "$feature/surveys-multiple-questions": true, + "$feature/surveys-results-visualizations": true, + "$feature/console-recording-search": true, + "$feature/persons-hogql-query": true, + "$feature/notebooks": true, + "$feature_flag_payloads": {}, + "realm": "hosted-clickhouse", + "email_service_available": false, + "slack_service_available": false, + "$user_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "is_demo_project": false, + "$groups": { + "project": "018a92f8-b602-0000-75de-4b9073693531", + "organization": "018a92f8-afff-0000-efec-ca77de39e384", + "customer": "cus_OdSgxxWtHOtq9g", + "instance": "http://localhost:8000" + }, + "has_billing_plan": true, + "customer_deactivated": false, + "current_total_amount_usd": "0.00", + "percentage_usage.product_analytics": 0, + "current_amount_usd.product_analytics": "0.00", + "unit_amount_usd.product_analytics": null, + "usage_limit.product_analytics": null, + "current_usage.product_analytics": 3729, + "projected_usage.product_analytics": 0, + "free_allocation.product_analytics": 0, + "percentage_usage.session_replay": 0, + "current_amount_usd.session_replay": "0.00", + "unit_amount_usd.session_replay": null, + "usage_limit.session_replay": null, + "current_usage.session_replay": 254, + "projected_usage.session_replay": 0, + "free_allocation.session_replay": 0, + "percentage_usage.feature_flags": 0, + "current_amount_usd.feature_flags": "0.00", + "unit_amount_usd.feature_flags": null, + "usage_limit.feature_flags": null, + "current_usage.feature_flags": 0, + "projected_usage.feature_flags": 0, + "free_allocation.feature_flags": 0, + "percentage_usage.integrations": 0, + "current_amount_usd.integrations": null, + "unit_amount_usd.integrations": null, + "usage_limit.integrations": 0, + "current_usage.integrations": 0, + "projected_usage.integrations": 0, + "free_allocation.integrations": 0, + "percentage_usage.platform_and_support": 0, + "current_amount_usd.platform_and_support": null, + "unit_amount_usd.platform_and_support": null, + "usage_limit.platform_and_support": 0, + "current_usage.platform_and_support": 0, + "projected_usage.platform_and_support": 0, + "free_allocation.platform_and_support": 0, + "billing_period_start": "2023-10-14T09:22:33.000Z", + "billing_period_end": "2023-11-14T09:22:33.000Z", + "$referrer": "$direct", + "$referring_domain": "$direct", + "$feature_flag": "notebooks", + "$feature_flag_response": true, + "token": "phc_OWGI2wKbfi7rWDZT9wkl8uGcfe0wOGCvflLEZSMiaT0", + "$session_id": "018b4cc2-908b-7989-a77a-ae1396eef1de", + "$window_id": "018b4cc2-908b-7989-a77a-ae1465fa2118", + "$ip": "127.0.0.1", + "$set": { + "$os": "Mac OS X", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/home", + "$pathname": "/home", + "$browser_version": 117, + "$referrer": "$direct", + "$referring_domain": "$direct" + }, + "$set_once": { + "$initial_os": "Mac OS X", + "$initial_browser": "Chrome", + "$initial_device_type": "Desktop", + "$initial_current_url": "http://localhost:8000/home", + "$initial_pathname": "/home", + "$initial_browser_version": 117, + "$initial_referrer": "$direct", + "$initial_referring_domain": "$direct" + }, + "$sent_at": "2023-10-20T11:05:04.317000+00:00", + "$geoip_city_name": "Sydney", + "$geoip_country_name": "Australia", + "$geoip_country_code": "AU", + "$geoip_continent_name": "Oceania", + "$geoip_continent_code": "OC", + "$geoip_postal_code": "2000", + "$geoip_latitude": -33.8715, + "$geoip_longitude": 151.2006, + "$geoip_time_zone": "Australia/Sydney", + "$geoip_subdivision_1_code": "NSW", + "$geoip_subdivision_1_name": "New South Wales", + "$plugins_succeeded": ["GeoIP (1)"], + "$plugins_failed": [], + "$plugins_deferred": [], + "$group_3": "018a92f8-b602-0000-75de-4b9073693531", + "$group_2": "018a92f8-afff-0000-efec-ca77de39e384", + "$group_4": "cus_OdSgxxWtHOtq9g", + "$group_1": "http://localhost:8000" + }, + "timestamp": "2023-10-20T11:05:01.387000+00:00", + "uuid": null + }, + { + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "elements": [], + "elements_chain": null, + "event": "$groupidentify", + "id": "018b4cc2-9140-73ac-b975-4e50e33b3fba", + "person": null, + "properties": { + "$os": "Mac OS X", + "$os_version": "10.15.7", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/home", + "$host": "localhost:8000", + "$pathname": "/home", + "$browser_version": 117, + "$browser_language": "en-GB", + "$screen_height": 982, + "$screen_width": 1512, + "$viewport_height": 859, + "$viewport_width": 1512, + "$lib": "web", + "$lib_version": "1.84.0", + "$insert_id": "x03pwwegn9jrn34n", + "$time": 1697799901.504, + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$device_id": "018a92fd-7b25-7770-a050-577e94fd148c", + "$console_log_recording_enabled_server_side": true, + "$session_recording_recorder_version_server_side": "v2", + "$autocapture_disabled_server_side": false, + "$active_feature_flags": [ + "signup-page-4.0", + "cmd-k-search", + "posthog-3000", + "funnels-cue-opt-out-7301", + "retention-breakdown", + "smoothing-interval", + "billing-limit", + "kafka-inspector", + "historical-exports-v2", + "person-on-events-enabled", + "region-select", + "ingestion-warnings-enabled", + "session-reset-on-load", + "recordings-on-feature-flags", + "auto-rollback-feature-flags", + "onboarding-v2-demo", + "feature-flag-rollout-ux", + "role-based-access", + "query_running_time", + "query-timings", + "recording-debugging", + "enable-prompts", + "feedback-scene", + "early-access-feature", + "early-access-feature-site-button", + "hedgehog-mode-debug", + "auto-redirect", + "session-recording-blob-replay", + "surveys", + "generic-signup-benefits", + "surveys-positions", + "web-analytics", + "high-frequency-batch-exports", + "exception-autocapture", + "data-warehouse", + "data-warehouse-views", + "ff-dashboard-templates", + "show-product-intro-existing-products", + "artificial-hog", + "cs-dashboards", + "product-specific-onboarding", + "redirect-signups-to-instance", + "apps-and-exports-ui", + "survey-nps-results", + "session-recording-allow-v1-snapshots", + "session-replay-cors-proxy", + "webhooks-denylist", + "surveys-site-app-deprecation", + "surveys-multiple-questions", + "surveys-results-visualizations", + "console-recording-search", + "persons-hogql-query", + "notebooks" + ], + "$feature/file-previews": false, + "$feature/signup-page-4.0": "control", + "$feature/hogql-insights": false, + "$feature/cmd-k-search": true, + "$feature/posthog-3000": true, + "$feature/funnels-cue-opt-out-7301": true, + "$feature/retention-breakdown": true, + "$feature/smoothing-interval": true, + "$feature/billing-limit": true, + "$feature/kafka-inspector": true, + "$feature/historical-exports-v2": true, + "$feature/person-on-events-enabled": true, + "$feature/region-select": true, + "$feature/ingestion-warnings-enabled": true, + "$feature/session-reset-on-load": true, + "$feature/recordings-on-feature-flags": true, + "$feature/auto-rollback-feature-flags": true, + "$feature/onboarding-v2-demo": true, + "$feature/feature-flag-rollout-ux": true, + "$feature/role-based-access": true, + "$feature/query_running_time": true, + "$feature/query-timings": true, + "$feature/recording-debugging": true, + "$feature/enable-prompts": true, + "$feature/feedback-scene": true, + "$feature/early-access-feature": true, + "$feature/early-access-feature-site-button": true, + "$feature/hedgehog-mode-debug": true, + "$feature/auto-redirect": true, + "$feature/session-recording-blob-replay": true, + "$feature/surveys": true, + "$feature/generic-signup-benefits": true, + "$feature/surveys-positions": true, + "$feature/web-analytics": true, + "$feature/high-frequency-batch-exports": true, + "$feature/exception-autocapture": true, + "$feature/data-warehouse": true, + "$feature/data-warehouse-views": true, + "$feature/ff-dashboard-templates": true, + "$feature/show-product-intro-existing-products": true, + "$feature/artificial-hog": true, + "$feature/cs-dashboards": true, + "$feature/product-specific-onboarding": true, + "$feature/redirect-signups-to-instance": true, + "$feature/apps-and-exports-ui": true, + "$feature/survey-nps-results": true, + "$feature/session-recording-allow-v1-snapshots": true, + "$feature/session-replay-cors-proxy": true, + "$feature/webhooks-denylist": true, + "$feature/surveys-site-app-deprecation": true, + "$feature/surveys-multiple-questions": true, + "$feature/surveys-results-visualizations": true, + "$feature/console-recording-search": true, + "$feature/persons-hogql-query": true, + "$feature/notebooks": true, + "$feature_flag_payloads": {}, + "realm": "hosted-clickhouse", + "email_service_available": false, + "slack_service_available": false, + "$user_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "is_demo_project": false, + "$groups": { + "project": "018a92f8-b602-0000-75de-4b9073693531", + "organization": "018a92f8-afff-0000-efec-ca77de39e384", + "customer": "cus_OdSgxxWtHOtq9g", + "instance": "http://localhost:8000" + }, + "has_billing_plan": true, + "customer_deactivated": false, + "current_total_amount_usd": "0.00", + "percentage_usage.product_analytics": 0, + "current_amount_usd.product_analytics": "0.00", + "unit_amount_usd.product_analytics": null, + "usage_limit.product_analytics": null, + "current_usage.product_analytics": 3729, + "projected_usage.product_analytics": 0, + "free_allocation.product_analytics": 0, + "percentage_usage.session_replay": 0, + "current_amount_usd.session_replay": "0.00", + "unit_amount_usd.session_replay": null, + "usage_limit.session_replay": null, + "current_usage.session_replay": 254, + "projected_usage.session_replay": 0, + "free_allocation.session_replay": 0, + "percentage_usage.feature_flags": 0, + "current_amount_usd.feature_flags": "0.00", + "unit_amount_usd.feature_flags": null, + "usage_limit.feature_flags": null, + "current_usage.feature_flags": 0, + "projected_usage.feature_flags": 0, + "free_allocation.feature_flags": 0, + "percentage_usage.integrations": 0, + "current_amount_usd.integrations": null, + "unit_amount_usd.integrations": null, + "usage_limit.integrations": 0, + "current_usage.integrations": 0, + "projected_usage.integrations": 0, + "free_allocation.integrations": 0, + "percentage_usage.platform_and_support": 0, + "current_amount_usd.platform_and_support": null, + "unit_amount_usd.platform_and_support": null, + "usage_limit.platform_and_support": 0, + "current_usage.platform_and_support": 0, + "projected_usage.platform_and_support": 0, + "free_allocation.platform_and_support": 0, + "billing_period_start": "2023-10-14T09:22:33.000Z", + "billing_period_end": "2023-11-14T09:22:33.000Z", + "$referrer": "$direct", + "$referring_domain": "$direct", + "$group_type": "instance", + "$group_key": "http://localhost:8000", + "$group_set": { + "site_url": "http://localhost:8000" + }, + "token": "phc_OWGI2wKbfi7rWDZT9wkl8uGcfe0wOGCvflLEZSMiaT0", + "$session_id": "018b4cc2-908b-7989-a77a-ae1396eef1de", + "$window_id": "018b4cc2-908b-7989-a77a-ae1465fa2118", + "$ip": "127.0.0.1", + "$set": { + "$os": "Mac OS X", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/home", + "$pathname": "/home", + "$browser_version": 117, + "$referrer": "$direct", + "$referring_domain": "$direct" + }, + "$set_once": { + "$initial_os": "Mac OS X", + "$initial_browser": "Chrome", + "$initial_device_type": "Desktop", + "$initial_current_url": "http://localhost:8000/home", + "$initial_pathname": "/home", + "$initial_browser_version": 117, + "$initial_referrer": "$direct", + "$initial_referring_domain": "$direct" + }, + "$sent_at": "2023-10-20T11:05:04.317000+00:00", + "$geoip_city_name": "Sydney", + "$geoip_country_name": "Australia", + "$geoip_country_code": "AU", + "$geoip_continent_name": "Oceania", + "$geoip_continent_code": "OC", + "$geoip_postal_code": "2000", + "$geoip_latitude": -33.8715, + "$geoip_longitude": 151.2006, + "$geoip_time_zone": "Australia/Sydney", + "$geoip_subdivision_1_code": "NSW", + "$geoip_subdivision_1_name": "New South Wales", + "$plugins_succeeded": ["GeoIP (1)"], + "$plugins_failed": [], + "$plugins_deferred": [], + "$group_3": "018a92f8-b602-0000-75de-4b9073693531", + "$group_2": "018a92f8-afff-0000-efec-ca77de39e384", + "$group_4": "cus_OdSgxxWtHOtq9g", + "$group_1": "http://localhost:8000" + }, + "timestamp": "2023-10-20T11:05:01.519000+00:00", + "uuid": null + }, + { + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "elements": [], + "elements_chain": null, + "event": "$pageview", + "id": "018b4cc2-91af-7940-abb9-c07bae63b31e", + "person": null, + "properties": { + "$os": "Mac OS X", + "$os_version": "10.15.7", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/home", + "$host": "localhost:8000", + "$pathname": "/home", + "$browser_version": 117, + "$browser_language": "en-GB", + "$screen_height": 982, + "$screen_width": 1512, + "$viewport_height": 859, + "$viewport_width": 1512, + "$lib": "web", + "$lib_version": "1.84.0", + "$insert_id": "5r7bw5fp42mlnj6q", + "$time": 1697799901.615, + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$device_id": "018a92fd-7b25-7770-a050-577e94fd148c", + "$console_log_recording_enabled_server_side": true, + "$session_recording_recorder_version_server_side": "v2", + "$autocapture_disabled_server_side": false, + "$active_feature_flags": [ + "signup-page-4.0", + "cmd-k-search", + "posthog-3000", + "funnels-cue-opt-out-7301", + "retention-breakdown", + "smoothing-interval", + "billing-limit", + "kafka-inspector", + "historical-exports-v2", + "person-on-events-enabled", + "region-select", + "ingestion-warnings-enabled", + "session-reset-on-load", + "recordings-on-feature-flags", + "auto-rollback-feature-flags", + "onboarding-v2-demo", + "feature-flag-rollout-ux", + "role-based-access", + "query_running_time", + "query-timings", + "recording-debugging", + "enable-prompts", + "feedback-scene", + "early-access-feature", + "early-access-feature-site-button", + "hedgehog-mode-debug", + "auto-redirect", + "session-recording-blob-replay", + "surveys", + "generic-signup-benefits", + "surveys-positions", + "web-analytics", + "high-frequency-batch-exports", + "exception-autocapture", + "data-warehouse", + "data-warehouse-views", + "ff-dashboard-templates", + "show-product-intro-existing-products", + "artificial-hog", + "cs-dashboards", + "product-specific-onboarding", + "redirect-signups-to-instance", + "apps-and-exports-ui", + "survey-nps-results", + "session-recording-allow-v1-snapshots", + "session-replay-cors-proxy", + "webhooks-denylist", + "surveys-site-app-deprecation", + "surveys-multiple-questions", + "surveys-results-visualizations", + "console-recording-search", + "persons-hogql-query", + "notebooks" + ], + "$feature/file-previews": false, + "$feature/signup-page-4.0": "control", + "$feature/hogql-insights": false, + "$feature/cmd-k-search": true, + "$feature/posthog-3000": true, + "$feature/funnels-cue-opt-out-7301": true, + "$feature/retention-breakdown": true, + "$feature/smoothing-interval": true, + "$feature/billing-limit": true, + "$feature/kafka-inspector": true, + "$feature/historical-exports-v2": true, + "$feature/person-on-events-enabled": true, + "$feature/region-select": true, + "$feature/ingestion-warnings-enabled": true, + "$feature/session-reset-on-load": true, + "$feature/recordings-on-feature-flags": true, + "$feature/auto-rollback-feature-flags": true, + "$feature/onboarding-v2-demo": true, + "$feature/feature-flag-rollout-ux": true, + "$feature/role-based-access": true, + "$feature/query_running_time": true, + "$feature/query-timings": true, + "$feature/recording-debugging": true, + "$feature/enable-prompts": true, + "$feature/feedback-scene": true, + "$feature/early-access-feature": true, + "$feature/early-access-feature-site-button": true, + "$feature/hedgehog-mode-debug": true, + "$feature/auto-redirect": true, + "$feature/session-recording-blob-replay": true, + "$feature/surveys": true, + "$feature/generic-signup-benefits": true, + "$feature/surveys-positions": true, + "$feature/web-analytics": true, + "$feature/high-frequency-batch-exports": true, + "$feature/exception-autocapture": true, + "$feature/data-warehouse": true, + "$feature/data-warehouse-views": true, + "$feature/ff-dashboard-templates": true, + "$feature/show-product-intro-existing-products": true, + "$feature/artificial-hog": true, + "$feature/cs-dashboards": true, + "$feature/product-specific-onboarding": true, + "$feature/redirect-signups-to-instance": true, + "$feature/apps-and-exports-ui": true, + "$feature/survey-nps-results": true, + "$feature/session-recording-allow-v1-snapshots": true, + "$feature/session-replay-cors-proxy": true, + "$feature/webhooks-denylist": true, + "$feature/surveys-site-app-deprecation": true, + "$feature/surveys-multiple-questions": true, + "$feature/surveys-results-visualizations": true, + "$feature/console-recording-search": true, + "$feature/persons-hogql-query": true, + "$feature/notebooks": true, + "$feature_flag_payloads": {}, + "realm": "hosted-clickhouse", + "email_service_available": false, + "slack_service_available": false, + "$user_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "is_demo_project": false, + "$groups": { + "project": "018a92f8-b602-0000-75de-4b9073693531", + "organization": "018a92f8-afff-0000-efec-ca77de39e384", + "customer": "cus_OdSgxxWtHOtq9g", + "instance": "http://localhost:8000" + }, + "has_billing_plan": true, + "customer_deactivated": false, + "current_total_amount_usd": "0.00", + "percentage_usage.product_analytics": 0, + "current_amount_usd.product_analytics": "0.00", + "unit_amount_usd.product_analytics": null, + "usage_limit.product_analytics": null, + "current_usage.product_analytics": 3729, + "projected_usage.product_analytics": 0, + "free_allocation.product_analytics": 0, + "percentage_usage.session_replay": 0, + "current_amount_usd.session_replay": "0.00", + "unit_amount_usd.session_replay": null, + "usage_limit.session_replay": null, + "current_usage.session_replay": 254, + "projected_usage.session_replay": 0, + "free_allocation.session_replay": 0, + "percentage_usage.feature_flags": 0, + "current_amount_usd.feature_flags": "0.00", + "unit_amount_usd.feature_flags": null, + "usage_limit.feature_flags": null, + "current_usage.feature_flags": 0, + "projected_usage.feature_flags": 0, + "free_allocation.feature_flags": 0, + "percentage_usage.integrations": 0, + "current_amount_usd.integrations": null, + "unit_amount_usd.integrations": null, + "usage_limit.integrations": 0, + "current_usage.integrations": 0, + "projected_usage.integrations": 0, + "free_allocation.integrations": 0, + "percentage_usage.platform_and_support": 0, + "current_amount_usd.platform_and_support": null, + "unit_amount_usd.platform_and_support": null, + "usage_limit.platform_and_support": 0, + "current_usage.platform_and_support": 0, + "projected_usage.platform_and_support": 0, + "free_allocation.platform_and_support": 0, + "billing_period_start": "2023-10-14T09:22:33.000Z", + "billing_period_end": "2023-11-14T09:22:33.000Z", + "$referrer": "$direct", + "$referring_domain": "$direct", + "token": "phc_OWGI2wKbfi7rWDZT9wkl8uGcfe0wOGCvflLEZSMiaT0", + "$session_id": "018b4cc2-908b-7989-a77a-ae1396eef1de", + "$window_id": "018b4cc2-908b-7989-a77a-ae1465fa2118", + "title": "Homepage \u2022 PostHog", + "$ip": "127.0.0.1", + "$set": { + "$os": "Mac OS X", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/home", + "$pathname": "/home", + "$browser_version": 117, + "$referrer": "$direct", + "$referring_domain": "$direct" + }, + "$set_once": { + "$initial_os": "Mac OS X", + "$initial_browser": "Chrome", + "$initial_device_type": "Desktop", + "$initial_current_url": "http://localhost:8000/home", + "$initial_pathname": "/home", + "$initial_browser_version": 117, + "$initial_referrer": "$direct", + "$initial_referring_domain": "$direct" + }, + "$sent_at": "2023-10-20T11:05:04.317000+00:00", + "$geoip_city_name": "Sydney", + "$geoip_country_name": "Australia", + "$geoip_country_code": "AU", + "$geoip_continent_name": "Oceania", + "$geoip_continent_code": "OC", + "$geoip_postal_code": "2000", + "$geoip_latitude": -33.8715, + "$geoip_longitude": 151.2006, + "$geoip_time_zone": "Australia/Sydney", + "$geoip_subdivision_1_code": "NSW", + "$geoip_subdivision_1_name": "New South Wales", + "$plugins_succeeded": ["GeoIP (1)"], + "$plugins_failed": [], + "$plugins_deferred": [], + "$group_3": "018a92f8-b602-0000-75de-4b9073693531", + "$group_2": "018a92f8-afff-0000-efec-ca77de39e384", + "$group_4": "cus_OdSgxxWtHOtq9g", + "$group_1": "http://localhost:8000" + }, + "timestamp": "2023-10-20T11:05:01.629000+00:00", + "uuid": null + }, + { + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "elements": [], + "elements_chain": null, + "event": "dashboard loading time", + "id": "018b4cc2-93a1-7246-a6bf-a897501c968c", + "person": null, + "properties": { + "$os": "Mac OS X", + "$os_version": "10.15.7", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/home", + "$host": "localhost:8000", + "$pathname": "/home", + "$browser_version": 117, + "$browser_language": "en-GB", + "$screen_height": 982, + "$screen_width": 1512, + "$viewport_height": 859, + "$viewport_width": 1512, + "$lib": "web", + "$lib_version": "1.84.0", + "$insert_id": "6bivi84ckma4m1y9", + "$time": 1697799902.113, + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$device_id": "018a92fd-7b25-7770-a050-577e94fd148c", + "$console_log_recording_enabled_server_side": true, + "$session_recording_recorder_version_server_side": "v2", + "$autocapture_disabled_server_side": false, + "$active_feature_flags": [ + "signup-page-4.0", + "cmd-k-search", + "posthog-3000", + "funnels-cue-opt-out-7301", + "retention-breakdown", + "smoothing-interval", + "billing-limit", + "kafka-inspector", + "historical-exports-v2", + "person-on-events-enabled", + "region-select", + "ingestion-warnings-enabled", + "session-reset-on-load", + "recordings-on-feature-flags", + "auto-rollback-feature-flags", + "onboarding-v2-demo", + "feature-flag-rollout-ux", + "role-based-access", + "query_running_time", + "query-timings", + "recording-debugging", + "enable-prompts", + "feedback-scene", + "early-access-feature", + "early-access-feature-site-button", + "hedgehog-mode-debug", + "auto-redirect", + "session-recording-blob-replay", + "surveys", + "generic-signup-benefits", + "surveys-positions", + "web-analytics", + "high-frequency-batch-exports", + "exception-autocapture", + "data-warehouse", + "data-warehouse-views", + "ff-dashboard-templates", + "show-product-intro-existing-products", + "artificial-hog", + "cs-dashboards", + "product-specific-onboarding", + "redirect-signups-to-instance", + "apps-and-exports-ui", + "survey-nps-results", + "session-recording-allow-v1-snapshots", + "session-replay-cors-proxy", + "webhooks-denylist", + "surveys-site-app-deprecation", + "surveys-multiple-questions", + "surveys-results-visualizations", + "console-recording-search", + "persons-hogql-query", + "notebooks" + ], + "$feature/file-previews": false, + "$feature/signup-page-4.0": "control", + "$feature/hogql-insights": false, + "$feature/cmd-k-search": true, + "$feature/posthog-3000": true, + "$feature/funnels-cue-opt-out-7301": true, + "$feature/retention-breakdown": true, + "$feature/smoothing-interval": true, + "$feature/billing-limit": true, + "$feature/kafka-inspector": true, + "$feature/historical-exports-v2": true, + "$feature/person-on-events-enabled": true, + "$feature/region-select": true, + "$feature/ingestion-warnings-enabled": true, + "$feature/session-reset-on-load": true, + "$feature/recordings-on-feature-flags": true, + "$feature/auto-rollback-feature-flags": true, + "$feature/onboarding-v2-demo": true, + "$feature/feature-flag-rollout-ux": true, + "$feature/role-based-access": true, + "$feature/query_running_time": true, + "$feature/query-timings": true, + "$feature/recording-debugging": true, + "$feature/enable-prompts": true, + "$feature/feedback-scene": true, + "$feature/early-access-feature": true, + "$feature/early-access-feature-site-button": true, + "$feature/hedgehog-mode-debug": true, + "$feature/auto-redirect": true, + "$feature/session-recording-blob-replay": true, + "$feature/surveys": true, + "$feature/generic-signup-benefits": true, + "$feature/surveys-positions": true, + "$feature/web-analytics": true, + "$feature/high-frequency-batch-exports": true, + "$feature/exception-autocapture": true, + "$feature/data-warehouse": true, + "$feature/data-warehouse-views": true, + "$feature/ff-dashboard-templates": true, + "$feature/show-product-intro-existing-products": true, + "$feature/artificial-hog": true, + "$feature/cs-dashboards": true, + "$feature/product-specific-onboarding": true, + "$feature/redirect-signups-to-instance": true, + "$feature/apps-and-exports-ui": true, + "$feature/survey-nps-results": true, + "$feature/session-recording-allow-v1-snapshots": true, + "$feature/session-replay-cors-proxy": true, + "$feature/webhooks-denylist": true, + "$feature/surveys-site-app-deprecation": true, + "$feature/surveys-multiple-questions": true, + "$feature/surveys-results-visualizations": true, + "$feature/console-recording-search": true, + "$feature/persons-hogql-query": true, + "$feature/notebooks": true, + "$feature_flag_payloads": {}, + "realm": "hosted-clickhouse", + "email_service_available": false, + "slack_service_available": false, + "$user_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "is_demo_project": false, + "$groups": { + "project": "018a92f8-b602-0000-75de-4b9073693531", + "organization": "018a92f8-afff-0000-efec-ca77de39e384", + "customer": "cus_OdSgxxWtHOtq9g", + "instance": "http://localhost:8000" + }, + "has_billing_plan": true, + "customer_deactivated": false, + "current_total_amount_usd": "0.00", + "percentage_usage.product_analytics": 0, + "current_amount_usd.product_analytics": "0.00", + "unit_amount_usd.product_analytics": null, + "usage_limit.product_analytics": null, + "current_usage.product_analytics": 3729, + "projected_usage.product_analytics": 0, + "free_allocation.product_analytics": 0, + "percentage_usage.session_replay": 0, + "current_amount_usd.session_replay": "0.00", + "unit_amount_usd.session_replay": null, + "usage_limit.session_replay": null, + "current_usage.session_replay": 254, + "projected_usage.session_replay": 0, + "free_allocation.session_replay": 0, + "percentage_usage.feature_flags": 0, + "current_amount_usd.feature_flags": "0.00", + "unit_amount_usd.feature_flags": null, + "usage_limit.feature_flags": null, + "current_usage.feature_flags": 0, + "projected_usage.feature_flags": 0, + "free_allocation.feature_flags": 0, + "percentage_usage.integrations": 0, + "current_amount_usd.integrations": null, + "unit_amount_usd.integrations": null, + "usage_limit.integrations": 0, + "current_usage.integrations": 0, + "projected_usage.integrations": 0, + "free_allocation.integrations": 0, + "percentage_usage.platform_and_support": 0, + "current_amount_usd.platform_and_support": null, + "unit_amount_usd.platform_and_support": null, + "usage_limit.platform_and_support": 0, + "current_usage.platform_and_support": 0, + "projected_usage.platform_and_support": 0, + "free_allocation.platform_and_support": 0, + "billing_period_start": "2023-10-14T09:22:33.000Z", + "billing_period_end": "2023-11-14T09:22:33.000Z", + "$referrer": "$direct", + "$referring_domain": "$direct", + "loadingMilliseconds": 507, + "dashboardId": 1, + "token": "phc_OWGI2wKbfi7rWDZT9wkl8uGcfe0wOGCvflLEZSMiaT0", + "$session_id": "018b4cc2-908b-7989-a77a-ae1396eef1de", + "$window_id": "018b4cc2-908b-7989-a77a-ae1465fa2118", + "$ip": "127.0.0.1", + "$set": { + "$os": "Mac OS X", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/home", + "$pathname": "/home", + "$browser_version": 117, + "$referrer": "$direct", + "$referring_domain": "$direct" + }, + "$set_once": { + "$initial_os": "Mac OS X", + "$initial_browser": "Chrome", + "$initial_device_type": "Desktop", + "$initial_current_url": "http://localhost:8000/home", + "$initial_pathname": "/home", + "$initial_browser_version": 117, + "$initial_referrer": "$direct", + "$initial_referring_domain": "$direct" + }, + "$sent_at": "2023-10-20T11:05:04.317000+00:00", + "$geoip_city_name": "Sydney", + "$geoip_country_name": "Australia", + "$geoip_country_code": "AU", + "$geoip_continent_name": "Oceania", + "$geoip_continent_code": "OC", + "$geoip_postal_code": "2000", + "$geoip_latitude": -33.8715, + "$geoip_longitude": 151.2006, + "$geoip_time_zone": "Australia/Sydney", + "$geoip_subdivision_1_code": "NSW", + "$geoip_subdivision_1_name": "New South Wales", + "$plugins_succeeded": ["GeoIP (1)"], + "$plugins_failed": [], + "$plugins_deferred": [], + "$group_3": "018a92f8-b602-0000-75de-4b9073693531", + "$group_2": "018a92f8-afff-0000-efec-ca77de39e384", + "$group_4": "cus_OdSgxxWtHOtq9g", + "$group_1": "http://localhost:8000" + }, + "timestamp": "2023-10-20T11:05:02.127000+00:00", + "uuid": null + }, + { + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "elements": [], + "elements_chain": null, + "event": "viewed dashboard", + "id": "018b4cc2-9669-7d7e-8b47-0c46f32bdc04", + "person": null, + "properties": { + "$os": "Mac OS X", + "$os_version": "10.15.7", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/home", + "$host": "localhost:8000", + "$pathname": "/home", + "$browser_version": 117, + "$browser_language": "en-GB", + "$screen_height": 982, + "$screen_width": 1512, + "$viewport_height": 859, + "$viewport_width": 1512, + "$lib": "web", + "$lib_version": "1.84.0", + "$insert_id": "m30j6hcfsn1nttq0", + "$time": 1697799902.826, + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$device_id": "018a92fd-7b25-7770-a050-577e94fd148c", + "$console_log_recording_enabled_server_side": true, + "$session_recording_recorder_version_server_side": "v2", + "$autocapture_disabled_server_side": false, + "$active_feature_flags": [ + "signup-page-4.0", + "cmd-k-search", + "posthog-3000", + "funnels-cue-opt-out-7301", + "retention-breakdown", + "smoothing-interval", + "billing-limit", + "kafka-inspector", + "historical-exports-v2", + "person-on-events-enabled", + "region-select", + "ingestion-warnings-enabled", + "session-reset-on-load", + "recordings-on-feature-flags", + "auto-rollback-feature-flags", + "onboarding-v2-demo", + "feature-flag-rollout-ux", + "role-based-access", + "query_running_time", + "query-timings", + "recording-debugging", + "enable-prompts", + "feedback-scene", + "early-access-feature", + "early-access-feature-site-button", + "hedgehog-mode-debug", + "auto-redirect", + "session-recording-blob-replay", + "surveys", + "generic-signup-benefits", + "surveys-positions", + "web-analytics", + "high-frequency-batch-exports", + "exception-autocapture", + "data-warehouse", + "data-warehouse-views", + "ff-dashboard-templates", + "show-product-intro-existing-products", + "artificial-hog", + "cs-dashboards", + "product-specific-onboarding", + "redirect-signups-to-instance", + "apps-and-exports-ui", + "survey-nps-results", + "session-recording-allow-v1-snapshots", + "session-replay-cors-proxy", + "webhooks-denylist", + "surveys-site-app-deprecation", + "surveys-multiple-questions", + "surveys-results-visualizations", + "console-recording-search", + "persons-hogql-query", + "notebooks" + ], + "$feature/file-previews": false, + "$feature/signup-page-4.0": "control", + "$feature/hogql-insights": false, + "$feature/cmd-k-search": true, + "$feature/posthog-3000": true, + "$feature/funnels-cue-opt-out-7301": true, + "$feature/retention-breakdown": true, + "$feature/smoothing-interval": true, + "$feature/billing-limit": true, + "$feature/kafka-inspector": true, + "$feature/historical-exports-v2": true, + "$feature/person-on-events-enabled": true, + "$feature/region-select": true, + "$feature/ingestion-warnings-enabled": true, + "$feature/session-reset-on-load": true, + "$feature/recordings-on-feature-flags": true, + "$feature/auto-rollback-feature-flags": true, + "$feature/onboarding-v2-demo": true, + "$feature/feature-flag-rollout-ux": true, + "$feature/role-based-access": true, + "$feature/query_running_time": true, + "$feature/query-timings": true, + "$feature/recording-debugging": true, + "$feature/enable-prompts": true, + "$feature/feedback-scene": true, + "$feature/early-access-feature": true, + "$feature/early-access-feature-site-button": true, + "$feature/hedgehog-mode-debug": true, + "$feature/auto-redirect": true, + "$feature/session-recording-blob-replay": true, + "$feature/surveys": true, + "$feature/generic-signup-benefits": true, + "$feature/surveys-positions": true, + "$feature/web-analytics": true, + "$feature/high-frequency-batch-exports": true, + "$feature/exception-autocapture": true, + "$feature/data-warehouse": true, + "$feature/data-warehouse-views": true, + "$feature/ff-dashboard-templates": true, + "$feature/show-product-intro-existing-products": true, + "$feature/artificial-hog": true, + "$feature/cs-dashboards": true, + "$feature/product-specific-onboarding": true, + "$feature/redirect-signups-to-instance": true, + "$feature/apps-and-exports-ui": true, + "$feature/survey-nps-results": true, + "$feature/session-recording-allow-v1-snapshots": true, + "$feature/session-replay-cors-proxy": true, + "$feature/webhooks-denylist": true, + "$feature/surveys-site-app-deprecation": true, + "$feature/surveys-multiple-questions": true, + "$feature/surveys-results-visualizations": true, + "$feature/console-recording-search": true, + "$feature/persons-hogql-query": true, + "$feature/notebooks": true, + "$feature_flag_payloads": {}, + "realm": "hosted-clickhouse", + "email_service_available": false, + "slack_service_available": false, + "$user_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "is_demo_project": false, + "$groups": { + "project": "018a92f8-b602-0000-75de-4b9073693531", + "organization": "018a92f8-afff-0000-efec-ca77de39e384", + "customer": "cus_OdSgxxWtHOtq9g", + "instance": "http://localhost:8000" + }, + "has_billing_plan": true, + "customer_deactivated": false, + "current_total_amount_usd": "0.00", + "percentage_usage.product_analytics": 0, + "current_amount_usd.product_analytics": "0.00", + "unit_amount_usd.product_analytics": null, + "usage_limit.product_analytics": null, + "current_usage.product_analytics": 3729, + "projected_usage.product_analytics": 0, + "free_allocation.product_analytics": 0, + "percentage_usage.session_replay": 0, + "current_amount_usd.session_replay": "0.00", + "unit_amount_usd.session_replay": null, + "usage_limit.session_replay": null, + "current_usage.session_replay": 254, + "projected_usage.session_replay": 0, + "free_allocation.session_replay": 0, + "percentage_usage.feature_flags": 0, + "current_amount_usd.feature_flags": "0.00", + "unit_amount_usd.feature_flags": null, + "usage_limit.feature_flags": null, + "current_usage.feature_flags": 0, + "projected_usage.feature_flags": 0, + "free_allocation.feature_flags": 0, + "percentage_usage.integrations": 0, + "current_amount_usd.integrations": null, + "unit_amount_usd.integrations": null, + "usage_limit.integrations": 0, + "current_usage.integrations": 0, + "projected_usage.integrations": 0, + "free_allocation.integrations": 0, + "percentage_usage.platform_and_support": 0, + "current_amount_usd.platform_and_support": null, + "unit_amount_usd.platform_and_support": null, + "usage_limit.platform_and_support": 0, + "current_usage.platform_and_support": 0, + "projected_usage.platform_and_support": 0, + "free_allocation.platform_and_support": 0, + "billing_period_start": "2023-10-14T09:22:33.000Z", + "billing_period_end": "2023-11-14T09:22:33.000Z", + "$referrer": "$direct", + "$referring_domain": "$direct", + "created_at": "2023-09-14T09:15:00.211731Z", + "is_shared": false, + "pinned": true, + "creation_mode": "default", + "sample_items_count": 0, + "item_count": 7, + "created_by_system": true, + "dashboard_id": 1, + "lastRefreshed": "2023-10-20T10:20:11.963Z", + "refreshAge": 2690, + "lifecycle_count": 2, + "trends_count": 3, + "funnels_count": 1, + "retention_count": 1, + "token": "phc_OWGI2wKbfi7rWDZT9wkl8uGcfe0wOGCvflLEZSMiaT0", + "$session_id": "018b4cc2-908b-7989-a77a-ae1396eef1de", + "$window_id": "018b4cc2-908b-7989-a77a-ae1465fa2118", + "$ip": "127.0.0.1", + "$set": { + "$os": "Mac OS X", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/home", + "$pathname": "/home", + "$browser_version": 117, + "$referrer": "$direct", + "$referring_domain": "$direct" + }, + "$set_once": { + "$initial_os": "Mac OS X", + "$initial_browser": "Chrome", + "$initial_device_type": "Desktop", + "$initial_current_url": "http://localhost:8000/home", + "$initial_pathname": "/home", + "$initial_browser_version": 117, + "$initial_referrer": "$direct", + "$initial_referring_domain": "$direct" + }, + "$sent_at": "2023-10-20T11:05:04.317000+00:00", + "$geoip_city_name": "Sydney", + "$geoip_country_name": "Australia", + "$geoip_country_code": "AU", + "$geoip_continent_name": "Oceania", + "$geoip_continent_code": "OC", + "$geoip_postal_code": "2000", + "$geoip_latitude": -33.8715, + "$geoip_longitude": 151.2006, + "$geoip_time_zone": "Australia/Sydney", + "$geoip_subdivision_1_code": "NSW", + "$geoip_subdivision_1_name": "New South Wales", + "$plugins_succeeded": ["GeoIP (1)"], + "$plugins_failed": [], + "$plugins_deferred": [], + "$group_3": "018a92f8-b602-0000-75de-4b9073693531", + "$group_2": "018a92f8-afff-0000-efec-ca77de39e384", + "$group_4": "cus_OdSgxxWtHOtq9g", + "$group_1": "http://localhost:8000" + }, + "timestamp": "2023-10-20T11:05:02.840000+00:00", + "uuid": null + }, + { + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "elements": [ + { + "attr_class": ["LemonButton__content"], + "attr_id": null, + "attributes": { + "attr__class": "LemonButton__content" + }, + "href": null, + "nth_child": 2.0, + "nth_of_type": 2.0, + "order": 0.0, + "tag_name": "span", + "text": "No date range override" + }, + { + "attr_class": [ + "LemonButton", + "LemonButton--has-icon", + "LemonButton--has-side-icon", + "LemonButton--secondary", + "LemonButton--small", + "LemonButton--status-stealth" + ], + "attr_id": "daterange_selector", + "attributes": { + "attr__aria-disabled": "false", + "attr__aria-haspopup": "true", + "attr__class": "LemonButton LemonButton--secondary LemonButton--status-stealth LemonButton--small LemonButton--has-icon LemonButton--has-side-icon", + "attr__data-attr": "date-filter", + "attr__id": "daterange_selector", + "attr__type": "button" + }, + "href": null, + "nth_child": 1.0, + "nth_of_type": 1.0, + "order": 1.0, + "tag_name": "button", + "text": "No date range override" + }, + { + "attr_class": ["flex", "h-8", "items-center", "shrink-0"], + "attr_id": null, + "attributes": { + "attr__class": "flex shrink-0 items-center h-8" + }, + "href": null, + "nth_child": 1.0, + "nth_of_type": 1.0, + "order": 2.0, + "tag_name": "div", + "text": null + }, + { + "attr_class": ["flex", "space-x-4"], + "attr_id": null, + "attributes": { + "attr__class": "flex space-x-4" + }, + "href": null, + "nth_child": 1.0, + "nth_of_type": 1.0, + "order": 3.0, + "tag_name": "div", + "text": null + }, + { + "attr_class": ["flex", "justify-between", "space-x-4"], + "attr_id": null, + "attributes": { + "attr__class": "flex space-x-4 justify-between" + }, + "href": null, + "nth_child": 1.0, + "nth_of_type": 1.0, + "order": 4.0, + "tag_name": "div", + "text": null + }, + { + "attr_class": null, + "attr_id": null, + "attributes": {}, + "href": null, + "nth_child": 1.0, + "nth_of_type": 1.0, + "order": 5.0, + "tag_name": "div", + "text": null + }, + { + "attr_class": ["dashboard"], + "attr_id": null, + "attributes": { + "attr__class": "dashboard" + }, + "href": null, + "nth_child": 1.0, + "nth_of_type": 1.0, + "order": 6.0, + "tag_name": "div", + "text": null + }, + { + "attr_class": ["project-homepage"], + "attr_id": null, + "attributes": { + "attr__class": "project-homepage" + }, + "href": null, + "nth_child": 1.0, + "nth_of_type": 1.0, + "order": 7.0, + "tag_name": "div", + "text": null + }, + { + "attr_class": ["Navigation3000__scene"], + "attr_id": null, + "attributes": { + "attr__class": "Navigation3000__scene" + }, + "href": null, + "nth_child": 2.0, + "nth_of_type": 2.0, + "order": 8.0, + "tag_name": "div", + "text": null + }, + { + "attr_class": null, + "attr_id": null, + "attributes": {}, + "href": null, + "nth_child": 4.0, + "nth_of_type": 1.0, + "order": 9.0, + "tag_name": "main", + "text": null + }, + { + "attr_class": ["Navigation3000"], + "attr_id": null, + "attributes": { + "attr__class": "Navigation3000" + }, + "href": null, + "nth_child": 1.0, + "nth_of_type": 1.0, + "order": 10.0, + "tag_name": "div", + "text": null + }, + { + "attr_class": null, + "attr_id": "root", + "attributes": { + "attr__id": "root" + }, + "href": null, + "nth_child": 4.0, + "nth_of_type": 1.0, + "order": 11.0, + "tag_name": "div", + "text": null + }, + { + "attr_class": ["posthog-3000"], + "attr_id": null, + "attributes": { + "attr__class": "posthog-3000", + "attr__theme": "light" + }, + "href": null, + "nth_child": 2.0, + "nth_of_type": 1.0, + "order": 12.0, + "tag_name": "body", + "text": null + } + ], + "elements_chain": "span.LemonButton__content:attr__class=\"LemonButton__content\"nth-child=\"2\"nth-of-type=\"2\"text=\"No date range override\";button.LemonButton.LemonButton--has-icon.LemonButton--has-side-icon.LemonButton--secondary.LemonButton--small.LemonButton--status-stealth:attr__aria-disabled=\"false\"attr__aria-haspopup=\"true\"attr__class=\"LemonButton LemonButton--secondary LemonButton--status-stealth LemonButton--small LemonButton--has-icon LemonButton--has-side-icon\"attr__data-attr=\"date-filter\"attr__id=\"daterange_selector\"attr__type=\"button\"attr_id=\"daterange_selector\"nth-child=\"1\"nth-of-type=\"1\"text=\"No date range override\";div.flex.h-8.items-center.shrink-0:attr__class=\"flex shrink-0 items-center h-8\"nth-child=\"1\"nth-of-type=\"1\";div.flex.space-x-4:attr__class=\"flex space-x-4\"nth-child=\"1\"nth-of-type=\"1\";div.flex.justify-between.space-x-4:attr__class=\"flex space-x-4 justify-between\"nth-child=\"1\"nth-of-type=\"1\";div:nth-child=\"1\"nth-of-type=\"1\";div.dashboard:attr__class=\"dashboard\"nth-child=\"1\"nth-of-type=\"1\";div.project-homepage:attr__class=\"project-homepage\"nth-child=\"1\"nth-of-type=\"1\";div.Navigation3000__scene:attr__class=\"Navigation3000__scene\"nth-child=\"2\"nth-of-type=\"2\";main:nth-child=\"4\"nth-of-type=\"1\";div.Navigation3000:attr__class=\"Navigation3000\"nth-child=\"1\"nth-of-type=\"1\";div:attr__id=\"root\"attr_id=\"root\"nth-child=\"4\"nth-of-type=\"1\";body.posthog-3000:attr__class=\"posthog-3000\"attr__theme=\"light\"nth-child=\"2\"nth-of-type=\"1\"", + "event": "$autocapture", + "id": "018b4cc2-9bd1-7a01-9caf-50416be478be", + "person": null, + "properties": { + "$os": "Mac OS X", + "$os_version": "10.15.7", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/home", + "$host": "localhost:8000", + "$pathname": "/home", + "$browser_version": 117, + "$browser_language": "en-GB", + "$screen_height": 982, + "$screen_width": 1512, + "$viewport_height": 859, + "$viewport_width": 1512, + "$lib": "web", + "$lib_version": "1.84.0", + "$insert_id": "t8lxw271peuuit3u", + "$time": 1697799904.209, + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$device_id": "018a92fd-7b25-7770-a050-577e94fd148c", + "$console_log_recording_enabled_server_side": true, + "$session_recording_recorder_version_server_side": "v2", + "$autocapture_disabled_server_side": false, + "$active_feature_flags": [ + "signup-page-4.0", + "cmd-k-search", + "posthog-3000", + "funnels-cue-opt-out-7301", + "retention-breakdown", + "smoothing-interval", + "billing-limit", + "kafka-inspector", + "historical-exports-v2", + "person-on-events-enabled", + "region-select", + "ingestion-warnings-enabled", + "session-reset-on-load", + "recordings-on-feature-flags", + "auto-rollback-feature-flags", + "onboarding-v2-demo", + "feature-flag-rollout-ux", + "role-based-access", + "query_running_time", + "query-timings", + "recording-debugging", + "enable-prompts", + "feedback-scene", + "early-access-feature", + "early-access-feature-site-button", + "hedgehog-mode-debug", + "auto-redirect", + "session-recording-blob-replay", + "surveys", + "generic-signup-benefits", + "surveys-positions", + "web-analytics", + "high-frequency-batch-exports", + "exception-autocapture", + "data-warehouse", + "data-warehouse-views", + "ff-dashboard-templates", + "show-product-intro-existing-products", + "artificial-hog", + "cs-dashboards", + "product-specific-onboarding", + "redirect-signups-to-instance", + "apps-and-exports-ui", + "survey-nps-results", + "session-recording-allow-v1-snapshots", + "session-replay-cors-proxy", + "webhooks-denylist", + "surveys-site-app-deprecation", + "surveys-multiple-questions", + "surveys-results-visualizations", + "console-recording-search", + "persons-hogql-query", + "notebooks" + ], + "$feature/file-previews": false, + "$feature/signup-page-4.0": "control", + "$feature/hogql-insights": false, + "$feature/cmd-k-search": true, + "$feature/posthog-3000": true, + "$feature/funnels-cue-opt-out-7301": true, + "$feature/retention-breakdown": true, + "$feature/smoothing-interval": true, + "$feature/billing-limit": true, + "$feature/kafka-inspector": true, + "$feature/historical-exports-v2": true, + "$feature/person-on-events-enabled": true, + "$feature/region-select": true, + "$feature/ingestion-warnings-enabled": true, + "$feature/session-reset-on-load": true, + "$feature/recordings-on-feature-flags": true, + "$feature/auto-rollback-feature-flags": true, + "$feature/onboarding-v2-demo": true, + "$feature/feature-flag-rollout-ux": true, + "$feature/role-based-access": true, + "$feature/query_running_time": true, + "$feature/query-timings": true, + "$feature/recording-debugging": true, + "$feature/enable-prompts": true, + "$feature/feedback-scene": true, + "$feature/early-access-feature": true, + "$feature/early-access-feature-site-button": true, + "$feature/hedgehog-mode-debug": true, + "$feature/auto-redirect": true, + "$feature/session-recording-blob-replay": true, + "$feature/surveys": true, + "$feature/generic-signup-benefits": true, + "$feature/surveys-positions": true, + "$feature/web-analytics": true, + "$feature/high-frequency-batch-exports": true, + "$feature/exception-autocapture": true, + "$feature/data-warehouse": true, + "$feature/data-warehouse-views": true, + "$feature/ff-dashboard-templates": true, + "$feature/show-product-intro-existing-products": true, + "$feature/artificial-hog": true, + "$feature/cs-dashboards": true, + "$feature/product-specific-onboarding": true, + "$feature/redirect-signups-to-instance": true, + "$feature/apps-and-exports-ui": true, + "$feature/survey-nps-results": true, + "$feature/session-recording-allow-v1-snapshots": true, + "$feature/session-replay-cors-proxy": true, + "$feature/webhooks-denylist": true, + "$feature/surveys-site-app-deprecation": true, + "$feature/surveys-multiple-questions": true, + "$feature/surveys-results-visualizations": true, + "$feature/console-recording-search": true, + "$feature/persons-hogql-query": true, + "$feature/notebooks": true, + "$feature_flag_payloads": {}, + "realm": "hosted-clickhouse", + "email_service_available": false, + "slack_service_available": false, + "$user_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "is_demo_project": false, + "$groups": { + "project": "018a92f8-b602-0000-75de-4b9073693531", + "organization": "018a92f8-afff-0000-efec-ca77de39e384", + "customer": "cus_OdSgxxWtHOtq9g", + "instance": "http://localhost:8000" + }, + "has_billing_plan": true, + "customer_deactivated": false, + "current_total_amount_usd": "0.00", + "percentage_usage.product_analytics": 0, + "current_amount_usd.product_analytics": "0.00", + "unit_amount_usd.product_analytics": null, + "usage_limit.product_analytics": null, + "current_usage.product_analytics": 3729, + "projected_usage.product_analytics": 0, + "free_allocation.product_analytics": 0, + "percentage_usage.session_replay": 0, + "current_amount_usd.session_replay": "0.00", + "unit_amount_usd.session_replay": null, + "usage_limit.session_replay": null, + "current_usage.session_replay": 254, + "projected_usage.session_replay": 0, + "free_allocation.session_replay": 0, + "percentage_usage.feature_flags": 0, + "current_amount_usd.feature_flags": "0.00", + "unit_amount_usd.feature_flags": null, + "usage_limit.feature_flags": null, + "current_usage.feature_flags": 0, + "projected_usage.feature_flags": 0, + "free_allocation.feature_flags": 0, + "percentage_usage.integrations": 0, + "current_amount_usd.integrations": null, + "unit_amount_usd.integrations": null, + "usage_limit.integrations": 0, + "current_usage.integrations": 0, + "projected_usage.integrations": 0, + "free_allocation.integrations": 0, + "percentage_usage.platform_and_support": 0, + "current_amount_usd.platform_and_support": null, + "unit_amount_usd.platform_and_support": null, + "usage_limit.platform_and_support": 0, + "current_usage.platform_and_support": 0, + "projected_usage.platform_and_support": 0, + "free_allocation.platform_and_support": 0, + "billing_period_start": "2023-10-14T09:22:33.000Z", + "billing_period_end": "2023-11-14T09:22:33.000Z", + "$referrer": "$direct", + "$referring_domain": "$direct", + "$event_type": "click", + "$ce_version": 1, + "$el_text": "No date range override", + "token": "phc_OWGI2wKbfi7rWDZT9wkl8uGcfe0wOGCvflLEZSMiaT0", + "$session_id": "018b4cc2-908b-7989-a77a-ae1396eef1de", + "$window_id": "018b4cc2-908b-7989-a77a-ae1465fa2118", + "$ip": "127.0.0.1", + "$set": { + "$os": "Mac OS X", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/home", + "$pathname": "/home", + "$browser_version": 117, + "$referrer": "$direct", + "$referring_domain": "$direct" + }, + "$set_once": { + "$initial_os": "Mac OS X", + "$initial_browser": "Chrome", + "$initial_device_type": "Desktop", + "$initial_current_url": "http://localhost:8000/home", + "$initial_pathname": "/home", + "$initial_browser_version": 117, + "$initial_referrer": "$direct", + "$initial_referring_domain": "$direct" + }, + "$sent_at": "2023-10-20T11:05:04.317000+00:00", + "$geoip_city_name": "Sydney", + "$geoip_country_name": "Australia", + "$geoip_country_code": "AU", + "$geoip_continent_name": "Oceania", + "$geoip_continent_code": "OC", + "$geoip_postal_code": "2000", + "$geoip_latitude": -33.8715, + "$geoip_longitude": 151.2006, + "$geoip_time_zone": "Australia/Sydney", + "$geoip_subdivision_1_code": "NSW", + "$geoip_subdivision_1_name": "New South Wales", + "$plugins_succeeded": ["GeoIP (1)"], + "$plugins_failed": [], + "$plugins_deferred": [], + "$group_3": "018a92f8-b602-0000-75de-4b9073693531", + "$group_2": "018a92f8-afff-0000-efec-ca77de39e384", + "$group_4": "cus_OdSgxxWtHOtq9g", + "$group_1": "http://localhost:8000" + }, + "timestamp": "2023-10-20T11:05:04.223000+00:00", + "uuid": null + }, + { + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "elements": [ + { + "attr_class": [ + "LemonButton", + "LemonButton--full-width", + "LemonButton--status-stealth", + "LemonButton--tertiary" + ], + "attr_id": null, + "attributes": { + "attr__class": "LemonButton LemonButton--tertiary LemonButton--status-stealth LemonButton--full-width", + "attr__type": "button" + }, + "href": null, + "nth_child": 15.0, + "nth_of_type": 14.0, + "order": 0.0, + "tag_name": "button", + "text": "From custom date until now\u2026" + }, + { + "attr_class": ["space-y-px"], + "attr_id": null, + "attributes": { + "attr__class": "space-y-px" + }, + "href": null, + "nth_child": 1.0, + "nth_of_type": 1.0, + "order": 1.0, + "tag_name": "div", + "text": null + }, + { + "attr_class": ["Popover__content"], + "attr_id": null, + "attributes": { + "attr__class": "Popover__content" + }, + "href": null, + "nth_child": 1.0, + "nth_of_type": 1.0, + "order": 2.0, + "tag_name": "div", + "text": null + }, + { + "attr_class": ["Popover__box"], + "attr_id": null, + "attributes": { + "attr__class": "Popover__box" + }, + "href": null, + "nth_child": 1.0, + "nth_of_type": 1.0, + "order": 3.0, + "tag_name": "div", + "text": null + }, + { + "attr_class": ["Popover", "Popover--actionable", "Popover--enter-done"], + "attr_id": null, + "attributes": { + "attr__aria-level": "0", + "attr__class": "Popover Popover--actionable Popover--enter-done", + "attr__data-placement": "bottom-start", + "attr__style": "position: fixed; top: 95.544px; left: 318.838px; max-height: 759.456px; max-width: 1189.16px; width: initial;" + }, + "href": null, + "nth_child": 1.0, + "nth_of_type": 1.0, + "order": 4.0, + "tag_name": "div", + "text": null + }, + { + "attr_class": null, + "attr_id": null, + "attributes": { + "attr__data-floating-ui-portal": "\"attr__id=", + "floating-ui-6\"attr_id": "floating-ui-6" + }, + "href": null, + "nth_child": 16.0, + "nth_of_type": 12.0, + "order": 5.0, + "tag_name": "div", + "text": null + }, + { + "attr_class": ["posthog-3000"], + "attr_id": null, + "attributes": { + "attr__class": "posthog-3000", + "attr__theme": "light" + }, + "href": null, + "nth_child": 2.0, + "nth_of_type": 1.0, + "order": 6.0, + "tag_name": "body", + "text": null + } + ], + "elements_chain": "button.LemonButton.LemonButton--full-width.LemonButton--status-stealth.LemonButton--tertiary:attr__class=\"LemonButton LemonButton--tertiary LemonButton--status-stealth LemonButton--full-width\"attr__type=\"button\"nth-child=\"15\"nth-of-type=\"14\"text=\"From custom date until now\u2026\";div.space-y-px:attr__class=\"space-y-px\"nth-child=\"1\"nth-of-type=\"1\";div.Popover__content:attr__class=\"Popover__content\"nth-child=\"1\"nth-of-type=\"1\";div.Popover__box:attr__class=\"Popover__box\"nth-child=\"1\"nth-of-type=\"1\";div.Popover.Popover--actionable.Popover--enter-done:attr__aria-level=\"0\"attr__class=\"Popover Popover--actionable Popover--enter-done\"attr__data-placement=\"bottom-start\"attr__style=\"position: fixed; top: 95.544px; left: 318.838px; max-height: 759.456px; max-width: 1189.16px; width: initial;\"nth-child=\"1\"nth-of-type=\"1\";div:attr__data-floating-ui-portal=\"\"attr__id=\"floating-ui-6\"attr_id=\"floating-ui-6\"nth-child=\"16\"nth-of-type=\"12\";body.posthog-3000:attr__class=\"posthog-3000\"attr__theme=\"light\"nth-child=\"2\"nth-of-type=\"1\"", + "event": "$autocapture", + "id": "018b4cc2-a773-7fd0-a00b-6d36dbcef384", + "person": null, + "properties": { + "$os": "Mac OS X", + "$os_version": "10.15.7", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/home", + "$host": "localhost:8000", + "$pathname": "/home", + "$browser_version": 117, + "$browser_language": "en-GB", + "$screen_height": 982, + "$screen_width": 1512, + "$viewport_height": 859, + "$viewport_width": 1512, + "$lib": "web", + "$lib_version": "1.84.0", + "$insert_id": "aeet4il6oqfjrsgl", + "$time": 1697799907.188, + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$device_id": "018a92fd-7b25-7770-a050-577e94fd148c", + "$console_log_recording_enabled_server_side": true, + "$session_recording_recorder_version_server_side": "v2", + "$autocapture_disabled_server_side": false, + "$active_feature_flags": [ + "signup-page-4.0", + "cmd-k-search", + "posthog-3000", + "funnels-cue-opt-out-7301", + "retention-breakdown", + "smoothing-interval", + "billing-limit", + "kafka-inspector", + "historical-exports-v2", + "person-on-events-enabled", + "region-select", + "ingestion-warnings-enabled", + "session-reset-on-load", + "recordings-on-feature-flags", + "auto-rollback-feature-flags", + "onboarding-v2-demo", + "feature-flag-rollout-ux", + "role-based-access", + "query_running_time", + "query-timings", + "recording-debugging", + "enable-prompts", + "feedback-scene", + "early-access-feature", + "early-access-feature-site-button", + "hedgehog-mode-debug", + "auto-redirect", + "session-recording-blob-replay", + "surveys", + "generic-signup-benefits", + "surveys-positions", + "web-analytics", + "high-frequency-batch-exports", + "exception-autocapture", + "data-warehouse", + "data-warehouse-views", + "ff-dashboard-templates", + "show-product-intro-existing-products", + "artificial-hog", + "cs-dashboards", + "product-specific-onboarding", + "redirect-signups-to-instance", + "apps-and-exports-ui", + "survey-nps-results", + "session-recording-allow-v1-snapshots", + "session-replay-cors-proxy", + "webhooks-denylist", + "surveys-site-app-deprecation", + "surveys-multiple-questions", + "surveys-results-visualizations", + "console-recording-search", + "persons-hogql-query", + "notebooks" + ], + "$feature/file-previews": false, + "$feature/signup-page-4.0": "control", + "$feature/hogql-insights": false, + "$feature/cmd-k-search": true, + "$feature/posthog-3000": true, + "$feature/funnels-cue-opt-out-7301": true, + "$feature/retention-breakdown": true, + "$feature/smoothing-interval": true, + "$feature/billing-limit": true, + "$feature/kafka-inspector": true, + "$feature/historical-exports-v2": true, + "$feature/person-on-events-enabled": true, + "$feature/region-select": true, + "$feature/ingestion-warnings-enabled": true, + "$feature/session-reset-on-load": true, + "$feature/recordings-on-feature-flags": true, + "$feature/auto-rollback-feature-flags": true, + "$feature/onboarding-v2-demo": true, + "$feature/feature-flag-rollout-ux": true, + "$feature/role-based-access": true, + "$feature/query_running_time": true, + "$feature/query-timings": true, + "$feature/recording-debugging": true, + "$feature/enable-prompts": true, + "$feature/feedback-scene": true, + "$feature/early-access-feature": true, + "$feature/early-access-feature-site-button": true, + "$feature/hedgehog-mode-debug": true, + "$feature/auto-redirect": true, + "$feature/session-recording-blob-replay": true, + "$feature/surveys": true, + "$feature/generic-signup-benefits": true, + "$feature/surveys-positions": true, + "$feature/web-analytics": true, + "$feature/high-frequency-batch-exports": true, + "$feature/exception-autocapture": true, + "$feature/data-warehouse": true, + "$feature/data-warehouse-views": true, + "$feature/ff-dashboard-templates": true, + "$feature/show-product-intro-existing-products": true, + "$feature/artificial-hog": true, + "$feature/cs-dashboards": true, + "$feature/product-specific-onboarding": true, + "$feature/redirect-signups-to-instance": true, + "$feature/apps-and-exports-ui": true, + "$feature/survey-nps-results": true, + "$feature/session-recording-allow-v1-snapshots": true, + "$feature/session-replay-cors-proxy": true, + "$feature/webhooks-denylist": true, + "$feature/surveys-site-app-deprecation": true, + "$feature/surveys-multiple-questions": true, + "$feature/surveys-results-visualizations": true, + "$feature/console-recording-search": true, + "$feature/persons-hogql-query": true, + "$feature/notebooks": true, + "$feature_flag_payloads": {}, + "realm": "hosted-clickhouse", + "email_service_available": false, + "slack_service_available": false, + "$user_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "is_demo_project": false, + "$groups": { + "project": "018a92f8-b602-0000-75de-4b9073693531", + "organization": "018a92f8-afff-0000-efec-ca77de39e384", + "customer": "cus_OdSgxxWtHOtq9g", + "instance": "http://localhost:8000" + }, + "has_billing_plan": true, + "customer_deactivated": false, + "current_total_amount_usd": "0.00", + "percentage_usage.product_analytics": 0, + "current_amount_usd.product_analytics": "0.00", + "unit_amount_usd.product_analytics": null, + "usage_limit.product_analytics": null, + "current_usage.product_analytics": 3729, + "projected_usage.product_analytics": 0, + "free_allocation.product_analytics": 0, + "percentage_usage.session_replay": 0, + "current_amount_usd.session_replay": "0.00", + "unit_amount_usd.session_replay": null, + "usage_limit.session_replay": null, + "current_usage.session_replay": 254, + "projected_usage.session_replay": 0, + "free_allocation.session_replay": 0, + "percentage_usage.feature_flags": 0, + "current_amount_usd.feature_flags": "0.00", + "unit_amount_usd.feature_flags": null, + "usage_limit.feature_flags": null, + "current_usage.feature_flags": 0, + "projected_usage.feature_flags": 0, + "free_allocation.feature_flags": 0, + "percentage_usage.integrations": 0, + "current_amount_usd.integrations": null, + "unit_amount_usd.integrations": null, + "usage_limit.integrations": 0, + "current_usage.integrations": 0, + "projected_usage.integrations": 0, + "free_allocation.integrations": 0, + "percentage_usage.platform_and_support": 0, + "current_amount_usd.platform_and_support": null, + "unit_amount_usd.platform_and_support": null, + "usage_limit.platform_and_support": 0, + "current_usage.platform_and_support": 0, + "projected_usage.platform_and_support": 0, + "free_allocation.platform_and_support": 0, + "billing_period_start": "2023-10-14T09:22:33.000Z", + "billing_period_end": "2023-11-14T09:22:33.000Z", + "$referrer": "$direct", + "$referring_domain": "$direct", + "$event_type": "click", + "$ce_version": 1, + "$el_text": "From custom date until now\u2026", + "token": "phc_OWGI2wKbfi7rWDZT9wkl8uGcfe0wOGCvflLEZSMiaT0", + "$session_id": "018b4cc2-908b-7989-a77a-ae1396eef1de", + "$window_id": "018b4cc2-908b-7989-a77a-ae1465fa2118", + "$ip": "127.0.0.1", + "$set": { + "$os": "Mac OS X", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/home", + "$pathname": "/home", + "$browser_version": 117, + "$referrer": "$direct", + "$referring_domain": "$direct" + }, + "$set_once": { + "$initial_os": "Mac OS X", + "$initial_browser": "Chrome", + "$initial_device_type": "Desktop", + "$initial_current_url": "http://localhost:8000/home", + "$initial_pathname": "/home", + "$initial_browser_version": 117, + "$initial_referrer": "$direct", + "$initial_referring_domain": "$direct" + }, + "$sent_at": "2023-10-20T11:05:07.436000+00:00", + "$geoip_city_name": "Sydney", + "$geoip_country_name": "Australia", + "$geoip_country_code": "AU", + "$geoip_continent_name": "Oceania", + "$geoip_continent_code": "OC", + "$geoip_postal_code": "2000", + "$geoip_latitude": -33.8715, + "$geoip_longitude": 151.2006, + "$geoip_time_zone": "Australia/Sydney", + "$geoip_subdivision_1_code": "NSW", + "$geoip_subdivision_1_name": "New South Wales", + "$plugins_succeeded": ["GeoIP (1)"], + "$plugins_failed": [], + "$plugins_deferred": [], + "$group_3": "018a92f8-b602-0000-75de-4b9073693531", + "$group_2": "018a92f8-afff-0000-efec-ca77de39e384", + "$group_4": "cus_OdSgxxWtHOtq9g", + "$group_1": "http://localhost:8000" + }, + "timestamp": "2023-10-20T11:05:07.200000+00:00", + "uuid": null + }, + { + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "elements": [ + { + "attr_class": ["LemonIcon"], + "attr_id": null, + "attributes": { + "attr__aria-hidden": "true", + "attr__class": "LemonIcon", + "attr__fill": "none", + "attr__focusable": "false", + "attr__height": "1em", + "attr__viewBox": "0 0 24 24", + "attr__width": "1em", + "attr__xmlns": "http://www.w3.org/2000/svg" + }, + "href": null, + "nth_child": 1.0, + "nth_of_type": 1.0, + "order": 0.0, + "tag_name": "svg", + "text": null + }, + { + "attr_class": ["LemonButton__icon"], + "attr_id": null, + "attributes": { + "attr__class": "LemonButton__icon" + }, + "href": null, + "nth_child": 1.0, + "nth_of_type": 1.0, + "order": 1.0, + "tag_name": "span", + "text": null + }, + { + "attr_class": [ + "LemonButton", + "LemonButton--full-width", + "LemonButton--has-icon", + "LemonButton--no-content", + "LemonButton--status-stealth", + "LemonButton--tertiary", + "absolute-left" + ], + "attr_id": null, + "attributes": { + "attr__class": "LemonButton LemonButton--tertiary LemonButton--status-stealth LemonButton--full-width LemonButton--no-content LemonButton--has-icon absolute-left", + "attr__data-attr": "lemon-calendar-month-previous", + "attr__type": "button" + }, + "href": null, + "nth_child": 1.0, + "nth_of_type": 1.0, + "order": 2.0, + "tag_name": "button", + "text": null + }, + { + "attr_class": ["relative"], + "attr_id": null, + "attributes": { + "attr__class": "relative" + }, + "href": null, + "nth_child": 1.0, + "nth_of_type": 1.0, + "order": 3.0, + "tag_name": "th", + "text": null + }, + { + "attr_class": null, + "attr_id": null, + "attributes": {}, + "href": null, + "nth_child": 1.0, + "nth_of_type": 1.0, + "order": 4.0, + "tag_name": "tr", + "text": null + }, + { + "attr_class": null, + "attr_id": null, + "attributes": {}, + "href": null, + "nth_child": 1.0, + "nth_of_type": 1.0, + "order": 5.0, + "tag_name": "thead", + "text": null + }, + { + "attr_class": ["LemonCalendar__month"], + "attr_id": null, + "attributes": { + "attr__class": "LemonCalendar__month", + "attr__data-attr": "lemon-calendar-month" + }, + "href": null, + "nth_child": 1.0, + "nth_of_type": 1.0, + "order": 6.0, + "tag_name": "table", + "text": null + }, + { + "attr_class": ["LemonCalendar", "flex", "gap-4", "items-start"], + "attr_id": null, + "attributes": { + "attr__class": "LemonCalendar flex items-start gap-4", + "attr__data-attr": "lemon-calendar" + }, + "href": null, + "nth_child": 1.0, + "nth_of_type": 1.0, + "order": 7.0, + "tag_name": "div", + "text": null + }, + { + "attr_class": ["p-2"], + "attr_id": null, + "attributes": { + "attr__class": "p-2" + }, + "href": null, + "nth_child": 2.0, + "nth_of_type": 2.0, + "order": 8.0, + "tag_name": "div", + "text": null + }, + { + "attr_class": ["LemonCalendarSelect"], + "attr_id": null, + "attributes": { + "attr__class": "LemonCalendarSelect", + "attr__data-attr": "lemon-calendar-select" + }, + "href": null, + "nth_child": 1.0, + "nth_of_type": 1.0, + "order": 9.0, + "tag_name": "div", + "text": null + }, + { + "attr_class": ["Popover__content"], + "attr_id": null, + "attributes": { + "attr__class": "Popover__content" + }, + "href": null, + "nth_child": 1.0, + "nth_of_type": 1.0, + "order": 10.0, + "tag_name": "div", + "text": null + }, + { + "attr_class": ["Popover__box"], + "attr_id": null, + "attributes": { + "attr__class": "Popover__box" + }, + "href": null, + "nth_child": 1.0, + "nth_of_type": 1.0, + "order": 11.0, + "tag_name": "div", + "text": null + }, + { + "attr_class": ["Popover", "Popover--actionable", "Popover--enter-done"], + "attr_id": null, + "attributes": { + "attr__aria-level": "0", + "attr__class": "Popover Popover--actionable Popover--enter-done", + "attr__data-placement": "bottom-start", + "attr__style": "position: fixed; top: 96px; left: 316px; max-height: 759px; max-width: 1192px; width: initial;" + }, + "href": null, + "nth_child": 1.0, + "nth_of_type": 1.0, + "order": 12.0, + "tag_name": "div", + "text": null + }, + { + "attr_class": null, + "attr_id": null, + "attributes": { + "attr__data-floating-ui-portal": "\"attr__id=", + "floating-ui-6\"attr_id": "floating-ui-6" + }, + "href": null, + "nth_child": 16.0, + "nth_of_type": 12.0, + "order": 13.0, + "tag_name": "div", + "text": null + }, + { + "attr_class": ["posthog-3000"], + "attr_id": null, + "attributes": { + "attr__class": "posthog-3000", + "attr__theme": "light" + }, + "href": null, + "nth_child": 2.0, + "nth_of_type": 1.0, + "order": 14.0, + "tag_name": "body", + "text": null + } + ], + "elements_chain": "svg.LemonIcon:attr__aria-hidden=\"true\"attr__class=\"LemonIcon\"attr__fill=\"none\"attr__focusable=\"false\"attr__height=\"1em\"attr__viewBox=\"0 0 24 24\"attr__width=\"1em\"attr__xmlns=\"http://www.w3.org/2000/svg\"nth-child=\"1\"nth-of-type=\"1\";span.LemonButton__icon:attr__class=\"LemonButton__icon\"nth-child=\"1\"nth-of-type=\"1\";button.LemonButton.LemonButton--full-width.LemonButton--has-icon.LemonButton--no-content.LemonButton--status-stealth.LemonButton--tertiary.absolute-left:attr__class=\"LemonButton LemonButton--tertiary LemonButton--status-stealth LemonButton--full-width LemonButton--no-content LemonButton--has-icon absolute-left\"attr__data-attr=\"lemon-calendar-month-previous\"attr__type=\"button\"nth-child=\"1\"nth-of-type=\"1\";th.relative:attr__class=\"relative\"nth-child=\"1\"nth-of-type=\"1\";tr:nth-child=\"1\"nth-of-type=\"1\";thead:nth-child=\"1\"nth-of-type=\"1\";table.LemonCalendar__month:attr__class=\"LemonCalendar__month\"attr__data-attr=\"lemon-calendar-month\"nth-child=\"1\"nth-of-type=\"1\";div.LemonCalendar.flex.gap-4.items-start:attr__class=\"LemonCalendar flex items-start gap-4\"attr__data-attr=\"lemon-calendar\"nth-child=\"1\"nth-of-type=\"1\";div.p-2:attr__class=\"p-2\"nth-child=\"2\"nth-of-type=\"2\";div.LemonCalendarSelect:attr__class=\"LemonCalendarSelect\"attr__data-attr=\"lemon-calendar-select\"nth-child=\"1\"nth-of-type=\"1\";div.Popover__content:attr__class=\"Popover__content\"nth-child=\"1\"nth-of-type=\"1\";div.Popover__box:attr__class=\"Popover__box\"nth-child=\"1\"nth-of-type=\"1\";div.Popover.Popover--actionable.Popover--enter-done:attr__aria-level=\"0\"attr__class=\"Popover Popover--actionable Popover--enter-done\"attr__data-placement=\"bottom-start\"attr__style=\"position: fixed; top: 96px; left: 316px; max-height: 759px; max-width: 1192px; width: initial;\"nth-child=\"1\"nth-of-type=\"1\";div:attr__data-floating-ui-portal=\"\"attr__id=\"floating-ui-6\"attr_id=\"floating-ui-6\"nth-child=\"16\"nth-of-type=\"12\";body.posthog-3000:attr__class=\"posthog-3000\"attr__theme=\"light\"nth-child=\"2\"nth-of-type=\"1\"", + "event": "$autocapture", + "id": "018b4cc2-adb8-743c-8b0c-2d058759323d", + "person": null, + "properties": { + "$os": "Mac OS X", + "$os_version": "10.15.7", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/home", + "$host": "localhost:8000", + "$pathname": "/home", + "$browser_version": 117, + "$browser_language": "en-GB", + "$screen_height": 982, + "$screen_width": 1512, + "$viewport_height": 859, + "$viewport_width": 1512, + "$lib": "web", + "$lib_version": "1.84.0", + "$insert_id": "b1np3outhrtw2umv", + "$time": 1697799908.792, + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$device_id": "018a92fd-7b25-7770-a050-577e94fd148c", + "$console_log_recording_enabled_server_side": true, + "$session_recording_recorder_version_server_side": "v2", + "$autocapture_disabled_server_side": false, + "$active_feature_flags": [ + "signup-page-4.0", + "cmd-k-search", + "posthog-3000", + "funnels-cue-opt-out-7301", + "retention-breakdown", + "smoothing-interval", + "billing-limit", + "kafka-inspector", + "historical-exports-v2", + "person-on-events-enabled", + "region-select", + "ingestion-warnings-enabled", + "session-reset-on-load", + "recordings-on-feature-flags", + "auto-rollback-feature-flags", + "onboarding-v2-demo", + "feature-flag-rollout-ux", + "role-based-access", + "query_running_time", + "query-timings", + "recording-debugging", + "enable-prompts", + "feedback-scene", + "early-access-feature", + "early-access-feature-site-button", + "hedgehog-mode-debug", + "auto-redirect", + "session-recording-blob-replay", + "surveys", + "generic-signup-benefits", + "surveys-positions", + "web-analytics", + "high-frequency-batch-exports", + "exception-autocapture", + "data-warehouse", + "data-warehouse-views", + "ff-dashboard-templates", + "show-product-intro-existing-products", + "artificial-hog", + "cs-dashboards", + "product-specific-onboarding", + "redirect-signups-to-instance", + "apps-and-exports-ui", + "survey-nps-results", + "session-recording-allow-v1-snapshots", + "session-replay-cors-proxy", + "webhooks-denylist", + "surveys-site-app-deprecation", + "surveys-multiple-questions", + "surveys-results-visualizations", + "console-recording-search", + "persons-hogql-query", + "notebooks" + ], + "$feature/file-previews": false, + "$feature/signup-page-4.0": "control", + "$feature/hogql-insights": false, + "$feature/cmd-k-search": true, + "$feature/posthog-3000": true, + "$feature/funnels-cue-opt-out-7301": true, + "$feature/retention-breakdown": true, + "$feature/smoothing-interval": true, + "$feature/billing-limit": true, + "$feature/kafka-inspector": true, + "$feature/historical-exports-v2": true, + "$feature/person-on-events-enabled": true, + "$feature/region-select": true, + "$feature/ingestion-warnings-enabled": true, + "$feature/session-reset-on-load": true, + "$feature/recordings-on-feature-flags": true, + "$feature/auto-rollback-feature-flags": true, + "$feature/onboarding-v2-demo": true, + "$feature/feature-flag-rollout-ux": true, + "$feature/role-based-access": true, + "$feature/query_running_time": true, + "$feature/query-timings": true, + "$feature/recording-debugging": true, + "$feature/enable-prompts": true, + "$feature/feedback-scene": true, + "$feature/early-access-feature": true, + "$feature/early-access-feature-site-button": true, + "$feature/hedgehog-mode-debug": true, + "$feature/auto-redirect": true, + "$feature/session-recording-blob-replay": true, + "$feature/surveys": true, + "$feature/generic-signup-benefits": true, + "$feature/surveys-positions": true, + "$feature/web-analytics": true, + "$feature/high-frequency-batch-exports": true, + "$feature/exception-autocapture": true, + "$feature/data-warehouse": true, + "$feature/data-warehouse-views": true, + "$feature/ff-dashboard-templates": true, + "$feature/show-product-intro-existing-products": true, + "$feature/artificial-hog": true, + "$feature/cs-dashboards": true, + "$feature/product-specific-onboarding": true, + "$feature/redirect-signups-to-instance": true, + "$feature/apps-and-exports-ui": true, + "$feature/survey-nps-results": true, + "$feature/session-recording-allow-v1-snapshots": true, + "$feature/session-replay-cors-proxy": true, + "$feature/webhooks-denylist": true, + "$feature/surveys-site-app-deprecation": true, + "$feature/surveys-multiple-questions": true, + "$feature/surveys-results-visualizations": true, + "$feature/console-recording-search": true, + "$feature/persons-hogql-query": true, + "$feature/notebooks": true, + "$feature_flag_payloads": {}, + "realm": "hosted-clickhouse", + "email_service_available": false, + "slack_service_available": false, + "$user_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "is_demo_project": false, + "$groups": { + "project": "018a92f8-b602-0000-75de-4b9073693531", + "organization": "018a92f8-afff-0000-efec-ca77de39e384", + "customer": "cus_OdSgxxWtHOtq9g", + "instance": "http://localhost:8000" + }, + "has_billing_plan": true, + "customer_deactivated": false, + "current_total_amount_usd": "0.00", + "percentage_usage.product_analytics": 0, + "current_amount_usd.product_analytics": "0.00", + "unit_amount_usd.product_analytics": null, + "usage_limit.product_analytics": null, + "current_usage.product_analytics": 3729, + "projected_usage.product_analytics": 0, + "free_allocation.product_analytics": 0, + "percentage_usage.session_replay": 0, + "current_amount_usd.session_replay": "0.00", + "unit_amount_usd.session_replay": null, + "usage_limit.session_replay": null, + "current_usage.session_replay": 254, + "projected_usage.session_replay": 0, + "free_allocation.session_replay": 0, + "percentage_usage.feature_flags": 0, + "current_amount_usd.feature_flags": "0.00", + "unit_amount_usd.feature_flags": null, + "usage_limit.feature_flags": null, + "current_usage.feature_flags": 0, + "projected_usage.feature_flags": 0, + "free_allocation.feature_flags": 0, + "percentage_usage.integrations": 0, + "current_amount_usd.integrations": null, + "unit_amount_usd.integrations": null, + "usage_limit.integrations": 0, + "current_usage.integrations": 0, + "projected_usage.integrations": 0, + "free_allocation.integrations": 0, + "percentage_usage.platform_and_support": 0, + "current_amount_usd.platform_and_support": null, + "unit_amount_usd.platform_and_support": null, + "usage_limit.platform_and_support": 0, + "current_usage.platform_and_support": 0, + "projected_usage.platform_and_support": 0, + "free_allocation.platform_and_support": 0, + "billing_period_start": "2023-10-14T09:22:33.000Z", + "billing_period_end": "2023-11-14T09:22:33.000Z", + "$referrer": "$direct", + "$referring_domain": "$direct", + "$event_type": "click", + "$ce_version": 1, + "token": "phc_OWGI2wKbfi7rWDZT9wkl8uGcfe0wOGCvflLEZSMiaT0", + "$session_id": "018b4cc2-908b-7989-a77a-ae1396eef1de", + "$window_id": "018b4cc2-908b-7989-a77a-ae1465fa2118", + "$ip": "127.0.0.1", + "$set": { + "$os": "Mac OS X", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/home", + "$pathname": "/home", + "$browser_version": 117, + "$referrer": "$direct", + "$referring_domain": "$direct" + }, + "$set_once": { + "$initial_os": "Mac OS X", + "$initial_browser": "Chrome", + "$initial_device_type": "Desktop", + "$initial_current_url": "http://localhost:8000/home", + "$initial_pathname": "/home", + "$initial_browser_version": 117, + "$initial_referrer": "$direct", + "$initial_referring_domain": "$direct" + }, + "$sent_at": "2023-10-20T11:05:10.440000+00:00", + "$geoip_city_name": "Sydney", + "$geoip_country_name": "Australia", + "$geoip_country_code": "AU", + "$geoip_continent_name": "Oceania", + "$geoip_continent_code": "OC", + "$geoip_postal_code": "2000", + "$geoip_latitude": -33.8715, + "$geoip_longitude": 151.2006, + "$geoip_time_zone": "Australia/Sydney", + "$geoip_subdivision_1_code": "NSW", + "$geoip_subdivision_1_name": "New South Wales", + "$plugins_succeeded": ["GeoIP (1)"], + "$plugins_failed": [], + "$plugins_deferred": [], + "$group_3": "018a92f8-b602-0000-75de-4b9073693531", + "$group_2": "018a92f8-afff-0000-efec-ca77de39e384", + "$group_4": "cus_OdSgxxWtHOtq9g", + "$group_1": "http://localhost:8000" + }, + "timestamp": "2023-10-20T11:05:08.797000+00:00", + "uuid": null + }, + { + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "elements": [ + { + "attr_class": null, + "attr_id": null, + "attributes": { + "attr__d": "M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12 19 6.41z", + "attr__fill": "currentColor" + }, + "href": null, + "nth_child": 1.0, + "nth_of_type": 1.0, + "order": 0.0, + "tag_name": "path", + "text": null + }, + { + "attr_class": ["LemonIcon"], + "attr_id": null, + "attributes": { + "attr__aria-hidden": "true", + "attr__class": "LemonIcon", + "attr__fill": "none", + "attr__focusable": "false", + "attr__height": "1em", + "attr__viewBox": "0 0 24 24", + "attr__width": "1em", + "attr__xmlns": "http://www.w3.org/2000/svg" + }, + "href": null, + "nth_child": 1.0, + "nth_of_type": 1.0, + "order": 1.0, + "tag_name": "svg", + "text": null + }, + { + "attr_class": ["LemonButton__icon"], + "attr_id": null, + "attributes": { + "attr__class": "LemonButton__icon" + }, + "href": null, + "nth_child": 1.0, + "nth_of_type": 1.0, + "order": 2.0, + "tag_name": "span", + "text": null + }, + { + "attr_class": [ + "LemonButton", + "LemonButton--has-icon", + "LemonButton--no-content", + "LemonButton--no-padding", + "LemonButton--small", + "LemonButton--status-stealth", + "LemonButton--tertiary" + ], + "attr_id": null, + "attributes": { + "attr__aria-label": "close", + "attr__class": "LemonButton LemonButton--tertiary LemonButton--status-stealth LemonButton--no-padding LemonButton--small LemonButton--no-content LemonButton--has-icon", + "attr__type": "button" + }, + "href": null, + "nth_child": 2.0, + "nth_of_type": 1.0, + "order": 3.0, + "tag_name": "button", + "text": null + }, + { + "attr_class": ["border-b", "flex", "justify-between", "p-2", "pb-4"], + "attr_id": null, + "attributes": { + "attr__class": "flex justify-between border-b p-2 pb-4" + }, + "href": null, + "nth_child": 1.0, + "nth_of_type": 1.0, + "order": 4.0, + "tag_name": "div", + "text": null + }, + { + "attr_class": ["LemonCalendarSelect"], + "attr_id": null, + "attributes": { + "attr__class": "LemonCalendarSelect", + "attr__data-attr": "lemon-calendar-select" + }, + "href": null, + "nth_child": 1.0, + "nth_of_type": 1.0, + "order": 5.0, + "tag_name": "div", + "text": null + }, + { + "attr_class": ["Popover__content"], + "attr_id": null, + "attributes": { + "attr__class": "Popover__content" + }, + "href": null, + "nth_child": 1.0, + "nth_of_type": 1.0, + "order": 6.0, + "tag_name": "div", + "text": null + }, + { + "attr_class": ["Popover__box"], + "attr_id": null, + "attributes": { + "attr__class": "Popover__box" + }, + "href": null, + "nth_child": 1.0, + "nth_of_type": 1.0, + "order": 7.0, + "tag_name": "div", + "text": null + }, + { + "attr_class": ["Popover", "Popover--actionable", "Popover--enter-done"], + "attr_id": null, + "attributes": { + "attr__aria-level": "0", + "attr__class": "Popover Popover--actionable Popover--enter-done", + "attr__data-placement": "bottom-start", + "attr__style": "position: fixed; top: 96px; left: 316px; max-height: 759px; max-width: 1192px; width: initial;" + }, + "href": null, + "nth_child": 1.0, + "nth_of_type": 1.0, + "order": 8.0, + "tag_name": "div", + "text": null + }, + { + "attr_class": null, + "attr_id": null, + "attributes": { + "attr__data-floating-ui-portal": "\"attr__id=", + "floating-ui-6\"attr_id": "floating-ui-6" + }, + "href": null, + "nth_child": 16.0, + "nth_of_type": 12.0, + "order": 9.0, + "tag_name": "div", + "text": null + }, + { + "attr_class": ["posthog-3000"], + "attr_id": null, + "attributes": { + "attr__class": "posthog-3000", + "attr__theme": "light" + }, + "href": null, + "nth_child": 2.0, + "nth_of_type": 1.0, + "order": 10.0, + "tag_name": "body", + "text": null + } + ], + "elements_chain": "path:attr__d=\"M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12 19 6.41z\"attr__fill=\"currentColor\"nth-child=\"1\"nth-of-type=\"1\";svg.LemonIcon:attr__aria-hidden=\"true\"attr__class=\"LemonIcon\"attr__fill=\"none\"attr__focusable=\"false\"attr__height=\"1em\"attr__viewBox=\"0 0 24 24\"attr__width=\"1em\"attr__xmlns=\"http://www.w3.org/2000/svg\"nth-child=\"1\"nth-of-type=\"1\";span.LemonButton__icon:attr__class=\"LemonButton__icon\"nth-child=\"1\"nth-of-type=\"1\";button.LemonButton.LemonButton--has-icon.LemonButton--no-content.LemonButton--no-padding.LemonButton--small.LemonButton--status-stealth.LemonButton--tertiary:attr__aria-label=\"close\"attr__class=\"LemonButton LemonButton--tertiary LemonButton--status-stealth LemonButton--no-padding LemonButton--small LemonButton--no-content LemonButton--has-icon\"attr__type=\"button\"nth-child=\"2\"nth-of-type=\"1\";div.border-b.flex.justify-between.p-2.pb-4:attr__class=\"flex justify-between border-b p-2 pb-4\"nth-child=\"1\"nth-of-type=\"1\";div.LemonCalendarSelect:attr__class=\"LemonCalendarSelect\"attr__data-attr=\"lemon-calendar-select\"nth-child=\"1\"nth-of-type=\"1\";div.Popover__content:attr__class=\"Popover__content\"nth-child=\"1\"nth-of-type=\"1\";div.Popover__box:attr__class=\"Popover__box\"nth-child=\"1\"nth-of-type=\"1\";div.Popover.Popover--actionable.Popover--enter-done:attr__aria-level=\"0\"attr__class=\"Popover Popover--actionable Popover--enter-done\"attr__data-placement=\"bottom-start\"attr__style=\"position: fixed; top: 96px; left: 316px; max-height: 759px; max-width: 1192px; width: initial;\"nth-child=\"1\"nth-of-type=\"1\";div:attr__data-floating-ui-portal=\"\"attr__id=\"floating-ui-6\"attr_id=\"floating-ui-6\"nth-child=\"16\"nth-of-type=\"12\";body.posthog-3000:attr__class=\"posthog-3000\"attr__theme=\"light\"nth-child=\"2\"nth-of-type=\"1\"", + "event": "$autocapture", + "id": "018b4cc2-b4f2-7fd1-96fd-33b43dbbba31", + "person": null, + "properties": { + "$os": "Mac OS X", + "$os_version": "10.15.7", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/home", + "$host": "localhost:8000", + "$pathname": "/home", + "$browser_version": 117, + "$browser_language": "en-GB", + "$screen_height": 982, + "$screen_width": 1512, + "$viewport_height": 859, + "$viewport_width": 1512, + "$lib": "web", + "$lib_version": "1.84.0", + "$insert_id": "q4ton426hanvq70d", + "$time": 1697799910.643, + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$device_id": "018a92fd-7b25-7770-a050-577e94fd148c", + "$console_log_recording_enabled_server_side": true, + "$session_recording_recorder_version_server_side": "v2", + "$autocapture_disabled_server_side": false, + "$active_feature_flags": [ + "signup-page-4.0", + "cmd-k-search", + "posthog-3000", + "funnels-cue-opt-out-7301", + "retention-breakdown", + "smoothing-interval", + "billing-limit", + "kafka-inspector", + "historical-exports-v2", + "person-on-events-enabled", + "region-select", + "ingestion-warnings-enabled", + "session-reset-on-load", + "recordings-on-feature-flags", + "auto-rollback-feature-flags", + "onboarding-v2-demo", + "feature-flag-rollout-ux", + "role-based-access", + "query_running_time", + "query-timings", + "recording-debugging", + "enable-prompts", + "feedback-scene", + "early-access-feature", + "early-access-feature-site-button", + "hedgehog-mode-debug", + "auto-redirect", + "session-recording-blob-replay", + "surveys", + "generic-signup-benefits", + "surveys-positions", + "web-analytics", + "high-frequency-batch-exports", + "exception-autocapture", + "data-warehouse", + "data-warehouse-views", + "ff-dashboard-templates", + "show-product-intro-existing-products", + "artificial-hog", + "cs-dashboards", + "product-specific-onboarding", + "redirect-signups-to-instance", + "apps-and-exports-ui", + "survey-nps-results", + "session-recording-allow-v1-snapshots", + "session-replay-cors-proxy", + "webhooks-denylist", + "surveys-site-app-deprecation", + "surveys-multiple-questions", + "surveys-results-visualizations", + "console-recording-search", + "persons-hogql-query", + "notebooks" + ], + "$feature/file-previews": false, + "$feature/signup-page-4.0": "control", + "$feature/hogql-insights": false, + "$feature/cmd-k-search": true, + "$feature/posthog-3000": true, + "$feature/funnels-cue-opt-out-7301": true, + "$feature/retention-breakdown": true, + "$feature/smoothing-interval": true, + "$feature/billing-limit": true, + "$feature/kafka-inspector": true, + "$feature/historical-exports-v2": true, + "$feature/person-on-events-enabled": true, + "$feature/region-select": true, + "$feature/ingestion-warnings-enabled": true, + "$feature/session-reset-on-load": true, + "$feature/recordings-on-feature-flags": true, + "$feature/auto-rollback-feature-flags": true, + "$feature/onboarding-v2-demo": true, + "$feature/feature-flag-rollout-ux": true, + "$feature/role-based-access": true, + "$feature/query_running_time": true, + "$feature/query-timings": true, + "$feature/recording-debugging": true, + "$feature/enable-prompts": true, + "$feature/feedback-scene": true, + "$feature/early-access-feature": true, + "$feature/early-access-feature-site-button": true, + "$feature/hedgehog-mode-debug": true, + "$feature/auto-redirect": true, + "$feature/session-recording-blob-replay": true, + "$feature/surveys": true, + "$feature/generic-signup-benefits": true, + "$feature/surveys-positions": true, + "$feature/web-analytics": true, + "$feature/high-frequency-batch-exports": true, + "$feature/exception-autocapture": true, + "$feature/data-warehouse": true, + "$feature/data-warehouse-views": true, + "$feature/ff-dashboard-templates": true, + "$feature/show-product-intro-existing-products": true, + "$feature/artificial-hog": true, + "$feature/cs-dashboards": true, + "$feature/product-specific-onboarding": true, + "$feature/redirect-signups-to-instance": true, + "$feature/apps-and-exports-ui": true, + "$feature/survey-nps-results": true, + "$feature/session-recording-allow-v1-snapshots": true, + "$feature/session-replay-cors-proxy": true, + "$feature/webhooks-denylist": true, + "$feature/surveys-site-app-deprecation": true, + "$feature/surveys-multiple-questions": true, + "$feature/surveys-results-visualizations": true, + "$feature/console-recording-search": true, + "$feature/persons-hogql-query": true, + "$feature/notebooks": true, + "$feature_flag_payloads": {}, + "realm": "hosted-clickhouse", + "email_service_available": false, + "slack_service_available": false, + "$user_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "is_demo_project": false, + "$groups": { + "project": "018a92f8-b602-0000-75de-4b9073693531", + "organization": "018a92f8-afff-0000-efec-ca77de39e384", + "customer": "cus_OdSgxxWtHOtq9g", + "instance": "http://localhost:8000" + }, + "has_billing_plan": true, + "customer_deactivated": false, + "current_total_amount_usd": "0.00", + "percentage_usage.product_analytics": 0, + "current_amount_usd.product_analytics": "0.00", + "unit_amount_usd.product_analytics": null, + "usage_limit.product_analytics": null, + "current_usage.product_analytics": 3729, + "projected_usage.product_analytics": 0, + "free_allocation.product_analytics": 0, + "percentage_usage.session_replay": 0, + "current_amount_usd.session_replay": "0.00", + "unit_amount_usd.session_replay": null, + "usage_limit.session_replay": null, + "current_usage.session_replay": 254, + "projected_usage.session_replay": 0, + "free_allocation.session_replay": 0, + "percentage_usage.feature_flags": 0, + "current_amount_usd.feature_flags": "0.00", + "unit_amount_usd.feature_flags": null, + "usage_limit.feature_flags": null, + "current_usage.feature_flags": 0, + "projected_usage.feature_flags": 0, + "free_allocation.feature_flags": 0, + "percentage_usage.integrations": 0, + "current_amount_usd.integrations": null, + "unit_amount_usd.integrations": null, + "usage_limit.integrations": 0, + "current_usage.integrations": 0, + "projected_usage.integrations": 0, + "free_allocation.integrations": 0, + "percentage_usage.platform_and_support": 0, + "current_amount_usd.platform_and_support": null, + "unit_amount_usd.platform_and_support": null, + "usage_limit.platform_and_support": 0, + "current_usage.platform_and_support": 0, + "projected_usage.platform_and_support": 0, + "free_allocation.platform_and_support": 0, + "billing_period_start": "2023-10-14T09:22:33.000Z", + "billing_period_end": "2023-11-14T09:22:33.000Z", + "$referrer": "$direct", + "$referring_domain": "$direct", + "$event_type": "click", + "$ce_version": 1, + "token": "phc_OWGI2wKbfi7rWDZT9wkl8uGcfe0wOGCvflLEZSMiaT0", + "$session_id": "018b4cc2-908b-7989-a77a-ae1396eef1de", + "$window_id": "018b4cc2-908b-7989-a77a-ae1465fa2118", + "$ip": "127.0.0.1", + "$set": { + "$os": "Mac OS X", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/home", + "$pathname": "/home", + "$browser_version": 117, + "$referrer": "$direct", + "$referring_domain": "$direct" + }, + "$set_once": { + "$initial_os": "Mac OS X", + "$initial_browser": "Chrome", + "$initial_device_type": "Desktop", + "$initial_current_url": "http://localhost:8000/home", + "$initial_pathname": "/home", + "$initial_browser_version": 117, + "$initial_referrer": "$direct", + "$initial_referring_domain": "$direct" + }, + "$sent_at": "2023-10-20T11:05:13.450000+00:00", + "$geoip_city_name": "Sydney", + "$geoip_country_name": "Australia", + "$geoip_country_code": "AU", + "$geoip_continent_name": "Oceania", + "$geoip_continent_code": "OC", + "$geoip_postal_code": "2000", + "$geoip_latitude": -33.8715, + "$geoip_longitude": 151.2006, + "$geoip_time_zone": "Australia/Sydney", + "$geoip_subdivision_1_code": "NSW", + "$geoip_subdivision_1_name": "New South Wales", + "$plugins_succeeded": ["GeoIP (1)"], + "$plugins_failed": [], + "$plugins_deferred": [], + "$group_3": "018a92f8-b602-0000-75de-4b9073693531", + "$group_2": "018a92f8-afff-0000-efec-ca77de39e384", + "$group_4": "cus_OdSgxxWtHOtq9g", + "$group_1": "http://localhost:8000" + }, + "timestamp": "2023-10-20T11:05:10.652000+00:00", + "uuid": null + }, + { + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "elements": [ + { + "attr_class": [ + "LemonButton", + "LemonButton--status-stealth", + "LemonButton--tertiary", + "RollingDateRangeFilter", + "ant-tooltip-open" + ], + "attr_id": null, + "attributes": { + "attr__class": "LemonButton LemonButton--tertiary LemonButton--status-stealth RollingDateRangeFilter ant-tooltip-open", + "attr__data-attr": "rolling-date-range-filter", + "attr__type": "button" + }, + "href": null, + "nth_child": 13.0, + "nth_of_type": 13.0, + "order": 0.0, + "tag_name": "button", + "text": null + }, + { + "attr_class": ["space-y-px"], + "attr_id": null, + "attributes": { + "attr__class": "space-y-px" + }, + "href": null, + "nth_child": 1.0, + "nth_of_type": 1.0, + "order": 1.0, + "tag_name": "div", + "text": null + }, + { + "attr_class": ["Popover__content"], + "attr_id": null, + "attributes": { + "attr__class": "Popover__content" + }, + "href": null, + "nth_child": 1.0, + "nth_of_type": 1.0, + "order": 2.0, + "tag_name": "div", + "text": null + }, + { + "attr_class": ["Popover__box"], + "attr_id": null, + "attributes": { + "attr__class": "Popover__box" + }, + "href": null, + "nth_child": 1.0, + "nth_of_type": 1.0, + "order": 3.0, + "tag_name": "div", + "text": null + }, + { + "attr_class": ["Popover", "Popover--actionable", "Popover--enter-done"], + "attr_id": null, + "attributes": { + "attr__aria-level": "0", + "attr__class": "Popover Popover--actionable Popover--enter-done", + "attr__data-placement": "bottom-start", + "attr__style": "position: fixed; top: 96px; left: 316px; max-height: 759px; max-width: 1192px; width: initial;" + }, + "href": null, + "nth_child": 1.0, + "nth_of_type": 1.0, + "order": 4.0, + "tag_name": "div", + "text": null + }, + { + "attr_class": null, + "attr_id": null, + "attributes": { + "attr__data-floating-ui-portal": "\"attr__id=", + "floating-ui-6\"attr_id": "floating-ui-6" + }, + "href": null, + "nth_child": 16.0, + "nth_of_type": 12.0, + "order": 5.0, + "tag_name": "div", + "text": null + }, + { + "attr_class": ["posthog-3000"], + "attr_id": null, + "attributes": { + "attr__class": "posthog-3000", + "attr__theme": "light" + }, + "href": null, + "nth_child": 2.0, + "nth_of_type": 1.0, + "order": 6.0, + "tag_name": "body", + "text": null + } + ], + "elements_chain": "button.LemonButton.LemonButton--status-stealth.LemonButton--tertiary.RollingDateRangeFilter.ant-tooltip-open:attr__class=\"LemonButton LemonButton--tertiary LemonButton--status-stealth RollingDateRangeFilter ant-tooltip-open\"attr__data-attr=\"rolling-date-range-filter\"attr__type=\"button\"nth-child=\"13\"nth-of-type=\"13\";div.space-y-px:attr__class=\"space-y-px\"nth-child=\"1\"nth-of-type=\"1\";div.Popover__content:attr__class=\"Popover__content\"nth-child=\"1\"nth-of-type=\"1\";div.Popover__box:attr__class=\"Popover__box\"nth-child=\"1\"nth-of-type=\"1\";div.Popover.Popover--actionable.Popover--enter-done:attr__aria-level=\"0\"attr__class=\"Popover Popover--actionable Popover--enter-done\"attr__data-placement=\"bottom-start\"attr__style=\"position: fixed; top: 96px; left: 316px; max-height: 759px; max-width: 1192px; width: initial;\"nth-child=\"1\"nth-of-type=\"1\";div:attr__data-floating-ui-portal=\"\"attr__id=\"floating-ui-6\"attr_id=\"floating-ui-6\"nth-child=\"16\"nth-of-type=\"12\";body.posthog-3000:attr__class=\"posthog-3000\"attr__theme=\"light\"nth-child=\"2\"nth-of-type=\"1\"", + "event": "$autocapture", + "id": "018b4cc2-ba8a-744a-9296-ae83a0fb678c", + "person": null, + "properties": { + "$os": "Mac OS X", + "$os_version": "10.15.7", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/home", + "$host": "localhost:8000", + "$pathname": "/home", + "$browser_version": 117, + "$browser_language": "en-GB", + "$screen_height": 982, + "$screen_width": 1512, + "$viewport_height": 859, + "$viewport_width": 1512, + "$lib": "web", + "$lib_version": "1.84.0", + "$insert_id": "9hbicf15by04k3kk", + "$time": 1697799912.074, + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$device_id": "018a92fd-7b25-7770-a050-577e94fd148c", + "$console_log_recording_enabled_server_side": true, + "$session_recording_recorder_version_server_side": "v2", + "$autocapture_disabled_server_side": false, + "$active_feature_flags": [ + "signup-page-4.0", + "cmd-k-search", + "posthog-3000", + "funnels-cue-opt-out-7301", + "retention-breakdown", + "smoothing-interval", + "billing-limit", + "kafka-inspector", + "historical-exports-v2", + "person-on-events-enabled", + "region-select", + "ingestion-warnings-enabled", + "session-reset-on-load", + "recordings-on-feature-flags", + "auto-rollback-feature-flags", + "onboarding-v2-demo", + "feature-flag-rollout-ux", + "role-based-access", + "query_running_time", + "query-timings", + "recording-debugging", + "enable-prompts", + "feedback-scene", + "early-access-feature", + "early-access-feature-site-button", + "hedgehog-mode-debug", + "auto-redirect", + "session-recording-blob-replay", + "surveys", + "generic-signup-benefits", + "surveys-positions", + "web-analytics", + "high-frequency-batch-exports", + "exception-autocapture", + "data-warehouse", + "data-warehouse-views", + "ff-dashboard-templates", + "show-product-intro-existing-products", + "artificial-hog", + "cs-dashboards", + "product-specific-onboarding", + "redirect-signups-to-instance", + "apps-and-exports-ui", + "survey-nps-results", + "session-recording-allow-v1-snapshots", + "session-replay-cors-proxy", + "webhooks-denylist", + "surveys-site-app-deprecation", + "surveys-multiple-questions", + "surveys-results-visualizations", + "console-recording-search", + "persons-hogql-query", + "notebooks" + ], + "$feature/file-previews": false, + "$feature/signup-page-4.0": "control", + "$feature/hogql-insights": false, + "$feature/cmd-k-search": true, + "$feature/posthog-3000": true, + "$feature/funnels-cue-opt-out-7301": true, + "$feature/retention-breakdown": true, + "$feature/smoothing-interval": true, + "$feature/billing-limit": true, + "$feature/kafka-inspector": true, + "$feature/historical-exports-v2": true, + "$feature/person-on-events-enabled": true, + "$feature/region-select": true, + "$feature/ingestion-warnings-enabled": true, + "$feature/session-reset-on-load": true, + "$feature/recordings-on-feature-flags": true, + "$feature/auto-rollback-feature-flags": true, + "$feature/onboarding-v2-demo": true, + "$feature/feature-flag-rollout-ux": true, + "$feature/role-based-access": true, + "$feature/query_running_time": true, + "$feature/query-timings": true, + "$feature/recording-debugging": true, + "$feature/enable-prompts": true, + "$feature/feedback-scene": true, + "$feature/early-access-feature": true, + "$feature/early-access-feature-site-button": true, + "$feature/hedgehog-mode-debug": true, + "$feature/auto-redirect": true, + "$feature/session-recording-blob-replay": true, + "$feature/surveys": true, + "$feature/generic-signup-benefits": true, + "$feature/surveys-positions": true, + "$feature/web-analytics": true, + "$feature/high-frequency-batch-exports": true, + "$feature/exception-autocapture": true, + "$feature/data-warehouse": true, + "$feature/data-warehouse-views": true, + "$feature/ff-dashboard-templates": true, + "$feature/show-product-intro-existing-products": true, + "$feature/artificial-hog": true, + "$feature/cs-dashboards": true, + "$feature/product-specific-onboarding": true, + "$feature/redirect-signups-to-instance": true, + "$feature/apps-and-exports-ui": true, + "$feature/survey-nps-results": true, + "$feature/session-recording-allow-v1-snapshots": true, + "$feature/session-replay-cors-proxy": true, + "$feature/webhooks-denylist": true, + "$feature/surveys-site-app-deprecation": true, + "$feature/surveys-multiple-questions": true, + "$feature/surveys-results-visualizations": true, + "$feature/console-recording-search": true, + "$feature/persons-hogql-query": true, + "$feature/notebooks": true, + "$feature_flag_payloads": {}, + "realm": "hosted-clickhouse", + "email_service_available": false, + "slack_service_available": false, + "$user_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "is_demo_project": false, + "$groups": { + "project": "018a92f8-b602-0000-75de-4b9073693531", + "organization": "018a92f8-afff-0000-efec-ca77de39e384", + "customer": "cus_OdSgxxWtHOtq9g", + "instance": "http://localhost:8000" + }, + "has_billing_plan": true, + "customer_deactivated": false, + "current_total_amount_usd": "0.00", + "percentage_usage.product_analytics": 0, + "current_amount_usd.product_analytics": "0.00", + "unit_amount_usd.product_analytics": null, + "usage_limit.product_analytics": null, + "current_usage.product_analytics": 3729, + "projected_usage.product_analytics": 0, + "free_allocation.product_analytics": 0, + "percentage_usage.session_replay": 0, + "current_amount_usd.session_replay": "0.00", + "unit_amount_usd.session_replay": null, + "usage_limit.session_replay": null, + "current_usage.session_replay": 254, + "projected_usage.session_replay": 0, + "free_allocation.session_replay": 0, + "percentage_usage.feature_flags": 0, + "current_amount_usd.feature_flags": "0.00", + "unit_amount_usd.feature_flags": null, + "usage_limit.feature_flags": null, + "current_usage.feature_flags": 0, + "projected_usage.feature_flags": 0, + "free_allocation.feature_flags": 0, + "percentage_usage.integrations": 0, + "current_amount_usd.integrations": null, + "unit_amount_usd.integrations": null, + "usage_limit.integrations": 0, + "current_usage.integrations": 0, + "projected_usage.integrations": 0, + "free_allocation.integrations": 0, + "percentage_usage.platform_and_support": 0, + "current_amount_usd.platform_and_support": null, + "unit_amount_usd.platform_and_support": null, + "usage_limit.platform_and_support": 0, + "current_usage.platform_and_support": 0, + "projected_usage.platform_and_support": 0, + "free_allocation.platform_and_support": 0, + "billing_period_start": "2023-10-14T09:22:33.000Z", + "billing_period_end": "2023-11-14T09:22:33.000Z", + "$referrer": "$direct", + "$referring_domain": "$direct", + "$event_type": "click", + "$ce_version": 1, + "token": "phc_OWGI2wKbfi7rWDZT9wkl8uGcfe0wOGCvflLEZSMiaT0", + "$session_id": "018b4cc2-908b-7989-a77a-ae1396eef1de", + "$window_id": "018b4cc2-908b-7989-a77a-ae1465fa2118", + "$ip": "127.0.0.1", + "$set": { + "$os": "Mac OS X", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/home", + "$pathname": "/home", + "$browser_version": 117, + "$referrer": "$direct", + "$referring_domain": "$direct" + }, + "$set_once": { + "$initial_os": "Mac OS X", + "$initial_browser": "Chrome", + "$initial_device_type": "Desktop", + "$initial_current_url": "http://localhost:8000/home", + "$initial_pathname": "/home", + "$initial_browser_version": 117, + "$initial_referrer": "$direct", + "$initial_referring_domain": "$direct" + }, + "$sent_at": "2023-10-20T11:05:13.450000+00:00", + "$geoip_city_name": "Sydney", + "$geoip_country_name": "Australia", + "$geoip_country_code": "AU", + "$geoip_continent_name": "Oceania", + "$geoip_continent_code": "OC", + "$geoip_postal_code": "2000", + "$geoip_latitude": -33.8715, + "$geoip_longitude": 151.2006, + "$geoip_time_zone": "Australia/Sydney", + "$geoip_subdivision_1_code": "NSW", + "$geoip_subdivision_1_name": "New South Wales", + "$plugins_succeeded": ["GeoIP (1)"], + "$plugins_failed": [], + "$plugins_deferred": [], + "$group_3": "018a92f8-b602-0000-75de-4b9073693531", + "$group_2": "018a92f8-afff-0000-efec-ca77de39e384", + "$group_4": "cus_OdSgxxWtHOtq9g", + "$group_1": "http://localhost:8000" + }, + "timestamp": "2023-10-20T11:05:12.083000+00:00", + "uuid": null + }, + { + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "elements": [], + "elements_chain": null, + "event": "dashboard date range changed", + "id": "018b4cc2-ba98-7ad6-98aa-a99547036166", + "person": null, + "properties": { + "$os": "Mac OS X", + "$os_version": "10.15.7", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/home", + "$host": "localhost:8000", + "$pathname": "/home", + "$browser_version": 117, + "$browser_language": "en-GB", + "$screen_height": 982, + "$screen_width": 1512, + "$viewport_height": 859, + "$viewport_width": 1512, + "$lib": "web", + "$lib_version": "1.84.0", + "$insert_id": "uwqspa6yuoq5q75h", + "$time": 1697799912.089, + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$device_id": "018a92fd-7b25-7770-a050-577e94fd148c", + "$console_log_recording_enabled_server_side": true, + "$session_recording_recorder_version_server_side": "v2", + "$autocapture_disabled_server_side": false, + "$active_feature_flags": [ + "signup-page-4.0", + "cmd-k-search", + "posthog-3000", + "funnels-cue-opt-out-7301", + "retention-breakdown", + "smoothing-interval", + "billing-limit", + "kafka-inspector", + "historical-exports-v2", + "person-on-events-enabled", + "region-select", + "ingestion-warnings-enabled", + "session-reset-on-load", + "recordings-on-feature-flags", + "auto-rollback-feature-flags", + "onboarding-v2-demo", + "feature-flag-rollout-ux", + "role-based-access", + "query_running_time", + "query-timings", + "recording-debugging", + "enable-prompts", + "feedback-scene", + "early-access-feature", + "early-access-feature-site-button", + "hedgehog-mode-debug", + "auto-redirect", + "session-recording-blob-replay", + "surveys", + "generic-signup-benefits", + "surveys-positions", + "web-analytics", + "high-frequency-batch-exports", + "exception-autocapture", + "data-warehouse", + "data-warehouse-views", + "ff-dashboard-templates", + "show-product-intro-existing-products", + "artificial-hog", + "cs-dashboards", + "product-specific-onboarding", + "redirect-signups-to-instance", + "apps-and-exports-ui", + "survey-nps-results", + "session-recording-allow-v1-snapshots", + "session-replay-cors-proxy", + "webhooks-denylist", + "surveys-site-app-deprecation", + "surveys-multiple-questions", + "surveys-results-visualizations", + "console-recording-search", + "persons-hogql-query", + "notebooks" + ], + "$feature/file-previews": false, + "$feature/signup-page-4.0": "control", + "$feature/hogql-insights": false, + "$feature/cmd-k-search": true, + "$feature/posthog-3000": true, + "$feature/funnels-cue-opt-out-7301": true, + "$feature/retention-breakdown": true, + "$feature/smoothing-interval": true, + "$feature/billing-limit": true, + "$feature/kafka-inspector": true, + "$feature/historical-exports-v2": true, + "$feature/person-on-events-enabled": true, + "$feature/region-select": true, + "$feature/ingestion-warnings-enabled": true, + "$feature/session-reset-on-load": true, + "$feature/recordings-on-feature-flags": true, + "$feature/auto-rollback-feature-flags": true, + "$feature/onboarding-v2-demo": true, + "$feature/feature-flag-rollout-ux": true, + "$feature/role-based-access": true, + "$feature/query_running_time": true, + "$feature/query-timings": true, + "$feature/recording-debugging": true, + "$feature/enable-prompts": true, + "$feature/feedback-scene": true, + "$feature/early-access-feature": true, + "$feature/early-access-feature-site-button": true, + "$feature/hedgehog-mode-debug": true, + "$feature/auto-redirect": true, + "$feature/session-recording-blob-replay": true, + "$feature/surveys": true, + "$feature/generic-signup-benefits": true, + "$feature/surveys-positions": true, + "$feature/web-analytics": true, + "$feature/high-frequency-batch-exports": true, + "$feature/exception-autocapture": true, + "$feature/data-warehouse": true, + "$feature/data-warehouse-views": true, + "$feature/ff-dashboard-templates": true, + "$feature/show-product-intro-existing-products": true, + "$feature/artificial-hog": true, + "$feature/cs-dashboards": true, + "$feature/product-specific-onboarding": true, + "$feature/redirect-signups-to-instance": true, + "$feature/apps-and-exports-ui": true, + "$feature/survey-nps-results": true, + "$feature/session-recording-allow-v1-snapshots": true, + "$feature/session-replay-cors-proxy": true, + "$feature/webhooks-denylist": true, + "$feature/surveys-site-app-deprecation": true, + "$feature/surveys-multiple-questions": true, + "$feature/surveys-results-visualizations": true, + "$feature/console-recording-search": true, + "$feature/persons-hogql-query": true, + "$feature/notebooks": true, + "$feature_flag_payloads": {}, + "realm": "hosted-clickhouse", + "email_service_available": false, + "slack_service_available": false, + "$user_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "is_demo_project": false, + "$groups": { + "project": "018a92f8-b602-0000-75de-4b9073693531", + "organization": "018a92f8-afff-0000-efec-ca77de39e384", + "customer": "cus_OdSgxxWtHOtq9g", + "instance": "http://localhost:8000" + }, + "has_billing_plan": true, + "customer_deactivated": false, + "current_total_amount_usd": "0.00", + "percentage_usage.product_analytics": 0, + "current_amount_usd.product_analytics": "0.00", + "unit_amount_usd.product_analytics": null, + "usage_limit.product_analytics": null, + "current_usage.product_analytics": 3729, + "projected_usage.product_analytics": 0, + "free_allocation.product_analytics": 0, + "percentage_usage.session_replay": 0, + "current_amount_usd.session_replay": "0.00", + "unit_amount_usd.session_replay": null, + "usage_limit.session_replay": null, + "current_usage.session_replay": 254, + "projected_usage.session_replay": 0, + "free_allocation.session_replay": 0, + "percentage_usage.feature_flags": 0, + "current_amount_usd.feature_flags": "0.00", + "unit_amount_usd.feature_flags": null, + "usage_limit.feature_flags": null, + "current_usage.feature_flags": 0, + "projected_usage.feature_flags": 0, + "free_allocation.feature_flags": 0, + "percentage_usage.integrations": 0, + "current_amount_usd.integrations": null, + "unit_amount_usd.integrations": null, + "usage_limit.integrations": 0, + "current_usage.integrations": 0, + "projected_usage.integrations": 0, + "free_allocation.integrations": 0, + "percentage_usage.platform_and_support": 0, + "current_amount_usd.platform_and_support": null, + "unit_amount_usd.platform_and_support": null, + "usage_limit.platform_and_support": 0, + "current_usage.platform_and_support": 0, + "projected_usage.platform_and_support": 0, + "free_allocation.platform_and_support": 0, + "billing_period_start": "2023-10-14T09:22:33.000Z", + "billing_period_end": "2023-11-14T09:22:33.000Z", + "$referrer": "$direct", + "$referring_domain": "$direct", + "date_from": "-3d", + "date_to": "", + "token": "phc_OWGI2wKbfi7rWDZT9wkl8uGcfe0wOGCvflLEZSMiaT0", + "$session_id": "018b4cc2-908b-7989-a77a-ae1396eef1de", + "$window_id": "018b4cc2-908b-7989-a77a-ae1465fa2118", + "$ip": "127.0.0.1", + "$set": { + "$os": "Mac OS X", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/home", + "$pathname": "/home", + "$browser_version": 117, + "$referrer": "$direct", + "$referring_domain": "$direct" + }, + "$set_once": { + "$initial_os": "Mac OS X", + "$initial_browser": "Chrome", + "$initial_device_type": "Desktop", + "$initial_current_url": "http://localhost:8000/home", + "$initial_pathname": "/home", + "$initial_browser_version": 117, + "$initial_referrer": "$direct", + "$initial_referring_domain": "$direct" + }, + "$sent_at": "2023-10-20T11:05:13.450000+00:00", + "$geoip_city_name": "Sydney", + "$geoip_country_name": "Australia", + "$geoip_country_code": "AU", + "$geoip_continent_name": "Oceania", + "$geoip_continent_code": "OC", + "$geoip_postal_code": "2000", + "$geoip_latitude": -33.8715, + "$geoip_longitude": 151.2006, + "$geoip_time_zone": "Australia/Sydney", + "$geoip_subdivision_1_code": "NSW", + "$geoip_subdivision_1_name": "New South Wales", + "$plugins_succeeded": ["GeoIP (1)"], + "$plugins_failed": [], + "$plugins_deferred": [], + "$group_3": "018a92f8-b602-0000-75de-4b9073693531", + "$group_2": "018a92f8-afff-0000-efec-ca77de39e384", + "$group_4": "cus_OdSgxxWtHOtq9g", + "$group_1": "http://localhost:8000" + }, + "timestamp": "2023-10-20T11:05:12.098000+00:00", + "uuid": null + }, + { + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "elements": [], + "elements_chain": null, + "event": "dashboard analyzed", + "id": "018b4cc2-bb85-7403-a87c-f4ba1a76997f", + "person": null, + "properties": { + "$os": "Mac OS X", + "$os_version": "10.15.7", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/home", + "$host": "localhost:8000", + "$pathname": "/home", + "$browser_version": 117, + "$browser_language": "en-GB", + "$screen_height": 982, + "$screen_width": 1512, + "$viewport_height": 859, + "$viewport_width": 1512, + "$lib": "web", + "$lib_version": "1.84.0", + "$insert_id": "6q7tobdbp8r841sq", + "$time": 1697799912.326, + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$device_id": "018a92fd-7b25-7770-a050-577e94fd148c", + "$console_log_recording_enabled_server_side": true, + "$session_recording_recorder_version_server_side": "v2", + "$autocapture_disabled_server_side": false, + "$active_feature_flags": [ + "signup-page-4.0", + "cmd-k-search", + "posthog-3000", + "funnels-cue-opt-out-7301", + "retention-breakdown", + "smoothing-interval", + "billing-limit", + "kafka-inspector", + "historical-exports-v2", + "person-on-events-enabled", + "region-select", + "ingestion-warnings-enabled", + "session-reset-on-load", + "recordings-on-feature-flags", + "auto-rollback-feature-flags", + "onboarding-v2-demo", + "feature-flag-rollout-ux", + "role-based-access", + "query_running_time", + "query-timings", + "recording-debugging", + "enable-prompts", + "feedback-scene", + "early-access-feature", + "early-access-feature-site-button", + "hedgehog-mode-debug", + "auto-redirect", + "session-recording-blob-replay", + "surveys", + "generic-signup-benefits", + "surveys-positions", + "web-analytics", + "high-frequency-batch-exports", + "exception-autocapture", + "data-warehouse", + "data-warehouse-views", + "ff-dashboard-templates", + "show-product-intro-existing-products", + "artificial-hog", + "cs-dashboards", + "product-specific-onboarding", + "redirect-signups-to-instance", + "apps-and-exports-ui", + "survey-nps-results", + "session-recording-allow-v1-snapshots", + "session-replay-cors-proxy", + "webhooks-denylist", + "surveys-site-app-deprecation", + "surveys-multiple-questions", + "surveys-results-visualizations", + "console-recording-search", + "persons-hogql-query", + "notebooks" + ], + "$feature/file-previews": false, + "$feature/signup-page-4.0": "control", + "$feature/hogql-insights": false, + "$feature/cmd-k-search": true, + "$feature/posthog-3000": true, + "$feature/funnels-cue-opt-out-7301": true, + "$feature/retention-breakdown": true, + "$feature/smoothing-interval": true, + "$feature/billing-limit": true, + "$feature/kafka-inspector": true, + "$feature/historical-exports-v2": true, + "$feature/person-on-events-enabled": true, + "$feature/region-select": true, + "$feature/ingestion-warnings-enabled": true, + "$feature/session-reset-on-load": true, + "$feature/recordings-on-feature-flags": true, + "$feature/auto-rollback-feature-flags": true, + "$feature/onboarding-v2-demo": true, + "$feature/feature-flag-rollout-ux": true, + "$feature/role-based-access": true, + "$feature/query_running_time": true, + "$feature/query-timings": true, + "$feature/recording-debugging": true, + "$feature/enable-prompts": true, + "$feature/feedback-scene": true, + "$feature/early-access-feature": true, + "$feature/early-access-feature-site-button": true, + "$feature/hedgehog-mode-debug": true, + "$feature/auto-redirect": true, + "$feature/session-recording-blob-replay": true, + "$feature/surveys": true, + "$feature/generic-signup-benefits": true, + "$feature/surveys-positions": true, + "$feature/web-analytics": true, + "$feature/high-frequency-batch-exports": true, + "$feature/exception-autocapture": true, + "$feature/data-warehouse": true, + "$feature/data-warehouse-views": true, + "$feature/ff-dashboard-templates": true, + "$feature/show-product-intro-existing-products": true, + "$feature/artificial-hog": true, + "$feature/cs-dashboards": true, + "$feature/product-specific-onboarding": true, + "$feature/redirect-signups-to-instance": true, + "$feature/apps-and-exports-ui": true, + "$feature/survey-nps-results": true, + "$feature/session-recording-allow-v1-snapshots": true, + "$feature/session-replay-cors-proxy": true, + "$feature/webhooks-denylist": true, + "$feature/surveys-site-app-deprecation": true, + "$feature/surveys-multiple-questions": true, + "$feature/surveys-results-visualizations": true, + "$feature/console-recording-search": true, + "$feature/persons-hogql-query": true, + "$feature/notebooks": true, + "$feature_flag_payloads": {}, + "realm": "hosted-clickhouse", + "email_service_available": false, + "slack_service_available": false, + "$user_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "is_demo_project": false, + "$groups": { + "project": "018a92f8-b602-0000-75de-4b9073693531", + "organization": "018a92f8-afff-0000-efec-ca77de39e384", + "customer": "cus_OdSgxxWtHOtq9g", + "instance": "http://localhost:8000" + }, + "has_billing_plan": true, + "customer_deactivated": false, + "current_total_amount_usd": "0.00", + "percentage_usage.product_analytics": 0, + "current_amount_usd.product_analytics": "0.00", + "unit_amount_usd.product_analytics": null, + "usage_limit.product_analytics": null, + "current_usage.product_analytics": 3729, + "projected_usage.product_analytics": 0, + "free_allocation.product_analytics": 0, + "percentage_usage.session_replay": 0, + "current_amount_usd.session_replay": "0.00", + "unit_amount_usd.session_replay": null, + "usage_limit.session_replay": null, + "current_usage.session_replay": 254, + "projected_usage.session_replay": 0, + "free_allocation.session_replay": 0, + "percentage_usage.feature_flags": 0, + "current_amount_usd.feature_flags": "0.00", + "unit_amount_usd.feature_flags": null, + "usage_limit.feature_flags": null, + "current_usage.feature_flags": 0, + "projected_usage.feature_flags": 0, + "free_allocation.feature_flags": 0, + "percentage_usage.integrations": 0, + "current_amount_usd.integrations": null, + "unit_amount_usd.integrations": null, + "usage_limit.integrations": 0, + "current_usage.integrations": 0, + "projected_usage.integrations": 0, + "free_allocation.integrations": 0, + "percentage_usage.platform_and_support": 0, + "current_amount_usd.platform_and_support": null, + "unit_amount_usd.platform_and_support": null, + "usage_limit.platform_and_support": 0, + "current_usage.platform_and_support": 0, + "projected_usage.platform_and_support": 0, + "free_allocation.platform_and_support": 0, + "billing_period_start": "2023-10-14T09:22:33.000Z", + "billing_period_end": "2023-11-14T09:22:33.000Z", + "$referrer": "$direct", + "$referring_domain": "$direct", + "created_at": "2023-09-14T09:15:00.211731Z", + "is_shared": false, + "pinned": true, + "creation_mode": "default", + "sample_items_count": 0, + "item_count": 7, + "created_by_system": true, + "dashboard_id": 1, + "lastRefreshed": "2023-10-20T10:20:11.963Z", + "refreshAge": 2700, + "lifecycle_count": 2, + "trends_count": 3, + "funnels_count": 1, + "retention_count": 1, + "token": "phc_OWGI2wKbfi7rWDZT9wkl8uGcfe0wOGCvflLEZSMiaT0", + "$session_id": "018b4cc2-908b-7989-a77a-ae1396eef1de", + "$window_id": "018b4cc2-908b-7989-a77a-ae1465fa2118", + "$ip": "127.0.0.1", + "$set": { + "$os": "Mac OS X", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/home", + "$pathname": "/home", + "$browser_version": 117, + "$referrer": "$direct", + "$referring_domain": "$direct" + }, + "$set_once": { + "$initial_os": "Mac OS X", + "$initial_browser": "Chrome", + "$initial_device_type": "Desktop", + "$initial_current_url": "http://localhost:8000/home", + "$initial_pathname": "/home", + "$initial_browser_version": 117, + "$initial_referrer": "$direct", + "$initial_referring_domain": "$direct" + }, + "$sent_at": "2023-10-20T11:05:13.450000+00:00", + "$geoip_city_name": "Sydney", + "$geoip_country_name": "Australia", + "$geoip_country_code": "AU", + "$geoip_continent_name": "Oceania", + "$geoip_continent_code": "OC", + "$geoip_postal_code": "2000", + "$geoip_latitude": -33.8715, + "$geoip_longitude": 151.2006, + "$geoip_time_zone": "Australia/Sydney", + "$geoip_subdivision_1_code": "NSW", + "$geoip_subdivision_1_name": "New South Wales", + "$plugins_succeeded": ["GeoIP (1)"], + "$plugins_failed": [], + "$plugins_deferred": [], + "$group_3": "018a92f8-b602-0000-75de-4b9073693531", + "$group_2": "018a92f8-afff-0000-efec-ca77de39e384", + "$group_4": "cus_OdSgxxWtHOtq9g", + "$group_1": "http://localhost:8000" + }, + "timestamp": "2023-10-20T11:05:12.335000+00:00", + "uuid": null + }, + { + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "elements": [], + "elements_chain": null, + "event": "$feature_flag_called", + "id": "018b4cc2-bc1a-78b3-8dd2-62a1da584a79", + "person": null, + "properties": { + "$os": "Mac OS X", + "$os_version": "10.15.7", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/home", + "$host": "localhost:8000", + "$pathname": "/home", + "$browser_version": 117, + "$browser_language": "en-GB", + "$screen_height": 982, + "$screen_width": 1512, + "$viewport_height": 859, + "$viewport_width": 1512, + "$lib": "web", + "$lib_version": "1.84.0", + "$insert_id": "rlklgku5nltwckj1", + "$time": 1697799912.475, + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$device_id": "018a92fd-7b25-7770-a050-577e94fd148c", + "$console_log_recording_enabled_server_side": true, + "$session_recording_recorder_version_server_side": "v2", + "$autocapture_disabled_server_side": false, + "$active_feature_flags": [ + "signup-page-4.0", + "cmd-k-search", + "posthog-3000", + "funnels-cue-opt-out-7301", + "retention-breakdown", + "smoothing-interval", + "billing-limit", + "kafka-inspector", + "historical-exports-v2", + "person-on-events-enabled", + "region-select", + "ingestion-warnings-enabled", + "session-reset-on-load", + "recordings-on-feature-flags", + "auto-rollback-feature-flags", + "onboarding-v2-demo", + "feature-flag-rollout-ux", + "role-based-access", + "query_running_time", + "query-timings", + "recording-debugging", + "enable-prompts", + "feedback-scene", + "early-access-feature", + "early-access-feature-site-button", + "hedgehog-mode-debug", + "auto-redirect", + "session-recording-blob-replay", + "surveys", + "generic-signup-benefits", + "surveys-positions", + "web-analytics", + "high-frequency-batch-exports", + "exception-autocapture", + "data-warehouse", + "data-warehouse-views", + "ff-dashboard-templates", + "show-product-intro-existing-products", + "artificial-hog", + "cs-dashboards", + "product-specific-onboarding", + "redirect-signups-to-instance", + "apps-and-exports-ui", + "survey-nps-results", + "session-recording-allow-v1-snapshots", + "session-replay-cors-proxy", + "webhooks-denylist", + "surveys-site-app-deprecation", + "surveys-multiple-questions", + "surveys-results-visualizations", + "console-recording-search", + "persons-hogql-query", + "notebooks" + ], + "$feature/file-previews": false, + "$feature/signup-page-4.0": "control", + "$feature/hogql-insights": false, + "$feature/cmd-k-search": true, + "$feature/posthog-3000": true, + "$feature/funnels-cue-opt-out-7301": true, + "$feature/retention-breakdown": true, + "$feature/smoothing-interval": true, + "$feature/billing-limit": true, + "$feature/kafka-inspector": true, + "$feature/historical-exports-v2": true, + "$feature/person-on-events-enabled": true, + "$feature/region-select": true, + "$feature/ingestion-warnings-enabled": true, + "$feature/session-reset-on-load": true, + "$feature/recordings-on-feature-flags": true, + "$feature/auto-rollback-feature-flags": true, + "$feature/onboarding-v2-demo": true, + "$feature/feature-flag-rollout-ux": true, + "$feature/role-based-access": true, + "$feature/query_running_time": true, + "$feature/query-timings": true, + "$feature/recording-debugging": true, + "$feature/enable-prompts": true, + "$feature/feedback-scene": true, + "$feature/early-access-feature": true, + "$feature/early-access-feature-site-button": true, + "$feature/hedgehog-mode-debug": true, + "$feature/auto-redirect": true, + "$feature/session-recording-blob-replay": true, + "$feature/surveys": true, + "$feature/generic-signup-benefits": true, + "$feature/surveys-positions": true, + "$feature/web-analytics": true, + "$feature/high-frequency-batch-exports": true, + "$feature/exception-autocapture": true, + "$feature/data-warehouse": true, + "$feature/data-warehouse-views": true, + "$feature/ff-dashboard-templates": true, + "$feature/show-product-intro-existing-products": true, + "$feature/artificial-hog": true, + "$feature/cs-dashboards": true, + "$feature/product-specific-onboarding": true, + "$feature/redirect-signups-to-instance": true, + "$feature/apps-and-exports-ui": true, + "$feature/survey-nps-results": true, + "$feature/session-recording-allow-v1-snapshots": true, + "$feature/session-replay-cors-proxy": true, + "$feature/webhooks-denylist": true, + "$feature/surveys-site-app-deprecation": true, + "$feature/surveys-multiple-questions": true, + "$feature/surveys-results-visualizations": true, + "$feature/console-recording-search": true, + "$feature/persons-hogql-query": true, + "$feature/notebooks": true, + "$feature_flag_payloads": {}, + "realm": "hosted-clickhouse", + "email_service_available": false, + "slack_service_available": false, + "$user_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "is_demo_project": false, + "$groups": { + "project": "018a92f8-b602-0000-75de-4b9073693531", + "organization": "018a92f8-afff-0000-efec-ca77de39e384", + "customer": "cus_OdSgxxWtHOtq9g", + "instance": "http://localhost:8000" + }, + "has_billing_plan": true, + "customer_deactivated": false, + "current_total_amount_usd": "0.00", + "percentage_usage.product_analytics": 0, + "current_amount_usd.product_analytics": "0.00", + "unit_amount_usd.product_analytics": null, + "usage_limit.product_analytics": null, + "current_usage.product_analytics": 3729, + "projected_usage.product_analytics": 0, + "free_allocation.product_analytics": 0, + "percentage_usage.session_replay": 0, + "current_amount_usd.session_replay": "0.00", + "unit_amount_usd.session_replay": null, + "usage_limit.session_replay": null, + "current_usage.session_replay": 254, + "projected_usage.session_replay": 0, + "free_allocation.session_replay": 0, + "percentage_usage.feature_flags": 0, + "current_amount_usd.feature_flags": "0.00", + "unit_amount_usd.feature_flags": null, + "usage_limit.feature_flags": null, + "current_usage.feature_flags": 0, + "projected_usage.feature_flags": 0, + "free_allocation.feature_flags": 0, + "percentage_usage.integrations": 0, + "current_amount_usd.integrations": null, + "unit_amount_usd.integrations": null, + "usage_limit.integrations": 0, + "current_usage.integrations": 0, + "projected_usage.integrations": 0, + "free_allocation.integrations": 0, + "percentage_usage.platform_and_support": 0, + "current_amount_usd.platform_and_support": null, + "unit_amount_usd.platform_and_support": null, + "usage_limit.platform_and_support": 0, + "current_usage.platform_and_support": 0, + "projected_usage.platform_and_support": 0, + "free_allocation.platform_and_support": 0, + "billing_period_start": "2023-10-14T09:22:33.000Z", + "billing_period_end": "2023-11-14T09:22:33.000Z", + "$referrer": "$direct", + "$referring_domain": "$direct", + "$feature_flag": "hogql-insights", + "$feature_flag_response": false, + "token": "phc_OWGI2wKbfi7rWDZT9wkl8uGcfe0wOGCvflLEZSMiaT0", + "$session_id": "018b4cc2-908b-7989-a77a-ae1396eef1de", + "$window_id": "018b4cc2-908b-7989-a77a-ae1465fa2118", + "$ip": "127.0.0.1", + "$set": { + "$os": "Mac OS X", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/home", + "$pathname": "/home", + "$browser_version": 117, + "$referrer": "$direct", + "$referring_domain": "$direct" + }, + "$set_once": { + "$initial_os": "Mac OS X", + "$initial_browser": "Chrome", + "$initial_device_type": "Desktop", + "$initial_current_url": "http://localhost:8000/home", + "$initial_pathname": "/home", + "$initial_browser_version": 117, + "$initial_referrer": "$direct", + "$initial_referring_domain": "$direct" + }, + "$sent_at": "2023-10-20T11:05:13.450000+00:00", + "$geoip_city_name": "Sydney", + "$geoip_country_name": "Australia", + "$geoip_country_code": "AU", + "$geoip_continent_name": "Oceania", + "$geoip_continent_code": "OC", + "$geoip_postal_code": "2000", + "$geoip_latitude": -33.8715, + "$geoip_longitude": 151.2006, + "$geoip_time_zone": "Australia/Sydney", + "$geoip_subdivision_1_code": "NSW", + "$geoip_subdivision_1_name": "New South Wales", + "$plugins_succeeded": ["GeoIP (1)"], + "$plugins_failed": [], + "$plugins_deferred": [], + "$group_3": "018a92f8-b602-0000-75de-4b9073693531", + "$group_2": "018a92f8-afff-0000-efec-ca77de39e384", + "$group_4": "cus_OdSgxxWtHOtq9g", + "$group_1": "http://localhost:8000" + }, + "timestamp": "2023-10-20T11:05:12.484000+00:00", + "uuid": null + }, + { + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "elements": [], + "elements_chain": null, + "event": "dashboard refreshed", + "id": "018b4cc2-bc66-7cf9-b8b3-9b34a5a4bda5", + "person": null, + "properties": { + "$os": "Mac OS X", + "$os_version": "10.15.7", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/home", + "$host": "localhost:8000", + "$pathname": "/home", + "$browser_version": 117, + "$browser_language": "en-GB", + "$screen_height": 982, + "$screen_width": 1512, + "$viewport_height": 859, + "$viewport_width": 1512, + "$lib": "web", + "$lib_version": "1.84.0", + "$insert_id": "lacrgsirai9uzwji", + "$time": 1697799912.551, + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$device_id": "018a92fd-7b25-7770-a050-577e94fd148c", + "$console_log_recording_enabled_server_side": true, + "$session_recording_recorder_version_server_side": "v2", + "$autocapture_disabled_server_side": false, + "$active_feature_flags": [ + "signup-page-4.0", + "cmd-k-search", + "posthog-3000", + "funnels-cue-opt-out-7301", + "retention-breakdown", + "smoothing-interval", + "billing-limit", + "kafka-inspector", + "historical-exports-v2", + "person-on-events-enabled", + "region-select", + "ingestion-warnings-enabled", + "session-reset-on-load", + "recordings-on-feature-flags", + "auto-rollback-feature-flags", + "onboarding-v2-demo", + "feature-flag-rollout-ux", + "role-based-access", + "query_running_time", + "query-timings", + "recording-debugging", + "enable-prompts", + "feedback-scene", + "early-access-feature", + "early-access-feature-site-button", + "hedgehog-mode-debug", + "auto-redirect", + "session-recording-blob-replay", + "surveys", + "generic-signup-benefits", + "surveys-positions", + "web-analytics", + "high-frequency-batch-exports", + "exception-autocapture", + "data-warehouse", + "data-warehouse-views", + "ff-dashboard-templates", + "show-product-intro-existing-products", + "artificial-hog", + "cs-dashboards", + "product-specific-onboarding", + "redirect-signups-to-instance", + "apps-and-exports-ui", + "survey-nps-results", + "session-recording-allow-v1-snapshots", + "session-replay-cors-proxy", + "webhooks-denylist", + "surveys-site-app-deprecation", + "surveys-multiple-questions", + "surveys-results-visualizations", + "console-recording-search", + "persons-hogql-query", + "notebooks" + ], + "$feature/file-previews": false, + "$feature/signup-page-4.0": "control", + "$feature/hogql-insights": false, + "$feature/cmd-k-search": true, + "$feature/posthog-3000": true, + "$feature/funnels-cue-opt-out-7301": true, + "$feature/retention-breakdown": true, + "$feature/smoothing-interval": true, + "$feature/billing-limit": true, + "$feature/kafka-inspector": true, + "$feature/historical-exports-v2": true, + "$feature/person-on-events-enabled": true, + "$feature/region-select": true, + "$feature/ingestion-warnings-enabled": true, + "$feature/session-reset-on-load": true, + "$feature/recordings-on-feature-flags": true, + "$feature/auto-rollback-feature-flags": true, + "$feature/onboarding-v2-demo": true, + "$feature/feature-flag-rollout-ux": true, + "$feature/role-based-access": true, + "$feature/query_running_time": true, + "$feature/query-timings": true, + "$feature/recording-debugging": true, + "$feature/enable-prompts": true, + "$feature/feedback-scene": true, + "$feature/early-access-feature": true, + "$feature/early-access-feature-site-button": true, + "$feature/hedgehog-mode-debug": true, + "$feature/auto-redirect": true, + "$feature/session-recording-blob-replay": true, + "$feature/surveys": true, + "$feature/generic-signup-benefits": true, + "$feature/surveys-positions": true, + "$feature/web-analytics": true, + "$feature/high-frequency-batch-exports": true, + "$feature/exception-autocapture": true, + "$feature/data-warehouse": true, + "$feature/data-warehouse-views": true, + "$feature/ff-dashboard-templates": true, + "$feature/show-product-intro-existing-products": true, + "$feature/artificial-hog": true, + "$feature/cs-dashboards": true, + "$feature/product-specific-onboarding": true, + "$feature/redirect-signups-to-instance": true, + "$feature/apps-and-exports-ui": true, + "$feature/survey-nps-results": true, + "$feature/session-recording-allow-v1-snapshots": true, + "$feature/session-replay-cors-proxy": true, + "$feature/webhooks-denylist": true, + "$feature/surveys-site-app-deprecation": true, + "$feature/surveys-multiple-questions": true, + "$feature/surveys-results-visualizations": true, + "$feature/console-recording-search": true, + "$feature/persons-hogql-query": true, + "$feature/notebooks": true, + "$feature_flag_payloads": {}, + "realm": "hosted-clickhouse", + "email_service_available": false, + "slack_service_available": false, + "$user_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "is_demo_project": false, + "$groups": { + "project": "018a92f8-b602-0000-75de-4b9073693531", + "organization": "018a92f8-afff-0000-efec-ca77de39e384", + "customer": "cus_OdSgxxWtHOtq9g", + "instance": "http://localhost:8000" + }, + "has_billing_plan": true, + "customer_deactivated": false, + "current_total_amount_usd": "0.00", + "percentage_usage.product_analytics": 0, + "current_amount_usd.product_analytics": "0.00", + "unit_amount_usd.product_analytics": null, + "usage_limit.product_analytics": null, + "current_usage.product_analytics": 3729, + "projected_usage.product_analytics": 0, + "free_allocation.product_analytics": 0, + "percentage_usage.session_replay": 0, + "current_amount_usd.session_replay": "0.00", + "unit_amount_usd.session_replay": null, + "usage_limit.session_replay": null, + "current_usage.session_replay": 254, + "projected_usage.session_replay": 0, + "free_allocation.session_replay": 0, + "percentage_usage.feature_flags": 0, + "current_amount_usd.feature_flags": "0.00", + "unit_amount_usd.feature_flags": null, + "usage_limit.feature_flags": null, + "current_usage.feature_flags": 0, + "projected_usage.feature_flags": 0, + "free_allocation.feature_flags": 0, + "percentage_usage.integrations": 0, + "current_amount_usd.integrations": null, + "unit_amount_usd.integrations": null, + "usage_limit.integrations": 0, + "current_usage.integrations": 0, + "projected_usage.integrations": 0, + "free_allocation.integrations": 0, + "percentage_usage.platform_and_support": 0, + "current_amount_usd.platform_and_support": null, + "unit_amount_usd.platform_and_support": null, + "usage_limit.platform_and_support": 0, + "current_usage.platform_and_support": 0, + "projected_usage.platform_and_support": 0, + "free_allocation.platform_and_support": 0, + "billing_period_start": "2023-10-14T09:22:33.000Z", + "billing_period_end": "2023-11-14T09:22:33.000Z", + "$referrer": "$direct", + "$referring_domain": "$direct", + "dashboard_id": 1, + "token": "phc_OWGI2wKbfi7rWDZT9wkl8uGcfe0wOGCvflLEZSMiaT0", + "$session_id": "018b4cc2-908b-7989-a77a-ae1396eef1de", + "$window_id": "018b4cc2-908b-7989-a77a-ae1465fa2118", + "$ip": "127.0.0.1", + "$set": { + "$os": "Mac OS X", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/home", + "$pathname": "/home", + "$browser_version": 117, + "$referrer": "$direct", + "$referring_domain": "$direct" + }, + "$set_once": { + "$initial_os": "Mac OS X", + "$initial_browser": "Chrome", + "$initial_device_type": "Desktop", + "$initial_current_url": "http://localhost:8000/home", + "$initial_pathname": "/home", + "$initial_browser_version": 117, + "$initial_referrer": "$direct", + "$initial_referring_domain": "$direct" + }, + "$sent_at": "2023-10-20T11:05:13.450000+00:00", + "$geoip_city_name": "Sydney", + "$geoip_country_name": "Australia", + "$geoip_country_code": "AU", + "$geoip_continent_name": "Oceania", + "$geoip_continent_code": "OC", + "$geoip_postal_code": "2000", + "$geoip_latitude": -33.8715, + "$geoip_longitude": 151.2006, + "$geoip_time_zone": "Australia/Sydney", + "$geoip_subdivision_1_code": "NSW", + "$geoip_subdivision_1_name": "New South Wales", + "$plugins_succeeded": ["GeoIP (1)"], + "$plugins_failed": [], + "$plugins_deferred": [], + "$group_3": "018a92f8-b602-0000-75de-4b9073693531", + "$group_2": "018a92f8-afff-0000-efec-ca77de39e384", + "$group_4": "cus_OdSgxxWtHOtq9g", + "$group_1": "http://localhost:8000" + }, + "timestamp": "2023-10-20T11:05:12.560000+00:00", + "uuid": null + }, + { + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "elements": [ + { + "attr_class": ["LemonButton__content"], + "attr_id": null, + "attributes": { + "attr__class": "LemonButton__content" + }, + "href": null, + "nth_child": 2.0, + "nth_of_type": 2.0, + "order": 0.0, + "tag_name": "span", + "text": "Last 3 days" + }, + { + "attr_class": [ + "LemonButton", + "LemonButton--has-icon", + "LemonButton--has-side-icon", + "LemonButton--secondary", + "LemonButton--small", + "LemonButton--status-stealth" + ], + "attr_id": "daterange_selector", + "attributes": { + "attr__aria-disabled": "false", + "attr__aria-haspopup": "true", + "attr__class": "LemonButton LemonButton--secondary LemonButton--status-stealth LemonButton--small LemonButton--has-icon LemonButton--has-side-icon", + "attr__data-attr": "date-filter", + "attr__id": "daterange_selector", + "attr__type": "button" + }, + "href": null, + "nth_child": 1.0, + "nth_of_type": 1.0, + "order": 1.0, + "tag_name": "button", + "text": "Last 3 days" + }, + { + "attr_class": ["flex", "h-8", "items-center", "shrink-0"], + "attr_id": null, + "attributes": { + "attr__class": "flex shrink-0 items-center h-8" + }, + "href": null, + "nth_child": 1.0, + "nth_of_type": 1.0, + "order": 2.0, + "tag_name": "div", + "text": null + }, + { + "attr_class": ["flex", "space-x-4"], + "attr_id": null, + "attributes": { + "attr__class": "flex space-x-4" + }, + "href": null, + "nth_child": 1.0, + "nth_of_type": 1.0, + "order": 3.0, + "tag_name": "div", + "text": null + }, + { + "attr_class": ["flex", "justify-between", "space-x-4"], + "attr_id": null, + "attributes": { + "attr__class": "flex space-x-4 justify-between" + }, + "href": null, + "nth_child": 1.0, + "nth_of_type": 1.0, + "order": 4.0, + "tag_name": "div", + "text": null + }, + { + "attr_class": null, + "attr_id": null, + "attributes": {}, + "href": null, + "nth_child": 1.0, + "nth_of_type": 1.0, + "order": 5.0, + "tag_name": "div", + "text": null + }, + { + "attr_class": ["dashboard"], + "attr_id": null, + "attributes": { + "attr__class": "dashboard" + }, + "href": null, + "nth_child": 1.0, + "nth_of_type": 1.0, + "order": 6.0, + "tag_name": "div", + "text": null + }, + { + "attr_class": ["project-homepage"], + "attr_id": null, + "attributes": { + "attr__class": "project-homepage" + }, + "href": null, + "nth_child": 1.0, + "nth_of_type": 1.0, + "order": 7.0, + "tag_name": "div", + "text": null + }, + { + "attr_class": ["Navigation3000__scene"], + "attr_id": null, + "attributes": { + "attr__class": "Navigation3000__scene" + }, + "href": null, + "nth_child": 2.0, + "nth_of_type": 2.0, + "order": 8.0, + "tag_name": "div", + "text": null + }, + { + "attr_class": null, + "attr_id": null, + "attributes": {}, + "href": null, + "nth_child": 4.0, + "nth_of_type": 1.0, + "order": 9.0, + "tag_name": "main", + "text": null + }, + { + "attr_class": ["Navigation3000"], + "attr_id": null, + "attributes": { + "attr__class": "Navigation3000" + }, + "href": null, + "nth_child": 1.0, + "nth_of_type": 1.0, + "order": 10.0, + "tag_name": "div", + "text": null + }, + { + "attr_class": null, + "attr_id": "root", + "attributes": { + "attr__id": "root" + }, + "href": null, + "nth_child": 4.0, + "nth_of_type": 1.0, + "order": 11.0, + "tag_name": "div", + "text": null + }, + { + "attr_class": ["posthog-3000"], + "attr_id": null, + "attributes": { + "attr__class": "posthog-3000", + "attr__theme": "light" + }, + "href": null, + "nth_child": 2.0, + "nth_of_type": 1.0, + "order": 12.0, + "tag_name": "body", + "text": null + } + ], + "elements_chain": "span.LemonButton__content:attr__class=\"LemonButton__content\"nth-child=\"2\"nth-of-type=\"2\"text=\"Last 3 days\";button.LemonButton.LemonButton--has-icon.LemonButton--has-side-icon.LemonButton--secondary.LemonButton--small.LemonButton--status-stealth:attr__aria-disabled=\"false\"attr__aria-haspopup=\"true\"attr__class=\"LemonButton LemonButton--secondary LemonButton--status-stealth LemonButton--small LemonButton--has-icon LemonButton--has-side-icon\"attr__data-attr=\"date-filter\"attr__id=\"daterange_selector\"attr__type=\"button\"attr_id=\"daterange_selector\"nth-child=\"1\"nth-of-type=\"1\"text=\"Last 3 days\";div.flex.h-8.items-center.shrink-0:attr__class=\"flex shrink-0 items-center h-8\"nth-child=\"1\"nth-of-type=\"1\";div.flex.space-x-4:attr__class=\"flex space-x-4\"nth-child=\"1\"nth-of-type=\"1\";div.flex.justify-between.space-x-4:attr__class=\"flex space-x-4 justify-between\"nth-child=\"1\"nth-of-type=\"1\";div:nth-child=\"1\"nth-of-type=\"1\";div.dashboard:attr__class=\"dashboard\"nth-child=\"1\"nth-of-type=\"1\";div.project-homepage:attr__class=\"project-homepage\"nth-child=\"1\"nth-of-type=\"1\";div.Navigation3000__scene:attr__class=\"Navigation3000__scene\"nth-child=\"2\"nth-of-type=\"2\";main:nth-child=\"4\"nth-of-type=\"1\";div.Navigation3000:attr__class=\"Navigation3000\"nth-child=\"1\"nth-of-type=\"1\";div:attr__id=\"root\"attr_id=\"root\"nth-child=\"4\"nth-of-type=\"1\";body.posthog-3000:attr__class=\"posthog-3000\"attr__theme=\"light\"nth-child=\"2\"nth-of-type=\"1\"", + "event": "$autocapture", + "id": "018b4cc2-bfa8-7a18-88bc-4c4df6cabd69", + "person": null, + "properties": { + "$os": "Mac OS X", + "$os_version": "10.15.7", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/home", + "$host": "localhost:8000", + "$pathname": "/home", + "$browser_version": 117, + "$browser_language": "en-GB", + "$screen_height": 982, + "$screen_width": 1512, + "$viewport_height": 859, + "$viewport_width": 1512, + "$lib": "web", + "$lib_version": "1.84.0", + "$insert_id": "h9m0b1qconuwsw62", + "$time": 1697799913.386, + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$device_id": "018a92fd-7b25-7770-a050-577e94fd148c", + "$console_log_recording_enabled_server_side": true, + "$session_recording_recorder_version_server_side": "v2", + "$autocapture_disabled_server_side": false, + "$active_feature_flags": [ + "signup-page-4.0", + "cmd-k-search", + "posthog-3000", + "funnels-cue-opt-out-7301", + "retention-breakdown", + "smoothing-interval", + "billing-limit", + "kafka-inspector", + "historical-exports-v2", + "person-on-events-enabled", + "region-select", + "ingestion-warnings-enabled", + "session-reset-on-load", + "recordings-on-feature-flags", + "auto-rollback-feature-flags", + "onboarding-v2-demo", + "feature-flag-rollout-ux", + "role-based-access", + "query_running_time", + "query-timings", + "recording-debugging", + "enable-prompts", + "feedback-scene", + "early-access-feature", + "early-access-feature-site-button", + "hedgehog-mode-debug", + "auto-redirect", + "session-recording-blob-replay", + "surveys", + "generic-signup-benefits", + "surveys-positions", + "web-analytics", + "high-frequency-batch-exports", + "exception-autocapture", + "data-warehouse", + "data-warehouse-views", + "ff-dashboard-templates", + "show-product-intro-existing-products", + "artificial-hog", + "cs-dashboards", + "product-specific-onboarding", + "redirect-signups-to-instance", + "apps-and-exports-ui", + "survey-nps-results", + "session-recording-allow-v1-snapshots", + "session-replay-cors-proxy", + "webhooks-denylist", + "surveys-site-app-deprecation", + "surveys-multiple-questions", + "surveys-results-visualizations", + "console-recording-search", + "persons-hogql-query", + "notebooks" + ], + "$feature/file-previews": false, + "$feature/signup-page-4.0": "control", + "$feature/hogql-insights": false, + "$feature/cmd-k-search": true, + "$feature/posthog-3000": true, + "$feature/funnels-cue-opt-out-7301": true, + "$feature/retention-breakdown": true, + "$feature/smoothing-interval": true, + "$feature/billing-limit": true, + "$feature/kafka-inspector": true, + "$feature/historical-exports-v2": true, + "$feature/person-on-events-enabled": true, + "$feature/region-select": true, + "$feature/ingestion-warnings-enabled": true, + "$feature/session-reset-on-load": true, + "$feature/recordings-on-feature-flags": true, + "$feature/auto-rollback-feature-flags": true, + "$feature/onboarding-v2-demo": true, + "$feature/feature-flag-rollout-ux": true, + "$feature/role-based-access": true, + "$feature/query_running_time": true, + "$feature/query-timings": true, + "$feature/recording-debugging": true, + "$feature/enable-prompts": true, + "$feature/feedback-scene": true, + "$feature/early-access-feature": true, + "$feature/early-access-feature-site-button": true, + "$feature/hedgehog-mode-debug": true, + "$feature/auto-redirect": true, + "$feature/session-recording-blob-replay": true, + "$feature/surveys": true, + "$feature/generic-signup-benefits": true, + "$feature/surveys-positions": true, + "$feature/web-analytics": true, + "$feature/high-frequency-batch-exports": true, + "$feature/exception-autocapture": true, + "$feature/data-warehouse": true, + "$feature/data-warehouse-views": true, + "$feature/ff-dashboard-templates": true, + "$feature/show-product-intro-existing-products": true, + "$feature/artificial-hog": true, + "$feature/cs-dashboards": true, + "$feature/product-specific-onboarding": true, + "$feature/redirect-signups-to-instance": true, + "$feature/apps-and-exports-ui": true, + "$feature/survey-nps-results": true, + "$feature/session-recording-allow-v1-snapshots": true, + "$feature/session-replay-cors-proxy": true, + "$feature/webhooks-denylist": true, + "$feature/surveys-site-app-deprecation": true, + "$feature/surveys-multiple-questions": true, + "$feature/surveys-results-visualizations": true, + "$feature/console-recording-search": true, + "$feature/persons-hogql-query": true, + "$feature/notebooks": true, + "$feature_flag_payloads": {}, + "realm": "hosted-clickhouse", + "email_service_available": false, + "slack_service_available": false, + "$user_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "is_demo_project": false, + "$groups": { + "project": "018a92f8-b602-0000-75de-4b9073693531", + "organization": "018a92f8-afff-0000-efec-ca77de39e384", + "customer": "cus_OdSgxxWtHOtq9g", + "instance": "http://localhost:8000" + }, + "has_billing_plan": true, + "customer_deactivated": false, + "current_total_amount_usd": "0.00", + "percentage_usage.product_analytics": 0, + "current_amount_usd.product_analytics": "0.00", + "unit_amount_usd.product_analytics": null, + "usage_limit.product_analytics": null, + "current_usage.product_analytics": 3729, + "projected_usage.product_analytics": 0, + "free_allocation.product_analytics": 0, + "percentage_usage.session_replay": 0, + "current_amount_usd.session_replay": "0.00", + "unit_amount_usd.session_replay": null, + "usage_limit.session_replay": null, + "current_usage.session_replay": 254, + "projected_usage.session_replay": 0, + "free_allocation.session_replay": 0, + "percentage_usage.feature_flags": 0, + "current_amount_usd.feature_flags": "0.00", + "unit_amount_usd.feature_flags": null, + "usage_limit.feature_flags": null, + "current_usage.feature_flags": 0, + "projected_usage.feature_flags": 0, + "free_allocation.feature_flags": 0, + "percentage_usage.integrations": 0, + "current_amount_usd.integrations": null, + "unit_amount_usd.integrations": null, + "usage_limit.integrations": 0, + "current_usage.integrations": 0, + "projected_usage.integrations": 0, + "free_allocation.integrations": 0, + "percentage_usage.platform_and_support": 0, + "current_amount_usd.platform_and_support": null, + "unit_amount_usd.platform_and_support": null, + "usage_limit.platform_and_support": 0, + "current_usage.platform_and_support": 0, + "projected_usage.platform_and_support": 0, + "free_allocation.platform_and_support": 0, + "billing_period_start": "2023-10-14T09:22:33.000Z", + "billing_period_end": "2023-11-14T09:22:33.000Z", + "$referrer": "$direct", + "$referring_domain": "$direct", + "$event_type": "click", + "$ce_version": 1, + "$el_text": "Last 3 days", + "token": "phc_OWGI2wKbfi7rWDZT9wkl8uGcfe0wOGCvflLEZSMiaT0", + "$session_id": "018b4cc2-908b-7989-a77a-ae1396eef1de", + "$window_id": "018b4cc2-908b-7989-a77a-ae1465fa2118", + "$ip": "127.0.0.1", + "$set": { + "$os": "Mac OS X", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/home", + "$pathname": "/home", + "$browser_version": 117, + "$referrer": "$direct", + "$referring_domain": "$direct" + }, + "$set_once": { + "$initial_os": "Mac OS X", + "$initial_browser": "Chrome", + "$initial_device_type": "Desktop", + "$initial_current_url": "http://localhost:8000/home", + "$initial_pathname": "/home", + "$initial_browser_version": 117, + "$initial_referrer": "$direct", + "$initial_referring_domain": "$direct" + }, + "$sent_at": "2023-10-20T11:05:13.450000+00:00", + "$geoip_city_name": "Sydney", + "$geoip_country_name": "Australia", + "$geoip_country_code": "AU", + "$geoip_continent_name": "Oceania", + "$geoip_continent_code": "OC", + "$geoip_postal_code": "2000", + "$geoip_latitude": -33.8715, + "$geoip_longitude": 151.2006, + "$geoip_time_zone": "Australia/Sydney", + "$geoip_subdivision_1_code": "NSW", + "$geoip_subdivision_1_name": "New South Wales", + "$plugins_succeeded": ["GeoIP (1)"], + "$plugins_failed": [], + "$plugins_deferred": [], + "$group_3": "018a92f8-b602-0000-75de-4b9073693531", + "$group_2": "018a92f8-afff-0000-efec-ca77de39e384", + "$group_4": "cus_OdSgxxWtHOtq9g", + "$group_1": "http://localhost:8000" + }, + "timestamp": "2023-10-20T11:05:13.395000+00:00", + "uuid": null + }, + { + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "elements": [], + "elements_chain": null, + "event": "insight refresh time", + "id": "018b4cc2-c072-7506-930b-471161be099f", + "person": null, + "properties": { + "$os": "Mac OS X", + "$os_version": "10.15.7", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/home", + "$host": "localhost:8000", + "$pathname": "/home", + "$browser_version": 117, + "$browser_language": "en-GB", + "$screen_height": 982, + "$screen_width": 1512, + "$viewport_height": 859, + "$viewport_width": 1512, + "$lib": "web", + "$lib_version": "1.84.0", + "$insert_id": "jnfwtms067nt0iva", + "$time": 1697799913.586, + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$device_id": "018a92fd-7b25-7770-a050-577e94fd148c", + "$console_log_recording_enabled_server_side": true, + "$session_recording_recorder_version_server_side": "v2", + "$autocapture_disabled_server_side": false, + "$active_feature_flags": [ + "signup-page-4.0", + "cmd-k-search", + "posthog-3000", + "funnels-cue-opt-out-7301", + "retention-breakdown", + "smoothing-interval", + "billing-limit", + "kafka-inspector", + "historical-exports-v2", + "person-on-events-enabled", + "region-select", + "ingestion-warnings-enabled", + "session-reset-on-load", + "recordings-on-feature-flags", + "auto-rollback-feature-flags", + "onboarding-v2-demo", + "feature-flag-rollout-ux", + "role-based-access", + "query_running_time", + "query-timings", + "recording-debugging", + "enable-prompts", + "feedback-scene", + "early-access-feature", + "early-access-feature-site-button", + "hedgehog-mode-debug", + "auto-redirect", + "session-recording-blob-replay", + "surveys", + "generic-signup-benefits", + "surveys-positions", + "web-analytics", + "high-frequency-batch-exports", + "exception-autocapture", + "data-warehouse", + "data-warehouse-views", + "ff-dashboard-templates", + "show-product-intro-existing-products", + "artificial-hog", + "cs-dashboards", + "product-specific-onboarding", + "redirect-signups-to-instance", + "apps-and-exports-ui", + "survey-nps-results", + "session-recording-allow-v1-snapshots", + "session-replay-cors-proxy", + "webhooks-denylist", + "surveys-site-app-deprecation", + "surveys-multiple-questions", + "surveys-results-visualizations", + "console-recording-search", + "persons-hogql-query", + "notebooks" + ], + "$feature/file-previews": false, + "$feature/signup-page-4.0": "control", + "$feature/hogql-insights": false, + "$feature/cmd-k-search": true, + "$feature/posthog-3000": true, + "$feature/funnels-cue-opt-out-7301": true, + "$feature/retention-breakdown": true, + "$feature/smoothing-interval": true, + "$feature/billing-limit": true, + "$feature/kafka-inspector": true, + "$feature/historical-exports-v2": true, + "$feature/person-on-events-enabled": true, + "$feature/region-select": true, + "$feature/ingestion-warnings-enabled": true, + "$feature/session-reset-on-load": true, + "$feature/recordings-on-feature-flags": true, + "$feature/auto-rollback-feature-flags": true, + "$feature/onboarding-v2-demo": true, + "$feature/feature-flag-rollout-ux": true, + "$feature/role-based-access": true, + "$feature/query_running_time": true, + "$feature/query-timings": true, + "$feature/recording-debugging": true, + "$feature/enable-prompts": true, + "$feature/feedback-scene": true, + "$feature/early-access-feature": true, + "$feature/early-access-feature-site-button": true, + "$feature/hedgehog-mode-debug": true, + "$feature/auto-redirect": true, + "$feature/session-recording-blob-replay": true, + "$feature/surveys": true, + "$feature/generic-signup-benefits": true, + "$feature/surveys-positions": true, + "$feature/web-analytics": true, + "$feature/high-frequency-batch-exports": true, + "$feature/exception-autocapture": true, + "$feature/data-warehouse": true, + "$feature/data-warehouse-views": true, + "$feature/ff-dashboard-templates": true, + "$feature/show-product-intro-existing-products": true, + "$feature/artificial-hog": true, + "$feature/cs-dashboards": true, + "$feature/product-specific-onboarding": true, + "$feature/redirect-signups-to-instance": true, + "$feature/apps-and-exports-ui": true, + "$feature/survey-nps-results": true, + "$feature/session-recording-allow-v1-snapshots": true, + "$feature/session-replay-cors-proxy": true, + "$feature/webhooks-denylist": true, + "$feature/surveys-site-app-deprecation": true, + "$feature/surveys-multiple-questions": true, + "$feature/surveys-results-visualizations": true, + "$feature/console-recording-search": true, + "$feature/persons-hogql-query": true, + "$feature/notebooks": true, + "$feature_flag_payloads": {}, + "realm": "hosted-clickhouse", + "email_service_available": false, + "slack_service_available": false, + "$user_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "is_demo_project": false, + "$groups": { + "project": "018a92f8-b602-0000-75de-4b9073693531", + "organization": "018a92f8-afff-0000-efec-ca77de39e384", + "customer": "cus_OdSgxxWtHOtq9g", + "instance": "http://localhost:8000" + }, + "has_billing_plan": true, + "customer_deactivated": false, + "current_total_amount_usd": "0.00", + "percentage_usage.product_analytics": 0, + "current_amount_usd.product_analytics": "0.00", + "unit_amount_usd.product_analytics": null, + "usage_limit.product_analytics": null, + "current_usage.product_analytics": 3729, + "projected_usage.product_analytics": 0, + "free_allocation.product_analytics": 0, + "percentage_usage.session_replay": 0, + "current_amount_usd.session_replay": "0.00", + "unit_amount_usd.session_replay": null, + "usage_limit.session_replay": null, + "current_usage.session_replay": 254, + "projected_usage.session_replay": 0, + "free_allocation.session_replay": 0, + "percentage_usage.feature_flags": 0, + "current_amount_usd.feature_flags": "0.00", + "unit_amount_usd.feature_flags": null, + "usage_limit.feature_flags": null, + "current_usage.feature_flags": 0, + "projected_usage.feature_flags": 0, + "free_allocation.feature_flags": 0, + "percentage_usage.integrations": 0, + "current_amount_usd.integrations": null, + "unit_amount_usd.integrations": null, + "usage_limit.integrations": 0, + "current_usage.integrations": 0, + "projected_usage.integrations": 0, + "free_allocation.integrations": 0, + "percentage_usage.platform_and_support": 0, + "current_amount_usd.platform_and_support": null, + "unit_amount_usd.platform_and_support": null, + "usage_limit.platform_and_support": 0, + "current_usage.platform_and_support": 0, + "projected_usage.platform_and_support": 0, + "free_allocation.platform_and_support": 0, + "billing_period_start": "2023-10-14T09:22:33.000Z", + "billing_period_end": "2023-11-14T09:22:33.000Z", + "$referrer": "$direct", + "$referring_domain": "$direct", + "loadingMilliseconds": 1053, + "insightShortId": "dr2P0xDf", + "token": "phc_OWGI2wKbfi7rWDZT9wkl8uGcfe0wOGCvflLEZSMiaT0", + "$session_id": "018b4cc2-908b-7989-a77a-ae1396eef1de", + "$window_id": "018b4cc2-908b-7989-a77a-ae1465fa2118", + "$ip": "127.0.0.1", + "$set": { + "$os": "Mac OS X", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/home", + "$pathname": "/home", + "$browser_version": 117, + "$referrer": "$direct", + "$referring_domain": "$direct" + }, + "$set_once": { + "$initial_os": "Mac OS X", + "$initial_browser": "Chrome", + "$initial_device_type": "Desktop", + "$initial_current_url": "http://localhost:8000/home", + "$initial_pathname": "/home", + "$initial_browser_version": 117, + "$initial_referrer": "$direct", + "$initial_referring_domain": "$direct" + }, + "$sent_at": "2023-10-20T11:05:16.465000+00:00", + "$geoip_city_name": "Sydney", + "$geoip_country_name": "Australia", + "$geoip_country_code": "AU", + "$geoip_continent_name": "Oceania", + "$geoip_continent_code": "OC", + "$geoip_postal_code": "2000", + "$geoip_latitude": -33.8715, + "$geoip_longitude": 151.2006, + "$geoip_time_zone": "Australia/Sydney", + "$geoip_subdivision_1_code": "NSW", + "$geoip_subdivision_1_name": "New South Wales", + "$plugins_succeeded": ["GeoIP (1)"], + "$plugins_failed": [], + "$plugins_deferred": [], + "$group_3": "018a92f8-b602-0000-75de-4b9073693531", + "$group_2": "018a92f8-afff-0000-efec-ca77de39e384", + "$group_4": "cus_OdSgxxWtHOtq9g", + "$group_1": "http://localhost:8000" + }, + "timestamp": "2023-10-20T11:05:13.602000+00:00", + "uuid": null + }, + { + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "elements": [], + "elements_chain": null, + "event": "insight refresh time", + "id": "018b4cc2-c10e-75bc-9275-189e47433d83", + "person": null, + "properties": { + "$os": "Mac OS X", + "$os_version": "10.15.7", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/home", + "$host": "localhost:8000", + "$pathname": "/home", + "$browser_version": 117, + "$browser_language": "en-GB", + "$screen_height": 982, + "$screen_width": 1512, + "$viewport_height": 859, + "$viewport_width": 1512, + "$lib": "web", + "$lib_version": "1.84.0", + "$insert_id": "c2ryrw33lz0vijd7", + "$time": 1697799913.743, + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$device_id": "018a92fd-7b25-7770-a050-577e94fd148c", + "$console_log_recording_enabled_server_side": true, + "$session_recording_recorder_version_server_side": "v2", + "$autocapture_disabled_server_side": false, + "$active_feature_flags": [ + "signup-page-4.0", + "cmd-k-search", + "posthog-3000", + "funnels-cue-opt-out-7301", + "retention-breakdown", + "smoothing-interval", + "billing-limit", + "kafka-inspector", + "historical-exports-v2", + "person-on-events-enabled", + "region-select", + "ingestion-warnings-enabled", + "session-reset-on-load", + "recordings-on-feature-flags", + "auto-rollback-feature-flags", + "onboarding-v2-demo", + "feature-flag-rollout-ux", + "role-based-access", + "query_running_time", + "query-timings", + "recording-debugging", + "enable-prompts", + "feedback-scene", + "early-access-feature", + "early-access-feature-site-button", + "hedgehog-mode-debug", + "auto-redirect", + "session-recording-blob-replay", + "surveys", + "generic-signup-benefits", + "surveys-positions", + "web-analytics", + "high-frequency-batch-exports", + "exception-autocapture", + "data-warehouse", + "data-warehouse-views", + "ff-dashboard-templates", + "show-product-intro-existing-products", + "artificial-hog", + "cs-dashboards", + "product-specific-onboarding", + "redirect-signups-to-instance", + "apps-and-exports-ui", + "survey-nps-results", + "session-recording-allow-v1-snapshots", + "session-replay-cors-proxy", + "webhooks-denylist", + "surveys-site-app-deprecation", + "surveys-multiple-questions", + "surveys-results-visualizations", + "console-recording-search", + "persons-hogql-query", + "notebooks" + ], + "$feature/file-previews": false, + "$feature/signup-page-4.0": "control", + "$feature/hogql-insights": false, + "$feature/cmd-k-search": true, + "$feature/posthog-3000": true, + "$feature/funnels-cue-opt-out-7301": true, + "$feature/retention-breakdown": true, + "$feature/smoothing-interval": true, + "$feature/billing-limit": true, + "$feature/kafka-inspector": true, + "$feature/historical-exports-v2": true, + "$feature/person-on-events-enabled": true, + "$feature/region-select": true, + "$feature/ingestion-warnings-enabled": true, + "$feature/session-reset-on-load": true, + "$feature/recordings-on-feature-flags": true, + "$feature/auto-rollback-feature-flags": true, + "$feature/onboarding-v2-demo": true, + "$feature/feature-flag-rollout-ux": true, + "$feature/role-based-access": true, + "$feature/query_running_time": true, + "$feature/query-timings": true, + "$feature/recording-debugging": true, + "$feature/enable-prompts": true, + "$feature/feedback-scene": true, + "$feature/early-access-feature": true, + "$feature/early-access-feature-site-button": true, + "$feature/hedgehog-mode-debug": true, + "$feature/auto-redirect": true, + "$feature/session-recording-blob-replay": true, + "$feature/surveys": true, + "$feature/generic-signup-benefits": true, + "$feature/surveys-positions": true, + "$feature/web-analytics": true, + "$feature/high-frequency-batch-exports": true, + "$feature/exception-autocapture": true, + "$feature/data-warehouse": true, + "$feature/data-warehouse-views": true, + "$feature/ff-dashboard-templates": true, + "$feature/show-product-intro-existing-products": true, + "$feature/artificial-hog": true, + "$feature/cs-dashboards": true, + "$feature/product-specific-onboarding": true, + "$feature/redirect-signups-to-instance": true, + "$feature/apps-and-exports-ui": true, + "$feature/survey-nps-results": true, + "$feature/session-recording-allow-v1-snapshots": true, + "$feature/session-replay-cors-proxy": true, + "$feature/webhooks-denylist": true, + "$feature/surveys-site-app-deprecation": true, + "$feature/surveys-multiple-questions": true, + "$feature/surveys-results-visualizations": true, + "$feature/console-recording-search": true, + "$feature/persons-hogql-query": true, + "$feature/notebooks": true, + "$feature_flag_payloads": {}, + "realm": "hosted-clickhouse", + "email_service_available": false, + "slack_service_available": false, + "$user_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "is_demo_project": false, + "$groups": { + "project": "018a92f8-b602-0000-75de-4b9073693531", + "organization": "018a92f8-afff-0000-efec-ca77de39e384", + "customer": "cus_OdSgxxWtHOtq9g", + "instance": "http://localhost:8000" + }, + "has_billing_plan": true, + "customer_deactivated": false, + "current_total_amount_usd": "0.00", + "percentage_usage.product_analytics": 0, + "current_amount_usd.product_analytics": "0.00", + "unit_amount_usd.product_analytics": null, + "usage_limit.product_analytics": null, + "current_usage.product_analytics": 3729, + "projected_usage.product_analytics": 0, + "free_allocation.product_analytics": 0, + "percentage_usage.session_replay": 0, + "current_amount_usd.session_replay": "0.00", + "unit_amount_usd.session_replay": null, + "usage_limit.session_replay": null, + "current_usage.session_replay": 254, + "projected_usage.session_replay": 0, + "free_allocation.session_replay": 0, + "percentage_usage.feature_flags": 0, + "current_amount_usd.feature_flags": "0.00", + "unit_amount_usd.feature_flags": null, + "usage_limit.feature_flags": null, + "current_usage.feature_flags": 0, + "projected_usage.feature_flags": 0, + "free_allocation.feature_flags": 0, + "percentage_usage.integrations": 0, + "current_amount_usd.integrations": null, + "unit_amount_usd.integrations": null, + "usage_limit.integrations": 0, + "current_usage.integrations": 0, + "projected_usage.integrations": 0, + "free_allocation.integrations": 0, + "percentage_usage.platform_and_support": 0, + "current_amount_usd.platform_and_support": null, + "unit_amount_usd.platform_and_support": null, + "usage_limit.platform_and_support": 0, + "current_usage.platform_and_support": 0, + "projected_usage.platform_and_support": 0, + "free_allocation.platform_and_support": 0, + "billing_period_start": "2023-10-14T09:22:33.000Z", + "billing_period_end": "2023-11-14T09:22:33.000Z", + "$referrer": "$direct", + "$referring_domain": "$direct", + "loadingMilliseconds": 1210, + "insightShortId": "gynVFet7", + "token": "phc_OWGI2wKbfi7rWDZT9wkl8uGcfe0wOGCvflLEZSMiaT0", + "$session_id": "018b4cc2-908b-7989-a77a-ae1396eef1de", + "$window_id": "018b4cc2-908b-7989-a77a-ae1465fa2118", + "$ip": "127.0.0.1", + "$set": { + "$os": "Mac OS X", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/home", + "$pathname": "/home", + "$browser_version": 117, + "$referrer": "$direct", + "$referring_domain": "$direct" + }, + "$set_once": { + "$initial_os": "Mac OS X", + "$initial_browser": "Chrome", + "$initial_device_type": "Desktop", + "$initial_current_url": "http://localhost:8000/home", + "$initial_pathname": "/home", + "$initial_browser_version": 117, + "$initial_referrer": "$direct", + "$initial_referring_domain": "$direct" + }, + "$sent_at": "2023-10-20T11:05:16.465000+00:00", + "$geoip_city_name": "Sydney", + "$geoip_country_name": "Australia", + "$geoip_country_code": "AU", + "$geoip_continent_name": "Oceania", + "$geoip_continent_code": "OC", + "$geoip_postal_code": "2000", + "$geoip_latitude": -33.8715, + "$geoip_longitude": 151.2006, + "$geoip_time_zone": "Australia/Sydney", + "$geoip_subdivision_1_code": "NSW", + "$geoip_subdivision_1_name": "New South Wales", + "$plugins_succeeded": ["GeoIP (1)"], + "$plugins_failed": [], + "$plugins_deferred": [], + "$group_3": "018a92f8-b602-0000-75de-4b9073693531", + "$group_2": "018a92f8-afff-0000-efec-ca77de39e384", + "$group_4": "cus_OdSgxxWtHOtq9g", + "$group_1": "http://localhost:8000" + }, + "timestamp": "2023-10-20T11:05:13.759000+00:00", + "uuid": null + }, + { + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "elements": [], + "elements_chain": null, + "event": "insight refresh time", + "id": "018b4cc2-c252-7c6f-b0d3-e2f321447b77", + "person": null, + "properties": { + "$os": "Mac OS X", + "$os_version": "10.15.7", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/home", + "$host": "localhost:8000", + "$pathname": "/home", + "$browser_version": 117, + "$browser_language": "en-GB", + "$screen_height": 982, + "$screen_width": 1512, + "$viewport_height": 859, + "$viewport_width": 1512, + "$lib": "web", + "$lib_version": "1.84.0", + "$insert_id": "u7298ffp3754ebcm", + "$time": 1697799914.066, + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$device_id": "018a92fd-7b25-7770-a050-577e94fd148c", + "$console_log_recording_enabled_server_side": true, + "$session_recording_recorder_version_server_side": "v2", + "$autocapture_disabled_server_side": false, + "$active_feature_flags": [ + "signup-page-4.0", + "cmd-k-search", + "posthog-3000", + "funnels-cue-opt-out-7301", + "retention-breakdown", + "smoothing-interval", + "billing-limit", + "kafka-inspector", + "historical-exports-v2", + "person-on-events-enabled", + "region-select", + "ingestion-warnings-enabled", + "session-reset-on-load", + "recordings-on-feature-flags", + "auto-rollback-feature-flags", + "onboarding-v2-demo", + "feature-flag-rollout-ux", + "role-based-access", + "query_running_time", + "query-timings", + "recording-debugging", + "enable-prompts", + "feedback-scene", + "early-access-feature", + "early-access-feature-site-button", + "hedgehog-mode-debug", + "auto-redirect", + "session-recording-blob-replay", + "surveys", + "generic-signup-benefits", + "surveys-positions", + "web-analytics", + "high-frequency-batch-exports", + "exception-autocapture", + "data-warehouse", + "data-warehouse-views", + "ff-dashboard-templates", + "show-product-intro-existing-products", + "artificial-hog", + "cs-dashboards", + "product-specific-onboarding", + "redirect-signups-to-instance", + "apps-and-exports-ui", + "survey-nps-results", + "session-recording-allow-v1-snapshots", + "session-replay-cors-proxy", + "webhooks-denylist", + "surveys-site-app-deprecation", + "surveys-multiple-questions", + "surveys-results-visualizations", + "console-recording-search", + "persons-hogql-query", + "notebooks" + ], + "$feature/file-previews": false, + "$feature/signup-page-4.0": "control", + "$feature/hogql-insights": false, + "$feature/cmd-k-search": true, + "$feature/posthog-3000": true, + "$feature/funnels-cue-opt-out-7301": true, + "$feature/retention-breakdown": true, + "$feature/smoothing-interval": true, + "$feature/billing-limit": true, + "$feature/kafka-inspector": true, + "$feature/historical-exports-v2": true, + "$feature/person-on-events-enabled": true, + "$feature/region-select": true, + "$feature/ingestion-warnings-enabled": true, + "$feature/session-reset-on-load": true, + "$feature/recordings-on-feature-flags": true, + "$feature/auto-rollback-feature-flags": true, + "$feature/onboarding-v2-demo": true, + "$feature/feature-flag-rollout-ux": true, + "$feature/role-based-access": true, + "$feature/query_running_time": true, + "$feature/query-timings": true, + "$feature/recording-debugging": true, + "$feature/enable-prompts": true, + "$feature/feedback-scene": true, + "$feature/early-access-feature": true, + "$feature/early-access-feature-site-button": true, + "$feature/hedgehog-mode-debug": true, + "$feature/auto-redirect": true, + "$feature/session-recording-blob-replay": true, + "$feature/surveys": true, + "$feature/generic-signup-benefits": true, + "$feature/surveys-positions": true, + "$feature/web-analytics": true, + "$feature/high-frequency-batch-exports": true, + "$feature/exception-autocapture": true, + "$feature/data-warehouse": true, + "$feature/data-warehouse-views": true, + "$feature/ff-dashboard-templates": true, + "$feature/show-product-intro-existing-products": true, + "$feature/artificial-hog": true, + "$feature/cs-dashboards": true, + "$feature/product-specific-onboarding": true, + "$feature/redirect-signups-to-instance": true, + "$feature/apps-and-exports-ui": true, + "$feature/survey-nps-results": true, + "$feature/session-recording-allow-v1-snapshots": true, + "$feature/session-replay-cors-proxy": true, + "$feature/webhooks-denylist": true, + "$feature/surveys-site-app-deprecation": true, + "$feature/surveys-multiple-questions": true, + "$feature/surveys-results-visualizations": true, + "$feature/console-recording-search": true, + "$feature/persons-hogql-query": true, + "$feature/notebooks": true, + "$feature_flag_payloads": {}, + "realm": "hosted-clickhouse", + "email_service_available": false, + "slack_service_available": false, + "$user_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "is_demo_project": false, + "$groups": { + "project": "018a92f8-b602-0000-75de-4b9073693531", + "organization": "018a92f8-afff-0000-efec-ca77de39e384", + "customer": "cus_OdSgxxWtHOtq9g", + "instance": "http://localhost:8000" + }, + "has_billing_plan": true, + "customer_deactivated": false, + "current_total_amount_usd": "0.00", + "percentage_usage.product_analytics": 0, + "current_amount_usd.product_analytics": "0.00", + "unit_amount_usd.product_analytics": null, + "usage_limit.product_analytics": null, + "current_usage.product_analytics": 3729, + "projected_usage.product_analytics": 0, + "free_allocation.product_analytics": 0, + "percentage_usage.session_replay": 0, + "current_amount_usd.session_replay": "0.00", + "unit_amount_usd.session_replay": null, + "usage_limit.session_replay": null, + "current_usage.session_replay": 254, + "projected_usage.session_replay": 0, + "free_allocation.session_replay": 0, + "percentage_usage.feature_flags": 0, + "current_amount_usd.feature_flags": "0.00", + "unit_amount_usd.feature_flags": null, + "usage_limit.feature_flags": null, + "current_usage.feature_flags": 0, + "projected_usage.feature_flags": 0, + "free_allocation.feature_flags": 0, + "percentage_usage.integrations": 0, + "current_amount_usd.integrations": null, + "unit_amount_usd.integrations": null, + "usage_limit.integrations": 0, + "current_usage.integrations": 0, + "projected_usage.integrations": 0, + "free_allocation.integrations": 0, + "percentage_usage.platform_and_support": 0, + "current_amount_usd.platform_and_support": null, + "unit_amount_usd.platform_and_support": null, + "usage_limit.platform_and_support": 0, + "current_usage.platform_and_support": 0, + "projected_usage.platform_and_support": 0, + "free_allocation.platform_and_support": 0, + "billing_period_start": "2023-10-14T09:22:33.000Z", + "billing_period_end": "2023-11-14T09:22:33.000Z", + "$referrer": "$direct", + "$referring_domain": "$direct", + "loadingMilliseconds": 1534, + "insightShortId": "XijxpxgK", + "token": "phc_OWGI2wKbfi7rWDZT9wkl8uGcfe0wOGCvflLEZSMiaT0", + "$session_id": "018b4cc2-908b-7989-a77a-ae1396eef1de", + "$window_id": "018b4cc2-908b-7989-a77a-ae1465fa2118", + "$ip": "127.0.0.1", + "$set": { + "$os": "Mac OS X", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/home", + "$pathname": "/home", + "$browser_version": 117, + "$referrer": "$direct", + "$referring_domain": "$direct" + }, + "$set_once": { + "$initial_os": "Mac OS X", + "$initial_browser": "Chrome", + "$initial_device_type": "Desktop", + "$initial_current_url": "http://localhost:8000/home", + "$initial_pathname": "/home", + "$initial_browser_version": 117, + "$initial_referrer": "$direct", + "$initial_referring_domain": "$direct" + }, + "$sent_at": "2023-10-20T11:05:16.465000+00:00", + "$geoip_city_name": "Sydney", + "$geoip_country_name": "Australia", + "$geoip_country_code": "AU", + "$geoip_continent_name": "Oceania", + "$geoip_continent_code": "OC", + "$geoip_postal_code": "2000", + "$geoip_latitude": -33.8715, + "$geoip_longitude": 151.2006, + "$geoip_time_zone": "Australia/Sydney", + "$geoip_subdivision_1_code": "NSW", + "$geoip_subdivision_1_name": "New South Wales", + "$plugins_succeeded": ["GeoIP (1)"], + "$plugins_failed": [], + "$plugins_deferred": [], + "$group_3": "018a92f8-b602-0000-75de-4b9073693531", + "$group_2": "018a92f8-afff-0000-efec-ca77de39e384", + "$group_4": "cus_OdSgxxWtHOtq9g", + "$group_1": "http://localhost:8000" + }, + "timestamp": "2023-10-20T11:05:14.082000+00:00", + "uuid": null + }, + { + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "elements": [], + "elements_chain": null, + "event": "insight refresh time", + "id": "018b4cc2-c3c4-7ea1-8759-3043985f1e2a", + "person": null, + "properties": { + "$os": "Mac OS X", + "$os_version": "10.15.7", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/home", + "$host": "localhost:8000", + "$pathname": "/home", + "$browser_version": 117, + "$browser_language": "en-GB", + "$screen_height": 982, + "$screen_width": 1512, + "$viewport_height": 859, + "$viewport_width": 1512, + "$lib": "web", + "$lib_version": "1.84.0", + "$insert_id": "sij6r7mjdn0dkglr", + "$time": 1697799914.436, + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$device_id": "018a92fd-7b25-7770-a050-577e94fd148c", + "$console_log_recording_enabled_server_side": true, + "$session_recording_recorder_version_server_side": "v2", + "$autocapture_disabled_server_side": false, + "$active_feature_flags": [ + "signup-page-4.0", + "cmd-k-search", + "posthog-3000", + "funnels-cue-opt-out-7301", + "retention-breakdown", + "smoothing-interval", + "billing-limit", + "kafka-inspector", + "historical-exports-v2", + "person-on-events-enabled", + "region-select", + "ingestion-warnings-enabled", + "session-reset-on-load", + "recordings-on-feature-flags", + "auto-rollback-feature-flags", + "onboarding-v2-demo", + "feature-flag-rollout-ux", + "role-based-access", + "query_running_time", + "query-timings", + "recording-debugging", + "enable-prompts", + "feedback-scene", + "early-access-feature", + "early-access-feature-site-button", + "hedgehog-mode-debug", + "auto-redirect", + "session-recording-blob-replay", + "surveys", + "generic-signup-benefits", + "surveys-positions", + "web-analytics", + "high-frequency-batch-exports", + "exception-autocapture", + "data-warehouse", + "data-warehouse-views", + "ff-dashboard-templates", + "show-product-intro-existing-products", + "artificial-hog", + "cs-dashboards", + "product-specific-onboarding", + "redirect-signups-to-instance", + "apps-and-exports-ui", + "survey-nps-results", + "session-recording-allow-v1-snapshots", + "session-replay-cors-proxy", + "webhooks-denylist", + "surveys-site-app-deprecation", + "surveys-multiple-questions", + "surveys-results-visualizations", + "console-recording-search", + "persons-hogql-query", + "notebooks" + ], + "$feature/file-previews": false, + "$feature/signup-page-4.0": "control", + "$feature/hogql-insights": false, + "$feature/cmd-k-search": true, + "$feature/posthog-3000": true, + "$feature/funnels-cue-opt-out-7301": true, + "$feature/retention-breakdown": true, + "$feature/smoothing-interval": true, + "$feature/billing-limit": true, + "$feature/kafka-inspector": true, + "$feature/historical-exports-v2": true, + "$feature/person-on-events-enabled": true, + "$feature/region-select": true, + "$feature/ingestion-warnings-enabled": true, + "$feature/session-reset-on-load": true, + "$feature/recordings-on-feature-flags": true, + "$feature/auto-rollback-feature-flags": true, + "$feature/onboarding-v2-demo": true, + "$feature/feature-flag-rollout-ux": true, + "$feature/role-based-access": true, + "$feature/query_running_time": true, + "$feature/query-timings": true, + "$feature/recording-debugging": true, + "$feature/enable-prompts": true, + "$feature/feedback-scene": true, + "$feature/early-access-feature": true, + "$feature/early-access-feature-site-button": true, + "$feature/hedgehog-mode-debug": true, + "$feature/auto-redirect": true, + "$feature/session-recording-blob-replay": true, + "$feature/surveys": true, + "$feature/generic-signup-benefits": true, + "$feature/surveys-positions": true, + "$feature/web-analytics": true, + "$feature/high-frequency-batch-exports": true, + "$feature/exception-autocapture": true, + "$feature/data-warehouse": true, + "$feature/data-warehouse-views": true, + "$feature/ff-dashboard-templates": true, + "$feature/show-product-intro-existing-products": true, + "$feature/artificial-hog": true, + "$feature/cs-dashboards": true, + "$feature/product-specific-onboarding": true, + "$feature/redirect-signups-to-instance": true, + "$feature/apps-and-exports-ui": true, + "$feature/survey-nps-results": true, + "$feature/session-recording-allow-v1-snapshots": true, + "$feature/session-replay-cors-proxy": true, + "$feature/webhooks-denylist": true, + "$feature/surveys-site-app-deprecation": true, + "$feature/surveys-multiple-questions": true, + "$feature/surveys-results-visualizations": true, + "$feature/console-recording-search": true, + "$feature/persons-hogql-query": true, + "$feature/notebooks": true, + "$feature_flag_payloads": {}, + "realm": "hosted-clickhouse", + "email_service_available": false, + "slack_service_available": false, + "$user_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "is_demo_project": false, + "$groups": { + "project": "018a92f8-b602-0000-75de-4b9073693531", + "organization": "018a92f8-afff-0000-efec-ca77de39e384", + "customer": "cus_OdSgxxWtHOtq9g", + "instance": "http://localhost:8000" + }, + "has_billing_plan": true, + "customer_deactivated": false, + "current_total_amount_usd": "0.00", + "percentage_usage.product_analytics": 0, + "current_amount_usd.product_analytics": "0.00", + "unit_amount_usd.product_analytics": null, + "usage_limit.product_analytics": null, + "current_usage.product_analytics": 3729, + "projected_usage.product_analytics": 0, + "free_allocation.product_analytics": 0, + "percentage_usage.session_replay": 0, + "current_amount_usd.session_replay": "0.00", + "unit_amount_usd.session_replay": null, + "usage_limit.session_replay": null, + "current_usage.session_replay": 254, + "projected_usage.session_replay": 0, + "free_allocation.session_replay": 0, + "percentage_usage.feature_flags": 0, + "current_amount_usd.feature_flags": "0.00", + "unit_amount_usd.feature_flags": null, + "usage_limit.feature_flags": null, + "current_usage.feature_flags": 0, + "projected_usage.feature_flags": 0, + "free_allocation.feature_flags": 0, + "percentage_usage.integrations": 0, + "current_amount_usd.integrations": null, + "unit_amount_usd.integrations": null, + "usage_limit.integrations": 0, + "current_usage.integrations": 0, + "projected_usage.integrations": 0, + "free_allocation.integrations": 0, + "percentage_usage.platform_and_support": 0, + "current_amount_usd.platform_and_support": null, + "unit_amount_usd.platform_and_support": null, + "usage_limit.platform_and_support": 0, + "current_usage.platform_and_support": 0, + "projected_usage.platform_and_support": 0, + "free_allocation.platform_and_support": 0, + "billing_period_start": "2023-10-14T09:22:33.000Z", + "billing_period_end": "2023-11-14T09:22:33.000Z", + "$referrer": "$direct", + "$referring_domain": "$direct", + "loadingMilliseconds": 1904, + "insightShortId": "12cRYEnk", + "token": "phc_OWGI2wKbfi7rWDZT9wkl8uGcfe0wOGCvflLEZSMiaT0", + "$session_id": "018b4cc2-908b-7989-a77a-ae1396eef1de", + "$window_id": "018b4cc2-908b-7989-a77a-ae1465fa2118", + "$ip": "127.0.0.1", + "$set": { + "$os": "Mac OS X", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/home", + "$pathname": "/home", + "$browser_version": 117, + "$referrer": "$direct", + "$referring_domain": "$direct" + }, + "$set_once": { + "$initial_os": "Mac OS X", + "$initial_browser": "Chrome", + "$initial_device_type": "Desktop", + "$initial_current_url": "http://localhost:8000/home", + "$initial_pathname": "/home", + "$initial_browser_version": 117, + "$initial_referrer": "$direct", + "$initial_referring_domain": "$direct" + }, + "$sent_at": "2023-10-20T11:05:16.465000+00:00", + "$geoip_city_name": "Sydney", + "$geoip_country_name": "Australia", + "$geoip_country_code": "AU", + "$geoip_continent_name": "Oceania", + "$geoip_continent_code": "OC", + "$geoip_postal_code": "2000", + "$geoip_latitude": -33.8715, + "$geoip_longitude": 151.2006, + "$geoip_time_zone": "Australia/Sydney", + "$geoip_subdivision_1_code": "NSW", + "$geoip_subdivision_1_name": "New South Wales", + "$plugins_succeeded": ["GeoIP (1)"], + "$plugins_failed": [], + "$plugins_deferred": [], + "$group_3": "018a92f8-b602-0000-75de-4b9073693531", + "$group_2": "018a92f8-afff-0000-efec-ca77de39e384", + "$group_4": "cus_OdSgxxWtHOtq9g", + "$group_1": "http://localhost:8000" + }, + "timestamp": "2023-10-20T11:05:14.453000+00:00", + "uuid": null + }, + { + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "elements": [], + "elements_chain": null, + "event": "insight refresh time", + "id": "018b4cc2-c4f5-77be-993e-9d88a05d46f8", + "person": null, + "properties": { + "$os": "Mac OS X", + "$os_version": "10.15.7", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/home", + "$host": "localhost:8000", + "$pathname": "/home", + "$browser_version": 117, + "$browser_language": "en-GB", + "$screen_height": 982, + "$screen_width": 1512, + "$viewport_height": 859, + "$viewport_width": 1512, + "$lib": "web", + "$lib_version": "1.84.0", + "$insert_id": "gh9axm48pflzlu2l", + "$time": 1697799914.742, + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$device_id": "018a92fd-7b25-7770-a050-577e94fd148c", + "$console_log_recording_enabled_server_side": true, + "$session_recording_recorder_version_server_side": "v2", + "$autocapture_disabled_server_side": false, + "$active_feature_flags": [ + "signup-page-4.0", + "cmd-k-search", + "posthog-3000", + "funnels-cue-opt-out-7301", + "retention-breakdown", + "smoothing-interval", + "billing-limit", + "kafka-inspector", + "historical-exports-v2", + "person-on-events-enabled", + "region-select", + "ingestion-warnings-enabled", + "session-reset-on-load", + "recordings-on-feature-flags", + "auto-rollback-feature-flags", + "onboarding-v2-demo", + "feature-flag-rollout-ux", + "role-based-access", + "query_running_time", + "query-timings", + "recording-debugging", + "enable-prompts", + "feedback-scene", + "early-access-feature", + "early-access-feature-site-button", + "hedgehog-mode-debug", + "auto-redirect", + "session-recording-blob-replay", + "surveys", + "generic-signup-benefits", + "surveys-positions", + "web-analytics", + "high-frequency-batch-exports", + "exception-autocapture", + "data-warehouse", + "data-warehouse-views", + "ff-dashboard-templates", + "show-product-intro-existing-products", + "artificial-hog", + "cs-dashboards", + "product-specific-onboarding", + "redirect-signups-to-instance", + "apps-and-exports-ui", + "survey-nps-results", + "session-recording-allow-v1-snapshots", + "session-replay-cors-proxy", + "webhooks-denylist", + "surveys-site-app-deprecation", + "surveys-multiple-questions", + "surveys-results-visualizations", + "console-recording-search", + "persons-hogql-query", + "notebooks" + ], + "$feature/file-previews": false, + "$feature/signup-page-4.0": "control", + "$feature/hogql-insights": false, + "$feature/cmd-k-search": true, + "$feature/posthog-3000": true, + "$feature/funnels-cue-opt-out-7301": true, + "$feature/retention-breakdown": true, + "$feature/smoothing-interval": true, + "$feature/billing-limit": true, + "$feature/kafka-inspector": true, + "$feature/historical-exports-v2": true, + "$feature/person-on-events-enabled": true, + "$feature/region-select": true, + "$feature/ingestion-warnings-enabled": true, + "$feature/session-reset-on-load": true, + "$feature/recordings-on-feature-flags": true, + "$feature/auto-rollback-feature-flags": true, + "$feature/onboarding-v2-demo": true, + "$feature/feature-flag-rollout-ux": true, + "$feature/role-based-access": true, + "$feature/query_running_time": true, + "$feature/query-timings": true, + "$feature/recording-debugging": true, + "$feature/enable-prompts": true, + "$feature/feedback-scene": true, + "$feature/early-access-feature": true, + "$feature/early-access-feature-site-button": true, + "$feature/hedgehog-mode-debug": true, + "$feature/auto-redirect": true, + "$feature/session-recording-blob-replay": true, + "$feature/surveys": true, + "$feature/generic-signup-benefits": true, + "$feature/surveys-positions": true, + "$feature/web-analytics": true, + "$feature/high-frequency-batch-exports": true, + "$feature/exception-autocapture": true, + "$feature/data-warehouse": true, + "$feature/data-warehouse-views": true, + "$feature/ff-dashboard-templates": true, + "$feature/show-product-intro-existing-products": true, + "$feature/artificial-hog": true, + "$feature/cs-dashboards": true, + "$feature/product-specific-onboarding": true, + "$feature/redirect-signups-to-instance": true, + "$feature/apps-and-exports-ui": true, + "$feature/survey-nps-results": true, + "$feature/session-recording-allow-v1-snapshots": true, + "$feature/session-replay-cors-proxy": true, + "$feature/webhooks-denylist": true, + "$feature/surveys-site-app-deprecation": true, + "$feature/surveys-multiple-questions": true, + "$feature/surveys-results-visualizations": true, + "$feature/console-recording-search": true, + "$feature/persons-hogql-query": true, + "$feature/notebooks": true, + "$feature_flag_payloads": {}, + "realm": "hosted-clickhouse", + "email_service_available": false, + "slack_service_available": false, + "$user_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "is_demo_project": false, + "$groups": { + "project": "018a92f8-b602-0000-75de-4b9073693531", + "organization": "018a92f8-afff-0000-efec-ca77de39e384", + "customer": "cus_OdSgxxWtHOtq9g", + "instance": "http://localhost:8000" + }, + "has_billing_plan": true, + "customer_deactivated": false, + "current_total_amount_usd": "0.00", + "percentage_usage.product_analytics": 0, + "current_amount_usd.product_analytics": "0.00", + "unit_amount_usd.product_analytics": null, + "usage_limit.product_analytics": null, + "current_usage.product_analytics": 3729, + "projected_usage.product_analytics": 0, + "free_allocation.product_analytics": 0, + "percentage_usage.session_replay": 0, + "current_amount_usd.session_replay": "0.00", + "unit_amount_usd.session_replay": null, + "usage_limit.session_replay": null, + "current_usage.session_replay": 254, + "projected_usage.session_replay": 0, + "free_allocation.session_replay": 0, + "percentage_usage.feature_flags": 0, + "current_amount_usd.feature_flags": "0.00", + "unit_amount_usd.feature_flags": null, + "usage_limit.feature_flags": null, + "current_usage.feature_flags": 0, + "projected_usage.feature_flags": 0, + "free_allocation.feature_flags": 0, + "percentage_usage.integrations": 0, + "current_amount_usd.integrations": null, + "unit_amount_usd.integrations": null, + "usage_limit.integrations": 0, + "current_usage.integrations": 0, + "projected_usage.integrations": 0, + "free_allocation.integrations": 0, + "percentage_usage.platform_and_support": 0, + "current_amount_usd.platform_and_support": null, + "unit_amount_usd.platform_and_support": null, + "usage_limit.platform_and_support": 0, + "current_usage.platform_and_support": 0, + "projected_usage.platform_and_support": 0, + "free_allocation.platform_and_support": 0, + "billing_period_start": "2023-10-14T09:22:33.000Z", + "billing_period_end": "2023-11-14T09:22:33.000Z", + "$referrer": "$direct", + "$referring_domain": "$direct", + "loadingMilliseconds": 2209, + "insightShortId": "VRqTSTUU", + "token": "phc_OWGI2wKbfi7rWDZT9wkl8uGcfe0wOGCvflLEZSMiaT0", + "$session_id": "018b4cc2-908b-7989-a77a-ae1396eef1de", + "$window_id": "018b4cc2-908b-7989-a77a-ae1465fa2118", + "$ip": "127.0.0.1", + "$set": { + "$os": "Mac OS X", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/home", + "$pathname": "/home", + "$browser_version": 117, + "$referrer": "$direct", + "$referring_domain": "$direct" + }, + "$set_once": { + "$initial_os": "Mac OS X", + "$initial_browser": "Chrome", + "$initial_device_type": "Desktop", + "$initial_current_url": "http://localhost:8000/home", + "$initial_pathname": "/home", + "$initial_browser_version": 117, + "$initial_referrer": "$direct", + "$initial_referring_domain": "$direct" + }, + "$sent_at": "2023-10-20T11:05:16.465000+00:00", + "$geoip_city_name": "Sydney", + "$geoip_country_name": "Australia", + "$geoip_country_code": "AU", + "$geoip_continent_name": "Oceania", + "$geoip_continent_code": "OC", + "$geoip_postal_code": "2000", + "$geoip_latitude": -33.8715, + "$geoip_longitude": 151.2006, + "$geoip_time_zone": "Australia/Sydney", + "$geoip_subdivision_1_code": "NSW", + "$geoip_subdivision_1_name": "New South Wales", + "$plugins_succeeded": ["GeoIP (1)"], + "$plugins_failed": [], + "$plugins_deferred": [], + "$group_3": "018a92f8-b602-0000-75de-4b9073693531", + "$group_2": "018a92f8-afff-0000-efec-ca77de39e384", + "$group_4": "cus_OdSgxxWtHOtq9g", + "$group_1": "http://localhost:8000" + }, + "timestamp": "2023-10-20T11:05:14.758000+00:00", + "uuid": null + }, + { + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "elements": [], + "elements_chain": null, + "event": "insight refresh time", + "id": "018b4cc2-c5f7-7ff9-ac9c-9b0b7d7fcf7b", + "person": null, + "properties": { + "$os": "Mac OS X", + "$os_version": "10.15.7", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/home", + "$host": "localhost:8000", + "$pathname": "/home", + "$browser_version": 117, + "$browser_language": "en-GB", + "$screen_height": 982, + "$screen_width": 1512, + "$viewport_height": 859, + "$viewport_width": 1512, + "$lib": "web", + "$lib_version": "1.84.0", + "$insert_id": "sshoh198v54qzg5s", + "$time": 1697799914.999, + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$device_id": "018a92fd-7b25-7770-a050-577e94fd148c", + "$console_log_recording_enabled_server_side": true, + "$session_recording_recorder_version_server_side": "v2", + "$autocapture_disabled_server_side": false, + "$active_feature_flags": [ + "signup-page-4.0", + "cmd-k-search", + "posthog-3000", + "funnels-cue-opt-out-7301", + "retention-breakdown", + "smoothing-interval", + "billing-limit", + "kafka-inspector", + "historical-exports-v2", + "person-on-events-enabled", + "region-select", + "ingestion-warnings-enabled", + "session-reset-on-load", + "recordings-on-feature-flags", + "auto-rollback-feature-flags", + "onboarding-v2-demo", + "feature-flag-rollout-ux", + "role-based-access", + "query_running_time", + "query-timings", + "recording-debugging", + "enable-prompts", + "feedback-scene", + "early-access-feature", + "early-access-feature-site-button", + "hedgehog-mode-debug", + "auto-redirect", + "session-recording-blob-replay", + "surveys", + "generic-signup-benefits", + "surveys-positions", + "web-analytics", + "high-frequency-batch-exports", + "exception-autocapture", + "data-warehouse", + "data-warehouse-views", + "ff-dashboard-templates", + "show-product-intro-existing-products", + "artificial-hog", + "cs-dashboards", + "product-specific-onboarding", + "redirect-signups-to-instance", + "apps-and-exports-ui", + "survey-nps-results", + "session-recording-allow-v1-snapshots", + "session-replay-cors-proxy", + "webhooks-denylist", + "surveys-site-app-deprecation", + "surveys-multiple-questions", + "surveys-results-visualizations", + "console-recording-search", + "persons-hogql-query", + "notebooks" + ], + "$feature/file-previews": false, + "$feature/signup-page-4.0": "control", + "$feature/hogql-insights": false, + "$feature/cmd-k-search": true, + "$feature/posthog-3000": true, + "$feature/funnels-cue-opt-out-7301": true, + "$feature/retention-breakdown": true, + "$feature/smoothing-interval": true, + "$feature/billing-limit": true, + "$feature/kafka-inspector": true, + "$feature/historical-exports-v2": true, + "$feature/person-on-events-enabled": true, + "$feature/region-select": true, + "$feature/ingestion-warnings-enabled": true, + "$feature/session-reset-on-load": true, + "$feature/recordings-on-feature-flags": true, + "$feature/auto-rollback-feature-flags": true, + "$feature/onboarding-v2-demo": true, + "$feature/feature-flag-rollout-ux": true, + "$feature/role-based-access": true, + "$feature/query_running_time": true, + "$feature/query-timings": true, + "$feature/recording-debugging": true, + "$feature/enable-prompts": true, + "$feature/feedback-scene": true, + "$feature/early-access-feature": true, + "$feature/early-access-feature-site-button": true, + "$feature/hedgehog-mode-debug": true, + "$feature/auto-redirect": true, + "$feature/session-recording-blob-replay": true, + "$feature/surveys": true, + "$feature/generic-signup-benefits": true, + "$feature/surveys-positions": true, + "$feature/web-analytics": true, + "$feature/high-frequency-batch-exports": true, + "$feature/exception-autocapture": true, + "$feature/data-warehouse": true, + "$feature/data-warehouse-views": true, + "$feature/ff-dashboard-templates": true, + "$feature/show-product-intro-existing-products": true, + "$feature/artificial-hog": true, + "$feature/cs-dashboards": true, + "$feature/product-specific-onboarding": true, + "$feature/redirect-signups-to-instance": true, + "$feature/apps-and-exports-ui": true, + "$feature/survey-nps-results": true, + "$feature/session-recording-allow-v1-snapshots": true, + "$feature/session-replay-cors-proxy": true, + "$feature/webhooks-denylist": true, + "$feature/surveys-site-app-deprecation": true, + "$feature/surveys-multiple-questions": true, + "$feature/surveys-results-visualizations": true, + "$feature/console-recording-search": true, + "$feature/persons-hogql-query": true, + "$feature/notebooks": true, + "$feature_flag_payloads": {}, + "realm": "hosted-clickhouse", + "email_service_available": false, + "slack_service_available": false, + "$user_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "is_demo_project": false, + "$groups": { + "project": "018a92f8-b602-0000-75de-4b9073693531", + "organization": "018a92f8-afff-0000-efec-ca77de39e384", + "customer": "cus_OdSgxxWtHOtq9g", + "instance": "http://localhost:8000" + }, + "has_billing_plan": true, + "customer_deactivated": false, + "current_total_amount_usd": "0.00", + "percentage_usage.product_analytics": 0, + "current_amount_usd.product_analytics": "0.00", + "unit_amount_usd.product_analytics": null, + "usage_limit.product_analytics": null, + "current_usage.product_analytics": 3729, + "projected_usage.product_analytics": 0, + "free_allocation.product_analytics": 0, + "percentage_usage.session_replay": 0, + "current_amount_usd.session_replay": "0.00", + "unit_amount_usd.session_replay": null, + "usage_limit.session_replay": null, + "current_usage.session_replay": 254, + "projected_usage.session_replay": 0, + "free_allocation.session_replay": 0, + "percentage_usage.feature_flags": 0, + "current_amount_usd.feature_flags": "0.00", + "unit_amount_usd.feature_flags": null, + "usage_limit.feature_flags": null, + "current_usage.feature_flags": 0, + "projected_usage.feature_flags": 0, + "free_allocation.feature_flags": 0, + "percentage_usage.integrations": 0, + "current_amount_usd.integrations": null, + "unit_amount_usd.integrations": null, + "usage_limit.integrations": 0, + "current_usage.integrations": 0, + "projected_usage.integrations": 0, + "free_allocation.integrations": 0, + "percentage_usage.platform_and_support": 0, + "current_amount_usd.platform_and_support": null, + "unit_amount_usd.platform_and_support": null, + "usage_limit.platform_and_support": 0, + "current_usage.platform_and_support": 0, + "projected_usage.platform_and_support": 0, + "free_allocation.platform_and_support": 0, + "billing_period_start": "2023-10-14T09:22:33.000Z", + "billing_period_end": "2023-11-14T09:22:33.000Z", + "$referrer": "$direct", + "$referring_domain": "$direct", + "loadingMilliseconds": 2466, + "insightShortId": "X4vwqdC6", + "token": "phc_OWGI2wKbfi7rWDZT9wkl8uGcfe0wOGCvflLEZSMiaT0", + "$session_id": "018b4cc2-908b-7989-a77a-ae1396eef1de", + "$window_id": "018b4cc2-908b-7989-a77a-ae1465fa2118", + "$ip": "127.0.0.1", + "$set": { + "$os": "Mac OS X", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/home", + "$pathname": "/home", + "$browser_version": 117, + "$referrer": "$direct", + "$referring_domain": "$direct" + }, + "$set_once": { + "$initial_os": "Mac OS X", + "$initial_browser": "Chrome", + "$initial_device_type": "Desktop", + "$initial_current_url": "http://localhost:8000/home", + "$initial_pathname": "/home", + "$initial_browser_version": 117, + "$initial_referrer": "$direct", + "$initial_referring_domain": "$direct" + }, + "$sent_at": "2023-10-20T11:05:16.465000+00:00", + "$geoip_city_name": "Sydney", + "$geoip_country_name": "Australia", + "$geoip_country_code": "AU", + "$geoip_continent_name": "Oceania", + "$geoip_continent_code": "OC", + "$geoip_postal_code": "2000", + "$geoip_latitude": -33.8715, + "$geoip_longitude": 151.2006, + "$geoip_time_zone": "Australia/Sydney", + "$geoip_subdivision_1_code": "NSW", + "$geoip_subdivision_1_name": "New South Wales", + "$plugins_succeeded": ["GeoIP (1)"], + "$plugins_failed": [], + "$plugins_deferred": [], + "$group_3": "018a92f8-b602-0000-75de-4b9073693531", + "$group_2": "018a92f8-afff-0000-efec-ca77de39e384", + "$group_4": "cus_OdSgxxWtHOtq9g", + "$group_1": "http://localhost:8000" + }, + "timestamp": "2023-10-20T11:05:15.015000+00:00", + "uuid": null + }, + { + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "elements": [], + "elements_chain": null, + "event": "insight refresh time", + "id": "018b4cc2-c6f4-7638-b108-639ce32e1062", + "person": null, + "properties": { + "$os": "Mac OS X", + "$os_version": "10.15.7", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/home", + "$host": "localhost:8000", + "$pathname": "/home", + "$browser_version": 117, + "$browser_language": "en-GB", + "$screen_height": 982, + "$screen_width": 1512, + "$viewport_height": 859, + "$viewport_width": 1512, + "$lib": "web", + "$lib_version": "1.84.0", + "$insert_id": "45hmgrym77londxt", + "$time": 1697799915.253, + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$device_id": "018a92fd-7b25-7770-a050-577e94fd148c", + "$console_log_recording_enabled_server_side": true, + "$session_recording_recorder_version_server_side": "v2", + "$autocapture_disabled_server_side": false, + "$active_feature_flags": [ + "signup-page-4.0", + "cmd-k-search", + "posthog-3000", + "funnels-cue-opt-out-7301", + "retention-breakdown", + "smoothing-interval", + "billing-limit", + "kafka-inspector", + "historical-exports-v2", + "person-on-events-enabled", + "region-select", + "ingestion-warnings-enabled", + "session-reset-on-load", + "recordings-on-feature-flags", + "auto-rollback-feature-flags", + "onboarding-v2-demo", + "feature-flag-rollout-ux", + "role-based-access", + "query_running_time", + "query-timings", + "recording-debugging", + "enable-prompts", + "feedback-scene", + "early-access-feature", + "early-access-feature-site-button", + "hedgehog-mode-debug", + "auto-redirect", + "session-recording-blob-replay", + "surveys", + "generic-signup-benefits", + "surveys-positions", + "web-analytics", + "high-frequency-batch-exports", + "exception-autocapture", + "data-warehouse", + "data-warehouse-views", + "ff-dashboard-templates", + "show-product-intro-existing-products", + "artificial-hog", + "cs-dashboards", + "product-specific-onboarding", + "redirect-signups-to-instance", + "apps-and-exports-ui", + "survey-nps-results", + "session-recording-allow-v1-snapshots", + "session-replay-cors-proxy", + "webhooks-denylist", + "surveys-site-app-deprecation", + "surveys-multiple-questions", + "surveys-results-visualizations", + "console-recording-search", + "persons-hogql-query", + "notebooks" + ], + "$feature/file-previews": false, + "$feature/signup-page-4.0": "control", + "$feature/hogql-insights": false, + "$feature/cmd-k-search": true, + "$feature/posthog-3000": true, + "$feature/funnels-cue-opt-out-7301": true, + "$feature/retention-breakdown": true, + "$feature/smoothing-interval": true, + "$feature/billing-limit": true, + "$feature/kafka-inspector": true, + "$feature/historical-exports-v2": true, + "$feature/person-on-events-enabled": true, + "$feature/region-select": true, + "$feature/ingestion-warnings-enabled": true, + "$feature/session-reset-on-load": true, + "$feature/recordings-on-feature-flags": true, + "$feature/auto-rollback-feature-flags": true, + "$feature/onboarding-v2-demo": true, + "$feature/feature-flag-rollout-ux": true, + "$feature/role-based-access": true, + "$feature/query_running_time": true, + "$feature/query-timings": true, + "$feature/recording-debugging": true, + "$feature/enable-prompts": true, + "$feature/feedback-scene": true, + "$feature/early-access-feature": true, + "$feature/early-access-feature-site-button": true, + "$feature/hedgehog-mode-debug": true, + "$feature/auto-redirect": true, + "$feature/session-recording-blob-replay": true, + "$feature/surveys": true, + "$feature/generic-signup-benefits": true, + "$feature/surveys-positions": true, + "$feature/web-analytics": true, + "$feature/high-frequency-batch-exports": true, + "$feature/exception-autocapture": true, + "$feature/data-warehouse": true, + "$feature/data-warehouse-views": true, + "$feature/ff-dashboard-templates": true, + "$feature/show-product-intro-existing-products": true, + "$feature/artificial-hog": true, + "$feature/cs-dashboards": true, + "$feature/product-specific-onboarding": true, + "$feature/redirect-signups-to-instance": true, + "$feature/apps-and-exports-ui": true, + "$feature/survey-nps-results": true, + "$feature/session-recording-allow-v1-snapshots": true, + "$feature/session-replay-cors-proxy": true, + "$feature/webhooks-denylist": true, + "$feature/surveys-site-app-deprecation": true, + "$feature/surveys-multiple-questions": true, + "$feature/surveys-results-visualizations": true, + "$feature/console-recording-search": true, + "$feature/persons-hogql-query": true, + "$feature/notebooks": true, + "$feature_flag_payloads": {}, + "realm": "hosted-clickhouse", + "email_service_available": false, + "slack_service_available": false, + "$user_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "is_demo_project": false, + "$groups": { + "project": "018a92f8-b602-0000-75de-4b9073693531", + "organization": "018a92f8-afff-0000-efec-ca77de39e384", + "customer": "cus_OdSgxxWtHOtq9g", + "instance": "http://localhost:8000" + }, + "has_billing_plan": true, + "customer_deactivated": false, + "current_total_amount_usd": "0.00", + "percentage_usage.product_analytics": 0, + "current_amount_usd.product_analytics": "0.00", + "unit_amount_usd.product_analytics": null, + "usage_limit.product_analytics": null, + "current_usage.product_analytics": 3729, + "projected_usage.product_analytics": 0, + "free_allocation.product_analytics": 0, + "percentage_usage.session_replay": 0, + "current_amount_usd.session_replay": "0.00", + "unit_amount_usd.session_replay": null, + "usage_limit.session_replay": null, + "current_usage.session_replay": 254, + "projected_usage.session_replay": 0, + "free_allocation.session_replay": 0, + "percentage_usage.feature_flags": 0, + "current_amount_usd.feature_flags": "0.00", + "unit_amount_usd.feature_flags": null, + "usage_limit.feature_flags": null, + "current_usage.feature_flags": 0, + "projected_usage.feature_flags": 0, + "free_allocation.feature_flags": 0, + "percentage_usage.integrations": 0, + "current_amount_usd.integrations": null, + "unit_amount_usd.integrations": null, + "usage_limit.integrations": 0, + "current_usage.integrations": 0, + "projected_usage.integrations": 0, + "free_allocation.integrations": 0, + "percentage_usage.platform_and_support": 0, + "current_amount_usd.platform_and_support": null, + "unit_amount_usd.platform_and_support": null, + "usage_limit.platform_and_support": 0, + "current_usage.platform_and_support": 0, + "projected_usage.platform_and_support": 0, + "free_allocation.platform_and_support": 0, + "billing_period_start": "2023-10-14T09:22:33.000Z", + "billing_period_end": "2023-11-14T09:22:33.000Z", + "$referrer": "$direct", + "$referring_domain": "$direct", + "loadingMilliseconds": 2720, + "insightShortId": "vTZuWkZE", + "token": "phc_OWGI2wKbfi7rWDZT9wkl8uGcfe0wOGCvflLEZSMiaT0", + "$session_id": "018b4cc2-908b-7989-a77a-ae1396eef1de", + "$window_id": "018b4cc2-908b-7989-a77a-ae1465fa2118", + "$ip": "127.0.0.1", + "$set": { + "$os": "Mac OS X", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/home", + "$pathname": "/home", + "$browser_version": 117, + "$referrer": "$direct", + "$referring_domain": "$direct" + }, + "$set_once": { + "$initial_os": "Mac OS X", + "$initial_browser": "Chrome", + "$initial_device_type": "Desktop", + "$initial_current_url": "http://localhost:8000/home", + "$initial_pathname": "/home", + "$initial_browser_version": 117, + "$initial_referrer": "$direct", + "$initial_referring_domain": "$direct" + }, + "$sent_at": "2023-10-20T11:05:16.465000+00:00", + "$geoip_city_name": "Sydney", + "$geoip_country_name": "Australia", + "$geoip_country_code": "AU", + "$geoip_continent_name": "Oceania", + "$geoip_continent_code": "OC", + "$geoip_postal_code": "2000", + "$geoip_latitude": -33.8715, + "$geoip_longitude": 151.2006, + "$geoip_time_zone": "Australia/Sydney", + "$geoip_subdivision_1_code": "NSW", + "$geoip_subdivision_1_name": "New South Wales", + "$plugins_succeeded": ["GeoIP (1)"], + "$plugins_failed": [], + "$plugins_deferred": [], + "$group_3": "018a92f8-b602-0000-75de-4b9073693531", + "$group_2": "018a92f8-afff-0000-efec-ca77de39e384", + "$group_4": "cus_OdSgxxWtHOtq9g", + "$group_1": "http://localhost:8000" + }, + "timestamp": "2023-10-20T11:05:15.269000+00:00", + "uuid": null + }, + { + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "elements": [ + { + "attr_class": [ + "LemonButton", + "LemonButton--full-width", + "LemonButton--status-stealth", + "LemonButton--tertiary" + ], + "attr_id": null, + "attributes": { + "attr__class": "LemonButton LemonButton--tertiary LemonButton--status-stealth LemonButton--full-width", + "attr__type": "button" + }, + "href": null, + "nth_child": 16.0, + "nth_of_type": 15.0, + "order": 0.0, + "tag_name": "button", + "text": "Custom fixed date range\u2026" + }, + { + "attr_class": ["space-y-px"], + "attr_id": null, + "attributes": { + "attr__class": "space-y-px" + }, + "href": null, + "nth_child": 1.0, + "nth_of_type": 1.0, + "order": 1.0, + "tag_name": "div", + "text": null + }, + { + "attr_class": ["Popover__content"], + "attr_id": null, + "attributes": { + "attr__class": "Popover__content" + }, + "href": null, + "nth_child": 1.0, + "nth_of_type": 1.0, + "order": 2.0, + "tag_name": "div", + "text": null + }, + { + "attr_class": ["Popover__box"], + "attr_id": null, + "attributes": { + "attr__class": "Popover__box" + }, + "href": null, + "nth_child": 1.0, + "nth_of_type": 1.0, + "order": 3.0, + "tag_name": "div", + "text": null + }, + { + "attr_class": ["Popover", "Popover--actionable", "Popover--enter-done"], + "attr_id": null, + "attributes": { + "attr__aria-level": "0", + "attr__class": "Popover Popover--actionable Popover--enter-done", + "attr__data-placement": "bottom-start", + "attr__style": "position: fixed; top: 95.5747px; left: 317.718px; max-height: 759.425px; max-width: 1190.28px; width: initial;" + }, + "href": null, + "nth_child": 1.0, + "nth_of_type": 1.0, + "order": 4.0, + "tag_name": "div", + "text": null + }, + { + "attr_class": null, + "attr_id": null, + "attributes": { + "attr__data-floating-ui-portal": "\"attr__id=", + "floating-ui-6\"attr_id": "floating-ui-6" + }, + "href": null, + "nth_child": 16.0, + "nth_of_type": 12.0, + "order": 5.0, + "tag_name": "div", + "text": null + }, + { + "attr_class": ["posthog-3000"], + "attr_id": null, + "attributes": { + "attr__class": "posthog-3000", + "attr__theme": "light" + }, + "href": null, + "nth_child": 2.0, + "nth_of_type": 1.0, + "order": 6.0, + "tag_name": "body", + "text": null + } + ], + "elements_chain": "button.LemonButton.LemonButton--full-width.LemonButton--status-stealth.LemonButton--tertiary:attr__class=\"LemonButton LemonButton--tertiary LemonButton--status-stealth LemonButton--full-width\"attr__type=\"button\"nth-child=\"16\"nth-of-type=\"15\"text=\"Custom fixed date range\u2026\";div.space-y-px:attr__class=\"space-y-px\"nth-child=\"1\"nth-of-type=\"1\";div.Popover__content:attr__class=\"Popover__content\"nth-child=\"1\"nth-of-type=\"1\";div.Popover__box:attr__class=\"Popover__box\"nth-child=\"1\"nth-of-type=\"1\";div.Popover.Popover--actionable.Popover--enter-done:attr__aria-level=\"0\"attr__class=\"Popover Popover--actionable Popover--enter-done\"attr__data-placement=\"bottom-start\"attr__style=\"position: fixed; top: 95.5747px; left: 317.718px; max-height: 759.425px; max-width: 1190.28px; width: initial;\"nth-child=\"1\"nth-of-type=\"1\";div:attr__data-floating-ui-portal=\"\"attr__id=\"floating-ui-6\"attr_id=\"floating-ui-6\"nth-child=\"16\"nth-of-type=\"12\";body.posthog-3000:attr__class=\"posthog-3000\"attr__theme=\"light\"nth-child=\"2\"nth-of-type=\"1\"", + "event": "$autocapture", + "id": "018b4cc2-caed-756a-af22-999c0b649d92", + "person": null, + "properties": { + "$os": "Mac OS X", + "$os_version": "10.15.7", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/home", + "$host": "localhost:8000", + "$pathname": "/home", + "$browser_version": 117, + "$browser_language": "en-GB", + "$screen_height": 982, + "$screen_width": 1512, + "$viewport_height": 859, + "$viewport_width": 1512, + "$lib": "web", + "$lib_version": "1.84.0", + "$insert_id": "ubrot88ulvd6b8lg", + "$time": 1697799916.27, + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$device_id": "018a92fd-7b25-7770-a050-577e94fd148c", + "$console_log_recording_enabled_server_side": true, + "$session_recording_recorder_version_server_side": "v2", + "$autocapture_disabled_server_side": false, + "$active_feature_flags": [ + "signup-page-4.0", + "cmd-k-search", + "posthog-3000", + "funnels-cue-opt-out-7301", + "retention-breakdown", + "smoothing-interval", + "billing-limit", + "kafka-inspector", + "historical-exports-v2", + "person-on-events-enabled", + "region-select", + "ingestion-warnings-enabled", + "session-reset-on-load", + "recordings-on-feature-flags", + "auto-rollback-feature-flags", + "onboarding-v2-demo", + "feature-flag-rollout-ux", + "role-based-access", + "query_running_time", + "query-timings", + "recording-debugging", + "enable-prompts", + "feedback-scene", + "early-access-feature", + "early-access-feature-site-button", + "hedgehog-mode-debug", + "auto-redirect", + "session-recording-blob-replay", + "surveys", + "generic-signup-benefits", + "surveys-positions", + "web-analytics", + "high-frequency-batch-exports", + "exception-autocapture", + "data-warehouse", + "data-warehouse-views", + "ff-dashboard-templates", + "show-product-intro-existing-products", + "artificial-hog", + "cs-dashboards", + "product-specific-onboarding", + "redirect-signups-to-instance", + "apps-and-exports-ui", + "survey-nps-results", + "session-recording-allow-v1-snapshots", + "session-replay-cors-proxy", + "webhooks-denylist", + "surveys-site-app-deprecation", + "surveys-multiple-questions", + "surveys-results-visualizations", + "console-recording-search", + "persons-hogql-query", + "notebooks" + ], + "$feature/file-previews": false, + "$feature/signup-page-4.0": "control", + "$feature/hogql-insights": false, + "$feature/cmd-k-search": true, + "$feature/posthog-3000": true, + "$feature/funnels-cue-opt-out-7301": true, + "$feature/retention-breakdown": true, + "$feature/smoothing-interval": true, + "$feature/billing-limit": true, + "$feature/kafka-inspector": true, + "$feature/historical-exports-v2": true, + "$feature/person-on-events-enabled": true, + "$feature/region-select": true, + "$feature/ingestion-warnings-enabled": true, + "$feature/session-reset-on-load": true, + "$feature/recordings-on-feature-flags": true, + "$feature/auto-rollback-feature-flags": true, + "$feature/onboarding-v2-demo": true, + "$feature/feature-flag-rollout-ux": true, + "$feature/role-based-access": true, + "$feature/query_running_time": true, + "$feature/query-timings": true, + "$feature/recording-debugging": true, + "$feature/enable-prompts": true, + "$feature/feedback-scene": true, + "$feature/early-access-feature": true, + "$feature/early-access-feature-site-button": true, + "$feature/hedgehog-mode-debug": true, + "$feature/auto-redirect": true, + "$feature/session-recording-blob-replay": true, + "$feature/surveys": true, + "$feature/generic-signup-benefits": true, + "$feature/surveys-positions": true, + "$feature/web-analytics": true, + "$feature/high-frequency-batch-exports": true, + "$feature/exception-autocapture": true, + "$feature/data-warehouse": true, + "$feature/data-warehouse-views": true, + "$feature/ff-dashboard-templates": true, + "$feature/show-product-intro-existing-products": true, + "$feature/artificial-hog": true, + "$feature/cs-dashboards": true, + "$feature/product-specific-onboarding": true, + "$feature/redirect-signups-to-instance": true, + "$feature/apps-and-exports-ui": true, + "$feature/survey-nps-results": true, + "$feature/session-recording-allow-v1-snapshots": true, + "$feature/session-replay-cors-proxy": true, + "$feature/webhooks-denylist": true, + "$feature/surveys-site-app-deprecation": true, + "$feature/surveys-multiple-questions": true, + "$feature/surveys-results-visualizations": true, + "$feature/console-recording-search": true, + "$feature/persons-hogql-query": true, + "$feature/notebooks": true, + "$feature_flag_payloads": {}, + "realm": "hosted-clickhouse", + "email_service_available": false, + "slack_service_available": false, + "$user_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "is_demo_project": false, + "$groups": { + "project": "018a92f8-b602-0000-75de-4b9073693531", + "organization": "018a92f8-afff-0000-efec-ca77de39e384", + "customer": "cus_OdSgxxWtHOtq9g", + "instance": "http://localhost:8000" + }, + "has_billing_plan": true, + "customer_deactivated": false, + "current_total_amount_usd": "0.00", + "percentage_usage.product_analytics": 0, + "current_amount_usd.product_analytics": "0.00", + "unit_amount_usd.product_analytics": null, + "usage_limit.product_analytics": null, + "current_usage.product_analytics": 3729, + "projected_usage.product_analytics": 0, + "free_allocation.product_analytics": 0, + "percentage_usage.session_replay": 0, + "current_amount_usd.session_replay": "0.00", + "unit_amount_usd.session_replay": null, + "usage_limit.session_replay": null, + "current_usage.session_replay": 254, + "projected_usage.session_replay": 0, + "free_allocation.session_replay": 0, + "percentage_usage.feature_flags": 0, + "current_amount_usd.feature_flags": "0.00", + "unit_amount_usd.feature_flags": null, + "usage_limit.feature_flags": null, + "current_usage.feature_flags": 0, + "projected_usage.feature_flags": 0, + "free_allocation.feature_flags": 0, + "percentage_usage.integrations": 0, + "current_amount_usd.integrations": null, + "unit_amount_usd.integrations": null, + "usage_limit.integrations": 0, + "current_usage.integrations": 0, + "projected_usage.integrations": 0, + "free_allocation.integrations": 0, + "percentage_usage.platform_and_support": 0, + "current_amount_usd.platform_and_support": null, + "unit_amount_usd.platform_and_support": null, + "usage_limit.platform_and_support": 0, + "current_usage.platform_and_support": 0, + "projected_usage.platform_and_support": 0, + "free_allocation.platform_and_support": 0, + "billing_period_start": "2023-10-14T09:22:33.000Z", + "billing_period_end": "2023-11-14T09:22:33.000Z", + "$referrer": "$direct", + "$referring_domain": "$direct", + "$event_type": "click", + "$ce_version": 1, + "$el_text": "Custom fixed date range\u2026", + "token": "phc_OWGI2wKbfi7rWDZT9wkl8uGcfe0wOGCvflLEZSMiaT0", + "$session_id": "018b4cc2-908b-7989-a77a-ae1396eef1de", + "$window_id": "018b4cc2-908b-7989-a77a-ae1465fa2118", + "$ip": "127.0.0.1", + "$set": { + "$os": "Mac OS X", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/home", + "$pathname": "/home", + "$browser_version": 117, + "$referrer": "$direct", + "$referring_domain": "$direct" + }, + "$set_once": { + "$initial_os": "Mac OS X", + "$initial_browser": "Chrome", + "$initial_device_type": "Desktop", + "$initial_current_url": "http://localhost:8000/home", + "$initial_pathname": "/home", + "$initial_browser_version": 117, + "$initial_referrer": "$direct", + "$initial_referring_domain": "$direct" + }, + "$sent_at": "2023-10-20T11:05:16.465000+00:00", + "$geoip_city_name": "Sydney", + "$geoip_country_name": "Australia", + "$geoip_country_code": "AU", + "$geoip_continent_name": "Oceania", + "$geoip_continent_code": "OC", + "$geoip_postal_code": "2000", + "$geoip_latitude": -33.8715, + "$geoip_longitude": 151.2006, + "$geoip_time_zone": "Australia/Sydney", + "$geoip_subdivision_1_code": "NSW", + "$geoip_subdivision_1_name": "New South Wales", + "$plugins_succeeded": ["GeoIP (1)"], + "$plugins_failed": [], + "$plugins_deferred": [], + "$group_3": "018a92f8-b602-0000-75de-4b9073693531", + "$group_2": "018a92f8-afff-0000-efec-ca77de39e384", + "$group_4": "cus_OdSgxxWtHOtq9g", + "$group_1": "http://localhost:8000" + }, + "timestamp": "2023-10-20T11:05:16.286000+00:00", + "uuid": null + }, + { + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "elements": [ + { + "attr_class": null, + "attr_id": null, + "attributes": { + "attr__clip-rule": "evenodd", + "attr__d": "M12.162 3.12a.25.25 0 0 0-.324 0l-7.25 6.152a.25.25 0 0 0-.088.191v9.787c0 .138.112.25.25.25h4a.25.25 0 0 0 .25-.25v-3.5c0-.966.784-1.75 1.75-1.75h2.5c.966 0 1.75.784 1.75 1.75v3.5c0 .138.112.25.25.25h4a.25.25 0 0 0 .25-.25V9.463a.25.25 0 0 0-.088-.19l-7.25-6.152Zm-1.294-1.143a1.75 1.75 0 0 1 2.264 0l7.25 6.152c.392.332.618.82.618 1.334v9.787A1.75 1.75 0 0 1 19.25 21h-4a1.75 1.75 0 0 1-1.75-1.75v-3.5a.25.25 0 0 0-.25-.25h-2.5a.25.25 0 0 0-.25.25v3.5A1.75 1.75 0 0 1 8.75 21h-4A1.75 1.75 0 0 1 3 19.25V9.463c0-.514.226-1.002.618-1.334l7.25-6.152Z", + "attr__fill-rule": "evenodd", + "attr__href": "/home" + }, + "href": "/home", + "nth_child": 1.0, + "nth_of_type": 1.0, + "order": 0.0, + "tag_name": "path", + "text": null + }, + { + "attr_class": ["LemonIcon"], + "attr_id": null, + "attributes": { + "attr__class": "LemonIcon", + "attr__fill": "currentColor", + "attr__viewBox": "0 0 24 24", + "attr__width": "100%", + "attr__xmlns": "http://www.w3.org/2000/svg" + }, + "href": null, + "nth_child": 1.0, + "nth_of_type": 1.0, + "order": 1.0, + "tag_name": "svg", + "text": null + }, + { + "attr_class": ["LemonButton__icon"], + "attr_id": null, + "attributes": { + "attr__class": "LemonButton__icon" + }, + "href": null, + "nth_child": 1.0, + "nth_of_type": 1.0, + "order": 2.0, + "tag_name": "span", + "text": null + }, + { + "attr_class": [ + "LemonButton", + "LemonButton--has-icon", + "LemonButton--no-content", + "LemonButton--status-primary", + "LemonButton--tertiary", + "Link", + "ant-tooltip-open" + ], + "attr_id": null, + "attributes": { + "attr__class": "Link LemonButton LemonButton--tertiary LemonButton--status-primary LemonButton--no-content LemonButton--has-icon ant-tooltip-open", + "attr__data-attr": "menu-item-projecthomepage", + "attr__draggable": "true", + "attr__href": "/home" + }, + "href": "/home", + "nth_child": 1.0, + "nth_of_type": 1.0, + "order": 3.0, + "tag_name": "a", + "text": null + }, + { + "attr_class": null, + "attr_id": null, + "attributes": {}, + "href": null, + "nth_child": 1.0, + "nth_of_type": 1.0, + "order": 4.0, + "tag_name": "li", + "text": null + }, + { + "attr_class": null, + "attr_id": null, + "attributes": {}, + "href": null, + "nth_child": 1.0, + "nth_of_type": 1.0, + "order": 5.0, + "tag_name": "ul", + "text": null + }, + { + "attr_class": ["Navbar3000__top"], + "attr_id": null, + "attributes": { + "attr__class": "Navbar3000__top" + }, + "href": null, + "nth_child": 1.0, + "nth_of_type": 1.0, + "order": 6.0, + "tag_name": "div", + "text": null + }, + { + "attr_class": ["Navbar3000__content"], + "attr_id": null, + "attributes": { + "attr__class": "Navbar3000__content" + }, + "href": null, + "nth_child": 1.0, + "nth_of_type": 1.0, + "order": 7.0, + "tag_name": "div", + "text": null + }, + { + "attr_class": ["Navbar3000"], + "attr_id": null, + "attributes": { + "attr__class": "Navbar3000" + }, + "href": null, + "nth_child": 1.0, + "nth_of_type": 1.0, + "order": 8.0, + "tag_name": "nav", + "text": null + }, + { + "attr_class": ["Navigation3000"], + "attr_id": null, + "attributes": { + "attr__class": "Navigation3000" + }, + "href": null, + "nth_child": 1.0, + "nth_of_type": 1.0, + "order": 9.0, + "tag_name": "div", + "text": null + }, + { + "attr_class": null, + "attr_id": "root", + "attributes": { + "attr__id": "root" + }, + "href": null, + "nth_child": 4.0, + "nth_of_type": 1.0, + "order": 10.0, + "tag_name": "div", + "text": null + }, + { + "attr_class": ["posthog-3000"], + "attr_id": null, + "attributes": { + "attr__class": "posthog-3000", + "attr__theme": "light" + }, + "href": null, + "nth_child": 2.0, + "nth_of_type": 1.0, + "order": 11.0, + "tag_name": "body", + "text": null + } + ], + "elements_chain": "path:attr__clip-rule=\"evenodd\"attr__d=\"M12.162 3.12a.25.25 0 0 0-.324 0l-7.25 6.152a.25.25 0 0 0-.088.191v9.787c0 .138.112.25.25.25h4a.25.25 0 0 0 .25-.25v-3.5c0-.966.784-1.75 1.75-1.75h2.5c.966 0 1.75.784 1.75 1.75v3.5c0 .138.112.25.25.25h4a.25.25 0 0 0 .25-.25V9.463a.25.25 0 0 0-.088-.19l-7.25-6.152Zm-1.294-1.143a1.75 1.75 0 0 1 2.264 0l7.25 6.152c.392.332.618.82.618 1.334v9.787A1.75 1.75 0 0 1 19.25 21h-4a1.75 1.75 0 0 1-1.75-1.75v-3.5a.25.25 0 0 0-.25-.25h-2.5a.25.25 0 0 0-.25.25v3.5A1.75 1.75 0 0 1 8.75 21h-4A1.75 1.75 0 0 1 3 19.25V9.463c0-.514.226-1.002.618-1.334l7.25-6.152Z\"attr__fill-rule=\"evenodd\"attr__href=\"/home\"href=\"/home\"nth-child=\"1\"nth-of-type=\"1\";svg.LemonIcon:attr__class=\"LemonIcon\"attr__fill=\"currentColor\"attr__viewBox=\"0 0 24 24\"attr__width=\"100%\"attr__xmlns=\"http://www.w3.org/2000/svg\"nth-child=\"1\"nth-of-type=\"1\";span.LemonButton__icon:attr__class=\"LemonButton__icon\"nth-child=\"1\"nth-of-type=\"1\";a.LemonButton.LemonButton--has-icon.LemonButton--no-content.LemonButton--status-primary.LemonButton--tertiary.Link.ant-tooltip-open:attr__class=\"Link LemonButton LemonButton--tertiary LemonButton--status-primary LemonButton--no-content LemonButton--has-icon ant-tooltip-open\"attr__data-attr=\"menu-item-projecthomepage\"attr__draggable=\"true\"attr__href=\"/home\"href=\"/home\"nth-child=\"1\"nth-of-type=\"1\";li:nth-child=\"1\"nth-of-type=\"1\";ul:nth-child=\"1\"nth-of-type=\"1\";div.Navbar3000__top:attr__class=\"Navbar3000__top\"nth-child=\"1\"nth-of-type=\"1\";div.Navbar3000__content:attr__class=\"Navbar3000__content\"nth-child=\"1\"nth-of-type=\"1\";nav.Navbar3000:attr__class=\"Navbar3000\"nth-child=\"1\"nth-of-type=\"1\";div.Navigation3000:attr__class=\"Navigation3000\"nth-child=\"1\"nth-of-type=\"1\";div:attr__id=\"root\"attr_id=\"root\"nth-child=\"4\"nth-of-type=\"1\";body.posthog-3000:attr__class=\"posthog-3000\"attr__theme=\"light\"nth-child=\"2\"nth-of-type=\"1\"", + "event": "$autocapture", + "id": "018b4cc2-d38c-7d90-9fc6-230883fb4c9d", + "person": null, + "properties": { + "$os": "Mac OS X", + "$os_version": "10.15.7", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/home", + "$host": "localhost:8000", + "$pathname": "/home", + "$browser_version": 117, + "$browser_language": "en-GB", + "$screen_height": 982, + "$screen_width": 1512, + "$viewport_height": 859, + "$viewport_width": 1512, + "$lib": "web", + "$lib_version": "1.84.0", + "$insert_id": "az8i1ijfsp7dcu8f", + "$time": 1697799918.476, + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$device_id": "018a92fd-7b25-7770-a050-577e94fd148c", + "$console_log_recording_enabled_server_side": true, + "$session_recording_recorder_version_server_side": "v2", + "$autocapture_disabled_server_side": false, + "$active_feature_flags": [ + "signup-page-4.0", + "cmd-k-search", + "posthog-3000", + "funnels-cue-opt-out-7301", + "retention-breakdown", + "smoothing-interval", + "billing-limit", + "kafka-inspector", + "historical-exports-v2", + "person-on-events-enabled", + "region-select", + "ingestion-warnings-enabled", + "session-reset-on-load", + "recordings-on-feature-flags", + "auto-rollback-feature-flags", + "onboarding-v2-demo", + "feature-flag-rollout-ux", + "role-based-access", + "query_running_time", + "query-timings", + "recording-debugging", + "enable-prompts", + "feedback-scene", + "early-access-feature", + "early-access-feature-site-button", + "hedgehog-mode-debug", + "auto-redirect", + "session-recording-blob-replay", + "surveys", + "generic-signup-benefits", + "surveys-positions", + "web-analytics", + "high-frequency-batch-exports", + "exception-autocapture", + "data-warehouse", + "data-warehouse-views", + "ff-dashboard-templates", + "show-product-intro-existing-products", + "artificial-hog", + "cs-dashboards", + "product-specific-onboarding", + "redirect-signups-to-instance", + "apps-and-exports-ui", + "survey-nps-results", + "session-recording-allow-v1-snapshots", + "session-replay-cors-proxy", + "webhooks-denylist", + "surveys-site-app-deprecation", + "surveys-multiple-questions", + "surveys-results-visualizations", + "console-recording-search", + "persons-hogql-query", + "notebooks" + ], + "$feature/file-previews": false, + "$feature/signup-page-4.0": "control", + "$feature/hogql-insights": false, + "$feature/cmd-k-search": true, + "$feature/posthog-3000": true, + "$feature/funnels-cue-opt-out-7301": true, + "$feature/retention-breakdown": true, + "$feature/smoothing-interval": true, + "$feature/billing-limit": true, + "$feature/kafka-inspector": true, + "$feature/historical-exports-v2": true, + "$feature/person-on-events-enabled": true, + "$feature/region-select": true, + "$feature/ingestion-warnings-enabled": true, + "$feature/session-reset-on-load": true, + "$feature/recordings-on-feature-flags": true, + "$feature/auto-rollback-feature-flags": true, + "$feature/onboarding-v2-demo": true, + "$feature/feature-flag-rollout-ux": true, + "$feature/role-based-access": true, + "$feature/query_running_time": true, + "$feature/query-timings": true, + "$feature/recording-debugging": true, + "$feature/enable-prompts": true, + "$feature/feedback-scene": true, + "$feature/early-access-feature": true, + "$feature/early-access-feature-site-button": true, + "$feature/hedgehog-mode-debug": true, + "$feature/auto-redirect": true, + "$feature/session-recording-blob-replay": true, + "$feature/surveys": true, + "$feature/generic-signup-benefits": true, + "$feature/surveys-positions": true, + "$feature/web-analytics": true, + "$feature/high-frequency-batch-exports": true, + "$feature/exception-autocapture": true, + "$feature/data-warehouse": true, + "$feature/data-warehouse-views": true, + "$feature/ff-dashboard-templates": true, + "$feature/show-product-intro-existing-products": true, + "$feature/artificial-hog": true, + "$feature/cs-dashboards": true, + "$feature/product-specific-onboarding": true, + "$feature/redirect-signups-to-instance": true, + "$feature/apps-and-exports-ui": true, + "$feature/survey-nps-results": true, + "$feature/session-recording-allow-v1-snapshots": true, + "$feature/session-replay-cors-proxy": true, + "$feature/webhooks-denylist": true, + "$feature/surveys-site-app-deprecation": true, + "$feature/surveys-multiple-questions": true, + "$feature/surveys-results-visualizations": true, + "$feature/console-recording-search": true, + "$feature/persons-hogql-query": true, + "$feature/notebooks": true, + "$feature_flag_payloads": {}, + "realm": "hosted-clickhouse", + "email_service_available": false, + "slack_service_available": false, + "$user_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "is_demo_project": false, + "$groups": { + "project": "018a92f8-b602-0000-75de-4b9073693531", + "organization": "018a92f8-afff-0000-efec-ca77de39e384", + "customer": "cus_OdSgxxWtHOtq9g", + "instance": "http://localhost:8000" + }, + "has_billing_plan": true, + "customer_deactivated": false, + "current_total_amount_usd": "0.00", + "percentage_usage.product_analytics": 0, + "current_amount_usd.product_analytics": "0.00", + "unit_amount_usd.product_analytics": null, + "usage_limit.product_analytics": null, + "current_usage.product_analytics": 3729, + "projected_usage.product_analytics": 0, + "free_allocation.product_analytics": 0, + "percentage_usage.session_replay": 0, + "current_amount_usd.session_replay": "0.00", + "unit_amount_usd.session_replay": null, + "usage_limit.session_replay": null, + "current_usage.session_replay": 254, + "projected_usage.session_replay": 0, + "free_allocation.session_replay": 0, + "percentage_usage.feature_flags": 0, + "current_amount_usd.feature_flags": "0.00", + "unit_amount_usd.feature_flags": null, + "usage_limit.feature_flags": null, + "current_usage.feature_flags": 0, + "projected_usage.feature_flags": 0, + "free_allocation.feature_flags": 0, + "percentage_usage.integrations": 0, + "current_amount_usd.integrations": null, + "unit_amount_usd.integrations": null, + "usage_limit.integrations": 0, + "current_usage.integrations": 0, + "projected_usage.integrations": 0, + "free_allocation.integrations": 0, + "percentage_usage.platform_and_support": 0, + "current_amount_usd.platform_and_support": null, + "unit_amount_usd.platform_and_support": null, + "usage_limit.platform_and_support": 0, + "current_usage.platform_and_support": 0, + "projected_usage.platform_and_support": 0, + "free_allocation.platform_and_support": 0, + "billing_period_start": "2023-10-14T09:22:33.000Z", + "billing_period_end": "2023-11-14T09:22:33.000Z", + "$referrer": "$direct", + "$referring_domain": "$direct", + "$event_type": "click", + "$ce_version": 1, + "token": "phc_OWGI2wKbfi7rWDZT9wkl8uGcfe0wOGCvflLEZSMiaT0", + "$session_id": "018b4cc2-908b-7989-a77a-ae1396eef1de", + "$window_id": "018b4cc2-908b-7989-a77a-ae1465fa2118", + "$ip": "127.0.0.1", + "$set": { + "$os": "Mac OS X", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/home", + "$pathname": "/home", + "$browser_version": 117, + "$referrer": "$direct", + "$referring_domain": "$direct" + }, + "$set_once": { + "$initial_os": "Mac OS X", + "$initial_browser": "Chrome", + "$initial_device_type": "Desktop", + "$initial_current_url": "http://localhost:8000/home", + "$initial_pathname": "/home", + "$initial_browser_version": 117, + "$initial_referrer": "$direct", + "$initial_referring_domain": "$direct" + }, + "$sent_at": "2023-10-20T11:05:19.477000+00:00", + "$geoip_city_name": "Sydney", + "$geoip_country_name": "Australia", + "$geoip_country_code": "AU", + "$geoip_continent_name": "Oceania", + "$geoip_continent_code": "OC", + "$geoip_postal_code": "2000", + "$geoip_latitude": -33.8715, + "$geoip_longitude": 151.2006, + "$geoip_time_zone": "Australia/Sydney", + "$geoip_subdivision_1_code": "NSW", + "$geoip_subdivision_1_name": "New South Wales", + "$plugins_succeeded": ["GeoIP (1)"], + "$plugins_failed": [], + "$plugins_deferred": [], + "$group_3": "018a92f8-b602-0000-75de-4b9073693531", + "$group_2": "018a92f8-afff-0000-efec-ca77de39e384", + "$group_4": "cus_OdSgxxWtHOtq9g", + "$group_1": "http://localhost:8000" + }, + "timestamp": "2023-10-20T11:05:18.486000+00:00", + "uuid": null + }, + { + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "elements": [], + "elements_chain": null, + "event": "$feature_flag_called", + "id": "018b4cc2-d395-72e8-a051-8b267d8e7066", + "person": null, + "properties": { + "$os": "Mac OS X", + "$os_version": "10.15.7", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/home", + "$host": "localhost:8000", + "$pathname": "/home", + "$browser_version": 117, + "$browser_language": "en-GB", + "$screen_height": 982, + "$screen_width": 1512, + "$viewport_height": 859, + "$viewport_width": 1512, + "$lib": "web", + "$lib_version": "1.84.0", + "$insert_id": "wqe2gfkuym7xcp8o", + "$time": 1697799918.485, + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$device_id": "018a92fd-7b25-7770-a050-577e94fd148c", + "$console_log_recording_enabled_server_side": true, + "$session_recording_recorder_version_server_side": "v2", + "$autocapture_disabled_server_side": false, + "$active_feature_flags": [ + "signup-page-4.0", + "cmd-k-search", + "posthog-3000", + "funnels-cue-opt-out-7301", + "retention-breakdown", + "smoothing-interval", + "billing-limit", + "kafka-inspector", + "historical-exports-v2", + "person-on-events-enabled", + "region-select", + "ingestion-warnings-enabled", + "session-reset-on-load", + "recordings-on-feature-flags", + "auto-rollback-feature-flags", + "onboarding-v2-demo", + "feature-flag-rollout-ux", + "role-based-access", + "query_running_time", + "query-timings", + "recording-debugging", + "enable-prompts", + "feedback-scene", + "early-access-feature", + "early-access-feature-site-button", + "hedgehog-mode-debug", + "auto-redirect", + "session-recording-blob-replay", + "surveys", + "generic-signup-benefits", + "surveys-positions", + "web-analytics", + "high-frequency-batch-exports", + "exception-autocapture", + "data-warehouse", + "data-warehouse-views", + "ff-dashboard-templates", + "show-product-intro-existing-products", + "artificial-hog", + "cs-dashboards", + "product-specific-onboarding", + "redirect-signups-to-instance", + "apps-and-exports-ui", + "survey-nps-results", + "session-recording-allow-v1-snapshots", + "session-replay-cors-proxy", + "webhooks-denylist", + "surveys-site-app-deprecation", + "surveys-multiple-questions", + "surveys-results-visualizations", + "console-recording-search", + "persons-hogql-query", + "notebooks" + ], + "$feature/file-previews": false, + "$feature/signup-page-4.0": "control", + "$feature/hogql-insights": false, + "$feature/cmd-k-search": true, + "$feature/posthog-3000": true, + "$feature/funnels-cue-opt-out-7301": true, + "$feature/retention-breakdown": true, + "$feature/smoothing-interval": true, + "$feature/billing-limit": true, + "$feature/kafka-inspector": true, + "$feature/historical-exports-v2": true, + "$feature/person-on-events-enabled": true, + "$feature/region-select": true, + "$feature/ingestion-warnings-enabled": true, + "$feature/session-reset-on-load": true, + "$feature/recordings-on-feature-flags": true, + "$feature/auto-rollback-feature-flags": true, + "$feature/onboarding-v2-demo": true, + "$feature/feature-flag-rollout-ux": true, + "$feature/role-based-access": true, + "$feature/query_running_time": true, + "$feature/query-timings": true, + "$feature/recording-debugging": true, + "$feature/enable-prompts": true, + "$feature/feedback-scene": true, + "$feature/early-access-feature": true, + "$feature/early-access-feature-site-button": true, + "$feature/hedgehog-mode-debug": true, + "$feature/auto-redirect": true, + "$feature/session-recording-blob-replay": true, + "$feature/surveys": true, + "$feature/generic-signup-benefits": true, + "$feature/surveys-positions": true, + "$feature/web-analytics": true, + "$feature/high-frequency-batch-exports": true, + "$feature/exception-autocapture": true, + "$feature/data-warehouse": true, + "$feature/data-warehouse-views": true, + "$feature/ff-dashboard-templates": true, + "$feature/show-product-intro-existing-products": true, + "$feature/artificial-hog": true, + "$feature/cs-dashboards": true, + "$feature/product-specific-onboarding": true, + "$feature/redirect-signups-to-instance": true, + "$feature/apps-and-exports-ui": true, + "$feature/survey-nps-results": true, + "$feature/session-recording-allow-v1-snapshots": true, + "$feature/session-replay-cors-proxy": true, + "$feature/webhooks-denylist": true, + "$feature/surveys-site-app-deprecation": true, + "$feature/surveys-multiple-questions": true, + "$feature/surveys-results-visualizations": true, + "$feature/console-recording-search": true, + "$feature/persons-hogql-query": true, + "$feature/notebooks": true, + "$feature_flag_payloads": {}, + "realm": "hosted-clickhouse", + "email_service_available": false, + "slack_service_available": false, + "$user_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "is_demo_project": false, + "$groups": { + "project": "018a92f8-b602-0000-75de-4b9073693531", + "organization": "018a92f8-afff-0000-efec-ca77de39e384", + "customer": "cus_OdSgxxWtHOtq9g", + "instance": "http://localhost:8000" + }, + "has_billing_plan": true, + "customer_deactivated": false, + "current_total_amount_usd": "0.00", + "percentage_usage.product_analytics": 0, + "current_amount_usd.product_analytics": "0.00", + "unit_amount_usd.product_analytics": null, + "usage_limit.product_analytics": null, + "current_usage.product_analytics": 3729, + "projected_usage.product_analytics": 0, + "free_allocation.product_analytics": 0, + "percentage_usage.session_replay": 0, + "current_amount_usd.session_replay": "0.00", + "unit_amount_usd.session_replay": null, + "usage_limit.session_replay": null, + "current_usage.session_replay": 254, + "projected_usage.session_replay": 0, + "free_allocation.session_replay": 0, + "percentage_usage.feature_flags": 0, + "current_amount_usd.feature_flags": "0.00", + "unit_amount_usd.feature_flags": null, + "usage_limit.feature_flags": null, + "current_usage.feature_flags": 0, + "projected_usage.feature_flags": 0, + "free_allocation.feature_flags": 0, + "percentage_usage.integrations": 0, + "current_amount_usd.integrations": null, + "unit_amount_usd.integrations": null, + "usage_limit.integrations": 0, + "current_usage.integrations": 0, + "projected_usage.integrations": 0, + "free_allocation.integrations": 0, + "percentage_usage.platform_and_support": 0, + "current_amount_usd.platform_and_support": null, + "unit_amount_usd.platform_and_support": null, + "usage_limit.platform_and_support": 0, + "current_usage.platform_and_support": 0, + "projected_usage.platform_and_support": 0, + "free_allocation.platform_and_support": 0, + "billing_period_start": "2023-10-14T09:22:33.000Z", + "billing_period_end": "2023-11-14T09:22:33.000Z", + "$referrer": "$direct", + "$referring_domain": "$direct", + "$feature_flag": "product-specific-onboarding", + "$feature_flag_response": true, + "token": "phc_OWGI2wKbfi7rWDZT9wkl8uGcfe0wOGCvflLEZSMiaT0", + "$session_id": "018b4cc2-908b-7989-a77a-ae1396eef1de", + "$window_id": "018b4cc2-908b-7989-a77a-ae1465fa2118", + "$ip": "127.0.0.1", + "$set": { + "$os": "Mac OS X", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/home", + "$pathname": "/home", + "$browser_version": 117, + "$referrer": "$direct", + "$referring_domain": "$direct" + }, + "$set_once": { + "$initial_os": "Mac OS X", + "$initial_browser": "Chrome", + "$initial_device_type": "Desktop", + "$initial_current_url": "http://localhost:8000/home", + "$initial_pathname": "/home", + "$initial_browser_version": 117, + "$initial_referrer": "$direct", + "$initial_referring_domain": "$direct" + }, + "$sent_at": "2023-10-20T11:05:19.477000+00:00", + "$geoip_city_name": "Sydney", + "$geoip_country_name": "Australia", + "$geoip_country_code": "AU", + "$geoip_continent_name": "Oceania", + "$geoip_continent_code": "OC", + "$geoip_postal_code": "2000", + "$geoip_latitude": -33.8715, + "$geoip_longitude": 151.2006, + "$geoip_time_zone": "Australia/Sydney", + "$geoip_subdivision_1_code": "NSW", + "$geoip_subdivision_1_name": "New South Wales", + "$plugins_succeeded": ["GeoIP (1)"], + "$plugins_failed": [], + "$plugins_deferred": [], + "$group_3": "018a92f8-b602-0000-75de-4b9073693531", + "$group_2": "018a92f8-afff-0000-efec-ca77de39e384", + "$group_4": "cus_OdSgxxWtHOtq9g", + "$group_1": "http://localhost:8000" + }, + "timestamp": "2023-10-20T11:05:18.495000+00:00", + "uuid": null + }, + { + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "elements": [], + "elements_chain": null, + "event": "$pageview", + "id": "018b4cc2-d398-7794-933f-fa78a242c2cb", + "person": null, + "properties": { + "$os": "Mac OS X", + "$os_version": "10.15.7", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/home", + "$host": "localhost:8000", + "$pathname": "/home", + "$browser_version": 117, + "$browser_language": "en-GB", + "$screen_height": 982, + "$screen_width": 1512, + "$viewport_height": 859, + "$viewport_width": 1512, + "$lib": "web", + "$lib_version": "1.84.0", + "$insert_id": "pbwgsdeb7kudbck5", + "$time": 1697799918.489, + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$device_id": "018a92fd-7b25-7770-a050-577e94fd148c", + "$console_log_recording_enabled_server_side": true, + "$session_recording_recorder_version_server_side": "v2", + "$autocapture_disabled_server_side": false, + "$active_feature_flags": [ + "signup-page-4.0", + "cmd-k-search", + "posthog-3000", + "funnels-cue-opt-out-7301", + "retention-breakdown", + "smoothing-interval", + "billing-limit", + "kafka-inspector", + "historical-exports-v2", + "person-on-events-enabled", + "region-select", + "ingestion-warnings-enabled", + "session-reset-on-load", + "recordings-on-feature-flags", + "auto-rollback-feature-flags", + "onboarding-v2-demo", + "feature-flag-rollout-ux", + "role-based-access", + "query_running_time", + "query-timings", + "recording-debugging", + "enable-prompts", + "feedback-scene", + "early-access-feature", + "early-access-feature-site-button", + "hedgehog-mode-debug", + "auto-redirect", + "session-recording-blob-replay", + "surveys", + "generic-signup-benefits", + "surveys-positions", + "web-analytics", + "high-frequency-batch-exports", + "exception-autocapture", + "data-warehouse", + "data-warehouse-views", + "ff-dashboard-templates", + "show-product-intro-existing-products", + "artificial-hog", + "cs-dashboards", + "product-specific-onboarding", + "redirect-signups-to-instance", + "apps-and-exports-ui", + "survey-nps-results", + "session-recording-allow-v1-snapshots", + "session-replay-cors-proxy", + "webhooks-denylist", + "surveys-site-app-deprecation", + "surveys-multiple-questions", + "surveys-results-visualizations", + "console-recording-search", + "persons-hogql-query", + "notebooks" + ], + "$feature/file-previews": false, + "$feature/signup-page-4.0": "control", + "$feature/hogql-insights": false, + "$feature/cmd-k-search": true, + "$feature/posthog-3000": true, + "$feature/funnels-cue-opt-out-7301": true, + "$feature/retention-breakdown": true, + "$feature/smoothing-interval": true, + "$feature/billing-limit": true, + "$feature/kafka-inspector": true, + "$feature/historical-exports-v2": true, + "$feature/person-on-events-enabled": true, + "$feature/region-select": true, + "$feature/ingestion-warnings-enabled": true, + "$feature/session-reset-on-load": true, + "$feature/recordings-on-feature-flags": true, + "$feature/auto-rollback-feature-flags": true, + "$feature/onboarding-v2-demo": true, + "$feature/feature-flag-rollout-ux": true, + "$feature/role-based-access": true, + "$feature/query_running_time": true, + "$feature/query-timings": true, + "$feature/recording-debugging": true, + "$feature/enable-prompts": true, + "$feature/feedback-scene": true, + "$feature/early-access-feature": true, + "$feature/early-access-feature-site-button": true, + "$feature/hedgehog-mode-debug": true, + "$feature/auto-redirect": true, + "$feature/session-recording-blob-replay": true, + "$feature/surveys": true, + "$feature/generic-signup-benefits": true, + "$feature/surveys-positions": true, + "$feature/web-analytics": true, + "$feature/high-frequency-batch-exports": true, + "$feature/exception-autocapture": true, + "$feature/data-warehouse": true, + "$feature/data-warehouse-views": true, + "$feature/ff-dashboard-templates": true, + "$feature/show-product-intro-existing-products": true, + "$feature/artificial-hog": true, + "$feature/cs-dashboards": true, + "$feature/product-specific-onboarding": true, + "$feature/redirect-signups-to-instance": true, + "$feature/apps-and-exports-ui": true, + "$feature/survey-nps-results": true, + "$feature/session-recording-allow-v1-snapshots": true, + "$feature/session-replay-cors-proxy": true, + "$feature/webhooks-denylist": true, + "$feature/surveys-site-app-deprecation": true, + "$feature/surveys-multiple-questions": true, + "$feature/surveys-results-visualizations": true, + "$feature/console-recording-search": true, + "$feature/persons-hogql-query": true, + "$feature/notebooks": true, + "$feature_flag_payloads": {}, + "realm": "hosted-clickhouse", + "email_service_available": false, + "slack_service_available": false, + "$user_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "is_demo_project": false, + "$groups": { + "project": "018a92f8-b602-0000-75de-4b9073693531", + "organization": "018a92f8-afff-0000-efec-ca77de39e384", + "customer": "cus_OdSgxxWtHOtq9g", + "instance": "http://localhost:8000" + }, + "has_billing_plan": true, + "customer_deactivated": false, + "current_total_amount_usd": "0.00", + "percentage_usage.product_analytics": 0, + "current_amount_usd.product_analytics": "0.00", + "unit_amount_usd.product_analytics": null, + "usage_limit.product_analytics": null, + "current_usage.product_analytics": 3729, + "projected_usage.product_analytics": 0, + "free_allocation.product_analytics": 0, + "percentage_usage.session_replay": 0, + "current_amount_usd.session_replay": "0.00", + "unit_amount_usd.session_replay": null, + "usage_limit.session_replay": null, + "current_usage.session_replay": 254, + "projected_usage.session_replay": 0, + "free_allocation.session_replay": 0, + "percentage_usage.feature_flags": 0, + "current_amount_usd.feature_flags": "0.00", + "unit_amount_usd.feature_flags": null, + "usage_limit.feature_flags": null, + "current_usage.feature_flags": 0, + "projected_usage.feature_flags": 0, + "free_allocation.feature_flags": 0, + "percentage_usage.integrations": 0, + "current_amount_usd.integrations": null, + "unit_amount_usd.integrations": null, + "usage_limit.integrations": 0, + "current_usage.integrations": 0, + "projected_usage.integrations": 0, + "free_allocation.integrations": 0, + "percentage_usage.platform_and_support": 0, + "current_amount_usd.platform_and_support": null, + "unit_amount_usd.platform_and_support": null, + "usage_limit.platform_and_support": 0, + "current_usage.platform_and_support": 0, + "projected_usage.platform_and_support": 0, + "free_allocation.platform_and_support": 0, + "billing_period_start": "2023-10-14T09:22:33.000Z", + "billing_period_end": "2023-11-14T09:22:33.000Z", + "$referrer": "$direct", + "$referring_domain": "$direct", + "token": "phc_OWGI2wKbfi7rWDZT9wkl8uGcfe0wOGCvflLEZSMiaT0", + "$session_id": "018b4cc2-908b-7989-a77a-ae1396eef1de", + "$window_id": "018b4cc2-908b-7989-a77a-ae1465fa2118", + "title": "Homepage \u2022 PostHog", + "$ip": "127.0.0.1", + "$set": { + "$os": "Mac OS X", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/home", + "$pathname": "/home", + "$browser_version": 117, + "$referrer": "$direct", + "$referring_domain": "$direct" + }, + "$set_once": { + "$initial_os": "Mac OS X", + "$initial_browser": "Chrome", + "$initial_device_type": "Desktop", + "$initial_current_url": "http://localhost:8000/home", + "$initial_pathname": "/home", + "$initial_browser_version": 117, + "$initial_referrer": "$direct", + "$initial_referring_domain": "$direct" + }, + "$sent_at": "2023-10-20T11:05:19.477000+00:00", + "$geoip_city_name": "Sydney", + "$geoip_country_name": "Australia", + "$geoip_country_code": "AU", + "$geoip_continent_name": "Oceania", + "$geoip_continent_code": "OC", + "$geoip_postal_code": "2000", + "$geoip_latitude": -33.8715, + "$geoip_longitude": 151.2006, + "$geoip_time_zone": "Australia/Sydney", + "$geoip_subdivision_1_code": "NSW", + "$geoip_subdivision_1_name": "New South Wales", + "$plugins_succeeded": ["GeoIP (1)"], + "$plugins_failed": [], + "$plugins_deferred": [], + "$group_3": "018a92f8-b602-0000-75de-4b9073693531", + "$group_2": "018a92f8-afff-0000-efec-ca77de39e384", + "$group_4": "cus_OdSgxxWtHOtq9g", + "$group_1": "http://localhost:8000" + }, + "timestamp": "2023-10-20T11:05:18.498000+00:00", + "uuid": null + }, + { + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "elements": [ + { + "attr_class": [ + "LemonButton", + "LemonButton--has-icon", + "LemonButton--has-side-icon", + "LemonButton--primary", + "LemonButton--small", + "LemonButton--status-primary", + "Link" + ], + "attr_id": null, + "attributes": { + "attr__class": "Link LemonButton LemonButton--primary LemonButton--status-primary LemonButton--small LemonButton--has-icon LemonButton--has-side-icon", + "attr__data-attr": "saved-insights-new-insight-button", + "attr__draggable": "true", + "attr__href": "/insights/new" + }, + "href": "/insights/new", + "nth_child": 1.0, + "nth_of_type": 1.0, + "order": 0.0, + "tag_name": "a", + "text": "New insight" + }, + { + "attr_class": ["LemonButtonWithSideAction", "LemonButtonWithSideAction--small"], + "attr_id": null, + "attributes": { + "attr__class": "LemonButtonWithSideAction LemonButtonWithSideAction--small" + }, + "href": null, + "nth_child": 2.0, + "nth_of_type": 1.0, + "order": 1.0, + "tag_name": "div", + "text": null + }, + { + "attr_class": ["Breadcrumbs3000__actions"], + "attr_id": null, + "attributes": { + "attr__class": "Breadcrumbs3000__actions" + }, + "href": null, + "nth_child": 7.0, + "nth_of_type": 6.0, + "order": 2.0, + "tag_name": "div", + "text": null + }, + { + "attr_class": ["Breadcrumbs3000"], + "attr_id": null, + "attributes": { + "attr__class": "Breadcrumbs3000" + }, + "href": null, + "nth_child": 1.0, + "nth_of_type": 1.0, + "order": 3.0, + "tag_name": "div", + "text": null + }, + { + "attr_class": null, + "attr_id": null, + "attributes": {}, + "href": null, + "nth_child": 4.0, + "nth_of_type": 1.0, + "order": 4.0, + "tag_name": "main", + "text": null + }, + { + "attr_class": ["Navigation3000"], + "attr_id": null, + "attributes": { + "attr__class": "Navigation3000" + }, + "href": null, + "nth_child": 1.0, + "nth_of_type": 1.0, + "order": 5.0, + "tag_name": "div", + "text": null + }, + { + "attr_class": null, + "attr_id": "root", + "attributes": { + "attr__id": "root" + }, + "href": null, + "nth_child": 4.0, + "nth_of_type": 1.0, + "order": 6.0, + "tag_name": "div", + "text": null + }, + { + "attr_class": ["posthog-3000"], + "attr_id": null, + "attributes": { + "attr__class": "posthog-3000", + "attr__theme": "light" + }, + "href": null, + "nth_child": 2.0, + "nth_of_type": 1.0, + "order": 7.0, + "tag_name": "body", + "text": null + } + ], + "elements_chain": "a.LemonButton.LemonButton--has-icon.LemonButton--has-side-icon.LemonButton--primary.LemonButton--small.LemonButton--status-primary.Link:attr__class=\"Link LemonButton LemonButton--primary LemonButton--status-primary LemonButton--small LemonButton--has-icon LemonButton--has-side-icon\"attr__data-attr=\"saved-insights-new-insight-button\"attr__draggable=\"true\"attr__href=\"/insights/new\"href=\"/insights/new\"nth-child=\"1\"nth-of-type=\"1\"text=\"New insight\";div.LemonButtonWithSideAction.LemonButtonWithSideAction--small:attr__class=\"LemonButtonWithSideAction LemonButtonWithSideAction--small\"nth-child=\"2\"nth-of-type=\"1\";div.Breadcrumbs3000__actions:attr__class=\"Breadcrumbs3000__actions\"nth-child=\"7\"nth-of-type=\"6\";div.Breadcrumbs3000:attr__class=\"Breadcrumbs3000\"nth-child=\"1\"nth-of-type=\"1\";main:nth-child=\"4\"nth-of-type=\"1\";div.Navigation3000:attr__class=\"Navigation3000\"nth-child=\"1\"nth-of-type=\"1\";div:attr__id=\"root\"attr_id=\"root\"nth-child=\"4\"nth-of-type=\"1\";body.posthog-3000:attr__class=\"posthog-3000\"attr__theme=\"light\"nth-child=\"2\"nth-of-type=\"1\"", + "event": "$autocapture", + "id": "018b4cc2-d79c-7232-afc4-a7c7814d2b09", + "person": null, + "properties": { + "$os": "Mac OS X", + "$os_version": "10.15.7", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/home", + "$host": "localhost:8000", + "$pathname": "/home", + "$browser_version": 117, + "$browser_language": "en-GB", + "$screen_height": 982, + "$screen_width": 1512, + "$viewport_height": 859, + "$viewport_width": 1512, + "$lib": "web", + "$lib_version": "1.84.0", + "$insert_id": "ak2ihfmu0jx88a2d", + "$time": 1697799919.516, + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$device_id": "018a92fd-7b25-7770-a050-577e94fd148c", + "$console_log_recording_enabled_server_side": true, + "$session_recording_recorder_version_server_side": "v2", + "$autocapture_disabled_server_side": false, + "$active_feature_flags": [ + "signup-page-4.0", + "cmd-k-search", + "posthog-3000", + "funnels-cue-opt-out-7301", + "retention-breakdown", + "smoothing-interval", + "billing-limit", + "kafka-inspector", + "historical-exports-v2", + "person-on-events-enabled", + "region-select", + "ingestion-warnings-enabled", + "session-reset-on-load", + "recordings-on-feature-flags", + "auto-rollback-feature-flags", + "onboarding-v2-demo", + "feature-flag-rollout-ux", + "role-based-access", + "query_running_time", + "query-timings", + "recording-debugging", + "enable-prompts", + "feedback-scene", + "early-access-feature", + "early-access-feature-site-button", + "hedgehog-mode-debug", + "auto-redirect", + "session-recording-blob-replay", + "surveys", + "generic-signup-benefits", + "surveys-positions", + "web-analytics", + "high-frequency-batch-exports", + "exception-autocapture", + "data-warehouse", + "data-warehouse-views", + "ff-dashboard-templates", + "show-product-intro-existing-products", + "artificial-hog", + "cs-dashboards", + "product-specific-onboarding", + "redirect-signups-to-instance", + "apps-and-exports-ui", + "survey-nps-results", + "session-recording-allow-v1-snapshots", + "session-replay-cors-proxy", + "webhooks-denylist", + "surveys-site-app-deprecation", + "surveys-multiple-questions", + "surveys-results-visualizations", + "console-recording-search", + "persons-hogql-query", + "notebooks" + ], + "$feature/file-previews": false, + "$feature/signup-page-4.0": "control", + "$feature/hogql-insights": false, + "$feature/cmd-k-search": true, + "$feature/posthog-3000": true, + "$feature/funnels-cue-opt-out-7301": true, + "$feature/retention-breakdown": true, + "$feature/smoothing-interval": true, + "$feature/billing-limit": true, + "$feature/kafka-inspector": true, + "$feature/historical-exports-v2": true, + "$feature/person-on-events-enabled": true, + "$feature/region-select": true, + "$feature/ingestion-warnings-enabled": true, + "$feature/session-reset-on-load": true, + "$feature/recordings-on-feature-flags": true, + "$feature/auto-rollback-feature-flags": true, + "$feature/onboarding-v2-demo": true, + "$feature/feature-flag-rollout-ux": true, + "$feature/role-based-access": true, + "$feature/query_running_time": true, + "$feature/query-timings": true, + "$feature/recording-debugging": true, + "$feature/enable-prompts": true, + "$feature/feedback-scene": true, + "$feature/early-access-feature": true, + "$feature/early-access-feature-site-button": true, + "$feature/hedgehog-mode-debug": true, + "$feature/auto-redirect": true, + "$feature/session-recording-blob-replay": true, + "$feature/surveys": true, + "$feature/generic-signup-benefits": true, + "$feature/surveys-positions": true, + "$feature/web-analytics": true, + "$feature/high-frequency-batch-exports": true, + "$feature/exception-autocapture": true, + "$feature/data-warehouse": true, + "$feature/data-warehouse-views": true, + "$feature/ff-dashboard-templates": true, + "$feature/show-product-intro-existing-products": true, + "$feature/artificial-hog": true, + "$feature/cs-dashboards": true, + "$feature/product-specific-onboarding": true, + "$feature/redirect-signups-to-instance": true, + "$feature/apps-and-exports-ui": true, + "$feature/survey-nps-results": true, + "$feature/session-recording-allow-v1-snapshots": true, + "$feature/session-replay-cors-proxy": true, + "$feature/webhooks-denylist": true, + "$feature/surveys-site-app-deprecation": true, + "$feature/surveys-multiple-questions": true, + "$feature/surveys-results-visualizations": true, + "$feature/console-recording-search": true, + "$feature/persons-hogql-query": true, + "$feature/notebooks": true, + "$feature_flag_payloads": {}, + "realm": "hosted-clickhouse", + "email_service_available": false, + "slack_service_available": false, + "$user_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "is_demo_project": false, + "$groups": { + "project": "018a92f8-b602-0000-75de-4b9073693531", + "organization": "018a92f8-afff-0000-efec-ca77de39e384", + "customer": "cus_OdSgxxWtHOtq9g", + "instance": "http://localhost:8000" + }, + "has_billing_plan": true, + "customer_deactivated": false, + "current_total_amount_usd": "0.00", + "percentage_usage.product_analytics": 0, + "current_amount_usd.product_analytics": "0.00", + "unit_amount_usd.product_analytics": null, + "usage_limit.product_analytics": null, + "current_usage.product_analytics": 3729, + "projected_usage.product_analytics": 0, + "free_allocation.product_analytics": 0, + "percentage_usage.session_replay": 0, + "current_amount_usd.session_replay": "0.00", + "unit_amount_usd.session_replay": null, + "usage_limit.session_replay": null, + "current_usage.session_replay": 254, + "projected_usage.session_replay": 0, + "free_allocation.session_replay": 0, + "percentage_usage.feature_flags": 0, + "current_amount_usd.feature_flags": "0.00", + "unit_amount_usd.feature_flags": null, + "usage_limit.feature_flags": null, + "current_usage.feature_flags": 0, + "projected_usage.feature_flags": 0, + "free_allocation.feature_flags": 0, + "percentage_usage.integrations": 0, + "current_amount_usd.integrations": null, + "unit_amount_usd.integrations": null, + "usage_limit.integrations": 0, + "current_usage.integrations": 0, + "projected_usage.integrations": 0, + "free_allocation.integrations": 0, + "percentage_usage.platform_and_support": 0, + "current_amount_usd.platform_and_support": null, + "unit_amount_usd.platform_and_support": null, + "usage_limit.platform_and_support": 0, + "current_usage.platform_and_support": 0, + "projected_usage.platform_and_support": 0, + "free_allocation.platform_and_support": 0, + "billing_period_start": "2023-10-14T09:22:33.000Z", + "billing_period_end": "2023-11-14T09:22:33.000Z", + "$referrer": "$direct", + "$referring_domain": "$direct", + "$event_type": "click", + "$ce_version": 1, + "$el_text": "New insight", + "token": "phc_OWGI2wKbfi7rWDZT9wkl8uGcfe0wOGCvflLEZSMiaT0", + "$session_id": "018b4cc2-908b-7989-a77a-ae1396eef1de", + "$window_id": "018b4cc2-908b-7989-a77a-ae1465fa2118", + "$ip": "127.0.0.1", + "$set": { + "$os": "Mac OS X", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/home", + "$pathname": "/home", + "$browser_version": 117, + "$referrer": "$direct", + "$referring_domain": "$direct" + }, + "$set_once": { + "$initial_os": "Mac OS X", + "$initial_browser": "Chrome", + "$initial_device_type": "Desktop", + "$initial_current_url": "http://localhost:8000/home", + "$initial_pathname": "/home", + "$initial_browser_version": 117, + "$initial_referrer": "$direct", + "$initial_referring_domain": "$direct" + }, + "$sent_at": "2023-10-20T11:05:22.490000+00:00", + "$geoip_city_name": "Sydney", + "$geoip_country_name": "Australia", + "$geoip_country_code": "AU", + "$geoip_continent_name": "Oceania", + "$geoip_continent_code": "OC", + "$geoip_postal_code": "2000", + "$geoip_latitude": -33.8715, + "$geoip_longitude": 151.2006, + "$geoip_time_zone": "Australia/Sydney", + "$geoip_subdivision_1_code": "NSW", + "$geoip_subdivision_1_name": "New South Wales", + "$plugins_succeeded": ["GeoIP (1)"], + "$plugins_failed": [], + "$plugins_deferred": [], + "$group_3": "018a92f8-b602-0000-75de-4b9073693531", + "$group_2": "018a92f8-afff-0000-efec-ca77de39e384", + "$group_4": "cus_OdSgxxWtHOtq9g", + "$group_1": "http://localhost:8000" + }, + "timestamp": "2023-10-20T11:05:19.533000+00:00", + "uuid": null + }, + { + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "elements": [], + "elements_chain": null, + "event": "$feature_flag_called", + "id": "018b4cc2-d81e-7875-a2ac-8846ffd710c1", + "person": null, + "properties": { + "$os": "Mac OS X", + "$os_version": "10.15.7", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/insights/new", + "$host": "localhost:8000", + "$pathname": "/insights/new", + "$browser_version": 117, + "$browser_language": "en-GB", + "$screen_height": 982, + "$screen_width": 1512, + "$viewport_height": 859, + "$viewport_width": 1512, + "$lib": "web", + "$lib_version": "1.84.0", + "$insert_id": "ccaf8o48a027gcdt", + "$time": 1697799919.646, + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$device_id": "018a92fd-7b25-7770-a050-577e94fd148c", + "$console_log_recording_enabled_server_side": true, + "$session_recording_recorder_version_server_side": "v2", + "$autocapture_disabled_server_side": false, + "$active_feature_flags": [ + "signup-page-4.0", + "cmd-k-search", + "posthog-3000", + "funnels-cue-opt-out-7301", + "retention-breakdown", + "smoothing-interval", + "billing-limit", + "kafka-inspector", + "historical-exports-v2", + "person-on-events-enabled", + "region-select", + "ingestion-warnings-enabled", + "session-reset-on-load", + "recordings-on-feature-flags", + "auto-rollback-feature-flags", + "onboarding-v2-demo", + "feature-flag-rollout-ux", + "role-based-access", + "query_running_time", + "query-timings", + "recording-debugging", + "enable-prompts", + "feedback-scene", + "early-access-feature", + "early-access-feature-site-button", + "hedgehog-mode-debug", + "auto-redirect", + "session-recording-blob-replay", + "surveys", + "generic-signup-benefits", + "surveys-positions", + "web-analytics", + "high-frequency-batch-exports", + "exception-autocapture", + "data-warehouse", + "data-warehouse-views", + "ff-dashboard-templates", + "show-product-intro-existing-products", + "artificial-hog", + "cs-dashboards", + "product-specific-onboarding", + "redirect-signups-to-instance", + "apps-and-exports-ui", + "survey-nps-results", + "session-recording-allow-v1-snapshots", + "session-replay-cors-proxy", + "webhooks-denylist", + "surveys-site-app-deprecation", + "surveys-multiple-questions", + "surveys-results-visualizations", + "console-recording-search", + "persons-hogql-query", + "notebooks" + ], + "$feature/file-previews": false, + "$feature/signup-page-4.0": "control", + "$feature/hogql-insights": false, + "$feature/cmd-k-search": true, + "$feature/posthog-3000": true, + "$feature/funnels-cue-opt-out-7301": true, + "$feature/retention-breakdown": true, + "$feature/smoothing-interval": true, + "$feature/billing-limit": true, + "$feature/kafka-inspector": true, + "$feature/historical-exports-v2": true, + "$feature/person-on-events-enabled": true, + "$feature/region-select": true, + "$feature/ingestion-warnings-enabled": true, + "$feature/session-reset-on-load": true, + "$feature/recordings-on-feature-flags": true, + "$feature/auto-rollback-feature-flags": true, + "$feature/onboarding-v2-demo": true, + "$feature/feature-flag-rollout-ux": true, + "$feature/role-based-access": true, + "$feature/query_running_time": true, + "$feature/query-timings": true, + "$feature/recording-debugging": true, + "$feature/enable-prompts": true, + "$feature/feedback-scene": true, + "$feature/early-access-feature": true, + "$feature/early-access-feature-site-button": true, + "$feature/hedgehog-mode-debug": true, + "$feature/auto-redirect": true, + "$feature/session-recording-blob-replay": true, + "$feature/surveys": true, + "$feature/generic-signup-benefits": true, + "$feature/surveys-positions": true, + "$feature/web-analytics": true, + "$feature/high-frequency-batch-exports": true, + "$feature/exception-autocapture": true, + "$feature/data-warehouse": true, + "$feature/data-warehouse-views": true, + "$feature/ff-dashboard-templates": true, + "$feature/show-product-intro-existing-products": true, + "$feature/artificial-hog": true, + "$feature/cs-dashboards": true, + "$feature/product-specific-onboarding": true, + "$feature/redirect-signups-to-instance": true, + "$feature/apps-and-exports-ui": true, + "$feature/survey-nps-results": true, + "$feature/session-recording-allow-v1-snapshots": true, + "$feature/session-replay-cors-proxy": true, + "$feature/webhooks-denylist": true, + "$feature/surveys-site-app-deprecation": true, + "$feature/surveys-multiple-questions": true, + "$feature/surveys-results-visualizations": true, + "$feature/console-recording-search": true, + "$feature/persons-hogql-query": true, + "$feature/notebooks": true, + "$feature_flag_payloads": {}, + "realm": "hosted-clickhouse", + "email_service_available": false, + "slack_service_available": false, + "$user_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "is_demo_project": false, + "$groups": { + "project": "018a92f8-b602-0000-75de-4b9073693531", + "organization": "018a92f8-afff-0000-efec-ca77de39e384", + "customer": "cus_OdSgxxWtHOtq9g", + "instance": "http://localhost:8000" + }, + "has_billing_plan": true, + "customer_deactivated": false, + "current_total_amount_usd": "0.00", + "percentage_usage.product_analytics": 0, + "current_amount_usd.product_analytics": "0.00", + "unit_amount_usd.product_analytics": null, + "usage_limit.product_analytics": null, + "current_usage.product_analytics": 3729, + "projected_usage.product_analytics": 0, + "free_allocation.product_analytics": 0, + "percentage_usage.session_replay": 0, + "current_amount_usd.session_replay": "0.00", + "unit_amount_usd.session_replay": null, + "usage_limit.session_replay": null, + "current_usage.session_replay": 254, + "projected_usage.session_replay": 0, + "free_allocation.session_replay": 0, + "percentage_usage.feature_flags": 0, + "current_amount_usd.feature_flags": "0.00", + "unit_amount_usd.feature_flags": null, + "usage_limit.feature_flags": null, + "current_usage.feature_flags": 0, + "projected_usage.feature_flags": 0, + "free_allocation.feature_flags": 0, + "percentage_usage.integrations": 0, + "current_amount_usd.integrations": null, + "unit_amount_usd.integrations": null, + "usage_limit.integrations": 0, + "current_usage.integrations": 0, + "projected_usage.integrations": 0, + "free_allocation.integrations": 0, + "percentage_usage.platform_and_support": 0, + "current_amount_usd.platform_and_support": null, + "unit_amount_usd.platform_and_support": null, + "usage_limit.platform_and_support": 0, + "current_usage.platform_and_support": 0, + "projected_usage.platform_and_support": 0, + "free_allocation.platform_and_support": 0, + "billing_period_start": "2023-10-14T09:22:33.000Z", + "billing_period_end": "2023-11-14T09:22:33.000Z", + "$referrer": "$direct", + "$referring_domain": "$direct", + "$feature_flag": "funnels-cue-opt-out-7301", + "$feature_flag_response": true, + "token": "phc_OWGI2wKbfi7rWDZT9wkl8uGcfe0wOGCvflLEZSMiaT0", + "$session_id": "018b4cc2-908b-7989-a77a-ae1396eef1de", + "$window_id": "018b4cc2-908b-7989-a77a-ae1465fa2118", + "$ip": "127.0.0.1", + "$set": { + "$os": "Mac OS X", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/insights/new", + "$pathname": "/insights/new", + "$browser_version": 117, + "$referrer": "$direct", + "$referring_domain": "$direct" + }, + "$set_once": { + "$initial_os": "Mac OS X", + "$initial_browser": "Chrome", + "$initial_device_type": "Desktop", + "$initial_current_url": "http://localhost:8000/insights/new", + "$initial_pathname": "/insights/new", + "$initial_browser_version": 117, + "$initial_referrer": "$direct", + "$initial_referring_domain": "$direct" + }, + "$sent_at": "2023-10-20T11:05:22.490000+00:00", + "$geoip_city_name": "Sydney", + "$geoip_country_name": "Australia", + "$geoip_country_code": "AU", + "$geoip_continent_name": "Oceania", + "$geoip_continent_code": "OC", + "$geoip_postal_code": "2000", + "$geoip_latitude": -33.8715, + "$geoip_longitude": 151.2006, + "$geoip_time_zone": "Australia/Sydney", + "$geoip_subdivision_1_code": "NSW", + "$geoip_subdivision_1_name": "New South Wales", + "$plugins_succeeded": ["GeoIP (1)"], + "$plugins_failed": [], + "$plugins_deferred": [], + "$group_3": "018a92f8-b602-0000-75de-4b9073693531", + "$group_2": "018a92f8-afff-0000-efec-ca77de39e384", + "$group_4": "cus_OdSgxxWtHOtq9g", + "$group_1": "http://localhost:8000" + }, + "timestamp": "2023-10-20T11:05:19.663000+00:00", + "uuid": null + }, + { + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "elements": [], + "elements_chain": null, + "event": "$feature_flag_called", + "id": "018b4cc2-d835-7d31-af5a-5294ec922967", + "person": null, + "properties": { + "$os": "Mac OS X", + "$os_version": "10.15.7", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/insights/new", + "$host": "localhost:8000", + "$pathname": "/insights/new", + "$browser_version": 117, + "$browser_language": "en-GB", + "$screen_height": 982, + "$screen_width": 1512, + "$viewport_height": 859, + "$viewport_width": 1512, + "$lib": "web", + "$lib_version": "1.84.0", + "$insert_id": "fnd160khukj3ji6d", + "$time": 1697799919.669, + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$device_id": "018a92fd-7b25-7770-a050-577e94fd148c", + "$console_log_recording_enabled_server_side": true, + "$session_recording_recorder_version_server_side": "v2", + "$autocapture_disabled_server_side": false, + "$active_feature_flags": [ + "signup-page-4.0", + "cmd-k-search", + "posthog-3000", + "funnels-cue-opt-out-7301", + "retention-breakdown", + "smoothing-interval", + "billing-limit", + "kafka-inspector", + "historical-exports-v2", + "person-on-events-enabled", + "region-select", + "ingestion-warnings-enabled", + "session-reset-on-load", + "recordings-on-feature-flags", + "auto-rollback-feature-flags", + "onboarding-v2-demo", + "feature-flag-rollout-ux", + "role-based-access", + "query_running_time", + "query-timings", + "recording-debugging", + "enable-prompts", + "feedback-scene", + "early-access-feature", + "early-access-feature-site-button", + "hedgehog-mode-debug", + "auto-redirect", + "session-recording-blob-replay", + "surveys", + "generic-signup-benefits", + "surveys-positions", + "web-analytics", + "high-frequency-batch-exports", + "exception-autocapture", + "data-warehouse", + "data-warehouse-views", + "ff-dashboard-templates", + "show-product-intro-existing-products", + "artificial-hog", + "cs-dashboards", + "product-specific-onboarding", + "redirect-signups-to-instance", + "apps-and-exports-ui", + "survey-nps-results", + "session-recording-allow-v1-snapshots", + "session-replay-cors-proxy", + "webhooks-denylist", + "surveys-site-app-deprecation", + "surveys-multiple-questions", + "surveys-results-visualizations", + "console-recording-search", + "persons-hogql-query", + "notebooks" + ], + "$feature/file-previews": false, + "$feature/signup-page-4.0": "control", + "$feature/hogql-insights": false, + "$feature/cmd-k-search": true, + "$feature/posthog-3000": true, + "$feature/funnels-cue-opt-out-7301": true, + "$feature/retention-breakdown": true, + "$feature/smoothing-interval": true, + "$feature/billing-limit": true, + "$feature/kafka-inspector": true, + "$feature/historical-exports-v2": true, + "$feature/person-on-events-enabled": true, + "$feature/region-select": true, + "$feature/ingestion-warnings-enabled": true, + "$feature/session-reset-on-load": true, + "$feature/recordings-on-feature-flags": true, + "$feature/auto-rollback-feature-flags": true, + "$feature/onboarding-v2-demo": true, + "$feature/feature-flag-rollout-ux": true, + "$feature/role-based-access": true, + "$feature/query_running_time": true, + "$feature/query-timings": true, + "$feature/recording-debugging": true, + "$feature/enable-prompts": true, + "$feature/feedback-scene": true, + "$feature/early-access-feature": true, + "$feature/early-access-feature-site-button": true, + "$feature/hedgehog-mode-debug": true, + "$feature/auto-redirect": true, + "$feature/session-recording-blob-replay": true, + "$feature/surveys": true, + "$feature/generic-signup-benefits": true, + "$feature/surveys-positions": true, + "$feature/web-analytics": true, + "$feature/high-frequency-batch-exports": true, + "$feature/exception-autocapture": true, + "$feature/data-warehouse": true, + "$feature/data-warehouse-views": true, + "$feature/ff-dashboard-templates": true, + "$feature/show-product-intro-existing-products": true, + "$feature/artificial-hog": true, + "$feature/cs-dashboards": true, + "$feature/product-specific-onboarding": true, + "$feature/redirect-signups-to-instance": true, + "$feature/apps-and-exports-ui": true, + "$feature/survey-nps-results": true, + "$feature/session-recording-allow-v1-snapshots": true, + "$feature/session-replay-cors-proxy": true, + "$feature/webhooks-denylist": true, + "$feature/surveys-site-app-deprecation": true, + "$feature/surveys-multiple-questions": true, + "$feature/surveys-results-visualizations": true, + "$feature/console-recording-search": true, + "$feature/persons-hogql-query": true, + "$feature/notebooks": true, + "$feature_flag_payloads": {}, + "realm": "hosted-clickhouse", + "email_service_available": false, + "slack_service_available": false, + "$user_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "is_demo_project": false, + "$groups": { + "project": "018a92f8-b602-0000-75de-4b9073693531", + "organization": "018a92f8-afff-0000-efec-ca77de39e384", + "customer": "cus_OdSgxxWtHOtq9g", + "instance": "http://localhost:8000" + }, + "has_billing_plan": true, + "customer_deactivated": false, + "current_total_amount_usd": "0.00", + "percentage_usage.product_analytics": 0, + "current_amount_usd.product_analytics": "0.00", + "unit_amount_usd.product_analytics": null, + "usage_limit.product_analytics": null, + "current_usage.product_analytics": 3729, + "projected_usage.product_analytics": 0, + "free_allocation.product_analytics": 0, + "percentage_usage.session_replay": 0, + "current_amount_usd.session_replay": "0.00", + "unit_amount_usd.session_replay": null, + "usage_limit.session_replay": null, + "current_usage.session_replay": 254, + "projected_usage.session_replay": 0, + "free_allocation.session_replay": 0, + "percentage_usage.feature_flags": 0, + "current_amount_usd.feature_flags": "0.00", + "unit_amount_usd.feature_flags": null, + "usage_limit.feature_flags": null, + "current_usage.feature_flags": 0, + "projected_usage.feature_flags": 0, + "free_allocation.feature_flags": 0, + "percentage_usage.integrations": 0, + "current_amount_usd.integrations": null, + "unit_amount_usd.integrations": null, + "usage_limit.integrations": 0, + "current_usage.integrations": 0, + "projected_usage.integrations": 0, + "free_allocation.integrations": 0, + "percentage_usage.platform_and_support": 0, + "current_amount_usd.platform_and_support": null, + "unit_amount_usd.platform_and_support": null, + "usage_limit.platform_and_support": 0, + "current_usage.platform_and_support": 0, + "projected_usage.platform_and_support": 0, + "free_allocation.platform_and_support": 0, + "billing_period_start": "2023-10-14T09:22:33.000Z", + "billing_period_end": "2023-11-14T09:22:33.000Z", + "$referrer": "$direct", + "$referring_domain": "$direct", + "$feature_flag": "smoothing-interval", + "$feature_flag_response": true, + "token": "phc_OWGI2wKbfi7rWDZT9wkl8uGcfe0wOGCvflLEZSMiaT0", + "$session_id": "018b4cc2-908b-7989-a77a-ae1396eef1de", + "$window_id": "018b4cc2-908b-7989-a77a-ae1465fa2118", + "$ip": "127.0.0.1", + "$set": { + "$os": "Mac OS X", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/insights/new", + "$pathname": "/insights/new", + "$browser_version": 117, + "$referrer": "$direct", + "$referring_domain": "$direct" + }, + "$set_once": { + "$initial_os": "Mac OS X", + "$initial_browser": "Chrome", + "$initial_device_type": "Desktop", + "$initial_current_url": "http://localhost:8000/insights/new", + "$initial_pathname": "/insights/new", + "$initial_browser_version": 117, + "$initial_referrer": "$direct", + "$initial_referring_domain": "$direct" + }, + "$sent_at": "2023-10-20T11:05:22.490000+00:00", + "$geoip_city_name": "Sydney", + "$geoip_country_name": "Australia", + "$geoip_country_code": "AU", + "$geoip_continent_name": "Oceania", + "$geoip_continent_code": "OC", + "$geoip_postal_code": "2000", + "$geoip_latitude": -33.8715, + "$geoip_longitude": 151.2006, + "$geoip_time_zone": "Australia/Sydney", + "$geoip_subdivision_1_code": "NSW", + "$geoip_subdivision_1_name": "New South Wales", + "$plugins_succeeded": ["GeoIP (1)"], + "$plugins_failed": [], + "$plugins_deferred": [], + "$group_3": "018a92f8-b602-0000-75de-4b9073693531", + "$group_2": "018a92f8-afff-0000-efec-ca77de39e384", + "$group_4": "cus_OdSgxxWtHOtq9g", + "$group_1": "http://localhost:8000" + }, + "timestamp": "2023-10-20T11:05:19.686000+00:00", + "uuid": null + }, + { + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "elements": [], + "elements_chain": null, + "event": "$pageview", + "id": "018b4cc2-d922-77e2-bc50-8d34466436e3", + "person": null, + "properties": { + "$os": "Mac OS X", + "$os_version": "10.15.7", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/insights/new", + "$host": "localhost:8000", + "$pathname": "/insights/new", + "$browser_version": 117, + "$browser_language": "en-GB", + "$screen_height": 982, + "$screen_width": 1512, + "$viewport_height": 859, + "$viewport_width": 1512, + "$lib": "web", + "$lib_version": "1.84.0", + "$insert_id": "p3n4m8xa3afpo3tx", + "$time": 1697799919.906, + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$device_id": "018a92fd-7b25-7770-a050-577e94fd148c", + "$console_log_recording_enabled_server_side": true, + "$session_recording_recorder_version_server_side": "v2", + "$autocapture_disabled_server_side": false, + "$active_feature_flags": [ + "signup-page-4.0", + "cmd-k-search", + "posthog-3000", + "funnels-cue-opt-out-7301", + "retention-breakdown", + "smoothing-interval", + "billing-limit", + "kafka-inspector", + "historical-exports-v2", + "person-on-events-enabled", + "region-select", + "ingestion-warnings-enabled", + "session-reset-on-load", + "recordings-on-feature-flags", + "auto-rollback-feature-flags", + "onboarding-v2-demo", + "feature-flag-rollout-ux", + "role-based-access", + "query_running_time", + "query-timings", + "recording-debugging", + "enable-prompts", + "feedback-scene", + "early-access-feature", + "early-access-feature-site-button", + "hedgehog-mode-debug", + "auto-redirect", + "session-recording-blob-replay", + "surveys", + "generic-signup-benefits", + "surveys-positions", + "web-analytics", + "high-frequency-batch-exports", + "exception-autocapture", + "data-warehouse", + "data-warehouse-views", + "ff-dashboard-templates", + "show-product-intro-existing-products", + "artificial-hog", + "cs-dashboards", + "product-specific-onboarding", + "redirect-signups-to-instance", + "apps-and-exports-ui", + "survey-nps-results", + "session-recording-allow-v1-snapshots", + "session-replay-cors-proxy", + "webhooks-denylist", + "surveys-site-app-deprecation", + "surveys-multiple-questions", + "surveys-results-visualizations", + "console-recording-search", + "persons-hogql-query", + "notebooks" + ], + "$feature/file-previews": false, + "$feature/signup-page-4.0": "control", + "$feature/hogql-insights": false, + "$feature/cmd-k-search": true, + "$feature/posthog-3000": true, + "$feature/funnels-cue-opt-out-7301": true, + "$feature/retention-breakdown": true, + "$feature/smoothing-interval": true, + "$feature/billing-limit": true, + "$feature/kafka-inspector": true, + "$feature/historical-exports-v2": true, + "$feature/person-on-events-enabled": true, + "$feature/region-select": true, + "$feature/ingestion-warnings-enabled": true, + "$feature/session-reset-on-load": true, + "$feature/recordings-on-feature-flags": true, + "$feature/auto-rollback-feature-flags": true, + "$feature/onboarding-v2-demo": true, + "$feature/feature-flag-rollout-ux": true, + "$feature/role-based-access": true, + "$feature/query_running_time": true, + "$feature/query-timings": true, + "$feature/recording-debugging": true, + "$feature/enable-prompts": true, + "$feature/feedback-scene": true, + "$feature/early-access-feature": true, + "$feature/early-access-feature-site-button": true, + "$feature/hedgehog-mode-debug": true, + "$feature/auto-redirect": true, + "$feature/session-recording-blob-replay": true, + "$feature/surveys": true, + "$feature/generic-signup-benefits": true, + "$feature/surveys-positions": true, + "$feature/web-analytics": true, + "$feature/high-frequency-batch-exports": true, + "$feature/exception-autocapture": true, + "$feature/data-warehouse": true, + "$feature/data-warehouse-views": true, + "$feature/ff-dashboard-templates": true, + "$feature/show-product-intro-existing-products": true, + "$feature/artificial-hog": true, + "$feature/cs-dashboards": true, + "$feature/product-specific-onboarding": true, + "$feature/redirect-signups-to-instance": true, + "$feature/apps-and-exports-ui": true, + "$feature/survey-nps-results": true, + "$feature/session-recording-allow-v1-snapshots": true, + "$feature/session-replay-cors-proxy": true, + "$feature/webhooks-denylist": true, + "$feature/surveys-site-app-deprecation": true, + "$feature/surveys-multiple-questions": true, + "$feature/surveys-results-visualizations": true, + "$feature/console-recording-search": true, + "$feature/persons-hogql-query": true, + "$feature/notebooks": true, + "$feature_flag_payloads": {}, + "realm": "hosted-clickhouse", + "email_service_available": false, + "slack_service_available": false, + "$user_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "is_demo_project": false, + "$groups": { + "project": "018a92f8-b602-0000-75de-4b9073693531", + "organization": "018a92f8-afff-0000-efec-ca77de39e384", + "customer": "cus_OdSgxxWtHOtq9g", + "instance": "http://localhost:8000" + }, + "has_billing_plan": true, + "customer_deactivated": false, + "current_total_amount_usd": "0.00", + "percentage_usage.product_analytics": 0, + "current_amount_usd.product_analytics": "0.00", + "unit_amount_usd.product_analytics": null, + "usage_limit.product_analytics": null, + "current_usage.product_analytics": 3729, + "projected_usage.product_analytics": 0, + "free_allocation.product_analytics": 0, + "percentage_usage.session_replay": 0, + "current_amount_usd.session_replay": "0.00", + "unit_amount_usd.session_replay": null, + "usage_limit.session_replay": null, + "current_usage.session_replay": 254, + "projected_usage.session_replay": 0, + "free_allocation.session_replay": 0, + "percentage_usage.feature_flags": 0, + "current_amount_usd.feature_flags": "0.00", + "unit_amount_usd.feature_flags": null, + "usage_limit.feature_flags": null, + "current_usage.feature_flags": 0, + "projected_usage.feature_flags": 0, + "free_allocation.feature_flags": 0, + "percentage_usage.integrations": 0, + "current_amount_usd.integrations": null, + "unit_amount_usd.integrations": null, + "usage_limit.integrations": 0, + "current_usage.integrations": 0, + "projected_usage.integrations": 0, + "free_allocation.integrations": 0, + "percentage_usage.platform_and_support": 0, + "current_amount_usd.platform_and_support": null, + "unit_amount_usd.platform_and_support": null, + "usage_limit.platform_and_support": 0, + "current_usage.platform_and_support": 0, + "projected_usage.platform_and_support": 0, + "free_allocation.platform_and_support": 0, + "billing_period_start": "2023-10-14T09:22:33.000Z", + "billing_period_end": "2023-11-14T09:22:33.000Z", + "$referrer": "$direct", + "$referring_domain": "$direct", + "token": "phc_OWGI2wKbfi7rWDZT9wkl8uGcfe0wOGCvflLEZSMiaT0", + "$session_id": "018b4cc2-908b-7989-a77a-ae1396eef1de", + "$window_id": "018b4cc2-908b-7989-a77a-ae1465fa2118", + "title": "Unnamed \u2022 Insights \u2022 PostHog", + "$ip": "127.0.0.1", + "$set": { + "$os": "Mac OS X", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/insights/new", + "$pathname": "/insights/new", + "$browser_version": 117, + "$referrer": "$direct", + "$referring_domain": "$direct" + }, + "$set_once": { + "$initial_os": "Mac OS X", + "$initial_browser": "Chrome", + "$initial_device_type": "Desktop", + "$initial_current_url": "http://localhost:8000/insights/new", + "$initial_pathname": "/insights/new", + "$initial_browser_version": 117, + "$initial_referrer": "$direct", + "$initial_referring_domain": "$direct" + }, + "$sent_at": "2023-10-20T11:05:22.490000+00:00", + "$geoip_city_name": "Sydney", + "$geoip_country_name": "Australia", + "$geoip_country_code": "AU", + "$geoip_continent_name": "Oceania", + "$geoip_continent_code": "OC", + "$geoip_postal_code": "2000", + "$geoip_latitude": -33.8715, + "$geoip_longitude": 151.2006, + "$geoip_time_zone": "Australia/Sydney", + "$geoip_subdivision_1_code": "NSW", + "$geoip_subdivision_1_name": "New South Wales", + "$plugins_succeeded": ["GeoIP (1)"], + "$plugins_failed": [], + "$plugins_deferred": [], + "$group_3": "018a92f8-b602-0000-75de-4b9073693531", + "$group_2": "018a92f8-afff-0000-efec-ca77de39e384", + "$group_4": "cus_OdSgxxWtHOtq9g", + "$group_1": "http://localhost:8000" + }, + "timestamp": "2023-10-20T11:05:19.923000+00:00", + "uuid": null + }, + { + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "elements": [], + "elements_chain": null, + "event": "query completed", + "id": "018b4cc2-d937-7dc2-a69b-339daae7720d", + "person": null, + "properties": { + "$os": "Mac OS X", + "$os_version": "10.15.7", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/insights/new", + "$host": "localhost:8000", + "$pathname": "/insights/new", + "$browser_version": 117, + "$browser_language": "en-GB", + "$screen_height": 982, + "$screen_width": 1512, + "$viewport_height": 859, + "$viewport_width": 1512, + "$lib": "web", + "$lib_version": "1.84.0", + "$insert_id": "b1ukfohazj37608n", + "$time": 1697799919.927, + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$device_id": "018a92fd-7b25-7770-a050-577e94fd148c", + "$console_log_recording_enabled_server_side": true, + "$session_recording_recorder_version_server_side": "v2", + "$autocapture_disabled_server_side": false, + "$active_feature_flags": [ + "signup-page-4.0", + "cmd-k-search", + "posthog-3000", + "funnels-cue-opt-out-7301", + "retention-breakdown", + "smoothing-interval", + "billing-limit", + "kafka-inspector", + "historical-exports-v2", + "person-on-events-enabled", + "region-select", + "ingestion-warnings-enabled", + "session-reset-on-load", + "recordings-on-feature-flags", + "auto-rollback-feature-flags", + "onboarding-v2-demo", + "feature-flag-rollout-ux", + "role-based-access", + "query_running_time", + "query-timings", + "recording-debugging", + "enable-prompts", + "feedback-scene", + "early-access-feature", + "early-access-feature-site-button", + "hedgehog-mode-debug", + "auto-redirect", + "session-recording-blob-replay", + "surveys", + "generic-signup-benefits", + "surveys-positions", + "web-analytics", + "high-frequency-batch-exports", + "exception-autocapture", + "data-warehouse", + "data-warehouse-views", + "ff-dashboard-templates", + "show-product-intro-existing-products", + "artificial-hog", + "cs-dashboards", + "product-specific-onboarding", + "redirect-signups-to-instance", + "apps-and-exports-ui", + "survey-nps-results", + "session-recording-allow-v1-snapshots", + "session-replay-cors-proxy", + "webhooks-denylist", + "surveys-site-app-deprecation", + "surveys-multiple-questions", + "surveys-results-visualizations", + "console-recording-search", + "persons-hogql-query", + "notebooks" + ], + "$feature/file-previews": false, + "$feature/signup-page-4.0": "control", + "$feature/hogql-insights": false, + "$feature/cmd-k-search": true, + "$feature/posthog-3000": true, + "$feature/funnels-cue-opt-out-7301": true, + "$feature/retention-breakdown": true, + "$feature/smoothing-interval": true, + "$feature/billing-limit": true, + "$feature/kafka-inspector": true, + "$feature/historical-exports-v2": true, + "$feature/person-on-events-enabled": true, + "$feature/region-select": true, + "$feature/ingestion-warnings-enabled": true, + "$feature/session-reset-on-load": true, + "$feature/recordings-on-feature-flags": true, + "$feature/auto-rollback-feature-flags": true, + "$feature/onboarding-v2-demo": true, + "$feature/feature-flag-rollout-ux": true, + "$feature/role-based-access": true, + "$feature/query_running_time": true, + "$feature/query-timings": true, + "$feature/recording-debugging": true, + "$feature/enable-prompts": true, + "$feature/feedback-scene": true, + "$feature/early-access-feature": true, + "$feature/early-access-feature-site-button": true, + "$feature/hedgehog-mode-debug": true, + "$feature/auto-redirect": true, + "$feature/session-recording-blob-replay": true, + "$feature/surveys": true, + "$feature/generic-signup-benefits": true, + "$feature/surveys-positions": true, + "$feature/web-analytics": true, + "$feature/high-frequency-batch-exports": true, + "$feature/exception-autocapture": true, + "$feature/data-warehouse": true, + "$feature/data-warehouse-views": true, + "$feature/ff-dashboard-templates": true, + "$feature/show-product-intro-existing-products": true, + "$feature/artificial-hog": true, + "$feature/cs-dashboards": true, + "$feature/product-specific-onboarding": true, + "$feature/redirect-signups-to-instance": true, + "$feature/apps-and-exports-ui": true, + "$feature/survey-nps-results": true, + "$feature/session-recording-allow-v1-snapshots": true, + "$feature/session-replay-cors-proxy": true, + "$feature/webhooks-denylist": true, + "$feature/surveys-site-app-deprecation": true, + "$feature/surveys-multiple-questions": true, + "$feature/surveys-results-visualizations": true, + "$feature/console-recording-search": true, + "$feature/persons-hogql-query": true, + "$feature/notebooks": true, + "$feature_flag_payloads": {}, + "realm": "hosted-clickhouse", + "email_service_available": false, + "slack_service_available": false, + "$user_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "is_demo_project": false, + "$groups": { + "project": "018a92f8-b602-0000-75de-4b9073693531", + "organization": "018a92f8-afff-0000-efec-ca77de39e384", + "customer": "cus_OdSgxxWtHOtq9g", + "instance": "http://localhost:8000" + }, + "has_billing_plan": true, + "customer_deactivated": false, + "current_total_amount_usd": "0.00", + "percentage_usage.product_analytics": 0, + "current_amount_usd.product_analytics": "0.00", + "unit_amount_usd.product_analytics": null, + "usage_limit.product_analytics": null, + "current_usage.product_analytics": 3729, + "projected_usage.product_analytics": 0, + "free_allocation.product_analytics": 0, + "percentage_usage.session_replay": 0, + "current_amount_usd.session_replay": "0.00", + "unit_amount_usd.session_replay": null, + "usage_limit.session_replay": null, + "current_usage.session_replay": 254, + "projected_usage.session_replay": 0, + "free_allocation.session_replay": 0, + "percentage_usage.feature_flags": 0, + "current_amount_usd.feature_flags": "0.00", + "unit_amount_usd.feature_flags": null, + "usage_limit.feature_flags": null, + "current_usage.feature_flags": 0, + "projected_usage.feature_flags": 0, + "free_allocation.feature_flags": 0, + "percentage_usage.integrations": 0, + "current_amount_usd.integrations": null, + "unit_amount_usd.integrations": null, + "usage_limit.integrations": 0, + "current_usage.integrations": 0, + "projected_usage.integrations": 0, + "free_allocation.integrations": 0, + "percentage_usage.platform_and_support": 0, + "current_amount_usd.platform_and_support": null, + "unit_amount_usd.platform_and_support": null, + "usage_limit.platform_and_support": 0, + "current_usage.platform_and_support": 0, + "projected_usage.platform_and_support": 0, + "free_allocation.platform_and_support": 0, + "billing_period_start": "2023-10-14T09:22:33.000Z", + "billing_period_end": "2023-11-14T09:22:33.000Z", + "$referrer": "$direct", + "$referring_domain": "$direct", + "query": { + "kind": "TrendsQuery", + "filterTestAccounts": false, + "series": [ + { + "kind": "EventsNode", + "event": "$pageview", + "name": "$pageview", + "math": "total" + } + ], + "interval": "day", + "trendsFilter": { + "display": "ActionsLineGraph" + } + }, + "duration": 275.5999999642372, + "token": "phc_OWGI2wKbfi7rWDZT9wkl8uGcfe0wOGCvflLEZSMiaT0", + "$session_id": "018b4cc2-908b-7989-a77a-ae1396eef1de", + "$window_id": "018b4cc2-908b-7989-a77a-ae1465fa2118", + "$ip": "127.0.0.1", + "$set": { + "$os": "Mac OS X", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/insights/new", + "$pathname": "/insights/new", + "$browser_version": 117, + "$referrer": "$direct", + "$referring_domain": "$direct" + }, + "$set_once": { + "$initial_os": "Mac OS X", + "$initial_browser": "Chrome", + "$initial_device_type": "Desktop", + "$initial_current_url": "http://localhost:8000/insights/new", + "$initial_pathname": "/insights/new", + "$initial_browser_version": 117, + "$initial_referrer": "$direct", + "$initial_referring_domain": "$direct" + }, + "$sent_at": "2023-10-20T11:05:22.490000+00:00", + "$geoip_city_name": "Sydney", + "$geoip_country_name": "Australia", + "$geoip_country_code": "AU", + "$geoip_continent_name": "Oceania", + "$geoip_continent_code": "OC", + "$geoip_postal_code": "2000", + "$geoip_latitude": -33.8715, + "$geoip_longitude": 151.2006, + "$geoip_time_zone": "Australia/Sydney", + "$geoip_subdivision_1_code": "NSW", + "$geoip_subdivision_1_name": "New South Wales", + "$plugins_succeeded": ["GeoIP (1)"], + "$plugins_failed": [], + "$plugins_deferred": [], + "$group_3": "018a92f8-b602-0000-75de-4b9073693531", + "$group_2": "018a92f8-afff-0000-efec-ca77de39e384", + "$group_4": "cus_OdSgxxWtHOtq9g", + "$group_1": "http://localhost:8000" + }, + "timestamp": "2023-10-20T11:05:19.944000+00:00", + "uuid": null + }, + { + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "elements": [], + "elements_chain": null, + "event": "insight created", + "id": "018b4cc2-d9b7-7c1f-a9e9-94c564b7a7de", + "person": null, + "properties": { + "$os": "Mac OS X", + "$os_version": "10.15.7", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/insights/new", + "$host": "localhost:8000", + "$pathname": "/insights/new", + "$browser_version": 117, + "$browser_language": "en-GB", + "$screen_height": 982, + "$screen_width": 1512, + "$viewport_height": 859, + "$viewport_width": 1512, + "$lib": "web", + "$lib_version": "1.84.0", + "$insert_id": "wj66f9ygnvcad5wh", + "$time": 1697799920.055, + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$device_id": "018a92fd-7b25-7770-a050-577e94fd148c", + "$console_log_recording_enabled_server_side": true, + "$session_recording_recorder_version_server_side": "v2", + "$autocapture_disabled_server_side": false, + "$active_feature_flags": [ + "signup-page-4.0", + "cmd-k-search", + "posthog-3000", + "funnels-cue-opt-out-7301", + "retention-breakdown", + "smoothing-interval", + "billing-limit", + "kafka-inspector", + "historical-exports-v2", + "person-on-events-enabled", + "region-select", + "ingestion-warnings-enabled", + "session-reset-on-load", + "recordings-on-feature-flags", + "auto-rollback-feature-flags", + "onboarding-v2-demo", + "feature-flag-rollout-ux", + "role-based-access", + "query_running_time", + "query-timings", + "recording-debugging", + "enable-prompts", + "feedback-scene", + "early-access-feature", + "early-access-feature-site-button", + "hedgehog-mode-debug", + "auto-redirect", + "session-recording-blob-replay", + "surveys", + "generic-signup-benefits", + "surveys-positions", + "web-analytics", + "high-frequency-batch-exports", + "exception-autocapture", + "data-warehouse", + "data-warehouse-views", + "ff-dashboard-templates", + "show-product-intro-existing-products", + "artificial-hog", + "cs-dashboards", + "product-specific-onboarding", + "redirect-signups-to-instance", + "apps-and-exports-ui", + "survey-nps-results", + "session-recording-allow-v1-snapshots", + "session-replay-cors-proxy", + "webhooks-denylist", + "surveys-site-app-deprecation", + "surveys-multiple-questions", + "surveys-results-visualizations", + "console-recording-search", + "persons-hogql-query", + "notebooks" + ], + "$feature/file-previews": false, + "$feature/signup-page-4.0": "control", + "$feature/hogql-insights": false, + "$feature/cmd-k-search": true, + "$feature/posthog-3000": true, + "$feature/funnels-cue-opt-out-7301": true, + "$feature/retention-breakdown": true, + "$feature/smoothing-interval": true, + "$feature/billing-limit": true, + "$feature/kafka-inspector": true, + "$feature/historical-exports-v2": true, + "$feature/person-on-events-enabled": true, + "$feature/region-select": true, + "$feature/ingestion-warnings-enabled": true, + "$feature/session-reset-on-load": true, + "$feature/recordings-on-feature-flags": true, + "$feature/auto-rollback-feature-flags": true, + "$feature/onboarding-v2-demo": true, + "$feature/feature-flag-rollout-ux": true, + "$feature/role-based-access": true, + "$feature/query_running_time": true, + "$feature/query-timings": true, + "$feature/recording-debugging": true, + "$feature/enable-prompts": true, + "$feature/feedback-scene": true, + "$feature/early-access-feature": true, + "$feature/early-access-feature-site-button": true, + "$feature/hedgehog-mode-debug": true, + "$feature/auto-redirect": true, + "$feature/session-recording-blob-replay": true, + "$feature/surveys": true, + "$feature/generic-signup-benefits": true, + "$feature/surveys-positions": true, + "$feature/web-analytics": true, + "$feature/high-frequency-batch-exports": true, + "$feature/exception-autocapture": true, + "$feature/data-warehouse": true, + "$feature/data-warehouse-views": true, + "$feature/ff-dashboard-templates": true, + "$feature/show-product-intro-existing-products": true, + "$feature/artificial-hog": true, + "$feature/cs-dashboards": true, + "$feature/product-specific-onboarding": true, + "$feature/redirect-signups-to-instance": true, + "$feature/apps-and-exports-ui": true, + "$feature/survey-nps-results": true, + "$feature/session-recording-allow-v1-snapshots": true, + "$feature/session-replay-cors-proxy": true, + "$feature/webhooks-denylist": true, + "$feature/surveys-site-app-deprecation": true, + "$feature/surveys-multiple-questions": true, + "$feature/surveys-results-visualizations": true, + "$feature/console-recording-search": true, + "$feature/persons-hogql-query": true, + "$feature/notebooks": true, + "$feature_flag_payloads": {}, + "realm": "hosted-clickhouse", + "email_service_available": false, + "slack_service_available": false, + "$user_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "is_demo_project": false, + "$groups": { + "project": "018a92f8-b602-0000-75de-4b9073693531", + "organization": "018a92f8-afff-0000-efec-ca77de39e384", + "customer": "cus_OdSgxxWtHOtq9g", + "instance": "http://localhost:8000" + }, + "has_billing_plan": true, + "customer_deactivated": false, + "current_total_amount_usd": "0.00", + "percentage_usage.product_analytics": 0, + "current_amount_usd.product_analytics": "0.00", + "unit_amount_usd.product_analytics": null, + "usage_limit.product_analytics": null, + "current_usage.product_analytics": 3729, + "projected_usage.product_analytics": 0, + "free_allocation.product_analytics": 0, + "percentage_usage.session_replay": 0, + "current_amount_usd.session_replay": "0.00", + "unit_amount_usd.session_replay": null, + "usage_limit.session_replay": null, + "current_usage.session_replay": 254, + "projected_usage.session_replay": 0, + "free_allocation.session_replay": 0, + "percentage_usage.feature_flags": 0, + "current_amount_usd.feature_flags": "0.00", + "unit_amount_usd.feature_flags": null, + "usage_limit.feature_flags": null, + "current_usage.feature_flags": 0, + "projected_usage.feature_flags": 0, + "free_allocation.feature_flags": 0, + "percentage_usage.integrations": 0, + "current_amount_usd.integrations": null, + "unit_amount_usd.integrations": null, + "usage_limit.integrations": 0, + "current_usage.integrations": 0, + "projected_usage.integrations": 0, + "free_allocation.integrations": 0, + "percentage_usage.platform_and_support": 0, + "current_amount_usd.platform_and_support": null, + "unit_amount_usd.platform_and_support": null, + "usage_limit.platform_and_support": 0, + "current_usage.platform_and_support": 0, + "projected_usage.platform_and_support": 0, + "free_allocation.platform_and_support": 0, + "billing_period_start": "2023-10-14T09:22:33.000Z", + "billing_period_end": "2023-11-14T09:22:33.000Z", + "$referrer": "$direct", + "$referring_domain": "$direct", + "insight": "TRENDS", + "token": "phc_OWGI2wKbfi7rWDZT9wkl8uGcfe0wOGCvflLEZSMiaT0", + "$session_id": "018b4cc2-908b-7989-a77a-ae1396eef1de", + "$window_id": "018b4cc2-908b-7989-a77a-ae1465fa2118", + "$ip": "127.0.0.1", + "$set": { + "$os": "Mac OS X", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/insights/new", + "$pathname": "/insights/new", + "$browser_version": 117, + "$referrer": "$direct", + "$referring_domain": "$direct" + }, + "$set_once": { + "$initial_os": "Mac OS X", + "$initial_browser": "Chrome", + "$initial_device_type": "Desktop", + "$initial_current_url": "http://localhost:8000/insights/new", + "$initial_pathname": "/insights/new", + "$initial_browser_version": 117, + "$initial_referrer": "$direct", + "$initial_referring_domain": "$direct" + }, + "$sent_at": "2023-10-20T11:05:22.490000+00:00", + "$geoip_city_name": "Sydney", + "$geoip_country_name": "Australia", + "$geoip_country_code": "AU", + "$geoip_continent_name": "Oceania", + "$geoip_continent_code": "OC", + "$geoip_postal_code": "2000", + "$geoip_latitude": -33.8715, + "$geoip_longitude": 151.2006, + "$geoip_time_zone": "Australia/Sydney", + "$geoip_subdivision_1_code": "NSW", + "$geoip_subdivision_1_name": "New South Wales", + "$plugins_succeeded": ["GeoIP (1)"], + "$plugins_failed": [], + "$plugins_deferred": [], + "$group_3": "018a92f8-b602-0000-75de-4b9073693531", + "$group_2": "018a92f8-afff-0000-efec-ca77de39e384", + "$group_4": "cus_OdSgxxWtHOtq9g", + "$group_1": "http://localhost:8000" + }, + "timestamp": "2023-10-20T11:05:20.072000+00:00", + "uuid": null + }, + { + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "elements": [ + { + "attr_class": ["LemonButton__content"], + "attr_id": null, + "attributes": { + "attr__class": "LemonButton__content" + }, + "href": null, + "nth_child": 2.0, + "nth_of_type": 2.0, + "order": 0.0, + "tag_name": "span", + "text": "Last 7 days" + }, + { + "attr_class": [ + "LemonButton", + "LemonButton--has-icon", + "LemonButton--has-side-icon", + "LemonButton--secondary", + "LemonButton--small", + "LemonButton--status-stealth" + ], + "attr_id": "daterange_selector", + "attributes": { + "attr__aria-disabled": "false", + "attr__aria-haspopup": "true", + "attr__class": "LemonButton LemonButton--secondary LemonButton--status-stealth LemonButton--small LemonButton--has-icon LemonButton--has-side-icon", + "attr__data-attr": "date-filter", + "attr__id": "daterange_selector", + "attr__type": "button" + }, + "href": null, + "nth_child": 1.0, + "nth_of_type": 1.0, + "order": 1.0, + "tag_name": "button", + "text": "Last 7 days" + }, + { + "attr_class": ["flex", "items-center", "space-x-2", "text-sm"], + "attr_id": null, + "attributes": { + "attr__class": "space-x-2 flex items-center text-sm" + }, + "href": null, + "nth_child": 1.0, + "nth_of_type": 1.0, + "order": 2.0, + "tag_name": "span", + "text": null + }, + { + "attr_class": ["flex", "flex-wrap", "gap-x-2", "gap-y-2", "items-center", "my-2"], + "attr_id": null, + "attributes": { + "attr__class": "flex items-center gap-x-2 flex-wrap my-2 gap-y-2" + }, + "href": null, + "nth_child": 1.0, + "nth_of_type": 1.0, + "order": 3.0, + "tag_name": "div", + "text": null + }, + { + "attr_class": ["flex", "flex-wrap", "items-center", "justify-between"], + "attr_id": null, + "attributes": { + "attr__class": "flex justify-between items-center flex-wrap", + "attr__data-attr": "insight-filters" + }, + "href": null, + "nth_child": 1.0, + "nth_of_type": 1.0, + "order": 4.0, + "tag_name": "div", + "text": null + }, + { + "attr_class": ["ant-card-head-title"], + "attr_id": null, + "attributes": { + "attr__class": "ant-card-head-title" + }, + "href": null, + "nth_child": 1.0, + "nth_of_type": 1.0, + "order": 5.0, + "tag_name": "div", + "text": null + }, + { + "attr_class": ["ant-card-head-wrapper"], + "attr_id": null, + "attributes": { + "attr__class": "ant-card-head-wrapper" + }, + "href": null, + "nth_child": 1.0, + "nth_of_type": 1.0, + "order": 6.0, + "tag_name": "div", + "text": null + }, + { + "attr_class": ["ant-card-head"], + "attr_id": null, + "attributes": { + "attr__class": "ant-card-head" + }, + "href": null, + "nth_child": 1.0, + "nth_of_type": 1.0, + "order": 7.0, + "tag_name": "div", + "text": null + }, + { + "attr_class": ["ant-card", "ant-card-bordered", "insights-graph-container"], + "attr_id": null, + "attributes": { + "attr__class": "ant-card ant-card-bordered insights-graph-container", + "attr__data-attr": "insights-graph" + }, + "href": null, + "nth_child": 1.0, + "nth_of_type": 1.0, + "order": 8.0, + "tag_name": "div", + "text": null + }, + { + "attr_class": ["insights-container"], + "attr_id": null, + "attributes": { + "attr__class": "insights-container", + "attr__data-attr": "insight-view" + }, + "href": null, + "nth_child": 2.0, + "nth_of_type": 2.0, + "order": 9.0, + "tag_name": "div", + "text": null + }, + { + "attr_class": ["insight-wrapper"], + "attr_id": null, + "attributes": { + "attr__class": "insight-wrapper" + }, + "href": null, + "nth_child": 4.0, + "nth_of_type": 4.0, + "order": 10.0, + "tag_name": "div", + "text": null + }, + { + "attr_class": ["insights-page"], + "attr_id": null, + "attributes": { + "attr__class": "insights-page" + }, + "href": null, + "nth_child": 1.0, + "nth_of_type": 1.0, + "order": 11.0, + "tag_name": "div", + "text": null + }, + { + "attr_class": ["Navigation3000__scene"], + "attr_id": null, + "attributes": { + "attr__class": "Navigation3000__scene" + }, + "href": null, + "nth_child": 2.0, + "nth_of_type": 2.0, + "order": 12.0, + "tag_name": "div", + "text": null + }, + { + "attr_class": null, + "attr_id": null, + "attributes": {}, + "href": null, + "nth_child": 4.0, + "nth_of_type": 1.0, + "order": 13.0, + "tag_name": "main", + "text": null + }, + { + "attr_class": ["Navigation3000"], + "attr_id": null, + "attributes": { + "attr__class": "Navigation3000" + }, + "href": null, + "nth_child": 1.0, + "nth_of_type": 1.0, + "order": 14.0, + "tag_name": "div", + "text": null + }, + { + "attr_class": null, + "attr_id": "root", + "attributes": { + "attr__id": "root" + }, + "href": null, + "nth_child": 4.0, + "nth_of_type": 1.0, + "order": 15.0, + "tag_name": "div", + "text": null + }, + { + "attr_class": ["posthog-3000"], + "attr_id": null, + "attributes": { + "attr__class": "posthog-3000", + "attr__theme": "light" + }, + "href": null, + "nth_child": 2.0, + "nth_of_type": 1.0, + "order": 16.0, + "tag_name": "body", + "text": null + } + ], + "elements_chain": "span.LemonButton__content:attr__class=\"LemonButton__content\"nth-child=\"2\"nth-of-type=\"2\"text=\"Last 7 days\";button.LemonButton.LemonButton--has-icon.LemonButton--has-side-icon.LemonButton--secondary.LemonButton--small.LemonButton--status-stealth:attr__aria-disabled=\"false\"attr__aria-haspopup=\"true\"attr__class=\"LemonButton LemonButton--secondary LemonButton--status-stealth LemonButton--small LemonButton--has-icon LemonButton--has-side-icon\"attr__data-attr=\"date-filter\"attr__id=\"daterange_selector\"attr__type=\"button\"attr_id=\"daterange_selector\"nth-child=\"1\"nth-of-type=\"1\"text=\"Last 7 days\";span.flex.items-center.space-x-2.text-sm:attr__class=\"space-x-2 flex items-center text-sm\"nth-child=\"1\"nth-of-type=\"1\";div.flex.flex-wrap.gap-x-2.gap-y-2.items-center.my-2:attr__class=\"flex items-center gap-x-2 flex-wrap my-2 gap-y-2\"nth-child=\"1\"nth-of-type=\"1\";div.flex.flex-wrap.items-center.justify-between:attr__class=\"flex justify-between items-center flex-wrap\"attr__data-attr=\"insight-filters\"nth-child=\"1\"nth-of-type=\"1\";div.ant-card-head-title:attr__class=\"ant-card-head-title\"nth-child=\"1\"nth-of-type=\"1\";div.ant-card-head-wrapper:attr__class=\"ant-card-head-wrapper\"nth-child=\"1\"nth-of-type=\"1\";div.ant-card-head:attr__class=\"ant-card-head\"nth-child=\"1\"nth-of-type=\"1\";div.ant-card.ant-card-bordered.insights-graph-container:attr__class=\"ant-card ant-card-bordered insights-graph-container\"attr__data-attr=\"insights-graph\"nth-child=\"1\"nth-of-type=\"1\";div.insights-container:attr__class=\"insights-container\"attr__data-attr=\"insight-view\"nth-child=\"2\"nth-of-type=\"2\";div.insight-wrapper:attr__class=\"insight-wrapper\"nth-child=\"4\"nth-of-type=\"4\";div.insights-page:attr__class=\"insights-page\"nth-child=\"1\"nth-of-type=\"1\";div.Navigation3000__scene:attr__class=\"Navigation3000__scene\"nth-child=\"2\"nth-of-type=\"2\";main:nth-child=\"4\"nth-of-type=\"1\";div.Navigation3000:attr__class=\"Navigation3000\"nth-child=\"1\"nth-of-type=\"1\";div:attr__id=\"root\"attr_id=\"root\"nth-child=\"4\"nth-of-type=\"1\";body.posthog-3000:attr__class=\"posthog-3000\"attr__theme=\"light\"nth-child=\"2\"nth-of-type=\"1\"", + "event": "$autocapture", + "id": "018b4cc2-e0d4-72f0-8d6d-5b301c3790d8", + "person": null, + "properties": { + "$os": "Mac OS X", + "$os_version": "10.15.7", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/insights/new", + "$host": "localhost:8000", + "$pathname": "/insights/new", + "$browser_version": 117, + "$browser_language": "en-GB", + "$screen_height": 982, + "$screen_width": 1512, + "$viewport_height": 859, + "$viewport_width": 1512, + "$lib": "web", + "$lib_version": "1.84.0", + "$insert_id": "knfewpc9dbfjykww", + "$time": 1697799921.876, + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$device_id": "018a92fd-7b25-7770-a050-577e94fd148c", + "$console_log_recording_enabled_server_side": true, + "$session_recording_recorder_version_server_side": "v2", + "$autocapture_disabled_server_side": false, + "$active_feature_flags": [ + "signup-page-4.0", + "cmd-k-search", + "posthog-3000", + "funnels-cue-opt-out-7301", + "retention-breakdown", + "smoothing-interval", + "billing-limit", + "kafka-inspector", + "historical-exports-v2", + "person-on-events-enabled", + "region-select", + "ingestion-warnings-enabled", + "session-reset-on-load", + "recordings-on-feature-flags", + "auto-rollback-feature-flags", + "onboarding-v2-demo", + "feature-flag-rollout-ux", + "role-based-access", + "query_running_time", + "query-timings", + "recording-debugging", + "enable-prompts", + "feedback-scene", + "early-access-feature", + "early-access-feature-site-button", + "hedgehog-mode-debug", + "auto-redirect", + "session-recording-blob-replay", + "surveys", + "generic-signup-benefits", + "surveys-positions", + "web-analytics", + "high-frequency-batch-exports", + "exception-autocapture", + "data-warehouse", + "data-warehouse-views", + "ff-dashboard-templates", + "show-product-intro-existing-products", + "artificial-hog", + "cs-dashboards", + "product-specific-onboarding", + "redirect-signups-to-instance", + "apps-and-exports-ui", + "survey-nps-results", + "session-recording-allow-v1-snapshots", + "session-replay-cors-proxy", + "webhooks-denylist", + "surveys-site-app-deprecation", + "surveys-multiple-questions", + "surveys-results-visualizations", + "console-recording-search", + "persons-hogql-query", + "notebooks" + ], + "$feature/file-previews": false, + "$feature/signup-page-4.0": "control", + "$feature/hogql-insights": false, + "$feature/cmd-k-search": true, + "$feature/posthog-3000": true, + "$feature/funnels-cue-opt-out-7301": true, + "$feature/retention-breakdown": true, + "$feature/smoothing-interval": true, + "$feature/billing-limit": true, + "$feature/kafka-inspector": true, + "$feature/historical-exports-v2": true, + "$feature/person-on-events-enabled": true, + "$feature/region-select": true, + "$feature/ingestion-warnings-enabled": true, + "$feature/session-reset-on-load": true, + "$feature/recordings-on-feature-flags": true, + "$feature/auto-rollback-feature-flags": true, + "$feature/onboarding-v2-demo": true, + "$feature/feature-flag-rollout-ux": true, + "$feature/role-based-access": true, + "$feature/query_running_time": true, + "$feature/query-timings": true, + "$feature/recording-debugging": true, + "$feature/enable-prompts": true, + "$feature/feedback-scene": true, + "$feature/early-access-feature": true, + "$feature/early-access-feature-site-button": true, + "$feature/hedgehog-mode-debug": true, + "$feature/auto-redirect": true, + "$feature/session-recording-blob-replay": true, + "$feature/surveys": true, + "$feature/generic-signup-benefits": true, + "$feature/surveys-positions": true, + "$feature/web-analytics": true, + "$feature/high-frequency-batch-exports": true, + "$feature/exception-autocapture": true, + "$feature/data-warehouse": true, + "$feature/data-warehouse-views": true, + "$feature/ff-dashboard-templates": true, + "$feature/show-product-intro-existing-products": true, + "$feature/artificial-hog": true, + "$feature/cs-dashboards": true, + "$feature/product-specific-onboarding": true, + "$feature/redirect-signups-to-instance": true, + "$feature/apps-and-exports-ui": true, + "$feature/survey-nps-results": true, + "$feature/session-recording-allow-v1-snapshots": true, + "$feature/session-replay-cors-proxy": true, + "$feature/webhooks-denylist": true, + "$feature/surveys-site-app-deprecation": true, + "$feature/surveys-multiple-questions": true, + "$feature/surveys-results-visualizations": true, + "$feature/console-recording-search": true, + "$feature/persons-hogql-query": true, + "$feature/notebooks": true, + "$feature_flag_payloads": {}, + "realm": "hosted-clickhouse", + "email_service_available": false, + "slack_service_available": false, + "$user_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "is_demo_project": false, + "$groups": { + "project": "018a92f8-b602-0000-75de-4b9073693531", + "organization": "018a92f8-afff-0000-efec-ca77de39e384", + "customer": "cus_OdSgxxWtHOtq9g", + "instance": "http://localhost:8000" + }, + "has_billing_plan": true, + "customer_deactivated": false, + "current_total_amount_usd": "0.00", + "percentage_usage.product_analytics": 0, + "current_amount_usd.product_analytics": "0.00", + "unit_amount_usd.product_analytics": null, + "usage_limit.product_analytics": null, + "current_usage.product_analytics": 3729, + "projected_usage.product_analytics": 0, + "free_allocation.product_analytics": 0, + "percentage_usage.session_replay": 0, + "current_amount_usd.session_replay": "0.00", + "unit_amount_usd.session_replay": null, + "usage_limit.session_replay": null, + "current_usage.session_replay": 254, + "projected_usage.session_replay": 0, + "free_allocation.session_replay": 0, + "percentage_usage.feature_flags": 0, + "current_amount_usd.feature_flags": "0.00", + "unit_amount_usd.feature_flags": null, + "usage_limit.feature_flags": null, + "current_usage.feature_flags": 0, + "projected_usage.feature_flags": 0, + "free_allocation.feature_flags": 0, + "percentage_usage.integrations": 0, + "current_amount_usd.integrations": null, + "unit_amount_usd.integrations": null, + "usage_limit.integrations": 0, + "current_usage.integrations": 0, + "projected_usage.integrations": 0, + "free_allocation.integrations": 0, + "percentage_usage.platform_and_support": 0, + "current_amount_usd.platform_and_support": null, + "unit_amount_usd.platform_and_support": null, + "usage_limit.platform_and_support": 0, + "current_usage.platform_and_support": 0, + "projected_usage.platform_and_support": 0, + "free_allocation.platform_and_support": 0, + "billing_period_start": "2023-10-14T09:22:33.000Z", + "billing_period_end": "2023-11-14T09:22:33.000Z", + "$referrer": "$direct", + "$referring_domain": "$direct", + "$event_type": "click", + "$ce_version": 1, + "$el_text": "Last 7 days", + "token": "phc_OWGI2wKbfi7rWDZT9wkl8uGcfe0wOGCvflLEZSMiaT0", + "$session_id": "018b4cc2-908b-7989-a77a-ae1396eef1de", + "$window_id": "018b4cc2-908b-7989-a77a-ae1465fa2118", + "$ip": "127.0.0.1", + "$set": { + "$os": "Mac OS X", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/insights/new", + "$pathname": "/insights/new", + "$browser_version": 117, + "$referrer": "$direct", + "$referring_domain": "$direct" + }, + "$set_once": { + "$initial_os": "Mac OS X", + "$initial_browser": "Chrome", + "$initial_device_type": "Desktop", + "$initial_current_url": "http://localhost:8000/insights/new", + "$initial_pathname": "/insights/new", + "$initial_browser_version": 117, + "$initial_referrer": "$direct", + "$initial_referring_domain": "$direct" + }, + "$sent_at": "2023-10-20T11:05:22.490000+00:00", + "$geoip_city_name": "Sydney", + "$geoip_country_name": "Australia", + "$geoip_country_code": "AU", + "$geoip_continent_name": "Oceania", + "$geoip_continent_code": "OC", + "$geoip_postal_code": "2000", + "$geoip_latitude": -33.8715, + "$geoip_longitude": 151.2006, + "$geoip_time_zone": "Australia/Sydney", + "$geoip_subdivision_1_code": "NSW", + "$geoip_subdivision_1_name": "New South Wales", + "$plugins_succeeded": ["GeoIP (1)"], + "$plugins_failed": [], + "$plugins_deferred": [], + "$group_3": "018a92f8-b602-0000-75de-4b9073693531", + "$group_2": "018a92f8-afff-0000-efec-ca77de39e384", + "$group_4": "cus_OdSgxxWtHOtq9g", + "$group_1": "http://localhost:8000" + }, + "timestamp": "2023-10-20T11:05:21.893000+00:00", + "uuid": null + }, + { + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "elements": [ + { + "attr_class": ["LemonButton__content"], + "attr_id": null, + "attributes": { + "attr__class": "LemonButton__content" + }, + "href": null, + "nth_child": 2.0, + "nth_of_type": 2.0, + "order": 0.0, + "tag_name": "span", + "text": "Last 7 days" + }, + { + "attr_class": [ + "LemonButton", + "LemonButton--active", + "LemonButton--has-icon", + "LemonButton--has-side-icon", + "LemonButton--secondary", + "LemonButton--small", + "LemonButton--status-stealth" + ], + "attr_id": "daterange_selector", + "attributes": { + "attr__aria-disabled": "false", + "attr__aria-haspopup": "true", + "attr__class": "LemonButton LemonButton--secondary LemonButton--status-stealth LemonButton--small LemonButton--active LemonButton--has-icon LemonButton--has-side-icon", + "attr__data-attr": "date-filter", + "attr__id": "daterange_selector", + "attr__type": "button" + }, + "href": null, + "nth_child": 1.0, + "nth_of_type": 1.0, + "order": 1.0, + "tag_name": "button", + "text": "Last 7 days" + }, + { + "attr_class": ["flex", "items-center", "space-x-2", "text-sm"], + "attr_id": null, + "attributes": { + "attr__class": "space-x-2 flex items-center text-sm" + }, + "href": null, + "nth_child": 1.0, + "nth_of_type": 1.0, + "order": 2.0, + "tag_name": "span", + "text": null + }, + { + "attr_class": ["flex", "flex-wrap", "gap-x-2", "gap-y-2", "items-center", "my-2"], + "attr_id": null, + "attributes": { + "attr__class": "flex items-center gap-x-2 flex-wrap my-2 gap-y-2" + }, + "href": null, + "nth_child": 1.0, + "nth_of_type": 1.0, + "order": 3.0, + "tag_name": "div", + "text": null + }, + { + "attr_class": ["flex", "flex-wrap", "items-center", "justify-between"], + "attr_id": null, + "attributes": { + "attr__class": "flex justify-between items-center flex-wrap", + "attr__data-attr": "insight-filters" + }, + "href": null, + "nth_child": 1.0, + "nth_of_type": 1.0, + "order": 4.0, + "tag_name": "div", + "text": null + }, + { + "attr_class": ["ant-card-head-title"], + "attr_id": null, + "attributes": { + "attr__class": "ant-card-head-title" + }, + "href": null, + "nth_child": 1.0, + "nth_of_type": 1.0, + "order": 5.0, + "tag_name": "div", + "text": null + }, + { + "attr_class": ["ant-card-head-wrapper"], + "attr_id": null, + "attributes": { + "attr__class": "ant-card-head-wrapper" + }, + "href": null, + "nth_child": 1.0, + "nth_of_type": 1.0, + "order": 6.0, + "tag_name": "div", + "text": null + }, + { + "attr_class": ["ant-card-head"], + "attr_id": null, + "attributes": { + "attr__class": "ant-card-head" + }, + "href": null, + "nth_child": 1.0, + "nth_of_type": 1.0, + "order": 7.0, + "tag_name": "div", + "text": null + }, + { + "attr_class": ["ant-card", "ant-card-bordered", "insights-graph-container"], + "attr_id": null, + "attributes": { + "attr__class": "ant-card ant-card-bordered insights-graph-container", + "attr__data-attr": "insights-graph" + }, + "href": null, + "nth_child": 1.0, + "nth_of_type": 1.0, + "order": 8.0, + "tag_name": "div", + "text": null + }, + { + "attr_class": ["insights-container"], + "attr_id": null, + "attributes": { + "attr__class": "insights-container", + "attr__data-attr": "insight-view" + }, + "href": null, + "nth_child": 2.0, + "nth_of_type": 2.0, + "order": 9.0, + "tag_name": "div", + "text": null + }, + { + "attr_class": ["insight-wrapper"], + "attr_id": null, + "attributes": { + "attr__class": "insight-wrapper" + }, + "href": null, + "nth_child": 4.0, + "nth_of_type": 4.0, + "order": 10.0, + "tag_name": "div", + "text": null + }, + { + "attr_class": ["insights-page"], + "attr_id": null, + "attributes": { + "attr__class": "insights-page" + }, + "href": null, + "nth_child": 1.0, + "nth_of_type": 1.0, + "order": 11.0, + "tag_name": "div", + "text": null + }, + { + "attr_class": ["Navigation3000__scene"], + "attr_id": null, + "attributes": { + "attr__class": "Navigation3000__scene" + }, + "href": null, + "nth_child": 2.0, + "nth_of_type": 2.0, + "order": 12.0, + "tag_name": "div", + "text": null + }, + { + "attr_class": null, + "attr_id": null, + "attributes": {}, + "href": null, + "nth_child": 4.0, + "nth_of_type": 1.0, + "order": 13.0, + "tag_name": "main", + "text": null + }, + { + "attr_class": ["Navigation3000"], + "attr_id": null, + "attributes": { + "attr__class": "Navigation3000" + }, + "href": null, + "nth_child": 1.0, + "nth_of_type": 1.0, + "order": 14.0, + "tag_name": "div", + "text": null + }, + { + "attr_class": null, + "attr_id": "root", + "attributes": { + "attr__id": "root" + }, + "href": null, + "nth_child": 4.0, + "nth_of_type": 1.0, + "order": 15.0, + "tag_name": "div", + "text": null + }, + { + "attr_class": ["posthog-3000"], + "attr_id": null, + "attributes": { + "attr__class": "posthog-3000", + "attr__theme": "light" + }, + "href": null, + "nth_child": 2.0, + "nth_of_type": 1.0, + "order": 16.0, + "tag_name": "body", + "text": null + } + ], + "elements_chain": "span.LemonButton__content:attr__class=\"LemonButton__content\"nth-child=\"2\"nth-of-type=\"2\"text=\"Last 7 days\";button.LemonButton.LemonButton--active.LemonButton--has-icon.LemonButton--has-side-icon.LemonButton--secondary.LemonButton--small.LemonButton--status-stealth:attr__aria-disabled=\"false\"attr__aria-haspopup=\"true\"attr__class=\"LemonButton LemonButton--secondary LemonButton--status-stealth LemonButton--small LemonButton--active LemonButton--has-icon LemonButton--has-side-icon\"attr__data-attr=\"date-filter\"attr__id=\"daterange_selector\"attr__type=\"button\"attr_id=\"daterange_selector\"nth-child=\"1\"nth-of-type=\"1\"text=\"Last 7 days\";span.flex.items-center.space-x-2.text-sm:attr__class=\"space-x-2 flex items-center text-sm\"nth-child=\"1\"nth-of-type=\"1\";div.flex.flex-wrap.gap-x-2.gap-y-2.items-center.my-2:attr__class=\"flex items-center gap-x-2 flex-wrap my-2 gap-y-2\"nth-child=\"1\"nth-of-type=\"1\";div.flex.flex-wrap.items-center.justify-between:attr__class=\"flex justify-between items-center flex-wrap\"attr__data-attr=\"insight-filters\"nth-child=\"1\"nth-of-type=\"1\";div.ant-card-head-title:attr__class=\"ant-card-head-title\"nth-child=\"1\"nth-of-type=\"1\";div.ant-card-head-wrapper:attr__class=\"ant-card-head-wrapper\"nth-child=\"1\"nth-of-type=\"1\";div.ant-card-head:attr__class=\"ant-card-head\"nth-child=\"1\"nth-of-type=\"1\";div.ant-card.ant-card-bordered.insights-graph-container:attr__class=\"ant-card ant-card-bordered insights-graph-container\"attr__data-attr=\"insights-graph\"nth-child=\"1\"nth-of-type=\"1\";div.insights-container:attr__class=\"insights-container\"attr__data-attr=\"insight-view\"nth-child=\"2\"nth-of-type=\"2\";div.insight-wrapper:attr__class=\"insight-wrapper\"nth-child=\"4\"nth-of-type=\"4\";div.insights-page:attr__class=\"insights-page\"nth-child=\"1\"nth-of-type=\"1\";div.Navigation3000__scene:attr__class=\"Navigation3000__scene\"nth-child=\"2\"nth-of-type=\"2\";main:nth-child=\"4\"nth-of-type=\"1\";div.Navigation3000:attr__class=\"Navigation3000\"nth-child=\"1\"nth-of-type=\"1\";div:attr__id=\"root\"attr_id=\"root\"nth-child=\"4\"nth-of-type=\"1\";body.posthog-3000:attr__class=\"posthog-3000\"attr__theme=\"light\"nth-child=\"2\"nth-of-type=\"1\"", + "event": "$autocapture", + "id": "018b4cc2-e3eb-739f-9033-12ea1e9c896e", + "person": null, + "properties": { + "$os": "Mac OS X", + "$os_version": "10.15.7", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/insights/new", + "$host": "localhost:8000", + "$pathname": "/insights/new", + "$browser_version": 117, + "$browser_language": "en-GB", + "$screen_height": 982, + "$screen_width": 1512, + "$viewport_height": 859, + "$viewport_width": 1512, + "$lib": "web", + "$lib_version": "1.84.0", + "$insert_id": "33gzljaml77fxfme", + "$time": 1697799922.668, + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$device_id": "018a92fd-7b25-7770-a050-577e94fd148c", + "$console_log_recording_enabled_server_side": true, + "$session_recording_recorder_version_server_side": "v2", + "$autocapture_disabled_server_side": false, + "$active_feature_flags": [ + "signup-page-4.0", + "cmd-k-search", + "posthog-3000", + "funnels-cue-opt-out-7301", + "retention-breakdown", + "smoothing-interval", + "billing-limit", + "kafka-inspector", + "historical-exports-v2", + "person-on-events-enabled", + "region-select", + "ingestion-warnings-enabled", + "session-reset-on-load", + "recordings-on-feature-flags", + "auto-rollback-feature-flags", + "onboarding-v2-demo", + "feature-flag-rollout-ux", + "role-based-access", + "query_running_time", + "query-timings", + "recording-debugging", + "enable-prompts", + "feedback-scene", + "early-access-feature", + "early-access-feature-site-button", + "hedgehog-mode-debug", + "auto-redirect", + "session-recording-blob-replay", + "surveys", + "generic-signup-benefits", + "surveys-positions", + "web-analytics", + "high-frequency-batch-exports", + "exception-autocapture", + "data-warehouse", + "data-warehouse-views", + "ff-dashboard-templates", + "show-product-intro-existing-products", + "artificial-hog", + "cs-dashboards", + "product-specific-onboarding", + "redirect-signups-to-instance", + "apps-and-exports-ui", + "survey-nps-results", + "session-recording-allow-v1-snapshots", + "session-replay-cors-proxy", + "webhooks-denylist", + "surveys-site-app-deprecation", + "surveys-multiple-questions", + "surveys-results-visualizations", + "console-recording-search", + "persons-hogql-query", + "notebooks" + ], + "$feature/file-previews": false, + "$feature/signup-page-4.0": "control", + "$feature/hogql-insights": false, + "$feature/cmd-k-search": true, + "$feature/posthog-3000": true, + "$feature/funnels-cue-opt-out-7301": true, + "$feature/retention-breakdown": true, + "$feature/smoothing-interval": true, + "$feature/billing-limit": true, + "$feature/kafka-inspector": true, + "$feature/historical-exports-v2": true, + "$feature/person-on-events-enabled": true, + "$feature/region-select": true, + "$feature/ingestion-warnings-enabled": true, + "$feature/session-reset-on-load": true, + "$feature/recordings-on-feature-flags": true, + "$feature/auto-rollback-feature-flags": true, + "$feature/onboarding-v2-demo": true, + "$feature/feature-flag-rollout-ux": true, + "$feature/role-based-access": true, + "$feature/query_running_time": true, + "$feature/query-timings": true, + "$feature/recording-debugging": true, + "$feature/enable-prompts": true, + "$feature/feedback-scene": true, + "$feature/early-access-feature": true, + "$feature/early-access-feature-site-button": true, + "$feature/hedgehog-mode-debug": true, + "$feature/auto-redirect": true, + "$feature/session-recording-blob-replay": true, + "$feature/surveys": true, + "$feature/generic-signup-benefits": true, + "$feature/surveys-positions": true, + "$feature/web-analytics": true, + "$feature/high-frequency-batch-exports": true, + "$feature/exception-autocapture": true, + "$feature/data-warehouse": true, + "$feature/data-warehouse-views": true, + "$feature/ff-dashboard-templates": true, + "$feature/show-product-intro-existing-products": true, + "$feature/artificial-hog": true, + "$feature/cs-dashboards": true, + "$feature/product-specific-onboarding": true, + "$feature/redirect-signups-to-instance": true, + "$feature/apps-and-exports-ui": true, + "$feature/survey-nps-results": true, + "$feature/session-recording-allow-v1-snapshots": true, + "$feature/session-replay-cors-proxy": true, + "$feature/webhooks-denylist": true, + "$feature/surveys-site-app-deprecation": true, + "$feature/surveys-multiple-questions": true, + "$feature/surveys-results-visualizations": true, + "$feature/console-recording-search": true, + "$feature/persons-hogql-query": true, + "$feature/notebooks": true, + "$feature_flag_payloads": {}, + "realm": "hosted-clickhouse", + "email_service_available": false, + "slack_service_available": false, + "$user_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "is_demo_project": false, + "$groups": { + "project": "018a92f8-b602-0000-75de-4b9073693531", + "organization": "018a92f8-afff-0000-efec-ca77de39e384", + "customer": "cus_OdSgxxWtHOtq9g", + "instance": "http://localhost:8000" + }, + "has_billing_plan": true, + "customer_deactivated": false, + "current_total_amount_usd": "0.00", + "percentage_usage.product_analytics": 0, + "current_amount_usd.product_analytics": "0.00", + "unit_amount_usd.product_analytics": null, + "usage_limit.product_analytics": null, + "current_usage.product_analytics": 3729, + "projected_usage.product_analytics": 0, + "free_allocation.product_analytics": 0, + "percentage_usage.session_replay": 0, + "current_amount_usd.session_replay": "0.00", + "unit_amount_usd.session_replay": null, + "usage_limit.session_replay": null, + "current_usage.session_replay": 254, + "projected_usage.session_replay": 0, + "free_allocation.session_replay": 0, + "percentage_usage.feature_flags": 0, + "current_amount_usd.feature_flags": "0.00", + "unit_amount_usd.feature_flags": null, + "usage_limit.feature_flags": null, + "current_usage.feature_flags": 0, + "projected_usage.feature_flags": 0, + "free_allocation.feature_flags": 0, + "percentage_usage.integrations": 0, + "current_amount_usd.integrations": null, + "unit_amount_usd.integrations": null, + "usage_limit.integrations": 0, + "current_usage.integrations": 0, + "projected_usage.integrations": 0, + "free_allocation.integrations": 0, + "percentage_usage.platform_and_support": 0, + "current_amount_usd.platform_and_support": null, + "unit_amount_usd.platform_and_support": null, + "usage_limit.platform_and_support": 0, + "current_usage.platform_and_support": 0, + "projected_usage.platform_and_support": 0, + "free_allocation.platform_and_support": 0, + "billing_period_start": "2023-10-14T09:22:33.000Z", + "billing_period_end": "2023-11-14T09:22:33.000Z", + "$referrer": "$direct", + "$referring_domain": "$direct", + "$event_type": "click", + "$ce_version": 1, + "$el_text": "Last 7 days", + "token": "phc_OWGI2wKbfi7rWDZT9wkl8uGcfe0wOGCvflLEZSMiaT0", + "$session_id": "018b4cc2-908b-7989-a77a-ae1396eef1de", + "$window_id": "018b4cc2-908b-7989-a77a-ae1465fa2118", + "$ip": "127.0.0.1", + "$set": { + "$os": "Mac OS X", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/insights/new", + "$pathname": "/insights/new", + "$browser_version": 117, + "$referrer": "$direct", + "$referring_domain": "$direct" + }, + "$set_once": { + "$initial_os": "Mac OS X", + "$initial_browser": "Chrome", + "$initial_device_type": "Desktop", + "$initial_current_url": "http://localhost:8000/insights/new", + "$initial_pathname": "/insights/new", + "$initial_browser_version": 117, + "$initial_referrer": "$direct", + "$initial_referring_domain": "$direct" + }, + "$sent_at": "2023-10-20T11:05:25.504000+00:00", + "$geoip_city_name": "Sydney", + "$geoip_country_name": "Australia", + "$geoip_country_code": "AU", + "$geoip_continent_name": "Oceania", + "$geoip_continent_code": "OC", + "$geoip_postal_code": "2000", + "$geoip_latitude": -33.8715, + "$geoip_longitude": 151.2006, + "$geoip_time_zone": "Australia/Sydney", + "$geoip_subdivision_1_code": "NSW", + "$geoip_subdivision_1_name": "New South Wales", + "$plugins_succeeded": ["GeoIP (1)"], + "$plugins_failed": [], + "$plugins_deferred": [], + "$group_3": "018a92f8-b602-0000-75de-4b9073693531", + "$group_2": "018a92f8-afff-0000-efec-ca77de39e384", + "$group_4": "cus_OdSgxxWtHOtq9g", + "$group_1": "http://localhost:8000" + }, + "timestamp": "2023-10-20T11:05:22.675000+00:00", + "uuid": null + }, + { + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "elements": [ + { + "attr_class": ["LemonTabs__tab-content"], + "attr_id": null, + "attributes": { + "attr__class": "LemonTabs__tab-content" + }, + "href": null, + "nth_child": 1.0, + "nth_of_type": 1.0, + "order": 0.0, + "tag_name": "div", + "text": null + }, + { + "attr_class": ["LemonTabs__tab"], + "attr_id": null, + "attributes": { + "attr__aria-selected": "false", + "attr__class": "LemonTabs__tab", + "attr__role": "tab", + "attr__tabindex": "0" + }, + "href": null, + "nth_child": 2.0, + "nth_of_type": 2.0, + "order": 1.0, + "tag_name": "li", + "text": null + }, + { + "attr_class": ["LemonTabs__bar"], + "attr_id": null, + "attributes": { + "attr__class": "LemonTabs__bar", + "attr__role": "tablist" + }, + "href": null, + "nth_child": 1.0, + "nth_of_type": 1.0, + "order": 2.0, + "tag_name": "ul", + "text": null + }, + { + "attr_class": ["LemonTabs"], + "attr_id": null, + "attributes": { + "attr__class": "LemonTabs", + "attr__style": "--lemon-tabs-slider-width: 44.171875px; --lemon-tabs-slider-offset: 0px;" + }, + "href": null, + "nth_child": 3.0, + "nth_of_type": 3.0, + "order": 3.0, + "tag_name": "div", + "text": null + }, + { + "attr_class": ["insights-page"], + "attr_id": null, + "attributes": { + "attr__class": "insights-page" + }, + "href": null, + "nth_child": 1.0, + "nth_of_type": 1.0, + "order": 4.0, + "tag_name": "div", + "text": null + }, + { + "attr_class": ["Navigation3000__scene"], + "attr_id": null, + "attributes": { + "attr__class": "Navigation3000__scene" + }, + "href": null, + "nth_child": 2.0, + "nth_of_type": 2.0, + "order": 5.0, + "tag_name": "div", + "text": null + }, + { + "attr_class": null, + "attr_id": null, + "attributes": {}, + "href": null, + "nth_child": 4.0, + "nth_of_type": 1.0, + "order": 6.0, + "tag_name": "main", + "text": null + }, + { + "attr_class": ["Navigation3000"], + "attr_id": null, + "attributes": { + "attr__class": "Navigation3000" + }, + "href": null, + "nth_child": 1.0, + "nth_of_type": 1.0, + "order": 7.0, + "tag_name": "div", + "text": null + }, + { + "attr_class": null, + "attr_id": "root", + "attributes": { + "attr__id": "root" + }, + "href": null, + "nth_child": 4.0, + "nth_of_type": 1.0, + "order": 8.0, + "tag_name": "div", + "text": null + }, + { + "attr_class": ["posthog-3000"], + "attr_id": null, + "attributes": { + "attr__class": "posthog-3000", + "attr__theme": "light" + }, + "href": null, + "nth_child": 2.0, + "nth_of_type": 1.0, + "order": 9.0, + "tag_name": "body", + "text": null + } + ], + "elements_chain": "div.LemonTabs__tab-content:attr__class=\"LemonTabs__tab-content\"nth-child=\"1\"nth-of-type=\"1\";li.LemonTabs__tab:attr__aria-selected=\"false\"attr__class=\"LemonTabs__tab\"attr__role=\"tab\"attr__tabindex=\"0\"nth-child=\"2\"nth-of-type=\"2\";ul.LemonTabs__bar:attr__class=\"LemonTabs__bar\"attr__role=\"tablist\"nth-child=\"1\"nth-of-type=\"1\";div.LemonTabs:attr__class=\"LemonTabs\"attr__style=\"--lemon-tabs-slider-width: 44.171875px; --lemon-tabs-slider-offset: 0px;\"nth-child=\"3\"nth-of-type=\"3\";div.insights-page:attr__class=\"insights-page\"nth-child=\"1\"nth-of-type=\"1\";div.Navigation3000__scene:attr__class=\"Navigation3000__scene\"nth-child=\"2\"nth-of-type=\"2\";main:nth-child=\"4\"nth-of-type=\"1\";div.Navigation3000:attr__class=\"Navigation3000\"nth-child=\"1\"nth-of-type=\"1\";div:attr__id=\"root\"attr_id=\"root\"nth-child=\"4\"nth-of-type=\"1\";body.posthog-3000:attr__class=\"posthog-3000\"attr__theme=\"light\"nth-child=\"2\"nth-of-type=\"1\"", + "event": "$autocapture", + "id": "018b4cc2-f490-7227-8d35-65880c75cac8", + "person": null, + "properties": { + "$os": "Mac OS X", + "$os_version": "10.15.7", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/insights/new", + "$host": "localhost:8000", + "$pathname": "/insights/new", + "$browser_version": 117, + "$browser_language": "en-GB", + "$screen_height": 982, + "$screen_width": 1512, + "$viewport_height": 859, + "$viewport_width": 1512, + "$lib": "web", + "$lib_version": "1.84.0", + "$insert_id": "dwrvit8pfft8n550", + "$time": 1697799926.928, + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$device_id": "018a92fd-7b25-7770-a050-577e94fd148c", + "$console_log_recording_enabled_server_side": true, + "$session_recording_recorder_version_server_side": "v2", + "$autocapture_disabled_server_side": false, + "$active_feature_flags": [ + "signup-page-4.0", + "cmd-k-search", + "posthog-3000", + "funnels-cue-opt-out-7301", + "retention-breakdown", + "smoothing-interval", + "billing-limit", + "kafka-inspector", + "historical-exports-v2", + "person-on-events-enabled", + "region-select", + "ingestion-warnings-enabled", + "session-reset-on-load", + "recordings-on-feature-flags", + "auto-rollback-feature-flags", + "onboarding-v2-demo", + "feature-flag-rollout-ux", + "role-based-access", + "query_running_time", + "query-timings", + "recording-debugging", + "enable-prompts", + "feedback-scene", + "early-access-feature", + "early-access-feature-site-button", + "hedgehog-mode-debug", + "auto-redirect", + "session-recording-blob-replay", + "surveys", + "generic-signup-benefits", + "surveys-positions", + "web-analytics", + "high-frequency-batch-exports", + "exception-autocapture", + "data-warehouse", + "data-warehouse-views", + "ff-dashboard-templates", + "show-product-intro-existing-products", + "artificial-hog", + "cs-dashboards", + "product-specific-onboarding", + "redirect-signups-to-instance", + "apps-and-exports-ui", + "survey-nps-results", + "session-recording-allow-v1-snapshots", + "session-replay-cors-proxy", + "webhooks-denylist", + "surveys-site-app-deprecation", + "surveys-multiple-questions", + "surveys-results-visualizations", + "console-recording-search", + "persons-hogql-query", + "notebooks" + ], + "$feature/file-previews": false, + "$feature/signup-page-4.0": "control", + "$feature/hogql-insights": false, + "$feature/cmd-k-search": true, + "$feature/posthog-3000": true, + "$feature/funnels-cue-opt-out-7301": true, + "$feature/retention-breakdown": true, + "$feature/smoothing-interval": true, + "$feature/billing-limit": true, + "$feature/kafka-inspector": true, + "$feature/historical-exports-v2": true, + "$feature/person-on-events-enabled": true, + "$feature/region-select": true, + "$feature/ingestion-warnings-enabled": true, + "$feature/session-reset-on-load": true, + "$feature/recordings-on-feature-flags": true, + "$feature/auto-rollback-feature-flags": true, + "$feature/onboarding-v2-demo": true, + "$feature/feature-flag-rollout-ux": true, + "$feature/role-based-access": true, + "$feature/query_running_time": true, + "$feature/query-timings": true, + "$feature/recording-debugging": true, + "$feature/enable-prompts": true, + "$feature/feedback-scene": true, + "$feature/early-access-feature": true, + "$feature/early-access-feature-site-button": true, + "$feature/hedgehog-mode-debug": true, + "$feature/auto-redirect": true, + "$feature/session-recording-blob-replay": true, + "$feature/surveys": true, + "$feature/generic-signup-benefits": true, + "$feature/surveys-positions": true, + "$feature/web-analytics": true, + "$feature/high-frequency-batch-exports": true, + "$feature/exception-autocapture": true, + "$feature/data-warehouse": true, + "$feature/data-warehouse-views": true, + "$feature/ff-dashboard-templates": true, + "$feature/show-product-intro-existing-products": true, + "$feature/artificial-hog": true, + "$feature/cs-dashboards": true, + "$feature/product-specific-onboarding": true, + "$feature/redirect-signups-to-instance": true, + "$feature/apps-and-exports-ui": true, + "$feature/survey-nps-results": true, + "$feature/session-recording-allow-v1-snapshots": true, + "$feature/session-replay-cors-proxy": true, + "$feature/webhooks-denylist": true, + "$feature/surveys-site-app-deprecation": true, + "$feature/surveys-multiple-questions": true, + "$feature/surveys-results-visualizations": true, + "$feature/console-recording-search": true, + "$feature/persons-hogql-query": true, + "$feature/notebooks": true, + "$feature_flag_payloads": {}, + "realm": "hosted-clickhouse", + "email_service_available": false, + "slack_service_available": false, + "$user_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "is_demo_project": false, + "$groups": { + "project": "018a92f8-b602-0000-75de-4b9073693531", + "organization": "018a92f8-afff-0000-efec-ca77de39e384", + "customer": "cus_OdSgxxWtHOtq9g", + "instance": "http://localhost:8000" + }, + "has_billing_plan": true, + "customer_deactivated": false, + "current_total_amount_usd": "0.00", + "percentage_usage.product_analytics": 0, + "current_amount_usd.product_analytics": "0.00", + "unit_amount_usd.product_analytics": null, + "usage_limit.product_analytics": null, + "current_usage.product_analytics": 3729, + "projected_usage.product_analytics": 0, + "free_allocation.product_analytics": 0, + "percentage_usage.session_replay": 0, + "current_amount_usd.session_replay": "0.00", + "unit_amount_usd.session_replay": null, + "usage_limit.session_replay": null, + "current_usage.session_replay": 254, + "projected_usage.session_replay": 0, + "free_allocation.session_replay": 0, + "percentage_usage.feature_flags": 0, + "current_amount_usd.feature_flags": "0.00", + "unit_amount_usd.feature_flags": null, + "usage_limit.feature_flags": null, + "current_usage.feature_flags": 0, + "projected_usage.feature_flags": 0, + "free_allocation.feature_flags": 0, + "percentage_usage.integrations": 0, + "current_amount_usd.integrations": null, + "unit_amount_usd.integrations": null, + "usage_limit.integrations": 0, + "current_usage.integrations": 0, + "projected_usage.integrations": 0, + "free_allocation.integrations": 0, + "percentage_usage.platform_and_support": 0, + "current_amount_usd.platform_and_support": null, + "unit_amount_usd.platform_and_support": null, + "usage_limit.platform_and_support": 0, + "current_usage.platform_and_support": 0, + "projected_usage.platform_and_support": 0, + "free_allocation.platform_and_support": 0, + "billing_period_start": "2023-10-14T09:22:33.000Z", + "billing_period_end": "2023-11-14T09:22:33.000Z", + "$referrer": "$direct", + "$referring_domain": "$direct", + "$event_type": "click", + "$ce_version": 1, + "token": "phc_OWGI2wKbfi7rWDZT9wkl8uGcfe0wOGCvflLEZSMiaT0", + "$session_id": "018b4cc2-908b-7989-a77a-ae1396eef1de", + "$window_id": "018b4cc2-908b-7989-a77a-ae1465fa2118", + "$ip": "127.0.0.1", + "$set": { + "$os": "Mac OS X", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/insights/new", + "$pathname": "/insights/new", + "$browser_version": 117, + "$referrer": "$direct", + "$referring_domain": "$direct" + }, + "$set_once": { + "$initial_os": "Mac OS X", + "$initial_browser": "Chrome", + "$initial_device_type": "Desktop", + "$initial_current_url": "http://localhost:8000/insights/new", + "$initial_pathname": "/insights/new", + "$initial_browser_version": 117, + "$initial_referrer": "$direct", + "$initial_referring_domain": "$direct" + }, + "$sent_at": "2023-10-20T11:05:28.530000+00:00", + "$geoip_city_name": "Sydney", + "$geoip_country_name": "Australia", + "$geoip_country_code": "AU", + "$geoip_continent_name": "Oceania", + "$geoip_continent_code": "OC", + "$geoip_postal_code": "2000", + "$geoip_latitude": -33.8715, + "$geoip_longitude": 151.2006, + "$geoip_time_zone": "Australia/Sydney", + "$geoip_subdivision_1_code": "NSW", + "$geoip_subdivision_1_name": "New South Wales", + "$plugins_succeeded": ["GeoIP (1)"], + "$plugins_failed": [], + "$plugins_deferred": [], + "$group_3": "018a92f8-b602-0000-75de-4b9073693531", + "$group_2": "018a92f8-afff-0000-efec-ca77de39e384", + "$group_4": "cus_OdSgxxWtHOtq9g", + "$group_1": "http://localhost:8000" + }, + "timestamp": "2023-10-20T11:05:26.936000+00:00", + "uuid": null + }, + { + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "elements": [], + "elements_chain": null, + "event": "query completed", + "id": "018b4cc2-f5b9-730b-9751-a1d1eb4ecce3", + "person": null, + "properties": { + "$os": "Mac OS X", + "$os_version": "10.15.7", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/insights/new", + "$host": "localhost:8000", + "$pathname": "/insights/new", + "$browser_version": 117, + "$browser_language": "en-GB", + "$screen_height": 982, + "$screen_width": 1512, + "$viewport_height": 859, + "$viewport_width": 1512, + "$lib": "web", + "$lib_version": "1.84.0", + "$insert_id": "qyw1jkyxn1okzklx", + "$time": 1697799927.226, + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$device_id": "018a92fd-7b25-7770-a050-577e94fd148c", + "$console_log_recording_enabled_server_side": true, + "$session_recording_recorder_version_server_side": "v2", + "$autocapture_disabled_server_side": false, + "$active_feature_flags": [ + "signup-page-4.0", + "cmd-k-search", + "posthog-3000", + "funnels-cue-opt-out-7301", + "retention-breakdown", + "smoothing-interval", + "billing-limit", + "kafka-inspector", + "historical-exports-v2", + "person-on-events-enabled", + "region-select", + "ingestion-warnings-enabled", + "session-reset-on-load", + "recordings-on-feature-flags", + "auto-rollback-feature-flags", + "onboarding-v2-demo", + "feature-flag-rollout-ux", + "role-based-access", + "query_running_time", + "query-timings", + "recording-debugging", + "enable-prompts", + "feedback-scene", + "early-access-feature", + "early-access-feature-site-button", + "hedgehog-mode-debug", + "auto-redirect", + "session-recording-blob-replay", + "surveys", + "generic-signup-benefits", + "surveys-positions", + "web-analytics", + "high-frequency-batch-exports", + "exception-autocapture", + "data-warehouse", + "data-warehouse-views", + "ff-dashboard-templates", + "show-product-intro-existing-products", + "artificial-hog", + "cs-dashboards", + "product-specific-onboarding", + "redirect-signups-to-instance", + "apps-and-exports-ui", + "survey-nps-results", + "session-recording-allow-v1-snapshots", + "session-replay-cors-proxy", + "webhooks-denylist", + "surveys-site-app-deprecation", + "surveys-multiple-questions", + "surveys-results-visualizations", + "console-recording-search", + "persons-hogql-query", + "notebooks" + ], + "$feature/file-previews": false, + "$feature/signup-page-4.0": "control", + "$feature/hogql-insights": false, + "$feature/cmd-k-search": true, + "$feature/posthog-3000": true, + "$feature/funnels-cue-opt-out-7301": true, + "$feature/retention-breakdown": true, + "$feature/smoothing-interval": true, + "$feature/billing-limit": true, + "$feature/kafka-inspector": true, + "$feature/historical-exports-v2": true, + "$feature/person-on-events-enabled": true, + "$feature/region-select": true, + "$feature/ingestion-warnings-enabled": true, + "$feature/session-reset-on-load": true, + "$feature/recordings-on-feature-flags": true, + "$feature/auto-rollback-feature-flags": true, + "$feature/onboarding-v2-demo": true, + "$feature/feature-flag-rollout-ux": true, + "$feature/role-based-access": true, + "$feature/query_running_time": true, + "$feature/query-timings": true, + "$feature/recording-debugging": true, + "$feature/enable-prompts": true, + "$feature/feedback-scene": true, + "$feature/early-access-feature": true, + "$feature/early-access-feature-site-button": true, + "$feature/hedgehog-mode-debug": true, + "$feature/auto-redirect": true, + "$feature/session-recording-blob-replay": true, + "$feature/surveys": true, + "$feature/generic-signup-benefits": true, + "$feature/surveys-positions": true, + "$feature/web-analytics": true, + "$feature/high-frequency-batch-exports": true, + "$feature/exception-autocapture": true, + "$feature/data-warehouse": true, + "$feature/data-warehouse-views": true, + "$feature/ff-dashboard-templates": true, + "$feature/show-product-intro-existing-products": true, + "$feature/artificial-hog": true, + "$feature/cs-dashboards": true, + "$feature/product-specific-onboarding": true, + "$feature/redirect-signups-to-instance": true, + "$feature/apps-and-exports-ui": true, + "$feature/survey-nps-results": true, + "$feature/session-recording-allow-v1-snapshots": true, + "$feature/session-replay-cors-proxy": true, + "$feature/webhooks-denylist": true, + "$feature/surveys-site-app-deprecation": true, + "$feature/surveys-multiple-questions": true, + "$feature/surveys-results-visualizations": true, + "$feature/console-recording-search": true, + "$feature/persons-hogql-query": true, + "$feature/notebooks": true, + "$feature_flag_payloads": {}, + "realm": "hosted-clickhouse", + "email_service_available": false, + "slack_service_available": false, + "$user_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "is_demo_project": false, + "$groups": { + "project": "018a92f8-b602-0000-75de-4b9073693531", + "organization": "018a92f8-afff-0000-efec-ca77de39e384", + "customer": "cus_OdSgxxWtHOtq9g", + "instance": "http://localhost:8000" + }, + "has_billing_plan": true, + "customer_deactivated": false, + "current_total_amount_usd": "0.00", + "percentage_usage.product_analytics": 0, + "current_amount_usd.product_analytics": "0.00", + "unit_amount_usd.product_analytics": null, + "usage_limit.product_analytics": null, + "current_usage.product_analytics": 3729, + "projected_usage.product_analytics": 0, + "free_allocation.product_analytics": 0, + "percentage_usage.session_replay": 0, + "current_amount_usd.session_replay": "0.00", + "unit_amount_usd.session_replay": null, + "usage_limit.session_replay": null, + "current_usage.session_replay": 254, + "projected_usage.session_replay": 0, + "free_allocation.session_replay": 0, + "percentage_usage.feature_flags": 0, + "current_amount_usd.feature_flags": "0.00", + "unit_amount_usd.feature_flags": null, + "usage_limit.feature_flags": null, + "current_usage.feature_flags": 0, + "projected_usage.feature_flags": 0, + "free_allocation.feature_flags": 0, + "percentage_usage.integrations": 0, + "current_amount_usd.integrations": null, + "unit_amount_usd.integrations": null, + "usage_limit.integrations": 0, + "current_usage.integrations": 0, + "projected_usage.integrations": 0, + "free_allocation.integrations": 0, + "percentage_usage.platform_and_support": 0, + "current_amount_usd.platform_and_support": null, + "unit_amount_usd.platform_and_support": null, + "usage_limit.platform_and_support": 0, + "current_usage.platform_and_support": 0, + "projected_usage.platform_and_support": 0, + "free_allocation.platform_and_support": 0, + "billing_period_start": "2023-10-14T09:22:33.000Z", + "billing_period_end": "2023-11-14T09:22:33.000Z", + "$referrer": "$direct", + "$referring_domain": "$direct", + "query": { + "kind": "FunnelsQuery", + "series": [ + { + "kind": "EventsNode", + "name": "$pageview", + "event": "$pageview" + } + ], + "funnelsFilter": { + "funnel_viz_type": "steps" + } + }, + "duration": 237.10000002384186, + "token": "phc_OWGI2wKbfi7rWDZT9wkl8uGcfe0wOGCvflLEZSMiaT0", + "$session_id": "018b4cc2-908b-7989-a77a-ae1396eef1de", + "$window_id": "018b4cc2-908b-7989-a77a-ae1465fa2118", + "$ip": "127.0.0.1", + "$set": { + "$os": "Mac OS X", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/insights/new", + "$pathname": "/insights/new", + "$browser_version": 117, + "$referrer": "$direct", + "$referring_domain": "$direct" + }, + "$set_once": { + "$initial_os": "Mac OS X", + "$initial_browser": "Chrome", + "$initial_device_type": "Desktop", + "$initial_current_url": "http://localhost:8000/insights/new", + "$initial_pathname": "/insights/new", + "$initial_browser_version": 117, + "$initial_referrer": "$direct", + "$initial_referring_domain": "$direct" + }, + "$sent_at": "2023-10-20T11:05:28.530000+00:00", + "$geoip_city_name": "Sydney", + "$geoip_country_name": "Australia", + "$geoip_country_code": "AU", + "$geoip_continent_name": "Oceania", + "$geoip_continent_code": "OC", + "$geoip_postal_code": "2000", + "$geoip_latitude": -33.8715, + "$geoip_longitude": 151.2006, + "$geoip_time_zone": "Australia/Sydney", + "$geoip_subdivision_1_code": "NSW", + "$geoip_subdivision_1_name": "New South Wales", + "$plugins_succeeded": ["GeoIP (1)"], + "$plugins_failed": [], + "$plugins_deferred": [], + "$group_3": "018a92f8-b602-0000-75de-4b9073693531", + "$group_2": "018a92f8-afff-0000-efec-ca77de39e384", + "$group_4": "cus_OdSgxxWtHOtq9g", + "$group_1": "http://localhost:8000" + }, + "timestamp": "2023-10-20T11:05:27.233000+00:00", + "uuid": null + }, + { + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "elements": [], + "elements_chain": null, + "event": "insight viewed", + "id": "018b4cc2-f68d-7712-8860-14242f72c761", + "person": null, + "properties": { + "$os": "Mac OS X", + "$os_version": "10.15.7", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/insights/new", + "$host": "localhost:8000", + "$pathname": "/insights/new", + "$browser_version": 117, + "$browser_language": "en-GB", + "$screen_height": 982, + "$screen_width": 1512, + "$viewport_height": 859, + "$viewport_width": 1512, + "$lib": "web", + "$lib_version": "1.84.0", + "$insert_id": "ing4xyzshu1yped4", + "$time": 1697799927.437, + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$device_id": "018a92fd-7b25-7770-a050-577e94fd148c", + "$console_log_recording_enabled_server_side": true, + "$session_recording_recorder_version_server_side": "v2", + "$autocapture_disabled_server_side": false, + "$active_feature_flags": [ + "signup-page-4.0", + "cmd-k-search", + "posthog-3000", + "funnels-cue-opt-out-7301", + "retention-breakdown", + "smoothing-interval", + "billing-limit", + "kafka-inspector", + "historical-exports-v2", + "person-on-events-enabled", + "region-select", + "ingestion-warnings-enabled", + "session-reset-on-load", + "recordings-on-feature-flags", + "auto-rollback-feature-flags", + "onboarding-v2-demo", + "feature-flag-rollout-ux", + "role-based-access", + "query_running_time", + "query-timings", + "recording-debugging", + "enable-prompts", + "feedback-scene", + "early-access-feature", + "early-access-feature-site-button", + "hedgehog-mode-debug", + "auto-redirect", + "session-recording-blob-replay", + "surveys", + "generic-signup-benefits", + "surveys-positions", + "web-analytics", + "high-frequency-batch-exports", + "exception-autocapture", + "data-warehouse", + "data-warehouse-views", + "ff-dashboard-templates", + "show-product-intro-existing-products", + "artificial-hog", + "cs-dashboards", + "product-specific-onboarding", + "redirect-signups-to-instance", + "apps-and-exports-ui", + "survey-nps-results", + "session-recording-allow-v1-snapshots", + "session-replay-cors-proxy", + "webhooks-denylist", + "surveys-site-app-deprecation", + "surveys-multiple-questions", + "surveys-results-visualizations", + "console-recording-search", + "persons-hogql-query", + "notebooks" + ], + "$feature/file-previews": false, + "$feature/signup-page-4.0": "control", + "$feature/hogql-insights": false, + "$feature/cmd-k-search": true, + "$feature/posthog-3000": true, + "$feature/funnels-cue-opt-out-7301": true, + "$feature/retention-breakdown": true, + "$feature/smoothing-interval": true, + "$feature/billing-limit": true, + "$feature/kafka-inspector": true, + "$feature/historical-exports-v2": true, + "$feature/person-on-events-enabled": true, + "$feature/region-select": true, + "$feature/ingestion-warnings-enabled": true, + "$feature/session-reset-on-load": true, + "$feature/recordings-on-feature-flags": true, + "$feature/auto-rollback-feature-flags": true, + "$feature/onboarding-v2-demo": true, + "$feature/feature-flag-rollout-ux": true, + "$feature/role-based-access": true, + "$feature/query_running_time": true, + "$feature/query-timings": true, + "$feature/recording-debugging": true, + "$feature/enable-prompts": true, + "$feature/feedback-scene": true, + "$feature/early-access-feature": true, + "$feature/early-access-feature-site-button": true, + "$feature/hedgehog-mode-debug": true, + "$feature/auto-redirect": true, + "$feature/session-recording-blob-replay": true, + "$feature/surveys": true, + "$feature/generic-signup-benefits": true, + "$feature/surveys-positions": true, + "$feature/web-analytics": true, + "$feature/high-frequency-batch-exports": true, + "$feature/exception-autocapture": true, + "$feature/data-warehouse": true, + "$feature/data-warehouse-views": true, + "$feature/ff-dashboard-templates": true, + "$feature/show-product-intro-existing-products": true, + "$feature/artificial-hog": true, + "$feature/cs-dashboards": true, + "$feature/product-specific-onboarding": true, + "$feature/redirect-signups-to-instance": true, + "$feature/apps-and-exports-ui": true, + "$feature/survey-nps-results": true, + "$feature/session-recording-allow-v1-snapshots": true, + "$feature/session-replay-cors-proxy": true, + "$feature/webhooks-denylist": true, + "$feature/surveys-site-app-deprecation": true, + "$feature/surveys-multiple-questions": true, + "$feature/surveys-results-visualizations": true, + "$feature/console-recording-search": true, + "$feature/persons-hogql-query": true, + "$feature/notebooks": true, + "$feature_flag_payloads": {}, + "realm": "hosted-clickhouse", + "email_service_available": false, + "slack_service_available": false, + "$user_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "is_demo_project": false, + "$groups": { + "project": "018a92f8-b602-0000-75de-4b9073693531", + "organization": "018a92f8-afff-0000-efec-ca77de39e384", + "customer": "cus_OdSgxxWtHOtq9g", + "instance": "http://localhost:8000" + }, + "has_billing_plan": true, + "customer_deactivated": false, + "current_total_amount_usd": "0.00", + "percentage_usage.product_analytics": 0, + "current_amount_usd.product_analytics": "0.00", + "unit_amount_usd.product_analytics": null, + "usage_limit.product_analytics": null, + "current_usage.product_analytics": 3729, + "projected_usage.product_analytics": 0, + "free_allocation.product_analytics": 0, + "percentage_usage.session_replay": 0, + "current_amount_usd.session_replay": "0.00", + "unit_amount_usd.session_replay": null, + "usage_limit.session_replay": null, + "current_usage.session_replay": 254, + "projected_usage.session_replay": 0, + "free_allocation.session_replay": 0, + "percentage_usage.feature_flags": 0, + "current_amount_usd.feature_flags": "0.00", + "unit_amount_usd.feature_flags": null, + "usage_limit.feature_flags": null, + "current_usage.feature_flags": 0, + "projected_usage.feature_flags": 0, + "free_allocation.feature_flags": 0, + "percentage_usage.integrations": 0, + "current_amount_usd.integrations": null, + "unit_amount_usd.integrations": null, + "usage_limit.integrations": 0, + "current_usage.integrations": 0, + "projected_usage.integrations": 0, + "free_allocation.integrations": 0, + "percentage_usage.platform_and_support": 0, + "current_amount_usd.platform_and_support": null, + "unit_amount_usd.platform_and_support": null, + "usage_limit.platform_and_support": 0, + "current_usage.platform_and_support": 0, + "projected_usage.platform_and_support": 0, + "free_allocation.platform_and_support": 0, + "billing_period_start": "2023-10-14T09:22:33.000Z", + "billing_period_end": "2023-11-14T09:22:33.000Z", + "$referrer": "$direct", + "$referring_domain": "$direct", + "filters_count": 0, + "events_count": 1, + "actions_count": 0, + "funnel_viz_type": "steps", + "properties_global": [], + "properties_global_custom_count": 0, + "properties_local": [], + "properties_local_custom_count": 0, + "properties_all": [], + "aggregating_by_groups": false, + "breakdown_by_groups": false, + "using_groups": false, + "used_cohort_filter_ids": [], + "insight": "FUNNELS", + "report_delay": 0, + "is_first_component_load": true, + "from_dashboard": false, + "total_event_actions_count": 1, + "total_event_action_filters_count": 0, + "mode": "edit", + "viewer_is_creator": false, + "description_length": 0, + "tags_count": 0, + "changed_insight": "TRENDS", + "changed_entity_type": [], + "changed_interval": "day", + "changed_hidden_legend_keys": [], + "changed_funnel_viz_type": [], + "token": "phc_OWGI2wKbfi7rWDZT9wkl8uGcfe0wOGCvflLEZSMiaT0", + "$session_id": "018b4cc2-908b-7989-a77a-ae1396eef1de", + "$window_id": "018b4cc2-908b-7989-a77a-ae1465fa2118", + "$ip": "127.0.0.1", + "$set": { + "$os": "Mac OS X", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/insights/new", + "$pathname": "/insights/new", + "$browser_version": 117, + "$referrer": "$direct", + "$referring_domain": "$direct" + }, + "$set_once": { + "$initial_os": "Mac OS X", + "$initial_browser": "Chrome", + "$initial_device_type": "Desktop", + "$initial_current_url": "http://localhost:8000/insights/new", + "$initial_pathname": "/insights/new", + "$initial_browser_version": 117, + "$initial_referrer": "$direct", + "$initial_referring_domain": "$direct" + }, + "$sent_at": "2023-10-20T11:05:28.530000+00:00", + "$geoip_city_name": "Sydney", + "$geoip_country_name": "Australia", + "$geoip_country_code": "AU", + "$geoip_continent_name": "Oceania", + "$geoip_continent_code": "OC", + "$geoip_postal_code": "2000", + "$geoip_latitude": -33.8715, + "$geoip_longitude": 151.2006, + "$geoip_time_zone": "Australia/Sydney", + "$geoip_subdivision_1_code": "NSW", + "$geoip_subdivision_1_name": "New South Wales", + "$plugins_succeeded": ["GeoIP (1)"], + "$plugins_failed": [], + "$plugins_deferred": [], + "$group_3": "018a92f8-b602-0000-75de-4b9073693531", + "$group_2": "018a92f8-afff-0000-efec-ca77de39e384", + "$group_4": "cus_OdSgxxWtHOtq9g", + "$group_1": "http://localhost:8000" + }, + "timestamp": "2023-10-20T11:05:27.445000+00:00", + "uuid": null + }, + { + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "elements": [], + "elements_chain": null, + "event": "insight analyzed", + "id": "018b4cc3-1da3-79bc-84eb-ba4883cd3036", + "person": null, + "properties": { + "$os": "Mac OS X", + "$os_version": "10.15.7", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/insights/new", + "$host": "localhost:8000", + "$pathname": "/insights/new", + "$browser_version": 117, + "$browser_language": "en-GB", + "$screen_height": 982, + "$screen_width": 1512, + "$viewport_height": 859, + "$viewport_width": 1512, + "$lib": "web", + "$lib_version": "1.84.0", + "$insert_id": "679ovhx0nx9fbz6c", + "$time": 1697799937.443, + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$device_id": "018a92fd-7b25-7770-a050-577e94fd148c", + "$console_log_recording_enabled_server_side": true, + "$session_recording_recorder_version_server_side": "v2", + "$autocapture_disabled_server_side": false, + "$active_feature_flags": [ + "signup-page-4.0", + "cmd-k-search", + "posthog-3000", + "funnels-cue-opt-out-7301", + "retention-breakdown", + "smoothing-interval", + "billing-limit", + "kafka-inspector", + "historical-exports-v2", + "person-on-events-enabled", + "region-select", + "ingestion-warnings-enabled", + "session-reset-on-load", + "recordings-on-feature-flags", + "auto-rollback-feature-flags", + "onboarding-v2-demo", + "feature-flag-rollout-ux", + "role-based-access", + "query_running_time", + "query-timings", + "recording-debugging", + "enable-prompts", + "feedback-scene", + "early-access-feature", + "early-access-feature-site-button", + "hedgehog-mode-debug", + "auto-redirect", + "session-recording-blob-replay", + "surveys", + "generic-signup-benefits", + "surveys-positions", + "web-analytics", + "high-frequency-batch-exports", + "exception-autocapture", + "data-warehouse", + "data-warehouse-views", + "ff-dashboard-templates", + "show-product-intro-existing-products", + "artificial-hog", + "cs-dashboards", + "product-specific-onboarding", + "redirect-signups-to-instance", + "apps-and-exports-ui", + "survey-nps-results", + "session-recording-allow-v1-snapshots", + "session-replay-cors-proxy", + "webhooks-denylist", + "surveys-site-app-deprecation", + "surveys-multiple-questions", + "surveys-results-visualizations", + "console-recording-search", + "persons-hogql-query", + "notebooks" + ], + "$feature/file-previews": false, + "$feature/signup-page-4.0": "control", + "$feature/hogql-insights": false, + "$feature/cmd-k-search": true, + "$feature/posthog-3000": true, + "$feature/funnels-cue-opt-out-7301": true, + "$feature/retention-breakdown": true, + "$feature/smoothing-interval": true, + "$feature/billing-limit": true, + "$feature/kafka-inspector": true, + "$feature/historical-exports-v2": true, + "$feature/person-on-events-enabled": true, + "$feature/region-select": true, + "$feature/ingestion-warnings-enabled": true, + "$feature/session-reset-on-load": true, + "$feature/recordings-on-feature-flags": true, + "$feature/auto-rollback-feature-flags": true, + "$feature/onboarding-v2-demo": true, + "$feature/feature-flag-rollout-ux": true, + "$feature/role-based-access": true, + "$feature/query_running_time": true, + "$feature/query-timings": true, + "$feature/recording-debugging": true, + "$feature/enable-prompts": true, + "$feature/feedback-scene": true, + "$feature/early-access-feature": true, + "$feature/early-access-feature-site-button": true, + "$feature/hedgehog-mode-debug": true, + "$feature/auto-redirect": true, + "$feature/session-recording-blob-replay": true, + "$feature/surveys": true, + "$feature/generic-signup-benefits": true, + "$feature/surveys-positions": true, + "$feature/web-analytics": true, + "$feature/high-frequency-batch-exports": true, + "$feature/exception-autocapture": true, + "$feature/data-warehouse": true, + "$feature/data-warehouse-views": true, + "$feature/ff-dashboard-templates": true, + "$feature/show-product-intro-existing-products": true, + "$feature/artificial-hog": true, + "$feature/cs-dashboards": true, + "$feature/product-specific-onboarding": true, + "$feature/redirect-signups-to-instance": true, + "$feature/apps-and-exports-ui": true, + "$feature/survey-nps-results": true, + "$feature/session-recording-allow-v1-snapshots": true, + "$feature/session-replay-cors-proxy": true, + "$feature/webhooks-denylist": true, + "$feature/surveys-site-app-deprecation": true, + "$feature/surveys-multiple-questions": true, + "$feature/surveys-results-visualizations": true, + "$feature/console-recording-search": true, + "$feature/persons-hogql-query": true, + "$feature/notebooks": true, + "$feature_flag_payloads": {}, + "realm": "hosted-clickhouse", + "email_service_available": false, + "slack_service_available": false, + "$user_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "is_demo_project": false, + "$groups": { + "project": "018a92f8-b602-0000-75de-4b9073693531", + "organization": "018a92f8-afff-0000-efec-ca77de39e384", + "customer": "cus_OdSgxxWtHOtq9g", + "instance": "http://localhost:8000" + }, + "has_billing_plan": true, + "customer_deactivated": false, + "current_total_amount_usd": "0.00", + "percentage_usage.product_analytics": 0, + "current_amount_usd.product_analytics": "0.00", + "unit_amount_usd.product_analytics": null, + "usage_limit.product_analytics": null, + "current_usage.product_analytics": 3729, + "projected_usage.product_analytics": 0, + "free_allocation.product_analytics": 0, + "percentage_usage.session_replay": 0, + "current_amount_usd.session_replay": "0.00", + "unit_amount_usd.session_replay": null, + "usage_limit.session_replay": null, + "current_usage.session_replay": 254, + "projected_usage.session_replay": 0, + "free_allocation.session_replay": 0, + "percentage_usage.feature_flags": 0, + "current_amount_usd.feature_flags": "0.00", + "unit_amount_usd.feature_flags": null, + "usage_limit.feature_flags": null, + "current_usage.feature_flags": 0, + "projected_usage.feature_flags": 0, + "free_allocation.feature_flags": 0, + "percentage_usage.integrations": 0, + "current_amount_usd.integrations": null, + "unit_amount_usd.integrations": null, + "usage_limit.integrations": 0, + "current_usage.integrations": 0, + "projected_usage.integrations": 0, + "free_allocation.integrations": 0, + "percentage_usage.platform_and_support": 0, + "current_amount_usd.platform_and_support": null, + "unit_amount_usd.platform_and_support": null, + "usage_limit.platform_and_support": 0, + "current_usage.platform_and_support": 0, + "projected_usage.platform_and_support": 0, + "free_allocation.platform_and_support": 0, + "billing_period_start": "2023-10-14T09:22:33.000Z", + "billing_period_end": "2023-11-14T09:22:33.000Z", + "$referrer": "$direct", + "$referring_domain": "$direct", + "filters_count": 0, + "events_count": 1, + "actions_count": 0, + "funnel_viz_type": "steps", + "properties_global": [], + "properties_global_custom_count": 0, + "properties_local": [], + "properties_local_custom_count": 0, + "properties_all": [], + "aggregating_by_groups": false, + "breakdown_by_groups": false, + "using_groups": false, + "used_cohort_filter_ids": [], + "insight": "FUNNELS", + "report_delay": 10, + "is_first_component_load": false, + "from_dashboard": false, + "total_event_actions_count": 1, + "total_event_action_filters_count": 0, + "mode": "edit", + "viewer_is_creator": false, + "description_length": 0, + "tags_count": 0, + "changed_insight": "TRENDS", + "changed_entity_type": [], + "changed_interval": "day", + "changed_hidden_legend_keys": [], + "changed_funnel_viz_type": [], + "token": "phc_OWGI2wKbfi7rWDZT9wkl8uGcfe0wOGCvflLEZSMiaT0", + "$session_id": "018b4cc2-908b-7989-a77a-ae1396eef1de", + "$window_id": "018b4cc2-908b-7989-a77a-ae1465fa2118", + "$ip": "127.0.0.1", + "$set": { + "$os": "Mac OS X", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/insights/new", + "$pathname": "/insights/new", + "$browser_version": 117, + "$referrer": "$direct", + "$referring_domain": "$direct" + }, + "$set_once": { + "$initial_os": "Mac OS X", + "$initial_browser": "Chrome", + "$initial_device_type": "Desktop", + "$initial_current_url": "http://localhost:8000/insights/new", + "$initial_pathname": "/insights/new", + "$initial_browser_version": 117, + "$initial_referrer": "$direct", + "$initial_referring_domain": "$direct" + }, + "$sent_at": "2023-10-20T11:05:37.539000+00:00", + "$geoip_city_name": "Sydney", + "$geoip_country_name": "Australia", + "$geoip_country_code": "AU", + "$geoip_continent_name": "Oceania", + "$geoip_continent_code": "OC", + "$geoip_postal_code": "2000", + "$geoip_latitude": -33.8715, + "$geoip_longitude": 151.2006, + "$geoip_time_zone": "Australia/Sydney", + "$geoip_subdivision_1_code": "NSW", + "$geoip_subdivision_1_name": "New South Wales", + "$plugins_succeeded": ["GeoIP (1)"], + "$plugins_failed": [], + "$plugins_deferred": [], + "$group_3": "018a92f8-b602-0000-75de-4b9073693531", + "$group_2": "018a92f8-afff-0000-efec-ca77de39e384", + "$group_4": "cus_OdSgxxWtHOtq9g", + "$group_1": "http://localhost:8000" + }, + "timestamp": "2023-10-20T11:05:37.451000+00:00", + "uuid": null + }, + { + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "elements": [], + "elements_chain": null, + "event": "$pageleave", + "id": "018b4cc3-513e-7fef-ab2a-04ab143a4f1c", + "person": null, + "properties": { + "$os": "Mac OS X", + "$os_version": "10.15.7", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/insights/new", + "$host": "localhost:8000", + "$pathname": "/insights/new", + "$browser_version": 117, + "$browser_language": "en-GB", + "$screen_height": 982, + "$screen_width": 1512, + "$viewport_height": 859, + "$viewport_width": 1512, + "$lib": "web", + "$lib_version": "1.84.0", + "$insert_id": "l3xm3x64ia727uwa", + "$time": 1697799950.655, + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$device_id": "018a92fd-7b25-7770-a050-577e94fd148c", + "$console_log_recording_enabled_server_side": true, + "$session_recording_recorder_version_server_side": "v2", + "$autocapture_disabled_server_side": false, + "$active_feature_flags": [ + "signup-page-4.0", + "cmd-k-search", + "posthog-3000", + "funnels-cue-opt-out-7301", + "retention-breakdown", + "smoothing-interval", + "billing-limit", + "kafka-inspector", + "historical-exports-v2", + "person-on-events-enabled", + "region-select", + "ingestion-warnings-enabled", + "session-reset-on-load", + "recordings-on-feature-flags", + "auto-rollback-feature-flags", + "onboarding-v2-demo", + "feature-flag-rollout-ux", + "role-based-access", + "query_running_time", + "query-timings", + "recording-debugging", + "enable-prompts", + "feedback-scene", + "early-access-feature", + "early-access-feature-site-button", + "hedgehog-mode-debug", + "auto-redirect", + "session-recording-blob-replay", + "surveys", + "generic-signup-benefits", + "surveys-positions", + "web-analytics", + "high-frequency-batch-exports", + "exception-autocapture", + "data-warehouse", + "data-warehouse-views", + "ff-dashboard-templates", + "show-product-intro-existing-products", + "artificial-hog", + "cs-dashboards", + "product-specific-onboarding", + "redirect-signups-to-instance", + "apps-and-exports-ui", + "survey-nps-results", + "session-recording-allow-v1-snapshots", + "session-replay-cors-proxy", + "webhooks-denylist", + "surveys-site-app-deprecation", + "surveys-multiple-questions", + "surveys-results-visualizations", + "console-recording-search", + "persons-hogql-query", + "notebooks" + ], + "$feature/file-previews": false, + "$feature/signup-page-4.0": "control", + "$feature/hogql-insights": false, + "$feature/cmd-k-search": true, + "$feature/posthog-3000": true, + "$feature/funnels-cue-opt-out-7301": true, + "$feature/retention-breakdown": true, + "$feature/smoothing-interval": true, + "$feature/billing-limit": true, + "$feature/kafka-inspector": true, + "$feature/historical-exports-v2": true, + "$feature/person-on-events-enabled": true, + "$feature/region-select": true, + "$feature/ingestion-warnings-enabled": true, + "$feature/session-reset-on-load": true, + "$feature/recordings-on-feature-flags": true, + "$feature/auto-rollback-feature-flags": true, + "$feature/onboarding-v2-demo": true, + "$feature/feature-flag-rollout-ux": true, + "$feature/role-based-access": true, + "$feature/query_running_time": true, + "$feature/query-timings": true, + "$feature/recording-debugging": true, + "$feature/enable-prompts": true, + "$feature/feedback-scene": true, + "$feature/early-access-feature": true, + "$feature/early-access-feature-site-button": true, + "$feature/hedgehog-mode-debug": true, + "$feature/auto-redirect": true, + "$feature/session-recording-blob-replay": true, + "$feature/surveys": true, + "$feature/generic-signup-benefits": true, + "$feature/surveys-positions": true, + "$feature/web-analytics": true, + "$feature/high-frequency-batch-exports": true, + "$feature/exception-autocapture": true, + "$feature/data-warehouse": true, + "$feature/data-warehouse-views": true, + "$feature/ff-dashboard-templates": true, + "$feature/show-product-intro-existing-products": true, + "$feature/artificial-hog": true, + "$feature/cs-dashboards": true, + "$feature/product-specific-onboarding": true, + "$feature/redirect-signups-to-instance": true, + "$feature/apps-and-exports-ui": true, + "$feature/survey-nps-results": true, + "$feature/session-recording-allow-v1-snapshots": true, + "$feature/session-replay-cors-proxy": true, + "$feature/webhooks-denylist": true, + "$feature/surveys-site-app-deprecation": true, + "$feature/surveys-multiple-questions": true, + "$feature/surveys-results-visualizations": true, + "$feature/console-recording-search": true, + "$feature/persons-hogql-query": true, + "$feature/notebooks": true, + "$feature_flag_payloads": {}, + "realm": "hosted-clickhouse", + "email_service_available": false, + "slack_service_available": false, + "$user_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "is_demo_project": false, + "$groups": { + "project": "018a92f8-b602-0000-75de-4b9073693531", + "organization": "018a92f8-afff-0000-efec-ca77de39e384", + "customer": "cus_OdSgxxWtHOtq9g", + "instance": "http://localhost:8000" + }, + "has_billing_plan": true, + "customer_deactivated": false, + "current_total_amount_usd": "0.00", + "percentage_usage.product_analytics": 0, + "current_amount_usd.product_analytics": "0.00", + "unit_amount_usd.product_analytics": null, + "usage_limit.product_analytics": null, + "current_usage.product_analytics": 3729, + "projected_usage.product_analytics": 0, + "free_allocation.product_analytics": 0, + "percentage_usage.session_replay": 0, + "current_amount_usd.session_replay": "0.00", + "unit_amount_usd.session_replay": null, + "usage_limit.session_replay": null, + "current_usage.session_replay": 254, + "projected_usage.session_replay": 0, + "free_allocation.session_replay": 0, + "percentage_usage.feature_flags": 0, + "current_amount_usd.feature_flags": "0.00", + "unit_amount_usd.feature_flags": null, + "usage_limit.feature_flags": null, + "current_usage.feature_flags": 0, + "projected_usage.feature_flags": 0, + "free_allocation.feature_flags": 0, + "percentage_usage.integrations": 0, + "current_amount_usd.integrations": null, + "unit_amount_usd.integrations": null, + "usage_limit.integrations": 0, + "current_usage.integrations": 0, + "projected_usage.integrations": 0, + "free_allocation.integrations": 0, + "percentage_usage.platform_and_support": 0, + "current_amount_usd.platform_and_support": null, + "unit_amount_usd.platform_and_support": null, + "usage_limit.platform_and_support": 0, + "current_usage.platform_and_support": 0, + "projected_usage.platform_and_support": 0, + "free_allocation.platform_and_support": 0, + "billing_period_start": "2023-10-14T09:22:33.000Z", + "billing_period_end": "2023-11-14T09:22:33.000Z", + "$referrer": "$direct", + "$referring_domain": "$direct", + "token": "phc_OWGI2wKbfi7rWDZT9wkl8uGcfe0wOGCvflLEZSMiaT0", + "$session_id": "018b4cc2-908b-7989-a77a-ae1396eef1de", + "$window_id": "018b4cc2-908b-7989-a77a-ae1465fa2118", + "$ip": "127.0.0.1", + "$set": { + "$os": "Mac OS X", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/insights/new", + "$pathname": "/insights/new", + "$browser_version": 117, + "$referrer": "$direct", + "$referring_domain": "$direct" + }, + "$set_once": { + "$initial_os": "Mac OS X", + "$initial_browser": "Chrome", + "$initial_device_type": "Desktop", + "$initial_current_url": "http://localhost:8000/insights/new", + "$initial_pathname": "/insights/new", + "$initial_browser_version": 117, + "$initial_referrer": "$direct", + "$initial_referring_domain": "$direct" + }, + "$sent_at": "2023-10-20T11:05:50.657000+00:00", + "$geoip_city_name": "Sydney", + "$geoip_country_name": "Australia", + "$geoip_country_code": "AU", + "$geoip_continent_name": "Oceania", + "$geoip_continent_code": "OC", + "$geoip_postal_code": "2000", + "$geoip_latitude": -33.8715, + "$geoip_longitude": 151.2006, + "$geoip_time_zone": "Australia/Sydney", + "$geoip_subdivision_1_code": "NSW", + "$geoip_subdivision_1_name": "New South Wales", + "$plugins_succeeded": ["GeoIP (1)"], + "$plugins_failed": [], + "$plugins_deferred": [], + "$group_3": "018a92f8-b602-0000-75de-4b9073693531", + "$group_2": "018a92f8-afff-0000-efec-ca77de39e384", + "$group_4": "cus_OdSgxxWtHOtq9g", + "$group_1": "http://localhost:8000" + }, + "timestamp": "2023-10-20T11:05:50.674000+00:00", + "uuid": null + } + ], + "recording_duration_s": 50.0, + "sessionId": "018b4cc2-908b-7989-a77a-ae1396eef1de" + }, + { + "events": [ + { + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "elements": [], + "elements_chain": null, + "event": "$set", + "id": "018b4ca3-1d07-7195-8202-c8a0a4015ef4", + "person": null, + "properties": { + "$os": "Mac OS X", + "$os_version": "10.15.7", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI#activeTab=feed&state=eyJ0eXBlIjoiZG9jIiwiY29udGVudCI6W3sidHlwZSI6ImhlYWRpbmciLCJhdHRycyI6eyJsZXZlbCI6MX0sImNvbnRlbnQiOlt7InR5cGUiOiJ0ZXh0IiwidGV4dCI6ImtyUmZnb3BzVXkxVHdOVTF5aFNETHFORFRkNk41dE1ackhsbThuTEpJREkifV19LHsidHlwZSI6InBoLXBlcnNvbi1mZWVkIiwiYXR0cnMiOnsiaGVpZ2h0IjpudWxsLCJ0aXRsZSI6bnVsbCwibm9kZUlkIjoiNmQ0ODUwNjYtZWM5OS00ODNkLThiOTgtNGQ4YTJkYzljYzRiIiwiaWQiOiJrclJmZ29wc1V5MVR3TlUxeWhTRExxTkRUZDZONXRNWnJIbG04bkxKSURJIiwiX19pbml0IjpudWxsLCJjaGlsZHJlbiI6W3sidHlwZSI6InBoLXBlcnNvbiIsImF0dHJzIjp7ImlkIjoia3JSZmdvcHNVeTFUd05VMXloU0RMcU5EVGQ2TjV0TVpySGxtOG5MSklESSIsIm5vZGVJZCI6IjNkMzZiZjU3LTFkYjQtNDJlZi1iNzhiLWUyZDNkNGViOWM5NSJ9fSx7InR5cGUiOiJwaC1tYXAiLCJhdHRycyI6eyJpZCI6ImtyUmZnb3BzVXkxVHdOVTF5aFNETHFORFRkNk41dE1ackhsbThuTEpJREkiLCJub2RlSWQiOiI1MzE0ZWI2MS1lYTA2LTQyOGQtYWEzZi0zMDA4OWJjZmUxYjgifX0seyJ0eXBlIjoicGgtcHJvcGVydGllcyIsImF0dHJzIjp7ImlkIjoia3JSZmdvcHNVeTFUd05VMXloU0RMcU5EVGQ2TjV0TVpySGxtOG5MSklESSIsIm5vZGVJZCI6ImUwMjE1NDU5LWY0YTgtNGJjNy04NDhmLTYxODE1NzY1NzlmNyJ9fV19fV19", + "$host": "localhost:8000", + "$pathname": "/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$browser_version": 117, + "$browser_language": "en-GB", + "$screen_height": 982, + "$screen_width": 1512, + "$viewport_height": 859, + "$viewport_width": 1512, + "$lib": "web", + "$lib_version": "1.84.0", + "$insert_id": "l2e0vvj7g4kj2vyc", + "$time": 1697797840.135, + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$device_id": "018a92fd-7b25-7770-a050-577e94fd148c", + "$console_log_recording_enabled_server_side": true, + "$session_recording_recorder_version_server_side": "v2", + "$autocapture_disabled_server_side": false, + "$active_feature_flags": [ + "signup-page-4.0", + "cmd-k-search", + "posthog-3000", + "funnels-cue-opt-out-7301", + "retention-breakdown", + "smoothing-interval", + "billing-limit", + "kafka-inspector", + "historical-exports-v2", + "person-on-events-enabled", + "region-select", + "ingestion-warnings-enabled", + "session-reset-on-load", + "recordings-on-feature-flags", + "auto-rollback-feature-flags", + "onboarding-v2-demo", + "feature-flag-rollout-ux", + "role-based-access", + "query_running_time", + "query-timings", + "recording-debugging", + "enable-prompts", + "feedback-scene", + "early-access-feature", + "early-access-feature-site-button", + "hedgehog-mode-debug", + "auto-redirect", + "session-recording-blob-replay", + "surveys", + "generic-signup-benefits", + "surveys-positions", + "web-analytics", + "high-frequency-batch-exports", + "exception-autocapture", + "data-warehouse", + "data-warehouse-views", + "ff-dashboard-templates", + "show-product-intro-existing-products", + "artificial-hog", + "cs-dashboards", + "product-specific-onboarding", + "redirect-signups-to-instance", + "apps-and-exports-ui", + "survey-nps-results", + "session-recording-allow-v1-snapshots", + "session-replay-cors-proxy", + "webhooks-denylist", + "surveys-site-app-deprecation", + "surveys-multiple-questions", + "surveys-results-visualizations", + "console-recording-search", + "persons-hogql-query", + "notebooks" + ], + "$feature/file-previews": false, + "$feature/signup-page-4.0": "control", + "$feature/hogql-insights": false, + "$feature/cmd-k-search": true, + "$feature/posthog-3000": true, + "$feature/funnels-cue-opt-out-7301": true, + "$feature/retention-breakdown": true, + "$feature/smoothing-interval": true, + "$feature/billing-limit": true, + "$feature/kafka-inspector": true, + "$feature/historical-exports-v2": true, + "$feature/person-on-events-enabled": true, + "$feature/region-select": true, + "$feature/ingestion-warnings-enabled": true, + "$feature/session-reset-on-load": true, + "$feature/recordings-on-feature-flags": true, + "$feature/auto-rollback-feature-flags": true, + "$feature/onboarding-v2-demo": true, + "$feature/feature-flag-rollout-ux": true, + "$feature/role-based-access": true, + "$feature/query_running_time": true, + "$feature/query-timings": true, + "$feature/recording-debugging": true, + "$feature/enable-prompts": true, + "$feature/feedback-scene": true, + "$feature/early-access-feature": true, + "$feature/early-access-feature-site-button": true, + "$feature/hedgehog-mode-debug": true, + "$feature/auto-redirect": true, + "$feature/session-recording-blob-replay": true, + "$feature/surveys": true, + "$feature/generic-signup-benefits": true, + "$feature/surveys-positions": true, + "$feature/web-analytics": true, + "$feature/high-frequency-batch-exports": true, + "$feature/exception-autocapture": true, + "$feature/data-warehouse": true, + "$feature/data-warehouse-views": true, + "$feature/ff-dashboard-templates": true, + "$feature/show-product-intro-existing-products": true, + "$feature/artificial-hog": true, + "$feature/cs-dashboards": true, + "$feature/product-specific-onboarding": true, + "$feature/redirect-signups-to-instance": true, + "$feature/apps-and-exports-ui": true, + "$feature/survey-nps-results": true, + "$feature/session-recording-allow-v1-snapshots": true, + "$feature/session-replay-cors-proxy": true, + "$feature/webhooks-denylist": true, + "$feature/surveys-site-app-deprecation": true, + "$feature/surveys-multiple-questions": true, + "$feature/surveys-results-visualizations": true, + "$feature/console-recording-search": true, + "$feature/persons-hogql-query": true, + "$feature/notebooks": true, + "$feature_flag_payloads": {}, + "realm": "hosted-clickhouse", + "email_service_available": false, + "slack_service_available": false, + "$user_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "is_demo_project": false, + "$groups": { + "project": "018a92f8-b602-0000-75de-4b9073693531", + "organization": "018a92f8-afff-0000-efec-ca77de39e384", + "customer": "cus_OdSgxxWtHOtq9g", + "instance": "http://localhost:8000" + }, + "has_billing_plan": true, + "customer_deactivated": false, + "current_total_amount_usd": "0.00", + "percentage_usage.product_analytics": 0, + "current_amount_usd.product_analytics": "0.00", + "unit_amount_usd.product_analytics": null, + "usage_limit.product_analytics": null, + "current_usage.product_analytics": 3729, + "projected_usage.product_analytics": 0, + "free_allocation.product_analytics": 0, + "percentage_usage.session_replay": 0, + "current_amount_usd.session_replay": "0.00", + "unit_amount_usd.session_replay": null, + "usage_limit.session_replay": null, + "current_usage.session_replay": 254, + "projected_usage.session_replay": 0, + "free_allocation.session_replay": 0, + "percentage_usage.feature_flags": 0, + "current_amount_usd.feature_flags": "0.00", + "unit_amount_usd.feature_flags": null, + "usage_limit.feature_flags": null, + "current_usage.feature_flags": 0, + "projected_usage.feature_flags": 0, + "free_allocation.feature_flags": 0, + "percentage_usage.integrations": 0, + "current_amount_usd.integrations": null, + "unit_amount_usd.integrations": null, + "usage_limit.integrations": 0, + "current_usage.integrations": 0, + "projected_usage.integrations": 0, + "free_allocation.integrations": 0, + "percentage_usage.platform_and_support": 0, + "current_amount_usd.platform_and_support": null, + "unit_amount_usd.platform_and_support": null, + "usage_limit.platform_and_support": 0, + "current_usage.platform_and_support": 0, + "projected_usage.platform_and_support": 0, + "free_allocation.platform_and_support": 0, + "billing_period_start": "2023-10-14T09:22:33.000Z", + "billing_period_end": "2023-11-14T09:22:33.000Z", + "$referrer": "$direct", + "$referring_domain": "$direct", + "$set": { + "email": "test@posthog.com", + "$os": "Mac OS X", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI#activeTab=feed&state=eyJ0eXBlIjoiZG9jIiwiY29udGVudCI6W3sidHlwZSI6ImhlYWRpbmciLCJhdHRycyI6eyJsZXZlbCI6MX0sImNvbnRlbnQiOlt7InR5cGUiOiJ0ZXh0IiwidGV4dCI6ImtyUmZnb3BzVXkxVHdOVTF5aFNETHFORFRkNk41dE1ackhsbThuTEpJREkifV19LHsidHlwZSI6InBoLXBlcnNvbi1mZWVkIiwiYXR0cnMiOnsiaGVpZ2h0IjpudWxsLCJ0aXRsZSI6bnVsbCwibm9kZUlkIjoiNmQ0ODUwNjYtZWM5OS00ODNkLThiOTgtNGQ4YTJkYzljYzRiIiwiaWQiOiJrclJmZ29wc1V5MVR3TlUxeWhTRExxTkRUZDZONXRNWnJIbG04bkxKSURJIiwiX19pbml0IjpudWxsLCJjaGlsZHJlbiI6W3sidHlwZSI6InBoLXBlcnNvbiIsImF0dHJzIjp7ImlkIjoia3JSZmdvcHNVeTFUd05VMXloU0RMcU5EVGQ2TjV0TVpySGxtOG5MSklESSIsIm5vZGVJZCI6IjNkMzZiZjU3LTFkYjQtNDJlZi1iNzhiLWUyZDNkNGViOWM5NSJ9fSx7InR5cGUiOiJwaC1tYXAiLCJhdHRycyI6eyJpZCI6ImtyUmZnb3BzVXkxVHdOVTF5aFNETHFORFRkNk41dE1ackhsbThuTEpJREkiLCJub2RlSWQiOiI1MzE0ZWI2MS1lYTA2LTQyOGQtYWEzZi0zMDA4OWJjZmUxYjgifX0seyJ0eXBlIjoicGgtcHJvcGVydGllcyIsImF0dHJzIjp7ImlkIjoia3JSZmdvcHNVeTFUd05VMXloU0RMcU5EVGQ2TjV0TVpySGxtOG5MSklESSIsIm5vZGVJZCI6ImUwMjE1NDU5LWY0YTgtNGJjNy04NDhmLTYxODE1NzY1NzlmNyJ9fV19fV19", + "$pathname": "/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$browser_version": 117, + "$referrer": "$direct", + "$referring_domain": "$direct" + }, + "$set_once": { + "$initial_os": "Mac OS X", + "$initial_browser": "Chrome", + "$initial_device_type": "Desktop", + "$initial_current_url": "http://localhost:8000/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI#activeTab=feed&state=eyJ0eXBlIjoiZG9jIiwiY29udGVudCI6W3sidHlwZSI6ImhlYWRpbmciLCJhdHRycyI6eyJsZXZlbCI6MX0sImNvbnRlbnQiOlt7InR5cGUiOiJ0ZXh0IiwidGV4dCI6ImtyUmZnb3BzVXkxVHdOVTF5aFNETHFORFRkNk41dE1ackhsbThuTEpJREkifV19LHsidHlwZSI6InBoLXBlcnNvbi1mZWVkIiwiYXR0cnMiOnsiaGVpZ2h0IjpudWxsLCJ0aXRsZSI6bnVsbCwibm9kZUlkIjoiNmQ0ODUwNjYtZWM5OS00ODNkLThiOTgtNGQ4YTJkYzljYzRiIiwiaWQiOiJrclJmZ29wc1V5MVR3TlUxeWhTRExxTkRUZDZONXRNWnJIbG04bkxKSURJIiwiX19pbml0IjpudWxsLCJjaGlsZHJlbiI6W3sidHlwZSI6InBoLXBlcnNvbiIsImF0dHJzIjp7ImlkIjoia3JSZmdvcHNVeTFUd05VMXloU0RMcU5EVGQ2TjV0TVpySGxtOG5MSklESSIsIm5vZGVJZCI6IjNkMzZiZjU3LTFkYjQtNDJlZi1iNzhiLWUyZDNkNGViOWM5NSJ9fSx7InR5cGUiOiJwaC1tYXAiLCJhdHRycyI6eyJpZCI6ImtyUmZnb3BzVXkxVHdOVTF5aFNETHFORFRkNk41dE1ackhsbThuTEpJREkiLCJub2RlSWQiOiI1MzE0ZWI2MS1lYTA2LTQyOGQtYWEzZi0zMDA4OWJjZmUxYjgifX0seyJ0eXBlIjoicGgtcHJvcGVydGllcyIsImF0dHJzIjp7ImlkIjoia3JSZmdvcHNVeTFUd05VMXloU0RMcU5EVGQ2TjV0TVpySGxtOG5MSklESSIsIm5vZGVJZCI6ImUwMjE1NDU5LWY0YTgtNGJjNy04NDhmLTYxODE1NzY1NzlmNyJ9fV19fV19", + "$initial_pathname": "/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$initial_browser_version": 117, + "$initial_referrer": "$direct", + "$initial_referring_domain": "$direct" + }, + "token": "phc_OWGI2wKbfi7rWDZT9wkl8uGcfe0wOGCvflLEZSMiaT0", + "$session_id": "018b4ca3-1d07-7195-8202-c8a103a9325a", + "$window_id": "018b4ca3-1d07-7195-8202-c8a2b00ad68a", + "$ip": "127.0.0.1", + "$sent_at": "2023-10-20T10:30:43.133000+00:00", + "$geoip_city_name": "Sydney", + "$geoip_country_name": "Australia", + "$geoip_country_code": "AU", + "$geoip_continent_name": "Oceania", + "$geoip_continent_code": "OC", + "$geoip_postal_code": "2000", + "$geoip_latitude": -33.8715, + "$geoip_longitude": 151.2006, + "$geoip_time_zone": "Australia/Sydney", + "$geoip_subdivision_1_code": "NSW", + "$geoip_subdivision_1_name": "New South Wales", + "$plugins_succeeded": ["GeoIP (1)"], + "$plugins_failed": [], + "$plugins_deferred": [], + "$group_3": "018a92f8-b602-0000-75de-4b9073693531", + "$group_2": "018a92f8-afff-0000-efec-ca77de39e384", + "$group_4": "cus_OdSgxxWtHOtq9g", + "$group_1": "http://localhost:8000" + }, + "timestamp": "2023-10-20T10:30:40.150000+00:00", + "uuid": null + }, + { + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "elements": [], + "elements_chain": null, + "event": "$groupidentify", + "id": "018b4ca3-1d08-72d6-8912-1c884aeb47ae", + "person": null, + "properties": { + "$os": "Mac OS X", + "$os_version": "10.15.7", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI#activeTab=feed&state=eyJ0eXBlIjoiZG9jIiwiY29udGVudCI6W3sidHlwZSI6ImhlYWRpbmciLCJhdHRycyI6eyJsZXZlbCI6MX0sImNvbnRlbnQiOlt7InR5cGUiOiJ0ZXh0IiwidGV4dCI6ImtyUmZnb3BzVXkxVHdOVTF5aFNETHFORFRkNk41dE1ackhsbThuTEpJREkifV19LHsidHlwZSI6InBoLXBlcnNvbi1mZWVkIiwiYXR0cnMiOnsiaGVpZ2h0IjpudWxsLCJ0aXRsZSI6bnVsbCwibm9kZUlkIjoiNmQ0ODUwNjYtZWM5OS00ODNkLThiOTgtNGQ4YTJkYzljYzRiIiwiaWQiOiJrclJmZ29wc1V5MVR3TlUxeWhTRExxTkRUZDZONXRNWnJIbG04bkxKSURJIiwiX19pbml0IjpudWxsLCJjaGlsZHJlbiI6W3sidHlwZSI6InBoLXBlcnNvbiIsImF0dHJzIjp7ImlkIjoia3JSZmdvcHNVeTFUd05VMXloU0RMcU5EVGQ2TjV0TVpySGxtOG5MSklESSIsIm5vZGVJZCI6IjNkMzZiZjU3LTFkYjQtNDJlZi1iNzhiLWUyZDNkNGViOWM5NSJ9fSx7InR5cGUiOiJwaC1tYXAiLCJhdHRycyI6eyJpZCI6ImtyUmZnb3BzVXkxVHdOVTF5aFNETHFORFRkNk41dE1ackhsbThuTEpJREkiLCJub2RlSWQiOiI1MzE0ZWI2MS1lYTA2LTQyOGQtYWEzZi0zMDA4OWJjZmUxYjgifX0seyJ0eXBlIjoicGgtcHJvcGVydGllcyIsImF0dHJzIjp7ImlkIjoia3JSZmdvcHNVeTFUd05VMXloU0RMcU5EVGQ2TjV0TVpySGxtOG5MSklESSIsIm5vZGVJZCI6ImUwMjE1NDU5LWY0YTgtNGJjNy04NDhmLTYxODE1NzY1NzlmNyJ9fV19fV19", + "$host": "localhost:8000", + "$pathname": "/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$browser_version": 117, + "$browser_language": "en-GB", + "$screen_height": 982, + "$screen_width": 1512, + "$viewport_height": 859, + "$viewport_width": 1512, + "$lib": "web", + "$lib_version": "1.84.0", + "$insert_id": "wla12x9igfbgty32", + "$time": 1697797840.136, + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$device_id": "018a92fd-7b25-7770-a050-577e94fd148c", + "$console_log_recording_enabled_server_side": true, + "$session_recording_recorder_version_server_side": "v2", + "$autocapture_disabled_server_side": false, + "$active_feature_flags": [ + "signup-page-4.0", + "cmd-k-search", + "posthog-3000", + "funnels-cue-opt-out-7301", + "retention-breakdown", + "smoothing-interval", + "billing-limit", + "kafka-inspector", + "historical-exports-v2", + "person-on-events-enabled", + "region-select", + "ingestion-warnings-enabled", + "session-reset-on-load", + "recordings-on-feature-flags", + "auto-rollback-feature-flags", + "onboarding-v2-demo", + "feature-flag-rollout-ux", + "role-based-access", + "query_running_time", + "query-timings", + "recording-debugging", + "enable-prompts", + "feedback-scene", + "early-access-feature", + "early-access-feature-site-button", + "hedgehog-mode-debug", + "auto-redirect", + "session-recording-blob-replay", + "surveys", + "generic-signup-benefits", + "surveys-positions", + "web-analytics", + "high-frequency-batch-exports", + "exception-autocapture", + "data-warehouse", + "data-warehouse-views", + "ff-dashboard-templates", + "show-product-intro-existing-products", + "artificial-hog", + "cs-dashboards", + "product-specific-onboarding", + "redirect-signups-to-instance", + "apps-and-exports-ui", + "survey-nps-results", + "session-recording-allow-v1-snapshots", + "session-replay-cors-proxy", + "webhooks-denylist", + "surveys-site-app-deprecation", + "surveys-multiple-questions", + "surveys-results-visualizations", + "console-recording-search", + "persons-hogql-query", + "notebooks" + ], + "$feature/file-previews": false, + "$feature/signup-page-4.0": "control", + "$feature/hogql-insights": false, + "$feature/cmd-k-search": true, + "$feature/posthog-3000": true, + "$feature/funnels-cue-opt-out-7301": true, + "$feature/retention-breakdown": true, + "$feature/smoothing-interval": true, + "$feature/billing-limit": true, + "$feature/kafka-inspector": true, + "$feature/historical-exports-v2": true, + "$feature/person-on-events-enabled": true, + "$feature/region-select": true, + "$feature/ingestion-warnings-enabled": true, + "$feature/session-reset-on-load": true, + "$feature/recordings-on-feature-flags": true, + "$feature/auto-rollback-feature-flags": true, + "$feature/onboarding-v2-demo": true, + "$feature/feature-flag-rollout-ux": true, + "$feature/role-based-access": true, + "$feature/query_running_time": true, + "$feature/query-timings": true, + "$feature/recording-debugging": true, + "$feature/enable-prompts": true, + "$feature/feedback-scene": true, + "$feature/early-access-feature": true, + "$feature/early-access-feature-site-button": true, + "$feature/hedgehog-mode-debug": true, + "$feature/auto-redirect": true, + "$feature/session-recording-blob-replay": true, + "$feature/surveys": true, + "$feature/generic-signup-benefits": true, + "$feature/surveys-positions": true, + "$feature/web-analytics": true, + "$feature/high-frequency-batch-exports": true, + "$feature/exception-autocapture": true, + "$feature/data-warehouse": true, + "$feature/data-warehouse-views": true, + "$feature/ff-dashboard-templates": true, + "$feature/show-product-intro-existing-products": true, + "$feature/artificial-hog": true, + "$feature/cs-dashboards": true, + "$feature/product-specific-onboarding": true, + "$feature/redirect-signups-to-instance": true, + "$feature/apps-and-exports-ui": true, + "$feature/survey-nps-results": true, + "$feature/session-recording-allow-v1-snapshots": true, + "$feature/session-replay-cors-proxy": true, + "$feature/webhooks-denylist": true, + "$feature/surveys-site-app-deprecation": true, + "$feature/surveys-multiple-questions": true, + "$feature/surveys-results-visualizations": true, + "$feature/console-recording-search": true, + "$feature/persons-hogql-query": true, + "$feature/notebooks": true, + "$feature_flag_payloads": {}, + "realm": "hosted-clickhouse", + "email_service_available": false, + "slack_service_available": false, + "$user_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "is_demo_project": false, + "$groups": { + "project": "018a92f8-b602-0000-75de-4b9073693531", + "organization": "018a92f8-afff-0000-efec-ca77de39e384", + "customer": "cus_OdSgxxWtHOtq9g", + "instance": "http://localhost:8000" + }, + "has_billing_plan": true, + "customer_deactivated": false, + "current_total_amount_usd": "0.00", + "percentage_usage.product_analytics": 0, + "current_amount_usd.product_analytics": "0.00", + "unit_amount_usd.product_analytics": null, + "usage_limit.product_analytics": null, + "current_usage.product_analytics": 3729, + "projected_usage.product_analytics": 0, + "free_allocation.product_analytics": 0, + "percentage_usage.session_replay": 0, + "current_amount_usd.session_replay": "0.00", + "unit_amount_usd.session_replay": null, + "usage_limit.session_replay": null, + "current_usage.session_replay": 254, + "projected_usage.session_replay": 0, + "free_allocation.session_replay": 0, + "percentage_usage.feature_flags": 0, + "current_amount_usd.feature_flags": "0.00", + "unit_amount_usd.feature_flags": null, + "usage_limit.feature_flags": null, + "current_usage.feature_flags": 0, + "projected_usage.feature_flags": 0, + "free_allocation.feature_flags": 0, + "percentage_usage.integrations": 0, + "current_amount_usd.integrations": null, + "unit_amount_usd.integrations": null, + "usage_limit.integrations": 0, + "current_usage.integrations": 0, + "projected_usage.integrations": 0, + "free_allocation.integrations": 0, + "percentage_usage.platform_and_support": 0, + "current_amount_usd.platform_and_support": null, + "unit_amount_usd.platform_and_support": null, + "usage_limit.platform_and_support": 0, + "current_usage.platform_and_support": 0, + "projected_usage.platform_and_support": 0, + "free_allocation.platform_and_support": 0, + "billing_period_start": "2023-10-14T09:22:33.000Z", + "billing_period_end": "2023-11-14T09:22:33.000Z", + "$referrer": "$direct", + "$referring_domain": "$direct", + "$group_type": "project", + "$group_key": "018a92f8-b602-0000-75de-4b9073693531", + "$group_set": { + "id": 1, + "uuid": "018a92f8-b602-0000-75de-4b9073693531", + "name": "Hedgebox", + "ingested_event": true, + "is_demo": false, + "timezone": "UTC", + "instance_tag": "none" + }, + "token": "phc_OWGI2wKbfi7rWDZT9wkl8uGcfe0wOGCvflLEZSMiaT0", + "$session_id": "018b4ca3-1d07-7195-8202-c8a103a9325a", + "$window_id": "018b4ca3-1d07-7195-8202-c8a2b00ad68a", + "$ip": "127.0.0.1", + "$set": { + "$os": "Mac OS X", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI#activeTab=feed&state=eyJ0eXBlIjoiZG9jIiwiY29udGVudCI6W3sidHlwZSI6ImhlYWRpbmciLCJhdHRycyI6eyJsZXZlbCI6MX0sImNvbnRlbnQiOlt7InR5cGUiOiJ0ZXh0IiwidGV4dCI6ImtyUmZnb3BzVXkxVHdOVTF5aFNETHFORFRkNk41dE1ackhsbThuTEpJREkifV19LHsidHlwZSI6InBoLXBlcnNvbi1mZWVkIiwiYXR0cnMiOnsiaGVpZ2h0IjpudWxsLCJ0aXRsZSI6bnVsbCwibm9kZUlkIjoiNmQ0ODUwNjYtZWM5OS00ODNkLThiOTgtNGQ4YTJkYzljYzRiIiwiaWQiOiJrclJmZ29wc1V5MVR3TlUxeWhTRExxTkRUZDZONXRNWnJIbG04bkxKSURJIiwiX19pbml0IjpudWxsLCJjaGlsZHJlbiI6W3sidHlwZSI6InBoLXBlcnNvbiIsImF0dHJzIjp7ImlkIjoia3JSZmdvcHNVeTFUd05VMXloU0RMcU5EVGQ2TjV0TVpySGxtOG5MSklESSIsIm5vZGVJZCI6IjNkMzZiZjU3LTFkYjQtNDJlZi1iNzhiLWUyZDNkNGViOWM5NSJ9fSx7InR5cGUiOiJwaC1tYXAiLCJhdHRycyI6eyJpZCI6ImtyUmZnb3BzVXkxVHdOVTF5aFNETHFORFRkNk41dE1ackhsbThuTEpJREkiLCJub2RlSWQiOiI1MzE0ZWI2MS1lYTA2LTQyOGQtYWEzZi0zMDA4OWJjZmUxYjgifX0seyJ0eXBlIjoicGgtcHJvcGVydGllcyIsImF0dHJzIjp7ImlkIjoia3JSZmdvcHNVeTFUd05VMXloU0RMcU5EVGQ2TjV0TVpySGxtOG5MSklESSIsIm5vZGVJZCI6ImUwMjE1NDU5LWY0YTgtNGJjNy04NDhmLTYxODE1NzY1NzlmNyJ9fV19fV19", + "$pathname": "/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$browser_version": 117, + "$referrer": "$direct", + "$referring_domain": "$direct" + }, + "$set_once": { + "$initial_os": "Mac OS X", + "$initial_browser": "Chrome", + "$initial_device_type": "Desktop", + "$initial_current_url": "http://localhost:8000/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI#activeTab=feed&state=eyJ0eXBlIjoiZG9jIiwiY29udGVudCI6W3sidHlwZSI6ImhlYWRpbmciLCJhdHRycyI6eyJsZXZlbCI6MX0sImNvbnRlbnQiOlt7InR5cGUiOiJ0ZXh0IiwidGV4dCI6ImtyUmZnb3BzVXkxVHdOVTF5aFNETHFORFRkNk41dE1ackhsbThuTEpJREkifV19LHsidHlwZSI6InBoLXBlcnNvbi1mZWVkIiwiYXR0cnMiOnsiaGVpZ2h0IjpudWxsLCJ0aXRsZSI6bnVsbCwibm9kZUlkIjoiNmQ0ODUwNjYtZWM5OS00ODNkLThiOTgtNGQ4YTJkYzljYzRiIiwiaWQiOiJrclJmZ29wc1V5MVR3TlUxeWhTRExxTkRUZDZONXRNWnJIbG04bkxKSURJIiwiX19pbml0IjpudWxsLCJjaGlsZHJlbiI6W3sidHlwZSI6InBoLXBlcnNvbiIsImF0dHJzIjp7ImlkIjoia3JSZmdvcHNVeTFUd05VMXloU0RMcU5EVGQ2TjV0TVpySGxtOG5MSklESSIsIm5vZGVJZCI6IjNkMzZiZjU3LTFkYjQtNDJlZi1iNzhiLWUyZDNkNGViOWM5NSJ9fSx7InR5cGUiOiJwaC1tYXAiLCJhdHRycyI6eyJpZCI6ImtyUmZnb3BzVXkxVHdOVTF5aFNETHFORFRkNk41dE1ackhsbThuTEpJREkiLCJub2RlSWQiOiI1MzE0ZWI2MS1lYTA2LTQyOGQtYWEzZi0zMDA4OWJjZmUxYjgifX0seyJ0eXBlIjoicGgtcHJvcGVydGllcyIsImF0dHJzIjp7ImlkIjoia3JSZmdvcHNVeTFUd05VMXloU0RMcU5EVGQ2TjV0TVpySGxtOG5MSklESSIsIm5vZGVJZCI6ImUwMjE1NDU5LWY0YTgtNGJjNy04NDhmLTYxODE1NzY1NzlmNyJ9fV19fV19", + "$initial_pathname": "/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$initial_browser_version": 117, + "$initial_referrer": "$direct", + "$initial_referring_domain": "$direct" + }, + "$sent_at": "2023-10-20T10:30:43.133000+00:00", + "$geoip_city_name": "Sydney", + "$geoip_country_name": "Australia", + "$geoip_country_code": "AU", + "$geoip_continent_name": "Oceania", + "$geoip_continent_code": "OC", + "$geoip_postal_code": "2000", + "$geoip_latitude": -33.8715, + "$geoip_longitude": 151.2006, + "$geoip_time_zone": "Australia/Sydney", + "$geoip_subdivision_1_code": "NSW", + "$geoip_subdivision_1_name": "New South Wales", + "$plugins_succeeded": ["GeoIP (1)"], + "$plugins_failed": [], + "$plugins_deferred": [], + "$group_3": "018a92f8-b602-0000-75de-4b9073693531", + "$group_2": "018a92f8-afff-0000-efec-ca77de39e384", + "$group_4": "cus_OdSgxxWtHOtq9g", + "$group_1": "http://localhost:8000" + }, + "timestamp": "2023-10-20T10:30:40.151000+00:00", + "uuid": null + }, + { + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "elements": [], + "elements_chain": null, + "event": "$groupidentify", + "id": "018b4ca3-1d09-7c1f-b227-cf790742dcb0", + "person": null, + "properties": { + "$os": "Mac OS X", + "$os_version": "10.15.7", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI#activeTab=feed&state=eyJ0eXBlIjoiZG9jIiwiY29udGVudCI6W3sidHlwZSI6ImhlYWRpbmciLCJhdHRycyI6eyJsZXZlbCI6MX0sImNvbnRlbnQiOlt7InR5cGUiOiJ0ZXh0IiwidGV4dCI6ImtyUmZnb3BzVXkxVHdOVTF5aFNETHFORFRkNk41dE1ackhsbThuTEpJREkifV19LHsidHlwZSI6InBoLXBlcnNvbi1mZWVkIiwiYXR0cnMiOnsiaGVpZ2h0IjpudWxsLCJ0aXRsZSI6bnVsbCwibm9kZUlkIjoiNmQ0ODUwNjYtZWM5OS00ODNkLThiOTgtNGQ4YTJkYzljYzRiIiwiaWQiOiJrclJmZ29wc1V5MVR3TlUxeWhTRExxTkRUZDZONXRNWnJIbG04bkxKSURJIiwiX19pbml0IjpudWxsLCJjaGlsZHJlbiI6W3sidHlwZSI6InBoLXBlcnNvbiIsImF0dHJzIjp7ImlkIjoia3JSZmdvcHNVeTFUd05VMXloU0RMcU5EVGQ2TjV0TVpySGxtOG5MSklESSIsIm5vZGVJZCI6IjNkMzZiZjU3LTFkYjQtNDJlZi1iNzhiLWUyZDNkNGViOWM5NSJ9fSx7InR5cGUiOiJwaC1tYXAiLCJhdHRycyI6eyJpZCI6ImtyUmZnb3BzVXkxVHdOVTF5aFNETHFORFRkNk41dE1ackhsbThuTEpJREkiLCJub2RlSWQiOiI1MzE0ZWI2MS1lYTA2LTQyOGQtYWEzZi0zMDA4OWJjZmUxYjgifX0seyJ0eXBlIjoicGgtcHJvcGVydGllcyIsImF0dHJzIjp7ImlkIjoia3JSZmdvcHNVeTFUd05VMXloU0RMcU5EVGQ2TjV0TVpySGxtOG5MSklESSIsIm5vZGVJZCI6ImUwMjE1NDU5LWY0YTgtNGJjNy04NDhmLTYxODE1NzY1NzlmNyJ9fV19fV19", + "$host": "localhost:8000", + "$pathname": "/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$browser_version": 117, + "$browser_language": "en-GB", + "$screen_height": 982, + "$screen_width": 1512, + "$viewport_height": 859, + "$viewport_width": 1512, + "$lib": "web", + "$lib_version": "1.84.0", + "$insert_id": "v9gjsx4xig703btp", + "$time": 1697797840.137, + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$device_id": "018a92fd-7b25-7770-a050-577e94fd148c", + "$console_log_recording_enabled_server_side": true, + "$session_recording_recorder_version_server_side": "v2", + "$autocapture_disabled_server_side": false, + "$active_feature_flags": [ + "signup-page-4.0", + "cmd-k-search", + "posthog-3000", + "funnels-cue-opt-out-7301", + "retention-breakdown", + "smoothing-interval", + "billing-limit", + "kafka-inspector", + "historical-exports-v2", + "person-on-events-enabled", + "region-select", + "ingestion-warnings-enabled", + "session-reset-on-load", + "recordings-on-feature-flags", + "auto-rollback-feature-flags", + "onboarding-v2-demo", + "feature-flag-rollout-ux", + "role-based-access", + "query_running_time", + "query-timings", + "recording-debugging", + "enable-prompts", + "feedback-scene", + "early-access-feature", + "early-access-feature-site-button", + "hedgehog-mode-debug", + "auto-redirect", + "session-recording-blob-replay", + "surveys", + "generic-signup-benefits", + "surveys-positions", + "web-analytics", + "high-frequency-batch-exports", + "exception-autocapture", + "data-warehouse", + "data-warehouse-views", + "ff-dashboard-templates", + "show-product-intro-existing-products", + "artificial-hog", + "cs-dashboards", + "product-specific-onboarding", + "redirect-signups-to-instance", + "apps-and-exports-ui", + "survey-nps-results", + "session-recording-allow-v1-snapshots", + "session-replay-cors-proxy", + "webhooks-denylist", + "surveys-site-app-deprecation", + "surveys-multiple-questions", + "surveys-results-visualizations", + "console-recording-search", + "persons-hogql-query", + "notebooks" + ], + "$feature/file-previews": false, + "$feature/signup-page-4.0": "control", + "$feature/hogql-insights": false, + "$feature/cmd-k-search": true, + "$feature/posthog-3000": true, + "$feature/funnels-cue-opt-out-7301": true, + "$feature/retention-breakdown": true, + "$feature/smoothing-interval": true, + "$feature/billing-limit": true, + "$feature/kafka-inspector": true, + "$feature/historical-exports-v2": true, + "$feature/person-on-events-enabled": true, + "$feature/region-select": true, + "$feature/ingestion-warnings-enabled": true, + "$feature/session-reset-on-load": true, + "$feature/recordings-on-feature-flags": true, + "$feature/auto-rollback-feature-flags": true, + "$feature/onboarding-v2-demo": true, + "$feature/feature-flag-rollout-ux": true, + "$feature/role-based-access": true, + "$feature/query_running_time": true, + "$feature/query-timings": true, + "$feature/recording-debugging": true, + "$feature/enable-prompts": true, + "$feature/feedback-scene": true, + "$feature/early-access-feature": true, + "$feature/early-access-feature-site-button": true, + "$feature/hedgehog-mode-debug": true, + "$feature/auto-redirect": true, + "$feature/session-recording-blob-replay": true, + "$feature/surveys": true, + "$feature/generic-signup-benefits": true, + "$feature/surveys-positions": true, + "$feature/web-analytics": true, + "$feature/high-frequency-batch-exports": true, + "$feature/exception-autocapture": true, + "$feature/data-warehouse": true, + "$feature/data-warehouse-views": true, + "$feature/ff-dashboard-templates": true, + "$feature/show-product-intro-existing-products": true, + "$feature/artificial-hog": true, + "$feature/cs-dashboards": true, + "$feature/product-specific-onboarding": true, + "$feature/redirect-signups-to-instance": true, + "$feature/apps-and-exports-ui": true, + "$feature/survey-nps-results": true, + "$feature/session-recording-allow-v1-snapshots": true, + "$feature/session-replay-cors-proxy": true, + "$feature/webhooks-denylist": true, + "$feature/surveys-site-app-deprecation": true, + "$feature/surveys-multiple-questions": true, + "$feature/surveys-results-visualizations": true, + "$feature/console-recording-search": true, + "$feature/persons-hogql-query": true, + "$feature/notebooks": true, + "$feature_flag_payloads": {}, + "realm": "hosted-clickhouse", + "email_service_available": false, + "slack_service_available": false, + "$user_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "is_demo_project": false, + "$groups": { + "project": "018a92f8-b602-0000-75de-4b9073693531", + "organization": "018a92f8-afff-0000-efec-ca77de39e384", + "customer": "cus_OdSgxxWtHOtq9g", + "instance": "http://localhost:8000" + }, + "has_billing_plan": true, + "customer_deactivated": false, + "current_total_amount_usd": "0.00", + "percentage_usage.product_analytics": 0, + "current_amount_usd.product_analytics": "0.00", + "unit_amount_usd.product_analytics": null, + "usage_limit.product_analytics": null, + "current_usage.product_analytics": 3729, + "projected_usage.product_analytics": 0, + "free_allocation.product_analytics": 0, + "percentage_usage.session_replay": 0, + "current_amount_usd.session_replay": "0.00", + "unit_amount_usd.session_replay": null, + "usage_limit.session_replay": null, + "current_usage.session_replay": 254, + "projected_usage.session_replay": 0, + "free_allocation.session_replay": 0, + "percentage_usage.feature_flags": 0, + "current_amount_usd.feature_flags": "0.00", + "unit_amount_usd.feature_flags": null, + "usage_limit.feature_flags": null, + "current_usage.feature_flags": 0, + "projected_usage.feature_flags": 0, + "free_allocation.feature_flags": 0, + "percentage_usage.integrations": 0, + "current_amount_usd.integrations": null, + "unit_amount_usd.integrations": null, + "usage_limit.integrations": 0, + "current_usage.integrations": 0, + "projected_usage.integrations": 0, + "free_allocation.integrations": 0, + "percentage_usage.platform_and_support": 0, + "current_amount_usd.platform_and_support": null, + "unit_amount_usd.platform_and_support": null, + "usage_limit.platform_and_support": 0, + "current_usage.platform_and_support": 0, + "projected_usage.platform_and_support": 0, + "free_allocation.platform_and_support": 0, + "billing_period_start": "2023-10-14T09:22:33.000Z", + "billing_period_end": "2023-11-14T09:22:33.000Z", + "$referrer": "$direct", + "$referring_domain": "$direct", + "$group_type": "organization", + "$group_key": "018a92f8-afff-0000-efec-ca77de39e384", + "$group_set": { + "id": "018a92f8-afff-0000-efec-ca77de39e384", + "name": "Hedgebox Inc.", + "slug": "hedgebox-inc", + "created_at": "2023-09-14T09:14:46.145060Z", + "available_features": [ + "zapier", + "slack_integration", + "microsoft_teams_integration", + "discord_integration", + "apps", + "app_metrics", + "boolean_flags", + "multivariate_flags", + "persist_flags_cross_authentication", + "feature_flag_payloads", + "multiple_release_conditions", + "release_condition_overrides", + "targeting_by_group", + "local_evaluation_and_bootstrapping", + "flag_usage_stats", + "experimentation", + "group_experiments", + "funnel_experiments", + "secondary_metrics", + "statistical_analysis", + "console_logs", + "recordings_playlists", + "recordings_performance", + "recordings_file_export", + "group_analytics", + "dashboards", + "funnels", + "graphs_trends", + "paths", + "subscriptions", + "paths_advanced", + "dashboard_permissioning", + "dashboard_collaboration", + "ingestion_taxonomy", + "correlation_analysis", + "tagging", + "behavioral_cohort_filtering", + "tracked_users", + "data_retention", + "team_members", + "organizations_projects", + "api_access", + "project_based_permissioning", + "social_sso", + "sso_enforcement", + "white_labelling", + "community_support", + "dedicated_support", + "email_support", + "terms_and_conditions", + "security_assessment" + ], + "instance_tag": "none" + }, + "token": "phc_OWGI2wKbfi7rWDZT9wkl8uGcfe0wOGCvflLEZSMiaT0", + "$session_id": "018b4ca3-1d07-7195-8202-c8a103a9325a", + "$window_id": "018b4ca3-1d07-7195-8202-c8a2b00ad68a", + "$ip": "127.0.0.1", + "$set": { + "$os": "Mac OS X", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI#activeTab=feed&state=eyJ0eXBlIjoiZG9jIiwiY29udGVudCI6W3sidHlwZSI6ImhlYWRpbmciLCJhdHRycyI6eyJsZXZlbCI6MX0sImNvbnRlbnQiOlt7InR5cGUiOiJ0ZXh0IiwidGV4dCI6ImtyUmZnb3BzVXkxVHdOVTF5aFNETHFORFRkNk41dE1ackhsbThuTEpJREkifV19LHsidHlwZSI6InBoLXBlcnNvbi1mZWVkIiwiYXR0cnMiOnsiaGVpZ2h0IjpudWxsLCJ0aXRsZSI6bnVsbCwibm9kZUlkIjoiNmQ0ODUwNjYtZWM5OS00ODNkLThiOTgtNGQ4YTJkYzljYzRiIiwiaWQiOiJrclJmZ29wc1V5MVR3TlUxeWhTRExxTkRUZDZONXRNWnJIbG04bkxKSURJIiwiX19pbml0IjpudWxsLCJjaGlsZHJlbiI6W3sidHlwZSI6InBoLXBlcnNvbiIsImF0dHJzIjp7ImlkIjoia3JSZmdvcHNVeTFUd05VMXloU0RMcU5EVGQ2TjV0TVpySGxtOG5MSklESSIsIm5vZGVJZCI6IjNkMzZiZjU3LTFkYjQtNDJlZi1iNzhiLWUyZDNkNGViOWM5NSJ9fSx7InR5cGUiOiJwaC1tYXAiLCJhdHRycyI6eyJpZCI6ImtyUmZnb3BzVXkxVHdOVTF5aFNETHFORFRkNk41dE1ackhsbThuTEpJREkiLCJub2RlSWQiOiI1MzE0ZWI2MS1lYTA2LTQyOGQtYWEzZi0zMDA4OWJjZmUxYjgifX0seyJ0eXBlIjoicGgtcHJvcGVydGllcyIsImF0dHJzIjp7ImlkIjoia3JSZmdvcHNVeTFUd05VMXloU0RMcU5EVGQ2TjV0TVpySGxtOG5MSklESSIsIm5vZGVJZCI6ImUwMjE1NDU5LWY0YTgtNGJjNy04NDhmLTYxODE1NzY1NzlmNyJ9fV19fV19", + "$pathname": "/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$browser_version": 117, + "$referrer": "$direct", + "$referring_domain": "$direct" + }, + "$set_once": { + "$initial_os": "Mac OS X", + "$initial_browser": "Chrome", + "$initial_device_type": "Desktop", + "$initial_current_url": "http://localhost:8000/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI#activeTab=feed&state=eyJ0eXBlIjoiZG9jIiwiY29udGVudCI6W3sidHlwZSI6ImhlYWRpbmciLCJhdHRycyI6eyJsZXZlbCI6MX0sImNvbnRlbnQiOlt7InR5cGUiOiJ0ZXh0IiwidGV4dCI6ImtyUmZnb3BzVXkxVHdOVTF5aFNETHFORFRkNk41dE1ackhsbThuTEpJREkifV19LHsidHlwZSI6InBoLXBlcnNvbi1mZWVkIiwiYXR0cnMiOnsiaGVpZ2h0IjpudWxsLCJ0aXRsZSI6bnVsbCwibm9kZUlkIjoiNmQ0ODUwNjYtZWM5OS00ODNkLThiOTgtNGQ4YTJkYzljYzRiIiwiaWQiOiJrclJmZ29wc1V5MVR3TlUxeWhTRExxTkRUZDZONXRNWnJIbG04bkxKSURJIiwiX19pbml0IjpudWxsLCJjaGlsZHJlbiI6W3sidHlwZSI6InBoLXBlcnNvbiIsImF0dHJzIjp7ImlkIjoia3JSZmdvcHNVeTFUd05VMXloU0RMcU5EVGQ2TjV0TVpySGxtOG5MSklESSIsIm5vZGVJZCI6IjNkMzZiZjU3LTFkYjQtNDJlZi1iNzhiLWUyZDNkNGViOWM5NSJ9fSx7InR5cGUiOiJwaC1tYXAiLCJhdHRycyI6eyJpZCI6ImtyUmZnb3BzVXkxVHdOVTF5aFNETHFORFRkNk41dE1ackhsbThuTEpJREkiLCJub2RlSWQiOiI1MzE0ZWI2MS1lYTA2LTQyOGQtYWEzZi0zMDA4OWJjZmUxYjgifX0seyJ0eXBlIjoicGgtcHJvcGVydGllcyIsImF0dHJzIjp7ImlkIjoia3JSZmdvcHNVeTFUd05VMXloU0RMcU5EVGQ2TjV0TVpySGxtOG5MSklESSIsIm5vZGVJZCI6ImUwMjE1NDU5LWY0YTgtNGJjNy04NDhmLTYxODE1NzY1NzlmNyJ9fV19fV19", + "$initial_pathname": "/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$initial_browser_version": 117, + "$initial_referrer": "$direct", + "$initial_referring_domain": "$direct" + }, + "$sent_at": "2023-10-20T10:30:43.133000+00:00", + "$geoip_city_name": "Sydney", + "$geoip_country_name": "Australia", + "$geoip_country_code": "AU", + "$geoip_continent_name": "Oceania", + "$geoip_continent_code": "OC", + "$geoip_postal_code": "2000", + "$geoip_latitude": -33.8715, + "$geoip_longitude": 151.2006, + "$geoip_time_zone": "Australia/Sydney", + "$geoip_subdivision_1_code": "NSW", + "$geoip_subdivision_1_name": "New South Wales", + "$plugins_succeeded": ["GeoIP (1)"], + "$plugins_failed": [], + "$plugins_deferred": [], + "$group_3": "018a92f8-b602-0000-75de-4b9073693531", + "$group_2": "018a92f8-afff-0000-efec-ca77de39e384", + "$group_4": "cus_OdSgxxWtHOtq9g", + "$group_1": "http://localhost:8000" + }, + "timestamp": "2023-10-20T10:30:40.152000+00:00", + "uuid": null + }, + { + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "elements": [], + "elements_chain": null, + "event": "$feature_flag_called", + "id": "018b4ca3-1d5d-7d58-ac71-0a9e143afc1e", + "person": null, + "properties": { + "$os": "Mac OS X", + "$os_version": "10.15.7", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI#activeTab=feed&state=eyJ0eXBlIjoiZG9jIiwiY29udGVudCI6W3sidHlwZSI6ImhlYWRpbmciLCJhdHRycyI6eyJsZXZlbCI6MX0sImNvbnRlbnQiOlt7InR5cGUiOiJ0ZXh0IiwidGV4dCI6ImtyUmZnb3BzVXkxVHdOVTF5aFNETHFORFRkNk41dE1ackhsbThuTEpJREkifV19LHsidHlwZSI6InBoLXBlcnNvbi1mZWVkIiwiYXR0cnMiOnsiaGVpZ2h0IjpudWxsLCJ0aXRsZSI6bnVsbCwibm9kZUlkIjoiNmQ0ODUwNjYtZWM5OS00ODNkLThiOTgtNGQ4YTJkYzljYzRiIiwiaWQiOiJrclJmZ29wc1V5MVR3TlUxeWhTRExxTkRUZDZONXRNWnJIbG04bkxKSURJIiwiX19pbml0IjpudWxsLCJjaGlsZHJlbiI6W3sidHlwZSI6InBoLXBlcnNvbiIsImF0dHJzIjp7ImlkIjoia3JSZmdvcHNVeTFUd05VMXloU0RMcU5EVGQ2TjV0TVpySGxtOG5MSklESSIsIm5vZGVJZCI6IjNkMzZiZjU3LTFkYjQtNDJlZi1iNzhiLWUyZDNkNGViOWM5NSJ9fSx7InR5cGUiOiJwaC1tYXAiLCJhdHRycyI6eyJpZCI6ImtyUmZnb3BzVXkxVHdOVTF5aFNETHFORFRkNk41dE1ackhsbThuTEpJREkiLCJub2RlSWQiOiI1MzE0ZWI2MS1lYTA2LTQyOGQtYWEzZi0zMDA4OWJjZmUxYjgifX0seyJ0eXBlIjoicGgtcHJvcGVydGllcyIsImF0dHJzIjp7ImlkIjoia3JSZmdvcHNVeTFUd05VMXloU0RMcU5EVGQ2TjV0TVpySGxtOG5MSklESSIsIm5vZGVJZCI6ImUwMjE1NDU5LWY0YTgtNGJjNy04NDhmLTYxODE1NzY1NzlmNyJ9fV19fV19", + "$host": "localhost:8000", + "$pathname": "/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$browser_version": 117, + "$browser_language": "en-GB", + "$screen_height": 982, + "$screen_width": 1512, + "$viewport_height": 859, + "$viewport_width": 1512, + "$lib": "web", + "$lib_version": "1.84.0", + "$insert_id": "vhe47zdv0zexeeuk", + "$time": 1697797840.222, + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$device_id": "018a92fd-7b25-7770-a050-577e94fd148c", + "$console_log_recording_enabled_server_side": true, + "$session_recording_recorder_version_server_side": "v2", + "$autocapture_disabled_server_side": false, + "$active_feature_flags": [ + "signup-page-4.0", + "cmd-k-search", + "posthog-3000", + "funnels-cue-opt-out-7301", + "retention-breakdown", + "smoothing-interval", + "billing-limit", + "kafka-inspector", + "historical-exports-v2", + "person-on-events-enabled", + "region-select", + "ingestion-warnings-enabled", + "session-reset-on-load", + "recordings-on-feature-flags", + "auto-rollback-feature-flags", + "onboarding-v2-demo", + "feature-flag-rollout-ux", + "role-based-access", + "query_running_time", + "query-timings", + "recording-debugging", + "enable-prompts", + "feedback-scene", + "early-access-feature", + "early-access-feature-site-button", + "hedgehog-mode-debug", + "auto-redirect", + "session-recording-blob-replay", + "surveys", + "generic-signup-benefits", + "surveys-positions", + "web-analytics", + "high-frequency-batch-exports", + "exception-autocapture", + "data-warehouse", + "data-warehouse-views", + "ff-dashboard-templates", + "show-product-intro-existing-products", + "artificial-hog", + "cs-dashboards", + "product-specific-onboarding", + "redirect-signups-to-instance", + "apps-and-exports-ui", + "survey-nps-results", + "session-recording-allow-v1-snapshots", + "session-replay-cors-proxy", + "webhooks-denylist", + "surveys-site-app-deprecation", + "surveys-multiple-questions", + "surveys-results-visualizations", + "console-recording-search", + "persons-hogql-query", + "notebooks" + ], + "$feature/file-previews": false, + "$feature/signup-page-4.0": "control", + "$feature/hogql-insights": false, + "$feature/cmd-k-search": true, + "$feature/posthog-3000": true, + "$feature/funnels-cue-opt-out-7301": true, + "$feature/retention-breakdown": true, + "$feature/smoothing-interval": true, + "$feature/billing-limit": true, + "$feature/kafka-inspector": true, + "$feature/historical-exports-v2": true, + "$feature/person-on-events-enabled": true, + "$feature/region-select": true, + "$feature/ingestion-warnings-enabled": true, + "$feature/session-reset-on-load": true, + "$feature/recordings-on-feature-flags": true, + "$feature/auto-rollback-feature-flags": true, + "$feature/onboarding-v2-demo": true, + "$feature/feature-flag-rollout-ux": true, + "$feature/role-based-access": true, + "$feature/query_running_time": true, + "$feature/query-timings": true, + "$feature/recording-debugging": true, + "$feature/enable-prompts": true, + "$feature/feedback-scene": true, + "$feature/early-access-feature": true, + "$feature/early-access-feature-site-button": true, + "$feature/hedgehog-mode-debug": true, + "$feature/auto-redirect": true, + "$feature/session-recording-blob-replay": true, + "$feature/surveys": true, + "$feature/generic-signup-benefits": true, + "$feature/surveys-positions": true, + "$feature/web-analytics": true, + "$feature/high-frequency-batch-exports": true, + "$feature/exception-autocapture": true, + "$feature/data-warehouse": true, + "$feature/data-warehouse-views": true, + "$feature/ff-dashboard-templates": true, + "$feature/show-product-intro-existing-products": true, + "$feature/artificial-hog": true, + "$feature/cs-dashboards": true, + "$feature/product-specific-onboarding": true, + "$feature/redirect-signups-to-instance": true, + "$feature/apps-and-exports-ui": true, + "$feature/survey-nps-results": true, + "$feature/session-recording-allow-v1-snapshots": true, + "$feature/session-replay-cors-proxy": true, + "$feature/webhooks-denylist": true, + "$feature/surveys-site-app-deprecation": true, + "$feature/surveys-multiple-questions": true, + "$feature/surveys-results-visualizations": true, + "$feature/console-recording-search": true, + "$feature/persons-hogql-query": true, + "$feature/notebooks": true, + "$feature_flag_payloads": {}, + "realm": "hosted-clickhouse", + "email_service_available": false, + "slack_service_available": false, + "$user_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "is_demo_project": false, + "$groups": { + "project": "018a92f8-b602-0000-75de-4b9073693531", + "organization": "018a92f8-afff-0000-efec-ca77de39e384", + "customer": "cus_OdSgxxWtHOtq9g", + "instance": "http://localhost:8000" + }, + "has_billing_plan": true, + "customer_deactivated": false, + "current_total_amount_usd": "0.00", + "percentage_usage.product_analytics": 0, + "current_amount_usd.product_analytics": "0.00", + "unit_amount_usd.product_analytics": null, + "usage_limit.product_analytics": null, + "current_usage.product_analytics": 3729, + "projected_usage.product_analytics": 0, + "free_allocation.product_analytics": 0, + "percentage_usage.session_replay": 0, + "current_amount_usd.session_replay": "0.00", + "unit_amount_usd.session_replay": null, + "usage_limit.session_replay": null, + "current_usage.session_replay": 254, + "projected_usage.session_replay": 0, + "free_allocation.session_replay": 0, + "percentage_usage.feature_flags": 0, + "current_amount_usd.feature_flags": "0.00", + "unit_amount_usd.feature_flags": null, + "usage_limit.feature_flags": null, + "current_usage.feature_flags": 0, + "projected_usage.feature_flags": 0, + "free_allocation.feature_flags": 0, + "percentage_usage.integrations": 0, + "current_amount_usd.integrations": null, + "unit_amount_usd.integrations": null, + "usage_limit.integrations": 0, + "current_usage.integrations": 0, + "projected_usage.integrations": 0, + "free_allocation.integrations": 0, + "percentage_usage.platform_and_support": 0, + "current_amount_usd.platform_and_support": null, + "unit_amount_usd.platform_and_support": null, + "usage_limit.platform_and_support": 0, + "current_usage.platform_and_support": 0, + "projected_usage.platform_and_support": 0, + "free_allocation.platform_and_support": 0, + "billing_period_start": "2023-10-14T09:22:33.000Z", + "billing_period_end": "2023-11-14T09:22:33.000Z", + "$referrer": "$direct", + "$referring_domain": "$direct", + "$feature_flag": "posthog-3000", + "$feature_flag_response": true, + "token": "phc_OWGI2wKbfi7rWDZT9wkl8uGcfe0wOGCvflLEZSMiaT0", + "$session_id": "018b4ca3-1d07-7195-8202-c8a103a9325a", + "$window_id": "018b4ca3-1d07-7195-8202-c8a2b00ad68a", + "$ip": "127.0.0.1", + "$set": { + "$os": "Mac OS X", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI#activeTab=feed&state=eyJ0eXBlIjoiZG9jIiwiY29udGVudCI6W3sidHlwZSI6ImhlYWRpbmciLCJhdHRycyI6eyJsZXZlbCI6MX0sImNvbnRlbnQiOlt7InR5cGUiOiJ0ZXh0IiwidGV4dCI6ImtyUmZnb3BzVXkxVHdOVTF5aFNETHFORFRkNk41dE1ackhsbThuTEpJREkifV19LHsidHlwZSI6InBoLXBlcnNvbi1mZWVkIiwiYXR0cnMiOnsiaGVpZ2h0IjpudWxsLCJ0aXRsZSI6bnVsbCwibm9kZUlkIjoiNmQ0ODUwNjYtZWM5OS00ODNkLThiOTgtNGQ4YTJkYzljYzRiIiwiaWQiOiJrclJmZ29wc1V5MVR3TlUxeWhTRExxTkRUZDZONXRNWnJIbG04bkxKSURJIiwiX19pbml0IjpudWxsLCJjaGlsZHJlbiI6W3sidHlwZSI6InBoLXBlcnNvbiIsImF0dHJzIjp7ImlkIjoia3JSZmdvcHNVeTFUd05VMXloU0RMcU5EVGQ2TjV0TVpySGxtOG5MSklESSIsIm5vZGVJZCI6IjNkMzZiZjU3LTFkYjQtNDJlZi1iNzhiLWUyZDNkNGViOWM5NSJ9fSx7InR5cGUiOiJwaC1tYXAiLCJhdHRycyI6eyJpZCI6ImtyUmZnb3BzVXkxVHdOVTF5aFNETHFORFRkNk41dE1ackhsbThuTEpJREkiLCJub2RlSWQiOiI1MzE0ZWI2MS1lYTA2LTQyOGQtYWEzZi0zMDA4OWJjZmUxYjgifX0seyJ0eXBlIjoicGgtcHJvcGVydGllcyIsImF0dHJzIjp7ImlkIjoia3JSZmdvcHNVeTFUd05VMXloU0RMcU5EVGQ2TjV0TVpySGxtOG5MSklESSIsIm5vZGVJZCI6ImUwMjE1NDU5LWY0YTgtNGJjNy04NDhmLTYxODE1NzY1NzlmNyJ9fV19fV19", + "$pathname": "/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$browser_version": 117, + "$referrer": "$direct", + "$referring_domain": "$direct" + }, + "$set_once": { + "$initial_os": "Mac OS X", + "$initial_browser": "Chrome", + "$initial_device_type": "Desktop", + "$initial_current_url": "http://localhost:8000/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI#activeTab=feed&state=eyJ0eXBlIjoiZG9jIiwiY29udGVudCI6W3sidHlwZSI6ImhlYWRpbmciLCJhdHRycyI6eyJsZXZlbCI6MX0sImNvbnRlbnQiOlt7InR5cGUiOiJ0ZXh0IiwidGV4dCI6ImtyUmZnb3BzVXkxVHdOVTF5aFNETHFORFRkNk41dE1ackhsbThuTEpJREkifV19LHsidHlwZSI6InBoLXBlcnNvbi1mZWVkIiwiYXR0cnMiOnsiaGVpZ2h0IjpudWxsLCJ0aXRsZSI6bnVsbCwibm9kZUlkIjoiNmQ0ODUwNjYtZWM5OS00ODNkLThiOTgtNGQ4YTJkYzljYzRiIiwiaWQiOiJrclJmZ29wc1V5MVR3TlUxeWhTRExxTkRUZDZONXRNWnJIbG04bkxKSURJIiwiX19pbml0IjpudWxsLCJjaGlsZHJlbiI6W3sidHlwZSI6InBoLXBlcnNvbiIsImF0dHJzIjp7ImlkIjoia3JSZmdvcHNVeTFUd05VMXloU0RMcU5EVGQ2TjV0TVpySGxtOG5MSklESSIsIm5vZGVJZCI6IjNkMzZiZjU3LTFkYjQtNDJlZi1iNzhiLWUyZDNkNGViOWM5NSJ9fSx7InR5cGUiOiJwaC1tYXAiLCJhdHRycyI6eyJpZCI6ImtyUmZnb3BzVXkxVHdOVTF5aFNETHFORFRkNk41dE1ackhsbThuTEpJREkiLCJub2RlSWQiOiI1MzE0ZWI2MS1lYTA2LTQyOGQtYWEzZi0zMDA4OWJjZmUxYjgifX0seyJ0eXBlIjoicGgtcHJvcGVydGllcyIsImF0dHJzIjp7ImlkIjoia3JSZmdvcHNVeTFUd05VMXloU0RMcU5EVGQ2TjV0TVpySGxtOG5MSklESSIsIm5vZGVJZCI6ImUwMjE1NDU5LWY0YTgtNGJjNy04NDhmLTYxODE1NzY1NzlmNyJ9fV19fV19", + "$initial_pathname": "/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$initial_browser_version": 117, + "$initial_referrer": "$direct", + "$initial_referring_domain": "$direct" + }, + "$sent_at": "2023-10-20T10:30:43.133000+00:00", + "$geoip_city_name": "Sydney", + "$geoip_country_name": "Australia", + "$geoip_country_code": "AU", + "$geoip_continent_name": "Oceania", + "$geoip_continent_code": "OC", + "$geoip_postal_code": "2000", + "$geoip_latitude": -33.8715, + "$geoip_longitude": 151.2006, + "$geoip_time_zone": "Australia/Sydney", + "$geoip_subdivision_1_code": "NSW", + "$geoip_subdivision_1_name": "New South Wales", + "$plugins_succeeded": ["GeoIP (1)"], + "$plugins_failed": [], + "$plugins_deferred": [], + "$group_3": "018a92f8-b602-0000-75de-4b9073693531", + "$group_2": "018a92f8-afff-0000-efec-ca77de39e384", + "$group_4": "cus_OdSgxxWtHOtq9g", + "$group_1": "http://localhost:8000" + }, + "timestamp": "2023-10-20T10:30:40.237000+00:00", + "uuid": null + }, + { + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "elements": [], + "elements_chain": null, + "event": "$feature_flag_called", + "id": "018b4ca3-1d5e-7346-afdf-2400e5e7f7d6", + "person": null, + "properties": { + "$os": "Mac OS X", + "$os_version": "10.15.7", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI#activeTab=feed&state=eyJ0eXBlIjoiZG9jIiwiY29udGVudCI6W3sidHlwZSI6ImhlYWRpbmciLCJhdHRycyI6eyJsZXZlbCI6MX0sImNvbnRlbnQiOlt7InR5cGUiOiJ0ZXh0IiwidGV4dCI6ImtyUmZnb3BzVXkxVHdOVTF5aFNETHFORFRkNk41dE1ackhsbThuTEpJREkifV19LHsidHlwZSI6InBoLXBlcnNvbi1mZWVkIiwiYXR0cnMiOnsiaGVpZ2h0IjpudWxsLCJ0aXRsZSI6bnVsbCwibm9kZUlkIjoiNmQ0ODUwNjYtZWM5OS00ODNkLThiOTgtNGQ4YTJkYzljYzRiIiwiaWQiOiJrclJmZ29wc1V5MVR3TlUxeWhTRExxTkRUZDZONXRNWnJIbG04bkxKSURJIiwiX19pbml0IjpudWxsLCJjaGlsZHJlbiI6W3sidHlwZSI6InBoLXBlcnNvbiIsImF0dHJzIjp7ImlkIjoia3JSZmdvcHNVeTFUd05VMXloU0RMcU5EVGQ2TjV0TVpySGxtOG5MSklESSIsIm5vZGVJZCI6IjNkMzZiZjU3LTFkYjQtNDJlZi1iNzhiLWUyZDNkNGViOWM5NSJ9fSx7InR5cGUiOiJwaC1tYXAiLCJhdHRycyI6eyJpZCI6ImtyUmZnb3BzVXkxVHdOVTF5aFNETHFORFRkNk41dE1ackhsbThuTEpJREkiLCJub2RlSWQiOiI1MzE0ZWI2MS1lYTA2LTQyOGQtYWEzZi0zMDA4OWJjZmUxYjgifX0seyJ0eXBlIjoicGgtcHJvcGVydGllcyIsImF0dHJzIjp7ImlkIjoia3JSZmdvcHNVeTFUd05VMXloU0RMcU5EVGQ2TjV0TVpySGxtOG5MSklESSIsIm5vZGVJZCI6ImUwMjE1NDU5LWY0YTgtNGJjNy04NDhmLTYxODE1NzY1NzlmNyJ9fV19fV19", + "$host": "localhost:8000", + "$pathname": "/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$browser_version": 117, + "$browser_language": "en-GB", + "$screen_height": 982, + "$screen_width": 1512, + "$viewport_height": 859, + "$viewport_width": 1512, + "$lib": "web", + "$lib_version": "1.84.0", + "$insert_id": "96opt7bntz65vkew", + "$time": 1697797840.222, + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$device_id": "018a92fd-7b25-7770-a050-577e94fd148c", + "$console_log_recording_enabled_server_side": true, + "$session_recording_recorder_version_server_side": "v2", + "$autocapture_disabled_server_side": false, + "$active_feature_flags": [ + "signup-page-4.0", + "cmd-k-search", + "posthog-3000", + "funnels-cue-opt-out-7301", + "retention-breakdown", + "smoothing-interval", + "billing-limit", + "kafka-inspector", + "historical-exports-v2", + "person-on-events-enabled", + "region-select", + "ingestion-warnings-enabled", + "session-reset-on-load", + "recordings-on-feature-flags", + "auto-rollback-feature-flags", + "onboarding-v2-demo", + "feature-flag-rollout-ux", + "role-based-access", + "query_running_time", + "query-timings", + "recording-debugging", + "enable-prompts", + "feedback-scene", + "early-access-feature", + "early-access-feature-site-button", + "hedgehog-mode-debug", + "auto-redirect", + "session-recording-blob-replay", + "surveys", + "generic-signup-benefits", + "surveys-positions", + "web-analytics", + "high-frequency-batch-exports", + "exception-autocapture", + "data-warehouse", + "data-warehouse-views", + "ff-dashboard-templates", + "show-product-intro-existing-products", + "artificial-hog", + "cs-dashboards", + "product-specific-onboarding", + "redirect-signups-to-instance", + "apps-and-exports-ui", + "survey-nps-results", + "session-recording-allow-v1-snapshots", + "session-replay-cors-proxy", + "webhooks-denylist", + "surveys-site-app-deprecation", + "surveys-multiple-questions", + "surveys-results-visualizations", + "console-recording-search", + "persons-hogql-query", + "notebooks" + ], + "$feature/file-previews": false, + "$feature/signup-page-4.0": "control", + "$feature/hogql-insights": false, + "$feature/cmd-k-search": true, + "$feature/posthog-3000": true, + "$feature/funnels-cue-opt-out-7301": true, + "$feature/retention-breakdown": true, + "$feature/smoothing-interval": true, + "$feature/billing-limit": true, + "$feature/kafka-inspector": true, + "$feature/historical-exports-v2": true, + "$feature/person-on-events-enabled": true, + "$feature/region-select": true, + "$feature/ingestion-warnings-enabled": true, + "$feature/session-reset-on-load": true, + "$feature/recordings-on-feature-flags": true, + "$feature/auto-rollback-feature-flags": true, + "$feature/onboarding-v2-demo": true, + "$feature/feature-flag-rollout-ux": true, + "$feature/role-based-access": true, + "$feature/query_running_time": true, + "$feature/query-timings": true, + "$feature/recording-debugging": true, + "$feature/enable-prompts": true, + "$feature/feedback-scene": true, + "$feature/early-access-feature": true, + "$feature/early-access-feature-site-button": true, + "$feature/hedgehog-mode-debug": true, + "$feature/auto-redirect": true, + "$feature/session-recording-blob-replay": true, + "$feature/surveys": true, + "$feature/generic-signup-benefits": true, + "$feature/surveys-positions": true, + "$feature/web-analytics": true, + "$feature/high-frequency-batch-exports": true, + "$feature/exception-autocapture": true, + "$feature/data-warehouse": true, + "$feature/data-warehouse-views": true, + "$feature/ff-dashboard-templates": true, + "$feature/show-product-intro-existing-products": true, + "$feature/artificial-hog": true, + "$feature/cs-dashboards": true, + "$feature/product-specific-onboarding": true, + "$feature/redirect-signups-to-instance": true, + "$feature/apps-and-exports-ui": true, + "$feature/survey-nps-results": true, + "$feature/session-recording-allow-v1-snapshots": true, + "$feature/session-replay-cors-proxy": true, + "$feature/webhooks-denylist": true, + "$feature/surveys-site-app-deprecation": true, + "$feature/surveys-multiple-questions": true, + "$feature/surveys-results-visualizations": true, + "$feature/console-recording-search": true, + "$feature/persons-hogql-query": true, + "$feature/notebooks": true, + "$feature_flag_payloads": {}, + "realm": "hosted-clickhouse", + "email_service_available": false, + "slack_service_available": false, + "$user_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "is_demo_project": false, + "$groups": { + "project": "018a92f8-b602-0000-75de-4b9073693531", + "organization": "018a92f8-afff-0000-efec-ca77de39e384", + "customer": "cus_OdSgxxWtHOtq9g", + "instance": "http://localhost:8000" + }, + "has_billing_plan": true, + "customer_deactivated": false, + "current_total_amount_usd": "0.00", + "percentage_usage.product_analytics": 0, + "current_amount_usd.product_analytics": "0.00", + "unit_amount_usd.product_analytics": null, + "usage_limit.product_analytics": null, + "current_usage.product_analytics": 3729, + "projected_usage.product_analytics": 0, + "free_allocation.product_analytics": 0, + "percentage_usage.session_replay": 0, + "current_amount_usd.session_replay": "0.00", + "unit_amount_usd.session_replay": null, + "usage_limit.session_replay": null, + "current_usage.session_replay": 254, + "projected_usage.session_replay": 0, + "free_allocation.session_replay": 0, + "percentage_usage.feature_flags": 0, + "current_amount_usd.feature_flags": "0.00", + "unit_amount_usd.feature_flags": null, + "usage_limit.feature_flags": null, + "current_usage.feature_flags": 0, + "projected_usage.feature_flags": 0, + "free_allocation.feature_flags": 0, + "percentage_usage.integrations": 0, + "current_amount_usd.integrations": null, + "unit_amount_usd.integrations": null, + "usage_limit.integrations": 0, + "current_usage.integrations": 0, + "projected_usage.integrations": 0, + "free_allocation.integrations": 0, + "percentage_usage.platform_and_support": 0, + "current_amount_usd.platform_and_support": null, + "unit_amount_usd.platform_and_support": null, + "usage_limit.platform_and_support": 0, + "current_usage.platform_and_support": 0, + "projected_usage.platform_and_support": 0, + "free_allocation.platform_and_support": 0, + "billing_period_start": "2023-10-14T09:22:33.000Z", + "billing_period_end": "2023-11-14T09:22:33.000Z", + "$referrer": "$direct", + "$referring_domain": "$direct", + "$feature_flag": "enable-prompts", + "$feature_flag_response": true, + "token": "phc_OWGI2wKbfi7rWDZT9wkl8uGcfe0wOGCvflLEZSMiaT0", + "$session_id": "018b4ca3-1d07-7195-8202-c8a103a9325a", + "$window_id": "018b4ca3-1d07-7195-8202-c8a2b00ad68a", + "$ip": "127.0.0.1", + "$set": { + "$os": "Mac OS X", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI#activeTab=feed&state=eyJ0eXBlIjoiZG9jIiwiY29udGVudCI6W3sidHlwZSI6ImhlYWRpbmciLCJhdHRycyI6eyJsZXZlbCI6MX0sImNvbnRlbnQiOlt7InR5cGUiOiJ0ZXh0IiwidGV4dCI6ImtyUmZnb3BzVXkxVHdOVTF5aFNETHFORFRkNk41dE1ackhsbThuTEpJREkifV19LHsidHlwZSI6InBoLXBlcnNvbi1mZWVkIiwiYXR0cnMiOnsiaGVpZ2h0IjpudWxsLCJ0aXRsZSI6bnVsbCwibm9kZUlkIjoiNmQ0ODUwNjYtZWM5OS00ODNkLThiOTgtNGQ4YTJkYzljYzRiIiwiaWQiOiJrclJmZ29wc1V5MVR3TlUxeWhTRExxTkRUZDZONXRNWnJIbG04bkxKSURJIiwiX19pbml0IjpudWxsLCJjaGlsZHJlbiI6W3sidHlwZSI6InBoLXBlcnNvbiIsImF0dHJzIjp7ImlkIjoia3JSZmdvcHNVeTFUd05VMXloU0RMcU5EVGQ2TjV0TVpySGxtOG5MSklESSIsIm5vZGVJZCI6IjNkMzZiZjU3LTFkYjQtNDJlZi1iNzhiLWUyZDNkNGViOWM5NSJ9fSx7InR5cGUiOiJwaC1tYXAiLCJhdHRycyI6eyJpZCI6ImtyUmZnb3BzVXkxVHdOVTF5aFNETHFORFRkNk41dE1ackhsbThuTEpJREkiLCJub2RlSWQiOiI1MzE0ZWI2MS1lYTA2LTQyOGQtYWEzZi0zMDA4OWJjZmUxYjgifX0seyJ0eXBlIjoicGgtcHJvcGVydGllcyIsImF0dHJzIjp7ImlkIjoia3JSZmdvcHNVeTFUd05VMXloU0RMcU5EVGQ2TjV0TVpySGxtOG5MSklESSIsIm5vZGVJZCI6ImUwMjE1NDU5LWY0YTgtNGJjNy04NDhmLTYxODE1NzY1NzlmNyJ9fV19fV19", + "$pathname": "/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$browser_version": 117, + "$referrer": "$direct", + "$referring_domain": "$direct" + }, + "$set_once": { + "$initial_os": "Mac OS X", + "$initial_browser": "Chrome", + "$initial_device_type": "Desktop", + "$initial_current_url": "http://localhost:8000/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI#activeTab=feed&state=eyJ0eXBlIjoiZG9jIiwiY29udGVudCI6W3sidHlwZSI6ImhlYWRpbmciLCJhdHRycyI6eyJsZXZlbCI6MX0sImNvbnRlbnQiOlt7InR5cGUiOiJ0ZXh0IiwidGV4dCI6ImtyUmZnb3BzVXkxVHdOVTF5aFNETHFORFRkNk41dE1ackhsbThuTEpJREkifV19LHsidHlwZSI6InBoLXBlcnNvbi1mZWVkIiwiYXR0cnMiOnsiaGVpZ2h0IjpudWxsLCJ0aXRsZSI6bnVsbCwibm9kZUlkIjoiNmQ0ODUwNjYtZWM5OS00ODNkLThiOTgtNGQ4YTJkYzljYzRiIiwiaWQiOiJrclJmZ29wc1V5MVR3TlUxeWhTRExxTkRUZDZONXRNWnJIbG04bkxKSURJIiwiX19pbml0IjpudWxsLCJjaGlsZHJlbiI6W3sidHlwZSI6InBoLXBlcnNvbiIsImF0dHJzIjp7ImlkIjoia3JSZmdvcHNVeTFUd05VMXloU0RMcU5EVGQ2TjV0TVpySGxtOG5MSklESSIsIm5vZGVJZCI6IjNkMzZiZjU3LTFkYjQtNDJlZi1iNzhiLWUyZDNkNGViOWM5NSJ9fSx7InR5cGUiOiJwaC1tYXAiLCJhdHRycyI6eyJpZCI6ImtyUmZnb3BzVXkxVHdOVTF5aFNETHFORFRkNk41dE1ackhsbThuTEpJREkiLCJub2RlSWQiOiI1MzE0ZWI2MS1lYTA2LTQyOGQtYWEzZi0zMDA4OWJjZmUxYjgifX0seyJ0eXBlIjoicGgtcHJvcGVydGllcyIsImF0dHJzIjp7ImlkIjoia3JSZmdvcHNVeTFUd05VMXloU0RMcU5EVGQ2TjV0TVpySGxtOG5MSklESSIsIm5vZGVJZCI6ImUwMjE1NDU5LWY0YTgtNGJjNy04NDhmLTYxODE1NzY1NzlmNyJ9fV19fV19", + "$initial_pathname": "/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$initial_browser_version": 117, + "$initial_referrer": "$direct", + "$initial_referring_domain": "$direct" + }, + "$sent_at": "2023-10-20T10:30:43.133000+00:00", + "$geoip_city_name": "Sydney", + "$geoip_country_name": "Australia", + "$geoip_country_code": "AU", + "$geoip_continent_name": "Oceania", + "$geoip_continent_code": "OC", + "$geoip_postal_code": "2000", + "$geoip_latitude": -33.8715, + "$geoip_longitude": 151.2006, + "$geoip_time_zone": "Australia/Sydney", + "$geoip_subdivision_1_code": "NSW", + "$geoip_subdivision_1_name": "New South Wales", + "$plugins_succeeded": ["GeoIP (1)"], + "$plugins_failed": [], + "$plugins_deferred": [], + "$group_3": "018a92f8-b602-0000-75de-4b9073693531", + "$group_2": "018a92f8-afff-0000-efec-ca77de39e384", + "$group_4": "cus_OdSgxxWtHOtq9g", + "$group_1": "http://localhost:8000" + }, + "timestamp": "2023-10-20T10:30:40.237000+00:00", + "uuid": null + }, + { + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "elements": [], + "elements_chain": null, + "event": "$feature_flag_called", + "id": "018b4ca3-1d63-70c3-bc8e-32652a5076c2", + "person": null, + "properties": { + "$os": "Mac OS X", + "$os_version": "10.15.7", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI#activeTab=feed&state=eyJ0eXBlIjoiZG9jIiwiY29udGVudCI6W3sidHlwZSI6ImhlYWRpbmciLCJhdHRycyI6eyJsZXZlbCI6MX0sImNvbnRlbnQiOlt7InR5cGUiOiJ0ZXh0IiwidGV4dCI6ImtyUmZnb3BzVXkxVHdOVTF5aFNETHFORFRkNk41dE1ackhsbThuTEpJREkifV19LHsidHlwZSI6InBoLXBlcnNvbi1mZWVkIiwiYXR0cnMiOnsiaGVpZ2h0IjpudWxsLCJ0aXRsZSI6bnVsbCwibm9kZUlkIjoiNmQ0ODUwNjYtZWM5OS00ODNkLThiOTgtNGQ4YTJkYzljYzRiIiwiaWQiOiJrclJmZ29wc1V5MVR3TlUxeWhTRExxTkRUZDZONXRNWnJIbG04bkxKSURJIiwiX19pbml0IjpudWxsLCJjaGlsZHJlbiI6W3sidHlwZSI6InBoLXBlcnNvbiIsImF0dHJzIjp7ImlkIjoia3JSZmdvcHNVeTFUd05VMXloU0RMcU5EVGQ2TjV0TVpySGxtOG5MSklESSIsIm5vZGVJZCI6IjNkMzZiZjU3LTFkYjQtNDJlZi1iNzhiLWUyZDNkNGViOWM5NSJ9fSx7InR5cGUiOiJwaC1tYXAiLCJhdHRycyI6eyJpZCI6ImtyUmZnb3BzVXkxVHdOVTF5aFNETHFORFRkNk41dE1ackhsbThuTEpJREkiLCJub2RlSWQiOiI1MzE0ZWI2MS1lYTA2LTQyOGQtYWEzZi0zMDA4OWJjZmUxYjgifX0seyJ0eXBlIjoicGgtcHJvcGVydGllcyIsImF0dHJzIjp7ImlkIjoia3JSZmdvcHNVeTFUd05VMXloU0RMcU5EVGQ2TjV0TVpySGxtOG5MSklESSIsIm5vZGVJZCI6ImUwMjE1NDU5LWY0YTgtNGJjNy04NDhmLTYxODE1NzY1NzlmNyJ9fV19fV19", + "$host": "localhost:8000", + "$pathname": "/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$browser_version": 117, + "$browser_language": "en-GB", + "$screen_height": 982, + "$screen_width": 1512, + "$viewport_height": 859, + "$viewport_width": 1512, + "$lib": "web", + "$lib_version": "1.84.0", + "$insert_id": "it0bs3zaxzky8511", + "$time": 1697797840.228, + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$device_id": "018a92fd-7b25-7770-a050-577e94fd148c", + "$console_log_recording_enabled_server_side": true, + "$session_recording_recorder_version_server_side": "v2", + "$autocapture_disabled_server_side": false, + "$active_feature_flags": [ + "signup-page-4.0", + "cmd-k-search", + "posthog-3000", + "funnels-cue-opt-out-7301", + "retention-breakdown", + "smoothing-interval", + "billing-limit", + "kafka-inspector", + "historical-exports-v2", + "person-on-events-enabled", + "region-select", + "ingestion-warnings-enabled", + "session-reset-on-load", + "recordings-on-feature-flags", + "auto-rollback-feature-flags", + "onboarding-v2-demo", + "feature-flag-rollout-ux", + "role-based-access", + "query_running_time", + "query-timings", + "recording-debugging", + "enable-prompts", + "feedback-scene", + "early-access-feature", + "early-access-feature-site-button", + "hedgehog-mode-debug", + "auto-redirect", + "session-recording-blob-replay", + "surveys", + "generic-signup-benefits", + "surveys-positions", + "web-analytics", + "high-frequency-batch-exports", + "exception-autocapture", + "data-warehouse", + "data-warehouse-views", + "ff-dashboard-templates", + "show-product-intro-existing-products", + "artificial-hog", + "cs-dashboards", + "product-specific-onboarding", + "redirect-signups-to-instance", + "apps-and-exports-ui", + "survey-nps-results", + "session-recording-allow-v1-snapshots", + "session-replay-cors-proxy", + "webhooks-denylist", + "surveys-site-app-deprecation", + "surveys-multiple-questions", + "surveys-results-visualizations", + "console-recording-search", + "persons-hogql-query", + "notebooks" + ], + "$feature/file-previews": false, + "$feature/signup-page-4.0": "control", + "$feature/hogql-insights": false, + "$feature/cmd-k-search": true, + "$feature/posthog-3000": true, + "$feature/funnels-cue-opt-out-7301": true, + "$feature/retention-breakdown": true, + "$feature/smoothing-interval": true, + "$feature/billing-limit": true, + "$feature/kafka-inspector": true, + "$feature/historical-exports-v2": true, + "$feature/person-on-events-enabled": true, + "$feature/region-select": true, + "$feature/ingestion-warnings-enabled": true, + "$feature/session-reset-on-load": true, + "$feature/recordings-on-feature-flags": true, + "$feature/auto-rollback-feature-flags": true, + "$feature/onboarding-v2-demo": true, + "$feature/feature-flag-rollout-ux": true, + "$feature/role-based-access": true, + "$feature/query_running_time": true, + "$feature/query-timings": true, + "$feature/recording-debugging": true, + "$feature/enable-prompts": true, + "$feature/feedback-scene": true, + "$feature/early-access-feature": true, + "$feature/early-access-feature-site-button": true, + "$feature/hedgehog-mode-debug": true, + "$feature/auto-redirect": true, + "$feature/session-recording-blob-replay": true, + "$feature/surveys": true, + "$feature/generic-signup-benefits": true, + "$feature/surveys-positions": true, + "$feature/web-analytics": true, + "$feature/high-frequency-batch-exports": true, + "$feature/exception-autocapture": true, + "$feature/data-warehouse": true, + "$feature/data-warehouse-views": true, + "$feature/ff-dashboard-templates": true, + "$feature/show-product-intro-existing-products": true, + "$feature/artificial-hog": true, + "$feature/cs-dashboards": true, + "$feature/product-specific-onboarding": true, + "$feature/redirect-signups-to-instance": true, + "$feature/apps-and-exports-ui": true, + "$feature/survey-nps-results": true, + "$feature/session-recording-allow-v1-snapshots": true, + "$feature/session-replay-cors-proxy": true, + "$feature/webhooks-denylist": true, + "$feature/surveys-site-app-deprecation": true, + "$feature/surveys-multiple-questions": true, + "$feature/surveys-results-visualizations": true, + "$feature/console-recording-search": true, + "$feature/persons-hogql-query": true, + "$feature/notebooks": true, + "$feature_flag_payloads": {}, + "realm": "hosted-clickhouse", + "email_service_available": false, + "slack_service_available": false, + "$user_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "is_demo_project": false, + "$groups": { + "project": "018a92f8-b602-0000-75de-4b9073693531", + "organization": "018a92f8-afff-0000-efec-ca77de39e384", + "customer": "cus_OdSgxxWtHOtq9g", + "instance": "http://localhost:8000" + }, + "has_billing_plan": true, + "customer_deactivated": false, + "current_total_amount_usd": "0.00", + "percentage_usage.product_analytics": 0, + "current_amount_usd.product_analytics": "0.00", + "unit_amount_usd.product_analytics": null, + "usage_limit.product_analytics": null, + "current_usage.product_analytics": 3729, + "projected_usage.product_analytics": 0, + "free_allocation.product_analytics": 0, + "percentage_usage.session_replay": 0, + "current_amount_usd.session_replay": "0.00", + "unit_amount_usd.session_replay": null, + "usage_limit.session_replay": null, + "current_usage.session_replay": 254, + "projected_usage.session_replay": 0, + "free_allocation.session_replay": 0, + "percentage_usage.feature_flags": 0, + "current_amount_usd.feature_flags": "0.00", + "unit_amount_usd.feature_flags": null, + "usage_limit.feature_flags": null, + "current_usage.feature_flags": 0, + "projected_usage.feature_flags": 0, + "free_allocation.feature_flags": 0, + "percentage_usage.integrations": 0, + "current_amount_usd.integrations": null, + "unit_amount_usd.integrations": null, + "usage_limit.integrations": 0, + "current_usage.integrations": 0, + "projected_usage.integrations": 0, + "free_allocation.integrations": 0, + "percentage_usage.platform_and_support": 0, + "current_amount_usd.platform_and_support": null, + "unit_amount_usd.platform_and_support": null, + "usage_limit.platform_and_support": 0, + "current_usage.platform_and_support": 0, + "projected_usage.platform_and_support": 0, + "free_allocation.platform_and_support": 0, + "billing_period_start": "2023-10-14T09:22:33.000Z", + "billing_period_end": "2023-11-14T09:22:33.000Z", + "$referrer": "$direct", + "$referring_domain": "$direct", + "$feature_flag": "notebooks", + "$feature_flag_response": true, + "token": "phc_OWGI2wKbfi7rWDZT9wkl8uGcfe0wOGCvflLEZSMiaT0", + "$session_id": "018b4ca3-1d07-7195-8202-c8a103a9325a", + "$window_id": "018b4ca3-1d07-7195-8202-c8a2b00ad68a", + "$ip": "127.0.0.1", + "$set": { + "$os": "Mac OS X", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI#activeTab=feed&state=eyJ0eXBlIjoiZG9jIiwiY29udGVudCI6W3sidHlwZSI6ImhlYWRpbmciLCJhdHRycyI6eyJsZXZlbCI6MX0sImNvbnRlbnQiOlt7InR5cGUiOiJ0ZXh0IiwidGV4dCI6ImtyUmZnb3BzVXkxVHdOVTF5aFNETHFORFRkNk41dE1ackhsbThuTEpJREkifV19LHsidHlwZSI6InBoLXBlcnNvbi1mZWVkIiwiYXR0cnMiOnsiaGVpZ2h0IjpudWxsLCJ0aXRsZSI6bnVsbCwibm9kZUlkIjoiNmQ0ODUwNjYtZWM5OS00ODNkLThiOTgtNGQ4YTJkYzljYzRiIiwiaWQiOiJrclJmZ29wc1V5MVR3TlUxeWhTRExxTkRUZDZONXRNWnJIbG04bkxKSURJIiwiX19pbml0IjpudWxsLCJjaGlsZHJlbiI6W3sidHlwZSI6InBoLXBlcnNvbiIsImF0dHJzIjp7ImlkIjoia3JSZmdvcHNVeTFUd05VMXloU0RMcU5EVGQ2TjV0TVpySGxtOG5MSklESSIsIm5vZGVJZCI6IjNkMzZiZjU3LTFkYjQtNDJlZi1iNzhiLWUyZDNkNGViOWM5NSJ9fSx7InR5cGUiOiJwaC1tYXAiLCJhdHRycyI6eyJpZCI6ImtyUmZnb3BzVXkxVHdOVTF5aFNETHFORFRkNk41dE1ackhsbThuTEpJREkiLCJub2RlSWQiOiI1MzE0ZWI2MS1lYTA2LTQyOGQtYWEzZi0zMDA4OWJjZmUxYjgifX0seyJ0eXBlIjoicGgtcHJvcGVydGllcyIsImF0dHJzIjp7ImlkIjoia3JSZmdvcHNVeTFUd05VMXloU0RMcU5EVGQ2TjV0TVpySGxtOG5MSklESSIsIm5vZGVJZCI6ImUwMjE1NDU5LWY0YTgtNGJjNy04NDhmLTYxODE1NzY1NzlmNyJ9fV19fV19", + "$pathname": "/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$browser_version": 117, + "$referrer": "$direct", + "$referring_domain": "$direct" + }, + "$set_once": { + "$initial_os": "Mac OS X", + "$initial_browser": "Chrome", + "$initial_device_type": "Desktop", + "$initial_current_url": "http://localhost:8000/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI#activeTab=feed&state=eyJ0eXBlIjoiZG9jIiwiY29udGVudCI6W3sidHlwZSI6ImhlYWRpbmciLCJhdHRycyI6eyJsZXZlbCI6MX0sImNvbnRlbnQiOlt7InR5cGUiOiJ0ZXh0IiwidGV4dCI6ImtyUmZnb3BzVXkxVHdOVTF5aFNETHFORFRkNk41dE1ackhsbThuTEpJREkifV19LHsidHlwZSI6InBoLXBlcnNvbi1mZWVkIiwiYXR0cnMiOnsiaGVpZ2h0IjpudWxsLCJ0aXRsZSI6bnVsbCwibm9kZUlkIjoiNmQ0ODUwNjYtZWM5OS00ODNkLThiOTgtNGQ4YTJkYzljYzRiIiwiaWQiOiJrclJmZ29wc1V5MVR3TlUxeWhTRExxTkRUZDZONXRNWnJIbG04bkxKSURJIiwiX19pbml0IjpudWxsLCJjaGlsZHJlbiI6W3sidHlwZSI6InBoLXBlcnNvbiIsImF0dHJzIjp7ImlkIjoia3JSZmdvcHNVeTFUd05VMXloU0RMcU5EVGQ2TjV0TVpySGxtOG5MSklESSIsIm5vZGVJZCI6IjNkMzZiZjU3LTFkYjQtNDJlZi1iNzhiLWUyZDNkNGViOWM5NSJ9fSx7InR5cGUiOiJwaC1tYXAiLCJhdHRycyI6eyJpZCI6ImtyUmZnb3BzVXkxVHdOVTF5aFNETHFORFRkNk41dE1ackhsbThuTEpJREkiLCJub2RlSWQiOiI1MzE0ZWI2MS1lYTA2LTQyOGQtYWEzZi0zMDA4OWJjZmUxYjgifX0seyJ0eXBlIjoicGgtcHJvcGVydGllcyIsImF0dHJzIjp7ImlkIjoia3JSZmdvcHNVeTFUd05VMXloU0RMcU5EVGQ2TjV0TVpySGxtOG5MSklESSIsIm5vZGVJZCI6ImUwMjE1NDU5LWY0YTgtNGJjNy04NDhmLTYxODE1NzY1NzlmNyJ9fV19fV19", + "$initial_pathname": "/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$initial_browser_version": 117, + "$initial_referrer": "$direct", + "$initial_referring_domain": "$direct" + }, + "$sent_at": "2023-10-20T10:30:43.133000+00:00", + "$geoip_city_name": "Sydney", + "$geoip_country_name": "Australia", + "$geoip_country_code": "AU", + "$geoip_continent_name": "Oceania", + "$geoip_continent_code": "OC", + "$geoip_postal_code": "2000", + "$geoip_latitude": -33.8715, + "$geoip_longitude": 151.2006, + "$geoip_time_zone": "Australia/Sydney", + "$geoip_subdivision_1_code": "NSW", + "$geoip_subdivision_1_name": "New South Wales", + "$plugins_succeeded": ["GeoIP (1)"], + "$plugins_failed": [], + "$plugins_deferred": [], + "$group_3": "018a92f8-b602-0000-75de-4b9073693531", + "$group_2": "018a92f8-afff-0000-efec-ca77de39e384", + "$group_4": "cus_OdSgxxWtHOtq9g", + "$group_1": "http://localhost:8000" + }, + "timestamp": "2023-10-20T10:30:40.243000+00:00", + "uuid": null + }, + { + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "elements": [], + "elements_chain": null, + "event": "$groupidentify", + "id": "018b4ca3-1db7-7917-8e7e-ce4d6db6aac0", + "person": null, + "properties": { + "$os": "Mac OS X", + "$os_version": "10.15.7", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI#activeTab=feed&state=eyJ0eXBlIjoiZG9jIiwiY29udGVudCI6W3sidHlwZSI6ImhlYWRpbmciLCJhdHRycyI6eyJsZXZlbCI6MX0sImNvbnRlbnQiOlt7InR5cGUiOiJ0ZXh0IiwidGV4dCI6ImtyUmZnb3BzVXkxVHdOVTF5aFNETHFORFRkNk41dE1ackhsbThuTEpJREkifV19LHsidHlwZSI6InBoLXBlcnNvbi1mZWVkIiwiYXR0cnMiOnsiaGVpZ2h0IjpudWxsLCJ0aXRsZSI6bnVsbCwibm9kZUlkIjoiNmQ0ODUwNjYtZWM5OS00ODNkLThiOTgtNGQ4YTJkYzljYzRiIiwiaWQiOiJrclJmZ29wc1V5MVR3TlUxeWhTRExxTkRUZDZONXRNWnJIbG04bkxKSURJIiwiX19pbml0IjpudWxsLCJjaGlsZHJlbiI6W3sidHlwZSI6InBoLXBlcnNvbiIsImF0dHJzIjp7ImlkIjoia3JSZmdvcHNVeTFUd05VMXloU0RMcU5EVGQ2TjV0TVpySGxtOG5MSklESSIsIm5vZGVJZCI6IjNkMzZiZjU3LTFkYjQtNDJlZi1iNzhiLWUyZDNkNGViOWM5NSJ9fSx7InR5cGUiOiJwaC1tYXAiLCJhdHRycyI6eyJpZCI6ImtyUmZnb3BzVXkxVHdOVTF5aFNETHFORFRkNk41dE1ackhsbThuTEpJREkiLCJub2RlSWQiOiI1MzE0ZWI2MS1lYTA2LTQyOGQtYWEzZi0zMDA4OWJjZmUxYjgifX0seyJ0eXBlIjoicGgtcHJvcGVydGllcyIsImF0dHJzIjp7ImlkIjoia3JSZmdvcHNVeTFUd05VMXloU0RMcU5EVGQ2TjV0TVpySGxtOG5MSklESSIsIm5vZGVJZCI6ImUwMjE1NDU5LWY0YTgtNGJjNy04NDhmLTYxODE1NzY1NzlmNyJ9fV19fV19", + "$host": "localhost:8000", + "$pathname": "/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$browser_version": 117, + "$browser_language": "en-GB", + "$screen_height": 982, + "$screen_width": 1512, + "$viewport_height": 859, + "$viewport_width": 1512, + "$lib": "web", + "$lib_version": "1.84.0", + "$insert_id": "b6ktfl60jskki58x", + "$time": 1697797840.312, + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$device_id": "018a92fd-7b25-7770-a050-577e94fd148c", + "$console_log_recording_enabled_server_side": true, + "$session_recording_recorder_version_server_side": "v2", + "$autocapture_disabled_server_side": false, + "$active_feature_flags": [ + "signup-page-4.0", + "cmd-k-search", + "posthog-3000", + "funnels-cue-opt-out-7301", + "retention-breakdown", + "smoothing-interval", + "billing-limit", + "kafka-inspector", + "historical-exports-v2", + "person-on-events-enabled", + "region-select", + "ingestion-warnings-enabled", + "session-reset-on-load", + "recordings-on-feature-flags", + "auto-rollback-feature-flags", + "onboarding-v2-demo", + "feature-flag-rollout-ux", + "role-based-access", + "query_running_time", + "query-timings", + "recording-debugging", + "enable-prompts", + "feedback-scene", + "early-access-feature", + "early-access-feature-site-button", + "hedgehog-mode-debug", + "auto-redirect", + "session-recording-blob-replay", + "surveys", + "generic-signup-benefits", + "surveys-positions", + "web-analytics", + "high-frequency-batch-exports", + "exception-autocapture", + "data-warehouse", + "data-warehouse-views", + "ff-dashboard-templates", + "show-product-intro-existing-products", + "artificial-hog", + "cs-dashboards", + "product-specific-onboarding", + "redirect-signups-to-instance", + "apps-and-exports-ui", + "survey-nps-results", + "session-recording-allow-v1-snapshots", + "session-replay-cors-proxy", + "webhooks-denylist", + "surveys-site-app-deprecation", + "surveys-multiple-questions", + "surveys-results-visualizations", + "console-recording-search", + "persons-hogql-query", + "notebooks" + ], + "$feature/file-previews": false, + "$feature/signup-page-4.0": "control", + "$feature/hogql-insights": false, + "$feature/cmd-k-search": true, + "$feature/posthog-3000": true, + "$feature/funnels-cue-opt-out-7301": true, + "$feature/retention-breakdown": true, + "$feature/smoothing-interval": true, + "$feature/billing-limit": true, + "$feature/kafka-inspector": true, + "$feature/historical-exports-v2": true, + "$feature/person-on-events-enabled": true, + "$feature/region-select": true, + "$feature/ingestion-warnings-enabled": true, + "$feature/session-reset-on-load": true, + "$feature/recordings-on-feature-flags": true, + "$feature/auto-rollback-feature-flags": true, + "$feature/onboarding-v2-demo": true, + "$feature/feature-flag-rollout-ux": true, + "$feature/role-based-access": true, + "$feature/query_running_time": true, + "$feature/query-timings": true, + "$feature/recording-debugging": true, + "$feature/enable-prompts": true, + "$feature/feedback-scene": true, + "$feature/early-access-feature": true, + "$feature/early-access-feature-site-button": true, + "$feature/hedgehog-mode-debug": true, + "$feature/auto-redirect": true, + "$feature/session-recording-blob-replay": true, + "$feature/surveys": true, + "$feature/generic-signup-benefits": true, + "$feature/surveys-positions": true, + "$feature/web-analytics": true, + "$feature/high-frequency-batch-exports": true, + "$feature/exception-autocapture": true, + "$feature/data-warehouse": true, + "$feature/data-warehouse-views": true, + "$feature/ff-dashboard-templates": true, + "$feature/show-product-intro-existing-products": true, + "$feature/artificial-hog": true, + "$feature/cs-dashboards": true, + "$feature/product-specific-onboarding": true, + "$feature/redirect-signups-to-instance": true, + "$feature/apps-and-exports-ui": true, + "$feature/survey-nps-results": true, + "$feature/session-recording-allow-v1-snapshots": true, + "$feature/session-replay-cors-proxy": true, + "$feature/webhooks-denylist": true, + "$feature/surveys-site-app-deprecation": true, + "$feature/surveys-multiple-questions": true, + "$feature/surveys-results-visualizations": true, + "$feature/console-recording-search": true, + "$feature/persons-hogql-query": true, + "$feature/notebooks": true, + "$feature_flag_payloads": {}, + "realm": "hosted-clickhouse", + "email_service_available": false, + "slack_service_available": false, + "$user_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "is_demo_project": false, + "$groups": { + "project": "018a92f8-b602-0000-75de-4b9073693531", + "organization": "018a92f8-afff-0000-efec-ca77de39e384", + "customer": "cus_OdSgxxWtHOtq9g", + "instance": "http://localhost:8000" + }, + "has_billing_plan": true, + "customer_deactivated": false, + "current_total_amount_usd": "0.00", + "percentage_usage.product_analytics": 0, + "current_amount_usd.product_analytics": "0.00", + "unit_amount_usd.product_analytics": null, + "usage_limit.product_analytics": null, + "current_usage.product_analytics": 3729, + "projected_usage.product_analytics": 0, + "free_allocation.product_analytics": 0, + "percentage_usage.session_replay": 0, + "current_amount_usd.session_replay": "0.00", + "unit_amount_usd.session_replay": null, + "usage_limit.session_replay": null, + "current_usage.session_replay": 254, + "projected_usage.session_replay": 0, + "free_allocation.session_replay": 0, + "percentage_usage.feature_flags": 0, + "current_amount_usd.feature_flags": "0.00", + "unit_amount_usd.feature_flags": null, + "usage_limit.feature_flags": null, + "current_usage.feature_flags": 0, + "projected_usage.feature_flags": 0, + "free_allocation.feature_flags": 0, + "percentage_usage.integrations": 0, + "current_amount_usd.integrations": null, + "unit_amount_usd.integrations": null, + "usage_limit.integrations": 0, + "current_usage.integrations": 0, + "projected_usage.integrations": 0, + "free_allocation.integrations": 0, + "percentage_usage.platform_and_support": 0, + "current_amount_usd.platform_and_support": null, + "unit_amount_usd.platform_and_support": null, + "usage_limit.platform_and_support": 0, + "current_usage.platform_and_support": 0, + "projected_usage.platform_and_support": 0, + "free_allocation.platform_and_support": 0, + "billing_period_start": "2023-10-14T09:22:33.000Z", + "billing_period_end": "2023-11-14T09:22:33.000Z", + "$referrer": "$direct", + "$referring_domain": "$direct", + "$group_type": "instance", + "$group_key": "http://localhost:8000", + "$group_set": { + "site_url": "http://localhost:8000" + }, + "token": "phc_OWGI2wKbfi7rWDZT9wkl8uGcfe0wOGCvflLEZSMiaT0", + "$session_id": "018b4ca3-1d07-7195-8202-c8a103a9325a", + "$window_id": "018b4ca3-1d07-7195-8202-c8a2b00ad68a", + "$ip": "127.0.0.1", + "$set": { + "$os": "Mac OS X", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI#activeTab=feed&state=eyJ0eXBlIjoiZG9jIiwiY29udGVudCI6W3sidHlwZSI6ImhlYWRpbmciLCJhdHRycyI6eyJsZXZlbCI6MX0sImNvbnRlbnQiOlt7InR5cGUiOiJ0ZXh0IiwidGV4dCI6ImtyUmZnb3BzVXkxVHdOVTF5aFNETHFORFRkNk41dE1ackhsbThuTEpJREkifV19LHsidHlwZSI6InBoLXBlcnNvbi1mZWVkIiwiYXR0cnMiOnsiaGVpZ2h0IjpudWxsLCJ0aXRsZSI6bnVsbCwibm9kZUlkIjoiNmQ0ODUwNjYtZWM5OS00ODNkLThiOTgtNGQ4YTJkYzljYzRiIiwiaWQiOiJrclJmZ29wc1V5MVR3TlUxeWhTRExxTkRUZDZONXRNWnJIbG04bkxKSURJIiwiX19pbml0IjpudWxsLCJjaGlsZHJlbiI6W3sidHlwZSI6InBoLXBlcnNvbiIsImF0dHJzIjp7ImlkIjoia3JSZmdvcHNVeTFUd05VMXloU0RMcU5EVGQ2TjV0TVpySGxtOG5MSklESSIsIm5vZGVJZCI6IjNkMzZiZjU3LTFkYjQtNDJlZi1iNzhiLWUyZDNkNGViOWM5NSJ9fSx7InR5cGUiOiJwaC1tYXAiLCJhdHRycyI6eyJpZCI6ImtyUmZnb3BzVXkxVHdOVTF5aFNETHFORFRkNk41dE1ackhsbThuTEpJREkiLCJub2RlSWQiOiI1MzE0ZWI2MS1lYTA2LTQyOGQtYWEzZi0zMDA4OWJjZmUxYjgifX0seyJ0eXBlIjoicGgtcHJvcGVydGllcyIsImF0dHJzIjp7ImlkIjoia3JSZmdvcHNVeTFUd05VMXloU0RMcU5EVGQ2TjV0TVpySGxtOG5MSklESSIsIm5vZGVJZCI6ImUwMjE1NDU5LWY0YTgtNGJjNy04NDhmLTYxODE1NzY1NzlmNyJ9fV19fV19", + "$pathname": "/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$browser_version": 117, + "$referrer": "$direct", + "$referring_domain": "$direct" + }, + "$set_once": { + "$initial_os": "Mac OS X", + "$initial_browser": "Chrome", + "$initial_device_type": "Desktop", + "$initial_current_url": "http://localhost:8000/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI#activeTab=feed&state=eyJ0eXBlIjoiZG9jIiwiY29udGVudCI6W3sidHlwZSI6ImhlYWRpbmciLCJhdHRycyI6eyJsZXZlbCI6MX0sImNvbnRlbnQiOlt7InR5cGUiOiJ0ZXh0IiwidGV4dCI6ImtyUmZnb3BzVXkxVHdOVTF5aFNETHFORFRkNk41dE1ackhsbThuTEpJREkifV19LHsidHlwZSI6InBoLXBlcnNvbi1mZWVkIiwiYXR0cnMiOnsiaGVpZ2h0IjpudWxsLCJ0aXRsZSI6bnVsbCwibm9kZUlkIjoiNmQ0ODUwNjYtZWM5OS00ODNkLThiOTgtNGQ4YTJkYzljYzRiIiwiaWQiOiJrclJmZ29wc1V5MVR3TlUxeWhTRExxTkRUZDZONXRNWnJIbG04bkxKSURJIiwiX19pbml0IjpudWxsLCJjaGlsZHJlbiI6W3sidHlwZSI6InBoLXBlcnNvbiIsImF0dHJzIjp7ImlkIjoia3JSZmdvcHNVeTFUd05VMXloU0RMcU5EVGQ2TjV0TVpySGxtOG5MSklESSIsIm5vZGVJZCI6IjNkMzZiZjU3LTFkYjQtNDJlZi1iNzhiLWUyZDNkNGViOWM5NSJ9fSx7InR5cGUiOiJwaC1tYXAiLCJhdHRycyI6eyJpZCI6ImtyUmZnb3BzVXkxVHdOVTF5aFNETHFORFRkNk41dE1ackhsbThuTEpJREkiLCJub2RlSWQiOiI1MzE0ZWI2MS1lYTA2LTQyOGQtYWEzZi0zMDA4OWJjZmUxYjgifX0seyJ0eXBlIjoicGgtcHJvcGVydGllcyIsImF0dHJzIjp7ImlkIjoia3JSZmdvcHNVeTFUd05VMXloU0RMcU5EVGQ2TjV0TVpySGxtOG5MSklESSIsIm5vZGVJZCI6ImUwMjE1NDU5LWY0YTgtNGJjNy04NDhmLTYxODE1NzY1NzlmNyJ9fV19fV19", + "$initial_pathname": "/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$initial_browser_version": 117, + "$initial_referrer": "$direct", + "$initial_referring_domain": "$direct" + }, + "$sent_at": "2023-10-20T10:30:43.133000+00:00", + "$geoip_city_name": "Sydney", + "$geoip_country_name": "Australia", + "$geoip_country_code": "AU", + "$geoip_continent_name": "Oceania", + "$geoip_continent_code": "OC", + "$geoip_postal_code": "2000", + "$geoip_latitude": -33.8715, + "$geoip_longitude": 151.2006, + "$geoip_time_zone": "Australia/Sydney", + "$geoip_subdivision_1_code": "NSW", + "$geoip_subdivision_1_name": "New South Wales", + "$plugins_succeeded": ["GeoIP (1)"], + "$plugins_failed": [], + "$plugins_deferred": [], + "$group_3": "018a92f8-b602-0000-75de-4b9073693531", + "$group_2": "018a92f8-afff-0000-efec-ca77de39e384", + "$group_4": "cus_OdSgxxWtHOtq9g", + "$group_1": "http://localhost:8000" + }, + "timestamp": "2023-10-20T10:30:40.327000+00:00", + "uuid": null + }, + { + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "elements": [], + "elements_chain": null, + "event": "$feature_flag_called", + "id": "018b4ca3-1dcd-712b-befa-52f257d2144b", + "person": null, + "properties": { + "$os": "Mac OS X", + "$os_version": "10.15.7", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI#activeTab=feed&state=eyJ0eXBlIjoiZG9jIiwiY29udGVudCI6W3sidHlwZSI6ImhlYWRpbmciLCJhdHRycyI6eyJsZXZlbCI6MX0sImNvbnRlbnQiOlt7InR5cGUiOiJ0ZXh0IiwidGV4dCI6ImtyUmZnb3BzVXkxVHdOVTF5aFNETHFORFRkNk41dE1ackhsbThuTEpJREkifV19LHsidHlwZSI6InBoLXBlcnNvbi1mZWVkIiwiYXR0cnMiOnsiaGVpZ2h0IjpudWxsLCJ0aXRsZSI6bnVsbCwibm9kZUlkIjoiNmQ0ODUwNjYtZWM5OS00ODNkLThiOTgtNGQ4YTJkYzljYzRiIiwiaWQiOiJrclJmZ29wc1V5MVR3TlUxeWhTRExxTkRUZDZONXRNWnJIbG04bkxKSURJIiwiX19pbml0IjpudWxsLCJjaGlsZHJlbiI6W3sidHlwZSI6InBoLXBlcnNvbiIsImF0dHJzIjp7ImlkIjoia3JSZmdvcHNVeTFUd05VMXloU0RMcU5EVGQ2TjV0TVpySGxtOG5MSklESSIsIm5vZGVJZCI6IjNkMzZiZjU3LTFkYjQtNDJlZi1iNzhiLWUyZDNkNGViOWM5NSJ9fSx7InR5cGUiOiJwaC1tYXAiLCJhdHRycyI6eyJpZCI6ImtyUmZnb3BzVXkxVHdOVTF5aFNETHFORFRkNk41dE1ackhsbThuTEpJREkiLCJub2RlSWQiOiI1MzE0ZWI2MS1lYTA2LTQyOGQtYWEzZi0zMDA4OWJjZmUxYjgifX0seyJ0eXBlIjoicGgtcHJvcGVydGllcyIsImF0dHJzIjp7ImlkIjoia3JSZmdvcHNVeTFUd05VMXloU0RMcU5EVGQ2TjV0TVpySGxtOG5MSklESSIsIm5vZGVJZCI6ImUwMjE1NDU5LWY0YTgtNGJjNy04NDhmLTYxODE1NzY1NzlmNyJ9fV19fV19", + "$host": "localhost:8000", + "$pathname": "/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$browser_version": 117, + "$browser_language": "en-GB", + "$screen_height": 982, + "$screen_width": 1512, + "$viewport_height": 859, + "$viewport_width": 1512, + "$lib": "web", + "$lib_version": "1.84.0", + "$insert_id": "kwzuadx4g5n5ms1d", + "$time": 1697797840.334, + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$device_id": "018a92fd-7b25-7770-a050-577e94fd148c", + "$console_log_recording_enabled_server_side": true, + "$session_recording_recorder_version_server_side": "v2", + "$autocapture_disabled_server_side": false, + "$active_feature_flags": [ + "signup-page-4.0", + "cmd-k-search", + "posthog-3000", + "funnels-cue-opt-out-7301", + "retention-breakdown", + "smoothing-interval", + "billing-limit", + "kafka-inspector", + "historical-exports-v2", + "person-on-events-enabled", + "region-select", + "ingestion-warnings-enabled", + "session-reset-on-load", + "recordings-on-feature-flags", + "auto-rollback-feature-flags", + "onboarding-v2-demo", + "feature-flag-rollout-ux", + "role-based-access", + "query_running_time", + "query-timings", + "recording-debugging", + "enable-prompts", + "feedback-scene", + "early-access-feature", + "early-access-feature-site-button", + "hedgehog-mode-debug", + "auto-redirect", + "session-recording-blob-replay", + "surveys", + "generic-signup-benefits", + "surveys-positions", + "web-analytics", + "high-frequency-batch-exports", + "exception-autocapture", + "data-warehouse", + "data-warehouse-views", + "ff-dashboard-templates", + "show-product-intro-existing-products", + "artificial-hog", + "cs-dashboards", + "product-specific-onboarding", + "redirect-signups-to-instance", + "apps-and-exports-ui", + "survey-nps-results", + "session-recording-allow-v1-snapshots", + "session-replay-cors-proxy", + "webhooks-denylist", + "surveys-site-app-deprecation", + "surveys-multiple-questions", + "surveys-results-visualizations", + "console-recording-search", + "persons-hogql-query", + "notebooks" + ], + "$feature/file-previews": false, + "$feature/signup-page-4.0": "control", + "$feature/hogql-insights": false, + "$feature/cmd-k-search": true, + "$feature/posthog-3000": true, + "$feature/funnels-cue-opt-out-7301": true, + "$feature/retention-breakdown": true, + "$feature/smoothing-interval": true, + "$feature/billing-limit": true, + "$feature/kafka-inspector": true, + "$feature/historical-exports-v2": true, + "$feature/person-on-events-enabled": true, + "$feature/region-select": true, + "$feature/ingestion-warnings-enabled": true, + "$feature/session-reset-on-load": true, + "$feature/recordings-on-feature-flags": true, + "$feature/auto-rollback-feature-flags": true, + "$feature/onboarding-v2-demo": true, + "$feature/feature-flag-rollout-ux": true, + "$feature/role-based-access": true, + "$feature/query_running_time": true, + "$feature/query-timings": true, + "$feature/recording-debugging": true, + "$feature/enable-prompts": true, + "$feature/feedback-scene": true, + "$feature/early-access-feature": true, + "$feature/early-access-feature-site-button": true, + "$feature/hedgehog-mode-debug": true, + "$feature/auto-redirect": true, + "$feature/session-recording-blob-replay": true, + "$feature/surveys": true, + "$feature/generic-signup-benefits": true, + "$feature/surveys-positions": true, + "$feature/web-analytics": true, + "$feature/high-frequency-batch-exports": true, + "$feature/exception-autocapture": true, + "$feature/data-warehouse": true, + "$feature/data-warehouse-views": true, + "$feature/ff-dashboard-templates": true, + "$feature/show-product-intro-existing-products": true, + "$feature/artificial-hog": true, + "$feature/cs-dashboards": true, + "$feature/product-specific-onboarding": true, + "$feature/redirect-signups-to-instance": true, + "$feature/apps-and-exports-ui": true, + "$feature/survey-nps-results": true, + "$feature/session-recording-allow-v1-snapshots": true, + "$feature/session-replay-cors-proxy": true, + "$feature/webhooks-denylist": true, + "$feature/surveys-site-app-deprecation": true, + "$feature/surveys-multiple-questions": true, + "$feature/surveys-results-visualizations": true, + "$feature/console-recording-search": true, + "$feature/persons-hogql-query": true, + "$feature/notebooks": true, + "$feature_flag_payloads": {}, + "realm": "hosted-clickhouse", + "email_service_available": false, + "slack_service_available": false, + "$user_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "is_demo_project": false, + "$groups": { + "project": "018a92f8-b602-0000-75de-4b9073693531", + "organization": "018a92f8-afff-0000-efec-ca77de39e384", + "customer": "cus_OdSgxxWtHOtq9g", + "instance": "http://localhost:8000" + }, + "has_billing_plan": true, + "customer_deactivated": false, + "current_total_amount_usd": "0.00", + "percentage_usage.product_analytics": 0, + "current_amount_usd.product_analytics": "0.00", + "unit_amount_usd.product_analytics": null, + "usage_limit.product_analytics": null, + "current_usage.product_analytics": 3729, + "projected_usage.product_analytics": 0, + "free_allocation.product_analytics": 0, + "percentage_usage.session_replay": 0, + "current_amount_usd.session_replay": "0.00", + "unit_amount_usd.session_replay": null, + "usage_limit.session_replay": null, + "current_usage.session_replay": 254, + "projected_usage.session_replay": 0, + "free_allocation.session_replay": 0, + "percentage_usage.feature_flags": 0, + "current_amount_usd.feature_flags": "0.00", + "unit_amount_usd.feature_flags": null, + "usage_limit.feature_flags": null, + "current_usage.feature_flags": 0, + "projected_usage.feature_flags": 0, + "free_allocation.feature_flags": 0, + "percentage_usage.integrations": 0, + "current_amount_usd.integrations": null, + "unit_amount_usd.integrations": null, + "usage_limit.integrations": 0, + "current_usage.integrations": 0, + "projected_usage.integrations": 0, + "free_allocation.integrations": 0, + "percentage_usage.platform_and_support": 0, + "current_amount_usd.platform_and_support": null, + "unit_amount_usd.platform_and_support": null, + "usage_limit.platform_and_support": 0, + "current_usage.platform_and_support": 0, + "projected_usage.platform_and_support": 0, + "free_allocation.platform_and_support": 0, + "billing_period_start": "2023-10-14T09:22:33.000Z", + "billing_period_end": "2023-11-14T09:22:33.000Z", + "$referrer": "$direct", + "$referring_domain": "$direct", + "$feature_flag": "cs-dashboards", + "$feature_flag_response": true, + "token": "phc_OWGI2wKbfi7rWDZT9wkl8uGcfe0wOGCvflLEZSMiaT0", + "$session_id": "018b4ca3-1d07-7195-8202-c8a103a9325a", + "$window_id": "018b4ca3-1d07-7195-8202-c8a2b00ad68a", + "$ip": "127.0.0.1", + "$set": { + "$os": "Mac OS X", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI#activeTab=feed&state=eyJ0eXBlIjoiZG9jIiwiY29udGVudCI6W3sidHlwZSI6ImhlYWRpbmciLCJhdHRycyI6eyJsZXZlbCI6MX0sImNvbnRlbnQiOlt7InR5cGUiOiJ0ZXh0IiwidGV4dCI6ImtyUmZnb3BzVXkxVHdOVTF5aFNETHFORFRkNk41dE1ackhsbThuTEpJREkifV19LHsidHlwZSI6InBoLXBlcnNvbi1mZWVkIiwiYXR0cnMiOnsiaGVpZ2h0IjpudWxsLCJ0aXRsZSI6bnVsbCwibm9kZUlkIjoiNmQ0ODUwNjYtZWM5OS00ODNkLThiOTgtNGQ4YTJkYzljYzRiIiwiaWQiOiJrclJmZ29wc1V5MVR3TlUxeWhTRExxTkRUZDZONXRNWnJIbG04bkxKSURJIiwiX19pbml0IjpudWxsLCJjaGlsZHJlbiI6W3sidHlwZSI6InBoLXBlcnNvbiIsImF0dHJzIjp7ImlkIjoia3JSZmdvcHNVeTFUd05VMXloU0RMcU5EVGQ2TjV0TVpySGxtOG5MSklESSIsIm5vZGVJZCI6IjNkMzZiZjU3LTFkYjQtNDJlZi1iNzhiLWUyZDNkNGViOWM5NSJ9fSx7InR5cGUiOiJwaC1tYXAiLCJhdHRycyI6eyJpZCI6ImtyUmZnb3BzVXkxVHdOVTF5aFNETHFORFRkNk41dE1ackhsbThuTEpJREkiLCJub2RlSWQiOiI1MzE0ZWI2MS1lYTA2LTQyOGQtYWEzZi0zMDA4OWJjZmUxYjgifX0seyJ0eXBlIjoicGgtcHJvcGVydGllcyIsImF0dHJzIjp7ImlkIjoia3JSZmdvcHNVeTFUd05VMXloU0RMcU5EVGQ2TjV0TVpySGxtOG5MSklESSIsIm5vZGVJZCI6ImUwMjE1NDU5LWY0YTgtNGJjNy04NDhmLTYxODE1NzY1NzlmNyJ9fV19fV19", + "$pathname": "/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$browser_version": 117, + "$referrer": "$direct", + "$referring_domain": "$direct" + }, + "$set_once": { + "$initial_os": "Mac OS X", + "$initial_browser": "Chrome", + "$initial_device_type": "Desktop", + "$initial_current_url": "http://localhost:8000/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI#activeTab=feed&state=eyJ0eXBlIjoiZG9jIiwiY29udGVudCI6W3sidHlwZSI6ImhlYWRpbmciLCJhdHRycyI6eyJsZXZlbCI6MX0sImNvbnRlbnQiOlt7InR5cGUiOiJ0ZXh0IiwidGV4dCI6ImtyUmZnb3BzVXkxVHdOVTF5aFNETHFORFRkNk41dE1ackhsbThuTEpJREkifV19LHsidHlwZSI6InBoLXBlcnNvbi1mZWVkIiwiYXR0cnMiOnsiaGVpZ2h0IjpudWxsLCJ0aXRsZSI6bnVsbCwibm9kZUlkIjoiNmQ0ODUwNjYtZWM5OS00ODNkLThiOTgtNGQ4YTJkYzljYzRiIiwiaWQiOiJrclJmZ29wc1V5MVR3TlUxeWhTRExxTkRUZDZONXRNWnJIbG04bkxKSURJIiwiX19pbml0IjpudWxsLCJjaGlsZHJlbiI6W3sidHlwZSI6InBoLXBlcnNvbiIsImF0dHJzIjp7ImlkIjoia3JSZmdvcHNVeTFUd05VMXloU0RMcU5EVGQ2TjV0TVpySGxtOG5MSklESSIsIm5vZGVJZCI6IjNkMzZiZjU3LTFkYjQtNDJlZi1iNzhiLWUyZDNkNGViOWM5NSJ9fSx7InR5cGUiOiJwaC1tYXAiLCJhdHRycyI6eyJpZCI6ImtyUmZnb3BzVXkxVHdOVTF5aFNETHFORFRkNk41dE1ackhsbThuTEpJREkiLCJub2RlSWQiOiI1MzE0ZWI2MS1lYTA2LTQyOGQtYWEzZi0zMDA4OWJjZmUxYjgifX0seyJ0eXBlIjoicGgtcHJvcGVydGllcyIsImF0dHJzIjp7ImlkIjoia3JSZmdvcHNVeTFUd05VMXloU0RMcU5EVGQ2TjV0TVpySGxtOG5MSklESSIsIm5vZGVJZCI6ImUwMjE1NDU5LWY0YTgtNGJjNy04NDhmLTYxODE1NzY1NzlmNyJ9fV19fV19", + "$initial_pathname": "/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$initial_browser_version": 117, + "$initial_referrer": "$direct", + "$initial_referring_domain": "$direct" + }, + "$sent_at": "2023-10-20T10:30:43.133000+00:00", + "$geoip_city_name": "Sydney", + "$geoip_country_name": "Australia", + "$geoip_country_code": "AU", + "$geoip_continent_name": "Oceania", + "$geoip_continent_code": "OC", + "$geoip_postal_code": "2000", + "$geoip_latitude": -33.8715, + "$geoip_longitude": 151.2006, + "$geoip_time_zone": "Australia/Sydney", + "$geoip_subdivision_1_code": "NSW", + "$geoip_subdivision_1_name": "New South Wales", + "$plugins_succeeded": ["GeoIP (1)"], + "$plugins_failed": [], + "$plugins_deferred": [], + "$group_3": "018a92f8-b602-0000-75de-4b9073693531", + "$group_2": "018a92f8-afff-0000-efec-ca77de39e384", + "$group_4": "cus_OdSgxxWtHOtq9g", + "$group_1": "http://localhost:8000" + }, + "timestamp": "2023-10-20T10:30:40.350000+00:00", + "uuid": null + }, + { + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "elements": [], + "elements_chain": null, + "event": "$pageview", + "id": "018b4ca3-1dd4-79b4-9077-540e9c915f51", + "person": null, + "properties": { + "$os": "Mac OS X", + "$os_version": "10.15.7", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI#activeTab=feed&state=eyJ0eXBlIjoiZG9jIiwiY29udGVudCI6W3sidHlwZSI6ImhlYWRpbmciLCJhdHRycyI6eyJsZXZlbCI6MX0sImNvbnRlbnQiOlt7InR5cGUiOiJ0ZXh0IiwidGV4dCI6ImtyUmZnb3BzVXkxVHdOVTF5aFNETHFORFRkNk41dE1ackhsbThuTEpJREkifV19LHsidHlwZSI6InBoLXBlcnNvbi1mZWVkIiwiYXR0cnMiOnsiaGVpZ2h0IjpudWxsLCJ0aXRsZSI6bnVsbCwibm9kZUlkIjoiNmQ0ODUwNjYtZWM5OS00ODNkLThiOTgtNGQ4YTJkYzljYzRiIiwiaWQiOiJrclJmZ29wc1V5MVR3TlUxeWhTRExxTkRUZDZONXRNWnJIbG04bkxKSURJIiwiX19pbml0IjpudWxsLCJjaGlsZHJlbiI6W3sidHlwZSI6InBoLXBlcnNvbiIsImF0dHJzIjp7ImlkIjoia3JSZmdvcHNVeTFUd05VMXloU0RMcU5EVGQ2TjV0TVpySGxtOG5MSklESSIsIm5vZGVJZCI6IjNkMzZiZjU3LTFkYjQtNDJlZi1iNzhiLWUyZDNkNGViOWM5NSJ9fSx7InR5cGUiOiJwaC1tYXAiLCJhdHRycyI6eyJpZCI6ImtyUmZnb3BzVXkxVHdOVTF5aFNETHFORFRkNk41dE1ackhsbThuTEpJREkiLCJub2RlSWQiOiI1MzE0ZWI2MS1lYTA2LTQyOGQtYWEzZi0zMDA4OWJjZmUxYjgifX0seyJ0eXBlIjoicGgtcHJvcGVydGllcyIsImF0dHJzIjp7ImlkIjoia3JSZmdvcHNVeTFUd05VMXloU0RMcU5EVGQ2TjV0TVpySGxtOG5MSklESSIsIm5vZGVJZCI6ImUwMjE1NDU5LWY0YTgtNGJjNy04NDhmLTYxODE1NzY1NzlmNyJ9fV19fV19", + "$host": "localhost:8000", + "$pathname": "/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$browser_version": 117, + "$browser_language": "en-GB", + "$screen_height": 982, + "$screen_width": 1512, + "$viewport_height": 859, + "$viewport_width": 1512, + "$lib": "web", + "$lib_version": "1.84.0", + "$insert_id": "s04xofpsygbioozp", + "$time": 1697797840.344, + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$device_id": "018a92fd-7b25-7770-a050-577e94fd148c", + "$console_log_recording_enabled_server_side": true, + "$session_recording_recorder_version_server_side": "v2", + "$autocapture_disabled_server_side": false, + "$active_feature_flags": [ + "signup-page-4.0", + "cmd-k-search", + "posthog-3000", + "funnels-cue-opt-out-7301", + "retention-breakdown", + "smoothing-interval", + "billing-limit", + "kafka-inspector", + "historical-exports-v2", + "person-on-events-enabled", + "region-select", + "ingestion-warnings-enabled", + "session-reset-on-load", + "recordings-on-feature-flags", + "auto-rollback-feature-flags", + "onboarding-v2-demo", + "feature-flag-rollout-ux", + "role-based-access", + "query_running_time", + "query-timings", + "recording-debugging", + "enable-prompts", + "feedback-scene", + "early-access-feature", + "early-access-feature-site-button", + "hedgehog-mode-debug", + "auto-redirect", + "session-recording-blob-replay", + "surveys", + "generic-signup-benefits", + "surveys-positions", + "web-analytics", + "high-frequency-batch-exports", + "exception-autocapture", + "data-warehouse", + "data-warehouse-views", + "ff-dashboard-templates", + "show-product-intro-existing-products", + "artificial-hog", + "cs-dashboards", + "product-specific-onboarding", + "redirect-signups-to-instance", + "apps-and-exports-ui", + "survey-nps-results", + "session-recording-allow-v1-snapshots", + "session-replay-cors-proxy", + "webhooks-denylist", + "surveys-site-app-deprecation", + "surveys-multiple-questions", + "surveys-results-visualizations", + "console-recording-search", + "persons-hogql-query", + "notebooks" + ], + "$feature/file-previews": false, + "$feature/signup-page-4.0": "control", + "$feature/hogql-insights": false, + "$feature/cmd-k-search": true, + "$feature/posthog-3000": true, + "$feature/funnels-cue-opt-out-7301": true, + "$feature/retention-breakdown": true, + "$feature/smoothing-interval": true, + "$feature/billing-limit": true, + "$feature/kafka-inspector": true, + "$feature/historical-exports-v2": true, + "$feature/person-on-events-enabled": true, + "$feature/region-select": true, + "$feature/ingestion-warnings-enabled": true, + "$feature/session-reset-on-load": true, + "$feature/recordings-on-feature-flags": true, + "$feature/auto-rollback-feature-flags": true, + "$feature/onboarding-v2-demo": true, + "$feature/feature-flag-rollout-ux": true, + "$feature/role-based-access": true, + "$feature/query_running_time": true, + "$feature/query-timings": true, + "$feature/recording-debugging": true, + "$feature/enable-prompts": true, + "$feature/feedback-scene": true, + "$feature/early-access-feature": true, + "$feature/early-access-feature-site-button": true, + "$feature/hedgehog-mode-debug": true, + "$feature/auto-redirect": true, + "$feature/session-recording-blob-replay": true, + "$feature/surveys": true, + "$feature/generic-signup-benefits": true, + "$feature/surveys-positions": true, + "$feature/web-analytics": true, + "$feature/high-frequency-batch-exports": true, + "$feature/exception-autocapture": true, + "$feature/data-warehouse": true, + "$feature/data-warehouse-views": true, + "$feature/ff-dashboard-templates": true, + "$feature/show-product-intro-existing-products": true, + "$feature/artificial-hog": true, + "$feature/cs-dashboards": true, + "$feature/product-specific-onboarding": true, + "$feature/redirect-signups-to-instance": true, + "$feature/apps-and-exports-ui": true, + "$feature/survey-nps-results": true, + "$feature/session-recording-allow-v1-snapshots": true, + "$feature/session-replay-cors-proxy": true, + "$feature/webhooks-denylist": true, + "$feature/surveys-site-app-deprecation": true, + "$feature/surveys-multiple-questions": true, + "$feature/surveys-results-visualizations": true, + "$feature/console-recording-search": true, + "$feature/persons-hogql-query": true, + "$feature/notebooks": true, + "$feature_flag_payloads": {}, + "realm": "hosted-clickhouse", + "email_service_available": false, + "slack_service_available": false, + "$user_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "is_demo_project": false, + "$groups": { + "project": "018a92f8-b602-0000-75de-4b9073693531", + "organization": "018a92f8-afff-0000-efec-ca77de39e384", + "customer": "cus_OdSgxxWtHOtq9g", + "instance": "http://localhost:8000" + }, + "has_billing_plan": true, + "customer_deactivated": false, + "current_total_amount_usd": "0.00", + "percentage_usage.product_analytics": 0, + "current_amount_usd.product_analytics": "0.00", + "unit_amount_usd.product_analytics": null, + "usage_limit.product_analytics": null, + "current_usage.product_analytics": 3729, + "projected_usage.product_analytics": 0, + "free_allocation.product_analytics": 0, + "percentage_usage.session_replay": 0, + "current_amount_usd.session_replay": "0.00", + "unit_amount_usd.session_replay": null, + "usage_limit.session_replay": null, + "current_usage.session_replay": 254, + "projected_usage.session_replay": 0, + "free_allocation.session_replay": 0, + "percentage_usage.feature_flags": 0, + "current_amount_usd.feature_flags": "0.00", + "unit_amount_usd.feature_flags": null, + "usage_limit.feature_flags": null, + "current_usage.feature_flags": 0, + "projected_usage.feature_flags": 0, + "free_allocation.feature_flags": 0, + "percentage_usage.integrations": 0, + "current_amount_usd.integrations": null, + "unit_amount_usd.integrations": null, + "usage_limit.integrations": 0, + "current_usage.integrations": 0, + "projected_usage.integrations": 0, + "free_allocation.integrations": 0, + "percentage_usage.platform_and_support": 0, + "current_amount_usd.platform_and_support": null, + "unit_amount_usd.platform_and_support": null, + "usage_limit.platform_and_support": 0, + "current_usage.platform_and_support": 0, + "projected_usage.platform_and_support": 0, + "free_allocation.platform_and_support": 0, + "billing_period_start": "2023-10-14T09:22:33.000Z", + "billing_period_end": "2023-11-14T09:22:33.000Z", + "$referrer": "$direct", + "$referring_domain": "$direct", + "token": "phc_OWGI2wKbfi7rWDZT9wkl8uGcfe0wOGCvflLEZSMiaT0", + "$session_id": "018b4ca3-1d07-7195-8202-c8a103a9325a", + "$window_id": "018b4ca3-1d07-7195-8202-c8a2b00ad68a", + "title": "Persons \u2022 PostHog", + "$ip": "127.0.0.1", + "$set": { + "$os": "Mac OS X", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI#activeTab=feed&state=eyJ0eXBlIjoiZG9jIiwiY29udGVudCI6W3sidHlwZSI6ImhlYWRpbmciLCJhdHRycyI6eyJsZXZlbCI6MX0sImNvbnRlbnQiOlt7InR5cGUiOiJ0ZXh0IiwidGV4dCI6ImtyUmZnb3BzVXkxVHdOVTF5aFNETHFORFRkNk41dE1ackhsbThuTEpJREkifV19LHsidHlwZSI6InBoLXBlcnNvbi1mZWVkIiwiYXR0cnMiOnsiaGVpZ2h0IjpudWxsLCJ0aXRsZSI6bnVsbCwibm9kZUlkIjoiNmQ0ODUwNjYtZWM5OS00ODNkLThiOTgtNGQ4YTJkYzljYzRiIiwiaWQiOiJrclJmZ29wc1V5MVR3TlUxeWhTRExxTkRUZDZONXRNWnJIbG04bkxKSURJIiwiX19pbml0IjpudWxsLCJjaGlsZHJlbiI6W3sidHlwZSI6InBoLXBlcnNvbiIsImF0dHJzIjp7ImlkIjoia3JSZmdvcHNVeTFUd05VMXloU0RMcU5EVGQ2TjV0TVpySGxtOG5MSklESSIsIm5vZGVJZCI6IjNkMzZiZjU3LTFkYjQtNDJlZi1iNzhiLWUyZDNkNGViOWM5NSJ9fSx7InR5cGUiOiJwaC1tYXAiLCJhdHRycyI6eyJpZCI6ImtyUmZnb3BzVXkxVHdOVTF5aFNETHFORFRkNk41dE1ackhsbThuTEpJREkiLCJub2RlSWQiOiI1MzE0ZWI2MS1lYTA2LTQyOGQtYWEzZi0zMDA4OWJjZmUxYjgifX0seyJ0eXBlIjoicGgtcHJvcGVydGllcyIsImF0dHJzIjp7ImlkIjoia3JSZmdvcHNVeTFUd05VMXloU0RMcU5EVGQ2TjV0TVpySGxtOG5MSklESSIsIm5vZGVJZCI6ImUwMjE1NDU5LWY0YTgtNGJjNy04NDhmLTYxODE1NzY1NzlmNyJ9fV19fV19", + "$pathname": "/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$browser_version": 117, + "$referrer": "$direct", + "$referring_domain": "$direct" + }, + "$set_once": { + "$initial_os": "Mac OS X", + "$initial_browser": "Chrome", + "$initial_device_type": "Desktop", + "$initial_current_url": "http://localhost:8000/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI#activeTab=feed&state=eyJ0eXBlIjoiZG9jIiwiY29udGVudCI6W3sidHlwZSI6ImhlYWRpbmciLCJhdHRycyI6eyJsZXZlbCI6MX0sImNvbnRlbnQiOlt7InR5cGUiOiJ0ZXh0IiwidGV4dCI6ImtyUmZnb3BzVXkxVHdOVTF5aFNETHFORFRkNk41dE1ackhsbThuTEpJREkifV19LHsidHlwZSI6InBoLXBlcnNvbi1mZWVkIiwiYXR0cnMiOnsiaGVpZ2h0IjpudWxsLCJ0aXRsZSI6bnVsbCwibm9kZUlkIjoiNmQ0ODUwNjYtZWM5OS00ODNkLThiOTgtNGQ4YTJkYzljYzRiIiwiaWQiOiJrclJmZ29wc1V5MVR3TlUxeWhTRExxTkRUZDZONXRNWnJIbG04bkxKSURJIiwiX19pbml0IjpudWxsLCJjaGlsZHJlbiI6W3sidHlwZSI6InBoLXBlcnNvbiIsImF0dHJzIjp7ImlkIjoia3JSZmdvcHNVeTFUd05VMXloU0RMcU5EVGQ2TjV0TVpySGxtOG5MSklESSIsIm5vZGVJZCI6IjNkMzZiZjU3LTFkYjQtNDJlZi1iNzhiLWUyZDNkNGViOWM5NSJ9fSx7InR5cGUiOiJwaC1tYXAiLCJhdHRycyI6eyJpZCI6ImtyUmZnb3BzVXkxVHdOVTF5aFNETHFORFRkNk41dE1ackhsbThuTEpJREkiLCJub2RlSWQiOiI1MzE0ZWI2MS1lYTA2LTQyOGQtYWEzZi0zMDA4OWJjZmUxYjgifX0seyJ0eXBlIjoicGgtcHJvcGVydGllcyIsImF0dHJzIjp7ImlkIjoia3JSZmdvcHNVeTFUd05VMXloU0RMcU5EVGQ2TjV0TVpySGxtOG5MSklESSIsIm5vZGVJZCI6ImUwMjE1NDU5LWY0YTgtNGJjNy04NDhmLTYxODE1NzY1NzlmNyJ9fV19fV19", + "$initial_pathname": "/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$initial_browser_version": 117, + "$initial_referrer": "$direct", + "$initial_referring_domain": "$direct" + }, + "$sent_at": "2023-10-20T10:30:43.133000+00:00", + "$geoip_city_name": "Sydney", + "$geoip_country_name": "Australia", + "$geoip_country_code": "AU", + "$geoip_continent_name": "Oceania", + "$geoip_continent_code": "OC", + "$geoip_postal_code": "2000", + "$geoip_latitude": -33.8715, + "$geoip_longitude": 151.2006, + "$geoip_time_zone": "Australia/Sydney", + "$geoip_subdivision_1_code": "NSW", + "$geoip_subdivision_1_name": "New South Wales", + "$plugins_succeeded": ["GeoIP (1)"], + "$plugins_failed": [], + "$plugins_deferred": [], + "$group_3": "018a92f8-b602-0000-75de-4b9073693531", + "$group_2": "018a92f8-afff-0000-efec-ca77de39e384", + "$group_4": "cus_OdSgxxWtHOtq9g", + "$group_1": "http://localhost:8000" + }, + "timestamp": "2023-10-20T10:30:40.359000+00:00", + "uuid": null + }, + { + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "elements": [], + "elements_chain": null, + "event": "query completed", + "id": "018b4ca3-1f42-700e-8bef-a6ad468cff87", + "person": null, + "properties": { + "$os": "Mac OS X", + "$os_version": "10.15.7", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI#activeTab=feed&state=eyJ0eXBlIjoiZG9jIiwiY29udGVudCI6W3sidHlwZSI6ImhlYWRpbmciLCJhdHRycyI6eyJsZXZlbCI6MX0sImNvbnRlbnQiOlt7InR5cGUiOiJ0ZXh0IiwidGV4dCI6ImtyUmZnb3BzVXkxVHdOVTF5aFNETHFORFRkNk41dE1ackhsbThuTEpJREkifV19LHsidHlwZSI6InBoLXBlcnNvbi1mZWVkIiwiYXR0cnMiOnsiaGVpZ2h0IjpudWxsLCJ0aXRsZSI6bnVsbCwibm9kZUlkIjoiNmQ0ODUwNjYtZWM5OS00ODNkLThiOTgtNGQ4YTJkYzljYzRiIiwiaWQiOiJrclJmZ29wc1V5MVR3TlUxeWhTRExxTkRUZDZONXRNWnJIbG04bkxKSURJIiwiX19pbml0IjpudWxsLCJjaGlsZHJlbiI6W3sidHlwZSI6InBoLXBlcnNvbiIsImF0dHJzIjp7ImlkIjoia3JSZmdvcHNVeTFUd05VMXloU0RMcU5EVGQ2TjV0TVpySGxtOG5MSklESSIsIm5vZGVJZCI6IjNkMzZiZjU3LTFkYjQtNDJlZi1iNzhiLWUyZDNkNGViOWM5NSJ9fSx7InR5cGUiOiJwaC1tYXAiLCJhdHRycyI6eyJpZCI6ImtyUmZnb3BzVXkxVHdOVTF5aFNETHFORFRkNk41dE1ackhsbThuTEpJREkiLCJub2RlSWQiOiI1MzE0ZWI2MS1lYTA2LTQyOGQtYWEzZi0zMDA4OWJjZmUxYjgifX0seyJ0eXBlIjoicGgtcHJvcGVydGllcyIsImF0dHJzIjp7ImlkIjoia3JSZmdvcHNVeTFUd05VMXloU0RMcU5EVGQ2TjV0TVpySGxtOG5MSklESSIsIm5vZGVJZCI6ImUwMjE1NDU5LWY0YTgtNGJjNy04NDhmLTYxODE1NzY1NzlmNyJ9fV19fV19", + "$host": "localhost:8000", + "$pathname": "/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$browser_version": 117, + "$browser_language": "en-GB", + "$screen_height": 982, + "$screen_width": 1512, + "$viewport_height": 859, + "$viewport_width": 1512, + "$lib": "web", + "$lib_version": "1.84.0", + "$insert_id": "cksjqjsjm4csoovv", + "$time": 1697797840.706, + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$device_id": "018a92fd-7b25-7770-a050-577e94fd148c", + "$console_log_recording_enabled_server_side": true, + "$session_recording_recorder_version_server_side": "v2", + "$autocapture_disabled_server_side": false, + "$active_feature_flags": [ + "signup-page-4.0", + "cmd-k-search", + "posthog-3000", + "funnels-cue-opt-out-7301", + "retention-breakdown", + "smoothing-interval", + "billing-limit", + "kafka-inspector", + "historical-exports-v2", + "person-on-events-enabled", + "region-select", + "ingestion-warnings-enabled", + "session-reset-on-load", + "recordings-on-feature-flags", + "auto-rollback-feature-flags", + "onboarding-v2-demo", + "feature-flag-rollout-ux", + "role-based-access", + "query_running_time", + "query-timings", + "recording-debugging", + "enable-prompts", + "feedback-scene", + "early-access-feature", + "early-access-feature-site-button", + "hedgehog-mode-debug", + "auto-redirect", + "session-recording-blob-replay", + "surveys", + "generic-signup-benefits", + "surveys-positions", + "web-analytics", + "high-frequency-batch-exports", + "exception-autocapture", + "data-warehouse", + "data-warehouse-views", + "ff-dashboard-templates", + "show-product-intro-existing-products", + "artificial-hog", + "cs-dashboards", + "product-specific-onboarding", + "redirect-signups-to-instance", + "apps-and-exports-ui", + "survey-nps-results", + "session-recording-allow-v1-snapshots", + "session-replay-cors-proxy", + "webhooks-denylist", + "surveys-site-app-deprecation", + "surveys-multiple-questions", + "surveys-results-visualizations", + "console-recording-search", + "persons-hogql-query", + "notebooks" + ], + "$feature/file-previews": false, + "$feature/signup-page-4.0": "control", + "$feature/hogql-insights": false, + "$feature/cmd-k-search": true, + "$feature/posthog-3000": true, + "$feature/funnels-cue-opt-out-7301": true, + "$feature/retention-breakdown": true, + "$feature/smoothing-interval": true, + "$feature/billing-limit": true, + "$feature/kafka-inspector": true, + "$feature/historical-exports-v2": true, + "$feature/person-on-events-enabled": true, + "$feature/region-select": true, + "$feature/ingestion-warnings-enabled": true, + "$feature/session-reset-on-load": true, + "$feature/recordings-on-feature-flags": true, + "$feature/auto-rollback-feature-flags": true, + "$feature/onboarding-v2-demo": true, + "$feature/feature-flag-rollout-ux": true, + "$feature/role-based-access": true, + "$feature/query_running_time": true, + "$feature/query-timings": true, + "$feature/recording-debugging": true, + "$feature/enable-prompts": true, + "$feature/feedback-scene": true, + "$feature/early-access-feature": true, + "$feature/early-access-feature-site-button": true, + "$feature/hedgehog-mode-debug": true, + "$feature/auto-redirect": true, + "$feature/session-recording-blob-replay": true, + "$feature/surveys": true, + "$feature/generic-signup-benefits": true, + "$feature/surveys-positions": true, + "$feature/web-analytics": true, + "$feature/high-frequency-batch-exports": true, + "$feature/exception-autocapture": true, + "$feature/data-warehouse": true, + "$feature/data-warehouse-views": true, + "$feature/ff-dashboard-templates": true, + "$feature/show-product-intro-existing-products": true, + "$feature/artificial-hog": true, + "$feature/cs-dashboards": true, + "$feature/product-specific-onboarding": true, + "$feature/redirect-signups-to-instance": true, + "$feature/apps-and-exports-ui": true, + "$feature/survey-nps-results": true, + "$feature/session-recording-allow-v1-snapshots": true, + "$feature/session-replay-cors-proxy": true, + "$feature/webhooks-denylist": true, + "$feature/surveys-site-app-deprecation": true, + "$feature/surveys-multiple-questions": true, + "$feature/surveys-results-visualizations": true, + "$feature/console-recording-search": true, + "$feature/persons-hogql-query": true, + "$feature/notebooks": true, + "$feature_flag_payloads": {}, + "realm": "hosted-clickhouse", + "email_service_available": false, + "slack_service_available": false, + "$user_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "is_demo_project": false, + "$groups": { + "project": "018a92f8-b602-0000-75de-4b9073693531", + "organization": "018a92f8-afff-0000-efec-ca77de39e384", + "customer": "cus_OdSgxxWtHOtq9g", + "instance": "http://localhost:8000" + }, + "has_billing_plan": true, + "customer_deactivated": false, + "current_total_amount_usd": "0.00", + "percentage_usage.product_analytics": 0, + "current_amount_usd.product_analytics": "0.00", + "unit_amount_usd.product_analytics": null, + "usage_limit.product_analytics": null, + "current_usage.product_analytics": 3729, + "projected_usage.product_analytics": 0, + "free_allocation.product_analytics": 0, + "percentage_usage.session_replay": 0, + "current_amount_usd.session_replay": "0.00", + "unit_amount_usd.session_replay": null, + "usage_limit.session_replay": null, + "current_usage.session_replay": 254, + "projected_usage.session_replay": 0, + "free_allocation.session_replay": 0, + "percentage_usage.feature_flags": 0, + "current_amount_usd.feature_flags": "0.00", + "unit_amount_usd.feature_flags": null, + "usage_limit.feature_flags": null, + "current_usage.feature_flags": 0, + "projected_usage.feature_flags": 0, + "free_allocation.feature_flags": 0, + "percentage_usage.integrations": 0, + "current_amount_usd.integrations": null, + "unit_amount_usd.integrations": null, + "usage_limit.integrations": 0, + "current_usage.integrations": 0, + "projected_usage.integrations": 0, + "free_allocation.integrations": 0, + "percentage_usage.platform_and_support": 0, + "current_amount_usd.platform_and_support": null, + "unit_amount_usd.platform_and_support": null, + "usage_limit.platform_and_support": 0, + "current_usage.platform_and_support": 0, + "projected_usage.platform_and_support": 0, + "free_allocation.platform_and_support": 0, + "billing_period_start": "2023-10-14T09:22:33.000Z", + "billing_period_end": "2023-11-14T09:22:33.000Z", + "$referrer": "$direct", + "$referring_domain": "$direct", + "query": { + "kind": "HogQLQuery", + "query": "select id, groupArray(pdi.distinct_id) as distinct_ids, properties, is_identified, created_at from persons where pdi.distinct_id={distinct_id} group by id, properties, is_identified, created_at", + "values": { + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI" + } + }, + "duration": 516.8999999761581, + "clickhouse_sql": "SELECT persons.id, groupArray(persons__pdi.distinct_id) AS distinct_ids, persons.properties, persons.is_identified, toTimeZone(persons.created_at, %(hogql_val_0)s) FROM (SELECT person.id, person.properties AS properties, person.is_identified AS is_identified, person.created_at AS created_at FROM person WHERE and(equals(person.team_id, 1), ifNull(in(tuple(person.id, person.version), (SELECT person.id, max(person.version) AS version FROM person WHERE equals(person.team_id, 1) GROUP BY person.id HAVING ifNull(equals(argMax(person.is_deleted, person.version), 0), 0))), 0)) SETTINGS optimize_aggregation_in_order=1) AS persons INNER JOIN (SELECT argMax(person_distinct_id2.person_id, person_distinct_id2.version) AS person_id, person_distinct_id2.distinct_id AS distinct_id FROM person_distinct_id2 WHERE equals(person_distinct_id2.team_id, 1) GROUP BY person_distinct_id2.distinct_id HAVING ifNull(equals(argMax(person_distinct_id2.is_deleted, person_distinct_id2.version), 0), 0)) AS persons__pdi ON equals(persons.id, persons__pdi.person_id) WHERE ifNull(equals(persons__pdi.distinct_id, %(hogql_val_1)s), 0) GROUP BY persons.id, persons.properties, persons.is_identified, toTimeZone(persons.created_at, %(hogql_val_2)s) LIMIT 100 SETTINGS readonly=2, max_execution_time=60, allow_experimental_object_type=1", + "token": "phc_OWGI2wKbfi7rWDZT9wkl8uGcfe0wOGCvflLEZSMiaT0", + "$session_id": "018b4ca3-1d07-7195-8202-c8a103a9325a", + "$window_id": "018b4ca3-1d07-7195-8202-c8a2b00ad68a", + "$ip": "127.0.0.1", + "$set": { + "$os": "Mac OS X", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI#activeTab=feed&state=eyJ0eXBlIjoiZG9jIiwiY29udGVudCI6W3sidHlwZSI6ImhlYWRpbmciLCJhdHRycyI6eyJsZXZlbCI6MX0sImNvbnRlbnQiOlt7InR5cGUiOiJ0ZXh0IiwidGV4dCI6ImtyUmZnb3BzVXkxVHdOVTF5aFNETHFORFRkNk41dE1ackhsbThuTEpJREkifV19LHsidHlwZSI6InBoLXBlcnNvbi1mZWVkIiwiYXR0cnMiOnsiaGVpZ2h0IjpudWxsLCJ0aXRsZSI6bnVsbCwibm9kZUlkIjoiNmQ0ODUwNjYtZWM5OS00ODNkLThiOTgtNGQ4YTJkYzljYzRiIiwiaWQiOiJrclJmZ29wc1V5MVR3TlUxeWhTRExxTkRUZDZONXRNWnJIbG04bkxKSURJIiwiX19pbml0IjpudWxsLCJjaGlsZHJlbiI6W3sidHlwZSI6InBoLXBlcnNvbiIsImF0dHJzIjp7ImlkIjoia3JSZmdvcHNVeTFUd05VMXloU0RMcU5EVGQ2TjV0TVpySGxtOG5MSklESSIsIm5vZGVJZCI6IjNkMzZiZjU3LTFkYjQtNDJlZi1iNzhiLWUyZDNkNGViOWM5NSJ9fSx7InR5cGUiOiJwaC1tYXAiLCJhdHRycyI6eyJpZCI6ImtyUmZnb3BzVXkxVHdOVTF5aFNETHFORFRkNk41dE1ackhsbThuTEpJREkiLCJub2RlSWQiOiI1MzE0ZWI2MS1lYTA2LTQyOGQtYWEzZi0zMDA4OWJjZmUxYjgifX0seyJ0eXBlIjoicGgtcHJvcGVydGllcyIsImF0dHJzIjp7ImlkIjoia3JSZmdvcHNVeTFUd05VMXloU0RMcU5EVGQ2TjV0TVpySGxtOG5MSklESSIsIm5vZGVJZCI6ImUwMjE1NDU5LWY0YTgtNGJjNy04NDhmLTYxODE1NzY1NzlmNyJ9fV19fV19", + "$pathname": "/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$browser_version": 117, + "$referrer": "$direct", + "$referring_domain": "$direct" + }, + "$set_once": { + "$initial_os": "Mac OS X", + "$initial_browser": "Chrome", + "$initial_device_type": "Desktop", + "$initial_current_url": "http://localhost:8000/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI#activeTab=feed&state=eyJ0eXBlIjoiZG9jIiwiY29udGVudCI6W3sidHlwZSI6ImhlYWRpbmciLCJhdHRycyI6eyJsZXZlbCI6MX0sImNvbnRlbnQiOlt7InR5cGUiOiJ0ZXh0IiwidGV4dCI6ImtyUmZnb3BzVXkxVHdOVTF5aFNETHFORFRkNk41dE1ackhsbThuTEpJREkifV19LHsidHlwZSI6InBoLXBlcnNvbi1mZWVkIiwiYXR0cnMiOnsiaGVpZ2h0IjpudWxsLCJ0aXRsZSI6bnVsbCwibm9kZUlkIjoiNmQ0ODUwNjYtZWM5OS00ODNkLThiOTgtNGQ4YTJkYzljYzRiIiwiaWQiOiJrclJmZ29wc1V5MVR3TlUxeWhTRExxTkRUZDZONXRNWnJIbG04bkxKSURJIiwiX19pbml0IjpudWxsLCJjaGlsZHJlbiI6W3sidHlwZSI6InBoLXBlcnNvbiIsImF0dHJzIjp7ImlkIjoia3JSZmdvcHNVeTFUd05VMXloU0RMcU5EVGQ2TjV0TVpySGxtOG5MSklESSIsIm5vZGVJZCI6IjNkMzZiZjU3LTFkYjQtNDJlZi1iNzhiLWUyZDNkNGViOWM5NSJ9fSx7InR5cGUiOiJwaC1tYXAiLCJhdHRycyI6eyJpZCI6ImtyUmZnb3BzVXkxVHdOVTF5aFNETHFORFRkNk41dE1ackhsbThuTEpJREkiLCJub2RlSWQiOiI1MzE0ZWI2MS1lYTA2LTQyOGQtYWEzZi0zMDA4OWJjZmUxYjgifX0seyJ0eXBlIjoicGgtcHJvcGVydGllcyIsImF0dHJzIjp7ImlkIjoia3JSZmdvcHNVeTFUd05VMXloU0RMcU5EVGQ2TjV0TVpySGxtOG5MSklESSIsIm5vZGVJZCI6ImUwMjE1NDU5LWY0YTgtNGJjNy04NDhmLTYxODE1NzY1NzlmNyJ9fV19fV19", + "$initial_pathname": "/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$initial_browser_version": 117, + "$initial_referrer": "$direct", + "$initial_referring_domain": "$direct" + }, + "$sent_at": "2023-10-20T10:30:43.133000+00:00", + "$geoip_city_name": "Sydney", + "$geoip_country_name": "Australia", + "$geoip_country_code": "AU", + "$geoip_continent_name": "Oceania", + "$geoip_continent_code": "OC", + "$geoip_postal_code": "2000", + "$geoip_latitude": -33.8715, + "$geoip_longitude": 151.2006, + "$geoip_time_zone": "Australia/Sydney", + "$geoip_subdivision_1_code": "NSW", + "$geoip_subdivision_1_name": "New South Wales", + "$plugins_succeeded": ["GeoIP (1)"], + "$plugins_failed": [], + "$plugins_deferred": [], + "$group_3": "018a92f8-b602-0000-75de-4b9073693531", + "$group_2": "018a92f8-afff-0000-efec-ca77de39e384", + "$group_4": "cus_OdSgxxWtHOtq9g", + "$group_1": "http://localhost:8000" + }, + "timestamp": "2023-10-20T10:30:40.721000+00:00", + "uuid": null + }, + { + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "elements": [], + "elements_chain": null, + "event": "$feature_flag_called", + "id": "018b4ca3-1f4d-7bfd-a091-0f8858fcc9ca", + "person": null, + "properties": { + "$os": "Mac OS X", + "$os_version": "10.15.7", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI#activeTab=feed&state=eyJ0eXBlIjoiZG9jIiwiY29udGVudCI6W3sidHlwZSI6ImhlYWRpbmciLCJhdHRycyI6eyJsZXZlbCI6MX0sImNvbnRlbnQiOlt7InR5cGUiOiJ0ZXh0IiwidGV4dCI6ImtyUmZnb3BzVXkxVHdOVTF5aFNETHFORFRkNk41dE1ackhsbThuTEpJREkifV19LHsidHlwZSI6InBoLXBlcnNvbi1mZWVkIiwiYXR0cnMiOnsiaGVpZ2h0IjpudWxsLCJ0aXRsZSI6bnVsbCwibm9kZUlkIjoiNmQ0ODUwNjYtZWM5OS00ODNkLThiOTgtNGQ4YTJkYzljYzRiIiwiaWQiOiJrclJmZ29wc1V5MVR3TlUxeWhTRExxTkRUZDZONXRNWnJIbG04bkxKSURJIiwiX19pbml0IjpudWxsLCJjaGlsZHJlbiI6W3sidHlwZSI6InBoLXBlcnNvbiIsImF0dHJzIjp7ImlkIjoia3JSZmdvcHNVeTFUd05VMXloU0RMcU5EVGQ2TjV0TVpySGxtOG5MSklESSIsIm5vZGVJZCI6IjNkMzZiZjU3LTFkYjQtNDJlZi1iNzhiLWUyZDNkNGViOWM5NSJ9fSx7InR5cGUiOiJwaC1tYXAiLCJhdHRycyI6eyJpZCI6ImtyUmZnb3BzVXkxVHdOVTF5aFNETHFORFRkNk41dE1ackhsbThuTEpJREkiLCJub2RlSWQiOiI1MzE0ZWI2MS1lYTA2LTQyOGQtYWEzZi0zMDA4OWJjZmUxYjgifX0seyJ0eXBlIjoicGgtcHJvcGVydGllcyIsImF0dHJzIjp7ImlkIjoia3JSZmdvcHNVeTFUd05VMXloU0RMcU5EVGQ2TjV0TVpySGxtOG5MSklESSIsIm5vZGVJZCI6ImUwMjE1NDU5LWY0YTgtNGJjNy04NDhmLTYxODE1NzY1NzlmNyJ9fV19fV19", + "$host": "localhost:8000", + "$pathname": "/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$browser_version": 117, + "$browser_language": "en-GB", + "$screen_height": 982, + "$screen_width": 1512, + "$viewport_height": 859, + "$viewport_width": 1512, + "$lib": "web", + "$lib_version": "1.84.0", + "$insert_id": "c1x6pz53d6fb5uqp", + "$time": 1697797840.718, + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$device_id": "018a92fd-7b25-7770-a050-577e94fd148c", + "$console_log_recording_enabled_server_side": true, + "$session_recording_recorder_version_server_side": "v2", + "$autocapture_disabled_server_side": false, + "$active_feature_flags": [ + "signup-page-4.0", + "cmd-k-search", + "posthog-3000", + "funnels-cue-opt-out-7301", + "retention-breakdown", + "smoothing-interval", + "billing-limit", + "kafka-inspector", + "historical-exports-v2", + "person-on-events-enabled", + "region-select", + "ingestion-warnings-enabled", + "session-reset-on-load", + "recordings-on-feature-flags", + "auto-rollback-feature-flags", + "onboarding-v2-demo", + "feature-flag-rollout-ux", + "role-based-access", + "query_running_time", + "query-timings", + "recording-debugging", + "enable-prompts", + "feedback-scene", + "early-access-feature", + "early-access-feature-site-button", + "hedgehog-mode-debug", + "auto-redirect", + "session-recording-blob-replay", + "surveys", + "generic-signup-benefits", + "surveys-positions", + "web-analytics", + "high-frequency-batch-exports", + "exception-autocapture", + "data-warehouse", + "data-warehouse-views", + "ff-dashboard-templates", + "show-product-intro-existing-products", + "artificial-hog", + "cs-dashboards", + "product-specific-onboarding", + "redirect-signups-to-instance", + "apps-and-exports-ui", + "survey-nps-results", + "session-recording-allow-v1-snapshots", + "session-replay-cors-proxy", + "webhooks-denylist", + "surveys-site-app-deprecation", + "surveys-multiple-questions", + "surveys-results-visualizations", + "console-recording-search", + "persons-hogql-query", + "notebooks" + ], + "$feature/file-previews": false, + "$feature/signup-page-4.0": "control", + "$feature/hogql-insights": false, + "$feature/cmd-k-search": true, + "$feature/posthog-3000": true, + "$feature/funnels-cue-opt-out-7301": true, + "$feature/retention-breakdown": true, + "$feature/smoothing-interval": true, + "$feature/billing-limit": true, + "$feature/kafka-inspector": true, + "$feature/historical-exports-v2": true, + "$feature/person-on-events-enabled": true, + "$feature/region-select": true, + "$feature/ingestion-warnings-enabled": true, + "$feature/session-reset-on-load": true, + "$feature/recordings-on-feature-flags": true, + "$feature/auto-rollback-feature-flags": true, + "$feature/onboarding-v2-demo": true, + "$feature/feature-flag-rollout-ux": true, + "$feature/role-based-access": true, + "$feature/query_running_time": true, + "$feature/query-timings": true, + "$feature/recording-debugging": true, + "$feature/enable-prompts": true, + "$feature/feedback-scene": true, + "$feature/early-access-feature": true, + "$feature/early-access-feature-site-button": true, + "$feature/hedgehog-mode-debug": true, + "$feature/auto-redirect": true, + "$feature/session-recording-blob-replay": true, + "$feature/surveys": true, + "$feature/generic-signup-benefits": true, + "$feature/surveys-positions": true, + "$feature/web-analytics": true, + "$feature/high-frequency-batch-exports": true, + "$feature/exception-autocapture": true, + "$feature/data-warehouse": true, + "$feature/data-warehouse-views": true, + "$feature/ff-dashboard-templates": true, + "$feature/show-product-intro-existing-products": true, + "$feature/artificial-hog": true, + "$feature/cs-dashboards": true, + "$feature/product-specific-onboarding": true, + "$feature/redirect-signups-to-instance": true, + "$feature/apps-and-exports-ui": true, + "$feature/survey-nps-results": true, + "$feature/session-recording-allow-v1-snapshots": true, + "$feature/session-replay-cors-proxy": true, + "$feature/webhooks-denylist": true, + "$feature/surveys-site-app-deprecation": true, + "$feature/surveys-multiple-questions": true, + "$feature/surveys-results-visualizations": true, + "$feature/console-recording-search": true, + "$feature/persons-hogql-query": true, + "$feature/notebooks": true, + "$feature_flag_payloads": {}, + "realm": "hosted-clickhouse", + "email_service_available": false, + "slack_service_available": false, + "$user_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "is_demo_project": false, + "$groups": { + "project": "018a92f8-b602-0000-75de-4b9073693531", + "organization": "018a92f8-afff-0000-efec-ca77de39e384", + "customer": "cus_OdSgxxWtHOtq9g", + "instance": "http://localhost:8000" + }, + "has_billing_plan": true, + "customer_deactivated": false, + "current_total_amount_usd": "0.00", + "percentage_usage.product_analytics": 0, + "current_amount_usd.product_analytics": "0.00", + "unit_amount_usd.product_analytics": null, + "usage_limit.product_analytics": null, + "current_usage.product_analytics": 3729, + "projected_usage.product_analytics": 0, + "free_allocation.product_analytics": 0, + "percentage_usage.session_replay": 0, + "current_amount_usd.session_replay": "0.00", + "unit_amount_usd.session_replay": null, + "usage_limit.session_replay": null, + "current_usage.session_replay": 254, + "projected_usage.session_replay": 0, + "free_allocation.session_replay": 0, + "percentage_usage.feature_flags": 0, + "current_amount_usd.feature_flags": "0.00", + "unit_amount_usd.feature_flags": null, + "usage_limit.feature_flags": null, + "current_usage.feature_flags": 0, + "projected_usage.feature_flags": 0, + "free_allocation.feature_flags": 0, + "percentage_usage.integrations": 0, + "current_amount_usd.integrations": null, + "unit_amount_usd.integrations": null, + "usage_limit.integrations": 0, + "current_usage.integrations": 0, + "projected_usage.integrations": 0, + "free_allocation.integrations": 0, + "percentage_usage.platform_and_support": 0, + "current_amount_usd.platform_and_support": null, + "unit_amount_usd.platform_and_support": null, + "usage_limit.platform_and_support": 0, + "current_usage.platform_and_support": 0, + "projected_usage.platform_and_support": 0, + "free_allocation.platform_and_support": 0, + "billing_period_start": "2023-10-14T09:22:33.000Z", + "billing_period_end": "2023-11-14T09:22:33.000Z", + "$referrer": "$direct", + "$referring_domain": "$direct", + "$feature_flag": "debug-react-renders", + "$feature_flag_response": false, + "token": "phc_OWGI2wKbfi7rWDZT9wkl8uGcfe0wOGCvflLEZSMiaT0", + "$session_id": "018b4ca3-1d07-7195-8202-c8a103a9325a", + "$window_id": "018b4ca3-1d07-7195-8202-c8a2b00ad68a", + "$ip": "127.0.0.1", + "$set": { + "$os": "Mac OS X", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI#activeTab=feed&state=eyJ0eXBlIjoiZG9jIiwiY29udGVudCI6W3sidHlwZSI6ImhlYWRpbmciLCJhdHRycyI6eyJsZXZlbCI6MX0sImNvbnRlbnQiOlt7InR5cGUiOiJ0ZXh0IiwidGV4dCI6ImtyUmZnb3BzVXkxVHdOVTF5aFNETHFORFRkNk41dE1ackhsbThuTEpJREkifV19LHsidHlwZSI6InBoLXBlcnNvbi1mZWVkIiwiYXR0cnMiOnsiaGVpZ2h0IjpudWxsLCJ0aXRsZSI6bnVsbCwibm9kZUlkIjoiNmQ0ODUwNjYtZWM5OS00ODNkLThiOTgtNGQ4YTJkYzljYzRiIiwiaWQiOiJrclJmZ29wc1V5MVR3TlUxeWhTRExxTkRUZDZONXRNWnJIbG04bkxKSURJIiwiX19pbml0IjpudWxsLCJjaGlsZHJlbiI6W3sidHlwZSI6InBoLXBlcnNvbiIsImF0dHJzIjp7ImlkIjoia3JSZmdvcHNVeTFUd05VMXloU0RMcU5EVGQ2TjV0TVpySGxtOG5MSklESSIsIm5vZGVJZCI6IjNkMzZiZjU3LTFkYjQtNDJlZi1iNzhiLWUyZDNkNGViOWM5NSJ9fSx7InR5cGUiOiJwaC1tYXAiLCJhdHRycyI6eyJpZCI6ImtyUmZnb3BzVXkxVHdOVTF5aFNETHFORFRkNk41dE1ackhsbThuTEpJREkiLCJub2RlSWQiOiI1MzE0ZWI2MS1lYTA2LTQyOGQtYWEzZi0zMDA4OWJjZmUxYjgifX0seyJ0eXBlIjoicGgtcHJvcGVydGllcyIsImF0dHJzIjp7ImlkIjoia3JSZmdvcHNVeTFUd05VMXloU0RMcU5EVGQ2TjV0TVpySGxtOG5MSklESSIsIm5vZGVJZCI6ImUwMjE1NDU5LWY0YTgtNGJjNy04NDhmLTYxODE1NzY1NzlmNyJ9fV19fV19", + "$pathname": "/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$browser_version": 117, + "$referrer": "$direct", + "$referring_domain": "$direct" + }, + "$set_once": { + "$initial_os": "Mac OS X", + "$initial_browser": "Chrome", + "$initial_device_type": "Desktop", + "$initial_current_url": "http://localhost:8000/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI#activeTab=feed&state=eyJ0eXBlIjoiZG9jIiwiY29udGVudCI6W3sidHlwZSI6ImhlYWRpbmciLCJhdHRycyI6eyJsZXZlbCI6MX0sImNvbnRlbnQiOlt7InR5cGUiOiJ0ZXh0IiwidGV4dCI6ImtyUmZnb3BzVXkxVHdOVTF5aFNETHFORFRkNk41dE1ackhsbThuTEpJREkifV19LHsidHlwZSI6InBoLXBlcnNvbi1mZWVkIiwiYXR0cnMiOnsiaGVpZ2h0IjpudWxsLCJ0aXRsZSI6bnVsbCwibm9kZUlkIjoiNmQ0ODUwNjYtZWM5OS00ODNkLThiOTgtNGQ4YTJkYzljYzRiIiwiaWQiOiJrclJmZ29wc1V5MVR3TlUxeWhTRExxTkRUZDZONXRNWnJIbG04bkxKSURJIiwiX19pbml0IjpudWxsLCJjaGlsZHJlbiI6W3sidHlwZSI6InBoLXBlcnNvbiIsImF0dHJzIjp7ImlkIjoia3JSZmdvcHNVeTFUd05VMXloU0RMcU5EVGQ2TjV0TVpySGxtOG5MSklESSIsIm5vZGVJZCI6IjNkMzZiZjU3LTFkYjQtNDJlZi1iNzhiLWUyZDNkNGViOWM5NSJ9fSx7InR5cGUiOiJwaC1tYXAiLCJhdHRycyI6eyJpZCI6ImtyUmZnb3BzVXkxVHdOVTF5aFNETHFORFRkNk41dE1ackhsbThuTEpJREkiLCJub2RlSWQiOiI1MzE0ZWI2MS1lYTA2LTQyOGQtYWEzZi0zMDA4OWJjZmUxYjgifX0seyJ0eXBlIjoicGgtcHJvcGVydGllcyIsImF0dHJzIjp7ImlkIjoia3JSZmdvcHNVeTFUd05VMXloU0RMcU5EVGQ2TjV0TVpySGxtOG5MSklESSIsIm5vZGVJZCI6ImUwMjE1NDU5LWY0YTgtNGJjNy04NDhmLTYxODE1NzY1NzlmNyJ9fV19fV19", + "$initial_pathname": "/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$initial_browser_version": 117, + "$initial_referrer": "$direct", + "$initial_referring_domain": "$direct" + }, + "$sent_at": "2023-10-20T10:30:43.133000+00:00", + "$geoip_city_name": "Sydney", + "$geoip_country_name": "Australia", + "$geoip_country_code": "AU", + "$geoip_continent_name": "Oceania", + "$geoip_continent_code": "OC", + "$geoip_postal_code": "2000", + "$geoip_latitude": -33.8715, + "$geoip_longitude": 151.2006, + "$geoip_time_zone": "Australia/Sydney", + "$geoip_subdivision_1_code": "NSW", + "$geoip_subdivision_1_name": "New South Wales", + "$plugins_succeeded": ["GeoIP (1)"], + "$plugins_failed": [], + "$plugins_deferred": [], + "$group_3": "018a92f8-b602-0000-75de-4b9073693531", + "$group_2": "018a92f8-afff-0000-efec-ca77de39e384", + "$group_4": "cus_OdSgxxWtHOtq9g", + "$group_1": "http://localhost:8000" + }, + "timestamp": "2023-10-20T10:30:40.733000+00:00", + "uuid": null + }, + { + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "elements": [], + "elements_chain": null, + "event": "$feature_flag_called", + "id": "018b4ca3-204e-7df2-a8b4-fe15ee87036d", + "person": null, + "properties": { + "$os": "Mac OS X", + "$os_version": "10.15.7", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI#activeTab=feed&state=eyJ0eXBlIjoiZG9jIiwiY29udGVudCI6W3sidHlwZSI6ImhlYWRpbmciLCJhdHRycyI6eyJsZXZlbCI6MX0sImNvbnRlbnQiOlt7InR5cGUiOiJ0ZXh0IiwidGV4dCI6ImtyUmZnb3BzVXkxVHdOVTF5aFNETHFORFRkNk41dE1ackhsbThuTEpJREkifV19LHsidHlwZSI6InBoLXBlcnNvbi1mZWVkIiwiYXR0cnMiOnsiaGVpZ2h0IjpudWxsLCJ0aXRsZSI6bnVsbCwibm9kZUlkIjoiNmQ0ODUwNjYtZWM5OS00ODNkLThiOTgtNGQ4YTJkYzljYzRiIiwiaWQiOiJrclJmZ29wc1V5MVR3TlUxeWhTRExxTkRUZDZONXRNWnJIbG04bkxKSURJIiwiX19pbml0IjpudWxsLCJjaGlsZHJlbiI6W3sidHlwZSI6InBoLXBlcnNvbiIsImF0dHJzIjp7ImlkIjoia3JSZmdvcHNVeTFUd05VMXloU0RMcU5EVGQ2TjV0TVpySGxtOG5MSklESSIsIm5vZGVJZCI6IjNkMzZiZjU3LTFkYjQtNDJlZi1iNzhiLWUyZDNkNGViOWM5NSJ9fSx7InR5cGUiOiJwaC1tYXAiLCJhdHRycyI6eyJpZCI6ImtyUmZnb3BzVXkxVHdOVTF5aFNETHFORFRkNk41dE1ackhsbThuTEpJREkiLCJub2RlSWQiOiI1MzE0ZWI2MS1lYTA2LTQyOGQtYWEzZi0zMDA4OWJjZmUxYjgifX0seyJ0eXBlIjoicGgtcHJvcGVydGllcyIsImF0dHJzIjp7ImlkIjoia3JSZmdvcHNVeTFUd05VMXloU0RMcU5EVGQ2TjV0TVpySGxtOG5MSklESSIsIm5vZGVJZCI6ImUwMjE1NDU5LWY0YTgtNGJjNy04NDhmLTYxODE1NzY1NzlmNyJ9fV19fV19", + "$host": "localhost:8000", + "$pathname": "/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$browser_version": 117, + "$browser_language": "en-GB", + "$screen_height": 982, + "$screen_width": 1512, + "$viewport_height": 859, + "$viewport_width": 1512, + "$lib": "web", + "$lib_version": "1.84.0", + "$insert_id": "37mvoi5i4r6lfyx3", + "$time": 1697797840.976, + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$device_id": "018a92fd-7b25-7770-a050-577e94fd148c", + "$console_log_recording_enabled_server_side": true, + "$session_recording_recorder_version_server_side": "v2", + "$autocapture_disabled_server_side": false, + "$active_feature_flags": [ + "signup-page-4.0", + "cmd-k-search", + "posthog-3000", + "funnels-cue-opt-out-7301", + "retention-breakdown", + "smoothing-interval", + "billing-limit", + "kafka-inspector", + "historical-exports-v2", + "person-on-events-enabled", + "region-select", + "ingestion-warnings-enabled", + "session-reset-on-load", + "recordings-on-feature-flags", + "auto-rollback-feature-flags", + "onboarding-v2-demo", + "feature-flag-rollout-ux", + "role-based-access", + "query_running_time", + "query-timings", + "recording-debugging", + "enable-prompts", + "feedback-scene", + "early-access-feature", + "early-access-feature-site-button", + "hedgehog-mode-debug", + "auto-redirect", + "session-recording-blob-replay", + "surveys", + "generic-signup-benefits", + "surveys-positions", + "web-analytics", + "high-frequency-batch-exports", + "exception-autocapture", + "data-warehouse", + "data-warehouse-views", + "ff-dashboard-templates", + "show-product-intro-existing-products", + "artificial-hog", + "cs-dashboards", + "product-specific-onboarding", + "redirect-signups-to-instance", + "apps-and-exports-ui", + "survey-nps-results", + "session-recording-allow-v1-snapshots", + "session-replay-cors-proxy", + "webhooks-denylist", + "surveys-site-app-deprecation", + "surveys-multiple-questions", + "surveys-results-visualizations", + "console-recording-search", + "persons-hogql-query", + "notebooks" + ], + "$feature/file-previews": false, + "$feature/signup-page-4.0": "control", + "$feature/hogql-insights": false, + "$feature/cmd-k-search": true, + "$feature/posthog-3000": true, + "$feature/funnels-cue-opt-out-7301": true, + "$feature/retention-breakdown": true, + "$feature/smoothing-interval": true, + "$feature/billing-limit": true, + "$feature/kafka-inspector": true, + "$feature/historical-exports-v2": true, + "$feature/person-on-events-enabled": true, + "$feature/region-select": true, + "$feature/ingestion-warnings-enabled": true, + "$feature/session-reset-on-load": true, + "$feature/recordings-on-feature-flags": true, + "$feature/auto-rollback-feature-flags": true, + "$feature/onboarding-v2-demo": true, + "$feature/feature-flag-rollout-ux": true, + "$feature/role-based-access": true, + "$feature/query_running_time": true, + "$feature/query-timings": true, + "$feature/recording-debugging": true, + "$feature/enable-prompts": true, + "$feature/feedback-scene": true, + "$feature/early-access-feature": true, + "$feature/early-access-feature-site-button": true, + "$feature/hedgehog-mode-debug": true, + "$feature/auto-redirect": true, + "$feature/session-recording-blob-replay": true, + "$feature/surveys": true, + "$feature/generic-signup-benefits": true, + "$feature/surveys-positions": true, + "$feature/web-analytics": true, + "$feature/high-frequency-batch-exports": true, + "$feature/exception-autocapture": true, + "$feature/data-warehouse": true, + "$feature/data-warehouse-views": true, + "$feature/ff-dashboard-templates": true, + "$feature/show-product-intro-existing-products": true, + "$feature/artificial-hog": true, + "$feature/cs-dashboards": true, + "$feature/product-specific-onboarding": true, + "$feature/redirect-signups-to-instance": true, + "$feature/apps-and-exports-ui": true, + "$feature/survey-nps-results": true, + "$feature/session-recording-allow-v1-snapshots": true, + "$feature/session-replay-cors-proxy": true, + "$feature/webhooks-denylist": true, + "$feature/surveys-site-app-deprecation": true, + "$feature/surveys-multiple-questions": true, + "$feature/surveys-results-visualizations": true, + "$feature/console-recording-search": true, + "$feature/persons-hogql-query": true, + "$feature/notebooks": true, + "$feature_flag_payloads": {}, + "realm": "hosted-clickhouse", + "email_service_available": false, + "slack_service_available": false, + "$user_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "is_demo_project": false, + "$groups": { + "project": "018a92f8-b602-0000-75de-4b9073693531", + "organization": "018a92f8-afff-0000-efec-ca77de39e384", + "customer": "cus_OdSgxxWtHOtq9g", + "instance": "http://localhost:8000" + }, + "has_billing_plan": true, + "customer_deactivated": false, + "current_total_amount_usd": "0.00", + "percentage_usage.product_analytics": 0, + "current_amount_usd.product_analytics": "0.00", + "unit_amount_usd.product_analytics": null, + "usage_limit.product_analytics": null, + "current_usage.product_analytics": 3729, + "projected_usage.product_analytics": 0, + "free_allocation.product_analytics": 0, + "percentage_usage.session_replay": 0, + "current_amount_usd.session_replay": "0.00", + "unit_amount_usd.session_replay": null, + "usage_limit.session_replay": null, + "current_usage.session_replay": 254, + "projected_usage.session_replay": 0, + "free_allocation.session_replay": 0, + "percentage_usage.feature_flags": 0, + "current_amount_usd.feature_flags": "0.00", + "unit_amount_usd.feature_flags": null, + "usage_limit.feature_flags": null, + "current_usage.feature_flags": 0, + "projected_usage.feature_flags": 0, + "free_allocation.feature_flags": 0, + "percentage_usage.integrations": 0, + "current_amount_usd.integrations": null, + "unit_amount_usd.integrations": null, + "usage_limit.integrations": 0, + "current_usage.integrations": 0, + "projected_usage.integrations": 0, + "free_allocation.integrations": 0, + "percentage_usage.platform_and_support": 0, + "current_amount_usd.platform_and_support": null, + "unit_amount_usd.platform_and_support": null, + "usage_limit.platform_and_support": 0, + "current_usage.platform_and_support": 0, + "projected_usage.platform_and_support": 0, + "free_allocation.platform_and_support": 0, + "billing_period_start": "2023-10-14T09:22:33.000Z", + "billing_period_end": "2023-11-14T09:22:33.000Z", + "$referrer": "$direct", + "$referring_domain": "$direct", + "$feature_flag": "hogql-insights", + "$feature_flag_response": false, + "token": "phc_OWGI2wKbfi7rWDZT9wkl8uGcfe0wOGCvflLEZSMiaT0", + "$session_id": "018b4ca3-1d07-7195-8202-c8a103a9325a", + "$window_id": "018b4ca3-1d07-7195-8202-c8a2b00ad68a", + "$ip": "127.0.0.1", + "$set": { + "$os": "Mac OS X", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI#activeTab=feed&state=eyJ0eXBlIjoiZG9jIiwiY29udGVudCI6W3sidHlwZSI6ImhlYWRpbmciLCJhdHRycyI6eyJsZXZlbCI6MX0sImNvbnRlbnQiOlt7InR5cGUiOiJ0ZXh0IiwidGV4dCI6ImtyUmZnb3BzVXkxVHdOVTF5aFNETHFORFRkNk41dE1ackhsbThuTEpJREkifV19LHsidHlwZSI6InBoLXBlcnNvbi1mZWVkIiwiYXR0cnMiOnsiaGVpZ2h0IjpudWxsLCJ0aXRsZSI6bnVsbCwibm9kZUlkIjoiNmQ0ODUwNjYtZWM5OS00ODNkLThiOTgtNGQ4YTJkYzljYzRiIiwiaWQiOiJrclJmZ29wc1V5MVR3TlUxeWhTRExxTkRUZDZONXRNWnJIbG04bkxKSURJIiwiX19pbml0IjpudWxsLCJjaGlsZHJlbiI6W3sidHlwZSI6InBoLXBlcnNvbiIsImF0dHJzIjp7ImlkIjoia3JSZmdvcHNVeTFUd05VMXloU0RMcU5EVGQ2TjV0TVpySGxtOG5MSklESSIsIm5vZGVJZCI6IjNkMzZiZjU3LTFkYjQtNDJlZi1iNzhiLWUyZDNkNGViOWM5NSJ9fSx7InR5cGUiOiJwaC1tYXAiLCJhdHRycyI6eyJpZCI6ImtyUmZnb3BzVXkxVHdOVTF5aFNETHFORFRkNk41dE1ackhsbThuTEpJREkiLCJub2RlSWQiOiI1MzE0ZWI2MS1lYTA2LTQyOGQtYWEzZi0zMDA4OWJjZmUxYjgifX0seyJ0eXBlIjoicGgtcHJvcGVydGllcyIsImF0dHJzIjp7ImlkIjoia3JSZmdvcHNVeTFUd05VMXloU0RMcU5EVGQ2TjV0TVpySGxtOG5MSklESSIsIm5vZGVJZCI6ImUwMjE1NDU5LWY0YTgtNGJjNy04NDhmLTYxODE1NzY1NzlmNyJ9fV19fV19", + "$pathname": "/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$browser_version": 117, + "$referrer": "$direct", + "$referring_domain": "$direct" + }, + "$set_once": { + "$initial_os": "Mac OS X", + "$initial_browser": "Chrome", + "$initial_device_type": "Desktop", + "$initial_current_url": "http://localhost:8000/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI#activeTab=feed&state=eyJ0eXBlIjoiZG9jIiwiY29udGVudCI6W3sidHlwZSI6ImhlYWRpbmciLCJhdHRycyI6eyJsZXZlbCI6MX0sImNvbnRlbnQiOlt7InR5cGUiOiJ0ZXh0IiwidGV4dCI6ImtyUmZnb3BzVXkxVHdOVTF5aFNETHFORFRkNk41dE1ackhsbThuTEpJREkifV19LHsidHlwZSI6InBoLXBlcnNvbi1mZWVkIiwiYXR0cnMiOnsiaGVpZ2h0IjpudWxsLCJ0aXRsZSI6bnVsbCwibm9kZUlkIjoiNmQ0ODUwNjYtZWM5OS00ODNkLThiOTgtNGQ4YTJkYzljYzRiIiwiaWQiOiJrclJmZ29wc1V5MVR3TlUxeWhTRExxTkRUZDZONXRNWnJIbG04bkxKSURJIiwiX19pbml0IjpudWxsLCJjaGlsZHJlbiI6W3sidHlwZSI6InBoLXBlcnNvbiIsImF0dHJzIjp7ImlkIjoia3JSZmdvcHNVeTFUd05VMXloU0RMcU5EVGQ2TjV0TVpySGxtOG5MSklESSIsIm5vZGVJZCI6IjNkMzZiZjU3LTFkYjQtNDJlZi1iNzhiLWUyZDNkNGViOWM5NSJ9fSx7InR5cGUiOiJwaC1tYXAiLCJhdHRycyI6eyJpZCI6ImtyUmZnb3BzVXkxVHdOVTF5aFNETHFORFRkNk41dE1ackhsbThuTEpJREkiLCJub2RlSWQiOiI1MzE0ZWI2MS1lYTA2LTQyOGQtYWEzZi0zMDA4OWJjZmUxYjgifX0seyJ0eXBlIjoicGgtcHJvcGVydGllcyIsImF0dHJzIjp7ImlkIjoia3JSZmdvcHNVeTFUd05VMXloU0RMcU5EVGQ2TjV0TVpySGxtOG5MSklESSIsIm5vZGVJZCI6ImUwMjE1NDU5LWY0YTgtNGJjNy04NDhmLTYxODE1NzY1NzlmNyJ9fV19fV19", + "$initial_pathname": "/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$initial_browser_version": 117, + "$initial_referrer": "$direct", + "$initial_referring_domain": "$direct" + }, + "$sent_at": "2023-10-20T10:30:43.133000+00:00", + "$geoip_city_name": "Sydney", + "$geoip_country_name": "Australia", + "$geoip_country_code": "AU", + "$geoip_continent_name": "Oceania", + "$geoip_continent_code": "OC", + "$geoip_postal_code": "2000", + "$geoip_latitude": -33.8715, + "$geoip_longitude": 151.2006, + "$geoip_time_zone": "Australia/Sydney", + "$geoip_subdivision_1_code": "NSW", + "$geoip_subdivision_1_name": "New South Wales", + "$plugins_succeeded": ["GeoIP (1)"], + "$plugins_failed": [], + "$plugins_deferred": [], + "$group_3": "018a92f8-b602-0000-75de-4b9073693531", + "$group_2": "018a92f8-afff-0000-efec-ca77de39e384", + "$group_4": "cus_OdSgxxWtHOtq9g", + "$group_1": "http://localhost:8000" + }, + "timestamp": "2023-10-20T10:30:40.991000+00:00", + "uuid": null + }, + { + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "elements": [], + "elements_chain": null, + "event": "person viewed", + "id": "018b4ca3-2139-7a8e-ac11-02e2850ecabb", + "person": null, + "properties": { + "$os": "Mac OS X", + "$os_version": "10.15.7", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI#activeTab=feed&state=eyJ0eXBlIjoiZG9jIiwiY29udGVudCI6W3sidHlwZSI6ImhlYWRpbmciLCJhdHRycyI6eyJsZXZlbCI6MX0sImNvbnRlbnQiOlt7InR5cGUiOiJ0ZXh0IiwidGV4dCI6ImtyUmZnb3BzVXkxVHdOVTF5aFNETHFORFRkNk41dE1ackhsbThuTEpJREkifV19LHsidHlwZSI6InBoLXBlcnNvbi1mZWVkIiwiYXR0cnMiOnsiaGVpZ2h0IjpudWxsLCJ0aXRsZSI6bnVsbCwibm9kZUlkIjoiNmQ0ODUwNjYtZWM5OS00ODNkLThiOTgtNGQ4YTJkYzljYzRiIiwiaWQiOiJrclJmZ29wc1V5MVR3TlUxeWhTRExxTkRUZDZONXRNWnJIbG04bkxKSURJIiwiX19pbml0IjpudWxsLCJjaGlsZHJlbiI6W3sidHlwZSI6InBoLXBlcnNvbiIsImF0dHJzIjp7ImlkIjoia3JSZmdvcHNVeTFUd05VMXloU0RMcU5EVGQ2TjV0TVpySGxtOG5MSklESSIsIm5vZGVJZCI6IjNkMzZiZjU3LTFkYjQtNDJlZi1iNzhiLWUyZDNkNGViOWM5NSJ9fSx7InR5cGUiOiJwaC1tYXAiLCJhdHRycyI6eyJpZCI6ImtyUmZnb3BzVXkxVHdOVTF5aFNETHFORFRkNk41dE1ackhsbThuTEpJREkiLCJub2RlSWQiOiI1MzE0ZWI2MS1lYTA2LTQyOGQtYWEzZi0zMDA4OWJjZmUxYjgifX0seyJ0eXBlIjoicGgtcHJvcGVydGllcyIsImF0dHJzIjp7ImlkIjoia3JSZmdvcHNVeTFUd05VMXloU0RMcU5EVGQ2TjV0TVpySGxtOG5MSklESSIsIm5vZGVJZCI6ImUwMjE1NDU5LWY0YTgtNGJjNy04NDhmLTYxODE1NzY1NzlmNyJ9fV19fV19", + "$host": "localhost:8000", + "$pathname": "/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$browser_version": 117, + "$browser_language": "en-GB", + "$screen_height": 982, + "$screen_width": 1512, + "$viewport_height": 859, + "$viewport_width": 1512, + "$lib": "web", + "$lib_version": "1.84.0", + "$insert_id": "fgp2uq9geh5d7kkq", + "$time": 1697797841.209, + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$device_id": "018a92fd-7b25-7770-a050-577e94fd148c", + "$console_log_recording_enabled_server_side": true, + "$session_recording_recorder_version_server_side": "v2", + "$autocapture_disabled_server_side": false, + "$active_feature_flags": [ + "signup-page-4.0", + "cmd-k-search", + "posthog-3000", + "funnels-cue-opt-out-7301", + "retention-breakdown", + "smoothing-interval", + "billing-limit", + "kafka-inspector", + "historical-exports-v2", + "person-on-events-enabled", + "region-select", + "ingestion-warnings-enabled", + "session-reset-on-load", + "recordings-on-feature-flags", + "auto-rollback-feature-flags", + "onboarding-v2-demo", + "feature-flag-rollout-ux", + "role-based-access", + "query_running_time", + "query-timings", + "recording-debugging", + "enable-prompts", + "feedback-scene", + "early-access-feature", + "early-access-feature-site-button", + "hedgehog-mode-debug", + "auto-redirect", + "session-recording-blob-replay", + "surveys", + "generic-signup-benefits", + "surveys-positions", + "web-analytics", + "high-frequency-batch-exports", + "exception-autocapture", + "data-warehouse", + "data-warehouse-views", + "ff-dashboard-templates", + "show-product-intro-existing-products", + "artificial-hog", + "cs-dashboards", + "product-specific-onboarding", + "redirect-signups-to-instance", + "apps-and-exports-ui", + "survey-nps-results", + "session-recording-allow-v1-snapshots", + "session-replay-cors-proxy", + "webhooks-denylist", + "surveys-site-app-deprecation", + "surveys-multiple-questions", + "surveys-results-visualizations", + "console-recording-search", + "persons-hogql-query", + "notebooks" + ], + "$feature/file-previews": false, + "$feature/signup-page-4.0": "control", + "$feature/hogql-insights": false, + "$feature/cmd-k-search": true, + "$feature/posthog-3000": true, + "$feature/funnels-cue-opt-out-7301": true, + "$feature/retention-breakdown": true, + "$feature/smoothing-interval": true, + "$feature/billing-limit": true, + "$feature/kafka-inspector": true, + "$feature/historical-exports-v2": true, + "$feature/person-on-events-enabled": true, + "$feature/region-select": true, + "$feature/ingestion-warnings-enabled": true, + "$feature/session-reset-on-load": true, + "$feature/recordings-on-feature-flags": true, + "$feature/auto-rollback-feature-flags": true, + "$feature/onboarding-v2-demo": true, + "$feature/feature-flag-rollout-ux": true, + "$feature/role-based-access": true, + "$feature/query_running_time": true, + "$feature/query-timings": true, + "$feature/recording-debugging": true, + "$feature/enable-prompts": true, + "$feature/feedback-scene": true, + "$feature/early-access-feature": true, + "$feature/early-access-feature-site-button": true, + "$feature/hedgehog-mode-debug": true, + "$feature/auto-redirect": true, + "$feature/session-recording-blob-replay": true, + "$feature/surveys": true, + "$feature/generic-signup-benefits": true, + "$feature/surveys-positions": true, + "$feature/web-analytics": true, + "$feature/high-frequency-batch-exports": true, + "$feature/exception-autocapture": true, + "$feature/data-warehouse": true, + "$feature/data-warehouse-views": true, + "$feature/ff-dashboard-templates": true, + "$feature/show-product-intro-existing-products": true, + "$feature/artificial-hog": true, + "$feature/cs-dashboards": true, + "$feature/product-specific-onboarding": true, + "$feature/redirect-signups-to-instance": true, + "$feature/apps-and-exports-ui": true, + "$feature/survey-nps-results": true, + "$feature/session-recording-allow-v1-snapshots": true, + "$feature/session-replay-cors-proxy": true, + "$feature/webhooks-denylist": true, + "$feature/surveys-site-app-deprecation": true, + "$feature/surveys-multiple-questions": true, + "$feature/surveys-results-visualizations": true, + "$feature/console-recording-search": true, + "$feature/persons-hogql-query": true, + "$feature/notebooks": true, + "$feature_flag_payloads": {}, + "realm": "hosted-clickhouse", + "email_service_available": false, + "slack_service_available": false, + "$user_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "is_demo_project": false, + "$groups": { + "project": "018a92f8-b602-0000-75de-4b9073693531", + "organization": "018a92f8-afff-0000-efec-ca77de39e384", + "customer": "cus_OdSgxxWtHOtq9g", + "instance": "http://localhost:8000" + }, + "has_billing_plan": true, + "customer_deactivated": false, + "current_total_amount_usd": "0.00", + "percentage_usage.product_analytics": 0, + "current_amount_usd.product_analytics": "0.00", + "unit_amount_usd.product_analytics": null, + "usage_limit.product_analytics": null, + "current_usage.product_analytics": 3729, + "projected_usage.product_analytics": 0, + "free_allocation.product_analytics": 0, + "percentage_usage.session_replay": 0, + "current_amount_usd.session_replay": "0.00", + "unit_amount_usd.session_replay": null, + "usage_limit.session_replay": null, + "current_usage.session_replay": 254, + "projected_usage.session_replay": 0, + "free_allocation.session_replay": 0, + "percentage_usage.feature_flags": 0, + "current_amount_usd.feature_flags": "0.00", + "unit_amount_usd.feature_flags": null, + "usage_limit.feature_flags": null, + "current_usage.feature_flags": 0, + "projected_usage.feature_flags": 0, + "free_allocation.feature_flags": 0, + "percentage_usage.integrations": 0, + "current_amount_usd.integrations": null, + "unit_amount_usd.integrations": null, + "usage_limit.integrations": 0, + "current_usage.integrations": 0, + "projected_usage.integrations": 0, + "free_allocation.integrations": 0, + "percentage_usage.platform_and_support": 0, + "current_amount_usd.platform_and_support": null, + "unit_amount_usd.platform_and_support": null, + "usage_limit.platform_and_support": 0, + "current_usage.platform_and_support": 0, + "projected_usage.platform_and_support": 0, + "free_allocation.platform_and_support": 0, + "billing_period_start": "2023-10-14T09:22:33.000Z", + "billing_period_end": "2023-11-14T09:22:33.000Z", + "$referrer": "$direct", + "$referring_domain": "$direct", + "properties_count": 40, + "has_email": true, + "has_name": false, + "custom_properties_count": 15, + "posthog_properties_count": 25, + "token": "phc_OWGI2wKbfi7rWDZT9wkl8uGcfe0wOGCvflLEZSMiaT0", + "$session_id": "018b4ca3-1d07-7195-8202-c8a103a9325a", + "$window_id": "018b4ca3-1d07-7195-8202-c8a2b00ad68a", + "$ip": "127.0.0.1", + "$set": { + "$os": "Mac OS X", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI#activeTab=feed&state=eyJ0eXBlIjoiZG9jIiwiY29udGVudCI6W3sidHlwZSI6ImhlYWRpbmciLCJhdHRycyI6eyJsZXZlbCI6MX0sImNvbnRlbnQiOlt7InR5cGUiOiJ0ZXh0IiwidGV4dCI6ImtyUmZnb3BzVXkxVHdOVTF5aFNETHFORFRkNk41dE1ackhsbThuTEpJREkifV19LHsidHlwZSI6InBoLXBlcnNvbi1mZWVkIiwiYXR0cnMiOnsiaGVpZ2h0IjpudWxsLCJ0aXRsZSI6bnVsbCwibm9kZUlkIjoiNmQ0ODUwNjYtZWM5OS00ODNkLThiOTgtNGQ4YTJkYzljYzRiIiwiaWQiOiJrclJmZ29wc1V5MVR3TlUxeWhTRExxTkRUZDZONXRNWnJIbG04bkxKSURJIiwiX19pbml0IjpudWxsLCJjaGlsZHJlbiI6W3sidHlwZSI6InBoLXBlcnNvbiIsImF0dHJzIjp7ImlkIjoia3JSZmdvcHNVeTFUd05VMXloU0RMcU5EVGQ2TjV0TVpySGxtOG5MSklESSIsIm5vZGVJZCI6IjNkMzZiZjU3LTFkYjQtNDJlZi1iNzhiLWUyZDNkNGViOWM5NSJ9fSx7InR5cGUiOiJwaC1tYXAiLCJhdHRycyI6eyJpZCI6ImtyUmZnb3BzVXkxVHdOVTF5aFNETHFORFRkNk41dE1ackhsbThuTEpJREkiLCJub2RlSWQiOiI1MzE0ZWI2MS1lYTA2LTQyOGQtYWEzZi0zMDA4OWJjZmUxYjgifX0seyJ0eXBlIjoicGgtcHJvcGVydGllcyIsImF0dHJzIjp7ImlkIjoia3JSZmdvcHNVeTFUd05VMXloU0RMcU5EVGQ2TjV0TVpySGxtOG5MSklESSIsIm5vZGVJZCI6ImUwMjE1NDU5LWY0YTgtNGJjNy04NDhmLTYxODE1NzY1NzlmNyJ9fV19fV19", + "$pathname": "/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$browser_version": 117, + "$referrer": "$direct", + "$referring_domain": "$direct" + }, + "$set_once": { + "$initial_os": "Mac OS X", + "$initial_browser": "Chrome", + "$initial_device_type": "Desktop", + "$initial_current_url": "http://localhost:8000/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI#activeTab=feed&state=eyJ0eXBlIjoiZG9jIiwiY29udGVudCI6W3sidHlwZSI6ImhlYWRpbmciLCJhdHRycyI6eyJsZXZlbCI6MX0sImNvbnRlbnQiOlt7InR5cGUiOiJ0ZXh0IiwidGV4dCI6ImtyUmZnb3BzVXkxVHdOVTF5aFNETHFORFRkNk41dE1ackhsbThuTEpJREkifV19LHsidHlwZSI6InBoLXBlcnNvbi1mZWVkIiwiYXR0cnMiOnsiaGVpZ2h0IjpudWxsLCJ0aXRsZSI6bnVsbCwibm9kZUlkIjoiNmQ0ODUwNjYtZWM5OS00ODNkLThiOTgtNGQ4YTJkYzljYzRiIiwiaWQiOiJrclJmZ29wc1V5MVR3TlUxeWhTRExxTkRUZDZONXRNWnJIbG04bkxKSURJIiwiX19pbml0IjpudWxsLCJjaGlsZHJlbiI6W3sidHlwZSI6InBoLXBlcnNvbiIsImF0dHJzIjp7ImlkIjoia3JSZmdvcHNVeTFUd05VMXloU0RMcU5EVGQ2TjV0TVpySGxtOG5MSklESSIsIm5vZGVJZCI6IjNkMzZiZjU3LTFkYjQtNDJlZi1iNzhiLWUyZDNkNGViOWM5NSJ9fSx7InR5cGUiOiJwaC1tYXAiLCJhdHRycyI6eyJpZCI6ImtyUmZnb3BzVXkxVHdOVTF5aFNETHFORFRkNk41dE1ackhsbThuTEpJREkiLCJub2RlSWQiOiI1MzE0ZWI2MS1lYTA2LTQyOGQtYWEzZi0zMDA4OWJjZmUxYjgifX0seyJ0eXBlIjoicGgtcHJvcGVydGllcyIsImF0dHJzIjp7ImlkIjoia3JSZmdvcHNVeTFUd05VMXloU0RMcU5EVGQ2TjV0TVpySGxtOG5MSklESSIsIm5vZGVJZCI6ImUwMjE1NDU5LWY0YTgtNGJjNy04NDhmLTYxODE1NzY1NzlmNyJ9fV19fV19", + "$initial_pathname": "/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$initial_browser_version": 117, + "$initial_referrer": "$direct", + "$initial_referring_domain": "$direct" + }, + "$sent_at": "2023-10-20T10:30:43.133000+00:00", + "$geoip_city_name": "Sydney", + "$geoip_country_name": "Australia", + "$geoip_country_code": "AU", + "$geoip_continent_name": "Oceania", + "$geoip_continent_code": "OC", + "$geoip_postal_code": "2000", + "$geoip_latitude": -33.8715, + "$geoip_longitude": 151.2006, + "$geoip_time_zone": "Australia/Sydney", + "$geoip_subdivision_1_code": "NSW", + "$geoip_subdivision_1_name": "New South Wales", + "$plugins_succeeded": ["GeoIP (1)"], + "$plugins_failed": [], + "$plugins_deferred": [], + "$group_3": "018a92f8-b602-0000-75de-4b9073693531", + "$group_2": "018a92f8-afff-0000-efec-ca77de39e384", + "$group_4": "cus_OdSgxxWtHOtq9g", + "$group_1": "http://localhost:8000" + }, + "timestamp": "2023-10-20T10:30:41.224000+00:00", + "uuid": null + }, + { + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "elements": [], + "elements_chain": null, + "event": "query completed", + "id": "018b4ca3-22e7-7fee-803e-8461e96d4eeb", + "person": null, + "properties": { + "$os": "Mac OS X", + "$os_version": "10.15.7", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI#activeTab=feed&state=eyJ0eXBlIjoiZG9jIiwiY29udGVudCI6W3sidHlwZSI6ImhlYWRpbmciLCJhdHRycyI6eyJsZXZlbCI6MX0sImNvbnRlbnQiOlt7InR5cGUiOiJ0ZXh0IiwidGV4dCI6ImtyUmZnb3BzVXkxVHdOVTF5aFNETHFORFRkNk41dE1ackhsbThuTEpJREkifV19LHsidHlwZSI6InBoLXBlcnNvbi1mZWVkIiwiYXR0cnMiOnsiaGVpZ2h0IjpudWxsLCJ0aXRsZSI6bnVsbCwibm9kZUlkIjoiNmQ0ODUwNjYtZWM5OS00ODNkLThiOTgtNGQ4YTJkYzljYzRiIiwiaWQiOiJrclJmZ29wc1V5MVR3TlUxeWhTRExxTkRUZDZONXRNWnJIbG04bkxKSURJIiwiX19pbml0IjpudWxsLCJjaGlsZHJlbiI6W3sidHlwZSI6InBoLXBlcnNvbiIsImF0dHJzIjp7ImlkIjoia3JSZmdvcHNVeTFUd05VMXloU0RMcU5EVGQ2TjV0TVpySGxtOG5MSklESSIsIm5vZGVJZCI6IjNkMzZiZjU3LTFkYjQtNDJlZi1iNzhiLWUyZDNkNGViOWM5NSJ9fSx7InR5cGUiOiJwaC1tYXAiLCJhdHRycyI6eyJpZCI6ImtyUmZnb3BzVXkxVHdOVTF5aFNETHFORFRkNk41dE1ackhsbThuTEpJREkiLCJub2RlSWQiOiI1MzE0ZWI2MS1lYTA2LTQyOGQtYWEzZi0zMDA4OWJjZmUxYjgifX0seyJ0eXBlIjoicGgtcHJvcGVydGllcyIsImF0dHJzIjp7ImlkIjoia3JSZmdvcHNVeTFUd05VMXloU0RMcU5EVGQ2TjV0TVpySGxtOG5MSklESSIsIm5vZGVJZCI6ImUwMjE1NDU5LWY0YTgtNGJjNy04NDhmLTYxODE1NzY1NzlmNyJ9fV19fV19", + "$host": "localhost:8000", + "$pathname": "/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$browser_version": 117, + "$browser_language": "en-GB", + "$screen_height": 982, + "$screen_width": 1512, + "$viewport_height": 859, + "$viewport_width": 1512, + "$lib": "web", + "$lib_version": "1.84.0", + "$insert_id": "w3rikko1nqif5eb6", + "$time": 1697797841.64, + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$device_id": "018a92fd-7b25-7770-a050-577e94fd148c", + "$console_log_recording_enabled_server_side": true, + "$session_recording_recorder_version_server_side": "v2", + "$autocapture_disabled_server_side": false, + "$active_feature_flags": [ + "signup-page-4.0", + "cmd-k-search", + "posthog-3000", + "funnels-cue-opt-out-7301", + "retention-breakdown", + "smoothing-interval", + "billing-limit", + "kafka-inspector", + "historical-exports-v2", + "person-on-events-enabled", + "region-select", + "ingestion-warnings-enabled", + "session-reset-on-load", + "recordings-on-feature-flags", + "auto-rollback-feature-flags", + "onboarding-v2-demo", + "feature-flag-rollout-ux", + "role-based-access", + "query_running_time", + "query-timings", + "recording-debugging", + "enable-prompts", + "feedback-scene", + "early-access-feature", + "early-access-feature-site-button", + "hedgehog-mode-debug", + "auto-redirect", + "session-recording-blob-replay", + "surveys", + "generic-signup-benefits", + "surveys-positions", + "web-analytics", + "high-frequency-batch-exports", + "exception-autocapture", + "data-warehouse", + "data-warehouse-views", + "ff-dashboard-templates", + "show-product-intro-existing-products", + "artificial-hog", + "cs-dashboards", + "product-specific-onboarding", + "redirect-signups-to-instance", + "apps-and-exports-ui", + "survey-nps-results", + "session-recording-allow-v1-snapshots", + "session-replay-cors-proxy", + "webhooks-denylist", + "surveys-site-app-deprecation", + "surveys-multiple-questions", + "surveys-results-visualizations", + "console-recording-search", + "persons-hogql-query", + "notebooks" + ], + "$feature/file-previews": false, + "$feature/signup-page-4.0": "control", + "$feature/hogql-insights": false, + "$feature/cmd-k-search": true, + "$feature/posthog-3000": true, + "$feature/funnels-cue-opt-out-7301": true, + "$feature/retention-breakdown": true, + "$feature/smoothing-interval": true, + "$feature/billing-limit": true, + "$feature/kafka-inspector": true, + "$feature/historical-exports-v2": true, + "$feature/person-on-events-enabled": true, + "$feature/region-select": true, + "$feature/ingestion-warnings-enabled": true, + "$feature/session-reset-on-load": true, + "$feature/recordings-on-feature-flags": true, + "$feature/auto-rollback-feature-flags": true, + "$feature/onboarding-v2-demo": true, + "$feature/feature-flag-rollout-ux": true, + "$feature/role-based-access": true, + "$feature/query_running_time": true, + "$feature/query-timings": true, + "$feature/recording-debugging": true, + "$feature/enable-prompts": true, + "$feature/feedback-scene": true, + "$feature/early-access-feature": true, + "$feature/early-access-feature-site-button": true, + "$feature/hedgehog-mode-debug": true, + "$feature/auto-redirect": true, + "$feature/session-recording-blob-replay": true, + "$feature/surveys": true, + "$feature/generic-signup-benefits": true, + "$feature/surveys-positions": true, + "$feature/web-analytics": true, + "$feature/high-frequency-batch-exports": true, + "$feature/exception-autocapture": true, + "$feature/data-warehouse": true, + "$feature/data-warehouse-views": true, + "$feature/ff-dashboard-templates": true, + "$feature/show-product-intro-existing-products": true, + "$feature/artificial-hog": true, + "$feature/cs-dashboards": true, + "$feature/product-specific-onboarding": true, + "$feature/redirect-signups-to-instance": true, + "$feature/apps-and-exports-ui": true, + "$feature/survey-nps-results": true, + "$feature/session-recording-allow-v1-snapshots": true, + "$feature/session-replay-cors-proxy": true, + "$feature/webhooks-denylist": true, + "$feature/surveys-site-app-deprecation": true, + "$feature/surveys-multiple-questions": true, + "$feature/surveys-results-visualizations": true, + "$feature/console-recording-search": true, + "$feature/persons-hogql-query": true, + "$feature/notebooks": true, + "$feature_flag_payloads": {}, + "realm": "hosted-clickhouse", + "email_service_available": false, + "slack_service_available": false, + "$user_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "is_demo_project": false, + "$groups": { + "project": "018a92f8-b602-0000-75de-4b9073693531", + "organization": "018a92f8-afff-0000-efec-ca77de39e384", + "customer": "cus_OdSgxxWtHOtq9g", + "instance": "http://localhost:8000" + }, + "has_billing_plan": true, + "customer_deactivated": false, + "current_total_amount_usd": "0.00", + "percentage_usage.product_analytics": 0, + "current_amount_usd.product_analytics": "0.00", + "unit_amount_usd.product_analytics": null, + "usage_limit.product_analytics": null, + "current_usage.product_analytics": 3729, + "projected_usage.product_analytics": 0, + "free_allocation.product_analytics": 0, + "percentage_usage.session_replay": 0, + "current_amount_usd.session_replay": "0.00", + "unit_amount_usd.session_replay": null, + "usage_limit.session_replay": null, + "current_usage.session_replay": 254, + "projected_usage.session_replay": 0, + "free_allocation.session_replay": 0, + "percentage_usage.feature_flags": 0, + "current_amount_usd.feature_flags": "0.00", + "unit_amount_usd.feature_flags": null, + "usage_limit.feature_flags": null, + "current_usage.feature_flags": 0, + "projected_usage.feature_flags": 0, + "free_allocation.feature_flags": 0, + "percentage_usage.integrations": 0, + "current_amount_usd.integrations": null, + "unit_amount_usd.integrations": null, + "usage_limit.integrations": 0, + "current_usage.integrations": 0, + "projected_usage.integrations": 0, + "free_allocation.integrations": 0, + "percentage_usage.platform_and_support": 0, + "current_amount_usd.platform_and_support": null, + "unit_amount_usd.platform_and_support": null, + "usage_limit.platform_and_support": 0, + "current_usage.platform_and_support": 0, + "projected_usage.platform_and_support": 0, + "free_allocation.platform_and_support": 0, + "billing_period_start": "2023-10-14T09:22:33.000Z", + "billing_period_end": "2023-11-14T09:22:33.000Z", + "$referrer": "$direct", + "$referring_domain": "$direct", + "query": { + "kind": "SessionsTimelineQuery", + "after": "2021-01-01T18:00:00Z", + "before": "2024-01-01T06:00:00Z", + "personId": "018a92fd-a1c3-0000-4144-fb39888c298e" + }, + "duration": 664.7000000476837, + "token": "phc_OWGI2wKbfi7rWDZT9wkl8uGcfe0wOGCvflLEZSMiaT0", + "$session_id": "018b4ca3-1d07-7195-8202-c8a103a9325a", + "$window_id": "018b4ca3-1d07-7195-8202-c8a2b00ad68a", + "$ip": "127.0.0.1", + "$set": { + "$os": "Mac OS X", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI#activeTab=feed&state=eyJ0eXBlIjoiZG9jIiwiY29udGVudCI6W3sidHlwZSI6ImhlYWRpbmciLCJhdHRycyI6eyJsZXZlbCI6MX0sImNvbnRlbnQiOlt7InR5cGUiOiJ0ZXh0IiwidGV4dCI6ImtyUmZnb3BzVXkxVHdOVTF5aFNETHFORFRkNk41dE1ackhsbThuTEpJREkifV19LHsidHlwZSI6InBoLXBlcnNvbi1mZWVkIiwiYXR0cnMiOnsiaGVpZ2h0IjpudWxsLCJ0aXRsZSI6bnVsbCwibm9kZUlkIjoiNmQ0ODUwNjYtZWM5OS00ODNkLThiOTgtNGQ4YTJkYzljYzRiIiwiaWQiOiJrclJmZ29wc1V5MVR3TlUxeWhTRExxTkRUZDZONXRNWnJIbG04bkxKSURJIiwiX19pbml0IjpudWxsLCJjaGlsZHJlbiI6W3sidHlwZSI6InBoLXBlcnNvbiIsImF0dHJzIjp7ImlkIjoia3JSZmdvcHNVeTFUd05VMXloU0RMcU5EVGQ2TjV0TVpySGxtOG5MSklESSIsIm5vZGVJZCI6IjNkMzZiZjU3LTFkYjQtNDJlZi1iNzhiLWUyZDNkNGViOWM5NSJ9fSx7InR5cGUiOiJwaC1tYXAiLCJhdHRycyI6eyJpZCI6ImtyUmZnb3BzVXkxVHdOVTF5aFNETHFORFRkNk41dE1ackhsbThuTEpJREkiLCJub2RlSWQiOiI1MzE0ZWI2MS1lYTA2LTQyOGQtYWEzZi0zMDA4OWJjZmUxYjgifX0seyJ0eXBlIjoicGgtcHJvcGVydGllcyIsImF0dHJzIjp7ImlkIjoia3JSZmdvcHNVeTFUd05VMXloU0RMcU5EVGQ2TjV0TVpySGxtOG5MSklESSIsIm5vZGVJZCI6ImUwMjE1NDU5LWY0YTgtNGJjNy04NDhmLTYxODE1NzY1NzlmNyJ9fV19fV19", + "$pathname": "/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$browser_version": 117, + "$referrer": "$direct", + "$referring_domain": "$direct" + }, + "$set_once": { + "$initial_os": "Mac OS X", + "$initial_browser": "Chrome", + "$initial_device_type": "Desktop", + "$initial_current_url": "http://localhost:8000/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI#activeTab=feed&state=eyJ0eXBlIjoiZG9jIiwiY29udGVudCI6W3sidHlwZSI6ImhlYWRpbmciLCJhdHRycyI6eyJsZXZlbCI6MX0sImNvbnRlbnQiOlt7InR5cGUiOiJ0ZXh0IiwidGV4dCI6ImtyUmZnb3BzVXkxVHdOVTF5aFNETHFORFRkNk41dE1ackhsbThuTEpJREkifV19LHsidHlwZSI6InBoLXBlcnNvbi1mZWVkIiwiYXR0cnMiOnsiaGVpZ2h0IjpudWxsLCJ0aXRsZSI6bnVsbCwibm9kZUlkIjoiNmQ0ODUwNjYtZWM5OS00ODNkLThiOTgtNGQ4YTJkYzljYzRiIiwiaWQiOiJrclJmZ29wc1V5MVR3TlUxeWhTRExxTkRUZDZONXRNWnJIbG04bkxKSURJIiwiX19pbml0IjpudWxsLCJjaGlsZHJlbiI6W3sidHlwZSI6InBoLXBlcnNvbiIsImF0dHJzIjp7ImlkIjoia3JSZmdvcHNVeTFUd05VMXloU0RMcU5EVGQ2TjV0TVpySGxtOG5MSklESSIsIm5vZGVJZCI6IjNkMzZiZjU3LTFkYjQtNDJlZi1iNzhiLWUyZDNkNGViOWM5NSJ9fSx7InR5cGUiOiJwaC1tYXAiLCJhdHRycyI6eyJpZCI6ImtyUmZnb3BzVXkxVHdOVTF5aFNETHFORFRkNk41dE1ackhsbThuTEpJREkiLCJub2RlSWQiOiI1MzE0ZWI2MS1lYTA2LTQyOGQtYWEzZi0zMDA4OWJjZmUxYjgifX0seyJ0eXBlIjoicGgtcHJvcGVydGllcyIsImF0dHJzIjp7ImlkIjoia3JSZmdvcHNVeTFUd05VMXloU0RMcU5EVGQ2TjV0TVpySGxtOG5MSklESSIsIm5vZGVJZCI6ImUwMjE1NDU5LWY0YTgtNGJjNy04NDhmLTYxODE1NzY1NzlmNyJ9fV19fV19", + "$initial_pathname": "/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$initial_browser_version": 117, + "$initial_referrer": "$direct", + "$initial_referring_domain": "$direct" + }, + "$sent_at": "2023-10-20T10:30:43.133000+00:00", + "$geoip_city_name": "Sydney", + "$geoip_country_name": "Australia", + "$geoip_country_code": "AU", + "$geoip_continent_name": "Oceania", + "$geoip_continent_code": "OC", + "$geoip_postal_code": "2000", + "$geoip_latitude": -33.8715, + "$geoip_longitude": 151.2006, + "$geoip_time_zone": "Australia/Sydney", + "$geoip_subdivision_1_code": "NSW", + "$geoip_subdivision_1_name": "New South Wales", + "$plugins_succeeded": ["GeoIP (1)"], + "$plugins_failed": [], + "$plugins_deferred": [], + "$group_3": "018a92f8-b602-0000-75de-4b9073693531", + "$group_2": "018a92f8-afff-0000-efec-ca77de39e384", + "$group_4": "cus_OdSgxxWtHOtq9g", + "$group_1": "http://localhost:8000" + }, + "timestamp": "2023-10-20T10:30:41.655000+00:00", + "uuid": null + }, + { + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "elements": [], + "elements_chain": null, + "event": "$feature_flag_called", + "id": "018b4ca3-2350-7671-8383-8c248f826729", + "person": null, + "properties": { + "$os": "Mac OS X", + "$os_version": "10.15.7", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI#activeTab=feed&state=eyJ0eXBlIjoiZG9jIiwiY29udGVudCI6W3sidHlwZSI6ImhlYWRpbmciLCJhdHRycyI6eyJsZXZlbCI6MX0sImNvbnRlbnQiOlt7InR5cGUiOiJ0ZXh0IiwidGV4dCI6ImtyUmZnb3BzVXkxVHdOVTF5aFNETHFORFRkNk41dE1ackhsbThuTEpJREkifV19LHsidHlwZSI6InBoLXBlcnNvbi1mZWVkIiwiYXR0cnMiOnsiaGVpZ2h0IjpudWxsLCJ0aXRsZSI6bnVsbCwibm9kZUlkIjoiNmQ0ODUwNjYtZWM5OS00ODNkLThiOTgtNGQ4YTJkYzljYzRiIiwiaWQiOiJrclJmZ29wc1V5MVR3TlUxeWhTRExxTkRUZDZONXRNWnJIbG04bkxKSURJIiwiX19pbml0IjpudWxsLCJjaGlsZHJlbiI6W3sidHlwZSI6InBoLXBlcnNvbiIsImF0dHJzIjp7ImlkIjoia3JSZmdvcHNVeTFUd05VMXloU0RMcU5EVGQ2TjV0TVpySGxtOG5MSklESSIsIm5vZGVJZCI6IjE0NDk2Y2ExLWUyNTUtNDlkMS1hM2IzLWU4ZjA1NzhhYjQ5YiJ9fSx7InR5cGUiOiJwaC1tYXAiLCJhdHRycyI6eyJpZCI6ImtyUmZnb3BzVXkxVHdOVTF5aFNETHFORFRkNk41dE1ackhsbThuTEpJREkiLCJub2RlSWQiOiJmMzgxYmFkOC1kMTNkLTQyOGItODYyNC03YTFkNTBhODBkMjMifX0seyJ0eXBlIjoicGgtcHJvcGVydGllcyIsImF0dHJzIjp7ImlkIjoia3JSZmdvcHNVeTFUd05VMXloU0RMcU5EVGQ2TjV0TVpySGxtOG5MSklESSIsIm5vZGVJZCI6ImE5Y2ZlOTlhLTRiZTktNDU1YS04OWMyLTViZGUyMGY2MWQwMiJ9fV19fV19", + "$host": "localhost:8000", + "$pathname": "/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$browser_version": 117, + "$browser_language": "en-GB", + "$screen_height": 982, + "$screen_width": 1512, + "$viewport_height": 859, + "$viewport_width": 1512, + "$lib": "web", + "$lib_version": "1.84.0", + "$insert_id": "h2xh5dfq47fd03xz", + "$time": 1697797841.745, + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$device_id": "018a92fd-7b25-7770-a050-577e94fd148c", + "$console_log_recording_enabled_server_side": true, + "$session_recording_recorder_version_server_side": "v2", + "$autocapture_disabled_server_side": false, + "$active_feature_flags": [ + "signup-page-4.0", + "cmd-k-search", + "posthog-3000", + "funnels-cue-opt-out-7301", + "retention-breakdown", + "smoothing-interval", + "billing-limit", + "kafka-inspector", + "historical-exports-v2", + "person-on-events-enabled", + "region-select", + "ingestion-warnings-enabled", + "session-reset-on-load", + "recordings-on-feature-flags", + "auto-rollback-feature-flags", + "onboarding-v2-demo", + "feature-flag-rollout-ux", + "role-based-access", + "query_running_time", + "query-timings", + "recording-debugging", + "enable-prompts", + "feedback-scene", + "early-access-feature", + "early-access-feature-site-button", + "hedgehog-mode-debug", + "auto-redirect", + "session-recording-blob-replay", + "surveys", + "generic-signup-benefits", + "surveys-positions", + "web-analytics", + "high-frequency-batch-exports", + "exception-autocapture", + "data-warehouse", + "data-warehouse-views", + "ff-dashboard-templates", + "show-product-intro-existing-products", + "artificial-hog", + "cs-dashboards", + "product-specific-onboarding", + "redirect-signups-to-instance", + "apps-and-exports-ui", + "survey-nps-results", + "session-recording-allow-v1-snapshots", + "session-replay-cors-proxy", + "webhooks-denylist", + "surveys-site-app-deprecation", + "surveys-multiple-questions", + "surveys-results-visualizations", + "console-recording-search", + "persons-hogql-query", + "notebooks" + ], + "$feature/file-previews": false, + "$feature/signup-page-4.0": "control", + "$feature/hogql-insights": false, + "$feature/cmd-k-search": true, + "$feature/posthog-3000": true, + "$feature/funnels-cue-opt-out-7301": true, + "$feature/retention-breakdown": true, + "$feature/smoothing-interval": true, + "$feature/billing-limit": true, + "$feature/kafka-inspector": true, + "$feature/historical-exports-v2": true, + "$feature/person-on-events-enabled": true, + "$feature/region-select": true, + "$feature/ingestion-warnings-enabled": true, + "$feature/session-reset-on-load": true, + "$feature/recordings-on-feature-flags": true, + "$feature/auto-rollback-feature-flags": true, + "$feature/onboarding-v2-demo": true, + "$feature/feature-flag-rollout-ux": true, + "$feature/role-based-access": true, + "$feature/query_running_time": true, + "$feature/query-timings": true, + "$feature/recording-debugging": true, + "$feature/enable-prompts": true, + "$feature/feedback-scene": true, + "$feature/early-access-feature": true, + "$feature/early-access-feature-site-button": true, + "$feature/hedgehog-mode-debug": true, + "$feature/auto-redirect": true, + "$feature/session-recording-blob-replay": true, + "$feature/surveys": true, + "$feature/generic-signup-benefits": true, + "$feature/surveys-positions": true, + "$feature/web-analytics": true, + "$feature/high-frequency-batch-exports": true, + "$feature/exception-autocapture": true, + "$feature/data-warehouse": true, + "$feature/data-warehouse-views": true, + "$feature/ff-dashboard-templates": true, + "$feature/show-product-intro-existing-products": true, + "$feature/artificial-hog": true, + "$feature/cs-dashboards": true, + "$feature/product-specific-onboarding": true, + "$feature/redirect-signups-to-instance": true, + "$feature/apps-and-exports-ui": true, + "$feature/survey-nps-results": true, + "$feature/session-recording-allow-v1-snapshots": true, + "$feature/session-replay-cors-proxy": true, + "$feature/webhooks-denylist": true, + "$feature/surveys-site-app-deprecation": true, + "$feature/surveys-multiple-questions": true, + "$feature/surveys-results-visualizations": true, + "$feature/console-recording-search": true, + "$feature/persons-hogql-query": true, + "$feature/notebooks": true, + "$feature_flag_payloads": {}, + "realm": "hosted-clickhouse", + "email_service_available": false, + "slack_service_available": false, + "$user_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "is_demo_project": false, + "$groups": { + "project": "018a92f8-b602-0000-75de-4b9073693531", + "organization": "018a92f8-afff-0000-efec-ca77de39e384", + "customer": "cus_OdSgxxWtHOtq9g", + "instance": "http://localhost:8000" + }, + "has_billing_plan": true, + "customer_deactivated": false, + "current_total_amount_usd": "0.00", + "percentage_usage.product_analytics": 0, + "current_amount_usd.product_analytics": "0.00", + "unit_amount_usd.product_analytics": null, + "usage_limit.product_analytics": null, + "current_usage.product_analytics": 3729, + "projected_usage.product_analytics": 0, + "free_allocation.product_analytics": 0, + "percentage_usage.session_replay": 0, + "current_amount_usd.session_replay": "0.00", + "unit_amount_usd.session_replay": null, + "usage_limit.session_replay": null, + "current_usage.session_replay": 254, + "projected_usage.session_replay": 0, + "free_allocation.session_replay": 0, + "percentage_usage.feature_flags": 0, + "current_amount_usd.feature_flags": "0.00", + "unit_amount_usd.feature_flags": null, + "usage_limit.feature_flags": null, + "current_usage.feature_flags": 0, + "projected_usage.feature_flags": 0, + "free_allocation.feature_flags": 0, + "percentage_usage.integrations": 0, + "current_amount_usd.integrations": null, + "unit_amount_usd.integrations": null, + "usage_limit.integrations": 0, + "current_usage.integrations": 0, + "projected_usage.integrations": 0, + "free_allocation.integrations": 0, + "percentage_usage.platform_and_support": 0, + "current_amount_usd.platform_and_support": null, + "unit_amount_usd.platform_and_support": null, + "usage_limit.platform_and_support": 0, + "current_usage.platform_and_support": 0, + "projected_usage.platform_and_support": 0, + "free_allocation.platform_and_support": 0, + "billing_period_start": "2023-10-14T09:22:33.000Z", + "billing_period_end": "2023-11-14T09:22:33.000Z", + "$referrer": "$direct", + "$referring_domain": "$direct", + "$feature_flag": "product-specific-onboarding", + "$feature_flag_response": true, + "token": "phc_OWGI2wKbfi7rWDZT9wkl8uGcfe0wOGCvflLEZSMiaT0", + "$session_id": "018b4ca3-1d07-7195-8202-c8a103a9325a", + "$window_id": "018b4ca3-1d07-7195-8202-c8a2b00ad68a", + "$ip": "127.0.0.1", + "$set": { + "$os": "Mac OS X", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI#activeTab=feed&state=eyJ0eXBlIjoiZG9jIiwiY29udGVudCI6W3sidHlwZSI6ImhlYWRpbmciLCJhdHRycyI6eyJsZXZlbCI6MX0sImNvbnRlbnQiOlt7InR5cGUiOiJ0ZXh0IiwidGV4dCI6ImtyUmZnb3BzVXkxVHdOVTF5aFNETHFORFRkNk41dE1ackhsbThuTEpJREkifV19LHsidHlwZSI6InBoLXBlcnNvbi1mZWVkIiwiYXR0cnMiOnsiaGVpZ2h0IjpudWxsLCJ0aXRsZSI6bnVsbCwibm9kZUlkIjoiNmQ0ODUwNjYtZWM5OS00ODNkLThiOTgtNGQ4YTJkYzljYzRiIiwiaWQiOiJrclJmZ29wc1V5MVR3TlUxeWhTRExxTkRUZDZONXRNWnJIbG04bkxKSURJIiwiX19pbml0IjpudWxsLCJjaGlsZHJlbiI6W3sidHlwZSI6InBoLXBlcnNvbiIsImF0dHJzIjp7ImlkIjoia3JSZmdvcHNVeTFUd05VMXloU0RMcU5EVGQ2TjV0TVpySGxtOG5MSklESSIsIm5vZGVJZCI6IjE0NDk2Y2ExLWUyNTUtNDlkMS1hM2IzLWU4ZjA1NzhhYjQ5YiJ9fSx7InR5cGUiOiJwaC1tYXAiLCJhdHRycyI6eyJpZCI6ImtyUmZnb3BzVXkxVHdOVTF5aFNETHFORFRkNk41dE1ackhsbThuTEpJREkiLCJub2RlSWQiOiJmMzgxYmFkOC1kMTNkLTQyOGItODYyNC03YTFkNTBhODBkMjMifX0seyJ0eXBlIjoicGgtcHJvcGVydGllcyIsImF0dHJzIjp7ImlkIjoia3JSZmdvcHNVeTFUd05VMXloU0RMcU5EVGQ2TjV0TVpySGxtOG5MSklESSIsIm5vZGVJZCI6ImE5Y2ZlOTlhLTRiZTktNDU1YS04OWMyLTViZGUyMGY2MWQwMiJ9fV19fV19", + "$pathname": "/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$browser_version": 117, + "$referrer": "$direct", + "$referring_domain": "$direct" + }, + "$set_once": { + "$initial_os": "Mac OS X", + "$initial_browser": "Chrome", + "$initial_device_type": "Desktop", + "$initial_current_url": "http://localhost:8000/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI#activeTab=feed&state=eyJ0eXBlIjoiZG9jIiwiY29udGVudCI6W3sidHlwZSI6ImhlYWRpbmciLCJhdHRycyI6eyJsZXZlbCI6MX0sImNvbnRlbnQiOlt7InR5cGUiOiJ0ZXh0IiwidGV4dCI6ImtyUmZnb3BzVXkxVHdOVTF5aFNETHFORFRkNk41dE1ackhsbThuTEpJREkifV19LHsidHlwZSI6InBoLXBlcnNvbi1mZWVkIiwiYXR0cnMiOnsiaGVpZ2h0IjpudWxsLCJ0aXRsZSI6bnVsbCwibm9kZUlkIjoiNmQ0ODUwNjYtZWM5OS00ODNkLThiOTgtNGQ4YTJkYzljYzRiIiwiaWQiOiJrclJmZ29wc1V5MVR3TlUxeWhTRExxTkRUZDZONXRNWnJIbG04bkxKSURJIiwiX19pbml0IjpudWxsLCJjaGlsZHJlbiI6W3sidHlwZSI6InBoLXBlcnNvbiIsImF0dHJzIjp7ImlkIjoia3JSZmdvcHNVeTFUd05VMXloU0RMcU5EVGQ2TjV0TVpySGxtOG5MSklESSIsIm5vZGVJZCI6IjE0NDk2Y2ExLWUyNTUtNDlkMS1hM2IzLWU4ZjA1NzhhYjQ5YiJ9fSx7InR5cGUiOiJwaC1tYXAiLCJhdHRycyI6eyJpZCI6ImtyUmZnb3BzVXkxVHdOVTF5aFNETHFORFRkNk41dE1ackhsbThuTEpJREkiLCJub2RlSWQiOiJmMzgxYmFkOC1kMTNkLTQyOGItODYyNC03YTFkNTBhODBkMjMifX0seyJ0eXBlIjoicGgtcHJvcGVydGllcyIsImF0dHJzIjp7ImlkIjoia3JSZmdvcHNVeTFUd05VMXloU0RMcU5EVGQ2TjV0TVpySGxtOG5MSklESSIsIm5vZGVJZCI6ImE5Y2ZlOTlhLTRiZTktNDU1YS04OWMyLTViZGUyMGY2MWQwMiJ9fV19fV19", + "$initial_pathname": "/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$initial_browser_version": 117, + "$initial_referrer": "$direct", + "$initial_referring_domain": "$direct" + }, + "$sent_at": "2023-10-20T10:30:43.133000+00:00", + "$geoip_city_name": "Sydney", + "$geoip_country_name": "Australia", + "$geoip_country_code": "AU", + "$geoip_continent_name": "Oceania", + "$geoip_continent_code": "OC", + "$geoip_postal_code": "2000", + "$geoip_latitude": -33.8715, + "$geoip_longitude": 151.2006, + "$geoip_time_zone": "Australia/Sydney", + "$geoip_subdivision_1_code": "NSW", + "$geoip_subdivision_1_name": "New South Wales", + "$plugins_succeeded": ["GeoIP (1)"], + "$plugins_failed": [], + "$plugins_deferred": [], + "$group_3": "018a92f8-b602-0000-75de-4b9073693531", + "$group_2": "018a92f8-afff-0000-efec-ca77de39e384", + "$group_4": "cus_OdSgxxWtHOtq9g", + "$group_1": "http://localhost:8000" + }, + "timestamp": "2023-10-20T10:30:41.760000+00:00", + "uuid": null + }, + { + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "elements": [], + "elements_chain": null, + "event": "$pageview", + "id": "018b4ca3-2368-78f4-88db-9fdc90e949de", + "person": null, + "properties": { + "$os": "Mac OS X", + "$os_version": "10.15.7", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI#activeTab=feed&state=eyJ0eXBlIjoiZG9jIiwiY29udGVudCI6W3sidHlwZSI6ImhlYWRpbmciLCJhdHRycyI6eyJsZXZlbCI6MX0sImNvbnRlbnQiOlt7InR5cGUiOiJ0ZXh0IiwidGV4dCI6ImtyUmZnb3BzVXkxVHdOVTF5aFNETHFORFRkNk41dE1ackhsbThuTEpJREkifV19LHsidHlwZSI6InBoLXBlcnNvbi1mZWVkIiwiYXR0cnMiOnsiaGVpZ2h0IjpudWxsLCJ0aXRsZSI6bnVsbCwibm9kZUlkIjoiNmQ0ODUwNjYtZWM5OS00ODNkLThiOTgtNGQ4YTJkYzljYzRiIiwiaWQiOiJrclJmZ29wc1V5MVR3TlUxeWhTRExxTkRUZDZONXRNWnJIbG04bkxKSURJIiwiX19pbml0IjpudWxsLCJjaGlsZHJlbiI6W3sidHlwZSI6InBoLXBlcnNvbiIsImF0dHJzIjp7ImlkIjoia3JSZmdvcHNVeTFUd05VMXloU0RMcU5EVGQ2TjV0TVpySGxtOG5MSklESSIsIm5vZGVJZCI6IjE0NDk2Y2ExLWUyNTUtNDlkMS1hM2IzLWU4ZjA1NzhhYjQ5YiJ9fSx7InR5cGUiOiJwaC1tYXAiLCJhdHRycyI6eyJpZCI6ImtyUmZnb3BzVXkxVHdOVTF5aFNETHFORFRkNk41dE1ackhsbThuTEpJREkiLCJub2RlSWQiOiJmMzgxYmFkOC1kMTNkLTQyOGItODYyNC03YTFkNTBhODBkMjMifX0seyJ0eXBlIjoicGgtcHJvcGVydGllcyIsImF0dHJzIjp7ImlkIjoia3JSZmdvcHNVeTFUd05VMXloU0RMcU5EVGQ2TjV0TVpySGxtOG5MSklESSIsIm5vZGVJZCI6ImE5Y2ZlOTlhLTRiZTktNDU1YS04OWMyLTViZGUyMGY2MWQwMiJ9fV19fV19", + "$host": "localhost:8000", + "$pathname": "/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$browser_version": 117, + "$browser_language": "en-GB", + "$screen_height": 982, + "$screen_width": 1512, + "$viewport_height": 859, + "$viewport_width": 1512, + "$lib": "web", + "$lib_version": "1.84.0", + "$insert_id": "m2opmkybj5tuw159", + "$time": 1697797841.769, + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$device_id": "018a92fd-7b25-7770-a050-577e94fd148c", + "$console_log_recording_enabled_server_side": true, + "$session_recording_recorder_version_server_side": "v2", + "$autocapture_disabled_server_side": false, + "$active_feature_flags": [ + "signup-page-4.0", + "cmd-k-search", + "posthog-3000", + "funnels-cue-opt-out-7301", + "retention-breakdown", + "smoothing-interval", + "billing-limit", + "kafka-inspector", + "historical-exports-v2", + "person-on-events-enabled", + "region-select", + "ingestion-warnings-enabled", + "session-reset-on-load", + "recordings-on-feature-flags", + "auto-rollback-feature-flags", + "onboarding-v2-demo", + "feature-flag-rollout-ux", + "role-based-access", + "query_running_time", + "query-timings", + "recording-debugging", + "enable-prompts", + "feedback-scene", + "early-access-feature", + "early-access-feature-site-button", + "hedgehog-mode-debug", + "auto-redirect", + "session-recording-blob-replay", + "surveys", + "generic-signup-benefits", + "surveys-positions", + "web-analytics", + "high-frequency-batch-exports", + "exception-autocapture", + "data-warehouse", + "data-warehouse-views", + "ff-dashboard-templates", + "show-product-intro-existing-products", + "artificial-hog", + "cs-dashboards", + "product-specific-onboarding", + "redirect-signups-to-instance", + "apps-and-exports-ui", + "survey-nps-results", + "session-recording-allow-v1-snapshots", + "session-replay-cors-proxy", + "webhooks-denylist", + "surveys-site-app-deprecation", + "surveys-multiple-questions", + "surveys-results-visualizations", + "console-recording-search", + "persons-hogql-query", + "notebooks" + ], + "$feature/file-previews": false, + "$feature/signup-page-4.0": "control", + "$feature/hogql-insights": false, + "$feature/cmd-k-search": true, + "$feature/posthog-3000": true, + "$feature/funnels-cue-opt-out-7301": true, + "$feature/retention-breakdown": true, + "$feature/smoothing-interval": true, + "$feature/billing-limit": true, + "$feature/kafka-inspector": true, + "$feature/historical-exports-v2": true, + "$feature/person-on-events-enabled": true, + "$feature/region-select": true, + "$feature/ingestion-warnings-enabled": true, + "$feature/session-reset-on-load": true, + "$feature/recordings-on-feature-flags": true, + "$feature/auto-rollback-feature-flags": true, + "$feature/onboarding-v2-demo": true, + "$feature/feature-flag-rollout-ux": true, + "$feature/role-based-access": true, + "$feature/query_running_time": true, + "$feature/query-timings": true, + "$feature/recording-debugging": true, + "$feature/enable-prompts": true, + "$feature/feedback-scene": true, + "$feature/early-access-feature": true, + "$feature/early-access-feature-site-button": true, + "$feature/hedgehog-mode-debug": true, + "$feature/auto-redirect": true, + "$feature/session-recording-blob-replay": true, + "$feature/surveys": true, + "$feature/generic-signup-benefits": true, + "$feature/surveys-positions": true, + "$feature/web-analytics": true, + "$feature/high-frequency-batch-exports": true, + "$feature/exception-autocapture": true, + "$feature/data-warehouse": true, + "$feature/data-warehouse-views": true, + "$feature/ff-dashboard-templates": true, + "$feature/show-product-intro-existing-products": true, + "$feature/artificial-hog": true, + "$feature/cs-dashboards": true, + "$feature/product-specific-onboarding": true, + "$feature/redirect-signups-to-instance": true, + "$feature/apps-and-exports-ui": true, + "$feature/survey-nps-results": true, + "$feature/session-recording-allow-v1-snapshots": true, + "$feature/session-replay-cors-proxy": true, + "$feature/webhooks-denylist": true, + "$feature/surveys-site-app-deprecation": true, + "$feature/surveys-multiple-questions": true, + "$feature/surveys-results-visualizations": true, + "$feature/console-recording-search": true, + "$feature/persons-hogql-query": true, + "$feature/notebooks": true, + "$feature_flag_payloads": {}, + "realm": "hosted-clickhouse", + "email_service_available": false, + "slack_service_available": false, + "$user_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "is_demo_project": false, + "$groups": { + "project": "018a92f8-b602-0000-75de-4b9073693531", + "organization": "018a92f8-afff-0000-efec-ca77de39e384", + "customer": "cus_OdSgxxWtHOtq9g", + "instance": "http://localhost:8000" + }, + "has_billing_plan": true, + "customer_deactivated": false, + "current_total_amount_usd": "0.00", + "percentage_usage.product_analytics": 0, + "current_amount_usd.product_analytics": "0.00", + "unit_amount_usd.product_analytics": null, + "usage_limit.product_analytics": null, + "current_usage.product_analytics": 3729, + "projected_usage.product_analytics": 0, + "free_allocation.product_analytics": 0, + "percentage_usage.session_replay": 0, + "current_amount_usd.session_replay": "0.00", + "unit_amount_usd.session_replay": null, + "usage_limit.session_replay": null, + "current_usage.session_replay": 254, + "projected_usage.session_replay": 0, + "free_allocation.session_replay": 0, + "percentage_usage.feature_flags": 0, + "current_amount_usd.feature_flags": "0.00", + "unit_amount_usd.feature_flags": null, + "usage_limit.feature_flags": null, + "current_usage.feature_flags": 0, + "projected_usage.feature_flags": 0, + "free_allocation.feature_flags": 0, + "percentage_usage.integrations": 0, + "current_amount_usd.integrations": null, + "unit_amount_usd.integrations": null, + "usage_limit.integrations": 0, + "current_usage.integrations": 0, + "projected_usage.integrations": 0, + "free_allocation.integrations": 0, + "percentage_usage.platform_and_support": 0, + "current_amount_usd.platform_and_support": null, + "unit_amount_usd.platform_and_support": null, + "usage_limit.platform_and_support": 0, + "current_usage.platform_and_support": 0, + "projected_usage.platform_and_support": 0, + "free_allocation.platform_and_support": 0, + "billing_period_start": "2023-10-14T09:22:33.000Z", + "billing_period_end": "2023-11-14T09:22:33.000Z", + "$referrer": "$direct", + "$referring_domain": "$direct", + "token": "phc_OWGI2wKbfi7rWDZT9wkl8uGcfe0wOGCvflLEZSMiaT0", + "$session_id": "018b4ca3-1d07-7195-8202-c8a103a9325a", + "$window_id": "018b4ca3-1d07-7195-8202-c8a2b00ad68a", + "title": "test@posthog.com \u2022 Persons \u2022 PostHog", + "$ip": "127.0.0.1", + "$set": { + "$os": "Mac OS X", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI#activeTab=feed&state=eyJ0eXBlIjoiZG9jIiwiY29udGVudCI6W3sidHlwZSI6ImhlYWRpbmciLCJhdHRycyI6eyJsZXZlbCI6MX0sImNvbnRlbnQiOlt7InR5cGUiOiJ0ZXh0IiwidGV4dCI6ImtyUmZnb3BzVXkxVHdOVTF5aFNETHFORFRkNk41dE1ackhsbThuTEpJREkifV19LHsidHlwZSI6InBoLXBlcnNvbi1mZWVkIiwiYXR0cnMiOnsiaGVpZ2h0IjpudWxsLCJ0aXRsZSI6bnVsbCwibm9kZUlkIjoiNmQ0ODUwNjYtZWM5OS00ODNkLThiOTgtNGQ4YTJkYzljYzRiIiwiaWQiOiJrclJmZ29wc1V5MVR3TlUxeWhTRExxTkRUZDZONXRNWnJIbG04bkxKSURJIiwiX19pbml0IjpudWxsLCJjaGlsZHJlbiI6W3sidHlwZSI6InBoLXBlcnNvbiIsImF0dHJzIjp7ImlkIjoia3JSZmdvcHNVeTFUd05VMXloU0RMcU5EVGQ2TjV0TVpySGxtOG5MSklESSIsIm5vZGVJZCI6IjE0NDk2Y2ExLWUyNTUtNDlkMS1hM2IzLWU4ZjA1NzhhYjQ5YiJ9fSx7InR5cGUiOiJwaC1tYXAiLCJhdHRycyI6eyJpZCI6ImtyUmZnb3BzVXkxVHdOVTF5aFNETHFORFRkNk41dE1ackhsbThuTEpJREkiLCJub2RlSWQiOiJmMzgxYmFkOC1kMTNkLTQyOGItODYyNC03YTFkNTBhODBkMjMifX0seyJ0eXBlIjoicGgtcHJvcGVydGllcyIsImF0dHJzIjp7ImlkIjoia3JSZmdvcHNVeTFUd05VMXloU0RMcU5EVGQ2TjV0TVpySGxtOG5MSklESSIsIm5vZGVJZCI6ImE5Y2ZlOTlhLTRiZTktNDU1YS04OWMyLTViZGUyMGY2MWQwMiJ9fV19fV19", + "$pathname": "/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$browser_version": 117, + "$referrer": "$direct", + "$referring_domain": "$direct" + }, + "$set_once": { + "$initial_os": "Mac OS X", + "$initial_browser": "Chrome", + "$initial_device_type": "Desktop", + "$initial_current_url": "http://localhost:8000/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI#activeTab=feed&state=eyJ0eXBlIjoiZG9jIiwiY29udGVudCI6W3sidHlwZSI6ImhlYWRpbmciLCJhdHRycyI6eyJsZXZlbCI6MX0sImNvbnRlbnQiOlt7InR5cGUiOiJ0ZXh0IiwidGV4dCI6ImtyUmZnb3BzVXkxVHdOVTF5aFNETHFORFRkNk41dE1ackhsbThuTEpJREkifV19LHsidHlwZSI6InBoLXBlcnNvbi1mZWVkIiwiYXR0cnMiOnsiaGVpZ2h0IjpudWxsLCJ0aXRsZSI6bnVsbCwibm9kZUlkIjoiNmQ0ODUwNjYtZWM5OS00ODNkLThiOTgtNGQ4YTJkYzljYzRiIiwiaWQiOiJrclJmZ29wc1V5MVR3TlUxeWhTRExxTkRUZDZONXRNWnJIbG04bkxKSURJIiwiX19pbml0IjpudWxsLCJjaGlsZHJlbiI6W3sidHlwZSI6InBoLXBlcnNvbiIsImF0dHJzIjp7ImlkIjoia3JSZmdvcHNVeTFUd05VMXloU0RMcU5EVGQ2TjV0TVpySGxtOG5MSklESSIsIm5vZGVJZCI6IjE0NDk2Y2ExLWUyNTUtNDlkMS1hM2IzLWU4ZjA1NzhhYjQ5YiJ9fSx7InR5cGUiOiJwaC1tYXAiLCJhdHRycyI6eyJpZCI6ImtyUmZnb3BzVXkxVHdOVTF5aFNETHFORFRkNk41dE1ackhsbThuTEpJREkiLCJub2RlSWQiOiJmMzgxYmFkOC1kMTNkLTQyOGItODYyNC03YTFkNTBhODBkMjMifX0seyJ0eXBlIjoicGgtcHJvcGVydGllcyIsImF0dHJzIjp7ImlkIjoia3JSZmdvcHNVeTFUd05VMXloU0RMcU5EVGQ2TjV0TVpySGxtOG5MSklESSIsIm5vZGVJZCI6ImE5Y2ZlOTlhLTRiZTktNDU1YS04OWMyLTViZGUyMGY2MWQwMiJ9fV19fV19", + "$initial_pathname": "/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$initial_browser_version": 117, + "$initial_referrer": "$direct", + "$initial_referring_domain": "$direct" + }, + "$sent_at": "2023-10-20T10:30:43.133000+00:00", + "$geoip_city_name": "Sydney", + "$geoip_country_name": "Australia", + "$geoip_country_code": "AU", + "$geoip_continent_name": "Oceania", + "$geoip_continent_code": "OC", + "$geoip_postal_code": "2000", + "$geoip_latitude": -33.8715, + "$geoip_longitude": 151.2006, + "$geoip_time_zone": "Australia/Sydney", + "$geoip_subdivision_1_code": "NSW", + "$geoip_subdivision_1_name": "New South Wales", + "$plugins_succeeded": ["GeoIP (1)"], + "$plugins_failed": [], + "$plugins_deferred": [], + "$group_3": "018a92f8-b602-0000-75de-4b9073693531", + "$group_2": "018a92f8-afff-0000-efec-ca77de39e384", + "$group_4": "cus_OdSgxxWtHOtq9g", + "$group_1": "http://localhost:8000" + }, + "timestamp": "2023-10-20T10:30:41.784000+00:00", + "uuid": null + }, + { + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "elements": [], + "elements_chain": null, + "event": "notebook content changed", + "id": "018b4ca3-236a-78d6-ba7b-155173c88abe", + "person": null, + "properties": { + "$os": "Mac OS X", + "$os_version": "10.15.7", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI#activeTab=feed&state=eyJ0eXBlIjoiZG9jIiwiY29udGVudCI6W3sidHlwZSI6ImhlYWRpbmciLCJhdHRycyI6eyJsZXZlbCI6MX0sImNvbnRlbnQiOlt7InR5cGUiOiJ0ZXh0IiwidGV4dCI6ImtyUmZnb3BzVXkxVHdOVTF5aFNETHFORFRkNk41dE1ackhsbThuTEpJREkifV19LHsidHlwZSI6InBoLXBlcnNvbi1mZWVkIiwiYXR0cnMiOnsiaGVpZ2h0IjpudWxsLCJ0aXRsZSI6bnVsbCwibm9kZUlkIjoiNmQ0ODUwNjYtZWM5OS00ODNkLThiOTgtNGQ4YTJkYzljYzRiIiwiaWQiOiJrclJmZ29wc1V5MVR3TlUxeWhTRExxTkRUZDZONXRNWnJIbG04bkxKSURJIiwiX19pbml0IjpudWxsLCJjaGlsZHJlbiI6W3sidHlwZSI6InBoLXBlcnNvbiIsImF0dHJzIjp7ImlkIjoia3JSZmdvcHNVeTFUd05VMXloU0RMcU5EVGQ2TjV0TVpySGxtOG5MSklESSIsIm5vZGVJZCI6IjE0NDk2Y2ExLWUyNTUtNDlkMS1hM2IzLWU4ZjA1NzhhYjQ5YiJ9fSx7InR5cGUiOiJwaC1tYXAiLCJhdHRycyI6eyJpZCI6ImtyUmZnb3BzVXkxVHdOVTF5aFNETHFORFRkNk41dE1ackhsbThuTEpJREkiLCJub2RlSWQiOiJmMzgxYmFkOC1kMTNkLTQyOGItODYyNC03YTFkNTBhODBkMjMifX0seyJ0eXBlIjoicGgtcHJvcGVydGllcyIsImF0dHJzIjp7ImlkIjoia3JSZmdvcHNVeTFUd05VMXloU0RMcU5EVGQ2TjV0TVpySGxtOG5MSklESSIsIm5vZGVJZCI6ImE5Y2ZlOTlhLTRiZTktNDU1YS04OWMyLTViZGUyMGY2MWQwMiJ9fV19fV19", + "$host": "localhost:8000", + "$pathname": "/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$browser_version": 117, + "$browser_language": "en-GB", + "$screen_height": 982, + "$screen_width": 1512, + "$viewport_height": 859, + "$viewport_width": 1512, + "$lib": "web", + "$lib_version": "1.84.0", + "$insert_id": "3tkk1xg4kr4es46n", + "$time": 1697797841.77, + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$device_id": "018a92fd-7b25-7770-a050-577e94fd148c", + "$console_log_recording_enabled_server_side": true, + "$session_recording_recorder_version_server_side": "v2", + "$autocapture_disabled_server_side": false, + "$active_feature_flags": [ + "signup-page-4.0", + "cmd-k-search", + "posthog-3000", + "funnels-cue-opt-out-7301", + "retention-breakdown", + "smoothing-interval", + "billing-limit", + "kafka-inspector", + "historical-exports-v2", + "person-on-events-enabled", + "region-select", + "ingestion-warnings-enabled", + "session-reset-on-load", + "recordings-on-feature-flags", + "auto-rollback-feature-flags", + "onboarding-v2-demo", + "feature-flag-rollout-ux", + "role-based-access", + "query_running_time", + "query-timings", + "recording-debugging", + "enable-prompts", + "feedback-scene", + "early-access-feature", + "early-access-feature-site-button", + "hedgehog-mode-debug", + "auto-redirect", + "session-recording-blob-replay", + "surveys", + "generic-signup-benefits", + "surveys-positions", + "web-analytics", + "high-frequency-batch-exports", + "exception-autocapture", + "data-warehouse", + "data-warehouse-views", + "ff-dashboard-templates", + "show-product-intro-existing-products", + "artificial-hog", + "cs-dashboards", + "product-specific-onboarding", + "redirect-signups-to-instance", + "apps-and-exports-ui", + "survey-nps-results", + "session-recording-allow-v1-snapshots", + "session-replay-cors-proxy", + "webhooks-denylist", + "surveys-site-app-deprecation", + "surveys-multiple-questions", + "surveys-results-visualizations", + "console-recording-search", + "persons-hogql-query", + "notebooks" + ], + "$feature/file-previews": false, + "$feature/signup-page-4.0": "control", + "$feature/hogql-insights": false, + "$feature/cmd-k-search": true, + "$feature/posthog-3000": true, + "$feature/funnels-cue-opt-out-7301": true, + "$feature/retention-breakdown": true, + "$feature/smoothing-interval": true, + "$feature/billing-limit": true, + "$feature/kafka-inspector": true, + "$feature/historical-exports-v2": true, + "$feature/person-on-events-enabled": true, + "$feature/region-select": true, + "$feature/ingestion-warnings-enabled": true, + "$feature/session-reset-on-load": true, + "$feature/recordings-on-feature-flags": true, + "$feature/auto-rollback-feature-flags": true, + "$feature/onboarding-v2-demo": true, + "$feature/feature-flag-rollout-ux": true, + "$feature/role-based-access": true, + "$feature/query_running_time": true, + "$feature/query-timings": true, + "$feature/recording-debugging": true, + "$feature/enable-prompts": true, + "$feature/feedback-scene": true, + "$feature/early-access-feature": true, + "$feature/early-access-feature-site-button": true, + "$feature/hedgehog-mode-debug": true, + "$feature/auto-redirect": true, + "$feature/session-recording-blob-replay": true, + "$feature/surveys": true, + "$feature/generic-signup-benefits": true, + "$feature/surveys-positions": true, + "$feature/web-analytics": true, + "$feature/high-frequency-batch-exports": true, + "$feature/exception-autocapture": true, + "$feature/data-warehouse": true, + "$feature/data-warehouse-views": true, + "$feature/ff-dashboard-templates": true, + "$feature/show-product-intro-existing-products": true, + "$feature/artificial-hog": true, + "$feature/cs-dashboards": true, + "$feature/product-specific-onboarding": true, + "$feature/redirect-signups-to-instance": true, + "$feature/apps-and-exports-ui": true, + "$feature/survey-nps-results": true, + "$feature/session-recording-allow-v1-snapshots": true, + "$feature/session-replay-cors-proxy": true, + "$feature/webhooks-denylist": true, + "$feature/surveys-site-app-deprecation": true, + "$feature/surveys-multiple-questions": true, + "$feature/surveys-results-visualizations": true, + "$feature/console-recording-search": true, + "$feature/persons-hogql-query": true, + "$feature/notebooks": true, + "$feature_flag_payloads": {}, + "realm": "hosted-clickhouse", + "email_service_available": false, + "slack_service_available": false, + "$user_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "is_demo_project": false, + "$groups": { + "project": "018a92f8-b602-0000-75de-4b9073693531", + "organization": "018a92f8-afff-0000-efec-ca77de39e384", + "customer": "cus_OdSgxxWtHOtq9g", + "instance": "http://localhost:8000" + }, + "has_billing_plan": true, + "customer_deactivated": false, + "current_total_amount_usd": "0.00", + "percentage_usage.product_analytics": 0, + "current_amount_usd.product_analytics": "0.00", + "unit_amount_usd.product_analytics": null, + "usage_limit.product_analytics": null, + "current_usage.product_analytics": 3729, + "projected_usage.product_analytics": 0, + "free_allocation.product_analytics": 0, + "percentage_usage.session_replay": 0, + "current_amount_usd.session_replay": "0.00", + "unit_amount_usd.session_replay": null, + "usage_limit.session_replay": null, + "current_usage.session_replay": 254, + "projected_usage.session_replay": 0, + "free_allocation.session_replay": 0, + "percentage_usage.feature_flags": 0, + "current_amount_usd.feature_flags": "0.00", + "unit_amount_usd.feature_flags": null, + "usage_limit.feature_flags": null, + "current_usage.feature_flags": 0, + "projected_usage.feature_flags": 0, + "free_allocation.feature_flags": 0, + "percentage_usage.integrations": 0, + "current_amount_usd.integrations": null, + "unit_amount_usd.integrations": null, + "usage_limit.integrations": 0, + "current_usage.integrations": 0, + "projected_usage.integrations": 0, + "free_allocation.integrations": 0, + "percentage_usage.platform_and_support": 0, + "current_amount_usd.platform_and_support": null, + "unit_amount_usd.platform_and_support": null, + "usage_limit.platform_and_support": 0, + "current_usage.platform_and_support": 0, + "projected_usage.platform_and_support": 0, + "free_allocation.platform_and_support": 0, + "billing_period_start": "2023-10-14T09:22:33.000Z", + "billing_period_end": "2023-11-14T09:22:33.000Z", + "$referrer": "$direct", + "$referring_domain": "$direct", + "token": "phc_OWGI2wKbfi7rWDZT9wkl8uGcfe0wOGCvflLEZSMiaT0", + "$session_id": "018b4ca3-1d07-7195-8202-c8a103a9325a", + "$window_id": "018b4ca3-1d07-7195-8202-c8a2b00ad68a", + "$ip": "127.0.0.1", + "$set": { + "$os": "Mac OS X", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI#activeTab=feed&state=eyJ0eXBlIjoiZG9jIiwiY29udGVudCI6W3sidHlwZSI6ImhlYWRpbmciLCJhdHRycyI6eyJsZXZlbCI6MX0sImNvbnRlbnQiOlt7InR5cGUiOiJ0ZXh0IiwidGV4dCI6ImtyUmZnb3BzVXkxVHdOVTF5aFNETHFORFRkNk41dE1ackhsbThuTEpJREkifV19LHsidHlwZSI6InBoLXBlcnNvbi1mZWVkIiwiYXR0cnMiOnsiaGVpZ2h0IjpudWxsLCJ0aXRsZSI6bnVsbCwibm9kZUlkIjoiNmQ0ODUwNjYtZWM5OS00ODNkLThiOTgtNGQ4YTJkYzljYzRiIiwiaWQiOiJrclJmZ29wc1V5MVR3TlUxeWhTRExxTkRUZDZONXRNWnJIbG04bkxKSURJIiwiX19pbml0IjpudWxsLCJjaGlsZHJlbiI6W3sidHlwZSI6InBoLXBlcnNvbiIsImF0dHJzIjp7ImlkIjoia3JSZmdvcHNVeTFUd05VMXloU0RMcU5EVGQ2TjV0TVpySGxtOG5MSklESSIsIm5vZGVJZCI6IjE0NDk2Y2ExLWUyNTUtNDlkMS1hM2IzLWU4ZjA1NzhhYjQ5YiJ9fSx7InR5cGUiOiJwaC1tYXAiLCJhdHRycyI6eyJpZCI6ImtyUmZnb3BzVXkxVHdOVTF5aFNETHFORFRkNk41dE1ackhsbThuTEpJREkiLCJub2RlSWQiOiJmMzgxYmFkOC1kMTNkLTQyOGItODYyNC03YTFkNTBhODBkMjMifX0seyJ0eXBlIjoicGgtcHJvcGVydGllcyIsImF0dHJzIjp7ImlkIjoia3JSZmdvcHNVeTFUd05VMXloU0RMcU5EVGQ2TjV0TVpySGxtOG5MSklESSIsIm5vZGVJZCI6ImE5Y2ZlOTlhLTRiZTktNDU1YS04OWMyLTViZGUyMGY2MWQwMiJ9fV19fV19", + "$pathname": "/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$browser_version": 117, + "$referrer": "$direct", + "$referring_domain": "$direct" + }, + "$set_once": { + "$initial_os": "Mac OS X", + "$initial_browser": "Chrome", + "$initial_device_type": "Desktop", + "$initial_current_url": "http://localhost:8000/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI#activeTab=feed&state=eyJ0eXBlIjoiZG9jIiwiY29udGVudCI6W3sidHlwZSI6ImhlYWRpbmciLCJhdHRycyI6eyJsZXZlbCI6MX0sImNvbnRlbnQiOlt7InR5cGUiOiJ0ZXh0IiwidGV4dCI6ImtyUmZnb3BzVXkxVHdOVTF5aFNETHFORFRkNk41dE1ackhsbThuTEpJREkifV19LHsidHlwZSI6InBoLXBlcnNvbi1mZWVkIiwiYXR0cnMiOnsiaGVpZ2h0IjpudWxsLCJ0aXRsZSI6bnVsbCwibm9kZUlkIjoiNmQ0ODUwNjYtZWM5OS00ODNkLThiOTgtNGQ4YTJkYzljYzRiIiwiaWQiOiJrclJmZ29wc1V5MVR3TlUxeWhTRExxTkRUZDZONXRNWnJIbG04bkxKSURJIiwiX19pbml0IjpudWxsLCJjaGlsZHJlbiI6W3sidHlwZSI6InBoLXBlcnNvbiIsImF0dHJzIjp7ImlkIjoia3JSZmdvcHNVeTFUd05VMXloU0RMcU5EVGQ2TjV0TVpySGxtOG5MSklESSIsIm5vZGVJZCI6IjE0NDk2Y2ExLWUyNTUtNDlkMS1hM2IzLWU4ZjA1NzhhYjQ5YiJ9fSx7InR5cGUiOiJwaC1tYXAiLCJhdHRycyI6eyJpZCI6ImtyUmZnb3BzVXkxVHdOVTF5aFNETHFORFRkNk41dE1ackhsbThuTEpJREkiLCJub2RlSWQiOiJmMzgxYmFkOC1kMTNkLTQyOGItODYyNC03YTFkNTBhODBkMjMifX0seyJ0eXBlIjoicGgtcHJvcGVydGllcyIsImF0dHJzIjp7ImlkIjoia3JSZmdvcHNVeTFUd05VMXloU0RMcU5EVGQ2TjV0TVpySGxtOG5MSklESSIsIm5vZGVJZCI6ImE5Y2ZlOTlhLTRiZTktNDU1YS04OWMyLTViZGUyMGY2MWQwMiJ9fV19fV19", + "$initial_pathname": "/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$initial_browser_version": 117, + "$initial_referrer": "$direct", + "$initial_referring_domain": "$direct" + }, + "$sent_at": "2023-10-20T10:30:43.133000+00:00", + "$geoip_city_name": "Sydney", + "$geoip_country_name": "Australia", + "$geoip_country_code": "AU", + "$geoip_continent_name": "Oceania", + "$geoip_continent_code": "OC", + "$geoip_postal_code": "2000", + "$geoip_latitude": -33.8715, + "$geoip_longitude": 151.2006, + "$geoip_time_zone": "Australia/Sydney", + "$geoip_subdivision_1_code": "NSW", + "$geoip_subdivision_1_name": "New South Wales", + "$plugins_succeeded": ["GeoIP (1)"], + "$plugins_failed": [], + "$plugins_deferred": [], + "$group_3": "018a92f8-b602-0000-75de-4b9073693531", + "$group_2": "018a92f8-afff-0000-efec-ca77de39e384", + "$group_4": "cus_OdSgxxWtHOtq9g", + "$group_1": "http://localhost:8000" + }, + "timestamp": "2023-10-20T10:30:41.785000+00:00", + "uuid": null + }, + { + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "elements": [], + "elements_chain": null, + "event": "$opt_in", + "id": "018b4cc2-9079-7685-b127-207ee22b84d4", + "person": null, + "properties": { + "$os": "Mac OS X", + "$os_version": "10.15.7", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/", + "$host": "localhost:8000", + "$pathname": "/", + "$browser_version": 117, + "$browser_language": "en-GB", + "$screen_height": 982, + "$screen_width": 1512, + "$viewport_height": 859, + "$viewport_width": 1512, + "$lib": "web", + "$lib_version": "1.84.0", + "$insert_id": "kegpygvidsjwpa52", + "$time": 1697799901.306, + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$device_id": "018a92fd-7b25-7770-a050-577e94fd148c", + "$console_log_recording_enabled_server_side": true, + "$session_recording_recorder_version_server_side": "v2", + "$autocapture_disabled_server_side": false, + "$active_feature_flags": [ + "signup-page-4.0", + "cmd-k-search", + "posthog-3000", + "funnels-cue-opt-out-7301", + "retention-breakdown", + "smoothing-interval", + "billing-limit", + "kafka-inspector", + "historical-exports-v2", + "person-on-events-enabled", + "region-select", + "ingestion-warnings-enabled", + "session-reset-on-load", + "recordings-on-feature-flags", + "auto-rollback-feature-flags", + "onboarding-v2-demo", + "feature-flag-rollout-ux", + "role-based-access", + "query_running_time", + "query-timings", + "recording-debugging", + "enable-prompts", + "feedback-scene", + "early-access-feature", + "early-access-feature-site-button", + "hedgehog-mode-debug", + "auto-redirect", + "session-recording-blob-replay", + "surveys", + "generic-signup-benefits", + "surveys-positions", + "web-analytics", + "high-frequency-batch-exports", + "exception-autocapture", + "data-warehouse", + "data-warehouse-views", + "ff-dashboard-templates", + "show-product-intro-existing-products", + "artificial-hog", + "cs-dashboards", + "product-specific-onboarding", + "redirect-signups-to-instance", + "apps-and-exports-ui", + "survey-nps-results", + "session-recording-allow-v1-snapshots", + "session-replay-cors-proxy", + "webhooks-denylist", + "surveys-site-app-deprecation", + "surveys-multiple-questions", + "surveys-results-visualizations", + "console-recording-search", + "persons-hogql-query", + "notebooks" + ], + "$feature/file-previews": false, + "$feature/signup-page-4.0": "control", + "$feature/hogql-insights": false, + "$feature/cmd-k-search": true, + "$feature/posthog-3000": true, + "$feature/funnels-cue-opt-out-7301": true, + "$feature/retention-breakdown": true, + "$feature/smoothing-interval": true, + "$feature/billing-limit": true, + "$feature/kafka-inspector": true, + "$feature/historical-exports-v2": true, + "$feature/person-on-events-enabled": true, + "$feature/region-select": true, + "$feature/ingestion-warnings-enabled": true, + "$feature/session-reset-on-load": true, + "$feature/recordings-on-feature-flags": true, + "$feature/auto-rollback-feature-flags": true, + "$feature/onboarding-v2-demo": true, + "$feature/feature-flag-rollout-ux": true, + "$feature/role-based-access": true, + "$feature/query_running_time": true, + "$feature/query-timings": true, + "$feature/recording-debugging": true, + "$feature/enable-prompts": true, + "$feature/feedback-scene": true, + "$feature/early-access-feature": true, + "$feature/early-access-feature-site-button": true, + "$feature/hedgehog-mode-debug": true, + "$feature/auto-redirect": true, + "$feature/session-recording-blob-replay": true, + "$feature/surveys": true, + "$feature/generic-signup-benefits": true, + "$feature/surveys-positions": true, + "$feature/web-analytics": true, + "$feature/high-frequency-batch-exports": true, + "$feature/exception-autocapture": true, + "$feature/data-warehouse": true, + "$feature/data-warehouse-views": true, + "$feature/ff-dashboard-templates": true, + "$feature/show-product-intro-existing-products": true, + "$feature/artificial-hog": true, + "$feature/cs-dashboards": true, + "$feature/product-specific-onboarding": true, + "$feature/redirect-signups-to-instance": true, + "$feature/apps-and-exports-ui": true, + "$feature/survey-nps-results": true, + "$feature/session-recording-allow-v1-snapshots": true, + "$feature/session-replay-cors-proxy": true, + "$feature/webhooks-denylist": true, + "$feature/surveys-site-app-deprecation": true, + "$feature/surveys-multiple-questions": true, + "$feature/surveys-results-visualizations": true, + "$feature/console-recording-search": true, + "$feature/persons-hogql-query": true, + "$feature/notebooks": true, + "$feature_flag_payloads": {}, + "realm": "hosted-clickhouse", + "email_service_available": false, + "slack_service_available": false, + "$user_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "is_demo_project": false, + "$groups": { + "project": "018a92f8-b602-0000-75de-4b9073693531", + "organization": "018a92f8-afff-0000-efec-ca77de39e384", + "customer": "cus_OdSgxxWtHOtq9g", + "instance": "http://localhost:8000" + }, + "has_billing_plan": true, + "customer_deactivated": false, + "current_total_amount_usd": "0.00", + "percentage_usage.product_analytics": 0, + "current_amount_usd.product_analytics": "0.00", + "unit_amount_usd.product_analytics": null, + "usage_limit.product_analytics": null, + "current_usage.product_analytics": 3729, + "projected_usage.product_analytics": 0, + "free_allocation.product_analytics": 0, + "percentage_usage.session_replay": 0, + "current_amount_usd.session_replay": "0.00", + "unit_amount_usd.session_replay": null, + "usage_limit.session_replay": null, + "current_usage.session_replay": 254, + "projected_usage.session_replay": 0, + "free_allocation.session_replay": 0, + "percentage_usage.feature_flags": 0, + "current_amount_usd.feature_flags": "0.00", + "unit_amount_usd.feature_flags": null, + "usage_limit.feature_flags": null, + "current_usage.feature_flags": 0, + "projected_usage.feature_flags": 0, + "free_allocation.feature_flags": 0, + "percentage_usage.integrations": 0, + "current_amount_usd.integrations": null, + "unit_amount_usd.integrations": null, + "usage_limit.integrations": 0, + "current_usage.integrations": 0, + "projected_usage.integrations": 0, + "free_allocation.integrations": 0, + "percentage_usage.platform_and_support": 0, + "current_amount_usd.platform_and_support": null, + "unit_amount_usd.platform_and_support": null, + "usage_limit.platform_and_support": 0, + "current_usage.platform_and_support": 0, + "projected_usage.platform_and_support": 0, + "free_allocation.platform_and_support": 0, + "billing_period_start": "2023-10-14T09:22:33.000Z", + "billing_period_end": "2023-11-14T09:22:33.000Z", + "$referrer": "$direct", + "$referring_domain": "$direct", + "token": "phc_OWGI2wKbfi7rWDZT9wkl8uGcfe0wOGCvflLEZSMiaT0", + "$session_id": "018b4ca3-1d07-7195-8202-c8a103a9325a", + "$window_id": "018b4cc2-9078-7092-8d1a-e6d2368f35a3", + "$ip": "127.0.0.1", + "$set": { + "$os": "Mac OS X", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/", + "$pathname": "/", + "$browser_version": 117, + "$referrer": "$direct", + "$referring_domain": "$direct" + }, + "$set_once": { + "$initial_os": "Mac OS X", + "$initial_browser": "Chrome", + "$initial_device_type": "Desktop", + "$initial_current_url": "http://localhost:8000/", + "$initial_pathname": "/", + "$initial_browser_version": 117, + "$initial_referrer": "$direct", + "$initial_referring_domain": "$direct" + }, + "$sent_at": "2023-10-20T11:05:01.307000+00:00", + "$geoip_city_name": "Sydney", + "$geoip_country_name": "Australia", + "$geoip_country_code": "AU", + "$geoip_continent_name": "Oceania", + "$geoip_continent_code": "OC", + "$geoip_postal_code": "2000", + "$geoip_latitude": -33.8715, + "$geoip_longitude": 151.2006, + "$geoip_time_zone": "Australia/Sydney", + "$geoip_subdivision_1_code": "NSW", + "$geoip_subdivision_1_name": "New South Wales", + "$plugins_succeeded": ["GeoIP (1)"], + "$plugins_failed": [], + "$plugins_deferred": [], + "$group_3": "018a92f8-b602-0000-75de-4b9073693531", + "$group_2": "018a92f8-afff-0000-efec-ca77de39e384", + "$group_4": "cus_OdSgxxWtHOtq9g", + "$group_1": "http://localhost:8000" + }, + "timestamp": "2023-10-20T11:05:01.309000+00:00", + "uuid": null + }, + { + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "elements": [], + "elements_chain": null, + "event": "$pageview", + "id": "018b4cc2-907c-7bc8-913f-5b1887950b73", + "person": null, + "properties": { + "$os": "Mac OS X", + "$os_version": "10.15.7", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/", + "$host": "localhost:8000", + "$pathname": "/", + "$browser_version": 117, + "$browser_language": "en-GB", + "$screen_height": 982, + "$screen_width": 1512, + "$viewport_height": 859, + "$viewport_width": 1512, + "$lib": "web", + "$lib_version": "1.84.0", + "$insert_id": "l26gbkzemq3muzti", + "$time": 1697799901.308, + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$device_id": "018a92fd-7b25-7770-a050-577e94fd148c", + "$console_log_recording_enabled_server_side": true, + "$session_recording_recorder_version_server_side": "v2", + "$autocapture_disabled_server_side": false, + "$active_feature_flags": [ + "signup-page-4.0", + "cmd-k-search", + "posthog-3000", + "funnels-cue-opt-out-7301", + "retention-breakdown", + "smoothing-interval", + "billing-limit", + "kafka-inspector", + "historical-exports-v2", + "person-on-events-enabled", + "region-select", + "ingestion-warnings-enabled", + "session-reset-on-load", + "recordings-on-feature-flags", + "auto-rollback-feature-flags", + "onboarding-v2-demo", + "feature-flag-rollout-ux", + "role-based-access", + "query_running_time", + "query-timings", + "recording-debugging", + "enable-prompts", + "feedback-scene", + "early-access-feature", + "early-access-feature-site-button", + "hedgehog-mode-debug", + "auto-redirect", + "session-recording-blob-replay", + "surveys", + "generic-signup-benefits", + "surveys-positions", + "web-analytics", + "high-frequency-batch-exports", + "exception-autocapture", + "data-warehouse", + "data-warehouse-views", + "ff-dashboard-templates", + "show-product-intro-existing-products", + "artificial-hog", + "cs-dashboards", + "product-specific-onboarding", + "redirect-signups-to-instance", + "apps-and-exports-ui", + "survey-nps-results", + "session-recording-allow-v1-snapshots", + "session-replay-cors-proxy", + "webhooks-denylist", + "surveys-site-app-deprecation", + "surveys-multiple-questions", + "surveys-results-visualizations", + "console-recording-search", + "persons-hogql-query", + "notebooks" + ], + "$feature/file-previews": false, + "$feature/signup-page-4.0": "control", + "$feature/hogql-insights": false, + "$feature/cmd-k-search": true, + "$feature/posthog-3000": true, + "$feature/funnels-cue-opt-out-7301": true, + "$feature/retention-breakdown": true, + "$feature/smoothing-interval": true, + "$feature/billing-limit": true, + "$feature/kafka-inspector": true, + "$feature/historical-exports-v2": true, + "$feature/person-on-events-enabled": true, + "$feature/region-select": true, + "$feature/ingestion-warnings-enabled": true, + "$feature/session-reset-on-load": true, + "$feature/recordings-on-feature-flags": true, + "$feature/auto-rollback-feature-flags": true, + "$feature/onboarding-v2-demo": true, + "$feature/feature-flag-rollout-ux": true, + "$feature/role-based-access": true, + "$feature/query_running_time": true, + "$feature/query-timings": true, + "$feature/recording-debugging": true, + "$feature/enable-prompts": true, + "$feature/feedback-scene": true, + "$feature/early-access-feature": true, + "$feature/early-access-feature-site-button": true, + "$feature/hedgehog-mode-debug": true, + "$feature/auto-redirect": true, + "$feature/session-recording-blob-replay": true, + "$feature/surveys": true, + "$feature/generic-signup-benefits": true, + "$feature/surveys-positions": true, + "$feature/web-analytics": true, + "$feature/high-frequency-batch-exports": true, + "$feature/exception-autocapture": true, + "$feature/data-warehouse": true, + "$feature/data-warehouse-views": true, + "$feature/ff-dashboard-templates": true, + "$feature/show-product-intro-existing-products": true, + "$feature/artificial-hog": true, + "$feature/cs-dashboards": true, + "$feature/product-specific-onboarding": true, + "$feature/redirect-signups-to-instance": true, + "$feature/apps-and-exports-ui": true, + "$feature/survey-nps-results": true, + "$feature/session-recording-allow-v1-snapshots": true, + "$feature/session-replay-cors-proxy": true, + "$feature/webhooks-denylist": true, + "$feature/surveys-site-app-deprecation": true, + "$feature/surveys-multiple-questions": true, + "$feature/surveys-results-visualizations": true, + "$feature/console-recording-search": true, + "$feature/persons-hogql-query": true, + "$feature/notebooks": true, + "$feature_flag_payloads": {}, + "realm": "hosted-clickhouse", + "email_service_available": false, + "slack_service_available": false, + "$user_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "is_demo_project": false, + "$groups": { + "project": "018a92f8-b602-0000-75de-4b9073693531", + "organization": "018a92f8-afff-0000-efec-ca77de39e384", + "customer": "cus_OdSgxxWtHOtq9g", + "instance": "http://localhost:8000" + }, + "has_billing_plan": true, + "customer_deactivated": false, + "current_total_amount_usd": "0.00", + "percentage_usage.product_analytics": 0, + "current_amount_usd.product_analytics": "0.00", + "unit_amount_usd.product_analytics": null, + "usage_limit.product_analytics": null, + "current_usage.product_analytics": 3729, + "projected_usage.product_analytics": 0, + "free_allocation.product_analytics": 0, + "percentage_usage.session_replay": 0, + "current_amount_usd.session_replay": "0.00", + "unit_amount_usd.session_replay": null, + "usage_limit.session_replay": null, + "current_usage.session_replay": 254, + "projected_usage.session_replay": 0, + "free_allocation.session_replay": 0, + "percentage_usage.feature_flags": 0, + "current_amount_usd.feature_flags": "0.00", + "unit_amount_usd.feature_flags": null, + "usage_limit.feature_flags": null, + "current_usage.feature_flags": 0, + "projected_usage.feature_flags": 0, + "free_allocation.feature_flags": 0, + "percentage_usage.integrations": 0, + "current_amount_usd.integrations": null, + "unit_amount_usd.integrations": null, + "usage_limit.integrations": 0, + "current_usage.integrations": 0, + "projected_usage.integrations": 0, + "free_allocation.integrations": 0, + "percentage_usage.platform_and_support": 0, + "current_amount_usd.platform_and_support": null, + "unit_amount_usd.platform_and_support": null, + "usage_limit.platform_and_support": 0, + "current_usage.platform_and_support": 0, + "projected_usage.platform_and_support": 0, + "free_allocation.platform_and_support": 0, + "billing_period_start": "2023-10-14T09:22:33.000Z", + "billing_period_end": "2023-11-14T09:22:33.000Z", + "$referrer": "$direct", + "$referring_domain": "$direct", + "title": "PostHog", + "token": "phc_OWGI2wKbfi7rWDZT9wkl8uGcfe0wOGCvflLEZSMiaT0", + "$session_id": "018b4ca3-1d07-7195-8202-c8a103a9325a", + "$window_id": "018b4cc2-9078-7092-8d1a-e6d2368f35a3", + "$ip": "127.0.0.1", + "$set": { + "$os": "Mac OS X", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/", + "$pathname": "/", + "$browser_version": 117, + "$referrer": "$direct", + "$referring_domain": "$direct" + }, + "$set_once": { + "$initial_os": "Mac OS X", + "$initial_browser": "Chrome", + "$initial_device_type": "Desktop", + "$initial_current_url": "http://localhost:8000/", + "$initial_pathname": "/", + "$initial_browser_version": 117, + "$initial_referrer": "$direct", + "$initial_referring_domain": "$direct" + }, + "$sent_at": "2023-10-20T11:05:01.308000+00:00", + "$geoip_city_name": "Sydney", + "$geoip_country_name": "Australia", + "$geoip_country_code": "AU", + "$geoip_continent_name": "Oceania", + "$geoip_continent_code": "OC", + "$geoip_postal_code": "2000", + "$geoip_latitude": -33.8715, + "$geoip_longitude": 151.2006, + "$geoip_time_zone": "Australia/Sydney", + "$geoip_subdivision_1_code": "NSW", + "$geoip_subdivision_1_name": "New South Wales", + "$plugins_succeeded": ["GeoIP (1)"], + "$plugins_failed": [], + "$plugins_deferred": [], + "$group_3": "018a92f8-b602-0000-75de-4b9073693531", + "$group_2": "018a92f8-afff-0000-efec-ca77de39e384", + "$group_4": "cus_OdSgxxWtHOtq9g", + "$group_1": "http://localhost:8000" + }, + "timestamp": "2023-10-20T11:05:01.312000+00:00", + "uuid": null + }, + { + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "elements": [], + "elements_chain": null, + "event": "$pageleave", + "id": "018b4cc3-527c-7bc2-b270-1e09559a1460", + "person": null, + "properties": { + "$os": "Mac OS X", + "$os_version": "10.15.7", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI#activeTab=feed&state=eyJ0eXBlIjoiZG9jIiwiY29udGVudCI6W3sidHlwZSI6ImhlYWRpbmciLCJhdHRycyI6eyJsZXZlbCI6MX0sImNvbnRlbnQiOlt7InR5cGUiOiJ0ZXh0IiwidGV4dCI6ImtyUmZnb3BzVXkxVHdOVTF5aFNETHFORFRkNk41dE1ackhsbThuTEpJREkifV19LHsidHlwZSI6InBoLXBlcnNvbi1mZWVkIiwiYXR0cnMiOnsiaGVpZ2h0IjpudWxsLCJ0aXRsZSI6bnVsbCwibm9kZUlkIjoiNmQ0ODUwNjYtZWM5OS00ODNkLThiOTgtNGQ4YTJkYzljYzRiIiwiaWQiOiJrclJmZ29wc1V5MVR3TlUxeWhTRExxTkRUZDZONXRNWnJIbG04bkxKSURJIiwiX19pbml0IjpudWxsLCJjaGlsZHJlbiI6W3sidHlwZSI6InBoLXBlcnNvbiIsImF0dHJzIjp7ImlkIjoia3JSZmdvcHNVeTFUd05VMXloU0RMcU5EVGQ2TjV0TVpySGxtOG5MSklESSIsIm5vZGVJZCI6IjE0NDk2Y2ExLWUyNTUtNDlkMS1hM2IzLWU4ZjA1NzhhYjQ5YiJ9fSx7InR5cGUiOiJwaC1tYXAiLCJhdHRycyI6eyJpZCI6ImtyUmZnb3BzVXkxVHdOVTF5aFNETHFORFRkNk41dE1ackhsbThuTEpJREkiLCJub2RlSWQiOiJmMzgxYmFkOC1kMTNkLTQyOGItODYyNC03YTFkNTBhODBkMjMifX0seyJ0eXBlIjoicGgtcHJvcGVydGllcyIsImF0dHJzIjp7ImlkIjoia3JSZmdvcHNVeTFUd05VMXloU0RMcU5EVGQ2TjV0TVpySGxtOG5MSklESSIsIm5vZGVJZCI6ImE5Y2ZlOTlhLTRiZTktNDU1YS04OWMyLTViZGUyMGY2MWQwMiJ9fV19fV19", + "$host": "localhost:8000", + "$pathname": "/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$browser_version": 117, + "$browser_language": "en-GB", + "$screen_height": 982, + "$screen_width": 1512, + "$viewport_height": 859, + "$viewport_width": 1512, + "$lib": "web", + "$lib_version": "1.84.0", + "$insert_id": "ubvpv3ao6iaj9wk8", + "$time": 1697799950.972, + "distinct_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$device_id": "018a92fd-7b25-7770-a050-577e94fd148c", + "$console_log_recording_enabled_server_side": true, + "$session_recording_recorder_version_server_side": "v2", + "$autocapture_disabled_server_side": false, + "$active_feature_flags": [ + "signup-page-4.0", + "cmd-k-search", + "posthog-3000", + "funnels-cue-opt-out-7301", + "retention-breakdown", + "smoothing-interval", + "billing-limit", + "kafka-inspector", + "historical-exports-v2", + "person-on-events-enabled", + "region-select", + "ingestion-warnings-enabled", + "session-reset-on-load", + "recordings-on-feature-flags", + "auto-rollback-feature-flags", + "onboarding-v2-demo", + "feature-flag-rollout-ux", + "role-based-access", + "query_running_time", + "query-timings", + "recording-debugging", + "enable-prompts", + "feedback-scene", + "early-access-feature", + "early-access-feature-site-button", + "hedgehog-mode-debug", + "auto-redirect", + "session-recording-blob-replay", + "surveys", + "generic-signup-benefits", + "surveys-positions", + "web-analytics", + "high-frequency-batch-exports", + "exception-autocapture", + "data-warehouse", + "data-warehouse-views", + "ff-dashboard-templates", + "show-product-intro-existing-products", + "artificial-hog", + "cs-dashboards", + "product-specific-onboarding", + "redirect-signups-to-instance", + "apps-and-exports-ui", + "survey-nps-results", + "session-recording-allow-v1-snapshots", + "session-replay-cors-proxy", + "webhooks-denylist", + "surveys-site-app-deprecation", + "surveys-multiple-questions", + "surveys-results-visualizations", + "console-recording-search", + "persons-hogql-query", + "notebooks" + ], + "$feature/file-previews": false, + "$feature/signup-page-4.0": "control", + "$feature/hogql-insights": false, + "$feature/cmd-k-search": true, + "$feature/posthog-3000": true, + "$feature/funnels-cue-opt-out-7301": true, + "$feature/retention-breakdown": true, + "$feature/smoothing-interval": true, + "$feature/billing-limit": true, + "$feature/kafka-inspector": true, + "$feature/historical-exports-v2": true, + "$feature/person-on-events-enabled": true, + "$feature/region-select": true, + "$feature/ingestion-warnings-enabled": true, + "$feature/session-reset-on-load": true, + "$feature/recordings-on-feature-flags": true, + "$feature/auto-rollback-feature-flags": true, + "$feature/onboarding-v2-demo": true, + "$feature/feature-flag-rollout-ux": true, + "$feature/role-based-access": true, + "$feature/query_running_time": true, + "$feature/query-timings": true, + "$feature/recording-debugging": true, + "$feature/enable-prompts": true, + "$feature/feedback-scene": true, + "$feature/early-access-feature": true, + "$feature/early-access-feature-site-button": true, + "$feature/hedgehog-mode-debug": true, + "$feature/auto-redirect": true, + "$feature/session-recording-blob-replay": true, + "$feature/surveys": true, + "$feature/generic-signup-benefits": true, + "$feature/surveys-positions": true, + "$feature/web-analytics": true, + "$feature/high-frequency-batch-exports": true, + "$feature/exception-autocapture": true, + "$feature/data-warehouse": true, + "$feature/data-warehouse-views": true, + "$feature/ff-dashboard-templates": true, + "$feature/show-product-intro-existing-products": true, + "$feature/artificial-hog": true, + "$feature/cs-dashboards": true, + "$feature/product-specific-onboarding": true, + "$feature/redirect-signups-to-instance": true, + "$feature/apps-and-exports-ui": true, + "$feature/survey-nps-results": true, + "$feature/session-recording-allow-v1-snapshots": true, + "$feature/session-replay-cors-proxy": true, + "$feature/webhooks-denylist": true, + "$feature/surveys-site-app-deprecation": true, + "$feature/surveys-multiple-questions": true, + "$feature/surveys-results-visualizations": true, + "$feature/console-recording-search": true, + "$feature/persons-hogql-query": true, + "$feature/notebooks": true, + "$feature_flag_payloads": {}, + "realm": "hosted-clickhouse", + "email_service_available": false, + "slack_service_available": false, + "$user_id": "krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "is_demo_project": false, + "$groups": { + "project": "018a92f8-b602-0000-75de-4b9073693531", + "organization": "018a92f8-afff-0000-efec-ca77de39e384", + "customer": "cus_OdSgxxWtHOtq9g", + "instance": "http://localhost:8000" + }, + "has_billing_plan": true, + "customer_deactivated": false, + "current_total_amount_usd": "0.00", + "percentage_usage.product_analytics": 0, + "current_amount_usd.product_analytics": "0.00", + "unit_amount_usd.product_analytics": null, + "usage_limit.product_analytics": null, + "current_usage.product_analytics": 3729, + "projected_usage.product_analytics": 0, + "free_allocation.product_analytics": 0, + "percentage_usage.session_replay": 0, + "current_amount_usd.session_replay": "0.00", + "unit_amount_usd.session_replay": null, + "usage_limit.session_replay": null, + "current_usage.session_replay": 254, + "projected_usage.session_replay": 0, + "free_allocation.session_replay": 0, + "percentage_usage.feature_flags": 0, + "current_amount_usd.feature_flags": "0.00", + "unit_amount_usd.feature_flags": null, + "usage_limit.feature_flags": null, + "current_usage.feature_flags": 0, + "projected_usage.feature_flags": 0, + "free_allocation.feature_flags": 0, + "percentage_usage.integrations": 0, + "current_amount_usd.integrations": null, + "unit_amount_usd.integrations": null, + "usage_limit.integrations": 0, + "current_usage.integrations": 0, + "projected_usage.integrations": 0, + "free_allocation.integrations": 0, + "percentage_usage.platform_and_support": 0, + "current_amount_usd.platform_and_support": null, + "unit_amount_usd.platform_and_support": null, + "usage_limit.platform_and_support": 0, + "current_usage.platform_and_support": 0, + "projected_usage.platform_and_support": 0, + "free_allocation.platform_and_support": 0, + "billing_period_start": "2023-10-14T09:22:33.000Z", + "billing_period_end": "2023-11-14T09:22:33.000Z", + "$referrer": "$direct", + "$referring_domain": "$direct", + "token": "phc_OWGI2wKbfi7rWDZT9wkl8uGcfe0wOGCvflLEZSMiaT0", + "$session_id": "018b4ca3-1d07-7195-8202-c8a103a9325a", + "$window_id": "018b4ca3-1d07-7195-8202-c8a2b00ad68a", + "$ip": "127.0.0.1", + "$set": { + "$os": "Mac OS X", + "$browser": "Chrome", + "$device_type": "Desktop", + "$current_url": "http://localhost:8000/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI#activeTab=feed&state=eyJ0eXBlIjoiZG9jIiwiY29udGVudCI6W3sidHlwZSI6ImhlYWRpbmciLCJhdHRycyI6eyJsZXZlbCI6MX0sImNvbnRlbnQiOlt7InR5cGUiOiJ0ZXh0IiwidGV4dCI6ImtyUmZnb3BzVXkxVHdOVTF5aFNETHFORFRkNk41dE1ackhsbThuTEpJREkifV19LHsidHlwZSI6InBoLXBlcnNvbi1mZWVkIiwiYXR0cnMiOnsiaGVpZ2h0IjpudWxsLCJ0aXRsZSI6bnVsbCwibm9kZUlkIjoiNmQ0ODUwNjYtZWM5OS00ODNkLThiOTgtNGQ4YTJkYzljYzRiIiwiaWQiOiJrclJmZ29wc1V5MVR3TlUxeWhTRExxTkRUZDZONXRNWnJIbG04bkxKSURJIiwiX19pbml0IjpudWxsLCJjaGlsZHJlbiI6W3sidHlwZSI6InBoLXBlcnNvbiIsImF0dHJzIjp7ImlkIjoia3JSZmdvcHNVeTFUd05VMXloU0RMcU5EVGQ2TjV0TVpySGxtOG5MSklESSIsIm5vZGVJZCI6IjE0NDk2Y2ExLWUyNTUtNDlkMS1hM2IzLWU4ZjA1NzhhYjQ5YiJ9fSx7InR5cGUiOiJwaC1tYXAiLCJhdHRycyI6eyJpZCI6ImtyUmZnb3BzVXkxVHdOVTF5aFNETHFORFRkNk41dE1ackhsbThuTEpJREkiLCJub2RlSWQiOiJmMzgxYmFkOC1kMTNkLTQyOGItODYyNC03YTFkNTBhODBkMjMifX0seyJ0eXBlIjoicGgtcHJvcGVydGllcyIsImF0dHJzIjp7ImlkIjoia3JSZmdvcHNVeTFUd05VMXloU0RMcU5EVGQ2TjV0TVpySGxtOG5MSklESSIsIm5vZGVJZCI6ImE5Y2ZlOTlhLTRiZTktNDU1YS04OWMyLTViZGUyMGY2MWQwMiJ9fV19fV19", + "$pathname": "/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$browser_version": 117, + "$referrer": "$direct", + "$referring_domain": "$direct" + }, + "$set_once": { + "$initial_os": "Mac OS X", + "$initial_browser": "Chrome", + "$initial_device_type": "Desktop", + "$initial_current_url": "http://localhost:8000/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI#activeTab=feed&state=eyJ0eXBlIjoiZG9jIiwiY29udGVudCI6W3sidHlwZSI6ImhlYWRpbmciLCJhdHRycyI6eyJsZXZlbCI6MX0sImNvbnRlbnQiOlt7InR5cGUiOiJ0ZXh0IiwidGV4dCI6ImtyUmZnb3BzVXkxVHdOVTF5aFNETHFORFRkNk41dE1ackhsbThuTEpJREkifV19LHsidHlwZSI6InBoLXBlcnNvbi1mZWVkIiwiYXR0cnMiOnsiaGVpZ2h0IjpudWxsLCJ0aXRsZSI6bnVsbCwibm9kZUlkIjoiNmQ0ODUwNjYtZWM5OS00ODNkLThiOTgtNGQ4YTJkYzljYzRiIiwiaWQiOiJrclJmZ29wc1V5MVR3TlUxeWhTRExxTkRUZDZONXRNWnJIbG04bkxKSURJIiwiX19pbml0IjpudWxsLCJjaGlsZHJlbiI6W3sidHlwZSI6InBoLXBlcnNvbiIsImF0dHJzIjp7ImlkIjoia3JSZmdvcHNVeTFUd05VMXloU0RMcU5EVGQ2TjV0TVpySGxtOG5MSklESSIsIm5vZGVJZCI6IjE0NDk2Y2ExLWUyNTUtNDlkMS1hM2IzLWU4ZjA1NzhhYjQ5YiJ9fSx7InR5cGUiOiJwaC1tYXAiLCJhdHRycyI6eyJpZCI6ImtyUmZnb3BzVXkxVHdOVTF5aFNETHFORFRkNk41dE1ackhsbThuTEpJREkiLCJub2RlSWQiOiJmMzgxYmFkOC1kMTNkLTQyOGItODYyNC03YTFkNTBhODBkMjMifX0seyJ0eXBlIjoicGgtcHJvcGVydGllcyIsImF0dHJzIjp7ImlkIjoia3JSZmdvcHNVeTFUd05VMXloU0RMcU5EVGQ2TjV0TVpySGxtOG5MSklESSIsIm5vZGVJZCI6ImE5Y2ZlOTlhLTRiZTktNDU1YS04OWMyLTViZGUyMGY2MWQwMiJ9fV19fV19", + "$initial_pathname": "/person/krRfgopsUy1TwNU1yhSDLqNDTd6N5tMZrHlm8nLJIDI", + "$initial_browser_version": 117, + "$initial_referrer": "$direct", + "$initial_referring_domain": "$direct" + }, + "$sent_at": "2023-10-20T11:05:50.975000+00:00", + "$geoip_city_name": "Sydney", + "$geoip_country_name": "Australia", + "$geoip_country_code": "AU", + "$geoip_continent_name": "Oceania", + "$geoip_continent_code": "OC", + "$geoip_postal_code": "2000", + "$geoip_latitude": -33.8715, + "$geoip_longitude": 151.2006, + "$geoip_time_zone": "Australia/Sydney", + "$geoip_subdivision_1_code": "NSW", + "$geoip_subdivision_1_name": "New South Wales", + "$plugins_succeeded": ["GeoIP (1)"], + "$plugins_failed": [], + "$plugins_deferred": [], + "$group_3": "018a92f8-b602-0000-75de-4b9073693531", + "$group_2": "018a92f8-afff-0000-efec-ca77de39e384", + "$group_4": "cus_OdSgxxWtHOtq9g", + "$group_1": "http://localhost:8000" + }, + "timestamp": "2023-10-20T11:05:50.993000+00:00", + "uuid": null + } + ], + "recording_duration_s": 2114.0, + "sessionId": "018b4ca3-1d07-7195-8202-c8a103a9325a" + } + ], + "timings": [ + { + "k": "./build_ast", + "t": 0.023964583000633866 + }, + { + "k": "./query", + "t": 4.433299181982875e-5 + }, + { + "k": "./replace_placeholders", + "t": 0.00022916699526831508 + }, + { + "k": "./max_limit", + "t": 4.520895890891552e-5 + }, + { + "k": "./hogql/prepare_ast/clone", + "t": 0.0003998330212198198 + }, + { + "k": "./hogql/prepare_ast/create_hogql_database", + "t": 0.026486458024010062 + }, + { + "k": "./hogql/prepare_ast/resolve_types", + "t": 0.0021655409946106374 + }, + { + "k": "./hogql/prepare_ast", + "t": 0.02919254096923396 + }, + { + "k": "./hogql/print_ast/printer", + "t": 0.001116375089623034 + }, + { + "k": "./hogql/print_ast", + "t": 0.0012727080029435456 + }, + { + "k": "./hogql", + "t": 0.03451150003820658 + }, + { + "k": "./print_ast/create_hogql_database", + "t": 0.020703041984234005 + }, + { + "k": "./print_ast/resolve_types", + "t": 0.0019762919982895255 + }, + { + "k": "./print_ast/resolve_property_types", + "t": 0.0009936250280588865 + }, + { + "k": "./print_ast/resolve_lazy_tables", + "t": 0.001264624996110797 + }, + { + "k": "./print_ast/printer", + "t": 0.0024609589600004256 + }, + { + "k": "./print_ast", + "t": 0.027551917009986937 + }, + { + "k": "./clickhouse_execute", + "t": 0.65883087500697 + }, + { + "k": ".", + "t": 0.7931497080135159 + } + ] +} diff --git a/frontend/src/scenes/notebooks/Nodes/NotebookNodePersonFeed/notebookNodePersonFeedLogic.ts b/frontend/src/scenes/notebooks/Nodes/NotebookNodePersonFeed/notebookNodePersonFeedLogic.ts new file mode 100644 index 0000000000000..1768b80caf50e --- /dev/null +++ b/frontend/src/scenes/notebooks/Nodes/NotebookNodePersonFeed/notebookNodePersonFeedLogic.ts @@ -0,0 +1,45 @@ +import { kea, key, path, props, afterMount } from 'kea' +import { loaders } from 'kea-loaders' + +// import { query } from '~/queries/query' +// import { +// // NodeKind, +// // SessionsTimelineQuery, +// SessionsTimelineQueryResponse, +// } from '~/queries/schema' + +import mockSessionsTimelineQueryResponse from './mockSessionsTimelineQueryResponse.json' + +import type { notebookNodePersonFeedLogicType } from './notebookNodePersonFeedLogicType' + +export type NotebookNodePersonFeedLogicProps = { + personId: string +} + +export const notebookNodePersonFeedLogic = kea([ + props({} as NotebookNodePersonFeedLogicProps), + path((key) => ['scenes', 'notebooks', 'Notebook', 'Nodes', 'notebookNodePersonFeedLogic', key]), + key(({ personId }) => personId), + + loaders(() => ({ + sessions: [ + // null as SessionsTimelineQueryResponse['results'] | null, + null as any | null, + { + loadSessionsTimeline: async () => { + // const result = await query({ + // kind: NodeKind.SessionsTimelineQuery, + // after: '2021-01-01T18:00:00Z', + // before: '2024-01-01T06:00:00Z', + // personId: props.personId, + // }) + const result = mockSessionsTimelineQueryResponse + return result.results + }, + }, + ], + })), + afterMount(({ actions }) => { + actions.loadSessionsTimeline() + }), +]) diff --git a/frontend/src/scenes/notebooks/Notebook/Editor.tsx b/frontend/src/scenes/notebooks/Notebook/Editor.tsx index 4b5cdaa3d8eda..51cf23c4166d1 100644 --- a/frontend/src/scenes/notebooks/Notebook/Editor.tsx +++ b/frontend/src/scenes/notebooks/Notebook/Editor.tsx @@ -38,6 +38,7 @@ import { notebookLogic } from './notebookLogic' import { sampleOne } from 'lib/utils' import { NotebookNodeGroup } from '../Nodes/NotebookNodeGroup' import { NotebookNodeCohort } from '../Nodes/NotebookNodeCohort' +import { NotebookNodePersonFeed } from '../Nodes/NotebookNodePersonFeed/NotebookNodePersonFeed' const CustomDocument = ExtensionDocument.extend({ content: 'heading block*', @@ -118,6 +119,7 @@ export function Editor(): JSX.Element { SlashCommandsExtension, BacklinkCommandsExtension, NodeGapInsertionExtension, + NotebookNodePersonFeed, ], editorProps: { handleDrop: (view, event, _slice, moved) => { diff --git a/frontend/src/scenes/notebooks/Notebook/utils.ts b/frontend/src/scenes/notebooks/Notebook/utils.ts index b21ff74c82db7..d0f9a67ac9b6d 100644 --- a/frontend/src/scenes/notebooks/Notebook/utils.ts +++ b/frontend/src/scenes/notebooks/Notebook/utils.ts @@ -124,6 +124,7 @@ export const textContent = (node: any): string => { 'ph-survey': customOrTitleSerializer, 'ph-group': customOrTitleSerializer, 'ph-cohort': customOrTitleSerializer, + 'ph-person-feed': customOrTitleSerializer, } return getText(node, { diff --git a/frontend/src/scenes/notebooks/NotebooksTable/ContainsTypeFilter.tsx b/frontend/src/scenes/notebooks/NotebooksTable/ContainsTypeFilter.tsx index dc0c082733816..10c2ba86f8239 100644 --- a/frontend/src/scenes/notebooks/NotebooksTable/ContainsTypeFilter.tsx +++ b/frontend/src/scenes/notebooks/NotebooksTable/ContainsTypeFilter.tsx @@ -2,7 +2,10 @@ import { NotebookNodeType } from '~/types' import { LemonSelectMultiple } from 'lib/lemon-ui/LemonSelectMultiple' import { NotebooksListFilters } from 'scenes/notebooks/NotebooksTable/notebooksTableLogic' -export const fromNodeTypeToLabel: Omit, NotebookNodeType.Backlink> = { +export const fromNodeTypeToLabel: Omit< + Record, + NotebookNodeType.Backlink | NotebookNodeType.PersonFeed +> = { [NotebookNodeType.FeatureFlag]: 'Feature flags', [NotebookNodeType.FeatureFlagCodeExample]: 'Feature flag Code Examples', [NotebookNodeType.Experiment]: 'Experiments', diff --git a/frontend/src/scenes/persons/PersonFeedCanvas.tsx b/frontend/src/scenes/persons/PersonFeedCanvas.tsx index d2de1646a62d5..1195b958aff42 100644 --- a/frontend/src/scenes/persons/PersonFeedCanvas.tsx +++ b/frontend/src/scenes/persons/PersonFeedCanvas.tsx @@ -24,7 +24,7 @@ const PersonFeedCanvas = ({ person }: PersonFeedCanvasProps): JSX.Element => { attrs: { height: null, title: null, - nodeId: '6d485066-ec99-483d-8b98-4d8a2dc9cc4b', + nodeId: uuid(), id: personId, __init: null, children: [ @@ -32,14 +32,6 @@ const PersonFeedCanvas = ({ person }: PersonFeedCanvasProps): JSX.Element => { type: 'ph-person', attrs: { id: personId, nodeId: uuid(), title: 'Info' }, }, - { - type: 'ph-map', - attrs: { id: personId, nodeId: uuid() }, - }, - { - type: 'ph-properties', - attrs: { id: personId, nodeId: uuid() }, - }, ], }, }, diff --git a/frontend/src/scenes/persons/PersonScene.tsx b/frontend/src/scenes/persons/PersonScene.tsx index 2a7a277deda10..bce2a2b72d130 100644 --- a/frontend/src/scenes/persons/PersonScene.tsx +++ b/frontend/src/scenes/persons/PersonScene.tsx @@ -34,6 +34,7 @@ import { LemonTabs } from 'lib/lemon-ui/LemonTabs' import { PersonDashboard } from './PersonDashboard' import { NotebookSelectButton } from 'scenes/notebooks/NotebookSelectButton/NotebookSelectButton' import { SessionRecordingsPlaylist } from 'scenes/session-recordings/playlist/SessionRecordingsPlaylist' +import PersonFeedCanvas from './PersonFeedCanvas' export const scene: SceneExport = { component: PersonScene, @@ -109,6 +110,7 @@ function PersonCaption({ person }: { person: PersonType }): JSX.Element { export function PersonScene(): JSX.Element | null { const { showCustomerSuccessDashboards, + feedEnabled, person, personLoading, currentTab, @@ -185,6 +187,13 @@ export function PersonScene(): JSX.Element | null { }} data-attr="persons-tabs" tabs={[ + feedEnabled + ? { + key: PersonsTabType.FEED, + label: Feed, + content: , + } + : false, { key: PersonsTabType.PROPERTIES, label: Properties, diff --git a/frontend/src/scenes/persons/personsLogic.tsx b/frontend/src/scenes/persons/personsLogic.tsx index 005924ec56924..eb1c15fd49a11 100644 --- a/frontend/src/scenes/persons/personsLogic.tsx +++ b/frontend/src/scenes/persons/personsLogic.tsx @@ -136,11 +136,10 @@ export const personsLogic = kea({ : 'https://posthog.com/docs/api/persons', ], cohortId: [() => [(_, props) => props.cohort], (cohort: PersonsLogicProps['cohort']) => cohort], - currentTab: [ - (s) => [s.activeTab], - (activeTab) => { - return activeTab || PersonsTabType.PROPERTIES - }, + currentTab: [(s) => [s.activeTab, s.defaultTab], (activeTab, defaultTab) => activeTab || defaultTab], + defaultTab: [ + (s) => [s.feedEnabled], + (feedEnabled) => (feedEnabled ? PersonsTabType.FEED : PersonsTabType.PROPERTIES), ], breadcrumbs: [ (s) => [s.person, router.selectors.location], @@ -179,6 +178,7 @@ export const personsLogic = kea({ (s) => [s.featureFlags], (featureFlags) => featureFlags[FEATURE_FLAGS.CS_DASHBOARDS], ], + feedEnabled: [(s) => [s.featureFlags], (featureFlags) => !!featureFlags[FEATURE_FLAGS.PERSON_FEED_CANVAS]], }), listeners: ({ actions, values }) => ({ editProperty: async ({ key, newValue }) => { @@ -375,7 +375,7 @@ export const personsLogic = kea({ } if (!activeTab) { - actions.setActiveTab(PersonsTabType.PROPERTIES) + actions.setActiveTab(values.defaultTab) } if (rawPersonDistinctId) { @@ -397,7 +397,7 @@ export const personsLogic = kea({ } if (!activeTab) { - actions.setActiveTab(PersonsTabType.PROPERTIES) + actions.setActiveTab(values.defaultTab) } if (rawPersonUUID) { diff --git a/frontend/src/types.ts b/frontend/src/types.ts index a8b702e55b296..cd88a6686260e 100644 --- a/frontend/src/types.ts +++ b/frontend/src/types.ts @@ -935,6 +935,7 @@ export enum StepOrderValue { } export enum PersonsTabType { + FEED = 'feed', EVENTS = 'events', SESSION_RECORDINGS = 'sessionRecordings', PROPERTIES = 'properties', @@ -3080,6 +3081,7 @@ export enum NotebookNodeType { Backlink = 'ph-backlink', ReplayTimestamp = 'ph-replay-timestamp', Image = 'ph-image', + PersonFeed = 'ph-person-feed', } export type NotebookNodeResource = { From 4412c2cbeb7b974c2eb94a24f0d0cc7f147fb75d Mon Sep 17 00:00:00 2001 From: Ben White Date: Thu, 26 Oct 2023 09:20:43 +0200 Subject: [PATCH 11/21] feat: Person feed map (#18184) --- .env.example | 1 + .../components-map--unavailable.png | Bin 0 -> 10618 bytes frontend/src/globals.d.ts | 1 + .../src/lib/components/Map/Map.stories.tsx | 31 + frontend/src/lib/components/Map/Map.tsx | 64 ++ .../notebooks/Nodes/NotebookNodeMap.tsx | 64 ++ .../components/NotebookNodeEmptyState.tsx | 11 + .../src/scenes/notebooks/Notebook/Editor.tsx | 2 + .../src/scenes/notebooks/Notebook/utils.ts | 1 + .../NotebooksTable/ContainsTypeFilter.tsx | 2 +- .../src/scenes/persons/PersonFeedCanvas.tsx | 4 + frontend/src/types.ts | 1 + package.json | 1 + pnpm-lock.yaml | 723 +++++++++++++----- posthog/settings/__init__.py | 3 + posthog/templates/head.html | 5 + posthog/utils.py | 3 + 17 files changed, 719 insertions(+), 198 deletions(-) create mode 100644 .env.example create mode 100644 frontend/__snapshots__/components-map--unavailable.png create mode 100644 frontend/src/lib/components/Map/Map.stories.tsx create mode 100644 frontend/src/lib/components/Map/Map.tsx create mode 100644 frontend/src/scenes/notebooks/Nodes/NotebookNodeMap.tsx create mode 100644 frontend/src/scenes/notebooks/Nodes/components/NotebookNodeEmptyState.tsx diff --git a/.env.example b/.env.example new file mode 100644 index 0000000000000..65971db798cd3 --- /dev/null +++ b/.env.example @@ -0,0 +1 @@ +MAPLIBRE_STYLE_URL=https://api.example.com/style.json?key=mykey \ No newline at end of file diff --git a/frontend/__snapshots__/components-map--unavailable.png b/frontend/__snapshots__/components-map--unavailable.png new file mode 100644 index 0000000000000000000000000000000000000000..6e49827d9e782bb66576ac1937a76d237851743d GIT binary patch literal 10618 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

MSb;d%Rn&7=C2VuhdtJncl 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 = { + title: 'Components/Map', + component: Map, + tags: ['autodocs'], +} +type Story = StoryObj + +const coordinates: [number, number] = [0.119167, 52.205276] + +export const Unavailable: Story = {} + +export const Basic: Story = { + render: (args) => ( + + ), + args: { + center: coordinates, + markers: [new Marker({ color: 'var(--primary)' }).setLngLat(coordinates)], + className: 'h-60', + }, +} + +export default meta diff --git a/frontend/src/lib/components/Map/Map.tsx b/frontend/src/lib/components/Map/Map.tsx new file mode 100644 index 0000000000000..0b72d136d04d4 --- /dev/null +++ b/frontend/src/lib/components/Map/Map.tsx @@ -0,0 +1,64 @@ +import { useEffect, useRef } from 'react' +import { Map as RawMap, Marker } from 'maplibre-gl' +import useResizeObserver from 'use-resize-observer' + +import 'maplibre-gl/dist/maplibre-gl.css' + +/** Latitude and longtitude in degrees (+lat is east, -lat is west, +lon is south, -lon is north). */ +export interface MapProps { + /** Coordinates to center the map on by default. */ + center: [number, number] + /** Markers to show. */ + markers?: Marker[] + /** Map container class names. */ + className?: string + /** The map's MapLibre style. This must be a JSON object conforming to the schema described in the MapLibre Style Specification, or a URL to such JSON. */ + mapLibreStyleUrl: string +} + +export function Map({ className, ...rest }: Omit): JSX.Element { + if (!window.JS_MAPLIBRE_STYLE_URL) { + return ( +

+

Map unavailable

+

+ The MAPLIBRE_STYLE_URL setting is not defined. Please configure this setting with a + valid MapLibre Style URL to display maps. +

+
+ ) + } + + return +} + +export function MapComponent({ center, markers, className, mapLibreStyleUrl }: MapProps): JSX.Element { + const mapContainer = useRef(null) + const map = useRef(null) + + useEffect(() => { + map.current = new RawMap({ + container: mapContainer.current as HTMLElement, + style: mapLibreStyleUrl, + center, + zoom: 4, + maxZoom: 10, + }) + if (markers) { + for (const marker of markers) { + marker.addTo(map.current) + } + } + }, []) + + useResizeObserver({ + ref: mapContainer, + onResize: () => { + if (map.current) { + map.current.resize() + } + }, + }) + + return
+} diff --git a/frontend/src/scenes/notebooks/Nodes/NotebookNodeMap.tsx b/frontend/src/scenes/notebooks/Nodes/NotebookNodeMap.tsx new file mode 100644 index 0000000000000..f0e5ef1931c7d --- /dev/null +++ b/frontend/src/scenes/notebooks/Nodes/NotebookNodeMap.tsx @@ -0,0 +1,64 @@ +import { Marker } from 'maplibre-gl' + +import { NotebookNodeType } from '~/types' +import { createPostHogWidgetNode } from 'scenes/notebooks/Nodes/NodeWrapper' +import { personLogic } from 'scenes/persons/personLogic' +import { useValues } from 'kea' +import { LemonSkeleton } from '@posthog/lemon-ui' +import { NotFound } from 'lib/components/NotFound' +import { Map } from '../../../lib/components/Map/Map' +import { notebookNodeLogic } from './notebookNodeLogic' +import { NotebookNodeProps } from 'scenes/notebooks/Notebook/utils' +import { NotebookNodeEmptyState } from './components/NotebookNodeEmptyState' + +const Component = ({ attributes }: NotebookNodeProps): JSX.Element | null => { + const { id } = attributes + const { expanded } = useValues(notebookNodeLogic) + + const logic = personLogic({ id }) + const { person, personLoading } = useValues(logic) + + if (personLoading) { + return + } else if (!person) { + return + } + + if (!expanded) { + return null + } + + const longtitude = person?.properties?.['$geoip_longitude'] + const latitude = person?.properties?.['$geoip_latitude'] + const personCoordinates: [number, number] | null = + !isNaN(longtitude) && !isNaN(latitude) ? [longtitude, latitude] : null + + if (!personCoordinates) { + return + } + + return ( + + ) +} + +type NotebookNodeMapAttributes = { + id: string +} + +export const NotebookNodeMap = createPostHogWidgetNode({ + nodeType: NotebookNodeType.Map, + titlePlaceholder: 'Location', + Component, + resizeable: true, + heightEstimate: 150, + expandable: true, + startExpanded: true, + attributes: { + id: {}, + }, +}) diff --git a/frontend/src/scenes/notebooks/Nodes/components/NotebookNodeEmptyState.tsx b/frontend/src/scenes/notebooks/Nodes/components/NotebookNodeEmptyState.tsx new file mode 100644 index 0000000000000..8dd8c292407f3 --- /dev/null +++ b/frontend/src/scenes/notebooks/Nodes/components/NotebookNodeEmptyState.tsx @@ -0,0 +1,11 @@ +type NotebookNodeEmptyStateProps = { + message: string +} + +export function NotebookNodeEmptyState({ message }: NotebookNodeEmptyStateProps): JSX.Element { + return ( +
+ {message} +
+ ) +} diff --git a/frontend/src/scenes/notebooks/Notebook/Editor.tsx b/frontend/src/scenes/notebooks/Notebook/Editor.tsx index 51cf23c4166d1..0954dda2dbb76 100644 --- a/frontend/src/scenes/notebooks/Notebook/Editor.tsx +++ b/frontend/src/scenes/notebooks/Notebook/Editor.tsx @@ -39,6 +39,7 @@ import { sampleOne } from 'lib/utils' import { NotebookNodeGroup } from '../Nodes/NotebookNodeGroup' import { NotebookNodeCohort } from '../Nodes/NotebookNodeCohort' import { NotebookNodePersonFeed } from '../Nodes/NotebookNodePersonFeed/NotebookNodePersonFeed' +import { NotebookNodeMap } from '../Nodes/NotebookNodeMap' const CustomDocument = ExtensionDocument.extend({ content: 'heading block*', @@ -120,6 +121,7 @@ export function Editor(): JSX.Element { BacklinkCommandsExtension, NodeGapInsertionExtension, NotebookNodePersonFeed, + NotebookNodeMap, ], editorProps: { handleDrop: (view, event, _slice, moved) => { diff --git a/frontend/src/scenes/notebooks/Notebook/utils.ts b/frontend/src/scenes/notebooks/Notebook/utils.ts index d0f9a67ac9b6d..085098f5e10be 100644 --- a/frontend/src/scenes/notebooks/Notebook/utils.ts +++ b/frontend/src/scenes/notebooks/Notebook/utils.ts @@ -125,6 +125,7 @@ export const textContent = (node: any): string => { 'ph-group': customOrTitleSerializer, 'ph-cohort': customOrTitleSerializer, 'ph-person-feed': customOrTitleSerializer, + 'ph-map': customOrTitleSerializer, } return getText(node, { diff --git a/frontend/src/scenes/notebooks/NotebooksTable/ContainsTypeFilter.tsx b/frontend/src/scenes/notebooks/NotebooksTable/ContainsTypeFilter.tsx index 10c2ba86f8239..3f91edb487efb 100644 --- a/frontend/src/scenes/notebooks/NotebooksTable/ContainsTypeFilter.tsx +++ b/frontend/src/scenes/notebooks/NotebooksTable/ContainsTypeFilter.tsx @@ -4,7 +4,7 @@ import { NotebooksListFilters } from 'scenes/notebooks/NotebooksTable/notebooksT export const fromNodeTypeToLabel: Omit< Record, - NotebookNodeType.Backlink | NotebookNodeType.PersonFeed + NotebookNodeType.Backlink | NotebookNodeType.PersonFeed | NotebookNodeType.Map > = { [NotebookNodeType.FeatureFlag]: 'Feature flags', [NotebookNodeType.FeatureFlagCodeExample]: 'Feature flag Code Examples', diff --git a/frontend/src/scenes/persons/PersonFeedCanvas.tsx b/frontend/src/scenes/persons/PersonFeedCanvas.tsx index 1195b958aff42..1273fa1c134fc 100644 --- a/frontend/src/scenes/persons/PersonFeedCanvas.tsx +++ b/frontend/src/scenes/persons/PersonFeedCanvas.tsx @@ -32,6 +32,10 @@ const PersonFeedCanvas = ({ person }: PersonFeedCanvasProps): JSX.Element => { type: 'ph-person', attrs: { id: personId, nodeId: uuid(), title: 'Info' }, }, + { + type: 'ph-map', + attrs: { id: personId, nodeId: uuid() }, + }, ], }, }, diff --git a/frontend/src/types.ts b/frontend/src/types.ts index cd88a6686260e..cbcfaa11bd959 100644 --- a/frontend/src/types.ts +++ b/frontend/src/types.ts @@ -3082,6 +3082,7 @@ export enum NotebookNodeType { ReplayTimestamp = 'ph-replay-timestamp', Image = 'ph-image', PersonFeed = 'ph-person-feed', + Map = 'ph-map', } export type NotebookNodeResource = { diff --git a/package.json b/package.json index 8a718827211fd..04efee98671d6 100644 --- a/package.json +++ b/package.json @@ -130,6 +130,7 @@ "kea-test-utils": "^0.2.4", "kea-waitfor": "^0.2.1", "kea-window-values": "^3.0.0", + "maplibre-gl": "^3.5.1", "md5": "^2.3.0", "monaco-editor": "^0.39.0", "papaparse": "^5.4.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d3710208675fd..d5c9d73418389 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1,4 +1,4 @@ -lockfileVersion: '6.0' +lockfileVersion: '6.1' settings: autoInstallPeers: true @@ -203,6 +203,9 @@ dependencies: kea-window-values: specifier: ^3.0.0 version: 3.0.0(kea@3.1.5) + maplibre-gl: + specifier: ^3.5.1 + version: 3.5.1 md5: specifier: ^2.3.0 version: 2.3.0 @@ -829,7 +832,7 @@ packages: '@babel/helper-plugin-utils': 7.22.5 debug: 4.3.4(supports-color@8.1.1) lodash.debounce: 4.0.8 - resolve: 1.22.8 + resolve: 1.22.1 transitivePeerDependencies: - supports-color @@ -2441,8 +2444,8 @@ packages: eslint-visitor-keys: 3.4.3 dev: true - /@eslint-community/regexpp@4.9.1: - resolution: {integrity: sha512-Y27x+MBLjXa+0JWDhykM3+JE+il3kHKAEqabfEWq3SDhZjLYb6/BHL/JKFnH3fe207JaXkyDo685Oc2Glt6ifA==} + /@eslint-community/regexpp@4.6.2: + resolution: {integrity: sha512-pPTNuaAG3QMH+buKyBIGJs3g/S5y0caxw0ygM3YyE6yJFySwiGGSzA+mM3KJ8QQvzeLh3blwgSonkFjgQdxzMw==} engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} dev: true @@ -3100,6 +3103,54 @@ packages: react: 16.14.0 dev: false + /@mapbox/geojson-rewind@0.5.2: + resolution: {integrity: sha512-tJaT+RbYGJYStt7wI3cq4Nl4SXxG8W7JDG5DMJu97V25RnbNg3QtQtf+KD+VLjNpWKYsRvXDNmNrBgEETr1ifA==} + hasBin: true + dependencies: + get-stream: 6.0.1 + minimist: 1.2.8 + dev: false + + /@mapbox/jsonlint-lines-primitives@2.0.2: + resolution: {integrity: sha512-rY0o9A5ECsTQRVhv7tL/OyDpGAoUB4tTvLiW1DSzQGq4bvTPhNw1VpSNjDJc5GFZ2XuyOtSWSVN05qOtcD71qQ==} + engines: {node: '>= 0.6'} + dev: false + + /@mapbox/point-geometry@0.1.0: + resolution: {integrity: sha512-6j56HdLTwWGO0fJPlrZtdU/B13q8Uwmo18Ck2GnGgN9PCFyKTZ3UbXeEdRFh18i9XQ92eH2VdtpJHpBD3aripQ==} + dev: false + + /@mapbox/tiny-sdf@2.0.6: + resolution: {integrity: sha512-qMqa27TLw+ZQz5Jk+RcwZGH7BQf5G/TrutJhspsca/3SHwmgKQ1iq+d3Jxz5oysPVYTGP6aXxCo5Lk9Er6YBAA==} + dev: false + + /@mapbox/unitbezier@0.0.1: + resolution: {integrity: sha512-nMkuDXFv60aBr9soUG5q+GvZYL+2KZHVvsqFCzqnkGEf46U2fvmytHaEVc1/YZbiLn8X+eR3QzX1+dwDO1lxlw==} + dev: false + + /@mapbox/vector-tile@1.3.1: + resolution: {integrity: sha512-MCEddb8u44/xfQ3oD+Srl/tNcQoqTw3goGk2oLsrFxOTc3dUp+kAnby3PvAeeBYSMSjSPD1nd1AJA6W49WnoUw==} + dependencies: + '@mapbox/point-geometry': 0.1.0 + dev: false + + /@mapbox/whoots-js@3.1.0: + resolution: {integrity: sha512-Es6WcD0nO5l+2BOQS4uLfNPYQaNDfbot3X1XUoloz+x0mPDS3eeORZJl06HXjwBG1fOGwCRnzK88LMdxKRrd6Q==} + engines: {node: '>=6.0.0'} + dev: false + + /@maplibre/maplibre-gl-style-spec@19.3.3: + resolution: {integrity: sha512-cOZZOVhDSulgK0meTsTkmNXb1ahVvmTmWmfx9gRBwc6hq98wS9JP35ESIoNq3xqEan+UN+gn8187Z6E4NKhLsw==} + hasBin: true + dependencies: + '@mapbox/jsonlint-lines-primitives': 2.0.2 + '@mapbox/unitbezier': 0.0.1 + json-stringify-pretty-compact: 3.0.0 + minimist: 1.2.8 + rw: 1.3.3 + sort-object: 3.0.3 + dev: false + /@maxmind/geoip2-node@3.5.0: resolution: {integrity: sha512-WG2TNxMwDWDOrljLwyZf5bwiEYubaHuICvQRlgz74lE9OZA/z4o+ZT6OisjDBAZh/yRJVNK6mfHqmP5lLlAwsA==} dependencies: @@ -3216,7 +3267,7 @@ packages: engines: {node: '>= 8'} dependencies: '@nodelib/fs.scandir': 2.1.5 - fastq: 1.15.0 + fastq: 1.13.0 dev: true /@open-draft/until@1.0.3: @@ -4924,7 +4975,7 @@ packages: flat-cache: 3.0.4 micromatch: 4.0.5 react-docgen-typescript: 2.2.2(typescript@4.9.5) - tslib: 2.6.2 + tslib: 2.4.1 typescript: 4.9.5 webpack: 5.88.2(@swc/core@1.3.93)(esbuild@0.14.54)(webpack-cli@5.1.4) transitivePeerDependencies: @@ -6004,6 +6055,10 @@ packages: resolution: {integrity: sha512-Nmh0K3iWQJzniTuPRcJn5hxXkfB1T1pgB89SBig5PlJQU5yocazeu4jATJlaA0GYFKWMqDdvYemoSnF2pXgLVA==} dev: true + /@types/geojson@7946.0.12: + resolution: {integrity: sha512-uK2z1ZHJyC0nQRbuovXFt4mzXDwf27vQeUWNhfKGwRcWW429GOhP8HxUHlM6TLH4bzmlv/HlEjpvJh3JfmGsAA==} + dev: false + /@types/graceful-fs@4.1.5: resolution: {integrity: sha512-anKkLmZZ+xm4p8JWBf4hElkM4XR+EZeA2M9BAkkTldmcyDY4mbdIJnRghDJH3Ov5ooY7/UAoENtmdMSkaAd7Cw==} dependencies: @@ -6080,10 +6135,6 @@ packages: resolution: {integrity: sha512-Hr5Jfhc9eYOQNPYO5WLDq/n4jqijdHNlDXjuAQkkt+mWdQR+XJToOHrsD4cPaMXpn6KO7y2+wM8AZEs8VpBLVA==} dev: true - /@types/json-schema@7.0.14: - resolution: {integrity: sha512-U3PUjAudAdJBeC2pgN8uTIKgxrb4nlDF3SF0++EldXQvQBGkpFZMSnwQiIoDU77tv45VgNkl/L4ouD+rEomujw==} - dev: true - /@types/less@3.0.3: resolution: {integrity: sha512-1YXyYH83h6We1djyoUEqTlVyQtCfJAFXELSKW2ZRtjHD4hQ82CC4lvrv5D0l0FLcKBaiPbXyi3MpMsI9ZRgKsw==} dev: false @@ -6092,6 +6143,18 @@ packages: resolution: {integrity: sha512-zmEmF5OIM3rb7SbLCFYoQhO4dGt2FRM9AMkxvA3LaADOF1n8in/zGJlWji9fmafLoNyz+FoL6FE0SLtGIArD7w==} dev: true + /@types/mapbox__point-geometry@0.1.3: + resolution: {integrity: sha512-2W46IOXlu7vC8m3+M5rDqSnuY22GFxxx3xhkoyqyPWrD+eP2iAwNst0A1+umLYjCTJMJTSpiofphn9h9k+Kw+w==} + dev: false + + /@types/mapbox__vector-tile@1.3.3: + resolution: {integrity: sha512-d263B3KCQtXKVZMHpMJrEW5EeLBsQ8jvAS9nhpUKC5hHIlQaACG9PWkW8qxEeNuceo9120AwPjeS91uNa4ltqA==} + dependencies: + '@types/geojson': 7946.0.12 + '@types/mapbox__point-geometry': 0.1.3 + '@types/pbf': 3.0.4 + dev: false + /@types/md5@2.3.2: resolution: {integrity: sha512-v+JFDu96+UYJ3/UWzB0mEglIS//MZXgRaJ4ubUPwOM0gvLc/kcQ3TWNYwENEK7/EcXGQVrW8h/XqednSjBd/Og==} dev: false @@ -6159,6 +6222,10 @@ packages: resolution: {integrity: sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==} dev: true + /@types/pbf@3.0.4: + resolution: {integrity: sha512-SOFlLGZkLbEXJRwcWCqeP/Koyaf/uAqLXHUsdo/nMfjLsNd8kqauwHe9GBOljSmpcHp/LC6kOjo3SidGjNirVA==} + dev: false + /@types/pica@9.0.1: resolution: {integrity: sha512-hTsYxcy0MqIOKzeALuh3zOHyozBlndxV/bX9X52GBFq2XUQchZF6T0vcRYeT5P1ggmswi2LlIwHAH+bKWxxalg==} dev: true @@ -6273,10 +6340,6 @@ packages: resolution: {integrity: sha512-G8hZ6XJiHnuhQKR7ZmysCeJWE08o8T0AXtk5darsCaTVsYZhhgUrq53jizaR2FvsoeCwJhlmwTjkXBY5Pn/ZHw==} dev: true - /@types/semver@7.5.4: - resolution: {integrity: sha512-MMzuxN3GdFwskAnb6fz0orFvhfqi752yjaXylr0Rp4oDg5H0Zn1IuyRhDVvYOwAXoJirx2xuS16I3WjxnAIHiQ==} - dev: true - /@types/send@0.17.3: resolution: {integrity: sha512-/7fKxvKUoETxjFUsuFlPB9YndePpxxRAOfGC/yJdc9kTjTeP5kRCTzfnE8kPUKCeyiyIZu0YQ76s50hCedI1ug==} dependencies: @@ -6310,6 +6373,12 @@ packages: resolution: {integrity: sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==} dev: true + /@types/supercluster@7.1.2: + resolution: {integrity: sha512-qMhofL945Z4njQUuntadexAgPtpiBC014WvVqU70Prj42LC77Xgmz04us7hSMmwjs7KbgAwGBmje+FSOvDbP0Q==} + dependencies: + '@types/geojson': 7946.0.12 + dev: false + /@types/testing-library__jest-dom@5.14.5: resolution: {integrity: sha512-SBwbxYoyPIvxHbeHxTZX2Pe/74F/tX2/D3mMvzabdeJ25bBojfW0TyB8BHrbq/9zaaKICJZjLP+8r6AeZMFCuQ==} dependencies: @@ -6376,7 +6445,7 @@ packages: typescript: optional: true dependencies: - '@eslint-community/regexpp': 4.9.1 + '@eslint-community/regexpp': 4.6.2 '@typescript-eslint/parser': 6.9.0(eslint@8.52.0)(typescript@4.9.5) '@typescript-eslint/scope-manager': 6.9.0 '@typescript-eslint/type-utils': 6.9.0(eslint@8.52.0)(typescript@4.9.5) @@ -6388,7 +6457,7 @@ packages: ignore: 5.2.4 natural-compare: 1.4.0 semver: 7.5.4 - ts-api-utils: 1.0.3(typescript@4.9.5) + ts-api-utils: 1.0.2(typescript@4.9.5) typescript: 4.9.5 transitivePeerDependencies: - supports-color @@ -6445,7 +6514,7 @@ packages: '@typescript-eslint/utils': 6.9.0(eslint@8.52.0)(typescript@4.9.5) debug: 4.3.4(supports-color@8.1.1) eslint: 8.52.0 - ts-api-utils: 1.0.3(typescript@4.9.5) + ts-api-utils: 1.0.2(typescript@4.9.5) typescript: 4.9.5 transitivePeerDependencies: - supports-color @@ -6497,7 +6566,7 @@ packages: globby: 11.1.0 is-glob: 4.0.3 semver: 7.5.4 - ts-api-utils: 1.0.3(typescript@4.9.5) + ts-api-utils: 1.0.2(typescript@4.9.5) typescript: 4.9.5 transitivePeerDependencies: - supports-color @@ -6530,8 +6599,8 @@ packages: eslint: ^7.0.0 || ^8.0.0 dependencies: '@eslint-community/eslint-utils': 4.4.0(eslint@8.52.0) - '@types/json-schema': 7.0.14 - '@types/semver': 7.5.4 + '@types/json-schema': 7.0.12 + '@types/semver': 7.5.0 '@typescript-eslint/scope-manager': 6.9.0 '@typescript-eslint/types': 6.9.0 '@typescript-eslint/typescript-estree': 6.9.0(typescript@4.9.5) @@ -6915,7 +6984,7 @@ packages: resolution: {integrity: sha512-IG23inYII3dWlU2EyiAiGj6Bwal5GzsgPMwjYGvc1HPE2dgbj4ZB5ToWBKSquKw74nB3TIuOwaI6/jSULzfgrw==} engines: {node: '>=14.16'} dependencies: - type-fest: 3.13.1 + type-fest: 3.5.3 dev: true /ansi-html-community@0.0.8: @@ -7081,6 +7150,11 @@ packages: dependencies: deep-equal: 2.1.0 + /arr-union@3.1.0: + resolution: {integrity: sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q==} + engines: {node: '>=0.10.0'} + dev: false + /array-buffer-byte-length@1.0.0: resolution: {integrity: sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==} dependencies: @@ -7091,14 +7165,14 @@ packages: /array-flatten@1.1.1: resolution: {integrity: sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==} - /array-includes@3.1.7: - resolution: {integrity: sha512-dlcsNBIiWhPkHdOEEKnehA+RNUWDc4UqFtnIXU4uuYDPtA4LDkr7qip2p0VvFAEXNDr0yWZ9PJyIRiGjRLQzwQ==} + /array-includes@3.1.6: + resolution: {integrity: sha512-sgTbLvL6cNnw24FnbaDyjmvddQ2ML8arZsgaJhoABMoplz/4QRhtrYS+alr1BUM1Bwp6dhx8vVCBSLG+StwOFw==} engines: {node: '>= 0.4'} dependencies: - call-bind: 1.0.5 - define-properties: 1.2.1 - es-abstract: 1.22.3 - get-intrinsic: 1.2.2 + call-bind: 1.0.2 + define-properties: 1.1.4 + es-abstract: 1.20.4 + get-intrinsic: 1.1.3 is-string: 1.0.7 dev: true @@ -7111,24 +7185,14 @@ packages: engines: {node: '>=8'} dev: true - /array.prototype.flat@1.3.2: - resolution: {integrity: sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==} - engines: {node: '>= 0.4'} - dependencies: - call-bind: 1.0.5 - define-properties: 1.2.1 - es-abstract: 1.22.3 - es-shim-unscopables: 1.0.2 - dev: true - - /array.prototype.flatmap@1.3.2: - resolution: {integrity: sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==} + /array.prototype.flatmap@1.3.1: + resolution: {integrity: sha512-8UGn9O1FDVvMNB0UlLv4voxRMze7+FpHyF5mSMRjWHUMlpoDViniy05870VlxhfgTnLbpuwTzvD76MTtWxB/mQ==} engines: {node: '>= 0.4'} dependencies: - call-bind: 1.0.5 - define-properties: 1.2.1 - es-abstract: 1.22.3 - es-shim-unscopables: 1.0.2 + call-bind: 1.0.2 + define-properties: 1.1.4 + es-abstract: 1.20.4 + es-shim-unscopables: 1.0.0 dev: true /array.prototype.reduce@1.0.5: @@ -7142,14 +7206,14 @@ packages: is-string: 1.0.7 dev: true - /array.prototype.tosorted@1.1.2: - resolution: {integrity: sha512-HuQCHOlk1Weat5jzStICBCd83NxiIMwqDg/dHEsoefabn/hJRj5pVdWcPUSpRrwhwxZOsQassMpgN/xRYFBMIg==} + /array.prototype.tosorted@1.1.1: + resolution: {integrity: sha512-pZYPXPRl2PqWcsUs6LOMn+1f1532nEoPTYowBtqLwAW+W8vSVhkIGnmOX1t/UQjD6YGI0vcD2B1U7ZFGQH9jnQ==} dependencies: - call-bind: 1.0.5 - define-properties: 1.2.1 - es-abstract: 1.22.3 - es-shim-unscopables: 1.0.2 - get-intrinsic: 1.2.2 + call-bind: 1.0.2 + define-properties: 1.1.4 + es-abstract: 1.20.4 + es-shim-unscopables: 1.0.0 + get-intrinsic: 1.1.3 dev: true /arraybuffer.prototype.slice@1.0.2: @@ -7188,6 +7252,11 @@ packages: util: 0.12.5 dev: true + /assign-symbols@1.0.0: + resolution: {integrity: sha512-Q+JC7Whu8HhmTdBph/Tq59IoRtoy6KAm5zzPv00WdujX82lbAL8K7WVjne7vdCsAmbF4AYaDOPyO3k0kl8qIrw==} + engines: {node: '>=0.10.0'} + dev: false + /ast-metadata-inferer@0.8.0: resolution: {integrity: sha512-jOMKcHht9LxYIEQu+RVd22vtgrPaVCtDRQ/16IGmurdzxvYbDd5ynxjnyrzLnieG96eTcAyaoj/wN/4/1FyyeA==} dependencies: @@ -7212,7 +7281,7 @@ packages: resolution: {integrity: sha512-6t10qk83GOG8p0vKmaCr8eiilZwO171AvbROMtvvNiwrTly62t+7XkA8RdIIVbpMhCASAsxgAzdRSwh6nw/5Dg==} engines: {node: '>=4'} dependencies: - tslib: 2.4.1 + tslib: 2.6.2 dev: true /astral-regex@2.0.0: @@ -7675,6 +7744,19 @@ packages: resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} engines: {node: '>= 0.8'} + /bytewise-core@1.2.3: + resolution: {integrity: sha512-nZD//kc78OOxeYtRlVk8/zXqTB4gf/nlguL1ggWA8FuchMyOxcyHR4QPQZMUmA7czC+YnaBrPUCubqAWe50DaA==} + dependencies: + typewise-core: 1.2.0 + dev: false + + /bytewise@1.1.0: + resolution: {integrity: sha512-rHuuseJ9iQ0na6UDhnrRVDh8YnWVlU6xM3VH6q/+yHDeUH2zIhUzP+2/h3LIrhLDBtTqzWpE3p3tP/boefskKQ==} + dependencies: + bytewise-core: 1.2.3 + typewise: 1.0.3 + dev: false + /c8@7.14.0: resolution: {integrity: sha512-i04rtkkcNcCf7zsQcSv/T9EbUn4RXQ6mropeMcjFOsQXQ0iGLAr/xT6TImQg4+U9hmNpN9XdvPkjUL1IzbgxJw==} engines: {node: '>=10.12.0'} @@ -7709,6 +7791,12 @@ packages: write-file-atomic: 3.0.3 dev: true + /call-bind@1.0.2: + resolution: {integrity: sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==} + dependencies: + function-bind: 1.1.1 + get-intrinsic: 1.2.2 + /call-bind@1.0.5: resolution: {integrity: sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ==} dependencies: @@ -8995,9 +9083,9 @@ packages: /deep-equal@2.1.0: resolution: {integrity: sha512-2pxgvWu3Alv1PoWEyVg7HS8YhGlUFUV7N5oOvfL6d+7xAmLSemMwv/c8Zv/i9KFzxV5Kt5CAvQc70fLwVuf4UA==} dependencies: - call-bind: 1.0.5 + call-bind: 1.0.2 es-get-iterator: 1.1.2 - get-intrinsic: 1.2.2 + get-intrinsic: 1.1.3 is-arguments: 1.1.1 is-date-object: 1.0.5 is-regex: 1.1.4 @@ -9056,7 +9144,7 @@ packages: dependencies: get-intrinsic: 1.2.2 gopd: 1.0.1 - has-property-descriptors: 1.0.1 + has-property-descriptors: 1.0.0 /define-lazy-prop@2.0.0: resolution: {integrity: sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==} @@ -9068,12 +9156,20 @@ packages: engines: {node: '>=12'} dev: true + /define-properties@1.1.4: + resolution: {integrity: sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==} + engines: {node: '>= 0.4'} + dependencies: + has-property-descriptors: 1.0.0 + object-keys: 1.1.1 + dev: true + /define-properties@1.2.1: resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} engines: {node: '>= 0.4'} dependencies: define-data-property: 1.1.1 - has-property-descriptors: 1.0.1 + has-property-descriptors: 1.0.0 object-keys: 1.1.1 /defu@6.1.2: @@ -9328,6 +9424,10 @@ packages: stream-shift: 1.0.1 dev: true + /earcut@2.2.4: + resolution: {integrity: sha512-/pjZsA1b4RPHbeWZQn66SWS8nZZWLQQ23oE3Eam7aroEFGEvwKAsJfZ9ytiEMycfzXWpca4FA9QIOehf7PocBQ==} + dev: false + /eastasianwidth@0.2.0: resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} dev: true @@ -9455,6 +9555,36 @@ packages: dependencies: stackframe: 1.3.4 + /es-abstract@1.20.4: + resolution: {integrity: sha512-0UtvRN79eMe2L+UNEF1BwRe364sj/DXhQ/k5FmivgoSdpM90b8Jc0mDzKMGo7QS0BVbOP/bTwBKNnDc9rNzaPA==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.2 + es-to-primitive: 1.2.1 + function-bind: 1.1.1 + function.prototype.name: 1.1.5 + get-intrinsic: 1.2.2 + get-symbol-description: 1.0.0 + has: 1.0.3 + has-property-descriptors: 1.0.0 + has-symbols: 1.0.3 + internal-slot: 1.0.6 + is-callable: 1.2.7 + is-negative-zero: 2.0.2 + is-regex: 1.1.4 + is-shared-array-buffer: 1.0.2 + is-string: 1.0.7 + is-weakref: 1.0.2 + object-inspect: 1.12.2 + object-keys: 1.1.1 + object.assign: 4.1.4 + regexp.prototype.flags: 1.4.3 + safe-regex-test: 1.0.0 + string.prototype.trimend: 1.0.5 + string.prototype.trimstart: 1.0.5 + unbox-primitive: 1.0.2 + dev: true + /es-abstract@1.22.3: resolution: {integrity: sha512-eiiY8HQeYfYH2Con2berK+To6GrK2RxbPawDkGq4UiCQQfZHb6wX9qQqkbpPqaxQFcl8d9QzZqo0tGE0VcrdwA==} engines: {node: '>= 0.4'} @@ -9470,7 +9600,7 @@ packages: get-symbol-description: 1.0.0 globalthis: 1.0.3 gopd: 1.0.1 - has-property-descriptors: 1.0.1 + has-property-descriptors: 1.0.0 has-proto: 1.0.1 has-symbols: 1.0.3 hasown: 2.0.0 @@ -9520,14 +9650,14 @@ packages: resolution: {integrity: sha512-GhoY8uYqd6iwUl2kgjTm4CZAf6oo5mHK7BPqx3rKgx893YSsy0LGHV6gfqqQvZt/8xM8xeOnfXBCfqclMKkJ5g==} dependencies: asynciterator.prototype: 1.0.0 - call-bind: 1.0.5 + call-bind: 1.0.2 define-properties: 1.2.1 es-abstract: 1.22.3 es-set-tostringtag: 2.0.2 - function-bind: 1.1.2 + function-bind: 1.1.1 get-intrinsic: 1.2.2 globalthis: 1.0.3 - has-property-descriptors: 1.0.1 + has-property-descriptors: 1.0.0 has-proto: 1.0.1 has-symbols: 1.0.3 internal-slot: 1.0.6 @@ -9548,10 +9678,10 @@ packages: hasown: 2.0.0 dev: true - /es-shim-unscopables@1.0.2: - resolution: {integrity: sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==} + /es-shim-unscopables@1.0.0: + resolution: {integrity: sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==} dependencies: - hasown: 2.0.0 + has: 1.0.3 dev: true /es-to-primitive@1.2.1: @@ -9956,23 +10086,23 @@ packages: peerDependencies: eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 dependencies: - array-includes: 3.1.7 - array.prototype.flatmap: 1.3.2 - array.prototype.tosorted: 1.1.2 + array-includes: 3.1.6 + array.prototype.flatmap: 1.3.1 + array.prototype.tosorted: 1.1.1 doctrine: 2.1.0 es-iterator-helpers: 1.0.15 eslint: 8.52.0 estraverse: 5.3.0 - jsx-ast-utils: 3.3.5 + jsx-ast-utils: 3.3.3 minimatch: 3.1.2 - object.entries: 1.1.7 - object.fromentries: 2.0.7 - object.hasown: 1.1.3 - object.values: 1.1.7 + object.entries: 1.1.6 + object.fromentries: 2.0.6 + object.hasown: 1.1.2 + object.values: 1.1.6 prop-types: 15.8.1 - resolve: 2.0.0-next.5 + resolve: 2.0.0-next.4 semver: 6.3.1 - string.prototype.matchall: 4.0.10 + string.prototype.matchall: 4.0.8 dev: true /eslint-plugin-storybook@0.6.15(eslint@8.52.0)(typescript@4.9.5): @@ -10018,7 +10148,7 @@ packages: hasBin: true dependencies: '@eslint-community/eslint-utils': 4.4.0(eslint@8.52.0) - '@eslint-community/regexpp': 4.9.1 + '@eslint-community/regexpp': 4.6.2 '@eslint/eslintrc': 2.1.2 '@eslint/js': 8.52.0 '@humanwhocodes/config-array': 0.11.13 @@ -10263,6 +10393,21 @@ packages: transitivePeerDependencies: - supports-color + /extend-shallow@2.0.1: + resolution: {integrity: sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==} + engines: {node: '>=0.10.0'} + dependencies: + is-extendable: 0.1.1 + dev: false + + /extend-shallow@3.0.2: + resolution: {integrity: sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==} + engines: {node: '>=0.10.0'} + dependencies: + assign-symbols: 1.0.0 + is-extendable: 1.0.1 + dev: false + /extend@3.0.2: resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==} @@ -10308,8 +10453,19 @@ packages: /fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} - /fast-diff@1.3.0: - resolution: {integrity: sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==} + /fast-diff@1.2.0: + resolution: {integrity: sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==} + dev: true + + /fast-glob@3.2.12: + resolution: {integrity: sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==} + engines: {node: '>=8.6.0'} + dependencies: + '@nodelib/fs.stat': 2.0.5 + '@nodelib/fs.walk': 1.2.8 + glob-parent: 5.1.2 + merge2: 1.4.1 + micromatch: 4.0.5 dev: true /fast-glob@3.3.1: @@ -10348,8 +10504,8 @@ packages: resolution: {integrity: sha512-bijHueCGd0LqqNK9b5oCMHc0MluJAx0cwqASgbWMvkO01lCYgIhacVRLcaDz3QnyYIRNJRDwMb41VuT6pHJ91Q==} dev: false - /fastq@1.15.0: - resolution: {integrity: sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==} + /fastq@1.13.0: + resolution: {integrity: sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==} dependencies: reusify: 1.0.4 dev: true @@ -10420,7 +10576,7 @@ packages: resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==} engines: {node: ^10.12.0 || >=12.0.0} dependencies: - flat-cache: 3.1.1 + flat-cache: 3.0.4 dev: true /file-loader@6.2.0(webpack@5.88.2): @@ -10444,7 +10600,7 @@ packages: /filelist@1.0.4: resolution: {integrity: sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==} dependencies: - minimatch: 5.1.6 + minimatch: 5.1.1 dev: true /fill-range@7.0.1: @@ -10558,23 +10714,10 @@ packages: rimraf: 3.0.2 dev: true - /flat-cache@3.1.1: - resolution: {integrity: sha512-/qM2b3LUIaIgviBQovTLvijfyOQXPtSRnRK26ksj2J7rzPIecePUIpJsZ4T02Qg+xiAEKIs5K8dsHEd+VaKa/Q==} - engines: {node: '>=12.0.0'} - dependencies: - flatted: 3.2.9 - keyv: 4.5.4 - rimraf: 3.0.2 - dev: true - /flatted@3.2.7: resolution: {integrity: sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==} dev: true - /flatted@3.2.9: - resolution: {integrity: sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==} - dev: true - /flow-parser@0.214.0: resolution: {integrity: sha512-RW1Dh6BuT14DA7+gtNRKzgzvG3GTPdrceHCi4ddZ9VFGQ9HtO5L8wzxMGsor7XtInIrbWZZCSak0oxnBF7tApw==} engines: {node: '>=0.4.0'} @@ -10755,9 +10898,22 @@ packages: requiresBuild: true optional: true + /function-bind@1.1.1: + resolution: {integrity: sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==} + /function-bind@1.1.2: resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + /function.prototype.name@1.1.5: + resolution: {integrity: sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.5 + define-properties: 1.2.1 + es-abstract: 1.22.3 + functions-have-names: 1.2.3 + dev: true + /function.prototype.name@1.1.6: resolution: {integrity: sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==} engines: {node: '>= 0.4'} @@ -10780,11 +10936,22 @@ packages: resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} engines: {node: '>=6.9.0'} + /geojson-vt@3.2.1: + resolution: {integrity: sha512-EvGQQi/zPrDA6zr6BnJD/YhwAkBP8nnJ9emh3EnHQKVMfg/MRVtPbMYdgVy/IaEmn4UfagD2a6fafPDL5hbtwg==} + dev: false + /get-caller-file@2.0.5: resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} engines: {node: 6.* || 8.* || >= 10.*} dev: true + /get-intrinsic@1.1.3: + resolution: {integrity: sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==} + dependencies: + function-bind: 1.1.1 + has: 1.0.3 + has-symbols: 1.0.3 + /get-intrinsic@1.2.2: resolution: {integrity: sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA==} dependencies: @@ -10832,7 +10999,6 @@ packages: /get-stream@6.0.1: resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} engines: {node: '>=10'} - dev: true /get-symbol-description@1.0.0: resolution: {integrity: sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==} @@ -10842,6 +11008,11 @@ packages: get-intrinsic: 1.2.2 dev: true + /get-value@2.0.6: + resolution: {integrity: sha512-Ln0UQDlxH1BapMu3GPtf7CuYNwRZf2gwCuPqbyG6pB8WfmFpzqcy4xtAaAMUhnNqjMKTiCPZG2oMT3YSx8U2NA==} + engines: {node: '>=0.10.0'} + dev: false + /getos@3.2.1: resolution: {integrity: sha512-U56CfOK17OKgTVqozZjUKNdkfEv6jk5WISBJ8SHoagjE6L69zOwl3Z+O8myjY9MEW3i2HPWQBt/LTbCgcC973Q==} dependencies: @@ -10877,6 +11048,10 @@ packages: resolution: {integrity: sha512-4hYlStsEIaYeYvZTZwgD5yOS2WVP0dcDsOBqeImdEM8eLuclvv0IEMlQQ1kuA5DN4he7wVH1jsYtNe9uininxg==} dev: true + /gl-matrix@3.4.3: + resolution: {integrity: sha512-wcCp8vu8FT22BnvKVPjXa/ICBWRq/zjFfdofZy1WSpQZpphblv12/bOQLBC1rMM7SGOFS9ltVmKOHil5+Ml7gA==} + dev: false + /glob-parent@5.1.2: resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} engines: {node: '>= 6'} @@ -10964,6 +11139,15 @@ packages: which: 1.3.1 dev: true + /global-prefix@3.0.0: + resolution: {integrity: sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==} + engines: {node: '>=6'} + dependencies: + ini: 1.3.8 + kind-of: 6.0.3 + which: 1.3.1 + dev: false + /globals@11.12.0: resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==} engines: {node: '>=4'} @@ -10988,7 +11172,7 @@ packages: dependencies: array-union: 2.1.0 dir-glob: 3.0.1 - fast-glob: 3.3.1 + fast-glob: 3.2.12 ignore: 5.2.4 merge2: 1.4.1 slash: 3.0.0 @@ -11050,8 +11234,8 @@ packages: resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} engines: {node: '>=8'} - /has-property-descriptors@1.0.1: - resolution: {integrity: sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg==} + /has-property-descriptors@1.0.0: + resolution: {integrity: sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==} dependencies: get-intrinsic: 1.2.2 @@ -11074,7 +11258,6 @@ packages: engines: {node: '>= 0.4.0'} dependencies: function-bind: 1.1.2 - dev: true /hasha@5.2.2: resolution: {integrity: sha512-Hrp5vIK/xr5SkeN2onO32H0MgNZ0f17HRNH39WfL0SYUNOTZ5Lz1TJ8Pajo/87dYGEFlLMm7mIc/k/s6Bvz9HQ==} @@ -11359,7 +11542,6 @@ packages: /ieee754@1.2.1: resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} - dev: true /ignore@5.2.4: resolution: {integrity: sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==} @@ -11433,7 +11615,6 @@ packages: /ini@1.3.8: resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==} - dev: true /ini@2.0.0: resolution: {integrity: sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==} @@ -11467,6 +11648,15 @@ packages: wrap-ansi: 7.0.0 dev: true + /internal-slot@1.0.3: + resolution: {integrity: sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==} + engines: {node: '>= 0.4'} + dependencies: + get-intrinsic: 1.2.2 + has: 1.0.3 + side-channel: 1.0.4 + dev: true + /internal-slot@1.0.6: resolution: {integrity: sha512-Xj6dv+PsbtwyPpEflsejS+oIZxmMlV44zAhG479uYu89MsjcYOhCFnNyKrkJrihbsiasQyY0afoCl/9BLR65bg==} engines: {node: '>= 0.4'} @@ -11604,10 +11794,10 @@ packages: rgba-regex: 1.0.0 dev: true - /is-core-module@2.13.1: - resolution: {integrity: sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==} + /is-core-module@2.11.0: + resolution: {integrity: sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==} dependencies: - hasown: 2.0.0 + has: 1.0.3 /is-date-object@1.0.5: resolution: {integrity: sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==} @@ -11639,6 +11829,11 @@ packages: hasBin: true dev: true + /is-extendable@0.1.1: + resolution: {integrity: sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==} + engines: {node: '>=0.10.0'} + dev: false + /is-extendable@1.0.1: resolution: {integrity: sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==} engines: {node: '>=0.10.0'} @@ -11839,13 +12034,13 @@ packages: for-each: 0.3.3 gopd: 1.0.1 has-tostringtag: 1.0.0 + dev: true /is-typed-array@1.1.12: resolution: {integrity: sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg==} engines: {node: '>= 0.4'} dependencies: which-typed-array: 1.1.13 - dev: true /is-typedarray@1.0.0: resolution: {integrity: sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==} @@ -11900,7 +12095,6 @@ packages: /isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} - dev: true /isobject@3.0.1: resolution: {integrity: sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==} @@ -12677,7 +12871,7 @@ packages: jest-pnp-resolver: 1.2.2(jest-resolve@28.1.3) jest-util: 28.1.3 jest-validate: 28.1.3 - resolve: 1.22.8 + resolve: 1.22.1 resolve.exports: 1.1.0 slash: 3.0.0 dev: true @@ -12692,7 +12886,7 @@ packages: jest-pnp-resolver: 1.2.2(jest-resolve@29.3.1) jest-util: 29.3.1 jest-validate: 29.3.1 - resolve: 1.22.8 + resolve: 1.22.1 resolve.exports: 1.1.0 slash: 3.0.0 dev: true @@ -13166,10 +13360,6 @@ packages: engines: {node: '>=4'} hasBin: true - /json-buffer@3.0.1: - resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} - dev: true - /json-parse-better-errors@1.0.2: resolution: {integrity: sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==} dev: true @@ -13193,6 +13383,10 @@ packages: resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} dev: true + /json-stringify-pretty-compact@3.0.0: + resolution: {integrity: sha512-Rc2suX5meI0S3bfdZuA7JMFBGkJ875ApfVyq2WHELjBiiG22My/l7/8zPpH/CfFVQHuVLd8NLR0nv6vi0BYYKA==} + dev: false + /json-stringify-safe@5.0.1: resolution: {integrity: sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==} dev: true @@ -13235,16 +13429,18 @@ packages: json-schema: 0.4.0 verror: 1.10.0 - /jsx-ast-utils@3.3.5: - resolution: {integrity: sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==} + /jsx-ast-utils@3.3.3: + resolution: {integrity: sha512-fYQHZTZ8jSfmWZ0iyzfwiU4WDX4HpHbMCZ3gPlWYiCl3BoeOTsqKBqnTVfH2rYT7eP5c3sVbeSPHnnJOaTrWiw==} engines: {node: '>=4.0'} dependencies: - array-includes: 3.1.7 - array.prototype.flat: 1.3.2 + array-includes: 3.1.6 object.assign: 4.1.4 - object.values: 1.1.7 dev: true + /kdbush@4.0.2: + resolution: {integrity: sha512-WbCVYJ27Sz8zi9Q7Q0xHC+05iwkm3Znipc2XTlrnJbsHMYktW4hPhXUE8Ys1engBrvffoSCqbil1JQAa7clRpA==} + dev: false + /kea-forms@3.0.3(kea@3.1.5): resolution: {integrity: sha512-ApiirM7K103ULa0hNNcJHiJ0ffvuVIn9Nwg4wsEadfyraV9GLrWVbUeZWW0qFI2zTlkizDplM/gc3gGUfQTs9g==} peerDependencies: @@ -13340,16 +13536,9 @@ packages: use-sync-external-store: 1.2.0(react@16.14.0) dev: false - /keyv@4.5.4: - resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} - dependencies: - json-buffer: 3.0.1 - dev: true - /kind-of@6.0.3: resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==} engines: {node: '>=0.10.0'} - dev: true /kleur@3.0.3: resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==} @@ -13413,7 +13602,7 @@ packages: dependencies: copy-anything: 2.0.6 parse-node-version: 1.0.1 - tslib: 2.6.2 + tslib: 2.4.1 optionalDependencies: errno: 0.1.8 graceful-fs: 4.2.11 @@ -13670,7 +13859,7 @@ packages: requiresBuild: true dependencies: pify: 4.0.1 - semver: 5.7.2 + semver: 5.7.1 /make-dir@3.1.0: resolution: {integrity: sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==} @@ -13697,6 +13886,37 @@ packages: resolution: {integrity: sha512-0aF7ZmVon1igznGI4VS30yugpduQW3y3GkcgGJOp7d8x8QrizhigUxjI/m2UojsXXto+jLAH3KSz+xOJTiORjg==} dev: true + /maplibre-gl@3.5.1: + resolution: {integrity: sha512-XFpqAKjpm7Y6cV3B1MDZ3FGUCXyrfeM2QkXloKc4x2QK9/e6/BEHdVebtxXcTrwdzpQexKrMqzdYCbaobJRNrw==} + engines: {node: '>=16.14.0', npm: '>=8.1.0'} + dependencies: + '@mapbox/geojson-rewind': 0.5.2 + '@mapbox/jsonlint-lines-primitives': 2.0.2 + '@mapbox/point-geometry': 0.1.0 + '@mapbox/tiny-sdf': 2.0.6 + '@mapbox/unitbezier': 0.0.1 + '@mapbox/vector-tile': 1.3.1 + '@mapbox/whoots-js': 3.1.0 + '@maplibre/maplibre-gl-style-spec': 19.3.3 + '@types/geojson': 7946.0.12 + '@types/mapbox__point-geometry': 0.1.3 + '@types/mapbox__vector-tile': 1.3.3 + '@types/pbf': 3.0.4 + '@types/supercluster': 7.1.2 + earcut: 2.2.4 + geojson-vt: 3.2.1 + gl-matrix: 3.4.3 + global-prefix: 3.0.0 + kdbush: 4.0.2 + murmurhash-js: 1.0.0 + pbf: 3.2.1 + potpack: 2.0.0 + quickselect: 2.0.0 + supercluster: 8.0.1 + tinyqueue: 2.0.3 + vt-pbf: 3.1.3 + dev: false + /markdown-it@13.0.1: resolution: {integrity: sha512-lTlxriVoy2criHP0JKRhO2VDG9c2ypWCsT237eDiLqi09rmbKoUetyGHq2uOIRoRS//kfoJckS0eUzzkDR+k2Q==} hasBin: true @@ -13875,13 +14095,6 @@ packages: brace-expansion: 2.0.1 dev: true - /minimatch@5.1.6: - resolution: {integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==} - engines: {node: '>=10'} - dependencies: - brace-expansion: 2.0.1 - dev: true - /minimatch@9.0.3: resolution: {integrity: sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==} engines: {node: '>=16 || 14 >=14.17'} @@ -13891,7 +14104,6 @@ packages: /minimist@1.2.8: resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} - dev: true /minipass@3.3.6: resolution: {integrity: sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==} @@ -14028,6 +14240,10 @@ packages: object-assign: 4.1.1 dev: false + /murmurhash-js@1.0.0: + resolution: {integrity: sha512-TvmkNhkv8yct0SVBSy+o8wYzXjE4Zz3PCesbfs8HiCXXdcTuocApFv11UWlNFWKYsP2okqrhb7JNlSm9InBhIw==} + dev: false + /mute-stream@0.0.8: resolution: {integrity: sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==} dev: true @@ -14147,8 +14363,8 @@ packages: resolution: {integrity: sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==} dependencies: hosted-git-info: 2.8.9 - resolve: 1.22.8 - semver: 5.7.2 + resolve: 1.22.1 + semver: 5.7.1 validate-npm-package-license: 3.0.4 dev: true @@ -14236,8 +14452,12 @@ packages: resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} engines: {node: '>=0.10.0'} + /object-inspect@1.12.2: + resolution: {integrity: sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==} + /object-inspect@1.13.1: resolution: {integrity: sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==} + dev: true /object-is@1.1.5: resolution: {integrity: sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==} @@ -14254,27 +14474,27 @@ packages: resolution: {integrity: sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==} engines: {node: '>= 0.4'} dependencies: - call-bind: 1.0.5 + call-bind: 1.0.2 define-properties: 1.2.1 has-symbols: 1.0.3 object-keys: 1.1.1 - /object.entries@1.1.7: - resolution: {integrity: sha512-jCBs/0plmPsOnrKAfFQXRG2NFjlhZgjjcBLSmTnEhU8U6vVTsVe8ANeQJCHTl3gSsI4J+0emOoCgoKlmQPMgmA==} + /object.entries@1.1.6: + resolution: {integrity: sha512-leTPzo4Zvg3pmbQ3rDK69Rl8GQvIqMWubrkxONG9/ojtFE2rD9fjMKfSI5BxW3osRH1m6VdzmqK8oAY9aT4x5w==} engines: {node: '>= 0.4'} dependencies: - call-bind: 1.0.5 - define-properties: 1.2.1 - es-abstract: 1.22.3 + call-bind: 1.0.2 + define-properties: 1.1.4 + es-abstract: 1.20.4 dev: true - /object.fromentries@2.0.7: - resolution: {integrity: sha512-UPbPHML6sL8PI/mOqPwsH4G6iyXcCGzLin8KvEPenOZN5lpCNBZZQ+V62vdjB1mQHrmqGQt5/OJzemUA+KJmEA==} + /object.fromentries@2.0.6: + resolution: {integrity: sha512-VciD13dswC4j1Xt5394WR4MzmAQmlgN72phd/riNp9vtD7tp4QQWJ0R4wvclXcafgcYK8veHRed2W6XeGBvcfg==} engines: {node: '>= 0.4'} dependencies: - call-bind: 1.0.5 - define-properties: 1.2.1 - es-abstract: 1.22.3 + call-bind: 1.0.2 + define-properties: 1.1.4 + es-abstract: 1.20.4 dev: true /object.getownpropertydescriptors@2.1.4: @@ -14287,11 +14507,11 @@ packages: es-abstract: 1.22.3 dev: true - /object.hasown@1.1.3: - resolution: {integrity: sha512-fFI4VcYpRHvSLXxP7yiZOMAd331cPfd2p7PFDVbgUsYOfCT3tICVqXWngbjr4m49OvsBwUBQ6O2uQoJvy3RexA==} + /object.hasown@1.1.2: + resolution: {integrity: sha512-B5UIT3J1W+WuWIU55h0mjlwaqxiE5vYENJXIXZ4VFe05pNYrkKuK0U/6aFcb0pKywYJh7IhfoqUfKVmrJJHZHw==} dependencies: - define-properties: 1.2.1 - es-abstract: 1.22.3 + define-properties: 1.1.4 + es-abstract: 1.20.4 dev: true /object.omit@3.0.0: @@ -14308,13 +14528,13 @@ packages: isobject: 3.0.1 dev: false - /object.values@1.1.7: - resolution: {integrity: sha512-aU6xnDFYT3x17e/f0IiiwlGPTy2jzMySGfUB4fq6z7CV8l85CWHDk5ErhyhpfDHhrOMwGFhSQkhMGHaIotA6Ng==} + /object.values@1.1.6: + resolution: {integrity: sha512-FVVTkD1vENCsAcwNs9k6jea2uHC/X0+JcjG8YA60FN5CMaJmG95wT9jek/xX9nornqGRrBkKtzuAu2wuHpKqvw==} engines: {node: '>= 0.4'} dependencies: - call-bind: 1.0.5 - define-properties: 1.2.1 - es-abstract: 1.22.3 + call-bind: 1.0.2 + define-properties: 1.1.4 + es-abstract: 1.20.4 dev: true /objectorarray@1.0.5: @@ -14636,6 +14856,14 @@ packages: resolution: {integrity: sha512-d+RQGp0MAYTIaDBIMmOfMwz3E+LOZnxx1HZd5R18mmCZY0QBlK0LDZfPc8FW8Ed2DlvsuE6PRjroDY+wg4+j/Q==} dev: true + /pbf@3.2.1: + resolution: {integrity: sha512-ClrV7pNOn7rtmoQVF4TS1vyU0WhYRnP92fzbfF75jAIwpnzdJXf8iTd4CMEqO4yUenH6NDqLiwjqlh6QgZzgLQ==} + hasBin: true + dependencies: + ieee754: 1.2.1 + resolve-protobuf-schema: 2.1.0 + dev: false + /peek-stream@1.1.3: resolution: {integrity: sha512-FhJ+YbOSBb9/rIl2ZeE/QHEsWn7PqNYt8ARAY3kIgNGOk13g9FGyIY6JIl/xB/3TFRVoTv5as0l11weORrTekA==} dependencies: @@ -15151,6 +15379,10 @@ packages: fflate: 0.4.8 dev: false + /potpack@2.0.0: + resolution: {integrity: sha512-Q+/tYsFU9r7xoOJ+y/ZTtdVQwTWfzjbiXBDMM/JKUux3+QPP02iUuIoeBQ+Ot6oEDlC+/PGjB/5A3K7KKb7hcw==} + dev: false + /prelude-ls@1.2.1: resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} engines: {node: '>= 0.8.0'} @@ -15160,7 +15392,7 @@ packages: resolution: {integrity: sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==} engines: {node: '>=6.0.0'} dependencies: - fast-diff: 1.3.0 + fast-diff: 1.2.0 dev: true /prettier@2.8.8: @@ -15409,6 +15641,10 @@ packages: prosemirror-transform: 1.7.1 dev: false + /protocol-buffers-schema@3.6.0: + resolution: {integrity: sha512-TdDRD+/QNdrCGCE7v8340QyuXd4kIWIgapsE2+n/SaGiSSbomYl4TjHlvIoCWRpE7wFt02EpB35VVA2ImcBVqw==} + dev: false + /proxy-addr@2.0.7: resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} engines: {node: '>= 0.10'} @@ -15526,6 +15762,10 @@ packages: engines: {node: '>=10'} dev: false + /quickselect@2.0.0: + resolution: {integrity: sha512-RKJ22hX8mHe3Y6wH/N3wCM6BWtjaxIyyUIkpHOvfFnxdI4yD4tBXEBKSbriGujF6jnSVkJrffuo6vxACiSSxIw==} + dev: false + /ramda@0.29.0: resolution: {integrity: sha512-BBea6L67bYLtdbOqfp8f58fPMqEwx0doL+pAi8TZyp2YWz8R9G8z9x75CZI8W+ftqhFHCpEX2cRnUUXK130iKA==} dev: true @@ -16280,7 +16520,7 @@ packages: react: 16.14.0 react-remove-scroll-bar: 2.3.4(@types/react@16.14.34)(react@16.14.0) react-style-singleton: 2.2.1(@types/react@16.14.34)(react@16.14.0) - tslib: 2.6.2 + tslib: 2.4.1 use-callback-ref: 1.3.0(@types/react@16.14.34)(react@16.14.0) use-sidecar: 1.1.2(@types/react@16.14.34)(react@16.14.0) dev: true @@ -16402,14 +16642,14 @@ packages: react-dom: 16.14.0(react@16.14.0) dev: false - /react-universal-interface@0.6.2(react@16.14.0)(tslib@2.6.2): + /react-universal-interface@0.6.2(react@16.14.0)(tslib@2.4.1): resolution: {integrity: sha512-dg8yXdcQmvgR13RIlZbTRQOoUrDciFVoSBZILwjE2LFISxZZ8loVJKAkuzswl5js8BHda79bIb2b84ehU8IjXw==} peerDependencies: react: '*' tslib: '*' dependencies: react: 16.14.0 - tslib: 2.6.2 + tslib: 2.4.1 dev: false /react-use@15.3.8(react-dom@16.14.0)(react@16.14.0): @@ -16427,13 +16667,13 @@ packages: nano-css: 5.3.5(react-dom@16.14.0)(react@16.14.0) react: 16.14.0 react-dom: 16.14.0(react@16.14.0) - react-universal-interface: 0.6.2(react@16.14.0)(tslib@2.6.2) + react-universal-interface: 0.6.2(react@16.14.0)(tslib@2.4.1) resize-observer-polyfill: 1.5.1 screenfull: 5.2.0 set-harmonic-interval: 1.0.1 throttle-debounce: 2.3.0 ts-easing: 0.2.0 - tslib: 2.6.2 + tslib: 2.4.1 dev: false /react-virtualized@9.22.5(react-dom@16.14.0)(react@16.14.0): @@ -16600,7 +16840,7 @@ packages: resolution: {integrity: sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==} engines: {node: '>= 0.4'} dependencies: - call-bind: 1.0.5 + call-bind: 1.0.2 define-properties: 1.2.1 functions-have-names: 1.2.3 @@ -16746,6 +16986,12 @@ packages: engines: {node: '>=8'} dev: true + /resolve-protobuf-schema@2.1.0: + resolution: {integrity: sha512-kI5ffTiZWmJaS/huM8wZfEMer1eRd7oJQhDuxeCLe3t7N7mX3z94CN0xPxBQxFYQTSNz9T0i+v6inKqSdK8xrQ==} + dependencies: + protocol-buffers-schema: 3.6.0 + dev: false + /resolve.exports@1.1.0: resolution: {integrity: sha512-J1l+Zxxp4XK3LUDZ9m60LRJF/mAe4z6a4xyabPHk7pvK5t35dACV32iIjJDFeWZFfZlO29w6SZ67knR0tHzJtQ==} engines: {node: '>=10'} @@ -16755,23 +17001,15 @@ packages: resolution: {integrity: sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==} hasBin: true dependencies: - is-core-module: 2.13.1 - path-parse: 1.0.7 - supports-preserve-symlinks-flag: 1.0.0 - - /resolve@1.22.8: - resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==} - hasBin: true - dependencies: - is-core-module: 2.13.1 + is-core-module: 2.11.0 path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 - /resolve@2.0.0-next.5: - resolution: {integrity: sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==} + /resolve@2.0.0-next.4: + resolution: {integrity: sha512-iMDbmAWtfU+MHpxt/I5iWI7cY6YVEZUQ3MBgPQ++XD1PELuJHIl82xBmObyP2KyQmkNB2dsqF7seoQQiAn5yDQ==} hasBin: true dependencies: - is-core-module: 2.13.1 + is-core-module: 2.11.0 path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 dev: true @@ -16898,7 +17136,7 @@ packages: resolution: {integrity: sha512-6XbUAseYE2KtOuGueyeobCySj9L4+66Tn6KQMOPQJrAJEowYKW/YR/MGJZl7FdydUdaFu4LYyDZjxf4/Nmo23Q==} engines: {node: '>=0.4'} dependencies: - call-bind: 1.0.5 + call-bind: 1.0.2 get-intrinsic: 1.2.2 has-symbols: 1.0.3 isarray: 2.0.5 @@ -17020,8 +17258,8 @@ packages: resolution: {integrity: sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow==} dev: true - /semver@5.7.2: - resolution: {integrity: sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==} + /semver@5.7.1: + resolution: {integrity: sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==} hasBin: true /semver@6.3.1: @@ -17088,7 +17326,7 @@ packages: define-data-property: 1.1.1 get-intrinsic: 1.2.2 gopd: 1.0.1 - has-property-descriptors: 1.0.1 + has-property-descriptors: 1.0.0 /set-function-name@2.0.1: resolution: {integrity: sha512-tMNCiqYVkXIZgc2Hnoy2IvC/f8ezc5koaRFkCjrpWzGpCd3qbZXPzVy9MAZzK1ch/X0jvSkojys3oqJN0qCmdA==} @@ -17096,7 +17334,7 @@ packages: dependencies: define-data-property: 1.1.1 functions-have-names: 1.2.3 - has-property-descriptors: 1.0.1 + has-property-descriptors: 1.0.0 dev: true /set-harmonic-interval@1.0.1: @@ -17104,6 +17342,16 @@ packages: engines: {node: '>=6.9'} dev: false + /set-value@2.0.1: + resolution: {integrity: sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==} + engines: {node: '>=0.10.0'} + dependencies: + extend-shallow: 2.0.1 + is-extendable: 0.1.1 + is-plain-object: 2.0.4 + split-string: 3.1.0 + dev: false + /setimmediate@1.0.5: resolution: {integrity: sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==} dev: false @@ -17137,9 +17385,9 @@ packages: /side-channel@1.0.4: resolution: {integrity: sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==} dependencies: - call-bind: 1.0.5 + call-bind: 1.0.2 get-intrinsic: 1.2.2 - object-inspect: 1.13.1 + object-inspect: 1.12.2 /signal-exit@3.0.7: resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} @@ -17195,6 +17443,28 @@ packages: is-fullwidth-code-point: 3.0.0 dev: true + /sort-asc@0.2.0: + resolution: {integrity: sha512-umMGhjPeHAI6YjABoSTrFp2zaBtXBej1a0yKkuMUyjjqu6FJsTF+JYwCswWDg+zJfk/5npWUUbd33HH/WLzpaA==} + engines: {node: '>=0.10.0'} + dev: false + + /sort-desc@0.2.0: + resolution: {integrity: sha512-NqZqyvL4VPW+RAxxXnB8gvE1kyikh8+pR+T+CXLksVRN9eiQqkQlPwqWYU0mF9Jm7UnctShlxLyAt1CaBOTL1w==} + engines: {node: '>=0.10.0'} + dev: false + + /sort-object@3.0.3: + resolution: {integrity: sha512-nK7WOY8jik6zaG9CRwZTaD5O7ETWDLZYMM12pqY8htll+7dYeqGfEUPcUBHOpSJg2vJOrvFIY2Dl5cX2ih1hAQ==} + engines: {node: '>=0.10.0'} + dependencies: + bytewise: 1.1.0 + get-value: 2.0.6 + is-extendable: 0.1.1 + sort-asc: 0.2.0 + sort-desc: 0.2.0 + union-value: 1.0.1 + dev: false + /source-map-js@1.0.2: resolution: {integrity: sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==} engines: {node: '>=0.10.0'} @@ -17284,6 +17554,13 @@ packages: resolution: {integrity: sha512-rr+VVSXtRhO4OHbXUiAF7xW3Bo9DuuF6C5jH+q/x15j2jniycgKbxU09Hr0WqlSLUs4i4ltHGXqTe7VHclYWyA==} dev: true + /split-string@3.1.0: + resolution: {integrity: sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==} + engines: {node: '>=0.10.0'} + dependencies: + extend-shallow: 3.0.2 + dev: false + /sprintf-js@1.0.3: resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} dev: true @@ -17459,17 +17736,16 @@ packages: strip-ansi: 7.0.1 dev: true - /string.prototype.matchall@4.0.10: - resolution: {integrity: sha512-rGXbGmOEosIQi6Qva94HUjgPs9vKW+dkG7Y8Q5O2OYkWL6wFaTRZO8zM4mhP94uX55wgyrXzfS2aGtGzUL7EJQ==} + /string.prototype.matchall@4.0.8: + resolution: {integrity: sha512-6zOCOcJ+RJAQshcTvXPHoxoQGONa3e/Lqx90wUA+wEzX78sg5Bo+1tQo4N0pohS0erG9qtCqJDjNCQBjeWVxyg==} dependencies: - call-bind: 1.0.5 - define-properties: 1.2.1 - es-abstract: 1.22.3 - get-intrinsic: 1.2.2 + call-bind: 1.0.2 + define-properties: 1.1.4 + es-abstract: 1.20.4 + get-intrinsic: 1.1.3 has-symbols: 1.0.3 - internal-slot: 1.0.6 - regexp.prototype.flags: 1.5.1 - set-function-name: 2.0.1 + internal-slot: 1.0.3 + regexp.prototype.flags: 1.4.3 side-channel: 1.0.4 dev: true @@ -17482,6 +17758,14 @@ packages: es-abstract: 1.22.3 dev: true + /string.prototype.trimend@1.0.5: + resolution: {integrity: sha512-I7RGvmjV4pJ7O3kdf+LXFpVfdNOxtCW/2C8f6jNiW4+PQchwxkCDzlk1/7p+Wl4bqFIZeF47qAHXLuHHWKAxog==} + dependencies: + call-bind: 1.0.5 + define-properties: 1.2.1 + es-abstract: 1.22.3 + dev: true + /string.prototype.trimend@1.0.7: resolution: {integrity: sha512-Ni79DqeB72ZFq1uH/L6zJ+DKZTkOtPIHovb3YZHQViE+HDouuU4mBrLOLDn5Dde3RF8qw5qVETEjhu9locMLvA==} dependencies: @@ -17490,6 +17774,14 @@ packages: es-abstract: 1.22.3 dev: true + /string.prototype.trimstart@1.0.5: + resolution: {integrity: sha512-THx16TJCGlsN0o6dl2o6ncWUsdgnLRSA23rRE5pyGBw/mLr3Ej/R2LaqCtgP8VNMGZsvMWnf9ooZPyY2bHvUFg==} + dependencies: + call-bind: 1.0.5 + define-properties: 1.2.1 + es-abstract: 1.22.3 + dev: true + /string.prototype.trimstart@1.0.7: resolution: {integrity: sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg==} dependencies: @@ -17613,6 +17905,12 @@ packages: ts-interface-checker: 0.1.13 dev: true + /supercluster@8.0.1: + resolution: {integrity: sha512-IiOea5kJ9iqzD2t7QJq/cREyLHTtSmUT6gQsweojg9WH2sYJqZK9SswTu6jrscO6D1G5v5vYZ9ru/eq85lXeZQ==} + dependencies: + kdbush: 4.0.2 + dev: false + /supports-color@5.5.0: resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} engines: {node: '>=4'} @@ -17664,7 +17962,7 @@ packages: csso: 4.2.0 js-yaml: 3.14.1 mkdirp: 0.5.6 - object.values: 1.1.7 + object.values: 1.1.6 sax: 1.2.4 stable: 0.1.8 unquote: 1.1.1 @@ -17880,6 +18178,10 @@ packages: engines: {node: '>=6'} dev: false + /tinyqueue@2.0.3: + resolution: {integrity: sha512-ppJZNDuKGgxzkHihX8v9v9G5f+18gzaTfrukGrq6ueg0lmH4nqVnA2IPG0AEH3jKEk2GRJCUhDoqpoiw3PHLBA==} + dev: false + /tippy.js@6.3.7: resolution: {integrity: sha512-E1d3oP2emgJ9dRQZdf3Kkn0qJgI6ZLpyS5z6ZkY1DF3kaQaBsGZsndEpHwx+eC+tYM41HaSNvNtLx8tU57FzTQ==} dependencies: @@ -17960,8 +18262,8 @@ packages: resolution: {integrity: sha512-rvuRbTarPXmMb79SmzEp8aqXNKcK+y0XaB298IXueQ8I2PsrATcPBCSPyK/dDNa2iWOhKlfNnOjdAOTBU/nkFA==} dev: false - /ts-api-utils@1.0.3(typescript@4.9.5): - resolution: {integrity: sha512-wNMeqtMz5NtwpT/UZGY5alT+VoKdSsOOP/kqHFcUW1P/VRhH2wJ48+DN2WwUliNbQ976ETwDL0Ifd2VVvgonvg==} + /ts-api-utils@1.0.2(typescript@4.9.5): + resolution: {integrity: sha512-Cbu4nIqnEdd+THNEsBdkolnOXhg0I8XteoHaEKgvsxpsbWda4IsUut2c187HxywQCvveojow0Dgw/amxtSKVkQ==} engines: {node: '>=16.13.0'} peerDependencies: typescript: '>=4.2.0' @@ -18046,6 +18348,7 @@ packages: /tslib@2.6.2: resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==} + dev: true /tsutils@3.21.0(typescript@4.9.5): resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==} @@ -18118,8 +18421,8 @@ packages: resolution: {integrity: sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==} engines: {node: '>=12.20'} - /type-fest@3.13.1: - resolution: {integrity: sha512-tLq3bSNx+xSpwvAJnzrK0Ep5CLNWjvFTOp71URMaAEWBfRb9nnJiBoUe0tF8bI4ZFO3omgBR6NvnbzVUT3Ly4g==} + /type-fest@3.5.3: + resolution: {integrity: sha512-V2+og4j/rWReWvaFrse3s9g2xvUv/K9Azm/xo6CjIuq7oeGqsoimC7+9/A3tfvNcbQf8RPSVj/HV81fB4DJrjA==} engines: {node: '>=14.16'} dev: true @@ -18184,6 +18487,16 @@ packages: hasBin: true dev: true + /typewise-core@1.2.0: + resolution: {integrity: sha512-2SCC/WLzj2SbUwzFOzqMCkz5amXLlxtJqDKTICqg30x+2DZxcfZN2MvQZmGfXWKNWaKK9pBPsvkcwv8bF/gxKg==} + dev: false + + /typewise@1.0.3: + resolution: {integrity: sha512-aXofE06xGhaQSPzt8hlTY+/YWQhm9P0jYUp1f2XtmW/3Bk0qzXcyFWAtPoo2uTGQj1ZwbDuSyuxicq+aDo8lCQ==} + dependencies: + typewise-core: 1.2.0 + dev: false + /ua-parser-js@0.7.32: resolution: {integrity: sha512-f9BESNVhzlhEFf2CHMSj40NWOjYPl1YKYbrvIr/hFTDEmLq7SRbWvm7FcdcpCYT95zrOhC7gZSxjdnnTpBcwVw==} dev: false @@ -18244,6 +18557,16 @@ packages: vfile: 4.2.1 dev: false + /union-value@1.0.1: + resolution: {integrity: sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==} + engines: {node: '>=0.10.0'} + dependencies: + arr-union: 3.1.0 + get-value: 2.0.6 + is-extendable: 0.1.1 + set-value: 2.0.1 + dev: false + /uniq@1.0.1: resolution: {integrity: sha512-Gw+zz50YNKPDKXs+9d+aKAjVwpjNwqzvNpLigIruT4HA9lMZNdMqs9x07kKHB/L9WRzqp4+DlTU5s4wG2esdoA==} dev: true @@ -18549,6 +18872,14 @@ packages: vfile-message: 2.0.4 dev: false + /vt-pbf@3.1.3: + resolution: {integrity: sha512-2LzDFzt0mZKZ9IpVF2r69G9bXaP2Q2sArJCmcCgvfTdCCZzSyz4aCLoQyUilu37Ll56tCblIZrXFIjNUpGIlmA==} + dependencies: + '@mapbox/point-geometry': 0.1.0 + '@mapbox/vector-tile': 1.3.1 + pbf: 3.2.1 + dev: false + /w3c-keyname@2.2.6: resolution: {integrity: sha512-f+fciywl1SJEniZHD6H+kUO8gOnwIr7f4ijKA6+ZvJFjeGi1r4PDLl53Ayud9O/rk64RqgoQine0feoeOU0kXg==} dev: false @@ -18826,7 +19157,6 @@ packages: for-each: 0.3.3 gopd: 1.0.1 has-tostringtag: 1.0.0 - dev: true /which-typed-array@1.1.9: resolution: {integrity: sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA==} @@ -18837,14 +19167,13 @@ packages: for-each: 0.3.3 gopd: 1.0.1 has-tostringtag: 1.0.0 - is-typed-array: 1.1.10 + is-typed-array: 1.1.12 /which@1.3.1: resolution: {integrity: sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==} hasBin: true dependencies: isexe: 2.0.0 - dev: true /which@2.0.2: resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} diff --git a/posthog/settings/__init__.py b/posthog/settings/__init__.py index 32b3d87d322ae..c164be0503f5d 100644 --- a/posthog/settings/__init__.py +++ b/posthog/settings/__init__.py @@ -79,6 +79,9 @@ # Whether kea should be act in verbose mode KEA_VERBOSE_LOGGING = get_from_env("KEA_VERBOSE_LOGGING", False, type_cast=str_to_bool) +# MapLibre Style URL to configure map tile source +MAPLIBRE_STYLE_URL = get_from_env("MAPLIBRE_STYLE_URL", optional=True) + # Only written in specific scripts - do not use outside of them. PERSON_ON_EVENTS_OVERRIDE = get_from_env("PERSON_ON_EVENTS_OVERRIDE", optional=True, type_cast=str_to_bool) diff --git a/posthog/templates/head.html b/posthog/templates/head.html index ed0d359faa014..7ca827ae15914 100644 --- a/posthog/templates/head.html +++ b/posthog/templates/head.html @@ -36,6 +36,11 @@ window.SENTRY_ENVIRONMENT = '{{ sentry_environment | escapejs }}'; {% endif %} +{% if js_maplibre_style_url %} + +{% endif %} check?"}, + { + "type": "open", + "question": "What up?", + "description": "check?", + }, { "type": "link", "link": "bazinga.com", @@ -828,7 +956,11 @@ def test_update_basic_survey_question_validation(self): "description": "Get feedback on the new notebooks feature", "type": "popover", "questions": [ - {"type": "open", "question": "What up?", "description": "check?"}, + { + "type": "open", + "question": "What up?", + "description": "check?", + }, { "type": "link", "link": "bazinga.com", diff --git a/posthog/api/test/test_team.py b/posthog/api/test/test_team.py index 052604d151276..297d23e54372c 100644 --- a/posthog/api/test/test_team.py +++ b/posthog/api/test/test_team.py @@ -54,7 +54,8 @@ def test_retrieve_project(self): get_instance_setting("PERSON_ON_EVENTS_ENABLED") or get_instance_setting("PERSON_ON_EVENTS_V2_ENABLED"), ) self.assertEqual( - response_data["groups_on_events_querying_enabled"], get_instance_setting("GROUPS_ON_EVENTS_ENABLED") + response_data["groups_on_events_querying_enabled"], + get_instance_setting("GROUPS_ON_EVENTS_ENABLED"), ) # TODO: These assertions will no longer make sense when we fully remove these attributes from the model @@ -188,13 +189,17 @@ def test_cant_update_project_from_another_org(self): def test_filter_permission(self): response = self.client.patch( - f"/api/projects/{self.team.id}/", {"test_account_filters": [{"key": "$current_url", "value": "test"}]} + f"/api/projects/{self.team.id}/", + {"test_account_filters": [{"key": "$current_url", "value": "test"}]}, ) self.assertEqual(response.status_code, status.HTTP_200_OK) response_data = response.json() self.assertEqual(response_data["name"], self.team.name) - self.assertEqual(response_data["test_account_filters"], [{"key": "$current_url", "value": "test"}]) + self.assertEqual( + response_data["test_account_filters"], + [{"key": "$current_url", "value": "test"}], + ) @patch("posthog.api.team.delete_bulky_postgres_data") @patch("posthoganalytics.capture") @@ -211,13 +216,18 @@ def test_delete_team_own_second(self, mock_capture: MagicMock, mock_delete_bulky self.assertEqual(response.status_code, 204) self.assertEqual(Team.objects.filter(organization=self.organization).count(), 1) self.assertEqual( - AsyncDeletion.objects.filter(team_id=team.id, deletion_type=DeletionType.Team, key=str(team.id)).count(), 1 + AsyncDeletion.objects.filter(team_id=team.id, deletion_type=DeletionType.Team, key=str(team.id)).count(), + 1, ) mock_capture.assert_called_once_with( self.user.distinct_id, "team deleted", properties={}, - groups={"instance": ANY, "organization": str(self.organization.id), "project": str(self.team.uuid)}, + groups={ + "instance": ANY, + "organization": str(self.organization.id), + "project": str(self.team.uuid), + }, ) mock_delete_bulky_postgres_data.assert_called_once_with(team_ids=[team.pk]) @@ -240,14 +250,23 @@ def test_delete_bulky_postgres_data(self): cohort = Cohort.objects.create(team=team, created_by=self.user, name="test") person = Person.objects.create( - team=team, distinct_ids=["example_id"], properties={"email": "tim@posthog.com", "team": "posthog"} + team=team, + distinct_ids=["example_id"], + properties={"email": "tim@posthog.com", "team": "posthog"}, ) person.add_distinct_id("test") flag = FeatureFlag.objects.create( - team=team, name="test", key="test", rollout_percentage=50, created_by=self.user + team=team, + name="test", + key="test", + rollout_percentage=50, + created_by=self.user, ) FeatureFlagHashKeyOverride.objects.create( - team_id=team.pk, person_id=person.id, feature_flag_key=flag.key, hash_key="test" + team_id=team.pk, + person_id=person.id, + feature_flag_key=flag.key, + hash_key="test", ) CohortPeople.objects.create(cohort_id=cohort.pk, person_id=person.pk) EarlyAccessFeature.objects.create( @@ -359,13 +378,16 @@ def test_update_timezone_remove_cache(self): data={"filters": {"events": json.dumps([{"id": "user signed up"}])}}, ) response = self.client.post( - f"/api/projects/{self.team.id}/insights/", data={"filters": {"events": json.dumps([{"id": "$pageview"}])}} + f"/api/projects/{self.team.id}/insights/", + data={"filters": {"events": json.dumps([{"id": "$pageview"}])}}, ).json() self.client.get( - f"/api/projects/{self.team.id}/insights/trend/", data={"events": json.dumps([{"id": "$pageview"}])} + f"/api/projects/{self.team.id}/insights/trend/", + data={"events": json.dumps([{"id": "$pageview"}])}, ) self.client.get( - f"/api/projects/{self.team.id}/insights/trend/", data={"events": json.dumps([{"id": "user signed up"}])} + f"/api/projects/{self.team.id}/insights/trend/", + data={"events": json.dumps([{"id": "user signed up"}])}, ) self.assertEqual(cache.get(response["filters_hash"])["result"][0]["count"], 0) @@ -412,7 +434,8 @@ def test_team_is_cached_on_create_and_update(self): self.assertEqual(cached_team.id, response.json()["id"]) response = self.client.patch( - f"/api/projects/{team_id}/", {"timezone": "Europe/Istanbul", "session_recording_opt_in": True} + f"/api/projects/{team_id}/", + {"timezone": "Europe/Istanbul", "session_recording_opt_in": True}, ) self.assertEqual(response.status_code, status.HTTP_200_OK) @@ -443,7 +466,10 @@ def test_turn_on_exception_autocapture(self): response = self.client.get("/api/projects/@current/") assert response.json()["autocapture_exceptions_opt_in"] is None - response = self.client.patch("/api/projects/@current/", {"autocapture_exceptions_opt_in": "Welwyn Garden City"}) + response = self.client.patch( + "/api/projects/@current/", + {"autocapture_exceptions_opt_in": "Welwyn Garden City"}, + ) assert response.status_code == status.HTTP_400_BAD_REQUEST assert response.json()["detail"] == "Must be a valid boolean." @@ -457,12 +483,16 @@ def test_configure_exception_autocapture_event_dropping(self): assert response.json()["autocapture_exceptions_errors_to_ignore"] is None response = self.client.patch( - "/api/projects/@current/", {"autocapture_exceptions_errors_to_ignore": {"wat": "am i"}} + "/api/projects/@current/", + {"autocapture_exceptions_errors_to_ignore": {"wat": "am i"}}, ) assert response.status_code == status.HTTP_400_BAD_REQUEST assert response.json()["detail"] == "Must provide a list for field: autocapture_exceptions_errors_to_ignore." - response = self.client.patch("/api/projects/@current/", {"autocapture_exceptions_errors_to_ignore": [1, False]}) + response = self.client.patch( + "/api/projects/@current/", + {"autocapture_exceptions_errors_to_ignore": [1, False]}, + ) assert response.status_code == status.HTTP_400_BAD_REQUEST assert ( response.json()["detail"] @@ -470,7 +500,8 @@ def test_configure_exception_autocapture_event_dropping(self): ) response = self.client.patch( - "/api/projects/@current/", {"autocapture_exceptions_errors_to_ignore": ["wat am i"]} + "/api/projects/@current/", + {"autocapture_exceptions_errors_to_ignore": ["wat am i"]}, ) assert response.status_code == status.HTTP_200_OK response = self.client.get("/api/projects/@current/") @@ -478,7 +509,8 @@ def test_configure_exception_autocapture_event_dropping(self): def test_configure_exception_autocapture_event_dropping_only_allows_simple_config(self): response = self.client.patch( - "/api/projects/@current/", {"autocapture_exceptions_errors_to_ignore": ["abc" * 300]} + "/api/projects/@current/", + {"autocapture_exceptions_errors_to_ignore": ["abc" * 300]}, ) assert response.status_code == status.HTTP_400_BAD_REQUEST assert ( @@ -488,10 +520,30 @@ def test_configure_exception_autocapture_event_dropping_only_allows_simple_confi @parameterized.expand( [ - ["non numeric string", "Welwyn Garden City", "invalid_input", "A valid number is required."], - ["negative number", "-1", "min_value", "Ensure this value is greater than or equal to 0."], - ["greater than one", "1.5", "max_value", "Ensure this value is less than or equal to 1."], - ["too many digits", "0.534", "max_decimal_places", "Ensure that there are no more than 2 decimal places."], + [ + "non numeric string", + "Welwyn Garden City", + "invalid_input", + "A valid number is required.", + ], + [ + "negative number", + "-1", + "min_value", + "Ensure this value is greater than or equal to 0.", + ], + [ + "greater than one", + "1.5", + "max_value", + "Ensure this value is less than or equal to 1.", + ], + [ + "too many digits", + "0.534", + "max_decimal_places", + "Ensure that there are no more than 2 decimal places.", + ], ] ) def test_invalid_session_recording_sample_rates( @@ -508,9 +560,24 @@ def test_invalid_session_recording_sample_rates( @parameterized.expand( [ - ["non numeric string", "Trentham monkey forest", "invalid_input", "A valid integer is required."], - ["negative number", "-1", "min_value", "Ensure this value is greater than or equal to 0."], - ["greater than 15000", "15001", "max_value", "Ensure this value is less than or equal to 15000."], + [ + "non numeric string", + "Trentham monkey forest", + "invalid_input", + "A valid integer is required.", + ], + [ + "negative number", + "-1", + "min_value", + "Ensure this value is greater than or equal to 0.", + ], + [ + "greater than 15000", + "15001", + "max_value", + "Ensure this value is less than or equal to 15000.", + ], ["too many digits", "0.5", "invalid_input", "A valid integer is required."], ] ) @@ -518,7 +585,8 @@ def test_invalid_session_recording_minimum_duration( self, _name: str, provided_value: str, expected_code: str, expected_error: str ) -> None: response = self.client.patch( - "/api/projects/@current/", {"session_recording_minimum_duration_milliseconds": provided_value} + "/api/projects/@current/", + {"session_recording_minimum_duration_milliseconds": provided_value}, ) assert response.status_code == status.HTTP_400_BAD_REQUEST assert response.json() == { @@ -530,7 +598,12 @@ def test_invalid_session_recording_minimum_duration( @parameterized.expand( [ - ["string", "Marple bridge", "invalid_input", "Must provide a dictionary or None."], + [ + "string", + "Marple bridge", + "invalid_input", + "Must provide a dictionary or None.", + ], ["numeric", "-1", "invalid_input", "Must provide a dictionary or None."], [ "unexpected json - no id", @@ -566,11 +639,15 @@ def test_invalid_session_recording_linked_flag( def test_can_set_and_unset_session_recording_linked_flag(self) -> None: first_patch_response = self.client.patch( - "/api/projects/@current/", {"session_recording_linked_flag": {"id": 1, "key": "provided_value"}} + "/api/projects/@current/", + {"session_recording_linked_flag": {"id": 1, "key": "provided_value"}}, ) assert first_patch_response.status_code == status.HTTP_200_OK get_response = self.client.get("/api/projects/@current/") - assert get_response.json()["session_recording_linked_flag"] == {"id": 1, "key": "provided_value"} + assert get_response.json()["session_recording_linked_flag"] == { + "id": 1, + "key": "provided_value", + } response = self.client.patch("/api/projects/@current/", {"session_recording_linked_flag": None}) assert response.status_code == status.HTTP_200_OK @@ -585,7 +662,11 @@ def create_team(organization: Organization, name: str = "Test team") -> Team: with real world scenarios. """ return Team.objects.create( - organization=organization, name=name, ingested_event=True, completed_snippet_onboarding=True, is_demo=True + organization=organization, + name=name, + ingested_event=True, + completed_snippet_onboarding=True, + is_demo=True, ) diff --git a/posthog/api/test/test_uploaded_media.py b/posthog/api/test/test_uploaded_media.py index c611643cb2610..2a7a23407fef6 100644 --- a/posthog/api/test/test_uploaded_media.py +++ b/posthog/api/test/test_uploaded_media.py @@ -52,7 +52,9 @@ def test_can_upload_and_retrieve_a_file(self) -> None: with self.settings(OBJECT_STORAGE_ENABLED=True, OBJECT_STORAGE_MEDIA_UPLOADS_FOLDER=TEST_BUCKET): with open(get_path_to("a-small-but-valid.gif"), "rb") as image: response = self.client.post( - f"/api/projects/{self.team.id}/uploaded_media", {"image": image}, format="multipart" + f"/api/projects/{self.team.id}/uploaded_media", + {"image": image}, + format="multipart", ) self.assertEqual(response.status_code, status.HTTP_201_CREATED, response.json()) assert response.json()["name"] == "a-small-but-valid.gif" @@ -68,14 +70,22 @@ def test_can_upload_and_retrieve_a_file(self) -> None: def test_rejects_non_image_file_type(self) -> None: fake_file = SimpleUploadedFile(name="test_image.jpg", content=b"a fake image", content_type="text/csv") response = self.client.post( - f"/api/projects/{self.team.id}/uploaded_media", {"image": fake_file}, format="multipart" + f"/api/projects/{self.team.id}/uploaded_media", + {"image": fake_file}, + format="multipart", + ) + self.assertEqual( + response.status_code, + status.HTTP_415_UNSUPPORTED_MEDIA_TYPE, + response.json(), ) - self.assertEqual(response.status_code, status.HTTP_415_UNSUPPORTED_MEDIA_TYPE, response.json()) def test_rejects_file_manually_crafted_to_start_with_image_magic_bytes(self) -> None: with open(get_path_to("file-masquerading-as-a.gif"), "rb") as image: response = self.client.post( - f"/api/projects/{self.team.id}/uploaded_media", {"image": image}, format="multipart" + f"/api/projects/{self.team.id}/uploaded_media", + {"image": image}, + format="multipart", ) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST, response.json()) @@ -88,10 +98,14 @@ def test_made_up_id_is_404(self) -> None: def test_rejects_too_large_file_type(self) -> None: four_megabytes_plus_a_little = b"1" * (4 * 1024 * 1024 + 1) fake_big_file = SimpleUploadedFile( - name="test_image.jpg", content=four_megabytes_plus_a_little, content_type="image/jpeg" + name="test_image.jpg", + content=four_megabytes_plus_a_little, + content_type="image/jpeg", ) response = self.client.post( - f"/api/projects/{self.team.id}/uploaded_media", {"image": fake_big_file}, format="multipart" + f"/api/projects/{self.team.id}/uploaded_media", + {"image": fake_big_file}, + format="multipart", ) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST, response.json()) self.assertEqual(response.json()["detail"], "Uploaded media must be less than 4MB") @@ -100,7 +114,12 @@ def test_rejects_upload_when_object_storage_is_unavailable(self) -> None: with override_settings(OBJECT_STORAGE_ENABLED=False): fake_big_file = SimpleUploadedFile(name="test_image.jpg", content=b"", content_type="image/jpeg") response = self.client.post( - f"/api/projects/{self.team.id}/uploaded_media", {"image": fake_big_file}, format="multipart" + f"/api/projects/{self.team.id}/uploaded_media", + {"image": fake_big_file}, + format="multipart", ) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST, response.json()) - self.assertEqual(response.json()["detail"], "Object storage must be available to allow media uploads.") + self.assertEqual( + response.json()["detail"], + "Object storage must be available to allow media uploads.", + ) diff --git a/posthog/api/test/test_user.py b/posthog/api/test/test_user.py index 62dca8dad6277..c5d93bbef211e 100644 --- a/posthog/api/test/test_user.py +++ b/posthog/api/test/test_user.py @@ -206,7 +206,11 @@ def test_update_current_user(self, mock_capture, mock_identify_task): "partial_notification_settings", ] }, - groups={"instance": ANY, "organization": str(self.team.organization_id), "project": str(self.team.uuid)}, + groups={ + "instance": ANY, + "organization": str(self.team.organization_id), + "project": str(self.team.uuid), + }, ) @patch("posthog.tasks.user_identify.identify_task") @@ -221,7 +225,12 @@ def test_set_scene_personalisation_for_user_dashboard_must_be_in_current_team( response = self.client.post( "/api/users/@me/scene_personalisation", # even if someone tries to send a different user or team they are ignored - {"user": 12345, "team": 12345, "dashboard": str(dashboard_one.id), "scene": "Person"}, + { + "user": 12345, + "team": 12345, + "dashboard": str(dashboard_one.id), + "scene": "Person", + }, ) assert response.status_code == status.HTTP_400_BAD_REQUEST @@ -320,7 +329,12 @@ def _assert_set_scene_choice( response = self.client.post( "/api/users/@me/scene_personalisation", # even if someone tries to send a different user or team they are ignored - {"user": 12345, "team": 12345, "dashboard": str(dashboard.id), "scene": scene}, + { + "user": 12345, + "team": 12345, + "dashboard": str(dashboard.id), + "scene": scene, + }, ) assert response.status_code == status.HTTP_200_OK response_data = response.json() @@ -354,7 +368,10 @@ def test_no_notifications_when_user_email_is_changed_and_email_not_available( @patch("posthog.tasks.email.send_email_change_emails.delay") @patch("posthog.tasks.email.send_email_verification.delay") def test_notifications_sent_when_user_email_is_changed_and_email_available( - self, mock_send_email_verification, mock_send_email_change_emails, mock_is_email_available + self, + mock_send_email_verification, + mock_send_email_change_emails, + mock_is_email_available, ): """Test that when a user updates their email, they receive a verification email before the switch actually happens.""" self.user.email = "alpha@example.com" @@ -381,7 +398,10 @@ def test_notifications_sent_when_user_email_is_changed_and_email_available( token = email_verification_token_generator.make_token(self.user) with freeze_time("2020-01-01T21:37:00+00:00"): - response = self.client.post(f"/api/users/@me/verify_email/", {"uuid": self.user.uuid, "token": token}) + response = self.client.post( + f"/api/users/@me/verify_email/", + {"uuid": self.user.uuid, "token": token}, + ) self.assertEqual(response.status_code, status.HTTP_200_OK) self.user.refresh_from_db() @@ -389,7 +409,10 @@ def test_notifications_sent_when_user_email_is_changed_and_email_available( self.assertIsNone(self.user.pending_email) mock_is_email_available.assert_called_once() mock_send_email_change_emails.assert_called_once_with( - "2020-01-01T21:37:00+00:00", self.user.first_name, "alpha@example.com", "beta@example.com" + "2020-01-01T21:37:00+00:00", + self.user.first_name, + "alpha@example.com", + "beta@example.com", ) @patch("posthog.api.user.is_email_available", return_value=True) @@ -420,7 +443,8 @@ def test_cannot_upgrade_yourself_to_staff_user(self): self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) self.assertEqual( - response.json(), self.permission_denied_response("You are not a staff user, contact your instance admin.") + response.json(), + self.permission_denied_response("You are not a staff user, contact your instance admin."), ) self.user.refresh_from_db() @@ -447,7 +471,11 @@ def test_can_update_current_organization(self, mock_capture, mock_identify): self.user.distinct_id, "user updated", properties={"updated_attrs": ["current_organization", "current_team"]}, - groups={"instance": ANY, "organization": str(self.new_org.id), "project": str(self.new_project.uuid)}, + groups={ + "instance": ANY, + "organization": str(self.new_org.id), + "project": str(self.new_project.uuid), + }, ) @patch("posthog.tasks.user_identify.identify_task") @@ -471,7 +499,11 @@ def test_can_update_current_project(self, mock_capture, mock_identify): self.user.distinct_id, "user updated", properties={"updated_attrs": ["current_organization", "current_team"]}, - groups={"instance": ANY, "organization": str(self.new_org.id), "project": str(team.uuid)}, + groups={ + "instance": ANY, + "organization": str(self.new_org.id), + "project": str(team.uuid), + }, ) def test_cannot_set_mismatching_org_and_team(self): @@ -481,7 +513,11 @@ def test_cannot_set_mismatching_org_and_team(self): self.user.join(organization=org) response = self.client.patch( - "/api/users/@me/", {"set_current_team": team.id, "set_current_organization": self.organization.id} + "/api/users/@me/", + { + "set_current_team": team.id, + "set_current_organization": self.organization.id, + }, ) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) self.assertEqual( @@ -583,7 +619,10 @@ def test_user_can_update_password(self, mock_capture, mock_identify): user = self._create_user("bob@posthog.com", password="A12345678") self.client.force_login(user) - response = self.client.patch("/api/users/@me/", {"current_password": "A12345678", "password": "a_new_password"}) + response = self.client.patch( + "/api/users/@me/", + {"current_password": "A12345678", "password": "a_new_password"}, + ) self.assertEqual(response.status_code, status.HTTP_200_OK) response_data = response.json() self.assertEqual(response_data["email"], "bob@posthog.com") @@ -602,7 +641,11 @@ def test_user_can_update_password(self, mock_capture, mock_identify): user.distinct_id, "user updated", properties={"updated_attrs": ["password"]}, - groups={"instance": ANY, "organization": str(self.team.organization_id), "project": str(self.team.uuid)}, + groups={ + "instance": ANY, + "organization": str(self.team.organization_id), + "project": str(self.team.uuid), + }, ) # User can log in with new password @@ -616,7 +659,8 @@ def test_user_with_no_password_set_can_set_password(self, mock_capture, mock_ide self.client.force_login(user) response = self.client.patch( - "/api/users/@me/", {"password": "a_new_password"} # note we don't send current password + "/api/users/@me/", + {"password": "a_new_password"}, # note we don't send current password ) self.assertEqual(response.status_code, status.HTTP_200_OK) response_data = response.json() @@ -636,11 +680,18 @@ def test_user_with_no_password_set_can_set_password(self, mock_capture, mock_ide user.distinct_id, "user updated", properties={"updated_attrs": ["password"]}, - groups={"instance": ANY, "organization": str(self.team.organization_id), "project": str(self.team.uuid)}, + groups={ + "instance": ANY, + "organization": str(self.team.organization_id), + "project": str(self.team.uuid), + }, ) # User can log in with new password - response = self.client.post("/api/login", {"email": "no_password@posthog.com", "password": "a_new_password"}) + response = self.client.post( + "/api/login", + {"email": "no_password@posthog.com", "password": "a_new_password"}, + ) self.assertEqual(response.status_code, status.HTTP_200_OK) def test_user_with_unusable_password_set_can_set_password(self): @@ -663,7 +714,10 @@ def test_user_with_unusable_password_set_can_set_password(self): @patch("posthog.tasks.user_identify.identify_task") @patch("posthoganalytics.capture") def test_cannot_update_to_insecure_password(self, mock_capture, mock_identify): - response = self.client.patch("/api/users/@me/", {"current_password": self.CONFIG_PASSWORD, "password": "123"}) + response = self.client.patch( + "/api/users/@me/", + {"current_password": self.CONFIG_PASSWORD, "password": "123"}, + ) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) self.assertEqual( response.json(), @@ -740,7 +794,10 @@ def test_user_cannot_update_password_with_incorrect_current_password_and_ratelim for _ in range(7): response = self.client.patch("/api/users/@me/", {"current_password": "wrong", "password": "12345678"}) self.assertEqual(response.status_code, status.HTTP_429_TOO_MANY_REQUESTS) - self.assertDictContainsSubset({"attr": None, "code": "throttled", "type": "throttled_error"}, response.json()) + self.assertDictContainsSubset( + {"attr": None, "code": "throttled", "type": "throttled_error"}, + response.json(), + ) # Password was not changed self.user.refresh_from_db() @@ -957,7 +1014,9 @@ def test_user_can_request_verification_email(self, mock_capture): html_message = mail.outbox[0].alternatives[0][0] # type: ignore self.validate_basic_html( - html_message, "https://my.posthog.net", preheader="Please follow the link inside to verify your account." + html_message, + "https://my.posthog.net", + preheader="Please follow the link inside to verify your account.", ) link_index = html_message.find("https://my.posthog.net/verify_email") reset_link = html_message[link_index : html_message.find('"', link_index)] @@ -975,7 +1034,11 @@ def test_user_can_request_verification_email(self, mock_capture): self.user.distinct_id, "user logged in", properties={"social_provider": ""}, - groups={"instance": ANY, "organization": str(self.team.organization_id), "project": str(self.team.uuid)}, + groups={ + "instance": ANY, + "organization": str(self.team.organization_id), + "project": str(self.team.uuid), + }, ) mock_capture.assert_any_call( self.user.distinct_id, @@ -1003,14 +1066,18 @@ def test_cant_verify_more_than_six_times(self): for i in range(7): with self.settings(CELERY_TASK_ALWAYS_EAGER=True, SITE_URL="https://my.posthog.net"): - response = self.client.post(f"/api/users/@me/request_email_verification/", {"uuid": self.user.uuid}) + response = self.client.post( + f"/api/users/@me/request_email_verification/", + {"uuid": self.user.uuid}, + ) if i < 6: self.assertEqual(response.status_code, status.HTTP_200_OK) else: # Fourth request should fail self.assertEqual(response.status_code, status.HTTP_429_TOO_MANY_REQUESTS) self.assertDictContainsSubset( - {"attr": None, "code": "throttled", "type": "throttled_error"}, response.json() + {"attr": None, "code": "throttled", "type": "throttled_error"}, + response.json(), ) # Three emails should be sent, fourth should not @@ -1028,7 +1095,12 @@ def test_cant_validate_email_verification_token_without_a_token(self): self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) self.assertEqual( response.json(), - {"type": "validation_error", "code": "required", "detail": "This field is required.", "attr": "token"}, + { + "type": "validation_error", + "code": "required", + "detail": "This field is required.", + "attr": "token", + }, ) def test_invalid_verification_token_returns_error(self): @@ -1038,8 +1110,16 @@ def test_invalid_verification_token_returns_error(self): # tokens expire after one day expired_token = default_token_generator.make_token(self.user) - for token in [valid_token[:-1], "not_even_trying", self.user.uuid, expired_token]: - response = self.client.post(f"/api/users/@me/verify_email/", {"uuid": self.user.uuid, "token": token}) + for token in [ + valid_token[:-1], + "not_even_trying", + self.user.uuid, + expired_token, + ]: + response = self.client.post( + f"/api/users/@me/verify_email/", + {"uuid": self.user.uuid, "token": token}, + ) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) self.assertEqual( response.json(), diff --git a/posthog/api/test/test_utils.py b/posthog/api/test/test_utils.py index 84a3d7315c220..8e0f08b009606 100644 --- a/posthog/api/test/test_utils.py +++ b/posthog/api/test/test_utils.py @@ -46,17 +46,24 @@ def test_format_paginated_url(self): "http://testserver/api/some_url?offset=10", ) self.assertEqual( - format_paginated_url(request("/api/some_url?offset=0"), offset=0, page_size=10), "api/some_url?offset=10" + format_paginated_url(request("/api/some_url?offset=0"), offset=0, page_size=10), + "api/some_url?offset=10", ) self.assertEqual( format_paginated_url( - request("/api/some_url?offset=0"), offset=0, page_size=10, mode=PaginationMode.previous + request("/api/some_url?offset=0"), + offset=0, + page_size=10, + mode=PaginationMode.previous, ), None, ) self.assertEqual( format_paginated_url( - request("/api/some_url?offset=0"), offset=20, page_size=10, mode=PaginationMode.previous + request("/api/some_url?offset=0"), + offset=20, + page_size=10, + mode=PaginationMode.previous, ), "api/some_url?offset=0", ) @@ -64,7 +71,11 @@ def test_format_paginated_url(self): def test_get_target_entity(self): request = lambda url: cast(Any, RequestFactory().get(url)) filter = Filter( - data={"entity_id": "$pageview", "entity_type": "events", "events": [{"id": "$pageview", "type": "events"}]} + data={ + "entity_id": "$pageview", + "entity_type": "events", + "events": [{"id": "$pageview", "type": "events"}], + } ) entity = get_target_entity(filter) @@ -90,10 +101,20 @@ def test_get_target_entity(self): assert entity.math == "unique_group" def test_check_definition_ids_inclusion_field_sql(self): + definition_ids = [ + "", + None, + '["1fcefbef-7ea1-42fd-abca-4848b53133c0", "c8452399-8a10-4142-864d-6f2ca8c65154"]', + ] - definition_ids = ["", None, '["1fcefbef-7ea1-42fd-abca-4848b53133c0", "c8452399-8a10-4142-864d-6f2ca8c65154"]'] - - expected_ids_list = [[], [], ["1fcefbef-7ea1-42fd-abca-4848b53133c0", "c8452399-8a10-4142-864d-6f2ca8c65154"]] + expected_ids_list = [ + [], + [], + [ + "1fcefbef-7ea1-42fd-abca-4848b53133c0", + "c8452399-8a10-4142-864d-6f2ca8c65154", + ], + ] for raw_ids, expected_ids in zip(definition_ids, expected_ids_list): ordered_expected_ids = list(set(expected_ids)) # type: ignore @@ -155,27 +176,43 @@ def test_raise_if_user_provided_url_unsafe(self): raise_if_user_provided_url_unsafe("https://1.1.1.1") # Safe, public IP self.assertRaisesMessage(ValueError, "No hostname", lambda: raise_if_user_provided_url_unsafe("")) self.assertRaisesMessage(ValueError, "No hostname", lambda: raise_if_user_provided_url_unsafe("@@@")) - self.assertRaisesMessage(ValueError, "No hostname", lambda: raise_if_user_provided_url_unsafe("posthog.com")) + self.assertRaisesMessage( + ValueError, + "No hostname", + lambda: raise_if_user_provided_url_unsafe("posthog.com"), + ) self.assertRaisesMessage( ValueError, "Scheme must be either HTTP or HTTPS", lambda: raise_if_user_provided_url_unsafe("ftp://posthog.com"), ) self.assertRaisesMessage( - ValueError, "Internal hostname", lambda: raise_if_user_provided_url_unsafe("http://localhost") + ValueError, + "Internal hostname", + lambda: raise_if_user_provided_url_unsafe("http://localhost"), ) self.assertRaisesMessage( - ValueError, "Internal hostname", lambda: raise_if_user_provided_url_unsafe("http://192.168.0.5") + ValueError, + "Internal hostname", + lambda: raise_if_user_provided_url_unsafe("http://192.168.0.5"), ) self.assertRaisesMessage( - ValueError, "Internal hostname", lambda: raise_if_user_provided_url_unsafe("http://0.0.0.0") + ValueError, + "Internal hostname", + lambda: raise_if_user_provided_url_unsafe("http://0.0.0.0"), ) self.assertRaisesMessage( - ValueError, "Internal hostname", lambda: raise_if_user_provided_url_unsafe("http://10.0.0.24") + ValueError, + "Internal hostname", + lambda: raise_if_user_provided_url_unsafe("http://10.0.0.24"), ) self.assertRaisesMessage( - ValueError, "Internal hostname", lambda: raise_if_user_provided_url_unsafe("http://172.20.0.21") + ValueError, + "Internal hostname", + lambda: raise_if_user_provided_url_unsafe("http://172.20.0.21"), ) self.assertRaisesMessage( - ValueError, "Invalid hostname", lambda: raise_if_user_provided_url_unsafe("http://fgtggggzzggggfd.com") + ValueError, + "Invalid hostname", + lambda: raise_if_user_provided_url_unsafe("http://fgtggggzzggggfd.com"), ) # Non-existent diff --git a/posthog/api/uploaded_media.py b/posthog/api/uploaded_media.py index 5b0e68b5ab2e7..4893994ecdb55 100644 --- a/posthog/api/uploaded_media.py +++ b/posthog/api/uploaded_media.py @@ -7,7 +7,11 @@ from drf_spectacular.utils import extend_schema from PIL import Image from rest_framework import status, viewsets -from rest_framework.exceptions import APIException, UnsupportedMediaType, ValidationError +from rest_framework.exceptions import ( + APIException, + UnsupportedMediaType, + ValidationError, +) from rest_framework.parsers import FormParser, MultiPartParser from rest_framework.permissions import IsAuthenticatedOrReadOnly from rest_framework.response import Response @@ -16,7 +20,10 @@ from posthog.api.routing import StructuredViewSetMixin from posthog.models import UploadedMedia from posthog.models.uploaded_media import ObjectStorageUnavailable -from posthog.permissions import ProjectMembershipNecessaryPermissions, TeamMemberAccessPermission +from posthog.permissions import ( + ProjectMembershipNecessaryPermissions, + TeamMemberAccessPermission, +) from posthog.storage import object_storage FOUR_MEGABYTES = 4 * 1024 * 1024 @@ -43,7 +50,12 @@ def validate_image_file(file: Optional[bytes], user: int) -> bool: im.close() return True except Exception as e: - logger.error("uploaded_media.image_verification_error", user=user, exception=e, exc_info=True) + logger.error( + "uploaded_media.image_verification_error", + user=user, + exception=e, + exc_info=True, + ) return False @@ -61,7 +73,10 @@ def download(request, *args, **kwargs) -> HttpResponse: file_bytes = object_storage.read_bytes(instance.media_location) - statsd.incr("uploaded_media.served", tags={"team_id": instance.team_id, "uuid": kwargs["image_uuid"]}) + statsd.incr( + "uploaded_media.served", + tags={"team_id": instance.team_id, "uuid": kwargs["image_uuid"]}, + ) return HttpResponse( file_bytes, @@ -109,15 +124,20 @@ def create(self, request, *args, **kwargs) -> Response: bytes_to_verify = object_storage.read_bytes(uploaded_media.media_location) if not validate_image_file(bytes_to_verify, user=request.user.id): statsd.incr( - "uploaded_media.image_failed_validation", tags={"file_name": file.name, "team": self.team_id} + "uploaded_media.image_failed_validation", + tags={"file_name": file.name, "team": self.team_id}, ) # TODO a batch process can delete media with no records in the DB or for deleted teams uploaded_media.delete() - raise ValidationError(code="invalid_image", detail="Uploaded media must be a valid image") + raise ValidationError( + code="invalid_image", + detail="Uploaded media must be a valid image", + ) headers = self.get_success_headers(uploaded_media.get_absolute_url()) statsd.incr( - "uploaded_media.uploaded", tags={"team_id": self.team.pk, "content_type": file.content_type} + "uploaded_media.uploaded", + tags={"team_id": self.team.pk, "content_type": file.content_type}, ) return Response( { @@ -134,7 +154,8 @@ def create(self, request, *args, **kwargs) -> Response: raise ValidationError(code="no-image-provided", detail="An image file must be provided") except ObjectStorageUnavailable: raise ValidationError( - code="object_storage_required", detail="Object storage must be available to allow media uploads." + code="object_storage_required", + detail="Object storage must be available to allow media uploads.", ) def get_success_headers(self, location: str) -> Dict: diff --git a/posthog/api/user.py b/posthog/api/user.py index 75276eca4f5ce..541a428074389 100644 --- a/posthog/api/user.py +++ b/posthog/api/user.py @@ -35,7 +35,11 @@ from posthog.auth import authenticate_secondarily from posthog.cloud_utils import is_cloud from posthog.email import is_email_available -from posthog.event_usage import report_user_logged_in, report_user_updated, report_user_verified_email +from posthog.event_usage import ( + report_user_logged_in, + report_user_updated, + report_user_verified_email, +) from posthog.models import Team, User, UserScenePersonalisation, Dashboard from posthog.models.organization import Organization from posthog.models.user import NOTIFICATION_DEFAULTS, Notifications @@ -110,7 +114,10 @@ class Meta: "has_seen_product_intro_for", "scene_personalisation", ] - extra_kwargs = {"date_joined": {"read_only": True}, "password": {"write_only": True}} + extra_kwargs = { + "date_joined": {"read_only": True}, + "password": {"write_only": True}, + } def get_has_password(self, instance: User) -> bool: return instance.has_usable_password() @@ -166,12 +173,14 @@ def validate_password_change( # usable (properly hashed) and that a password actually exists. if not current_password: raise serializers.ValidationError( - {"current_password": ["This field is required when updating your password."]}, code="required" + {"current_password": ["This field is required when updating your password."]}, + code="required", ) if not instance.check_password(current_password): raise serializers.ValidationError( - {"current_password": ["Your current password is incorrect."]}, code="incorrect_password" + {"current_password": ["Your current password is incorrect."]}, + code="incorrect_password", ) try: validate_password(password, instance) @@ -276,7 +285,12 @@ def save(self, **kwargs): ) -class UserViewSet(mixins.RetrieveModelMixin, mixins.UpdateModelMixin, mixins.ListModelMixin, viewsets.GenericViewSet): +class UserViewSet( + mixins.RetrieveModelMixin, + mixins.UpdateModelMixin, + mixins.ListModelMixin, + viewsets.GenericViewSet, +): throttle_classes = [UserAuthenticationThrottle] serializer_class = UserSerializer permission_classes = [permissions.IsAuthenticated] @@ -305,7 +319,10 @@ def get_queryset(self): return queryset def get_serializer_context(self): - return {**super().get_serializer_context(), "user_permissions": UserPermissions(cast(User, self.request.user))} + return { + **super().get_serializer_context(), + "user_permissions": UserPermissions(cast(User, self.request.user)), + } @action(methods=["GET"], detail=True) def start_2fa_setup(self, request, **kwargs): @@ -319,7 +336,9 @@ def start_2fa_setup(self, request, **kwargs): @action(methods=["POST"], detail=True) def validate_2fa(self, request, **kwargs): form = TOTPDeviceForm( - request.session["django_two_factor-hex"], request.user, data={"token": request.data["token"]} + request.session["django_two_factor-hex"], + request.user, + data={"token": request.data["token"]}, ) if not form.is_valid(): raise serializers.ValidationError("Token is not valid", code="token_invalid") @@ -345,7 +364,8 @@ def verify_email(self, request, **kwargs): if not user or not EmailVerifier.check_token(user, token): raise serializers.ValidationError( - {"token": ["This verification token is invalid or has expired."]}, code="invalid_token" + {"token": ["This verification token is invalid or has expired."]}, + code="invalid_token", ) if user.pending_email: @@ -364,7 +384,10 @@ def verify_email(self, request, **kwargs): return Response({"success": True, "token": token}) @action( - methods=["POST"], detail=True, permission_classes=[AllowAny], throttle_classes=[UserEmailVerificationThrottle] + methods=["POST"], + detail=True, + permission_classes=[AllowAny], + throttle_classes=[UserEmailVerificationThrottle], ) def request_email_verification(self, request, **kwargs): uuid = request.data["uuid"] diff --git a/posthog/apps.py b/posthog/apps.py index 6ae001ccf93fc..3e6b2aaf76fee 100644 --- a/posthog/apps.py +++ b/posthog/apps.py @@ -7,7 +7,12 @@ from posthoganalytics.client import Client from posthog.settings import SELF_CAPTURE, SKIP_ASYNC_MIGRATIONS_SETUP -from posthog.utils import get_git_branch, get_git_commit, get_machine_id, get_self_capture_api_token +from posthog.utils import ( + get_git_branch, + get_git_commit, + get_machine_id, + get_self_capture_api_token, +) logger = structlog.get_logger(__name__) diff --git a/posthog/async_migrations/definition.py b/posthog/async_migrations/definition.py index 77e7261aab55e..859b8af08819d 100644 --- a/posthog/async_migrations/definition.py +++ b/posthog/async_migrations/definition.py @@ -19,7 +19,11 @@ class AsyncMigrationOperation: - def __init__(self, fn: Callable[[str], None], rollback_fn: Callable[[str], None] = lambda _: None): + def __init__( + self, + fn: Callable[[str], None], + rollback_fn: Callable[[str], None] = lambda _: None, + ): self.fn = fn # This should not be a long operation as it will be executed synchronously! @@ -55,7 +59,10 @@ def rollback_fn(self, query_id: str): self._execute_op(query_id, self.rollback, self.rollback_settings) def _execute_op(self, query_id: str, sql: str, settings: Optional[Dict]): - from posthog.async_migrations.utils import execute_op_clickhouse, execute_op_postgres + from posthog.async_migrations.utils import ( + execute_op_clickhouse, + execute_op_postgres, + ) if self.database == AnalyticsDBMS.CLICKHOUSE: execute_op_clickhouse( diff --git a/posthog/async_migrations/disk_util.py b/posthog/async_migrations/disk_util.py index 96ff6a383e7fc..ac7398a2c3e2f 100644 --- a/posthog/async_migrations/disk_util.py +++ b/posthog/async_migrations/disk_util.py @@ -27,10 +27,17 @@ def analyze_enough_disk_space_free_for_table(table_name: str, required_ratio: fl total_disk_space - (free_disk_space - %(ratio)s * table_size) AS required, formatReadableSize(required) """, - {"database": CLICKHOUSE_DATABASE, "table_name": table_name, "ratio": required_ratio}, + { + "database": CLICKHOUSE_DATABASE, + "table_name": table_name, + "ratio": required_ratio, + }, )[0] if current_ratio >= required_ratio: return (True, None) else: - return (False, f"Upgrade your ClickHouse storage to at least {required_space_pretty}.") + return ( + False, + f"Upgrade your ClickHouse storage to at least {required_space_pretty}.", + ) diff --git a/posthog/async_migrations/examples/example.py b/posthog/async_migrations/examples/example.py index 1c0143744d796..c079c5ca6e504 100644 --- a/posthog/async_migrations/examples/example.py +++ b/posthog/async_migrations/examples/example.py @@ -28,7 +28,6 @@ def example_rollback_fn(uuid: str): class Migration(AsyncMigrationDefinition): - description = "An example async migration." posthog_min_version = "1.29.0" diff --git a/posthog/async_migrations/examples/test_migration.py b/posthog/async_migrations/examples/test_migration.py index 4b85264004865..7b3516c8ced91 100644 --- a/posthog/async_migrations/examples/test_migration.py +++ b/posthog/async_migrations/examples/test_migration.py @@ -26,7 +26,6 @@ def side_effect_rollback(self, _): class Migration(AsyncMigrationDefinition): - # For testing only!! fail = False error_message = "Healthcheck failed" diff --git a/posthog/async_migrations/examples/test_with_rollback_exception.py b/posthog/async_migrations/examples/test_with_rollback_exception.py index 75371d4cfba37..b17f52391c9d6 100644 --- a/posthog/async_migrations/examples/test_with_rollback_exception.py +++ b/posthog/async_migrations/examples/test_with_rollback_exception.py @@ -1,4 +1,7 @@ -from posthog.async_migrations.definition import AsyncMigrationDefinition, AsyncMigrationOperation +from posthog.async_migrations.definition import ( + AsyncMigrationDefinition, + AsyncMigrationOperation, +) # For testing purposes @@ -8,7 +11,6 @@ def raise_exception_fn(_): class Migration(AsyncMigrationDefinition): - # For testing only!! description = "Another example async migration that's less realistic and used in tests." diff --git a/posthog/async_migrations/migrations/0001_events_sample_by.py b/posthog/async_migrations/migrations/0001_events_sample_by.py index 6a27833d38e0d..4098fd38f32a1 100644 --- a/posthog/async_migrations/migrations/0001_events_sample_by.py +++ b/posthog/async_migrations/migrations/0001_events_sample_by.py @@ -1,6 +1,9 @@ from typing import List -from posthog.async_migrations.definition import AsyncMigrationDefinition, AsyncMigrationOperation +from posthog.async_migrations.definition import ( + AsyncMigrationDefinition, + AsyncMigrationOperation, +) """ Nooping this migration for future compatibility. Superseded by 0002_events_sample_by. @@ -10,7 +13,6 @@ class Migration(AsyncMigrationDefinition): - description = "Test migration" posthog_max_version = "1.33.9" diff --git a/posthog/async_migrations/migrations/0002_events_sample_by.py b/posthog/async_migrations/migrations/0002_events_sample_by.py index c4d7ca9181f67..7ad43de2934a3 100644 --- a/posthog/async_migrations/migrations/0002_events_sample_by.py +++ b/posthog/async_migrations/migrations/0002_events_sample_by.py @@ -59,7 +59,6 @@ def generate_insert_into_op(partition_gte: int, partition_lt=None) -> AsyncMigra class Migration(AsyncMigrationDefinition): - description = ( "Schema change to the events table ensuring our SAMPLE BY clause is compatible with ClickHouse >=21.7.0." ) @@ -138,7 +137,10 @@ def operations(self): ), AsyncMigrationOperation( fn=lambda query_id: run_optimize_table( - unique_name="0002_events_sample_by", query_id=query_id, table_name=EVENTS_TABLE_NAME, final=True + unique_name="0002_events_sample_by", + query_id=query_id, + table_name=EVENTS_TABLE_NAME, + final=True, ) ), ] diff --git a/posthog/async_migrations/migrations/0003_fill_person_distinct_id2.py b/posthog/async_migrations/migrations/0003_fill_person_distinct_id2.py index 3cb5f123c5124..ba1d6dd917292 100644 --- a/posthog/async_migrations/migrations/0003_fill_person_distinct_id2.py +++ b/posthog/async_migrations/migrations/0003_fill_person_distinct_id2.py @@ -1,6 +1,9 @@ from functools import cached_property -from posthog.async_migrations.definition import AsyncMigrationDefinition, AsyncMigrationOperationSQL +from posthog.async_migrations.definition import ( + AsyncMigrationDefinition, + AsyncMigrationOperationSQL, +) from posthog.client import sync_execute from posthog.constants import AnalyticsDBMS from posthog.settings import CLICKHOUSE_DATABASE @@ -29,7 +32,6 @@ class Migration(AsyncMigrationDefinition): - description = "Set up person_distinct_id2 table, speeding up person-related queries." depends_on = "0002_events_sample_by" diff --git a/posthog/async_migrations/migrations/0004_replicated_schema.py b/posthog/async_migrations/migrations/0004_replicated_schema.py index 18f54a315e621..9bdbdc4ebe5f3 100644 --- a/posthog/async_migrations/migrations/0004_replicated_schema.py +++ b/posthog/async_migrations/migrations/0004_replicated_schema.py @@ -49,7 +49,6 @@ class Migration(AsyncMigrationDefinition): - description = "Replace tables with replicated counterparts" depends_on = "0003_fill_person_distinct_id2" diff --git a/posthog/async_migrations/migrations/0005_person_replacing_by_version.py b/posthog/async_migrations/migrations/0005_person_replacing_by_version.py index 69e38de0a4bf8..276d6c54abed3 100644 --- a/posthog/async_migrations/migrations/0005_person_replacing_by_version.py +++ b/posthog/async_migrations/migrations/0005_person_replacing_by_version.py @@ -160,9 +160,14 @@ def operations(self): ON CLUSTER '{settings.CLICKHOUSE_CLUSTER}' """, ), - AsyncMigrationOperationSQL(database=AnalyticsDBMS.CLICKHOUSE, sql=PERSONS_TABLE_MV_SQL, rollback=None), + AsyncMigrationOperationSQL( + database=AnalyticsDBMS.CLICKHOUSE, + sql=PERSONS_TABLE_MV_SQL, + rollback=None, + ), AsyncMigrationOperation( - fn=self.copy_persons_from_postgres, rollback_fn=lambda _: self.unset_highwatermark() + fn=self.copy_persons_from_postgres, + rollback_fn=lambda _: self.unset_highwatermark(), ), ] @@ -195,10 +200,16 @@ def copy_persons_from_postgres(self, query_id: str): should_continue = self._copy_batch_from_postgres(query_id) self.unset_highwatermark() run_optimize_table( - unique_name="0005_person_replacing_by_version", query_id=query_id, table_name=PERSON_TABLE, final=True + unique_name="0005_person_replacing_by_version", + query_id=query_id, + table_name=PERSON_TABLE, + final=True, ) except Exception as err: - logger.warn("Re-copying persons from postgres failed. Marking async migration as complete.", error=err) + logger.warn( + "Re-copying persons from postgres failed. Marking async migration as complete.", + error=err, + ) capture_exception(err) def _copy_batch_from_postgres(self, query_id: str) -> bool: diff --git a/posthog/async_migrations/migrations/0006_persons_and_groups_on_events_backfill.py b/posthog/async_migrations/migrations/0006_persons_and_groups_on_events_backfill.py index f83b509698394..62f539f333481 100644 --- a/posthog/async_migrations/migrations/0006_persons_and_groups_on_events_backfill.py +++ b/posthog/async_migrations/migrations/0006_persons_and_groups_on_events_backfill.py @@ -1,6 +1,9 @@ from typing import List -from posthog.async_migrations.definition import AsyncMigrationDefinition, AsyncMigrationOperation +from posthog.async_migrations.definition import ( + AsyncMigrationDefinition, + AsyncMigrationOperation, +) """ Nooping this migration for future compatibility. Superseded by 0007_persons_and_groups_on_events_backfill. @@ -10,7 +13,6 @@ class Migration(AsyncMigrationDefinition): - description = "No-op migration" posthog_max_version = "1.41.99" diff --git a/posthog/async_migrations/migrations/0007_persons_and_groups_on_events_backfill.py b/posthog/async_migrations/migrations/0007_persons_and_groups_on_events_backfill.py index de0911a54a41a..9b140eedf8a1c 100644 --- a/posthog/async_migrations/migrations/0007_persons_and_groups_on_events_backfill.py +++ b/posthog/async_migrations/migrations/0007_persons_and_groups_on_events_backfill.py @@ -10,7 +10,11 @@ AsyncMigrationOperationSQL, ) from posthog.async_migrations.disk_util import analyze_enough_disk_space_free_for_table -from posthog.async_migrations.utils import execute_op_clickhouse, run_optimize_table, sleep_until_finished +from posthog.async_migrations.utils import ( + execute_op_clickhouse, + run_optimize_table, + sleep_until_finished, +) from posthog.client import sync_execute from posthog.models.event.sql import EVENTS_DATA_TABLE from posthog.utils import str_to_bool @@ -74,16 +78,36 @@ class Migration(AsyncMigrationDefinition): posthog_max_version = "1.41.99" parameters = { - "PERSON_DICT_CACHE_SIZE": (5000000, "ClickHouse cache size (in rows) for persons data.", int), + "PERSON_DICT_CACHE_SIZE": ( + 5000000, + "ClickHouse cache size (in rows) for persons data.", + int, + ), "PERSON_DISTINCT_ID_DICT_CACHE_SIZE": ( 5000000, "ClickHouse cache size (in rows) for person distinct id data.", int, ), - "GROUPS_DICT_CACHE_SIZE": (1000000, "ClickHouse cache size (in rows) for groups data.", int), - "RUN_DATA_VALIDATION_POSTCHECK": ("True", "Whether to run a postcheck validating the backfilled data.", str), - "TIMESTAMP_LOWER_BOUND": ("2020-01-01", "Timestamp lower bound for events to backfill", str), - "TIMESTAMP_UPPER_BOUND": ("2024-01-01", "Timestamp upper bound for events to backfill", str), + "GROUPS_DICT_CACHE_SIZE": ( + 1000000, + "ClickHouse cache size (in rows) for groups data.", + int, + ), + "RUN_DATA_VALIDATION_POSTCHECK": ( + "True", + "Whether to run a postcheck validating the backfilled data.", + str, + ), + "TIMESTAMP_LOWER_BOUND": ( + "2020-01-01", + "Timestamp lower bound for events to backfill", + str, + ), + "TIMESTAMP_UPPER_BOUND": ( + "2024-01-01", + "Timestamp upper bound for events to backfill", + str, + ), "TEAM_ID": ( None, "The team_id of team to run backfill for. If unset the backfill will run for all teams.", @@ -95,7 +119,6 @@ def precheck(self): return analyze_enough_disk_space_free_for_table(EVENTS_DATA_TABLE(), required_ratio=2.0) def is_required(self) -> bool: - # we don't check groupX_created_at columns as they are 0 by default rows_to_backfill_check = sync_execute( """ @@ -435,8 +458,9 @@ def _run_backfill_mutation(self, query_id): ) def _create_dictionaries(self, query_id): - execute_op_clickhouse( - f""" + ( + execute_op_clickhouse( + f""" CREATE DICTIONARY IF NOT EXISTS {settings.CLICKHOUSE_DATABASE}.person_dict {{on_cluster_clause}} ( team_id Int64, @@ -449,12 +473,14 @@ def _create_dictionaries(self, query_id): LAYOUT(complex_key_cache(size_in_cells %(cache_size)s max_threads_for_updates 6 allow_read_expired_keys 1)) Lifetime(60000) """, - {"cache_size": self.get_parameter("PERSON_DICT_CACHE_SIZE")}, - per_shard=True, - query_id=query_id, - ), - execute_op_clickhouse( - f""" + {"cache_size": self.get_parameter("PERSON_DICT_CACHE_SIZE")}, + per_shard=True, + query_id=query_id, + ), + ) + ( + execute_op_clickhouse( + f""" CREATE DICTIONARY IF NOT EXISTS {settings.CLICKHOUSE_DATABASE}.person_distinct_id2_dict {{on_cluster_clause}} ( team_id Int64, @@ -466,10 +492,11 @@ def _create_dictionaries(self, query_id): LAYOUT(complex_key_cache(size_in_cells %(cache_size)s max_threads_for_updates 6 allow_read_expired_keys 1)) Lifetime(60000) """, - {"cache_size": self.get_parameter("PERSON_DISTINCT_ID_DICT_CACHE_SIZE")}, - per_shard=True, - query_id=query_id, - ), + {"cache_size": self.get_parameter("PERSON_DISTINCT_ID_DICT_CACHE_SIZE")}, + per_shard=True, + query_id=query_id, + ), + ) execute_op_clickhouse( f""" CREATE DICTIONARY IF NOT EXISTS {settings.CLICKHOUSE_DATABASE}.groups_dict {{on_cluster_clause}} @@ -501,7 +528,10 @@ def _count_running_mutations(self): FROM clusterAllReplicas(%(cluster)s, system, 'mutations') WHERE not is_done AND command LIKE %(pattern)s """, - {"cluster": settings.CLICKHOUSE_CLUSTER, "pattern": "%person_created_at = toDateTime(0)%"}, + { + "cluster": settings.CLICKHOUSE_CLUSTER, + "pattern": "%person_created_at = toDateTime(0)%", + }, )[0][0] def _clear_temporary_tables(self, query_id): diff --git a/posthog/async_migrations/migrations/0008_speed_up_kafka_timestamp_filters.py b/posthog/async_migrations/migrations/0008_speed_up_kafka_timestamp_filters.py index b8a3fa65bfdf5..20d81d063cd26 100644 --- a/posthog/async_migrations/migrations/0008_speed_up_kafka_timestamp_filters.py +++ b/posthog/async_migrations/migrations/0008_speed_up_kafka_timestamp_filters.py @@ -3,7 +3,10 @@ import structlog from django.conf import settings -from posthog.async_migrations.definition import AsyncMigrationDefinition, AsyncMigrationOperationSQL +from posthog.async_migrations.definition import ( + AsyncMigrationDefinition, + AsyncMigrationOperationSQL, +) from posthog.client import sync_execute from posthog.constants import AnalyticsDBMS from posthog.version_requirement import ServiceVersionRequirement diff --git a/posthog/async_migrations/migrations/0009_minmax_indexes_for_materialized_columns.py b/posthog/async_migrations/migrations/0009_minmax_indexes_for_materialized_columns.py index ea21377f19b69..9b4c64c9af869 100644 --- a/posthog/async_migrations/migrations/0009_minmax_indexes_for_materialized_columns.py +++ b/posthog/async_migrations/migrations/0009_minmax_indexes_for_materialized_columns.py @@ -1,6 +1,9 @@ from typing import List -from posthog.async_migrations.definition import AsyncMigrationDefinition, AsyncMigrationOperation +from posthog.async_migrations.definition import ( + AsyncMigrationDefinition, + AsyncMigrationOperation, +) class Migration(AsyncMigrationDefinition): diff --git a/posthog/async_migrations/migrations/0010_move_old_partitions.py b/posthog/async_migrations/migrations/0010_move_old_partitions.py index 990e339bff581..8097224014f00 100644 --- a/posthog/async_migrations/migrations/0010_move_old_partitions.py +++ b/posthog/async_migrations/migrations/0010_move_old_partitions.py @@ -2,7 +2,10 @@ import structlog -from posthog.async_migrations.definition import AsyncMigrationDefinition, AsyncMigrationOperationSQL +from posthog.async_migrations.definition import ( + AsyncMigrationDefinition, + AsyncMigrationOperationSQL, +) from posthog.client import sync_execute from posthog.constants import AnalyticsDBMS from posthog.version_requirement import ServiceVersionRequirement @@ -20,9 +23,21 @@ class Migration(AsyncMigrationDefinition): posthog_max_version = "1.49.99" parameters = { - "OLDEST_PARTITION_TO_KEEP": ("200001", "ID of the oldest partition to keep", str), - "NEWEST_PARTITION_TO_KEEP": ("202308", "ID of the newest partition to keep", str), - "OPTIMIZE_TABLE": (False, "Optimize sharded_events table after moving partitions?", bool), + "OLDEST_PARTITION_TO_KEEP": ( + "200001", + "ID of the oldest partition to keep", + str, + ), + "NEWEST_PARTITION_TO_KEEP": ( + "202308", + "ID of the newest partition to keep", + str, + ), + "OPTIMIZE_TABLE": ( + False, + "Optimize sharded_events table after moving partitions?", + bool, + ), } service_version_requirements = [ServiceVersionRequirement(service="clickhouse", supported_version=">=22.3.0")] diff --git a/posthog/async_migrations/runner.py b/posthog/async_migrations/runner.py index 931ee5d67a232..78f2afcf21201 100644 --- a/posthog/async_migrations/runner.py +++ b/posthog/async_migrations/runner.py @@ -19,7 +19,11 @@ trigger_migration, update_async_migration, ) -from posthog.models.async_migration import AsyncMigration, MigrationStatus, get_all_running_async_migrations +from posthog.models.async_migration import ( + AsyncMigration, + MigrationStatus, + get_all_running_async_migrations, +) from posthog.models.instance_setting import get_instance_setting from posthog.models.utils import UUIDT from posthog.version_requirement import ServiceVersionRequirement @@ -33,7 +37,9 @@ def start_async_migration( - migration_name: str, ignore_posthog_version=False, migration_definition: Optional[AsyncMigrationDefinition] = None + migration_name: str, + ignore_posthog_version=False, + migration_definition: Optional[AsyncMigrationDefinition] = None, ) -> bool: """ Performs some basic checks to ensure the migration can indeed run, and then kickstarts the chain of operations @@ -63,7 +69,10 @@ def start_async_migration( if not ( ignore_posthog_version - or is_posthog_version_compatible(migration_instance.posthog_min_version, migration_instance.posthog_max_version) + or is_posthog_version_compatible( + migration_instance.posthog_min_version, + migration_instance.posthog_max_version, + ) ): process_error( migration_instance, @@ -102,7 +111,9 @@ def start_async_migration( ok, error = run_migration_precheck(migration_instance) if not ok: process_error( - migration_instance, f"Migration precheck failed with error:{error}", status=MigrationStatus.FailedAtStartup + migration_instance, + f"Migration precheck failed with error:{error}", + status=MigrationStatus.FailedAtStartup, ) return False @@ -245,7 +256,10 @@ def attempt_migration_rollback(migration_instance: AsyncMigration): return update_async_migration( - migration_instance=migration_instance, status=MigrationStatus.RolledBack, progress=0, current_operation_index=0 + migration_instance=migration_instance, + status=MigrationStatus.RolledBack, + progress=0, + current_operation_index=0, ) diff --git a/posthog/async_migrations/setup.py b/posthog/async_migrations/setup.py index 30a74b0acf76c..fff7205a4c8e0 100644 --- a/posthog/async_migrations/setup.py +++ b/posthog/async_migrations/setup.py @@ -6,7 +6,10 @@ from posthog.async_migrations.definition import AsyncMigrationDefinition from posthog.constants import FROZEN_POSTHOG_VERSION -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.models.instance_setting import get_instance_setting from posthog.settings import TEST diff --git a/posthog/async_migrations/test/test_0007_persons_and_groups_on_events_backfill.py b/posthog/async_migrations/test/test_0007_persons_and_groups_on_events_backfill.py index 27c660a8c749d..4e6588ad45920 100644 --- a/posthog/async_migrations/test/test_0007_persons_and_groups_on_events_backfill.py +++ b/posthog/async_migrations/test/test_0007_persons_and_groups_on_events_backfill.py @@ -5,14 +5,25 @@ import pytest from posthog.async_migrations.runner import start_async_migration -from posthog.async_migrations.setup import get_async_migration_definition, setup_async_migrations +from posthog.async_migrations.setup import ( + get_async_migration_definition, + setup_async_migrations, +) from posthog.async_migrations.test.util import AsyncMigrationBaseTest from posthog.client import query_with_columns, sync_execute from posthog.models import Person -from posthog.models.async_migration import AsyncMigration, AsyncMigrationError, MigrationStatus +from posthog.models.async_migration import ( + AsyncMigration, + AsyncMigrationError, + MigrationStatus, +) from posthog.models.event.util import create_event from posthog.models.group.util import create_group -from posthog.models.person.util import create_person, create_person_distinct_id, delete_person +from posthog.models.person.util import ( + create_person, + create_person_distinct_id, + delete_person, +) from posthog.models.utils import UUIDT from posthog.test.base import ClickhouseTestMixin, run_clickhouse_statement_in_parallel @@ -269,7 +280,12 @@ def test_data_copy_groups(self): team=self.team, distinct_id="1", event="$pageview", - properties={"$group_0": "org:7", "$group_1": "77", "$group_2": "77", "$group_3": "77"}, + properties={ + "$group_0": "org:7", + "$group_1": "77", + "$group_2": "77", + "$group_3": "77", + }, ) # we need to also create person data so the backfill postcheck does not fail @@ -327,7 +343,10 @@ def test_rollback(self): migration_successful = run_migration() self.assertFalse(migration_successful) - self.assertEqual(AsyncMigration.objects.get(name=MIGRATION_NAME).status, MigrationStatus.RolledBack) + self.assertEqual( + AsyncMigration.objects.get(name=MIGRATION_NAME).status, + MigrationStatus.RolledBack, + ) MIGRATION_DEFINITION.operations[-1].fn = old_fn @@ -553,7 +572,8 @@ def test_check_person_data_failure(self): # Test that we fail the postcheck with the right message when 3 out of 101 events is incomplete (~2%) with self.assertRaisesRegex( - Exception, "Backfill did not work succesfully. ~2% of events did not get the correct data for persons." + Exception, + "Backfill did not work succesfully. ~2% of events did not get the correct data for persons.", ): MIGRATION_DEFINITION._check_person_data() # type: ignore diff --git a/posthog/async_migrations/test/test_0010_move_old_partitions.py b/posthog/async_migrations/test/test_0010_move_old_partitions.py index 272b51c1735c8..3cc21d3b67a58 100644 --- a/posthog/async_migrations/test/test_0010_move_old_partitions.py +++ b/posthog/async_migrations/test/test_0010_move_old_partitions.py @@ -1,7 +1,10 @@ import pytest from posthog.async_migrations.runner import start_async_migration -from posthog.async_migrations.setup import get_async_migration_definition, setup_async_migrations +from posthog.async_migrations.setup import ( + get_async_migration_definition, + setup_async_migrations, +) from posthog.async_migrations.test.util import AsyncMigrationBaseTest from posthog.models.event.util import create_event from posthog.models.utils import UUIDT @@ -24,18 +27,38 @@ def run_migration(): class Test0010MoveOldPartitions(AsyncMigrationBaseTest): def setUp(self): - MIGRATION_DEFINITION.parameters["OLDEST_PARTITION_TO_KEEP"] = ("202301", "", str) - MIGRATION_DEFINITION.parameters["NEWEST_PARTITION_TO_KEEP"] = ("202302", "", str) + MIGRATION_DEFINITION.parameters["OLDEST_PARTITION_TO_KEEP"] = ( + "202301", + "", + str, + ) + MIGRATION_DEFINITION.parameters["NEWEST_PARTITION_TO_KEEP"] = ( + "202302", + "", + str, + ) MIGRATION_DEFINITION.parameters["OPTIMIZE_TABLE"] = (False, "", bool) create_event( - event_uuid=uuid1, team=self.team, distinct_id="1", event="$pageview", timestamp="1900-01-02T00:00:00Z" + event_uuid=uuid1, + team=self.team, + distinct_id="1", + event="$pageview", + timestamp="1900-01-02T00:00:00Z", ) create_event( - event_uuid=uuid2, team=self.team, distinct_id="1", event="$pageview", timestamp="2022-02-02T00:00:00Z" + event_uuid=uuid2, + team=self.team, + distinct_id="1", + event="$pageview", + timestamp="2022-02-02T00:00:00Z", ) create_event( - event_uuid=uuid3, team=self.team, distinct_id="1", event="$pageview", timestamp="2045-02-02T00:00:00Z" + event_uuid=uuid3, + team=self.team, + distinct_id="1", + event="$pageview", + timestamp="2045-02-02T00:00:00Z", ) super().setUp() @@ -44,7 +67,6 @@ def tearDown(self): super().tearDown() def test_completes_successfully(self): - self.assertTrue(run_migration()) # create table + 3 move operations diff --git a/posthog/async_migrations/test/test_definition.py b/posthog/async_migrations/test/test_definition.py index 24c556841649a..1acdfa758499b 100644 --- a/posthog/async_migrations/test/test_definition.py +++ b/posthog/async_migrations/test/test_definition.py @@ -1,7 +1,10 @@ import pytest from infi.clickhouse_orm.utils import import_submodules -from posthog.async_migrations.definition import AsyncMigrationDefinition, AsyncMigrationOperation +from posthog.async_migrations.definition import ( + AsyncMigrationDefinition, + AsyncMigrationOperation, +) from posthog.async_migrations.setup import ( ASYNC_MIGRATIONS_EXAMPLE_MODULE_PATH, get_async_migration_definition, @@ -16,7 +19,10 @@ class TestAsyncMigrationDefinition(BaseTest): def test_get_async_migration_definition(self): - from posthog.async_migrations.examples.example import example_fn, example_rollback_fn + from posthog.async_migrations.examples.example import ( + example_fn, + example_rollback_fn, + ) modules = import_submodules(ASYNC_MIGRATIONS_EXAMPLE_MODULE_PATH) example_migration = modules["example"].Migration("example") @@ -28,7 +34,12 @@ def test_get_async_migration_definition(self): self.assertEqual(example_migration.posthog_max_version, "1.30.0") self.assertEqual(example_migration.operations[-1].fn, example_fn) self.assertEqual(example_migration.operations[-1].rollback_fn, example_rollback_fn) - self.assertTrue(isinstance(example_migration.service_version_requirements[0], ServiceVersionRequirement)) + self.assertTrue( + isinstance( + example_migration.service_version_requirements[0], + ServiceVersionRequirement, + ) + ) def test_get_migration_instance_and_parameters(self): setup_async_migrations(ignore_posthog_version=True) @@ -41,7 +52,8 @@ def test_get_migration_instance_and_parameters(self): self.assertEqual(definition.migration_instance(), instance) self.assertEqual( - definition.get_parameter("PERSON_DICT_CACHE_SIZE"), definition.parameters["PERSON_DICT_CACHE_SIZE"][0] + definition.get_parameter("PERSON_DICT_CACHE_SIZE"), + definition.parameters["PERSON_DICT_CACHE_SIZE"][0], ) instance.parameters = {"PERSON_DICT_CACHE_SIZE": 123} diff --git a/posthog/async_migrations/test/test_migrations_not_required.py b/posthog/async_migrations/test/test_migrations_not_required.py index 76f9de401e097..9665f534ac81f 100644 --- a/posthog/async_migrations/test/test_migrations_not_required.py +++ b/posthog/async_migrations/test/test_migrations_not_required.py @@ -7,6 +7,7 @@ pytestmark = pytest.mark.async_migrations + # Async migrations are data migrations aimed at getting users from an old schema to a new schema # Fresh installs should have the new schema, however. So check that async migrations are being # written correctly such that this is the case @@ -19,4 +20,7 @@ def setUp(self): def test_async_migrations_not_required_on_fresh_instances(self): for name, migration in ALL_ASYNC_MIGRATIONS.items(): - self.assertFalse(migration.is_required(), f"Async migration {name} is_required returned True") + self.assertFalse( + migration.is_required(), + f"Async migration {name} is_required returned True", + ) diff --git a/posthog/async_migrations/test/test_runner.py b/posthog/async_migrations/test/test_runner.py index f433a5e36be3e..9c4a7b1fe5ea5 100644 --- a/posthog/async_migrations/test/test_runner.py +++ b/posthog/async_migrations/test/test_runner.py @@ -9,9 +9,16 @@ run_async_migration_next_op, start_async_migration, ) -from posthog.async_migrations.test.util import AsyncMigrationBaseTest, create_async_migration +from posthog.async_migrations.test.util import ( + AsyncMigrationBaseTest, + create_async_migration, +) from posthog.async_migrations.utils import update_async_migration -from posthog.models.async_migration import AsyncMigration, AsyncMigrationError, MigrationStatus +from posthog.models.async_migration import ( + AsyncMigration, + AsyncMigrationError, + MigrationStatus, +) from posthog.models.utils import UUIDT pytestmark = pytest.mark.async_migrations @@ -52,7 +59,6 @@ def test_run_migration_in_full(self): self.assertEqual(self.migration.sec.side_effect_rollback_count, 0) def test_rollback_migration(self): - self.migration.sec.reset_count() migration_successful = start_async_migration("test_migration") diff --git a/posthog/async_migrations/test/test_utils.py b/posthog/async_migrations/test/test_utils.py index f2e45a24ab042..da01ec9dda54d 100644 --- a/posthog/async_migrations/test/test_utils.py +++ b/posthog/async_migrations/test/test_utils.py @@ -4,7 +4,10 @@ import pytest from posthog.async_migrations.definition import AsyncMigrationOperationSQL -from posthog.async_migrations.test.util import AsyncMigrationBaseTest, create_async_migration +from posthog.async_migrations.test.util import ( + AsyncMigrationBaseTest, + create_async_migration, +) from posthog.async_migrations.utils import ( complete_migration, execute_on_each_shard, diff --git a/posthog/async_migrations/utils.py b/posthog/async_migrations/utils.py index efa70424e8846..20ad64cf7d75b 100644 --- a/posthog/async_migrations/utils.py +++ b/posthog/async_migrations/utils.py @@ -15,7 +15,11 @@ from posthog.clickhouse.client.connection import make_ch_pool from posthog.clickhouse.query_tagging import reset_query_tags, tag_queries from posthog.email import is_email_available -from posthog.models.async_migration import AsyncMigration, AsyncMigrationError, MigrationStatus +from posthog.models.async_migration import ( + AsyncMigration, + AsyncMigrationError, + MigrationStatus, +) from posthog.models.instance_setting import get_instance_setting from posthog.models.user import User from posthog.settings import ( @@ -154,7 +158,13 @@ def sleep_until_finished(name, is_running: Callable[[], bool]) -> None: def run_optimize_table( - *, unique_name: str, query_id: str, table_name: str, deduplicate=False, final=False, per_shard=False + *, + unique_name: str, + query_id: str, + table_name: str, + deduplicate=False, + final=False, + per_shard=False, ): """ Runs the passed OPTIMIZE TABLE query. @@ -163,7 +173,10 @@ def run_optimize_table( we'll wait for that to complete first. """ if not TEST and _get_number_running_on_cluster(f"%%optimize:{unique_name}%%") > 0: - sleep_until_finished(unique_name, lambda: _get_number_running_on_cluster(f"%%optimize:{unique_name}%%") > 0) + sleep_until_finished( + unique_name, + lambda: _get_number_running_on_cluster(f"%%optimize:{unique_name}%%") > 0, + ) else: final_clause = "FINAL" if final else "" deduplicate_clause = "DEDUPLICATE" if deduplicate else "" @@ -175,7 +188,10 @@ def run_optimize_table( execute_op_clickhouse( sql, query_id=f"optimize:{unique_name}/{query_id}", - settings={"max_execution_time": ASYNC_MIGRATIONS_DEFAULT_TIMEOUT_SECONDS, "mutations_sync": 2}, + settings={ + "max_execution_time": ASYNC_MIGRATIONS_DEFAULT_TIMEOUT_SECONDS, + "mutations_sync": 2, + }, per_shard=per_shard, ) @@ -213,7 +229,9 @@ def process_error( from posthog.tasks.email import send_async_migration_errored_email send_async_migration_errored_email.delay( - migration_key=migration_instance.name, time=now().isoformat(), error=error + migration_key=migration_instance.name, + time=now().isoformat(), + error=error, ) if ( @@ -237,7 +255,9 @@ def trigger_migration(migration_instance: AsyncMigration, fresh_start: bool = Tr def force_stop_migration( - migration_instance: AsyncMigration, error: str = "Force stopped by user", rollback: bool = True + migration_instance: AsyncMigration, + error: str = "Force stopped by user", + rollback: bool = True, ): """ In theory this is dangerous, as it can cause another task to be lost @@ -299,7 +319,10 @@ def mark_async_migration_as_running(migration_instance: AsyncMigration) -> bool: # update to running iff the state was Starting (ui triggered) or NotStarted (api triggered) with transaction.atomic(): instance = AsyncMigration.objects.select_for_update().get(pk=migration_instance.pk) - if instance.status not in [MigrationStatus.Starting, MigrationStatus.NotStarted]: + if instance.status not in [ + MigrationStatus.Starting, + MigrationStatus.NotStarted, + ]: return False instance.status = MigrationStatus.Running instance.current_query_id = "" diff --git a/posthog/batch_exports/http.py b/posthog/batch_exports/http.py index 06fb9866ac0e9..aa71cc9060a13 100644 --- a/posthog/batch_exports/http.py +++ b/posthog/batch_exports/http.py @@ -88,7 +88,11 @@ class RunsCursorPagination(CursorPagination): class BatchExportRunViewSet(StructuredViewSetMixin, viewsets.ReadOnlyModelViewSet): queryset = BatchExportRun.objects.all() - permission_classes = [IsAuthenticated, ProjectMembershipNecessaryPermissions, TeamMemberAccessPermission] + permission_classes = [ + IsAuthenticated, + ProjectMembershipNecessaryPermissions, + TeamMemberAccessPermission, + ] serializer_class = BatchExportRunSerializer pagination_class = RunsCursorPagination @@ -98,7 +102,8 @@ def get_queryset(self, date_range: tuple[dt.datetime, dt.datetime] | None = None if date_range: return self.queryset.filter( - batch_export_id=self.kwargs["parent_lookup_batch_export_id"], created_at__range=date_range + batch_export_id=self.kwargs["parent_lookup_batch_export_id"], + created_at__range=date_range, ).order_by("-created_at") else: return self.queryset.filter(batch_export_id=self.kwargs["parent_lookup_batch_export_id"]).order_by( @@ -178,7 +183,10 @@ def create(self, validated_data: dict) -> BatchExport: str(team.uuid), groups={"organization": str(team.organization.id)}, group_properties={ - "organization": {"id": str(team.organization.id), "created_at": team.organization.created_at} + "organization": { + "id": str(team.organization.id), + "created_at": team.organization.created_at, + } }, send_feature_flag_events=False, ): @@ -216,7 +224,11 @@ def update(self, batch_export: BatchExport, validated_data: dict) -> BatchExport class BatchExportViewSet(StructuredViewSetMixin, viewsets.ModelViewSet): queryset = BatchExport.objects.all() - permission_classes = [IsAuthenticated, ProjectMembershipNecessaryPermissions, TeamMemberAccessPermission] + permission_classes = [ + IsAuthenticated, + ProjectMembershipNecessaryPermissions, + TeamMemberAccessPermission, + ] serializer_class = BatchExportSerializer def get_queryset(self): @@ -319,7 +331,11 @@ class Meta: class BatchExportLogViewSet(StructuredViewSetMixin, mixins.ListModelMixin, viewsets.GenericViewSet): - permission_classes = [IsAuthenticated, ProjectMembershipNecessaryPermissions, TeamMemberAccessPermission] + permission_classes = [ + IsAuthenticated, + ProjectMembershipNecessaryPermissions, + TeamMemberAccessPermission, + ] serializer_class = BatchExportLogEntrySerializer def get_queryset(self): diff --git a/posthog/batch_exports/models.py b/posthog/batch_exports/models.py index 633163b831238..dc86c2ce7286a 100644 --- a/posthog/batch_exports/models.py +++ b/posthog/batch_exports/models.py @@ -38,7 +38,9 @@ class Destination(models.TextChoices): } type: models.CharField = models.CharField( - choices=Destination.choices, max_length=64, help_text="A choice of supported BatchExportDestination types." + choices=Destination.choices, + max_length=64, + help_text="A choice of supported BatchExportDestination types.", ) config: models.JSONField = models.JSONField( default=dict, @@ -46,10 +48,12 @@ class Destination(models.TextChoices): help_text="A JSON field to store all configuration parameters required to access a BatchExportDestination.", ) created_at: models.DateTimeField = models.DateTimeField( - auto_now_add=True, help_text="The timestamp at which this BatchExportDestination was created." + auto_now_add=True, + help_text="The timestamp at which this BatchExportDestination was created.", ) last_updated_at: models.DateTimeField = models.DateTimeField( - auto_now=True, help_text="The timestamp at which this BatchExportDestination was last updated." + auto_now=True, + help_text="The timestamp at which this BatchExportDestination was last updated.", ) @@ -74,7 +78,9 @@ class Status(models.TextChoices): STARTING = "Starting" batch_export = models.ForeignKey( - "BatchExport", on_delete=models.CASCADE, help_text="The BatchExport this run belongs to." + "BatchExport", + on_delete=models.CASCADE, + help_text="The BatchExport this run belongs to.", ) status: models.CharField = models.CharField( choices=Status.choices, max_length=64, help_text="The status of this run." @@ -89,17 +95,25 @@ class Status(models.TextChoices): data_interval_end: models.DateTimeField = models.DateTimeField(help_text="The end of the data interval.") cursor: models.TextField = models.TextField(null=True, help_text="An opaque cursor that may be used to resume.") created_at: models.DateTimeField = models.DateTimeField( - auto_now_add=True, help_text="The timestamp at which this BatchExportRun was created." + auto_now_add=True, + help_text="The timestamp at which this BatchExportRun was created.", ) finished_at: models.DateTimeField = models.DateTimeField( - null=True, help_text="The timestamp at which this BatchExportRun finished, successfully or not." + null=True, + help_text="The timestamp at which this BatchExportRun finished, successfully or not.", ) last_updated_at: models.DateTimeField = models.DateTimeField( - auto_now=True, help_text="The timestamp at which this BatchExportRun was last updated." + auto_now=True, + help_text="The timestamp at which this BatchExportRun was last updated.", ) -BATCH_EXPORT_INTERVALS = [("hour", "hour"), ("day", "day"), ("week", "week"), ("every 5 minutes", "every 5 minutes")] +BATCH_EXPORT_INTERVALS = [ + ("hour", "hour"), + ("day", "day"), + ("week", "week"), + ("every 5 minutes", "every 5 minutes"), +] class BatchExport(UUIDModel): @@ -113,7 +127,9 @@ class BatchExport(UUIDModel): team: models.ForeignKey = models.ForeignKey("Team", on_delete=models.CASCADE, help_text="The team this belongs to.") name: models.TextField = models.TextField(help_text="A human-readable name for this BatchExport.") destination: models.ForeignKey = models.ForeignKey( - "BatchExportDestination", on_delete=models.CASCADE, help_text="The destination to export data to." + "BatchExportDestination", + on_delete=models.CASCADE, + help_text="The destination to export data to.", ) interval = models.CharField( max_length=64, @@ -125,19 +141,27 @@ class BatchExport(UUIDModel): paused = models.BooleanField(default=False, help_text="Whether this BatchExport is paused or not.") deleted = models.BooleanField(default=False, help_text="Whether this BatchExport is deleted or not.") created_at: models.DateTimeField = models.DateTimeField( - auto_now_add=True, help_text="The timestamp at which this BatchExport was created." + auto_now_add=True, + help_text="The timestamp at which this BatchExport was created.", ) last_updated_at: models.DateTimeField = models.DateTimeField( - auto_now=True, help_text="The timestamp at which this BatchExport was last updated." + auto_now=True, + help_text="The timestamp at which this BatchExport was last updated.", ) last_paused_at: models.DateTimeField = models.DateTimeField( - null=True, default=None, help_text="The timestamp at which this BatchExport was last paused." + null=True, + default=None, + help_text="The timestamp at which this BatchExport was last paused.", ) start_at: models.DateTimeField = models.DateTimeField( - null=True, default=None, help_text="Time before which any Batch Export runs won't be triggered." + null=True, + default=None, + help_text="Time before which any Batch Export runs won't be triggered.", ) end_at: models.DateTimeField = models.DateTimeField( - null=True, default=None, help_text="Time after which any Batch Export runs won't be triggered." + null=True, + default=None, + help_text="Time after which any Batch Export runs won't be triggered.", ) @property @@ -244,7 +268,9 @@ class Status(models.TextChoices): team: models.ForeignKey = models.ForeignKey("Team", on_delete=models.CASCADE, help_text="The team this belongs to.") batch_export = models.ForeignKey( - "BatchExport", on_delete=models.CASCADE, help_text="The BatchExport this backfill belongs to." + "BatchExport", + on_delete=models.CASCADE, + help_text="The BatchExport this backfill belongs to.", ) start_at: models.DateTimeField = models.DateTimeField(help_text="The start of the data interval.") end_at: models.DateTimeField = models.DateTimeField(help_text="The end of the data interval.") @@ -252,11 +278,14 @@ class Status(models.TextChoices): choices=Status.choices, max_length=64, help_text="The status of this backfill." ) created_at: models.DateTimeField = models.DateTimeField( - auto_now_add=True, help_text="The timestamp at which this BatchExportBackfill was created." + auto_now_add=True, + help_text="The timestamp at which this BatchExportBackfill was created.", ) finished_at: models.DateTimeField = models.DateTimeField( - null=True, help_text="The timestamp at which this BatchExportBackfill finished, successfully or not." + null=True, + help_text="The timestamp at which this BatchExportBackfill finished, successfully or not.", ) last_updated_at: models.DateTimeField = models.DateTimeField( - auto_now=True, help_text="The timestamp at which this BatchExportBackfill was last updated." + auto_now=True, + help_text="The timestamp at which this BatchExportBackfill was last updated.", ) diff --git a/posthog/batch_exports/service.py b/posthog/batch_exports/service.py index ffe5ee0b692d9..008096d5f50bc 100644 --- a/posthog/batch_exports/service.py +++ b/posthog/batch_exports/service.py @@ -186,7 +186,10 @@ async def pause_schedule(temporal: Client, schedule_id: str, note: str | None = def unpause_batch_export( - temporal: Client, batch_export_id: str, note: str | None = None, backfill: bool = False + temporal: Client, + batch_export_id: str, + note: str | None = None, + backfill: bool = False, ) -> None: """Pause this BatchExport. diff --git a/posthog/caching/calculate_results.py b/posthog/caching/calculate_results.py index 73fc11de7b54f..be11c4ffe48b5 100644 --- a/posthog/caching/calculate_results.py +++ b/posthog/caching/calculate_results.py @@ -16,12 +16,23 @@ ) from posthog.decorators import CacheType from posthog.logging.timing import timed -from posthog.models import Dashboard, DashboardTile, EventDefinition, Filter, Insight, RetentionFilter, Team +from posthog.models import ( + Dashboard, + DashboardTile, + EventDefinition, + Filter, + Insight, + RetentionFilter, + Team, +) from posthog.models.filters import PathFilter from posthog.models.filters.stickiness_filter import StickinessFilter from posthog.models.filters.utils import get_filter from posthog.models.insight import generate_insight_cache_key -from posthog.queries.funnels import ClickhouseFunnelTimeToConvert, ClickhouseFunnelTrends +from posthog.queries.funnels import ( + ClickhouseFunnelTimeToConvert, + ClickhouseFunnelTrends, +) from posthog.queries.funnels.utils import get_funnel_order_class from posthog.queries.paths import Paths from posthog.queries.retention import Retention @@ -225,6 +236,10 @@ def _events_from_filter(filter: Union[RetentionFilter, StickinessFilter, PathFil return [] except Exception as exc: - logger.error("update_cache_item.could_not_list_events_from_filter", exc=exc, exc_info=True) + logger.error( + "update_cache_item.could_not_list_events_from_filter", + exc=exc, + exc_info=True, + ) capture_exception(exc) return [] diff --git a/posthog/caching/fetch_from_cache.py b/posthog/caching/fetch_from_cache.py index b507cdf4d277e..d7c0e5e03e50a 100644 --- a/posthog/caching/fetch_from_cache.py +++ b/posthog/caching/fetch_from_cache.py @@ -5,14 +5,19 @@ from django.utils.timezone import now from prometheus_client import Counter -from posthog.caching.calculate_results import calculate_cache_key, calculate_result_by_insight +from posthog.caching.calculate_results import ( + calculate_cache_key, + calculate_result_by_insight, +) from posthog.caching.insight_cache import update_cached_state from posthog.models import DashboardTile, Insight from posthog.models.dashboard import Dashboard from posthog.utils import get_safe_cache insight_cache_read_counter = Counter( - "posthog_cloud_insight_cache_read", "A read from the redis insight cache", labelnames=["result"] + "posthog_cloud_insight_cache_read", + "A read from the redis insight cache", + labelnames=["result"], ) @@ -72,7 +77,9 @@ def fetch_cached_insight_result(target: Union[Insight, DashboardTile], refresh_f def synchronously_update_cache( - insight: Insight, dashboard: Optional[Dashboard], refresh_frequency: Optional[timedelta] = None + insight: Insight, + dashboard: Optional[Dashboard], + refresh_frequency: Optional[timedelta] = None, ) -> InsightResult: cache_key, cache_type, result = calculate_result_by_insight(team=insight.team, insight=insight, dashboard=dashboard) timestamp = now() diff --git a/posthog/caching/insight_cache.py b/posthog/caching/insight_cache.py index b019fd774df39..d1214c3a67a98 100644 --- a/posthog/caching/insight_cache.py +++ b/posthog/caching/insight_cache.py @@ -42,7 +42,9 @@ def schedule_cache_updates(): if len(representative_by_cache_key) > 0: logger.warn( - "Scheduled caches to be updated", candidates=len(to_update), tasks_created=len(representative_by_cache_key) + "Scheduled caches to be updated", + candidates=len(to_update), + tasks_created=len(representative_by_cache_key), ) else: logger.warn("No caches were found to be updated") @@ -120,7 +122,12 @@ def update_cache(caching_state_id: UUID): statsd.incr("caching_state_update_success") statsd.incr("caching_state_update_rows_updated", rows_updated) statsd.timing("caching_state_update_success_timing", duration) - logger.warn("Re-calculated insight cache", rows_updated=rows_updated, duration=duration, **metadata) + logger.warn( + "Re-calculated insight cache", + rows_updated=rows_updated, + duration=duration, + **metadata, + ) else: logger.warn( "Failed to re-calculate insight cache", @@ -137,11 +144,18 @@ def update_cache(caching_state_id: UUID): update_cache_task.apply_async(args=[caching_state_id], countdown=timedelta(minutes=10).total_seconds()) InsightCachingState.objects.filter(pk=caching_state.pk).update( - refresh_attempt=caching_state.refresh_attempt + 1, last_refresh_queued_at=now() + refresh_attempt=caching_state.refresh_attempt + 1, + last_refresh_queued_at=now(), ) -def update_cached_state(team_id: int, cache_key: str, timestamp: datetime, result: Any, ttl: Optional[int] = None): +def update_cached_state( + team_id: int, + cache_key: str, + timestamp: datetime, + result: Any, + ttl: Optional[int] = None, +): cache.set(cache_key, result, ttl if ttl is not None else settings.CACHED_RESULTS_TTL) insight_cache_write_counter.inc() @@ -156,6 +170,9 @@ def _extract_insight_dashboard(caching_state: InsightCachingState) -> Tuple[Insi if caching_state.dashboard_tile is not None: assert caching_state.dashboard_tile.insight is not None - return caching_state.dashboard_tile.insight, caching_state.dashboard_tile.dashboard + return ( + caching_state.dashboard_tile.insight, + caching_state.dashboard_tile.dashboard, + ) else: return caching_state.insight, None diff --git a/posthog/caching/insight_caching_state.py b/posthog/caching/insight_caching_state.py index fc87915c25a98..a8ae36c14f05a 100644 --- a/posthog/caching/insight_caching_state.py +++ b/posthog/caching/insight_caching_state.py @@ -20,6 +20,7 @@ logger = structlog.get_logger(__name__) + # :TODO: Make these configurable class TargetCacheAge(Enum): NO_CACHING = None @@ -95,7 +96,12 @@ def sync_insight_cache_states(): tiles = ( DashboardTile.objects.all() .filter(insight__isnull=False) - .prefetch_related("dashboard", "dashboard__sharingconfiguration_set", "insight", "insight__team") + .prefetch_related( + "dashboard", + "dashboard__sharingconfiguration_set", + "insight", + "insight__team", + ) .order_by("pk") ) @@ -105,7 +111,10 @@ def sync_insight_cache_states(): def upsert( - team: Team, target: Union[DashboardTile, Insight], lazy_loader: Optional[LazyLoader] = None, execute=True + team: Team, + target: Union[DashboardTile, Insight], + lazy_loader: Optional[LazyLoader] = None, + execute=True, ) -> Optional[InsightCachingState]: lazy_loader = lazy_loader or LazyLoader() cache_key = calculate_cache_key(target) @@ -129,7 +138,11 @@ def upsert( return model -def sync_insight_caching_state(team_id: int, insight_id: Optional[int] = None, dashboard_tile_id: Optional[int] = None): +def sync_insight_caching_state( + team_id: int, + insight_id: Optional[int] = None, + dashboard_tile_id: Optional[int] = None, +): try: team = Team.objects.get(pk=team_id) item: Optional[DashboardTile | Insight] = None diff --git a/posthog/caching/insights_api.py b/posthog/caching/insights_api.py index 399e889cf18af..1b07f37bc7804 100644 --- a/posthog/caching/insights_api.py +++ b/posthog/caching/insights_api.py @@ -5,7 +5,10 @@ import zoneinfo from rest_framework import request -from posthog.caching.calculate_results import CLICKHOUSE_MAX_EXECUTION_TIME, calculate_cache_key +from posthog.caching.calculate_results import ( + CLICKHOUSE_MAX_EXECUTION_TIME, + calculate_cache_key, +) from posthog.caching.insight_caching_state import InsightCachingState from posthog.models import DashboardTile, Insight from posthog.models.filters.utils import get_filter @@ -25,7 +28,11 @@ def should_refresh_insight( - insight: Insight, dashboard_tile: Optional[DashboardTile], *, request: request.Request, is_shared=False + insight: Insight, + dashboard_tile: Optional[DashboardTile], + *, + request: request.Request, + is_shared=False, ) -> Tuple[bool, timedelta]: """Return whether the insight should be refreshed now, and what's the minimum wait time between refreshes. diff --git a/posthog/caching/test/test_fetch_from_cache.py b/posthog/caching/test/test_fetch_from_cache.py index 4ffd44d24eca3..6ac03f0a0e451 100644 --- a/posthog/caching/test/test_fetch_from_cache.py +++ b/posthog/caching/test/test_fetch_from_cache.py @@ -11,7 +11,13 @@ ) from posthog.decorators import CacheType from posthog.models import Insight -from posthog.test.base import BaseTest, ClickhouseTestMixin, _create_event, _create_insight, flush_persons_and_events +from posthog.test.base import ( + BaseTest, + ClickhouseTestMixin, + _create_event, + _create_insight, + flush_persons_and_events, +) from posthog.utils import get_safe_cache @@ -20,12 +26,24 @@ class TestFetchFromCache(ClickhouseTestMixin, BaseTest): def setUp(self): super().setUp() - _create_event(team=self.team, event="$pageview", distinct_id="1", properties={"prop": "val"}) - _create_event(team=self.team, event="$pageview", distinct_id="2", properties={"prop": "another_val"}) + _create_event( + team=self.team, + event="$pageview", + distinct_id="1", + properties={"prop": "val"}, + ) + _create_event( + team=self.team, + event="$pageview", + distinct_id="2", + properties={"prop": "another_val"}, + ) flush_persons_and_events() insight, dashboard, dashboard_tile = _create_insight( - self.team, {"events": [{"id": "$pageview"}], "properties": []}, {"properties": [{}]} + self.team, + {"events": [{"id": "$pageview"}], "properties": []}, + {"properties": [{}]}, ) self.dashboard = dashboard self.insight = insight diff --git a/posthog/caching/test/test_insight_cache.py b/posthog/caching/test/test_insight_cache.py index 99ff1d8ca63d2..1dbe0b5ce2dc1 100644 --- a/posthog/caching/test/test_insight_cache.py +++ b/posthog/caching/test/test_insight_cache.py @@ -7,10 +7,19 @@ from freezegun import freeze_time from posthog.caching.calculate_results import get_cache_type -from posthog.caching.insight_cache import fetch_states_in_need_of_updating, schedule_cache_updates, update_cache +from posthog.caching.insight_cache import ( + fetch_states_in_need_of_updating, + schedule_cache_updates, + update_cache, +) from posthog.caching.insight_caching_state import upsert from posthog.caching.test.test_insight_caching_state import create_insight, filter_dict -from posthog.constants import INSIGHT_PATHS, INSIGHT_RETENTION, INSIGHT_STICKINESS, INSIGHT_TRENDS +from posthog.constants import ( + INSIGHT_PATHS, + INSIGHT_RETENTION, + INSIGHT_STICKINESS, + INSIGHT_TRENDS, +) from posthog.decorators import CacheType from posthog.models import Filter, InsightCachingState, RetentionFilter, Team, User from posthog.models.filters import PathFilter @@ -64,7 +73,10 @@ def test_schedule_cache_updates(update_cache_task, team: Team, user: User): schedule_cache_updates() - assert update_cache_task.delay.call_args_list == [call(caching_state1.pk), call(caching_state3.pk)] + assert update_cache_task.delay.call_args_list == [ + call(caching_state1.pk), + call(caching_state3.pk), + ] last_refresh_queued_at = InsightCachingState.objects.filter(team=team).values_list( "last_refresh_queued_at", flat=True @@ -81,9 +93,27 @@ def test_schedule_cache_updates(update_cache_task, team: Team, user: User): ({"last_refresh": None}, 1), ({"target_cache_age": None, "last_refresh": None}, 0), ({"target_cache_age": timedelta(days=1), "last_refresh": timedelta(days=2)}, 1), - ({"target_cache_age": timedelta(days=1), "last_refresh": timedelta(hours=23)}, 0), - ({"target_cache_age": timedelta(days=1), "last_refresh_queued_at": timedelta(hours=23)}, 1), - ({"target_cache_age": timedelta(days=1), "last_refresh_queued_at": timedelta(minutes=5)}, 0), + ( + { + "target_cache_age": timedelta(days=1), + "last_refresh": timedelta(hours=23), + }, + 0, + ), + ( + { + "target_cache_age": timedelta(days=1), + "last_refresh_queued_at": timedelta(hours=23), + }, + 1, + ), + ( + { + "target_cache_age": timedelta(days=1), + "last_refresh_queued_at": timedelta(minutes=5), + }, + 0, + ), ({"refresh_attempt": 2}, 1), ({"refresh_attempt": 3}, 0), ], @@ -137,7 +167,11 @@ def test_update_cache_updates_identical_cache_keys(team: Team, user: User, cache @patch("posthog.celery.update_cache_task") @patch("posthog.caching.insight_cache.calculate_result_by_insight") def test_update_cache_when_calculation_fails( - spy_calculate_result_by_insight, spy_update_cache_task, team: Team, user: User, cache + spy_calculate_result_by_insight, + spy_update_cache_task, + team: Team, + user: User, + cache, ): caching_state = create_insight_caching_state(team, user, refresh_attempt=1) spy_calculate_result_by_insight.side_effect = Exception() @@ -180,6 +214,11 @@ def test_update_cache_when_recently_refreshed(spy_calculate_result_by_insight, t ], ) @pytest.mark.django_db -def test_get_cache_type(team: Team, filter_model: Callable, insight_type: str, expected_cache_type: CacheType) -> None: +def test_get_cache_type( + team: Team, + filter_model: Callable, + insight_type: str, + expected_cache_type: CacheType, +) -> None: filter = filter_model(data={"insight": insight_type}, team=team) assert get_cache_type(filter) == expected_cache_type diff --git a/posthog/caching/test/test_insight_caching_state.py b/posthog/caching/test/test_insight_caching_state.py index 9b6f60aecf1c9..03a3652555202 100644 --- a/posthog/caching/test/test_insight_caching_state.py +++ b/posthog/caching/test/test_insight_caching_state.py @@ -52,7 +52,12 @@ def create_insight( insight = Insight.objects.create(team=team, filters=filters, deleted=deleted, query=query) if viewed_at_delta is not None: - InsightViewed.objects.create(insight=insight, last_viewed_at=now() - viewed_at_delta, user=user, team=team) + InsightViewed.objects.create( + insight=insight, + last_viewed_at=now() - viewed_at_delta, + user=user, + team=team, + ) if is_shared: SharingConfiguration.objects.create(team=team, insight=insight, enabled=True) @@ -78,7 +83,9 @@ def create_tile( mock_active_teams.return_value = {team.pk} if team_should_be_active else set() dashboard = Dashboard.objects.create( - team=team, last_accessed_at=now() - viewed_at_delta if viewed_at_delta else None, deleted=dashboard_deleted + team=team, + last_accessed_at=now() - viewed_at_delta if viewed_at_delta else None, + deleted=dashboard_deleted, ) if on_home_dashboard: @@ -109,36 +116,91 @@ def create_tile( [ # Insight test cases pytest.param(create_insight, {}, TargetCacheAge.MID_PRIORITY, id="shared insight (base)"), - pytest.param(create_insight, {"is_shared": False}, TargetCacheAge.NO_CACHING, id="not shared insight"), pytest.param( - create_insight, {"team_should_be_active": False}, TargetCacheAge.NO_CACHING, id="insight with inactive team" + create_insight, + {"is_shared": False}, + TargetCacheAge.NO_CACHING, + id="not shared insight", + ), + pytest.param( + create_insight, + {"team_should_be_active": False}, + TargetCacheAge.NO_CACHING, + id="insight with inactive team", + ), + pytest.param( + create_insight, + {"viewed_at_delta": None}, + TargetCacheAge.NO_CACHING, + id="insight never viewed", ), - pytest.param(create_insight, {"viewed_at_delta": None}, TargetCacheAge.NO_CACHING, id="insight never viewed"), pytest.param( create_insight, {"viewed_at_delta": timedelta(weeks=100)}, TargetCacheAge.NO_CACHING, id="insight viewed long time ago", ), - pytest.param(create_insight, {"filters": {}}, TargetCacheAge.NO_CACHING, id="insight with no filters"), - pytest.param(create_insight, {"deleted": True}, TargetCacheAge.NO_CACHING, id="deleted insight"), + pytest.param( + create_insight, + {"filters": {}}, + TargetCacheAge.NO_CACHING, + id="insight with no filters", + ), + pytest.param( + create_insight, + {"deleted": True}, + TargetCacheAge.NO_CACHING, + id="deleted insight", + ), # Dashboard tile test cases pytest.param(create_tile, {}, TargetCacheAge.LOW_PRIORITY, id="shared tile (base)"), - pytest.param(create_tile, {"is_dashboard_shared": False}, TargetCacheAge.NO_CACHING, id="not shared tile"), pytest.param( - create_tile, {"team_should_be_active": False}, TargetCacheAge.NO_CACHING, id="tile with inactive team" + create_tile, + {"is_dashboard_shared": False}, + TargetCacheAge.NO_CACHING, + id="not shared tile", + ), + pytest.param( + create_tile, + {"team_should_be_active": False}, + TargetCacheAge.NO_CACHING, + id="tile with inactive team", + ), + pytest.param( + create_tile, + {"dashboard_tile_deleted": True}, + TargetCacheAge.NO_CACHING, + id="deleted tile", + ), + pytest.param( + create_tile, + {"dashboard_deleted": True}, + TargetCacheAge.NO_CACHING, + id="tile with deleted dashboard", ), - pytest.param(create_tile, {"dashboard_tile_deleted": True}, TargetCacheAge.NO_CACHING, id="deleted tile"), pytest.param( - create_tile, {"dashboard_deleted": True}, TargetCacheAge.NO_CACHING, id="tile with deleted dashboard" + create_tile, + {"insight_deleted": True}, + TargetCacheAge.NO_CACHING, + id="tile with deleted insight", ), - pytest.param(create_tile, {"insight_deleted": True}, TargetCacheAge.NO_CACHING, id="tile with deleted insight"), pytest.param( - create_tile, {"insight_filters": {}}, TargetCacheAge.NO_CACHING, id="tile with insight with no filters" + create_tile, + {"insight_filters": {}}, + TargetCacheAge.NO_CACHING, + id="tile with insight with no filters", ), - pytest.param(create_tile, {"text_tile": True}, TargetCacheAge.NO_CACHING, id="tile with text"), pytest.param( - create_tile, {"on_home_dashboard": True}, TargetCacheAge.HIGH_PRIORITY, id="tile on home dashboard" + create_tile, + {"text_tile": True}, + TargetCacheAge.NO_CACHING, + id="tile with text", + ), + pytest.param( + create_tile, + {"on_home_dashboard": True}, + TargetCacheAge.HIGH_PRIORITY, + id="tile on home dashboard", ), pytest.param( create_tile, @@ -165,7 +227,10 @@ def create_tile( id="recently viewed tile (2)", ), pytest.param( - create_tile, {"viewed_at_delta": timedelta(days=20)}, TargetCacheAge.LOW_PRIORITY, id="tile viewed ages ago" + create_tile, + {"viewed_at_delta": timedelta(days=20)}, + TargetCacheAge.LOW_PRIORITY, + id="tile viewed ages ago", ), # cacheable types of query pytest.param( @@ -182,13 +247,19 @@ def create_tile( ), pytest.param( create_insight, - {"query": {"kind": "TimeToSeeDataSessionsQuery"}, "viewed_at_delta": timedelta(days=1)}, + { + "query": {"kind": "TimeToSeeDataSessionsQuery"}, + "viewed_at_delta": timedelta(days=1), + }, TargetCacheAge.MID_PRIORITY, id="insight with TimeToSeeDataSessionsQuery query viewed recently", ), pytest.param( create_insight, - {"query": {"kind": "TimeToSeeDataQuery"}, "viewed_at_delta": timedelta(days=1)}, + { + "query": {"kind": "TimeToSeeDataQuery"}, + "viewed_at_delta": timedelta(days=1), + }, TargetCacheAge.MID_PRIORITY, id="insight with TimeToSeeDataQuery query viewed recently", ), @@ -220,7 +291,12 @@ def create_tile( @pytest.mark.django_db @patch("posthog.caching.insight_caching_state.active_teams") def test_calculate_target_age( - mock_active_teams, team: Team, user: User, create_item, create_item_kw: Dict, expected_target_age: TargetCacheAge + mock_active_teams, + team: Team, + user: User, + create_item, + create_item_kw: Dict, + expected_target_age: TargetCacheAge, ): item = cast( Union[Insight, DashboardTile], diff --git a/posthog/caching/test/test_should_refresh_insight.py b/posthog/caching/test/test_should_refresh_insight.py index 12fb385ef2926..9c8932cd61e19 100644 --- a/posthog/caching/test/test_should_refresh_insight.py +++ b/posthog/caching/test/test_should_refresh_insight.py @@ -8,7 +8,10 @@ from rest_framework.request import Request from posthog.caching.calculate_results import CLICKHOUSE_MAX_EXECUTION_TIME from posthog.caching.insight_caching_state import InsightCachingState -from posthog.caching.insights_api import BASE_MINIMUM_INSIGHT_REFRESH_INTERVAL, should_refresh_insight +from posthog.caching.insights_api import ( + BASE_MINIMUM_INSIGHT_REFRESH_INTERVAL, + should_refresh_insight, +) from posthog.test.base import BaseTest, ClickhouseTestMixin, _create_insight @@ -97,7 +100,9 @@ def test_insights_with_hour_intervals_can_be_refreshed_more_often(self): @freeze_time("2012-01-14T03:21:34.000Z") def test_insights_with_ranges_lower_than_7_days_can_be_refreshed_more_often(self): insight, _, _ = _create_insight( - self.team, {"events": [{"id": "$pageview"}], "interval": "day", "date_from": "-3d"}, {} + self.team, + {"events": [{"id": "$pageview"}], "interval": "day", "date_from": "-3d"}, + {}, ) should_refresh_now, refresh_frequency = should_refresh_insight(insight, None, request=self.refresh_request) @@ -116,7 +121,9 @@ def test_insights_with_ranges_lower_than_7_days_can_be_refreshed_more_often(self @freeze_time("2012-01-14T03:21:34.000Z") def test_dashboard_filters_should_override_insight_filters_when_deciding_on_refresh_time(self): insight, _, dashboard_tile = _create_insight( - self.team, {"events": [{"id": "$pageview"}], "interval": "month"}, {"interval": "hour"} + self.team, + {"events": [{"id": "$pageview"}], "interval": "month"}, + {"interval": "hour"}, ) should_refresh_now, refresh_frequency = should_refresh_insight( diff --git a/posthog/caching/test/test_tolerant_zlib_compressor.py b/posthog/caching/test/test_tolerant_zlib_compressor.py index 3f895f244b49e..acefa330fe228 100644 --- a/posthog/caching/test/test_tolerant_zlib_compressor.py +++ b/posthog/caching/test/test_tolerant_zlib_compressor.py @@ -15,8 +15,18 @@ class TestTolerantZlibCompressor(TestCase): @parameterized.expand( [ - ("test_when_disabled_compress_is_the_identity", False, uncompressed_bytes, uncompressed_bytes), - ("test_when_enabled_can_compress", True, uncompressed_bytes, compressed_bytes), + ( + "test_when_disabled_compress_is_the_identity", + False, + uncompressed_bytes, + uncompressed_bytes, + ), + ( + "test_when_enabled_can_compress", + True, + uncompressed_bytes, + compressed_bytes, + ), ( "test_when_enabled_does_not_compress_small_values", True, @@ -32,9 +42,24 @@ def test_the_zlib_compressor_compression(self, _, setting: bool, input: bytes, o @parameterized.expand( [ - ("test_when_disabled_decompress_is_the_identity", False, uncompressed_bytes, uncompressed_bytes), - ("test_when_enabled_can_decompress", True, compressed_bytes, uncompressed_bytes), - ("test_when_disabled_can_still_decompress", False, compressed_bytes, uncompressed_bytes), + ( + "test_when_disabled_decompress_is_the_identity", + False, + uncompressed_bytes, + uncompressed_bytes, + ), + ( + "test_when_enabled_can_decompress", + True, + compressed_bytes, + uncompressed_bytes, + ), + ( + "test_when_disabled_can_still_decompress", + False, + compressed_bytes, + uncompressed_bytes, + ), ] ) def test_the_zlib_compressor_decompression(self, _, setting: bool, input: bytes, output: bytes) -> None: diff --git a/posthog/caching/utils.py b/posthog/caching/utils.py index 45ff4ba640968..636fdbb19c53e 100644 --- a/posthog/caching/utils.py +++ b/posthog/caching/utils.py @@ -56,7 +56,10 @@ def active_teams() -> Set[int]: ) if not teams_by_recency: return set() - redis.zadd(RECENTLY_ACCESSED_TEAMS_REDIS_KEY, {team: score for team, score in teams_by_recency}) + redis.zadd( + RECENTLY_ACCESSED_TEAMS_REDIS_KEY, + {team: score for team, score in teams_by_recency}, + ) redis.expire(RECENTLY_ACCESSED_TEAMS_REDIS_KEY, IN_A_DAY) all_teams = teams_by_recency @@ -71,7 +74,10 @@ def stale_cache_invalidation_disabled(team: Team) -> bool: str(team.uuid), groups={"organization": str(team.organization.id)}, group_properties={ - "organization": {"id": str(team.organization.id), "created_at": team.organization.created_at} + "organization": { + "id": str(team.organization.id), + "created_at": team.organization.created_at, + } }, only_evaluate_locally=True, send_feature_flag_events=False, @@ -81,7 +87,9 @@ def stale_cache_invalidation_disabled(team: Team) -> bool: def is_stale_filter( - team: Team, filter: Filter | RetentionFilter | StickinessFilter | PathFilter, cached_result: Any + team: Team, + filter: Filter | RetentionFilter | StickinessFilter | PathFilter, + cached_result: Any, ) -> bool: interval = filter.period.lower() if isinstance(filter, RetentionFilter) else filter.interval return is_stale(team, filter.date_to, interval, cached_result) diff --git a/posthog/celery.py b/posthog/celery.py index fb9043f56467a..1eb5bb40db888 100644 --- a/posthog/celery.py +++ b/posthog/celery.py @@ -104,7 +104,10 @@ def on_worker_start(**kwargs) -> None: def add_periodic_task_with_expiry( - sender: Celery, schedule_seconds: int, task_signature: Signature, name: str | None = None + sender: Celery, + schedule_seconds: int, + task_signature: Signature, + name: str | None = None, ): """ If the workers get delayed in processing tasks, then tasks that fire every X seconds get queued multiple times @@ -125,7 +128,10 @@ def add_periodic_task_with_expiry( def setup_periodic_tasks(sender: Celery, **kwargs): # Monitoring tasks add_periodic_task_with_expiry( - sender, 60, monitoring_check_clickhouse_schema_drift.s(), "check clickhouse schema drift" + sender, + 60, + monitoring_check_clickhouse_schema_drift.s(), + "check clickhouse schema drift", ) if not settings.DEBUG: @@ -136,15 +142,22 @@ def setup_periodic_tasks(sender: Celery, **kwargs): # Update events table partitions twice a week sender.add_periodic_task( - crontab(day_of_week="mon,fri", hour="0", minute="0"), update_event_partitions.s() # check twice a week + crontab(day_of_week="mon,fri", hour="0", minute="0"), + update_event_partitions.s(), # check twice a week ) # Send all instance usage to the Billing service sender.add_periodic_task( - crontab(hour="0", minute="5"), send_org_usage_reports.s(), name="send instance usage report" + crontab(hour="0", minute="5"), + send_org_usage_reports.s(), + name="send instance usage report", ) # Update local usage info for rate limiting purposes - offset by 30 minutes to not clash with the above - sender.add_periodic_task(crontab(hour="*", minute="30"), update_quota_limiting.s(), name="update quota limiting") + sender.add_periodic_task( + crontab(hour="*", minute="30"), + update_quota_limiting.s(), + name="update quota limiting", + ) # PostHog Cloud cron jobs # NOTE: We can't use is_cloud here as some Django elements aren't loaded yet. We check in the task execution instead @@ -152,7 +165,11 @@ def setup_periodic_tasks(sender: Celery, **kwargs): sender.add_periodic_task(crontab(hour="4", minute="0"), verify_persons_data_in_sync.s()) # Every 30 minutes, send decide request counts to the main posthog instance - sender.add_periodic_task(crontab(minute="*/30"), calculate_decide_usage.s(), name="calculate decide usage") + sender.add_periodic_task( + crontab(minute="*/30"), + calculate_decide_usage.s(), + name="calculate decide usage", + ) # Reset master project data every Monday at Thursday at 5 AM UTC. Mon and Thu because doing this every day # would be too hard on ClickHouse, and those days ensure most users will have data at most 3 days old. @@ -166,7 +183,9 @@ def setup_periodic_tasks(sender: Celery, **kwargs): sync_insight_cache_states_schedule = get_crontab(settings.SYNC_INSIGHT_CACHE_STATES_SCHEDULE) if sync_insight_cache_states_schedule: sender.add_periodic_task( - sync_insight_cache_states_schedule, sync_insight_cache_states_task.s(), name="sync insight cache states" + sync_insight_cache_states_schedule, + sync_insight_cache_states_task.s(), + name="sync insight cache states", ) add_periodic_task_with_expiry( @@ -226,7 +245,9 @@ def setup_periodic_tasks(sender: Celery, **kwargs): name="PG table cache hit rate", ) sender.add_periodic_task( - crontab(minute="0", hour="*"), pg_plugin_server_query_timing.s(), name="PG plugin server query timing" + crontab(minute="0", hour="*"), + pg_plugin_server_query_timing.s(), + name="PG plugin server query timing", ) add_periodic_task_with_expiry( sender, @@ -244,7 +265,9 @@ def setup_periodic_tasks(sender: Celery, **kwargs): if clear_clickhouse_crontab := get_crontab(settings.CLEAR_CLICKHOUSE_REMOVED_DATA_SCHEDULE_CRON): sender.add_periodic_task( - clear_clickhouse_crontab, clickhouse_clear_removed_data.s(), name="clickhouse clear removed data" + clear_clickhouse_crontab, + clickhouse_clear_removed_data.s(), + name="clickhouse clear removed data", ) if clear_clickhouse_deleted_person_crontab := get_crontab(settings.CLEAR_CLICKHOUSE_DELETED_PERSON_SCHEDULE_CRON): @@ -256,17 +279,21 @@ def setup_periodic_tasks(sender: Celery, **kwargs): if settings.EE_AVAILABLE: sender.add_periodic_task( - crontab(hour="0", minute=str(randrange(0, 40))), clickhouse_send_license_usage.s() + crontab(hour="0", minute=str(randrange(0, 40))), + clickhouse_send_license_usage.s(), ) # every day at a random minute past midnight. Randomize to avoid overloading license.posthog.com sender.add_periodic_task( - crontab(hour="4", minute=str(randrange(0, 40))), clickhouse_send_license_usage.s() + crontab(hour="4", minute=str(randrange(0, 40))), + clickhouse_send_license_usage.s(), ) # again a few hours later just to make sure materialize_columns_crontab = get_crontab(settings.MATERIALIZE_COLUMNS_SCHEDULE_CRON) if materialize_columns_crontab: sender.add_periodic_task( - materialize_columns_crontab, clickhouse_materialize_columns.s(), name="clickhouse materialize columns" + materialize_columns_crontab, + clickhouse_materialize_columns.s(), + name="clickhouse materialize columns", ) sender.add_periodic_task( @@ -276,7 +303,10 @@ def setup_periodic_tasks(sender: Celery, **kwargs): ) sender.add_periodic_task(crontab(hour="*", minute="55"), schedule_all_subscriptions.s()) - sender.add_periodic_task(crontab(hour="2", minute=str(randrange(0, 40))), ee_persist_finished_recordings.s()) + sender.add_periodic_task( + crontab(hour="2", minute=str(randrange(0, 40))), + ee_persist_finished_recordings.s(), + ) sender.add_periodic_task( crontab(minute="0", hour="*"), @@ -303,7 +333,10 @@ def setup_periodic_tasks(sender: Celery, **kwargs): def pre_run_signal_handler(task_id, task, **kwargs): from statshog.defaults.django import statsd - from posthog.clickhouse.client.connection import Workload, set_default_clickhouse_workload_type + from posthog.clickhouse.client.connection import ( + Workload, + set_default_clickhouse_workload_type, + ) from posthog.clickhouse.query_tagging import tag_queries statsd.incr("celery_tasks_metrics.pre_run", tags={"name": task.name}) @@ -359,7 +392,15 @@ def enqueue_clickhouse_execute_with_progress( """ from posthog.client import execute_with_progress - execute_with_progress(team_id, query_id, query, args, settings, with_column_types, task_id=self.request.id) + execute_with_progress( + team_id, + query_id, + query, + args, + settings, + with_column_types, + task_id=self.request.id, + ) @app.task(ignore_result=True) @@ -425,7 +466,9 @@ def pg_plugin_server_query_timing(): if key == "query_type": continue statsd.gauge( - f"pg_plugin_server_query_{key}", value, tags={"query_type": row_dictionary["query_type"]} + f"pg_plugin_server_query_{key}", + value, + tags={"query_type": row_dictionary["query_type"]}, ) except: # if this doesn't work keep going @@ -457,7 +500,13 @@ def pg_row_count(): pass -CLICKHOUSE_TABLES = ["events", "person", "person_distinct_id2", "session_replay_events", "log_entries"] +CLICKHOUSE_TABLES = [ + "events", + "person", + "person_distinct_id2", + "session_replay_events", + "log_entries", +] if not is_cloud(): CLICKHOUSE_TABLES.append("session_recording_events") @@ -482,7 +531,11 @@ def clickhouse_lag(): ) query = QUERY.format(table=table) lag = sync_execute(query)[0][2] - statsd.gauge("posthog_celery_clickhouse__table_lag_seconds", lag, tags={"table": table}) + statsd.gauge( + "posthog_celery_clickhouse__table_lag_seconds", + lag, + tags={"table": table}, + ) lag_gauge.labels(table_name=table).set(lag) except: pass @@ -535,7 +588,12 @@ def ingestion_lag(): pass -KNOWN_CELERY_TASK_IDENTIFIERS = {"pluginJob", "runEveryHour", "runEveryMinute", "runEveryDay"} +KNOWN_CELERY_TASK_IDENTIFIERS = { + "pluginJob", + "runEveryHour", + "runEveryMinute", + "runEveryDay", +} @app.task(ignore_result=True) @@ -588,7 +646,11 @@ def graphile_worker_queue_size(): seen_task_identifier.add(task_identifier) waiting_jobs_gauge.labels(task_identifier=task_identifier).set(count) processing_lag_gauge.labels(task_identifier=task_identifier).set(time.time() - float(oldest)) - statsd.gauge("graphile_waiting_jobs", count, tags={"task_identifier": task_identifier}) + statsd.gauge( + "graphile_waiting_jobs", + count, + tags={"task_identifier": task_identifier}, + ) # The query will not return rows for empty queues, creating missing points. # Let's emit updates for known queues even if they are empty. @@ -618,7 +680,11 @@ def clickhouse_row_count(): query = QUERY.format(table=table) rows = sync_execute(query)[0][0] row_count_gauge.labels(table_name=table).set(rows) - statsd.gauge(f"posthog_celery_clickhouse_table_row_count", rows, tags={"table": table}) + statsd.gauge( + f"posthog_celery_clickhouse_table_row_count", + rows, + tags={"table": table}, + ) except: pass @@ -681,7 +747,11 @@ def clickhouse_part_count(): ) for table, parts in rows: parts_count_gauge.labels(table=table).set(parts) - statsd.gauge(f"posthog_celery_clickhouse_table_parts_count", parts, tags={"table": table}) + statsd.gauge( + f"posthog_celery_clickhouse_table_parts_count", + parts, + tags={"table": table}, + ) @app.task(ignore_result=True) @@ -710,7 +780,11 @@ def clickhouse_mutation_count(): ) for table, muts in rows: mutations_count_gauge.labels(table=table).set(muts) - statsd.gauge(f"posthog_celery_clickhouse_table_mutations_count", muts, tags={"table": table}) + statsd.gauge( + f"posthog_celery_clickhouse_table_mutations_count", + muts, + tags={"table": table}, + ) @app.task(ignore_result=True) @@ -739,7 +813,9 @@ def redis_celery_queue_depth(): try: with pushed_metrics_registry("redis_celery_queue_depth_registry") as registry: celery_task_queue_depth_gauge = Gauge( - "posthog_celery_queue_depth", "We use this to monitor the depth of the celery queue.", registry=registry + "posthog_celery_queue_depth", + "We use this to monitor the depth of the celery queue.", + registry=registry, ) llen = get_client().llen("celery") @@ -767,7 +843,9 @@ def clean_stale_partials(): @app.task(ignore_result=True) def monitoring_check_clickhouse_schema_drift(): - from posthog.tasks.check_clickhouse_schema_drift import check_clickhouse_schema_drift + from posthog.tasks.check_clickhouse_schema_drift import ( + check_clickhouse_schema_drift, + ) check_clickhouse_schema_drift() @@ -801,7 +879,11 @@ def update_cache_task(caching_state_id: UUID): @app.task(ignore_result=True) -def sync_insight_caching_state(team_id: int, insight_id: Optional[int] = None, dashboard_tile_id: Optional[int] = None): +def sync_insight_caching_state( + team_id: int, + insight_id: Optional[int] = None, + dashboard_tile_id: Optional[int] = None, +): from posthog.caching.insight_caching_state import sync_insight_caching_state sync_insight_caching_state(team_id, insight_id, dashboard_tile_id) @@ -851,7 +933,9 @@ def calculate_decide_usage() -> None: def find_flags_with_enriched_analytics(): from datetime import datetime, timedelta - from posthog.models.feature_flag.flag_analytics import find_flags_with_enriched_analytics + from posthog.models.feature_flag.flag_analytics import ( + find_flags_with_enriched_analytics, + ) end = datetime.now() begin = end - timedelta(hours=12) @@ -869,7 +953,9 @@ def demo_reset_master_team(): @app.task(ignore_result=True) def sync_all_organization_available_features(): - from posthog.tasks.sync_all_organization_available_features import sync_all_organization_available_features + from posthog.tasks.sync_all_organization_available_features import ( + sync_all_organization_available_features, + ) sync_all_organization_available_features() @@ -883,7 +969,9 @@ def check_async_migration_health(): @app.task(ignore_result=True) def verify_persons_data_in_sync(): - from posthog.tasks.verify_persons_data_in_sync import verify_persons_data_in_sync as verify + from posthog.tasks.verify_persons_data_in_sync import ( + verify_persons_data_in_sync as verify, + ) if not is_cloud(): return @@ -905,7 +993,9 @@ def recompute_materialized_columns_enabled() -> bool: def clickhouse_materialize_columns(): if recompute_materialized_columns_enabled(): try: - from ee.clickhouse.materialized_columns.analyze import materialize_properties_task + from ee.clickhouse.materialized_columns.analyze import ( + materialize_properties_task, + ) except ImportError: pass else: @@ -943,7 +1033,9 @@ def update_quota_limiting(): @app.task(ignore_result=True) def schedule_all_subscriptions(): try: - from ee.tasks.subscriptions import schedule_all_subscriptions as _schedule_all_subscriptions + from ee.tasks.subscriptions import ( + schedule_all_subscriptions as _schedule_all_subscriptions, + ) except ImportError: pass else: diff --git a/posthog/clickhouse/client/connection.py b/posthog/clickhouse/client/connection.py index 8cf665d857c60..fbbfd08086822 100644 --- a/posthog/clickhouse/client/connection.py +++ b/posthog/clickhouse/client/connection.py @@ -30,7 +30,10 @@ def get_pool(workload: Workload, team_id=None, readonly=False): # Note that `readonly` does nothing if the relevant vars are not set! if readonly and settings.READONLY_CLICKHOUSE_USER is not None and settings.READONLY_CLICKHOUSE_PASSWORD: - return make_ch_pool(user=settings.READONLY_CLICKHOUSE_USER, password=settings.READONLY_CLICKHOUSE_PASSWORD) + return make_ch_pool( + user=settings.READONLY_CLICKHOUSE_USER, + password=settings.READONLY_CLICKHOUSE_PASSWORD, + ) if ( workload == Workload.OFFLINE or workload == Workload.DEFAULT and _default_workload == Workload.OFFLINE diff --git a/posthog/clickhouse/client/execute.py b/posthog/clickhouse/client/execute.py index 60cad345fcaa7..5f039c78c19f9 100644 --- a/posthog/clickhouse/client/execute.py +++ b/posthog/clickhouse/client/execute.py @@ -40,7 +40,10 @@ @lru_cache(maxsize=1) def default_settings() -> Dict: - return {"join_algorithm": "direct,parallel_hash", "distributed_replica_max_ignored_errors": 1000} + return { + "join_algorithm": "direct,parallel_hash", + "distributed_replica_max_ignored_errors": 1000, + } @lru_cache(maxsize=1) @@ -81,7 +84,7 @@ def sync_execute( from posthog.test.base import flush_persons_and_events flush_persons_and_events() - except ModuleNotFoundError: # when we run plugin server tests it tries to run above, ignore + except (ModuleNotFoundError): # when we run plugin server tests it tries to run above, ignore pass with get_pool(workload, team_id, readonly).get_client() as client: @@ -91,7 +94,10 @@ def sync_execute( query_id = validated_client_query_id() core_settings = {**default_settings(), **(settings or {})} tags["query_settings"] = core_settings - settings = {**core_settings, "log_comment": json.dumps(tags, separators=(",", ":"))} + settings = { + **core_settings, + "log_comment": json.dumps(tags, separators=(",", ":")), + } try: result = client.execute( prepared_sql, @@ -102,7 +108,10 @@ def sync_execute( ) except Exception as err: err = wrap_query_error(err) - statsd.incr("clickhouse_sync_execution_failure", tags={"failed": True, "reason": type(err).__name__}) + statsd.incr( + "clickhouse_sync_execution_failure", + tags={"failed": True, "reason": type(err).__name__}, + ) raise err finally: @@ -147,7 +156,12 @@ def query_with_columns( @patchable -def _prepare_query(client: SyncClient, query: str, args: QueryArgs, workload: Workload = Workload.DEFAULT): +def _prepare_query( + client: SyncClient, + query: str, + args: QueryArgs, + workload: Workload = Workload.DEFAULT, +): """ Given a string query with placeholders we do one of two things: @@ -219,7 +233,9 @@ def format_sql(rendered_sql, colorize=True): import pygments.lexers return pygments.highlight( - formatted_sql, pygments.lexers.get_lexer_by_name("sql"), pygments.formatters.TerminalFormatter() + formatted_sql, + pygments.lexers.get_lexer_by_name("sql"), + pygments.formatters.TerminalFormatter(), ) except: pass diff --git a/posthog/clickhouse/client/execute_async.py b/posthog/clickhouse/client/execute_async.py index 89de42427f568..3bb28c3f20075 100644 --- a/posthog/clickhouse/client/execute_async.py +++ b/posthog/clickhouse/client/execute_async.py @@ -49,7 +49,14 @@ def generate_redis_results_key(query_id): def execute_with_progress( - team_id, query_id, query, args=None, settings=None, with_column_types=False, update_freq=0.2, task_id=None + team_id, + query_id, + query, + args=None, + settings=None, + with_column_types=False, + update_freq=0.2, + task_id=None, ): """ Kick off query with progress reporting @@ -81,7 +88,10 @@ def execute_with_progress( try: progress = ch_client.execute_with_progress( - prepared_sql, params=prepared_args, settings=settings, with_column_types=with_column_types + prepared_sql, + params=prepared_args, + settings=settings, + with_column_types=with_column_types, ) for num_rows, total_rows in progress: query_status = QueryStatus( @@ -145,7 +155,14 @@ def execute_with_progress( def enqueue_execute_with_progress( - team_id, query, args=None, settings=None, with_column_types=False, bypass_celery=False, query_id=None, force=False + team_id, + query, + args=None, + settings=None, + with_column_types=False, + bypass_celery=False, + query_id=None, + force=False, ): if not query_id: query_id = _query_hash(query, team_id, args) diff --git a/posthog/clickhouse/client/test/test_connection.py b/posthog/clickhouse/client/test/test_connection.py index d40e544bf16fc..e05a87b84e60c 100644 --- a/posthog/clickhouse/client/test/test_connection.py +++ b/posthog/clickhouse/client/test/test_connection.py @@ -1,6 +1,11 @@ import pytest -from posthog.clickhouse.client.connection import Workload, get_pool, make_ch_pool, set_default_clickhouse_workload_type +from posthog.clickhouse.client.connection import ( + Workload, + get_pool, + make_ch_pool, + set_default_clickhouse_workload_type, +) def test_connection_pool_creation_without_offline_cluster(settings): diff --git a/posthog/clickhouse/dead_letter_queue.py b/posthog/clickhouse/dead_letter_queue.py index 53896bbfa6869..298d99e4ed88b 100644 --- a/posthog/clickhouse/dead_letter_queue.py +++ b/posthog/clickhouse/dead_letter_queue.py @@ -86,7 +86,9 @@ _offset FROM {database}.kafka_{table_name} """.format( - table_name=DEAD_LETTER_QUEUE_TABLE, cluster=CLICKHOUSE_CLUSTER, database=CLICKHOUSE_DATABASE + table_name=DEAD_LETTER_QUEUE_TABLE, + cluster=CLICKHOUSE_CLUSTER, + database=CLICKHOUSE_DATABASE, ) diff --git a/posthog/clickhouse/log_entries.py b/posthog/clickhouse/log_entries.py index 017ee408aea44..471ca18eac7fb 100644 --- a/posthog/clickhouse/log_entries.py +++ b/posthog/clickhouse/log_entries.py @@ -69,7 +69,9 @@ _offset FROM {database}.kafka_{table_name} """.format( - table_name=LOG_ENTRIES_TABLE, cluster=CLICKHOUSE_CLUSTER, database=CLICKHOUSE_DATABASE + table_name=LOG_ENTRIES_TABLE, + cluster=CLICKHOUSE_CLUSTER, + database=CLICKHOUSE_DATABASE, ) diff --git a/posthog/clickhouse/migrations/0003_person.py b/posthog/clickhouse/migrations/0003_person.py index d780fd855ec8b..ccdcf428de43b 100644 --- a/posthog/clickhouse/migrations/0003_person.py +++ b/posthog/clickhouse/migrations/0003_person.py @@ -1,5 +1,9 @@ from posthog.clickhouse.client.migration_tools import run_sql_with_exceptions -from posthog.models.person.sql import COMMENT_DISTINCT_ID_COLUMN_SQL, PERSONS_DISTINCT_ID_TABLE_SQL, PERSONS_TABLE_SQL +from posthog.models.person.sql import ( + COMMENT_DISTINCT_ID_COLUMN_SQL, + PERSONS_DISTINCT_ID_TABLE_SQL, + PERSONS_TABLE_SQL, +) operations = [ run_sql_with_exceptions(PERSONS_TABLE_SQL()), diff --git a/posthog/clickhouse/migrations/0004_kafka.py b/posthog/clickhouse/migrations/0004_kafka.py index 5243e206bd098..857398c2a3cc7 100644 --- a/posthog/clickhouse/migrations/0004_kafka.py +++ b/posthog/clickhouse/migrations/0004_kafka.py @@ -1,5 +1,8 @@ from posthog.clickhouse.client.migration_tools import run_sql_with_exceptions -from posthog.models.event.sql import DISTRIBUTED_EVENTS_TABLE_SQL, WRITABLE_EVENTS_TABLE_SQL +from posthog.models.event.sql import ( + DISTRIBUTED_EVENTS_TABLE_SQL, + WRITABLE_EVENTS_TABLE_SQL, +) from posthog.models.person.sql import ( KAFKA_PERSONS_DISTINCT_ID_TABLE_SQL, KAFKA_PERSONS_TABLE_SQL, diff --git a/posthog/clickhouse/migrations/0012_person_id_deleted_column.py b/posthog/clickhouse/migrations/0012_person_id_deleted_column.py index ef324ce2417f9..40a3a0a0ef4f6 100644 --- a/posthog/clickhouse/migrations/0012_person_id_deleted_column.py +++ b/posthog/clickhouse/migrations/0012_person_id_deleted_column.py @@ -1,5 +1,8 @@ from posthog.clickhouse.client.migration_tools import run_sql_with_exceptions -from posthog.models.person.sql import KAFKA_PERSONS_DISTINCT_ID_TABLE_SQL, PERSONS_DISTINCT_ID_TABLE_MV_SQL +from posthog.models.person.sql import ( + KAFKA_PERSONS_DISTINCT_ID_TABLE_SQL, + PERSONS_DISTINCT_ID_TABLE_MV_SQL, +) from posthog.settings import CLICKHOUSE_CLUSTER operations = [ diff --git a/posthog/clickhouse/migrations/0018_group_analytics_schema.py b/posthog/clickhouse/migrations/0018_group_analytics_schema.py index 69e923f8b7989..05cf74d0c24ae 100644 --- a/posthog/clickhouse/migrations/0018_group_analytics_schema.py +++ b/posthog/clickhouse/migrations/0018_group_analytics_schema.py @@ -1,5 +1,9 @@ from posthog.clickhouse.client.migration_tools import run_sql_with_exceptions -from posthog.models.group.sql import GROUPS_TABLE_MV_SQL, GROUPS_TABLE_SQL, KAFKA_GROUPS_TABLE_SQL +from posthog.models.group.sql import ( + GROUPS_TABLE_MV_SQL, + GROUPS_TABLE_SQL, + KAFKA_GROUPS_TABLE_SQL, +) operations = [ run_sql_with_exceptions(GROUPS_TABLE_SQL()), diff --git a/posthog/clickhouse/migrations/0023_dead_letter_queue_tags.py b/posthog/clickhouse/migrations/0023_dead_letter_queue_tags.py index f34752a660a28..cce6212290056 100644 --- a/posthog/clickhouse/migrations/0023_dead_letter_queue_tags.py +++ b/posthog/clickhouse/migrations/0023_dead_letter_queue_tags.py @@ -1,5 +1,8 @@ from posthog.clickhouse.client.migration_tools import run_sql_with_exceptions -from posthog.clickhouse.dead_letter_queue import DEAD_LETTER_QUEUE_TABLE_MV_SQL, KAFKA_DEAD_LETTER_QUEUE_TABLE_SQL +from posthog.clickhouse.dead_letter_queue import ( + DEAD_LETTER_QUEUE_TABLE_MV_SQL, + KAFKA_DEAD_LETTER_QUEUE_TABLE_SQL, +) from posthog.settings import CLICKHOUSE_CLUSTER operations = [ diff --git a/posthog/clickhouse/migrations/0025_json_events.py b/posthog/clickhouse/migrations/0025_json_events.py index 1dd452dff732e..fd8056b227123 100644 --- a/posthog/clickhouse/migrations/0025_json_events.py +++ b/posthog/clickhouse/migrations/0025_json_events.py @@ -1,5 +1,8 @@ from posthog.clickhouse.client.migration_tools import run_sql_with_exceptions -from posthog.models.event.sql import EVENTS_TABLE_JSON_MV_SQL, KAFKA_EVENTS_TABLE_JSON_SQL +from posthog.models.event.sql import ( + EVENTS_TABLE_JSON_MV_SQL, + KAFKA_EVENTS_TABLE_JSON_SQL, +) operations = [ run_sql_with_exceptions(KAFKA_EVENTS_TABLE_JSON_SQL()), diff --git a/posthog/clickhouse/migrations/0026_fix_materialized_window_and_session_ids.py b/posthog/clickhouse/migrations/0026_fix_materialized_window_and_session_ids.py index d2fc6a7d4bac9..b27c8ad29f59a 100644 --- a/posthog/clickhouse/migrations/0026_fix_materialized_window_and_session_ids.py +++ b/posthog/clickhouse/migrations/0026_fix_materialized_window_and_session_ids.py @@ -1,6 +1,9 @@ from infi.clickhouse_orm import migrations -from posthog.clickhouse.materialized_columns import get_materialized_columns, materialize +from posthog.clickhouse.materialized_columns import ( + get_materialized_columns, + materialize, +) from posthog.client import sync_execute from posthog.settings import CLICKHOUSE_CLUSTER @@ -38,7 +41,6 @@ def ensure_only_new_column_exists(database, table_name, old_column_name, new_col def materialize_session_and_window_id(database): - properties = ["$session_id", "$window_id"] for property_name in properties: materialized_columns = get_materialized_columns("events", use_cache=False) diff --git a/posthog/clickhouse/migrations/0027_persons_and_groups_on_events.py b/posthog/clickhouse/migrations/0027_persons_and_groups_on_events.py index 500d2e1184f4b..534a2d6dbf01c 100644 --- a/posthog/clickhouse/migrations/0027_persons_and_groups_on_events.py +++ b/posthog/clickhouse/migrations/0027_persons_and_groups_on_events.py @@ -2,7 +2,10 @@ from posthog.clickhouse.client.migration_tools import run_sql_with_exceptions from posthog.client import sync_execute -from posthog.models.event.sql import EVENTS_TABLE_JSON_MV_SQL, KAFKA_EVENTS_TABLE_JSON_SQL +from posthog.models.event.sql import ( + EVENTS_TABLE_JSON_MV_SQL, + KAFKA_EVENTS_TABLE_JSON_SQL, +) from posthog.settings import CLICKHOUSE_CLUSTER ADD_COLUMNS_BASE_SQL = """ diff --git a/posthog/clickhouse/migrations/0028_dead_letter_queue_settings.py b/posthog/clickhouse/migrations/0028_dead_letter_queue_settings.py index fd8676e47b74e..ff7746fe8e326 100644 --- a/posthog/clickhouse/migrations/0028_dead_letter_queue_settings.py +++ b/posthog/clickhouse/migrations/0028_dead_letter_queue_settings.py @@ -1,5 +1,8 @@ from posthog.clickhouse.client.migration_tools import run_sql_with_exceptions -from posthog.clickhouse.dead_letter_queue import DEAD_LETTER_QUEUE_TABLE_MV_SQL, KAFKA_DEAD_LETTER_QUEUE_TABLE_SQL +from posthog.clickhouse.dead_letter_queue import ( + DEAD_LETTER_QUEUE_TABLE_MV_SQL, + KAFKA_DEAD_LETTER_QUEUE_TABLE_SQL, +) from posthog.settings.data_stores import CLICKHOUSE_CLUSTER operations = [ diff --git a/posthog/clickhouse/migrations/0030_created_at_persons_and_groups_on_events.py b/posthog/clickhouse/migrations/0030_created_at_persons_and_groups_on_events.py index a68f39422ab65..254ff78a531ff 100644 --- a/posthog/clickhouse/migrations/0030_created_at_persons_and_groups_on_events.py +++ b/posthog/clickhouse/migrations/0030_created_at_persons_and_groups_on_events.py @@ -2,7 +2,10 @@ from posthog.clickhouse.client.migration_tools import run_sql_with_exceptions from posthog.client import sync_execute -from posthog.models.event.sql import EVENTS_TABLE_JSON_MV_SQL, KAFKA_EVENTS_TABLE_JSON_SQL +from posthog.models.event.sql import ( + EVENTS_TABLE_JSON_MV_SQL, + KAFKA_EVENTS_TABLE_JSON_SQL, +) from posthog.settings import CLICKHOUSE_CLUSTER ADD_COLUMNS_BASE_SQL = """ diff --git a/posthog/clickhouse/migrations/0036_session_recording_events_materialized_columns.py b/posthog/clickhouse/migrations/0036_session_recording_events_materialized_columns.py index be819a0111a01..d6705db02eb33 100644 --- a/posthog/clickhouse/migrations/0036_session_recording_events_materialized_columns.py +++ b/posthog/clickhouse/migrations/0036_session_recording_events_materialized_columns.py @@ -1,12 +1,13 @@ from infi.clickhouse_orm import migrations from posthog.client import sync_execute -from posthog.session_recordings.sql.session_recording_event_sql import MATERIALIZED_COLUMNS +from posthog.session_recordings.sql.session_recording_event_sql import ( + MATERIALIZED_COLUMNS, +) from posthog.settings import CLICKHOUSE_CLUSTER def create_events_summary_mat_columns(database): - columns_to_add = [ "events_summary", "click_count", diff --git a/posthog/clickhouse/migrations/0042_kafka_partitions_stats.py b/posthog/clickhouse/migrations/0042_kafka_partitions_stats.py index afc8e898f1327..1a588a1092474 100644 --- a/posthog/clickhouse/migrations/0042_kafka_partitions_stats.py +++ b/posthog/clickhouse/migrations/0042_kafka_partitions_stats.py @@ -1,5 +1,8 @@ from posthog.clickhouse.client.migration_tools import run_sql_with_exceptions -from posthog.kafka_client.topics import KAFKA_EVENTS_PLUGIN_INGESTION_OVERFLOW, KAFKA_SESSION_RECORDING_EVENTS +from posthog.kafka_client.topics import ( + KAFKA_EVENTS_PLUGIN_INGESTION_OVERFLOW, + KAFKA_SESSION_RECORDING_EVENTS, +) from posthog.models.kafka_partition_stats.sql import ( CREATE_PARTITION_STATISTICS_KAFKA_TABLE, CREATE_PARTITION_STATISTICS_MV, diff --git a/posthog/clickhouse/plugin_log_entries.py b/posthog/clickhouse/plugin_log_entries.py index cb03e34eb3471..1f4f7c70d7146 100644 --- a/posthog/clickhouse/plugin_log_entries.py +++ b/posthog/clickhouse/plugin_log_entries.py @@ -61,7 +61,9 @@ _offset FROM {database}.kafka_{table_name} """.format( - table_name=PLUGIN_LOG_ENTRIES_TABLE, cluster=CLICKHOUSE_CLUSTER, database=CLICKHOUSE_DATABASE + table_name=PLUGIN_LOG_ENTRIES_TABLE, + cluster=CLICKHOUSE_CLUSTER, + database=CLICKHOUSE_DATABASE, ) diff --git a/posthog/clickhouse/system_status.py b/posthog/clickhouse/system_status.py index 2317e41c39e1d..bd9bd22f427c6 100644 --- a/posthog/clickhouse/system_status.py +++ b/posthog/clickhouse/system_status.py @@ -6,10 +6,17 @@ from dateutil.relativedelta import relativedelta from django.utils import timezone -from posthog.api.dead_letter_queue import get_dead_letter_queue_events_last_24h, get_dead_letter_queue_size +from posthog.api.dead_letter_queue import ( + get_dead_letter_queue_events_last_24h, + get_dead_letter_queue_size, +) from posthog.cache_utils import cache_for from posthog.client import query_with_columns, sync_execute -from posthog.models.event.util import get_event_count, get_event_count_for_last_month, get_event_count_month_to_date +from posthog.models.event.util import ( + get_event_count, + get_event_count_for_last_month, + get_event_count_month_to_date, +) from posthog.session_recordings.models.system_status_queries import ( get_recording_status_month_to_date, ) @@ -25,12 +32,20 @@ def system_status() -> Generator[SystemStatusRow, None, None]: alive = is_alive() - yield {"key": "clickhouse_alive", "metric": "Clickhouse database alive", "value": alive} + yield { + "key": "clickhouse_alive", + "metric": "Clickhouse database alive", + "value": alive, + } if not alive: return - yield {"key": "clickhouse_event_count", "metric": "Events in ClickHouse", "value": get_event_count()} + yield { + "key": "clickhouse_event_count", + "metric": "Events in ClickHouse", + "value": get_event_count(), + } yield { "key": "clickhouse_event_count_last_month", "metric": "Events recorded last month", @@ -67,8 +82,16 @@ def system_status() -> Generator[SystemStatusRow, None, None]: for index, (total_space, free_space) in enumerate(disk_status): metric = "Clickhouse disk" if len(disk_status) == 1 else f"Clickhouse disk {index}" - yield {"key": f"clickhouse_disk_{index}_free_space", "metric": f"{metric} free space", "value": free_space} - yield {"key": f"clickhouse_disk_{index}_total_space", "metric": f"{metric} total space", "value": total_space} + yield { + "key": f"clickhouse_disk_{index}_free_space", + "metric": f"{metric} free space", + "value": free_space, + } + yield { + "key": f"clickhouse_disk_{index}_total_space", + "metric": f"{metric} total space", + "value": total_space, + } table_sizes = sync_execute( """ @@ -97,7 +120,10 @@ def system_status() -> Generator[SystemStatusRow, None, None]: "key": "clickhouse_system_metrics", "metric": "Clickhouse system metrics", "value": "", - "subrows": {"columns": ["Metric", "Value", "Description"], "rows": list(sorted(system_metrics))}, + "subrows": { + "columns": ["Metric", "Value", "Description"], + "rows": list(sorted(system_metrics)), + }, } # This timestamp is a naive timestamp (does not include a timezone) @@ -121,9 +147,16 @@ def system_status() -> Generator[SystemStatusRow, None, None]: dead_letter_queue_size = get_dead_letter_queue_size() - yield {"key": "dead_letter_queue_size", "metric": "Dead letter queue size", "value": dead_letter_queue_size} + yield { + "key": "dead_letter_queue_size", + "metric": "Dead letter queue size", + "value": dead_letter_queue_size, + } - dead_letter_queue_events_high, dead_letter_queue_events_last_day = dead_letter_queue_ratio() + ( + dead_letter_queue_events_high, + dead_letter_queue_events_last_day, + ) = dead_letter_queue_ratio() yield { "key": "dead_letter_queue_events_last_day", diff --git a/posthog/clickhouse/test/test_person_overrides.py b/posthog/clickhouse/test/test_person_overrides.py index f0d33c7d617f4..dc8bc2b17c503 100644 --- a/posthog/clickhouse/test/test_person_overrides.py +++ b/posthog/clickhouse/test/test_person_overrides.py @@ -81,7 +81,14 @@ def test_can_insert_person_overrides(): assert results != [] [result] = results created_at, *the_rest = result - assert the_rest == [1, old_person_id, override_person_id, oldest_event, merged_at, 2] + assert the_rest == [ + 1, + old_person_id, + override_person_id, + oldest_event, + merged_at, + 2, + ] assert created_at > datetime.now(tz=ZoneInfo("UTC")) - timedelta(seconds=10) finally: producer.close() @@ -124,7 +131,8 @@ def test_person_overrides_dict(): sync_execute("INSERT INTO person_overrides (*) VALUES", [values]) sync_execute("SYSTEM RELOAD DICTIONARY person_overrides_dict") results = sync_execute( - "SELECT dictGet(person_overrides_dict, 'override_person_id', (%(team_id)s, %(old_person_id)s))", values + "SELECT dictGet(person_overrides_dict, 'override_person_id', (%(team_id)s, %(old_person_id)s))", + values, ) assert len(results) == 1 @@ -136,7 +144,8 @@ def test_person_overrides_dict(): sync_execute("INSERT INTO person_overrides (*) VALUES", [values]) sync_execute("SYSTEM RELOAD DICTIONARY person_overrides_dict") new_results = sync_execute( - "SELECT dictGet(person_overrides_dict, 'override_person_id', (%(team_id)s, %(old_person_id)s))", values + "SELECT dictGet(person_overrides_dict, 'override_person_id', (%(team_id)s, %(old_person_id)s))", + values, ) assert len(new_results) == 1 diff --git a/posthog/conftest.py b/posthog/conftest.py index 06e7e256aed79..2b819ff9390ad 100644 --- a/posthog/conftest.py +++ b/posthog/conftest.py @@ -11,7 +11,11 @@ def create_clickhouse_tables(num_tables: int): # Create clickhouse tables to default before running test # Mostly so that test runs locally work correctly - from posthog.clickhouse.schema import CREATE_DISTRIBUTED_TABLE_QUERIES, CREATE_MERGETREE_TABLE_QUERIES, build_query + from posthog.clickhouse.schema import ( + CREATE_DISTRIBUTED_TABLE_QUERIES, + CREATE_MERGETREE_TABLE_QUERIES, + build_query, + ) # REMEMBER TO ADD ANY NEW CLICKHOUSE TABLES TO THIS ARRAY! CREATE_TABLE_QUERIES: Tuple[Any, ...] = CREATE_MERGETREE_TABLE_QUERIES + CREATE_DISTRIBUTED_TABLE_QUERIES @@ -27,8 +31,12 @@ def create_clickhouse_tables(num_tables: int): def reset_clickhouse_tables(): # Truncate clickhouse tables to default before running test # Mostly so that test runs locally work correctly - from posthog.clickhouse.dead_letter_queue import TRUNCATE_DEAD_LETTER_QUEUE_TABLE_SQL - from posthog.clickhouse.plugin_log_entries import TRUNCATE_PLUGIN_LOG_ENTRIES_TABLE_SQL + from posthog.clickhouse.dead_letter_queue import ( + TRUNCATE_DEAD_LETTER_QUEUE_TABLE_SQL, + ) + from posthog.clickhouse.plugin_log_entries import ( + TRUNCATE_PLUGIN_LOG_ENTRIES_TABLE_SQL, + ) from posthog.models.app_metrics.sql import TRUNCATE_APP_METRICS_TABLE_SQL from posthog.models.cohort.sql import TRUNCATE_COHORTPEOPLE_TABLE_SQL from posthog.models.event.sql import TRUNCATE_EVENTS_TABLE_SQL @@ -40,7 +48,9 @@ def reset_clickhouse_tables(): TRUNCATE_PERSON_STATIC_COHORT_TABLE_SQL, TRUNCATE_PERSON_TABLE_SQL, ) - from posthog.session_recordings.sql.session_recording_event_sql import TRUNCATE_SESSION_RECORDING_EVENTS_TABLE_SQL + from posthog.session_recordings.sql.session_recording_event_sql import ( + TRUNCATE_SESSION_RECORDING_EVENTS_TABLE_SQL, + ) # REMEMBER TO ADD ANY NEW CLICKHOUSE TABLES TO THIS ARRAY! TABLES_TO_CREATE_DROP = [ @@ -80,7 +90,8 @@ def django_db_setup(django_db_setup, django_db_keepdb): database.create_database() # Create database if it doesn't exist table_count = sync_execute( - "SELECT count() FROM system.tables WHERE database = %(database)s", {"database": settings.CLICKHOUSE_DATABASE} + "SELECT count() FROM system.tables WHERE database = %(database)s", + {"database": settings.CLICKHOUSE_DATABASE}, )[0][0] create_clickhouse_tables(table_count) diff --git a/posthog/constants.py b/posthog/constants.py index 3beb8ca12b3b9..ecfeb03e1259f 100644 --- a/posthog/constants.py +++ b/posthog/constants.py @@ -55,7 +55,13 @@ class AvailableFeature(str, Enum): TRENDS_BOLD_NUMBER = "BoldNumber" # Sync with frontend NON_TIME_SERIES_DISPLAY_TYPES -NON_TIME_SERIES_DISPLAY_TYPES = [TRENDS_TABLE, TRENDS_PIE, TRENDS_BAR_VALUE, TRENDS_WORLD_MAP, TRENDS_BOLD_NUMBER] +NON_TIME_SERIES_DISPLAY_TYPES = [ + TRENDS_TABLE, + TRENDS_PIE, + TRENDS_BAR_VALUE, + TRENDS_WORLD_MAP, + TRENDS_BOLD_NUMBER, +] # Sync with frontend NON_BREAKDOWN_DISPLAY_TYPES NON_BREAKDOWN_DISPLAY_TYPES = [TRENDS_BOLD_NUMBER] diff --git a/posthog/demo/legacy/app_data_generator.py b/posthog/demo/legacy/app_data_generator.py index 51a12e3d486ff..56f7c3ebcecc2 100644 --- a/posthog/demo/legacy/app_data_generator.py +++ b/posthog/demo/legacy/app_data_generator.py @@ -50,7 +50,12 @@ def create_actions_dashboards(self): "order": 0, "type": TREND_FILTER_TYPE_ACTIONS, }, - {"id": rated_app_action.id, "name": "Rated App", "order": 1, "type": TREND_FILTER_TYPE_ACTIONS}, + { + "id": rated_app_action.id, + "name": "Rated App", + "order": 1, + "type": TREND_FILTER_TYPE_ACTIONS, + }, { "id": rated_app_action.id, "name": "Rated App", @@ -68,8 +73,16 @@ def create_actions_dashboards(self): def populate_person_events(self, person: Person, distinct_id: str, _index: int): start_day = random.randint(1, self.n_days) - self.add_event(event="$pageview", distinct_id=distinct_id, timestamp=now() - relativedelta(days=start_day)) - self.add_event(event="installed_app", distinct_id=distinct_id, timestamp=now() - relativedelta(days=start_day)) + self.add_event( + event="$pageview", + distinct_id=distinct_id, + timestamp=now() - relativedelta(days=start_day), + ) + self.add_event( + event="installed_app", + distinct_id=distinct_id, + timestamp=now() - relativedelta(days=start_day), + ) if random.randint(0, 10) <= 9: self.add_event( diff --git a/posthog/demo/legacy/data_generator.py b/posthog/demo/legacy/data_generator.py index 65bdd350acc88..ccc9f163e6c3c 100644 --- a/posthog/demo/legacy/data_generator.py +++ b/posthog/demo/legacy/data_generator.py @@ -3,7 +3,9 @@ from posthog.models import Person, PersonDistinctId, Team from posthog.models.utils import UUIDT -from posthog.session_recordings.queries.test.session_replay_sql import produce_replay_summary +from posthog.session_recordings.queries.test.session_replay_sql import ( + produce_replay_summary, +) class DataGenerator: diff --git a/posthog/demo/legacy/revenue_data_generator.py b/posthog/demo/legacy/revenue_data_generator.py index 641cd30f5250e..2fa4901389eb0 100644 --- a/posthog/demo/legacy/revenue_data_generator.py +++ b/posthog/demo/legacy/revenue_data_generator.py @@ -29,7 +29,9 @@ def create_missing_events_and_properties(self): def populate_person_events(self, person: Person, distinct_id: str, index: int): if random.randint(0, 10) <= 4: self.add_event( - event="entered_free_trial", distinct_id=distinct_id, timestamp=now() - relativedelta(days=345) + event="entered_free_trial", + distinct_id=distinct_id, + timestamp=now() - relativedelta(days=345), ) self.add_event( @@ -68,7 +70,14 @@ def create_actions_dashboards(self): team=self.team, name="Entered Free Trial -> Purchase (Premium)", filters={ - "events": [{"id": "$pageview", "name": "Pageview", "order": 0, "type": TREND_FILTER_TYPE_ACTIONS}], + "events": [ + { + "id": "$pageview", + "name": "Pageview", + "order": 0, + "type": TREND_FILTER_TYPE_ACTIONS, + } + ], "actions": [ { "id": purchase_action.id, diff --git a/posthog/demo/legacy/web_data_generator.py b/posthog/demo/legacy/web_data_generator.py index e74ddc53bfe99..aa0836d3db732 100644 --- a/posthog/demo/legacy/web_data_generator.py +++ b/posthog/demo/legacy/web_data_generator.py @@ -7,7 +7,15 @@ from django.utils.timezone import now from posthog.constants import TREND_FILTER_TYPE_ACTIONS -from posthog.models import Action, ActionStep, Dashboard, DashboardTile, Insight, Person, PropertyDefinition +from posthog.models import ( + Action, + ActionStep, + Dashboard, + DashboardTile, + Insight, + Person, + PropertyDefinition, +) from posthog.models.filters.mixins.utils import cached_property from posthog.models.utils import UUIDT from posthog.utils import get_absolute_path @@ -27,7 +35,12 @@ def create_missing_events_and_properties(self): def create_actions_dashboards(self): homepage = Action.objects.create(team=self.team, name="Hogflix homepage view") - ActionStep.objects.create(action=homepage, event="$pageview", url="http://hogflix.com", url_matching="exact") + ActionStep.objects.create( + action=homepage, + event="$pageview", + url="http://hogflix.com", + url_matching="exact", + ) user_signed_up = Action.objects.create(team=self.team, name="Hogflix signed up") ActionStep.objects.create( @@ -54,14 +67,24 @@ def create_actions_dashboards(self): description="Shows a conversion funnel from sign up to watching a movie.", filters={ "actions": [ - {"id": homepage.id, "name": "Hogflix homepage view", "order": 0, "type": TREND_FILTER_TYPE_ACTIONS}, + { + "id": homepage.id, + "name": "Hogflix homepage view", + "order": 0, + "type": TREND_FILTER_TYPE_ACTIONS, + }, { "id": user_signed_up.id, "name": "Hogflix signed up", "order": 1, "type": TREND_FILTER_TYPE_ACTIONS, }, - {"id": user_paid.id, "name": "Hogflix paid", "order": 2, "type": TREND_FILTER_TYPE_ACTIONS}, + { + "id": user_paid.id, + "name": "Hogflix paid", + "order": 2, + "type": TREND_FILTER_TYPE_ACTIONS, + }, ], "insight": "FUNNELS", }, @@ -77,7 +100,11 @@ def populate_person_events(self, person: Person, distinct_id: str, index: int): event="$pageview", distinct_id=distinct_id, timestamp=now() - relativedelta(days=start_day), - properties={"$current_url": "http://hogflix.com", "$browser": browser, "$lib": "web"}, + properties={ + "$current_url": "http://hogflix.com", + "$browser": browser, + "$lib": "web", + }, ) self.add_event( @@ -107,7 +134,11 @@ def populate_person_events(self, person: Person, distinct_id: str, index: int): self.add_event( event="$pageview", distinct_id=distinct_id, - properties={"$current_url": "http://hogflix.com/2", "$browser": browser, "$lib": "web"}, + properties={ + "$current_url": "http://hogflix.com/2", + "$browser": browser, + "$lib": "web", + }, timestamp=now() - relativedelta(days=start_day) + relativedelta(seconds=30), ) if index % 5 == 0: @@ -131,7 +162,11 @@ def populate_person_events(self, person: Person, distinct_id: str, index: int): self.add_event( event="$pageview", distinct_id=distinct_id, - properties={"$current_url": "http://hogflix.com/3", "$browser": browser, "$lib": "web"}, + properties={ + "$current_url": "http://hogflix.com/3", + "$browser": browser, + "$lib": "web", + }, timestamp=now() - relativedelta(days=start_day) + relativedelta(seconds=60), ) diff --git a/posthog/demo/matrix/manager.py b/posthog/demo/matrix/manager.py index 8b13bd78c2b24..c174b2c782bc9 100644 --- a/posthog/demo/matrix/manager.py +++ b/posthog/demo/matrix/manager.py @@ -66,7 +66,12 @@ def ensure_account_and_save( with transaction.atomic(): organization = Organization.objects.create(**organization_kwargs) new_user = User.objects.create_and_join( - organization, email, password, first_name, OrganizationMembership.Level.ADMIN, is_staff=is_staff + organization, + email, + password, + first_name, + OrganizationMembership.Level.ADMIN, + is_staff=is_staff, ) team = self.create_team(organization) self.run_on_team(team, new_user) @@ -99,7 +104,11 @@ def reset_master(self): @staticmethod def create_team(organization: Organization, **kwargs) -> Team: team = Team.objects.create( - organization=organization, ingested_event=True, completed_snippet_onboarding=True, is_demo=True, **kwargs + organization=organization, + ingested_event=True, + completed_snippet_onboarding=True, + is_demo=True, + **kwargs, ) return team @@ -132,11 +141,19 @@ def _save_analytics_data(self, data_team: Team): for group_type_index, (group_type, groups) in enumerate(self.matrix.groups.items()): group_type_index += self.matrix.group_type_index_offset # Adjust bulk_group_type_mappings.append( - GroupTypeMapping(team=data_team, group_type_index=group_type_index, group_type=group_type) + GroupTypeMapping( + team=data_team, + group_type_index=group_type_index, + group_type=group_type, + ) ) for group_key, group in groups.items(): self._save_sim_group( - data_team, cast(Literal[0, 1, 2, 3, 4], group_type_index), group_key, group, self.matrix.now + data_team, + cast(Literal[0, 1, 2, 3, 4], group_type_index), + group_key, + group, + self.matrix.now, ) try: GroupTypeMapping.objects.bulk_create(bulk_group_type_mappings) @@ -164,16 +181,28 @@ def _create_master_team(cls) -> Team: @classmethod def _erase_master_team_data(cls): AsyncEventDeletion().process( - [AsyncDeletion(team_id=cls.MASTER_TEAM_ID, key=cls.MASTER_TEAM_ID, deletion_type=DeletionType.Team)] + [ + AsyncDeletion( + team_id=cls.MASTER_TEAM_ID, + key=cls.MASTER_TEAM_ID, + deletion_type=DeletionType.Team, + ) + ] ) GroupTypeMapping.objects.filter(team_id=cls.MASTER_TEAM_ID).delete() def _copy_analytics_data_from_master_team(self, target_team: Team): from posthog.models.event.sql import COPY_EVENTS_BETWEEN_TEAMS from posthog.models.group.sql import COPY_GROUPS_BETWEEN_TEAMS - from posthog.models.person.sql import COPY_PERSON_DISTINCT_ID2S_BETWEEN_TEAMS, COPY_PERSONS_BETWEEN_TEAMS + from posthog.models.person.sql import ( + COPY_PERSON_DISTINCT_ID2S_BETWEEN_TEAMS, + COPY_PERSONS_BETWEEN_TEAMS, + ) - copy_params = {"source_team_id": self.MASTER_TEAM_ID, "target_team_id": target_team.pk} + copy_params = { + "source_team_id": self.MASTER_TEAM_ID, + "target_team_id": target_team.pk, + } sync_execute(COPY_PERSONS_BETWEEN_TEAMS, copy_params) sync_execute(COPY_PERSON_DISTINCT_ID2S_BETWEEN_TEAMS, copy_params) sync_execute(COPY_EVENTS_BETWEEN_TEAMS, copy_params) @@ -191,7 +220,10 @@ def _copy_analytics_data_from_master_team(self, target_team: Team): @classmethod def _sync_postgres_with_clickhouse_data(cls, source_team_id: int, target_team_id: int): from posthog.models.group.sql import SELECT_GROUPS_OF_TEAM - from posthog.models.person.sql import SELECT_PERSON_DISTINCT_ID2S_OF_TEAM, SELECT_PERSONS_OF_TEAM + from posthog.models.person.sql import ( + SELECT_PERSON_DISTINCT_ID2S_OF_TEAM, + SELECT_PERSONS_OF_TEAM, + ) list_params = {"source_team_id": source_team_id} # Persons @@ -220,7 +252,11 @@ def _sync_postgres_with_clickhouse_data(cls, source_team_id: int, target_team_id person_uuid = row.pop("person_uuid") try: bulk_person_distinct_ids.append( - PersonDistinctId(team_id=target_team_id, person_id=bulk_persons[person_uuid].pk, **row) + PersonDistinctId( + team_id=target_team_id, + person_id=bulk_persons[person_uuid].pk, + **row, + ) ) except KeyError: pre_existing_id_count -= 1 @@ -232,7 +268,14 @@ def _sync_postgres_with_clickhouse_data(cls, source_team_id: int, target_team_id bulk_groups = [] for row in clickhouse_groups: group_properties = json.loads(row.pop("group_properties", "{}")) - bulk_groups.append(Group(team_id=target_team_id, version=0, group_properties=group_properties, **row)) + bulk_groups.append( + Group( + team_id=target_team_id, + version=0, + group_properties=group_properties, + **row, + ) + ) try: Group.objects.bulk_create(bulk_groups) except IntegrityError as e: @@ -241,16 +284,24 @@ def _sync_postgres_with_clickhouse_data(cls, source_team_id: int, target_team_id def _save_sim_person(self, team: Team, subject: SimPerson): # We only want to save directly if there are past events if subject.past_events: - from posthog.models.person.util import create_person, create_person_distinct_id + from posthog.models.person.util import ( + create_person, + create_person_distinct_id, + ) create_person( - uuid=str(subject.in_posthog_id), team_id=team.pk, properties=subject.properties_at_now, version=0 + uuid=str(subject.in_posthog_id), + team_id=team.pk, + properties=subject.properties_at_now, + version=0, ) self._persons_created += 1 self._person_distinct_ids_created += len(subject.distinct_ids_at_now) for distinct_id in subject.distinct_ids_at_now: create_person_distinct_id( - team_id=team.pk, distinct_id=str(distinct_id), person_id=str(subject.in_posthog_id) + team_id=team.pk, + distinct_id=str(distinct_id), + person_id=str(subject.in_posthog_id), ) self._save_past_sim_events(team, subject.past_events) # We only want to queue future events if there are any @@ -294,14 +345,21 @@ def _save_future_sim_events(team: Team, events: List[SimEvent]): @staticmethod def _save_sim_group( - team: Team, type_index: Literal[0, 1, 2, 3, 4], key: str, properties: Dict[str, Any], timestamp: dt.datetime + team: Team, + type_index: Literal[0, 1, 2, 3, 4], + key: str, + properties: Dict[str, Any], + timestamp: dt.datetime, ): from posthog.models.group.util import raw_create_group_ch raw_create_group_ch(team.pk, type_index, key, properties, timestamp) def _sleep_until_person_data_in_clickhouse(self, team_id: int): - from posthog.models.person.sql import GET_PERSON_COUNT_FOR_TEAM, GET_PERSON_DISTINCT_ID2_COUNT_FOR_TEAM + from posthog.models.person.sql import ( + GET_PERSON_COUNT_FOR_TEAM, + GET_PERSON_DISTINCT_ID2_COUNT_FOR_TEAM, + ) while True: person_count: int = sync_execute(GET_PERSON_COUNT_FOR_TEAM, {"team_id": team_id})[0][0] diff --git a/posthog/demo/matrix/matrix.py b/posthog/demo/matrix/matrix.py index 1a080057a0ceb..d94988bc4210d 100644 --- a/posthog/demo/matrix/matrix.py +++ b/posthog/demo/matrix/matrix.py @@ -72,7 +72,12 @@ def __init__(self, *, index: int, matrix: "Matrix") -> None: self.radius = int(self.MIN_RADIUS + self.radius_distribution() * (self.MAX_RADIUS - self.MIN_RADIUS)) self.people_matrix = [ [ - matrix.PERSON_CLASS(kernel=(x == self.radius and y == self.radius), x=x, y=y, cluster=self) + matrix.PERSON_CLASS( + kernel=(x == self.radius and y == self.radius), + x=x, + y=y, + cluster=self, + ) for x in range(1 + self.radius * 2) ] for y in range(1 + self.radius * 2) diff --git a/posthog/demo/matrix/models.py b/posthog/demo/matrix/models.py index fbb1dff7f98ff..a2e7796518914 100644 --- a/posthog/demo/matrix/models.py +++ b/posthog/demo/matrix/models.py @@ -181,7 +181,11 @@ class SimBrowserClient(SimClient): def __init__(self, person: "SimPerson"): self.person = person self.matrix = person.cluster.matrix - self.device_type, self.os, self.browser = self.person.cluster.properties_provider.device_type_os_browser() + ( + self.device_type, + self.os, + self.browser, + ) = self.person.cluster.properties_provider.device_type_os_browser() self.device_id = str(UUID(int=self.person.cluster.random.getrandbits(128))) self.active_distinct_id = self.device_id # Pre-`$identify`, the device ID is used as the distinct ID self.active_session_id = None @@ -223,7 +227,10 @@ def capture(self, event: str, properties: Optional[Properties] = None): if properties: if referrer := properties.get("$referrer"): referring_domain = urlparse(referrer).netloc if referrer != "$direct" else referrer - referrer_properties = {"$referrer": referrer, "$referring_domain": referring_domain} + referrer_properties = { + "$referrer": referrer, + "$referring_domain": referring_domain, + } self.register(referrer_properties) combined_properties["$set"].update(referrer_properties) combined_properties["$referring_domain"] = referring_domain @@ -235,7 +242,11 @@ def capture(self, event: str, properties: Optional[Properties] = None): super()._capture_raw(event, combined_properties, distinct_id=self.active_distinct_id) def capture_pageview( - self, current_url: str, properties: Optional[Properties] = None, *, referrer: Optional[str] = None + self, + current_url: str, + properties: Optional[Properties] = None, + *, + referrer: Optional[str] = None, ): """Capture a $pageview event. $pageleave is handled implicitly.""" if self.current_url is not None: @@ -259,14 +270,24 @@ def identify(self, distinct_id: Optional[str], set_properties: Optional[Properti self.active_distinct_id = distinct_id self.capture(EVENT_IDENTIFY, identify_properties) - def group(self, group_type: str, group_key: str, set_properties: Optional[Properties] = None): + def group( + self, + group_type: str, + group_key: str, + set_properties: Optional[Properties] = None, + ): """Link the person to the specified group. Similar to JS `posthog.group()`.""" if set_properties is None: set_properties = {} self.person._groups[group_type] = group_key self.person.cluster.matrix._update_group(group_type, group_key, set_properties) self.capture( - EVENT_GROUP_IDENTIFY, {"$group_type": group_type, "$group_key": group_key, "$group_set": set_properties} + EVENT_GROUP_IDENTIFY, + { + "$group_type": group_type, + "$group_key": group_key, + "$group_set": set_properties, + }, ) def reset(self): @@ -404,7 +425,13 @@ def schedule_effect( An effect is a function that runs on the person, so it can change the person's state.""" self.cluster.raw_schedule_effect( - Effect(timestamp=timestamp, callback=callback, source=self, target=target, condition=condition) + Effect( + timestamp=timestamp, + callback=callback, + source=self, + target=target, + condition=condition, + ) ) # Person state @@ -423,7 +450,14 @@ def move_attribute(self, attr: str, delta: float) -> Literal[True]: setattr(self, attr, getattr(self, attr) + delta) return True - def _append_event(self, event: str, properties: Properties, *, distinct_id: str, timestamp: dt.datetime): + def _append_event( + self, + event: str, + properties: Properties, + *, + distinct_id: str, + timestamp: dt.datetime, + ): """Append event to `past_events` or `future_events`, whichever is appropriate.""" if self.in_posthog_id is None: self.in_posthog_id = self.cluster.roll_uuidt() diff --git a/posthog/demo/matrix/randomization.py b/posthog/demo/matrix/randomization.py index c0d6a8edb6bb3..ca6bcfd588640 100644 --- a/posthog/demo/matrix/randomization.py +++ b/posthog/demo/matrix/randomization.py @@ -23,19 +23,28 @@ class Industry(str, Enum): class PropertiesProvider(mimesis.BaseProvider): # Somewhat realistically segmented and weighted pools for random properties: device type/OS/browser - DEVICE_TYPE_WEIGHTED_POOL: WeightedPool = (["Desktop", "Mobile", "Tablet"], [8, 1, 1]) + DEVICE_TYPE_WEIGHTED_POOL: WeightedPool = ( + ["Desktop", "Mobile", "Tablet"], + [8, 1, 1], + ) OS_WEIGHTED_POOLS: Dict[str, WeightedPool] = { "Desktop": (["Windows", "Mac OS X", "Linux", "Chrome OS"], [18, 16, 7, 1]), "Mobile": (["iOS", "Android"], [1, 1]), "Tablet": (["iOS", "Android"], [1, 1]), } BROWSER_WEIGHTED_POOLS: Dict[str, WeightedPool] = { - "Windows": (["Chrome", "Firefox", "Opera", "Microsoft Edge", "Internet Explorer"], [12, 4, 2, 1, 1]), + "Windows": ( + ["Chrome", "Firefox", "Opera", "Microsoft Edge", "Internet Explorer"], + [12, 4, 2, 1, 1], + ), "Mac OS X": (["Chrome", "Firefox", "Opera", "Safari"], [4, 2, 1, 2]), "Linux": (["Chrome", "Firefox", "Opera"], [3, 3, 1]), "Chrome OS": (["Chrome"], [1]), "iOS": (["Mobile Safari", "Chrome iOS", "Firefox iOS"], [8, 1, 1]), - "Android": (["Chrome", "Android Mobile", "Samsung Internet", "Firefox"], [5, 3, 3, 1]), + "Android": ( + ["Chrome", "Android Mobile", "Samsung Internet", "Firefox"], + [5, 3, 3, 1], + ), } INDUSTRY_POOL = ( diff --git a/posthog/demo/products/hedgebox/matrix.py b/posthog/demo/products/hedgebox/matrix.py index ed863556ecbf4..5c169ad0afd28 100644 --- a/posthog/demo/products/hedgebox/matrix.py +++ b/posthog/demo/products/hedgebox/matrix.py @@ -4,7 +4,13 @@ from django.db import IntegrityError -from posthog.constants import INSIGHT_TRENDS, PAGEVIEW_EVENT, RETENTION_FIRST_TIME, TRENDS_LINEAR, TRENDS_WORLD_MAP +from posthog.constants import ( + INSIGHT_TRENDS, + PAGEVIEW_EVENT, + RETENTION_FIRST_TIME, + TRENDS_LINEAR, + TRENDS_WORLD_MAP, +) from posthog.demo.matrix.matrix import Cluster, Matrix from posthog.demo.matrix.randomization import Industry from posthog.models import ( @@ -46,7 +52,8 @@ def __init__(self, *args, **kwargs): is_company = self.random.random() < COMPANY_CLUSTERS_PROPORTION if is_company: self.company = HedgdboxCompany( - name=self.finance_provider.company(), industry=self.properties_provider.industry() + name=self.finance_provider.company(), + industry=self.properties_provider.industry(), ) else: self.company = None @@ -81,7 +88,10 @@ def set_project_up(self, team, user): # Actions interacted_with_file_action = Action.objects.create( - name="Interacted with file", team=team, description="Logged-in interaction with a file.", created_by=user + name="Interacted with file", + team=team, + description="Logged-in interaction with a file.", + created_by=user, ) ActionStep.objects.bulk_create( ( @@ -97,7 +107,18 @@ def set_project_up(self, team, user): team=team, name="Signed-up users", created_by=user, - groups=[{"properties": [{"key": "email", "type": "person", "value": "is_set", "operator": "is_set"}]}], + groups=[ + { + "properties": [ + { + "key": "email", + "type": "person", + "value": "is_set", + "operator": "is_set", + } + ] + } + ], ) real_users_cohort = Cohort.objects.create( team=team, @@ -105,14 +126,26 @@ def set_project_up(self, team, user): description="People who don't belong to the Hedgebox team.", created_by=user, groups=[ - {"properties": [{"key": "email", "type": "person", "value": "@hedgebox.net$", "operator": "not_regex"}]} + { + "properties": [ + { + "key": "email", + "type": "person", + "value": "@hedgebox.net$", + "operator": "not_regex", + } + ] + } ], ) team.test_account_filters = [{"key": "id", "type": "cohort", "value": real_users_cohort.pk}] # Dashboard: Key metrics (project home) key_metrics_dashboard = Dashboard.objects.create( - team=team, name="🔑 Key metrics", description="Company overview.", pinned=True + team=team, + name="🔑 Key metrics", + description="Company overview.", + pinned=True, ) team.primary_dashboard = key_metrics_dashboard weekly_signups_insight = Insight.objects.create( @@ -137,7 +170,16 @@ def set_project_up(self, team, user): color="blue", layouts={ "sm": {"h": 5, "w": 6, "x": 0, "y": 0, "minH": 5, "minW": 3}, - "xs": {"h": 5, "w": 1, "x": 0, "y": 0, "minH": 5, "minW": 3, "moved": False, "static": False}, + "xs": { + "h": 5, + "w": 1, + "x": 0, + "y": 0, + "minH": 5, + "minW": 3, + "moved": False, + "static": False, + }, }, ) signups_by_country_insight = Insight.objects.create( @@ -162,7 +204,16 @@ def set_project_up(self, team, user): insight=signups_by_country_insight, layouts={ "sm": {"h": 5, "w": 6, "x": 6, "y": 0, "minH": 5, "minW": 3}, - "xs": {"h": 5, "w": 1, "x": 0, "y": 5, "minH": 5, "minW": 3, "moved": False, "static": False}, + "xs": { + "h": 5, + "w": 1, + "x": 0, + "y": 5, + "minH": 5, + "minW": 3, + "moved": False, + "static": False, + }, }, ) activation_funnel = Insight.objects.create( @@ -210,7 +261,16 @@ def set_project_up(self, team, user): insight=activation_funnel, layouts={ "sm": {"h": 5, "w": 6, "x": 0, "y": 5, "minH": 5, "minW": 3}, - "xs": {"h": 5, "w": 1, "x": 0, "y": 10, "minH": 5, "minW": 3, "moved": False, "static": False}, + "xs": { + "h": 5, + "w": 1, + "x": 0, + "y": 10, + "minH": 5, + "minW": 3, + "moved": False, + "static": False, + }, }, ) new_user_retention = Insight.objects.create( @@ -227,11 +287,23 @@ def set_project_up(self, team, user): "values": [ { "type": "AND", - "values": [{"key": "email", "type": "person", "value": "is_set", "operator": "is_set"}], + "values": [ + { + "key": "email", + "type": "person", + "value": "is_set", + "operator": "is_set", + } + ], } ], }, - "target_entity": {"id": EVENT_SIGNED_UP, "name": EVENT_SIGNED_UP, "type": "events", "order": 0}, + "target_entity": { + "id": EVENT_SIGNED_UP, + "name": EVENT_SIGNED_UP, + "type": "events", + "order": 0, + }, "retention_type": RETENTION_FIRST_TIME, "total_intervals": 9, "returning_entity": { @@ -249,7 +321,16 @@ def set_project_up(self, team, user): insight=new_user_retention, layouts={ "sm": {"h": 5, "w": 6, "x": 6, "y": 5, "minH": 5, "minW": 3}, - "xs": {"h": 5, "w": 1, "x": 0, "y": 15, "minH": 5, "minW": 3, "moved": False, "static": False}, + "xs": { + "h": 5, + "w": 1, + "x": 0, + "y": 15, + "minH": 5, + "minW": 3, + "moved": False, + "static": False, + }, }, ) active_user_lifecycle = Insight.objects.create( @@ -287,7 +368,16 @@ def set_project_up(self, team, user): insight=active_user_lifecycle, layouts={ "sm": {"h": 5, "w": 6, "x": 0, "y": 10, "minH": 5, "minW": 3}, - "xs": {"h": 5, "w": 1, "x": 0, "y": 20, "minH": 5, "minW": 3, "moved": False, "static": False}, + "xs": { + "h": 5, + "w": 1, + "x": 0, + "y": 20, + "minH": 5, + "minW": 3, + "moved": False, + "static": False, + }, }, ) weekly_file_volume = Insight.objects.create( @@ -333,7 +423,16 @@ def set_project_up(self, team, user): insight=weekly_file_volume, layouts={ "sm": {"h": 5, "w": 6, "x": 6, "y": 10, "minH": 5, "minW": 3}, - "xs": {"h": 5, "w": 1, "x": 0, "y": 25, "minH": 5, "minW": 3, "moved": False, "static": False}, + "xs": { + "h": 5, + "w": 1, + "x": 0, + "y": 25, + "minH": 5, + "minW": 3, + "moved": False, + "static": False, + }, }, ) @@ -346,7 +445,13 @@ def set_project_up(self, team, user): name="Monthly app revenue", filters={ "events": [ - {"id": EVENT_PAID_BILL, "type": "events", "order": 0, "math": "sum", "math_property": "amount_usd"} + { + "id": EVENT_PAID_BILL, + "type": "events", + "order": 0, + "math": "sum", + "math_property": "amount_usd", + } ], "actions": [], "display": TRENDS_LINEAR, @@ -362,7 +467,16 @@ def set_project_up(self, team, user): insight=monthly_app_revenue_trends, layouts={ "sm": {"h": 5, "w": 6, "x": 0, "y": 0, "minH": 5, "minW": 3}, - "xs": {"h": 5, "w": 1, "x": 0, "y": 0, "minH": 5, "minW": 3, "moved": False, "static": False}, + "xs": { + "h": 5, + "w": 1, + "x": 0, + "y": 0, + "minH": 5, + "minW": 3, + "moved": False, + "static": False, + }, }, ) bills_paid_trends = Insight.objects.create( @@ -399,7 +513,16 @@ def set_project_up(self, team, user): insight=bills_paid_trends, layouts={ "sm": {"h": 5, "w": 6, "x": 6, "y": 0, "minH": 5, "minW": 3}, - "xs": {"h": 5, "w": 1, "x": 0, "y": 5, "minH": 5, "minW": 3, "moved": False, "static": False}, + "xs": { + "h": 5, + "w": 1, + "x": 0, + "y": 5, + "minH": 5, + "minW": 3, + "moved": False, + "static": False, + }, }, ) @@ -426,7 +549,16 @@ def set_project_up(self, team, user): insight=daily_unique_visitors_trends, layouts={ "sm": {"h": 5, "w": 6, "x": 0, "y": 0, "minH": 5, "minW": 3}, - "xs": {"h": 5, "w": 1, "x": 0, "y": 0, "minH": 5, "minW": 3, "moved": False, "static": False}, + "xs": { + "h": 5, + "w": 1, + "x": 0, + "y": 0, + "minH": 5, + "minW": 3, + "moved": False, + "static": False, + }, }, ) most_popular_pages_trends = Insight.objects.create( @@ -435,7 +567,14 @@ def set_project_up(self, team, user): saved=True, name="Most popular pages", filters={ - "events": [{"id": PAGEVIEW_EVENT, "math": "total", "type": "events", "order": 0}], + "events": [ + { + "id": PAGEVIEW_EVENT, + "math": "total", + "type": "events", + "order": 0, + } + ], "actions": [], "display": "ActionsTable", "insight": "TRENDS", @@ -469,7 +608,16 @@ def set_project_up(self, team, user): insight=most_popular_pages_trends, layouts={ "sm": {"h": 5, "w": 6, "x": 6, "y": 0, "minH": 5, "minW": 3}, - "xs": {"h": 5, "w": 1, "x": 0, "y": 5, "minH": 5, "minW": 3, "moved": False, "static": False}, + "xs": { + "h": 5, + "w": 1, + "x": 0, + "y": 5, + "minH": 5, + "minW": 3, + "moved": False, + "static": False, + }, }, ) @@ -487,7 +635,12 @@ def set_project_up(self, team, user): "type": "events", "order": 0, "properties": [ - {"key": "$current_url", "type": "event", "value": URL_HOME, "operator": "exact"} + { + "key": "$current_url", + "type": "event", + "value": URL_HOME, + "operator": "exact", + } ], }, { @@ -497,10 +650,21 @@ def set_project_up(self, team, user): "type": "events", "order": 1, "properties": [ - {"key": "$current_url", "type": "event", "value": URL_SIGNUP, "operator": "regex"} + { + "key": "$current_url", + "type": "event", + "value": URL_SIGNUP, + "operator": "regex", + } ], }, - {"custom_name": "Signed up", "id": "signed_up", "name": "signed_up", "type": "events", "order": 2}, + { + "custom_name": "Signed up", + "id": "signed_up", + "name": "signed_up", + "type": "events", + "order": 2, + }, ], "actions": [], "display": "FunnelViz", @@ -563,7 +727,11 @@ def set_project_up(self, team, user): user=user, insight=insight, last_viewed_at=( - self.now - dt.timedelta(days=self.random.randint(0, 3), minutes=self.random.randint(5, 60)) + self.now + - dt.timedelta( + days=self.random.randint(0, 3), + minutes=self.random.randint(5, 60), + ) ), ) for insight in Insight.objects.filter(team=team) @@ -610,8 +778,14 @@ def set_project_up(self, team, user): "groups": [{"properties": [], "rollout_percentage": None}], "multivariate": { "variants": [ - {"key": "control", "rollout_percentage": 100 - NEW_SIGNUP_PAGE_FLAG_ROLLOUT_PERCENT}, - {"key": "test", "rollout_percentage": NEW_SIGNUP_PAGE_FLAG_ROLLOUT_PERCENT}, + { + "key": "control", + "rollout_percentage": 100 - NEW_SIGNUP_PAGE_FLAG_ROLLOUT_PERCENT, + }, + { + "key": "test", + "rollout_percentage": NEW_SIGNUP_PAGE_FLAG_ROLLOUT_PERCENT, + }, ] }, }, @@ -632,10 +806,20 @@ def set_project_up(self, team, user): "type": "events", "order": 0, "properties": [ - {"key": "$current_url", "type": "event", "value": URL_SIGNUP, "operator": "exact"} + { + "key": "$current_url", + "type": "event", + "value": URL_SIGNUP, + "operator": "exact", + } ], }, - {"id": "signed_up", "name": "signed_up", "type": "events", "order": 1}, + { + "id": "signed_up", + "name": "signed_up", + "type": "events", + "order": 1, + }, ], "actions": [], "display": "FunnelViz", @@ -646,8 +830,14 @@ def set_project_up(self, team, user): }, parameters={ "feature_flag_variants": [ - {"key": "control", "rollout_percentage": 100 - NEW_SIGNUP_PAGE_FLAG_ROLLOUT_PERCENT}, - {"key": "test", "rollout_percentage": NEW_SIGNUP_PAGE_FLAG_ROLLOUT_PERCENT}, + { + "key": "control", + "rollout_percentage": 100 - NEW_SIGNUP_PAGE_FLAG_ROLLOUT_PERCENT, + }, + { + "key": "test", + "rollout_percentage": NEW_SIGNUP_PAGE_FLAG_ROLLOUT_PERCENT, + }, ], "recommended_sample_size": int(len(self.clusters) * 0.274), "recommended_running_time": None, diff --git a/posthog/demo/products/hedgebox/models.py b/posthog/demo/products/hedgebox/models.py index 132f3d6ac5f32..1c0a0e4ffd0da 100644 --- a/posthog/demo/products/hedgebox/models.py +++ b/posthog/demo/products/hedgebox/models.py @@ -279,9 +279,18 @@ def determine_session_intent(self) -> Optional[HedgeboxSessionIntent]: # The more files, the more likely to delete/download/share rather than upload possible_intents_with_weights.extend( [ - (HedgeboxSessionIntent.DELETE_FILE_S, math.log10(file_count) / 8 if file_count else 0), - (HedgeboxSessionIntent.DOWNLOAD_OWN_FILE_S, math.log10(file_count + 1) if file_count else 0), - (HedgeboxSessionIntent.SHARE_FILE, math.log10(file_count) / 3 if file_count else 0), + ( + HedgeboxSessionIntent.DELETE_FILE_S, + math.log10(file_count) / 8 if file_count else 0, + ), + ( + HedgeboxSessionIntent.DOWNLOAD_OWN_FILE_S, + math.log10(file_count + 1) if file_count else 0, + ), + ( + HedgeboxSessionIntent.SHARE_FILE, + math.log10(file_count) / 3 if file_count else 0, + ), ] ) if self.account.allocation_used_fraction < 0.99: @@ -304,7 +313,8 @@ def determine_session_intent(self) -> Optional[HedgeboxSessionIntent]: if possible_intents_with_weights: possible_intents, weights = zip(*possible_intents_with_weights) return self.cluster.random.choices( - cast(Tuple[HedgeboxSessionIntent], possible_intents), cast(Tuple[float], weights) + cast(Tuple[HedgeboxSessionIntent], possible_intents), + cast(Tuple[float], weights), )[0] else: return None @@ -526,7 +536,10 @@ def go_to_shared_file(self, file: HedgeboxFile): self.active_client.capture_pageview(dyn_url_file(file.id)) self.advance_timer(0.5 + self.cluster.random.betavariate(1.2, 1.6) * 20) if self.cluster.random.random() < 0.7: - self.active_client.capture(EVENT_DOWNLOADED_FILE, {"file_type": file.type, "file_size_b": file.size_b}) + self.active_client.capture( + EVENT_DOWNLOADED_FILE, + {"file_type": file.type, "file_size_b": file.size_b}, + ) self.advance_timer(0.5 + self.cluster.random.betavariate(1.2, 2) * 80) self.need += (self.cluster.random.betavariate(1.2, 1) - 0.5) * 0.08 if self.cluster.random.random() < 0.2: @@ -537,13 +550,20 @@ def go_to_account_settings(self): self.advance_timer(1 + self.cluster.random.betavariate(1.2, 1.2) * 5) random = self.cluster.random.random() if ( - self.active_session_intent in (HedgeboxSessionIntent.UPGRADE_PLAN, HedgeboxSessionIntent.DOWNGRADE_PLAN) + self.active_session_intent + in ( + HedgeboxSessionIntent.UPGRADE_PLAN, + HedgeboxSessionIntent.DOWNGRADE_PLAN, + ) or random < 0.1 ): self.go_to_account_billing() elif ( self.active_session_intent - in (HedgeboxSessionIntent.INVITE_TEAM_MEMBER, HedgeboxSessionIntent.REMOVE_TEAM_MEMBER) + in ( + HedgeboxSessionIntent.INVITE_TEAM_MEMBER, + HedgeboxSessionIntent.REMOVE_TEAM_MEMBER, + ) or random < 0.1 ): self.go_to_account_team() @@ -609,7 +629,11 @@ def join_team(self): raise ValueError("Cannot join team without an account") self.active_client.capture(EVENT_SIGNED_UP, {"from_invite": True}) self.advance_timer(self.cluster.random.uniform(0.1, 0.2)) - self.active_client.group(GROUP_TYPE_ACCOUNT, self.account.id, {"team_size": len(self.account.team_members)}) + self.active_client.group( + GROUP_TYPE_ACCOUNT, + self.account.id, + {"team_size": len(self.account.team_members)}, + ) self.account.team_members.add(self) def upload_file(self, file: HedgeboxFile): @@ -618,12 +642,19 @@ def upload_file(self, file: HedgeboxFile): self.account.files.add(file) self.active_client.capture( EVENT_UPLOADED_FILE, - properties={"file_type": file.type, "file_size_b": file.size_b, "used_mb": self.account.current_used_mb}, + properties={ + "file_type": file.type, + "file_size_b": file.size_b, + "used_mb": self.account.current_used_mb, + }, ) self.active_client.group( GROUP_TYPE_ACCOUNT, self.account.id, - {"used_mb": self.account.current_used_mb, "file_count": len(self.account.files)}, + { + "used_mb": self.account.current_used_mb, + "file_count": len(self.account.files), + }, ) self.satisfaction += self.cluster.random.uniform(-0.19, 0.2) if self.satisfaction > 0.9: @@ -643,7 +674,10 @@ def delete_file(self, file: HedgeboxFile): self.active_client.group( GROUP_TYPE_ACCOUNT, self.account.id, - {"used_mb": self.account.current_used_mb, "file_count": len(self.account.files)}, + { + "used_mb": self.account.current_used_mb, + "file_count": len(self.account.files), + }, ) def share_file(self, file: HedgeboxFile): @@ -662,7 +696,8 @@ def upgrade_plan(self): if new_plan is None: raise ValueError("There's no successor plan") self.active_client.capture( - EVENT_UPGRADED_PLAN, {"previous_plan": str(previous_plan), "new_plan": str(new_plan)} + EVENT_UPGRADED_PLAN, + {"previous_plan": str(previous_plan), "new_plan": str(new_plan)}, ) self.advance_timer(self.cluster.random.betavariate(1.2, 1.2) * 2) self.schedule_effect( @@ -678,7 +713,11 @@ def upgrade_plan(self): ) for i in range(future_months): bill_timestamp = self.cluster.simulation_time + dt.timedelta(days=30 * i) - self.schedule_effect(bill_timestamp, lambda person: person.bill_account(), Effect.Target.SELF) + self.schedule_effect( + bill_timestamp, + lambda person: person.bill_account(), + Effect.Target.SELF, + ) def downgrade_plan(self): assert self.account is not None @@ -687,7 +726,8 @@ def downgrade_plan(self): if new_plan is None: raise ValueError("There's no predecessor plan") self.active_client.capture( - EVENT_DOWNGRADED_PLAN, {"previous_plan": str(previous_plan), "new_plan": str(new_plan)} + EVENT_DOWNGRADED_PLAN, + {"previous_plan": str(previous_plan), "new_plan": str(new_plan)}, ) self.account.plan = new_plan @@ -716,7 +756,10 @@ def bill_account(self): if self.account and self.account.current_monthly_bill_usd: self.cluster.matrix.server_client.capture( EVENT_PAID_BILL, - {"amount_usd": self.account.current_monthly_bill_usd, "plan": self.account.plan}, + { + "amount_usd": self.account.current_monthly_bill_usd, + "plan": self.account.plan, + }, distinct_id=self.in_product_id, ) diff --git a/posthog/demo/test/test_matrix_manager.py b/posthog/demo/test/test_matrix_manager.py index 99f0451c5485d..25770553ab613 100644 --- a/posthog/demo/test/test_matrix_manager.py +++ b/posthog/demo/test/test_matrix_manager.py @@ -55,7 +55,9 @@ class TestMatrixManager(ClickhouseDestroyTablesMixin): def setUpTestData(cls): super().setUpTestData() cls.matrix = DummyMatrix( - n_clusters=3, now=dt.datetime(2020, 1, 1, 0, 0, 0, 0, tzinfo=ZoneInfo("UTC")), days_future=0 + n_clusters=3, + now=dt.datetime(2020, 1, 1, 0, 0, 0, 0, tzinfo=ZoneInfo("UTC")), + days_future=0, ) cls.matrix.simulate() @@ -83,7 +85,10 @@ def test_run_on_team(self): # At least one event for each cluster assert ( - sync_execute("SELECT count() FROM events WHERE team_id = %(team_id)s", {"team_id": self.team.pk})[0][0] >= 3 + sync_execute("SELECT count() FROM events WHERE team_id = %(team_id)s", {"team_id": self.team.pk},)[ + 0 + ][0] + >= 3 ) assert self.team.name == DummyMatrix.PRODUCT_NAME @@ -95,5 +100,8 @@ def test_run_on_team_using_pre_save(self): # At least one event for each cluster assert sync_execute("SELECT count() FROM events WHERE team_id = 0")[0][0] >= 3 assert ( - sync_execute("SELECT count() FROM events WHERE team_id = %(team_id)s", {"team_id": self.team.pk})[0][0] >= 3 + sync_execute("SELECT count() FROM events WHERE team_id = %(team_id)s", {"team_id": self.team.pk},)[ + 0 + ][0] + >= 3 ) diff --git a/posthog/email.py b/posthog/email.py index 579d68cb0e0ac..93968b6c07844 100644 --- a/posthog/email.py +++ b/posthog/email.py @@ -59,7 +59,6 @@ def _send_email( records: List = [] with transaction.atomic(): - for dest in to: record, _ = MessagingRecord.objects.get_or_create(raw_email=dest["raw_email"], campaign_key=campaign_key) @@ -113,7 +112,11 @@ def _send_email( try: connection.close() # type: ignore except Exception as err: - print("Could not close email connection (this can be ignored):", err, file=sys.stderr) + print( + "Could not close email connection (this can be ignored):", + err, + file=sys.stderr, + ) class EmailMessage: diff --git a/posthog/event_usage.py b/posthog/event_usage.py index 7d238a29738e6..fa69f0c23662b 100644 --- a/posthog/event_usage.py +++ b/posthog/event_usage.py @@ -93,7 +93,8 @@ def report_user_joined_organization(organization: Organization, current_user: Us def report_user_logged_in( - user: User, social_provider: str = "" # which third-party provider processed the login (empty = no third-party) + user: User, + social_provider: str = "", # which third-party provider processed the login (empty = no third-party) ) -> None: """ Reports that a user has logged in to PostHog. @@ -125,7 +126,9 @@ def report_user_password_reset(user: User) -> None: Reports a user resetting their password. """ posthoganalytics.capture( - user.distinct_id, "user password reset", groups=groups(user.current_organization, user.current_team) + user.distinct_id, + "user password reset", + groups=groups(user.current_organization, user.current_team), ) @@ -195,13 +198,19 @@ def report_bulk_invited( def report_user_action(user: User, event: str, properties: Dict = {}): posthoganalytics.capture( - user.distinct_id, event, properties=properties, groups=groups(user.current_organization, user.current_team) + user.distinct_id, + event, + properties=properties, + groups=groups(user.current_organization, user.current_team), ) def report_organization_deleted(user: User, organization: Organization): posthoganalytics.capture( - user.distinct_id, "organization deleted", organization.get_analytics_metadata(), groups=groups(organization) + user.distinct_id, + "organization deleted", + organization.get_analytics_metadata(), + groups=groups(organization), ) @@ -219,7 +228,12 @@ def groups(organization: Optional[Organization] = None, team: Optional[Team] = N return result -def report_team_action(team: Team, event: str, properties: Dict = {}, group_properties: Optional[Dict] = None): +def report_team_action( + team: Team, + event: str, + properties: Dict = {}, + group_properties: Optional[Dict] = None, +): """ For capturing events where it is unclear which user was the core actor we can use the team instead """ @@ -230,13 +244,19 @@ def report_team_action(team: Team, event: str, properties: Dict = {}, group_prop def report_organization_action( - organization: Organization, event: str, properties: Dict = {}, group_properties: Optional[Dict] = None + organization: Organization, + event: str, + properties: Dict = {}, + group_properties: Optional[Dict] = None, ): """ For capturing events where it is unclear which user was the core actor we can use the organization instead """ posthoganalytics.capture( - str(organization.id), event, properties=properties, groups=groups(organization=organization) + str(organization.id), + event, + properties=properties, + groups=groups(organization=organization), ) if group_properties: diff --git a/posthog/exceptions.py b/posthog/exceptions.py index 1cdcc5f1bf957..a38b334b566fb 100644 --- a/posthog/exceptions.py +++ b/posthog/exceptions.py @@ -75,6 +75,7 @@ def generate_exception_response( from statshog.defaults.django import statsd statsd.incr( - f"posthog_cloud_raw_endpoint_exception", tags={"endpoint": endpoint, "code": code, "type": type, "attr": attr} + f"posthog_cloud_raw_endpoint_exception", + tags={"endpoint": endpoint, "code": code, "type": type, "attr": attr}, ) return JsonResponse({"type": type, "code": code, "detail": detail, "attr": attr}, status=status_code) diff --git a/posthog/filters.py b/posthog/filters.py index 0e8bb86cae7c6..ac098dea92c68 100644 --- a/posthog/filters.py +++ b/posthog/filters.py @@ -33,7 +33,12 @@ def get_search_terms(self, request: Request): terms = terms.replace("\x00", "") # strip null characters return list(filter(None, terms.split(" "))) - def filter_queryset(self, request: Request, queryset: Union[QuerySet[_MT], RawQuerySet], view: APIView): + def filter_queryset( + self, + request: Request, + queryset: Union[QuerySet[_MT], RawQuerySet], + view: APIView, + ): if isinstance(queryset, RawQuerySet): return queryset @@ -54,7 +59,9 @@ def filter_queryset(self, request: Request, queryset: Union[QuerySet[_MT], RawQu def term_search_filter_sql( - search_fields: List[str], search_terms: Optional[str] = "", search_extra: Optional[str] = "" + search_fields: List[str], + search_terms: Optional[str] = "", + search_extra: Optional[str] = "", ) -> Tuple[str, dict]: if not search_fields or not search_terms: return "", {} diff --git a/posthog/health.py b/posthog/health.py index 782fab5a2942a..a77e4d79718f3 100644 --- a/posthog/health.py +++ b/posthog/health.py @@ -59,7 +59,13 @@ # NOTE: we can be pretty picky about what the worker needs as by its nature # of reading from a durable queue rather that being required to perform # request/response, we are more resilient to service downtime. - "worker": ["http", "postgres", "postgres_migrations_uptodate", "clickhouse", "celery_broker"], + "worker": [ + "http", + "postgres", + "postgres_migrations_uptodate", + "clickhouse", + "celery_broker", + ], "decide": ["http"], } diff --git a/posthog/helpers/dashboard_templates.py b/posthog/helpers/dashboard_templates.py index 7a1179b3af5d3..cfaa2bac5e1d1 100644 --- a/posthog/helpers/dashboard_templates.py +++ b/posthog/helpers/dashboard_templates.py @@ -39,7 +39,9 @@ def _create_website_dashboard(dashboard: Dashboard) -> None: dashboard.filters = {DATE_FROM: "-30d"} if dashboard.team.organization.is_feature_available(AvailableFeature.TAGGING): tag, _ = Tag.objects.get_or_create( - name="marketing", team_id=dashboard.team_id, defaults={"team_id": dashboard.team_id} + name="marketing", + team_id=dashboard.team_id, + defaults={"team_id": dashboard.team_id}, ) dashboard.tagged_items.create(tag_id=tag.id) dashboard.save(update_fields=["filters"]) @@ -50,7 +52,13 @@ def _create_website_dashboard(dashboard: Dashboard) -> None: name="Website Unique Users (Total)", description="Shows the number of unique users that use your app every day.", filters={ - TREND_FILTER_TYPE_EVENTS: [{"id": "$pageview", "math": UNIQUE_USERS, "type": TREND_FILTER_TYPE_EVENTS}], + TREND_FILTER_TYPE_EVENTS: [ + { + "id": "$pageview", + "math": UNIQUE_USERS, + "type": TREND_FILTER_TYPE_EVENTS, + } + ], INTERVAL: "day", INSIGHT: INSIGHT_TRENDS, DATE_FROM: "-30d", @@ -77,7 +85,13 @@ def _create_website_dashboard(dashboard: Dashboard) -> None: name="Organic SEO Unique Users (Total)", description="", filters={ - TREND_FILTER_TYPE_EVENTS: [{"id": "$pageview", "math": UNIQUE_USERS, "type": TREND_FILTER_TYPE_EVENTS}], + TREND_FILTER_TYPE_EVENTS: [ + { + "id": "$pageview", + "math": UNIQUE_USERS, + "type": TREND_FILTER_TYPE_EVENTS, + } + ], INTERVAL: "day", INSIGHT: INSIGHT_TRENDS, DATE_FROM: "-30d", @@ -89,8 +103,18 @@ def _create_website_dashboard(dashboard: Dashboard) -> None: { "type": "AND", "values": [ - {"key": "$referring_domain", "type": "event", "value": "google", "operator": "icontains"}, - {"key": "utm_source", "type": "event", "value": "is_not_set", "operator": "is_not_set"}, + { + "key": "$referring_domain", + "type": "event", + "value": "google", + "operator": "icontains", + }, + { + "key": "utm_source", + "type": "event", + "value": "is_not_set", + "operator": "is_not_set", + }, ], } ], @@ -117,7 +141,13 @@ def _create_website_dashboard(dashboard: Dashboard) -> None: name="Website Unique Users (Breakdown)", description="", filters={ - TREND_FILTER_TYPE_EVENTS: [{"id": "$pageview", "math": UNIQUE_USERS, "type": TREND_FILTER_TYPE_EVENTS}], + TREND_FILTER_TYPE_EVENTS: [ + { + "id": "$pageview", + "math": UNIQUE_USERS, + "type": TREND_FILTER_TYPE_EVENTS, + } + ], INTERVAL: "week", INSIGHT: INSIGHT_TRENDS, DATE_FROM: "-30d", @@ -149,8 +179,18 @@ def _create_website_dashboard(dashboard: Dashboard) -> None: "math": UNIQUE_USERS, "type": TREND_FILTER_TYPE_EVENTS, PROPERTIES: [ - {"key": "$referring_domain", "type": "event", "value": "google", "operator": "icontains"}, - {"key": "utm_source", "type": "event", "value": "is_not_set", "operator": "is_not_set"}, + { + "key": "$referring_domain", + "type": "event", + "value": "google", + "operator": "icontains", + }, + { + "key": "utm_source", + "type": "event", + "value": "is_not_set", + "operator": "is_not_set", + }, ], } ], @@ -283,7 +323,14 @@ def _create_website_dashboard(dashboard: Dashboard) -> None: "values": [ { "type": "AND", - "values": [{"key": "$current_url", "type": "event", "value": "?", "operator": "not_icontains"}], + "values": [ + { + "key": "$current_url", + "type": "event", + "value": "?", + "operator": "not_icontains", + } + ], } ], }, @@ -329,8 +376,18 @@ def _create_website_dashboard(dashboard: Dashboard) -> None: { "type": "AND", "values": [ - {"key": "$current_url", "type": "event", "value": "?", "operator": "not_icontains"}, - {"key": "$referring_domain", "type": "event", "value": "google", "operator": "icontains"}, + { + "key": "$current_url", + "type": "event", + "value": "?", + "operator": "not_icontains", + }, + { + "key": "$referring_domain", + "type": "event", + "value": "google", + "operator": "icontains", + }, ], } ], @@ -403,7 +460,9 @@ def create_from_template(dashboard: Dashboard, template: DashboardTemplate) -> N if dashboard.team.organization.is_feature_available(AvailableFeature.TAGGING): for template_tag in template.tags or []: tag, _ = Tag.objects.get_or_create( - name=template_tag, team_id=dashboard.team_id, defaults={"team_id": dashboard.team_id} + name=template_tag, + team_id=dashboard.team_id, + defaults={"team_id": dashboard.team_id}, ) dashboard.tagged_items.create(tag_id=tag.id) dashboard.save() @@ -490,7 +549,9 @@ def create_feature_flag_dashboard(feature_flag, dashboard: Dashboard) -> None: dashboard.filters = {DATE_FROM: "-30d"} if dashboard.team.organization.is_feature_available(AvailableFeature.TAGGING): tag, _ = Tag.objects.get_or_create( - name="feature flags", team_id=dashboard.team_id, defaults={"team_id": dashboard.team_id} + name="feature flags", + team_id=dashboard.team_id, + defaults={"team_id": dashboard.team_id}, ) dashboard.tagged_items.create(tag_id=tag.id) dashboard.save(update_fields=["filters"]) @@ -502,7 +563,11 @@ def create_feature_flag_dashboard(feature_flag, dashboard: Dashboard) -> None: description="Shows the number of total calls made on feature flag with key: " + feature_flag.key, filters={ TREND_FILTER_TYPE_EVENTS: [ - {"id": "$feature_flag_called", "name": "$feature_flag_called", "type": TREND_FILTER_TYPE_EVENTS} + { + "id": "$feature_flag_called", + "name": "$feature_flag_called", + "type": TREND_FILTER_TYPE_EVENTS, + } ], INTERVAL: "day", INSIGHT: INSIGHT_TRENDS, @@ -514,7 +579,11 @@ def create_feature_flag_dashboard(feature_flag, dashboard: Dashboard) -> None: { "type": "AND", "values": [ - {"key": "$feature_flag", "type": "event", "value": feature_flag.key}, + { + "key": "$feature_flag", + "type": "event", + "value": feature_flag.key, + }, ], } ], @@ -562,7 +631,11 @@ def create_feature_flag_dashboard(feature_flag, dashboard: Dashboard) -> None: { "type": "AND", "values": [ - {"key": "$feature_flag", "type": "event", "value": feature_flag.key}, + { + "key": "$feature_flag", + "type": "event", + "value": feature_flag.key, + }, ], } ], @@ -595,7 +668,11 @@ def add_enriched_insights_to_feature_flag_dashboard(feature_flag, dashboard: Das description="Shows the total number of times this feature was viewed and interacted with", filters={ TREND_FILTER_TYPE_EVENTS: [ - {"id": "$feature_view", "name": "Feature View - Total", "type": TREND_FILTER_TYPE_EVENTS}, + { + "id": "$feature_view", + "name": "Feature View - Total", + "type": TREND_FILTER_TYPE_EVENTS, + }, { "id": "$feature_view", "name": "Feature View - Unique users", @@ -613,7 +690,11 @@ def add_enriched_insights_to_feature_flag_dashboard(feature_flag, dashboard: Das { "type": "AND", "values": [ - {"key": "feature_flag", "type": "event", "value": feature_flag.key}, + { + "key": "feature_flag", + "type": "event", + "value": feature_flag.key, + }, ], } ], @@ -630,7 +711,11 @@ def add_enriched_insights_to_feature_flag_dashboard(feature_flag, dashboard: Das description="Shows the total number of times this feature was viewed and interacted with", filters={ TREND_FILTER_TYPE_EVENTS: [ - {"id": "$feature_interaction", "name": "Feature Interaction - Total", "type": TREND_FILTER_TYPE_EVENTS}, + { + "id": "$feature_interaction", + "name": "Feature Interaction - Total", + "type": TREND_FILTER_TYPE_EVENTS, + }, { "id": "$feature_interaction", "name": "Feature Interaction - Unique users", @@ -648,7 +733,11 @@ def add_enriched_insights_to_feature_flag_dashboard(feature_flag, dashboard: Das { "type": "AND", "values": [ - {"key": "feature_flag", "type": "event", "value": feature_flag.key}, + { + "key": "feature_flag", + "type": "event", + "value": feature_flag.key, + }, ], } ], diff --git a/posthog/helpers/tests/test_multi_property_breakdown.py b/posthog/helpers/tests/test_multi_property_breakdown.py index 311cd465ad9b8..cc2dad4bbc57f 100644 --- a/posthog/helpers/tests/test_multi_property_breakdown.py +++ b/posthog/helpers/tests/test_multi_property_breakdown.py @@ -1,7 +1,9 @@ from typing import Any, Dict, List from unittest import TestCase -from posthog.helpers.multi_property_breakdown import protect_old_clients_from_multi_property_default +from posthog.helpers.multi_property_breakdown import ( + protect_old_clients_from_multi_property_default, +) class TestMultiPropertyBreakdown(TestCase): @@ -15,7 +17,11 @@ def test_handles_empty_inputs(self): assert False, "should not raise any KeyError" def test_handles_empty_breakdowns_array(self): - data: Dict[str, Any] = {"breakdowns": [], "insight": "FUNNELS", "breakdown_type": "event"} + data: Dict[str, Any] = { + "breakdowns": [], + "insight": "FUNNELS", + "breakdown_type": "event", + } result: List = [] try: @@ -24,7 +30,11 @@ def test_handles_empty_breakdowns_array(self): assert False, "should not raise any KeyError" def test_keeps_multi_property_breakdown_for_multi_property_requests(self): - data: Dict[str, Any] = {"breakdowns": ["a", "b"], "insight": "FUNNELS", "breakdown_type": "event"} + data: Dict[str, Any] = { + "breakdowns": ["a", "b"], + "insight": "FUNNELS", + "breakdown_type": "event", + } result: List[List[Dict[str, Any]]] = [[{"breakdown": ["a1", "b1"], "breakdown_value": ["a1", "b1"]}]] actual = protect_old_clients_from_multi_property_default(data, result) @@ -38,7 +48,11 @@ def test_keeps_multi_property_breakdown_for_multi_property_requests(self): assert "breakdown" not in data def test_flattens_multi_property_breakdown_for_single_property_requests(self): - data: Dict[str, Any] = {"breakdown": "a", "insight": "FUNNELS", "breakdown_type": "event"} + data: Dict[str, Any] = { + "breakdown": "a", + "insight": "FUNNELS", + "breakdown_type": "event", + } result: List[List[Dict[str, Any]]] = [[{"breakdown": ["a1"], "breakdown_value": ["a1", "b1"]}]] actual = protect_old_clients_from_multi_property_default(data, result) diff --git a/posthog/hogql/ai.py b/posthog/hogql/ai.py index 915d03b77e49c..c53e9814d807a 100644 --- a/posthog/hogql/ai.py +++ b/posthog/hogql/ai.py @@ -85,7 +85,11 @@ def write_sql_from_prompt(prompt: str, *, current_query: Optional[str] = None, t ] if current_query: messages.insert( - -1, {"role": "user", "content": CURRENT_QUERY_MESSAGE.format(current_query_input=current_query)} + -1, + { + "role": "user", + "content": CURRENT_QUERY_MESSAGE.format(current_query_input=current_query), + }, ) candidate_sql: Optional[str] = None @@ -116,7 +120,12 @@ def write_sql_from_prompt(prompt: str, *, current_query: Optional[str] = None, t print_ast(parse_select(candidate_sql), context=context, dialect="clickhouse") except HogQLException as e: messages.append({"role": "assistant", "content": candidate_sql}) - messages.append({"role": "user", "content": f"That query has this problem: {e}. Return fixed query."}) + messages.append( + { + "role": "user", + "content": f"That query has this problem: {e}. Return fixed query.", + } + ) else: generated_valid_hogql = True break diff --git a/posthog/hogql/bytecode.py b/posthog/hogql/bytecode.py index ab468338ca803..7a4a6904527b9 100644 --- a/posthog/hogql/bytecode.py +++ b/posthog/hogql/bytecode.py @@ -3,7 +3,11 @@ from posthog.hogql import ast from posthog.hogql.errors import NotImplementedException from posthog.hogql.visitor import Visitor -from hogvm.python.operation import Operation, HOGQL_BYTECODE_IDENTIFIER, SUPPORTED_FUNCTIONS +from hogvm.python.operation import ( + Operation, + HOGQL_BYTECODE_IDENTIFIER, + SUPPORTED_FUNCTIONS, +) COMPARE_OPERATIONS = { ast.CompareOperationOp.Eq: Operation.EQ, @@ -74,7 +78,11 @@ def visit_compare_operation(self, node: ast.CompareOperation): return [*self.visit(node.right), *self.visit(node.left), operation] def visit_arithmetic_operation(self, node: ast.ArithmeticOperation): - return [*self.visit(node.right), *self.visit(node.left), ARITHMETIC_OPERATIONS[node.op]] + return [ + *self.visit(node.right), + *self.visit(node.left), + ARITHMETIC_OPERATIONS[node.op], + ] def visit_field(self, node: ast.Field): chain = [] diff --git a/posthog/hogql/constants.py b/posthog/hogql/constants.py index cd08da81fca30..0a2806ca99878 100644 --- a/posthog/hogql/constants.py +++ b/posthog/hogql/constants.py @@ -4,7 +4,16 @@ from pydantic import ConfigDict, BaseModel ConstantDataType: TypeAlias = Literal[ - "int", "float", "str", "bool", "array", "tuple", "date", "datetime", "uuid", "unknown" + "int", + "float", + "str", + "bool", + "array", + "tuple", + "date", + "datetime", + "uuid", + "unknown", ] ConstantSupportedPrimitive: TypeAlias = int | float | str | bool | date | datetime | UUID | None ConstantSupportedData: TypeAlias = ( diff --git a/posthog/hogql/context.py b/posthog/hogql/context.py index 65c17ba7006be..7f45d66fa4f83 100644 --- a/posthog/hogql/context.py +++ b/posthog/hogql/context.py @@ -55,7 +55,11 @@ def add_sensitive_value(self, value: Any) -> str: return f"%({key})s" def add_notice( - self, message: str, start: Optional[int] = None, end: Optional[int] = None, fix: Optional[str] = None + self, + message: str, + start: Optional[int] = None, + end: Optional[int] = None, + fix: Optional[str] = None, ): if not any(n.start == start and n.end == end and n.message == message and n.fix == fix for n in self.notices): self.notices.append(HogQLNotice(start=start, end=end, message=message, fix=fix)) diff --git a/posthog/hogql/database/argmax.py b/posthog/hogql/database/argmax.py index a46b068513e6b..0302ac14ddb26 100644 --- a/posthog/hogql/database/argmax.py +++ b/posthog/hogql/database/argmax.py @@ -18,7 +18,12 @@ def argmax_select( fields_to_select: List[ast.Expr] = [] for name, chain in select_fields.items(): if name not in group_fields: - fields_to_select.append(ast.Alias(alias=name, expr=argmax_version(ast.Field(chain=[table_name] + chain)))) + fields_to_select.append( + ast.Alias( + alias=name, + expr=argmax_version(ast.Field(chain=[table_name] + chain)), + ) + ) for key in group_fields: fields_to_group.append(ast.Field(chain=[table_name, key])) fields_to_select.append(ast.Alias(alias=key, expr=ast.Field(chain=[table_name, key]))) diff --git a/posthog/hogql/database/database.py b/posthog/hogql/database/database.py index dc898dde6924e..db2791c348d76 100644 --- a/posthog/hogql/database/database.py +++ b/posthog/hogql/database/database.py @@ -27,10 +27,19 @@ from posthog.hogql.database.schema.events import EventsTable from posthog.hogql.database.schema.groups import GroupsTable, RawGroupsTable from posthog.hogql.database.schema.numbers import NumbersTable -from posthog.hogql.database.schema.person_distinct_ids import PersonDistinctIdsTable, RawPersonDistinctIdsTable +from posthog.hogql.database.schema.person_distinct_ids import ( + PersonDistinctIdsTable, + RawPersonDistinctIdsTable, +) from posthog.hogql.database.schema.persons import PersonsTable, RawPersonsTable -from posthog.hogql.database.schema.person_overrides import PersonOverridesTable, RawPersonOverridesTable -from posthog.hogql.database.schema.session_replay_events import RawSessionReplayEventsTable, SessionReplayEventsTable +from posthog.hogql.database.schema.person_overrides import ( + PersonOverridesTable, + RawPersonOverridesTable, +) +from posthog.hogql.database.schema.session_replay_events import ( + RawSessionReplayEventsTable, + SessionReplayEventsTable, +) from posthog.hogql.database.schema.static_cohort_people import StaticCohortPeople from posthog.hogql.errors import HogQLException from posthog.models.group_type_mapping import GroupTypeMapping @@ -52,10 +61,10 @@ class Database(BaseModel): cohort_people: CohortPeople = CohortPeople() static_cohort_people: StaticCohortPeople = StaticCohortPeople() log_entries: LogEntriesTable = LogEntriesTable() - console_logs_log_entries: ReplayConsoleLogsLogEntriesTable = ReplayConsoleLogsLogEntriesTable() + console_logs_log_entries: (ReplayConsoleLogsLogEntriesTable) = ReplayConsoleLogsLogEntriesTable() batch_export_log_entries: BatchExportLogEntriesTable = BatchExportLogEntriesTable() - raw_session_replay_events: RawSessionReplayEventsTable = RawSessionReplayEventsTable() + raw_session_replay_events: (RawSessionReplayEventsTable) = RawSessionReplayEventsTable() raw_person_distinct_ids: RawPersonDistinctIdsTable = RawPersonDistinctIdsTable() raw_persons: RawPersonsTable = RawPersonsTable() raw_groups: RawGroupsTable = RawGroupsTable() @@ -111,7 +120,11 @@ def add_warehouse_tables(self, **field_definitions: Any): def create_hogql_database(team_id: int, modifiers: Optional[HogQLQueryModifiers] = None) -> Database: from posthog.models import Team from posthog.hogql.query import create_default_modifiers_for_team - from posthog.warehouse.models import DataWarehouseTable, DataWarehouseSavedQuery, DataWarehouseViewLink + from posthog.warehouse.models import ( + DataWarehouseTable, + DataWarehouseSavedQuery, + DataWarehouseViewLink, + ) team = Team.objects.get(pk=team_id) modifiers = create_default_modifiers_for_team(team, modifiers) diff --git a/posthog/hogql/database/schema/cohort_people.py b/posthog/hogql/database/schema/cohort_people.py index 097e74856f410..4cce926a61350 100644 --- a/posthog/hogql/database/schema/cohort_people.py +++ b/posthog/hogql/database/schema/cohort_people.py @@ -15,7 +15,11 @@ "person_id": StringDatabaseField(name="person_id"), "cohort_id": IntegerDatabaseField(name="cohort_id"), "team_id": IntegerDatabaseField(name="team_id"), - "person": LazyJoin(from_field="person_id", join_table=PersonsTable(), join_function=join_with_persons_table), + "person": LazyJoin( + from_field="person_id", + join_table=PersonsTable(), + join_function=join_with_persons_table, + ), } @@ -25,7 +29,11 @@ def select_from_cohort_people_table(requested_fields: Dict[str, List[str]]): table_name = "raw_cohort_people" # must always include the person and cohort ids regardless of what other fields are requested - requested_fields = {"person_id": ["person_id"], "cohort_id": ["cohort_id"], **requested_fields} + requested_fields = { + "person_id": ["person_id"], + "cohort_id": ["cohort_id"], + **requested_fields, + } fields: List[ast.Expr] = [ast.Field(chain=[table_name] + chain) for name, chain in requested_fields.items()] return ast.SelectQuery( diff --git a/posthog/hogql/database/schema/event_sessions.py b/posthog/hogql/database/schema/event_sessions.py index 3ccb665540476..a6951478ada4a 100644 --- a/posthog/hogql/database/schema/event_sessions.py +++ b/posthog/hogql/database/schema/event_sessions.py @@ -2,7 +2,12 @@ from typing import Any, Dict, List, Optional from posthog.hogql import ast from posthog.hogql.context import HogQLContext -from posthog.hogql.database.models import FieldOrTable, IntegerDatabaseField, StringDatabaseField, VirtualTable +from posthog.hogql.database.models import ( + FieldOrTable, + IntegerDatabaseField, + StringDatabaseField, + VirtualTable, +) from posthog.hogql.parser import parse_select from posthog.hogql.resolver_utils import get_long_table_name, lookup_field_by_name from posthog.hogql.visitor import CloningVisitor, TraversingVisitor @@ -53,7 +58,12 @@ def visit_field(self, node: ast.Field): class WhereClauseExtractor: compare_operators: List[ast.Expr] - def __init__(self, where_expression: ast.Expr, from_table_name: str, select_query_type: ast.SelectQueryType): + def __init__( + self, + where_expression: ast.Expr, + from_table_name: str, + select_query_type: ast.SelectQueryType, + ): self.table_name = from_table_name self.select_query_type = select_query_type self.compare_operators = self.run(deepcopy(where_expression)) @@ -147,7 +157,9 @@ def join_with_events_table_session_duration( exprs=[ *compare_operators, ast.CompareOperation( - left=ast.Field(chain=["$session_id"]), op=ast.CompareOperationOp.NotEq, right=ast.Constant(value="") + left=ast.Field(chain=["$session_id"]), + op=ast.CompareOperationOp.NotEq, + right=ast.Constant(value=""), ), ] ) diff --git a/posthog/hogql/database/schema/events.py b/posthog/hogql/database/schema/events.py index 06cab31fca940..e90142c290c72 100644 --- a/posthog/hogql/database/schema/events.py +++ b/posthog/hogql/database/schema/events.py @@ -11,13 +11,19 @@ FieldTraverser, FieldOrTable, ) -from posthog.hogql.database.schema.event_sessions import EventsSessionSubTable, join_with_events_table_session_duration +from posthog.hogql.database.schema.event_sessions import ( + EventsSessionSubTable, + join_with_events_table_session_duration, +) from posthog.hogql.database.schema.groups import GroupsTable, join_with_group_n_table from posthog.hogql.database.schema.person_distinct_ids import ( PersonDistinctIdsTable, join_with_person_distinct_ids_table, ) -from posthog.hogql.database.schema.person_overrides import PersonOverridesTable, join_with_person_overrides_table +from posthog.hogql.database.schema.person_overrides import ( + PersonOverridesTable, + join_with_person_overrides_table, +) class EventsPersonSubTable(VirtualTable): @@ -55,7 +61,6 @@ def to_printed_hogql(self): class EventsTable(Table): - fields: Dict[str, FieldOrTable] = { "uuid": StringDatabaseField(name="uuid"), "event": StringDatabaseField(name="event"), @@ -90,15 +95,35 @@ class EventsTable(Table): "person": FieldTraverser(chain=["pdi", "person"]), "person_id": FieldTraverser(chain=["pdi", "person_id"]), "$group_0": StringDatabaseField(name="$group_0"), - "group_0": LazyJoin(from_field="$group_0", join_table=GroupsTable(), join_function=join_with_group_n_table(0)), + "group_0": LazyJoin( + from_field="$group_0", + join_table=GroupsTable(), + join_function=join_with_group_n_table(0), + ), "$group_1": StringDatabaseField(name="$group_1"), - "group_1": LazyJoin(from_field="$group_1", join_table=GroupsTable(), join_function=join_with_group_n_table(1)), + "group_1": LazyJoin( + from_field="$group_1", + join_table=GroupsTable(), + join_function=join_with_group_n_table(1), + ), "$group_2": StringDatabaseField(name="$group_2"), - "group_2": LazyJoin(from_field="$group_2", join_table=GroupsTable(), join_function=join_with_group_n_table(2)), + "group_2": LazyJoin( + from_field="$group_2", + join_table=GroupsTable(), + join_function=join_with_group_n_table(2), + ), "$group_3": StringDatabaseField(name="$group_3"), - "group_3": LazyJoin(from_field="$group_3", join_table=GroupsTable(), join_function=join_with_group_n_table(3)), + "group_3": LazyJoin( + from_field="$group_3", + join_table=GroupsTable(), + join_function=join_with_group_n_table(3), + ), "$group_4": StringDatabaseField(name="$group_4"), - "group_4": LazyJoin(from_field="$group_4", join_table=GroupsTable(), join_function=join_with_group_n_table(4)), + "group_4": LazyJoin( + from_field="$group_4", + join_table=GroupsTable(), + join_function=join_with_group_n_table(4), + ), "session": LazyJoin( from_field="$session_id", join_table=EventsSessionSubTable(), diff --git a/posthog/hogql/database/schema/groups.py b/posthog/hogql/database/schema/groups.py index 251be8a11b243..39382b246349b 100644 --- a/posthog/hogql/database/schema/groups.py +++ b/posthog/hogql/database/schema/groups.py @@ -49,7 +49,9 @@ def join_with_group_table( select_query = select_from_groups_table(requested_fields) select_query.where = ast.CompareOperation( - left=ast.Field(chain=["index"]), op=ast.CompareOperationOp.Eq, right=ast.Constant(value=group_index) + left=ast.Field(chain=["index"]), + op=ast.CompareOperationOp.Eq, + right=ast.Constant(value=group_index), ) join_expr = ast.JoinExpr(table=select_query) diff --git a/posthog/hogql/database/schema/person_distinct_ids.py b/posthog/hogql/database/schema/person_distinct_ids.py index 963f0bdd24db8..d5785bef98c49 100644 --- a/posthog/hogql/database/schema/person_distinct_ids.py +++ b/posthog/hogql/database/schema/person_distinct_ids.py @@ -20,7 +20,11 @@ "team_id": IntegerDatabaseField(name="team_id"), "distinct_id": StringDatabaseField(name="distinct_id"), "person_id": StringDatabaseField(name="person_id"), - "person": LazyJoin(from_field="person_id", join_table=PersonsTable(), join_function=join_with_persons_table), + "person": LazyJoin( + from_field="person_id", + join_table=PersonsTable(), + join_function=join_with_persons_table, + ), } diff --git a/posthog/hogql/database/schema/person_overrides.py b/posthog/hogql/database/schema/person_overrides.py index 1dc15126a6ebc..800e902d343fe 100644 --- a/posthog/hogql/database/schema/person_overrides.py +++ b/posthog/hogql/database/schema/person_overrides.py @@ -34,7 +34,11 @@ def select_from_person_overrides_table(requested_fields: Dict[str, List[str]]): def join_with_person_overrides_table( - from_table: str, to_table: str, requested_fields: Dict[str, Any], context: HogQLContext, node: SelectQuery + from_table: str, + to_table: str, + requested_fields: Dict[str, Any], + context: HogQLContext, + node: SelectQuery, ): from posthog.hogql import ast diff --git a/posthog/hogql/database/schema/persons.py b/posthog/hogql/database/schema/persons.py index 67a36b747d279..1a1d79123436d 100644 --- a/posthog/hogql/database/schema/persons.py +++ b/posthog/hogql/database/schema/persons.py @@ -83,7 +83,11 @@ def select_from_persons_table(requested_fields: Dict[str, List[str]], modifiers: def join_with_persons_table( - from_table: str, to_table: str, requested_fields: Dict[str, List[str]], context: HogQLContext, node: SelectQuery + from_table: str, + to_table: str, + requested_fields: Dict[str, List[str]], + context: HogQLContext, + node: SelectQuery, ): from posthog.hogql import ast diff --git a/posthog/hogql/database/schema/persons_pdi.py b/posthog/hogql/database/schema/persons_pdi.py index 33d21d4efed04..9c7fcf9e03e43 100644 --- a/posthog/hogql/database/schema/persons_pdi.py +++ b/posthog/hogql/database/schema/persons_pdi.py @@ -31,7 +31,11 @@ def persons_pdi_select(requested_fields: Dict[str, List[str]]): # :NOTE: We already have person_distinct_ids.py, which most tables link to. This persons_pdi.py is a hack to # make "select persons.pdi.distinct_id from persons" work while avoiding circular imports. Don't use directly. def persons_pdi_join( - from_table: str, to_table: str, requested_fields: Dict[str, List[str]], context: HogQLContext, node: SelectQuery + from_table: str, + to_table: str, + requested_fields: Dict[str, List[str]], + context: HogQLContext, + node: SelectQuery, ): from posthog.hogql import ast diff --git a/posthog/hogql/database/schema/static_cohort_people.py b/posthog/hogql/database/schema/static_cohort_people.py index d09a7479f080d..c9737f86c6af9 100644 --- a/posthog/hogql/database/schema/static_cohort_people.py +++ b/posthog/hogql/database/schema/static_cohort_people.py @@ -1,6 +1,12 @@ from typing import Dict -from posthog.hogql.database.models import Table, StringDatabaseField, IntegerDatabaseField, LazyJoin, FieldOrTable +from posthog.hogql.database.models import ( + Table, + StringDatabaseField, + IntegerDatabaseField, + LazyJoin, + FieldOrTable, +) from posthog.hogql.database.schema.persons import PersonsTable, join_with_persons_table @@ -9,7 +15,11 @@ class StaticCohortPeople(Table): "person_id": StringDatabaseField(name="person_id"), "cohort_id": IntegerDatabaseField(name="cohort_id"), "team_id": IntegerDatabaseField(name="team_id"), - "person": LazyJoin(from_field="person_id", join_table=PersonsTable(), join_function=join_with_persons_table), + "person": LazyJoin( + from_field="person_id", + join_table=PersonsTable(), + join_function=join_with_persons_table, + ), } def avoid_asterisk_fields(self): diff --git a/posthog/hogql/database/schema/test/test_event_sessions.py b/posthog/hogql/database/schema/test/test_event_sessions.py index 34cb2c2bbba6c..268180a773e6c 100644 --- a/posthog/hogql/database/schema/test/test_event_sessions.py +++ b/posthog/hogql/database/schema/test/test_event_sessions.py @@ -2,7 +2,10 @@ from posthog.hogql import ast from posthog.hogql.context import HogQLContext from posthog.hogql.database.database import create_hogql_database -from posthog.hogql.database.schema.event_sessions import CleanTableNameFromChain, WhereClauseExtractor +from posthog.hogql.database.schema.event_sessions import ( + CleanTableNameFromChain, + WhereClauseExtractor, +) from posthog.hogql.parser import parse_expr, parse_select from posthog.hogql.resolver import resolve_types from posthog.hogql.visitor import clone_expr @@ -35,7 +38,9 @@ def test_with_simple_equality_clause(self): assert len(compare_operators) == 1 assert compare_operators[0] == ast.CompareOperation( - left=ast.Field(chain=["event"]), op=ast.CompareOperationOp.Eq, right=ast.Constant(value="$pageview") + left=ast.Field(chain=["event"]), + op=ast.CompareOperationOp.Eq, + right=ast.Constant(value="$pageview"), ) def test_with_timestamps(self): @@ -51,7 +56,9 @@ def test_with_timestamps(self): assert len(compare_operators) == 1 assert compare_operators[0] == ast.CompareOperation( - left=ast.Field(chain=["timestamp"]), op=ast.CompareOperationOp.Gt, right=ast.Constant(value="2023-01-01") + left=ast.Field(chain=["timestamp"]), + op=ast.CompareOperationOp.Gt, + right=ast.Constant(value="2023-01-01"), ) def test_with_alias_table(self): @@ -67,7 +74,9 @@ def test_with_alias_table(self): assert len(compare_operators) == 1 assert compare_operators[0] == ast.CompareOperation( - left=ast.Field(chain=["event"]), op=ast.CompareOperationOp.Eq, right=ast.Constant(value="$pageview") + left=ast.Field(chain=["event"]), + op=ast.CompareOperationOp.Eq, + right=ast.Constant(value="$pageview"), ) def test_with_multiple_clauses(self): @@ -83,10 +92,14 @@ def test_with_multiple_clauses(self): assert len(compare_operators) == 2 assert compare_operators[0] == ast.CompareOperation( - left=ast.Field(chain=["event"]), op=ast.CompareOperationOp.Eq, right=ast.Constant(value="$pageview") + left=ast.Field(chain=["event"]), + op=ast.CompareOperationOp.Eq, + right=ast.Constant(value="$pageview"), ) assert compare_operators[1] == ast.CompareOperation( - left=ast.Field(chain=["timestamp"]), op=ast.CompareOperationOp.Gt, right=ast.Constant(value="2023-01-01") + left=ast.Field(chain=["timestamp"]), + op=ast.CompareOperationOp.Gt, + right=ast.Constant(value="2023-01-01"), ) def test_with_join(self): @@ -104,7 +117,9 @@ def test_with_join(self): assert len(compare_operators) == 1 assert compare_operators[0] == ast.CompareOperation( - left=ast.Field(chain=["event"]), op=ast.CompareOperationOp.Eq, right=ast.Constant(value="$pageview") + left=ast.Field(chain=["event"]), + op=ast.CompareOperationOp.Eq, + right=ast.Constant(value="$pageview"), ) def test_with_ignoring_ors(self): diff --git a/posthog/hogql/database/test/tables.py b/posthog/hogql/database/test/tables.py index f675f3c8d194d..f3328091791b7 100644 --- a/posthog/hogql/database/test/tables.py +++ b/posthog/hogql/database/test/tables.py @@ -1,4 +1,8 @@ -from posthog.hogql.database.models import DateDatabaseField, IntegerDatabaseField, FloatDatabaseField +from posthog.hogql.database.models import ( + DateDatabaseField, + IntegerDatabaseField, + FloatDatabaseField, +) from posthog.hogql.database.s3_table import S3Table from posthog.hogql.database.models import SavedQuery diff --git a/posthog/hogql/database/test/test_argmax.py b/posthog/hogql/database/test/test_argmax.py index 535c17cae97ed..8c61ecd4a29c4 100644 --- a/posthog/hogql/database/test/test_argmax.py +++ b/posthog/hogql/database/test/test_argmax.py @@ -58,7 +58,10 @@ def test_argmax_select_deleted(self): op=ast.CompareOperationOp.Eq, left=ast.Call( name="argMax", - args=[ast.Field(chain=["raw_persons", "is_deleted"]), ast.Field(chain=["raw_persons", "version"])], + args=[ + ast.Field(chain=["raw_persons", "is_deleted"]), + ast.Field(chain=["raw_persons", "version"]), + ], ), right=ast.Constant(value=0), ), diff --git a/posthog/hogql/database/test/test_database.py b/posthog/hogql/database/test/test_database.py index 1ea0583c4e349..16bfeb9e4a392 100644 --- a/posthog/hogql/database/test/test_database.py +++ b/posthog/hogql/database/test/test_database.py @@ -51,7 +51,11 @@ def test_database_with_warehouse_tables(self, patch_execute): team=self.team, access_key="_accesskey", access_secret="_secret" ) DataWarehouseTable.objects.create( - name="whatever", team=self.team, columns={"id": "String"}, credential=credential, url_pattern="" + name="whatever", + team=self.team, + columns={"id": "String"}, + credential=credential, + url_pattern="", ) create_hogql_database(team_id=self.team.pk) diff --git a/posthog/hogql/database/test/test_s3_table.py b/posthog/hogql/database/test/test_s3_table.py index 1711aebb688a6..72b5dfa6cf3c0 100644 --- a/posthog/hogql/database/test/test_s3_table.py +++ b/posthog/hogql/database/test/test_s3_table.py @@ -27,7 +27,10 @@ def test_s3_table_select(self): self._init_database() hogql = self._select(query="SELECT * FROM aapl_stock LIMIT 10", dialect="hogql") - self.assertEqual(hogql, "SELECT Date, Open, High, Low, Close, Volume, OpenInt FROM aapl_stock LIMIT 10") + self.assertEqual( + hogql, + "SELECT Date, Open, High, Low, Close, Volume, OpenInt FROM aapl_stock LIMIT 10", + ) clickhouse = self._select(query="SELECT * FROM aapl_stock LIMIT 10", dialect="clickhouse") @@ -80,7 +83,8 @@ def test_s3_table_select_join_with_alias(self): dialect="hogql", ) self.assertEqual( - hogql, "SELECT a.High, a.Low FROM aapl_stock AS a JOIN aapl_stock AS b ON equals(a.High, b.High) LIMIT 10" + hogql, + "SELECT a.High, a.Low FROM aapl_stock AS a JOIN aapl_stock AS b ON equals(a.High, b.High) LIMIT 10", ) clickhouse = self._select( @@ -180,7 +184,8 @@ def test_s3_table_select_in(self): self._init_database() hogql = self._select( - query="SELECT uuid, event FROM events WHERE event IN (SELECT Date FROM aapl_stock)", dialect="hogql" + query="SELECT uuid, event FROM events WHERE event IN (SELECT Date FROM aapl_stock)", + dialect="hogql", ) self.assertEqual( hogql, @@ -188,7 +193,8 @@ def test_s3_table_select_in(self): ) clickhouse = self._select( - query="SELECT uuid, event FROM events WHERE event IN (SELECT Date FROM aapl_stock)", dialect="clickhouse" + query="SELECT uuid, event FROM events WHERE event IN (SELECT Date FROM aapl_stock)", + dialect="clickhouse", ) self.assertEqual( diff --git a/posthog/hogql/database/test/test_saved_query.py b/posthog/hogql/database/test/test_saved_query.py index 5e64f9760fcbf..7c7f534c66f21 100644 --- a/posthog/hogql/database/test/test_saved_query.py +++ b/posthog/hogql/database/test/test_saved_query.py @@ -35,7 +35,10 @@ def test_saved_query_table_select(self): self._init_database() hogql = self._select(query="SELECT * FROM aapl_stock LIMIT 10", dialect="hogql") - self.assertEqual(hogql, "SELECT Date, Open, High, Low, Close, Volume, OpenInt FROM aapl_stock LIMIT 10") + self.assertEqual( + hogql, + "SELECT Date, Open, High, Low, Close, Volume, OpenInt FROM aapl_stock LIMIT 10", + ) clickhouse = self._select(query="SELECT * FROM aapl_stock_view LIMIT 10", dialect="clickhouse") @@ -48,9 +51,15 @@ def test_saved_query_with_alias(self): self._init_database() hogql = self._select(query="SELECT * FROM aapl_stock LIMIT 10", dialect="hogql") - self.assertEqual(hogql, "SELECT Date, Open, High, Low, Close, Volume, OpenInt FROM aapl_stock LIMIT 10") + self.assertEqual( + hogql, + "SELECT Date, Open, High, Low, Close, Volume, OpenInt FROM aapl_stock LIMIT 10", + ) - clickhouse = self._select(query="SELECT * FROM aapl_stock_view AS some_alias LIMIT 10", dialect="clickhouse") + clickhouse = self._select( + query="SELECT * FROM aapl_stock_view AS some_alias LIMIT 10", + dialect="clickhouse", + ) self.assertEqual( clickhouse, diff --git a/posthog/hogql/database/test/test_view.py b/posthog/hogql/database/test/test_view.py index 3d773314e1f8f..26ce89e10653c 100644 --- a/posthog/hogql/database/test/test_view.py +++ b/posthog/hogql/database/test/test_view.py @@ -35,7 +35,10 @@ def test_view_table_select(self): self._init_database() hogql = self._select(query="SELECT * FROM aapl_stock LIMIT 10", dialect="hogql") - self.assertEqual(hogql, "SELECT Date, Open, High, Low, Close, Volume, OpenInt FROM aapl_stock LIMIT 10") + self.assertEqual( + hogql, + "SELECT Date, Open, High, Low, Close, Volume, OpenInt FROM aapl_stock LIMIT 10", + ) clickhouse = self._select(query="SELECT * FROM aapl_stock_view LIMIT 10", dialect="clickhouse") @@ -48,9 +51,15 @@ def test_view_with_alias(self): self._init_database() hogql = self._select(query="SELECT * FROM aapl_stock LIMIT 10", dialect="hogql") - self.assertEqual(hogql, "SELECT Date, Open, High, Low, Close, Volume, OpenInt FROM aapl_stock LIMIT 10") + self.assertEqual( + hogql, + "SELECT Date, Open, High, Low, Close, Volume, OpenInt FROM aapl_stock LIMIT 10", + ) - clickhouse = self._select(query="SELECT * FROM aapl_stock_view AS some_alias LIMIT 10", dialect="clickhouse") + clickhouse = self._select( + query="SELECT * FROM aapl_stock_view AS some_alias LIMIT 10", + dialect="clickhouse", + ) self.assertEqual( clickhouse, diff --git a/posthog/hogql/errors.py b/posthog/hogql/errors.py index 5dd36c2bf7143..4035e30eed173 100644 --- a/posthog/hogql/errors.py +++ b/posthog/hogql/errors.py @@ -11,7 +11,12 @@ class HogQLException(Exception): end: Optional[int] def __init__( - self, message: str, *, start: Optional[int] = None, end: Optional[int] = None, node: Optional["Expr"] = None + self, + message: str, + *, + start: Optional[int] = None, + end: Optional[int] = None, + node: Optional["Expr"] = None, ): super().__init__(message) if node is not None and node.start is not None and node.end is not None: diff --git a/posthog/hogql/escape_sql.py b/posthog/hogql/escape_sql.py index 68e326ede1437..d6c9b4bfefd99 100644 --- a/posthog/hogql/escape_sql.py +++ b/posthog/hogql/escape_sql.py @@ -54,19 +54,25 @@ def escape_clickhouse_identifier(identifier: str) -> str: def escape_hogql_string( - name: float | int | str | list | tuple | date | datetime | UUID | UUIDT, timezone: Optional[str] = None + name: float | int | str | list | tuple | date | datetime | UUID | UUIDT, + timezone: Optional[str] = None, ) -> str: return SQLValueEscaper(timezone=timezone, dialect="hogql").visit(name) def escape_clickhouse_string( - name: float | int | str | list | tuple | date | datetime | UUID | UUIDT, timezone: Optional[str] = None + name: float | int | str | list | tuple | date | datetime | UUID | UUIDT, + timezone: Optional[str] = None, ) -> str: return SQLValueEscaper(timezone=timezone, dialect="clickhouse").visit(name) class SQLValueEscaper: - def __init__(self, timezone: Optional[str] = None, dialect: Literal["hogql", "clickhouse"] = "clickhouse"): + def __init__( + self, + timezone: Optional[str] = None, + dialect: Literal["hogql", "clickhouse"] = "clickhouse", + ): self._timezone = timezone or "UTC" self._dialect = dialect diff --git a/posthog/hogql/filters.py b/posthog/hogql/filters.py index 61f992ac86688..c900ac1bc5ea6 100644 --- a/posthog/hogql/filters.py +++ b/posthog/hogql/filters.py @@ -59,7 +59,12 @@ def visit_placeholder(self, node): parsed_date = isoparse(dateTo) except ValueError: parsed_date = relative_date_parse(dateTo, self.team.timezone_info) - exprs.append(parse_expr("timestamp < {timestamp}", {"timestamp": ast.Constant(value=parsed_date)})) + exprs.append( + parse_expr( + "timestamp < {timestamp}", + {"timestamp": ast.Constant(value=parsed_date)}, + ) + ) # limit to the last 30d by default dateFrom = self.filters.dateRange.date_from if self.filters.dateRange else None @@ -68,7 +73,12 @@ def visit_placeholder(self, node): parsed_date = isoparse(dateFrom) except ValueError: parsed_date = relative_date_parse(dateFrom, self.team.timezone_info) - exprs.append(parse_expr("timestamp >= {timestamp}", {"timestamp": ast.Constant(value=parsed_date)})) + exprs.append( + parse_expr( + "timestamp >= {timestamp}", + {"timestamp": ast.Constant(value=parsed_date)}, + ) + ) if len(exprs) == 0: return ast.Constant(value=True) diff --git a/posthog/hogql/functions/mapping.py b/posthog/hogql/functions/mapping.py index 8da35817dcf56..5c4933ca981a4 100644 --- a/posthog/hogql/functions/mapping.py +++ b/posthog/hogql/functions/mapping.py @@ -142,7 +142,11 @@ class HogQLFunctionMeta: "toFloat": HogQLFunctionMeta("toFloat64OrNull", 1, 1), "toDecimal": HogQLFunctionMeta("toDecimal64OrNull", 1, 1), "toDate": HogQLFunctionMeta( - "toDateOrNull", 1, 1, overloads=[((ast.DateTimeType, ast.DateType), "toDate")], tz_aware=True + "toDateOrNull", + 1, + 1, + overloads=[((ast.DateTimeType, ast.DateType), "toDate")], + tz_aware=True, ), "toDateTime": HogQLFunctionMeta( "parseDateTime64BestEffortOrNull", @@ -725,6 +729,17 @@ class HogQLFunctionMeta: # TODO: Make the below details part of function meta # Functions where we use a -OrNull variant by default -ADD_OR_NULL_DATETIME_FUNCTIONS = ("toDateTime", "parseDateTime", "parseDateTimeBestEffort") +ADD_OR_NULL_DATETIME_FUNCTIONS = ( + "toDateTime", + "parseDateTime", + "parseDateTimeBestEffort", +) # Functions where the first argument needs to be DateTime and not DateTime64 -FIRST_ARG_DATETIME_FUNCTIONS = ("tumble", "tumbleStart", "tumbleEnd", "hop", "hopStart", "hopEnd") +FIRST_ARG_DATETIME_FUNCTIONS = ( + "tumble", + "tumbleStart", + "tumbleEnd", + "hop", + "hopStart", + "hopEnd", +) diff --git a/posthog/hogql/functions/test/test_cohort.py b/posthog/hogql/functions/test/test_cohort.py index c9adaffbba8a0..f893eea1e5e68 100644 --- a/posthog/hogql/functions/test/test_cohort.py +++ b/posthog/hogql/functions/test/test_cohort.py @@ -8,7 +8,12 @@ from posthog.models.cohort.util import recalculate_cohortpeople from posthog.models.utils import UUIDT from posthog.schema import HogQLQueryModifiers -from posthog.test.base import BaseTest, _create_person, _create_event, flush_persons_and_events +from posthog.test.base import ( + BaseTest, + _create_person, + _create_event, + flush_persons_and_events, +) elements_chain_match = lambda x: parse_expr("match(elements_chain, {regex})", {"regex": ast.Constant(value=str(x))}) not_call = lambda x: ast.Call(name="not", args=[x]) @@ -33,7 +38,8 @@ def _create_random_events(self) -> str: def test_in_cohort_dynamic(self): random_uuid = self._create_random_events() cohort = Cohort.objects.create( - team=self.team, groups=[{"properties": [{"key": "$os", "value": "Chrome", "type": "person"}]}] + team=self.team, + groups=[{"properties": [{"key": "$os", "value": "Chrome", "type": "person"}]}], ) recalculate_cohortpeople(cohort, pending_version=0) response = execute_hogql_query( @@ -100,5 +106,8 @@ def test_in_cohort_error(self): self.assertEqual(str(e.exception), "cohort() takes exactly one string or integer argument") with self.assertRaises(HogQLException) as e: - execute_hogql_query(f"SELECT event FROM events WHERE person_id IN COHORT 'blabla'", self.team) + execute_hogql_query( + f"SELECT event FROM events WHERE person_id IN COHORT 'blabla'", + self.team, + ) self.assertEqual(str(e.exception), "Could not find a cohort with the name 'blabla'") diff --git a/posthog/hogql/functions/test/test_sparkline.py b/posthog/hogql/functions/test/test_sparkline.py index febffcf2b8948..2a5c24d90b1af 100644 --- a/posthog/hogql/functions/test/test_sparkline.py +++ b/posthog/hogql/functions/test/test_sparkline.py @@ -14,7 +14,10 @@ def test_sparkline(self): response.hogql, f"SELECT tuple('__hogql_chart_type', 'sparkline', 'results', [1, 2, 3]) LIMIT 100", ) - self.assertEqual(response.results[0][0], ("__hogql_chart_type", "sparkline", "results", [1, 2, 3])) + self.assertEqual( + response.results[0][0], + ("__hogql_chart_type", "sparkline", "results", [1, 2, 3]), + ) def test_sparkline_error(self): with self.assertRaises(HogQLException) as e: diff --git a/posthog/hogql/hogql.py b/posthog/hogql/hogql.py index 87a2e0ee8f47e..6410bdc6a7d46 100644 --- a/posthog/hogql/hogql.py +++ b/posthog/hogql/hogql.py @@ -3,7 +3,11 @@ from posthog.hogql import ast from posthog.hogql.context import HogQLContext from posthog.hogql.database.database import create_hogql_database -from posthog.hogql.errors import HogQLException, NotImplementedException, SyntaxException +from posthog.hogql.errors import ( + HogQLException, + NotImplementedException, + SyntaxException, +) from posthog.hogql.parser import parse_expr from posthog.hogql.printer import prepare_ast_for_printing, print_prepared_ast @@ -38,7 +42,10 @@ def translate_hogql( prepare_ast_for_printing(select_query, context=context, dialect=dialect, stack=[select_query]), ) return print_prepared_ast( - prepared_select_query.select[0], context=context, dialect=dialect, stack=[prepared_select_query] + prepared_select_query.select[0], + context=context, + dialect=dialect, + stack=[prepared_select_query], ) except (NotImplementedException, SyntaxException): raise diff --git a/posthog/hogql/metadata.py b/posthog/hogql/metadata.py index de044ed2c4743..29a9b11075ab0 100644 --- a/posthog/hogql/metadata.py +++ b/posthog/hogql/metadata.py @@ -31,7 +31,9 @@ def get_hogql_metadata( translate_hogql(query.expr, context=context, table=query.table or "events") elif isinstance(query.select, str): context = HogQLContext( - team_id=team.pk, modifiers=create_default_modifiers_for_team(team), enable_select_queries=True + team_id=team.pk, + modifiers=create_default_modifiers_for_team(team), + enable_select_queries=True, ) select_ast = parse_select(query.select) diff --git a/posthog/hogql/parser.py b/posthog/hogql/parser.py index cacae5eefec95..d1d8ef2a1b7a7 100644 --- a/posthog/hogql/parser.py +++ b/posthog/hogql/parser.py @@ -7,7 +7,11 @@ from posthog.hogql import ast from posthog.hogql.base import AST from posthog.hogql.constants import RESERVED_KEYWORDS -from posthog.hogql.errors import NotImplementedException, HogQLException, SyntaxException +from posthog.hogql.errors import ( + NotImplementedException, + HogQLException, + SyntaxException, +) from posthog.hogql.grammar.HogQLLexer import HogQLLexer from posthog.hogql.grammar.HogQLParser import HogQLParser from posthog.hogql.parse_string import parse_string, parse_string_literal @@ -211,7 +215,11 @@ def visitSelectStmt(self, ctx: HogQLParser.SelectStmtContext): select_query.array_join_list = self.visit(array_join_clause.columnExprList()) for expr in select_query.array_join_list: if not isinstance(expr, ast.Alias): - raise SyntaxException("ARRAY JOIN arrays must have an alias", start=expr.start, end=expr.end) + raise SyntaxException( + "ARRAY JOIN arrays must have an alias", + start=expr.start, + end=expr.end, + ) if ctx.topClause(): raise NotImplementedException(f"Unsupported: SelectStmt.topClause()") @@ -382,7 +390,8 @@ def visitRatioExpr(self, ctx: HogQLParser.RatioExprContext): right = number_literals[1] if ctx.SLASH() and len(number_literals) > 1 else None return ast.RatioExpr( - left=self.visitNumberLiteral(left), right=self.visitNumberLiteral(right) if right else None + left=self.visitNumberLiteral(left), + right=self.visitNumberLiteral(right) if right else None, ) def visitSettingExprList(self, ctx: HogQLParser.SettingExprListContext): @@ -455,7 +464,11 @@ def visitColumnExprList(self, ctx: HogQLParser.ColumnExprListContext): def visitColumnExprTernaryOp(self, ctx: HogQLParser.ColumnExprTernaryOpContext): return ast.Call( name="if", - args=[self.visit(ctx.columnExpr(0)), self.visit(ctx.columnExpr(1)), self.visit(ctx.columnExpr(2))], + args=[ + self.visit(ctx.columnExpr(0)), + self.visit(ctx.columnExpr(1)), + self.visit(ctx.columnExpr(2)), + ], ) def visitColumnExprAlias(self, ctx: HogQLParser.ColumnExprAliasContext): @@ -480,7 +493,9 @@ def visitColumnExprExtract(self, ctx: HogQLParser.ColumnExprExtractContext): def visitColumnExprNegate(self, ctx: HogQLParser.ColumnExprNegateContext): return ast.ArithmeticOperation( - op=ast.ArithmeticOperationOp.Sub, left=ast.Constant(value=0), right=self.visit(ctx.columnExpr()) + op=ast.ArithmeticOperationOp.Sub, + left=ast.Constant(value=0), + right=self.visit(ctx.columnExpr()), ) def visitColumnExprSubquery(self, ctx: HogQLParser.ColumnExprSubqueryContext): @@ -737,7 +752,8 @@ def visitColumnArgExpr(self, ctx: HogQLParser.ColumnArgExprContext): def visitColumnLambdaExpr(self, ctx: HogQLParser.ColumnLambdaExprContext): return ast.Lambda( - args=[self.visit(identifier) for identifier in ctx.identifier()], expr=self.visit(ctx.columnExpr()) + args=[self.visit(identifier) for identifier in ctx.identifier()], + expr=self.visit(ctx.columnExpr()), ) def visitWithExprList(self, ctx: HogQLParser.WithExprListContext): @@ -863,4 +879,7 @@ def visitEnumValue(self, ctx: HogQLParser.EnumValueContext): raise NotImplementedException(f"Unsupported node: EnumValue") def visitColumnExprNullish(self, ctx: HogQLParser.ColumnExprNullishContext): - return ast.Call(name="ifNull", args=[self.visit(ctx.columnExpr(0)), self.visit(ctx.columnExpr(1))]) + return ast.Call( + name="ifNull", + args=[self.visit(ctx.columnExpr(0)), self.visit(ctx.columnExpr(1))], + ) diff --git a/posthog/hogql/printer.py b/posthog/hogql/printer.py index dae5a1a0c610c..a2a541b3b0b41 100644 --- a/posthog/hogql/printer.py +++ b/posthog/hogql/printer.py @@ -75,7 +75,12 @@ def print_ast( ) -> str: prepared_ast = prepare_ast_for_printing(node=node, context=context, dialect=dialect, stack=stack, settings=settings) return print_prepared_ast( - node=prepared_ast, context=context, dialect=dialect, stack=stack, settings=settings, pretty=pretty + node=prepared_ast, + context=context, + dialect=dialect, + stack=stack, + settings=settings, + pretty=pretty, ) @@ -122,9 +127,13 @@ def print_prepared_ast( ) -> str: with context.timings.measure("printer"): # _Printer also adds a team_id guard if printing clickhouse - return _Printer(context=context, dialect=dialect, stack=stack or [], settings=settings, pretty=pretty).visit( - node - ) + return _Printer( + context=context, + dialect=dialect, + stack=stack or [], + settings=settings, + pretty=pretty, + ).visit(node) @dataclass @@ -239,7 +248,11 @@ def visit_select_query(self, node: ast.SelectQuery): array_join = "" if node.array_join_op is not None: - if node.array_join_op not in ("ARRAY JOIN", "LEFT ARRAY JOIN", "INNER ARRAY JOIN"): + if node.array_join_op not in ( + "ARRAY JOIN", + "LEFT ARRAY JOIN", + "INNER ARRAY JOIN", + ): raise HogQLException(f"Invalid ARRAY JOIN operation: {node.array_join_op}") array_join = node.array_join_op if len(node.array_join_list) == 0: @@ -267,7 +280,10 @@ def visit_select_query(self, node: ast.SelectQuery): if isinstance(limit, ast.Constant) and isinstance(limit.value, int): limit.value = min(limit.value, MAX_SELECT_RETURNED_ROWS) else: - limit = ast.Call(name="min2", args=[ast.Constant(value=MAX_SELECT_RETURNED_ROWS), limit]) + limit = ast.Call( + name="min2", + args=[ast.Constant(value=MAX_SELECT_RETURNED_ROWS), limit], + ) else: limit = ast.Constant(value=MAX_SELECT_RETURNED_ROWS) @@ -643,7 +659,11 @@ def visit_call(self, node: ast.Call): func_meta = HOGQL_AGGREGATIONS[node.name] validate_function_args( - node.args, func_meta.min_args, func_meta.max_args, node.name, function_term="aggregation" + node.args, + func_meta.min_args, + func_meta.max_args, + node.name, + function_term="aggregation", ) if func_meta.min_params: if node.params is None: @@ -679,7 +699,11 @@ def visit_call(self, node: ast.Call): if node.params is None: raise HogQLException(f"Function '{node.name}' requires parameters in addition to arguments") validate_function_args( - node.params, func_meta.min_params, func_meta.max_params, node.name, argument_term="parameter" + node.params, + func_meta.min_params, + func_meta.max_params, + node.name, + argument_term="parameter", ) if self.dialect == "clickhouse": @@ -725,7 +749,10 @@ def visit_call(self, node: ast.Call): ) if first_arg_constant_type is not None: - for overload_types, overload_clickhouse_name in func_meta.overloads: + for ( + overload_types, + overload_clickhouse_name, + ) in func_meta.overloads: if isinstance(first_arg_constant_type, overload_types): relevant_clickhouse_name = overload_clickhouse_name break # Found an overload matching the first function org @@ -803,7 +830,8 @@ def visit_field_type(self, type: ast.FieldType): return self.visit( ast.AsteriskType( table_type=ast.TableAliasType( - table_type=ast.TableType(table=resolved_field), alias=type.table_type.alias + table_type=ast.TableType(table=resolved_field), + alias=type.table_type.alias, ) ) ) diff --git a/posthog/hogql/property.py b/posthog/hogql/property.py index c0341461e1293..9d619c23175b6 100644 --- a/posthog/hogql/property.py +++ b/posthog/hogql/property.py @@ -10,12 +10,24 @@ from posthog.hogql.errors import NotImplementedException from posthog.hogql.parser import parse_expr from posthog.hogql.visitor import TraversingVisitor, clone_expr -from posthog.models import Action, ActionStep, Cohort, Property, Team, PropertyDefinition +from posthog.models import ( + Action, + ActionStep, + Cohort, + Property, + Team, + PropertyDefinition, +) from posthog.models.event import Selector from posthog.models.property import PropertyGroup from posthog.models.property.util import build_selector_regex from posthog.models.property_definition import PropertyType -from posthog.schema import PropertyOperator, PropertyGroupFilter, PropertyGroupFilterValue, FilterLogicalOperator +from posthog.schema import ( + PropertyOperator, + PropertyGroupFilter, + PropertyGroupFilterValue, + FilterLogicalOperator, +) def has_aggregation(expr: AST) -> bool: @@ -116,7 +128,14 @@ def property_to_expr( else: exprs = [ property_to_expr( - Property(type=property.type, key=property.key, operator=property.operator, value=v), team, scope + Property( + type=property.type, + key=property.key, + operator=property.operator, + value=v, + ), + team, + scope, ) for v in value ] @@ -133,12 +152,25 @@ def property_to_expr( properties_field = ast.Field(chain=chain) if operator == PropertyOperator.is_set: - return ast.CompareOperation(op=ast.CompareOperationOp.NotEq, left=field, right=ast.Constant(value=None)) + return ast.CompareOperation( + op=ast.CompareOperationOp.NotEq, + left=field, + right=ast.Constant(value=None), + ) elif operator == PropertyOperator.is_not_set: return ast.Or( exprs=[ - ast.CompareOperation(op=ast.CompareOperationOp.Eq, left=field, right=ast.Constant(value=None)), - ast.Not(expr=ast.Call(name="JSONHas", args=[properties_field, ast.Constant(value=property.key)])), + ast.CompareOperation( + op=ast.CompareOperationOp.Eq, + left=field, + right=ast.Constant(value=None), + ), + ast.Not( + expr=ast.Call( + name="JSONHas", + args=[properties_field, ast.Constant(value=property.key)], + ) + ), ] ) elif operator == PropertyOperator.icontains: @@ -156,7 +188,10 @@ def property_to_expr( elif operator == PropertyOperator.regex: return ast.Call(name="match", args=[field, ast.Constant(value=value)]) elif operator == PropertyOperator.not_regex: - return ast.Call(name="not", args=[ast.Call(name="match", args=[field, ast.Constant(value=value)])]) + return ast.Call( + name="not", + args=[ast.Call(name="match", args=[field, ast.Constant(value=value)])], + ) elif operator == PropertyOperator.exact or operator == PropertyOperator.is_date_exact: op = ast.CompareOperationOp.Eq elif operator == PropertyOperator.is_not: @@ -207,7 +242,14 @@ def property_to_expr( else: exprs = [ property_to_expr( - Property(type=property.type, key=property.key, operator=property.operator, value=v), team, scope + Property( + type=property.type, + key=property.key, + operator=property.operator, + value=v, + ), + team, + scope, ) for v in value ] @@ -287,11 +329,20 @@ def action_to_expr(action: Action) -> ast.Expr: if step.url: if step.url_matching == ActionStep.EXACT: - expr = parse_expr("properties.$current_url = {url}", {"url": ast.Constant(value=step.url)}) + expr = parse_expr( + "properties.$current_url = {url}", + {"url": ast.Constant(value=step.url)}, + ) elif step.url_matching == ActionStep.REGEX: - expr = parse_expr("properties.$current_url =~ {regex}", {"regex": ast.Constant(value=step.url)}) + expr = parse_expr( + "properties.$current_url =~ {regex}", + {"regex": ast.Constant(value=step.url)}, + ) else: - expr = parse_expr("properties.$current_url like {url}", {"url": ast.Constant(value=f"%{step.url}%")}) + expr = parse_expr( + "properties.$current_url like {url}", + {"url": ast.Constant(value=f"%{step.url}%")}, + ) exprs.append(expr) if step.properties: diff --git a/posthog/hogql/query.py b/posthog/hogql/query.py index 723476b0ab5e4..697305d0ae964 100644 --- a/posthog/hogql/query.py +++ b/posthog/hogql/query.py @@ -8,7 +8,11 @@ from posthog.hogql.modifiers import create_default_modifiers_for_team from posthog.hogql.parser import parse_select from posthog.hogql.placeholders import replace_placeholders, find_placeholders -from posthog.hogql.printer import prepare_ast_for_printing, print_ast, print_prepared_ast +from posthog.hogql.printer import ( + prepare_ast_for_printing, + print_ast, + print_prepared_ast, +) from posthog.hogql.filters import replace_filters from posthog.hogql.timings import HogQLTimings from posthog.hogql.visitor import clone_expr @@ -61,7 +65,10 @@ def execute_hogql_query( select_query = replace_placeholders(select_query, placeholders) with timings.measure("max_limit"): - from posthog.hogql.constants import DEFAULT_RETURNED_ROWS, MAX_SELECT_RETURNED_ROWS + from posthog.hogql.constants import ( + DEFAULT_RETURNED_ROWS, + MAX_SELECT_RETURNED_ROWS, + ) select_queries = ( select_query.select_queries if isinstance(select_query, ast.SelectUnionQuery) else [select_query] @@ -104,7 +111,10 @@ def execute_hogql_query( else: print_columns.append( print_prepared_ast( - node=node, context=hogql_query_context, dialect="hogql", stack=[select_query_hogql] + node=node, + context=hogql_query_context, + dialect="hogql", + stack=[select_query_hogql], ) ) @@ -117,7 +127,10 @@ def execute_hogql_query( modifiers=query_modifiers, ) clickhouse_sql = print_ast( - select_query, context=clickhouse_context, dialect="clickhouse", settings=settings or HogQLGlobalSettings() + select_query, + context=clickhouse_context, + dialect="clickhouse", + settings=settings or HogQLGlobalSettings(), ) timings_dict = timings.to_dict() diff --git a/posthog/hogql/resolver.py b/posthog/hogql/resolver.py index b2e94b4c6893d..8d971084aa583 100644 --- a/posthog/hogql/resolver.py +++ b/posthog/hogql/resolver.py @@ -6,7 +6,12 @@ from posthog.hogql.ast import FieldTraverserType, ConstantType from posthog.hogql.functions import HOGQL_POSTHOG_FUNCTIONS, cohort from posthog.hogql.context import HogQLContext -from posthog.hogql.database.models import StringJSONDatabaseField, FunctionCallTable, LazyTable, SavedQuery +from posthog.hogql.database.models import ( + StringJSONDatabaseField, + FunctionCallTable, + LazyTable, + SavedQuery, +) from posthog.hogql.errors import ResolverException from posthog.hogql.functions.mapping import validate_function_args from posthog.hogql.functions.sparkline import sparkline @@ -48,7 +53,9 @@ def resolve_constant_data_type(constant: Any) -> ConstantType: def resolve_types( - node: ast.Expr, context: HogQLContext, scopes: Optional[List[ast.SelectQueryType]] = None + node: ast.Expr, + context: HogQLContext, + scopes: Optional[List[ast.SelectQueryType]] = None, ) -> ast.Expr: return Resolver(scopes=scopes, context=context).visit(node) @@ -332,7 +339,10 @@ def visit_call(self, node: ast.Call): else: param_types.append(ast.UnknownType()) node.type = ast.CallType( - name=node.name, arg_types=arg_types, param_types=param_types, return_type=ast.UnknownType() + name=node.name, + arg_types=arg_types, + param_types=param_types, + return_type=ast.UnknownType(), ) return node @@ -454,7 +464,10 @@ def visit_array_access(self, node: ast.ArrayAccess): (isinstance(node.array.type, ast.PropertyType)) or ( isinstance(node.array.type, ast.FieldType) - and isinstance(node.array.type.resolve_database_field(), StringJSONDatabaseField) + and isinstance( + node.array.type.resolve_database_field(), + StringJSONDatabaseField, + ) ) ) ): diff --git a/posthog/hogql/test/_test_parser.py b/posthog/hogql/test/_test_parser.py index 765d4fbaab4de..9b5fa20dcf910 100644 --- a/posthog/hogql/test/_test_parser.py +++ b/posthog/hogql/test/_test_parser.py @@ -57,7 +57,9 @@ def test_conditional(self): name="if", args=[ ast.CompareOperation( - op=ast.CompareOperationOp.Gt, left=ast.Constant(value=1), right=ast.Constant(value=2) + op=ast.CompareOperationOp.Gt, + left=ast.Constant(value=1), + right=ast.Constant(value=2), ), ast.Constant(value=1), ast.Constant(value=2), @@ -69,11 +71,15 @@ def test_arrays(self): self.assertEqual(self._expr("[]"), ast.Array(exprs=[])) self.assertEqual(self._expr("[1]"), ast.Array(exprs=[ast.Constant(value=1)])) self.assertEqual( - self._expr("[1, avg()]"), ast.Array(exprs=[ast.Constant(value=1), ast.Call(name="avg", args=[])]) + self._expr("[1, avg()]"), + ast.Array(exprs=[ast.Constant(value=1), ast.Call(name="avg", args=[])]), ) self.assertEqual( self._expr("properties['value']"), - ast.ArrayAccess(array=ast.Field(chain=["properties"]), property=ast.Constant(value="value")), + ast.ArrayAccess( + array=ast.Field(chain=["properties"]), + property=ast.Constant(value="value"), + ), ) self.assertEqual( self._expr("properties[(select 'value')]"), @@ -98,7 +104,8 @@ def test_arrays(self): def test_tuples(self): self.assertEqual( - self._expr("(1, avg())"), ast.Tuple(exprs=[ast.Constant(value=1), ast.Call(name="avg", args=[])]) + self._expr("(1, avg())"), + ast.Tuple(exprs=[ast.Constant(value=1), ast.Call(name="avg", args=[])]), ) # needs at least two values to be a tuple self.assertEqual(self._expr("(1)"), ast.Constant(value=1)) @@ -165,44 +172,58 @@ def test_arithmetic_operations(self): self.assertEqual( self._expr("1 + 2"), ast.ArithmeticOperation( - left=ast.Constant(value=1), right=ast.Constant(value=2), op=ast.ArithmeticOperationOp.Add + left=ast.Constant(value=1), + right=ast.Constant(value=2), + op=ast.ArithmeticOperationOp.Add, ), ) self.assertEqual( self._expr("1 + -2"), ast.ArithmeticOperation( - left=ast.Constant(value=1), right=ast.Constant(value=-2), op=ast.ArithmeticOperationOp.Add + left=ast.Constant(value=1), + right=ast.Constant(value=-2), + op=ast.ArithmeticOperationOp.Add, ), ) self.assertEqual( self._expr("1 - 2"), ast.ArithmeticOperation( - left=ast.Constant(value=1), right=ast.Constant(value=2), op=ast.ArithmeticOperationOp.Sub + left=ast.Constant(value=1), + right=ast.Constant(value=2), + op=ast.ArithmeticOperationOp.Sub, ), ) self.assertEqual( self._expr("1 * 2"), ast.ArithmeticOperation( - left=ast.Constant(value=1), right=ast.Constant(value=2), op=ast.ArithmeticOperationOp.Mult + left=ast.Constant(value=1), + right=ast.Constant(value=2), + op=ast.ArithmeticOperationOp.Mult, ), ) self.assertEqual( self._expr("1 / 2"), ast.ArithmeticOperation( - left=ast.Constant(value=1), right=ast.Constant(value=2), op=ast.ArithmeticOperationOp.Div + left=ast.Constant(value=1), + right=ast.Constant(value=2), + op=ast.ArithmeticOperationOp.Div, ), ) self.assertEqual( self._expr("1 % 2"), ast.ArithmeticOperation( - left=ast.Constant(value=1), right=ast.Constant(value=2), op=ast.ArithmeticOperationOp.Mod + left=ast.Constant(value=1), + right=ast.Constant(value=2), + op=ast.ArithmeticOperationOp.Mod, ), ) self.assertEqual( self._expr("1 + 2 + 2"), ast.ArithmeticOperation( left=ast.ArithmeticOperation( - left=ast.Constant(value=1), right=ast.Constant(value=2), op=ast.ArithmeticOperationOp.Add + left=ast.Constant(value=1), + right=ast.Constant(value=2), + op=ast.ArithmeticOperationOp.Add, ), right=ast.Constant(value=2), op=ast.ArithmeticOperationOp.Add, @@ -212,7 +233,9 @@ def test_arithmetic_operations(self): self._expr("1 * 1 * 2"), ast.ArithmeticOperation( left=ast.ArithmeticOperation( - left=ast.Constant(value=1), right=ast.Constant(value=1), op=ast.ArithmeticOperationOp.Mult + left=ast.Constant(value=1), + right=ast.Constant(value=1), + op=ast.ArithmeticOperationOp.Mult, ), right=ast.Constant(value=2), op=ast.ArithmeticOperationOp.Mult, @@ -223,7 +246,9 @@ def test_arithmetic_operations(self): ast.ArithmeticOperation( left=ast.Constant(value=1), right=ast.ArithmeticOperation( - left=ast.Constant(value=1), right=ast.Constant(value=2), op=ast.ArithmeticOperationOp.Mult + left=ast.Constant(value=1), + right=ast.Constant(value=2), + op=ast.ArithmeticOperationOp.Mult, ), op=ast.ArithmeticOperationOp.Add, ), @@ -232,7 +257,9 @@ def test_arithmetic_operations(self): self._expr("1 * 1 + 2"), ast.ArithmeticOperation( left=ast.ArithmeticOperation( - left=ast.Constant(value=1), right=ast.Constant(value=1), op=ast.ArithmeticOperationOp.Mult + left=ast.Constant(value=1), + right=ast.Constant(value=1), + op=ast.ArithmeticOperationOp.Mult, ), right=ast.Constant(value=2), op=ast.ArithmeticOperationOp.Add, @@ -243,43 +270,57 @@ def test_math_comparison_operations(self): self.assertEqual( self._expr("1 = 2"), ast.CompareOperation( - left=ast.Constant(value=1), right=ast.Constant(value=2), op=ast.CompareOperationOp.Eq + left=ast.Constant(value=1), + right=ast.Constant(value=2), + op=ast.CompareOperationOp.Eq, ), ) self.assertEqual( self._expr("1 == 2"), ast.CompareOperation( - left=ast.Constant(value=1), right=ast.Constant(value=2), op=ast.CompareOperationOp.Eq + left=ast.Constant(value=1), + right=ast.Constant(value=2), + op=ast.CompareOperationOp.Eq, ), ) self.assertEqual( self._expr("1 != 2"), ast.CompareOperation( - left=ast.Constant(value=1), right=ast.Constant(value=2), op=ast.CompareOperationOp.NotEq + left=ast.Constant(value=1), + right=ast.Constant(value=2), + op=ast.CompareOperationOp.NotEq, ), ) self.assertEqual( self._expr("1 < 2"), ast.CompareOperation( - left=ast.Constant(value=1), right=ast.Constant(value=2), op=ast.CompareOperationOp.Lt + left=ast.Constant(value=1), + right=ast.Constant(value=2), + op=ast.CompareOperationOp.Lt, ), ) self.assertEqual( self._expr("1 <= 2"), ast.CompareOperation( - left=ast.Constant(value=1), right=ast.Constant(value=2), op=ast.CompareOperationOp.LtEq + left=ast.Constant(value=1), + right=ast.Constant(value=2), + op=ast.CompareOperationOp.LtEq, ), ) self.assertEqual( self._expr("1 > 2"), ast.CompareOperation( - left=ast.Constant(value=1), right=ast.Constant(value=2), op=ast.CompareOperationOp.Gt + left=ast.Constant(value=1), + right=ast.Constant(value=2), + op=ast.CompareOperationOp.Gt, ), ) self.assertEqual( self._expr("1 >= 2"), ast.CompareOperation( - left=ast.Constant(value=1), right=ast.Constant(value=2), op=ast.CompareOperationOp.GtEq + left=ast.Constant(value=1), + right=ast.Constant(value=2), + op=ast.CompareOperationOp.GtEq, ), ) @@ -287,13 +328,17 @@ def test_null_comparison_operations(self): self.assertEqual( self._expr("1 is null"), ast.CompareOperation( - left=ast.Constant(value=1), right=ast.Constant(value=None), op=ast.CompareOperationOp.Eq + left=ast.Constant(value=1), + right=ast.Constant(value=None), + op=ast.CompareOperationOp.Eq, ), ) self.assertEqual( self._expr("1 is not null"), ast.CompareOperation( - left=ast.Constant(value=1), right=ast.Constant(value=None), op=ast.CompareOperationOp.NotEq + left=ast.Constant(value=1), + right=ast.Constant(value=None), + op=ast.CompareOperationOp.NotEq, ), ) @@ -301,25 +346,33 @@ def test_like_comparison_operations(self): self.assertEqual( self._expr("1 like 'a%sd'"), ast.CompareOperation( - left=ast.Constant(value=1), right=ast.Constant(value="a%sd"), op=ast.CompareOperationOp.Like + left=ast.Constant(value=1), + right=ast.Constant(value="a%sd"), + op=ast.CompareOperationOp.Like, ), ) self.assertEqual( self._expr("1 not like 'a%sd'"), ast.CompareOperation( - left=ast.Constant(value=1), right=ast.Constant(value="a%sd"), op=ast.CompareOperationOp.NotLike + left=ast.Constant(value=1), + right=ast.Constant(value="a%sd"), + op=ast.CompareOperationOp.NotLike, ), ) self.assertEqual( self._expr("1 ilike 'a%sd'"), ast.CompareOperation( - left=ast.Constant(value=1), right=ast.Constant(value="a%sd"), op=ast.CompareOperationOp.ILike + left=ast.Constant(value=1), + right=ast.Constant(value="a%sd"), + op=ast.CompareOperationOp.ILike, ), ) self.assertEqual( self._expr("1 not ilike 'a%sd'"), ast.CompareOperation( - left=ast.Constant(value=1), right=ast.Constant(value="a%sd"), op=ast.CompareOperationOp.NotILike + left=ast.Constant(value=1), + right=ast.Constant(value="a%sd"), + op=ast.CompareOperationOp.NotILike, ), ) @@ -335,7 +388,10 @@ def test_and_or(self): self.assertEqual( self._expr("true and not false"), ast.And( - exprs=[ast.Constant(value=True), ast.Not(expr=ast.Constant(value=False))], + exprs=[ + ast.Constant(value=True), + ast.Not(expr=ast.Constant(value=False)), + ], ), ) self.assertEqual( @@ -355,7 +411,10 @@ def test_and_or(self): exprs=[ ast.Constant(value=True), ast.And( - exprs=[ast.Constant(value=False), ast.Not(expr=ast.Constant(value=True))], + exprs=[ + ast.Constant(value=False), + ast.Not(expr=ast.Constant(value=True)), + ], ), ast.Constant(value=2), ], @@ -376,7 +435,9 @@ def test_parens(self): self.assertEqual( self._expr("(1 + 1)"), ast.ArithmeticOperation( - left=ast.Constant(value=1), right=ast.Constant(value=1), op=ast.ArithmeticOperationOp.Add + left=ast.Constant(value=1), + right=ast.Constant(value=1), + op=ast.ArithmeticOperationOp.Add, ), ) self.assertEqual( @@ -384,7 +445,9 @@ def test_parens(self): ast.ArithmeticOperation( left=ast.Constant(value=1), right=ast.ArithmeticOperation( - left=ast.Constant(value=1), right=ast.Constant(value=1), op=ast.ArithmeticOperationOp.Add + left=ast.Constant(value=1), + right=ast.Constant(value=1), + op=ast.ArithmeticOperationOp.Add, ), op=ast.ArithmeticOperationOp.Add, ), @@ -398,7 +461,9 @@ def test_field_access(self): self.assertEqual( self._expr("event like '$%'"), ast.CompareOperation( - left=ast.Field(chain=["event"]), right=ast.Constant(value="$%"), op=ast.CompareOperationOp.Like + left=ast.Field(chain=["event"]), + right=ast.Constant(value="$%"), + op=ast.CompareOperationOp.Like, ), ) @@ -435,13 +500,24 @@ def test_calls(self): ) self.assertEqual( self._expr("avg(1,2,3)"), - ast.Call(name="avg", args=[ast.Constant(value=1), ast.Constant(value=2), ast.Constant(value=3)]), + ast.Call( + name="avg", + args=[ + ast.Constant(value=1), + ast.Constant(value=2), + ast.Constant(value=3), + ], + ), ) def test_calls_with_params(self): self.assertEqual( self._expr("quantile(0.95)(foo)"), - ast.Call(name="quantile", args=[ast.Field(chain=["foo"])], params=[ast.Constant(value=0.95)]), + ast.Call( + name="quantile", + args=[ast.Field(chain=["foo"])], + params=[ast.Constant(value=0.95)], + ), ) def test_alias(self): @@ -513,15 +589,25 @@ def test_intervals(self): ) def test_select_columns(self): - self.assertEqual(self._select("select 1"), ast.SelectQuery(select=[ast.Constant(value=1)])) + self.assertEqual( + self._select("select 1"), + ast.SelectQuery(select=[ast.Constant(value=1)]), + ) self.assertEqual( self._select("select 1, 4, 'string'"), - ast.SelectQuery(select=[ast.Constant(value=1), ast.Constant(value=4), ast.Constant(value="string")]), + ast.SelectQuery( + select=[ + ast.Constant(value=1), + ast.Constant(value=4), + ast.Constant(value="string"), + ] + ), ) def test_select_columns_distinct(self): self.assertEqual( - self._select("select distinct 1"), ast.SelectQuery(select=[ast.Constant(value=1)], distinct=True) + self._select("select distinct 1"), + ast.SelectQuery(select=[ast.Constant(value=1)], distinct=True), ) def test_select_where(self): @@ -534,7 +620,9 @@ def test_select_where(self): ast.SelectQuery( select=[ast.Constant(value=1)], where=ast.CompareOperation( - op=ast.CompareOperationOp.Eq, left=ast.Constant(value=1), right=ast.Constant(value=2) + op=ast.CompareOperationOp.Eq, + left=ast.Constant(value=1), + right=ast.Constant(value=2), ), ), ) @@ -549,7 +637,9 @@ def test_select_prewhere(self): ast.SelectQuery( select=[ast.Constant(value=1)], prewhere=ast.CompareOperation( - op=ast.CompareOperationOp.Eq, left=ast.Constant(value=1), right=ast.Constant(value=2) + op=ast.CompareOperationOp.Eq, + left=ast.Constant(value=1), + right=ast.Constant(value=2), ), ), ) @@ -564,7 +654,9 @@ def test_select_having(self): ast.SelectQuery( select=[ast.Constant(value=1)], having=ast.CompareOperation( - op=ast.CompareOperationOp.Eq, left=ast.Constant(value=1), right=ast.Constant(value=2) + op=ast.CompareOperationOp.Eq, + left=ast.Constant(value=1), + right=ast.Constant(value=2), ), ), ) @@ -575,10 +667,14 @@ def test_select_complex_wheres(self): ast.SelectQuery( select=[ast.Constant(value=1)], where=ast.CompareOperation( - op=ast.CompareOperationOp.Eq, left=ast.Constant(value=1), right=ast.Constant(value=2) + op=ast.CompareOperationOp.Eq, + left=ast.Constant(value=1), + right=ast.Constant(value=2), ), prewhere=ast.CompareOperation( - op=ast.CompareOperationOp.NotEq, left=ast.Constant(value=2), right=ast.Constant(value=3) + op=ast.CompareOperationOp.NotEq, + left=ast.Constant(value=2), + right=ast.Constant(value=3), ), having=ast.CompareOperation( op=ast.CompareOperationOp.Like, @@ -592,7 +688,8 @@ def test_select_from(self): self.assertEqual( self._select("select 1 from events"), ast.SelectQuery( - select=[ast.Constant(value=1)], select_from=ast.JoinExpr(table=ast.Field(chain=["events"])) + select=[ast.Constant(value=1)], + select_from=ast.JoinExpr(table=ast.Field(chain=["events"])), ), ) self.assertEqual( @@ -636,7 +733,8 @@ def test_select_from(self): select=[ast.Constant(value=1)], select_from=ast.JoinExpr( table=ast.SelectQuery( - select=[ast.Constant(value=1)], select_from=ast.JoinExpr(table=ast.Field(chain=["events"])) + select=[ast.Constant(value=1)], + select_from=ast.JoinExpr(table=ast.Field(chain=["events"])), ) ), ), @@ -647,7 +745,8 @@ def test_select_from(self): select=[ast.Constant(value=1)], select_from=ast.JoinExpr( table=ast.SelectQuery( - select=[ast.Constant(value=1)], select_from=ast.JoinExpr(table=ast.Field(chain=["events"])) + select=[ast.Constant(value=1)], + select_from=ast.JoinExpr(table=ast.Field(chain=["events"])), ), alias="sq", ), @@ -663,7 +762,10 @@ def test_select_from_placeholder(self): ), ) self.assertEqual( - self._select("select 1 from {placeholder}", {"placeholder": ast.Field(chain=["events"])}), + self._select( + "select 1 from {placeholder}", + {"placeholder": ast.Field(chain=["events"])}, + ), ast.SelectQuery( select=[ast.Constant(value=1)], select_from=ast.JoinExpr(table=ast.Field(chain=["events"])), @@ -830,7 +932,13 @@ def test_select_array_join(self): array_join_op="ARRAY JOIN", array_join_list=[ ast.Alias( - expr=ast.Array(exprs=[ast.Constant(value=1), ast.Constant(value=2), ast.Constant(value=3)]), + expr=ast.Array( + exprs=[ + ast.Constant(value=1), + ast.Constant(value=2), + ast.Constant(value=3), + ] + ), alias="a", ) ], @@ -844,7 +952,13 @@ def test_select_array_join(self): array_join_op="INNER ARRAY JOIN", array_join_list=[ ast.Alias( - expr=ast.Array(exprs=[ast.Constant(value=1), ast.Constant(value=2), ast.Constant(value=3)]), + expr=ast.Array( + exprs=[ + ast.Constant(value=1), + ast.Constant(value=2), + ast.Constant(value=3), + ] + ), alias="a", ) ], @@ -858,11 +972,23 @@ def test_select_array_join(self): array_join_op="LEFT ARRAY JOIN", array_join_list=[ ast.Alias( - expr=ast.Array(exprs=[ast.Constant(value=1), ast.Constant(value=2), ast.Constant(value=3)]), + expr=ast.Array( + exprs=[ + ast.Constant(value=1), + ast.Constant(value=2), + ast.Constant(value=3), + ] + ), alias="a", ), ast.Alias( - expr=ast.Array(exprs=[ast.Constant(value=4), ast.Constant(value=5), ast.Constant(value=6)]), + expr=ast.Array( + exprs=[ + ast.Constant(value=4), + ast.Constant(value=5), + ast.Constant(value=6), + ] + ), alias="b", ), ], @@ -878,7 +1004,10 @@ def test_select_array_join_errors(self): with self.assertRaises(HogQLException) as e: self._select("select a ARRAY JOIN [1,2,3]") - self.assertEqual(str(e.exception), "Using ARRAY JOIN without a FROM clause is not permitted") + self.assertEqual( + str(e.exception), + "Using ARRAY JOIN without a FROM clause is not permitted", + ) self.assertEqual(e.exception.start, 0) self.assertEqual(e.exception.end, 27) @@ -895,15 +1024,30 @@ def test_select_group_by(self): def test_order_by(self): self.assertEqual( parse_order_expr("1 ASC"), - ast.OrderExpr(expr=ast.Constant(value=1, start=0, end=1), order="ASC", start=0, end=5), + ast.OrderExpr( + expr=ast.Constant(value=1, start=0, end=1), + order="ASC", + start=0, + end=5, + ), ) self.assertEqual( parse_order_expr("event"), - ast.OrderExpr(expr=ast.Field(chain=["event"], start=0, end=5), order="ASC", start=0, end=5), + ast.OrderExpr( + expr=ast.Field(chain=["event"], start=0, end=5), + order="ASC", + start=0, + end=5, + ), ) self.assertEqual( parse_order_expr("timestamp DESC"), - ast.OrderExpr(expr=ast.Field(chain=["timestamp"], start=0, end=9), order="DESC", start=0, end=14), + ast.OrderExpr( + expr=ast.Field(chain=["timestamp"], start=0, end=9), + order="DESC", + start=0, + end=14, + ), ) def test_select_order_by(self): @@ -993,7 +1137,10 @@ def test_select_placeholders(self): ), ) self.assertEqual( - self._select("select 1 where 1 == {hogql_val_1}", {"hogql_val_1": ast.Constant(value="bar")}), + self._select( + "select 1 where 1 == {hogql_val_1}", + {"hogql_val_1": ast.Constant(value="bar")}, + ), ast.SelectQuery( select=[ast.Constant(value=1)], where=ast.CompareOperation( @@ -1082,7 +1229,13 @@ def test_select_with_columns(self): self.assertEqual( self._select("with event as boo select boo from events"), ast.SelectQuery( - ctes={"boo": ast.CTE(name="boo", expr=ast.Field(chain=["event"]), cte_type="column")}, + ctes={ + "boo": ast.CTE( + name="boo", + expr=ast.Field(chain=["event"]), + cte_type="column", + ) + }, select=[ast.Field(chain=["boo"])], select_from=ast.JoinExpr(table=ast.Field(chain=["events"])), ), @@ -1090,7 +1243,13 @@ def test_select_with_columns(self): self.assertEqual( self._select("with count() as kokku select kokku from events"), ast.SelectQuery( - ctes={"kokku": ast.CTE(name="kokku", expr=ast.Call(name="count", args=[]), cte_type="column")}, + ctes={ + "kokku": ast.CTE( + name="kokku", + expr=ast.Call(name="count", args=[]), + cte_type="column", + ) + }, select=[ast.Field(chain=["kokku"])], select_from=ast.JoinExpr(table=ast.Field(chain=["events"])), ), @@ -1169,7 +1328,14 @@ def test_ctes_subquery_recursion(self): def test_case_when(self): self.assertEqual( self._expr("case when 1 then 2 else 3 end"), - ast.Call(name="if", args=[ast.Constant(value=1), ast.Constant(value=2), ast.Constant(value=3)]), + ast.Call( + name="if", + args=[ + ast.Constant(value=1), + ast.Constant(value=2), + ast.Constant(value=3), + ], + ), ) def test_case_when_many(self): @@ -1214,7 +1380,12 @@ def test_window_functions(self): args=[ast.Field(chain=["timestamp"])], over_expr=ast.WindowExpr( partition_by=[ast.Field(chain=["person", "id"])], - order_by=[ast.OrderExpr(expr=ast.Field(chain=["timestamp"]), order="DESC")], + order_by=[ + ast.OrderExpr( + expr=ast.Field(chain=["timestamp"]), + order="DESC", + ) + ], frame_method="ROWS", frame_start=ast.WindowFrameExpr(frame_type="PRECEDING", frame_value=None), frame_end=ast.WindowFrameExpr(frame_type="PRECEDING", frame_value=1), @@ -1257,7 +1428,8 @@ def test_window_functions_with_window(self): def test_property_access_with_arrays_zero_index_error(self): query = f"SELECT properties.something[0] FROM events" with self.assertRaisesMessage( - SyntaxException, "SQL indexes start from one, not from zero. E.g: array[1]" + SyntaxException, + "SQL indexes start from one, not from zero. E.g: array[1]", ) as e: self._select(query) self.assertEqual(e.exception.start, 7) @@ -1266,7 +1438,8 @@ def test_property_access_with_arrays_zero_index_error(self): def test_property_access_with_tuples_zero_index_error(self): query = f"SELECT properties.something.0 FROM events" with self.assertRaisesMessage( - SyntaxException, "SQL indexes start from one, not from zero. E.g: array[1]" + SyntaxException, + "SQL indexes start from one, not from zero. E.g: array[1]", ) as e: self._select(query) self.assertEqual(e.exception.start, 7) @@ -1275,7 +1448,8 @@ def test_property_access_with_tuples_zero_index_error(self): def test_reserved_keyword_alias_error(self): query = f"SELECT 0 AS trUE FROM events" with self.assertRaisesMessage( - SyntaxException, '"trUE" cannot be an alias or identifier, as it\'s a reserved keyword' + SyntaxException, + '"trUE" cannot be an alias or identifier, as it\'s a reserved keyword', ) as e: self._select(query) self.assertEqual(e.exception.start, 7) @@ -1284,7 +1458,8 @@ def test_reserved_keyword_alias_error(self): def test_malformed_sql(self): query = "SELEC 2" with self.assertRaisesMessage( - SyntaxException, "mismatched input 'SELEC' expecting {SELECT, WITH, '('}" + SyntaxException, + "mismatched input 'SELEC' expecting {SELECT, WITH, '('}", ) as e: self._select(query) self.assertEqual(e.exception.start, 0) diff --git a/posthog/hogql/test/test_bytecode.py b/posthog/hogql/test/test_bytecode.py index bbd90608fe0c6..7fee12533d6da 100644 --- a/posthog/hogql/test/test_bytecode.py +++ b/posthog/hogql/test/test_bytecode.py @@ -11,20 +11,54 @@ def test_bytecode_create(self): self.assertEqual(to_bytecode("1 or 2"), [_H, op.INTEGER, 2, op.INTEGER, 1, op.OR, 2]) self.assertEqual( to_bytecode("1 or (2 and 1) or 2"), - [_H, op.INTEGER, 2, op.INTEGER, 1, op.INTEGER, 2, op.AND, 2, op.INTEGER, 1, op.OR, 3], + [ + _H, + op.INTEGER, + 2, + op.INTEGER, + 1, + op.INTEGER, + 2, + op.AND, + 2, + op.INTEGER, + 1, + op.OR, + 3, + ], ) self.assertEqual( to_bytecode("(1 or 2) and (1 or 2)"), - [_H, op.INTEGER, 2, op.INTEGER, 1, op.OR, 2, op.INTEGER, 2, op.INTEGER, 1, op.OR, 2, op.AND, 2], + [ + _H, + op.INTEGER, + 2, + op.INTEGER, + 1, + op.OR, + 2, + op.INTEGER, + 2, + op.INTEGER, + 1, + op.OR, + 2, + op.AND, + 2, + ], ) self.assertEqual(to_bytecode("not true"), [_H, op.TRUE, op.NOT]) self.assertEqual(to_bytecode("true"), [_H, op.TRUE]) self.assertEqual(to_bytecode("false"), [_H, op.FALSE]) self.assertEqual(to_bytecode("null"), [_H, op.NULL]) self.assertEqual(to_bytecode("3.14"), [_H, op.FLOAT, 3.14]) - self.assertEqual(to_bytecode("properties.bla"), [_H, op.STRING, "bla", op.STRING, "properties", op.FIELD, 2]) self.assertEqual( - to_bytecode("concat('arg', 'another')"), [_H, op.STRING, "another", op.STRING, "arg", op.CALL, "concat", 2] + to_bytecode("properties.bla"), + [_H, op.STRING, "bla", op.STRING, "properties", op.FIELD, 2], + ) + self.assertEqual( + to_bytecode("concat('arg', 'another')"), + [_H, op.STRING, "another", op.STRING, "arg", op.CALL, "concat", 2], ) self.assertEqual(to_bytecode("1 = 2"), [_H, op.INTEGER, 2, op.INTEGER, 1, op.EQ]) self.assertEqual(to_bytecode("1 == 2"), [_H, op.INTEGER, 2, op.INTEGER, 1, op.EQ]) @@ -36,32 +70,58 @@ def test_bytecode_create(self): self.assertEqual(to_bytecode("1 like 2"), [_H, op.INTEGER, 2, op.INTEGER, 1, op.LIKE]) self.assertEqual(to_bytecode("1 ilike 2"), [_H, op.INTEGER, 2, op.INTEGER, 1, op.ILIKE]) self.assertEqual(to_bytecode("1 not like 2"), [_H, op.INTEGER, 2, op.INTEGER, 1, op.NOT_LIKE]) - self.assertEqual(to_bytecode("1 not ilike 2"), [_H, op.INTEGER, 2, op.INTEGER, 1, op.NOT_ILIKE]) + self.assertEqual( + to_bytecode("1 not ilike 2"), + [_H, op.INTEGER, 2, op.INTEGER, 1, op.NOT_ILIKE], + ) self.assertEqual(to_bytecode("1 in 2"), [_H, op.INTEGER, 2, op.INTEGER, 1, op.IN]) self.assertEqual(to_bytecode("1 not in 2"), [_H, op.INTEGER, 2, op.INTEGER, 1, op.NOT_IN]) - self.assertEqual(to_bytecode("'string' ~ 'regex'"), [_H, op.STRING, "regex", op.STRING, "string", op.REGEX]) - self.assertEqual(to_bytecode("'string' =~ 'regex'"), [_H, op.STRING, "regex", op.STRING, "string", op.REGEX]) self.assertEqual( - to_bytecode("'string' !~ 'regex'"), [_H, op.STRING, "regex", op.STRING, "string", op.NOT_REGEX] + to_bytecode("'string' ~ 'regex'"), + [_H, op.STRING, "regex", op.STRING, "string", op.REGEX], + ) + self.assertEqual( + to_bytecode("'string' =~ 'regex'"), + [_H, op.STRING, "regex", op.STRING, "string", op.REGEX], + ) + self.assertEqual( + to_bytecode("'string' !~ 'regex'"), + [_H, op.STRING, "regex", op.STRING, "string", op.NOT_REGEX], ) - self.assertEqual(to_bytecode("'string' ~* 'regex'"), [_H, op.STRING, "regex", op.STRING, "string", op.IREGEX]) - self.assertEqual(to_bytecode("'string' =~* 'regex'"), [_H, op.STRING, "regex", op.STRING, "string", op.IREGEX]) self.assertEqual( - to_bytecode("'string' !~* 'regex'"), [_H, op.STRING, "regex", op.STRING, "string", op.NOT_IREGEX] + to_bytecode("'string' ~* 'regex'"), + [_H, op.STRING, "regex", op.STRING, "string", op.IREGEX], ) self.assertEqual( - to_bytecode("match('test', 'e.*')"), [_H, op.STRING, "e.*", op.STRING, "test", op.CALL, "match", 2] + to_bytecode("'string' =~* 'regex'"), + [_H, op.STRING, "regex", op.STRING, "string", op.IREGEX], ) self.assertEqual( - to_bytecode("match('test', '^e.*')"), [_H, op.STRING, "^e.*", op.STRING, "test", op.CALL, "match", 2] + to_bytecode("'string' !~* 'regex'"), + [_H, op.STRING, "regex", op.STRING, "string", op.NOT_IREGEX], ) self.assertEqual( - to_bytecode("match('test', 'x.*')"), [_H, op.STRING, "x.*", op.STRING, "test", op.CALL, "match", 2] + to_bytecode("match('test', 'e.*')"), + [_H, op.STRING, "e.*", op.STRING, "test", op.CALL, "match", 2], + ) + self.assertEqual( + to_bytecode("match('test', '^e.*')"), + [_H, op.STRING, "^e.*", op.STRING, "test", op.CALL, "match", 2], + ) + self.assertEqual( + to_bytecode("match('test', 'x.*')"), + [_H, op.STRING, "x.*", op.STRING, "test", op.CALL, "match", 2], ) self.assertEqual(to_bytecode("not('test')"), [_H, op.STRING, "test", op.NOT]) self.assertEqual(to_bytecode("not 'test'"), [_H, op.STRING, "test", op.NOT]) - self.assertEqual(to_bytecode("or('test', 'test2')"), [_H, op.STRING, "test2", op.STRING, "test", op.OR, 2]) - self.assertEqual(to_bytecode("and('test', 'test2')"), [_H, op.STRING, "test2", op.STRING, "test", op.AND, 2]) + self.assertEqual( + to_bytecode("or('test', 'test2')"), + [_H, op.STRING, "test2", op.STRING, "test", op.OR, 2], + ) + self.assertEqual( + to_bytecode("and('test', 'test2')"), + [_H, op.STRING, "test2", op.STRING, "test", op.AND, 2], + ) def test_bytecode_create_error(self): with self.assertRaises(NotImplementedException) as e: diff --git a/posthog/hogql/test/test_escape_sql.py b/posthog/hogql/test/test_escape_sql.py index 8f541f05aab40..0e24d8d8116f5 100644 --- a/posthog/hogql/test/test_escape_sql.py +++ b/posthog/hogql/test/test_escape_sql.py @@ -65,7 +65,10 @@ def test_sanitize_clickhouse_string(self): uuid = UUIDT() self.assertEqual(escape_clickhouse_string(uuid), f"toUUIDOrNull('{str(uuid)}')") date = datetime.fromisoformat("2020-02-02 02:02:02") - self.assertEqual(escape_clickhouse_string(date), "toDateTime64('2020-02-02 02:02:02.000000', 6, 'UTC')") + self.assertEqual( + escape_clickhouse_string(date), + "toDateTime64('2020-02-02 02:02:02.000000', 6, 'UTC')", + ) self.assertEqual( escape_clickhouse_string(date, timezone="Europe/Brussels"), "toDateTime64('2020-02-02 03:02:02.000000', 6, 'Europe/Brussels')", @@ -80,7 +83,10 @@ def test_sanitize_clickhouse_string(self): self.assertEqual(escape_clickhouse_string(float("123.123")), "123.123") self.assertEqual(escape_clickhouse_string(float("-123.123")), "-123.123") self.assertEqual(escape_clickhouse_string(float("0.000000000000000001")), "1e-18") - self.assertEqual(escape_clickhouse_string(float("234732482374928374923")), "2.3473248237492837e+20") + self.assertEqual( + escape_clickhouse_string(float("234732482374928374923")), + "2.3473248237492837e+20", + ) def test_sanitize_hogql_string(self): self.assertEqual(escape_hogql_string("a"), "'a'") @@ -101,7 +107,8 @@ def test_sanitize_hogql_string(self): date = datetime.fromisoformat("2020-02-02 02:02:02") self.assertEqual(escape_hogql_string(date), "toDateTime('2020-02-02 02:02:02.000000')") self.assertEqual( - escape_hogql_string(date, timezone="Europe/Brussels"), "toDateTime('2020-02-02 03:02:02.000000')" + escape_hogql_string(date, timezone="Europe/Brussels"), + "toDateTime('2020-02-02 03:02:02.000000')", ) self.assertEqual(escape_hogql_string(date.date()), "toDate('2020-02-02')") self.assertEqual(escape_hogql_string(1), "1") @@ -113,7 +120,10 @@ def test_sanitize_hogql_string(self): self.assertEqual(escape_hogql_string(float("123.123")), "123.123") self.assertEqual(escape_hogql_string(float("-123.123")), "-123.123") self.assertEqual(escape_hogql_string(float("0.000000000000000001")), "1e-18") - self.assertEqual(escape_hogql_string(float("234732482374928374923")), "2.3473248237492837e+20") + self.assertEqual( + escape_hogql_string(float("234732482374928374923")), + "2.3473248237492837e+20", + ) def test_escape_hogql_identifier_errors(self): with self.assertRaises(HogQLException) as context: diff --git a/posthog/hogql/test/test_filters.py b/posthog/hogql/test/test_filters.py index b7c20e67e4f7e..98b319bb31694 100644 --- a/posthog/hogql/test/test_filters.py +++ b/posthog/hogql/test/test_filters.py @@ -6,7 +6,12 @@ from posthog.hogql.parser import parse_expr, parse_select from posthog.hogql.printer import print_ast from posthog.hogql.visitor import clear_locations -from posthog.schema import HogQLFilters, EventPropertyFilter, PersonPropertyFilter, DateRange +from posthog.schema import ( + HogQLFilters, + EventPropertyFilter, + PersonPropertyFilter, + DateRange, +) from posthog.test.base import BaseTest @@ -20,14 +25,20 @@ def _parse_select(self, select: str, placeholders: Dict[str, Any] = None): return clear_locations(parse_select(select, placeholders=placeholders)) def _print_ast(self, node: ast.Expr): - return print_ast(node, dialect="hogql", context=HogQLContext(team_id=self.team.pk, enable_select_queries=True)) + return print_ast( + node, + dialect="hogql", + context=HogQLContext(team_id=self.team.pk, enable_select_queries=True), + ) def test_replace_filters(self): select = replace_filters(self._parse_select("SELECT event FROM events"), HogQLFilters(), self.team) self.assertEqual(self._print_ast(select), "SELECT event FROM events LIMIT 10000") select = replace_filters( - self._parse_select("SELECT event FROM events where {filters}"), HogQLFilters(), self.team + self._parse_select("SELECT event FROM events where {filters}"), + HogQLFilters(), + self.team, ) self.assertEqual(self._print_ast(select), "SELECT event FROM events WHERE true LIMIT 10000") @@ -59,7 +70,8 @@ def test_replace_filters(self): self.team, ) self.assertEqual( - self._print_ast(select), "SELECT event FROM events WHERE equals(properties.random_uuid, '123') LIMIT 10000" + self._print_ast(select), + "SELECT event FROM events WHERE equals(properties.random_uuid, '123') LIMIT 10000", ) select = replace_filters( diff --git a/posthog/hogql/test/test_metadata.py b/posthog/hogql/test/test_metadata.py index 46f9e13cc04f3..fe440243e909d 100644 --- a/posthog/hogql/test/test_metadata.py +++ b/posthog/hogql/test/test_metadata.py @@ -9,12 +9,14 @@ class TestMetadata(ClickhouseTestMixin, APIBaseTest): def _expr(self, query: str, table: str = "events") -> HogQLMetadataResponse: return get_hogql_metadata( - query=HogQLMetadata(kind="HogQLMetadata", expr=query, table=table, response=None), team=self.team + query=HogQLMetadata(kind="HogQLMetadata", expr=query, table=table, response=None), + team=self.team, ) def _select(self, query: str) -> HogQLMetadataResponse: return get_hogql_metadata( - query=HogQLMetadata(kind="HogQLMetadata", select=query, response=None), team=self.team + query=HogQLMetadata(kind="HogQLMetadata", select=query, response=None), + team=self.team, ) def test_metadata_valid_expr_select(self): @@ -26,7 +28,14 @@ def test_metadata_valid_expr_select(self): "isValid": False, "inputExpr": "select 1", "inputSelect": None, - "errors": [{"message": "extraneous input '1' expecting ", "start": 7, "end": 8, "fix": None}], + "errors": [ + { + "message": "extraneous input '1' expecting ", + "start": 7, + "end": 8, + "fix": None, + } + ], }, ) diff --git a/posthog/hogql/test/test_modifiers.py b/posthog/hogql/test/test_modifiers.py index b876d7ada529d..ba5ed58e84882 100644 --- a/posthog/hogql/test/test_modifiers.py +++ b/posthog/hogql/test/test_modifiers.py @@ -13,11 +13,13 @@ def test_create_default_modifiers_for_team_init(self): modifiers = create_default_modifiers_for_team(self.team) assert modifiers.personsOnEventsMode == PersonsOnEventsMode.disabled # NB! not a None modifiers = create_default_modifiers_for_team( - self.team, HogQLQueryModifiers(personsOnEventsMode=PersonsOnEventsMode.v1_enabled) + self.team, + HogQLQueryModifiers(personsOnEventsMode=PersonsOnEventsMode.v1_enabled), ) assert modifiers.personsOnEventsMode == PersonsOnEventsMode.v1_enabled modifiers = create_default_modifiers_for_team( - self.team, HogQLQueryModifiers(personsOnEventsMode=PersonsOnEventsMode.v2_enabled) + self.team, + HogQLQueryModifiers(personsOnEventsMode=PersonsOnEventsMode.v2_enabled), ) assert modifiers.personsOnEventsMode == PersonsOnEventsMode.v2_enabled @@ -26,13 +28,17 @@ def test_modifiers_persons_on_events_mode_v1_enabled(self): # Control response = execute_hogql_query( - query, team=self.team, modifiers=HogQLQueryModifiers(personsOnEventsMode=PersonsOnEventsMode.disabled) + query, + team=self.team, + modifiers=HogQLQueryModifiers(personsOnEventsMode=PersonsOnEventsMode.disabled), ) assert " JOIN " in response.clickhouse # Test response = execute_hogql_query( - query, team=self.team, modifiers=HogQLQueryModifiers(personsOnEventsMode=PersonsOnEventsMode.v1_enabled) + query, + team=self.team, + modifiers=HogQLQueryModifiers(personsOnEventsMode=PersonsOnEventsMode.v1_enabled), ) assert " JOIN " not in response.clickhouse @@ -70,9 +76,11 @@ def test_modifiers_persons_on_events_mode_mapping(self): ), ] - for (mode, *expected) in test_cases: + for mode, *expected in test_cases: response = execute_hogql_query( - query, team=self.team, modifiers=HogQLQueryModifiers(personsOnEventsMode=mode) + query, + team=self.team, + modifiers=HogQLQueryModifiers(personsOnEventsMode=mode), ) assert f"SELECT {', '.join(expected)} FROM" in response.clickhouse, f"PoE mode: {mode}" @@ -80,11 +88,19 @@ def test_modifiers_persons_argmax_version_v2(self): query = "SELECT * FROM persons" # Control (v1) - response = execute_hogql_query(query, team=self.team, modifiers=HogQLQueryModifiers(personsArgMaxVersion="v1")) + response = execute_hogql_query( + query, + team=self.team, + modifiers=HogQLQueryModifiers(personsArgMaxVersion="v1"), + ) assert "in(tuple(person.id, person.version)" not in response.clickhouse # Test (v2) - response = execute_hogql_query(query, team=self.team, modifiers=HogQLQueryModifiers(personsArgMaxVersion="v2")) + response = execute_hogql_query( + query, + team=self.team, + modifiers=HogQLQueryModifiers(personsArgMaxVersion="v2"), + ) assert "in(tuple(person.id, person.version)" in response.clickhouse def test_modifiers_persons_argmax_version_auto(self): diff --git a/posthog/hogql/test/test_placeholders.py b/posthog/hogql/test/test_placeholders.py index 6906104795775..88c92ebfc8fe8 100644 --- a/posthog/hogql/test/test_placeholders.py +++ b/posthog/hogql/test/test_placeholders.py @@ -26,11 +26,15 @@ def test_replace_placeholders_error(self): expr = ast.Placeholder(field="foo") with self.assertRaises(HogQLException) as context: replace_placeholders(expr, {}) - self.assertEqual("Placeholders, such as {foo}, are not supported in this context", str(context.exception)) + self.assertEqual( + "Placeholders, such as {foo}, are not supported in this context", + str(context.exception), + ) with self.assertRaises(HogQLException) as context: replace_placeholders(expr, {"bar": ast.Constant(value=123)}) self.assertEqual( - "Placeholder {foo} is not available in this context. You can use the following: bar", str(context.exception) + "Placeholder {foo} is not available in this context. You can use the following: bar", + str(context.exception), ) def test_replace_placeholders_comparison(self): @@ -61,4 +65,7 @@ def test_assert_no_placeholders(self): expr = ast.Placeholder(field="foo") with self.assertRaises(HogQLException) as context: replace_placeholders(expr, None) - self.assertEqual("Placeholders, such as {foo}, are not supported in this context", str(context.exception)) + self.assertEqual( + "Placeholders, such as {foo}, are not supported in this context", + str(context.exception), + ) diff --git a/posthog/hogql/test/test_printer.py b/posthog/hogql/test/test_printer.py index 3861bd77fce42..75f182a618f54 100644 --- a/posthog/hogql/test/test_printer.py +++ b/posthog/hogql/test/test_printer.py @@ -23,13 +23,19 @@ class TestPrinter(BaseTest): # Helper to always translate HogQL with a blank context def _expr( - self, query: str, context: Optional[HogQLContext] = None, dialect: Literal["hogql", "clickhouse"] = "clickhouse" + self, + query: str, + context: Optional[HogQLContext] = None, + dialect: Literal["hogql", "clickhouse"] = "clickhouse", ) -> str: return translate_hogql(query, context or HogQLContext(team_id=self.team.pk), dialect) # Helper to always translate HogQL with a blank context, def _select( - self, query: str, context: Optional[HogQLContext] = None, placeholders: Optional[Dict[str, ast.Expr]] = None + self, + query: str, + context: Optional[HogQLContext] = None, + placeholders: Optional[Dict[str, ast.Expr]] = None, ) -> str: return print_ast( parse_select(query, placeholders=placeholders), @@ -37,7 +43,12 @@ def _select( "clickhouse", ) - def _assert_expr_error(self, expr, expected_error, dialect: Literal["hogql", "clickhouse"] = "clickhouse"): + def _assert_expr_error( + self, + expr, + expected_error, + dialect: Literal["hogql", "clickhouse"] = "clickhouse", + ): with self.assertRaises(HogQLException) as context: self._expr(expr, None, dialect) if expected_error not in str(context.exception): @@ -90,9 +101,13 @@ def test_tuples(self): self.assertEqual(self._expr("(1,2,[])"), "tuple(1, 2, [])") def test_lambdas(self): - self.assertEqual(self._expr("arrayMap(x -> x*2, [1,2,3])"), "arrayMap(x -> multiply(x, 2), [1, 2, 3])") self.assertEqual( - self._expr("arrayMap((x, y) -> x*y, [1,2,3])"), "arrayMap((x, y) -> multiply(x, y), [1, 2, 3])" + self._expr("arrayMap(x -> x*2, [1,2,3])"), + "arrayMap(x -> multiply(x, 2), [1, 2, 3])", + ) + self.assertEqual( + self._expr("arrayMap((x, y) -> x*y, [1,2,3])"), + "arrayMap((x, y) -> multiply(x, y), [1, 2, 3])", ) def test_equals_null(self): @@ -162,7 +177,11 @@ def test_hogql_properties(self): "person", ) self.assertEqual( - self._expr("person.properties.$browser", HogQLContext(team_id=self.team.pk), "hogql"), + self._expr( + "person.properties.$browser", + HogQLContext(team_id=self.team.pk), + "hogql", + ), "person.properties.$browser", ) self.assertEqual( @@ -170,23 +189,43 @@ def test_hogql_properties(self): "properties.$browser", ) self.assertEqual( - self._expr("properties.`$browser with a space`", HogQLContext(team_id=self.team.pk), "hogql"), + self._expr( + "properties.`$browser with a space`", + HogQLContext(team_id=self.team.pk), + "hogql", + ), "properties.`$browser with a space`", ) self.assertEqual( - self._expr('properties."$browser with a space"', HogQLContext(team_id=self.team.pk), "hogql"), + self._expr( + 'properties."$browser with a space"', + HogQLContext(team_id=self.team.pk), + "hogql", + ), "properties.`$browser with a space`", ) self.assertEqual( - self._expr("properties['$browser with a space']", HogQLContext(team_id=self.team.pk), "hogql"), + self._expr( + "properties['$browser with a space']", + HogQLContext(team_id=self.team.pk), + "hogql", + ), "properties.`$browser with a space`", ) self.assertEqual( - self._expr("properties['$browser with a ` tick']", HogQLContext(team_id=self.team.pk), "hogql"), + self._expr( + "properties['$browser with a ` tick']", + HogQLContext(team_id=self.team.pk), + "hogql", + ), "properties.`$browser with a \\` tick`", ) self.assertEqual( - self._expr("properties['$browser \\\\with a \\n` tick']", HogQLContext(team_id=self.team.pk), "hogql"), + self._expr( + "properties['$browser \\\\with a \\n` tick']", + HogQLContext(team_id=self.team.pk), + "hogql", + ), "properties.`$browser \\\\with a \\n\\` tick`", ) # "dot NUMBER" means "tuple access" in clickhouse. To access strings properties, wrap them in `backquotes` @@ -198,7 +237,11 @@ def test_hogql_properties(self): self._expr("properties.`1`", HogQLContext(team_id=self.team.pk), "hogql"), "properties.`1`", ) - self._assert_expr_error("properties.'no strings'", "no viable alternative at input '.'no strings'", "hogql") + self._assert_expr_error( + "properties.'no strings'", + "no viable alternative at input '.'no strings'", + "hogql", + ) def test_hogql_properties_json(self): context = HogQLContext(team_id=self.team.pk) @@ -206,7 +249,10 @@ def test_hogql_properties_json(self): self._expr("properties.nomat.json.yet", context), "replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(events.properties, %(hogql_val_0)s, %(hogql_val_1)s, %(hogql_val_2)s), ''), 'null'), '^\"|\"$', '')", ) - self.assertEqual(context.values, {"hogql_val_0": "nomat", "hogql_val_1": "json", "hogql_val_2": "yet"}) + self.assertEqual( + context.values, + {"hogql_val_0": "nomat", "hogql_val_1": "json", "hogql_val_2": "yet"}, + ) def test_hogql_properties_materialized_json_access(self): try: @@ -232,11 +278,15 @@ def test_materialized_fields_and_properties(self): self.assertEqual(1 + 2, 3) return materialize("events", "$browser") - self.assertEqual(self._expr("properties['$browser']"), "nullIf(nullIf(events.`mat_$browser`, ''), 'null')") + self.assertEqual( + self._expr("properties['$browser']"), + "nullIf(nullIf(events.`mat_$browser`, ''), 'null')", + ) materialize("events", "withoutdollar") self.assertEqual( - self._expr("properties['withoutdollar']"), "nullIf(nullIf(events.mat_withoutdollar, ''), 'null')" + self._expr("properties['withoutdollar']"), + "nullIf(nullIf(events.mat_withoutdollar, ''), 'null')", ) materialize("events", "$browser and string") @@ -247,13 +297,17 @@ def test_materialized_fields_and_properties(self): materialize("events", "$browser%%%#@!@") self.assertEqual( - self._expr("properties['$browser%%%#@!@']"), "nullIf(nullIf(events.`mat_$browser_______`, ''), 'null')" + self._expr("properties['$browser%%%#@!@']"), + "nullIf(nullIf(events.`mat_$browser_______`, ''), 'null')", ) def test_methods(self): self.assertEqual(self._expr("count()"), "count()") self.assertEqual(self._expr("count(distinct event)"), "count(DISTINCT events.event)") - self.assertEqual(self._expr("countIf(distinct event, 1 == 2)"), "countIf(DISTINCT events.event, 0)") + self.assertEqual( + self._expr("countIf(distinct event, 1 == 2)"), + "countIf(DISTINCT events.event, 0)", + ) self.assertEqual(self._expr("sumIf(1, 1 == 2)"), "sumIf(1, 0)") def test_functions(self): @@ -269,32 +323,49 @@ def test_expr_parse_errors(self): self._assert_expr_error("avg(bla)", "Unable to resolve field: bla") self._assert_expr_error("count(1,2,3,4)", "Aggregation 'count' expects at most 1 argument, found 4") self._assert_expr_error("countIf()", "Aggregation 'countIf' expects at least 1 argument, found 0") - self._assert_expr_error("countIf(2,3,4)", "Aggregation 'countIf' expects at most 2 arguments, found 3") + self._assert_expr_error( + "countIf(2,3,4)", + "Aggregation 'countIf' expects at most 2 arguments, found 3", + ) self._assert_expr_error("uniq()", "Aggregation 'uniq' expects at least 1 argument, found 0") self._assert_expr_error( - "quantile(event)", "Aggregation 'quantile' requires parameters in addition to arguments" + "quantile(event)", + "Aggregation 'quantile' requires parameters in addition to arguments", ) self._assert_expr_error( - "quantile()(event)", "Aggregation 'quantile' requires parameters in addition to arguments" + "quantile()(event)", + "Aggregation 'quantile' requires parameters in addition to arguments", + ) + self._assert_expr_error( + "quantile(0.5, 2)(event)", + "Aggregation 'quantile' expects 1 parameter, found 2", ) - self._assert_expr_error("quantile(0.5, 2)(event)", "Aggregation 'quantile' expects 1 parameter, found 2") self._assert_expr_error("sparkline()", "Function 'sparkline' expects 1 argument, found 0") self._assert_expr_error("hamburger(event)", "Unsupported function call 'hamburger(...)'") self._assert_expr_error("mad(event)", "Unsupported function call 'mad(...)'") - self._assert_expr_error("noway(event)", "Unsupported function call 'noway(...)'. Perhaps you meant 'now(...)'?") self._assert_expr_error( - "tostring(event)", "Unsupported function call 'tostring(...)'. Perhaps you meant 'toString(...)'?" + "noway(event)", + "Unsupported function call 'noway(...)'. Perhaps you meant 'now(...)'?", + ) + self._assert_expr_error( + "tostring(event)", + "Unsupported function call 'tostring(...)'. Perhaps you meant 'toString(...)'?", ) self._assert_expr_error("yeet.the.cloud", "Unable to resolve field: yeet") self._assert_expr_error("chipotle", "Unable to resolve field: chipotle") self._assert_expr_error( - "avg(avg(properties.bla))", "Aggregation 'avg' cannot be nested inside another aggregation 'avg'." + "avg(avg(properties.bla))", + "Aggregation 'avg' cannot be nested inside another aggregation 'avg'.", ) self._assert_expr_error("person.chipotle", "Field not found: chipotle") self._assert_expr_error("properties.0", "SQL indexes start from one, not from zero. E.g: array[1]") - self._assert_expr_error("properties.id.0", "SQL indexes start from one, not from zero. E.g: array[1]") self._assert_expr_error( - "event as `as%d`", 'The HogQL identifier "as%d" is not permitted as it contains the "%" character' + "properties.id.0", + "SQL indexes start from one, not from zero. E.g: array[1]", + ) + self._assert_expr_error( + "event as `as%d`", + 'The HogQL identifier "as%d" is not permitted as it contains the "%" character', ) @override_settings(PERSON_ON_EVENTS_OVERRIDE=True, PERSON_ON_EVENTS_V2_OVERRIDE=True) @@ -337,24 +408,55 @@ def test_logic(self): def test_comparisons(self): context = HogQLContext(team_id=self.team.pk) self.assertEqual(self._expr("event == 'E'", context), "equals(events.event, %(hogql_val_0)s)") - self.assertEqual(self._expr("event != 'E'", context), "notEquals(events.event, %(hogql_val_1)s)") + self.assertEqual( + self._expr("event != 'E'", context), + "notEquals(events.event, %(hogql_val_1)s)", + ) self.assertEqual(self._expr("event > 'E'", context), "greater(events.event, %(hogql_val_2)s)") - self.assertEqual(self._expr("event >= 'E'", context), "greaterOrEquals(events.event, %(hogql_val_3)s)") + self.assertEqual( + self._expr("event >= 'E'", context), + "greaterOrEquals(events.event, %(hogql_val_3)s)", + ) self.assertEqual(self._expr("event < 'E'", context), "less(events.event, %(hogql_val_4)s)") - self.assertEqual(self._expr("event <= 'E'", context), "lessOrEquals(events.event, %(hogql_val_5)s)") + self.assertEqual( + self._expr("event <= 'E'", context), + "lessOrEquals(events.event, %(hogql_val_5)s)", + ) self.assertEqual(self._expr("event like 'E'", context), "like(events.event, %(hogql_val_6)s)") - self.assertEqual(self._expr("event not like 'E'", context), "notLike(events.event, %(hogql_val_7)s)") - self.assertEqual(self._expr("event ilike 'E'", context), "ilike(events.event, %(hogql_val_8)s)") - self.assertEqual(self._expr("event not ilike 'E'", context), "notILike(events.event, %(hogql_val_9)s)") + self.assertEqual( + self._expr("event not like 'E'", context), + "notLike(events.event, %(hogql_val_7)s)", + ) + self.assertEqual( + self._expr("event ilike 'E'", context), + "ilike(events.event, %(hogql_val_8)s)", + ) + self.assertEqual( + self._expr("event not ilike 'E'", context), + "notILike(events.event, %(hogql_val_9)s)", + ) self.assertEqual(self._expr("event in 'E'", context), "in(events.event, %(hogql_val_10)s)") - self.assertEqual(self._expr("event not in 'E'", context), "notIn(events.event, %(hogql_val_11)s)") + self.assertEqual( + self._expr("event not in 'E'", context), + "notIn(events.event, %(hogql_val_11)s)", + ) self.assertEqual(self._expr("event ~ 'E'", context), "match(events.event, %(hogql_val_12)s)") self.assertEqual(self._expr("event =~ 'E'", context), "match(events.event, %(hogql_val_13)s)") - self.assertEqual(self._expr("event !~ 'E'", context), "not(match(events.event, %(hogql_val_14)s))") - self.assertEqual(self._expr("event ~* 'E'", context), "match(events.event, concat('(?i)', %(hogql_val_15)s))") - self.assertEqual(self._expr("event =~* 'E'", context), "match(events.event, concat('(?i)', %(hogql_val_16)s))") self.assertEqual( - self._expr("event !~* 'E'", context), "not(match(events.event, concat('(?i)', %(hogql_val_17)s)))" + self._expr("event !~ 'E'", context), + "not(match(events.event, %(hogql_val_14)s))", + ) + self.assertEqual( + self._expr("event ~* 'E'", context), + "match(events.event, concat('(?i)', %(hogql_val_15)s))", + ) + self.assertEqual( + self._expr("event =~* 'E'", context), + "match(events.event, concat('(?i)', %(hogql_val_16)s))", + ) + self.assertEqual( + self._expr("event !~* 'E'", context), + "not(match(events.event, concat('(?i)', %(hogql_val_17)s)))", ) def test_comments(self): @@ -369,31 +471,48 @@ def test_values(self): self._expr("coalesce(4.2, 5, 'lol', 'hoo')", context), "coalesce(4.2, 5, %(hogql_val_1)s, %(hogql_val_2)s)", ) - self.assertEqual(context.values, {"hogql_val_0": "E", "hogql_val_1": "lol", "hogql_val_2": "hoo"}) + self.assertEqual( + context.values, + {"hogql_val_0": "E", "hogql_val_1": "lol", "hogql_val_2": "hoo"}, + ) def test_alias_keywords(self): self._assert_expr_error( - "1 as team_id", '"team_id" cannot be an alias or identifier, as it\'s a reserved keyword' + "1 as team_id", + '"team_id" cannot be an alias or identifier, as it\'s a reserved keyword', + ) + self._assert_expr_error( + "1 as true", + '"true" cannot be an alias or identifier, as it\'s a reserved keyword', ) - self._assert_expr_error("1 as true", '"true" cannot be an alias or identifier, as it\'s a reserved keyword') self._assert_select_error( - "select 1 as team_id from events", '"team_id" cannot be an alias or identifier, as it\'s a reserved keyword' + "select 1 as team_id from events", + '"team_id" cannot be an alias or identifier, as it\'s a reserved keyword', ) self.assertEqual( self._select("select 1 as `-- select team_id` from events"), f"SELECT 1 AS `-- select team_id` FROM events WHERE equals(events.team_id, {self.team.pk}) LIMIT 10000", ) # Some aliases are funny, but that's what the antlr syntax permits, and ClickHouse doesn't complain either - self.assertEqual(self._expr("event makes little sense"), "((events.event AS makes) AS little) AS sense") + self.assertEqual( + self._expr("event makes little sense"), + "((events.event AS makes) AS little) AS sense", + ) def test_case_when(self): self.assertEqual(self._expr("case when 1 then 2 else 3 end"), "if(1, 2, 3)") def test_case_when_many(self): - self.assertEqual(self._expr("case when 1 then 2 when 3 then 4 else 5 end"), "multiIf(1, 2, 3, 4, 5)") + self.assertEqual( + self._expr("case when 1 then 2 when 3 then 4 else 5 end"), + "multiIf(1, 2, 3, 4, 5)", + ) def test_case_when_case(self): - self.assertEqual(self._expr("case 0 when 1 then 2 when 3 then 4 else 5 end"), "transform(0, [1, 3], [2, 4], 5)") + self.assertEqual( + self._expr("case 0 when 1 then 2 when 3 then 4 else 5 end"), + "transform(0, [1, 3], [2, 4], 5)", + ) def test_select(self): self.assertEqual(self._select("select 1"), "SELECT 1 LIMIT 10000") @@ -421,19 +540,29 @@ def test_select_from(self): def test_select_from_placeholder(self): self.assertEqual( - self._select("select 1 from {placeholder}", placeholders={"placeholder": ast.Field(chain=["events"])}), - f"SELECT 1 FROM events WHERE equals(events.team_id, {self.team.pk}) LIMIT 10000", - ) - with self.assertRaises(HogQLException) as error_context: self._select( "select 1 from {placeholder}", - placeholders={ - "placeholder": ast.CompareOperation( - left=ast.Constant(value=1), right=ast.Constant(value=1), op=ast.CompareOperationOp.Eq - ) - }, + placeholders={"placeholder": ast.Field(chain=["events"])}, ), - self.assertEqual(str(error_context.exception), "JoinExpr with table of type CompareOperation not supported") + f"SELECT 1 FROM events WHERE equals(events.team_id, {self.team.pk}) LIMIT 10000", + ) + with self.assertRaises(HogQLException) as error_context: + ( + self._select( + "select 1 from {placeholder}", + placeholders={ + "placeholder": ast.CompareOperation( + left=ast.Constant(value=1), + right=ast.Constant(value=1), + op=ast.CompareOperationOp.Eq, + ) + }, + ), + ) + self.assertEqual( + str(error_context.exception), + "JoinExpr with table of type CompareOperation not supported", + ) def test_select_cross_join(self): self.assertEqual( @@ -702,13 +831,16 @@ def test_count_if_distinct(self): def test_print_timezone(self): context = HogQLContext( - team_id=self.team.pk, enable_select_queries=True, database=Database(None, WeekStartDay.SUNDAY) + team_id=self.team.pk, + enable_select_queries=True, + database=Database(None, WeekStartDay.SUNDAY), ) context.database.events.fields["test_date"] = DateDatabaseField(name="test_date") # type: ignore self.assertEqual( self._select( - "SELECT now(), toDateTime(timestamp), toDate(test_date), toDateTime('2020-02-02') FROM events", context + "SELECT now(), toDateTime(timestamp), toDate(test_date), toDateTime('2020-02-02') FROM events", + context, ), f"SELECT now64(6, %(hogql_val_0)s), toDateTime(toTimeZone(events.timestamp, %(hogql_val_1)s), %(hogql_val_2)s), toDate(events.test_date, %(hogql_val_3)s), parseDateTime64BestEffortOrNull(%(hogql_val_4)s, 6, %(hogql_val_5)s) FROM events WHERE equals(events.team_id, {self.team.pk}) LIMIT 10000", ) @@ -729,7 +861,10 @@ def test_print_timezone_custom(self): self.team.save() context = HogQLContext(team_id=self.team.pk, enable_select_queries=True) self.assertEqual( - self._select("SELECT now(), toDateTime(timestamp), toDateTime('2020-02-02') FROM events", context), + self._select( + "SELECT now(), toDateTime(timestamp), toDateTime('2020-02-02') FROM events", + context, + ), f"SELECT now64(6, %(hogql_val_0)s), toDateTime(toTimeZone(events.timestamp, %(hogql_val_1)s), %(hogql_val_2)s), parseDateTime64BestEffortOrNull(%(hogql_val_3)s, 6, %(hogql_val_4)s) FROM events WHERE equals(events.team_id, {self.team.pk}) LIMIT 10000", ) self.assertEqual( @@ -749,7 +884,10 @@ def test_print_timezone_gibberish(self): context = HogQLContext(team_id=self.team.pk, enable_select_queries=True) with self.assertRaises(HogQLException) as error_context: - self._select("SELECT now(), toDateTime(timestamp), toDateTime('2020-02-02') FROM events", context) + self._select( + "SELECT now(), toDateTime(timestamp), toDateTime('2020-02-02') FROM events", + context, + ) self.assertEqual(str(error_context.exception), "Unknown timezone: 'Europe/PostHogLandia'") def test_window_functions(self): @@ -907,7 +1045,11 @@ def test_print_global_settings(self): def test_print_query_level_settings(self): query = parse_select("SELECT 1 FROM events") query.settings = HogQLQuerySettings(optimize_aggregation_in_order=True) - printed = print_ast(query, HogQLContext(team_id=self.team.pk, enable_select_queries=True), "clickhouse") + printed = print_ast( + query, + HogQLContext(team_id=self.team.pk, enable_select_queries=True), + "clickhouse", + ) self.assertEqual( printed, f"SELECT 1 FROM events WHERE equals(events.team_id, {self.team.pk}) LIMIT 10000 SETTINGS optimize_aggregation_in_order=1", diff --git a/posthog/hogql/test/test_property.py b/posthog/hogql/test/test_property.py index 1e57589805645..c0ed528ea4da9 100644 --- a/posthog/hogql/test/test_property.py +++ b/posthog/hogql/test/test_property.py @@ -12,7 +12,14 @@ tag_name_to_expr, ) from posthog.hogql.visitor import clear_locations -from posthog.models import Action, ActionStep, Cohort, Property, PropertyDefinition, Team +from posthog.models import ( + Action, + ActionStep, + Cohort, + Property, + PropertyDefinition, + Team, +) from posthog.models.property import PropertyGroup from posthog.models.property_definition import PropertyType from posthog.schema import HogQLPropertyFilter, PropertyOperator @@ -49,8 +56,14 @@ def test_has_aggregation(self): def test_property_to_expr_hogql(self): self.assertEqual(self._property_to_expr({"type": "hogql", "key": "1"}), ast.Constant(value=1)) - self.assertEqual(self._property_to_expr(Property(type="hogql", key="1")), ast.Constant(value=1)) - self.assertEqual(self._property_to_expr(HogQLPropertyFilter(type="hogql", key="1")), ast.Constant(value=1)) + self.assertEqual( + self._property_to_expr(Property(type="hogql", key="1")), + ast.Constant(value=1), + ) + self.assertEqual( + self._property_to_expr(HogQLPropertyFilter(type="hogql", key="1")), + ast.Constant(value=1), + ) def test_property_to_expr_event(self): self.assertEqual( @@ -128,7 +141,10 @@ def test_property_to_expr_boolean(self): property_type=PropertyType.String, ) self.assertEqual( - self._property_to_expr({"type": "event", "key": "boolean_prop", "value": "true"}, team=self.team), + self._property_to_expr( + {"type": "event", "key": "boolean_prop", "value": "true"}, + team=self.team, + ), self._parse_expr("properties.boolean_prop = true"), ) self.assertEqual( @@ -136,7 +152,10 @@ def test_property_to_expr_boolean(self): self._parse_expr("properties.string_prop = 'true'"), ) self.assertEqual( - self._property_to_expr({"type": "event", "key": "unknown_prop", "value": "true"}, team=self.team), + self._property_to_expr( + {"type": "event", "key": "unknown_prop", "value": "true"}, + team=self.team, + ), self._parse_expr("properties.unknown_prop = true"), ) @@ -147,7 +166,14 @@ def test_property_to_expr_event_list(self): self._parse_expr("properties.a = 'b' or properties.a = 'c'"), ) self.assertEqual( - self._property_to_expr({"type": "event", "key": "a", "value": ["b", "c"], "operator": "icontains"}), + self._property_to_expr( + { + "type": "event", + "key": "a", + "value": ["b", "c"], + "operator": "icontains", + } + ), self._parse_expr("properties.a ilike '%b%' or properties.a ilike '%c%'"), ) self.assertEqual( @@ -160,11 +186,25 @@ def test_property_to_expr_event_list(self): self._parse_expr("properties.a != 'b' and properties.a != 'c'"), ) self.assertEqual( - self._property_to_expr({"type": "event", "key": "a", "value": ["b", "c"], "operator": "not_icontains"}), + self._property_to_expr( + { + "type": "event", + "key": "a", + "value": ["b", "c"], + "operator": "not_icontains", + } + ), self._parse_expr("properties.a not ilike '%b%' and properties.a not ilike '%c%'"), ) self.assertEqual( - self._property_to_expr({"type": "event", "key": "a", "value": ["b", "c"], "operator": "not_regex"}), + self._property_to_expr( + { + "type": "event", + "key": "a", + "value": ["b", "c"], + "operator": "not_regex", + } + ), self._parse_expr("not(match(properties.a, 'b')) and not(match(properties.a, 'c'))"), ) @@ -182,27 +222,69 @@ def test_property_to_expr_person(self): def test_property_to_expr_element(self): self.assertEqual( - self._property_to_expr({"type": "element", "key": "selector", "value": "div", "operator": "exact"}), + self._property_to_expr( + { + "type": "element", + "key": "selector", + "value": "div", + "operator": "exact", + } + ), self._selector_to_expr("div"), ) self.assertEqual( - self._property_to_expr({"type": "element", "key": "selector", "value": "div", "operator": "is_not"}), + self._property_to_expr( + { + "type": "element", + "key": "selector", + "value": "div", + "operator": "is_not", + } + ), clear_locations(not_call(self._selector_to_expr("div"))), ) self.assertEqual( - self._property_to_expr({"type": "element", "key": "tag_name", "value": "div", "operator": "exact"}), + self._property_to_expr( + { + "type": "element", + "key": "tag_name", + "value": "div", + "operator": "exact", + } + ), clear_locations(tag_name_to_expr("div")), ) self.assertEqual( - self._property_to_expr({"type": "element", "key": "tag_name", "value": "div", "operator": "is_not"}), + self._property_to_expr( + { + "type": "element", + "key": "tag_name", + "value": "div", + "operator": "is_not", + } + ), clear_locations(not_call(tag_name_to_expr("div"))), ) self.assertEqual( - self._property_to_expr({"type": "element", "key": "href", "value": "href-text.", "operator": "exact"}), + self._property_to_expr( + { + "type": "element", + "key": "href", + "value": "href-text.", + "operator": "exact", + } + ), clear_locations(element_chain_key_filter("href", "href-text.", PropertyOperator.exact)), ) self.assertEqual( - self._property_to_expr({"type": "element", "key": "text", "value": "text-text.", "operator": "regex"}), + self._property_to_expr( + { + "type": "element", + "key": "text", + "value": "text-text.", + "operator": "regex", + } + ), clear_locations(element_chain_key_filter("text", "text-text.", PropertyOperator.regex)), ) @@ -259,7 +341,8 @@ def test_property_groups_single(self): self.assertEqual( self._property_to_expr( PropertyGroup( - type=PropertyOperatorType.OR, values=[Property(type="event", key="e", value="b", operator="exact")] + type=PropertyOperatorType.OR, + values=[Property(type="event", key="e", value="b", operator="exact")], ) ), self._parse_expr("properties.e = 'b'"), @@ -277,8 +360,18 @@ def test_property_groups_combined(self): PropertyGroup( type=PropertyOperatorType.OR, values=[ - Property(type="person", key="a", value="b", operator="exact"), - Property(type="event", key="e", value="b", operator="exact"), + Property( + type="person", + key="a", + value="b", + operator="exact", + ), + Property( + type="event", + key="e", + value="b", + operator="exact", + ), ], ), ], @@ -290,7 +383,8 @@ def test_property_groups_combined(self): def test_tag_name_to_expr(self): self.assertEqual( - clear_locations(tag_name_to_expr("a")), clear_locations(elements_chain_match("(^|;)a(\\.|$|;|:)")) + clear_locations(tag_name_to_expr("a")), + clear_locations(elements_chain_match("(^|;)a(\\.|$|;|:)")), ) def test_selector_to_expr(self): @@ -379,7 +473,12 @@ def test_elements_chain_key_filter(self): def test_action_to_expr(self): action1 = Action.objects.create(team=self.team) - ActionStep.objects.create(event="$autocapture", action=action1, selector="a.nav-link.active", tag_name="a") + ActionStep.objects.create( + event="$autocapture", + action=action1, + selector="a.nav-link.active", + tag_name="a", + ) self.assertEqual( clear_locations(action_to_expr(action1)), self._parse_expr( @@ -394,15 +493,30 @@ def test_action_to_expr(self): ) action2 = Action.objects.create(team=self.team) - ActionStep.objects.create(event="$pageview", action=action2, url="https://example.com", url_matching="contains") + ActionStep.objects.create( + event="$pageview", + action=action2, + url="https://example.com", + url_matching="contains", + ) self.assertEqual( clear_locations(action_to_expr(action2)), self._parse_expr("event = '$pageview' and properties.$current_url like '%https://example.com%'"), ) action3 = Action.objects.create(team=self.team) - ActionStep.objects.create(event="$pageview", action=action3, url="https://example2.com", url_matching="regex") - ActionStep.objects.create(event="custom", action=action3, url="https://example3.com", url_matching="exact") + ActionStep.objects.create( + event="$pageview", + action=action3, + url="https://example2.com", + url_matching="regex", + ) + ActionStep.objects.create( + event="custom", + action=action3, + url="https://example3.com", + url_matching="exact", + ) self.assertEqual( clear_locations(action_to_expr(action3)), self._parse_expr( @@ -435,7 +549,8 @@ def test_cohort_filter_static(self): def test_cohort_filter_dynamic(self): cohort = Cohort.objects.create( - team=self.team, groups=[{"properties": [{"key": "$os", "value": "Chrome", "type": "person"}]}] + team=self.team, + groups=[{"properties": [{"key": "$os", "value": "Chrome", "type": "person"}]}], ) self.assertEqual( self._property_to_expr({"type": "cohort", "key": "id", "value": cohort.pk}, self.team), @@ -444,15 +559,25 @@ def test_cohort_filter_dynamic(self): def test_person_scope(self): self.assertEqual( - self._property_to_expr({"type": "person", "key": "a", "value": "b", "operator": "exact"}, scope="event"), + self._property_to_expr( + {"type": "person", "key": "a", "value": "b", "operator": "exact"}, + scope="event", + ), self._parse_expr("person.properties.a = 'b'"), ) self.assertEqual( - self._property_to_expr({"type": "person", "key": "a", "value": "b", "operator": "exact"}, scope="person"), + self._property_to_expr( + {"type": "person", "key": "a", "value": "b", "operator": "exact"}, + scope="person", + ), self._parse_expr("properties.a = 'b'"), ) with self.assertRaises(Exception) as e: - self._property_to_expr({"type": "event", "key": "a", "value": "b", "operator": "exact"}, scope="person") + self._property_to_expr( + {"type": "event", "key": "a", "value": "b", "operator": "exact"}, + scope="person", + ) self.assertEqual( - str(e.exception), "The 'event' property filter only works in 'event' scope, not in 'person' scope" + str(e.exception), + "The 'event' property filter only works in 'event' scope, not in 'person' scope", ) diff --git a/posthog/hogql/test/test_query.py b/posthog/hogql/test/test_query.py index 475a346ff2b5e..0d6cf4342dead 100644 --- a/posthog/hogql/test/test_query.py +++ b/posthog/hogql/test/test_query.py @@ -15,9 +15,17 @@ from posthog.models import Cohort from posthog.models.cohort.util import recalculate_cohortpeople from posthog.models.utils import UUIDT -from posthog.session_recordings.queries.test.session_replay_sql import produce_replay_summary +from posthog.session_recordings.queries.test.session_replay_sql import ( + produce_replay_summary, +) from posthog.schema import HogQLFilters, EventPropertyFilter, DateRange, QueryTiming -from posthog.test.base import APIBaseTest, ClickhouseTestMixin, _create_event, _create_person, flush_persons_and_events +from posthog.test.base import ( + APIBaseTest, + ClickhouseTestMixin, + _create_event, + _create_person, + flush_persons_and_events, +) from posthog.warehouse.models import DataWarehouseSavedQuery, DataWarehouseViewLink @@ -38,7 +46,11 @@ def _create_random_events(self) -> str: distinct_id="bla", event="random event", team=self.team, - properties={"random_prop": "don't include", "random_uuid": random_uuid, "index": index}, + properties={ + "random_prop": "don't include", + "random_uuid": random_uuid, + "index": index, + }, ) flush_persons_and_events() return random_uuid @@ -241,7 +253,10 @@ def test_query_joins_pdi_persons(self): ) assert pretty_print_in_tests(response.clickhouse, self.team.pk) == self.snapshot self.assertEqual(response.results[0][0], "bla") - self.assertEqual(response.results[0][1], datetime.datetime(2020, 1, 10, 0, 0, tzinfo=timezone.utc)) + self.assertEqual( + response.results[0][1], + datetime.datetime(2020, 1, 10, 0, 0, tzinfo=timezone.utc), + ) @pytest.mark.usefixtures("unittest_snapshot") def test_query_joins_pdi_person_properties(self): @@ -402,20 +417,42 @@ def test_query_select_person_with_poe_without_joins(self): def test_prop_cohort_basic(self): with freeze_time("2020-01-10"): - _create_person(distinct_ids=["some_other_id"], team_id=self.team.pk, properties={"$some_prop": "something"}) + _create_person( + distinct_ids=["some_other_id"], + team_id=self.team.pk, + properties={"$some_prop": "something"}, + ) _create_person( distinct_ids=["some_id"], team_id=self.team.pk, properties={"$some_prop": "something", "$another_prop": "something"}, ) _create_person(distinct_ids=["no_match"], team_id=self.team.pk) - _create_event(event="$pageview", team=self.team, distinct_id="some_id", properties={"attr": "some_val"}) _create_event( - event="$pageview", team=self.team, distinct_id="some_other_id", properties={"attr": "some_val"} + event="$pageview", + team=self.team, + distinct_id="some_id", + properties={"attr": "some_val"}, + ) + _create_event( + event="$pageview", + team=self.team, + distinct_id="some_other_id", + properties={"attr": "some_val"}, ) cohort = Cohort.objects.create( team=self.team, - groups=[{"properties": [{"key": "$some_prop", "value": "something", "type": "person"}]}], + groups=[ + { + "properties": [ + { + "key": "$some_prop", + "value": "something", + "type": "person", + } + ] + } + ], name="cohort", ) recalculate_cohortpeople(cohort, pending_version=0) @@ -425,7 +462,8 @@ def test_prop_cohort_basic(self): team=self.team, placeholders={ "cohort_filter": property_to_expr( - {"type": "cohort", "key": "id", "value": cohort.pk}, self.team + {"type": "cohort", "key": "id", "value": cohort.pk}, + self.team, ) }, ) @@ -441,7 +479,8 @@ def test_prop_cohort_basic(self): team=self.team, placeholders={ "cohort_filter": property_to_expr( - {"type": "cohort", "key": "id", "value": cohort.pk}, self.team + {"type": "cohort", "key": "id", "value": cohort.pk}, + self.team, ) }, ) @@ -456,16 +495,28 @@ def test_prop_cohort_basic(self): def test_prop_cohort_static(self): with freeze_time("2020-01-10"): - _create_person(distinct_ids=["some_other_id"], team_id=self.team.pk, properties={"$some_prop": "something"}) + _create_person( + distinct_ids=["some_other_id"], + team_id=self.team.pk, + properties={"$some_prop": "something"}, + ) _create_person( distinct_ids=["some_id"], team_id=self.team.pk, properties={"$some_prop": "something", "$another_prop": "something"}, ) _create_person(distinct_ids=["no_match"], team_id=self.team.pk) - _create_event(event="$pageview", team=self.team, distinct_id="some_id", properties={"attr": "some_val"}) _create_event( - event="$pageview", team=self.team, distinct_id="some_other_id", properties={"attr": "some_val"} + event="$pageview", + team=self.team, + distinct_id="some_id", + properties={"attr": "some_val"}, + ) + _create_event( + event="$pageview", + team=self.team, + distinct_id="some_other_id", + properties={"attr": "some_val"}, ) cohort = Cohort.objects.create(team=self.team, groups=[], is_static=True) cohort.insert_users_by_list(["some_id"]) @@ -476,7 +527,8 @@ def test_prop_cohort_static(self): team=self.team, placeholders={ "cohort_filter": property_to_expr( - {"type": "cohort", "key": "id", "value": cohort.pk}, self.team + {"type": "cohort", "key": "id", "value": cohort.pk}, + self.team, ) }, ) @@ -493,7 +545,8 @@ def test_prop_cohort_static(self): team=self.team, placeholders={ "cohort_filter": property_to_expr( - {"type": "cohort", "key": "id", "value": cohort.pk}, self.team + {"type": "cohort", "key": "id", "value": cohort.pk}, + self.team, ) }, ) @@ -505,7 +558,11 @@ def test_prop_cohort_static(self): def test_join_with_property_materialized_session_id(self): with freeze_time("2020-01-10"): - _create_person(distinct_ids=["some_id"], team_id=self.team.pk, properties={"$some_prop": "something"}) + _create_person( + distinct_ids=["some_id"], + team_id=self.team.pk, + properties={"$some_prop": "something"}, + ) _create_event( event="$pageview", team=self.team, @@ -519,7 +576,10 @@ def test_join_with_property_materialized_session_id(self): properties={"attr": "some_val", "$session_id": "111"}, ) produce_replay_summary( - distinct_id="some_id", session_id="111", first_timestamp=timezone.now(), team_id=self.team.pk + distinct_id="some_id", + session_id="111", + first_timestamp=timezone.now(), + team_id=self.team.pk, ) response = execute_hogql_query( @@ -544,7 +604,11 @@ def test_join_with_property_materialized_session_id(self): def test_join_with_property_not_materialized(self): with freeze_time("2020-01-10"): - _create_person(distinct_ids=["some_id"], team_id=self.team.pk, properties={"$some_prop": "something"}) + _create_person( + distinct_ids=["some_id"], + team_id=self.team.pk, + properties={"$some_prop": "something"}, + ) _create_event( event="$pageview", team=self.team, @@ -558,7 +622,10 @@ def test_join_with_property_not_materialized(self): properties={"attr": "some_val", "$$$session_id": "111"}, ) produce_replay_summary( - distinct_id="some_id", session_id="111", first_timestamp=timezone.now(), team_id=self.team.pk + distinct_id="some_id", + session_id="111", + first_timestamp=timezone.now(), + team_id=self.team.pk, ) response = execute_hogql_query( @@ -625,7 +692,10 @@ def test_tuple_access(self): query, team=self.team, ) - self.assertEqual(response.results, [("0", [("random event", 1)]), ("1", [("random event", 1)])]) + self.assertEqual( + response.results, + [("0", [("random event", 1)]), ("1", [("random event", 1)])], + ) assert pretty_print_in_tests(response.clickhouse, self.team.pk) == self.snapshot def test_null_properties(self): @@ -635,7 +705,12 @@ def test_null_properties(self): distinct_id="bla", event="empty event", team=self.team, - properties={"empty_string": "", "null": None, "str_zero": "0", "num_zero": 0}, + properties={ + "empty_string": "", + "null": None, + "str_zero": "0", + "num_zero": 0, + }, ) query = """ @@ -881,7 +956,10 @@ def test_with_pivot_table_1_level(self): query, team=self.team, ) - self.assertEqual(response.results, [("0", [("random event", 1)]), ("1", [("random event", 1)])]) + self.assertEqual( + response.results, + [("0", [("random event", 1)]), ("1", [("random event", 1)])], + ) assert pretty_print_in_tests(response.clickhouse, self.team.pk) == self.snapshot @pytest.mark.usefixtures("unittest_snapshot") @@ -917,7 +995,10 @@ def test_with_pivot_table_2_levels(self): query, team=self.team, ) - self.assertEqual(response.results, [("0", [("random event", 1)]), ("1", [("random event", 1)])]) + self.assertEqual( + response.results, + [("0", [("random event", 1)]), ("1", [("random event", 1)])], + ) assert pretty_print_in_tests(response.clickhouse, self.team.pk) == self.snapshot def test_property_access_with_arrays(self): @@ -1308,7 +1389,11 @@ def test_view_link(self): saved_query = DataWarehouseSavedQuery.objects.get(pk=saved_query_response["id"]) DataWarehouseViewLink.objects.create( - saved_query=saved_query, table="events", to_join_key="fake", from_join_key="distinct_id", team=self.team + saved_query=saved_query, + table="events", + to_join_key="fake", + from_join_key="distinct_id", + team=self.team, ) response = execute_hogql_query("SELECT event_view.fake FROM events", team=self.team) @@ -1366,7 +1451,10 @@ def test_hogql_query_filters_double_error(self): query = "SELECT event from events where {filters}" with self.assertRaises(HogQLException) as e: execute_hogql_query( - query, team=self.team, filters=HogQLFilters(), placeholders={"filters": ast.Constant(value=True)} + query, + team=self.team, + filters=HogQLFilters(), + placeholders={"filters": ast.Constant(value=True)}, ) self.assertEqual( str(e.exception), @@ -1378,7 +1466,14 @@ def test_hogql_query_filters_alias(self): random_uuid = self._create_random_events() query = "SELECT event, distinct_id from events e WHERE {filters}" filters = HogQLFilters( - properties=[EventPropertyFilter(key="random_uuid", operator="exact", value=random_uuid, type="event")] + properties=[ + EventPropertyFilter( + key="random_uuid", + operator="exact", + value=random_uuid, + type="event", + ) + ] ) response = execute_hogql_query(query, team=self.team, filters=filters) self.assertEqual( diff --git a/posthog/hogql/test/test_resolver.py b/posthog/hogql/test/test_resolver.py index 7ed33e37291d2..1a946c2c3e769 100644 --- a/posthog/hogql/test/test_resolver.py +++ b/posthog/hogql/test/test_resolver.py @@ -27,11 +27,18 @@ class TestResolver(BaseTest): maxDiff = None def _select(self, query: str, placeholders: Optional[Dict[str, ast.Expr]] = None) -> ast.SelectQuery: - return cast(ast.SelectQuery, clone_expr(parse_select(query, placeholders=placeholders), clear_locations=True)) + return cast( + ast.SelectQuery, + clone_expr(parse_select(query, placeholders=placeholders), clear_locations=True), + ) def _print_hogql(self, select: str): expr = self._select(select) - return print_ast(expr, HogQLContext(team_id=self.team.pk, enable_select_queries=True), "hogql") + return print_ast( + expr, + HogQLContext(team_id=self.team.pk, enable_select_queries=True), + "hogql", + ) def setUp(self): self.database = create_hogql_database(self.team.pk) @@ -80,7 +87,8 @@ def test_will_not_run_twice(self): with self.assertRaises(ResolverException) as context: expr = resolve_types(expr, self.context) self.assertEqual( - str(context.exception), "Type already resolved for SelectQuery (SelectQueryType). Can't run again." + str(context.exception), + "Type already resolved for SelectQuery (SelectQueryType). Can't run again.", ) def test_resolve_events_table_alias(self): @@ -134,11 +142,17 @@ def test_resolve_events_table_column_alias(self): select_query_type = ast.SelectQueryType( aliases={ "ee": ast.FieldAliasType(alias="ee", type=event_field_type), - "e": ast.FieldAliasType(alias="e", type=ast.FieldAliasType(alias="ee", type=event_field_type)), + "e": ast.FieldAliasType( + alias="e", + type=ast.FieldAliasType(alias="ee", type=event_field_type), + ), }, columns={ "ee": ast.FieldAliasType(alias="ee", type=event_field_type), - "e": ast.FieldAliasType(alias="e", type=ast.FieldAliasType(alias="ee", type=event_field_type)), + "e": ast.FieldAliasType( + alias="e", + type=ast.FieldAliasType(alias="ee", type=event_field_type), + ), "timestamp": timestamp_field_type, }, tables={"e": events_table_alias_type}, @@ -184,7 +198,8 @@ def test_resolve_events_table_column_alias_inside_subquery(self): expr = resolve_types(expr, self.context) inner_events_table_type = ast.TableType(table=self.database.events) inner_event_field_type = ast.FieldAliasType( - alias="b", type=ast.FieldType(name="event", table_type=inner_events_table_type) + alias="b", + type=ast.FieldType(name="event", table_type=inner_events_table_type), ) timestamp_field_type = ast.FieldType(name="timestamp", table_type=inner_events_table_type) timstamp_alias_type = ast.FieldAliasType(alias="c", type=timestamp_field_type) @@ -288,13 +303,25 @@ def test_resolve_constant_type(self): ast.Constant(value=1.1232, type=ast.FloatType()), ast.Constant(value=None, type=ast.UnknownType()), ast.Constant(value=date(2020, 1, 10), type=ast.DateType()), - ast.Constant(value=datetime(2020, 1, 10, 0, 0, 0, tzinfo=timezone.utc), type=ast.DateTimeType()), - ast.Constant(value=UUID("00000000-0000-4000-8000-000000000000"), type=ast.UUIDType()), + ast.Constant( + value=datetime(2020, 1, 10, 0, 0, 0, tzinfo=timezone.utc), + type=ast.DateTimeType(), + ), + ast.Constant( + value=UUID("00000000-0000-4000-8000-000000000000"), + type=ast.UUIDType(), + ), ast.Constant(value=[], type=ast.ArrayType(item_type=ast.UnknownType())), ast.Constant(value=[1, 2], type=ast.ArrayType(item_type=ast.IntegerType())), ast.Constant( value=(1, 2, 3), - type=ast.TupleType(item_types=[ast.IntegerType(), ast.IntegerType(), ast.IntegerType()]), + type=ast.TupleType( + item_types=[ + ast.IntegerType(), + ast.IntegerType(), + ast.IntegerType(), + ] + ), ), ], type=ast.SelectQueryType(aliases={}, columns={}, tables={}), @@ -634,7 +661,9 @@ def test_resolve_virtual_events_poe(self): type=ast.FieldType( name="id", table_type=ast.VirtualTableType( - table_type=events_table_type, field="poe", virtual_table=self.database.events.fields["poe"] + table_type=events_table_type, + field="poe", + virtual_table=self.database.events.fields["poe"], ), ), ), @@ -674,15 +703,27 @@ def test_resolve_union_all(self): self.assertEqual( node.select_queries[0].select, [ - ast.Field(chain=["event"], type=ast.FieldType(name="event", table_type=events_table_type)), - ast.Field(chain=["timestamp"], type=ast.FieldType(name="timestamp", table_type=events_table_type)), + ast.Field( + chain=["event"], + type=ast.FieldType(name="event", table_type=events_table_type), + ), + ast.Field( + chain=["timestamp"], + type=ast.FieldType(name="timestamp", table_type=events_table_type), + ), ], ) self.assertEqual( node.select_queries[1].select, [ - ast.Field(chain=["event"], type=ast.FieldType(name="event", table_type=events_table_type)), - ast.Field(chain=["timestamp"], type=ast.FieldType(name="timestamp", table_type=events_table_type)), + ast.Field( + chain=["event"], + type=ast.FieldType(name="event", table_type=events_table_type), + ), + ast.Field( + chain=["timestamp"], + type=ast.FieldType(name="timestamp", table_type=events_table_type), + ), ], ) @@ -693,11 +734,18 @@ def test_call_type(self): ast.Call( name="max", # NB! timestamp was resolved to a DateTimeType for the Call's arg type. - type=ast.CallType(name="max", arg_types=[ast.DateTimeType()], return_type=ast.UnknownType()), + type=ast.CallType( + name="max", + arg_types=[ast.DateTimeType()], + return_type=ast.UnknownType(), + ), args=[ ast.Field( chain=["timestamp"], - type=ast.FieldType(name="timestamp", table_type=ast.TableType(table=self.database.events)), + type=ast.FieldType( + name="timestamp", + table_type=ast.TableType(table=self.database.events), + ), ) ], ), @@ -776,21 +824,58 @@ def test_asterisk_expander_table(self): self.assertEqual( node.select, [ - ast.Field(chain=["uuid"], type=ast.FieldType(name="uuid", table_type=events_table_type)), - ast.Field(chain=["event"], type=ast.FieldType(name="event", table_type=events_table_type)), - ast.Field(chain=["properties"], type=ast.FieldType(name="properties", table_type=events_table_type)), - ast.Field(chain=["timestamp"], type=ast.FieldType(name="timestamp", table_type=events_table_type)), - ast.Field(chain=["distinct_id"], type=ast.FieldType(name="distinct_id", table_type=events_table_type)), - ast.Field( - chain=["elements_chain"], type=ast.FieldType(name="elements_chain", table_type=events_table_type) - ), - ast.Field(chain=["created_at"], type=ast.FieldType(name="created_at", table_type=events_table_type)), - ast.Field(chain=["$session_id"], type=ast.FieldType(name="$session_id", table_type=events_table_type)), - ast.Field(chain=["$group_0"], type=ast.FieldType(name="$group_0", table_type=events_table_type)), - ast.Field(chain=["$group_1"], type=ast.FieldType(name="$group_1", table_type=events_table_type)), - ast.Field(chain=["$group_2"], type=ast.FieldType(name="$group_2", table_type=events_table_type)), - ast.Field(chain=["$group_3"], type=ast.FieldType(name="$group_3", table_type=events_table_type)), - ast.Field(chain=["$group_4"], type=ast.FieldType(name="$group_4", table_type=events_table_type)), + ast.Field( + chain=["uuid"], + type=ast.FieldType(name="uuid", table_type=events_table_type), + ), + ast.Field( + chain=["event"], + type=ast.FieldType(name="event", table_type=events_table_type), + ), + ast.Field( + chain=["properties"], + type=ast.FieldType(name="properties", table_type=events_table_type), + ), + ast.Field( + chain=["timestamp"], + type=ast.FieldType(name="timestamp", table_type=events_table_type), + ), + ast.Field( + chain=["distinct_id"], + type=ast.FieldType(name="distinct_id", table_type=events_table_type), + ), + ast.Field( + chain=["elements_chain"], + type=ast.FieldType(name="elements_chain", table_type=events_table_type), + ), + ast.Field( + chain=["created_at"], + type=ast.FieldType(name="created_at", table_type=events_table_type), + ), + ast.Field( + chain=["$session_id"], + type=ast.FieldType(name="$session_id", table_type=events_table_type), + ), + ast.Field( + chain=["$group_0"], + type=ast.FieldType(name="$group_0", table_type=events_table_type), + ), + ast.Field( + chain=["$group_1"], + type=ast.FieldType(name="$group_1", table_type=events_table_type), + ), + ast.Field( + chain=["$group_2"], + type=ast.FieldType(name="$group_2", table_type=events_table_type), + ), + ast.Field( + chain=["$group_3"], + type=ast.FieldType(name="$group_3", table_type=events_table_type), + ), + ast.Field( + chain=["$group_4"], + type=ast.FieldType(name="$group_4", table_type=events_table_type), + ), ], ) @@ -805,32 +890,58 @@ def test_asterisk_expander_table_alias(self): self.assertEqual( node.select, [ - ast.Field(chain=["uuid"], type=ast.FieldType(name="uuid", table_type=events_table_alias_type)), - ast.Field(chain=["event"], type=ast.FieldType(name="event", table_type=events_table_alias_type)), ast.Field( - chain=["properties"], type=ast.FieldType(name="properties", table_type=events_table_alias_type) + chain=["uuid"], + type=ast.FieldType(name="uuid", table_type=events_table_alias_type), ), ast.Field( - chain=["timestamp"], type=ast.FieldType(name="timestamp", table_type=events_table_alias_type) + chain=["event"], + type=ast.FieldType(name="event", table_type=events_table_alias_type), ), ast.Field( - chain=["distinct_id"], type=ast.FieldType(name="distinct_id", table_type=events_table_alias_type) + chain=["properties"], + type=ast.FieldType(name="properties", table_type=events_table_alias_type), + ), + ast.Field( + chain=["timestamp"], + type=ast.FieldType(name="timestamp", table_type=events_table_alias_type), + ), + ast.Field( + chain=["distinct_id"], + type=ast.FieldType(name="distinct_id", table_type=events_table_alias_type), ), ast.Field( chain=["elements_chain"], type=ast.FieldType(name="elements_chain", table_type=events_table_alias_type), ), ast.Field( - chain=["created_at"], type=ast.FieldType(name="created_at", table_type=events_table_alias_type) + chain=["created_at"], + type=ast.FieldType(name="created_at", table_type=events_table_alias_type), + ), + ast.Field( + chain=["$session_id"], + type=ast.FieldType(name="$session_id", table_type=events_table_alias_type), + ), + ast.Field( + chain=["$group_0"], + type=ast.FieldType(name="$group_0", table_type=events_table_alias_type), ), ast.Field( - chain=["$session_id"], type=ast.FieldType(name="$session_id", table_type=events_table_alias_type) + chain=["$group_1"], + type=ast.FieldType(name="$group_1", table_type=events_table_alias_type), + ), + ast.Field( + chain=["$group_2"], + type=ast.FieldType(name="$group_2", table_type=events_table_alias_type), + ), + ast.Field( + chain=["$group_3"], + type=ast.FieldType(name="$group_3", table_type=events_table_alias_type), + ), + ast.Field( + chain=["$group_4"], + type=ast.FieldType(name="$group_4", table_type=events_table_alias_type), ), - ast.Field(chain=["$group_0"], type=ast.FieldType(name="$group_0", table_type=events_table_alias_type)), - ast.Field(chain=["$group_1"], type=ast.FieldType(name="$group_1", table_type=events_table_alias_type)), - ast.Field(chain=["$group_2"], type=ast.FieldType(name="$group_2", table_type=events_table_alias_type)), - ast.Field(chain=["$group_3"], type=ast.FieldType(name="$group_3", table_type=events_table_alias_type)), - ast.Field(chain=["$group_4"], type=ast.FieldType(name="$group_4", table_type=events_table_alias_type)), ], ) @@ -852,8 +963,14 @@ def test_asterisk_expander_subquery(self): self.assertEqual( node.select, [ - ast.Field(chain=["a"], type=ast.FieldType(name="a", table_type=select_subquery_type)), - ast.Field(chain=["b"], type=ast.FieldType(name="b", table_type=select_subquery_type)), + ast.Field( + chain=["a"], + type=ast.FieldType(name="a", table_type=select_subquery_type), + ), + ast.Field( + chain=["b"], + type=ast.FieldType(name="b", table_type=select_subquery_type), + ), ], ) @@ -878,8 +995,14 @@ def test_asterisk_expander_subquery_alias(self): self.assertEqual( node.select, [ - ast.Field(chain=["a"], type=ast.FieldType(name="a", table_type=select_subquery_type)), - ast.Field(chain=["b"], type=ast.FieldType(name="b", table_type=select_subquery_type)), + ast.Field( + chain=["a"], + type=ast.FieldType(name="a", table_type=select_subquery_type), + ), + ast.Field( + chain=["b"], + type=ast.FieldType(name="b", table_type=select_subquery_type), + ), ], ) @@ -914,22 +1037,58 @@ def test_asterisk_expander_from_subquery_table(self): self.assertEqual( node.select, [ - ast.Field(chain=["uuid"], type=ast.FieldType(name="uuid", table_type=inner_select_type)), - ast.Field(chain=["event"], type=ast.FieldType(name="event", table_type=inner_select_type)), - ast.Field(chain=["properties"], type=ast.FieldType(name="properties", table_type=inner_select_type)), - ast.Field(chain=["timestamp"], type=ast.FieldType(name="timestamp", table_type=inner_select_type)), - ast.Field(chain=["distinct_id"], type=ast.FieldType(name="distinct_id", table_type=inner_select_type)), + ast.Field( + chain=["uuid"], + type=ast.FieldType(name="uuid", table_type=inner_select_type), + ), + ast.Field( + chain=["event"], + type=ast.FieldType(name="event", table_type=inner_select_type), + ), + ast.Field( + chain=["properties"], + type=ast.FieldType(name="properties", table_type=inner_select_type), + ), + ast.Field( + chain=["timestamp"], + type=ast.FieldType(name="timestamp", table_type=inner_select_type), + ), + ast.Field( + chain=["distinct_id"], + type=ast.FieldType(name="distinct_id", table_type=inner_select_type), + ), ast.Field( chain=["elements_chain"], type=ast.FieldType(name="elements_chain", table_type=inner_select_type), ), - ast.Field(chain=["created_at"], type=ast.FieldType(name="created_at", table_type=inner_select_type)), - ast.Field(chain=["$session_id"], type=ast.FieldType(name="$session_id", table_type=inner_select_type)), - ast.Field(chain=["$group_0"], type=ast.FieldType(name="$group_0", table_type=inner_select_type)), - ast.Field(chain=["$group_1"], type=ast.FieldType(name="$group_1", table_type=inner_select_type)), - ast.Field(chain=["$group_2"], type=ast.FieldType(name="$group_2", table_type=inner_select_type)), - ast.Field(chain=["$group_3"], type=ast.FieldType(name="$group_3", table_type=inner_select_type)), - ast.Field(chain=["$group_4"], type=ast.FieldType(name="$group_4", table_type=inner_select_type)), + ast.Field( + chain=["created_at"], + type=ast.FieldType(name="created_at", table_type=inner_select_type), + ), + ast.Field( + chain=["$session_id"], + type=ast.FieldType(name="$session_id", table_type=inner_select_type), + ), + ast.Field( + chain=["$group_0"], + type=ast.FieldType(name="$group_0", table_type=inner_select_type), + ), + ast.Field( + chain=["$group_1"], + type=ast.FieldType(name="$group_1", table_type=inner_select_type), + ), + ast.Field( + chain=["$group_2"], + type=ast.FieldType(name="$group_2", table_type=inner_select_type), + ), + ast.Field( + chain=["$group_3"], + type=ast.FieldType(name="$group_3", table_type=inner_select_type), + ), + ast.Field( + chain=["$group_4"], + type=ast.FieldType(name="$group_4", table_type=inner_select_type), + ), ], ) @@ -938,7 +1097,8 @@ def test_asterisk_expander_multiple_table_error(self): with self.assertRaises(ResolverException) as e: resolve_types(node, self.context) self.assertEqual( - str(e.exception), "Cannot use '*' without table name when there are multiple tables in the query" + str(e.exception), + "Cannot use '*' without table name when there are multiple tables in the query", ) @override_settings(PERSON_ON_EVENTS_OVERRIDE=False, PERSON_ON_EVENTS_V2_OVERRIDE=False) @@ -977,22 +1137,58 @@ def test_asterisk_expander_select_union(self): self.assertEqual( node.select, [ - ast.Field(chain=["uuid"], type=ast.FieldType(name="uuid", table_type=inner_select_type)), - ast.Field(chain=["event"], type=ast.FieldType(name="event", table_type=inner_select_type)), - ast.Field(chain=["properties"], type=ast.FieldType(name="properties", table_type=inner_select_type)), - ast.Field(chain=["timestamp"], type=ast.FieldType(name="timestamp", table_type=inner_select_type)), - ast.Field(chain=["distinct_id"], type=ast.FieldType(name="distinct_id", table_type=inner_select_type)), + ast.Field( + chain=["uuid"], + type=ast.FieldType(name="uuid", table_type=inner_select_type), + ), + ast.Field( + chain=["event"], + type=ast.FieldType(name="event", table_type=inner_select_type), + ), + ast.Field( + chain=["properties"], + type=ast.FieldType(name="properties", table_type=inner_select_type), + ), + ast.Field( + chain=["timestamp"], + type=ast.FieldType(name="timestamp", table_type=inner_select_type), + ), + ast.Field( + chain=["distinct_id"], + type=ast.FieldType(name="distinct_id", table_type=inner_select_type), + ), ast.Field( chain=["elements_chain"], type=ast.FieldType(name="elements_chain", table_type=inner_select_type), ), - ast.Field(chain=["created_at"], type=ast.FieldType(name="created_at", table_type=inner_select_type)), - ast.Field(chain=["$session_id"], type=ast.FieldType(name="$session_id", table_type=inner_select_type)), - ast.Field(chain=["$group_0"], type=ast.FieldType(name="$group_0", table_type=inner_select_type)), - ast.Field(chain=["$group_1"], type=ast.FieldType(name="$group_1", table_type=inner_select_type)), - ast.Field(chain=["$group_2"], type=ast.FieldType(name="$group_2", table_type=inner_select_type)), - ast.Field(chain=["$group_3"], type=ast.FieldType(name="$group_3", table_type=inner_select_type)), - ast.Field(chain=["$group_4"], type=ast.FieldType(name="$group_4", table_type=inner_select_type)), + ast.Field( + chain=["created_at"], + type=ast.FieldType(name="created_at", table_type=inner_select_type), + ), + ast.Field( + chain=["$session_id"], + type=ast.FieldType(name="$session_id", table_type=inner_select_type), + ), + ast.Field( + chain=["$group_0"], + type=ast.FieldType(name="$group_0", table_type=inner_select_type), + ), + ast.Field( + chain=["$group_1"], + type=ast.FieldType(name="$group_1", table_type=inner_select_type), + ), + ast.Field( + chain=["$group_2"], + type=ast.FieldType(name="$group_2", table_type=inner_select_type), + ), + ast.Field( + chain=["$group_3"], + type=ast.FieldType(name="$group_3", table_type=inner_select_type), + ), + ast.Field( + chain=["$group_4"], + type=ast.FieldType(name="$group_4", table_type=inner_select_type), + ), ], ) diff --git a/posthog/hogql/test/test_visitor.py b/posthog/hogql/test/test_visitor.py index d946af02073dd..78b2d6dc42536 100644 --- a/posthog/hogql/test/test_visitor.py +++ b/posthog/hogql/test/test_visitor.py @@ -66,7 +66,10 @@ def test_everything_visitor(self): ], ) ), - ast.Alias(expr=ast.SelectQuery(select=[ast.Field(chain=["timestamp"])]), alias="f"), + ast.Alias( + expr=ast.SelectQuery(select=[ast.Field(chain=["timestamp"])]), + alias="f", + ), ast.SelectQuery( select=[ast.Field(chain=["a"])], select_from=ast.JoinExpr( diff --git a/posthog/hogql/transforms/in_cohort.py b/posthog/hogql/transforms/in_cohort.py index aa1fe0e3a23ee..670d0a8e73c2a 100644 --- a/posthog/hogql/transforms/in_cohort.py +++ b/posthog/hogql/transforms/in_cohort.py @@ -9,12 +9,20 @@ from posthog.hogql.visitor import TraversingVisitor, clone_expr -def resolve_in_cohorts(node: ast.Expr, stack: Optional[List[ast.SelectQuery]] = None, context: HogQLContext = None): +def resolve_in_cohorts( + node: ast.Expr, + stack: Optional[List[ast.SelectQuery]] = None, + context: HogQLContext = None, +): InCohortResolver(stack=stack, context=context).visit(node) class InCohortResolver(TraversingVisitor): - def __init__(self, stack: Optional[List[ast.SelectQuery]] = None, context: HogQLContext = None): + def __init__( + self, + stack: Optional[List[ast.SelectQuery]] = None, + context: HogQLContext = None, + ): super().__init__() self.stack: List[ast.SelectQuery] = stack or [] self.context = context @@ -80,7 +88,12 @@ def visit_compare_operation(self, node: ast.CompareOperation): self.visit(node.right) def _add_join_for_cohort( - self, cohort_id: int, is_static: bool, select: ast.SelectQuery, compare: ast.CompareOperation, negative: bool + self, + cohort_id: int, + is_static: bool, + select: ast.SelectQuery, + compare: ast.CompareOperation, + negative: bool, ): must_add_join = True last_join = select.select_from @@ -115,9 +128,14 @@ def _add_join_for_cohort( ) ), ) - new_join = cast(ast.JoinExpr, resolve_types(new_join, self.context, [self.stack[-1].type])) + new_join = cast( + ast.JoinExpr, + resolve_types(new_join, self.context, [self.stack[-1].type]), + ) new_join.constraint.expr.left = resolve_types( - ast.Field(chain=[f"in_cohort__{cohort_id}", "person_id"]), self.context, [self.stack[-1].type] + ast.Field(chain=[f"in_cohort__{cohort_id}", "person_id"]), + self.context, + [self.stack[-1].type], ) new_join.constraint.expr.right = clone_expr(compare.left) if last_join: @@ -127,6 +145,8 @@ def _add_join_for_cohort( compare.op = ast.CompareOperationOp.NotEq if negative else ast.CompareOperationOp.Eq compare.left = resolve_types( - ast.Field(chain=[f"in_cohort__{cohort_id}", "matched"]), self.context, [self.stack[-1].type] + ast.Field(chain=[f"in_cohort__{cohort_id}", "matched"]), + self.context, + [self.stack[-1].type], ) compare.right = resolve_types(ast.Constant(value=1), self.context, [self.stack[-1].type]) diff --git a/posthog/hogql/transforms/lazy_tables.py b/posthog/hogql/transforms/lazy_tables.py index 543035f843460..48018cd789264 100644 --- a/posthog/hogql/transforms/lazy_tables.py +++ b/posthog/hogql/transforms/lazy_tables.py @@ -10,7 +10,11 @@ from posthog.hogql.visitor import TraversingVisitor -def resolve_lazy_tables(node: ast.Expr, stack: Optional[List[ast.SelectQuery]] = None, context: HogQLContext = None): +def resolve_lazy_tables( + node: ast.Expr, + stack: Optional[List[ast.SelectQuery]] = None, + context: HogQLContext = None, +): LazyTableResolver(stack=stack, context=context).visit(node) @@ -29,7 +33,11 @@ class TableToAdd: class LazyTableResolver(TraversingVisitor): - def __init__(self, stack: Optional[List[ast.SelectQuery]] = None, context: HogQLContext = None): + def __init__( + self, + stack: Optional[List[ast.SelectQuery]] = None, + context: HogQLContext = None, + ): super().__init__() self.stack_of_fields: List[List[ast.FieldType | ast.PropertyType]] = [[]] if stack else [] self.context = context @@ -188,7 +196,11 @@ def visit_select_query(self, node: ast.SelectQuery): # For all the collected joins, create the join subqueries, and add them to the table. for to_table, join_scope in joins_to_add.items(): join_to_add: ast.JoinExpr = join_scope.lazy_join.join_function( - join_scope.from_table, join_scope.to_table, join_scope.fields_accessed, self.context, node + join_scope.from_table, + join_scope.to_table, + join_scope.fields_accessed, + self.context, + node, ) join_to_add = cast(ast.JoinExpr, resolve_types(join_to_add, self.context, [node.type])) diff --git a/posthog/hogql/transforms/property_types.py b/posthog/hogql/transforms/property_types.py index be46d24873a91..a2fe60c9aaacd 100644 --- a/posthog/hogql/transforms/property_types.py +++ b/posthog/hogql/transforms/property_types.py @@ -46,7 +46,10 @@ def resolve_property_types(node: ast.Expr, context: HogQLContext = None) -> ast. timezone = context.database.get_timezone() if context and context.database else "UTC" property_swapper = PropertySwapper( - timezone=timezone, event_properties=event_properties, person_properties=person_properties, context=context + timezone=timezone, + event_properties=event_properties, + person_properties=person_properties, + context=context, ) return property_swapper.visit(node) @@ -83,7 +86,11 @@ def visit_field(self, node: ast.Field): class PropertySwapper(CloningVisitor): def __init__( - self, timezone: str, event_properties: Dict[str, str], person_properties: Dict[str, str], context: HogQLContext + self, + timezone: str, + event_properties: Dict[str, str], + person_properties: Dict[str, str], + context: HogQLContext, ): super().__init__(clear_types=False) self.timezone = timezone @@ -98,7 +105,9 @@ def visit_field(self, node: ast.Field): name="toTimeZone", args=[node, ast.Constant(value=self.timezone)], type=ast.CallType( - name="toTimeZone", arg_types=[ast.DateTimeType()], return_type=ast.DateTimeType() + name="toTimeZone", + arg_types=[ast.DateTimeType()], + return_type=ast.DateTimeType(), ), ) @@ -128,7 +137,10 @@ def visit_field(self, node: ast.Field): return node def _convert_string_property_to_type( - self, node: ast.Field, property_type: Literal["event", "person"], property_name: str + self, + node: ast.Field, + property_type: Literal["event", "person"], + property_name: str, ): posthog_field_type = ( self.person_properties.get(property_name) @@ -146,7 +158,12 @@ def _convert_string_property_to_type( return parse_expr("{node} = 'true'", {"node": node}) return node - def _add_property_notice(self, node: ast.Field, property_type: Literal["event", "person"], field_type: str) -> str: + def _add_property_notice( + self, + node: ast.Field, + property_type: Literal["event", "person"], + field_type: str, + ) -> str: property_name = node.chain[-1] if property_type == "person": if self.context.modifiers.personsOnEventsMode != PersonOnEventsMode.DISABLED: diff --git a/posthog/hogql/transforms/test/test_in_cohort.py b/posthog/hogql/transforms/test/test_in_cohort.py index dbef0b685aadf..26e2e18b66af7 100644 --- a/posthog/hogql/transforms/test/test_in_cohort.py +++ b/posthog/hogql/transforms/test/test_in_cohort.py @@ -8,7 +8,12 @@ from posthog.models.cohort.util import recalculate_cohortpeople from posthog.models.utils import UUIDT from posthog.schema import HogQLQueryModifiers -from posthog.test.base import BaseTest, _create_person, _create_event, flush_persons_and_events +from posthog.test.base import ( + BaseTest, + _create_person, + _create_event, + flush_persons_and_events, +) elements_chain_match = lambda x: parse_expr("match(elements_chain, {regex})", {"regex": ast.Constant(value=str(x))}) not_call = lambda x: ast.Call(name="not", args=[x]) @@ -33,7 +38,8 @@ def _create_random_events(self) -> str: def test_in_cohort_dynamic(self): random_uuid = self._create_random_events() cohort = Cohort.objects.create( - team=self.team, groups=[{"properties": [{"key": "$os", "value": "Chrome", "type": "person"}]}] + team=self.team, + groups=[{"properties": [{"key": "$os", "value": "Chrome", "type": "person"}]}], ) recalculate_cohortpeople(cohort, pending_version=0) response = execute_hogql_query( @@ -100,5 +106,8 @@ def test_in_cohort_error(self): self.assertEqual(str(e.exception), "cohort() takes exactly one string or integer argument") with self.assertRaises(HogQLException) as e: - execute_hogql_query(f"SELECT event FROM events WHERE person_id IN COHORT 'blabla'", self.team) + execute_hogql_query( + f"SELECT event FROM events WHERE person_id IN COHORT 'blabla'", + self.team, + ) self.assertEqual(str(e.exception), "Could not find a cohort with the name 'blabla'") diff --git a/posthog/hogql/transforms/test/test_lazy_tables.py b/posthog/hogql/transforms/test/test_lazy_tables.py index aad1dbae3fb1c..131fcb227fbbc 100644 --- a/posthog/hogql/transforms/test/test_lazy_tables.py +++ b/posthog/hogql/transforms/test/test_lazy_tables.py @@ -80,5 +80,9 @@ def test_select_count_from_lazy_table(self): def _print_select(self, select: str): expr = parse_select(select) - query = print_ast(expr, HogQLContext(team_id=self.team.pk, enable_select_queries=True), "clickhouse") + query = print_ast( + expr, + HogQLContext(team_id=self.team.pk, enable_select_queries=True), + "clickhouse", + ) return pretty_print_in_tests(query, self.team.pk) diff --git a/posthog/hogql/transforms/test/test_property_types.py b/posthog/hogql/transforms/test/test_property_types.py index c50f19a0a792d..10d8bf27cc97b 100644 --- a/posthog/hogql/transforms/test/test_property_types.py +++ b/posthog/hogql/transforms/test/test_property_types.py @@ -30,10 +30,16 @@ def setUp(self): defaults={"property_type": "Numeric"}, ) PropertyDefinition.objects.get_or_create( - team=self.team, type=PropertyDefinition.Type.EVENT, name="bool", defaults={"property_type": "Boolean"} + team=self.team, + type=PropertyDefinition.Type.EVENT, + name="bool", + defaults={"property_type": "Boolean"}, ) PropertyDefinition.objects.get_or_create( - team=self.team, type=PropertyDefinition.Type.PERSON, name="tickets", defaults={"property_type": "Numeric"} + team=self.team, + type=PropertyDefinition.Type.PERSON, + name="tickets", + defaults={"property_type": "Numeric"}, ) PropertyDefinition.objects.get_or_create( team=self.team, @@ -89,5 +95,9 @@ def test_resolve_property_types_event_person_poe_on(self): def _print_select(self, select: str): expr = parse_select(select) - query = print_ast(expr, HogQLContext(team_id=self.team.pk, enable_select_queries=True), "clickhouse") + query = print_ast( + expr, + HogQLContext(team_id=self.team.pk, enable_select_queries=True), + "clickhouse", + ) return pretty_print_in_tests(query, self.team.pk) diff --git a/posthog/hogql/visitor.py b/posthog/hogql/visitor.py index c8e1a5a57a789..db6b1ef6fb72e 100644 --- a/posthog/hogql/visitor.py +++ b/posthog/hogql/visitor.py @@ -128,8 +128,8 @@ def visit_select_query(self, node: ast.SelectQuery): self.visit(expr) for expr in node.limit_by or []: self.visit(expr) - self.visit(node.limit), - self.visit(node.offset), + (self.visit(node.limit),) + (self.visit(node.offset),) for expr in (node.window_exprs or {}).values(): self.visit(expr) @@ -248,7 +248,11 @@ def visit_join_constraint(self, node: ast.JoinConstraint): class CloningVisitor(Visitor): """Visitor that traverses and clones the AST tree. Clears types.""" - def __init__(self, clear_types: Optional[bool] = True, clear_locations: Optional[bool] = False): + def __init__( + self, + clear_types: Optional[bool] = True, + clear_locations: Optional[bool] = False, + ): self.clear_types = clear_types self.clear_locations = clear_locations diff --git a/posthog/hogql_queries/events_query_runner.py b/posthog/hogql_queries/events_query_runner.py index ff85691b983d3..d85d251684fa1 100644 --- a/posthog/hogql_queries/events_query_runner.py +++ b/posthog/hogql_queries/events_query_runner.py @@ -99,7 +99,9 @@ def to_query(self) -> ast.SelectQuery: with self.timings.measure("event"): where_exprs.append( parse_expr( - "event = {event}", {"event": ast.Constant(value=self.query.event)}, timings=self.timings + "event = {event}", + {"event": ast.Constant(value=self.query.event)}, + timings=self.timings, ) ) if self.query.actionId: @@ -118,7 +120,9 @@ def to_query(self) -> ast.SelectQuery: ids_list = list(map(str, distinct_ids)) where_exprs.append( parse_expr( - "distinct_id in {list}", {"list": ast.Constant(value=ids_list)}, timings=self.timings + "distinct_id in {list}", + {"list": ast.Constant(value=ids_list)}, + timings=self.timings, ) ) @@ -131,7 +135,9 @@ def to_query(self) -> ast.SelectQuery: parsed_date = relative_date_parse(before, self.team.timezone_info) where_exprs.append( parse_expr( - "timestamp < {timestamp}", {"timestamp": ast.Constant(value=parsed_date)}, timings=self.timings + "timestamp < {timestamp}", + {"timestamp": ast.Constant(value=parsed_date)}, + timings=self.timings, ) ) @@ -261,7 +267,10 @@ def select_input_raw(self) -> List[str]: def limit(self) -> int: # importing locally so we could override in a test - from posthog.hogql.constants import DEFAULT_RETURNED_ROWS, MAX_SELECT_RETURNED_ROWS + from posthog.hogql.constants import ( + DEFAULT_RETURNED_ROWS, + MAX_SELECT_RETURNED_ROWS, + ) # adding +1 to the limit to check if there's a "next page" after the requested results return ( diff --git a/posthog/hogql_queries/hogql_query_runner.py b/posthog/hogql_queries/hogql_query_runner.py index 815822ce894c6..576419fdff967 100644 --- a/posthog/hogql_queries/hogql_query_runner.py +++ b/posthog/hogql_queries/hogql_query_runner.py @@ -10,7 +10,13 @@ from posthog.hogql.timings import HogQLTimings from posthog.hogql_queries.query_runner import QueryRunner from posthog.models import Team -from posthog.schema import HogQLQuery, HogQLQueryResponse, DashboardFilter, HogQLFilters, DateRange +from posthog.schema import ( + HogQLQuery, + HogQLQueryResponse, + DashboardFilter, + HogQLFilters, + DateRange, +) class HogQLQueryRunner(QueryRunner): diff --git a/posthog/hogql_queries/insights/lifecycle_query_runner.py b/posthog/hogql_queries/insights/lifecycle_query_runner.py index ffa274958ceb0..87a8a345a8462 100644 --- a/posthog/hogql_queries/insights/lifecycle_query_runner.py +++ b/posthog/hogql_queries/insights/lifecycle_query_runner.py @@ -3,7 +3,10 @@ from typing import Optional, Any, Dict, List from django.utils.timezone import datetime -from posthog.caching.insights_api import BASE_MINIMUM_INSIGHT_REFRESH_INTERVAL, REDUCED_MINIMUM_INSIGHT_REFRESH_INTERVAL +from posthog.caching.insights_api import ( + BASE_MINIMUM_INSIGHT_REFRESH_INTERVAL, + REDUCED_MINIMUM_INSIGHT_REFRESH_INTERVAL, +) from posthog.caching.utils import is_stale from posthog.hogql import ast @@ -16,7 +19,12 @@ from posthog.models import Team, Action from posthog.hogql_queries.utils.query_date_range import QueryDateRange from posthog.models.filters.mixins.utils import cached_property -from posthog.schema import LifecycleQuery, ActionsNode, EventsNode, LifecycleQueryResponse +from posthog.schema import ( + LifecycleQuery, + ActionsNode, + EventsNode, + LifecycleQueryResponse, +) class LifecycleQueryRunner(QueryRunner): @@ -139,7 +147,10 @@ def calculate(self): @cached_property def query_date_range(self): return QueryDateRange( - date_range=self.query.dateRange, team=self.team, interval=self.query.interval, now=datetime.now() + date_range=self.query.dateRange, + team=self.team, + interval=self.query.interval, + now=datetime.now(), ) @cached_property diff --git a/posthog/hogql_queries/insights/test/test_events_query.py b/posthog/hogql_queries/insights/test/test_events_query.py index 707891d424a41..927829290367f 100644 --- a/posthog/hogql_queries/insights/test/test_events_query.py +++ b/posthog/hogql_queries/insights/test/test_events_query.py @@ -8,7 +8,12 @@ EventPropertyFilter, PropertyOperator, ) -from posthog.test.base import APIBaseTest, ClickhouseTestMixin, _create_event, _create_person +from posthog.test.base import ( + APIBaseTest, + ClickhouseTestMixin, + _create_event, + _create_person, +) class TestEventsQueryRunner(ClickhouseTestMixin, APIBaseTest): diff --git a/posthog/hogql_queries/insights/test/test_lifecycle_query_runner.py b/posthog/hogql_queries/insights/test/test_lifecycle_query_runner.py index 75637d5216ebd..1dba61d970e6c 100644 --- a/posthog/hogql_queries/insights/test/test_lifecycle_query_runner.py +++ b/posthog/hogql_queries/insights/test/test_lifecycle_query_runner.py @@ -6,7 +6,13 @@ from posthog.hogql_queries.insights.lifecycle_query_runner import LifecycleQueryRunner from posthog.models.utils import UUIDT from posthog.schema import DateRange, IntervalType, LifecycleQuery, EventsNode -from posthog.test.base import APIBaseTest, ClickhouseTestMixin, _create_event, _create_person, flush_persons_and_events +from posthog.test.base import ( + APIBaseTest, + ClickhouseTestMixin, + _create_event, + _create_person, + flush_persons_and_events, +) class TestLifecycleQueryRunner(ClickhouseTestMixin, APIBaseTest): @@ -26,7 +32,11 @@ def _create_random_events(self) -> str: distinct_id="bla", event="random event", team=self.team, - properties={"random_prop": "don't include", "random_uuid": random_uuid, "index": index}, + properties={ + "random_prop": "don't include", + "random_uuid": random_uuid, + "index": index, + }, ) flush_persons_and_events() return random_uuid @@ -39,7 +49,10 @@ def _create_events(self, data, event="$pageview"): _create_person( team_id=self.team.pk, distinct_ids=[id], - properties={"name": id, **({"email": "test@posthog.com"} if id == "p1" else {})}, + properties={ + "name": id, + **({"email": "test@posthog.com"} if id == "p1" else {}), + }, ) ) for timestamp in timestamps: @@ -69,7 +82,9 @@ def _create_test_events(self): def _create_query_runner(self, date_from, date_to, interval) -> LifecycleQueryRunner: series = [EventsNode(event="$pageview")] query = LifecycleQuery( - dateRange=DateRange(date_from=date_from, date_to=date_to), interval=interval, series=series + dateRange=DateRange(date_from=date_from, date_to=date_to), + interval=interval, + series=series, ) return LifecycleQueryRunner(team=self.team, query=query) diff --git a/posthog/hogql_queries/insights/trends/aggregation_operations.py b/posthog/hogql_queries/insights/trends/aggregation_operations.py index f585fc313dc70..3920344cbfd52 100644 --- a/posthog/hogql_queries/insights/trends/aggregation_operations.py +++ b/posthog/hogql_queries/insights/trends/aggregation_operations.py @@ -121,7 +121,10 @@ def _events_query(self, events_where_clause: ast.Expr, sample_value: ast.RatioEx timestamp, actor_id """, - placeholders={"events_where_clause": events_where_clause, "sample": sample_value}, + placeholders={ + "events_where_clause": events_where_clause, + "sample": sample_value, + }, ) def get_query_orchestrator(self, events_where_clause: ast.Expr, sample_value: str): diff --git a/posthog/hogql_queries/insights/trends/breakdown.py b/posthog/hogql_queries/insights/trends/breakdown.py index 403c5be4da536..a713cb09dcee1 100644 --- a/posthog/hogql_queries/insights/trends/breakdown.py +++ b/posthog/hogql_queries/insights/trends/breakdown.py @@ -4,7 +4,10 @@ from posthog.hogql.timings import HogQLTimings from posthog.hogql_queries.insights.trends.breakdown_session import BreakdownSession from posthog.hogql_queries.insights.trends.breakdown_values import BreakdownValues -from posthog.hogql_queries.insights.trends.utils import get_properties_chain, series_event_name +from posthog.hogql_queries.insights.trends.utils import ( + get_properties_chain, + series_event_name, +) from posthog.hogql_queries.utils.query_date_range import QueryDateRange from posthog.models.filters.mixins.utils import cached_property from posthog.models.team.team import Team @@ -143,7 +146,6 @@ def _get_breakdown_histogram_multi_if(self) -> ast.Expr: buckets = self._get_breakdown_histogram_buckets() for lower_bound, upper_bound in buckets: - multi_if_exprs.extend( [ ast.And( diff --git a/posthog/hogql_queries/insights/trends/breakdown_values.py b/posthog/hogql_queries/insights/trends/breakdown_values.py index 72ae54d0286be..37d9f7168e121 100644 --- a/posthog/hogql_queries/insights/trends/breakdown_values.py +++ b/posthog/hogql_queries/insights/trends/breakdown_values.py @@ -122,7 +122,12 @@ def _where_filter(self) -> ast.Expr: ) if self.event_name is not None: - filters.append(parse_expr("event = {event}", placeholders={"event": ast.Constant(value=self.event_name)})) + filters.append( + parse_expr( + "event = {event}", + placeholders={"event": ast.Constant(value=self.event_name)}, + ) + ) return ast.And(exprs=filters) diff --git a/posthog/hogql_queries/insights/trends/query_builder.py b/posthog/hogql_queries/insights/trends/query_builder.py index 3c0cd7d9356c7..0a90cae985dba 100644 --- a/posthog/hogql_queries/insights/trends/query_builder.py +++ b/posthog/hogql_queries/insights/trends/query_builder.py @@ -3,7 +3,9 @@ from posthog.hogql.parser import parse_expr, parse_select from posthog.hogql.property import property_to_expr from posthog.hogql.timings import HogQLTimings -from posthog.hogql_queries.insights.trends.aggregation_operations import AggregationOperations +from posthog.hogql_queries.insights.trends.aggregation_operations import ( + AggregationOperations, +) from posthog.hogql_queries.insights.trends.breakdown import Breakdown from posthog.hogql_queries.insights.trends.breakdown_session import BreakdownSession from posthog.hogql_queries.insights.trends.utils import series_event_name @@ -157,7 +159,8 @@ def _get_events_subquery(self) -> ast.SelectQuery: # Just complex series aggregation elif self._aggregation_operation.requires_query_orchestration(): return self._aggregation_operation.get_query_orchestrator( - events_where_clause=self._events_filter(), sample_value=self._sample_value() + events_where_clause=self._events_filter(), + sample_value=self._sample_value(), ).build() return default_query @@ -222,7 +225,8 @@ def _events_filter(self) -> ast.Expr: if series_event_name(self.series) is not None: filters.append( parse_expr( - "event = {event}", placeholders={"event": ast.Constant(value=series_event_name(self.series))} + "event = {event}", + placeholders={"event": ast.Constant(value=series_event_name(self.series))}, ) ) diff --git a/posthog/hogql_queries/insights/trends/test/test_trends_query_runner.py b/posthog/hogql_queries/insights/trends/test/test_trends_query_runner.py index 760c55577d7db..88e012672e12d 100644 --- a/posthog/hogql_queries/insights/trends/test/test_trends_query_runner.py +++ b/posthog/hogql_queries/insights/trends/test/test_trends_query_runner.py @@ -3,8 +3,19 @@ from freezegun import freeze_time from posthog.hogql_queries.insights.trends.trends_query_runner import TrendsQueryRunner -from posthog.schema import DateRange, EventsNode, IntervalType, TrendsFilter, TrendsQuery -from posthog.test.base import APIBaseTest, ClickhouseTestMixin, _create_event, _create_person +from posthog.schema import ( + DateRange, + EventsNode, + IntervalType, + TrendsFilter, + TrendsQuery, +) +from posthog.test.base import ( + APIBaseTest, + ClickhouseTestMixin, + _create_event, + _create_person, +) @dataclass @@ -41,7 +52,12 @@ def _create_events(self, data: List[SeriesTestData]): ) for event in person.events: for timestamp in event.timestamps: - _create_event(team=self.team, event=event.event, distinct_id=id, timestamp=timestamp) + _create_event( + team=self.team, + event=event.event, + distinct_id=id, + timestamp=timestamp, + ) return person_result def _create_test_events(self): @@ -74,7 +90,10 @@ def _create_test_events(self): SeriesTestData( distinct_id="p2", events=[ - Series(event="$pageview", timestamps=["2020-01-09T12:00:00Z", "2020-01-12T12:00:00Z"]), + Series( + event="$pageview", + timestamps=["2020-01-09T12:00:00Z", "2020-01-12T12:00:00Z"], + ), Series( event="$pageleave", timestamps=[ @@ -111,7 +130,12 @@ def _create_query_runner(self, date_from, date_to, interval, series, trends_filt return TrendsQueryRunner(team=self.team, query=query) def _run_trends_query( - self, date_from, date_to, interval, series=None, trends_filters: Optional[TrendsFilter] = None + self, + date_from, + date_to, + interval, + series=None, + trends_filters: Optional[TrendsFilter] = None, ): return self._create_query_runner(date_from, date_to, interval, series, trends_filters).calculate() @@ -221,7 +245,11 @@ def test_trends_query_compare(self): self._create_test_events() response = self._run_trends_query( - "2020-01-15", "2020-01-19", IntervalType.day, [EventsNode(event="$pageview")], TrendsFilter(compare=True) + "2020-01-15", + "2020-01-19", + IntervalType.day, + [EventsNode(event="$pageview")], + TrendsFilter(compare=True), ) self.assertEqual(2, len(response.results)) diff --git a/posthog/hogql_queries/insights/trends/trends_query_runner.py b/posthog/hogql_queries/insights/trends/trends_query_runner.py index 9c1dc4eca64f5..cfbcb60fdf28e 100644 --- a/posthog/hogql_queries/insights/trends/trends_query_runner.py +++ b/posthog/hogql_queries/insights/trends/trends_query_runner.py @@ -6,7 +6,10 @@ from typing import List, Optional, Any, Dict from django.utils.timezone import datetime -from posthog.caching.insights_api import BASE_MINIMUM_INSIGHT_REFRESH_INTERVAL, REDUCED_MINIMUM_INSIGHT_REFRESH_INTERVAL +from posthog.caching.insights_api import ( + BASE_MINIMUM_INSIGHT_REFRESH_INTERVAL, + REDUCED_MINIMUM_INSIGHT_REFRESH_INTERVAL, +) from posthog.caching.utils import is_stale from posthog.hogql import ast @@ -17,12 +20,20 @@ from posthog.hogql_queries.query_runner import QueryRunner from posthog.hogql_queries.utils.formula_ast import FormulaAST from posthog.hogql_queries.utils.query_date_range import QueryDateRange -from posthog.hogql_queries.utils.query_previous_period_date_range import QueryPreviousPeriodDateRange +from posthog.hogql_queries.utils.query_previous_period_date_range import ( + QueryPreviousPeriodDateRange, +) from posthog.models import Team from posthog.models.cohort.cohort import Cohort from posthog.models.filters.mixins.utils import cached_property from posthog.models.property_definition import PropertyDefinition -from posthog.schema import ActionsNode, EventsNode, HogQLQueryResponse, TrendsQuery, TrendsQueryResponse +from posthog.schema import ( + ActionsNode, + EventsNode, + HogQLQueryResponse, + TrendsQuery, + TrendsQueryResponse, +) class TrendsQueryRunner(QueryRunner): @@ -141,7 +152,10 @@ def build_series_response(self, response: HogQLQueryResponse, series: SeriesWith # Modifications for when comparing to previous period if self.query.trendsFilter is not None and self.query.trendsFilter.compare: labels = [ - "{} {}".format(self.query.interval if self.query.interval is not None else "day", i) + "{} {}".format( + self.query.interval if self.query.interval is not None else "day", + i, + ) for i in range(len(series_object["labels"])) ] @@ -171,13 +185,19 @@ def build_series_response(self, response: HogQLQueryResponse, series: SeriesWith @cached_property def query_date_range(self): return QueryDateRange( - date_range=self.query.dateRange, team=self.team, interval=self.query.interval, now=datetime.now() + date_range=self.query.dateRange, + team=self.team, + interval=self.query.interval, + now=datetime.now(), ) @cached_property def query_previous_date_range(self): return QueryPreviousPeriodDateRange( - date_range=self.query.dateRange, team=self.team, interval=self.query.interval, now=datetime.now() + date_range=self.query.dateRange, + team=self.team, + interval=self.query.interval, + now=datetime.now(), ) def series_event(self, series: EventsNode | ActionsNode) -> str | None: @@ -209,12 +229,16 @@ def setup_series(self) -> List[SeriesWithExtras]: for series in series_with_extras: updated_series.append( SeriesWithExtras( - series=series.series, is_previous_period_series=False, overriden_query=series.overriden_query + series=series.series, + is_previous_period_series=False, + overriden_query=series.overriden_query, ) ) updated_series.append( SeriesWithExtras( - series=series.series, is_previous_period_series=True, overriden_query=series.overriden_query + series=series.series, + is_previous_period_series=True, + overriden_query=series.overriden_query, ) ) series_with_extras = updated_series @@ -265,7 +289,9 @@ def _is_breakdown_field_boolean(self): property_type = PropertyDefinition.Type.EVENT field_type = self._event_property( - self.query.breakdown.breakdown, property_type, self.query.breakdown.breakdown_group_type_index + self.query.breakdown.breakdown, + property_type, + self.query.breakdown.breakdown_group_type_index, ) return field_type == "Boolean" @@ -273,7 +299,12 @@ def _convert_boolean(self, value: any): bool_map = {1: "true", 0: "false", "": ""} return bool_map.get(value) or value - def _event_property(self, field: str, field_type: PropertyDefinition.Type, group_type_index: Optional[int]): + def _event_property( + self, + field: str, + field_type: PropertyDefinition.Type, + group_type_index: Optional[int], + ): return PropertyDefinition.objects.get( name=field, team=self.team, diff --git a/posthog/hogql_queries/legacy_compatibility/filter_to_query.py b/posthog/hogql_queries/legacy_compatibility/filter_to_query.py index f8941c3899125..ce490cadfc834 100644 --- a/posthog/hogql_queries/legacy_compatibility/filter_to_query.py +++ b/posthog/hogql_queries/legacy_compatibility/filter_to_query.py @@ -240,11 +240,17 @@ def _properties(filter: Dict): if raw_properties is None or len(raw_properties) == 0: return {} elif isinstance(raw_properties, list): - raw_properties = {"type": "AND", "values": [{"type": "AND", "values": raw_properties}]} + raw_properties = { + "type": "AND", + "values": [{"type": "AND", "values": raw_properties}], + } return {"properties": PropertyGroupFilter(**clean_properties(raw_properties))} elif is_old_style_properties(raw_properties): raw_properties = transform_old_style_properties(raw_properties) - raw_properties = {"type": "AND", "values": [{"type": "AND", "values": raw_properties}]} + raw_properties = { + "type": "AND", + "values": [{"type": "AND", "values": raw_properties}], + } return {"properties": PropertyGroupFilter(**clean_properties(raw_properties))} else: return {"properties": PropertyGroupFilter(**clean_properties(raw_properties))} diff --git a/posthog/hogql_queries/legacy_compatibility/test/test_filter_to_query.py b/posthog/hogql_queries/legacy_compatibility/test/test_filter_to_query.py index f07405b248976..9a130faa9774f 100644 --- a/posthog/hogql_queries/legacy_compatibility/test/test_filter_to_query.py +++ b/posthog/hogql_queries/legacy_compatibility/test/test_filter_to_query.py @@ -58,8 +58,20 @@ } insight_2 = { "events": [ - {"id": "signed_up", "name": "signed_up", "type": "events", "order": 2, "custom_name": "Signed up"}, - {"id": "upgraded_plan", "name": "upgraded_plan", "type": "events", "order": 4, "custom_name": "Upgraded plan"}, + { + "id": "signed_up", + "name": "signed_up", + "type": "events", + "order": 2, + "custom_name": "Signed up", + }, + { + "id": "upgraded_plan", + "name": "upgraded_plan", + "type": "events", + "order": 4, + "custom_name": "Upgraded plan", + }, ], "actions": [{"id": 1, "name": "Interacted with file", "type": "actions", "order": 3}], "display": "FunnelViz", @@ -76,17 +88,45 @@ "properties": { "type": "AND", "values": [ - {"type": "AND", "values": [{"key": "email", "type": "person", "value": "is_set", "operator": "is_set"}]} + { + "type": "AND", + "values": [ + { + "key": "email", + "type": "person", + "value": "is_set", + "operator": "is_set", + } + ], + } ], }, - "target_entity": {"id": "signed_up", "name": "signed_up", "type": "events", "order": 0}, + "target_entity": { + "id": "signed_up", + "name": "signed_up", + "type": "events", + "order": 0, + }, "retention_type": "retention_first_time", "total_intervals": 9, - "returning_entity": {"id": 1, "name": "Interacted with file", "type": "actions", "order": 0}, + "returning_entity": { + "id": 1, + "name": "Interacted with file", + "type": "actions", + "order": 0, + }, } insight_4 = { "events": [], - "actions": [{"id": 1, "math": "total", "name": "Interacted with file", "type": "actions", "order": 0}], + "actions": [ + { + "id": 1, + "math": "total", + "name": "Interacted with file", + "type": "actions", + "order": 0, + } + ], "compare": False, "display": "ActionsLineGraph", "insight": "LIFECYCLE", @@ -128,7 +168,15 @@ "filter_test_accounts": True, } insight_6 = { - "events": [{"id": "paid_bill", "math": "sum", "type": "events", "order": 0, "math_property": "amount_usd"}], + "events": [ + { + "id": "paid_bill", + "math": "sum", + "type": "events", + "order": 0, + "math_property": "amount_usd", + } + ], "actions": [], "display": "ActionsLineGraph", "insight": "TRENDS", @@ -170,7 +218,14 @@ "values": [ { "type": "AND", - "values": [{"key": "$current_url", "type": "event", "value": "/files/", "operator": "not_icontains"}], + "values": [ + { + "key": "$current_url", + "type": "event", + "value": "/files/", + "operator": "not_icontains", + } + ], } ], }, @@ -184,7 +239,12 @@ "type": "events", "order": 0, "properties": [ - {"key": "$current_url", "type": "event", "value": "https://hedgebox.net/", "operator": "exact"} + { + "key": "$current_url", + "type": "event", + "value": "https://hedgebox.net/", + "operator": "exact", + } ], "custom_name": "Viewed homepage", }, @@ -194,11 +254,22 @@ "type": "events", "order": 1, "properties": [ - {"key": "$current_url", "type": "event", "value": "https://hedgebox.net/signup/", "operator": "regex"} + { + "key": "$current_url", + "type": "event", + "value": "https://hedgebox.net/signup/", + "operator": "regex", + } ], "custom_name": "Viewed signup page", }, - {"id": "signed_up", "name": "signed_up", "type": "events", "order": 2, "custom_name": "Signed up"}, + { + "id": "signed_up", + "name": "signed_up", + "type": "events", + "order": 2, + "custom_name": "Signed up", + }, ], "actions": [], "display": "FunnelViz", @@ -279,9 +350,24 @@ } insight_17 = { "events": [ - {"id": "$pageview", "type": "events", "order": 0, "custom_name": "First page view"}, - {"id": "$pageview", "type": "events", "order": 1, "custom_name": "Second page view"}, - {"id": "$pageview", "type": "events", "order": 2, "custom_name": "Third page view"}, + { + "id": "$pageview", + "type": "events", + "order": 0, + "custom_name": "First page view", + }, + { + "id": "$pageview", + "type": "events", + "order": 1, + "custom_name": "Second page view", + }, + { + "id": "$pageview", + "type": "events", + "order": 2, + "custom_name": "Third page view", + }, ], "layout": "horizontal", "display": "FunnelViz", @@ -303,7 +389,14 @@ "name": "Pageviews", "type": "actions", "order": 0, - "properties": [{"key": "$browser", "type": "event", "value": "Chrome", "operator": None}], + "properties": [ + { + "key": "$browser", + "type": "event", + "value": "Chrome", + "operator": None, + } + ], "math_property": None, } ], @@ -392,7 +485,14 @@ "interval": "day", "shown_as": "Volume", "breakdown": False, - "properties": [{"key": "$current_url", "type": "event", "value": "https://example.com/", "operator": "icontains"}], + "properties": [ + { + "key": "$current_url", + "type": "event", + "value": "https://example.com/", + "operator": "icontains", + } + ], "breakdown_type": "undefined", } insight_24 = { @@ -471,7 +571,12 @@ "type": "events", "order": 1, "properties": [ - {"key": "$current_url", "type": "event", "value": "posthog.com/signup$", "operator": "regex"} + { + "key": "$current_url", + "type": "event", + "value": "posthog.com/signup$", + "operator": "regex", + } ], "custom_name": "Views on signup page", }, @@ -491,7 +596,15 @@ "breakdown_group_type_index": 0, } insight_31 = { - "events": [{"id": "$autocapture", "math": "total", "name": "$autocapture", "type": "events", "order": 0}], + "events": [ + { + "id": "$autocapture", + "math": "total", + "name": "$autocapture", + "type": "events", + "order": 0, + } + ], "insight": "STICKINESS", "entity_type": "events", } @@ -592,7 +705,12 @@ def test_base_insights(filter: dict): properties_1 = [{"key": "account_id", "type": "event", "value": ["some_id"], "operator": "exact"}] properties_2 = [ {"key": "account_id", "type": "event", "value": ["some_id"], "operator": "exact"}, - {"key": "$current_url", "type": "event", "value": "/path", "operator": "not_icontains"}, + { + "key": "$current_url", + "type": "event", + "value": "/path", + "operator": "not_icontains", + }, ] properties_3 = {} properties_4 = {"type": "AND", "values": []} @@ -603,8 +721,18 @@ def test_base_insights(filter: dict): { "type": "AND", "values": [ - {"key": "$current_url", "type": "event", "value": "?", "operator": "not_icontains"}, - {"key": "$referring_domain", "type": "event", "value": "google", "operator": "icontains"}, + { + "key": "$current_url", + "type": "event", + "value": "?", + "operator": "not_icontains", + }, + { + "key": "$referring_domain", + "type": "event", + "value": "google", + "operator": "icontains", + }, ], } ], @@ -612,10 +740,19 @@ def test_base_insights(filter: dict): properties_7 = { "type": "AND", "values": [ - {"type": "AND", "values": [{"type": "AND", "values": []}, {"type": "AND", "values": []}]}, { "type": "AND", - "values": [{"key": "dateDiff('minute', timestamp, now()) < 5", "type": "hogql", "value": None}], + "values": [{"type": "AND", "values": []}, {"type": "AND", "values": []}], + }, + { + "type": "AND", + "values": [ + { + "key": "dateDiff('minute', timestamp, now()) < 5", + "type": "hogql", + "value": None, + } + ], }, ], } @@ -624,11 +761,23 @@ def test_base_insights(filter: dict): "values": [ { "type": "AND", - "values": [{"key": "dateDiff('minute', timestamp, now()) < 5", "type": "hogql", "value": None}], + "values": [ + { + "key": "dateDiff('minute', timestamp, now()) < 5", + "type": "hogql", + "value": None, + } + ], }, { "type": "AND", - "values": [{"key": "dateDiff('minute', timestamp, now()) < 5", "type": "hogql", "value": None}], + "values": [ + { + "key": "dateDiff('minute', timestamp, now()) < 5", + "type": "hogql", + "value": None, + } + ], }, ], } @@ -638,9 +787,24 @@ def test_base_insights(filter: dict): { "type": "AND", "values": [ - {"key": "$browser", "value": ["Chrome"], "operator": "exact", "type": "event"}, - {"key": "$browser", "value": ["Chrome"], "operator": "exact", "type": "person"}, - {"key": "$feature/hogql-insights", "value": ["true"], "operator": "exact", "type": "event"}, + { + "key": "$browser", + "value": ["Chrome"], + "operator": "exact", + "type": "event", + }, + { + "key": "$browser", + "value": ["Chrome"], + "operator": "exact", + "type": "person", + }, + { + "key": "$feature/hogql-insights", + "value": ["true"], + "operator": "exact", + "type": "event", + }, { "key": "site_url", "value": ["http://localhost:8000"], @@ -649,8 +813,18 @@ def test_base_insights(filter: dict): "group_type_index": 1, }, {"key": "id", "value": 2, "type": "cohort"}, - {"key": "tag_name", "value": ["elem"], "operator": "exact", "type": "element"}, - {"key": "$session_duration", "value": None, "operator": "gt", "type": "session"}, + { + "key": "tag_name", + "value": ["elem"], + "operator": "exact", + "type": "element", + }, + { + "key": "$session_duration", + "value": None, + "operator": "gt", + "type": "session", + }, {"type": "hogql", "key": "properties.name", "value": None}, ], }, @@ -659,7 +833,14 @@ def test_base_insights(filter: dict): } properties_10 = [{"key": "id", "type": "cohort", "value": 71, "operator": None}] properties_11 = [{"key": [498], "type": "cohort", "value": 498, "operator": None}] -properties_12 = [{"key": "userId", "type": "event", "values": ["63ffaeae99ac3c4240976d60"], "operator": "exact"}] +properties_12 = [ + { + "key": "userId", + "type": "event", + "values": ["63ffaeae99ac3c4240976d60"], + "operator": "exact", + } +] properties_13 = {"plan": "premium"} properties_14 = {"$current_url__icontains": "signin"} @@ -783,7 +964,10 @@ def test_series_custom(self): def test_series_order(self): filter = { - "events": [{"id": "$pageview", "order": 1}, {"id": "$pageview", "math": "dau", "order": 2}], + "events": [ + {"id": "$pageview", "order": 1}, + {"id": "$pageview", "math": "dau", "order": 2}, + ], "actions": [{"id": 1, "order": 3}, {"id": 1, "math": "dau", "order": 0}], } @@ -803,9 +987,20 @@ def test_series_math(self): filter = { "events": [ {"id": "$pageview", "math": "dau"}, # base math type - {"id": "$pageview", "math": "median", "math_property": "$math_prop"}, # property math type - {"id": "$pageview", "math": "avg_count_per_actor"}, # count per actor math type - {"id": "$pageview", "math": "unique_group", "math_group_type_index": 0}, # unique group + { + "id": "$pageview", + "math": "median", + "math_property": "$math_prop", + }, # property math type + { + "id": "$pageview", + "math": "avg_count_per_actor", + }, # count per actor math type + { + "id": "$pageview", + "math": "unique_group", + "math_group_type_index": 0, + }, # unique group { "id": "$pageview", "math": "hogql", @@ -821,10 +1016,22 @@ def test_series_math(self): [ EventsNode(event="$pageview", name="$pageview", math=BaseMathType.dau), EventsNode( - event="$pageview", name="$pageview", math=PropertyMathType.median, math_property="$math_prop" + event="$pageview", + name="$pageview", + math=PropertyMathType.median, + math_property="$math_prop", + ), + EventsNode( + event="$pageview", + name="$pageview", + math=CountPerActorMathType.avg_count_per_actor, + ), + EventsNode( + event="$pageview", + name="$pageview", + math="unique_group", + math_group_type_index=0, ), - EventsNode(event="$pageview", name="$pageview", math=CountPerActorMathType.avg_count_per_actor), - EventsNode(event="$pageview", name="$pageview", math="unique_group", math_group_type_index=0), EventsNode( event="$pageview", name="$pageview", @@ -840,21 +1047,52 @@ def test_series_properties(self): {"id": "$pageview", "properties": []}, # smoke test { "id": "$pageview", - "properties": [{"key": "success", "type": "event", "value": ["true"], "operator": "exact"}], + "properties": [ + { + "key": "success", + "type": "event", + "value": ["true"], + "operator": "exact", + } + ], }, { "id": "$pageview", - "properties": [{"key": "email", "type": "person", "value": "is_set", "operator": "is_set"}], + "properties": [ + { + "key": "email", + "type": "person", + "value": "is_set", + "operator": "is_set", + } + ], }, { "id": "$pageview", - "properties": [{"key": "text", "value": ["some text"], "operator": "exact", "type": "element"}], + "properties": [ + { + "key": "text", + "value": ["some text"], + "operator": "exact", + "type": "element", + } + ], + }, + { + "id": "$pageview", + "properties": [ + { + "key": "$session_duration", + "value": 1, + "operator": "gt", + "type": "session", + } + ], }, { "id": "$pageview", - "properties": [{"key": "$session_duration", "value": 1, "operator": "gt", "type": "session"}], + "properties": [{"key": "id", "value": 2, "type": "cohort"}], }, - {"id": "$pageview", "properties": [{"key": "id", "value": 2, "type": "cohort"}]}, { "id": "$pageview", "properties": [ @@ -870,14 +1108,28 @@ def test_series_properties(self): { "id": "$pageview", "properties": [ - {"key": "dateDiff('minute', timestamp, now()) < 30", "type": "hogql", "value": None} + { + "key": "dateDiff('minute', timestamp, now()) < 30", + "type": "hogql", + "value": None, + } ], }, { "id": "$pageview", "properties": [ - {"key": "$referring_domain", "type": "event", "value": "google", "operator": "icontains"}, - {"key": "utm_source", "type": "event", "value": "is_not_set", "operator": "is_not_set"}, + { + "key": "$referring_domain", + "type": "event", + "value": "google", + "operator": "icontains", + }, + { + "key": "utm_source", + "type": "event", + "value": "is_not_set", + "operator": "is_not_set", + }, ], }, ] @@ -892,18 +1144,34 @@ def test_series_properties(self): EventsNode( event="$pageview", name="$pageview", - properties=[EventPropertyFilter(key="success", value=["true"], operator=PropertyOperator.exact)], + properties=[ + EventPropertyFilter( + key="success", + value=["true"], + operator=PropertyOperator.exact, + ) + ], ), EventsNode( event="$pageview", name="$pageview", - properties=[PersonPropertyFilter(key="email", value="is_set", operator=PropertyOperator.is_set)], + properties=[ + PersonPropertyFilter( + key="email", + value="is_set", + operator=PropertyOperator.is_set, + ) + ], ), EventsNode( event="$pageview", name="$pageview", properties=[ - ElementPropertyFilter(key=Key.text, value=["some text"], operator=PropertyOperator.exact) + ElementPropertyFilter( + key=Key.text, + value=["some text"], + operator=PropertyOperator.exact, + ) ], ), EventsNode( @@ -911,13 +1179,20 @@ def test_series_properties(self): name="$pageview", properties=[SessionPropertyFilter(value=1, operator=PropertyOperator.gt)], ), - EventsNode(event="$pageview", name="$pageview", properties=[CohortPropertyFilter(value=2)]), + EventsNode( + event="$pageview", + name="$pageview", + properties=[CohortPropertyFilter(value=2)], + ), EventsNode( event="$pageview", name="$pageview", properties=[ GroupPropertyFilter( - key="name", value=["Hedgebox Inc."], operator=PropertyOperator.exact, group_type_index=2 + key="name", + value=["Hedgebox Inc."], + operator=PropertyOperator.exact, + group_type_index=2, ) ], ), @@ -931,9 +1206,15 @@ def test_series_properties(self): name="$pageview", properties=[ EventPropertyFilter( - key="$referring_domain", value="google", operator=PropertyOperator.icontains + key="$referring_domain", + value="google", + operator=PropertyOperator.icontains, + ), + EventPropertyFilter( + key="utm_source", + value="is_not_set", + operator=PropertyOperator.is_not_set, ), - EventPropertyFilter(key="utm_source", value="is_not_set", operator=PropertyOperator.is_not_set), ], ), ], @@ -1070,7 +1351,11 @@ def test_retention_filter(self): "retention_type": "retention_first_time", # retention_reference="previous", "total_intervals": 12, - "returning_entity": {"id": "$pageview", "name": "$pageview", "type": "events"}, + "returning_entity": { + "id": "$pageview", + "name": "$pageview", + "type": "events", + }, "target_entity": {"id": "$pageview", "name": "$pageview", "type": "events"}, "period": "Week", } @@ -1119,7 +1404,13 @@ def test_paths_filter(self): "funnel_filter": { "insight": "FUNNELS", "events": [ - {"type": "events", "id": "$pageview", "order": 0, "name": "$pageview", "math": "total"}, + { + "type": "events", + "id": "$pageview", + "order": 0, + "name": "$pageview", + "math": "total", + }, {"type": "events", "id": None, "order": 1, "math": "total"}, ], "funnel_viz_type": "steps", @@ -1152,7 +1443,13 @@ def test_paths_filter(self): funnel_filter={ "insight": "FUNNELS", "events": [ - {"type": "events", "id": "$pageview", "order": 0, "name": "$pageview", "math": "total"}, + { + "type": "events", + "id": "$pageview", + "order": 0, + "name": "$pageview", + "math": "total", + }, {"type": "events", "id": None, "order": 1, "math": "total"}, ], "funnel_viz_type": "steps", diff --git a/posthog/hogql_queries/persons_query_runner.py b/posthog/hogql_queries/persons_query_runner.py index a373a1acbf7d9..d597f4bab1c2a 100644 --- a/posthog/hogql_queries/persons_query_runner.py +++ b/posthog/hogql_queries/persons_query_runner.py @@ -69,7 +69,11 @@ def filter_conditions(self) -> List[ast.Expr]: source_query_runner = get_query_runner(source, self.team, self.timings) source_query = source_query_runner.to_persons_query() where_exprs.append( - ast.CompareOperation(left=ast.Field(chain=["id"]), op=ast.CompareOperationOp.In, right=source_query) + ast.CompareOperation( + left=ast.Field(chain=["id"]), + op=ast.CompareOperationOp.In, + right=source_query, + ) ) except NotImplementedError: raise ValueError(f"Queries of type '{source.kind}' are not implemented as a PersonsQuery sources.") @@ -113,7 +117,10 @@ def input_columns(self) -> List[str]: return self.query.select or ["person", "id", "created_at", "person.$delete"] def query_limit(self) -> int: - return min(MAX_SELECT_RETURNED_ROWS, DEFAULT_RETURNED_ROWS if self.query.limit is None else self.query.limit) + return min( + MAX_SELECT_RETURNED_ROWS, + DEFAULT_RETURNED_ROWS if self.query.limit is None else self.query.limit, + ) def to_query(self) -> ast.SelectQuery: with self.timings.measure("columns"): @@ -175,7 +182,8 @@ def to_query(self) -> ast.SelectQuery: ast.OrderExpr( expr=ast.Field(chain=["properties", order_property]), order=cast( - Literal["ASC", "DESC"], "DESC" if self.query.orderBy[0] == "person DESC" else "ASC" + Literal["ASC", "DESC"], + "DESC" if self.query.orderBy[0] == "person DESC" else "ASC", ), ) ] diff --git a/posthog/hogql_queries/test/test_hogql_query_runner.py b/posthog/hogql_queries/test/test_hogql_query_runner.py index 6af80f638e3ba..badc27efef3bf 100644 --- a/posthog/hogql_queries/test/test_hogql_query_runner.py +++ b/posthog/hogql_queries/test/test_hogql_query_runner.py @@ -3,7 +3,13 @@ from posthog.hogql_queries.hogql_query_runner import HogQLQueryRunner from posthog.models.utils import UUIDT from posthog.schema import HogQLPropertyFilter, HogQLQuery, HogQLFilters -from posthog.test.base import APIBaseTest, ClickhouseTestMixin, _create_person, flush_persons_and_events, _create_event +from posthog.test.base import ( + APIBaseTest, + ClickhouseTestMixin, + _create_person, + flush_persons_and_events, + _create_event, +) class TestHogQLQueryRunner(ClickhouseTestMixin, APIBaseTest): @@ -24,7 +30,11 @@ def _create_random_persons(self) -> str: distinct_ids=[f"id-{random_uuid}-{index}"], is_identified=True, ) - _create_event(distinct_id=f"id-{random_uuid}-{index}", event=f"clicky-{index}", team=self.team) + _create_event( + distinct_id=f"id-{random_uuid}-{index}", + event=f"clicky-{index}", + team=self.team, + ) flush_persons_and_events() return random_uuid @@ -60,7 +70,9 @@ def test_hogql_query_filters(self): select=[ast.Call(name="count", args=[ast.Field(chain=["event"])])], select_from=ast.JoinExpr(table=ast.Field(chain=["events"])), where=ast.CompareOperation( - left=ast.Field(chain=["event"]), op=ast.CompareOperationOp.Eq, right=ast.Constant(value="clicky-3") + left=ast.Field(chain=["event"]), + op=ast.CompareOperationOp.Eq, + right=ast.Constant(value="clicky-3"), ), ) self.assertEqual(clear_locations(query), expected) @@ -69,7 +81,10 @@ def test_hogql_query_filters(self): def test_hogql_query_values(self): runner = self._create_runner( - HogQLQuery(query="select count(event) from events where event={e}", values={"e": "clicky-3"}) + HogQLQuery( + query="select count(event) from events where event={e}", + values={"e": "clicky-3"}, + ) ) query = runner.to_query() query = clear_locations(query) @@ -77,7 +92,9 @@ def test_hogql_query_values(self): select=[ast.Call(name="count", args=[ast.Field(chain=["event"])])], select_from=ast.JoinExpr(table=ast.Field(chain=["events"])), where=ast.CompareOperation( - left=ast.Field(chain=["event"]), op=ast.CompareOperationOp.Eq, right=ast.Constant(value="clicky-3") + left=ast.Field(chain=["event"]), + op=ast.CompareOperationOp.Eq, + right=ast.Constant(value="clicky-3"), ), ) self.assertEqual(clear_locations(query), expected) diff --git a/posthog/hogql_queries/test/test_persons_query_runner.py b/posthog/hogql_queries/test/test_persons_query_runner.py index fbe65319a5912..7460d8cd728b7 100644 --- a/posthog/hogql_queries/test/test_persons_query_runner.py +++ b/posthog/hogql_queries/test/test_persons_query_runner.py @@ -13,7 +13,13 @@ EventsNode, IntervalType, ) -from posthog.test.base import APIBaseTest, ClickhouseTestMixin, _create_person, flush_persons_and_events, _create_event +from posthog.test.base import ( + APIBaseTest, + ClickhouseTestMixin, + _create_person, + flush_persons_and_events, + _create_event, +) from freezegun import freeze_time @@ -35,7 +41,11 @@ def _create_random_persons(self) -> str: distinct_ids=[f"id-{random_uuid}-{index}"], is_identified=True, ) - _create_event(distinct_id=f"id-{random_uuid}-{index}", event=f"clicky-{index}", team=self.team) + _create_event( + distinct_id=f"id-{random_uuid}-{index}", + event=f"clicky-{index}", + team=self.team, + ) flush_persons_and_events() return random_uuid @@ -81,7 +91,11 @@ def test_persons_query_properties(self): runner = self._create_runner( PersonsQuery( properties=[ - PersonPropertyFilter(key="random_uuid", value=self.random_uuid, operator=PropertyOperator.exact), + PersonPropertyFilter( + key="random_uuid", + value=self.random_uuid, + operator=PropertyOperator.exact, + ), HogQLPropertyFilter(key="toInt(properties.index) > 5"), ] ) @@ -93,7 +107,11 @@ def test_persons_query_fixed_properties(self): runner = self._create_runner( PersonsQuery( fixedProperties=[ - PersonPropertyFilter(key="random_uuid", value=self.random_uuid, operator=PropertyOperator.exact), + PersonPropertyFilter( + key="random_uuid", + value=self.random_uuid, + operator=PropertyOperator.exact, + ), HogQLPropertyFilter(key="toInt(properties.index) < 2"), ] ) @@ -144,7 +162,12 @@ def test_persons_query_limit(self): self.assertEqual(response.hasMore, True) runner = self._create_runner( - PersonsQuery(select=["properties.email"], orderBy=["properties.email DESC"], limit=1, offset=2) + PersonsQuery( + select=["properties.email"], + orderBy=["properties.email DESC"], + limit=1, + offset=2, + ) ) response = runner.calculate() self.assertEqual(response.results, [[f"jacob7@{self.random_uuid}.posthog.com"]]) @@ -153,7 +176,11 @@ def test_persons_query_limit(self): def test_source_hogql_query(self): self.random_uuid = self._create_random_persons() source_query = HogQLQuery(query="SELECT distinct person_id FROM events WHERE event='clicky-4'") - query = PersonsQuery(select=["properties.email"], orderBy=["properties.email DESC"], source=source_query) + query = PersonsQuery( + select=["properties.email"], + orderBy=["properties.email DESC"], + source=source_query, + ) runner = self._create_runner(query) response = runner.calculate() self.assertEqual(response.results, [[f"jacob4@{self.random_uuid}.posthog.com"]]) @@ -165,12 +192,20 @@ def test_source_lifecycle_query(self): source_query = LifecycleQuery( series=[EventsNode(event="clicky-4")], properties=[ - PersonPropertyFilter(key="random_uuid", value=self.random_uuid, operator=PropertyOperator.exact) + PersonPropertyFilter( + key="random_uuid", + value=self.random_uuid, + operator=PropertyOperator.exact, + ) ], interval=IntervalType.day, dateRange=DateRange(date_from="-7d"), ) - query = PersonsQuery(select=["properties.email"], orderBy=["properties.email DESC"], source=source_query) + query = PersonsQuery( + select=["properties.email"], + orderBy=["properties.email DESC"], + source=source_query, + ) runner = self._create_runner(query) response = runner.calculate() self.assertEqual(response.results, [[f"jacob4@{self.random_uuid}.posthog.com"]]) diff --git a/posthog/hogql_queries/test/test_query_runner.py b/posthog/hogql_queries/test/test_query_runner.py index 9ac9cb5956df2..5b82b0fae5af9 100644 --- a/posthog/hogql_queries/test/test_query_runner.py +++ b/posthog/hogql_queries/test/test_query_runner.py @@ -6,7 +6,11 @@ from freezegun import freeze_time from pydantic import BaseModel -from posthog.hogql_queries.query_runner import QueryResponse, QueryRunner, RunnableQueryNode +from posthog.hogql_queries.query_runner import ( + QueryResponse, + QueryRunner, + RunnableQueryNode, +) from posthog.models.team.team import Team from posthog.test.base import BaseTest diff --git a/posthog/hogql_queries/utils/query_date_range.py b/posthog/hogql_queries/utils/query_date_range.py index 9c2a99e62d61f..be4e993326486 100644 --- a/posthog/hogql_queries/utils/query_date_range.py +++ b/posthog/hogql_queries/utils/query_date_range.py @@ -11,7 +11,11 @@ from posthog.models.team import Team from posthog.queries.util import get_earliest_timestamp from posthog.schema import DateRange, IntervalType -from posthog.utils import DEFAULT_DATE_FROM_DAYS, relative_date_parse, relative_date_parse_with_delta_mapping +from posthog.utils import ( + DEFAULT_DATE_FROM_DAYS, + relative_date_parse, + relative_date_parse_with_delta_mapping, +) # Originally similar to posthog/queries/query_date_range.py but rewritten to be used in HogQL queries @@ -24,7 +28,11 @@ class QueryDateRange: _now_without_timezone: datetime def __init__( - self, date_range: Optional[DateRange], team: Team, interval: Optional[IntervalType], now: datetime + self, + date_range: Optional[DateRange], + team: Team, + interval: Optional[IntervalType], + now: datetime, ) -> None: self._team = team self._date_range = date_range @@ -40,7 +48,10 @@ def date_to(self) -> datetime: if self._date_range and self._date_range.date_to: date_to, delta_mapping = relative_date_parse_with_delta_mapping( - self._date_range.date_to, self._team.timezone_info, always_truncate=True, now=self.now_with_timezone + self._date_range.date_to, + self._team.timezone_info, + always_truncate=True, + now=self.now_with_timezone, ) is_relative = not self._date_range or not self._date_range.date_to or delta_mapping is not None @@ -60,7 +71,9 @@ def date_from(self) -> datetime: date_from = self.get_earliest_timestamp() elif self._date_range and isinstance(self._date_range.date_from, str): date_from = relative_date_parse( - self._date_range.date_from, self._team.timezone_info, now=self.now_with_timezone + self._date_range.date_from, + self._team.timezone_info, + now=self.now_with_timezone, ) else: date_from = self.now_with_timezone.replace(hour=0, minute=0, second=0, microsecond=0) - relativedelta( @@ -106,25 +119,38 @@ def interval_name(self) -> str: def date_to_as_hogql(self) -> ast.Expr: return ast.Call( - name="assumeNotNull", args=[ast.Call(name="toDateTime", args=[(ast.Constant(value=self.date_to_str))])] + name="assumeNotNull", + args=[ast.Call(name="toDateTime", args=[(ast.Constant(value=self.date_to_str))])], ) def date_from_as_hogql(self) -> ast.Expr: return ast.Call( - name="assumeNotNull", args=[ast.Call(name="toDateTime", args=[(ast.Constant(value=self.date_from_str))])] + name="assumeNotNull", + args=[ast.Call(name="toDateTime", args=[(ast.Constant(value=self.date_from_str))])], ) def previous_period_date_from_as_hogql(self) -> ast.Expr: return ast.Call( name="assumeNotNull", - args=[ast.Call(name="toDateTime", args=[(ast.Constant(value=self.previous_period_date_from_str))])], + args=[ + ast.Call( + name="toDateTime", + args=[(ast.Constant(value=self.previous_period_date_from_str))], + ) + ], ) def one_interval_period(self) -> ast.Expr: - return ast.Call(name=f"toInterval{self.interval_name.capitalize()}", args=[ast.Constant(value=1)]) + return ast.Call( + name=f"toInterval{self.interval_name.capitalize()}", + args=[ast.Constant(value=1)], + ) def number_interval_periods(self) -> ast.Expr: - return ast.Call(name=f"toInterval{self.interval_name.capitalize()}", args=[ast.Field(chain=["number"])]) + return ast.Call( + name=f"toInterval{self.interval_name.capitalize()}", + args=[ast.Field(chain=["number"])], + ) def interval_period_string_as_hogql_constant(self) -> ast.Expr: return ast.Constant(value=self.interval_name) @@ -143,7 +169,13 @@ def to_properties(self, field: Optional[List[str]] = None) -> List[ast.Expr]: field = ["timestamp"] return [ ast.CompareOperation( - left=ast.Field(chain=field), op=CompareOperationOp.LtEq, right=self.date_to_as_hogql() + left=ast.Field(chain=field), + op=CompareOperationOp.LtEq, + right=self.date_to_as_hogql(), + ), + ast.CompareOperation( + left=ast.Field(chain=field), + op=CompareOperationOp.Gt, + right=self.date_to_as_hogql(), ), - ast.CompareOperation(left=ast.Field(chain=field), op=CompareOperationOp.Gt, right=self.date_to_as_hogql()), ] diff --git a/posthog/hogql_queries/utils/query_previous_period_date_range.py b/posthog/hogql_queries/utils/query_previous_period_date_range.py index ac16f0b9eec10..c127ac3e36d07 100644 --- a/posthog/hogql_queries/utils/query_previous_period_date_range.py +++ b/posthog/hogql_queries/utils/query_previous_period_date_range.py @@ -4,7 +4,10 @@ from posthog.hogql_queries.utils.query_date_range import QueryDateRange from posthog.models.team import Team from posthog.schema import DateRange, IntervalType -from posthog.utils import get_compare_period_dates, relative_date_parse_with_delta_mapping +from posthog.utils import ( + get_compare_period_dates, + relative_date_parse_with_delta_mapping, +) # Originally similar to posthog/queries/query_date_range.py but rewritten to be used in HogQL queries @@ -17,14 +20,20 @@ class QueryPreviousPeriodDateRange(QueryDateRange): _now_without_timezone: datetime def __init__( - self, date_range: Optional[DateRange], team: Team, interval: Optional[IntervalType], now: datetime + self, + date_range: Optional[DateRange], + team: Team, + interval: Optional[IntervalType], + now: datetime, ) -> None: super().__init__(date_range, team, interval, now) def date_from_delta_mappings(self) -> Dict[str, int] | None: if self._date_range and isinstance(self._date_range.date_from, str) and self._date_range.date_from != "all": delta_mapping = relative_date_parse_with_delta_mapping( - self._date_range.date_from, self._team.timezone_info, now=self.now_with_timezone + self._date_range.date_from, + self._team.timezone_info, + now=self.now_with_timezone, )[1] return delta_mapping @@ -33,7 +42,10 @@ def date_from_delta_mappings(self) -> Dict[str, int] | None: def date_to_delta_mappings(self) -> Dict[str, int] | None: if self._date_range and self._date_range.date_to: delta_mapping = relative_date_parse_with_delta_mapping( - self._date_range.date_to, self._team.timezone_info, always_truncate=True, now=self.now_with_timezone + self._date_range.date_to, + self._team.timezone_info, + always_truncate=True, + now=self.now_with_timezone, )[1] return delta_mapping return None diff --git a/posthog/hogql_queries/web_analytics/stats_table.py b/posthog/hogql_queries/web_analytics/stats_table.py index 12e739413f2d1..dbd92defd2814 100644 --- a/posthog/hogql_queries/web_analytics/stats_table.py +++ b/posthog/hogql_queries/web_analytics/stats_table.py @@ -5,7 +5,9 @@ COUNTS_CTE, BOUNCE_RATE_CTE, ) -from posthog.hogql_queries.web_analytics.web_analytics_query_runner import WebAnalyticsQueryRunner +from posthog.hogql_queries.web_analytics.web_analytics_query_runner import ( + WebAnalyticsQueryRunner, +) from posthog.schema import ( WebStatsTableQuery, WebStatsBreakdown, diff --git a/posthog/hogql_queries/web_analytics/top_clicks.py b/posthog/hogql_queries/web_analytics/top_clicks.py index 004cad7947c93..1693f2c1d86ce 100644 --- a/posthog/hogql_queries/web_analytics/top_clicks.py +++ b/posthog/hogql_queries/web_analytics/top_clicks.py @@ -4,7 +4,9 @@ from posthog.hogql.parser import parse_select from posthog.hogql.query import execute_hogql_query from posthog.hogql_queries.utils.query_date_range import QueryDateRange -from posthog.hogql_queries.web_analytics.web_analytics_query_runner import WebAnalyticsQueryRunner +from posthog.hogql_queries.web_analytics.web_analytics_query_runner import ( + WebAnalyticsQueryRunner, +) from posthog.models.filters.mixins.utils import cached_property from posthog.schema import WebTopClicksQuery, WebTopClicksQueryResponse @@ -51,9 +53,17 @@ def calculate(self): ) return WebTopClicksQueryResponse( - columns=response.columns, results=response.results, timings=response.timings, types=response.types + columns=response.columns, + results=response.results, + timings=response.timings, + types=response.types, ) @cached_property def query_date_range(self): - return QueryDateRange(date_range=self.query.dateRange, team=self.team, interval=None, now=datetime.now()) + return QueryDateRange( + date_range=self.query.dateRange, + team=self.team, + interval=None, + now=datetime.now(), + ) diff --git a/posthog/hogql_queries/web_analytics/web_analytics_query_runner.py b/posthog/hogql_queries/web_analytics/web_analytics_query_runner.py index a9d0092565f59..16f31272d43a4 100644 --- a/posthog/hogql_queries/web_analytics/web_analytics_query_runner.py +++ b/posthog/hogql_queries/web_analytics/web_analytics_query_runner.py @@ -35,7 +35,12 @@ def _refresh_frequency(self): @cached_property def query_date_range(self): - return QueryDateRange(date_range=self.query.dateRange, team=self.team, interval=None, now=datetime.now()) + return QueryDateRange( + date_range=self.query.dateRange, + team=self.team, + interval=None, + now=datetime.now(), + ) @cached_property def pathname_property_filter(self) -> Optional[EventPropertyFilter]: diff --git a/posthog/hogql_queries/web_analytics/web_overview.py b/posthog/hogql_queries/web_analytics/web_overview.py index 062bf72d2968e..19a587245443d 100644 --- a/posthog/hogql_queries/web_analytics/web_overview.py +++ b/posthog/hogql_queries/web_analytics/web_overview.py @@ -7,7 +7,9 @@ from posthog.hogql.property import property_to_expr from posthog.hogql.query import execute_hogql_query from posthog.hogql_queries.utils.query_date_range import QueryDateRange -from posthog.hogql_queries.web_analytics.web_analytics_query_runner import WebAnalyticsQueryRunner +from posthog.hogql_queries.web_analytics.web_analytics_query_runner import ( + WebAnalyticsQueryRunner, +) from posthog.models.filters.mixins.utils import cached_property from posthog.schema import WebOverviewQueryResponse, WebOverviewQuery @@ -118,14 +120,23 @@ def calculate(self): @cached_property def query_date_range(self): - return QueryDateRange(date_range=self.query.dateRange, team=self.team, interval=None, now=datetime.now()) + return QueryDateRange( + date_range=self.query.dateRange, + team=self.team, + interval=None, + now=datetime.now(), + ) def event_properties(self) -> ast.Expr: return property_to_expr(self.query.properties, team=self.team) def to_data( - key: str, kind: str, value: Optional[float], previous: Optional[float], is_increase_bad: Optional[bool] = None + key: str, + kind: str, + value: Optional[float], + previous: Optional[float], + is_increase_bad: Optional[bool] = None, ) -> dict: if kind == "percentage": if value is not None: diff --git a/posthog/jwt.py b/posthog/jwt.py index 73d42c80c3ee1..fa458ab2f5e3f 100644 --- a/posthog/jwt.py +++ b/posthog/jwt.py @@ -20,7 +20,11 @@ def encode_jwt(payload: dict, expiry_delta: timedelta, audience: PosthogJwtAudie raise Exception("Audience must be in the list of PostHog-supported audiences") encoded_jwt = jwt.encode( - {**payload, "exp": datetime.now(tz=timezone.utc) + expiry_delta, "aud": audience.value}, + { + **payload, + "exp": datetime.now(tz=timezone.utc) + expiry_delta, + "aud": audience.value, + }, settings.SECRET_KEY, algorithm="HS256", ) diff --git a/posthog/kafka_client/client.py b/posthog/kafka_client/client.py index 2de052c8e73f8..a22de73a8fffe 100644 --- a/posthog/kafka_client/client.py +++ b/posthog/kafka_client/client.py @@ -6,7 +6,11 @@ from django.conf import settings from kafka import KafkaConsumer as KC from kafka import KafkaProducer as KP -from kafka.producer.future import FutureProduceResult, FutureRecordMetadata, RecordMetadata +from kafka.producer.future import ( + FutureProduceResult, + FutureRecordMetadata, + RecordMetadata, +) from kafka.structs import TopicPartition from statshog.defaults.django import statsd from structlog import get_logger @@ -24,7 +28,13 @@ class KafkaProducerForTests: def __init__(self): pass - def send(self, topic: str, value: Any, key: Any = None, headers: Optional[List[Tuple[str, bytes]]] = None): + def send( + self, + topic: str, + value: Any, + key: Any = None, + headers: Optional[List[Tuple[str, bytes]]] = None, + ): produce_future = FutureProduceResult(topic_partition=TopicPartition(topic, 1)) future = FutureRecordMetadata( produce_future=produce_future, @@ -81,7 +91,10 @@ class _KafkaSecurityProtocol(str, Enum): def _sasl_params(): - if settings.KAFKA_SECURITY_PROTOCOL in [_KafkaSecurityProtocol.SASL_PLAINTEXT, _KafkaSecurityProtocol.SASL_SSL]: + if settings.KAFKA_SECURITY_PROTOCOL in [ + _KafkaSecurityProtocol.SASL_PLAINTEXT, + _KafkaSecurityProtocol.SASL_SSL, + ]: return { "sasl_mechanism": settings.KAFKA_SASL_MECHANISM, "sasl_plain_username": settings.KAFKA_SASL_USER, @@ -135,7 +148,10 @@ def on_send_success(self, record_metadata: RecordMetadata): statsd.incr("posthog_cloud_kafka_send_success", tags={"topic": record_metadata.topic}) def on_send_failure(self, topic: str, exc: Exception): - statsd.incr("posthog_cloud_kafka_send_failure", tags={"topic": topic, "exception": exc.__class__.__name__}) + statsd.incr( + "posthog_cloud_kafka_send_failure", + tags={"topic": topic, "exception": exc.__class__.__name__}, + ) def produce( self, @@ -208,7 +224,10 @@ def build_kafka_consumer( ): if test: consumer = KafkaConsumerForTests( - topic=topic, auto_offset_reset=auto_offset_reset, max=10, consumer_timeout_ms=consumer_timeout_ms + topic=topic, + auto_offset_reset=auto_offset_reset, + max=10, + consumer_timeout_ms=consumer_timeout_ms, ) elif settings.KAFKA_BASE64_KEYS: consumer = helper.get_kafka_consumer( diff --git a/posthog/logging/timing.py b/posthog/logging/timing.py index b736450e0d8d7..d83b692fb2894 100644 --- a/posthog/logging/timing.py +++ b/posthog/logging/timing.py @@ -34,7 +34,8 @@ def wrapper(*args, **kwargs): finally: duration = round((time() - start) * 1000, 1) print( # noqa T201 - f"Timed function: {fn_name} took {duration}ms with args", {"args": args, "kwargs": kwargs} + f"Timed function: {fn_name} took {duration}ms with args", + {"args": args, "kwargs": kwargs}, ) return wrapper diff --git a/posthog/management/commands/backfill_persons_and_groups_on_events.py b/posthog/management/commands/backfill_persons_and_groups_on_events.py index 04880e7fa32dc..b7fb2fcbc46e9 100644 --- a/posthog/management/commands/backfill_persons_and_groups_on_events.py +++ b/posthog/management/commands/backfill_persons_and_groups_on_events.py @@ -138,7 +138,6 @@ def print_and_execute_query(sql: str, name: str, dry_run: bool, timeout=180, que def run_backfill(options): - if not options["team_id"]: logger.error("You must specify --team-id to run this script") exit(1) @@ -149,12 +148,20 @@ def run_backfill(options): print("Dry run. Queries to run:", end="\n\n") print_and_execute_query(GROUPS_DICTIONARY_SQL, "GROUPS_DICTIONARY_SQL", dry_run) - print_and_execute_query(PERSON_DISTINCT_IDS_DICTIONARY_SQL, "PERSON_DISTINCT_IDS_DICTIONARY_SQL", dry_run) + print_and_execute_query( + PERSON_DISTINCT_IDS_DICTIONARY_SQL, + "PERSON_DISTINCT_IDS_DICTIONARY_SQL", + dry_run, + ) print_and_execute_query(PERSONS_DICTIONARY_SQL, "PERSONS_DICTIONARY_SQL", dry_run) tag_queries(kind="backfill", id=backfill_query_id) print_and_execute_query( - BACKFILL_SQL, "BACKFILL_SQL", dry_run, 0, {"team_id": options["team_id"], "id": backfill_query_id} + BACKFILL_SQL, + "BACKFILL_SQL", + dry_run, + 0, + {"team_id": options["team_id"], "id": backfill_query_id}, ) reset_query_tags() @@ -177,11 +184,17 @@ class Command(BaseCommand): help = "Backfill persons and groups data on events for a given team" def add_arguments(self, parser): - - parser.add_argument("--team-id", default=None, type=str, help="Specify a team to backfill data for.") + parser.add_argument( + "--team-id", + default=None, + type=str, + help="Specify a team to backfill data for.", + ) parser.add_argument( - "--live-run", action="store_true", help="Opts out of default 'dry run' mode and actually runs the queries." + "--live-run", + action="store_true", + help="Opts out of default 'dry run' mode and actually runs the queries.", ) def handle(self, *args, **options): diff --git a/posthog/management/commands/create_batch_export_from_app.py b/posthog/management/commands/create_batch_export_from_app.py index 510e0f3dbfa4d..6fa577f582c55 100644 --- a/posthog/management/commands/create_batch_export_from_app.py +++ b/posthog/management/commands/create_batch_export_from_app.py @@ -15,7 +15,9 @@ class Command(BaseCommand): def add_arguments(self, parser): """Add arguments to the parser.""" parser.add_argument( - "--plugin-config-id", type=int, help="The ID of the PluginConfig to use as a base for the new BatchExport" + "--plugin-config-id", + type=int, + help="The ID of the PluginConfig to use as a base for the new BatchExport", ) parser.add_argument( "--team-id", @@ -116,7 +118,11 @@ def handle(self, *args, **options): end_at = dt.datetime.utcnow() start_at = end_at - (dt.timedelta(hours=1) if interval == "hour" else dt.timedelta(days=1)) backfill_export( - client, batch_export_id=str(batch_export.id), team_id=team_id, start_at=start_at, end_at=end_at + client, + batch_export_id=str(batch_export.id), + team_id=team_id, + start_at=start_at, + end_at=end_at, ) self.stdout.write(f"Triggered backfill for BatchExport '{name}'.") diff --git a/posthog/management/commands/create_ch_migration.py b/posthog/management/commands/create_ch_migration.py index 3b5334498589b..3f4495a0825b9 100644 --- a/posthog/management/commands/create_ch_migration.py +++ b/posthog/management/commands/create_ch_migration.py @@ -10,6 +10,7 @@ operations = [] """ + # ex: python manage.py create_ch_migration class Command(BaseCommand): help = "Create blank clickhouse migration" diff --git a/posthog/management/commands/execute_temporal_workflow.py b/posthog/management/commands/execute_temporal_workflow.py index 73d61979ab909..df9f5d993fc07 100644 --- a/posthog/management/commands/execute_temporal_workflow.py +++ b/posthog/management/commands/execute_temporal_workflow.py @@ -31,17 +31,45 @@ def add_arguments(self, parser): "Set an ID in order to limit concurrency." ), ) - parser.add_argument("--temporal-host", default=settings.TEMPORAL_HOST, help="Hostname for Temporal Scheduler") - parser.add_argument("--temporal-port", default=settings.TEMPORAL_PORT, help="Port for Temporal Scheduler") - parser.add_argument("--namespace", default=settings.TEMPORAL_NAMESPACE, help="Namespace to connect to") - parser.add_argument("--task-queue", default=settings.TEMPORAL_TASK_QUEUE, help="Task queue to service") parser.add_argument( - "--server-root-ca-cert", default=settings.TEMPORAL_CLIENT_ROOT_CA, help="Optional root server CA cert" + "--temporal-host", + default=settings.TEMPORAL_HOST, + help="Hostname for Temporal Scheduler", ) - parser.add_argument("--client-cert", default=settings.TEMPORAL_CLIENT_CERT, help="Optional client cert") - parser.add_argument("--client-key", default=settings.TEMPORAL_CLIENT_KEY, help="Optional client key") parser.add_argument( - "--max-attempts", default=settings.TEMPORAL_WORKFLOW_MAX_ATTEMPTS, help="Number of max attempts" + "--temporal-port", + default=settings.TEMPORAL_PORT, + help="Port for Temporal Scheduler", + ) + parser.add_argument( + "--namespace", + default=settings.TEMPORAL_NAMESPACE, + help="Namespace to connect to", + ) + parser.add_argument( + "--task-queue", + default=settings.TEMPORAL_TASK_QUEUE, + help="Task queue to service", + ) + parser.add_argument( + "--server-root-ca-cert", + default=settings.TEMPORAL_CLIENT_ROOT_CA, + help="Optional root server CA cert", + ) + parser.add_argument( + "--client-cert", + default=settings.TEMPORAL_CLIENT_CERT, + help="Optional client cert", + ) + parser.add_argument( + "--client-key", + default=settings.TEMPORAL_CLIENT_KEY, + help="Optional client key", + ) + parser.add_argument( + "--max-attempts", + default=settings.TEMPORAL_WORKFLOW_MAX_ATTEMPTS, + help="Number of max attempts", ) def handle(self, *args, **options): diff --git a/posthog/management/commands/generate_demo_data.py b/posthog/management/commands/generate_demo_data.py index 3948813b854ad..2a6e27c992345 100644 --- a/posthog/management/commands/generate_demo_data.py +++ b/posthog/management/commands/generate_demo_data.py @@ -20,7 +20,9 @@ class Command(BaseCommand): def add_arguments(self, parser): parser.add_argument("--seed", type=str, help="Simulation seed for deterministic output") parser.add_argument( - "--now", type=dt.datetime.fromisoformat, help="Simulation 'now' datetime in ISO format (default: now)" + "--now", + type=dt.datetime.fromisoformat, + help="Simulation 'now' datetime in ISO format (default: now)", ) parser.add_argument( "--days-past", @@ -34,7 +36,12 @@ def add_arguments(self, parser): default=30, help="At how many days after 'now' should the simulation end (default: 30)", ) - parser.add_argument("--n-clusters", type=int, default=500, help="Number of clusters (default: 500)") + parser.add_argument( + "--n-clusters", + type=int, + default=500, + help="Number of clusters (default: 500)", + ) parser.add_argument("--dry-run", action="store_true", help="Don't save simulation results") parser.add_argument( "--team-id", @@ -43,10 +50,16 @@ def add_arguments(self, parser): help="If specified, an existing project with this ID will be used, and no new user will be created. If the ID is 0, data will be generated for the master project (but insights etc. won't be created)", ) parser.add_argument( - "--email", type=str, default="test@posthog.com", help="Email of the demo user (default: test@posthog.com)" + "--email", + type=str, + default="test@posthog.com", + help="Email of the demo user (default: test@posthog.com)", ) parser.add_argument( - "--password", type=str, default="12345678", help="Password of the demo user (default: 12345678)" + "--password", + type=str, + default="12345678", + help="Password of the demo user (default: 12345678)", ) def handle(self, *args, **options): @@ -74,7 +87,12 @@ def handle(self, *args, **options): ) print("Running simulation...") matrix.simulate() - self.print_results(matrix, seed=seed, duration=monotonic() - timer, verbosity=options["verbosity"]) + self.print_results( + matrix, + seed=seed, + duration=monotonic() - timer, + verbosity=options["verbosity"], + ) if not options["dry_run"]: email = options["email"] password = options["password"] @@ -89,7 +107,11 @@ def handle(self, *args, **options): matrix_manager.run_on_team(team, existing_user) else: matrix_manager.ensure_account_and_save( - email, "Employee 427", "Hedgebox Inc.", password=password, disallow_collision=True + email, + "Employee 427", + "Hedgebox Inc.", + password=password, + disallow_collision=True, ) except exceptions.ValidationError as e: print(f"Error: {e}") diff --git a/posthog/management/commands/makemigrations.py b/posthog/management/commands/makemigrations.py index 3ab70d9bc0800..8ff0a37bfaa34 100644 --- a/posthog/management/commands/makemigrations.py +++ b/posthog/management/commands/makemigrations.py @@ -1,6 +1,8 @@ """Cause git to detect a merge conflict when two branches have migrations.""" -from django.core.management.commands.makemigrations import Command as MakeMigrationsCommand +from django.core.management.commands.makemigrations import ( + Command as MakeMigrationsCommand, +) from django.db.migrations.loader import MigrationLoader diff --git a/posthog/management/commands/migrate_clickhouse.py b/posthog/management/commands/migrate_clickhouse.py index 82da287a1743d..b9a4d31eea3d9 100644 --- a/posthog/management/commands/migrate_clickhouse.py +++ b/posthog/management/commands/migrate_clickhouse.py @@ -6,7 +6,12 @@ from infi.clickhouse_orm.migrations import MigrationHistory from infi.clickhouse_orm.utils import import_submodules -from posthog.settings import CLICKHOUSE_DATABASE, CLICKHOUSE_HTTP_URL, CLICKHOUSE_PASSWORD, CLICKHOUSE_USER +from posthog.settings import ( + CLICKHOUSE_DATABASE, + CLICKHOUSE_HTTP_URL, + CLICKHOUSE_PASSWORD, + CLICKHOUSE_USER, +) from posthog.settings.data_stores import CLICKHOUSE_CLUSTER MIGRATIONS_PACKAGE_NAME = "posthog.clickhouse.migrations" @@ -17,14 +22,25 @@ class Command(BaseCommand): def add_arguments(self, parser): parser.add_argument( - "--upto", default=99_999, type=int, help="Database state will be brought to the state after that migration." + "--upto", + default=99_999, + type=int, + help="Database state will be brought to the state after that migration.", ) - parser.add_argument("--fake", action="store_true", help="Mark migrations as run without actually running them.") parser.add_argument( - "--check", action="store_true", help="Exits with a non-zero status if unapplied migrations exist." + "--fake", + action="store_true", + help="Mark migrations as run without actually running them.", ) parser.add_argument( - "--plan", action="store_true", help="Shows a list of the migration actions that will be performed." + "--check", + action="store_true", + help="Exits with a non-zero status if unapplied migrations exist.", + ) + parser.add_argument( + "--plan", + action="store_true", + help="Shows a list of the migration actions that will be performed.", ) parser.add_argument( "--print-sql", diff --git a/posthog/management/commands/notify_helm_install.py b/posthog/management/commands/notify_helm_install.py index ce0b5c3b333f1..684261cdae418 100644 --- a/posthog/management/commands/notify_helm_install.py +++ b/posthog/management/commands/notify_helm_install.py @@ -25,5 +25,10 @@ def handle(self, *args, **options): posthoganalytics.api_key = "sTMFPsFhdP1Ssg" disabled = posthoganalytics.disabled posthoganalytics.disabled = False - posthoganalytics.capture(get_machine_id(), "helm_install", report, groups={"instance": settings.SITE_URL}) + posthoganalytics.capture( + get_machine_id(), + "helm_install", + report, + groups={"instance": settings.SITE_URL}, + ) posthoganalytics.disabled = disabled diff --git a/posthog/management/commands/partition.py b/posthog/management/commands/partition.py index 68a24aef0efc0..b17e958b0c1e1 100644 --- a/posthog/management/commands/partition.py +++ b/posthog/management/commands/partition.py @@ -18,7 +18,6 @@ def add_arguments(self, parser): parser.add_argument("--reverse", action="store_true", help="unpartition event table") def handle(self, *args, **options): - if options["reverse"]: print("Reversing partitions...") with connection.cursor() as cursor: diff --git a/posthog/management/commands/plugin_server_load_test.py b/posthog/management/commands/plugin_server_load_test.py index 3fe197c154393..4adfe8941e644 100644 --- a/posthog/management/commands/plugin_server_load_test.py +++ b/posthog/management/commands/plugin_server_load_test.py @@ -32,7 +32,9 @@ class Command(BaseCommand): def add_arguments(self, parser): parser.add_argument("--seed", type=str, help="Simulation seed for deterministic output") parser.add_argument( - "--now", type=dt.datetime.fromisoformat, help="Simulation 'now' datetime in ISO format (default: now)" + "--now", + type=dt.datetime.fromisoformat, + help="Simulation 'now' datetime in ISO format (default: now)", ) parser.add_argument( "--days-past", @@ -46,9 +48,17 @@ def add_arguments(self, parser): default=30, help="At how many days after 'now' should the simulation end (default: 30)", ) - parser.add_argument("--n-clusters", type=int, default=500, help="Number of clusters (default: 500)") parser.add_argument( - "--team-id", type=str, default="1", help="The team to which the events should be associated." + "--n-clusters", + type=int, + default=500, + help="Number of clusters (default: 500)", + ) + parser.add_argument( + "--team-id", + type=str, + default="1", + help="The team to which the events should be associated.", ) def handle(self, *args, **options): @@ -83,7 +93,8 @@ def handle(self, *args, **options): # Make sure events are ordered by time to simulate how they would be # ingested in real life. ordered_events = sorted( - chain.from_iterable(person.all_events for person in matrix.people), key=lambda e: e.timestamp + chain.from_iterable(person.all_events for person in matrix.people), + key=lambda e: e.timestamp, ) start_time = time.monotonic() @@ -107,7 +118,11 @@ def handle(self, *args, **options): offsets = admin.list_consumer_group_offsets(group_id="clickhouse-ingestion") end_offsets = consumer.end_offsets([TopicPartition(topic=KAFKA_EVENTS_PLUGIN_INGESTION_TOPIC, partition=0)]) if end_offsets is None: - logger.error("no_end_offsets", topic=KAFKA_EVENTS_PLUGIN_INGESTION_TOPIC, partition=0) + logger.error( + "no_end_offsets", + topic=KAFKA_EVENTS_PLUGIN_INGESTION_TOPIC, + partition=0, + ) sys.exit(1) end_offset = end_offsets[TopicPartition(topic=KAFKA_EVENTS_PLUGIN_INGESTION_TOPIC, partition=0)] diff --git a/posthog/management/commands/run_async_migrations.py b/posthog/management/commands/run_async_migrations.py index e0b9cfef5cb20..611c6038fd43b 100644 --- a/posthog/management/commands/run_async_migrations.py +++ b/posthog/management/commands/run_async_migrations.py @@ -6,8 +6,16 @@ from django.core.management.base import BaseCommand from semantic_version.base import Version -from posthog.async_migrations.runner import complete_migration, is_migration_dependency_fulfilled, start_async_migration -from posthog.async_migrations.setup import ALL_ASYNC_MIGRATIONS, setup_async_migrations, setup_model +from posthog.async_migrations.runner import ( + complete_migration, + is_migration_dependency_fulfilled, + start_async_migration, +) +from posthog.async_migrations.setup import ( + ALL_ASYNC_MIGRATIONS, + setup_async_migrations, + setup_model, +) from posthog.constants import FROZEN_POSTHOG_VERSION from posthog.models.async_migration import ( AsyncMigration, @@ -41,7 +49,9 @@ class Command(BaseCommand): def add_arguments(self, parser): parser.add_argument( - "--check", action="store_true", help="Exits with a non-zero status if required unapplied migrations exist." + "--check", + action="store_true", + help="Exits with a non-zero status if required unapplied migrations exist.", ) parser.add_argument( "--plan", diff --git a/posthog/management/commands/send_usage_report.py b/posthog/management/commands/send_usage_report.py index 03e4b4a102da4..cfcd7c8758516 100644 --- a/posthog/management/commands/send_usage_report.py +++ b/posthog/management/commands/send_usage_report.py @@ -9,11 +9,21 @@ class Command(BaseCommand): def add_arguments(self, parser): parser.add_argument("--dry-run", type=bool, help="Print information instead of sending it") parser.add_argument("--date", type=str, help="The date to be ran in format YYYY-MM-DD") - parser.add_argument("--event-name", type=str, help="Override the event name to be sent - for testing") parser.add_argument( - "--skip-capture-event", type=str, help="Skip the posthog capture events - for retrying to billing service" + "--event-name", + type=str, + help="Override the event name to be sent - for testing", + ) + parser.add_argument( + "--skip-capture-event", + type=str, + help="Skip the posthog capture events - for retrying to billing service", + ) + parser.add_argument( + "--organization-id", + type=str, + help="Only send the report for this organization ID", ) - parser.add_argument("--organization-id", type=str, help="Only send the report for this organization ID") parser.add_argument("--async", type=bool, help="Run the task asynchronously") def handle(self, *args, **options): @@ -26,11 +36,19 @@ def handle(self, *args, **options): if run_async: send_all_org_usage_reports.delay( - dry_run, date, event_name, skip_capture_event=skip_capture_event, only_organization_id=organization_id + dry_run, + date, + event_name, + skip_capture_event=skip_capture_event, + only_organization_id=organization_id, ) else: send_all_org_usage_reports( - dry_run, date, event_name, skip_capture_event=skip_capture_event, only_organization_id=organization_id + dry_run, + date, + event_name, + skip_capture_event=skip_capture_event, + only_organization_id=organization_id, ) if dry_run: diff --git a/posthog/management/commands/setup_dev.py b/posthog/management/commands/setup_dev.py index 09281d2b6c39f..42d6d33be512f 100644 --- a/posthog/management/commands/setup_dev.py +++ b/posthog/management/commands/setup_dev.py @@ -2,7 +2,15 @@ from django.db import transaction from posthog.demo.legacy import ORGANIZATION_NAME, TEAM_NAME, create_demo_data -from posthog.models import EventProperty, PersonalAPIKey, Plugin, PluginConfig, PluginSourceFile, Team, User +from posthog.models import ( + EventProperty, + PersonalAPIKey, + Plugin, + PluginConfig, + PluginSourceFile, + Team, + User, +) from posthog.models.event_definition import EventDefinition from posthog.models.personal_api_key import hash_key_value from posthog.models.property_definition import PropertyDefinition @@ -13,7 +21,11 @@ class Command(BaseCommand): def add_arguments(self, parser): parser.add_argument("--no-data", action="store_true", help="Create demo account without data") - parser.add_argument("--create-e2e-test-plugin", action="store_true", help="Create plugin for charts E2E test") + parser.add_argument( + "--create-e2e-test-plugin", + action="store_true", + help="Create plugin for charts E2E test", + ) def handle(self, *args, **options): print("\n⚠️ setup_dev is deprecated. Use the more robust generate_demo_data command instead.\n") # noqa T201 @@ -43,7 +55,9 @@ def handle(self, *args, **options): PropertyDefinition.objects.create(name="is_demo", type=PropertyDefinition.Type.PERSON, team=team) PersonalAPIKey.objects.create( - user=user, label="e2e_demo_api_key key", secure_value=hash_key_value("e2e_demo_api_key") + user=user, + label="e2e_demo_api_key key", + secure_value=hash_key_value("e2e_demo_api_key"), ) if not options["no_data"]: create_demo_data(team) @@ -62,7 +76,9 @@ def create_plugin(self, team): plugin_config = PluginConfig.objects.create(plugin=plugin, team=team, order=1, config={}) PluginSourceFile.objects.update_or_create( - plugin=plugin, filename="plugin.json", source='{ "name": "e2e test plugin", "config": [] }' + plugin=plugin, + filename="plugin.json", + source='{ "name": "e2e test plugin", "config": [] }', ) PluginSourceFile.objects.update_or_create( plugin=plugin, diff --git a/posthog/management/commands/split_person.py b/posthog/management/commands/split_person.py index a7b52be1bc786..f32804b14b33c 100644 --- a/posthog/management/commands/split_person.py +++ b/posthog/management/commands/split_person.py @@ -18,10 +18,18 @@ class Command(BaseCommand): def add_arguments(self, parser): parser.add_argument("--team-id", default=None, type=int, help="Specify a team to fix data for.") - parser.add_argument("--person-id", default=None, type=int, help="Specify the person ID to split.") + parser.add_argument( + "--person-id", + default=None, + type=int, + help="Specify the person ID to split.", + ) parser.add_argument("--live-run", action="store_true", help="Run changes, default is dry-run") parser.add_argument( - "--max-splits", default=None, type=int, help="Only split off a given number of distinct_ids and exit." + "--max-splits", + default=None, + type=int, + help="Only split off a given number of distinct_ids and exit.", ) def handle(self, *args, **options): diff --git a/posthog/management/commands/start_temporal_worker.py b/posthog/management/commands/start_temporal_worker.py index 0ea2feea50f85..6e10a28b31b7d 100644 --- a/posthog/management/commands/start_temporal_worker.py +++ b/posthog/management/commands/start_temporal_worker.py @@ -14,15 +14,41 @@ class Command(BaseCommand): help = "Start Temporal Python Django-aware Worker" def add_arguments(self, parser): - parser.add_argument("--temporal_host", default=settings.TEMPORAL_HOST, help="Hostname for Temporal Scheduler") - parser.add_argument("--temporal_port", default=settings.TEMPORAL_PORT, help="Port for Temporal Scheduler") - parser.add_argument("--namespace", default=settings.TEMPORAL_NAMESPACE, help="Namespace to connect to") - parser.add_argument("--task-queue", default=settings.TEMPORAL_TASK_QUEUE, help="Task queue to service") parser.add_argument( - "--server-root-ca-cert", default=settings.TEMPORAL_CLIENT_ROOT_CA, help="Optional root server CA cert" + "--temporal_host", + default=settings.TEMPORAL_HOST, + help="Hostname for Temporal Scheduler", + ) + parser.add_argument( + "--temporal_port", + default=settings.TEMPORAL_PORT, + help="Port for Temporal Scheduler", + ) + parser.add_argument( + "--namespace", + default=settings.TEMPORAL_NAMESPACE, + help="Namespace to connect to", + ) + parser.add_argument( + "--task-queue", + default=settings.TEMPORAL_TASK_QUEUE, + help="Task queue to service", + ) + parser.add_argument( + "--server-root-ca-cert", + default=settings.TEMPORAL_CLIENT_ROOT_CA, + help="Optional root server CA cert", + ) + parser.add_argument( + "--client-cert", + default=settings.TEMPORAL_CLIENT_CERT, + help="Optional client cert", + ) + parser.add_argument( + "--client-key", + default=settings.TEMPORAL_CLIENT_KEY, + help="Optional client key", ) - parser.add_argument("--client-cert", default=settings.TEMPORAL_CLIENT_CERT, help="Optional client cert") - parser.add_argument("--client-key", default=settings.TEMPORAL_CLIENT_KEY, help="Optional client key") def handle(self, *args, **options): temporal_host = options["temporal_host"] diff --git a/posthog/management/commands/sync_available_features.py b/posthog/management/commands/sync_available_features.py index 516e1eed78490..841cf210cffdf 100644 --- a/posthog/management/commands/sync_available_features.py +++ b/posthog/management/commands/sync_available_features.py @@ -3,7 +3,9 @@ import structlog from django.core.management.base import BaseCommand -from posthog.tasks.sync_all_organization_available_features import sync_all_organization_available_features +from posthog.tasks.sync_all_organization_available_features import ( + sync_all_organization_available_features, +) logger = structlog.get_logger(__name__) logger.setLevel(logging.INFO) diff --git a/posthog/management/commands/sync_feature_flags.py b/posthog/management/commands/sync_feature_flags.py index 2459d7f2c80c9..186316bb6a2df 100644 --- a/posthog/management/commands/sync_feature_flags.py +++ b/posthog/management/commands/sync_feature_flags.py @@ -56,14 +56,26 @@ def handle(self, *args, **options): "groups": [{"properties": [], "rollout_percentage": None}], "multivariate": { "variants": [ - {"key": "control", "name": "Control", "rollout_percentage": 0}, - {"key": "test", "name": "Test", "rollout_percentage": 100}, + { + "key": "control", + "name": "Control", + "rollout_percentage": 0, + }, + { + "key": "test", + "name": "Test", + "rollout_percentage": 100, + }, ] }, }, ) else: FeatureFlag.objects.create( - team=team, rollout_percentage=100, name=flag, key=flag, created_by=first_user + team=team, + rollout_percentage=100, + name=flag, + key=flag, + created_by=first_user, ) print(f"Created feature flag '{flag} for team {team.id} {' - ' + team.name if team.name else ''}") diff --git a/posthog/management/commands/sync_persons_to_clickhouse.py b/posthog/management/commands/sync_persons_to_clickhouse.py index 9e3af26deb3b5..6bf7639fcfa33 100644 --- a/posthog/management/commands/sync_persons_to_clickhouse.py +++ b/posthog/management/commands/sync_persons_to_clickhouse.py @@ -36,7 +36,9 @@ def add_arguments(self, parser): parser.add_argument("--person-override", action="store_true", help="Sync person overrides") parser.add_argument("--group", action="store_true", help="Sync groups") parser.add_argument( - "--deletes", action="store_true", help="process deletes for data in ClickHouse but not Postgres" + "--deletes", + action="store_true", + help="process deletes for data in ClickHouse but not Postgres", ) parser.add_argument("--live-run", action="store_true", help="Run changes, default is dry-run") diff --git a/posthog/management/commands/sync_replicated_schema.py b/posthog/management/commands/sync_replicated_schema.py index 35b73e2808378..40d4ab8d32ca5 100644 --- a/posthog/management/commands/sync_replicated_schema.py +++ b/posthog/management/commands/sync_replicated_schema.py @@ -24,7 +24,9 @@ class Command(BaseCommand): def add_arguments(self, parser): parser.add_argument( - "--dry-run", action="store_true", help="Exits with a non-zero status if schema changes would be required." + "--dry-run", + action="store_true", + help="Exits with a non-zero status if schema changes would be required.", ) def handle(self, *args, **options): @@ -35,7 +37,10 @@ def handle(self, *args, **options): _, create_table_queries, out_of_sync_hosts = self.analyze_cluster_tables() if len(out_of_sync_hosts) > 0: - logger.info("Schema out of sync on some clickhouse nodes!", out_of_sync_hosts=out_of_sync_hosts) + logger.info( + "Schema out of sync on some clickhouse nodes!", + out_of_sync_hosts=out_of_sync_hosts, + ) if options.get("dry_run"): exit(1) @@ -81,7 +86,9 @@ def get_out_of_sync_hosts(self, host_tables: Dict[HostName, Set[TableName]]) -> return out_of_sync def create_missing_tables( - self, out_of_sync_hosts: Dict[HostName, Set[TableName]], create_table_queries: Dict[TableName, Query] + self, + out_of_sync_hosts: Dict[HostName, Set[TableName]], + create_table_queries: Dict[TableName, Query], ): missing_tables = set(table for tables in out_of_sync_hosts.values() for table in tables) @@ -95,5 +102,5 @@ def run_on_cluster(self, create_table_query: Query) -> Query: r"^CREATE TABLE (\S+)", f"CREATE TABLE IF NOT EXISTS \\1 ON CLUSTER '{settings.CLICKHOUSE_CLUSTER}'", create_table_query, - 1, + count=1, ) diff --git a/posthog/management/commands/test/test_backfill_persons_and_groups_on_events.py b/posthog/management/commands/test/test_backfill_persons_and_groups_on_events.py index d67b74e1ab466..3f410beef2372 100644 --- a/posthog/management/commands/test/test_backfill_persons_and_groups_on_events.py +++ b/posthog/management/commands/test/test_backfill_persons_and_groups_on_events.py @@ -6,7 +6,9 @@ from posthog.client import sync_execute from posthog.conftest import create_clickhouse_tables -from posthog.management.commands.backfill_persons_and_groups_on_events import run_backfill +from posthog.management.commands.backfill_persons_and_groups_on_events import ( + run_backfill, +) from posthog.models.event.sql import EVENTS_DATA_TABLE from posthog.test.base import BaseTest, ClickhouseTestMixin @@ -73,7 +75,11 @@ def test_person_backfill(self): events_after = sync_execute("select event, person_id, person_properties from events") self.assertEqual( - events_after, [("event1", person_id, '{ "foo": "bar" }'), ("event2", person_id, '{ "foo": "bar" }')] + events_after, + [ + ("event1", person_id, '{ "foo": "bar" }'), + ("event2", person_id, '{ "foo": "bar" }'), + ], ) def test_groups_backfill(self): @@ -99,4 +105,7 @@ def test_groups_backfill(self): sleep(10) events_after = sync_execute("select event, $group_0, group0_properties from events") - self.assertEqual(events_after, [("event1", "my_group", group_props), ("event2", "my_group", group_props)]) + self.assertEqual( + events_after, + [("event1", "my_group", group_props), ("event2", "my_group", group_props)], + ) diff --git a/posthog/management/commands/test/test_create_batch_export_from_app.py b/posthog/management/commands/test/test_create_batch_export_from_app.py index fb216dc4f2bb4..aabe5ad511c99 100644 --- a/posthog/management/commands/test/test_create_batch_export_from_app.py +++ b/posthog/management/commands/test/test_create_batch_export_from_app.py @@ -92,7 +92,11 @@ def config(request): @pytest.fixture def snowflake_plugin_config(snowflake_plugin, team) -> typing.Generator[PluginConfig, None, None]: plugin_config = PluginConfig.objects.create( - plugin=snowflake_plugin, order=1, team=team, enabled=True, config=test_snowflake_config + plugin=snowflake_plugin, + order=1, + team=team, + enabled=True, + config=test_snowflake_config, ) yield plugin_config plugin_config.delete() diff --git a/posthog/management/commands/test/test_fix_person_distinct_ids_after_delete.py b/posthog/management/commands/test/test_fix_person_distinct_ids_after_delete.py index 2698af803934c..954dac77d9c06 100644 --- a/posthog/management/commands/test/test_fix_person_distinct_ids_after_delete.py +++ b/posthog/management/commands/test/test_fix_person_distinct_ids_after_delete.py @@ -24,7 +24,11 @@ class TestFixPersonDistinctIdsAfterDelete(BaseTest, ClickhouseTestMixin): def test_dry_run(self, mocked_ch_call): # clickhouse only deleted person and distinct id that should be updated ch_only_deleted_person_uuid = create_person( - uuid=str(uuid4()), team_id=self.team.pk, is_deleted=True, version=5, sync=True + uuid=str(uuid4()), + team_id=self.team.pk, + is_deleted=True, + version=5, + sync=True, ) create_person_distinct_id( team_id=self.team.pk, @@ -39,7 +43,10 @@ def test_dry_run(self, mocked_ch_call): team_id=self.team.pk, properties={"abcdefg": 11112}, version=1, uuid=uuid4() ) PersonDistinctId.objects.create( - team=self.team, person=person_linked_to_after, distinct_id="distinct_id", version=0 + team=self.team, + person=person_linked_to_after, + distinct_id="distinct_id", + version=0, ) options = {"live_run": False, "team_id": self.team.pk, "new_version": 2500} run(options, True) @@ -61,7 +68,13 @@ def test_dry_run(self, mocked_ch_call): self.assertEqual( ch_person_distinct_ids, [ - (UUID(ch_only_deleted_person_uuid), self.team.pk, "distinct_id", 7, True), + ( + UUID(ch_only_deleted_person_uuid), + self.team.pk, + "distinct_id", + 7, + True, + ), ], ) mocked_ch_call.assert_not_called() @@ -73,7 +86,11 @@ def test_dry_run(self, mocked_ch_call): def test_live_run(self, mocked_ch_call): # clickhouse only deleted person and distinct id that should be updated ch_only_deleted_person_uuid = create_person( - uuid=str(uuid4()), team_id=self.team.pk, is_deleted=True, version=5, sync=True + uuid=str(uuid4()), + team_id=self.team.pk, + is_deleted=True, + version=5, + sync=True, ) create_person_distinct_id( team_id=self.team.pk, @@ -96,10 +113,16 @@ def test_live_run(self, mocked_ch_call): team_id=self.team.pk, properties={"abcdefg": 11112}, version=1, uuid=uuid4() ) PersonDistinctId.objects.create( - team=self.team, person=person_linked_to_after, distinct_id="distinct_id", version=0 + team=self.team, + person=person_linked_to_after, + distinct_id="distinct_id", + version=0, ) PersonDistinctId.objects.create( - team=self.team, person=person_linked_to_after, distinct_id="distinct_id-2", version=0 + team=self.team, + person=person_linked_to_after, + distinct_id="distinct_id-2", + version=0, ) options = {"live_run": True, "team_id": self.team.pk, "new_version": 2500} run(options, True) @@ -110,7 +133,8 @@ def test_live_run(self, mocked_ch_call): self.assertEqual(pg_distinct_ids[0].version, 2500) self.assertEqual(pg_distinct_ids[1].version, 2500) self.assertEqual( - {pg_distinct_ids[0].distinct_id, pg_distinct_ids[1].distinct_id}, {"distinct_id", "distinct_id-2"} + {pg_distinct_ids[0].distinct_id, pg_distinct_ids[1].distinct_id}, + {"distinct_id", "distinct_id-2"}, ) self.assertEqual(pg_distinct_ids[0].person.uuid, person_linked_to_after.uuid) self.assertEqual(pg_distinct_ids[1].person.uuid, person_linked_to_after.uuid) @@ -126,7 +150,13 @@ def test_live_run(self, mocked_ch_call): ch_person_distinct_ids, [ (person_linked_to_after.uuid, self.team.pk, "distinct_id", 2500, False), - (person_linked_to_after.uuid, self.team.pk, "distinct_id-2", 2500, False), + ( + person_linked_to_after.uuid, + self.team.pk, + "distinct_id-2", + 2500, + False, + ), ], ) self.assertEqual(mocked_ch_call.call_count, 2) @@ -145,7 +175,10 @@ def test_no_op(self, mocked_ch_call): # distinct id no update PersonDistinctId.objects.create( - team=self.team, person=person_not_changed_1, distinct_id="distinct_id-1", version=0 + team=self.team, + person=person_not_changed_1, + distinct_id="distinct_id-1", + version=0, ) # deleted person not re-used @@ -153,7 +186,10 @@ def test_no_op(self, mocked_ch_call): team_id=self.team.pk, properties={"abcdef": 1111}, version=0, uuid=uuid4() ) PersonDistinctId.objects.create( - team=self.team, person=person_deleted_1, distinct_id="distinct_id-del-1", version=16 + team=self.team, + person=person_deleted_1, + distinct_id="distinct_id-del-1", + version=16, ) person_deleted_1.delete() diff --git a/posthog/management/commands/test/test_migrate_kafka_data.py b/posthog/management/commands/test/test_migrate_kafka_data.py index 0053c7201b876..05bf9f0c47c3e 100644 --- a/posthog/management/commands/test/test_migrate_kafka_data.py +++ b/posthog/management/commands/test/test_migrate_kafka_data.py @@ -34,7 +34,12 @@ def test_can_migrate_data_from_one_topic_to_another_on_a_different_cluster(): _create_topic(new_events_topic) # Put some data to the old topic - _send_message(old_events_topic, b'{ "event": "test" }', key=message_key.encode("utf-8"), headers=[("foo", b"bar")]) + _send_message( + old_events_topic, + b'{ "event": "test" }', + key=message_key.encode("utf-8"), + headers=[("foo", b"bar")], + ) migrate_kafka_data( "--from-topic", @@ -95,7 +100,12 @@ def test_we_do_not_migrate_when_dry_run_is_set(): _create_topic(new_events_topic) # Put some data to the old topic - _send_message(old_events_topic, b'{ "event": "test" }', key=message_key.encode("utf-8"), headers=[("foo", b"bar")]) + _send_message( + old_events_topic, + b'{ "event": "test" }', + key=message_key.encode("utf-8"), + headers=[("foo", b"bar")], + ) migrate_kafka_data( "--from-topic", @@ -128,7 +138,12 @@ def test_cannot_send_data_back_into_same_topic_on_same_cluster(): _commit_offsets_for_topic(topic, consumer_group_id) # Put some data to the topic - _send_message(topic, b'{ "event": "test" }', key=message_key.encode("utf-8"), headers=[("foo", b"bar")]) + _send_message( + topic, + b'{ "event": "test" }', + key=message_key.encode("utf-8"), + headers=[("foo", b"bar")], + ) try: migrate_kafka_data( @@ -161,7 +176,12 @@ def test_that_the_command_fails_if_the_specified_consumer_group_does_not_exist() _create_topic(new_topic) # Put some data to the topic - _send_message(old_topic, b'{ "event": "test" }', key=message_key.encode("utf-8"), headers=[("foo", b"bar")]) + _send_message( + old_topic, + b'{ "event": "test" }', + key=message_key.encode("utf-8"), + headers=[("foo", b"bar")], + ) try: migrate_kafka_data( @@ -195,7 +215,12 @@ def test_that_we_error_if_the_target_topic_doesnt_exist(): _commit_offsets_for_topic(old_topic, consumer_group_id) # Put some data to the topic - _send_message(old_topic, b'{ "event": "test" }', key=message_key.encode("utf-8"), headers=[("foo", b"bar")]) + _send_message( + old_topic, + b'{ "event": "test" }', + key=message_key.encode("utf-8"), + headers=[("foo", b"bar")], + ) try: migrate_kafka_data( @@ -231,7 +256,12 @@ def test_we_fail_on_send_errors_to_new_topic(): _commit_offsets_for_topic(old_topic, consumer_group_id) # Put some data to the topic - _send_message(old_topic, b'{ "event": "test" }', key=message_key.encode("utf-8"), headers=[("foo", b"bar")]) + _send_message( + old_topic, + b'{ "event": "test" }', + key=message_key.encode("utf-8"), + headers=[("foo", b"bar")], + ) with mock.patch("kafka.KafkaProducer.send") as mock_send: produce_future = FutureProduceResult(topic_partition=TopicPartition(new_topic, 1)) diff --git a/posthog/management/commands/test/test_sync_persons_to_clickhouse.py b/posthog/management/commands/test/test_sync_persons_to_clickhouse.py index 56e956d04f73b..acde0c4630f19 100644 --- a/posthog/management/commands/test/test_sync_persons_to_clickhouse.py +++ b/posthog/management/commands/test/test_sync_persons_to_clickhouse.py @@ -29,7 +29,11 @@ class TestSyncPersonsToClickHouse(BaseTest, ClickhouseTestMixin): def test_persons_sync(self): with mute_selected_signals(): # without creating/updating in clickhouse person = Person.objects.create( - team_id=self.team.pk, properties={"a": 1234}, is_identified=True, version=4, uuid=uuid4() + team_id=self.team.pk, + properties={"a": 1234}, + is_identified=True, + version=4, + uuid=uuid4(), ) run_person_sync(self.team.pk, live_run=True, deletes=False, sync=True) @@ -45,7 +49,11 @@ def test_persons_sync(self): def test_persons_sync_with_null_version(self): with mute_selected_signals(): # without creating/updating in clickhouse person = Person.objects.create( - team_id=self.team.pk, properties={"a": 1234}, is_identified=True, version=None, uuid=uuid4() + team_id=self.team.pk, + properties={"a": 1234}, + is_identified=True, + version=None, + uuid=uuid4(), ) run_person_sync(self.team.pk, live_run=True, deletes=False, sync=True) @@ -59,7 +67,13 @@ def test_persons_sync_with_null_version(self): self.assertEqual(ch_persons, [(person.uuid, self.team.pk, '{"a": 1234}', True, 0, False)]) def test_persons_deleted(self): - uuid = create_person(uuid=str(uuid4()), team_id=self.team.pk, version=5, properties={"abc": 123}, sync=True) + uuid = create_person( + uuid=str(uuid4()), + team_id=self.team.pk, + version=5, + properties={"abc": 123}, + sync=True, + ) run_person_sync(self.team.pk, live_run=True, deletes=True, sync=True) @@ -104,7 +118,12 @@ def test_distinct_ids_sync_with_null_version(self): def test_distinct_ids_deleted(self): uuid = uuid4() create_person_distinct_id( - team_id=self.team.pk, distinct_id="test-id-7", person_id=str(uuid), is_deleted=False, version=7, sync=True + team_id=self.team.pk, + distinct_id="test-id-7", + person_id=str(uuid), + is_deleted=False, + version=7, + sync=True, ) run_distinct_id_sync(self.team.pk, live_run=True, deletes=True, sync=True) @@ -114,7 +133,10 @@ def test_distinct_ids_deleted(self): """, {"team_id": self.team.pk}, ) - self.assertEqual(ch_person_distinct_ids, [(UUID(int=0), self.team.pk, "test-id-7", 107, True)]) + self.assertEqual( + ch_person_distinct_ids, + [(UUID(int=0), self.team.pk, "test-id-7", 107, True)], + ) @mock.patch( f"{posthog.management.commands.sync_persons_to_clickhouse.__name__}.raw_create_group_ch", @@ -156,7 +178,13 @@ def test_group_sync(self, mocked_ch_call): wraps=posthog.management.commands.sync_persons_to_clickhouse.raw_create_group_ch, ) def test_group_sync_updates_group(self, mocked_ch_call): - group = create_group(self.team.pk, 2, "group-key", {"a": 5}, timestamp=datetime.utcnow() - timedelta(hours=3)) + group = create_group( + self.team.pk, + 2, + "group-key", + {"a": 5}, + timestamp=datetime.utcnow() - timedelta(hours=3), + ) group.group_properties = {"a": 5, "b": 3} group.save() @@ -175,9 +203,18 @@ def test_group_sync_updates_group(self, mocked_ch_call): self.assertEqual(ch_group[0], 2) self.assertEqual(ch_group[1], "group-key") self.assertEqual(ch_group[2], '{"a": 5, "b": 3}') - self.assertEqual(ch_group[3].strftime("%Y-%m-%d %H:%M:%S"), group.created_at.strftime("%Y-%m-%d %H:%M:%S")) - self.assertGreaterEqual(ch_group[4].strftime("%Y-%m-%d %H:%M:%S"), ts_before.strftime("%Y-%m-%d %H:%M:%S")) - self.assertLessEqual(ch_group[4].strftime("%Y-%m-%d %H:%M:%S"), datetime.utcnow().strftime("%Y-%m-%d %H:%M:%S")) + self.assertEqual( + ch_group[3].strftime("%Y-%m-%d %H:%M:%S"), + group.created_at.strftime("%Y-%m-%d %H:%M:%S"), + ) + self.assertGreaterEqual( + ch_group[4].strftime("%Y-%m-%d %H:%M:%S"), + ts_before.strftime("%Y-%m-%d %H:%M:%S"), + ) + self.assertLessEqual( + ch_group[4].strftime("%Y-%m-%d %H:%M:%S"), + datetime.utcnow().strftime("%Y-%m-%d %H:%M:%S"), + ) # second time it's a no-op run_group_sync(self.team.pk, live_run=True, sync=True) @@ -256,15 +293,24 @@ def everything_test_run(self, live_run): # 2 persons who should be created with mute_selected_signals(): # without creating/updating in clickhouse person_should_be_created_1 = Person.objects.create( - team_id=self.team.pk, properties={"abcde": 12553633}, version=2, uuid=uuid4() + team_id=self.team.pk, + properties={"abcde": 12553633}, + version=2, + uuid=uuid4(), ) person_should_be_created_2 = Person.objects.create( - team_id=self.team.pk, properties={"abcdeit34": 12553633}, version=3, uuid=uuid4() + team_id=self.team.pk, + properties={"abcdeit34": 12553633}, + version=3, + uuid=uuid4(), ) # 2 persons who have updates person_should_update_1 = Person.objects.create( - team_id=self.team.pk, properties={"abcde": 12553}, version=5, uuid=uuid4() + team_id=self.team.pk, + properties={"abcde": 12553}, + version=5, + uuid=uuid4(), ) person_should_update_2 = Person.objects.create( team_id=self.team.pk, properties={"abc": 125}, version=7, uuid=uuid4() @@ -286,35 +332,61 @@ def everything_test_run(self, live_run): # 2 persons need to be deleted deleted_person_1_uuid = create_person( - uuid=str(uuid4()), team_id=self.team.pk, version=7, properties={"abcd": 123}, sync=True + uuid=str(uuid4()), + team_id=self.team.pk, + version=7, + properties={"abcd": 123}, + sync=True, ) deleted_person_2_uuid = create_person( - uuid=str(uuid4()), team_id=self.team.pk, version=8, properties={"abcef": 123}, sync=True + uuid=str(uuid4()), + team_id=self.team.pk, + version=8, + properties={"abcef": 123}, + sync=True, ) # 2 distinct id no update PersonDistinctId.objects.create( - team=self.team, person=person_not_changed_1, distinct_id="distinct_id", version=0 + team=self.team, + person=person_not_changed_1, + distinct_id="distinct_id", + version=0, ) PersonDistinctId.objects.create( - team=self.team, person=person_not_changed_1, distinct_id="distinct_id-9", version=9 + team=self.team, + person=person_not_changed_1, + distinct_id="distinct_id-9", + version=9, ) # # 2 distinct id to be created with mute_selected_signals(): # without creating/updating in clickhouse PersonDistinctId.objects.create( - team=self.team, person=person_not_changed_1, distinct_id="distinct_id-10", version=10 + team=self.team, + person=person_not_changed_1, + distinct_id="distinct_id-10", + version=10, ) PersonDistinctId.objects.create( - team=self.team, person=person_not_changed_1, distinct_id="distinct_id-11", version=11 + team=self.team, + person=person_not_changed_1, + distinct_id="distinct_id-11", + version=11, ) # 2 distinct id that need to update PersonDistinctId.objects.create( - team=self.team, person=person_not_changed_2, distinct_id="distinct_id-12", version=13 + team=self.team, + person=person_not_changed_2, + distinct_id="distinct_id-12", + version=13, ) PersonDistinctId.objects.create( - team=self.team, person=person_not_changed_2, distinct_id="distinct_id-14", version=15 + team=self.team, + person=person_not_changed_2, + distinct_id="distinct_id-14", + version=15, ) create_person_distinct_id( team_id=self.team.pk, @@ -397,23 +469,95 @@ def everything_test_run(self, live_run): self.assertEqual( ch_persons, [ - (person_not_changed_1.uuid, self.team.pk, '{"abcdef": 1111}', False, 0, False), - (person_not_changed_2.uuid, self.team.pk, '{"abcdefg": 11112}', False, 1, False), - (person_should_update_1.uuid, self.team.pk, '{"a": 13}', False, 4, False), - (person_should_update_2.uuid, self.team.pk, '{"a": 1}', False, 6, False), - (UUID(deleted_person_1_uuid), self.team.pk, '{"abcd": 123}', False, 7, False), - (UUID(deleted_person_2_uuid), self.team.pk, '{"abcef": 123}', False, 8, False), + ( + person_not_changed_1.uuid, + self.team.pk, + '{"abcdef": 1111}', + False, + 0, + False, + ), + ( + person_not_changed_2.uuid, + self.team.pk, + '{"abcdefg": 11112}', + False, + 1, + False, + ), + ( + person_should_update_1.uuid, + self.team.pk, + '{"a": 13}', + False, + 4, + False, + ), + ( + person_should_update_2.uuid, + self.team.pk, + '{"a": 1}', + False, + 6, + False, + ), + ( + UUID(deleted_person_1_uuid), + self.team.pk, + '{"abcd": 123}', + False, + 7, + False, + ), + ( + UUID(deleted_person_2_uuid), + self.team.pk, + '{"abcef": 123}', + False, + 8, + False, + ), ], ) self.assertEqual( ch_person_distinct_ids, [ (person_not_changed_1.uuid, self.team.pk, "distinct_id", 0, False), - (person_not_changed_1.uuid, self.team.pk, "distinct_id-9", 9, False), - (person_not_changed_1.uuid, self.team.pk, "distinct_id-12", 12, False), - (person_not_changed_1.uuid, self.team.pk, "distinct_id-14", 14, False), - (deleted_distinct_id_1_uuid, self.team.pk, "distinct_id-17", 17, False), - (deleted_distinct_id_2_uuid, self.team.pk, "distinct_id-18", 18, False), + ( + person_not_changed_1.uuid, + self.team.pk, + "distinct_id-9", + 9, + False, + ), + ( + person_not_changed_1.uuid, + self.team.pk, + "distinct_id-12", + 12, + False, + ), + ( + person_not_changed_1.uuid, + self.team.pk, + "distinct_id-14", + 14, + False, + ), + ( + deleted_distinct_id_1_uuid, + self.team.pk, + "distinct_id-17", + 17, + False, + ), + ( + deleted_distinct_id_2_uuid, + self.team.pk, + "distinct_id-18", + 18, + False, + ), ], ) self.assertEqual(len(ch_groups), 0) @@ -421,12 +565,54 @@ def everything_test_run(self, live_run): self.assertEqual( ch_persons, [ - (person_not_changed_1.uuid, self.team.pk, '{"abcdef": 1111}', False, 0, False), - (person_not_changed_2.uuid, self.team.pk, '{"abcdefg": 11112}', False, 1, False), - (person_should_be_created_1.uuid, self.team.pk, '{"abcde": 12553633}', False, 2, False), - (person_should_be_created_2.uuid, self.team.pk, '{"abcdeit34": 12553633}', False, 3, False), - (person_should_update_1.uuid, self.team.pk, '{"abcde": 12553}', False, 5, False), - (person_should_update_2.uuid, self.team.pk, '{"abc": 125}', False, 7, False), + ( + person_not_changed_1.uuid, + self.team.pk, + '{"abcdef": 1111}', + False, + 0, + False, + ), + ( + person_not_changed_2.uuid, + self.team.pk, + '{"abcdefg": 11112}', + False, + 1, + False, + ), + ( + person_should_be_created_1.uuid, + self.team.pk, + '{"abcde": 12553633}', + False, + 2, + False, + ), + ( + person_should_be_created_2.uuid, + self.team.pk, + '{"abcdeit34": 12553633}', + False, + 3, + False, + ), + ( + person_should_update_1.uuid, + self.team.pk, + '{"abcde": 12553}', + False, + 5, + False, + ), + ( + person_should_update_2.uuid, + self.team.pk, + '{"abc": 125}', + False, + 7, + False, + ), (UUID(deleted_person_1_uuid), self.team.pk, "{}", False, 107, True), (UUID(deleted_person_2_uuid), self.team.pk, "{}", False, 108, True), ], @@ -435,11 +621,41 @@ def everything_test_run(self, live_run): ch_person_distinct_ids, [ (person_not_changed_1.uuid, self.team.pk, "distinct_id", 0, False), - (person_not_changed_1.uuid, self.team.pk, "distinct_id-9", 9, False), - (person_not_changed_1.uuid, self.team.pk, "distinct_id-10", 10, False), - (person_not_changed_1.uuid, self.team.pk, "distinct_id-11", 11, False), - (person_not_changed_2.uuid, self.team.pk, "distinct_id-12", 13, False), - (person_not_changed_2.uuid, self.team.pk, "distinct_id-14", 15, False), + ( + person_not_changed_1.uuid, + self.team.pk, + "distinct_id-9", + 9, + False, + ), + ( + person_not_changed_1.uuid, + self.team.pk, + "distinct_id-10", + 10, + False, + ), + ( + person_not_changed_1.uuid, + self.team.pk, + "distinct_id-11", + 11, + False, + ), + ( + person_not_changed_2.uuid, + self.team.pk, + "distinct_id-12", + 13, + False, + ), + ( + person_not_changed_2.uuid, + self.team.pk, + "distinct_id-14", + 15, + False, + ), (UUID(int=0), self.team.pk, "distinct_id-17", 117, True), (UUID(int=0), self.team.pk, "distinct_id-18", 118, True), ], diff --git a/posthog/management/commands/test/test_sync_replicated_schema.py b/posthog/management/commands/test/test_sync_replicated_schema.py index 83ba19901b229..8b51b9259b5c0 100644 --- a/posthog/management/commands/test/test_sync_replicated_schema.py +++ b/posthog/management/commands/test/test_sync_replicated_schema.py @@ -21,7 +21,11 @@ def recreate_database(self, create_tables=True): def test_analyze_test_cluster(self): self.recreate_database(create_tables=True) - host_tables, create_table_queries, out_of_sync_hosts = Command().analyze_cluster_tables() + ( + host_tables, + create_table_queries, + out_of_sync_hosts, + ) = Command().analyze_cluster_tables() self.assertEqual(len(host_tables), 1) self.assertGreater(len(create_table_queries), 0) @@ -34,7 +38,11 @@ def test_analyze_test_cluster(self): def test_analyze_empty_cluster(self): self.recreate_database(create_tables=False) - host_tables, create_table_queries, out_of_sync_hosts = Command().analyze_cluster_tables() + ( + host_tables, + create_table_queries, + out_of_sync_hosts, + ) = Command().analyze_cluster_tables() self.assertEqual(host_tables, {}) self.assertEqual(create_table_queries, {}) diff --git a/posthog/middleware.py b/posthog/middleware.py index e2cdc2624d6e1..b480580afad40 100644 --- a/posthog/middleware.py +++ b/posthog/middleware.py @@ -13,7 +13,11 @@ from django.middleware.csrf import CsrfViewMiddleware from django.urls import resolve from django.utils.cache import add_never_cache_headers -from django_prometheus.middleware import Metrics, PrometheusAfterMiddleware, PrometheusBeforeMiddleware +from django_prometheus.middleware import ( + Metrics, + PrometheusAfterMiddleware, + PrometheusBeforeMiddleware, +) from rest_framework import status from statshog.defaults.django import statsd @@ -233,7 +237,10 @@ def __call__(self, request: HttpRequest): response: HttpResponse = self.get_response(request) if "api/" in request.path and "capture" not in request.path: - statsd.incr("http_api_request_response", tags={"id": route_id, "status_code": response.status_code}) + statsd.incr( + "http_api_request_response", + tags={"id": route_id, "status_code": response.status_code}, + ) return response finally: @@ -248,7 +255,13 @@ def _get_param(self, request: HttpRequest, name: str): class QueryTimeCountingMiddleware: - ALLOW_LIST_ROUTES = ["dashboard", "insight", "property_definitions", "properties", "person"] + ALLOW_LIST_ROUTES = [ + "dashboard", + "insight", + "property_definitions", + "properties", + "person", + ] def __init__(self, get_response): self.get_response = get_response @@ -291,7 +304,8 @@ class ShortCircuitMiddleware: def __init__(self, get_response): self.get_response = get_response self.decide_throttler = DecideRateThrottle( - replenish_rate=settings.DECIDE_BUCKET_REPLENISH_RATE, bucket_capacity=settings.DECIDE_BUCKET_CAPACITY + replenish_rate=settings.DECIDE_BUCKET_REPLENISH_RATE, + bucket_capacity=settings.DECIDE_BUCKET_CAPACITY, ) def __call__(self, request: HttpRequest): @@ -396,7 +410,12 @@ def __call__(self, request: HttpRequest): resolver_match = resolve(request.path) request.resolver_match = resolver_match for middleware in self.CAPTURE_MIDDLEWARE: - middleware.process_view(request, resolver_match.func, resolver_match.args, resolver_match.kwargs) + middleware.process_view( + request, + resolver_match.func, + resolver_match.args, + resolver_match.kwargs, + ) response: HttpResponse = get_event(request) diff --git a/posthog/migrations/0001_initial.py b/posthog/migrations/0001_initial.py index a196986062dd6..4a4f27e763557 100644 --- a/posthog/migrations/0001_initial.py +++ b/posthog/migrations/0001_initial.py @@ -10,7 +10,6 @@ class Migration(migrations.Migration): - initial = True dependencies = [ diff --git a/posthog/migrations/0001_initial_squashed_0284_improved_caching_state_idx.py b/posthog/migrations/0001_initial_squashed_0284_improved_caching_state_idx.py index cab1b248467f5..d862ca30ecf22 100644 --- a/posthog/migrations/0001_initial_squashed_0284_improved_caching_state_idx.py +++ b/posthog/migrations/0001_initial_squashed_0284_improved_caching_state_idx.py @@ -324,11 +324,28 @@ class Migration(migrations.Migration): migrations.CreateModel( name="User", fields=[ - ("id", models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), ("password", models.CharField(max_length=128, verbose_name="password")), - ("last_login", models.DateTimeField(blank=True, null=True, verbose_name="last login")), - ("first_name", models.CharField(blank=True, max_length=150, verbose_name="first name")), - ("last_name", models.CharField(blank=True, max_length=150, verbose_name="last name")), + ( + "last_login", + models.DateTimeField(blank=True, null=True, verbose_name="last login"), + ), + ( + "first_name", + models.CharField(blank=True, max_length=150, verbose_name="first name"), + ), + ( + "last_name", + models.CharField(blank=True, max_length=150, verbose_name="last name"), + ), ( "is_staff", models.BooleanField( @@ -345,7 +362,10 @@ class Migration(migrations.Migration): verbose_name="active", ), ), - ("date_joined", models.DateTimeField(default=django.utils.timezone.now, verbose_name="date joined")), + ( + "date_joined", + models.DateTimeField(default=django.utils.timezone.now, verbose_name="date joined"), + ), # NOTE: to achieve parity with the constraint names from the # unsquashed migration, we need to apply uniqueness separately # as Django appears to have different behaviour in these cases. @@ -362,10 +382,22 @@ class Migration(migrations.Migration): "temporary_token", models.CharField(blank=True, max_length=200, null=True), ), # NOTE: we make this unique later - ("distinct_id", models.CharField(blank=True, max_length=200)), # NOTE: we make this unique later - ("email_opt_in", models.BooleanField(blank=True, default=False, null=True)), - ("partial_notification_settings", models.JSONField(blank=True, null=True)), - ("anonymize_data", models.BooleanField(blank=True, default=False, null=True)), + ( + "distinct_id", + models.CharField(blank=True, max_length=200), + ), # NOTE: we make this unique later + ( + "email_opt_in", + models.BooleanField(blank=True, default=False, null=True), + ), + ( + "partial_notification_settings", + models.JSONField(blank=True, null=True), + ), + ( + "anonymize_data", + models.BooleanField(blank=True, default=False, null=True), + ), ( "toolbar_mode", models.CharField( @@ -376,7 +408,10 @@ class Migration(migrations.Migration): null=True, ), ), - ("events_column_config", models.JSONField(default=posthog.models.user.events_column_config_default)), + ( + "events_column_config", + models.JSONField(default=posthog.models.user.events_column_config_default), + ), ], options={ "verbose_name": "user", @@ -414,22 +449,44 @@ class Migration(migrations.Migration): migrations.CreateModel( name="Action", fields=[ - ("id", models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), ("name", models.CharField(blank=True, max_length=400, null=True)), ("description", models.TextField(blank=True, default="")), ("created_at", models.DateTimeField(auto_now_add=True)), ("deleted", models.BooleanField(default=False)), ("post_to_slack", models.BooleanField(default=False)), - ("slack_message_format", models.CharField(blank=True, default="", max_length=600)), + ( + "slack_message_format", + models.CharField(blank=True, default="", max_length=600), + ), ("is_calculating", models.BooleanField(default=False)), ("updated_at", models.DateTimeField(auto_now=True)), - ("last_calculated_at", models.DateTimeField(blank=True, default=django.utils.timezone.now)), + ( + "last_calculated_at", + models.DateTimeField(blank=True, default=django.utils.timezone.now), + ), ], ), migrations.CreateModel( name="ActionStep", fields=[ - ("id", models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), ("tag_name", models.CharField(blank=True, max_length=400, null=True)), ("text", models.CharField(blank=True, max_length=400, null=True)), ("href", models.CharField(blank=True, max_length=65535, null=True)), @@ -439,7 +496,11 @@ class Migration(migrations.Migration): "url_matching", models.CharField( blank=True, - choices=[("contains", "contains"), ("regex", "regex"), ("exact", "exact")], + choices=[ + ("contains", "contains"), + ("regex", "regex"), + ("exact", "exact"), + ], default="contains", max_length=400, null=True, @@ -456,7 +517,10 @@ class Migration(migrations.Migration): ( "id", models.UUIDField( - default=posthog.models.utils.UUIDT, editable=False, primary_key=True, serialize=False + default=posthog.models.utils.UUIDT, + editable=False, + primary_key=True, + serialize=False, ), ), ("team_id", models.PositiveIntegerField(null=True)), @@ -468,7 +532,8 @@ class Migration(migrations.Migration): ( "detail", models.JSONField( - encoder=posthog.models.activity_logging.activity_log.ActivityDetailEncoder, null=True + encoder=posthog.models.activity_logging.activity_log.ActivityDetailEncoder, + null=True, ), ), ("created_at", models.DateTimeField(default=django.utils.timezone.now)), @@ -477,9 +542,20 @@ class Migration(migrations.Migration): migrations.CreateModel( name="Annotation", fields=[ - ("id", models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), ("content", models.CharField(blank=True, max_length=400, null=True)), - ("created_at", models.DateTimeField(default=django.utils.timezone.now, null=True)), + ( + "created_at", + models.DateTimeField(default=django.utils.timezone.now, null=True), + ), ("updated_at", models.DateTimeField(auto_now=True)), ( "scope", @@ -495,7 +571,11 @@ class Migration(migrations.Migration): ), ( "creation_type", - models.CharField(choices=[("USR", "user"), ("GIT", "GitHub")], default="USR", max_length=3), + models.CharField( + choices=[("USR", "user"), ("GIT", "GitHub")], + default="USR", + max_length=3, + ), ), ("date_marker", models.DateTimeField(blank=True, null=True)), ("deleted", models.BooleanField(default=False)), @@ -523,16 +603,28 @@ class Migration(migrations.Migration): fields=[ ("id", models.BigAutoField(primary_key=True, serialize=False)), ("name", models.CharField(max_length=50)), - ("description", models.CharField(blank=True, max_length=400, null=True)), + ( + "description", + models.CharField(blank=True, max_length=400, null=True), + ), ("progress", models.PositiveSmallIntegerField(default=0)), ("status", models.PositiveSmallIntegerField(default=0)), - ("current_operation_index", models.PositiveSmallIntegerField(default=0)), + ( + "current_operation_index", + models.PositiveSmallIntegerField(default=0), + ), ("current_query_id", models.CharField(default="", max_length=100)), ("celery_task_id", models.CharField(default="", max_length=100)), ("started_at", models.DateTimeField(blank=True, null=True)), ("finished_at", models.DateTimeField(blank=True, null=True)), - ("posthog_min_version", models.CharField(blank=True, max_length=20, null=True)), - ("posthog_max_version", models.CharField(blank=True, max_length=20, null=True)), + ( + "posthog_min_version", + models.CharField(blank=True, max_length=20, null=True), + ), + ( + "posthog_max_version", + models.CharField(blank=True, max_length=20, null=True), + ), ("parameters", models.JSONField(default=dict)), ], ), @@ -555,7 +647,15 @@ class Migration(migrations.Migration): migrations.CreateModel( name="Cohort", fields=[ - ("id", models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), ("name", models.CharField(blank=True, max_length=400, null=True)), ("description", models.CharField(blank=True, max_length=1000)), ("deleted", models.BooleanField(default=False)), @@ -563,7 +663,10 @@ class Migration(migrations.Migration): ("version", models.IntegerField(blank=True, null=True)), ("pending_version", models.IntegerField(blank=True, null=True)), ("count", models.IntegerField(blank=True, null=True)), - ("created_at", models.DateTimeField(blank=True, default=django.utils.timezone.now, null=True)), + ( + "created_at", + models.DateTimeField(blank=True, default=django.utils.timezone.now, null=True), + ), ("is_calculating", models.BooleanField(default=False)), ("last_calculation", models.DateTimeField(blank=True, null=True)), ("errors_calculating", models.IntegerField(default=0)), @@ -581,7 +684,15 @@ class Migration(migrations.Migration): migrations.CreateModel( name="Dashboard", fields=[ - ("id", models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), ("name", models.CharField(blank=True, max_length=400, null=True)), ("description", models.TextField(blank=True)), ("pinned", models.BooleanField(default=False)), @@ -592,7 +703,11 @@ class Migration(migrations.Migration): ( "creation_mode", models.CharField( - choices=[("default", "Default"), ("template", "Template"), ("duplicate", "Duplicate")], + choices=[ + ("default", "Default"), + ("template", "Template"), + ("duplicate", "Duplicate"), + ], default="default", max_length=16, ), @@ -610,7 +725,11 @@ class Migration(migrations.Migration): ( "deprecated_tags", django.contrib.postgres.fields.ArrayField( - base_field=models.CharField(max_length=32), blank=True, default=list, null=True, size=None + base_field=models.CharField(max_length=32), + blank=True, + default=list, + null=True, + size=None, ), ), ( @@ -624,17 +743,31 @@ class Migration(migrations.Migration): size=None, ), ), - ("share_token", models.CharField(blank=True, max_length=400, null=True)), + ( + "share_token", + models.CharField(blank=True, max_length=400, null=True), + ), ("is_shared", models.BooleanField(default=False)), ], ), migrations.CreateModel( name="DashboardTile", fields=[ - ("id", models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), ("layouts", models.JSONField(default=dict)), ("color", models.CharField(blank=True, max_length=400, null=True)), - ("filters_hash", models.CharField(blank=True, max_length=400, null=True)), + ( + "filters_hash", + models.CharField(blank=True, max_length=400, null=True), + ), ("last_refresh", models.DateTimeField(blank=True, null=True)), ("refreshing", models.BooleanField(null=True)), ("refresh_attempt", models.IntegerField(blank=True, null=True)), @@ -644,7 +777,15 @@ class Migration(migrations.Migration): migrations.CreateModel( name="Element", fields=[ - ("id", models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), ("text", models.CharField(blank=True, max_length=10000, null=True)), ("tag_name", models.CharField(blank=True, max_length=1000, null=True)), ("href", models.CharField(blank=True, max_length=10000, null=True)), @@ -652,7 +793,10 @@ class Migration(migrations.Migration): ( "attr_class", django.contrib.postgres.fields.ArrayField( - base_field=models.CharField(blank=True, max_length=200), blank=True, null=True, size=None + base_field=models.CharField(blank=True, max_length=200), + blank=True, + null=True, + size=None, ), ), ("nth_child", models.IntegerField(blank=True, null=True)), @@ -664,20 +808,42 @@ class Migration(migrations.Migration): migrations.CreateModel( name="ElementGroup", fields=[ - ("id", models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), ("hash", models.CharField(blank=True, max_length=400, null=True)), ], ), migrations.CreateModel( name="Event", fields=[ - ("id", models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), ("created_at", models.DateTimeField(auto_now_add=True, null=True)), ("event", models.CharField(blank=True, max_length=200, null=True)), ("distinct_id", models.CharField(max_length=200)), ("properties", models.JSONField(default=dict)), - ("timestamp", models.DateTimeField(blank=True, default=django.utils.timezone.now)), - ("elements_hash", models.CharField(blank=True, max_length=200, null=True)), + ( + "timestamp", + models.DateTimeField(blank=True, default=django.utils.timezone.now), + ), + ( + "elements_hash", + models.CharField(blank=True, max_length=200, null=True), + ), ("site_url", models.CharField(blank=True, max_length=200, null=True)), ("elements", models.JSONField(blank=True, default=list, null=True)), ], @@ -685,7 +851,15 @@ class Migration(migrations.Migration): migrations.CreateModel( name="EventBuffer", fields=[ - ("id", models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), ("event", models.JSONField(blank=True, null=True)), ("process_at", models.DateTimeField()), ("locked", models.BooleanField()), @@ -697,11 +871,17 @@ class Migration(migrations.Migration): ( "id", models.UUIDField( - default=posthog.models.utils.UUIDT, editable=False, primary_key=True, serialize=False + default=posthog.models.utils.UUIDT, + editable=False, + primary_key=True, + serialize=False, ), ), ("name", models.CharField(max_length=400)), - ("created_at", models.DateTimeField(default=django.utils.timezone.now, null=True)), + ( + "created_at", + models.DateTimeField(default=django.utils.timezone.now, null=True), + ), ("last_seen_at", models.DateTimeField(default=None, null=True)), ("volume_30_day", models.IntegerField(default=None, null=True)), ("query_usage_30_day", models.IntegerField(default=None, null=True)), @@ -710,7 +890,15 @@ class Migration(migrations.Migration): migrations.CreateModel( name="EventProperty", fields=[ - ("id", models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), ("event", models.CharField(max_length=400)), ("property", models.CharField(max_length=400)), ], @@ -718,9 +906,20 @@ class Migration(migrations.Migration): migrations.CreateModel( name="Experiment", fields=[ - ("id", models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), ("name", models.CharField(max_length=400)), - ("description", models.CharField(blank=True, max_length=400, null=True)), + ( + "description", + models.CharField(blank=True, max_length=400, null=True), + ), ("filters", models.JSONField(default=dict)), ("parameters", models.JSONField(default=dict, null=True)), ("secondary_metrics", models.JSONField(default=list, null=True)), @@ -734,7 +933,15 @@ class Migration(migrations.Migration): migrations.CreateModel( name="ExportedAsset", fields=[ - ("id", models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), ( "export_format", models.CharField( @@ -749,7 +956,10 @@ class Migration(migrations.Migration): ("content", models.BinaryField(null=True)), ("created_at", models.DateTimeField(auto_now_add=True)), ("export_context", models.JSONField(blank=True, null=True)), - ("content_location", models.TextField(blank=True, max_length=1000, null=True)), + ( + "content_location", + models.TextField(blank=True, max_length=1000, null=True), + ), ( "access_token", models.CharField( @@ -764,7 +974,15 @@ class Migration(migrations.Migration): migrations.CreateModel( name="FeatureFlag", fields=[ - ("id", models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), ("key", models.CharField(max_length=400)), ("name", models.TextField(blank=True)), ("filters", models.JSONField(default=dict)), @@ -774,13 +992,24 @@ class Migration(migrations.Migration): ("active", models.BooleanField(default=True)), ("rollback_conditions", models.JSONField(blank=True, null=True)), ("performed_rollback", models.BooleanField(blank=True, null=True)), - ("ensure_experience_continuity", models.BooleanField(blank=True, default=False, null=True)), + ( + "ensure_experience_continuity", + models.BooleanField(blank=True, default=False, null=True), + ), ], ), migrations.CreateModel( name="FeatureFlagHashKeyOverride", fields=[ - ("id", models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), ("feature_flag_key", models.CharField(max_length=400)), ("hash_key", models.CharField(max_length=400)), ], @@ -788,14 +1017,30 @@ class Migration(migrations.Migration): migrations.CreateModel( name="FeatureFlagOverride", fields=[ - ("id", models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), ("override_value", models.JSONField()), ], ), migrations.CreateModel( name="Group", fields=[ - ("id", models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), ("group_key", models.CharField(max_length=400)), ("group_type_index", models.IntegerField()), ("group_properties", models.JSONField(default=dict)), @@ -808,22 +1053,53 @@ class Migration(migrations.Migration): migrations.CreateModel( name="GroupTypeMapping", fields=[ - ("id", models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), ("group_type", models.CharField(max_length=400)), ("group_type_index", models.IntegerField()), - ("name_singular", models.CharField(blank=True, max_length=400, null=True)), - ("name_plural", models.CharField(blank=True, max_length=400, null=True)), + ( + "name_singular", + models.CharField(blank=True, max_length=400, null=True), + ), + ( + "name_plural", + models.CharField(blank=True, max_length=400, null=True), + ), ], ), migrations.CreateModel( name="Insight", fields=[ - ("id", models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), ("name", models.CharField(blank=True, max_length=400, null=True)), - ("derived_name", models.CharField(blank=True, max_length=400, null=True)), - ("description", models.CharField(blank=True, max_length=400, null=True)), + ( + "derived_name", + models.CharField(blank=True, max_length=400, null=True), + ), + ( + "description", + models.CharField(blank=True, max_length=400, null=True), + ), ("filters", models.JSONField(default=dict)), - ("filters_hash", models.CharField(blank=True, max_length=400, null=True)), + ( + "filters_hash", + models.CharField(blank=True, max_length=400, null=True), + ), ("order", models.IntegerField(blank=True, null=True)), ("deleted", models.BooleanField(default=False)), ("saved", models.BooleanField(default=False)), @@ -831,10 +1107,20 @@ class Migration(migrations.Migration): ("last_refresh", models.DateTimeField(blank=True, null=True)), ("refreshing", models.BooleanField(default=False)), ("is_sample", models.BooleanField(default=False)), - ("short_id", models.CharField(blank=True, default=posthog.utils.generate_short_id, max_length=12)), + ( + "short_id", + models.CharField( + blank=True, + default=posthog.utils.generate_short_id, + max_length=12, + ), + ), ("favorited", models.BooleanField(default=False)), ("refresh_attempt", models.IntegerField(blank=True, null=True)), - ("last_modified_at", models.DateTimeField(default=django.utils.timezone.now)), + ( + "last_modified_at", + models.DateTimeField(default=django.utils.timezone.now), + ), ("layouts", models.JSONField(default=dict)), ("color", models.CharField(blank=True, max_length=400, null=True)), ("updated_at", models.DateTimeField(auto_now=True)), @@ -843,7 +1129,11 @@ class Migration(migrations.Migration): ( "deprecated_tags", django.contrib.postgres.fields.ArrayField( - base_field=models.CharField(max_length=32), blank=True, default=list, null=True, size=None + base_field=models.CharField(max_length=32), + blank=True, + default=list, + null=True, + size=None, ), ), ( @@ -868,7 +1158,10 @@ class Migration(migrations.Migration): ( "id", models.UUIDField( - default=posthog.models.utils.UUIDT, editable=False, primary_key=True, serialize=False + default=posthog.models.utils.UUIDT, + editable=False, + primary_key=True, + serialize=False, ), ), ("cache_key", models.CharField(max_length=400)), @@ -883,14 +1176,30 @@ class Migration(migrations.Migration): migrations.CreateModel( name="InsightViewed", fields=[ - ("id", models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), ("last_viewed_at", models.DateTimeField()), ], ), migrations.CreateModel( name="InstanceSetting", fields=[ - ("id", models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), ("key", models.CharField(max_length=128)), ("raw_value", models.CharField(blank=True, max_length=1024)), ], @@ -901,26 +1210,44 @@ class Migration(migrations.Migration): ( "id", models.UUIDField( - default=posthog.models.utils.UUIDT, editable=False, primary_key=True, serialize=False + default=posthog.models.utils.UUIDT, + editable=False, + primary_key=True, + serialize=False, ), ), ("name", models.CharField(max_length=64)), - ("slug", posthog.models.utils.LowercaseSlugField(max_length=48, unique=True)), + ( + "slug", + posthog.models.utils.LowercaseSlugField(max_length=48, unique=True), + ), ("created_at", models.DateTimeField(auto_now_add=True)), ("updated_at", models.DateTimeField(auto_now=True)), ( "plugins_access_level", models.PositiveSmallIntegerField( - choices=[(0, "none"), (3, "config"), (6, "install"), (9, "root")], default=3 + choices=[ + (0, "none"), + (3, "config"), + (6, "install"), + (9, "root"), + ], + default=3, ), ), ("for_internal_metrics", models.BooleanField(default=False)), ("is_member_join_email_enabled", models.BooleanField(default=True)), - ("customer_id", models.CharField(blank=True, max_length=200, null=True)), + ( + "customer_id", + models.CharField(blank=True, max_length=200, null=True), + ), ( "available_features", django.contrib.postgres.fields.ArrayField( - base_field=models.CharField(max_length=64), blank=True, default=list, size=None + base_field=models.CharField(max_length=64), + blank=True, + default=list, + size=None, ), ), ("usage", models.JSONField(blank=True, null=True)), @@ -929,7 +1256,10 @@ class Migration(migrations.Migration): ( "domain_whitelist", django.contrib.postgres.fields.ArrayField( - base_field=models.CharField(max_length=256), blank=True, default=list, size=None + base_field=models.CharField(max_length=256), + blank=True, + default=list, + size=None, ), ), ], @@ -937,18 +1267,39 @@ class Migration(migrations.Migration): migrations.CreateModel( name="Person", fields=[ - ("id", models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), ("created_at", models.DateTimeField(auto_now_add=True)), - ("properties_last_updated_at", models.JSONField(blank=True, default=dict, null=True)), + ( + "properties_last_updated_at", + models.JSONField(blank=True, default=dict, null=True), + ), ("properties_last_operation", models.JSONField(blank=True, null=True)), ("properties", models.JSONField(default=dict)), ("is_identified", models.BooleanField(default=False)), - ("uuid", models.UUIDField(db_index=True, default=posthog.models.utils.UUIDT, editable=False)), + ( + "uuid", + models.UUIDField( + db_index=True, + default=posthog.models.utils.UUIDT, + editable=False, + ), + ), ("version", models.BigIntegerField(blank=True, null=True)), ( "is_user", models.ForeignKey( - blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + to=settings.AUTH_USER_MODEL, ), ), ], @@ -956,7 +1307,15 @@ class Migration(migrations.Migration): migrations.CreateModel( name="Plugin", fields=[ - ("id", models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), ( "plugin_type", models.CharField( @@ -974,7 +1333,10 @@ class Migration(migrations.Migration): ), ("is_global", models.BooleanField(default=False)), ("is_preinstalled", models.BooleanField(default=False)), - ("is_stateless", models.BooleanField(blank=True, default=False, null=True)), + ( + "is_stateless", + models.BooleanField(blank=True, default=False, null=True), + ), ("name", models.CharField(blank=True, max_length=200, null=True)), ("description", models.TextField(blank=True, null=True)), ("url", models.CharField(blank=True, max_length=800, null=True)), @@ -1008,7 +1370,15 @@ class Migration(migrations.Migration): migrations.CreateModel( name="PluginConfig", fields=[ - ("id", models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), ("enabled", models.BooleanField(default=False)), ("order", models.IntegerField()), ("config", models.JSONField(default=dict)), @@ -1016,27 +1386,49 @@ class Migration(migrations.Migration): ("web_token", models.CharField(default=None, max_length=64, null=True)), ("created_at", models.DateTimeField(auto_now_add=True)), ("updated_at", models.DateTimeField(auto_now=True)), - ("plugin", models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="posthog.plugin")), + ( + "plugin", + models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="posthog.plugin"), + ), ], ), migrations.CreateModel( name="Prompt", fields=[ - ("id", models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), ("step", models.IntegerField()), ("type", models.CharField(max_length=200)), ("title", models.CharField(max_length=200)), ("text", models.CharField(max_length=1000)), ("placement", models.CharField(default="top", max_length=200)), ("buttons", models.JSONField()), - ("reference", models.CharField(default=None, max_length=200, null=True)), + ( + "reference", + models.CharField(default=None, max_length=200, null=True), + ), ("icon", models.CharField(max_length=200)), ], ), migrations.CreateModel( name="PromptSequence", fields=[ - ("id", models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), ("key", models.CharField(max_length=200)), ("type", models.CharField(max_length=200)), ( @@ -1050,7 +1442,10 @@ class Migration(migrations.Migration): ("status", models.CharField(max_length=200)), ("requires_opt_in", models.BooleanField(default=False)), ("autorun", models.BooleanField(default=True)), - ("must_have_completed", models.ManyToManyField(blank=True, to="posthog.PromptSequence")), + ( + "must_have_completed", + models.ManyToManyField(blank=True, to="posthog.PromptSequence"), + ), ("prompts", models.ManyToManyField(to="posthog.Prompt")), ], ), @@ -1060,7 +1455,10 @@ class Migration(migrations.Migration): ( "id", models.UUIDField( - default=posthog.models.utils.UUIDT, editable=False, primary_key=True, serialize=False + default=posthog.models.utils.UUIDT, + editable=False, + primary_key=True, + serialize=False, ), ), ("name", models.CharField(max_length=400)), @@ -1086,7 +1484,10 @@ class Migration(migrations.Migration): blank=True, choices=[ ("unix_timestamp", "Unix Timestamp in seconds"), - ("unix_timestamp_milliseconds", "Unix Timestamp in milliseconds"), + ( + "unix_timestamp_milliseconds", + "Unix Timestamp in milliseconds", + ), ("YYYY-MM-DDThh:mm:ssZ", "YYYY-MM-DDThh:mm:ssZ"), ("YYYY-MM-DD hh:mm:ss", "YYYY-MM-DD hh:mm:ss"), ("DD-MM-YYYY hh:mm:ss", "DD-MM-YYYY hh:mm:ss"), @@ -1105,21 +1506,45 @@ class Migration(migrations.Migration): migrations.CreateModel( name="SessionRecordingPlaylist", fields=[ - ("id", models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), - ("short_id", models.CharField(blank=True, default=posthog.utils.generate_short_id, max_length=12)), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ( + "short_id", + models.CharField( + blank=True, + default=posthog.utils.generate_short_id, + max_length=12, + ), + ), ("name", models.CharField(blank=True, max_length=400, null=True)), - ("derived_name", models.CharField(blank=True, max_length=400, null=True)), + ( + "derived_name", + models.CharField(blank=True, max_length=400, null=True), + ), ("description", models.TextField(blank=True)), ("pinned", models.BooleanField(default=False)), ("deleted", models.BooleanField(default=False)), ("filters", models.JSONField(default=dict)), ("created_at", models.DateTimeField(auto_now_add=True)), - ("last_modified_at", models.DateTimeField(default=django.utils.timezone.now)), + ( + "last_modified_at", + models.DateTimeField(default=django.utils.timezone.now), + ), ("is_static", models.BooleanField(default=False)), ( "created_by", models.ForeignKey( - blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + to=settings.AUTH_USER_MODEL, ), ), ( @@ -1140,7 +1565,10 @@ class Migration(migrations.Migration): ( "id", models.UUIDField( - default=posthog.models.utils.UUIDT, editable=False, primary_key=True, serialize=False + default=posthog.models.utils.UUIDT, + editable=False, + primary_key=True, + serialize=False, ), ), ("name", models.CharField(max_length=255)), @@ -1149,7 +1577,15 @@ class Migration(migrations.Migration): migrations.CreateModel( name="Team", fields=[ - ("id", models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), ( "uuid", models.UUIDField(default=posthog.models.utils.UUIDT, editable=False), @@ -1161,7 +1597,8 @@ class Migration(migrations.Migration): max_length=200, validators=[ django.core.validators.MinLengthValidator( - 10, "Project's API token must be at least 10 characters long!" + 10, + "Project's API token must be at least 10 characters long!", ) ], ), @@ -1169,7 +1606,10 @@ class Migration(migrations.Migration): ( "app_urls", django.contrib.postgres.fields.ArrayField( - base_field=models.CharField(max_length=200, null=True), blank=True, default=list, size=None + base_field=models.CharField(max_length=200, null=True), + blank=True, + default=list, + size=None, ), ), ( @@ -1180,21 +1620,36 @@ class Migration(migrations.Migration): validators=[django.core.validators.MinLengthValidator(1, "Project must have a name!")], ), ), - ("slack_incoming_webhook", models.CharField(blank=True, max_length=500, null=True)), + ( + "slack_incoming_webhook", + models.CharField(blank=True, max_length=500, null=True), + ), ("created_at", models.DateTimeField(auto_now_add=True)), ("updated_at", models.DateTimeField(auto_now=True)), ("anonymize_ips", models.BooleanField(default=False)), ("completed_snippet_onboarding", models.BooleanField(default=False)), ("ingested_event", models.BooleanField(default=False)), ("session_recording_opt_in", models.BooleanField(default=False)), - ("capture_console_log_opt_in", models.BooleanField(blank=True, null=True)), - ("signup_token", models.CharField(blank=True, max_length=200, null=True)), + ( + "capture_console_log_opt_in", + models.BooleanField(blank=True, null=True), + ), + ( + "signup_token", + models.CharField(blank=True, max_length=200, null=True), + ), ("is_demo", models.BooleanField(default=False)), ("access_control", models.BooleanField(default=False)), ("inject_web_apps", models.BooleanField(null=True)), ("test_account_filters", models.JSONField(default=list)), - ("test_account_filters_default_checked", models.BooleanField(blank=True, null=True)), - ("path_cleaning_filters", models.JSONField(blank=True, default=list, null=True)), + ( + "test_account_filters_default_checked", + models.BooleanField(blank=True, null=True), + ), + ( + "path_cleaning_filters", + models.JSONField(blank=True, default=list, null=True), + ), ( "timezone", models.CharField( @@ -1256,16 +1711,34 @@ class Migration(migrations.Migration): ("America/Anguilla", "America/Anguilla"), ("America/Antigua", "America/Antigua"), ("America/Araguaina", "America/Araguaina"), - ("America/Argentina/Buenos_Aires", "America/Argentina/Buenos_Aires"), - ("America/Argentina/Catamarca", "America/Argentina/Catamarca"), + ( + "America/Argentina/Buenos_Aires", + "America/Argentina/Buenos_Aires", + ), + ( + "America/Argentina/Catamarca", + "America/Argentina/Catamarca", + ), ("America/Argentina/Cordoba", "America/Argentina/Cordoba"), ("America/Argentina/Jujuy", "America/Argentina/Jujuy"), - ("America/Argentina/La_Rioja", "America/Argentina/La_Rioja"), + ( + "America/Argentina/La_Rioja", + "America/Argentina/La_Rioja", + ), ("America/Argentina/Mendoza", "America/Argentina/Mendoza"), - ("America/Argentina/Rio_Gallegos", "America/Argentina/Rio_Gallegos"), + ( + "America/Argentina/Rio_Gallegos", + "America/Argentina/Rio_Gallegos", + ), ("America/Argentina/Salta", "America/Argentina/Salta"), - ("America/Argentina/San_Juan", "America/Argentina/San_Juan"), - ("America/Argentina/San_Luis", "America/Argentina/San_Luis"), + ( + "America/Argentina/San_Juan", + "America/Argentina/San_Juan", + ), + ( + "America/Argentina/San_Luis", + "America/Argentina/San_Luis", + ), ("America/Argentina/Tucuman", "America/Argentina/Tucuman"), ("America/Argentina/Ushuaia", "America/Argentina/Ushuaia"), ("America/Aruba", "America/Aruba"), @@ -1314,10 +1787,16 @@ class Migration(migrations.Migration): ("America/Halifax", "America/Halifax"), ("America/Havana", "America/Havana"), ("America/Hermosillo", "America/Hermosillo"), - ("America/Indiana/Indianapolis", "America/Indiana/Indianapolis"), + ( + "America/Indiana/Indianapolis", + "America/Indiana/Indianapolis", + ), ("America/Indiana/Knox", "America/Indiana/Knox"), ("America/Indiana/Marengo", "America/Indiana/Marengo"), - ("America/Indiana/Petersburg", "America/Indiana/Petersburg"), + ( + "America/Indiana/Petersburg", + "America/Indiana/Petersburg", + ), ("America/Indiana/Tell_City", "America/Indiana/Tell_City"), ("America/Indiana/Vevay", "America/Indiana/Vevay"), ("America/Indiana/Vincennes", "America/Indiana/Vincennes"), @@ -1326,8 +1805,14 @@ class Migration(migrations.Migration): ("America/Iqaluit", "America/Iqaluit"), ("America/Jamaica", "America/Jamaica"), ("America/Juneau", "America/Juneau"), - ("America/Kentucky/Louisville", "America/Kentucky/Louisville"), - ("America/Kentucky/Monticello", "America/Kentucky/Monticello"), + ( + "America/Kentucky/Louisville", + "America/Kentucky/Louisville", + ), + ( + "America/Kentucky/Monticello", + "America/Kentucky/Monticello", + ), ("America/Kralendijk", "America/Kralendijk"), ("America/La_Paz", "America/La_Paz"), ("America/Lima", "America/Lima"), @@ -1354,9 +1839,18 @@ class Migration(migrations.Migration): ("America/Nipigon", "America/Nipigon"), ("America/Nome", "America/Nome"), ("America/Noronha", "America/Noronha"), - ("America/North_Dakota/Beulah", "America/North_Dakota/Beulah"), - ("America/North_Dakota/Center", "America/North_Dakota/Center"), - ("America/North_Dakota/New_Salem", "America/North_Dakota/New_Salem"), + ( + "America/North_Dakota/Beulah", + "America/North_Dakota/Beulah", + ), + ( + "America/North_Dakota/Center", + "America/North_Dakota/Center", + ), + ( + "America/North_Dakota/New_Salem", + "America/North_Dakota/New_Salem", + ), ("America/Nuuk", "America/Nuuk"), ("America/Ojinaga", "America/Ojinaga"), ("America/Panama", "America/Panama"), @@ -1643,11 +2137,17 @@ class Migration(migrations.Migration): max_length=240, ), ), - ("data_attributes", models.JSONField(default=posthog.models.team.team.get_default_data_attributes)), + ( + "data_attributes", + models.JSONField(default=posthog.models.team.team.get_default_data_attributes), + ), ( "person_display_name_properties", django.contrib.postgres.fields.ArrayField( - base_field=models.CharField(max_length=400), blank=True, null=True, size=None + base_field=models.CharField(max_length=400), + blank=True, + null=True, + size=None, ), ), ( @@ -1659,11 +2159,20 @@ class Migration(migrations.Migration): ( "recording_domains", django.contrib.postgres.fields.ArrayField( - base_field=models.CharField(max_length=200, null=True), blank=True, null=True, size=None + base_field=models.CharField(max_length=200, null=True), + blank=True, + null=True, + size=None, ), ), - ("correlation_config", models.JSONField(blank=True, default=dict, null=True)), - ("session_recording_retention_period_days", models.IntegerField(blank=True, default=None, null=True)), + ( + "correlation_config", + models.JSONField(blank=True, default=dict, null=True), + ), + ( + "session_recording_retention_period_days", + models.IntegerField(blank=True, default=None, null=True), + ), ("plugins_opt_in", models.BooleanField(default=False)), ("opt_out_capture", models.BooleanField(default=False)), ("event_names", models.JSONField(default=list)), @@ -1720,16 +2229,36 @@ class Migration(migrations.Migration): migrations.CreateModel( name="UserPromptState", fields=[ - ("id", models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), - ("last_updated_at", models.DateTimeField(default=django.utils.timezone.now)), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ( + "last_updated_at", + models.DateTimeField(default=django.utils.timezone.now), + ), ("step", models.IntegerField(default=None, null=True)), ("completed", models.BooleanField(default=False)), ("dismissed", models.BooleanField(default=False)), ( "sequence", - models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="posthog.promptsequence"), + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + to="posthog.promptsequence", + ), + ), + ( + "user", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + to=settings.AUTH_USER_MODEL, + ), ), - ("user", models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), ], ), migrations.CreateModel( @@ -1738,20 +2267,35 @@ class Migration(migrations.Migration): ( "id", models.UUIDField( - default=posthog.models.utils.UUIDT, editable=False, primary_key=True, serialize=False + default=posthog.models.utils.UUIDT, + editable=False, + primary_key=True, + serialize=False, ), ), ("created_at", models.DateTimeField(auto_now_add=True)), - ("media_location", models.TextField(blank=True, max_length=1000, null=True)), - ("content_type", models.TextField(blank=True, max_length=100, null=True)), + ( + "media_location", + models.TextField(blank=True, max_length=1000, null=True), + ), + ( + "content_type", + models.TextField(blank=True, max_length=100, null=True), + ), ("file_name", models.TextField(blank=True, max_length=1000, null=True)), ( "created_by", models.ForeignKey( - blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + to=settings.AUTH_USER_MODEL, ), ), - ("team", models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="posthog.team")), + ( + "team", + models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="posthog.team"), + ), ], options={ "abstract": False, @@ -1760,13 +2304,27 @@ class Migration(migrations.Migration): migrations.CreateModel( name="Text", fields=[ - ("id", models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), ("body", models.CharField(blank=True, max_length=4000, null=True)), - ("last_modified_at", models.DateTimeField(default=django.utils.timezone.now)), + ( + "last_modified_at", + models.DateTimeField(default=django.utils.timezone.now), + ), ( "created_by", models.ForeignKey( - blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + to=settings.AUTH_USER_MODEL, ), ), ( @@ -1779,7 +2337,10 @@ class Migration(migrations.Migration): to=settings.AUTH_USER_MODEL, ), ), - ("team", models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="posthog.team")), + ( + "team", + models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="posthog.team"), + ), ], ), migrations.CreateModel( @@ -1788,7 +2349,10 @@ class Migration(migrations.Migration): ( "id", models.UUIDField( - default=posthog.models.utils.UUIDT, editable=False, primary_key=True, serialize=False + default=posthog.models.utils.UUIDT, + editable=False, + primary_key=True, + serialize=False, ), ), ( @@ -1844,7 +2408,9 @@ class Migration(migrations.Migration): ( "tag", models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, related_name="tagged_items", to="posthog.tag" + on_delete=django.db.models.deletion.CASCADE, + related_name="tagged_items", + to="posthog.tag", ), ), ], @@ -1857,12 +2423,25 @@ class Migration(migrations.Migration): migrations.CreateModel( name="Subscription", fields=[ - ("id", models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), ("title", models.CharField(blank=True, max_length=100, null=True)), ( "target_type", models.CharField( - choices=[("email", "Email"), ("slack", "Slack"), ("webhook", "Webhook")], max_length=10 + choices=[ + ("email", "Email"), + ("slack", "Slack"), + ("webhook", "Webhook"), + ], + max_length=10, ), ), ("target_value", models.TextField()), @@ -1910,24 +2489,46 @@ class Migration(migrations.Migration): ( "created_by", models.ForeignKey( - blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + to=settings.AUTH_USER_MODEL, ), ), ( "dashboard", - models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to="posthog.dashboard"), + models.ForeignKey( + null=True, + on_delete=django.db.models.deletion.CASCADE, + to="posthog.dashboard", + ), ), ( "insight", - models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to="posthog.insight"), + models.ForeignKey( + null=True, + on_delete=django.db.models.deletion.CASCADE, + to="posthog.insight", + ), + ), + ( + "team", + models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="posthog.team"), ), - ("team", models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="posthog.team")), ], ), migrations.CreateModel( name="SharingConfiguration", fields=[ - ("id", models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), ("created_at", models.DateTimeField(auto_now_add=True)), ("enabled", models.BooleanField(default=False)), ( @@ -1942,29 +2543,65 @@ class Migration(migrations.Migration): ), ( "dashboard", - models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to="posthog.dashboard"), + models.ForeignKey( + null=True, + on_delete=django.db.models.deletion.CASCADE, + to="posthog.dashboard", + ), ), ( "insight", - models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to="posthog.insight"), + models.ForeignKey( + null=True, + on_delete=django.db.models.deletion.CASCADE, + to="posthog.insight", + ), + ), + ( + "team", + models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="posthog.team"), ), - ("team", models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="posthog.team")), ], ), migrations.CreateModel( name="SessionRecordingViewed", fields=[ - ("id", models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), ("created_at", models.DateTimeField(auto_now_add=True, null=True)), ("session_id", models.CharField(max_length=200)), - ("team", models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="posthog.team")), - ("user", models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), + ( + "team", + models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="posthog.team"), + ), + ( + "user", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + to=settings.AUTH_USER_MODEL, + ), + ), ], ), migrations.CreateModel( name="SessionRecordingPlaylistItem", fields=[ - ("id", models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), ("session_id", models.CharField(max_length=200)), ("created_at", models.DateTimeField(auto_now_add=True)), ("deleted", models.BooleanField(blank=True, null=True)), @@ -1986,14 +2623,28 @@ class Migration(migrations.Migration): migrations.CreateModel( name="SessionRecordingEvent", fields=[ - ("id", models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), ("created_at", models.DateTimeField(auto_now_add=True, null=True)), - ("timestamp", models.DateTimeField(blank=True, default=django.utils.timezone.now)), + ( + "timestamp", + models.DateTimeField(blank=True, default=django.utils.timezone.now), + ), ("distinct_id", models.CharField(max_length=200)), ("session_id", models.CharField(max_length=200)), ("window_id", models.CharField(blank=True, max_length=200, null=True)), ("snapshot_data", models.JSONField(default=dict)), - ("team", models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="posthog.team")), + ( + "team", + models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="posthog.team"), + ), ], ), migrations.AddField( @@ -2009,12 +2660,23 @@ class Migration(migrations.Migration): migrations.CreateModel( name="PluginStorage", fields=[ - ("id", models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), ("key", models.CharField(max_length=200)), ("value", models.TextField(blank=True, null=True)), ( "plugin_config", - models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="posthog.pluginconfig"), + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + to="posthog.pluginconfig", + ), ), ], ), @@ -2024,7 +2686,10 @@ class Migration(migrations.Migration): ( "id", models.UUIDField( - default=posthog.models.utils.UUIDT, editable=False, primary_key=True, serialize=False + default=posthog.models.utils.UUIDT, + editable=False, + primary_key=True, + serialize=False, ), ), ("filename", models.CharField(max_length=200)), @@ -2032,7 +2697,11 @@ class Migration(migrations.Migration): ( "status", models.CharField( - choices=[("LOCKED", "locked"), ("TRANSPILED", "transpiled"), ("ERROR", "error")], + choices=[ + ("LOCKED", "locked"), + ("TRANSPILED", "transpiled"), + ("ERROR", "error"), + ], max_length=20, null=True, ), @@ -2040,18 +2709,33 @@ class Migration(migrations.Migration): ("transpiled", models.TextField(blank=True, null=True)), ("error", models.TextField(blank=True, null=True)), ("updated_at", models.DateTimeField(blank=True, null=True)), - ("plugin", models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="posthog.plugin")), + ( + "plugin", + models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="posthog.plugin"), + ), ], ), migrations.AddField( model_name="pluginconfig", name="team", - field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to="posthog.team"), + field=models.ForeignKey( + null=True, + on_delete=django.db.models.deletion.CASCADE, + to="posthog.team", + ), ), migrations.CreateModel( name="PluginAttachment", fields=[ - ("id", models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), ("key", models.CharField(max_length=200)), ("content_type", models.CharField(max_length=200)), ("file_name", models.CharField(max_length=200)), @@ -2060,22 +2744,46 @@ class Migration(migrations.Migration): ( "plugin_config", models.ForeignKey( - null=True, on_delete=django.db.models.deletion.CASCADE, to="posthog.pluginconfig" + null=True, + on_delete=django.db.models.deletion.CASCADE, + to="posthog.pluginconfig", + ), + ), + ( + "team", + models.ForeignKey( + null=True, + on_delete=django.db.models.deletion.CASCADE, + to="posthog.team", ), ), - ("team", models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to="posthog.team")), ], ), migrations.CreateModel( name="PersonDistinctId", fields=[ - ("id", models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), ("distinct_id", models.CharField(max_length=400)), ("version", models.BigIntegerField(blank=True, null=True)), - ("person", models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="posthog.person")), + ( + "person", + models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="posthog.person"), + ), ( "team", - models.ForeignKey(db_index=False, on_delete=django.db.models.deletion.CASCADE, to="posthog.team"), + models.ForeignKey( + db_index=False, + on_delete=django.db.models.deletion.CASCADE, + to="posthog.team", + ), ), ], ), @@ -2092,8 +2800,20 @@ class Migration(migrations.Migration): ), ), ("label", models.CharField(max_length=40)), - ("value", models.CharField(blank=True, editable=False, max_length=50, null=True, unique=True)), - ("secure_value", models.CharField(editable=False, max_length=300, null=True, unique=True)), + ( + "value", + models.CharField( + blank=True, + editable=False, + max_length=50, + null=True, + unique=True, + ), + ), + ( + "secure_value", + models.CharField(editable=False, max_length=300, null=True, unique=True), + ), ("created_at", models.DateTimeField(default=django.utils.timezone.now)), ("last_used_at", models.DateTimeField(blank=True, null=True)), ( @@ -2127,13 +2847,17 @@ class Migration(migrations.Migration): ( "id", models.UUIDField( - default=posthog.models.utils.UUIDT, editable=False, primary_key=True, serialize=False + default=posthog.models.utils.UUIDT, + editable=False, + primary_key=True, + serialize=False, ), ), ( "level", models.PositiveSmallIntegerField( - choices=[(1, "member"), (8, "administrator"), (15, "owner")], default=1 + choices=[(1, "member"), (8, "administrator"), (15, "owner")], + default=1, ), ), ("joined_at", models.DateTimeField(auto_now_add=True)), @@ -2164,10 +2888,16 @@ class Migration(migrations.Migration): ( "id", models.UUIDField( - default=posthog.models.utils.UUIDT, editable=False, primary_key=True, serialize=False + default=posthog.models.utils.UUIDT, + editable=False, + primary_key=True, + serialize=False, ), ), - ("target_email", models.EmailField(db_index=True, max_length=254, null=True)), + ( + "target_email", + models.EmailField(db_index=True, max_length=254, null=True), + ), ("first_name", models.CharField(blank=True, default="", max_length=30)), ("emailing_attempt_made", models.BooleanField(default=False)), ("created_at", models.DateTimeField(auto_now_add=True)), @@ -2203,27 +2933,45 @@ class Migration(migrations.Migration): ( "id", models.UUIDField( - default=posthog.models.utils.UUIDT, editable=False, primary_key=True, serialize=False + default=posthog.models.utils.UUIDT, + editable=False, + primary_key=True, + serialize=False, ), ), ("domain", models.CharField(max_length=128, unique=True)), ( "verification_challenge", models.CharField( - default=posthog.models.organization_domain.generate_verification_challenge, max_length=128 + default=posthog.models.organization_domain.generate_verification_challenge, + max_length=128, ), ), - ("verified_at", models.DateTimeField(blank=True, default=None, null=True)), - ("last_verification_retry", models.DateTimeField(blank=True, default=None, null=True)), + ( + "verified_at", + models.DateTimeField(blank=True, default=None, null=True), + ), + ( + "last_verification_retry", + models.DateTimeField(blank=True, default=None, null=True), + ), ("jit_provisioning_enabled", models.BooleanField(default=False)), ("sso_enforcement", models.CharField(blank=True, max_length=28)), - ("saml_entity_id", models.CharField(blank=True, max_length=512, null=True)), - ("saml_acs_url", models.CharField(blank=True, max_length=512, null=True)), + ( + "saml_entity_id", + models.CharField(blank=True, max_length=512, null=True), + ), + ( + "saml_acs_url", + models.CharField(blank=True, max_length=512, null=True), + ), ("saml_x509_cert", models.TextField(blank=True, null=True)), ( "organization", models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, related_name="domains", to="posthog.organization" + on_delete=django.db.models.deletion.CASCADE, + related_name="domains", + to="posthog.organization", ), ), ], @@ -2247,14 +2995,19 @@ class Migration(migrations.Migration): ( "id", models.UUIDField( - default=posthog.models.utils.UUIDT, editable=False, primary_key=True, serialize=False + default=posthog.models.utils.UUIDT, + editable=False, + primary_key=True, + serialize=False, ), ), ("last_viewed_activity_date", models.DateTimeField(default=None)), ( "user", models.ForeignKey( - null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL + null=True, + on_delete=django.db.models.deletion.SET_NULL, + to=settings.AUTH_USER_MODEL, ), ), ], @@ -2265,7 +3018,10 @@ class Migration(migrations.Migration): ( "id", models.UUIDField( - default=posthog.models.utils.UUIDT, editable=False, primary_key=True, serialize=False + default=posthog.models.utils.UUIDT, + editable=False, + primary_key=True, + serialize=False, ), ), ("email_hash", models.CharField(max_length=1024)), @@ -2280,7 +3036,15 @@ class Migration(migrations.Migration): migrations.CreateModel( name="Integration", fields=[ - ("id", models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), ("kind", models.CharField(choices=[("slack", "Slack")], max_length=10)), ("config", models.JSONField(default=dict)), ("sensitive_config", models.JSONField(default=dict)), @@ -2289,10 +3053,16 @@ class Migration(migrations.Migration): ( "created_by", models.ForeignKey( - blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + to=settings.AUTH_USER_MODEL, ), ), - ("team", models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="posthog.team")), + ( + "team", + models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="posthog.team"), + ), ], ), migrations.AddConstraint( @@ -2328,7 +3098,9 @@ class Migration(migrations.Migration): model_name="insightcachingstate", name="insight", field=models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, related_name="caching_states", to="posthog.insight" + on_delete=django.db.models.deletion.CASCADE, + related_name="caching_states", + to="posthog.insight", ), ), migrations.AddField( @@ -2340,7 +3112,10 @@ class Migration(migrations.Migration): model_name="insight", name="created_by", field=models.ForeignKey( - blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + to=settings.AUTH_USER_MODEL, ), ), migrations.AddField( @@ -2358,7 +3133,10 @@ class Migration(migrations.Migration): model_name="insight", name="dive_dashboard", field=models.ForeignKey( - blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to="posthog.dashboard" + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + to="posthog.dashboard", ), ), migrations.AddField( @@ -2426,18 +3204,29 @@ class Migration(migrations.Migration): model_name="exportedasset", name="created_by", field=models.ForeignKey( - blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + to=settings.AUTH_USER_MODEL, ), ), migrations.AddField( model_name="exportedasset", name="dashboard", - field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to="posthog.dashboard"), + field=models.ForeignKey( + null=True, + on_delete=django.db.models.deletion.CASCADE, + to="posthog.dashboard", + ), ), migrations.AddField( model_name="exportedasset", name="insight", - field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to="posthog.insight"), + field=models.ForeignKey( + null=True, + on_delete=django.db.models.deletion.CASCADE, + to="posthog.insight", + ), ), migrations.AddField( model_name="exportedasset", @@ -2488,21 +3277,29 @@ class Migration(migrations.Migration): model_name="element", name="event", field=models.ForeignKey( - blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to="posthog.event" + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + to="posthog.event", ), ), migrations.AddField( model_name="element", name="group", field=models.ForeignKey( - blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to="posthog.elementgroup" + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + to="posthog.elementgroup", ), ), migrations.AddField( model_name="dashboardtile", name="dashboard", field=models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, related_name="tiles", to="posthog.dashboard" + on_delete=django.db.models.deletion.CASCADE, + related_name="tiles", + to="posthog.dashboard", ), ), migrations.AddField( @@ -2529,14 +3326,20 @@ class Migration(migrations.Migration): model_name="dashboard", name="created_by", field=models.ForeignKey( - blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + to=settings.AUTH_USER_MODEL, ), ), migrations.AddField( model_name="dashboard", name="insights", field=models.ManyToManyField( - blank=True, related_name="dashboards", through="posthog.DashboardTile", to="posthog.Insight" + blank=True, + related_name="dashboards", + through="posthog.DashboardTile", + to="posthog.Insight", ), ), migrations.AddField( @@ -2558,7 +3361,10 @@ class Migration(migrations.Migration): model_name="cohort", name="created_by", field=models.ForeignKey( - blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + to=settings.AUTH_USER_MODEL, ), ), migrations.AddField( @@ -2580,27 +3386,39 @@ class Migration(migrations.Migration): model_name="asyncdeletion", name="created_by", field=models.ForeignKey( - null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL + null=True, + on_delete=django.db.models.deletion.SET_NULL, + to=settings.AUTH_USER_MODEL, ), ), migrations.AddField( model_name="annotation", name="created_by", field=models.ForeignKey( - blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + to=settings.AUTH_USER_MODEL, ), ), migrations.AddField( model_name="annotation", name="dashboard_item", field=models.ForeignKey( - blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to="posthog.insight" + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + to="posthog.insight", ), ), migrations.AddField( model_name="annotation", name="organization", - field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to="posthog.organization"), + field=models.ForeignKey( + null=True, + on_delete=django.db.models.deletion.CASCADE, + to="posthog.organization", + ), ), migrations.AddField( model_name="annotation", @@ -2611,21 +3429,28 @@ class Migration(migrations.Migration): model_name="activitylog", name="user", field=models.ForeignKey( - null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL + null=True, + on_delete=django.db.models.deletion.SET_NULL, + to=settings.AUTH_USER_MODEL, ), ), migrations.AddField( model_name="actionstep", name="action", field=models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, related_name="steps", to="posthog.action" + on_delete=django.db.models.deletion.CASCADE, + related_name="steps", + to="posthog.action", ), ), migrations.AddField( model_name="action", name="created_by", field=models.ForeignKey( - blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + to=settings.AUTH_USER_MODEL, ), ), migrations.AddField( @@ -2772,7 +3597,16 @@ class Migration(migrations.Migration): ), migrations.AlterUniqueTogether( name="taggeditem", - unique_together={("tag", "dashboard", "insight", "event_definition", "property_definition", "action")}, + unique_together={ + ( + "tag", + "dashboard", + "insight", + "event_definition", + "property_definition", + "action", + ) + }, ), migrations.AlterUniqueTogether( name="tag", @@ -2780,7 +3614,10 @@ class Migration(migrations.Migration): ), migrations.AddIndex( model_name="sessionrecordingviewed", - index=models.Index(fields=["team_id", "user_id", "session_id"], name="posthog_ses_team_id_465af1_idx"), + index=models.Index( + fields=["team_id", "user_id", "session_id"], + name="posthog_ses_team_id_465af1_idx", + ), ), migrations.AlterUniqueTogether( name="sessionrecordingviewed", @@ -2801,14 +3638,17 @@ class Migration(migrations.Migration): migrations.AddIndex( model_name="sessionrecordingevent", index=models.Index( - fields=["team_id", "distinct_id", "timestamp", "session_id"], name="posthog_ses_team_id_46392f_idx" + fields=["team_id", "distinct_id", "timestamp", "session_id"], + name="posthog_ses_team_id_46392f_idx", ), ), TrigramExtension(), migrations.AddIndex( model_name="propertydefinition", index=django.contrib.postgres.indexes.GinIndex( - fields=["name"], name="index_property_definition_name", opclasses=["gin_trgm_ops"] + fields=["name"], + name="index_property_definition_name", + opclasses=["gin_trgm_ops"], ), ), migrations.AddConstraint( @@ -2829,7 +3669,8 @@ class Migration(migrations.Migration): migrations.AddConstraint( model_name="pluginstorage", constraint=models.UniqueConstraint( - fields=("plugin_config_id", "key"), name="posthog_unique_plugin_storage_key" + fields=("plugin_config_id", "key"), + name="posthog_unique_plugin_storage_key", ), ), migrations.AddConstraint( @@ -2851,13 +3692,16 @@ class Migration(migrations.Migration): migrations.AddConstraint( model_name="organizationmembership", constraint=models.UniqueConstraint( - fields=("organization_id", "user_id"), name="unique_organization_membership" + fields=("organization_id", "user_id"), + name="unique_organization_membership", ), ), migrations.AddConstraint( model_name="organizationmembership", constraint=models.UniqueConstraint( - condition=models.Q(("level", 15)), fields=("organization_id",), name="only_one_owner_per_organization" + condition=models.Q(("level", 15)), + fields=("organization_id",), + name="only_one_owner_per_organization", ), ), migrations.AddConstraint( @@ -2874,7 +3718,10 @@ class Migration(migrations.Migration): ), migrations.AddIndex( model_name="insightviewed", - index=models.Index(fields=["team_id", "user_id", "-last_viewed_at"], name="posthog_ins_team_id_339ee0_idx"), + index=models.Index( + fields=["team_id", "user_id", "-last_viewed_at"], + name="posthog_ins_team_id_339ee0_idx", + ), ), migrations.AddConstraint( model_name="insightviewed", @@ -2903,13 +3750,15 @@ class Migration(migrations.Migration): migrations.AddConstraint( model_name="grouptypemapping", constraint=models.UniqueConstraint( - fields=("team", "group_type_index"), name="unique event column indexes for team" + fields=("team", "group_type_index"), + name="unique event column indexes for team", ), ), migrations.AddConstraint( model_name="grouptypemapping", constraint=models.CheckConstraint( - check=models.Q(("group_type_index__lte", 5)), name="group_type_index is less than or equal 5" + check=models.Q(("group_type_index__lte", 5)), + name="group_type_index is less than or equal 5", ), ), migrations.AddConstraint( @@ -2922,13 +3771,15 @@ class Migration(migrations.Migration): migrations.AddConstraint( model_name="featureflagoverride", constraint=models.UniqueConstraint( - fields=("user", "feature_flag", "team"), name="unique feature flag for a user/team combo" + fields=("user", "feature_flag", "team"), + name="unique feature flag for a user/team combo", ), ), migrations.AddConstraint( model_name="featureflaghashkeyoverride", constraint=models.UniqueConstraint( - fields=("team", "person", "feature_flag_key"), name="Unique hash_key for a user/team/feature_flag combo" + fields=("team", "person", "feature_flag_key"), + name="Unique hash_key for a user/team/feature_flag combo", ), ), migrations.AddConstraint( @@ -2946,13 +3797,16 @@ class Migration(migrations.Migration): migrations.AddConstraint( model_name="eventproperty", constraint=models.UniqueConstraint( - fields=("team", "event", "property"), name="posthog_event_property_unique_team_event_property" + fields=("team", "event", "property"), + name="posthog_event_property_unique_team_event_property", ), ), migrations.AddIndex( model_name="eventdefinition", index=django.contrib.postgres.indexes.GinIndex( - fields=["name"], name="index_event_definition_name", opclasses=["gin_trgm_ops"] + fields=["name"], + name="index_event_definition_name", + opclasses=["gin_trgm_ops"], ), ), migrations.AlterUniqueTogether( @@ -2965,7 +3819,10 @@ class Migration(migrations.Migration): ), migrations.AddIndex( model_name="event", - index=models.Index(fields=["timestamp", "team_id", "event"], name="posthog_eve_timesta_1f6a8c_idx"), + index=models.Index( + fields=["timestamp", "team_id", "event"], + name="posthog_eve_timesta_1f6a8c_idx", + ), ), migrations.AddConstraint( model_name="elementgroup", @@ -2986,7 +3843,9 @@ class Migration(migrations.Migration): migrations.AddConstraint( model_name="dashboardtile", constraint=models.UniqueConstraint( - condition=models.Q(("text__isnull", False)), fields=("dashboard", "text"), name="unique_dashboard_text" + condition=models.Q(("text__isnull", False)), + fields=("dashboard", "text"), + name="unique_dashboard_text", ), ), migrations.AddConstraint( @@ -3019,17 +3878,25 @@ class Migration(migrations.Migration): migrations.AddConstraint( model_name="asyncdeletion", constraint=models.UniqueConstraint( - fields=("deletion_type", "key", "group_type_index"), name="unique deletion for groups" + fields=("deletion_type", "key", "group_type_index"), + name="unique deletion for groups", ), ), migrations.AddIndex( model_name="activitylog", - index=models.Index(fields=["team_id", "scope", "item_id"], name="posthog_act_team_id_13a0a8_idx"), + index=models.Index( + fields=["team_id", "scope", "item_id"], + name="posthog_act_team_id_13a0a8_idx", + ), ), migrations.AddConstraint( model_name="activitylog", constraint=models.CheckConstraint( - check=models.Q(("team_id__isnull", False), ("organization_id__isnull", False), _connector="OR"), + check=models.Q( + ("team_id__isnull", False), + ("organization_id__isnull", False), + _connector="OR", + ), name="must_have_team_or_organization_id", ), ), @@ -3060,7 +3927,9 @@ class Migration(migrations.Migration): model_name="persondistinctid", name="team", field=models.ForeignKey( - db_index=False, on_delete=django.db.models.deletion.CASCADE, to="posthog.team" + db_index=False, + on_delete=django.db.models.deletion.CASCADE, + to="posthog.team", ), ), ], diff --git a/posthog/migrations/0002_person.py b/posthog/migrations/0002_person.py index b7c46ca5c2675..00676ae9e5077 100644 --- a/posthog/migrations/0002_person.py +++ b/posthog/migrations/0002_person.py @@ -6,7 +6,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0001_initial"), ] diff --git a/posthog/migrations/0003_person_is_user.py b/posthog/migrations/0003_person_is_user.py index d894d52ddf69e..e9ebff11822ba 100644 --- a/posthog/migrations/0003_person_is_user.py +++ b/posthog/migrations/0003_person_is_user.py @@ -6,7 +6,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0002_person"), ] diff --git a/posthog/migrations/0004_auto_20200125_0415.py b/posthog/migrations/0004_auto_20200125_0415.py index 2c182399e54d7..7a504bd6a4261 100644 --- a/posthog/migrations/0004_auto_20200125_0415.py +++ b/posthog/migrations/0004_auto_20200125_0415.py @@ -5,7 +5,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0003_person_is_user"), ] diff --git a/posthog/migrations/0005_remove_person_distinct_ids.py b/posthog/migrations/0005_remove_person_distinct_ids.py index 8355585fac3e4..e1b6f7a96f75a 100644 --- a/posthog/migrations/0005_remove_person_distinct_ids.py +++ b/posthog/migrations/0005_remove_person_distinct_ids.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0004_auto_20200125_0415"), ] diff --git a/posthog/migrations/0006_person_distinct_ids.py b/posthog/migrations/0006_person_distinct_ids.py index 4c13b697fa97b..c193d33a9916e 100644 --- a/posthog/migrations/0006_person_distinct_ids.py +++ b/posthog/migrations/0006_person_distinct_ids.py @@ -5,7 +5,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0005_remove_person_distinct_ids"), ] diff --git a/posthog/migrations/0007_element.py b/posthog/migrations/0007_element.py index ca419df97b1cc..e190ac2f5bec5 100644 --- a/posthog/migrations/0007_element.py +++ b/posthog/migrations/0007_element.py @@ -6,7 +6,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0006_person_distinct_ids"), ] diff --git a/posthog/migrations/0008_action_actionstep.py b/posthog/migrations/0008_action_actionstep.py index 4720db487a565..1d17b8f064470 100644 --- a/posthog/migrations/0008_action_actionstep.py +++ b/posthog/migrations/0008_action_actionstep.py @@ -6,7 +6,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0007_element"), ] diff --git a/posthog/migrations/0009_auto_20200127_0018.py b/posthog/migrations/0009_auto_20200127_0018.py index 3319c69a0cb13..8828294ee9399 100644 --- a/posthog/migrations/0009_auto_20200127_0018.py +++ b/posthog/migrations/0009_auto_20200127_0018.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0008_action_actionstep"), ] diff --git a/posthog/migrations/0010_funnel_funnelstep.py b/posthog/migrations/0010_funnel_funnelstep.py index 2d7d45f7ed572..3bcafa4035942 100644 --- a/posthog/migrations/0010_funnel_funnelstep.py +++ b/posthog/migrations/0010_funnel_funnelstep.py @@ -6,7 +6,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0009_auto_20200127_0018"), ] diff --git a/posthog/migrations/0011_auto_20200127_2105.py b/posthog/migrations/0011_auto_20200127_2105.py index b52911c657af8..c9f83a19c57b4 100644 --- a/posthog/migrations/0011_auto_20200127_2105.py +++ b/posthog/migrations/0011_auto_20200127_2105.py @@ -5,7 +5,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0010_funnel_funnelstep"), ] diff --git a/posthog/migrations/0012_team_app_url.py b/posthog/migrations/0012_team_app_url.py index dd087ab0d35fe..c6916c0818f36 100644 --- a/posthog/migrations/0012_team_app_url.py +++ b/posthog/migrations/0012_team_app_url.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0011_auto_20200127_2105"), ] diff --git a/posthog/migrations/0013_element_attr_class.py b/posthog/migrations/0013_element_attr_class.py index 44d25b77c683b..b5ec08787553e 100644 --- a/posthog/migrations/0013_element_attr_class.py +++ b/posthog/migrations/0013_element_attr_class.py @@ -5,7 +5,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0012_team_app_url"), ] diff --git a/posthog/migrations/0014_auto_20200129_0703.py b/posthog/migrations/0014_auto_20200129_0703.py index d936899632ca3..4be8151c42872 100644 --- a/posthog/migrations/0014_auto_20200129_0703.py +++ b/posthog/migrations/0014_auto_20200129_0703.py @@ -6,7 +6,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0013_element_attr_class"), ] diff --git a/posthog/migrations/0015_actionstep_event.py b/posthog/migrations/0015_actionstep_event.py index d2eef953a2311..7b2927a2813b2 100644 --- a/posthog/migrations/0015_actionstep_event.py +++ b/posthog/migrations/0015_actionstep_event.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0014_auto_20200129_0703"), ] diff --git a/posthog/migrations/0016_user_temporary_token.py b/posthog/migrations/0016_user_temporary_token.py index 926e5aaef0bbd..d2bcda6de4e23 100644 --- a/posthog/migrations/0016_user_temporary_token.py +++ b/posthog/migrations/0016_user_temporary_token.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0015_actionstep_event"), ] diff --git a/posthog/migrations/0017_dashboarditem.py b/posthog/migrations/0017_dashboarditem.py index b6ee906d4c455..51eb088ba2840 100644 --- a/posthog/migrations/0017_dashboarditem.py +++ b/posthog/migrations/0017_dashboarditem.py @@ -6,7 +6,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0016_user_temporary_token"), ] diff --git a/posthog/migrations/0018_funnel_deleted.py b/posthog/migrations/0018_funnel_deleted.py index 6560947c7d27b..43f596fcf7376 100644 --- a/posthog/migrations/0018_funnel_deleted.py +++ b/posthog/migrations/0018_funnel_deleted.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0017_dashboarditem"), ] diff --git a/posthog/migrations/0019_team_name.py b/posthog/migrations/0019_team_name.py index b3328cc23fb81..5b73755da2f73 100644 --- a/posthog/migrations/0019_team_name.py +++ b/posthog/migrations/0019_team_name.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0018_funnel_deleted"), ] diff --git a/posthog/migrations/0020_auto_20200210_0212.py b/posthog/migrations/0020_auto_20200210_0212.py index c5737413424f1..f9278fecde9a9 100644 --- a/posthog/migrations/0020_auto_20200210_0212.py +++ b/posthog/migrations/0020_auto_20200210_0212.py @@ -5,7 +5,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0019_team_name"), ] diff --git a/posthog/migrations/0021_user_distinct_id.py b/posthog/migrations/0021_user_distinct_id.py index 062702ddbdc03..95881bcc9225d 100644 --- a/posthog/migrations/0021_user_distinct_id.py +++ b/posthog/migrations/0021_user_distinct_id.py @@ -18,7 +18,6 @@ def reverse_func(apps, schema_editor): class Migration(migrations.Migration): - dependencies = [ ("posthog", "0020_auto_20200210_0212"), ] diff --git a/posthog/migrations/0022_action_deleted.py b/posthog/migrations/0022_action_deleted.py index a9878f6b01754..d9340dc0be1ea 100644 --- a/posthog/migrations/0022_action_deleted.py +++ b/posthog/migrations/0022_action_deleted.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0021_user_distinct_id"), ] diff --git a/posthog/migrations/0023_team_opt_out_capture.py b/posthog/migrations/0023_team_opt_out_capture.py index ecd04b3b91dda..25dab1b607a4c 100644 --- a/posthog/migrations/0023_team_opt_out_capture.py +++ b/posthog/migrations/0023_team_opt_out_capture.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0022_action_deleted"), ] diff --git a/posthog/migrations/0025_cohort.py b/posthog/migrations/0025_cohort.py index 06f93085d95a9..e330d91cb45ce 100644 --- a/posthog/migrations/0025_cohort.py +++ b/posthog/migrations/0025_cohort.py @@ -6,7 +6,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0024_add_event_distinct_id_index"), ] diff --git a/posthog/migrations/0027_move_elements_to_group.py b/posthog/migrations/0027_move_elements_to_group.py index a52d14506c71a..51a65b1f5da39 100644 --- a/posthog/migrations/0027_move_elements_to_group.py +++ b/posthog/migrations/0027_move_elements_to_group.py @@ -61,5 +61,10 @@ class Migration(migrations.Migration): ] operations = [ - migrations.RunPython(forwards, reverse_code=backwards, hints={"target_db": "default"}, elidable=True), + migrations.RunPython( + forwards, + reverse_code=backwards, + hints={"target_db": "default"}, + elidable=True, + ), ] diff --git a/posthog/migrations/0028_actionstep_url_matching.py b/posthog/migrations/0028_actionstep_url_matching.py index a127710db6dbf..4100495be04e0 100644 --- a/posthog/migrations/0028_actionstep_url_matching.py +++ b/posthog/migrations/0028_actionstep_url_matching.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0027_move_elements_to_group"), ] diff --git a/posthog/migrations/0029_migrate_dashboard_actions.py b/posthog/migrations/0029_migrate_dashboard_actions.py index 89e8eea0ecbc9..7ddce5a0bce9d 100644 --- a/posthog/migrations/0029_migrate_dashboard_actions.py +++ b/posthog/migrations/0029_migrate_dashboard_actions.py @@ -18,7 +18,6 @@ def migrate_to_array(apps, schema_editor): class Migration(migrations.Migration): - dependencies = [ ("posthog", "0028_actionstep_url_matching"), ] diff --git a/posthog/migrations/0030_migrate_dashboard_days.py b/posthog/migrations/0030_migrate_dashboard_days.py index 4edf8c1a38633..a3516a251ef6e 100644 --- a/posthog/migrations/0030_migrate_dashboard_days.py +++ b/posthog/migrations/0030_migrate_dashboard_days.py @@ -18,7 +18,6 @@ def migrate_to_array(apps, schema_editor): class Migration(migrations.Migration): - dependencies = [ ("posthog", "0029_migrate_dashboard_actions"), ] diff --git a/posthog/migrations/0031_team_signup_token.py b/posthog/migrations/0031_team_signup_token.py index 63b6e208d5322..3e8a66ff19931 100644 --- a/posthog/migrations/0031_team_signup_token.py +++ b/posthog/migrations/0031_team_signup_token.py @@ -17,7 +17,6 @@ def backwards(apps, schema_editor): class Migration(migrations.Migration): - dependencies = [ ("posthog", "0030_migrate_dashboard_days"), ] diff --git a/posthog/migrations/0032_team_multiple_app_urls.py b/posthog/migrations/0032_team_multiple_app_urls.py index 7efbf6b31218c..13173c75b6376 100644 --- a/posthog/migrations/0032_team_multiple_app_urls.py +++ b/posthog/migrations/0032_team_multiple_app_urls.py @@ -5,7 +5,6 @@ def migrate_to_array(apps, schema_editor): - Team = apps.get_model("posthog", "Team") for mm in Team.objects.all(): @@ -14,7 +13,6 @@ def migrate_to_array(apps, schema_editor): def rollback_to_string(apps, schema_editor): - Team = apps.get_model("posthog", "Team") for mm in Team.objects.all(): @@ -23,7 +21,6 @@ def rollback_to_string(apps, schema_editor): class Migration(migrations.Migration): - dependencies = [ ("posthog", "0031_team_signup_token"), ] diff --git a/posthog/migrations/0033_auto_20200316_1655.py b/posthog/migrations/0033_auto_20200316_1655.py index b51694a2941b3..83fa47260ad7a 100644 --- a/posthog/migrations/0033_auto_20200316_1655.py +++ b/posthog/migrations/0033_auto_20200316_1655.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0032_team_multiple_app_urls"), ] diff --git a/posthog/migrations/0034_pg_trgm_and_btree_20200318_1447.py b/posthog/migrations/0034_pg_trgm_and_btree_20200318_1447.py index 4fa956d1b61be..a48ff23a7ffc5 100644 --- a/posthog/migrations/0034_pg_trgm_and_btree_20200318_1447.py +++ b/posthog/migrations/0034_pg_trgm_and_btree_20200318_1447.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0033_auto_20200316_1655"), ] diff --git a/posthog/migrations/0036_remove_current_url_index.py b/posthog/migrations/0036_remove_current_url_index.py index a705491e1bb18..00d8ed6871125 100644 --- a/posthog/migrations/0036_remove_current_url_index.py +++ b/posthog/migrations/0036_remove_current_url_index.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0035_current_url_index_20200318_1459"), ] diff --git a/posthog/migrations/0037_action_step_url_matching_can_be_null_20200402_1351.py b/posthog/migrations/0037_action_step_url_matching_can_be_null_20200402_1351.py index 66be9b4b9bc3a..b69d237cf84ec 100644 --- a/posthog/migrations/0037_action_step_url_matching_can_be_null_20200402_1351.py +++ b/posthog/migrations/0037_action_step_url_matching_can_be_null_20200402_1351.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0036_remove_current_url_index"), ] diff --git a/posthog/migrations/0038_migrate_actions_to_precalculate_events.py b/posthog/migrations/0038_migrate_actions_to_precalculate_events.py index 172ce9d3e81ef..3cbb4c8e06082 100644 --- a/posthog/migrations/0038_migrate_actions_to_precalculate_events.py +++ b/posthog/migrations/0038_migrate_actions_to_precalculate_events.py @@ -12,7 +12,6 @@ def rollback(apps, schema_editor): class Migration(migrations.Migration): - dependencies = [ ("posthog", "0037_action_step_url_matching_can_be_null_20200402_1351"), ] diff --git a/posthog/migrations/0039_populate_event_ip_property.py b/posthog/migrations/0039_populate_event_ip_property.py index 9fb98ba2a7f30..d1e4166a1982e 100644 --- a/posthog/migrations/0039_populate_event_ip_property.py +++ b/posthog/migrations/0039_populate_event_ip_property.py @@ -2,7 +2,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0038_migrate_actions_to_precalculate_events"), ] diff --git a/posthog/migrations/0039_user_email_opt_in.py b/posthog/migrations/0039_user_email_opt_in.py index f5132cde4b4f6..3f8a25572715b 100644 --- a/posthog/migrations/0039_user_email_opt_in.py +++ b/posthog/migrations/0039_user_email_opt_in.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0038_migrate_actions_to_precalculate_events"), ] diff --git a/posthog/migrations/0040_remove_event_ip.py b/posthog/migrations/0040_remove_event_ip.py index 741cf5232a3df..944ae3c63c847 100644 --- a/posthog/migrations/0040_remove_event_ip.py +++ b/posthog/migrations/0040_remove_event_ip.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0039_populate_event_ip_property"), ] diff --git a/posthog/migrations/0041_merge_20200407_1805.py b/posthog/migrations/0041_merge_20200407_1805.py index aa209ddaadd9a..a73e12aa07488 100644 --- a/posthog/migrations/0041_merge_20200407_1805.py +++ b/posthog/migrations/0041_merge_20200407_1805.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0040_remove_event_ip"), ("posthog", "0039_user_email_opt_in"), diff --git a/posthog/migrations/0042_add_type_dashboarditems.py b/posthog/migrations/0042_add_type_dashboarditems.py index 37728e73ebb87..33a721640d5e8 100644 --- a/posthog/migrations/0042_add_type_dashboarditems.py +++ b/posthog/migrations/0042_add_type_dashboarditems.py @@ -33,7 +33,6 @@ def reverse_filter_types(apps, schema_editor): class Migration(migrations.Migration): - dependencies = [ ("posthog", "0041_merge_20200407_1805"), ] diff --git a/posthog/migrations/0043_slack_webhooks.py b/posthog/migrations/0043_slack_webhooks.py index bc68ade92b1e5..097da3742916d 100644 --- a/posthog/migrations/0043_slack_webhooks.py +++ b/posthog/migrations/0043_slack_webhooks.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0042_add_type_dashboarditems"), ] diff --git a/posthog/migrations/0044_auto_20200413_1936.py b/posthog/migrations/0044_auto_20200413_1936.py index eda91a6b76ae0..fdda5eaf560ec 100644 --- a/posthog/migrations/0044_auto_20200413_1936.py +++ b/posthog/migrations/0044_auto_20200413_1936.py @@ -33,7 +33,6 @@ def revert_funnel_steps(apps, schema_editor): class Migration(migrations.Migration): - dependencies = [ ("posthog", "0043_slack_webhooks"), ] diff --git a/posthog/migrations/0045_add_timestamp_index.py b/posthog/migrations/0045_add_timestamp_index.py index 497a8dca04f7d..b6598fe802492 100644 --- a/posthog/migrations/0045_add_timestamp_index.py +++ b/posthog/migrations/0045_add_timestamp_index.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0044_auto_20200413_1936"), ] diff --git a/posthog/migrations/0046_event_names_properties_to_team.py b/posthog/migrations/0046_event_names_properties_to_team.py index a90b2c2e1c526..7350a5a8de701 100644 --- a/posthog/migrations/0046_event_names_properties_to_team.py +++ b/posthog/migrations/0046_event_names_properties_to_team.py @@ -30,7 +30,6 @@ def noop(apps, schema_editor): class Migration(migrations.Migration): - dependencies = [ ("posthog", "0045_add_timestamp_index"), ] diff --git a/posthog/migrations/0047_auto_20200416_1631.py b/posthog/migrations/0047_auto_20200416_1631.py index 2e2c359df1d3b..fd236cf551358 100644 --- a/posthog/migrations/0047_auto_20200416_1631.py +++ b/posthog/migrations/0047_auto_20200416_1631.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0046_event_names_properties_to_team"), ] diff --git a/posthog/migrations/0048_auto_20200420_1051.py b/posthog/migrations/0048_auto_20200420_1051.py index e29ed78cc695f..29248b69fb693 100644 --- a/posthog/migrations/0048_auto_20200420_1051.py +++ b/posthog/migrations/0048_auto_20200420_1051.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0047_auto_20200416_1631"), ] diff --git a/posthog/migrations/0049_delete_funnelstep.py b/posthog/migrations/0049_delete_funnelstep.py index a29722f0e313a..e66988922c931 100644 --- a/posthog/migrations/0049_delete_funnelstep.py +++ b/posthog/migrations/0049_delete_funnelstep.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0048_auto_20200420_1051"), ] diff --git a/posthog/migrations/0050_dashboards.py b/posthog/migrations/0050_dashboards.py index 8d74bcf7394e7..70d1559591be7 100644 --- a/posthog/migrations/0050_dashboards.py +++ b/posthog/migrations/0050_dashboards.py @@ -26,7 +26,6 @@ def backwards(apps, schema_editor): class Migration(migrations.Migration): - dependencies = [ ("posthog", "0049_delete_funnelstep"), ] @@ -73,7 +72,12 @@ class Migration(migrations.Migration): to="posthog.Dashboard", ), ), - migrations.RunPython(forwards, reverse_code=backwards, hints={"target_db": "default"}, elidable=True), + migrations.RunPython( + forwards, + reverse_code=backwards, + hints={"target_db": "default"}, + elidable=True, + ), migrations.AlterField( model_name="dashboarditem", name="dashboard", diff --git a/posthog/migrations/0051_precalculate_cohorts.py b/posthog/migrations/0051_precalculate_cohorts.py index 4e4f2224c6927..0d2e2f83981b1 100644 --- a/posthog/migrations/0051_precalculate_cohorts.py +++ b/posthog/migrations/0051_precalculate_cohorts.py @@ -7,7 +7,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0050_dashboards"), ] diff --git a/posthog/migrations/0052_data_precalculate_cohorts.py b/posthog/migrations/0052_data_precalculate_cohorts.py index b6e01cd1e2a42..d2c7990399a2b 100644 --- a/posthog/migrations/0052_data_precalculate_cohorts.py +++ b/posthog/migrations/0052_data_precalculate_cohorts.py @@ -15,7 +15,6 @@ def backwards(apps, schema_editor): class Migration(migrations.Migration): - dependencies = [ ("posthog", "0051_precalculate_cohorts"), ] diff --git a/posthog/migrations/0053_dashboard_item_layouts.py b/posthog/migrations/0053_dashboard_item_layouts.py index 77fcfa4df7275..f514a48fc5352 100644 --- a/posthog/migrations/0053_dashboard_item_layouts.py +++ b/posthog/migrations/0053_dashboard_item_layouts.py @@ -5,7 +5,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0052_data_precalculate_cohorts"), ] diff --git a/posthog/migrations/0054_dashboard_item_color.py b/posthog/migrations/0054_dashboard_item_color.py index 052811a71b0c0..1ba803e0baa84 100644 --- a/posthog/migrations/0054_dashboard_item_color.py +++ b/posthog/migrations/0054_dashboard_item_color.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0053_dashboard_item_layouts"), ] diff --git a/posthog/migrations/0055_user_anonymize_data.py b/posthog/migrations/0055_user_anonymize_data.py index cea3694da7149..412e2f08666b9 100644 --- a/posthog/migrations/0055_user_anonymize_data.py +++ b/posthog/migrations/0055_user_anonymize_data.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0054_dashboard_item_color"), ] diff --git a/posthog/migrations/0056_auto_20200522_1024.py b/posthog/migrations/0056_auto_20200522_1024.py index 861d269961096..ae09c0519a391 100644 --- a/posthog/migrations/0056_auto_20200522_1024.py +++ b/posthog/migrations/0056_auto_20200522_1024.py @@ -5,7 +5,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0055_user_anonymize_data"), ] diff --git a/posthog/migrations/0057_action_updated_at.py b/posthog/migrations/0057_action_updated_at.py index 2cdf65ea2b683..1acfa631c6425 100644 --- a/posthog/migrations/0057_action_updated_at.py +++ b/posthog/migrations/0057_action_updated_at.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0056_auto_20200522_1024"), ] diff --git a/posthog/migrations/0058_dashboarditem_last_refresh.py b/posthog/migrations/0058_dashboarditem_last_refresh.py index ad71e982e45ca..428995375c6e4 100644 --- a/posthog/migrations/0058_dashboarditem_last_refresh.py +++ b/posthog/migrations/0058_dashboarditem_last_refresh.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0057_action_updated_at"), ] diff --git a/posthog/migrations/0059_dashboarditem_refreshing.py b/posthog/migrations/0059_dashboarditem_refreshing.py index f5e82621b32a0..1a873e17817b2 100644 --- a/posthog/migrations/0059_dashboarditem_refreshing.py +++ b/posthog/migrations/0059_dashboarditem_refreshing.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0058_dashboarditem_last_refresh"), ] diff --git a/posthog/migrations/0060_auto_20200616_0746.py b/posthog/migrations/0060_auto_20200616_0746.py index 3c6acbdc31a2a..cfea859ea3f47 100644 --- a/posthog/migrations/0060_auto_20200616_0746.py +++ b/posthog/migrations/0060_auto_20200616_0746.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0059_dashboarditem_refreshing"), ] diff --git a/posthog/migrations/0061_featureflag.py b/posthog/migrations/0061_featureflag.py index ee2456e8c172c..d7a05ea799558 100644 --- a/posthog/migrations/0061_featureflag.py +++ b/posthog/migrations/0061_featureflag.py @@ -8,7 +8,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0060_auto_20200616_0746"), ] diff --git a/posthog/migrations/0062_team_anonymize_ips.py b/posthog/migrations/0062_team_anonymize_ips.py index cdd7fd305169f..d5234b8b47310 100644 --- a/posthog/migrations/0062_team_anonymize_ips.py +++ b/posthog/migrations/0062_team_anonymize_ips.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0061_featureflag"), ] diff --git a/posthog/migrations/0063_team_completed_snippet_onboarding.py b/posthog/migrations/0063_team_completed_snippet_onboarding.py index d9341aead8321..1a3819af10dae 100644 --- a/posthog/migrations/0063_team_completed_snippet_onboarding.py +++ b/posthog/migrations/0063_team_completed_snippet_onboarding.py @@ -17,7 +17,6 @@ def backwards(apps, schema_editor): class Migration(migrations.Migration): - dependencies = [ ("posthog", "0062_team_anonymize_ips"), ] diff --git a/posthog/migrations/0064_toolbar_mode.py b/posthog/migrations/0064_toolbar_mode.py index e8031d315fc79..566ad520e284e 100644 --- a/posthog/migrations/0064_toolbar_mode.py +++ b/posthog/migrations/0064_toolbar_mode.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0063_team_completed_snippet_onboarding"), ] diff --git a/posthog/migrations/0065_auto_20200624_1842.py b/posthog/migrations/0065_auto_20200624_1842.py index c44d120ca2517..6941eb7672045 100644 --- a/posthog/migrations/0065_auto_20200624_1842.py +++ b/posthog/migrations/0065_auto_20200624_1842.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0064_toolbar_mode"), ] diff --git a/posthog/migrations/0066_team_created_at.py b/posthog/migrations/0066_team_created_at.py index e2b76d8be195c..0e9b0f2f0c4bd 100644 --- a/posthog/migrations/0066_team_created_at.py +++ b/posthog/migrations/0066_team_created_at.py @@ -5,7 +5,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0065_auto_20200624_1842"), ] diff --git a/posthog/migrations/0067_team_updated_at.py b/posthog/migrations/0067_team_updated_at.py index 31dfbb25225ed..5545097a96e05 100644 --- a/posthog/migrations/0067_team_updated_at.py +++ b/posthog/migrations/0067_team_updated_at.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0066_team_created_at"), ] diff --git a/posthog/migrations/0068_auto_20200629_1322.py b/posthog/migrations/0068_auto_20200629_1322.py index 216a5c3f1c499..fc6c23eb79aa5 100644 --- a/posthog/migrations/0068_auto_20200629_1322.py +++ b/posthog/migrations/0068_auto_20200629_1322.py @@ -6,7 +6,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0067_team_updated_at"), ] diff --git a/posthog/migrations/0069_auto_20200714_1642.py b/posthog/migrations/0069_auto_20200714_1642.py index ff7cb3d92860a..a9a8091b0d32e 100644 --- a/posthog/migrations/0069_auto_20200714_1642.py +++ b/posthog/migrations/0069_auto_20200714_1642.py @@ -5,7 +5,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0068_auto_20200629_1322"), ] diff --git a/posthog/migrations/0070_team_event_properties_numerical.py b/posthog/migrations/0070_team_event_properties_numerical.py index 3b0d300c5785a..032e9a336179f 100644 --- a/posthog/migrations/0070_team_event_properties_numerical.py +++ b/posthog/migrations/0070_team_event_properties_numerical.py @@ -5,7 +5,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0069_auto_20200714_1642"), ] diff --git a/posthog/migrations/0071_cache_dashboard_items.py b/posthog/migrations/0071_cache_dashboard_items.py index 909daf452e801..9b9d1b2b72a78 100644 --- a/posthog/migrations/0071_cache_dashboard_items.py +++ b/posthog/migrations/0071_cache_dashboard_items.py @@ -30,7 +30,6 @@ def reverse_func(apps, schema_editor): class Migration(migrations.Migration): - dependencies = [ ("posthog", "0070_team_event_properties_numerical"), ] diff --git a/posthog/migrations/0072_action_step_url_matching_regex.py b/posthog/migrations/0072_action_step_url_matching_regex.py index e7a624c3e06fb..2afb583ce5097 100644 --- a/posthog/migrations/0072_action_step_url_matching_regex.py +++ b/posthog/migrations/0072_action_step_url_matching_regex.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0071_cache_dashboard_items"), ] diff --git a/posthog/migrations/0073_update_dashboard_item_filters.py b/posthog/migrations/0073_update_dashboard_item_filters.py index 3f204ce499a30..d4310df88ef1c 100644 --- a/posthog/migrations/0073_update_dashboard_item_filters.py +++ b/posthog/migrations/0073_update_dashboard_item_filters.py @@ -20,7 +20,6 @@ def reverse_func(apps, schema_editor): class Migration(migrations.Migration): - dependencies = [ ("posthog", "0072_action_step_url_matching_regex"), ] diff --git a/posthog/migrations/0074_toolbar_default_on.py b/posthog/migrations/0074_toolbar_default_on.py index 2804bc5edb060..9fcc672bb598f 100644 --- a/posthog/migrations/0074_toolbar_default_on.py +++ b/posthog/migrations/0074_toolbar_default_on.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0073_update_dashboard_item_filters"), ] diff --git a/posthog/migrations/0075_action_slack_message_format.py b/posthog/migrations/0075_action_slack_message_format.py index 7404c7965efd9..9eb7d8c7cda26 100644 --- a/posthog/migrations/0075_action_slack_message_format.py +++ b/posthog/migrations/0075_action_slack_message_format.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0074_toolbar_default_on"), ] diff --git a/posthog/migrations/0076_auto_20200819_1214.py b/posthog/migrations/0076_auto_20200819_1214.py index d450022fc29bc..a02021d092451 100644 --- a/posthog/migrations/0076_auto_20200819_1214.py +++ b/posthog/migrations/0076_auto_20200819_1214.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0075_action_slack_message_format"), ] diff --git a/posthog/migrations/0077_cohortpeople_id_to_bigautofield.py b/posthog/migrations/0077_cohortpeople_id_to_bigautofield.py index 4c80a3f2f2469..ae77683b0ce12 100644 --- a/posthog/migrations/0077_cohortpeople_id_to_bigautofield.py +++ b/posthog/migrations/0077_cohortpeople_id_to_bigautofield.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0076_auto_20200819_1214"), ] diff --git a/posthog/migrations/0078_auto_20200731_1323.py b/posthog/migrations/0078_auto_20200731_1323.py index 0d171ef26858e..0a67bdd4874ad 100644 --- a/posthog/migrations/0078_auto_20200731_1323.py +++ b/posthog/migrations/0078_auto_20200731_1323.py @@ -6,7 +6,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0077_cohortpeople_id_to_bigautofield"), ] diff --git a/posthog/migrations/0079_move_funnels_to_insights.py b/posthog/migrations/0079_move_funnels_to_insights.py index 9a381f2af3b26..d4466b0cccb5f 100644 --- a/posthog/migrations/0079_move_funnels_to_insights.py +++ b/posthog/migrations/0079_move_funnels_to_insights.py @@ -39,7 +39,6 @@ def reverse(apps, schema_editor): class Migration(migrations.Migration): - dependencies = [ ("posthog", "0078_auto_20200731_1323"), ] diff --git a/posthog/migrations/0080_update_dashboard_funnel_filters.py b/posthog/migrations/0080_update_dashboard_funnel_filters.py index db3f6771e8ff6..09bdafafbb262 100644 --- a/posthog/migrations/0080_update_dashboard_funnel_filters.py +++ b/posthog/migrations/0080_update_dashboard_funnel_filters.py @@ -37,7 +37,6 @@ def reverse(apps, schema_editor): class Migration(migrations.Migration): - dependencies = [ ("posthog", "0079_move_funnels_to_insights"), ] diff --git a/posthog/migrations/0081_person_is_identified.py b/posthog/migrations/0081_person_is_identified.py index d5b37b3255d6c..40443fd8b91ff 100644 --- a/posthog/migrations/0081_person_is_identified.py +++ b/posthog/migrations/0081_person_is_identified.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0080_update_dashboard_funnel_filters"), ] diff --git a/posthog/migrations/0082_personalapikey.py b/posthog/migrations/0082_personalapikey.py index ce4ad061c3928..95520b06dd452 100644 --- a/posthog/migrations/0082_personalapikey.py +++ b/posthog/migrations/0082_personalapikey.py @@ -9,7 +9,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0081_person_is_identified"), ] diff --git a/posthog/migrations/0083_auto_20200826_1504.py b/posthog/migrations/0083_auto_20200826_1504.py index aa0ba2b90251e..07ccc49fc93a9 100644 --- a/posthog/migrations/0083_auto_20200826_1504.py +++ b/posthog/migrations/0083_auto_20200826_1504.py @@ -15,7 +15,6 @@ def create_uuid(apps, schema_editor): class Migration(migrations.Migration): - dependencies = [ ("posthog", "0082_personalapikey"), ] diff --git a/posthog/migrations/0084_person_uuid.py b/posthog/migrations/0084_person_uuid.py index f32f3e14ae3a9..f6bd7480de94e 100644 --- a/posthog/migrations/0084_person_uuid.py +++ b/posthog/migrations/0084_person_uuid.py @@ -6,7 +6,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0083_auto_20200826_1504"), ] diff --git a/posthog/migrations/0085_org_models.py b/posthog/migrations/0085_org_models.py index 25e8b90aefd2c..7483d43a62394 100644 --- a/posthog/migrations/0085_org_models.py +++ b/posthog/migrations/0085_org_models.py @@ -51,7 +51,6 @@ def reverse_func(apps, schema_editor): class Migration(migrations.Migration): - dependencies = [ ("posthog", "0084_person_uuid"), ] diff --git a/posthog/migrations/0086_team_session_recording_opt_in.py b/posthog/migrations/0086_team_session_recording_opt_in.py index f26a94a383e7b..4fcd8c23c6d47 100644 --- a/posthog/migrations/0086_team_session_recording_opt_in.py +++ b/posthog/migrations/0086_team_session_recording_opt_in.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0085_org_models"), ] diff --git a/posthog/migrations/0087_fix_annotation_created_at.py b/posthog/migrations/0087_fix_annotation_created_at.py index 0c4483174d1c4..3b77ccea233ae 100644 --- a/posthog/migrations/0087_fix_annotation_created_at.py +++ b/posthog/migrations/0087_fix_annotation_created_at.py @@ -5,7 +5,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0086_team_session_recording_opt_in"), ] diff --git a/posthog/migrations/0088_toolbar_disabled.py b/posthog/migrations/0088_toolbar_disabled.py index 071ba75c8dcfd..64a2f05a274b5 100644 --- a/posthog/migrations/0088_toolbar_disabled.py +++ b/posthog/migrations/0088_toolbar_disabled.py @@ -15,7 +15,6 @@ def reverse(apps, schema_editor): class Migration(migrations.Migration): - dependencies = [ ("posthog", "0087_fix_annotation_created_at"), ] diff --git a/posthog/migrations/0089_auto_20201015_1031.py b/posthog/migrations/0089_auto_20201015_1031.py index 72b6195c5d0d7..f19ad04b047d2 100644 --- a/posthog/migrations/0089_auto_20201015_1031.py +++ b/posthog/migrations/0089_auto_20201015_1031.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0088_toolbar_disabled"), ] diff --git a/posthog/migrations/0090_org_live.py b/posthog/migrations/0090_org_live.py index 79dd818bd2d86..d63d3f545de00 100644 --- a/posthog/migrations/0090_org_live.py +++ b/posthog/migrations/0090_org_live.py @@ -8,7 +8,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0089_auto_20201015_1031"), ] @@ -29,14 +28,19 @@ class Migration(migrations.Migration): model_name="team", name="api_token", field=models.CharField( - default=posthog.models.utils.generate_random_token, max_length=200, null=True, unique=True + default=posthog.models.utils.generate_random_token, + max_length=200, + null=True, + unique=True, ), ), migrations.AlterField( model_name="team", name="users", field=models.ManyToManyField( - blank=True, related_name="teams_deprecated_relationship", to=settings.AUTH_USER_MODEL + blank=True, + related_name="teams_deprecated_relationship", + to=settings.AUTH_USER_MODEL, ), ), migrations.AlterField( diff --git a/posthog/migrations/0091_messagingrecord.py b/posthog/migrations/0091_messagingrecord.py index f00d2ee1da4b5..669c582ed6893 100644 --- a/posthog/migrations/0091_messagingrecord.py +++ b/posthog/migrations/0091_messagingrecord.py @@ -6,7 +6,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0090_org_live"), ] @@ -18,7 +17,10 @@ class Migration(migrations.Migration): ( "id", models.UUIDField( - default=posthog.models.utils.UUIDT, editable=False, primary_key=True, serialize=False + default=posthog.models.utils.UUIDT, + editable=False, + primary_key=True, + serialize=False, ), ), ("email_hash", models.CharField(max_length=1024)), diff --git a/posthog/migrations/0093_remove_user_is_superuser.py b/posthog/migrations/0093_remove_user_is_superuser.py index 4b797ea341ab8..c56685c477ea8 100644 --- a/posthog/migrations/0093_remove_user_is_superuser.py +++ b/posthog/migrations/0093_remove_user_is_superuser.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0092_rename_projects_to_default"), ] diff --git a/posthog/migrations/0094_description_on_dashboard_items.py b/posthog/migrations/0094_description_on_dashboard_items.py index 612b57160c044..24dde3b3926f4 100644 --- a/posthog/migrations/0094_description_on_dashboard_items.py +++ b/posthog/migrations/0094_description_on_dashboard_items.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0093_remove_user_is_superuser"), ] diff --git a/posthog/migrations/0095_session_recording_event_table.py b/posthog/migrations/0095_session_recording_event_table.py index a972e792e3041..94b9d9848dc23 100644 --- a/posthog/migrations/0095_session_recording_event_table.py +++ b/posthog/migrations/0095_session_recording_event_table.py @@ -7,7 +7,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0094_description_on_dashboard_items"), ] @@ -16,13 +15,30 @@ class Migration(migrations.Migration): migrations.CreateModel( name="SessionRecordingEvent", fields=[ - ("id", models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), ("created_at", models.DateTimeField(auto_now_add=True, null=True)), - ("timestamp", models.DateTimeField(blank=True, default=django.utils.timezone.now)), + ( + "timestamp", + models.DateTimeField(blank=True, default=django.utils.timezone.now), + ), ("session_id", models.CharField(max_length=200)), ("distinct_id", models.CharField(max_length=200)), - ("snapshot_data", django.contrib.postgres.fields.jsonb.JSONField(default=dict)), - ("team", models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="posthog.Team")), + ( + "snapshot_data", + django.contrib.postgres.fields.jsonb.JSONField(default=dict), + ), + ( + "team", + models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="posthog.Team"), + ), ], ), migrations.AddIndex( @@ -32,7 +48,8 @@ class Migration(migrations.Migration): migrations.AddIndex( model_name="sessionrecordingevent", index=models.Index( - fields=["team_id", "distinct_id", "timestamp", "session_id"], name="posthog_ses_team_id_46392f_idx" + fields=["team_id", "distinct_id", "timestamp", "session_id"], + name="posthog_ses_team_id_46392f_idx", ), ), ] diff --git a/posthog/migrations/0096_plugins.py b/posthog/migrations/0096_plugins.py index 765e13e122a65..8ae7167596371 100644 --- a/posthog/migrations/0096_plugins.py +++ b/posthog/migrations/0096_plugins.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0095_session_recording_event_table"), ] diff --git a/posthog/migrations/0097_invite_emails.py b/posthog/migrations/0097_invite_emails.py index f12ac859111ef..ff6aa476f5e30 100644 --- a/posthog/migrations/0097_invite_emails.py +++ b/posthog/migrations/0097_invite_emails.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0096_plugins"), ] diff --git a/posthog/migrations/0098_events_property_usage.py b/posthog/migrations/0098_events_property_usage.py index ed45de9c99645..99f56f0bb1387 100644 --- a/posthog/migrations/0098_events_property_usage.py +++ b/posthog/migrations/0098_events_property_usage.py @@ -5,7 +5,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0097_invite_emails"), ] diff --git a/posthog/migrations/0099_plugin_attachment.py b/posthog/migrations/0099_plugin_attachment.py index 6cb474f0a6bac..4f49ebf712858 100644 --- a/posthog/migrations/0099_plugin_attachment.py +++ b/posthog/migrations/0099_plugin_attachment.py @@ -5,7 +5,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0098_events_property_usage"), ] @@ -14,7 +13,15 @@ class Migration(migrations.Migration): migrations.CreateModel( name="PluginAttachment", fields=[ - ("id", models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), ("key", models.CharField(max_length=200)), ("content_type", models.CharField(max_length=200)), ("file_name", models.CharField(max_length=200)), @@ -22,9 +29,19 @@ class Migration(migrations.Migration): ("contents", models.BinaryField()), ( "plugin_config", - models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="posthog.PluginConfig"), + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + to="posthog.PluginConfig", + ), + ), + ( + "team", + models.ForeignKey( + null=True, + on_delete=django.db.models.deletion.CASCADE, + to="posthog.Team", + ), ), - ("team", models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to="posthog.Team")), ], ), ] diff --git a/posthog/migrations/0100_action_step_max_length.py b/posthog/migrations/0100_action_step_max_length.py index a14256c139273..f81ac84ae64d3 100644 --- a/posthog/migrations/0100_action_step_max_length.py +++ b/posthog/migrations/0100_action_step_max_length.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0099_plugin_attachment"), ] diff --git a/posthog/migrations/0101_org_owners.py b/posthog/migrations/0101_org_owners.py index f9e04e97fb4e1..93effd980a703 100644 --- a/posthog/migrations/0101_org_owners.py +++ b/posthog/migrations/0101_org_owners.py @@ -20,7 +20,6 @@ def make_owners_administrators_again(apps, schema_editor): class Migration(migrations.Migration): - dependencies = [ ("posthog", "0100_action_step_max_length"), ] @@ -36,8 +35,14 @@ class Migration(migrations.Migration): migrations.AddConstraint( model_name="organizationmembership", constraint=models.UniqueConstraint( - condition=models.Q(level=15), fields=("organization_id",), name="only_one_owner_per_organization" + condition=models.Q(level=15), + fields=("organization_id",), + name="only_one_owner_per_organization", ), ), - migrations.RunPython(make_first_administrators_owners, make_owners_administrators_again, elidable=True), + migrations.RunPython( + make_first_administrators_owners, + make_owners_administrators_again, + elidable=True, + ), ] diff --git a/posthog/migrations/0102_dashboarditem_filters_hash.py b/posthog/migrations/0102_dashboarditem_filters_hash.py index 188859c466359..9d3d12c9b6e88 100644 --- a/posthog/migrations/0102_dashboarditem_filters_hash.py +++ b/posthog/migrations/0102_dashboarditem_filters_hash.py @@ -24,7 +24,6 @@ def reverse(apps, schema_editor): class Migration(migrations.Migration): - dependencies = [ ("posthog", "0101_org_owners"), ] diff --git a/posthog/migrations/0103_retention_remove_date.py b/posthog/migrations/0103_retention_remove_date.py index 45b20942c8a9b..ed00fec812576 100644 --- a/posthog/migrations/0103_retention_remove_date.py +++ b/posthog/migrations/0103_retention_remove_date.py @@ -7,7 +7,9 @@ def forward(apps, schema_editor): DashboardItem = apps.get_model("posthog", "DashboardItem") for item in DashboardItem.objects.filter( - filters__insight="RETENTION", filters__selectedDate__isnull=False, dashboard__isnull=False + filters__insight="RETENTION", + filters__selectedDate__isnull=False, + dashboard__isnull=False, ): item.filters.pop("selectedDate") item.save() @@ -18,7 +20,6 @@ def reverse(apps, schema_editor): class Migration(migrations.Migration): - dependencies = [ ("posthog", "0102_dashboarditem_filters_hash"), ] diff --git a/posthog/migrations/0104_auto_20201208_1052.py b/posthog/migrations/0104_auto_20201208_1052.py index ecda95ed3a63a..15a0f8e90b9d1 100644 --- a/posthog/migrations/0104_auto_20201208_1052.py +++ b/posthog/migrations/0104_auto_20201208_1052.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0103_retention_remove_date"), ] diff --git a/posthog/migrations/0105_cohort_errors_calculating.py b/posthog/migrations/0105_cohort_errors_calculating.py index 9fb142a129edc..d0254fa311159 100644 --- a/posthog/migrations/0105_cohort_errors_calculating.py +++ b/posthog/migrations/0105_cohort_errors_calculating.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0104_auto_20201208_1052"), ] diff --git a/posthog/migrations/0106_dashboard_item_type_to_display.py b/posthog/migrations/0106_dashboard_item_type_to_display.py index dd456b59717ae..8a47a57f3c167 100644 --- a/posthog/migrations/0106_dashboard_item_type_to_display.py +++ b/posthog/migrations/0106_dashboard_item_type_to_display.py @@ -23,7 +23,6 @@ def reverse(apps, schema_editor): class Migration(migrations.Migration): - dependencies = [ ("posthog", "0105_cohort_errors_calculating"), ] diff --git a/posthog/migrations/0107_plugin_source.py b/posthog/migrations/0107_plugin_source.py index 3e24136c29984..b8d380da63624 100644 --- a/posthog/migrations/0107_plugin_source.py +++ b/posthog/migrations/0107_plugin_source.py @@ -15,7 +15,6 @@ def backwards(apps, schema_editor): class Migration(migrations.Migration): - dependencies = [ ("posthog", "0106_dashboard_item_type_to_display"), ] @@ -26,7 +25,12 @@ class Migration(migrations.Migration): name="plugin_type", field=models.CharField( blank=True, - choices=[("local", "local"), ("custom", "custom"), ("repository", "repository"), ("source", "source")], + choices=[ + ("local", "local"), + ("custom", "custom"), + ("repository", "repository"), + ("source", "source"), + ], default=None, max_length=200, null=True, diff --git a/posthog/migrations/0108_plugin_organization.py b/posthog/migrations/0108_plugin_organization.py index e66b63ca91f79..36a422017b66e 100644 --- a/posthog/migrations/0108_plugin_organization.py +++ b/posthog/migrations/0108_plugin_organization.py @@ -11,7 +11,6 @@ def set_plugin_organization(apps, schema_editor): class Migration(migrations.Migration): - dependencies = [ ("posthog", "0107_plugin_source"), ] diff --git a/posthog/migrations/0109_fix_retention_filters.py b/posthog/migrations/0109_fix_retention_filters.py index 087994342e5f2..b313aa87c7d00 100644 --- a/posthog/migrations/0109_fix_retention_filters.py +++ b/posthog/migrations/0109_fix_retention_filters.py @@ -17,7 +17,6 @@ def backwards(apps, schema_editor): class Migration(migrations.Migration): - dependencies = [ ("posthog", "0108_plugin_organization"), ] diff --git a/posthog/migrations/0111_plugin_storage.py b/posthog/migrations/0111_plugin_storage.py index 5d26fe5444f90..2016036bca333 100644 --- a/posthog/migrations/0111_plugin_storage.py +++ b/posthog/migrations/0111_plugin_storage.py @@ -5,7 +5,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0110_sessionrecordingeventbyteamandtimestamp"), ] @@ -14,19 +13,31 @@ class Migration(migrations.Migration): migrations.CreateModel( name="PluginStorage", fields=[ - ("id", models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), ("key", models.CharField(max_length=200)), ("value", models.TextField(blank=True, null=True)), ( "plugin_config", - models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="posthog.PluginConfig"), + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + to="posthog.PluginConfig", + ), ), ], ), migrations.AddConstraint( model_name="pluginstorage", constraint=models.UniqueConstraint( - fields=("plugin_config_id", "key"), name="posthog_unique_plugin_storage_key" + fields=("plugin_config_id", "key"), + name="posthog_unique_plugin_storage_key", ), ), ] diff --git a/posthog/migrations/0112_sessions_filter.py b/posthog/migrations/0112_sessions_filter.py index e681e0ee54775..2667a1f5e04cb 100644 --- a/posthog/migrations/0112_sessions_filter.py +++ b/posthog/migrations/0112_sessions_filter.py @@ -7,7 +7,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0111_plugin_storage"), ] @@ -16,18 +15,35 @@ class Migration(migrations.Migration): migrations.CreateModel( name="SessionsFilter", fields=[ - ("id", models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), ("name", models.CharField(blank=True, max_length=400, null=False)), ("created_at", models.DateTimeField(auto_now_add=True)), ("updated_at", models.DateTimeField(auto_now=True)), - ("filters", django.contrib.postgres.fields.jsonb.JSONField(default=dict)), + ( + "filters", + django.contrib.postgres.fields.jsonb.JSONField(default=dict), + ), ( "created_by", models.ForeignKey( - blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + to=settings.AUTH_USER_MODEL, ), ), - ("team", models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="posthog.Team")), + ( + "team", + models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="posthog.Team"), + ), ], ), migrations.AddIndex( diff --git a/posthog/migrations/0113_cohort_is_static.py b/posthog/migrations/0113_cohort_is_static.py index cb76e16a26b8a..4e47813670209 100644 --- a/posthog/migrations/0113_cohort_is_static.py +++ b/posthog/migrations/0113_cohort_is_static.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0112_sessions_filter"), ] diff --git a/posthog/migrations/0114_fix_team_event_names.py b/posthog/migrations/0114_fix_team_event_names.py index 6b9143bf4c69c..a9803e62f9d4c 100644 --- a/posthog/migrations/0114_fix_team_event_names.py +++ b/posthog/migrations/0114_fix_team_event_names.py @@ -9,7 +9,9 @@ def fix_team_event_names(apps, schema_editor): old_event_names = team.event_names team.event_names = [event for event in old_event_names if isinstance(event, str)] if len(team.event_names) != len(old_event_names): - from posthog.tasks.calculate_event_property_usage import calculate_event_property_usage_for_team + from posthog.tasks.calculate_event_property_usage import ( + calculate_event_property_usage_for_team, + ) team.save() calculate_event_property_usage_for_team(team.pk) @@ -20,7 +22,6 @@ def backwards(apps, schema_editor): class Migration(migrations.Migration): - dependencies = [ ("posthog", "0113_cohort_is_static"), ] diff --git a/posthog/migrations/0115_session_recording_viewed.py b/posthog/migrations/0115_session_recording_viewed.py index af7c4adfffa86..695ce6592e144 100644 --- a/posthog/migrations/0115_session_recording_viewed.py +++ b/posthog/migrations/0115_session_recording_viewed.py @@ -6,7 +6,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0114_fix_team_event_names"), ] @@ -15,16 +14,36 @@ class Migration(migrations.Migration): migrations.CreateModel( name="SessionRecordingViewed", fields=[ - ("id", models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), ("created_at", models.DateTimeField(auto_now_add=True, null=True)), ("session_id", models.CharField(max_length=200)), - ("team", models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="posthog.Team")), - ("user", models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), + ( + "team", + models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="posthog.Team"), + ), + ( + "user", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + to=settings.AUTH_USER_MODEL, + ), + ), ], ), migrations.AddIndex( model_name="sessionrecordingviewed", - index=models.Index(fields=["team_id", "user_id", "session_id"], name="posthog_ses_team_id_465af1_idx"), + index=models.Index( + fields=["team_id", "user_id", "session_id"], + name="posthog_ses_team_id_465af1_idx", + ), ), migrations.AlterUniqueTogether( name="sessionrecordingviewed", diff --git a/posthog/migrations/0116_plugin_latest_tag.py b/posthog/migrations/0116_plugin_latest_tag.py index d9206f419e8c0..43bdaf4b6c293 100644 --- a/posthog/migrations/0116_plugin_latest_tag.py +++ b/posthog/migrations/0116_plugin_latest_tag.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0115_session_recording_viewed"), ] diff --git a/posthog/migrations/0116_session_recording_retention_period.py b/posthog/migrations/0116_session_recording_retention_period.py index 7c22507ebb464..fcba843db267f 100644 --- a/posthog/migrations/0116_session_recording_retention_period.py +++ b/posthog/migrations/0116_session_recording_retention_period.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0115_session_recording_viewed"), ] diff --git a/posthog/migrations/0117_merge_20210126_0917.py b/posthog/migrations/0117_merge_20210126_0917.py index 58d4c58b420ed..215b295e771a2 100644 --- a/posthog/migrations/0117_merge_20210126_0917.py +++ b/posthog/migrations/0117_merge_20210126_0917.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0116_plugin_latest_tag"), ("posthog", "0116_session_recording_retention_period"), diff --git a/posthog/migrations/0118_is_demo.py b/posthog/migrations/0118_is_demo.py index ad156872b060d..a8ee78022e0ab 100644 --- a/posthog/migrations/0118_is_demo.py +++ b/posthog/migrations/0118_is_demo.py @@ -13,7 +13,6 @@ def reverse(apps, schema_editor): class Migration(migrations.Migration): - dependencies = [ ("posthog", "0117_merge_20210126_0917"), ] diff --git a/posthog/migrations/0119_mandatory_plugin_order.py b/posthog/migrations/0119_mandatory_plugin_order.py index 0d11fe4c5dba3..d357ac97b0c5d 100644 --- a/posthog/migrations/0119_mandatory_plugin_order.py +++ b/posthog/migrations/0119_mandatory_plugin_order.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0118_is_demo"), ] diff --git a/posthog/migrations/0120_organization_personalization.py b/posthog/migrations/0120_organization_personalization.py index dbba7585b1562..d8bbda6227122 100644 --- a/posthog/migrations/0120_organization_personalization.py +++ b/posthog/migrations/0120_organization_personalization.py @@ -5,7 +5,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0119_mandatory_plugin_order"), ] diff --git a/posthog/migrations/0122_organization_setup_section_2_completed.py b/posthog/migrations/0122_organization_setup_section_2_completed.py index 1f08e6c3eb76c..36d060caa991e 100644 --- a/posthog/migrations/0122_organization_setup_section_2_completed.py +++ b/posthog/migrations/0122_organization_setup_section_2_completed.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0121_person_email_index"), ] diff --git a/posthog/migrations/0123_organizationinvite_first_name.py b/posthog/migrations/0123_organizationinvite_first_name.py index f20482d789e85..a16a8e1f23030 100644 --- a/posthog/migrations/0123_organizationinvite_first_name.py +++ b/posthog/migrations/0123_organizationinvite_first_name.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0122_organization_setup_section_2_completed"), ] diff --git a/posthog/migrations/0124_unset_is_calculating_static_cohorts.py b/posthog/migrations/0124_unset_is_calculating_static_cohorts.py index ed1a3000d6a57..cb7a3bc8176dc 100644 --- a/posthog/migrations/0124_unset_is_calculating_static_cohorts.py +++ b/posthog/migrations/0124_unset_is_calculating_static_cohorts.py @@ -13,7 +13,6 @@ def reverse(apps, schema_editor): class Migration(migrations.Migration): - dependencies = [ ("posthog", "0123_organizationinvite_first_name"), ] diff --git a/posthog/migrations/0125_longer_webhook_url.py b/posthog/migrations/0125_longer_webhook_url.py index c87c15ae5438f..3ea0beab6aabc 100644 --- a/posthog/migrations/0125_longer_webhook_url.py +++ b/posthog/migrations/0125_longer_webhook_url.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0124_unset_is_calculating_static_cohorts"), ] diff --git a/posthog/migrations/0126_fix_funnels_insights_links.py b/posthog/migrations/0126_fix_funnels_insights_links.py index 074b95c34ebfa..5379cf8920a89 100644 --- a/posthog/migrations/0126_fix_funnels_insights_links.py +++ b/posthog/migrations/0126_fix_funnels_insights_links.py @@ -15,7 +15,6 @@ def reverse(apps, schema_editor): class Migration(migrations.Migration): - dependencies = [ ("posthog", "0125_longer_webhook_url"), ] diff --git a/posthog/migrations/0127_add_dashboard_filters.py b/posthog/migrations/0127_add_dashboard_filters.py index 73052b72778a5..1cd1b2d0bbc69 100644 --- a/posthog/migrations/0127_add_dashboard_filters.py +++ b/posthog/migrations/0127_add_dashboard_filters.py @@ -5,7 +5,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0126_fix_funnels_insights_links"), ] diff --git a/posthog/migrations/0127_stricter_team_data.py b/posthog/migrations/0127_stricter_team_data.py index 64d4d15703251..3a2e6a0ba733d 100644 --- a/posthog/migrations/0127_stricter_team_data.py +++ b/posthog/migrations/0127_stricter_team_data.py @@ -17,11 +17,14 @@ def adjust_teams_for_stricter_requirements(apps, schema_editor): class Migration(migrations.Migration): - dependencies = [ ("posthog", "0126_fix_funnels_insights_links"), ] operations = [ - migrations.RunPython(adjust_teams_for_stricter_requirements, migrations.RunPython.noop, elidable=True), + migrations.RunPython( + adjust_teams_for_stricter_requirements, + migrations.RunPython.noop, + elidable=True, + ), ] diff --git a/posthog/migrations/0128_stricter_team_schema.py b/posthog/migrations/0128_stricter_team_schema.py index c974080e643da..26f0210798515 100644 --- a/posthog/migrations/0128_stricter_team_schema.py +++ b/posthog/migrations/0128_stricter_team_schema.py @@ -8,7 +8,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0127_stricter_team_data"), ] diff --git a/posthog/migrations/0129_merge_20210223_0757.py b/posthog/migrations/0129_merge_20210223_0757.py index 919bfb5ada376..4f28607b0bec2 100644 --- a/posthog/migrations/0129_merge_20210223_0757.py +++ b/posthog/migrations/0129_merge_20210223_0757.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0128_stricter_team_schema"), ("posthog", "0127_add_dashboard_filters"), diff --git a/posthog/migrations/0130_dashboard_creation_mode.py b/posthog/migrations/0130_dashboard_creation_mode.py index a163da42b2e05..cf102ef97a5c9 100644 --- a/posthog/migrations/0130_dashboard_creation_mode.py +++ b/posthog/migrations/0130_dashboard_creation_mode.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0129_merge_20210223_0757"), ] @@ -14,7 +13,11 @@ class Migration(migrations.Migration): model_name="dashboard", name="creation_mode", field=models.CharField( - choices=[("default", "Default"), ("template", "Template"), ("duplicate", "Duplicate")], + choices=[ + ("default", "Default"), + ("template", "Template"), + ("duplicate", "Duplicate"), + ], default="default", max_length=16, ), diff --git a/posthog/migrations/0131_add_plugins_updated_created_at.py b/posthog/migrations/0131_add_plugins_updated_created_at.py index 873214abf6a73..1c3ef33ab1b0d 100644 --- a/posthog/migrations/0131_add_plugins_updated_created_at.py +++ b/posthog/migrations/0131_add_plugins_updated_created_at.py @@ -6,7 +6,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0130_dashboard_creation_mode"), ] diff --git a/posthog/migrations/0132_team_test_account_filters.py b/posthog/migrations/0132_team_test_account_filters.py index 339ac4ec5ceee..313de9f3355e4 100644 --- a/posthog/migrations/0132_team_test_account_filters.py +++ b/posthog/migrations/0132_team_test_account_filters.py @@ -40,7 +40,12 @@ def forward(apps, schema_editor): { "key": "$host", "operator": "is_not", - "value": ["localhost:8000", "localhost:5000", "127.0.0.1:8000", "127.0.0.1:3000"], + "value": [ + "localhost:8000", + "localhost:5000", + "127.0.0.1:8000", + "127.0.0.1:3000", + ], }, ] if team.organization: @@ -51,7 +56,12 @@ def forward(apps, schema_editor): example_email = re.search(r"@[\w.]+", example_emails[0]) if example_email: filters += [ - {"key": "email", "operator": "not_icontains", "value": example_email.group(), "type": "person"}, + { + "key": "email", + "operator": "not_icontains", + "value": example_email.group(), + "type": "person", + }, ] team.test_account_filters = filters team.save() @@ -62,7 +72,6 @@ def reverse(apps, schema_editor): class Migration(migrations.Migration): - dependencies = [ ("posthog", "0131_add_plugins_updated_created_at"), ] diff --git a/posthog/migrations/0133_plugins_access_control.py b/posthog/migrations/0133_plugins_access_control.py index 824853fdb0666..0e10347b18393 100644 --- a/posthog/migrations/0133_plugins_access_control.py +++ b/posthog/migrations/0133_plugins_access_control.py @@ -5,7 +5,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0132_team_test_account_filters"), ] @@ -33,7 +32,10 @@ class Migration(migrations.Migration): model_name="team", name="app_urls", field=fields.ArrayField( - base_field=models.CharField(max_length=200, null=True), blank=True, default=list, size=None + base_field=models.CharField(max_length=200, null=True), + blank=True, + default=list, + size=None, ), ), migrations.AlterField( diff --git a/posthog/migrations/0134_event_site_url.py b/posthog/migrations/0134_event_site_url.py index 0096edcf1b74f..c70de913a77b8 100644 --- a/posthog/migrations/0134_event_site_url.py +++ b/posthog/migrations/0134_event_site_url.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0133_plugins_access_control"), ] diff --git a/posthog/migrations/0135_plugins_on_cloud.py b/posthog/migrations/0135_plugins_on_cloud.py index 38afccfb7dfdf..bbf7165f956bf 100644 --- a/posthog/migrations/0135_plugins_on_cloud.py +++ b/posthog/migrations/0135_plugins_on_cloud.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0134_event_site_url"), ] diff --git a/posthog/migrations/0136_global_plugin_attachments.py b/posthog/migrations/0136_global_plugin_attachments.py index cd269c296886b..b0207e75bb878 100644 --- a/posthog/migrations/0136_global_plugin_attachments.py +++ b/posthog/migrations/0136_global_plugin_attachments.py @@ -5,7 +5,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0135_plugins_on_cloud"), ] @@ -14,6 +13,10 @@ class Migration(migrations.Migration): migrations.AlterField( model_name="pluginattachment", name="plugin_config", - field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to="posthog.PluginConfig"), + field=models.ForeignKey( + null=True, + on_delete=django.db.models.deletion.CASCADE, + to="posthog.PluginConfig", + ), ), ] diff --git a/posthog/migrations/0137_team_timezone.py b/posthog/migrations/0137_team_timezone.py index 09c9077a4172c..b7b31ff04f75c 100644 --- a/posthog/migrations/0137_team_timezone.py +++ b/posthog/migrations/0137_team_timezone.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0136_global_plugin_attachments"), ] @@ -72,13 +71,19 @@ class Migration(migrations.Migration): ("America/Anguilla", "America/Anguilla"), ("America/Antigua", "America/Antigua"), ("America/Araguaina", "America/Araguaina"), - ("America/Argentina/Buenos_Aires", "America/Argentina/Buenos_Aires"), + ( + "America/Argentina/Buenos_Aires", + "America/Argentina/Buenos_Aires", + ), ("America/Argentina/Catamarca", "America/Argentina/Catamarca"), ("America/Argentina/Cordoba", "America/Argentina/Cordoba"), ("America/Argentina/Jujuy", "America/Argentina/Jujuy"), ("America/Argentina/La_Rioja", "America/Argentina/La_Rioja"), ("America/Argentina/Mendoza", "America/Argentina/Mendoza"), - ("America/Argentina/Rio_Gallegos", "America/Argentina/Rio_Gallegos"), + ( + "America/Argentina/Rio_Gallegos", + "America/Argentina/Rio_Gallegos", + ), ("America/Argentina/Salta", "America/Argentina/Salta"), ("America/Argentina/San_Juan", "America/Argentina/San_Juan"), ("America/Argentina/San_Luis", "America/Argentina/San_Luis"), @@ -172,7 +177,10 @@ class Migration(migrations.Migration): ("America/Noronha", "America/Noronha"), ("America/North_Dakota/Beulah", "America/North_Dakota/Beulah"), ("America/North_Dakota/Center", "America/North_Dakota/Center"), - ("America/North_Dakota/New_Salem", "America/North_Dakota/New_Salem"), + ( + "America/North_Dakota/New_Salem", + "America/North_Dakota/New_Salem", + ), ("America/Nuuk", "America/Nuuk"), ("America/Ojinaga", "America/Ojinaga"), ("America/Panama", "America/Panama"), diff --git a/posthog/migrations/0138_featureflag_name_optional.py b/posthog/migrations/0138_featureflag_name_optional.py index 91cea1870b0f4..95e892cc419fb 100644 --- a/posthog/migrations/0138_featureflag_name_optional.py +++ b/posthog/migrations/0138_featureflag_name_optional.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0137_team_timezone"), ] diff --git a/posthog/migrations/0139_dashboard_tagging.py b/posthog/migrations/0139_dashboard_tagging.py index f16d90cd0933c..f5b1d24d1db8b 100644 --- a/posthog/migrations/0139_dashboard_tagging.py +++ b/posthog/migrations/0139_dashboard_tagging.py @@ -5,13 +5,16 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0138_featureflag_name_optional"), ] operations = [ - migrations.AddField(model_name="dashboard", name="description", field=models.TextField(blank=True)), + migrations.AddField( + model_name="dashboard", + name="description", + field=models.TextField(blank=True), + ), migrations.AddField( model_name="dashboard", name="tags", diff --git a/posthog/migrations/0140_team_data_attributes.py b/posthog/migrations/0140_team_data_attributes.py index 4d832106ebe5b..3a53999977c36 100644 --- a/posthog/migrations/0140_team_data_attributes.py +++ b/posthog/migrations/0140_team_data_attributes.py @@ -10,7 +10,6 @@ def set_default_data_attributes(apps, schema_editor): class Migration(migrations.Migration): - dependencies = [ ("posthog", "0139_dashboard_tagging"), ] diff --git a/posthog/migrations/0142_fix_team_data_attributes_default.py b/posthog/migrations/0142_fix_team_data_attributes_default.py index be1c263053aac..1e24b7d580234 100644 --- a/posthog/migrations/0142_fix_team_data_attributes_default.py +++ b/posthog/migrations/0142_fix_team_data_attributes_default.py @@ -7,7 +7,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0141_events_created_at_index"), ] diff --git a/posthog/migrations/0143_user_uuid.py b/posthog/migrations/0143_user_uuid.py index 484c78c1db1d3..8e3d2cb7ae384 100644 --- a/posthog/migrations/0143_user_uuid.py +++ b/posthog/migrations/0143_user_uuid.py @@ -17,7 +17,6 @@ def backwards(app, schema_editor): class Migration(migrations.Migration): - dependencies = [ ("posthog", "0142_fix_team_data_attributes_default"), ] diff --git a/posthog/migrations/0144_update_django_3_1_8.py b/posthog/migrations/0144_update_django_3_1_8.py index a063dbfaf77d0..375a532b7456c 100644 --- a/posthog/migrations/0144_update_django_3_1_8.py +++ b/posthog/migrations/0144_update_django_3_1_8.py @@ -6,7 +6,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0143_user_uuid"), ] diff --git a/posthog/migrations/0145_eventdefinition_propertydefinition.py b/posthog/migrations/0145_eventdefinition_propertydefinition.py index 6ebf7328ae3e4..e97e52b591120 100644 --- a/posthog/migrations/0145_eventdefinition_propertydefinition.py +++ b/posthog/migrations/0145_eventdefinition_propertydefinition.py @@ -7,7 +7,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0144_update_django_3_1_8"), ] @@ -19,7 +18,10 @@ class Migration(migrations.Migration): ( "id", models.UUIDField( - default=posthog.models.utils.UUIDT, editable=False, primary_key=True, serialize=False + default=posthog.models.utils.UUIDT, + editable=False, + primary_key=True, + serialize=False, ), ), ("name", models.CharField(max_length=400)), @@ -46,7 +48,10 @@ class Migration(migrations.Migration): ( "id", models.UUIDField( - default=posthog.models.utils.UUIDT, editable=False, primary_key=True, serialize=False + default=posthog.models.utils.UUIDT, + editable=False, + primary_key=True, + serialize=False, ), ), ("name", models.CharField(max_length=400)), diff --git a/posthog/migrations/0146_eventproperty_sync.py b/posthog/migrations/0146_eventproperty_sync.py index a83f455f1bbf9..a53527c2ad2bf 100644 --- a/posthog/migrations/0146_eventproperty_sync.py +++ b/posthog/migrations/0146_eventproperty_sync.py @@ -12,7 +12,6 @@ def sync_event_and_properties_definitions(team_uuid: str, Team, EventDefinition, PropertyDefinition) -> None: - team = None # It is possible that the team was deleted before the task could run @@ -64,11 +63,14 @@ def sync_team_event_names_and_properties(apps, schema_editor): class Migration(migrations.Migration): - dependencies = [ ("posthog", "0145_eventdefinition_propertydefinition"), ] operations = [ - migrations.RunPython(sync_team_event_names_and_properties, migrations.RunPython.noop, elidable=True), + migrations.RunPython( + sync_team_event_names_and_properties, + migrations.RunPython.noop, + elidable=True, + ), ] diff --git a/posthog/migrations/0147_fix_stickiness_dashboard_items.py b/posthog/migrations/0147_fix_stickiness_dashboard_items.py index 212aa8a489867..ba7954637f05b 100644 --- a/posthog/migrations/0147_fix_stickiness_dashboard_items.py +++ b/posthog/migrations/0147_fix_stickiness_dashboard_items.py @@ -11,7 +11,6 @@ def update_stickiness(apps, schema_editor): class Migration(migrations.Migration): - dependencies = [ ("posthog", "0146_eventproperty_sync"), ] diff --git a/posthog/migrations/0147_plugin_logs.py b/posthog/migrations/0147_plugin_logs.py index e5163836374b4..5d2844aa81c80 100644 --- a/posthog/migrations/0147_plugin_logs.py +++ b/posthog/migrations/0147_plugin_logs.py @@ -8,7 +8,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0146_eventproperty_sync"), ] @@ -20,7 +19,10 @@ class Migration(migrations.Migration): ( "id", models.UUIDField( - default=posthog.models.utils.UUIDT, editable=False, primary_key=True, serialize=False + default=posthog.models.utils.UUIDT, + editable=False, + primary_key=True, + serialize=False, ), ), ("timestamp", models.DateTimeField(default=django.utils.timezone.now)), @@ -50,16 +52,28 @@ class Migration(migrations.Migration): ), ("message", models.TextField(db_index=True)), ("instance_id", models.UUIDField()), - ("plugin", models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="posthog.plugin")), + ( + "plugin", + models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="posthog.plugin"), + ), ( "plugin_config", - models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="posthog.pluginconfig"), + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + to="posthog.pluginconfig", + ), + ), + ( + "team", + models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="posthog.team"), ), - ("team", models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="posthog.team")), ], ), migrations.AddIndex( model_name="pluginlogentry", - index=models.Index(fields=["plugin_config_id", "timestamp"], name="posthog_plu_plugin__736133_idx"), + index=models.Index( + fields=["plugin_config_id", "timestamp"], + name="posthog_plu_plugin__736133_idx", + ), ), ] diff --git a/posthog/migrations/0148_merge_20210506_0823.py b/posthog/migrations/0148_merge_20210506_0823.py index 3bb39d35e22a1..3e880cf836478 100644 --- a/posthog/migrations/0148_merge_20210506_0823.py +++ b/posthog/migrations/0148_merge_20210506_0823.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0147_plugin_logs"), ("posthog", "0147_fix_stickiness_dashboard_items"), diff --git a/posthog/migrations/0149_fix_lifecycle_dashboard_items.py b/posthog/migrations/0149_fix_lifecycle_dashboard_items.py index 1bd984dda628d..0890b104ec6f4 100644 --- a/posthog/migrations/0149_fix_lifecycle_dashboard_items.py +++ b/posthog/migrations/0149_fix_lifecycle_dashboard_items.py @@ -11,7 +11,6 @@ def update_lifecycle(apps, _): class Migration(migrations.Migration): - dependencies = [ ("posthog", "0148_merge_20210506_0823"), ] diff --git a/posthog/migrations/0150_increase_element_varchars.py b/posthog/migrations/0150_increase_element_varchars.py index ad622bd0f727d..93f4df18194b4 100644 --- a/posthog/migrations/0150_increase_element_varchars.py +++ b/posthog/migrations/0150_increase_element_varchars.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0149_fix_lifecycle_dashboard_items"), ] diff --git a/posthog/migrations/0151_plugin_preinstalled.py b/posthog/migrations/0151_plugin_preinstalled.py index f008fcf5c506e..d42fc8ede9904 100644 --- a/posthog/migrations/0151_plugin_preinstalled.py +++ b/posthog/migrations/0151_plugin_preinstalled.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0150_increase_element_varchars"), ] diff --git a/posthog/migrations/0152_user_events_column_config.py b/posthog/migrations/0152_user_events_column_config.py index e543eb2dbe967..0b8a311f2f2e3 100644 --- a/posthog/migrations/0152_user_events_column_config.py +++ b/posthog/migrations/0152_user_events_column_config.py @@ -6,7 +6,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0151_plugin_preinstalled"), ] diff --git a/posthog/migrations/0153_plugin_capabilities.py b/posthog/migrations/0153_plugin_capabilities.py index 1543275859024..a5b14ba10f758 100644 --- a/posthog/migrations/0153_plugin_capabilities.py +++ b/posthog/migrations/0153_plugin_capabilities.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0152_user_events_column_config"), ] diff --git a/posthog/migrations/0154_organization_for_internal_metrics.py b/posthog/migrations/0154_organization_for_internal_metrics.py index 0e27e01bc65c3..af56792e73be0 100644 --- a/posthog/migrations/0154_organization_for_internal_metrics.py +++ b/posthog/migrations/0154_organization_for_internal_metrics.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0153_plugin_capabilities"), ] diff --git a/posthog/migrations/0155_organization_available_features.py b/posthog/migrations/0155_organization_available_features.py index 2b2fe5de8e3c6..d0bda03ae5a79 100644 --- a/posthog/migrations/0155_organization_available_features.py +++ b/posthog/migrations/0155_organization_available_features.py @@ -5,7 +5,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0154_organization_for_internal_metrics"), ] @@ -15,7 +14,10 @@ class Migration(migrations.Migration): model_name="organization", name="available_features", field=django.contrib.postgres.fields.ArrayField( - base_field=models.CharField(max_length=64), blank=True, default=list, size=None + base_field=models.CharField(max_length=64), + blank=True, + default=list, + size=None, ), ), ] diff --git a/posthog/migrations/0157_plugin_metrics.py b/posthog/migrations/0157_plugin_metrics.py index 64ce3cdf26008..a33e2e9c3c993 100644 --- a/posthog/migrations/0157_plugin_metrics.py +++ b/posthog/migrations/0157_plugin_metrics.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0156_insight_short_id"), ] diff --git a/posthog/migrations/0158_new_token_format.py b/posthog/migrations/0158_new_token_format.py index d4118cb976040..165a7b9b2fcb5 100644 --- a/posthog/migrations/0158_new_token_format.py +++ b/posthog/migrations/0158_new_token_format.py @@ -7,7 +7,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0157_plugin_metrics"), ] @@ -17,7 +16,10 @@ class Migration(migrations.Migration): model_name="personalapikey", name="value", field=models.CharField( - default=posthog.models.utils.generate_random_token_personal, editable=False, max_length=50, unique=True + default=posthog.models.utils.generate_random_token_personal, + editable=False, + max_length=50, + unique=True, ), ), migrations.AlterField( diff --git a/posthog/migrations/0160_organization_domain_whitelist.py b/posthog/migrations/0160_organization_domain_whitelist.py index f277a8b3b4865..03307b3a5efc9 100644 --- a/posthog/migrations/0160_organization_domain_whitelist.py +++ b/posthog/migrations/0160_organization_domain_whitelist.py @@ -5,7 +5,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0159_remove_funnels_with_breakdown"), ] @@ -15,7 +14,10 @@ class Migration(migrations.Migration): model_name="organization", name="domain_whitelist", field=django.contrib.postgres.fields.ArrayField( - base_field=models.CharField(max_length=256), blank=True, default=list, size=None + base_field=models.CharField(max_length=256), + blank=True, + default=list, + size=None, ), ), ] diff --git a/posthog/migrations/0161_property_defs_search.py b/posthog/migrations/0161_property_defs_search.py index 96dd9f6d9b713..5963799289e95 100644 --- a/posthog/migrations/0161_property_defs_search.py +++ b/posthog/migrations/0161_property_defs_search.py @@ -6,7 +6,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0160_organization_domain_whitelist"), ] @@ -15,10 +14,18 @@ class Migration(migrations.Migration): TrigramExtension(), migrations.AddIndex( model_name="eventdefinition", - index=GinIndex(fields=["name"], name="index_event_definition_name", opclasses=["gin_trgm_ops"]), + index=GinIndex( + fields=["name"], + name="index_event_definition_name", + opclasses=["gin_trgm_ops"], + ), ), migrations.AddIndex( model_name="propertydefinition", - index=GinIndex(fields=["name"], name="index_property_definition_name", opclasses=["gin_trgm_ops"]), + index=GinIndex( + fields=["name"], + name="index_property_definition_name", + opclasses=["gin_trgm_ops"], + ), ), ] diff --git a/posthog/migrations/0162_organization_is_member_join_email_enabled.py b/posthog/migrations/0162_organization_is_member_join_email_enabled.py index 1277559492597..0d632f1231b78 100644 --- a/posthog/migrations/0162_organization_is_member_join_email_enabled.py +++ b/posthog/migrations/0162_organization_is_member_join_email_enabled.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0161_property_defs_search"), ] diff --git a/posthog/migrations/0163_insights_favorited_updatedat_tags.py b/posthog/migrations/0163_insights_favorited_updatedat_tags.py index c5a40dcc94e66..2d84e5b65fa2c 100644 --- a/posthog/migrations/0163_insights_favorited_updatedat_tags.py +++ b/posthog/migrations/0163_insights_favorited_updatedat_tags.py @@ -5,7 +5,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0162_organization_is_member_join_email_enabled"), ] @@ -20,7 +19,10 @@ class Migration(migrations.Migration): model_name="dashboarditem", name="tags", field=django.contrib.postgres.fields.ArrayField( - base_field=models.CharField(max_length=32), blank=True, default=list, size=None + base_field=models.CharField(max_length=32), + blank=True, + default=list, + size=None, ), ), migrations.AddField( diff --git a/posthog/migrations/0165_dashboarditem_dive_dashboard.py b/posthog/migrations/0165_dashboarditem_dive_dashboard.py index a38a150f89772..6ac346a7cddb1 100644 --- a/posthog/migrations/0165_dashboarditem_dive_dashboard.py +++ b/posthog/migrations/0165_dashboarditem_dive_dashboard.py @@ -5,7 +5,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0164_person_index_by_team_and_id"), ] @@ -15,7 +14,10 @@ class Migration(migrations.Migration): model_name="dashboarditem", name="dive_dashboard", field=models.ForeignKey( - blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to="posthog.dashboard" + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + to="posthog.dashboard", ), ), ] diff --git a/posthog/migrations/0166_plugin_public_jobs.py b/posthog/migrations/0166_plugin_public_jobs.py index 082bd8e5be961..2a1ea2976b7e5 100644 --- a/posthog/migrations/0166_plugin_public_jobs.py +++ b/posthog/migrations/0166_plugin_public_jobs.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0165_dashboarditem_dive_dashboard"), ] diff --git a/posthog/migrations/0167_feature_flag_override.py b/posthog/migrations/0167_feature_flag_override.py index 3dc9007b090a9..d8612997f9aea 100644 --- a/posthog/migrations/0167_feature_flag_override.py +++ b/posthog/migrations/0167_feature_flag_override.py @@ -6,7 +6,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0166_plugin_public_jobs"), ] @@ -15,20 +14,41 @@ class Migration(migrations.Migration): migrations.CreateModel( name="FeatureFlagOverride", fields=[ - ("id", models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), ("override_value", models.JSONField()), ( "feature_flag", - models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="posthog.featureflag"), + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + to="posthog.featureflag", + ), + ), + ( + "user", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + to=settings.AUTH_USER_MODEL, + ), + ), + ( + "team", + models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="posthog.team"), ), - ("user", models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), - ("team", models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="posthog.team")), ], ), migrations.AddConstraint( model_name="featureflagoverride", constraint=models.UniqueConstraint( - fields=("user", "feature_flag", "team"), name="unique feature flag for a user/team combo" + fields=("user", "feature_flag", "team"), + name="unique feature flag for a user/team combo", ), ), ] diff --git a/posthog/migrations/0169_person_properties_last_updated_at.py b/posthog/migrations/0169_person_properties_last_updated_at.py index cec9034911e9e..381bc7a25c81d 100644 --- a/posthog/migrations/0169_person_properties_last_updated_at.py +++ b/posthog/migrations/0169_person_properties_last_updated_at.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0168_action_step_empty_string_reset"), ] diff --git a/posthog/migrations/0170_project_based_permissioning.py b/posthog/migrations/0170_project_based_permissioning.py index 7f214bc84f48e..0f774199b0001 100644 --- a/posthog/migrations/0170_project_based_permissioning.py +++ b/posthog/migrations/0170_project_based_permissioning.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0169_person_properties_last_updated_at"), ] diff --git a/posthog/migrations/0171_cohort_description.py b/posthog/migrations/0171_cohort_description.py index 951f992947026..70f78f35e30a5 100644 --- a/posthog/migrations/0171_cohort_description.py +++ b/posthog/migrations/0171_cohort_description.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0170_project_based_permissioning"), ] diff --git a/posthog/migrations/0172_person_properties_last_operation.py b/posthog/migrations/0172_person_properties_last_operation.py index c2d8fbb5b6543..de91895bf629d 100644 --- a/posthog/migrations/0172_person_properties_last_operation.py +++ b/posthog/migrations/0172_person_properties_last_operation.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0171_cohort_description"), ] diff --git a/posthog/migrations/0173_should_update_person_props_function.py b/posthog/migrations/0173_should_update_person_props_function.py index 57c0b37fbe87e..dae88cbdfbf13 100644 --- a/posthog/migrations/0173_should_update_person_props_function.py +++ b/posthog/migrations/0173_should_update_person_props_function.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0172_person_properties_last_operation"), ] diff --git a/posthog/migrations/0174_organization_slug.py b/posthog/migrations/0174_organization_slug.py index 8d79133fb2b51..8bdd611d3b9e0 100644 --- a/posthog/migrations/0174_organization_slug.py +++ b/posthog/migrations/0174_organization_slug.py @@ -28,7 +28,6 @@ def slugify_all(apps, schema_editor): class Migration(migrations.Migration): - dependencies = [ ("posthog", "0173_should_update_person_props_function"), ] diff --git a/posthog/migrations/0175_should_update_person_props_function.py b/posthog/migrations/0175_should_update_person_props_function.py index b90a896e5c139..356028422d461 100644 --- a/posthog/migrations/0175_should_update_person_props_function.py +++ b/posthog/migrations/0175_should_update_person_props_function.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0174_organization_slug"), ] diff --git a/posthog/migrations/0176_update_person_props_function.py b/posthog/migrations/0176_update_person_props_function.py index 3f0f1f6e919ad..974fb90062026 100644 --- a/posthog/migrations/0176_update_person_props_function.py +++ b/posthog/migrations/0176_update_person_props_function.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0175_should_update_person_props_function"), ] diff --git a/posthog/migrations/0177_path_cleaning_filters.py b/posthog/migrations/0177_path_cleaning_filters.py index 3e731d7787655..adaf7819b135c 100644 --- a/posthog/migrations/0177_path_cleaning_filters.py +++ b/posthog/migrations/0177_path_cleaning_filters.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0176_update_person_props_function"), ] diff --git a/posthog/migrations/0178_rename_dashboard_item_to_insight.py b/posthog/migrations/0178_rename_dashboard_item_to_insight.py index 1c6bf777abf49..2cea98aedaa7c 100644 --- a/posthog/migrations/0178_rename_dashboard_item_to_insight.py +++ b/posthog/migrations/0178_rename_dashboard_item_to_insight.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0177_path_cleaning_filters"), ] diff --git a/posthog/migrations/0179_add_group_type_mapping.py b/posthog/migrations/0179_add_group_type_mapping.py index e977ee52079f9..47311ff1756ab 100644 --- a/posthog/migrations/0179_add_group_type_mapping.py +++ b/posthog/migrations/0179_add_group_type_mapping.py @@ -5,7 +5,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0178_rename_dashboard_item_to_insight"), ] @@ -14,10 +13,21 @@ class Migration(migrations.Migration): migrations.CreateModel( name="GroupTypeMapping", fields=[ - ("id", models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), ("group_type", models.CharField(max_length=400)), ("group_type_index", models.IntegerField()), - ("team", models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="posthog.team")), + ( + "team", + models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="posthog.team"), + ), ], ), migrations.AddConstraint( @@ -27,13 +37,15 @@ class Migration(migrations.Migration): migrations.AddConstraint( model_name="grouptypemapping", constraint=models.UniqueConstraint( - fields=("team", "group_type_index"), name="unique event column indexes for team" + fields=("team", "group_type_index"), + name="unique event column indexes for team", ), ), migrations.AddConstraint( model_name="grouptypemapping", constraint=models.CheckConstraint( - check=models.Q(("group_type_index__lte", 5)), name="group_type_index is less than or equal 5" + check=models.Q(("group_type_index__lte", 5)), + name="group_type_index is less than or equal 5", ), ), ] diff --git a/posthog/migrations/0180_person_version.py b/posthog/migrations/0180_person_version.py index 46d008ccf5f35..d6d48d7643f78 100644 --- a/posthog/migrations/0180_person_version.py +++ b/posthog/migrations/0180_person_version.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0179_add_group_type_mapping"), ] diff --git a/posthog/migrations/0181_team_correlation_config.py b/posthog/migrations/0181_team_correlation_config.py index 5d8dc4f3a80bd..9bc7be124d8c6 100644 --- a/posthog/migrations/0181_team_correlation_config.py +++ b/posthog/migrations/0181_team_correlation_config.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0180_person_version"), ] diff --git a/posthog/migrations/0182_sessionrecordingevent_window_id.py b/posthog/migrations/0182_sessionrecordingevent_window_id.py index 1bfcb9b9b71a9..ba59120a0bbb9 100644 --- a/posthog/migrations/0182_sessionrecordingevent_window_id.py +++ b/posthog/migrations/0182_sessionrecordingevent_window_id.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0181_team_correlation_config"), ] diff --git a/posthog/migrations/0183_groups_pg.py b/posthog/migrations/0183_groups_pg.py index 2924c8a581c05..ff5d69ffb0cce 100644 --- a/posthog/migrations/0183_groups_pg.py +++ b/posthog/migrations/0183_groups_pg.py @@ -5,7 +5,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0182_sessionrecordingevent_window_id"), ] @@ -14,7 +13,15 @@ class Migration(migrations.Migration): migrations.CreateModel( name="Group", fields=[ - ("id", models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), ("group_key", models.CharField(max_length=400)), ("group_type_index", models.IntegerField()), ("group_properties", models.JSONField(default=dict)), @@ -22,7 +29,10 @@ class Migration(migrations.Migration): ("properties_last_updated_at", models.JSONField(default=dict)), ("properties_last_operation", models.JSONField(default=dict)), ("version", models.BigIntegerField()), - ("team", models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="posthog.team")), + ( + "team", + models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="posthog.team"), + ), ], ), migrations.AddConstraint( diff --git a/posthog/migrations/0184_delete_sessionsfilter.py b/posthog/migrations/0184_delete_sessionsfilter.py index 4d5c6d7fda3f1..44df92d321541 100644 --- a/posthog/migrations/0184_delete_sessionsfilter.py +++ b/posthog/migrations/0184_delete_sessionsfilter.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0183_groups_pg"), ] diff --git a/posthog/migrations/0185_special_migrations.py b/posthog/migrations/0185_special_migrations.py index ef779c7aafcde..3c95dcb6e2a40 100644 --- a/posthog/migrations/0185_special_migrations.py +++ b/posthog/migrations/0185_special_migrations.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0184_delete_sessionsfilter"), ] @@ -15,17 +14,29 @@ class Migration(migrations.Migration): fields=[ ("id", models.BigAutoField(primary_key=True, serialize=False)), ("name", models.CharField(max_length=50)), - ("description", models.CharField(blank=True, max_length=400, null=True)), + ( + "description", + models.CharField(blank=True, max_length=400, null=True), + ), ("progress", models.PositiveSmallIntegerField(default=0)), ("status", models.PositiveSmallIntegerField(default=0)), - ("current_operation_index", models.PositiveSmallIntegerField(default=0)), + ( + "current_operation_index", + models.PositiveSmallIntegerField(default=0), + ), ("current_query_id", models.CharField(default="", max_length=100)), ("celery_task_id", models.CharField(default="", max_length=100)), ("started_at", models.DateTimeField(blank=True, null=True)), ("finished_at", models.DateTimeField(blank=True, null=True)), ("last_error", models.TextField(blank=True, null=True)), - ("posthog_min_version", models.CharField(blank=True, max_length=20, null=True)), - ("posthog_max_version", models.CharField(blank=True, max_length=20, null=True)), + ( + "posthog_min_version", + models.CharField(blank=True, max_length=20, null=True), + ), + ( + "posthog_max_version", + models.CharField(blank=True, max_length=20, null=True), + ), ], ), migrations.AddConstraint( diff --git a/posthog/migrations/0186_insight_refresh_attempt.py b/posthog/migrations/0186_insight_refresh_attempt.py index 052ef134cbb68..2f643dfe7d070 100644 --- a/posthog/migrations/0186_insight_refresh_attempt.py +++ b/posthog/migrations/0186_insight_refresh_attempt.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0185_special_migrations"), ] diff --git a/posthog/migrations/0187_stale_events.py b/posthog/migrations/0187_stale_events.py index c7aad3faeec0e..3fa16bd4457fa 100644 --- a/posthog/migrations/0187_stale_events.py +++ b/posthog/migrations/0187_stale_events.py @@ -4,7 +4,6 @@ def set_created_at(apps, schema_editor): - try: from posthog.client import sync_execute except ImportError: @@ -32,7 +31,6 @@ def set_created_at(apps, schema_editor): class Migration(migrations.Migration): - dependencies = [ ("posthog", "0186_insight_refresh_attempt"), ] diff --git a/posthog/migrations/0188_person_distinct_id_version.py b/posthog/migrations/0188_person_distinct_id_version.py index 0d068def31b40..57f2ab732499d 100644 --- a/posthog/migrations/0188_person_distinct_id_version.py +++ b/posthog/migrations/0188_person_distinct_id_version.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0187_stale_events"), ] diff --git a/posthog/migrations/0189_alter_annotation_scope.py b/posthog/migrations/0189_alter_annotation_scope.py index 2b0bc6b7ce2f1..c8eb52286e0c5 100644 --- a/posthog/migrations/0189_alter_annotation_scope.py +++ b/posthog/migrations/0189_alter_annotation_scope.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0188_person_distinct_id_version"), ] @@ -14,7 +13,11 @@ class Migration(migrations.Migration): model_name="annotation", name="scope", field=models.CharField( - choices=[("dashboard_item", "insight"), ("project", "project"), ("organization", "organization")], + choices=[ + ("dashboard_item", "insight"), + ("project", "project"), + ("organization", "organization"), + ], default="dashboard_item", max_length=24, ), diff --git a/posthog/migrations/0190_experiment.py b/posthog/migrations/0190_experiment.py index cec03a5e882d5..071722ba18e6c 100644 --- a/posthog/migrations/0190_experiment.py +++ b/posthog/migrations/0190_experiment.py @@ -7,7 +7,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0189_alter_annotation_scope"), ] @@ -16,9 +15,20 @@ class Migration(migrations.Migration): migrations.CreateModel( name="Experiment", fields=[ - ("id", models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), ("name", models.CharField(max_length=400)), - ("description", models.CharField(blank=True, max_length=400, null=True)), + ( + "description", + models.CharField(blank=True, max_length=400, null=True), + ), ("filters", models.JSONField(default=dict)), ("parameters", models.JSONField(default=dict, null=True)), ("start_date", models.DateTimeField(null=True)), @@ -27,13 +37,22 @@ class Migration(migrations.Migration): ("updated_at", models.DateTimeField(auto_now=True)), ( "created_by", - models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL), + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + to=settings.AUTH_USER_MODEL, + ), ), ( "feature_flag", - models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="posthog.featureflag"), + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + to="posthog.featureflag", + ), + ), + ( + "team", + models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="posthog.team"), ), - ("team", models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="posthog.team")), ], ), ] diff --git a/posthog/migrations/0191_rename_specialmigration_asyncmigration.py b/posthog/migrations/0191_rename_specialmigration_asyncmigration.py index 89455a47093bc..518b6cd3032a1 100644 --- a/posthog/migrations/0191_rename_specialmigration_asyncmigration.py +++ b/posthog/migrations/0191_rename_specialmigration_asyncmigration.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0190_experiment"), ] diff --git a/posthog/migrations/0192_event_properties.py b/posthog/migrations/0192_event_properties.py index d2d1c0afd023d..90cd831c338e0 100644 --- a/posthog/migrations/0192_event_properties.py +++ b/posthog/migrations/0192_event_properties.py @@ -6,7 +6,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0191_rename_specialmigration_asyncmigration"), ] @@ -15,7 +14,15 @@ class Migration(migrations.Migration): migrations.CreateModel( name="EventProperty", fields=[ - ("id", models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), ("event", models.CharField(max_length=400)), ("property", models.CharField(max_length=400)), ( @@ -38,7 +45,8 @@ class Migration(migrations.Migration): migrations.AddConstraint( model_name="eventproperty", constraint=models.UniqueConstraint( - fields=("team", "event", "property"), name="posthog_event_property_unique_team_event_property" + fields=("team", "event", "property"), + name="posthog_event_property_unique_team_event_property", ), ), ] diff --git a/posthog/migrations/0193_auto_20211222_0912.py b/posthog/migrations/0193_auto_20211222_0912.py index c5236c5300b02..a028cb6a7649f 100644 --- a/posthog/migrations/0193_auto_20211222_0912.py +++ b/posthog/migrations/0193_auto_20211222_0912.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0192_event_properties"), ] @@ -44,8 +43,14 @@ class Migration(migrations.Migration): constraint=models.CheckConstraint( check=models.Q( models.Q( - ("property_type__in", ["DateTime", "String", "Numeric", "Boolean"]), - ("property_type_format__in", ["unix_timestamp", "YYYY-MM-DD hh:mm:ss", "YYYY-MM-DD"]), + ( + "property_type__in", + ["DateTime", "String", "Numeric", "Boolean"], + ), + ( + "property_type_format__in", + ["unix_timestamp", "YYYY-MM-DD hh:mm:ss", "YYYY-MM-DD"], + ), ) ), name="property_type_and_format_are_valid", diff --git a/posthog/migrations/0194_set_property_type_for_time.py b/posthog/migrations/0194_set_property_type_for_time.py index 40a11c5cf10c9..452c46f18a144 100644 --- a/posthog/migrations/0194_set_property_type_for_time.py +++ b/posthog/migrations/0194_set_property_type_for_time.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0193_auto_20211222_0912"), ] diff --git a/posthog/migrations/0195_group_type_name.py b/posthog/migrations/0195_group_type_name.py index 4f818f3d3384c..c100c26b761f9 100644 --- a/posthog/migrations/0195_group_type_name.py +++ b/posthog/migrations/0195_group_type_name.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0194_set_property_type_for_time"), ] diff --git a/posthog/migrations/0196_update_property_types.py b/posthog/migrations/0196_update_property_types.py index 790cfed311ae3..230a536e0254c 100644 --- a/posthog/migrations/0196_update_property_types.py +++ b/posthog/migrations/0196_update_property_types.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0195_group_type_name"), ] @@ -39,7 +38,10 @@ class Migration(migrations.Migration): constraint=models.CheckConstraint( check=models.Q( models.Q( - ("property_type__in", ["DateTime", "String", "Numeric", "Boolean"]), + ( + "property_type__in", + ["DateTime", "String", "Numeric", "Boolean"], + ), ( "property_type_format__in", [ diff --git a/posthog/migrations/0197_plugin_is_stateless.py b/posthog/migrations/0197_plugin_is_stateless.py index 0b09f00404905..32d9018c89257 100644 --- a/posthog/migrations/0197_plugin_is_stateless.py +++ b/posthog/migrations/0197_plugin_is_stateless.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0196_update_property_types"), ] diff --git a/posthog/migrations/0198_async_migration_error.py b/posthog/migrations/0198_async_migration_error.py index 1fca61f08fca8..bd1932c772b76 100644 --- a/posthog/migrations/0198_async_migration_error.py +++ b/posthog/migrations/0198_async_migration_error.py @@ -5,7 +5,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0197_plugin_is_stateless"), ] @@ -23,7 +22,10 @@ class Migration(migrations.Migration): ("description", models.CharField(max_length=400)), ( "async_migration", - models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="posthog.asyncmigration"), + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + to="posthog.asyncmigration", + ), ), ], ), diff --git a/posthog/migrations/0199_update_experiment_model.py b/posthog/migrations/0199_update_experiment_model.py index dc1d1aa4cf5ff..eac2ce551d81c 100644 --- a/posthog/migrations/0199_update_experiment_model.py +++ b/posthog/migrations/0199_update_experiment_model.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0198_async_migration_error"), ] diff --git a/posthog/migrations/0200_insight_last_modified.py b/posthog/migrations/0200_insight_last_modified.py index 61335edd71dff..6b568c4381480 100644 --- a/posthog/migrations/0200_insight_last_modified.py +++ b/posthog/migrations/0200_insight_last_modified.py @@ -7,7 +7,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0199_update_experiment_model"), ] diff --git a/posthog/migrations/0201_remove_property_type_format_constraint.py b/posthog/migrations/0201_remove_property_type_format_constraint.py index 83435e998f337..4451b2d81b1b7 100644 --- a/posthog/migrations/0201_remove_property_type_format_constraint.py +++ b/posthog/migrations/0201_remove_property_type_format_constraint.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0200_insight_last_modified"), ] diff --git a/posthog/migrations/0202_descriptions_for_action.py b/posthog/migrations/0202_descriptions_for_action.py index d446196299d02..cfda7fdf75f07 100644 --- a/posthog/migrations/0202_descriptions_for_action.py +++ b/posthog/migrations/0202_descriptions_for_action.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0201_remove_property_type_format_constraint"), ] diff --git a/posthog/migrations/0203_dashboard_permissions.py b/posthog/migrations/0203_dashboard_permissions.py index 58936560d68c2..b029b2aeb06f2 100644 --- a/posthog/migrations/0203_dashboard_permissions.py +++ b/posthog/migrations/0203_dashboard_permissions.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0202_descriptions_for_action"), ] diff --git a/posthog/migrations/0204_remove_duplicate_plugin_configs.py b/posthog/migrations/0204_remove_duplicate_plugin_configs.py index c076acc3ef8dd..a9be75e301fe4 100644 --- a/posthog/migrations/0204_remove_duplicate_plugin_configs.py +++ b/posthog/migrations/0204_remove_duplicate_plugin_configs.py @@ -23,7 +23,6 @@ def remove_duplicate_plugin_configs(apps, schema_editor): class Migration(migrations.Migration): - dependencies = [ ("posthog", "0203_dashboard_permissions"), ] diff --git a/posthog/migrations/0205_auto_20220204_1748.py b/posthog/migrations/0205_auto_20220204_1748.py index 8fc138fbd95ea..1b09b6736692b 100644 --- a/posthog/migrations/0205_auto_20220204_1748.py +++ b/posthog/migrations/0205_auto_20220204_1748.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0204_remove_duplicate_plugin_configs"), ] diff --git a/posthog/migrations/0206_global_tags_setup.py b/posthog/migrations/0206_global_tags_setup.py index f977c5106d110..f5927c2baea49 100644 --- a/posthog/migrations/0206_global_tags_setup.py +++ b/posthog/migrations/0206_global_tags_setup.py @@ -7,7 +7,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0205_auto_20220204_1748"), ] @@ -19,11 +18,17 @@ class Migration(migrations.Migration): ( "id", models.UUIDField( - default=posthog.models.utils.UUIDT, editable=False, primary_key=True, serialize=False + default=posthog.models.utils.UUIDT, + editable=False, + primary_key=True, + serialize=False, ), ), ("name", models.CharField(max_length=255)), - ("team", models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="posthog.team")), + ( + "team", + models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="posthog.team"), + ), ], ), migrations.CreateModel( @@ -32,7 +37,10 @@ class Migration(migrations.Migration): ( "id", models.UUIDField( - default=posthog.models.utils.UUIDT, editable=False, primary_key=True, serialize=False + default=posthog.models.utils.UUIDT, + editable=False, + primary_key=True, + serialize=False, ), ), ( @@ -48,7 +56,9 @@ class Migration(migrations.Migration): ( "tag", models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, related_name="tagged_items", to="posthog.tag" + on_delete=django.db.models.deletion.CASCADE, + related_name="tagged_items", + to="posthog.tag", ), ), ], @@ -56,7 +66,8 @@ class Migration(migrations.Migration): migrations.AddConstraint( model_name="taggeditem", constraint=models.CheckConstraint( - check=models.Q(models.Q(("action__isnull", False)), _connector="OR"), name="exactly_one_related_object" + check=models.Q(models.Q(("action__isnull", False)), _connector="OR"), + name="exactly_one_related_object", ), ), migrations.AlterUniqueTogether( diff --git a/posthog/migrations/0207_cohort_count.py b/posthog/migrations/0207_cohort_count.py index 95e985f8c0ec0..794ed5add5ea7 100644 --- a/posthog/migrations/0207_cohort_count.py +++ b/posthog/migrations/0207_cohort_count.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0206_global_tags_setup"), ] diff --git a/posthog/migrations/0208_alter_plugin_updated_at.py b/posthog/migrations/0208_alter_plugin_updated_at.py index 81e0492d6d74d..2e30b98562a35 100644 --- a/posthog/migrations/0208_alter_plugin_updated_at.py +++ b/posthog/migrations/0208_alter_plugin_updated_at.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0207_cohort_count"), ] diff --git a/posthog/migrations/0209_plugin_logs_disabled.py b/posthog/migrations/0209_plugin_logs_disabled.py index 31b8423790ea4..72cbcbb80cbb4 100644 --- a/posthog/migrations/0209_plugin_logs_disabled.py +++ b/posthog/migrations/0209_plugin_logs_disabled.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0208_alter_plugin_updated_at"), ] diff --git a/posthog/migrations/0210_drop_update_person_functions.py b/posthog/migrations/0210_drop_update_person_functions.py index 6d70f4c0cf32b..c036799c5429f 100644 --- a/posthog/migrations/0210_drop_update_person_functions.py +++ b/posthog/migrations/0210_drop_update_person_functions.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0209_plugin_logs_disabled"), ] diff --git a/posthog/migrations/0211_async_migrations_errors_length.py b/posthog/migrations/0211_async_migrations_errors_length.py index 445b85183e7a9..a29e6bd862808 100644 --- a/posthog/migrations/0211_async_migrations_errors_length.py +++ b/posthog/migrations/0211_async_migrations_errors_length.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0210_drop_update_person_functions"), ] diff --git a/posthog/migrations/0212_alter_persondistinctid_team.py b/posthog/migrations/0212_alter_persondistinctid_team.py index 89995547f70db..3f0b7eb908fac 100644 --- a/posthog/migrations/0212_alter_persondistinctid_team.py +++ b/posthog/migrations/0212_alter_persondistinctid_team.py @@ -48,7 +48,9 @@ class Migration(migrations.Migration): model_name="persondistinctid", name="team", field=models.ForeignKey( - db_index=False, on_delete=django.db.models.deletion.CASCADE, to="posthog.team" + db_index=False, + on_delete=django.db.models.deletion.CASCADE, + to="posthog.team", ), ) ], diff --git a/posthog/migrations/0213_deprecated_old_tags.py b/posthog/migrations/0213_deprecated_old_tags.py index d713f0aaa5f45..2efc99288852c 100644 --- a/posthog/migrations/0213_deprecated_old_tags.py +++ b/posthog/migrations/0213_deprecated_old_tags.py @@ -6,7 +6,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0212_alter_persondistinctid_team"), ] @@ -18,14 +17,22 @@ class Migration(migrations.Migration): model_name="dashboard", name="deprecated_tags", field=django.contrib.postgres.fields.ArrayField( - base_field=models.CharField(max_length=32), blank=True, default=list, null=True, size=None + base_field=models.CharField(max_length=32), + blank=True, + default=list, + null=True, + size=None, ), ), migrations.AlterField( model_name="insight", name="deprecated_tags", field=django.contrib.postgres.fields.ArrayField( - base_field=models.CharField(max_length=32), blank=True, default=list, null=True, size=None + base_field=models.CharField(max_length=32), + blank=True, + default=list, + null=True, + size=None, ), ), migrations.RemoveConstraint( @@ -78,7 +85,16 @@ class Migration(migrations.Migration): ), migrations.AlterUniqueTogether( name="taggeditem", - unique_together={("tag", "dashboard", "insight", "event_definition", "property_definition", "action")}, + unique_together={ + ( + "tag", + "dashboard", + "insight", + "event_definition", + "property_definition", + "action", + ) + }, ), migrations.AddConstraint( model_name="taggeditem", diff --git a/posthog/migrations/0215_add_tags_back.py b/posthog/migrations/0215_add_tags_back.py index 0bd14fee6f5ac..bc66b0997cd60 100644 --- a/posthog/migrations/0215_add_tags_back.py +++ b/posthog/migrations/0215_add_tags_back.py @@ -5,7 +5,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0214_migrate_dashboard_insight_tags"), ] @@ -15,14 +14,22 @@ class Migration(migrations.Migration): model_name="dashboard", name="tags", field=django.contrib.postgres.fields.ArrayField( - base_field=models.CharField(max_length=32), blank=True, default=None, null=True, size=None + base_field=models.CharField(max_length=32), + blank=True, + default=None, + null=True, + size=None, ), ), migrations.AddField( model_name="insight", name="tags", field=django.contrib.postgres.fields.ArrayField( - base_field=models.CharField(max_length=32), blank=True, default=None, null=True, size=None + base_field=models.CharField(max_length=32), + blank=True, + default=None, + null=True, + size=None, ), ), ] diff --git a/posthog/migrations/0216_insight_placeholder_name.py b/posthog/migrations/0216_insight_placeholder_name.py index 43e0a93447550..7d5956a0cfbc6 100644 --- a/posthog/migrations/0216_insight_placeholder_name.py +++ b/posthog/migrations/0216_insight_placeholder_name.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0215_add_tags_back"), ] diff --git a/posthog/migrations/0217_team_primary_dashboard.py b/posthog/migrations/0217_team_primary_dashboard.py index 98a8f32763983..cb164adf85455 100644 --- a/posthog/migrations/0217_team_primary_dashboard.py +++ b/posthog/migrations/0217_team_primary_dashboard.py @@ -5,7 +5,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0216_insight_placeholder_name"), ] diff --git a/posthog/migrations/0219_migrate_tags_v2.py b/posthog/migrations/0219_migrate_tags_v2.py index 1895d3b86c59d..ecc4f4312a812 100644 --- a/posthog/migrations/0219_migrate_tags_v2.py +++ b/posthog/migrations/0219_migrate_tags_v2.py @@ -33,7 +33,11 @@ def forwards(apps, schema_editor): ) for insight_page in insight_paginator.page_range: - logger.info("insight_tag_batch_get_start", limit=batch_size, offset=(insight_page - 1) * batch_size) + logger.info( + "insight_tag_batch_get_start", + limit=batch_size, + offset=(insight_page - 1) * batch_size, + ) insights = iter(insight_paginator.get_page(insight_page)) for tags, team_id, insight_id in insights: unique_tags = set(tagify(t) for t in tags if isinstance(t, str) and t.strip() != "") @@ -55,13 +59,22 @@ def forwards(apps, schema_editor): ) for dashboard_page in dashboard_paginator.page_range: - logger.info("dashboard_tag_batch_get_start", limit=batch_size, offset=(dashboard_page - 1) * batch_size) + logger.info( + "dashboard_tag_batch_get_start", + limit=batch_size, + offset=(dashboard_page - 1) * batch_size, + ) dashboards = iter(dashboard_paginator.get_page(dashboard_page)) for tags, team_id, dashboard_id in dashboards: unique_tags = set(tagify(t) for t in tags if isinstance(t, str) and t.strip() != "") for tag in unique_tags: temp_tag = Tag(name=tag, team_id=team_id) - createables.append((temp_tag, TaggedItem(dashboard_id=dashboard_id, tag_id=temp_tag.id))) + createables.append( + ( + temp_tag, + TaggedItem(dashboard_id=dashboard_id, tag_id=temp_tag.id), + ) + ) logger.info("dashboard_tag_get_end", tags_count=len(createables) - num_insight_tags) @@ -94,7 +107,9 @@ def forwards(apps, schema_editor): # Create tag <-> item relationships, ignoring conflicts TaggedItem.objects.bulk_create( - [tagged_item for (_, tagged_item) in createable_batch], ignore_conflicts=True, batch_size=batch_size + [tagged_item for (_, tagged_item) in createable_batch], + ignore_conflicts=True, + batch_size=batch_size, ) logger.info("posthog/0219_migrate_tags_v2_end") diff --git a/posthog/migrations/0220_backfill_primary_dashboards.py b/posthog/migrations/0220_backfill_primary_dashboards.py index 4633c81b90bbf..f32def59bc25c 100644 --- a/posthog/migrations/0220_backfill_primary_dashboards.py +++ b/posthog/migrations/0220_backfill_primary_dashboards.py @@ -10,7 +10,6 @@ def backfill_primary_dashboards(apps, _): team_dashboards = [] with connection.cursor() as cursor: - # Fetch a list of teams and the id of the dashboard that should be set as the primary dashboard # The primary dashboard should be the oldest pinned dashboard, if one exists # or the oldest dashboard, if no pinned dashboards exist diff --git a/posthog/migrations/0221_add_activity_log_model.py b/posthog/migrations/0221_add_activity_log_model.py index dda3d6001c30a..077951fbfda0f 100644 --- a/posthog/migrations/0221_add_activity_log_model.py +++ b/posthog/migrations/0221_add_activity_log_model.py @@ -10,7 +10,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0220_backfill_primary_dashboards"), ] @@ -22,7 +21,10 @@ class Migration(migrations.Migration): ( "id", models.UUIDField( - default=posthog.models.utils.UUIDT, editable=False, primary_key=True, serialize=False + default=posthog.models.utils.UUIDT, + editable=False, + primary_key=True, + serialize=False, ), ), ("team_id", models.PositiveIntegerField(null=True)), @@ -33,26 +35,36 @@ class Migration(migrations.Migration): ( "detail", models.JSONField( - encoder=posthog.models.activity_logging.activity_log.ActivityDetailEncoder, null=True + encoder=posthog.models.activity_logging.activity_log.ActivityDetailEncoder, + null=True, ), ), ("created_at", models.DateTimeField(default=django.utils.timezone.now)), ( "user", models.ForeignKey( - null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL + null=True, + on_delete=django.db.models.deletion.SET_NULL, + to=settings.AUTH_USER_MODEL, ), ), ], ), migrations.AddIndex( model_name="activitylog", - index=models.Index(fields=["team_id", "scope", "item_id"], name="posthog_act_team_id_13a0a8_idx"), + index=models.Index( + fields=["team_id", "scope", "item_id"], + name="posthog_act_team_id_13a0a8_idx", + ), ), migrations.AddConstraint( model_name="activitylog", constraint=models.CheckConstraint( - check=models.Q(("team_id__isnull", False), ("organization_id__isnull", False), _connector="OR"), + check=models.Q( + ("team_id__isnull", False), + ("organization_id__isnull", False), + _connector="OR", + ), name="must_have_team_or_organization_id", ), ), diff --git a/posthog/migrations/0222_fix_deleted_primary_dashboards.py b/posthog/migrations/0222_fix_deleted_primary_dashboards.py index 7869597e61475..a65df9e39f2f7 100644 --- a/posthog/migrations/0222_fix_deleted_primary_dashboards.py +++ b/posthog/migrations/0222_fix_deleted_primary_dashboards.py @@ -15,7 +15,6 @@ def fix_for_deleted_primary_dashboards(apps, _): expected_team_dashboards = [] with connection.cursor() as cursor: - # Fetch a list of teams and the id of the dashboard that should be set as the primary dashboard # The primary dashboard should be the oldest pinned dashboard, if one exists # or the oldest dashboard, if no pinned dashboards exist diff --git a/posthog/migrations/0223_organizationdomain.py b/posthog/migrations/0223_organizationdomain.py index 30cef1aca53a0..c46349689ff69 100644 --- a/posthog/migrations/0223_organizationdomain.py +++ b/posthog/migrations/0223_organizationdomain.py @@ -15,12 +15,14 @@ def migrate_domain_whitelist(apps, schema_editor): for organization in Organization.objects.exclude(domain_whitelist=[]): for domain in organization.domain_whitelist: OrganizationDomain.objects.create( - organization=organization, domain=domain, verified_at=timezone.now(), jit_provisioning_enabled=True + organization=organization, + domain=domain, + verified_at=timezone.now(), + jit_provisioning_enabled=True, ) class Migration(migrations.Migration): - dependencies = [ ("posthog", "0222_fix_deleted_primary_dashboards"), ] @@ -32,18 +34,28 @@ class Migration(migrations.Migration): ( "id", models.UUIDField( - default=posthog.models.utils.UUIDT, editable=False, primary_key=True, serialize=False + default=posthog.models.utils.UUIDT, + editable=False, + primary_key=True, + serialize=False, ), ), ("domain", models.CharField(max_length=128, unique=True)), ( "verification_challenge", models.CharField( - default=posthog.models.organization_domain.generate_verification_challenge, max_length=128 + default=posthog.models.organization_domain.generate_verification_challenge, + max_length=128, ), ), - ("verified_at", models.DateTimeField(blank=True, default=None, null=True)), - ("last_verification_retry", models.DateTimeField(blank=True, default=None, null=True)), + ( + "verified_at", + models.DateTimeField(blank=True, default=None, null=True), + ), + ( + "last_verification_retry", + models.DateTimeField(blank=True, default=None, null=True), + ), ( "jit_provisioning_enabled", models.BooleanField(default=False), @@ -52,7 +64,9 @@ class Migration(migrations.Migration): ( "organization", models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, related_name="domains", to="posthog.organization" + on_delete=django.db.models.deletion.CASCADE, + related_name="domains", + to="posthog.organization", ), ), ], diff --git a/posthog/migrations/0224_saml_multitenant.py b/posthog/migrations/0224_saml_multitenant.py index 2f942a4caf0d2..b2813acd95827 100644 --- a/posthog/migrations/0224_saml_multitenant.py +++ b/posthog/migrations/0224_saml_multitenant.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0223_organizationdomain"), ] diff --git a/posthog/migrations/0225_insight_viewed.py b/posthog/migrations/0225_insight_viewed.py index e0f1b58456766..7d4195a4fb681 100644 --- a/posthog/migrations/0225_insight_viewed.py +++ b/posthog/migrations/0225_insight_viewed.py @@ -6,7 +6,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0224_saml_multitenant"), ] @@ -15,16 +14,42 @@ class Migration(migrations.Migration): migrations.CreateModel( name="InsightViewed", fields=[ - ("id", models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), ("last_viewed_at", models.DateTimeField()), - ("insight", models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="posthog.insight")), - ("team", models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="posthog.team")), - ("user", models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), + ( + "insight", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + to="posthog.insight", + ), + ), + ( + "team", + models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="posthog.team"), + ), + ( + "user", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + to=settings.AUTH_USER_MODEL, + ), + ), ], ), migrations.AddIndex( model_name="insightviewed", - index=models.Index(fields=["team_id", "user_id", "-last_viewed_at"], name="posthog_ins_team_id_339ee0_idx"), + index=models.Index( + fields=["team_id", "user_id", "-last_viewed_at"], + name="posthog_ins_team_id_339ee0_idx", + ), ), migrations.AddConstraint( model_name="insightviewed", diff --git a/posthog/migrations/0226_longer_action_slack_message_format.py b/posthog/migrations/0226_longer_action_slack_message_format.py index 8f6a1968f2492..b6d0d5d448ecf 100644 --- a/posthog/migrations/0226_longer_action_slack_message_format.py +++ b/posthog/migrations/0226_longer_action_slack_message_format.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0225_insight_viewed"), ] diff --git a/posthog/migrations/0227_add_dashboard_tiles.py b/posthog/migrations/0227_add_dashboard_tiles.py index 88e2258ca455f..5ced1caad6326 100644 --- a/posthog/migrations/0227_add_dashboard_tiles.py +++ b/posthog/migrations/0227_add_dashboard_tiles.py @@ -58,7 +58,6 @@ def reverse(apps, _) -> None: class Migration(migrations.Migration): - dependencies = [ ("posthog", "0226_longer_action_slack_message_format"), ] @@ -67,9 +66,23 @@ class Migration(migrations.Migration): migrations.CreateModel( name="DashboardTile", fields=[ - ("id", models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), - ("dashboard", models.ForeignKey(on_delete=models.deletion.CASCADE, to="posthog.dashboard")), - ("insight", models.ForeignKey(on_delete=models.deletion.CASCADE, to="posthog.insight")), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ( + "dashboard", + models.ForeignKey(on_delete=models.deletion.CASCADE, to="posthog.dashboard"), + ), + ( + "insight", + models.ForeignKey(on_delete=models.deletion.CASCADE, to="posthog.insight"), + ), ("layouts", models.JSONField(default=dict)), ("color", models.CharField(blank=True, max_length=400, null=True)), ], @@ -78,7 +91,10 @@ class Migration(migrations.Migration): model_name="dashboard", name="insights", field=models.ManyToManyField( - blank=True, related_name="dashboards", through="posthog.DashboardTile", to="posthog.Insight" + blank=True, + related_name="dashboards", + through="posthog.DashboardTile", + to="posthog.Insight", ), ), migrations.RunPython(migrate_dashboard_insight_relations, reverse, elidable=True), diff --git a/posthog/migrations/0228_fix_tile_layouts.py b/posthog/migrations/0228_fix_tile_layouts.py index bea976781fe8b..f819390449f04 100644 --- a/posthog/migrations/0228_fix_tile_layouts.py +++ b/posthog/migrations/0228_fix_tile_layouts.py @@ -42,7 +42,6 @@ def migrate_dashboard_insight_relations(apps, _) -> None: class Migration(migrations.Migration): - dependencies = [ ("posthog", "0227_add_dashboard_tiles"), ] diff --git a/posthog/migrations/0229_add_filters_hash_to_dashboard_table.py b/posthog/migrations/0229_add_filters_hash_to_dashboard_table.py index fdb078043a99a..7bbd818dbbafa 100644 --- a/posthog/migrations/0229_add_filters_hash_to_dashboard_table.py +++ b/posthog/migrations/0229_add_filters_hash_to_dashboard_table.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0228_fix_tile_layouts"), ] diff --git a/posthog/migrations/0230_cohort_filters.py b/posthog/migrations/0230_cohort_filters.py index 96dff620cea4c..c695d413372eb 100644 --- a/posthog/migrations/0230_cohort_filters.py +++ b/posthog/migrations/0230_cohort_filters.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0229_add_filters_hash_to_dashboard_table"), ] diff --git a/posthog/migrations/0231_add_refreshing_data_to_tiles.py b/posthog/migrations/0231_add_refreshing_data_to_tiles.py index 90e4171ba8f65..18a31765beead 100644 --- a/posthog/migrations/0231_add_refreshing_data_to_tiles.py +++ b/posthog/migrations/0231_add_refreshing_data_to_tiles.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0230_cohort_filters"), ] diff --git a/posthog/migrations/0232_add_team_person_display_name_properties.py b/posthog/migrations/0232_add_team_person_display_name_properties.py index 1508ea860d7ed..56402418d2a46 100644 --- a/posthog/migrations/0232_add_team_person_display_name_properties.py +++ b/posthog/migrations/0232_add_team_person_display_name_properties.py @@ -5,7 +5,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0231_add_refreshing_data_to_tiles"), ] @@ -15,7 +14,10 @@ class Migration(migrations.Migration): model_name="team", name="person_display_name_properties", field=django.contrib.postgres.fields.ArrayField( - base_field=models.CharField(max_length=400), blank=True, null=True, size=None + base_field=models.CharField(max_length=400), + blank=True, + null=True, + size=None, ), ), ] diff --git a/posthog/migrations/0233_plugin_source_file.py b/posthog/migrations/0233_plugin_source_file.py index 2686bb99ca8bc..0e5a13827425a 100644 --- a/posthog/migrations/0233_plugin_source_file.py +++ b/posthog/migrations/0233_plugin_source_file.py @@ -33,7 +33,6 @@ def migrate_plugin_source(apps, schema_editor): class Migration(migrations.Migration): - dependencies = [ ("posthog", "0232_add_team_person_display_name_properties"), ] @@ -45,12 +44,18 @@ class Migration(migrations.Migration): ( "id", models.UUIDField( - default=posthog.models.utils.UUIDT, editable=False, primary_key=True, serialize=False + default=posthog.models.utils.UUIDT, + editable=False, + primary_key=True, + serialize=False, ), ), ("filename", models.CharField(max_length=200)), ("source", models.TextField(blank=True, null=True)), - ("plugin", models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="posthog.plugin")), + ( + "plugin", + models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="posthog.plugin"), + ), ], ), migrations.AddConstraint( diff --git a/posthog/migrations/0234_create_plugin_jsons.py b/posthog/migrations/0234_create_plugin_jsons.py index 6d6e3420efbb5..36b12068613e3 100644 --- a/posthog/migrations/0234_create_plugin_jsons.py +++ b/posthog/migrations/0234_create_plugin_jsons.py @@ -27,7 +27,6 @@ def migrate_plugin_source(apps, schema_editor): class Migration(migrations.Migration): - dependencies = [ ("posthog", "0233_plugin_source_file"), ] diff --git a/posthog/migrations/0235_plugin_source_transpilation.py b/posthog/migrations/0235_plugin_source_transpilation.py index 767db8bd4fd6b..a657113cf57ce 100644 --- a/posthog/migrations/0235_plugin_source_transpilation.py +++ b/posthog/migrations/0235_plugin_source_transpilation.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0234_create_plugin_jsons"), ] @@ -20,7 +19,11 @@ class Migration(migrations.Migration): name="status", field=models.CharField( null=True, - choices=[("LOCKED", "locked"), ("TRANSPILED", "transpiled"), ("ERROR", "error")], + choices=[ + ("LOCKED", "locked"), + ("TRANSPILED", "transpiled"), + ("ERROR", "error"), + ], max_length=20, ), ), diff --git a/posthog/migrations/0236_add_instance_setting_model.py b/posthog/migrations/0236_add_instance_setting_model.py index b42aa22cba4da..f41fae6f6f5fd 100644 --- a/posthog/migrations/0236_add_instance_setting_model.py +++ b/posthog/migrations/0236_add_instance_setting_model.py @@ -33,7 +33,15 @@ class Migration(migrations.Migration): migrations.CreateModel( name="InstanceSetting", fields=[ - ("id", models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), ("key", models.CharField(max_length=128)), ("raw_value", models.CharField(blank=True, max_length=1024)), ], diff --git a/posthog/migrations/0237_remove_timezone_from_teams.py b/posthog/migrations/0237_remove_timezone_from_teams.py index 4bd8f99cf24c4..e4ff58e555d6d 100644 --- a/posthog/migrations/0237_remove_timezone_from_teams.py +++ b/posthog/migrations/0237_remove_timezone_from_teams.py @@ -8,7 +8,6 @@ def reset_team_timezone_to_UTC(apps, _) -> None: class Migration(migrations.Migration): - dependencies = [ ("posthog", "0236_add_instance_setting_model"), ] diff --git a/posthog/migrations/0238_exportedasset.py b/posthog/migrations/0238_exportedasset.py index 92eef7b7faefa..f1ace97313135 100644 --- a/posthog/migrations/0238_exportedasset.py +++ b/posthog/migrations/0238_exportedasset.py @@ -7,7 +7,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0237_remove_timezone_from_teams"), ] @@ -16,7 +15,15 @@ class Migration(migrations.Migration): migrations.CreateModel( name="ExportedAsset", fields=[ - ("id", models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), ( "export_format", models.CharField( @@ -41,13 +48,24 @@ class Migration(migrations.Migration): ), ( "dashboard", - models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to="posthog.dashboard"), + models.ForeignKey( + null=True, + on_delete=django.db.models.deletion.CASCADE, + to="posthog.dashboard", + ), ), ( "insight", - models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to="posthog.insight"), + models.ForeignKey( + null=True, + on_delete=django.db.models.deletion.CASCADE, + to="posthog.insight", + ), + ), + ( + "team", + models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="posthog.team"), ), - ("team", models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="posthog.team")), ], ), ] diff --git a/posthog/migrations/0239_delete_postgres_pluginlogentry.py b/posthog/migrations/0239_delete_postgres_pluginlogentry.py index 34dc7a34ca8c8..4161c47e28212 100644 --- a/posthog/migrations/0239_delete_postgres_pluginlogentry.py +++ b/posthog/migrations/0239_delete_postgres_pluginlogentry.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0238_exportedasset"), ] diff --git a/posthog/migrations/0240_organizationinvite_message.py b/posthog/migrations/0240_organizationinvite_message.py index 17cf1a9c22a06..cefc8aa46b5f9 100644 --- a/posthog/migrations/0240_organizationinvite_message.py +++ b/posthog/migrations/0240_organizationinvite_message.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0239_delete_postgres_pluginlogentry"), ] diff --git a/posthog/migrations/0241_subscription.py b/posthog/migrations/0241_subscription.py index 5c85060da6553..8d00dbef43f2d 100644 --- a/posthog/migrations/0241_subscription.py +++ b/posthog/migrations/0241_subscription.py @@ -7,7 +7,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0240_organizationinvite_message"), ] @@ -16,9 +15,20 @@ class Migration(migrations.Migration): migrations.CreateModel( name="Subscription", fields=[ - ("id", models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), ("title", models.CharField(blank=True, max_length=100, null=True)), - ("target_type", models.CharField(choices=[("email", "Email")], max_length=10)), + ( + "target_type", + models.CharField(choices=[("email", "Email")], max_length=10), + ), ("target_value", models.TextField()), ( "frequency", @@ -64,18 +74,32 @@ class Migration(migrations.Migration): ( "created_by", models.ForeignKey( - blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + to=settings.AUTH_USER_MODEL, ), ), ( "dashboard", - models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to="posthog.dashboard"), + models.ForeignKey( + null=True, + on_delete=django.db.models.deletion.CASCADE, + to="posthog.dashboard", + ), ), ( "insight", - models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to="posthog.insight"), + models.ForeignKey( + null=True, + on_delete=django.db.models.deletion.CASCADE, + to="posthog.insight", + ), + ), + ( + "team", + models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="posthog.team"), ), - ("team", models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="posthog.team")), ], ), ] diff --git a/posthog/migrations/0242_team_live_events_columns.py b/posthog/migrations/0242_team_live_events_columns.py index 8dee3fe2fd900..e29c482738406 100644 --- a/posthog/migrations/0242_team_live_events_columns.py +++ b/posthog/migrations/0242_team_live_events_columns.py @@ -5,7 +5,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0241_subscription"), ] diff --git a/posthog/migrations/0243_unpack_plugin_source_files.py b/posthog/migrations/0243_unpack_plugin_source_files.py index d0e10ef482302..58aac54e753a9 100644 --- a/posthog/migrations/0243_unpack_plugin_source_files.py +++ b/posthog/migrations/0243_unpack_plugin_source_files.py @@ -56,7 +56,9 @@ def sync_from_plugin_archive(plugin): ) else: logger.debug( - "Migration 0243 - extracted and saved code of plugin.", plugin=plugin.name, plugin_id=plugin.id + "Migration 0243 - extracted and saved code of plugin.", + plugin=plugin.name, + plugin_id=plugin.id, ) logger.info("Migration 0243 - finished") @@ -70,7 +72,6 @@ def reverse_func(apps, schema_editor): class Migration(migrations.Migration): - dependencies = [ ("posthog", "0242_team_live_events_columns"), ] diff --git a/posthog/migrations/0244_drop_should_update_person_prop.py b/posthog/migrations/0244_drop_should_update_person_prop.py index 40dc0f451e916..210e46ce4d36d 100644 --- a/posthog/migrations/0244_drop_should_update_person_prop.py +++ b/posthog/migrations/0244_drop_should_update_person_prop.py @@ -2,7 +2,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0243_unpack_plugin_source_files"), ] diff --git a/posthog/migrations/0245_silence_deprecated_tags_warnings.py b/posthog/migrations/0245_silence_deprecated_tags_warnings.py index f39278900d75c..56c2a042db092 100644 --- a/posthog/migrations/0245_silence_deprecated_tags_warnings.py +++ b/posthog/migrations/0245_silence_deprecated_tags_warnings.py @@ -5,7 +5,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0244_drop_should_update_person_prop"), ] diff --git a/posthog/migrations/0246_integrations.py b/posthog/migrations/0246_integrations.py index d80dd3e6040d7..9bc1f0cb4b6eb 100644 --- a/posthog/migrations/0246_integrations.py +++ b/posthog/migrations/0246_integrations.py @@ -6,7 +6,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0245_silence_deprecated_tags_warnings"), ] @@ -16,13 +15,26 @@ class Migration(migrations.Migration): model_name="subscription", name="target_type", field=models.CharField( - choices=[("email", "Email"), ("slack", "Slack"), ("webhook", "Webhook")], max_length=10 + choices=[ + ("email", "Email"), + ("slack", "Slack"), + ("webhook", "Webhook"), + ], + max_length=10, ), ), migrations.CreateModel( name="Integration", fields=[ - ("id", models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), ("kind", models.CharField(choices=[("slack", "Slack")], max_length=10)), ("config", models.JSONField(default=dict)), ("sensitive_config", models.JSONField(default=dict)), @@ -31,10 +43,16 @@ class Migration(migrations.Migration): ( "created_by", models.ForeignKey( - blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + to=settings.AUTH_USER_MODEL, ), ), - ("team", models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="posthog.team")), + ( + "team", + models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="posthog.team"), + ), ], ), ] diff --git a/posthog/migrations/0247_feature_flags_experience_continuity.py b/posthog/migrations/0247_feature_flags_experience_continuity.py index 31a5c471c1fdb..f23365acf60fe 100644 --- a/posthog/migrations/0247_feature_flags_experience_continuity.py +++ b/posthog/migrations/0247_feature_flags_experience_continuity.py @@ -5,7 +5,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0246_integrations"), ] @@ -19,17 +18,32 @@ class Migration(migrations.Migration): migrations.CreateModel( name="FeatureFlagHashKeyOverride", fields=[ - ("id", models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), ("feature_flag_key", models.CharField(max_length=400)), ("hash_key", models.CharField(max_length=400)), - ("person", models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="posthog.person")), - ("team", models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="posthog.team")), + ( + "person", + models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="posthog.person"), + ), + ( + "team", + models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="posthog.team"), + ), ], ), migrations.AddConstraint( model_name="featureflaghashkeyoverride", constraint=models.UniqueConstraint( - fields=("team", "person", "feature_flag_key"), name="Unique hash_key for a user/team/feature_flag combo" + fields=("team", "person", "feature_flag_key"), + name="Unique hash_key for a user/team/feature_flag combo", ), ), ] diff --git a/posthog/migrations/0248_add_context_for_csv_exports.py b/posthog/migrations/0248_add_context_for_csv_exports.py index ad5891165b54e..9b86fee68a8f2 100644 --- a/posthog/migrations/0248_add_context_for_csv_exports.py +++ b/posthog/migrations/0248_add_context_for_csv_exports.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0247_feature_flags_experience_continuity"), ] diff --git a/posthog/migrations/0249_add_sharingconfiguration.py b/posthog/migrations/0249_add_sharingconfiguration.py index 8ee425789c583..ad3f6ccf209f3 100644 --- a/posthog/migrations/0249_add_sharingconfiguration.py +++ b/posthog/migrations/0249_add_sharingconfiguration.py @@ -29,7 +29,6 @@ def reverse(apps, schema_editor): class Migration(migrations.Migration): - dependencies = [ ("posthog", "0248_add_context_for_csv_exports"), ] @@ -38,7 +37,15 @@ class Migration(migrations.Migration): migrations.CreateModel( name="SharingConfiguration", fields=[ - ("id", models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), ("created_at", models.DateTimeField(auto_now_add=True)), ("enabled", models.BooleanField(default=False)), ( @@ -53,13 +60,24 @@ class Migration(migrations.Migration): ), ( "dashboard", - models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to="posthog.dashboard"), + models.ForeignKey( + null=True, + on_delete=django.db.models.deletion.CASCADE, + to="posthog.dashboard", + ), ), ( "insight", - models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to="posthog.insight"), + models.ForeignKey( + null=True, + on_delete=django.db.models.deletion.CASCADE, + to="posthog.insight", + ), + ), + ( + "team", + models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="posthog.team"), ), - ("team", models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="posthog.team")), ], ), migrations.RunPython(create_sharing_configurations, reverse, elidable=True), diff --git a/posthog/migrations/0250_exportedasset_created_by.py b/posthog/migrations/0250_exportedasset_created_by.py index e0f21ea5a447e..72a9984ab53fd 100644 --- a/posthog/migrations/0250_exportedasset_created_by.py +++ b/posthog/migrations/0250_exportedasset_created_by.py @@ -6,7 +6,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0249_add_sharingconfiguration"), ] @@ -16,7 +15,10 @@ class Migration(migrations.Migration): model_name="exportedasset", name="created_by", field=models.ForeignKey( - blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + to=settings.AUTH_USER_MODEL, ), ), ] diff --git a/posthog/migrations/0251_event_buffer.py b/posthog/migrations/0251_event_buffer.py index af6b8f3b105b6..c0323f3057ce8 100644 --- a/posthog/migrations/0251_event_buffer.py +++ b/posthog/migrations/0251_event_buffer.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0250_exportedasset_created_by"), ] @@ -13,7 +12,15 @@ class Migration(migrations.Migration): migrations.CreateModel( name="EventBuffer", fields=[ - ("id", models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), ("event", models.JSONField(null=True, blank=True)), ("process_at", models.DateTimeField()), ("locked", models.BooleanField()), diff --git a/posthog/migrations/0252_reset_insight_refreshing_status.py b/posthog/migrations/0252_reset_insight_refreshing_status.py index 140128632f575..abfef85709b30 100644 --- a/posthog/migrations/0252_reset_insight_refreshing_status.py +++ b/posthog/migrations/0252_reset_insight_refreshing_status.py @@ -16,7 +16,6 @@ def reverse(_apps, _schema_editor) -> None: class Migration(migrations.Migration): - dependencies = [ ("posthog", "0251_event_buffer"), ] diff --git a/posthog/migrations/0253_add_async_migration_parameters.py b/posthog/migrations/0253_add_async_migration_parameters.py index a81e43700dee4..d96735c67c483 100644 --- a/posthog/migrations/0253_add_async_migration_parameters.py +++ b/posthog/migrations/0253_add_async_migration_parameters.py @@ -10,7 +10,6 @@ def describe(self): class Migration(migrations.Migration): - dependencies = [ ("posthog", "0252_reset_insight_refreshing_status"), ] diff --git a/posthog/migrations/0254_prompt_sequence_state.py b/posthog/migrations/0254_prompt_sequence_state.py index 94b920a964a8a..e10e4a2530b4d 100644 --- a/posthog/migrations/0254_prompt_sequence_state.py +++ b/posthog/migrations/0254_prompt_sequence_state.py @@ -6,7 +6,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0253_add_async_migration_parameters"), ] @@ -15,20 +14,38 @@ class Migration(migrations.Migration): migrations.CreateModel( name="PromptSequenceState", fields=[ - ("id", models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), ("key", models.CharField(max_length=400)), - ("last_updated_at", models.DateTimeField(default=django.utils.timezone.now)), + ( + "last_updated_at", + models.DateTimeField(default=django.utils.timezone.now), + ), ("step", models.IntegerField(default=0)), ("completed", models.BooleanField(default=False)), ("dismissed", models.BooleanField(default=False)), - ("person", models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="posthog.person")), - ("team", models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="posthog.team")), + ( + "person", + models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="posthog.person"), + ), + ( + "team", + models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="posthog.team"), + ), ], ), migrations.AddConstraint( model_name="promptsequencestate", constraint=models.UniqueConstraint( - fields=("team", "person", "key"), name="unique sequence key for person for team" + fields=("team", "person", "key"), + name="unique sequence key for person for team", ), ), ] diff --git a/posthog/migrations/0255_user_prompt_sequence_state.py b/posthog/migrations/0255_user_prompt_sequence_state.py index 9c1d2ec48f7fe..ebfe3dc5e6363 100644 --- a/posthog/migrations/0255_user_prompt_sequence_state.py +++ b/posthog/migrations/0255_user_prompt_sequence_state.py @@ -7,7 +7,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0254_prompt_sequence_state"), ] @@ -16,13 +15,30 @@ class Migration(migrations.Migration): migrations.CreateModel( name="UserPromptSequenceState", fields=[ - ("id", models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), ("key", models.CharField(max_length=400)), - ("last_updated_at", models.DateTimeField(default=django.utils.timezone.now)), + ( + "last_updated_at", + models.DateTimeField(default=django.utils.timezone.now), + ), ("step", models.IntegerField(default=0)), ("completed", models.BooleanField(default=False)), ("dismissed", models.BooleanField(default=False)), - ("user", models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), + ( + "user", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + to=settings.AUTH_USER_MODEL, + ), + ), ], ), migrations.AddConstraint( diff --git a/posthog/migrations/0256_add_async_deletion_model.py b/posthog/migrations/0256_add_async_deletion_model.py index dcc035f70bc08..636fe554b15d5 100644 --- a/posthog/migrations/0256_add_async_deletion_model.py +++ b/posthog/migrations/0256_add_async_deletion_model.py @@ -6,7 +6,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0255_user_prompt_sequence_state"), ] @@ -24,10 +23,15 @@ class Migration(migrations.Migration): ( "created_by", models.ForeignKey( - null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL + null=True, + on_delete=django.db.models.deletion.SET_NULL, + to=settings.AUTH_USER_MODEL, ), ), - ("team", models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="posthog.team")), + ( + "team", + models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="posthog.team"), + ), ], ), migrations.AddIndex( @@ -45,7 +49,8 @@ class Migration(migrations.Migration): migrations.AddConstraint( model_name="asyncdeletion", constraint=models.UniqueConstraint( - fields=("deletion_type", "key", "group_type_index"), name="unique deletion for groups" + fields=("deletion_type", "key", "group_type_index"), + name="unique deletion for groups", ), ), ] diff --git a/posthog/migrations/0257_add_default_checked_for_test_filters_on_team.py b/posthog/migrations/0257_add_default_checked_for_test_filters_on_team.py index ccf6d725f15a3..b513fb4713dd5 100644 --- a/posthog/migrations/0257_add_default_checked_for_test_filters_on_team.py +++ b/posthog/migrations/0257_add_default_checked_for_test_filters_on_team.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0256_add_async_deletion_model"), ] diff --git a/posthog/migrations/0258_team_recording_domains.py b/posthog/migrations/0258_team_recording_domains.py index 510cf5500bb26..9ae7931f1048a 100644 --- a/posthog/migrations/0258_team_recording_domains.py +++ b/posthog/migrations/0258_team_recording_domains.py @@ -3,7 +3,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0257_add_default_checked_for_test_filters_on_team"), ] @@ -13,7 +12,10 @@ class Migration(migrations.Migration): model_name="team", name="recording_domains", field=django.contrib.postgres.fields.ArrayField( - base_field=models.CharField(max_length=200, null=True), blank=True, null=True, size=None + base_field=models.CharField(max_length=200, null=True), + blank=True, + null=True, + size=None, ), ), ] diff --git a/posthog/migrations/0259_backfill_team_recording_domains.py b/posthog/migrations/0259_backfill_team_recording_domains.py index 8589dcc83de02..1f0dcba4f08f8 100644 --- a/posthog/migrations/0259_backfill_team_recording_domains.py +++ b/posthog/migrations/0259_backfill_team_recording_domains.py @@ -45,7 +45,6 @@ def reverse(apps, _): class Migration(migrations.Migration): - dependencies = [ ("posthog", "0258_team_recording_domains"), ] diff --git a/posthog/migrations/0260_pak_v2.py b/posthog/migrations/0260_pak_v2.py index abd6b490b303c..02fbd842ed39a 100644 --- a/posthog/migrations/0260_pak_v2.py +++ b/posthog/migrations/0260_pak_v2.py @@ -20,7 +20,6 @@ def hash_all_keys(apps, schema_editor): class Migration(migrations.Migration): - dependencies = [ ("posthog", "0259_backfill_team_recording_domains"), ] diff --git a/posthog/migrations/0261_team_capture_console_log_opt_in.py b/posthog/migrations/0261_team_capture_console_log_opt_in.py index 9bca3ca244582..92f202606cea9 100644 --- a/posthog/migrations/0261_team_capture_console_log_opt_in.py +++ b/posthog/migrations/0261_team_capture_console_log_opt_in.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0260_pak_v2"), ] diff --git a/posthog/migrations/0262_track_viewed_notifications.py b/posthog/migrations/0262_track_viewed_notifications.py index 441d6472514f2..a333ce35688ea 100644 --- a/posthog/migrations/0262_track_viewed_notifications.py +++ b/posthog/migrations/0262_track_viewed_notifications.py @@ -8,7 +8,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0261_team_capture_console_log_opt_in"), ] @@ -20,14 +19,19 @@ class Migration(migrations.Migration): ( "id", models.UUIDField( - default=posthog.models.utils.UUIDT, editable=False, primary_key=True, serialize=False + default=posthog.models.utils.UUIDT, + editable=False, + primary_key=True, + serialize=False, ), ), ("last_viewed_activity_date", models.DateTimeField(default=None)), ( "user", models.ForeignKey( - null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL + null=True, + on_delete=django.db.models.deletion.SET_NULL, + to=settings.AUTH_USER_MODEL, ), ), ], diff --git a/posthog/migrations/0263_plugin_config_web_token.py b/posthog/migrations/0263_plugin_config_web_token.py index 1600ef55c4f5d..79aabbaf0d3c9 100644 --- a/posthog/migrations/0263_plugin_config_web_token.py +++ b/posthog/migrations/0263_plugin_config_web_token.py @@ -14,7 +14,6 @@ def forwards_func(apps, schema_editor): class Migration(migrations.Migration): - dependencies = [ ("posthog", "0262_track_viewed_notifications"), ] diff --git a/posthog/migrations/0264_user_partial_notification_settings.py b/posthog/migrations/0264_user_partial_notification_settings.py index 53984cb854b21..c8f8b9c727fd8 100644 --- a/posthog/migrations/0264_user_partial_notification_settings.py +++ b/posthog/migrations/0264_user_partial_notification_settings.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0263_plugin_config_web_token"), ] diff --git a/posthog/migrations/0265_related_tiles.py b/posthog/migrations/0265_related_tiles.py index a161e58ec4d6e..55a5958054c00 100644 --- a/posthog/migrations/0265_related_tiles.py +++ b/posthog/migrations/0265_related_tiles.py @@ -5,7 +5,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0264_user_partial_notification_settings"), ] @@ -16,7 +15,9 @@ class Migration(migrations.Migration): model_name="dashboardtile", name="dashboard", field=models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, related_name="tiles", to="posthog.dashboard" + on_delete=django.db.models.deletion.CASCADE, + related_name="tiles", + to="posthog.dashboard", ), ), ] diff --git a/posthog/migrations/0266_add_is_system_field_to_activity_log.py b/posthog/migrations/0266_add_is_system_field_to_activity_log.py index 539307c29a4db..b6716d09b3c55 100644 --- a/posthog/migrations/0266_add_is_system_field_to_activity_log.py +++ b/posthog/migrations/0266_add_is_system_field_to_activity_log.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0265_related_tiles"), ] diff --git a/posthog/migrations/0267_add_text_tiles.py b/posthog/migrations/0267_add_text_tiles.py index 808f7020e6500..b33ffea3d4905 100644 --- a/posthog/migrations/0267_add_text_tiles.py +++ b/posthog/migrations/0267_add_text_tiles.py @@ -7,7 +7,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0266_add_is_system_field_to_activity_log"), ] @@ -16,9 +15,20 @@ class Migration(migrations.Migration): migrations.CreateModel( name="Text", fields=[ - ("id", models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), ("body", models.CharField(blank=True, max_length=4000, null=True)), - ("last_modified_at", models.DateTimeField(default=django.utils.timezone.now)), + ( + "last_modified_at", + models.DateTimeField(default=django.utils.timezone.now), + ), ], ), # allow null and add related name to the field @@ -36,7 +46,10 @@ class Migration(migrations.Migration): model_name="text", name="created_by", field=models.ForeignKey( - blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + to=settings.AUTH_USER_MODEL, ), ), migrations.AddField( @@ -78,7 +91,9 @@ class Migration(migrations.Migration): migrations.AddConstraint( model_name="dashboardtile", constraint=models.UniqueConstraint( - condition=models.Q(("text__isnull", False)), fields=("dashboard", "text"), name="unique_dashboard_text" + condition=models.Q(("text__isnull", False)), + fields=("dashboard", "text"), + name="unique_dashboard_text", ), ), # can't have both insight and text on a tile diff --git a/posthog/migrations/0268_plugin_source_file_updated_at.py b/posthog/migrations/0268_plugin_source_file_updated_at.py index 29bb3d78e98c0..c9e23fd601222 100644 --- a/posthog/migrations/0268_plugin_source_file_updated_at.py +++ b/posthog/migrations/0268_plugin_source_file_updated_at.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0267_add_text_tiles"), ] diff --git a/posthog/migrations/0269_soft_delete_tiles.py b/posthog/migrations/0269_soft_delete_tiles.py index fd12b437a9b90..6c02e4aba196a 100644 --- a/posthog/migrations/0269_soft_delete_tiles.py +++ b/posthog/migrations/0269_soft_delete_tiles.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0268_plugin_source_file_updated_at"), ] diff --git a/posthog/migrations/0270_add_uploaded_media.py b/posthog/migrations/0270_add_uploaded_media.py index eac6c04e6c5d5..4b202c85757e8 100644 --- a/posthog/migrations/0270_add_uploaded_media.py +++ b/posthog/migrations/0270_add_uploaded_media.py @@ -8,7 +8,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0269_soft_delete_tiles"), ] @@ -20,20 +19,35 @@ class Migration(migrations.Migration): ( "id", models.UUIDField( - default=posthog.models.utils.UUIDT, editable=False, primary_key=True, serialize=False + default=posthog.models.utils.UUIDT, + editable=False, + primary_key=True, + serialize=False, ), ), ("created_at", models.DateTimeField(auto_now_add=True)), - ("media_location", models.TextField(blank=True, max_length=1000, null=True)), - ("content_type", models.TextField(blank=True, max_length=100, null=True)), + ( + "media_location", + models.TextField(blank=True, max_length=1000, null=True), + ), + ( + "content_type", + models.TextField(blank=True, max_length=100, null=True), + ), ("file_name", models.TextField(blank=True, max_length=1000, null=True)), ( "created_by", models.ForeignKey( - blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + to=settings.AUTH_USER_MODEL, ), ), - ("team", models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="posthog.team")), + ( + "team", + models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="posthog.team"), + ), ], options={ "abstract": False, diff --git a/posthog/migrations/0271_delete_promptsequencestate.py b/posthog/migrations/0271_delete_promptsequencestate.py index cd1df66344aa7..479482c1981b5 100644 --- a/posthog/migrations/0271_delete_promptsequencestate.py +++ b/posthog/migrations/0271_delete_promptsequencestate.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0270_add_uploaded_media"), ] diff --git a/posthog/migrations/0272_alter_organization_plugins_access_level.py b/posthog/migrations/0272_alter_organization_plugins_access_level.py index 13f56d6f21b90..5f7fee6db4de3 100644 --- a/posthog/migrations/0272_alter_organization_plugins_access_level.py +++ b/posthog/migrations/0272_alter_organization_plugins_access_level.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0271_delete_promptsequencestate"), ] @@ -15,7 +14,8 @@ class Migration(migrations.Migration): model_name="organization", name="plugins_access_level", field=models.PositiveSmallIntegerField( - choices=[(0, "none"), (3, "config"), (6, "install"), (9, "root")], default=3 + choices=[(0, "none"), (3, "config"), (6, "install"), (9, "root")], + default=3, ), ), ] diff --git a/posthog/migrations/0273_mark_inactive_exports_as_finished.py b/posthog/migrations/0273_mark_inactive_exports_as_finished.py index 324a6fdcd2683..fcf024f5e6281 100644 --- a/posthog/migrations/0273_mark_inactive_exports_as_finished.py +++ b/posthog/migrations/0273_mark_inactive_exports_as_finished.py @@ -32,7 +32,12 @@ def should_verify_if_ongoing(start_entry, finished_exports): else: finished_exports.add(key(entry)) - start_entries = list(filter(lambda entry: should_verify_if_ongoing(entry, finished_exports), start_entries)) + start_entries = list( + filter( + lambda entry: should_verify_if_ongoing(entry, finished_exports), + start_entries, + ) + ) for entry in start_entries: expected_running_job_id = entry.detail["trigger"]["job_id"] diff --git a/posthog/migrations/0274_add_plugin_icon_and_rewrite_urls.py b/posthog/migrations/0274_add_plugin_icon_and_rewrite_urls.py index ee0b095199239..683937de53ac8 100644 --- a/posthog/migrations/0274_add_plugin_icon_and_rewrite_urls.py +++ b/posthog/migrations/0274_add_plugin_icon_and_rewrite_urls.py @@ -2,7 +2,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0273_mark_inactive_exports_as_finished"), ] diff --git a/posthog/migrations/0275_feature_flag_rollback_fields.py b/posthog/migrations/0275_feature_flag_rollback_fields.py index 6e938205fcad4..9078a175497a9 100644 --- a/posthog/migrations/0275_feature_flag_rollback_fields.py +++ b/posthog/migrations/0275_feature_flag_rollback_fields.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0274_add_plugin_icon_and_rewrite_urls"), ] diff --git a/posthog/migrations/0276_organization_usage.py b/posthog/migrations/0276_organization_usage.py index 1aa80ff6c5cf1..0e46fb7f50e7f 100644 --- a/posthog/migrations/0276_organization_usage.py +++ b/posthog/migrations/0276_organization_usage.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0275_feature_flag_rollback_fields"), ] diff --git a/posthog/migrations/0277_recording_playlist_model.py b/posthog/migrations/0277_recording_playlist_model.py index 137e9c0c75727..3a7b1ea2fd68c 100644 --- a/posthog/migrations/0277_recording_playlist_model.py +++ b/posthog/migrations/0277_recording_playlist_model.py @@ -9,7 +9,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0276_organization_usage"), ] @@ -18,20 +17,44 @@ class Migration(migrations.Migration): migrations.CreateModel( name="SessionRecordingPlaylist", fields=[ - ("id", models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), - ("short_id", models.CharField(blank=True, default=posthog.utils.generate_short_id, max_length=12)), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ( + "short_id", + models.CharField( + blank=True, + default=posthog.utils.generate_short_id, + max_length=12, + ), + ), ("name", models.CharField(blank=True, max_length=400, null=True)), - ("derived_name", models.CharField(blank=True, max_length=400, null=True)), + ( + "derived_name", + models.CharField(blank=True, max_length=400, null=True), + ), ("description", models.TextField(blank=True)), ("pinned", models.BooleanField(default=False)), ("deleted", models.BooleanField(default=False)), ("filters", models.JSONField(default=dict)), ("created_at", models.DateTimeField(auto_now_add=True)), - ("last_modified_at", models.DateTimeField(default=django.utils.timezone.now)), + ( + "last_modified_at", + models.DateTimeField(default=django.utils.timezone.now), + ), ( "created_by", models.ForeignKey( - blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + to=settings.AUTH_USER_MODEL, ), ), ( @@ -44,7 +67,10 @@ class Migration(migrations.Migration): to=settings.AUTH_USER_MODEL, ), ), - ("team", models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="posthog.team")), + ( + "team", + models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="posthog.team"), + ), ], options={ "unique_together": {("team", "short_id")}, diff --git a/posthog/migrations/0278_organization_customer_id.py b/posthog/migrations/0278_organization_customer_id.py index bebede0dcb936..76e65bf416d02 100644 --- a/posthog/migrations/0278_organization_customer_id.py +++ b/posthog/migrations/0278_organization_customer_id.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0277_recording_playlist_model"), ] diff --git a/posthog/migrations/0279_recording_playlist_item_model.py b/posthog/migrations/0279_recording_playlist_item_model.py index cc8a359c9cca8..6bf9e98877bcd 100644 --- a/posthog/migrations/0279_recording_playlist_item_model.py +++ b/posthog/migrations/0279_recording_playlist_item_model.py @@ -5,7 +5,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0278_organization_customer_id"), ] @@ -19,7 +18,15 @@ class Migration(migrations.Migration): migrations.CreateModel( name="SessionRecordingPlaylistItem", fields=[ - ("id", models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), ("session_id", models.CharField(max_length=200)), ("created_at", models.DateTimeField(auto_now_add=True)), ("deleted", models.BooleanField(blank=True, null=True)), diff --git a/posthog/migrations/0280_fix_async_deletion_team.py b/posthog/migrations/0280_fix_async_deletion_team.py index 98c1b3a81b9a9..9b218d0aad5eb 100644 --- a/posthog/migrations/0280_fix_async_deletion_team.py +++ b/posthog/migrations/0280_fix_async_deletion_team.py @@ -10,7 +10,6 @@ def describe(self): class Migration(migrations.Migration): - dependencies = [ ("posthog", "0279_recording_playlist_item_model"), ] diff --git a/posthog/migrations/0281_create_insight_caching_state_model.py b/posthog/migrations/0281_create_insight_caching_state_model.py index d8fb19f00a79c..9d176840bd954 100644 --- a/posthog/migrations/0281_create_insight_caching_state_model.py +++ b/posthog/migrations/0281_create_insight_caching_state_model.py @@ -7,7 +7,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0280_fix_async_deletion_team"), ] @@ -19,7 +18,10 @@ class Migration(migrations.Migration): ( "id", models.UUIDField( - default=posthog.models.utils.UUIDT, editable=False, primary_key=True, serialize=False + default=posthog.models.utils.UUIDT, + editable=False, + primary_key=True, + serialize=False, ), ), ("cache_key", models.CharField(max_length=400)), @@ -41,10 +43,15 @@ class Migration(migrations.Migration): ( "insight", models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, related_name="caching_state", to="posthog.insight" + on_delete=django.db.models.deletion.CASCADE, + related_name="caching_state", + to="posthog.insight", ), ), - ("team", models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="posthog.team")), + ( + "team", + models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="posthog.team"), + ), ], ), migrations.AddIndex( diff --git a/posthog/migrations/0282_fix_insight_caching_state_model.py b/posthog/migrations/0282_fix_insight_caching_state_model.py index c8f06becdcf7c..68606d0329dce 100644 --- a/posthog/migrations/0282_fix_insight_caching_state_model.py +++ b/posthog/migrations/0282_fix_insight_caching_state_model.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0281_create_insight_caching_state_model"), ] @@ -35,14 +34,19 @@ class Migration(migrations.Migration): model_name="insightcachingstate", name="dashboard_tile", field=models.ForeignKey( - null=True, on_delete=models.deletion.CASCADE, related_name="caching_states", to="posthog.dashboardtile" + null=True, + on_delete=models.deletion.CASCADE, + related_name="caching_states", + to="posthog.dashboardtile", ), ), migrations.AlterField( model_name="insightcachingstate", name="insight", field=models.ForeignKey( - on_delete=models.deletion.CASCADE, related_name="caching_states", to="posthog.insight" + on_delete=models.deletion.CASCADE, + related_name="caching_states", + to="posthog.insight", ), ), ] diff --git a/posthog/migrations/0283_prompt_sequence_model.py b/posthog/migrations/0283_prompt_sequence_model.py index 49378f62d32dd..16d29c076e483 100644 --- a/posthog/migrations/0283_prompt_sequence_model.py +++ b/posthog/migrations/0283_prompt_sequence_model.py @@ -8,7 +8,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0282_fix_insight_caching_state_model"), ] @@ -17,21 +16,40 @@ class Migration(migrations.Migration): migrations.CreateModel( name="Prompt", fields=[ - ("id", models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), ("step", models.IntegerField()), ("type", models.CharField(max_length=200)), ("title", models.CharField(max_length=200)), ("text", models.CharField(max_length=1000)), ("placement", models.CharField(default="top", max_length=200)), ("buttons", models.JSONField()), - ("reference", models.CharField(default=None, max_length=200, null=True)), + ( + "reference", + models.CharField(default=None, max_length=200, null=True), + ), ("icon", models.CharField(max_length=200)), ], ), migrations.CreateModel( name="PromptSequence", fields=[ - ("id", models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), ("key", models.CharField(max_length=200)), ("type", models.CharField(max_length=200)), ( @@ -45,23 +63,46 @@ class Migration(migrations.Migration): ("status", models.CharField(max_length=200)), ("requires_opt_in", models.BooleanField(default=False)), ("autorun", models.BooleanField(default=True)), - ("must_have_completed", models.ManyToManyField(blank=True, to="posthog.PromptSequence")), + ( + "must_have_completed", + models.ManyToManyField(blank=True, to="posthog.PromptSequence"), + ), ("prompts", models.ManyToManyField(to="posthog.Prompt")), ], ), migrations.CreateModel( name="UserPromptState", fields=[ - ("id", models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), - ("last_updated_at", models.DateTimeField(default=django.utils.timezone.now)), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ( + "last_updated_at", + models.DateTimeField(default=django.utils.timezone.now), + ), ("step", models.IntegerField(default=None, null=True)), ("completed", models.BooleanField(default=False)), ("dismissed", models.BooleanField(default=False)), ( "sequence", - models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="posthog.promptsequence"), + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + to="posthog.promptsequence", + ), + ), + ( + "user", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + to=settings.AUTH_USER_MODEL, + ), ), - ("user", models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), ], ), migrations.DeleteModel( diff --git a/posthog/migrations/0285_capture_performance_opt_in.py b/posthog/migrations/0285_capture_performance_opt_in.py index ba1673cef18f2..9f478625b7be2 100644 --- a/posthog/migrations/0285_capture_performance_opt_in.py +++ b/posthog/migrations/0285_capture_performance_opt_in.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0284_improved_caching_state_idx"), ] diff --git a/posthog/migrations/0287_add_session_recording_model.py b/posthog/migrations/0287_add_session_recording_model.py index 28bcd68907815..ca2ecb40a642c 100644 --- a/posthog/migrations/0287_add_session_recording_model.py +++ b/posthog/migrations/0287_add_session_recording_model.py @@ -24,7 +24,10 @@ def migrate_playlist_item_recording_relations(apps, _) -> None: Recording.objects.bulk_create( [ - Recording(session_id=playlist_item_object.session_id, team=playlist_item_object.playlist.team) + Recording( + session_id=playlist_item_object.session_id, + team=playlist_item_object.playlist.team, + ) for playlist_item_object in playlist_items ], ignore_conflicts=True, @@ -44,7 +47,6 @@ def reverse(apps, _) -> None: class Migration(migrations.Migration): - dependencies = [ ("posthog", "0286_index_insightcachingstate_lookup"), ] @@ -72,12 +74,18 @@ class Migration(migrations.Migration): ( "id", models.UUIDField( - default=posthog.models.utils.UUIDT, editable=False, primary_key=True, serialize=False + default=posthog.models.utils.UUIDT, + editable=False, + primary_key=True, + serialize=False, ), ), ("session_id", models.CharField(max_length=200, unique=True)), ("created_at", models.DateTimeField(auto_now_add=True, null=True)), - ("team", models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="posthog.team")), + ( + "team", + models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="posthog.team"), + ), ], options={ "unique_together": {("team", "session_id")}, diff --git a/posthog/migrations/0288_add_session_recording_persistence.py b/posthog/migrations/0288_add_session_recording_persistence.py index 3bf5226e91025..785346ecc2c10 100644 --- a/posthog/migrations/0288_add_session_recording_persistence.py +++ b/posthog/migrations/0288_add_session_recording_persistence.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0287_add_session_recording_model"), ] diff --git a/posthog/migrations/0289_add_tags_to_feature_flags.py b/posthog/migrations/0289_add_tags_to_feature_flags.py index debf52c006c03..913cbf6c99a36 100644 --- a/posthog/migrations/0289_add_tags_to_feature_flags.py +++ b/posthog/migrations/0289_add_tags_to_feature_flags.py @@ -5,7 +5,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0288_add_session_recording_persistence"), ] @@ -29,7 +28,15 @@ class Migration(migrations.Migration): migrations.AlterUniqueTogether( name="taggeditem", unique_together={ - ("tag", "dashboard", "insight", "event_definition", "property_definition", "action", "feature_flag") + ( + "tag", + "dashboard", + "insight", + "event_definition", + "property_definition", + "action", + "feature_flag", + ) }, ), migrations.AddConstraint( diff --git a/posthog/migrations/0290_add_dashboard_templates.py b/posthog/migrations/0290_add_dashboard_templates.py index 65f8835a89cdd..736a495c8747e 100644 --- a/posthog/migrations/0290_add_dashboard_templates.py +++ b/posthog/migrations/0290_add_dashboard_templates.py @@ -8,7 +8,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0289_add_tags_to_feature_flags"), ] @@ -20,7 +19,10 @@ class Migration(migrations.Migration): ( "id", models.UUIDField( - default=posthog.models.utils.UUIDT, editable=False, primary_key=True, serialize=False + default=posthog.models.utils.UUIDT, + editable=False, + primary_key=True, + serialize=False, ), ), ("template_name", models.CharField(max_length=400, null=True)), @@ -30,11 +32,20 @@ class Migration(migrations.Migration): ( "tags", django.contrib.postgres.fields.ArrayField( - base_field=models.CharField(max_length=255), default=list, size=None + base_field=models.CharField(max_length=255), + default=list, + size=None, ), ), ("github_url", models.CharField(max_length=8201, null=True)), - ("team", models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to="posthog.team")), + ( + "team", + models.ForeignKey( + null=True, + on_delete=django.db.models.deletion.CASCADE, + to="posthog.team", + ), + ), ], ), migrations.AddConstraint( diff --git a/posthog/migrations/0291_create_person_override_model.py b/posthog/migrations/0291_create_person_override_model.py index 59b7b9e5268fb..81c4191a25be3 100644 --- a/posthog/migrations/0291_create_person_override_model.py +++ b/posthog/migrations/0291_create_person_override_model.py @@ -5,7 +5,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0290_add_dashboard_templates"), ] @@ -14,18 +13,30 @@ class Migration(migrations.Migration): migrations.CreateModel( name="PersonOverride", fields=[ - ("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), ("old_person_id", models.UUIDField(db_index=True)), ("override_person_id", models.UUIDField(db_index=True)), ("oldest_event", models.DateTimeField()), ("version", models.BigIntegerField(blank=True, null=True)), - ("team", models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="posthog.team")), + ( + "team", + models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="posthog.team"), + ), ], ), migrations.AddConstraint( model_name="personoverride", constraint=models.UniqueConstraint( - fields=("team", "old_person_id"), name="unique override per old_person_id" + fields=("team", "old_person_id"), + name="unique override per old_person_id", ), ), ] diff --git a/posthog/migrations/0292_property_definitions_persons_and_groups_support.py b/posthog/migrations/0292_property_definitions_persons_and_groups_support.py index cde16d28f1840..d57a95ffa75de 100644 --- a/posthog/migrations/0292_property_definitions_persons_and_groups_support.py +++ b/posthog/migrations/0292_property_definitions_persons_and_groups_support.py @@ -35,7 +35,9 @@ class Migration(migrations.Migration): model_name="propertydefinition", constraint=models.CheckConstraint( check=models.Q( - models.Q(("type", 3), _negated=True), ("group_type_index__isnull", False), _connector="OR" + models.Q(("type", 3), _negated=True), + ("group_type_index__isnull", False), + _connector="OR", ), name="group_type_index_set", ), diff --git a/posthog/migrations/0293_property_definitions_drop_old_constraint.py b/posthog/migrations/0293_property_definitions_drop_old_constraint.py index f1d623521c903..9da2dbdfbe217 100644 --- a/posthog/migrations/0293_property_definitions_drop_old_constraint.py +++ b/posthog/migrations/0293_property_definitions_drop_old_constraint.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0292_property_definitions_persons_and_groups_support"), ] diff --git a/posthog/migrations/0294_plugin_blank_fields.py b/posthog/migrations/0294_plugin_blank_fields.py index 053fbb1d48ac0..7f519b9c021d0 100644 --- a/posthog/migrations/0294_plugin_blank_fields.py +++ b/posthog/migrations/0294_plugin_blank_fields.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0293_property_definitions_drop_old_constraint"), ] diff --git a/posthog/migrations/0295_plugin_allow_blank_config_schema.py b/posthog/migrations/0295_plugin_allow_blank_config_schema.py index 8952f8a252fad..4c8de8d40ef26 100644 --- a/posthog/migrations/0295_plugin_allow_blank_config_schema.py +++ b/posthog/migrations/0295_plugin_allow_blank_config_schema.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0294_plugin_blank_fields"), ] diff --git a/posthog/migrations/0296_team_allow_blank_fields.py b/posthog/migrations/0296_team_allow_blank_fields.py index f6c9065580709..9c593b68404ba 100644 --- a/posthog/migrations/0296_team_allow_blank_fields.py +++ b/posthog/migrations/0296_team_allow_blank_fields.py @@ -5,7 +5,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0295_plugin_allow_blank_config_schema"), ] diff --git a/posthog/migrations/0298_add_insight_queries.py b/posthog/migrations/0298_add_insight_queries.py index 48d3475819d91..82c04e7388164 100644 --- a/posthog/migrations/0298_add_insight_queries.py +++ b/posthog/migrations/0298_add_insight_queries.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0297_property_definitions_index_query"), ] diff --git a/posthog/migrations/0299_set_templates_global.py b/posthog/migrations/0299_set_templates_global.py index 4cdaf2f2c645f..7ca39b1814f35 100644 --- a/posthog/migrations/0299_set_templates_global.py +++ b/posthog/migrations/0299_set_templates_global.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0298_add_insight_queries"), ] diff --git a/posthog/migrations/0300_add_constraints_to_person_override.py b/posthog/migrations/0300_add_constraints_to_person_override.py index 91716cd8cc292..1f54ee839514a 100644 --- a/posthog/migrations/0300_add_constraints_to_person_override.py +++ b/posthog/migrations/0300_add_constraints_to_person_override.py @@ -31,7 +31,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0299_set_templates_global"), ] @@ -45,7 +44,11 @@ class Migration(migrations.Migration): model_name="personoverride", constraint=models.CheckConstraint( check=models.Q( - ("old_person_id__exact", django.db.models.expressions.F("override_person_id")), _negated=True + ( + "old_person_id__exact", + django.db.models.expressions.F("override_person_id"), + ), + _negated=True, ), name="old_person_id_different_from_override_person_id", ), diff --git a/posthog/migrations/0301_organization_enforce_2fa.py b/posthog/migrations/0301_organization_enforce_2fa.py index 21885de4fd954..43ae649c9d298 100644 --- a/posthog/migrations/0301_organization_enforce_2fa.py +++ b/posthog/migrations/0301_organization_enforce_2fa.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0300_add_constraints_to_person_override"), ] diff --git a/posthog/migrations/0302_add_user_pending_email_and_is_verified.py b/posthog/migrations/0302_add_user_pending_email_and_is_verified.py index e318a48cce19b..1c779dc12df73 100644 --- a/posthog/migrations/0302_add_user_pending_email_and_is_verified.py +++ b/posthog/migrations/0302_add_user_pending_email_and_is_verified.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0301_organization_enforce_2fa"), ] @@ -19,7 +18,10 @@ class Migration(migrations.Migration): model_name="user", name="pending_email", field=models.EmailField( - blank=True, max_length=254, null=True, verbose_name="pending email address awaiting verification" + blank=True, + max_length=254, + null=True, + verbose_name="pending email address awaiting verification", ), ), ] diff --git a/posthog/migrations/0303_team_session_recording_version.py b/posthog/migrations/0303_team_session_recording_version.py index b0517f1506d38..29469557f3b5f 100644 --- a/posthog/migrations/0303_team_session_recording_version.py +++ b/posthog/migrations/0303_team_session_recording_version.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0302_add_user_pending_email_and_is_verified"), ] diff --git a/posthog/migrations/0304_store_dashboard_template_in_db.py b/posthog/migrations/0304_store_dashboard_template_in_db.py index 6097f8761a29c..997ce8aab1bb8 100644 --- a/posthog/migrations/0304_store_dashboard_template_in_db.py +++ b/posthog/migrations/0304_store_dashboard_template_in_db.py @@ -13,7 +13,6 @@ def describe(self): class Migration(migrations.Migration): - dependencies = [ ("posthog", "0303_team_session_recording_version"), ] @@ -28,7 +27,10 @@ class Migration(migrations.Migration): model_name="dashboardtemplate", name="created_by", field=models.ForeignKey( - blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + to=settings.AUTH_USER_MODEL, ), ), migrations.AddField( @@ -66,7 +68,10 @@ class Migration(migrations.Migration): model_name="dashboardtemplate", name="tags", field=django.contrib.postgres.fields.ArrayField( - base_field=models.CharField(max_length=255), blank=True, null=True, size=None + base_field=models.CharField(max_length=255), + blank=True, + null=True, + size=None, ), ), AlterFieldNullSafe( diff --git a/posthog/migrations/0305_rework_person_overrides.py b/posthog/migrations/0305_rework_person_overrides.py index 3afd6d4154b54..e5da39fce39b4 100644 --- a/posthog/migrations/0305_rework_person_overrides.py +++ b/posthog/migrations/0305_rework_person_overrides.py @@ -2,7 +2,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0304_store_dashboard_template_in_db"), ] diff --git a/posthog/migrations/0306_featureflag_dashboard.py b/posthog/migrations/0306_featureflag_dashboard.py index 87d6332e8f08d..b465eda4bee5e 100644 --- a/posthog/migrations/0306_featureflag_dashboard.py +++ b/posthog/migrations/0306_featureflag_dashboard.py @@ -5,7 +5,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0305_rework_person_overrides"), ] @@ -15,7 +14,10 @@ class Migration(migrations.Migration): model_name="featureflag", name="usage_dashboard", field=models.ForeignKey( - blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to="posthog.dashboard" + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + to="posthog.dashboard", ), ), ] diff --git a/posthog/migrations/0307_pluginconfig_admin.py b/posthog/migrations/0307_pluginconfig_admin.py index 2716382f4fc62..2a901a1492bb1 100644 --- a/posthog/migrations/0307_pluginconfig_admin.py +++ b/posthog/migrations/0307_pluginconfig_admin.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0306_featureflag_dashboard"), ] diff --git a/posthog/migrations/0308_add_indirect_person_override_constraints.py b/posthog/migrations/0308_add_indirect_person_override_constraints.py index 757cc46f80126..78231ace0834e 100644 --- a/posthog/migrations/0308_add_indirect_person_override_constraints.py +++ b/posthog/migrations/0308_add_indirect_person_override_constraints.py @@ -20,7 +20,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0307_pluginconfig_admin"), ] @@ -29,7 +28,15 @@ class Migration(migrations.Migration): migrations.CreateModel( name="PersonOverrideMapping", fields=[ - ("id", models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), ("uuid", models.UUIDField()), ("team_id", models.BigIntegerField()), ], @@ -73,14 +80,19 @@ class Migration(migrations.Migration): migrations.AddConstraint( model_name="personoverride", constraint=models.UniqueConstraint( - fields=("team", "old_person_id"), name="unique override per old_person_id" + fields=("team", "old_person_id"), + name="unique override per old_person_id", ), ), migrations.AddConstraint( model_name="personoverride", constraint=models.CheckConstraint( check=models.Q( - ("old_person_id__exact", django.db.models.expressions.F("override_person_id")), _negated=True + ( + "old_person_id__exact", + django.db.models.expressions.F("override_person_id"), + ), + _negated=True, ), name="old_person_id_different_from_override_person_id", ), diff --git a/posthog/migrations/0309_team_autocapture_opt_out.py b/posthog/migrations/0309_team_autocapture_opt_out.py index 5f77749d65eed..11b8e8a9cb0d7 100644 --- a/posthog/migrations/0309_team_autocapture_opt_out.py +++ b/posthog/migrations/0309_team_autocapture_opt_out.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0308_add_indirect_person_override_constraints"), ] diff --git a/posthog/migrations/0310_add_starter_dashboard_template.py b/posthog/migrations/0310_add_starter_dashboard_template.py index 70957615b1975..2d1fc6972b517 100644 --- a/posthog/migrations/0310_add_starter_dashboard_template.py +++ b/posthog/migrations/0310_add_starter_dashboard_template.py @@ -148,7 +148,6 @@ def create_starter_template(apps, schema_editor): class Migration(migrations.Migration): - dependencies = [ ("posthog", "0309_team_autocapture_opt_out"), ] diff --git a/posthog/migrations/0311_dashboard_template_scope.py b/posthog/migrations/0311_dashboard_template_scope.py index 6843e09d68511..41e34afa83109 100644 --- a/posthog/migrations/0311_dashboard_template_scope.py +++ b/posthog/migrations/0311_dashboard_template_scope.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0310_add_starter_dashboard_template"), ] @@ -15,7 +14,10 @@ class Migration(migrations.Migration): model_name="dashboardtemplate", name="scope", field=models.CharField( - choices=[("team", "Only team"), ("global", "Global")], max_length=24, null=True, blank=True + choices=[("team", "Only team"), ("global", "Global")], + max_length=24, + null=True, + blank=True, ), ), migrations.RunSQL( diff --git a/posthog/migrations/0312_organization_available_product_features.py b/posthog/migrations/0312_organization_available_product_features.py index c5b2eb170f9c4..2459cd9726c07 100644 --- a/posthog/migrations/0312_organization_available_product_features.py +++ b/posthog/migrations/0312_organization_available_product_features.py @@ -5,7 +5,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0311_dashboard_template_scope"), ] diff --git a/posthog/migrations/0313_early_access_feature.py b/posthog/migrations/0313_early_access_feature.py index 20d1dfe22d479..e5bc07942ff24 100644 --- a/posthog/migrations/0313_early_access_feature.py +++ b/posthog/migrations/0313_early_access_feature.py @@ -7,7 +7,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0312_organization_available_product_features"), ] @@ -19,7 +18,10 @@ class Migration(migrations.Migration): ( "id", models.UUIDField( - default=posthog.models.utils.UUIDT, editable=False, primary_key=True, serialize=False + default=posthog.models.utils.UUIDT, + editable=False, + primary_key=True, + serialize=False, ), ), ("name", models.CharField(max_length=200)), diff --git a/posthog/migrations/0314_sharingconfiguration_recording.py b/posthog/migrations/0314_sharingconfiguration_recording.py index 940a09db8d46f..d4ce07d2ffebc 100644 --- a/posthog/migrations/0314_sharingconfiguration_recording.py +++ b/posthog/migrations/0314_sharingconfiguration_recording.py @@ -5,7 +5,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0313_early_access_feature"), ] diff --git a/posthog/migrations/0315_notebook.py b/posthog/migrations/0315_notebook.py index b14d66d59c3f7..b02a15842a7a1 100644 --- a/posthog/migrations/0315_notebook.py +++ b/posthog/migrations/0315_notebook.py @@ -9,7 +9,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0314_sharingconfiguration_recording"), ] @@ -21,20 +20,36 @@ class Migration(migrations.Migration): ( "id", models.UUIDField( - default=posthog.models.utils.UUIDT, editable=False, primary_key=True, serialize=False + default=posthog.models.utils.UUIDT, + editable=False, + primary_key=True, + serialize=False, + ), + ), + ( + "short_id", + models.CharField( + blank=True, + default=posthog.utils.generate_short_id, + max_length=12, ), ), - ("short_id", models.CharField(blank=True, default=posthog.utils.generate_short_id, max_length=12)), ("title", models.CharField(blank=True, max_length=256, null=True)), ("content", models.JSONField(blank=True, default=None, null=True)), ("deleted", models.BooleanField(default=False)), ("version", models.IntegerField(default=0)), ("created_at", models.DateTimeField(auto_now_add=True)), - ("last_modified_at", models.DateTimeField(default=django.utils.timezone.now)), + ( + "last_modified_at", + models.DateTimeField(default=django.utils.timezone.now), + ), ( "created_by", models.ForeignKey( - blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + to=settings.AUTH_USER_MODEL, ), ), ( @@ -47,7 +62,10 @@ class Migration(migrations.Migration): to=settings.AUTH_USER_MODEL, ), ), - ("team", models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="posthog.team")), + ( + "team", + models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="posthog.team"), + ), ], options={ "unique_together": {("team", "short_id")}, diff --git a/posthog/migrations/0316_action_href_text_matching.py b/posthog/migrations/0316_action_href_text_matching.py index 870c045ad6a34..fdded1fd8cbf0 100644 --- a/posthog/migrations/0316_action_href_text_matching.py +++ b/posthog/migrations/0316_action_href_text_matching.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0315_notebook"), ] @@ -15,7 +14,11 @@ class Migration(migrations.Migration): name="href_matching", field=models.CharField( blank=True, - choices=[("contains", "contains"), ("regex", "regex"), ("exact", "exact")], + choices=[ + ("contains", "contains"), + ("regex", "regex"), + ("exact", "exact"), + ], max_length=400, null=True, ), @@ -25,7 +28,11 @@ class Migration(migrations.Migration): name="text_matching", field=models.CharField( blank=True, - choices=[("contains", "contains"), ("regex", "regex"), ("exact", "exact")], + choices=[ + ("contains", "contains"), + ("regex", "regex"), + ("exact", "exact"), + ], max_length=400, null=True, ), diff --git a/posthog/migrations/0317_batch_export_models.py b/posthog/migrations/0317_batch_export_models.py index b8feb24b4b75e..f17bf9293ad34 100644 --- a/posthog/migrations/0317_batch_export_models.py +++ b/posthog/migrations/0317_batch_export_models.py @@ -17,7 +17,10 @@ class Migration(migrations.Migration): ( "id", models.UUIDField( - default=posthog.models.utils.UUIDT, editable=False, primary_key=True, serialize=False + default=posthog.models.utils.UUIDT, + editable=False, + primary_key=True, + serialize=False, ), ), ( @@ -39,13 +42,15 @@ class Migration(migrations.Migration): ( "created_at", models.DateTimeField( - auto_now_add=True, help_text="The timestamp at which this BatchExportDestination was created." + auto_now_add=True, + help_text="The timestamp at which this BatchExportDestination was created.", ), ), ( "last_updated_at", models.DateTimeField( - auto_now=True, help_text="The timestamp at which this BatchExportDestination was last updated." + auto_now=True, + help_text="The timestamp at which this BatchExportDestination was last updated.", ), ), ], @@ -59,7 +64,10 @@ class Migration(migrations.Migration): ( "id", models.UUIDField( - default=posthog.models.utils.UUIDT, editable=False, primary_key=True, serialize=False + default=posthog.models.utils.UUIDT, + editable=False, + primary_key=True, + serialize=False, ), ), ( @@ -70,7 +78,10 @@ class Migration(migrations.Migration): to="posthog.team", ), ), - ("name", models.TextField(help_text="A human-readable name for this BatchExport.")), + ( + "name", + models.TextField(help_text="A human-readable name for this BatchExport."), + ), ( "destination", models.ForeignKey( @@ -88,21 +99,32 @@ class Migration(migrations.Migration): max_length=64, ), ), - ("paused", models.BooleanField(default=False, help_text="Whether this BatchExport is paused or not.")), + ( + "paused", + models.BooleanField( + default=False, + help_text="Whether this BatchExport is paused or not.", + ), + ), ( "deleted", - models.BooleanField(default=False, help_text="Whether this BatchExport is deleted or not."), + models.BooleanField( + default=False, + help_text="Whether this BatchExport is deleted or not.", + ), ), ( "created_at", models.DateTimeField( - auto_now_add=True, help_text="The timestamp at which this BatchExport was created." + auto_now_add=True, + help_text="The timestamp at which this BatchExport was created.", ), ), ( "last_updated_at", models.DateTimeField( - auto_now=True, help_text="The timestamp at which this BatchExport was last updated." + auto_now=True, + help_text="The timestamp at which this BatchExport was last updated.", ), ), ], @@ -116,7 +138,10 @@ class Migration(migrations.Migration): ( "id", models.UUIDField( - default=posthog.models.utils.UUIDT, editable=False, primary_key=True, serialize=False + default=posthog.models.utils.UUIDT, + editable=False, + primary_key=True, + serialize=False, ), ), ( @@ -138,31 +163,52 @@ class Migration(migrations.Migration): ), ( "records_completed", - models.IntegerField(help_text="The number of records that have been exported.", null=True), + models.IntegerField( + help_text="The number of records that have been exported.", + null=True, + ), ), ( "latest_error", - models.TextField(help_text="The latest error that occurred during this run.", null=True), + models.TextField( + help_text="The latest error that occurred during this run.", + null=True, + ), + ), + ( + "data_interval_start", + models.DateTimeField(help_text="The start of the data interval."), + ), + ( + "data_interval_end", + models.DateTimeField(help_text="The end of the data interval."), + ), + ( + "cursor", + models.TextField( + help_text="An opaque cursor that may be used to resume.", + null=True, + ), ), - ("data_interval_start", models.DateTimeField(help_text="The start of the data interval.")), - ("data_interval_end", models.DateTimeField(help_text="The end of the data interval.")), - ("cursor", models.TextField(help_text="An opaque cursor that may be used to resume.", null=True)), ( "created_at", models.DateTimeField( - auto_now_add=True, help_text="The timestamp at which this BatchExportRun was created." + auto_now_add=True, + help_text="The timestamp at which this BatchExportRun was created.", ), ), ( "finished_at", models.DateTimeField( - help_text="The timestamp at which this BatchExportRun finished, successfully or not.", null=True + help_text="The timestamp at which this BatchExportRun finished, successfully or not.", + null=True, ), ), ( "last_updated_at", models.DateTimeField( - auto_now=True, help_text="The timestamp at which this BatchExportRun was last updated." + auto_now=True, + help_text="The timestamp at which this BatchExportRun was last updated.", ), ), ( diff --git a/posthog/migrations/0318_alter_earlyaccessfeature_stage.py b/posthog/migrations/0318_alter_earlyaccessfeature_stage.py index 2657a38695868..92abd1afd5d86 100644 --- a/posthog/migrations/0318_alter_earlyaccessfeature_stage.py +++ b/posthog/migrations/0318_alter_earlyaccessfeature_stage.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0317_batch_export_models"), ] diff --git a/posthog/migrations/0319_user_requested_password_reset_at.py b/posthog/migrations/0319_user_requested_password_reset_at.py index 0b51cd0063256..7de6560f71fec 100644 --- a/posthog/migrations/0319_user_requested_password_reset_at.py +++ b/posthog/migrations/0319_user_requested_password_reset_at.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0318_alter_earlyaccessfeature_stage"), ] diff --git a/posthog/migrations/0320_survey.py b/posthog/migrations/0320_survey.py index 9e8fea849ef9b..8dff33ee768db 100644 --- a/posthog/migrations/0320_survey.py +++ b/posthog/migrations/0320_survey.py @@ -7,7 +7,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0319_user_requested_password_reset_at"), ] @@ -19,7 +18,10 @@ class Migration(migrations.Migration): ( "id", models.UUIDField( - default=posthog.models.utils.UUIDT, editable=False, primary_key=True, serialize=False + default=posthog.models.utils.UUIDT, + editable=False, + primary_key=True, + serialize=False, ), ), ("name", models.CharField(max_length=400)), diff --git a/posthog/migrations/0321_add_exception_autocapture_optin.py b/posthog/migrations/0321_add_exception_autocapture_optin.py index a1adce2374eb6..c15700964f90d 100644 --- a/posthog/migrations/0321_add_exception_autocapture_optin.py +++ b/posthog/migrations/0321_add_exception_autocapture_optin.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0320_survey"), ] diff --git a/posthog/migrations/0322_auto_20230531_1904.py b/posthog/migrations/0322_auto_20230531_1904.py index c7b774f365c67..687d77316a99f 100644 --- a/posthog/migrations/0322_auto_20230531_1904.py +++ b/posthog/migrations/0322_auto_20230531_1904.py @@ -5,7 +5,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0321_add_exception_autocapture_optin"), ] @@ -14,13 +13,30 @@ class Migration(migrations.Migration): migrations.CreateModel( name="FeatureFlagDashboards", fields=[ - ("id", models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), ("created_at", models.DateTimeField(auto_now_add=True, null=True)), ("updated_at", models.DateTimeField(auto_now=True, null=True)), - ("dashboard", models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="posthog.dashboard")), + ( + "dashboard", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + to="posthog.dashboard", + ), + ), ( "feature_flag", - models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="posthog.featureflag"), + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + to="posthog.featureflag", + ), ), ], ), @@ -37,7 +53,8 @@ class Migration(migrations.Migration): migrations.AddConstraint( model_name="featureflagdashboards", constraint=models.UniqueConstraint( - fields=("feature_flag", "dashboard"), name="unique feature flag for a dashboard" + fields=("feature_flag", "dashboard"), + name="unique feature flag for a dashboard", ), ), ] diff --git a/posthog/migrations/0324_user_has_seen_product_intro_for.py b/posthog/migrations/0324_user_has_seen_product_intro_for.py index 5c75b6a7472e4..6c5142cdf47a6 100644 --- a/posthog/migrations/0324_user_has_seen_product_intro_for.py +++ b/posthog/migrations/0324_user_has_seen_product_intro_for.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0323_alter_batchexportdestination_type"), ] diff --git a/posthog/migrations/0325_alter_dashboardtemplate_scope.py b/posthog/migrations/0325_alter_dashboardtemplate_scope.py index cccfc358af848..d6829a963ac7c 100644 --- a/posthog/migrations/0325_alter_dashboardtemplate_scope.py +++ b/posthog/migrations/0325_alter_dashboardtemplate_scope.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0324_user_has_seen_product_intro_for"), ] @@ -15,7 +14,11 @@ class Migration(migrations.Migration): name="scope", field=models.CharField( blank=True, - choices=[("team", "Only team"), ("global", "Global"), ("feature_flag", "Feature Flag")], + choices=[ + ("team", "Only team"), + ("global", "Global"), + ("feature_flag", "Feature Flag"), + ], max_length=24, null=True, ), diff --git a/posthog/migrations/0326_team_extra_settings.py b/posthog/migrations/0326_team_extra_settings.py index 1ce5ca0886c75..62deb954703eb 100644 --- a/posthog/migrations/0326_team_extra_settings.py +++ b/posthog/migrations/0326_team_extra_settings.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0325_alter_dashboardtemplate_scope"), ] diff --git a/posthog/migrations/0327_alter_earlyaccessfeature_stage.py b/posthog/migrations/0327_alter_earlyaccessfeature_stage.py index c9d2454d40d21..f5376b89e999c 100644 --- a/posthog/migrations/0327_alter_earlyaccessfeature_stage.py +++ b/posthog/migrations/0327_alter_earlyaccessfeature_stage.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0326_team_extra_settings"), ] diff --git a/posthog/migrations/0328_add_starter_feature_flag_template.py b/posthog/migrations/0328_add_starter_feature_flag_template.py index adf9d5b971a60..eef2e038dc7a9 100644 --- a/posthog/migrations/0328_add_starter_feature_flag_template.py +++ b/posthog/migrations/0328_add_starter_feature_flag_template.py @@ -59,7 +59,6 @@ def create_starter_template(apps, schema_editor): class Migration(migrations.Migration): - dependencies = [ ("posthog", "0327_alter_earlyaccessfeature_stage"), ] diff --git a/posthog/migrations/0329_datawarehousecredential_datawarehousetable.py b/posthog/migrations/0329_datawarehousecredential_datawarehousetable.py index 7b1e88d018b8d..b3957067826df 100644 --- a/posthog/migrations/0329_datawarehousecredential_datawarehousetable.py +++ b/posthog/migrations/0329_datawarehousecredential_datawarehousetable.py @@ -8,7 +8,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0328_add_starter_feature_flag_template"), ] @@ -21,18 +20,33 @@ class Migration(migrations.Migration): ( "id", models.UUIDField( - default=posthog.models.utils.UUIDT, editable=False, primary_key=True, serialize=False + default=posthog.models.utils.UUIDT, + editable=False, + primary_key=True, + serialize=False, ), ), - ("access_key", encrypted_fields.fields.EncryptedTextField(max_length=500)), - ("access_secret", encrypted_fields.fields.EncryptedTextField(max_length=500)), + ( + "access_key", + encrypted_fields.fields.EncryptedTextField(max_length=500), + ), + ( + "access_secret", + encrypted_fields.fields.EncryptedTextField(max_length=500), + ), ( "created_by", models.ForeignKey( - blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + to=settings.AUTH_USER_MODEL, ), ), - ("team", models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="posthog.team")), + ( + "team", + models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="posthog.team"), + ), ], options={ "abstract": False, @@ -46,11 +60,17 @@ class Migration(migrations.Migration): ( "id", models.UUIDField( - default=posthog.models.utils.UUIDT, editable=False, primary_key=True, serialize=False + default=posthog.models.utils.UUIDT, + editable=False, + primary_key=True, + serialize=False, ), ), ("name", models.CharField(max_length=128)), - ("format", models.CharField(choices=[("CSV", "CSV"), ("Parquet", "Parquet")], max_length=128)), + ( + "format", + models.CharField(choices=[("CSV", "CSV"), ("Parquet", "Parquet")], max_length=128), + ), ("url_pattern", models.CharField(max_length=500)), ( "columns", @@ -64,7 +84,10 @@ class Migration(migrations.Migration): ( "created_by", models.ForeignKey( - blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + to=settings.AUTH_USER_MODEL, ), ), ( @@ -76,7 +99,10 @@ class Migration(migrations.Migration): to="posthog.datawarehousecredential", ), ), - ("team", models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="posthog.team")), + ( + "team", + models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="posthog.team"), + ), ], options={ "abstract": False, diff --git a/posthog/migrations/0330_add_autocapture_exceptions_events_to_ignore.py b/posthog/migrations/0330_add_autocapture_exceptions_events_to_ignore.py index ae830ee034d0d..71671bb4096f1 100644 --- a/posthog/migrations/0330_add_autocapture_exceptions_events_to_ignore.py +++ b/posthog/migrations/0330_add_autocapture_exceptions_events_to_ignore.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0329_datawarehousecredential_datawarehousetable"), ] diff --git a/posthog/migrations/0331_add_missing_property_definition_index.py b/posthog/migrations/0331_add_missing_property_definition_index.py index f4c0bcbca4fad..376cec5d0b3d7 100644 --- a/posthog/migrations/0331_add_missing_property_definition_index.py +++ b/posthog/migrations/0331_add_missing_property_definition_index.py @@ -18,6 +18,9 @@ class Migration(migrations.Migration): operations = [ AddIndexConcurrently( model_name="propertydefinition", - index=models.Index(fields=["team_id", "type", "is_numerical"], name="posthog_pro_team_id_eac36d_idx"), + index=models.Index( + fields=["team_id", "type", "is_numerical"], + name="posthog_pro_team_id_eac36d_idx", + ), ), ] diff --git a/posthog/migrations/0332_featureflag_has_enriched_analytics.py b/posthog/migrations/0332_featureflag_has_enriched_analytics.py index 259845b925947..d12ca4079d5aa 100644 --- a/posthog/migrations/0332_featureflag_has_enriched_analytics.py +++ b/posthog/migrations/0332_featureflag_has_enriched_analytics.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0331_add_missing_property_definition_index"), ] diff --git a/posthog/migrations/0333_add_timestamp_fields_to_batch_exports.py b/posthog/migrations/0333_add_timestamp_fields_to_batch_exports.py index aa9654a3ca275..b945693d75c20 100644 --- a/posthog/migrations/0333_add_timestamp_fields_to_batch_exports.py +++ b/posthog/migrations/0333_add_timestamp_fields_to_batch_exports.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0332_featureflag_has_enriched_analytics"), ] @@ -14,21 +13,27 @@ class Migration(migrations.Migration): model_name="batchexport", name="end_at", field=models.DateTimeField( - default=None, help_text="Time after which any Batch Export runs won't be triggered.", null=True + default=None, + help_text="Time after which any Batch Export runs won't be triggered.", + null=True, ), ), migrations.AddField( model_name="batchexport", name="last_paused_at", field=models.DateTimeField( - default=None, help_text="The timestamp at which this BatchExport was last paused.", null=True + default=None, + help_text="The timestamp at which this BatchExport was last paused.", + null=True, ), ), migrations.AddField( model_name="batchexport", name="start_at", field=models.DateTimeField( - default=None, help_text="Time before which any Batch Export runs won't be triggered.", null=True + default=None, + help_text="Time before which any Batch Export runs won't be triggered.", + null=True, ), ), ] diff --git a/posthog/migrations/0334_add_asset_ttl.py b/posthog/migrations/0334_add_asset_ttl.py index ec77eedb9cd78..8a97eca2b11e4 100644 --- a/posthog/migrations/0334_add_asset_ttl.py +++ b/posthog/migrations/0334_add_asset_ttl.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0333_add_timestamp_fields_to_batch_exports"), ] diff --git a/posthog/migrations/0335_alter_asyncdeletion_deletion_type.py b/posthog/migrations/0335_alter_asyncdeletion_deletion_type.py index 33f5294d206ef..36d8ddbccc372 100644 --- a/posthog/migrations/0335_alter_asyncdeletion_deletion_type.py +++ b/posthog/migrations/0335_alter_asyncdeletion_deletion_type.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0334_add_asset_ttl"), ] @@ -14,7 +13,13 @@ class Migration(migrations.Migration): model_name="asyncdeletion", name="deletion_type", field=models.PositiveSmallIntegerField( - choices=[(0, "Team"), (1, "Person"), (2, "Group"), (3, "Cohort Stale"), (4, "Cohort Full")] + choices=[ + (0, "Team"), + (1, "Person"), + (2, "Group"), + (3, "Cohort Stale"), + (4, "Cohort Full"), + ] ), ), ] diff --git a/posthog/migrations/0336_alter_survey_type.py b/posthog/migrations/0336_alter_survey_type.py index c432eb88eed46..8fe97122f5db7 100644 --- a/posthog/migrations/0336_alter_survey_type.py +++ b/posthog/migrations/0336_alter_survey_type.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0335_alter_asyncdeletion_deletion_type"), ] diff --git a/posthog/migrations/0337_more_session_recording_fields.py b/posthog/migrations/0337_more_session_recording_fields.py index 66e59191c3b6d..c0396ef1417b5 100644 --- a/posthog/migrations/0337_more_session_recording_fields.py +++ b/posthog/migrations/0337_more_session_recording_fields.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0336_alter_survey_type"), ] diff --git a/posthog/migrations/0338_datawarehouse_saved_query.py b/posthog/migrations/0338_datawarehouse_saved_query.py index eac5feef35a87..88ab851d0b1c8 100644 --- a/posthog/migrations/0338_datawarehouse_saved_query.py +++ b/posthog/migrations/0338_datawarehouse_saved_query.py @@ -8,7 +8,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0337_more_session_recording_fields"), ] @@ -22,7 +21,10 @@ class Migration(migrations.Migration): ( "id", models.UUIDField( - default=posthog.models.utils.UUIDT, editable=False, primary_key=True, serialize=False + default=posthog.models.utils.UUIDT, + editable=False, + primary_key=True, + serialize=False, ), ), ( @@ -41,20 +43,30 @@ class Migration(migrations.Migration): null=True, ), ), - ("query", models.JSONField(blank=True, default=dict, help_text="HogQL query", null=True)), + ( + "query", + models.JSONField(blank=True, default=dict, help_text="HogQL query", null=True), + ), ( "created_by", models.ForeignKey( - blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + to=settings.AUTH_USER_MODEL, ), ), - ("team", models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="posthog.team")), + ( + "team", + models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="posthog.team"), + ), ], ), migrations.AddConstraint( model_name="datawarehousesavedquery", constraint=models.UniqueConstraint( - fields=("team", "name"), name="posthog_datawarehouse_saved_query_unique_name" + fields=("team", "name"), + name="posthog_datawarehouse_saved_query_unique_name", ), ), ] diff --git a/posthog/migrations/0339_add_user_scene_personalisation.py b/posthog/migrations/0339_add_user_scene_personalisation.py index d38c1ec1da9a7..aede86b617e5a 100644 --- a/posthog/migrations/0339_add_user_scene_personalisation.py +++ b/posthog/migrations/0339_add_user_scene_personalisation.py @@ -7,7 +7,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0338_datawarehouse_saved_query"), ] @@ -19,20 +18,29 @@ class Migration(migrations.Migration): ( "id", models.UUIDField( - default=posthog.models.utils.UUIDT, editable=False, primary_key=True, serialize=False + default=posthog.models.utils.UUIDT, + editable=False, + primary_key=True, + serialize=False, ), ), ("scene", models.CharField(max_length=200)), ( "dashboard", models.ForeignKey( - blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to="posthog.dashboard" + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + to="posthog.dashboard", ), ), ( "team", models.ForeignKey( - blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to="posthog.team" + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + to="posthog.team", ), ), ( @@ -50,7 +58,8 @@ class Migration(migrations.Migration): migrations.AddConstraint( model_name="userscenepersonalisation", constraint=models.UniqueConstraint( - fields=("team", "user", "scene"), name="posthog_unique_scene_personalisation" + fields=("team", "user", "scene"), + name="posthog_unique_scene_personalisation", ), ), ] diff --git a/posthog/migrations/0340_action_bytecode.py b/posthog/migrations/0340_action_bytecode.py index c55a3678f0142..3603c83d8ef1a 100644 --- a/posthog/migrations/0340_action_bytecode.py +++ b/posthog/migrations/0340_action_bytecode.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0339_add_user_scene_personalisation"), ] diff --git a/posthog/migrations/0341_add_session_recording_storage_version.py b/posthog/migrations/0341_add_session_recording_storage_version.py index 92828fd84168b..6e81b4105e6fc 100644 --- a/posthog/migrations/0341_add_session_recording_storage_version.py +++ b/posthog/migrations/0341_add_session_recording_storage_version.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0340_action_bytecode"), ] diff --git a/posthog/migrations/0342_alter_featureflag_usage_dashboard.py b/posthog/migrations/0342_alter_featureflag_usage_dashboard.py index 942413fd5d49a..55feb73d8a362 100644 --- a/posthog/migrations/0342_alter_featureflag_usage_dashboard.py +++ b/posthog/migrations/0342_alter_featureflag_usage_dashboard.py @@ -5,7 +5,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0341_add_session_recording_storage_version"), ] @@ -15,7 +14,10 @@ class Migration(migrations.Migration): model_name="featureflag", name="usage_dashboard", field=models.ForeignKey( - blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to="posthog.dashboard" + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + to="posthog.dashboard", ), ), ] diff --git a/posthog/migrations/0343_team_has_completed_onboarding_for.py b/posthog/migrations/0343_team_has_completed_onboarding_for.py index c6fba2fc6334f..e3c1aab1edc01 100644 --- a/posthog/migrations/0343_team_has_completed_onboarding_for.py +++ b/posthog/migrations/0343_team_has_completed_onboarding_for.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0342_alter_featureflag_usage_dashboard"), ] diff --git a/posthog/migrations/0344_add_new_export_type.py b/posthog/migrations/0344_add_new_export_type.py index 49155d32f940b..947c1cb537a40 100644 --- a/posthog/migrations/0344_add_new_export_type.py +++ b/posthog/migrations/0344_add_new_export_type.py @@ -13,7 +13,11 @@ class Migration(migrations.Migration): model_name="batchexportdestination", name="type", field=models.CharField( - choices=[("S3", "S3"), ("Snowflake", "Snowflake"), ("Postgres", "Postgres")], + choices=[ + ("S3", "S3"), + ("Snowflake", "Snowflake"), + ("Postgres", "Postgres"), + ], help_text="A choice of supported BatchExportDestination types.", max_length=64, ), diff --git a/posthog/migrations/0345_view_link_and_s3_table_update.py b/posthog/migrations/0345_view_link_and_s3_table_update.py index 0e91d001128e9..5b0cbcc45b68b 100644 --- a/posthog/migrations/0345_view_link_and_s3_table_update.py +++ b/posthog/migrations/0345_view_link_and_s3_table_update.py @@ -7,7 +7,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0344_add_new_export_type"), ] @@ -16,7 +15,12 @@ class Migration(migrations.Migration): migrations.AddField( model_name="datawarehousesavedquery", name="external_tables", - field=models.JSONField(blank=True, default=list, help_text="List of all external tables", null=True), + field=models.JSONField( + blank=True, + default=list, + help_text="List of all external tables", + null=True, + ), ), migrations.CreateModel( name="DataWarehouseViewLink", @@ -26,7 +30,10 @@ class Migration(migrations.Migration): ( "id", models.UUIDField( - default=posthog.models.utils.UUIDT, editable=False, primary_key=True, serialize=False + default=posthog.models.utils.UUIDT, + editable=False, + primary_key=True, + serialize=False, ), ), ("table", models.CharField(max_length=128)), @@ -35,16 +42,23 @@ class Migration(migrations.Migration): ( "created_by", models.ForeignKey( - blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + to=settings.AUTH_USER_MODEL, ), ), ( "saved_query", models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="posthog.datawarehousesavedquery" + on_delete=django.db.models.deletion.CASCADE, + to="posthog.datawarehousesavedquery", ), ), - ("team", models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="posthog.team")), + ( + "team", + models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="posthog.team"), + ), ], options={ "abstract": False, diff --git a/posthog/migrations/0346_team_week_start_day.py b/posthog/migrations/0346_team_week_start_day.py index d8f659ccbefae..716fd071fff04 100644 --- a/posthog/migrations/0346_team_week_start_day.py +++ b/posthog/migrations/0346_team_week_start_day.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0345_view_link_and_s3_table_update"), ] diff --git a/posthog/migrations/0347_add_bigquery_export_type.py b/posthog/migrations/0347_add_bigquery_export_type.py index 862befb04723a..6f9b25a1b38de 100644 --- a/posthog/migrations/0347_add_bigquery_export_type.py +++ b/posthog/migrations/0347_add_bigquery_export_type.py @@ -13,7 +13,12 @@ class Migration(migrations.Migration): model_name="batchexportdestination", name="type", field=models.CharField( - choices=[("S3", "S3"), ("Snowflake", "Snowflake"), ("Postgres", "Postgres"), ("BigQuery", "Bigquery")], + choices=[ + ("S3", "S3"), + ("Snowflake", "Snowflake"), + ("Postgres", "Postgres"), + ("BigQuery", "Bigquery"), + ], help_text="A choice of supported BatchExportDestination types.", max_length=64, ), diff --git a/posthog/migrations/0348_alter_datawarehousetable_format.py b/posthog/migrations/0348_alter_datawarehousetable_format.py index 72434bbc99fdb..d2f464830a957 100644 --- a/posthog/migrations/0348_alter_datawarehousetable_format.py +++ b/posthog/migrations/0348_alter_datawarehousetable_format.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0347_add_bigquery_export_type"), ] @@ -14,7 +13,12 @@ class Migration(migrations.Migration): model_name="datawarehousetable", name="format", field=models.CharField( - choices=[("CSV", "CSV"), ("Parquet", "Parquet"), ("JSONEachRow", "JSON")], max_length=128 + choices=[ + ("CSV", "CSV"), + ("Parquet", "Parquet"), + ("JSONEachRow", "JSON"), + ], + max_length=128, ), ), ] diff --git a/posthog/migrations/0349_update_survey_query_name.py b/posthog/migrations/0349_update_survey_query_name.py index cbcbbb3a0c954..13235cdc67fbc 100644 --- a/posthog/migrations/0349_update_survey_query_name.py +++ b/posthog/migrations/0349_update_survey_query_name.py @@ -5,7 +5,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0348_alter_datawarehousetable_format"), ] diff --git a/posthog/migrations/0350_add_notebook_text_content.py b/posthog/migrations/0350_add_notebook_text_content.py index bfe4b079b9945..b2a5c0c14285f 100644 --- a/posthog/migrations/0350_add_notebook_text_content.py +++ b/posthog/migrations/0350_add_notebook_text_content.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0349_update_survey_query_name"), ] diff --git a/posthog/migrations/0351_team_surveys_opt_in.py b/posthog/migrations/0351_team_surveys_opt_in.py index c1722b7a11000..207677ab8b36d 100644 --- a/posthog/migrations/0351_team_surveys_opt_in.py +++ b/posthog/migrations/0351_team_surveys_opt_in.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0350_add_notebook_text_content"), ] diff --git a/posthog/migrations/0353_add_5_minute_interval_to_batch_exports.py b/posthog/migrations/0353_add_5_minute_interval_to_batch_exports.py index 014edcd509144..3b255ea8a4778 100644 --- a/posthog/migrations/0353_add_5_minute_interval_to_batch_exports.py +++ b/posthog/migrations/0353_add_5_minute_interval_to_batch_exports.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0352_auto_20230926_1833"), ] @@ -14,7 +13,12 @@ class Migration(migrations.Migration): model_name="batchexport", name="interval", field=models.CharField( - choices=[("hour", "hour"), ("day", "day"), ("week", "week"), ("every 5 minutes", "every 5 minutes")], + choices=[ + ("hour", "hour"), + ("day", "day"), + ("week", "week"), + ("every 5 minutes", "every 5 minutes"), + ], default="hour", help_text="The interval at which to export data.", max_length=64, diff --git a/posthog/migrations/0354_organization_never_drop_data.py b/posthog/migrations/0354_organization_never_drop_data.py index 154446df669d5..560f1f518c612 100644 --- a/posthog/migrations/0354_organization_never_drop_data.py +++ b/posthog/migrations/0354_organization_never_drop_data.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0353_add_5_minute_interval_to_batch_exports"), ] diff --git a/posthog/migrations/0355_add_batch_export_backfill_model.py b/posthog/migrations/0355_add_batch_export_backfill_model.py index c558d2a74d7f8..294ad7e019db6 100644 --- a/posthog/migrations/0355_add_batch_export_backfill_model.py +++ b/posthog/migrations/0355_add_batch_export_backfill_model.py @@ -33,11 +33,20 @@ class Migration(migrations.Migration): ( "id", models.UUIDField( - default=posthog.models.utils.UUIDT, editable=False, primary_key=True, serialize=False + default=posthog.models.utils.UUIDT, + editable=False, + primary_key=True, + serialize=False, ), ), - ("start_at", models.DateTimeField(help_text="The start of the data interval.")), - ("end_at", models.DateTimeField(help_text="The end of the data interval.")), + ( + "start_at", + models.DateTimeField(help_text="The start of the data interval."), + ), + ( + "end_at", + models.DateTimeField(help_text="The end of the data interval."), + ), ( "status", models.CharField( @@ -58,7 +67,8 @@ class Migration(migrations.Migration): ( "created_at", models.DateTimeField( - auto_now_add=True, help_text="The timestamp at which this BatchExportBackfill was created." + auto_now_add=True, + help_text="The timestamp at which this BatchExportBackfill was created.", ), ), ( @@ -71,7 +81,8 @@ class Migration(migrations.Migration): ( "last_updated_at", models.DateTimeField( - auto_now=True, help_text="The timestamp at which this BatchExportBackfill was last updated." + auto_now=True, + help_text="The timestamp at which this BatchExportBackfill was last updated.", ), ), ( diff --git a/posthog/migrations/0356_add_replay_cost_control.py b/posthog/migrations/0356_add_replay_cost_control.py index 96c5cb166f4f8..72e04e1d8a46f 100644 --- a/posthog/migrations/0356_add_replay_cost_control.py +++ b/posthog/migrations/0356_add_replay_cost_control.py @@ -6,7 +6,6 @@ class Migration(migrations.Migration): - dependencies = [ ("posthog", "0355_add_batch_export_backfill_model"), ] diff --git a/posthog/models/__init__.py b/posthog/models/__init__.py index 89432e0809984..b5f0586a349bb 100644 --- a/posthog/models/__init__.py +++ b/posthog/models/__init__.py @@ -37,7 +37,13 @@ from .organization_domain import OrganizationDomain from .person import Person, PersonDistinctId, PersonOverride, PersonOverrideMapping from .personal_api_key import PersonalAPIKey -from .plugin import Plugin, PluginAttachment, PluginConfig, PluginSourceFile, PluginLogEntry +from .plugin import ( + Plugin, + PluginAttachment, + PluginConfig, + PluginSourceFile, + PluginLogEntry, +) from .prompt.prompt import Prompt, PromptSequence, UserPromptState from .property import Property from .property_definition import PropertyDefinition @@ -51,8 +57,12 @@ from .user import User, UserManager from .user_scene_personalisation import UserScenePersonalisation from ..session_recordings.models.session_recording import SessionRecording -from ..session_recordings.models.session_recording_playlist import SessionRecordingPlaylist -from ..session_recordings.models.session_recording_playlist_item import SessionRecordingPlaylistItem +from ..session_recordings.models.session_recording_playlist import ( + SessionRecordingPlaylist, +) +from ..session_recordings.models.session_recording_playlist_item import ( + SessionRecordingPlaylistItem, +) __all__ = [ "Action", diff --git a/posthog/models/action/action.py b/posthog/models/action/action.py index 28642eaedeb53..368100fcbc978 100644 --- a/posthog/models/action/action.py +++ b/posthog/models/action/action.py @@ -78,7 +78,10 @@ def refresh_bytecode(self): @receiver(post_save, sender=Action) def action_saved(sender, instance: Action, created, **kwargs): - get_client().publish("reload-action", json.dumps({"teamId": instance.team_id, "actionId": instance.id})) + get_client().publish( + "reload-action", + json.dumps({"teamId": instance.team_id, "actionId": instance.id}), + ) @mutable_receiver(post_delete, sender=Action) diff --git a/posthog/models/action/util.py b/posthog/models/action/util.py index 7a1fcd007f0aa..b67ecf0115dc4 100644 --- a/posthog/models/action/util.py +++ b/posthog/models/action/util.py @@ -35,7 +35,9 @@ def format_action_filter( conditions: List[str] = [] # filter element if step.event == AUTOCAPTURE_EVENT: - from posthog.models.property.util import filter_element # prevent circular import + from posthog.models.property.util import ( + filter_element, + ) # prevent circular import if step.selector: element_condition, element_params = filter_element( diff --git a/posthog/models/action_step.py b/posthog/models/action_step.py index 2f792f1f74d85..036e6fad60d13 100644 --- a/posthog/models/action_step.py +++ b/posthog/models/action_step.py @@ -52,7 +52,8 @@ class ActionStep(models.Model): def action_step_saved(sender, instance: ActionStep, created, **kwargs): instance.action.refresh_bytecode() get_client().publish( - "reload-action", json.dumps({"teamId": instance.action.team_id, "actionId": instance.action.id}) + "reload-action", + json.dumps({"teamId": instance.action.team_id, "actionId": instance.action.id}), ) @@ -60,5 +61,6 @@ def action_step_saved(sender, instance: ActionStep, created, **kwargs): def action_step_deleted(sender, instance: ActionStep, **kwargs): instance.action.refresh_bytecode() get_client().publish( - "reload-action", json.dumps({"teamId": instance.action.team_id, "actionId": instance.action.id}) + "reload-action", + json.dumps({"teamId": instance.action.team_id, "actionId": instance.action.id}), ) diff --git a/posthog/models/activity_logging/activity_log.py b/posthog/models/activity_logging/activity_log.py index f3b36e2c3dbd0..94a9c0914faf6 100644 --- a/posthog/models/activity_logging/activity_log.py +++ b/posthog/models/activity_logging/activity_log.py @@ -99,8 +99,23 @@ class Meta: field_exclusions: Dict[ActivityScope, List[str]] = { - "Notebook": ["id", "last_modified_at", "last_modified_by", "created_at", "created_by", "text_content"], - "FeatureFlag": ["id", "created_at", "created_by", "is_simple_flag", "experiment", "team", "featureflagoverride"], + "Notebook": [ + "id", + "last_modified_at", + "last_modified_by", + "created_at", + "created_by", + "text_content", + ], + "FeatureFlag": [ + "id", + "created_at", + "created_by", + "is_simple_flag", + "experiment", + "team", + "featureflagoverride", + ], "Person": [ "id", "uuid", @@ -143,7 +158,14 @@ class Meta: "dashboardtile", "caching_states", ], - "SessionRecordingPlaylist": ["id", "short_id", "created_at", "created_by", "last_modified_at", "last_modified_by"], + "SessionRecordingPlaylist": [ + "id", + "short_id", + "created_at", + "created_by", + "last_modified_at", + "last_modified_by", + ], "EventDefinition": [ "eventdefinition_ptr_id", "id", @@ -246,13 +268,24 @@ def changes_between( elif right is None and left is not None: changes.append(Change(type=model_type, field=field, action="deleted", before=left)) elif left != right: - changes.append(Change(type=model_type, field=field, action="changed", before=left, after=right)) + changes.append( + Change( + type=model_type, + field=field, + action="changed", + before=left, + after=right, + ) + ) return changes def dict_changes_between( - model_type: ActivityScope, previous: Dict[Any, Any], new: Dict[Any, Any], use_field_exclusions: bool = False + model_type: ActivityScope, + previous: Dict[Any, Any], + new: Dict[Any, Any], + use_field_exclusions: bool = False, ) -> List[Change]: """ Identifies changes between two dictionaries by comparing fields @@ -276,10 +309,23 @@ def dict_changes_between( if previous_value is None and new_value is not None: changes.append(Change(type=model_type, field=field, action="created", after=new_value)) elif new_value is None and previous_value is not None: - changes.append(Change(type=model_type, field=field, action="deleted", before=previous_value)) + changes.append( + Change( + type=model_type, + field=field, + action="deleted", + before=previous_value, + ) + ) elif previous_value != new_value: changes.append( - Change(type=model_type, field=field, action="changed", before=previous_value, after=new_value) + Change( + type=model_type, + field=field, + action="changed", + before=previous_value, + after=new_value, + ) ) return changes @@ -350,7 +396,11 @@ def get_activity_page(activity_query: models.QuerySet, limit: int = 10, page: in def load_activity( - scope: ActivityScope, team_id: int, item_id: Optional[int] = None, limit: int = 10, page: int = 1 + scope: ActivityScope, + team_id: int, + item_id: Optional[int] = None, + limit: int = 10, + page: int = 1, ) -> ActivityPage: # TODO in follow-up to posthog #8931 selecting specific fields into a return type from this query diff --git a/posthog/models/app_metrics/sql.py b/posthog/models/app_metrics/sql.py index 3198b3226e52b..65d1de6de3060 100644 --- a/posthog/models/app_metrics/sql.py +++ b/posthog/models/app_metrics/sql.py @@ -1,7 +1,11 @@ from django.conf import settings from posthog.clickhouse.kafka_engine import KAFKA_COLUMNS_WITH_PARTITION, kafka_engine -from posthog.clickhouse.table_engines import AggregatingMergeTree, Distributed, ReplicationScheme +from posthog.clickhouse.table_engines import ( + AggregatingMergeTree, + Distributed, + ReplicationScheme, +) from posthog.kafka_client.topics import KAFKA_APP_METRICS SHARDED_APP_METRICS_TABLE_ENGINE = lambda: AggregatingMergeTree( diff --git a/posthog/models/async_deletion/async_deletion.py b/posthog/models/async_deletion/async_deletion.py index 513657f73daae..a851fa513f526 100644 --- a/posthog/models/async_deletion/async_deletion.py +++ b/posthog/models/async_deletion/async_deletion.py @@ -21,7 +21,8 @@ class Meta: condition=models.Q(group_type_index__isnull=True), ), models.UniqueConstraint( - name="unique deletion for groups", fields=["deletion_type", "key", "group_type_index"] + name="unique deletion for groups", + fields=["deletion_type", "key", "group_type_index"], ), ] indexes = [models.Index(name="delete_verified_at index", fields=["delete_verified_at"])] diff --git a/posthog/models/async_deletion/delete.py b/posthog/models/async_deletion/delete.py index 378d655a02714..7774cf2384016 100644 --- a/posthog/models/async_deletion/delete.py +++ b/posthog/models/async_deletion/delete.py @@ -41,7 +41,10 @@ def mark_deletions_done(self): AsyncDeletion.objects.filter(pk__in=[row.pk for row in to_verify]).update(delete_verified_at=timezone.now()) logger.warn( "Updated `delete_verified_at` for AsyncDeletion", - {"count": len(to_verify), "team_ids": list(set(row.team_id for row in to_verify))}, + { + "count": len(to_verify), + "team_ids": list(set(row.team_id for row in to_verify)), + }, ) def _fetch_unverified_deletions_grouped(self): diff --git a/posthog/models/async_deletion/delete_cohorts.py b/posthog/models/async_deletion/delete_cohorts.py index a71f16ae26cd0..3a4737c221964 100644 --- a/posthog/models/async_deletion/delete_cohorts.py +++ b/posthog/models/async_deletion/delete_cohorts.py @@ -15,7 +15,10 @@ def process(self, deletions: List[AsyncDeletion]): logger.warn( "Starting AsyncDeletion on `cohortpeople` table in ClickHouse", - {"count": len(deletions), "team_ids": list(set(row.team_id for row in deletions))}, + { + "count": len(deletions), + "team_ids": list(set(row.team_id for row in deletions)), + }, ) conditions, args = self._conditions(deletions) @@ -62,13 +65,20 @@ def _condition(self, async_deletion: AsyncDeletion, suffix: str) -> Tuple[str, D version_param = f"version{suffix}" if async_deletion.deletion_type == DeletionType.Cohort_full: key, _ = async_deletion.key.split("_") - return f"( team_id = %({team_id_param})s AND {self._column_name(async_deletion)} = %({key_param})s )", { - team_id_param: async_deletion.team_id, - key_param: key, - } + return ( + f"( team_id = %({team_id_param})s AND {self._column_name(async_deletion)} = %({key_param})s )", + { + team_id_param: async_deletion.team_id, + key_param: key, + }, + ) else: key, version = async_deletion.key.split("_") return ( f"( team_id = %({team_id_param})s AND {self._column_name(async_deletion)} = %({key_param})s AND version < %({version_param})s )", - {team_id_param: async_deletion.team_id, version_param: version, key_param: key}, + { + team_id_param: async_deletion.team_id, + version_param: version, + key_param: key, + }, ) diff --git a/posthog/models/async_deletion/delete_events.py b/posthog/models/async_deletion/delete_events.py index 5529ca8a95843..cef9c97688f85 100644 --- a/posthog/models/async_deletion/delete_events.py +++ b/posthog/models/async_deletion/delete_events.py @@ -27,7 +27,10 @@ def process(self, deletions: List[AsyncDeletion]): logger.info( "Starting AsyncDeletion on `events` table in ClickHouse", - {"count": len(deletions), "team_ids": list(set(row.team_id for row in deletions))}, + { + "count": len(deletions), + "team_ids": list(set(row.team_id for row in deletions)), + }, ) conditions, args = self._conditions(deletions) @@ -48,7 +51,10 @@ def process(self, deletions: List[AsyncDeletion]): logger.info( "Starting AsyncDeletion for teams on other tables", - {"count": len(team_deletions), "team_ids": list(set(row.team_id for row in deletions))}, + { + "count": len(team_deletions), + "team_ids": list(set(row.team_id for row in deletions)), + }, ) conditions, args = self._conditions(team_deletions) for table in TABLES_TO_DELETE_TEAM_DATA_FROM: @@ -97,5 +103,8 @@ def _condition(self, async_deletion: AsyncDeletion, suffix: str) -> Tuple[str, D else: return ( f"(team_id = %(team_id{suffix})s AND {self._column_name(async_deletion)} = %(key{suffix})s)", - {f"team_id{suffix}": async_deletion.team_id, f"key{suffix}": async_deletion.key}, + { + f"team_id{suffix}": async_deletion.team_id, + f"key{suffix}": async_deletion.key, + }, ) diff --git a/posthog/models/async_migration.py b/posthog/models/async_migration.py index 885f7ce397931..ab60eed94d0c5 100644 --- a/posthog/models/async_migration.py +++ b/posthog/models/async_migration.py @@ -33,7 +33,7 @@ class Meta: null=False, blank=False, default=MigrationStatus.NotStarted ) - current_operation_index: models.PositiveSmallIntegerField = models.PositiveSmallIntegerField( + current_operation_index: (models.PositiveSmallIntegerField) = models.PositiveSmallIntegerField( null=False, blank=False, default=0 ) current_query_id: models.CharField = models.CharField(max_length=100, null=False, blank=False, default="") diff --git a/posthog/models/cohort/cohort.py b/posthog/models/cohort/cohort.py index b101a0fa68bf6..b907df41c934a 100644 --- a/posthog/models/cohort/cohort.py +++ b/posthog/models/cohort/cohort.py @@ -193,7 +193,12 @@ def calculate_people_ch(self, pending_version): from posthog.models.cohort.util import recalculate_cohortpeople from posthog.tasks.calculate_cohort import clear_stale_cohort - logger.warn("cohort_calculation_started", id=self.pk, current_version=self.version, new_version=pending_version) + logger.warn( + "cohort_calculation_started", + id=self.pk, + current_version=self.version, + new_version=pending_version, + ) start_time = time.monotonic() try: @@ -237,7 +242,10 @@ def insert_users_by_list(self, items: List[str]) -> None: """ batchsize = 1000 - from posthog.models.cohort.util import insert_static_cohort, get_static_cohort_size + from posthog.models.cohort.util import ( + insert_static_cohort, + get_static_cohort_size, + ) if TEST: from posthog.test.base import flush_persons_and_events @@ -251,15 +259,26 @@ def insert_users_by_list(self, items: List[str]) -> None: batch = items[i : i + batchsize] persons_query = ( Person.objects.filter(team_id=self.team_id) - .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) ) - 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() query = UPDATE_QUERY.format( cohort_id=self.pk, values_query=sql.replace( - 'FROM "posthog_person"', f', {self.pk}, {self.version or "NULL"} FROM "posthog_person"', 1 + 'FROM "posthog_person"', + f', {self.pk}, {self.version or "NULL"} FROM "posthog_person"', + 1, ), ) cursor.execute(query, params) @@ -294,7 +313,9 @@ def insert_users_list_by_uuid(self, items: List[str]) -> None: query = UPDATE_QUERY.format( cohort_id=self.pk, values_query=sql.replace( - 'FROM "posthog_person"', f', {self.pk}, {self.version or "NULL"} FROM "posthog_person"', 1 + 'FROM "posthog_person"', + f', {self.pk}, {self.version or "NULL"} FROM "posthog_person"', + 1, ), ) cursor.execute(query, params) diff --git a/posthog/models/cohort/sql.py b/posthog/models/cohort/sql.py index b73662931aeb2..821e84e29fd37 100644 --- a/posthog/models/cohort/sql.py +++ b/posthog/models/cohort/sql.py @@ -19,7 +19,9 @@ Order By (team_id, cohort_id, person_id, version) {storage_policy} """.format( - cluster=CLICKHOUSE_CLUSTER, engine=COHORTPEOPLE_TABLE_ENGINE(), storage_policy="" + cluster=CLICKHOUSE_CLUSTER, + engine=COHORTPEOPLE_TABLE_ENGINE(), + storage_policy="", ) TRUNCATE_COHORTPEOPLE_TABLE_SQL = f"TRUNCATE TABLE IF EXISTS cohortpeople ON CLUSTER '{CLICKHOUSE_CLUSTER}'" diff --git a/posthog/models/cohort/test/test_util.py b/posthog/models/cohort/test/test_util.py index 7db7d6a5e0130..d8ff051a0bb41 100644 --- a/posthog/models/cohort/test/test_util.py +++ b/posthog/models/cohort/test/test_util.py @@ -1,5 +1,8 @@ from posthog.models.cohort import Cohort -from posthog.models.cohort.util import get_dependent_cohorts, simplified_cohort_filter_properties +from posthog.models.cohort.util import ( + get_dependent_cohorts, + simplified_cohort_filter_properties, +) from posthog.test.base import BaseTest, _create_person, flush_persons_and_events @@ -14,8 +17,11 @@ def _create_cohort(**kwargs): class TestCohortUtils(BaseTest): def test_simplified_cohort_filter_properties_static_cohort(self): - - _create_person(team_id=self.team.pk, distinct_ids=["p1"], properties={"name": "test", "name": "test"}) + _create_person( + team_id=self.team.pk, + distinct_ids=["p1"], + properties={"name": "test", "name": "test"}, + ) cohort = _create_cohort(team=self.team, name="cohort1", groups=[], is_static=True) flush_persons_and_events() cohort.insert_users_by_list(["p1"]) @@ -24,12 +30,25 @@ def test_simplified_cohort_filter_properties_static_cohort(self): self.assertEqual( result.to_dict(), - {"type": "AND", "values": [{"key": "id", "negation": False, "type": "static-cohort", "value": cohort.pk}]}, + { + "type": "AND", + "values": [ + { + "key": "id", + "negation": False, + "type": "static-cohort", + "value": cohort.pk, + } + ], + }, ) def test_simplified_cohort_filter_properties_static_cohort_with_negation(self): - - _create_person(team_id=self.team.pk, distinct_ids=["p1"], properties={"name": "test", "name": "test"}) + _create_person( + team_id=self.team.pk, + distinct_ids=["p1"], + properties={"name": "test", "name": "test"}, + ) cohort = _create_cohort(team=self.team, name="cohort1", groups=[], is_static=True) flush_persons_and_events() cohort.insert_users_by_list(["p1"]) @@ -38,7 +57,17 @@ def test_simplified_cohort_filter_properties_static_cohort_with_negation(self): self.assertEqual( result.to_dict(), - {"type": "AND", "values": [{"key": "id", "negation": True, "type": "static-cohort", "value": cohort.pk}]}, + { + "type": "AND", + "values": [ + { + "key": "id", + "negation": True, + "type": "static-cohort", + "value": cohort.pk, + } + ], + }, ) def test_simplified_cohort_filter_properties_precalculated_cohort(self): @@ -57,7 +86,14 @@ def test_simplified_cohort_filter_properties_precalculated_cohort(self): result.to_dict(), { "type": "AND", - "values": [{"key": "id", "negation": False, "type": "precalculated-cohort", "value": cohort.pk}], + "values": [ + { + "key": "id", + "negation": False, + "type": "precalculated-cohort", + "value": cohort.pk, + } + ], }, ) @@ -77,7 +113,14 @@ def test_simplified_cohort_filter_properties_precalculated_cohort_negated(self): result.to_dict(), { "type": "AND", - "values": [{"key": "id", "negation": True, "type": "precalculated-cohort", "value": cohort.pk}], + "values": [ + { + "key": "id", + "negation": True, + "type": "precalculated-cohort", + "value": cohort.pk, + } + ], }, ) @@ -113,7 +156,17 @@ def test_simplified_cohort_filter_properties_non_precalculated_cohort_with_behav self.assertEqual( result.to_dict(), - {"type": "AND", "values": [{"key": "id", "negation": False, "type": "cohort", "value": cohort.pk}]}, + { + "type": "AND", + "values": [ + { + "key": "id", + "negation": False, + "type": "cohort", + "value": cohort.pk, + } + ], + }, ) # with negation @@ -122,7 +175,17 @@ def test_simplified_cohort_filter_properties_non_precalculated_cohort_with_behav self.assertEqual( result.to_dict(), - {"type": "AND", "values": [{"key": "id", "negation": True, "type": "cohort", "value": cohort.pk}]}, + { + "type": "AND", + "values": [ + { + "key": "id", + "negation": True, + "type": "cohort", + "value": cohort.pk, + } + ], + }, ) def test_simplified_cohort_filter_properties_non_precalculated_cohort_with_cohort_filter(self): @@ -139,7 +202,12 @@ def test_simplified_cohort_filter_properties_non_precalculated_cohort_with_cohor "type": "AND", "values": [ {"key": "name", "value": "test", "type": "person"}, - {"key": "id", "value": cohort1.pk, "type": "cohort", "negation": True}, + { + "key": "id", + "value": cohort1.pk, + "type": "cohort", + "negation": True, + }, ], } }, @@ -154,11 +222,19 @@ def test_simplified_cohort_filter_properties_non_precalculated_cohort_with_cohor { "type": "AND", "values": [ - {"type": "AND", "values": [{"key": "name", "value": "test", "type": "person"}]}, + { + "type": "AND", + "values": [{"key": "name", "value": "test", "type": "person"}], + }, { "type": "AND", "values": [ - {"key": "id", "value": cohort1.pk, "type": "cohort", "negation": True}, + { + "key": "id", + "value": cohort1.pk, + "type": "cohort", + "negation": True, + }, ], }, ], @@ -171,7 +247,17 @@ def test_simplified_cohort_filter_properties_non_precalculated_cohort_with_cohor self.assertEqual( result.to_dict(), - {"type": "AND", "values": [{"key": "id", "negation": True, "type": "cohort", "value": cohort.pk}]}, + { + "type": "AND", + "values": [ + { + "key": "id", + "negation": True, + "type": "cohort", + "value": cohort.pk, + } + ], + }, ) def test_simplified_cohort_filter_properties_non_precalculated_cohort_with_only_person_property_filters(self): @@ -182,7 +268,10 @@ def test_simplified_cohort_filter_properties_non_precalculated_cohort_with_only_ "properties": { "type": "OR", "values": [ - {"type": "AND", "values": [{"key": "name", "value": "test", "type": "person"}]}, + { + "type": "AND", + "values": [{"key": "name", "value": "test", "type": "person"}], + }, { "type": "OR", "values": [ @@ -204,7 +293,10 @@ def test_simplified_cohort_filter_properties_non_precalculated_cohort_with_only_ { "type": "OR", "values": [ - {"type": "AND", "values": [{"key": "name", "value": "test", "type": "person"}]}, + { + "type": "AND", + "values": [{"key": "name", "value": "test", "type": "person"}], + }, { "type": "OR", "values": [ @@ -222,7 +314,17 @@ def test_simplified_cohort_filter_properties_non_precalculated_cohort_with_only_ self.assertEqual( result.to_dict(), - {"type": "AND", "values": [{"key": "id", "negation": True, "type": "cohort", "value": cohort.pk}]}, + { + "type": "AND", + "values": [ + { + "key": "id", + "negation": True, + "type": "cohort", + "value": cohort.pk, + } + ], + }, ) @@ -268,7 +370,18 @@ def test_dependent_cohorts_for_deeply_nested_cohort(self): cohort3 = _create_cohort( team=self.team, name="cohort3", - groups=[{"properties": [{"key": "id", "value": cohort2.pk, "type": "cohort", "negation": True}]}], + groups=[ + { + "properties": [ + { + "key": "id", + "value": cohort2.pk, + "type": "cohort", + "negation": True, + } + ] + } + ], ) self.assertEqual(get_dependent_cohorts(cohort1), []) @@ -291,7 +404,18 @@ def test_dependent_cohorts_for_circular_nested_cohort(self): cohort3 = _create_cohort( team=self.team, name="cohort1", - groups=[{"properties": [{"key": "id", "value": cohort2.pk, "type": "cohort", "negation": True}]}], + groups=[ + { + "properties": [ + { + "key": "id", + "value": cohort2.pk, + "type": "cohort", + "negation": True, + } + ] + } + ], ) cohort1.groups = [{"properties": [{"key": "id", "value": cohort3.pk, "type": "cohort"}]}] @@ -328,7 +452,12 @@ def test_dependent_cohorts_for_complex_nested_cohort(self): { "properties": [ {"key": "name", "value": "test3", "type": "person"}, - {"key": "id", "value": cohort2.pk, "type": "cohort", "negation": True}, + { + "key": "id", + "value": cohort2.pk, + "type": "cohort", + "negation": True, + }, ] } ], @@ -337,7 +466,18 @@ def test_dependent_cohorts_for_complex_nested_cohort(self): cohort4 = _create_cohort( team=self.team, name="cohort1", - groups=[{"properties": [{"key": "id", "value": cohort1.pk, "type": "cohort", "negation": True}]}], + groups=[ + { + "properties": [ + { + "key": "id", + "value": cohort1.pk, + "type": "cohort", + "negation": True, + } + ] + } + ], ) cohort5 = _create_cohort( @@ -346,8 +486,18 @@ def test_dependent_cohorts_for_complex_nested_cohort(self): groups=[ { "properties": [ - {"key": "id", "value": cohort2.pk, "type": "cohort", "negation": True}, - {"key": "id", "value": cohort4.pk, "type": "cohort", "negation": True}, + { + "key": "id", + "value": cohort2.pk, + "type": "cohort", + "negation": True, + }, + { + "key": "id", + "value": cohort4.pk, + "type": "cohort", + "negation": True, + }, ] } ], diff --git a/posthog/models/cohort/util.py b/posthog/models/cohort/util.py index c5b8c39ec4f1d..800b937d51f15 100644 --- a/posthog/models/cohort/util.py +++ b/posthog/models/cohort/util.py @@ -52,7 +52,11 @@ def format_person_query(cohort: Cohort, index: int, hogql_context: HogQLContext) from posthog.queries.cohort_query import CohortQuery query_builder = CohortQuery( - Filter(data={"properties": cohort.properties}, team=cohort.team, hogql_context=hogql_context), + Filter( + data={"properties": cohort.properties}, + team=cohort.team, + hogql_context=hogql_context, + ), cohort.team, cohort_pk=cohort.pk, ) @@ -72,7 +76,13 @@ def format_static_cohort_query(cohort: Cohort, index: int, prepend: str) -> Tupl def format_precalculated_cohort_query(cohort: Cohort, index: int, prepend: str = "") -> Tuple[str, Dict[str, Any]]: filter_query = GET_PERSON_ID_BY_PRECALCULATED_COHORT_ID.format(index=index, prepend=prepend) - return (filter_query, {f"{prepend}_cohort_id_{index}": cohort.pk, f"{prepend}_version_{index}": cohort.version}) + return ( + filter_query, + { + f"{prepend}_cohort_id_{index}": cohort.pk, + f"{prepend}_version_{index}": cohort.version, + }, + ) def get_count_operator(count_operator: Optional[str]) -> str: @@ -102,7 +112,10 @@ def get_entity_query( elif action_id: action = Action.objects.get(pk=action_id, team_id=team_id) action_filter_query, action_params = format_action_filter( - team_id=team_id, action=action, prepend="_{}_action".format(group_idx), hogql_context=hogql_context + team_id=team_id, + action=action, + prepend="_{}_action".format(group_idx), + hogql_context=hogql_context, ) return action_filter_query, action_params else: @@ -128,7 +141,10 @@ def parse_entity_timestamps_in_days(days: int) -> Tuple[str, Dict[str, str]]: return ( "AND timestamp >= %(date_from)s AND timestamp <= %(date_to)s", - {"date_from": start_time.strftime("%Y-%m-%d %H:%M:%S"), "date_to": curr_time.strftime("%Y-%m-%d %H:%M:%S")}, + { + "date_from": start_time.strftime("%Y-%m-%d %H:%M:%S"), + "date_to": curr_time.strftime("%Y-%m-%d %H:%M:%S"), + }, ) @@ -142,7 +158,10 @@ def parse_cohort_timestamps(start_time: Optional[str], end_time: Optional[str]) params = {"date_from": datetime.strptime(start_time, "%Y-%m-%dT%H:%M:%S").strftime("%Y-%m-%d %H:%M:%S")} if end_time: clause += "timestamp <= %(date_to)s" - params = {**params, "date_to": datetime.strptime(end_time, "%Y-%m-%dT%H:%M:%S").strftime("%Y-%m-%d %H:%M:%S")} + params = { + **params, + "date_to": datetime.strptime(end_time, "%Y-%m-%dT%H:%M:%S").strftime("%Y-%m-%d %H:%M:%S"), + } return clause, params @@ -177,7 +196,10 @@ def format_filter_query( def format_cohort_subquery( - cohort: Cohort, index: int, hogql_context: HogQLContext, custom_match_field="person_id" + cohort: Cohort, + index: int, + hogql_context: HogQLContext, + custom_match_field="person_id", ) -> Tuple[str, Dict[str, Any]]: is_precalculated = is_precalculated_query(cohort) if is_precalculated: @@ -189,7 +211,12 @@ def format_cohort_subquery( return person_query, params -def get_person_ids_by_cohort_id(team: Team, cohort_id: int, limit: Optional[int] = None, offset: Optional[int] = None): +def get_person_ids_by_cohort_id( + team: Team, + cohort_id: int, + limit: Optional[int] = None, + offset: Optional[int] = None, +): from posthog.models.property.util import parse_prop_grouped_clauses filter = Filter(data={"properties": [{"key": "id", "value": cohort_id, "type": "cohort"}]}) @@ -254,7 +281,10 @@ def recalculate_cohortpeople(cohort: Cohort, pending_version: int) -> Optional[i if before_count: logger.warn( - "Recalculating cohortpeople starting", team_id=cohort.team_id, cohort_id=cohort.pk, size_before=before_count + "Recalculating cohortpeople starting", + team_id=cohort.team_id, + cohort_id=cohort.pk, + size_before=before_count, ) recalcluate_cohortpeople_sql = RECALCULATE_COHORT_BY_ID.format(cohort_filter=cohort_query) @@ -289,7 +319,11 @@ def clear_stale_cohortpeople(cohort: Cohort, before_version: int) -> None: if cohort.version and cohort.version > 0: stale_count_result = sync_execute( STALE_COHORTPEOPLE, - {"cohort_id": cohort.pk, "team_id": cohort.team_id, "version": before_version}, + { + "cohort_id": cohort.pk, + "team_id": cohort.team_id, + "version": before_version, + }, ) if stale_count_result and len(stale_count_result) and len(stale_count_result[0]): @@ -333,7 +367,14 @@ def simplified_cohort_filter_properties(cohort: Cohort, team: Team, is_negated=F if is_precalculated_query(cohort): return PropertyGroup( type=PropertyOperatorType.AND, - values=[Property(type="precalculated-cohort", key="id", value=cohort.pk, negation=is_negated)], + values=[ + Property( + type="precalculated-cohort", + key="id", + value=cohort.pk, + negation=is_negated, + ) + ], ) # Cohort can have multiple match groups. @@ -356,7 +397,14 @@ def simplified_cohort_filter_properties(cohort: Cohort, team: Team, is_negated=F if is_negated: return PropertyGroup( type=PropertyOperatorType.AND, - values=[Property(type="cohort", key="id", value=cohort.pk, negation=is_negated)], + values=[ + Property( + type="cohort", + key="id", + value=cohort.pk, + negation=is_negated, + ) + ], ) # :TRICKY: We need to ensure we don't have infinite loops in here # guaranteed during cohort creation @@ -390,7 +438,9 @@ def get_all_cohort_ids_by_person_uuid(uuid: str, team_id: int) -> List[int]: def get_dependent_cohorts( - cohort: Cohort, using_database: str = "default", seen_cohorts_cache: Optional[Dict[str, Cohort]] = None + cohort: Cohort, + using_database: str = "default", + seen_cohorts_cache: Optional[Dict[str, Cohort]] = None, ) -> List[Cohort]: if seen_cohorts_cache is None: seen_cohorts_cache = {} diff --git a/posthog/models/dashboard.py b/posthog/models/dashboard.py index d2a477d97e0f8..f20fc9fdcb0f2 100644 --- a/posthog/models/dashboard.py +++ b/posthog/models/dashboard.py @@ -18,14 +18,23 @@ class Dashboard(models.Model): class CreationMode(models.TextChoices): DEFAULT = "default", "Default" - TEMPLATE = "template", "Template" # dashboard was created from a predefined template - DUPLICATE = "duplicate", "Duplicate" # dashboard was duplicated from another dashboard + TEMPLATE = ( + "template", + "Template", + ) # dashboard was created from a predefined template + DUPLICATE = ( + "duplicate", + "Duplicate", + ) # dashboard was duplicated from another dashboard class RestrictionLevel(models.IntegerChoices): """Collaboration restriction level (which is a dashboard setting). Sync with PrivilegeLevel.""" EVERYONE_IN_PROJECT_CAN_EDIT = 21, "Everyone in the project can edit" - ONLY_COLLABORATORS_CAN_EDIT = 37, "Only those invited to this dashboard can edit" + ONLY_COLLABORATORS_CAN_EDIT = ( + 37, + "Only those invited to this dashboard can edit", + ) class PrivilegeLevel(models.IntegerChoices): """Collaboration privilege level (which is a user property). Sync with RestrictionLevel.""" @@ -43,15 +52,25 @@ class PrivilegeLevel(models.IntegerChoices): last_accessed_at: models.DateTimeField = models.DateTimeField(blank=True, null=True) filters: models.JSONField = models.JSONField(default=dict) creation_mode: models.CharField = models.CharField(max_length=16, default="default", choices=CreationMode.choices) - restriction_level: models.PositiveSmallIntegerField = models.PositiveSmallIntegerField( - default=RestrictionLevel.EVERYONE_IN_PROJECT_CAN_EDIT, choices=RestrictionLevel.choices + restriction_level: (models.PositiveSmallIntegerField) = models.PositiveSmallIntegerField( + default=RestrictionLevel.EVERYONE_IN_PROJECT_CAN_EDIT, + choices=RestrictionLevel.choices, + ) + insights = models.ManyToManyField( + "posthog.Insight", + related_name="dashboards", + through="DashboardTile", + blank=True, ) - insights = models.ManyToManyField("posthog.Insight", related_name="dashboards", through="DashboardTile", blank=True) # Deprecated in favour of app-wide tagging model. See EnterpriseTaggedItem deprecated_tags: ArrayField = ArrayField(models.CharField(max_length=32), null=True, blank=True, default=list) deprecated_tags_v2: ArrayField = ArrayField( - models.CharField(max_length=32), null=True, blank=True, default=None, db_column="tags" + models.CharField(max_length=32), + null=True, + blank=True, + default=None, + db_column="tags", ) # DEPRECATED: using the new "sharing" relation instead diff --git a/posthog/models/dashboard_tile.py b/posthog/models/dashboard_tile.py index ed4a885bfc1c1..7cc6b2601cb62 100644 --- a/posthog/models/dashboard_tile.py +++ b/posthog/models/dashboard_tile.py @@ -16,7 +16,11 @@ class Text(models.Model): created_by: models.ForeignKey = models.ForeignKey("User", on_delete=models.SET_NULL, null=True, blank=True) last_modified_at: models.DateTimeField = models.DateTimeField(default=timezone.now) last_modified_by: models.ForeignKey = models.ForeignKey( - "User", on_delete=models.SET_NULL, null=True, blank=True, related_name="modified_text_tiles" + "User", + on_delete=models.SET_NULL, + null=True, + blank=True, + related_name="modified_text_tiles", ) team: models.ForeignKey = models.ForeignKey("Team", on_delete=models.CASCADE) @@ -33,8 +37,18 @@ class DashboardTile(models.Model): # Relations dashboard = models.ForeignKey("posthog.Dashboard", on_delete=models.CASCADE, related_name="tiles") - insight = models.ForeignKey("posthog.Insight", on_delete=models.CASCADE, related_name="dashboard_tiles", null=True) - text = models.ForeignKey("posthog.Text", on_delete=models.CASCADE, related_name="dashboard_tiles", null=True) + insight = models.ForeignKey( + "posthog.Insight", + on_delete=models.CASCADE, + related_name="dashboard_tiles", + null=True, + ) + text = models.ForeignKey( + "posthog.Text", + on_delete=models.CASCADE, + related_name="dashboard_tiles", + null=True, + ) # Tile layout and style layouts: models.JSONField = models.JSONField(default=dict) @@ -57,9 +71,14 @@ class Meta: condition=Q(("insight__isnull", False)), ), UniqueConstraint( - fields=["dashboard", "text"], name=f"unique_dashboard_text", condition=Q(("text__isnull", False)) + fields=["dashboard", "text"], + name=f"unique_dashboard_text", + condition=Q(("text__isnull", False)), + ), + models.CheckConstraint( + check=build_check(("insight", "text")), + name="dash_tile_exactly_one_related_object", ), - models.CheckConstraint(check=build_check(("insight", "text")), name="dash_tile_exactly_one_related_object"), ] @property @@ -94,7 +113,11 @@ def save(self, *args, **kwargs) -> None: def copy_to_dashboard(self, dashboard: Dashboard) -> None: DashboardTile.objects.create( - dashboard=dashboard, insight=self.insight, text=self.text, color=self.color, layouts=self.layouts + dashboard=dashboard, + insight=self.insight, + text=self.text, + color=self.color, + layouts=self.layouts, ) @staticmethod diff --git a/posthog/models/early_access_feature.py b/posthog/models/early_access_feature.py index e73c463b96a09..3ec1c99543b9a 100644 --- a/posthog/models/early_access_feature.py +++ b/posthog/models/early_access_feature.py @@ -12,7 +12,10 @@ class Stage(models.TextChoices): ARCHIVED = "archived", "archived" team: models.ForeignKey = models.ForeignKey( - "posthog.Team", on_delete=models.CASCADE, related_name="features", related_query_name="feature" + "posthog.Team", + on_delete=models.CASCADE, + related_name="features", + related_query_name="feature", ) feature_flag: models.ForeignKey = models.ForeignKey( "posthog.FeatureFlag", diff --git a/posthog/models/element_group.py b/posthog/models/element_group.py index d248ba9d25739..3d399f2559844 100644 --- a/posthog/models/element_group.py +++ b/posthog/models/element_group.py @@ -30,7 +30,8 @@ def create(self, *args: Any, **kwargs: Any): group = super().create(*args, **kwargs) except: return ElementGroup.objects.get( - hash=kwargs["hash"], team_id=kwargs["team"].pk if kwargs.get("team") else kwargs["team_id"] + hash=kwargs["hash"], + team_id=kwargs["team"].pk if kwargs.get("team") else kwargs["team_id"], ) for element in elements: element.group = group diff --git a/posthog/models/entity/entity.py b/posthog/models/entity/entity.py index 8f62e5ea98aba..aced3a18a8842 100644 --- a/posthog/models/entity/entity.py +++ b/posthog/models/entity/entity.py @@ -65,7 +65,10 @@ class Entity(PropertyMixin): def __init__(self, data: Dict[str, Any]) -> None: self.id = data.get("id") - if data.get("type") not in [TREND_FILTER_TYPE_ACTIONS, TREND_FILTER_TYPE_EVENTS]: + if data.get("type") not in [ + TREND_FILTER_TYPE_ACTIONS, + TREND_FILTER_TYPE_EVENTS, + ]: raise ValueError("Type needs to be either TREND_FILTER_TYPE_ACTIONS or TREND_FILTER_TYPE_EVENTS") self.type = data["type"] order_provided = data.get("order") @@ -150,7 +153,15 @@ def get_action(self) -> Action: raise ValidationError(f"Action ID {self.id} does not exist!") __repr__ = sane_repr( - "id", "type", "order", "name", "custom_name", "math", "math_property", "math_hogql", "properties" + "id", + "type", + "order", + "name", + "custom_name", + "math", + "math_property", + "math_hogql", + "properties", ) diff --git a/posthog/models/event/query_event_list.py b/posthog/models/event/query_event_list.py index 527bfb62645ea..de70d511da156 100644 --- a/posthog/models/event/query_event_list.py +++ b/posthog/models/event/query_event_list.py @@ -87,7 +87,10 @@ def query_events_list( tzinfo=team.timezone_info, ) prop_filters, prop_filter_params = parse_prop_grouped_clauses( - team_id=team.pk, property_group=filter.property_groups, has_person_id_joined=False, hogql_context=hogql_context + team_id=team.pk, + property_group=filter.property_groups, + has_person_id_joined=False, + hogql_context=hogql_context, ) if action_id: @@ -106,7 +109,10 @@ def query_events_list( if prop_filters != "": return insight_query_with_columns( SELECT_EVENT_BY_TEAM_AND_CONDITIONS_FILTERS_SQL.format( - conditions=conditions, limit=limit_sql, filters=prop_filters, order=order + conditions=conditions, + limit=limit_sql, + filters=prop_filters, + order=order, ), { "team_id": team.pk, diff --git a/posthog/models/event/util.py b/posthog/models/event/util.py index 7deb2ee87b291..2cd36b34e1dd2 100644 --- a/posthog/models/event/util.py +++ b/posthog/models/event/util.py @@ -12,7 +12,11 @@ from posthog.kafka_client.client import ClickhouseProducer from posthog.kafka_client.topics import KAFKA_EVENTS_JSON from posthog.models import Group -from posthog.models.element.element import Element, chain_to_elements, elements_to_string +from posthog.models.element.element import ( + Element, + chain_to_elements, + elements_to_string, +) from posthog.models.event.sql import BULK_INSERT_EVENT_SQL, INSERT_EVENT_SQL from posthog.models.person import Person from posthog.models.team import Team @@ -167,7 +171,8 @@ def bulk_create_events(events: List[Dict[str, Any]], person_mapping: Optional[Di else: try: person = Person.objects.get( - persondistinctid__distinct_id=event["distinct_id"], persondistinctid__team_id=team_id + persondistinctid__distinct_id=event["distinct_id"], + persondistinctid__team_id=team_id, ) person_properties = person.properties person_id = person.uuid @@ -179,7 +184,10 @@ def bulk_create_events(events: List[Dict[str, Any]], person_mapping: Optional[Di event = { **event, - "person_properties": {**person_properties, **event.get("person_properties", {})}, + "person_properties": { + **person_properties, + **event.get("person_properties", {}), + }, "person_id": person_id, "person_created_at": person_created_at, } @@ -189,13 +197,20 @@ def bulk_create_events(events: List[Dict[str, Any]], person_mapping: Optional[Di if property_key.startswith("$group_"): group_type_index = property_key[-1] try: - group = Group.objects.get(team_id=team_id, group_type_index=group_type_index, group_key=value) + group = Group.objects.get( + team_id=team_id, + group_type_index=group_type_index, + group_key=value, + ) group_property_key = f"group{group_type_index}_properties" group_created_at_key = f"group{group_type_index}_created_at" event = { **event, - group_property_key: {**group.group_properties, **event.get(group_property_key, {})}, + group_property_key: { + **group.group_properties, + **event.get(group_property_key, {}), + }, group_created_at_key: event.get(group_created_at_key, datetime64_default_timestamp), } @@ -238,7 +253,10 @@ def bulk_create_events(events: List[Dict[str, Any]], person_mapping: Optional[Di else datetime64_default_timestamp, } - params = {**params, **{"{}_{}".format(key, index): value for key, value in event.items()}} + params = { + **params, + **{"{}_{}".format(key, index): value for key, value in event.items()}, + } sync_execute(BULK_INSERT_EVENT_SQL() + ", ".join(inserts), params, flush=False) diff --git a/posthog/models/event_definition.py b/posthog/models/event_definition.py index 7e2aa00d48819..5b22a9e6a2869 100644 --- a/posthog/models/event_definition.py +++ b/posthog/models/event_definition.py @@ -8,7 +8,10 @@ class EventDefinition(UUIDModel): team: models.ForeignKey = models.ForeignKey( - Team, on_delete=models.CASCADE, related_name="event_definitions", related_query_name="team" + Team, + on_delete=models.CASCADE, + related_name="event_definitions", + related_query_name="team", ) name: models.CharField = models.CharField(max_length=400) created_at: models.DateTimeField = models.DateTimeField(default=timezone.now, null=True) @@ -26,7 +29,9 @@ class Meta: unique_together = ("team", "name") indexes = [ GinIndex( - name="index_event_definition_name", fields=["name"], opclasses=["gin_trgm_ops"] + name="index_event_definition_name", + fields=["name"], + opclasses=["gin_trgm_ops"], ) # To speed up DB-based fuzzy searching ] diff --git a/posthog/models/event_property.py b/posthog/models/event_property.py index 458567c376ab4..4824248ddfce2 100644 --- a/posthog/models/event_property.py +++ b/posthog/models/event_property.py @@ -12,9 +12,13 @@ class EventProperty(models.Model): class Meta: constraints = [ models.UniqueConstraint( - fields=["team", "event", "property"], name="posthog_event_property_unique_team_event_property" + fields=["team", "event", "property"], + name="posthog_event_property_unique_team_event_property", ) ] - indexes = [models.Index(fields=["team", "event"]), models.Index(fields=["team", "property"])] + indexes = [ + models.Index(fields=["team", "event"]), + models.Index(fields=["team", "property"]), + ] __repr__ = sane_repr("event", "property", "team_id") diff --git a/posthog/models/exported_asset.py b/posthog/models/exported_asset.py index eb3bf961c9aaa..675245e867634 100644 --- a/posthog/models/exported_asset.py +++ b/posthog/models/exported_asset.py @@ -96,7 +96,11 @@ def file_ext(self): return self.export_format.split("/")[1] def get_analytics_metadata(self): - return {"export_format": self.export_format, "dashboard_id": self.dashboard_id, "insight_id": self.insight_id} + return { + "export_format": self.export_format, + "dashboard_id": self.dashboard_id, + "insight_id": self.insight_id, + } def get_public_content_url(self, expiry_delta: Optional[timedelta] = None): token = get_public_access_token(self, expiry_delta) @@ -112,7 +116,11 @@ def delete_expired_assets(cls): def get_public_access_token(asset: ExportedAsset, expiry_delta: Optional[timedelta] = None) -> str: if not expiry_delta: expiry_delta = timedelta(days=PUBLIC_ACCESS_TOKEN_EXP_DAYS) - return encode_jwt({"id": asset.id}, expiry_delta=expiry_delta, audience=PosthogJwtAudience.EXPORTED_ASSET) + return encode_jwt( + {"id": asset.id}, + expiry_delta=expiry_delta, + audience=PosthogJwtAudience.EXPORTED_ASSET, + ) def asset_for_token(token: str) -> ExportedAsset: @@ -153,7 +161,10 @@ def save_content(exported_asset: ExportedAsset, content: bytes) -> None: except ObjectStorageError as ose: capture_exception(ose) logger.error( - "exported_asset.object-storage-error", exported_asset_id=exported_asset.id, exception=ose, exc_info=True + "exported_asset.object-storage-error", + exported_asset_id=exported_asset.id, + exception=ose, + exc_info=True, ) save_content_to_exported_asset(exported_asset, content) diff --git a/posthog/models/feature_flag/feature_flag.py b/posthog/models/feature_flag/feature_flag.py index 29d8e89296e49..b45271bb16845 100644 --- a/posthog/models/feature_flag/feature_flag.py +++ b/posthog/models/feature_flag/feature_flag.py @@ -8,7 +8,10 @@ from django.utils import timezone from sentry_sdk.api import capture_exception -from posthog.constants import ENRICHED_DASHBOARD_INSIGHT_IDENTIFIER, PropertyOperatorType +from posthog.constants import ( + ENRICHED_DASHBOARD_INSIGHT_IDENTIFIER, + PropertyOperatorType, +) from posthog.models.cohort import Cohort from posthog.models.experiment import Experiment from posthog.models.property import GroupTypeIndex @@ -120,12 +123,17 @@ def get_filters(self): # We don't want to migrate to avoid /decide endpoint downtime until this code has been deployed return { "groups": [ - {"properties": self.filters.get("properties", []), "rollout_percentage": self.rollout_percentage} + { + "properties": self.filters.get("properties", []), + "rollout_percentage": self.rollout_percentage, + } ], } def transform_cohort_filters_for_easy_evaluation( - self, using_database: str = "default", seen_cohorts_cache: Optional[Dict[str, Cohort]] = None + self, + using_database: str = "default", + seen_cohorts_cache: Optional[Dict[str, Cohort]] = None, ): """ Expands cohort filters into person property filters when possible. @@ -248,7 +256,9 @@ def transform_cohort_filters_for_easy_evaluation( return parsed_conditions def get_cohort_ids( - self, using_database: str = "default", seen_cohorts_cache: Optional[Dict[str, Cohort]] = None + self, + using_database: str = "default", + seen_cohorts_cache: Optional[Dict[str, Cohort]] = None, ) -> List[int]: from posthog.models.cohort.util import get_dependent_cohorts @@ -274,7 +284,9 @@ def get_cohort_ids( [ dependent_cohort.pk for dependent_cohort in get_dependent_cohorts( - cohort, using_database=using_database, seen_cohorts_cache=seen_cohorts_cache + cohort, + using_database=using_database, + seen_cohorts_cache=seen_cohorts_cache, ) ] ) @@ -310,7 +322,8 @@ class FeatureFlagHashKeyOverride(models.Model): class Meta: constraints = [ models.UniqueConstraint( - fields=["team", "person", "feature_flag_key"], name="Unique hash_key for a user/team/feature_flag combo" + fields=["team", "person", "feature_flag_key"], + name="Unique hash_key for a user/team/feature_flag combo", ) ] @@ -329,7 +342,8 @@ class FeatureFlagOverride(models.Model): class Meta: constraints = [ models.UniqueConstraint( - fields=["user", "feature_flag", "team"], name="unique feature flag for a user/team combo" + fields=["user", "feature_flag", "team"], + name="unique feature flag for a user/team combo", ) ] @@ -340,7 +354,9 @@ class Meta: def set_feature_flags_for_team_in_cache( - team_id: int, feature_flags: Optional[List[FeatureFlag]] = None, using_database: str = "default" + team_id: int, + feature_flags: Optional[List[FeatureFlag]] = None, + using_database: str = "default", ) -> List[FeatureFlag]: from posthog.api.feature_flag import MinimalFeatureFlagSerializer @@ -391,5 +407,8 @@ class FeatureFlagDashboards(models.Model): class Meta: constraints = [ - models.UniqueConstraint(fields=["feature_flag", "dashboard"], name="unique feature flag for a dashboard") + models.UniqueConstraint( + fields=["feature_flag", "dashboard"], + name="unique feature flag for a dashboard", + ) ] diff --git a/posthog/models/feature_flag/flag_analytics.py b/posthog/models/feature_flag/flag_analytics.py index e949de479d166..367c836f75882 100644 --- a/posthog/models/feature_flag/flag_analytics.py +++ b/posthog/models/feature_flag/flag_analytics.py @@ -1,6 +1,8 @@ from typing import TYPE_CHECKING, Tuple from posthog.constants import FlagRequestType -from posthog.helpers.dashboard_templates import add_enriched_insights_to_feature_flag_dashboard +from posthog.helpers.dashboard_templates import ( + add_enriched_insights_to_feature_flag_dashboard, +) from posthog.models.feature_flag.feature_flag import FeatureFlag from posthog.redis import redis, get_client import time @@ -68,9 +70,11 @@ def capture_team_decide_usage(ph_client: "Posthog", team_id: int, team_uuid: str with client.lock(f"{REDIS_LOCK_TOKEN}:{team_id}", timeout=60, blocking=False): decide_key_name = get_team_request_key(team_id, FlagRequestType.DECIDE) - total_decide_request_count, min_time, max_time = _extract_total_count_for_key_from_redis_hash( - client, decide_key_name - ) + ( + total_decide_request_count, + min_time, + max_time, + ) = _extract_total_count_for_key_from_redis_hash(client, decide_key_name) if total_decide_request_count > 0 and settings.DECIDE_BILLING_ANALYTICS_TOKEN: ph_client.capture( @@ -87,9 +91,11 @@ def capture_team_decide_usage(ph_client: "Posthog", team_id: int, team_uuid: str ) local_evaluation_key_name = get_team_request_key(team_id, FlagRequestType.LOCAL_EVALUATION) - total_local_evaluation_request_count, min_time, max_time = _extract_total_count_for_key_from_redis_hash( - client, local_evaluation_key_name - ) + ( + total_local_evaluation_request_count, + min_time, + max_time, + ) = _extract_total_count_for_key_from_redis_hash(client, local_evaluation_key_name) if total_local_evaluation_request_count > 0 and settings.DECIDE_BILLING_ANALYTICS_TOKEN: ph_client.capture( @@ -113,7 +119,6 @@ def capture_team_decide_usage(ph_client: "Posthog", team_id: int, team_uuid: str def find_flags_with_enriched_analytics(begin: datetime, end: datetime): - result = sync_execute( """ SELECT team_id, JSONExtractString(properties, 'feature_flag') as flag_key diff --git a/posthog/models/feature_flag/flag_matching.py b/posthog/models/feature_flag/flag_matching.py index 059b60d7211f8..05c5bbccb8f63 100644 --- a/posthog/models/feature_flag/flag_matching.py +++ b/posthog/models/feature_flag/flag_matching.py @@ -25,7 +25,10 @@ from posthog.models.cohort import Cohort from posthog.models.utils import execute_with_timeout from posthog.queries.base import match_property, properties_to_Q -from posthog.database_healthcheck import postgres_healthcheck, DATABASE_FOR_FLAG_MATCHING +from posthog.database_healthcheck import ( + postgres_healthcheck, + DATABASE_FOR_FLAG_MATCHING, +) from posthog.utils import label_for_team_id_to_track from .feature_flag import ( @@ -156,7 +159,11 @@ def get_match(self, feature_flag: FeatureFlag) -> FeatureFlagMatch: # Match for boolean super condition first if feature_flag.filters.get("super_groups", None): - is_match, super_condition_value, evaluation_reason = self.is_super_condition_match(feature_flag) + ( + is_match, + super_condition_value, + evaluation_reason, + ) = self.is_super_condition_match(feature_flag) if is_match: payload = self.get_matching_payload(super_condition_value, None, feature_flag) return FeatureFlagMatch( @@ -184,11 +191,18 @@ def get_match(self, feature_flag: FeatureFlag) -> FeatureFlagMatch: payload = self.get_matching_payload(is_match, variant, feature_flag) return FeatureFlagMatch( - match=True, variant=variant, reason=evaluation_reason, condition_index=index, payload=payload + match=True, + variant=variant, + reason=evaluation_reason, + condition_index=index, + payload=payload, ) - highest_priority_evaluation_reason, highest_priority_index = self.get_highest_priority_match_evaluation( - highest_priority_evaluation_reason, highest_priority_index, evaluation_reason, index + (highest_priority_evaluation_reason, highest_priority_index,) = self.get_highest_priority_match_evaluation( + highest_priority_evaluation_reason, + highest_priority_index, + evaluation_reason, + index, ) return FeatureFlagMatch( @@ -227,7 +241,12 @@ def get_matches(self) -> Tuple[Dict[str, Union[str, bool]], Dict[str, dict], Dic faced_error_computing_flags = True handle_feature_flag_exception(err, "[Feature Flags] Error computing flags") - return flag_values, flag_evaluation_reasons, flag_payloads, faced_error_computing_flags + return ( + flag_values, + flag_evaluation_reasons, + flag_payloads, + faced_error_computing_flags, + ) def get_matching_variant(self, feature_flag: FeatureFlag) -> Optional[str]: for variant in self.variant_lookup_table(feature_flag): @@ -259,7 +278,11 @@ def is_super_condition_match(self, feature_flag: FeatureFlag) -> Tuple[bool, boo super_condition_value = self._super_condition_matches(feature_flag) if super_condition_value_is_set: - return True, super_condition_value, FeatureFlagMatchReason.SUPER_CONDITION_VALUE + return ( + True, + super_condition_value, + FeatureFlagMatchReason.SUPER_CONDITION_VALUE, + ) # Evaluate if properties are empty if feature_flag.super_conditions and len(feature_flag.super_conditions) > 0: @@ -290,7 +313,8 @@ def is_condition_match( target_properties = self.property_value_overrides if feature_flag.aggregation_group_type_index is not None: target_properties = self.group_property_value_overrides.get( - self.cache.group_type_index_to_name[feature_flag.aggregation_group_type_index], {} + self.cache.group_type_index_to_name[feature_flag.aggregation_group_type_index], + {}, ) condition_match = all(match_property(property, target_properties) for property in properties) else: @@ -344,7 +368,9 @@ def query_conditions(self) -> Dict[str, bool]: all_conditions: Dict = {} team_id = self.feature_flags[0].team_id person_query: QuerySet = Person.objects.using(DATABASE_FOR_FLAG_MATCHING).filter( - team_id=team_id, persondistinctid__distinct_id=self.distinct_id, persondistinctid__team_id=team_id + team_id=team_id, + persondistinctid__distinct_id=self.distinct_id, + persondistinctid__team_id=team_id, ) basic_group_query: QuerySet = Group.objects.using(DATABASE_FOR_FLAG_MATCHING).filter(team_id=team_id) group_query_per_group_type_mapping: Dict[GroupTypeIndex, Tuple[QuerySet, List[str]]] = {} @@ -372,7 +398,8 @@ def condition_eval(key, condition): target_properties = self.property_value_overrides if feature_flag.aggregation_group_type_index is not None: target_properties = self.group_property_value_overrides.get( - self.cache.group_type_index_to_name[feature_flag.aggregation_group_type_index], {} + self.cache.group_type_index_to_name[feature_flag.aggregation_group_type_index], + {}, ) expr = properties_to_Q( Filter(data=condition).property_groups.flat, @@ -401,7 +428,8 @@ def condition_eval(key, condition): person_query = person_query.annotate( **{ key: ExpressionWrapper( - expr if expr else RawSQL("true", []), output_field=BooleanField() + expr if expr else RawSQL("true", []), + output_field=BooleanField(), ) } ) @@ -410,13 +438,15 @@ def condition_eval(key, condition): if feature_flag.aggregation_group_type_index not in group_query_per_group_type_mapping: # ignore flags that didn't have the right groups passed in return - group_query, group_fields = group_query_per_group_type_mapping[ - feature_flag.aggregation_group_type_index - ] + ( + group_query, + group_fields, + ) = group_query_per_group_type_mapping[feature_flag.aggregation_group_type_index] group_query = group_query.annotate( **{ key: ExpressionWrapper( - expr if expr else RawSQL("true", []), output_field=BooleanField() + expr if expr else RawSQL("true", []), + output_field=BooleanField(), ) } ) @@ -468,7 +498,10 @@ def condition_eval(key, condition): if len(person_query) > 0: all_conditions = {**all_conditions, **person_query[0]} - for group_query, group_fields in group_query_per_group_type_mapping.values(): + for ( + group_query, + group_fields, + ) in group_query_per_group_type_mapping.values(): group_query = group_query.values(*group_fields) if len(group_query) > 0: assert len(group_query) == 1, f"Expected 1 group query result, got {len(group_query)}" @@ -514,7 +547,9 @@ def get_hash(self, feature_flag: FeatureFlag, salt="") -> float: return hash_val / __LONG_SCALE__ def can_compute_locally( - self, properties: List[Property], group_type_index: Optional[GroupTypeIndex] = None + self, + properties: List[Property], + group_type_index: Optional[GroupTypeIndex] = None, ) -> bool: target_properties = self.property_value_overrides if group_type_index is not None: @@ -661,7 +696,10 @@ def get_all_feature_flags( SELECT key FROM posthog_featureflag WHERE team_id = %(team_id)s AND ensure_experience_continuity = TRUE AND active = TRUE AND deleted = FALSE AND key NOT IN (SELECT feature_flag_key FROM existing_overrides) """ - cursor.execute(query, {"team_id": team_id, "distinct_ids": tuple(distinct_ids)}) # type: ignore + cursor.execute( + query, + {"team_id": team_id, "distinct_ids": tuple(distinct_ids)}, # type: ignore + ) flags_with_no_overrides = [row[0] for row in cursor.fetchall()] should_write_hash_key_override = len(flags_with_no_overrides) > 0 except Exception as e: @@ -686,7 +724,8 @@ def get_all_feature_flags( ) team_id_label = label_for_team_id_to_track(team_id) FLAG_HASH_KEY_WRITES_COUNTER.labels( - team_id=team_id_label, successful_write=writing_hash_key_override + team_id=team_id_label, + successful_write=writing_hash_key_override, ).inc() except Exception as e: # If the database is in read-only mode, we can't handle experience continuity flags, @@ -695,7 +734,9 @@ def get_all_feature_flags( # For this case, and for any other case, do not error out on decide, just continue assuming continuity couldn't happen. # At the same time, don't set db down, because the read-replica might still be up. handle_feature_flag_exception( - e, "[Feature Flags] Error while setting feature flag hash key overrides", set_healthcheck=False + e, + "[Feature Flags] Error while setting feature flag hash key overrides", + set_healthcheck=False, ) # This is the read-path for experience continuity. We need to get the overrides, and to do that, we get the person_id. @@ -783,14 +824,24 @@ def set_feature_flag_hash_key_overrides(team_id: int, distinct_ids: List[str], h # We don't want to return an error response for `/decide` just because of this. # There can be cases where it's a different override (like a person on two different browser sending the same request at the same time), # but we don't care about that case because first override wins. - cursor.execute(query, {"team_id": team_id, "distinct_ids": tuple(distinct_ids), "hash_key_override": hash_key_override}) # type: ignore + cursor.execute( + query, + { + "team_id": team_id, + "distinct_ids": tuple(distinct_ids), # type: ignore + "hash_key_override": hash_key_override, + }, + ) return cursor.rowcount > 0 except IntegrityError as e: if "violates foreign key constraint" in str(e) and retry < max_retries - 1: # This can happen if a person is deleted while we're trying to add overrides for it. # This is the only case when we retry. - logger.info("Retrying set_feature_flag_hash_key_overrides due to person deletion", exc_info=True) + logger.info( + "Retrying set_feature_flag_hash_key_overrides due to person deletion", + exc_info=True, + ) time.sleep(retry_delay) else: raise e diff --git a/posthog/models/feature_flag/permissions.py b/posthog/models/feature_flag/permissions.py index 3df6cc1fe16b4..95d39636c4c07 100644 --- a/posthog/models/feature_flag/permissions.py +++ b/posthog/models/feature_flag/permissions.py @@ -22,7 +22,8 @@ def can_user_edit_feature_flag(request, feature_flag): all_role_memberships = request.user.role_memberships.select_related("role").all() try: feature_flag_resource_access = OrganizationResourceAccess.objects.get( - organization=request.user.organization, resource=OrganizationResourceAccess.Resources.FEATURE_FLAGS + organization=request.user.organization, + resource=OrganizationResourceAccess.Resources.FEATURE_FLAGS, ) if feature_flag_resource_access.access_level >= OrganizationResourceAccess.AccessLevel.CAN_ALWAYS_EDIT: return True @@ -30,7 +31,10 @@ def can_user_edit_feature_flag(request, feature_flag): except OrganizationResourceAccess.DoesNotExist: org_level = OrganizationResourceAccess.AccessLevel.CAN_ALWAYS_EDIT - role_level = max([membership.role.feature_flags_access_level for membership in all_role_memberships], default=0) + role_level = max( + [membership.role.feature_flags_access_level for membership in all_role_memberships], + default=0, + ) if role_level == 0: final_level = org_level diff --git a/posthog/models/feature_flag/user_blast_radius.py b/posthog/models/feature_flag/user_blast_radius.py index 317c12e8a18ac..5843e3513e6b1 100644 --- a/posthog/models/feature_flag/user_blast_radius.py +++ b/posthog/models/feature_flag/user_blast_radius.py @@ -9,15 +9,17 @@ from posthog.models.team.team import Team -def get_user_blast_radius(team: Team, feature_flag_condition: dict, group_type_index: Optional[GroupTypeIndex] = None): - +def get_user_blast_radius( + team: Team, + feature_flag_condition: dict, + group_type_index: Optional[GroupTypeIndex] = None, +): from posthog.queries.person_query import PersonQuery # No rollout % calculations here, since it makes more sense to compute that on the frontend properties = feature_flag_condition.get("properties") or [] if group_type_index is not None: - try: from ee.clickhouse.queries.groups_join_query import GroupsJoinQuery except Exception: diff --git a/posthog/models/feedback/survey.py b/posthog/models/feedback/survey.py index 13938222d317e..b8a91b0b92527 100644 --- a/posthog/models/feedback/survey.py +++ b/posthog/models/feedback/survey.py @@ -16,7 +16,10 @@ class Meta: constraints = [models.UniqueConstraint(fields=["team", "name"], name="unique survey name for team")] team: models.ForeignKey = models.ForeignKey( - "posthog.Team", on_delete=models.CASCADE, related_name="surveys", related_query_name="survey" + "posthog.Team", + on_delete=models.CASCADE, + related_name="surveys", + related_query_name="survey", ) name: models.CharField = models.CharField(max_length=400) description: models.TextField = models.TextField(blank=True) @@ -57,7 +60,12 @@ class Meta: @mutable_receiver([post_save, post_delete], sender=Survey) def update_surveys_opt_in(sender, instance, **kwargs): active_surveys_count = ( - Survey.objects.filter(team_id=instance.team_id, start_date__isnull=False, end_date__isnull=True, archived=False) + Survey.objects.filter( + team_id=instance.team_id, + start_date__isnull=False, + end_date__isnull=True, + archived=False, + ) .exclude(type="api") .count() ) diff --git a/posthog/models/filters/base_filter.py b/posthog/models/filters/base_filter.py index 193c71f574b50..8b86de9b23129 100644 --- a/posthog/models/filters/base_filter.py +++ b/posthog/models/filters/base_filter.py @@ -40,7 +40,12 @@ def __init__( elif request.data and request.data.get(PROPERTIES): properties = request.data[PROPERTIES] - data = {**request.GET.dict(), **request.data, **(data if data else {}), **({PROPERTIES: properties})} + data = { + **request.GET.dict(), + **request.data, + **(data if data else {}), + **({PROPERTIES: properties}), + } elif data is None: raise ValueError("You need to define either a data dict or a request") @@ -50,7 +55,8 @@ def __init__( # Set the HogQL context for the request self.hogql_context = self.kwargs.get( - "hogql_context", HogQLContext(within_non_hogql_query=True, team_id=self.team.pk if self.team else None) + "hogql_context", + HogQLContext(within_non_hogql_query=True, team_id=self.team.pk if self.team else None), ) if self.team: self.hogql_context.person_on_events_mode = self.team.person_on_events_mode @@ -77,7 +83,8 @@ def toJSON(self): def shallow_clone(self, overrides: Dict[str, Any]): "Clone the filter's data while sharing the HogQL context" return type(self)( - data={**self._data, **overrides}, **{**self.kwargs, "team": self.team, "hogql_context": self.hogql_context} + data={**self._data, **overrides}, + **{**self.kwargs, "team": self.team, "hogql_context": self.hogql_context}, ) def query_tags(self) -> Dict[str, Any]: diff --git a/posthog/models/filters/mixins/common.py b/posthog/models/filters/mixins/common.py index bbb727407c6be..ae50d71f30656 100644 --- a/posthog/models/filters/mixins/common.py +++ b/posthog/models/filters/mixins/common.py @@ -50,7 +50,12 @@ ) from posthog.models.entity import Entity, ExclusionEntity, MathType from posthog.models.filters.mixins.base import BaseParamMixin, BreakdownType -from posthog.models.filters.mixins.utils import cached_property, include_dict, include_query_tags, process_bool +from posthog.models.filters.mixins.utils import ( + cached_property, + include_dict, + include_query_tags, + process_bool, +) from posthog.models.filters.utils import GroupTypeIndex, validate_group_type_index from posthog.utils import DEFAULT_DATE_FROM_DAYS, relative_date_parse_with_delta_mapping @@ -239,7 +244,10 @@ def breakdown_group_type_index(self) -> Optional[GroupTypeIndex]: @include_dict def breakdown_type_and_group_to_dict(self): if self.breakdown_type == "group": - return {BREAKDOWN_TYPE: self.breakdown_type, BREAKDOWN_GROUP_TYPE_INDEX: self.breakdown_group_type_index} + return { + BREAKDOWN_TYPE: self.breakdown_type, + BREAKDOWN_GROUP_TYPE_INDEX: self.breakdown_group_type_index, + } elif self.breakdown_type: return {BREAKDOWN_TYPE: self.breakdown_type} else: @@ -343,7 +351,11 @@ def date_from(self) -> Optional[datetime.datetime]: if self._date_from == "all": return None elif isinstance(self._date_from, str): - date, delta_mapping = relative_date_parse_with_delta_mapping(self._date_from, self.team.timezone_info, always_truncate=True) # type: ignore + date, delta_mapping = relative_date_parse_with_delta_mapping( + self._date_from, + self.team.timezone_info, # type: ignore + always_truncate=True, + ) self.date_from_delta_mapping = delta_mapping return date else: @@ -361,7 +373,11 @@ def date_to(self) -> datetime.datetime: if isinstance(self._date_to, str): try: return datetime.datetime.strptime(self._date_to, "%Y-%m-%d").replace( - hour=23, minute=59, second=59, microsecond=999999, tzinfo=ZoneInfo("UTC") + hour=23, + minute=59, + second=59, + microsecond=999999, + tzinfo=ZoneInfo("UTC"), ) except ValueError: try: @@ -369,7 +385,11 @@ def date_to(self) -> datetime.datetime: tzinfo=ZoneInfo("UTC") ) except ValueError: - date, delta_mapping = relative_date_parse_with_delta_mapping(self._date_to, self.team.timezone_info, always_truncate=True) # type: ignore + date, delta_mapping = relative_date_parse_with_delta_mapping( + self._date_to, + self.team.timezone_info, # type: ignore + always_truncate=True, + ) self.date_to_delta_mapping = delta_mapping return date else: diff --git a/posthog/models/filters/mixins/funnel.py b/posthog/models/filters/mixins/funnel.py index 4c13029ec0fb6..91312a5030478 100644 --- a/posthog/models/filters/mixins/funnel.py +++ b/posthog/models/filters/mixins/funnel.py @@ -264,7 +264,11 @@ class FunnelTrendsPersonsMixin(BaseParamMixin): @cached_property def entrance_period_start(self) -> Optional[datetime.datetime]: entrance_period_start_raw = self._data.get(ENTRANCE_PERIOD_START) - return relative_date_parse(entrance_period_start_raw, self.team.timezone_info) if entrance_period_start_raw else None # type: ignore + return ( + relative_date_parse(entrance_period_start_raw, self.team.timezone_info) # type: ignore + if entrance_period_start_raw + else None + ) @cached_property def drop_off(self) -> Optional[bool]: diff --git a/posthog/models/filters/mixins/property.py b/posthog/models/filters/mixins/property.py index 5812967c035e2..7ca409d4897d1 100644 --- a/posthog/models/filters/mixins/property.py +++ b/posthog/models/filters/mixins/property.py @@ -5,7 +5,11 @@ from posthog.constants import PROPERTIES, PropertyOperatorType from posthog.models.filters.mixins.base import BaseParamMixin -from posthog.models.filters.mixins.utils import cached_property, include_dict, include_query_tags +from posthog.models.filters.mixins.utils import ( + cached_property, + include_dict, + include_query_tags, +) from posthog.models.property import Property, PropertyGroup @@ -82,7 +86,10 @@ def _parse_properties(self, properties: Optional[Any]) -> List[Property]: key_split = key.split("__") ret.append( Property( - key=key_split[0], value=value, operator=key_split[1] if len(key_split) > 1 else None, type="event" + key=key_split[0], + value=value, + operator=key_split[1] if len(key_split) > 1 else None, + type="event", ) ) return ret @@ -90,7 +97,8 @@ def _parse_properties(self, properties: Optional[Any]) -> List[Property]: def _parse_property_group(self, group: Optional[Dict]) -> PropertyGroup: if group and "type" in group and "values" in group: return PropertyGroup( - PropertyOperatorType(group["type"].upper()), self._parse_property_group_list(group["values"]) + PropertyOperatorType(group["type"].upper()), + self._parse_property_group_list(group["values"]), ) return PropertyGroup(PropertyOperatorType.AND, cast(List[Property], [])) diff --git a/posthog/models/filters/mixins/retention.py b/posthog/models/filters/mixins/retention.py index 53146bf62a7b3..c2b55f3d30e2e 100644 --- a/posthog/models/filters/mixins/retention.py +++ b/posthog/models/filters/mixins/retention.py @@ -17,7 +17,11 @@ TREND_FILTER_TYPE_EVENTS, ) from posthog.models.entity import Entity -from posthog.models.filters.mixins.common import BaseParamMixin, DateMixin, EntitiesMixin +from posthog.models.filters.mixins.common import ( + BaseParamMixin, + DateMixin, + EntitiesMixin, +) from posthog.models.filters.mixins.utils import cached_property, include_dict from posthog.utils import relative_date_parse diff --git a/posthog/models/filters/mixins/simplify.py b/posthog/models/filters/mixins/simplify.py index 4afdc5dec64cf..4735a95e6a7d6 100644 --- a/posthog/models/filters/mixins/simplify.py +++ b/posthog/models/filters/mixins/simplify.py @@ -38,16 +38,23 @@ def simplify(self: T, team: "Team", **kwargs) -> T: updated_entities = {} if hasattr(result, "entities_to_dict"): for entity_type, entities in result.entities_to_dict().items(): - updated_entities[entity_type] = [self._simplify_entity(team, entity_type, entity, **kwargs) for entity in entities] # type: ignore + updated_entities[entity_type] = [ + self._simplify_entity(team, entity_type, entity, **kwargs) for entity in entities # type: ignore + ] from posthog.models.property.util import clear_excess_levels - prop_group = clear_excess_levels(self._simplify_property_group(team, result.property_groups, **kwargs), skip=True) # type: ignore + prop_group = clear_excess_levels( + self._simplify_property_group(team, result.property_groups, **kwargs), # type: ignore + skip=True, + ) prop_group = prop_group.to_dict() # type: ignore new_group_props = [] if getattr(result, "aggregation_group_type_index", None) is not None: - new_group_props.append(self._group_set_property(cast(int, result.aggregation_group_type_index)).to_dict()) # type: ignore + new_group_props.append( + self._group_set_property(cast(int, result.aggregation_group_type_index)).to_dict() # type: ignore + ) if new_group_props: new_group = {"type": "AND", "values": new_group_props} @@ -56,7 +63,11 @@ def simplify(self: T, team: "Team", **kwargs) -> T: return result.shallow_clone({**updated_entities, "properties": prop_group}) def _simplify_entity( - self, team: "Team", entity_type: Literal["events", "actions", "exclusions"], entity_params: Dict, **kwargs + self, + team: "Team", + entity_type: Literal["events", "actions", "exclusions"], + entity_params: Dict, + **kwargs, ) -> Dict: from posthog.models.entity import Entity, ExclusionEntity diff --git a/posthog/models/filters/mixins/test/test_interval.py b/posthog/models/filters/mixins/test/test_interval.py index efeb33e3479d7..d47adfc6b3e81 100644 --- a/posthog/models/filters/mixins/test/test_interval.py +++ b/posthog/models/filters/mixins/test/test_interval.py @@ -26,10 +26,13 @@ def test_filter_interval_success(filter, expected_interval): @pytest.mark.parametrize( "filter,expected_error_message", [ - (Filter(data={"interval": "foo"}), "Interval foo does not belong to SUPPORTED_INTERVAL_TYPES!"), + ( + Filter(data={"interval": "foo"}), + "Interval foo does not belong to SUPPORTED_INTERVAL_TYPES!", + ), (Filter(data={"interval": 123}), "Interval must be a string!"), ], ) def test_filter_interval_errors(filter, expected_error_message): with pytest.raises(ValueError, match=expected_error_message): - filter.interval + filter.interval # noqa: B018 diff --git a/posthog/models/filters/mixins/test/test_property.py b/posthog/models/filters/mixins/test/test_property.py index e1e250b5916a4..8f8b7c56721e2 100644 --- a/posthog/models/filters/mixins/test/test_property.py +++ b/posthog/models/filters/mixins/test/test_property.py @@ -13,7 +13,13 @@ def test_property_group_multi_level_parsing(): "properties": { "type": "AND", "values": [ - {"type": "AND", "values": [{"key": "attr", "value": "val_1"}, {"key": "attr_2", "value": "val_2"}]}, + { + "type": "AND", + "values": [ + {"key": "attr", "value": "val_1"}, + {"key": "attr_2", "value": "val_2"}, + ], + }, {"type": "OR", "values": [{"key": "attr", "value": "val_2"}]}, ], } @@ -42,7 +48,10 @@ def test_property_group_simple_parsing(): data={ "properties": { "type": "AND", - "values": [{"key": "attr", "value": "val_1"}, {"key": "attr_2", "value": "val_2"}], + "values": [ + {"key": "attr", "value": "val_1"}, + {"key": "attr_2", "value": "val_2"}, + ], } } ) @@ -64,22 +73,23 @@ def test_property_group_empty_parsing(): def test_property_group_invalid_parsing(): - filter = Filter( data={ "properties": { "type": "XaND", - "values": [{"key": "attr", "value": "val_1"}, {"key": "attr_2", "value": "val_2"}], + "values": [ + {"key": "attr", "value": "val_1"}, + {"key": "attr_2", "value": "val_2"}, + ], } } ) with pytest.raises(ValidationError): - filter.property_groups + filter.property_groups # noqa: B018 def test_property_group_includes_unhomogenous_groups(): - filter = Filter( data={ "properties": { @@ -95,7 +105,7 @@ def test_property_group_includes_unhomogenous_groups(): ) with pytest.raises(ValidationError): - filter.property_groups + filter.property_groups # noqa: B018 def test_property_multi_level_to_dict(): @@ -104,7 +114,13 @@ def test_property_multi_level_to_dict(): "properties": { "type": "AND", "values": [ - {"type": "AND", "values": [{"key": "attr", "value": "val_1"}, {"key": "attr_2", "value": "val_2"}]}, + { + "type": "AND", + "values": [ + {"key": "attr", "value": "val_1"}, + {"key": "attr_2", "value": "val_2"}, + ], + }, {"type": "OR", "values": [{"key": "attr", "value": "val_2"}]}, ], } @@ -121,7 +137,10 @@ def test_property_multi_level_to_dict(): {"key": "attr_2", "value": "val_2", "type": "event"}, ], }, - {"type": "OR", "values": [{"key": "attr", "value": "val_2", "type": "event"}]}, + { + "type": "OR", + "values": [{"key": "attr", "value": "val_2", "type": "event"}], + }, ], } @@ -131,7 +150,10 @@ def test_property_group_simple_to_dict(): data={ "properties": { "type": "AND", - "values": [{"key": "attr", "value": "val_1"}, {"key": "attr_2", "value": "val_2"}], + "values": [ + {"key": "attr", "value": "val_1"}, + {"key": "attr_2", "value": "val_2"}, + ], } } ) @@ -149,7 +171,13 @@ def test_property_group_simple_json_parsing(): filter = Filter( data={ "properties": json.dumps( - {"type": "AND", "values": [{"key": "attr", "value": "val_1"}, {"key": "attr_2", "value": "val_2"}]} + { + "type": "AND", + "values": [ + {"key": "attr", "value": "val_1"}, + {"key": "attr_2", "value": "val_2"}, + ], + } ) } ) @@ -173,7 +201,10 @@ def test_property_group_multi_level_json_parsing(): "values": [ { "type": "AND", - "values": [{"key": "attr", "value": "val_1"}, {"key": "attr_2", "value": "val_2"}], + "values": [ + {"key": "attr", "value": "val_1"}, + {"key": "attr_2", "value": "val_2"}, + ], }, {"type": "OR", "values": [{"key": "attr", "value": "val_2"}]}, ], diff --git a/posthog/models/filters/mixins/utils.py b/posthog/models/filters/mixins/utils.py index 2d224ca98a716..a297cdcfa6320 100644 --- a/posthog/models/filters/mixins/utils.py +++ b/posthog/models/filters/mixins/utils.py @@ -5,6 +5,7 @@ T = TypeVar("T") + # can't use cached_property directly from functools because of 3.7 compatibilty def cached_property(func: Callable[..., T]) -> T: return property(lru_cache(maxsize=1)(func)) # type: ignore diff --git a/posthog/models/filters/path_filter.py b/posthog/models/filters/path_filter.py index 9fe71d5d6d16b..4373092b91520 100644 --- a/posthog/models/filters/path_filter.py +++ b/posthog/models/filters/path_filter.py @@ -17,7 +17,11 @@ SampleMixin, SearchMixin, ) -from .mixins.funnel import FunnelCorrelationMixin, FunnelPersonsStepMixin, FunnelWindowMixin +from .mixins.funnel import ( + FunnelCorrelationMixin, + FunnelPersonsStepMixin, + FunnelWindowMixin, +) from .mixins.groups import GroupsAggregationMixin from .mixins.interval import IntervalMixin from .mixins.paths import ( @@ -76,7 +80,12 @@ class PathFilter( BaseFilter, SampleMixin, ): - def __init__(self, data: Optional[Dict[str, Any]] = None, request: Optional[Request] = None, **kwargs) -> None: + def __init__( + self, + data: Optional[Dict[str, Any]] = None, + request: Optional[Request] = None, + **kwargs, + ) -> None: if data: data["insight"] = INSIGHT_PATHS else: diff --git a/posthog/models/filters/retention_filter.py b/posthog/models/filters/retention_filter.py index cd767606a6dd1..9cc3e8d0c7a08 100644 --- a/posthog/models/filters/retention_filter.py +++ b/posthog/models/filters/retention_filter.py @@ -18,7 +18,11 @@ from .mixins.funnel import FunnelCorrelationMixin from .mixins.groups import GroupsAggregationMixin from .mixins.property import PropertyMixin -from .mixins.retention import EntitiesDerivedMixin, RetentionDateDerivedMixin, RetentionTypeMixin +from .mixins.retention import ( + EntitiesDerivedMixin, + RetentionDateDerivedMixin, + RetentionTypeMixin, +) from .mixins.simplify import SimplifyFilterMixin from .mixins.utils import cached_property, include_dict diff --git a/posthog/models/filters/stickiness_filter.py b/posthog/models/filters/stickiness_filter.py index dbabdd5e6897a..4674c4ceeb3d9 100644 --- a/posthog/models/filters/stickiness_filter.py +++ b/posthog/models/filters/stickiness_filter.py @@ -1,6 +1,11 @@ from typing import TYPE_CHECKING, Any, Callable, Dict, Optional, Union -from django.db.models.functions.datetime import TruncDay, TruncHour, TruncMonth, TruncWeek +from django.db.models.functions.datetime import ( + TruncDay, + TruncHour, + TruncMonth, + TruncWeek, +) from rest_framework.exceptions import ValidationError from rest_framework.request import Request @@ -55,7 +60,12 @@ class StickinessFilter( get_earliest_timestamp: Optional[Callable] team: "Team" - def __init__(self, data: Optional[Dict[str, Any]] = None, request: Optional[Request] = None, **kwargs) -> None: + def __init__( + self, + data: Optional[Dict[str, Any]] = None, + request: Optional[Request] = None, + **kwargs, + ) -> None: if data: data["insight"] = INSIGHT_STICKINESS else: diff --git a/posthog/models/filters/test/test_filter.py b/posthog/models/filters/test/test_filter.py index 3113cc3598000..d7f60b149b93b 100644 --- a/posthog/models/filters/test/test_filter.py +++ b/posthog/models/filters/test/test_filter.py @@ -60,7 +60,12 @@ def test_to_dict(self): def test_simplify_test_accounts(self): self.team.test_account_filters = [ - {"key": "email", "value": "@posthog.com", "operator": "not_icontains", "type": "person"} + { + "key": "email", + "value": "@posthog.com", + "operator": "not_icontains", + "type": "person", + } ] self.team.save() @@ -70,7 +75,12 @@ def test_simplify_test_accounts(self): self.assertEqual( filter.properties_to_dict(), - {"properties": {"type": "AND", "values": [{"key": "attr", "value": "some_val", "type": "event"}]}}, + { + "properties": { + "type": "AND", + "values": [{"key": "attr", "value": "some_val", "type": "event"}], + } + }, ) self.assertTrue(filter.is_simplified) @@ -85,10 +95,18 @@ def test_simplify_test_accounts(self): { "type": "AND", "values": [ - {"key": "email", "value": "@posthog.com", "operator": "not_icontains", "type": "person"} + { + "key": "email", + "value": "@posthog.com", + "operator": "not_icontains", + "type": "person", + } ], }, - {"type": "AND", "values": [{"key": "attr", "value": "some_val", "type": "event"}]}, + { + "type": "AND", + "values": [{"key": "attr", "value": "some_val", "type": "event"}], + }, ], } }, @@ -104,10 +122,18 @@ def test_simplify_test_accounts(self): { "type": "AND", "values": [ - {"key": "email", "value": "@posthog.com", "operator": "not_icontains", "type": "person"} + { + "key": "email", + "value": "@posthog.com", + "operator": "not_icontains", + "type": "person", + } ], }, - {"type": "AND", "values": [{"key": "attr", "value": "some_val", "type": "event"}]}, + { + "type": "AND", + "values": [{"key": "attr", "value": "some_val", "type": "event"}], + }, ], } }, @@ -117,27 +143,61 @@ def test_simplify_test_accounts(self): def property_to_Q_test_factory(filter_persons: Callable, person_factory): class TestPropertiesToQ(BaseTest): def test_simple_persons(self): - person_factory(team_id=self.team.pk, distinct_ids=["person1"], properties={"url": "https://whatever.com"}) + person_factory( + team_id=self.team.pk, + distinct_ids=["person1"], + properties={"url": "https://whatever.com"}, + ) person_factory(team_id=self.team.pk, distinct_ids=["person2"], properties={"url": 1}) - person_factory(team_id=self.team.pk, distinct_ids=["person3"], properties={"url": {"bla": "bla"}}) + person_factory( + team_id=self.team.pk, + distinct_ids=["person3"], + properties={"url": {"bla": "bla"}}, + ) person_factory(team_id=self.team.pk, distinct_ids=["person4"]) - filter = Filter(data={"properties": [{"type": "person", "key": "url", "value": "https://whatever.com"}]}) + filter = Filter( + data={ + "properties": [ + { + "type": "person", + "key": "url", + "value": "https://whatever.com", + } + ] + } + ) results = filter_persons(filter, self.team) self.assertEqual(len(results), 1) def test_multiple_equality_persons(self): - person_factory(team_id=self.team.pk, distinct_ids=["person1"], properties={"url": "https://whatever.com"}) + person_factory( + team_id=self.team.pk, + distinct_ids=["person1"], + properties={"url": "https://whatever.com"}, + ) person_factory(team_id=self.team.pk, distinct_ids=["person2"], properties={"url": 1}) - person_factory(team_id=self.team.pk, distinct_ids=["person3"], properties={"url": {"bla": "bla"}}) + person_factory( + team_id=self.team.pk, + distinct_ids=["person3"], + properties={"url": {"bla": "bla"}}, + ) person_factory(team_id=self.team.pk, distinct_ids=["person4"]) - person_factory(team_id=self.team.pk, distinct_ids=["person5"], properties={"url": "https://example.com"}) + person_factory( + team_id=self.team.pk, + distinct_ids=["person5"], + properties={"url": "https://example.com"}, + ) filter = Filter( data={ "properties": [ - {"type": "person", "key": "url", "value": ["https://whatever.com", "https://example.com"]} + { + "type": "person", + "key": "url", + "value": ["https://whatever.com", "https://example.com"], + } ] } ) @@ -147,7 +207,15 @@ def test_multiple_equality_persons(self): def test_incomplete_data(self): filter = Filter( - data={"properties": [{"key": "$current_url", "operator": "not_icontains", "type": "event"}]} + data={ + "properties": [ + { + "key": "$current_url", + "operator": "not_icontains", + "type": "event", + } + ] + } ) self.assertListEqual(filter.property_groups.values, []) @@ -156,21 +224,60 @@ def test_numerical_person_properties(self): person_factory(team_id=self.team.pk, distinct_ids=["p2"], properties={"$a_number": 5}) person_factory(team_id=self.team.pk, distinct_ids=["p3"], properties={"$a_number": 6}) - filter = Filter(data={"properties": [{"type": "person", "key": "$a_number", "value": 4, "operator": "gt"}]}) + filter = Filter( + data={ + "properties": [ + { + "type": "person", + "key": "$a_number", + "value": 4, + "operator": "gt", + } + ] + } + ) self.assertEqual(len(filter_persons(filter, self.team)), 2) filter = Filter(data={"properties": [{"type": "person", "key": "$a_number", "value": 5}]}) self.assertEqual(len(filter_persons(filter, self.team)), 1) - filter = Filter(data={"properties": [{"type": "person", "key": "$a_number", "value": 6, "operator": "lt"}]}) + filter = Filter( + data={ + "properties": [ + { + "type": "person", + "key": "$a_number", + "value": 6, + "operator": "lt", + } + ] + } + ) self.assertEqual(len(filter_persons(filter, self.team)), 2) def test_contains_persons(self): - person_factory(team_id=self.team.pk, distinct_ids=["p1"], properties={"url": "https://whatever.com"}) - person_factory(team_id=self.team.pk, distinct_ids=["p2"], properties={"url": "https://example.com"}) + person_factory( + team_id=self.team.pk, + distinct_ids=["p1"], + properties={"url": "https://whatever.com"}, + ) + person_factory( + team_id=self.team.pk, + distinct_ids=["p2"], + properties={"url": "https://example.com"}, + ) filter = Filter( - data={"properties": [{"type": "person", "key": "url", "value": "whatever", "operator": "icontains"}]} + data={ + "properties": [ + { + "type": "person", + "key": "url", + "value": "whatever", + "operator": "icontains", + } + ] + } ) results = filter_persons(filter, self.team) @@ -179,49 +286,106 @@ def test_contains_persons(self): def test_regex_persons(self): p1_uuid = str( person_factory( - team_id=self.team.pk, distinct_ids=["p1"], properties={"url": "https://whatever.com"} + team_id=self.team.pk, + distinct_ids=["p1"], + properties={"url": "https://whatever.com"}, ).uuid ) p2_uuid = str(person_factory(team_id=self.team.pk, distinct_ids=["p2"]).uuid) filter = Filter( - data={"properties": [{"type": "person", "key": "url", "value": r"\.com$", "operator": "regex"}]} + data={ + "properties": [ + { + "type": "person", + "key": "url", + "value": r"\.com$", + "operator": "regex", + } + ] + } ) results = filter_persons(filter, self.team) self.assertCountEqual(results, [p1_uuid]) filter = Filter( - data={"properties": [{"type": "person", "key": "url", "value": r"\.eee$", "operator": "not_regex"}]} + data={ + "properties": [ + { + "type": "person", + "key": "url", + "value": r"\.eee$", + "operator": "not_regex", + } + ] + } ) results = filter_persons(filter, self.team) self.assertCountEqual(results, [p1_uuid, p2_uuid]) def test_invalid_regex_persons(self): - person_factory(team_id=self.team.pk, distinct_ids=["p1"], properties={"url": "https://whatever.com"}) - person_factory(team_id=self.team.pk, distinct_ids=["p2"], properties={"url": "https://example.com"}) + person_factory( + team_id=self.team.pk, + distinct_ids=["p1"], + properties={"url": "https://whatever.com"}, + ) + person_factory( + team_id=self.team.pk, + distinct_ids=["p2"], + properties={"url": "https://example.com"}, + ) filter = Filter( - data={"properties": [{"type": "person", "key": "url", "value": r"?*", "operator": "regex"}]} + data={ + "properties": [ + { + "type": "person", + "key": "url", + "value": r"?*", + "operator": "regex", + } + ] + } ) self.assertEqual(len(filter_persons(filter, self.team)), 0) filter = Filter( - data={"properties": [{"type": "person", "key": "url", "value": r"?*", "operator": "not_regex"}]} + data={ + "properties": [ + { + "type": "person", + "key": "url", + "value": r"?*", + "operator": "not_regex", + } + ] + } ) self.assertEqual(len(filter_persons(filter, self.team)), 0) def test_is_not_persons(self): - person_factory(team_id=self.team.pk, distinct_ids=["p1"], properties={"url": "https://whatever.com"}) + person_factory( + team_id=self.team.pk, + distinct_ids=["p1"], + properties={"url": "https://whatever.com"}, + ) p2_uuid = str( person_factory( - team_id=self.team.pk, distinct_ids=["p2"], properties={"url": "https://example.com"} + team_id=self.team.pk, + distinct_ids=["p2"], + properties={"url": "https://example.com"}, ).uuid ) filter = Filter( data={ "properties": [ - {"type": "person", "key": "url", "value": "https://whatever.com", "operator": "is_not"} + { + "type": "person", + "key": "url", + "value": "https://whatever.com", + "operator": "is_not", + } ] } ) @@ -229,10 +393,16 @@ def test_is_not_persons(self): self.assertCountEqual(results, [p2_uuid]) def test_does_not_contain_persons(self): - person_factory(team_id=self.team.pk, distinct_ids=["p1"], properties={"url": "https://whatever.com"}) + person_factory( + team_id=self.team.pk, + distinct_ids=["p1"], + properties={"url": "https://whatever.com"}, + ) p2_uuid = str( person_factory( - team_id=self.team.pk, distinct_ids=["p2"], properties={"url": "https://example.com"} + team_id=self.team.pk, + distinct_ids=["p2"], + properties={"url": "https://example.com"}, ).uuid ) p3_uuid = str(person_factory(team_id=self.team.pk, distinct_ids=["p3"]).uuid) @@ -241,7 +411,12 @@ def test_does_not_contain_persons(self): filter = Filter( data={ "properties": [ - {"type": "person", "key": "url", "value": "whatever.com", "operator": "not_icontains"} + { + "type": "person", + "key": "url", + "value": "whatever.com", + "operator": "not_icontains", + } ] } ) @@ -256,12 +431,21 @@ def test_multiple_persons(self): properties={"url": "https://whatever.com", "another_key": "value"}, ).uuid ) - person_factory(team_id=self.team.pk, distinct_ids=["p2"], properties={"url": "https://whatever.com"}) + person_factory( + team_id=self.team.pk, + distinct_ids=["p2"], + properties={"url": "https://whatever.com"}, + ) filter = Filter( data={ "properties": [ - {"type": "person", "key": "url", "value": "whatever.com", "operator": "icontains"}, + { + "type": "person", + "key": "url", + "value": "whatever.com", + "operator": "icontains", + }, {"type": "person", "key": "another_key", "value": "value"}, ] } @@ -271,7 +455,11 @@ def test_multiple_persons(self): def test_boolean_filters_persons(self): p1_uuid = str( - person_factory(team_id=self.team.pk, distinct_ids=["p1"], properties={"is_first_user": True}).uuid + person_factory( + team_id=self.team.pk, + distinct_ids=["p1"], + properties={"is_first_user": True}, + ).uuid ) person_factory(team_id=self.team.pk, distinct_ids=["p2"]) @@ -281,29 +469,62 @@ def test_boolean_filters_persons(self): def test_is_not_set_and_is_set_persons(self): p1_uuid = str( - person_factory(team_id=self.team.pk, distinct_ids=["p1"], properties={"is_first_user": True}).uuid + person_factory( + team_id=self.team.pk, + distinct_ids=["p1"], + properties={"is_first_user": True}, + ).uuid ) p2_uuid = str(person_factory(team_id=self.team.pk, distinct_ids=["p2"]).uuid) filter = Filter( - data={"properties": [{"type": "person", "key": "is_first_user", "value": "", "operator": "is_set"}]} + data={ + "properties": [ + { + "type": "person", + "key": "is_first_user", + "value": "", + "operator": "is_set", + } + ] + } ) results = filter_persons(filter, self.team) self.assertEqual(results, [p1_uuid]) filter = Filter( - data={"properties": [{"type": "person", "key": "is_first_user", "value": "", "operator": "is_not_set"}]} + data={ + "properties": [ + { + "type": "person", + "key": "is_first_user", + "value": "", + "operator": "is_not_set", + } + ] + } ) results = filter_persons(filter, self.team) self.assertEqual(results, [p2_uuid]) def test_is_not_true_false_persons(self): - person_factory(team_id=self.team.pk, distinct_ids=["p1"], properties={"is_first_user": True}) + person_factory( + team_id=self.team.pk, + distinct_ids=["p1"], + properties={"is_first_user": True}, + ) p2_uuid = str(person_factory(team_id=self.team.pk, distinct_ids=["p2"]).uuid) filter = Filter( data={ - "properties": [{"type": "person", "key": "is_first_user", "value": ["true"], "operator": "is_not"}] + "properties": [ + { + "type": "person", + "key": "is_first_user", + "value": ["true"], + "operator": "is_not", + } + ] } ) results = filter_persons(filter, self.team) @@ -312,15 +533,26 @@ def test_is_not_true_false_persons(self): def test_is_date_before_persons(self): p1_uuid = str( person_factory( - team_id=self.team.pk, distinct_ids=["p1"], properties={"some-timestamp": "2022-03-01"} + team_id=self.team.pk, + distinct_ids=["p1"], + properties={"some-timestamp": "2022-03-01"}, ).uuid ) - person_factory(team_id=self.team.pk, distinct_ids=["p2"], properties={"some-timestamp": "2022-05-01"}) + person_factory( + team_id=self.team.pk, + distinct_ids=["p2"], + properties={"some-timestamp": "2022-05-01"}, + ) filter = Filter( data={ "properties": [ - {"type": "person", "key": "some-timestamp", "value": "2022-04-01", "operator": "is_date_before"} + { + "type": "person", + "key": "some-timestamp", + "value": "2022-04-01", + "operator": "is_date_before", + } ] } ) @@ -348,14 +580,25 @@ def test_json_object(self): self.assertEqual(results, [str(p1_uuid.uuid)]) def test_filter_out_team_members_persons(self): - person_factory(team_id=self.team.pk, distinct_ids=["team_member"], properties={"email": "test@posthog.com"}) + person_factory( + team_id=self.team.pk, + distinct_ids=["team_member"], + properties={"email": "test@posthog.com"}, + ) p2_uuid = str( person_factory( - team_id=self.team.pk, distinct_ids=["random_user"], properties={"email": "test@gmail.com"} + team_id=self.team.pk, + distinct_ids=["random_user"], + properties={"email": "test@gmail.com"}, ).uuid ) self.team.test_account_filters = [ - {"key": "email", "value": "@posthog.com", "operator": "not_icontains", "type": "person"} + { + "key": "email", + "value": "@posthog.com", + "operator": "not_icontains", + "type": "person", + } ] self.team.save() filter = Filter(data={FILTER_TEST_ACCOUNTS: True}, team=self.team) @@ -373,7 +616,9 @@ def _filter_persons(filter: Filter, team: Team): return [str(uuid) for uuid in persons.values_list("uuid", flat=True)] -class TestDjangoPropertiesToQ(property_to_Q_test_factory(_filter_persons, _create_person), QueryMatchingTest): # type: ignore +class TestDjangoPropertiesToQ( + property_to_Q_test_factory(_filter_persons, _create_person), QueryMatchingTest +): # type: ignore @snapshot_postgres_queries def test_array_property_as_string_on_persons(self): Person.objects.create( @@ -388,7 +633,16 @@ def test_array_property_as_string_on_persons(self): # some idiosyncracies on how this works, but we shouldn't error out on this filter = Filter( - data={"properties": [{"type": "person", "key": "urls", "operator": "icontains", "value": '["abcd"]'}]} + data={ + "properties": [ + { + "type": "person", + "key": "urls", + "operator": "icontains", + "value": '["abcd"]', + } + ] + } ) persons = Person.objects.filter(property_group_to_Q(filter.property_groups)) @@ -401,7 +655,9 @@ def test_array_property_as_string_on_persons(self): def test_person_cohort_properties(self): person1_distinct_id = "person1" person1 = Person.objects.create( - team=self.team, distinct_ids=[person1_distinct_id], properties={"$some_prop": 1} + team=self.team, + distinct_ids=[person1_distinct_id], + properties={"$some_prop": 1}, ) cohort1 = Cohort.objects.create(team=self.team, groups=[{"properties": {"$some_prop": 1}}], name="cohort1") cohort1.people.add(person1) @@ -410,7 +666,10 @@ def test_person_cohort_properties(self): with self.assertNumQueries(2): matched_person = ( - Person.objects.filter(team_id=self.team.pk, persondistinctid__distinct_id=person1_distinct_id) + Person.objects.filter( + team_id=self.team.pk, + persondistinctid__distinct_id=person1_distinct_id, + ) .filter(properties_to_Q(filter.property_groups.flat)) .exists() ) @@ -419,7 +678,9 @@ def test_person_cohort_properties(self): def test_person_cohort_properties_with_zero_value(self): person1_distinct_id = "person1" person1 = Person.objects.create( - team=self.team, distinct_ids=[person1_distinct_id], properties={"$some_prop": 0} + team=self.team, + distinct_ids=[person1_distinct_id], + properties={"$some_prop": 0}, ) cohort1 = Cohort.objects.create(team=self.team, groups=[{"properties": {"$some_prop": 0}}], name="cohort1") cohort1.people.add(person1) @@ -428,7 +689,10 @@ def test_person_cohort_properties_with_zero_value(self): with self.assertNumQueries(2): matched_person = ( - Person.objects.filter(team_id=self.team.pk, persondistinctid__distinct_id=person1_distinct_id) + Person.objects.filter( + team_id=self.team.pk, + persondistinctid__distinct_id=person1_distinct_id, + ) .filter(properties_to_Q(filter.property_groups.flat)) .exists() ) @@ -436,7 +700,11 @@ def test_person_cohort_properties_with_zero_value(self): def test_person_cohort_properties_with_negation(self): person1_distinct_id = "example_id" - Person.objects.create(team=self.team, distinct_ids=["example_id"], properties={"$some_prop": "matches"}) + Person.objects.create( + team=self.team, + distinct_ids=["example_id"], + properties={"$some_prop": "matches"}, + ) user_in = Cohort.objects.create( team=self.team, @@ -447,7 +715,11 @@ def test_person_cohort_properties_with_negation(self): { "type": "AND", "values": [ - {"key": "$some_prop", "value": "matches", "type": "person"}, + { + "key": "$some_prop", + "value": "matches", + "type": "person", + }, ], } ], @@ -464,7 +736,11 @@ def test_person_cohort_properties_with_negation(self): { "type": "OR", "values": [ - {"key": "$bad_prop", "value": "nomatchihope", "type": "person"}, + { + "key": "$bad_prop", + "value": "nomatchihope", + "type": "person", + }, ], }, ], @@ -501,14 +777,28 @@ def test_person_cohort_properties_with_negation(self): with self.assertNumQueries(4): matched_person = ( - Person.objects.filter(team_id=self.team.pk, persondistinctid__distinct_id=person1_distinct_id) + Person.objects.filter( + team_id=self.team.pk, + persondistinctid__distinct_id=person1_distinct_id, + ) .filter(properties_to_Q(filter.property_groups.flat)) .exists() ) self.assertTrue(matched_person) def test_group_property_filters_direct(self): - filter = Filter(data={"properties": [{"key": "some_prop", "value": 5, "type": "group", "group_type_index": 1}]}) + filter = Filter( + data={ + "properties": [ + { + "key": "some_prop", + "value": 5, + "type": "group", + "group_type_index": 1, + } + ] + } + ) query_filter = properties_to_Q(filter.property_groups.flat) self.assertEqual( query_filter, @@ -543,9 +833,17 @@ def filter_persons_with_property_group( class TestDjangoPropertyGroupToQ(BaseTest, QueryMatchingTest): def test_simple_property_group_to_q(self): - _create_person(team_id=self.team.pk, distinct_ids=["person1"], properties={"url": "https://whatever.com"}) + _create_person( + team_id=self.team.pk, + distinct_ids=["person1"], + properties={"url": "https://whatever.com"}, + ) _create_person(team_id=self.team.pk, distinct_ids=["person2"], properties={"url": 1}) - _create_person(team_id=self.team.pk, distinct_ids=["person3"], properties={"url": {"bla": "bla"}}) + _create_person( + team_id=self.team.pk, + distinct_ids=["person3"], + properties={"url": {"bla": "bla"}}, + ) _create_person(team_id=self.team.pk, distinct_ids=["person4"]) filter = Filter( @@ -553,7 +851,11 @@ def test_simple_property_group_to_q(self): "properties": { "type": "OR", "values": [ - {"type": "person", "key": "url", "value": "https://whatever.com"}, + { + "type": "person", + "key": "url", + "value": "https://whatever.com", + }, {"type": "person", "key": "url", "value": 1}, ], } @@ -566,10 +868,20 @@ def test_simple_property_group_to_q(self): def test_multiple_properties_property_group_to_q(self): _create_person( - team_id=self.team.pk, distinct_ids=["person1"], properties={"url": "https://whatever.com", "bla": 1} + team_id=self.team.pk, + distinct_ids=["person1"], + properties={"url": "https://whatever.com", "bla": 1}, + ) + _create_person( + team_id=self.team.pk, + distinct_ids=["person2"], + properties={"url": 1, "bla": 2}, + ) + _create_person( + team_id=self.team.pk, + distinct_ids=["person3"], + properties={"url": {"bla": "bla"}, "bla": 3}, ) - _create_person(team_id=self.team.pk, distinct_ids=["person2"], properties={"url": 1, "bla": 2}) - _create_person(team_id=self.team.pk, distinct_ids=["person3"], properties={"url": {"bla": "bla"}, "bla": 3}) _create_person(team_id=self.team.pk, distinct_ids=["person4"]) filter = Filter( @@ -577,7 +889,11 @@ def test_multiple_properties_property_group_to_q(self): "properties": { "type": "OR", "values": [ - {"type": "person", "key": "url", "value": "https://whatever.com"}, + { + "type": "person", + "key": "url", + "value": "https://whatever.com", + }, {"type": "person", "key": "bla", "value": 1}, ], } @@ -590,10 +906,20 @@ def test_multiple_properties_property_group_to_q(self): def test_nested_property_group_to_q(self): _create_person( - team_id=self.team.pk, distinct_ids=["person1"], properties={"url": "https://whatever.com", "bla": 1} + team_id=self.team.pk, + distinct_ids=["person1"], + properties={"url": "https://whatever.com", "bla": 1}, + ) + _create_person( + team_id=self.team.pk, + distinct_ids=["person2"], + properties={"url": 1, "bla": 2}, + ) + _create_person( + team_id=self.team.pk, + distinct_ids=["person3"], + properties={"url": {"bla": "bla"}, "bla": 3}, ) - _create_person(team_id=self.team.pk, distinct_ids=["person2"], properties={"url": 1, "bla": 2}) - _create_person(team_id=self.team.pk, distinct_ids=["person3"], properties={"url": {"bla": "bla"}, "bla": 3}) _create_person(team_id=self.team.pk, distinct_ids=["person4"]) filter = Filter( @@ -604,11 +930,18 @@ def test_nested_property_group_to_q(self): { "type": "AND", "values": [ - {"type": "person", "key": "url", "value": "https://whatever.com"}, + { + "type": "person", + "key": "url", + "value": "https://whatever.com", + }, {"type": "person", "key": "bla", "value": 1}, ], }, - {"type": "AND", "values": [{"type": "person", "key": "bla", "value": 3}]}, + { + "type": "AND", + "values": [{"type": "person", "key": "bla", "value": 3}], + }, ], } } @@ -620,10 +953,20 @@ def test_nested_property_group_to_q(self): def test_property_group_to_q_with_property_overrides(self): _create_person( - team_id=self.team.pk, distinct_ids=["person1"], properties={"url": "https://whatever.com", "bla": 1} + team_id=self.team.pk, + distinct_ids=["person1"], + properties={"url": "https://whatever.com", "bla": 1}, + ) + _create_person( + team_id=self.team.pk, + distinct_ids=["person2"], + properties={"url": 1, "bla": 2}, + ) + _create_person( + team_id=self.team.pk, + distinct_ids=["person3"], + properties={"url": {"bla": "bla"}, "bla": 3}, ) - _create_person(team_id=self.team.pk, distinct_ids=["person2"], properties={"url": 1, "bla": 2}) - _create_person(team_id=self.team.pk, distinct_ids=["person3"], properties={"url": {"bla": "bla"}, "bla": 3}) _create_person(team_id=self.team.pk, distinct_ids=["person4"]) filter = Filter( @@ -634,11 +977,18 @@ def test_property_group_to_q_with_property_overrides(self): { "type": "AND", "values": [ - {"type": "person", "key": "url", "value": "https://whatever.com"}, + { + "type": "person", + "key": "url", + "value": "https://whatever.com", + }, {"type": "person", "key": "bla", "value": 1}, ], }, - {"type": "AND", "values": [{"type": "person", "key": "bla", "value": 3}]}, + { + "type": "AND", + "values": [{"type": "person", "key": "bla", "value": 3}], + }, ], } } @@ -651,10 +1001,20 @@ def test_property_group_to_q_with_property_overrides(self): @snapshot_postgres_queries def test_property_group_to_q_with_cohorts(self): _create_person( - team_id=self.team.pk, distinct_ids=["person1"], properties={"url": "https://whatever.com", "bla": 1} + team_id=self.team.pk, + distinct_ids=["person1"], + properties={"url": "https://whatever.com", "bla": 1}, + ) + _create_person( + team_id=self.team.pk, + distinct_ids=["person2"], + properties={"url": 1, "bla": 2}, + ) + _create_person( + team_id=self.team.pk, + distinct_ids=["person3"], + properties={"url": {"bla": "bla"}, "bla": 3}, ) - _create_person(team_id=self.team.pk, distinct_ids=["person2"], properties={"url": 1, "bla": 2}) - _create_person(team_id=self.team.pk, distinct_ids=["person3"], properties={"url": {"bla": "bla"}, "bla": 3}) _create_person(team_id=self.team.pk, distinct_ids=["person4"]) cohort1 = Cohort.objects.create( @@ -679,12 +1039,19 @@ def test_property_group_to_q_with_cohorts(self): { "type": "AND", "values": [ - {"type": "person", "key": "url", "value": "https://whatever.com"}, + { + "type": "person", + "key": "url", + "value": "https://whatever.com", + }, {"type": "person", "key": "bla", "value": 1}, {"type": "cohort", "key": "id", "value": cohort1.pk}, ], }, - {"type": "AND", "values": [{"type": "person", "key": "bla", "value": 3}]}, + { + "type": "AND", + "values": [{"type": "person", "key": "bla", "value": 3}], + }, ], } } @@ -696,12 +1063,36 @@ def test_property_group_to_q_with_cohorts(self): @snapshot_postgres_queries def test_property_group_to_q_with_negation_cohorts(self): - _create_person(team_id=self.team.pk, distinct_ids=["person1"], properties={"bla": 1, "other": 1}) - _create_person(team_id=self.team.pk, distinct_ids=["person2"], properties={"bla": 2, "other": 1}) - _create_person(team_id=self.team.pk, distinct_ids=["person3"], properties={"bla": 3, "other": 2}) - _create_person(team_id=self.team.pk, distinct_ids=["person4"], properties={"bla": 4, "other": 1}) - _create_person(team_id=self.team.pk, distinct_ids=["person5"], properties={"bla": 5, "other": 1}) - _create_person(team_id=self.team.pk, distinct_ids=["person6"], properties={"bla": 6, "other": 1}) + _create_person( + team_id=self.team.pk, + distinct_ids=["person1"], + properties={"bla": 1, "other": 1}, + ) + _create_person( + team_id=self.team.pk, + distinct_ids=["person2"], + properties={"bla": 2, "other": 1}, + ) + _create_person( + team_id=self.team.pk, + distinct_ids=["person3"], + properties={"bla": 3, "other": 2}, + ) + _create_person( + team_id=self.team.pk, + distinct_ids=["person4"], + properties={"bla": 4, "other": 1}, + ) + _create_person( + team_id=self.team.pk, + distinct_ids=["person5"], + properties={"bla": 5, "other": 1}, + ) + _create_person( + team_id=self.team.pk, + distinct_ids=["person6"], + properties={"bla": 6, "other": 1}, + ) cohort1 = Cohort.objects.create( team=self.team, @@ -750,8 +1141,18 @@ def test_property_group_to_q_with_negation_cohorts(self): "properties": { "type": "AND", "values": [ - {"type": "cohort", "key": "id", "value": cohort1.pk, "negation": True}, - {"type": "cohort", "key": "id", "value": cohort2.pk, "negation": True}, + { + "type": "cohort", + "key": "id", + "value": cohort1.pk, + "negation": True, + }, + { + "type": "cohort", + "key": "id", + "value": cohort2.pk, + "negation": True, + }, {"type": "cohort", "key": "id", "value": cohort3.pk}, ], } @@ -777,10 +1178,20 @@ def test_property_group_to_q_with_negation_cohorts(self): @snapshot_postgres_queries def test_property_group_to_q_with_cohorts_no_match(self): _create_person( - team_id=self.team.pk, distinct_ids=["person1"], properties={"url": "https://whatever.com", "bla": 1} + team_id=self.team.pk, + distinct_ids=["person1"], + properties={"url": "https://whatever.com", "bla": 1}, + ) + _create_person( + team_id=self.team.pk, + distinct_ids=["person2"], + properties={"url": 1, "bla": 2}, + ) + _create_person( + team_id=self.team.pk, + distinct_ids=["person3"], + properties={"url": {"bla": "bla"}, "bla": 3}, ) - _create_person(team_id=self.team.pk, distinct_ids=["person2"], properties={"url": 1, "bla": 2}) - _create_person(team_id=self.team.pk, distinct_ids=["person3"], properties={"url": {"bla": "bla"}, "bla": 3}) _create_person(team_id=self.team.pk, distinct_ids=["person4"]) cohort1 = Cohort.objects.create( @@ -805,12 +1216,19 @@ def test_property_group_to_q_with_cohorts_no_match(self): { "type": "AND", "values": [ - {"type": "person", "key": "url", "value": "https://whatever.com"}, + { + "type": "person", + "key": "url", + "value": "https://whatever.com", + }, {"type": "person", "key": "bla", "value": 1}, {"type": "cohort", "key": "id", "value": cohort1.pk}, ], }, - {"type": "AND", "values": [{"type": "person", "key": "bla", "value": 3}]}, + { + "type": "AND", + "values": [{"type": "person", "key": "bla", "value": 3}], + }, ], } } @@ -822,13 +1240,27 @@ def test_property_group_to_q_with_cohorts_no_match(self): def test_property_group_to_q_with_behavioural_cohort(self): _create_person( - team_id=self.team.pk, distinct_ids=["person1"], properties={"url": "https://whatever.com", "bla": 1} + team_id=self.team.pk, + distinct_ids=["person1"], + properties={"url": "https://whatever.com", "bla": 1}, + ) + _create_person( + team_id=self.team.pk, + distinct_ids=["person2"], + properties={"url": 1, "bla": 2}, + ) + _create_person( + team_id=self.team.pk, + distinct_ids=["person3"], + properties={"url": {"bla": "bla"}, "bla": 3}, ) - _create_person(team_id=self.team.pk, distinct_ids=["person2"], properties={"url": 1, "bla": 2}) - _create_person(team_id=self.team.pk, distinct_ids=["person3"], properties={"url": {"bla": "bla"}, "bla": 3}) _create_person(team_id=self.team.pk, distinct_ids=["person4"]) - cohort2 = Cohort.objects.create(team=self.team, groups=[{"event_id": "$pageview", "days": 7}], name="cohort2") + cohort2 = Cohort.objects.create( + team=self.team, + groups=[{"event_id": "$pageview", "days": 7}], + name="cohort2", + ) filter = Filter( data={ @@ -838,12 +1270,19 @@ def test_property_group_to_q_with_behavioural_cohort(self): { "type": "AND", "values": [ - {"type": "person", "key": "url", "value": "https://whatever.com"}, + { + "type": "person", + "key": "url", + "value": "https://whatever.com", + }, {"type": "person", "key": "bla", "value": 1}, {"type": "cohort", "key": "id", "value": cohort2.pk}, ], }, - {"type": "AND", "values": [{"type": "person", "key": "bla", "value": 3}]}, + { + "type": "AND", + "values": [{"type": "person", "key": "bla", "value": 3}], + }, ], } } diff --git a/posthog/models/filters/test/test_lifecycle_filter.py b/posthog/models/filters/test/test_lifecycle_filter.py index 8bf5d904c66f4..9273a12e654d1 100644 --- a/posthog/models/filters/test/test_lifecycle_filter.py +++ b/posthog/models/filters/test/test_lifecycle_filter.py @@ -64,4 +64,7 @@ def test_filter_properties(self): }, ) self.assertEqual(filter.lifecycle_type, lifecycle_type) - self.assertEqual(filter.target_date, relative_date_parse(target_date, self.team.timezone_info)) + self.assertEqual( + filter.target_date, + relative_date_parse(target_date, self.team.timezone_info), + ) diff --git a/posthog/models/filters/utils.py b/posthog/models/filters/utils.py index 7c2f75331bc74..0b31b209afa69 100644 --- a/posthog/models/filters/utils.py +++ b/posthog/models/filters/utils.py @@ -33,19 +33,31 @@ def get_filter(team, data: dict = {}, request: Optional[Request] = None): if insight == INSIGHT_RETENTION: return RetentionFilter(data={**data, "insight": INSIGHT_RETENTION}, request=request, team=team) elif insight == INSIGHT_STICKINESS or (insight == INSIGHT_TRENDS and data.get("shown_as") == "Stickiness"): - return StickinessFilter(data=data, request=request, team=team, get_earliest_timestamp=earliest_timestamp_func) + return StickinessFilter( + data=data, + request=request, + team=team, + get_earliest_timestamp=earliest_timestamp_func, + ) elif insight == INSIGHT_PATHS: return PathFilter(data={**data, "insight": INSIGHT_PATHS}, request=request, team=team) elif insight == INSIGHT_FUNNELS: return Filter( - data={**data, **(request.data if request else {}), "insight": INSIGHT_FUNNELS}, request=request, team=team + data={ + **data, + **(request.data if request else {}), + "insight": INSIGHT_FUNNELS, + }, + request=request, + team=team, ) return Filter(data=data, request=request, team=team) def validate_group_type_index(param_name: str, value: Any, required=False) -> Optional[GroupTypeIndex]: error = ValidationError( - f"{param_name} is required to be at least 0 and less than {GROUP_TYPES_LIMIT}", code="invalid" + f"{param_name} is required to be at least 0 and less than {GROUP_TYPES_LIMIT}", + code="invalid", ) if required and value is None: diff --git a/posthog/models/group/sql.py b/posthog/models/group/sql.py index 2eb5222859729..41b9e72cebcbb 100644 --- a/posthog/models/group/sql.py +++ b/posthog/models/group/sql.py @@ -36,7 +36,10 @@ ) KAFKA_GROUPS_TABLE_SQL = lambda: GROUPS_TABLE_BASE_SQL.format( - table_name="kafka_" + GROUPS_TABLE, cluster=CLICKHOUSE_CLUSTER, engine=kafka_engine(KAFKA_GROUPS), extra_fields="" + table_name="kafka_" + GROUPS_TABLE, + cluster=CLICKHOUSE_CLUSTER, + engine=kafka_engine(KAFKA_GROUPS), + extra_fields="", ) # You must include the database here because of a bug in clickhouse diff --git a/posthog/models/group/util.py b/posthog/models/group/util.py index fa3520dc9912c..427c883a2e920 100644 --- a/posthog/models/group/util.py +++ b/posthog/models/group/util.py @@ -60,7 +60,15 @@ def create_group( else: timestamp = timestamp.astimezone(ZoneInfo("UTC")) - raw_create_group_ch(team_id, group_type_index, group_key, properties, timestamp, timestamp=timestamp, sync=sync) + raw_create_group_ch( + team_id, + group_type_index, + group_key, + properties, + timestamp, + timestamp=timestamp, + sync=sync, + ) group = Group.objects.create( team_id=team_id, group_type_index=group_type_index, @@ -73,7 +81,9 @@ def create_group( def get_aggregation_target_field( - aggregation_group_type_index: Optional[GroupTypeIndex], event_table_alias: str, default: str + aggregation_group_type_index: Optional[GroupTypeIndex], + event_table_alias: str, + default: str, ) -> str: if aggregation_group_type_index is not None: return f'{event_table_alias}."$group_{aggregation_group_type_index}"' diff --git a/posthog/models/group_type_mapping.py b/posthog/models/group_type_mapping.py index 80ebdebfdeaf6..ed4a19164f4fb 100644 --- a/posthog/models/group_type_mapping.py +++ b/posthog/models/group_type_mapping.py @@ -7,9 +7,13 @@ class GroupTypeMapping(models.Model): class Meta: constraints = [ models.UniqueConstraint(fields=["team", "group_type"], name="unique group types for team"), - models.UniqueConstraint(fields=["team", "group_type_index"], name="unique event column indexes for team"), + models.UniqueConstraint( + fields=["team", "group_type_index"], + name="unique event column indexes for team", + ), models.CheckConstraint( - check=models.Q(group_type_index__lte=5), name="group_type_index is less than or equal 5" + check=models.Q(group_type_index__lte=5), + name="group_type_index is less than or equal 5", ), ] diff --git a/posthog/models/ingestion_warnings/sql.py b/posthog/models/ingestion_warnings/sql.py index 55a631a0835c0..6f3023744f51f 100644 --- a/posthog/models/ingestion_warnings/sql.py +++ b/posthog/models/ingestion_warnings/sql.py @@ -1,7 +1,11 @@ from django.conf import settings from posthog.clickhouse.kafka_engine import KAFKA_COLUMNS_WITH_PARTITION, kafka_engine -from posthog.clickhouse.table_engines import Distributed, MergeTreeEngine, ReplicationScheme +from posthog.clickhouse.table_engines import ( + Distributed, + MergeTreeEngine, + ReplicationScheme, +) from posthog.kafka_client.topics import KAFKA_INGESTION_WARNINGS INGESTION_WARNINGS_TABLE_BASE_SQL = """ diff --git a/posthog/models/insight.py b/posthog/models/insight.py index 1c5d168ed7b5b..a3057cdb11c7d 100644 --- a/posthog/models/insight.py +++ b/posthog/models/insight.py @@ -52,12 +52,20 @@ class Insight(models.Model): refresh_attempt: models.IntegerField = models.IntegerField(null=True, blank=True) last_modified_at: models.DateTimeField = models.DateTimeField(default=timezone.now) last_modified_by: models.ForeignKey = models.ForeignKey( - "User", on_delete=models.SET_NULL, null=True, blank=True, related_name="modified_insights" + "User", + on_delete=models.SET_NULL, + null=True, + blank=True, + related_name="modified_insights", ) # DEPRECATED: using the new "dashboards" relation instead dashboard: models.ForeignKey = models.ForeignKey( - "Dashboard", related_name="items", on_delete=models.CASCADE, null=True, blank=True + "Dashboard", + related_name="items", + on_delete=models.CASCADE, + null=True, + blank=True, ) # DEPRECATED: on dashboard_insight now layouts: models.JSONField = models.JSONField(default=dict) @@ -75,7 +83,11 @@ class Insight(models.Model): deprecated_tags: ArrayField = ArrayField(models.CharField(max_length=32), null=True, blank=True, default=list) # DEPRECATED: now using app-wide tagging model. See EnterpriseTaggedItem deprecated_tags_v2: ArrayField = ArrayField( - models.CharField(max_length=32), null=True, blank=True, default=None, db_column="tags" + models.CharField(max_length=32), + null=True, + blank=True, + default=None, + db_column="tags", ) # Changing these fields materially alters the Insight, so these count for the "last_modified_*" fields @@ -141,7 +153,10 @@ def dashboard_filters(self, dashboard: Optional[Dashboard] = None): elif self.filters.get("properties", {}).get("type"): filters["properties"] = { "type": "AND", - "values": [self.filters["properties"], {"type": "AND", "values": dashboard_properties}], + "values": [ + self.filters["properties"], + {"type": "AND", "values": dashboard_properties}, + ], } elif not self.filters.get("properties"): filters["properties"] = dashboard_properties @@ -157,7 +172,9 @@ def dashboard_filters(self, dashboard: Optional[Dashboard] = None): def dashboard_query(self, dashboard: Optional[Dashboard]) -> Optional[dict]: if not dashboard or not self.query: return self.query - from posthog.hogql_queries.apply_dashboard_filters import apply_dashboard_filters + from posthog.hogql_queries.apply_dashboard_filters import ( + apply_dashboard_filters, + ) return apply_dashboard_filters(self.query, dashboard.filters, self.team) @@ -184,7 +201,9 @@ def generate_insight_cache_key(insight: Insight, dashboard: Optional[Dashboard]) dashboard_filters = dashboard.filters if dashboard else None if dashboard_filters: - from posthog.hogql_queries.apply_dashboard_filters import apply_dashboard_filters + from posthog.hogql_queries.apply_dashboard_filters import ( + apply_dashboard_filters, + ) q = apply_dashboard_filters(insight.query, dashboard_filters, insight.team) else: diff --git a/posthog/models/insight_caching_state.py b/posthog/models/insight_caching_state.py index 2c1382b637efd..9e6abc0b7b5a8 100644 --- a/posthog/models/insight_caching_state.py +++ b/posthog/models/insight_caching_state.py @@ -15,15 +15,24 @@ class Meta: indexes = [models.Index(fields=["cache_key"], name="filter_by_cache_key_idx")] constraints = [ UniqueConstraintByExpression( - name="unique_insight_tile_idx", expression="(insight_id, coalesce(dashboard_tile_id, -1))" + name="unique_insight_tile_idx", + expression="(insight_id, coalesce(dashboard_tile_id, -1))", ) ] team: models.ForeignKey = models.ForeignKey(Team, on_delete=models.CASCADE) - insight = models.ForeignKey("posthog.Insight", on_delete=models.CASCADE, related_name="caching_states", null=False) + insight = models.ForeignKey( + "posthog.Insight", + on_delete=models.CASCADE, + related_name="caching_states", + null=False, + ) dashboard_tile = models.ForeignKey( - "posthog.DashboardTile", on_delete=models.CASCADE, related_name="caching_states", null=True + "posthog.DashboardTile", + on_delete=models.CASCADE, + related_name="caching_states", + null=True, ) cache_key: models.CharField = models.CharField(max_length=400, null=False, blank=False) @@ -67,7 +76,11 @@ def sync_dashboard_updated(sender, instance: Dashboard, **kwargs): from posthog.celery import sync_insight_caching_state update_fields = kwargs.get("update_fields") - if update_fields in [frozenset({"filters_hash"}), frozenset({"last_refresh"}), frozenset({"last_accessed_at"})]: + if update_fields in [ + frozenset({"filters_hash"}), + frozenset({"last_refresh"}), + frozenset({"last_accessed_at"}), + ]: return for tile_id in DashboardTile.objects.filter(dashboard=instance).values_list("pk", flat=True): diff --git a/posthog/models/integration.py b/posthog/models/integration.py index 55ed06232445a..8ce1c9d6ef7c7 100644 --- a/posthog/models/integration.py +++ b/posthog/models/integration.py @@ -106,7 +106,11 @@ def integration_from_slack_response(cls, team_id: str, created_by: User, params: integration, created = Integration.objects.update_or_create( team_id=team_id, kind="slack", - defaults={"config": config, "sensitive_config": sensitive_config, "created_by": created_by}, + defaults={ + "config": config, + "sensitive_config": sensitive_config, + "created_by": created_by, + }, ) return integration @@ -147,6 +151,12 @@ def validate_request(cls, request: Request): @classmethod @cache_for(timedelta(minutes=5)) def slack_config(cls): - config = get_instance_settings(["SLACK_APP_CLIENT_ID", "SLACK_APP_CLIENT_SECRET", "SLACK_APP_SIGNING_SECRET"]) + config = get_instance_settings( + [ + "SLACK_APP_CLIENT_ID", + "SLACK_APP_CLIENT_SECRET", + "SLACK_APP_SIGNING_SECRET", + ] + ) return config diff --git a/posthog/models/messaging.py b/posthog/models/messaging.py index c1a787e30d309..5514f98baccb2 100644 --- a/posthog/models/messaging.py +++ b/posthog/models/messaging.py @@ -31,4 +31,7 @@ class MessagingRecord(UUIDModel): created_at: models.DateTimeField = models.DateTimeField(auto_now_add=True) class Meta: - unique_together = ("email_hash", "campaign_key") # can only send campaign once to each email + unique_together = ( + "email_hash", + "campaign_key", + ) # can only send campaign once to each email diff --git a/posthog/models/notebook/notebook.py b/posthog/models/notebook/notebook.py index 490645909df26..ec61ab1c22ed0 100644 --- a/posthog/models/notebook/notebook.py +++ b/posthog/models/notebook/notebook.py @@ -19,7 +19,11 @@ class Notebook(UUIDModel): created_by: models.ForeignKey = models.ForeignKey("User", on_delete=models.SET_NULL, null=True, blank=True) last_modified_at: models.DateTimeField = models.DateTimeField(default=timezone.now) last_modified_by: models.ForeignKey = models.ForeignKey( - "User", on_delete=models.SET_NULL, null=True, blank=True, related_name="modified_notebooks" + "User", + on_delete=models.SET_NULL, + null=True, + blank=True, + related_name="modified_notebooks", ) class Meta: diff --git a/posthog/models/organization.py b/posthog/models/organization.py index cc4c07568312e..700fea47658f1 100644 --- a/posthog/models/organization.py +++ b/posthog/models/organization.py @@ -24,7 +24,12 @@ from posthog.cloud_utils import is_cloud from posthog.constants import MAX_SLUG_LENGTH, AvailableFeature from posthog.email import is_email_available -from posthog.models.utils import LowercaseSlugField, UUIDModel, create_with_slug, sane_repr +from posthog.models.utils import ( + LowercaseSlugField, + UUIDModel, + create_with_slug, + sane_repr, +) from posthog.redis import get_client from posthog.utils import absolute_uri @@ -56,7 +61,11 @@ def create(self, *args: Any, **kwargs: Any): return create_with_slug(super().create, *args, **kwargs) def bootstrap( - self, user: Optional["User"], *, team_fields: Optional[Dict[str, Any]] = None, **kwargs + self, + user: Optional["User"], + *, + team_fields: Optional[Dict[str, Any]] = None, + **kwargs, ) -> Tuple["Organization", Optional["OrganizationMembership"], "Team"]: """Instead of doing the legwork of creating an organization yourself, delegate the details with bootstrap.""" from .team import Team # Avoiding circular import @@ -67,7 +76,9 @@ def bootstrap( organization_membership: Optional[OrganizationMembership] = None if user is not None: organization_membership = OrganizationMembership.objects.create( - organization=organization, user=user, level=OrganizationMembership.Level.OWNER + organization=organization, + user=user, + level=OrganizationMembership.Level.OWNER, ) user.current_organization = organization user.organization = user.current_organization # Update cached property @@ -111,7 +122,7 @@ class PluginsAccessLevel(models.IntegerChoices): slug: LowercaseSlugField = LowercaseSlugField(unique=True, max_length=MAX_SLUG_LENGTH) created_at: models.DateTimeField = models.DateTimeField(auto_now_add=True) updated_at: models.DateTimeField = models.DateTimeField(auto_now=True) - plugins_access_level: models.PositiveSmallIntegerField = models.PositiveSmallIntegerField( + plugins_access_level: (models.PositiveSmallIntegerField) = models.PositiveSmallIntegerField( default=PluginsAccessLevel.CONFIG, choices=PluginsAccessLevel.choices, ) @@ -222,8 +233,14 @@ def organization_about_to_be_created(sender, instance: Organization, raw, using, def ensure_available_features_sync(sender, instance: Organization, **kwargs): updated_fields = kwargs.get("update_fields") or [] if "available_features" in updated_fields: - logger.info("Notifying plugin-server to reset available features cache.", {"organization_id": instance.id}) - get_client().publish("reset-available-features-cache", json.dumps({"organization_id": str(instance.id)})) + logger.info( + "Notifying plugin-server to reset available features cache.", + {"organization_id": instance.id}, + ) + get_client().publish( + "reset-available-features-cache", + json.dumps({"organization_id": str(instance.id)}), + ) class OrganizationMembership(UUIDModel): @@ -235,7 +252,10 @@ class Level(models.IntegerChoices): OWNER = 15, "owner" organization: models.ForeignKey = models.ForeignKey( - "posthog.Organization", on_delete=models.CASCADE, related_name="memberships", related_query_name="membership" + "posthog.Organization", + on_delete=models.CASCADE, + related_name="memberships", + related_query_name="membership", ) user: models.ForeignKey = models.ForeignKey( "posthog.User", @@ -251,9 +271,14 @@ class Level(models.IntegerChoices): class Meta: constraints = [ - models.UniqueConstraint(fields=["organization_id", "user_id"], name="unique_organization_membership"), models.UniqueConstraint( - fields=["organization_id"], condition=models.Q(level=15), name="only_one_owner_per_organization" + fields=["organization_id", "user_id"], + name="unique_organization_membership", + ), + models.UniqueConstraint( + fields=["organization_id"], + condition=models.Q(level=15), + name="only_one_owner_per_organization", ), ] @@ -261,7 +286,9 @@ def __str__(self): return str(self.Level(self.level)) def validate_update( - self, membership_being_updated: "OrganizationMembership", new_level: Optional[Level] = None + self, + membership_being_updated: "OrganizationMembership", + new_level: Optional[Level] = None, ) -> None: if new_level is not None: if membership_being_updated.id == self.id: @@ -290,7 +317,10 @@ def validate_update( class OrganizationInvite(UUIDModel): organization: models.ForeignKey = models.ForeignKey( - "posthog.Organization", on_delete=models.CASCADE, related_name="invites", related_query_name="invite" + "posthog.Organization", + on_delete=models.CASCADE, + related_name="invites", + related_query_name="invite", ) target_email: models.EmailField = models.EmailField(null=True, db_index=True) first_name: models.CharField = models.CharField(max_length=30, blank=True, default="") @@ -326,7 +356,8 @@ def validate( if self.is_expired(): raise exceptions.ValidationError( - "This invite has expired. Please ask your admin for a new one.", code="expired" + "This invite has expired. Please ask your admin for a new one.", + code="expired", ) if user is None and User.objects.filter(email=invite_email).exists(): @@ -334,7 +365,8 @@ def validate( if OrganizationMembership.objects.filter(organization=self.organization, user=user).exists(): raise exceptions.ValidationError( - "You already are a member of this organization.", code="user_already_member" + "You already are a member of this organization.", + code="user_already_member", ) if OrganizationMembership.objects.filter( @@ -352,7 +384,12 @@ def use(self, user: "User", *, prevalidated: bool = False) -> None: if is_email_available(with_absolute_urls=True) and self.organization.is_member_join_email_enabled: from posthog.tasks.email import send_member_join - send_member_join.apply_async(kwargs={"invitee_uuid": user.uuid, "organization_id": self.organization_id}) + send_member_join.apply_async( + kwargs={ + "invitee_uuid": user.uuid, + "organization_id": self.organization_id, + } + ) OrganizationInvite.objects.filter(target_email__iexact=self.target_email).delete() def is_expired(self) -> bool: diff --git a/posthog/models/performance/sql.py b/posthog/models/performance/sql.py index 14c5b1763cc08..31914e858b9b9 100644 --- a/posthog/models/performance/sql.py +++ b/posthog/models/performance/sql.py @@ -1,7 +1,16 @@ """https://developer.mozilla.org/en-US/docs/Web/API/PerformanceEntry""" from posthog import settings -from posthog.clickhouse.kafka_engine import KAFKA_COLUMNS_WITH_PARTITION, STORAGE_POLICY, kafka_engine, ttl_period -from posthog.clickhouse.table_engines import Distributed, MergeTreeEngine, ReplicationScheme +from posthog.clickhouse.kafka_engine import ( + KAFKA_COLUMNS_WITH_PARTITION, + STORAGE_POLICY, + kafka_engine, + ttl_period, +) +from posthog.clickhouse.table_engines import ( + Distributed, + MergeTreeEngine, + ReplicationScheme, +) from posthog.kafka_client.topics import KAFKA_PERFORMANCE_EVENTS """ diff --git a/posthog/models/person/person.py b/posthog/models/person/person.py index b2b3bb3e36725..cae5e450fa766 100644 --- a/posthog/models/person/person.py +++ b/posthog/models/person/person.py @@ -66,7 +66,10 @@ def split_person(self, main_distinct_id: Optional[str], max_splits: Optional[int pdi.version = (pdi.version or 0) + 1 pdi.save(update_fields=["version", "person_id"]) - from posthog.models.person.util import create_person, create_person_distinct_id + from posthog.models.person.util import ( + create_person, + create_person_distinct_id, + ) create_person_distinct_id( team_id=self.team_id, @@ -75,7 +78,11 @@ def split_person(self, main_distinct_id: Optional[str], max_splits: Optional[int is_deleted=False, version=pdi.version, ) - create_person(team_id=self.team_id, uuid=str(person.uuid), version=person.version or 0) + create_person( + team_id=self.team_id, + uuid=str(person.uuid), + version=person.version or 0, + ) objects = PersonManager() created_at: models.DateTimeField = models.DateTimeField(auto_now_add=True, blank=True) @@ -138,7 +145,10 @@ class PersonOverride(models.Model): class Meta: constraints = [ - models.UniqueConstraint(fields=["team", "old_person_id"], name="unique override per old_person_id"), + models.UniqueConstraint( + fields=["team", "old_person_id"], + name="unique override per old_person_id", + ), models.CheckConstraint( check=~Q(old_person_id__exact=F("override_person_id")), name="old_person_id_different_from_override_person_id", diff --git a/posthog/models/person/sql.py b/posthog/models/person/sql.py index 61088e6c03761..ffb80869b9e9a 100644 --- a/posthog/models/person/sql.py +++ b/posthog/models/person/sql.py @@ -2,7 +2,11 @@ from posthog.clickhouse.indexes import index_by_kafka_timestamp from posthog.clickhouse.kafka_engine import KAFKA_COLUMNS, STORAGE_POLICY, kafka_engine from posthog.clickhouse.table_engines import CollapsingMergeTree, ReplacingMergeTree -from posthog.kafka_client.topics import KAFKA_PERSON, KAFKA_PERSON_DISTINCT_ID, KAFKA_PERSON_UNIQUE_ID +from posthog.kafka_client.topics import ( + KAFKA_PERSON, + KAFKA_PERSON_DISTINCT_ID, + KAFKA_PERSON_UNIQUE_ID, +) from posthog.settings import CLICKHOUSE_CLUSTER, CLICKHOUSE_DATABASE TRUNCATE_PERSON_TABLE_SQL = f"TRUNCATE TABLE IF EXISTS person ON CLUSTER '{CLICKHOUSE_CLUSTER}'" @@ -48,7 +52,10 @@ ) KAFKA_PERSONS_TABLE_SQL = lambda: PERSONS_TABLE_BASE_SQL.format( - table_name="kafka_" + PERSONS_TABLE, cluster=CLICKHOUSE_CLUSTER, engine=kafka_engine(KAFKA_PERSON), extra_fields="" + table_name="kafka_" + PERSONS_TABLE, + cluster=CLICKHOUSE_CLUSTER, + engine=kafka_engine(KAFKA_PERSON), + extra_fields="", ) # You must include the database here because of a bug in clickhouse @@ -154,7 +161,9 @@ _offset FROM {database}.kafka_{table_name} """.format( - table_name=PERSONS_DISTINCT_ID_TABLE, cluster=CLICKHOUSE_CLUSTER, database=CLICKHOUSE_DATABASE + table_name=PERSONS_DISTINCT_ID_TABLE, + cluster=CLICKHOUSE_CLUSTER, + database=CLICKHOUSE_DATABASE, ) # @@ -216,7 +225,9 @@ _partition FROM {database}.kafka_{table_name} """.format( - table_name=PERSON_DISTINCT_ID2_TABLE, cluster=CLICKHOUSE_CLUSTER, database=CLICKHOUSE_DATABASE + table_name=PERSON_DISTINCT_ID2_TABLE, + cluster=CLICKHOUSE_CLUSTER, + database=CLICKHOUSE_DATABASE, ) # diff --git a/posthog/models/person/util.py b/posthog/models/person/util.py index 9af13bc6e9d05..7e8afc3db5e78 100644 --- a/posthog/models/person/util.py +++ b/posthog/models/person/util.py @@ -13,7 +13,11 @@ from posthog.client import sync_execute from posthog.kafka_client.client import ClickhouseProducer -from posthog.kafka_client.topics import KAFKA_PERSON, KAFKA_PERSON_DISTINCT_ID, KAFKA_PERSON_OVERRIDES +from posthog.kafka_client.topics import ( + KAFKA_PERSON, + KAFKA_PERSON_DISTINCT_ID, + KAFKA_PERSON_OVERRIDES, +) from posthog.models.person import Person, PersonDistinctId from posthog.models.person.sql import ( BULK_INSERT_PERSON_DISTINCT_ID2, @@ -53,12 +57,22 @@ def person_distinct_id_created(sender, instance: PersonDistinctId, created, **kw @receiver(post_delete, sender=Person) def person_deleted(sender, instance: Person, **kwargs): - _delete_person(instance.team.id, instance.uuid, int(instance.version or 0), instance.created_at, sync=True) + _delete_person( + instance.team.id, + instance.uuid, + int(instance.version or 0), + instance.created_at, + sync=True, + ) @receiver(post_delete, sender=PersonDistinctId) def person_distinct_id_deleted(sender, instance: PersonDistinctId, **kwargs): _delete_ch_distinct_id( - instance.team.pk, instance.person.uuid, instance.distinct_id, instance.version or 0, sync=True + instance.team.pk, + instance.person.uuid, + instance.distinct_id, + instance.version or 0, + sync=True, ) try: @@ -83,7 +97,11 @@ def bulk_create_persons(persons_list: List[Dict]): for index, person in enumerate(inserted): for distinct_id in persons_list[index]["distinct_ids"]: distinct_ids.append( - PersonDistinctId(person_id=person.pk, distinct_id=distinct_id, team_id=person.team_id) + PersonDistinctId( + person_id=person.pk, + distinct_id=distinct_id, + team_id=person.team_id, + ) ) distinct_id_inserts.append(f"('{distinct_id}', '{person.uuid}', {person.team_id}, 0, 0, now(), 0, 0)") person_mapping[distinct_id] = person @@ -96,7 +114,10 @@ def bulk_create_persons(persons_list: List[Dict]): PersonDistinctId.objects.bulk_create(distinct_ids) sync_execute(INSERT_PERSON_BULK_SQL + ", ".join(person_inserts), flush=False) - sync_execute(BULK_INSERT_PERSON_DISTINCT_ID2 + ", ".join(distinct_id_inserts), flush=False) + sync_execute( + BULK_INSERT_PERSON_DISTINCT_ID2 + ", ".join(distinct_id_inserts), + flush=False, + ) return person_mapping @@ -147,7 +168,12 @@ def create_person( def create_person_distinct_id( - team_id: int, distinct_id: str, person_id: str, version=0, is_deleted: bool = False, sync: bool = False + team_id: int, + distinct_id: str, + person_id: str, + version=0, + is_deleted: bool = False, + sync: bool = False, ) -> None: p = ClickhouseProducer() p.produce( @@ -191,7 +217,9 @@ def create_person_override( def get_persons_by_distinct_ids(team_id: int, distinct_ids: List[str]) -> QuerySet: return Person.objects.filter( - team_id=team_id, persondistinctid__team_id=team_id, persondistinctid__distinct_id__in=distinct_ids + team_id=team_id, + persondistinctid__team_id=team_id, + persondistinctid__distinct_id__in=distinct_ids, ) @@ -208,7 +236,11 @@ def delete_person(person: Person, sync: bool = False) -> None: def _delete_person( - team_id: int, uuid: UUID, version: int, created_at: Optional[datetime.datetime] = None, sync: bool = False + team_id: int, + uuid: UUID, + version: int, + created_at: Optional[datetime.datetime] = None, + sync: bool = False, ) -> None: create_person( uuid=str(uuid), diff --git a/posthog/models/person_overrides/sql.py b/posthog/models/person_overrides/sql.py index 853988495f639..c518db6de0e11 100644 --- a/posthog/models/person_overrides/sql.py +++ b/posthog/models/person_overrides/sql.py @@ -14,7 +14,11 @@ from django.conf import settings from posthog.kafka_client.topics import KAFKA_PERSON_OVERRIDE -from posthog.settings.data_stores import CLICKHOUSE_CLUSTER, CLICKHOUSE_DATABASE, KAFKA_HOSTS +from posthog.settings.data_stores import ( + CLICKHOUSE_CLUSTER, + CLICKHOUSE_DATABASE, + KAFKA_HOSTS, +) PERSON_OVERRIDES_CREATE_TABLE_SQL = f""" CREATE TABLE IF NOT EXISTS `{CLICKHOUSE_DATABASE}`.`person_overrides` diff --git a/posthog/models/personal_api_key.py b/posthog/models/personal_api_key.py index 7d42679a627a4..8692654e3861a 100644 --- a/posthog/models/personal_api_key.py +++ b/posthog/models/personal_api_key.py @@ -29,5 +29,9 @@ class PersonalAPIKey(models.Model): # DEPRECATED: personal API keys are now specifically personal, without team affiliation team = models.ForeignKey( - "posthog.Team", on_delete=models.SET_NULL, related_name="personal_api_keys+", null=True, blank=True + "posthog.Team", + on_delete=models.SET_NULL, + related_name="personal_api_keys+", + null=True, + blank=True, ) diff --git a/posthog/models/plugin.py b/posthog/models/plugin.py index 0f055f9d68c49..b8787dd3df344 100644 --- a/posthog/models/plugin.py +++ b/posthog/models/plugin.py @@ -135,12 +135,24 @@ def install(self, **kwargs) -> "Plugin": class Plugin(models.Model): class PluginType(models.TextChoices): LOCAL = "local", "local" # url starts with "file:" - CUSTOM = "custom", "custom" # github or npm url downloaded as zip or tar.gz into field "archive" - REPOSITORY = "repository", "repository" # same, but originating from our plugins.json repository - SOURCE = "source", "source" # coded inside the browser (versioned via plugin_source_version) + CUSTOM = ( + "custom", + "custom", + ) # github or npm url downloaded as zip or tar.gz into field "archive" + REPOSITORY = ( + "repository", + "repository", + ) # same, but originating from our plugins.json repository + SOURCE = ( + "source", + "source", + ) # coded inside the browser (versioned via plugin_source_version) organization: models.ForeignKey = models.ForeignKey( - "posthog.Organization", on_delete=models.CASCADE, related_name="plugins", related_query_name="plugin" + "posthog.Organization", + on_delete=models.CASCADE, + related_name="plugins", + related_query_name="plugin", ) plugin_type: models.CharField = models.CharField( max_length=200, null=True, blank=True, choices=PluginType.choices, default=None @@ -240,7 +252,10 @@ class PluginAttachment(models.Model): class PluginStorage(models.Model): class Meta: constraints = [ - models.UniqueConstraint(fields=["plugin_config_id", "key"], name="posthog_unique_plugin_storage_key") + models.UniqueConstraint( + fields=["plugin_config_id", "key"], + name="posthog_unique_plugin_storage_key", + ) ] plugin_config: models.ForeignKey = models.ForeignKey("PluginConfig", on_delete=models.CASCADE) @@ -266,7 +281,10 @@ class PluginSourceFileManager(models.Manager): def sync_from_plugin_archive( self, plugin: Plugin, plugin_json_parsed: Optional[Dict[str, Any]] = None ) -> Tuple[ - "PluginSourceFile", Optional["PluginSourceFile"], Optional["PluginSourceFile"], Optional["PluginSourceFile"] + "PluginSourceFile", + Optional["PluginSourceFile"], + Optional["PluginSourceFile"], + Optional["PluginSourceFile"], ]: """Create PluginSourceFile objects from a plugin that has an archive. @@ -281,7 +299,12 @@ def sync_from_plugin_archive( plugin_json_instance, _ = PluginSourceFile.objects.update_or_create( plugin=plugin, filename="plugin.json", - defaults={"source": plugin_json, "transpiled": None, "status": None, "error": None}, + defaults={ + "source": plugin_json, + "transpiled": None, + "status": None, + "error": None, + }, ) # Save frontend.tsx frontend_tsx_instance: Optional["PluginSourceFile"] = None @@ -289,7 +312,12 @@ def sync_from_plugin_archive( frontend_tsx_instance, _ = PluginSourceFile.objects.update_or_create( plugin=plugin, filename="frontend.tsx", - defaults={"source": frontend_tsx, "transpiled": None, "status": None, "error": None}, + defaults={ + "source": frontend_tsx, + "transpiled": None, + "status": None, + "error": None, + }, ) else: filenames_to_delete.append("frontend.tsx") @@ -299,7 +327,12 @@ def sync_from_plugin_archive( site_ts_instance, _ = PluginSourceFile.objects.update_or_create( plugin=plugin, filename="site.ts", - defaults={"source": site_ts, "transpiled": None, "status": None, "error": None}, + defaults={ + "source": site_ts, + "transpiled": None, + "status": None, + "error": None, + }, ) else: filenames_to_delete.append("site.ts") @@ -311,7 +344,12 @@ def sync_from_plugin_archive( index_ts_instance, _ = PluginSourceFile.objects.update_or_create( plugin=plugin, filename="index.ts", - defaults={"source": index_ts, "transpiled": None, "status": None, "error": None}, + defaults={ + "source": index_ts, + "transpiled": None, + "status": None, + "error": None, + }, ) else: filenames_to_delete.append("index.ts") @@ -319,7 +357,12 @@ def sync_from_plugin_archive( PluginSourceFile.objects.filter(plugin=plugin, filename__in=filenames_to_delete).delete() # Trigger plugin server reload and code transpilation plugin.save() - return plugin_json_instance, index_ts_instance, frontend_tsx_instance, site_ts_instance + return ( + plugin_json_instance, + index_ts_instance, + frontend_tsx_instance, + site_ts_instance, + ) class PluginSourceFile(UUIDModel): @@ -431,7 +474,8 @@ def preinstall_plugins_for_new_organization(sender, instance: Organization, crea ) except Exception as e: print( - f"⚠️ Cannot preinstall plugin from {plugin_url}, skipping it for organization {instance.name}:\n", e + f"⚠️ Cannot preinstall plugin from {plugin_url}, skipping it for organization {instance.name}:\n", + e, ) @@ -439,7 +483,6 @@ def preinstall_plugins_for_new_organization(sender, instance: Organization, crea def enable_preinstalled_plugins_for_new_team(sender, instance: Team, created: bool, **kwargs): if created and can_configure_plugins(instance.organization): for order, preinstalled_plugin in enumerate(Plugin.objects.filter(is_preinstalled=True)): - PluginConfig.objects.create( team=instance, plugin=preinstalled_plugin, diff --git a/posthog/models/prompt/prompt.py b/posthog/models/prompt/prompt.py index 74d55a0f43354..2d975a54b3e1a 100644 --- a/posthog/models/prompt/prompt.py +++ b/posthog/models/prompt/prompt.py @@ -4,7 +4,6 @@ class Prompt(models.Model): - step: models.IntegerField = models.IntegerField() type: models.CharField = models.CharField(max_length=200) # tooltip, modal, etc title: models.CharField = models.CharField(max_length=200) diff --git a/posthog/models/property/property.py b/posthog/models/property/property.py index ff57e46b77e21..3b2b2decbc574 100644 --- a/posthog/models/property/property.py +++ b/posthog/models/property/property.py @@ -78,7 +78,12 @@ class BehavioralPropertyType(str, Enum): PropertyIdentifier = Tuple[PropertyName, PropertyType, Optional[GroupTypeIndex]] NEGATED_OPERATORS = ["is_not", "not_icontains", "not_regex", "is_not_set"] -CLICKHOUSE_ONLY_PROPERTY_TYPES = ["static-cohort", "precalculated-cohort", "behavioral", "recording"] +CLICKHOUSE_ONLY_PROPERTY_TYPES = [ + "static-cohort", + "precalculated-cohort", + "behavioral", + "recording", +] VALIDATE_PROP_TYPES = { "event": ["key", "value"], @@ -95,7 +100,13 @@ class BehavioralPropertyType(str, Enum): } VALIDATE_BEHAVIORAL_PROP_TYPES = { - BehavioralPropertyType.PERFORMED_EVENT: ["key", "value", "event_type", "time_value", "time_interval"], + BehavioralPropertyType.PERFORMED_EVENT: [ + "key", + "value", + "event_type", + "time_value", + "time_interval", + ], BehavioralPropertyType.PERFORMED_EVENT_MULTIPLE: [ "key", "value", @@ -104,7 +115,13 @@ class BehavioralPropertyType(str, Enum): "time_interval", "operator_value", ], - BehavioralPropertyType.PERFORMED_EVENT_FIRST_TIME: ["key", "value", "event_type", "time_value", "time_interval"], + BehavioralPropertyType.PERFORMED_EVENT_FIRST_TIME: [ + "key", + "value", + "event_type", + "time_value", + "time_interval", + ], BehavioralPropertyType.PERFORMED_EVENT_SEQUENCE: [ "key", "value", @@ -282,7 +299,11 @@ class PropertyGroup: type: PropertyOperatorType values: Union[List[Property], List["PropertyGroup"]] - def __init__(self, type: PropertyOperatorType, values: Union[List[Property], List["PropertyGroup"]]) -> None: + def __init__( + self, + type: PropertyOperatorType, + values: Union[List[Property], List["PropertyGroup"]], + ) -> None: self.type = type self.values = values @@ -310,7 +331,10 @@ def to_dict(self): if not self.values: return {} - return {"type": self.type.value, "values": [prop.to_dict() for prop in self.values]} + return { + "type": self.type.value, + "values": [prop.to_dict() for prop in self.values], + } def __repr__(self): params_repr = ", ".join(f"{repr(prop)}" for prop in self.values) diff --git a/posthog/models/property/util.py b/posthog/models/property/util.py index 18368ac082f5d..b353eb11bb141 100644 --- a/posthog/models/property/util.py +++ b/posthog/models/property/util.py @@ -17,7 +17,10 @@ from posthog.clickhouse.client.escape import escape_param_for_clickhouse from posthog.clickhouse.kafka_engine import trim_quotes_expr -from posthog.clickhouse.materialized_columns import TableWithProperties, get_materialized_columns +from posthog.clickhouse.materialized_columns import ( + TableWithProperties, + get_materialized_columns, +) from posthog.constants import PropertyOperatorType from posthog.hogql import ast from posthog.hogql.hogql import HogQLContext @@ -36,7 +39,10 @@ ) from posthog.models.event import Selector from posthog.models.group.sql import GET_GROUP_IDS_BY_PROPERTY_SQL -from posthog.models.person.sql import GET_DISTINCT_IDS_BY_PERSON_ID_FILTER, GET_DISTINCT_IDS_BY_PROPERTY_SQL +from posthog.models.person.sql import ( + GET_DISTINCT_IDS_BY_PERSON_ID_FILTER, + GET_DISTINCT_IDS_BY_PROPERTY_SQL, +) from posthog.models.property import ( NEGATED_OPERATORS, OperatorType, @@ -177,13 +183,19 @@ def parse_prop_clauses( else: if person_properties_mode == PersonPropertiesMode.USING_SUBQUERY: person_id_query, cohort_filter_params = format_filter_query( - cohort, idx, hogql_context, custom_match_field=person_id_joined_alias + cohort, + idx, + hogql_context, + custom_match_field=person_id_joined_alias, ) params = {**params, **cohort_filter_params} final.append(f"{property_operator} {table_formatted}distinct_id IN ({person_id_query})") else: person_id_query, cohort_filter_params = format_cohort_subquery( - cohort, idx, hogql_context, custom_match_field=f"{person_id_joined_alias}" + cohort, + idx, + hogql_context, + custom_match_field=f"{person_id_joined_alias}", ) params = {**params, **cohort_filter_params} final.append(f"{property_operator} {person_id_query}") @@ -236,7 +248,8 @@ def parse_prop_clauses( final.append( " {property_operator} {table_name}distinct_id IN ({filter_query})".format( filter_query=GET_DISTINCT_IDS_BY_PROPERTY_SQL.format( - filters=filter_query, GET_TEAM_PERSON_DISTINCT_IDS=get_team_distinct_ids_query(team_id) + filters=filter_query, + GET_TEAM_PERSON_DISTINCT_IDS=get_team_distinct_ids_query(team_id), ), table_name=table_formatted, property_operator=property_operator, @@ -270,7 +283,10 @@ def parse_prop_clauses( params.update(filter_params) elif prop.type == "element": query, filter_params = filter_element( - cast(StringMatching, prop.key), prop.value, operator=prop.operator, prepend="{}_".format(prepend) + cast(StringMatching, prop.key), + prop.value, + operator=prop.operator, + prepend="{}_".format(prepend), ) if query: final.append(f"{property_operator} {query}") @@ -278,7 +294,10 @@ def parse_prop_clauses( elif ( prop.type == "group" and person_properties_mode - in [PersonPropertiesMode.DIRECT_ON_EVENTS, PersonPropertiesMode.DIRECT_ON_EVENTS_WITH_POE_V2] + in [ + PersonPropertiesMode.DIRECT_ON_EVENTS, + PersonPropertiesMode.DIRECT_ON_EVENTS_WITH_POE_V2, + ] and groups_on_events_querying_enabled() ): group_column = f"group{prop.group_type_index}_properties" @@ -308,7 +327,11 @@ def parse_prop_clauses( else: # :TRICKY: offer groups support for queries which don't support automatically joining with groups table yet (e.g. lifecycle) filter_query, filter_params = prop_filter_json_extract( - prop, idx, prepend, prop_var=f"group_properties", allow_denormalized_props=False + prop, + idx, + prepend, + prop_var=f"group_properties", + allow_denormalized_props=False, ) group_type_index_var = f"{prepend}_group_type_index_{idx}" groups_subquery = GET_GROUP_IDS_BY_PROPERTY_SQL.format( @@ -335,7 +358,8 @@ def parse_prop_clauses( else: # :TODO: (performance) Avoid subqueries whenever possible, use joins instead subquery = GET_DISTINCT_IDS_BY_PERSON_ID_FILTER.format( - filters=filter_query, GET_TEAM_PERSON_DISTINCT_IDS=get_team_distinct_ids_query(team_id) + filters=filter_query, + GET_TEAM_PERSON_DISTINCT_IDS=get_team_distinct_ids_query(team_id), ) final.append(f"{property_operator} {table_formatted}distinct_id IN ({subquery})") params.update(filter_params) @@ -415,28 +439,46 @@ def prop_filter_json_extract( params: Dict[str, Any] = {} if operator == "is_not": - params = {"k{}_{}".format(prepend, idx): prop.key, "v{}_{}".format(prepend, idx): box_value(prop.value)} + params = { + "k{}_{}".format(prepend, idx): prop.key, + "v{}_{}".format(prepend, idx): box_value(prop.value), + } return ( " {property_operator} NOT has(%(v{prepend}_{idx})s, {left})".format( - idx=idx, prepend=prepend, left=property_expr, property_operator=property_operator + idx=idx, + prepend=prepend, + left=property_expr, + property_operator=property_operator, ), params, ) elif operator == "icontains": value = "%{}%".format(prop.value) - params = {"k{}_{}".format(prepend, idx): prop.key, "v{}_{}".format(prepend, idx): value} + params = { + "k{}_{}".format(prepend, idx): prop.key, + "v{}_{}".format(prepend, idx): value, + } return ( " {property_operator} {left} ILIKE %(v{prepend}_{idx})s".format( - idx=idx, prepend=prepend, left=property_expr, property_operator=property_operator + idx=idx, + prepend=prepend, + left=property_expr, + property_operator=property_operator, ), params, ) elif operator == "not_icontains": value = "%{}%".format(prop.value) - params = {"k{}_{}".format(prepend, idx): prop.key, "v{}_{}".format(prepend, idx): value} + params = { + "k{}_{}".format(prepend, idx): prop.key, + "v{}_{}".format(prepend, idx): value, + } return ( " {property_operator} NOT ({left} ILIKE %(v{prepend}_{idx})s)".format( - idx=idx, prepend=prepend, left=property_expr, property_operator=property_operator + idx=idx, + prepend=prepend, + left=property_expr, + property_operator=property_operator, ), params, ) @@ -445,7 +487,10 @@ def prop_filter_json_extract( # If OR'ing, shouldn't be a problem since nothing will match this specific clause return f"{property_operator} 1 = 2", {} - params = {"k{}_{}".format(prepend, idx): prop.key, "v{}_{}".format(prepend, idx): prop.value} + params = { + "k{}_{}".format(prepend, idx): prop.key, + "v{}_{}".format(prepend, idx): prop.value, + } return ( " {property_operator} {regex_function}({left}, %(v{prepend}_{idx})s)".format( @@ -458,7 +503,10 @@ def prop_filter_json_extract( params, ) elif operator == "is_set": - params = {"k{}_{}".format(prepend, idx): prop.key, "v{}_{}".format(prepend, idx): prop.value} + params = { + "k{}_{}".format(prepend, idx): prop.key, + "v{}_{}".format(prepend, idx): prop.value, + } if is_denormalized: return ( " {property_operator} notEmpty({left})".format(left=property_expr, property_operator=property_operator), @@ -466,12 +514,18 @@ def prop_filter_json_extract( ) return ( " {property_operator} JSONHas({prop_var}, %(k{prepend}_{idx})s)".format( - idx=idx, prepend=prepend, prop_var=prop_var, property_operator=property_operator + idx=idx, + prepend=prepend, + prop_var=prop_var, + property_operator=property_operator, ), params, ) elif operator == "is_not_set": - params = {"k{}_{}".format(prepend, idx): prop.key, "v{}_{}".format(prepend, idx): prop.value} + params = { + "k{}_{}".format(prepend, idx): prop.key, + "v{}_{}".format(prepend, idx): prop.value, + } if is_denormalized: return ( " {property_operator} empty({left})".format(left=property_expr, property_operator=property_operator), @@ -479,7 +533,11 @@ def prop_filter_json_extract( ) return ( " {property_operator} (isNull({left}) OR NOT JSONHas({prop_var}, %(k{prepend}_{idx})s))".format( - idx=idx, prepend=prepend, prop_var=prop_var, left=property_expr, property_operator=property_operator + idx=idx, + prepend=prepend, + prop_var=prop_var, + left=property_expr, + property_operator=property_operator, ), params, ) @@ -496,7 +554,10 @@ def prop_filter_json_extract( parseDateTimeBestEffortOrNull(substring({property_expr}, 1, 10)) )) = %({prop_value_param_key})s""" - return (query, {"k{}_{}".format(prepend, idx): prop.key, prop_value_param_key: prop.value}) + return ( + query, + {"k{}_{}".format(prepend, idx): prop.key, prop_value_param_key: prop.value}, + ) elif operator == "is_date_after": # TODO introducing duplication in these branches now rather than refactor too early assert isinstance(prop.value, str) @@ -518,7 +579,10 @@ def prop_filter_json_extract( query = f"""{property_operator} {first_of_date_or_timestamp} > {adjusted_value}""" - return (query, {"k{}_{}".format(prepend, idx): prop.key, prop_value_param_key: prop.value}) + return ( + query, + {"k{}_{}".format(prepend, idx): prop.key, prop_value_param_key: prop.value}, + ) elif operator == "is_date_before": # TODO introducing duplication in these branches now rather than refactor too early assert isinstance(prop.value, str) @@ -528,11 +592,17 @@ def prop_filter_json_extract( first_of_date_or_timestamp = f"coalesce({try_parse_as_date},{try_parse_as_timestamp})" query = f"""{property_operator} {first_of_date_or_timestamp} < %({prop_value_param_key})s""" - return (query, {"k{}_{}".format(prepend, idx): prop.key, prop_value_param_key: prop.value}) + return ( + query, + {"k{}_{}".format(prepend, idx): prop.key, prop_value_param_key: prop.value}, + ) elif operator in ["gt", "lt", "gte", "lte"]: count_operator = get_count_operator(operator) - params = {"k{}_{}".format(prepend, idx): prop.key, "v{}_{}".format(prepend, idx): prop.value} + params = { + "k{}_{}".format(prepend, idx): prop.key, + "v{}_{}".format(prepend, idx): prop.value, + } extract_property_expr = trim_quotes_expr(f"replaceRegexpAll({property_expr}, ' ', '')") return ( f" {property_operator} toFloat64OrNull({extract_property_expr}) {count_operator} %(v{prepend}_{idx})s", @@ -547,10 +617,17 @@ def prop_filter_json_extract( } else: clause = " {property_operator} has(%(v{prepend}_{idx})s, {left})" - params = {"k{}_{}".format(prepend, idx): prop.key, "v{}_{}".format(prepend, idx): box_value(prop.value)} + params = { + "k{}_{}".format(prepend, idx): prop.key, + "v{}_{}".format(prepend, idx): box_value(prop.value), + } return ( clause.format( - left=property_expr, idx=idx, prepend=prepend, prop_var=prop_var, property_operator=property_operator + left=property_expr, + idx=idx, + prepend=prepend, + prop_var=prop_var, + property_operator=property_operator, ), params, ) @@ -664,7 +741,10 @@ def get_property_string_expr( and (property_name, materialised_table_column) in materialized_columns and ("group" not in materialised_table_column or groups_on_events_querying_enabled()) ): - return f'{table_string}"{materialized_columns[(property_name, materialised_table_column)]}"', True + return ( + f'{table_string}"{materialized_columns[(property_name, materialised_table_column)]}"', + True, + ) return trim_quotes_expr(f"JSONExtractRaw({table_string}{column}, {var})"), False @@ -731,7 +811,10 @@ def filter_element( raise ValueError(f'Invalid element filtering key "{key}"') if combination_conditions: - return f"{'NOT ' if operator in NEGATED_OPERATORS else ''}({' OR '.join(combination_conditions)})", params + return ( + f"{'NOT ' if operator in NEGATED_OPERATORS else ''}({' OR '.join(combination_conditions)})", + params, + ) else: # If there are no values to filter by, this either matches nothing (for non-negated operators like "equals"), # or everything (for negated operators like "doesn't equal") @@ -837,7 +920,10 @@ def get_session_property_filter_statement(prop: Property, idx: int, prepend: str value = f"session_duration_value{prepend}_{idx}" operator = get_count_operator(prop.operator) - return (f"{SessionQuery.SESSION_TABLE_ALIAS}.session_duration {operator} %({value})s", {value: duration}) + return ( + f"{SessionQuery.SESSION_TABLE_ALIAS}.session_duration {operator} %({value})s", + {value: duration}, + ) else: raise exceptions.ValidationError(f"Property '{prop.key}' is not allowed in session property filters.") diff --git a/posthog/models/property_definition.py b/posthog/models/property_definition.py index b295229a8cfcd..7747a17c71820 100644 --- a/posthog/models/property_definition.py +++ b/posthog/models/property_definition.py @@ -16,7 +16,10 @@ class PropertyType(models.TextChoices): class PropertyFormat(models.TextChoices): UnixTimestamp = "unix_timestamp", "Unix Timestamp in seconds" - UnixTimestampMilliseconds = "unix_timestamp_milliseconds", "Unix Timestamp in milliseconds" + UnixTimestampMilliseconds = ( + "unix_timestamp_milliseconds", + "Unix Timestamp in milliseconds", + ) ISO8601Date = "YYYY-MM-DDThh:mm:ssZ", "YYYY-MM-DDThh:mm:ssZ" FullDate = "YYYY-MM-DD hh:mm:ss", "YYYY-MM-DD hh:mm:ss" FullDateIncreasing = "DD-MM-YYYY hh:mm:ss", "DD-MM-YYYY hh:mm:ss" @@ -33,7 +36,10 @@ class Type(models.IntegerChoices): GROUP = 3, "group" team: models.ForeignKey = models.ForeignKey( - Team, on_delete=models.CASCADE, related_name="property_definitions", related_query_name="team" + Team, + on_delete=models.CASCADE, + related_name="property_definitions", + related_query_name="team", ) name: models.CharField = models.CharField(max_length=400) is_numerical: models.BooleanField = models.BooleanField( @@ -45,7 +51,7 @@ class Type(models.IntegerChoices): # :TRICKY: May be null for historical events type: models.PositiveSmallIntegerField = models.PositiveSmallIntegerField(default=Type.EVENT, choices=Type.choices) # Only populated for `Type.GROUP` - group_type_index: models.PositiveSmallIntegerField = models.PositiveSmallIntegerField(null=True) + group_type_index: (models.PositiveSmallIntegerField) = models.PositiveSmallIntegerField(null=True) # DEPRECATED property_type_format = models.CharField( @@ -76,15 +82,19 @@ class Meta: models.Index(fields=["team_id", "type", "is_numerical"]), ] + [ GinIndex( - name="index_property_definition_name", fields=["name"], opclasses=["gin_trgm_ops"] + name="index_property_definition_name", + fields=["name"], + opclasses=["gin_trgm_ops"], ) # To speed up DB-based fuzzy searching ] constraints = [ models.CheckConstraint( - name="property_type_is_valid", check=models.Q(property_type__in=PropertyType.values) + name="property_type_is_valid", + check=models.Q(property_type__in=PropertyType.values), ), models.CheckConstraint( - name="group_type_index_set", check=~models.Q(type=3) | models.Q(group_type_index__isnull=False) + name="group_type_index_set", + check=~models.Q(type=3) | models.Q(group_type_index__isnull=False), ), UniqueConstraintByExpression( name="posthog_propertydefinition_uniq", diff --git a/posthog/models/sharing_configuration.py b/posthog/models/sharing_configuration.py index 7dcdcb7e8f2b9..44cc70cbb7be4 100644 --- a/posthog/models/sharing_configuration.py +++ b/posthog/models/sharing_configuration.py @@ -26,7 +26,11 @@ class SharingConfiguration(models.Model): enabled: models.BooleanField = models.BooleanField(default=False) access_token: models.CharField = models.CharField( - max_length=400, null=True, blank=True, default=get_default_access_token, unique=True + max_length=400, + null=True, + blank=True, + default=get_default_access_token, + unique=True, ) def can_access_object(self, obj: models.Model): diff --git a/posthog/models/subscription.py b/posthog/models/subscription.py index e291f7c1b0490..3680155f7df27 100644 --- a/posthog/models/subscription.py +++ b/posthog/models/subscription.py @@ -92,7 +92,10 @@ def __init__(self, *args, **kwargs): interval: models.IntegerField = models.IntegerField(default=1) count: models.IntegerField = models.IntegerField(null=True) byweekday: ArrayField = ArrayField( - models.CharField(max_length=10, choices=SubscriptionByWeekDay.choices), null=True, blank=True, default=None + models.CharField(max_length=10, choices=SubscriptionByWeekDay.choices), + null=True, + blank=True, + default=None, ) bysetpos: models.IntegerField = models.IntegerField(null=True) start_date: models.DateTimeField = models.DateTimeField() @@ -141,7 +144,9 @@ def url(self): def resource_info(self) -> Optional[SubscriptionResourceInfo]: if self.insight: return SubscriptionResourceInfo( - "Insight", f"{self.insight.name or self.insight.derived_name}", self.insight.url + "Insight", + f"{self.insight.name or self.insight.derived_name}", + self.insight.url, ) elif self.dashboard: return SubscriptionResourceInfo("Dashboard", self.dashboard.name, self.dashboard.url) @@ -151,14 +156,25 @@ def resource_info(self) -> Optional[SubscriptionResourceInfo]: @property def summary(self): try: - human_frequency = {"daily": "day", "weekly": "week", "monthly": "month", "yearly": "year"}[self.frequency] + human_frequency = { + "daily": "day", + "weekly": "week", + "monthly": "month", + "yearly": "year", + }[self.frequency] if self.interval > 1: human_frequency = f"{human_frequency}s" summary = f"sent every {str(self.interval) + ' ' if self.interval > 1 else ''}{human_frequency}" if self.byweekday and self.bysetpos: - human_bysetpos = {1: "first", 2: "second", 3: "third", 4: "fourth", -1: "last"}[self.bysetpos] + human_bysetpos = { + 1: "first", + 2: "second", + 3: "third", + 4: "fourth", + -1: "last", + }[self.bysetpos] summary += ( f" on the {human_bysetpos} {self.byweekday[0].capitalize() if len(self.byweekday) == 1 else 'day'}" ) diff --git a/posthog/models/tagged_item.py b/posthog/models/tagged_item.py index 3d6b73383aaf8..4c55c4a663791 100644 --- a/posthog/models/tagged_item.py +++ b/posthog/models/tagged_item.py @@ -6,7 +6,14 @@ from posthog.models.utils import UUIDModel -RELATED_OBJECTS = ("dashboard", "insight", "event_definition", "property_definition", "action", "feature_flag") +RELATED_OBJECTS = ( + "dashboard", + "insight", + "event_definition", + "property_definition", + "action", + "feature_flag", +) # Checks that exactly one object field is populated @@ -14,7 +21,10 @@ def build_check(related_objects: Iterable[str]): built_check_list: List[Union[Q, Q]] = [] for field in related_objects: built_check_list.append( - Q(*[(f"{other_field}__isnull", other_field != field) for other_field in related_objects], _connector="AND") + Q( + *[(f"{other_field}__isnull", other_field != field) for other_field in related_objects], + _connector="AND", + ) ) return Q(*built_check_list, _connector="OR") @@ -23,7 +33,9 @@ def build_check(related_objects: Iterable[str]): # uniqueness across null columns. def build_partial_uniqueness_constraint(field: str): return UniqueConstraint( - fields=["tag", field], name=f"unique_{field}_tagged_item", condition=Q((f"{field}__isnull", False)) + fields=["tag", field], + name=f"unique_{field}_tagged_item", + condition=Q((f"{field}__isnull", False)), ) @@ -47,22 +59,46 @@ class TaggedItem(UUIDModel): # When adding a new taggeditem-model relationship, make sure to add the foreign key field and append field name to # the `RELATED_OBJECTS` tuple above. dashboard: models.ForeignKey = models.ForeignKey( - "Dashboard", on_delete=models.CASCADE, null=True, blank=True, related_name="tagged_items" + "Dashboard", + on_delete=models.CASCADE, + null=True, + blank=True, + related_name="tagged_items", ) insight: models.ForeignKey = models.ForeignKey( - "Insight", on_delete=models.CASCADE, null=True, blank=True, related_name="tagged_items" + "Insight", + on_delete=models.CASCADE, + null=True, + blank=True, + related_name="tagged_items", ) event_definition: models.ForeignKey = models.ForeignKey( - "EventDefinition", on_delete=models.CASCADE, null=True, blank=True, related_name="tagged_items" + "EventDefinition", + on_delete=models.CASCADE, + null=True, + blank=True, + related_name="tagged_items", ) property_definition: models.ForeignKey = models.ForeignKey( - "PropertyDefinition", on_delete=models.CASCADE, null=True, blank=True, related_name="tagged_items" + "PropertyDefinition", + on_delete=models.CASCADE, + null=True, + blank=True, + related_name="tagged_items", ) action: models.ForeignKey = models.ForeignKey( - "Action", on_delete=models.CASCADE, null=True, blank=True, related_name="tagged_items" + "Action", + on_delete=models.CASCADE, + null=True, + blank=True, + related_name="tagged_items", ) feature_flag: models.ForeignKey = models.ForeignKey( - "FeatureFlag", on_delete=models.CASCADE, null=True, blank=True, related_name="tagged_items" + "FeatureFlag", + on_delete=models.CASCADE, + null=True, + blank=True, + related_name="tagged_items", ) class Meta: diff --git a/posthog/models/team/team.py b/posthog/models/team/team.py index 4cd9ae773fdeb..bc458807b56a4 100644 --- a/posthog/models/team/team.py +++ b/posthog/models/team/team.py @@ -7,7 +7,11 @@ import pytz from django.conf import settings from django.contrib.postgres.fields import ArrayField -from django.core.validators import MinLengthValidator, MaxValueValidator, MinValueValidator +from django.core.validators import ( + MinLengthValidator, + MaxValueValidator, + MinValueValidator, +) from django.db import models from django.db.models.signals import post_delete, post_save from zoneinfo import ZoneInfo @@ -20,7 +24,11 @@ from posthog.models.filters.utils import GroupTypeIndex from posthog.models.instance_setting import get_instance_setting from posthog.models.signals import mutable_receiver -from posthog.models.utils import UUIDClassicModel, generate_random_token_project, sane_repr +from posthog.models.utils import ( + UUIDClassicModel, + generate_random_token_project, + sane_repr, +) from posthog.settings.utils import get_list from posthog.utils import GenericEmails, PersonOnEventsMode @@ -66,7 +74,12 @@ def set_test_account_filters(self, organization: Optional[Any]) -> List: example_email = re.search(r"@[\w.]+", example_emails[0]) if example_email: return [ - {"key": "email", "operator": "not_icontains", "value": example_email.group(), "type": "person"} + { + "key": "email", + "operator": "not_icontains", + "value": example_email.group(), + "type": "person", + } ] + filters return filters @@ -126,7 +139,10 @@ def clickhouse_mode(self) -> str: class Team(UUIDClassicModel): organization: models.ForeignKey = models.ForeignKey( - "posthog.Organization", on_delete=models.CASCADE, related_name="teams", related_query_name="team" + "posthog.Organization", + on_delete=models.CASCADE, + related_name="teams", + related_query_name="team", ) api_token: models.CharField = models.CharField( max_length=200, @@ -136,7 +152,9 @@ class Team(UUIDClassicModel): ) app_urls: ArrayField = ArrayField(models.CharField(max_length=200, null=True), default=list, blank=True) name: models.CharField = models.CharField( - max_length=200, default="Default Project", validators=[MinLengthValidator(1, "Project must have a name!")] + max_length=200, + default="Default Project", + validators=[MinLengthValidator(1, "Project must have a name!")], ) slack_incoming_webhook: models.CharField = models.CharField(max_length=500, null=True, blank=True) created_at: models.DateTimeField = models.DateTimeField(auto_now_add=True) @@ -157,8 +175,10 @@ class Team(UUIDClassicModel): decimal_places=2, validators=[MinValueValidator(Decimal(0)), MaxValueValidator(Decimal(1))], ) - session_recording_minimum_duration_milliseconds: models.IntegerField = models.IntegerField( - null=True, blank=True, validators=[MinValueValidator(0), MaxValueValidator(15000)] + session_recording_minimum_duration_milliseconds: (models.IntegerField) = models.IntegerField( + null=True, + blank=True, + validators=[MinValueValidator(0), MaxValueValidator(15000)], ) session_recording_linked_flag: models.JSONField = models.JSONField(null=True, blank=True) capture_console_log_opt_in: models.BooleanField = models.BooleanField(null=True, blank=True) @@ -185,7 +205,11 @@ class Team(UUIDClassicModel): recording_domains: ArrayField = ArrayField(models.CharField(max_length=200, null=True), blank=True, null=True) primary_dashboard: models.ForeignKey = models.ForeignKey( - "posthog.Dashboard", on_delete=models.SET_NULL, null=True, related_name="primary_dashboard_teams", blank=True + "posthog.Dashboard", + on_delete=models.SET_NULL, + null=True, + related_name="primary_dashboard_teams", + blank=True, ) # Dashboard shown on project homepage # Generic field for storing any team-specific context that is more temporary in nature and thus @@ -233,7 +257,10 @@ def person_on_events_mode(self) -> PersonOnEventsMode: if self._person_on_events_querying_enabled: # also tag person_on_events_enabled for legacy compatibility - tag_queries(person_on_events_enabled=True, person_on_events_mode=PersonOnEventsMode.V1_ENABLED) + tag_queries( + person_on_events_enabled=True, + person_on_events_mode=PersonOnEventsMode.V1_ENABLED, + ) return PersonOnEventsMode.V1_ENABLED return PersonOnEventsMode.DISABLED @@ -259,7 +286,10 @@ def _person_on_events_querying_enabled(self) -> bool: str(self.uuid), groups={"organization": str(self.organization_id)}, group_properties={ - "organization": {"id": str(self.organization_id), "created_at": self.organization.created_at} + "organization": { + "id": str(self.organization_id), + "created_at": self.organization.created_at, + } }, only_evaluate_locally=True, send_feature_flag_events=False, @@ -280,7 +310,10 @@ def _person_on_events_v2_querying_enabled(self) -> bool: str(self.uuid), groups={"organization": str(self.organization_id)}, group_properties={ - "organization": {"id": str(self.organization_id), "created_at": self.organization.created_at} + "organization": { + "id": str(self.organization_id), + "created_at": self.organization.created_at, + } }, only_evaluate_locally=True, send_feature_flag_events=False, diff --git a/posthog/models/team/util.py b/posthog/models/team/util.py index b2fa36b1430dd..ccaa249c559bf 100644 --- a/posthog/models/team/util.py +++ b/posthog/models/team/util.py @@ -49,6 +49,7 @@ def delete_batch_exports(team_ids: List[int]): can_enable_actor_on_events = False + # :TRICKY: Avoid overly eagerly checking whether the migration is complete. # We instead cache negative responses for a minute and a positive one forever. def actor_on_events_ready() -> bool: diff --git a/posthog/models/test/test_activity_logging.py b/posthog/models/test/test_activity_logging.py index ebe161d5e3986..e7f3ed4c13663 100644 --- a/posthog/models/test/test_activity_logging.py +++ b/posthog/models/test/test_activity_logging.py @@ -13,6 +13,33 @@ def test_dict_changes_between(self): self.assertEqual(len(changes), 3) - self.assertIn(Change(type="Plugin", action="changed", field="change_field", before="foo", after="bar"), changes) - self.assertIn(Change(type="Plugin", action="created", field="new_field", before=None, after="bar"), changes) - self.assertIn(Change(type="Plugin", action="deleted", field="delete_field", before="foo", after=None), changes) + self.assertIn( + Change( + type="Plugin", + action="changed", + field="change_field", + before="foo", + after="bar", + ), + changes, + ) + self.assertIn( + Change( + type="Plugin", + action="created", + field="new_field", + before=None, + after="bar", + ), + changes, + ) + self.assertIn( + Change( + type="Plugin", + action="deleted", + field="delete_field", + before="foo", + after=None, + ), + changes, + ) diff --git a/posthog/models/test/test_async_deletion_model.py b/posthog/models/test/test_async_deletion_model.py index c1f94dc825ed0..abb057fd6b9fa 100644 --- a/posthog/models/test/test_async_deletion_model.py +++ b/posthog/models/test/test_async_deletion_model.py @@ -35,7 +35,10 @@ def setUp(self): @snapshot_clickhouse_queries def test_mark_team_deletions_done(self): deletion = AsyncDeletion.objects.create( - deletion_type=DeletionType.Team, team_id=self.teams[0].pk, key=str(self.teams[0].pk), created_by=self.user + deletion_type=DeletionType.Team, + team_id=self.teams[0].pk, + key=str(self.teams[0].pk), + created_by=self.user, ) AsyncEventDeletion().mark_deletions_done() @@ -48,7 +51,10 @@ def test_mark_deletions_done_team_when_not_done(self): _create_event(event_uuid=uuid4(), event="event1", team=self.teams[0], distinct_id="1") deletion = AsyncDeletion.objects.create( - deletion_type=DeletionType.Team, team_id=self.teams[0].pk, key=str(self.teams[0].pk), created_by=self.user + deletion_type=DeletionType.Team, + team_id=self.teams[0].pk, + key=str(self.teams[0].pk), + created_by=self.user, ) AsyncEventDeletion().mark_deletions_done() @@ -58,11 +64,26 @@ def test_mark_deletions_done_team_when_not_done(self): @snapshot_clickhouse_queries def test_mark_deletions_done_person(self): - _create_event(event_uuid=uuid4(), event="event1", team=self.teams[0], distinct_id="1", person_id=uuid2) - _create_event(event_uuid=uuid4(), event="event1", team=self.teams[1], distinct_id="1", person_id=uuid) + _create_event( + event_uuid=uuid4(), + event="event1", + team=self.teams[0], + distinct_id="1", + person_id=uuid2, + ) + _create_event( + event_uuid=uuid4(), + event="event1", + team=self.teams[1], + distinct_id="1", + person_id=uuid, + ) deletion = AsyncDeletion.objects.create( - deletion_type=DeletionType.Person, team_id=self.teams[0].pk, key=str(uuid), created_by=self.user + deletion_type=DeletionType.Person, + team_id=self.teams[0].pk, + key=str(uuid), + created_by=self.user, ) AsyncEventDeletion().mark_deletions_done() @@ -72,10 +93,19 @@ def test_mark_deletions_done_person(self): @snapshot_clickhouse_queries def test_mark_deletions_done_person_when_not_done(self): - _create_event(event_uuid=uuid4(), event="event1", team=self.teams[0], distinct_id="1", person_id=uuid) + _create_event( + event_uuid=uuid4(), + event="event1", + team=self.teams[0], + distinct_id="1", + person_id=uuid, + ) deletion = AsyncDeletion.objects.create( - deletion_type=DeletionType.Person, team_id=self.teams[0].pk, key=str(uuid), created_by=self.user + deletion_type=DeletionType.Person, + team_id=self.teams[0].pk, + key=str(uuid), + created_by=self.user, ) AsyncEventDeletion().mark_deletions_done() @@ -86,13 +116,25 @@ def test_mark_deletions_done_person_when_not_done(self): @snapshot_clickhouse_queries def test_mark_deletions_done_groups(self): _create_event( - event_uuid=uuid4(), event="event1", team=self.teams[0], distinct_id="1", properties={"$group_1": "foo"} + event_uuid=uuid4(), + event="event1", + team=self.teams[0], + distinct_id="1", + properties={"$group_1": "foo"}, ) _create_event( - event_uuid=uuid4(), event="event1", team=self.teams[0], distinct_id="1", properties={"$group_0": "bar"} + event_uuid=uuid4(), + event="event1", + team=self.teams[0], + distinct_id="1", + properties={"$group_0": "bar"}, ) _create_event( - event_uuid=uuid4(), event="event1", team=self.teams[1], distinct_id="1", properties={"$group_0": "foo"} + event_uuid=uuid4(), + event="event1", + team=self.teams[1], + distinct_id="1", + properties={"$group_0": "foo"}, ) deletion = AsyncDeletion.objects.create( @@ -111,7 +153,11 @@ def test_mark_deletions_done_groups(self): @snapshot_clickhouse_queries def test_mark_deletions_done_groups_when_not_done(self): _create_event( - event_uuid=uuid4(), event="event1", team=self.teams[0], distinct_id="1", properties={"$group_0": "foo"} + event_uuid=uuid4(), + event="event1", + team=self.teams[0], + distinct_id="1", + properties={"$group_0": "foo"}, ) deletion = AsyncDeletion.objects.create( @@ -132,7 +178,10 @@ def test_delete_teams(self): _create_event(event_uuid=uuid4(), event="event1", team=self.teams[0], distinct_id="1") AsyncDeletion.objects.create( - deletion_type=DeletionType.Team, team_id=self.teams[0].pk, key=str(self.teams[0].pk), created_by=self.user + deletion_type=DeletionType.Team, + team_id=self.teams[0].pk, + key=str(self.teams[0].pk), + created_by=self.user, ) AsyncEventDeletion().run() @@ -144,7 +193,10 @@ def test_delete_teams_unrelated(self): _create_event(event_uuid=uuid4(), event="event1", team=self.teams[1], distinct_id="1") AsyncDeletion.objects.create( - deletion_type=DeletionType.Team, team_id=self.teams[0].pk, key=str(self.teams[0].pk), created_by=self.user + deletion_type=DeletionType.Team, + team_id=self.teams[0].pk, + key=str(self.teams[0].pk), + created_by=self.user, ) AsyncEventDeletion().run() @@ -153,10 +205,19 @@ def test_delete_teams_unrelated(self): @snapshot_clickhouse_alter_queries def test_delete_person(self): - _create_event(event_uuid=uuid4(), event="event1", team=self.teams[0], distinct_id="1", person_id=uuid) + _create_event( + event_uuid=uuid4(), + event="event1", + team=self.teams[0], + distinct_id="1", + person_id=uuid, + ) AsyncDeletion.objects.create( - deletion_type=DeletionType.Person, team_id=self.teams[0].pk, key=str(uuid), created_by=self.user + deletion_type=DeletionType.Person, + team_id=self.teams[0].pk, + key=str(uuid), + created_by=self.user, ) AsyncEventDeletion().run() @@ -165,11 +226,26 @@ def test_delete_person(self): @snapshot_clickhouse_alter_queries def test_delete_person_unrelated(self): - _create_event(event_uuid=uuid4(), event="event1", team=self.teams[0], distinct_id="1", person_id=uuid2) - _create_event(event_uuid=uuid4(), event="event1", team=self.teams[1], distinct_id="1", person_id=uuid) + _create_event( + event_uuid=uuid4(), + event="event1", + team=self.teams[0], + distinct_id="1", + person_id=uuid2, + ) + _create_event( + event_uuid=uuid4(), + event="event1", + team=self.teams[1], + distinct_id="1", + person_id=uuid, + ) AsyncDeletion.objects.create( - deletion_type=DeletionType.Person, team_id=self.teams[0].pk, key=str(uuid), created_by=self.user + deletion_type=DeletionType.Person, + team_id=self.teams[0].pk, + key=str(uuid), + created_by=self.user, ) AsyncEventDeletion().run() @@ -179,7 +255,11 @@ def test_delete_person_unrelated(self): @snapshot_clickhouse_alter_queries def test_delete_group(self): _create_event( - event_uuid=uuid4(), event="event1", team=self.teams[0], distinct_id="1", properties={"$group_0": "foo"} + event_uuid=uuid4(), + event="event1", + team=self.teams[0], + distinct_id="1", + properties={"$group_0": "foo"}, ) AsyncDeletion.objects.create( @@ -197,13 +277,25 @@ def test_delete_group(self): @snapshot_clickhouse_alter_queries def test_delete_group_unrelated(self): _create_event( - event_uuid=uuid4(), event="event1", team=self.teams[0], distinct_id="1", properties={"$group_1": "foo"} + event_uuid=uuid4(), + event="event1", + team=self.teams[0], + distinct_id="1", + properties={"$group_1": "foo"}, ) _create_event( - event_uuid=uuid4(), event="event1", team=self.teams[0], distinct_id="1", properties={"$group_0": "bar"} + event_uuid=uuid4(), + event="event1", + team=self.teams[0], + distinct_id="1", + properties={"$group_0": "bar"}, ) _create_event( - event_uuid=uuid4(), event="event1", team=self.teams[1], distinct_id="1", properties={"$group_0": "foo"} + event_uuid=uuid4(), + event="event1", + team=self.teams[1], + distinct_id="1", + properties={"$group_0": "foo"}, ) AsyncDeletion.objects.create( @@ -222,7 +314,12 @@ def test_delete_group_unrelated(self): def test_delete_auxilary_models_via_team(self): create_person(team_id=self.teams[0].pk, properties={"x": 0}, version=0, uuid=uuid) create_person_distinct_id(self.teams[0].pk, "0", uuid) - create_group(team_id=self.teams[0].pk, group_type_index=0, group_key="org:5", properties={}) + create_group( + team_id=self.teams[0].pk, + group_type_index=0, + group_key="org:5", + properties={}, + ) insert_static_cohort([uuid4()], 0, self.teams[0]) self._insert_cohortpeople_row(self.teams[0], uuid4(), 3) create_plugin_log_entry( @@ -236,7 +333,10 @@ def test_delete_auxilary_models_via_team(self): ) AsyncDeletion.objects.create( - deletion_type=DeletionType.Team, team_id=self.teams[0].pk, key=str(self.teams[0].pk), created_by=self.user + deletion_type=DeletionType.Team, + team_id=self.teams[0].pk, + key=str(self.teams[0].pk), + created_by=self.user, ) AsyncEventDeletion().run() @@ -252,7 +352,12 @@ def test_delete_auxilary_models_via_team(self): def test_delete_auxilary_models_via_team_unrelated(self): create_person(team_id=self.teams[1].pk, properties={"x": 0}, version=0, uuid=uuid) create_person_distinct_id(self.teams[1].pk, "0", uuid) - create_group(team_id=self.teams[1].pk, group_type_index=0, group_key="org:5", properties={}) + create_group( + team_id=self.teams[1].pk, + group_type_index=0, + group_key="org:5", + properties={}, + ) insert_static_cohort([uuid4()], 0, self.teams[1]) self._insert_cohortpeople_row(self.teams[1], uuid4(), 3) create_plugin_log_entry( @@ -266,7 +371,10 @@ def test_delete_auxilary_models_via_team_unrelated(self): ) AsyncDeletion.objects.create( - deletion_type=DeletionType.Team, team_id=self.teams[0].pk, key=str(self.teams[0].pk), created_by=self.user + deletion_type=DeletionType.Team, + team_id=self.teams[0].pk, + key=str(self.teams[0].pk), + created_by=self.user, ) AsyncEventDeletion().run() @@ -284,7 +392,10 @@ def test_delete_cohortpeople(self): self._insert_cohortpeople_row(team, uuid4(), cohort_id) AsyncDeletion.objects.create( - deletion_type=DeletionType.Cohort_full, team_id=team.pk, key=str(cohort_id) + "_0", created_by=self.user + deletion_type=DeletionType.Cohort_full, + team_id=team.pk, + key=str(cohort_id) + "_0", + created_by=self.user, ) AsyncCohortDeletion().run() @@ -298,7 +409,10 @@ def test_delete_cohortpeople_version(self): self._insert_cohortpeople_row(team, uuid4(), cohort_id, 3) AsyncDeletion.objects.create( - deletion_type=DeletionType.Cohort_stale, team_id=team.pk, key=str(cohort_id) + "_3", created_by=self.user + deletion_type=DeletionType.Cohort_stale, + team_id=team.pk, + key=str(cohort_id) + "_3", + created_by=self.user, ) AsyncCohortDeletion().run() @@ -314,5 +428,10 @@ def _insert_cohortpeople_row(self, team: Team, person_id: UUID, cohort_id: int, INSERT INTO cohortpeople (person_id, cohort_id, team_id, sign, version) VALUES (%(person_id)s, %(cohort_id)s, %(team_id)s, 1, %(version)s) """, - {"person_id": str(person_id), "cohort_id": cohort_id, "team_id": team.pk, "version": version}, + { + "person_id": str(person_id), + "cohort_id": cohort_id, + "team_id": team.pk, + "version": version, + }, ) diff --git a/posthog/models/test/test_dashboard_tile_model.py b/posthog/models/test/test_dashboard_tile_model.py index fe88e813c1181..be13ba06975c3 100644 --- a/posthog/models/test/test_dashboard_tile_model.py +++ b/posthog/models/test/test_dashboard_tile_model.py @@ -5,7 +5,11 @@ from django.db.utils import IntegrityError from posthog.models.dashboard import Dashboard -from posthog.models.dashboard_tile import DashboardTile, Text, get_tiles_ordered_by_position +from posthog.models.dashboard_tile import ( + DashboardTile, + Text, + get_tiles_ordered_by_position, +) from posthog.models.exported_asset import ExportedAsset from posthog.models.insight import Insight from posthog.test.base import APIBaseTest @@ -60,7 +64,6 @@ def test_cannot_add_a_tile_with_insight_and_text_on_validation(self) -> None: DashboardTile.objects.create(dashboard=self.dashboard, insight=insight, text=text) def test_cannot_set_caching_data_for_text_tiles(self) -> None: - tile_fields: List[Dict] = [ {"filters_hash": "123"}, {"refreshing": True}, diff --git a/posthog/models/test/test_entity_model.py b/posthog/models/test/test_entity_model.py index 55d0de18fc01a..c11e5bd99e9fd 100644 --- a/posthog/models/test/test_entity_model.py +++ b/posthog/models/test/test_entity_model.py @@ -1,6 +1,10 @@ from django.test import TestCase -from posthog.models.entity import TREND_FILTER_TYPE_ACTIONS, TREND_FILTER_TYPE_EVENTS, Entity +from posthog.models.entity import ( + TREND_FILTER_TYPE_ACTIONS, + TREND_FILTER_TYPE_EVENTS, + Entity, +) class TestEntity(TestCase): @@ -16,7 +20,11 @@ def test_inclusion(self): "type": TREND_FILTER_TYPE_EVENTS, "properties": [ {"key": "email", "value": "test@posthog.com", "type": "person"}, - {"key": "current_url", "value": "test@posthog.com", "type": "element"}, + { + "key": "current_url", + "value": "test@posthog.com", + "type": "element", + }, ], } ) @@ -24,7 +32,13 @@ def test_inclusion(self): { "id": "e1", "type": TREND_FILTER_TYPE_EVENTS, - "properties": [{"key": "current_url", "value": "test@posthog.com", "type": "element"}], + "properties": [ + { + "key": "current_url", + "value": "test@posthog.com", + "type": "element", + } + ], } ) @@ -38,7 +52,11 @@ def test_inclusion_unordered(self): "type": TREND_FILTER_TYPE_EVENTS, "properties": [ {"key": "browser", "value": "chrome", "type": "person"}, - {"key": "current_url", "value": "test@posthog.com", "type": "element"}, + { + "key": "current_url", + "value": "test@posthog.com", + "type": "element", + }, {"key": "email", "value": "test@posthog.com", "type": "person"}, ], } @@ -47,7 +65,13 @@ def test_inclusion_unordered(self): { "id": "e1", "type": TREND_FILTER_TYPE_EVENTS, - "properties": [{"key": "current_url", "value": "test@posthog.com", "type": "element"}], + "properties": [ + { + "key": "current_url", + "value": "test@posthog.com", + "type": "element", + } + ], } ) @@ -55,7 +79,6 @@ def test_inclusion_unordered(self): self.assertFalse(entity1.is_superset(entity2)) def test_equality_with_ids(self): - entity1 = Entity({"id": "e1", "type": TREND_FILTER_TYPE_ACTIONS}) entity2 = Entity({"id": "e1", "type": TREND_FILTER_TYPE_ACTIONS}) @@ -83,7 +106,11 @@ def test_equality_with_simple_properties(self): "type": TREND_FILTER_TYPE_EVENTS, "properties": [ {"key": "email", "value": "test@posthog.com", "type": "person"}, - {"key": "current_url", "value": "test@posthog.com", "type": "element"}, + { + "key": "current_url", + "value": "test@posthog.com", + "type": "element", + }, ], } ) @@ -92,7 +119,11 @@ def test_equality_with_simple_properties(self): "id": "e1", "type": TREND_FILTER_TYPE_EVENTS, "properties": [ - {"key": "current_url", "value": "test@posthog.com", "type": "element"}, + { + "key": "current_url", + "value": "test@posthog.com", + "type": "element", + }, {"key": "email", "value": "test@posthog.com", "type": "person"}, ], } @@ -105,7 +136,11 @@ def test_equality_with_simple_properties(self): "id": "e1", "type": TREND_FILTER_TYPE_EVENTS, "properties": [ - {"key": "current$url", "value": "test@posthog.com", "type": "element"}, + { + "key": "current$url", + "value": "test@posthog.com", + "type": "element", + }, {"key": "email", "value": "test@posthog.com", "type": "person"}, ], } @@ -120,8 +155,18 @@ def test_equality_with_complex_operator_properties(self): "type": TREND_FILTER_TYPE_EVENTS, "properties": [ {"key": "count", "operator": "lt", "value": 12, "type": "element"}, - {"key": "email", "operator": "in", "value": ["a, b"], "type": "person"}, - {"key": "selector", "value": [".btn"], "operator": "exact", "type": "element"}, + { + "key": "email", + "operator": "in", + "value": ["a, b"], + "type": "person", + }, + { + "key": "selector", + "value": [".btn"], + "operator": "exact", + "type": "element", + }, {"key": "test_prop", "value": 1.2, "operator": "gt"}, ], } @@ -133,8 +178,18 @@ def test_equality_with_complex_operator_properties(self): "properties": [ {"key": "test_prop", "value": 1.20, "operator": "gt"}, {"key": "count", "operator": "lt", "value": 12, "type": "element"}, - {"key": "selector", "value": [".btn"], "operator": "exact", "type": "element"}, - {"key": "email", "operator": "in", "value": ["a, b"], "type": "person"}, + { + "key": "selector", + "value": [".btn"], + "operator": "exact", + "type": "element", + }, + { + "key": "email", + "operator": "in", + "value": ["a, b"], + "type": "person", + }, ], } ) @@ -149,8 +204,18 @@ def test_equality_with_complex_operator_properties(self): "properties": [ {"key": "test_prop", "value": 1.200, "operator": "gt"}, {"key": "count", "operator": "lt", "value": 12, "type": "element"}, - {"key": "selector", "value": [".btn"], "operator": "exact", "type": "element"}, - {"key": "email", "operator": "in", "value": ["a, b"], "type": "person"}, + { + "key": "selector", + "value": [".btn"], + "operator": "exact", + "type": "element", + }, + { + "key": "email", + "operator": "in", + "value": ["a, b"], + "type": "person", + }, ], } ) @@ -164,8 +229,18 @@ def test_equality_with_complex_operator_properties(self): "properties": [ {"key": "test_prop", "value": 1.2001, "operator": "gt"}, {"key": "count", "operator": "lt", "value": 12, "type": "element"}, - {"key": "selector", "value": [".btn"], "operator": "exact", "type": "element"}, - {"key": "email", "operator": "in", "value": ["a, b"], "type": "person"}, + { + "key": "selector", + "value": [".btn"], + "operator": "exact", + "type": "element", + }, + { + "key": "email", + "operator": "in", + "value": ["a, b"], + "type": "person", + }, ], } ) @@ -173,9 +248,19 @@ def test_equality_with_complex_operator_properties(self): self.assertFalse(entity1.equals(entity2)) def test_equality_with_old_style_and_new_style_properties(self): - entity1 = Entity({"id": "e1", "type": TREND_FILTER_TYPE_EVENTS, "properties": {"key": "value"}}) + entity1 = Entity( + { + "id": "e1", + "type": TREND_FILTER_TYPE_EVENTS, + "properties": {"key": "value"}, + } + ) entity2 = Entity( - {"id": "e1", "type": TREND_FILTER_TYPE_EVENTS, "properties": [{"key": "key", "value": "value"}]} + { + "id": "e1", + "type": TREND_FILTER_TYPE_EVENTS, + "properties": [{"key": "key", "value": "value"}], + } ) self.assertTrue(entity1.equals(entity2)) diff --git a/posthog/models/test/test_event_model.py b/posthog/models/test/test_event_model.py index d5343e9141949..8c0f2ab8994b3 100644 --- a/posthog/models/test/test_event_model.py +++ b/posthog/models/test/test_event_model.py @@ -20,7 +20,10 @@ def test_filter_with_selector_direct_decendant_ordering(self): self.team, [ {"event": "$autocapture", "selector": "div > div > a"}, - {"event": "$autocapture", "selector": "div > a.somethingthatdoesntexist"}, + { + "event": "$autocapture", + "selector": "div > a.somethingthatdoesntexist", + }, ], ) @@ -28,7 +31,10 @@ def test_filter_with_selector_direct_decendant_ordering(self): def test_filter_with_selector_nth_child(self): all_events = self._setup_action_selector_events() - action = _create_action(self.team, [{"event": "$autocapture", "selector": "div > a:nth-child(2)"}]) + action = _create_action( + self.team, + [{"event": "$autocapture", "selector": "div > a:nth-child(2)"}], + ) self.assertActionEventsMatch(action, [all_events[1]]) @@ -58,7 +64,13 @@ def _setup_action_selector_events(self): team=self.team, distinct_id="whatever", elements=[ - Element(tag_name="a", href="/a-url", nth_child=1, nth_of_type=0, attr_class=["one-class"]), + Element( + tag_name="a", + href="/a-url", + nth_child=1, + nth_of_type=0, + attr_class=["one-class"], + ), Element(tag_name="button", nth_child=0, nth_of_type=0), Element(tag_name="div", nth_child=0, nth_of_type=0), Element(tag_name="div", nth_child=0, nth_of_type=0, attr_id="nested"), @@ -126,14 +138,30 @@ def test_with_normal_filters(self): team=self.team, event="$autocapture", distinct_id="whatever", - elements=[Element(tag_name="a", href="/a-url", text="some_text", nth_child=0, nth_of_type=0)], + elements=[ + Element( + tag_name="a", + href="/a-url", + text="some_text", + nth_child=0, + nth_of_type=0, + ) + ], ) event2_uuid = _create_event( team=self.team, event="$autocapture", distinct_id="whatever2", - elements=[Element(tag_name="a", href="/a-url", text="some_text", nth_child=0, nth_of_type=0)], + elements=[ + Element( + tag_name="a", + href="/a-url", + text="some_text", + nth_child=0, + nth_of_type=0, + ) + ], ) event3_uuid = _create_event( @@ -141,9 +169,20 @@ def test_with_normal_filters(self): event="$autocapture", distinct_id="whatever", elements=[ - Element(tag_name="a", href="/a-url-2", text="some_other_text", nth_child=0, nth_of_type=0), + Element( + tag_name="a", + href="/a-url-2", + text="some_other_text", + nth_child=0, + nth_of_type=0, + ), # make sure elements don't get double counted if they're part of the same event - Element(tag_name="div", text="some_other_text", nth_child=0, nth_of_type=0), + Element( + tag_name="div", + text="some_other_text", + nth_child=0, + nth_of_type=0, + ), ], ) @@ -152,9 +191,20 @@ def test_with_normal_filters(self): event="$autocapture", distinct_id="whatever2", elements=[ - Element(tag_name="a", href="/a-url-2", text="some_other_text", nth_child=0, nth_of_type=0), + Element( + tag_name="a", + href="/a-url-2", + text="some_other_text", + nth_child=0, + nth_of_type=0, + ), # make sure elements don't get double counted if they're part of the same event - Element(tag_name="div", text="some_other_text", nth_child=0, nth_of_type=0), + Element( + tag_name="div", + text="some_other_text", + nth_child=0, + nth_of_type=0, + ), ], ) @@ -163,13 +213,29 @@ def test_with_normal_filters(self): team=team2, event="$autocapture", distinct_id="whatever2", - elements=[Element(tag_name="a", href="/a-url", text="some_other_text", nth_child=0, nth_of_type=0)], + elements=[ + Element( + tag_name="a", + href="/a-url", + text="some_other_text", + nth_child=0, + nth_of_type=0, + ) + ], ) _create_event( team=team2, event="$autocapture", distinct_id="whatever2", - elements=[Element(tag_name="a", href="/a-url-2", text="some_other_text", nth_child=0, nth_of_type=0)], + elements=[ + Element( + tag_name="a", + href="/a-url-2", + text="some_other_text", + nth_child=0, + nth_of_type=0, + ) + ], ) events = _get_events_for_action(action1) @@ -184,14 +250,26 @@ def test_with_href_contains(self): action1 = Action.objects.create(team=self.team) ActionStep.objects.create( - event="$autocapture", action=action1, href="/a-url", href_matching="contains", selector="a" + event="$autocapture", + action=action1, + href="/a-url", + href_matching="contains", + selector="a", ) event1_uuid = _create_event( team=self.team, event="$autocapture", distinct_id="whatever", - elements=[Element(tag_name="a", href="/a-url", text="some_text", nth_child=0, nth_of_type=0)], + elements=[ + Element( + tag_name="a", + href="/a-url", + text="some_text", + nth_child=0, + nth_of_type=0, + ) + ], ) event2_uuid = _create_event( @@ -199,7 +277,13 @@ def test_with_href_contains(self): event="$autocapture", distinct_id="whatever2", elements=[ - Element(tag_name="a", href="https://google.com/a-url", text="some_text", nth_child=0, nth_of_type=0) + Element( + tag_name="a", + href="https://google.com/a-url", + text="some_text", + nth_child=0, + nth_of_type=0, + ) ], ) @@ -208,9 +292,20 @@ def test_with_href_contains(self): event="$autocapture", distinct_id="whatever", elements=[ - Element(tag_name="a", href="/a-url-2", text="some_other_text", nth_child=0, nth_of_type=0), + Element( + tag_name="a", + href="/a-url-2", + text="some_other_text", + nth_child=0, + nth_of_type=0, + ), # make sure elements don't get double counted if they're part of the same event - Element(tag_name="div", text="some_other_text", nth_child=0, nth_of_type=0), + Element( + tag_name="div", + text="some_other_text", + nth_child=0, + nth_of_type=0, + ), ], ) @@ -219,9 +314,20 @@ def test_with_href_contains(self): event="$autocapture", distinct_id="whatever2", elements=[ - Element(tag_name="a", href="/b-url", text="some_other_text", nth_child=0, nth_of_type=0), + Element( + tag_name="a", + href="/b-url", + text="some_other_text", + nth_child=0, + nth_of_type=0, + ), # make sure elements don't get double counted if they're part of the same event - Element(tag_name="div", text="some_other_text", nth_child=0, nth_of_type=0), + Element( + tag_name="div", + text="some_other_text", + nth_child=0, + nth_of_type=0, + ), ], ) @@ -234,7 +340,12 @@ def test_with_href_contains(self): def test_with_class(self): _create_person(distinct_ids=["whatever"], team=self.team) action1 = Action.objects.create(team=self.team) - ActionStep.objects.create(event="$autocapture", action=action1, selector="a.nav-link.active", tag_name="a") + ActionStep.objects.create( + event="$autocapture", + action=action1, + selector="a.nav-link.active", + tag_name="a", + ) event1_uuid = _create_event( event="$autocapture", team=self.team, @@ -250,7 +361,10 @@ def test_with_class(self): event="$autocapture", team=self.team, distinct_id="whatever", - elements=[Element(tag_name="span", attr_class=None), Element(tag_name="a", attr_class=None)], + elements=[ + Element(tag_name="span", attr_class=None), + Element(tag_name="a", attr_class=None), + ], ) events = _get_events_for_action(action1) @@ -260,7 +374,12 @@ def test_with_class(self): def test_with_class_with_escaped_symbols(self): _create_person(distinct_ids=["whatever"], team=self.team) action1 = Action.objects.create(team=self.team) - ActionStep.objects.create(event="$autocapture", action=action1, selector="a.na\\v-link:b@ld", tag_name="a") + ActionStep.objects.create( + event="$autocapture", + action=action1, + selector="a.na\\v-link:b@ld", + tag_name="a", + ) event1_uuid = _create_event( event="$autocapture", team=self.team, @@ -279,7 +398,10 @@ def test_with_class_with_escaped_slashes(self): _create_person(distinct_ids=["whatever"], team=self.team) action1 = Action.objects.create(team=self.team) ActionStep.objects.create( - event="$autocapture", action=action1, selector="a.na\\\\\\v-link:b@ld", tag_name="a" + event="$autocapture", + action=action1, + selector="a.na\\\\\\v-link:b@ld", + tag_name="a", ) event1_uuid = _create_event( event="$autocapture", @@ -323,15 +445,28 @@ def test_filter_events_by_url(self): ActionStep.objects.create(event="$autocapture", action=action1, href="/a-url-2") action2 = Action.objects.create(team=self.team) - ActionStep.objects.create(event="$autocapture", action=action2, url="123", url_matching=ActionStep.CONTAINS) + ActionStep.objects.create( + event="$autocapture", + action=action2, + url="123", + url_matching=ActionStep.CONTAINS, + ) action3 = Action.objects.create(team=self.team) ActionStep.objects.create( - event="$autocapture", action=action3, url="https://posthog.com/%/123", url_matching=ActionStep.CONTAINS + event="$autocapture", + action=action3, + url="https://posthog.com/%/123", + url_matching=ActionStep.CONTAINS, ) action4 = Action.objects.create(team=self.team) - ActionStep.objects.create(event="$autocapture", action=action4, url="/123$", url_matching=ActionStep.REGEX) + ActionStep.objects.create( + event="$autocapture", + action=action4, + url="/123$", + url_matching=ActionStep.REGEX, + ) _create_event(team=self.team, distinct_id="whatever", event="$autocapture") event2_uuid = _create_event( @@ -339,7 +474,14 @@ def test_filter_events_by_url(self): team=self.team, distinct_id="whatever", properties={"$current_url": "https://posthog.com/feedback/123"}, - elements=[Element(tag_name="div", text="some_other_text", nth_child=0, nth_of_type=0)], + elements=[ + Element( + tag_name="div", + text="some_other_text", + nth_child=0, + nth_of_type=0, + ) + ], ) events = _get_events_for_action(action1) @@ -360,7 +502,12 @@ def test_filter_events_by_url(self): def test_person_with_different_distinct_id(self): action_watch_movie = Action.objects.create(team=self.team, name="watched movie") - ActionStep.objects.create(action=action_watch_movie, tag_name="a", href="/movie", event="$autocapture") + ActionStep.objects.create( + action=action_watch_movie, + tag_name="a", + href="/movie", + event="$autocapture", + ) _create_person(distinct_ids=["anonymous_user", "is_now_signed_up"], team=self.team) _create_event( @@ -396,13 +543,19 @@ def test_no_person_leakage_from_other_teams(self): self.assertEqual(events[0].distinct_id, "anonymous_user") def test_person_property(self): - _create_person(team=self.team, distinct_ids=["person1"], properties={"$browser": "Chrome"}) + _create_person( + team=self.team, + distinct_ids=["person1"], + properties={"$browser": "Chrome"}, + ) _create_person(team=self.team, distinct_ids=["person2"]) _create_event(event="$pageview", distinct_id="person1", team=self.team) _create_event(event="$pageview", distinct_id="person2", team=self.team) action = Action.objects.create(name="pageview", team=self.team) ActionStep.objects.create( - action=action, event="$pageview", properties=[{"key": "$browser", "value": "Chrome", "type": "person"}] + action=action, + event="$pageview", + properties=[{"key": "$browser", "value": "Chrome", "type": "person"}], ) events = _get_events_for_action(action) self.assertEqual(len(events), 1) @@ -482,7 +635,10 @@ def test_selector_attribute(self): self.assertEqual(selector1.parts[0].direct_descendant, False) self.assertEqual(selector1.parts[0].unique_order, 0) - self.assertEqual(selector1.parts[1].data, {"tag_name": "div", "attributes__attr__data-id": "5"}) + self.assertEqual( + selector1.parts[1].data, + {"tag_name": "div", "attributes__attr__data-id": "5"}, + ) self.assertEqual(selector1.parts[1].direct_descendant, True) self.assertEqual(selector1.parts[1].unique_order, 0) @@ -518,7 +674,10 @@ def test_class(self): self.assertEqual(selector1.parts[0].direct_descendant, False) self.assertEqual(selector1.parts[0].unique_order, 0) - self.assertEqual(selector1.parts[1].data, {"tag_name": "div", "attr_class__contains": ["classone", "classtwo"]}) + self.assertEqual( + selector1.parts[1].data, + {"tag_name": "div", "attr_class__contains": ["classone", "classtwo"]}, + ) self.assertEqual(selector1.parts[1].direct_descendant, True) self.assertEqual(selector1.parts[1].unique_order, 0) diff --git a/posthog/models/test/test_exported_asset_model.py b/posthog/models/test/test_exported_asset_model.py index 40337c6c50635..f17808caadd54 100644 --- a/posthog/models/test/test_exported_asset_model.py +++ b/posthog/models/test/test_exported_asset_model.py @@ -68,7 +68,10 @@ def test_delete_expired_assets(self) -> None: ExportedAsset.delete_expired_assets() - assert list(ExportedAsset.objects.all()) == [asset_that_is_not_expired, asset_that_has_no_expiry] + assert list(ExportedAsset.objects.all()) == [ + asset_that_is_not_expired, + asset_that_has_no_expiry, + ] assert list(ExportedAsset.objects_including_ttl_deleted.all()) == [ asset_that_is_not_expired, asset_that_has_no_expiry, diff --git a/posthog/models/test/test_insight_caching_state.py b/posthog/models/test/test_insight_caching_state.py index 65b4086f9443f..2727d67f582f6 100644 --- a/posthog/models/test/test_insight_caching_state.py +++ b/posthog/models/test/test_insight_caching_state.py @@ -2,7 +2,13 @@ from django.utils.timezone import now -from posthog.models import Dashboard, DashboardTile, Insight, InsightCachingState, SharingConfiguration +from posthog.models import ( + Dashboard, + DashboardTile, + Insight, + InsightCachingState, + SharingConfiguration, +) from posthog.models.signals import mute_selected_signals from posthog.test.base import BaseTest diff --git a/posthog/models/test/test_insight_model.py b/posthog/models/test/test_insight_model.py index 08d82d0a416ac..2519b8a79cb0a 100644 --- a/posthog/models/test/test_insight_model.py +++ b/posthog/models/test/test_insight_model.py @@ -102,7 +102,8 @@ def test_dashboard_with_date_from_changes_filters_hash(self) -> None: def test_query_hash_matches_same_query_source(self) -> None: insight_with_query_at_top_level = Insight.objects.create(team=self.team, query={"kind": "EventsQuery"}) insight_with_query_in_source = Insight.objects.create( - team=self.team, query={"kind": "DataTable", "source": {"kind": "EventsQuery"}} + team=self.team, + query={"kind": "DataTable", "source": {"kind": "EventsQuery"}}, ) filters_hash_one = generate_insight_cache_key(insight_with_query_at_top_level, None) @@ -141,25 +142,37 @@ def test_dashboard_with_query_insight_and_filters(self) -> None: # test that query filters are equal when there are no dashboard filters {"dateRange": {"date_from": "-14d", "date_to": "-7d"}}, {}, - {"dateRange": {"date_from": "-14d", "date_to": "-7d"}, "properties": None}, + { + "dateRange": {"date_from": "-14d", "date_to": "-7d"}, + "properties": None, + }, ), ( # test that dashboard filters are used when there are no query filters {}, {"date_from": "-14d", "date_to": "-7d"}, - {"dateRange": {"date_from": "-14d", "date_to": "-7d"}, "properties": None}, + { + "dateRange": {"date_from": "-14d", "date_to": "-7d"}, + "properties": None, + }, ), ( # test that dashboard filters take priority {"dateRange": {"date_from": "-2d", "date_to": "-1d"}}, {"date_from": "-4d", "date_to": "-3d"}, - {"dateRange": {"date_from": "-4d", "date_to": "-3d"}, "properties": None}, + { + "dateRange": {"date_from": "-4d", "date_to": "-3d"}, + "properties": None, + }, ), ( # test that dashboard filters take priority, even if only one value is set, the other is set to None {"dateRange": {"date_from": "-14d", "date_to": "-7d"}}, {"date_from": "all"}, - {"dateRange": {"date_from": "all", "date_to": None}, "properties": None}, + { + "dateRange": {"date_from": "all", "date_to": None}, + "properties": None, + }, ), ( # test that if no filters are set then none are outputted @@ -171,13 +184,19 @@ def test_dashboard_with_query_insight_and_filters(self) -> None: # test that properties from the query are used when there are no dashboard properties {"properties": [browser_equals_firefox]}, {}, - {"dateRange": {"date_from": None, "date_to": None}, "properties": [browser_equals_firefox]}, + { + "dateRange": {"date_from": None, "date_to": None}, + "properties": [browser_equals_firefox], + }, ), ( # test that properties from the dashboard are used when there are no query properties {}, {"properties": [browser_equals_chrome]}, - {"dateRange": {"date_from": None, "date_to": None}, "properties": [browser_equals_chrome]}, + { + "dateRange": {"date_from": None, "date_to": None}, + "properties": [browser_equals_chrome], + }, ), ( # test that properties are merged when set in both query and dashboard diff --git a/posthog/models/test/test_organization_model.py b/posthog/models/test/test_organization_model.py index 0f9c29904e4ab..f140dcc862f26 100644 --- a/posthog/models/test/test_organization_model.py +++ b/posthog/models/test/test_organization_model.py @@ -29,16 +29,19 @@ def test_plugins_are_preinstalled_on_self_hosted(self, mock_get): with self.is_cloud(False): with self.settings(PLUGINS_PREINSTALLED_URLS=["https://github.com/PostHog/helloworldplugin/"]): new_org, _, _ = Organization.objects.bootstrap( - self.user, plugins_access_level=Organization.PluginsAccessLevel.INSTALL + self.user, + plugins_access_level=Organization.PluginsAccessLevel.INSTALL, ) self.assertEqual(Plugin.objects.filter(organization=new_org, is_preinstalled=True).count(), 1) self.assertEqual( - Plugin.objects.filter(organization=new_org, is_preinstalled=True).get().name, "helloworldplugin" + Plugin.objects.filter(organization=new_org, is_preinstalled=True).get().name, + "helloworldplugin", ) self.assertEqual(mock_get.call_count, 2) mock_get.assert_any_call( - f"https://github.com/PostHog/helloworldplugin/archive/{HELLO_WORLD_PLUGIN_GITHUB_ZIP[0]}.zip", headers={} + f"https://github.com/PostHog/helloworldplugin/archive/{HELLO_WORLD_PLUGIN_GITHUB_ZIP[0]}.zip", + headers={}, ) @mock.patch("requests.get", side_effect=mocked_plugin_requests_get) @@ -46,7 +49,8 @@ def test_plugins_are_not_preinstalled_on_cloud(self, mock_get): with self.is_cloud(True): with self.settings(PLUGINS_PREINSTALLED_URLS=["https://github.com/PostHog/helloworldplugin/"]): new_org, _, _ = Organization.objects.bootstrap( - self.user, plugins_access_level=Organization.PluginsAccessLevel.INSTALL + self.user, + plugins_access_level=Organization.PluginsAccessLevel.INSTALL, ) self.assertEqual(Plugin.objects.filter(organization=new_org, is_preinstalled=True).count(), 0) diff --git a/posthog/models/test/test_person_override_model.py b/posthog/models/test/test_person_override_model.py index e3365adaf524a..13f3b0a8511ab 100644 --- a/posthog/models/test/test_person_override_model.py +++ b/posthog/models/test/test_person_override_model.py @@ -416,7 +416,13 @@ def create_connection(alias=DEFAULT_DB_ALIAS): def _merge_people( - team, cursor, old_person_uuid, override_person_uuid, oldest_event, can_lock_event=None, done_event=None + team, + cursor, + old_person_uuid, + override_person_uuid, + oldest_event, + can_lock_event=None, + done_event=None, ): """ Merge two people together, using the override_person_id as the canonical @@ -592,7 +598,13 @@ def test_person_override_allow_consecutive_merges(people, team, oldest_event): with create_connection() as second_cursor: second_cursor.execute("BEGIN") - _merge_people(team, second_cursor, override_person.uuid, new_override_person.uuid, oldest_event) + _merge_people( + team, + second_cursor, + override_person.uuid, + new_override_person.uuid, + oldest_event, + ) second_cursor.execute("COMMIT") assert [_[0] for _ in PersonOverrideMapping.objects.all().values_list("uuid")] == [ @@ -648,12 +660,24 @@ def test_person_override_disallows_concurrent_merge(people, team, oldest_event): done_t2_event = Event() t1 = Thread( target=_merge_people, - args=(team, first_cursor, old_person.uuid, override_person.uuid, oldest_event), + args=( + team, + first_cursor, + old_person.uuid, + override_person.uuid, + oldest_event, + ), kwargs={"can_lock_event": can_lock_event, "done_event": done_t1_event}, ) t2 = Thread( target=_merge_people, - args=(team, second_cursor, override_person.uuid, new_override_person.uuid, oldest_event), + args=( + team, + second_cursor, + override_person.uuid, + new_override_person.uuid, + oldest_event, + ), kwargs={"done_event": done_t2_event}, ) t1.start() @@ -708,12 +732,24 @@ def test_person_override_disallows_concurrent_merge_different_order(people, team done_t2_event = Event() t1 = Thread( target=_merge_people, - args=(team, first_cursor, old_person.uuid, override_person.uuid, oldest_event), + args=( + team, + first_cursor, + old_person.uuid, + override_person.uuid, + oldest_event, + ), kwargs={"done_event": done_t1_event}, ) t2 = Thread( target=_merge_people, - args=(team, second_cursor, override_person.uuid, new_override_person.uuid, oldest_event), + args=( + team, + second_cursor, + override_person.uuid, + new_override_person.uuid, + oldest_event, + ), kwargs={"can_lock_event": can_lock_event, "done_event": done_t2_event}, ) t1.start() diff --git a/posthog/models/test/test_subscription_model.py b/posthog/models/test/test_subscription_model.py index bc9bf583e6f15..8552d8bca795a 100644 --- a/posthog/models/test/test_subscription_model.py +++ b/posthog/models/test/test_subscription_model.py @@ -80,7 +80,12 @@ def test_generating_token(self): token = get_unsubscribe_token(subscription, "test2@posthog.com") assert token.startswith("ey") - info = jwt.decode(token, "not-so-secret", audience=PosthogJwtAudience.UNSUBSCRIBE.value, algorithms=["HS256"]) + info = jwt.decode( + token, + "not-so-secret", + audience=PosthogJwtAudience.UNSUBSCRIBE.value, + algorithms=["HS256"], + ) assert info["id"] == subscription.id assert info["email"] == "test2@posthog.com" @@ -137,7 +142,10 @@ def test_unsubscribe_deletes_subscription_if_last_subscriber(self): def test_complex_rrule_configuration(self): # Equivalent to last monday and wednesday of every other month subscription = self._create_insight_subscription( - interval=2, frequency="monthly", bysetpos=-1, byweekday=["wednesday", "friday"] + interval=2, + frequency="monthly", + bysetpos=-1, + byweekday=["wednesday", "friday"], ) # Last wed or fri of 01.22 is Wed 28th @@ -156,7 +164,15 @@ def test_should_work_for_nth_days(self): interval=1, frequency="monthly", bysetpos=3, - byweekday=["monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday"], + byweekday=[ + "monday", + "tuesday", + "wednesday", + "thursday", + "friday", + "saturday", + "sunday", + ], ) subscription.save() assert subscription.next_delivery_date == datetime(2022, 1, 3, 0, 0).replace(tzinfo=ZoneInfo("UTC")) @@ -185,7 +201,15 @@ def test_subscription_summary(self): subscription = self._create_insight_subscription( interval=1, frequency="monthly", - byweekday=["monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday"], + byweekday=[ + "monday", + "tuesday", + "wednesday", + "thursday", + "friday", + "saturday", + "sunday", + ], bysetpos=3, ) assert subscription.summary == "sent every month on the third day" diff --git a/posthog/models/test/test_user_model.py b/posthog/models/test/test_user_model.py index 7b805157266f7..fe26931522eac 100644 --- a/posthog/models/test/test_user_model.py +++ b/posthog/models/test/test_user_model.py @@ -12,7 +12,10 @@ def test_create_user_with_distinct_id(self): def test_analytics_metadata(self): # One org, one team, anonymized organization, team, user = User.objects.bootstrap( - organization_name="Test Org", email="test_org@posthog.com", password="12345678", anonymize_data=True + organization_name="Test Org", + email="test_org@posthog.com", + password="12345678", + anonymize_data=True, ) with self.is_cloud(True): diff --git a/posthog/models/uploaded_media.py b/posthog/models/uploaded_media.py index 0a25f452495f1..0161b71beb4f6 100644 --- a/posthog/models/uploaded_media.py +++ b/posthog/models/uploaded_media.py @@ -35,11 +35,19 @@ def get_absolute_url(self) -> str: @classmethod def save_content( - cls, team: Team, created_by: User, file_name: str, content_type: str, content: bytes + cls, + team: Team, + created_by: User, + file_name: str, + content_type: str, + content: bytes, ) -> Optional["UploadedMedia"]: try: media = UploadedMedia.objects.create( - team=team, created_by=created_by, file_name=file_name, content_type=content_type + team=team, + created_by=created_by, + file_name=file_name, + content_type=content_type, ) if settings.OBJECT_STORAGE_ENABLED: save_content_to_object_storage(media, content) @@ -54,7 +62,11 @@ def save_content( except ObjectStorageError as ose: capture_exception(ose) logger.error( - "uploaded_media.object-storage-error", file_name=file_name, team=team.pk, exception=ose, exc_info=True + "uploaded_media.object-storage-error", + file_name=file_name, + team=team.pk, + exception=ose, + exc_info=True, ) return None diff --git a/posthog/models/user.py b/posthog/models/user.py index b385f4b0fc8ab..423936747e2cc 100644 --- a/posthog/models/user.py +++ b/posthog/models/user.py @@ -78,7 +78,11 @@ def bootstrap( organization_fields.setdefault("name", organization_name) organization = Organization.objects.create(**organization_fields) user = self.create_user( - email=email, password=password, first_name=first_name, is_staff=is_staff, **user_fields + email=email, + password=password, + first_name=first_name, + is_staff=is_staff, + **user_fields, ) if create_team: team = create_team(organization, user) @@ -129,7 +133,10 @@ class User(AbstractUser, UUIDClassicModel): TOOLBAR_CHOICES = [(DISABLED, DISABLED), (TOOLBAR, TOOLBAR)] current_organization = models.ForeignKey( - "posthog.Organization", models.SET_NULL, null=True, related_name="users_currently+" + "posthog.Organization", + models.SET_NULL, + null=True, + related_name="users_currently+", ) current_team = models.ForeignKey("posthog.Team", models.SET_NULL, null=True, related_name="teams_currently+") email = models.EmailField(_("email address"), unique=True) @@ -168,7 +175,8 @@ def teams(self): """ teams = Team.objects.filter(organization__members=self) if Organization.objects.filter( - members=self, available_features__contains=[AvailableFeature.PROJECT_BASED_PERMISSIONING] + members=self, + available_features__contains=[AvailableFeature.PROJECT_BASED_PERMISSIONING], ).exists(): try: from ee.models import ExplicitTeamMembership @@ -210,7 +218,10 @@ def team(self) -> Optional[Team]: return self.current_team def join( - self, *, organization: Organization, level: OrganizationMembership.Level = OrganizationMembership.Level.MEMBER + self, + *, + organization: Organization, + level: OrganizationMembership.Level = OrganizationMembership.Level.MEMBER, ) -> OrganizationMembership: with transaction.atomic(): membership = OrganizationMembership.objects.create(user=self, organization=organization, level=level) diff --git a/posthog/models/user_scene_personalisation.py b/posthog/models/user_scene_personalisation.py index cf4d3c6ed724f..8b745f67a6808 100644 --- a/posthog/models/user_scene_personalisation.py +++ b/posthog/models/user_scene_personalisation.py @@ -8,10 +8,17 @@ class UserScenePersonalisation(UUIDModel): dashboard: models.ForeignKey = models.ForeignKey("Dashboard", on_delete=models.CASCADE, null=True, blank=True) team: models.ForeignKey = models.ForeignKey("Team", on_delete=models.CASCADE, null=True, blank=True) user: models.ForeignKey = models.ForeignKey( - "User", on_delete=models.CASCADE, null=True, blank=True, related_name="scene_personalisation" + "User", + on_delete=models.CASCADE, + null=True, + blank=True, + related_name="scene_personalisation", ) class Meta: constraints = [ - models.UniqueConstraint(fields=["team", "user", "scene"], name="posthog_unique_scene_personalisation") + models.UniqueConstraint( + fields=["team", "user", "scene"], + name="posthog_unique_scene_personalisation", + ) ] diff --git a/posthog/models/utils.py b/posthog/models/utils.py index 0452084be4c4d..b00a87eb881c5 100644 --- a/posthog/models/utils.py +++ b/posthog/models/utils.py @@ -78,7 +78,7 @@ def get_series(cls, unix_time_ms: int) -> int: @classmethod def is_valid_uuid(cls, candidate: Any) -> bool: - if type(candidate) != str: + if not isinstance(candidate, str): return False hex = candidate.replace("urn:", "").replace("uuid:", "") hex = hex.strip("{}").replace("-", "") @@ -205,7 +205,9 @@ def create_with_slug(create_func: Callable[..., T], default_slug: str = "", *arg def get_deferred_field_set_for_model( - model: Type[models.Model], fields_not_deferred: Set[str] = set(), field_prefix: str = "" + model: Type[models.Model], + fields_not_deferred: Set[str] = set(), + field_prefix: str = "", ) -> Set[str]: """Return a set of field names to be deferred for a given model. Used with `.defer()` after `select_related` diff --git a/posthog/permissions.py b/posthog/permissions.py index 2a6339601cd9a..229a69a311b50 100644 --- a/posthog/permissions.py +++ b/posthog/permissions.py @@ -119,7 +119,6 @@ class OrganizationAdminWritePermissions(BasePermission): message = "Your organization access level is insufficient." def has_permission(self, request: Request, view) -> bool: - if request.method in SAFE_METHODS: return True @@ -136,7 +135,6 @@ def has_permission(self, request: Request, view) -> bool: ) def has_object_permission(self, request: Request, view, object: Model) -> bool: - if request.method in SAFE_METHODS: return True @@ -156,7 +154,7 @@ class TeamMemberAccessPermission(BasePermission): def has_permission(self, request, view) -> bool: try: - view.team + view.team # noqa: B018 except Team.DoesNotExist: return True # This will be handled as a 404 in the viewset requesting_level = view.user_permissions.current_team.effective_membership_level diff --git a/posthog/plugins/site.py b/posthog/plugins/site.py index 18b1dcbc947a4..9cb2b3023f80e 100644 --- a/posthog/plugins/site.py +++ b/posthog/plugins/site.py @@ -32,7 +32,13 @@ def get_transpiled_site_source(id: int, token: str) -> Optional[WebJsSource]: plugin__pluginsourcefile__filename="site.ts", plugin__pluginsourcefile__status=PluginSourceFile.Status.TRANSPILED, ) - .values_list("id", "plugin__pluginsourcefile__transpiled", "web_token", "plugin__config_schema", "config") + .values_list( + "id", + "plugin__pluginsourcefile__transpiled", + "web_token", + "plugin__config_schema", + "config", + ) .first() ) @@ -53,7 +59,13 @@ def get_decide_site_apps(team: "Team", using_database: str = "default") -> List[ plugin__pluginsourcefile__filename="site.ts", plugin__pluginsourcefile__status=PluginSourceFile.Status.TRANSPILED, ) - .values_list("id", "web_token", "plugin__pluginsourcefile__updated_at", "plugin__updated_at", "updated_at") + .values_list( + "id", + "web_token", + "plugin__pluginsourcefile__updated_at", + "plugin__updated_at", + "updated_at", + ) .all() ) diff --git a/posthog/plugins/test/mock.py b/posthog/plugins/test/mock.py index 91c2a473e7b42..04c61b17cf063 100644 --- a/posthog/plugins/test/mock.py +++ b/posthog/plugins/test/mock.py @@ -45,19 +45,34 @@ def ok(self): if args[0] == "https://api.github.com/repos/PostHog/posthog/commits?sha=&path=": return MockJSONResponse( - [{"sha": "MOCKLATESTCOMMIT", "html_url": "https://www.github.com/PostHog/posthog/commit/MOCKLATESTCOMMIT"}], + [ + { + "sha": "MOCKLATESTCOMMIT", + "html_url": "https://www.github.com/PostHog/posthog/commit/MOCKLATESTCOMMIT", + } + ], 200, ) if args[0] == "https://api.github.com/repos/PostHog/posthog/commits?sha=main&path=": return MockJSONResponse( - [{"sha": "MOCKLATESTCOMMIT", "html_url": "https://www.github.com/PostHog/posthog/commit/MOCKLATESTCOMMIT"}], + [ + { + "sha": "MOCKLATESTCOMMIT", + "html_url": "https://www.github.com/PostHog/posthog/commit/MOCKLATESTCOMMIT", + } + ], 200, ) if args[0] == "https://api.github.com/repos/PostHog/posthog/commits?sha=main&path=test/path/in/repo": return MockJSONResponse( - [{"sha": "MOCKLATESTCOMMIT", "html_url": "https://www.github.com/PostHog/posthog/commit/MOCKLATESTCOMMIT"}], + [ + { + "sha": "MOCKLATESTCOMMIT", + "html_url": "https://www.github.com/PostHog/posthog/commit/MOCKLATESTCOMMIT", + } + ], 200, ) diff --git a/posthog/plugins/test/test_utils.py b/posthog/plugins/test/test_utils.py index d597db91017c5..d2f971073d481 100644 --- a/posthog/plugins/test/test_utils.py +++ b/posthog/plugins/test/test_utils.py @@ -41,7 +41,10 @@ def test_parse_github_urls(self, mock_get): self.assertEqual(parsed_url["tag"], "MOCKLATESTCOMMIT") self.assertEqual(parsed_url.get("path", None), None) self.assertEqual(mock_get.call_count, 1) - mock_get.assert_called_with("https://api.github.com/repos/PostHog/posthog/commits?sha=&path=", headers={}) + mock_get.assert_called_with( + "https://api.github.com/repos/PostHog/posthog/commits?sha=&path=", + headers={}, + ) mock_get.reset_mock() parsed_url = parse_url("https://github.com/PostHog/posthog/tree/82c9218ee40f561b7f37a22d6b6a0ca82887ee3e") @@ -54,7 +57,8 @@ def test_parse_github_urls(self, mock_get): mock_get.reset_mock() parsed_url = parse_url( - "https://github.com/PostHog/posthog/tree/82c9218ee40f561b7f37a22d6b6a0ca82887ee3e", get_latest_if_none=True + "https://github.com/PostHog/posthog/tree/82c9218ee40f561b7f37a22d6b6a0ca82887ee3e", + get_latest_if_none=True, ) self.assertEqual(parsed_url["type"], "github") self.assertEqual(parsed_url["user"], "PostHog") @@ -83,11 +87,15 @@ def test_parse_github_urls(self, mock_get): self.assertEqual(parsed_url["tag"], "MOCKLATESTCOMMIT") self.assertEqual(parsed_url.get("path", None), None) self.assertEqual(mock_get.call_count, 1) - mock_get.assert_called_with("https://api.github.com/repos/PostHog/posthog/commits?sha=main&path=", headers={}) + mock_get.assert_called_with( + "https://api.github.com/repos/PostHog/posthog/commits?sha=main&path=", + headers={}, + ) mock_get.reset_mock() parsed_url = parse_url( - "https://github.com/PostHog/posthog/tree/main/test/path/in/repo", get_latest_if_none=True + "https://github.com/PostHog/posthog/tree/main/test/path/in/repo", + get_latest_if_none=True, ) self.assertEqual(parsed_url["type"], "github") self.assertEqual(parsed_url["user"], "PostHog") @@ -96,7 +104,8 @@ def test_parse_github_urls(self, mock_get): self.assertEqual(parsed_url["path"], "test/path/in/repo") self.assertEqual(mock_get.call_count, 1) mock_get.assert_called_with( - "https://api.github.com/repos/PostHog/posthog/commits?sha=main&path=test/path/in/repo", headers={} + "https://api.github.com/repos/PostHog/posthog/commits?sha=main&path=test/path/in/repo", + headers={}, ) mock_get.reset_mock() @@ -165,14 +174,18 @@ def test_parse_github_urls(self, mock_get): self.assertEqual(mock_get.call_count, 0) mock_get.reset_mock() - parsed_url = parse_url("https://github.com/PostHog/posthog?private_token=TOKEN", get_latest_if_none=True) + parsed_url = parse_url( + "https://github.com/PostHog/posthog?private_token=TOKEN", + get_latest_if_none=True, + ) self.assertEqual(parsed_url["type"], "github") self.assertEqual(parsed_url["user"], "PostHog") self.assertEqual(parsed_url["repo"], "posthog") self.assertEqual(parsed_url["tag"], "MOCKLATESTCOMMIT") self.assertEqual(parsed_url.get("path", None), None) mock_get.assert_called_with( - "https://api.github.com/repos/PostHog/posthog/commits?sha=&path=", headers={"Authorization": "Bearer TOKEN"} + "https://api.github.com/repos/PostHog/posthog/commits?sha=&path=", + headers={"Authorization": "Bearer TOKEN"}, ) self.assertEqual(mock_get.call_count, 1) mock_get.reset_mock() @@ -205,7 +218,10 @@ def test_parse_github_urls(self, mock_get): self.assertEqual(mock_get.call_count, 1) mock_get.reset_mock() - parsed_url = parse_url("https://github.com/PostHog/posthog?private_token=TOKEN", get_latest_if_none=True) + parsed_url = parse_url( + "https://github.com/PostHog/posthog?private_token=TOKEN", + get_latest_if_none=True, + ) self.assertEqual(parsed_url["type"], "github") self.assertEqual(parsed_url["user"], "PostHog") self.assertEqual(parsed_url["repo"], "posthog") @@ -233,34 +249,47 @@ def test_parse_gitlab_urls(self, mock_get): self.assertEqual(parsed_url.get("private_token", None), None) self.assertEqual(mock_get.call_count, 1) mock_get.assert_called_with( - "https://gitlab.com/api/v4/projects/mariusandra%2Fhelloworldplugin/repository/commits", headers={} + "https://gitlab.com/api/v4/projects/mariusandra%2Fhelloworldplugin/repository/commits", + headers={}, ) parsed_url = parse_url( "https://gitlab.com/gitlab-org/gl-openshift/openshift-demos/openshift-custom-pipeline/-/tree/master" ) - self.assertEqual(parsed_url["project"], "gitlab-org/gl-openshift/openshift-demos/openshift-custom-pipeline") + self.assertEqual( + parsed_url["project"], + "gitlab-org/gl-openshift/openshift-demos/openshift-custom-pipeline", + ) self.assertEqual(parsed_url["tag"], "master") self.assertEqual(mock_get.call_count, 1) parsed_url = parse_url( "https://gitlab.com/gitlab-org/gl-openshift/openshift-demos/openshift-custom-pipeline/-/tree/2b6494bdf8ad35073aafe36ca8a1bdfaf3dc72d1" ) - self.assertEqual(parsed_url["project"], "gitlab-org/gl-openshift/openshift-demos/openshift-custom-pipeline") + self.assertEqual( + parsed_url["project"], + "gitlab-org/gl-openshift/openshift-demos/openshift-custom-pipeline", + ) self.assertEqual(parsed_url["tag"], "2b6494bdf8ad35073aafe36ca8a1bdfaf3dc72d1") self.assertEqual(mock_get.call_count, 1) parsed_url = parse_url( "https://gitlab.com/gitlab-org/gl-openshift/openshift-demos/openshift-custom-pipeline/-/commit/2b6494bdf8ad35073aafe36ca8a1bdfaf3dc72d1" ) - self.assertEqual(parsed_url["project"], "gitlab-org/gl-openshift/openshift-demos/openshift-custom-pipeline") + self.assertEqual( + parsed_url["project"], + "gitlab-org/gl-openshift/openshift-demos/openshift-custom-pipeline", + ) self.assertEqual(parsed_url["tag"], "2b6494bdf8ad35073aafe36ca8a1bdfaf3dc72d1") self.assertEqual(mock_get.call_count, 1) parsed_url = parse_url( "https://gitlab.com/gitlab-org/gl-openshift/openshift-demos/openshift-custom-pipeline/-/archive/master/openshift-custom-pipeline-master.zip" ) - self.assertEqual(parsed_url["project"], "gitlab-org/gl-openshift/openshift-demos/openshift-custom-pipeline") + self.assertEqual( + parsed_url["project"], + "gitlab-org/gl-openshift/openshift-demos/openshift-custom-pipeline", + ) self.assertEqual(parsed_url["tag"], "master") self.assertEqual(mock_get.call_count, 1) @@ -273,7 +302,8 @@ def test_parse_gitlab_urls(self, mock_get): self.assertEqual(mock_get.call_count, 1) parsed_url = parse_url( - "https://gitlab.com/mariusandra/helloworldplugin?private_token=PRIVATE", get_latest_if_none=True + "https://gitlab.com/mariusandra/helloworldplugin?private_token=PRIVATE", + get_latest_if_none=True, ) self.assertEqual(parsed_url["type"], "gitlab") self.assertEqual(parsed_url["project"], "mariusandra/helloworldplugin") @@ -288,7 +318,10 @@ def test_parse_gitlab_urls(self, mock_get): parsed_url = parse_url( "https://gitlab.com/gitlab-org/gl-openshift/openshift-demos/openshift-custom-pipeline/-/commit/2b6494bdf8ad35073aafe36ca8a1bdfaf3dc72d1?private_token=PRIVATE" ) - self.assertEqual(parsed_url["project"], "gitlab-org/gl-openshift/openshift-demos/openshift-custom-pipeline") + self.assertEqual( + parsed_url["project"], + "gitlab-org/gl-openshift/openshift-demos/openshift-custom-pipeline", + ) self.assertEqual(parsed_url["tag"], "2b6494bdf8ad35073aafe36ca8a1bdfaf3dc72d1") self.assertEqual(parsed_url["private_token"], "PRIVATE") self.assertEqual(mock_get.call_count, 2) @@ -296,7 +329,8 @@ def test_parse_gitlab_urls(self, mock_get): # default global token with self.settings(GITLAB_TOKEN="MY_GITLAB_TOKEN"): parsed_url = parse_url( - "https://gitlab.com/mariusandra/helloworldplugin?private_token=PRIVATE", get_latest_if_none=True + "https://gitlab.com/mariusandra/helloworldplugin?private_token=PRIVATE", + get_latest_if_none=True, ) self.assertEqual(parsed_url["type"], "gitlab") self.assertEqual(parsed_url["project"], "mariusandra/helloworldplugin") @@ -308,7 +342,10 @@ def test_parse_gitlab_urls(self, mock_get): headers={"Authorization": "Bearer PRIVATE"}, ) - parsed_url = parse_url("https://gitlab.com/mariusandra/helloworldplugin", get_latest_if_none=True) + parsed_url = parse_url( + "https://gitlab.com/mariusandra/helloworldplugin", + get_latest_if_none=True, + ) self.assertEqual(parsed_url["type"], "gitlab") self.assertEqual(parsed_url["project"], "mariusandra/helloworldplugin") self.assertEqual(parsed_url["tag"], "ff78cbe1d70316055c610a962a8355a4616d874b") @@ -332,14 +369,20 @@ def test_parse_npm_urls(self, mock_get): self.assertEqual(parsed_url.get("tag", None), None) self.assertEqual(mock_get.call_count, 0) - parsed_url = parse_url("https://www.npmjs.com/package/posthog-helloworld-plugin", get_latest_if_none=True) + parsed_url = parse_url( + "https://www.npmjs.com/package/posthog-helloworld-plugin", + get_latest_if_none=True, + ) self.assertEqual(parsed_url["type"], "npm") self.assertEqual(parsed_url["pkg"], "posthog-helloworld-plugin") self.assertEqual(parsed_url["tag"], "MOCK") self.assertEqual(mock_get.call_count, 1) mock_get.assert_called_with("https://registry.npmjs.org/posthog-helloworld-plugin/latest", headers={}) - parsed_url = parse_url("https://www.npmjs.com/package/@posthog/helloworldplugin", get_latest_if_none=True) + parsed_url = parse_url( + "https://www.npmjs.com/package/@posthog/helloworldplugin", + get_latest_if_none=True, + ) self.assertEqual(parsed_url["type"], "npm") self.assertEqual(parsed_url["pkg"], "@posthog/helloworldplugin") self.assertEqual(parsed_url["tag"], "MOCK") @@ -359,7 +402,8 @@ def test_parse_npm_urls(self, mock_get): self.assertEqual(mock_get.call_count, 2) parsed_url = parse_url( - "https://www.npmjs.com/package/posthog-helloworld-plugin/v/0.0.0", get_latest_if_none=True + "https://www.npmjs.com/package/posthog-helloworld-plugin/v/0.0.0", + get_latest_if_none=True, ) self.assertEqual(parsed_url["type"], "npm") self.assertEqual(parsed_url["pkg"], "posthog-helloworld-plugin") @@ -368,7 +412,8 @@ def test_parse_npm_urls(self, mock_get): # private tokens parsed_url = parse_url( - "https://www.npmjs.com/package/posthog-helloworld-plugin?private_token=TOKEN", get_latest_if_none=True + "https://www.npmjs.com/package/posthog-helloworld-plugin?private_token=TOKEN", + get_latest_if_none=True, ) self.assertEqual(parsed_url["type"], "npm") self.assertEqual(parsed_url["pkg"], "posthog-helloworld-plugin") @@ -376,7 +421,8 @@ def test_parse_npm_urls(self, mock_get): self.assertEqual(parsed_url["private_token"], "TOKEN") self.assertEqual(mock_get.call_count, 3) mock_get.assert_called_with( - "https://registry.npmjs.org/posthog-helloworld-plugin/latest", headers={"Authorization": "Bearer TOKEN"} + "https://registry.npmjs.org/posthog-helloworld-plugin/latest", + headers={"Authorization": "Bearer TOKEN"}, ) parsed_url = parse_url("https://www.npmjs.com/package/posthog-helloworld-plugin/v/0.0.0?private_token=TOKEN") @@ -396,7 +442,8 @@ def test_parse_npm_urls(self, mock_get): # default global token with self.settings(NPM_TOKEN="MY_NPM_TOKEN"): parsed_url = parse_url( - "https://www.npmjs.com/package/posthog-helloworld-plugin?private_token=TOKEN", get_latest_if_none=True + "https://www.npmjs.com/package/posthog-helloworld-plugin?private_token=TOKEN", + get_latest_if_none=True, ) self.assertEqual(parsed_url["type"], "npm") self.assertEqual(parsed_url["pkg"], "posthog-helloworld-plugin") @@ -404,10 +451,14 @@ def test_parse_npm_urls(self, mock_get): self.assertEqual(parsed_url["private_token"], "TOKEN") self.assertEqual(mock_get.call_count, 4) mock_get.assert_called_with( - "https://registry.npmjs.org/posthog-helloworld-plugin/latest", headers={"Authorization": "Bearer TOKEN"} + "https://registry.npmjs.org/posthog-helloworld-plugin/latest", + headers={"Authorization": "Bearer TOKEN"}, ) - parsed_url = parse_url("https://www.npmjs.com/package/posthog-helloworld-plugin", get_latest_if_none=True) + parsed_url = parse_url( + "https://www.npmjs.com/package/posthog-helloworld-plugin", + get_latest_if_none=True, + ) self.assertEqual(parsed_url["type"], "npm") self.assertEqual(parsed_url["pkg"], "posthog-helloworld-plugin") self.assertEqual(parsed_url["tag"], "MOCK") @@ -488,8 +539,14 @@ def test_download_plugin_archive_github(self, mock_get): "https://github.com/PostHog/helloworldplugin/archive/f5a9ea85adaafe7c99014b7e8e0982c447631d54.zip", headers={}, ) - self.assertEqual(zip_file.getinfo("helloworldplugin-imageless-version/index.js").CRC, 1913611967) - self.assertEqual(zip_file.getinfo("helloworldplugin-imageless-version/plugin.json").CRC, 2713501883) + self.assertEqual( + zip_file.getinfo("helloworldplugin-imageless-version/index.js").CRC, + 1913611967, + ) + self.assertEqual( + zip_file.getinfo("helloworldplugin-imageless-version/plugin.json").CRC, + 2713501883, + ) def test_download_plugin_archive_gitlab(self, mock_get): plugin_gitlab = download_plugin_archive( @@ -542,7 +599,8 @@ def test_download_plugin_archive_npm(self, mock_get): self.assertEqual(plugin_npm_tgz, base64.b64decode(HELLO_WORLD_PLUGIN_NPM_TGZ[1])) self.assertEqual(mock_get.call_count, 1) mock_get.assert_called_with( - "https://registry.npmjs.org/posthog-helloworld-plugin/-/posthog-helloworld-plugin-0.0.0.tgz", headers={} + "https://registry.npmjs.org/posthog-helloworld-plugin/-/posthog-helloworld-plugin-0.0.0.tgz", + headers={}, ) plugin_npm_tgz = download_plugin_archive( @@ -576,21 +634,24 @@ def test_download_plugin_archive_npm(self, mock_get): def test_get_file_from_archive(self, mock_get): plugin_json_zip = cast( - dict, get_file_from_archive(base64.b64decode(HELLO_WORLD_PLUGIN_GITHUB_ZIP[1]), "plugin.json") + dict, + get_file_from_archive(base64.b64decode(HELLO_WORLD_PLUGIN_GITHUB_ZIP[1]), "plugin.json"), ) self.assertEqual(plugin_json_zip["name"], "helloworldplugin") self.assertEqual(plugin_json_zip["url"], "https://github.com/PostHog/helloworldplugin") self.assertEqual(plugin_json_zip["description"], "Greet the World and Foo a Bar, JS edition!") plugin_json_zip = cast( - dict, get_file_from_archive(base64.b64decode(HELLO_WORLD_PLUGIN_GITLAB_ZIP[1]), "plugin.json") + dict, + get_file_from_archive(base64.b64decode(HELLO_WORLD_PLUGIN_GITLAB_ZIP[1]), "plugin.json"), ) self.assertEqual(plugin_json_zip["name"], "hellojsplugin") self.assertEqual(plugin_json_zip["url"], "https://github.com/PosthHog/helloworldplugin") self.assertEqual(plugin_json_zip["description"], "Greet the World and Foo a Bar, JS edition!") plugin_json_tgz = cast( - dict, get_file_from_archive(base64.b64decode(HELLO_WORLD_PLUGIN_NPM_TGZ[1]), "plugin.json") + dict, + get_file_from_archive(base64.b64decode(HELLO_WORLD_PLUGIN_NPM_TGZ[1]), "plugin.json"), ) self.assertEqual(plugin_json_tgz["name"], "helloworldplugin") self.assertEqual(plugin_json_tgz["url"], "https://github.com/PostHog/helloworldplugin") diff --git a/posthog/plugins/utils.py b/posthog/plugins/utils.py index 9ce8d867acbc4..45eeb5ca94843 100644 --- a/posthog/plugins/utils.py +++ b/posthog/plugins/utils.py @@ -47,7 +47,10 @@ def parse_github_url(url: str, get_latest_if_none=False) -> Optional[Dict[str, O parsed["tag"] = "refs/tags/{}".format(parsed["tag"]) elif not re.match(r"^[a-f0-9]{40}$", parsed["tag"] or ""): commits_url = "https://api.github.com/repos/{}/{}/commits?sha={}&path={}".format( - parsed["user"], parsed["repo"], parsed["tag"] or "", parsed["path"] or "" + parsed["user"], + parsed["repo"], + parsed["tag"] or "", + parsed["path"] or "", ) commits = requests.get(commits_url, headers=headers).json() @@ -95,7 +98,8 @@ def parse_gitlab_url(url: str, get_latest_if_none=False) -> Optional[Dict[str, O parsed["tag"] = path.split("/")[1] parsed["root_url"] = "https://gitlab.com/{}{}".format( - parsed["project"], "?private_token={}".format(private_token) if private_token else "" + parsed["project"], + "?private_token={}".format(private_token) if private_token else "", ) if get_latest_if_none and not parsed["tag"]: @@ -115,7 +119,9 @@ def parse_gitlab_url(url: str, get_latest_if_none=False) -> Optional[Dict[str, O if parsed["tag"]: parsed["tagged_url"] = "https://gitlab.com/{}/-/tree/{}{}".format( - parsed["project"], parsed["tag"], "?private_token={}".format(private_token) if private_token else "" + parsed["project"], + parsed["tag"], + "?private_token={}".format(private_token) if private_token else "", ) return parsed @@ -124,7 +130,8 @@ def parse_gitlab_url(url: str, get_latest_if_none=False) -> Optional[Dict[str, O def parse_npm_url(url: str, get_latest_if_none=False) -> Optional[Dict[str, Optional[str]]]: url, private_token = split_url_and_private_token(url) match = re.search( - r"^https?://(?:www\.)?npmjs\.com/package/([@a-z0-9_-]+(/[a-z0-9_-]+)?)?/?(v/([A-Za-z0-9_.-]+)/?|)$", url + r"^https?://(?:www\.)?npmjs\.com/package/([@a-z0-9_-]+(/[a-z0-9_-]+)?)?/?(v/([A-Za-z0-9_.-]+)/?|)$", + url, ) if not match: return None @@ -136,19 +143,25 @@ def parse_npm_url(url: str, get_latest_if_none=False) -> Optional[Dict[str, Opti } parsed["root_url"] = "https://www.npmjs.com/package/{}{}".format( - parsed["pkg"], "?private_token={}".format(private_token) if private_token else "" + parsed["pkg"], + "?private_token={}".format(private_token) if private_token else "", ) if get_latest_if_none and not parsed["tag"]: try: token = private_token or settings.NPM_TOKEN headers = {"Authorization": "Bearer {}".format(token)} if token else {} - details = requests.get("https://registry.npmjs.org/{}/latest".format(parsed["pkg"]), headers=headers).json() + details = requests.get( + "https://registry.npmjs.org/{}/latest".format(parsed["pkg"]), + headers=headers, + ).json() parsed["tag"] = details["version"] except Exception: raise Exception("Could not get latest version for: {}".format(url)) if parsed["tag"]: parsed["tagged_url"] = "https://www.npmjs.com/package/{}/v/{}{}".format( - parsed["pkg"], parsed["tag"], "?private_token={}".format(private_token) if private_token else "" + parsed["pkg"], + parsed["tag"], + "?private_token={}".format(private_token) if private_token else "", ) return parsed @@ -184,7 +197,9 @@ def download_plugin_archive(url: str, tag: Optional[str] = None) -> bytes: if not (tag or parsed_url.get("tag", None)): raise Exception("No GitHub tag given!") url = "https://github.com/{user}/{repo}/archive/{tag}.zip".format( - user=parsed_url["user"], repo=parsed_url["repo"], tag=tag or parsed_url["tag"] + user=parsed_url["user"], + repo=parsed_url["repo"], + tag=tag or parsed_url["tag"], ) token = parsed_url["private_token"] or settings.GITHUB_TOKEN if token: @@ -259,9 +274,9 @@ def get_file_from_zip_archive(archive: bytes, filename: str, *, json_parse: bool file_bytes = reader.read() if json_parse: return json.loads(file_bytes) - if type(file_bytes) == bytes: + if isinstance(file_bytes, bytes): return file_bytes.decode("utf-8") - return str(file_bytes) + return str(file_bytes) # type: ignore def get_file_from_tgz_archive(archive: bytes, filename, *, json_parse: bool) -> Any: diff --git a/posthog/queries/actor_base_query.py b/posthog/queries/actor_base_query.py index 706829dfba191..396c216f9c01d 100644 --- a/posthog/queries/actor_base_query.py +++ b/posthog/queries/actor_base_query.py @@ -96,7 +96,7 @@ def is_aggregating_by_groups(self) -> bool: def get_actors( self, - ) -> Tuple[Union[QuerySet[Person], QuerySet[Group]], Union[List[SerializedGroup], List[SerializedPerson]], int]: + ) -> Tuple[Union[QuerySet[Person], QuerySet[Group]], Union[List[SerializedGroup], List[SerializedPerson]], int,]: """Get actors in data model and dict formats. Builds query and executes""" self._filter.team = self._team query, params = self.actor_query() @@ -109,13 +109,20 @@ def get_actors( ) actors, serialized_actors = self.get_actors_from_result(raw_result) - if hasattr(self._filter, "include_recordings") and self._filter.include_recordings and self._filter.insight in [INSIGHT_PATHS, INSIGHT_TRENDS, INSIGHT_FUNNELS]: # type: ignore + if ( + hasattr(self._filter, "include_recordings") + and self._filter.include_recordings # type: ignore + and self._filter.insight in [INSIGHT_PATHS, INSIGHT_TRENDS, INSIGHT_FUNNELS] + ): serialized_actors = self.add_matched_recordings_to_serialized_actors(serialized_actors, raw_result) return actors, serialized_actors, len(raw_result) def query_for_session_ids_with_recordings( - self, session_ids: Set[str], date_from: datetime | None, date_to: datetime | None + self, + session_ids: Set[str], + date_from: datetime | None, + date_to: datetime | None, ) -> Set[str]: """Filters a list of session_ids to those that actually have recordings""" query = """ @@ -154,7 +161,9 @@ def query_for_session_ids_with_recordings( return {row[0] for row in raw_result} def add_matched_recordings_to_serialized_actors( - self, serialized_actors: Union[List[SerializedGroup], List[SerializedPerson]], raw_result + self, + serialized_actors: Union[List[SerializedGroup], List[SerializedPerson]], + raw_result, ) -> Union[List[SerializedGroup], List[SerializedPerson]]: all_session_ids = set() @@ -172,7 +181,9 @@ def add_matched_recordings_to_serialized_actors( # Prune out deleted recordings session_ids_with_deleted_recordings = set( SessionRecording.objects.filter( - team=self._team, session_id__in=session_ids_with_all_recordings, deleted=True + team=self._team, + session_id__in=session_ids_with_all_recordings, + deleted=True, ).values_list("session_id", flat=True) ) session_ids_with_recordings = session_ids_with_all_recordings.difference(session_ids_with_deleted_recordings) @@ -206,7 +217,7 @@ def add_matched_recordings_to_serialized_actors( def get_actors_from_result( self, raw_result - ) -> Tuple[Union[QuerySet[Person], QuerySet[Group]], Union[List[SerializedGroup], List[SerializedPerson]]]: + ) -> Tuple[Union[QuerySet[Person], QuerySet[Group]], Union[List[SerializedGroup], List[SerializedPerson]],]: actors: Union[QuerySet[Person], QuerySet[Group]] serialized_actors: Union[List[SerializedGroup], List[SerializedPerson]] @@ -215,7 +226,10 @@ def get_actors_from_result( if self.is_aggregating_by_groups: actors, serialized_actors = get_groups( - self._team.pk, cast(int, self.aggregation_group_type_index), actor_ids, value_per_actor_id + self._team.pk, + cast(int, self.aggregation_group_type_index), + actor_ids, + value_per_actor_id, ) else: actors, serialized_actors = get_people(self._team, actor_ids, value_per_actor_id) @@ -223,13 +237,19 @@ def get_actors_from_result( if self.ACTOR_VALUES_INCLUDED: # We fetched actors from Postgres in get_groups/get_people, so `ORDER BY actor_value DESC` no longer holds # We need .sort() to restore this order - serialized_actors.sort(key=lambda actor: cast(float, actor["value_at_data_point"]), reverse=True) + serialized_actors.sort( + key=lambda actor: cast(float, actor["value_at_data_point"]), + reverse=True, + ) return actors, serialized_actors def get_groups( - team_id: int, group_type_index: int, group_ids: List[Any], value_per_actor_id: Optional[Dict[str, float]] = None + team_id: int, + group_type_index: int, + group_ids: List[Any], + value_per_actor_id: Optional[Dict[str, float]] = None, ) -> Tuple[QuerySet[Group], List[SerializedGroup]]: """Get groups from raw SQL results in data model and dict formats""" groups: QuerySet[Group] = Group.objects.filter( @@ -239,7 +259,10 @@ def get_groups( def get_people( - team: Team, people_ids: List[Any], value_per_actor_id: Optional[Dict[str, float]] = None, distinct_id_limit=1000 + team: Team, + people_ids: List[Any], + value_per_actor_id: Optional[Dict[str, float]] = None, + distinct_id_limit=1000, ) -> Tuple[QuerySet[Person], List[SerializedPerson]]: """Get people from raw SQL results in data model and dict formats""" distinct_id_subquery = Subquery( @@ -263,7 +286,9 @@ def get_people( def serialize_people( - team: Team, data: Union[QuerySet[Person], List[Person]], value_per_actor_id: Optional[Dict[str, float]] = None + team: Team, + data: Union[QuerySet[Person], List[Person]], + value_per_actor_id: Optional[Dict[str, float]] = None, ) -> List[SerializedPerson]: from posthog.api.person import get_person_name diff --git a/posthog/queries/app_metrics/app_metrics.py b/posthog/queries/app_metrics/app_metrics.py index e6c36b799ff1e..26f91f626ec0b 100644 --- a/posthog/queries/app_metrics/app_metrics.py +++ b/posthog/queries/app_metrics/app_metrics.py @@ -13,7 +13,10 @@ from posthog.models.event.util import format_clickhouse_timestamp from posthog.models.filters.mixins.base import IntervalType from posthog.models.team.team import Team -from posthog.queries.app_metrics.serializers import AppMetricsErrorsRequestSerializer, AppMetricsRequestSerializer +from posthog.queries.app_metrics.serializers import ( + AppMetricsErrorsRequestSerializer, + AppMetricsRequestSerializer, +) from posthog.queries.util import format_ch_timestamp, get_time_in_seconds_for_period from posthog.utils import relative_date_parse @@ -27,7 +30,10 @@ def __init__(self, team: Team): def run(self): results = sync_execute( self.QUERY, - {"team_id": self.team.pk, "from_date": format_clickhouse_timestamp(datetime.now() - timedelta(hours=24))}, + { + "team_id": self.team.pk, + "from_date": format_clickhouse_timestamp(datetime.now() - timedelta(hours=24)), + }, ) return dict(results) @@ -80,7 +86,9 @@ def query(self): @property def date_from(self): return relative_date_parse( - self.filter.validated_data.get("date_from"), self.team.timezone_info, always_truncate=True + self.filter.validated_data.get("date_from"), + self.team.timezone_info, + always_truncate=True, ) @property @@ -121,7 +129,12 @@ def run(self): class AppMetricsErrorDetailsQuery: QUERY = QUERY_APP_METRICS_ERROR_DETAILS - def __init__(self, team: Team, plugin_config_id: int, filter: AppMetricsErrorsRequestSerializer): + def __init__( + self, + team: Team, + plugin_config_id: int, + filter: AppMetricsErrorsRequestSerializer, + ): self.team = team self.plugin_config_id = plugin_config_id self.filter = filter diff --git a/posthog/queries/app_metrics/historical_exports.py b/posthog/queries/app_metrics/historical_exports.py index 484f01546001b..cbf22d480156b 100644 --- a/posthog/queries/app_metrics/historical_exports.py +++ b/posthog/queries/app_metrics/historical_exports.py @@ -7,7 +7,10 @@ from posthog.models.activity_logging.activity_log import ActivityLog from posthog.models.plugin import PluginStorage from posthog.models.team.team import Team -from posthog.queries.app_metrics.app_metrics import AppMetricsErrorsQuery, AppMetricsQuery +from posthog.queries.app_metrics.app_metrics import ( + AppMetricsErrorsQuery, + AppMetricsQuery, +) from posthog.queries.app_metrics.serializers import AppMetricsRequestSerializer diff --git a/posthog/queries/app_metrics/test/test_app_metrics.py b/posthog/queries/app_metrics/test/test_app_metrics.py index affe411457116..95eeb13bc09f4 100644 --- a/posthog/queries/app_metrics/test/test_app_metrics.py +++ b/posthog/queries/app_metrics/test/test_app_metrics.py @@ -15,7 +15,10 @@ AppMetricsQuery, TeamPluginsDeliveryRateQuery, ) -from posthog.queries.app_metrics.serializers import AppMetricsErrorsRequestSerializer, AppMetricsRequestSerializer +from posthog.queries.app_metrics.serializers import ( + AppMetricsErrorsRequestSerializer, + AppMetricsRequestSerializer, +) from posthog.test.base import BaseTest, ClickhouseTestMixin, snapshot_clickhouse_queries from posthog.utils import cast_timestamp_or_now @@ -100,7 +103,11 @@ def test_query_delivery_rate(self): @freeze_time("2021-12-05T13:23:00Z") def test_ignores_out_of_bound_metrics(self): create_app_metric( - team_id=-1, category="processEvent", plugin_config_id=3, timestamp="2021-12-05T00:10:00Z", successes=5 + team_id=-1, + category="processEvent", + plugin_config_id=3, + timestamp="2021-12-05T00:10:00Z", + successes=5, ) create_app_metric( team_id=self.team.pk, @@ -269,7 +276,11 @@ def test_ignores_unrelated_data(self): # Negative examples # Different team create_app_metric( - team_id=-1, category="processEvent", plugin_config_id=3, timestamp="2021-12-05T13:10:00Z", failures=1 + team_id=-1, + category="processEvent", + plugin_config_id=3, + timestamp="2021-12-05T13:10:00Z", + failures=1, ) # Different pluginConfigId create_app_metric( @@ -544,7 +555,9 @@ def test_error_details_query(self): ) filter = make_filter( - serializer_klass=AppMetricsErrorsRequestSerializer, category="processEvent", error_type="SomeError" + serializer_klass=AppMetricsErrorsRequestSerializer, + category="processEvent", + error_type="SomeError", ) results = AppMetricsErrorDetailsQuery(self.team, 3, filter).run() @@ -679,7 +692,9 @@ def test_ignores_unrelated_data(self): ) filter = make_filter( - serializer_klass=AppMetricsErrorsRequestSerializer, category="processEvent", error_type="SomeError" + serializer_klass=AppMetricsErrorsRequestSerializer, + category="processEvent", + error_type="SomeError", ) results = AppMetricsErrorDetailsQuery(self.team, 3, filter).run() diff --git a/posthog/queries/app_metrics/test/test_historical_exports.py b/posthog/queries/app_metrics/test/test_historical_exports.py index 2e9ffcb41a7bb..6bed36981931c 100644 --- a/posthog/queries/app_metrics/test/test_historical_exports.py +++ b/posthog/queries/app_metrics/test/test_historical_exports.py @@ -8,9 +8,17 @@ from posthog.models.plugin import Plugin, PluginConfig, PluginStorage from posthog.models.team.team import Team from posthog.models.utils import UUIDT -from posthog.queries.app_metrics.historical_exports import historical_export_metrics, historical_exports_activity +from posthog.queries.app_metrics.historical_exports import ( + historical_export_metrics, + historical_exports_activity, +) from posthog.queries.app_metrics.test.test_app_metrics import create_app_metric -from posthog.test.base import BaseTest, ClickhouseTestMixin, snapshot_clickhouse_queries, snapshot_postgres_queries +from posthog.test.base import ( + BaseTest, + ClickhouseTestMixin, + snapshot_clickhouse_queries, + snapshot_postgres_queries, +) SAMPLE_PAYLOAD = {"dateRange": ["2021-06-10", "2022-06-12"], "parallelism": 1} @@ -32,12 +40,18 @@ def test_historical_exports_activity_for_not_finished_export(self): activity="job_triggered", detail=Detail( name="Some export plugin", - trigger=Trigger(job_type="Export historical events V2", job_id="1234", payload=SAMPLE_PAYLOAD), + trigger=Trigger( + job_type="Export historical events V2", + job_id="1234", + payload=SAMPLE_PAYLOAD, + ), ), ) PluginStorage.objects.create( - plugin_config_id=self.plugin_config.pk, key="EXPORT_COORDINATION", value=json.dumps({"progress": 0.33}) + plugin_config_id=self.plugin_config.pk, + key="EXPORT_COORDINATION", + value=json.dumps({"progress": 0.33}), ) activities = historical_exports_activity(self.team.pk, self.plugin_config.pk) @@ -61,7 +75,11 @@ def test_historical_exports_activity_for_finished_export(self): activity="job_triggered", detail=Detail( name="Some export plugin", - trigger=Trigger(job_type="Export historical events V2", job_id="1234", payload=SAMPLE_PAYLOAD), + trigger=Trigger( + job_type="Export historical events V2", + job_id="1234", + payload=SAMPLE_PAYLOAD, + ), ), ) with freeze_time("2021-08-25T13:00:00Z"): @@ -69,7 +87,11 @@ def test_historical_exports_activity_for_finished_export(self): activity="export_success", detail=Detail( name="Some export plugin", - trigger=Trigger(job_type="Export historical events V2", job_id="1234", payload={}), + trigger=Trigger( + job_type="Export historical events V2", + job_id="1234", + payload={}, + ), ), ) @@ -95,7 +117,11 @@ def test_historical_exports_activity_for_failed_export(self): activity="job_triggered", detail=Detail( name="Some export plugin", - trigger=Trigger(job_type="Export historical events V2", job_id="1234", payload=SAMPLE_PAYLOAD), + trigger=Trigger( + job_type="Export historical events V2", + job_id="1234", + payload=SAMPLE_PAYLOAD, + ), ), ) with freeze_time("2021-08-25T13:00:00Z"): @@ -104,7 +130,9 @@ def test_historical_exports_activity_for_failed_export(self): detail=Detail( name="Some export plugin", trigger=Trigger( - job_type="Export historical events V2", job_id="1234", payload={"failure_reason": "foobar"} + job_type="Export historical events V2", + job_id="1234", + payload={"failure_reason": "foobar"}, ), ), ) @@ -130,7 +158,11 @@ def test_historical_exports_activity_ignores_unrelated_entries(self): activity="job_triggered", detail=Detail( name="Some export plugin", - trigger=Trigger(job_type="Export historical events V2", job_id="1234", payload=SAMPLE_PAYLOAD), + trigger=Trigger( + job_type="Export historical events V2", + job_id="1234", + payload=SAMPLE_PAYLOAD, + ), ), ) @@ -192,7 +224,9 @@ def test_historical_exports_orders_activity_by_created_at(self): detail=Detail( name="Some export plugin", trigger=Trigger( - job_type="Export historical events V2", job_id=str(hour), payload=SAMPLE_PAYLOAD + job_type="Export historical events V2", + job_id=str(hour), + payload=SAMPLE_PAYLOAD, ), ), ) @@ -218,7 +252,11 @@ def test_historical_export_metrics(self): activity="job_triggered", detail=Detail( name="Some export plugin", - trigger=Trigger(job_type="Export historical events V2", job_id="1234", payload=SAMPLE_PAYLOAD), + trigger=Trigger( + job_type="Export historical events V2", + job_id="1234", + payload=SAMPLE_PAYLOAD, + ), ), ) with freeze_time("2021-08-25T05:00:00Z"): @@ -226,7 +264,11 @@ def test_historical_export_metrics(self): activity="export_success", detail=Detail( name="Some export plugin", - trigger=Trigger(job_type="Export historical events V2", job_id="1234", payload={}), + trigger=Trigger( + job_type="Export historical events V2", + job_id="1234", + payload={}, + ), ), ) @@ -276,7 +318,11 @@ def test_historical_export_metrics(self): "successes": [0, 102, 0, 10, 0, 0, 0], "successes_on_retry": [0, 0, 0, 0, 0, 0, 0], "failures": [0, 0, 2, 0, 0, 0, 0], - "totals": {"successes": 112, "successes_on_retry": 0, "failures": 2}, + "totals": { + "successes": 112, + "successes_on_retry": 0, + "failures": 2, + }, }, "summary": { "duration": 4 * 60 * 60, diff --git a/posthog/queries/base.py b/posthog/queries/base.py index 57ff555c2dcc8..f03e6723ac72e 100644 --- a/posthog/queries/base.py +++ b/posthog/queries/base.py @@ -19,7 +19,11 @@ from posthog.models.cohort import Cohort, CohortPeople from posthog.models.filters.filter import Filter from posthog.models.filters.path_filter import PathFilter -from posthog.models.property import CLICKHOUSE_ONLY_PROPERTY_TYPES, Property, PropertyGroup +from posthog.models.property import ( + CLICKHOUSE_ONLY_PROPERTY_TYPES, + Property, + PropertyGroup, +) from posthog.models.property.property import OperatorType, ValueT from posthog.models.team import Team from posthog.queries.util import convert_to_datetime_aware @@ -181,9 +185,12 @@ def match_property(property: Property, override_property_values: Dict[str, Any]) def empty_or_null_with_value_q( - column: str, key: str, operator: Optional[OperatorType], value: ValueT, negated: bool = False + column: str, + key: str, + operator: Optional[OperatorType], + value: ValueT, + negated: bool = False, ) -> Q: - if operator == "exact" or operator is None: value_as_given = Property._parse_value(value) value_as_coerced_to_number = Property._parse_value(value, convert_to_number=True) @@ -220,13 +227,11 @@ def property_to_Q( cohorts_cache: Optional[Dict[int, Cohort]] = None, using_database: str = "default", ) -> Q: - if property.type in CLICKHOUSE_ONLY_PROPERTY_TYPES: raise ValueError(f"property_to_Q: type is not supported: {repr(property.type)}") value = property._parse_value(property.value) if property.type == "cohort": - cohort_id = int(cast(Union[str, int], value)) if cohorts_cache is not None: if cohorts_cache.get(cohort_id) is None: @@ -239,14 +244,23 @@ def property_to_Q( return Q( Exists( CohortPeople.objects.using(using_database) - .filter(cohort_id=cohort_id, person_id=OuterRef("id"), cohort__id=cohort_id) + .filter( + cohort_id=cohort_id, + person_id=OuterRef("id"), + cohort__id=cohort_id, + ) .only("id") ) ) else: # :TRICKY: This has potential to create an infinite loop if the cohort is recursive. # But, this shouldn't happen because we check for cyclic cohorts on creation. - return property_group_to_Q(cohort.properties, override_property_values, cohorts_cache, using_database) + return property_group_to_Q( + cohort.properties, + override_property_values, + cohorts_cache, + using_database, + ) # short circuit query if key exists in override_property_values if property.key in override_property_values and property.operator != "is_not_set": @@ -277,7 +291,11 @@ def property_to_Q( return Q(pk=-1) if isinstance(property.operator, str) and property.operator.startswith("not_"): return empty_or_null_with_value_q( - column, property.key, cast(OperatorType, property.operator[4:]), value, negated=True + column, + property.key, + cast(OperatorType, property.operator[4:]), + value, + negated=True, ) if property.operator in ("is_date_after", "is_date_before"): @@ -294,7 +312,6 @@ def property_group_to_Q( cohorts_cache: Optional[Dict[int, Cohort]] = None, using_database: str = "default", ) -> Q: - filters = Q() if not property_group or len(property_group.values) == 0: @@ -303,7 +320,10 @@ def property_group_to_Q( if isinstance(property_group.values[0], PropertyGroup): for group in property_group.values: group_filter = property_group_to_Q( - cast(PropertyGroup, group), override_property_values, cohorts_cache, using_database + cast(PropertyGroup, group), + override_property_values, + cohorts_cache, + using_database, ) if property_group.type == PropertyOperatorType.OR: filters |= group_filter diff --git a/posthog/queries/breakdown_props.py b/posthog/queries/breakdown_props.py index 9d0ccf80db32e..a7a320e8e5dfa 100644 --- a/posthog/queries/breakdown_props.py +++ b/posthog/queries/breakdown_props.py @@ -2,7 +2,12 @@ from django.forms import ValidationError -from posthog.constants import BREAKDOWN_TYPES, MONTHLY_ACTIVE, WEEKLY_ACTIVE, PropertyOperatorType +from posthog.constants import ( + BREAKDOWN_TYPES, + MONTHLY_ACTIVE, + WEEKLY_ACTIVE, + PropertyOperatorType, +) from posthog.hogql.hogql import HogQLContext from posthog.models.cohort import Cohort from posthog.models.cohort.util import format_filter_query @@ -26,7 +31,10 @@ from posthog.queries.person_query import PersonQuery from posthog.queries.query_date_range import QueryDateRange from posthog.session_recordings.queries.session_query import SessionQuery -from posthog.queries.trends.sql import HISTOGRAM_ELEMENTS_ARRAY_OF_KEY_SQL, TOP_ELEMENTS_ARRAY_OF_KEY_SQL +from posthog.queries.trends.sql import ( + HISTOGRAM_ELEMENTS_ARRAY_OF_KEY_SQL, + TOP_ELEMENTS_ARRAY_OF_KEY_SQL, +) from posthog.queries.util import PersonPropertiesMode from posthog.utils import PersonOnEventsMode @@ -98,7 +106,10 @@ def get_breakdown_prop_values( ) person_query = PersonQuery( - filter, team.pk, column_optimizer=column_optimizer, entity=entity if not use_all_funnel_entities else None + filter, + team.pk, + column_optimizer=column_optimizer, + entity=entity if not use_all_funnel_entities else None, ) if person_properties_mode == PersonPropertiesMode.DIRECT_ON_EVENTS_WITH_POE_V2: person_join_clauses = PERSON_OVERRIDES_JOIN_SQL.format( @@ -160,7 +171,10 @@ def get_breakdown_prop_values( filter.hogql_context, filter.breakdown_normalize_url, direct_on_events=person_properties_mode - in [PersonPropertiesMode.DIRECT_ON_EVENTS, PersonPropertiesMode.DIRECT_ON_EVENTS_WITH_POE_V2], + in [ + PersonPropertiesMode.DIRECT_ON_EVENTS, + PersonPropertiesMode.DIRECT_ON_EVENTS_WITH_POE_V2, + ], cast_as_float=filter.using_histogram, ) @@ -269,7 +283,11 @@ def _to_value_expression( value_expression = translate_hogql(cast(str, breakdown), hogql_context) else: value_expression = get_single_or_multi_property_string_expr( - breakdown, table="events", query_alias=None, column="properties", normalize_url=breakdown_normalize_url + breakdown, + table="events", + query_alias=None, + column="properties", + normalize_url=breakdown_normalize_url, ) if cast_as_float: diff --git a/posthog/queries/cohort_query.py b/posthog/queries/cohort_query.py index ec1a1d7f9efff..1c1b697bfc222 100644 --- a/posthog/queries/cohort_query.py +++ b/posthog/queries/cohort_query.py @@ -1,6 +1,8 @@ from posthog.settings import EE_AVAILABLE if EE_AVAILABLE: - from ee.clickhouse.queries.enterprise_cohort_query import EnterpriseCohortQuery as CohortQuery + from ee.clickhouse.queries.enterprise_cohort_query import ( + EnterpriseCohortQuery as CohortQuery, + ) else: from posthog.queries.foss_cohort_query import FOSSCohortQuery as CohortQuery # type: ignore diff --git a/posthog/queries/column_optimizer/column_optimizer.py b/posthog/queries/column_optimizer/column_optimizer.py index 2d49afeeaf8dd..f1952e500c169 100644 --- a/posthog/queries/column_optimizer/column_optimizer.py +++ b/posthog/queries/column_optimizer/column_optimizer.py @@ -2,7 +2,9 @@ from posthog.settings import EE_AVAILABLE if EE_AVAILABLE: - from ee.clickhouse.queries.column_optimizer import EnterpriseColumnOptimizer as ColumnOptimizer + from ee.clickhouse.queries.column_optimizer import ( + EnterpriseColumnOptimizer as ColumnOptimizer, + ) else: from posthog.queries.column_optimizer.foss_column_optimizer import ( # type: ignore FOSSColumnOptimizer as ColumnOptimizer, diff --git a/posthog/queries/column_optimizer/foss_column_optimizer.py b/posthog/queries/column_optimizer/foss_column_optimizer.py index 104f3cd000137..19487a7cb5de4 100644 --- a/posthog/queries/column_optimizer/foss_column_optimizer.py +++ b/posthog/queries/column_optimizer/foss_column_optimizer.py @@ -4,7 +4,10 @@ from posthog.clickhouse.materialized_columns import ColumnName, get_materialized_columns from posthog.constants import TREND_FILTER_TYPE_ACTIONS, FunnelCorrelationType -from posthog.models.action.util import get_action_tables_and_properties, uses_elements_chain +from posthog.models.action.util import ( + get_action_tables_and_properties, + uses_elements_chain, +) from posthog.models.entity import Entity from posthog.models.filters import Filter from posthog.models.filters.mixins.utils import cached_property @@ -13,7 +16,11 @@ from posthog.models.filters.retention_filter import RetentionFilter from posthog.models.filters.stickiness_filter import StickinessFilter from posthog.models.filters.utils import GroupTypeIndex -from posthog.models.property import PropertyIdentifier, PropertyType, TableWithProperties +from posthog.models.property import ( + PropertyIdentifier, + PropertyType, + TableWithProperties, +) from posthog.models.property.util import box_value, extract_tables_and_properties from posthog.queries.property_optimizer import PropertyOptimizer @@ -27,7 +34,13 @@ class FOSSColumnOptimizer: def __init__( self, - filter: Union[Filter, PathFilter, RetentionFilter, StickinessFilter, PropertiesTimelineFilter], + filter: Union[ + Filter, + PathFilter, + RetentionFilter, + StickinessFilter, + PropertiesTimelineFilter, + ], team_id: int, ): self.filter = filter @@ -53,7 +66,10 @@ def person_columns_to_query(self) -> Set[ColumnName]: return self.columns_to_query("person", set(self.used_properties_with_type("person"))) def columns_to_query( - self, table: TableWithProperties, used_properties: Set[PropertyIdentifier], table_column: str = "properties" + self, + table: TableWithProperties, + used_properties: Set[PropertyIdentifier], + table_column: str = "properties", ) -> Set[ColumnName]: "Transforms a list of property names to what columns are needed for that query" @@ -119,12 +135,24 @@ def properties_used_in_filter(self) -> TCounter[PropertyIdentifier]: boxed_breakdown = box_value(self.filter.breakdown) for b in boxed_breakdown: if isinstance(b, str): - counter[(b, self.filter.breakdown_type, self.filter.breakdown_group_type_index)] += 1 + counter[ + ( + b, + self.filter.breakdown_type, + self.filter.breakdown_group_type_index, + ) + ] += 1 # If we have a breakdowns attribute then make sure we pull in everything we # need to calculate it for breakdown in self.filter.breakdowns or []: - counter[(breakdown["property"], breakdown["type"], self.filter.breakdown_group_type_index)] += 1 + counter[ + ( + breakdown["property"], + breakdown["type"], + self.filter.breakdown_group_type_index, + ) + ] += 1 # Both entities and funnel exclusions can contain nested property filters for entity in self.entities_used_in_filter(): @@ -147,7 +175,6 @@ def properties_used_in_filter(self) -> TCounter[PropertyIdentifier]: and self.filter.correlation_type == FunnelCorrelationType.PROPERTIES and self.filter.correlation_property_names ): - for prop_value in self.filter.correlation_property_names: counter[(prop_value, "person", None)] += 1 @@ -157,7 +184,11 @@ def used_properties_with_type(self, property_type: PropertyType) -> TCounter[Pro return Counter( { (name, type, group_type_index): count - for (name, type, group_type_index), count in self.properties_used_in_filter.items() + for ( + name, + type, + group_type_index, + ), count in self.properties_used_in_filter.items() if type == property_type } ) diff --git a/posthog/queries/event_query/event_query.py b/posthog/queries/event_query/event_query.py index 9be4dc1a2fbd2..5018892060873 100644 --- a/posthog/queries/event_query/event_query.py +++ b/posthog/queries/event_query/event_query.py @@ -47,7 +47,12 @@ class EventQuery(metaclass=ABCMeta): def __init__( self, filter: Union[ - Filter, PathFilter, RetentionFilter, StickinessFilter, SessionRecordingsFilter, PropertiesTimelineFilter + Filter, + PathFilter, + RetentionFilter, + StickinessFilter, + SessionRecordingsFilter, + PropertiesTimelineFilter, ], team: Team, round_interval=False, @@ -68,7 +73,10 @@ def __init__( self._extra_event_properties = extra_event_properties self._column_optimizer = ColumnOptimizer(self._filter, self._team_id) self._extra_person_fields = extra_person_fields - self.params: Dict[str, Any] = {"team_id": self._team_id, "timezone": team.timezone} + self.params: Dict[str, Any] = { + "team_id": self._team_id, + "timezone": team.timezone, + } self._should_join_distinct_ids = should_join_distinct_ids self._should_join_persons = should_join_persons @@ -183,7 +191,12 @@ def _does_cohort_need_persons(self, prop: Property) -> bool: def _person_query(self) -> PersonQuery: if isinstance(self._filter, PropertiesTimelineFilter): raise Exception("Properties Timeline never needs person query") - return PersonQuery(self._filter, self._team_id, self._column_optimizer, extra_fields=self._extra_person_fields) + return PersonQuery( + self._filter, + self._team_id, + self._column_optimizer, + extra_fields=self._extra_person_fields, + ) def _get_person_query(self) -> Tuple[str, Dict]: if self._should_join_persons: @@ -205,7 +218,11 @@ def _get_groups_query(self) -> Tuple[str, Dict]: def _sessions_query(self) -> SessionQuery: if isinstance(self._filter, PropertiesTimelineFilter): raise Exception("Properties Timeline never needs sessions query") - return SessionQuery(filter=self._filter, team=self._team, session_id_alias=self._session_id_alias) + return SessionQuery( + filter=self._filter, + team=self._team, + session_id_alias=self._session_id_alias, + ) def _get_sessions_query(self) -> Tuple[str, Dict]: if self._should_join_sessions: diff --git a/posthog/queries/foss_cohort_query.py b/posthog/queries/foss_cohort_query.py index b9fc8511b6301..e6005abab632a 100644 --- a/posthog/queries/foss_cohort_query.py +++ b/posthog/queries/foss_cohort_query.py @@ -5,9 +5,19 @@ from posthog.models import Filter, Team from posthog.models.action import Action from posthog.models.cohort import Cohort -from posthog.models.cohort.util import format_static_cohort_query, get_count_operator, get_entity_query +from posthog.models.cohort.util import ( + format_static_cohort_query, + get_count_operator, + get_entity_query, +) from posthog.models.filters.mixins.utils import cached_property -from posthog.models.property import BehavioralPropertyType, OperatorInterval, Property, PropertyGroup, PropertyName +from posthog.models.property import ( + BehavioralPropertyType, + OperatorInterval, + Property, + PropertyGroup, + PropertyName, +) from posthog.models.property.util import prop_filter_json_extract from posthog.queries.event_query import EventQuery from posthog.queries.util import PersonPropertiesMode @@ -17,7 +27,14 @@ Event = Tuple[str, Union[str, int]] -INTERVAL_TO_SECONDS = {"minute": 60, "hour": 3600, "day": 86400, "week": 604800, "month": 2592000, "year": 31536000} +INTERVAL_TO_SECONDS = { + "minute": 60, + "hour": 3600, + "day": 86400, + "week": 604800, + "month": 2592000, + "year": 31536000, +} def relative_date_to_seconds(date: Tuple[Optional[int], Union[OperatorInterval, None]]): @@ -101,7 +118,6 @@ def if_condition(condition: str, true_res: str, false_res: str) -> str: class FOSSCohortQuery(EventQuery): - BEHAVIOR_QUERY_ALIAS = "behavior_query" FUNNEL_QUERY_ALIAS = "funnel_query" SEQUENCE_FIELD_ALIAS = "steps" @@ -205,7 +221,13 @@ def _unwrap(property_group: PropertyGroup, negate_group: bool = False) -> Proper new_property_group_list.append( PropertyGroup( type=PropertyOperatorType.AND, - values=[Property(key="fake_key_01r2ho", value=0, type="person")], + values=[ + Property( + key="fake_key_01r2ho", + value=0, + type="person", + ) + ], ) ) else: @@ -228,7 +250,6 @@ def _unwrap(property_group: PropertyGroup, negate_group: bool = False) -> Proper # Implemented in /ee def get_query(self) -> Tuple[str, Dict[str, Any]]: - if not self._outer_property_groups: # everything is pushed down, no behavioral stuff to do # thus, use personQuery directly @@ -240,7 +261,11 @@ def get_query(self) -> Tuple[str, Dict[str, Any]]: subq = [] - behavior_subquery, behavior_subquery_params, behavior_query_alias = self._get_behavior_subquery() + ( + behavior_subquery, + behavior_subquery_params, + behavior_query_alias, + ) = self._get_behavior_subquery() subq.append((behavior_subquery, behavior_query_alias)) self.params.update(behavior_subquery_params) @@ -302,7 +327,6 @@ def _get_behavior_subquery(self) -> Tuple[str, Dict[str, Any], str]: query, params = "", {} if self._should_join_behavioral_query: - _fields = [ f"{self.DISTINCT_ID_TABLE_ALIAS if self._person_on_events_mode == PersonOnEventsMode.DISABLED else self.EVENT_TABLE_ALIAS}.person_id AS person_id" ] @@ -328,7 +352,12 @@ def _get_behavior_subquery(self) -> Tuple[str, Dict[str, Any], str]: query, params = ( query, - {"team_id": self._team_id, event_param_name: self._events, **date_params, **person_prop_params}, + { + "team_id": self._team_id, + event_param_name: self._events, + **date_params, + **person_prop_params, + }, ) return query, params, self.BEHAVIOR_QUERY_ALIAS @@ -389,7 +418,6 @@ def build_conditions(prop: Optional[Union[PropertyGroup, Property]], prepend="le # Implemented in /ee def _get_condition_for_property(self, prop: Property, prepend: str, idx: int) -> Tuple[str, Dict[str, Any]]: - res: str = "" params: Dict[str, Any] = {} @@ -412,7 +440,12 @@ def _get_condition_for_property(self, prop: Property, prepend: str, idx: int) -> def get_person_condition(self, prop: Property, prepend: str, idx: int) -> Tuple[str, Dict[str, Any]]: if self._outer_property_groups and len(self._outer_property_groups.flat): return prop_filter_json_extract( - prop, idx, prepend, prop_var="person_props", allow_denormalized_props=True, property_operator="" + prop, + idx, + prepend, + prop_var="person_props", + allow_denormalized_props=True, + property_operator="", ) else: return "", {} @@ -440,7 +473,10 @@ def get_performed_event_condition(self, prop: Property, prepend: str, idx: int) self._fields.append(field) # Negation is handled in the where clause to ensure the right result if a full join occurs where the joined person did not perform the event - return f"{'NOT' if prop.negation else ''} {column_name}", {f"{date_param}": date_value, **entity_params} + return f"{'NOT' if prop.negation else ''} {column_name}", { + f"{date_param}": date_value, + **entity_params, + } def get_performed_event_multiple(self, prop: Property, prepend: str, idx: int) -> Tuple[str, Dict[str, Any]]: event = (prop.event_type, prop.key) @@ -461,7 +497,11 @@ def get_performed_event_multiple(self, prop: Property, prepend: str, idx: int) - # Negation is handled in the where clause to ensure the right result if a full join occurs where the joined person did not perform the event return ( f"{'NOT' if prop.negation else ''} {column_name}", - {f"{operator_value_param}": count, f"{date_param}": date_value, **entity_params}, + { + f"{operator_value_param}": count, + f"{date_param}": date_value, + **entity_params, + }, ) def _determine_should_join_distinct_ids(self) -> None: @@ -497,7 +537,10 @@ def _validate_negations(self) -> None: pass def _get_entity( - self, event: Tuple[Optional[str], Optional[Union[int, str]]], prepend: str, idx: int + self, + event: Tuple[Optional[str], Optional[Union[int, str]]], + prepend: str, + idx: int, ) -> Tuple[str, Dict[str, Any]]: res: str = "" params: Dict[str, Any] = {} @@ -508,12 +551,20 @@ def _get_entity( if event[0] == "actions": self._add_action(int(event[1])) res, params = get_entity_query( - None, int(event[1]), self._team_id, f"{prepend}_entity_{idx}", self._filter.hogql_context + None, + int(event[1]), + self._team_id, + f"{prepend}_entity_{idx}", + self._filter.hogql_context, ) elif event[0] == "events": self._add_event(str(event[1])) res, params = get_entity_query( - str(event[1]), None, self._team_id, f"{prepend}_entity_{idx}", self._filter.hogql_context + str(event[1]), + None, + self._team_id, + f"{prepend}_entity_{idx}", + self._filter.hogql_context, ) else: raise ValueError(f"Event type must be 'events' or 'actions'") diff --git a/posthog/queries/funnels/base.py b/posthog/queries/funnels/base.py index 32cfadf4abd1e..8ac25880932a7 100644 --- a/posthog/queries/funnels/base.py +++ b/posthog/queries/funnels/base.py @@ -76,7 +76,10 @@ def __init__( if self._filter.funnel_window_days: self._filter = self._filter.shallow_clone( - {FUNNEL_WINDOW_INTERVAL: self._filter.funnel_window_days, FUNNEL_WINDOW_INTERVAL_UNIT: "day"} + { + FUNNEL_WINDOW_INTERVAL: self._filter.funnel_window_days, + FUNNEL_WINDOW_INTERVAL_UNIT: "day", + } ) if not self._filter.limit: @@ -308,7 +311,6 @@ def _get_timestamp_selects(self) -> Tuple[str, str]: target_step -= 1 if self._include_preceding_timestamp: - if target_step == 0: raise ValueError("Cannot request preceding step timestamp if target funnel step is the first step") @@ -391,7 +393,6 @@ def _get_exclusion_condition(self): return "" def _get_sorting_condition(self, curr_index: int, max_steps: int): - if curr_index == 1: return "1" @@ -414,7 +415,11 @@ def _get_sorting_condition(self, curr_index: int, max_steps: int): return f"if({' AND '.join(conditions)}, {curr_index}, {self._get_sorting_condition(curr_index - 1, max_steps)})" def _get_inner_event_query( - self, entities=None, entity_name="events", skip_entity_filter=False, skip_step_filter=False + self, + entities=None, + entity_name="events", + skip_entity_filter=False, + skip_step_filter=False, ) -> str: entities_to_use = entities or self._filter.entities @@ -444,7 +449,12 @@ def _get_inner_event_query( all_step_cols.extend(step_cols) for exclusion_id, entity in enumerate(self._filter.exclusions): - step_cols = self._get_step_col(entity, entity.funnel_from_step, entity_name, f"exclusion_{exclusion_id}_") + step_cols = self._get_step_col( + entity, + entity.funnel_from_step, + entity_name, + f"exclusion_{exclusion_id}_", + ) # every exclusion entity has the form: exclusion__step_i & timestamp exclusion__latest_i # where i is the starting step for exclusion on that entity all_step_cols.extend(step_cols) @@ -715,7 +725,6 @@ def _get_breakdown_select_prop(self) -> str: self.params.update({"breakdown": self._filter.breakdown}) if self._filter.breakdown_type == "person": - if self._team.person_on_events_mode != PersonOnEventsMode.DISABLED: basic_prop_selector = get_single_or_multi_property_string_expr( self._filter.breakdown, @@ -727,7 +736,10 @@ def _get_breakdown_select_prop(self) -> str: ) else: basic_prop_selector = get_single_or_multi_property_string_expr( - self._filter.breakdown, table="person", query_alias="prop_basic", column="person_props" + self._filter.breakdown, + table="person", + query_alias="prop_basic", + column="person_props", ) elif self._filter.breakdown_type == "event": basic_prop_selector = get_single_or_multi_property_string_expr( @@ -756,7 +768,10 @@ def _get_breakdown_select_prop(self) -> str: else: properties_field = f"group_properties_{self._filter.breakdown_group_type_index}" expression, _ = get_property_string_expr( - table="groups", property_name=self._filter.breakdown, var="%(breakdown)s", column=properties_field + table="groups", + property_name=self._filter.breakdown, + var="%(breakdown)s", + column=properties_field, ) basic_prop_selector = f"{expression} AS prop_basic" elif self._filter.breakdown_type == "hogql": @@ -789,7 +804,6 @@ def _get_breakdown_select_prop(self) -> str: BreakdownAttributionType.FIRST_TOUCH, BreakdownAttributionType.LAST_TOUCH, ]: - prop_conditional = ( "notEmpty(arrayFilter(x -> notEmpty(x), prop))" if self._query_has_array_breakdown() @@ -833,7 +847,10 @@ def _get_breakdown_conditions(self) -> Optional[str]: if self._filter.breakdown: use_all_funnel_entities = ( self._filter.breakdown_attribution_type - in [BreakdownAttributionType.FIRST_TOUCH, BreakdownAttributionType.LAST_TOUCH] + in [ + BreakdownAttributionType.FIRST_TOUCH, + BreakdownAttributionType.LAST_TOUCH, + ] or self._filter.funnel_order_type == FunnelOrderType.UNORDERED ) first_entity = self._filter.entities[0] @@ -860,7 +877,11 @@ def _get_breakdown_conditions(self) -> Optional[str]: def _get_breakdown_prop(self, group_remaining=False) -> str: if self._filter.breakdown: other_aggregation = "['Other']" if self._query_has_array_breakdown() else "'Other'" - if group_remaining and self._filter.breakdown_type in ["person", "event", "group"]: + if group_remaining and self._filter.breakdown_type in [ + "person", + "event", + "group", + ]: return f", if(has(%(breakdown_values)s, prop), prop, {other_aggregation}) as prop" else: # Cohorts don't have "Other" aggregation diff --git a/posthog/queries/funnels/funnel.py b/posthog/queries/funnels/funnel.py index 79f0c69898214..e1ac23f00d637 100644 --- a/posthog/queries/funnels/funnel.py +++ b/posthog/queries/funnels/funnel.py @@ -111,7 +111,6 @@ def get_comparison_cols(self, level_index: int, max_steps: int): return ", ".join(cols) def build_step_subquery(self, level_index: int, max_steps: int, event_names_alias: str = "events"): - if level_index >= max_steps: return f""" SELECT diff --git a/posthog/queries/funnels/funnel_event_query.py b/posthog/queries/funnels/funnel_event_query.py index be41ec9116bf8..dad407abffa0d 100644 --- a/posthog/queries/funnels/funnel_event_query.py +++ b/posthog/queries/funnels/funnel_event_query.py @@ -21,7 +21,9 @@ def get_query( # Aggregating by group if self._filter.aggregation_group_type_index is not None: aggregation_target = get_aggregation_target_field( - self._filter.aggregation_group_type_index, self.EVENT_TABLE_ALIAS, self._person_id_alias + self._filter.aggregation_group_type_index, + self.EVENT_TABLE_ALIAS, + self._person_id_alias, ) # Aggregating by HogQL diff --git a/posthog/queries/funnels/funnel_persons.py b/posthog/queries/funnels/funnel_persons.py index 5153473857eba..5cebef5fb7dcd 100644 --- a/posthog/queries/funnels/funnel_persons.py +++ b/posthog/queries/funnels/funnel_persons.py @@ -15,7 +15,11 @@ class ClickhouseFunnelActors(ClickhouseFunnel, ActorBaseQuery): def aggregation_group_type_index(self): return self._filter.aggregation_group_type_index - def actor_query(self, limit_actors: Optional[bool] = True, extra_fields: Optional[List[str]] = None): + def actor_query( + self, + limit_actors: Optional[bool] = True, + extra_fields: Optional[List[str]] = None, + ): extra_fields_string = ", ".join([self._get_timestamp_outer_select()] + (extra_fields or [])) return ( FUNNEL_PERSONS_BY_STEP_SQL.format( diff --git a/posthog/queries/funnels/funnel_strict.py b/posthog/queries/funnels/funnel_strict.py index dd5c4db883437..38b5d3a4c6a09 100644 --- a/posthog/queries/funnels/funnel_strict.py +++ b/posthog/queries/funnels/funnel_strict.py @@ -18,7 +18,6 @@ def get_query(self): """ def get_step_counts_query(self): - steps_per_person_query = self.get_step_counts_without_aggregation_query() max_steps = len(self._filter.entities) breakdown_clause = self._get_breakdown_prop() diff --git a/posthog/queries/funnels/funnel_strict_persons.py b/posthog/queries/funnels/funnel_strict_persons.py index 716c27608eb3b..cca6f8e598dc8 100644 --- a/posthog/queries/funnels/funnel_strict_persons.py +++ b/posthog/queries/funnels/funnel_strict_persons.py @@ -15,7 +15,11 @@ class ClickhouseFunnelStrictActors(ClickhouseFunnelStrict, ActorBaseQuery): def aggregation_group_type_index(self): return self._filter.aggregation_group_type_index - def actor_query(self, limit_actors: Optional[bool] = True, extra_fields: Optional[List[str]] = None): + def actor_query( + self, + limit_actors: Optional[bool] = True, + extra_fields: Optional[List[str]] = None, + ): extra_fields_string = ", ".join([self._get_timestamp_outer_select()] + (extra_fields or [])) return ( FUNNEL_PERSONS_BY_STEP_SQL.format( diff --git a/posthog/queries/funnels/funnel_trends.py b/posthog/queries/funnels/funnel_trends.py index 3c6bbca8b79a1..d67b24ae78bbc 100644 --- a/posthog/queries/funnels/funnel_trends.py +++ b/posthog/queries/funnels/funnel_trends.py @@ -55,13 +55,11 @@ class ClickhouseFunnelTrends(ClickhouseFunnelBase): QUERY_TYPE = "funnel_trends" def __init__(self, filter: Filter, team: Team) -> None: - super().__init__(filter, team) self.funnel_order = get_funnel_order_class(filter)(filter, team) def _exec_query(self): - return self._summarize_data(super()._exec_query()) def get_step_counts_without_aggregation_query( @@ -97,7 +95,11 @@ def get_query(self) -> str: # Expects multiple rows for same person, first event time, steps taken. self.params.update(self.funnel_order.params) - reached_from_step_count_condition, reached_to_step_count_condition, _ = self.get_steps_reached_conditions() + ( + reached_from_step_count_condition, + reached_to_step_count_condition, + _, + ) = self.get_steps_reached_conditions() interval_func = get_interval_func_ch(self._filter.interval) if self._filter.date_from is None: @@ -157,10 +159,13 @@ def get_steps_reached_conditions(self) -> Tuple[str, str, str]: reached_to_step_count_condition = f"steps_completed >= {to_step+1}" # Those who dropped off did_not_reach_to_step_count_condition = f"{reached_from_step_count_condition} AND steps_completed < {to_step+1}" - return reached_from_step_count_condition, reached_to_step_count_condition, did_not_reach_to_step_count_condition + return ( + reached_from_step_count_condition, + reached_to_step_count_condition, + did_not_reach_to_step_count_condition, + ) def _summarize_data(self, results): - breakdown_clause = self._get_breakdown_prop() summary = [] @@ -185,7 +190,6 @@ def _summarize_data(self, results): return summary def _format_results(self, summary): - if self._filter.breakdown: grouper = lambda row: row["breakdown_value"] sorted_data = sorted(summary, key=grouper) diff --git a/posthog/queries/funnels/funnel_trends_persons.py b/posthog/queries/funnels/funnel_trends_persons.py index 46f2a9f1bf7df..0f4391eb041e4 100644 --- a/posthog/queries/funnels/funnel_trends_persons.py +++ b/posthog/queries/funnels/funnel_trends_persons.py @@ -50,7 +50,11 @@ def actor_query(self, limit_actors: Optional[bool] = True): # Expects multiple rows for same person, first event time, steps taken. self.params.update(self.funnel_order.params) - _, reached_to_step_count_condition, did_not_reach_to_step_count_condition = self.get_steps_reached_conditions() + ( + _, + reached_to_step_count_condition, + did_not_reach_to_step_count_condition, + ) = self.get_steps_reached_conditions() return ( FUNNEL_PERSONS_BY_STEP_SQL.format( diff --git a/posthog/queries/funnels/funnel_unordered.py b/posthog/queries/funnels/funnel_unordered.py index e72abdf40c220..ac3a6d939b09f 100644 --- a/posthog/queries/funnels/funnel_unordered.py +++ b/posthog/queries/funnels/funnel_unordered.py @@ -54,7 +54,6 @@ def _serialize_step( } def get_query(self): - max_steps = len(self._filter.entities) for exclusion in self._filter.exclusions: @@ -70,7 +69,6 @@ def get_query(self): """ def get_step_counts_query(self): - max_steps = len(self._filter.entities) union_query = self.get_step_counts_without_aggregation_query() @@ -140,7 +138,6 @@ def _get_step_times(self, max_steps: int): return f", {formatted}" if formatted else "" def get_sorting_condition(self, max_steps: int): - conditions = [] event_times_elements = [] diff --git a/posthog/queries/funnels/funnel_unordered_persons.py b/posthog/queries/funnels/funnel_unordered_persons.py index 972a8b9ec7f7c..334798c990208 100644 --- a/posthog/queries/funnels/funnel_unordered_persons.py +++ b/posthog/queries/funnels/funnel_unordered_persons.py @@ -22,7 +22,11 @@ def _get_funnel_person_step_events(self): return ", array() as matching_events" return "" - def actor_query(self, limit_actors: Optional[bool] = True, extra_fields: Optional[List[str]] = None): + def actor_query( + self, + limit_actors: Optional[bool] = True, + extra_fields: Optional[List[str]] = None, + ): extra_fields_string = ", ".join([self._get_timestamp_outer_select()] + (extra_fields or [])) return ( FUNNEL_PERSONS_BY_STEP_SQL.format( diff --git a/posthog/queries/funnels/test/breakdown_cases.py b/posthog/queries/funnels/test/breakdown_cases.py index 0a1e46331f90e..9f8fd74785f63 100644 --- a/posthog/queries/funnels/test/breakdown_cases.py +++ b/posthog/queries/funnels/test/breakdown_cases.py @@ -8,7 +8,11 @@ from posthog.models.filters import Filter from posthog.queries.breakdown_props import ALL_USERS_COHORT_ID from posthog.queries.funnels.funnel_unordered import ClickhouseFunnelUnordered -from posthog.test.base import APIBaseTest, also_test_with_materialized_columns, snapshot_clickhouse_queries +from posthog.test.base import ( + APIBaseTest, + also_test_with_materialized_columns, + snapshot_clickhouse_queries, +) from posthog.test.test_journeys import journeys_for @@ -46,7 +50,10 @@ def funnel_result(step: FunnelStepResult, order: int) -> Dict[str, Any]: "breakdown": step.breakdown, "breakdown_value": step.breakdown, **( - {"action_id": None, "name": f"Completed {order+1} step{'s' if order > 0 else ''}"} + { + "action_id": None, + "name": f"Completed {order+1} step{'s' if order > 0 else ''}", + } if Funnel == ClickhouseFunnelUnordered else {} ), @@ -60,9 +67,12 @@ def funnel_result(step: FunnelStepResult, order: int) -> Dict[str, Any]: @also_test_with_materialized_columns(["$browser", "$browser_version"]) def test_funnel_step_multi_property_breakdown_event(self): - filters = { - "events": [{"id": "sign up", "order": 0}, {"id": "play movie", "order": 1}, {"id": "buy", "order": 2}], + "events": [ + {"id": "sign up", "order": 0}, + {"id": "play movie", "order": 1}, + {"id": "buy", "order": 2}, + ], "insight": INSIGHT_FUNNELS, "date_from": "2020-01-01", "date_to": "2020-01-08", @@ -79,36 +89,60 @@ def test_funnel_step_multi_property_breakdown_event(self): { "event": "sign up", "timestamp": datetime(2020, 1, 1, 12), - "properties": {"key": "val", "$browser": "Chrome", "$browser_version": 95}, + "properties": { + "key": "val", + "$browser": "Chrome", + "$browser_version": 95, + }, }, { "event": "play movie", "timestamp": datetime(2020, 1, 1, 13), - "properties": {"key": "val", "$browser": "Chrome", "$browser_version": 95}, + "properties": { + "key": "val", + "$browser": "Chrome", + "$browser_version": 95, + }, }, { "event": "buy", "timestamp": datetime(2020, 1, 1, 15), - "properties": {"key": "val", "$browser": "Chrome", "$browser_version": 95}, + "properties": { + "key": "val", + "$browser": "Chrome", + "$browser_version": 95, + }, }, ], "person2": [ { "event": "sign up", "timestamp": datetime(2020, 1, 2, 14), - "properties": {"key": "val", "$browser": "Safari", "$browser_version": 15}, + "properties": { + "key": "val", + "$browser": "Safari", + "$browser_version": 15, + }, }, { "event": "play movie", "timestamp": datetime(2020, 1, 2, 16), - "properties": {"key": "val", "$browser": "Safari", "$browser_version": 15}, + "properties": { + "key": "val", + "$browser": "Safari", + "$browser_version": 15, + }, }, ], "person3": [ { "event": "sign up", "timestamp": datetime(2020, 1, 2, 14), - "properties": {"key": "val", "$browser": "Safari", "$browser_version": 14}, + "properties": { + "key": "val", + "$browser": "Safari", + "$browser_version": 14, + }, } ], } @@ -126,7 +160,10 @@ def test_funnel_step_multi_property_breakdown_event(self): ], ) - self.assertCountEqual(self._get_actor_ids_at_step(filter, 1, ["Safari", "14"]), [people["person3"].uuid]) + self.assertCountEqual( + self._get_actor_ids_at_step(filter, 1, ["Safari", "14"]), + [people["person3"].uuid], + ) self.assertCountEqual(self._get_actor_ids_at_step(filter, 2, ["Safari", "14"]), []) self._assert_funnel_breakdown_result_is_correct( @@ -143,8 +180,14 @@ def test_funnel_step_multi_property_breakdown_event(self): FunnelStepResult(name="buy", breakdown=["Safari", "15"], count=0), ], ) - self.assertCountEqual(self._get_actor_ids_at_step(filter, 1, ["Safari", "15"]), [people["person2"].uuid]) - self.assertCountEqual(self._get_actor_ids_at_step(filter, 2, ["Safari", "15"]), [people["person2"].uuid]) + self.assertCountEqual( + self._get_actor_ids_at_step(filter, 1, ["Safari", "15"]), + [people["person2"].uuid], + ) + self.assertCountEqual( + self._get_actor_ids_at_step(filter, 2, ["Safari", "15"]), + [people["person2"].uuid], + ) self._assert_funnel_breakdown_result_is_correct( result[2], @@ -166,14 +209,23 @@ def test_funnel_step_multi_property_breakdown_event(self): ), ], ) - self.assertCountEqual(self._get_actor_ids_at_step(filter, 1, ["Chrome", "95"]), [people["person1"].uuid]) - self.assertCountEqual(self._get_actor_ids_at_step(filter, 2, ["Chrome", "95"]), [people["person1"].uuid]) + self.assertCountEqual( + self._get_actor_ids_at_step(filter, 1, ["Chrome", "95"]), + [people["person1"].uuid], + ) + self.assertCountEqual( + self._get_actor_ids_at_step(filter, 2, ["Chrome", "95"]), + [people["person1"].uuid], + ) @also_test_with_materialized_columns(["$browser"]) def test_funnel_step_breakdown_event_with_string_only_breakdown(self): - filters = { - "events": [{"id": "sign up", "order": 0}, {"id": "play movie", "order": 1}, {"id": "buy", "order": 2}], + "events": [ + {"id": "sign up", "order": 0}, + {"id": "play movie", "order": 1}, + {"id": "buy", "order": 2}, + ], "insight": INSIGHT_FUNNELS, "date_from": "2020-01-01", "date_to": "2020-01-08", @@ -248,8 +300,14 @@ def test_funnel_step_breakdown_event_with_string_only_breakdown(self): ), ], ) - self.assertCountEqual(self._get_actor_ids_at_step(filter, 1, "Chrome"), [people["person1"].uuid]) - self.assertCountEqual(self._get_actor_ids_at_step(filter, 2, "Chrome"), [people["person1"].uuid]) + self.assertCountEqual( + self._get_actor_ids_at_step(filter, 1, "Chrome"), + [people["person1"].uuid], + ) + self.assertCountEqual( + self._get_actor_ids_at_step(filter, 2, "Chrome"), + [people["person1"].uuid], + ) self._assert_funnel_breakdown_result_is_correct( result[1], [ @@ -266,15 +324,22 @@ def test_funnel_step_breakdown_event_with_string_only_breakdown(self): ) self.assertCountEqual( - self._get_actor_ids_at_step(filter, 1, "Safari"), [people["person2"].uuid, people["person3"].uuid] + self._get_actor_ids_at_step(filter, 1, "Safari"), + [people["person2"].uuid, people["person3"].uuid], + ) + self.assertCountEqual( + self._get_actor_ids_at_step(filter, 2, "Safari"), + [people["person2"].uuid], ) - self.assertCountEqual(self._get_actor_ids_at_step(filter, 2, "Safari"), [people["person2"].uuid]) @also_test_with_materialized_columns(["$browser"]) def test_funnel_step_breakdown_event(self): - filters = { - "events": [{"id": "sign up", "order": 0}, {"id": "play movie", "order": 1}, {"id": "buy", "order": 2}], + "events": [ + {"id": "sign up", "order": 0}, + {"id": "play movie", "order": 1}, + {"id": "buy", "order": 2}, + ], "insight": INSIGHT_FUNNELS, "date_from": "2020-01-01", "date_to": "2020-01-08", @@ -349,8 +414,14 @@ def test_funnel_step_breakdown_event(self): ), ], ) - self.assertCountEqual(self._get_actor_ids_at_step(filter, 1, "Chrome"), [people["person1"].uuid]) - self.assertCountEqual(self._get_actor_ids_at_step(filter, 2, "Chrome"), [people["person1"].uuid]) + self.assertCountEqual( + self._get_actor_ids_at_step(filter, 1, "Chrome"), + [people["person1"].uuid], + ) + self.assertCountEqual( + self._get_actor_ids_at_step(filter, 2, "Chrome"), + [people["person1"].uuid], + ) self._assert_funnel_breakdown_result_is_correct( result[1], @@ -368,15 +439,22 @@ def test_funnel_step_breakdown_event(self): ) self.assertCountEqual( - self._get_actor_ids_at_step(filter, 1, "Safari"), [people["person2"].uuid, people["person3"].uuid] + self._get_actor_ids_at_step(filter, 1, "Safari"), + [people["person2"].uuid, people["person3"].uuid], + ) + self.assertCountEqual( + self._get_actor_ids_at_step(filter, 2, "Safari"), + [people["person2"].uuid], ) - self.assertCountEqual(self._get_actor_ids_at_step(filter, 2, "Safari"), [people["person2"].uuid]) @also_test_with_materialized_columns(["$browser"]) def test_funnel_step_breakdown_event_with_other(self): - filters = { - "events": [{"id": "sign up", "order": 0}, {"id": "play movie", "order": 1}, {"id": "buy", "order": 2}], + "events": [ + {"id": "sign up", "order": 0}, + {"id": "play movie", "order": 1}, + {"id": "buy", "order": 2}, + ], "insight": INSIGHT_FUNNELS, "date_from": "2020-01-01", "date_to": "2020-01-08", @@ -391,16 +469,28 @@ def test_funnel_step_breakdown_event_with_other(self): events_by_person = { "person1": [ - {"event": "sign up", "timestamp": datetime(2020, 1, 1, 12), "properties": {"$browser": "Chrome"}}, + { + "event": "sign up", + "timestamp": datetime(2020, 1, 1, 12), + "properties": {"$browser": "Chrome"}, + }, { "event": "play movie", "timestamp": datetime(2020, 1, 1, 13), "properties": {"$browser": "Chrome"}, }, - {"event": "buy", "timestamp": datetime(2020, 1, 1, 15), "properties": {"$browser": "Chrome"}}, + { + "event": "buy", + "timestamp": datetime(2020, 1, 1, 15), + "properties": {"$browser": "Chrome"}, + }, ], "person2": [ - {"event": "sign up", "timestamp": datetime(2020, 1, 2, 14), "properties": {"$browser": "Safari"}}, + { + "event": "sign up", + "timestamp": datetime(2020, 1, 2, 14), + "properties": {"$browser": "Safari"}, + }, { "event": "play movie", "timestamp": datetime(2020, 1, 2, 16), @@ -408,10 +498,18 @@ def test_funnel_step_breakdown_event_with_other(self): }, ], "person3": [ - {"event": "sign up", "timestamp": datetime(2020, 1, 2, 14), "properties": {"$browser": "Safari"}} + { + "event": "sign up", + "timestamp": datetime(2020, 1, 2, 14), + "properties": {"$browser": "Safari"}, + } ], "person4": [ - {"event": "sign up", "timestamp": datetime(2020, 1, 2, 14), "properties": {"$browser": "random"}} + { + "event": "sign up", + "timestamp": datetime(2020, 1, 2, 14), + "properties": {"$browser": "random"}, + } ], "person5": [ { @@ -443,9 +541,13 @@ def test_funnel_step_breakdown_event_with_other(self): ) self.assertCountEqual( - self._get_actor_ids_at_step(filter, 1, "Safari"), [people["person2"].uuid, people["person3"].uuid] + self._get_actor_ids_at_step(filter, 1, "Safari"), + [people["person2"].uuid, people["person3"].uuid], + ) + self.assertCountEqual( + self._get_actor_ids_at_step(filter, 2, "Safari"), + [people["person2"].uuid], ) - self.assertCountEqual(self._get_actor_ids_at_step(filter, 2, "Safari"), [people["person2"].uuid]) self._assert_funnel_breakdown_result_is_correct( result[0], @@ -470,15 +572,25 @@ def test_funnel_step_breakdown_event_with_other(self): self.assertCountEqual( self._get_actor_ids_at_step(filter, 1, "Other"), - [people["person1"].uuid, people["person4"].uuid, people["person5"].uuid], + [ + people["person1"].uuid, + people["person4"].uuid, + people["person5"].uuid, + ], + ) + self.assertCountEqual( + self._get_actor_ids_at_step(filter, 2, "Other"), + [people["person1"].uuid], ) - self.assertCountEqual(self._get_actor_ids_at_step(filter, 2, "Other"), [people["person1"].uuid]) @also_test_with_materialized_columns(["$browser"]) def test_funnel_step_breakdown_event_no_type(self): - filters = { - "events": [{"id": "sign up", "order": 0}, {"id": "play movie", "order": 1}, {"id": "buy", "order": 2}], + "events": [ + {"id": "sign up", "order": 0}, + {"id": "play movie", "order": 1}, + {"id": "buy", "order": 2}, + ], "insight": INSIGHT_FUNNELS, "date_from": "2020-01-01", "date_to": "2020-01-08", @@ -491,16 +603,28 @@ def test_funnel_step_breakdown_event_no_type(self): events_by_person = { "person1": [ - {"event": "sign up", "timestamp": datetime(2020, 1, 1, 12), "properties": {"$browser": "Chrome"}}, + { + "event": "sign up", + "timestamp": datetime(2020, 1, 1, 12), + "properties": {"$browser": "Chrome"}, + }, { "event": "play movie", "timestamp": datetime(2020, 1, 1, 13), "properties": {"$browser": "Chrome"}, }, - {"event": "buy", "timestamp": datetime(2020, 1, 1, 15), "properties": {"$browser": "Chrome"}}, + { + "event": "buy", + "timestamp": datetime(2020, 1, 1, 15), + "properties": {"$browser": "Chrome"}, + }, ], "person2": [ - {"event": "sign up", "timestamp": datetime(2020, 1, 2, 14), "properties": {"$browser": "Safari"}}, + { + "event": "sign up", + "timestamp": datetime(2020, 1, 2, 14), + "properties": {"$browser": "Safari"}, + }, { "event": "play movie", "timestamp": datetime(2020, 1, 2, 16), @@ -508,7 +632,11 @@ def test_funnel_step_breakdown_event_no_type(self): }, ], "person3": [ - {"event": "sign up", "timestamp": datetime(2020, 1, 2, 14), "properties": {"$browser": "Safari"}} + { + "event": "sign up", + "timestamp": datetime(2020, 1, 2, 14), + "properties": {"$browser": "Safari"}, + } ], } @@ -537,8 +665,14 @@ def test_funnel_step_breakdown_event_no_type(self): ], ) - self.assertCountEqual(self._get_actor_ids_at_step(filter, 1, "Chrome"), [people["person1"].uuid]) - self.assertCountEqual(self._get_actor_ids_at_step(filter, 2, "Chrome"), [people["person1"].uuid]) + self.assertCountEqual( + self._get_actor_ids_at_step(filter, 1, "Chrome"), + [people["person1"].uuid], + ) + self.assertCountEqual( + self._get_actor_ids_at_step(filter, 2, "Chrome"), + [people["person1"].uuid], + ) self._assert_funnel_breakdown_result_is_correct( result[1], @@ -556,15 +690,22 @@ def test_funnel_step_breakdown_event_no_type(self): ) self.assertCountEqual( - self._get_actor_ids_at_step(filter, 1, "Safari"), [people["person2"].uuid, people["person3"].uuid] + self._get_actor_ids_at_step(filter, 1, "Safari"), + [people["person2"].uuid, people["person3"].uuid], + ) + self.assertCountEqual( + self._get_actor_ids_at_step(filter, 2, "Safari"), + [people["person2"].uuid], ) - self.assertCountEqual(self._get_actor_ids_at_step(filter, 2, "Safari"), [people["person2"].uuid]) @also_test_with_materialized_columns(person_properties=["$browser"]) def test_funnel_step_breakdown_person(self): - filters = { - "events": [{"id": "sign up", "order": 0}, {"id": "play movie", "order": 1}, {"id": "buy", "order": 2}], + "events": [ + {"id": "sign up", "order": 0}, + {"id": "play movie", "order": 1}, + {"id": "buy", "order": 2}, + ], "insight": INSIGHT_FUNNELS, "date_from": "2020-01-01", "date_to": "2020-01-08", @@ -576,8 +717,16 @@ def test_funnel_step_breakdown_person(self): filter = Filter(data=filters) funnel = Funnel(filter, self.team) - person1 = _create_person(distinct_ids=["person1"], team_id=self.team.pk, properties={"$browser": "Chrome"}) - person2 = _create_person(distinct_ids=["person2"], team_id=self.team.pk, properties={"$browser": "Safari"}) + person1 = _create_person( + distinct_ids=["person1"], + team_id=self.team.pk, + properties={"$browser": "Chrome"}, + ) + person2 = _create_person( + distinct_ids=["person2"], + team_id=self.team.pk, + properties={"$browser": "Safari"}, + ) peoples_journeys = { "person1": [ @@ -638,9 +787,12 @@ def test_funnel_step_breakdown_person(self): @also_test_with_materialized_columns(["some_breakdown_val"]) def test_funnel_step_breakdown_limit(self): - filters = { - "events": [{"id": "sign up", "order": 0}, {"id": "play movie", "order": 1}, {"id": "buy", "order": 2}], + "events": [ + {"id": "sign up", "order": 0}, + {"id": "play movie", "order": 1}, + {"id": "buy", "order": 2}, + ], "insight": INSIGHT_FUNNELS, "date_from": "2020-01-01", "date_to": "2020-01-08", @@ -684,9 +836,12 @@ def test_funnel_step_breakdown_limit(self): @also_test_with_materialized_columns(["some_breakdown_val"]) def test_funnel_step_custom_breakdown_limit_with_nulls(self): - filters = { - "events": [{"id": "sign up", "order": 0}, {"id": "play movie", "order": 1}, {"id": "buy", "order": 2}], + "events": [ + {"id": "sign up", "order": 0}, + {"id": "play movie", "order": 1}, + {"id": "buy", "order": 2}, + ], "insight": INSIGHT_FUNNELS, "date_from": "2020-01-01", "date_to": "2020-01-08", @@ -738,9 +893,12 @@ def test_funnel_step_custom_breakdown_limit_with_nulls(self): @also_test_with_materialized_columns(["some_breakdown_val"]) def test_funnel_step_custom_breakdown_limit_with_nulls_included(self): - filters = { - "events": [{"id": "sign up", "order": 0}, {"id": "play movie", "order": 1}, {"id": "buy", "order": 2}], + "events": [ + {"id": "sign up", "order": 0}, + {"id": "play movie", "order": 1}, + {"id": "buy", "order": 2}, + ], "insight": INSIGHT_FUNNELS, "date_from": "2020-01-01", "date_to": "2020-01-08", @@ -797,7 +955,6 @@ def test_funnel_step_custom_breakdown_limit_with_nulls_included(self): @also_test_with_materialized_columns(["$browser"]) def test_funnel_step_breakdown_event_single_person_multiple_breakdowns(self): - filters = { "events": [{"id": "sign up", "order": 0}], "insight": INSIGHT_FUNNELS, @@ -816,11 +973,27 @@ def test_funnel_step_breakdown_event_single_person_multiple_breakdowns(self): # event events_by_person = { "person1": [ - {"event": "sign up", "timestamp": datetime(2020, 1, 1, 12), "properties": {"$browser": "Chrome"}}, - {"event": "sign up", "timestamp": datetime(2020, 1, 1, 13), "properties": {"$browser": "Safari"}}, - {"event": "sign up", "timestamp": datetime(2020, 1, 2, 14), "properties": {"$browser": "Mac"}}, + { + "event": "sign up", + "timestamp": datetime(2020, 1, 1, 12), + "properties": {"$browser": "Chrome"}, + }, + { + "event": "sign up", + "timestamp": datetime(2020, 1, 1, 13), + "properties": {"$browser": "Safari"}, + }, + { + "event": "sign up", + "timestamp": datetime(2020, 1, 2, 14), + "properties": {"$browser": "Mac"}, + }, # mixed property type! - {"event": "sign up", "timestamp": datetime(2020, 1, 2, 15), "properties": {"$browser": 0}}, + { + "event": "sign up", + "timestamp": datetime(2020, 1, 2, 15), + "properties": {"$browser": 0}, + }, ] } people = journeys_for(events_by_person, self.team) @@ -835,27 +1008,38 @@ def test_funnel_step_breakdown_event_single_person_multiple_breakdowns(self): self.assertCountEqual(self._get_actor_ids_at_step(filter, 1, "0"), [people["person1"].uuid]) self._assert_funnel_breakdown_result_is_correct( - result[1], [FunnelStepResult(name="sign up", count=1, breakdown=["Chrome"])] + result[1], + [FunnelStepResult(name="sign up", count=1, breakdown=["Chrome"])], ) - self.assertCountEqual(self._get_actor_ids_at_step(filter, 1, "Chrome"), [people["person1"].uuid]) + self.assertCountEqual( + self._get_actor_ids_at_step(filter, 1, "Chrome"), + [people["person1"].uuid], + ) self._assert_funnel_breakdown_result_is_correct( - result[2], [FunnelStepResult(name="sign up", count=1, breakdown=["Mac"])] + result[2], + [FunnelStepResult(name="sign up", count=1, breakdown=["Mac"])], ) self.assertCountEqual(self._get_actor_ids_at_step(filter, 1, "Mac"), [people["person1"].uuid]) self._assert_funnel_breakdown_result_is_correct( - result[3], [FunnelStepResult(name="sign up", count=1, breakdown=["Safari"])] + result[3], + [FunnelStepResult(name="sign up", count=1, breakdown=["Safari"])], ) - self.assertCountEqual(self._get_actor_ids_at_step(filter, 1, "Safari"), [people["person1"].uuid]) + self.assertCountEqual( + self._get_actor_ids_at_step(filter, 1, "Safari"), + [people["person1"].uuid], + ) def test_funnel_step_breakdown_event_single_person_events_with_multiple_properties(self): - filters = { - "events": [{"id": "sign up", "order": 0}, {"id": "play movie", "order": 1}], + "events": [ + {"id": "sign up", "order": 0}, + {"id": "play movie", "order": 1}, + ], "insight": INSIGHT_FUNNELS, "date_from": "2020-01-01", "date_to": "2020-01-08", @@ -907,7 +1091,10 @@ def test_funnel_step_breakdown_event_single_person_events_with_multiple_properti ], ) - self.assertCountEqual(self._get_actor_ids_at_step(filter, 1, "Chrome"), [people["person1"].uuid]) + self.assertCountEqual( + self._get_actor_ids_at_step(filter, 1, "Chrome"), + [people["person1"].uuid], + ) self.assertCountEqual(self._get_actor_ids_at_step(filter, 2, "Chrome"), []) self._assert_funnel_breakdown_result_is_correct( @@ -924,14 +1111,27 @@ def test_funnel_step_breakdown_event_single_person_events_with_multiple_properti ], ) - self.assertCountEqual(self._get_actor_ids_at_step(filter, 1, "Safari"), [people["person1"].uuid]) - self.assertCountEqual(self._get_actor_ids_at_step(filter, 2, "Safari"), [people["person1"].uuid]) + self.assertCountEqual( + self._get_actor_ids_at_step(filter, 1, "Safari"), + [people["person1"].uuid], + ) + self.assertCountEqual( + self._get_actor_ids_at_step(filter, 2, "Safari"), + [people["person1"].uuid], + ) @also_test_with_materialized_columns(person_properties=["key"], verify_no_jsonextract=False) def test_funnel_cohort_breakdown(self): # This caused some issues with SQL parsing - _create_person(distinct_ids=[f"person1"], team_id=self.team.pk, properties={"key": "value"}) - people = journeys_for({"person1": [{"event": "sign up", "timestamp": datetime(2020, 1, 2, 12)}]}, self.team) + _create_person( + distinct_ids=[f"person1"], + team_id=self.team.pk, + properties={"key": "value"}, + ) + people = journeys_for( + {"person1": [{"event": "sign up", "timestamp": datetime(2020, 1, 2, 12)}]}, + self.team, + ) cohort = Cohort.objects.create( team=self.team, @@ -939,7 +1139,11 @@ def test_funnel_cohort_breakdown(self): groups=[{"properties": [{"key": "key", "value": "value", "type": "person"}]}], ) filters = { - "events": [{"id": "sign up", "order": 0}, {"id": "play movie", "order": 1}, {"id": "buy", "order": 2}], + "events": [ + {"id": "sign up", "order": 0}, + {"id": "play movie", "order": 1}, + {"id": "buy", "order": 2}, + ], "insight": INSIGHT_FUNNELS, "date_from": "2020-01-01", "date_to": "2020-01-08", @@ -958,15 +1162,25 @@ def test_funnel_cohort_breakdown(self): self.assertEqual(result[0][0]["breakdown"], "all users") self.assertEqual(len(result[1]), 3) self.assertEqual(result[1][0]["breakdown"], "test_cohort") - self.assertCountEqual(self._get_actor_ids_at_step(filter, 1, cohort.pk), [people["person1"].uuid]) + self.assertCountEqual( + self._get_actor_ids_at_step(filter, 1, cohort.pk), + [people["person1"].uuid], + ) self.assertCountEqual(self._get_actor_ids_at_step(filter, 2, cohort.pk), []) - self.assertCountEqual(self._get_actor_ids_at_step(filter, 1, ALL_USERS_COHORT_ID), [people["person1"].uuid]) + self.assertCountEqual( + self._get_actor_ids_at_step(filter, 1, ALL_USERS_COHORT_ID), + [people["person1"].uuid], + ) self.assertCountEqual(self._get_actor_ids_at_step(filter, 2, ALL_USERS_COHORT_ID), []) # non array filters = { - "events": [{"id": "sign up", "order": 0}, {"id": "play movie", "order": 1}, {"id": "buy", "order": 2}], + "events": [ + {"id": "sign up", "order": 0}, + {"id": "play movie", "order": 1}, + {"id": "buy", "order": 2}, + ], "insight": INSIGHT_FUNNELS, "date_from": "2020-01-01", "date_to": "2020-01-08", @@ -981,11 +1195,13 @@ def test_funnel_cohort_breakdown(self): self.assertEqual(len(result[0]), 3) self.assertEqual(result[0][0]["breakdown"], "test_cohort") self.assertEqual(result[0][0]["breakdown_value"], cohort.pk) - self.assertCountEqual(self._get_actor_ids_at_step(filter, 1, cohort.pk), [people["person1"].uuid]) + self.assertCountEqual( + self._get_actor_ids_at_step(filter, 1, cohort.pk), + [people["person1"].uuid], + ) self.assertCountEqual(self._get_actor_ids_at_step(filter, 2, cohort.pk), []) def test_basic_funnel_default_funnel_days_breakdown_event(self): - events_by_person = { "user_1": [ { @@ -1047,7 +1263,11 @@ def test_basic_funnel_default_funnel_days_breakdown_event(self): self._assert_funnel_breakdown_result_is_correct( result[0], [ - FunnelStepResult(name="user signed up", count=1, breakdown=["https://posthog.com/docs/x"]), + FunnelStepResult( + name="user signed up", + count=1, + breakdown=["https://posthog.com/docs/x"], + ), FunnelStepResult( name="paid", count=1, @@ -1135,7 +1355,6 @@ def test_basic_funnel_default_funnel_days_breakdown_action(self): ) def test_funnel_step_breakdown_with_first_touch_attribution(self): - filters = { "events": [{"id": "sign up", "order": 0}, {"id": "buy", "order": 1}], "insight": INSIGHT_FUNNELS, @@ -1153,21 +1372,41 @@ def test_funnel_step_breakdown_with_first_touch_attribution(self): # event events_by_person = { "person1": [ - {"event": "sign up", "timestamp": datetime(2020, 1, 1, 12), "properties": {"$browser": "Chrome"}}, + { + "event": "sign up", + "timestamp": datetime(2020, 1, 1, 12), + "properties": {"$browser": "Chrome"}, + }, {"event": "buy", "timestamp": datetime(2020, 1, 1, 13)}, ], "person2": [ {"event": "sign up", "timestamp": datetime(2020, 1, 1, 13)}, - {"event": "buy", "timestamp": datetime(2020, 1, 2, 13), "properties": {"$browser": "Safari"}}, + { + "event": "buy", + "timestamp": datetime(2020, 1, 2, 13), + "properties": {"$browser": "Safari"}, + }, ], "person3": [ - {"event": "sign up", "timestamp": datetime(2020, 1, 2, 14), "properties": {"$browser": "Mac"}}, + { + "event": "sign up", + "timestamp": datetime(2020, 1, 2, 14), + "properties": {"$browser": "Mac"}, + }, {"event": "buy", "timestamp": datetime(2020, 1, 2, 15)}, ], "person4": [ - {"event": "sign up", "timestamp": datetime(2020, 1, 2, 15), "properties": {"$browser": 0}}, + { + "event": "sign up", + "timestamp": datetime(2020, 1, 2, 15), + "properties": {"$browser": 0}, + }, # first touch means alakazam is disregarded - {"event": "buy", "timestamp": datetime(2020, 1, 2, 16), "properties": {"$browser": "alakazam"}}, + { + "event": "buy", + "timestamp": datetime(2020, 1, 2, 16), + "properties": {"$browser": "alakazam"}, + }, ], # no properties dude, represented by '' "person5": [ @@ -1187,7 +1426,11 @@ def test_funnel_step_breakdown_with_first_touch_attribution(self): [ FunnelStepResult(name="sign up", breakdown=[""], count=1), FunnelStepResult( - name="buy", breakdown=[""], count=1, average_conversion_time=3600, median_conversion_time=3600 + name="buy", + breakdown=[""], + count=1, + average_conversion_time=3600, + median_conversion_time=3600, ), ], ) @@ -1199,7 +1442,11 @@ def test_funnel_step_breakdown_with_first_touch_attribution(self): [ FunnelStepResult(name="sign up", breakdown=["0"], count=1), FunnelStepResult( - name="buy", breakdown=["0"], count=1, average_conversion_time=3600, median_conversion_time=3600 + name="buy", + breakdown=["0"], + count=1, + average_conversion_time=3600, + median_conversion_time=3600, ), ], ) @@ -1220,7 +1467,10 @@ def test_funnel_step_breakdown_with_first_touch_attribution(self): ], ) - self.assertCountEqual(self._get_actor_ids_at_step(filter, 1, "Chrome"), [people["person1"].uuid]) + self.assertCountEqual( + self._get_actor_ids_at_step(filter, 1, "Chrome"), + [people["person1"].uuid], + ) self._assert_funnel_breakdown_result_is_correct( result[3], @@ -1252,10 +1502,12 @@ def test_funnel_step_breakdown_with_first_touch_attribution(self): ], ) - self.assertCountEqual(self._get_actor_ids_at_step(filter, 1, "Safari"), [people["person2"].uuid]) + self.assertCountEqual( + self._get_actor_ids_at_step(filter, 1, "Safari"), + [people["person2"].uuid], + ) def test_funnel_step_breakdown_with_last_touch_attribution(self): - filters = { "events": [{"id": "sign up", "order": 0}, {"id": "buy", "order": 1}], "insight": INSIGHT_FUNNELS, @@ -1273,21 +1525,41 @@ def test_funnel_step_breakdown_with_last_touch_attribution(self): # event events_by_person = { "person1": [ - {"event": "sign up", "timestamp": datetime(2020, 1, 1, 12), "properties": {"$browser": "Chrome"}}, + { + "event": "sign up", + "timestamp": datetime(2020, 1, 1, 12), + "properties": {"$browser": "Chrome"}, + }, {"event": "buy", "timestamp": datetime(2020, 1, 1, 13)}, ], "person2": [ {"event": "sign up", "timestamp": datetime(2020, 1, 1, 13)}, - {"event": "buy", "timestamp": datetime(2020, 1, 2, 13), "properties": {"$browser": "Safari"}}, + { + "event": "buy", + "timestamp": datetime(2020, 1, 2, 13), + "properties": {"$browser": "Safari"}, + }, ], "person3": [ - {"event": "sign up", "timestamp": datetime(2020, 1, 2, 14), "properties": {"$browser": "Mac"}}, + { + "event": "sign up", + "timestamp": datetime(2020, 1, 2, 14), + "properties": {"$browser": "Mac"}, + }, {"event": "buy", "timestamp": datetime(2020, 1, 2, 15)}, ], "person4": [ - {"event": "sign up", "timestamp": datetime(2020, 1, 2, 15), "properties": {"$browser": 0}}, + { + "event": "sign up", + "timestamp": datetime(2020, 1, 2, 15), + "properties": {"$browser": 0}, + }, # last touch means 0 is disregarded - {"event": "buy", "timestamp": datetime(2020, 1, 2, 16), "properties": {"$browser": "Alakazam"}}, + { + "event": "buy", + "timestamp": datetime(2020, 1, 2, 16), + "properties": {"$browser": "Alakazam"}, + }, ], # no properties dude, represented by '' "person5": [ @@ -1307,7 +1579,11 @@ def test_funnel_step_breakdown_with_last_touch_attribution(self): [ FunnelStepResult(name="sign up", breakdown=[""], count=1), FunnelStepResult( - name="buy", breakdown=[""], count=1, average_conversion_time=3600, median_conversion_time=3600 + name="buy", + breakdown=[""], + count=1, + average_conversion_time=3600, + median_conversion_time=3600, ), ], ) @@ -1328,7 +1604,10 @@ def test_funnel_step_breakdown_with_last_touch_attribution(self): ], ) - self.assertCountEqual(self._get_actor_ids_at_step(filter, 1, "Alakazam"), [people["person4"].uuid]) + self.assertCountEqual( + self._get_actor_ids_at_step(filter, 1, "Alakazam"), + [people["person4"].uuid], + ) self._assert_funnel_breakdown_result_is_correct( result[2], @@ -1344,7 +1623,10 @@ def test_funnel_step_breakdown_with_last_touch_attribution(self): ], ) - self.assertCountEqual(self._get_actor_ids_at_step(filter, 1, "Chrome"), [people["person1"].uuid]) + self.assertCountEqual( + self._get_actor_ids_at_step(filter, 1, "Chrome"), + [people["person1"].uuid], + ) self._assert_funnel_breakdown_result_is_correct( result[3], @@ -1376,10 +1658,12 @@ def test_funnel_step_breakdown_with_last_touch_attribution(self): ], ) - self.assertCountEqual(self._get_actor_ids_at_step(filter, 1, "Safari"), [people["person2"].uuid]) + self.assertCountEqual( + self._get_actor_ids_at_step(filter, 1, "Safari"), + [people["person2"].uuid], + ) def test_funnel_step_breakdown_with_step_attribution(self): - filters = { "events": [{"id": "sign up", "order": 0}, {"id": "buy", "order": 1}], "insight": INSIGHT_FUNNELS, @@ -1398,21 +1682,41 @@ def test_funnel_step_breakdown_with_step_attribution(self): # event events_by_person = { "person1": [ - {"event": "sign up", "timestamp": datetime(2020, 1, 1, 12), "properties": {"$browser": "Chrome"}}, + { + "event": "sign up", + "timestamp": datetime(2020, 1, 1, 12), + "properties": {"$browser": "Chrome"}, + }, {"event": "buy", "timestamp": datetime(2020, 1, 1, 13)}, ], "person2": [ {"event": "sign up", "timestamp": datetime(2020, 1, 1, 13)}, - {"event": "buy", "timestamp": datetime(2020, 1, 2, 13), "properties": {"$browser": "Safari"}}, + { + "event": "buy", + "timestamp": datetime(2020, 1, 2, 13), + "properties": {"$browser": "Safari"}, + }, ], "person3": [ - {"event": "sign up", "timestamp": datetime(2020, 1, 2, 14), "properties": {"$browser": "Mac"}}, + { + "event": "sign up", + "timestamp": datetime(2020, 1, 2, 14), + "properties": {"$browser": "Mac"}, + }, {"event": "buy", "timestamp": datetime(2020, 1, 2, 15)}, ], "person4": [ - {"event": "sign up", "timestamp": datetime(2020, 1, 2, 15), "properties": {"$browser": 0}}, + { + "event": "sign up", + "timestamp": datetime(2020, 1, 2, 15), + "properties": {"$browser": 0}, + }, # step attribution means alakazam is valid when step = 1 - {"event": "buy", "timestamp": datetime(2020, 1, 2, 16), "properties": {"$browser": "alakazam"}}, + { + "event": "buy", + "timestamp": datetime(2020, 1, 2, 16), + "properties": {"$browser": "alakazam"}, + }, ], } people = journeys_for(events_by_person, self.team) @@ -1427,7 +1731,11 @@ def test_funnel_step_breakdown_with_step_attribution(self): [ FunnelStepResult(name="sign up", breakdown=[""], count=1), FunnelStepResult( - name="buy", breakdown=[""], count=1, average_conversion_time=86400, median_conversion_time=86400 + name="buy", + breakdown=[""], + count=1, + average_conversion_time=86400, + median_conversion_time=86400, ), ], ) @@ -1439,7 +1747,11 @@ def test_funnel_step_breakdown_with_step_attribution(self): [ FunnelStepResult(name="sign up", breakdown=["0"], count=1), FunnelStepResult( - name="buy", breakdown=["0"], count=1, average_conversion_time=3600, median_conversion_time=3600 + name="buy", + breakdown=["0"], + count=1, + average_conversion_time=3600, + median_conversion_time=3600, ), ], ) @@ -1460,7 +1772,10 @@ def test_funnel_step_breakdown_with_step_attribution(self): ], ) - self.assertCountEqual(self._get_actor_ids_at_step(filter, 1, "Chrome"), [people["person1"].uuid]) + self.assertCountEqual( + self._get_actor_ids_at_step(filter, 1, "Chrome"), + [people["person1"].uuid], + ) self._assert_funnel_breakdown_result_is_correct( result[3], @@ -1479,7 +1794,6 @@ def test_funnel_step_breakdown_with_step_attribution(self): self.assertCountEqual(self._get_actor_ids_at_step(filter, 1, "Mac"), [people["person3"].uuid]) def test_funnel_step_breakdown_with_step_one_attribution(self): - filters = { "events": [{"id": "sign up", "order": 0}, {"id": "buy", "order": 1}], "insight": INSIGHT_FUNNELS, @@ -1498,21 +1812,41 @@ def test_funnel_step_breakdown_with_step_one_attribution(self): # event events_by_person = { "person1": [ - {"event": "sign up", "timestamp": datetime(2020, 1, 1, 12), "properties": {"$browser": "Chrome"}}, + { + "event": "sign up", + "timestamp": datetime(2020, 1, 1, 12), + "properties": {"$browser": "Chrome"}, + }, {"event": "buy", "timestamp": datetime(2020, 1, 1, 13)}, ], "person2": [ {"event": "sign up", "timestamp": datetime(2020, 1, 1, 13)}, - {"event": "buy", "timestamp": datetime(2020, 1, 2, 13), "properties": {"$browser": "Safari"}}, + { + "event": "buy", + "timestamp": datetime(2020, 1, 2, 13), + "properties": {"$browser": "Safari"}, + }, ], "person3": [ - {"event": "sign up", "timestamp": datetime(2020, 1, 2, 14), "properties": {"$browser": "Mac"}}, + { + "event": "sign up", + "timestamp": datetime(2020, 1, 2, 14), + "properties": {"$browser": "Mac"}, + }, {"event": "buy", "timestamp": datetime(2020, 1, 2, 15)}, ], "person4": [ - {"event": "sign up", "timestamp": datetime(2020, 1, 2, 15), "properties": {"$browser": 0}}, + { + "event": "sign up", + "timestamp": datetime(2020, 1, 2, 15), + "properties": {"$browser": 0}, + }, # step attribution means alakazam is valid when step = 1 - {"event": "buy", "timestamp": datetime(2020, 1, 2, 16), "properties": {"$browser": "alakazam"}}, + { + "event": "buy", + "timestamp": datetime(2020, 1, 2, 16), + "properties": {"$browser": "alakazam"}, + }, ], } people = journeys_for(events_by_person, self.team) @@ -1528,13 +1862,18 @@ def test_funnel_step_breakdown_with_step_one_attribution(self): [ FunnelStepResult(name="sign up", breakdown=[""], count=2), FunnelStepResult( - name="buy", breakdown=[""], count=2, average_conversion_time=3600, median_conversion_time=3600 + name="buy", + breakdown=[""], + count=2, + average_conversion_time=3600, + median_conversion_time=3600, ), ], ) self.assertCountEqual( - self._get_actor_ids_at_step(filter, 1, ""), [people["person1"].uuid, people["person3"].uuid] + self._get_actor_ids_at_step(filter, 1, ""), + [people["person1"].uuid, people["person3"].uuid], ) self._assert_funnel_breakdown_result_is_correct( @@ -1551,7 +1890,10 @@ def test_funnel_step_breakdown_with_step_one_attribution(self): ], ) - self.assertCountEqual(self._get_actor_ids_at_step(filter, 1, "Safari"), [people["person2"].uuid]) + self.assertCountEqual( + self._get_actor_ids_at_step(filter, 1, "Safari"), + [people["person2"].uuid], + ) self._assert_funnel_breakdown_result_is_correct( result[2], @@ -1567,10 +1909,12 @@ def test_funnel_step_breakdown_with_step_one_attribution(self): ], ) - self.assertCountEqual(self._get_actor_ids_at_step(filter, 1, "alakazam"), [people["person4"].uuid]) + self.assertCountEqual( + self._get_actor_ids_at_step(filter, 1, "alakazam"), + [people["person4"].uuid], + ) def test_funnel_step_multiple_breakdown_with_first_touch_attribution(self): - filters = { "events": [{"id": "sign up", "order": 0}, {"id": "buy", "order": 1}], "insight": INSIGHT_FUNNELS, @@ -1604,8 +1948,16 @@ def test_funnel_step_multiple_breakdown_with_first_touch_attribution(self): }, ], "person3": [ - {"event": "sign up", "timestamp": datetime(2020, 1, 2, 14), "properties": {"$browser": "Mac"}}, - {"event": "buy", "timestamp": datetime(2020, 1, 2, 15), "properties": {"$version": "no-mac"}}, + { + "event": "sign up", + "timestamp": datetime(2020, 1, 2, 14), + "properties": {"$browser": "Mac"}, + }, + { + "event": "buy", + "timestamp": datetime(2020, 1, 2, 15), + "properties": {"$version": "no-mac"}, + }, ], "person4": [ { @@ -1613,7 +1965,11 @@ def test_funnel_step_multiple_breakdown_with_first_touch_attribution(self): "timestamp": datetime(2020, 1, 2, 15), "properties": {"$browser": 0, "$version": 0}, }, - {"event": "buy", "timestamp": datetime(2020, 1, 2, 16), "properties": {"$browser": "alakazam"}}, + { + "event": "buy", + "timestamp": datetime(2020, 1, 2, 16), + "properties": {"$browser": "alakazam"}, + }, ], # no properties dude, represented by '' "person5": [ @@ -1642,7 +1998,10 @@ def test_funnel_step_multiple_breakdown_with_first_touch_attribution(self): ], ) - self.assertCountEqual(self._get_actor_ids_at_step(filter, 1, ["", ""]), [people["person5"].uuid]) + self.assertCountEqual( + self._get_actor_ids_at_step(filter, 1, ["", ""]), + [people["person5"].uuid], + ) self._assert_funnel_breakdown_result_is_correct( result[1], @@ -1657,7 +2016,10 @@ def test_funnel_step_multiple_breakdown_with_first_touch_attribution(self): ), ], ) - self.assertCountEqual(self._get_actor_ids_at_step(filter, 1, ["0", "0"]), [people["person4"].uuid]) + self.assertCountEqual( + self._get_actor_ids_at_step(filter, 1, ["0", "0"]), + [people["person4"].uuid], + ) self._assert_funnel_breakdown_result_is_correct( result[2], @@ -1673,7 +2035,10 @@ def test_funnel_step_multiple_breakdown_with_first_touch_attribution(self): ], ) - self.assertCountEqual(self._get_actor_ids_at_step(filter, 1, ["Chrome", "xyz"]), [people["person1"].uuid]) + self.assertCountEqual( + self._get_actor_ids_at_step(filter, 1, ["Chrome", "xyz"]), + [people["person1"].uuid], + ) self._assert_funnel_breakdown_result_is_correct( result[3], @@ -1689,7 +2054,10 @@ def test_funnel_step_multiple_breakdown_with_first_touch_attribution(self): ], ) - self.assertCountEqual(self._get_actor_ids_at_step(filter, 1, ["Mac", ""]), [people["person3"].uuid]) + self.assertCountEqual( + self._get_actor_ids_at_step(filter, 1, ["Mac", ""]), + [people["person3"].uuid], + ) self._assert_funnel_breakdown_result_is_correct( result[4], @@ -1705,10 +2073,12 @@ def test_funnel_step_multiple_breakdown_with_first_touch_attribution(self): ], ) - self.assertCountEqual(self._get_actor_ids_at_step(filter, 1, ["Safari", "xyz"]), [people["person2"].uuid]) + self.assertCountEqual( + self._get_actor_ids_at_step(filter, 1, ["Safari", "xyz"]), + [people["person2"].uuid], + ) def test_funnel_step_multiple_breakdown_with_first_touch_attribution_incomplete_funnel(self): - filters = { "events": [{"id": "sign up", "order": 0}, {"id": "buy", "order": 1}], "insight": INSIGHT_FUNNELS, @@ -1742,7 +2112,11 @@ def test_funnel_step_multiple_breakdown_with_first_touch_attribution_incomplete_ }, ], "person3": [ - {"event": "sign up", "timestamp": datetime(2020, 1, 2, 14), "properties": {"$browser": "Mac"}}, + { + "event": "sign up", + "timestamp": datetime(2020, 1, 2, 14), + "properties": {"$browser": "Mac"}, + }, # {"event": "buy", "timestamp": datetime(2020, 1, 2, 15), "properties": {"$version": "no-mac"}}, ], "person4": [ @@ -1780,7 +2154,10 @@ def test_funnel_step_multiple_breakdown_with_first_touch_attribution_incomplete_ ], ) - self.assertCountEqual(self._get_actor_ids_at_step(filter, 1, ["", ""]), [people["person5"].uuid]) + self.assertCountEqual( + self._get_actor_ids_at_step(filter, 1, ["", ""]), + [people["person5"].uuid], + ) self._assert_funnel_breakdown_result_is_correct( result[1], @@ -1789,7 +2166,10 @@ def test_funnel_step_multiple_breakdown_with_first_touch_attribution_incomplete_ FunnelStepResult(name="buy", breakdown=["0", "0"], count=0), ], ) - self.assertCountEqual(self._get_actor_ids_at_step(filter, 1, ["0", "0"]), [people["person4"].uuid]) + self.assertCountEqual( + self._get_actor_ids_at_step(filter, 1, ["0", "0"]), + [people["person4"].uuid], + ) self._assert_funnel_breakdown_result_is_correct( result[2], @@ -1805,7 +2185,10 @@ def test_funnel_step_multiple_breakdown_with_first_touch_attribution_incomplete_ ], ) - self.assertCountEqual(self._get_actor_ids_at_step(filter, 1, ["Chrome", "xyz"]), [people["person1"].uuid]) + self.assertCountEqual( + self._get_actor_ids_at_step(filter, 1, ["Chrome", "xyz"]), + [people["person1"].uuid], + ) self._assert_funnel_breakdown_result_is_correct( result[3], @@ -1815,7 +2198,10 @@ def test_funnel_step_multiple_breakdown_with_first_touch_attribution_incomplete_ ], ) - self.assertCountEqual(self._get_actor_ids_at_step(filter, 1, ["Mac", ""]), [people["person3"].uuid]) + self.assertCountEqual( + self._get_actor_ids_at_step(filter, 1, ["Mac", ""]), + [people["person3"].uuid], + ) self.assertCountEqual(self._get_actor_ids_at_step(filter, 2, ["Mac", ""]), []) self._assert_funnel_breakdown_result_is_correct( @@ -1832,10 +2218,12 @@ def test_funnel_step_multiple_breakdown_with_first_touch_attribution_incomplete_ ], ) - self.assertCountEqual(self._get_actor_ids_at_step(filter, 1, ["Safari", "xyz"]), [people["person2"].uuid]) + self.assertCountEqual( + self._get_actor_ids_at_step(filter, 1, ["Safari", "xyz"]), + [people["person2"].uuid], + ) def test_funnel_step_breakdown_with_step_one_attribution_incomplete_funnel(self): - filters = { "events": [{"id": "sign up", "order": 0}, {"id": "buy", "order": 1}], "insight": INSIGHT_FUNNELS, @@ -1854,7 +2242,11 @@ def test_funnel_step_breakdown_with_step_one_attribution_incomplete_funnel(self) # event events_by_person = { "person1": [ - {"event": "sign up", "timestamp": datetime(2020, 1, 1, 12), "properties": {"$browser": "Chrome"}}, + { + "event": "sign up", + "timestamp": datetime(2020, 1, 1, 12), + "properties": {"$browser": "Chrome"}, + }, {"event": "buy", "timestamp": datetime(2020, 1, 1, 13)}, ], "person2": [ @@ -1862,13 +2254,25 @@ def test_funnel_step_breakdown_with_step_one_attribution_incomplete_funnel(self) # {"event": "buy", "timestamp": datetime(2020, 1, 2, 13), "properties": {"$browser": "Safari"}} ], "person3": [ - {"event": "sign up", "timestamp": datetime(2020, 1, 2, 14), "properties": {"$browser": "Mac"}}, + { + "event": "sign up", + "timestamp": datetime(2020, 1, 2, 14), + "properties": {"$browser": "Mac"}, + }, # {"event": "buy", "timestamp": datetime(2020, 1, 2, 15)} ], "person4": [ - {"event": "sign up", "timestamp": datetime(2020, 1, 2, 15), "properties": {"$browser": 0}}, + { + "event": "sign up", + "timestamp": datetime(2020, 1, 2, 15), + "properties": {"$browser": 0}, + }, # step attribution means alakazam is valid when step = 1 - {"event": "buy", "timestamp": datetime(2020, 1, 2, 16), "properties": {"$browser": "alakazam"}}, + { + "event": "buy", + "timestamp": datetime(2020, 1, 2, 16), + "properties": {"$browser": "alakazam"}, + }, ], } people = journeys_for(events_by_person, self.team) @@ -1885,7 +2289,11 @@ def test_funnel_step_breakdown_with_step_one_attribution_incomplete_funnel(self) [ FunnelStepResult(name="sign up", breakdown=[""], count=1), FunnelStepResult( - name="buy", breakdown=[""], count=1, average_conversion_time=3600, median_conversion_time=3600 + name="buy", + breakdown=[""], + count=1, + average_conversion_time=3600, + median_conversion_time=3600, ), ], ) @@ -1906,10 +2314,12 @@ def test_funnel_step_breakdown_with_step_one_attribution_incomplete_funnel(self) ], ) - self.assertCountEqual(self._get_actor_ids_at_step(filter, 1, "alakazam"), [people["person4"].uuid]) + self.assertCountEqual( + self._get_actor_ids_at_step(filter, 1, "alakazam"), + [people["person4"].uuid], + ) def test_funnel_step_non_array_breakdown_with_step_one_attribution_incomplete_funnel(self): - filters = { "events": [{"id": "sign up", "order": 0}, {"id": "buy", "order": 1}], "insight": INSIGHT_FUNNELS, @@ -1928,7 +2338,11 @@ def test_funnel_step_non_array_breakdown_with_step_one_attribution_incomplete_fu # event events_by_person = { "person1": [ - {"event": "sign up", "timestamp": datetime(2020, 1, 1, 12), "properties": {"$browser": "Chrome"}}, + { + "event": "sign up", + "timestamp": datetime(2020, 1, 1, 12), + "properties": {"$browser": "Chrome"}, + }, {"event": "buy", "timestamp": datetime(2020, 1, 1, 13)}, ], "person2": [ @@ -1936,13 +2350,25 @@ def test_funnel_step_non_array_breakdown_with_step_one_attribution_incomplete_fu # {"event": "buy", "timestamp": datetime(2020, 1, 2, 13), "properties": {"$browser": "Safari"}} ], "person3": [ - {"event": "sign up", "timestamp": datetime(2020, 1, 2, 14), "properties": {"$browser": "Mac"}}, + { + "event": "sign up", + "timestamp": datetime(2020, 1, 2, 14), + "properties": {"$browser": "Mac"}, + }, # {"event": "buy", "timestamp": datetime(2020, 1, 2, 15)} ], "person4": [ - {"event": "sign up", "timestamp": datetime(2020, 1, 2, 15), "properties": {"$browser": 0}}, + { + "event": "sign up", + "timestamp": datetime(2020, 1, 2, 15), + "properties": {"$browser": 0}, + }, # step attribution means alakazam is valid when step = 1 - {"event": "buy", "timestamp": datetime(2020, 1, 2, 16), "properties": {"$browser": "alakazam"}}, + { + "event": "buy", + "timestamp": datetime(2020, 1, 2, 16), + "properties": {"$browser": "alakazam"}, + }, ], } people = journeys_for(events_by_person, self.team) @@ -1959,7 +2385,11 @@ def test_funnel_step_non_array_breakdown_with_step_one_attribution_incomplete_fu [ FunnelStepResult(name="sign up", breakdown=[""], count=1), FunnelStepResult( - name="buy", breakdown=[""], count=1, average_conversion_time=3600, median_conversion_time=3600 + name="buy", + breakdown=[""], + count=1, + average_conversion_time=3600, + median_conversion_time=3600, ), ], ) @@ -1980,7 +2410,10 @@ def test_funnel_step_non_array_breakdown_with_step_one_attribution_incomplete_fu ], ) - self.assertCountEqual(self._get_actor_ids_at_step(filter, 1, "alakazam"), [people["person4"].uuid]) + self.assertCountEqual( + self._get_actor_ids_at_step(filter, 1, "alakazam"), + [people["person4"].uuid], + ) @snapshot_clickhouse_queries def test_funnel_step_multiple_breakdown_snapshot(self): @@ -2019,8 +2452,16 @@ def test_funnel_step_multiple_breakdown_snapshot(self): }, ], "person3": [ - {"event": "sign up", "timestamp": datetime(2020, 1, 2, 14), "properties": {"$browser": "Mac"}}, - {"event": "buy", "timestamp": datetime(2020, 1, 2, 15), "properties": {"$version": "no-mac"}}, + { + "event": "sign up", + "timestamp": datetime(2020, 1, 2, 14), + "properties": {"$browser": "Mac"}, + }, + { + "event": "buy", + "timestamp": datetime(2020, 1, 2, 15), + "properties": {"$version": "no-mac"}, + }, ], "person4": [ { @@ -2028,7 +2469,11 @@ def test_funnel_step_multiple_breakdown_snapshot(self): "timestamp": datetime(2020, 1, 2, 15), "properties": {"$browser": 0, "$version": 0}, }, - {"event": "buy", "timestamp": datetime(2020, 1, 2, 16), "properties": {"$browser": "alakazam"}}, + { + "event": "buy", + "timestamp": datetime(2020, 1, 2, 16), + "properties": {"$browser": "alakazam"}, + }, ], # no properties dude, represented by '' "person5": [ @@ -2050,7 +2495,11 @@ def test_funnel_breakdown_correct_breakdown_props_are_chosen(self): filters = { "events": [ {"id": "sign up", "order": 0}, - {"id": "buy", "properties": [{"type": "event", "key": "$version", "value": "xyz"}], "order": 1}, + { + "id": "buy", + "properties": [{"type": "event", "key": "$version", "value": "xyz"}], + "order": 1, + }, ], "insight": INSIGHT_FUNNELS, "date_from": "2020-01-01", @@ -2072,7 +2521,11 @@ def test_funnel_breakdown_correct_breakdown_props_are_chosen(self): "timestamp": datetime(2020, 1, 1, 12), "properties": {"$browser": "Chrome", "$version": "xyz"}, }, - {"event": "buy", "timestamp": datetime(2020, 1, 1, 13), "properties": {"$browser": "Chrome"}}, + { + "event": "buy", + "timestamp": datetime(2020, 1, 1, 13), + "properties": {"$browser": "Chrome"}, + }, # discarded at step 1 because doesn't meet criteria ], "person2": [ @@ -2084,7 +2537,11 @@ def test_funnel_breakdown_correct_breakdown_props_are_chosen(self): }, ], "person3": [ - {"event": "sign up", "timestamp": datetime(2020, 1, 2, 14), "properties": {"$browser": "Mac"}}, + { + "event": "sign up", + "timestamp": datetime(2020, 1, 2, 14), + "properties": {"$browser": "Mac"}, + }, { "event": "buy", "timestamp": datetime(2020, 1, 2, 15), @@ -2104,7 +2561,10 @@ def test_funnel_breakdown_correct_breakdown_props_are_chosen(self): self.assertEqual(len(result), 4) - self.assertCountEqual([res[0]["breakdown"] for res in result], [["Mac"], ["Chrome"], ["Safari"], [""]]) + self.assertCountEqual( + [res[0]["breakdown"] for res in result], + [["Mac"], ["Chrome"], ["Safari"], [""]], + ) @snapshot_clickhouse_queries def test_funnel_breakdown_correct_breakdown_props_are_chosen_for_step(self): @@ -2113,7 +2573,11 @@ def test_funnel_breakdown_correct_breakdown_props_are_chosen_for_step(self): filters = { "events": [ {"id": "sign up", "order": 0}, - {"id": "buy", "properties": [{"type": "event", "key": "$version", "value": "xyz"}], "order": 1}, + { + "id": "buy", + "properties": [{"type": "event", "key": "$version", "value": "xyz"}], + "order": 1, + }, ], "insight": INSIGHT_FUNNELS, "date_from": "2020-01-01", @@ -2136,7 +2600,11 @@ def test_funnel_breakdown_correct_breakdown_props_are_chosen_for_step(self): "timestamp": datetime(2020, 1, 1, 12), "properties": {"$browser": "Chrome", "$version": "xyz"}, }, - {"event": "buy", "timestamp": datetime(2020, 1, 1, 13), "properties": {"$browser": "Chrome"}}, + { + "event": "buy", + "timestamp": datetime(2020, 1, 1, 13), + "properties": {"$browser": "Chrome"}, + }, # discarded because doesn't meet criteria ], "person2": [ @@ -2148,7 +2616,11 @@ def test_funnel_breakdown_correct_breakdown_props_are_chosen_for_step(self): }, ], "person3": [ - {"event": "sign up", "timestamp": datetime(2020, 1, 2, 14), "properties": {"$browser": "Mac"}}, + { + "event": "sign up", + "timestamp": datetime(2020, 1, 2, 14), + "properties": {"$browser": "Mac"}, + }, { "event": "buy", "timestamp": datetime(2020, 1, 2, 15), @@ -2188,7 +2660,6 @@ def assert_funnel_results_equal(left: List[Dict[str, Any]], right: List[Dict[str """ def _filter(steps: List[Dict[str, Any]]) -> List[Dict[str, Any]]: - return [{**step, "converted_people_url": None, "dropped_people_url": None} for step in steps] assert len(left) == len(right) @@ -2200,5 +2671,8 @@ def _filter(steps: List[Dict[str, Any]]) -> List[Dict[str, Any]]: try: assert item[key] == other[key] except AssertionError as e: - e.args += (f"failed comparing ${key}", f'Got "{item[key]}" and "{other[key]}"') + e.args += ( + f"failed comparing ${key}", + f'Got "{item[key]}" and "{other[key]}"', + ) raise diff --git a/posthog/queries/funnels/test/conversion_time_cases.py b/posthog/queries/funnels/test/conversion_time_cases.py index 278dfd989a724..02e8167818373 100644 --- a/posthog/queries/funnels/test/conversion_time_cases.py +++ b/posthog/queries/funnels/test/conversion_time_cases.py @@ -34,14 +34,26 @@ def test_funnel_with_multiple_incomplete_tries(self): { "person1": [ # person1 completed funnel on 2021-05-01 - {"event": "user signed up", "timestamp": datetime(2021, 5, 1, 1)}, + { + "event": "user signed up", + "timestamp": datetime(2021, 5, 1, 1), + }, {"event": "$pageview", "timestamp": datetime(2021, 5, 1, 2)}, - {"event": "something else", "timestamp": datetime(2021, 5, 1, 3)}, + { + "event": "something else", + "timestamp": datetime(2021, 5, 1, 3), + }, # person1 completed part of funnel on 2021-05-03 and took 2 hours to convert - {"event": "user signed up", "timestamp": datetime(2021, 5, 3, 4)}, + { + "event": "user signed up", + "timestamp": datetime(2021, 5, 3, 4), + }, {"event": "$pageview", "timestamp": datetime(2021, 5, 3, 5)}, # person1 completed part of funnel on 2021-05-04 and took 3 hours to convert - {"event": "user signed up", "timestamp": datetime(2021, 5, 4, 7)}, + { + "event": "user signed up", + "timestamp": datetime(2021, 5, 4, 7), + }, {"event": "$pageview", "timestamp": datetime(2021, 5, 4, 10)}, ] }, @@ -61,7 +73,11 @@ def test_funnel_with_multiple_incomplete_tries(self): def test_funnel_step_conversion_times(self): filters = { - "events": [{"id": "sign up", "order": 0}, {"id": "play movie", "order": 1}, {"id": "buy", "order": 2}], + "events": [ + {"id": "sign up", "order": 0}, + {"id": "play movie", "order": 1}, + {"id": "buy", "order": 2}, + ], "insight": INSIGHT_FUNNELS, "date_from": "2020-01-01", "date_to": "2020-01-08", @@ -121,13 +137,27 @@ def test_funnel_times_with_different_conversion_windows(self): people = journeys_for( { "stopped_after_signup1": [ - {"event": "user signed up", "timestamp": datetime(2020, 1, 2, 14)}, + { + "event": "user signed up", + "timestamp": datetime(2020, 1, 2, 14), + }, {"event": "pageview", "timestamp": datetime(2020, 1, 2, 14, 5)}, ], - "stopped_after_signup2": [{"event": "user signed up", "timestamp": datetime(2020, 1, 2, 14, 3)}], + "stopped_after_signup2": [ + { + "event": "user signed up", + "timestamp": datetime(2020, 1, 2, 14, 3), + } + ], "stopped_after_signup3": [ - {"event": "user signed up", "timestamp": datetime(2020, 1, 2, 12)}, - {"event": "pageview", "timestamp": datetime(2020, 1, 2, 12, 15)}, + { + "event": "user signed up", + "timestamp": datetime(2020, 1, 2, 12), + }, + { + "event": "pageview", + "timestamp": datetime(2020, 1, 2, 12, 15), + }, ], }, self.team, @@ -149,7 +179,10 @@ def test_funnel_times_with_different_conversion_windows(self): self.assertCountEqual( self._get_actor_ids_at_step(filter, 2), - [people["stopped_after_signup1"].uuid, people["stopped_after_signup3"].uuid], + [ + people["stopped_after_signup1"].uuid, + people["stopped_after_signup3"].uuid, + ], ) filter = filter.shallow_clone({"funnel_window_interval": 5, "funnel_window_interval_unit": "minute"}) @@ -171,6 +204,9 @@ def test_funnel_times_with_different_conversion_windows(self): ], ) - self.assertCountEqual(self._get_actor_ids_at_step(filter, 2), [people["stopped_after_signup1"].uuid]) + self.assertCountEqual( + self._get_actor_ids_at_step(filter, 2), + [people["stopped_after_signup1"].uuid], + ) return TestFunnelConversionTime diff --git a/posthog/queries/funnels/test/test_breakdowns_by_current_url.py b/posthog/queries/funnels/test/test_breakdowns_by_current_url.py index 098d51ddecddd..bb6673387b64d 100644 --- a/posthog/queries/funnels/test/test_breakdowns_by_current_url.py +++ b/posthog/queries/funnels/test/test_breakdowns_by_current_url.py @@ -3,7 +3,11 @@ from posthog.models import Filter from posthog.queries.funnels import ClickhouseFunnel -from posthog.test.base import APIBaseTest, ClickhouseTestMixin, snapshot_clickhouse_queries +from posthog.test.base import ( + APIBaseTest, + ClickhouseTestMixin, + snapshot_clickhouse_queries, +) from posthog.test.test_journeys import journeys_for @@ -16,13 +20,19 @@ def setUp(self): { "event": "watched movie", "timestamp": datetime(2020, 1, 2, 12, 1), - "properties": {"$current_url": "https://example.com", "$pathname": ""}, + "properties": { + "$current_url": "https://example.com", + "$pathname": "", + }, }, # trailing question mark { "event": "watched movie", "timestamp": datetime(2020, 1, 2, 12, 2), - "properties": {"$current_url": "https://example.com?", "$pathname": "?"}, + "properties": { + "$current_url": "https://example.com?", + "$pathname": "?", + }, }, { "event": "terminate funnel", @@ -34,13 +44,19 @@ def setUp(self): { "event": "watched movie", "timestamp": datetime(2020, 1, 2, 12, 1), - "properties": {"$current_url": "https://example.com/", "$pathname": "/"}, + "properties": { + "$current_url": "https://example.com/", + "$pathname": "/", + }, }, # trailing hash { "event": "watched movie", "timestamp": datetime(2020, 1, 2, 12, 2), - "properties": {"$current_url": "https://example.com#", "$pathname": "#"}, + "properties": { + "$current_url": "https://example.com#", + "$pathname": "#", + }, }, { "event": "terminate funnel", @@ -52,7 +68,10 @@ def setUp(self): { "event": "watched movie", "timestamp": datetime(2020, 1, 2, 12, 1), - "properties": {"$current_url": "https://example.com/home", "$pathname": "/home"}, + "properties": { + "$current_url": "https://example.com/home", + "$pathname": "/home", + }, }, { "event": "terminate funnel", @@ -64,19 +83,28 @@ def setUp(self): { "event": "watched movie", "timestamp": datetime(2020, 1, 2, 12, 1), - "properties": {"$current_url": "https://example.com/home/", "$pathname": "/home/"}, + "properties": { + "$current_url": "https://example.com/home/", + "$pathname": "/home/", + }, }, # trailing hash { "event": "watched movie", "timestamp": datetime(2020, 1, 2, 12, 2), - "properties": {"$current_url": "https://example.com/home#", "$pathname": "/home#"}, + "properties": { + "$current_url": "https://example.com/home#", + "$pathname": "/home#", + }, }, # all the things { "event": "watched movie", "timestamp": datetime(2020, 1, 2, 12, 3), - "properties": {"$current_url": "https://example.com/home/?#", "$pathname": "/home/?#"}, + "properties": { + "$current_url": "https://example.com/home/?#", + "$pathname": "/home/?#", + }, }, { "event": "terminate funnel", @@ -92,7 +120,13 @@ def _run(self, extra: Dict = {}, events_extra: Dict = {}): Filter( data={ "events": [ - {"id": "watched movie", "name": "watched movie", "type": "events", "order": 0, **events_extra}, + { + "id": "watched movie", + "name": "watched movie", + "type": "events", + "order": 0, + **events_extra, + }, { "id": "terminate funnel", "name": "terminate funnel", @@ -115,12 +149,24 @@ def _run(self, extra: Dict = {}, events_extra: Dict = {}): @snapshot_clickhouse_queries def test_breakdown_by_pathname(self) -> None: - response = self._run({"breakdown": "$pathname", "breakdown_type": "event", "breakdown_normalize_url": True}) + response = self._run( + { + "breakdown": "$pathname", + "breakdown_type": "event", + "breakdown_normalize_url": True, + } + ) actual = [] for breakdown_value in response: for funnel_step in breakdown_value: - actual.append((funnel_step["name"], funnel_step["count"], funnel_step["breakdown"])) + actual.append( + ( + funnel_step["name"], + funnel_step["count"], + funnel_step["breakdown"], + ) + ) assert actual == [ ("watched movie", 2, ["/"]), @@ -131,12 +177,24 @@ def test_breakdown_by_pathname(self) -> None: @snapshot_clickhouse_queries def test_breakdown_by_current_url(self) -> None: - response = self._run({"breakdown": "$current_url", "breakdown_type": "event", "breakdown_normalize_url": True}) + response = self._run( + { + "breakdown": "$current_url", + "breakdown_type": "event", + "breakdown_normalize_url": True, + } + ) actual = [] for breakdown_value in response: for funnel_step in breakdown_value: - actual.append((funnel_step["name"], funnel_step["count"], funnel_step["breakdown"])) + actual.append( + ( + funnel_step["name"], + funnel_step["count"], + funnel_step["breakdown"], + ) + ) assert actual == [ ("watched movie", 2, ["https://example.com/home"]), diff --git a/posthog/queries/funnels/test/test_funnel.py b/posthog/queries/funnels/test/test_funnel.py index deddf642a4c50..334f0dc9c41c0 100644 --- a/posthog/queries/funnels/test/test_funnel.py +++ b/posthog/queries/funnels/test/test_funnel.py @@ -13,8 +13,13 @@ from posthog.models.filters import Filter from posthog.models.instance_setting import get_instance_setting from posthog.queries.funnels import ClickhouseFunnel, ClickhouseFunnelActors -from posthog.queries.funnels.test.breakdown_cases import assert_funnel_results_equal, funnel_breakdown_test_factory -from posthog.queries.funnels.test.conversion_time_cases import funnel_conversion_time_test_factory +from posthog.queries.funnels.test.breakdown_cases import ( + assert_funnel_results_equal, + funnel_breakdown_test_factory, +) +from posthog.queries.funnels.test.conversion_time_cases import ( + funnel_conversion_time_test_factory, +) from posthog.test.base import ( APIBaseTest, ClickhouseTestMixin, @@ -36,12 +41,26 @@ def _create_action(**kwargs): return action -class TestFunnelBreakdown(ClickhouseTestMixin, funnel_breakdown_test_factory(ClickhouseFunnel, ClickhouseFunnelActors, _create_event, _create_action, _create_person)): # type: ignore +class TestFunnelBreakdown( + ClickhouseTestMixin, + funnel_breakdown_test_factory( # type: ignore + ClickhouseFunnel, + ClickhouseFunnelActors, + _create_event, + _create_action, + _create_person, + ), +): maxDiff = None pass -class TestFunnelConversionTime(ClickhouseTestMixin, funnel_conversion_time_test_factory(ClickhouseFunnel, ClickhouseFunnelActors, _create_event, _create_person)): # type: ignore +class TestFunnelConversionTime( + ClickhouseTestMixin, + funnel_conversion_time_test_factory( # type: ignore + ClickhouseFunnel, ClickhouseFunnelActors, _create_event, _create_person + ), +): maxDiff = None pass @@ -96,10 +115,18 @@ def _single_step_funnel(self, properties=None, filters=None): def _basic_funnel(self, properties=None, filters=None): action_credit_card = Action.objects.create(team=self.team, name="paid") ActionStep.objects.create( - action=action_credit_card, event="$autocapture", tag_name="button", text="Pay $10" + action=action_credit_card, + event="$autocapture", + tag_name="button", + text="Pay $10", ) action_play_movie = Action.objects.create(team=self.team, name="watched movie") - ActionStep.objects.create(action=action_play_movie, event="$autocapture", tag_name="a", href="/movie") + ActionStep.objects.create( + action=action_play_movie, + event="$autocapture", + tag_name="a", + href="/movie", + ) if filters is None: filters = { @@ -157,7 +184,10 @@ def test_funnel_events(self): self._signup_event(distinct_id="stopped_after_pay") self._pay_event(distinct_id="stopped_after_pay") - person_factory(distinct_ids=["had_anonymous_id", "completed_movie"], team_id=self.team.pk) + person_factory( + distinct_ids=["had_anonymous_id", "completed_movie"], + team_id=self.team.pk, + ) self._signup_event(distinct_id="had_anonymous_id") self._pay_event(distinct_id="completed_movie") self._movie_event(distinct_id="completed_movie") @@ -193,18 +223,30 @@ def test_funnel_events_with_person_on_events_v2(self): # events stopped_after_signup_person_id = uuid.uuid4() person_factory(distinct_ids=["stopped_after_signup"], team_id=self.team.pk) - self._signup_event(distinct_id="stopped_after_signup", person_id=stopped_after_signup_person_id) + self._signup_event( + distinct_id="stopped_after_signup", + person_id=stopped_after_signup_person_id, + ) with freeze_time("2012-01-01T03:21:36.000Z"): stopped_after_pay_person_id = uuid.uuid4() person_factory(distinct_ids=["stopped_after_pay"], team_id=self.team.pk) - self._signup_event(distinct_id="stopped_after_pay", person_id=stopped_after_pay_person_id) + self._signup_event( + distinct_id="stopped_after_pay", + person_id=stopped_after_pay_person_id, + ) with freeze_time("2012-01-01T03:21:37.000Z"): - self._pay_event(distinct_id="stopped_after_pay", person_id=stopped_after_pay_person_id) + self._pay_event( + distinct_id="stopped_after_pay", + person_id=stopped_after_pay_person_id, + ) with freeze_time("2012-01-01T03:21:38.000Z"): had_anonymous_id_person_id = uuid.uuid4() - person_factory(distinct_ids=["had_anonymous_id", "completed_movie"], team_id=self.team.pk) + person_factory( + distinct_ids=["had_anonymous_id", "completed_movie"], + team_id=self.team.pk, + ) self._signup_event(distinct_id="had_anonymous_id", person_id=had_anonymous_id_person_id) with freeze_time("2012-01-01T03:21:39.000Z"): self._pay_event(distinct_id="completed_movie", person_id=had_anonymous_id_person_id) @@ -243,7 +285,12 @@ def test_funnel_events_with_person_on_events_v2(self): def test_funnel_with_messed_up_order(self): action_play_movie = Action.objects.create(team=self.team, name="watched movie") - ActionStep.objects.create(action=action_play_movie, event="$autocapture", tag_name="a", href="/movie") + ActionStep.objects.create( + action=action_play_movie, + event="$autocapture", + tag_name="a", + href="/movie", + ) funnel = self._basic_funnel( filters={ @@ -261,7 +308,10 @@ def test_funnel_with_messed_up_order(self): self._signup_event(distinct_id="stopped_after_pay") self._movie_event(distinct_id="completed_movie") - person_factory(distinct_ids=["had_anonymous_id", "completed_movie"], team_id=self.team.pk) + person_factory( + distinct_ids=["had_anonymous_id", "completed_movie"], + team_id=self.team.pk, + ) self._signup_event(distinct_id="had_anonymous_id") self._movie_event(distinct_id="completed_movie") @@ -323,7 +373,12 @@ def test_funnel_with_any_event(self): def test_funnel_with_new_entities_that_mess_up_order(self): action_play_movie = Action.objects.create(team=self.team, name="watched movie") - ActionStep.objects.create(action=action_play_movie, event="$autocapture", tag_name="a", href="/movie") + ActionStep.objects.create( + action=action_play_movie, + event="$autocapture", + tag_name="a", + href="/movie", + ) funnel = self._basic_funnel( filters={ @@ -345,7 +400,10 @@ def test_funnel_with_new_entities_that_mess_up_order(self): self._signup_event(distinct_id="stopped_after_pay") self._movie_event(distinct_id="completed_movie") - person_factory(distinct_ids=["had_anonymous_id", "completed_movie"], team_id=self.team.pk) + person_factory( + distinct_ids=["had_anonymous_id", "completed_movie"], + team_id=self.team.pk, + ) self._signup_event(distinct_id="had_anonymous_id") self._movie_event(distinct_id="completed_movie") @@ -405,10 +463,18 @@ def test_funnel_prop_filters(self): def test_funnel_prop_filters_per_entity(self): action_credit_card = Action.objects.create(team_id=self.team.pk, name="paid") ActionStep.objects.create( - action=action_credit_card, event="$autocapture", tag_name="button", text="Pay $10" + action=action_credit_card, + event="$autocapture", + tag_name="button", + text="Pay $10", ) action_play_movie = Action.objects.create(team_id=self.team.pk, name="watched movie") - ActionStep.objects.create(action=action_play_movie, event="$autocapture", tag_name="a", href="/movie") + ActionStep.objects.create( + action=action_play_movie, + event="$autocapture", + tag_name="a", + href="/movie", + ) filters = { "events": [ { @@ -417,7 +483,11 @@ def test_funnel_prop_filters_per_entity(self): "order": 0, "properties": [ {"key": "$browser", "value": "Safari"}, - {"key": "$browser", "operator": "is_not", "value": "Chrome"}, + { + "key": "$browser", + "operator": "is_not", + "value": "Chrome", + }, ], } ], @@ -440,7 +510,11 @@ def test_funnel_prop_filters_per_entity(self): funnel = self._basic_funnel(filters=filters) # events - person_factory(distinct_ids=["with_property"], team_id=self.team.pk, properties={"$browser": "Safari"}) + person_factory( + distinct_ids=["with_property"], + team_id=self.team.pk, + properties={"$browser": "Safari"}, + ) self._signup_event(distinct_id="with_property", properties={"$browser": "Safari"}) self._pay_event(distinct_id="with_property", properties={"$browser": "Safari"}) self._movie_event(distinct_id="with_property") @@ -466,17 +540,31 @@ def test_funnel_prop_filters_per_entity(self): def test_funnel_person_prop(self): action_credit_card = Action.objects.create(team_id=self.team.pk, name="paid") ActionStep.objects.create( - action=action_credit_card, event="$autocapture", tag_name="button", text="Pay $10" + action=action_credit_card, + event="$autocapture", + tag_name="button", + text="Pay $10", ) action_play_movie = Action.objects.create(team_id=self.team.pk, name="watched movie") - ActionStep.objects.create(action=action_play_movie, event="$autocapture", tag_name="a", href="/movie") + ActionStep.objects.create( + action=action_play_movie, + event="$autocapture", + tag_name="a", + href="/movie", + ) filters = { "events": [ { "id": "user signed up", "type": "events", "order": 0, - "properties": [{"key": "email", "value": "hello@posthog.com", "type": "person"}], + "properties": [ + { + "key": "email", + "value": "hello@posthog.com", + "type": "person", + } + ], } ], "actions": [ @@ -489,7 +577,9 @@ def test_funnel_person_prop(self): # events person_factory( - distinct_ids=["with_property"], team_id=self.team.pk, properties={"email": "hello@posthog.com"} + distinct_ids=["with_property"], + team_id=self.team.pk, + properties={"email": "hello@posthog.com"}, ) self._signup_event(distinct_id="with_property") self._pay_event(distinct_id="with_property") @@ -507,18 +597,34 @@ def test_funnel_multiple_actions(self): # This test prevents a regression person_factory(distinct_ids=["person1"], team_id=self.team.pk) event_factory(distinct_id="person1", event="event1", team=self.team) - event_factory(distinct_id="person1", event="event2", properties={"test_propX": "a"}, team=self.team) + event_factory( + distinct_id="person1", + event="event2", + properties={"test_propX": "a"}, + team=self.team, + ) action1 = Action.objects.create(team_id=self.team.pk, name="event2") - ActionStep.objects.create(action=action1, event="event2", properties=[{"key": "test_propX", "value": "a"}]) + ActionStep.objects.create( + action=action1, + event="event2", + properties=[{"key": "test_propX", "value": "a"}], + ) action2 = Action.objects.create(team_id=self.team.pk, name="event2") - ActionStep.objects.create(action=action2, event="event2", properties=[{"key": "test_propX", "value": "c"}]) + ActionStep.objects.create( + action=action2, + event="event2", + properties=[{"key": "test_propX", "value": "c"}], + ) result = Funnel( filter=Filter( data={ "events": [{"id": "event1", "order": 0}], - "actions": [{"id": action1.pk, "order": 1}, {"id": action2.pk, "order": 2}], + "actions": [ + {"id": action1.pk, "order": 1}, + {"id": action2.pk, "order": 2}, + ], "insight": INSIGHT_FUNNELS, "funnel_window_days": 14, } @@ -531,7 +637,11 @@ def test_funnel_multiple_actions(self): @also_test_with_materialized_columns(person_properties=["email"]) def test_funnel_filter_test_accounts(self): - person_factory(distinct_ids=["person1"], team_id=self.team.pk, properties={"email": "test@posthog.com"}) + person_factory( + distinct_ids=["person1"], + team_id=self.team.pk, + properties={"email": "test@posthog.com"}, + ) person_factory(distinct_ids=["person2"], team_id=self.team.pk) event_factory(distinct_id="person1", event="event1", team=self.team) event_factory(distinct_id="person2", event="event1", team=self.team) @@ -551,8 +661,16 @@ def test_funnel_filter_test_accounts(self): @also_test_with_materialized_columns(person_properties=["email"]) def test_funnel_with_entity_person_property_filters(self): - person_factory(distinct_ids=["person1"], team_id=self.team.pk, properties={"email": "test@posthog.com"}) - person_factory(distinct_ids=["person2"], team_id=self.team.pk, properties={"email": "another@example.com"}) + person_factory( + distinct_ids=["person1"], + team_id=self.team.pk, + properties={"email": "test@posthog.com"}, + ) + person_factory( + distinct_ids=["person2"], + team_id=self.team.pk, + properties={"email": "another@example.com"}, + ) person_factory(distinct_ids=["person3"], team_id=self.team.pk) event_factory(distinct_id="person1", event="event1", team=self.team) event_factory(distinct_id="person2", event="event1", team=self.team) @@ -566,7 +684,12 @@ def test_funnel_with_entity_person_property_filters(self): "id": "event1", "order": 0, "properties": [ - {"key": "email", "value": "is_set", "operator": "is_set", "type": "person"} + { + "key": "email", + "value": "is_set", + "operator": "is_set", + "type": "person", + } ], } ], @@ -580,8 +703,16 @@ def test_funnel_with_entity_person_property_filters(self): @also_test_with_materialized_columns(person_properties=["email"], verify_no_jsonextract=False) def test_funnel_filter_by_action_with_person_properties(self): - person_factory(distinct_ids=["person1"], team_id=self.team.pk, properties={"email": "test@posthog.com"}) - person_factory(distinct_ids=["person2"], team_id=self.team.pk, properties={"email": "another@example.com"}) + person_factory( + distinct_ids=["person1"], + team_id=self.team.pk, + properties={"email": "test@posthog.com"}, + ) + person_factory( + distinct_ids=["person2"], + team_id=self.team.pk, + properties={"email": "another@example.com"}, + ) person_factory(distinct_ids=["person3"], team_id=self.team.pk) event_factory(distinct_id="person1", event="event1", team=self.team) event_factory(distinct_id="person2", event="event1", team=self.team) @@ -591,7 +722,14 @@ def test_funnel_filter_by_action_with_person_properties(self): ActionStep.objects.create( action=action, event="event1", - properties=[{"key": "email", "value": "is_set", "operator": "is_set", "type": "person"}], + properties=[ + { + "key": "email", + "value": "is_set", + "operator": "is_set", + "type": "person", + } + ], ) result = Funnel( @@ -624,9 +762,17 @@ def test_basic_funnel_default_funnel_days(self): # event _create_person(distinct_ids=["user_1"], team_id=self.team.pk) _create_event( - team=self.team, event="user signed up", distinct_id="user_1", timestamp="2020-01-02T14:00:00Z" + team=self.team, + event="user signed up", + distinct_id="user_1", + timestamp="2020-01-02T14:00:00Z", + ) + _create_event( + team=self.team, + event="paid", + distinct_id="user_1", + timestamp="2020-01-10T14:00:00Z", ) - _create_event(team=self.team, event="paid", distinct_id="user_1", timestamp="2020-01-10T14:00:00Z") result = funnel.run() @@ -653,11 +799,23 @@ def test_basic_funnel_with_repeat_steps(self): person1_stopped_after_two_signups = _create_person( distinct_ids=["stopped_after_signup1"], team_id=self.team.pk ) - _create_event(team=self.team, event="user signed up", distinct_id="stopped_after_signup1") - _create_event(team=self.team, event="user signed up", distinct_id="stopped_after_signup1") + _create_event( + team=self.team, + event="user signed up", + distinct_id="stopped_after_signup1", + ) + _create_event( + team=self.team, + event="user signed up", + distinct_id="stopped_after_signup1", + ) person2_stopped_after_signup = _create_person(distinct_ids=["stopped_after_signup2"], team_id=self.team.pk) - _create_event(team=self.team, event="user signed up", distinct_id="stopped_after_signup2") + _create_event( + team=self.team, + event="user signed up", + distinct_id="stopped_after_signup2", + ) result = funnel.run() self.assertEqual(result[0]["name"], "user signed up") @@ -667,16 +825,27 @@ def test_basic_funnel_with_repeat_steps(self): self.assertCountEqual( self._get_actor_ids_at_step(filter, 1), - [person1_stopped_after_two_signups.uuid, person2_stopped_after_signup.uuid], + [ + person1_stopped_after_two_signups.uuid, + person2_stopped_after_signup.uuid, + ], ) - self.assertCountEqual(self._get_actor_ids_at_step(filter, 2), [person1_stopped_after_two_signups.uuid]) + self.assertCountEqual( + self._get_actor_ids_at_step(filter, 2), + [person1_stopped_after_two_signups.uuid], + ) @also_test_with_materialized_columns(["key"]) def test_basic_funnel_with_derivative_steps(self): filters = { "events": [ - {"id": "user signed up", "type": "events", "order": 0, "properties": {"key": "val"}}, + { + "id": "user signed up", + "type": "events", + "order": 0, + "properties": {"key": "val"}, + }, {"id": "user signed up", "type": "events", "order": 1}, ], "insight": INSIGHT_FUNNELS, @@ -691,13 +860,23 @@ def test_basic_funnel_with_derivative_steps(self): distinct_ids=["stopped_after_signup1"], team_id=self.team.pk ) _create_event( - team=self.team, event="user signed up", distinct_id="stopped_after_signup1", properties={"key": "val"} + team=self.team, + event="user signed up", + distinct_id="stopped_after_signup1", + properties={"key": "val"}, + ) + _create_event( + team=self.team, + event="user signed up", + distinct_id="stopped_after_signup1", ) - _create_event(team=self.team, event="user signed up", distinct_id="stopped_after_signup1") person2_stopped_after_signup = _create_person(distinct_ids=["stopped_after_signup2"], team_id=self.team.pk) _create_event( - team=self.team, event="user signed up", distinct_id="stopped_after_signup2", properties={"key": "val"} + team=self.team, + event="user signed up", + distinct_id="stopped_after_signup2", + properties={"key": "val"}, ) result = funnel.run() @@ -708,15 +887,24 @@ def test_basic_funnel_with_derivative_steps(self): self.assertCountEqual( self._get_actor_ids_at_step(filter, 1), - [person1_stopped_after_two_signups.uuid, person2_stopped_after_signup.uuid], + [ + person1_stopped_after_two_signups.uuid, + person2_stopped_after_signup.uuid, + ], ) - self.assertCountEqual(self._get_actor_ids_at_step(filter, 2), [person1_stopped_after_two_signups.uuid]) + self.assertCountEqual( + self._get_actor_ids_at_step(filter, 2), + [person1_stopped_after_two_signups.uuid], + ) def test_basic_funnel_with_repeat_step_updated_param(self): people = journeys_for( { - "stopped_after_signup1": [{"event": "user signed up"}, {"event": "user signed up"}], + "stopped_after_signup1": [ + {"event": "user signed up"}, + {"event": "user signed up"}, + ], "stopped_after_signup2": [{"event": "user signed up"}], }, self.team, @@ -743,10 +931,16 @@ def test_basic_funnel_with_repeat_step_updated_param(self): self.assertCountEqual( self._get_actor_ids_at_step(filter, 1), - [people["stopped_after_signup1"].uuid, people["stopped_after_signup2"].uuid], + [ + people["stopped_after_signup1"].uuid, + people["stopped_after_signup2"].uuid, + ], ) - self.assertCountEqual(self._get_actor_ids_at_step(filter, 2), [people["stopped_after_signup1"].uuid]) + self.assertCountEqual( + self._get_actor_ids_at_step(filter, 2), + [people["stopped_after_signup1"].uuid], + ) filters = { "events": [ @@ -792,7 +986,12 @@ def test_funnel_exclusions_full_window(self): "date_from": "2021-05-01 00:00:00", "date_to": "2021-05-14 00:00:00", "exclusions": [ - {"id": "x 1 name with numbers 2", "type": "events", "funnel_from_step": 0, "funnel_to_step": 1} + { + "id": "x 1 name with numbers 2", + "type": "events", + "funnel_from_step": 0, + "funnel_to_step": 1, + } ], } filter = Filter(data=filters) @@ -801,26 +1000,53 @@ def test_funnel_exclusions_full_window(self): # event 1 person1 = _create_person(distinct_ids=["person1"], team_id=self.team.pk) _create_event( - team=self.team, event="user signed up", distinct_id="person1", timestamp="2021-05-01 01:00:00" + team=self.team, + event="user signed up", + distinct_id="person1", + timestamp="2021-05-01 01:00:00", + ) + _create_event( + team=self.team, + event="paid", + distinct_id="person1", + timestamp="2021-05-01 02:00:00", ) - _create_event(team=self.team, event="paid", distinct_id="person1", timestamp="2021-05-01 02:00:00") # event 2 _create_person(distinct_ids=["person2"], team_id=self.team.pk) _create_event( - team=self.team, event="user signed up", distinct_id="person2", timestamp="2021-05-01 03:00:00" + team=self.team, + event="user signed up", + distinct_id="person2", + timestamp="2021-05-01 03:00:00", + ) + _create_event( + team=self.team, + event="x 1 name with numbers 2", + distinct_id="person2", + timestamp="2021-05-01 03:30:00", ) _create_event( - team=self.team, event="x 1 name with numbers 2", distinct_id="person2", timestamp="2021-05-01 03:30:00" + team=self.team, + event="paid", + distinct_id="person2", + timestamp="2021-05-01 04:00:00", ) - _create_event(team=self.team, event="paid", distinct_id="person2", timestamp="2021-05-01 04:00:00") # event 3 person3 = _create_person(distinct_ids=["person3"], team_id=self.team.pk) _create_event( - team=self.team, event="user signed up", distinct_id="person3", timestamp="2021-05-01 05:00:00" + team=self.team, + event="user signed up", + distinct_id="person3", + timestamp="2021-05-01 05:00:00", + ) + _create_event( + team=self.team, + event="paid", + distinct_id="person3", + timestamp="2021-05-01 06:00:00", ) - _create_event(team=self.team, event="paid", distinct_id="person3", timestamp="2021-05-01 06:00:00") result = funnel.run() self.assertEqual(len(result), 2) @@ -845,7 +1071,14 @@ def test_advanced_funnel_exclusions_between_steps(self): "date_from": "2021-05-01 00:00:00", "date_to": "2021-05-14 00:00:00", "insight": INSIGHT_FUNNELS, - "exclusions": [{"id": "x", "type": "events", "funnel_from_step": 0, "funnel_to_step": 1}], + "exclusions": [ + { + "id": "x", + "type": "events", + "funnel_from_step": 0, + "funnel_to_step": 1, + } + ], } person1 = _create_person(distinct_ids=["person1"], team_id=self.team.pk) @@ -853,53 +1086,145 @@ def test_advanced_funnel_exclusions_between_steps(self): # this dude is discarded when funnel_from_step = 2 # this dude is discarded when funnel_from_step = 3 _create_event( - team=self.team, event="user signed up", distinct_id="person1", timestamp="2021-05-01 01:00:00" + team=self.team, + event="user signed up", + distinct_id="person1", + timestamp="2021-05-01 01:00:00", + ) + _create_event( + team=self.team, + event="$pageview", + distinct_id="person1", + timestamp="2021-05-01 02:00:00", + ) + _create_event( + team=self.team, + event="x", + distinct_id="person1", + timestamp="2021-05-01 03:00:00", + ) + _create_event( + team=self.team, + event="insight viewed", + distinct_id="person1", + timestamp="2021-05-01 04:00:00", + ) + _create_event( + team=self.team, + event="x", + distinct_id="person1", + timestamp="2021-05-01 04:30:00", + ) + _create_event( + team=self.team, + event="invite teammate", + distinct_id="person1", + timestamp="2021-05-01 05:00:00", ) - _create_event(team=self.team, event="$pageview", distinct_id="person1", timestamp="2021-05-01 02:00:00") - _create_event(team=self.team, event="x", distinct_id="person1", timestamp="2021-05-01 03:00:00") _create_event( - team=self.team, event="insight viewed", distinct_id="person1", timestamp="2021-05-01 04:00:00" + team=self.team, + event="x", + distinct_id="person1", + timestamp="2021-05-01 05:30:00", ) - _create_event(team=self.team, event="x", distinct_id="person1", timestamp="2021-05-01 04:30:00") _create_event( - team=self.team, event="invite teammate", distinct_id="person1", timestamp="2021-05-01 05:00:00" + team=self.team, + event="pageview2", + distinct_id="person1", + timestamp="2021-05-01 06:00:00", ) - _create_event(team=self.team, event="x", distinct_id="person1", timestamp="2021-05-01 05:30:00") - _create_event(team=self.team, event="pageview2", distinct_id="person1", timestamp="2021-05-01 06:00:00") person2 = _create_person(distinct_ids=["person2"], team_id=self.team.pk) # this dude is discarded when funnel_from_step = 2 # this dude is discarded when funnel_from_step = 3 _create_event( - team=self.team, event="user signed up", distinct_id="person2", timestamp="2021-05-01 01:00:00" + team=self.team, + event="user signed up", + distinct_id="person2", + timestamp="2021-05-01 01:00:00", + ) + _create_event( + team=self.team, + event="$pageview", + distinct_id="person2", + timestamp="2021-05-01 02:00:00", + ) + _create_event( + team=self.team, + event="insight viewed", + distinct_id="person2", + timestamp="2021-05-01 04:00:00", + ) + _create_event( + team=self.team, + event="x", + distinct_id="person2", + timestamp="2021-05-01 04:30:00", + ) + _create_event( + team=self.team, + event="invite teammate", + distinct_id="person2", + timestamp="2021-05-01 05:00:00", ) - _create_event(team=self.team, event="$pageview", distinct_id="person2", timestamp="2021-05-01 02:00:00") _create_event( - team=self.team, event="insight viewed", distinct_id="person2", timestamp="2021-05-01 04:00:00" + team=self.team, + event="x", + distinct_id="person2", + timestamp="2021-05-01 05:30:00", ) - _create_event(team=self.team, event="x", distinct_id="person2", timestamp="2021-05-01 04:30:00") _create_event( - team=self.team, event="invite teammate", distinct_id="person2", timestamp="2021-05-01 05:00:00" + team=self.team, + event="pageview2", + distinct_id="person2", + timestamp="2021-05-01 06:00:00", ) - _create_event(team=self.team, event="x", distinct_id="person2", timestamp="2021-05-01 05:30:00") - _create_event(team=self.team, event="pageview2", distinct_id="person2", timestamp="2021-05-01 06:00:00") person3 = _create_person(distinct_ids=["person3"], team_id=self.team.pk) # this dude is discarded when funnel_from_step = 0 # this dude is discarded when funnel_from_step = 3 _create_event( - team=self.team, event="user signed up", distinct_id="person3", timestamp="2021-05-01 01:00:00" + team=self.team, + event="user signed up", + distinct_id="person3", + timestamp="2021-05-01 01:00:00", + ) + _create_event( + team=self.team, + event="x", + distinct_id="person3", + timestamp="2021-05-01 01:30:00", + ) + _create_event( + team=self.team, + event="$pageview", + distinct_id="person3", + timestamp="2021-05-01 02:00:00", + ) + _create_event( + team=self.team, + event="insight viewed", + distinct_id="person3", + timestamp="2021-05-01 04:00:00", + ) + _create_event( + team=self.team, + event="invite teammate", + distinct_id="person3", + timestamp="2021-05-01 05:00:00", ) - _create_event(team=self.team, event="x", distinct_id="person3", timestamp="2021-05-01 01:30:00") - _create_event(team=self.team, event="$pageview", distinct_id="person3", timestamp="2021-05-01 02:00:00") _create_event( - team=self.team, event="insight viewed", distinct_id="person3", timestamp="2021-05-01 04:00:00" + team=self.team, + event="x", + distinct_id="person3", + timestamp="2021-05-01 05:30:00", ) _create_event( - team=self.team, event="invite teammate", distinct_id="person3", timestamp="2021-05-01 05:00:00" + team=self.team, + event="pageview2", + distinct_id="person3", + timestamp="2021-05-01 06:00:00", ) - _create_event(team=self.team, event="x", distinct_id="person3", timestamp="2021-05-01 05:30:00") - _create_event(team=self.team, event="pageview2", distinct_id="person3", timestamp="2021-05-01 06:00:00") filter = Filter(data=filters) funnel = Funnel(filter, self.team) @@ -914,7 +1239,16 @@ def test_advanced_funnel_exclusions_between_steps(self): self.assertCountEqual(self._get_actor_ids_at_step(filter, 1), [person1.uuid, person2.uuid]) filter = filter.shallow_clone( - {"exclusions": [{"id": "x", "type": "events", "funnel_from_step": 1, "funnel_to_step": 2}]} + { + "exclusions": [ + { + "id": "x", + "type": "events", + "funnel_from_step": 1, + "funnel_to_step": 2, + } + ] + } ) funnel = Funnel(filter, self.team) @@ -928,7 +1262,16 @@ def test_advanced_funnel_exclusions_between_steps(self): self.assertCountEqual(self._get_actor_ids_at_step(filter, 1), [person2.uuid, person3.uuid]) filter = filter.shallow_clone( - {"exclusions": [{"id": "x", "type": "events", "funnel_from_step": 2, "funnel_to_step": 3}]} + { + "exclusions": [ + { + "id": "x", + "type": "events", + "funnel_from_step": 2, + "funnel_to_step": 3, + } + ] + } ) funnel = Funnel(filter, self.team) @@ -942,7 +1285,16 @@ def test_advanced_funnel_exclusions_between_steps(self): self.assertCountEqual(self._get_actor_ids_at_step(filter, 1), [person3.uuid]) filter = filter.shallow_clone( - {"exclusions": [{"id": "x", "type": "events", "funnel_from_step": 3, "funnel_to_step": 4}]} + { + "exclusions": [ + { + "id": "x", + "type": "events", + "funnel_from_step": 3, + "funnel_to_step": 4, + } + ] + } ) funnel = Funnel(filter, self.team) @@ -957,7 +1309,16 @@ def test_advanced_funnel_exclusions_between_steps(self): #  bigger step window filter = filter.shallow_clone( - {"exclusions": [{"id": "x", "type": "events", "funnel_from_step": 1, "funnel_to_step": 3}]} + { + "exclusions": [ + { + "id": "x", + "type": "events", + "funnel_from_step": 1, + "funnel_to_step": 3, + } + ] + } ) funnel = Funnel(filter, self.team) @@ -988,7 +1349,10 @@ def test_advanced_funnel_with_repeat_steps(self): people = journeys_for( { "stopped_after_signup1": [{"event": "user signed up"}], - "stopped_after_pageview1": [{"event": "user signed up"}, {"event": "$pageview"}], + "stopped_after_pageview1": [ + {"event": "user signed up"}, + {"event": "$pageview"}, + ], "stopped_after_pageview2": [ {"event": "user signed up"}, {"event": "$pageview"}, @@ -1062,11 +1426,17 @@ def test_advanced_funnel_with_repeat_steps(self): self.assertCountEqual( self._get_actor_ids_at_step(filter, 4), - [people["stopped_after_pageview3"].uuid, people["stopped_after_pageview4"].uuid], - ) - - self.assertCountEqual(self._get_actor_ids_at_step(filter, 5), [people["stopped_after_pageview4"].uuid]) - + [ + people["stopped_after_pageview3"].uuid, + people["stopped_after_pageview4"].uuid, + ], + ) + + self.assertCountEqual( + self._get_actor_ids_at_step(filter, 5), + [people["stopped_after_pageview4"].uuid], + ) + def test_advanced_funnel_with_repeat_steps_out_of_order_events(self): filters = { "events": [ @@ -1088,45 +1458,85 @@ def test_advanced_funnel_with_repeat_steps_out_of_order_events(self): distinct_ids=["random", "stopped_after_signup1"], team_id=self.team.pk ) _create_event(team=self.team, event="$pageview", distinct_id="random") - _create_event(team=self.team, event="user signed up", distinct_id="stopped_after_signup1") + _create_event( + team=self.team, + event="user signed up", + distinct_id="stopped_after_signup1", + ) person2_stopped_after_one_pageview = _create_person( distinct_ids=["stopped_after_pageview1"], team_id=self.team.pk ) - _create_event(team=self.team, event="user signed up", distinct_id="stopped_after_pageview1") + _create_event( + team=self.team, + event="user signed up", + distinct_id="stopped_after_pageview1", + ) _create_event(team=self.team, event="$pageview", distinct_id="stopped_after_pageview1") person3_stopped_after_two_pageview = _create_person( distinct_ids=["stopped_after_pageview2"], team_id=self.team.pk ) _create_event(team=self.team, event="$pageview", distinct_id="stopped_after_pageview2") - _create_event(team=self.team, event="user signed up", distinct_id="stopped_after_pageview2") - _create_event(team=self.team, event="blaah blaa", distinct_id="stopped_after_pageview2") + _create_event( + team=self.team, + event="user signed up", + distinct_id="stopped_after_pageview2", + ) + _create_event( + team=self.team, + event="blaah blaa", + distinct_id="stopped_after_pageview2", + ) _create_event(team=self.team, event="$pageview", distinct_id="stopped_after_pageview2") person4_stopped_after_three_pageview = _create_person( distinct_ids=["stopped_after_pageview3"], team_id=self.team.pk ) - _create_event(team=self.team, event="blaah blaa", distinct_id="stopped_after_pageview3") + _create_event( + team=self.team, + event="blaah blaa", + distinct_id="stopped_after_pageview3", + ) _create_event(team=self.team, event="$pageview", distinct_id="stopped_after_pageview3") - _create_event(team=self.team, event="blaah blaa", distinct_id="stopped_after_pageview3") + _create_event( + team=self.team, + event="blaah blaa", + distinct_id="stopped_after_pageview3", + ) _create_event(team=self.team, event="$pageview", distinct_id="stopped_after_pageview3") - _create_event(team=self.team, event="user signed up", distinct_id="stopped_after_pageview3") + _create_event( + team=self.team, + event="user signed up", + distinct_id="stopped_after_pageview3", + ) _create_event(team=self.team, event="$pageview", distinct_id="stopped_after_pageview3") person5_stopped_after_many_pageview = _create_person( distinct_ids=["stopped_after_pageview4"], team_id=self.team.pk ) - _create_event(team=self.team, event="user signed up", distinct_id="stopped_after_pageview4") + _create_event( + team=self.team, + event="user signed up", + distinct_id="stopped_after_pageview4", + ) _create_event(team=self.team, event="$pageview", distinct_id="stopped_after_pageview4") - _create_event(team=self.team, event="blaah blaa", distinct_id="stopped_after_pageview4") + _create_event( + team=self.team, + event="blaah blaa", + distinct_id="stopped_after_pageview4", + ) _create_event(team=self.team, event="$pageview", distinct_id="stopped_after_pageview4") _create_event(team=self.team, event="$pageview", distinct_id="stopped_after_pageview4") _create_event(team=self.team, event="$pageview", distinct_id="stopped_after_pageview4") _create_person(distinct_ids=["stopped_after_pageview5"], team_id=self.team.pk) _create_event(team=self.team, event="$pageview", distinct_id="stopped_after_pageview5") - _create_event(team=self.team, event="blaah blaa", distinct_id="stopped_after_pageview5") + _create_event( + team=self.team, + event="blaah blaa", + distinct_id="stopped_after_pageview5", + ) _create_event(team=self.team, event="$pageview", distinct_id="stopped_after_pageview5") _create_event(team=self.team, event="$pageview", distinct_id="stopped_after_pageview5") _create_event(team=self.team, event="$pageview", distinct_id="stopped_after_pageview5") @@ -1168,19 +1578,34 @@ def test_advanced_funnel_with_repeat_steps_out_of_order_events(self): ], ) - self.assertCountEqual(self._get_actor_ids_at_step(filter, 3), [person5_stopped_after_many_pageview.uuid]) + self.assertCountEqual( + self._get_actor_ids_at_step(filter, 3), + [person5_stopped_after_many_pageview.uuid], + ) - self.assertCountEqual(self._get_actor_ids_at_step(filter, 4), [person5_stopped_after_many_pageview.uuid]) + self.assertCountEqual( + self._get_actor_ids_at_step(filter, 4), + [person5_stopped_after_many_pageview.uuid], + ) - self.assertCountEqual(self._get_actor_ids_at_step(filter, 5), [person5_stopped_after_many_pageview.uuid]) + self.assertCountEqual( + self._get_actor_ids_at_step(filter, 5), + [person5_stopped_after_many_pageview.uuid], + ) @also_test_with_materialized_columns(["key"]) def test_funnel_with_actions(self): - sign_up_action = _create_action( name="sign up", team=self.team, - properties=[{"key": "key", "type": "event", "value": ["val"], "operator": "exact"}], + properties=[ + { + "key": "key", + "type": "event", + "value": ["val"], + "operator": "exact", + } + ], ) filters = { @@ -1199,15 +1624,24 @@ def test_funnel_with_actions(self): distinct_ids=["stopped_after_signup1"], team_id=self.team.pk ) _create_event( - team=self.team, event="sign up", distinct_id="stopped_after_signup1", properties={"key": "val"} + team=self.team, + event="sign up", + distinct_id="stopped_after_signup1", + properties={"key": "val"}, ) _create_event( - team=self.team, event="sign up", distinct_id="stopped_after_signup1", properties={"key": "val"} + team=self.team, + event="sign up", + distinct_id="stopped_after_signup1", + properties={"key": "val"}, ) person2_stopped_after_signup = _create_person(distinct_ids=["stopped_after_signup2"], team_id=self.team.pk) _create_event( - team=self.team, event="sign up", distinct_id="stopped_after_signup2", properties={"key": "val"} + team=self.team, + event="sign up", + distinct_id="stopped_after_signup2", + properties={"key": "val"}, ) result = funnel.run() @@ -1220,17 +1654,29 @@ def test_funnel_with_actions(self): # check ordering of people in first step self.assertCountEqual( self._get_actor_ids_at_step(filter, 1), - [person1_stopped_after_two_signups.uuid, person2_stopped_after_signup.uuid], + [ + person1_stopped_after_two_signups.uuid, + person2_stopped_after_signup.uuid, + ], ) - self.assertCountEqual(self._get_actor_ids_at_step(filter, 2), [person1_stopped_after_two_signups.uuid]) + self.assertCountEqual( + self._get_actor_ids_at_step(filter, 2), + [person1_stopped_after_two_signups.uuid], + ) def test_funnel_with_different_actions_at_same_time_count_as_converted(self): - sign_up_action = _create_action( name="sign up", team=self.team, - properties=[{"key": "key", "type": "event", "value": ["val"], "operator": "exact"}], + properties=[ + { + "key": "key", + "type": "event", + "value": ["val"], + "operator": "exact", + } + ], ) filters = { @@ -1250,17 +1696,26 @@ def test_funnel_with_different_actions_at_same_time_count_as_converted(self): distinct_ids=["stopped_after_signup1"], team_id=self.team.pk ) _create_event( - team=self.team, event="sign up", distinct_id="stopped_after_signup1", properties={"key": "val"} + team=self.team, + event="sign up", + distinct_id="stopped_after_signup1", + properties={"key": "val"}, ) _create_event( - team=self.team, event="$pageview", distinct_id="stopped_after_signup1", properties={"key": "val"} + team=self.team, + event="$pageview", + distinct_id="stopped_after_signup1", + properties={"key": "val"}, ) person2_stopped_after_signup = _create_person( distinct_ids=["stopped_after_signup2"], team_id=self.team.pk ) _create_event( - team=self.team, event="sign up", distinct_id="stopped_after_signup2", properties={"key": "val"} + team=self.team, + event="sign up", + distinct_id="stopped_after_signup2", + properties={"key": "val"}, ) result = funnel.run() @@ -1273,16 +1728,29 @@ def test_funnel_with_different_actions_at_same_time_count_as_converted(self): # check ordering of people in first step self.assertCountEqual( self._get_actor_ids_at_step(filter, 1), - [person1_stopped_after_two_signups.uuid, person2_stopped_after_signup.uuid], + [ + person1_stopped_after_two_signups.uuid, + person2_stopped_after_signup.uuid, + ], ) - self.assertCountEqual(self._get_actor_ids_at_step(filter, 2), [person1_stopped_after_two_signups.uuid]) + self.assertCountEqual( + self._get_actor_ids_at_step(filter, 2), + [person1_stopped_after_two_signups.uuid], + ) def test_funnel_with_actions_and_props(self): sign_up_action = _create_action( name="sign up", team=self.team, - properties=[{"key": "email", "operator": "icontains", "value": ".com", "type": "person"}], + properties=[ + { + "key": "email", + "operator": "icontains", + "value": ".com", + "type": "person", + } + ], ) filters = { @@ -1298,20 +1766,33 @@ def test_funnel_with_actions_and_props(self): # event person1_stopped_after_two_signups = _create_person( - distinct_ids=["stopped_after_signup1"], team_id=self.team.pk, properties={"email": "fake@test.com"} + distinct_ids=["stopped_after_signup1"], + team_id=self.team.pk, + properties={"email": "fake@test.com"}, ) _create_event( - team=self.team, event="sign up", distinct_id="stopped_after_signup1", properties={"key": "val"} + team=self.team, + event="sign up", + distinct_id="stopped_after_signup1", + properties={"key": "val"}, ) _create_event( - team=self.team, event="sign up", distinct_id="stopped_after_signup1", properties={"key": "val"} + team=self.team, + event="sign up", + distinct_id="stopped_after_signup1", + properties={"key": "val"}, ) person2_stopped_after_signup = _create_person( - distinct_ids=["stopped_after_signup2"], team_id=self.team.pk, properties={"email": "fake@test.com"} + distinct_ids=["stopped_after_signup2"], + team_id=self.team.pk, + properties={"email": "fake@test.com"}, ) _create_event( - team=self.team, event="sign up", distinct_id="stopped_after_signup2", properties={"key": "val"} + team=self.team, + event="sign up", + distinct_id="stopped_after_signup2", + properties={"key": "val"}, ) result = funnel.run() @@ -1324,13 +1805,18 @@ def test_funnel_with_actions_and_props(self): # check ordering of people in first step self.assertCountEqual( self._get_actor_ids_at_step(filter, 1), - [person1_stopped_after_two_signups.uuid, person2_stopped_after_signup.uuid], + [ + person1_stopped_after_two_signups.uuid, + person2_stopped_after_signup.uuid, + ], ) - self.assertCountEqual(self._get_actor_ids_at_step(filter, 2), [person1_stopped_after_two_signups.uuid]) + self.assertCountEqual( + self._get_actor_ids_at_step(filter, 2), + [person1_stopped_after_two_signups.uuid], + ) def test_funnel_with_actions_and_props_with_zero_person_ids(self): - # only a person-on-event test if not get_instance_setting("PERSON_ON_EVENTS_ENABLED"): return True @@ -1338,7 +1824,14 @@ def test_funnel_with_actions_and_props_with_zero_person_ids(self): sign_up_action = _create_action( name="sign up", team=self.team, - properties=[{"key": "email", "operator": "icontains", "value": ".com", "type": "person"}], + properties=[ + { + "key": "email", + "operator": "icontains", + "value": ".com", + "type": "person", + } + ], ) filters = { @@ -1354,20 +1847,33 @@ def test_funnel_with_actions_and_props_with_zero_person_ids(self): # event person1_stopped_after_two_signups = _create_person( - distinct_ids=["stopped_after_signup1"], team_id=self.team.pk, properties={"email": "fake@test.com"} + distinct_ids=["stopped_after_signup1"], + team_id=self.team.pk, + properties={"email": "fake@test.com"}, ) _create_event( - team=self.team, event="sign up", distinct_id="stopped_after_signup1", properties={"key": "val"} + team=self.team, + event="sign up", + distinct_id="stopped_after_signup1", + properties={"key": "val"}, ) _create_event( - team=self.team, event="sign up", distinct_id="stopped_after_signup1", properties={"key": "val"} + team=self.team, + event="sign up", + distinct_id="stopped_after_signup1", + properties={"key": "val"}, ) person2_stopped_after_signup = _create_person( - distinct_ids=["stopped_after_signup2"], team_id=self.team.pk, properties={"email": "fake@test.com"} + distinct_ids=["stopped_after_signup2"], + team_id=self.team.pk, + properties={"email": "fake@test.com"}, ) _create_event( - team=self.team, event="sign up", distinct_id="stopped_after_signup2", properties={"key": "val"} + team=self.team, + event="sign up", + distinct_id="stopped_after_signup2", + properties={"key": "val"}, ) _create_event( @@ -1395,19 +1901,31 @@ def test_funnel_with_actions_and_props_with_zero_person_ids(self): # check ordering of people in first step self.assertCountEqual( self._get_actor_ids_at_step(filter, 1), - [person1_stopped_after_two_signups.uuid, person2_stopped_after_signup.uuid], + [ + person1_stopped_after_two_signups.uuid, + person2_stopped_after_signup.uuid, + ], ) - self.assertCountEqual(self._get_actor_ids_at_step(filter, 2), [person1_stopped_after_two_signups.uuid]) + self.assertCountEqual( + self._get_actor_ids_at_step(filter, 2), + [person1_stopped_after_two_signups.uuid], + ) @also_test_with_materialized_columns(["key"]) @skip("Flaky funnel test") def test_funnel_with_actions_and_events(self): - sign_up_action = _create_action( name="sign up", team=self.team, - properties=[{"key": "key", "type": "event", "value": ["val"], "operator": "exact"}], + properties=[ + { + "key": "key", + "type": "event", + "value": ["val"], + "operator": "exact", + } + ], ) filters = { @@ -1479,7 +1997,10 @@ def test_funnel_with_actions_and_events(self): person3 = _create_person(distinct_ids=["person3"], team_id=self.team.pk) _create_event( - team=self.team, event="user signed up", distinct_id="person3", timestamp="2021-05-01 00:00:07" + team=self.team, + event="user signed up", + distinct_id="person3", + timestamp="2021-05-01 00:00:07", ) _create_event( team=self.team, @@ -1489,7 +2010,10 @@ def test_funnel_with_actions_and_events(self): timestamp="2021-05-01 00:00:08", ) _create_event( - team=self.team, event="user signed up", distinct_id="person3", timestamp="2021-05-01 00:00:09" + team=self.team, + event="user signed up", + distinct_id="person3", + timestamp="2021-05-01 00:00:09", ) _create_event( team=self.team, @@ -1501,7 +2025,10 @@ def test_funnel_with_actions_and_events(self): person4 = _create_person(distinct_ids=["person4"], team_id=self.team.pk) _create_event( - team=self.team, event="user signed up", distinct_id="person4", timestamp="2021-05-01 00:00:11" + team=self.team, + event="user signed up", + distinct_id="person4", + timestamp="2021-05-01 00:00:11", ) _create_event( team=self.team, @@ -1511,7 +2038,10 @@ def test_funnel_with_actions_and_events(self): timestamp="2021-05-01 00:00:12", ) _create_event( - team=self.team, event="user signed up", distinct_id="person4", timestamp="2021-05-01 00:00:13" + team=self.team, + event="user signed up", + distinct_id="person4", + timestamp="2021-05-01 00:00:13", ) _create_person(distinct_ids=["person5"], team_id=self.team.pk) @@ -1535,33 +2065,58 @@ def test_funnel_with_actions_and_events(self): # check ordering of people in steps self.assertCountEqual( self._get_actor_ids_at_step(filter, 1), - [person1_stopped_after_two_signups.uuid, person2_stopped_after_signup.uuid, person3.uuid, person4.uuid], + [ + person1_stopped_after_two_signups.uuid, + person2_stopped_after_signup.uuid, + person3.uuid, + person4.uuid, + ], ) self.assertCountEqual( self._get_actor_ids_at_step(filter, 2), - [person1_stopped_after_two_signups.uuid, person2_stopped_after_signup.uuid, person3.uuid, person4.uuid], + [ + person1_stopped_after_two_signups.uuid, + person2_stopped_after_signup.uuid, + person3.uuid, + person4.uuid, + ], ) self.assertCountEqual( self._get_actor_ids_at_step(filter, 3), - [person1_stopped_after_two_signups.uuid, person2_stopped_after_signup.uuid, person3.uuid], + [ + person1_stopped_after_two_signups.uuid, + person2_stopped_after_signup.uuid, + person3.uuid, + ], ) - self.assertCountEqual(self._get_actor_ids_at_step(filter, 4), [person1_stopped_after_two_signups.uuid]) + self.assertCountEqual( + self._get_actor_ids_at_step(filter, 4), + [person1_stopped_after_two_signups.uuid], + ) @also_test_with_materialized_columns(["$current_url"]) def test_funnel_with_matching_properties(self): filters = { "events": [ {"id": "user signed up", "order": 0}, - {"id": "$pageview", "order": 1, "properties": {"$current_url": "aloha.com"}}, + { + "id": "$pageview", + "order": 1, + "properties": {"$current_url": "aloha.com"}, + }, { "id": "$pageview", "order": 2, "properties": {"$current_url": "aloha2.com"}, }, # different event to above - {"id": "$pageview", "order": 3, "properties": {"$current_url": "aloha2.com"}}, + { + "id": "$pageview", + "order": 3, + "properties": {"$current_url": "aloha2.com"}, + }, {"id": "$pageview", "order": 4}, ], "insight": INSIGHT_FUNNELS, @@ -1577,28 +2132,61 @@ def test_funnel_with_matching_properties(self): "stopped_after_signup1": [{"event": "user signed up"}], "stopped_after_pageview1": [ {"event": "user signed up"}, - {"event": "$pageview", "properties": {"$current_url": "aloha.com"}}, + { + "event": "$pageview", + "properties": {"$current_url": "aloha.com"}, + }, ], "stopped_after_pageview2": [ {"event": "user signed up"}, - {"event": "$pageview", "properties": {"$current_url": "aloha.com"}}, - {"event": "blaah blaa", "properties": {"$current_url": "aloha.com"}}, - {"event": "$pageview", "properties": {"$current_url": "aloha2.com"}}, + { + "event": "$pageview", + "properties": {"$current_url": "aloha.com"}, + }, + { + "event": "blaah blaa", + "properties": {"$current_url": "aloha.com"}, + }, + { + "event": "$pageview", + "properties": {"$current_url": "aloha2.com"}, + }, ], "stopped_after_pageview3": [ {"event": "user signed up"}, - {"event": "$pageview", "properties": {"$current_url": "aloha.com"}}, - {"event": "$pageview", "properties": {"$current_url": "aloha2.com"}}, - {"event": "$pageview", "properties": {"$current_url": "aloha2.com"}}, + { + "event": "$pageview", + "properties": {"$current_url": "aloha.com"}, + }, + { + "event": "$pageview", + "properties": {"$current_url": "aloha2.com"}, + }, + { + "event": "$pageview", + "properties": {"$current_url": "aloha2.com"}, + }, {"event": "blaah blaa"}, ], "stopped_after_pageview4": [ {"event": "user signed up"}, - {"event": "$pageview", "properties": {"$current_url": "aloha.com"}}, + { + "event": "$pageview", + "properties": {"$current_url": "aloha.com"}, + }, {"event": "blaah blaa"}, - {"event": "$pageview", "properties": {"$current_url": "aloha2.com"}}, - {"event": "$pageview", "properties": {"$current_url": "aloha.com"}}, - {"event": "$pageview", "properties": {"$current_url": "aloha2.com"}}, + { + "event": "$pageview", + "properties": {"$current_url": "aloha2.com"}, + }, + { + "event": "$pageview", + "properties": {"$current_url": "aloha.com"}, + }, + { + "event": "$pageview", + "properties": {"$current_url": "aloha2.com"}, + }, ], }, self.team, @@ -1647,7 +2235,10 @@ def test_funnel_with_matching_properties(self): self.assertCountEqual( self._get_actor_ids_at_step(filter, 4), - [people["stopped_after_pageview3"].uuid, people["stopped_after_pageview4"].uuid], + [ + people["stopped_after_pageview3"].uuid, + people["stopped_after_pageview4"].uuid, + ], ) self.assertCountEqual(self._get_actor_ids_at_step(filter, 5), []) @@ -1658,19 +2249,31 @@ def test_funnel_conversion_window(self): person = _create_person(distinct_ids=[f"user_{i}"], team=self.team) ids_to_compare.append(str(person.uuid)) _create_event( - event="step one", distinct_id=f"user_{i}", team=self.team, timestamp="2021-05-01 00:00:00" + event="step one", + distinct_id=f"user_{i}", + team=self.team, + timestamp="2021-05-01 00:00:00", ) _create_event( - event="step two", distinct_id=f"user_{i}", team=self.team, timestamp="2021-05-02 00:00:00" + event="step two", + distinct_id=f"user_{i}", + team=self.team, + timestamp="2021-05-02 00:00:00", ) for i in range(10, 25): _create_person(distinct_ids=[f"user_{i}"], team=self.team) _create_event( - event="step one", distinct_id=f"user_{i}", team=self.team, timestamp="2021-05-01 00:00:00" + event="step one", + distinct_id=f"user_{i}", + team=self.team, + timestamp="2021-05-01 00:00:00", ) _create_event( - event="step two", distinct_id=f"user_{i}", team=self.team, timestamp="2021-05-10 00:00:00" + event="step two", + distinct_id=f"user_{i}", + team=self.team, + timestamp="2021-05-10 00:00:00", ) data = { @@ -1693,7 +2296,10 @@ def test_funnel_conversion_window(self): self.assertEqual(results[1]["count"], 10) self.assertEqual(results[2]["count"], 0) - self.assertCountEqual([str(id) for id in self._get_actor_ids_at_step(filter, 2)], ids_to_compare) + self.assertCountEqual( + [str(id) for id in self._get_actor_ids_at_step(filter, 2)], + ids_to_compare, + ) @snapshot_clickhouse_queries def test_funnel_conversion_window_seconds(self): @@ -1702,19 +2308,31 @@ def test_funnel_conversion_window_seconds(self): person = _create_person(distinct_ids=[f"user_{i}"], team=self.team) ids_to_compare.append(str(person.uuid)) _create_event( - event="step one", distinct_id=f"user_{i}", team=self.team, timestamp="2021-05-01 00:00:00" + event="step one", + distinct_id=f"user_{i}", + team=self.team, + timestamp="2021-05-01 00:00:00", ) _create_event( - event="step two", distinct_id=f"user_{i}", team=self.team, timestamp="2021-05-01 00:00:10" + event="step two", + distinct_id=f"user_{i}", + team=self.team, + timestamp="2021-05-01 00:00:10", ) for i in range(10, 25): _create_person(distinct_ids=[f"user_{i}"], team=self.team) _create_event( - event="step one", distinct_id=f"user_{i}", team=self.team, timestamp="2021-05-01 00:00:00" + event="step one", + distinct_id=f"user_{i}", + team=self.team, + timestamp="2021-05-01 00:00:00", ) _create_event( - event="step two", distinct_id=f"user_{i}", team=self.team, timestamp="2021-05-01 00:00:20" + event="step two", + distinct_id=f"user_{i}", + team=self.team, + timestamp="2021-05-01 00:00:20", ) data = { @@ -1737,7 +2355,10 @@ def test_funnel_conversion_window_seconds(self): self.assertEqual(results[1]["count"], 10) self.assertEqual(results[2]["count"], 0) - self.assertCountEqual([str(id) for id in self._get_actor_ids_at_step(filter, 2)], ids_to_compare) + self.assertCountEqual( + [str(id) for id in self._get_actor_ids_at_step(filter, 2)], + ids_to_compare, + ) def test_funnel_exclusions_invalid_params(self): filters = { @@ -1749,23 +2370,57 @@ def test_funnel_exclusions_invalid_params(self): "funnel_window_days": 14, "date_from": "2021-05-01 00:00:00", "date_to": "2021-05-14 00:00:00", - "exclusions": [{"id": "x", "type": "events", "funnel_from_step": 1, "funnel_to_step": 1}], + "exclusions": [ + { + "id": "x", + "type": "events", + "funnel_from_step": 1, + "funnel_to_step": 1, + } + ], } filter = Filter(data=filters) self.assertRaises(ValidationError, lambda: Funnel(filter, self.team)) filter = filter.shallow_clone( - {"exclusions": [{"id": "x", "type": "events", "funnel_from_step": 1, "funnel_to_step": 2}]} + { + "exclusions": [ + { + "id": "x", + "type": "events", + "funnel_from_step": 1, + "funnel_to_step": 2, + } + ] + } ) self.assertRaises(ValidationError, lambda: Funnel(filter, self.team)) filter = filter.shallow_clone( - {"exclusions": [{"id": "x", "type": "events", "funnel_from_step": 2, "funnel_to_step": 1}]} + { + "exclusions": [ + { + "id": "x", + "type": "events", + "funnel_from_step": 2, + "funnel_to_step": 1, + } + ] + } ) self.assertRaises(ValidationError, lambda: Funnel(filter, self.team)) filter = filter.shallow_clone( - {"exclusions": [{"id": "x", "type": "events", "funnel_from_step": 0, "funnel_to_step": 2}]} + { + "exclusions": [ + { + "id": "x", + "type": "events", + "funnel_from_step": 0, + "funnel_to_step": 2, + } + ] + } ) self.assertRaises(ValidationError, lambda: Funnel(filter, self.team)) @@ -1779,7 +2434,14 @@ def test_funnel_exclusion_no_end_event(self): "funnel_window_days": 1, "date_from": "2021-05-01 00:00:00", "date_to": "2021-05-14 00:00:00", - "exclusions": [{"id": "x", "type": "events", "funnel_from_step": 0, "funnel_to_step": 1}], + "exclusions": [ + { + "id": "x", + "type": "events", + "funnel_from_step": 0, + "funnel_to_step": 1, + } + ], } filter = Filter(data=filters) funnel = Funnel(filter, self.team) @@ -1787,32 +2449,69 @@ def test_funnel_exclusion_no_end_event(self): # event 1 person1 = _create_person(distinct_ids=["person1"], team_id=self.team.pk) _create_event( - team=self.team, event="user signed up", distinct_id="person1", timestamp="2021-05-01 01:00:00" + team=self.team, + event="user signed up", + distinct_id="person1", + timestamp="2021-05-01 01:00:00", + ) + _create_event( + team=self.team, + event="paid", + distinct_id="person1", + timestamp="2021-05-01 02:00:00", ) - _create_event(team=self.team, event="paid", distinct_id="person1", timestamp="2021-05-01 02:00:00") # event 2 _create_person(distinct_ids=["person2"], team_id=self.team.pk) _create_event( - team=self.team, event="user signed up", distinct_id="person2", timestamp="2021-05-01 03:00:00" + team=self.team, + event="user signed up", + distinct_id="person2", + timestamp="2021-05-01 03:00:00", + ) + _create_event( + team=self.team, + event="x", + distinct_id="person2", + timestamp="2021-05-01 03:30:00", + ) + _create_event( + team=self.team, + event="paid", + distinct_id="person2", + timestamp="2021-05-01 04:00:00", + ) + + # event 3 + _create_person(distinct_ids=["person3"], team_id=self.team.pk) + # should be discarded, even if nothing happened after x, since within conversion window + _create_event( + team=self.team, + event="user signed up", + distinct_id="person3", + timestamp="2021-05-01 05:00:00", ) - _create_event(team=self.team, event="x", distinct_id="person2", timestamp="2021-05-01 03:30:00") - _create_event(team=self.team, event="paid", distinct_id="person2", timestamp="2021-05-01 04:00:00") - - # event 3 - _create_person(distinct_ids=["person3"], team_id=self.team.pk) - # should be discarded, even if nothing happened after x, since within conversion window _create_event( - team=self.team, event="user signed up", distinct_id="person3", timestamp="2021-05-01 05:00:00" + team=self.team, + event="x", + distinct_id="person3", + timestamp="2021-05-01 06:00:00", ) - _create_event(team=self.team, event="x", distinct_id="person3", timestamp="2021-05-01 06:00:00") # event 4 - outside conversion window person4 = _create_person(distinct_ids=["person4"], team_id=self.team.pk) _create_event( - team=self.team, event="user signed up", distinct_id="person4", timestamp="2021-05-01 07:00:00" + team=self.team, + event="user signed up", + distinct_id="person4", + timestamp="2021-05-01 07:00:00", + ) + _create_event( + team=self.team, + event="x", + distinct_id="person4", + timestamp="2021-05-02 08:00:00", ) - _create_event(team=self.team, event="x", distinct_id="person4", timestamp="2021-05-02 08:00:00") result = funnel.run() self.assertEqual(len(result), 2) @@ -1827,11 +2526,17 @@ def test_funnel_exclusion_no_end_event(self): @also_test_with_materialized_columns(["key"]) def test_funnel_exclusions_with_actions(self): - sign_up_action = _create_action( name="sign up", team=self.team, - properties=[{"key": "key", "type": "event", "value": ["val"], "operator": "exact"}], + properties=[ + { + "key": "key", + "type": "event", + "value": ["val"], + "operator": "exact", + } + ], ) filters = { @@ -1844,7 +2549,12 @@ def test_funnel_exclusions_with_actions(self): "date_from": "2021-05-01 00:00:00", "date_to": "2021-05-14 00:00:00", "exclusions": [ - {"id": sign_up_action.id, "type": "actions", "funnel_from_step": 0, "funnel_to_step": 1} + { + "id": sign_up_action.id, + "type": "actions", + "funnel_from_step": 0, + "funnel_to_step": 1, + } ], } filter = Filter(data=filters) @@ -1853,14 +2563,25 @@ def test_funnel_exclusions_with_actions(self): # event 1 person1 = _create_person(distinct_ids=["person1"], team_id=self.team.pk) _create_event( - team=self.team, event="user signed up", distinct_id="person1", timestamp="2021-05-01 01:00:00" + team=self.team, + event="user signed up", + distinct_id="person1", + timestamp="2021-05-01 01:00:00", + ) + _create_event( + team=self.team, + event="paid", + distinct_id="person1", + timestamp="2021-05-01 02:00:00", ) - _create_event(team=self.team, event="paid", distinct_id="person1", timestamp="2021-05-01 02:00:00") # event 2 _create_person(distinct_ids=["person2"], team_id=self.team.pk) _create_event( - team=self.team, event="user signed up", distinct_id="person2", timestamp="2021-05-01 03:00:00" + team=self.team, + event="user signed up", + distinct_id="person2", + timestamp="2021-05-01 03:00:00", ) _create_event( team=self.team, @@ -1869,14 +2590,27 @@ def test_funnel_exclusions_with_actions(self): properties={"key": "val"}, timestamp="2021-05-01 03:30:00", ) - _create_event(team=self.team, event="paid", distinct_id="person2", timestamp="2021-05-01 04:00:00") + _create_event( + team=self.team, + event="paid", + distinct_id="person2", + timestamp="2021-05-01 04:00:00", + ) # event 3 person3 = _create_person(distinct_ids=["person3"], team_id=self.team.pk) _create_event( - team=self.team, event="user signed up", distinct_id="person3", timestamp="2021-05-01 05:00:00" + team=self.team, + event="user signed up", + distinct_id="person3", + timestamp="2021-05-01 05:00:00", + ) + _create_event( + team=self.team, + event="paid", + distinct_id="person3", + timestamp="2021-05-01 06:00:00", ) - _create_event(team=self.team, event="paid", distinct_id="person3", timestamp="2021-05-01 06:00:00") result = funnel.run() self.assertEqual(len(result), 2) @@ -1919,7 +2653,12 @@ def test_funnel_with_denormalised_properties(self): timestamp="2020-01-02T14:00:00Z", properties={"test_prop": "hi"}, ) - _create_event(team=self.team, event="paid", distinct_id="user_1", timestamp="2020-01-10T14:00:00Z") + _create_event( + team=self.team, + event="paid", + distinct_id="user_1", + timestamp="2020-01-10T14:00:00Z", + ) result = funnel.run() @@ -1939,69 +2678,190 @@ def test_advanced_funnel_multiple_exclusions_between_steps(self): "date_to": "2021-05-14 00:00:00", "insight": INSIGHT_FUNNELS, "exclusions": [ - {"id": "x", "type": "events", "funnel_from_step": 0, "funnel_to_step": 1}, - {"id": "y", "type": "events", "funnel_from_step": 2, "funnel_to_step": 3}, + { + "id": "x", + "type": "events", + "funnel_from_step": 0, + "funnel_to_step": 1, + }, + { + "id": "y", + "type": "events", + "funnel_from_step": 2, + "funnel_to_step": 3, + }, ], } _create_person(distinct_ids=["person1"], team_id=self.team.pk) _create_event( - team=self.team, event="user signed up", distinct_id="person1", timestamp="2021-05-01 01:00:00" + team=self.team, + event="user signed up", + distinct_id="person1", + timestamp="2021-05-01 01:00:00", + ) + _create_event( + team=self.team, + event="x", + distinct_id="person1", + timestamp="2021-05-01 02:00:00", + ) + _create_event( + team=self.team, + event="$pageview", + distinct_id="person1", + timestamp="2021-05-01 03:00:00", + ) + _create_event( + team=self.team, + event="insight viewed", + distinct_id="person1", + timestamp="2021-05-01 04:00:00", ) - _create_event(team=self.team, event="x", distinct_id="person1", timestamp="2021-05-01 02:00:00") - _create_event(team=self.team, event="$pageview", distinct_id="person1", timestamp="2021-05-01 03:00:00") _create_event( - team=self.team, event="insight viewed", distinct_id="person1", timestamp="2021-05-01 04:00:00" + team=self.team, + event="y", + distinct_id="person1", + timestamp="2021-05-01 04:30:00", + ) + _create_event( + team=self.team, + event="invite teammate", + distinct_id="person1", + timestamp="2021-05-01 05:00:00", ) - _create_event(team=self.team, event="y", distinct_id="person1", timestamp="2021-05-01 04:30:00") _create_event( - team=self.team, event="invite teammate", distinct_id="person1", timestamp="2021-05-01 05:00:00" + team=self.team, + event="pageview2", + distinct_id="person1", + timestamp="2021-05-01 06:00:00", ) - _create_event(team=self.team, event="pageview2", distinct_id="person1", timestamp="2021-05-01 06:00:00") _create_person(distinct_ids=["person2"], team_id=self.team.pk) _create_event( - team=self.team, event="user signed up", distinct_id="person2", timestamp="2021-05-01 01:00:00" + team=self.team, + event="user signed up", + distinct_id="person2", + timestamp="2021-05-01 01:00:00", + ) + _create_event( + team=self.team, + event="y", + distinct_id="person2", + timestamp="2021-05-01 01:30:00", + ) + _create_event( + team=self.team, + event="$pageview", + distinct_id="person2", + timestamp="2021-05-01 02:00:00", + ) + _create_event( + team=self.team, + event="insight viewed", + distinct_id="person2", + timestamp="2021-05-01 04:00:00", + ) + _create_event( + team=self.team, + event="y", + distinct_id="person2", + timestamp="2021-05-01 04:30:00", + ) + _create_event( + team=self.team, + event="invite teammate", + distinct_id="person2", + timestamp="2021-05-01 05:00:00", ) - _create_event(team=self.team, event="y", distinct_id="person2", timestamp="2021-05-01 01:30:00") - _create_event(team=self.team, event="$pageview", distinct_id="person2", timestamp="2021-05-01 02:00:00") _create_event( - team=self.team, event="insight viewed", distinct_id="person2", timestamp="2021-05-01 04:00:00" + team=self.team, + event="x", + distinct_id="person2", + timestamp="2021-05-01 05:30:00", ) - _create_event(team=self.team, event="y", distinct_id="person2", timestamp="2021-05-01 04:30:00") _create_event( - team=self.team, event="invite teammate", distinct_id="person2", timestamp="2021-05-01 05:00:00" + team=self.team, + event="pageview2", + distinct_id="person2", + timestamp="2021-05-01 06:00:00", ) - _create_event(team=self.team, event="x", distinct_id="person2", timestamp="2021-05-01 05:30:00") - _create_event(team=self.team, event="pageview2", distinct_id="person2", timestamp="2021-05-01 06:00:00") _create_person(distinct_ids=["person3"], team_id=self.team.pk) _create_event( - team=self.team, event="user signed up", distinct_id="person3", timestamp="2021-05-01 01:00:00" + team=self.team, + event="user signed up", + distinct_id="person3", + timestamp="2021-05-01 01:00:00", + ) + _create_event( + team=self.team, + event="x", + distinct_id="person3", + timestamp="2021-05-01 01:30:00", + ) + _create_event( + team=self.team, + event="$pageview", + distinct_id="person3", + timestamp="2021-05-01 02:00:00", + ) + _create_event( + team=self.team, + event="insight viewed", + distinct_id="person3", + timestamp="2021-05-01 04:00:00", + ) + _create_event( + team=self.team, + event="invite teammate", + distinct_id="person3", + timestamp="2021-05-01 05:00:00", ) - _create_event(team=self.team, event="x", distinct_id="person3", timestamp="2021-05-01 01:30:00") - _create_event(team=self.team, event="$pageview", distinct_id="person3", timestamp="2021-05-01 02:00:00") _create_event( - team=self.team, event="insight viewed", distinct_id="person3", timestamp="2021-05-01 04:00:00" + team=self.team, + event="x", + distinct_id="person3", + timestamp="2021-05-01 05:30:00", ) _create_event( - team=self.team, event="invite teammate", distinct_id="person3", timestamp="2021-05-01 05:00:00" + team=self.team, + event="pageview2", + distinct_id="person3", + timestamp="2021-05-01 06:00:00", ) - _create_event(team=self.team, event="x", distinct_id="person3", timestamp="2021-05-01 05:30:00") - _create_event(team=self.team, event="pageview2", distinct_id="person3", timestamp="2021-05-01 06:00:00") person4 = _create_person(distinct_ids=["person4"], team_id=self.team.pk) _create_event( - team=self.team, event="user signed up", distinct_id="person4", timestamp="2021-05-01 01:00:00" + team=self.team, + event="user signed up", + distinct_id="person4", + timestamp="2021-05-01 01:00:00", + ) + _create_event( + team=self.team, + event="$pageview", + distinct_id="person4", + timestamp="2021-05-01 02:00:00", + ) + _create_event( + team=self.team, + event="insight viewed", + distinct_id="person4", + timestamp="2021-05-01 04:00:00", ) - _create_event(team=self.team, event="$pageview", distinct_id="person4", timestamp="2021-05-01 02:00:00") _create_event( - team=self.team, event="insight viewed", distinct_id="person4", timestamp="2021-05-01 04:00:00" + team=self.team, + event="invite teammate", + distinct_id="person4", + timestamp="2021-05-01 05:00:00", ) _create_event( - team=self.team, event="invite teammate", distinct_id="person4", timestamp="2021-05-01 05:00:00" + team=self.team, + event="pageview2", + distinct_id="person4", + timestamp="2021-05-01 06:00:00", ) - _create_event(team=self.team, event="pageview2", distinct_id="person4", timestamp="2021-05-01 06:00:00") filter = Filter(data=filters) funnel = Funnel(filter, self.team) @@ -2018,8 +2878,18 @@ def test_advanced_funnel_multiple_exclusions_between_steps(self): filter = filter.shallow_clone( { "exclusions": [ - {"id": "x", "type": "events", "funnel_from_step": 0, "funnel_to_step": 1}, - {"id": "y", "type": "events", "funnel_from_step": 0, "funnel_to_step": 1}, + { + "id": "x", + "type": "events", + "funnel_from_step": 0, + "funnel_to_step": 1, + }, + { + "id": "y", + "type": "events", + "funnel_from_step": 0, + "funnel_to_step": 1, + }, ] } ) @@ -2037,8 +2907,18 @@ def test_advanced_funnel_multiple_exclusions_between_steps(self): filter = filter.shallow_clone( { "exclusions": [ - {"id": "x", "type": "events", "funnel_from_step": 0, "funnel_to_step": 1}, - {"id": "y", "type": "events", "funnel_from_step": 0, "funnel_to_step": 1}, + { + "id": "x", + "type": "events", + "funnel_from_step": 0, + "funnel_to_step": 1, + }, + { + "id": "y", + "type": "events", + "funnel_from_step": 0, + "funnel_to_step": 1, + }, ] } ) @@ -2056,8 +2936,18 @@ def test_advanced_funnel_multiple_exclusions_between_steps(self): filter = filter.shallow_clone( { "exclusions": [ - {"id": "x", "type": "events", "funnel_from_step": 0, "funnel_to_step": 4}, - {"id": "y", "type": "events", "funnel_from_step": 0, "funnel_to_step": 4}, + { + "id": "x", + "type": "events", + "funnel_from_step": 0, + "funnel_to_step": 4, + }, + { + "id": "y", + "type": "events", + "funnel_from_step": 0, + "funnel_to_step": 4, + }, ] } ) @@ -2095,7 +2985,12 @@ def test_funnel_with_elements_chain(self): "name": "$autocapture", "order": 1, "properties": [ - {"key": "tag_name", "value": [tag_name], "operator": "exact", "type": "element"} + { + "key": "tag_name", + "value": [tag_name], + "operator": "exact", + "type": "element", + } ], "type": "events", }, @@ -2133,22 +3028,52 @@ def test_breakdown_values_is_set_on_the_query_with_fewer_than_two_entities(self) @snapshot_clickhouse_queries def test_funnel_with_cohorts_step_filter(self): - - _create_person(distinct_ids=["user_1"], team_id=self.team.pk, properties={"email": "n@test.com"}) + _create_person( + distinct_ids=["user_1"], + team_id=self.team.pk, + properties={"email": "n@test.com"}, + ) + _create_event( + team=self.team, + event="user signed up", + distinct_id="user_1", + timestamp="2020-01-02T14:00:00Z", + ) _create_event( - team=self.team, event="user signed up", distinct_id="user_1", timestamp="2020-01-02T14:00:00Z" + team=self.team, + event="paid", + distinct_id="user_1", + timestamp="2020-01-10T14:00:00Z", ) - _create_event(team=self.team, event="paid", distinct_id="user_1", timestamp="2020-01-10T14:00:00Z") _create_person(distinct_ids=["user_2"], team_id=self.team.pk) _create_event( - team=self.team, event="user signed up", distinct_id="user_2", timestamp="2020-01-02T14:00:00Z" + team=self.team, + event="user signed up", + distinct_id="user_2", + timestamp="2020-01-02T14:00:00Z", + ) + _create_event( + team=self.team, + event="paid", + distinct_id="user_2", + timestamp="2020-01-10T14:00:00Z", ) - _create_event(team=self.team, event="paid", distinct_id="user_2", timestamp="2020-01-10T14:00:00Z") cohort = Cohort.objects.create( team=self.team, - groups=[{"properties": [{"key": "email", "operator": "icontains", "value": ".com", "type": "person"}]}], + groups=[ + { + "properties": [ + { + "key": "email", + "operator": "icontains", + "value": ".com", + "type": "person", + } + ] + } + ], ) filters = { @@ -2176,22 +3101,52 @@ def test_funnel_with_cohorts_step_filter(self): @snapshot_clickhouse_queries def test_funnel_with_precalculated_cohort_step_filter(self): - - _create_person(distinct_ids=["user_1"], team_id=self.team.pk, properties={"email": "n@test.com"}) + _create_person( + distinct_ids=["user_1"], + team_id=self.team.pk, + properties={"email": "n@test.com"}, + ) + _create_event( + team=self.team, + event="user signed up", + distinct_id="user_1", + timestamp="2020-01-02T14:00:00Z", + ) _create_event( - team=self.team, event="user signed up", distinct_id="user_1", timestamp="2020-01-02T14:00:00Z" + team=self.team, + event="paid", + distinct_id="user_1", + timestamp="2020-01-10T14:00:00Z", ) - _create_event(team=self.team, event="paid", distinct_id="user_1", timestamp="2020-01-10T14:00:00Z") _create_person(distinct_ids=["user_2"], team_id=self.team.pk) _create_event( - team=self.team, event="user signed up", distinct_id="user_2", timestamp="2020-01-02T14:00:00Z" + team=self.team, + event="user signed up", + distinct_id="user_2", + timestamp="2020-01-02T14:00:00Z", + ) + _create_event( + team=self.team, + event="paid", + distinct_id="user_2", + timestamp="2020-01-10T14:00:00Z", ) - _create_event(team=self.team, event="paid", distinct_id="user_2", timestamp="2020-01-10T14:00:00Z") cohort = Cohort.objects.create( team=self.team, - groups=[{"properties": [{"key": "email", "operator": "icontains", "value": ".com", "type": "person"}]}], + groups=[ + { + "properties": [ + { + "key": "email", + "operator": "icontains", + "value": ".com", + "type": "person", + } + ] + } + ], ) filters = { @@ -2200,7 +3155,13 @@ def test_funnel_with_precalculated_cohort_step_filter(self): "id": "user signed up", "type": "events", "order": 0, - "properties": [{"type": "precalculated-cohort", "key": "id", "value": cohort.pk}], + "properties": [ + { + "type": "precalculated-cohort", + "key": "id", + "value": cohort.pk, + } + ], }, {"id": "paid", "type": "events", "order": 1}, ], @@ -2222,18 +3183,37 @@ def test_funnel_with_precalculated_cohort_step_filter(self): @snapshot_clickhouse_queries def test_funnel_with_static_cohort_step_filter(self): - - _create_person(distinct_ids=["user_1"], team_id=self.team.pk, properties={"email": "n@test.com"}) + _create_person( + distinct_ids=["user_1"], + team_id=self.team.pk, + properties={"email": "n@test.com"}, + ) + _create_event( + team=self.team, + event="user signed up", + distinct_id="user_1", + timestamp="2020-01-02T14:00:00Z", + ) _create_event( - team=self.team, event="user signed up", distinct_id="user_1", timestamp="2020-01-02T14:00:00Z" + team=self.team, + event="paid", + distinct_id="user_1", + timestamp="2020-01-10T14:00:00Z", ) - _create_event(team=self.team, event="paid", distinct_id="user_1", timestamp="2020-01-10T14:00:00Z") _create_person(distinct_ids=["user_2"], team_id=self.team.pk) _create_event( - team=self.team, event="user signed up", distinct_id="user_2", timestamp="2020-01-02T14:00:00Z" + team=self.team, + event="user signed up", + distinct_id="user_2", + timestamp="2020-01-02T14:00:00Z", + ) + _create_event( + team=self.team, + event="paid", + distinct_id="user_2", + timestamp="2020-01-10T14:00:00Z", ) - _create_event(team=self.team, event="paid", distinct_id="user_2", timestamp="2020-01-10T14:00:00Z") cohort = Cohort.objects.create(team=self.team, groups=[], is_static=True) cohort.insert_users_by_list(["user_2", "rando"]) @@ -2269,7 +3249,11 @@ def test_funnel_with_property_groups(self): "date_to": "2020-07-01 00:00:00", "events": [ {"id": "user signed up", "order": 0}, - {"id": "$pageview", "order": 1, "properties": {"$current_url": "aloha.com"}}, + { + "id": "$pageview", + "order": 1, + "properties": {"$current_url": "aloha.com"}, + }, { "id": "$pageview", "order": 2, @@ -2284,15 +3268,35 @@ def test_funnel_with_property_groups(self): { "type": "AND", "values": [ - {"key": "email", "operator": "icontains", "value": ".com", "type": "person"}, - {"key": "age", "operator": "exact", "value": "20", "type": "person"}, + { + "key": "email", + "operator": "icontains", + "value": ".com", + "type": "person", + }, + { + "key": "age", + "operator": "exact", + "value": "20", + "type": "person", + }, ], }, { "type": "OR", "values": [ - {"key": "email", "operator": "icontains", "value": ".org", "type": "person"}, - {"key": "age", "operator": "exact", "value": "28", "type": "person"}, + { + "key": "email", + "operator": "icontains", + "value": ".org", + "type": "person", + }, + { + "key": "age", + "operator": "exact", + "value": "28", + "type": "person", + }, ], }, ], @@ -2332,10 +3336,23 @@ def test_funnel_with_property_groups(self): # event journeys_for( { - "stopped_after_signup1": [{"event": "user signed up", "timestamp": datetime(2020, 5, 1, 0)}], - "stopped_after_pageview1": [{"event": "user signed up", "timestamp": datetime(2020, 5, 1, 0)}], + "stopped_after_signup1": [ + { + "event": "user signed up", + "timestamp": datetime(2020, 5, 1, 0), + } + ], + "stopped_after_pageview1": [ + { + "event": "user signed up", + "timestamp": datetime(2020, 5, 1, 0), + } + ], "stopped_after_pageview2": [ - {"event": "user signed up", "timestamp": datetime(2020, 5, 1, 0)}, + { + "event": "user signed up", + "timestamp": datetime(2020, 5, 1, 0), + }, { "event": "$pageview", "properties": {"$current_url": "aloha.com"}, @@ -2343,7 +3360,10 @@ def test_funnel_with_property_groups(self): }, ], "stopped_after_pageview3": [ - {"event": "user signed up", "timestamp": datetime(2020, 5, 1, 0)}, + { + "event": "user signed up", + "timestamp": datetime(2020, 5, 1, 0), + }, { "event": "$pageview", "properties": {"$current_url": "aloha.com"}, @@ -2398,10 +3418,16 @@ def test_funnel_with_property_groups(self): self.assertCountEqual( self._get_actor_ids_at_step(filter, 2), - [people["stopped_after_pageview2"].uuid, people["stopped_after_pageview3"].uuid], + [ + people["stopped_after_pageview2"].uuid, + people["stopped_after_pageview3"].uuid, + ], ) - self.assertCountEqual(self._get_actor_ids_at_step(filter, 3), [people["stopped_after_pageview3"].uuid]) + self.assertCountEqual( + self._get_actor_ids_at_step(filter, 3), + [people["stopped_after_pageview3"].uuid], + ) @snapshot_clickhouse_queries def test_timezones(self): @@ -2425,7 +3451,10 @@ def test_timezones(self): _create_person(distinct_ids=["user_1"], team_id=self.team.pk) #  this event shouldn't appear as in US/Pacific this would be the previous day _create_event( - team=self.team, event="user signed up", distinct_id="user_1", timestamp="2020-01-01T01:00:00Z" + team=self.team, + event="user signed up", + distinct_id="user_1", + timestamp="2020-01-01T01:00:00Z", ) result = funnel.run() @@ -2434,7 +3463,12 @@ def test_timezones(self): def test_funnel_with_sampling(self): action_play_movie = Action.objects.create(team=self.team, name="watched movie") - ActionStep.objects.create(action=action_play_movie, event="$autocapture", tag_name="a", href="/movie") + ActionStep.objects.create( + action=action_play_movie, + event="$autocapture", + tag_name="a", + href="/movie", + ) funnel = self._basic_funnel( filters={ @@ -2453,7 +3487,10 @@ def test_funnel_with_sampling(self): self._signup_event(distinct_id="stopped_after_pay") self._movie_event(distinct_id="completed_movie") - person_factory(distinct_ids=["had_anonymous_id", "completed_movie"], team_id=self.team.pk) + person_factory( + distinct_ids=["had_anonymous_id", "completed_movie"], + team_id=self.team.pk, + ) self._signup_event(distinct_id="had_anonymous_id") self._movie_event(distinct_id="completed_movie") @@ -2511,7 +3548,10 @@ def test_hogql_aggregation(self): # properties.$session_id result = self._basic_funnel( - filters={**basic_filters, "funnel_aggregate_by_hogql": "properties.$session_id"} + filters={ + **basic_filters, + "funnel_aggregate_by_hogql": "properties.$session_id", + } ).run() self.assertEqual(result[0]["count"], 3) self.assertEqual(result[1]["count"], 2) @@ -2544,14 +3584,27 @@ def test_funnel_all_events_with_properties(self): filters = { "events": [ - {"type": "events", "id": "user signed up", "order": 0, "name": "user signed up", "math": "total"}, + { + "type": "events", + "id": "user signed up", + "order": 0, + "name": "user signed up", + "math": "total", + }, { "type": "events", "id": None, "order": 1, "name": "All events", "math": "total", - "properties": [{"key": "is_saved", "value": ["true"], "operator": "exact", "type": "event"}], + "properties": [ + { + "key": "is_saved", + "value": ["true"], + "operator": "exact", + "type": "event", + } + ], }, ], "funnel_window_days": 14, diff --git a/posthog/queries/funnels/test/test_funnel_persons.py b/posthog/queries/funnels/test/test_funnel_persons.py index 8f8ed2b638f67..995030339484a 100644 --- a/posthog/queries/funnels/test/test_funnel_persons.py +++ b/posthog/queries/funnels/test/test_funnel_persons.py @@ -9,7 +9,9 @@ from posthog.models.event.util import bulk_create_events from posthog.models.person.util import bulk_create_persons from posthog.queries.funnels.funnel_persons import ClickhouseFunnelActors -from posthog.session_recordings.queries.test.session_replay_sql import produce_replay_summary +from posthog.session_recordings.queries.test.session_replay_sql import ( + produce_replay_summary, +) from posthog.test.base import ( APIBaseTest, ClickhouseTestMixin, @@ -33,10 +35,20 @@ def _create_sample_data_multiple_dropoffs(self): events = [] for i in range(5): events.append( - {"event": "step one", "distinct_id": f"user_{i}", "team": self.team, "timestamp": "2021-05-01 00:00:00"} + { + "event": "step one", + "distinct_id": f"user_{i}", + "team": self.team, + "timestamp": "2021-05-01 00:00:00", + } ) events.append( - {"event": "step two", "distinct_id": f"user_{i}", "team": self.team, "timestamp": "2021-05-03 00:00:00"} + { + "event": "step two", + "distinct_id": f"user_{i}", + "team": self.team, + "timestamp": "2021-05-03 00:00:00", + } ) events.append( { @@ -49,21 +61,44 @@ def _create_sample_data_multiple_dropoffs(self): for i in range(5, 15): events.append( - {"event": "step one", "distinct_id": f"user_{i}", "team": self.team, "timestamp": "2021-05-01 00:00:00"} + { + "event": "step one", + "distinct_id": f"user_{i}", + "team": self.team, + "timestamp": "2021-05-01 00:00:00", + } ) events.append( - {"event": "step two", "distinct_id": f"user_{i}", "team": self.team, "timestamp": "2021-05-03 00:00:00"} + { + "event": "step two", + "distinct_id": f"user_{i}", + "team": self.team, + "timestamp": "2021-05-03 00:00:00", + } ) for i in range(15, 35): events.append( - {"event": "step one", "distinct_id": f"user_{i}", "team": self.team, "timestamp": "2021-05-01 00:00:00"} + { + "event": "step one", + "distinct_id": f"user_{i}", + "team": self.team, + "timestamp": "2021-05-01 00:00:00", + } ) bulk_create_events(events) def _create_browser_breakdown_events(self): - person1 = _create_person(distinct_ids=["person1"], team_id=self.team.pk, properties={"$country": "PL"}) - person2 = _create_person(distinct_ids=["person2"], team_id=self.team.pk, properties={"$country": "EE"}) + person1 = _create_person( + distinct_ids=["person1"], + team_id=self.team.pk, + properties={"$country": "PL"}, + ) + person2 = _create_person( + distinct_ids=["person2"], + team_id=self.team.pk, + properties={"$country": "EE"}, + ) journeys_for( { "person1": [ @@ -180,9 +215,24 @@ def test_last_step_dropoff(self): def _create_sample_data(self): for i in range(110): _create_person(distinct_ids=[f"user_{i}"], team=self.team) - _create_event(event="step one", distinct_id=f"user_{i}", team=self.team, timestamp="2021-05-01 00:00:00") - _create_event(event="step two", distinct_id=f"user_{i}", team=self.team, timestamp="2021-05-03 00:00:00") - _create_event(event="step three", distinct_id=f"user_{i}", team=self.team, timestamp="2021-05-05 00:00:00") + _create_event( + event="step one", + distinct_id=f"user_{i}", + team=self.team, + timestamp="2021-05-01 00:00:00", + ) + _create_event( + event="step two", + distinct_id=f"user_{i}", + team=self.team, + timestamp="2021-05-03 00:00:00", + ) + _create_event( + event="step three", + distinct_id=f"user_{i}", + team=self.team, + timestamp="2021-05-05 00:00:00", + ) def test_basic_offset(self): self._create_sample_data() @@ -305,7 +355,11 @@ def test_first_step_breakdowns(self): "interval": "day", "funnel_window_days": 7, "funnel_step": 1, - "events": [{"id": "sign up", "order": 0}, {"id": "play movie", "order": 1}, {"id": "buy", "order": 2}], + "events": [ + {"id": "sign up", "order": 0}, + {"id": "play movie", "order": 1}, + {"id": "buy", "order": 2}, + ], "breakdown_type": "event", "breakdown": "$browser", } @@ -336,7 +390,11 @@ def test_first_step_breakdowns_with_multi_property_breakdown(self): "interval": "day", "funnel_window_days": 7, "funnel_step": 1, - "events": [{"id": "sign up", "order": 0}, {"id": "play movie", "order": 1}, {"id": "buy", "order": 2}], + "events": [ + {"id": "sign up", "order": 0}, + {"id": "play movie", "order": 1}, + {"id": "buy", "order": 2}, + ], "breakdown_type": "event", "breakdown": ["$browser", "$browser_version"], } @@ -367,7 +425,11 @@ def test_first_step_breakdown_person(self): "interval": "day", "funnel_window_days": 7, "funnel_step": 1, - "events": [{"id": "sign up", "order": 0}, {"id": "play movie", "order": 1}, {"id": "buy", "order": 2}], + "events": [ + {"id": "sign up", "order": 0}, + {"id": "play movie", "order": 1}, + {"id": "buy", "order": 2}, + ], "breakdown_type": "person", "breakdown": "$country", } @@ -383,7 +445,8 @@ def test_first_step_breakdown_person(self): # Check custom_steps give same answers for breakdowns _, custom_step_results, _ = ClickhouseFunnelActors( - filter.shallow_clone({"funnel_step_breakdown": "EE", "funnel_custom_steps": [1, 2, 3]}), self.team + filter.shallow_clone({"funnel_step_breakdown": "EE", "funnel_custom_steps": [1, 2, 3]}), + self.team, ).get_actors() self.assertEqual(results, custom_step_results) @@ -394,7 +457,8 @@ def test_first_step_breakdown_person(self): # Check custom_steps give same answers for breakdowns _, custom_step_results, _ = ClickhouseFunnelActors( - filter.shallow_clone({"funnel_step_breakdown": "PL", "funnel_custom_steps": [1, 2, 3]}), self.team + filter.shallow_clone({"funnel_step_breakdown": "PL", "funnel_custom_steps": [1, 2, 3]}), + self.team, ).get_actors() self.assertEqual(results, custom_step_results) @@ -402,7 +466,11 @@ def test_first_step_breakdown_person(self): def test_funnel_cohort_breakdown_persons(self): person = _create_person(distinct_ids=[f"person1"], team_id=self.team.pk, properties={"key": "value"}) _create_event( - team=self.team, event="sign up", distinct_id=f"person1", properties={}, timestamp="2020-01-02T12:00:00Z" + team=self.team, + event="sign up", + distinct_id=f"person1", + properties={}, + timestamp="2020-01-02T12:00:00Z", ) cohort = Cohort.objects.create( team=self.team, @@ -410,7 +478,11 @@ def test_funnel_cohort_breakdown_persons(self): groups=[{"properties": [{"key": "key", "value": "value", "type": "person"}]}], ) filters = { - "events": [{"id": "sign up", "order": 0}, {"id": "play movie", "order": 1}, {"id": "buy", "order": 2}], + "events": [ + {"id": "sign up", "order": 0}, + {"id": "play movie", "order": 1}, + {"id": "buy", "order": 2}, + ], "insight": INSIGHT_FUNNELS, "date_from": "2020-01-01", "date_to": "2020-01-08", diff --git a/posthog/queries/funnels/test/test_funnel_strict.py b/posthog/queries/funnels/test/test_funnel_strict.py index 8cc43e176a0e0..0f0d4b691ce21 100644 --- a/posthog/queries/funnels/test/test_funnel_strict.py +++ b/posthog/queries/funnels/test/test_funnel_strict.py @@ -7,9 +7,19 @@ from posthog.models.instance_setting import override_instance_config from posthog.queries.funnels.funnel_strict import ClickhouseFunnelStrict from posthog.queries.funnels.funnel_strict_persons import ClickhouseFunnelStrictActors -from posthog.queries.funnels.test.breakdown_cases import assert_funnel_results_equal, funnel_breakdown_test_factory -from posthog.queries.funnels.test.conversion_time_cases import funnel_conversion_time_test_factory -from posthog.test.base import APIBaseTest, ClickhouseTestMixin, _create_event, _create_person +from posthog.queries.funnels.test.breakdown_cases import ( + assert_funnel_results_equal, + funnel_breakdown_test_factory, +) +from posthog.queries.funnels.test.conversion_time_cases import ( + funnel_conversion_time_test_factory, +) +from posthog.test.base import ( + APIBaseTest, + ClickhouseTestMixin, + _create_event, + _create_person, +) from posthog.test.test_journeys import journeys_for FORMAT_TIME = "%Y-%m-%d 00:00:00" @@ -24,8 +34,16 @@ def _create_action(**kwargs): return action -class TestFunnelStrictStepsBreakdown(ClickhouseTestMixin, funnel_breakdown_test_factory(ClickhouseFunnelStrict, ClickhouseFunnelStrictActors, _create_event, _create_action, _create_person)): # type: ignore - +class TestFunnelStrictStepsBreakdown( + ClickhouseTestMixin, + funnel_breakdown_test_factory( # type: ignore + ClickhouseFunnelStrict, + ClickhouseFunnelStrictActors, + _create_event, + _create_action, + _create_person, + ), +): maxDiff = None def test_basic_funnel_default_funnel_days_breakdown_event(self): @@ -39,7 +57,6 @@ def test_basic_funnel_default_funnel_days_breakdown_action_materialized(self): pass def test_strict_breakdown_events_with_multiple_properties(self): - filters = { "events": [{"id": "sign up", "order": 0}, {"id": "play movie", "order": 1}], "insight": INSIGHT_FUNNELS, @@ -56,8 +73,16 @@ def test_strict_breakdown_events_with_multiple_properties(self): people = journeys_for( { "person1": [ - {"event": "sign up", "timestamp": datetime(2020, 1, 1, 12), "properties": {"$browser": "Chrome"}}, - {"event": "blah", "timestamp": datetime(2020, 1, 1, 13), "properties": {"$browser": "Chrome"}}, + { + "event": "sign up", + "timestamp": datetime(2020, 1, 1, 12), + "properties": {"$browser": "Chrome"}, + }, + { + "event": "blah", + "timestamp": datetime(2020, 1, 1, 13), + "properties": {"$browser": "Chrome"}, + }, { "event": "play movie", "timestamp": datetime(2020, 1, 1, 14), @@ -65,7 +90,11 @@ def test_strict_breakdown_events_with_multiple_properties(self): }, ], "person2": [ - {"event": "sign up", "timestamp": datetime(2020, 1, 2, 13), "properties": {"$browser": "Safari"}}, + { + "event": "sign up", + "timestamp": datetime(2020, 1, 2, 13), + "properties": {"$browser": "Safari"}, + }, { "event": "play movie", "timestamp": datetime(2020, 1, 2, 14), @@ -146,14 +175,20 @@ def test_strict_breakdown_events_with_multiple_properties(self): self.assertCountEqual(self._get_actor_ids_at_step(filter, 2, ["Safari"]), [people["person2"].uuid]) -class TestFunnelStrictStepsConversionTime(ClickhouseTestMixin, funnel_conversion_time_test_factory(ClickhouseFunnelStrict, ClickhouseFunnelStrictActors, _create_event, _create_person)): # type: ignore - +class TestFunnelStrictStepsConversionTime( + ClickhouseTestMixin, + funnel_conversion_time_test_factory( # type: ignore + ClickhouseFunnelStrict, + ClickhouseFunnelStrictActors, + _create_event, + _create_person, + ), +): maxDiff = None pass class TestFunnelStrictSteps(ClickhouseTestMixin, APIBaseTest): - maxDiff = None def _get_actor_ids_at_step(self, filter, funnel_step, breakdown_value=None): @@ -177,7 +212,9 @@ def test_basic_strict_funnel(self): funnel = ClickhouseFunnelStrict(filter, self.team) person1_stopped_after_signup = _create_person( - distinct_ids=["stopped_after_signup1"], team_id=self.team.pk, properties={"test": "okay"} + distinct_ids=["stopped_after_signup1"], + team_id=self.team.pk, + properties={"test": "okay"}, ) _create_event(team=self.team, event="user signed up", distinct_id="stopped_after_signup1") @@ -185,32 +222,60 @@ def test_basic_strict_funnel(self): distinct_ids=["stopped_after_pageview1"], team_id=self.team.pk ) _create_event(team=self.team, event="$pageview", distinct_id="stopped_after_pageview1") - _create_event(team=self.team, event="user signed up", distinct_id="stopped_after_pageview1") + _create_event( + team=self.team, + event="user signed up", + distinct_id="stopped_after_pageview1", + ) person3_stopped_after_insight_view = _create_person( distinct_ids=["stopped_after_insightview"], team_id=self.team.pk ) - _create_event(team=self.team, event="user signed up", distinct_id="stopped_after_insightview") + _create_event( + team=self.team, + event="user signed up", + distinct_id="stopped_after_insightview", + ) _create_event(team=self.team, event="$pageview", distinct_id="stopped_after_insightview") _create_event(team=self.team, event="blaah blaa", distinct_id="stopped_after_insightview") - _create_event(team=self.team, event="insight viewed", distinct_id="stopped_after_insightview") + _create_event( + team=self.team, + event="insight viewed", + distinct_id="stopped_after_insightview", + ) person4_stopped_after_insight_view_not_strict_order = _create_person( distinct_ids=["stopped_after_insightview2"], team_id=self.team.pk ) - _create_event(team=self.team, event="insight viewed", distinct_id="stopped_after_insightview2") + _create_event( + team=self.team, + event="insight viewed", + distinct_id="stopped_after_insightview2", + ) _create_event(team=self.team, event="blaah blaa", distinct_id="stopped_after_insightview2") _create_event(team=self.team, event="$pageview", distinct_id="stopped_after_insightview2") - _create_event(team=self.team, event="user signed up", distinct_id="stopped_after_insightview2") + _create_event( + team=self.team, + event="user signed up", + distinct_id="stopped_after_insightview2", + ) person5_stopped_after_insight_view_random = _create_person( distinct_ids=["stopped_after_insightview3"], team_id=self.team.pk ) _create_event(team=self.team, event="$pageview", distinct_id="stopped_after_insightview3") - _create_event(team=self.team, event="user signed up", distinct_id="stopped_after_insightview3") + _create_event( + team=self.team, + event="user signed up", + distinct_id="stopped_after_insightview3", + ) _create_event(team=self.team, event="blaah blaa", distinct_id="stopped_after_insightview3") _create_event(team=self.team, event="$pageview", distinct_id="stopped_after_insightview3") - _create_event(team=self.team, event="insight viewed", distinct_id="stopped_after_insightview3") + _create_event( + team=self.team, + event="insight viewed", + distinct_id="stopped_after_insightview3", + ) person6 = _create_person(distinct_ids=["person6"], team_id=self.team.pk) _create_event(team=self.team, event="blaah blaa", distinct_id="person6") @@ -226,7 +291,11 @@ def test_basic_strict_funnel(self): _create_event(team=self.team, event="blaah blaa", distinct_id="person7") _create_person(distinct_ids=["stopped_after_insightview6"], team_id=self.team.pk) - _create_event(team=self.team, event="insight viewed", distinct_id="stopped_after_insightview6") + _create_event( + team=self.team, + event="insight viewed", + distinct_id="stopped_after_insightview6", + ) _create_event(team=self.team, event="$pageview", distinct_id="stopped_after_insightview6") result = funnel.run() @@ -250,7 +319,8 @@ def test_basic_strict_funnel(self): ) self.assertCountEqual( - self._get_actor_ids_at_step(filter, 2), [person3_stopped_after_insight_view.uuid, person7.uuid] + self._get_actor_ids_at_step(filter, 2), + [person3_stopped_after_insight_view.uuid, person7.uuid], ) self.assertCountEqual(self._get_actor_ids_at_step(filter, 3), [person7.uuid]) @@ -263,7 +333,6 @@ def test_basic_strict_funnel(self): self.assertEqual(result[0]["count"], 7) def test_advanced_strict_funnel(self): - sign_up_action = _create_action( name="sign up", team=self.team, @@ -297,59 +366,122 @@ def test_advanced_strict_funnel(self): person2_stopped_after_one_pageview = _create_person( distinct_ids=["stopped_after_pageview1"], team_id=self.team.pk ) - _create_event(team=self.team, event="user signed up", distinct_id="stopped_after_pageview1") + _create_event( + team=self.team, + event="user signed up", + distinct_id="stopped_after_pageview1", + ) _create_event(team=self.team, event="$pageview", distinct_id="stopped_after_pageview1") person3_stopped_after_insight_view = _create_person( distinct_ids=["stopped_after_insightview"], team_id=self.team.pk ) - _create_event(team=self.team, event="user signed up", distinct_id="stopped_after_insightview") _create_event( - team=self.team, event="sign up", distinct_id="stopped_after_insightview", properties={"key": "val"} + team=self.team, + event="user signed up", + distinct_id="stopped_after_insightview", + ) + _create_event( + team=self.team, + event="sign up", + distinct_id="stopped_after_insightview", + properties={"key": "val"}, ) _create_event( - team=self.team, event="sign up", distinct_id="stopped_after_insightview", properties={"key": "val2"} + team=self.team, + event="sign up", + distinct_id="stopped_after_insightview", + properties={"key": "val2"}, ) _create_event(team=self.team, event="$pageview", distinct_id="stopped_after_insightview") _create_event(team=self.team, event="blaah blaa", distinct_id="stopped_after_insightview") - _create_event(team=self.team, event="insight viewed", distinct_id="stopped_after_insightview") + _create_event( + team=self.team, + event="insight viewed", + distinct_id="stopped_after_insightview", + ) person4 = _create_person(distinct_ids=["person4"], team_id=self.team.pk) _create_event(team=self.team, event="blaah blaa", distinct_id="person4") _create_event(team=self.team, event="user signed up", distinct_id="person4") - _create_event(team=self.team, event="sign up", distinct_id="person4", properties={"key": "val"}) - _create_event(team=self.team, event="$pageview", distinct_id="person4", properties={"key": "val"}) + _create_event( + team=self.team, + event="sign up", + distinct_id="person4", + properties={"key": "val"}, + ) + _create_event( + team=self.team, + event="$pageview", + distinct_id="person4", + properties={"key": "val"}, + ) _create_event(team=self.team, event="blaah blaa", distinct_id="person4") person5 = _create_person(distinct_ids=["person5"], team_id=self.team.pk) _create_event(team=self.team, event="blaah blaa", distinct_id="person5") _create_event(team=self.team, event="user signed up", distinct_id="person5") - _create_event(team=self.team, event="sign up", distinct_id="person5", properties={"key": "val"}) + _create_event( + team=self.team, + event="sign up", + distinct_id="person5", + properties={"key": "val"}, + ) _create_event(team=self.team, event="$pageview", distinct_id="person5") _create_event(team=self.team, event="blaah blaa", distinct_id="person5") person6 = _create_person(distinct_ids=["person6"], team_id=self.team.pk) _create_event(team=self.team, event="blaah blaa", distinct_id="person6") _create_event(team=self.team, event="user signed up", distinct_id="person6") - _create_event(team=self.team, event="sign up", distinct_id="person6", properties={"key": "val"}) + _create_event( + team=self.team, + event="sign up", + distinct_id="person6", + properties={"key": "val"}, + ) _create_event(team=self.team, event="$pageview", distinct_id="person6") - _create_event(team=self.team, event="pageview", distinct_id="person6", properties={"key": "val1"}) + _create_event( + team=self.team, + event="pageview", + distinct_id="person6", + properties={"key": "val1"}, + ) person7 = _create_person(distinct_ids=["person7"], team_id=self.team.pk) _create_event(team=self.team, event="blaah blaa", distinct_id="person7") _create_event(team=self.team, event="user signed up", distinct_id="person7") - _create_event(team=self.team, event="sign up", distinct_id="person7", properties={"key": "val"}) + _create_event( + team=self.team, + event="sign up", + distinct_id="person7", + properties={"key": "val"}, + ) _create_event(team=self.team, event="$pageview", distinct_id="person7") _create_event(team=self.team, event="user signed up", distinct_id="person7") - _create_event(team=self.team, event="pageview", distinct_id="person7", properties={"key": "val"}) + _create_event( + team=self.team, + event="pageview", + distinct_id="person7", + properties={"key": "val"}, + ) person8 = _create_person(distinct_ids=["person8"], team_id=self.team.pk) _create_event(team=self.team, event="blaah blaa", distinct_id="person8") _create_event(team=self.team, event="user signed up", distinct_id="person8") _create_event(team=self.team, event="user signed up", distinct_id="person8") - _create_event(team=self.team, event="sign up", distinct_id="person8", properties={"key": "val"}) + _create_event( + team=self.team, + event="sign up", + distinct_id="person8", + properties={"key": "val"}, + ) _create_event(team=self.team, event="$pageview", distinct_id="person8") - _create_event(team=self.team, event="pageview", distinct_id="person8", properties={"key": "val"}) + _create_event( + team=self.team, + event="pageview", + distinct_id="person8", + properties={"key": "val"}, + ) result = funnel.run() @@ -410,7 +542,10 @@ def test_basic_strict_funnel_conversion_times(self): person1_stopped_after_signup = _create_person(distinct_ids=["stopped_after_signup1"], team_id=self.team.pk) _create_event( - team=self.team, event="user signed up", distinct_id="stopped_after_signup1", timestamp="2021-05-02 00:00:00" + team=self.team, + event="user signed up", + distinct_id="stopped_after_signup1", + timestamp="2021-05-02 00:00:00", ) person2_stopped_after_one_pageview = _create_person( @@ -423,7 +558,10 @@ def test_basic_strict_funnel_conversion_times(self): timestamp="2021-05-02 00:00:00", ) _create_event( - team=self.team, event="$pageview", distinct_id="stopped_after_pageview1", timestamp="2021-05-02 01:00:00" + team=self.team, + event="$pageview", + distinct_id="stopped_after_pageview1", + timestamp="2021-05-02 01:00:00", ) person3_stopped_after_insight_view = _create_person( @@ -436,7 +574,10 @@ def test_basic_strict_funnel_conversion_times(self): timestamp="2021-05-02 00:00:00", ) _create_event( - team=self.team, event="$pageview", distinct_id="stopped_after_insightview", timestamp="2021-05-02 02:00:00" + team=self.team, + event="$pageview", + distinct_id="stopped_after_insightview", + timestamp="2021-05-02 02:00:00", ) _create_event( team=self.team, @@ -469,7 +610,13 @@ def test_basic_strict_funnel_conversion_times(self): self.assertCountEqual( self._get_actor_ids_at_step(filter, 2), - [person2_stopped_after_one_pageview.uuid, person3_stopped_after_insight_view.uuid], + [ + person2_stopped_after_one_pageview.uuid, + person3_stopped_after_insight_view.uuid, + ], ) - self.assertCountEqual(self._get_actor_ids_at_step(filter, 3), [person3_stopped_after_insight_view.uuid]) + self.assertCountEqual( + self._get_actor_ids_at_step(filter, 3), + [person3_stopped_after_insight_view.uuid], + ) diff --git a/posthog/queries/funnels/test/test_funnel_strict_persons.py b/posthog/queries/funnels/test/test_funnel_strict_persons.py index 9c9a304a59e8f..7b76faf42a54a 100644 --- a/posthog/queries/funnels/test/test_funnel_strict_persons.py +++ b/posthog/queries/funnels/test/test_funnel_strict_persons.py @@ -7,7 +7,9 @@ from posthog.constants import INSIGHT_FUNNELS from posthog.models.filters import Filter from posthog.queries.funnels.funnel_strict_persons import ClickhouseFunnelStrictActors -from posthog.session_recordings.queries.test.session_replay_sql import produce_replay_summary +from posthog.session_recordings.queries.test.session_replay_sql import ( + produce_replay_summary, +) from posthog.test.base import ( APIBaseTest, ClickhouseTestMixin, diff --git a/posthog/queries/funnels/test/test_funnel_time_to_convert.py b/posthog/queries/funnels/test/test_funnel_time_to_convert.py index 514bb5af66473..dba62ca133ae3 100644 --- a/posthog/queries/funnels/test/test_funnel_time_to_convert.py +++ b/posthog/queries/funnels/test/test_funnel_time_to_convert.py @@ -22,17 +22,52 @@ def test_auto_bin_count_single_step(self): _create_person(distinct_ids=["user b"], team=self.team) _create_person(distinct_ids=["user c"], team=self.team) - _create_event(event="step one", distinct_id="user a", team=self.team, timestamp="2021-06-08 18:00:00") - _create_event(event="step two", distinct_id="user a", team=self.team, timestamp="2021-06-08 19:00:00") + _create_event( + event="step one", + distinct_id="user a", + team=self.team, + timestamp="2021-06-08 18:00:00", + ) + _create_event( + event="step two", + distinct_id="user a", + team=self.team, + timestamp="2021-06-08 19:00:00", + ) # Converted from 0 to 1 in 3600 s - _create_event(event="step three", distinct_id="user a", team=self.team, timestamp="2021-06-08 21:00:00") + _create_event( + event="step three", + distinct_id="user a", + team=self.team, + timestamp="2021-06-08 21:00:00", + ) - _create_event(event="step one", distinct_id="user b", team=self.team, timestamp="2021-06-09 13:00:00") - _create_event(event="step two", distinct_id="user b", team=self.team, timestamp="2021-06-09 13:37:00") + _create_event( + event="step one", + distinct_id="user b", + team=self.team, + timestamp="2021-06-09 13:00:00", + ) + _create_event( + event="step two", + distinct_id="user b", + team=self.team, + timestamp="2021-06-09 13:37:00", + ) # Converted from 0 to 1 in 2200 s - _create_event(event="step one", distinct_id="user c", team=self.team, timestamp="2021-06-11 07:00:00") - _create_event(event="step two", distinct_id="user c", team=self.team, timestamp="2021-06-12 06:00:00") + _create_event( + event="step one", + distinct_id="user c", + team=self.team, + timestamp="2021-06-11 07:00:00", + ) + _create_event( + event="step two", + distinct_id="user c", + team=self.team, + timestamp="2021-06-12 06:00:00", + ) # Converted from 0 to 1 in 82_800 s filter = Filter( @@ -60,9 +95,18 @@ def test_auto_bin_count_single_step(self): results, { "bins": [ - (2220.0, 2), # Reached step 1 from step 0 in at least 2200 s but less than 29_080 s - users A and B - (42510.0, 0), # Analogous to above, just an interval (in this case 26_880 s) up - no users - (82800.0, 1), # Reached step 1 from step 0 in at least 82_800 s but less than 109_680 s - user C + ( + 2220.0, + 2, + ), # Reached step 1 from step 0 in at least 2200 s but less than 29_080 s - users A and B + ( + 42510.0, + 0, + ), # Analogous to above, just an interval (in this case 26_880 s) up - no users + ( + 82800.0, + 1, + ), # Reached step 1 from step 0 in at least 82_800 s but less than 109_680 s - user C ], "average_conversion_time": 29_540, }, @@ -75,17 +119,52 @@ def test_auto_bin_count_single_step_duplicate_events(self): _create_person(distinct_ids=["user b"], team=self.team) _create_person(distinct_ids=["user c"], team=self.team) - _create_event(event="step one", distinct_id="user a", team=self.team, timestamp="2021-06-08 18:00:00") - _create_event(event="step one", distinct_id="user a", team=self.team, timestamp="2021-06-08 19:00:00") + _create_event( + event="step one", + distinct_id="user a", + team=self.team, + timestamp="2021-06-08 18:00:00", + ) + _create_event( + event="step one", + distinct_id="user a", + team=self.team, + timestamp="2021-06-08 19:00:00", + ) # Converted from 0 to 1 in 3600 s - _create_event(event="step one", distinct_id="user a", team=self.team, timestamp="2021-06-08 21:00:00") + _create_event( + event="step one", + distinct_id="user a", + team=self.team, + timestamp="2021-06-08 21:00:00", + ) - _create_event(event="step one", distinct_id="user b", team=self.team, timestamp="2021-06-09 13:00:00") - _create_event(event="step one", distinct_id="user b", team=self.team, timestamp="2021-06-09 13:37:00") + _create_event( + event="step one", + distinct_id="user b", + team=self.team, + timestamp="2021-06-09 13:00:00", + ) + _create_event( + event="step one", + distinct_id="user b", + team=self.team, + timestamp="2021-06-09 13:37:00", + ) # Converted from 0 to 1 in 2200 s - _create_event(event="step one", distinct_id="user c", team=self.team, timestamp="2021-06-11 07:00:00") - _create_event(event="step one", distinct_id="user c", team=self.team, timestamp="2021-06-12 06:00:00") + _create_event( + event="step one", + distinct_id="user c", + team=self.team, + timestamp="2021-06-11 07:00:00", + ) + _create_event( + event="step one", + distinct_id="user c", + team=self.team, + timestamp="2021-06-12 06:00:00", + ) # Converted from 0 to 1 in 82_800 s filter = Filter( @@ -113,9 +192,18 @@ def test_auto_bin_count_single_step_duplicate_events(self): results, { "bins": [ - (2220.0, 2), # Reached step 1 from step 0 in at least 2200 s but less than 29_080 s - users A and B - (42510.0, 0), # Analogous to above, just an interval (in this case 26_880 s) up - no users - (82800.0, 1), # Reached step 1 from step 0 in at least 82_800 s but less than 109_680 s - user C + ( + 2220.0, + 2, + ), # Reached step 1 from step 0 in at least 2200 s but less than 29_080 s - users A and B + ( + 42510.0, + 0, + ), # Analogous to above, just an interval (in this case 26_880 s) up - no users + ( + 82800.0, + 1, + ), # Reached step 1 from step 0 in at least 82_800 s but less than 109_680 s - user C ], "average_conversion_time": 29_540, }, @@ -126,17 +214,52 @@ def test_custom_bin_count_single_step(self): _create_person(distinct_ids=["user b"], team=self.team) _create_person(distinct_ids=["user c"], team=self.team) - _create_event(event="step one", distinct_id="user a", team=self.team, timestamp="2021-06-08 18:00:00") - _create_event(event="step two", distinct_id="user a", team=self.team, timestamp="2021-06-08 19:00:00") + _create_event( + event="step one", + distinct_id="user a", + team=self.team, + timestamp="2021-06-08 18:00:00", + ) + _create_event( + event="step two", + distinct_id="user a", + team=self.team, + timestamp="2021-06-08 19:00:00", + ) # Converted from 0 to 1 in 3600 s - _create_event(event="step three", distinct_id="user a", team=self.team, timestamp="2021-06-08 21:00:00") + _create_event( + event="step three", + distinct_id="user a", + team=self.team, + timestamp="2021-06-08 21:00:00", + ) - _create_event(event="step one", distinct_id="user b", team=self.team, timestamp="2021-06-09 13:00:00") - _create_event(event="step two", distinct_id="user b", team=self.team, timestamp="2021-06-09 13:37:00") + _create_event( + event="step one", + distinct_id="user b", + team=self.team, + timestamp="2021-06-09 13:00:00", + ) + _create_event( + event="step two", + distinct_id="user b", + team=self.team, + timestamp="2021-06-09 13:37:00", + ) # Converted from 0 to 1 in 2200 s - _create_event(event="step one", distinct_id="user c", team=self.team, timestamp="2021-06-11 07:00:00") - _create_event(event="step two", distinct_id="user c", team=self.team, timestamp="2021-06-12 06:00:00") + _create_event( + event="step one", + distinct_id="user c", + team=self.team, + timestamp="2021-06-11 07:00:00", + ) + _create_event( + event="step two", + distinct_id="user c", + team=self.team, + timestamp="2021-06-12 06:00:00", + ) # Converted from 0 to 1 in 82_800 s filter = Filter( @@ -165,13 +288,22 @@ def test_custom_bin_count_single_step(self): results, { "bins": [ - (2220.0, 2), # Reached step 1 from step 0 in at least 2200 s but less than 13_732 s - users A and B - (13732.0, 0), # Analogous to above, just an interval (in this case 13_732 s) up - no users + ( + 2220.0, + 2, + ), # Reached step 1 from step 0 in at least 2200 s but less than 13_732 s - users A and B + ( + 13732.0, + 0, + ), # Analogous to above, just an interval (in this case 13_732 s) up - no users (25244.0, 0), # And so on (36756.0, 0), (48268.0, 0), (59780.0, 0), - (71292.0, 1), # Reached step 1 from step 0 in at least 71_292 s but less than 82_804 s - user C + ( + 71292.0, + 1, + ), # Reached step 1 from step 0 in at least 71_292 s but less than 82_804 s - user C (82804.0, 0), ], "average_conversion_time": 29_540, @@ -184,16 +316,51 @@ def test_auto_bin_count_total(self): _create_person(distinct_ids=["user b"], team=self.team) _create_person(distinct_ids=["user c"], team=self.team) - _create_event(event="step one", distinct_id="user a", team=self.team, timestamp="2021-06-08 18:00:00") - _create_event(event="step two", distinct_id="user a", team=self.team, timestamp="2021-06-08 19:00:00") - _create_event(event="step three", distinct_id="user a", team=self.team, timestamp="2021-06-08 21:00:00") + _create_event( + event="step one", + distinct_id="user a", + team=self.team, + timestamp="2021-06-08 18:00:00", + ) + _create_event( + event="step two", + distinct_id="user a", + team=self.team, + timestamp="2021-06-08 19:00:00", + ) + _create_event( + event="step three", + distinct_id="user a", + team=self.team, + timestamp="2021-06-08 21:00:00", + ) # Converted from 0 to 2 in 10_800 s - _create_event(event="step one", distinct_id="user b", team=self.team, timestamp="2021-06-09 13:00:00") - _create_event(event="step two", distinct_id="user b", team=self.team, timestamp="2021-06-09 13:37:00") + _create_event( + event="step one", + distinct_id="user b", + team=self.team, + timestamp="2021-06-09 13:00:00", + ) + _create_event( + event="step two", + distinct_id="user b", + team=self.team, + timestamp="2021-06-09 13:37:00", + ) - _create_event(event="step one", distinct_id="user c", team=self.team, timestamp="2021-06-11 07:00:00") - _create_event(event="step two", distinct_id="user c", team=self.team, timestamp="2021-06-12 06:00:00") + _create_event( + event="step one", + distinct_id="user c", + team=self.team, + timestamp="2021-06-11 07:00:00", + ) + _create_event( + event="step two", + distinct_id="user c", + team=self.team, + timestamp="2021-06-12 06:00:00", + ) filter = Filter( data={ @@ -217,8 +384,14 @@ def test_auto_bin_count_total(self): results, { "bins": [ - (10800.0, 1), # Reached step 2 from step 0 in at least 10_800 s but less than 10_860 s - user A - (10860.0, 0), # Analogous to above, just an interval (in this case 60 s) up - no users + ( + 10800.0, + 1, + ), # Reached step 2 from step 0 in at least 10_800 s but less than 10_860 s - user A + ( + 10860.0, + 0, + ), # Analogous to above, just an interval (in this case 60 s) up - no users ], "average_conversion_time": 10_800.0, }, @@ -226,7 +399,8 @@ def test_auto_bin_count_total(self): # Let's verify that behavior with steps unspecified is the same as when first and last steps specified funnel_trends_steps_specified = ClickhouseFunnelTimeToConvert( - Filter(data={**filter._data, "funnel_from_step": 0, "funnel_to_step": 2}), self.team + Filter(data={**filter._data, "funnel_from_step": 0, "funnel_to_step": 2}), + self.team, ) results_steps_specified = funnel_trends_steps_specified.run() @@ -238,17 +412,52 @@ def test_basic_unordered(self): _create_person(distinct_ids=["user b"], team=self.team) _create_person(distinct_ids=["user c"], team=self.team) - _create_event(event="step three", distinct_id="user a", team=self.team, timestamp="2021-06-08 18:00:00") - _create_event(event="step one", distinct_id="user a", team=self.team, timestamp="2021-06-08 19:00:00") - _create_event(event="step two", distinct_id="user a", team=self.team, timestamp="2021-06-08 21:00:00") + _create_event( + event="step three", + distinct_id="user a", + team=self.team, + timestamp="2021-06-08 18:00:00", + ) + _create_event( + event="step one", + distinct_id="user a", + team=self.team, + timestamp="2021-06-08 19:00:00", + ) + _create_event( + event="step two", + distinct_id="user a", + team=self.team, + timestamp="2021-06-08 21:00:00", + ) # Converted from 0 to 1 in 7200 s - _create_event(event="step one", distinct_id="user b", team=self.team, timestamp="2021-06-09 13:00:00") - _create_event(event="step two", distinct_id="user b", team=self.team, timestamp="2021-06-09 13:37:00") + _create_event( + event="step one", + distinct_id="user b", + team=self.team, + timestamp="2021-06-09 13:00:00", + ) + _create_event( + event="step two", + distinct_id="user b", + team=self.team, + timestamp="2021-06-09 13:37:00", + ) # Converted from 0 to 1 in 2200 s - _create_event(event="step two", distinct_id="user c", team=self.team, timestamp="2021-06-11 07:00:00") - _create_event(event="step one", distinct_id="user c", team=self.team, timestamp="2021-06-12 06:00:00") + _create_event( + event="step two", + distinct_id="user c", + team=self.team, + timestamp="2021-06-11 07:00:00", + ) + _create_event( + event="step one", + distinct_id="user c", + team=self.team, + timestamp="2021-06-12 06:00:00", + ) # Converted from 0 to 1 in 82_800 s filter = Filter( @@ -278,9 +487,18 @@ def test_basic_unordered(self): results, { "bins": [ - (2220.0, 2), # Reached step 1 from step 0 in at least 2200 s but less than 29_080 s - users A and B - (42510.0, 0), # Analogous to above, just an interval (in this case 26_880 s) up - no users - (82800.0, 1), # Reached step 1 from step 0 in at least 82_800 s but less than 109_680 s - user C + ( + 2220.0, + 2, + ), # Reached step 1 from step 0 in at least 2200 s but less than 29_080 s - users A and B + ( + 42510.0, + 0, + ), # Analogous to above, just an interval (in this case 26_880 s) up - no users + ( + 82800.0, + 1, + ), # Reached step 1 from step 0 in at least 82_800 s but less than 109_680 s - user C ], "average_conversion_time": 29540, }, @@ -293,25 +511,85 @@ def test_basic_strict(self): _create_person(distinct_ids=["user c"], team=self.team) _create_person(distinct_ids=["user d"], team=self.team) - _create_event(event="step one", distinct_id="user a", team=self.team, timestamp="2021-06-08 18:00:00") - _create_event(event="step two", distinct_id="user a", team=self.team, timestamp="2021-06-08 19:00:00") + _create_event( + event="step one", + distinct_id="user a", + team=self.team, + timestamp="2021-06-08 18:00:00", + ) + _create_event( + event="step two", + distinct_id="user a", + team=self.team, + timestamp="2021-06-08 19:00:00", + ) # Converted from 0 to 1 in 3600 s - _create_event(event="step three", distinct_id="user a", team=self.team, timestamp="2021-06-08 21:00:00") + _create_event( + event="step three", + distinct_id="user a", + team=self.team, + timestamp="2021-06-08 21:00:00", + ) - _create_event(event="step one", distinct_id="user b", team=self.team, timestamp="2021-06-09 13:00:00") - _create_event(event="step two", distinct_id="user b", team=self.team, timestamp="2021-06-09 13:37:00") + _create_event( + event="step one", + distinct_id="user b", + team=self.team, + timestamp="2021-06-09 13:00:00", + ) + _create_event( + event="step two", + distinct_id="user b", + team=self.team, + timestamp="2021-06-09 13:37:00", + ) # Converted from 0 to 1 in 2200 s - _create_event(event="blah", distinct_id="user b", team=self.team, timestamp="2021-06-09 13:38:00") - _create_event(event="step three", distinct_id="user b", team=self.team, timestamp="2021-06-09 13:39:00") + _create_event( + event="blah", + distinct_id="user b", + team=self.team, + timestamp="2021-06-09 13:38:00", + ) + _create_event( + event="step three", + distinct_id="user b", + team=self.team, + timestamp="2021-06-09 13:39:00", + ) - _create_event(event="step one", distinct_id="user c", team=self.team, timestamp="2021-06-11 07:00:00") - _create_event(event="step two", distinct_id="user c", team=self.team, timestamp="2021-06-12 06:00:00") + _create_event( + event="step one", + distinct_id="user c", + team=self.team, + timestamp="2021-06-11 07:00:00", + ) + _create_event( + event="step two", + distinct_id="user c", + team=self.team, + timestamp="2021-06-12 06:00:00", + ) # Converted from 0 to 1 in 82_800 s - _create_event(event="step one", distinct_id="user d", team=self.team, timestamp="2021-06-11 07:00:00") - _create_event(event="blah", distinct_id="user d", team=self.team, timestamp="2021-06-12 07:00:00") + _create_event( + event="step one", + distinct_id="user d", + team=self.team, + timestamp="2021-06-11 07:00:00", + ) + _create_event( + event="blah", + distinct_id="user d", + team=self.team, + timestamp="2021-06-12 07:00:00", + ) # Blah cancels conversion - _create_event(event="step two", distinct_id="user d", team=self.team, timestamp="2021-06-12 09:00:00") + _create_event( + event="step two", + distinct_id="user d", + team=self.team, + timestamp="2021-06-12 09:00:00", + ) filter = Filter( data={ @@ -340,9 +618,18 @@ def test_basic_strict(self): results, { "bins": [ - (2220.0, 2), # Reached step 1 from step 0 in at least 2200 s but less than 29_080 s - users A and B - (42510.0, 0), # Analogous to above, just an interval (in this case 26_880 s) up - no users - (82800.0, 1), # Reached step 1 from step 0 in at least 82_800 s but less than 109_680 s - user C + ( + 2220.0, + 2, + ), # Reached step 1 from step 0 in at least 2200 s but less than 29_080 s - users A and B + ( + 42510.0, + 0, + ), # Analogous to above, just an interval (in this case 26_880 s) up - no users + ( + 82800.0, + 1, + ), # Reached step 1 from step 0 in at least 82_800 s but less than 109_680 s - user C ], "average_conversion_time": 29540, }, diff --git a/posthog/queries/funnels/test/test_funnel_trends.py b/posthog/queries/funnels/test/test_funnel_trends.py index 12e8b81af02a5..537333ce07476 100644 --- a/posthog/queries/funnels/test/test_funnel_trends.py +++ b/posthog/queries/funnels/test/test_funnel_trends.py @@ -8,7 +8,12 @@ from posthog.models.filters import Filter from posthog.queries.funnels.funnel_trends import ClickhouseFunnelTrends from posthog.queries.funnels.funnel_trends_persons import ClickhouseFunnelTrendsActors -from posthog.test.base import APIBaseTest, ClickhouseTestMixin, _create_person, snapshot_clickhouse_queries +from posthog.test.base import ( + APIBaseTest, + ClickhouseTestMixin, + _create_person, + snapshot_clickhouse_queries, +) from posthog.test.test_journeys import journeys_for FORMAT_TIME = "%Y-%m-%d %H:%M:%S" @@ -60,7 +65,10 @@ def _create_sample_data(self): ) def test_no_event_in_period(self): - journeys_for({"user a": [{"event": "Step one", "timestamp": datetime(2021, 6, 6, 21)}]}, self.team) + journeys_for( + {"user a": [{"event": "Step one", "timestamp": datetime(2021, 6, 6, 21)}]}, + self.team, + ) filter = Filter( data={ @@ -86,7 +94,10 @@ def test_no_event_in_period(self): self.assertEqual(formatted_results[0]["days"][0], "2021-06-07") def test_only_one_user_reached_one_step(self): - journeys_for({"user a": [{"event": "step one", "timestamp": datetime(2021, 6, 7, 19)}]}, self.team) + journeys_for( + {"user a": [{"event": "step one", "timestamp": datetime(2021, 6, 7, 19)}]}, + self.team, + ) filter = Filter( data={ @@ -161,7 +172,8 @@ def test_only_one_user_reached_one_step(self): self.assertEqual(len(funnel_trends_persons_existent_dropped_off_results), 1) self.assertEqual( - [person["distinct_ids"] for person in funnel_trends_persons_existent_dropped_off_results], [["user a"]] + [person["distinct_ids"] for person in funnel_trends_persons_existent_dropped_off_results], + [["user a"]], ) # No users converted 2021-06-07 @@ -691,7 +703,8 @@ def test_one_person_in_multiple_periods_and_windows(self): self.assertEqual(len(funnel_trends_persons_existent_dropped_off_results), 1) self.assertEqual( - [person["distinct_ids"] for person in funnel_trends_persons_existent_dropped_off_results], [["user_two"]] + [person["distinct_ids"] for person in funnel_trends_persons_existent_dropped_off_results], + [["user_two"]], ) # 1 user who converted starting # 2021-05-04 @@ -701,7 +714,8 @@ def test_one_person_in_multiple_periods_and_windows(self): self.assertEqual(len(funnel_trends_persons_existent_dropped_off_results), 1) self.assertEqual( - [person["distinct_ids"] for person in funnel_trends_persons_existent_dropped_off_results], [["user_one"]] + [person["distinct_ids"] for person in funnel_trends_persons_existent_dropped_off_results], + [["user_one"]], ) def test_from_second_step(self): @@ -889,7 +903,8 @@ def test_one_person_in_multiple_periods_and_windows_in_unordered_funnel(self): self.assertEqual(len(funnel_trends_persons_existent_dropped_off_results), 1) self.assertEqual( - [person["distinct_ids"] for person in funnel_trends_persons_existent_dropped_off_results], [["user_two"]] + [person["distinct_ids"] for person in funnel_trends_persons_existent_dropped_off_results], + [["user_two"]], ) # 1 user who converted starting # 2021-05-04 @@ -899,7 +914,8 @@ def test_one_person_in_multiple_periods_and_windows_in_unordered_funnel(self): self.assertEqual(len(funnel_trends_persons_existent_dropped_off_results), 1) self.assertEqual( - [person["distinct_ids"] for person in funnel_trends_persons_existent_dropped_off_results], [["user_one"]] + [person["distinct_ids"] for person in funnel_trends_persons_existent_dropped_off_results], + [["user_one"]], ) def test_one_person_in_multiple_periods_and_windows_in_strict_funnel(self): @@ -976,19 +992,55 @@ def test_funnel_step_breakdown_event(self): journeys_for( { "user_one": [ - {"event": "step one", "timestamp": datetime(2021, 5, 1), "properties": {"$browser": "Chrome"}}, - {"event": "step two", "timestamp": datetime(2021, 5, 3), "properties": {"$browser": "Chrome"}}, - {"event": "step three", "timestamp": datetime(2021, 5, 5), "properties": {"$browser": "Chrome"}}, + { + "event": "step one", + "timestamp": datetime(2021, 5, 1), + "properties": {"$browser": "Chrome"}, + }, + { + "event": "step two", + "timestamp": datetime(2021, 5, 3), + "properties": {"$browser": "Chrome"}, + }, + { + "event": "step three", + "timestamp": datetime(2021, 5, 5), + "properties": {"$browser": "Chrome"}, + }, ], "user_two": [ - {"event": "step one", "timestamp": datetime(2021, 5, 2), "properties": {"$browser": "Chrome"}}, - {"event": "step two", "timestamp": datetime(2021, 5, 3), "properties": {"$browser": "Chrome"}}, - {"event": "step three", "timestamp": datetime(2021, 5, 5), "properties": {"$browser": "Chrome"}}, + { + "event": "step one", + "timestamp": datetime(2021, 5, 2), + "properties": {"$browser": "Chrome"}, + }, + { + "event": "step two", + "timestamp": datetime(2021, 5, 3), + "properties": {"$browser": "Chrome"}, + }, + { + "event": "step three", + "timestamp": datetime(2021, 5, 5), + "properties": {"$browser": "Chrome"}, + }, ], "user_three": [ - {"event": "step one", "timestamp": datetime(2021, 5, 3), "properties": {"$browser": "Safari"}}, - {"event": "step two", "timestamp": datetime(2021, 5, 4), "properties": {"$browser": "Safari"}}, - {"event": "step three", "timestamp": datetime(2021, 5, 5), "properties": {"$browser": "Safari"}}, + { + "event": "step one", + "timestamp": datetime(2021, 5, 3), + "properties": {"$browser": "Safari"}, + }, + { + "event": "step two", + "timestamp": datetime(2021, 5, 4), + "properties": {"$browser": "Safari"}, + }, + { + "event": "step three", + "timestamp": datetime(2021, 5, 5), + "properties": {"$browser": "Safari"}, + }, ], }, self.team, @@ -1018,16 +1070,40 @@ def test_funnel_step_breakdown_event(self): for res in result: if res["breakdown_value"] == ["Chrome"]: - self.assertEqual(res["data"], [100.0, 100.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]) + self.assertEqual( + res["data"], + [ + 100.0, + 100.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + ], + ) elif res["breakdown_value"] == ["Safari"]: - self.assertEqual(res["data"], [0.0, 0.0, 100.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]) + self.assertEqual( + res["data"], + [0.0, 0.0, 100.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], + ) else: self.fail(msg="Invalid breakdown value") def test_funnel_step_breakdown_person(self): _create_person(distinct_ids=["user_one"], team=self.team, properties={"$browser": "Chrome"}) _create_person(distinct_ids=["user_two"], team=self.team, properties={"$browser": "Chrome"}) - _create_person(distinct_ids=["user_three"], team=self.team, properties={"$browser": "Safari"}) + _create_person( + distinct_ids=["user_three"], + team=self.team, + properties={"$browser": "Safari"}, + ) journeys_for( { "user_one": [ @@ -1073,16 +1149,40 @@ def test_funnel_step_breakdown_person(self): for res in result: if res["breakdown_value"] == ["Chrome"]: - self.assertEqual(res["data"], [100.0, 100.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]) + self.assertEqual( + res["data"], + [ + 100.0, + 100.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + ], + ) elif res["breakdown_value"] == ["Safari"]: - self.assertEqual(res["data"], [0.0, 0.0, 100.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]) + self.assertEqual( + res["data"], + [0.0, 0.0, 100.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], + ) else: self.fail(msg="Invalid breakdown value") def test_funnel_trend_cohort_breakdown(self): _create_person(distinct_ids=["user_one"], team=self.team, properties={"key": "value"}) _create_person(distinct_ids=["user_two"], team=self.team, properties={"key": "value"}) - _create_person(distinct_ids=["user_three"], team=self.team, properties={"$browser": "Safari"}) + _create_person( + distinct_ids=["user_three"], + team=self.team, + properties={"$browser": "Safari"}, + ) journeys_for( { @@ -1131,26 +1231,56 @@ def test_funnel_trend_cohort_breakdown(self): result = funnel_trends.run() self.assertEqual(len(result), 1) - self.assertEqual(result[0]["data"], [100.0, 100.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]) + self.assertEqual( + result[0]["data"], + [100.0, 100.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], + ) @snapshot_clickhouse_queries def test_timezones_trends(self): journeys_for( { "user_one": [ - {"event": "step one", "timestamp": datetime(2021, 5, 1, 10)}, # 04-30 in pacific - {"event": "step two", "timestamp": datetime(2021, 5, 1, 11)}, # today in pacific - {"event": "step three", "timestamp": datetime(2021, 5, 1, 12)}, # today in pacific + { + "event": "step one", + "timestamp": datetime(2021, 5, 1, 10), + }, # 04-30 in pacific + { + "event": "step two", + "timestamp": datetime(2021, 5, 1, 11), + }, # today in pacific + { + "event": "step three", + "timestamp": datetime(2021, 5, 1, 12), + }, # today in pacific ], "user_two": [ - {"event": "step one", "timestamp": datetime(2021, 5, 1, 1)}, # 04-30 in pacific - {"event": "step two", "timestamp": datetime(2021, 5, 1, 2)}, # 04-30 in pacific - {"event": "step three", "timestamp": datetime(2021, 5, 1, 3)}, # 04-30 in pacific + { + "event": "step one", + "timestamp": datetime(2021, 5, 1, 1), + }, # 04-30 in pacific + { + "event": "step two", + "timestamp": datetime(2021, 5, 1, 2), + }, # 04-30 in pacific + { + "event": "step three", + "timestamp": datetime(2021, 5, 1, 3), + }, # 04-30 in pacific ], "user_three": [ - {"event": "step one", "timestamp": datetime(2021, 5, 1, 1)}, # 04-30 in pacific - {"event": "step two", "timestamp": datetime(2021, 5, 1, 10)}, # today in pacific - {"event": "step three", "timestamp": datetime(2021, 5, 1, 11)}, # today in pacific + { + "event": "step one", + "timestamp": datetime(2021, 5, 1, 1), + }, # 04-30 in pacific + { + "event": "step two", + "timestamp": datetime(2021, 5, 1, 10), + }, # today in pacific + { + "event": "step three", + "timestamp": datetime(2021, 5, 1, 11), + }, # today in pacific ], "user_eight": [], }, diff --git a/posthog/queries/funnels/test/test_funnel_trends_persons.py b/posthog/queries/funnels/test/test_funnel_trends_persons.py index ee75bfb025719..60ec3df37c3ff 100644 --- a/posthog/queries/funnels/test/test_funnel_trends_persons.py +++ b/posthog/queries/funnels/test/test_funnel_trends_persons.py @@ -3,8 +3,14 @@ from posthog.constants import INSIGHT_FUNNELS, FunnelVizType from posthog.models.filters import Filter from posthog.queries.funnels.funnel_trends_persons import ClickhouseFunnelTrendsActors -from posthog.session_recordings.queries.test.session_replay_sql import produce_replay_summary -from posthog.test.base import APIBaseTest, ClickhouseTestMixin, snapshot_clickhouse_queries +from posthog.session_recordings.queries.test.session_replay_sql import ( + produce_replay_summary, +) +from posthog.test.base import ( + APIBaseTest, + ClickhouseTestMixin, + snapshot_clickhouse_queries, +) from posthog.test.test_journeys import journeys_for filter_data = { @@ -17,7 +23,11 @@ "funnel_from_step": 0, "entrance_period_start": "2021-05-01 00:00:00", "drop_off": False, - "events": [{"id": "step one", "order": 0}, {"id": "step two", "order": 1}, {"id": "step three", "order": 2}], + "events": [ + {"id": "step one", "order": 0}, + {"id": "step two", "order": 1}, + {"id": "step three", "order": 2}, + ], "include_recordings": "true", } @@ -28,9 +38,21 @@ def test_funnel_trend_persons_returns_recordings(self): persons = journeys_for( { "user_one": [ - {"event": "step one", "timestamp": datetime(2021, 5, 1), "properties": {"$session_id": "s1a"}}, - {"event": "step two", "timestamp": datetime(2021, 5, 2), "properties": {"$session_id": "s1b"}}, - {"event": "step three", "timestamp": datetime(2021, 5, 3), "properties": {"$session_id": "s1c"}}, + { + "event": "step one", + "timestamp": datetime(2021, 5, 1), + "properties": {"$session_id": "s1a"}, + }, + { + "event": "step two", + "timestamp": datetime(2021, 5, 2), + "properties": {"$session_id": "s1b"}, + }, + { + "event": "step three", + "timestamp": datetime(2021, 5, 3), + "properties": {"$session_id": "s1c"}, + }, ] }, self.team, @@ -47,16 +69,31 @@ def test_funnel_trend_persons_returns_recordings(self): filter = Filter(data={"funnel_to_step": 1, **filter_data}) _, results, _ = ClickhouseFunnelTrendsActors(filter, self.team).get_actors() self.assertEqual([person["id"] for person in results], [persons["user_one"].uuid]) - self.assertEqual([person["matched_recordings"][0]["session_id"] for person in results], ["s1b"]) + self.assertEqual( + [person["matched_recordings"][0]["session_id"] for person in results], + ["s1b"], + ) @snapshot_clickhouse_queries def test_funnel_trend_persons_with_no_to_step(self): persons = journeys_for( { "user_one": [ - {"event": "step one", "timestamp": datetime(2021, 5, 1), "properties": {"$session_id": "s1a"}}, - {"event": "step two", "timestamp": datetime(2021, 5, 2), "properties": {"$session_id": "s1b"}}, - {"event": "step three", "timestamp": datetime(2021, 5, 3), "properties": {"$session_id": "s1c"}}, + { + "event": "step one", + "timestamp": datetime(2021, 5, 1), + "properties": {"$session_id": "s1a"}, + }, + { + "event": "step two", + "timestamp": datetime(2021, 5, 2), + "properties": {"$session_id": "s1b"}, + }, + { + "event": "step three", + "timestamp": datetime(2021, 5, 3), + "properties": {"$session_id": "s1c"}, + }, ] }, self.team, @@ -74,14 +111,21 @@ def test_funnel_trend_persons_with_no_to_step(self): filter = Filter(data=filter_data) _, results, _ = ClickhouseFunnelTrendsActors(filter, self.team).get_actors() self.assertEqual([person["id"] for person in results], [persons["user_one"].uuid]) - self.assertEqual([person["matched_recordings"][0]["session_id"] for person in results], ["s1c"]) + self.assertEqual( + [person["matched_recordings"][0]["session_id"] for person in results], + ["s1c"], + ) @snapshot_clickhouse_queries def test_funnel_trend_persons_with_drop_off(self): persons = journeys_for( { "user_one": [ - {"event": "step one", "timestamp": datetime(2021, 5, 1), "properties": {"$session_id": "s1a"}} + { + "event": "step one", + "timestamp": datetime(2021, 5, 1), + "properties": {"$session_id": "s1a"}, + } ] }, self.team, @@ -98,4 +142,7 @@ def test_funnel_trend_persons_with_drop_off(self): filter = Filter(data={**filter_data, "drop_off": True}) _, results, _ = ClickhouseFunnelTrendsActors(filter, self.team).get_actors() self.assertEqual([person["id"] for person in results], [persons["user_one"].uuid]) - self.assertEqual([person["matched_recordings"][0].get("session_id") for person in results], ["s1a"]) + self.assertEqual( + [person["matched_recordings"][0].get("session_id") for person in results], + ["s1a"], + ) diff --git a/posthog/queries/funnels/test/test_funnel_unordered.py b/posthog/queries/funnels/test/test_funnel_unordered.py index cb4eaba04776f..ce3643d007fc6 100644 --- a/posthog/queries/funnels/test/test_funnel_unordered.py +++ b/posthog/queries/funnels/test/test_funnel_unordered.py @@ -7,13 +7,17 @@ from posthog.models.action_step import ActionStep from posthog.models.filters import Filter from posthog.queries.funnels.funnel_unordered import ClickhouseFunnelUnordered -from posthog.queries.funnels.funnel_unordered_persons import ClickhouseFunnelUnorderedActors +from posthog.queries.funnels.funnel_unordered_persons import ( + ClickhouseFunnelUnorderedActors, +) from posthog.queries.funnels.test.breakdown_cases import ( FunnelStepResult, assert_funnel_results_equal, funnel_breakdown_test_factory, ) -from posthog.queries.funnels.test.conversion_time_cases import funnel_conversion_time_test_factory +from posthog.queries.funnels.test.conversion_time_cases import ( + funnel_conversion_time_test_factory, +) from posthog.test.base import ( APIBaseTest, ClickhouseTestMixin, @@ -35,7 +39,16 @@ def _create_action(**kwargs): return action -class TestFunnelUnorderedStepsBreakdown(ClickhouseTestMixin, funnel_breakdown_test_factory(ClickhouseFunnelUnordered, ClickhouseFunnelUnorderedActors, _create_event, _create_action, _create_person)): # type: ignore +class TestFunnelUnorderedStepsBreakdown( + ClickhouseTestMixin, + funnel_breakdown_test_factory( # type: ignore + ClickhouseFunnelUnordered, + ClickhouseFunnelUnorderedActors, + _create_event, + _create_action, + _create_person, + ), +): maxDiff = None def test_funnel_step_breakdown_event_single_person_events_with_multiple_properties(self): @@ -170,21 +183,41 @@ def test_funnel_step_breakdown_with_step_attribution(self): # event events_by_person = { "person1": [ - {"event": "sign up", "timestamp": datetime(2020, 1, 1, 12), "properties": {"$browser": "Chrome"}}, + { + "event": "sign up", + "timestamp": datetime(2020, 1, 1, 12), + "properties": {"$browser": "Chrome"}, + }, {"event": "buy", "timestamp": datetime(2020, 1, 1, 13)}, ], "person2": [ {"event": "sign up", "timestamp": datetime(2020, 1, 1, 13)}, - {"event": "buy", "timestamp": datetime(2020, 1, 2, 13), "properties": {"$browser": "Safari"}}, + { + "event": "buy", + "timestamp": datetime(2020, 1, 2, 13), + "properties": {"$browser": "Safari"}, + }, ], "person3": [ - {"event": "sign up", "timestamp": datetime(2020, 1, 2, 14), "properties": {"$browser": "Mac"}}, + { + "event": "sign up", + "timestamp": datetime(2020, 1, 2, 14), + "properties": {"$browser": "Mac"}, + }, {"event": "buy", "timestamp": datetime(2020, 1, 2, 15)}, ], "person4": [ - {"event": "sign up", "timestamp": datetime(2020, 1, 2, 15), "properties": {"$browser": 0}}, + { + "event": "sign up", + "timestamp": datetime(2020, 1, 2, 15), + "properties": {"$browser": 0}, + }, # step attribution means alakazam is valid when step = 1 - {"event": "buy", "timestamp": datetime(2020, 1, 2, 16), "properties": {"$browser": "alakazam"}}, + { + "event": "buy", + "timestamp": datetime(2020, 1, 2, 16), + "properties": {"$browser": "alakazam"}, + }, ], } people = journeys_for(events_by_person, self.team) @@ -217,21 +250,41 @@ def test_funnel_step_breakdown_with_step_one_attribution(self): # event events_by_person = { "person1": [ - {"event": "sign up", "timestamp": datetime(2020, 1, 1, 12), "properties": {"$browser": "Chrome"}}, + { + "event": "sign up", + "timestamp": datetime(2020, 1, 1, 12), + "properties": {"$browser": "Chrome"}, + }, {"event": "buy", "timestamp": datetime(2020, 1, 1, 13)}, ], "person2": [ {"event": "sign up", "timestamp": datetime(2020, 1, 1, 13)}, - {"event": "buy", "timestamp": datetime(2020, 1, 2, 13), "properties": {"$browser": "Safari"}}, + { + "event": "buy", + "timestamp": datetime(2020, 1, 2, 13), + "properties": {"$browser": "Safari"}, + }, ], "person3": [ - {"event": "sign up", "timestamp": datetime(2020, 1, 2, 14), "properties": {"$browser": "Mac"}}, + { + "event": "sign up", + "timestamp": datetime(2020, 1, 2, 14), + "properties": {"$browser": "Mac"}, + }, {"event": "buy", "timestamp": datetime(2020, 1, 2, 15)}, ], "person4": [ - {"event": "sign up", "timestamp": datetime(2020, 1, 2, 15), "properties": {"$browser": 0}}, + { + "event": "sign up", + "timestamp": datetime(2020, 1, 2, 15), + "properties": {"$browser": 0}, + }, # step attribution means alakazam is valid when step = 1 - {"event": "buy", "timestamp": datetime(2020, 1, 2, 16), "properties": {"$browser": "alakazam"}}, + { + "event": "buy", + "timestamp": datetime(2020, 1, 2, 16), + "properties": {"$browser": "alakazam"}, + }, ], } people = journeys_for(events_by_person, self.team) @@ -261,7 +314,8 @@ def test_funnel_step_breakdown_with_step_one_attribution(self): [people["person1"].uuid, people["person2"].uuid, people["person3"].uuid], ) self.assertCountEqual( - self._get_actor_ids_at_step(filter, 2, ""), [people["person1"].uuid, people["person3"].uuid] + self._get_actor_ids_at_step(filter, 2, ""), + [people["person1"].uuid, people["person3"].uuid], ) self._assert_funnel_breakdown_result_is_correct( @@ -296,7 +350,11 @@ def test_funnel_step_breakdown_with_step_one_attribution_incomplete_funnel(self) # event events_by_person = { "person1": [ - {"event": "sign up", "timestamp": datetime(2020, 1, 1, 12), "properties": {"$browser": "Chrome"}}, + { + "event": "sign up", + "timestamp": datetime(2020, 1, 1, 12), + "properties": {"$browser": "Chrome"}, + }, {"event": "buy", "timestamp": datetime(2020, 1, 1, 13)}, ], "person2": [ @@ -304,13 +362,25 @@ def test_funnel_step_breakdown_with_step_one_attribution_incomplete_funnel(self) # {"event": "buy", "timestamp": datetime(2020, 1, 2, 13), "properties": {"$browser": "Safari"}} ], "person3": [ - {"event": "sign up", "timestamp": datetime(2020, 1, 2, 14), "properties": {"$browser": "Mac"}}, + { + "event": "sign up", + "timestamp": datetime(2020, 1, 2, 14), + "properties": {"$browser": "Mac"}, + }, # {"event": "buy", "timestamp": datetime(2020, 1, 2, 15)} ], "person4": [ - {"event": "sign up", "timestamp": datetime(2020, 1, 2, 15), "properties": {"$browser": 0}}, + { + "event": "sign up", + "timestamp": datetime(2020, 1, 2, 15), + "properties": {"$browser": 0}, + }, # step attribution means alakazam is valid when step = 1 - {"event": "buy", "timestamp": datetime(2020, 1, 2, 16), "properties": {"$browser": "alakazam"}}, + { + "event": "buy", + "timestamp": datetime(2020, 1, 2, 16), + "properties": {"$browser": "alakazam"}, + }, ], } people = journeys_for(events_by_person, self.team) @@ -396,7 +466,11 @@ def test_funnel_step_non_array_breakdown_with_step_one_attribution_incomplete_fu # event events_by_person = { "person1": [ - {"event": "sign up", "timestamp": datetime(2020, 1, 1, 12), "properties": {"$browser": "Chrome"}}, + { + "event": "sign up", + "timestamp": datetime(2020, 1, 1, 12), + "properties": {"$browser": "Chrome"}, + }, {"event": "buy", "timestamp": datetime(2020, 1, 1, 13)}, ], "person2": [ @@ -404,13 +478,25 @@ def test_funnel_step_non_array_breakdown_with_step_one_attribution_incomplete_fu # {"event": "buy", "timestamp": datetime(2020, 1, 2, 13), "properties": {"$browser": "Safari"}} ], "person3": [ - {"event": "sign up", "timestamp": datetime(2020, 1, 2, 14), "properties": {"$browser": "Mac"}}, + { + "event": "sign up", + "timestamp": datetime(2020, 1, 2, 14), + "properties": {"$browser": "Mac"}, + }, # {"event": "buy", "timestamp": datetime(2020, 1, 2, 15)} ], "person4": [ - {"event": "sign up", "timestamp": datetime(2020, 1, 2, 15), "properties": {"$browser": 0}}, + { + "event": "sign up", + "timestamp": datetime(2020, 1, 2, 15), + "properties": {"$browser": 0}, + }, # step attribution means alakazam is valid when step = 1 - {"event": "buy", "timestamp": datetime(2020, 1, 2, 16), "properties": {"$browser": "alakazam"}}, + { + "event": "buy", + "timestamp": datetime(2020, 1, 2, 16), + "properties": {"$browser": "alakazam"}, + }, ], } people = journeys_for(events_by_person, self.team) @@ -482,7 +568,11 @@ def test_funnel_breakdown_correct_breakdown_props_are_chosen_for_step(self): filters = { "events": [ {"id": "sign up", "order": 0}, - {"id": "buy", "properties": [{"type": "event", "key": "$version", "value": "xyz"}], "order": 1}, + { + "id": "buy", + "properties": [{"type": "event", "key": "$version", "value": "xyz"}], + "order": 1, + }, ], "insight": INSIGHT_FUNNELS, "date_from": "2020-01-01", @@ -506,7 +596,11 @@ def test_funnel_breakdown_correct_breakdown_props_are_chosen_for_step(self): "timestamp": datetime(2020, 1, 1, 12), "properties": {"$browser": "Chrome", "$version": "xyz"}, }, - {"event": "buy", "timestamp": datetime(2020, 1, 1, 13), "properties": {"$browser": "Chrome"}}, + { + "event": "buy", + "timestamp": datetime(2020, 1, 1, 13), + "properties": {"$browser": "Chrome"}, + }, # discarded because doesn't meet criteria ], "person2": [ @@ -518,7 +612,11 @@ def test_funnel_breakdown_correct_breakdown_props_are_chosen_for_step(self): }, ], "person3": [ - {"event": "sign up", "timestamp": datetime(2020, 1, 2, 14), "properties": {"$browser": "Mac"}}, + { + "event": "sign up", + "timestamp": datetime(2020, 1, 2, 14), + "properties": {"$browser": "Mac"}, + }, { "event": "buy", "timestamp": datetime(2020, 1, 2, 15), @@ -541,7 +639,15 @@ def test_funnel_breakdown_correct_breakdown_props_are_chosen_for_step(self): self.assertCountEqual([res[0]["breakdown"] for res in result], [[""], ["Mac"], ["Safari"]]) -class TestFunnelUnorderedStepsConversionTime(ClickhouseTestMixin, funnel_conversion_time_test_factory(ClickhouseFunnelUnordered, ClickhouseFunnelUnorderedActors, _create_event, _create_person)): # type: ignore +class TestFunnelUnorderedStepsConversionTime( + ClickhouseTestMixin, + funnel_conversion_time_test_factory( # type: ignore + ClickhouseFunnelUnordered, + ClickhouseFunnelUnorderedActors, + _create_event, + _create_person, + ), +): maxDiff = None pass @@ -574,43 +680,79 @@ def test_basic_unordered_funnel(self): distinct_ids=["stopped_after_pageview1"], team_id=self.team.pk ) _create_event(team=self.team, event="$pageview", distinct_id="stopped_after_pageview1") - _create_event(team=self.team, event="user signed up", distinct_id="stopped_after_pageview1") + _create_event( + team=self.team, + event="user signed up", + distinct_id="stopped_after_pageview1", + ) person3_stopped_after_insight_view = _create_person( distinct_ids=["stopped_after_insightview"], team_id=self.team.pk ) - _create_event(team=self.team, event="user signed up", distinct_id="stopped_after_insightview") + _create_event( + team=self.team, + event="user signed up", + distinct_id="stopped_after_insightview", + ) _create_event(team=self.team, event="$pageview", distinct_id="stopped_after_insightview") _create_event(team=self.team, event="blaah blaa", distinct_id="stopped_after_insightview") - _create_event(team=self.team, event="insight viewed", distinct_id="stopped_after_insightview") + _create_event( + team=self.team, + event="insight viewed", + distinct_id="stopped_after_insightview", + ) person4_stopped_after_insight_view_reverse_order = _create_person( distinct_ids=["stopped_after_insightview2"], team_id=self.team.pk ) - _create_event(team=self.team, event="insight viewed", distinct_id="stopped_after_insightview2") + _create_event( + team=self.team, + event="insight viewed", + distinct_id="stopped_after_insightview2", + ) _create_event(team=self.team, event="$pageview", distinct_id="stopped_after_insightview2") - _create_event(team=self.team, event="user signed up", distinct_id="stopped_after_insightview2") + _create_event( + team=self.team, + event="user signed up", + distinct_id="stopped_after_insightview2", + ) person5_stopped_after_insight_view_random = _create_person( distinct_ids=["stopped_after_insightview3"], team_id=self.team.pk ) _create_event(team=self.team, event="$pageview", distinct_id="stopped_after_insightview3") - _create_event(team=self.team, event="user signed up", distinct_id="stopped_after_insightview3") + _create_event( + team=self.team, + event="user signed up", + distinct_id="stopped_after_insightview3", + ) _create_event(team=self.team, event="blaah blaa", distinct_id="stopped_after_insightview3") - _create_event(team=self.team, event="insight viewed", distinct_id="stopped_after_insightview3") + _create_event( + team=self.team, + event="insight viewed", + distinct_id="stopped_after_insightview3", + ) person6_did_only_insight_view = _create_person( distinct_ids=["stopped_after_insightview4"], team_id=self.team.pk ) _create_event(team=self.team, event="blaah blaa", distinct_id="stopped_after_insightview4") - _create_event(team=self.team, event="insight viewed", distinct_id="stopped_after_insightview4") + _create_event( + team=self.team, + event="insight viewed", + distinct_id="stopped_after_insightview4", + ) person7_did_only_pageview = _create_person(distinct_ids=["stopped_after_insightview5"], team_id=self.team.pk) _create_event(team=self.team, event="$pageview", distinct_id="stopped_after_insightview5") _create_event(team=self.team, event="blaah blaa", distinct_id="stopped_after_insightview5") person8_didnot_signup = _create_person(distinct_ids=["stopped_after_insightview6"], team_id=self.team.pk) - _create_event(team=self.team, event="insight viewed", distinct_id="stopped_after_insightview6") + _create_event( + team=self.team, + event="insight viewed", + distinct_id="stopped_after_insightview6", + ) _create_event(team=self.team, event="$pageview", distinct_id="stopped_after_insightview6") result = funnel.run() @@ -649,7 +791,11 @@ def test_basic_unordered_funnel(self): self.assertCountEqual( self._get_actor_ids_at_step(filter, -2), - [person1_stopped_after_signup.uuid, person6_did_only_insight_view.uuid, person7_did_only_pageview.uuid], + [ + person1_stopped_after_signup.uuid, + person6_did_only_insight_view.uuid, + person7_did_only_pageview.uuid, + ], ) self.assertCountEqual( @@ -691,38 +837,70 @@ def test_big_multi_step_unordered_funnel(self): person3_stopped_after_insight_view = _create_person( distinct_ids=["stopped_after_insightview"], team_id=self.team.pk ) - _create_event(team=self.team, event="user signed up", distinct_id="stopped_after_insightview") + _create_event( + team=self.team, + event="user signed up", + distinct_id="stopped_after_insightview", + ) _create_event(team=self.team, event="$pageview", distinct_id="stopped_after_insightview") _create_event(team=self.team, event="blaah blaa", distinct_id="stopped_after_insightview") - _create_event(team=self.team, event="insight viewed", distinct_id="stopped_after_insightview") + _create_event( + team=self.team, + event="insight viewed", + distinct_id="stopped_after_insightview", + ) person4_stopped_after_insight_view_reverse_order = _create_person( distinct_ids=["stopped_after_insightview2"], team_id=self.team.pk ) - _create_event(team=self.team, event="insight viewed", distinct_id="stopped_after_insightview2") + _create_event( + team=self.team, + event="insight viewed", + distinct_id="stopped_after_insightview2", + ) _create_event(team=self.team, event="crying", distinct_id="stopped_after_insightview2") - _create_event(team=self.team, event="user signed up", distinct_id="stopped_after_insightview2") + _create_event( + team=self.team, + event="user signed up", + distinct_id="stopped_after_insightview2", + ) person5_stopped_after_insight_view_random = _create_person( distinct_ids=["stopped_after_insightview3"], team_id=self.team.pk ) _create_event(team=self.team, event="$pageview", distinct_id="stopped_after_insightview3") - _create_event(team=self.team, event="user signed up", distinct_id="stopped_after_insightview3") + _create_event( + team=self.team, + event="user signed up", + distinct_id="stopped_after_insightview3", + ) _create_event(team=self.team, event="crying", distinct_id="stopped_after_insightview3") - _create_event(team=self.team, event="insight viewed", distinct_id="stopped_after_insightview3") + _create_event( + team=self.team, + event="insight viewed", + distinct_id="stopped_after_insightview3", + ) person6_did_only_insight_view = _create_person( distinct_ids=["stopped_after_insightview4"], team_id=self.team.pk ) _create_event(team=self.team, event="blaah blaa", distinct_id="stopped_after_insightview4") - _create_event(team=self.team, event="insight viewed", distinct_id="stopped_after_insightview4") + _create_event( + team=self.team, + event="insight viewed", + distinct_id="stopped_after_insightview4", + ) person7_did_only_pageview = _create_person(distinct_ids=["stopped_after_insightview5"], team_id=self.team.pk) _create_event(team=self.team, event="$pageview", distinct_id="stopped_after_insightview5") _create_event(team=self.team, event="blaah blaa", distinct_id="stopped_after_insightview5") person8_didnot_signup = _create_person(distinct_ids=["stopped_after_insightview6"], team_id=self.team.pk) - _create_event(team=self.team, event="insight viewed", distinct_id="stopped_after_insightview6") + _create_event( + team=self.team, + event="insight viewed", + distinct_id="stopped_after_insightview6", + ) _create_event(team=self.team, event="$pageview", distinct_id="stopped_after_insightview6") funnel = ClickhouseFunnelUnordered(filter, self.team) @@ -771,7 +949,10 @@ def test_big_multi_step_unordered_funnel(self): ], ) - self.assertCountEqual(self._get_actor_ids_at_step(filter, 4), [person5_stopped_after_insight_view_random.uuid]) + self.assertCountEqual( + self._get_actor_ids_at_step(filter, 4), + [person5_stopped_after_insight_view_random.uuid], + ) def test_basic_unordered_funnel_conversion_times(self): filter = Filter( @@ -792,14 +973,20 @@ def test_basic_unordered_funnel_conversion_times(self): person1_stopped_after_signup = _create_person(distinct_ids=["stopped_after_signup1"], team_id=self.team.pk) _create_event( - team=self.team, event="user signed up", distinct_id="stopped_after_signup1", timestamp="2021-05-02 00:00:00" + team=self.team, + event="user signed up", + distinct_id="stopped_after_signup1", + timestamp="2021-05-02 00:00:00", ) person2_stopped_after_one_pageview = _create_person( distinct_ids=["stopped_after_pageview1"], team_id=self.team.pk ) _create_event( - team=self.team, event="$pageview", distinct_id="stopped_after_pageview1", timestamp="2021-05-02 00:00:00" + team=self.team, + event="$pageview", + distinct_id="stopped_after_pageview1", + timestamp="2021-05-02 00:00:00", ) _create_event( team=self.team, @@ -824,11 +1011,17 @@ def test_basic_unordered_funnel_conversion_times(self): timestamp="2021-05-02 02:00:00", ) _create_event( - team=self.team, event="$pageview", distinct_id="stopped_after_insightview", timestamp="2021-05-02 04:00:00" + team=self.team, + event="$pageview", + distinct_id="stopped_after_insightview", + timestamp="2021-05-02 04:00:00", ) _create_event( - team=self.team, event="$pageview", distinct_id="stopped_after_insightview", timestamp="2021-05-03 00:00:00" + team=self.team, + event="$pageview", + distinct_id="stopped_after_insightview", + timestamp="2021-05-03 00:00:00", ) _create_event( team=self.team, @@ -870,10 +1063,16 @@ def test_basic_unordered_funnel_conversion_times(self): self.assertCountEqual( self._get_actor_ids_at_step(filter, 2), - [person2_stopped_after_one_pageview.uuid, person3_stopped_after_insight_view.uuid], + [ + person2_stopped_after_one_pageview.uuid, + person3_stopped_after_insight_view.uuid, + ], ) - self.assertCountEqual(self._get_actor_ids_at_step(filter, 3), [person3_stopped_after_insight_view.uuid]) + self.assertCountEqual( + self._get_actor_ids_at_step(filter, 3), + [person3_stopped_after_insight_view.uuid], + ) def test_single_event_unordered_funnel(self): filter = Filter( @@ -889,12 +1088,18 @@ def test_single_event_unordered_funnel(self): _create_person(distinct_ids=["stopped_after_signup1"], team_id=self.team.pk) _create_event( - team=self.team, event="user signed up", distinct_id="stopped_after_signup1", timestamp="2021-05-02 00:00:00" + team=self.team, + event="user signed up", + distinct_id="stopped_after_signup1", + timestamp="2021-05-02 00:00:00", ) _create_person(distinct_ids=["stopped_after_pageview1"], team_id=self.team.pk) _create_event( - team=self.team, event="$pageview", distinct_id="stopped_after_pageview1", timestamp="2021-05-02 00:00:00" + team=self.team, + event="$pageview", + distinct_id="stopped_after_pageview1", + timestamp="2021-05-02 00:00:00", ) _create_event( team=self.team, @@ -917,14 +1122,30 @@ def test_funnel_exclusions_invalid_params(self): ], "insight": INSIGHT_FUNNELS, "funnel_window_days": 14, - "exclusions": [{"id": "x", "type": "events", "funnel_from_step": 1, "funnel_to_step": 1}], + "exclusions": [ + { + "id": "x", + "type": "events", + "funnel_from_step": 1, + "funnel_to_step": 1, + } + ], } filter = Filter(data=filters) self.assertRaises(ValidationError, lambda: ClickhouseFunnelUnordered(filter, self.team).run()) # partial windows not allowed for unordered filter = filter.shallow_clone( - {"exclusions": [{"id": "x", "type": "events", "funnel_from_step": 0, "funnel_to_step": 1}]} + { + "exclusions": [ + { + "id": "x", + "type": "events", + "funnel_from_step": 0, + "funnel_to_step": 1, + } + ] + } ) self.assertRaises(ValidationError, lambda: ClickhouseFunnelUnordered(filter, self.team).run()) @@ -938,26 +1159,68 @@ def test_funnel_exclusions_full_window(self): "funnel_window_days": 14, "date_from": "2021-05-01 00:00:00", "date_to": "2021-05-14 00:00:00", - "exclusions": [{"id": "x", "type": "events", "funnel_from_step": 0, "funnel_to_step": 1}], + "exclusions": [ + { + "id": "x", + "type": "events", + "funnel_from_step": 0, + "funnel_to_step": 1, + } + ], } filter = Filter(data=filters) funnel = ClickhouseFunnelUnordered(filter, self.team) # event 1 person1 = _create_person(distinct_ids=["person1"], team_id=self.team.pk) - _create_event(team=self.team, event="user signed up", distinct_id="person1", timestamp="2021-05-01 01:00:00") - _create_event(team=self.team, event="paid", distinct_id="person1", timestamp="2021-05-01 02:00:00") + _create_event( + team=self.team, + event="user signed up", + distinct_id="person1", + timestamp="2021-05-01 01:00:00", + ) + _create_event( + team=self.team, + event="paid", + distinct_id="person1", + timestamp="2021-05-01 02:00:00", + ) # event 2 person2 = _create_person(distinct_ids=["person2"], team_id=self.team.pk) - _create_event(team=self.team, event="user signed up", distinct_id="person2", timestamp="2021-05-01 03:00:00") - _create_event(team=self.team, event="x", distinct_id="person2", timestamp="2021-05-01 03:30:00") - _create_event(team=self.team, event="paid", distinct_id="person2", timestamp="2021-05-01 04:00:00") + _create_event( + team=self.team, + event="user signed up", + distinct_id="person2", + timestamp="2021-05-01 03:00:00", + ) + _create_event( + team=self.team, + event="x", + distinct_id="person2", + timestamp="2021-05-01 03:30:00", + ) + _create_event( + team=self.team, + event="paid", + distinct_id="person2", + timestamp="2021-05-01 04:00:00", + ) # event 3 person3 = _create_person(distinct_ids=["person3"], team_id=self.team.pk) - _create_event(team=self.team, event="user signed up", distinct_id="person3", timestamp="2021-05-01 05:00:00") - _create_event(team=self.team, event="paid", distinct_id="person3", timestamp="2021-05-01 06:00:00") + _create_event( + team=self.team, + event="user signed up", + distinct_id="person3", + timestamp="2021-05-01 05:00:00", + ) + _create_event( + team=self.team, + event="paid", + distinct_id="person3", + timestamp="2021-05-01 06:00:00", + ) result = funnel.run() @@ -967,7 +1230,10 @@ def test_funnel_exclusions_full_window(self): self.assertEqual(result[1]["name"], "Completed 2 steps") self.assertEqual(result[1]["count"], 2) - self.assertCountEqual(self._get_actor_ids_at_step(filter, 1), [person1.uuid, person2.uuid, person3.uuid]) + self.assertCountEqual( + self._get_actor_ids_at_step(filter, 1), + [person1.uuid, person2.uuid, person3.uuid], + ) self.assertCountEqual(self._get_actor_ids_at_step(filter, 2), [person1.uuid, person3.uuid]) def test_advanced_funnel_multiple_exclusions_between_steps(self): @@ -983,56 +1249,246 @@ def test_advanced_funnel_multiple_exclusions_between_steps(self): "date_to": "2021-05-14 00:00:00", "insight": INSIGHT_FUNNELS, "exclusions": [ - {"id": "x", "type": "events", "funnel_from_step": 0, "funnel_to_step": 4}, - {"id": "y", "type": "events", "funnel_from_step": 0, "funnel_to_step": 4}, + { + "id": "x", + "type": "events", + "funnel_from_step": 0, + "funnel_to_step": 4, + }, + { + "id": "y", + "type": "events", + "funnel_from_step": 0, + "funnel_to_step": 4, + }, ], } person1 = _create_person(distinct_ids=["person1"], team_id=self.team.pk) - _create_event(team=self.team, event="user signed up", distinct_id="person1", timestamp="2021-05-01 01:00:00") - _create_event(team=self.team, event="x", distinct_id="person1", timestamp="2021-05-01 02:00:00") - _create_event(team=self.team, event="$pageview", distinct_id="person1", timestamp="2021-05-01 03:00:00") - _create_event(team=self.team, event="insight viewed", distinct_id="person1", timestamp="2021-05-01 04:00:00") - _create_event(team=self.team, event="y", distinct_id="person1", timestamp="2021-05-01 04:30:00") - _create_event(team=self.team, event="invite teammate", distinct_id="person1", timestamp="2021-05-01 05:00:00") - _create_event(team=self.team, event="pageview2", distinct_id="person1", timestamp="2021-05-01 06:00:00") + _create_event( + team=self.team, + event="user signed up", + distinct_id="person1", + timestamp="2021-05-01 01:00:00", + ) + _create_event( + team=self.team, + event="x", + distinct_id="person1", + timestamp="2021-05-01 02:00:00", + ) + _create_event( + team=self.team, + event="$pageview", + distinct_id="person1", + timestamp="2021-05-01 03:00:00", + ) + _create_event( + team=self.team, + event="insight viewed", + distinct_id="person1", + timestamp="2021-05-01 04:00:00", + ) + _create_event( + team=self.team, + event="y", + distinct_id="person1", + timestamp="2021-05-01 04:30:00", + ) + _create_event( + team=self.team, + event="invite teammate", + distinct_id="person1", + timestamp="2021-05-01 05:00:00", + ) + _create_event( + team=self.team, + event="pageview2", + distinct_id="person1", + timestamp="2021-05-01 06:00:00", + ) person2 = _create_person(distinct_ids=["person2"], team_id=self.team.pk) - _create_event(team=self.team, event="user signed up", distinct_id="person2", timestamp="2021-05-01 01:00:00") - _create_event(team=self.team, event="y", distinct_id="person2", timestamp="2021-05-01 01:30:00") - _create_event(team=self.team, event="$pageview", distinct_id="person2", timestamp="2021-05-01 02:00:00") - _create_event(team=self.team, event="insight viewed", distinct_id="person2", timestamp="2021-05-01 04:00:00") - _create_event(team=self.team, event="y", distinct_id="person2", timestamp="2021-05-01 04:30:00") - _create_event(team=self.team, event="invite teammate", distinct_id="person2", timestamp="2021-05-01 05:00:00") - _create_event(team=self.team, event="x", distinct_id="person2", timestamp="2021-05-01 05:30:00") - _create_event(team=self.team, event="pageview2", distinct_id="person2", timestamp="2021-05-01 06:00:00") + _create_event( + team=self.team, + event="user signed up", + distinct_id="person2", + timestamp="2021-05-01 01:00:00", + ) + _create_event( + team=self.team, + event="y", + distinct_id="person2", + timestamp="2021-05-01 01:30:00", + ) + _create_event( + team=self.team, + event="$pageview", + distinct_id="person2", + timestamp="2021-05-01 02:00:00", + ) + _create_event( + team=self.team, + event="insight viewed", + distinct_id="person2", + timestamp="2021-05-01 04:00:00", + ) + _create_event( + team=self.team, + event="y", + distinct_id="person2", + timestamp="2021-05-01 04:30:00", + ) + _create_event( + team=self.team, + event="invite teammate", + distinct_id="person2", + timestamp="2021-05-01 05:00:00", + ) + _create_event( + team=self.team, + event="x", + distinct_id="person2", + timestamp="2021-05-01 05:30:00", + ) + _create_event( + team=self.team, + event="pageview2", + distinct_id="person2", + timestamp="2021-05-01 06:00:00", + ) person3 = _create_person(distinct_ids=["person3"], team_id=self.team.pk) - _create_event(team=self.team, event="user signed up", distinct_id="person3", timestamp="2021-05-01 01:00:00") - _create_event(team=self.team, event="x", distinct_id="person3", timestamp="2021-05-01 01:30:00") - _create_event(team=self.team, event="$pageview", distinct_id="person3", timestamp="2021-05-01 02:00:00") - _create_event(team=self.team, event="insight viewed", distinct_id="person3", timestamp="2021-05-01 04:00:00") - _create_event(team=self.team, event="invite teammate", distinct_id="person3", timestamp="2021-05-01 05:00:00") - _create_event(team=self.team, event="x", distinct_id="person3", timestamp="2021-05-01 05:30:00") - _create_event(team=self.team, event="pageview2", distinct_id="person3", timestamp="2021-05-01 06:00:00") + _create_event( + team=self.team, + event="user signed up", + distinct_id="person3", + timestamp="2021-05-01 01:00:00", + ) + _create_event( + team=self.team, + event="x", + distinct_id="person3", + timestamp="2021-05-01 01:30:00", + ) + _create_event( + team=self.team, + event="$pageview", + distinct_id="person3", + timestamp="2021-05-01 02:00:00", + ) + _create_event( + team=self.team, + event="insight viewed", + distinct_id="person3", + timestamp="2021-05-01 04:00:00", + ) + _create_event( + team=self.team, + event="invite teammate", + distinct_id="person3", + timestamp="2021-05-01 05:00:00", + ) + _create_event( + team=self.team, + event="x", + distinct_id="person3", + timestamp="2021-05-01 05:30:00", + ) + _create_event( + team=self.team, + event="pageview2", + distinct_id="person3", + timestamp="2021-05-01 06:00:00", + ) person4 = _create_person(distinct_ids=["person4"], team_id=self.team.pk) - _create_event(team=self.team, event="user signed up", distinct_id="person4", timestamp="2021-05-01 01:00:00") - _create_event(team=self.team, event="$pageview", distinct_id="person4", timestamp="2021-05-01 02:00:00") - _create_event(team=self.team, event="insight viewed", distinct_id="person4", timestamp="2021-05-01 04:00:00") - _create_event(team=self.team, event="invite teammate", distinct_id="person4", timestamp="2021-05-01 05:00:00") - _create_event(team=self.team, event="pageview2", distinct_id="person4", timestamp="2021-05-01 06:00:00") + _create_event( + team=self.team, + event="user signed up", + distinct_id="person4", + timestamp="2021-05-01 01:00:00", + ) + _create_event( + team=self.team, + event="$pageview", + distinct_id="person4", + timestamp="2021-05-01 02:00:00", + ) + _create_event( + team=self.team, + event="insight viewed", + distinct_id="person4", + timestamp="2021-05-01 04:00:00", + ) + _create_event( + team=self.team, + event="invite teammate", + distinct_id="person4", + timestamp="2021-05-01 05:00:00", + ) + _create_event( + team=self.team, + event="pageview2", + distinct_id="person4", + timestamp="2021-05-01 06:00:00", + ) person5 = _create_person(distinct_ids=["person5"], team_id=self.team.pk) - _create_event(team=self.team, event="user signed up", distinct_id="person5", timestamp="2021-05-01 01:00:00") - _create_event(team=self.team, event="x", distinct_id="person5", timestamp="2021-05-01 01:30:00") - _create_event(team=self.team, event="$pageview", distinct_id="person5", timestamp="2021-05-01 02:00:00") - _create_event(team=self.team, event="x", distinct_id="person5", timestamp="2021-05-01 02:30:00") - _create_event(team=self.team, event="insight viewed", distinct_id="person5", timestamp="2021-05-01 04:00:00") - _create_event(team=self.team, event="y", distinct_id="person5", timestamp="2021-05-01 04:30:00") - _create_event(team=self.team, event="invite teammate", distinct_id="person5", timestamp="2021-05-01 05:00:00") - _create_event(team=self.team, event="x", distinct_id="person5", timestamp="2021-05-01 05:30:00") - _create_event(team=self.team, event="pageview2", distinct_id="person5", timestamp="2021-05-01 06:00:00") + _create_event( + team=self.team, + event="user signed up", + distinct_id="person5", + timestamp="2021-05-01 01:00:00", + ) + _create_event( + team=self.team, + event="x", + distinct_id="person5", + timestamp="2021-05-01 01:30:00", + ) + _create_event( + team=self.team, + event="$pageview", + distinct_id="person5", + timestamp="2021-05-01 02:00:00", + ) + _create_event( + team=self.team, + event="x", + distinct_id="person5", + timestamp="2021-05-01 02:30:00", + ) + _create_event( + team=self.team, + event="insight viewed", + distinct_id="person5", + timestamp="2021-05-01 04:00:00", + ) + _create_event( + team=self.team, + event="y", + distinct_id="person5", + timestamp="2021-05-01 04:30:00", + ) + _create_event( + team=self.team, + event="invite teammate", + distinct_id="person5", + timestamp="2021-05-01 05:00:00", + ) + _create_event( + team=self.team, + event="x", + distinct_id="person5", + timestamp="2021-05-01 05:30:00", + ) + _create_event( + team=self.team, + event="pageview2", + distinct_id="person5", + timestamp="2021-05-01 06:00:00", + ) filter = Filter(data=filters) funnel = ClickhouseFunnelUnordered(filter, self.team) @@ -1058,18 +1514,36 @@ def test_advanced_funnel_multiple_exclusions_between_steps(self): def test_funnel_unordered_all_events_with_properties(self): _create_person(distinct_ids=["user"], team=self.team) _create_event(event="user signed up", distinct_id="user", team=self.team) - _create_event(event="added to card", distinct_id="user", properties={"is_saved": True}, team=self.team) + _create_event( + event="added to card", + distinct_id="user", + properties={"is_saved": True}, + team=self.team, + ) filters = { "events": [ - {"type": "events", "id": "user signed up", "order": 0, "name": "user signed up", "math": "total"}, + { + "type": "events", + "id": "user signed up", + "order": 0, + "name": "user signed up", + "math": "total", + }, { "type": "events", "id": None, "order": 1, "name": "All events", "math": "total", - "properties": [{"key": "is_saved", "value": ["true"], "operator": "exact", "type": "event"}], + "properties": [ + { + "key": "is_saved", + "value": ["true"], + "operator": "exact", + "type": "event", + } + ], }, ], "funnel_window_days": 14, @@ -1084,9 +1558,17 @@ def test_funnel_unordered_all_events_with_properties(self): def test_funnel_unordered_entity_filters(self): _create_person(distinct_ids=["user"], team=self.team) - _create_event(event="user signed up", distinct_id="user", properties={"prop_a": "some value"}, team=self.team) _create_event( - event="user signed up", distinct_id="user", properties={"prop_b": "another value"}, team=self.team + event="user signed up", + distinct_id="user", + properties={"prop_a": "some value"}, + team=self.team, + ) + _create_event( + event="user signed up", + distinct_id="user", + properties={"prop_b": "another value"}, + team=self.team, ) filters = { @@ -1097,7 +1579,14 @@ def test_funnel_unordered_entity_filters(self): "order": 0, "name": "user signed up", "math": "total", - "properties": [{"key": "prop_a", "value": ["some value"], "operator": "exact", "type": "event"}], + "properties": [ + { + "key": "prop_a", + "value": ["some value"], + "operator": "exact", + "type": "event", + } + ], }, { "type": "events", @@ -1105,7 +1594,14 @@ def test_funnel_unordered_entity_filters(self): "order": 1, "name": "user signed up", "math": "total", - "properties": [{"key": "prop_b", "value": "another", "operator": "icontains", "type": "event"}], + "properties": [ + { + "key": "prop_b", + "value": "another", + "operator": "icontains", + "type": "event", + } + ], }, ], } diff --git a/posthog/queries/funnels/test/test_funnel_unordered_persons.py b/posthog/queries/funnels/test/test_funnel_unordered_persons.py index 673dee6d30826..c00e6975f5044 100644 --- a/posthog/queries/funnels/test/test_funnel_unordered_persons.py +++ b/posthog/queries/funnels/test/test_funnel_unordered_persons.py @@ -6,8 +6,12 @@ from posthog.constants import INSIGHT_FUNNELS from posthog.models.filters import Filter -from posthog.queries.funnels.funnel_unordered_persons import ClickhouseFunnelUnorderedActors -from posthog.session_recordings.queries.test.session_replay_sql import produce_replay_summary +from posthog.queries.funnels.funnel_unordered_persons import ( + ClickhouseFunnelUnorderedActors, +) +from posthog.session_recordings.queries.test.session_replay_sql import ( + produce_replay_summary, +) from posthog.test.base import ( APIBaseTest, ClickhouseTestMixin, diff --git a/posthog/queries/funnels/test/test_utils.py b/posthog/queries/funnels/test/test_utils.py index 8a71c02e6f6e5..c45a4eddcb518 100644 --- a/posthog/queries/funnels/test/test_utils.py +++ b/posthog/queries/funnels/test/test_utils.py @@ -1,6 +1,10 @@ from posthog.constants import FunnelOrderType from posthog.models.filters import Filter -from posthog.queries.funnels import ClickhouseFunnel, ClickhouseFunnelStrict, ClickhouseFunnelUnordered +from posthog.queries.funnels import ( + ClickhouseFunnel, + ClickhouseFunnelStrict, + ClickhouseFunnelUnordered, +) from posthog.queries.funnels.utils import get_funnel_order_class from posthog.test.base import BaseTest diff --git a/posthog/queries/funnels/utils.py b/posthog/queries/funnels/utils.py index 33ef56e271bd2..68f93c2d4542e 100644 --- a/posthog/queries/funnels/utils.py +++ b/posthog/queries/funnels/utils.py @@ -6,7 +6,11 @@ def get_funnel_order_class(filter: Filter) -> Type[ClickhouseFunnelBase]: - from posthog.queries.funnels import ClickhouseFunnel, ClickhouseFunnelStrict, ClickhouseFunnelUnordered + from posthog.queries.funnels import ( + ClickhouseFunnel, + ClickhouseFunnelStrict, + ClickhouseFunnelUnordered, + ) if filter.funnel_order_type == FunnelOrderType.UNORDERED: return ClickhouseFunnelUnordered diff --git a/posthog/queries/insight.py b/posthog/queries/insight.py index 294eb012d60b0..5992d16ddf1e9 100644 --- a/posthog/queries/insight.py +++ b/posthog/queries/insight.py @@ -7,7 +7,13 @@ # Wrapper around sync_execute, adding query tags for insights performance def insight_sync_execute( - query, args=None, *, team_id: int, query_type: str, filter: Optional["FilterType"] = None, **kwargs + query, + args=None, + *, + team_id: int, + query_type: str, + filter: Optional["FilterType"] = None, + **kwargs, ): tag_queries(team_id=team_id) _tag_query(query, query_type, filter) diff --git a/posthog/queries/paths/paths.py b/posthog/queries/paths/paths.py index b829d8487dddf..6a98857e3927d 100644 --- a/posthog/queries/paths/paths.py +++ b/posthog/queries/paths/paths.py @@ -104,7 +104,6 @@ def _exec_query(self) -> List[Tuple]: ) def get_query(self) -> str: - path_query = self.get_path_query() funnel_cte = "" @@ -198,7 +197,6 @@ def should_query_funnel(self) -> bool: return False def get_path_query(self) -> str: - paths_per_person_query = self.get_paths_per_person_query() self.params["edge_limit"] = self._filter.edge_limit @@ -243,7 +241,10 @@ def get_session_threshold_clause(self) -> str: # Implemented in /ee def get_target_clause(self) -> Tuple[str, Dict]: - params: Dict[str, Union[str, None]] = {"target_point": None, "secondary_target_point": None} + params: Dict[str, Union[str, None]] = { + "target_point": None, + "secondary_target_point": None, + } filtered_path_ordering_clause = self.get_filtered_path_ordering() compacting_function = self.get_array_compacting_function() diff --git a/posthog/queries/paths/paths_event_query.py b/posthog/queries/paths/paths_event_query.py index 6cc96243cc034..913307b7fdc21 100644 --- a/posthog/queries/paths/paths_event_query.py +++ b/posthog/queries/paths/paths_event_query.py @@ -22,7 +22,6 @@ class PathEventQuery(EventQuery): _filter: PathFilter def get_query(self) -> Tuple[str, Dict[str, Any]]: - funnel_paths_timestamp = "" funnel_paths_join = "" funnel_paths_filter = "" @@ -55,7 +54,13 @@ def get_query(self) -> Tuple[str, Dict[str, Any]]: ] _fields += [f"{self.EVENT_TABLE_ALIAS}.{field} AS {field}" for field in self._extra_fields] _fields += [ - get_property_string_expr("events", field, f"'{field}'", "properties", table_alias=self.EVENT_TABLE_ALIAS)[0] + get_property_string_expr( + "events", + field, + f"'{field}'", + "properties", + table_alias=self.EVENT_TABLE_ALIAS, + )[0] + f" as {field}" for field in self._extra_event_properties ] diff --git a/posthog/queries/person_distinct_id_query.py b/posthog/queries/person_distinct_id_query.py index 9e8d0606337bb..c04711fbe2370 100644 --- a/posthog/queries/person_distinct_id_query.py +++ b/posthog/queries/person_distinct_id_query.py @@ -2,7 +2,6 @@ def get_team_distinct_ids_query(team_id: int) -> str: - # ensure team_id is actually an int so we can safely interpolate into the query assert isinstance(team_id, int) diff --git a/posthog/queries/person_query.py b/posthog/queries/person_query.py index 43b86d79ec256..73a779e5aca6a 100644 --- a/posthog/queries/person_query.py +++ b/posthog/queries/person_query.py @@ -5,8 +5,14 @@ from posthog.constants import PropertyOperatorType from posthog.models import Filter from posthog.models.cohort import Cohort -from posthog.models.cohort.sql import GET_COHORTPEOPLE_BY_COHORT_ID, GET_STATIC_COHORTPEOPLE_BY_COHORT_ID -from posthog.models.cohort.util import format_precalculated_cohort_query, format_static_cohort_query +from posthog.models.cohort.sql import ( + GET_COHORTPEOPLE_BY_COHORT_ID, + GET_STATIC_COHORTPEOPLE_BY_COHORT_ID, +) +from posthog.models.cohort.util import ( + format_precalculated_cohort_query, + format_static_cohort_query, +) from posthog.models.entity import Entity from posthog.models.filters.path_filter import PathFilter from posthog.models.filters.retention_filter import RetentionFilter @@ -71,7 +77,8 @@ def __init__( self._extra_fields = self._extra_fields - {self.PERSON_PROPERTIES_ALIAS} | {"properties"} properties = self._filter.property_groups.combine_property_group( - PropertyOperatorType.AND, self._entity.property_groups if self._entity else None + PropertyOperatorType.AND, + self._entity.property_groups if self._entity else None, ) self._inner_person_properties = self._column_optimizer.property_optimizer.parse_property_groups( @@ -79,7 +86,10 @@ def __init__( ).inner def get_query( - self, prepend: Optional[Union[str, int]] = None, paginate: bool = False, filter_future_persons: bool = False + self, + prepend: Optional[Union[str, int]] = None, + paginate: bool = False, + filter_future_persons: bool = False, ) -> Tuple[str, Dict]: prepend = str(prepend) if prepend is not None else "" @@ -92,7 +102,10 @@ def get_query( person_filters_finalization_condition, person_filters_params, ) = self._get_person_filter_clauses(prepend=prepend) - multiple_cohorts_condition, multiple_cohorts_params = self._get_multiple_cohorts_clause(prepend=prepend) + ( + multiple_cohorts_condition, + multiple_cohorts_params, + ) = self._get_multiple_cohorts_clause(prepend=prepend) single_cohort_join, single_cohort_params = self._get_fast_single_cohort_clause() if paginate: order = "ORDER BY argMax(person.created_at, version) DESC, id DESC" if paginate else "" @@ -100,9 +113,11 @@ def get_query( else: order = "" limit_offset, limit_params = "", {} - search_prefiltering_condition, search_finalization_condition, search_params = self._get_search_clauses( - prepend=prepend - ) + ( + search_prefiltering_condition, + search_finalization_condition, + search_params, + ) = self._get_search_clauses(prepend=prepend) distinct_id_condition, distinct_id_params = self._get_distinct_id_clause() email_condition, email_params = self._get_email_clause() filter_future_persons_condition = ( @@ -228,7 +243,11 @@ def _get_fast_single_cohort_clause(self) -> Tuple[str, Dict]: ) {self.COHORT_TABLE_ALIAS} ON {self.COHORT_TABLE_ALIAS}.person_id = person.id """, - {"team_id": self._team_id, "cohort_id": self._cohort.pk, "version": self._cohort.version}, + { + "team_id": self._team_id, + "cohort_id": self._cohort.pk, + "version": self._cohort.version, + }, ) else: return "", {} @@ -301,7 +320,14 @@ def _get_search_clauses(self, prepend: str = "") -> Tuple[str, str, Dict]: prop_group = PropertyGroup( type=PropertyOperatorType.AND, - values=[Property(key="email", operator="icontains", value=self._filter.search, type="person")], + values=[ + Property( + key="email", + operator="icontains", + value=self._filter.search, + type="person", + ) + ], ) finalization_conditions_sql, params = parse_prop_grouped_clauses( team_id=self._team_id, @@ -315,7 +341,7 @@ def _get_search_clauses(self, prepend: str = "") -> Tuple[str, str, Dict]: ) finalization_sql = f"AND ({finalization_conditions_sql} OR {id_conditions_sql})" - prefiltering_conditions_sql, prefiltering_params = parse_prop_grouped_clauses( + (prefiltering_conditions_sql, prefiltering_params,) = parse_prop_grouped_clauses( team_id=self._team_id, property_group=prop_group, prepend=f"search_pre_{prepend}", @@ -360,7 +386,8 @@ def _add_distinct_id_join_if_needed(self, query: str, params: Dict[Any, Any]) -> GROUP BY person.* ORDER BY created_at desc, id desc """.format( - person_query=query, distinct_id_query=get_team_distinct_ids_query(self._team_id) + person_query=query, + distinct_id_query=get_team_distinct_ids_query(self._team_id), ), params, ) @@ -371,7 +398,9 @@ def _get_email_clause(self) -> Tuple[str, Dict]: if self._filter.email: return prop_filter_json_extract( - Property(key="email", value=self._filter.email, type="person"), 0, prepend="_email" + Property(key="email", value=self._filter.email, type="person"), + 0, + prepend="_email", ) return "", {} diff --git a/posthog/queries/properties_timeline/properties_timeline.py b/posthog/queries/properties_timeline/properties_timeline.py index 328c0da8fa03c..578a9dee85620 100644 --- a/posthog/queries/properties_timeline/properties_timeline.py +++ b/posthog/queries/properties_timeline/properties_timeline.py @@ -5,7 +5,10 @@ from posthog.models.filters.properties_timeline_filter import PropertiesTimelineFilter from posthog.models.group.group import Group from posthog.models.person.person import Person -from posthog.models.property.util import extract_tables_and_properties, get_single_or_multi_property_string_expr +from posthog.models.property.util import ( + extract_tables_and_properties, + get_single_or_multi_property_string_expr, +) from posthog.models.team.team import Team from posthog.queries.insight import insight_sync_execute from posthog.queries.trends.util import offset_time_series_date_by_interval @@ -87,7 +90,9 @@ def run( filter = filter.shallow_clone( { "date_to": offset_time_series_date_by_interval( - cast(datetime.datetime, filter.date_from), filter=filter, team=team + cast(datetime.datetime, filter.date_from), + filter=filter, + team=team, ) } ) @@ -120,7 +125,10 @@ def run( actor_properties_column=actor_properties_column, ) - params = {**event_query_params, "actor_id": actor.uuid if isinstance(actor, Person) else actor.group_key} + params = { + **event_query_params, + "actor_id": actor.uuid if isinstance(actor, Person) else actor.group_key, + } raw_query_result = insight_sync_execute( formatted_sql, {**params, **filter.hogql_context.values}, diff --git a/posthog/queries/property_values.py b/posthog/queries/property_values.py index d5d37a076e869..a8b943f25d1d2 100644 --- a/posthog/queries/property_values.py +++ b/posthog/queries/property_values.py @@ -3,7 +3,10 @@ from django.utils import timezone from posthog.models.event.sql import SELECT_PROP_VALUES_SQL_WITH_FILTER -from posthog.models.person.sql import SELECT_PERSON_PROP_VALUES_SQL, SELECT_PERSON_PROP_VALUES_SQL_WITH_FILTER +from posthog.models.person.sql import ( + SELECT_PERSON_PROP_VALUES_SQL, + SELECT_PERSON_PROP_VALUES_SQL_WITH_FILTER, +) from posthog.models.property.util import get_property_string_expr from posthog.models.team import Team from posthog.queries.insight import insight_sync_execute @@ -11,7 +14,10 @@ def get_property_values_for_key( - key: str, team: Team, event_names: Optional[List[str]] = None, value: Optional[str] = None + key: str, + team: Team, + event_names: Optional[List[str]] = None, + value: Optional[str] = None, ): property_field, mat_column_exists = get_property_string_expr("events", key, "%(key)s", "properties") parsed_date_from = "AND timestamp >= '{}'".format( diff --git a/posthog/queries/query_date_range.py b/posthog/queries/query_date_range.py index 208bf0207843d..e0604c3b44b91 100644 --- a/posthog/queries/query_date_range.py +++ b/posthog/queries/query_date_range.py @@ -10,8 +10,16 @@ from posthog.models.filters.mixins.interval import IntervalMixin from posthog.models.team import Team -from posthog.queries.util import TIME_IN_SECONDS, get_earliest_timestamp, get_start_of_interval_sql -from posthog.utils import DEFAULT_DATE_FROM_DAYS, relative_date_parse, relative_date_parse_with_delta_mapping +from posthog.queries.util import ( + TIME_IN_SECONDS, + get_earliest_timestamp, + get_start_of_interval_sql, +) +from posthog.utils import ( + DEFAULT_DATE_FROM_DAYS, + relative_date_parse, + relative_date_parse_with_delta_mapping, +) class QueryDateRange: @@ -28,7 +36,13 @@ class QueryDateRange: _table: str _should_round: Optional[bool] - def __init__(self, filter: AnyFilter, team: Team, should_round: Optional[bool] = None, table="") -> None: + def __init__( + self, + filter: AnyFilter, + team: Team, + should_round: Optional[bool] = None, + table="", + ) -> None: filter.team = team # This is a dirty - but the easiest - way to get the team into the filter self._filter = filter self._team = team @@ -97,7 +111,10 @@ def date_to(self) -> Tuple[str, Dict]: date_to_query = self.date_to_clause date_to = self.date_to_param - date_to_param = {"date_to": date_to.strftime("%Y-%m-%d %H:%M:%S"), "timezone": self._team.timezone} + date_to_param = { + "date_to": date_to.strftime("%Y-%m-%d %H:%M:%S"), + "timezone": self._team.timezone, + } return date_to_query, date_to_param @@ -106,7 +123,10 @@ def date_from(self) -> Tuple[str, Dict]: date_from_query = self.date_from_clause date_from = self.date_from_param - date_from_param = {"date_from": date_from.strftime("%Y-%m-%d %H:%M:%S"), "timezone": self._team.timezone} + date_from_param = { + "date_from": date_from.strftime("%Y-%m-%d %H:%M:%S"), + "timezone": self._team.timezone, + } return date_from_query, date_from_param diff --git a/posthog/queries/retention/__init__.py b/posthog/queries/retention/__init__.py index f0817c016bb5c..c3d1590058eea 100644 --- a/posthog/queries/retention/__init__.py +++ b/posthog/queries/retention/__init__.py @@ -1,7 +1,9 @@ from posthog.settings import EE_AVAILABLE if EE_AVAILABLE: - from ee.clickhouse.queries.retention.retention import ClickhouseRetention as Retention + from ee.clickhouse.queries.retention.retention import ( + ClickhouseRetention as Retention, + ) else: from posthog.queries.retention.retention import Retention # type: ignore diff --git a/posthog/queries/retention/actors_query.py b/posthog/queries/retention/actors_query.py index ef31f6fd8c473..5a49c510a3240 100644 --- a/posthog/queries/retention/actors_query.py +++ b/posthog/queries/retention/actors_query.py @@ -99,7 +99,10 @@ def build_actor_activity_query( aggregate_users_by_distinct_id: Optional[bool] = None, retention_events_query=RetentionEventsQuery, ) -> Tuple[str, Dict[str, Any]]: - from posthog.queries.retention import build_returning_event_query, build_target_event_query + from posthog.queries.retention import ( + build_returning_event_query, + build_target_event_query, + ) """ The retention actor query is used to retrieve something of the form: @@ -134,7 +137,8 @@ def build_actor_activity_query( } query = RETENTION_BREAKDOWN_ACTOR_SQL.format( - returning_event_query=returning_event_query, target_event_query=target_event_query + returning_event_query=returning_event_query, + target_event_query=target_event_query, ) return query, all_params @@ -147,7 +151,6 @@ def _build_actor_query( selected_interval: Optional[int] = None, retention_events_query=RetentionEventsQuery, ) -> Tuple[str, Dict[str, Any]]: - actor_activity_query, actor_activity_query_params = build_actor_activity_query( filter=filter, team=team, @@ -157,7 +160,11 @@ def _build_actor_query( retention_events_query=retention_events_query, ) - params = {"offset": filter.offset, "limit": filter.limit or 100, **actor_activity_query_params} + params = { + "offset": filter.offset, + "limit": filter.limit or 100, + **actor_activity_query_params, + } actor_query_template = """ SELECT actor_id, diff --git a/posthog/queries/retention/retention.py b/posthog/queries/retention/retention.py index 145ee1404c37b..24cbe95376e93 100644 --- a/posthog/queries/retention/retention.py +++ b/posthog/queries/retention/retention.py @@ -6,7 +6,10 @@ from posthog.models.filters.retention_filter import RetentionFilter from posthog.models.team import Team from posthog.queries.insight import insight_sync_execute -from posthog.queries.retention.actors_query import RetentionActorsByPeriod, build_actor_activity_query +from posthog.queries.retention.actors_query import ( + RetentionActorsByPeriod, + build_actor_activity_query, +) from posthog.queries.retention.retention_events_query import RetentionEventsQuery from posthog.queries.retention.sql import RETENTION_BREAKDOWN_SQL from posthog.queries.retention.types import BreakdownValues, CohortKey @@ -49,7 +52,9 @@ def _get_retention_by_breakdown_values( "count": correct_result_for_sampling(count, filter.sampling_factor), "people": [], "people_url": self._construct_people_url_for_trend_breakdown_interval( - filter=filter, breakdown_values=breakdown_values, selected_interval=intervals_from_base + filter=filter, + breakdown_values=breakdown_values, + selected_interval=intervals_from_base, ), } for (breakdown_values, intervals_from_base, count) in result @@ -58,10 +63,17 @@ def _get_retention_by_breakdown_values( return result_dict def _construct_people_url_for_trend_breakdown_interval( - self, filter: RetentionFilter, selected_interval: int, breakdown_values: BreakdownValues + self, + filter: RetentionFilter, + selected_interval: int, + breakdown_values: BreakdownValues, ): params = RetentionFilter( - {**filter._data, "breakdown_values": breakdown_values, "selected_interval": selected_interval}, + { + **filter._data, + "breakdown_values": breakdown_values, + "selected_interval": selected_interval, + }, ).to_params() return f"{self._base_uri}api/person/retention/?{urlencode(params)}" @@ -69,7 +81,10 @@ def process_breakdown_table_result(self, resultset: Dict[CohortKey, Dict[str, An result = [ { "values": [ - resultset.get(CohortKey(breakdown_values, interval), {"count": 0, "people": []}) + resultset.get( + CohortKey(breakdown_values, interval), + {"count": 0, "people": []}, + ) for interval in range(filter.total_intervals) ], "label": "::".join(map(str, breakdown_values)), @@ -84,7 +99,12 @@ def process_breakdown_table_result(self, resultset: Dict[CohortKey, Dict[str, An return result - def process_table_result(self, resultset: Dict[CohortKey, Dict[str, Any]], filter: RetentionFilter, team: Team): + def process_table_result( + self, + resultset: Dict[CohortKey, Dict[str, Any]], + filter: RetentionFilter, + team: Team, + ): """ Constructs a response for the rest api when there is no breakdown specified @@ -96,7 +116,11 @@ def process_table_result(self, resultset: Dict[CohortKey, Dict[str, Any]], filte def construct_url(first_day): params = RetentionFilter( - {**filter._data, "display": "ActionsTable", "breakdown_values": [first_day]}, + { + **filter._data, + "display": "ActionsTable", + "breakdown_values": [first_day], + }, ).to_params() return "/api/person/retention/?" f"{urlencode(params)}" diff --git a/posthog/queries/retention/retention_events_query.py b/posthog/queries/retention/retention_events_query.py index a3adba8b7bda6..609f66387e865 100644 --- a/posthog/queries/retention/retention_events_query.py +++ b/posthog/queries/retention/retention_events_query.py @@ -38,7 +38,6 @@ def __init__( ) def get_query(self) -> Tuple[str, Dict[str, Any]]: - _fields = [ self.get_timestamp_field(), self.target_field(), @@ -176,7 +175,9 @@ def target_field(self) -> str: def get_timestamp_field(self) -> str: start_of_inteval_sql = get_start_of_interval_sql( - self._filter.period, source=f"{self.EVENT_TABLE_ALIAS}.timestamp", team=self._team + self._filter.period, + source=f"{self.EVENT_TABLE_ALIAS}.timestamp", + team=self._team, ) if self._event_query_type == RetentionQueryType.TARGET: return f"DISTINCT {start_of_inteval_sql} AS event_date" diff --git a/posthog/queries/stickiness/__init__.py b/posthog/queries/stickiness/__init__.py index 6e3acf68fdaa8..421459fd7cfdd 100644 --- a/posthog/queries/stickiness/__init__.py +++ b/posthog/queries/stickiness/__init__.py @@ -2,7 +2,9 @@ if EE_AVAILABLE: from ee.clickhouse.queries.stickiness import ClickhouseStickiness as Stickiness - from ee.clickhouse.queries.stickiness import ClickhouseStickinessActors as StickinessActors + from ee.clickhouse.queries.stickiness import ( + ClickhouseStickinessActors as StickinessActors, + ) else: from posthog.queries.stickiness.stickiness import Stickiness # type: ignore from posthog.queries.stickiness.stickiness_actors import StickinessActors # type: ignore diff --git a/posthog/queries/stickiness/stickiness.py b/posthog/queries/stickiness/stickiness.py index 2a43419be00e1..08bea51c8b042 100644 --- a/posthog/queries/stickiness/stickiness.py +++ b/posthog/queries/stickiness/stickiness.py @@ -20,7 +20,6 @@ class Stickiness: actor_query_class = StickinessActors def run(self, filter: StickinessFilter, team: Team, *args, **kwargs) -> List[Dict[str, Any]]: - response = [] for entity in filter.entities: if entity.type == TREND_FILTER_TYPE_ACTIONS and entity.id is not None: @@ -44,14 +43,26 @@ def stickiness(self, entity: Entity, filter: StickinessFilter, team: Team) -> Di counts = insight_sync_execute( query, - {**event_params, **filter.hogql_context.values, "num_intervals": filter.total_intervals}, + { + **event_params, + **filter.hogql_context.values, + "num_intervals": filter.total_intervals, + }, query_type="stickiness", filter=filter, team_id=team.pk, ) return self.process_result(counts, filter, entity) - def people(self, target_entity: Entity, filter: StickinessFilter, team: Team, request, *args, **kwargs): + def people( + self, + target_entity: Entity, + filter: StickinessFilter, + team: Team, + request, + *args, + **kwargs, + ): _, serialized_actors, _ = self.actor_query_class(entity=target_entity, filter=filter, team=team).get_actors() return serialized_actors diff --git a/posthog/queries/stickiness/stickiness_event_query.py b/posthog/queries/stickiness/stickiness_event_query.py index df7fb280b37b0..0e70af72bb997 100644 --- a/posthog/queries/stickiness/stickiness_event_query.py +++ b/posthog/queries/stickiness/stickiness_event_query.py @@ -20,7 +20,6 @@ def __init__(self, entity: Entity, *args, **kwargs): super().__init__(*args, **kwargs) def get_query(self) -> Tuple[str, Dict[str, Any]]: - prop_query, prop_params = self._get_prop_groups( self._filter.property_groups.combine_property_group(PropertyOperatorType.AND, self._entity.property_groups), person_properties_mode=get_person_properties_mode(self._team), diff --git a/posthog/queries/test/test_base.py b/posthog/queries/test/test_base.py index 0710babe19525..bccc9ca60a53e 100644 --- a/posthog/queries/test/test_base.py +++ b/posthog/queries/test/test_base.py @@ -21,7 +21,10 @@ def test_determine_compared_filter(self): self.assertIsInstance(compared_filter, PathFilter) self.assertDictContainsSubset( - {"date_from": "2020-05-16T00:00:00+00:00", "date_to": "2020-05-22T23:59:59.999999+00:00"}, + { + "date_from": "2020-05-16T00:00:00+00:00", + "date_to": "2020-05-22T23:59:59.999999+00:00", + }, compared_filter.to_dict(), ) @@ -186,7 +189,8 @@ def test_match_property_date_operators(self): self.assertTrue(match_property(property_a, {"key": datetime.datetime(2022, 4, 30, 1, 2, 3)})) self.assertTrue( match_property( - property_a, {"key": datetime.datetime(2022, 4, 30, 1, 2, 3, tzinfo=tz.gettz("Europe/Madrid"))} + property_a, + {"key": datetime.datetime(2022, 4, 30, 1, 2, 3, tzinfo=tz.gettz("Europe/Madrid"))}, ) ) self.assertTrue(match_property(property_a, {"key": parser.parse("2022-04-30")})) diff --git a/posthog/queries/test/test_lifecycle.py b/posthog/queries/test/test_lifecycle.py index bafbf6bbdff5e..6bb34bfd7d143 100644 --- a/posthog/queries/test/test_lifecycle.py +++ b/posthog/queries/test/test_lifecycle.py @@ -34,7 +34,10 @@ def _create_events(self, data, event="$pageview"): _create_person( team_id=self.team.pk, distinct_ids=[id], - properties={"name": id, **({"email": "test@posthog.com"} if id == "p1" else {})}, + properties={ + "name": id, + **({"email": "test@posthog.com"} if id == "p1" else {}), + }, ) ) for timestamp in timestamps: @@ -241,14 +244,34 @@ def test_lifecycle_trend_prop_filtering(self): ) _create_person(team_id=self.team.pk, distinct_ids=["p2"], properties={"name": "p2"}) - _create_event(team=self.team, event="$pageview", distinct_id="p2", timestamp="2020-01-09T12:00:00Z") - _create_event(team=self.team, event="$pageview", distinct_id="p2", timestamp="2020-01-12T12:00:00Z") + _create_event( + team=self.team, + event="$pageview", + distinct_id="p2", + timestamp="2020-01-09T12:00:00Z", + ) + _create_event( + team=self.team, + event="$pageview", + distinct_id="p2", + timestamp="2020-01-12T12:00:00Z", + ) _create_person(team_id=self.team.pk, distinct_ids=["p3"], properties={"name": "p3"}) - _create_event(team=self.team, event="$pageview", distinct_id="p3", timestamp="2020-01-12T12:00:00Z") + _create_event( + team=self.team, + event="$pageview", + distinct_id="p3", + timestamp="2020-01-12T12:00:00Z", + ) _create_person(team_id=self.team.pk, distinct_ids=["p4"], properties={"name": "p4"}) - _create_event(team=self.team, event="$pageview", distinct_id="p4", timestamp="2020-01-15T12:00:00Z") + _create_event( + team=self.team, + event="$pageview", + distinct_id="p4", + timestamp="2020-01-15T12:00:00Z", + ) result = Trends().run( Filter( @@ -352,14 +375,34 @@ def test_lifecycle_trend_person_prop_filtering(self): ) _create_person(team_id=self.team.pk, distinct_ids=["p2"], properties={"name": "p2"}) - _create_event(team=self.team, event="$pageview", distinct_id="p2", timestamp="2020-01-09T12:00:00Z") - _create_event(team=self.team, event="$pageview", distinct_id="p2", timestamp="2020-01-12T12:00:00Z") + _create_event( + team=self.team, + event="$pageview", + distinct_id="p2", + timestamp="2020-01-09T12:00:00Z", + ) + _create_event( + team=self.team, + event="$pageview", + distinct_id="p2", + timestamp="2020-01-12T12:00:00Z", + ) _create_person(team_id=self.team.pk, distinct_ids=["p3"], properties={"name": "p3"}) - _create_event(team=self.team, event="$pageview", distinct_id="p3", timestamp="2020-01-12T12:00:00Z") + _create_event( + team=self.team, + event="$pageview", + distinct_id="p3", + timestamp="2020-01-12T12:00:00Z", + ) _create_person(team_id=self.team.pk, distinct_ids=["p4"], properties={"name": "p4"}) - _create_event(team=self.team, event="$pageview", distinct_id="p4", timestamp="2020-01-15T12:00:00Z") + _create_event( + team=self.team, + event="$pageview", + distinct_id="p4", + timestamp="2020-01-15T12:00:00Z", + ) result = Trends().run( Filter( @@ -392,15 +435,44 @@ def test_lifecycle_trend_person_prop_filtering(self): def test_lifecycle_trends_distinct_id_repeat(self): with freeze_time("2020-01-12T12:00:00Z"): - _create_person(team_id=self.team.pk, distinct_ids=["p1", "another_p1"], properties={"name": "p1"}) + _create_person( + team_id=self.team.pk, + distinct_ids=["p1", "another_p1"], + properties={"name": "p1"}, + ) - _create_event(team=self.team, event="$pageview", distinct_id="p1", timestamp="2020-01-12T12:00:00Z") - _create_event(team=self.team, event="$pageview", distinct_id="another_p1", timestamp="2020-01-14T12:00:00Z") - _create_event(team=self.team, event="$pageview", distinct_id="p1", timestamp="2020-01-15T12:00:00Z") + _create_event( + team=self.team, + event="$pageview", + distinct_id="p1", + timestamp="2020-01-12T12:00:00Z", + ) + _create_event( + team=self.team, + event="$pageview", + distinct_id="another_p1", + timestamp="2020-01-14T12:00:00Z", + ) + _create_event( + team=self.team, + event="$pageview", + distinct_id="p1", + timestamp="2020-01-15T12:00:00Z", + ) - _create_event(team=self.team, event="$pageview", distinct_id="p1", timestamp="2020-01-17T12:00:00Z") + _create_event( + team=self.team, + event="$pageview", + distinct_id="p1", + timestamp="2020-01-17T12:00:00Z", + ) - _create_event(team=self.team, event="$pageview", distinct_id="p1", timestamp="2020-01-19T12:00:00Z") + _create_event( + team=self.team, + event="$pageview", + distinct_id="p1", + timestamp="2020-01-19T12:00:00Z", + ) result = Trends().run( Filter( @@ -495,7 +567,10 @@ def test_lifecycle_trend_people_paginated(self): person_id = "person{}".format(i) _create_person(team_id=self.team.pk, distinct_ids=[person_id]) _create_event( - team=self.team, event="$pageview", distinct_id=person_id, timestamp="2020-01-15T12:00:00Z" + team=self.team, + event="$pageview", + distinct_id=person_id, + timestamp="2020-01-15T12:00:00Z", ) # even if set to hour 6 it should default to beginning of day and include all pageviews above result = self.client.get( @@ -635,7 +710,15 @@ def test_lifecycle_trend_weeks(self): ) self.assertEqual( - result[0]["days"], ["2020-02-03", "2020-02-10", "2020-02-17", "2020-02-24", "2020-03-02", "2020-03-09"] + result[0]["days"], + [ + "2020-02-03", + "2020-02-10", + "2020-02-17", + "2020-02-24", + "2020-03-02", + "2020-03-09", + ], ) assertLifecycleResults( @@ -812,7 +895,10 @@ def test_timezones(self): assertLifecycleResults( result_pacific, [ - {"status": "dormant", "data": [-1.0, -2.0, -1.0, 0.0, -2.0, 0.0, -1.0, 0.0]}, + { + "status": "dormant", + "data": [-1.0, -2.0, -1.0, 0.0, -2.0, 0.0, -1.0, 0.0], + }, {"status": "new", "data": [1, 0, 0, 1, 0, 0, 0, 0]}, {"status": "resurrecting", "data": [1, 1, 0, 1, 0, 1, 0, 1]}, {"status": "returning", "data": [0, 0, 0, 0, 0, 0, 0, 0]}, diff --git a/posthog/queries/test/test_paths.py b/posthog/queries/test/test_paths.py index c7e3df9ced0a9..45f09a9ca5787 100644 --- a/posthog/queries/test/test_paths.py +++ b/posthog/queries/test/test_paths.py @@ -53,7 +53,11 @@ def test_current_url_paths_and_logic(self): ] ) - _create_person(team_id=self.team.pk, distinct_ids=["person_1"], properties={"email": "test@posthog.com"}) + _create_person( + team_id=self.team.pk, + distinct_ids=["person_1"], + properties={"email": "test@posthog.com"}, + ) events.append( _create_event( properties={"$current_url": "/"}, @@ -191,7 +195,10 @@ def test_current_url_paths_and_logic(self): date_from = now() - relativedelta(days=7) date_to = now() + relativedelta(days=7) - date_params = {"date_from": date_from.strftime("%Y-%m-%d"), "date_to": date_to.strftime("%Y-%m-%d")} + date_params = { + "date_from": date_from.strftime("%Y-%m-%d"), + "date_to": date_to.strftime("%Y-%m-%d"), + } filter = PathFilter(team=self.team, data={**date_params}) response = Paths(team=self.team, filter=filter).run(team=self.team, filter=filter) @@ -204,7 +211,10 @@ def test_current_url_paths_and_logic(self): date_from = now() + relativedelta(days=7) date_to = now() - relativedelta(days=7) - date_params = {"date_from": date_from.strftime("%Y-%m-%d"), "date_to": date_to.strftime("%Y-%m-%d")} + date_params = { + "date_from": date_from.strftime("%Y-%m-%d"), + "date_to": date_to.strftime("%Y-%m-%d"), + } filter = PathFilter(team=self.team, data={**date_params}) response = Paths(team=self.team, filter=filter).run(team=self.team, filter=filter) self.assertEqual(len(response), 0) @@ -215,18 +225,86 @@ def test_custom_event_paths(self): _create_person(team_id=self.team.pk, distinct_ids=["person_3"]) _create_person(team_id=self.team.pk, distinct_ids=["person_4"]) - _create_event(distinct_id="person_1", event="custom_event_1", team=self.team, properties={}), - _create_event(distinct_id="person_1", event="custom_event_3", team=self.team, properties={}), - _create_event( - properties={"$current_url": "/"}, distinct_id="person_1", event="$pageview", team=self.team - ), # should be ignored, - _create_event(distinct_id="person_2", event="custom_event_1", team=self.team, properties={}), - _create_event(distinct_id="person_2", event="custom_event_2", team=self.team, properties={}), - _create_event(distinct_id="person_2", event="custom_event_3", team=self.team, properties={}), - _create_event(distinct_id="person_3", event="custom_event_2", team=self.team, properties={}), - _create_event(distinct_id="person_3", event="custom_event_1", team=self.team, properties={}), - _create_event(distinct_id="person_4", event="custom_event_1", team=self.team, properties={}), - _create_event(distinct_id="person_4", event="custom_event_2", team=self.team, properties={}), + ( + _create_event( + distinct_id="person_1", + event="custom_event_1", + team=self.team, + properties={}, + ), + ) + ( + _create_event( + distinct_id="person_1", + event="custom_event_3", + team=self.team, + properties={}, + ), + ) + ( + _create_event( + properties={"$current_url": "/"}, + distinct_id="person_1", + event="$pageview", + team=self.team, + ), + ) # should be ignored, + ( + _create_event( + distinct_id="person_2", + event="custom_event_1", + team=self.team, + properties={}, + ), + ) + ( + _create_event( + distinct_id="person_2", + event="custom_event_2", + team=self.team, + properties={}, + ), + ) + ( + _create_event( + distinct_id="person_2", + event="custom_event_3", + team=self.team, + properties={}, + ), + ) + ( + _create_event( + distinct_id="person_3", + event="custom_event_2", + team=self.team, + properties={}, + ), + ) + ( + _create_event( + distinct_id="person_3", + event="custom_event_1", + team=self.team, + properties={}, + ), + ) + ( + _create_event( + distinct_id="person_4", + event="custom_event_1", + team=self.team, + properties={}, + ), + ) + ( + _create_event( + distinct_id="person_4", + event="custom_event_2", + team=self.team, + properties={}, + ), + ) filter = PathFilter(team=self.team, data={"path_type": "custom_event"}) response = Paths(team=self.team, filter=filter).run(team=self.team, filter=filter) @@ -253,21 +331,93 @@ def test_custom_hogql_paths(self): _create_person(team_id=self.team.pk, distinct_ids=["person_3"]) _create_person(team_id=self.team.pk, distinct_ids=["person_4"]) - _create_event(distinct_id="person_1", event="custom_event_1", team=self.team, properties={"a": "!"}), - _create_event(distinct_id="person_1", event="custom_event_3", team=self.team, properties={"a": "!"}), - _create_event( - properties={"$current_url": "/"}, distinct_id="person_1", event="$pageview", team=self.team - ), # should be ignored, - _create_event(distinct_id="person_2", event="custom_event_1", team=self.team, properties={"a": "!"}), - _create_event(distinct_id="person_2", event="custom_event_2", team=self.team, properties={"a": "!"}), - _create_event(distinct_id="person_2", event="custom_event_3", team=self.team, properties={"a": "!"}), - _create_event(distinct_id="person_3", event="custom_event_2", team=self.team, properties={"a": "!"}), - _create_event(distinct_id="person_3", event="custom_event_1", team=self.team, properties={"a": "!"}), - _create_event(distinct_id="person_4", event="custom_event_1", team=self.team, properties={"a": "!"}), - _create_event(distinct_id="person_4", event="custom_event_2", team=self.team, properties={"a": "!"}), + ( + _create_event( + distinct_id="person_1", + event="custom_event_1", + team=self.team, + properties={"a": "!"}, + ), + ) + ( + _create_event( + distinct_id="person_1", + event="custom_event_3", + team=self.team, + properties={"a": "!"}, + ), + ) + ( + _create_event( + properties={"$current_url": "/"}, + distinct_id="person_1", + event="$pageview", + team=self.team, + ), + ) # should be ignored, + ( + _create_event( + distinct_id="person_2", + event="custom_event_1", + team=self.team, + properties={"a": "!"}, + ), + ) + ( + _create_event( + distinct_id="person_2", + event="custom_event_2", + team=self.team, + properties={"a": "!"}, + ), + ) + ( + _create_event( + distinct_id="person_2", + event="custom_event_3", + team=self.team, + properties={"a": "!"}, + ), + ) + ( + _create_event( + distinct_id="person_3", + event="custom_event_2", + team=self.team, + properties={"a": "!"}, + ), + ) + ( + _create_event( + distinct_id="person_3", + event="custom_event_1", + team=self.team, + properties={"a": "!"}, + ), + ) + ( + _create_event( + distinct_id="person_4", + event="custom_event_1", + team=self.team, + properties={"a": "!"}, + ), + ) + ( + _create_event( + distinct_id="person_4", + event="custom_event_2", + team=self.team, + properties={"a": "!"}, + ), + ) filter = PathFilter( - data={"path_type": "hogql", "paths_hogql_expression": "event || properties.a"}, team=self.team + data={ + "path_type": "hogql", + "paths_hogql_expression": "event || properties.a", + }, + team=self.team, ) response = Paths(team=self.team, filter=filter).run(team=self.team, filter=filter) @@ -293,17 +443,78 @@ def test_screen_paths(self): _create_person(team_id=self.team.pk, distinct_ids=["person_3"]) _create_person(team_id=self.team.pk, distinct_ids=["person_4"]) - _create_event(properties={"$screen_name": "/"}, distinct_id="person_1", event="$screen", team=self.team), - _create_event(properties={"$screen_name": "/about"}, distinct_id="person_1", event="$screen", team=self.team), - _create_event(properties={"$screen_name": "/"}, distinct_id="person_2b", event="$screen", team=self.team), - _create_event( - properties={"$screen_name": "/pricing"}, distinct_id="person_2a", event="$screen", team=self.team - ), - _create_event(properties={"$screen_name": "/about"}, distinct_id="person_2b", event="$screen", team=self.team), - _create_event(properties={"$screen_name": "/pricing"}, distinct_id="person_3", event="$screen", team=self.team), - _create_event(properties={"$screen_name": "/"}, distinct_id="person_3", event="$screen", team=self.team), - _create_event(properties={"$screen_name": "/"}, distinct_id="person_4", event="$screen", team=self.team), - _create_event(properties={"$screen_name": "/pricing"}, distinct_id="person_4", event="$screen", team=self.team), + ( + _create_event( + properties={"$screen_name": "/"}, + distinct_id="person_1", + event="$screen", + team=self.team, + ), + ) + ( + _create_event( + properties={"$screen_name": "/about"}, + distinct_id="person_1", + event="$screen", + team=self.team, + ), + ) + ( + _create_event( + properties={"$screen_name": "/"}, + distinct_id="person_2b", + event="$screen", + team=self.team, + ), + ) + ( + _create_event( + properties={"$screen_name": "/pricing"}, + distinct_id="person_2a", + event="$screen", + team=self.team, + ), + ) + ( + _create_event( + properties={"$screen_name": "/about"}, + distinct_id="person_2b", + event="$screen", + team=self.team, + ), + ) + ( + _create_event( + properties={"$screen_name": "/pricing"}, + distinct_id="person_3", + event="$screen", + team=self.team, + ), + ) + ( + _create_event( + properties={"$screen_name": "/"}, + distinct_id="person_3", + event="$screen", + team=self.team, + ), + ) + ( + _create_event( + properties={"$screen_name": "/"}, + distinct_id="person_4", + event="$screen", + team=self.team, + ), + ) + ( + _create_event( + properties={"$screen_name": "/pricing"}, + distinct_id="person_4", + event="$screen", + team=self.team, + ), + ) filter = PathFilter(team=self.team, data={"path_type": "$screen"}) response = Paths(team=self.team, filter=filter).run(team=self.team, filter=filter) @@ -329,47 +540,82 @@ def test_paths_properties_filter(self): _create_person(team_id=self.team.pk, distinct_ids=["person_3"]) _create_person(team_id=self.team.pk, distinct_ids=["person_4"]) - _create_event( - properties={"$current_url": "/", "$browser": "Chrome"}, - distinct_id="person_1", - event="$pageview", - team=self.team, - ), - _create_event( - properties={"$current_url": "/about", "$browser": "Chrome"}, - distinct_id="person_1", - event="$pageview", - team=self.team, - ), - _create_event( - properties={"$current_url": "/", "$browser": "Chrome"}, - distinct_id="person_2", - event="$pageview", - team=self.team, - ), - _create_event( - properties={"$current_url": "/pricing", "$browser": "Chrome"}, - distinct_id="person_2", - event="$pageview", - team=self.team, - ), - _create_event( - properties={"$current_url": "/about", "$browser": "Chrome"}, - distinct_id="person_2", - event="$pageview", - team=self.team, - ), - _create_event( - properties={"$current_url": "/pricing"}, distinct_id="person_3", event="$pageview", team=self.team - ), - _create_event(properties={"$current_url": "/"}, distinct_id="person_3", event="$pageview", team=self.team), - _create_event(properties={"$current_url": "/"}, distinct_id="person_4", event="$pageview", team=self.team), - _create_event( - properties={"$current_url": "/pricing"}, distinct_id="person_4", event="$pageview", team=self.team - ), + ( + _create_event( + properties={"$current_url": "/", "$browser": "Chrome"}, + distinct_id="person_1", + event="$pageview", + team=self.team, + ), + ) + ( + _create_event( + properties={"$current_url": "/about", "$browser": "Chrome"}, + distinct_id="person_1", + event="$pageview", + team=self.team, + ), + ) + ( + _create_event( + properties={"$current_url": "/", "$browser": "Chrome"}, + distinct_id="person_2", + event="$pageview", + team=self.team, + ), + ) + ( + _create_event( + properties={"$current_url": "/pricing", "$browser": "Chrome"}, + distinct_id="person_2", + event="$pageview", + team=self.team, + ), + ) + ( + _create_event( + properties={"$current_url": "/about", "$browser": "Chrome"}, + distinct_id="person_2", + event="$pageview", + team=self.team, + ), + ) + ( + _create_event( + properties={"$current_url": "/pricing"}, + distinct_id="person_3", + event="$pageview", + team=self.team, + ), + ) + ( + _create_event( + properties={"$current_url": "/"}, + distinct_id="person_3", + event="$pageview", + team=self.team, + ), + ) + ( + _create_event( + properties={"$current_url": "/"}, + distinct_id="person_4", + event="$pageview", + team=self.team, + ), + ) + ( + _create_event( + properties={"$current_url": "/pricing"}, + distinct_id="person_4", + event="$pageview", + team=self.team, + ), + ) filter = PathFilter( - team=self.team, data={"properties": [{"key": "$browser", "value": "Chrome", "type": "event"}]} + team=self.team, + data={"properties": [{"key": "$browser", "value": "Chrome", "type": "event"}]}, ) response = Paths(team=self.team, filter=filter).run(team=self.team, filter=filter) @@ -393,36 +639,118 @@ def test_paths_start(self): _create_person(team_id=self.team.pk, distinct_ids=["person_4"]) _create_person(team_id=self.team.pk, distinct_ids=["person_5a", "person_5b"]) - _create_event(properties={"$current_url": "/"}, distinct_id="person_1", event="$pageview", team=self.team), - _create_event( - properties={"$current_url": "/about/"}, distinct_id="person_1", event="$pageview", team=self.team - ), - _create_event(properties={"$current_url": "/"}, distinct_id="person_2", event="$pageview", team=self.team), - _create_event( - properties={"$current_url": "/pricing/"}, distinct_id="person_2", event="$pageview", team=self.team - ), - _create_event(properties={"$current_url": "/about"}, distinct_id="person_2", event="$pageview", team=self.team), - _create_event( - properties={"$current_url": "/pricing"}, distinct_id="person_3", event="$pageview", team=self.team - ), - _create_event(properties={"$current_url": "/"}, distinct_id="person_3", event="$pageview", team=self.team), - _create_event( - properties={"$current_url": "/about/"}, distinct_id="person_3", event="$pageview", team=self.team - ), - _create_event(properties={"$current_url": "/"}, distinct_id="person_4", event="$pageview", team=self.team), - _create_event( - properties={"$current_url": "/pricing/"}, distinct_id="person_4", event="$pageview", team=self.team - ), - _create_event( - properties={"$current_url": "/pricing"}, distinct_id="person_5a", event="$pageview", team=self.team - ), - _create_event( - properties={"$current_url": "/about"}, distinct_id="person_5b", event="$pageview", team=self.team - ), - _create_event( - properties={"$current_url": "/pricing/"}, distinct_id="person_5a", event="$pageview", team=self.team - ), - _create_event(properties={"$current_url": "/help"}, distinct_id="person_5b", event="$pageview", team=self.team), + ( + _create_event( + properties={"$current_url": "/"}, + distinct_id="person_1", + event="$pageview", + team=self.team, + ), + ) + ( + _create_event( + properties={"$current_url": "/about/"}, + distinct_id="person_1", + event="$pageview", + team=self.team, + ), + ) + ( + _create_event( + properties={"$current_url": "/"}, + distinct_id="person_2", + event="$pageview", + team=self.team, + ), + ) + ( + _create_event( + properties={"$current_url": "/pricing/"}, + distinct_id="person_2", + event="$pageview", + team=self.team, + ), + ) + ( + _create_event( + properties={"$current_url": "/about"}, + distinct_id="person_2", + event="$pageview", + team=self.team, + ), + ) + ( + _create_event( + properties={"$current_url": "/pricing"}, + distinct_id="person_3", + event="$pageview", + team=self.team, + ), + ) + ( + _create_event( + properties={"$current_url": "/"}, + distinct_id="person_3", + event="$pageview", + team=self.team, + ), + ) + ( + _create_event( + properties={"$current_url": "/about/"}, + distinct_id="person_3", + event="$pageview", + team=self.team, + ), + ) + ( + _create_event( + properties={"$current_url": "/"}, + distinct_id="person_4", + event="$pageview", + team=self.team, + ), + ) + ( + _create_event( + properties={"$current_url": "/pricing/"}, + distinct_id="person_4", + event="$pageview", + team=self.team, + ), + ) + ( + _create_event( + properties={"$current_url": "/pricing"}, + distinct_id="person_5a", + event="$pageview", + team=self.team, + ), + ) + ( + _create_event( + properties={"$current_url": "/about"}, + distinct_id="person_5b", + event="$pageview", + team=self.team, + ), + ) + ( + _create_event( + properties={"$current_url": "/pricing/"}, + distinct_id="person_5a", + event="$pageview", + team=self.team, + ), + ) + ( + _create_event( + properties={"$current_url": "/help"}, + distinct_id="person_5b", + event="$pageview", + team=self.team, + ), + ) response = self.client.get( f"/api/projects/{self.team.id}/insights/path/?type=%24pageview&start=%2Fpricing" @@ -463,34 +791,42 @@ def test_paths_start(self): def test_paths_in_window(self): _create_person(team_id=self.team.pk, distinct_ids=["person_1"]) - _create_event( - properties={"$current_url": "/"}, - distinct_id="person_1", - event="$pageview", - team=self.team, - timestamp="2020-04-14 03:25:34", - ), - _create_event( - properties={"$current_url": "/about"}, - distinct_id="person_1", - event="$pageview", - team=self.team, - timestamp="2020-04-14 03:30:34", - ), - _create_event( - properties={"$current_url": "/"}, - distinct_id="person_1", - event="$pageview", - team=self.team, - timestamp="2020-04-15 03:25:34", - ), - _create_event( - properties={"$current_url": "/about"}, - distinct_id="person_1", - event="$pageview", - team=self.team, - timestamp="2020-04-15 03:30:34", - ), + ( + _create_event( + properties={"$current_url": "/"}, + distinct_id="person_1", + event="$pageview", + team=self.team, + timestamp="2020-04-14 03:25:34", + ), + ) + ( + _create_event( + properties={"$current_url": "/about"}, + distinct_id="person_1", + event="$pageview", + team=self.team, + timestamp="2020-04-14 03:30:34", + ), + ) + ( + _create_event( + properties={"$current_url": "/"}, + distinct_id="person_1", + event="$pageview", + team=self.team, + timestamp="2020-04-15 03:25:34", + ), + ) + ( + _create_event( + properties={"$current_url": "/about"}, + distinct_id="person_1", + event="$pageview", + team=self.team, + timestamp="2020-04-15 03:30:34", + ), + ) filter = PathFilter(team=self.team, data={"date_from": "2020-04-13"}) response = Paths(team=self.team, filter=filter).run(team=self.team, filter=filter) diff --git a/posthog/queries/test/test_query_date_range.py b/posthog/queries/test/test_query_date_range.py index 15e7944502ba6..ebb21ad90e5ac 100644 --- a/posthog/queries/test/test_query_date_range.py +++ b/posthog/queries/test/test_query_date_range.py @@ -7,7 +7,6 @@ class TestQueryDateRange(APIBaseTest): def test_parsed_date(self): - with freeze_time("2021-08-25T00:00:00.000Z"): filter = Filter( data={ @@ -31,7 +30,6 @@ def test_parsed_date(self): ) def test_parsed_date_hour(self): - with freeze_time("2021-08-25T00:00:00.000Z"): filter = Filter( data={ @@ -55,7 +53,6 @@ def test_parsed_date_hour(self): ) # ensure last hour is included def test_parsed_date_middle_of_hour(self): - with freeze_time("2021-08-25T00:00:00.000Z"): filter = Filter( data={ @@ -80,7 +77,6 @@ def test_parsed_date_middle_of_hour(self): ) # ensure last hour is included def test_parsed_date_week_rounded(self): - with freeze_time("2021-08-25T00:00:00.000Z"): filter = Filter( data={ @@ -104,7 +100,6 @@ def test_parsed_date_week_rounded(self): ) def test_is_hourly(self): - with freeze_time("2021-08-25T00:00:00.000Z"): filter = Filter( data={ diff --git a/posthog/queries/test/test_retention.py b/posthog/queries/test/test_retention.py index 42b7c596b14a9..5b823d462d917 100644 --- a/posthog/queries/test/test_retention.py +++ b/posthog/queries/test/test_retention.py @@ -57,7 +57,13 @@ def _create_events(team, user_and_timestamps, event="$pageview"): if len(properties_args) == 1: properties.update(properties_args[0]) - _create_event(team=team, event=event, distinct_id=distinct_id, timestamp=timestamp, properties=properties) + _create_event( + team=team, + event=event, + distinct_id=distinct_id, + timestamp=timestamp, + properties=properties, + ) i += 1 @@ -126,7 +132,19 @@ def test_day_interval(self): self.assertEqual(len(result), 11) self.assertEqual( pluck(result, "label"), - ["Day 0", "Day 1", "Day 2", "Day 3", "Day 4", "Day 5", "Day 6", "Day 7", "Day 8", "Day 9", "Day 10"], + [ + "Day 0", + "Day 1", + "Day 2", + "Day 3", + "Day 4", + "Day 5", + "Day 6", + "Day 7", + "Day 8", + "Day 9", + "Day 10", + ], ) self.assertEqual(result[0]["date"], datetime(2020, 6, 10, 0, tzinfo=ZoneInfo("UTC"))) @@ -148,8 +166,16 @@ def test_day_interval(self): ) def test_month_interval(self): - _create_person(team=self.team, distinct_ids=["person1", "alias1"], properties={"email": "person1@test.com"}) - _create_person(team=self.team, distinct_ids=["person2"], properties={"email": "person2@test.com"}) + _create_person( + team=self.team, + distinct_ids=["person1", "alias1"], + properties={"email": "person1@test.com"}, + ) + _create_person( + team=self.team, + distinct_ids=["person2"], + properties={"email": "person2@test.com"}, + ) _create_events( self.team, @@ -227,8 +253,16 @@ def test_month_interval(self): @override_settings(PERSON_ON_EVENTS_V2_OVERRIDE=True) @snapshot_clickhouse_queries def test_month_interval_with_person_on_events_v2(self): - _create_person(team=self.team, distinct_ids=["person1", "alias1"], properties={"email": "person1@test.com"}) - _create_person(team=self.team, distinct_ids=["person2"], properties={"email": "person2@test.com"}) + _create_person( + team=self.team, + distinct_ids=["person1", "alias1"], + properties={"email": "person1@test.com"}, + ) + _create_person( + team=self.team, + distinct_ids=["person2"], + properties={"email": "person2@test.com"}, + ) person_id1 = str(uuid.uuid4()) person_id2 = str(uuid.uuid4()) @@ -386,8 +420,16 @@ def test_month_interval_with_person_on_events_v2(self): ) def test_week_interval(self): - _create_person(team=self.team, distinct_ids=["person1", "alias1"], properties={"email": "person1@test.com"}) - _create_person(team=self.team, distinct_ids=["person2"], properties={"email": "person2@test.com"}) + _create_person( + team=self.team, + distinct_ids=["person1", "alias1"], + properties={"email": "person1@test.com"}, + ) + _create_person( + team=self.team, + distinct_ids=["person2"], + properties={"email": "person2@test.com"}, + ) _create_events( self.team, @@ -408,17 +450,32 @@ def test_week_interval(self): ) result = retention().run( - RetentionFilter(data={"date_to": _date(10, month=1, hour=0), "period": "Week", "total_intervals": 7}), + RetentionFilter( + data={ + "date_to": _date(10, month=1, hour=0), + "period": "Week", + "total_intervals": 7, + } + ), self.team, ) self.assertEqual( - pluck(result, "label"), ["Week 0", "Week 1", "Week 2", "Week 3", "Week 4", "Week 5", "Week 6"] + pluck(result, "label"), + ["Week 0", "Week 1", "Week 2", "Week 3", "Week 4", "Week 5", "Week 6"], ) self.assertEqual( pluck(result, "values", "count"), - [[2, 2, 1, 2, 2, 0, 1], [2, 1, 2, 2, 0, 1], [1, 1, 1, 0, 0], [2, 2, 0, 1], [2, 0, 1], [0, 0], [1]], + [ + [2, 2, 1, 2, 2, 0, 1], + [2, 1, 2, 2, 0, 1], + [1, 1, 1, 0, 0], + [2, 2, 0, 1], + [2, 0, 1], + [0, 0], + [1], + ], ) self.assertEqual( @@ -435,8 +492,16 @@ def test_week_interval(self): ) def test_hour_interval(self): - _create_person(team=self.team, distinct_ids=["person1", "alias1"], properties={"email": "person1@test.com"}) - _create_person(team=self.team, distinct_ids=["person2"], properties={"email": "person2@test.com"}) + _create_person( + team=self.team, + distinct_ids=["person1", "alias1"], + properties={"email": "person1@test.com"}, + ) + _create_person( + team=self.team, + distinct_ids=["person2"], + properties={"email": "person2@test.com"}, + ) _create_events( self.team, @@ -513,8 +578,16 @@ def test_hour_interval(self): # ensure that the first interval is properly rounded acoording to the specified period def test_interval_rounding(self): - _create_person(team=self.team, distinct_ids=["person1", "alias1"], properties={"email": "person1@test.com"}) - _create_person(team=self.team, distinct_ids=["person2"], properties={"email": "person2@test.com"}) + _create_person( + team=self.team, + distinct_ids=["person1", "alias1"], + properties={"email": "person1@test.com"}, + ) + _create_person( + team=self.team, + distinct_ids=["person2"], + properties={"email": "person2@test.com"}, + ) _create_events( self.team, @@ -535,17 +608,32 @@ def test_interval_rounding(self): ) result = retention().run( - RetentionFilter(data={"date_to": _date(14, month=1, hour=0), "period": "Week", "total_intervals": 7}), + RetentionFilter( + data={ + "date_to": _date(14, month=1, hour=0), + "period": "Week", + "total_intervals": 7, + } + ), self.team, ) self.assertEqual( - pluck(result, "label"), ["Week 0", "Week 1", "Week 2", "Week 3", "Week 4", "Week 5", "Week 6"] + pluck(result, "label"), + ["Week 0", "Week 1", "Week 2", "Week 3", "Week 4", "Week 5", "Week 6"], ) self.assertEqual( pluck(result, "values", "count"), - [[2, 2, 1, 2, 2, 0, 1], [2, 1, 2, 2, 0, 1], [1, 1, 1, 0, 0], [2, 2, 0, 1], [2, 0, 1], [0, 0], [1]], + [ + [2, 2, 1, 2, 2, 0, 1], + [2, 1, 2, 2, 0, 1], + [1, 1, 1, 0, 0], + [2, 2, 0, 1], + [2, 0, 1], + [0, 0], + [1], + ], ) self.assertEqual( @@ -583,7 +671,11 @@ def test_retention_people_basic(self): # even if set to hour 6 it should default to beginning of day and include all pageviews above result, _ = retention().actors_in_period( - RetentionFilter(data={"date_to": _date(10, hour=6), "selected_interval": 0}, team=self.team), self.team + RetentionFilter( + data={"date_to": _date(10, hour=6), "selected_interval": 0}, + team=self.team, + ), + self.team, ) self.assertEqual(len(result), 1) self.assertTrue(result[0]["person"]["id"] == person1.uuid, person1.uuid) @@ -632,12 +724,18 @@ def test_retention_people_paginated(self): _create_person(team_id=self.team.pk, distinct_ids=[person_id]) _create_events( self.team, - [(person_id, _date(0)), (person_id, _date(1)), (person_id, _date(2)), (person_id, _date(5))], + [ + (person_id, _date(0)), + (person_id, _date(1)), + (person_id, _date(2)), + (person_id, _date(5)), + ], ) # even if set to hour 6 it should default to beginning of day and include all pageviews above result = self.client.get( - "/api/person/retention", data={"date_to": _date(10, hour=6), "selected_interval": 2} + "/api/person/retention", + data={"date_to": _date(10, hour=6), "selected_interval": 2}, ).json() self.assertEqual(len(result["result"]), 100) @@ -650,7 +748,8 @@ def test_retention_invalid_properties(self): self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) self.assertDictEqual( - response.json(), self.validation_error_response("Properties are unparsable!", "invalid_input") + response.json(), + self.validation_error_response("Properties are unparsable!", "invalid_input"), ) def test_retention_people_in_period(self): @@ -676,7 +775,11 @@ def test_retention_people_in_period(self): # even if set to hour 6 it should default to beginning of day and include all pageviews above result, _ = retention().actors_in_period( - RetentionFilter(data={"date_to": _date(10, hour=6), "selected_interval": 2}, team=self.team), self.team + RetentionFilter( + data={"date_to": _date(10, hour=6), "selected_interval": 2}, + team=self.team, + ), + self.team, ) # should be descending order on number of appearances @@ -732,7 +835,9 @@ def test_retention_multiple_events(self): ) _create_events( - self.team, [("person1", _date(5)), ("person1", _date(6)), ("person2", _date(5))], "$pageview" + self.team, + [("person1", _date(5)), ("person1", _date(6)), ("person2", _date(5))], + "$pageview", ) target_entity = json.dumps({"id": first_event, "type": TREND_FILTER_TYPE_EVENTS}) @@ -748,11 +853,22 @@ def test_retention_multiple_events(self): self.team, ) self.assertEqual(len(result), 7) - self.assertEqual(pluck(result, "label"), ["Day 0", "Day 1", "Day 2", "Day 3", "Day 4", "Day 5", "Day 6"]) + self.assertEqual( + pluck(result, "label"), + ["Day 0", "Day 1", "Day 2", "Day 3", "Day 4", "Day 5", "Day 6"], + ) self.assertEqual( pluck(result, "values", "count"), - [[2, 0, 0, 0, 0, 2, 1], [2, 0, 0, 0, 2, 1], [2, 0, 0, 2, 1], [2, 0, 2, 1], [0, 0, 0], [1, 0], [0]], + [ + [2, 0, 0, 0, 0, 2, 1], + [2, 0, 0, 0, 2, 1], + [2, 0, 0, 2, 1], + [2, 0, 2, 1], + [0, 0, 0], + [1, 0], + [0], + ], ) def test_retention_any_event(self): @@ -778,7 +894,9 @@ def test_retention_any_event(self): ) _create_events( - self.team, [("person1", _date(5)), ("person1", _date(6)), ("person2", _date(5))], "$pageview" + self.team, + [("person1", _date(5)), ("person1", _date(6)), ("person2", _date(5))], + "$pageview", ) result = retention().run( @@ -793,11 +911,22 @@ def test_retention_any_event(self): self.team, ) self.assertEqual(len(result), 7) - self.assertEqual(pluck(result, "label"), ["Day 0", "Day 1", "Day 2", "Day 3", "Day 4", "Day 5", "Day 6"]) + self.assertEqual( + pluck(result, "label"), + ["Day 0", "Day 1", "Day 2", "Day 3", "Day 4", "Day 5", "Day 6"], + ) self.assertEqual( pluck(result, "values", "count"), - [[2, 2, 2, 2, 0, 2, 1], [2, 2, 2, 0, 2, 1], [2, 2, 0, 2, 1], [2, 0, 2, 1], [0, 0, 0], [3, 1], [1]], + [ + [2, 2, 2, 2, 0, 2, 1], + [2, 2, 2, 0, 2, 1], + [2, 2, 0, 2, 1], + [2, 0, 2, 1], + [0, 0, 0], + [3, 1], + [1], + ], ) @snapshot_clickhouse_queries @@ -828,7 +957,10 @@ def test_retention_event_action(self): data={ "date_to": _date(6, hour=0), "target_entity": start_entity, - "returning_entity": {"id": some_event, "type": TREND_FILTER_TYPE_EVENTS}, + "returning_entity": { + "id": some_event, + "type": TREND_FILTER_TYPE_EVENTS, + }, "total_intervals": 7, } ), @@ -836,12 +968,23 @@ def test_retention_event_action(self): ) self.assertEqual(len(result), 7) - self.assertEqual(pluck(result, "label"), ["Day 0", "Day 1", "Day 2", "Day 3", "Day 4", "Day 5", "Day 6"]) + self.assertEqual( + pluck(result, "label"), + ["Day 0", "Day 1", "Day 2", "Day 3", "Day 4", "Day 5", "Day 6"], + ) self.assertEqual(result[0]["date"], datetime(2020, 6, 10, 0, tzinfo=ZoneInfo("UTC"))) self.assertEqual( pluck(result, "values", "count"), - [[2, 0, 0, 1, 0, 1, 0], [2, 0, 1, 0, 1, 0], [2, 1, 0, 1, 0], [2, 0, 1, 0], [0, 0, 0], [0, 0], [0]], + [ + [2, 0, 0, 1, 0, 1, 0], + [2, 0, 1, 0, 1, 0], + [2, 1, 0, 1, 0], + [2, 0, 1, 0], + [0, 0, 0], + [0, 0], + [0], + ], ) def test_first_time_retention(self): @@ -862,11 +1005,22 @@ def test_first_time_retention(self): ) self.assertEqual(len(result), 7) - self.assertEqual(pluck(result, "label"), ["Day 0", "Day 1", "Day 2", "Day 3", "Day 4", "Day 5", "Day 6"]) + self.assertEqual( + pluck(result, "label"), + ["Day 0", "Day 1", "Day 2", "Day 3", "Day 4", "Day 5", "Day 6"], + ) self.assertEqual( pluck(result, "values", "count"), - [[2, 1, 2, 2, 1, 0, 1], [1, 1, 0, 1, 1, 1], [0, 0, 0, 0, 0], [1, 1, 0, 1], [0, 0, 0], [0, 0], [0]], + [ + [2, 1, 2, 2, 1, 0, 1], + [1, 1, 0, 1, 1, 1], + [0, 0, 0, 0, 0], + [1, 1, 0, 1], + [0, 0, 0], + [0, 0], + [0], + ], ) def test_retention_with_properties(self): @@ -891,14 +1045,29 @@ def test_retention_with_properties(self): result = retention().run( RetentionFilter( - data={"properties": [{"key": "$some_property", "value": "value"}], "date_to": _date(10, hour=0)} + data={ + "properties": [{"key": "$some_property", "value": "value"}], + "date_to": _date(10, hour=0), + } ), self.team, ) self.assertEqual(len(result), 11) self.assertEqual( pluck(result, "label"), - ["Day 0", "Day 1", "Day 2", "Day 3", "Day 4", "Day 5", "Day 6", "Day 7", "Day 8", "Day 9", "Day 10"], + [ + "Day 0", + "Day 1", + "Day 2", + "Day 3", + "Day 4", + "Day 5", + "Day 6", + "Day 7", + "Day 8", + "Day 9", + "Day 10", + ], ) self.assertEqual(result[0]["date"], datetime(2020, 6, 10, 0, tzinfo=ZoneInfo("UTC"))) @@ -921,9 +1090,15 @@ def test_retention_with_properties(self): def test_retention_with_user_properties(self): _create_person( - team_id=self.team.pk, distinct_ids=["person1", "alias1"], properties={"email": "person1@test.com"} + team_id=self.team.pk, + distinct_ids=["person1", "alias1"], + properties={"email": "person1@test.com"}, + ) + _create_person( + team_id=self.team.pk, + distinct_ids=["person2"], + properties={"email": "person2@test.com"}, ) - _create_person(team_id=self.team.pk, distinct_ids=["person2"], properties={"email": "person2@test.com"}) _create_events( self.team, @@ -944,7 +1119,13 @@ def test_retention_with_user_properties(self): result = retention().run( RetentionFilter( data={ - "properties": [{"key": "email", "value": "person1@test.com", "type": "person"}], + "properties": [ + { + "key": "email", + "value": "person1@test.com", + "type": "person", + } + ], "date_to": _date(6, hour=0), "total_intervals": 7, } @@ -953,11 +1134,22 @@ def test_retention_with_user_properties(self): ) self.assertEqual(len(result), 7) - self.assertEqual(pluck(result, "label"), ["Day 0", "Day 1", "Day 2", "Day 3", "Day 4", "Day 5", "Day 6"]) + self.assertEqual( + pluck(result, "label"), + ["Day 0", "Day 1", "Day 2", "Day 3", "Day 4", "Day 5", "Day 6"], + ) self.assertEqual(result[0]["date"], datetime(2020, 6, 10, 0, tzinfo=ZoneInfo("UTC"))) self.assertEqual( pluck(result, "values", "count"), - [[1, 1, 1, 0, 0, 1, 1], [1, 1, 0, 0, 1, 1], [1, 0, 0, 1, 1], [0, 0, 0, 0], [0, 0, 0], [1, 1], [1]], + [ + [1, 1, 1, 0, 0, 1, 1], + [1, 1, 0, 0, 1, 1], + [1, 0, 0, 1, 1], + [0, 0, 0, 0], + [0, 0, 0], + [1, 1], + [1], + ], ) @snapshot_clickhouse_queries @@ -970,9 +1162,15 @@ def test_retention_with_user_properties_via_action(self): ) _create_person( - team_id=self.team.pk, distinct_ids=["person1", "alias1"], properties={"email": "person1@test.com"} + team_id=self.team.pk, + distinct_ids=["person1", "alias1"], + properties={"email": "person1@test.com"}, + ) + _create_person( + team_id=self.team.pk, + distinct_ids=["person2"], + properties={"email": "person2@test.com"}, ) - _create_person(team_id=self.team.pk, distinct_ids=["person2"], properties={"email": "person2@test.com"}) _create_events( self.team, @@ -1003,11 +1201,22 @@ def test_retention_with_user_properties_via_action(self): ) self.assertEqual(len(result), 7) - self.assertEqual(pluck(result, "label"), ["Day 0", "Day 1", "Day 2", "Day 3", "Day 4", "Day 5", "Day 6"]) + self.assertEqual( + pluck(result, "label"), + ["Day 0", "Day 1", "Day 2", "Day 3", "Day 4", "Day 5", "Day 6"], + ) self.assertEqual(result[0]["date"], datetime(2020, 6, 10, 0, tzinfo=ZoneInfo("UTC"))) self.assertEqual( pluck(result, "values", "count"), - [[1, 1, 1, 0, 0, 1, 1], [1, 1, 0, 0, 1, 1], [1, 0, 0, 1, 1], [0, 0, 0, 0], [0, 0, 0], [1, 1], [1]], + [ + [1, 1, 1, 0, 0, 1, 1], + [1, 1, 0, 0, 1, 1], + [1, 0, 0, 1, 1], + [0, 0, 0, 0], + [0, 0, 0], + [1, 1], + [1], + ], ) def test_retention_action_start_point(self): @@ -1044,17 +1253,30 @@ def test_retention_action_start_point(self): ) self.assertEqual(len(result), 7) - self.assertEqual(pluck(result, "label"), ["Day 0", "Day 1", "Day 2", "Day 3", "Day 4", "Day 5", "Day 6"]) + self.assertEqual( + pluck(result, "label"), + ["Day 0", "Day 1", "Day 2", "Day 3", "Day 4", "Day 5", "Day 6"], + ) self.assertEqual(result[0]["date"], datetime(2020, 6, 10, 0, tzinfo=ZoneInfo("UTC"))) self.assertEqual( pluck(result, "values", "count"), - [[1, 1, 1, 0, 0, 1, 1], [2, 2, 1, 0, 1, 2], [2, 1, 0, 1, 2], [1, 0, 0, 1], [0, 0, 0], [1, 1], [2]], + [ + [1, 1, 1, 0, 0, 1, 1], + [2, 2, 1, 0, 1, 2], + [2, 1, 0, 1, 2], + [1, 0, 0, 1], + [0, 0, 0], + [1, 1], + [2], + ], ) def test_filter_test_accounts(self): _create_person( - team_id=self.team.pk, distinct_ids=["person1", "alias1"], properties={"email": "test@posthog.com"} + team_id=self.team.pk, + distinct_ids=["person1", "alias1"], + properties={"email": "test@posthog.com"}, ) _create_person(team_id=self.team.pk, distinct_ids=["person2"]) @@ -1076,13 +1298,28 @@ def test_filter_test_accounts(self): # even if set to hour 6 it should default to beginning of day and include all pageviews above result = retention().run( - RetentionFilter(data={"date_to": _date(10, hour=6), FILTER_TEST_ACCOUNTS: True}, team=self.team), + RetentionFilter( + data={"date_to": _date(10, hour=6), FILTER_TEST_ACCOUNTS: True}, + team=self.team, + ), self.team, ) self.assertEqual(len(result), 11) self.assertEqual( pluck(result, "label"), - ["Day 0", "Day 1", "Day 2", "Day 3", "Day 4", "Day 5", "Day 6", "Day 7", "Day 8", "Day 9", "Day 10"], + [ + "Day 0", + "Day 1", + "Day 2", + "Day 3", + "Day 4", + "Day 5", + "Day 6", + "Day 7", + "Day 8", + "Day 9", + "Day 10", + ], ) self.assertEqual(result[0]["date"], datetime(2020, 6, 10, 0, tzinfo=ZoneInfo("UTC"))) @@ -1144,7 +1381,13 @@ def _create_first_time_retention_events(self): _create_events(self.team, [("person3", _date(0))], "$user_signed_up") _create_events( - self.team, [("person3", _date(1)), ("person3", _date(3)), ("person3", _date(4)), ("person3", _date(5))] + self.team, + [ + ("person3", _date(1)), + ("person3", _date(3)), + ("person3", _date(4)), + ("person3", _date(5)), + ], ) _create_events(self.team, [("person4", _date(2))], "$user_signed_up") @@ -1154,7 +1397,11 @@ def _create_first_time_retention_events(self): return p1, p2, p3, p4 def test_retention_aggregate_by_distinct_id(self): - _create_person(team_id=self.team.pk, distinct_ids=["person1", "alias1"], properties={"test": "ok"}) + _create_person( + team_id=self.team.pk, + distinct_ids=["person1", "alias1"], + properties={"test": "ok"}, + ) _create_person(team_id=self.team.pk, distinct_ids=["person2"]) _create_events( @@ -1203,7 +1450,14 @@ def test_retention_aggregate_by_distinct_id(self): [2, 1, 0, 1, 2, 0, 0, 0, 0], [1, 0, 0, 1, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0], - [2, 1, 0, 0, 0, 0], # this first day is different b/c of the distinct_id aggregation + [ + 2, + 1, + 0, + 0, + 0, + 0, + ], # this first day is different b/c of the distinct_id aggregation [2, 0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0], @@ -1229,7 +1483,14 @@ def test_retention_aggregate_by_distinct_id(self): [1, 0, 0, 1, 1, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0], - [2, 1, 0, 0, 0, 0], # this first day is different b/c of the distinct_id aggregation + [ + 2, + 1, + 0, + 0, + 0, + 0, + ], # this first day is different b/c of the distinct_id aggregation [1, 0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0], @@ -1248,26 +1509,48 @@ def test_timezones(self): [ ("person1", _date(-1, 1)), ("person1", _date(0, 1)), - ("person1", _date(1, 1)), # this is the only event in US Pacific on the first day + ( + "person1", + _date(1, 1), + ), # this is the only event in US Pacific on the first day ("person2", _date(6, 1)), ("person2", _date(6, 9)), ], ) - result = retention().run(RetentionFilter(data={"date_to": _date(10, hour=6)}, team=self.team), self.team) + result = retention().run( + RetentionFilter(data={"date_to": _date(10, hour=6)}, team=self.team), + self.team, + ) self.team.timezone = "US/Pacific" self.team.save() result_pacific = retention().run( - RetentionFilter(data={"date_to": _date(10, hour=6)}, team=self.team), self.team + RetentionFilter(data={"date_to": _date(10, hour=6)}, team=self.team), + self.team, ) self.assertEqual( pluck(result_pacific, "label"), - ["Day 0", "Day 1", "Day 2", "Day 3", "Day 4", "Day 5", "Day 6", "Day 7", "Day 8", "Day 9", "Day 10"], + [ + "Day 0", + "Day 1", + "Day 2", + "Day 3", + "Day 4", + "Day 5", + "Day 6", + "Day 7", + "Day 8", + "Day 9", + "Day 10", + ], ) - self.assertEqual(result_pacific[0]["date"], datetime(2020, 6, 10, tzinfo=ZoneInfo("US/Pacific"))) + self.assertEqual( + result_pacific[0]["date"], + datetime(2020, 6, 10, tzinfo=ZoneInfo("US/Pacific")), + ) self.assertEqual(result_pacific[0]["date"].isoformat(), "2020-06-10T00:00:00-07:00") self.assertEqual( @@ -1327,12 +1610,25 @@ def test_day_interval_sampled(self): # even if set to hour 6 it should default to beginning of day and include all pageviews above result = retention().run( - RetentionFilter(data={"date_to": _date(10, hour=6), "sampling_factor": 1}), self.team + RetentionFilter(data={"date_to": _date(10, hour=6), "sampling_factor": 1}), + self.team, ) self.assertEqual(len(result), 11) self.assertEqual( pluck(result, "label"), - ["Day 0", "Day 1", "Day 2", "Day 3", "Day 4", "Day 5", "Day 6", "Day 7", "Day 8", "Day 9", "Day 10"], + [ + "Day 0", + "Day 1", + "Day 2", + "Day 3", + "Day 4", + "Day 5", + "Day 6", + "Day 7", + "Day 8", + "Day 9", + "Day 10", + ], ) self.assertEqual(result[0]["date"], datetime(2020, 6, 10, 0, tzinfo=ZoneInfo("UTC"))) diff --git a/posthog/queries/test/test_trends.py b/posthog/queries/test/test_trends.py index 3cce0cfd1907a..63b7024d3d6bf 100644 --- a/posthog/queries/test/test_trends.py +++ b/posthog/queries/test/test_trends.py @@ -32,7 +32,11 @@ Person, ) from posthog.models.group.util import create_group -from posthog.models.instance_setting import get_instance_setting, override_instance_config, set_instance_setting +from posthog.models.instance_setting import ( + get_instance_setting, + override_instance_config, + set_instance_setting, +) from posthog.models.person.util import create_person_distinct_id from posthog.queries.trends.trends import Trends from posthog.test.base import ( @@ -54,7 +58,7 @@ def breakdown_label(entity: Entity, value: Union[str, int]) -> Dict[str, Optional[Union[str, int]]]: ret_dict: Dict[str, Optional[Union[str, int]]] = {} if not value or not isinstance(value, str) or "cohort_" not in value: - label = value if (value or type(value) == bool) and value != "None" and value != "nan" else "Other" + label = value if (value or isinstance(value, bool)) and value != "None" and value != "nan" else "Other" ret_dict["label"] = f"{entity.name} - {label}" ret_dict["breakdown_value"] = label else: @@ -104,14 +108,19 @@ def _get_trend_people(self, filter: Filter, entity: Entity): return response["results"][0]["people"] def _create_events(self, use_time=False) -> Tuple[Action, Person]: - person = _create_person( - team_id=self.team.pk, distinct_ids=["blabla", "anonymous_id"], properties={"$some_prop": "some_val"} + team_id=self.team.pk, + distinct_ids=["blabla", "anonymous_id"], + properties={"$some_prop": "some_val"}, ) _, _, secondTeam = Organization.objects.bootstrap(None, team_fields={"api_token": "token456"}) freeze_without_time = ["2019-12-24", "2020-01-01", "2020-01-02"] - freeze_with_time = ["2019-12-24 03:45:34", "2020-01-01 00:06:34", "2020-01-02 16:34:34"] + freeze_with_time = [ + "2019-12-24 03:45:34", + "2020-01-01 00:06:34", + "2020-01-02 16:34:34", + ] freeze_args = freeze_without_time if use_time: @@ -132,20 +141,31 @@ def _create_events(self, use_time=False) -> Tuple[Action, Person]: distinct_id="blabla", properties={"$some_property": "value", "$bool_prop": False}, ) - _create_event(team=self.team, event="sign up", distinct_id="anonymous_id", properties={"$bool_prop": False}) + _create_event( + team=self.team, + event="sign up", + distinct_id="anonymous_id", + properties={"$bool_prop": False}, + ) _create_event(team=self.team, event="sign up", distinct_id="blabla") with freeze_time(freeze_args[2]): _create_event( team=self.team, event="sign up", distinct_id="blabla", - properties={"$some_property": "other_value", "$some_numerical_prop": 80}, + properties={ + "$some_property": "other_value", + "$some_numerical_prop": 80, + }, ) _create_event(team=self.team, event="no events", distinct_id="blabla") # second team should have no effect _create_event( - team=secondTeam, event="sign up", distinct_id="blabla", properties={"$some_property": "other_value"} + team=secondTeam, + event="sign up", + distinct_id="blabla", + properties={"$some_property": "other_value"}, ) _create_action(team=self.team, name="no events") @@ -160,14 +180,27 @@ def _create_breakdown_events(self): with freeze_time(freeze_without_time[0]): for i in range(25): - _create_event(team=self.team, event="sign up", distinct_id="blabla", properties={"$some_property": i}) + _create_event( + team=self.team, + event="sign up", + distinct_id="blabla", + properties={"$some_property": i}, + ) _create_action(team=self.team, name="sign up") def _create_event_count_per_actor_events(self): - _create_person(team_id=self.team.pk, distinct_ids=["blabla", "anonymous_id"], properties={"fruit": "mango"}) + _create_person( + team_id=self.team.pk, + distinct_ids=["blabla", "anonymous_id"], + properties={"fruit": "mango"}, + ) _create_person(team_id=self.team.pk, distinct_ids=["tintin"], properties={"fruit": "mango"}) _create_person(team_id=self.team.pk, distinct_ids=["murmur"], properties={}) # No fruit here - _create_person(team_id=self.team.pk, distinct_ids=["reeree"], properties={"fruit": "tomato"}) + _create_person( + team_id=self.team.pk, + distinct_ids=["reeree"], + properties={"fruit": "tomato"}, + ) with freeze_time("2020-01-01 00:06:02"): _create_event( @@ -177,7 +210,10 @@ def _create_event_count_per_actor_events(self): properties={"color": "red", "$group_0": "bouba"}, ) _create_event( - team=self.team, event="viewed video", distinct_id="blabla", properties={"$group_0": "bouba"} + team=self.team, + event="viewed video", + distinct_id="blabla", + properties={"$group_0": "bouba"}, ) # No color here _create_event( team=self.team, @@ -185,10 +221,20 @@ def _create_event_count_per_actor_events(self): distinct_id="reeree", properties={"color": "blue", "$group_0": "bouba"}, ) - _create_event(team=self.team, event="sign up", distinct_id="tintin", properties={"$group_0": "kiki"}) + _create_event( + team=self.team, + event="sign up", + distinct_id="tintin", + properties={"$group_0": "kiki"}, + ) with freeze_time("2020-01-03 19:06:34"): - _create_event(team=self.team, event="sign up", distinct_id="murmur", properties={"$group_0": "kiki"}) + _create_event( + team=self.team, + event="sign up", + distinct_id="murmur", + properties={"$group_0": "kiki"}, + ) with freeze_time("2020-01-04 23:17:00"): _create_event( @@ -206,7 +252,10 @@ def _create_event_count_per_actor_events(self): properties={"color": "blue", "$group_0": "bouba"}, ) _create_event( - team=self.team, event="viewed video", distinct_id="tintin", properties={"color": "red"} + team=self.team, + event="viewed video", + distinct_id="tintin", + properties={"color": "red"}, ) # No group here _create_event( team=self.team, @@ -226,7 +275,13 @@ def test_trends_per_day(self): with freeze_time("2020-01-04T13:00:01Z"): # with self.assertNumQueries(16): response = Trends().run( - Filter(team=self.team, data={"date_from": "-7d", "events": [{"id": "sign up"}, {"id": "no events"}]}), + Filter( + team=self.team, + data={ + "date_from": "-7d", + "events": [{"id": "sign up"}, {"id": "no events"}], + }, + ), self.team, ) self.assertEqual(response[0]["label"], "sign up") @@ -272,7 +327,11 @@ def test_trend_actors_person_on_events_pagination_with_alias_inconsistencies(sel ) flush_persons_and_events() - data = {"date_from": "-7d", "events": [{"id": "sign up", "math": "dau"}], "limit": 5} + data = { + "date_from": "-7d", + "events": [{"id": "sign up", "math": "dau"}], + "limit": 5, + } with override_instance_config("PERSON_ON_EVENTS_ENABLED", True): from posthog.models.team import util @@ -318,7 +377,12 @@ def test_no_props(self): "date_from": "-14d", "breakdown": "$some_property", "events": [ - {"id": "sign up", "name": "sign up", "type": "events", "order": 0}, + { + "id": "sign up", + "name": "sign up", + "type": "events", + "order": 0, + }, {"id": "no events"}, ], }, @@ -348,7 +412,6 @@ def test_trends_per_day_48hours(self): def test_trends_per_day_cumulative(self): self._create_events() with freeze_time("2020-01-04T13:00:01Z"): - response = Trends().run( Filter( team=self.team, @@ -371,7 +434,6 @@ def test_trends_per_day_cumulative(self): def test_trends_groups_per_day_cumulative(self): self._create_event_count_per_actor_events() with freeze_time("2020-01-06T13:00:01Z"): - response = Trends().run( Filter( team=self.team, @@ -399,7 +461,6 @@ def test_trends_groups_per_day_cumulative(self): def test_trends_breakdown_cumulative(self): self._create_events() with freeze_time("2020-01-04T13:00:01Z"): - response = Trends().run( Filter( team=self.team, @@ -429,7 +490,11 @@ def test_trends_single_aggregate_dau(self): daily_response = Trends().run( Filter( team=self.team, - data={"display": TRENDS_TABLE, "interval": "week", "events": [{"id": "sign up", "math": "dau"}]}, + data={ + "display": TRENDS_TABLE, + "interval": "week", + "events": [{"id": "sign up", "math": "dau"}], + }, ), self.team, ) @@ -438,29 +503,73 @@ def test_trends_single_aggregate_dau(self): weekly_response = Trends().run( Filter( team=self.team, - data={"display": TRENDS_TABLE, "interval": "day", "events": [{"id": "sign up", "math": "dau"}]}, + data={ + "display": TRENDS_TABLE, + "interval": "day", + "events": [{"id": "sign up", "math": "dau"}], + }, ), self.team, ) self.assertEqual(daily_response[0]["aggregated_value"], 1) - self.assertEqual(daily_response[0]["aggregated_value"], weekly_response[0]["aggregated_value"]) + self.assertEqual( + daily_response[0]["aggregated_value"], + weekly_response[0]["aggregated_value"], + ) @also_test_with_materialized_columns(["$math_prop"]) def test_trends_single_aggregate_math(self): _create_person( - team_id=self.team.pk, distinct_ids=["blabla", "anonymous_id"], properties={"$some_prop": "some_val"} + team_id=self.team.pk, + distinct_ids=["blabla", "anonymous_id"], + properties={"$some_prop": "some_val"}, ) with freeze_time("2020-01-01 00:06:34"): - _create_event(team=self.team, event="sign up", distinct_id="blabla", properties={"$math_prop": 1}) - _create_event(team=self.team, event="sign up", distinct_id="blabla", properties={"$math_prop": 1}) - _create_event(team=self.team, event="sign up", distinct_id="blabla", properties={"$math_prop": 1}) - _create_event(team=self.team, event="sign up", distinct_id="blabla", properties={"$math_prop": 2}) - _create_event(team=self.team, event="sign up", distinct_id="blabla", properties={"$math_prop": 3}) + _create_event( + team=self.team, + event="sign up", + distinct_id="blabla", + properties={"$math_prop": 1}, + ) + _create_event( + team=self.team, + event="sign up", + distinct_id="blabla", + properties={"$math_prop": 1}, + ) + _create_event( + team=self.team, + event="sign up", + distinct_id="blabla", + properties={"$math_prop": 1}, + ) + _create_event( + team=self.team, + event="sign up", + distinct_id="blabla", + properties={"$math_prop": 2}, + ) + _create_event( + team=self.team, + event="sign up", + distinct_id="blabla", + properties={"$math_prop": 3}, + ) with freeze_time("2020-01-02 00:06:34"): - _create_event(team=self.team, event="sign up", distinct_id="blabla", properties={"$math_prop": 4}) - _create_event(team=self.team, event="sign up", distinct_id="blabla", properties={"$math_prop": 4}) + _create_event( + team=self.team, + event="sign up", + distinct_id="blabla", + properties={"$math_prop": 4}, + ) + _create_event( + team=self.team, + event="sign up", + distinct_id="blabla", + properties={"$math_prop": 4}, + ) with freeze_time("2020-01-04T13:00:01Z"): daily_response = Trends().run( @@ -469,7 +578,13 @@ def test_trends_single_aggregate_math(self): data={ "display": TRENDS_TABLE, "interval": "week", - "events": [{"id": "sign up", "math": "median", "math_property": "$math_prop"}], + "events": [ + { + "id": "sign up", + "math": "median", + "math_property": "$math_prop", + } + ], }, ), self.team, @@ -482,21 +597,36 @@ def test_trends_single_aggregate_math(self): data={ "display": TRENDS_TABLE, "interval": "day", - "events": [{"id": "sign up", "math": "median", "math_property": "$math_prop"}], + "events": [ + { + "id": "sign up", + "math": "median", + "math_property": "$math_prop", + } + ], }, ), self.team, ) self.assertEqual(daily_response[0]["aggregated_value"], 2.0) - self.assertEqual(daily_response[0]["aggregated_value"], weekly_response[0]["aggregated_value"]) + self.assertEqual( + daily_response[0]["aggregated_value"], + weekly_response[0]["aggregated_value"], + ) @snapshot_clickhouse_queries def test_trends_with_session_property_single_aggregate_math(self): _create_person( - team_id=self.team.pk, distinct_ids=["blabla", "anonymous_id"], properties={"$some_prop": "some_val"} + team_id=self.team.pk, + distinct_ids=["blabla", "anonymous_id"], + properties={"$some_prop": "some_val"}, + ) + _create_person( + team_id=self.team.pk, + distinct_ids=["blabla2"], + properties={"$some_prop": "some_val"}, ) - _create_person(team_id=self.team.pk, distinct_ids=["blabla2"], properties={"$some_prop": "some_val"}) _create_event( team=self.team, @@ -568,7 +698,13 @@ def test_trends_with_session_property_single_aggregate_math(self): data={ "display": TRENDS_TABLE, "interval": "week", - "events": [{"id": "sign up", "math": "median", "math_property": "$session_duration"}], + "events": [ + { + "id": "sign up", + "math": "median", + "math_property": "$session_duration", + } + ], }, ), self.team, @@ -581,20 +717,35 @@ def test_trends_with_session_property_single_aggregate_math(self): data={ "display": TRENDS_TABLE, "interval": "day", - "events": [{"id": "sign up", "math": "median", "math_property": "$session_duration"}], + "events": [ + { + "id": "sign up", + "math": "median", + "math_property": "$session_duration", + } + ], }, ), self.team, ) self.assertEqual(daily_response[0]["aggregated_value"], 7.5) - self.assertEqual(daily_response[0]["aggregated_value"], weekly_response[0]["aggregated_value"]) + self.assertEqual( + daily_response[0]["aggregated_value"], + weekly_response[0]["aggregated_value"], + ) def test_unique_session_with_session_breakdown(self): _create_person( - team_id=self.team.pk, distinct_ids=["blabla", "anonymous_id"], properties={"$some_prop": "some_val"} + team_id=self.team.pk, + distinct_ids=["blabla", "anonymous_id"], + properties={"$some_prop": "some_val"}, + ) + _create_person( + team_id=self.team.pk, + distinct_ids=["blabla2"], + properties={"$some_prop": "some_val"}, ) - _create_person(team_id=self.team.pk, distinct_ids=["blabla2"], properties={"$some_prop": "some_val"}) _create_event( team=self.team, @@ -779,7 +930,9 @@ def test_trends_breakdown_single_aggregate_cohorts(self): def test_trends_breakdown_single_aggregate(self): _create_person( - team_id=self.team.pk, distinct_ids=["blabla", "anonymous_id"], properties={"$some_prop": "some_val"} + team_id=self.team.pk, + distinct_ids=["blabla", "anonymous_id"], + properties={"$some_prop": "some_val"}, ) with freeze_time("2020-01-01 00:06:34"): _create_event( @@ -831,7 +984,11 @@ def test_trends_breakdown_single_aggregate(self): daily_response = Trends().run( Filter( team=self.team, - data={"display": TRENDS_TABLE, "breakdown": "$browser", "events": [{"id": "sign up"}]}, + data={ + "display": TRENDS_TABLE, + "breakdown": "$browser", + "events": [{"id": "sign up"}], + }, ), self.team, ) @@ -848,7 +1005,9 @@ def test_trends_breakdown_single_aggregate_with_zero_person_ids(self): return True _create_person( - team_id=self.team.pk, distinct_ids=["blabla", "anonymous_id"], properties={"$some_prop": "some_val"} + team_id=self.team.pk, + distinct_ids=["blabla", "anonymous_id"], + properties={"$some_prop": "some_val"}, ) with freeze_time("2020-01-01 00:06:34"): _create_event( @@ -935,7 +1094,11 @@ def test_trends_breakdown_single_aggregate_with_zero_person_ids(self): daily_response = Trends().run( Filter( team=self.team, - data={"display": TRENDS_TABLE, "breakdown": "$browser", "events": [{"id": "sign up"}]}, + data={ + "display": TRENDS_TABLE, + "breakdown": "$browser", + "events": [{"id": "sign up"}], + }, ), self.team, ) @@ -948,7 +1111,9 @@ def test_trends_breakdown_single_aggregate_with_zero_person_ids(self): def test_trends_breakdown_single_aggregate_math(self): _create_person( - team_id=self.team.pk, distinct_ids=["blabla", "anonymous_id"], properties={"$some_prop": "some_val"} + team_id=self.team.pk, + distinct_ids=["blabla", "anonymous_id"], + properties={"$some_prop": "some_val"}, ) with freeze_time("2020-01-01 00:06:34"): _create_event( @@ -1004,7 +1169,13 @@ def test_trends_breakdown_single_aggregate_math(self): "display": TRENDS_TABLE, "interval": "day", "breakdown": "$some_property", - "events": [{"id": "sign up", "math": "median", "math_property": "$math_prop"}], + "events": [ + { + "id": "sign up", + "math": "median", + "math_property": "$math_prop", + } + ], }, ), self.team, @@ -1018,21 +1189,36 @@ def test_trends_breakdown_single_aggregate_math(self): "display": TRENDS_TABLE, "interval": "week", "breakdown": "$some_property", - "events": [{"id": "sign up", "math": "median", "math_property": "$math_prop"}], + "events": [ + { + "id": "sign up", + "math": "median", + "math_property": "$math_prop", + } + ], }, ), self.team, ) self.assertEqual(daily_response[0]["aggregated_value"], 2.0) - self.assertEqual(daily_response[0]["aggregated_value"], weekly_response[0]["aggregated_value"]) + self.assertEqual( + daily_response[0]["aggregated_value"], + weekly_response[0]["aggregated_value"], + ) @snapshot_clickhouse_queries def test_trends_breakdown_with_session_property_single_aggregate_math_and_breakdown(self): _create_person( - team_id=self.team.pk, distinct_ids=["blabla", "anonymous_id"], properties={"$some_prop": "some_val"} + team_id=self.team.pk, + distinct_ids=["blabla", "anonymous_id"], + properties={"$some_prop": "some_val"}, + ) + _create_person( + team_id=self.team.pk, + distinct_ids=["blabla2"], + properties={"$some_prop": "some_val"}, ) - _create_person(team_id=self.team.pk, distinct_ids=["blabla2"], properties={"$some_prop": "some_val"}) _create_event( team=self.team, @@ -1119,7 +1305,13 @@ def test_trends_breakdown_with_session_property_single_aggregate_math_and_breakd "display": TRENDS_TABLE, "interval": "week", "breakdown": "$some_property", - "events": [{"id": "sign up", "math": "median", "math_property": "$session_duration"}], + "events": [ + { + "id": "sign up", + "math": "median", + "math_property": "$session_duration", + } + ], }, ), self.team, @@ -1128,7 +1320,10 @@ def test_trends_breakdown_with_session_property_single_aggregate_math_and_breakd # value1 has: 5 seconds, 10 seconds, 15 seconds # value2 has: 10 seconds, 15 seconds (aggregated by session, so 15 is not double counted) # empty has: 1 seconds - self.assertEqual([resp["breakdown_value"] for resp in daily_response], ["value2", "value1", ""]) + self.assertEqual( + [resp["breakdown_value"] for resp in daily_response], + ["value2", "value1", ""], + ) self.assertEqual([resp["aggregated_value"] for resp in daily_response], [12.5, 10, 1]) with freeze_time("2020-01-04T13:00:01Z"): @@ -1139,7 +1334,13 @@ def test_trends_breakdown_with_session_property_single_aggregate_math_and_breakd "display": TRENDS_TABLE, "interval": "day", "breakdown": "$some_property", - "events": [{"id": "sign up", "math": "median", "math_property": "$session_duration"}], + "events": [ + { + "id": "sign up", + "math": "median", + "math_property": "$session_duration", + } + ], }, ), self.team, @@ -1157,9 +1358,15 @@ def test_trends_breakdown_with_session_property_single_aggregate_math_and_breakd @snapshot_clickhouse_queries def test_trends_person_breakdown_with_session_property_single_aggregate_math_and_breakdown(self): _create_person( - team_id=self.team.pk, distinct_ids=["blabla", "anonymous_id"], properties={"$some_prop": "some_val"} + team_id=self.team.pk, + distinct_ids=["blabla", "anonymous_id"], + properties={"$some_prop": "some_val"}, + ) + _create_person( + team_id=self.team.pk, + distinct_ids=["blabla2"], + properties={"$some_prop": "another_val"}, ) - _create_person(team_id=self.team.pk, distinct_ids=["blabla2"], properties={"$some_prop": "another_val"}) _create_event( team=self.team, @@ -1247,7 +1454,13 @@ def test_trends_person_breakdown_with_session_property_single_aggregate_math_and "interval": "week", "breakdown": "$some_prop", "breakdown_type": "person", - "events": [{"id": "sign up", "math": "median", "math_property": "$session_duration"}], + "events": [ + { + "id": "sign up", + "math": "median", + "math_property": "$session_duration", + } + ], }, ), self.team, @@ -1255,7 +1468,10 @@ def test_trends_person_breakdown_with_session_property_single_aggregate_math_and # another_val has: 10 seconds # some_val has: 1, 5 seconds, 15 seconds - self.assertEqual([resp["breakdown_value"] for resp in daily_response], ["another_val", "some_val"]) + self.assertEqual( + [resp["breakdown_value"] for resp in daily_response], + ["another_val", "some_val"], + ) self.assertEqual([resp["aggregated_value"] for resp in daily_response], [10.0, 5.0]) @snapshot_clickhouse_queries @@ -1289,7 +1505,6 @@ def test_trends_any_event_total_count(self): @also_test_with_materialized_columns(["$math_prop", "$some_property"]) def test_trends_breakdown_with_math_func(self): - with freeze_time("2020-01-01 00:06:34"): for i in range(20): _create_person(team_id=self.team.pk, distinct_ids=[f"person{i}"]) @@ -1322,7 +1537,13 @@ def test_trends_breakdown_with_math_func(self): "display": TRENDS_TABLE, "interval": "day", "breakdown": "$some_property", - "events": [{"id": "sign up", "math": "p90", "math_property": "$math_prop"}], + "events": [ + { + "id": "sign up", + "math": "p90", + "math_property": "$math_prop", + } + ], }, ), self.team, @@ -1336,7 +1557,14 @@ def test_trends_compare_day_interval_relative_range(self): self._create_events() with freeze_time("2020-01-04T13:00:01Z"): response = Trends().run( - Filter(team=self.team, data={"compare": "true", "date_from": "-7d", "events": [{"id": "sign up"}]}), + Filter( + team=self.team, + data={ + "compare": "true", + "date_from": "-7d", + "events": [{"id": "sign up"}], + }, + ), self.team, ) @@ -1380,7 +1608,11 @@ def test_trends_compare_day_interval_relative_range(self): with freeze_time("2020-01-04T13:00:01Z"): no_compare_response = Trends().run( - Filter(team=self.team, data={"compare": "false", "events": [{"id": "sign up"}]}), self.team + Filter( + team=self.team, + data={"compare": "false", "events": [{"id": "sign up"}]}, + ), + self.team, ) self.assertEqual(no_compare_response[0]["label"], "sign up") @@ -1555,17 +1787,28 @@ def _test_events_with_dates(self, dates: List[str], result, query_time=None, **f for time in dates: with freeze_time(time): _create_event( - event="event_name", team=self.team, distinct_id="person_1", properties={"$browser": "Safari"} + event="event_name", + team=self.team, + distinct_id="person_1", + properties={"$browser": "Safari"}, ) if query_time: with freeze_time(query_time): response = Trends().run( - Filter(team=self.team, data={**filter_params, "events": [{"id": "event_name"}]}), self.team + Filter( + team=self.team, + data={**filter_params, "events": [{"id": "event_name"}]}, + ), + self.team, ) else: response = Trends().run( - Filter(team=self.team, data={**filter_params, "events": [{"id": "event_name"}]}), self.team + Filter( + team=self.team, + data={**filter_params, "events": [{"id": "event_name"}]}, + ), + self.team, ) self.assertEqual(result[0]["count"], response[0]["count"]) @@ -1720,8 +1963,20 @@ def test_week_interval(self): "label": "event_name", "count": 4.0, "data": [0.0, 1.0, 2.0, 1.0, 0.0], - "labels": ["25-Oct-2020", "1-Nov-2020", "8-Nov-2020", "15-Nov-2020", "22-Nov-2020"], - "days": ["2020-10-25", "2020-11-01", "2020-11-08", "2020-11-15", "2020-11-22"], + "labels": [ + "25-Oct-2020", + "1-Nov-2020", + "8-Nov-2020", + "15-Nov-2020", + "22-Nov-2020", + ], + "days": [ + "2020-10-25", + "2020-11-01", + "2020-11-08", + "2020-11-15", + "2020-11-22", + ], } ], ) @@ -1749,8 +2004,22 @@ def test_month_interval(self): "label": "event_name", "count": 3.0, "data": [0.0, 2.0, 0.0, 0.0, 1.0, 0.0], - "labels": ["1-Jun-2020", "1-Jul-2020", "1-Aug-2020", "1-Sep-2020", "1-Oct-2020", "1-Nov-2020"], - "days": ["2020-06-01", "2020-07-01", "2020-08-01", "2020-09-01", "2020-10-01", "2020-11-01"], + "labels": [ + "1-Jun-2020", + "1-Jul-2020", + "1-Aug-2020", + "1-Sep-2020", + "1-Oct-2020", + "1-Nov-2020", + ], + "days": [ + "2020-06-01", + "2020-07-01", + "2020-08-01", + "2020-09-01", + "2020-10-01", + "2020-11-01", + ], } ], ) @@ -1778,7 +2047,12 @@ def test_interval_rounding(self): "label": "event_name", "count": 4.0, "data": [1.0, 2.0, 1.0, 0.0], - "labels": ["1-Nov-2020", "8-Nov-2020", "15-Nov-2020", "22-Nov-2020"], + "labels": [ + "1-Nov-2020", + "8-Nov-2020", + "15-Nov-2020", + "22-Nov-2020", + ], "days": ["2020-11-01", "2020-11-08", "2020-11-15", "2020-11-22"], } ], @@ -1872,7 +2146,12 @@ def test_yesterday_timerange(self): def test_last24hours_timerange(self): self._test_events_with_dates( - dates=["2020-11-01 05:20:00", "2020-11-01 10:22:00", "2020-11-01 10:25:00", "2020-11-02 08:25:00"], + dates=[ + "2020-11-01 05:20:00", + "2020-11-01 10:22:00", + "2020-11-01 10:25:00", + "2020-11-02 08:25:00", + ], date_from="-24h", query_time="2020-11-02 10:20:00", result=[ @@ -1900,9 +2179,14 @@ def test_last24hours_timerange(self): def test_last48hours_timerange(self): self._test_events_with_dates( - dates=["2020-11-01 05:20:00", "2020-11-01 10:22:00", "2020-11-01 10:25:00", "2020-11-02 08:25:00"], - date_from="-48h", - query_time="2020-11-02 10:20:00", + dates=[ + "2020-11-01 05:20:00", + "2020-11-01 10:22:00", + "2020-11-01 10:25:00", + "2020-11-02 08:25:00", + ], + date_from="-48h", + query_time="2020-11-02 10:20:00", result=[ { "action": { @@ -1928,7 +2212,12 @@ def test_last48hours_timerange(self): def test_last7days_timerange(self): self._test_events_with_dates( - dates=["2020-11-01 05:20:00", "2020-11-02 10:22:00", "2020-11-04 10:25:00", "2020-11-05 08:25:00"], + dates=[ + "2020-11-01 05:20:00", + "2020-11-02 10:22:00", + "2020-11-04 10:25:00", + "2020-11-05 08:25:00", + ], date_from="-7d", query_time="2020-11-07 10:20:00", result=[ @@ -2000,7 +2289,23 @@ def test_last14days_timerange(self): }, "label": "event_name", "count": 6.0, - "data": [0.0, 1.0, 1.0, 0.0, 1.0, 2.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0], + "data": [ + 0.0, + 1.0, + 1.0, + 0.0, + 1.0, + 2.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + ], "labels": [ "31-Oct-2020", "1-Nov-2020", @@ -2077,7 +2382,14 @@ def test_last30days_timerange(self): "22-Nov-2020", "29-Nov-2020", ], - "days": ["2020-10-25", "2020-11-01", "2020-11-08", "2020-11-15", "2020-11-22", "2020-11-29"], + "days": [ + "2020-10-25", + "2020-11-01", + "2020-11-08", + "2020-11-15", + "2020-11-22", + "2020-11-29", + ], } ], ) @@ -2293,8 +2605,22 @@ def test_custom_range_timerange(self): "label": "event_name", "count": 3.0, "data": [2.0, 0.0, 0.0, 0.0, 1.0, 0.0], - "labels": ["5-Jan-2020", "6-Jan-2020", "7-Jan-2020", "8-Jan-2020", "9-Jan-2020", "10-Jan-2020"], - "days": ["2020-01-05", "2020-01-06", "2020-01-07", "2020-01-08", "2020-01-09", "2020-01-10"], + "labels": [ + "5-Jan-2020", + "6-Jan-2020", + "7-Jan-2020", + "8-Jan-2020", + "9-Jan-2020", + "10-Jan-2020", + ], + "days": [ + "2020-01-05", + "2020-01-06", + "2020-01-07", + "2020-01-08", + "2020-01-09", + "2020-01-10", + ], } ], ) @@ -2363,9 +2689,15 @@ def test_trends_with_hogql_math(self): @snapshot_clickhouse_queries def test_trends_with_session_property_total_volume_math(self): _create_person( - team_id=self.team.pk, distinct_ids=["blabla", "anonymous_id"], properties={"$some_prop": "some_val"} + team_id=self.team.pk, + distinct_ids=["blabla", "anonymous_id"], + properties={"$some_prop": "some_val"}, + ) + _create_person( + team_id=self.team.pk, + distinct_ids=["blabla2"], + properties={"$some_prop": "some_val"}, ) - _create_person(team_id=self.team.pk, distinct_ids=["blabla2"], properties={"$some_prop": "some_val"}) _create_event( team=self.team, @@ -2452,7 +2784,13 @@ def test_trends_with_session_property_total_volume_math(self): team=self.team, data={ "interval": "week", - "events": [{"id": "sign up", "math": "median", "math_property": "$session_duration"}], + "events": [ + { + "id": "sign up", + "math": "median", + "math_property": "$session_duration", + } + ], }, ), self.team, @@ -2464,7 +2802,13 @@ def test_trends_with_session_property_total_volume_math(self): team=self.team, data={ "interval": "day", - "events": [{"id": "sign up", "math": "median", "math_property": "$session_duration"}], + "events": [ + { + "id": "sign up", + "math": "median", + "math_property": "$session_duration", + } + ], }, ), self.team, @@ -2491,9 +2835,15 @@ def test_trends_with_session_property_total_volume_math(self): @snapshot_clickhouse_queries def test_trends_with_session_property_total_volume_math_with_breakdowns(self): _create_person( - team_id=self.team.pk, distinct_ids=["blabla", "anonymous_id"], properties={"$some_prop": "some_val"} + team_id=self.team.pk, + distinct_ids=["blabla", "anonymous_id"], + properties={"$some_prop": "some_val"}, + ) + _create_person( + team_id=self.team.pk, + distinct_ids=["blabla2"], + properties={"$some_prop": "some_val"}, ) - _create_person(team_id=self.team.pk, distinct_ids=["blabla2"], properties={"$some_prop": "some_val"}) _create_event( team=self.team, @@ -2581,7 +2931,13 @@ def test_trends_with_session_property_total_volume_math_with_breakdowns(self): data={ "breakdown": "$some_property", "interval": "week", - "events": [{"id": "sign up", "math": "median", "math_property": "$session_duration"}], + "events": [ + { + "id": "sign up", + "math": "median", + "math_property": "$session_duration", + } + ], }, ), self.team, @@ -2594,7 +2950,13 @@ def test_trends_with_session_property_total_volume_math_with_breakdowns(self): data={ "breakdown": "$some_property", "interval": "day", - "events": [{"id": "sign up", "math": "median", "math_property": "$session_duration"}], + "events": [ + { + "id": "sign up", + "math": "median", + "math_property": "$session_duration", + } + ], }, ), self.team, @@ -2626,9 +2988,15 @@ def test_trends_with_session_property_total_volume_math_with_breakdowns(self): def test_trends_with_session_property_total_volume_math_with_sessions_spanning_multiple_intervals(self): _create_person( - team_id=self.team.pk, distinct_ids=["blabla", "anonymous_id"], properties={"$some_prop": "some_val"} + team_id=self.team.pk, + distinct_ids=["blabla", "anonymous_id"], + properties={"$some_prop": "some_val"}, + ) + _create_person( + team_id=self.team.pk, + distinct_ids=["blabla2"], + properties={"$some_prop": "some_val"}, ) - _create_person(team_id=self.team.pk, distinct_ids=["blabla2"], properties={"$some_prop": "some_val"}) _create_event( team=self.team, @@ -2674,7 +3042,13 @@ def test_trends_with_session_property_total_volume_math_with_sessions_spanning_m team=self.team, data={ "interval": "day", - "events": [{"id": "sign up", "math": "median", "math_property": "$session_duration"}], + "events": [ + { + "id": "sign up", + "math": "median", + "math_property": "$session_duration", + } + ], }, ), self.team, @@ -2717,9 +3091,24 @@ def test_filter_events_by_cohort(self): _create_person(team_id=self.team.pk, distinct_ids=["person_1"], properties={"name": "John"}) _create_person(team_id=self.team.pk, distinct_ids=["person_2"], properties={"name": "Jane"}) - _create_event(event="event_name", team=self.team, distinct_id="person_1", properties={"$browser": "Safari"}) - _create_event(event="event_name", team=self.team, distinct_id="person_2", properties={"$browser": "Chrome"}) - _create_event(event="event_name", team=self.team, distinct_id="person_2", properties={"$browser": "Safari"}) + _create_event( + event="event_name", + team=self.team, + distinct_id="person_1", + properties={"$browser": "Safari"}, + ) + _create_event( + event="event_name", + team=self.team, + distinct_id="person_2", + properties={"$browser": "Chrome"}, + ) + _create_event( + event="event_name", + team=self.team, + distinct_id="person_2", + properties={"$browser": "Safari"}, + ) cohort = _create_cohort( team=self.team, @@ -2745,12 +3134,35 @@ def test_filter_events_by_cohort(self): @snapshot_clickhouse_queries def test_filter_events_by_precalculated_cohort(self): with freeze_time("2020-01-02"): - _create_person(team_id=self.team.pk, distinct_ids=["person_1"], properties={"name": "John"}) - _create_person(team_id=self.team.pk, distinct_ids=["person_2"], properties={"name": "Jane"}) + _create_person( + team_id=self.team.pk, + distinct_ids=["person_1"], + properties={"name": "John"}, + ) + _create_person( + team_id=self.team.pk, + distinct_ids=["person_2"], + properties={"name": "Jane"}, + ) - _create_event(event="event_name", team=self.team, distinct_id="person_1", properties={"$browser": "Safari"}) - _create_event(event="event_name", team=self.team, distinct_id="person_2", properties={"$browser": "Chrome"}) - _create_event(event="event_name", team=self.team, distinct_id="person_2", properties={"$browser": "Safari"}) + _create_event( + event="event_name", + team=self.team, + distinct_id="person_1", + properties={"$browser": "Safari"}, + ) + _create_event( + event="event_name", + team=self.team, + distinct_id="person_2", + properties={"$browser": "Chrome"}, + ) + _create_event( + event="event_name", + team=self.team, + distinct_id="person_2", + properties={"$browser": "Safari"}, + ) cohort = _create_cohort( team=self.team, @@ -2785,7 +3197,13 @@ def test_interval_filtering_hour(self): with freeze_time("2020-01-02"): response = Trends().run( - Filter(data={"date_from": "2019-12-24", "interval": "hour", "events": [{"id": "sign up"}]}), + Filter( + data={ + "date_from": "2019-12-24", + "interval": "hour", + "events": [{"id": "sign up"}], + } + ), self.team, ) self.assertEqual(response[0]["labels"][3], "24-Dec-2019 03:00") @@ -2810,7 +3228,8 @@ def test_interval_filtering_week(self): self.team, ) self.assertEqual( - response[0]["labels"][:5], ["24-Nov-2019", "1-Dec-2019", "8-Dec-2019", "15-Dec-2019", "22-Dec-2019"] + response[0]["labels"][:5], + ["24-Nov-2019", "1-Dec-2019", "8-Dec-2019", "15-Dec-2019", "22-Dec-2019"], ) self.assertEqual(response[0]["data"][:5], [0.0, 0.0, 0.0, 0.0, 1.0]) @@ -2820,7 +3239,12 @@ def test_interval_filtering_month(self): with freeze_time("2020-01-02"): response = Trends().run( Filter( - team=self.team, data={"date_from": "2019-9-24", "interval": "month", "events": [{"id": "sign up"}]} + team=self.team, + data={ + "date_from": "2019-9-24", + "interval": "month", + "events": [{"id": "sign up"}], + }, ), self.team, ) @@ -2839,7 +3263,14 @@ def test_interval_filtering_today_hourly(self): with freeze_time("2020-01-02T23:31:00Z"): response = Trends().run( - Filter(team=self.team, data={"date_from": "dStart", "interval": "hour", "events": [{"id": "sign up"}]}), + Filter( + team=self.team, + data={ + "date_from": "dStart", + "interval": "hour", + "events": [{"id": "sign up"}], + }, + ), self.team, ) self.assertEqual(response[0]["labels"][23], "2-Jan-2020 23:00") @@ -2860,25 +3291,56 @@ def test_breakdown_label(self): self.assertEqual(none_label, {"label": "$pageview - Other", "breakdown_value": "Other"}) cohort_all_label = breakdown_label(entity, "cohort_all") - self.assertEqual(cohort_all_label, {"label": "$pageview - all users", "breakdown_value": "all"}) + self.assertEqual( + cohort_all_label, + {"label": "$pageview - all users", "breakdown_value": "all"}, + ) cohort = _create_cohort(team=self.team, name="cohort1", groups=[{"properties": {"name": "Jane"}}]) cohort_label = breakdown_label(entity, f"cohort_{cohort.pk}") - self.assertEqual(cohort_label, {"label": f"$pageview - {cohort.name}", "breakdown_value": cohort.pk}) + self.assertEqual( + cohort_label, + {"label": f"$pageview - {cohort.name}", "breakdown_value": cohort.pk}, + ) @also_test_with_materialized_columns(["key"]) def test_breakdown_with_filter(self): - _create_person(team_id=self.team.pk, distinct_ids=["person1"], properties={"email": "test@posthog.com"}) - _create_person(team_id=self.team.pk, distinct_ids=["person2"], properties={"email": "test@gmail.com"}) - _create_event(event="sign up", distinct_id="person1", team=self.team, properties={"key": "val"}) - _create_event(event="sign up", distinct_id="person2", team=self.team, properties={"key": "oh"}) + _create_person( + team_id=self.team.pk, + distinct_ids=["person1"], + properties={"email": "test@posthog.com"}, + ) + _create_person( + team_id=self.team.pk, + distinct_ids=["person2"], + properties={"email": "test@gmail.com"}, + ) + _create_event( + event="sign up", + distinct_id="person1", + team=self.team, + properties={"key": "val"}, + ) + _create_event( + event="sign up", + distinct_id="person2", + team=self.team, + properties={"key": "oh"}, + ) response = Trends().run( Filter( team=self.team, data={ "date_from": "-14d", "breakdown": "key", - "events": [{"id": "sign up", "name": "sign up", "type": "events", "order": 0}], + "events": [ + { + "id": "sign up", + "name": "sign up", + "type": "events", + "order": 0, + } + ], "properties": [{"key": "key", "value": "oh", "operator": "not_icontains"}], }, ), @@ -2889,7 +3351,10 @@ def test_breakdown_with_filter(self): def test_action_filtering(self): sign_up_action, person = self._create_events() - action_response = Trends().run(Filter(team=self.team, data={"actions": [{"id": sign_up_action.id}]}), self.team) + action_response = Trends().run( + Filter(team=self.team, data={"actions": [{"id": sign_up_action.id}]}), + self.team, + ) event_response = Trends().run(Filter(team=self.team, data={"events": [{"id": "sign up"}]}), self.team) self.assertEqual(len(action_response), 1) @@ -2931,7 +3396,9 @@ def test_action_filtering_with_cohort(self): ) sign_up_action = _create_action( - team=self.team, name="sign up", properties=[{"key": "id", "type": "cohort", "value": cohort.id}] + team=self.team, + name="sign up", + properties=[{"key": "id", "type": "cohort", "value": cohort.id}], ) cohort.calculate_people_ch(pending_version=2) @@ -2963,9 +3430,21 @@ def test_trends_for_non_existing_action(self): @also_test_with_materialized_columns(person_properties=["email", "bar"]) def test_trends_regression_filtering_by_action_with_person_properties(self): - _create_person(team_id=self.team.pk, properties={"email": "foo@example.com", "bar": "aa"}, distinct_ids=["d1"]) - _create_person(team_id=self.team.pk, properties={"email": "bar@example.com", "bar": "bb"}, distinct_ids=["d2"]) - _create_person(team_id=self.team.pk, properties={"email": "efg@example.com", "bar": "ab"}, distinct_ids=["d3"]) + _create_person( + team_id=self.team.pk, + properties={"email": "foo@example.com", "bar": "aa"}, + distinct_ids=["d1"], + ) + _create_person( + team_id=self.team.pk, + properties={"email": "bar@example.com", "bar": "bb"}, + distinct_ids=["d2"], + ) + _create_person( + team_id=self.team.pk, + properties={"email": "efg@example.com", "bar": "ab"}, + distinct_ids=["d3"], + ) _create_person(team_id=self.team.pk, properties={"bar": "aa"}, distinct_ids=["d4"]) with freeze_time("2020-01-02 16:34:34"): @@ -2983,7 +3462,11 @@ def test_trends_regression_filtering_by_action_with_person_properties(self): with freeze_time("2020-01-04T13:01:01Z"): response = Trends().run( - Filter(team=self.team, data={"actions": [{"id": event_filtering_action.id}]}), self.team + Filter( + team=self.team, + data={"actions": [{"id": event_filtering_action.id}]}, + ), + self.team, ) self.assertEqual(len(response), 1) self.assertEqual(response[0]["count"], 3) @@ -2994,7 +3477,14 @@ def test_trends_regression_filtering_by_action_with_person_properties(self): team=self.team, data={ "actions": [{"id": event_filtering_action.id}], - "properties": [{"key": "email", "type": "person", "value": "is_set", "operator": "is_set"}], + "properties": [ + { + "key": "email", + "type": "person", + "value": "is_set", + "operator": "is_set", + } + ], }, ), self.team, @@ -3011,7 +3501,11 @@ def test_dau_filtering(self): with freeze_time("2020-01-04"): action_response = Trends().run( - Filter(team=self.team, data={"actions": [{"id": sign_up_action.id, "math": "dau"}]}), self.team + Filter( + team=self.team, + data={"actions": [{"id": sign_up_action.id, "math": "dau"}]}, + ), + self.team, ) response = Trends().run(Filter(data={"events": [{"id": "sign up", "math": "dau"}]}), self.team) @@ -3024,9 +3518,17 @@ def _create_maths_events(self, values): _create_person(team_id=self.team.pk, distinct_ids=["someone_else"]) for value in values: _create_event( - team=self.team, event="sign up", distinct_id="someone_else", properties={"some_number": value} + team=self.team, + event="sign up", + distinct_id="someone_else", + properties={"some_number": value}, ) - _create_event(team=self.team, event="sign up", distinct_id="someone_else", properties={"some_number": None}) + _create_event( + team=self.team, + event="sign up", + distinct_id="someone_else", + properties={"some_number": None}, + ) return sign_up_action def _test_math_property_aggregation(self, math_property, values, expected_value): @@ -3035,12 +3537,30 @@ def _test_math_property_aggregation(self, math_property, values, expected_value) action_response = Trends().run( Filter( team=self.team, - data={"actions": [{"id": sign_up_action.id, "math": math_property, "math_property": "some_number"}]}, + data={ + "actions": [ + { + "id": sign_up_action.id, + "math": math_property, + "math_property": "some_number", + } + ] + }, ), self.team, ) event_response = Trends().run( - Filter(data={"events": [{"id": "sign up", "math": math_property, "math_property": "some_number"}]}), + Filter( + data={ + "events": [ + { + "id": "sign up", + "math": math_property, + "math_property": "some_number", + } + ] + } + ), self.team, ) # :TRICKY: Work around clickhouse functions not being 100% @@ -3083,16 +3603,47 @@ def test_p99_filtering(self): def test_avg_filtering_non_number_resiliency(self): sign_up_action, person = self._create_events() _create_person(team_id=self.team.pk, distinct_ids=["someone_else"]) - _create_event(team=self.team, event="sign up", distinct_id="someone_else", properties={"some_number": 2}) - _create_event(team=self.team, event="sign up", distinct_id="someone_else", properties={"some_number": "x"}) - _create_event(team=self.team, event="sign up", distinct_id="someone_else", properties={"some_number": None}) - _create_event(team=self.team, event="sign up", distinct_id="someone_else", properties={"some_number": 8}) + _create_event( + team=self.team, + event="sign up", + distinct_id="someone_else", + properties={"some_number": 2}, + ) + _create_event( + team=self.team, + event="sign up", + distinct_id="someone_else", + properties={"some_number": "x"}, + ) + _create_event( + team=self.team, + event="sign up", + distinct_id="someone_else", + properties={"some_number": None}, + ) + _create_event( + team=self.team, + event="sign up", + distinct_id="someone_else", + properties={"some_number": 8}, + ) action_response = Trends().run( - Filter(data={"actions": [{"id": sign_up_action.id, "math": "avg", "math_property": "some_number"}]}), + Filter( + data={ + "actions": [ + { + "id": sign_up_action.id, + "math": "avg", + "math_property": "some_number", + } + ] + } + ), self.team, ) event_response = Trends().run( - Filter(data={"events": [{"id": "sign up", "math": "avg", "math_property": "some_number"}]}), self.team + Filter(data={"events": [{"id": "sign up", "math": "avg", "math_property": "some_number"}]}), + self.team, ) self.assertEqual(action_response[0]["data"][-1], 5) self.assertEntityResponseEqual(action_response, event_response) @@ -3107,8 +3658,14 @@ def test_per_entity_filtering(self): data={ "date_from": "-7d", "events": [ - {"id": "sign up", "properties": [{"key": "$some_property", "value": "value"}]}, - {"id": "sign up", "properties": [{"key": "$some_property", "value": "other_value"}]}, + { + "id": "sign up", + "properties": [{"key": "$some_property", "value": "value"}], + }, + { + "id": "sign up", + "properties": [{"key": "$some_property", "value": "other_value"}], + }, ], }, ), @@ -3123,10 +3680,26 @@ def test_per_entity_filtering(self): self.assertEqual(response[1]["count"], 1) def _create_multiple_people(self): - person1 = _create_person(team_id=self.team.pk, distinct_ids=["person1"], properties={"name": "person1"}) - person2 = _create_person(team_id=self.team.pk, distinct_ids=["person2"], properties={"name": "person2"}) - person3 = _create_person(team_id=self.team.pk, distinct_ids=["person3"], properties={"name": "person3"}) - person4 = _create_person(team_id=self.team.pk, distinct_ids=["person4"], properties={"name": "person4"}) + person1 = _create_person( + team_id=self.team.pk, + distinct_ids=["person1"], + properties={"name": "person1"}, + ) + person2 = _create_person( + team_id=self.team.pk, + distinct_ids=["person2"], + properties={"name": "person2"}, + ) + person3 = _create_person( + team_id=self.team.pk, + distinct_ids=["person3"], + properties={"name": "person3"}, + ) + person4 = _create_person( + team_id=self.team.pk, + distinct_ids=["person4"], + properties={"name": "person4"}, + ) journey = { "person1": [ @@ -3255,7 +3828,13 @@ def test_entity_person_property_filtering(self): "events": [ { "id": "watched movie", - "properties": [{"key": "name", "value": "person1", "type": "person"}], + "properties": [ + { + "key": "name", + "value": "person1", + "type": "person", + } + ], } ] }, @@ -3269,7 +3848,12 @@ def test_entity_person_property_filtering(self): def test_breakdown_by_empty_cohort(self): _create_person(team_id=self.team.pk, distinct_ids=["p1"], properties={"name": "p1"}) - _create_event(team=self.team, event="$pageview", distinct_id="p1", timestamp="2020-01-04T12:00:00Z") + _create_event( + team=self.team, + event="$pageview", + distinct_id="p1", + timestamp="2020-01-04T12:00:00Z", + ) with freeze_time("2020-01-04T13:01:01Z"): event_response = Trends().run( @@ -3332,7 +3916,14 @@ def test_breakdown_by_cohort(self): "date_from": "-14d", "breakdown": json.dumps([cohort.pk, cohort2.pk, cohort3.pk, "all"]), "breakdown_type": "cohort", - "events": [{"id": "watched movie", "name": "watched movie", "type": "events", "order": 0}], + "events": [ + { + "id": "watched movie", + "name": "watched movie", + "type": "events", + "order": 0, + } + ], }, ), self.team, @@ -3403,7 +3994,8 @@ def test_interval_filtering_breakdown(self): ) self.assertEqual( - response[0]["labels"][:5], ["24-Nov-2019", "1-Dec-2019", "8-Dec-2019", "15-Dec-2019", "22-Dec-2019"] + response[0]["labels"][:5], + ["24-Nov-2019", "1-Dec-2019", "8-Dec-2019", "15-Dec-2019", "22-Dec-2019"], ) self.assertEqual(response[0]["data"][:5], [0.0, 0.0, 0.0, 0.0, 1.0]) @@ -3472,14 +4064,22 @@ def test_breakdown_by_person_property(self): "date_from": "-14d", "breakdown": "name", "breakdown_type": "person", - "events": [{"id": "watched movie", "name": "watched movie", "type": "events", "order": 0}], + "events": [ + { + "id": "watched movie", + "name": "watched movie", + "type": "events", + "order": 0, + } + ], }, ), self.team, ) self.assertListEqual( - sorted(res["breakdown_value"] for res in event_response), ["person1", "person2", "person3"] + sorted(res["breakdown_value"] for res in event_response), + ["person1", "person2", "person3"], ) for response in event_response: @@ -3505,14 +4105,22 @@ def test_breakdown_by_person_property_for_person_on_events(self): "date_from": "-14d", "breakdown": "name", "breakdown_type": "person", - "events": [{"id": "watched movie", "name": "watched movie", "type": "events", "order": 0}], + "events": [ + { + "id": "watched movie", + "name": "watched movie", + "type": "events", + "order": 0, + } + ], }, ), self.team, ) self.assertListEqual( - sorted(res["breakdown_value"] for res in event_response), ["person1", "person2", "person3"] + sorted(res["breakdown_value"] for res in event_response), + ["person1", "person2", "person3"], ) for response in event_response: @@ -3564,14 +4172,22 @@ def test_breakdown_by_person_property_for_person_on_events_with_zero_person_ids( "date_from": "-14d", "breakdown": "name", "breakdown_type": "person", - "events": [{"id": "watched movie", "name": "watched movie", "type": "events", "order": 0}], + "events": [ + { + "id": "watched movie", + "name": "watched movie", + "type": "events", + "order": 0, + } + ], }, ), self.team, ) self.assertListEqual( - sorted(res["breakdown_value"] for res in event_response), ["person1", "person2", "person3"] + sorted(res["breakdown_value"] for res in event_response), + ["person1", "person2", "person3"], ) for response in event_response: @@ -3643,7 +4259,13 @@ def test_breakdown_by_property_pie(self): "breakdown_type": "event", "display": "ActionsPie", "events": [ - {"id": "watched movie", "name": "watched movie", "type": "events", "order": 0, "math": "dau"} + { + "id": "watched movie", + "name": "watched movie", + "type": "events", + "order": 0, + "math": "dau", + } ], } event_response = Trends().run(Filter(team=self.team, data=data), self.team) @@ -3652,7 +4274,8 @@ def test_breakdown_by_property_pie(self): entity = Entity({"id": "watched movie", "type": "events", "math": "dau"}) people_value_1 = self._get_trend_people( - Filter(team=self.team, data={**data, "breakdown_value": "value_1"}), entity + Filter(team=self.team, data={**data, "breakdown_value": "value_1"}), + entity, ) assert people_value_1 == [ # Persons with higher value come first @@ -3695,7 +4318,8 @@ def test_breakdown_by_property_pie(self): ] people_value_2 = self._get_trend_people( - Filter(team=self.team, data={**data, "breakdown_value": "value_2"}), entity + Filter(team=self.team, data={**data, "breakdown_value": "value_2"}), + entity, ) assert people_value_2 == [ { @@ -3763,7 +4387,12 @@ def test_breakdown_by_person_property_pie_with_event_dau_filter(self): "order": 0, "math": "dau", "properties": [ - {"key": "name", "operator": "not_icontains", "value": "person3", "type": "person"} + { + "key": "name", + "operator": "not_icontains", + "value": "person3", + "type": "person", + } ], } ], @@ -3864,7 +4493,11 @@ def test_filter_test_accounts_cohorts(self): self.team.save() response = Trends().run( - Filter(data={"events": [{"id": "event_name"}], "filter_test_accounts": True}, team=self.team), self.team + Filter( + data={"events": [{"id": "event_name"}], "filter_test_accounts": True}, + team=self.team, + ), + self.team, ) self.assertEqual(response[0]["count"], 2) @@ -3969,7 +4602,9 @@ def test_trends_aggregate_by_distinct_id(self): # Stopgap until https://github.com/PostHog/meta/pull/39 is implemented _create_person( - team_id=self.team.pk, distinct_ids=["blabla", "anonymous_id"], properties={"$some_prop": "some_val"} + team_id=self.team.pk, + distinct_ids=["blabla", "anonymous_id"], + properties={"$some_prop": "some_val"}, ) _create_person(team_id=self.team.pk, distinct_ids=["third"]) @@ -3984,7 +4619,13 @@ def test_trends_aggregate_by_distinct_id(self): with override_instance_config("AGGREGATE_BY_DISTINCT_IDS_TEAMS", f"{self.team.pk},4"): with freeze_time("2019-12-31T13:00:01Z"): daily_response = Trends().run( - Filter(team=self.team, data={"interval": "day", "events": [{"id": "sign up", "math": "dau"}]}), + Filter( + team=self.team, + data={ + "interval": "day", + "events": [{"id": "sign up", "math": "dau"}], + }, + ), self.team, ) @@ -3997,7 +4638,13 @@ def test_trends_aggregate_by_distinct_id(self): data={ "interval": "day", "events": [{"id": "sign up", "math": "dau"}], - "properties": [{"key": "$some_prop", "value": "some_val", "type": "person"}], + "properties": [ + { + "key": "$some_prop", + "value": "some_val", + "type": "person", + } + ], }, ), self.team, @@ -4028,7 +4675,10 @@ def test_trends_aggregate_by_distinct_id(self): monthly_response = Trends().run( Filter( team=self.team, - data={"interval": "day", "events": [{"id": "sign up", "math": "monthly_active"}]}, + data={ + "interval": "day", + "events": [{"id": "sign up", "math": "monthly_active"}], + }, ), self.team, ) @@ -4037,7 +4687,11 @@ def test_trends_aggregate_by_distinct_id(self): with freeze_time("2019-12-31T13:00:01Z"): weekly_response = Trends().run( Filter( - team=self.team, data={"interval": "day", "events": [{"id": "sign up", "math": "weekly_active"}]} + team=self.team, + data={ + "interval": "day", + "events": [{"id": "sign up", "math": "weekly_active"}], + }, ), self.team, ) @@ -4067,7 +4721,14 @@ def test_breakdown_filtering_limit(self): data={ "date_from": "-14d", "breakdown": "$some_property", - "events": [{"id": "sign up", "name": "sign up", "type": "events", "order": 0}], + "events": [ + { + "id": "sign up", + "name": "sign up", + "type": "events", + "order": 0, + } + ], }, ), self.team, @@ -4104,7 +4765,13 @@ def test_breakdown_with_person_property_filter(self): "name": "watched movie", "type": "events", "order": 0, - "properties": [{"key": "name", "value": "person2", "type": "person"}], + "properties": [ + { + "key": "name", + "value": "person2", + "type": "person", + } + ], } ], }, @@ -4128,7 +4795,12 @@ def test_breakdown_filtering(self): "date_from": "-14d", "breakdown": "$some_property", "events": [ - {"id": "sign up", "name": "sign up", "type": "events", "order": 0}, + { + "id": "sign up", + "name": "sign up", + "type": "events", + "order": 0, + }, {"id": "no events"}, ], }, @@ -4148,13 +4820,36 @@ def test_breakdown_filtering(self): @also_test_with_materialized_columns(person_properties=["email"]) def test_breakdown_filtering_persons(self): - _create_person(team_id=self.team.pk, distinct_ids=["person1"], properties={"email": "test@posthog.com"}) - _create_person(team_id=self.team.pk, distinct_ids=["person2"], properties={"email": "test@gmail.com"}) + _create_person( + team_id=self.team.pk, + distinct_ids=["person1"], + properties={"email": "test@posthog.com"}, + ) + _create_person( + team_id=self.team.pk, + distinct_ids=["person2"], + properties={"email": "test@gmail.com"}, + ) _create_person(team_id=self.team.pk, distinct_ids=["person3"], properties={}) - _create_event(event="sign up", distinct_id="person1", team=self.team, properties={"key": "val"}) - _create_event(event="sign up", distinct_id="person2", team=self.team, properties={"key": "val"}) - _create_event(event="sign up", distinct_id="person3", team=self.team, properties={"key": "val"}) + _create_event( + event="sign up", + distinct_id="person1", + team=self.team, + properties={"key": "val"}, + ) + _create_event( + event="sign up", + distinct_id="person2", + team=self.team, + properties={"key": "val"}, + ) + _create_event( + event="sign up", + distinct_id="person3", + team=self.team, + properties={"key": "val"}, + ) response = Trends().run( Filter( team=self.team, @@ -4162,7 +4857,14 @@ def test_breakdown_filtering_persons(self): "date_from": "-14d", "breakdown": "email", "breakdown_type": "person", - "events": [{"id": "sign up", "name": "sign up", "type": "events", "order": 0}], + "events": [ + { + "id": "sign up", + "name": "sign up", + "type": "events", + "order": 0, + } + ], }, ), self.team, @@ -4178,13 +4880,36 @@ def test_breakdown_filtering_persons(self): # ensure that column names are properly handled when subqueries and person subquery share properties column @also_test_with_materialized_columns(event_properties=["key"], person_properties=["email"]) def test_breakdown_filtering_persons_with_action_props(self): - _create_person(team_id=self.team.pk, distinct_ids=["person1"], properties={"email": "test@posthog.com"}) - _create_person(team_id=self.team.pk, distinct_ids=["person2"], properties={"email": "test@gmail.com"}) + _create_person( + team_id=self.team.pk, + distinct_ids=["person1"], + properties={"email": "test@posthog.com"}, + ) + _create_person( + team_id=self.team.pk, + distinct_ids=["person2"], + properties={"email": "test@gmail.com"}, + ) _create_person(team_id=self.team.pk, distinct_ids=["person3"], properties={}) - _create_event(event="sign up", distinct_id="person1", team=self.team, properties={"key": "val"}) - _create_event(event="sign up", distinct_id="person2", team=self.team, properties={"key": "val"}) - _create_event(event="sign up", distinct_id="person3", team=self.team, properties={"key": "val"}) + _create_event( + event="sign up", + distinct_id="person1", + team=self.team, + properties={"key": "val"}, + ) + _create_event( + event="sign up", + distinct_id="person2", + team=self.team, + properties={"key": "val"}, + ) + _create_event( + event="sign up", + distinct_id="person3", + team=self.team, + properties={"key": "val"}, + ) action = _create_action( name="sign up", team=self.team, @@ -4217,26 +4942,42 @@ def test_breakdown_filtering_with_properties(self): team=self.team, event="sign up", distinct_id="blabla", - properties={"$current_url": "first url", "$browser": "Firefox", "$os": "Mac"}, + properties={ + "$current_url": "first url", + "$browser": "Firefox", + "$os": "Mac", + }, ) _create_event( team=self.team, event="sign up", distinct_id="blabla", - properties={"$current_url": "first url", "$browser": "Chrome", "$os": "Windows"}, + properties={ + "$current_url": "first url", + "$browser": "Chrome", + "$os": "Windows", + }, ) with freeze_time("2020-01-04T13:01:01Z"): _create_event( team=self.team, event="sign up", distinct_id="blabla", - properties={"$current_url": "second url", "$browser": "Firefox", "$os": "Mac"}, + properties={ + "$current_url": "second url", + "$browser": "Firefox", + "$os": "Mac", + }, ) _create_event( team=self.team, event="sign up", distinct_id="blabla", - properties={"$current_url": "second url", "$browser": "Chrome", "$os": "Windows"}, + properties={ + "$current_url": "second url", + "$browser": "Chrome", + "$os": "Windows", + }, ) with freeze_time("2020-01-05T13:01:01Z"): @@ -4278,26 +5019,42 @@ def test_breakdown_filtering_with_properties_in_new_format(self): team=self.team, event="sign up", distinct_id="blabla", - properties={"$current_url": "first url", "$browser": "Firefox", "$os": "Windows"}, + properties={ + "$current_url": "first url", + "$browser": "Firefox", + "$os": "Windows", + }, ) _create_event( team=self.team, event="sign up", distinct_id="blabla", - properties={"$current_url": "first url", "$browser": "Chrome", "$os": "Mac"}, + properties={ + "$current_url": "first url", + "$browser": "Chrome", + "$os": "Mac", + }, ) with freeze_time("2020-01-04T13:01:01Z"): _create_event( team=self.team, event="sign up", distinct_id="blabla1", - properties={"$current_url": "second url", "$browser": "Firefox", "$os": "Mac"}, + properties={ + "$current_url": "second url", + "$browser": "Firefox", + "$os": "Mac", + }, ) _create_event( team=self.team, event="sign up", distinct_id="blabla2", - properties={"$current_url": "second url", "$browser": "Chrome", "$os": "Windows"}, + properties={ + "$current_url": "second url", + "$browser": "Chrome", + "$os": "Windows", + }, ) with freeze_time("2020-01-05T13:01:01Z"): @@ -4318,7 +5075,10 @@ def test_breakdown_filtering_with_properties_in_new_format(self): ], "properties": { "type": "OR", - "values": [{"key": "$browser", "value": "Firefox"}, {"key": "$os", "value": "Windows"}], + "values": [ + {"key": "$browser", "value": "Firefox"}, + {"key": "$os", "value": "Windows"}, + ], }, }, ), @@ -4350,7 +5110,10 @@ def test_breakdown_filtering_with_properties_in_new_format(self): ], "properties": { "type": "AND", - "values": [{"key": "$browser", "value": "Firefox"}, {"key": "$os", "value": "Windows"}], + "values": [ + {"key": "$browser", "value": "Firefox"}, + {"key": "$os", "value": "Windows"}, + ], }, }, ), @@ -4394,7 +5157,13 @@ def test_mau_with_breakdown_filtering_and_prop_filter(self): "breakdown": "$some_prop", "breakdown_type": "person", "events": [{"id": "sign up", "math": "monthly_active"}], - "properties": [{"key": "filter_prop", "value": "filter_val", "type": "person"}], + "properties": [ + { + "key": "filter_prop", + "value": "filter_val", + "type": "person", + } + ], "display": "ActionsLineGraph", }, ), @@ -4415,19 +5184,29 @@ def test_dau_with_breakdown_filtering(self): sign_up_action, _ = self._create_events() with freeze_time("2020-01-02T13:01:01Z"): _create_event( - team=self.team, event="sign up", distinct_id="blabla", properties={"$some_property": "other_value"} + team=self.team, + event="sign up", + distinct_id="blabla", + properties={"$some_property": "other_value"}, ) with freeze_time("2020-01-04T13:01:01Z"): action_response = Trends().run( Filter( team=self.team, - data={"breakdown": "$some_property", "actions": [{"id": sign_up_action.id, "math": "dau"}]}, + data={ + "breakdown": "$some_property", + "actions": [{"id": sign_up_action.id, "math": "dau"}], + }, ), self.team, ) event_response = Trends().run( Filter( - team=self.team, data={"breakdown": "$some_property", "events": [{"id": "sign up", "math": "dau"}]} + team=self.team, + data={ + "breakdown": "$some_property", + "events": [{"id": "sign up", "math": "dau"}], + }, ), self.team, ) @@ -4448,7 +5227,10 @@ def test_dau_with_breakdown_filtering_with_sampling(self): sign_up_action, _ = self._create_events() with freeze_time("2020-01-02T13:01:01Z"): _create_event( - team=self.team, event="sign up", distinct_id="blabla", properties={"$some_property": "other_value"} + team=self.team, + event="sign up", + distinct_id="blabla", + properties={"$some_property": "other_value"}, ) with freeze_time("2020-01-04T13:01:01Z"): action_response = Trends().run( @@ -4530,7 +5312,9 @@ def test_dau_with_breakdown_filtering_with_prop_filter(self): def test_against_clashing_entity_and_property_filter_naming(self): # Regression test for https://github.com/PostHog/posthog/issues/5814 _create_person( - team_id=self.team.pk, distinct_ids=["blabla", "anonymous_id"], properties={"$some_prop": "some_val"} + team_id=self.team.pk, + distinct_ids=["blabla", "anonymous_id"], + properties={"$some_prop": "some_val"}, ) _create_event( team=self.team, @@ -4548,10 +5332,21 @@ def test_against_clashing_entity_and_property_filter_naming(self): "events": [ { "id": "$pageview", - "properties": [{"key": "$host", "operator": "icontains", "value": ".com"}], + "properties": [ + { + "key": "$host", + "operator": "icontains", + "value": ".com", + } + ], + } + ], + "properties": [ + { + "key": "$host", + "value": ["app.example.com", "another.com"], } ], - "properties": [{"key": "$host", "value": ["app.example.com", "another.com"]}], "breakdown": "$some_prop", "breakdown_type": "person", }, @@ -4565,7 +5360,9 @@ def test_against_clashing_entity_and_property_filter_naming(self): @also_test_with_materialized_columns(["$current_url"]) def test_action_with_prop(self): _create_person( - team_id=self.team.pk, distinct_ids=["blabla", "anonymous_id"], properties={"$some_prop": "some_val"} + team_id=self.team.pk, + distinct_ids=["blabla", "anonymous_id"], + properties={"$some_prop": "some_val"}, ) sign_up_action = Action.objects.create(team=self.team, name="sign up") ActionStep.objects.create( @@ -4609,7 +5406,9 @@ def test_combine_all_cohort_and_icontains(self): # This caused some issues with SQL parsing sign_up_action, _ = self._create_events() cohort = Cohort.objects.create( - team=self.team, name="a", groups=[{"properties": [{"key": "key", "value": "value", "type": "person"}]}] + team=self.team, + name="a", + groups=[{"properties": [{"key": "key", "value": "value", "type": "person"}]}], ) action_response = Trends().run( Filter( @@ -4642,20 +5441,48 @@ def test_person_filtering_in_cohort_in_action(self): step.save() with freeze_time("2020-01-04T13:01:01Z"): action_response = Trends().run( - Filter(team=self.team, data={"actions": [{"id": sign_up_action.id}], "breakdown": "$some_property"}), + Filter( + team=self.team, + data={ + "actions": [{"id": sign_up_action.id}], + "breakdown": "$some_property", + }, + ), self.team, ) self.assertEqual(action_response[0]["count"], 2) @also_test_with_materialized_columns(event_properties=["key"], person_properties=["email"]) def test_breakdown_user_props_with_filter(self): - _create_person(team_id=self.team.pk, distinct_ids=["person1"], properties={"email": "test@posthog.com"}) - _create_person(team_id=self.team.pk, distinct_ids=["person2"], properties={"email": "test@gmail.com"}) - person = _create_person(team_id=self.team.pk, distinct_ids=["person3"], properties={"email": "test@gmail.com"}) + _create_person( + team_id=self.team.pk, + distinct_ids=["person1"], + properties={"email": "test@posthog.com"}, + ) + _create_person( + team_id=self.team.pk, + distinct_ids=["person2"], + properties={"email": "test@gmail.com"}, + ) + person = _create_person( + team_id=self.team.pk, + distinct_ids=["person3"], + properties={"email": "test@gmail.com"}, + ) create_person_distinct_id(self.team.pk, "person1", str(person.uuid)) - _create_event(event="sign up", distinct_id="person1", team=self.team, properties={"key": "val"}) - _create_event(event="sign up", distinct_id="person2", team=self.team, properties={"key": "val"}) + _create_event( + event="sign up", + distinct_id="person1", + team=self.team, + properties={"key": "val"}, + ) + _create_event( + event="sign up", + distinct_id="person2", + team=self.team, + properties={"key": "val"}, + ) response = Trends().run( Filter( team=self.team, @@ -4663,9 +5490,21 @@ def test_breakdown_user_props_with_filter(self): "date_from": "-14d", "breakdown": "email", "breakdown_type": "person", - "events": [{"id": "sign up", "name": "sign up", "type": "events", "order": 0}], + "events": [ + { + "id": "sign up", + "name": "sign up", + "type": "events", + "order": 0, + } + ], "properties": [ - {"key": "email", "value": "@posthog.com", "operator": "not_icontains", "type": "person"}, + { + "key": "email", + "value": "@posthog.com", + "operator": "not_icontains", + "type": "person", + }, {"key": "key", "value": "val"}, ], }, @@ -4682,7 +5521,11 @@ def test_trend_breakdown_user_props_with_filter_with_partial_property_pushdowns( _create_person( team_id=self.team.pk, distinct_ids=["person1"], - properties={"email": "test@posthog.com", "$os": "ios", "$browser": "chrome"}, + properties={ + "email": "test@posthog.com", + "$os": "ios", + "$browser": "chrome", + }, ) _create_person( team_id=self.team.pk, @@ -4692,41 +5535,103 @@ def test_trend_breakdown_user_props_with_filter_with_partial_property_pushdowns( _create_person( team_id=self.team.pk, distinct_ids=["person3"], - properties={"email": "test2@posthog.com", "$os": "android", "$browser": "chrome"}, + properties={ + "email": "test2@posthog.com", + "$os": "android", + "$browser": "chrome", + }, ) # a second person with same properties, just so snapshot passes on different CH versions (indeterminate sorting currently) _create_person( team_id=self.team.pk, distinct_ids=["person32"], - properties={"email": "test2@posthog.com", "$os": "android", "$browser": "chrome"}, + properties={ + "email": "test2@posthog.com", + "$os": "android", + "$browser": "chrome", + }, ) _create_person( team_id=self.team.pk, distinct_ids=["person4"], - properties={"email": "test3@posthog.com", "$os": "android", "$browser": "safari"}, + properties={ + "email": "test3@posthog.com", + "$os": "android", + "$browser": "safari", + }, ) _create_person( team_id=self.team.pk, distinct_ids=["person5"], - properties={"email": "test4@posthog.com", "$os": "android", "$browser": "safari"}, + properties={ + "email": "test4@posthog.com", + "$os": "android", + "$browser": "safari", + }, ) _create_person( team_id=self.team.pk, distinct_ids=["person6"], - properties={"email": "test5@posthog.com", "$os": "android", "$browser": "safari"}, + properties={ + "email": "test5@posthog.com", + "$os": "android", + "$browser": "safari", + }, ) journeys_for( team=self.team, create_people=False, events_by_person={ - "person1": [{"event": "sign up", "properties": {"key": "val"}, "timestamp": datetime(2020, 5, 1, 0)}], - "person2": [{"event": "sign up", "properties": {"key": "val"}, "timestamp": datetime(2020, 5, 1, 0)}], - "person3": [{"event": "sign up", "properties": {"key": "val"}, "timestamp": datetime(2020, 5, 1, 0)}], - "person32": [{"event": "sign up", "properties": {"key": "val"}, "timestamp": datetime(2020, 5, 1, 0)}], - "person4": [{"event": "sign up", "properties": {"key": "val"}, "timestamp": datetime(2020, 5, 1, 0)}], - "person5": [{"event": "sign up", "properties": {"key": "val"}, "timestamp": datetime(2020, 5, 1, 0)}], - "person6": [{"event": "sign up", "properties": {"key": "val"}, "timestamp": datetime(2020, 5, 1, 0)}], + "person1": [ + { + "event": "sign up", + "properties": {"key": "val"}, + "timestamp": datetime(2020, 5, 1, 0), + } + ], + "person2": [ + { + "event": "sign up", + "properties": {"key": "val"}, + "timestamp": datetime(2020, 5, 1, 0), + } + ], + "person3": [ + { + "event": "sign up", + "properties": {"key": "val"}, + "timestamp": datetime(2020, 5, 1, 0), + } + ], + "person32": [ + { + "event": "sign up", + "properties": {"key": "val"}, + "timestamp": datetime(2020, 5, 1, 0), + } + ], + "person4": [ + { + "event": "sign up", + "properties": {"key": "val"}, + "timestamp": datetime(2020, 5, 1, 0), + } + ], + "person5": [ + { + "event": "sign up", + "properties": {"key": "val"}, + "timestamp": datetime(2020, 5, 1, 0), + } + ], + "person6": [ + { + "event": "sign up", + "properties": {"key": "val"}, + "timestamp": datetime(2020, 5, 1, 0), + } + ], }, ) @@ -4738,7 +5643,14 @@ def test_trend_breakdown_user_props_with_filter_with_partial_property_pushdowns( "date_to": "2020-07-01 00:00:00", "breakdown": "email", "breakdown_type": "person", - "events": [{"id": "sign up", "name": "sign up", "type": "events", "order": 0}], + "events": [ + { + "id": "sign up", + "name": "sign up", + "type": "events", + "order": 0, + } + ], "properties": { "type": "AND", "values": [ @@ -4757,8 +5669,18 @@ def test_trend_breakdown_user_props_with_filter_with_partial_property_pushdowns( { "type": "OR", "values": [ - {"key": "$os", "value": "android", "operator": "exact", "type": "person"}, - {"key": "$browser", "value": "safari", "operator": "exact", "type": "person"}, + { + "key": "$os", + "value": "android", + "operator": "exact", + "type": "person", + }, + { + "key": "$browser", + "value": "safari", + "operator": "exact", + "type": "person", + }, ], }, ], @@ -4811,8 +5733,18 @@ def test_trend_breakdown_user_props_with_filter_with_partial_property_pushdowns( { "type": "AND", "values": [ - {"key": "$os", "value": "android", "operator": "exact", "type": "person"}, - {"key": "$browser", "value": "chrome", "operator": "exact", "type": "person"}, + { + "key": "$os", + "value": "android", + "operator": "exact", + "type": "person", + }, + { + "key": "$browser", + "value": "chrome", + "operator": "exact", + "type": "person", + }, ], } ], @@ -4898,7 +5830,14 @@ def test_weekly_active_users_aggregated_range_wider_than_week(self): "date_from": "2020-01-01", "date_to": "2020-01-08", "display": TRENDS_TABLE, - "events": [{"id": "$pageview", "type": "events", "order": 0, "math": "weekly_active"}], + "events": [ + { + "id": "$pageview", + "type": "events", + "order": 0, + "math": "weekly_active", + } + ], } filter = Filter(team=self.team, data=data) @@ -4915,7 +5854,14 @@ def test_weekly_active_users_aggregated_range_wider_than_week_with_sampling(self "date_from": "2020-01-01", "date_to": "2020-01-08", "display": TRENDS_TABLE, - "events": [{"id": "$pageview", "type": "events", "order": 0, "math": "weekly_active"}], + "events": [ + { + "id": "$pageview", + "type": "events", + "order": 0, + "math": "weekly_active", + } + ], } filter = Filter(team=self.team, data=data) @@ -4931,7 +5877,14 @@ def test_weekly_active_users_aggregated_range_narrower_than_week(self): "date_from": "2020-01-11", "date_to": "2020-01-12", "display": TRENDS_TABLE, - "events": [{"id": "$pageview", "type": "events", "order": 0, "math": "weekly_active"}], + "events": [ + { + "id": "$pageview", + "type": "events", + "order": 0, + "math": "weekly_active", + } + ], } filter = Filter(team=self.team, data=data) @@ -4948,7 +5901,14 @@ def test_weekly_active_users_monthly(self): "date_from": "2019-12-01", "date_to": "2020-02-29", # T'was a leap year "interval": "month", - "events": [{"id": "$pageview", "type": "events", "order": 0, "math": "weekly_active"}], + "events": [ + { + "id": "$pageview", + "type": "events", + "order": 0, + "math": "weekly_active", + } + ], } filter = Filter(team=self.team, data=data) @@ -4965,7 +5925,14 @@ def test_weekly_active_users_daily(self): data = { "date_from": "2020-01-08", "date_to": "2020-01-19", - "events": [{"id": "$pageview", "type": "events", "order": 0, "math": "weekly_active"}], + "events": [ + { + "id": "$pageview", + "type": "events", + "order": 0, + "math": "weekly_active", + } + ], } filter = Filter(team=self.team, data=data) @@ -5013,7 +5980,14 @@ def test_weekly_active_users_daily_based_on_action(self): data = { "date_from": "2020-01-08", "date_to": "2020-01-19", - "actions": [{"id": action.id, "type": "actions", "order": 0, "math": "weekly_active"}], + "actions": [ + { + "id": action.id, + "type": "actions", + "order": 0, + "math": "weekly_active", + } + ], } filter = Filter(team=self.team, data=data) @@ -5036,7 +6010,10 @@ def test_weekly_active_users_daily_based_on_action(self): ], ) # Same as test_weekly_active_users_daily - self.assertEqual(result[0]["data"], [1.0, 3.0, 2.0, 2.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 1.0, 0.0]) + self.assertEqual( + result[0]["data"], + [1.0, 3.0, 2.0, 2.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 1.0, 0.0], + ) @also_test_with_different_timezones @snapshot_clickhouse_queries @@ -5047,7 +6024,14 @@ def test_weekly_active_users_weekly(self): "date_from": "2019-12-29", "date_to": "2020-01-18", "interval": "week", - "events": [{"id": "$pageview", "type": "events", "order": 0, "math": "weekly_active"}], + "events": [ + { + "id": "$pageview", + "type": "events", + "order": 0, + "math": "weekly_active", + } + ], } filter = Filter(team=self.team, data=data) @@ -5063,7 +6047,14 @@ def test_weekly_active_users_hourly(self): "date_from": "2020-01-09T06:00:00Z", "date_to": "2020-01-09T17:00:00Z", "interval": "hour", - "events": [{"id": "$pageview", "type": "events", "order": 0, "math": "weekly_active"}], + "events": [ + { + "id": "$pageview", + "type": "events", + "order": 0, + "math": "weekly_active", + } + ], } filter = Filter(team=self.team, data=data) @@ -5091,7 +6082,10 @@ def test_weekly_active_users_hourly(self): # necessary, because there's a presentation issue: in monthly/weekly graphs data points are formatted as # D-MMM-YYYY, so if a user sees e.g. 1-Jan-2077, they'll likely expect the active users count to be for # the first day of the month, and not the last. If they saw just Jan-2077, the more general case would work. - self.assertEqual(result[0]["data"], [3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0]) + self.assertEqual( + result[0]["data"], + [3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0], + ) def test_weekly_active_users_daily_based_on_action_with_zero_person_ids(self): # only a person-on-event test @@ -5121,13 +6115,23 @@ def test_weekly_active_users_daily_based_on_action_with_zero_person_ids(self): data = { "date_from": "2020-01-08", "date_to": "2020-01-19", - "actions": [{"id": action.id, "type": "actions", "order": 0, "math": "weekly_active"}], + "actions": [ + { + "id": action.id, + "type": "actions", + "order": 0, + "math": "weekly_active", + } + ], } filter = Filter(team=self.team, data=data) result = Trends().run(filter, self.team) # Zero person IDs shouldn't be counted - self.assertEqual(result[0]["data"], [1.0, 3.0, 2.0, 2.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 1.0, 0.0]) + self.assertEqual( + result[0]["data"], + [1.0, 3.0, 2.0, 2.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 1.0, 0.0], + ) @also_test_with_materialized_columns(["key"]) def test_breakdown_weekly_active_users_daily(self): @@ -5174,12 +6178,22 @@ def test_breakdown_weekly_active_users_daily(self): "date_from": "2020-01-01T00:00:00Z", "date_to": "2020-01-12T00:00:00Z", "breakdown": "key", - "events": [{"id": "$pageview", "type": "events", "order": 0, "math": "weekly_active"}], + "events": [ + { + "id": "$pageview", + "type": "events", + "order": 0, + "math": "weekly_active", + } + ], } filter = Filter(team=self.team, data=data) result = Trends().run(filter, self.team) - self.assertEqual(result[0]["data"], [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 2.0, 2.0, 2.0, 0.0]) + self.assertEqual( + result[0]["data"], + [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 2.0, 2.0, 2.0, 0.0], + ) @also_test_with_materialized_columns(person_properties=["name"]) @snapshot_clickhouse_queries @@ -5212,15 +6226,30 @@ def test_weekly_active_users_filtering(self): data={ "date_from": "2020-01-01T00:00:00Z", "date_to": "2020-01-12T00:00:00Z", - "events": [{"id": "$pageview", "type": "events", "order": 0, "math": "weekly_active"}], + "events": [ + { + "id": "$pageview", + "type": "events", + "order": 0, + "math": "weekly_active", + } + ], "properties": [ - {"key": "name", "operator": "exact", "value": ["person-1", "person-2"], "type": "person"} + { + "key": "name", + "operator": "exact", + "value": ["person-1", "person-2"], + "type": "person", + } ], }, ) result = Trends().run(filter, self.team) - self.assertEqual(result[0]["data"], [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 2.0, 2.0, 2.0]) + self.assertEqual( + result[0]["data"], + [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 2.0, 2.0, 2.0], + ) @snapshot_clickhouse_queries def test_breakdown_weekly_active_users_daily_based_on_action(self): @@ -5281,14 +6310,30 @@ def test_breakdown_weekly_active_users_daily_based_on_action(self): cohort = Cohort.objects.create( team=self.team, - groups=[{"properties": [{"key": "name", "operator": "exact", "value": ["p1", "p2"], "type": "person"}]}], + groups=[ + { + "properties": [ + { + "key": "name", + "operator": "exact", + "value": ["p1", "p2"], + "type": "person", + } + ] + } + ], ) pageview_action = _create_action( name="$pageview", team=self.team, properties=[ - {"key": "name", "operator": "exact", "value": ["p1", "p2", "p3"], "type": "person"}, + { + "key": "name", + "operator": "exact", + "value": ["p1", "p2", "p3"], + "type": "person", + }, {"type": "cohort", "key": "id", "value": cohort.pk}, ], ) @@ -5297,12 +6342,22 @@ def test_breakdown_weekly_active_users_daily_based_on_action(self): "date_from": "2020-01-01T00:00:00Z", "date_to": "2020-01-12T00:00:00Z", "breakdown": "key", - "actions": [{"id": pageview_action.id, "type": "actions", "order": 0, "math": "weekly_active"}], + "actions": [ + { + "id": pageview_action.id, + "type": "actions", + "order": 0, + "math": "weekly_active", + } + ], } filter = Filter(team=self.team, data=data) result = Trends().run(filter, self.team) - self.assertEqual(result[0]["data"], [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 2.0, 2.0, 2.0, 0.0]) + self.assertEqual( + result[0]["data"], + [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 2.0, 2.0, 2.0, 0.0], + ) @also_test_with_materialized_columns(["key"]) @snapshot_clickhouse_queries @@ -5313,7 +6368,14 @@ def test_breakdown_weekly_active_users_aggregated(self): "date_from": "2020-01-11", "date_to": "2020-01-11", "display": TRENDS_TABLE, - "events": [{"id": "$pageview", "type": "events", "order": 0, "math": "weekly_active"}], + "events": [ + { + "id": "$pageview", + "type": "events", + "order": 0, + "math": "weekly_active", + } + ], "breakdown": "key", } @@ -5383,7 +6445,14 @@ def test_breakdown_filtering_bar_chart_by_value(self): data={ "date_from": "-7d", "breakdown": "$some_property", - "events": [{"id": "sign up", "name": "sign up", "type": "events", "order": 0}], + "events": [ + { + "id": "sign up", + "name": "sign up", + "type": "events", + "order": 0, + } + ], "display": TRENDS_BAR_VALUE, }, ), @@ -5555,7 +6624,12 @@ def test_filtering_with_action_props(self): ) response = Trends().run( - Filter(data={"date_from": "-14d", "actions": [{"id": action.pk, "type": "actions", "order": 0}]}), + Filter( + data={ + "date_from": "-14d", + "actions": [{"id": action.pk, "type": "actions", "order": 0}], + } + ), self.team, ) @@ -5573,7 +6647,18 @@ def test_should_throw_exception(self, patch_sync_execute): with self.assertRaises(Exception): with self.settings(TEST=False, DEBUG=False): Trends().run( - Filter(data={"events": [{"id": "sign up", "name": "sign up", "type": "events", "order": 0}]}), + Filter( + data={ + "events": [ + { + "id": "sign up", + "name": "sign up", + "type": "events", + "order": 0, + } + ] + } + ), self.team, ) @@ -5585,21 +6670,33 @@ def test_timezones_hourly_relative_from(self): team=self.team, event="sign up", distinct_id="blabla", - properties={"$current_url": "first url", "$browser": "Firefox", "$os": "Mac"}, + properties={ + "$current_url": "first url", + "$browser": "Firefox", + "$os": "Mac", + }, timestamp="2020-01-04T22:01:01", ) _create_event( team=self.team, event="sign up", distinct_id="blabla", - properties={"$current_url": "first url", "$browser": "Firefox", "$os": "Mac"}, + properties={ + "$current_url": "first url", + "$browser": "Firefox", + "$os": "Mac", + }, timestamp="2020-01-05T07:01:01", ) _create_event( team=self.team, event="sign up", distinct_id="blabla", - properties={"$current_url": "first url", "$browser": "Firefox", "$os": "Mac"}, + properties={ + "$current_url": "first url", + "$browser": "Firefox", + "$os": "Mac", + }, timestamp="2020-01-05T08:01:01", ) @@ -5693,21 +6790,33 @@ def test_timezones_hourly_absolute_from(self): team=self.team, event="sign up", distinct_id="blabla", - properties={"$current_url": "first url", "$browser": "Firefox", "$os": "Mac"}, + properties={ + "$current_url": "first url", + "$browser": "Firefox", + "$os": "Mac", + }, timestamp="2020-01-02T17:01:01", ) _create_event( team=self.team, event="sign up", distinct_id="blabla", - properties={"$current_url": "second url", "$browser": "Firefox", "$os": "Mac"}, + properties={ + "$current_url": "second url", + "$browser": "Firefox", + "$os": "Mac", + }, timestamp="2020-01-03T17:01:01", ) _create_event( team=self.team, event="sign up", distinct_id="blabla", - properties={"$current_url": "second url", "$browser": "Firefox", "$os": "Mac"}, + properties={ + "$current_url": "second url", + "$browser": "Firefox", + "$os": "Mac", + }, timestamp="2020-01-06T00:30:01", # Shouldn't be included anywhere ) @@ -5779,27 +6888,45 @@ def test_timezones_daily(self): team=self.team, event="sign up", distinct_id="blabla", - properties={"$current_url": "first url", "$browser": "Firefox", "$os": "Mac"}, + properties={ + "$current_url": "first url", + "$browser": "Firefox", + "$os": "Mac", + }, timestamp="2020-01-02T17:01:01", ) _create_event( team=self.team, event="sign up", distinct_id="blabla", - properties={"$current_url": "second url", "$browser": "Firefox", "$os": "Mac"}, + properties={ + "$current_url": "second url", + "$browser": "Firefox", + "$os": "Mac", + }, timestamp="2020-01-03T17:01:01", ) _create_event( team=self.team, event="sign up", distinct_id="blabla", - properties={"$current_url": "second url", "$browser": "Firefox", "$os": "Mac"}, + properties={ + "$current_url": "second url", + "$browser": "Firefox", + "$os": "Mac", + }, timestamp="2020-01-06T00:30:01", # Shouldn't be included anywhere ) with freeze_time(datetime(2020, 1, 5, 5, 0, tzinfo=ZoneInfo(self.team.timezone))): response = Trends().run( - Filter(data={"date_from": "-7d", "events": [{"id": "sign up", "name": "sign up"}]}, team=self.team), + Filter( + data={ + "date_from": "-7d", + "events": [{"id": "sign up", "name": "sign up"}], + }, + team=self.team, + ), self.team, ) @@ -5823,12 +6950,16 @@ def test_timezones_daily(self): response = Trends().run( Filter( team=self.team, - data={"date_from": "-14d", "events": [{"id": "sign up", "name": "sign up", "math": "dau"}]}, + data={ + "date_from": "-14d", + "events": [{"id": "sign up", "name": "sign up", "math": "dau"}], + }, ), self.team, ) self.assertEqual( - response[0]["data"], [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 0.0, 0.0] + response[0]["data"], + [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 0.0, 0.0], ) self.assertEqual( response[0]["labels"], @@ -5857,7 +6988,13 @@ def test_timezones_daily(self): team=self.team, data={ "date_from": "-7d", - "events": [{"id": "sign up", "name": "sign up", "math": "weekly_active"}], + "events": [ + { + "id": "sign up", + "name": "sign up", + "math": "weekly_active", + } + ], }, ), self.team, @@ -5882,7 +7019,10 @@ def test_timezones_daily(self): response = Trends().run( Filter( team=self.team, - data={"date_from": "-7d", "events": [{"id": "sign up", "name": "sign up", "breakdown": "$os"}]}, + data={ + "date_from": "-7d", + "events": [{"id": "sign up", "name": "sign up", "breakdown": "$os"}], + }, ), self.team, ) @@ -5932,7 +7072,11 @@ def test_non_deterministic_timezones(self): team=self.team, event="sign up", distinct_id="blabla", - properties={"$current_url": "first url", "$browser": "Firefox", "$os": "Mac"}, + properties={ + "$current_url": "first url", + "$browser": "Firefox", + "$os": "Mac", + }, ) with freeze_time("2022-11-10T01:01:01Z"): @@ -5940,7 +7084,11 @@ def test_non_deterministic_timezones(self): team=self.team, event="sign up", distinct_id="blabla", - properties={"$current_url": "second url", "$browser": "Firefox", "$os": "Mac"}, + properties={ + "$current_url": "second url", + "$browser": "Firefox", + "$os": "Mac", + }, ) with freeze_time("2022-11-17T08:30:01Z"): @@ -5948,7 +7096,11 @@ def test_non_deterministic_timezones(self): team=self.team, event="sign up", distinct_id="blabla", - properties={"$current_url": "second url", "$browser": "Firefox", "$os": "Mac"}, + properties={ + "$current_url": "second url", + "$browser": "Firefox", + "$os": "Mac", + }, ) with freeze_time("2022-11-24T08:30:01Z"): @@ -5956,7 +7108,11 @@ def test_non_deterministic_timezones(self): team=self.team, event="sign up", distinct_id="blabla", - properties={"$current_url": "second url", "$browser": "Firefox", "$os": "Mac"}, + properties={ + "$current_url": "second url", + "$browser": "Firefox", + "$os": "Mac", + }, ) with freeze_time("2022-11-30T08:30:01Z"): @@ -5964,7 +7120,11 @@ def test_non_deterministic_timezones(self): team=self.team, event="sign up", distinct_id="blabla", - properties={"$current_url": "second url", "$browser": "Firefox", "$os": "Mac"}, + properties={ + "$current_url": "second url", + "$browser": "Firefox", + "$os": "Mac", + }, ) with freeze_time("2022-11-30T13:01:01Z"): @@ -5991,21 +7151,33 @@ def test_timezones_weekly(self): team=self.team, event="sign up", distinct_id="blabla", - properties={"$current_url": "first url", "$browser": "Firefox", "$os": "Mac"}, + properties={ + "$current_url": "first url", + "$browser": "Firefox", + "$os": "Mac", + }, timestamp="2020-01-11T19:01:01", # Saturday; TRICKY: This is the next UTC day in America/Phoenix ) _create_event( # This event should count towards week of 2020-01-12 (or 2020-01-06 in Monday mode) team=self.team, event="sign up", distinct_id="blabla", - properties={"$current_url": "first url", "$browser": "Firefox", "$os": "Mac"}, + properties={ + "$current_url": "first url", + "$browser": "Firefox", + "$os": "Mac", + }, timestamp="2020-01-12T02:01:01", # Sunday; TRICKY: This is the previous UTC day in Asia/Tokyo ) _create_event( # This event should count towards week of 2020-01-19 (or 2020-01-20 in Monday mode) team=self.team, event="sign up", distinct_id="blabla", - properties={"$current_url": "second url", "$browser": "Firefox", "$os": "Mac"}, + properties={ + "$current_url": "second url", + "$browser": "Firefox", + "$os": "Mac", + }, timestamp="2020-01-21T18:01:01", # Tuesday; TRICKY: This is the next UTC day in America/Phoenix ) @@ -6057,7 +7229,11 @@ def test_same_day(self): team=self.team, event="sign up", distinct_id="blabla", - properties={"$current_url": "first url", "$browser": "Firefox", "$os": "Mac"}, + properties={ + "$current_url": "first url", + "$browser": "Firefox", + "$os": "Mac", + }, timestamp="2020-01-03T01:01:01Z", ) response = Trends().run( @@ -6086,7 +7262,11 @@ def test_same_day_with_person_on_events_v2(self): team=self.team, event="sign up", distinct_id="distinctid1", - properties={"$current_url": "first url", "$browser": "Firefox", "$os": "Mac"}, + properties={ + "$current_url": "first url", + "$browser": "Firefox", + "$os": "Mac", + }, timestamp="2020-01-03T01:01:01Z", person_id=person_id1, ) @@ -6095,7 +7275,11 @@ def test_same_day_with_person_on_events_v2(self): team=self.team, event="sign up", distinct_id="distinctid2", - properties={"$current_url": "first url", "$browser": "Firefox", "$os": "Mac"}, + properties={ + "$current_url": "first url", + "$browser": "Firefox", + "$os": "Mac", + }, timestamp="2020-01-03T01:01:01Z", person_id=person_id2, ) @@ -6148,7 +7332,11 @@ def test_same_day_with_person_on_events_v2_latest_override(self): team=self.team, event="sign up", distinct_id="distinctid1", - properties={"$current_url": "first url", "$browser": "Firefox", "$os": "Mac"}, + properties={ + "$current_url": "first url", + "$browser": "Firefox", + "$os": "Mac", + }, timestamp="2020-01-03T01:01:01Z", person_id=person_id1, ) @@ -6157,7 +7345,11 @@ def test_same_day_with_person_on_events_v2_latest_override(self): team=self.team, event="some other event", distinct_id="distinctid2", - properties={"$current_url": "first url", "$browser": "Firefox", "$os": "Mac"}, + properties={ + "$current_url": "first url", + "$browser": "Firefox", + "$os": "Mac", + }, timestamp="2020-01-03T01:01:01Z", person_id=person_id2, ) @@ -6166,7 +7358,11 @@ def test_same_day_with_person_on_events_v2_latest_override(self): team=self.team, event="sign up", distinct_id="distinctid3", - properties={"$current_url": "first url", "$browser": "Firefox", "$os": "Mac"}, + properties={ + "$current_url": "first url", + "$browser": "Firefox", + "$os": "Mac", + }, timestamp="2020-01-03T01:01:01Z", person_id=person_id3, ) @@ -6232,11 +7428,33 @@ def test_ilike_regression_with_current_clickhouse_version(self): team=self.team, data={ "date_from": "-14d", - "events": [{"id": "watched movie", "name": "watched movie", "type": "events", "order": 0}], + "events": [ + { + "id": "watched movie", + "name": "watched movie", + "type": "events", + "order": 0, + } + ], "properties": [ - {"key": "email", "type": "event", "value": "posthog.com", "operator": "not_icontains"}, - {"key": "name", "type": "event", "value": "posthog.com", "operator": "not_icontains"}, - {"key": "name", "type": "person", "value": "posthog.com", "operator": "not_icontains"}, + { + "key": "email", + "type": "event", + "value": "posthog.com", + "operator": "not_icontains", + }, + { + "key": "name", + "type": "event", + "value": "posthog.com", + "operator": "not_icontains", + }, + { + "key": "name", + "type": "person", + "value": "posthog.com", + "operator": "not_icontains", + }, ], }, ), @@ -6477,7 +7695,13 @@ def test_trends_count_per_group_average_daily(self): team=self.team, data={ "display": TRENDS_LINEAR, - "events": [{"id": "viewed video", "math": "avg_count_per_actor", "math_group_type_index": 0}], + "events": [ + { + "id": "viewed video", + "math": "avg_count_per_actor", + "math_group_type_index": 0, + } + ], "date_from": "2020-01-01", "date_to": "2020-01-07", }, @@ -6518,7 +7742,13 @@ def test_trends_count_per_group_average_aggregated(self): team=self.team, data={ "display": TRENDS_TABLE, - "events": [{"id": "viewed video", "math": "avg_count_per_actor", "math_group_type_index": 0}], + "events": [ + { + "id": "viewed video", + "math": "avg_count_per_actor", + "math_group_type_index": 0, + } + ], "date_from": "2020-01-01", "date_to": "2020-01-07", }, @@ -6537,7 +7767,10 @@ def test_trends_breakdown_timezone(self): with freeze_time("2020-01-03 19:06:34"): _create_person(team_id=self.team.pk, distinct_ids=["another_user"]) _create_event( - team=self.team, event="viewed video", distinct_id="another_user", properties={"color": "orange"} + team=self.team, + event="viewed video", + distinct_id="another_user", + properties={"color": "orange"}, ) daily_response = Trends().run( @@ -6564,11 +7797,29 @@ def _create_groups(self): 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) - create_group(team_id=self.team.pk, group_type_index=0, group_key="org:5", properties={"industry": "finance"}) - create_group(team_id=self.team.pk, group_type_index=0, group_key="org:6", properties={"industry": "technology"}) - create_group(team_id=self.team.pk, group_type_index=0, group_key="org:7", properties={"industry": "finance"}) create_group( - team_id=self.team.pk, group_type_index=1, group_key="company:10", properties={"industry": "finance"} + team_id=self.team.pk, + group_type_index=0, + group_key="org:5", + properties={"industry": "finance"}, + ) + create_group( + team_id=self.team.pk, + group_type_index=0, + group_key="org:6", + properties={"industry": "technology"}, + ) + create_group( + team_id=self.team.pk, + group_type_index=0, + group_key="org:7", + properties={"industry": "finance"}, + ) + create_group( + team_id=self.team.pk, + group_type_index=1, + group_key="company:10", + properties={"industry": "finance"}, ) # TODO: Delete this test when moved to person-on-events @@ -6604,8 +7855,22 @@ def test_breakdown_with_filter_groups(self): "date_from": "2020-01-01T00:00:00Z", "date_to": "2020-01-12T00:00:00Z", "breakdown": "key", - "events": [{"id": "sign up", "name": "sign up", "type": "events", "order": 0}], - "properties": [{"key": "industry", "value": "finance", "type": "group", "group_type_index": 0}], + "events": [ + { + "id": "sign up", + "name": "sign up", + "type": "events", + "order": 0, + } + ], + "properties": [ + { + "key": "industry", + "value": "finance", + "type": "group", + "group_type_index": 0, + } + ], }, ), self.team, @@ -6618,7 +7883,9 @@ def test_breakdown_with_filter_groups(self): self.assertEqual(response[1]["count"], 1) @also_test_with_materialized_columns( - event_properties=["key"], group_properties=[(0, "industry")], materialize_only_with_person_on_events=True + event_properties=["key"], + group_properties=[(0, "industry")], + materialize_only_with_person_on_events=True, ) @snapshot_clickhouse_queries def test_breakdown_with_filter_groups_person_on_events(self): @@ -6653,8 +7920,22 @@ def test_breakdown_with_filter_groups_person_on_events(self): "date_from": "2020-01-01T00:00:00Z", "date_to": "2020-01-12T00:00:00Z", "breakdown": "key", - "events": [{"id": "sign up", "name": "sign up", "type": "events", "order": 0}], - "properties": [{"key": "industry", "value": "finance", "type": "group", "group_type_index": 0}], + "events": [ + { + "id": "sign up", + "name": "sign up", + "type": "events", + "order": 0, + } + ], + "properties": [ + { + "key": "industry", + "value": "finance", + "type": "group", + "group_type_index": 0, + } + ], }, ), self.team, @@ -6714,8 +7995,23 @@ def test_breakdown_with_filter_groups_person_on_events_v2(self): "date_from": "2020-01-01T00:00:00Z", "date_to": "2020-01-12T00:00:00Z", "breakdown": "key", - "events": [{"id": "sign up", "name": "sign up", "type": "events", "order": 0, "math": "dau"}], - "properties": [{"key": "industry", "value": "finance", "type": "group", "group_type_index": 0}], + "events": [ + { + "id": "sign up", + "name": "sign up", + "type": "events", + "order": 0, + "math": "dau", + } + ], + "properties": [ + { + "key": "industry", + "value": "finance", + "type": "group", + "group_type_index": 0, + } + ], }, ), self.team, @@ -6777,7 +8073,11 @@ def test_breakdown_by_group_props(self): self.assertEqual(response[1]["count"], 1) filter = filter.shallow_clone( - {"breakdown_value": "technology", "date_from": "2020-01-02T00:00:00Z", "date_to": "2020-01-03"} + { + "breakdown_value": "technology", + "date_from": "2020-01-02T00:00:00Z", + "date_to": "2020-01-03", + } ) entity = Entity({"id": "sign up", "name": "sign up", "type": "events", "order": 0}) res = self._get_trend_people(filter, entity) @@ -6839,7 +8139,11 @@ def test_breakdown_by_group_props_person_on_events(self): self.assertEqual(response[1]["count"], 1) filter = filter.shallow_clone( - {"breakdown_value": "technology", "date_from": "2020-01-02T00:00:00Z", "date_to": "2020-01-02"} + { + "breakdown_value": "technology", + "date_from": "2020-01-02T00:00:00Z", + "date_to": "2020-01-02", + } ) entity = Entity({"id": "sign up", "name": "sign up", "type": "events", "order": 0}) res = self._get_trend_people(filter, entity) @@ -6895,7 +8199,12 @@ def test_filtering_with_group_props(self): self._create_groups() Person.objects.create(team_id=self.team.pk, distinct_ids=["person1"], properties={"key": "value"}) - _create_event(event="$pageview", distinct_id="person1", team=self.team, timestamp="2020-01-02T12:00:00Z") + _create_event( + event="$pageview", + distinct_id="person1", + team=self.team, + timestamp="2020-01-02T12:00:00Z", + ) _create_event( event="$pageview", distinct_id="person1", @@ -6925,7 +8234,12 @@ def test_filtering_with_group_props(self): "date_to": "2020-01-12T00:00:00Z", "events": [{"id": "$pageview", "type": "events", "order": 0}], "properties": [ - {"key": "industry", "value": "finance", "type": "group", "group_type_index": 0}, + { + "key": "industry", + "value": "finance", + "type": "group", + "group_type_index": 0, + }, {"key": "key", "value": "value", "type": "person"}, ], }, @@ -6938,7 +8252,12 @@ def test_filtering_with_group_props_event_with_no_group_data(self): self._create_groups() Person.objects.create(team_id=self.team.pk, distinct_ids=["person1"], properties={"key": "value"}) - _create_event(event="$pageview", distinct_id="person1", team=self.team, timestamp="2020-01-02T12:00:00Z") + _create_event( + event="$pageview", + distinct_id="person1", + team=self.team, + timestamp="2020-01-02T12:00:00Z", + ) _create_event( event="$pageview", distinct_id="person1", @@ -6985,7 +8304,9 @@ def test_filtering_with_group_props_event_with_no_group_data(self): self.assertEqual(response[0]["count"], 4) @also_test_with_materialized_columns( - person_properties=["key"], group_properties=[(0, "industry")], materialize_only_with_person_on_events=True + person_properties=["key"], + group_properties=[(0, "industry")], + materialize_only_with_person_on_events=True, ) @snapshot_clickhouse_queries def test_breakdown_by_group_props_with_person_filter_person_on_events(self): @@ -7033,14 +8354,21 @@ def test_breakdown_by_group_props_with_person_filter_person_on_events(self): self.assertEqual(response[0]["count"], 1) @also_test_with_materialized_columns( - person_properties=["key"], group_properties=[(0, "industry")], materialize_only_with_person_on_events=True + person_properties=["key"], + group_properties=[(0, "industry")], + materialize_only_with_person_on_events=True, ) @snapshot_clickhouse_queries def test_filtering_with_group_props_person_on_events(self): self._create_groups() Person.objects.create(team_id=self.team.pk, distinct_ids=["person1"], properties={"key": "value"}) - _create_event(event="$pageview", distinct_id="person1", team=self.team, timestamp="2020-01-02T12:00:00Z") + _create_event( + event="$pageview", + distinct_id="person1", + team=self.team, + timestamp="2020-01-02T12:00:00Z", + ) _create_event( event="$pageview", distinct_id="person1", @@ -7070,7 +8398,12 @@ def test_filtering_with_group_props_person_on_events(self): "date_to": "2020-01-12T00:00:00Z", "events": [{"id": "$pageview", "type": "events", "order": 0}], "properties": [ - {"key": "industry", "value": "finance", "type": "group", "group_type_index": 0}, + { + "key": "industry", + "value": "finance", + "type": "group", + "group_type_index": 0, + }, {"key": "key", "value": "value", "type": "person"}, ], }, @@ -7081,17 +8414,38 @@ def test_filtering_with_group_props_person_on_events(self): self.assertEqual(response[0]["count"], 1) @also_test_with_materialized_columns( - group_properties=[(0, "industry"), (2, "name")], materialize_only_with_person_on_events=True + group_properties=[(0, "industry"), (2, "name")], + materialize_only_with_person_on_events=True, ) @snapshot_clickhouse_queries def test_filtering_by_multiple_groups_person_on_events(self): 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=2) - create_group(team_id=self.team.pk, group_type_index=0, group_key="org:5", properties={"industry": "finance"}) - create_group(team_id=self.team.pk, group_type_index=0, group_key="org:6", properties={"industry": "technology"}) - create_group(team_id=self.team.pk, group_type_index=2, group_key="company:5", properties={"name": "five"}) - create_group(team_id=self.team.pk, group_type_index=2, group_key="company:6", properties={"name": "six"}) + create_group( + team_id=self.team.pk, + group_type_index=0, + group_key="org:5", + properties={"industry": "finance"}, + ) + create_group( + team_id=self.team.pk, + group_type_index=0, + group_key="org:6", + properties={"industry": "technology"}, + ) + create_group( + team_id=self.team.pk, + group_type_index=2, + group_key="company:5", + properties={"name": "five"}, + ) + create_group( + team_id=self.team.pk, + group_type_index=2, + group_key="company:6", + properties={"name": "six"}, + ) journey = { "person1": [ @@ -7105,8 +8459,16 @@ def test_filtering_by_multiple_groups_person_on_events(self): "timestamp": datetime(2020, 1, 2, 12, 30), "properties": {"$group_2": "company:6"}, }, - {"event": "sign up", "timestamp": datetime(2020, 1, 2, 13), "properties": {"$group_0": "org:6"}}, - {"event": "sign up", "timestamp": datetime(2020, 1, 3, 15), "properties": {"$group_2": "company:5"}}, + { + "event": "sign up", + "timestamp": datetime(2020, 1, 2, 13), + "properties": {"$group_0": "org:6"}, + }, + { + "event": "sign up", + "timestamp": datetime(2020, 1, 3, 15), + "properties": {"$group_2": "company:5"}, + }, ] } @@ -7119,8 +8481,18 @@ def test_filtering_by_multiple_groups_person_on_events(self): "date_to": "2020-01-12", "events": [{"id": "sign up", "name": "sign up", "type": "events", "order": 0}], "properties": [ - {"key": "industry", "value": "finance", "type": "group", "group_type_index": 0}, - {"key": "name", "value": "six", "type": "group", "group_type_index": 2}, + { + "key": "industry", + "value": "finance", + "type": "group", + "group_type_index": 0, + }, + { + "key": "name", + "value": "six", + "type": "group", + "group_type_index": 2, + }, ], }, ) @@ -7130,7 +8502,10 @@ def test_filtering_by_multiple_groups_person_on_events(self): self.assertEqual(len(response), 1) self.assertEqual(response[0]["count"], 1) - self.assertEqual(response[0]["data"], [0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]) + self.assertEqual( + response[0]["data"], + [0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], + ) filter = filter.shallow_clone({"date_from": "2020-01-02T00:00:00Z", "date_to": "2020-01-02T00:00:00Z"}) entity = Entity({"id": "sign up", "name": "sign up", "type": "events", "order": 0}) @@ -7161,7 +8536,16 @@ def test_get_cached_result_bad_cache(self): set_instance_setting("STRICT_CACHING_TEAMS", "all") fake_cached = { - "result": [{"days": ["2020-11-01 05:20:00", "2020-11-01 10:22:00", "2020-11-01 10:25:00"], "data": []}] + "result": [ + { + "days": [ + "2020-11-01 05:20:00", + "2020-11-01 10:22:00", + "2020-11-01 10:25:00", + ], + "data": [], + } + ] } filter = Filter( @@ -7183,7 +8567,14 @@ def test_get_cached_result_hour(self): fake_cached = { "result": [ - {"days": ["2020-11-01 05:20:00", "2020-11-01 10:22:00", "2020-11-01 10:25:00"], "data": [0.0, 0.0, 0.0]} + { + "days": [ + "2020-11-01 05:20:00", + "2020-11-01 10:22:00", + "2020-11-01 10:25:00", + ], + "data": [0.0, 0.0, 0.0], + } ] } @@ -7215,10 +8606,21 @@ def test_get_cached_result_hour(self): def test_get_cached_result_day(self): set_instance_setting("STRICT_CACHING_TEAMS", "all") - fake_cached = {"result": [{"days": ["2020-01-02", "2020-01-03", "2020-01-04"], "data": [0.0, 0.0, 0.0]}]} + fake_cached = { + "result": [ + { + "days": ["2020-01-02", "2020-01-03", "2020-01-04"], + "data": [0.0, 0.0, 0.0], + } + ] + } filter = Filter( team=self.team, - data={"date_from": "2020-01-02", "date_to": "2020-01-04", "events": [{"id": "sign up", "name": "sign up"}]}, + data={ + "date_from": "2020-01-02", + "date_to": "2020-01-04", + "events": [{"id": "sign up", "name": "sign up"}], + }, ) cache_key = generate_cache_key(f"{filter.toJSON()}_{self.team.pk}") cache.set(cache_key, fake_cached, settings.CACHED_RESULTS_TTL) @@ -7226,7 +8628,14 @@ def test_get_cached_result_day(self): res = Trends().get_cached_result(filter, self.team) self.assertTrue(res) - fake_cached = {"result": [{"days": ["2020-01-01", "2020-01-02", "2020-01-03"], "data": [0.0, 0.0, 0.0]}]} + fake_cached = { + "result": [ + { + "days": ["2020-01-01", "2020-01-02", "2020-01-03"], + "data": [0.0, 0.0, 0.0], + } + ] + } cache.set(cache_key, fake_cached, settings.CACHED_RESULTS_TTL) @@ -7236,11 +8645,22 @@ def test_get_cached_result_day(self): def test_get_cached_result_week(self): set_instance_setting("STRICT_CACHING_TEAMS", "all") - fake_cached = {"result": [{"days": ["2020-11-01", "2020-11-08", "2020-11-15"], "data": [0.0, 0.0, 0.0]}]} + fake_cached = { + "result": [ + { + "days": ["2020-11-01", "2020-11-08", "2020-11-15"], + "data": [0.0, 0.0, 0.0], + } + ] + } filter = Filter( team=self.team, - data={"date_to": "2020-11-16", "events": [{"id": "sign up", "name": "sign up"}], "interval": "week"}, + data={ + "date_to": "2020-11-16", + "events": [{"id": "sign up", "name": "sign up"}], + "interval": "week", + }, ) cache_key = generate_cache_key(f"{filter.toJSON()}_{self.team.pk}") cache.set(cache_key, fake_cached, settings.CACHED_RESULTS_TTL) @@ -7250,7 +8670,11 @@ def test_get_cached_result_week(self): filter = Filter( team=self.team, - data={"date_to": "2020-11-23", "events": [{"id": "sign up", "name": "sign up"}], "interval": "week"}, + data={ + "date_to": "2020-11-23", + "events": [{"id": "sign up", "name": "sign up"}], + "interval": "week", + }, ) res = Trends().get_cached_result(filter, self.team) @@ -7259,11 +8683,22 @@ def test_get_cached_result_week(self): def test_get_cached_result_month(self): set_instance_setting("STRICT_CACHING_TEAMS", "all") - fake_cached = {"result": [{"days": ["2020-09-01", "2020-10-01", "2020-11-01"], "data": [0.0, 0.0, 0.0]}]} + fake_cached = { + "result": [ + { + "days": ["2020-09-01", "2020-10-01", "2020-11-01"], + "data": [0.0, 0.0, 0.0], + } + ] + } filter = Filter( team=self.team, - data={"date_to": "2020-11-16", "events": [{"id": "sign up", "name": "sign up"}], "interval": "month"}, + data={ + "date_to": "2020-11-16", + "events": [{"id": "sign up", "name": "sign up"}], + "interval": "month", + }, ) cache_key = generate_cache_key(f"{filter.toJSON()}_{self.team.pk}") cache.set(cache_key, fake_cached, settings.CACHED_RESULTS_TTL) @@ -7273,7 +8708,11 @@ def test_get_cached_result_month(self): filter = Filter( team=self.team, - data={"date_to": "2020-12-01", "events": [{"id": "sign up", "name": "sign up"}], "interval": "week"}, + data={ + "date_to": "2020-12-01", + "events": [{"id": "sign up", "name": "sign up"}], + "interval": "week", + }, ) res = Trends().get_cached_result(filter, self.team) @@ -7290,7 +8729,11 @@ def test_merge_result(self): } filter = Filter( team=self.team, - data={"date_from": "2020-01-02", "date_to": "2020-01-04", "events": [{"id": "sign up", "name": "sign up"}]}, + data={ + "date_from": "2020-01-02", + "date_to": "2020-01-04", + "events": [{"id": "sign up", "name": "sign up"}], + }, ) result = [{"label": "sign up - Chrome", "data": [15.0, 12.0]}] @@ -7298,10 +8741,13 @@ def test_merge_result(self): self.assertEqual(merged_result[0]["data"], [23.0, 15.0, 12.0]) def test_merge_result_no_cache(self): - filter = Filter( team=self.team, - data={"date_from": "2020-01-02", "date_to": "2020-01-04", "events": [{"id": "sign up", "name": "sign up"}]}, + data={ + "date_from": "2020-01-02", + "date_to": "2020-01-04", + "events": [{"id": "sign up", "name": "sign up"}], + }, ) result = [{"label": "sign up - Chrome", "data": [15.0, 12.0]}] @@ -7326,7 +8772,11 @@ def test_merge_result_multiple(self): } filter = Filter( team=self.team, - data={"date_from": "2020-01-02", "date_to": "2020-01-04", "events": [{"id": "sign up", "name": "sign up"}]}, + data={ + "date_from": "2020-01-02", + "date_to": "2020-01-04", + "events": [{"id": "sign up", "name": "sign up"}], + }, ) result = [ diff --git a/posthog/queries/time_to_see_data/sessions.py b/posthog/queries/time_to_see_data/sessions.py index b7c3274bf9241..8ebeeb8db36a6 100644 --- a/posthog/queries/time_to_see_data/sessions.py +++ b/posthog/queries/time_to_see_data/sessions.py @@ -68,7 +68,10 @@ def get_session_events(query: SessionEventsQuerySerializer) -> Optional[Dict]: events = query_with_columns(GET_SESSION_EVENTS, params) queries = query_with_columns(GET_SESSION_QUERIES, params) session_query = SessionsQuerySerializer( - data={"team_id": query.validated_data["team_id"], "session_id": query.validated_data["session_id"]} + data={ + "team_id": query.validated_data["team_id"], + "session_id": query.validated_data["session_id"], + } ) session_query.is_valid(raise_exception=True) sessions = get_sessions(session_query).data diff --git a/posthog/queries/time_to_see_data/test/test_hierarchy.py b/posthog/queries/time_to_see_data/test/test_hierarchy.py index c449609e26905..609300868ffe1 100644 --- a/posthog/queries/time_to_see_data/test/test_hierarchy.py +++ b/posthog/queries/time_to_see_data/test/test_hierarchy.py @@ -1,16 +1,37 @@ import pytest -from posthog.queries.time_to_see_data.hierarchy import Node, NodeType, construct_hierarchy, is_child +from posthog.queries.time_to_see_data.hierarchy import ( + Node, + NodeType, + construct_hierarchy, + is_child, +) @pytest.mark.parametrize( "potential_parent,potential_child,expected_result", [ # Sessions - (Node(NodeType.SESSION, {"session_id": 1}), Node(NodeType.INTERACTION, {"session_id": 1}), True), - (Node(NodeType.SESSION, {"session_id": 1}), Node(NodeType.QUERY, {"session_id": 1}), True), - (Node(NodeType.SESSION, {"session_id": 2}), Node(NodeType.QUERY, {"session_id": 1}), False), - (Node(NodeType.SESSION, {"session_id": 1}), Node(NodeType.SESSION, {"session_id": 1}), False), + ( + Node(NodeType.SESSION, {"session_id": 1}), + Node(NodeType.INTERACTION, {"session_id": 1}), + True, + ), + ( + Node(NodeType.SESSION, {"session_id": 1}), + Node(NodeType.QUERY, {"session_id": 1}), + True, + ), + ( + Node(NodeType.SESSION, {"session_id": 2}), + Node(NodeType.QUERY, {"session_id": 1}), + False, + ), + ( + Node(NodeType.SESSION, {"session_id": 1}), + Node(NodeType.SESSION, {"session_id": 1}), + False, + ), # Interactions ( Node(NodeType.INTERACTION, {"primary_interaction_id": "1"}), @@ -37,7 +58,11 @@ Node(NodeType.SUBQUERY, {"client_query_id": "123::2543245"}), False, ), - (Node(NodeType.INTERACTION, {"session_id": 1}), Node(NodeType.SESSION, {}), False), + ( + Node(NodeType.INTERACTION, {"session_id": 1}), + Node(NodeType.SESSION, {}), + False, + ), (Node(NodeType.INTERACTION, {}), Node(NodeType.INTERACTION, {}), False), # Events ( @@ -75,17 +100,44 @@ def test_is_child(potential_parent, potential_child, expected_result): def test_construct_hierarchy(): session = {"session_id": 1} - interaction_1 = {**session, "is_primary_interaction": True, "primary_interaction_id": "123"} - event_11 = {**session, "is_primary_interaction": False, "primary_interaction_id": "123", "query_id": "456"} + interaction_1 = { + **session, + "is_primary_interaction": True, + "primary_interaction_id": "123", + } + event_11 = { + **session, + "is_primary_interaction": False, + "primary_interaction_id": "123", + "query_id": "456", + } query_111 = {**session, "client_query_id": "123::456", "is_initial_query": True} - subquery_1111 = {**session, "client_query_id": "123::456", "is_initial_query": False} - event_12 = {**session, "is_primary_interaction": False, "primary_interaction_id": "123", "query_id": "789"} + subquery_1111 = { + **session, + "client_query_id": "123::456", + "is_initial_query": False, + } + event_12 = { + **session, + "is_primary_interaction": False, + "primary_interaction_id": "123", + "query_id": "789", + } query_121 = {**session, "client_query_id": "123::789", "is_initial_query": True} query_13 = {**session, "client_query_id": "123::1111", "is_initial_query": True} - interaction_2 = {**session, "is_primary_interaction": True, "primary_interaction_id": "8888"} + interaction_2 = { + **session, + "is_primary_interaction": True, + "primary_interaction_id": "8888", + } - stray_event = {**session, "is_primary_interaction": False, "primary_interaction_id": "efg", "query_id": "9999"} + stray_event = { + **session, + "is_primary_interaction": False, + "primary_interaction_id": "efg", + "query_id": "9999", + } stray_query = {**session, "client_query_id": "foobar", "is_initial_query": True} result = construct_hierarchy( diff --git a/posthog/queries/trends/breakdown.py b/posthog/queries/trends/breakdown.py index 7e1d8c0b6198b..e891190f6e310 100644 --- a/posthog/queries/trends/breakdown.py +++ b/posthog/queries/trends/breakdown.py @@ -23,7 +23,11 @@ from posthog.models.filters import Filter from posthog.models.filters.mixins.utils import cached_property from posthog.models.property import PropertyGroup -from posthog.models.property.util import get_property_string_expr, normalize_url_breakdown, parse_prop_grouped_clauses +from posthog.models.property.util import ( + get_property_string_expr, + normalize_url_breakdown, + parse_prop_grouped_clauses, +) from posthog.models.team import Team from posthog.models.team.team import groups_on_events_querying_enabled from posthog.queries.breakdown_props import ( @@ -65,8 +69,16 @@ parse_response, process_math, ) -from posthog.queries.util import get_interval_func_ch, get_person_properties_mode, get_start_of_interval_sql -from posthog.utils import PersonOnEventsMode, encode_get_request_params, generate_short_id +from posthog.queries.util import ( + get_interval_func_ch, + get_person_properties_mode, + get_start_of_interval_sql, +) +from posthog.utils import ( + PersonOnEventsMode, + encode_get_request_params, + generate_short_id, +) from posthog.queries.person_on_events_v2_sql import PERSON_OVERRIDES_JOIN_SQL @@ -186,23 +198,35 @@ def get_query(self) -> Tuple[str, Dict, Callable]: _params, _breakdown_filter_params = {}, {} if self.filter.breakdown_type == "cohort": - _params, breakdown_filter, _breakdown_filter_params, breakdown_value = self._breakdown_cohort_params() + ( + _params, + breakdown_filter, + _breakdown_filter_params, + breakdown_value, + ) = self._breakdown_cohort_params() else: aggregate_operation_for_breakdown_init = ( "count(*)" if self.entity.math == "dau" or self.entity.math in COUNT_PER_ACTOR_MATH_FUNCTIONS else aggregate_operation ) - _params, breakdown_filter, _breakdown_filter_params, breakdown_value = self._breakdown_prop_params( - aggregate_operation_for_breakdown_init, math_params - ) + ( + _params, + breakdown_filter, + _breakdown_filter_params, + breakdown_value, + ) = self._breakdown_prop_params(aggregate_operation_for_breakdown_init, math_params) if len(_params["values"]) == 0: # If there are no breakdown values, we are sure that there's no relevant events, so instead of adjusting # a "real" SELECT for this, we only include the below dummy SELECT. # It's a drop-in replacement for a "real" one, simply always returning 0 rows. # See https://github.com/PostHog/posthog/pull/5674 for context. - return ("SELECT [now()] AS date, [0] AS total, '' AS breakdown_value LIMIT 0", {}, lambda _: []) + return ( + "SELECT [now()] AS date, [0] AS total, '' AS breakdown_value LIMIT 0", + {}, + lambda _: [], + ) person_join_condition, person_join_params = self._person_join_condition() groups_join_condition, groups_join_params = self._groups_join_condition() @@ -219,16 +243,20 @@ def get_query(self) -> Tuple[str, Dict, Callable]: **sessions_join_params, **sampling_params, } - breakdown_filter_params = {**breakdown_filter_params, **_breakdown_filter_params} + breakdown_filter_params = { + **breakdown_filter_params, + **_breakdown_filter_params, + } if self.filter.display in NON_TIME_SERIES_DISPLAY_TYPES: breakdown_filter = breakdown_filter.format(**breakdown_filter_params) if self.entity.math in [WEEKLY_ACTIVE, MONTHLY_ACTIVE]: interval_func = get_interval_func_ch(self.filter.interval) - active_user_format_params, active_user_query_params = get_active_user_params( - self.filter, self.entity, self.team_id - ) + ( + active_user_format_params, + active_user_query_params, + ) = get_active_user_params(self.filter, self.entity, self.team_id) self.params.update(active_user_query_params) conditions = BREAKDOWN_ACTIVE_USER_CONDITIONS_SQL.format( **breakdown_filter_params, **active_user_format_params @@ -297,9 +325,10 @@ def get_query(self) -> Tuple[str, Dict, Callable]: breakdown_filter = breakdown_filter.format(**breakdown_filter_params) if self.entity.math in [WEEKLY_ACTIVE, MONTHLY_ACTIVE]: - active_user_format_params, active_user_query_params = get_active_user_params( - self.filter, self.entity, self.team_id - ) + ( + active_user_format_params, + active_user_query_params, + ) = get_active_user_params(self.filter, self.entity, self.team_id) self.params.update(active_user_query_params) conditions = BREAKDOWN_ACTIVE_USER_CONDITIONS_SQL.format( **breakdown_filter_params, **active_user_format_params @@ -386,7 +415,12 @@ def get_query(self) -> Tuple[str, Dict, Callable]: date_to_truncated=get_start_of_interval_sql(self.filter.interval, team=self.team, source="%(date_to)s"), interval_func=get_interval_func_ch(self.filter.interval), ) - self.params.update({"seconds_in_interval": seconds_in_interval, "num_intervals": num_intervals}) + self.params.update( + { + "seconds_in_interval": seconds_in_interval, + "num_intervals": num_intervals, + } + ) return breakdown_query, self.params, self._parse_trend_result(self.filter, self.entity) def _breakdown_cohort_params(self): @@ -422,7 +456,10 @@ def _breakdown_prop_params(self, aggregate_operation: str, math_params: Dict): return ( {"values": values_arr}, BREAKDOWN_PROP_JOIN_SQL if not self.filter.using_histogram else BREAKDOWN_HISTOGRAM_PROP_JOIN_SQL, - {"breakdown_value_expr": breakdown_value, "numeric_property_filter": numeric_property_filter}, + { + "breakdown_value_expr": breakdown_value, + "numeric_property_filter": numeric_property_filter, + }, breakdown_value, ) @@ -447,12 +484,20 @@ def _get_breakdown_value(self, breakdown: str) -> str: ): properties_field = f"group{self.filter.breakdown_group_type_index}_properties" breakdown_value, _ = get_property_string_expr( - "events", breakdown, "%(key)s", properties_field, materialised_table_column=properties_field + "events", + breakdown, + "%(key)s", + properties_field, + materialised_table_column=properties_field, ) elif self.person_on_events_mode != PersonOnEventsMode.DISABLED and self.filter.breakdown_type != "group": if self.filter.breakdown_type == "person": breakdown_value, _ = get_property_string_expr( - "events", breakdown, "%(key)s", "person_properties", materialised_table_column="person_properties" + "events", + breakdown, + "%(key)s", + "person_properties", + materialised_table_column="person_properties", ) else: breakdown_value, _ = get_property_string_expr("events", breakdown, "%(key)s", "properties") @@ -462,7 +507,11 @@ def _get_breakdown_value(self, breakdown: str) -> str: elif self.filter.breakdown_type == "group": properties_field = f"group_properties_{self.filter.breakdown_group_type_index}" breakdown_value, _ = get_property_string_expr( - "groups", breakdown, "%(key)s", properties_field, materialised_table_column="group_properties" + "groups", + breakdown, + "%(key)s", + properties_field, + materialised_table_column="group_properties", ) else: breakdown_value, _ = get_property_string_expr("events", breakdown, "%(key)s", "properties") @@ -565,7 +614,11 @@ def _parse(result: List) -> List: parsed_result.update( { "persons_urls": self._get_persons_url( - filter, entity, self.team, stats[0], result_descriptors["breakdown_value"] + filter, + entity, + self.team, + stats[0], + result_descriptors["breakdown_value"], ) } ) @@ -683,7 +736,10 @@ def _person_join_condition(self) -> Tuple[str, Dict]: def _groups_join_condition(self) -> Tuple[str, Dict]: return GroupsJoinQuery( - self.filter, self.team_id, self.column_optimizer, person_on_events_mode=self.person_on_events_mode + self.filter, + self.team_id, + self.column_optimizer, + person_on_events_mode=self.person_on_events_mode, ).get_join_query() def _sessions_join_condition(self) -> Tuple[str, Dict]: diff --git a/posthog/queries/trends/lifecycle.py b/posthog/queries/trends/lifecycle.py index 8e659a5368970..4821d5295a363 100644 --- a/posthog/queries/trends/lifecycle.py +++ b/posthog/queries/trends/lifecycle.py @@ -13,7 +13,11 @@ from posthog.queries.trends.sql import LIFECYCLE_EVENTS_QUERY, LIFECYCLE_SQL from posthog.queries.trends.util import parse_response from posthog.queries.util import get_person_properties_mode -from posthog.utils import PersonOnEventsMode, encode_get_request_params, generate_short_id +from posthog.utils import ( + PersonOnEventsMode, + encode_get_request_params, + generate_short_id, +) # Lifecycle takes an event/action, time range, interval and for every period, splits the users who did the action into 4: # diff --git a/posthog/queries/trends/test/test_breakdowns.py b/posthog/queries/trends/test/test_breakdowns.py index df24ea8c14237..29c917e4dd843 100644 --- a/posthog/queries/trends/test/test_breakdowns.py +++ b/posthog/queries/trends/test/test_breakdowns.py @@ -4,7 +4,11 @@ from posthog.constants import TRENDS_TABLE from posthog.models import Filter from posthog.queries.trends.trends import Trends -from posthog.test.base import APIBaseTest, ClickhouseTestMixin, snapshot_clickhouse_queries +from posthog.test.base import ( + APIBaseTest, + ClickhouseTestMixin, + snapshot_clickhouse_queries, +) from posthog.test.test_journeys import journeys_for @@ -17,7 +21,11 @@ def setUp(self): { "event": "watched movie", "timestamp": datetime(2020, 1, 2, 12, 1), - "properties": {"$session_id": "1", "movie_length": 100, "$current_url": "https://example.com"}, + "properties": { + "$session_id": "1", + "movie_length": 100, + "$current_url": "https://example.com", + }, } ], # Duration 60 seconds, with 2 events in 1 session @@ -25,12 +33,20 @@ def setUp(self): { "event": "watched movie", "timestamp": datetime(2020, 1, 2, 12, 1), - "properties": {"$session_id": "2", "movie_length": 50, "$current_url": "https://example.com"}, + "properties": { + "$session_id": "2", + "movie_length": 50, + "$current_url": "https://example.com", + }, }, { "event": "watched movie", "timestamp": datetime(2020, 1, 2, 12, 2), - "properties": {"$session_id": "2", "movie_length": 75, "$current_url": "https://example.com"}, + "properties": { + "$session_id": "2", + "movie_length": 75, + "$current_url": "https://example.com", + }, }, ], # Duration 90 seconds, but session spans query boundary, so only a single event is counted @@ -90,7 +106,14 @@ def _run(self, extra: Dict = {}, events_extra: Dict = {}): response = Trends().run( Filter( data={ - "events": [{"id": "watched movie", "name": "watched movie", "type": "events", **events_extra}], + "events": [ + { + "id": "watched movie", + "name": "watched movie", + "type": "events", + **events_extra, + } + ], "date_from": "2020-01-02T00:00:00Z", "date_to": "2020-01-12T00:00:00Z", **extra, @@ -106,7 +129,13 @@ def test_breakdown_by_session_duration_of_events(self): { "breakdown": "$session_duration", "breakdown_type": "session", - "properties": [{"key": "$current_url", "operator": "is_not", "value": ["https://test.com"]}], + "properties": [ + { + "key": "$current_url", + "operator": "is_not", + "value": ["https://test.com"], + } + ], } ) @@ -128,16 +157,34 @@ def test_breakdown_by_session_duration_of_events_with_bucketing(self): "breakdown": "$session_duration", "breakdown_type": "session", "breakdown_histogram_bin_count": 3, - "properties": [{"key": "$current_url", "operator": "is_not", "value": ["https://test.com"]}], + "properties": [ + { + "key": "$current_url", + "operator": "is_not", + "value": ["https://test.com"], + } + ], } ) self.assertEqual( [(item["breakdown_value"], item["count"], item["data"]) for item in response], [ - ("[0.0,69.92]", 3.0, [3.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]), - ("[69.92,110.72]", 1.0, [1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]), - ("[110.72,180.01]", 5.0, [0.0, 0.0, 1.0, 4.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]), + ( + "[0.0,69.92]", + 3.0, + [3.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], + ), + ( + "[69.92,110.72]", + 1.0, + [1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], + ), + ( + "[110.72,180.01]", + 5.0, + [0.0, 0.0, 1.0, 4.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], + ), ], ) @@ -160,7 +207,8 @@ def test_breakdown_by_session_duration_of_events_single_aggregate(self): @snapshot_clickhouse_queries def test_breakdown_by_session_duration_of_unique_sessions(self): response = self._run( - {"breakdown": "$session_duration", "breakdown_type": "session"}, events_extra={"math": "unique_session"} + {"breakdown": "$session_duration", "breakdown_type": "session"}, + events_extra={"math": "unique_session"}, ) self.assertEqual( @@ -177,62 +225,126 @@ def test_breakdown_by_session_duration_of_unique_sessions(self): @snapshot_clickhouse_queries def test_breakdown_by_session_duration_of_unique_sessions_with_bucketing(self): response = self._run( - {"breakdown": "$session_duration", "breakdown_type": "session", "breakdown_histogram_bin_count": 3}, + { + "breakdown": "$session_duration", + "breakdown_type": "session", + "breakdown_histogram_bin_count": 3, + }, events_extra={"math": "unique_session"}, ) self.assertEqual( [(item["breakdown_value"], item["count"], item["data"]) for item in response], [ - ("[0.0,69.92]", 2.0, [2.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]), - ("[69.92,110.72]", 1.0, [1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]), - ("[110.72,180.01]", 3.0, [0.0, 0.0, 1.0, 2.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]), + ( + "[0.0,69.92]", + 2.0, + [2.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], + ), + ( + "[69.92,110.72]", + 1.0, + [1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], + ), + ( + "[110.72,180.01]", + 3.0, + [0.0, 0.0, 1.0, 2.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], + ), ], ) @snapshot_clickhouse_queries def test_breakdown_by_event_property_with_bucketing(self): response = self._run( - {"breakdown": "movie_length", "breakdown_type": "event", "breakdown_histogram_bin_count": 3} + { + "breakdown": "movie_length", + "breakdown_type": "event", + "breakdown_histogram_bin_count": 3, + } ) self.assertEqual( [(item["breakdown_value"], item["count"], item["data"]) for item in response], [ - ("[25.0,66.25]", 4.0, [2.0, 0.0, 0.0, 2.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]), - ("[66.25,98.37]", 2.0, [1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]), - ("[98.37,1000.01]", 2.0, [1.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]), + ( + "[25.0,66.25]", + 4.0, + [2.0, 0.0, 0.0, 2.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], + ), + ( + "[66.25,98.37]", + 2.0, + [1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], + ), + ( + "[98.37,1000.01]", + 2.0, + [1.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], + ), ], ) @snapshot_clickhouse_queries def test_breakdown_by_event_property_of_unique_sessions_with_bucketing(self): response = self._run( - {"breakdown": "movie_length", "breakdown_type": "event", "breakdown_histogram_bin_count": 3}, + { + "breakdown": "movie_length", + "breakdown_type": "event", + "breakdown_histogram_bin_count": 3, + }, events_extra={"math": "unique_session"}, ) self.assertEqual( [(item["breakdown_value"], item["count"], item["data"]) for item in response], [ - ("[25.0,66.25]", 3.0, [2.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]), - ("[66.25,98.37]", 2.0, [1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]), - ("[98.37,1000.01]", 2.0, [1.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]), + ( + "[25.0,66.25]", + 3.0, + [2.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], + ), + ( + "[66.25,98.37]", + 2.0, + [1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], + ), + ( + "[98.37,1000.01]", + 2.0, + [1.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], + ), ], ) def test_breakdown_by_event_property_with_bucketing_and_duplicate_buckets(self): journey = { "person1": [ - {"event": "watched tv", "timestamp": datetime(2020, 1, 2, 12, 1), "properties": {"episode_length": 300}} + { + "event": "watched tv", + "timestamp": datetime(2020, 1, 2, 12, 1), + "properties": {"episode_length": 300}, + } ], "person2": [ - {"event": "watched tv", "timestamp": datetime(2020, 1, 4, 12, 1), "properties": {"episode_length": 300}} + { + "event": "watched tv", + "timestamp": datetime(2020, 1, 4, 12, 1), + "properties": {"episode_length": 300}, + } ], "person3": [ - {"event": "watched tv", "timestamp": datetime(2020, 1, 6, 12, 1), "properties": {"episode_length": 300}} + { + "event": "watched tv", + "timestamp": datetime(2020, 1, 6, 12, 1), + "properties": {"episode_length": 300}, + } ], "person4": [ - {"event": "watched tv", "timestamp": datetime(2020, 1, 8, 12, 1), "properties": {"episode_length": 300}} + { + "event": "watched tv", + "timestamp": datetime(2020, 1, 8, 12, 1), + "properties": {"episode_length": 300}, + } ], } @@ -256,22 +368,44 @@ def test_breakdown_by_event_property_with_bucketing_and_duplicate_buckets(self): self.assertEqual( [(item["breakdown_value"], item["count"], item["data"]) for item in response], - [("[300.0,300.01]", 4.0, [1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0])], + [ + ( + "[300.0,300.01]", + 4.0, + [1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0], + ) + ], ) def test_breakdown_by_event_property_with_bucketing_and_single_bucket(self): journey = { "person1": [ - {"event": "watched tv", "timestamp": datetime(2020, 1, 2, 12, 1), "properties": {"episode_length": 300}} + { + "event": "watched tv", + "timestamp": datetime(2020, 1, 2, 12, 1), + "properties": {"episode_length": 300}, + } ], "person2": [ - {"event": "watched tv", "timestamp": datetime(2020, 1, 4, 12, 1), "properties": {"episode_length": 300}} + { + "event": "watched tv", + "timestamp": datetime(2020, 1, 4, 12, 1), + "properties": {"episode_length": 300}, + } ], "person3": [ - {"event": "watched tv", "timestamp": datetime(2020, 1, 5, 12, 1), "properties": {"episode_length": 320}} + { + "event": "watched tv", + "timestamp": datetime(2020, 1, 5, 12, 1), + "properties": {"episode_length": 320}, + } ], "person4": [ - {"event": "watched tv", "timestamp": datetime(2020, 1, 6, 12, 1), "properties": {"episode_length": 305}} + { + "event": "watched tv", + "timestamp": datetime(2020, 1, 6, 12, 1), + "properties": {"episode_length": 305}, + } ], } @@ -293,7 +427,13 @@ def test_breakdown_by_event_property_with_bucketing_and_single_bucket(self): self.assertEqual( [(item["breakdown_value"], item["count"], item["data"]) for item in response], - [("[300.0,320.01]", 4.0, [1.0, 0.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0])], + [ + ( + "[300.0,320.01]", + 4.0, + [1.0, 0.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], + ) + ], ) @snapshot_clickhouse_queries @@ -301,7 +441,14 @@ def test_breakdown_by_event_property_with_entity_session_filter(self): response = self._run( {"breakdown": "$current_url", "breakdown_type": "event"}, events_extra={ - "properties": [{"key": "$session_duration", "type": "session", "operator": "gt", "value": 30}] + "properties": [ + { + "key": "$session_duration", + "type": "session", + "operator": "gt", + "value": 30, + } + ] }, ) @@ -309,7 +456,11 @@ def test_breakdown_by_event_property_with_entity_session_filter(self): [(item["breakdown_value"], item["count"], item["data"]) for item in response], [ ("", 6.0, [1.0, 0.0, 1.0, 4.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]), - ("https://example.com", 2.0, [2.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]), + ( + "https://example.com", + 2.0, + [2.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], + ), ], ) @@ -326,6 +477,10 @@ def test_breakdown_histogram_by_missing_property_regression(self): self.assertEqual( [(item["breakdown_value"], item["count"], item["data"]) for item in response], [ - ("[nan,nan]", 0.0, [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]), + ( + "[nan,nan]", + 0.0, + [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], + ), ], ) diff --git a/posthog/queries/trends/test/test_breakdowns_by_current_url.py b/posthog/queries/trends/test/test_breakdowns_by_current_url.py index 76b7ad94902ea..bc7a81595843b 100644 --- a/posthog/queries/trends/test/test_breakdowns_by_current_url.py +++ b/posthog/queries/trends/test/test_breakdowns_by_current_url.py @@ -3,7 +3,11 @@ from posthog.models import Filter from posthog.queries.trends.trends import Trends -from posthog.test.base import APIBaseTest, ClickhouseTestMixin, snapshot_clickhouse_queries +from posthog.test.base import ( + APIBaseTest, + ClickhouseTestMixin, + snapshot_clickhouse_queries, +) from posthog.test.test_journeys import journeys_for @@ -16,13 +20,19 @@ def setUp(self): { "event": "watched movie", "timestamp": datetime(2020, 1, 2, 12, 1), - "properties": {"$current_url": "https://example.com", "$pathname": ""}, + "properties": { + "$current_url": "https://example.com", + "$pathname": "", + }, }, # trailing question mark { "event": "watched movie", "timestamp": datetime(2020, 1, 2, 12, 1), - "properties": {"$current_url": "https://example.com?", "$pathname": "?"}, + "properties": { + "$current_url": "https://example.com?", + "$pathname": "?", + }, }, ], "person2": [ @@ -30,13 +40,19 @@ def setUp(self): { "event": "watched movie", "timestamp": datetime(2020, 1, 2, 12, 1), - "properties": {"$current_url": "https://example.com/", "$pathname": "/"}, + "properties": { + "$current_url": "https://example.com/", + "$pathname": "/", + }, }, # trailing hash { "event": "watched movie", "timestamp": datetime(2020, 1, 2, 12, 1), - "properties": {"$current_url": "https://example.com#", "$pathname": "#"}, + "properties": { + "$current_url": "https://example.com#", + "$pathname": "#", + }, }, ], "person3": [ @@ -44,7 +60,10 @@ def setUp(self): { "event": "watched movie", "timestamp": datetime(2020, 1, 2, 12, 1), - "properties": {"$current_url": "https://example.com/home", "$pathname": "/home"}, + "properties": { + "$current_url": "https://example.com/home", + "$pathname": "/home", + }, }, ], "person4": [ @@ -52,19 +71,28 @@ def setUp(self): { "event": "watched movie", "timestamp": datetime(2020, 1, 2, 12, 1), - "properties": {"$current_url": "https://example.com/home/", "$pathname": "/home/"}, + "properties": { + "$current_url": "https://example.com/home/", + "$pathname": "/home/", + }, }, # trailing hash { "event": "watched movie", "timestamp": datetime(2020, 1, 2, 12, 1), - "properties": {"$current_url": "https://example.com/home#", "$pathname": "/home#"}, + "properties": { + "$current_url": "https://example.com/home#", + "$pathname": "/home#", + }, }, # all the things { "event": "watched movie", "timestamp": datetime(2020, 1, 2, 12, 1), - "properties": {"$current_url": "https://example.com/home/?#", "$pathname": "/home/?#"}, + "properties": { + "$current_url": "https://example.com/home/?#", + "$pathname": "/home/?#", + }, }, ], } @@ -75,7 +103,14 @@ def _run(self, extra: Dict = {}, events_extra: Dict = {}): response = Trends().run( Filter( data={ - "events": [{"id": "watched movie", "name": "watched movie", "type": "events", **events_extra}], + "events": [ + { + "id": "watched movie", + "name": "watched movie", + "type": "events", + **events_extra, + } + ], "date_from": "2020-01-02T00:00:00Z", "date_to": "2020-01-12T00:00:00Z", **extra, @@ -87,7 +122,13 @@ def _run(self, extra: Dict = {}, events_extra: Dict = {}): @snapshot_clickhouse_queries def test_breakdown_by_pathname(self) -> None: - response = self._run({"breakdown": "$pathname", "breakdown_type": "event", "breakdown_normalize_url": True}) + response = self._run( + { + "breakdown": "$pathname", + "breakdown_type": "event", + "breakdown_normalize_url": True, + } + ) assert [(item["breakdown_value"], item["count"], item["data"]) for item in response] == [ ("/", 4.0, [4.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]), @@ -96,9 +137,23 @@ def test_breakdown_by_pathname(self) -> None: @snapshot_clickhouse_queries def test_breakdown_by_current_url(self) -> None: - response = self._run({"breakdown": "$current_url", "breakdown_type": "event", "breakdown_normalize_url": True}) + response = self._run( + { + "breakdown": "$current_url", + "breakdown_type": "event", + "breakdown_normalize_url": True, + } + ) assert [(item["breakdown_value"], item["count"], item["data"]) for item in response] == [ - ("https://example.com", 4.0, [4.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]), - ("https://example.com/home", 4.0, [4.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]), + ( + "https://example.com", + 4.0, + [4.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], + ), + ( + "https://example.com/home", + 4.0, + [4.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], + ), ] diff --git a/posthog/queries/trends/test/test_formula.py b/posthog/queries/trends/test/test_formula.py index 5dffeac08959c..d6dc332fbf4f4 100644 --- a/posthog/queries/trends/test/test_formula.py +++ b/posthog/queries/trends/test/test_formula.py @@ -7,7 +7,12 @@ from posthog.models.filters.filter import Filter from posthog.models.group.util import create_group from posthog.queries.trends.trends import Trends -from posthog.test.base import APIBaseTest, ClickhouseTestMixin, _create_event, snapshot_clickhouse_queries +from posthog.test.base import ( + APIBaseTest, + ClickhouseTestMixin, + _create_event, + snapshot_clickhouse_queries, +) class TestFormula(ClickhouseTestMixin, APIBaseTest): @@ -17,10 +22,17 @@ def setUp(self): super().setUp() Person.objects.create( - team_id=self.team.pk, distinct_ids=["blabla", "anonymous_id"], properties={"$some_prop": "some_val"} + team_id=self.team.pk, + distinct_ids=["blabla", "anonymous_id"], + properties={"$some_prop": "some_val"}, ) - create_group(team_id=self.team.pk, group_type_index=0, group_key="org:5", properties={"industry": "finance"}) + create_group( + team_id=self.team.pk, + group_type_index=0, + group_key="org:5", + properties={"industry": "finance"}, + ) with freeze_time("2020-01-02T13:01:01Z"): _create_event( @@ -39,33 +51,58 @@ def setUp(self): team=self.team, event="session start", distinct_id="blabla", - properties={"session duration": 300, "location": "Paris", "$session_id": "1", "$group_0": "org:5"}, + properties={ + "session duration": 300, + "location": "Paris", + "$session_id": "1", + "$group_0": "org:5", + }, ) _create_event( team=self.team, event="session start", distinct_id="blabla", - properties={"session duration": 400, "location": "London", "$session_id": "1", "$group_0": "org:5"}, + properties={ + "session duration": 400, + "location": "London", + "$session_id": "1", + "$group_0": "org:5", + }, ) with freeze_time("2020-01-03T13:01:01Z"): _create_event( team=self.team, event="session start", distinct_id="blabla", - properties={"session duration": 400, "location": "London", "$session_id": "1", "$group_0": "org:5"}, + properties={ + "session duration": 400, + "location": "London", + "$session_id": "1", + "$group_0": "org:5", + }, ) with freeze_time("2020-01-03T13:04:01Z"): _create_event( team=self.team, event="session start", distinct_id="blabla", - properties={"session duration": 500, "location": "London", "$session_id": "1", "$group_0": "org:5"}, + properties={ + "session duration": 500, + "location": "London", + "$session_id": "1", + "$group_0": "org:5", + }, ) _create_event( team=self.team, event="session end", distinct_id="blabla", - properties={"session duration": 500, "location": "London", "$session_id": "1", "$group_0": "org:5"}, + properties={ + "session duration": 500, + "location": "London", + "$session_id": "1", + "$group_0": "org:5", + }, ) _create_event( @@ -98,8 +135,16 @@ def _run(self, extra: Dict = {}, run_at: Optional[str] = None): Filter( data={ "events": [ - {"id": "session start", "math": "sum", "math_property": "session duration"}, - {"id": "session start", "math": "avg", "math_property": "session duration"}, + { + "id": "session start", + "math": "sum", + "math_property": "session duration", + }, + { + "id": "session start", + "math": "avg", + "math_property": "session duration", + }, ], "formula": "A + B", **extra, @@ -191,13 +236,28 @@ def test_month_interval(self): self.assertEqual(data, [0.0, 0.0, 2160.0]) def test_formula(self): - self.assertEqual(self._run({"formula": "A - B"})[0]["data"], [0.0, 0.0, 0.0, 0.0, 0.0, 600.0, 450.0, 0.0]) - self.assertEqual(self._run({"formula": "A * B"})[0]["data"], [0.0, 0.0, 0.0, 0.0, 0.0, 270000.0, 405000.0, 0.0]) - self.assertEqual(self._run({"formula": "A / B"})[0]["data"], [0.0, 0.0, 0.0, 0.0, 0.0, 3.0, 2.0, 0.0]) - self.assertEqual(self._run({"formula": "(A/3600)/B"})[0]["data"], [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]) + self.assertEqual( + self._run({"formula": "A - B"})[0]["data"], + [0.0, 0.0, 0.0, 0.0, 0.0, 600.0, 450.0, 0.0], + ) + self.assertEqual( + self._run({"formula": "A * B"})[0]["data"], + [0.0, 0.0, 0.0, 0.0, 0.0, 270000.0, 405000.0, 0.0], + ) + self.assertEqual( + self._run({"formula": "A / B"})[0]["data"], + [0.0, 0.0, 0.0, 0.0, 0.0, 3.0, 2.0, 0.0], + ) + self.assertEqual( + self._run({"formula": "(A/3600)/B"})[0]["data"], + [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], + ) self.assertEqual(self._run({"formula": "(A/3600)/B"})[0]["count"], 0) - self.assertEqual(self._run({"formula": "A/0"})[0]["data"], [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]) + self.assertEqual( + self._run({"formula": "A/0"})[0]["data"], + [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], + ) self.assertEqual(self._run({"formula": "A/0"})[0]["count"], 0) @snapshot_clickhouse_queries @@ -228,7 +288,12 @@ def test_regression_formula_with_unique_sessions_2x_and_duration_filter(self): "id": "session start", "math": "unique_session", "properties": [ - {"key": "$session_duration", "value": 12, "operator": "gt", "type": "session"} + { + "key": "$session_duration", + "value": 12, + "operator": "gt", + "type": "session", + } ], }, {"id": "session start", "math": "unique_session"}, @@ -252,14 +317,24 @@ def test_regression_formula_with_unique_sessions_2x_and_duration_filter_2x(self) "id": "$autocapture", "math": "unique_session", "properties": [ - {"key": "$session_duration", "type": "session", "value": 30, "operator": "lt"} + { + "key": "$session_duration", + "type": "session", + "value": 30, + "operator": "lt", + } ], }, { "id": "session start", "math": "unique_session", "properties": [ - {"key": "$session_duration", "type": "session", "value": 500, "operator": "gt"} + { + "key": "$session_duration", + "type": "session", + "value": 500, + "operator": "gt", + } ], }, ], @@ -286,7 +361,13 @@ def test_regression_formula_with_session_duration_aggregation(self): "math": "avg", "math_property": "$session_duration", }, - {"type": "events", "id": "session end", "order": 1, "name": "$pageview", "math": "total"}, + { + "type": "events", + "id": "session end", + "order": 1, + "name": "$pageview", + "math": "total", + }, ], "formula": "A / B", } @@ -349,12 +430,19 @@ def test_breakdown_aggregated(self): @snapshot_clickhouse_queries def test_breakdown_with_different_breakdown_values_per_series(self): - response = self._run( { "events": [ - {"id": "session start", "math": "sum", "math_property": "session duration"}, - {"id": "session end", "math": "sum", "math_property": "session duration"}, + { + "id": "session start", + "math": "sum", + "math_property": "session duration", + }, + { + "id": "session end", + "math": "sum", + "math_property": "session duration", + }, ], "formula": "A + B", "breakdown": "location", @@ -387,8 +475,18 @@ def test_breakdown_counts_of_different_events_one_without_events(self): "breakdown": "location", "breakdown_type": "event", "events": [ - {"id": "session start", "name": "session start", "type": "events", "order": 0}, - {"id": "session error", "name": "session error", "type": "events", "order": 1}, + { + "id": "session start", + "name": "session start", + "type": "events", + "order": 0, + }, + { + "id": "session error", + "name": "session error", + "type": "events", + "order": 1, + }, ], } ), @@ -468,9 +566,15 @@ def test_breakdown_cohort(self): @snapshot_clickhouse_queries def test_breakdown_hogql(self): response = self._run( - {"breakdown": "concat(person.properties.$some_prop, ' : ', properties.location)", "breakdown_type": "hogql"} + { + "breakdown": "concat(person.properties.$some_prop, ' : ', properties.location)", + "breakdown_type": "hogql", + } + ) + self.assertEqual( + [series["label"] for series in response], + ["some_val : London", "some_val : Paris"], ) - self.assertEqual([series["label"] for series in response], ["some_val : London", "some_val : Paris"]) self.assertEqual( [ [0.0, 0.0, 0.0, 0.0, 0.0, 800.0, 1350.0, 0.0], @@ -481,7 +585,11 @@ def test_breakdown_hogql(self): def test_breakdown_mismatching_sizes(self): response = self._run( - {"events": [{"id": "session start"}, {"id": "session end"}], "breakdown": "location", "formula": "A + B"} + { + "events": [{"id": "session start"}, {"id": "session end"}], + "breakdown": "location", + "formula": "A + B", + } ) self.assertEqual(response[0]["label"], "London") @@ -522,7 +630,11 @@ def test_event_properties(self): "math_property": "session duration", "properties": [{"key": "$current_url", "value": "http://example.org"}], }, - {"id": "session start", "math": "avg", "math_property": "session duration"}, + { + "id": "session start", + "math": "avg", + "math_property": "session duration", + }, ] } )[0]["data"], @@ -541,7 +653,8 @@ def test_aggregated(self): def test_cumulative(self): self.assertEqual( - self._run({"display": TRENDS_CUMULATIVE})[0]["data"], [0.0, 0.0, 0.0, 0.0, 0.0, 1200.0, 2550.0, 2550.0] + self._run({"display": TRENDS_CUMULATIVE})[0]["data"], + [0.0, 0.0, 0.0, 0.0, 0.0, 1200.0, 2550.0, 2550.0], ) def test_multiple_events(self): @@ -550,9 +663,21 @@ def test_multiple_events(self): self._run( { "events": [ - {"id": "session start", "math": "sum", "math_property": "session duration"}, - {"id": "session start", "math": "avg", "math_property": "session duration"}, - {"id": "session start", "math": "avg", "math_property": "session duration"}, + { + "id": "session start", + "math": "sum", + "math_property": "session duration", + }, + { + "id": "session start", + "math": "avg", + "math_property": "session duration", + }, + { + "id": "session start", + "math": "avg", + "math_property": "session duration", + }, ] } )[0]["data"], @@ -573,13 +698,20 @@ def test_session_formulas(self): ) def test_group_formulas(self): - self.assertEqual( self._run( { "events": [ - {"id": "session start", "math": "unique_group", "math_group_type_index": 0}, - {"id": "session start", "math": "unique_group", "math_group_type_index": 0}, + { + "id": "session start", + "math": "unique_group", + "math_group_type_index": 0, + }, + { + "id": "session start", + "math": "unique_group", + "math_group_type_index": 0, + }, ] } )[0]["data"], diff --git a/posthog/queries/trends/test/test_paging_breakdowns.py b/posthog/queries/trends/test/test_paging_breakdowns.py index 573d036e4b82e..e15175cd92d76 100644 --- a/posthog/queries/trends/test/test_paging_breakdowns.py +++ b/posthog/queries/trends/test/test_paging_breakdowns.py @@ -41,7 +41,17 @@ def _run(self, extra: Dict = {}, run_at: Optional[str] = None): with freeze_time(run_at or "2020-01-04T13:01:01Z"): action_response = Trends().run( Filter( - data={"events": [{"id": "$pageview", "name": "$pageview", "type": "events", "order": 0}], **extra} + data={ + "events": [ + { + "id": "$pageview", + "name": "$pageview", + "type": "events", + "order": 0, + } + ], + **extra, + } ), self.team, ) diff --git a/posthog/queries/trends/test/test_person.py b/posthog/queries/trends/test/test_person.py index bfd18b6ed8de8..1cd04cfd3d206 100644 --- a/posthog/queries/trends/test/test_person.py +++ b/posthog/queries/trends/test/test_person.py @@ -12,7 +12,9 @@ from posthog.models.group.util import create_group from posthog.models.group_type_mapping import GroupTypeMapping from posthog.queries.trends.trends_actors import TrendsActors -from posthog.session_recordings.queries.test.session_replay_sql import produce_replay_summary +from posthog.session_recordings.queries.test.session_replay_sql import ( + produce_replay_summary, +) from posthog.test.base import ( APIBaseTest, ClickhouseTestMixin, @@ -103,7 +105,11 @@ def test_person_query_does_not_include_recording_events_if_flag_not_set(self): event = {"id": "pageview", "name": "pageview", "type": "events", "order": 0} filter = Filter( - data={"date_from": "2021-01-21T00:00:00Z", "date_to": "2021-01-21T23:59:59Z", "events": [event]} + data={ + "date_from": "2021-01-21T00:00:00Z", + "date_to": "2021-01-21T23:59:59Z", + "events": [event], + } ) entity = Entity(event) _, serialized_actors, _ = TrendsActors(self.team, entity, filter).get_actors() @@ -125,7 +131,11 @@ def test_group_query_includes_recording_events(self): ) _create_event( - event="pageview", distinct_id="u1", team=self.team, timestamp=timezone.now(), properties={"$group_0": "bla"} + event="pageview", + distinct_id="u1", + team=self.team, + timestamp=timezone.now(), + properties={"$group_0": "bla"}, ) _create_event( event="pageview", @@ -204,7 +214,10 @@ def test_weekly_active_users(self): data = response.json() self.assertEqual(data.get("results")[0].get("count"), 2) - self.assertEqual([item["name"] for item in data.get("results")[0].get("people")], ["u_17", "u_16"]) + self.assertEqual( + [item["name"] for item in data.get("results")[0].get("people")], + ["u_17", "u_16"], + ) def test_weekly_active_users_grouped_by_week(self): for d in range(10, 18): # create a person and event for each day 10. Sep - 17. Sep @@ -271,7 +284,10 @@ def test_weekly_active_users_cumulative(self): data = response.json() self.assertEqual(data.get("results")[0].get("count"), 2) - self.assertEqual([item["name"] for item in data.get("results")[0].get("people")], ["u_11", "u_10"]) + self.assertEqual( + [item["name"] for item in data.get("results")[0].get("people")], + ["u_11", "u_10"], + ) @skip("see PR 17356") def test_weekly_active_users_breakdown(self): @@ -313,4 +329,7 @@ def test_weekly_active_users_breakdown(self): data = response.json() # self.assertEqual(data.get("results")[0].get("count"), 2) - self.assertEqual([item["name"] for item in data.get("results")[0].get("people")], ["a_17", "a_16"]) + self.assertEqual( + [item["name"] for item in data.get("results")[0].get("people")], + ["a_17", "a_16"], + ) diff --git a/posthog/queries/trends/total_volume.py b/posthog/queries/trends/total_volume.py index 154e105e77f92..31f5d83b4c15c 100644 --- a/posthog/queries/trends/total_volume.py +++ b/posthog/queries/trends/total_volume.py @@ -38,8 +38,16 @@ parse_response, process_math, ) -from posthog.queries.util import TIME_IN_SECONDS, get_interval_func_ch, get_start_of_interval_sql -from posthog.utils import PersonOnEventsMode, encode_get_request_params, generate_short_id +from posthog.queries.util import ( + TIME_IN_SECONDS, + get_interval_func_ch, + get_start_of_interval_sql, +) +from posthog.utils import ( + PersonOnEventsMode, + encode_get_request_params, + generate_short_id, +) class TrendsTotalVolume: @@ -115,7 +123,11 @@ def _total_volume_query(self, entity: Entity, filter: Filter, team: Team) -> Tup tag_queries(trend_volume_type="volume_aggregate") content_sql = VOLUME_AGGREGATE_SQL.format(event_query_base=event_query_base, **content_sql_params) - return (content_sql, params, self._parse_aggregate_volume_result(filter, entity, team.id)) + return ( + content_sql, + params, + self._parse_aggregate_volume_result(filter, entity, team.id), + ) else: tag_queries(trend_volume_display="time_series") null_sql = NULL_SQL.format( @@ -133,12 +145,17 @@ def _total_volume_query(self, entity: Entity, filter: Filter, team: Team) -> Tup aggregator=determine_aggregator(entity, team), # TODO: Support groups officialy and with tests date_to_truncated=get_start_of_interval_sql(filter.interval, team=team, source="%(date_to)s"), date_from_active_users_adjusted_truncated=get_start_of_interval_sql( - filter.interval, team=team, source="%(date_from_active_users_adjusted)s" + filter.interval, + team=team, + source="%(date_from_active_users_adjusted)s", ), **content_sql_params, **trend_event_query.active_user_params, ) - elif filter.display == TRENDS_CUMULATIVE and entity.math in (UNIQUE_USERS, UNIQUE_GROUPS): + elif filter.display == TRENDS_CUMULATIVE and entity.math in ( + UNIQUE_USERS, + UNIQUE_GROUPS, + ): # :TODO: Consider using bitmap-per-date to speed this up tag_queries(trend_volume_type="cumulative_actors") cumulative_sql = CUMULATIVE_SQL.format( @@ -272,7 +289,11 @@ def _offset_date_to(self, point_datetime: datetime, filter: Filter, entity: Enti return offset_time_series_date_by_interval(point_datetime, filter=filter, team=team) def _get_persons_url( - self, filter: Filter, entity: Entity, team: Team, point_datetimes: List[datetime] + self, + filter: Filter, + entity: Entity, + team: Team, + point_datetimes: List[datetime], ) -> List[Dict[str, Any]]: persons_url = [] cache_invalidation_key = generate_short_id() diff --git a/posthog/queries/trends/trends.py b/posthog/queries/trends/trends.py index 049417799bb8b..479d64f3259b1 100644 --- a/posthog/queries/trends/trends.py +++ b/posthog/queries/trends/trends.py @@ -101,7 +101,12 @@ def adjusted_filter(self, filter: Filter, team: Team) -> Tuple[Filter, Optional[ return new_filter, label_to_payload def merge_results( - self, result, cached_result: Optional[Dict[str, Any]], entity_order: int, filter: Filter, team: Team + self, + result, + cached_result: Optional[Dict[str, Any]], + entity_order: int, + filter: Filter, + team: Team, ): if cached_result and filter.display != TRENDS_CUMULATIVE: new_res = [] @@ -139,7 +144,11 @@ def _run_query(self, filter: Filter, team: Team, entity: Entity) -> List[Dict[st result = parse_function(result) serialized_data = self._format_serialized(entity, result) merged_results, cached_result = self.merge_results( - serialized_data, cached_result, entity.order or entity.index, filter, team + serialized_data, + cached_result, + entity.order or entity.index, + filter, + team, ) if cached_result: @@ -149,7 +158,15 @@ def _run_query(self, filter: Filter, team: Team, entity: Entity) -> List[Dict[st return merged_results def _run_query_for_threading( - self, result: List, index: int, query_type, sql, params, query_tags: Dict, filter: Filter, team_id: int + self, + result: List, + index: int, + query_type, + sql, + params, + query_tags: Dict, + filter: Filter, + team_id: int, ): tag_queries(**query_tags) with push_scope() as scope: @@ -171,7 +188,16 @@ def _run_parallel(self, filter: Filter, team: Team) -> List[Dict[str, Any]]: sql_statements_with_params[entity.index] = (sql, query_params) thread = threading.Thread( target=self._run_query_for_threading, - args=(result, entity.index, query_type, sql, query_params, get_query_tags(), adjusted_filter, team.pk), + args=( + result, + entity.index, + query_type, + sql, + query_params, + get_query_tags(), + adjusted_filter, + team.pk, + ), ) jobs.append(thread) @@ -189,12 +215,20 @@ def _run_parallel(self, filter: Filter, team: Team) -> List[Dict[str, Any]]: scope.set_tag("team", team) for i, entity in enumerate(filter.entities): scope.set_context( - "query", {"sql": sql_statements_with_params[i][0], "params": sql_statements_with_params[i][1]} + "query", + { + "sql": sql_statements_with_params[i][0], + "params": sql_statements_with_params[i][1], + }, ) serialized_data = cast(List[Callable], parse_functions)[entity.index](result[entity.index]) serialized_data = self._format_serialized(entity, serialized_data) merged_results, cached_result = self.merge_results( - serialized_data, cached_result, entity.order or entity.index, filter, team + serialized_data, + cached_result, + entity.order or entity.index, + filter, + team, ) result[entity.index] = merged_results diff --git a/posthog/queries/trends/trends_actors.py b/posthog/queries/trends/trends_actors.py index ed484968af7dd..228eac4f799e3 100644 --- a/posthog/queries/trends/trends_actors.py +++ b/posthog/queries/trends/trends_actors.py @@ -43,7 +43,8 @@ def actor_query(self, limit_actors: Optional[bool] = True) -> Tuple[str, Dict]: self._filter = self._filter.shallow_clone( { "properties": self._filter.property_groups.combine_properties( - PropertyOperatorType.AND, [Property(key="id", value=cohort.pk, type="cohort")] + PropertyOperatorType.AND, + [Property(key="id", value=cohort.pk, type="cohort")], ).to_dict() } ) @@ -115,7 +116,10 @@ def actor_query(self, limit_actors: Optional[bool] = True) -> Tuple[str, Dict]: else "" ) - actor_value_expression, actor_value_params = self._aggregation_actor_value_expression_with_params + ( + actor_value_expression, + actor_value_params, + ) = self._aggregation_actor_value_expression_with_params return ( GET_ACTORS_FROM_EVENT_QUERY.format( @@ -126,7 +130,12 @@ def actor_query(self, limit_actors: Optional[bool] = True) -> Tuple[str, Dict]: limit="LIMIT %(limit)s" if limit_actors else "", offset="OFFSET %(offset)s" if limit_actors else "", ), - {**params, **actor_value_params, "offset": self._filter.offset, "limit": self._filter.limit or 100}, + { + **params, + **actor_value_params, + "offset": self._filter.offset, + "limit": self._filter.limit or 100, + }, ) @cached_property diff --git a/posthog/queries/trends/trends_event_query.py b/posthog/queries/trends/trends_event_query.py index c5504ce388486..6ef5cf009dafc 100644 --- a/posthog/queries/trends/trends_event_query.py +++ b/posthog/queries/trends/trends_event_query.py @@ -24,7 +24,13 @@ def get_query(self) -> Tuple[str, Dict[str, Any]]: + " ".join( [ ", " - + get_property_string_expr("events", property, f"'{property}'", "properties", table_alias="e")[0] + + get_property_string_expr( + "events", + property, + f"'{property}'", + "properties", + table_alias="e", + )[0] + f" as {property}" for property in self._extra_event_properties ] diff --git a/posthog/queries/trends/trends_event_query_base.py b/posthog/queries/trends/trends_event_query_base.py index 93dd843349046..4eaaa46d75a52 100644 --- a/posthog/queries/trends/trends_event_query_base.py +++ b/posthog/queries/trends/trends_event_query_base.py @@ -1,6 +1,11 @@ from typing import Any, Dict, Tuple -from posthog.constants import MONTHLY_ACTIVE, UNIQUE_USERS, WEEKLY_ACTIVE, PropertyOperatorType +from posthog.constants import ( + MONTHLY_ACTIVE, + UNIQUE_USERS, + WEEKLY_ACTIVE, + PropertyOperatorType, +) from posthog.models import Entity from posthog.models.entity.util import get_entity_filtering_params from posthog.models.filters.filter import Filter @@ -8,7 +13,10 @@ from posthog.queries.event_query import EventQuery from posthog.queries.person_query import PersonQuery from posthog.queries.query_date_range import QueryDateRange -from posthog.queries.trends.util import COUNT_PER_ACTOR_MATH_FUNCTIONS, get_active_user_params +from posthog.queries.trends.util import ( + COUNT_PER_ACTOR_MATH_FUNCTIONS, + get_active_user_params, +) from posthog.queries.util import get_person_properties_mode from posthog.utils import PersonOnEventsMode @@ -117,9 +125,10 @@ def _get_date_filter(self) -> Tuple[str, Dict]: self.parsed_date_to = parsed_date_to if self._entity.math in [WEEKLY_ACTIVE, MONTHLY_ACTIVE]: - active_user_format_params, active_user_query_params = get_active_user_params( - self._filter, self._entity, self._team_id - ) + ( + active_user_format_params, + active_user_query_params, + ) = get_active_user_params(self._filter, self._entity, self._team_id) self.active_user_params = active_user_format_params date_params.update(active_user_query_params) diff --git a/posthog/queries/trends/util.py b/posthog/queries/trends/util.py index 46cd2a8041f32..382201a9e0203 100644 --- a/posthog/queries/trends/util.py +++ b/posthog/queries/trends/util.py @@ -7,7 +7,13 @@ from dateutil.relativedelta import relativedelta from rest_framework.exceptions import ValidationError -from posthog.constants import MONTHLY_ACTIVE, NON_TIME_SERIES_DISPLAY_TYPES, UNIQUE_GROUPS, UNIQUE_USERS, WEEKLY_ACTIVE +from posthog.constants import ( + MONTHLY_ACTIVE, + NON_TIME_SERIES_DISPLAY_TYPES, + UNIQUE_GROUPS, + UNIQUE_USERS, + WEEKLY_ACTIVE, +) from posthog.hogql.hogql import translate_hogql from posthog.models.entity import Entity from posthog.models.event.sql import EVENT_JOIN_PERSON_SQL @@ -42,7 +48,10 @@ "p99_count_per_actor": "quantile(0.99)", } -ALL_SUPPORTED_MATH_FUNCTIONS = [*list(PROPERTY_MATH_FUNCTIONS.keys()), *list(COUNT_PER_ACTOR_MATH_FUNCTIONS.keys())] +ALL_SUPPORTED_MATH_FUNCTIONS = [ + *list(PROPERTY_MATH_FUNCTIONS.keys()), + *list(COUNT_PER_ACTOR_MATH_FUNCTIONS.keys()), +] def process_math( @@ -72,7 +81,8 @@ def process_math( elif entity.math in PROPERTY_MATH_FUNCTIONS: if entity.math_property is None: raise ValidationError( - {"math_property": "This field is required when `math` is set to a function."}, code="required" + {"math_property": "This field is required when `math` is set to a function."}, + code="required", ) if entity.math_property == "$session_duration": aggregate_operation = f"{PROPERTY_MATH_FUNCTIONS[entity.math]}(session_duration)" @@ -90,7 +100,10 @@ def process_math( def parse_response( - stats: Dict, filter: Filter, additional_values: Dict = {}, entity: Optional[Entity] = None + stats: Dict, + filter: Filter, + additional_values: Dict = {}, + entity: Optional[Entity] = None, ) -> Dict[str, Any]: counts = stats[1] labels = [item.strftime("%-d-%b-%Y{}".format(" %H:%M" if filter.interval == "hour" else "")) for item in stats[0]] diff --git a/posthog/queries/util.py b/posthog/queries/util.py index ec218785b1dc9..8fdda3799dbd1 100644 --- a/posthog/queries/util.py +++ b/posthog/queries/util.py @@ -155,7 +155,9 @@ def convert_to_datetime_aware(date_obj): def correct_result_for_sampling( - value: Union[int, float], sampling_factor: Optional[float], entity_math: Optional[str] = None + value: Union[int, float], + sampling_factor: Optional[float], + entity_math: Optional[str] = None, ) -> Union[int, float]: from posthog.queries.trends.util import ALL_SUPPORTED_MATH_FUNCTIONS diff --git a/posthog/rate_limit.py b/posthog/rate_limit.py index 587eb742ee4f1..dbaa478d9f462 100644 --- a/posthog/rate_limit.py +++ b/posthog/rate_limit.py @@ -82,7 +82,6 @@ def safely_get_team_id_from_view(view): return None def allow_request(self, request, view): - if not is_rate_limit_enabled(round(time.time() / 60)): return True @@ -114,7 +113,12 @@ def allow_request(self, request, view): statsd.incr( "rate_limit_exceeded", - tags={"team_id": team_id, "scope": scope, "rate": rate, "path": path}, + tags={ + "team_id": team_id, + "scope": scope, + "rate": rate, + "path": path, + }, ) RATE_LIMIT_EXCEEDED_COUNTER.labels(team_id=team_id, scope=scope, path=path).inc() @@ -188,7 +192,6 @@ def safely_get_token_from_request(request: Request) -> Optional[str]: return None def allow_request(self, request, view): - if not is_decide_rate_limit_enabled(): return True diff --git a/posthog/session_recordings/models/session_recording.py b/posthog/session_recordings/models/session_recording.py index b3b09a03d0b74..5ef51b34c2f1b 100644 --- a/posthog/session_recordings/models/session_recording.py +++ b/posthog/session_recordings/models/session_recording.py @@ -12,7 +12,9 @@ RecordingMatchingEvents, RecordingMetadata, ) -from posthog.session_recordings.models.session_recording_event import SessionRecordingViewed +from posthog.session_recordings.models.session_recording_event import ( + SessionRecordingViewed, +) from posthog.session_recordings.queries.session_replay_events import SessionReplayEvents diff --git a/posthog/session_recordings/models/session_recording_playlist.py b/posthog/session_recordings/models/session_recording_playlist.py index a0f11b5718335..9c198dbd83e3c 100644 --- a/posthog/session_recordings/models/session_recording_playlist.py +++ b/posthog/session_recordings/models/session_recording_playlist.py @@ -5,7 +5,6 @@ class SessionRecordingPlaylist(models.Model): - short_id: models.CharField = models.CharField(max_length=12, blank=True, default=generate_short_id) name: models.CharField = models.CharField(max_length=400, null=True, blank=True) derived_name: models.CharField = models.CharField(max_length=400, null=True, blank=True) @@ -18,7 +17,11 @@ class SessionRecordingPlaylist(models.Model): created_by: models.ForeignKey = models.ForeignKey("User", on_delete=models.SET_NULL, null=True, blank=True) last_modified_at: models.DateTimeField = models.DateTimeField(default=timezone.now) last_modified_by: models.ForeignKey = models.ForeignKey( - "User", on_delete=models.SET_NULL, null=True, blank=True, related_name="modified_playlists" + "User", + on_delete=models.SET_NULL, + null=True, + blank=True, + related_name="modified_playlists", ) # DEPRECATED diff --git a/posthog/session_recordings/models/session_recording_playlist_item.py b/posthog/session_recordings/models/session_recording_playlist_item.py index f0caf9721aa7b..73d38815fdef8 100644 --- a/posthog/session_recordings/models/session_recording_playlist_item.py +++ b/posthog/session_recordings/models/session_recording_playlist_item.py @@ -14,7 +14,9 @@ class Meta: blank=True, ) playlist: models.ForeignKey = models.ForeignKey( - "SessionRecordingPlaylist", related_name="playlist_items", on_delete=models.CASCADE + "SessionRecordingPlaylist", + related_name="playlist_items", + on_delete=models.CASCADE, ) created_at: models.DateTimeField = models.DateTimeField(auto_now_add=True, blank=True) diff --git a/posthog/session_recordings/models/system_status_queries.py b/posthog/session_recordings/models/system_status_queries.py index f14396bf06270..9728c0695c1fa 100644 --- a/posthog/session_recordings/models/system_status_queries.py +++ b/posthog/session_recordings/models/system_status_queries.py @@ -19,5 +19,7 @@ def get_recording_status_month_to_date() -> RecordingsSystemStatus: """ )[0] return RecordingsSystemStatus( - count=result[0], events=f"{result[1]:,} rrweb events in {result[2]:,} messages", size=result[3] + count=result[0], + events=f"{result[1]:,} rrweb events in {result[2]:,} messages", + size=result[3], ) diff --git a/posthog/session_recordings/queries/session_recording_list_from_replay_summary.py b/posthog/session_recordings/queries/session_recording_list_from_replay_summary.py index b725c95cb658e..c39eee18bf79c 100644 --- a/posthog/session_recordings/queries/session_recording_list_from_replay_summary.py +++ b/posthog/session_recordings/queries/session_recording_list_from_replay_summary.py @@ -117,7 +117,10 @@ def _get_console_log_clause( console_logs_filter: List[Literal["error", "warn", "log"]] ) -> Tuple[str, Dict[str, Any]]: return ( - (f"AND level in %(console_logs_levels)s", {"console_logs_levels": console_logs_filter}) + ( + f"AND level in %(console_logs_levels)s", + {"console_logs_levels": console_logs_filter}, + ) if console_logs_filter else ("", {}) ) @@ -126,7 +129,10 @@ def get_query(self) -> Tuple[str, Dict]: if not self._filter.console_search_query: return "", {} - events_timestamp_clause, events_timestamp_params = self._get_events_timestamp_clause + ( + events_timestamp_clause, + events_timestamp_params, + ) = self._get_events_timestamp_clause console_log_clause, console_log_params = self._get_console_log_clause(self._filter.console_logs_filter) return self._rawQuery.format( @@ -319,9 +325,10 @@ def build_event_filters(self) -> SummaryEventFiltersSQL: if entity.id and entity.id not in event_names_to_filter: event_names_to_filter.append(entity.id) - this_entity_condition_sql, this_entity_filter_params = self.format_event_filter( - entity, prepend=f"event_matcher_{index}", team_id=self._team_id - ) + ( + this_entity_condition_sql, + this_entity_filter_params, + ) = self.format_event_filter(entity, prepend=f"event_matcher_{index}", team_id=self._team_id) joining = "OR" if index > 0 else "" condition_sql += f"{joining} {this_entity_condition_sql}" # wrap in smooths to constrain the scope of the OR @@ -355,7 +362,10 @@ def _get_groups_query(self) -> Tuple[str, Dict]: from posthog.queries.groups_join_query import GroupsJoinQuery return GroupsJoinQuery( - self._filter, self._team_id, self._column_optimizer, person_on_events_mode=self._person_on_events_mode + self._filter, + self._team_id, + self._column_optimizer, + person_on_events_mode=self._person_on_events_mode, ).get_join_query() # We want to select events beyond the range of the recording to handle the case where @@ -382,13 +392,17 @@ def get_query(self, select_event_ids: bool = False) -> Tuple[str, Dict[str, Any] } _, recording_start_time_params = _get_recording_start_time_clause(self._filter) - provided_session_ids_clause, provided_session_ids_params = _get_filter_by_provided_session_ids_clause( - recording_filters=self._filter, column_name="$session_id" - ) + ( + provided_session_ids_clause, + provided_session_ids_params, + ) = _get_filter_by_provided_session_ids_clause(recording_filters=self._filter, column_name="$session_id") event_filters = self.build_event_filters event_filters_params = event_filters.params - events_timestamp_clause, events_timestamp_params = self._get_events_timestamp_clause + ( + events_timestamp_clause, + events_timestamp_params, + ) = self._get_events_timestamp_clause groups_query, groups_params = self._get_groups_query() @@ -407,9 +421,11 @@ def get_query(self, select_event_ids: bool = False) -> Tuple[str, Dict[str, Any] person_id_joined_alias=f"{self.DISTINCT_ID_TABLE_ALIAS}.person_id", ) - persons_join, persons_select_params, persons_sub_query = self._persons_join_or_subquery( - event_filters, prop_query - ) + ( + persons_join, + persons_select_params, + persons_sub_query, + ) = self._persons_join_or_subquery(event_filters, prop_query) return ( self._raw_events_query.format( @@ -590,9 +606,10 @@ def get_query(self) -> Tuple[str, Dict[str, Any]]: } _, recording_start_time_params = _get_recording_start_time_clause(self._filter) - provided_session_ids_clause, provided_session_ids_params = _get_filter_by_provided_session_ids_clause( - recording_filters=self._filter - ) + ( + provided_session_ids_clause, + provided_session_ids_params, + ) = _get_filter_by_provided_session_ids_clause(recording_filters=self._filter) ( log_matching_session_ids_clause, @@ -636,7 +653,8 @@ def get_query(self) -> Tuple[str, Dict[str, Any]]: ) def duration_clause( - self, duration_filter_type: Literal["duration", "active_seconds", "inactive_seconds"] + self, + duration_filter_type: Literal["duration", "active_seconds", "inactive_seconds"], ) -> Tuple[str, Dict[str, Any]]: duration_clause = "" duration_params = {} diff --git a/posthog/session_recordings/queries/session_recording_properties.py b/posthog/session_recordings/queries/session_recording_properties.py index 22d54e9799b4d..e7c5544f14fe7 100644 --- a/posthog/session_recordings/queries/session_recording_properties.py +++ b/posthog/session_recordings/queries/session_recording_properties.py @@ -73,12 +73,19 @@ def format_session_recording_id_filters(self) -> Tuple[str, Dict]: def get_query(self) -> Tuple[str, Dict[str, Any]]: base_params = {"team_id": self._team_id} - events_timestamp_clause, events_timestamp_params = self._get_events_timestamp_clause() - session_ids_clause, session_ids_params = self.format_session_recording_id_filters() + ( + events_timestamp_clause, + events_timestamp_params, + ) = self._get_events_timestamp_clause() + ( + session_ids_clause, + session_ids_params, + ) = self.format_session_recording_id_filters() return ( self._core_single_pageview_event_query.format( - events_timestamp_clause=events_timestamp_clause, session_ids_clause=session_ids_clause + events_timestamp_clause=events_timestamp_clause, + session_ids_clause=session_ids_clause, ), {**base_params, **events_timestamp_params, **session_ids_params}, ) diff --git a/posthog/session_recordings/queries/session_replay_events.py b/posthog/session_recordings/queries/session_replay_events.py index 02c2a26519c21..0d60559c7a047 100644 --- a/posthog/session_recordings/queries/session_replay_events.py +++ b/posthog/session_recordings/queries/session_replay_events.py @@ -25,12 +25,19 @@ def exists(self, session_id: str, team: Team) -> bool: AND session_id = %(session_id)s AND min_first_timestamp >= now() - INTERVAL %(recording_ttl_days)s DAY """, - {"team_id": team.pk, "session_id": session_id, "recording_ttl_days": ttl_days(team)}, + { + "team_id": team.pk, + "session_id": session_id, + "recording_ttl_days": ttl_days(team), + }, ) return result[0][0] > 0 def get_metadata( - self, session_id: str, team: Team, recording_start_time: Optional[datetime] = None + self, + session_id: str, + team: Team, + recording_start_time: Optional[datetime] = None, ) -> Optional[RecordingMetadata]: query = """ SELECT @@ -63,7 +70,11 @@ def get_metadata( replay_response: List[Tuple] = sync_execute( query, - {"team_id": team.pk, "session_id": session_id, "recording_start_time": recording_start_time}, + { + "team_id": team.pk, + "session_id": session_id, + "recording_start_time": recording_start_time, + }, ) if len(replay_response) == 0: diff --git a/posthog/session_recordings/queries/test/session_replay_sql.py b/posthog/session_recordings/queries/test/session_replay_sql.py index fcc3eee03a44e..3b094a5a75c8c 100644 --- a/posthog/session_recordings/queries/test/session_replay_sql.py +++ b/posthog/session_recordings/queries/test/session_replay_sql.py @@ -7,7 +7,10 @@ from posthog.clickhouse.log_entries import INSERT_LOG_ENTRY_SQL from posthog.kafka_client.client import ClickhouseProducer -from posthog.kafka_client.topics import KAFKA_CLICKHOUSE_SESSION_REPLAY_EVENTS, KAFKA_LOG_ENTRIES +from posthog.kafka_client.topics import ( + KAFKA_CLICKHOUSE_SESSION_REPLAY_EVENTS, + KAFKA_LOG_ENTRIES, +) from posthog.models.event.util import format_clickhouse_timestamp from posthog.utils import cast_timestamp_or_now @@ -134,7 +137,11 @@ def produce_replay_summary( } p = ClickhouseProducer() # because this is in a test it will write directly using SQL not really with Kafka - p.produce(topic=KAFKA_CLICKHOUSE_SESSION_REPLAY_EVENTS, sql=INSERT_SINGLE_SESSION_REPLAY, data=data) + p.produce( + topic=KAFKA_CLICKHOUSE_SESSION_REPLAY_EVENTS, + sql=INSERT_SINGLE_SESSION_REPLAY, + data=data, + ) for level, messages in log_messages.items(): for message in messages: diff --git a/posthog/session_recordings/queries/test/test_session_recording_list_from_session_replay.py b/posthog/session_recordings/queries/test/test_session_recording_list_from_session_replay.py index 9424a9df2a51c..f70f86fdba3cf 100644 --- a/posthog/session_recordings/queries/test/test_session_recording_list_from_session_replay.py +++ b/posthog/session_recordings/queries/test/test_session_recording_list_from_session_replay.py @@ -14,13 +14,17 @@ from posthog.models.action_step import ActionStep from posthog.models.filters.session_recordings_filter import SessionRecordingsFilter from posthog.models.group.util import create_group -from posthog.session_recordings.sql.session_replay_event_sql import TRUNCATE_SESSION_REPLAY_EVENTS_TABLE_SQL +from posthog.session_recordings.sql.session_replay_event_sql import ( + TRUNCATE_SESSION_REPLAY_EVENTS_TABLE_SQL, +) from posthog.models.team import Team from posthog.session_recordings.queries.session_recording_list_from_replay_summary import ( SessionRecordingListFromReplaySummary, ) from posthog.session_recordings.queries.session_replay_events import ttl_days -from posthog.session_recordings.queries.test.session_replay_sql import produce_replay_summary +from posthog.session_recordings.queries.test.session_replay_sql import ( + produce_replay_summary, +) from posthog.test.base import ( APIBaseTest, ClickhouseTestMixin, @@ -64,7 +68,11 @@ def create_event( if properties is None: properties = {"$os": "Windows 95", "$current_url": "aloha.com/2"} return _create_event( - team=team, event=event_name, timestamp=timestamp, distinct_id=distinct_id, properties=properties + team=team, + event=event_name, + timestamp=timestamp, + distinct_id=distinct_id, + properties=properties, ) @property @@ -123,7 +131,10 @@ def test_basic_query(self): filter = SessionRecordingsFilter(team=self.team, data={"no_filter": None}) session_recording_list_instance = SessionRecordingListFromReplaySummary(filter=filter, team=self.team) - (session_recordings, more_recordings_available) = session_recording_list_instance.run() + ( + session_recordings, + more_recordings_available, + ) = session_recording_list_instance.run() assert session_recordings == [ { @@ -225,7 +236,10 @@ def test_basic_query_active_sessions( }, ) session_recording_list_instance = SessionRecordingListFromReplaySummary(filter=filter, team=self.team) - (session_recordings, more_recordings_available) = session_recording_list_instance.run() + ( + session_recordings, + more_recordings_available, + ) = session_recording_list_instance.run() assert sorted( [(s["session_id"], s["duration"], s["active_seconds"]) for s in session_recordings], @@ -243,7 +257,10 @@ def test_basic_query_active_sessions( }, ) session_recording_list_instance = SessionRecordingListFromReplaySummary(filter=filter, team=self.team) - (session_recordings, more_recordings_available) = session_recording_list_instance.run() + ( + session_recordings, + more_recordings_available, + ) = session_recording_list_instance.run() assert [(s["session_id"], s["duration"], s["active_seconds"]) for s in session_recordings] == [ (session_id_active_is_61, 59, 61.0) @@ -257,7 +274,10 @@ def test_basic_query_active_sessions( }, ) session_recording_list_instance = SessionRecordingListFromReplaySummary(filter=filter, team=self.team) - (session_recordings, more_recordings_available) = session_recording_list_instance.run() + ( + session_recordings, + more_recordings_available, + ) = session_recording_list_instance.run() assert [(s["session_id"], s["duration"], s["inactive_seconds"]) for s in session_recordings] == [ (session_id_inactive_is_61, 61, 61.0) @@ -315,7 +335,10 @@ def test_basic_query_with_paging(self): filter = SessionRecordingsFilter(team=self.team, data={"no_filter": None, "limit": 1, "offset": 0}) session_recording_list_instance = SessionRecordingListFromReplaySummary(filter=filter, team=self.team) - (session_recordings, more_recordings_available) = session_recording_list_instance.run() + ( + session_recordings, + more_recordings_available, + ) = session_recording_list_instance.run() assert session_recordings == [ { @@ -341,7 +364,10 @@ def test_basic_query_with_paging(self): filter = SessionRecordingsFilter(team=self.team, data={"no_filter": None, "limit": 1, "offset": 1}) session_recording_list_instance = SessionRecordingListFromReplaySummary(filter=filter, team=self.team) - (session_recordings, more_recordings_available) = session_recording_list_instance.run() + ( + session_recordings, + more_recordings_available, + ) = session_recording_list_instance.run() assert session_recordings == [ { @@ -367,7 +393,10 @@ def test_basic_query_with_paging(self): filter = SessionRecordingsFilter(team=self.team, data={"no_filter": None, "limit": 1, "offset": 2}) session_recording_list_instance = SessionRecordingListFromReplaySummary(filter=filter, team=self.team) - (session_recordings, more_recordings_available) = session_recording_list_instance.run() + ( + session_recordings, + more_recordings_available, + ) = session_recording_list_instance.run() assert session_recordings == [] @@ -479,7 +508,10 @@ def test_first_url_selection(self): filter = SessionRecordingsFilter(team=self.team, data={"no_filter": None}) session_recording_list_instance = SessionRecordingListFromReplaySummary(filter=filter, team=self.team) - (session_recordings, more_recordings_available) = session_recording_list_instance.run() + ( + session_recordings, + more_recordings_available, + ) = session_recording_list_instance.run() assert sorted( [{"session_id": r["session_id"], "first_url": r["first_url"]} for r in session_recordings], @@ -561,7 +593,11 @@ def test_event_filter(self): first_timestamp=self.base_time, team_id=self.team.id, ) - self.create_event(user, self.base_time, properties={"$session_id": session_id_one, "$window_id": str(uuid4())}) + self.create_event( + user, + self.base_time, + properties={"$session_id": session_id_one, "$window_id": str(uuid4())}, + ) produce_replay_summary( distinct_id=user, session_id=session_id_one, @@ -571,7 +607,16 @@ def test_event_filter(self): filter = SessionRecordingsFilter( team=self.team, - data={"events": [{"id": "$pageview", "type": "events", "order": 0, "name": "$pageview"}]}, + data={ + "events": [ + { + "id": "$pageview", + "type": "events", + "order": 0, + "name": "$pageview", + } + ] + }, ) session_recording_list_instance = SessionRecordingListFromReplaySummary(filter=filter, team=self.team) (session_recordings, _) = session_recording_list_instance.run() @@ -580,7 +625,16 @@ def test_event_filter(self): filter = SessionRecordingsFilter( team=self.team, - data={"events": [{"id": "$autocapture", "type": "events", "order": 0, "name": "$autocapture"}]}, + data={ + "events": [ + { + "id": "$autocapture", + "type": "events", + "order": 0, + "name": "$autocapture", + } + ] + }, ) session_recording_list_instance = SessionRecordingListFromReplaySummary(filter=filter, team=self.team) (session_recordings, _) = session_recording_list_instance.run() @@ -609,7 +663,16 @@ def test_event_filter_has_ttl_applied_too(self): filter = SessionRecordingsFilter( team=self.team, - data={"events": [{"id": "$pageview", "type": "events", "order": 0, "name": "$pageview"}]}, + data={ + "events": [ + { + "id": "$pageview", + "type": "events", + "order": 0, + "name": "$pageview", + } + ] + }, ) session_recording_list_instance = SessionRecordingListFromReplaySummary(filter=filter, team=self.team) (session_recordings, _) = session_recording_list_instance.run() @@ -654,7 +717,12 @@ def test_event_filter_with_active_sessions( session_id_active_is_61 = f"test_basic_query_active_sessions-active-{str(uuid4())}" self.create_event( - user, self.base_time, properties={"$session_id": session_id_total_is_61, "$window_id": str(uuid4())} + user, + self.base_time, + properties={ + "$session_id": session_id_total_is_61, + "$window_id": str(uuid4()), + }, ) produce_replay_summary( session_id=session_id_total_is_61, @@ -671,7 +739,12 @@ def test_event_filter_with_active_sessions( ) self.create_event( - user, self.base_time, properties={"$session_id": session_id_active_is_61, "$window_id": str(uuid4())} + user, + self.base_time, + properties={ + "$session_id": session_id_active_is_61, + "$window_id": str(uuid4()), + }, ) produce_replay_summary( session_id=session_id_active_is_61, @@ -691,12 +764,22 @@ def test_event_filter_with_active_sessions( team=self.team, data={ "duration_type_filter": "duration", - "events": [{"id": "$pageview", "type": "events", "order": 0, "name": "$pageview"}], + "events": [ + { + "id": "$pageview", + "type": "events", + "order": 0, + "name": "$pageview", + } + ], "session_recording_duration": '{"type":"recording","key":"duration","value":60,"operator":"gt"}', }, ) session_recording_list_instance = SessionRecordingListFromReplaySummary(filter=filter, team=self.team) - (session_recordings, more_recordings_available) = session_recording_list_instance.run() + ( + session_recordings, + more_recordings_available, + ) = session_recording_list_instance.run() assert [(s["session_id"], s["duration"], s["active_seconds"]) for s in session_recordings] == [ (session_id_total_is_61, 61, 59.0) @@ -706,12 +789,22 @@ def test_event_filter_with_active_sessions( team=self.team, data={ "duration_type_filter": "active_seconds", - "events": [{"id": "$pageview", "type": "events", "order": 0, "name": "$pageview"}], + "events": [ + { + "id": "$pageview", + "type": "events", + "order": 0, + "name": "$pageview", + } + ], "session_recording_duration": '{"type":"recording","key":"duration","value":60,"operator":"gt"}', }, ) session_recording_list_instance = SessionRecordingListFromReplaySummary(filter=filter, team=self.team) - (session_recordings, more_recordings_available) = session_recording_list_instance.run() + ( + session_recordings, + more_recordings_available, + ) = session_recording_list_instance.run() assert [(s["session_id"], s["duration"], s["active_seconds"]) for s in session_recordings] == [ (session_id_active_is_61, 59, 61.0) @@ -732,7 +825,11 @@ def test_event_filter_with_properties(self): self.create_event( user, self.base_time, - properties={"$browser": "Chrome", "$session_id": session_id_one, "$window_id": str(uuid4())}, + properties={ + "$browser": "Chrome", + "$session_id": session_id_one, + "$window_id": str(uuid4()), + }, ) produce_replay_summary( distinct_id=user, @@ -749,7 +846,14 @@ def test_event_filter_with_properties(self): "type": "events", "order": 0, "name": "$pageview", - "properties": [{"key": "$browser", "value": ["Chrome"], "operator": "exact", "type": "event"}], + "properties": [ + { + "key": "$browser", + "value": ["Chrome"], + "operator": "exact", + "type": "event", + } + ], } ] }, @@ -768,7 +872,14 @@ def test_event_filter_with_properties(self): "type": "events", "order": 0, "name": "$pageview", - "properties": [{"key": "$browser", "value": ["Firefox"], "operator": "exact", "type": "event"}], + "properties": [ + { + "key": "$browser", + "value": ["Firefox"], + "operator": "exact", + "type": "event", + } + ], } ] }, @@ -783,12 +894,22 @@ def test_multiple_event_filters(self): user = "test_multiple_event_filters-user" Person.objects.create(team=self.team, distinct_ids=[user], properties={"email": "bla"}) produce_replay_summary( - distinct_id=user, session_id=session_id, first_timestamp=self.base_time, team_id=self.team.id + distinct_id=user, + session_id=session_id, + first_timestamp=self.base_time, + team_id=self.team.id, ) - self.create_event(user, self.base_time, properties={"$session_id": session_id, "$window_id": "1"}) self.create_event( - user, self.base_time, properties={"$session_id": session_id, "$window_id": "1"}, event_name="new-event" + user, + self.base_time, + properties={"$session_id": session_id, "$window_id": "1"}, + ) + self.create_event( + user, + self.base_time, + properties={"$session_id": session_id, "$window_id": "1"}, + event_name="new-event", ) produce_replay_summary( distinct_id=user, @@ -801,8 +922,18 @@ def test_multiple_event_filters(self): team=self.team, data={ "events": [ - {"id": "$pageview", "type": "events", "order": 0, "name": "$pageview"}, - {"id": "new-event", "type": "events", "order": 0, "name": "new-event"}, + { + "id": "$pageview", + "type": "events", + "order": 0, + "name": "$pageview", + }, + { + "id": "new-event", + "type": "events", + "order": 0, + "name": "new-event", + }, ] }, ) @@ -817,8 +948,18 @@ def test_multiple_event_filters(self): team=self.team, data={ "events": [ - {"id": "$pageview", "type": "events", "order": 0, "name": "$pageview"}, - {"id": "new-event2", "type": "events", "order": 0, "name": "new-event2"}, + { + "id": "$pageview", + "type": "events", + "order": 0, + "name": "$pageview", + }, + { + "id": "new-event2", + "type": "events", + "order": 0, + "name": "new-event2", + }, ] }, ) @@ -844,7 +985,10 @@ def test_action_filter(self): ) action_without_properties = self.create_action( name="custom-event", - properties=[{"key": "$session_id", "value": session_id_one}, {"key": "$window_id", "value": window_id}], + properties=[ + {"key": "$session_id", "value": session_id_one}, + {"key": "$window_id", "value": window_id}, + ], ) produce_replay_summary( @@ -857,7 +1001,11 @@ def test_action_filter(self): user, self.base_time, event_name="custom-event", - properties={"$browser": "Chrome", "$session_id": session_id_one, "$window_id": window_id}, + properties={ + "$browser": "Chrome", + "$session_id": session_id_one, + "$window_id": window_id, + }, ) produce_replay_summary( distinct_id=user, @@ -869,7 +1017,14 @@ def test_action_filter(self): filter = SessionRecordingsFilter( team=self.team, data={ - "actions": [{"id": action_with_properties.id, "type": "actions", "order": 1, "name": "custom-event"}] + "actions": [ + { + "id": action_with_properties.id, + "type": "actions", + "order": 1, + "name": "custom-event", + } + ] }, ) session_recording_list_instance = SessionRecordingListFromReplaySummary(filter=filter, team=self.team) @@ -879,7 +1034,14 @@ def test_action_filter(self): filter = SessionRecordingsFilter( team=self.team, data={ - "actions": [{"id": action_without_properties.id, "type": "actions", "order": 1, "name": "custom-event"}] + "actions": [ + { + "id": action_without_properties.id, + "type": "actions", + "order": 1, + "name": "custom-event", + } + ] }, ) session_recording_list_instance = SessionRecordingListFromReplaySummary(filter=filter, team=self.team) @@ -898,7 +1060,14 @@ def test_action_filter(self): "type": "actions", "order": 1, "name": "custom-event", - "properties": [{"key": "$browser", "value": ["Firefox"], "operator": "exact", "type": "event"}], + "properties": [ + { + "key": "$browser", + "value": ["Firefox"], + "operator": "exact", + "type": "event", + } + ], } ] }, @@ -917,7 +1086,14 @@ def test_action_filter(self): "type": "actions", "order": 1, "name": "custom-event", - "properties": [{"key": "$browser", "value": ["Chrome"], "operator": "exact", "type": "event"}], + "properties": [ + { + "key": "$browser", + "value": ["Chrome"], + "operator": "exact", + "type": "event", + } + ], } ] }, @@ -941,7 +1117,11 @@ def test_all_sessions_recording_object_keys_with_entity_filter(self): last_timestamp=(self.base_time + relativedelta(seconds=60)), team_id=self.team.id, ) - self.create_event(user, self.base_time, properties={"$session_id": session_id, "$window_id": window_id}) + self.create_event( + user, + self.base_time, + properties={"$session_id": session_id, "$window_id": window_id}, + ) produce_replay_summary( distinct_id=user, session_id=session_id, @@ -951,7 +1131,16 @@ def test_all_sessions_recording_object_keys_with_entity_filter(self): ) filter = SessionRecordingsFilter( team=self.team, - data={"events": [{"id": "$pageview", "type": "events", "order": 0, "name": "$pageview"}]}, + data={ + "events": [ + { + "id": "$pageview", + "type": "events", + "order": 0, + "name": "$pageview", + } + ] + }, ) session_recording_list_instance = SessionRecordingListFromReplaySummary(filter=filter, team=self.team) (session_recordings, _) = session_recording_list_instance.run() @@ -1056,7 +1245,8 @@ def test_date_from_filter(self): assert session_recordings == [] filter = SessionRecordingsFilter( - team=self.team, data={"date_from": (self.base_time - relativedelta(days=2)).strftime("%Y-%m-%d")} + team=self.team, + data={"date_from": (self.base_time - relativedelta(days=2)).strftime("%Y-%m-%d")}, ) session_recording_list_instance = SessionRecordingListFromReplaySummary(filter=filter, team=self.team) (session_recordings, _) = session_recording_list_instance.run() @@ -1086,7 +1276,8 @@ def test_date_from_filter_cannot_search_before_ttl(self): ) filter = SessionRecordingsFilter( - team=self.team, data={"date_from": (self.base_time - relativedelta(days=20)).strftime("%Y-%m-%d")} + team=self.team, + data={"date_from": (self.base_time - relativedelta(days=20)).strftime("%Y-%m-%d")}, ) session_recording_list_instance = SessionRecordingListFromReplaySummary(filter=filter, team=self.team) (session_recordings, _) = session_recording_list_instance.run() @@ -1094,7 +1285,8 @@ def test_date_from_filter_cannot_search_before_ttl(self): assert session_recordings[0]["session_id"] == "storage is not past ttl" filter = SessionRecordingsFilter( - team=self.team, data={"date_from": (self.base_time - relativedelta(days=21)).strftime("%Y-%m-%d")} + team=self.team, + data={"date_from": (self.base_time - relativedelta(days=21)).strftime("%Y-%m-%d")}, ) session_recording_list_instance = SessionRecordingListFromReplaySummary(filter=filter, team=self.team) (session_recordings, _) = session_recording_list_instance.run() @@ -1102,7 +1294,8 @@ def test_date_from_filter_cannot_search_before_ttl(self): assert session_recordings[0]["session_id"] == "storage is not past ttl" filter = SessionRecordingsFilter( - team=self.team, data={"date_from": (self.base_time - relativedelta(days=22)).strftime("%Y-%m-%d")} + team=self.team, + data={"date_from": (self.base_time - relativedelta(days=22)).strftime("%Y-%m-%d")}, ) session_recording_list_instance = SessionRecordingListFromReplaySummary(filter=filter, team=self.team) (session_recordings, _) = session_recording_list_instance.run() @@ -1129,14 +1322,16 @@ def test_date_to_filter(self): ) filter = SessionRecordingsFilter( - team=self.team, data={"date_to": (self.base_time - relativedelta(days=4)).strftime("%Y-%m-%d")} + team=self.team, + data={"date_to": (self.base_time - relativedelta(days=4)).strftime("%Y-%m-%d")}, ) session_recording_list_instance = SessionRecordingListFromReplaySummary(filter=filter, team=self.team) (session_recordings, _) = session_recording_list_instance.run() assert session_recordings == [] filter = SessionRecordingsFilter( - team=self.team, data={"date_to": (self.base_time - relativedelta(days=3)).strftime("%Y-%m-%d")} + team=self.team, + data={"date_to": (self.base_time - relativedelta(days=3)).strftime("%Y-%m-%d")}, ) session_recording_list_instance = SessionRecordingListFromReplaySummary(filter=filter, team=self.team) (session_recordings, _) = session_recording_list_instance.run() @@ -1176,9 +1371,15 @@ def test_person_id_filter(self): session_id_one = f"test_person_id_filter-{str(uuid4())}" session_id_two = f"test_person_id_filter-{str(uuid4())}" p = Person.objects.create( - team=self.team, distinct_ids=[three_user_ids[0], three_user_ids[1]], properties={"email": "bla"} + team=self.team, + distinct_ids=[three_user_ids[0], three_user_ids[1]], + properties={"email": "bla"}, + ) + produce_replay_summary( + distinct_id=three_user_ids[0], + session_id=session_id_one, + team_id=self.team.id, ) - produce_replay_summary(distinct_id=three_user_ids[0], session_id=session_id_one, team_id=self.team.id) produce_replay_summary( distinct_id=three_user_ids[1], session_id=session_id_two, @@ -1201,7 +1402,9 @@ def test_all_filters_at_once(self): target_session_id = f"test_all_filters_at_once-{str(uuid4())}" p = Person.objects.create( - team=self.team, distinct_ids=[three_user_ids[0], three_user_ids[1]], properties={"email": "bla"} + team=self.team, + distinct_ids=[three_user_ids[0], three_user_ids[1]], + properties={"email": "bla"}, ) custom_event_action = self.create_action(name="custom-event") @@ -1219,7 +1422,9 @@ def test_all_filters_at_once(self): team_id=self.team.id, ) self.create_event( - three_user_ids[0], self.base_time - relativedelta(days=3), properties={"$session_id": target_session_id} + three_user_ids[0], + self.base_time - relativedelta(days=3), + properties={"$session_id": target_session_id}, ) self.create_event( three_user_ids[0], @@ -1250,8 +1455,22 @@ def test_all_filters_at_once(self): "date_to": (self.base_time + relativedelta(days=3)).strftime("%Y-%m-%d"), "date_from": (self.base_time - relativedelta(days=10)).strftime("%Y-%m-%d"), "session_recording_duration": '{"type":"recording","key":"duration","value":60,"operator":"gt"}', - "events": [{"id": "$pageview", "type": "events", "order": 0, "name": "$pageview"}], - "actions": [{"id": custom_event_action.id, "type": "actions", "order": 1, "name": "custom-event"}], + "events": [ + { + "id": "$pageview", + "type": "events", + "order": 0, + "name": "$pageview", + } + ], + "actions": [ + { + "id": custom_event_action.id, + "type": "actions", + "order": 1, + "name": "custom-event", + } + ], }, ) session_recording_list_instance = SessionRecordingListFromReplaySummary(filter=filter, team=self.team) @@ -1264,7 +1483,10 @@ def test_teams_dont_leak_event_filter(self): session_id = f"test_teams_dont_leak_event_filter-{str(uuid4())}" produce_replay_summary( - distinct_id=user, session_id=session_id, first_timestamp=self.base_time, team_id=self.team.id + distinct_id=user, + session_id=session_id, + first_timestamp=self.base_time, + team_id=self.team.id, ) self.create_event(1, self.base_time + relativedelta(seconds=15), team=another_team) produce_replay_summary( @@ -1276,7 +1498,16 @@ def test_teams_dont_leak_event_filter(self): filter = SessionRecordingsFilter( team=self.team, - data={"events": [{"id": "$pageview", "type": "events", "order": 0, "name": "$pageview"}]}, + data={ + "events": [ + { + "id": "$pageview", + "type": "events", + "order": 0, + "name": "$pageview", + } + ] + }, ) session_recording_list_instance = SessionRecordingListFromReplaySummary(filter=filter, team=self.team) @@ -1295,7 +1526,10 @@ def test_event_filter_with_person_properties(self): Person.objects.create(team=self.team, distinct_ids=[user_two], properties={"email": "bla2"}) produce_replay_summary( - distinct_id=user_one, session_id=session_id_one, first_timestamp=self.base_time, team_id=self.team.id + distinct_id=user_one, + session_id=session_id_one, + first_timestamp=self.base_time, + team_id=self.team.id, ) produce_replay_summary( distinct_id=user_one, @@ -1304,7 +1538,10 @@ def test_event_filter_with_person_properties(self): team_id=self.team.id, ) produce_replay_summary( - distinct_id=user_two, session_id=session_id_two, first_timestamp=self.base_time, team_id=self.team.id + distinct_id=user_two, + session_id=session_id_two, + first_timestamp=self.base_time, + team_id=self.team.id, ) produce_replay_summary( distinct_id=user_two, @@ -1315,7 +1552,16 @@ def test_event_filter_with_person_properties(self): filter = SessionRecordingsFilter( team=self.team, - data={"properties": [{"key": "email", "value": ["bla"], "operator": "exact", "type": "person"}]}, + data={ + "properties": [ + { + "key": "email", + "value": ["bla"], + "operator": "exact", + "type": "person", + } + ] + }, ) session_recording_list_instance = SessionRecordingListFromReplaySummary(filter=filter, team=self.team) @@ -1336,12 +1582,24 @@ def test_filter_with_cohort_properties(self): Person.objects.create(team=self.team, distinct_ids=[user_one], properties={"email": "bla"}) Person.objects.create( - team=self.team, distinct_ids=[user_two], properties={"email": "bla2", "$some_prop": "some_val"} + team=self.team, + distinct_ids=[user_two], + properties={"email": "bla2", "$some_prop": "some_val"}, ) cohort = Cohort.objects.create( team=self.team, name="cohort1", - groups=[{"properties": [{"key": "$some_prop", "value": "some_val", "type": "person"}]}], + groups=[ + { + "properties": [ + { + "key": "$some_prop", + "value": "some_val", + "type": "person", + } + ] + } + ], ) cohort.calculate_people_ch(pending_version=0) @@ -1373,7 +1631,16 @@ def test_filter_with_cohort_properties(self): ) filter = SessionRecordingsFilter( team=self.team, - data={"properties": [{"key": "id", "value": cohort.pk, "operator": None, "type": "cohort"}]}, + data={ + "properties": [ + { + "key": "id", + "value": cohort.pk, + "operator": None, + "type": "cohort", + } + ] + }, ) session_recording_list_instance = SessionRecordingListFromReplaySummary(filter=filter, team=self.team) (session_recordings, _) = session_recording_list_instance.run() @@ -1393,12 +1660,24 @@ def test_filter_with_events_and_cohorts(self): Person.objects.create(team=self.team, distinct_ids=[user_one], properties={"email": "bla"}) Person.objects.create( - team=self.team, distinct_ids=[user_two], properties={"email": "bla2", "$some_prop": "some_val"} + team=self.team, + distinct_ids=[user_two], + properties={"email": "bla2", "$some_prop": "some_val"}, ) cohort = Cohort.objects.create( team=self.team, name="cohort1", - groups=[{"properties": [{"key": "$some_prop", "value": "some_val", "type": "person"}]}], + groups=[ + { + "properties": [ + { + "key": "$some_prop", + "value": "some_val", + "type": "person", + } + ] + } + ], ) cohort.calculate_people_ch(pending_version=0) @@ -1446,8 +1725,22 @@ def test_filter_with_events_and_cohorts(self): data={ # has to be in the cohort and pageview has to be in the events # test data has one user in the cohort but no pageviews - "properties": [{"key": "id", "value": cohort.pk, "operator": None, "type": "cohort"}], - "events": [{"id": "$pageview", "type": "events", "order": 0, "name": "$pageview"}], + "properties": [ + { + "key": "id", + "value": cohort.pk, + "operator": None, + "type": "cohort", + } + ], + "events": [ + { + "id": "$pageview", + "type": "events", + "order": 0, + "name": "$pageview", + } + ], }, ) session_recording_list_instance = SessionRecordingListFromReplaySummary(filter=filter, team=self.team) @@ -1458,8 +1751,22 @@ def test_filter_with_events_and_cohorts(self): filter = SessionRecordingsFilter( team=self.team, data={ - "properties": [{"key": "id", "value": cohort.pk, "operator": None, "type": "cohort"}], - "events": [{"id": "custom_event", "type": "events", "order": 0, "name": "custom_event"}], + "properties": [ + { + "key": "id", + "value": cohort.pk, + "operator": None, + "type": "cohort", + } + ], + "events": [ + { + "id": "custom_event", + "type": "events", + "order": 0, + "name": "custom_event", + } + ], }, ) session_recording_list_instance = SessionRecordingListFromReplaySummary(filter=filter, team=self.team) @@ -1476,14 +1783,23 @@ def test_event_filter_with_matching_on_session_id(self): session_id = f"test_event_filter_with_matching_on_session_id-1-{str(uuid4())}" self.create_event( - user_distinct_id, self.base_time, event_name="$pageview", properties={"$session_id": session_id} + user_distinct_id, + self.base_time, + event_name="$pageview", + properties={"$session_id": session_id}, ) self.create_event( - user_distinct_id, self.base_time, event_name="$autocapture", properties={"$session_id": str(uuid4())} + user_distinct_id, + self.base_time, + event_name="$autocapture", + properties={"$session_id": str(uuid4())}, ) produce_replay_summary( - distinct_id=user_distinct_id, session_id=session_id, first_timestamp=self.base_time, team_id=self.team.id + distinct_id=user_distinct_id, + session_id=session_id, + first_timestamp=self.base_time, + team_id=self.team.id, ) produce_replay_summary( distinct_id=user_distinct_id, @@ -1494,7 +1810,16 @@ def test_event_filter_with_matching_on_session_id(self): filter = SessionRecordingsFilter( team=self.team, - data={"events": [{"id": "$pageview", "type": "events", "order": 0, "name": "$pageview"}]}, + data={ + "events": [ + { + "id": "$pageview", + "type": "events", + "order": 0, + "name": "$pageview", + } + ] + }, ) session_recording_list_instance = SessionRecordingListFromReplaySummary(filter=filter, team=self.team) (session_recordings, _) = session_recording_list_instance.run() @@ -1504,7 +1829,16 @@ def test_event_filter_with_matching_on_session_id(self): filter = SessionRecordingsFilter( team=self.team, - data={"events": [{"id": "$autocapture", "type": "events", "order": 0, "name": "$autocapture"}]}, + data={ + "events": [ + { + "id": "$autocapture", + "type": "events", + "order": 0, + "name": "$autocapture", + } + ] + }, ) session_recording_list_instance = SessionRecordingListFromReplaySummary(filter=filter, team=self.team) (session_recordings, _) = session_recording_list_instance.run() @@ -1521,11 +1855,18 @@ def test_event_filter_with_hogql_properties(self): self.create_event( user, self.base_time, - properties={"$browser": "Chrome", "$session_id": session_id, "$window_id": str(uuid4())}, + properties={ + "$browser": "Chrome", + "$session_id": session_id, + "$window_id": str(uuid4()), + }, ) produce_replay_summary( - distinct_id=user, session_id=session_id, first_timestamp=self.base_time, team_id=self.team.id + distinct_id=user, + session_id=session_id, + first_timestamp=self.base_time, + team_id=self.team.id, ) produce_replay_summary( distinct_id=user, @@ -1586,11 +1927,18 @@ def test_event_filter_with_hogql_person_properties(self): self.create_event( user, self.base_time, - properties={"$browser": "Chrome", "$session_id": session_id, "$window_id": str(uuid4())}, + properties={ + "$browser": "Chrome", + "$session_id": session_id, + "$window_id": str(uuid4()), + }, ) produce_replay_summary( - distinct_id=user, session_id=session_id, first_timestamp=self.base_time, team_id=self.team.id + distinct_id=user, + session_id=session_id, + first_timestamp=self.base_time, + team_id=self.team.id, ) produce_replay_summary( distinct_id=user, @@ -1609,7 +1957,10 @@ def test_event_filter_with_hogql_person_properties(self): "order": 0, "name": "$pageview", "properties": [ - {"key": "person.properties.email == 'bla'", "type": "hogql"}, + { + "key": "person.properties.email == 'bla'", + "type": "hogql", + }, ], } ] @@ -1631,7 +1982,10 @@ def test_event_filter_with_hogql_person_properties(self): "order": 0, "name": "$pageview", "properties": [ - {"key": "person.properties.email == 'something else'", "type": "hogql"}, + { + "key": "person.properties.email == 'something else'", + "type": "hogql", + }, ], } ] @@ -1656,21 +2010,33 @@ def test_any_event_filter_with_properties(self): self.create_event( "user", self.base_time, - properties={"$browser": "Chrome", "$session_id": page_view_session_id, "$window_id": "1"}, + properties={ + "$browser": "Chrome", + "$session_id": page_view_session_id, + "$window_id": "1", + }, event_name="$pageview", ) self.create_event( "user", self.base_time, - properties={"$browser": "Chrome", "$session_id": my_custom_event_session_id, "$window_id": "1"}, + properties={ + "$browser": "Chrome", + "$session_id": my_custom_event_session_id, + "$window_id": "1", + }, event_name="my-custom-event", ) self.create_event( "user", self.base_time, - properties={"$browser": "Safari", "$session_id": non_matching__event_session_id, "$window_id": "1"}, + properties={ + "$browser": "Safari", + "$session_id": non_matching__event_session_id, + "$window_id": "1", + }, event_name="my-non-matching-event", ) @@ -1727,7 +2093,14 @@ def test_any_event_filter_with_properties(self): "type": "events", "order": 0, "name": "All events", - "properties": [{"key": "$browser", "value": ["Chrome"], "operator": "exact", "type": "event"}], + "properties": [ + { + "key": "$browser", + "value": ["Chrome"], + "operator": "exact", + "type": "event", + } + ], } ] }, @@ -1749,7 +2122,14 @@ def test_any_event_filter_with_properties(self): "type": "events", "order": 0, "name": "All events", - "properties": [{"key": "$browser", "value": ["Firefox"], "operator": "exact", "type": "event"}], + "properties": [ + { + "key": "$browser", + "value": ["Firefox"], + "operator": "exact", + "type": "event", + } + ], } ] }, @@ -1990,7 +2370,14 @@ def test_filter_for_recordings_by_console_text(self): first_timestamp=self.base_time, team_id=self.team.id, console_log_count=4, - log_messages={"log": ["log message 1", "log message 2", "log message 3", "log message 4"]}, + log_messages={ + "log": [ + "log message 1", + "log message 2", + "log message 3", + "log message 4", + ] + }, ) produce_replay_summary( distinct_id="user", @@ -1999,7 +2386,13 @@ def test_filter_for_recordings_by_console_text(self): team_id=self.team.id, console_warn_count=5, log_messages={ - "warn": ["warn message 1", "warn message 2", "warn message 3", "warn message 4", "warn message 5"] + "warn": [ + "warn message 1", + "warn message 2", + "warn message 3", + "warn message 4", + "warn message 5", + ] }, ) produce_replay_summary( @@ -2008,7 +2401,14 @@ def test_filter_for_recordings_by_console_text(self): first_timestamp=self.base_time, team_id=self.team.id, console_error_count=4, - log_messages={"error": ["error message 1", "error message 2", "error message 3", "error message 4"]}, + log_messages={ + "error": [ + "error message 1", + "error message 2", + "error message 3", + "error message 4", + ] + }, ) produce_replay_summary( distinct_id="user", @@ -2018,7 +2418,12 @@ def test_filter_for_recordings_by_console_text(self): console_error_count=4, console_log_count=3, log_messages={ - "error": ["error message 1", "error message 2", "error message 3", "error message 4"], + "error": [ + "error message 1", + "error message 2", + "error message 3", + "error message 4", + ], "log": ["log message 1", "log message 2", "log message 3"], }, ) @@ -2026,7 +2431,10 @@ def test_filter_for_recordings_by_console_text(self): filter = SessionRecordingsFilter( team=self.team, # there are 5 warn and 4 error logs, message 4 matches in both - data={"console_logs": ["warn", "error"], "console_search_query": "message 4"}, + data={ + "console_logs": ["warn", "error"], + "console_search_query": "message 4", + }, ) session_recording_list_instance = SessionRecordingListFromReplaySummary(filter=filter, team=self.team) @@ -2043,7 +2451,10 @@ def test_filter_for_recordings_by_console_text(self): filter = SessionRecordingsFilter( team=self.team, # there are 5 warn and 4 error logs, message 5 matches only matches in warn - data={"console_logs": ["warn", "error"], "console_search_query": "message 5"}, + data={ + "console_logs": ["warn", "error"], + "console_search_query": "message 5", + }, ) session_recording_list_instance = SessionRecordingListFromReplaySummary(filter=filter, team=self.team) @@ -2058,7 +2469,10 @@ def test_filter_for_recordings_by_console_text(self): filter = SessionRecordingsFilter( team=self.team, # match is case-insensitive - data={"console_logs": ["warn", "error"], "console_search_query": "MESSAGE 5"}, + data={ + "console_logs": ["warn", "error"], + "console_search_query": "MESSAGE 5", + }, ) session_recording_list_instance = SessionRecordingListFromReplaySummary(filter=filter, team=self.team) @@ -2083,14 +2497,26 @@ def test_filter_for_recordings_by_console_text(self): assert sorted([sr["session_id"] for sr in session_recordings]) == sorted([]) @also_test_with_materialized_columns( - event_properties=["is_internal_user"], person_properties=["email"], verify_no_jsonextract=False + event_properties=["is_internal_user"], + person_properties=["email"], + verify_no_jsonextract=False, ) @freeze_time("2021-01-21T20:00:00.000Z") @snapshot_clickhouse_queries def test_event_filter_with_test_accounts_excluded(self): self.team.test_account_filters = [ - {"key": "email", "value": "@posthog.com", "operator": "not_icontains", "type": "person"}, - {"key": "is_internal_user", "value": ["false"], "operator": "exact", "type": "event"}, + { + "key": "email", + "value": "@posthog.com", + "operator": "not_icontains", + "type": "person", + }, + { + "key": "is_internal_user", + "value": ["false"], + "operator": "exact", + "type": "event", + }, {"key": "properties.$browser == 'Chrome'", "type": "hogql"}, ] self.team.save() @@ -2106,7 +2532,11 @@ def test_event_filter_with_test_accounts_excluded(self): self.create_event( "user", self.base_time, - properties={"$session_id": "1", "$window_id": "1", "is_internal_user": "true"}, + properties={ + "$session_id": "1", + "$window_id": "1", + "is_internal_user": "true", + }, ) produce_replay_summary( distinct_id="user", @@ -2118,7 +2548,14 @@ def test_event_filter_with_test_accounts_excluded(self): filter = SessionRecordingsFilter( team=self.team, data={ - "events": [{"id": "$pageview", "type": "events", "order": 0, "name": "$pageview"}], + "events": [ + { + "id": "$pageview", + "type": "events", + "order": 0, + "name": "$pageview", + } + ], "filter_test_accounts": True, }, ) @@ -2129,7 +2566,14 @@ def test_event_filter_with_test_accounts_excluded(self): filter = SessionRecordingsFilter( team=self.team, data={ - "events": [{"id": "$pageview", "type": "events", "order": 0, "name": "$pageview"}], + "events": [ + { + "id": "$pageview", + "type": "events", + "order": 0, + "name": "$pageview", + } + ], "filter_test_accounts": False, }, ) @@ -2138,7 +2582,9 @@ def test_event_filter_with_test_accounts_excluded(self): self.assertEqual(len(session_recordings), 1) @also_test_with_materialized_columns( - event_properties=["$browser"], person_properties=["email"], verify_no_jsonextract=False + event_properties=["$browser"], + person_properties=["email"], + verify_no_jsonextract=False, ) @freeze_time("2021-01-21T20:00:00.000Z") @snapshot_clickhouse_queries @@ -2149,7 +2595,11 @@ def test_event_filter_with_hogql_event_properties_test_accounts_excluded(self): self.team.save() Person.objects.create(team=self.team, distinct_ids=["user"], properties={"email": "bla"}) - Person.objects.create(team=self.team, distinct_ids=["user2"], properties={"email": "not-the-other-one"}) + Person.objects.create( + team=self.team, + distinct_ids=["user2"], + properties={"email": "not-the-other-one"}, + ) produce_replay_summary( distinct_id="user", @@ -2186,7 +2636,14 @@ def test_event_filter_with_hogql_event_properties_test_accounts_excluded(self): team=self.team, data={ # pageview that matches the hogql test_accounts filter - "events": [{"id": "$pageview", "type": "events", "order": 0, "name": "$pageview"}], + "events": [ + { + "id": "$pageview", + "type": "events", + "order": 0, + "name": "$pageview", + } + ], "filter_test_accounts": False, }, ) @@ -2203,7 +2660,14 @@ def test_event_filter_with_hogql_event_properties_test_accounts_excluded(self): team=self.team, data={ # only 1 pageview that matches the hogql test_accounts filter - "events": [{"id": "$pageview", "type": "events", "order": 0, "name": "$pageview"}], + "events": [ + { + "id": "$pageview", + "type": "events", + "order": 0, + "name": "$pageview", + } + ], "filter_test_accounts": True, }, ) @@ -2239,12 +2703,21 @@ def test_top_level_event_property_test_account_filter(self): The filter wasn't triggering the "should join events check", and so we didn't apply the filter at all """ self.team.test_account_filters = [ - {"key": "is_internal_user", "value": ["false"], "operator": "exact", "type": "event"}, + { + "key": "is_internal_user", + "value": ["false"], + "operator": "exact", + "type": "event", + }, ] self.team.save() Person.objects.create(team=self.team, distinct_ids=["user"], properties={"email": "bla"}) - Person.objects.create(team=self.team, distinct_ids=["user2"], properties={"email": "not-the-other-one"}) + Person.objects.create( + team=self.team, + distinct_ids=["user2"], + properties={"email": "not-the-other-one"}, + ) produce_replay_summary( distinct_id="user", @@ -2255,7 +2728,11 @@ def test_top_level_event_property_test_account_filter(self): self.create_event( "user", self.base_time, - properties={"$session_id": "1", "$window_id": "1", "is_internal_user": False}, + properties={ + "$session_id": "1", + "$window_id": "1", + "is_internal_user": False, + }, ) produce_replay_summary( distinct_id="user", @@ -2273,7 +2750,11 @@ def test_top_level_event_property_test_account_filter(self): self.create_event( "user2", self.base_time, - properties={"$session_id": "2", "$window_id": "1", "is_internal_user": True}, + properties={ + "$session_id": "2", + "$window_id": "1", + "is_internal_user": True, + }, ) # there are 2 pageviews @@ -2281,7 +2762,14 @@ def test_top_level_event_property_test_account_filter(self): team=self.team, data={ # pageview that matches the hogql test_accounts filter - "events": [{"id": "$pageview", "type": "events", "order": 0, "name": "$pageview"}], + "events": [ + { + "id": "$pageview", + "type": "events", + "order": 0, + "name": "$pageview", + } + ], "filter_test_accounts": False, }, ) @@ -2316,7 +2804,11 @@ def test_top_level_hogql_event_property_test_account_filter(self): self.team.save() Person.objects.create(team=self.team, distinct_ids=["user"], properties={"email": "bla"}) - Person.objects.create(team=self.team, distinct_ids=["user2"], properties={"email": "not-the-other-one"}) + Person.objects.create( + team=self.team, + distinct_ids=["user2"], + properties={"email": "not-the-other-one"}, + ) produce_replay_summary( distinct_id="user", @@ -2327,7 +2819,11 @@ def test_top_level_hogql_event_property_test_account_filter(self): self.create_event( "user", self.base_time, - properties={"$session_id": "1", "$window_id": "1", "is_internal_user": False}, + properties={ + "$session_id": "1", + "$window_id": "1", + "is_internal_user": False, + }, ) produce_replay_summary( distinct_id="user", @@ -2345,7 +2841,11 @@ def test_top_level_hogql_event_property_test_account_filter(self): self.create_event( "user2", self.base_time, - properties={"$session_id": "2", "$window_id": "1", "is_internal_user": True}, + properties={ + "$session_id": "2", + "$window_id": "1", + "is_internal_user": True, + }, ) # there are 2 pageviews @@ -2353,7 +2853,14 @@ def test_top_level_hogql_event_property_test_account_filter(self): team=self.team, data={ # pageview that matches the hogql test_accounts filter - "events": [{"id": "$pageview", "type": "events", "order": 0, "name": "$pageview"}], + "events": [ + { + "id": "$pageview", + "type": "events", + "order": 0, + "name": "$pageview", + } + ], "filter_test_accounts": False, }, ) @@ -2388,7 +2895,11 @@ def test_top_level_hogql_person_property_test_account_filter(self): self.team.save() Person.objects.create(team=self.team, distinct_ids=["user"], properties={"email": "bla"}) - Person.objects.create(team=self.team, distinct_ids=["user2"], properties={"email": "not-the-other-one"}) + Person.objects.create( + team=self.team, + distinct_ids=["user2"], + properties={"email": "not-the-other-one"}, + ) produce_replay_summary( distinct_id="user", @@ -2399,7 +2910,11 @@ def test_top_level_hogql_person_property_test_account_filter(self): self.create_event( "user", self.base_time, - properties={"$session_id": "1", "$window_id": "1", "is_internal_user": False}, + properties={ + "$session_id": "1", + "$window_id": "1", + "is_internal_user": False, + }, ) produce_replay_summary( distinct_id="user", @@ -2417,7 +2932,11 @@ def test_top_level_hogql_person_property_test_account_filter(self): self.create_event( "user2", self.base_time, - properties={"$session_id": "2", "$window_id": "1", "is_internal_user": True}, + properties={ + "$session_id": "2", + "$window_id": "1", + "is_internal_user": True, + }, ) # there are 2 pageviews @@ -2425,7 +2944,14 @@ def test_top_level_hogql_person_property_test_account_filter(self): team=self.team, data={ # pageview that matches the hogql test_accounts filter - "events": [{"id": "$pageview", "type": "events", "order": 0, "name": "$pageview"}], + "events": [ + { + "id": "$pageview", + "type": "events", + "order": 0, + "name": "$pageview", + } + ], "filter_test_accounts": False, }, ) @@ -2458,7 +2984,11 @@ def test_top_level_person_property_test_account_filter(self): self.team.save() Person.objects.create(team=self.team, distinct_ids=["user"], properties={"email": "bla"}) - Person.objects.create(team=self.team, distinct_ids=["user2"], properties={"email": "not-the-other-one"}) + Person.objects.create( + team=self.team, + distinct_ids=["user2"], + properties={"email": "not-the-other-one"}, + ) produce_replay_summary( distinct_id="user", @@ -2469,7 +2999,11 @@ def test_top_level_person_property_test_account_filter(self): self.create_event( "user", self.base_time, - properties={"$session_id": "1", "$window_id": "1", "is_internal_user": False}, + properties={ + "$session_id": "1", + "$window_id": "1", + "is_internal_user": False, + }, ) produce_replay_summary( distinct_id="user", @@ -2487,7 +3021,11 @@ def test_top_level_person_property_test_account_filter(self): self.create_event( "user2", self.base_time, - properties={"$session_id": "2", "$window_id": "1", "is_internal_user": True}, + properties={ + "$session_id": "2", + "$window_id": "1", + "is_internal_user": True, + }, ) # there are 2 pageviews @@ -2495,7 +3033,14 @@ def test_top_level_person_property_test_account_filter(self): team=self.team, data={ # pageview that matches the hogql test_accounts filter - "events": [{"id": "$pageview", "type": "events", "order": 0, "name": "$pageview"}], + "events": [ + { + "id": "$pageview", + "type": "events", + "order": 0, + "name": "$pageview", + } + ], "filter_test_accounts": False, }, ) @@ -2531,8 +3076,18 @@ def test_event_filter_with_two_events_and_multiple_teams(self): team=self.team, data={ "events": [ - {"id": "$pageview", "type": "events", "order": 0, "name": "$pageview"}, - {"id": "$pageleave", "type": "events", "order": 0, "name": "$pageleave"}, + { + "id": "$pageview", + "type": "events", + "order": 0, + "name": "$pageview", + }, + { + "id": "$pageleave", + "type": "events", + "order": 0, + "name": "$pageleave", + }, ], }, ) @@ -2585,11 +3140,19 @@ def test_event_filter_with_group_filter(self): GroupTypeMapping.objects.create(team=self.team, group_type="project", group_type_index=0) create_group( - team_id=self.team.pk, group_type_index=0, group_key="project:1", properties={"name": "project one"} + team_id=self.team.pk, + group_type_index=0, + group_key="project:1", + properties={"name": "project one"}, ) GroupTypeMapping.objects.create(team=self.team, group_type="organization", group_type_index=1) - create_group(team_id=self.team.pk, group_type_index=1, group_key="org:1", properties={"name": "org one"}) + create_group( + team_id=self.team.pk, + group_type_index=1, + group_key="org:1", + properties={"name": "org one"}, + ) self.create_event( "user", diff --git a/posthog/session_recordings/queries/test/test_session_recording_properties.py b/posthog/session_recordings/queries/test/test_session_recording_properties.py index 9844d77006721..aa152b0b2fa16 100644 --- a/posthog/session_recordings/queries/test/test_session_recording_properties.py +++ b/posthog/session_recordings/queries/test/test_session_recording_properties.py @@ -4,9 +4,18 @@ from posthog.models import Person from posthog.models.filters.session_recordings_filter import SessionRecordingsFilter -from posthog.session_recordings.queries.session_recording_properties import SessionRecordingProperties -from posthog.session_recordings.queries.test.session_replay_sql import produce_replay_summary -from posthog.test.base import BaseTest, ClickhouseTestMixin, _create_event, snapshot_clickhouse_queries +from posthog.session_recordings.queries.session_recording_properties import ( + SessionRecordingProperties, +) +from posthog.session_recordings.queries.test.session_replay_sql import ( + produce_replay_summary, +) +from posthog.test.base import ( + BaseTest, + ClickhouseTestMixin, + _create_event, + snapshot_clickhouse_queries, +) class TestSessionRecordingProperties(BaseTest, ClickhouseTestMixin): @@ -20,7 +29,13 @@ def create_event( ): if team is None: team = self.team - _create_event(team=team, event=event_name, timestamp=timestamp, distinct_id=distinct_id, properties=properties) + _create_event( + team=team, + event=event_name, + timestamp=timestamp, + distinct_id=distinct_id, + properties=properties, + ) @property def base_time(self): @@ -77,7 +92,10 @@ def test_properties_list(self): self.assertEqual(session_recordings_properties[0]["properties"]["$browser"], "Chrome") self.assertEqual(session_recordings_properties[0]["properties"]["$os"], "Mac OS X") self.assertEqual(session_recordings_properties[0]["properties"]["$device_type"], "Desktop") - self.assertEqual(session_recordings_properties[0]["properties"]["$current_url"], "https://blah.com/blah") + self.assertEqual( + session_recordings_properties[0]["properties"]["$current_url"], + "https://blah.com/blah", + ) self.assertEqual(session_recordings_properties[0]["properties"]["$host"], "blah.com") self.assertEqual(session_recordings_properties[0]["properties"]["$pathname"], "/blah") self.assertEqual(session_recordings_properties[0]["properties"]["$geoip_country_code"], "KR") diff --git a/posthog/session_recordings/queries/test/test_session_replay_events.py b/posthog/session_recordings/queries/test/test_session_replay_events.py index bbdec4ea0cc3e..04393f8500c07 100644 --- a/posthog/session_recordings/queries/test/test_session_replay_events.py +++ b/posthog/session_recordings/queries/test/test_session_replay_events.py @@ -1,6 +1,8 @@ from posthog.models import Team from posthog.session_recordings.queries.session_replay_events import SessionReplayEvents -from posthog.session_recordings.queries.test.session_replay_sql import produce_replay_summary +from posthog.session_recordings.queries.test.session_replay_sql import ( + produce_replay_summary, +) from posthog.test.base import ClickhouseTestMixin, APIBaseTest from dateutil.relativedelta import relativedelta from django.utils.timezone import now @@ -63,6 +65,8 @@ def test_get_metadata_does_not_leak_between_teams(self) -> None: def test_get_metadata_filters_by_date(self) -> None: metadata = SessionReplayEvents().get_metadata( - session_id="1", team=self.team, recording_start_time=self.base_time + relativedelta(days=2) + session_id="1", + team=self.team, + recording_start_time=self.base_time + relativedelta(days=2), ) assert metadata is None diff --git a/posthog/session_recordings/queries/test/test_session_replay_summaries.py b/posthog/session_recordings/queries/test/test_session_replay_summaries.py index 5a1e9b94db842..6d3376d467ae6 100644 --- a/posthog/session_recordings/queries/test/test_session_replay_summaries.py +++ b/posthog/session_recordings/queries/test/test_session_replay_summaries.py @@ -9,7 +9,9 @@ from posthog.models import Team from posthog.models.event.util import format_clickhouse_timestamp from posthog.queries.app_metrics.serializers import AppMetricsRequestSerializer -from posthog.session_recordings.queries.test.session_replay_sql import produce_replay_summary +from posthog.session_recordings.queries.test.session_replay_sql import ( + produce_replay_summary, +) from posthog.test.base import BaseTest, ClickhouseTestMixin, snapshot_clickhouse_queries diff --git a/posthog/session_recordings/realtime_snapshots.py b/posthog/session_recordings/realtime_snapshots.py index 20e8a0846440c..e1191c4ddb37e 100644 --- a/posthog/session_recordings/realtime_snapshots.py +++ b/posthog/session_recordings/realtime_snapshots.py @@ -40,7 +40,10 @@ def get_realtime_snapshots(team_id: str, session_id: str, attempt_count=0) -> Op # We always publish as it could be that a rebalance has occured and the consumer doesn't know it should be # sending data to redis - redis.publish(SUBSCRIPTION_CHANNEL, json.dumps({"team_id": team_id, "session_id": session_id})) + redis.publish( + SUBSCRIPTION_CHANNEL, + json.dumps({"team_id": team_id, "session_id": session_id}), + ) if not encoded_snapshots and attempt_count < ATTEMPT_MAX: logger.info( @@ -50,7 +53,10 @@ def get_realtime_snapshots(team_id: str, session_id: str, attempt_count=0) -> Op attempt_count=attempt_count, ) # If we don't have it we could be in the process of getting it and syncing it - redis.publish(SUBSCRIPTION_CHANNEL, json.dumps({"team_id": team_id, "session_id": session_id})) + redis.publish( + SUBSCRIPTION_CHANNEL, + json.dumps({"team_id": team_id, "session_id": session_id}), + ) PUBLISHED_REALTIME_SUBSCRIPTIONS_COUNTER.labels( team_id=team_id, session_id=session_id, attempt_count=attempt_count ).inc() @@ -73,7 +79,10 @@ def get_realtime_snapshots(team_id: str, session_id: str, attempt_count=0) -> Op # very broad capture to see if there are any unexpected errors capture_exception( e, - extras={"attempt_count": attempt_count, "operation": "get_realtime_snapshots"}, + extras={ + "attempt_count": attempt_count, + "operation": "get_realtime_snapshots", + }, tags={"team_id": team_id, "session_id": session_id}, ) raise e diff --git a/posthog/session_recordings/session_recording_api.py b/posthog/session_recordings/session_recording_api.py index 827703006340c..6996d2c990460 100644 --- a/posthog/session_recordings/session_recording_api.py +++ b/posthog/session_recordings/session_recording_api.py @@ -29,17 +29,26 @@ SharingTokenPermission, TeamMemberAccessPermission, ) -from posthog.session_recordings.models.session_recording_event import SessionRecordingViewed +from posthog.session_recordings.models.session_recording_event import ( + SessionRecordingViewed, +) from posthog.session_recordings.queries.session_recording_list_from_replay_summary import ( SessionRecordingListFromReplaySummary, SessionIdEventsQuery, ) -from posthog.session_recordings.queries.session_recording_properties import SessionRecordingProperties -from posthog.rate_limit import ClickHouseBurstRateThrottle, ClickHouseSustainedRateThrottle +from posthog.session_recordings.queries.session_recording_properties import ( + SessionRecordingProperties, +) +from posthog.rate_limit import ( + ClickHouseBurstRateThrottle, + ClickHouseSustainedRateThrottle, +) from posthog.session_recordings.queries.session_replay_events import SessionReplayEvents from posthog.session_recordings.realtime_snapshots import get_realtime_snapshots -from posthog.session_recordings.snapshots.convert_legacy_snapshots import convert_original_version_lts_recording +from posthog.session_recordings.snapshots.convert_legacy_snapshots import ( + convert_original_version_lts_recording, +) from posthog.storage import object_storage from prometheus_client import Counter @@ -130,7 +139,11 @@ class SessionRecordingSnapshotsSerializer(serializers.Serializer): class SessionRecordingViewSet(StructuredViewSetMixin, viewsets.GenericViewSet): - permission_classes = [IsAuthenticated, ProjectMembershipNecessaryPermissions, TeamMemberAccessPermission] + permission_classes = [ + IsAuthenticated, + ProjectMembershipNecessaryPermissions, + TeamMemberAccessPermission, + ] throttle_classes = [ClickHouseBurstRateThrottle, ClickHouseSustainedRateThrottle] serializer_class = SessionRecordingSerializer # We don't use this @@ -269,7 +282,9 @@ def snapshots(self, request: request.Request, **kwargs): event_properties["$session_id"] = request.headers["X-POSTHOG-SESSION-ID"] posthoganalytics.capture( - self._distinct_id_from_request(request), "v2 session recording snapshots viewed", event_properties + self._distinct_id_from_request(request), + "v2 session recording snapshots viewed", + event_properties, ) if source: @@ -338,7 +353,9 @@ def snapshots(self, request: request.Request, **kwargs): event_properties["source"] = "realtime" event_properties["snapshots_length"] = len(snapshots) posthoganalytics.capture( - self._distinct_id_from_request(request), "session recording snapshots v2 loaded", event_properties + self._distinct_id_from_request(request), + "session recording snapshots v2 loaded", + event_properties, ) response_data["snapshots"] = snapshots @@ -366,7 +383,9 @@ def snapshots(self, request: request.Request, **kwargs): event_properties["source"] = "blob" event_properties["blob_key"] = blob_key posthoganalytics.capture( - self._distinct_id_from_request(request), "session recording snapshots v2 loaded", event_properties + self._distinct_id_from_request(request), + "session recording snapshots v2 loaded", + event_properties, ) with requests.get(url=url, stream=True) as r: @@ -451,9 +470,10 @@ def list_recordings(filter: SessionRecordingsFilter, request: request.Request, c if (all_session_ids and filter.session_ids) or not all_session_ids: # Only go to clickhouse if we still have remaining specified IDs, or we are not specifying IDs - (ch_session_recordings, more_recordings_available) = SessionRecordingListFromReplaySummary( - filter=filter, team=team - ).run() + ( + ch_session_recordings, + more_recordings_available, + ) = SessionRecordingListFromReplaySummary(filter=filter, team=team).run() recordings_from_clickhouse = SessionRecording.get_or_build_from_clickhouse(team, ch_session_recordings) recordings = recordings + recordings_from_clickhouse @@ -462,7 +482,10 @@ def list_recordings(filter: SessionRecordingsFilter, request: request.Request, c # If we have specified session_ids we need to sort them by the order they were specified if all_session_ids: - recordings = sorted(recordings, key=lambda x: cast(List[str], all_session_ids).index(x.session_id)) + recordings = sorted( + recordings, + key=lambda x: cast(List[str], all_session_ids).index(x.session_id), + ) if not request.user.is_authenticated: # for mypy raise exceptions.NotAuthenticated() diff --git a/posthog/session_recordings/snapshots/convert_legacy_snapshots.py b/posthog/session_recordings/snapshots/convert_legacy_snapshots.py index a60e1b74717e0..963016d0e869a 100644 --- a/posthog/session_recordings/snapshots/convert_legacy_snapshots.py +++ b/posthog/session_recordings/snapshots/convert_legacy_snapshots.py @@ -18,12 +18,17 @@ def _save_converted_content_back_to_storage(converted_content: str, recording: SessionRecording) -> str: try: - from ee.session_recordings.session_recording_extensions import save_recording_with_new_content + from ee.session_recordings.session_recording_extensions import ( + save_recording_with_new_content, + ) return save_recording_with_new_content(recording, converted_content) except ImportError: # not running in EE context... shouldn't get here - logger.error("attempted_to_save_converted_content_back_to_storage_in_non_ee_context", recording_id=recording.id) + logger.error( + "attempted_to_save_converted_content_back_to_storage_in_non_ee_context", + recording_id=recording.id, + ) return "" diff --git a/posthog/session_recordings/sql/session_recording_event_sql.py b/posthog/session_recordings/sql/session_recording_event_sql.py index 908b4b4034ddd..fc52f27fbdae8 100644 --- a/posthog/session_recordings/sql/session_recording_event_sql.py +++ b/posthog/session_recordings/sql/session_recording_event_sql.py @@ -2,7 +2,11 @@ from posthog.clickhouse.indexes import index_by_kafka_timestamp from posthog.clickhouse.kafka_engine import KAFKA_COLUMNS, kafka_engine, ttl_period -from posthog.clickhouse.table_engines import Distributed, ReplacingMergeTree, ReplicationScheme +from posthog.clickhouse.table_engines import ( + Distributed, + ReplacingMergeTree, + ReplicationScheme, +) from posthog.kafka_client.topics import KAFKA_CLICKHOUSE_SESSION_RECORDING_EVENTS SESSION_RECORDING_EVENTS_DATA_TABLE = lambda: "sharded_session_recording_events" @@ -72,7 +76,9 @@ SESSION_RECORDING_EVENTS_DATA_TABLE_ENGINE = lambda: ReplacingMergeTree( - "session_recording_events", ver="_timestamp", replication_scheme=ReplicationScheme.SHARDED + "session_recording_events", + ver="_timestamp", + replication_scheme=ReplicationScheme.SHARDED, ) SESSION_RECORDING_EVENTS_TABLE_SQL = lambda: ( SESSION_RECORDING_EVENTS_TABLE_BASE_SQL @@ -129,7 +135,10 @@ WRITABLE_SESSION_RECORDING_EVENTS_TABLE_SQL = lambda: SESSION_RECORDING_EVENTS_TABLE_BASE_SQL.format( table_name="writable_session_recording_events", cluster=settings.CLICKHOUSE_CLUSTER, - engine=Distributed(data_table=SESSION_RECORDING_EVENTS_DATA_TABLE(), sharding_key="sipHash64(distinct_id)"), + engine=Distributed( + data_table=SESSION_RECORDING_EVENTS_DATA_TABLE(), + sharding_key="sipHash64(distinct_id)", + ), extra_fields=KAFKA_COLUMNS, materialized_columns="", ) @@ -138,7 +147,10 @@ DISTRIBUTED_SESSION_RECORDING_EVENTS_TABLE_SQL = lambda: SESSION_RECORDING_EVENTS_TABLE_BASE_SQL.format( table_name="session_recording_events", cluster=settings.CLICKHOUSE_CLUSTER, - engine=Distributed(data_table=SESSION_RECORDING_EVENTS_DATA_TABLE(), sharding_key="sipHash64(distinct_id)"), + engine=Distributed( + data_table=SESSION_RECORDING_EVENTS_DATA_TABLE(), + sharding_key="sipHash64(distinct_id)", + ), extra_fields=KAFKA_COLUMNS, materialized_columns=SESSION_RECORDING_EVENTS_PROXY_MATERIALIZED_COLUMNS, ) diff --git a/posthog/session_recordings/sql/session_replay_event_migrations_sql.py b/posthog/session_recordings/sql/session_replay_event_migrations_sql.py index ac897fccc1d08..dcf8e5abd809d 100644 --- a/posthog/session_recordings/sql/session_replay_event_migrations_sql.py +++ b/posthog/session_recordings/sql/session_replay_event_migrations_sql.py @@ -1,6 +1,8 @@ from django.conf import settings -from posthog.session_recordings.sql.session_replay_event_sql import SESSION_REPLAY_EVENTS_DATA_TABLE +from posthog.session_recordings.sql.session_replay_event_sql import ( + SESSION_REPLAY_EVENTS_DATA_TABLE, +) DROP_SESSION_REPLAY_EVENTS_TABLE_MV_SQL = ( lambda: "DROP TABLE IF EXISTS session_replay_events_mv ON CLUSTER {cluster}".format( diff --git a/posthog/session_recordings/sql/session_replay_event_sql.py b/posthog/session_recordings/sql/session_replay_event_sql.py index dfe839843979f..e7c2576e93f66 100644 --- a/posthog/session_recordings/sql/session_replay_event_sql.py +++ b/posthog/session_recordings/sql/session_replay_event_sql.py @@ -1,7 +1,11 @@ from django.conf import settings from posthog.clickhouse.kafka_engine import kafka_engine -from posthog.clickhouse.table_engines import Distributed, ReplicationScheme, AggregatingMergeTree +from posthog.clickhouse.table_engines import ( + Distributed, + ReplicationScheme, + AggregatingMergeTree, +) from posthog.kafka_client.topics import KAFKA_CLICKHOUSE_SESSION_REPLAY_EVENTS SESSION_REPLAY_EVENTS_DATA_TABLE = lambda: "sharded_session_replay_events" @@ -147,7 +151,10 @@ WRITABLE_SESSION_REPLAY_EVENTS_TABLE_SQL = lambda: SESSION_REPLAY_EVENTS_TABLE_BASE_SQL.format( table_name="writable_session_replay_events", cluster=settings.CLICKHOUSE_CLUSTER, - engine=Distributed(data_table=SESSION_REPLAY_EVENTS_DATA_TABLE(), sharding_key="sipHash64(distinct_id)"), + engine=Distributed( + data_table=SESSION_REPLAY_EVENTS_DATA_TABLE(), + sharding_key="sipHash64(distinct_id)", + ), ) @@ -155,7 +162,10 @@ DISTRIBUTED_SESSION_REPLAY_EVENTS_TABLE_SQL = lambda: SESSION_REPLAY_EVENTS_TABLE_BASE_SQL.format( table_name="session_replay_events", cluster=settings.CLICKHOUSE_CLUSTER, - engine=Distributed(data_table=SESSION_REPLAY_EVENTS_DATA_TABLE(), sharding_key="sipHash64(distinct_id)"), + engine=Distributed( + data_table=SESSION_REPLAY_EVENTS_DATA_TABLE(), + sharding_key="sipHash64(distinct_id)", + ), ) diff --git a/posthog/session_recordings/test/test_lts_session_recordings.py b/posthog/session_recordings/test/test_lts_session_recordings.py index b16d873b93d7b..e7de94464c18f 100644 --- a/posthog/session_recordings/test/test_lts_session_recordings.py +++ b/posthog/session_recordings/test/test_lts_session_recordings.py @@ -19,7 +19,10 @@ def setUp(self): # Create a new team each time to ensure no clashing between tests self.team = Team.objects.create(organization=self.organization, name="New Team") - @patch("posthog.session_recordings.queries.session_replay_events.SessionReplayEvents.exists", return_value=True) + @patch( + "posthog.session_recordings.queries.session_replay_events.SessionReplayEvents.exists", + return_value=True, + ) @patch("posthog.session_recordings.session_recording_api.object_storage.list_objects") def test_2023_08_01_version_stored_snapshots_can_be_gathered( self, mock_list_objects: MagicMock, _mock_exists: MagicMock @@ -72,7 +75,10 @@ def list_objects_func(path: str) -> List[str]: ], } - @patch("posthog.session_recordings.queries.session_replay_events.SessionReplayEvents.exists", return_value=True) + @patch( + "posthog.session_recordings.queries.session_replay_events.SessionReplayEvents.exists", + return_value=True, + ) @patch("posthog.session_recordings.session_recording_api.object_storage.list_objects") def test_original_version_stored_snapshots_can_be_gathered( self, mock_list_objects: MagicMock, _mock_exists: MagicMock @@ -112,7 +118,10 @@ def list_objects_func(path: str) -> List[str]: ], } - @patch("posthog.session_recordings.queries.session_replay_events.SessionReplayEvents.exists", return_value=True) + @patch( + "posthog.session_recordings.queries.session_replay_events.SessionReplayEvents.exists", + return_value=True, + ) @patch("posthog.session_recordings.session_recording_api.requests.get") @patch("posthog.session_recordings.session_recording_api.object_storage.get_presigned_url") @patch("posthog.session_recordings.session_recording_api.object_storage.list_objects") @@ -173,7 +182,10 @@ def list_objects_func(path: str) -> List[str]: assert response_data == "the file contents" - @patch("posthog.session_recordings.queries.session_replay_events.SessionReplayEvents.exists", return_value=True) + @patch( + "posthog.session_recordings.queries.session_replay_events.SessionReplayEvents.exists", + return_value=True, + ) @patch("posthog.session_recordings.session_recording_api.requests.get") @patch("posthog.session_recordings.session_recording_api.object_storage.tag") @patch("posthog.session_recordings.session_recording_api.object_storage.write") diff --git a/posthog/session_recordings/test/test_session_recording_helpers.py b/posthog/session_recordings/test/test_session_recording_helpers.py index 6c64d84efaf78..d59cf816dbf83 100644 --- a/posthog/session_recordings/test/test_session_recording_helpers.py +++ b/posthog/session_recordings/test/test_session_recording_helpers.py @@ -244,14 +244,20 @@ def test_new_ingestion_large_full_snapshot_is_separated(raw_snapshot_events, moc "distinct_id": "abc123", "$session_id": "1234", "$window_id": "1", - "$snapshot_items": [{"type": 3, "timestamp": 1546300800000}, {"type": 3, "timestamp": 1546300800000}], + "$snapshot_items": [ + {"type": 3, "timestamp": 1546300800000}, + {"type": 3, "timestamp": 1546300800000}, + ], }, }, ] def test_new_ingestion_large_non_full_snapshots_are_separated(raw_snapshot_events, mocker: MockerFixture): - mocker.patch("posthog.models.utils.UUIDT", return_value="0178495e-8521-0000-8e1c-2652fa57099b") + mocker.patch( + "posthog.models.utils.UUIDT", + return_value="0178495e-8521-0000-8e1c-2652fa57099b", + ) mocker.patch("time.time", return_value=0) almost_too_big_payloads = [ @@ -265,7 +271,11 @@ def test_new_ingestion_large_non_full_snapshots_are_separated(raw_snapshot_event "properties": { "$session_id": "1234", "$window_id": "1", - "$snapshot_data": {"type": 7, "timestamp": 234, "something": almost_too_big_payloads[0]}, + "$snapshot_data": { + "type": 7, + "timestamp": 234, + "something": almost_too_big_payloads[0], + }, "distinct_id": "abc123", }, }, @@ -274,7 +284,11 @@ def test_new_ingestion_large_non_full_snapshots_are_separated(raw_snapshot_event "properties": { "$session_id": "1234", "$window_id": "1", - "$snapshot_data": {"type": 8, "timestamp": 123, "something": almost_too_big_payloads[1]}, + "$snapshot_data": { + "type": 8, + "timestamp": 123, + "something": almost_too_big_payloads[1], + }, "distinct_id": "abc123", }, }, @@ -285,7 +299,13 @@ def test_new_ingestion_large_non_full_snapshots_are_separated(raw_snapshot_event "properties": { "$session_id": "1234", "$window_id": "1", - "$snapshot_items": [{"type": 7, "timestamp": 234, "something": almost_too_big_payloads[0]}], + "$snapshot_items": [ + { + "type": 7, + "timestamp": 234, + "something": almost_too_big_payloads[0], + } + ], "distinct_id": "abc123", }, }, @@ -294,7 +314,13 @@ def test_new_ingestion_large_non_full_snapshots_are_separated(raw_snapshot_event "properties": { "$session_id": "1234", "$window_id": "1", - "$snapshot_items": [{"type": 8, "timestamp": 123, "something": almost_too_big_payloads[1]}], + "$snapshot_items": [ + { + "type": 8, + "timestamp": 123, + "something": almost_too_big_payloads[1], + } + ], "distinct_id": "abc123", }, }, @@ -302,7 +328,10 @@ def test_new_ingestion_large_non_full_snapshots_are_separated(raw_snapshot_event def test_new_ingestion_groups_using_snapshot_bytes_if_possible(raw_snapshot_events, mocker: MockerFixture): - mocker.patch("posthog.models.utils.UUIDT", return_value="0178495e-8521-0000-8e1c-2652fa57099b") + mocker.patch( + "posthog.models.utils.UUIDT", + return_value="0178495e-8521-0000-8e1c-2652fa57099b", + ) mocker.patch("time.time", return_value=0) almost_too_big_event = { @@ -350,7 +379,11 @@ def test_new_ingestion_groups_using_snapshot_bytes_if_possible(raw_snapshot_even }, ] - assert [event["properties"]["$snapshot_bytes"] for event in events] == [106, 1072, 159] + assert [event["properties"]["$snapshot_bytes"] for event in events] == [ + 106, + 1072, + 159, + ] space_with_headroom = math.ceil((106 + 1072 + 50) * 1.05) assert list(mock_capture_flow(events, max_size_bytes=space_with_headroom)[1]) == [ diff --git a/posthog/session_recordings/test/test_session_recordings.py b/posthog/session_recordings/test/test_session_recordings.py index 61c05d993ee4a..3dca9b46b9fb2 100644 --- a/posthog/session_recordings/test/test_session_recordings.py +++ b/posthog/session_recordings/test/test_session_recordings.py @@ -12,13 +12,17 @@ from freezegun import freeze_time from rest_framework import status -from posthog.session_recordings.models.session_recording_event import SessionRecordingViewed +from posthog.session_recordings.models.session_recording_event import ( + SessionRecordingViewed, +) from posthog.api.test.test_team import create_team from posthog.constants import SESSION_RECORDINGS_FILTER_IDS from posthog.models import Organization, Person, SessionRecording from posthog.models.filters.session_recordings_filter import SessionRecordingsFilter from posthog.models.team import Team -from posthog.session_recordings.queries.test.session_replay_sql import produce_replay_summary +from posthog.session_recordings.queries.test.session_replay_sql import ( + produce_replay_summary, +) from posthog.test.base import ( APIBaseTest, ClickhouseTestMixin, @@ -122,10 +126,14 @@ def create_snapshots( def test_get_session_recordings(self): user = Person.objects.create( - team=self.team, distinct_ids=["user"], properties={"$some_prop": "something", "email": "bob@bob.com"} + team=self.team, + distinct_ids=["user"], + properties={"$some_prop": "something", "email": "bob@bob.com"}, ) user2 = Person.objects.create( - team=self.team, distinct_ids=["user2"], properties={"$some_prop": "something", "email": "bob@bob.com"} + team=self.team, + distinct_ids=["user2"], + properties={"$some_prop": "something", "email": "bob@bob.com"}, ) base_time = (now() - relativedelta(days=1)).replace(microsecond=0) session_id_one = f"test_get_session_recordings-1-{uuid.uuid4()}" @@ -160,7 +168,15 @@ def test_get_session_recordings(self): False, user2.pk, ), - (session_id_one, "user", base_time, base_time + relativedelta(seconds=30), 30, False, user.pk), + ( + session_id_one, + "user", + base_time, + base_time + relativedelta(seconds=30), + 30, + False, + user.pk, + ), ] @patch("posthog.session_recordings.session_recording_api.SessionRecordingListFromReplaySummary") @@ -170,7 +186,7 @@ def test_console_log_filters_are_correctly_passed_to_listing(self, mock_summary_ self.client.get(f'/api/projects/{self.team.id}/session_recordings?console_logs=["warn", "error"]') assert len(mock_summary_lister.call_args_list) == 1 - filter_passed_to_mock: SessionRecordingsFilter = mock_summary_lister.call_args_list[0].kwargs["filter"] + filter_passed_to_mock: (SessionRecordingsFilter) = mock_summary_lister.call_args_list[0].kwargs["filter"] assert filter_passed_to_mock.console_logs_filter == ["warn", "error"] @snapshot_postgres_queries @@ -194,7 +210,9 @@ def test_listing_recordings_is_not_nplus1_for_persons(self): def _person_with_snapshots(self, base_time: datetime, distinct_id: str = "user", session_id: str = "1") -> None: Person.objects.create( - team=self.team, distinct_ids=[distinct_id], properties={"$some_prop": "something", "email": "bob@bob.com"} + team=self.team, + distinct_ids=[distinct_id], + properties={"$some_prop": "something", "email": "bob@bob.com"}, ) self.create_snapshot(distinct_id, session_id, base_time) self.create_snapshot(distinct_id, session_id, base_time + relativedelta(seconds=10)) @@ -203,10 +221,14 @@ def _person_with_snapshots(self, base_time: datetime, distinct_id: str = "user", def test_session_recordings_dont_leak_teams(self) -> None: another_team = Team.objects.create(organization=self.organization) Person.objects.create( - team=another_team, distinct_ids=["user"], properties={"$some_prop": "something", "email": "bob@bob.com"} + team=another_team, + distinct_ids=["user"], + properties={"$some_prop": "something", "email": "bob@bob.com"}, ) Person.objects.create( - team=self.team, distinct_ids=["user"], properties={"$some_prop": "something", "email": "bob@bob.com"} + team=self.team, + distinct_ids=["user"], + properties={"$some_prop": "something", "email": "bob@bob.com"}, ) base_time = (now() - relativedelta(days=1)).replace(microsecond=0) @@ -236,7 +258,9 @@ def test_session_recording_for_user_with_multiple_distinct_ids(self) -> None: def test_viewed_state_of_session_recording_version_1(self): Person.objects.create( - team=self.team, distinct_ids=["u1"], properties={"$some_prop": "something", "email": "bob@bob.com"} + team=self.team, + distinct_ids=["u1"], + properties={"$some_prop": "something", "email": "bob@bob.com"}, ) base_time = (now() - timedelta(days=1)).replace(microsecond=0) SessionRecordingViewed.objects.create(team=self.team, user=self.user, session_id="1") @@ -252,7 +276,9 @@ def test_viewed_state_of_session_recording_version_1(self): def test_viewed_state_of_session_recording_version_3(self): Person.objects.create( - team=self.team, distinct_ids=["u1"], properties={"$some_prop": "something", "email": "bob@bob.com"} + team=self.team, + distinct_ids=["u1"], + properties={"$some_prop": "something", "email": "bob@bob.com"}, ) base_time = (now() - timedelta(days=1)).replace(microsecond=0) session_id_one = "1" @@ -272,7 +298,9 @@ def test_viewed_state_of_session_recording_version_3(self): def test_setting_viewed_state_of_session_recording(self): Person.objects.create( - team=self.team, distinct_ids=["u1"], properties={"$some_prop": "something", "email": "bob@bob.com"} + team=self.team, + distinct_ids=["u1"], + properties={"$some_prop": "something", "email": "bob@bob.com"}, ) base_time = (now() - relativedelta(days=1)).replace(microsecond=0) @@ -326,7 +354,9 @@ def test_setting_viewed_state_of_session_recording(self): def test_get_single_session_recording_metadata(self): with freeze_time("2023-01-01T12:00:00.000Z"): p = Person.objects.create( - team=self.team, distinct_ids=["d1"], properties={"$some_prop": "something", "email": "bob@bob.com"} + team=self.team, + distinct_ids=["d1"], + properties={"$some_prop": "something", "email": "bob@bob.com"}, ) session_recording_id = "session_1" base_time = (now() - relativedelta(days=1)).replace(microsecond=0) @@ -370,7 +400,12 @@ def test_get_single_session_recording_metadata(self): def test_single_session_recording_doesnt_leak_teams(self): another_team = Team.objects.create(organization=self.organization) - self.create_snapshot("user", "id_no_team_leaking", now() - relativedelta(days=1), team_id=another_team.pk) + self.create_snapshot( + "user", + "id_no_team_leaking", + now() - relativedelta(days=1), + team_id=another_team.pk, + ) response = self.client.get(f"/api/projects/{self.team.id}/session_recordings/id_no_team_leaking") self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) @@ -400,7 +435,12 @@ def test_session_recording_doesnt_exist(self): def test_request_to_another_teams_endpoint_returns_401(self): org = Organization.objects.create(name="Separate Org") another_team = Team.objects.create(organization=org) - self.create_snapshot("user", "id_no_team_leaking", now() - relativedelta(days=1), team_id=another_team.pk) + self.create_snapshot( + "user", + "id_no_team_leaking", + now() - relativedelta(days=1), + team_id=another_team.pk, + ) response = self.client.get(f"/api/projects/{another_team.pk}/session_recordings/id_no_team_leaking") self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) @@ -413,11 +453,28 @@ def test_request_to_another_teams_endpoint_returns_401(self): def test_session_ids_filter(self, use_recording_events: bool, api_version: int): with freeze_time("2020-09-13T12:26:40.000Z"): Person.objects.create( - team=self.team, distinct_ids=["user"], properties={"$some_prop": "something", "email": "bob@bob.com"} + team=self.team, + distinct_ids=["user"], + properties={"$some_prop": "something", "email": "bob@bob.com"}, + ) + self.create_snapshot( + "user", + "1", + now() - relativedelta(days=1), + use_recording_table=use_recording_events, + ) + self.create_snapshot( + "user", + "2", + now() - relativedelta(days=2), + use_recording_table=use_recording_events, + ) + self.create_snapshot( + "user", + "3", + now() - relativedelta(days=3), + use_recording_table=use_recording_events, ) - self.create_snapshot("user", "1", now() - relativedelta(days=1), use_recording_table=use_recording_events) - self.create_snapshot("user", "2", now() - relativedelta(days=2), use_recording_table=use_recording_events) - self.create_snapshot("user", "3", now() - relativedelta(days=3), use_recording_table=use_recording_events) # Fetch playlist params_string = urlencode({"session_ids": '["1", "2", "3"]', "version": api_version}) @@ -433,7 +490,9 @@ def test_session_ids_filter(self, use_recording_events: bool, api_version: int): def test_empty_list_session_ids_filter_returns_no_recordings(self): with freeze_time("2020-09-13T12:26:40.000Z"): Person.objects.create( - team=self.team, distinct_ids=["user"], properties={"$some_prop": "something", "email": "bob@bob.com"} + team=self.team, + distinct_ids=["user"], + properties={"$some_prop": "something", "email": "bob@bob.com"}, ) self.create_snapshot("user", "1", now() - relativedelta(days=1)) self.create_snapshot("user", "2", now() - relativedelta(days=2)) @@ -455,7 +514,10 @@ def test_delete_session_recording(self): response = self.client.delete(f"/api/projects/{self.team.id}/session_recordings/1") self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) - @patch("ee.session_recordings.session_recording_extensions.object_storage.copy_objects", return_value=2) + @patch( + "ee.session_recordings.session_recording_extensions.object_storage.copy_objects", + return_value=2, + ) def test_persist_session_recording(self, _mock_copy_objects: MagicMock) -> None: self.create_snapshot("user", "1", now() - relativedelta(days=1), team_id=self.team.pk) @@ -473,7 +535,10 @@ def test_persist_session_recording(self, _mock_copy_objects: MagicMock) -> None: # New snapshot loading method @freeze_time("2023-01-01T00:00:00Z") - @patch("posthog.session_recordings.queries.session_replay_events.SessionReplayEvents.exists", return_value=True) + @patch( + "posthog.session_recordings.queries.session_replay_events.SessionReplayEvents.exists", + return_value=True, + ) @patch("posthog.session_recordings.session_recording_api.object_storage.list_objects") def test_get_snapshots_v2_default_response(self, mock_list_objects: MagicMock, _mock_exists: MagicMock) -> None: session_id = str(uuid.uuid4()) @@ -510,7 +575,10 @@ def test_get_snapshots_v2_default_response(self, mock_list_objects: MagicMock, _ mock_list_objects.assert_called_with(f"session_recordings/team_id/{self.team.pk}/session_id/{session_id}/data") @freeze_time("2023-01-01T00:00:00Z") - @patch("posthog.session_recordings.queries.session_replay_events.SessionReplayEvents.exists", return_value=True) + @patch( + "posthog.session_recordings.queries.session_replay_events.SessionReplayEvents.exists", + return_value=True, + ) @patch("posthog.session_recordings.session_recording_api.object_storage.list_objects") def test_get_snapshots_v2_from_lts(self, mock_list_objects: MagicMock, _mock_exists: MagicMock) -> None: session_id = str(uuid.uuid4()) @@ -568,7 +636,10 @@ def list_objects_func(path: str) -> List[str]: ] @freeze_time("2023-01-01T00:00:00Z") - @patch("posthog.session_recordings.queries.session_replay_events.SessionReplayEvents.exists", return_value=True) + @patch( + "posthog.session_recordings.queries.session_replay_events.SessionReplayEvents.exists", + return_value=True, + ) @patch("posthog.session_recordings.session_recording_api.object_storage.list_objects") def test_get_snapshots_v2_default_response_no_realtime_if_old(self, mock_list_objects, _mock_exists) -> None: session_id = str(uuid.uuid4()) @@ -591,12 +662,19 @@ def test_get_snapshots_v2_default_response_no_realtime_if_old(self, mock_list_ob ] } - @patch("posthog.session_recordings.queries.session_replay_events.SessionReplayEvents.exists", return_value=True) + @patch( + "posthog.session_recordings.queries.session_replay_events.SessionReplayEvents.exists", + return_value=True, + ) @patch("posthog.session_recordings.session_recording_api.SessionRecording.get_or_build") @patch("posthog.session_recordings.session_recording_api.object_storage.get_presigned_url") @patch("posthog.session_recordings.session_recording_api.requests") def test_can_get_session_recording_blob( - self, _mock_requests, mock_presigned_url, mock_get_session_recording, _mock_exists + self, + _mock_requests, + mock_presigned_url, + mock_get_session_recording, + _mock_exists, ) -> None: session_id = str(uuid.uuid4()) """API will add session_recordings/team_id/{self.team.pk}/session_id/{session_id}""" @@ -662,7 +740,8 @@ def test_get_via_sharing_token(self, mock_copy_objects: MagicMock) -> None: ) token = self.client.patch( - f"/api/projects/{self.team.id}/session_recordings/{session_id}/sharing", {"enabled": True} + f"/api/projects/{self.team.id}/session_recordings/{session_id}/sharing", + {"enabled": True}, ).json()["access_token"] self.client.logout() @@ -764,7 +843,10 @@ def test_get_matching_events(self) -> None: session_id = f"test_get_matching_events-1-{uuid.uuid4()}" self.create_snapshot("user", session_id, base_time) event_id = _create_event( - event="$pageview", properties={"$session_id": session_id}, team=self.team, distinct_id=uuid.uuid4() + event="$pageview", + properties={"$session_id": session_id}, + team=self.team, + distinct_id=uuid.uuid4(), ) # a non-matching session diff --git a/posthog/settings/__init__.py b/posthog/settings/__init__.py index c164be0503f5d..099e1812e5311 100644 --- a/posthog/settings/__init__.py +++ b/posthog/settings/__init__.py @@ -46,7 +46,10 @@ # https://posthog.com/docs/self-host/configure/environment-variables debug_queries = get_from_env("DEBUG_QUERIES", False, type_cast=str_to_bool) disable_paid_fs = get_from_env("DISABLE_PAID_FEATURE_SHOWCASING", False, type_cast=str_to_bool) -INSTANCE_PREFERENCES = {"debug_queries": debug_queries, "disable_paid_fs": disable_paid_fs} +INSTANCE_PREFERENCES = { + "debug_queries": debug_queries, + "disable_paid_fs": disable_paid_fs, +} SITE_URL: str = os.getenv("SITE_URL", "http://localhost:8000").rstrip("/") INSTANCE_TAG: str = os.getenv("INSTANCE_TAG", "none") @@ -60,7 +63,10 @@ "DISABLE_MMDB", TEST, type_cast=str_to_bool ) # plugin server setting disabling GeoIP feature PLUGINS_PREINSTALLED_URLS: List[str] = ( - os.getenv("PLUGINS_PREINSTALLED_URLS", "https://www.npmjs.com/package/@posthog/geoip-plugin").split(",") + os.getenv( + "PLUGINS_PREINSTALLED_URLS", + "https://www.npmjs.com/package/@posthog/geoip-plugin", + ).split(",") if not DISABLE_MMDB else [] ) diff --git a/posthog/settings/data_stores.py b/posthog/settings/data_stores.py index 49fa73f3bd030..9f6f9ca74cab8 100644 --- a/posthog/settings/data_stores.py +++ b/posthog/settings/data_stores.py @@ -62,7 +62,10 @@ def postgres_config(host: str) -> dict: PG_PASSWORD = os.getenv("PGPASSWORD", "posthog") PG_PORT = os.getenv("PGPORT", "5432") PG_DATABASE = os.getenv("PGDATABASE", "posthog") - DATABASE_URL = os.getenv("DATABASE_URL", f"postgres://{PG_USER}:{PG_PASSWORD}@{PG_HOST}:{PG_PORT}/{PG_DATABASE}") + DATABASE_URL = os.getenv( + "DATABASE_URL", + f"postgres://{PG_USER}:{PG_PASSWORD}@{PG_HOST}:{PG_PORT}/{PG_DATABASE}", + ) else: DATABASE_URL = os.getenv("DATABASE_URL", "") diff --git a/posthog/settings/dynamic_settings.py b/posthog/settings/dynamic_settings.py index 94d774b0200f0..b7eb65967fc65 100644 --- a/posthog/settings/dynamic_settings.py +++ b/posthog/settings/dynamic_settings.py @@ -223,4 +223,9 @@ # SECRET_SETTINGS can only be updated but will never be exposed through the API (we do store them plain text in the DB) # On the frontend UI will clearly show which configuration elements are secret and whether they have a set value or not. -SECRET_SETTINGS = ["EMAIL_HOST_PASSWORD", "SLACK_APP_CLIENT_SECRET", "SLACK_APP_SIGNING_SECRET", "SENTRY_AUTH_TOKEN"] +SECRET_SETTINGS = [ + "EMAIL_HOST_PASSWORD", + "SLACK_APP_CLIENT_SECRET", + "SLACK_APP_SIGNING_SECRET", + "SENTRY_AUTH_TOKEN", +] diff --git a/posthog/settings/sentry.py b/posthog/settings/sentry.py index 208f3bfd81e2c..f2c36695b62cb 100644 --- a/posthog/settings/sentry.py +++ b/posthog/settings/sentry.py @@ -136,7 +136,12 @@ def sentry_init() -> None: send_default_pii=send_pii, dsn=os.environ["SENTRY_DSN"], release=release, - integrations=[DjangoIntegration(), CeleryIntegration(), RedisIntegration(), sentry_logging], + integrations=[ + DjangoIntegration(), + CeleryIntegration(), + RedisIntegration(), + sentry_logging, + ], request_bodies="always" if send_pii else "never", sample_rate=1.0, # Configures the sample rate for error events, in the range of 0.0 to 1.0 (default). diff --git a/posthog/settings/service_requirements.py b/posthog/settings/service_requirements.py index 2592d73a1be60..79cdc55d51c67 100644 --- a/posthog/settings/service_requirements.py +++ b/posthog/settings/service_requirements.py @@ -8,7 +8,9 @@ SKIP_SERVICE_VERSION_REQUIREMENTS = get_from_env( - "SKIP_SERVICE_VERSION_REQUIREMENTS", TEST or IS_COLLECT_STATIC or DEBUG, type_cast=str_to_bool + "SKIP_SERVICE_VERSION_REQUIREMENTS", + TEST or IS_COLLECT_STATIC or DEBUG, + type_cast=str_to_bool, ) if SKIP_SERVICE_VERSION_REQUIREMENTS and not (TEST or DEBUG): diff --git a/posthog/settings/utils.py b/posthog/settings/utils.py index 51ce8543645ba..6dd22dbf97cf8 100644 --- a/posthog/settings/utils.py +++ b/posthog/settings/utils.py @@ -8,7 +8,13 @@ __all__ = ["get_from_env", "get_list", "str_to_bool"] -def get_from_env(key: str, default: Any = None, *, optional: bool = False, type_cast: Optional[Callable] = None) -> Any: +def get_from_env( + key: str, + default: Any = None, + *, + optional: bool = False, + type_cast: Optional[Callable] = None, +) -> Any: value = os.getenv(key) if value is None or value == "": if optional: diff --git a/posthog/settings/web.py b/posthog/settings/web.py index c732c7a8e4314..b846a2486c5df 100644 --- a/posthog/settings/web.py +++ b/posthog/settings/web.py @@ -183,7 +183,12 @@ SOCIAL_AUTH_STRATEGY = "social_django.strategy.DjangoStrategy" SOCIAL_AUTH_STORAGE = "social_django.models.DjangoStorage" -SOCIAL_AUTH_FIELDS_STORED_IN_SESSION = ["invite_id", "user_name", "email_opt_in", "organization_name"] +SOCIAL_AUTH_FIELDS_STORED_IN_SESSION = [ + "invite_id", + "user_name", + "email_opt_in", + "organization_name", +] SOCIAL_AUTH_GITHUB_SCOPE = ["user:email"] SOCIAL_AUTH_GITHUB_KEY = os.getenv("SOCIAL_AUTH_GITHUB_KEY") SOCIAL_AUTH_GITHUB_SECRET = os.getenv("SOCIAL_AUTH_GITHUB_SECRET") @@ -222,7 +227,10 @@ STATIC_ROOT = os.path.join(BASE_DIR, "staticfiles") STATIC_URL = "/static/" -STATICFILES_DIRS = [os.path.join(BASE_DIR, "frontend/dist"), os.path.join(BASE_DIR, "posthog/year_in_posthog/images")] +STATICFILES_DIRS = [ + os.path.join(BASE_DIR, "frontend/dist"), + os.path.join(BASE_DIR, "posthog/year_in_posthog/images"), +] STATICFILES_STORAGE = "whitenoise.storage.ManifestStaticFilesStorage" AUTH_USER_MODEL = "posthog.User" diff --git a/posthog/storage/object_storage.py b/posthog/storage/object_storage.py index 79ea0c90ceb19..a1ff639b1c293 100644 --- a/posthog/storage/object_storage.py +++ b/posthog/storage/object_storage.py @@ -111,7 +111,12 @@ def list_objects(self, bucket: str, prefix: str) -> Optional[List[str]]: else: return None except Exception as e: - logger.error("object_storage.list_objects_failed", bucket=bucket, prefix=prefix, error=e) + logger.error( + "object_storage.list_objects_failed", + bucket=bucket, + prefix=prefix, + error=e, + ) capture_exception(e) return None @@ -128,7 +133,13 @@ def read_bytes(self, bucket: str, key: str) -> Optional[bytes]: s3_response = self.aws_client.get_object(Bucket=bucket, Key=key) return s3_response["Body"].read() except Exception as e: - logger.error("object_storage.read_failed", bucket=bucket, file_name=key, error=e, s3_response=s3_response) + logger.error( + "object_storage.read_failed", + bucket=bucket, + file_name=key, + error=e, + s3_response=s3_response, + ) capture_exception(e) raise ObjectStorageError("read failed") from e @@ -149,7 +160,13 @@ def write(self, bucket: str, key: str, content: Union[str, bytes], extras: Dict try: s3_response = self.aws_client.put_object(Bucket=bucket, Body=content, Key=key, **(extras or {})) except Exception as e: - logger.error("object_storage.write_failed", bucket=bucket, file_name=key, error=e, s3_response=s3_response) + logger.error( + "object_storage.write_failed", + bucket=bucket, + file_name=key, + error=e, + s3_response=s3_response, + ) capture_exception(e) raise ObjectStorageError("write failed") from e @@ -165,7 +182,10 @@ def copy_objects(self, bucket: str, source_prefix: str, target_prefix: str) -> i return len(source_objects) except Exception as e: logger.error( - "object_storage.copy_objects_failed", source_prefix=source_prefix, target_prefix=target_prefix, error=e + "object_storage.copy_objects_failed", + source_prefix=source_prefix, + target_prefix=target_prefix, + error=e, ) capture_exception(e) return None @@ -186,7 +206,11 @@ def object_storage_client() -> ObjectStorageClient: endpoint_url=settings.OBJECT_STORAGE_ENDPOINT, aws_access_key_id=settings.OBJECT_STORAGE_ACCESS_KEY_ID, aws_secret_access_key=settings.OBJECT_STORAGE_SECRET_ACCESS_KEY, - config=Config(signature_version="s3v4", connect_timeout=1, retries={"max_attempts": 1}), + config=Config( + signature_version="s3v4", + connect_timeout=1, + retries={"max_attempts": 1}, + ), region_name=settings.OBJECT_STORAGE_REGION, ) ) @@ -196,7 +220,10 @@ def object_storage_client() -> ObjectStorageClient: def write(file_name: str, content: Union[str, bytes], extras: Dict | None = None) -> None: return object_storage_client().write( - bucket=settings.OBJECT_STORAGE_BUCKET, key=file_name, content=content, extras=extras + bucket=settings.OBJECT_STORAGE_BUCKET, + key=file_name, + content=content, + extras=extras, ) @@ -219,7 +246,9 @@ def list_objects(prefix: str) -> Optional[List[str]]: def copy_objects(source_prefix: str, target_prefix: str) -> int: return ( object_storage_client().copy_objects( - bucket=settings.OBJECT_STORAGE_BUCKET, source_prefix=source_prefix, target_prefix=target_prefix + bucket=settings.OBJECT_STORAGE_BUCKET, + source_prefix=source_prefix, + target_prefix=target_prefix, ) or 0 ) diff --git a/posthog/storage/test/test_object_storage.py b/posthog/storage/test/test_object_storage.py index 3544df570d4c2..f24114911ba9e 100644 --- a/posthog/storage/test/test_object_storage.py +++ b/posthog/storage/test/test_object_storage.py @@ -10,7 +10,14 @@ OBJECT_STORAGE_ENDPOINT, OBJECT_STORAGE_SECRET_ACCESS_KEY, ) -from posthog.storage.object_storage import health_check, read, write, get_presigned_url, list_objects, copy_objects +from posthog.storage.object_storage import ( + health_check, + read, + write, + get_presigned_url, + list_objects, + copy_objects, +) from posthog.test.base import APIBaseTest TEST_BUCKET = "test_storage_bucket" @@ -113,7 +120,8 @@ def test_can_copy_objects_between_prefixes(self) -> None: write(file_name, "my content".encode("utf-8")) copied_count = copy_objects( - source_prefix=f"{TEST_BUCKET}/{shared_prefix}", target_prefix=f"{TEST_BUCKET}/the_destination/folder" + source_prefix=f"{TEST_BUCKET}/{shared_prefix}", + target_prefix=f"{TEST_BUCKET}/the_destination/folder", ) assert copied_count == 3 @@ -137,7 +145,8 @@ def test_can_safely_copy_objects_from_unknown_prefix(self) -> None: write(file_name, "my content".encode("utf-8")) copied_count = copy_objects( - source_prefix=f"nothing_here", target_prefix=f"{TEST_BUCKET}/the_destination/folder" + source_prefix=f"nothing_here", + target_prefix=f"{TEST_BUCKET}/the_destination/folder", ) assert copied_count == 0 diff --git a/posthog/tasks/async_migrations.py b/posthog/tasks/async_migrations.py index 608fead3e07a3..ae505b44131e5 100644 --- a/posthog/tasks/async_migrations.py +++ b/posthog/tasks/async_migrations.py @@ -7,7 +7,11 @@ start_async_migration, update_migration_progress, ) -from posthog.async_migrations.utils import force_stop_migration, process_error, trigger_migration +from posthog.async_migrations.utils import ( + force_stop_migration, + process_error, + trigger_migration, +) from posthog.celery import app from posthog.models.instance_setting import get_instance_setting @@ -44,7 +48,11 @@ def check_async_migration_health() -> None: # failures and successes are handled elsewhere # pending means we haven't picked up the task yet # retry is not possible as max_retries == 0 - if migration_task_celery_state not in (states.STARTED, states.PENDING, states.FAILURE): + if migration_task_celery_state not in ( + states.STARTED, + states.PENDING, + states.FAILURE, + ): return inspector = app.control.inspect() diff --git a/posthog/tasks/calculate_cohort.py b/posthog/tasks/calculate_cohort.py index f3c09f65119e4..1c4492071c78a 100644 --- a/posthog/tasks/calculate_cohort.py +++ b/posthog/tasks/calculate_cohort.py @@ -62,7 +62,10 @@ def calculate_cohort_from_list(cohort_id: int, items: List[str]) -> None: @shared_task(ignore_result=True, max_retries=1) def insert_cohort_from_insight_filter(cohort_id: int, filter_data: Dict[str, Any]) -> None: - from posthog.api.cohort import insert_cohort_actors_into_ch, insert_cohort_people_into_pg + from posthog.api.cohort import ( + insert_cohort_actors_into_ch, + insert_cohort_people_into_pg, + ) cohort = Cohort.objects.get(pk=cohort_id) diff --git a/posthog/tasks/check_clickhouse_schema_drift.py b/posthog/tasks/check_clickhouse_schema_drift.py index d4ed1347f4419..bea00530b7eba 100644 --- a/posthog/tasks/check_clickhouse_schema_drift.py +++ b/posthog/tasks/check_clickhouse_schema_drift.py @@ -91,7 +91,8 @@ def get_clickhouse_schema_drift( def check_clickhouse_schema_drift( - clickhouse_nodes: List[Tuple[str]] = [], clickhouse_schema: List[Tuple[str, str, str]] = [] + clickhouse_nodes: List[Tuple[str]] = [], + clickhouse_schema: List[Tuple[str, str, str]] = [], ) -> None: try: if not clickhouse_nodes: diff --git a/posthog/tasks/email.py b/posthog/tasks/email.py index 44bd8eae03087..bd7f60188b166 100644 --- a/posthog/tasks/email.py +++ b/posthog/tasks/email.py @@ -9,7 +9,15 @@ from posthog.celery import app from posthog.cloud_utils import is_cloud from posthog.email import EmailMessage, is_email_available -from posthog.models import Organization, OrganizationInvite, OrganizationMembership, Plugin, PluginConfig, Team, User +from posthog.models import ( + Organization, + OrganizationInvite, + OrganizationMembership, + Plugin, + PluginConfig, + Team, + User, +) from posthog.user_permissions import UserPermissions logger = structlog.get_logger(__name__) @@ -119,7 +127,10 @@ def send_email_verification(user_id: int, token: str) -> None: retry_backoff=True, ) def send_fatal_plugin_error( - plugin_config_id: int, plugin_config_updated_at: Optional[str], error: str, is_system_error: bool + plugin_config_id: int, + plugin_config_updated_at: Optional[str], + error: str, + is_system_error: bool, ) -> None: if not is_email_available(with_absolute_urls=True): return @@ -131,7 +142,12 @@ def send_fatal_plugin_error( campaign_key=campaign_key, subject=f"[Alert] {plugin} has been disabled in project {team} due to a fatal error", template_name="fatal_plugin_error", - template_context={"plugin": plugin, "team": team, "error": error, "is_system_error": is_system_error}, + template_context={ + "plugin": plugin, + "team": team, + "error": error, + "is_system_error": is_system_error, + }, ) memberships_to_email = [] memberships = OrganizationMembership.objects.prefetch_related("user", "organization").filter( @@ -181,13 +197,21 @@ def send_email_change_emails(now_iso: str, user_name: str, old_address: str, new campaign_key=f"email_change_old_address_{now_iso}", subject="This is no longer your PostHog account email", template_name="email_change_old_address", - template_context={"user_name": user_name, "old_address": old_address, "new_address": new_address}, + template_context={ + "user_name": user_name, + "old_address": old_address, + "new_address": new_address, + }, ) message_new_address = EmailMessage( campaign_key=f"email_change_new_address_{now_iso}", subject="This is your new PostHog account email", template_name="email_change_new_address", - template_context={"user_name": user_name, "old_address": old_address, "new_address": new_address}, + template_context={ + "user_name": user_name, + "old_address": old_address, + "new_address": new_address, + }, ) message_old_address.add_recipient(email=old_address) message_new_address.add_recipient(email=new_address) diff --git a/posthog/tasks/exporter.py b/posthog/tasks/exporter.py index 01c85537602f0..ed41d9d5412d0 100644 --- a/posthog/tasks/exporter.py +++ b/posthog/tasks/exporter.py @@ -34,14 +34,20 @@ # export_asset is used in chords/groups and so must not ignore its results -@app.task(autoretry_for=(Exception,), max_retries=5, retry_backoff=True, acks_late=True, ignore_result=False) +@app.task( + autoretry_for=(Exception,), + max_retries=5, + retry_backoff=True, + acks_late=True, + ignore_result=False, +) def export_asset(exported_asset_id: int, limit: Optional[int] = None) -> None: from posthog.tasks.exports import csv_exporter, image_exporter # if Celery is lagging then you can end up with an exported asset that has had a TTL added # and that TTL has passed, in the exporter we don't care about that. # the TTL is for later cleanup. - exported_asset: ExportedAsset = ExportedAsset.objects_including_ttl_deleted.select_related( + exported_asset: (ExportedAsset) = ExportedAsset.objects_including_ttl_deleted.select_related( "insight", "dashboard" ).get(pk=exported_asset_id) diff --git a/posthog/tasks/exports/csv_exporter.py b/posthog/tasks/exports/csv_exporter.py index 9643244119668..622798774ec1d 100644 --- a/posthog/tasks/exports/csv_exporter.py +++ b/posthog/tasks/exports/csv_exporter.py @@ -12,7 +12,12 @@ from posthog.models.exported_asset import ExportedAsset, save_content from posthog.utils import absolute_uri from .ordered_csv_renderer import OrderedCsvRenderer -from ..exporter import EXPORT_FAILED_COUNTER, EXPORT_ASSET_UNKNOWN_COUNTER, EXPORT_SUCCEEDED_COUNTER, EXPORT_TIMER +from ..exporter import ( + EXPORT_FAILED_COUNTER, + EXPORT_ASSET_UNKNOWN_COUNTER, + EXPORT_SUCCEEDED_COUNTER, + EXPORT_TIMER, +) from ...constants import CSV_EXPORT_LIMIT logger = structlog.get_logger(__name__) @@ -128,12 +133,18 @@ def _convert_response_to_csv_data(data: Any) -> List[Any]: for item in items: if item.get("date"): # Dated means we create a grid - line = {"cohort": item["date"], "cohort size": item["values"][0]["count"]} + line = { + "cohort": item["date"], + "cohort size": item["values"][0]["count"], + } for index, data in enumerate(item["values"]): line[items[index]["label"]] = data["count"] else: # Otherwise we just specify "Period" for titles - line = {"cohort": item["label"], "cohort size": item["values"][0]["count"]} + line = { + "cohort": item["label"], + "cohort size": item["values"][0]["count"], + } for index, data in enumerate(item["values"]): line[f"Period {index}"] = data["count"] @@ -182,7 +193,9 @@ def _export_to_csv(exported_asset: ExportedAsset, limit: int = 1000) -> None: body = resource.get("body", None) next_url = None access_token = encode_jwt( - {"id": exported_asset.created_by_id}, datetime.timedelta(minutes=15), PosthogJwtAudience.IMPERSONATED_USER + {"id": exported_asset.created_by_id}, + datetime.timedelta(minutes=15), + PosthogJwtAudience.IMPERSONATED_USER, ) while len(all_csv_rows) < CSV_EXPORT_LIMIT: @@ -243,13 +256,24 @@ def get_limit_param_key(path: str) -> str: def make_api_call( - access_token: str, body: Any, limit: int, method: str, next_url: Optional[str], path: str + access_token: str, + body: Any, + limit: int, + method: str, + next_url: Optional[str], + path: str, ) -> requests.models.Response: request_url: str = absolute_uri(next_url or path) try: - url = add_query_params(request_url, {get_limit_param_key(request_url): str(limit), "is_csv_export": "1"}) + url = add_query_params( + request_url, + {get_limit_param_key(request_url): str(limit), "is_csv_export": "1"}, + ) response = requests.request( - method=method.lower(), url=url, json=body, headers={"Authorization": f"Bearer {access_token}"} + method=method.lower(), + url=url, + json=body, + headers={"Authorization": f"Bearer {access_token}"}, ) return response except Exception as ex: diff --git a/posthog/tasks/exports/exporter_utils.py b/posthog/tasks/exports/exporter_utils.py index 38b8979f8f467..a47f43aa41710 100644 --- a/posthog/tasks/exports/exporter_utils.py +++ b/posthog/tasks/exports/exporter_utils.py @@ -50,4 +50,8 @@ def log_error_if_site_url_not_reachable() -> None: if not settings.SITE_URL: logger.error("site_url_not_set") elif not is_site_url_reachable(): - logger.error("site_url_not_reachable", site_url=settings.SITE_URL, exception=_site_reachable_exception) + logger.error( + "site_url_not_reachable", + site_url=settings.SITE_URL, + exception=_site_reachable_exception, + ) diff --git a/posthog/tasks/exports/image_exporter.py b/posthog/tasks/exports/image_exporter.py index 057239a929f50..1961d9a456053 100644 --- a/posthog/tasks/exports/image_exporter.py +++ b/posthog/tasks/exports/image_exporter.py @@ -16,8 +16,16 @@ from webdriver_manager.core.os_manager import ChromeType from posthog.caching.fetch_from_cache import synchronously_update_cache -from posthog.models.exported_asset import ExportedAsset, get_public_access_token, save_content -from posthog.tasks.exporter import EXPORT_SUCCEEDED_COUNTER, EXPORT_FAILED_COUNTER, EXPORT_TIMER +from posthog.models.exported_asset import ( + ExportedAsset, + get_public_access_token, + save_content, +) +from posthog.tasks.exporter import ( + EXPORT_SUCCEEDED_COUNTER, + EXPORT_FAILED_COUNTER, + EXPORT_TIMER, +) from posthog.tasks.exports.exporter_utils import log_error_if_site_url_not_reachable from posthog.utils import absolute_uri @@ -111,7 +119,10 @@ def _export_to_png(exported_asset: ExportedAsset) -> None: def _screenshot_asset( - image_path: str, url_to_render: str, screenshot_width: ScreenWidth, wait_for_css_selector: CSSSelector + image_path: str, + url_to_render: str, + screenshot_width: ScreenWidth, + wait_for_css_selector: CSSSelector, ) -> None: driver: Optional[webdriver.Chrome] = None try: diff --git a/posthog/tasks/exports/ordered_csv_renderer.py b/posthog/tasks/exports/ordered_csv_renderer.py index c969772e9d815..1b7a16dd83c3e 100644 --- a/posthog/tasks/exports/ordered_csv_renderer.py +++ b/posthog/tasks/exports/ordered_csv_renderer.py @@ -16,7 +16,6 @@ def tablize(self, data: Any, header: Any = None, labels: Any = None) -> Generato header = data.header if data: - # First, flatten the data (i.e., convert it to a list of # dictionaries that are each exactly one level deep). The key for # each item designates the name of the column that the item will diff --git a/posthog/tasks/exports/test/test_csv_exporter.py b/posthog/tasks/exports/test/test_csv_exporter.py index 62ca713517f0e..65fda3baa0dd4 100644 --- a/posthog/tasks/exports/test/test_csv_exporter.py +++ b/posthog/tasks/exports/test/test_csv_exporter.py @@ -19,7 +19,10 @@ from posthog.storage import object_storage from posthog.storage.object_storage import ObjectStorageError from posthog.tasks.exports import csv_exporter -from posthog.tasks.exports.csv_exporter import UnexpectedEmptyJsonResponse, add_query_params +from posthog.tasks.exports.csv_exporter import ( + UnexpectedEmptyJsonResponse, + add_query_params, +) from posthog.test.base import APIBaseTest, _create_event, flush_persons_and_events from posthog.utils import absolute_uri @@ -257,7 +260,10 @@ def test_limiting_query_as_expected(self) -> None: with self.settings(SITE_URL="https://app.posthog.com"): modified_url = add_query_params(absolute_uri(regression_11204), {"limit": "3500"}) actual_bits = self._split_to_dict(modified_url) - expected_bits = {**self._split_to_dict(regression_11204), **{"limit": "3500"}} + expected_bits = { + **self._split_to_dict(regression_11204), + **{"limit": "3500"}, + } assert expected_bits == actual_bits def test_limiting_existing_limit_query_as_expected(self) -> None: @@ -265,7 +271,10 @@ def test_limiting_existing_limit_query_as_expected(self) -> None: url_with_existing_limit = regression_11204 + "&limit=100000" modified_url = add_query_params(absolute_uri(url_with_existing_limit), {"limit": "3500"}) actual_bits = self._split_to_dict(modified_url) - expected_bits = {**self._split_to_dict(regression_11204), **{"limit": "3500"}} + expected_bits = { + **self._split_to_dict(regression_11204), + **{"limit": "3500"}, + } assert expected_bits == actual_bits @patch("posthog.tasks.exports.csv_exporter.make_api_call") @@ -341,7 +350,11 @@ def test_csv_exporter_events_query(self, mocked_uuidt, MAX_SELECT_RETURNED_ROWS= team=self.team, export_format=ExportedAsset.ExportFormat.CSV, export_context={ - "source": {"kind": "EventsQuery", "select": ["event", "*"], "where": [f"distinct_id = '{random_uuid}'"]} + "source": { + "kind": "EventsQuery", + "select": ["event", "*"], + "where": [f"distinct_id = '{random_uuid}'"], + } }, ) exported_asset.save() diff --git a/posthog/tasks/exports/test/test_csv_exporter_renders.py b/posthog/tasks/exports/test/test_csv_exporter_renders.py index 26cb67c08885a..f17e64635370b 100644 --- a/posthog/tasks/exports/test/test_csv_exporter_renders.py +++ b/posthog/tasks/exports/test/test_csv_exporter_renders.py @@ -33,7 +33,9 @@ def test_csv_rendering(mock_settings, mock_request, filename): fixture = json.load(f) asset = ExportedAsset( - team=team, export_format=ExportedAsset.ExportFormat.CSV, export_context={"path": "/api/literally/anything"} + team=team, + export_format=ExportedAsset.ExportFormat.CSV, + export_context={"path": "/api/literally/anything"}, ) asset.save() diff --git a/posthog/tasks/exports/test/test_csv_exporter_url_sanitising.py b/posthog/tasks/exports/test/test_csv_exporter_url_sanitising.py index 70161c42b6244..b78a870e626c4 100644 --- a/posthog/tasks/exports/test/test_csv_exporter_url_sanitising.py +++ b/posthog/tasks/exports/test/test_csv_exporter_url_sanitising.py @@ -16,10 +16,26 @@ def test_sanitize_url_when_provided_path_and_site_url_has_a_port(self) -> None: assert sanitised == "https://localhost:8000/some/location" error_test_cases = [ - ("changing scheme", "https://localhost:8000", "http://localhost:8000/some/location"), - ("changing port", "https://localhost:8000", "https://localhost:8123/some/location"), - ("changing port and url", "https://something.posthog.com:8000", "https://localhost:8123/some/location"), - ("changing domain", "https://app.posthog.com", "https://google.com/some/location"), + ( + "changing scheme", + "https://localhost:8000", + "http://localhost:8000/some/location", + ), + ( + "changing port", + "https://localhost:8000", + "https://localhost:8123/some/location", + ), + ( + "changing port and url", + "https://something.posthog.com:8000", + "https://localhost:8123/some/location", + ), + ( + "changing domain", + "https://app.posthog.com", + "https://google.com/some/location", + ), ] @parameterized.expand(error_test_cases) diff --git a/posthog/tasks/exports/test/test_image_exporter.py b/posthog/tasks/exports/test/test_image_exporter.py index 948500a9d77b8..3c3a84133a1b1 100644 --- a/posthog/tasks/exports/test/test_image_exporter.py +++ b/posthog/tasks/exports/test/test_image_exporter.py @@ -20,7 +20,11 @@ @patch("posthog.tasks.exports.image_exporter.synchronously_update_cache") @patch("posthog.tasks.exports.image_exporter._screenshot_asset") -@patch("posthog.tasks.exports.image_exporter.open", new_callable=mock_open, read_data=b"image_data") +@patch( + "posthog.tasks.exports.image_exporter.open", + new_callable=mock_open, + read_data=b"image_data", +) @patch("os.remove") class TestImageExporter(APIBaseTest): exported_asset: ExportedAsset @@ -28,7 +32,9 @@ class TestImageExporter(APIBaseTest): def setup_method(self, method): insight = Insight.objects.create(team=self.team) asset = ExportedAsset.objects.create( - team=self.team, export_format=ExportedAsset.ExportFormat.PNG, insight=insight + team=self.team, + export_format=ExportedAsset.ExportFormat.PNG, + insight=insight, ) self.exported_asset = asset diff --git a/posthog/tasks/test/test_async_migrations.py b/posthog/tasks/test/test_async_migrations.py index bb7cfce0797e7..27bb8fc991b8a 100644 --- a/posthog/tasks/test/test_async_migrations.py +++ b/posthog/tasks/test/test_async_migrations.py @@ -6,7 +6,10 @@ from celery.result import AsyncResult from posthog.async_migrations.examples.test_migration import Migration -from posthog.async_migrations.runner import run_async_migration_next_op, run_async_migration_operations +from posthog.async_migrations.runner import ( + run_async_migration_next_op, + run_async_migration_operations, +) from posthog.async_migrations.test.util import create_async_migration from posthog.models.async_migration import AsyncMigration, MigrationStatus from posthog.models.instance_setting import set_instance_setting @@ -45,7 +48,10 @@ def setUp(self) -> None: @pytest.mark.ee @patch.object(AsyncResult, "state", states.STARTED) @patch("posthog.celery.app.control.inspect", side_effect=inspect_mock) - @patch("posthog.tasks.async_migrations.run_async_migration.delay", side_effect=run_async_migration_mock) + @patch( + "posthog.tasks.async_migrations.run_async_migration.delay", + side_effect=run_async_migration_mock, + ) def test_check_async_migration_health_during_resumable_op(self, _: Any, __: Any) -> None: """ Mocks celery tasks and tests that `check_async_migration_health` works as expected @@ -76,7 +82,10 @@ def test_check_async_migration_health_during_resumable_op(self, _: Any, __: Any) @pytest.mark.ee @patch.object(AsyncResult, "state", states.STARTED) @patch("posthog.celery.app.control.inspect", side_effect=inspect_mock) - @patch("posthog.tasks.async_migrations.run_async_migration.delay", side_effect=run_async_migration_mock) + @patch( + "posthog.tasks.async_migrations.run_async_migration.delay", + side_effect=run_async_migration_mock, + ) def test_check_async_migration_health_during_non_resumable_op(self, _: Any, __: Any) -> None: """ Same as above, but now we find a non-resumbale op. diff --git a/posthog/tasks/test/test_calculate_cohort.py b/posthog/tasks/test/test_calculate_cohort.py index 749387c2a6344..0c81076c8fa81 100644 --- a/posthog/tasks/test/test_calculate_cohort.py +++ b/posthog/tasks/test/test_calculate_cohort.py @@ -71,7 +71,10 @@ def test_calculate_cohorts(self) -> None: team=self.team, filters={ "groups": [ - {"properties": [{"key": "id", "type": "cohort", "value": 267}], "rollout_percentage": None} + { + "properties": [{"key": "id", "type": "cohort", "value": 267}], + "rollout_percentage": None, + } ] }, key="default-flag-1", diff --git a/posthog/tasks/test/test_check_clickhouse_schema_drift.py b/posthog/tasks/test/test_check_clickhouse_schema_drift.py index 831e4ffbc1c3d..8d38d134cac40 100644 --- a/posthog/tasks/test/test_check_clickhouse_schema_drift.py +++ b/posthog/tasks/test/test_check_clickhouse_schema_drift.py @@ -2,7 +2,10 @@ from clickhouse_driver.errors import Error as ClickhouseError -from posthog.tasks.check_clickhouse_schema_drift import check_clickhouse_schema_drift, get_clickhouse_schema_drift +from posthog.tasks.check_clickhouse_schema_drift import ( + check_clickhouse_schema_drift, + get_clickhouse_schema_drift, +) def test_get_clickhouse_schema_drift() -> None: diff --git a/posthog/tasks/test/test_email.py b/posthog/tasks/test/test_email.py index 9ef1f27907908..a728879586aad 100644 --- a/posthog/tasks/test/test_email.py +++ b/posthog/tasks/test/test_email.py @@ -28,7 +28,10 @@ def create_org_team_and_user(creation_date: str, email: str, ingested_event: boo org = Organization.objects.create(name="too_late_org") Team.objects.create(organization=org, name="Default Project", ingested_event=ingested_event) user = User.objects.create_and_join( - organization=org, email=email, password=None, level=OrganizationMembership.Level.OWNER + organization=org, + email=email, + password=None, + level=OrganizationMembership.Level.OWNER, ) return org, user @@ -47,7 +50,11 @@ def setUpTestData(cls) -> None: set_instance_setting("EMAIL_HOST", "fake_host") set_instance_setting("EMAIL_ENABLED", True) create_org_team_and_user("2022-01-01 00:00:00", "too_late_user@posthog.com") - create_org_team_and_user("2022-01-02 00:00:00", "ingested_event_in_range_user@posthog.com", ingested_event=True) + create_org_team_and_user( + "2022-01-02 00:00:00", + "ingested_event_in_range_user@posthog.com", + ingested_event=True, + ) create_org_team_and_user("2022-01-03 00:00:00", "too_early_user@posthog.com") def test_send_invite(self, MockEmailMessage: MagicMock) -> None: @@ -68,7 +75,10 @@ def test_send_member_join(self, MockEmailMessage: MagicMock) -> None: org, user = create_org_team_and_user("2022-01-02 00:00:00", "admin@posthog.com") user = User.objects.create_and_join( - organization=org, email="new-user@posthog.com", password=None, level=OrganizationMembership.Level.MEMBER + organization=org, + email="new-user@posthog.com", + password=None, + level=OrganizationMembership.Level.MEMBER, ) send_member_join(user.uuid, org.id) diff --git a/posthog/tasks/test/test_usage_report.py b/posthog/tasks/test/test_usage_report.py index ec758a24fd548..715c3829855d2 100644 --- a/posthog/tasks/test/test_usage_report.py +++ b/posthog/tasks/test/test_usage_report.py @@ -28,7 +28,9 @@ from posthog.models.plugin import PluginConfig from posthog.models.sharing_configuration import SharingConfiguration from posthog.schema import EventsQuery -from posthog.session_recordings.queries.test.session_replay_sql import produce_replay_summary +from posthog.session_recordings.queries.test.session_replay_sql import ( + produce_replay_summary, +) from posthog.tasks.usage_report import ( _get_all_org_reports, _get_all_usage_data_as_team_rows, @@ -109,7 +111,10 @@ def _create_sample_usage_data(self) -> None: created_by=self.user, ) SharingConfiguration.objects.create( - team=self.org_1_team_1, dashboard=dashboard, access_token="testtoken", enabled=True + team=self.org_1_team_1, + dashboard=dashboard, + access_token="testtoken", + enabled=True, ) FeatureFlag.objects.create( @@ -184,7 +189,10 @@ def _create_sample_usage_data(self) -> None: GroupTypeMapping.objects.create(team=self.org_1_team_1, group_type="organization", group_type_index=0) GroupTypeMapping.objects.create(team=self.org_1_team_1, group_type="company", group_type_index=1) create_group( - team_id=self.org_1_team_1.pk, group_type_index=0, group_key="org:5", properties={"industry": "finance"} + team_id=self.org_1_team_1.pk, + group_type_index=0, + group_key="org:5", + properties={"industry": "finance"}, ) create_group( team_id=self.org_1_team_1.pk, @@ -323,7 +331,10 @@ def _test_usage_report(self) -> List[dict]: period_start, period_end = period all_reports = _get_all_org_reports(period_start, period_end) report = _get_full_org_usage_report_as_dict( - _get_full_org_usage_report(all_reports[str(self.organization.id)], get_instance_metadata(period)) + _get_full_org_usage_report( + all_reports[str(self.organization.id)], + get_instance_metadata(period), + ) ) assert report["table_sizes"] @@ -349,7 +360,10 @@ def _test_usage_report(self) -> List[dict]: "users_who_signed_up": [], "users_who_signed_up_count": 0, "table_sizes": report["table_sizes"], - "plugins_installed": {"Installed and enabled": 1, "Installed but not enabled": 1}, + "plugins_installed": { + "Installed and enabled": 1, + "Installed but not enabled": 1, + }, "plugins_enabled": {"Installed and enabled": 1}, "instance_tag": "none", "event_count_lifetime": 55, @@ -480,7 +494,10 @@ def _test_usage_report(self) -> List[dict]: "users_who_signed_up": [], "users_who_signed_up_count": 0, "table_sizes": report["table_sizes"], - "plugins_installed": {"Installed and enabled": 1, "Installed but not enabled": 1}, + "plugins_installed": { + "Installed and enabled": 1, + "Installed but not enabled": 1, + }, "plugins_enabled": {"Installed and enabled": 1}, "instance_tag": "none", "event_count_lifetime": 11, @@ -571,7 +588,8 @@ def _test_usage_report(self) -> List[dict]: for expectation in expectations: report = _get_full_org_usage_report_as_dict( _get_full_org_usage_report( - all_reports[expectation["organization_id"]], get_instance_metadata(period) + all_reports[expectation["organization_id"]], + get_instance_metadata(period), ) ) assert report == expectation @@ -634,7 +652,11 @@ def test_usage_report_hogql_queries(self) -> None: sync_execute("SYSTEM FLUSH LOGS") sync_execute("TRUNCATE TABLE system.query_log") - execute_hogql_query(query="select * from events limit 200", team=self.team, query_type="HogQLQuery") + execute_hogql_query( + query="select * from events limit 200", + team=self.team, + query_type="HogQLQuery", + ) EventsQueryRunner(query=EventsQuery(select=["event"], limit=50), team=self.team).calculate() sync_execute("SYSTEM FLUSH LOGS") @@ -881,7 +903,10 @@ def test_usage_report_survey_responses(self, billing_task_mock: MagicMock, posth _create_event( distinct_id="3", event="survey sent", - properties={"$survey_id": "seeeep-o12-as124", "$survey_response": "correct"}, + properties={ + "$survey_id": "seeeep-o12-as124", + "$survey_response": "correct", + }, timestamp=now() - relativedelta(hours=i), team=self.analytics_team, ) @@ -890,7 +915,10 @@ def test_usage_report_survey_responses(self, billing_task_mock: MagicMock, posth _create_event( distinct_id="4", event="survey sent", - properties={"$survey_id": "see22eep-o12-as124", "$survey_response": "correct"}, + properties={ + "$survey_id": "see22eep-o12-as124", + "$survey_response": "correct", + }, timestamp=now() - relativedelta(hours=i), team=self.org_1_team_1, ) @@ -958,17 +986,42 @@ def setUp(self) -> None: self.team2 = Team.objects.create(organization=self.organization) - _create_event(event="$pageview", team=self.team, distinct_id=1, timestamp="2021-10-08T14:01:01Z") - _create_event(event="$pageview", team=self.team, distinct_id=1, timestamp="2021-10-09T12:01:01Z") - _create_event(event="$pageview", team=self.team, distinct_id=1, timestamp="2021-10-09T13:01:01Z") + _create_event( + event="$pageview", + team=self.team, + distinct_id=1, + timestamp="2021-10-08T14:01:01Z", + ) + _create_event( + event="$pageview", + team=self.team, + distinct_id=1, + timestamp="2021-10-09T12:01:01Z", + ) + _create_event( + event="$pageview", + team=self.team, + distinct_id=1, + timestamp="2021-10-09T13:01:01Z", + ) _create_event( event="$$internal_metrics_shouldnt_be_billed", team=self.team, distinct_id=1, timestamp="2021-10-09T13:01:01Z", ) - _create_event(event="$pageview", team=self.team2, distinct_id=1, timestamp="2021-10-09T14:01:01Z") - _create_event(event="$pageview", team=self.team, distinct_id=1, timestamp="2021-10-10T14:01:01Z") + _create_event( + event="$pageview", + team=self.team2, + distinct_id=1, + timestamp="2021-10-09T14:01:01Z", + ) + _create_event( + event="$pageview", + team=self.team, + distinct_id=1, + timestamp="2021-10-10T14:01:01Z", + ) flush_persons_and_events() TEST_clear_instance_license_cache() @@ -1041,7 +1094,10 @@ def test_send_usage_cloud(self, mock_post: MagicMock, mock_client: MagicMock) -> period_start, period_end = period all_reports = _get_all_org_reports(period_start, period_end) full_report_as_dict = _get_full_org_usage_report_as_dict( - _get_full_org_usage_report(all_reports[str(self.organization.id)], get_instance_metadata(period)) + _get_full_org_usage_report( + all_reports[str(self.organization.id)], + get_instance_metadata(period), + ) ) send_all_org_usage_reports(dry_run=False) license = License.objects.first() @@ -1057,7 +1113,10 @@ def test_send_usage_cloud(self, mock_post: MagicMock, mock_client: MagicMock) -> self.user.distinct_id, "organization usage report", {**full_report_as_dict, "scope": "user"}, - groups={"instance": "http://localhost:8000", "organization": str(self.organization.id)}, + groups={ + "instance": "http://localhost:8000", + "organization": str(self.organization.id), + }, timestamp=None, ) @@ -1134,7 +1193,13 @@ def test_capture_event_called_with_string_timestamp(self, mock_client: MagicMock organization = Organization.objects.create() mock_posthog = MagicMock() mock_client.return_value = mock_posthog - capture_event(mock_client, "test event", organization.id, {"prop1": "val1"}, "2021-10-10T23:01:00.00Z") + capture_event( + mock_client, + "test event", + organization.id, + {"prop1": "val1"}, + "2021-10-10T23:01:00.00Z", + ) assert mock_client.capture.call_args[1]["timestamp"] == datetime(2021, 10, 10, 23, 1, tzinfo=tzutc()) @@ -1158,11 +1223,36 @@ class SendUsageNoLicenseTest(APIBaseTest): def test_no_license(self, mock_post: MagicMock, mock_client: MagicMock) -> None: TEST_clear_instance_license_cache() # Same test, we just don't include the LicensedTestMixin so no license - _create_event(event="$pageview", team=self.team, distinct_id=1, timestamp="2021-10-08T14:01:01Z") - _create_event(event="$pageview", team=self.team, distinct_id=1, timestamp="2021-10-09T12:01:01Z") - _create_event(event="$pageview", team=self.team, distinct_id=1, timestamp="2021-10-09T13:01:01Z") - _create_event(event="$pageview", team=self.team, distinct_id=1, timestamp="2021-10-09T14:01:01Z") - _create_event(event="$pageview", team=self.team, distinct_id=1, timestamp="2021-10-10T14:01:01Z") + _create_event( + event="$pageview", + team=self.team, + distinct_id=1, + timestamp="2021-10-08T14:01:01Z", + ) + _create_event( + event="$pageview", + team=self.team, + distinct_id=1, + timestamp="2021-10-09T12:01:01Z", + ) + _create_event( + event="$pageview", + team=self.team, + distinct_id=1, + timestamp="2021-10-09T13:01:01Z", + ) + _create_event( + event="$pageview", + team=self.team, + distinct_id=1, + timestamp="2021-10-09T14:01:01Z", + ) + _create_event( + event="$pageview", + team=self.team, + distinct_id=1, + timestamp="2021-10-10T14:01:01Z", + ) flush_persons_and_events() diff --git a/posthog/tasks/usage_report.py b/posthog/tasks/usage_report.py index b150a75f88f12..a9a06ecbff7c5 100644 --- a/posthog/tasks/usage_report.py +++ b/posthog/tasks/usage_report.py @@ -41,7 +41,13 @@ from posthog.models.team.team import Team from posthog.models.utils import namedtuplefetchall from posthog.settings import CLICKHOUSE_CLUSTER, INSTANCE_TAG -from posthog.utils import get_helm_info_env, get_instance_realm, get_instance_region, get_machine_id, get_previous_day +from posthog.utils import ( + get_helm_info_env, + get_instance_realm, + get_instance_region, + get_machine_id, + get_previous_day, +) logger = structlog.get_logger(__name__) @@ -174,7 +180,10 @@ def get_instance_metadata(period: Tuple[datetime, datetime]) -> InstanceMetadata metadata = InstanceMetadata( deployment_infrastructure=os.getenv("DEPLOYMENT", "unknown"), realm=realm, - period={"start_inclusive": period_start.isoformat(), "end_inclusive": period_end.isoformat()}, + period={ + "start_inclusive": period_start.isoformat(), + "end_inclusive": period_end.isoformat(), + }, site_url=settings.SITE_URL, product=get_product_name(realm, has_license), # Non-cloud vars @@ -197,7 +206,12 @@ def get_instance_metadata(period: Tuple[datetime, datetime]) -> InstanceMetadata metadata.users_who_logged_in = [ {"id": user.id, "distinct_id": user.distinct_id} if user.anonymize_data - else {"id": user.id, "distinct_id": user.distinct_id, "first_name": user.first_name, "email": user.email} + else { + "id": user.id, + "distinct_id": user.distinct_id, + "first_name": user.first_name, + "email": user.email, + } for user in User.objects.filter(is_active=True, last_login__gte=period_start, last_login__lte=period_end) ] metadata.users_who_logged_in_count = len(metadata.users_who_logged_in) @@ -205,8 +219,17 @@ def get_instance_metadata(period: Tuple[datetime, datetime]) -> InstanceMetadata metadata.users_who_signed_up = [ {"id": user.id, "distinct_id": user.distinct_id} if user.anonymize_data - else {"id": user.id, "distinct_id": user.distinct_id, "first_name": user.first_name, "email": user.email} - for user in User.objects.filter(is_active=True, date_joined__gte=period_start, date_joined__lte=period_end) + else { + "id": user.id, + "distinct_id": user.distinct_id, + "first_name": user.first_name, + "email": user.email, + } + for user in User.objects.filter( + is_active=True, + date_joined__gte=period_start, + date_joined__lte=period_end, + ) ] metadata.users_who_signed_up_count = len(metadata.users_who_signed_up) @@ -243,7 +266,8 @@ def get_org_owner_or_first_user(organization_id: str) -> Optional[User]: user = membership.user else: capture_exception( - Exception("No user found for org while generating report"), {"org": {"organization_id": organization_id}} + Exception("No user found for org while generating report"), + {"org": {"organization_id": organization_id}}, ) return user @@ -288,7 +312,12 @@ def send_report_to_billing_service(org_id: str, report: Dict[str, Any]) -> None: logger.error(f"UsageReport failed sending to Billing for organization: {organization.id}: {err}") capture_exception(err) pha_client = Client("sTMFPsFhdP1Ssg") - capture_event(pha_client, f"organization usage report to billing service failure", org_id, {"err": str(err)}) + capture_event( + pha_client, + f"organization usage report to billing service failure", + org_id, + {"err": str(err)}, + ) raise err @@ -496,7 +525,12 @@ def get_teams_with_hogql_metric( AND access_method = %(access_method)s GROUP BY team_id """, - {"begin": begin, "end": end, "query_types": query_types, "access_method": access_method}, + { + "begin": begin, + "end": end, + "query_types": query_types, + "access_method": access_method, + }, workload=Workload.OFFLINE, settings=CH_BILLING_SETTINGS, ) @@ -559,7 +593,10 @@ def get_teams_with_survey_responses_count_in_period( @app.task(ignore_result=True, max_retries=0) def capture_report( - capture_event_name: str, org_id: str, full_report_dict: Dict[str, Any], at_date: Optional[datetime] = None + capture_event_name: str, + org_id: str, + full_report_dict: Dict[str, Any], + at_date: Optional[datetime] = None, ) -> None: pha_client = Client("sTMFPsFhdP1Ssg") try: @@ -821,7 +858,10 @@ def _get_team_report(all_data: Dict[str, Any], team: Team) -> UsageReportCounter def _add_team_report_to_org_reports( - org_reports: Dict[str, OrgReport], team: Team, team_report: UsageReportCounters, period_start: datetime + org_reports: Dict[str, OrgReport], + team: Team, + team_report: UsageReportCounters, + period_start: datetime, ) -> None: org_id = str(team.organization.id) if org_id not in org_reports: diff --git a/posthog/tasks/user_identify.py b/posthog/tasks/user_identify.py index 9235410582eca..93dd0c851dbe8 100644 --- a/posthog/tasks/user_identify.py +++ b/posthog/tasks/user_identify.py @@ -6,6 +6,9 @@ @app.task(ignore_result=True) def identify_task(user_id: int) -> None: - user = User.objects.get(id=user_id) - posthoganalytics.capture(user.distinct_id, "update user properties", {"$set": user.get_analytics_metadata()}) + posthoganalytics.capture( + user.distinct_id, + "update user properties", + {"$set": user.get_analytics_metadata()}, + ) diff --git a/posthog/tasks/verify_persons_data_in_sync.py b/posthog/tasks/verify_persons_data_in_sync.py index d5cf24d9ad220..8aea487d96279 100644 --- a/posthog/tasks/verify_persons_data_in_sync.py +++ b/posthog/tasks/verify_persons_data_in_sync.py @@ -53,7 +53,9 @@ def verify_persons_data_in_sync( max_pk = Person.objects.filter(created_at__lte=now() - period_start).latest("id").id person_data = list( Person.objects.filter( - pk__lte=max_pk, pk__gte=max_pk - LIMIT * 5, created_at__gte=now() - period_end + pk__lte=max_pk, + pk__gte=max_pk - LIMIT * 5, + created_at__gte=now() - period_end, ).values_list("id", "uuid", "team_id")[:limit] ) person_data.sort(key=lambda row: row[2]) # keep persons from same team together @@ -94,11 +96,15 @@ def _team_integrity_statistics(person_data: List[Any]) -> Counter: ) ch_persons = _index_by( - sync_execute(GET_PERSON_CH_QUERY, {"person_ids": person_uuids, "team_ids": team_ids}), lambda row: row[0] + sync_execute(GET_PERSON_CH_QUERY, {"person_ids": person_uuids, "team_ids": team_ids}), + lambda row: row[0], ) ch_distinct_ids_mapping = _index_by( - sync_execute(GET_DISTINCT_IDS_CH_QUERY, {"person_ids": person_uuids, "team_ids": team_ids}), + sync_execute( + GET_DISTINCT_IDS_CH_QUERY, + {"person_ids": person_uuids, "team_ids": team_ids}, + ), lambda row: row[1], flat=False, ) diff --git a/posthog/temporal/client.py b/posthog/temporal/client.py index e98687a6f7659..df6dc1cc81e74 100644 --- a/posthog/temporal/client.py +++ b/posthog/temporal/client.py @@ -8,7 +8,15 @@ from posthog.temporal.codec import EncryptionCodec -async def connect(host, port, namespace, server_root_ca_cert=None, client_cert=None, client_key=None, runtime=None): +async def connect( + host, + port, + namespace, + server_root_ca_cert=None, + client_cert=None, + client_key=None, + runtime=None, +): tls: TLSConfig | bool = False if server_root_ca_cert and client_cert and client_key: tls = TLSConfig( @@ -22,7 +30,8 @@ async def connect(host, port, namespace, server_root_ca_cert=None, client_cert=N tls=tls, runtime=runtime, data_converter=dataclasses.replace( - temporalio.converter.default(), payload_codec=EncryptionCodec(settings=settings) + temporalio.converter.default(), + payload_codec=EncryptionCodec(settings=settings), ), ) return client diff --git a/posthog/temporal/tests/batch_exports/test_batch_exports.py b/posthog/temporal/tests/batch_exports/test_batch_exports.py index a760baed9d4b0..e59d6c178c7f1 100644 --- a/posthog/temporal/tests/batch_exports/test_batch_exports.py +++ b/posthog/temporal/tests/batch_exports/test_batch_exports.py @@ -253,7 +253,11 @@ async def test_get_rows_count_can_exclude_events(client): # Exclude the latter half of events. exclude_events = (f"test-{i}" for i in range(5000, 10000)) row_count = await get_rows_count( - client, team_id, "2023-04-20 14:30:00", "2023-04-20 14:31:00", exclude_events=exclude_events + client, + team_id, + "2023-04-20 14:30:00", + "2023-04-20 14:31:00", + exclude_events=exclude_events, ) assert row_count == 5000 @@ -302,7 +306,11 @@ async def test_get_rows_count_can_include_events(client): # Include the latter half of events. include_events = (f"test-{i}" for i in range(5000, 10000)) row_count = await get_rows_count( - client, team_id, "2023-04-20 14:30:00", "2023-04-20 14:31:00", include_events=include_events + client, + team_id, + "2023-04-20 14:30:00", + "2023-04-20 14:31:00", + include_events=include_events, ) assert row_count == 5000 @@ -715,7 +723,13 @@ def test_batch_export_temporary_file_write_records_to_csv(records): assert be_file.records_since_last_reset == len(records) be_file.seek(0) - reader = csv.reader(be_file._file, delimiter=",", quotechar='"', escapechar="\\", quoting=csv.QUOTE_NONE) + reader = csv.reader( + be_file._file, + delimiter=",", + quotechar='"', + escapechar="\\", + quoting=csv.QUOTE_NONE, + ) rows = [row for row in reader] assert len(rows) == len(records) @@ -761,7 +775,13 @@ def test_batch_export_temporary_file_write_records_to_tsv(records): assert be_file.records_since_last_reset == len(records) be_file.seek(0) - reader = csv.reader(be_file._file, delimiter="\t", quotechar='"', escapechar="\\", quoting=csv.QUOTE_NONE) + reader = csv.reader( + be_file._file, + delimiter="\t", + quotechar='"', + escapechar="\\", + quoting=csv.QUOTE_NONE, + ) rows = [row for row in reader] assert len(rows) == len(records) diff --git a/posthog/temporal/tests/batch_exports/test_bigquery_batch_export_workflow.py b/posthog/temporal/tests/batch_exports/test_bigquery_batch_export_workflow.py index 5abec97d3e4ad..f28be3815d846 100644 --- a/posthog/temporal/tests/batch_exports/test_bigquery_batch_export_workflow.py +++ b/posthog/temporal/tests/batch_exports/test_bigquery_batch_export_workflow.py @@ -283,7 +283,10 @@ async def test_bigquery_export_workflow( team = await acreate_team(organization=organization) test_table_id = f"test_workflow_table_{team.pk}_{interval}" - destination_data = {"type": "BigQuery", "config": {**bigquery_config, "table_id": test_table_id}} + destination_data = { + "type": "BigQuery", + "config": {**bigquery_config, "table_id": test_table_id}, + } batch_export_data = { "name": "my-production-bigquery-export", "destination": destination_data, @@ -385,12 +388,16 @@ async def test_bigquery_export_workflow( ) with freeze_time(TEST_TIME) as frozen_time: - async with await WorkflowEnvironment.start_time_skipping() as activity_environment: + async with await (WorkflowEnvironment.start_time_skipping()) as activity_environment: async with Worker( activity_environment.client, task_queue=settings.TEMPORAL_TASK_QUEUE, workflows=[BigQueryBatchExportWorkflow], - activities=[create_export_run, insert_into_bigquery_activity, update_export_run_status], + activities=[ + create_export_run, + insert_into_bigquery_activity, + update_export_run_status, + ], workflow_runner=UnsandboxedWorkflowRunner(), ): await activity_environment.client.execute_workflow( @@ -493,7 +500,11 @@ async def insert_into_bigquery_activity_mocked(_: BigQueryInsertInputs) -> str: activity_environment.client, task_queue=settings.TEMPORAL_TASK_QUEUE, workflows=[BigQueryBatchExportWorkflow], - activities=[create_export_run, insert_into_bigquery_activity_mocked, update_export_run_status], + activities=[ + create_export_run, + insert_into_bigquery_activity_mocked, + update_export_run_status, + ], workflow_runner=UnsandboxedWorkflowRunner(), ): with pytest.raises(WorkflowFailureError): @@ -536,7 +547,11 @@ async def never_finish_activity(_: BigQueryInsertInputs) -> str: activity_environment.client, task_queue=settings.TEMPORAL_TASK_QUEUE, workflows=[BigQueryBatchExportWorkflow], - activities=[create_export_run, never_finish_activity, update_export_run_status], + activities=[ + create_export_run, + never_finish_activity, + update_export_run_status, + ], workflow_runner=UnsandboxedWorkflowRunner(), ): handle = await activity_environment.client.start_workflow( diff --git a/posthog/temporal/tests/batch_exports/test_postgres_batch_export_workflow.py b/posthog/temporal/tests/batch_exports/test_postgres_batch_export_workflow.py index e7ae1a7d09144..d7ca05c0784b6 100644 --- a/posthog/temporal/tests/batch_exports/test_postgres_batch_export_workflow.py +++ b/posthog/temporal/tests/batch_exports/test_postgres_batch_export_workflow.py @@ -110,7 +110,10 @@ def setup_test_db(postgres_config): connection.set_session(autocommit=True) with connection.cursor() as cursor: - cursor.execute(sql.SQL("SELECT 1 FROM pg_database WHERE datname = %s"), (postgres_config["database"],)) + cursor.execute( + sql.SQL("SELECT 1 FROM pg_database WHERE datname = %s"), + (postgres_config["database"],), + ) if cursor.fetchone() is None: cursor.execute(sql.SQL("CREATE DATABASE {}").format(sql.Identifier(postgres_config["database"]))) @@ -322,7 +325,10 @@ async def test_postgres_export_workflow( ): """Test Postgres Export Workflow end-to-end by using a local PG database.""" table_name = "test_workflow_table" - destination_data = {"type": "Postgres", "config": {**postgres_config, "table_name": table_name}} + destination_data = { + "type": "Postgres", + "config": {**postgres_config, "table_name": table_name}, + } batch_export_data = { "name": "my-production-postgres-export", "destination": destination_data, @@ -430,7 +436,11 @@ async def test_postgres_export_workflow( activity_environment.client, task_queue=settings.TEMPORAL_TASK_QUEUE, workflows=[PostgresBatchExportWorkflow], - activities=[create_export_run, insert_into_postgres_activity, update_export_run_status], + activities=[ + create_export_run, + insert_into_postgres_activity, + update_export_run_status, + ], workflow_runner=UnsandboxedWorkflowRunner(), ): with override_settings(BATCH_EXPORT_POSTGRES_UPLOAD_CHUNK_SIZE_BYTES=5 * 1024**2): @@ -469,7 +479,10 @@ async def team(organization): @pytest_asyncio.fixture async def batch_export(team, postgres_config): table_name = "test_workflow_table" - destination_data = {"type": "Postgres", "config": {**postgres_config, "table_name": table_name}} + destination_data = { + "type": "Postgres", + "config": {**postgres_config, "table_name": table_name}, + } batch_export_data = { "name": "my-production-postgres-export", "destination": destination_data, @@ -517,7 +530,11 @@ async def insert_into_postgres_activity_mocked(_: PostgresInsertInputs) -> str: activity_environment.client, task_queue=settings.TEMPORAL_TASK_QUEUE, workflows=[PostgresBatchExportWorkflow], - activities=[create_export_run, insert_into_postgres_activity_mocked, update_export_run_status], + activities=[ + create_export_run, + insert_into_postgres_activity_mocked, + update_export_run_status, + ], workflow_runner=UnsandboxedWorkflowRunner(), ): with pytest.raises(WorkflowFailureError): @@ -560,7 +577,11 @@ async def never_finish_activity(_: PostgresInsertInputs) -> str: activity_environment.client, task_queue=settings.TEMPORAL_TASK_QUEUE, workflows=[PostgresBatchExportWorkflow], - activities=[create_export_run, never_finish_activity, update_export_run_status], + activities=[ + create_export_run, + never_finish_activity, + update_export_run_status, + ], workflow_runner=UnsandboxedWorkflowRunner(), ): handle = await activity_environment.client.start_workflow( diff --git a/posthog/temporal/tests/batch_exports/test_s3_batch_export_workflow.py b/posthog/temporal/tests/batch_exports/test_s3_batch_export_workflow.py index 8dd8636a87e56..3487c612808f3 100644 --- a/posthog/temporal/tests/batch_exports/test_s3_batch_export_workflow.py +++ b/posthog/temporal/tests/batch_exports/test_s3_batch_export_workflow.py @@ -105,7 +105,12 @@ async def s3_client(bucket_name): async def assert_events_in_s3( - s3_client, bucket_name, key_prefix, events, compression: str | None = None, exclude_events: list[str] | None = None + s3_client, + bucket_name, + key_prefix, + events, + compression: str | None = None, + exclude_events: list[str] | None = None, ): """Assert provided events written to JSON in key_prefix in S3 bucket_name.""" # List the objects in the bucket with the prefix. @@ -148,7 +153,12 @@ def to_expected_event(event): k: mapping_functions.get(k, lambda x: x)(v) for k, v in event.items() if k not in ["team_id", "_timestamp"] } - expected_events = list(map(to_expected_event, (event for event in events if event["event"] not in exclude_events))) + expected_events = list( + map( + to_expected_event, + (event for event in events if event["event"] not in exclude_events), + ) + ) expected_events.sort(key=lambda x: x["timestamp"] if x["timestamp"] is not None else 0) @@ -309,7 +319,8 @@ async def test_insert_into_s3_activity_puts_data_into_s3( BATCH_EXPORT_S3_UPLOAD_CHUNK_SIZE_BYTES=5 * 1024**2 ): # 5MB, the minimum for Multipart uploads with mock.patch( - "posthog.temporal.workflows.s3_batch_export.aioboto3.Session.client", side_effect=create_test_client + "posthog.temporal.workflows.s3_batch_export.aioboto3.Session.client", + side_effect=create_test_client, ): await activity_environment.run(insert_into_s3_activity, insert_inputs) @@ -320,7 +331,11 @@ async def test_insert_into_s3_activity_puts_data_into_s3( @pytest.mark.asyncio @pytest.mark.parametrize( "interval,compression,exclude_events", - itertools.product(["hour", "day", "every 5 minutes"], [None, "gzip", "brotli"], [None, ["test-exclude"]]), + itertools.product( + ["hour", "day", "every 5 minutes"], + [None, "gzip", "brotli"], + [None, ["test-exclude"]], + ), ) async def test_s3_export_workflow_with_minio_bucket( client: HttpClient, s3_client, bucket_name, interval, compression, exclude_events @@ -428,11 +443,16 @@ async def test_s3_export_workflow_with_minio_bucket( activity_environment.client, task_queue=settings.TEMPORAL_TASK_QUEUE, workflows=[S3BatchExportWorkflow], - activities=[create_export_run, insert_into_s3_activity, update_export_run_status], + activities=[ + create_export_run, + insert_into_s3_activity, + update_export_run_status, + ], workflow_runner=UnsandboxedWorkflowRunner(), ): with mock.patch( - "posthog.temporal.workflows.s3_batch_export.aioboto3.Session.client", side_effect=create_test_client + "posthog.temporal.workflows.s3_batch_export.aioboto3.Session.client", + side_effect=create_test_client, ): await activity_environment.client.execute_workflow( S3BatchExportWorkflow.run, @@ -581,16 +601,21 @@ async def create_s3_client(*args, **kwargs): """Mock function to return an already initialized S3 client.""" yield s3_client - async with await WorkflowEnvironment.start_time_skipping() as activity_environment: + async with await (WorkflowEnvironment.start_time_skipping()) as activity_environment: async with Worker( activity_environment.client, task_queue=settings.TEMPORAL_TASK_QUEUE, workflows=[S3BatchExportWorkflow], - activities=[create_export_run, insert_into_s3_activity, update_export_run_status], + activities=[ + create_export_run, + insert_into_s3_activity, + update_export_run_status, + ], workflow_runner=UnsandboxedWorkflowRunner(), ): with mock.patch( - "posthog.temporal.workflows.s3_batch_export.aioboto3.Session.client", side_effect=create_s3_client + "posthog.temporal.workflows.s3_batch_export.aioboto3.Session.client", + side_effect=create_s3_client, ): await activity_environment.client.execute_workflow( S3BatchExportWorkflow.run, @@ -691,11 +716,16 @@ async def test_s3_export_workflow_with_minio_bucket_and_a_lot_of_data(s3_client, activity_environment.client, task_queue=settings.TEMPORAL_TASK_QUEUE, workflows=[S3BatchExportWorkflow], - activities=[create_export_run, insert_into_s3_activity, update_export_run_status], + activities=[ + create_export_run, + insert_into_s3_activity, + update_export_run_status, + ], workflow_runner=UnsandboxedWorkflowRunner(), ): with mock.patch( - "posthog.temporal.workflows.s3_batch_export.aioboto3.Session.client", side_effect=create_test_client + "posthog.temporal.workflows.s3_batch_export.aioboto3.Session.client", + side_effect=create_test_client, ): await activity_environment.client.execute_workflow( S3BatchExportWorkflow.run, @@ -713,7 +743,11 @@ async def test_s3_export_workflow_with_minio_bucket_and_a_lot_of_data(s3_client, assert run.status == "Completed" await assert_events_in_s3( - s3_client, bucket_name, prefix.format(year=2023, month="04", day="25"), events, compression + s3_client, + bucket_name, + prefix.format(year=2023, month="04", day="25"), + events, + compression, ) @@ -811,11 +845,16 @@ async def test_s3_export_workflow_defaults_to_timestamp_on_null_inserted_at(s3_c activity_environment.client, task_queue=settings.TEMPORAL_TASK_QUEUE, workflows=[S3BatchExportWorkflow], - activities=[create_export_run, insert_into_s3_activity, update_export_run_status], + activities=[ + create_export_run, + insert_into_s3_activity, + update_export_run_status, + ], workflow_runner=UnsandboxedWorkflowRunner(), ): with mock.patch( - "posthog.temporal.workflows.s3_batch_export.aioboto3.Session.client", side_effect=create_test_client + "posthog.temporal.workflows.s3_batch_export.aioboto3.Session.client", + side_effect=create_test_client, ): await activity_environment.client.execute_workflow( S3BatchExportWorkflow.run, @@ -914,11 +953,16 @@ async def test_s3_export_workflow_with_minio_bucket_and_custom_key_prefix(s3_cli activity_environment.client, task_queue=settings.TEMPORAL_TASK_QUEUE, workflows=[S3BatchExportWorkflow], - activities=[create_export_run, insert_into_s3_activity, update_export_run_status], + activities=[ + create_export_run, + insert_into_s3_activity, + update_export_run_status, + ], workflow_runner=UnsandboxedWorkflowRunner(), ): with mock.patch( - "posthog.temporal.workflows.s3_batch_export.aioboto3.Session.client", side_effect=create_test_client + "posthog.temporal.workflows.s3_batch_export.aioboto3.Session.client", + side_effect=create_test_client, ): await activity_environment.client.execute_workflow( S3BatchExportWorkflow.run, @@ -936,7 +980,13 @@ async def test_s3_export_workflow_with_minio_bucket_and_custom_key_prefix(s3_cli assert run.status == "Completed" expected_key_prefix = prefix.format( - table="events", year="2023", month="04", day="25", hour="14", minute="30", second="00" + table="events", + year="2023", + month="04", + day="25", + hour="14", + minute="30", + second="00", ) objects = await s3_client.list_objects_v2(Bucket=bucket_name, Prefix=expected_key_prefix) key = objects["Contents"][0].get("Key") @@ -1058,11 +1108,16 @@ async def test_s3_export_workflow_with_minio_bucket_produces_no_duplicates(s3_cl activity_environment.client, task_queue=settings.TEMPORAL_TASK_QUEUE, workflows=[S3BatchExportWorkflow], - activities=[create_export_run, insert_into_s3_activity, update_export_run_status], + activities=[ + create_export_run, + insert_into_s3_activity, + update_export_run_status, + ], workflow_runner=UnsandboxedWorkflowRunner(), ): with mock.patch( - "posthog.temporal.workflows.s3_batch_export.aioboto3.Session.client", side_effect=create_test_client + "posthog.temporal.workflows.s3_batch_export.aioboto3.Session.client", + side_effect=create_test_client, ): await activity_environment.client.execute_workflow( S3BatchExportWorkflow.run, @@ -1157,7 +1212,11 @@ async def insert_into_s3_activity_mocked(_: S3InsertInputs) -> str: activity_environment.client, task_queue=settings.TEMPORAL_TASK_QUEUE, workflows=[S3BatchExportWorkflow], - activities=[create_export_run, insert_into_s3_activity_mocked, update_export_run_status], + activities=[ + create_export_run, + insert_into_s3_activity_mocked, + update_export_run_status, + ], workflow_runner=UnsandboxedWorkflowRunner(), ): with pytest.raises(WorkflowFailureError): @@ -1200,7 +1259,11 @@ async def never_finish_activity(_: S3InsertInputs) -> str: activity_environment.client, task_queue=settings.TEMPORAL_TASK_QUEUE, workflows=[S3BatchExportWorkflow], - activities=[create_export_run, never_finish_activity, update_export_run_status], + activities=[ + create_export_run, + never_finish_activity, + update_export_run_status, + ], workflow_runner=UnsandboxedWorkflowRunner(), ): handle = await activity_environment.client.start_workflow( @@ -1536,7 +1599,8 @@ def assert_heartbeat_details(*details): with override_settings(BATCH_EXPORT_S3_UPLOAD_CHUNK_SIZE_BYTES=5 * 1024**2): with mock.patch( - "posthog.temporal.workflows.s3_batch_export.aioboto3.Session.client", side_effect=create_test_client + "posthog.temporal.workflows.s3_batch_export.aioboto3.Session.client", + side_effect=create_test_client, ): await activity_environment.run(insert_into_s3_activity, insert_inputs) diff --git a/posthog/temporal/tests/batch_exports/test_snowflake_batch_export_workflow.py b/posthog/temporal/tests/batch_exports/test_snowflake_batch_export_workflow.py index 3a92f9fad84b4..2205977459b91 100644 --- a/posthog/temporal/tests/batch_exports/test_snowflake_batch_export_workflow.py +++ b/posthog/temporal/tests/batch_exports/test_snowflake_batch_export_workflow.py @@ -89,7 +89,18 @@ def query_request_handler(request: PreparedRequest): staged_files.append(f.read()) if fail == "put": - rowset = [("test", "test.gz", 456, 0, "NONE", "GZIP", "FAILED", "Some error on put")] + rowset = [ + ( + "test", + "test.gz", + 456, + 0, + "NONE", + "GZIP", + "FAILED", + "Some error on put", + ) + ] else: if fail == "copy": @@ -186,7 +197,12 @@ def query_request_handler(request: PreparedRequest): "https://account.snowflakecomputing.com:443/session/v1/login-request", json={ "success": True, - "data": {"token": "test-token", "masterToken": "test-token", "code": None, "message": None}, + "data": { + "token": "test-token", + "masterToken": "test-token", + "code": None, + "message": None, + }, }, ) rsps.add_callback( @@ -335,7 +351,11 @@ async def test_snowflake_export_workflow_exports_events_in_the_last_hour_for_the activity_environment.client, task_queue=settings.TEMPORAL_TASK_QUEUE, workflows=[SnowflakeBatchExportWorkflow], - activities=[create_export_run, insert_into_snowflake_activity, update_export_run_status], + activities=[ + create_export_run, + insert_into_snowflake_activity, + update_export_run_status, + ], workflow_runner=UnsandboxedWorkflowRunner(), ): with responses.RequestsMock( @@ -414,7 +434,11 @@ async def test_snowflake_export_workflow_exports_events_in_the_last_hour_for_the activity_environment.client, task_queue=settings.TEMPORAL_TASK_QUEUE, workflows=[SnowflakeBatchExportWorkflow], - activities=[create_export_run, insert_into_snowflake_activity, update_export_run_status], + activities=[ + create_export_run, + insert_into_snowflake_activity, + update_export_run_status, + ], workflow_runner=UnsandboxedWorkflowRunner(), ): with responses.RequestsMock( @@ -534,7 +558,11 @@ async def test_snowflake_export_workflow_raises_error_on_put_fail(): activity_environment.client, task_queue=settings.TEMPORAL_TASK_QUEUE, workflows=[SnowflakeBatchExportWorkflow], - activities=[create_export_run, insert_into_snowflake_activity, update_export_run_status], + activities=[ + create_export_run, + insert_into_snowflake_activity, + update_export_run_status, + ], workflow_runner=UnsandboxedWorkflowRunner(), ): with responses.RequestsMock( @@ -633,7 +661,11 @@ async def test_snowflake_export_workflow_raises_error_on_copy_fail(): activity_environment.client, task_queue=settings.TEMPORAL_TASK_QUEUE, workflows=[SnowflakeBatchExportWorkflow], - activities=[create_export_run, insert_into_snowflake_activity, update_export_run_status], + activities=[ + create_export_run, + insert_into_snowflake_activity, + update_export_run_status, + ], workflow_runner=UnsandboxedWorkflowRunner(), ): with responses.RequestsMock( @@ -732,7 +764,11 @@ async def insert_into_snowflake_activity_mocked(_: SnowflakeInsertInputs) -> str activity_environment.client, task_queue=settings.TEMPORAL_TASK_QUEUE, workflows=[SnowflakeBatchExportWorkflow], - activities=[create_export_run, insert_into_snowflake_activity_mocked, update_export_run_status], + activities=[ + create_export_run, + insert_into_snowflake_activity_mocked, + update_export_run_status, + ], workflow_runner=UnsandboxedWorkflowRunner(), ): with pytest.raises(WorkflowFailureError): @@ -775,7 +811,11 @@ async def never_finish_activity(_: SnowflakeInsertInputs) -> str: activity_environment.client, task_queue=settings.TEMPORAL_TASK_QUEUE, workflows=[SnowflakeBatchExportWorkflow], - activities=[create_export_run, never_finish_activity, update_export_run_status], + activities=[ + create_export_run, + never_finish_activity, + update_export_run_status, + ], workflow_runner=UnsandboxedWorkflowRunner(), ): handle = await activity_environment.client.start_workflow( diff --git a/posthog/temporal/tests/test_clickhouse.py b/posthog/temporal/tests/test_clickhouse.py index 9f5798b2e877c..d31d6c2b5dd59 100644 --- a/posthog/temporal/tests/test_clickhouse.py +++ b/posthog/temporal/tests/test_clickhouse.py @@ -9,7 +9,10 @@ @pytest.mark.parametrize( "data,expected", [ - (uuid.UUID("c4c5547d-8782-4017-8eca-3ea19f4d528e"), b"'c4c5547d-8782-4017-8eca-3ea19f4d528e'"), + ( + uuid.UUID("c4c5547d-8782-4017-8eca-3ea19f4d528e"), + b"'c4c5547d-8782-4017-8eca-3ea19f4d528e'", + ), ("", b"''"), ("'", b"'\\''"), ("\\", b"'\\\\'"), @@ -19,7 +22,10 @@ (["a", 1, ["b", 2]], b"['a',1,['b',2]]"), (("; DROP TABLE events --",), b"('; DROP TABLE events --')"), (("'a'); DROP TABLE events --",), b"('\\'a\\'); DROP TABLE events --')"), - (dt.datetime(2023, 7, 14, 0, 0, 0, tzinfo=dt.timezone.utc), b"toDateTime('2023-07-14 00:00:00', 'UTC')"), + ( + dt.datetime(2023, 7, 14, 0, 0, 0, tzinfo=dt.timezone.utc), + b"toDateTime('2023-07-14 00:00:00', 'UTC')", + ), (dt.datetime(2023, 7, 14, 0, 0, 0), b"toDateTime('2023-07-14 00:00:00')"), ( dt.datetime(2023, 7, 14, 0, 0, 0, 5555, tzinfo=dt.timezone.utc), diff --git a/posthog/temporal/tests/test_squash_person_overrides_workflow.py b/posthog/temporal/tests/test_squash_person_overrides_workflow.py index d3040583bfad5..8cde17ccb42d1 100644 --- a/posthog/temporal/tests/test_squash_person_overrides_workflow.py +++ b/posthog/temporal/tests/test_squash_person_overrides_workflow.py @@ -41,10 +41,19 @@ @pytest.mark.parametrize( "inputs,expected", [ - ({"partition_ids": None, "last_n_months": 5}, ["202303", "202302", "202301", "202212", "202211"]), + ( + {"partition_ids": None, "last_n_months": 5}, + ["202303", "202302", "202301", "202212", "202211"], + ), ({"last_n_months": 1}, ["202303"]), - ({"partition_ids": ["202303", "202302"], "last_n_months": 3}, ["202303", "202302"]), - ({"partition_ids": ["202303", "202302"], "last_n_months": None}, ["202303", "202302"]), + ( + {"partition_ids": ["202303", "202302"], "last_n_months": 3}, + ["202303", "202302"], + ), + ( + {"partition_ids": ["202303", "202302"], "last_n_months": None}, + ["202303", "202302"], + ), ], ) def test_workflow_inputs_yields_partition_ids(inputs, expected): @@ -490,7 +499,10 @@ def events_to_override(person_overrides_data): } all_test_events.append(values) - sync_execute("INSERT INTO sharded_events (uuid, event, timestamp, team_id, person_id) VALUES", all_test_events) + sync_execute( + "INSERT INTO sharded_events (uuid, event, timestamp, team_id, person_id) VALUES", + all_test_events, + ) yield all_test_events @@ -505,7 +517,8 @@ def assert_events_have_been_overriden(overriden_events, person_overrides): """ for event in overriden_events: rows = sync_execute( - "SELECT uuid, event, team_id, person_id FROM events WHERE uuid = %(uuid)s", {"uuid": event["uuid"]} + "SELECT uuid, event, team_id, person_id FROM events WHERE uuid = %(uuid)s", + {"uuid": event["uuid"]}, ) new_event = { "uuid": rows[0][0], @@ -569,7 +582,8 @@ async def test_squash_events_partition_dry_run( for event in events_to_override: rows = sync_execute( - "SELECT uuid, event, team_id, person_id FROM events WHERE uuid = %(uuid)s", {"uuid": event["uuid"]} + "SELECT uuid, event, team_id, person_id FROM events WHERE uuid = %(uuid)s", + {"uuid": event["uuid"]}, ) new_event = { "uuid": rows[0][0], @@ -586,7 +600,11 @@ async def test_squash_events_partition_dry_run( @pytest.mark.django_db @pytest.mark.asyncio async def test_squash_events_partition_with_older_overrides( - query_inputs, activity_environment, person_overrides_data, events_to_override, older_overrides + query_inputs, + activity_environment, + person_overrides_data, + events_to_override, + older_overrides, ): """Test events are properly squashed even in the prescence of older overrides. @@ -613,7 +631,11 @@ async def test_squash_events_partition_with_older_overrides( @pytest.mark.django_db @pytest.mark.asyncio async def test_squash_events_partition_with_newer_overrides( - query_inputs, activity_environment, person_overrides_data, events_to_override, newer_overrides + query_inputs, + activity_environment, + person_overrides_data, + events_to_override, + newer_overrides, ): """Test events are properly squashed even in the prescence of newer overrides. @@ -1218,7 +1240,11 @@ async def test_squash_person_overrides_workflow( @pytest.mark.django_db @pytest.mark.asyncio async def test_squash_person_overrides_workflow_with_newer_overrides( - query_inputs, events_to_override, person_overrides_data, person_overrides, newer_overrides + query_inputs, + events_to_override, + person_overrides_data, + person_overrides, + newer_overrides, ): """Test the squash_person_overrides workflow end-to-end with newer overrides.""" client = await Client.connect( diff --git a/posthog/temporal/worker.py b/posthog/temporal/worker.py index d506c29c497fb..fcae8d29d65d4 100644 --- a/posthog/temporal/worker.py +++ b/posthog/temporal/worker.py @@ -9,9 +9,25 @@ from posthog.temporal.workflows import ACTIVITIES, WORKFLOWS -async def start_worker(host, port, namespace, task_queue, server_root_ca_cert=None, client_cert=None, client_key=None): +async def start_worker( + host, + port, + namespace, + task_queue, + server_root_ca_cert=None, + client_cert=None, + client_key=None, +): runtime = Runtime(telemetry=TelemetryConfig(metrics=PrometheusConfig(bind_address="0.0.0.0:8596"))) - client = await connect(host, port, namespace, server_root_ca_cert, client_cert, client_key, runtime=runtime) + client = await connect( + host, + port, + namespace, + server_root_ca_cert, + client_cert, + client_key, + runtime=runtime, + ) worker = Worker( client, task_queue=task_queue, diff --git a/posthog/temporal/workflows/backfill_batch_export.py b/posthog/temporal/workflows/backfill_batch_export.py index 6c0e653cf6a8c..b47cbf5d8cb30 100644 --- a/posthog/temporal/workflows/backfill_batch_export.py +++ b/posthog/temporal/workflows/backfill_batch_export.py @@ -281,7 +281,10 @@ async def run(self, inputs: BackfillBatchExportInputs) -> None: """Workflow implementation to backfill a BatchExport.""" logger = get_batch_exports_logger(inputs=inputs) logger.info( - "Starting Backfill for BatchExport %s: %s - %s", inputs.batch_export_id, inputs.start_at, inputs.end_at + "Starting Backfill for BatchExport %s: %s - %s", + inputs.batch_export_id, + inputs.start_at, + inputs.end_at, ) create_batch_export_backfill_inputs = CreateBatchExportBackfillInputs( diff --git a/posthog/temporal/workflows/batch_exports.py b/posthog/temporal/workflows/batch_exports.py index c0d253852417f..bf375ada75ce7 100644 --- a/posthog/temporal/workflows/batch_exports.py +++ b/posthog/temporal/workflows/batch_exports.py @@ -649,7 +649,11 @@ class UpdateBatchExportRunStatusInputs: @activity.defn async def update_export_run_status(inputs: UpdateBatchExportRunStatusInputs): """Activity that updates the status of an BatchExportRun.""" - await sync_to_async(update_batch_export_run_status)(run_id=uuid.UUID(inputs.id), status=inputs.status, latest_error=inputs.latest_error) # type: ignore + await sync_to_async(update_batch_export_run_status)( + run_id=uuid.UUID(inputs.id), + status=inputs.status, + latest_error=inputs.latest_error, + ) # type: ignore @dataclasses.dataclass @@ -698,4 +702,6 @@ class UpdateBatchExportBackfillStatusInputs: @activity.defn async def update_batch_export_backfill_model_status(inputs: UpdateBatchExportBackfillStatusInputs): """Activity that updates the status of an BatchExportRun.""" - await sync_to_async(update_batch_export_backfill_status)(backfill_id=uuid.UUID(inputs.id), status=inputs.status) # type: ignore + await sync_to_async(update_batch_export_backfill_status)( + backfill_id=uuid.UUID(inputs.id), status=inputs.status + ) # type: ignore diff --git a/posthog/temporal/workflows/bigquery_batch_export.py b/posthog/temporal/workflows/bigquery_batch_export.py index 01a1a622633fb..09234c0db86d5 100644 --- a/posthog/temporal/workflows/bigquery_batch_export.py +++ b/posthog/temporal/workflows/bigquery_batch_export.py @@ -154,7 +154,11 @@ async def insert_into_bigquery_activity(inputs: BigQueryInsertInputs): with bigquery_client(inputs) as bq_client: bigquery_table = create_table_in_bigquery( - inputs.project_id, inputs.dataset_id, inputs.table_id, table_schema, bq_client + inputs.project_id, + inputs.dataset_id, + inputs.table_id, + table_schema, + bq_client, ) with BatchExportTemporaryFile() as jsonl_file: @@ -212,7 +216,11 @@ async def run(self, inputs: BigQueryBatchExportInputs): """Workflow implementation to export data to BigQuery.""" logger = get_batch_exports_logger(inputs=inputs) data_interval_start, data_interval_end = get_data_interval(inputs.interval, inputs.data_interval_end) - logger.info("Starting BigQuery export batch %s - %s", data_interval_start, data_interval_end) + logger.info( + "Starting BigQuery export batch %s - %s", + data_interval_start, + data_interval_end, + ) data_interval_start, data_interval_end = get_data_interval(inputs.interval, inputs.data_interval_end) @@ -289,7 +297,11 @@ async def run(self, inputs: BigQueryBatchExportInputs): raise else: - logger.info("Successfully finished BigQuery export batch %s - %s", data_interval_start, data_interval_end) + logger.info( + "Successfully finished BigQuery export batch %s - %s", + data_interval_start, + data_interval_end, + ) finally: await workflow.execute_activity( diff --git a/posthog/temporal/workflows/clickhouse.py b/posthog/temporal/workflows/clickhouse.py index 55e19b4eeb338..0c8f5d6c558e9 100644 --- a/posthog/temporal/workflows/clickhouse.py +++ b/posthog/temporal/workflows/clickhouse.py @@ -123,7 +123,10 @@ async def is_alive(self) -> bool: """ try: await self.session.get( - url=self.url, params={**self.params, "query": "SELECT 1"}, headers=self.headers, raise_for_status=True + url=self.url, + params={**self.params, "query": "SELECT 1"}, + headers=self.headers, + raise_for_status=True, ) except aiohttp.ClientResponseError: return False @@ -236,7 +239,12 @@ def post_query(self, query, *data, query_parameters, query_id) -> collections.ab with requests.Session() as s: response = s.post( - url=self.url, params=params, headers=self.headers, data=request_data, stream=True, verify=False + url=self.url, + params=params, + headers=self.headers, + data=request_data, + stream=True, + verify=False, ) self.check_response(response, query) yield response @@ -259,7 +267,12 @@ async def read_query(self, query, *data, query_parameters=None, query_id: str | return await response.content.read() async def stream_query_as_jsonl( - self, query, *data, query_parameters=None, query_id: str | None = None, line_separator=b"\n" + self, + query, + *data, + query_parameters=None, + query_id: str | None = None, + line_separator=b"\n", ) -> typing.AsyncGenerator[dict[typing.Any, typing.Any], None]: """Execute the given query in ClickHouse and stream back the response as one JSON per line. diff --git a/posthog/temporal/workflows/postgres_batch_export.py b/posthog/temporal/workflows/postgres_batch_export.py index 4c02a3c983119..f47684242df6b 100644 --- a/posthog/temporal/workflows/postgres_batch_export.py +++ b/posthog/temporal/workflows/postgres_batch_export.py @@ -178,7 +178,13 @@ async def insert_into_postgres_activity(inputs: PostgresInsertInputs): pg_file.records_since_last_reset, pg_file.bytes_since_last_reset, ) - copy_tsv_to_postgres(pg_file, connection, inputs.schema, inputs.table_name, schema_columns) + copy_tsv_to_postgres( + pg_file, + connection, + inputs.schema, + inputs.table_name, + schema_columns, + ) pg_file.reset() if pg_file.tell() > 0: @@ -187,7 +193,13 @@ async def insert_into_postgres_activity(inputs: PostgresInsertInputs): pg_file.records_since_last_reset, pg_file.bytes_since_last_reset, ) - copy_tsv_to_postgres(pg_file, connection, inputs.schema, inputs.table_name, schema_columns) + copy_tsv_to_postgres( + pg_file, + connection, + inputs.schema, + inputs.table_name, + schema_columns, + ) @workflow.defn(name="postgres-export") @@ -211,7 +223,11 @@ async def run(self, inputs: PostgresBatchExportInputs): """Workflow implementation to export data to Postgres.""" logger = get_batch_exports_logger(inputs=inputs) data_interval_start, data_interval_end = get_data_interval(inputs.interval, inputs.data_interval_end) - logger.info("Starting Postgres export batch %s - %s", data_interval_start, data_interval_end) + logger.info( + "Starting Postgres export batch %s - %s", + data_interval_start, + data_interval_end, + ) create_export_run_inputs = CreateBatchExportRunInputs( team_id=inputs.team_id, @@ -288,7 +304,11 @@ async def run(self, inputs: PostgresBatchExportInputs): raise else: - logger.info("Successfully finished Postgres export batch %s - %s", data_interval_start, data_interval_end) + logger.info( + "Successfully finished Postgres export batch %s - %s", + data_interval_start, + data_interval_end, + ) finally: await workflow.execute_activity( diff --git a/posthog/temporal/workflows/s3_batch_export.py b/posthog/temporal/workflows/s3_batch_export.py index 2c7545fecfb3e..1e3e59a8ca4e8 100644 --- a/posthog/temporal/workflows/s3_batch_export.py +++ b/posthog/temporal/workflows/s3_batch_export.py @@ -178,7 +178,10 @@ async def complete(self) -> str: async with self.s3_client() as s3_client: response = await s3_client.complete_multipart_upload( - Bucket=self.bucket_name, Key=self.key, UploadId=self.upload_id, MultipartUpload={"Parts": self.parts} + Bucket=self.bucket_name, + Key=self.key, + UploadId=self.upload_id, + MultipartUpload={"Parts": self.parts}, ) self.upload_id = None @@ -538,7 +541,11 @@ async def run(self, inputs: S3BatchExportInputs): raise else: - logger.info("Successfully finished S3 export batch %s - %s", data_interval_start, data_interval_end) + logger.info( + "Successfully finished S3 export batch %s - %s", + data_interval_start, + data_interval_end, + ) finally: await workflow.execute_activity( diff --git a/posthog/temporal/workflows/snowflake_batch_export.py b/posthog/temporal/workflows/snowflake_batch_export.py index 7b844a9ef268b..ba65ef418d41d 100644 --- a/posthog/temporal/workflows/snowflake_batch_export.py +++ b/posthog/temporal/workflows/snowflake_batch_export.py @@ -296,7 +296,11 @@ async def run(self, inputs: SnowflakeBatchExportInputs): """Workflow implementation to export data to Snowflake table.""" logger = get_batch_exports_logger(inputs=inputs) data_interval_start, data_interval_end = get_data_interval(inputs.interval, inputs.data_interval_end) - logger.info("Starting Snowflake export batch %s - %s", data_interval_start, data_interval_end) + logger.info( + "Starting Snowflake export batch %s - %s", + data_interval_start, + data_interval_end, + ) data_interval_start, data_interval_end = get_data_interval(inputs.interval, inputs.data_interval_end) @@ -374,7 +378,11 @@ async def run(self, inputs: SnowflakeBatchExportInputs): raise else: - logger.info("Successfully finished Snowflake export batch %s - %s", data_interval_start, data_interval_end) + logger.info( + "Successfully finished Snowflake export batch %s - %s", + data_interval_start, + data_interval_end, + ) finally: await workflow.execute_activity( diff --git a/posthog/temporal/workflows/squash_person_overrides.py b/posthog/temporal/workflows/squash_person_overrides.py index 90d78bad9abf3..1386964339589 100644 --- a/posthog/temporal/workflows/squash_person_overrides.py +++ b/posthog/temporal/workflows/squash_person_overrides.py @@ -268,7 +268,10 @@ async def drop_dictionary(inputs: QueryInputs) -> None: activity.logger.info("Dropping DICTIONARY %s", inputs.dictionary_name) sync_execute( - DROP_DICTIONARY_QUERY.format(database=settings.CLICKHOUSE_DATABASE, dictionary_name=inputs.dictionary_name) + DROP_DICTIONARY_QUERY.format( + database=settings.CLICKHOUSE_DATABASE, + dictionary_name=inputs.dictionary_name, + ) ) @@ -492,7 +495,9 @@ async def delete_squashed_person_overrides_from_postgres(inputs: QueryInputs) -> if inputs.dry_run is True: activity.logger.info("This is a DRY RUN so nothing will be deleted.") activity.logger.info( - "Would have run query: %s with parameters %s", DELETE_FROM_PERSON_OVERRIDES, parameters + "Would have run query: %s with parameters %s", + DELETE_FROM_PERSON_OVERRIDES, + parameters, ) continue diff --git a/posthog/test/activity_logging/test_activity_logging.py b/posthog/test/activity_logging/test_activity_logging.py index b700fb13bcc85..9e2030779f1a9 100644 --- a/posthog/test/activity_logging/test_activity_logging.py +++ b/posthog/test/activity_logging/test_activity_logging.py @@ -2,14 +2,25 @@ from django.db.utils import IntegrityError from posthog.models import User -from posthog.models.activity_logging.activity_log import ActivityLog, Change, Detail, log_activity +from posthog.models.activity_logging.activity_log import ( + ActivityLog, + Change, + Detail, + log_activity, +) from posthog.models.utils import UUIDT from posthog.test.base import BaseTest class TestActivityLogModel(BaseTest): def test_can_save_a_model_changed_activity_log(self) -> None: - change = Change(type="FeatureFlag", field="active", action="created", before=False, after=True) + change = Change( + type="FeatureFlag", + field="active", + action="created", + before=False, + after=True, + ) log_activity( organization_id=self.organization.id, team_id=self.team.id, @@ -87,7 +98,10 @@ def test_does_not_throw_if_cannot_log_activity(self) -> None: logged_warning = log.records[0].__dict__ self.assertEqual(logged_warning["levelname"], "WARNING") - self.assertEqual(logged_warning["msg"]["event"], "activity_log.failed_to_write_to_activity_log") + self.assertEqual( + logged_warning["msg"]["event"], + "activity_log.failed_to_write_to_activity_log", + ) self.assertEqual(logged_warning["msg"]["scope"], "testing throwing exceptions on create") self.assertEqual(logged_warning["msg"]["team"], 1) self.assertEqual(logged_warning["msg"]["activity"], "does not explode") diff --git a/posthog/test/activity_logging/test_feature_flag_activity_logging.py b/posthog/test/activity_logging/test_feature_flag_activity_logging.py index bd4fe53c51219..e3c48cd1b7766 100644 --- a/posthog/test/activity_logging/test_feature_flag_activity_logging.py +++ b/posthog/test/activity_logging/test_feature_flag_activity_logging.py @@ -18,7 +18,15 @@ def test_a_change_of_name_can_be_logged(self) -> None: previous=self._a_feature_flag_with(name="a"), current=self._a_feature_flag_with(name="b"), ) - expected = [Change(type="FeatureFlag", field="name", action="changed", before="a", after="b")] + expected = [ + Change( + type="FeatureFlag", + field="name", + action="changed", + before="a", + after="b", + ) + ] assert actual == expected def test_a_change_of_key_can_be_logged(self) -> None: @@ -27,7 +35,15 @@ def test_a_change_of_key_can_be_logged(self) -> None: previous=self._a_feature_flag_with(key="the-key"), current=self._a_feature_flag_with(key="the-new-key"), ) - expected = [Change(type="FeatureFlag", field="key", action="changed", before="the-key", after="the-new-key")] + expected = [ + Change( + type="FeatureFlag", + field="key", + action="changed", + before="the-key", + after="the-new-key", + ) + ] assert actual == expected def test_a_change_of_flag_active_status_can_be_logged(self) -> None: @@ -36,7 +52,15 @@ def test_a_change_of_flag_active_status_can_be_logged(self) -> None: previous=self._a_feature_flag_with(active=False), current=self._a_feature_flag_with(active=True), ) - expected = [Change(type="FeatureFlag", field="active", action="changed", before=False, after=True)] + expected = [ + Change( + type="FeatureFlag", + field="active", + action="changed", + before=False, + after=True, + ) + ] assert actual == expected def test_adding_a_rollout_percentage_can_be_logged(self) -> None: @@ -45,7 +69,14 @@ def test_adding_a_rollout_percentage_can_be_logged(self) -> None: previous=self._a_feature_flag_with(), current=self._a_feature_flag_with(rollout_percentage=23), ) - expected = [Change(type="FeatureFlag", field="rollout_percentage", action="created", after=23)] + expected = [ + Change( + type="FeatureFlag", + field="rollout_percentage", + action="created", + after=23, + ) + ] assert actual == expected def test_a_change_of_rollout_percentage_can_be_logged(self) -> None: @@ -54,7 +85,15 @@ def test_a_change_of_rollout_percentage_can_be_logged(self) -> None: previous=self._a_feature_flag_with(rollout_percentage=12), current=self._a_feature_flag_with(rollout_percentage=23), ) - expected = [Change(type="FeatureFlag", field="rollout_percentage", action="changed", before=12, after=23)] + expected = [ + Change( + type="FeatureFlag", + field="rollout_percentage", + action="changed", + before=12, + after=23, + ) + ] assert actual == expected def test_a_change_of_soft_delete_can_be_logged(self) -> None: @@ -63,7 +102,15 @@ def test_a_change_of_soft_delete_can_be_logged(self) -> None: previous=self._a_feature_flag_with(deleted=False), current=self._a_feature_flag_with(deleted=True), ) - expected = [Change(type="FeatureFlag", field="deleted", action="changed", before=False, after=True)] + expected = [ + Change( + type="FeatureFlag", + field="deleted", + action="changed", + before=False, + after=True, + ) + ] assert actual == expected def test_a_change_of_filters_can_be_logged(self) -> None: diff --git a/posthog/test/activity_logging/test_insight_activity_logging.py b/posthog/test/activity_logging/test_insight_activity_logging.py index a41268a8e6b90..0c0ec74b97667 100644 --- a/posthog/test/activity_logging/test_insight_activity_logging.py +++ b/posthog/test/activity_logging/test_insight_activity_logging.py @@ -23,7 +23,10 @@ def test_a_change_of_insight_dashboard_can_be_logged(self) -> None: field="dashboards", before=[], after=[ - {"dashboard": {"id": dashboard.id, "name": dashboard.name}, "insight": {"id": insight_after.id}} + { + "dashboard": {"id": dashboard.id, "name": dashboard.name}, + "insight": {"id": insight_after.id}, + } ], ) ] @@ -36,7 +39,15 @@ def test_insight_change_of_name_can_be_logged(self) -> None: previous=self._an_insight_with(name="name"), current=self._an_insight_with(name="new name"), ) - expected = [Change(type="Insight", field="name", action="changed", before="name", after="new name")] + expected = [ + Change( + type="Insight", + field="name", + action="changed", + before="name", + after="new name", + ) + ] self.assertCountEqual(actual, expected) @@ -47,7 +58,13 @@ def test_insight_change_of_tags_can_be_logged(self) -> None: current=self._an_insight_with(tagged_items=["after", "tags"]), ) expected = [ - Change(type="Insight", field="tags", action="changed", before=["before", "tags"], after=["after", "tags"]) + Change( + type="Insight", + field="tags", + action="changed", + before=["before", "tags"], + after=["after", "tags"], + ) ] self.assertCountEqual(actual, expected) @@ -58,7 +75,15 @@ def test_insight_change_of_derived_name_can_be_logged(self) -> None: previous=self._an_insight_with(derived_name="starting"), current=self._an_insight_with(derived_name="after"), ) - expected = [Change(type="Insight", field="derived_name", action="changed", before="starting", after="after")] + expected = [ + Change( + type="Insight", + field="derived_name", + action="changed", + before="starting", + after="after", + ) + ] self.assertCountEqual(actual, expected) @@ -68,7 +93,15 @@ def test_insight_change_of_description_can_be_logged(self) -> None: previous=self._an_insight_with(description="starting"), current=self._an_insight_with(description="after"), ) - expected = [Change(type="Insight", field="description", action="changed", before="starting", after="after")] + expected = [ + Change( + type="Insight", + field="description", + action="changed", + before="starting", + after="after", + ) + ] self.assertCountEqual(actual, expected) @@ -91,7 +124,10 @@ def _an_insight_with(self, tagged_items=None, **kwargs) -> Insight: refreshing=kwargs.get("refreshing", False), created_by=kwargs.get("user", self.user), is_sample=kwargs.get("is_sample", False), - short_id=kwargs.get("short_id", "".join(random.choices(string.ascii_letters + string.digits, k=6))), + short_id=kwargs.get( + "short_id", + "".join(random.choices(string.ascii_letters + string.digits, k=6)), + ), favorited=kwargs.get("favorited", False), refresh_attempt=kwargs.get("refresh_attempt", 0), last_modified_at=kwargs.get("last_modified_at", parser.parse("12th April 2003")), diff --git a/posthog/test/base.py b/posthog/test/base.py index d76a2e28b732d..105285fa3073e 100644 --- a/posthog/test/base.py +++ b/posthog/test/base.py @@ -24,10 +24,18 @@ from posthog.clickhouse.client import sync_execute from posthog.clickhouse.client.connection import ch_pool from posthog.clickhouse.plugin_log_entries import TRUNCATE_PLUGIN_LOG_ENTRIES_TABLE_SQL -from posthog.cloud_utils import TEST_clear_cloud_cache, TEST_clear_instance_license_cache, is_cloud +from posthog.cloud_utils import ( + TEST_clear_cloud_cache, + TEST_clear_instance_license_cache, + is_cloud, +) from posthog.models import Dashboard, DashboardTile, Insight, Organization, Team, User from posthog.models.cohort.sql import TRUNCATE_COHORTPEOPLE_TABLE_SQL -from posthog.models.event.sql import DISTRIBUTED_EVENTS_TABLE_SQL, DROP_EVENTS_TABLE_SQL, EVENTS_TABLE_SQL +from posthog.models.event.sql import ( + DISTRIBUTED_EVENTS_TABLE_SQL, + DROP_EVENTS_TABLE_SQL, + EVENTS_TABLE_SQL, +) from posthog.models.event.util import bulk_create_events from posthog.models.group.sql import TRUNCATE_GROUPS_TABLE_SQL from posthog.models.instance_setting import get_instance_setting @@ -68,7 +76,14 @@ def _setup_test_data(klass): klass.team = Team.objects.create( organization=klass.organization, api_token=klass.CONFIG_API_TOKEN, - test_account_filters=[{"key": "email", "value": "@posthog.com", "operator": "not_icontains", "type": "person"}], + test_account_filters=[ + { + "key": "email", + "value": "@posthog.com", + "operator": "not_icontains", + "type": "person", + } + ], has_completed_onboarding_for={"product_analytics": True}, ) if klass.CONFIG_EMAIL: @@ -108,12 +123,22 @@ class ErrorResponsesMixin: } def not_found_response(self, message: str = "Not found.") -> Dict[str, Optional[str]]: - return {"type": "invalid_request", "code": "not_found", "detail": message, "attr": None} + return { + "type": "invalid_request", + "code": "not_found", + "detail": message, + "attr": None, + } def permission_denied_response( self, message: str = "You do not have permission to perform this action." ) -> Dict[str, Optional[str]]: - return {"type": "authentication_error", "code": "permission_denied", "detail": message, "attr": None} + return { + "type": "authentication_error", + "code": "permission_denied", + "detail": message, + "attr": None, + } def method_not_allowed_response(self, method: str) -> Dict[str, Optional[str]]: return { @@ -124,14 +149,29 @@ def method_not_allowed_response(self, method: str) -> Dict[str, Optional[str]]: } def unauthenticated_response( - self, message: str = "Authentication credentials were not provided.", code: str = "not_authenticated" + self, + message: str = "Authentication credentials were not provided.", + code: str = "not_authenticated", ) -> Dict[str, Optional[str]]: - return {"type": "authentication_error", "code": code, "detail": message, "attr": None} + return { + "type": "authentication_error", + "code": code, + "detail": message, + "attr": None, + } def validation_error_response( - self, message: str = "Malformed request", code: str = "invalid_input", attr: Optional[str] = None + self, + message: str = "Malformed request", + code: str = "invalid_input", + attr: Optional[str] = None, ) -> Dict[str, Optional[str]]: - return {"type": "validation_error", "code": code, "detail": message, "attr": attr} + return { + "type": "validation_error", + "code": code, + "detail": message, + "attr": attr, + } class TestMixin: @@ -313,7 +353,9 @@ def stripResponse(response, remove=("action", "label", "persons_urls", "filter") def default_materialised_columns(): try: from ee.clickhouse.materialized_columns.analyze import get_materialized_columns - from ee.clickhouse.materialized_columns.test.test_columns import EVENTS_TABLE_DEFAULT_MATERIALIZED_COLUMNS + from ee.clickhouse.materialized_columns.test.test_columns import ( + EVENTS_TABLE_DEFAULT_MATERIALIZED_COLUMNS, + ) except: # EE not available? Skip @@ -383,7 +425,11 @@ def fn_with_materialized(self, *args, **kwargs): materialize("person", prop) materialize("events", prop, table_column="person_properties") for group_type_index, prop in group_properties: - materialize("events", prop, table_column=f"group{group_type_index}_properties") # type: ignore + materialize( + "events", + prop, + table_column=f"group{group_type_index}_properties", # type: ignore + ) try: with self.capture_select_queries() as sqls: @@ -461,7 +507,11 @@ def assertQueryMatchesSnapshot(self, query, params=None, replace_all_numbers=Fal query, ) - query = re.sub(rf"""user_id:([0-9]+) request:[a-zA-Z0-9-_]+""", r"""user_id:0 request:_snapshot_""", query) + query = re.sub( + rf"""user_id:([0-9]+) request:[a-zA-Z0-9-_]+""", + r"""user_id:0 request:_snapshot_""", + query, + ) # ee license check has varying datetime # e.g. WHERE "ee_license"."valid_until" >= '2023-03-02T21:13:59.298031+00:00'::timestamptz @@ -482,7 +532,11 @@ def assertQueryMatchesSnapshot(self, query, params=None, replace_all_numbers=Fal query = re.sub(r"SAVEPOINT \".+\"", "SAVEPOINT _snapshot_", query) # test_formula has some values that change on every run - query = re.sub(r"\SELECT \[\d+, \d+] as breakdown_value", "SELECT [1, 2] as breakdown_value", query) + query = re.sub( + r"\SELECT \[\d+, \d+] as breakdown_value", + "SELECT [1, 2] as breakdown_value", + query, + ) query = re.sub( r"SELECT distinct_id,[\n\r\s]+\d+ as value", "SELECT distinct_id, 1 as value", diff --git a/posthog/test/test_celery.py b/posthog/test/test_celery.py index c004be2370a97..19b0a303fd57b 100644 --- a/posthog/test/test_celery.py +++ b/posthog/test/test_celery.py @@ -16,6 +16,7 @@ def test_clickhouse_errors_count(self, _, mock_push_to_gateway, mock_sync_execut self.assertEqual( 60, registry.get_sample_value( - "posthog_celery_clickhouse_errors", labels={"name": "NO_ZOOKEEPER", "replica": "ch1", "shard": "1"} + "posthog_celery_clickhouse_errors", + labels={"name": "NO_ZOOKEEPER", "replica": "ch1", "shard": "1"}, ), ) diff --git a/posthog/test/test_cohort_model.py b/posthog/test/test_cohort_model.py index df9da32b0a2ee..4d7eabe210740 100644 --- a/posthog/test/test_cohort_model.py +++ b/posthog/test/test_cohort_model.py @@ -41,11 +41,15 @@ def test_calculating_cohort_clickhouse(self): name="cohort1", ) person1 = Person.objects.create( - distinct_ids=["person1"], team_id=self.team.pk, properties={"$some_prop": "something"} + distinct_ids=["person1"], + team_id=self.team.pk, + properties={"$some_prop": "something"}, ) Person.objects.create(distinct_ids=["person2"], team_id=self.team.pk, properties={}) person3 = Person.objects.create( - distinct_ids=["person3"], team_id=self.team.pk, properties={"$some_prop": "something"} + distinct_ids=["person3"], + team_id=self.team.pk, + properties={"$some_prop": "something"}, ) cohort.calculate_people_ch(pending_version=0) @@ -53,7 +57,11 @@ def test_calculating_cohort_clickhouse(self): row[0] for row in sync_execute( GET_COHORTPEOPLE_BY_COHORT_ID, - {"cohort_id": cohort.pk, "team_id": self.team.pk, "version": cohort.version}, + { + "cohort_id": cohort.pk, + "team_id": self.team.pk, + "version": cohort.version, + }, ) ] self.assertCountEqual(uuids, [person1.uuid, person3.uuid]) @@ -74,11 +82,22 @@ def test_group_to_property_conversion(self): groups=[ { "properties": [ - {"key": "$some_prop", "value": "something", "type": "person", "operator": "contains"}, + { + "key": "$some_prop", + "value": "something", + "type": "person", + "operator": "contains", + }, {"key": "other_prop", "value": "other_value", "type": "person"}, ] }, - {"days": "4", "count": "3", "label": "$pageview", "action_id": 1, "count_operator": "eq"}, + { + "days": "4", + "count": "3", + "label": "$pageview", + "action_id": 1, + "count_operator": "eq", + }, ], name="cohort1", ) @@ -91,8 +110,17 @@ def test_group_to_property_conversion(self): { "type": "AND", "values": [ - {"key": "$some_prop", "type": "person", "value": "something", "operator": "contains"}, - {"key": "other_prop", "type": "person", "value": "other_value"}, + { + "key": "$some_prop", + "type": "person", + "value": "something", + "operator": "contains", + }, + { + "key": "other_prop", + "type": "person", + "value": "other_value", + }, ], }, { @@ -120,11 +148,22 @@ def test_group_to_property_conversion_with_valid_zero_count(self): groups=[ { "properties": [ - {"key": "$some_prop", "value": "something", "type": "person", "operator": "contains"}, + { + "key": "$some_prop", + "value": "something", + "type": "person", + "operator": "contains", + }, {"key": "other_prop", "value": "other_value", "type": "person"}, ] }, - {"days": "4", "count": "0", "label": "$pageview", "event_id": "$pageview", "count_operator": "gte"}, + { + "days": "4", + "count": "0", + "label": "$pageview", + "event_id": "$pageview", + "count_operator": "gte", + }, ], name="cohort1", ) @@ -137,8 +176,17 @@ def test_group_to_property_conversion_with_valid_zero_count(self): { "type": "AND", "values": [ - {"key": "$some_prop", "type": "person", "value": "something", "operator": "contains"}, - {"key": "other_prop", "type": "person", "value": "other_value"}, + { + "key": "$some_prop", + "type": "person", + "value": "something", + "operator": "contains", + }, + { + "key": "other_prop", + "type": "person", + "value": "other_value", + }, ], }, { @@ -164,7 +212,13 @@ def test_group_to_property_conversion_with_valid_zero_count_different_operator(s cohort = Cohort.objects.create( team=self.team, groups=[ - {"days": "4", "count": "0", "label": "$pageview", "event_id": "$pageview", "count_operator": "lte"} + { + "days": "4", + "count": "0", + "label": "$pageview", + "event_id": "$pageview", + "count_operator": "lte", + } ], name="cohort1", ) @@ -196,7 +250,14 @@ def test_group_to_property_conversion_with_valid_zero_count_different_operator(s def test_group_to_property_conversion_with_missing_days_and_invalid_count(self): cohort = Cohort.objects.create( team=self.team, - groups=[{"count": -3, "label": "$pageview", "event_id": "$pageview", "count_operator": "gte"}], + groups=[ + { + "count": -3, + "label": "$pageview", + "event_id": "$pageview", + "count_operator": "gte", + } + ], name="cohort1", ) diff --git a/posthog/test/test_datetime.py b/posthog/test/test_datetime.py index b25fa7098f9b5..2b8e6b087e5fb 100644 --- a/posthog/test/test_datetime.py +++ b/posthog/test/test_datetime.py @@ -1,6 +1,12 @@ from datetime import datetime, timezone -from posthog.datetime import start_of_hour, start_of_day, end_of_day, start_of_week, start_of_month +from posthog.datetime import ( + start_of_hour, + start_of_day, + end_of_day, + start_of_week, + start_of_month, +) def test_start_of_hour(): diff --git a/posthog/test/test_decorators.py b/posthog/test/test_decorators.py index 5ff6a48441369..a796125345b07 100644 --- a/posthog/test/test_decorators.py +++ b/posthog/test/test_decorators.py @@ -81,7 +81,10 @@ def test_discards_stale_response(self) -> None: class TestIsStaleHelper(BaseTest): - cached_response = {"last_refresh": datetime.fromisoformat("2023-02-08T12:05:23+00:00"), "result": "bla"} + cached_response = { + "last_refresh": datetime.fromisoformat("2023-02-08T12:05:23+00:00"), + "result": "bla", + } def test_keeps_fresh_hourly_result(self) -> None: with freeze_time("2023-02-08T12:59:59Z"): diff --git a/posthog/test/test_element_model.py b/posthog/test/test_element_model.py index 0286a6d55776c..bb51463464b23 100644 --- a/posthog/test/test_element_model.py +++ b/posthog/test/test_element_model.py @@ -21,7 +21,12 @@ def test_elements_to_string(self) -> None: nth_child=1, nth_of_type=0, ), - Element(tag_name="button", attr_class=["btn", "btn-primary"], nth_child=0, nth_of_type=0), + Element( + tag_name="button", + attr_class=["btn", "btn-primary"], + nth_child=0, + nth_of_type=0, + ), Element(tag_name="div", nth_child=0, nth_of_type=0), Element(tag_name="div", nth_child=0, nth_of_type=0, attr_id="nested"), ] @@ -66,7 +71,10 @@ def test_broken_class_names(self): elements_string = elements_to_string( elements=[ Element( - tag_name="a", href="/a-url", attr_class=['small"', "xy:z"], attributes={"attr_class": 'xyz small"'} + tag_name="a", + href="/a-url", + attr_class=['small"', "xy:z"], + attributes={"attr_class": 'xyz small"'}, ) ] ) diff --git a/posthog/test/test_email.py b/posthog/test/test_email.py index 6beea8f3d2251..85f48107913ed 100644 --- a/posthog/test/test_email.py +++ b/posthog/test/test_email.py @@ -53,10 +53,14 @@ def test_cant_send_same_campaign_twice(self) -> None: record.save() with self.settings(CELERY_TASK_ALWAYS_EAGER=True): - _send_email( campaign_key="campaign_1", - to=[{"raw_email": "test0@posthog.com", "recipient": "Test PostHog "}], + to=[ + { + "raw_email": "test0@posthog.com", + "recipient": "Test PostHog ", + } + ], subject="Test email", headers={}, ) diff --git a/posthog/test/test_feature_flag.py b/posthog/test/test_feature_flag.py index e9d12f7d6d047..668868356f46e 100644 --- a/posthog/test/test_feature_flag.py +++ b/posthog/test/test_feature_flag.py @@ -24,7 +24,12 @@ from posthog.models.organization import Organization from posthog.models.team import Team from posthog.models.user import User -from posthog.test.base import BaseTest, QueryMatchingTest, snapshot_postgres_queries, snapshot_postgres_queries_context +from posthog.test.base import ( + BaseTest, + QueryMatchingTest, + snapshot_postgres_queries, + snapshot_postgres_queries_context, +) class TestFeatureFlagCohortExpansion(BaseTest): @@ -34,7 +39,16 @@ def test_cohort_expansion(self): cohort = Cohort.objects.create( team=self.team, groups=[ - {"properties": [{"key": "email", "value": ["@posthog.com"], "type": "person", "operator": "icontains"}]} + { + "properties": [ + { + "key": "email", + "value": ["@posthog.com"], + "type": "person", + "operator": "icontains", + } + ] + } ], ) flag: FeatureFlag = FeatureFlag.objects.create( @@ -49,7 +63,12 @@ def test_cohort_expansion(self): [ { "properties": [ - {"key": "email", "operator": "icontains", "type": "person", "value": ["@posthog.com"]} + { + "key": "email", + "operator": "icontains", + "type": "person", + "value": ["@posthog.com"], + } ], "rollout_percentage": None, } @@ -91,8 +110,18 @@ def test_cohort_expansion_multiple_properties(self): groups=[ { "properties": [ - {"key": "email", "value": ["@posthog.com"], "type": "person", "operator": "icontains"}, - {"key": "name", "value": ["posthog"], "type": "person", "operator": "icontains"}, + { + "key": "email", + "value": ["@posthog.com"], + "type": "person", + "operator": "icontains", + }, + { + "key": "name", + "value": ["posthog"], + "type": "person", + "operator": "icontains", + }, ] } ], @@ -109,8 +138,18 @@ def test_cohort_expansion_multiple_properties(self): [ { "properties": [ - {"key": "email", "operator": "icontains", "type": "person", "value": ["@posthog.com"]}, - {"key": "name", "value": ["posthog"], "type": "person", "operator": "icontains"}, + { + "key": "email", + "operator": "icontains", + "type": "person", + "value": ["@posthog.com"], + }, + { + "key": "name", + "value": ["posthog"], + "type": "person", + "operator": "icontains", + }, ], "rollout_percentage": None, } @@ -127,8 +166,16 @@ def test_cohort_property_group(self): { "type": "OR", "values": [ - {"key": "$some_prop", "value": "nomatchihope", "type": "person"}, - {"key": "$some_prop2", "value": "nomatchihope2", "type": "person"}, + { + "key": "$some_prop", + "value": "nomatchihope", + "type": "person", + }, + { + "key": "$some_prop2", + "value": "nomatchihope2", + "type": "person", + }, ], } ], @@ -143,7 +190,10 @@ def test_cohort_property_group(self): key="active-flag", filters={ "groups": [ - {"properties": [{"key": "id", "value": cohort.pk, "type": "cohort"}], "rollout_percentage": 50} + { + "properties": [{"key": "id", "value": cohort.pk, "type": "cohort"}], + "rollout_percentage": 50, + } ] }, ) @@ -155,7 +205,13 @@ def test_cohort_property_group(self): "rollout_percentage": 50, }, { - "properties": [{"key": "$some_prop2", "value": "nomatchihope2", "type": "person"}], + "properties": [ + { + "key": "$some_prop2", + "value": "nomatchihope2", + "type": "person", + } + ], "rollout_percentage": 50, }, ], @@ -171,8 +227,16 @@ def test_behavioral_cohorts(self): { "type": "OR", "values": [ - {"key": "$some_prop", "value": "nomatchihope", "type": "person"}, - {"key": "$some_prop2", "value": "nomatchihope2", "type": "person"}, + { + "key": "$some_prop", + "value": "nomatchihope", + "type": "person", + }, + { + "key": "$some_prop2", + "value": "nomatchihope2", + "type": "person", + }, { "key": "$pageview", "event_type": "events", @@ -195,13 +259,21 @@ def test_behavioral_cohorts(self): key="active-flag", filters={ "groups": [ - {"properties": [{"key": "id", "value": cohort.pk, "type": "cohort"}], "rollout_percentage": 50} + { + "properties": [{"key": "id", "value": cohort.pk, "type": "cohort"}], + "rollout_percentage": 50, + } ] }, ) self.assertEqual( flag.transform_cohort_filters_for_easy_evaluation(), - [{"properties": [{"key": "id", "value": cohort.pk, "type": "cohort"}], "rollout_percentage": 50}], + [ + { + "properties": [{"key": "id", "value": cohort.pk, "type": "cohort"}], + "rollout_percentage": 50, + } + ], ) def test_multiple_cohorts(self): @@ -214,8 +286,16 @@ def test_multiple_cohorts(self): { "type": "OR", "values": [ - {"key": "$some_prop", "value": "nomatchihope", "type": "person"}, - {"key": "$some_prop2", "value": "nomatchihope2", "type": "person"}, + { + "key": "$some_prop", + "value": "nomatchihope", + "type": "person", + }, + { + "key": "$some_prop2", + "value": "nomatchihope2", + "type": "person", + }, ], } ], @@ -233,8 +313,16 @@ def test_multiple_cohorts(self): { "type": "AND", "values": [ - {"key": "$some_prop", "value": "nomatchihope", "type": "person"}, - {"key": "$some_prop2", "value": "nomatchihope2", "type": "person"}, + { + "key": "$some_prop", + "value": "nomatchihope", + "type": "person", + }, + { + "key": "$some_prop2", + "value": "nomatchihope2", + "type": "person", + }, ], } ], @@ -249,8 +337,14 @@ def test_multiple_cohorts(self): key="active-flag", filters={ "groups": [ - {"properties": [{"key": "id", "value": cohort.pk, "type": "cohort"}], "rollout_percentage": 50}, - {"properties": [{"key": "id", "value": cohort2.pk, "type": "cohort"}], "rollout_percentage": 50}, + { + "properties": [{"key": "id", "value": cohort.pk, "type": "cohort"}], + "rollout_percentage": 50, + }, + { + "properties": [{"key": "id", "value": cohort2.pk, "type": "cohort"}], + "rollout_percentage": 50, + }, ] }, ) @@ -269,15 +363,31 @@ def test_cohort_thats_impossible_to_expand(self): { "type": "OR", "values": [ - {"key": "$some_prop", "value": "nomatchihope", "type": "person"}, - {"key": "$some_prop2", "value": "nomatchihope2", "type": "person"}, + { + "key": "$some_prop", + "value": "nomatchihope", + "type": "person", + }, + { + "key": "$some_prop2", + "value": "nomatchihope2", + "type": "person", + }, ], }, { "type": "AND", "values": [ - {"key": "$some_prop3", "value": "nomatchihope", "type": "person"}, - {"key": "$some_prop4", "value": "nomatchihope2", "type": "person"}, + { + "key": "$some_prop3", + "value": "nomatchihope", + "type": "person", + }, + { + "key": "$some_prop4", + "value": "nomatchihope2", + "type": "person", + }, ], }, ], @@ -293,7 +403,10 @@ def test_cohort_thats_impossible_to_expand(self): key="active-flag", filters={ "groups": [ - {"properties": [{"key": "id", "value": cohort.pk, "type": "cohort"}], "rollout_percentage": 50}, + { + "properties": [{"key": "id", "value": cohort.pk, "type": "cohort"}], + "rollout_percentage": 50, + }, ] }, ) @@ -310,8 +423,16 @@ def test_feature_flag_preventing_simple_cohort_expansion(self): { "type": "OR", "values": [ - {"key": "$some_prop", "value": "nomatchihope", "type": "person"}, - {"key": "$some_prop2", "value": "nomatchihope2", "type": "person"}, + { + "key": "$some_prop", + "value": "nomatchihope", + "type": "person", + }, + { + "key": "$some_prop2", + "value": "nomatchihope2", + "type": "person", + }, ], } ], @@ -350,20 +471,36 @@ def test_feature_flag_with_additional_conditions_playing_well_with_complex_cohor { "type": "AND", "values": [ - {"key": "$some_prop", "value": "nomatchihope", "type": "person"}, - {"key": "$some_prop2", "value": "nomatchihope2", "type": "person"}, + { + "key": "$some_prop", + "value": "nomatchihope", + "type": "person", + }, + { + "key": "$some_prop2", + "value": "nomatchihope2", + "type": "person", + }, ], }, { "type": "AND", "values": [ - {"key": "$name", "value": "nomatchihope", "type": "person"}, + { + "key": "$name", + "value": "nomatchihope", + "type": "person", + }, ], }, { "type": "AND", "values": [ - {"key": "$email", "value": "nomatchihope", "type": "person"}, + { + "key": "$email", + "value": "nomatchihope", + "type": "person", + }, ], }, ], @@ -383,8 +520,14 @@ def test_feature_flag_with_additional_conditions_playing_well_with_complex_cohor "properties": [{"key": "name_above", "value": "name", "type": "person"}], "rollout_percentage": 50, }, - {"properties": [{"key": "id", "value": cohort.pk, "type": "cohort"}], "rollout_percentage": 50}, - {"properties": [{"key": "name", "value": "name", "type": "person"}], "rollout_percentage": 50}, + { + "properties": [{"key": "id", "value": cohort.pk, "type": "cohort"}], + "rollout_percentage": 50, + }, + { + "properties": [{"key": "name", "value": "name", "type": "person"}], + "rollout_percentage": 50, + }, ] }, ) @@ -392,12 +535,26 @@ def test_feature_flag_with_additional_conditions_playing_well_with_complex_cohor self.assertEqual( flag.transform_cohort_filters_for_easy_evaluation(), [ - {"properties": [{"key": "name_above", "value": "name", "type": "person"}], "rollout_percentage": 50}, - {"properties": [{"key": "name", "value": "name", "type": "person"}], "rollout_percentage": 50}, + { + "properties": [{"key": "name_above", "value": "name", "type": "person"}], + "rollout_percentage": 50, + }, + { + "properties": [{"key": "name", "value": "name", "type": "person"}], + "rollout_percentage": 50, + }, { "properties": [ - {"key": "$some_prop", "value": "nomatchihope", "type": "person"}, - {"key": "$some_prop2", "value": "nomatchihope2", "type": "person"}, + { + "key": "$some_prop", + "value": "nomatchihope", + "type": "person", + }, + { + "key": "$some_prop2", + "value": "nomatchihope2", + "type": "person", + }, ], "rollout_percentage": 50, }, @@ -426,19 +583,31 @@ def test_complex_cohort_expansion_that_is_simplified_via_clearing_excess_levels( { "type": "OR", "values": [ - {"key": "$some_prop", "value": "nomatchihope", "type": "person"}, + { + "key": "$some_prop", + "value": "nomatchihope", + "type": "person", + }, ], }, { "type": "OR", "values": [ - {"key": "$name", "value": "nomatchihope", "type": "person"}, + { + "key": "$name", + "value": "nomatchihope", + "type": "person", + }, ], }, { "type": "AND", "values": [ - {"key": "$email", "value": "nomatchihope", "type": "person"}, + { + "key": "$email", + "value": "nomatchihope", + "type": "person", + }, ], }, ], @@ -454,8 +623,14 @@ def test_complex_cohort_expansion_that_is_simplified_via_clearing_excess_levels( key="active-flag", filters={ "groups": [ - {"properties": [{"key": "id", "value": cohort.pk, "type": "cohort"}], "rollout_percentage": 50}, - {"properties": [{"key": "name", "value": "name", "type": "person"}], "rollout_percentage": 50}, + { + "properties": [{"key": "id", "value": cohort.pk, "type": "cohort"}], + "rollout_percentage": 50, + }, + { + "properties": [{"key": "name", "value": "name", "type": "person"}], + "rollout_percentage": 50, + }, ] }, ) @@ -463,12 +638,18 @@ def test_complex_cohort_expansion_that_is_simplified_via_clearing_excess_levels( self.assertEqual( flag.transform_cohort_filters_for_easy_evaluation(), [ - {"properties": [{"key": "name", "value": "name", "type": "person"}], "rollout_percentage": 50}, + { + "properties": [{"key": "name", "value": "name", "type": "person"}], + "rollout_percentage": 50, + }, { "properties": [{"key": "$some_prop", "value": "nomatchihope", "type": "person"}], "rollout_percentage": 50, }, - {"properties": [{"key": "$name", "value": "nomatchihope", "type": "person"}], "rollout_percentage": 50}, + { + "properties": [{"key": "$name", "value": "nomatchihope", "type": "person"}], + "rollout_percentage": 50, + }, { "properties": [{"key": "$email", "value": "nomatchihope", "type": "person"}], "rollout_percentage": 50, @@ -590,7 +771,16 @@ def test_coercion_of_strings_and_numbers(self): feature_flag = self.create_feature_flag( filters={ "groups": [ - {"properties": [{"key": "Organizer Id", "value": ["307"], "operator": "exact", "type": "person"}]} + { + "properties": [ + { + "key": "Organizer Id", + "value": ["307"], + "operator": "exact", + "type": "person", + } + ] + } ] } ) @@ -598,8 +788,26 @@ def test_coercion_of_strings_and_numbers(self): key="random", filters={ "groups": [ - {"properties": [{"key": "Distinct Id", "value": ["307"], "operator": "exact", "type": "person"}]}, - {"properties": [{"key": "Distinct Id", "value": [307], "operator": "exact", "type": "person"}]}, + { + "properties": [ + { + "key": "Distinct Id", + "value": ["307"], + "operator": "exact", + "type": "person", + } + ] + }, + { + "properties": [ + { + "key": "Distinct Id", + "value": [307], + "operator": "exact", + "type": "person", + } + ] + }, ] }, ) @@ -660,7 +868,16 @@ def test_coercion_of_booleans(self): key="random1", filters={ "groups": [ - {"properties": [{"key": "enabled", "value": ["true"], "operator": "exact", "type": "person"}]} + { + "properties": [ + { + "key": "enabled", + "value": ["true"], + "operator": "exact", + "type": "person", + } + ] + } ] }, ) @@ -668,8 +885,26 @@ def test_coercion_of_booleans(self): key="random2", filters={ "groups": [ - {"properties": [{"key": "enabled", "value": True, "operator": "exact", "type": "person"}]}, - {"properties": [{"key": "enabled", "value": [True], "operator": "exact", "type": "person"}]}, + { + "properties": [ + { + "key": "enabled", + "value": True, + "operator": "exact", + "type": "person", + } + ] + }, + { + "properties": [ + { + "key": "enabled", + "value": [True], + "operator": "exact", + "type": "person", + } + ] + }, ] }, ) @@ -677,8 +912,26 @@ def test_coercion_of_booleans(self): key="random3", filters={ "groups": [ - {"properties": [{"key": "string_enabled", "value": [True], "operator": "exact", "type": "person"}]}, - {"properties": [{"key": "string_enabled", "value": True, "operator": "exact", "type": "person"}]}, + { + "properties": [ + { + "key": "string_enabled", + "value": [True], + "operator": "exact", + "type": "person", + } + ] + }, + { + "properties": [ + { + "key": "string_enabled", + "value": True, + "operator": "exact", + "type": "person", + } + ] + }, ] }, ) @@ -688,12 +941,22 @@ def test_coercion_of_booleans(self): "groups": [ { "properties": [ - {"key": "string_enabled", "value": ['"true"'], "operator": "exact", "type": "person"} + { + "key": "string_enabled", + "value": ['"true"'], + "operator": "exact", + "type": "person", + } ] }, { "properties": [ - {"key": "string_enabled", "value": '"true"', "operator": "exact", "type": "person"} + { + "key": "string_enabled", + "value": '"true"', + "operator": "exact", + "type": "person", + } ] }, ] @@ -731,15 +994,19 @@ def test_coercion_of_booleans(self): FeatureFlagMatch(True, None, FeatureFlagMatchReason.CONDITION_MATCH, 0), ) self.assertEqual( - FeatureFlagMatcher([feature_flag3], "307", property_value_overrides={"string_enabled": True}).get_match( - feature_flag3 - ), + FeatureFlagMatcher( + [feature_flag3], + "307", + property_value_overrides={"string_enabled": True}, + ).get_match(feature_flag3), FeatureFlagMatch(True, None, FeatureFlagMatchReason.CONDITION_MATCH, 0), ) self.assertEqual( - FeatureFlagMatcher([feature_flag4], "307", property_value_overrides={"string_enabled": True}).get_match( - feature_flag4 - ), + FeatureFlagMatcher( + [feature_flag4], + "307", + property_value_overrides={"string_enabled": True}, + ).get_match(feature_flag4), FeatureFlagMatch(True, None, FeatureFlagMatchReason.CONDITION_MATCH, 0), ) @@ -756,15 +1023,19 @@ def test_coercion_of_booleans(self): FeatureFlagMatch(True, None, FeatureFlagMatchReason.CONDITION_MATCH, 0), ) self.assertEqual( - FeatureFlagMatcher([feature_flag3], "307", property_value_overrides={"string_enabled": "true"}).get_match( - feature_flag3 - ), + FeatureFlagMatcher( + [feature_flag3], + "307", + property_value_overrides={"string_enabled": "true"}, + ).get_match(feature_flag3), FeatureFlagMatch(True, None, FeatureFlagMatchReason.CONDITION_MATCH, 0), ) self.assertEqual( - FeatureFlagMatcher([feature_flag4], "307", property_value_overrides={"string_enabled": "true"}).get_match( - feature_flag4 - ), + FeatureFlagMatcher( + [feature_flag4], + "307", + property_value_overrides={"string_enabled": "true"}, + ).get_match(feature_flag4), FeatureFlagMatch(True, None, FeatureFlagMatchReason.CONDITION_MATCH, 0), ) @@ -782,7 +1053,16 @@ def test_db_matches_independent_of_string_or_number_type(self): feature_flag = self.create_feature_flag( filters={ "groups": [ - {"properties": [{"key": "Distinct Id", "value": ["307"], "operator": "exact", "type": "person"}]} + { + "properties": [ + { + "key": "Distinct Id", + "value": ["307"], + "operator": "exact", + "type": "person", + } + ] + } ] } ) @@ -790,7 +1070,16 @@ def test_db_matches_independent_of_string_or_number_type(self): key="random", filters={ "groups": [ - {"properties": [{"key": "Distinct Id", "value": [307], "operator": "exact", "type": "person"}]}, + { + "properties": [ + { + "key": "Distinct Id", + "value": [307], + "operator": "exact", + "type": "person", + } + ] + }, ] }, ) @@ -799,7 +1088,16 @@ def test_db_matches_independent_of_string_or_number_type(self): key="random2", filters={ "groups": [ - {"properties": [{"key": "Distinct Id", "value": 307, "operator": "exact", "type": "person"}]}, + { + "properties": [ + { + "key": "Distinct Id", + "value": 307, + "operator": "exact", + "type": "person", + } + ] + }, ] }, ) @@ -873,14 +1171,23 @@ def test_zero_rollout_percentage(self): ) def test_complicated_flag(self): - Person.objects.create(team=self.team, distinct_ids=["test_id"], properties={"email": "test@posthog.com"}) + Person.objects.create( + team=self.team, + distinct_ids=["test_id"], + properties={"email": "test@posthog.com"}, + ) feature_flag = self.create_feature_flag( filters={ "groups": [ { "properties": [ - {"key": "email", "type": "person", "value": "test@posthog.com", "operator": "exact"} + { + "key": "email", + "type": "person", + "value": "test@posthog.com", + "operator": "exact", + } ], "rollout_percentage": 100, }, @@ -904,7 +1211,9 @@ def test_complicated_flag(self): def test_super_condition_matches_boolean(self): Person.objects.create( - team=self.team, distinct_ids=["test_id"], properties={"email": "test@posthog.com", "is_enabled": True} + team=self.team, + distinct_ids=["test_id"], + properties={"email": "test@posthog.com", "is_enabled": True}, ) feature_flag = self.create_feature_flag( @@ -912,13 +1221,23 @@ def test_super_condition_matches_boolean(self): "groups": [ { "properties": [ - {"key": "email", "type": "person", "value": "fake@posthog.com", "operator": "exact"} + { + "key": "email", + "type": "person", + "value": "fake@posthog.com", + "operator": "exact", + } ], "rollout_percentage": 0, }, { "properties": [ - {"key": "email", "type": "person", "value": "test@posthog.com", "operator": "exact"} + { + "key": "email", + "type": "person", + "value": "test@posthog.com", + "operator": "exact", + } ], "rollout_percentage": 100, }, @@ -926,8 +1245,15 @@ def test_super_condition_matches_boolean(self): ], "super_groups": [ { - "properties": [{"key": "is_enabled", "type": "person", "operator": "exact", "value": ["true"]}], - "rollout_percentage": 100, + "properties": [ + { + "key": "is_enabled", + "type": "person", + "operator": "exact", + "value": ["true"], + } + ], + "rollout_percentage": 100, }, ], }, @@ -948,7 +1274,9 @@ def test_super_condition_matches_boolean(self): def test_super_condition_matches_string(self): Person.objects.create( - team=self.team, distinct_ids=["test_id"], properties={"email": "test@posthog.com", "is_enabled": "true"} + team=self.team, + distinct_ids=["test_id"], + properties={"email": "test@posthog.com", "is_enabled": "true"}, ) feature_flag = self.create_feature_flag( @@ -956,13 +1284,23 @@ def test_super_condition_matches_string(self): "groups": [ { "properties": [ - {"key": "email", "type": "person", "value": "fake@posthog.com", "operator": "exact"} + { + "key": "email", + "type": "person", + "value": "fake@posthog.com", + "operator": "exact", + } ], "rollout_percentage": 0, }, { "properties": [ - {"key": "email", "type": "person", "value": "test@posthog.com", "operator": "exact"} + { + "key": "email", + "type": "person", + "value": "test@posthog.com", + "operator": "exact", + } ], "rollout_percentage": 100, }, @@ -970,7 +1308,14 @@ def test_super_condition_matches_string(self): ], "super_groups": [ { - "properties": [{"key": "is_enabled", "type": "person", "operator": "exact", "value": "true"}], + "properties": [ + { + "key": "is_enabled", + "type": "person", + "operator": "exact", + "value": "true", + } + ], "rollout_percentage": 100, }, ], @@ -985,7 +1330,9 @@ def test_super_condition_matches_string(self): def test_super_condition_matches_and_false(self): Person.objects.create( - team=self.team, distinct_ids=["test_id"], properties={"email": "test@posthog.com", "is_enabled": True} + team=self.team, + distinct_ids=["test_id"], + properties={"email": "test@posthog.com", "is_enabled": True}, ) feature_flag = self.create_feature_flag( @@ -993,13 +1340,23 @@ def test_super_condition_matches_and_false(self): "groups": [ { "properties": [ - {"key": "email", "type": "person", "value": "fake@posthog.com", "operator": "exact"} + { + "key": "email", + "type": "person", + "value": "fake@posthog.com", + "operator": "exact", + } ], "rollout_percentage": 0, }, { "properties": [ - {"key": "email", "type": "person", "value": "test@posthog.com", "operator": "exact"} + { + "key": "email", + "type": "person", + "value": "test@posthog.com", + "operator": "exact", + } ], "rollout_percentage": 100, }, @@ -1007,7 +1364,14 @@ def test_super_condition_matches_and_false(self): ], "super_groups": [ { - "properties": [{"key": "is_enabled", "type": "person", "operator": "exact", "value": False}], + "properties": [ + { + "key": "is_enabled", + "type": "person", + "operator": "exact", + "value": False, + } + ], "rollout_percentage": 100, }, ], @@ -1028,20 +1392,34 @@ def test_super_condition_matches_and_false(self): ) def test_super_condition_is_not_set(self): - Person.objects.create(team=self.team, distinct_ids=["test_id"], properties={"email": "test@posthog.com"}) + Person.objects.create( + team=self.team, + distinct_ids=["test_id"], + properties={"email": "test@posthog.com"}, + ) feature_flag = self.create_feature_flag( filters={ "groups": [ { "properties": [ - {"key": "email", "type": "person", "value": "fake@posthog.com", "operator": "exact"} + { + "key": "email", + "type": "person", + "value": "fake@posthog.com", + "operator": "exact", + } ], "rollout_percentage": 0, }, { "properties": [ - {"key": "email", "type": "person", "value": "test@posthog.com", "operator": "exact"} + { + "key": "email", + "type": "person", + "value": "test@posthog.com", + "operator": "exact", + } ], "rollout_percentage": 100, }, @@ -1049,7 +1427,14 @@ def test_super_condition_is_not_set(self): ], "super_groups": [ { - "properties": [{"key": "is_enabled", "type": "person", "operator": "exact", "value": True}], + "properties": [ + { + "key": "is_enabled", + "type": "person", + "operator": "exact", + "value": True, + } + ], "rollout_percentage": 100, }, ], @@ -1071,7 +1456,9 @@ def test_super_condition_is_not_set(self): def test_super_condition_promoted(self): Person.objects.create( - team=self.team, distinct_ids=["test_id"], properties={"email": "test@posthog.com", "is_enabled": True} + team=self.team, + distinct_ids=["test_id"], + properties={"email": "test@posthog.com", "is_enabled": True}, ) feature_flag = self.create_feature_flag( @@ -1079,13 +1466,23 @@ def test_super_condition_promoted(self): "groups": [ { "properties": [ - {"key": "email", "type": "person", "value": "fake@posthog.com", "operator": "exact"} + { + "key": "email", + "type": "person", + "value": "fake@posthog.com", + "operator": "exact", + } ], "rollout_percentage": 0, }, { "properties": [ - {"key": "email", "type": "person", "value": "test@posthog.com", "operator": "exact"} + { + "key": "email", + "type": "person", + "value": "test@posthog.com", + "operator": "exact", + } ], "rollout_percentage": 100, }, @@ -1116,7 +1513,9 @@ def test_super_condition_promoted(self): def test_super_condition_rolled_out_to_50(self): Person.objects.create( - team=self.team, distinct_ids=["test_id"], properties={"email": "test@posthog.com", "is_enabled": True} + team=self.team, + distinct_ids=["test_id"], + properties={"email": "test@posthog.com", "is_enabled": True}, ) feature_flag = self.create_feature_flag( @@ -1124,13 +1523,23 @@ def test_super_condition_rolled_out_to_50(self): "groups": [ { "properties": [ - {"key": "email", "type": "person", "value": "fake@posthog.com", "operator": "exact"} + { + "key": "email", + "type": "person", + "value": "fake@posthog.com", + "operator": "exact", + } ], "rollout_percentage": 0, }, { "properties": [ - {"key": "email", "type": "person", "value": "test@posthog.com", "operator": "exact"} + { + "key": "email", + "type": "person", + "value": "test@posthog.com", + "operator": "exact", + } ], "rollout_percentage": 100, }, @@ -1161,7 +1570,9 @@ def test_super_condition_rolled_out_to_50(self): def test_super_condition_with_override_properties(self): Person.objects.create( - team=self.team, distinct_ids=["test_id"], properties={"email": "test@posthog.com", "is_enabled": False} + team=self.team, + distinct_ids=["test_id"], + properties={"email": "test@posthog.com", "is_enabled": False}, ) feature_flag = self.create_feature_flag( @@ -1169,13 +1580,23 @@ def test_super_condition_with_override_properties(self): "groups": [ { "properties": [ - {"key": "email", "type": "person", "value": "fake@posthog.com", "operator": "exact"} + { + "key": "email", + "type": "person", + "value": "fake@posthog.com", + "operator": "exact", + } ], "rollout_percentage": 0, }, { "properties": [ - {"key": "email", "type": "person", "value": "test@posthog.com", "operator": "exact"} + { + "key": "email", + "type": "person", + "value": "test@posthog.com", + "operator": "exact", + } ], "rollout_percentage": 100, }, @@ -1183,7 +1604,14 @@ def test_super_condition_with_override_properties(self): ], "super_groups": [ { - "properties": [{"key": "is_enabled", "type": "person", "operator": "exact", "value": True}], + "properties": [ + { + "key": "is_enabled", + "type": "person", + "operator": "exact", + "value": True, + } + ], "rollout_percentage": 100, }, ], @@ -1205,9 +1633,11 @@ def test_super_condition_with_override_properties(self): FeatureFlagMatch(True, None, FeatureFlagMatchReason.CONDITION_MATCH, 2), ) self.assertEqual( - FeatureFlagMatcher([feature_flag], "example_id", property_value_overrides={"is_enabled": True}).get_match( - feature_flag - ), + FeatureFlagMatcher( + [feature_flag], + "example_id", + property_value_overrides={"is_enabled": True}, + ).get_match(feature_flag), FeatureFlagMatch(True, None, FeatureFlagMatchReason.SUPER_CONDITION_VALUE, 0), ) self.assertEqual( @@ -1215,27 +1645,43 @@ def test_super_condition_with_override_properties(self): FeatureFlagMatch(False, None, FeatureFlagMatchReason.OUT_OF_ROLLOUT_BOUND, 2), ) self.assertEqual( - FeatureFlagMatcher([feature_flag], "another_id", property_value_overrides={"is_enabled": True}).get_match( - feature_flag - ), + FeatureFlagMatcher( + [feature_flag], + "another_id", + property_value_overrides={"is_enabled": True}, + ).get_match(feature_flag), FeatureFlagMatch(True, None, FeatureFlagMatchReason.SUPER_CONDITION_VALUE, 0), ) def test_super_condition_with_override_properties_with_property_not_ingested(self): - Person.objects.create(team=self.team, distinct_ids=["test_id"], properties={"email": "test@posthog.com"}) + Person.objects.create( + team=self.team, + distinct_ids=["test_id"], + properties={"email": "test@posthog.com"}, + ) feature_flag = self.create_feature_flag( filters={ "groups": [ { "properties": [ - {"key": "email", "type": "person", "value": "fake@posthog.com", "operator": "exact"} + { + "key": "email", + "type": "person", + "value": "fake@posthog.com", + "operator": "exact", + } ], "rollout_percentage": 0, }, { "properties": [ - {"key": "email", "type": "person", "value": "test@posthog.com", "operator": "exact"} + { + "key": "email", + "type": "person", + "value": "test@posthog.com", + "operator": "exact", + } ], "rollout_percentage": 100, }, @@ -1243,7 +1689,14 @@ def test_super_condition_with_override_properties_with_property_not_ingested(sel ], "super_groups": [ { - "properties": [{"key": "is_enabled", "type": "person", "operator": "exact", "value": True}], + "properties": [ + { + "key": "is_enabled", + "type": "person", + "operator": "exact", + "value": True, + } + ], "rollout_percentage": 100, }, ], @@ -1265,9 +1718,11 @@ def test_super_condition_with_override_properties_with_property_not_ingested(sel FeatureFlagMatch(True, None, FeatureFlagMatchReason.CONDITION_MATCH, 2), ) self.assertEqual( - FeatureFlagMatcher([feature_flag], "example_id", property_value_overrides={"is_enabled": True}).get_match( - feature_flag - ), + FeatureFlagMatcher( + [feature_flag], + "example_id", + property_value_overrides={"is_enabled": True}, + ).get_match(feature_flag), FeatureFlagMatch(True, None, FeatureFlagMatchReason.SUPER_CONDITION_VALUE, 0), ) self.assertEqual( @@ -1275,15 +1730,21 @@ def test_super_condition_with_override_properties_with_property_not_ingested(sel FeatureFlagMatch(False, None, FeatureFlagMatchReason.OUT_OF_ROLLOUT_BOUND, 2), ) self.assertEqual( - FeatureFlagMatcher([feature_flag], "another_id", property_value_overrides={"is_enabled": True}).get_match( - feature_flag - ), + FeatureFlagMatcher( + [feature_flag], + "another_id", + property_value_overrides={"is_enabled": True}, + ).get_match(feature_flag), FeatureFlagMatch(True, None, FeatureFlagMatchReason.SUPER_CONDITION_VALUE, 0), ) @pytest.mark.skip("TODO: We're going to the database for now, but we should be able to do this in memory.") def test_super_condition_with_override_properties_doesnt_make_database_requests(self): - Person.objects.create(team=self.team, distinct_ids=["test_id"], properties={"email": "test@posthog.com"}) + Person.objects.create( + team=self.team, + distinct_ids=["test_id"], + properties={"email": "test@posthog.com"}, + ) feature_flag = self.create_feature_flag( filters={ @@ -1292,7 +1753,14 @@ def test_super_condition_with_override_properties_doesnt_make_database_requests( ], "super_groups": [ { - "properties": [{"key": "is_enabled", "type": "person", "operator": "exact", "value": True}], + "properties": [ + { + "key": "is_enabled", + "type": "person", + "operator": "exact", + "value": True, + } + ], "rollout_percentage": 100, }, ], @@ -1301,27 +1769,40 @@ def test_super_condition_with_override_properties_doesnt_make_database_requests( with self.assertNumQueries(0), snapshot_postgres_queries_context(self): self.assertEqual( - FeatureFlagMatcher([feature_flag], "test_id", property_value_overrides={"is_enabled": True}).get_match( - feature_flag - ), + FeatureFlagMatcher( + [feature_flag], + "test_id", + property_value_overrides={"is_enabled": True}, + ).get_match(feature_flag), FeatureFlagMatch(True, None, FeatureFlagMatchReason.SUPER_CONDITION_VALUE, 0), ) self.assertEqual( FeatureFlagMatcher( - [feature_flag], "example_id", property_value_overrides={"is_enabled": True} + [feature_flag], + "example_id", + property_value_overrides={"is_enabled": True}, ).get_match(feature_flag), FeatureFlagMatch(True, None, FeatureFlagMatchReason.SUPER_CONDITION_VALUE, 0), ) def test_flag_with_variant_overrides(self): - Person.objects.create(team=self.team, distinct_ids=["test_id"], properties={"email": "test@posthog.com"}) + Person.objects.create( + team=self.team, + distinct_ids=["test_id"], + properties={"email": "test@posthog.com"}, + ) feature_flag = self.create_feature_flag( filters={ "groups": [ { "properties": [ - {"key": "email", "type": "person", "value": "test@posthog.com", "operator": "exact"} + { + "key": "email", + "type": "person", + "value": "test@posthog.com", + "operator": "exact", + } ], "rollout_percentage": 100, "variant": "second-variant", @@ -1330,9 +1811,21 @@ def test_flag_with_variant_overrides(self): ], "multivariate": { "variants": [ - {"key": "first-variant", "name": "First Variant", "rollout_percentage": 50}, - {"key": "second-variant", "name": "Second Variant", "rollout_percentage": 25}, - {"key": "third-variant", "name": "Third Variant", "rollout_percentage": 25}, + { + "key": "first-variant", + "name": "First Variant", + "rollout_percentage": 50, + }, + { + "key": "second-variant", + "name": "Second Variant", + "rollout_percentage": 25, + }, + { + "key": "third-variant", + "name": "Third Variant", + "rollout_percentage": 25, + }, ] }, } @@ -1355,7 +1848,9 @@ def test_flag_with_variant_overrides(self): def test_flag_with_clashing_variant_overrides(self): Person.objects.create( - team=self.team, distinct_ids=["test_id", "example_id"], properties={"email": "test@posthog.com"} + team=self.team, + distinct_ids=["test_id", "example_id"], + properties={"email": "test@posthog.com"}, ) feature_flag = self.create_feature_flag( @@ -1363,7 +1858,12 @@ def test_flag_with_clashing_variant_overrides(self): "groups": [ { "properties": [ - {"key": "email", "type": "person", "value": "test@posthog.com", "operator": "exact"} + { + "key": "email", + "type": "person", + "value": "test@posthog.com", + "operator": "exact", + } ], "rollout_percentage": 100, "variant": "second-variant", @@ -1371,7 +1871,12 @@ def test_flag_with_clashing_variant_overrides(self): # since second-variant comes first in the list, it will be the one that gets picked { "properties": [ - {"key": "email", "type": "person", "value": "test@posthog.com", "operator": "exact"} + { + "key": "email", + "type": "person", + "value": "test@posthog.com", + "operator": "exact", + } ], "rollout_percentage": 100, "variant": "first-variant", @@ -1380,9 +1885,21 @@ def test_flag_with_clashing_variant_overrides(self): ], "multivariate": { "variants": [ - {"key": "first-variant", "name": "First Variant", "rollout_percentage": 50}, - {"key": "second-variant", "name": "Second Variant", "rollout_percentage": 25}, - {"key": "third-variant", "name": "Third Variant", "rollout_percentage": 25}, + { + "key": "first-variant", + "name": "First Variant", + "rollout_percentage": 50, + }, + { + "key": "second-variant", + "name": "Second Variant", + "rollout_percentage": 25, + }, + { + "key": "third-variant", + "name": "Third Variant", + "rollout_percentage": 25, + }, ] }, } @@ -1402,14 +1919,23 @@ def test_flag_with_clashing_variant_overrides(self): ) def test_flag_with_invalid_variant_overrides(self): - Person.objects.create(team=self.team, distinct_ids=["test_id"], properties={"email": "test@posthog.com"}) + Person.objects.create( + team=self.team, + distinct_ids=["test_id"], + properties={"email": "test@posthog.com"}, + ) feature_flag = self.create_feature_flag( filters={ "groups": [ { "properties": [ - {"key": "email", "type": "person", "value": "test@posthog.com", "operator": "exact"} + { + "key": "email", + "type": "person", + "value": "test@posthog.com", + "operator": "exact", + } ], "rollout_percentage": 100, "variant": "second???", @@ -1418,9 +1944,21 @@ def test_flag_with_invalid_variant_overrides(self): ], "multivariate": { "variants": [ - {"key": "first-variant", "name": "First Variant", "rollout_percentage": 50}, - {"key": "second-variant", "name": "Second Variant", "rollout_percentage": 25}, - {"key": "third-variant", "name": "Third Variant", "rollout_percentage": 25}, + { + "key": "first-variant", + "name": "First Variant", + "rollout_percentage": 50, + }, + { + "key": "second-variant", + "name": "Second Variant", + "rollout_percentage": 25, + }, + { + "key": "third-variant", + "name": "Third Variant", + "rollout_percentage": 25, + }, ] }, } @@ -1442,7 +1980,11 @@ def test_flag_with_invalid_variant_overrides(self): ) def test_flag_with_multiple_variant_overrides(self): - Person.objects.create(team=self.team, distinct_ids=["test_id"], properties={"email": "test@posthog.com"}) + Person.objects.create( + team=self.team, + distinct_ids=["test_id"], + properties={"email": "test@posthog.com"}, + ) feature_flag = self.create_feature_flag( filters={ @@ -1453,7 +1995,12 @@ def test_flag_with_multiple_variant_overrides(self): }, { "properties": [ - {"key": "email", "type": "person", "value": "test@posthog.com", "operator": "exact"} + { + "key": "email", + "type": "person", + "value": "test@posthog.com", + "operator": "exact", + } ], "rollout_percentage": 100, "variant": "second-variant", @@ -1462,9 +2009,21 @@ def test_flag_with_multiple_variant_overrides(self): ], "multivariate": { "variants": [ - {"key": "first-variant", "name": "First Variant", "rollout_percentage": 50}, - {"key": "second-variant", "name": "Second Variant", "rollout_percentage": 25}, - {"key": "third-variant", "name": "Third Variant", "rollout_percentage": 25}, + { + "key": "first-variant", + "name": "First Variant", + "rollout_percentage": 50, + }, + { + "key": "second-variant", + "name": "Second Variant", + "rollout_percentage": 25, + }, + { + "key": "third-variant", + "name": "Third Variant", + "rollout_percentage": 25, + }, ] }, } @@ -1484,14 +2043,23 @@ def test_flag_with_multiple_variant_overrides(self): ) def test_multiple_flags(self): - Person.objects.create(team=self.team, distinct_ids=["test_id"], properties={"email": "test@posthog.com"}) + Person.objects.create( + team=self.team, + distinct_ids=["test_id"], + properties={"email": "test@posthog.com"}, + ) self.create_groups() feature_flag_one = self.create_feature_flag( filters={ "groups": [ { "properties": [ - {"key": "email", "type": "person", "value": "test@posthog.com", "operator": "exact"} + { + "key": "email", + "type": "person", + "value": "test@posthog.com", + "operator": "exact", + } ], "rollout_percentage": 100, }, @@ -1507,10 +2075,18 @@ def test_multiple_flags(self): filters={"groups": [{"rollout_percentage": 0}]}, key="never_match" ) feature_flag_group_match = self.create_feature_flag( - filters={"aggregation_group_type_index": 1, "groups": [{"rollout_percentage": 100}]}, key="group_match" + filters={ + "aggregation_group_type_index": 1, + "groups": [{"rollout_percentage": 100}], + }, + key="group_match", ) feature_flag_group_no_match = self.create_feature_flag( - filters={"aggregation_group_type_index": 1, "groups": [{"rollout_percentage": 0}]}, key="group_no_match" + filters={ + "aggregation_group_type_index": 1, + "groups": [{"rollout_percentage": 0}], + }, + key="group_no_match", ) feature_flag_group_property_match = self.create_feature_flag( filters={ @@ -1621,13 +2197,34 @@ def test_multiple_flags(self): self.assertEqual( reasons, { - "one": {"reason": FeatureFlagMatchReason.CONDITION_MATCH, "condition_index": 0}, - "always_match": {"reason": FeatureFlagMatchReason.CONDITION_MATCH, "condition_index": 0}, - "group_match": {"reason": FeatureFlagMatchReason.CONDITION_MATCH, "condition_index": 0}, - "variant": {"reason": FeatureFlagMatchReason.CONDITION_MATCH, "condition_index": 0}, - "group_property_match": {"reason": FeatureFlagMatchReason.CONDITION_MATCH, "condition_index": 0}, - "never_match": {"reason": FeatureFlagMatchReason.OUT_OF_ROLLOUT_BOUND, "condition_index": 0}, - "group_no_match": {"reason": FeatureFlagMatchReason.OUT_OF_ROLLOUT_BOUND, "condition_index": 0}, + "one": { + "reason": FeatureFlagMatchReason.CONDITION_MATCH, + "condition_index": 0, + }, + "always_match": { + "reason": FeatureFlagMatchReason.CONDITION_MATCH, + "condition_index": 0, + }, + "group_match": { + "reason": FeatureFlagMatchReason.CONDITION_MATCH, + "condition_index": 0, + }, + "variant": { + "reason": FeatureFlagMatchReason.CONDITION_MATCH, + "condition_index": 0, + }, + "group_property_match": { + "reason": FeatureFlagMatchReason.CONDITION_MATCH, + "condition_index": 0, + }, + "never_match": { + "reason": FeatureFlagMatchReason.OUT_OF_ROLLOUT_BOUND, + "condition_index": 0, + }, + "group_no_match": { + "reason": FeatureFlagMatchReason.OUT_OF_ROLLOUT_BOUND, + "condition_index": 0, + }, "group_property_different_match": { "reason": FeatureFlagMatchReason.NO_CONDITION_MATCH, "condition_index": 0, @@ -1678,23 +2275,52 @@ def test_multiple_flags(self): self.assertEqual( reasons, { - "one": {"reason": FeatureFlagMatchReason.CONDITION_MATCH, "condition_index": 0}, - "always_match": {"reason": FeatureFlagMatchReason.CONDITION_MATCH, "condition_index": 0}, - "group_match": {"reason": FeatureFlagMatchReason.NO_GROUP_TYPE, "condition_index": None}, - "variant": {"reason": FeatureFlagMatchReason.CONDITION_MATCH, "condition_index": 0}, + "one": { + "reason": FeatureFlagMatchReason.CONDITION_MATCH, + "condition_index": 0, + }, + "always_match": { + "reason": FeatureFlagMatchReason.CONDITION_MATCH, + "condition_index": 0, + }, + "group_match": { + "reason": FeatureFlagMatchReason.NO_GROUP_TYPE, + "condition_index": None, + }, + "variant": { + "reason": FeatureFlagMatchReason.CONDITION_MATCH, + "condition_index": 0, + }, "group_property_different_match": { "reason": FeatureFlagMatchReason.CONDITION_MATCH, "condition_index": 0, }, - "never_match": {"reason": FeatureFlagMatchReason.OUT_OF_ROLLOUT_BOUND, "condition_index": 0}, - "group_no_match": {"reason": FeatureFlagMatchReason.NO_GROUP_TYPE, "condition_index": None}, - "group_property_match": {"reason": FeatureFlagMatchReason.NO_CONDITION_MATCH, "condition_index": 0}, + "never_match": { + "reason": FeatureFlagMatchReason.OUT_OF_ROLLOUT_BOUND, + "condition_index": 0, + }, + "group_no_match": { + "reason": FeatureFlagMatchReason.NO_GROUP_TYPE, + "condition_index": None, + }, + "group_property_match": { + "reason": FeatureFlagMatchReason.NO_CONDITION_MATCH, + "condition_index": 0, + }, }, ) def test_multi_property_filters(self): - Person.objects.create(team=self.team, distinct_ids=["example_id"], properties={"email": "tim@posthog.com"}) - Person.objects.create(team=self.team, distinct_ids=["another_id"], properties={"email": "example@example.com"}) + Person.objects.create( + team=self.team, + distinct_ids=["example_id"], + properties={"email": "tim@posthog.com"}, + ) + Person.objects.create( + team=self.team, + distinct_ids=["another_id"], + properties={"email": "example@example.com"}, + ) Person.objects.create(team=self.team, distinct_ids=["false_id"], properties={}) feature_flag = self.create_feature_flag( filters={ @@ -1720,8 +2346,16 @@ def test_multi_property_filters(self): ) def test_multi_property_filters_with_override_properties(self): - Person.objects.create(team=self.team, distinct_ids=["example_id"], properties={"email": "tim@posthog.com"}) - Person.objects.create(team=self.team, distinct_ids=["another_id"], properties={"email": "example@example.com"}) + Person.objects.create( + team=self.team, + distinct_ids=["example_id"], + properties={"email": "tim@posthog.com"}, + ) + Person.objects.create( + team=self.team, + distinct_ids=["another_id"], + properties={"email": "example@example.com"}, + ) Person.objects.create(team=self.team, distinct_ids=["random_id"], properties={}) feature_flag = self.create_feature_flag( filters={ @@ -1738,9 +2372,11 @@ def test_multi_property_filters_with_override_properties(self): ) # can be computed locally self.assertEqual( - FeatureFlagMatcher([feature_flag], "example_id", property_value_overrides={"email": "bzz"}).get_match( - feature_flag - ), + FeatureFlagMatcher( + [feature_flag], + "example_id", + property_value_overrides={"email": "bzz"}, + ).get_match(feature_flag), FeatureFlagMatch(False, None, FeatureFlagMatchReason.NO_CONDITION_MATCH, 1), ) @@ -1753,7 +2389,9 @@ def test_multi_property_filters_with_override_properties(self): # can be computed locally self.assertEqual( FeatureFlagMatcher( - [feature_flag], "random_id", property_value_overrides={"email": "example@example.com"} + [feature_flag], + "random_id", + property_value_overrides={"email": "example@example.com"}, ).get_match(feature_flag), FeatureFlagMatch(True, None, FeatureFlagMatchReason.CONDITION_MATCH, 1), ) @@ -1766,8 +2404,18 @@ def test_multi_property_filters_with_override_group_properties(self): "groups": [ { "properties": [ - {"key": "name", "value": ["foo.inc"], "type": "group", "group_type_index": 0}, - {"key": "not_ingested", "value": "example.com", "type": "group", "group_type_index": 0}, + { + "key": "name", + "value": ["foo.inc"], + "type": "group", + "group_type_index": 0, + }, + { + "key": "not_ingested", + "value": "example.com", + "type": "group", + "group_type_index": 0, + }, ] }, ], @@ -1775,7 +2423,7 @@ def test_multi_property_filters_with_override_group_properties(self): ) cache = FlagsMatcherCache(self.team.id) # force the query to load group types - cache.group_type_index_to_name + cache.group_type_index_to_name # noqa: B018 with self.assertNumQueries(12): self.assertEqual( @@ -1824,7 +2472,12 @@ def test_multi_property_filters_with_override_group_properties(self): "random_id", cache=cache, groups={"organization": "foo"}, - group_property_value_overrides={"organization": {"not_ingested": "example.com", "name": "foo.inc"}}, + group_property_value_overrides={ + "organization": { + "not_ingested": "example.com", + "name": "foo.inc", + } + }, ).get_match(feature_flag), FeatureFlagMatch(True, None, FeatureFlagMatchReason.CONDITION_MATCH, 0), ) @@ -1835,7 +2488,12 @@ def test_multi_property_filters_with_override_group_properties(self): "random_id", cache=cache, groups={"organization": "bar"}, - group_property_value_overrides={"organization": {"not_ingested": "example.com", "name": "foo.inc"}}, + group_property_value_overrides={ + "organization": { + "not_ingested": "example.com", + "name": "foo.inc", + } + }, ).get_match(feature_flag), FeatureFlagMatch(True, None, FeatureFlagMatchReason.CONDITION_MATCH, 0), ) @@ -1844,7 +2502,15 @@ def test_override_properties_where_person_doesnt_exist_yet(self): feature_flag = self.create_feature_flag( filters={ "groups": [ - {"properties": [{"key": "email", "value": "tim@posthog.com", "type": "person"}]}, + { + "properties": [ + { + "key": "email", + "value": "tim@posthog.com", + "type": "person", + } + ] + }, {"properties": [{"key": "email", "value": "example@example.com"}]}, ] } @@ -1852,14 +2518,18 @@ def test_override_properties_where_person_doesnt_exist_yet(self): with self.assertNumQueries(0): self.assertEqual( FeatureFlagMatcher( - [feature_flag], "example_id", property_value_overrides={"email": "tim@posthog.com"} + [feature_flag], + "example_id", + property_value_overrides={"email": "tim@posthog.com"}, ).get_match(feature_flag), FeatureFlagMatch(True, None, FeatureFlagMatchReason.CONDITION_MATCH, 0), ) self.assertEqual( - FeatureFlagMatcher([feature_flag], "example_id", property_value_overrides={"email": "bzz"}).get_match( - feature_flag - ), + FeatureFlagMatcher( + [feature_flag], + "example_id", + property_value_overrides={"email": "bzz"}, + ).get_match(feature_flag), FeatureFlagMatch(False, None, FeatureFlagMatchReason.NO_CONDITION_MATCH, 1), ) @@ -1872,7 +2542,9 @@ def test_override_properties_where_person_doesnt_exist_yet(self): with self.assertNumQueries(0): self.assertEqual( FeatureFlagMatcher( - [feature_flag], "random_id", property_value_overrides={"email": "example@example.com"} + [feature_flag], + "random_id", + property_value_overrides={"email": "example@example.com"}, ).get_match(feature_flag), FeatureFlagMatch(True, None, FeatureFlagMatchReason.CONDITION_MATCH, 1), ) @@ -1896,14 +2568,18 @@ def test_override_properties_where_person_doesnt_exist_yet_multiple_conditions(s # and user doesn't exist yet self.assertEqual( FeatureFlagMatcher( - [feature_flag], "example_id", property_value_overrides={"email": "tim@posthog.com"} + [feature_flag], + "example_id", + property_value_overrides={"email": "tim@posthog.com"}, ).get_match(feature_flag), FeatureFlagMatch(False, None, FeatureFlagMatchReason.NO_CONDITION_MATCH, 0), ) self.assertEqual( - FeatureFlagMatcher([feature_flag], "example_id", property_value_overrides={"email": "bzz"}).get_match( - feature_flag - ), + FeatureFlagMatcher( + [feature_flag], + "example_id", + property_value_overrides={"email": "bzz"}, + ).get_match(feature_flag), FeatureFlagMatch(False, None, FeatureFlagMatchReason.NO_CONDITION_MATCH, 0), ) @@ -1919,7 +2595,11 @@ def test_override_properties_where_person_doesnt_exist_yet_multiple_conditions(s FeatureFlagMatcher( [feature_flag], "random_id_without_rollout", - property_value_overrides={"email": "tim@posthog.com", "another_prop": "slow", "blah": "blah"}, + property_value_overrides={ + "email": "tim@posthog.com", + "another_prop": "slow", + "blah": "blah", + }, ).get_match(feature_flag), FeatureFlagMatch(True, None, FeatureFlagMatchReason.CONDITION_MATCH, 0), ) @@ -1927,7 +2607,11 @@ def test_override_properties_where_person_doesnt_exist_yet_multiple_conditions(s FeatureFlagMatcher( [feature_flag], "random_id_within_rollout", - property_value_overrides={"email": "tim@posthog.com", "another_prop": "slow", "blah": "blah"}, + property_value_overrides={ + "email": "tim@posthog.com", + "another_prop": "slow", + "blah": "blah", + }, ).get_match(feature_flag), FeatureFlagMatch(False, None, FeatureFlagMatchReason.OUT_OF_ROLLOUT_BOUND, 0), ) @@ -1938,7 +2622,11 @@ def test_override_properties_where_person_doesnt_exist_yet_multiple_conditions(s FeatureFlagMatcher( [feature_flag], "random_id_without_rollout", - property_value_overrides={"email": "tim@posthog.com", "another_prop": "slow2", "blah": "blah"}, + property_value_overrides={ + "email": "tim@posthog.com", + "another_prop": "slow2", + "blah": "blah", + }, ).get_match(feature_flag), FeatureFlagMatch(False, None, FeatureFlagMatchReason.NO_CONDITION_MATCH, 0), ) @@ -1946,14 +2634,26 @@ def test_override_properties_where_person_doesnt_exist_yet_multiple_conditions(s FeatureFlagMatcher( [feature_flag], "random_id_without_rollout", - property_value_overrides={"email": "tim2@posthog.com", "another_prop": "slow", "blah": "blah"}, + property_value_overrides={ + "email": "tim2@posthog.com", + "another_prop": "slow", + "blah": "blah", + }, ).get_match(feature_flag), FeatureFlagMatch(False, None, FeatureFlagMatchReason.NO_CONDITION_MATCH, 0), ) def test_multi_property_filters_with_override_properties_with_is_not_set(self): - Person.objects.create(team=self.team, distinct_ids=["example_id"], properties={"email": "tim@posthog.com"}) - Person.objects.create(team=self.team, distinct_ids=["another_id"], properties={"email": "example@example.com"}) + Person.objects.create( + team=self.team, + distinct_ids=["example_id"], + properties={"email": "tim@posthog.com"}, + ) + Person.objects.create( + team=self.team, + distinct_ids=["another_id"], + properties={"email": "example@example.com"}, + ) Person.objects.create(team=self.team, distinct_ids=["random_id"], properties={}) feature_flag = self.create_feature_flag( filters={"groups": [{"properties": [{"key": "email", "operator": "is_not_set"}]}]} @@ -1964,9 +2664,11 @@ def test_multi_property_filters_with_override_properties_with_is_not_set(self): FeatureFlagMatch(False, None, FeatureFlagMatchReason.NO_CONDITION_MATCH, 0), ) self.assertEqual( - FeatureFlagMatcher([feature_flag], "example_id", property_value_overrides={"email": "bzz"}).get_match( - feature_flag - ), + FeatureFlagMatcher( + [feature_flag], + "example_id", + property_value_overrides={"email": "bzz"}, + ).get_match(feature_flag), FeatureFlagMatch(False, None, FeatureFlagMatchReason.NO_CONDITION_MATCH, 0), ) @@ -1977,7 +2679,9 @@ def test_multi_property_filters_with_override_properties_with_is_not_set(self): ) self.assertEqual( FeatureFlagMatcher( - [feature_flag], "random_id", property_value_overrides={"email": "example@example.com"} + [feature_flag], + "random_id", + property_value_overrides={"email": "example@example.com"}, ).get_match(feature_flag), FeatureFlagMatch(True, None, FeatureFlagMatchReason.CONDITION_MATCH, 0), ) @@ -2037,7 +2741,8 @@ def test_cohort_cache_no_unnecessary_queries(self): ) feature_flag1: FeatureFlag = self.create_feature_flag( - key="x1", filters={"groups": [{"properties": [{"key": "id", "value": cohort1.pk, "type": "cohort"}]}]} + key="x1", + filters={"groups": [{"properties": [{"key": "id", "value": cohort1.pk, "type": "cohort"}]}]}, ) feature_flag2: FeatureFlag = self.create_feature_flag( filters={"groups": [{"properties": [{"key": "id", "value": cohort2.pk, "type": "cohort"}]}]} @@ -2052,14 +2757,20 @@ def test_cohort_cache_no_unnecessary_queries(self): ] }, ) - Person.objects.create(team=self.team, distinct_ids=["example_id"], properties={"email": "tim@posthog.com"}) + Person.objects.create( + team=self.team, + distinct_ids=["example_id"], + properties={"email": "tim@posthog.com"}, + ) with self.assertNumQueries(5): # single query for all cohorts # no team queries self.assertEqual( FeatureFlagMatcher( - [feature_flag1, feature_flag2, feature_flag3], "example_id", property_value_overrides={} + [feature_flag1, feature_flag2, feature_flag3], + "example_id", + property_value_overrides={}, ).get_match(feature_flag1), FeatureFlagMatch(True, None, FeatureFlagMatchReason.CONDITION_MATCH, 0), ) @@ -2101,18 +2812,25 @@ def test_cohort_filters_with_override_properties(self): ) feature_flag1: FeatureFlag = self.create_feature_flag( - key="x1", filters={"groups": [{"properties": [{"key": "id", "value": cohort1.pk, "type": "cohort"}]}]} + key="x1", + filters={"groups": [{"properties": [{"key": "id", "value": cohort1.pk, "type": "cohort"}]}]}, ) feature_flag2: FeatureFlag = self.create_feature_flag( filters={"groups": [{"properties": [{"key": "id", "value": cohort2.pk, "type": "cohort"}]}]} ) - Person.objects.create(team=self.team, distinct_ids=["example_id"], properties={"email": "tim@posthog.com"}) + Person.objects.create( + team=self.team, + distinct_ids=["example_id"], + properties={"email": "tim@posthog.com"}, + ) with self.assertNumQueries(5): self.assertEqual( - FeatureFlagMatcher([feature_flag1, feature_flag2], "example_id", property_value_overrides={}).get_match( - feature_flag1 - ), + FeatureFlagMatcher( + [feature_flag1, feature_flag2], + "example_id", + property_value_overrides={}, + ).get_match(feature_flag1), FeatureFlagMatch(True, None, FeatureFlagMatchReason.CONDITION_MATCH, 0), ) @@ -2121,7 +2839,9 @@ def test_cohort_filters_with_override_properties(self): # no postgres person query required here to get the person, because email is sufficient self.assertEqual( FeatureFlagMatcher( - [feature_flag1, feature_flag2], "example_id", property_value_overrides={"email": "bzz"} + [feature_flag1, feature_flag2], + "example_id", + property_value_overrides={"email": "bzz"}, ).get_match(feature_flag1), FeatureFlagMatch(False, None, FeatureFlagMatchReason.NO_CONDITION_MATCH, 0), ) @@ -2130,7 +2850,9 @@ def test_cohort_filters_with_override_properties(self): # no postgres query required here to get the person self.assertEqual( FeatureFlagMatcher( - [feature_flag1, feature_flag2], "example_id", property_value_overrides={"email": "neil@posthog.com"} + [feature_flag1, feature_flag2], + "example_id", + property_value_overrides={"email": "neil@posthog.com"}, ).get_match(feature_flag1), FeatureFlagMatch(True, None, FeatureFlagMatchReason.CONDITION_MATCH, 0), ) @@ -2139,7 +2861,9 @@ def test_cohort_filters_with_override_properties(self): # Random person doesn't yet exist, but still should resolve thanks to overrides self.assertEqual( FeatureFlagMatcher( - [feature_flag1, feature_flag2], "random_id", property_value_overrides={"email": "xxx"} + [feature_flag1, feature_flag2], + "random_id", + property_value_overrides={"email": "xxx"}, ).get_match(feature_flag2), FeatureFlagMatch(False, None, FeatureFlagMatchReason.NO_CONDITION_MATCH, 0), ) @@ -2192,13 +2916,16 @@ def test_complex_cohort_filter_with_override_properties(self): name="cohort1", ) feature_flag1: FeatureFlag = self.create_feature_flag( - key="x1", filters={"groups": [{"properties": [{"key": "id", "value": cohort1.pk, "type": "cohort"}]}]} + key="x1", + filters={"groups": [{"properties": [{"key": "id", "value": cohort1.pk, "type": "cohort"}]}]}, ) with self.assertNumQueries(5): self.assertEqual( FeatureFlagMatcher( - [feature_flag1], "example_id", property_value_overrides={"email": "neil@posthog.com"} + [feature_flag1], + "example_id", + property_value_overrides={"email": "neil@posthog.com"}, ).get_match(feature_flag1), FeatureFlagMatch(True, None, FeatureFlagMatchReason.CONDITION_MATCH, 0), ) @@ -2206,9 +2933,11 @@ def test_complex_cohort_filter_with_override_properties(self): with self.assertNumQueries(5): # no local computation because cohort lookup is required self.assertEqual( - FeatureFlagMatcher([feature_flag1], "example_id", property_value_overrides={"email": "bzz"}).get_match( - feature_flag1 - ), + FeatureFlagMatcher( + [feature_flag1], + "example_id", + property_value_overrides={"email": "bzz"}, + ).get_match(feature_flag1), FeatureFlagMatch(False, None, FeatureFlagMatchReason.NO_CONDITION_MATCH, 0), ) @@ -2234,7 +2963,12 @@ def test_cohort_filters_with_multiple_OR_override_properties(self): { "type": "AND", "values": [ - {"key": "email", "type": "person", "value": ["fuzion@xyz.com"], "operator": "exact"} + { + "key": "email", + "type": "person", + "value": ["fuzion@xyz.com"], + "operator": "exact", + } ], }, ], @@ -2247,7 +2981,11 @@ def test_cohort_filters_with_multiple_OR_override_properties(self): filters={"groups": [{"properties": [{"key": "id", "value": cohort1.pk, "type": "cohort"}]}]} ) - Person.objects.create(team=self.team, distinct_ids=["example_id"], properties={"email": "tim@posthog.com"}) + Person.objects.create( + team=self.team, + distinct_ids=["example_id"], + properties={"email": "tim@posthog.com"}, + ) with self.assertNumQueries(5): self.assertEqual( @@ -2259,16 +2997,32 @@ def test_cohort_filters_with_multiple_OR_override_properties(self): # no local computation because cohort lookup is required self.assertEqual( FeatureFlagMatcher( - [feature_flag1], "example_id", property_value_overrides={"email": "neil@posthog.com"} + [feature_flag1], + "example_id", + property_value_overrides={"email": "neil@posthog.com"}, ).get_match(feature_flag1), FeatureFlagMatch(True, None, FeatureFlagMatchReason.CONDITION_MATCH, 0), ) def test_user_in_cohort(self): - Person.objects.create(team=self.team, distinct_ids=["example_id_1"], properties={"$some_prop_1": "something_1"}) + Person.objects.create( + team=self.team, + distinct_ids=["example_id_1"], + properties={"$some_prop_1": "something_1"}, + ) cohort = Cohort.objects.create( team=self.team, - groups=[{"properties": [{"key": "$some_prop_1", "value": "something_1", "type": "person"}]}], + groups=[ + { + "properties": [ + { + "key": "$some_prop_1", + "value": "something_1", + "type": "person", + } + ] + } + ], name="cohort1", ) cohort.calculate_people_ch(pending_version=0) @@ -2287,9 +3041,21 @@ def test_user_in_cohort(self): ) def test_cohort_expansion_returns_same_result_as_regular_flag(self): - Person.objects.create(team=self.team, distinct_ids=["example_id_4"], properties={"$some_prop1": "something1"}) - Person.objects.create(team=self.team, distinct_ids=["example_id_5"], properties={"$some_prop2": "something2"}) - Person.objects.create(team=self.team, distinct_ids=["example_id_6"], properties={"$some_prop": "something"}) + Person.objects.create( + team=self.team, + distinct_ids=["example_id_4"], + properties={"$some_prop1": "something1"}, + ) + Person.objects.create( + team=self.team, + distinct_ids=["example_id_5"], + properties={"$some_prop2": "something2"}, + ) + Person.objects.create( + team=self.team, + distinct_ids=["example_id_6"], + properties={"$some_prop": "something"}, + ) cohort = Cohort.objects.create( team=self.team, @@ -2300,8 +3066,16 @@ def test_cohort_expansion_returns_same_result_as_regular_flag(self): { "type": "OR", "values": [ - {"key": "$some_prop1", "value": "something1", "type": "person"}, - {"key": "$some_prop2", "value": "something2", "type": "person"}, + { + "key": "$some_prop1", + "value": "something1", + "type": "person", + }, + { + "key": "$some_prop2", + "value": "something2", + "type": "person", + }, ], } ], @@ -2318,7 +3092,10 @@ def test_cohort_expansion_returns_same_result_as_regular_flag(self): key=ff_key, filters={ "groups": [ - {"properties": [{"key": "id", "value": cohort.pk, "type": "cohort"}], "rollout_percentage": 28} + { + "properties": [{"key": "id", "value": cohort.pk, "type": "cohort"}], + "rollout_percentage": 28, + } ] }, ) @@ -2377,10 +3154,24 @@ def test_user_in_static_cohort(self): ) def test_user_in_cohort_without_calculation(self): - Person.objects.create(team=self.team, distinct_ids=["example_id_1"], properties={"$some_prop_1": "something_1"}) + Person.objects.create( + team=self.team, + distinct_ids=["example_id_1"], + properties={"$some_prop_1": "something_1"}, + ) cohort = Cohort.objects.create( team=self.team, - groups=[{"properties": [{"key": "$some_prop_1", "value": "something_1", "type": "person"}]}], + groups=[ + { + "properties": [ + { + "key": "$some_prop_1", + "value": "something_1", + "type": "person", + } + ] + } + ], name="cohort1", ) feature_flag: FeatureFlag = self.create_feature_flag( @@ -2407,8 +3198,16 @@ def test_invalid_filters_dont_set_db_down(self, mock_database_healthcheck): { "type": "OR", "values": [ - {"key": "$some_prop", "value": "nomatchihope", "type": "person"}, - {"key": "$some_prop2", "value": "nomatchihope2", "type": "person"}, + { + "key": "$some_prop", + "value": "nomatchihope", + "type": "person", + }, + { + "key": "$some_prop2", + "value": "nomatchihope2", + "type": "person", + }, { "key": "$pageview", "event_type": "events", @@ -2431,7 +3230,10 @@ def test_invalid_filters_dont_set_db_down(self, mock_database_healthcheck): key="active-flag", filters={ "groups": [ - {"properties": [{"key": "id", "value": cohort.pk, "type": "cohort"}], "rollout_percentage": 50} + { + "properties": [{"key": "id", "value": cohort.pk, "type": "cohort"}], + "rollout_percentage": 50, + } ] }, ) @@ -2469,7 +3271,12 @@ def test_invalid_group_filters_dont_set_db_down(self, mock_database_healthcheck) matcher.get_matches(), ( {"active-flag": True}, - {"active-flag": {"condition_index": 0, "reason": FeatureFlagMatchReason.CONDITION_MATCH}}, + { + "active-flag": { + "condition_index": 0, + "reason": FeatureFlagMatchReason.CONDITION_MATCH, + } + }, {}, True, ), @@ -2512,9 +3319,21 @@ def test_legacy_property_filters(self): ) def test_legacy_rollout_and_property_filter(self): - Person.objects.create(team=self.team, distinct_ids=["example_id"], properties={"email": "tim@posthog.com"}) - Person.objects.create(team=self.team, distinct_ids=["another_id"], properties={"email": "tim@posthog.com"}) - Person.objects.create(team=self.team, distinct_ids=["id_number_3"], properties={"email": "example@example.com"}) + Person.objects.create( + team=self.team, + distinct_ids=["example_id"], + properties={"email": "tim@posthog.com"}, + ) + Person.objects.create( + team=self.team, + distinct_ids=["another_id"], + properties={"email": "tim@posthog.com"}, + ) + Person.objects.create( + team=self.team, + distinct_ids=["id_number_3"], + properties={"email": "example@example.com"}, + ) feature_flag = self.create_feature_flag( rollout_percentage=50, filters={"properties": [{"key": "email", "value": "tim@posthog.com", "type": "person"}]}, @@ -2534,10 +3353,24 @@ def test_legacy_rollout_and_property_filter(self): ) def test_legacy_user_in_cohort(self): - Person.objects.create(team=self.team, distinct_ids=["example_id_2"], properties={"$some_prop_2": "something_2"}) + Person.objects.create( + team=self.team, + distinct_ids=["example_id_2"], + properties={"$some_prop_2": "something_2"}, + ) cohort = Cohort.objects.create( team=self.team, - groups=[{"properties": [{"key": "$some_prop_2", "value": "something_2", "type": "person"}]}], + groups=[ + { + "properties": [ + { + "key": "$some_prop_2", + "value": "something_2", + "type": "person", + } + ] + } + ], name="cohort2", ) cohort.calculate_people_ch(pending_version=0) @@ -2561,9 +3394,21 @@ def test_variants(self): "groups": [{"properties": [], "rollout_percentage": None}], "multivariate": { "variants": [ - {"key": "first-variant", "name": "First Variant", "rollout_percentage": 50}, - {"key": "second-variant", "name": "Second Variant", "rollout_percentage": 25}, - {"key": "third-variant", "name": "Third Variant", "rollout_percentage": 25}, + { + "key": "first-variant", + "name": "First Variant", + "rollout_percentage": 50, + }, + { + "key": "second-variant", + "name": "Second Variant", + "rollout_percentage": 25, + }, + { + "key": "third-variant", + "name": "Third Variant", + "rollout_percentage": 25, + }, ] }, } @@ -2572,26 +3417,38 @@ def test_variants(self): self.assertEqual( FeatureFlagMatcher([feature_flag], "11").get_match(feature_flag), FeatureFlagMatch( - True, variant="first-variant", reason=FeatureFlagMatchReason.CONDITION_MATCH, condition_index=0 + True, + variant="first-variant", + reason=FeatureFlagMatchReason.CONDITION_MATCH, + condition_index=0, ), ) self.assertEqual( FeatureFlagMatcher([feature_flag], "example_id").get_match(feature_flag), FeatureFlagMatch( - True, variant="second-variant", reason=FeatureFlagMatchReason.CONDITION_MATCH, condition_index=0 + True, + variant="second-variant", + reason=FeatureFlagMatchReason.CONDITION_MATCH, + condition_index=0, ), ) self.assertEqual( FeatureFlagMatcher([feature_flag], "3").get_match(feature_flag), FeatureFlagMatch( - True, variant="third-variant", reason=FeatureFlagMatchReason.CONDITION_MATCH, condition_index=0 + True, + variant="third-variant", + reason=FeatureFlagMatchReason.CONDITION_MATCH, + condition_index=0, ), ) def test_flag_by_groups_with_rollout_100(self): self.create_groups() feature_flag = self.create_feature_flag( - filters={"aggregation_group_type_index": 1, "groups": [{"rollout_percentage": 100}]} + filters={ + "aggregation_group_type_index": 1, + "groups": [{"rollout_percentage": 100}], + } ) self.assertEqual( @@ -2614,7 +3471,10 @@ def test_flag_by_groups_with_rollout_100(self): def test_flag_by_groups_with_rollout_50(self): self.create_groups() feature_flag = self.create_feature_flag( - filters={"aggregation_group_type_index": 1, "groups": [{"rollout_percentage": 50}]} + filters={ + "aggregation_group_type_index": 1, + "groups": [{"rollout_percentage": 50}], + } ) self.assertEqual( @@ -2632,7 +3492,16 @@ def test_flag_by_group_properties(self): filters={ "aggregation_group_type_index": 0, "groups": [ - {"properties": [{"key": "name", "value": ["foo.inc"], "type": "group", "group_type_index": 0}]} + { + "properties": [ + { + "key": "name", + "value": ["foo.inc"], + "type": "group", + "group_type_index": 0, + } + ] + } ], } ) @@ -2659,18 +3528,34 @@ def create_groups(self): version=1, ) Group.objects.create( - team=self.team, group_type_index=0, group_key="foo", group_properties={"name": "foo.inc"}, version=1 + team=self.team, + group_type_index=0, + group_key="foo", + group_properties={"name": "foo.inc"}, + version=1, ) Group.objects.create( - team=self.team, group_type_index=0, group_key="bar", group_properties={"name": "var.inc"}, version=1 + team=self.team, + group_type_index=0, + group_key="bar", + group_properties={"name": "var.inc"}, + version=1, ) # Add other irrelevant groups for i in range(5): Group.objects.create( - team=self.team, group_type_index=1, group_key=f"group_key{i}", group_properties={}, version=1 + team=self.team, + group_type_index=1, + group_key=f"group_key{i}", + group_properties={}, + version=1, ) Group.objects.create( - team=self.team, group_type_index=1, group_key="group_key", group_properties={"name": "var.inc"}, version=1 + team=self.team, + group_type_index=1, + group_key="group_key", + group_properties={"name": "var.inc"}, + version=1, ) def create_feature_flag(self, key="beta-feature", **kwargs): @@ -2704,9 +3589,21 @@ def setUpTestData(cls): "groups": [{"properties": [], "rollout_percentage": None}], "multivariate": { "variants": [ - {"key": "first-variant", "name": "First Variant", "rollout_percentage": 50}, - {"key": "second-variant", "name": "Second Variant", "rollout_percentage": 25}, - {"key": "third-variant", "name": "Third Variant", "rollout_percentage": 25}, + { + "key": "first-variant", + "name": "First Variant", + "rollout_percentage": 50, + }, + { + "key": "second-variant", + "name": "Second Variant", + "rollout_percentage": 25, + }, + { + "key": "third-variant", + "name": "Third Variant", + "rollout_percentage": 25, + }, ] }, }, @@ -2717,12 +3614,16 @@ def setUpTestData(cls): ) cls.person = Person.objects.create( - team=cls.team, distinct_ids=["example_id"], properties={"email": "tim@posthog.com", "team": "posthog"} + team=cls.team, + distinct_ids=["example_id"], + properties={"email": "tim@posthog.com", "team": "posthog"}, ) def test_setting_overrides(self): set_feature_flag_hash_key_overrides( - team_id=self.team.pk, distinct_ids=self.person.distinct_ids, hash_key_override="other_id" + team_id=self.team.pk, + distinct_ids=self.person.distinct_ids, + hash_key_override="other_id", ) with connection.cursor() as cursor: @@ -2735,7 +3636,9 @@ def test_setting_overrides(self): def test_retrieving_hash_key_overrides(self): set_feature_flag_hash_key_overrides( - team_id=self.team.pk, distinct_ids=self.person.distinct_ids, hash_key_override="other_id" + team_id=self.team.pk, + distinct_ids=self.person.distinct_ids, + hash_key_override="other_id", ) hash_keys = get_feature_flag_hash_key_overrides(self.team.pk, ["example_id"]) @@ -2744,11 +3647,15 @@ def test_retrieving_hash_key_overrides(self): def test_hash_key_overrides_for_multiple_ids_when_people_are_not_merged(self): Person.objects.create( - team=self.team, distinct_ids=["1"], properties={"email": "beuk@posthog.com", "team": "posthog"} + team=self.team, + distinct_ids=["1"], + properties={"email": "beuk@posthog.com", "team": "posthog"}, ) Person.objects.create( - team=self.team, distinct_ids=["2"], properties={"email": "beuk2@posthog.com", "team": "posthog"} + team=self.team, + distinct_ids=["2"], + properties={"email": "beuk2@posthog.com", "team": "posthog"}, ) set_feature_flag_hash_key_overrides(team_id=self.team.pk, distinct_ids=["1"], hash_key_override="other_id1") @@ -2766,7 +3673,10 @@ def test_setting_overrides_doesnt_balk_with_existing_overrides(self): FeatureFlagHashKeyOverride.objects.bulk_create( [ FeatureFlagHashKeyOverride( - team_id=self.team.pk, person_id=self.person.id, feature_flag_key=feature_flag.key, hash_key=hash_key + team_id=self.team.pk, + person_id=self.person.id, + feature_flag_key=feature_flag.key, + hash_key=hash_key, ) for feature_flag in all_feature_flags ] @@ -2774,7 +3684,9 @@ def test_setting_overrides_doesnt_balk_with_existing_overrides(self): # and now we come to get new overrides set_feature_flag_hash_key_overrides( - team_id=self.team.pk, distinct_ids=self.person.distinct_ids, hash_key_override="other_id" + team_id=self.team.pk, + distinct_ids=self.person.distinct_ids, + hash_key_override="other_id", ) with connection.cursor() as cursor: @@ -2787,7 +3699,9 @@ def test_setting_overrides_doesnt_balk_with_existing_overrides(self): def test_setting_overrides_when_persons_dont_exist(self): set_feature_flag_hash_key_overrides( - team_id=self.team.pk, distinct_ids=["1", "2", "3", "4"], hash_key_override="other_id" + team_id=self.team.pk, + distinct_ids=["1", "2", "3", "4"], + hash_key_override="other_id", ) with connection.cursor() as cursor: @@ -2830,7 +3744,10 @@ def test_entire_flow_with_hash_key_override(self): self.assertEqual(payloads, {}) -@patch("posthog.models.feature_flag.flag_matching.postgres_healthcheck.is_connected", return_value=True) +@patch( + "posthog.models.feature_flag.flag_matching.postgres_healthcheck.is_connected", + return_value=True, +) class TestHashKeyOverridesRaceConditions(TransactionTestCase, QueryMatchingTest): def setUp(self) -> None: return super().setUp() @@ -2861,9 +3778,21 @@ def test_hash_key_overrides_with_race_conditions(self, *args): "groups": [{"properties": [], "rollout_percentage": None}], "multivariate": { "variants": [ - {"key": "first-variant", "name": "First Variant", "rollout_percentage": 50}, - {"key": "second-variant", "name": "Second Variant", "rollout_percentage": 25}, - {"key": "third-variant", "name": "Third Variant", "rollout_percentage": 25}, + { + "key": "first-variant", + "name": "First Variant", + "rollout_percentage": 50, + }, + { + "key": "second-variant", + "name": "Second Variant", + "rollout_percentage": 25, + }, + { + "key": "third-variant", + "name": "Third Variant", + "rollout_percentage": 25, + }, ] }, }, @@ -2874,12 +3803,20 @@ def test_hash_key_overrides_with_race_conditions(self, *args): ) Person.objects.create( - team=team, distinct_ids=["example_id"], properties={"email": "tim@posthog.com", "team": "posthog"} + team=team, + distinct_ids=["example_id"], + properties={"email": "tim@posthog.com", "team": "posthog"}, ) with concurrent.futures.ThreadPoolExecutor(max_workers=5) as executor: future_to_index = { - executor.submit(get_all_feature_flags, team.pk, "other_id", {}, hash_key_override="example_id"): index + executor.submit( + get_all_feature_flags, + team.pk, + "other_id", + {}, + hash_key_override="example_id", + ): index for index in range(5) } for future in concurrent.futures.as_completed(future_to_index): @@ -2934,9 +3871,21 @@ def insert_fail(execute, sql, *args, **kwargs): "groups": [{"properties": [], "rollout_percentage": None}], "multivariate": { "variants": [ - {"key": "first-variant", "name": "First Variant", "rollout_percentage": 50}, - {"key": "second-variant", "name": "Second Variant", "rollout_percentage": 25}, - {"key": "third-variant", "name": "Third Variant", "rollout_percentage": 25}, + { + "key": "first-variant", + "name": "First Variant", + "rollout_percentage": 50, + }, + { + "key": "second-variant", + "name": "Second Variant", + "rollout_percentage": 25, + }, + { + "key": "third-variant", + "name": "Third Variant", + "rollout_percentage": 25, + }, ] }, }, @@ -2947,10 +3896,14 @@ def insert_fail(execute, sql, *args, **kwargs): ) Person.objects.create( - team=team, distinct_ids=["example_id"], properties={"email": "tim@posthog.com", "team": "posthog"} + team=team, + distinct_ids=["example_id"], + properties={"email": "tim@posthog.com", "team": "posthog"}, ) Person.objects.create( - team=team, distinct_ids=["other_id"], properties={"email": "tim@posthog.com", "team": "posthog"} + team=team, + distinct_ids=["other_id"], + properties={"email": "tim@posthog.com", "team": "posthog"}, ) with snapshot_postgres_queries_context(self, capture_all_queries=True), connection.execute_wrapper(insert_fail): @@ -3011,9 +3964,21 @@ def __call__(self, execute, sql, *args, **kwargs): "groups": [{"properties": [], "rollout_percentage": None}], "multivariate": { "variants": [ - {"key": "first-variant", "name": "First Variant", "rollout_percentage": 50}, - {"key": "second-variant", "name": "Second Variant", "rollout_percentage": 25}, - {"key": "third-variant", "name": "Third Variant", "rollout_percentage": 25}, + { + "key": "first-variant", + "name": "First Variant", + "rollout_percentage": 50, + }, + { + "key": "second-variant", + "name": "Second Variant", + "rollout_percentage": 25, + }, + { + "key": "third-variant", + "name": "Third Variant", + "rollout_percentage": 25, + }, ] }, }, @@ -3024,10 +3989,14 @@ def __call__(self, execute, sql, *args, **kwargs): ) Person.objects.create( - team=team, distinct_ids=["example_id"], properties={"email": "tim@posthog.com", "team": "posthog"} + team=team, + distinct_ids=["example_id"], + properties={"email": "tim@posthog.com", "team": "posthog"}, ) Person.objects.create( - team=team, distinct_ids=["other_id"], properties={"email": "tim@posthog.com", "team": "posthog"} + team=team, + distinct_ids=["other_id"], + properties={"email": "tim@posthog.com", "team": "posthog"}, ) with snapshot_postgres_queries_context(self, capture_all_queries=True), connection.execute_wrapper( @@ -3070,9 +4039,21 @@ def test_hash_key_overrides_with_race_conditions_on_person_creation_and_deletion "groups": [{"properties": [], "rollout_percentage": None}], "multivariate": { "variants": [ - {"key": "first-variant", "name": "First Variant", "rollout_percentage": 50}, - {"key": "second-variant", "name": "Second Variant", "rollout_percentage": 25}, - {"key": "third-variant", "name": "Third Variant", "rollout_percentage": 25}, + { + "key": "first-variant", + "name": "First Variant", + "rollout_percentage": 50, + }, + { + "key": "second-variant", + "name": "Second Variant", + "rollout_percentage": 25, + }, + { + "key": "third-variant", + "name": "Third Variant", + "rollout_percentage": 25, + }, ] }, }, @@ -3083,10 +4064,14 @@ def test_hash_key_overrides_with_race_conditions_on_person_creation_and_deletion ) person1 = Person.objects.create( - team=team, distinct_ids=["example_id"], properties={"email": "tim@posthog.com", "team": "posthog"} + team=team, + distinct_ids=["example_id"], + properties={"email": "tim@posthog.com", "team": "posthog"}, ) person2 = Person.objects.create( - team=team, distinct_ids=["other_id"], properties={"email": "tim@posthog.com", "team": "posthog"} + team=team, + distinct_ids=["other_id"], + properties={"email": "tim@posthog.com", "team": "posthog"}, ) def delete_and_add(person, person2, distinct_id): @@ -3097,7 +4082,13 @@ def delete_and_add(person, person2, distinct_id): with concurrent.futures.ThreadPoolExecutor(max_workers=5) as executor: future_to_index = { - executor.submit(get_all_feature_flags, team.pk, "other_id", {}, hash_key_override="example_id"): index + executor.submit( + get_all_feature_flags, + team.pk, + "other_id", + {}, + hash_key_override="example_id", + ): index for index in range(5) } @@ -4142,11 +5133,13 @@ def test_simple_flag_consistency(self): if results[i]: self.assertEqual( - feature_flag_match, FeatureFlagMatch(True, None, FeatureFlagMatchReason.CONDITION_MATCH, 0) + feature_flag_match, + FeatureFlagMatch(True, None, FeatureFlagMatchReason.CONDITION_MATCH, 0), ) else: self.assertEqual( - feature_flag_match, FeatureFlagMatch(False, None, FeatureFlagMatchReason.OUT_OF_ROLLOUT_BOUND, 0) + feature_flag_match, + FeatureFlagMatch(False, None, FeatureFlagMatchReason.OUT_OF_ROLLOUT_BOUND, 0), ) def test_multivariate_flag_consistency(self): @@ -4159,11 +5152,31 @@ def test_multivariate_flag_consistency(self): "groups": [{"properties": [], "rollout_percentage": 55}], "multivariate": { "variants": [ - {"key": "first-variant", "name": "First Variant", "rollout_percentage": 50}, - {"key": "second-variant", "name": "Second Variant", "rollout_percentage": 20}, - {"key": "third-variant", "name": "Third Variant", "rollout_percentage": 20}, - {"key": "fourth-variant", "name": "Fourth Variant", "rollout_percentage": 5}, - {"key": "fifth-variant", "name": "Fifth Variant", "rollout_percentage": 5}, + { + "key": "first-variant", + "name": "First Variant", + "rollout_percentage": 50, + }, + { + "key": "second-variant", + "name": "Second Variant", + "rollout_percentage": 20, + }, + { + "key": "third-variant", + "name": "Third Variant", + "rollout_percentage": 20, + }, + { + "key": "fourth-variant", + "name": "Fourth Variant", + "rollout_percentage": 5, + }, + { + "key": "fifth-variant", + "name": "Fifth Variant", + "rollout_percentage": 5, + }, ] }, }, @@ -5189,5 +6202,6 @@ def test_multivariate_flag_consistency(self): ) else: self.assertEqual( - feature_flag_match, FeatureFlagMatch(False, None, FeatureFlagMatchReason.OUT_OF_ROLLOUT_BOUND, 0) + feature_flag_match, + FeatureFlagMatch(False, None, FeatureFlagMatchReason.OUT_OF_ROLLOUT_BOUND, 0), ) diff --git a/posthog/test/test_feature_flag_analytics.py b/posthog/test/test_feature_flag_analytics.py index 17566d9806fd0..6387b96fda750 100644 --- a/posthog/test/test_feature_flag_analytics.py +++ b/posthog/test/test_feature_flag_analytics.py @@ -57,10 +57,12 @@ def test_increment_request_count_adds_requests_to_appropriate_buckets(self): # redis returns encoded bytes self.assertEqual( - client.hgetall(f"posthog:decide_requests:{team_id}"), {b"165192618": b"10", b"165192619": b"5"} + client.hgetall(f"posthog:decide_requests:{team_id}"), + {b"165192618": b"10", b"165192619": b"5"}, ) self.assertEqual( - client.hgetall(f"posthog:decide_requests:{other_team_id}"), {b"165192618": b"7", b"165192619": b"3"} + client.hgetall(f"posthog:decide_requests:{other_team_id}"), + {b"165192618": b"7", b"165192619": b"3"}, ) self.assertEqual(client.hgetall(f"posthog:decide_requests:other"), {}) @@ -184,7 +186,10 @@ def test_no_token_loses_capture_team_decide_usage_data(self): mock_capture.capture.assert_not_called() client = redis.get_client() - self.assertEqual(client.hgetall(f"posthog:decide_requests:{team_id}"), {b"165192620": b"5"}) + self.assertEqual( + client.hgetall(f"posthog:decide_requests:{team_id}"), + {b"165192620": b"5"}, + ) with self.settings(DECIDE_BILLING_ANALYTICS_TOKEN="token"): capture_team_decide_usage(mock_capture, team_id, team_uuid) @@ -252,7 +257,12 @@ def test_no_interference_between_different_types_of_new_incoming_increments(self for index in range(5) } future_to_index = { - executor.submit(increment_request_count, team_id, 1, FlagRequestType.LOCAL_EVALUATION): index + executor.submit( + increment_request_count, + team_id, + 1, + FlagRequestType.LOCAL_EVALUATION, + ): index for index in range(10, 15) } @@ -291,8 +301,14 @@ def test_no_interference_between_different_types_of_new_incoming_increments(self # check that the increments made it through # and no extra requests were counted - self.assertEqual(client.hgetall(f"posthog:decide_requests:{team_id}"), {b"165192620": b"8"}) - self.assertEqual(client.hgetall(f"posthog:local_evaluation_requests:{team_id}"), {b"165192620": b"8"}) + self.assertEqual( + client.hgetall(f"posthog:decide_requests:{team_id}"), + {b"165192620": b"8"}, + ) + self.assertEqual( + client.hgetall(f"posthog:local_evaluation_requests:{team_id}"), + {b"165192620": b"8"}, + ) self.assertEqual(client.hgetall(f"posthog:decide_requests:{other_team_id}"), {}) self.assertEqual(client.hgetall(f"posthog:local_evaluation_requests:{other_team_id}"), {}) @@ -345,7 +361,12 @@ def test_locking_works_for_capture_team_decide_usage(self): for index in range(5) } future_to_index = { - executor.submit(capture_team_decide_usage, mock_capture, other_team_id, other_team_uuid): index + executor.submit( + capture_team_decide_usage, + mock_capture, + other_team_id, + other_team_uuid, + ): index for index in range(5, 10) } @@ -446,7 +467,10 @@ def test_locking_in_redis_doesnt_block_new_incoming_increments(self): # check that the increments made it through # and no extra requests were counted - self.assertEqual(client.hgetall(f"posthog:decide_requests:{team_id}"), {b"165192620": b"8"}) + self.assertEqual( + client.hgetall(f"posthog:decide_requests:{team_id}"), + {b"165192620": b"8"}, + ) self.assertEqual(client.hgetall(f"posthog:decide_requests:{other_team_id}"), {}) diff --git a/posthog/test/test_gzip_middleware.py b/posthog/test/test_gzip_middleware.py index bdb9176bf1005..8ee7529767608 100644 --- a/posthog/test/test_gzip_middleware.py +++ b/posthog/test/test_gzip_middleware.py @@ -33,7 +33,11 @@ def test_compresses_when_on_allow_list(self) -> None: def test_no_compression_for_unsuccessful_requests_to_paths_on_the_allow_list(self) -> None: with self.settings(GZIP_RESPONSE_ALLOW_LIST=["something-else", "snapshots$"]): response = self._get_path(f"/api/projects/{self.team.pk}/session_recordings/blah/snapshots") - self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND, msg=response.content.decode("utf-8")) + self.assertEqual( + response.status_code, + status.HTTP_404_NOT_FOUND, + msg=response.content.decode("utf-8"), + ) contentEncoding = response.headers.get("Content-Encoding", None) self.assertEqual(contentEncoding, None) diff --git a/posthog/test/test_instance_setting_model.py b/posthog/test/test_instance_setting_model.py index 2c3b28408594d..6ddd659c6a213 100644 --- a/posthog/test/test_instance_setting_model.py +++ b/posthog/test/test_instance_setting_model.py @@ -59,7 +59,11 @@ def test_can_retrieve_multiple_settings(db): assert get_instance_setting("ASYNC_MIGRATIONS_ROLLBACK_TIMEOUT") == 20000 returned = get_instance_settings( - ["MATERIALIZED_COLUMNS_ENABLED", "ASYNC_MIGRATIONS_ROLLBACK_TIMEOUT", "ASYNC_MIGRATIONS_AUTO_CONTINUE"] + [ + "MATERIALIZED_COLUMNS_ENABLED", + "ASYNC_MIGRATIONS_ROLLBACK_TIMEOUT", + "ASYNC_MIGRATIONS_AUTO_CONTINUE", + ] ) assert returned == { diff --git a/posthog/test/test_journeys.py b/posthog/test/test_journeys.py index 0b48e84e3e553..784a1d8867d81 100644 --- a/posthog/test/test_journeys.py +++ b/posthog/test/test_journeys.py @@ -13,7 +13,9 @@ def journeys_for( - events_by_person: Dict[str, List[Dict[str, Any]]], team: Team, create_people: bool = True + events_by_person: Dict[str, List[Dict[str, Any]]], + team: Team, + create_people: bool = True, ) -> Dict[str, Person]: """ Helper for creating specific events for a team. @@ -48,18 +50,22 @@ def _create_event_from_args(**event): people[distinct_id] = update_or_create_person(distinct_ids=[distinct_id], team_id=team.pk) else: people[distinct_id] = Person.objects.get( - persondistinctid__distinct_id=distinct_id, persondistinctid__team_id=team.pk + persondistinctid__distinct_id=distinct_id, + persondistinctid__team_id=team.pk, ) for event in events: - # Populate group properties as well group_mapping = {} for property_key, value in (event.get("properties") or {}).items(): if property_key.startswith("$group_"): group_type_index = property_key[-1] try: - group = Group.objects.get(team_id=team.pk, group_type_index=group_type_index, group_key=value) + group = Group.objects.get( + team_id=team.pk, + group_type_index=group_type_index, + group_key=value, + ) group_mapping[f"group{group_type_index}"] = group except Group.DoesNotExist: @@ -191,6 +197,10 @@ def update_or_create_person(distinct_ids: List[str], team_id: int, **kwargs): PersonDistinctId.objects.update_or_create( distinct_id=distinct_id, team_id=person.team_id, - defaults={"person_id": person.id, "team_id": team_id, "distinct_id": distinct_id}, + defaults={ + "person_id": person.id, + "team_id": team_id, + "distinct_id": distinct_id, + }, ) return person diff --git a/posthog/test/test_middleware.py b/posthog/test/test_middleware.py index 2739336182db7..b5efb9c731891 100644 --- a/posthog/test/test_middleware.py +++ b/posthog/test/test_middleware.py @@ -68,21 +68,42 @@ def test_ip_range(self): self.assertIn(b"IP is not allowed", response.content) def test_trusted_proxies(self): - with self.settings(ALLOWED_IP_BLOCKS=["192.168.0.0/31", "127.0.0.0/25,128.0.0.1"], USE_X_FORWARDED_HOST=True): + with self.settings( + ALLOWED_IP_BLOCKS=["192.168.0.0/31", "127.0.0.0/25,128.0.0.1"], + USE_X_FORWARDED_HOST=True, + ): with self.settings(TRUSTED_PROXIES="10.0.0.1"): - response = self.client.get("/", REMOTE_ADDR="10.0.0.1", HTTP_X_FORWARDED_FOR="192.168.0.1,10.0.0.1") + response = self.client.get( + "/", + REMOTE_ADDR="10.0.0.1", + HTTP_X_FORWARDED_FOR="192.168.0.1,10.0.0.1", + ) self.assertNotIn(b"IP is not allowed", response.content) def test_attempt_spoofing(self): - with self.settings(ALLOWED_IP_BLOCKS=["192.168.0.0/31", "127.0.0.0/25,128.0.0.1"], USE_X_FORWARDED_HOST=True): + with self.settings( + ALLOWED_IP_BLOCKS=["192.168.0.0/31", "127.0.0.0/25,128.0.0.1"], + USE_X_FORWARDED_HOST=True, + ): with self.settings(TRUSTED_PROXIES="10.0.0.1"): - response = self.client.get("/", REMOTE_ADDR="10.0.0.1", HTTP_X_FORWARDED_FOR="192.168.0.1,10.0.0.2") + response = self.client.get( + "/", + REMOTE_ADDR="10.0.0.1", + HTTP_X_FORWARDED_FOR="192.168.0.1,10.0.0.2", + ) self.assertIn(b"IP is not allowed", response.content) def test_trust_all_proxies(self): - with self.settings(ALLOWED_IP_BLOCKS=["192.168.0.0/31", "127.0.0.0/25,128.0.0.1"], USE_X_FORWARDED_HOST=True): + with self.settings( + ALLOWED_IP_BLOCKS=["192.168.0.0/31", "127.0.0.0/25,128.0.0.1"], + USE_X_FORWARDED_HOST=True, + ): with self.settings(TRUST_ALL_PROXIES=True): - response = self.client.get("/", REMOTE_ADDR="10.0.0.1", HTTP_X_FORWARDED_FOR="192.168.0.1,10.0.0.1") + response = self.client.get( + "/", + REMOTE_ADDR="10.0.0.1", + HTTP_X_FORWARDED_FOR="192.168.0.1,10.0.0.1", + ) self.assertNotIn(b"IP is not allowed", response.content) @@ -137,7 +158,10 @@ def test_project_switched_when_accessing_dashboard_of_another_accessible_team_wi def test_project_unchanged_when_accessing_dashboard_of_another_off_limits_team(self): _, _, third_team = Organization.objects.bootstrap( - None, name="Third Party", slug="third-party", team_fields={"name": "Third Team"} + None, + name="Third Party", + slug="third-party", + team_fields={"name": "Third Team"}, ) dashboard = Dashboard.objects.create(team=third_team) diff --git a/posthog/test/test_migration_0218.py b/posthog/test/test_migration_0218.py index 28e2269a4f13d..3165b4f6ef845 100644 --- a/posthog/test/test_migration_0218.py +++ b/posthog/test/test_migration_0218.py @@ -7,7 +7,6 @@ class TaggedItemsUniquenessTest(NonAtomicTestMigrations): - migrate_from = "0217_team_primary_dashboard" migrate_to = "0218_uniqueness_constraint_tagged_items" diff --git a/posthog/test/test_migration_0219.py b/posthog/test/test_migration_0219.py index 0b3e91016537b..65be99a451258 100644 --- a/posthog/test/test_migration_0219.py +++ b/posthog/test/test_migration_0219.py @@ -7,7 +7,6 @@ class TagsTestCase(TestMigrations): - migrate_from = "0218_uniqueness_constraint_tagged_items" migrate_to = "0219_migrate_tags_v2" assert_snapshots = True @@ -27,7 +26,10 @@ def setUpBeforeMigration(self, apps): name="private dashboard", deprecated_tags=["a", "b", "c", "a", "b", "existing tag", "", " ", None], ) - filter_dict = {"events": [{"id": "$pageview"}], "properties": [{"key": "$browser", "value": "Mac OS X"}]} + filter_dict = { + "events": [{"id": "$pageview"}], + "properties": [{"key": "$browser", "value": "Mac OS X"}], + } self.insight_with_tags = Insight.objects.create( dashboard=self.dashboard, filters=filter_dict, @@ -45,7 +47,12 @@ def setUpBeforeMigration(self, apps): organization=self.org2, api_token="token12345", test_account_filters=[ - {"key": "email", "value": "@posthog.com", "operator": "not_icontains", "type": "person"} + { + "key": "email", + "value": "@posthog.com", + "operator": "not_icontains", + "type": "person", + } ], ) self.team2_total_insights = 1_001 @@ -64,7 +71,10 @@ def setUpBeforeMigration(self, apps): ignore_conflicts=True, batch_size=1000, ) - TaggedItem.objects.create(tag=tag2, insight_id=Insight.objects.filter(team_id=self.team2.id).first().id) + TaggedItem.objects.create( + tag=tag2, + insight_id=Insight.objects.filter(team_id=self.team2.id).first().id, + ) def test_tags_migrated(self): Tag = self.apps.get_model("posthog", "Tag") # type: ignore diff --git a/posthog/test/test_migration_0220.py b/posthog/test/test_migration_0220.py index 94be745296a62..c052967cd7383 100644 --- a/posthog/test/test_migration_0220.py +++ b/posthog/test/test_migration_0220.py @@ -6,7 +6,6 @@ class TagsTestCase(TestMigrations): - migrate_from = "0219_migrate_tags_v2" migrate_to = "0220_backfill_primary_dashboards" assert_snapshots = True @@ -63,16 +62,25 @@ def test_backfill_primary_dashboard(self): Team = self.apps.get_model("posthog", "Team") # type: ignore # CASE 1: - self.assertEqual(Team.objects.get(name="t1").primary_dashboard.id, Dashboard.objects.get(name="d2").id) + self.assertEqual( + Team.objects.get(name="t1").primary_dashboard.id, + Dashboard.objects.get(name="d2").id, + ) # CASE 2: self.assertEqual(Team.objects.get(name="t2").primary_dashboard, None) # CASE 3: - self.assertEqual(Team.objects.get(name="t3").primary_dashboard.id, Dashboard.objects.get(name="d4").id) + self.assertEqual( + Team.objects.get(name="t3").primary_dashboard.id, + Dashboard.objects.get(name="d4").id, + ) # CASE 4: - self.assertEqual(Team.objects.get(name="t4").primary_dashboard.id, Dashboard.objects.get(name="d6").id) + self.assertEqual( + Team.objects.get(name="t4").primary_dashboard.id, + Dashboard.objects.get(name="d6").id, + ) # BATCH CASE teams = Team.objects.filter(name__startswith="batch_team-") diff --git a/posthog/test/test_migration_0222.py b/posthog/test/test_migration_0222.py index 759fe8e27e453..e2b80f26d3eba 100644 --- a/posthog/test/test_migration_0222.py +++ b/posthog/test/test_migration_0222.py @@ -6,7 +6,6 @@ class DeletedPrimaryDashboardTestCase(TestMigrations): - migrate_from = "0221_add_activity_log_model" migrate_to = "0222_fix_deleted_primary_dashboards" assert_snapshots = True @@ -65,19 +64,31 @@ def test_backfill_primary_dashboard(self): Team = self.apps.get_model("posthog", "Team") # type: ignore # CASE 1: - self.assertEqual(Team.objects.get(name="t1").primary_dashboard.id, Dashboard.objects.get(name="d1").id) + self.assertEqual( + Team.objects.get(name="t1").primary_dashboard.id, + Dashboard.objects.get(name="d1").id, + ) # CASE 2: self.assertEqual(Team.objects.get(name="t2").primary_dashboard, None) # CASE 3: - self.assertEqual(Team.objects.get(name="t3").primary_dashboard.id, Dashboard.objects.get(name="d4").id) + self.assertEqual( + Team.objects.get(name="t3").primary_dashboard.id, + Dashboard.objects.get(name="d4").id, + ) # CASE 4: - self.assertEqual(Team.objects.get(name="t4").primary_dashboard.id, Dashboard.objects.get(name="d6").id) + self.assertEqual( + Team.objects.get(name="t4").primary_dashboard.id, + Dashboard.objects.get(name="d6").id, + ) # CASE 5: - self.assertEqual(Team.objects.get(name="t5").primary_dashboard.id, Dashboard.objects.get(name="d9").id) + self.assertEqual( + Team.objects.get(name="t5").primary_dashboard.id, + Dashboard.objects.get(name="d9").id, + ) def tearDown(self): Team = self.apps.get_model("posthog", "Team") # type: ignore diff --git a/posthog/test/test_migration_0227.py b/posthog/test/test_migration_0227.py index 6a024080fa2d4..d920752faa57a 100644 --- a/posthog/test/test_migration_0227.py +++ b/posthog/test/test_migration_0227.py @@ -6,7 +6,6 @@ class CreatingDashboardTilesTestCase(TestMigrations): - migrate_from = "0226_longer_action_slack_message_format" migrate_to = "0227_add_dashboard_tiles" @@ -50,7 +49,10 @@ def setUpBeforeMigration(self, apps): # Expect: no tiles dashboard_3 = Dashboard.objects.create(name="d3", team=team, deleted=False) Insight.objects.create( - team=team, filters={"insight": "TRENDS", "date_from": "-7d"}, dashboard=dashboard_3, deleted=True + team=team, + filters={"insight": "TRENDS", "date_from": "-7d"}, + dashboard=dashboard_3, + deleted=True, ) def test_migrate_to_create_tiles(self): diff --git a/posthog/test/test_migration_0228.py b/posthog/test/test_migration_0228.py index 1bdd78d476f1d..d4031020e6c48 100644 --- a/posthog/test/test_migration_0228.py +++ b/posthog/test/test_migration_0228.py @@ -8,7 +8,6 @@ class FixingDashboardTilesTestCase(TestMigrations): - migrate_from = "0227_add_dashboard_tiles" migrate_to = "0228_fix_tile_layouts" @@ -27,7 +26,9 @@ def setUpBeforeMigration(self, apps): # dashboard tile with valid layouts # Expect: no conversion for this tile insight_for_case_1 = Insight.objects.create( - team=team, filters={"insight": "TRENDS", "date_from": "-7d"}, name="has valid layouts on tile" + team=team, + filters={"insight": "TRENDS", "date_from": "-7d"}, + name="has valid layouts on tile", ) DashboardTile.objects.create(dashboard=dashboard, insight=insight_for_case_1, layouts={"a": "dict"}) @@ -35,9 +36,15 @@ def setUpBeforeMigration(self, apps): # dashboard with layout that has been stringified once # Expect: conversion for this tile insight_for_case_2 = Insight.objects.create( - team=team, filters={"insight": "TRENDS", "date_from": "-7d"}, name="has invalid layouts on tile" + team=team, + filters={"insight": "TRENDS", "date_from": "-7d"}, + name="has invalid layouts on tile", + ) + DashboardTile.objects.create( + dashboard=dashboard, + insight=insight_for_case_2, + layouts=json.dumps({"a": "dict"}), ) - DashboardTile.objects.create(dashboard=dashboard, insight=insight_for_case_2, layouts=json.dumps({"a": "dict"})) def test_migrate_to_create_tiles(self): """ @@ -56,12 +63,14 @@ def test_migrate_to_create_tiles(self): # CASE 1: self.assertIsInstance( - DashboardTile.objects.get(dashboard__name="d1", insight__name="has valid layouts on tile").layouts, dict + DashboardTile.objects.get(dashboard__name="d1", insight__name="has valid layouts on tile").layouts, + dict, ) # CASE 2: self.assertIsInstance( - DashboardTile.objects.get(dashboard__name="d1", insight__name="has invalid layouts on tile").layouts, dict + DashboardTile.objects.get(dashboard__name="d1", insight__name="has invalid layouts on tile").layouts, + dict, ) def tearDown(self): diff --git a/posthog/test/test_migration_0259.py b/posthog/test/test_migration_0259.py index 297ed9db491a7..304a05c9fd6ac 100644 --- a/posthog/test/test_migration_0259.py +++ b/posthog/test/test_migration_0259.py @@ -6,7 +6,6 @@ class RecordingDomainMigrationTestCase(TestMigrations): - migrate_from = "0258_team_recording_domains" migrate_to = "0259_backfill_team_recording_domains" assert_snapshots = True @@ -48,7 +47,13 @@ def setUpBeforeMigration(self, apps): Team.objects.create( name="t4", organization=org, - app_urls=["jamaican me crazy", "test.com", "http://", "", "https://test.example.com"], + app_urls=[ + "jamaican me crazy", + "test.com", + "http://", + "", + "https://test.example.com", + ], ) def test_backfill_recording_domain(self): diff --git a/posthog/test/test_migration_0273.py b/posthog/test/test_migration_0273.py index 333bde6cffad9..3ce270f54540c 100644 --- a/posthog/test/test_migration_0273.py +++ b/posthog/test/test_migration_0273.py @@ -136,7 +136,9 @@ def test_migration(self): }, ) PluginStorage.objects.create( - plugin_config_id=self.plugin_configs[4].pk, key="EXPORT_PARAMETERS", value=json.dumps({"id": "5"}) + plugin_config_id=self.plugin_configs[4].pk, + key="EXPORT_PARAMETERS", + value=json.dumps({"id": "5"}), ) # Case 6: Started export with storage containing another that's running @@ -153,7 +155,9 @@ def test_migration(self): }, ) PluginStorage.objects.create( - plugin_config_id=self.plugin_configs[5].pk, key="EXPORT_PARAMETERS", value=json.dumps({"id": "7"}) + plugin_config_id=self.plugin_configs[5].pk, + key="EXPORT_PARAMETERS", + value=json.dumps({"id": "7"}), ) migration = importlib.import_module("posthog.migrations.0273_mark_inactive_exports_as_finished") diff --git a/posthog/test/test_migration_0287.py b/posthog/test/test_migration_0287.py index 0335be816919d..13740f7aab983 100644 --- a/posthog/test/test_migration_0287.py +++ b/posthog/test/test_migration_0287.py @@ -2,7 +2,6 @@ class CreatingSessionRecordingModelMigrationTestCase(NonAtomicTestMigrations): - migrate_from = "0286_index_insightcachingstate_lookup" migrate_to = "0287_add_session_recording_model" diff --git a/posthog/test/test_plugin.py b/posthog/test/test_plugin.py index 3522d29a7249d..8e249de2f7399 100644 --- a/posthog/test/test_plugin.py +++ b/posthog/test/test_plugin.py @@ -27,7 +27,8 @@ class TestPlugin(BaseTest): def test_default_config_list(self): some_plugin: Plugin = Plugin.objects.create( - organization=self.organization, config_schema=[{"key": "a", "default": 2}, {"key": "b"}] + organization=self.organization, + config_schema=[{"key": "a", "default": 2}, {"key": "b"}], ) default_config = some_plugin.get_default_config() @@ -36,7 +37,8 @@ def test_default_config_list(self): def test_default_config_dict(self): some_plugin: Plugin = Plugin.objects.create( - organization=self.organization, config_schema={"x": {"default": "z"}, "y": {"default": None}} + organization=self.organization, + config_schema={"x": {"default": "z"}, "y": {"default": None}}, ) default_config = some_plugin.get_default_config() @@ -50,9 +52,17 @@ def test_validate_plugin_job_payload(self): validate_plugin_job_payload(Plugin(public_jobs={}), "unknown_job", {}, is_staff=False) validate_plugin_job_payload(Plugin(public_jobs={"foo_job": {}}), "foo_job", {}, is_staff=False) - validate_plugin_job_payload(Plugin(public_jobs={"foo_job": {"payload": {}}}), "foo_job", {}, is_staff=False) validate_plugin_job_payload( - Plugin(public_jobs={"foo_job": {"payload": {"param": {"type": "number"}}}}), "foo_job", {}, is_staff=False + Plugin(public_jobs={"foo_job": {"payload": {}}}), + "foo_job", + {}, + is_staff=False, + ) + validate_plugin_job_payload( + Plugin(public_jobs={"foo_job": {"payload": {"param": {"type": "number"}}}}), + "foo_job", + {}, + is_staff=False, ) validate_plugin_job_payload( Plugin(public_jobs={"foo_job": {"payload": {"param": {"type": "number", "required": False}}}}), @@ -77,7 +87,17 @@ def test_validate_plugin_job_payload(self): ) validate_plugin_job_payload( Plugin( - public_jobs={"foo_job": {"payload": {"param": {"type": "number", "staff_only": True, "default": 5}}}} + public_jobs={ + "foo_job": { + "payload": { + "param": { + "type": "number", + "staff_only": True, + "default": 5, + } + } + } + } ), "foo_job", {"param": 5}, @@ -88,7 +108,15 @@ def test_validate_plugin_job_payload(self): validate_plugin_job_payload( Plugin( public_jobs={ - "foo_job": {"payload": {"param": {"type": "number", "staff_only": True, "default": 1}}} + "foo_job": { + "payload": { + "param": { + "type": "number", + "staff_only": True, + "default": 1, + } + } + } } ), "foo_job", @@ -120,7 +148,10 @@ def test_sync_from_plugin_archive_from_no_archive_fails(self): with self.assertRaises(exceptions.ValidationError) as cm: PluginSourceFile.objects.sync_from_plugin_archive(test_plugin) - self.assertEqual(cm.exception.message, f"There is no archive to extract code from in plugin Contoso") + self.assertEqual( + cm.exception.message, + f"There is no archive to extract code from in plugin Contoso", + ) @snapshot_postgres_queries def test_sync_from_plugin_archive_from_zip_without_plugin_js_fails(self): @@ -138,7 +169,9 @@ def test_sync_from_plugin_archive_from_zip_without_plugin_js_fails(self): @snapshot_postgres_queries def test_sync_from_plugin_archive_from_zip_with_explicit_index_js_works(self): test_plugin: Plugin = Plugin.objects.create( - organization=self.organization, name="Contoso", archive=base64.b64decode(HELLO_WORLD_PLUGIN_GITHUB_ZIP[1]) + organization=self.organization, + name="Contoso", + archive=base64.b64decode(HELLO_WORLD_PLUGIN_GITHUB_ZIP[1]), ) ( @@ -158,7 +191,9 @@ def test_sync_from_plugin_archive_from_zip_with_explicit_index_js_works(self): @snapshot_postgres_queries def test_sync_from_plugin_archive_from_tgz_with_explicit_index_js_works(self): test_plugin: Plugin = Plugin.objects.create( - organization=self.organization, name="Contoso", archive=base64.b64decode(HELLO_WORLD_PLUGIN_NPM_TGZ[1]) + organization=self.organization, + name="Contoso", + archive=base64.b64decode(HELLO_WORLD_PLUGIN_NPM_TGZ[1]), ) # First time - create @@ -273,7 +308,10 @@ def test_sync_from_plugin_archive_from_zip_without_any_code_fails(self): with self.assertRaises(exceptions.ValidationError) as cm: PluginSourceFile.objects.sync_from_plugin_archive(test_plugin) - self.assertEqual(cm.exception.message, f"Could not find main file index.js or index.ts in plugin Contoso") + self.assertEqual( + cm.exception.message, + f"Could not find main file index.js or index.ts in plugin Contoso", + ) @snapshot_postgres_queries def test_sync_from_plugin_archive_twice_from_zip_with_index_ts_replaced_by_frontend_tsx_works(self): diff --git a/posthog/test/test_plugin_log_entry.py b/posthog/test/test_plugin_log_entry.py index 917642bd992d9..29cc1c5e3dbb0 100644 --- a/posthog/test/test_plugin_log_entry.py +++ b/posthog/test/test_plugin_log_entry.py @@ -2,7 +2,11 @@ from posthog.client import sync_execute from posthog.models import Plugin, PluginConfig -from posthog.models.plugin import PluginLogEntrySource, PluginLogEntryType, fetch_plugin_log_entries +from posthog.models.plugin import ( + PluginLogEntrySource, + PluginLogEntryType, + fetch_plugin_log_entries, +) from posthog.models.utils import UUIDT from posthog.test.base import BaseTest @@ -126,7 +130,8 @@ def test_log_type_filter_works(self): ) results = fetch_plugin_log_entries( - plugin_config_id=some_plugin_config.pk, type_filter=[PluginLogEntryType.ERROR, PluginLogEntryType.DEBUG] + plugin_config_id=some_plugin_config.pk, + type_filter=[PluginLogEntryType.ERROR, PluginLogEntryType.DEBUG], ) self.assertEqual(len(results), 2) diff --git a/posthog/test/test_rate_limit.py b/posthog/test/test_rate_limit.py index 019e203a403a9..d3499a215a1da 100644 --- a/posthog/test/test_rate_limit.py +++ b/posthog/test/test_rate_limit.py @@ -28,7 +28,11 @@ def setUp(self): cache.clear() self.personal_api_key = generate_random_token_personal() - PersonalAPIKey.objects.create(label="X", user=self.user, secure_value=hash_key_value(self.personal_api_key)) + PersonalAPIKey.objects.create( + label="X", + user=self.user, + secure_value=hash_key_value(self.personal_api_key), + ) def tearDown(self): super().tearDown() @@ -42,18 +46,23 @@ def tearDown(self): def test_default_burst_rate_limit(self, rate_limit_enabled_mock, incr_mock): for _ in range(5): response = self.client.get( - f"/api/projects/{self.team.pk}/feature_flags", HTTP_AUTHORIZATION=f"Bearer {self.personal_api_key}" + f"/api/projects/{self.team.pk}/feature_flags", + HTTP_AUTHORIZATION=f"Bearer {self.personal_api_key}", ) self.assertEqual(response.status_code, status.HTTP_200_OK) response = self.client.get( - f"/api/projects/{self.team.pk}/feature_flags", HTTP_AUTHORIZATION=f"Bearer {self.personal_api_key}" + f"/api/projects/{self.team.pk}/feature_flags", + HTTP_AUTHORIZATION=f"Bearer {self.personal_api_key}", ) self.assertEqual(response.status_code, status.HTTP_429_TOO_MANY_REQUESTS) # mock_calls call object is a tuple of (function, args, kwargs) # so the incremented metric is args[0] - self.assertEqual(len([1 for name, args, kwargs in incr_mock.mock_calls if args[0] == "rate_limit_exceeded"]), 1) + self.assertEqual( + len([1 for name, args, kwargs in incr_mock.mock_calls if args[0] == "rate_limit_exceeded"]), + 1, + ) incr_mock.assert_any_call( "rate_limit_exceeded", tags={ @@ -72,7 +81,8 @@ def test_default_sustained_rate_limit(self, rate_limit_enabled_mock, incr_mock): for _ in range(5): with freeze_time(base_time): response = self.client.get( - f"/api/projects/{self.team.pk}/feature_flags", HTTP_AUTHORIZATION=f"Bearer {self.personal_api_key}" + f"/api/projects/{self.team.pk}/feature_flags", + HTTP_AUTHORIZATION=f"Bearer {self.personal_api_key}", ) base_time += timedelta(seconds=61) self.assertEqual(response.status_code, status.HTTP_200_OK) @@ -80,11 +90,13 @@ def test_default_sustained_rate_limit(self, rate_limit_enabled_mock, incr_mock): with freeze_time(base_time): for _ in range(2): response = self.client.get( - f"/api/projects/{self.team.pk}/feature_flags", HTTP_AUTHORIZATION=f"Bearer {self.personal_api_key}" + f"/api/projects/{self.team.pk}/feature_flags", + HTTP_AUTHORIZATION=f"Bearer {self.personal_api_key}", ) self.assertEqual(response.status_code, status.HTTP_429_TOO_MANY_REQUESTS) self.assertEqual( - len([1 for name, args, kwargs in incr_mock.mock_calls if args[0] == "rate_limit_exceeded"]), 2 + len([1 for name, args, kwargs in incr_mock.mock_calls if args[0] == "rate_limit_exceeded"]), + 2, ) incr_mock.assert_any_call( "rate_limit_exceeded", @@ -103,24 +115,30 @@ def test_clickhouse_burst_rate_limit(self, rate_limit_enabled_mock, incr_mock): # Does nothing on /feature_flags endpoint for _ in range(10): response = self.client.get( - f"/api/projects/{self.team.pk}/feature_flags", HTTP_AUTHORIZATION=f"Bearer {self.personal_api_key}" + f"/api/projects/{self.team.pk}/feature_flags", + HTTP_AUTHORIZATION=f"Bearer {self.personal_api_key}", ) self.assertEqual(response.status_code, status.HTTP_200_OK) assert call("rate_limit_exceeded", tags=ANY) not in incr_mock.mock_calls for _ in range(5): response = self.client.get( - f"/api/projects/{self.team.pk}/events", HTTP_AUTHORIZATION=f"Bearer {self.personal_api_key}" + f"/api/projects/{self.team.pk}/events", + HTTP_AUTHORIZATION=f"Bearer {self.personal_api_key}", ) self.assertEqual(response.status_code, status.HTTP_200_OK) # Does not actually block the request, but increments the counter response = self.client.get( - f"/api/projects/{self.team.pk}/events", HTTP_AUTHORIZATION=f"Bearer {self.personal_api_key}" + f"/api/projects/{self.team.pk}/events", + HTTP_AUTHORIZATION=f"Bearer {self.personal_api_key}", ) self.assertEqual(response.status_code, status.HTTP_429_TOO_MANY_REQUESTS) - self.assertEqual(len([1 for name, args, kwargs in incr_mock.mock_calls if args[0] == "rate_limit_exceeded"]), 1) + self.assertEqual( + len([1 for name, args, kwargs in incr_mock.mock_calls if args[0] == "rate_limit_exceeded"]), + 1, + ) incr_mock.assert_any_call( "rate_limit_exceeded", tags={ @@ -138,16 +156,21 @@ def test_rate_limits_are_based_on_the_team_not_user(self, rate_limit_enabled_moc self.client.logout() for _ in range(5): response = self.client.get( - f"/api/projects/{self.team.pk}/feature_flags", HTTP_AUTHORIZATION=f"Bearer {self.personal_api_key}" + f"/api/projects/{self.team.pk}/feature_flags", + HTTP_AUTHORIZATION=f"Bearer {self.personal_api_key}", ) self.assertEqual(response.status_code, status.HTTP_200_OK) # First user gets rate limited response = self.client.get( - f"/api/projects/{self.team.pk}/feature_flags", HTTP_AUTHORIZATION=f"Bearer {self.personal_api_key}" + f"/api/projects/{self.team.pk}/feature_flags", + HTTP_AUTHORIZATION=f"Bearer {self.personal_api_key}", ) self.assertEqual(response.status_code, status.HTTP_429_TOO_MANY_REQUESTS) - self.assertEqual(len([1 for name, args, kwargs in incr_mock.mock_calls if args[0] == "rate_limit_exceeded"]), 1) + self.assertEqual( + len([1 for name, args, kwargs in incr_mock.mock_calls if args[0] == "rate_limit_exceeded"]), + 1, + ) incr_mock.assert_any_call( "rate_limit_exceeded", tags={ @@ -168,11 +191,15 @@ def test_rate_limits_are_based_on_the_team_not_user(self, rate_limit_enabled_moc # Second user gets rate limited after a single request response = self.client.get( - f"/api/projects/{self.team.pk}/feature_flags", HTTP_AUTHORIZATION=f"Bearer {new_personal_api_key}" + f"/api/projects/{self.team.pk}/feature_flags", + HTTP_AUTHORIZATION=f"Bearer {new_personal_api_key}", ) self.assertEqual(response.status_code, status.HTTP_429_TOO_MANY_REQUESTS) - self.assertEqual(len([1 for name, args, kwargs in incr_mock.mock_calls if args[0] == "rate_limit_exceeded"]), 1) + self.assertEqual( + len([1 for name, args, kwargs in incr_mock.mock_calls if args[0] == "rate_limit_exceeded"]), + 1, + ) incr_mock.assert_any_call( "rate_limit_exceeded", tags={ @@ -193,18 +220,26 @@ def test_rate_limits_are_based_on_the_team_not_user(self, rate_limit_enabled_moc # Requests to the new team are not rate limited response = self.client.get( - f"/api/projects/{new_team.pk}/feature_flags", HTTP_AUTHORIZATION=f"Bearer {new_personal_api_key}" + f"/api/projects/{new_team.pk}/feature_flags", + HTTP_AUTHORIZATION=f"Bearer {new_personal_api_key}", ) self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertEqual(len([1 for name, args, kwargs in incr_mock.mock_calls if args[0] == "rate_limit_exceeded"]), 0) + self.assertEqual( + len([1 for name, args, kwargs in incr_mock.mock_calls if args[0] == "rate_limit_exceeded"]), + 0, + ) # until it hits their specific limit for _ in range(5): response = self.client.get( - f"/api/projects/{new_team.pk}/feature_flags", HTTP_AUTHORIZATION=f"Bearer {new_personal_api_key}" + f"/api/projects/{new_team.pk}/feature_flags", + HTTP_AUTHORIZATION=f"Bearer {new_personal_api_key}", ) self.assertEqual(response.status_code, status.HTTP_429_TOO_MANY_REQUESTS) - self.assertEqual(len([1 for name, args, kwargs in incr_mock.mock_calls if args[0] == "rate_limit_exceeded"]), 1) + self.assertEqual( + len([1 for name, args, kwargs in incr_mock.mock_calls if args[0] == "rate_limit_exceeded"]), + 1, + ) @patch("posthog.rate_limit.BurstRateThrottle.rate", new="5/minute") @patch("posthog.rate_limit.statsd.incr") @@ -219,11 +254,15 @@ def test_rate_limits_work_on_non_team_endpoints(self, rate_limit_enabled_mock, i self.assertEqual(response.status_code, status.HTTP_200_OK) response = self.client.get( - f"/api/organizations/{self.organization.pk}/plugins", HTTP_AUTHORIZATION=f"Bearer {self.personal_api_key}" + f"/api/organizations/{self.organization.pk}/plugins", + HTTP_AUTHORIZATION=f"Bearer {self.personal_api_key}", ) self.assertEqual(response.status_code, status.HTTP_429_TOO_MANY_REQUESTS) - self.assertEqual(len([1 for name, args, kwargs in incr_mock.mock_calls if args[0] == "rate_limit_exceeded"]), 1) + self.assertEqual( + len([1 for name, args, kwargs in incr_mock.mock_calls if args[0] == "rate_limit_exceeded"]), + 1, + ) incr_mock.assert_any_call( "rate_limit_exceeded", tags={ @@ -247,7 +286,10 @@ def test_does_not_rate_limit_non_personal_api_key_endpoints(self, rate_limit_ena ) self.assertEqual(response.status_code, status.HTTP_429_TOO_MANY_REQUESTS) # got rate limited with personal API key - self.assertEqual(len([1 for name, args, kwargs in incr_mock.mock_calls if args[0] == "rate_limit_exceeded"]), 1) + self.assertEqual( + len([1 for name, args, kwargs in incr_mock.mock_calls if args[0] == "rate_limit_exceeded"]), + 1, + ) incr_mock.reset_mock() # if not logged in, we 401 @@ -259,7 +301,10 @@ def test_does_not_rate_limit_non_personal_api_key_endpoints(self, rate_limit_ena # but no rate limits when logged in and not using personal API key response = self.client.get(f"/api/organizations/{self.organization.pk}/plugins") self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertEqual(len([1 for name, args, kwargs in incr_mock.mock_calls if args[0] == "rate_limit_exceeded"]), 0) + self.assertEqual( + len([1 for name, args, kwargs in incr_mock.mock_calls if args[0] == "rate_limit_exceeded"]), + 0, + ) @patch("posthog.rate_limit.BurstRateThrottle.rate", new="5/minute") @patch("posthog.rate_limit.statsd.incr") @@ -274,7 +319,10 @@ def test_rate_limits_unauthenticated_users(self, rate_limit_enabled_mock, incr_m response = self.client.post(f"/api/login") self.assertEqual(response.status_code, status.HTTP_429_TOO_MANY_REQUESTS) - self.assertEqual(len([1 for name, args, kwargs in incr_mock.mock_calls if args[0] == "rate_limit_exceeded"]), 1) + self.assertEqual( + len([1 for name, args, kwargs in incr_mock.mock_calls if args[0] == "rate_limit_exceeded"]), + 1, + ) incr_mock.assert_any_call( "rate_limit_exceeded", tags={ @@ -290,7 +338,10 @@ def test_rate_limits_unauthenticated_users(self, rate_limit_enabled_mock, incr_m @patch("posthog.rate_limit.is_rate_limit_enabled", return_value=True) @patch("posthog.kafka_client.client._KafkaProducer.produce") def test_does_not_rate_limit_capture_endpoints(self, kafka_mock, rate_limit_enabled_mock, incr_mock): - data = {"event": "$autocapture", "properties": {"distinct_id": 2, "token": self.team.api_token}} + data = { + "event": "$autocapture", + "properties": {"distinct_id": 2, "token": self.team.api_token}, + } for _ in range(6): response = self.client.get("/e/?data=%s" % quote(json.dumps(data)), HTTP_ORIGIN="https://localhost") self.assertEqual(response.status_code, status.HTTP_200_OK) @@ -331,7 +382,9 @@ def test_does_not_call_get_instance_setting_for_every_request(self, rate_limit_e with freeze_time("2022-04-01 12:34:45") as frozen_time: with override_instance_config("RATE_LIMITING_ALLOW_LIST_TEAMS", f"{self.team.pk}"): with patch.object( - rate_limit, "get_instance_setting", wraps=models.instance_setting.get_instance_setting + rate_limit, + "get_instance_setting", + wraps=models.instance_setting.get_instance_setting, ) as wrapped_get_instance_setting: for _ in range(10): self.client.get( diff --git a/posthog/test/test_renderers.py b/posthog/test/test_renderers.py index 07eaedd62f43d..a68b24afa97f1 100644 --- a/posthog/test/test_renderers.py +++ b/posthog/test/test_renderers.py @@ -14,7 +14,14 @@ def test_cleans_dict_with_nan_and_inf_scalars(self): self.assertEqual(top_level_markers, (False, False)) self.assertDictEqual( - data, {"control": 1.0, "test_1": None, "test_1::nan": True, "test_2": None, "test_2::inf": True} + data, + { + "control": 1.0, + "test_1": None, + "test_1::nan": True, + "test_2": None, + "test_2::inf": True, + }, ) def test_cleans_dict_with_nan_and_inf_list(self): @@ -26,13 +33,24 @@ def test_cleans_dict_with_nan_and_inf_list(self): self.assertEqual(top_level_markers, (False, False)) self.assertDictEqual( - {"control": 1.0, "test": [None, 1.0, None], "test::nan": {2: True}, "test::inf": {0: True}}, data + { + "control": 1.0, + "test": [None, 1.0, None], + "test::nan": {2: True}, + "test::inf": {0: True}, + }, + data, ) def test_cleans_dict_with_nan_and_inf_nested_list(self): data = { "control": 1.0, - "test": [float("inf"), [float("inf"), float("nan"), 1.0], float("nan"), 5.0], + "test": [ + float("inf"), + [float("inf"), float("nan"), 1.0], + float("nan"), + 5.0, + ], } top_level_markers = clean_data_for_json(data) @@ -56,6 +74,9 @@ def test_cleans_dict_with_nan_nested_dict(self): self.assertEqual(top_level_markers, (False, False)) self.assertDictEqual( - {"control": 1.0, "test": [{"yup": True, "meh": [], "nope": None, "nope::nan": True}]}, + { + "control": 1.0, + "test": [{"yup": True, "meh": [], "nope": None, "nope::nan": True}], + }, data, ) diff --git a/posthog/test/test_team.py b/posthog/test/test_team.py index b8f6dc5cff7b8..ac95e5c8cc7e7 100644 --- a/posthog/test/test_team.py +++ b/posthog/test/test_team.py @@ -3,7 +3,14 @@ from django.core.cache import cache from django.test import TestCase -from posthog.models import Dashboard, DashboardTile, Organization, PluginConfig, Team, User +from posthog.models import ( + Dashboard, + DashboardTile, + Organization, + PluginConfig, + Team, + User, +) from posthog.models.instance_setting import override_instance_config from posthog.models.team import get_team_in_cache, util from posthog.plugins.test.mock import mocked_plugin_requests_get @@ -70,7 +77,12 @@ def test_create_team_with_test_account_filters(self): self.assertEqual( team.test_account_filters, [ - {"key": "email", "value": "@posthog.com", "operator": "not_icontains", "type": "person"}, + { + "key": "email", + "value": "@posthog.com", + "operator": "not_icontains", + "type": "person", + }, { "key": "$host", "operator": "not_regex", @@ -109,11 +121,15 @@ def test_preinstalled_are_autoenabled(self, mock_get): with self.is_cloud(False): with self.settings(PLUGINS_PREINSTALLED_URLS=["https://github.com/PostHog/helloworldplugin/"]): _, _, new_team = Organization.objects.bootstrap( - self.user, plugins_access_level=Organization.PluginsAccessLevel.INSTALL + self.user, + plugins_access_level=Organization.PluginsAccessLevel.INSTALL, ) self.assertEqual(PluginConfig.objects.filter(team=new_team, enabled=True).count(), 1) - self.assertEqual(PluginConfig.objects.filter(team=new_team, enabled=True).get().plugin.name, "helloworldplugin") + self.assertEqual( + PluginConfig.objects.filter(team=new_team, enabled=True).get().plugin.name, + "helloworldplugin", + ) self.assertEqual(mock_get.call_count, 2) @mock.patch("posthoganalytics.feature_enabled", return_value=True) @@ -139,7 +155,6 @@ def test_team_on_cloud_uses_feature_flag_to_determine_person_on_events(self, moc @mock.patch("posthoganalytics.feature_enabled", return_value=False) def test_team_on_self_hosted_uses_instance_setting_to_determine_person_on_events(self, mock_feature_enabled): - with self.is_cloud(False): with override_instance_config("PERSON_ON_EVENTS_V2_ENABLED", True): team = Team.objects.create_with_data(organization=self.organization) diff --git a/posthog/test/test_urls.py b/posthog/test/test_urls.py index 9f9581a920853..23d02f30f0584 100644 --- a/posthog/test/test_urls.py +++ b/posthog/test/test_urls.py @@ -58,37 +58,43 @@ def test_authorize_and_redirect_domain(self): self.team.save() response = self.client.get( - "/authorize_and_redirect/?redirect=https://not-permitted.com", HTTP_REFERER="https://not-permitted.com" + "/authorize_and_redirect/?redirect=https://not-permitted.com", + HTTP_REFERER="https://not-permitted.com", ) self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) self.assertTrue("Can only redirect to a permitted domain." in str(response.content)) response = self.client.get( - "/authorize_and_redirect/?redirect=https://domain.com", HTTP_REFERER="https://not.com" + "/authorize_and_redirect/?redirect=https://domain.com", + HTTP_REFERER="https://not.com", ) self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) self.assertTrue("Can only redirect to the same domain as the referer: not.com" in str(response.content)) response = self.client.get( - "/authorize_and_redirect/?redirect=http://domain.com", HTTP_REFERER="https://domain.com" + "/authorize_and_redirect/?redirect=http://domain.com", + HTTP_REFERER="https://domain.com", ) self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) self.assertTrue("Can only redirect to the same scheme as the referer: https" in str(response.content)) response = self.client.get( - "/authorize_and_redirect/?redirect=https://domain.com:555", HTTP_REFERER="https://domain.com:443" + "/authorize_and_redirect/?redirect=https://domain.com:555", + HTTP_REFERER="https://domain.com:443", ) self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) self.assertTrue("Can only redirect to the same port as the referer: 443" in str(response.content)) response = self.client.get( - "/authorize_and_redirect/?redirect=https://domain.com:555", HTTP_REFERER="https://domain.com/no-port" + "/authorize_and_redirect/?redirect=https://domain.com:555", + HTTP_REFERER="https://domain.com/no-port", ) self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) self.assertTrue("Can only redirect to the same port as the referer: no port in URL" in str(response.content)) response = self.client.get( - "/authorize_and_redirect/?redirect=https://domain.com/sdf", HTTP_REFERER="https://domain.com/asd" + "/authorize_and_redirect/?redirect=https://domain.com/sdf", + HTTP_REFERER="https://domain.com/asd", ) self.assertEqual(response.status_code, status.HTTP_200_OK) # TODO: build frontend before backend tests, or find a way to mock the template diff --git a/posthog/test/test_user_permissions.py b/posthog/test/test_user_permissions.py index ea80fb9c77677..da9faef7330ad 100644 --- a/posthog/test/test_user_permissions.py +++ b/posthog/test/test_user_permissions.py @@ -70,7 +70,9 @@ def test_team_effective_membership_level_with_explicit_membership_returns_explic self.organization_membership.save() ExplicitTeamMembership.objects.create( - team=self.team, parent_membership=self.organization_membership, level=ExplicitTeamMembership.Level.ADMIN + team=self.team, + parent_membership=self.organization_membership, + level=ExplicitTeamMembership.Level.ADMIN, ) with self.assertNumQueries(2): @@ -90,7 +92,9 @@ def test_team_ids_visible_for_user_explicit_permission(self): self.team.save() ExplicitTeamMembership.objects.create( - team=self.team, parent_membership=self.organization_membership, level=ExplicitTeamMembership.Level.ADMIN + team=self.team, + parent_membership=self.organization_membership, + level=ExplicitTeamMembership.Level.ADMIN, ) assert self.permissions().team_ids_visible_for_user == [self.team.pk] @@ -165,7 +169,9 @@ def test_dashboard_effective_privilege_level_priviledged(self): self.dashboard.save() DashboardPrivilege.objects.create( - user=self.user, dashboard=self.dashboard, level=Dashboard.PrivilegeLevel.CAN_EDIT + user=self.user, + dashboard=self.dashboard, + level=Dashboard.PrivilegeLevel.CAN_EDIT, ) assert self.dashboard_permissions().effective_privilege_level == Dashboard.PrivilegeLevel.CAN_EDIT @@ -203,7 +209,9 @@ def test_dashboard_can_edit_priviledged(self): self.dashboard.save() DashboardPrivilege.objects.create( - user=self.user, dashboard=self.dashboard, level=Dashboard.PrivilegeLevel.CAN_EDIT + user=self.user, + dashboard=self.dashboard, + level=Dashboard.PrivilegeLevel.CAN_EDIT, ) assert self.dashboard_permissions().can_edit @@ -216,7 +224,8 @@ def setUp(self): self.organization.save() self.dashboard1 = Dashboard.objects.create( - team=self.team, restriction_level=Dashboard.RestrictionLevel.ONLY_COLLABORATORS_CAN_EDIT + team=self.team, + restriction_level=Dashboard.RestrictionLevel.ONLY_COLLABORATORS_CAN_EDIT, ) self.dashboard2 = Dashboard.objects.create(team=self.team) self.insight = Insight.objects.create(team=self.team) @@ -287,7 +296,8 @@ def test_dashboard_efficiency(self): self.organization.save() dashboard = Dashboard.objects.create( - team=self.team, restriction_level=Dashboard.RestrictionLevel.ONLY_COLLABORATORS_CAN_EDIT + team=self.team, + restriction_level=Dashboard.RestrictionLevel.ONLY_COLLABORATORS_CAN_EDIT, ) insights, tiles = [], [] for _ in range(10): diff --git a/posthog/test/test_utils.py b/posthog/test/test_utils.py index 444355857b40b..f6c5d4079505c 100644 --- a/posthog/test/test_utils.py +++ b/posthog/test/test_utils.py @@ -35,12 +35,36 @@ def test_format_absolute_url(self) -> None: absolute_urls_test_cases = [ (None, "https://my-amazing.site", "https://my-amazing.site"), (None, "https://my-amazing.site/", "https://my-amazing.site/"), - ("api/path", "https://my-amazing.site/", "https://my-amazing.site/api/path"), - ("/api/path", "https://my-amazing.site/", "https://my-amazing.site/api/path"), - ("api/path", "https://my-amazing.site/base_url/", "https://my-amazing.site/base_url/api/path"), - ("/api/path", "https://my-amazing.site/base_url", "https://my-amazing.site/base_url/api/path"), - (regression_11204, "https://app.posthog.com", f"https://app.posthog.com/{regression_11204}"), - ("https://app.posthog.com", "https://app.posthog.com", "https://app.posthog.com"), + ( + "api/path", + "https://my-amazing.site/", + "https://my-amazing.site/api/path", + ), + ( + "/api/path", + "https://my-amazing.site/", + "https://my-amazing.site/api/path", + ), + ( + "api/path", + "https://my-amazing.site/base_url/", + "https://my-amazing.site/base_url/api/path", + ), + ( + "/api/path", + "https://my-amazing.site/base_url", + "https://my-amazing.site/base_url/api/path", + ), + ( + regression_11204, + "https://app.posthog.com", + f"https://app.posthog.com/{regression_11204}", + ), + ( + "https://app.posthog.com", + "https://app.posthog.com", + "https://app.posthog.com", + ), ( "https://app.posthog.com/some/path?=something", "https://app.posthog.com", @@ -70,17 +94,17 @@ def test_format_absolute_url(self) -> None: def test_absolute_uri_can_not_escape_out_host(self) -> None: with self.settings(SITE_URL="https://app.posthog.com"): with pytest.raises(PotentialSecurityProblemException): - absolute_uri("https://an.external.domain.com/something-outside-posthog"), + (absolute_uri("https://an.external.domain.com/something-outside-posthog"),) def test_absolute_uri_can_not_escape_out_host_on_different_scheme(self) -> None: with self.settings(SITE_URL="https://app.posthog.com"): with pytest.raises(PotentialSecurityProblemException): - absolute_uri("ftp://an.external.domain.com/something-outside-posthog"), + (absolute_uri("ftp://an.external.domain.com/something-outside-posthog"),) def test_absolute_uri_can_not_escape_out_host_when_site_url_is_the_empty_string(self) -> None: with self.settings(SITE_URL=""): with pytest.raises(PotentialSecurityProblemException): - absolute_uri("https://an.external.domain.com/something-outside-posthog"), + (absolute_uri("https://an.external.domain.com/something-outside-posthog"),) class TestFormatUrls(TestCase): @@ -111,12 +135,18 @@ def test_format_query_params_absolute_url(self) -> None: ] for params, expected in test_to_expected: - self.assertEqual(expected, format_query_params_absolute_url(Request(request=build_req), *params)) + self.assertEqual( + expected, + format_query_params_absolute_url(Request(request=build_req), *params), + ) def test_format_query_params_absolute_url_with_https(self) -> None: with self.settings(SECURE_PROXY_SSL_HEADER=("HTTP_X_FORWARDED_PROTO", "https")): build_req = HttpRequest() - build_req.META = {"HTTP_HOST": "www.testserver", "HTTP_X_FORWARDED_PROTO": "https"} + build_req.META = { + "HTTP_HOST": "www.testserver", + "HTTP_X_FORWARDED_PROTO": "https", + } request: Request = Request(build_req) self.assertEqual("https://www.testserver", format_query_params_absolute_url(request)) @@ -155,41 +185,98 @@ def test_fetching_env_var_parsed_as_float_from_nonsense_input(self, mock_env): class TestRelativeDateParse(TestCase): @freeze_time("2020-01-31T12:22:23") def test_hour(self): - self.assertEqual(relative_date_parse("-24h", ZoneInfo("UTC")).isoformat(), "2020-01-30T12:22:23+00:00") - self.assertEqual(relative_date_parse("-48h", ZoneInfo("UTC")).isoformat(), "2020-01-29T12:22:23+00:00") + self.assertEqual( + relative_date_parse("-24h", ZoneInfo("UTC")).isoformat(), + "2020-01-30T12:22:23+00:00", + ) + self.assertEqual( + relative_date_parse("-48h", ZoneInfo("UTC")).isoformat(), + "2020-01-29T12:22:23+00:00", + ) @freeze_time("2020-01-31") def test_day(self): - self.assertEqual(relative_date_parse("dStart", ZoneInfo("UTC")).strftime("%Y-%m-%d"), "2020-01-31") - self.assertEqual(relative_date_parse("-1d", ZoneInfo("UTC")).strftime("%Y-%m-%d"), "2020-01-30") - self.assertEqual(relative_date_parse("-2d", ZoneInfo("UTC")).strftime("%Y-%m-%d"), "2020-01-29") + self.assertEqual( + relative_date_parse("dStart", ZoneInfo("UTC")).strftime("%Y-%m-%d"), + "2020-01-31", + ) + self.assertEqual( + relative_date_parse("-1d", ZoneInfo("UTC")).strftime("%Y-%m-%d"), + "2020-01-30", + ) + self.assertEqual( + relative_date_parse("-2d", ZoneInfo("UTC")).strftime("%Y-%m-%d"), + "2020-01-29", + ) - self.assertEqual(relative_date_parse("-1dStart", ZoneInfo("UTC")).isoformat(), "2020-01-30T00:00:00+00:00") - self.assertEqual(relative_date_parse("-1dEnd", ZoneInfo("UTC")).isoformat(), "2020-01-30T23:59:59.999999+00:00") + self.assertEqual( + relative_date_parse("-1dStart", ZoneInfo("UTC")).isoformat(), + "2020-01-30T00:00:00+00:00", + ) + self.assertEqual( + relative_date_parse("-1dEnd", ZoneInfo("UTC")).isoformat(), + "2020-01-30T23:59:59.999999+00:00", + ) @freeze_time("2020-01-31") def test_month(self): - self.assertEqual(relative_date_parse("-1m", ZoneInfo("UTC")).strftime("%Y-%m-%d"), "2019-12-31") - self.assertEqual(relative_date_parse("-2m", ZoneInfo("UTC")).strftime("%Y-%m-%d"), "2019-11-30") + self.assertEqual( + relative_date_parse("-1m", ZoneInfo("UTC")).strftime("%Y-%m-%d"), + "2019-12-31", + ) + self.assertEqual( + relative_date_parse("-2m", ZoneInfo("UTC")).strftime("%Y-%m-%d"), + "2019-11-30", + ) - self.assertEqual(relative_date_parse("mStart", ZoneInfo("UTC")).strftime("%Y-%m-%d"), "2020-01-01") - self.assertEqual(relative_date_parse("-1mStart", ZoneInfo("UTC")).strftime("%Y-%m-%d"), "2019-12-01") - self.assertEqual(relative_date_parse("-2mStart", ZoneInfo("UTC")).strftime("%Y-%m-%d"), "2019-11-01") + self.assertEqual( + relative_date_parse("mStart", ZoneInfo("UTC")).strftime("%Y-%m-%d"), + "2020-01-01", + ) + self.assertEqual( + relative_date_parse("-1mStart", ZoneInfo("UTC")).strftime("%Y-%m-%d"), + "2019-12-01", + ) + self.assertEqual( + relative_date_parse("-2mStart", ZoneInfo("UTC")).strftime("%Y-%m-%d"), + "2019-11-01", + ) - self.assertEqual(relative_date_parse("-1mEnd", ZoneInfo("UTC")).strftime("%Y-%m-%d"), "2019-12-31") - self.assertEqual(relative_date_parse("-2mEnd", ZoneInfo("UTC")).strftime("%Y-%m-%d"), "2019-11-30") + self.assertEqual( + relative_date_parse("-1mEnd", ZoneInfo("UTC")).strftime("%Y-%m-%d"), + "2019-12-31", + ) + self.assertEqual( + relative_date_parse("-2mEnd", ZoneInfo("UTC")).strftime("%Y-%m-%d"), + "2019-11-30", + ) @freeze_time("2020-01-31") def test_year(self): - self.assertEqual(relative_date_parse("-1y", ZoneInfo("UTC")).strftime("%Y-%m-%d"), "2019-01-31") - self.assertEqual(relative_date_parse("-2y", ZoneInfo("UTC")).strftime("%Y-%m-%d"), "2018-01-31") + self.assertEqual( + relative_date_parse("-1y", ZoneInfo("UTC")).strftime("%Y-%m-%d"), + "2019-01-31", + ) + self.assertEqual( + relative_date_parse("-2y", ZoneInfo("UTC")).strftime("%Y-%m-%d"), + "2018-01-31", + ) - self.assertEqual(relative_date_parse("yStart", ZoneInfo("UTC")).strftime("%Y-%m-%d"), "2020-01-01") - self.assertEqual(relative_date_parse("-1yStart", ZoneInfo("UTC")).strftime("%Y-%m-%d"), "2019-01-01") + self.assertEqual( + relative_date_parse("yStart", ZoneInfo("UTC")).strftime("%Y-%m-%d"), + "2020-01-01", + ) + self.assertEqual( + relative_date_parse("-1yStart", ZoneInfo("UTC")).strftime("%Y-%m-%d"), + "2019-01-01", + ) @freeze_time("2020-01-31") def test_normal_date(self): - self.assertEqual(relative_date_parse("2019-12-31", ZoneInfo("UTC")).strftime("%Y-%m-%d"), "2019-12-31") + self.assertEqual( + relative_date_parse("2019-12-31", ZoneInfo("UTC")).strftime("%Y-%m-%d"), + "2019-12-31", + ) class TestDefaultEventName(BaseTest): @@ -229,7 +316,11 @@ def test_pushes_debug_information_into_sentry_scope_from_origin_header(self, pat patched_scope.assert_called_once() mock_set_tag.assert_has_calls( - [call("origin", origin), call("referer", referer), call("library.version", "1.20.0")] + [ + call("origin", origin), + call("referer", referer), + call("library.version", "1.20.0"), + ] ) @patch("posthog.utils.configure_scope") @@ -246,7 +337,11 @@ def test_pushes_debug_information_into_sentry_scope_when_origin_header_not_prese patched_scope.assert_called_once() mock_set_tag.assert_has_calls( - [call("origin", origin), call("referer", referer), call("library.version", "1.20.0")] + [ + call("origin", origin), + call("referer", referer), + call("library.version", "1.20.0"), + ] ) @patch("posthog.utils.configure_scope") @@ -261,7 +356,11 @@ def test_still_tags_sentry_scope_even_when_debug_signal_is_not_available(self, p patched_scope.assert_called_once() mock_set_tag.assert_has_calls( - [call("origin", "unknown"), call("referer", "unknown"), call("library.version", "unknown")] + [ + call("origin", "unknown"), + call("referer", "unknown"), + call("library.version", "unknown"), + ] ) def test_fails_to_JSON_parse_the_literal_string_undefined_when_not_compressed(self): @@ -277,7 +376,10 @@ def test_fails_to_JSON_parse_the_literal_string_undefined_when_not_compressed(se with self.assertRaises(RequestParsingError) as ctx: load_data_from_request(post_request) - self.assertEqual("Invalid JSON: Expecting value: line 1 column 1 (char 0)", str(ctx.exception)) + self.assertEqual( + "Invalid JSON: Expecting value: line 1 column 1 (char 0)", + str(ctx.exception), + ) def test_raises_specific_error_for_the_literal_string_undefined_when_compressed(self): rf = RequestFactory() @@ -357,4 +459,10 @@ def test_flatten_lots_of_depth(self): assert list(flatten([1, [2, 3], [[4], [5, [6, 7]]]])) == [1, 2, 3, 4, 5, 6, 7] def test_flatten_single_depth(self): - assert list(flatten([1, [2, 3], [[4], [5, [6, 7]]]], max_depth=1)) == [1, 2, 3, [4], [5, [6, 7]]] + assert list(flatten([1, [2, 3], [[4], [5, [6, 7]]]], max_depth=1)) == [ + 1, + 2, + 3, + [4], + [5, [6, 7]], + ] diff --git a/posthog/test/test_version_requirement.py b/posthog/test/test_version_requirement.py index b0ab147d6bc6d..9798dc51a8bd4 100644 --- a/posthog/test/test_version_requirement.py +++ b/posthog/test/test_version_requirement.py @@ -34,7 +34,6 @@ def test_accepted_services(self): ) def test_service_versions(self): - version1 = version_requirement.version_string_to_semver("14") self.assertEqual(version1.major, 14) self.assertEqual(version1.minor, 0) @@ -70,7 +69,10 @@ def test_service_versions(self): self.assertEqual(version6.minor, 13) self.assertEqual(version6.patch, 0) - @patch("posthog.version_requirement.ServiceVersionRequirement.get_service_version", lambda x: Version("12.1.2")) + @patch( + "posthog.version_requirement.ServiceVersionRequirement.get_service_version", + lambda x: Version("12.1.2"), + ) def test_ranges(self): v1 = ServiceVersionRequirement(service="postgresql", supported_version="==14.0.0") in_range, service_version = v1.is_service_in_accepted_version() diff --git a/posthog/types.py b/posthog/types.py index f768cf8833a85..b13d1a08a531b 100644 --- a/posthog/types.py +++ b/posthog/types.py @@ -4,8 +4,22 @@ from posthog.models.filters.path_filter import PathFilter from posthog.models.filters.retention_filter import RetentionFilter from posthog.models.filters.stickiness_filter import StickinessFilter -from posthog.schema import TrendsQuery, FunnelsQuery, RetentionQuery, PathsQuery, StickinessQuery, LifecycleQuery +from posthog.schema import ( + TrendsQuery, + FunnelsQuery, + RetentionQuery, + PathsQuery, + StickinessQuery, + LifecycleQuery, +) FilterType = Union[Filter, PathFilter, RetentionFilter, StickinessFilter] -InsightQueryNode = Union[TrendsQuery, FunnelsQuery, RetentionQuery, PathsQuery, StickinessQuery, LifecycleQuery] +InsightQueryNode = Union[ + TrendsQuery, + FunnelsQuery, + RetentionQuery, + PathsQuery, + StickinessQuery, + LifecycleQuery, +] diff --git a/posthog/urls.py b/posthog/urls.py index f460a15859db9..c271406c73469 100644 --- a/posthog/urls.py +++ b/posthog/urls.py @@ -5,9 +5,17 @@ from django.http import HttpRequest, HttpResponse, HttpResponseServerError from django.template import loader from django.urls import URLPattern, include, path, re_path -from django.views.decorators.csrf import csrf_exempt, ensure_csrf_cookie, requires_csrf_token +from django.views.decorators.csrf import ( + csrf_exempt, + ensure_csrf_cookie, + requires_csrf_token, +) from django_prometheus.exports import ExportToDjangoView -from drf_spectacular.views import SpectacularAPIView, SpectacularRedocView, SpectacularSwaggerView +from drf_spectacular.views import ( + SpectacularAPIView, + SpectacularRedocView, + SpectacularSwaggerView, +) from revproxy.views import ProxyView from sentry_sdk import last_event_id from two_factor.urls import urlpatterns as tf_urls @@ -36,7 +44,14 @@ from posthog.demo.legacy import demo_route from posthog.models import User from .utils import render_template -from .views import health, login_required, preflight_check, robots_txt, security_txt, stats +from .views import ( + health, + login_required, + preflight_check, + robots_txt, + security_txt, + stats, +) from .year_in_posthog import year_in_posthog ee_urlpatterns: List[Any] = [] @@ -86,20 +101,30 @@ def authorize_and_redirect(request: HttpRequest) -> HttpResponse: return HttpResponse(f"Can only redirect to a permitted domain.", status=403) if referer_url.hostname != redirect_url.hostname: - return HttpResponse(f"Can only redirect to the same domain as the referer: {referer_url.hostname}", status=403) + return HttpResponse( + f"Can only redirect to the same domain as the referer: {referer_url.hostname}", + status=403, + ) if referer_url.scheme != redirect_url.scheme: - return HttpResponse(f"Can only redirect to the same scheme as the referer: {referer_url.scheme}", status=403) + return HttpResponse( + f"Can only redirect to the same scheme as the referer: {referer_url.scheme}", + status=403, + ) if referer_url.port != redirect_url.port: return HttpResponse( - f"Can only redirect to the same port as the referer: {referer_url.port or 'no port in URL'}", status=403 + f"Can only redirect to the same port as the referer: {referer_url.port or 'no port in URL'}", + status=403, ) return render_template( "authorize_and_redirect.html", request=request, - context={"domain": redirect_url.hostname, "redirect_url": request.GET["redirect"]}, + context={ + "domain": redirect_url.hostname, + "redirect_url": request.GET["redirect"], + }, ) @@ -112,8 +137,16 @@ def opt_slash_path(route: str, view: Callable, name: Optional[str] = None) -> UR urlpatterns = [ path("api/schema/", SpectacularAPIView.as_view(), name="schema"), # Optional UI: - path("api/schema/swagger-ui/", SpectacularSwaggerView.as_view(url_name="schema"), name="swagger-ui"), - path("api/schema/redoc/", SpectacularRedocView.as_view(url_name="schema"), name="redoc"), + path( + "api/schema/swagger-ui/", + SpectacularSwaggerView.as_view(url_name="schema"), + name="swagger-ui", + ), + path( + "api/schema/redoc/", + SpectacularRedocView.as_view(url_name="schema"), + name="redoc", + ), # Health check probe endpoints for K8s # NOTE: We have _health, livez, and _readyz. _health is deprecated and # is only included for compatability with old installations. For new @@ -141,11 +174,23 @@ def opt_slash_path(route: str, view: Callable, name: Optional[str] = None) -> UR ), re_path(r"^api.+", api_not_found), path("authorize_and_redirect/", login_required(authorize_and_redirect)), - path("shared_dashboard/", sharing.SharingViewerPageViewSet.as_view({"get": "retrieve"})), - path("shared/", sharing.SharingViewerPageViewSet.as_view({"get": "retrieve"})), - path("embedded/", sharing.SharingViewerPageViewSet.as_view({"get": "retrieve"})), + path( + "shared_dashboard/", + sharing.SharingViewerPageViewSet.as_view({"get": "retrieve"}), + ), + path( + "shared/", + sharing.SharingViewerPageViewSet.as_view({"get": "retrieve"}), + ), + path( + "embedded/", + sharing.SharingViewerPageViewSet.as_view({"get": "retrieve"}), + ), path("exporter", sharing.SharingViewerPageViewSet.as_view({"get": "retrieve"})), - path("exporter/", sharing.SharingViewerPageViewSet.as_view({"get": "retrieve"})), + path( + "exporter/", + sharing.SharingViewerPageViewSet.as_view({"get": "retrieve"}), + ), path("site_app////", site_app.get_site_app), re_path(r"^demo.*", login_required(demo_route)), # ingestion @@ -182,7 +227,6 @@ def opt_slash_path(route: str, view: Callable, name: Optional[str] = None) -> UR if settings.TEST: - # Used in posthog-js e2e tests @csrf_exempt def delete_events(request): diff --git a/posthog/user_permissions.py b/posthog/user_permissions.py index 3b31ca82e8d84..4d1a13fa76815 100644 --- a/posthog/user_permissions.py +++ b/posthog/user_permissions.py @@ -3,7 +3,15 @@ from uuid import UUID from posthog.constants import AvailableFeature -from posthog.models import Dashboard, DashboardTile, Insight, Organization, OrganizationMembership, Team, User +from posthog.models import ( + Dashboard, + DashboardTile, + Insight, + Organization, + OrganizationMembership, + Team, + User, +) class UserPermissions: @@ -147,7 +155,9 @@ def effective_membership_level(self) -> Optional["OrganizationMembership.Level"] return self.effective_membership_level_for_parent_membership(organization, membership) def effective_membership_level_for_parent_membership( - self, organization: Optional[Organization], organization_membership: Optional[OrganizationMembership] + self, + organization: Optional[Organization], + organization_membership: Optional[OrganizationMembership], ) -> Optional["OrganizationMembership.Level"]: if organization is None or organization_membership is None: return None diff --git a/posthog/utils.py b/posthog/utils.py index 6105a253f9fa5..286e4ff4ce6a2 100644 --- a/posthog/utils.py +++ b/posthog/utils.py @@ -168,7 +168,11 @@ def get_current_day(at: Optional[datetime.datetime] = None) -> Tuple[datetime.da def relative_date_parse_with_delta_mapping( - input: str, timezone_info: ZoneInfo, *, always_truncate: bool = False, now: Optional[datetime.datetime] = None + input: str, + timezone_info: ZoneInfo, + *, + always_truncate: bool = False, + now: Optional[datetime.datetime] = None, ) -> Tuple[datetime.datetime, Optional[Dict[str, int]]]: """Returns the parsed datetime, along with the period mapping - if the input was a relative datetime string.""" try: @@ -244,7 +248,11 @@ def relative_date_parse_with_delta_mapping( def relative_date_parse( - input: str, timezone_info: ZoneInfo, *, always_truncate: bool = False, now: Optional[datetime.datetime] = None + input: str, + timezone_info: ZoneInfo, + *, + always_truncate: bool = False, + now: Optional[datetime.datetime] = None, ) -> datetime.datetime: return relative_date_parse_with_delta_mapping(input, timezone_info, always_truncate=always_truncate, now=now)[0] @@ -290,7 +298,11 @@ def get_js_url(request: HttpRequest) -> str: def render_template( - template_name: str, request: HttpRequest, context: Dict = {}, *, team_for_public_context: Optional["Team"] = None + template_name: str, + request: HttpRequest, + context: Dict = {}, + *, + team_for_public_context: Optional["Team"] = None, ) -> HttpResponse: """Render Django template. @@ -369,13 +381,17 @@ def render_template( user = cast("User", request.user) user_permissions = UserPermissions(user=user, team=user.team) user_serialized = UserSerializer( - request.user, context={"request": request, "user_permissions": user_permissions}, many=False + request.user, + context={"request": request, "user_permissions": user_permissions}, + many=False, ) posthog_app_context["current_user"] = user_serialized.data posthog_distinct_id = user_serialized.data.get("distinct_id") if user.team: team_serialized = TeamSerializer( - user.team, context={"request": request, "user_permissions": user_permissions}, many=False + user.team, + context={"request": request, "user_permissions": user_permissions}, + many=False, ) posthog_app_context["current_team"] = team_serialized.data posthog_app_context["frontend_apps"] = get_frontend_apps(user.team.pk) @@ -451,8 +467,18 @@ def get_frontend_apps(team_id: int) -> Dict[int, Dict[str, Any]]: plugin_configs = ( Plugin.objects.filter(pluginconfig__team_id=team_id, pluginconfig__enabled=True) - .filter(pluginsourcefile__status=PluginSourceFile.Status.TRANSPILED, pluginsourcefile__filename="frontend.tsx") - .values("pluginconfig__id", "pluginconfig__config", "config_schema", "id", "plugin_type", "name") + .filter( + pluginsourcefile__status=PluginSourceFile.Status.TRANSPILED, + pluginsourcefile__filename="frontend.tsx", + ) + .values( + "pluginconfig__id", + "pluginconfig__config", + "config_schema", + "id", + "plugin_type", + "name", + ) .all() ) @@ -653,7 +679,10 @@ def load_data_from_request(request): with configure_scope() as scope: if isinstance(data, dict): scope.set_context("data", data) - scope.set_tag("origin", request.headers.get("origin", request.headers.get("remote_host", "unknown"))) + scope.set_tag( + "origin", + request.headers.get("origin", request.headers.get("remote_host", "unknown")), + ) scope.set_tag("referer", request.headers.get("referer", "unknown")) # since version 1.20.0 posthog-js adds its version to the `ver` query parameter as a debug signal here scope.set_tag("library.version", request.GET.get("ver", "unknown")) @@ -882,7 +911,9 @@ def flatten(i: Union[List, Tuple], max_depth=10) -> Generator: def get_daterange( - start_date: Optional[datetime.datetime], end_date: Optional[datetime.datetime], frequency: str + start_date: Optional[datetime.datetime], + end_date: Optional[datetime.datetime], + frequency: str, ) -> List[Any]: """ Returns list of a fixed frequency Datetime objects between given bounds. @@ -1183,7 +1214,23 @@ def get_week_start_for_country_code(country_code: str) -> int: "ZW", ]: return 0 # Sunday - if country_code in ["AE", "AF", "BH", "DJ", "DZ", "EG", "IQ", "IR", "JO", "KW", "LY", "OM", "QA", "SD", "SY"]: + if country_code in [ + "AE", + "AF", + "BH", + "DJ", + "DZ", + "EG", + "IQ", + "IR", + "JO", + "KW", + "LY", + "OM", + "QA", + "SD", + "SY", + ]: return 6 # Saturday return 1 # Monday diff --git a/posthog/views.py b/posthog/views.py index 7bfa1f05efe7d..5e12d332f7b2e 100644 --- a/posthog/views.py +++ b/posthog/views.py @@ -109,7 +109,10 @@ def preflight_check(request: HttpRequest) -> JsonResponse: "available_social_auth_providers": get_instance_available_sso_providers(), "can_create_org": get_can_create_org(request.user), "email_service_available": is_cloud() or is_email_available(with_absolute_urls=True), - "slack_service": {"available": bool(slack_client_id), "client_id": slack_client_id or None}, + "slack_service": { + "available": bool(slack_client_id), + "client_id": slack_client_id or None, + }, "object_storage": is_cloud() or is_object_storage_available(), } diff --git a/posthog/warehouse/api/saved_query.py b/posthog/warehouse/api/saved_query.py index 1ab07b1e1ea1e..91e3c42dce089 100644 --- a/posthog/warehouse/api/saved_query.py +++ b/posthog/warehouse/api/saved_query.py @@ -23,7 +23,15 @@ class DataWarehouseSavedQuerySerializer(serializers.ModelSerializer): class Meta: model = DataWarehouseSavedQuery - fields = ["id", "deleted", "name", "query", "created_by", "created_at", "columns"] + fields = [ + "id", + "deleted", + "name", + "query", + "created_by", + "created_at", + "columns", + ] read_only_fields = ["id", "created_by", "created_at", "columns"] def get_columns(self, view: DataWarehouseSavedQuery) -> List[SerializedField]: @@ -65,7 +73,13 @@ def validate_query(self, query): if not _is_valid_view: raise exceptions.ValidationError(detail="Ensure all fields are aliased") try: - print_ast(node=select_ast, context=context, dialect="clickhouse", stack=None, settings=None) + print_ast( + node=select_ast, + context=context, + dialect="clickhouse", + stack=None, + settings=None, + ) except Exception as err: if isinstance(err, ValueError) or isinstance(err, HogQLException): error = str(err) diff --git a/posthog/warehouse/api/table.py b/posthog/warehouse/api/table.py index 40fc5d5d25b89..cb63f3b5b8335 100644 --- a/posthog/warehouse/api/table.py +++ b/posthog/warehouse/api/table.py @@ -3,7 +3,11 @@ from rest_framework.exceptions import NotAuthenticated from rest_framework.permissions import IsAuthenticated from rest_framework import filters, serializers, viewsets -from posthog.warehouse.models import DataWarehouseTable, DataWarehouseCredential, DataWarehouseSavedQuery +from posthog.warehouse.models import ( + DataWarehouseTable, + DataWarehouseCredential, + DataWarehouseSavedQuery, +) from posthog.hogql.database.database import serialize_fields, SerializedField from posthog.api.shared import UserBasicSerializer from posthog.api.routing import StructuredViewSetMixin @@ -33,7 +37,17 @@ class TableSerializer(serializers.ModelSerializer): class Meta: model = DataWarehouseTable - fields = ["id", "deleted", "name", "format", "created_by", "created_at", "url_pattern", "credential", "columns"] + fields = [ + "id", + "deleted", + "name", + "format", + "created_by", + "created_at", + "url_pattern", + "credential", + "columns", + ] read_only_fields = ["id", "created_by", "created_at", "columns"] def get_columns(self, table: DataWarehouseTable) -> List[SerializedField]: diff --git a/posthog/warehouse/api/test/test_table.py b/posthog/warehouse/api/test/test_table.py index 4df7147466d42..6f5dbc9d661e6 100644 --- a/posthog/warehouse/api/test/test_table.py +++ b/posthog/warehouse/api/test/test_table.py @@ -17,7 +17,10 @@ def test_create(self, patch_get_columns): { "name": "whatever", "url_pattern": "https://your-org.s3.amazonaws.com/bucket/whatever.pqt", - "credential": {"access_key": "_accesskey", "access_secret": "_accesssecret"}, + "credential": { + "access_key": "_accesskey", + "access_secret": "_accesssecret", + }, "format": "Parquet", }, ) @@ -42,7 +45,10 @@ def test_credentialerror(self, patch_get_columns): { "name": "whatever", "url_pattern": "https://your-org.s3.amazonaws.com/bucket/whatever.pqt", - "credential": {"access_key": "_accesskey", "access_secret": "_accesssecret"}, + "credential": { + "access_key": "_accesskey", + "access_secret": "_accesssecret", + }, "format": "Parquet", }, ) diff --git a/posthog/warehouse/api/test/test_view.py b/posthog/warehouse/api/test/test_view.py index d6eb83c3fb218..d3dfbfcc17f87 100644 --- a/posthog/warehouse/api/test/test_view.py +++ b/posthog/warehouse/api/test/test_view.py @@ -77,7 +77,10 @@ def test_view_with_external_table(self, patch_get_columns_1, patch_get_columns_2 { "name": "whatever", "url_pattern": "https://your-org.s3.amazonaws.com/bucket/whatever.pqt", - "credential": {"access_key": "_accesskey", "access_secret": "_accesssecret"}, + "credential": { + "access_key": "_accesskey", + "access_secret": "_accesssecret", + }, "format": "Parquet", }, ) diff --git a/posthog/warehouse/api/test/test_view_link.py b/posthog/warehouse/api/test/test_view_link.py index 0692c687be709..3a2dcae6bf160 100644 --- a/posthog/warehouse/api/test/test_view_link.py +++ b/posthog/warehouse/api/test/test_view_link.py @@ -124,7 +124,13 @@ def test_view_link_columns(self): }, ) self.assertIn( - {"key": "event_view", "type": "view", "table": "event_view", "fields": ["fake"]}, query_response["events"] + { + "key": "event_view", + "type": "view", + "table": "event_view", + "fields": ["fake"], + }, + query_response["events"], ) def test_view_link_columns_query(self): @@ -142,7 +148,11 @@ def test_view_link_columns_query(self): saved_query = DataWarehouseSavedQuery.objects.get(pk=saved_query_response["id"]) DataWarehouseViewLink.objects.create( - saved_query=saved_query, table="events", to_join_key="fake", from_join_key="distinct_id", team=self.team + saved_query=saved_query, + table="events", + to_join_key="fake", + from_join_key="distinct_id", + team=self.team, ) query_response = process_query( @@ -169,7 +179,11 @@ def test_view_link_nested_multiple_joins(self): saved_query = DataWarehouseSavedQuery.objects.get(pk=saved_query_response["id"]) DataWarehouseViewLink.objects.create( - saved_query=saved_query, table="events", to_join_key="fake", from_join_key="distinct_id", team=self.team + saved_query=saved_query, + table="events", + to_join_key="fake", + from_join_key="distinct_id", + team=self.team, ) response = self.client.post( @@ -203,7 +217,10 @@ def test_view_link_nested_multiple_joins(self): self.assertEqual( query_response["types"], - [("events__event_view.fake", "String"), ("events__person_view.p_distinct_id", "String")], + [ + ("events__event_view.fake", "String"), + ("events__person_view.p_distinct_id", "String"), + ], ) def test_delete(self): diff --git a/posthog/warehouse/api/view_link.py b/posthog/warehouse/api/view_link.py index 24b5d88859a66..d626999a969bc 100644 --- a/posthog/warehouse/api/view_link.py +++ b/posthog/warehouse/api/view_link.py @@ -47,7 +47,6 @@ def create(self, validated_data): return view_link def _validate_saved_query(self, saved_query_id: str, join_key: Optional[str], team_id: int) -> None: - if not join_key: raise serializers.ValidationError("View column must have a join key.") diff --git a/posthog/warehouse/models/datawarehouse_saved_query.py b/posthog/warehouse/models/datawarehouse_saved_query.py index 64617a744c421..bca809bb30912 100644 --- a/posthog/warehouse/models/datawarehouse_saved_query.py +++ b/posthog/warehouse/models/datawarehouse_saved_query.py @@ -28,7 +28,10 @@ class DataWarehouseSavedQuery(CreatedMetaFields, UUIDModel, DeletedMetaFields): name: models.CharField = models.CharField(max_length=128, validators=[validate_saved_query_name]) team: models.ForeignKey = models.ForeignKey(Team, on_delete=models.CASCADE) columns: models.JSONField = models.JSONField( - default=dict, null=True, blank=True, help_text="Dict of all columns with ClickHouse type (including Nullable())" + default=dict, + null=True, + blank=True, + help_text="Dict of all columns with ClickHouse type (including Nullable())", ) external_tables: models.JSONField = models.JSONField( default=list, null=True, blank=True, help_text="List of all external tables" @@ -37,7 +40,10 @@ class DataWarehouseSavedQuery(CreatedMetaFields, UUIDModel, DeletedMetaFields): class Meta: constraints = [ - models.UniqueConstraint(fields=["team", "name"], name="posthog_datawarehouse_saved_query_unique_name") + models.UniqueConstraint( + fields=["team", "name"], + name="posthog_datawarehouse_saved_query_unique_name", + ) ] def get_columns(self) -> Dict[str, str]: @@ -58,7 +64,9 @@ def s3_tables(self): from posthog.models.property.util import S3TableVisitor context = HogQLContext( - team_id=self.team.pk, enable_select_queries=True, modifiers=create_default_modifiers_for_team(self.team) + team_id=self.team.pk, + enable_select_queries=True, + modifiers=create_default_modifiers_for_team(self.team), ) node = parse_select(self.query["query"]) context.database = create_hogql_database(context.team_id) diff --git a/posthog/warehouse/models/table.py b/posthog/warehouse/models/table.py index dcb1b2297216f..2acf4fb1faf9b 100644 --- a/posthog/warehouse/models/table.py +++ b/posthog/warehouse/models/table.py @@ -1,4 +1,9 @@ -from posthog.models.utils import UUIDModel, CreatedMetaFields, sane_repr, DeletedMetaFields +from posthog.models.utils import ( + UUIDModel, + CreatedMetaFields, + sane_repr, + DeletedMetaFields, +) from posthog.errors import wrap_query_error from django.db import models from posthog.models.team import Team @@ -61,7 +66,10 @@ class TableFormat(models.TextChoices): ) columns: models.JSONField = models.JSONField( - default=dict, null=True, blank=True, help_text="Dict of all columns with Clickhouse type (including Nullable())" + default=dict, + null=True, + blank=True, + help_text="Dict of all columns with Clickhouse type (including Nullable())", ) __repr__ = sane_repr("name") diff --git a/posthog/warehouse/models/test/test_table.py b/posthog/warehouse/models/test/test_table.py index b82f77ba7b857..00f1fd1bbfbdc 100644 --- a/posthog/warehouse/models/test/test_table.py +++ b/posthog/warehouse/models/test/test_table.py @@ -34,10 +34,12 @@ def test_hogql_definition(self): }, credential=credential, ) - self.assertEqual(list(table.hogql_definition().fields.keys()), ["id", "timestamp", "mrr", "offset"]) + self.assertEqual( + list(table.hogql_definition().fields.keys()), + ["id", "timestamp", "mrr", "offset"], + ) def test_hogql_definition_tuple_patch(self): - credential = DataWarehouseCredential.objects.create(access_key="test", access_secret="test", team=self.team) table = DataWarehouseTable.objects.create( name="bla", diff --git a/posthog/warehouse/models/view_link.py b/posthog/warehouse/models/view_link.py index a989c07a74b06..37ae87d294c10 100644 --- a/posthog/warehouse/models/view_link.py +++ b/posthog/warehouse/models/view_link.py @@ -9,7 +9,6 @@ class DataWarehouseViewLink(CreatedMetaFields, UUIDModel, DeletedMetaFields): - team: models.ForeignKey = models.ForeignKey(Team, on_delete=models.CASCADE) table: models.CharField = models.CharField(max_length=128) from_join_key: models.CharField = models.CharField(max_length=400) @@ -19,7 +18,11 @@ class DataWarehouseViewLink(CreatedMetaFields, UUIDModel, DeletedMetaFields): @property def join_function(self): def _join_function( - from_table: str, to_table: str, requested_fields: Dict[str, Any], context: HogQLContext, node: SelectQuery + from_table: str, + to_table: str, + requested_fields: Dict[str, Any], + context: HogQLContext, + node: SelectQuery, ): from posthog.hogql import ast from posthog.hogql.parser import parse_select diff --git a/requirements-dev.in b/requirements-dev.in index 5a761bd0f05ae..2a55d54cf7382 100644 --- a/requirements-dev.in +++ b/requirements-dev.in @@ -11,7 +11,7 @@ -c requirements.txt -ruff>=0.0.257 +ruff>=0.1.2 pip-tools==6.13.0 mypy==0.981 mypy-extensions==0.4.3 diff --git a/requirements-dev.txt b/requirements-dev.txt index 249fd1ed9bad5..4ed1eb4080e41 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -272,7 +272,7 @@ ruamel-yaml-clib==0.2.7 # via # -c requirements.txt # ruamel-yaml -ruff==0.0.257 +ruff==0.1.2 # via -r requirements-dev.in six==1.16.0 # via From 40bbf00423098fff973e11f799ab1cf0f2c784d1 Mon Sep 17 00:00:00 2001 From: David Newell Date: Thu, 26 Oct 2023 12:11:38 +0100 Subject: [PATCH 20/21] chore: custom lint rules (#18206) --- .eslintrc.js | 20 ++++++++++++++++-- eslint-rules/README.md | 3 +++ eslint-rules/index.js | 10 +++++++++ eslint-rules/warn-elements.js | 3 +++ ...l-left-to-right-breakdown-edit--webkit.png | Bin 123204 -> 152079 bytes ...hts--funnel-left-to-right-edit--webkit.png | Bin 114145 -> 141298 bytes ...l-top-to-bottom-breakdown-edit--webkit.png | Bin 160653 -> 160842 bytes ...hts--funnel-top-to-bottom-edit--webkit.png | Bin 156853 -> 157060 bytes ...-app-insights--user-paths-edit--webkit.png | Bin 135892 -> 160257 bytes .../scenes-app-insights--user-paths-edit.png | Bin 138009 -> 173667 bytes .../components/PayGateMini/PayGateMini.tsx | 4 ++-- package.json | 1 + pnpm-lock.yaml | 5 ++++- 13 files changed, 41 insertions(+), 5 deletions(-) create mode 100644 eslint-rules/README.md create mode 100644 eslint-rules/index.js create mode 100644 eslint-rules/warn-elements.js diff --git a/.eslintrc.js b/.eslintrc.js index 3d136069d31cb..7c47fb0b89d16 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -18,6 +18,12 @@ module.exports = { react: { version: 'detect', }, + 'import/resolver': { + node: { + paths: ['eslint-rules'], // Add the directory containing your custom rules + extensions: ['.js', '.jsx', '.ts', '.tsx'], // Ensure ESLint resolves both JS and TS files + }, + }, }, extends: [ 'eslint:recommended', @@ -37,7 +43,7 @@ module.exports = { ecmaVersion: 2018, sourceType: 'module', }, - plugins: ['prettier', 'react', 'cypress', '@typescript-eslint', 'no-only-tests', 'jest', 'compat'], + plugins: ['prettier', 'react', 'cypress', '@typescript-eslint', 'no-only-tests', 'jest', 'compat', 'posthog'], rules: { 'no-console': ['error', { allow: ['warn', 'error'] }], 'no-debugger': 'error', @@ -91,7 +97,7 @@ module.exports = { ], }, ], - 'react/forbid-elements': [ + 'posthog/warn-elements': [ 1, { forbid: [ @@ -236,6 +242,16 @@ module.exports = { '@typescript-eslint/no-var-requires': 'off', }, }, + { + files: 'eslint-rules/**/*', + extends: ['eslint:recommended'], + rules: { + '@typescript-eslint/no-var-requires': 'off', + }, + env: { + node: true, + }, + }, ], reportUnusedDisableDirectives: true, } diff --git a/eslint-rules/README.md b/eslint-rules/README.md new file mode 100644 index 0000000000000..9d1d8c0667208 --- /dev/null +++ b/eslint-rules/README.md @@ -0,0 +1,3 @@ +# PostHog Custom ESLint rules + +This package contains custom ESLint rules for PostHog's codebase. diff --git a/eslint-rules/index.js b/eslint-rules/index.js new file mode 100644 index 0000000000000..61e49e1b8c393 --- /dev/null +++ b/eslint-rules/index.js @@ -0,0 +1,10 @@ +const { readdirSync } = require('fs') +const { basename } = require('path') + +const ruleFiles = readdirSync('eslint-rules').filter( + (file) => file.endsWith('.js') && file !== 'index.js' && !file.endsWith('test.js') +) + +const rules = Object.fromEntries(ruleFiles.map((file) => [basename(file, '.js'), require('./' + file)])) + +module.exports = { rules } diff --git a/eslint-rules/warn-elements.js b/eslint-rules/warn-elements.js new file mode 100644 index 0000000000000..4013d6090e4a1 --- /dev/null +++ b/eslint-rules/warn-elements.js @@ -0,0 +1,3 @@ +const { rules } = require('eslint-plugin-react') + +module.exports = rules['forbid-elements'] diff --git a/frontend/__snapshots__/scenes-app-insights--funnel-left-to-right-breakdown-edit--webkit.png b/frontend/__snapshots__/scenes-app-insights--funnel-left-to-right-breakdown-edit--webkit.png index bc79f804ca56024d809d6d562296d3eeac685a89..6db5ed04bf68a335c0e49b5623edd40cfa062ac4 100644 GIT binary patch literal 152079 zcmcG$by!vJ_Aj~!0SQ661O!whBm|U@k`j^b27{DFI+TzUky082>F#b&Lb|)VyU$?n z{k{8l&U5b{_m4C6L7%0pIoF)y9ph6kesVGrIGE&^2m}J>g`}tg0)dKwK-^fwK!#Vm z8*s7U4>W_95~7H!>t6}gsi6o24dR8Uu#!W}daS(`q3Tepd;248USAwJe_AQ|*AnYE z!hu{S_@QY%gj|mO!>-@H8yV=ll-~1eA$`foD8k9;M?{AtmV)V@fc%M2*h&3^{iGn; zXDfDd)sxaQaei!l2lm7c} z@bwGQe_qA=?~6#**#G`Mj86z2w12+MgYy4*KcWAA7fq|je@=q&^|jDHZ~L45pBIt; zf4nWi*H-Rxvcl=p{4|bQsr&lmwuy0)dS<3?=JXS%#7V62|9vS&=h$f2$^|AZLD3Mv{_~XQWtW2V}X3HnlyV;u*tF;*3(fjki2AKV`JoT%^>i(8g~` z9vV4x$<5x9tZ!*&bSR~(MV?MuQ=<9x$&|}uX6E(%l|Bk?v#0Kt=Zl@uc5>-{etxyJ zwS|R+w^kKo130OZKQ6sMVddminG2zlSnT-mGrGce@YPE<_A;wIpTKmAMfb0lG=hS< zl}V#T#&k<)^!M()ee=dwG+Q6V%ilkvnW^TbWJT`8!h7j?=bW4A4qt;v|LpjxoXNMbSUGA5K z_FFognudA_7Dj1TmjxCEvx;1`{;%6Gyu^}{s~#Q8S5i&yupOE7=}*LV{XiwL;Yn`{H|#WVea5EHN$5;;BX(G=4)pRSaVDrmHVZ ztanTCdP>>e6Z#y~|7o{dnarK;5Oi=P(|Vx4euhz-E+3(wqvMZm;@PmO{O;YO$us=P z+=NzJmu+_jSEpY`Ovekj*t#A_7W|nJhIYSKs#zyH+*kw zh8=jsgdq@o^W`+}%{h`86^-}#QKri1oV^}AN?hEJNpiD3tyed}6)bT2yQ|BhJ3%;8HTMw{)9Wtzy_gv) z+v|s0@aBcMxVW0yuyzOTZi&i5AyQXF#*Bc!h+rTu@#p|*w2g%laYeA@QvSUYuzO!-&gr4C?}_;GGYEwa!@Xfc91uE z(VCz;SvkUGrGI-JI4Z zWuEY1WUtY^8G=^Xm7ei-qY$Ow}Ttd8U7A+tTMXpET(wMb)_5ivjWZ zr?2R#>d*S}r)|bx3^BY636oaJ44PBUmG-G0mqntnWs)&(^prTRy|5eF!owy5bxZvdLy# z5Po;r%;ab7j>}Peo-ibdviP$ozi_Cbkt{@T?ks$m=#%?wT)Aj9V~wD{*yHUX`)%8L zzG#~8hdm{yyLNrspK+-%y+vNWeCeZ4%&LPuUH1{?^Q}8=zkeSej#-S@^z$1IqffwH z#ibT7d;69Pnj{hmnv#-IQ&UskgP3Q|C5Bybw{CTb>ORy_*4ExwTXVj;yr`<;M-1g? z_x1G!_-Dj++$JMiSz8 zNNM1A+|`&xt?T(ttH1tE#^hYaoE6&;@Sk9Jz2J`dtC;j|65*JLKf3iMOm}h8|Y${urETpTRl z3={pn(9qD4eSd#{w~Nz@^Sv&df#fpr0<(#$^A>l9$D28es?}A2CtQIeHlJ=DCvY!_ zK7G9XO8ow7{$K1*zWqp2`1O(|^lKYGQ8d{hx6L-TqE?ITkKf}Js?j>~&Fi<`wlR|W z=vTdCyJ~v8=B|eQKi02#vteZ;4kM+y&4`Z`%!ew?*mf<@hODC#vL2zj5ce^_Z!*ny$vk;#eEbh zNP5+5_YGAyjY%r~RzN#xB+a7mhY8~vn;(Vp*o|ywvh1v^p|vp=JEm&yXB)Lz>f;|W zn15FZrwx&G=e2YjIn^zzrFQ4hRHQQ&x{Yb{zHaJH`bBn8J_p$xev_78`m5Zu48D{2 zV<)8k#-wZL_~yt zv%%rfOyg(6j_>tsfl*7+FJ8Qe7jWg^;3#XjxVT`|t|+ozXbYlvQt+_wT_>;QG~z7U z^)$W0U;jJV<9A*@J{;J4E2;73Vw(*x0zR8-7|^Mq;Tjpccb z1RB|rktU2hSb{EMLqq3QR@4;~XhZ*;?ynFK5j8&)txkLHgU#c(o1B!SRNbmv9Ws*i z$?x= z+woodPIzl&$ihwCuP|Ey^jZ%bJ`5sY<5-l6RMroTv=7#D1x zyG-#!{1)|X*Jn<s1>$jGWsS2MLfPPy#8GBaEEBX}S!EqzSX34^LF?BTe+uyDPm zMRiIIafoDpv8gKe#PG1%*@z_eJ{(+R@$M0kpJ(>sEg#&Oh}j-fm!|Metq_*t6%}#d z50|77vaqNBRo{v9OMH7-A==!`w_MonhWX`(Vny~(P*sYYAfrojpSjDj(*%Y^*h8%O^jnl*{;^aX#_>DA2~VU`mM5AD;VAgX??^DtG2H zHK|XCBt2A!dgX@=#Sqj~nOG@l=?(w~($Z#QB`k3Q?qLFk3W|!&20MXdkITL>F)~7- z&u?vA?X*(oYL#<5dGh4pL*v#jcg{zZwQuPC{(3hgBt%$PSYBR!tkmLaDc*f{cDBhN zKRY`+ARxftIrN>Ht4rtdrsLz|kwU|*kwS@0q|Cxa6dIgmX%v49)K37N_n^*>4h}Y^ zYOlVtzYYux?C-~@o1E0ikLmAMO4-`^{+%?%;?3dLGd2Tb<3EG&B|YumRlJF>?25wm z?RRm=lx2#&uKWX&rp3NOL)p#J$jG6@=bwkC=30ZV_WNX2v(!Q&BO||mFMB`6-E7K5 z80Ro!G;@;bs=HcgxJ5-`Nb>BXPU@FC6mz6%YHHXN+{~Pu`^7^#l}-n%rw420%;L@X z+}Mo_kF49|0a_Irc0t3v*lxsiam(0Ie~Lx=`%n>RR0^xhwN zx{#d9`P4P`hf`*5xv3J7r>qXdFCPbP2Gbd`Ti{>%HAV)k7AR$JHVXZzh@tdu-d^!P z;LCSM*>{*Qpuj4#&EVs7JT+5N{-%WX49Vd}TAiUP()@59P)O1qH<*q;iqj-u(XB96$o!kXKO9+u8XZKrK|0va)i9 zfh02v3sEDsN{$w^v^UDG26s5A>k@=LB~dDR5a?H8CzH-wLDYhmTeVj;wky4W?%d9I zB)GUT9?GpaYYkAS3=KA^=>?ya#OY%5u>*cFa0?1n% z%&u`g8yy)jeqc#Z65CD2QWg9WF0eS6c8-6nt-%YSKbVS?k;AZs75Nch`rsf>(rAY`ss+jUHc1 zRz#M>)<)zl5q?~Yn5vTg)}M-<{#RSCyWFiF+!@0)QL4<)(Be(h2&|M%74tLwn&je7 zD5KM|-*db-Hd-4xhL~RM6I-5Jy`N9F$UV;YuZFd(_t{)#c@gz--zc@qk@#)pHfhP` zpRL1J4|NV&X;=v((wIc$KbwC+pyZ>*uA5$Mz7^I*MIZ~Ks2B}sWv<@FJkW_}FEXzB zBuIO7rU{)zu(rO%@ZAW|KPw|WCj`njHBzh+deg=oAW_g z6=@l;nDqUzO8YHiH-u)2`Abo(p z|M1j#xS%-iH>AnDL!WU&PZ($*Izh#5ZDUI!m|KE#>W7 zfyv1rRuh1~r>CdTW@lyj(Dd~6+26K>0Vr*0X?geNjmzmuDhL?Rn_ykUbG&Vf;xdKV zw>eeYC9}!SorANEhk?q?%^m&3;u2s1aN~F`TOFIW0Xwg7`>f#0)1Wnc~*pZ(w@UU6=Wae8=936^p4xUZ5m4#Phh)!Jb@; zci_^|zWF=S(;eIQNd%Ervm6{Y`An!wKiNMYQ7VR}aAkz8^xv8#_tFwop_0+9XLbKq z{Y1R`&W^U_>bI;3g2gMrxoTEC#+r2Fi8%3)!z zdpXvh`NbfM-ltjo`&cISL&mhJrt8V7@fRPyr%!#GX92*|@$sDjDj#=9j9Lox_HKsf z7|E(jML-Z55|R%~7ASIBMh0e`*G&SMIDSWv6@V1BDJL&7K6_SO?}<*$_aShD@Njit z4FDY(8QI0z(NG={FlTbK7*5l@7tmrnf`hx@AGandNk~Xa?bcMd^NWhErvjhtvYd{N zj;*b&h=>Sa!2W;?!hh4@gVpdpAD>-@_gK0?8j?wb%J$SAv9S}?&PUJ#bTl+F%E<`` z2%tg6hlkriBZaeeMR5hRlMA|?rz@s@3k{VBA|If+8$M}1dn2it($mg#h=P<9d3$~3 zWT)baoSYnad7|=Y{spV4_OG}&9X-7SsQg(J^M$r>Am>*wky2kpA0F?_#k-yU>F*DF zMa}W%xBKN@{7PSHWO(?-WVPnDnVB$v(@FQMi*P2@#rgRJ0i}W6KM&%|Dk}cQ3%UxU`Z&hvdspVH`W zrm{Ld&W0y%R~{VGuE&om3#it7L`h{|e^2@B^Ru;{@KTpgQOsg)Q=cB)>5r{TlKOFH zeY=)x_>xJy#*=O-PtW>7?9Ym2qX-}%``WtWX5VtpMhesCe&YMhO^FU`p%phm`hWVV z*olXd<}qe<<~!eUJHx86$)9KHpbQv_JGdy4gZ^|7k?XT)QPZEf9}tR8Dz`~7+^0J2I?U2n=uz`?1q@s}fp@hob29VBfLOG`t&1$Y%c zHKfa**4NiJ#!8{NRwpMXn-1l`hfiAKl2D=Iz6?x5C5){9i4{>hIqgQ_$}X3@qw${W z+*xUd)&1{zdo*q@qQ@4HY)f689*70iPQ|^g_Y$Mt*<)|U|NZuYT+=(QMkjKI+{=yN zKk|PfQK!Jk@Nmh^`>%ft8|SCs{iBRW^{#*U81&gY&h4kkZSv)j{eLFP9QN&fWqW_S?d|hhwAA2E9nB>2%LKhE9?H>C-r(n7D zUl-zkm<<1Y@&CRx@qfwj`2Tv_gx8o@Sd9%0y}i8}8hA;~G!!&K@2=ey{zwc`pB~rj zrN6N-raY<`kUu6SCRSIw!s=@cBztXUmgQU@6`quoWVbdL9uX1s{kzN6#SsgOO#2=y zCrSYl&!smvg5%oBnROKFr!5Bjp~)Vi{~d_+HBa2%UtV6mR#C^twT=q7r~$pDq@*C$ zH#RgiB9=b6Cz5@|`Mtwhg!Gl{+A!&2Vwomo!-nQ?2LS>%DaRX(NF8P6@X%13mEM%| z^K%ftsQ5mtXO~X)Ry%Zl2A>2vEH(}fFs#wuf+GGana4B~(|cS0;|=ko_P1vm0TUn} zPkZ9JxVX$)1KkohnGc0)LP7BauqoeKaGTe&!vk&$l$!67Kk;{$4m4a~P39974;SG> zV^i^ydZ;l!Vr3mFw)D!Oc}(*g?Yb&w%ad-1_zh1ZNk~X2+h79b-nK=i6^zyYURG9? zmX_vxwE4_&SCk%qWONi}pedl*41Y!jhNmEn!r|stBS~*!GJ!Z;MOBqmEe}y=np@3nJui8=0LU;?CHvc-Hvj_T z1l6(@&mP5B_oA+M(hbn!N-=pq%nj>I$2uec3U_TAVO|7wqxMA zULtpOiLTD~WMM=*IXS7T|9~l3ShxpZV0>aCd@$+7%aaCXP-TFf=mR)oXZQB@hFR2kVxa-?<`c z#;2lk1JoB4MZS3s$kydxKo!g&z0Zt9Q)+Mm!Ha!Gb#=1HZ}IW&o8#rs$Fg;*D?o!Z zOOj*YeEgW{;X{2xytaC_4ge=)K0EvSZz_=yz{T(3-$XRm%i}O{v9SRx#BP*KQ7FfU zrvHY64AGngR4gJa?E8-&Cue6&{-d9&mfs0+cRT3VQV20|p>W~PuGmwls;bt+QS&=& zPuNc_EG^kQTv%ARdGjW;XVbwfs}COrb5dg1L=y8VDx5l_xWdE3%_q_L-rbkh)&(&w9FHGA zF&_sb0UjIwhjq0F4<3X_5>ivU&;P!iujaD9EMHSW-mf4->gswiQE6XUULHiso}`#6 zgYPH0*@z77yN7;xlzlqMA3#LLzL&4B@AF-c#e6=itjqz10CwXw$Ggh;R!Pst7yYuR zpa41HskFoH{GX>20L{4-dp6dD;+$Thb=-=^sBLX_7~N19UOhf&>3(HPfL{7(A}92~n1-dG$z zIwmGu!Ph+}Kt;ZOBf^*PZVvGbSJaYe~;? z4|8{K5BmJ^gXpNJHtor7_+b1NeXpSxXfW~GVHXq@j^J)WB|JDAR7wWX)}s0#0#;t{ zILuY3a+rjlK7ERb0b5oLK^u|=Rlj}{nhh*x1pEUk@<)T4<0Kz8i&f?2!OOXs0BU!0 zbF)dsLppA>?D1G5qq z8X68c;qBY?7TQ);J12WfNYe2F+UZn9E#u=ZaF@@Hwz@hyW4Yf)5$msIx4^Rhjn=)| zA#{O?(tI)thRJI~k*njmU}%Hz5bf;kRZZ|Uio%Fm1_w)E4IW6zz})AgiseOHH#ADY z@NNM0`4$CtmTIn!fBDMF3N#ex8PmB=NFJ_TJbZjMudRWXM@psq`USi!PKwECfB81z z*|TSlGLAt&Tqhj^eLY*;0nBnfKEBPb(Wjt+w_Vl%tCW@wtf>)jPr4gm(2?^YyzKyO zn7sk4^0k$fd=v+*K@h;346LAH!fxee(9+X;Z9F$>fKNO(J6m(U`?6U~ufNZv!^6zO z43Yg8yI-1(ftmTuz~3&ISsTeOLScozf^_HaOGF&@%)&XnX|I9PpHRvV4j0?10L7Nb4^W6baZt1>g?=HLJ|qH3o;*j zx)eJ*I|vx7$_GlDlhs&tfByJsZt*{S_<~@j(sreR+T!)+n>$5MXu_pnE@0?^BLG*n zp!?hV&+g}uqRcRAH7FQ3)~BbtOD%K}X3kIupeZ{zlnK#%7jUh(Uu+3DN3C--gc6wZ z)kf)*nVH$7(^|IAAx4k?e?ECTHs=q$gxp-#(sLs@xv! zCVv0^z0e+MGvz`)s&LS7jqEx<%G^OYe0&YXxTqWWf!M=oq0Pb|1NYLz-2Cs`@UXDF z__z~`k-$J~L`DtYV{C#ucY+M3IM?fD;Qro!6_xC$d0dTzAbF(q`|sb9!op}a{ZHdR zjE#-WzB9Yeyx(A4z$GYn?WOojT3TOo z#_-GCc2?ltYDGpNAKG?SbGaO$`lL=KYP0uTORt5Nh`dIg3)pQBi6tu93$(G5hv#>-GrKNeW3xNj=hE zfH(XDjKK_xduoN;B~FCW-PhOHhoiW_z`_Fei^2Jp`^rA|`_btYqX=54$czH0;b8-4 zitX*~&IhZ_)zK#mIH3bM3Wu?9>%UM7-qKs`PuC(QQR^^w<#jo>bQ85E;4tb=0BmbA zL?;TZu>gt1=q(I^H)!jhNm5*ozJA5~Ac1_TwJ|(A3^@Z{jMu6+u=(FoB9Uh z+p}l+`T4M>mM5$EuCVy{q`w0n*%;-bqx%UxgAsF&zq<`qhY*&=51a&|A4r*#t-;iV zr!&WUU4kPMKMxKL%DXtgb)SF*zBAW4QrT$nkgvU=q2W_4gQBN~6v1^oP6Ktq8{e4y z{I#hmRzgye0VF~oGgVSj0-QruN~*%;gkvb>E0ZNyK>&&Y5<-Lm8ynl!(lRY4rv?Uq zHx|kDlXxb)@Q94vKoo|eo!tQ#MFQsIPeK0tDD*Wtn&Qr#J0v9NdSD(%wO*A?B0OMz zt7z~5+-rT5J4qj2K#sPxkZ8a<1BP*XQw1G=2a{GZJPhL@J_vtY>coxgrRL zMMJ{?7^I>y2qy+)2k#8&ffGK`r@Xw#dZh0_IfdSGhwnpHMuwEEtf2d)%ZCpolJpv7 zmUrE`MLady(gW^a=LVPY@9>~$DOq_sp`f7O;&(l@H8(exx;`)?ue-_R#Th7rs`U8f z6&1UzI|m0rKq7;JSQr?FEA3e$H|OVz^y)uxnGQ0vbpy+LsQ3#N9o+^AjS>wF4KR&z zaR9-Sm2R-P1}^zB8r~FVhMhHS&CSu3M&gz3`-7rsQz>S&21WSMr}q?E`)_O)S67I- z0E_tX<45`1c4F?H(NQOWP5@h*3d#3&cEEtB1#jZRheKS!^E%d65S!~i-8g5<_9+Sb z*Jmoi;I+mc7Lz0=RK~6YO=P0N?(W^Y&_tk>`1tt1YIbvT10Ey@4mDwtKN8G6XrqGs z{O5o(A%KV7SY$e64lIXG;!9vaz-v-*8ob}tIS5oVw2F#~%Yz|ZxHK~{xVylxDWMrf z?QrKjVRJq-YkteC){p(gME>Cz1+W-cJrV7*s2G@-Cd;DYu|20yrwNHg0zg_gP)tqN zK$rwXl$w(AB1M6ZuM)Bg*O0rSLcvyTU+0v7Kn+6DA8|3gP@C>3NT?vv@{!7!K^^LMLDd1 zkI(DzZ@zw~j!hb1kG_85xQ0F}G2nPOM_ZeJZDAR$SjzF7Me@5OsjSC67)iJ2P|A2{ z^)Q%6Ii0n$AA~J~P`FO`9PYwRg8O;wtw2pnEv9ba;<7R^J?7%lF1NntuKhmgK=_@| zR~$T1n?^QiadDsPnkX;NaO7e|#rFfD434Hhe_n)J$Z7fH;wC0ZwI<#6;=eDh#!)!p z>Nz+Ea>m|VupkKDjGcBLKIr7>Aytx6_xRua*PTf!2PyJqBbz_po7x0IVq#2GWOE`U zo?CIkA{k%q(PAt(R2Uo{FJ>nlJVj#$;B$4hRSN`DPDSNcZmxx~@yg=jAk1=B*4zl< zpzb?w&`?JZ!kpAF5~0Re_e+rl@croN=o&{x)QvY=uYO|C&N|k2BjTBjCK)xN{~fRu zE&TTFTTe^aX6$p208{x_uSJ6IH4U+V?E42U+| zm-4c*q9SIP_f1%`Ytd{%cop@NXyrGgdfS<9+n@*U%J|7EA^ID{T|Kj=P@eu zr9MDZUcSfu>TIgFR{?y5YnL&l*-@ScVr3B1ftvfUKAh;LNFnk(f>~WbORLIuML|}! z>ppWtwW9wD073ADuTycrlmL-lZsff?Q2?8ULx-Qx%@X%)3Gocm$}Iw zPEQd(9eR8M0w^t{qCw^1w;UsUAn>+OSZLL_l%JTCL-q#&9^)=1r$lGABk)oyt9&^I zTN@kGQK=EW6iFyYFadz)Juw@WQ&Q?L3crpLdkr>?_w+JN;|HwTAF19>?gm*upOuCDGQ?faob zgoIw7KTp-V3qE;r1Z2nobdTsfolkPjDHLkwM8Cc?RX8Td-}pomw#!ia5YurS)!PW2 z2aOefad9z#m}?KYgavb~8Tgw?jVvw1RMu5Vtg*?xqBI-dah0>SPNYMhJzDO0{s`m& zd+1kygAHQQKN*=nnrb@ll4EJvgios9cQ#J}+{?@7FO!^(Z}Lsdo?DprXyfQ?*&@0Q z4LUnIfOU7f6c-8fk4L?$FkO%B?dwxqwFZA0a6NJY3;E3nJa>`-+0xnzF6{VC6M18J zR#Bgc&kVrmaf2QUKoa;3h&y2G!ZU`I2^fIkS#3c9gnV|Ptw4BM){|$x^d<95RQC6C3+L`a8`~->knzo?boJq;?6^2S&Y|KKc;P0MQiY>e2ikf)L3!rlwJvHv{r7_jOFSIzA_mSb<6Hlz>3ZqLabJE@$m4#r~ygNIy1`1 zXuw2oE9~b_x+$e&_&CT$Q#IASztRg{7#(&gXlqyN)gvQvs}DzihtQoIK)K{-6ieL? z#i8PNxI8~OXUBPfeCnp}IcMg)jrbvkX?1%t9?1_|GhW6=&<*M8-W>we zo>e2VR+{_w7a_9F$iy_K08E!vs|=5bsMvZz3S`pqJ&Vbza>FjF%M-XtIDq0&yY7dK zH^c(40jY<9keq@dSH198LIMOl@*4etP>g|}uf}}1w}(PQhzVr|=wR6Q1`nwZgbQdI z*?@0Z>wHu=>4HZOoO2*kwbXP-M*jQi>M8((Jo(Y-W^It=rr~b2cjaQeU;<19a92u7 zqwrl2seX0?(vL)gv;lmpo+S<@O!}GW8!`l{z_!dofw#b3X4Mex#|qy;2+XxLhNf` zz=BK%(i7-R8m2#QQnQNAmD{512|j;?LyAV-f$EWsu4m+t8(CWPhV|B4qTxd(8Es+t zhg!V)=6LsmyX6NabM=of0VdTP zfSc=}*=*zfg&^&CBWCW%zi6QlKxxt=?+?({XZ-xonfwC+ zWMiI&#KfFW*L#BclA{Z@@l&_+V+h5<@__9P5H1XQ^@NkNUuGlYcUzl*^9g7l0R5n# zs6dF%&VCQm4w5)fQV^B^SaVd5PMx;|EN#$~3YMWp^#QlirB74}F?V_*Qopk)C>;4t z2PT`3vB-@EGNw1f6j~Fis?MR7Gt<)niY_@ztiH#`IWfGAfeKj&gM77|qbs;z=r;wm z3k9$U0kGldfuV|DFmlZG`#643*9Uz{5_czZchh$t?^!Y<=pXv`wv_N6ZI3s zlfIBW_IY^(syeC9#(o$$Mn8V!uYd(^Z)uqq7dHu&d_uhsdJPK;OE9&d4&;ټh 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 literal 123204 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�Xu6cx{p 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
UcfPSjq2%IL!6dTGW58cq9eGn;PT;)AW& z1N!>S_lg=Zd!M_!dZ>|apNL2nv}EI1{o{nrM2~|VU0k<=&_PzF_LKLAKbk*mqRW_7 za4k0)kN2a;x9m+46z((a)pZhm*wNL#nzP%&`+gvQy`$SjKx}rs`dP`(KmM%!Ikt~= zAzN+girJQzx*AS@<(bl|x<-ZmA+N_T6Ej$uM>eIdqV9#toTaKvqF~qccCke)RW;_y z@03GA*1wyuL5>bNjU-r}fIvQ`06w@k7sBgi2vc@ijW+1JTx|NB8`f|7{gCQthCQa0 z`{GqyH@L{G{6+jpUSi;)9?jTYvMmqCv~%OHFd{E#uW1iA{q86#YeUDU6;d_VS98Dk z^kT`z(@nBw{4@cq&)M(pGDCHGWEacqY5jN1vWVl&VcJSM)!5Edi*qdzmfemXkLzQk zV^MM0VU@;PPRur^_1%ftczEmAZ!*8_882Tw3}xcgEe2dr4|KD2qW!7C;^BIZ&q1!e zHl*b8)K8) z&o6=F+N+L{M7E{^C)hiw`#I6ruKSj7vn92@t$pO?Jf-?{(FX zGh|I0t3S#P&u4w$ZgmVH*EvTi^X1L;!3uaefNR@CXccku?#NT)Xq2_{?O0n}GYVcn zz>Wkfu6?dw^OGHo=(*hbXRgKXa**2t{zaPE_^`LV{>RfKcGez&IcFzJE@R1KpQ0zM zC$UFqb>+fI8#wI#4<=+(CN25hKO|BaEtqRUn)LWQ$a#-e*9wAE#?N>5L5VuOl{nWz z$M@UmxR;v%U!ttkaEig`X7OAyS@+Vj(W~WZ_eJ&bGHW_vKjT#N<7-;`kG~6pGJ9y8 z1&M6_b2!=?a}GlF%OHqtiHMWmZzfp~=jJ1LgzqoSx^H9Wf4+DdLI2l(`EOYLKSkNw zPqAeoAl!rh*zg(xNoz>6tgJn9it&8W{PvCUCj9@_(8YCd=QZ4zawrY&W%(=Uzy?E>aPfdL&f z;rkKVa&ia6CHGoER{9ADx+5kmEmZLKz4!kC DUCNr} diff --git a/frontend/__snapshots__/scenes-app-insights--funnel-left-to-right-edit--webkit.png b/frontend/__snapshots__/scenes-app-insights--funnel-left-to-right-edit--webkit.png index 118d11b614a3fe4d452a5f4d68d317825b131c96..8d7d747f8990a9d7674a53e3ff09bb8688c55150 100644 GIT binary patch literal 141298 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

J~;NNiS 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%0ApO%v`GM-@TXS=?jQcSI39~8+ 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 BFb@C# diff --git a/frontend/__snapshots__/scenes-app-insights--funnel-top-to-bottom-breakdown-edit--webkit.png b/frontend/__snapshots__/scenes-app-insights--funnel-top-to-bottom-breakdown-edit--webkit.png index 5f8f362dc80f4af044c2e616759d941c55f989e3..192aee1058894fd124bf1591f8ec5875060d8c61 100644 GIT binary patch delta 10816 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 Ao&W#< delta 10622 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 F{{iyo%pd>& diff --git a/frontend/__snapshots__/scenes-app-insights--funnel-top-to-bottom-edit--webkit.png b/frontend/__snapshots__/scenes-app-insights--funnel-top-to-bottom-edit--webkit.png index 73a6ac1fbc6d525450749bce3d57d7a395d943d1..1158f400a0d85da9d688fe8da1abdd7278dcb5c1 100644 GIT binary patch delta 26662 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 diff --git a/frontend/__snapshots__/scenes-app-insights--user-paths-edit--webkit.png b/frontend/__snapshots__/scenes-app-insights--user-paths-edit--webkit.png index 25086a8cbda7ff334b201d31bbdb2a4e6eaa07c7..aa0201c92e8b62a6d552e5a8f0ca1b0be974fabd 100644 GIT binary patch literal 160257 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%0AA4$@DZu=?`R!jD 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

b|+&J`)$cibG1vA|K8pUQD@eVH}_4I%j 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

_zz^$hTaRq=n!wUrH#D*_7s#IO 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 literal 135892 zcmb@ubySsa6fTIOC<-Ed2tit!LpLHF(jkp>Bi$e%(%r3eBi-Fn(%s$NHSf{iotZ!G zthux9oVD}_e&>t#-SO;aKl}L0NQof7zTN=!(G8NYy>?K~$H+FVvN5Hp`tLvH} z`RPSIeJnZ9^R-3KTa?_80SD< zVoJ#~E;KUKTG-OTEwZp8h*8LEwqwRgALnBHU%%{t@UI$6$`Wflg&lT?i|38)@N`{3 z`R@a0BmH-C5O@*YKb7V)&S%@0SXi~+ia(Vs7go*Jep&he4Y*tKB~0OV8rIbe#G)!4^s+T|jL#!)K%G)50aG<69W~|T+UkypsA+zzrkx`8 zlbzh~m?f|L3Rcs3@KzzR8xe_wqG_@H8yAuRnf+&qh^#|_ryq=0-1EewrDNs$`xDu; za;=@Y6tCr4>~_YZRXDu8ykh7yROviOaBy(Wb|w~@Jovm2;52o0|LivmoH*0kA?_Yo zJ@mXWz-ohZpB--wrPD2aOki$-_!Xh`J8u@4I?nAEXF@+UYTTXM6kY`cXdZN)Dn}IE z3T;@tHe|Gl50GkxICgZAACJF0AMb=zzctbP{T=FP_l|}p392isu8t48o~7=eD{q2{ zs@d`n=L6icX&+{malE(3@=&h^EOk$D4$2|Vxrh*BfA0d}eX}cA>c$J<`P9hJg)efn*uU~wmj--3&)gU8Rct?!c z1%X-EJdN(32TOq}>1kabNh79@9|8=KI)m{jSQlHopD8U~EO_wQZpuKBIw7kY8_%9S zn<&z#Ga1X9tF;RZ^+?j@=WjXP8X;4+KN!nbR#i>t9g`xqJ($;Mj0oPqg}1C(U0)Y> zn)hfwUhBO%-`klWqvC7QZmv4vyH;B$!?wT>P!5hucVGB4H|UDXek(HO5^ycitV^4i zTHHx5d*GgV-;is|`QGbR3&(fW@mI}u5F_Z2_qOHMwqINviJTZmMf%xc~3zf?TH!?f?rF6JJtP7V0z z`m?h>x}a8i^h(_C8(+7pYJ~obLLptA30F32`Lw!y?0fk**%Ldagu(6P!Cg8$yo)?( zm#r79n?H%uZ!N|c7oVbN@BBDcQZYWk60p@?D^67!F(LNN3S-~7;O6DtwpFAc=BcXe zI+dtf9_V~aMD$ZWTPm7LF;6}_#E!9Kz`%MwQa(nXXw|IJpg&=d@1fpeu6Ezy{rT?H zNY+O@u{`6Etfi%;apj1PW>0uBuMF~y;h-QS#3XjBWi{!^a^py`&%H6U>?~I42xD( z)c(<bC*uBpB!{lOmHdeR9bIdFXO=12=>&>)IN|> zXmRYNuv@hv7yGR==n=Z^^I=*{*buu(GWKEW%QkKgi z!NVl2sFUY`I#e`~UC_}&S3G>%exmdJ_PgM7A-=iqN@9Y};$m_KTopf!ZN$WBT7KZv zMrW)pV_}&Od9hO{V`9|e!W)lu8|^7xOO185ExP18lb(+!-}%zlx|06dZSV|)9)6la zfgf{tIhxEoS0CLtKKI%3uXROqH%8W$wRiXvMy}ggnul)1+IJ)e^S6CRrjSl?z1Y{_ znDL8bK3_&rrUj5YpM58X?`9@NAfRRt0?G zcD(OHfWuuKmMoqnjGBC<%yivStxePzHuS7>hOk!@f{W zi=Qnx&YpG@cxNeYVp(H3jj$xj1M#8Q_Yg*J51|cT5)! zW;L69Yv{@$q}kv+#<};Kg`S$amviv9n9?vak&+*Y{ zRQ#QSwf{Hs(G4rV=vdOTI{K6=2(VdfbUL}gurnD`2TQa{D?XN+@UuuskA=&lI}Q01 z71LDV9VSKOo1-f&%ozwfbJpQodFSn;s@^J7H{)o%k$Xb|{pzZpW{aiM-TsK} zaTKwsBUDWWd)DL^9$d|h7t(gN6)T;I^7Ah(E8ZXksav>V(JVx!K762mOMm{zj16Hw zI=VAfn9F*9%hSY?cmqVIn6Ajq*eB`B8fr6Y*O?kt&vf5zU~%l>^SRG*T5Z7}w7?@W zUxXs3x?dZA`V_~JXg*WfuS<74*6Q=J&_hTvkezh~q)I2JP~@HI3eygxIP;62g5z&+ zD7~X(zEyXj)hf$Gm7ES?}GVJRNGuV4n8TBTWdFjTkm$+Kq?rlLm~ zDx~fT3Q_-O+=*oq?B8$v;-0#8Y*}0j-?onLfvWrEV4jDgBA%LGMkY+%K(7trU1m6_ zRHQ!DXg1`BO0tSXw{+0-&{(yjpU7&ys`DBTZzp0Ric((3EQ!#*mIV>>@MO@<-0wiJaXNQ!%|Jg*CCDH9x7@!n1!TR z_8%04rcQ9nWS*&}>Y|3ia+H+DFxmpa{I4oQ#KbQmcM<|_6!%BLMJ3J(p^7ODl{0D* zmAr~}ue7GNSo!JgNeP+03bN)^&`ar>@P`$S?~N;(@~Gd5e7&wt%#U&~5-=u149_SC zjnbQ{+gS_gbgi$bzayUU-vqj8%n+6?T4KTEb^mH4T-tfeA*GKKJrIc zG<=y8Fm;h^DyQDRZPy05##(7>BzrJ{#Z*pSo=k9n>Db&3FD+CL@X|g3A4rQWFqv}f<{c_7d^cU*q(nmTF%}He8XWa7-2myeW406 z(t5+iJauWI>|4g^J6KfM8#Yo=Q6Zp+xSIKI!)-SI{N%LT7Hx=#h-lZ%$jAVeEkHbM z3nB-r(h~4$ke#g8UZ9{9Yc(}iRX&9aYLQ?-pomFAxz3rGj~BTf#iQ}0*Fn-t_jtHZ zn~sc(TnjRmTJD5&3$?CHX|Ocq8B4(q>}+TU=IC~s>Z_68 zau^%Ods1L`kUJo^=QeZd=hDJ43!TjuN@pE-^@7Ta>Co2}vvMbF#;N3QtnQ~rx(7Zk z4O7ksdH#hF{QUe(27Qj5cod}Fx$6VTUGTMO>FKewYUD$!r1nS4La08N)Jl@BSWM+} zQ;@hv+z1@>IL6eql^}O|dV1=>3tkj!)Qz`5Cef>cJY5jy24~J^_MV{-Fn2Z+nJ$>_ zxwD=-a&^v#%{b^TD(`Tpzr?RSm`c_2)T0UqVVP)xJXZ6Is9=#dNW?**q2OGVw|MyY z+@|9+HR`IN>?t!^a9^SCUh2NZ6KI0W6)L5sez$bC(*3g9jmmM+AJ3F+voWwvt&6lj zS4W}LqMGuKk55amiKTmEI8%b0n~Tc@K!R}@Vve8L85yIw@*7=*9;Y23ISZjVfe4bG zMu3vu)88L0ccqWiC-Y6m=w)3D&llCuqLfPU3f%Kc>U8}PLL)oV!koy|;-~p6-4x3` zlfDJMCdS<(KLwXI#^!8!=AF02Q-gp{l7@Sj=M?eaG(;w5$KD;i`;2$4bmyJQ8~ECa zoKh{lr;FYRx2*SK5Q*&gJX*vRM||~9TpHuUsGtfJr(;DV^oymyi1@h>D@w``$=q3g z_nT`(?@-uQy3y$%ig#kxH$U1nL&~rnr_npxlpU_JNfoxYcwyPuJU=}@OurWpNd20{ zc%1u}E$k_2O64B!*?e}n*ynM-b+oxJDOSNDAh76%eqlgJLoM_G0NOMvt-V+-Ga&kA zw#J6muF?JOn$>)o9S=T~%$CnmqWbIrtQeR5?j|hcvI_VQr1DuN&+xojJhdM_pMzZf z7iDeuOXC27oY3+x|Bf)_(n5p^BJwL8B=x+tF-K7l929gZBHK@xnD{%4{!E5|D+NGe_*K*cO)Cz*mdL+DA4!n!0iv$R-?ic%W zAU`_n&#Gk1#4{Nh45rXh5T`#CIs=Kw3D|j+&K}5%e%qQR^jedeX`~eiYiB1=I8mcnn@stv3m+iO?^`FxdUb zS_#^_)jgF99{*gH8q{iO4}$&yl~{w?2yNY0B2r(|wgpe@HvhELJ_C`!es_{6yu%LW zUX6=ckgvc&x^pF^f~*@$GYVJ9bZS*AObiA}s(uOrq-{MvUu~7HAhYaOUpcV!O65k; zwC07Mc#M3JpJjOcJeL1CaOxq*<=;$diD~sSCr31)m)CMeQx$-w984;OUqx0Lb@mnG zO+`eEfvd|bhP=lFS^+)ZoTIqoae(Z5h! z{;m1XcC}E`M{qFuC)D@JXpx2*9ekl`1*h}rJCPKjR`WaIUk**f0fn-JcAEtYl-fw* z>59fLGH9b5VVC^MHV0|HjW}E`dTSu^ek@mQ*!t!lJ;=TDVtIL4 zP;O&mqiGy7{8)lkM_2bvy=TtS!*fR)TF<+aiFGO}f`5-JEh-^_&ZA+GM`9O_>vY3v zgdelGmEC*sk5hE~prA0ib6?OLGD^nDIXzQldHkFhMK>Vf^IryX5fN}cE;c6LaK2pq z$4Tlo|F@P9c;0{KXoeiN0A})1#KgqJ$jC@R0psH%xHY*oT_nx$!LB(51hV!N9v2V` zCw>a}?(UlT8pX%Q@6A-j#({cmV|J8&5(5XFMpklp7z+w_*Q_f^KQ0~%R+;soD zCjHm1U#1g9!?*z3*j`cb@$oS*$TR{V=|QQ%;c~ufJ+)4)R1h{DjKlQ3?Z9s7aH(xQ z1L}NgqzVrhSqOYkOTGnCKtMnrZ3BQh>|M88*{P(e#hMN5R?neOsPGZsD(hVB)_!B2 zDB?67wQv6h(Ke=+m5|dmXVl{E`V8N__~pgH0t^KM!lHL%#-rY9vD`V|=i0)PDl~NG zzpEsEMp|B32@c?K*iW+QLnRRwEeD_YviuqrEDDFRr3o*J-S4jquS}Z1KBCX3Mn^;Y zt>w+}@!DfXCM;g_PpY2GA@A*VvANia~WM;lXUN|8B?B2nm*^oK07|!v}^65E1asKp*$UxOoEKBjFl5dYWk2xHVgI0yZs^dtRZg zseiMOy8j9Ml-2d=mJV7511KM2uo^*05U5aJUN`gM+Igijc)|Uqust>ekIf>9LjY6P z%TwX=LZjPCSLnf9T~&Egc^imt2lEX(u9JR8la=O)_^erQ3vL&4CAwX%eI?~6d|Z^2 zl)$FmfGzf?A7e(=C-~%K_Riy`HFKfA&=VPt)iLNbCZ;}d60h5ICQAqbk7|AE>gsCT zLhQ|EHTcJ?H=NzdFR^I8Tv4&HRT&PZ97i*2_uRL0TQ8PRALiJ$Zxd@&toLu@XSmi2t z!t%|>ha+laT0)LVH?{BNwdn;8lR>q_32^Md`;(kYkzibXY@0L{9^o>Aj8EuD8P{n~ z=X3+&Z0IY&GX9As{>hCc*IshNZn;3MIX!1S+2B$Y9$_zd8SsJ`9cjE!Z9~`8FZwLb zE|yMXHg=%=RU%l>)18UIwYVepj@wLpcdTP-hWnAspQKtR&A;8qzc;xp?ZKT?kH;wd zR^ZR5lrVKnGF#F8OsX>CTxY*$EygbyH6_HV-iX%pnIL(JkS@Agx-Xsj(oOfQ7{e$ln3k^?_MVB9(7%wqS4O~;d-NBSLMF+_52*i=-6Tl zvV2PFQA^%7Nc}4q@7mIZhydGt!JDHl!adI_i@ELDnzC?u5NbY3N@Dl}Zh!zCKw`mI zLHDaQ?8vzcvB=i8Hlb8NaSqis*R`{;@p=;wnFvI+Cv!Qt-<>IM5J?-*4?O{PM!^1M zF`Pt%fZOryu(%1RWfek+r5hP>Gu5grh_i`FNHU258x?aLcRBt>#)gTJn%WcqCSe@| zo)$UFEV%VoB}OX7!FZvsg-l69n5Cqo1_GJWZIlrJ*&$5)UOI&v2OXVc&p=VVk;=Y9 zqOQ&dux9ba8O>dxgxEFqORZ1K1|q)2jYq!LQY9fJZ6`guyI3IPb^TNt;^zm$jbeh_ z5rNaJ4KSw#Bv=nWor=VhEz={H^~!R5sm4{cY2Q?Sv-+`LT_JBGhg0}G=7Y>5-Pyjk z=>OfhaPVviG_y^N`6&LmWrH1Tg+zOY#LvES)Pex@83ojURl700xa!vKVeV01pz&lk z=qKwh`YKwE5z5AwUx2WZ(la1?)+CGUoMY}gnkxZAah?F?5!%e$$xg)Tj zMN=UP)5ya01((DAX@l^%X6cd+(ed%IV0yPQaO^5y>3GJDsPVPN^}Cx3P#L|`GGAz% zBf}h2j7(=L&ClaN(qcxCzW-f$mk;Rr#N3B- zEiM1s_WBwx%Z=^)x+4U<-y6=_fMbuC(qCqzjVd#nDA7f|R&o}1R#7OV3Fenf+h$qY zYNGYcJv{lle3$Gki@Q^0`{+n8Q$^q8WguZ<8qqH}1Sa6+<;6XJj{(qwq?~fGCJWKH zs9U&xqjJ}DzU4wAp!N1qVLs0LHZLdV9V6p#Is+pchQ_*@#4YFpIN^`#VZLuqz41e3 za#Q++Vsnv?lR6Xa)%ECTV<4Gn0ftx|G3m$l8*Mg1aQJN(n;%_V!noKYp?RLFH^alj zwYFQ!vdeggrlXZ^q7h@J1P4BW^epx}HS)E+i-+hZi$||&CFp1HelIkBY33frVKxer zxCAs1Sv?5mH8nN+g`YhVMW8Qqh3);l9Q?_re7=9L<$e}vz_vBx@s#Wgy-c@|pV={s zibjrPV|&lzMtzURv*7VND8c%w`GTGE&He}nhtuHQ#TXlcHFEB-lDV~7v;Gj4-Ac@S z_1|95@g4o6Yt0+)zHBe|6-}P~O$V*bY~*n10lllICarR3`^wuW!HU^XsI{;l z5`X#@h9$1uClxh&Wdhq>PQ%w)p|twrOHdi9qUe*ap6i$E-=x{e}(LP6t* zQu4>D>5+3AoLt&_c9(~rLs9Jy=FPwB+(f8?3?SCOhON_seZdCt`(ZV)K<7}ZL7Ju2 ze>q!J9(q_wBE(X2$%xUV+aXa=7n~o@@Y$>DQU_1cRf`i-sZ;_jD! zaIjsdCAk^*1b1xzQk8bg zcCG^IC#EojxE<(zJ*$Iw?YxlFZDhwMf0mqQV&{ZUhswK^B_+Il*^sqqZnMs`WLRV* z!C>?~Z(NF}kJeQ8?OI>2a=v{ImcZ%O(2IxI@7v-9tO$fp^AeKnh(M2<&pns1OtFkV zbR|e5V?fibo_0Yqc%+ahM*B=^&e_9AolzQz+ZoA+4tW>=-!B0JMKnC$^-X z_<7%D8c5iFnj8R`RedG^#HBE&sPF~%=Q*?(=6au_7_hQ+!P3m47Xe3*$bYd3cxNV7B z9uL$SI|E8&S+V}KmWza>ZMLJy@o4#FZ9-q4WaQ}8$wos5bj4}+!w5brK$a(vg`l$w z_La&Y6ux}>d4ne^zMf+;9hX}i+DV1lgkel>*S1WE?YgFu3+uA=t#LTFF=ME`=2@WtZFg~V(Bz;Mc?8Gp0GvF^%Ko_I7O$-xfhM+BxOIGT5?ooiz-`YyN!mD+ z&^T*Gx7S8bL(|t6cCJ)6k}aM1y)=srV2k(KB1OZ6&{(^hFF&eV$Y*W5chE=4}+oM|Z(pS;QIk_ra*o@)$@JX9NT>k!X1 zk2E8?D>r+BPMrI)*ehKO}9n2rV8;Gx!L8%XLZCo5Alv5K8YMN3V z`n^gpqf1APe!s!>%K9i_=n)e}mp)e3o7^b3X(K3=rt_Tna$UDRmqG3a5aNH@Tqv5buc;OHY@BL5st3# zbE>usFm_J?>(N|_vX8<+kk3iplkjDSQO>7IzEa7YVuJxg$Db~-Z~d2Ez|FrFcL`}R zptk{<7r@L@Yz64NYWk51VaM}E4_7^PVMb`WQy2N=!C0!90A)y>=67CjP&HM4jaeL$ zG;*Ka@%pa48REUbIvmR1j_6wT9uHwBUckLEZ+qi=r z!AD39gi8c{4Fe0ypwqZ|(|`%BM}x<)4L6q_+hrkNH`v%dRmX@S??Z++%cj%X@91@R zLs3z`-kYXXt;mGHkS3>-EJO#b>$#dqgY}Y|X3~X3u#zp!Gl|)PnK)u5v@XnnBh`yfd<@P!%@QC5Wc5m#W ziax2Qua7wsBo28|lmW-@ zc%(s2H?qt!Q>k-x6nGtSKW9rj1-S7A8n!3J?jg|X*qAP8;iEhU-wZ;WnF1&C{X@HOszdGfrbqR?3wf^fkyl`+n!ao z8m+DO=MBBbV$sI4uSQKjROq`j!jR4qp7Z1n%ojQTPS~BWx=s>g&pv zGuVS2QA?LcD*!vK55;#OqGT!Vfvl(jDN`@lbZ7FN=ZIonq|uiG5>KpNLcE7tXSFa~!s6q% zpdZA=18T%L08x9RJzG#fBMVPNL`2{Kja6fMKFQ#E`Q>7*k9O7hfKjx^DWg%DnT!I2r^s+#utRA!Z0ukY!HJ$BzZ^n># zFrKOFZf12=Zv~E)f6Ee9-1Ilh0L_b&m zU}2SHzR3S_8Slf+gLMXEO6xTN60m?U*pc))gVSJZ7<4na%D=mL@t3^R#XqZeI%$Wi z=KcU>!iU8KVWA?`ir;6r>L2)^J8n;hl@|uq<~jkoUOqT}E8m1xEw09cQ^g>CzJ#3HitCFkD(%COwU52S5Yh3# z%A5=g4M+)R**I^*$ifj<14F(eDHKJ{y%%yTA)ryL6~Y}kV97Uu9^0WT+7T*b)Yj&L zB#ydc_klP=eZC`~0ND-da9QhcKtM=%;Li2S?dJUa>@qlvv9<=__4BHi@g*G^wYFA- z?z(d*mHS+rp`#byD`IiP4u~sBDVf$ri+cMRqX0=}P>c-&ac zPF|ik-m>)ur=6jE_eTBGwqoMAv)vY`isKE2e@mUh6eMEMMv5d$D0Ha>jZ>y0kQ9HU z^zBDysAFkG)FvuLcu#3kZD^K}LozZm8(#RPB4Q_QFm7)FfTP9J__pK^>&xIU1)HyY&B+Aj6n_Ym3_U!hTIfgx(0&82bx_@BgaHzd zLMrK(<}>Qr_M*u?S~VLjC3P9Vh5Ee229zR+YJXm%Mi*Y6n@TvP9BQr?3-fHvBmo5= z+=J#BRt$sscP5G#fcXJ7hJ=_{saVro^K7ii!^5=59Ave;xk7@57ZcwC#Uu4HxdGGy zN5=|d@oCq4(xW4dMpn>#90%k_gsTwO_wU~m@D7J@=?-GQ?6WLTK%)AW4EKn~P|0ZP zM8AQOP(mN%XbZFYUIk>2o8_7~mlFg_?}YjaSbz>5vQBOKY*$s)8Z|22=Z>uX1Qo6m z#*MzKqGylXNptcq<^o7mtNP2&F6`2PMyToYT9Sy4l_Lx^v}LF}sM-o~O6*zI0ot-L zm9fTtx~rKEP_Jky-G!A>R=EfjY zFagFRR_e5BIdgiB+-;|#-yWtkE0jDq)O`Hxjj;&#_nTmo4b2nak5l;WPoF+*X=&N7 z3&Q7+dj)?Y`ui@VPRs2`yPO=klI zySux9pz#-F)JLyy1O52Woe=;thj%RU6*Gw=8n;+DaKYuNJ=Y1!K z0oZ9(gY~|6;#i(W(w3hS0nnBoNU!)PqsxQXA4N8nPYxt=k^L#4+}%qibwBfATHkXY zuxUy5czKW2Dfu%zZ?4{HWGx?XPVudxNod^ipj!ts14o-+evTiGBWQ5HfmIys8peE`Nm!!x+z-X+7r^(oNg1Sqbv zy`7Yl6f__Uw3_DYH-3UP_kO-FPzwLM%Q9`RM^QIz#W^`f^Yu=9^@no~3mo*Y&duK~ zU;KE*&)5Pt|E&$y;Rf{C4%i^TR{`lR0t!LB(Gaokm?t>+Z%+W$?Rl>Ph*-rGrS~zl zpylaub3XVH3NOv)f%vZh(~K@hD4UYE()hOEshXrh)xe^!>(s<5EvL-Dp?eOJk z4BKNdMEO4?s|`8-+F5{=WS`>Al~J$!3gBQB$4q(!vh>3jNA9 zj){@me>1iiZ?a1qo%F#4_IYij6cKA{>pF@j2nZn%=rS<<%!HMtHs71G9c39AnY=p3 z70`x2r;wrv&k+Bm@Eyo7&JGr|SOJO9U^Z2XEw;VS!(!6Nig0}8jyi}8J0}CeAPEhP z+2LY~10gCN9`KH7kheiYBkR;Us+~-JgB^vCcXzU61q2wkg$`_>0U(jPzrWM@y(&i) z-2qB5EIRdfc(SsxokSSk#F_T^vJS&zg{#@~i+z~x@~}$)aX1jM>{#2VegORh-&nPW zm)LZt;C$_o$=puIz~;3ooz6DF=L%ku324anh+usLRnZbxM6W|5nM$gzev5NG$*IKy$VfITs%UZw4G1+$7rY9H0Eu!Ci0DJuv$SX z-fV*}HEhY6A>1fTEsG%Ioj3EioCo2tNwErczrtt#(x1SRCJ)k)&{VNnl~gO}RZ$UN z0?i&85h-Z~aAERNL56UkqoP9v)a_4#;6!XUnq%cwp)J+6O?`pYV{mA&*lQlz;VF!_ zK$X*8?udwbM4V8lk&y(CfW)9OTWuxq7+?@{{Ssgb<>ky*c_0$}{P}Y~IvMn|0d3e{ z`S-#6Nn+m8(9rPkXiUpY^U={sO_4)jO*6Fp33T{gOd4caj+$w_?(-0m+bGy0F(B~1 zJ+|!*Bck&JV*sipIzDE8G*}v@K7n~DET%DLG%BTfAS{soT0|v3&Qr`U=tf0FT_zk& zw>pWWkgjYk{Crvp1v+)p^&-JnNJz{xbOKj}8l(6|QOw$xrQ9acD;|ZRZrnB|E zO{FEEw?KUh$ZEIiQz-1t`swynfY-G3`TR1JRZt*ZYqIXJD=id+a6A5*vX{y$mmo7( z1pcd&mh~}_98tV2;iusFC7_2Ap}Gj5XaKL@-H>W&hSw_GI_=NH^MLHY8v(iYhQ{Eu z{xu;XAsQO7Y9$D;%gCgqW_8(?glv`%6K14jWGYY~;evuLoCKEI%s99W$vB43pnXTD zBHHp89)9lGQh|DnHBbZ^%y8t&(MFT+*{r>Cc2ra)LkB+;WQ2uGI|-ej-T;Xt$QNoY_|RGRo__0re6B*U`} zrC_J$f#QA2UKFfQ1(+V$LH!8k4*(<7e@X0e3)DyU`?DNOOz6sgmq`CJlHmIJ&cp%C zjrV6!DVq%XaZxMA(FE8mW`XFi4RoSOTY>w+bX5qoeL$?b-0oi*c=-)Pf&g_oDk?OQ zp+>hGfS@I+caQto7DTsu4rw|c%oKM5d{pod_!FfRQt2|8%D%hTQ#4%0>j69+P zfWk~};2F{E>-sOj+8)9Bw->(ydP=@ua*--dXQFw)kcgO;Jy=lI%HL%7UQb`{Mq&YC z2)sZgrVotW0E-_aIGCK-Y>M&b9q!pCZ`Gyej~_n(7SROs@RQE2u22G=S`fitjh#As za|??i#Dy9gL*VydGbtqFzU++CqO+Tfz5{L3odwXx37|#Qr`f7TNkl|M443SGA$pDh z9GNWMers4L$^R1Tf~Ni>!)sU|1`$~8!C5j7N!$+Tlsw^|C3Fwhk3WH@b_YoYKyZz5 z|6|e1t8CNPJz7)q)hK`09H0%iFF4X#tOY>F0(i<|)!f;5PP@F&vX|%h69$W|cItm~ zUFYIiyZ)`))N54KC9D0GUfSrFAc)Wf3i3=q;!sHZV5g@N(uLDQvmhX4(<-4s_C{$`b+mXjJ# zhqd{l^qRh$Mn?I2y3S@Mpx6LS?zP4@FJHdoi2M6n-NP(&JUj`K{|=#Eb9^2C=4STa z_*PI0US8bF%F6$FY+9%G9m%bD4Is||b9Q{bmm`}FBz>o|u+R>C(P!nqJJ0L|naj=p ze1*hSnw5lPWd)RPyJds*nFr}m2%}zi46PdbtN(65e6bk%nuVUqV}PWfxi^-c&2qk8 zJemqvG9gHZM{or2$RMe??x2EeD1@dE04;Adn9eevF82=%WU>OuNXPyF6gObdX|De} z5jAz7HzMrR3<&z>NSqG)uBV$ro12^8k?|73l9H0ZoqR$Pkd++*9yRZBz=L{30Kd2O zNgAoNtPDt~oj{9nO0&jVAK0ZH3Fv!+ELkjJ;&C$lW{#BVk;3@Ex$fm0-wGPpz zd0VfQ8?8l8K=!XN8Dq4>G9Aw7=?KKuC*kIvC#$|3qEJtQVE)ga zmjI;1V>Wub-2_N8pi4WB$?765p+be7K^rN+7-{#CB`QZK5DRo%*=E3E7AWS&bYG{7 zgjSkO4F~A%@4Fy@0S8buVZ44F24)Cmu<13KJKsNUy56Ryw)TDX21o*7CxZ*}L?>&c zk~K3k1F5j8W?Ng^-U#9c0fD&<$S2S9(Z-woI!gI0QRX8!a7=G^ceTSo%31q+ zSFhCy-L6+tywpv3eDCMy7d8iGL5M9{KEFfFNBifaKc2kn zd^zwt1svw{?VICmKu;I!5xzpdw0>4hQ%-GdZ3RPpV0I4x7txFdUqW}tn>WG#Fl~_M zLj8WgRd+ZEP;UdIZu#ejXI0nJ07ZY;DL^Kbl$1m&{JZgoS$N){y2Zl89QyP3KP}6l z3{kq4ZwDyI$b3ltv%5hGdU|?R)^ngSaX6S~Ap+YzL2#t%3kV2(0|RTwzgzzMd0?e~ z-~Sik^}o+_!Zm9VWUY}Wi~A#g44TFwY*6&j6S$9le-&^JJ9jhWy;Ieb3v0_gi2yW; z#XIz>n+ab^6yv{uEa*{`v|Q0_;0u2T`={d+YsWmQe;-X3ZY_8IqmMmo z)4++Y`1z<0M=%d(|6Up#6yR%I(-`{J`hmN?%T^Ee+n`7F_p`IHyJ=_7+|JGah%{K3 z)vTd4>KsmEVNMgoxs4JyntGs_!(a)Bxg(S`G~A{DlN_H>HMy%Vp1*z{z;mkmnm-T1kYWd2==Oy3n&;J6d&P6gjZy<}6 zN@6cT3IdM!8A!*Zq(aQ-KmB^kz`(%A*90&zfu@=6q9rlFIAB0bA8K+G0D-^5Vv_FE zR^8yxQrvd5nnR}kqPjsyQ64`I<~8>_-`X3dRmu53^9u>7dOk`y-8O>2Ho(E`Ba?u~1Lbcq8=&>^M5x5^xz3FmeOP(~PLe-1?nj!_=Z;RMk zuCiqY{a~Fe=Id4LqvAlZz=8_uoe{7UU_?{m8<0a0(bErpqaY^-*)$WVWc2 z%Oz_82Zi9W{QiBq-k+#cZI+Rh1pugWfCdPKfNTn=ww3ymSx$~R^&F&S9f@)fN7vV# zAq-_e-wkAQ28M%W;Lg(DYsnU zB`5DxlcN)~lsGg(8V|Xxk#1<=LtfDPP-GEcs>NdD@Fh+}_jLvB{0!Lhe9yO^Ose8I%XNE!}gdDS8@>bzI0=toS1u7~^pa?q<+FQT=mWf9CMG3J4y$`Pq7 zJ;U|((#jHff7k&;qll0w`++15WL#!Yx7$enb`uHRLB-Mi1%?&xJ@8CExD!;R@1$>a zrv&r+DeJz*#ieSXIb$S}h@sg684*lj215@gpJ%OQs?k!cn<2Rx6T+4ysO2RNd>~-T zhfY0iW){u?!Sh%dG#ZidKn~oqN(ycPN|8Q$km5lJ*k=#+Pq0U$(N#sE!blJubb330 zz4$i=1H}7fhxHchxhpdQn8`$aWA^lS2(4OW6teG=1{`=(NFQL)cO4pOff+i1Ar_`E zV}RD}wnwd;ejUzA?wM0R1XyT-u}rfh;J5%I#Jp)>sg_s(fxoAeSVtCUn&u*pdm(}a z4fkVpZ(6aFV#1a_cJ>{Vsk3t9c^4wii<3!-Mb$zL(%inD<5VhqBvkN4;~mda4uf`0-=XSqmg?R<(84-YH`x5}tUANSE1DmYgq74B0Dds6`0bCCzjX*PvRCTI0mG(hZ8fhL# z^{LfMfeu^r1u=9ka4Af?B)A2z5B;YIZD6Qlml1JNEo*+7m7ZSuNl^wR0gxf$ooA@y z&SoBfdfD(Q5-hWiuP+y={*pOpeIfkh+dcTyaN{-K``v@1({=4&RhOwUPo>OYcnDzf z1rSicq^ju?%g)7Qhj}qc*Q5!M`!zz?eE-W+^19^#>9A2M8b$)jVERl021#Q$jCh zD@>JbY%~tX7wOz4etmAcymVyhdhZ&JGqf5J#U++4hac1uOk2h2@uv)=3bx?6eQhL* zR4FS~1W?JvERTWthN$0+2=lltiO{eB(a=N(k#0}D+WFZ39`w=>X}Q$x_1DlmVj1NG^fj0{8Ykm)4b!9FlCV5VoUp0oWbdaLV6^VO{en(M`=Lx3S zlJ$dWY}fNCLqKjFyB!~aH708T<86KrAo4T;ITls?M^eHfadVl|6 z!o21e0~~lOBe@;0rSV^GWQaq97yBWA7Zt@5f3voT545RcXM^VdqROMFr$BXLY-~&x zHw`9ecJ_Y6g5hf$m)8E~M8MC|l!eaj_+UZ~E3jgkbTe9~f zXLQ!bl>VK^igWVGBzW=`cZ_%fJ&+xxk0RB4`cGa)S ziD?CDPQD2|>JOnP9@kppJ7xETC$Cs2YdxaJ5dc7I-l2aJpy2NLyMH9rtF_D1M~I4E zYi)JAsZ@ipW;MUhEc*U^=De~o%IKYBbaHwb9n~?(Q%XHCOvE3vbzVux4-FW!o_i!X znED+f>#%Cpu>rM$mXT+vQoKH$K#%tvK?iX^Bll7d2swb*DPA3X%SH4jJDLw~II=^8 zbC{GzgVi`?${X1%-}>~p=ph8ziPdEH#wX>K5?q^5z|DU;E%Rcudb%FzP|acf3U2KW zWOu&dhE{rarm9$v30Q+F=#NO4{RSAIb`;9YTwcy}ci4skT>-uVx8&H2fee&enw{P54WDT;lB!1jMl-CqbUcf~O=pF(Jxm^S#My1si z0K58{&@}IZT0kyAGuJaTYyzU1QBKh3=H|XF8|1~~vM&(01z!--L)S4d&{(H_Z`c=y zij93CewW5rI$C3zXMjC+^Q^GG|Kt(sjt-(=OYuTsDygWpK_$WM$y<5L#3R0A<<-V- zqSda{As^bE-5XzF@YDAg@QiwPDs(qx7w4dG=6-E4Ip?f!t-E$F$(vMlJj)XSw$X`AMuc-!UmqVuFigGl zlOGY+TNxd7B%3Zb^zj&5#(PGKmAAXEN z!2KmBs_KhxCv>YRimGm6`V=+?(DfJ;bwjv@6<}<_gKN&sA^#fiQvkq6NR8zw*4gb~ z0ZqYd3Vknx26?JX`n4^@uuoUbhkLELpfd5oaK>i)~|FNNyJVSQFb&?o%W=-+@h| zH;pdbr=q;+*g0AuIZlbAgn0Ry@}s_pGgF=orLqe%-u z9-`?WcZ8?ffNv}5lYg!?J*6v5zY|AEMRg6Z0dR|Tw0l6{N+xqw2nMzEJE_iQ)7{nm zEPU8-*t^$?{c<5)Z17O}x!a@6cUI%r!7lIN|6uMtfTCKvu0a%Slpu;CNdys)AYh{e zL6VYl&OsXx1OdqzL{y>(O;WN5l5@_WsDQa zV{^_E_OtieYpvt@Ey}Y}@W8VPJCT!*?x(~HxN<{3<2V-5&qxCgET~nM7)Z&L4wQPj zBe_C=>RXL<=(ixoG)R6J^C6<@hiui4=JMscFD8Zkp6Y!7oQfBq7pMiLf7#RtTK}qN zH6?tY-l|jjXzIhJfpqwoIjoPlk_iufXiyn?iShZqxy;NsBJQ@^H@94&(?=G-w3fV# z4tg%b2kNN{OMCf&b>NM(Jf;1MhbHllg=&v_T8Xylc@IwIB8pEe?pclO$~_*+?+%{b zXa9N>`E5VQqoJSg&f%*#_U8h~U|rD;M~akq+~j?Z7(7ZL!K35Vba+iiwOgdBbm4b^mqJf>@0|W5iOT#96LOMmnd(Ds&X` zKth}|5!Dnwm|>fqm(IvIG_F3LK9x6i9W)Hd(xiK&(Pu#3-k)zQ<67WkZsOzMs?`*z zNp^qYcz+>>eGRZSPz!0kY7`bcXgW4*>h#bdG^E7@?e2SiU)&b@?G2DrV4Y9@(zP;f z4M^hQ&iYIKaklV#x_n97FG=X(nOWHRnJIXXIdU}$vumJxAyUx9cgVPKdVlNNhg3Ul z^L3}-LHiJSsRqoL?G*XehI0C%jdA#CN9g4M*ni<{G4Z*zlAiDpClVDnDOY6L465CR z%2fsd(uDxTo226Mpt+ZFEE=hqt7RdSY4wdbI?DsUufXHmcT>L_>-c@Sn_M>8Q8iL* zL+MYm)JV0{yEckmks1DQjEdND?B1Lg7mp1<@?J{o!wlT)9oF05tL?tHbXjmE1Mj9- zgSmChU0sXwDl!jM54ym?h}!1f!>#CaJldA+KHk`(-wbo_caFZe8`iWU|gBs)Lb& z@k3~$t(BNZ_(WjSz~!h=MLNj7a=2t?HLutmQa%z%M}b7W{)oH8 z7Te8*(6~;#Ubb0Je(0iMZYL0CnsIe{jB&OF$8#ZVA1@;duh*-`>?_I9(n_^rja4Qd zrg;J^1oq`rqPL&@JpRTa&_mnAZT%?FOLA|XdQ(4f(sSdZ{s&2tQBUbkmaB%jD`Aw! zpUv*8=ICx7aP(Ffm{ZXP8L!H2DVgX!^t$$ojC^Ins~@8AgbyRSxc2HLuo<#PSa zE#R~TdE8=Cqb+#97ubGnPTo-y^q5{_hmtGpIVZKkDVg!xMfkcbOQ+sZ){ zcbjUXA}aw4^7TD81l<>jmhVVOt$jz^>OGo{g`@F_TZnHp`|;b;S(xpvcmTR#o47rx z21pzrHbVpPJJ267Ca*f$w|Gku3qr1P4ONJshJ=vrFWSofb(YwTv@gmA;1k-S9ouOt zDPZ^(H^R%2(aK&V=(d~d>kZ{M-<82?egB%+?9m7vWS1--8M|(7*gK|&=1fWyRNgVV z0>r$lu4-xTt_#{NM|oJ%CO$B&yk70On_2$i(Zb46ifXfnfT@I$W9?%u&(GWlq0HV5 z{IB0lNd+Cf@r6?Q$^hk2XTZPq`9fS*2}Y%R%jGk=Lh{f#dh?r4gHG?4BNytVKaXgr zybCn8bWMh2if?}2EC?WaA6VDfNePnf2j9Abn;3Kp#kl4_YZ!ENu#OqdL9Yl9-Q32E zbHKG*zss}VZ8#9EWCW9t{~Z@#=i;}e0C&?dFeJk!5IWukSfh3XIk$FeTRPV40eIE* zS)20wgd+R04@cG!z)3=aBg^k27_xY$T+-mkNC?<%er`06%1jLpoVb zRc1oU$9LyWF2v>wX9ZtOzI+}a!MQYPl~S>28SgdPWS5BIy#m%FwgR2 zP**@5Peroq-dYliw+Uip@r-#;K9 z$uB^Pu=L}TxBFRz_X8_2G1tnj^rb3I0oD|3ZVSOU>ys$m>E9%3Y0Ama7j*)3_PRlw zHg}`&74Kd#>282;Vfg@dHp7iQm|U}xA6wNN6>Cv87h>c0yczAMvHauf*s%@j{fdT%ZikP{hhRyJqxRg; z*)7*uqXrva*4?da4=s@jB^QRoJOcZmpJdl-_ICB(dW_ZOozokB=W1W788*K}!=b_F z^yT_xHH4K!gdmv5p|5=dLl~g;RbQj(*E8|Sj)%6tUDY|QE?-~_F6-48wUF%bFf+H1 z8BQ*J*xbGBs+B?+8JQ^|F79#{0qI`Wn5>G7edZAL_q8SJpUBUVPVK1@R)Sy{`0G}@ z8(l+0O}F}XB#o=N6kx{AH${^DJuUWIXfC|R2nkd-Jsz9H{OKZ>UD+2BFFC?2p8vkG zhat4w>I5vuNd>?fs)tWP)Mx%sKcTBu5S@2Eo9CzPHuHO4tFi=L^eZywyMEvPc;IPH zV9W;hL~cFzdOfngbOur`ahvpoMB%-?eVsj)wIKN)>_f&n59>XA@$SH-M6qpE5;;m0 zDJ2cKlFmuw>qtMDy5Fp!39o(g@*)*=Mf3%!5554ScoVDxV0D)qs=yk8SIRst5nKVT^IKn=NK!9Zx4l+TTakzK{4J{JZY$33>cqD8%5UCpqb;Ni*3m?MPf0j#yTnAg z89iD#et!NZ(G7NX%b#E00G-2@Ty^8=E9|m{-e#ppFKo9b-`;|3Cz)CIUERLtZ56}Z z2a)9<7Sj8l26 zaDrMwoB2O@9(?t`4@LCi2O0=~w7`P;do#5rq7T8t!#{?dxKTJAK%-k*EuEcBShg#8 zWCTf?Uh2-v%QK!Nk{-iS=%tKjRk1&L`Rj&_w&<3*6(OKFPU_fi;V3>Am6wo^sM&6u zgbZnu0sFmLR`zsAk+FZU^lklAnikz2?Io_u$rSO5fJ02YCfBX$~kPNo98SS}hzW36F-KU*I3+5kor&o><| zoWpdEyZUHYFZ+}$phHJTM?-&)((^dS*`i|?7pqhpil3qDURvCKa*?)nGswcfPW1-i zxr=J2y9hs!7|LE!d-#>S%hl>Msf&Rb?TzzNGN+4@%a^T?>vu9aDbHVISvfd7{=fy| zn!6M2`+s(_nHPYwX~vM<&jO<6!Q3ax<2^lhd3itJQsc~rlBWtL5b`>d@d-G9>_yh!SAYP)T&T<=tdw+QfH|*zGf~#QO3)8Y-^Xj93s{=6O*sccH zM1>gXxlMuy_4xSMrdsK{6p+kGb%Hs~vU4~P`Loc|HYXd)F%a64{j;=0O-038JV z2c(YqobWJ%N+)YzmbWw9sstvIZ6>a;J1K4xyGBaWG7uW=0-=(z3&+9nt!vwm1ODXb zJ+KUJ-G#gqarP{;aXmhOH;lOGO_@{E-Chr&VrKczA=? z1sr=-!b0kzsD*_9ue$5e*(5kPNGIoNYnM0Wg@vl$ui5Ai3OZx@{0D{>AT$|}6Cs?sT_Bg2l zsK>w6=_HVMx($0yo-I7a>UC{xEuh{Ppz(cV;tjMdM!6`a_orDwYA#Y`*q28B+Q$b_ z#ZqY$ZF?-g##Oev*q*K{zAjiu>~{?eXq1IF_i6i$Fm(#E?(XiU@<^P*>6JnLa418# zJ};NX!Kt5|-fLXm8l1OUg6IbO$-&W4qv;&rn!rztkb*zxFEXd@@67tv!Sp7{g3@MV zrt@8ZmnsA4Fq?Lxle07Q+?Ze?Z~WnxuB_B0u{JO;u-F4LNytZEsI~YUfpu0`}XulmO3Ufl{ zf3Ap05aB3>QrqK_;y%l)uNQq*ghrDrUc{-T?KY9_{1_aph-)c~z2@7=H3dVr5_-Gfns&KX`< zq>k0NyWNp`VtrP{`|;y=??+kU`4~Xu#vJQFBW5m4d=d9M4}_UhwfwXK`J@k=R%!Y9N7N`j(w`kKrlLi}SmEGM#*n)m@6D`KwE~6b_vqsEwEg;TDdyEK z2^zgJo8;o;3-j|;I^*I~AZXwO9nB55OWE~;ghTf1g2((I3SGn(mqPHuv<{Lg0WUN3>UX3P-W6 zL6~p;3K0mcV8KID4$s#6ryAH*%B74{t$id#85(`g3)$qA->>!^R%d{&R)hB@lWLi@ z>H2d&wh@Oopp&sMF%46Chzqt#8mC_g{klm-`~_OHMZ_ zqJHw7pO;OLl)QZPi=VGbN_K#SX?8rwX)}!77D+w&H6B$Vqb1wEB1=+lE_s_3*mjCZ z?RV-|7VNy}O}EFRNin)g7RgATEYn>3`FEh2(DhMI`u)*leq~ww9;;qg|A2t-8T`Ob zbZ~Hj?vp!~=RjxcD)1!=hLq^M@#xVbtdu2NkH3OXMp`<8!+^a2nlLDkbiAh#a*)mG>FzeV z1Y{OR-NcN(kqSqkg}RT8j=JnDyMwnjh1OD$y>>L@6d+JB`p8nC5Y5fT!=oWVXot_A zHHyju1x~RC76Fg-_gZ5^Clga~%U=CCH<#9Hn9ES~Zl&=0RL88{xW@a}${6R7Tb<)1 z6i31op_{yh^jEW#}s{E-dIgqe-#>Rl-MYb@eao+2H;PWbtkX z2YFUMU*BC|4u_Qi&8WZB+R*+JbS8qYcSsH(aEN?DXDrPoq7vVIPRZ_bMFt0{+NevJ zF$AcUkNzh+=uZ0{Cr|-lj#G+x0s{Tupk~wM%A^`dgTkaZ0|?u0w^9s0vz#v#)yTMI zFO6m^*gZIqu}rr+=+n_jDGHB_1P#Tb?*^P!DAX^YR3&q3pb`uQ^K70#_5}xb2)tb2 zy~cNRkjb?vo!?7KRltw}+xsD=`_4d`8hR`1< zTB>UFxbZMpWyUI&&#}kTqxsNS$nQK;Btg=LD_;oGcRt86&XuNbs^nkuP^&^ER4!dX zI+>to$3!6YfQ-m~UwTd#>N9(w&y<$(=Dh+uHPt;aLr_x84BLCQvnyP;hNBtOFu4nh zG3w}#ADQt(;^NrPf?TK{PGO*lu-v^sBdDu&>ZTqQ&b=2rsp+J>50Sz8!%JkqoL*EV z%*+`NqAUA+Mcw0#(rj;94=51A*C7qD)x|25j6^`Ipmcc_NJfjJWh%FL`pQm;SGdgQ zOtva0Nn2`H71^ul0MUQHauj|geTxGFV*d>_D;Xt^oI#({*ANWS>DFVPeH0 zODRza9%C21qpo`Q_NwmfLgQ?9GrTqJVO1g+w*7#vR_YL%IS?q8IR8&-KX9|Ig7_yZCGF9PR)%yaG z1)B465`=+Q)LGyA`8fl$*2d*I%Wx}SxF0s_ezq{Nq+ zn%moZ9US(nQXuP0gdRFH+xb~o<{=B$*Vk8@AI3>|QZBNUS*y)s#b6^V3*O>U>nyEA ziP`nSoR4p!Xa)90F5-HdFBEd$ceV!^8RT=yGt+I6&_w!l6M-NwZ>a5)QZyjcwFtRL zMpgpsI#^Pz%qx&&H#P{5>;`SAK1<=x_NJcC5;gIJl+4q^m+4dq376*Y4{76BqH6Aq zFLnIPvj*3!ZvBBUef-;_KbqHBFJFf^xX z15XQUy?G62wl`?Nu&EkAXa<=GrdurD*mW!%6jRBl6iRJnanXBqbrljORuy=q1Ry_& z?w-w%R`!l`K(ylwu&Zosg2T$n%4%9Y5lF5y0xqf)G^C`-f4&SesH+jCmlVsJha!P* z7HRvA(*u$&KGfsfTc|Nwe!nN3b!(0lz zEbpsZKc{4rNb$_NrwBt%iIo{oD%muAYYOQiP9i6!;W^XY(~~^K8QsxnqI6v_8wTlt zn{E$ka`W0$dQN+LdzfIC5hwFh!xe_J8raEgz92OX;5M)658CN|S_`sF6)7#Pk6|Is zDGKqH3+{9`liyw!aAD%1q?m)#j53HEEcVi2-J$tev|NRSg+V(Re#;NWi#;@~Y&2w6I`%sVA`fI#=uC^W){YN z*4L}<>#*9^&JG5mGjv66u-ySeI$~mCs8x&tMDLD{je)rWeG}T)*~NuLquE}&``J`Q zdXwbc@~D9e)Aq?TH&>SVNvh^0Mi!(QwlwrLSa8>^`^vpti6vsInir(0@LOx5)u!x| z)m{yR_g_W+m}9*Kgto`EFQK4o>7u>A4tT917H6Jow2wa~pad(}c;GK(COm z!>v$z#-sq9jv+ds9R9HNS!&1>p{%&pO!A%AuVZm-jqEOI>HW1lmQ#I2!;InMu)hEbX z7U$%wKp#PtQAJx@8w$VZ=;%7U##1;KaqDsBPf>jAEaW)-{Un`z!E=#>grxmx!FrS1 zE5c@pt+H1oW@mltDn=K>!ot8%)z!(#mt=Eg0`p5O4tW}<9tZgnA?jSV)juXNV8sCG z?H{!_KQ01js}#rcVyn8V#1ZcjN|B0(>g0BD61)~fAPJY2mL4U5`%U)@4>+k^d{0qx zL2myNGJIMDwgC8d@{9}Lz}7-2Y&r3_(E0Bdi!2R44{cG!&3S(oCpA(MLjgpq;>d^p zE#A#9BS6^??WWH95@3=@!fC;n<_C_!|8hmEh z>LV2fo+;&8!O%4_GDqN52HtRg>fqo&q=~&{;SR@MB8`6lLqJ5afBsf!Ft{gw6aJrm zm=L6>uOAm4Zp`^{w<)pw*iq(bL0RK58S%*{q*|$iB$ETBsI2_Zy!V+AajOT2U+RfY z<_@Z+z@g_6&(RL4Jk8@_?$Z4K43;WUXiI(3tNquD9gv3%pTaH`K(?x5-CG6E3KPzn z{LpCH-x=&L>VC_Bz-q91zH|V^OqQ_+s1sF{m7wEIl7*b= z;BcceL;K0r9~ajx9GrWD8!A3|#ZK;=1zDKxAwExU{f{DdGldq@hm+9C3+-I}n0X6o z3ZssW5|7p7t!9RiU2*p;GOJt#7=zR`i`DJzaqwB#M{;u70Nw=)OIUzcsEFD)V8CR< zVeEaBz5qs#uY;Tn+n6>I*C7T87KjQpiDvAHz#jx29lLAX)F=26wp> zp#1_Of;}Gt8(LPT@=*ZpzowvbF7Zj`t_2E@*i5-#0f1D!HPS zf+^V|c7L8H_$z$Tzy#g8%h2yRuX+hXee6%ngj+CBefy%#Aa`|AZ#nJY@biQvzHhlW z<_}wCLIw*v_gl`H2XHJ#Dyu%9Jg`hMQ0?{Qx?K&TRb-lJp|i|s~jTe z9<=0UwHH+Suilrr7Et=c#; z)*cF@8}$vF%9?95Jcc^U47sF>-l-@n6B8F_q3Me%Dou~j0ohnOM53)C2TFrWH49G( zwm!?IBdF*yshfrnbn-eAG>7Y!bn#XeQ-;gha__S~lMRy?bItUBOrrBE<@L@C*A#vB z@iOuvQ7-Ep^LJZ4O2uYk=f7m;daS-F%1uqIoEhk6Ey>jCT#V%0+VO9C%DE0NZ^Ih0Fd?L4A)lqZ zZ({^I!)mqP%APcD|+$8t&MI z8d+-777>Q2-f6pd1Zzvsae%~r}<9t_bG?m zwbxjfD%7CkF;F0+vl?b?HMtxcP-kq23SQqNMe@ElHs0eB(sGp*KUv%P+zmJgyqqnygAXi}eL(P6oz@-p0XiydKYdAO* zS5&x4N=ky-AS|R6(1{|Mfi!g;Vmv0C7alIRP_*}tc-k!9<1<+=RkPi#e$ip(VR=v| zxDPbMLdUsT+4OXBQv;o_qfv*F_v?ZxZ|)+Cn~3e|X>X2f4{jbASemi06d#*#%%Bof zv#V{>lIph)UqZT#XP`+OlR@q|*T{;xnB<&1;p;pqeMY!RXQu(&A3UMlg}4vGp|r@z z0nlFEz8b)p2JqpXJFC#_K1V>H!np;KR~U3%T{>Rg!Eo}y4tt2B;7b9!w*_m6w6yDg zL!)oF4;QC)FDg&3wCxwg53SALZV&vBA39z#&Op*U8~?FcR{o7S$ET< zQ7`UwZ*$*}Y6{nNn`bfiu`ZUuJI`F4q|0awu35NGdQXqMlO3QLEJl4*UT}4f4e+9U zc694zW|!mh9XUUOG-8_fdPc6n+T5b5DI2df>LQkOWK_b$t z28ZHHgolSs!~7ldimvUOo`TOTMmx7#6TZ^vd^t9#vKVq$9oHB?la9S7Fz0C-z!ap| zw*_E+-e%4_Iv;gFJJQo$b(C2m`(4G2&G~G<)Wpzr$>4CUl7n!vl;Mu#%Iv~9oRKY} zr3Gn~yB2Ne$_ewpCFl&0i^deo?GI!ZtMh$ZkUll*^!M1#DGIB02`}F`GqNOQb%vVi zN&M*_Yjgl{3Qy=)kl&x!CSN-e9U*w*F=%}7)1c}KHrc}B$1(Ag_$_nAo|@*|KfavN zW7O#q&*am`<^UIQ|8wrsll(hP_~-OKNfRXL{*xx4CI83E$Imi`rX?l4KFL}F z0|Gu%|0|mj?B`1zB zn~*b%%1NsFVjaGM6d2xd`WsTzlbp4-1#&2CVvX}M6c3xtVw2Zf#8@m7n-R)i$Nn}f zTp#lQ{_#m(#`}Nyfg($ny`irTuQW6QGY3B7>Z9!uunbqXS7u9sqXG;kz%arMy1H-+ z304w>`dA-9NV3B1$|@@lEduHwW1s1W*67Ph9oLl)u>f;?6L`f!$L$L^e}Ac>Njf5MS~17pb@IXO8~ zy4p!bc6N4PxCD;TYE)t~@X+94!B#^a!{ zWn^UJ)04tUwT*e;Xxp9HAwM;nW{$mOm=#_T&I3r2T591vV;~Yu7?-1eRvyUnQ5K{r zN;ZyM2Lm6IjDh6|N)4dO=U@1R0K_arR`2R9ztU7OsNQe4O-vY=fx1&hPLAl@xj~T3 zMO6SsEBDmx_^@nDHwZ;bfJOt>4_(2V;(<@YAB915%1D@!40IO^1Zsy6i=tBCW0TmrfZEM%v`w$?T_K*kUjOP)G#hV$;-n%!Rn zLwu|yB&T{+cv9bz(ju&a4^OvweMZ`n`ItLO*P>T(n^5@p{-!k8L^O|Fk{kQ(rZ36K z%rw{+%7Q1caduAizVyK(d12v~=p#rl9ywb+0X8stO~`e-{h2=pH`W#gjx07%mjX}@ z>qDc*oxzcZ4gnN2!0Z9%VV*0E1DBf6vqOGfTT-dUR6H--~_|O+!DcGp{J{l<`ia&{f`K^>e2FHM!c}u}V#Kuu7h(RK9qaFyXFx9D73N&xST2jPL zv9`2~Oy7u8CP%gyQzvnA8P?g2f?2Apos}W{z0K9$OStyz63BDJ#2P}dC6!%SL-yks zv|vT6Tm#II0g-(b4`RzWn*6p-@olk39v&VYz9O)$?Yf4qA9SD%9)GN2lFgiyiqfL~ zxP4FJ;Sp14J<*@r_)~Fo*x7wY{=j`-RryH;&wkt74LF$hf9-6+`j$em&7^=V61Jv( z$FV(Q+5?b@!q7rox*Oerc01VJh4(+|Ha0ajVqaX**nA&+vSe&_fJX=x3#}iY15X#5 zuS9+(myO|t`b(L625j)bAyP(OUY*hJ#_ryp-#4JM_+fb6cL&qRXHSAuB?B_pa(-(e z?Jaqw#Wu~mxO?Wdi|?G4ni(>7Bu$${4FW<@ctL9`q1X{7Kn|8z#n;r-j5UL#395qP z!ootZgoE7)f?)I&t@Q&)qSH=d7DSs5fUp_OUuKjYEHaO@(NKUv`n>=9J^ku3%!v;NJT(Axu0G+oTl`a&C(LemC1o6@H!IAXI@ zf32)cfE+3LDcp@S`YBA!M%`4NIOWgUJaXokh`0_V>_LJ(DTTk0dPDMB`mDL5qo~>` zCWDc$}QX_jHk(`9@Neh^=WWI9S~Q^@lSpBM4mUfgVxRRmK>p|*=2zjYSEXFFWef1OLcD`nE&||@TPbTLR|qj zH@H>tca-n~HU+sMLlg?|!e_dK@P14+MB^eOH$5Oi}IA*CEgr%#U zcAai@UdR2L(%dse<{r@CPE&YeUvCOv0yKdE;r=1$1}d4slV;r@&^N$hra5=)TN7tK z&{m*r4>Pd<%Zm;He4ORwWz?m)xjE%_AQRoY*SkOetqG>A42D%%xx4-2-6CQdeh9_G zi;CH}^}6qS$h>DW7)OfU80KBGIhiOJMQy^x<2_zpUdU&f(9Rj2%gf*)Ff)@v7#S9J zTd#Z*B-R@vBhoR+phW|S@qd8facTNjUC?)>m;m|@#4J{x3(pKRSUl+ZxUI%V zm+h0~AyR5bQ=dI6W_$Hb#|N6k4LlR(w5OQ88*t*0URlR8`PY4D63+7gSnFY1;!g#^ zrl3M46^3s=T`KdjS#2?N!-nzyNnVkuGnRKulm>wtK$a88`{EuWOFw-c# zrVqbh(No}|DE=#5hUC;xGX7(1>^rbxg92Xqe*!8YUB%{^*gyXr;!Ic${tIE6muUwq zQWp%hdyb#_oBURa0i;Yncbl2{6SEnx$VJD&8p|5@Z{qy2fqc3C6{!NTm z)$e?i)n!d(ZH|N9{lANY*^wcGMGlW`JR?GWe(o+9f0+Gg2&0eseHl9(_1w)`9Y!u6A|kXEgAH_b zMgO@hc_!?*05SSfG}P@h@NJ?7-)3gY-Y>BZx^?bVs<(LS?YYlvn6QfyiQHq)Q>$Xx#Hbes+idbnXGAXcU6>P-y61(xF$yH@xmVay;N&84 zLilIcV&R`>c}06JF(N?Ze~oaiCk>=187wqVsYNsJOzhW1_TP+zk^=i-uV{VW-auGL z4E@>~s+`zg$SyY0o>|JYmn3X$%_88@nnJ@k{k`y9eFDp76za$!W6N024X3o%6;O*;OWJ(!VwAHiZxnl!BHnL36Y)3*TO8^f#8B`SI$<;P|EIcpd*`|QXq!s2ewXe2iq_m7Z_`H=i#GNxjyYR+5=Sp1h@UTaqg~%Fn@e?hd(O3SbIgiz2vPdS9 z`xV5Yn1fSJ7?#ex=YPSscJ5$}#|Lbf^#Hc-E>B&r?dhY$D5PdFpH0NDgBL(QTC>;g z;4VD<7jq-KX5_TP9DV)yxPj8{fL>O~6sz=A&F5rv>-a2WxFL92t$P_9CcXN|=9Z%4 z@_?;B92&Sux#w!PACaDYctImjLB6DqapVma=kh%za`8-;Fmz%(%#OlKmImzJ{PgOl zm>5Bb5+7$Buy)b~*fX8vKN`SxT$UBF;3~g7nLgL)lb=eT)dYA_4hFg#Rp>SEi{b+VfSv>udHh>5McJ z3)>@(FvZap!VM!c$>gO`Mz;_(%VurGMIq4!$StEVIY}dN2J=Y1hHHTVBCS1jd|rOHOBGhwvY=2|8e4~(af)Uy+UFya`G82%;at6zKDw>RV$vFFZ-;L zEovRp`V5n}w&Rv|c0)vp$qrIaWGv)*n?>7q`3qK8!rMLk5OoAxc{sBUiq%5`zYX1Jq4)t3mnNI?u6n04sjy#A6G- zT8E8JvI5rUBGGj+^Bm!af9?YQJ@Tj>TIVT-&mHKeCTO0!jwdXt#VSHWx$oGO_+TI$ zK&g`*voiZoWc^ax_nNeeFN1~hu069T<13i0 z+a@k*VKtXT7vT599><0u(JJ4>(`^c#Rx+E8$2DSQ3X3!kN=vlAdKg*SJlQoEsee2$ zv7o0+SVdtKm zaixZdqv+0NC%sW^xV&aIUiaHGD7eX!t*r#e>iPmcvRN)oa-YUB_bB$`R6P0XW9P0a z%<=S)_iub;=>vam`ir>OZXYaG-*OJb41$T-BX4@Ijo@^e34!C$ibm$-3`Ql)VRn;j}j?z4qEfEU1QN#synZ3*5RmTfd@81MmDs+d{`YWNYaEwTEnTVc zFIXwBUYV8uSv|2KNSF8tD=ERo>|X(D4Mbe|Pb;c2`#w-R%>lxK4g zEIWL}TL1FjKXze9MBJ_N-?$ra{m}IOSk{XjA+qIN0-eQUleW2KG2(twG9#%||K%Sb zXc7DGnQtOsk^S8Z_h^w!%`DQxI#-U~v7xtHCI0KhHxWMCR~qDtu34&)uczcZczkg^ zg|nM`PLbfhT=jNCJyH7A)tgwf6Pt1*p7O1$o*>hUR*G@X;yuvsT1t+%nRN;G-;Ycg zNG^J4uGDT6P0Sn7Qf*R(G&q_u{4WpfLe7y*tjnd!yOExC=Nlm8e<}T@$j}9(48gk!Cww{`;K0NTgF-^uerkx~S@+ z-kMj&zzQpku^XG#x7D$fx9^UMFZg*SH|Luzby}Zq$*HlkP;*#X-G7&mRe3$2E?U52 zd@*kaK}?EGqalD!zI)UB(pRK4G^NO*VLpbuSC+qWi1ZO5r6lSd`MrCs8#JWxOKRlD z8gE80vle2z2Jly<<3;_Yp?TQkV1W)kF{Na{cZS6OrxSK5c+UrTar*?XadNfAd=8v& zT|G>=M4(f$LviQ9Y=5j%vMhM1w$gYk|FBJ$n31}ilH;c!YaJDNjh~duuDyiQs^-&1 zr(WeJd1;q0KKt){%(MlaA4hEqt$YqA&FFW#4vbLjhG%cn*(3vp-j`oM8!!&M6h=2 z?M3oBQX|9r2IJBL6T8d8gl09QnhwWHI;yATnqR>XYdjfiZBywfSP_(r0A~5FIJee+ z;iY$-6j4qa(Bd0fs#sgMR{z1+A{NFOP))GJZ#3Swu*1-DPP4MemIecagQm^ogM=Zp ze@oJ%CU(!!uAOmjQ3?Z9qd6YCI3v}y^UUZMp7&k+dcP!bpe3Y>=|3hnD5t8^5eT?1 zr-y}&wngM)IHk^O6qRW^AFX$v>$J5sR?DeZEo}S~eA8QkUG;4RaZHt+nv#bi2E0j%Z&7)?qI5QP)j`#FC z!S&6)(?fp5Q`cF~XGc-99B6QhM$FQbD!ok}+l-c%s)&DTG^d&|A-eK=*SaWg_^pjg zp~hBi!N^&8f_A;aWK8Z}Ubo#B3Dnu8ii0u|+@hj)zFrwt=HU)_D8;rsJ=WAqtcr=d zx->Vd0=?|eEfAuPHU}$`FR96fKD%6gr1)Bu_=JR(`y?Bld zHFeQfaJQNUBwC(v>f2oU*jrwu@UZ)`{kA3U(^x*Tg%8!4BW}V+ytc<*5|VGU=HBPO zRg)l0F`l>Zn%nQ~6y_S{^;=N*?;eRh*P zN0%b_i)oib4BAXaQtG3a)Fb0diB}z$8B#~+&O3fDnAw*rS@|JG@guEY@^atd+UJ5i z=|^+d{#lhR11ziu-U>~AY)n(}0ww3uS&@p`72O;;-}g1_9ig8VQ{svj66)%IT;8qb zFC!Zb2(s+s|1}DKWS@!Ut^p2|-P%mg{F3Tq)TplF+E*IMaO%4|41M09=b|SgJeo@~ z+_#xuRNI=`UY#=QjtJd&zH@Ag{u;FR^o>cRlzTN{Zu9NQzD{t)a7=b( z$a?-TwX1w+yHwOe?j}b2n<(fuWt~S2`H2Yxn<#D8j$x%ijKjka( z=Oe{g02gDGK;RD#s-3ph*75mYSZ_fvW0DMlE&=E{S_VkHqY7VC9u5`HAMirXBc2z-yr3g1Z*C1rqpV3`jjLM76jYKJB@ME zByorDcbhh+XIq%I3|F_meQRP<>rRXFo(YQDjZLyf7cLFjC+62L2g##SRA8a;C|3jW zWHHc!PPHK7XJjY}a5Z%)y#KrTgA^-6UAf1?r!nPgDP~jiTL-X#7zACqKg|Fg;+Kye zrivXkH~(VG=Y<}!^fL#dkyT?uOouYPEJs}Kkuf^6Muj!CaLz8Bt6P-I6C3g@9^Drh z&TyGjV?k)3mIwL!W*O8#x5trlT++9@oVtU8F4kK>LBUS0(}C!R3Cc|zSHg>l!lBIcE%LL~LV(Dh0N3k<9QqGD=ib_V37QK?N||qx zy4%kpm9DyLEiv)+tN-Yl&%1*{zp)=kHJL>_Gu!fYL|dm$zC}wbbv|c>!D#&F(XZKp z^eo6O&yK|DPs4b)G4e&OPmC)pJ-W}`ojKdq6cA}eL{XJA@xyt3<(D?{N3r)M!^Oe~_+v(Sx!u>_G zUDOFW^LA($(}?Lje;vKMg#3Y7FW1JTF9$&qJU%`Swn7?0Af3HH#hnSl8@aweOb98V zLG(f9q|it1NtzjtwVI_y{>EMXn&JCfR)vO~+{b<JMpNrneKIM@5fZki|}63)jbKIi8%p2j^j zD%y^s)tUK04&^K=;g0z&!$Q z)ULTC$d8~sFLQkYRGZLXoBs1B{o@h9{6^x?I|9KS~89a|RxG|iz!`os~h>tjF(gFf3cy-H5H$5N$hJ6DpElUw{W zXSz;H03q0hYtln)vK&C_9|;Y@Xzxpc#bjjLG~AfpvO(zvh%1l#hU59SV;F~0+Eb6_ zl%lJz@w!NTDK_J&hNV5jQROz4ME^qXp!2ZwbI$vT`N<`pzQ9%#GodzRcjE!omY32^ zzu1gn-7JXk5p*(;Kiuln&CvT%7QllbB+joI&l}iW8Cc1yj1q+KOx8`?ALt~v;(4Xdgy_&suYeCL>baVvTvh*-;nREb_JFJGQ z!2DPL@kNem3Kd*@tRUftiF|kYxW>%4E|A%OsXW(Ok4(Bseg=or{+;-Bm^Z6;ierrNk|92kd%rJX}TIyHmx9&qP?ddi&rBvRE zA;6?2`#AjwD1ppmSCiVy?H78*Wa9+|pr0*42m-ofSve`G5NTkT#DkJ7N$T>}yqB-f z;2Y?wneXHIiN70PSlNmWqrvoAR+9XY^ZX@Ecs=K+hnwcmWV~M};^%T)O~BqZ2cdsm zl}`(L!NAYml*dD6@Y(r_5DnCI=_el>CIyw(4_E}q*xzK_K&02e+J#VLhxC<^)UTO- zJR^8K-^S!uLPqT>*E4=?^qbJPHwC*U-~umlx?(vG(Baj1%McwIqhF?=*BT>u#7Q*{ zeW;mu&+MBB06q5hl>KJCX8lY3xk;A?a^lxm5g+S3{}1BcJF3aA+Zt6-)SoB{(yR22 zphyR?Pz9t*S9mnvjJ4lGZsZM~ms5bswPX)mz@8`uxq#j_ zHZ%+%z*ta$;yqw>f>z?GB7F&!7K~+(83OuUO$8@4Ee*)Hd8}$5fccy|@Cf_bxCK?@ z$eAf1o;X)eC*MAjF+6BMi&}3tcr92T>(lCm$0x7usM5gnUL!RF4C%?@mka>?{oe+7)PMm8Y-=jUGVB8nv(>oe8AKw+99k4NrjK7n}tf6u#ARc6Wgn zBBovm+EWZ=Uok|2Y#T$jASLoaX`Z=E2cPf0+nz?%RWP@IA)e6OMNyTzv|M%bJQ`Qp zJ{y>6YP&4cNF*razQTm9xCKB}!P}w`3t4&jSp1?wmm-*aEHDn}O z^`?&6KYz+0pw3KpPZ!8=gCwz+Z-fLDD+H*al{aj1XvkZ(#%u9%G{8zQo9eA1VZ)VFc zndr`ByXz6%&+tHYa8cgz7fT|-($$>?+JT>6WrEg-nVGk|yu57^`nQ_S;o>dSCtfO5 zW52LL!B#dN;kw!Bk0qg>3R-}U!^FEJNcf#?-|*x<1s)3WwpdBa*xXV@AEZw&C@vRe ztt>JUS7JT}-ORdIXn<cqP_d$JtVVu3d{-&tM znpw|dIe?{rd^1^_K{jqzKS|{Cbn7{yw%1#`>GrWeLKuL^z{D2|5kFW{YHIb=)O}lx$&)`IitEd;x}xcSiKJTMYuAINKws8#9_UWsRdIqu3M#6aqlPZ8K!^A zal31_@1lar`{|2m7ZiKL>?w|p@f4}mn+tTw zhb0K~tu+KvIXN!!BV=I#v#?xg_njBQdA?^3#Um*D+T#PkDZIihzZAn5T)|hL`8;Hg z2HDyk*#bCf9TMEZjcT_UNE?d4k14lWA1p#Wrl-;_w)1dGw>EgR8Yr7wsmi`!hJw$s3bUlY51TfNqr*ZU_(;$i63RrpWIkcy&#OeeX_L7- z*6M&DjizK25LCE*{w)OUIa;{;Ws>NpEJa4XQ%b}0-ldgLiKzSjKfL6!zwQ%V2AT3I z;ky&_#R^Wi+a*EEH)_=bOI#~vHN9$-7x?iPGrfoB?`Mz z>_TH-4e2ot>4sqP*$8Nwq%b%ZCe_-Uj&4t^51$NWOuuUDQ5aqY=S3*hRkkUXU66V) z?@FGQueWxw^!zhM=bEhOxll7Brpq3_g@JWCVgSiS#H1{@e#mL@$9$OJ(G(>7jVTtq zGIutWLi1ZuwAL!O>8j^*RL58+o*|Jtz@sb>RmlYvd=2MD>bkbK zwh;s(eLc~wHF!!2+rL4mp~GD@V;&Y^IR~dy)$NtNpuM0C@leI2N#nV2d!Fjqd-Oc* zmu-$FRG1mg-r^S$%_0abH~xzo`i~xHYdCFy&00+bC@IB&v-MgqUtXf>K1J2yj@0*< z)z<0C*e~u;&2qi_{C&yQ0)sM1dE>`gHSRL(>n>Cu8j#_S%>mR^x;uV4#1a%~NKaRL z5?3<*ULDrk0Kv7bqCW3N3cj!}0z@dbd>rMILx2~&h7Z_4>er0@@0LNJV zH7x`*C;WCFC(~05Aam%$|Ce+JlFa-->puW|Y%SGb&Q_0+8TjRfi-9AVcA=)CkSg!qQ=iEB&*| z%;yT%r)hfZ>d6s+0gxzgyp_i{-W0~lYHiSy#4*MtZ#O2LPs4~BT{}e?i0Rj<{~R?` zOyR_$a28YHRjU77N4!Wy@Vw2PbzXKeEQykRpb&!%%}XPS>yy)sl;v^2RM1*|;d8j0 zARz7NloIh=&e+M={A|k@BK5_3f_up#w-;NL1zY^i+gU*KJ^qFM@nkDn;v$y0XzEcL zPfNE@^V4e!56Xa(>lnG6L3esI_xi3T?sPJ7sRggjz%@&QdN=(rZPorU^ACGxfeo}o zRd_xC=o|`b7{|q>D&Oe|^d3~TGrT5zy^n%tQ!rbMyPl$2P8odY6L1ANNjZVuy$byv z-&Z*6bm-J`%f1f%14K{9oRY{rcBh65^?@Lcc=I<~9u@*Dm|&4FV5jes@Xt9Ijd&d# zSO$q@TrccJSB^!4*R=nQ16%Fxw%gwT{);?*Pw!V!jo*4WDN)YK9cjcd} zW!QNHzFO2K06JKWj~W}F?Q)3)1e}=@vg0BkF9RBoS&!!x(fuM-Zf64_pyf$T{iS$j z<;!u~qIx#9viaH2y8Pz1Ex6S~VUb3;Dr?IRix&j+zLdSsQMDsgOvr_8-6&|rCEH&D zT17oWoC^-9x|-J4(BMQEHy=9^sU*vbO z>gE}r^|dFoaB_DVUfS-22EAyR@*v)KIhwf5ojc)0)8td9vGILJ657=#!J*i@10}=Y z1g5_LPN4YJz_0VuS){SPFu?XdKJCB`&h?E*cx*6%i>AH% zvqYEGtcAjn$=u6rcZ6YJ#5p{S$%RPcc9*)T+SK@vVuBoiE20y z^AKHm*syf$s^d!iwHW!G2un?{e+GBldX5P>>LGrIKWTKeP6-VD%*gkpx`%d`mLKOv zXsc%v6CZXKj27<0gkhK-DS#e6+^HG>VS5hQv<^m3Zn|vAJ!ajqM3MnDTdo0BGpw1r zO6zX1&blIMah7dggpSj(Yq;FxW3kS)!gC5R)+h)8TgQ`ptj>YLbV?+*P^v|z{>OlXYN38NXOdZPb2J?Q& zc{z@FKd7ov$fmr-*tQ#ym}`C>SNy{C9N+@11Xw-^rfRQ_Rh85P)gTh#gK5vIr5ncY z1X)O$ne*yAQ7zLLh7ULos8x|3>CKoilHT_Lp{;7n0~?oLtz?`+;s3rJrY~?DipFL&p)fW9LuX71~pI?Ghx8g-1xpX_>C^t5%9$<)SvD z#*{!YrEW8|m^~q0=iU!J>oz&&;y5+O2hLQF$C1~(A-H(L0`mWix~6{37z4cs;3Izb z68*0iF)`&vfXf$XSE~vxEDi2}&SOrFUgaipZoOtT;8jr2LGQWKF9GDxbN5yNVE{C+ z+5?$WkPiVG2P7zCBPq9)tN>-{H=2k9jmW@bV0d>Hl~ka}vv;6r=Ki;6sBNV1;K8`z zd`{_&YIPmP$g|Bhs`1i8J{rCKT8MKPIX_#+@P}(+yH9c8{csf^q5*o0<6hz3^NF9H zwa(teOjS&!(3ce(7|D&5Fg`nV0X`mpxBxm7`EC_Z>0!>47r8L#20`o zBw!E#3s!OVnAljdyLZ1IT?1ZgJDZyd_SA9a;D`hoP!D$o<>x^!ZX@rsJ1s46mRv%i zjGq`Yx7gXI^a07T?029~e2fiVSon6dID?WhrJW62rDJK-moJCwr_WqmJ_j>1wd+>x zXvSp#tXkJgnESzlx&d{AXs6X9snIH+@4m7%FXgOxAtS{=oQcl%MEdJi|3wF z5zJajikL^Q+(S?%U0anq^U z0CWTt+}*W!G+L4Q4hWdT9aCD(IWwLeAYQY_GIG^Gd{ZU6r>W`r@vd?hep~jRg1EN~ z7e*TtYna`l`h9;eh- zgBmEF)H8;FVm4)?h<9=Hg5$ZOL2L>u^UVSH#d=Wd>`@g!$2mAeX@lZO!Xx8eAo&59 zF{P1FqlU8SV;9}Tk3Yx>W(CAw+@cK1(`!=rQdM!$(HJJ=sFOrSwpk9E{HFMm$^jL4 z>*n^!;iLY~?d>wsML-)L=n>Qp?Alh5$~kBBCJ*qZhgd`mBC|?K3?cImzguDSmypXE zz!}_SYc9az0}SRz4yx(S0tA1$E^L^wMNc+-1f;eoJMI`#KYElV70H0+jPFaHmo!Ty z@bUMb979nchg^^METPUUGN!=WDt<^>hrT0G(Z}E=Xx#6VuaO2`R-4TMvjV)eOw0DO zt&TkVXkaWBO7S%s^dsv>y;IM!K+M@=$8tPa8Uk(2larG`H>1}5kh`NV$_@DMxdA4yH>$e8YUz812|cd1J9o$4m3hhNC*8w+cq#M-m^-7|66T;FO|x(B{4b zqAZ*s0t;~72lqhhHaHX@lLvG&q{}5?JS>*20AtQ6qh7d6PM*8Mson=b#++qq#&9_p zh8l=Dd~>wSfUh&Qzrm!QHrEWjYd+mH2#i$QAOunEy-&_}2IV?*>yOM_fa@HX;g3jM z5AEgvouJ_449;L9eOs|I_o>Wns5M}F$})a()Jg%0L^&iSp~NO$^wB~~V~8B=*nHpg zM#$a^;4e7U)+V8jzj+l#pH${EriC55Y!+scpzS5rSx8q=%-12JTcWZX_ECDIxt&F2 z_aFjTUI1?@zgHe72N5nZW@hk)-Tr*v9PK4D`K1ErCT&9z4+}e|9}pk3ghWPCb#;O> zGt)KIe60r%i5(SHPImSlD-M{_@3=ymPaI6Vi3Gsyiq-p=;1?b2QG#PgDd;?ty1v02 zeKonsxA&I;IARwMja>%Si zC8M-i3^@TLqOCUC5jw zCmGwsz>BQsyG_f}+^1VOQt73YnJ^d(ik7-l>Ay z4GT6mMtuo!hUthm4Y8XBdQ?%f>`Wvi@(CCrp0r}|iTxdC-sj)3Rws_3hoRl<}3PTC6=nTY1$vf^uYntcl)@NFc0Le1?4twMsv>EY) znHuCp9&F&+QjnO6rV2{(VKGB=z9LU36@9w;hYt(5K$>7AKV>J!4ndmll#wH>vc#fd z&4UvIpx`o#f|cqN&#~;Wh`o1fz;>3oT#ebjGX7r|Jp-mR2+ufFA}e6x#&Svk9#kqo zx6C-``CkC&4g|N@&z}ozXT_zGkoRo>9}hHv$9{anoer)9<4z5RxH9%ROVoY9K=QF1 zbI;A>0ik~xRBSCQy1{EP=8`#IhaVdECW83P+*cz_IZ@?k-qE@;d~&d<&wVyPKR$UV zP4fd-eP?B{at8s*(O{dws*x=VHg>Ft+0Y1-o{Fzf7q2bFYib^-wE*HmW_oAI2rlJB z3Q)Vo$=NUEv%K!e6U?S&9LBUutR5aptemEzO>t9vI2{DIsm-*h!TGhdd>zMZ@h-l} zXaR_{S2Vnw6uYbIz59?=fq$U;{Wwr^h{;Y)rtC~I?bOQ8{Jow5!{s%lz4Fu-nt*4( zbF0)D-rf#aJD!L0v3j=v_Bv8Wu7np0P&SO&9AHBMbDuHZM`QF8P;)m|R~|sehMF>` zW%5*3_R%*$N9m)ZuD(2u@A~io!v>Nnn@oLqOTB8a{EY_NCuq6HM#J?^tY+@6@@bC4 zxyUEQ)M}i=r3o$3VDeX409$e~z-R)jzvx%mojLVuT`Mv%Y%x3$dr`8g);7+_J7Z+e zShVwdDf=gEbviycG=Cw@gWJ<7S218~XTaOSwife_W+XCHDmDHtkPNc|U(f+CJ7-cl zuEQ_%;_ckG7^z<;=&p*W%0#)}7?jC(z1Ou~uZv}9o0)(yGHIh1J912TEB^!S*C!wS zUjxD#NJF{-j(O1~HsnBxo}GOJWa9uAih)rSBR2@p+`*K{08ld}zqu~-D$@__4j9e9 zl`}=GKU+ptz+>gg%Ny&0DXdmqD}O-+b<(743Iw z_rLgKjS&u|5FedE^{h(?e-0RCaB(W<%&!DnRXTX_ChM4WNi;O-6DAXthJFQY`JiNi z%R59Ji=|IG$I(v;-KUNQPCk?m423BM88YAOXt7SWGfX-c$#9*A`GbQP@Xf!?$)g;{OsTT)$JKY;GqZ`d+A?O!=sMRj!;g&?q2k|jy`{CNY2 z%}Lfx0k0oXQPC29nVuPd=Kse8F|QNJ2A#GB6@ICU)i{R{8>-$r{d&ye?IDKt(9I0_tQ=9(%1Goz zp*);bpwb$qsT>ont)SCt;m>5bt>U`f*A*T1PC{BBl=ZyFShav_eq@cm!y}`67>hnx zHx@L>J1$NXH#4>rQ%g07QtEhel%=|hiS^g)o{K_IKPg)rIo9gw>JugsCZNr>4cHTU zKKcnyEgn9ph^=4k3QOe%V0swDaSxm11qf z{x!5m%6fl^V0@hLBYUF-h;eURf6Ku%3b`C9U{_FHd6o!E6*wJ^vnLe2wNNTYXB)dy zTUgN}<7$8irkH-PO}+tlT#^%BO`iw7>6ACsU!~~HnD)}pO|z{X%)X&7a#uTs3nNw;H=EnyQO@X{!&b?amr-W{TT$vtn~B}etxyK5HiLT zO-I_O7*sMuuGn3w+VFt2poS(bE*r=ZHW{8A9aVwq1r9miL)K*|&OUd5e}jJ5sVi_n zg;sab`C#A1Lu_zhLr*bQHo!+|ixuqmp|r%;X&_qUulh zJcniOu9491{<2Qw@GB2{bzW-K?w~6Lw4qvdIOVXLr35Op8{wS0Uz1B0o0mPvyfRa6 zF&lQC{d^%ZJYTcD-I!TiC2za0k{wROwW0nH=7^VMcG&X>UN)uantl?gR!TH!5lM5~ zrH3?0FCq~#pX|gHe&jp6KsfD;Bh+))^@&2>!$h{*q^r{$pS1!-kdvZE9of}gaNjMV zvIw2tUCbjIKlmWU5WiZRJQNqROhBb`CpIfLw*qs{)9HR#H;hC|3+N~*S?=sxT39^v zwH_^2w{v(Dty`q`iQf;99bd(9x2({tIN{y%krzE3N(6pBE!MTWG0t2zmeK||u~$Gz zo0^kzg#2uz{%m)y13#6XTL{##wZg3?xWdy9>&4-T=6g9yxb>F8c(9VDPPA$X6tc~5~@|PbZ*?4kJWQ$Hm0w$rJ`q$@~|>1${CN=6Xpr;r3<$xMz}ve+CiUTH+>7~`RZr{78G zY^hElS_;RVu-m0EjIQncFxT^8KiRb7L~dywq5OPY^;hk)-QK7>hfC1nC-Qn5r=5FU zhn7aoi6xWZ=Ab_Alub_oZ5c+-X|Ak(8E3@z*>1xFsy3E#MC0nOyMO0O5Fg};f}MG} z>PC6}=_)WRi&+r@h7VmaJ)wGUpIn8$DKQF(sDs445Vxu6umN3c$^H$s`%{{4-pmji z8T+oRbcvpyY=dI~<1I%ZlVIiFV4aM-nWHb6%B;Ha12RlhzZ4$DD}XG1(unt(%YR!Q zXMzynr}yxktsmXm=(Vbr2>uBfSGwY@v6xj0ulZ>T8b;k?lb*BL-uJn7Yazk@0H6UOnJ;u0B2LaggT@oaIDmOfpRZLj_m^2}>Oxj| z7%^PR$SZ;(<&Omfs(>DoCok>n2maTdRzNmbo4}`7dh(!o^DvpQPXkS+L7#D!(hmom zF`Ki@z4w9M3c)2Ld!g-Nb^6xQ2CtU0vxM(sm7j75MN6pq>oYEt!yHbkOO{)Fv0@^0 z59qOz7qqm7_o!%nLQoyM_xbK6{7z%QprkgjbbiHRc z02TP`6Om5%6;QADPi^PZyJcv|i?MDmicd`?;~oP%{@}frfN~Ey394gJ(+Te!9uSvj z%`SyGln>>6vgB?A^R0vPR?s+I^n_Eh;_IO@(N4QQ)?sj;)+&qM?BmMSe1Y_M*3Fdl zwk?!e1(Dw1+EAus-msQn?tmA>mUVPruQB2otS+<>pJTZQ4*z^nH-o<-gmL&=lN}iw|44xXkV{;^$0jWukN>k zRlYQyJKwL-Ao{sJE3J)U`*foB)v9mXkISrOZBOld6@2m5h2x$Q^w;|3UYtwVqO0wrh+Ao!BTGk_U!M~{{P2IsZE-{AP^V^ zJtNBO$)%?UG!m6SWQ70MgWoH1W(p&-&dSQlPI$}l+NDNf{?3jf4o=QKd7!rqXcazZ z^q8hQyUg^MOHW0`LS5`80F4sU5b%xP&Mx1s0O%~@+BJ9e^Z@0%-%qc71Nx0O%1W;M zNufZ*wo$!!Gr$`Lr;*-&{>1R#LE&QS{~!Jc!`x}iAOKy$YnVQP_N@suv|5vOP*Php ze~xHv)-TQ-qtRfJVP1HHb#~g#pM_;jrs{ul`Ww7lpDR_hIS~@im23jU{8V~$3hb;u zqDiOjXR8&9WpUp6%~zqu{>g?d4l? z>Ue})*!D3OIw_l_zCD5X2g=Zkq%!oQb>}f}oX!4Co)diSv3FG2LHuPuN2HNK z_&eW@b(L864n7Ca>Jav-}4%Qo*QES0l6<-VZv@~>_Nx%MIqt4Gr0Q7 zt_WdE5N=qOQq8PXj?<9m!K$&h61NYmV;1M$Fm$sHq+GAhMkiR%;+*;=mldmelxv;N zr?BwIpr&UDmuwAuMOwanmR<;lJg*LPkHL#?(nc}hOG|Mqz{jw653j7!VTaY_WacUw zs<^3Q=_uKnP8t33k9}!ht?}Z?@XDaNr%aC7`i3+6p{~*2)$wJdd4{)darwK^5YOUI zXuHT(=omy}xxv?`oPIf|e7xSX?5RifPMJ_$rcU3(*C=&uRJn)P0}q9F<;2h{GGpbAh;Yu%CM%#>w^4^B8-_>hnVi zjcdg_6C4!Ew`~*Wf<7GuR_Ld4&PvuDA9L*;>`ptd(yr@KE1lZrCcNC>=55pYC-pA( z*skKK>luS~`+nw9KMVYn9lHN=yHsN$&|B2J<3D^hmV8o}JblhN@3WADA$1%Y{Z-xA zb=9=`I`(qs{m#nxb}+N>RwY?X8k zu_aF#BT0gL^;Z)U_gHgiAx_JS)bqv*l#Ds;?Gp?%$5w^iJ~_j(rMmup+!LySBxn+0 zC%By@-58Q4CbNHP4NA%ooZzmxTf8}pqC=;K^rB8^ccBAzf_r&X&=NG!ns2)qFgok7cCJC0rpc#KmmT~m=QHj)?|8SRe@UdXLR0TiM zsFIjXO&ardb|y{Hvz2=W9=cJak91B^C1d2N!lL;*Q))X+u8EY*rkOR|y(_y%9SP^h zHOUFH^ERAdhrZb>p>b7zET8jo zPMUn?JXwtl*U6RrknPdmkn)}PW1CFd8}`5V>JrJroNIr#6lyFZ1cvpCNuDqV(%-ie zb13+IJjMLt;)sAbLH+kH^I*URhgcBm5mzrA-2`E~qvKy;yR);Cg_Sj%{?d2(a9W+0 zFR%Rx-@W}~W6;=GMq}wUAc5^dE5Xk{JdZ+k+2USA+`Cx&Rv10tgoH?-@mtrfke`~` zD9`$5^I*aVA^bf{|9|u2$68_oV<7ryHa8>(qy$33XJO`s8>>>Lh8yzHY7@teHi#KasstJylBLGU7Wji5bZ8;xYOyFdT;6~tDr)zu@C zJoq1N(}2tPDc{ajQe2G3irHxz|7Y?eV5}~7AMg(*NP`Dv$id?x9D*UWXrX3gY||?$ zWCufg=~9(n`e0>c)nG0JxCW>bgYm&U9BxW|rH|lXVhT?e zm}~iF;{%7ofqt*W#V^K%x?7J3(W9BpQ)*;N()fj(W4Ghc>S8XYp}oH`;U8ESo(LUBnpL^zRY{0f>>Ea zrK7P>;a|4|stm3l@Dgl59s(X;#w7)k5)#O^^um*pddjY1p1ZM?PWt--G2~v%GryAs z@bAB$p!RS1W`pwe)+A;vKC!d2t5Cc9v0c0p%X%2|98h`dWq)$jGUVb5HNRhp zB)y4w+W+z>BM)%J!VLa7qp69BT>Tqruj(Dn-;+SH2~0A(Et$F_E1#3qf%@NfoBH-G zd@d6c3-$8dp~ROE`s3Jo(R{we`wR63rLC=m=)0IWaOo*2p|9Ru0*J!aS%_e&yKgWd zL97(TKV)1?EG#SzU+U_nR!u(Igq#2<3A5*!^czc)o`}^Batb&$u&y}J!pz|Ca8EFsd9IzBmx86kl)_On{c`%-& z{}1?ZYV3FP*s`*DBDCN2W|;eP3kvGd-+-MYecJ9}&O1rw;ug~adZA>u33L3+k zzx6HRbJ_e#3loV43XgsLM`6ScVW8fK(f1dTAOrro;OMFC*Ox3jUIPJzXiAcSsVU6i z8+0eXFgosFOu0`;NUD$F%K?>0FCZHU&Z!$f{~M@##yzUEo%J>G#i0VEiTx1zCkLnd z(}K0Nnx3{}rKYU~nD0Q1T}z97vtv{wjZBX^ZW?IsvuA&$3z~M{4jB!cP?| zf#$I|BuwZ3XmIhlY|JRh3)2VgHs0d&H_w25$PRkdkHB4Ot_QO#mo5{qmVL2_`DuM$+Eo&EJ|p)ZA#3e2bN5WfhZDFaHt)!5YbUu3A?{!V2o@hXr1zT`QW<=;&Qg^^A#*wtamur>K9lJau%! zeaQI;l<>8;JUL0e_GP|+UXwnHkBIomz*CS9?s|2POurrxfP%R>_o~@_A9|j+463{! z4(6!QmVKi=`OS-Uk)7*J;af4amTv)^bqBw|aeasTnUc~VXopGhJTg`4CNGa|Z_;+2 z-2H-8%nzs-*~MptcN5c`M4wRE6dSNdo8Q3V)9T#TesV8d_%OAtOL})n^?<(jqduW+5R;^_ zU4a585SUINsT>dfUQH|+!w;r17)Ng*bQvUD&PI__d|wiLc$3lrM%r$Yer40v+4HLGZ!3iL%Vf0=@ ze)90}>`&N-^*?W-2G(mU`qZv9{9saw^2XyK%F6)>C9X;IbY~EhoR8Sby6qc3-UOij z_O{#|%q`XXzONS^74_I==4pxbBBwCOBJRS06 zdNbL?*h-nNfahe{32+^Rggls(d2^OkX0P)U{tRpcbQ$mE9ojqELFXs0+r0W&h{Cw7C zL}zJf36xO4edz-&RCCKk`fZeu6)sxZ{iu5a^zoskWo4L9h^Ncha=c%EE^If~4w_a# zQ#B@-aMwM+P7ZuG7G#jGNVy##H7WPz7%pyPU|<1y1ROW788-rTbL`usbkFF0XO@1- zgoK3HFLb;93SeBT-Ph?@Ct}wyn7ID>$o3TlD0Y(p13Ez1Qbw&39Twzr#G$6o&zzO= z4R!Z$R@i|zl?~7U5Ptaly~la+W%5PAStV(s|-$-h;D(MmVwq!{S(M>0F)^T3~h)<+Uu@eBp}Vy zkDF)4Lbj|kEjLk!HgFzH4YYw{jO&13yC*sucEzoO95n1e1dfg1!9{(XE`9~`lipj#-^t^l&+Snr zkT>Q6@jOf#a)C#W6%B*1ProG&i@QicA- zK?k!xVoo>UfjRDg$DgM!PCDSf|LebeJ1{X&b}qTKbFI2QscycF;JVU)-E;HVyeStU zmOZ`qMrV^NtNe%b`Q{d_jgv$r`L3i7Zn&iD=laDvfk&XMjCUly{VcuovGXrij&e;k_jK7vX`pXW<4^aT6z~!6$uf0Ln;1& zkzl1>@B6TkdWFS#qv7=d?yc=x*2$rje6|Z^`28M{%^g!r#|9fg-bgcHhZ8OJmzE|0 z4c!Q|TXvNyJXHy)zn*O!bMSdivgYWNI65&quZhjBjoF_Ug1Z)6HRPj zpdDF~p2%TtMpj)Lcrv<3pyH_OQU0~2xYu^Z*AnKuE^m`7`jZ9Q0}=KyocO92&r_Ud zia6=2J(@KI2&CSfjvh{m{nOSXU!&%4DM>;fo8KYxVtt4hn4+aTDBX?!5$JO<|XbxT^?Bjy$i>wRb<7eN3DJ5 zev@Z5cA}llVd>Y~tXrk7N=r31E=UuWAs1J@Jv~^SJL-^{3h&K53Sd@SU=R5G&~f`H z4+b|U9kvwS?J4cCCtM{cc-U5Hll}V67w+B<8ONNu>~__tp`j<9yOX||3&Z};rM4Pw z#8slf-s7rue$*T{Zg95n2|p;qqtClps-#RxQb8E$+X+9C6-=8iH`vO9=*1^!CW%Xm z#6EJ~6q&VGQUWw6-sCzSDt+ZDq&BqBRh=#`gu^uAMYZIoW`2(KuKMV*ye zAAOkA*<QslhOQC`31HnU|nVIxbO$gr>c%oF0)!nzv-HaNdDh1QuipUF} zVe%zjIgW|r9ABle>gR)^`tRjo&d3>{=`W}CZXumQ-gpR z%kWmu*=B5qy^~g*TN(msxACSk_!FetQV7yNRnwSYX}M}jayTtFt!P&=)+MI&B;7(I z8^5?H1Z#S#y<|J~#eFT#$dD>l8XZq7eSxTa`&R9Q1 zX*+MipL6rVY|-e1j8w96A5H_p;FMx1mYB_g=;bhy?Wi~z_WCFfZ6g|lIy!DpZ1iL% zyY%e7Dd3HM>e?gHV#TM5Jl#9y7wo3rD!rK)KDqL$G2`Q$#ptJ#dp^xLyUX?2zL~u} zMSs9r#{F5s>;`L=QDb&Ogi#9VS%8_TN-GRqNJ<-Dsr7@%EH8AvzYgALaLU$Lg=(=*}JRD zwuxuSHhx0s<|+SN=f3k#lCprg#XXR_6_)-R@zPJGQdh zImIC8_~SMmxARS;wh}!XE%{H?YtJlRuOoUP8C%=;my}Q4*J!7Vkxi57C?2>B#JhWY zy1Y-RbN%$~d}$T=NXd9oOV{RiNHL>Imf!z9SHjupuCtW~WZK5Po7g9lHI0-NM8RsI zZlvRVHGS08iR32aVefm&L*Ivb5R{$bv09-{zbv^_zxMU#QRQ=)%BAw^sBzb3NsQ`r zz#09a=sc1X(*z1IClt*BU(vJrh`yU;vLMsPh&QeifdBjF`9Rhqy- z812fEC;F0mxMT&V)rLRN17aRfV{t`duA;=mFx^(nu&HcNq-Ca6mdB~)==lC=Wto_6 z3nx=q*kQXM+6Co1c0U`&9Wm$G$2@KuJd?Q`|8C|CQiuQ^q{me9Emh7m?NAPc&JfTw0EKzb5<}~M*;7?wRZGd6 zDf8}q$g9@xc9mYBh_vZAH+0bG%NGoao&74>p@Z8sjCAkrqN#|Jk_Utd?%RS{s_OHQ{}%lMY_ggoJ~{df)iz5H2nepekQ$F!;Yv8n+c3k$J2 zbsCTLe_BBlDDs&kEvt2uf4U8AD{FWK(owRNIBNA3_Yup?8RGNVt%_H=!c^8}){gvy zj`HQ&yiR#Fm%qHDS_(RPHt_OvcVB=M|mI_Nst`wj(8JsLQ)+u%LQfe`c-Xr|{CIA|^iDJ&tT@IkJQq;*}>g zyXOm^k3h$#?W%`#?&x_^cv=(WW*}*<<-qful~l+ze(Kh_J2gXGu#P<`PBb)N zHd~HQ?6XboW6&A)nO)d3j^2BX(<^ya*?Hre}>x$m2bUPjUQfHQQF;+UH z^VQng-czz}ifL6vLeTY!7v6dUC+FFtl5&FBH&qi?u!BX^ z$plrJ-jap{o+lVP#$vT) zS?{o8Cuid2>nO4AXQ?roy_4*6N+#rb4|-@~lg1{fYFA}FSJHLvXz6%P8l&{jTfSYy zy?^W`LIb~TxNBidN`x0fQZYcrinH?A+EI}VxwApoSql@ zDBgARhZK%bl59=xb$iHRr8GsK?c`mo*$ob_@>4uATfUC$GZ$u9A96h7Ho9#1umsyZ zri4uIZpCD}9}k=i;;mfYQBvOZ>}8uwM5v=FiASI}SRX+Ts+s?+kXqvVF86(`R%-mc zbr)fH>;X14Um18hUN^Nec)-N(a4c|eK_Y6IBSiJ6C1~u+$jXwQgh>n%t;p3oqI-Hc zd2r)HKp@&xs`k3t^)0U`t82qNw}Y*YtnrfI#{@1!Sn^68c)Hz1xbDvJp7@}cTuXzk<78&2TxPqdE2FS%DdbC2$ z65ZVMr#LKMmm_*pq~}W#&-}ebE5!;{7=&{bCV$+DvU;9UvHlurL6No;d)~FEgi}L~ zYdwBXh^TtbL`K4{iV)|y2GBBI z4Xw2eO$s}`=Rs6 z^PY3`Wl z1?LW>jBU*nEeeYh5t+m(TA1H_QS3&a5^1*NvNV#S6t@3&MJZ*w#|%<&Z9L*#1S#b< zDKez?Dd7u3vA)5db89H{76VgpTBx-)r5bQuN~{hqw^)tXRC*Es@h^%iiS|(Rbry**^IDi+UJz6I zsA%@B-q?cYXsx|~O2E?!U88Ns7r80hZ*6WKn2T>s zP;&Fre-3x&Zi~@WO~XBUBMFEYmrT?lqHl7l?aue1eu{56E>0k zkXLXa{W4)te65bC_KsJInttmz=OF~MuwG`M@8Cd>L^rC|tlw(U0$bJ`y_p}D;*CGn zg;vGnjPG+oBK!XAH-Z!uRV>({kr0-zqJ9%yYC&_CIO^%IZ__gN2~N51>v+Njj!I%C z&SGF0dvX}wZJY$^aT?>xFE2vDJ6hYAIZEkQZEG z{%{gLD0Hf&4LT4&9=C*=ApEn)Ofid$43iSHZN%fA+q&sZrbb6tjo-Tb^vgcO9j%`q z(|JlfPg*tut!-#rgOQyJsp1jZSAkfv-uGDlC97#NO}CP&%rb>2HBr-?YG>?AKN8%E zd2MI@A?su@lTWUE2%u&sorEi=2=I59E)z*bmB~U=;~j8dF@zC(?dxSWO1iYuG1ctN zY7u_bYA?0+@Dr~(!FOx(`=gk0D(3Mo(8A&Z$oWrdQU5(;@;`ZnR?N@Cg42KA>E0Ln z_~u4r%&|%n=R($x?OZOJ9kYW_eNUtf2|Mfb6O|WHfx(WUw3}#`)X+#N78aG3L^azb z7Ov;?#_%Dw=$Jh2e0aBzW5(-wf^72)c>1&Gk*s((?~fazTHK>?}%8_Zlc zUX$~sg)(FfGLJDe({tM?JALisRBV}tr-~za;d^(W*Do+6&?$9;W}@X=3LkNr97E25 zgX3B;N0`ZTsZVgr*MzrRuU#NQfR1pr-@5sm%!^hu!>f+Css`wd=jzc`=>{2}@c#XZ zg640QD`CUV#5kH2K-_29Bn-GvG*A%vaLwk*lqqMV&l_NUq>hWV`=!WAo0^y0{GRmA zJEbP!fXmV3&*A}~+Sw`1x*vRrYtf!7d{Anj^2+D~_R^z|-(SG`zETl6#B(8E4p1}Dh;bg}jUDa$oZcwQhwI2P z7|ce@)8MVX>zb^;ZkY!yJ`@4Yp0a{}o(A)E=N6S@Wjc+1q6e6F7as&BZDYz9w&PDY zm?E555c%aFj#`$XFEC#MQ$^-_Uzk?=oZx=WqOvjm565Sgd|9gNN~~TAq818DYB}pM zIs9Zp#oGV=@Vnw~*jV{uy6aJBm@>3u$T?QJJ0SeIH6yJF_KTF8IKPid@8WB!wOeL%}TP|pn0uOgaC$gEROMJG5Q$WJl_?0cQ=n3y73TF4!z zbE@{-;8Q8RYAKxG-E7v1r--%!KiG0r(_!aF*8r`n)Knn#MSC|oQNzu+y)vKjq`FL3 zg3Cs@Cg@0HQ$Fdmv@E-X2!Y-H5wyFx8E0py(i509!_1BqnlBv%;Yp&44UR2EsJYB* z<4Y9Ai&xl+@eg;rJz21U`wu>&oK}rXQ6gh-&Mv4v0`DZ3_1b+QZ6;Ds2L=wH2cYCk zbbpc64v9p{3vD)oBG3FfP~ZYf7gH|=jBgAb9lBhdlwMf4!Et@c6-A*h5+-t##ov_T zb#@4<#V1|5XLi4uZ%#|}C6dP-ei8FYzXUjO3$F~mQhFY|Q#T{|8Nxdi&Rqix3`s~x z@*}&v47Whde5wX#!8BPXM!8@cl>%JKmbYtvAp+0_1D4O(R?#KbjtaaJ=?1Kjp8`pf zv?=73<b#58>*#ncfx^$&{`zKFQiz-J7bk7|a zK@rSBvmlWrfLc))RN^sZ5_f{{zJ*Nw5Gghq0-J?I4Ma~ZN@2n+*2(2q) zx-pM?1P#Nd>Qm`*hU89#^q{@ObI=0gBP62BD7lZN#1*Pri;E`N|A)7)e5mRR)&?ns z0|*j_?hquU8!18Q?(S~sRJu#LySux)yQCYWrQeP5yZ8PB?+5&Fgnjm2duGK?re;>IwBmNX3{cYQlLg&tv!fCc5>QBlySlpA0=$N-t}Wbj!h(XLyi#bL=Vdg4 z^ntT9fM6FnFE&E4L&J_T@OiVTTDKP|zNWbN2sj-sL=zSc@5W`+`)F%h$zFf2NWKb; z@xE7dKL+##;`GKRxtibQOP>M9&@AAqkls~A-QGnNG2B4g$CF_(`zO;|@4}<~J+5Vx z9i3xy9YQF>lIdABS=xNa(mhiNZb6fdtD{BzATagn-Rue~R4wy80OE)Wp(W6}8^CZ( zD6U5d8E&@QlZh7<68b6!OyZU6b>6Cp{8$`&-=Aj&&_tbnc)@W6cr6C@Rx3S~t6Y-g z!8PX>mXJ6Jafq7yRBIkJ1aNv)VIEBUtkb*fUU_Rk$zw_uM+A(rHnOy2W%>dL2Bc8c zFN*E%v02Wz0wJkK6r_fHqI`2J6ByP<=N+`*cUOKLrq46dq3RaHw={YHXZ;Up4B~pgsX8Cp=Gk1Up1( zO62<@a1_U7iHs10Vg@d}Ga34_Ot?r$tB!c5bRs9ALpUGP*Xa>FW?rpc+UEeJ>}Bad zoQs&M>GBEGG-dV7y(u}$8V)hi`+$g8^Jx+|+yh2AH^?^I6q81(Hv_)C&8JKZ@P%sD zBW!L)0oqB7?8S7zDCTa8o<@P=kW(|l_dd4FR-_5+W1u9<-;7KJ#+XS!Ps@^B%e`tQ z*vZd!qlPWz|>Hg?hlz|0K01JQc`CdLe)BH)Ax#ZLVWfFA$` zUfTM23xuD?q4%R~Jts!ErOe-ah$DAr2rRV=VB zYmx1P-)xfsTi5>`fwzD5_4NUo7DM?O^$Mt1zW{nkJXA9inT_h{$NGB_DqHu67Q6kq z!ZVfph8=x3*7;ADu|%D?32h&1rl=i3FQhvkP@p7ZxX8%15-nTe0Ys3gBX(tEW3ew! z*!k2%3p!M--*pqQI;%UY*r$_;WDe?qK52m6#PbcOXt|Up2`@M%=?GytvxeW1bdI3- zDn*9cfpeAedn5m_N^UCug{`l27N{l>d4bWgfGEk513f)!hIMb-Qd&h!2q&xoo|UR-Rz))q zMYs7xiv>aZ`}@y~kwp%SLGJ4%-6aOA;xAchJP~$JdXde}1Oc;dTAzDpCh%yR6;FB$ z9t24Q@Z}7B4(AVC(zX7?lDN(~!rr<0N<)`|O$+Mu(G9NZD&+3AqqXL0aWcb&-Y1K% z$5xuNX}OGxQ^oVSrSLG?WQKPiSfdHIA_I3n&(}6CQI3^TEEZHI3oRa6QVM_?#%`V` z*$OW-12G&R1>K_gU}}6x2j*GkSSBrIvy!@D(Ex#k|0oHZ-&>e|qGKJ|J#+b6C!_}Q#w}e44vR{>7SDC0I z6w)H##-oEc3{(E)ayv0;PJAku3 z3xtylVt`_c&!8iyrulm8k{9SDi)d+S`SimF`5E_=pA1ZeU9#5e4KXr1 z2C!%#JPx@DXVLnl8R}fIjM>fZph!j0qXc?w?@h^`4Kc}N4*e>8G zprtyfQ0Tk_ur_}-)pIsUnj_Wc#1=sj{<3mgFKx>9Jiu1oegV;)SNNJ&0|zDRIodo* z%^J0SA}rsDKF{3fHTZb_uvdR9b(8@ZC%$=lNO7C>G3Dh1H*RY9T zI~NiT{SOfQ)Udeugm%>I)R0Y+69tK^B5YZEHd;y6F6Zeti5HU}bBm=DkuNJy0rntGfu%X|s!F7|(a$gG1hmKOrBdFOW;}Z5-Zxt{~^B2+rZeD+@*XR^Ag>PT51Q{(oiUbA1abPE*SrI2Ei; zF;#Sllnk%1ulUQYRg7kNTAu(2%fFw!>=TktR$wd#1}j^Pi>H{mI6B}oYgxe90Z|yY~@SxzvCCS7>nUS4!kJo{E23tKj3MWAoVu+6a=ZV9_@Lg7% z8G6MpH7c?LU4WL;5<7zxqEIS6F?44Xxb9n$i_U0ekN;TVT1r>jTfM3x*BLO14w0XJ ztqva@_A?0Vxuf@jf$%j{N+S#q3HSi!<#YS)xqAit0L+l*PrLw~h2NseUcWziMtwd1 zJpUr_$)5o7|KU%YX<-2sZ$KTLFcapPxcS__1a3b=GpHRI=iW@9_|!*r+9SdRq0d1NRYj*|qTFFiySm_M)f3!o1OP*52NJ5)dulamw@ zNp)XNbwsZd6B35jOlM2nfb3`4fPa+t$rTtK?%LPi@3axZ`V7Go2>x^_Y|si6K_d80 zn?Q;BT&*$$Fl;|JKF$W|4E6NbknEC|ex2Okob%otR)&TmVI5u0YQ~KVhv6qjM{n*U z12=DGW)^+6I^Ew(;1LW}x3!`u$6tPQj<7LRF1WZ8h|T;<+@4FC`+;up^{2*LGp|Qe z`gH(I90I)m-)r)0A-<*0Kyg4sX?kV``^XBY#2^JO> zz9Hg}=eG`#($Y#W0UTHPN0;km#~`^r4`A>zS)!$}am1*{!-3}Y(ISQJKq&|i6tAzJ zpWGDg0aS)=YggS>zX8sUWe!Y&W>f*l0sx9uO+({Y0aT~^BT8~7Ki>3G+%x)0PL&r84(eYHX#17{S#1;kC!sAS#`S>WwA63Wpw@G z?%qOr@w-^v28vapksro3{lB^~fJIi<)THawUwE!-Gesjv69qvHA{r4Ar%$@Rx6@YD z`05>2{tiMs<0yP2t}rmF>0V1AKZGaXS$1)%cQ z(9i%N=NDBvRo?+fW@McoZ~7kzJXRm=yYVkC!}jGWTD*SdV%p!E)FItyG5)EW;>V~z zhAfN+j7RtVua$!q+Sv$rLm?((!F0q12aqlX;Xs+ z&8^pqYF^xEmFf9mUw(B5M+B3Mt2*=T=>CpjKnV6HMECLb_I{Q|17v1^sSgIL5a(x2 zlYJ2p5dgKt!7ShcXmIiZfOBApnNpZH6+poZLhpexk4vZPWqbf{l!%Z}01ZIEV&{q3 z1=_+r9?!Wi)8~a+%hdU3N>)}ycWGf^s3qd+^-_YuCs&2#>w<*l74}(2Gch@3(?&0? zo}7>W6IWkD5f^p0A(WgjeCKki7zf6O{|jEvPDJ;dIQ$p?`G5rU@9y!uR{(s%|Nhe} z3amDwD6&4C&W3lk_9cTOA}d2?IvyBnL}9Qy>z|`vIHVR6pUYUXKe|I(xcT{^bdKqv z%qpIgQ9-C|8yIH_!SLgy5OB?Lf@3gnNJVgi8J9zV<$jq!MKy_hXX|?5=W1arZy$0y z?ggAzr77uS8pXY?_LrQ6w`L11281pC-HM=8V0$$xdRz$!hx{sKc=+LyRMG;$(X6GA zV186T$0epbW#L3A_N9cMJae^?ZJl(EP3eL9yS)sDZ+&1ETtM96-;T)d)cb=km;;j(oaZ*^3f;lED zHNbX`NywHUyK^D%`F+guH=reeU!o(#E@L1l$~{%(xORW55O0k>;grXXk`7mQtmkv2 z0agPsgm`J0a!fr|)-FyzAoG=lu)nyhlTbl@wTNLJQei>9;#ac$4*3UxC7I`)>R)b< zG24}9){dGgU2P!SxmR~JAV$JjYC4u2R*JUY`vy|*1rM0lAFZozb) zTfMuqXd0O+M7$Aj=u<&AbzT}(-p9WDM(;x-^`rd5H`X!hHZktq!-$B$kkEh6*44I* z=ks;25e5CzEK{!juc49B)u}MB&Ec3UmGbrL@aW}oYHv!x4w&Upw%7jl0G6T=$3bsP|YtcHHyhZHOg6*GgeDoIqZZEZ{Fy!Ay^yhgE6_9XrCs)|2 z9&0a1JnZZw^%%3Pem=sD;BU?c@ zR;xgf_SZZBAwXJ<`OdugrbQ1{`aIJqMlGJok34$Y`?=`JpIgL{^*+*FNjL=UiU9TB zy%k%^z?%gfLI#7R%iLl4w>!3#klueU^|F`~w$K@$ne(cuw#M-?m_+oc8r5yGjq;`) zynLOOro=ljRX%%mDYFbuIo2mBH?{kSTymmK_(2Gi^a1JemPg)Q+cP6o?JD+xiKRFZ z=ipoZpLj2$<@O6jzUf#un{})+`hZTj z2Mymifs87{=COH>KPAn*_dPRkMY);%=Ei#TfA6Xc!zU0ON8Zg1SyF(N`sf>O90My82c>@{**1Bk z_fJxdlB82+r%orloUYq!!-z`2=0Kh5&t6)}IPhr1BFhtzHE@^bRbinY{fRm=9Mz}e z05b5Wgo)62dlCn~Ur2DiQx$2z?vJm@g<-0m zBY=CyxH?gg%Ii?c+iU`CThCe52MN&3rNxvW?ooH8jBQZ!$;LReyh^%7^t>ttp5)=3 zVWQScevjTC!k)xxlk?j%$GnNu+f5IMq=xSgJG@d z!Fgw=kY-F9n;a9P3A~75p3rzF{&6-)ftNB2bq*waD6#cL-5C;Oj<%Ejd9^k3+dz%K zs0+1^b4l}Z-uCZvd%rYbm>WA72gfZP$K=l3Zs%6y`dU3~p+ z-g6uoxG*Y1nHn9ul&>Z+wTrTvqo%SI+e*r{qureNV;j~3eR&tCdHNRT?_1IVR3S|S zN=1fexFI=2MXx+Kx@)rD#$5zO4Jp!zK1Sf^&03L34m6kGC`!@XorShvWh?DJW9mbWMc$XHQzKx@8Qn$2H#M)jZ)TEIUxH&xCk4z&_-? zsm#>V5vJcJC^o;v8Zx`#rL-SdO5c;lP9_M^N@S?INvGy#KVxIz9FdH_xisWyZ zrt?Drq+kgWWXjcq-<>aLQo#$TRWEo)IYaY(nDZ4yR22<01u+flz(sSY1@GC{T^rd9 zoNmZKD>3cvlE!ACq{zn$>MM@`dbHSG^@>cWe>eKWQmo3^mN4VgZV2yVMbvxqPsz@r z)zyXP^EIWB4xb+JhN>L%BH@!ioQnB+2JuUadJ>zRDdq<*yX$+&jzUUby!4|XySz8@ zPVsmG^v!?Uk~qkH1=l}s-f?pz$=SAaabYJ(V%+?;G-i$<*?rB#NG&&7X9v@`p8-ef zb@P05ULGkQ3Vy$-Q?*;%o(ZYJoQAR%YN~~$CZLv)I!U%zxa$4K@rh=mjeuKqSX|+B zxGK&oXQqzqYA8}^P3(6ywJ}R@FP6z8WRKmH0s2oaOT>9Y&Gx-%b-=Y@<4x6dukD$D zQS$>Yd?v*1JVp%iP86)a5 z4A^U= z>QhI!@Sn`MUvFB5JBnOI^%&SU%hgV@Mfie$IrgS)8h8@hnMQPH;JmQ6eBf-ZXiFQ; zFmDI*U&uQ&|FV0ypL9q1&vng~P||h_qpYRli{EbnSza{&{AsZX7Y~ zEfC;Ng;?FCFwS=mv0ev+AdKfPC_?@*wL0CgUPsW-yLlrslD8H9UXRW*HGwj;dl!_4 z#wO#VVXbOus`6ha7f~Brdw&=xdlGLJ_)?b3eX}UNVM126=zzInt0)E1I|76m0tbda znKRH&`5*uaj%De|4D3QI*gw=HBaJaWF)Y=I5iBm@XFUh@{Ao(6>O09&WM&3RWGUYy z^gf4^D-+C2E0@CJrUf1eli1@6I#~B&w6}k<9e*h_ADYG&X#5jN9JI?<_k#Ueo2EM7 z%!RshuQ^$*6uu%A!vnaWod$Qf%A(hzdqXTlYb3Dx=#YV93roiH+$uX3ju_HkW&5ur z`o(D)iX%YfHjU4^SI?3AJhc57Lg=U3TV9v(*t%%>J+nD8ag@ZIcSm}3Bl#&=j$6#P zUJ`K#7aL)yw7WYhu#&kjU1>OM4oJr)A2U|B({ZddBHWnrX)0LpLS^2sdPrp52I<9-199bMy#6UR`q~nrnFRSXzW2;GHLo+&sz>O zK>Y$Oy<%;m)Xu}av88XQJU?ZFM64UW;;h;X>aUd*fz9s7_)yF+J3?ktg#`Ct$Ij#< zRdhpyvYnd<;nmU0wiV`B3_9=H$m!3H9;IEBwmWOSTqc!NM~2 z_-^LemDZfW$cJ*J@Z(CzfV={Ih(TYqw#Jwpw8#4Dzjlx#sN*TrYY%p((%ix-bLbJB zbyt-%y~uP*@;kGIpq`riTjgYHQAZbGkIop)pX}$5NSdaN2wxFm$SZ=Eg7zq+pLB0T zAvR;a#5Y_S(>nFKLh0#%7Ttm?R#QAlp#!6AkdG}7nf8PdJC#?&>8HX z4VW2CIO!?0v;?}c(f(j=I?$1NllF3ihS=udS5J9~u%MwIx>AiTRmCFRxWn;WDsN^~4F!Q2pJPp}mdIbeA&Pjdu0Nr2yTAF((YLsZub!3&*C*5t%p zaf?m(ic{Cm_KE63nt`f1E)fEu>m2j>SpZ+^_yBSscq!%E z6=T^i7~)s`Nk+fG8yYbOvEX1Tn=3izTI$&mVsPV1RL#}jPAMjn!Nsr-&SnKUR}XqT zxbE4+C8ADG!BTpgd}3zWv!9DHCtd8Oh_Al_xM#aWGORY1Wtq=y*XIrAI};hl>$H~v z?;TAOIpWP+bn>&+8@=XHH*ENMhYdK2ZW*m^(cREnU1FrjKM##Ld1wc?6RGG{hGsA> z-%|3Z;~gkJE^OrpR@*}crk&Laa33ra;S3U7({G8pwwX+qLZjfMt0Mg_Y#{l4gTRL& zASvI0{>J+0SjbN!RP_>x-7EN+WmyDd48%gSmird->TZ7Jq(K!uK>SRE*qW}%Z5c=? zDwxDfcWD-}iR(@);o(Ce#gPau^eass89G1k3!e2$1l}LPYwDjXvj5pbxQSTRwU#Hb z@5pM8uDsq+@@P%w;3O;lorjp}T6Ovo(=o(Pg0Rlt z3$6@gGa7Cogy_vU=b^dHwzhVX%g?ayNOi(K9NW|QUi9$)?!gkiJO=xY;sGOJVrrlV zjf~Y-jZ71*e*}-Xbw=i3G?!6~+^SX+>)KI3#tUlFIDA?2$@<1f`d%{mBm6)v>NG1f z$Na zC}>rfo~LyI`fO&>b7SN4OiNFGDk)+!h+~BZNu`K`vu7r5VOvs5c*Se#7=Zo*gwSe@ z$NTq}79tMXagK>Nl!Y!KM7=F+Jl>0T_YE0 zCWj3XhYaLwdYjEcZg^#PBxHB0tXi=*9H)vCMp=A5cazT#rJxN;pH_aY{B^! ztS~3m24v2*IrJ03As7@bpKqi&JVv4`uTpc&aTu@w>t@bI{N3cs6PnL{gN9L~J-x7F z#R+OCl}=UZ8}5-lq8*XHi(ZE2BR~O#M&u@3YFTy3H3DRbIBPTGgsqfw2%2gobjQx6 z6bw7|jcG`uA(>qmsPDbYzd0&{5)z=$97}G-E>l_s_CBZTr9;;Ehx{T1;5W7ZhgQ>NK(G- zPU<#kZb+q!;Y*Z^Gc%-_B}8?BD)KuUud@6$>^Sqb6$swH8fk>)cBYd4Wa>#gws@fu zP~37!FG0HJs9=YFs%?uTjLk)@%3AB+HD%>^Aj0iMb?>-o}|JS4XJCC@x~# z<4R6lzxK|UmW|>#U{2(X%}eC9S8`)Y=14@rW^Us3_c9ButI|+WH(nOqqB#PBddTcU zO0mK+56!Q|aiYH!%s3PSn>z=P>gQfvA*s4N?8>QHm}`iJu%D1DA~8k&)Zcb8b)yyg z`84nHrnKhx-Rd=6eW6RU#`Vfswkn<(GR_ zBa%CZqw}&SWj-OKm}Ql#Q%>X%?R>?tqBgj)XRZA=vHPkurQ5VF`lJp;okc=>ZQqGp zrKL8u8zDguu&<%%Jqf>Np>Dg$CLL0^9uCx=!ML#+>7h5&D+;}%wNG|oRU_)NeEM9XM{T;n0 zWE;c_FrO5k55IQ6XZS3HCKCr)BF1_#`C=YZ875}K(hj!Lfw!beY7QnX{1BdyJMDd> zVXz)5sb7j{%oNyJ3+)$&q6V_AiQvg}ynf$q8-xq!1E8Wo0vpMV#fU~cN(*ip?%)vU z#E7X)Km(?dz8_?({8+j6L%d35oO{>nDlRYpY{bOaPtq$_xWV3q|CTXUPRSI!a6}F@ zs#HUn&CAr-;lXMB-&!CGg9h|veyDF}YfB=h#Nb8Uk=@vCvN&nKJ{+qXp6@iiWuh=F z&^E-V6A8&sd|rrhqNtiwWEQUW!G0gk+zNeFb)T2mA%mT4E8mSO3(zHa+90$bp06)O z@7dmI6OZ;K&T04?k(kt}8F7V4kJVF4-pFaObFI1d{EC*>K1;63)Fdo5htv;uDio(i zMq?ZnmOZU?UmPJAJ6CR0j40A!Y9)DF(t*bx2;e`LCZyDAOOqjo*^F_w?v^@RoVWav zV>nl~W4eHAc-3evJ1-HI&_rc;z#o9iB|lxjMW2>T8MVZbwjmq3BhyHw@=DfrQQgec zWKt}Xb!p5;QWjIP%jfTMYeB%kfQzE#2D12?=c4Fnm(!BJGja)xL{*)KRQ-tOYe&8Q zSnV7=`KfNMtse}N{?)r70+tFq*1nI!3>v*EGQoE;*i{nn+vDyfM@*;E{eS|}f}r<= zfQ5jfd`S#T7Q^_~v-Db~apKTWc9f+mM=ljbvdXS1^-5rejADm2s#R$f#fW-IpZ;ex zO=;kjhGZ;e;<@&!zafi_$;d?wI?XqVSL{ZLozEA1`Fv$>SkQo}o(zQMNxwDSWGZg3 z?C8u?lAHEQjS=U(Sj`I zl7hC+s+vmc#8DsO8{09ao!C%6yf*!8J5bDoRx%cu(~GZ%{O?PA#;7JQ59)G>7dcHe^$h(GKZ^e~I*#6!+pNtL~9ym|7*O z%M^ciLJy42>zM?Zuzi7n0z-fZpDzy22;6;?XuH+gs)`xks9X&=^y~Yt=@+V-tczkb z3_Zk2<=y(ol7kDOMt*jP;EHLelQg<_)}<6WEUHeL_=?7vmFPRP@i$4jy2I8d^l`Xf znyzV|9f2RPfU`Tfj0D(tG}75e=4ztErlWwhc>55dRMKW&1jD2HGinyqg{ZiieX;b8 zi>BfFz7;tQbP;I`#TP#*!z8Um?VKvFwfJNd>UZ%Xy2U9dnaO#uOhb(?CjgeuS4Cuc z2rwT6lqV#bFN#kAM?4x=oX1&4mJXCI8H7`h%u0<@Y{b`)yrRbMSlMb9dyym`Ew>g$ zVKx4IDYU$DpU6b=|2N0z^9%pAQ?Rv+CD-jghGf{w%g&pX)K z({lL9VPfFM%CqPAn03>>daDdx+#(haU!-SnFr4W0d>k!PLu5z>p}g*?TmITlQB$%u z|Dr0j|BfJWGleVp;m}*L*1A=W7YkN|kFk|>LxRwO`Kp*IkAbv zgF4OJpOtn7VaFjbebNal%S&uCpY0=a-iHRMq@*KP=6txDv|(bLUp_NWA>ZBHS;AbB zo?O<@^Okz@93(+PWl^}m*T(~uXsCli`3Hm(9Y1yf!9kQ z*7~81TomO^TF^oLTFjDxMwZ2A+ydi`4<>)384xJPy!i`1!?RFmiJR}fo4W0~(36c@ ztFya0_wXYx%0<>!^nZov#(&mlN^oNkf?uc<*yumd+|-W%*@KfGv&Qmp;I9^J}^UjX>J54?PrMRRStD-m}Z3w@(m z7>gjZF(-rRZaLhLo-xFJiWF)h$OmxKFFTVvzp@ zJZw;cs=ka>!;2mrpLJ(}$A@3hAE~sc(%wrNq4CCs%1M0nG03UOOUvTFk{86miXx&V z3;3zJ{xO=3fbJOmb`TyJL{C^zV6pK5fexowc!MRHyAW!^%nBpvlfZkeKM&!V#s}>) zBf|LBs2OrY&u5z!>E%b(+04nCAp!WHHJqQ&$c3h~t>+EjEa?Z!%_0$m)N1@cqZnEQ zWsZLnkEvnd8EsXl!=wM=R(rgD6o0#&LJJ<^1$KgGpOwJ?+x2B>waBuu50+d7C|Pq4 z+ZoX=Gk*bmht`oGGOw+&{KW#OBgXc0z0dy5D=@lE47(S&XH}t&hMtfr&m8xAO3I9q zo!{5?*9?G%zJAU+*q~tdMerEk_O*M4^VyWXIr|)cYk2IBvv)r?O(l8RFpSl2(bo1= z(E9!xI+%W6ujuWT=vytT(<_iPWRmo6Q+&QR8&;j4c>?4x#jIo8eR~4FkeeF7v4K+6 z$G0re@guZWTP4vt7H0T#j<6`^{l#YAAPXZP2l@D+;o$F`zAnD-x!uO^g8#FIkRU=M zPOUMrDDN?3!qzF*nzrT-D9$00Y&+}q$*pohO?5g(2l47e7;(wYlGk~jJlq_~rm#rD z9NUnhy}E)OP#&6VHEnGO5?~PQAESB+zbls!Y7viSCegM;%<5XjhFe?l3*U9h%>vGt zX*xKaxV|hl6Vl;x;l^GoEe*ukVd>Jwah^nnr?eoQyOK1pTmF~#SbFg*)_#VkLe?@$ z@b8R<@TQQA&B{*>%5SOlGVAyyg)7E6NYNNmbX#MLDL=m3hfByQsx z67ok5Y;&qGSa924O9NhDI|#O!@hzD49$_#eZ)8CFqe~xIpRnqzKiqUIC~XqU)9XU7 z?<{%I8w8y-C>p4?1_AY-9Yn%_ zn3^Ac=PD}6Z&CU_$QQF51f+tn0ueD{KTDPr1uTiV^JGRR#z!JbDmg7?y`X)|gS!QZ zA8tn@pHGboJlymC2V^MxXP*2|X`kVzf*#HaE+5m4k%eYGeO8N|^zuHk_`$71zC8<9 zC%WwgAqE8p4r1h520@|V3wVbYt{Z&wR%B~~`2F$$8~5H6CEGuW6ZJ~qAr&Vodwp|J zfYsY7!9`fjRJ_XdWG>gu6&_B}q4VVtqM5Kh+;X3w`IrGe9L-sLsbBsI9u9c6=MVxU z=;2&iW4x46FAlL=)2rioCg4Q4MPVp(glwcei>#E}wXCgAv*R?pMG*cc$rzB!NY{=>gP64s>Dm5S;fJVW ztdDcjLQ z;nN$a7#OjD{O6T6FwO1+nAW$Jb~j+L$`W$bVZq(vz zyS15e1xcGejlj))z>SIx%S!GCDj0wb0ldqTj;{!t$E8Kz*Es=D5JFhq&6carC>b(eNcp09W`ZPdYdVi72y9~gv+90lTl9Q9&9&dK`9z3opQy

    `!+ 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%0DR{e^5F`FL;b6oTsA&Raie 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 diff --git a/frontend/__snapshots__/scenes-app-insights--user-paths-edit.png b/frontend/__snapshots__/scenes-app-insights--user-paths-edit.png index 1c01944a7c95c51611c7628deb14cf6f6eb6b0e2..df710f4dd46daa8b4fc1885a59ffd62ef58b6ab5 100644 GIT binary patch literal 173667 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 dr^4=^RbPB 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
    {featureSummary.description}

    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 V_g{Pe9eQz3Lq%5^u4ohS{{XYc3TOZT diff --git a/frontend/src/lib/components/PayGateMini/PayGateMini.tsx b/frontend/src/lib/components/PayGateMini/PayGateMini.tsx index 477fda2461dca..6c02869d74613 100644 --- a/frontend/src/lib/components/PayGateMini/PayGateMini.tsx +++ b/frontend/src/lib/components/PayGateMini/PayGateMini.tsx @@ -120,12 +120,12 @@ export function PayGateMini({

    - Subscribe to gain {featureSummary.umbrella}. + Subscribe to gain {featureSummary.umbrella}. {featureSummary.docsHref && ( <> {' '} - Learn more in PostHog Docs. + Learn more in PostHog Docs. )} diff --git a/package.json b/package.json index e98ba7d7b16d2..85796f23468b3 100644 --- a/package.json +++ b/package.json @@ -248,6 +248,7 @@ "eslint-plugin-eslint-comments": "^3.2.0", "eslint-plugin-jest": "^27.4.3", "eslint-plugin-no-only-tests": "^3.1.0", + "eslint-plugin-posthog": "link:./eslint-rules", "eslint-plugin-prettier": "^5.0.1", "eslint-plugin-react": "^7.33.2", "eslint-plugin-storybook": "^0.6.15", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 43ab2cbe9a530..ba38929ba6fa4 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1,4 +1,4 @@ -lockfileVersion: '6.1' +lockfileVersion: '6.0' settings: autoInstallPeers: true @@ -546,6 +546,9 @@ devDependencies: eslint-plugin-no-only-tests: specifier: ^3.1.0 version: 3.1.0 + eslint-plugin-posthog: + specifier: link:./eslint-rules + version: link:eslint-rules eslint-plugin-prettier: specifier: ^5.0.1 version: 5.0.1(eslint-config-prettier@9.0.0)(eslint@8.52.0)(prettier@2.8.8) From d6d259a117e131db8ab48a7a40d975547fbe0e57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Oberm=C3=BCller?= Date: Thu, 26 Oct 2023 13:27:17 +0200 Subject: [PATCH 21/21] feat(storybook): add theme toggle to storybook (#18123) --- .storybook/decorators/with3000.tsx | 20 -------- .storybook/decorators/withFeatureFlags.tsx | 8 ++-- .storybook/decorators/withKea/withKea.tsx | 4 +- .storybook/decorators/withMockDate.tsx | 4 +- .../decorators/withSnapshotsDisabled.tsx | 4 +- .storybook/decorators/withTheme.tsx | 44 ++++++++++++++++++ .storybook/preview.tsx | 19 ++++++++ ...sthog-3000-navigation--navigation-3000.png | Bin 0 -> 55596 bytes ...sthog-3000-navigation--navigation-base.png | Bin 0 -> 107231 bytes .../posthog-3000-navigation--navigation.png | Bin 0 -> 122335 bytes .../posthog-3000-sidebar--feature-flags.png | Bin 94464 -> 62321 bytes .../scenes-app-notebooks--headings.png | Bin 67039 -> 67041 bytes ...nes-app-notebooks--recordings-playlist.png | Bin 84057 -> 84062 bytes .../FeaturePreviewsModal.stories.tsx | 4 +- .../navigation-3000/Navigation.stories.tsx | 17 +++---- .../components/Sidebar.stories.tsx | 5 +- frontend/src/mocks/browser.tsx | 2 +- .../insights/__mocks__/createInsightScene.tsx | 4 +- .../NotebookSelectButton.stories.tsx | 4 +- 19 files changed, 89 insertions(+), 50 deletions(-) delete mode 100644 .storybook/decorators/with3000.tsx create mode 100644 .storybook/decorators/withTheme.tsx create mode 100644 frontend/__snapshots__/posthog-3000-navigation--navigation-3000.png create mode 100644 frontend/__snapshots__/posthog-3000-navigation--navigation-base.png create mode 100644 frontend/__snapshots__/posthog-3000-navigation--navigation.png diff --git a/.storybook/decorators/with3000.tsx b/.storybook/decorators/with3000.tsx deleted file mode 100644 index 67c13abade016..0000000000000 --- a/.storybook/decorators/with3000.tsx +++ /dev/null @@ -1,20 +0,0 @@ -import { useMountedLogic } from 'kea' -import { FEATURE_FLAGS } from 'lib/constants' -import { useEffect } from 'react' -import { themeLogic } from '~/layout/navigation-3000/themeLogic' -import { useFeatureFlags } from '~/mocks/browser' -import type { DecoratorFn } from '@storybook/react' - -/** Activate PostHog 3000. */ -export const with3000: DecoratorFn = (Story) => { - useFeatureFlags([FEATURE_FLAGS.POSTHOG_3000]) - useMountedLogic(themeLogic) - useEffect(() => { - document.body.classList.add('posthog-3000') - return () => { - document.body.classList.remove('posthog-3000') - } - }) - - return -} diff --git a/.storybook/decorators/withFeatureFlags.tsx b/.storybook/decorators/withFeatureFlags.tsx index 307c9f8943f16..752630fb4b400 100644 --- a/.storybook/decorators/withFeatureFlags.tsx +++ b/.storybook/decorators/withFeatureFlags.tsx @@ -1,5 +1,5 @@ -import { useFeatureFlags } from '~/mocks/browser' -import type { DecoratorFn } from '@storybook/react' +import { setFeatureFlags } from '~/mocks/browser' +import type { Decorator } from '@storybook/react' /** Global story decorator that allows setting feature flags. * @@ -13,9 +13,9 @@ import type { DecoratorFn } from '@storybook/react' * } as ComponentMeta * ``` */ -export const withFeatureFlags: DecoratorFn = (Story, { parameters }) => { +export const withFeatureFlags: Decorator = (Story, { parameters }) => { if (parameters.featureFlags) { - useFeatureFlags(parameters.featureFlags) + setFeatureFlags(parameters.featureFlags) } return diff --git a/.storybook/decorators/withKea/withKea.tsx b/.storybook/decorators/withKea/withKea.tsx index 6abad47e4b55c..67d41cb9339f2 100644 --- a/.storybook/decorators/withKea/withKea.tsx +++ b/.storybook/decorators/withKea/withKea.tsx @@ -1,9 +1,9 @@ -import type { DecoratorFn } from '@storybook/react' +import type { Decorator } from '@storybook/react' import { useAvailableFeatures } from '~/mocks/features' import { KeaStory } from './kea-story' -export const withKea: DecoratorFn = (Story) => { +export const withKea: Decorator = (Story) => { // Reset enabled enterprise features. Overwrite this line within your stories. useAvailableFeatures([]) return ( diff --git a/.storybook/decorators/withMockDate.tsx b/.storybook/decorators/withMockDate.tsx index d84e333871d77..0582d225a5f90 100644 --- a/.storybook/decorators/withMockDate.tsx +++ b/.storybook/decorators/withMockDate.tsx @@ -1,4 +1,4 @@ -import type { DecoratorFn } from '@storybook/react' +import type { Decorator } from '@storybook/react' import MockDate from 'mockdate' /** Global story decorator that allows mocking of dates. @@ -13,7 +13,7 @@ import MockDate from 'mockdate' * } as ComponentMeta * ``` */ -export const withMockDate: DecoratorFn = (Story, { parameters }) => { +export const withMockDate: Decorator = (Story, { parameters }) => { if (parameters.mockDate) { MockDate.set(parameters.mockDate) } else { diff --git a/.storybook/decorators/withSnapshotsDisabled.tsx b/.storybook/decorators/withSnapshotsDisabled.tsx index e2cd4e2edf906..6e7598c7a9c7e 100644 --- a/.storybook/decorators/withSnapshotsDisabled.tsx +++ b/.storybook/decorators/withSnapshotsDisabled.tsx @@ -1,9 +1,9 @@ -import { DecoratorFn } from '@storybook/react' +import { Decorator } from '@storybook/react' import { inStorybookTestRunner } from 'lib/utils' /** Workaround for https://github.com/storybookjs/test-runner/issues/74 */ // TODO: Smoke-test all the stories by removing this decorator, once all the stories pass -export const withSnapshotsDisabled: DecoratorFn = (Story, { parameters }) => { +export const withSnapshotsDisabled: Decorator = (Story, { parameters }) => { if (parameters?.testOptions?.skip && inStorybookTestRunner()) { return <>Disabled for Test Runner } diff --git a/.storybook/decorators/withTheme.tsx b/.storybook/decorators/withTheme.tsx new file mode 100644 index 0000000000000..1749a4244c497 --- /dev/null +++ b/.storybook/decorators/withTheme.tsx @@ -0,0 +1,44 @@ +import type { Decorator } from '@storybook/react' + +import { FEATURE_FLAGS } from 'lib/constants' + +/** Global story decorator that is used by the theming control to + * switch between themes. + */ +export const withTheme: Decorator = (Story, context) => { + const theme = context.globals.theme + + // set the body class + const actualClassState = document.body.classList.contains('posthog-3000') + const desiredClassState = theme !== 'legacy' + + if (actualClassState !== desiredClassState) { + if (desiredClassState) { + document.body.classList.add('posthog-3000') + } else { + document.body.classList.remove('posthog-3000') + } + } + + // set the feature flag + const actualFeatureFlagState = window.POSTHOG_APP_CONTEXT!.persisted_feature_flags?.includes( + FEATURE_FLAGS.POSTHOG_3000 + ) + const desiredFeatureFlagState = theme !== 'legacy' + + if (actualFeatureFlagState !== desiredFeatureFlagState) { + const currentFlags = window.POSTHOG_APP_CONTEXT!.persisted_feature_flags || [] + if (desiredFeatureFlagState) { + window.POSTHOG_APP_CONTEXT!.persisted_feature_flags = [...currentFlags, FEATURE_FLAGS.POSTHOG_3000] + } else { + window.POSTHOG_APP_CONTEXT!.persisted_feature_flags = currentFlags.filter( + (f) => f !== FEATURE_FLAGS.POSTHOG_3000 + ) + } + } + + // set the theme + document.body.setAttribute('theme', theme === 'dark' ? 'dark' : 'light') + + return +} diff --git a/.storybook/preview.tsx b/.storybook/preview.tsx index 9b0a76da1d367..091884046929e 100644 --- a/.storybook/preview.tsx +++ b/.storybook/preview.tsx @@ -10,6 +10,7 @@ import { withMockDate } from './decorators/withMockDate' import { defaultMocks } from '~/mocks/handlers' import { withSnapshotsDisabled } from './decorators/withSnapshotsDisabled' import { withFeatureFlags } from './decorators/withFeatureFlags' +import { withTheme } from './decorators/withTheme' const setupMsw = () => { // Make sure the msw worker is started @@ -86,6 +87,8 @@ export const decorators: Meta['decorators'] = [ withMockDate, // Allow us to easily set feature flags in stories. withFeatureFlags, + // Set theme from global context + withTheme, ] const preview: Preview = { @@ -110,6 +113,22 @@ const preview: Preview = { ), }, }, + globalTypes: { + theme: { + description: '', + defaultValue: 'legacy', + toolbar: { + title: 'Theme', + items: [ + { value: 'legacy', icon: 'faceneutral', title: 'Legacy' }, + { value: 'light', icon: 'sun', title: 'Light' }, + { value: 'dark', icon: 'moon', title: 'Dark' }, + ], + // change the title based on the selected value + dynamicTitle: true, + }, + }, + }, } export default preview diff --git a/frontend/__snapshots__/posthog-3000-navigation--navigation-3000.png b/frontend/__snapshots__/posthog-3000-navigation--navigation-3000.png new file mode 100644 index 0000000000000000000000000000000000000000..d3cf126326368809b32f1b349f1c3935a51233b7 GIT binary patch literal 55596 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 literal 0 HcmV?d00001 diff --git a/frontend/__snapshots__/posthog-3000-navigation--navigation-base.png b/frontend/__snapshots__/posthog-3000-navigation--navigation-base.png new file mode 100644 index 0000000000000000000000000000000000000000..0f29fe159698fcac6a8dc454a8fc0034cb65757f GIT binary patch literal 107231 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 literal 0 HcmV?d00001 diff --git a/frontend/__snapshots__/posthog-3000-navigation--navigation.png b/frontend/__snapshots__/posthog-3000-navigation--navigation.png new file mode 100644 index 0000000000000000000000000000000000000000..6cbf8a3a5b0340b80d32afb9fe63b953ed6b4b2f GIT binary patch literal 122335 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 a8uqA~{#tfrkJcyf74p=KgIy_ae)>26NAw;5 literal 94464 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 OHf`9xKF8eUKcX!utKhF8@ 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⪙n$M-|zxGb7z*b^a_UVz{!vk^yjO;TF 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 U+uD5Y7734Z>2oKOq%OMtKgJ+Ul>h($ delta 49872 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 diff --git a/frontend/__snapshots__/scenes-app-notebooks--recordings-playlist.png b/frontend/__snapshots__/scenes-app-notebooks--recordings-playlist.png index 44e5a61e789a25d3d0eedceb7303b89374a9e0e4..fc45aca0387a32d8a478460c6992a26bf91b669b 100644 GIT binary patch literal 84062 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

    5tdpWUC*wMj%OLn8fhI(NYUnt*x&0`LR9OUQ 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 z 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

    _+I;lNIT@ zO+H{c`i!(gLPDOXRT&PlT zTKZVbto%~C+4(Tz;B=H~;NsD6hm|lyNEd1E`N~``tw*dimP()#HwAh`14@$>hqjt1 zJGPe${S)u%{rhXnK>bepKc77}ezi@+h($q2Ooll|630ep#o5&#Sby2Fc(Om1(^V@F z9=OsHz!H_(ifhlb-O$tXWsj$M$uRoVnG&sOmreL?n}+q6+-(2l?`4uw+uhlKYYgwX z4-|VghGE5g4E$@QcU}R9-dY(OTPK@nSZXb#M`@jUW;~cNE0?42S7%j%ufh-xO|R|N zgnP6TptaXJ92YZ`fA3~ZhAs3DiKOFk``h|yeY7ijaNzCu`YG<<2u-O->K)sx{zw}{4 zKf&>>(e5-LNYZWR8Y`@)VqE9EV@F0t1Uravp(iIN#s`ak>aTX|&abY9;Zk_2g&M|A zvTyhNpm#Sspt;8n95)BZwPoYk0|37tO4*hQy^S{?&K|6?*1SC4Fg!e9kB*P;JY4DC zm}?TTo~kkicfUTJvV}0|Hj;to1dY(+6(C#>D=ub9trl z;N|Td62Ze^>jwfXH0)zM^1#Fdv2R5MCwzyE%{4eYe6>A{bbG3r($`{i8Up(K4_sVa zDr|0Y8?WIJ!e5e;$=CXl8J$SkIm*GoW6+h|7026acR)0n4QGe>XdbQhs+Z^qQ%hpA z9AEh32dr&xe+#R`fr5rm6Ii7Yp3EzsJXtAoET~=Q@~5{q>|_hERju9RlMJ*i9B%vb zf-7fxbN$iuN@imP#FWr$Hn{{&{jO+wGT!e;dBElT01>IlX)zM)ezZDRYA7Xqy)SmU zJz=P<25^gEM>q|@!89^4^Sdb=yR6jIet^}27k~TqO|;q=%-wx-0deT)po20B^kBad zFn+zMxtXhjuTM@?{}%Q?Jr3F|DjCwlgg4nVFO;*EDa;<$;WAQYYI1*Jp%W`d?dq?? zTZ^9XeA@1fB3D13?>c`lwm+*@vV^zvYw_{IMjk#Xnx!ymgazLfd&T!?gKJnim+)+4 zmDMyFN2Ah%l7J{G88ngjTQXB4%~wvx5Ak@`&w~#gZRU!QD@h3DKjR8Z@8ySGVd`dQ zK0Vd(sl_z8g&-wIpK|@gdLr@}zUJ7)bb~`-{$Q>Vtxv_FDzVP>DxyV(12*fWEB_^B zM}LxMzfIB@ilg@FH2v@fE(hDoUmkWhIY6~@^;4h~y_sa)(L|5(`2`n*M?iG29>e_cTX4(O@YChK0LC~6vUO^9UVaru?Xka*Wa0$y#mRaHjISJ zpf8EfX=f5PQEpo9b>VQs2K+_+@YZN^8YEC-Anv`7L?9O!SXy>(j^<<42O4+BC^mRF zoAf1x#Ksa)dLKVp>t|GWBQuLeC!h3pr8_pB+nVGFt?WGDGrf)nr3gg=MQ)Ct067G> z%n)!Hliq|sV}+W%F}n3`Y)5PTIi~$7J;?&Gs5m67&YQ~eDT41)g}nj$BiY2UJyDJZ z`hO{Iix{DkQFABC`Kof1gjE)!U%~UEqM@OM7J~vqd`0<%BjmyF_E~Cv{)CYcWl>R= z2LqWQ)r#>wJ+h!aExMa%Zx2j+Zp>?KVDJLK15gidoaHMsBqb$*`kvXz)4;&sTi?lY z)D1DKp6~4%@NG+EaC8bsA>cb{v!VYnyJhl!;?Q@w~*+a8ULR&nm ziekjusvs{`=3LjV-V)&9o!V10x+-6aDDYM(t~{7IZPWav83>Md zP{MKT=F*g;v|fDkqP(p|)@<_C7!B(`Iw4tM6p5)=$>|-)NdJf$U4^2>*7OPWRYO`U zwcZ$GSAWA)+lX!SP710*>@Nz|yWS*^eqBGBM5iJeFrhWFK?Hy6W zCcWygJXuor@Mb38Y-M-#hY7(bbb|WcOs#fR36twhhPqFg?aq4FO4pt_&O!+GYbdXu zz$-Sgo|lxX^kH;0%}jnTJ{4xYp;_^4%9dv78i<-7&NVx$dR}Sy%YHuMh)jT3zoH>V zO68Z6na=Uo-dCLn_GVIQy{)%dJj+!9?q@{D37vblPn~SbM~iWe+8O6eMb=_%6j$jg zGJ#)xzD^BA*t9kmu`ai`3y3_Z;{M~|_Bpb_6!33rJJoYzclB-u1__+ztpIc?<|%`| zUkGrZQkNZ#8?V~``c%{PAr`Yn#X$ee3`jJub?QIOQ(jM1n73uVkAh_JXaT$Dby~;o zP2{Ow_hw~hk8Ey!lj3#w9&&wiQ(D;@j|JA-@%8iJh?N6Kd(?tPxxUo|R7s4g1!=k> z!`h#v!pYu)OmHG}0J_kBK|17f*?txweEG`9#|OAl&{~Qo?uQ4>9h6WqDX9)GN;H|G zj=sL|*V?}z1GSE(H)jA%-OfleK>$I*gEdK|8#a3VT8>H9AL8x8-MH((~co&HF4 zxoxgVC@6w#bzniH_TUT$B&Y-HlXoGgz7Rh&Jd=%~EU=Jnpa}})ww;x2^0_G~?YyGj zX$`;vKrUUC5hGX!N+T#`tX~ z%GLDE6jsFeUVT_ zTbOiMNEjj%D@4T%BgZsZA2Kl@UiD+HLE!K?quD|9!Rhsv z?rYBc)Fba?G;-%Cif__PT@97LgWo129aHHsNBpcm6s6qWk$x`34$su-<|c_dqs2}^ znJeh6n~Owz4d3z zh1nyuBCT|QeeRQq6lE{5`v_283a$xyUsfo32WnK?SReZ&Cx(V%VPIf*U2fz6?dYZ_ zqe;YfOmuWTfE9kXw?C$&><8=m+?K+44!yCl37mw0If~oRBsc&G5H2Gl<4?8X!23ly zH(Zt;169_ff0f7WA%XV;IUiZUjpJ)4>Q91AA+T&FUR<^%Z4&gf_q-=KPr&+Giqqb%FTAz*qMJxuivh2;q2G7Epqtj zzLPJz)NG&F03)IzqH+etP0a6Bwr|}zw1V?$;e`X8=!`jEKzEs}EfqpFTb z_CQ)eoI4EVMyN|5J2r!R=EGF#CeNIYZ|h=M zS0=t}mHMj)M`b)+nblwrK&ih_u*wUB(%fjE(kzpl=-vJnZs&`XC?Ne85+>VE#L^mflNd)cSBB2!1E z58kyV!U=$cuICPy$MJg0XJj;9kKItd9dH_Z(L(>=Pu8 zd{@1-t<4WC^s?Wde|x$o@+MWdff&^HV9TEfk=u8Gac5~m!wWP39q}lIQyzX{AYA|` z>ihTa?>rM`R>s`8S_F9ruj6_Z_Ig$_+o6kg6Re3O`m zO>8|eP}B3nv7K_!l;v}~vtw&+ENaX7BYYRkSD1Y>TYoEI^j( z6IE4}k8|2AyWofKwH{zed(sLfm){%_ba6?{^~M`+yA`>Qg{P?g?aLOZ63^69@iiotTR%7k78~q4c-g%3K1y{JwJZRSzL@A z>Vxcd$M~tV!3{~ze3s*b$Ml91KL|sGP&@&*{j|aFh%d8iOzu$jEJe5^SWVVtrnxKe z3o}3MtOZC5aVdpmqiE&s2N;wu#=w?9$u3VBw{q*JWm7xlb-4V#zMh>CCx?`BnfxZy~2M7Mv54HZN?`c#6Q2>5cM@|+VuFB7W zG#~G2%eZH7by1*q4THm}0q@$!as77yi>1E#9=Ed@qSm?YnShd3TwI*h!>Mn4=$A$fgVsaK=d4j?bsls zw}Ha0*5}3}z2Ep1Ab%1EU1e6dtOGT|GF{P}GJD25Bqe9)R^wRt zF0VqFmJtGj-)lY3Ha{2-{y?lUAg)&!+z!OXYY^vd5f)trYyzRB&2IX8){4=p=V}SX z#vgX?3e=8ls+YNtv-cvh&Q8Z>k}l`8(h6jSCiR}?(pZ;NBU1f^|7t^^2xG4&$xhdmtqK#}$ktTFg0 z@|vIj*C&M1z*QPpu|HX1E}O*r1JIuPTg6Rfu6wf&+N8x0McRg7rnYAr63^zKsrQov zVnZUcZn=q^&)tn{mCa1o<;hk&yRmeN&Nn0^B>%ubhs$I02M-?fj6}y~A(nP``}Ugd z`Wn5nDqchb;sG;D+yeqmT@;PAcXV8uvTb6URIPKd4qa`ub9FTZq0Qt>bBJQatI}K-rbYJr+L>P3D@7O+e@6${Rki(;NgsbI>3Z(2X!6PJAiyx0`_^oNZ-xF zgWYyk5KdJOP@HkgmxoLm6~W*iK7jHj4pfa`VEUC(tE+jy*-PMEvjG!EOGH60uL*cH zNkAolRiy^tGAJl0tXAW!KIaQ)q5V;bfE^1J=D54FvLBydaQss^Vea!8^F!dc_X)07 z=>s1D$cY8L2q|vE)<$sw$<+m>@wip51?v^pda^46UBYM(k5nt&ou7|(v;;Df@q5kN zC+KHS^d|_jdH~#Kz;9$PZ+>T&TlW3Uu8yN{SoBUy`u?%4c2#FdZ3hG+gWddMqt}tEFCGbScx-l^4VAyysCFWIG!WkPmw^IH8DPP5X^g z_%!r=SJyzX7mB`2OM}Hiad`<~$LM>bsj4}TObGsfrpAwG5A*R|GMbI!G{h4HKj)sMPl0)|zm6OR8++4ymSYzO5C-3_wE^1x=t1E%U)kwM#=gBEHdw{1~v})u!Z$ejFEZS zgfTMvr1nry?PL_@RT*dOZvGJ+y`$JqJ@}>iz`+X{X#WhaVH@JTY zAGJ`pe8qxy<9HWyOQ43Cn&6iE3oa5&V%g&(B7>TP`yV^4gjpZ2K&bQvWL121`rg^W zgK|&4vIaI2x?W- z%|*Jh>+`cloJTM1o}*XGRvZ8`OgppNhJ`n=JO7~EG-&@eTT+WOVw)e!+}LSYZd
    e*z5#~;k=2&OEoiBrcpy?!uj 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 s*p$Y+{^Hu-l2R`H)|KPCgY~QA = ({ earlyAccessFeatures, enabledFeatureFlag 'https://app.posthog.com/api/early_access_features/': { earlyAccessFeatures }, }, }) - useFeatureFlags(enabledFeatureFlags) + setFeatureFlags(enabledFeatureFlags) return (

    diff --git a/frontend/src/layout/navigation-3000/Navigation.stories.tsx b/frontend/src/layout/navigation-3000/Navigation.stories.tsx index a46783d69faba..e843af7e75f5f 100644 --- a/frontend/src/layout/navigation-3000/Navigation.stories.tsx +++ b/frontend/src/layout/navigation-3000/Navigation.stories.tsx @@ -1,13 +1,10 @@ import { Meta } from '@storybook/react' -import { mswDecorator } from '~/mocks/browser' +import { mswDecorator, setFeatureFlags } from '~/mocks/browser' import { useEffect } from 'react' import { router } from 'kea-router' import { urls } from 'scenes/urls' import { App } from 'scenes/App' import { EMPTY_PAGINATED_RESPONSE } from '~/mocks/handlers' -import { useActions } from 'kea' -import { themeLogic } from './themeLogic' -import { with3000 } from 'storybook/decorators/with3000' const meta: Meta = { title: 'PostHog 3000/Navigation', @@ -21,7 +18,6 @@ const meta: Meta = { '/api/projects/:team_id/session_recordings/': EMPTY_PAGINATED_RESPONSE, }, }), - with3000, ], parameters: { layout: 'fullscreen', @@ -30,21 +26,20 @@ const meta: Meta = { }, } export default meta -export function LightMode(): JSX.Element { - const { overrideTheme } = useActions(themeLogic) + +export function NavigationBase(): JSX.Element { + setFeatureFlags(['posthog-3000']) useEffect(() => { router.actions.push(urls.projectHomepage()) - overrideTheme(false) }, []) return } -export function DarkMode(): JSX.Element { - const { overrideTheme } = useActions(themeLogic) +export function Navigation3000(): JSX.Element { + setFeatureFlags(['posthog-3000', 'posthog-3000-nav']) useEffect(() => { router.actions.push(urls.projectHomepage()) - overrideTheme(true) }, []) return diff --git a/frontend/src/layout/navigation-3000/components/Sidebar.stories.tsx b/frontend/src/layout/navigation-3000/components/Sidebar.stories.tsx index 4176e5a156a15..0927f46babe33 100644 --- a/frontend/src/layout/navigation-3000/components/Sidebar.stories.tsx +++ b/frontend/src/layout/navigation-3000/components/Sidebar.stories.tsx @@ -7,8 +7,8 @@ import { navigation3000Logic } from '../navigationLogic' import { Sidebar } from './Sidebar' import featureFlagsJson from '../../../scenes/feature-flags/__mocks__/feature_flags.json' import dashboardsJson from '../../../scenes/dashboard/__mocks__/dashboards.json' -import { with3000 } from 'storybook/decorators/with3000' import { SidebarNavbarItem } from '../types' +import { setFeatureFlags } from '~/mocks/browser' const meta: Meta = { title: 'PostHog 3000/Sidebar', @@ -17,7 +17,6 @@ const meta: Meta = { layout: 'fullscreen', viewMode: 'story', }, - decorators: [with3000], } export default meta /** featureFlagsJson * 6 to fill the sidebar up more. */ @@ -33,6 +32,7 @@ const multipliedFeatureFlagsJson = { } export function Dashboards(): JSX.Element { + setFeatureFlags(['posthog-3000', 'posthog-3000-nav']) useStorybookMocks({ get: { '/api/projects/:team_id/dashboards/': dashboardsJson, @@ -52,6 +52,7 @@ export function Dashboards(): JSX.Element { } export function FeatureFlags(): JSX.Element { + setFeatureFlags(['posthog-3000', 'posthog-3000-nav']) useStorybookMocks({ get: { '/api/projects/:team_id/feature_flags/': multipliedFeatureFlagsJson, diff --git a/frontend/src/mocks/browser.tsx b/frontend/src/mocks/browser.tsx index adf00a8cc8125..6baf8552fa047 100644 --- a/frontend/src/mocks/browser.tsx +++ b/frontend/src/mocks/browser.tsx @@ -30,6 +30,6 @@ export const mswDecorator = (mocks: Mocks): DecoratorFunction => { } } -export const useFeatureFlags = (featureFlags: string[]): void => { +export const setFeatureFlags = (featureFlags: string[]): void => { ;(window as any).POSTHOG_APP_CONTEXT.persisted_feature_flags = featureFlags } diff --git a/frontend/src/scenes/insights/__mocks__/createInsightScene.tsx b/frontend/src/scenes/insights/__mocks__/createInsightScene.tsx index 302e148caf4ef..7326a262550eb 100644 --- a/frontend/src/scenes/insights/__mocks__/createInsightScene.tsx +++ b/frontend/src/scenes/insights/__mocks__/createInsightScene.tsx @@ -1,5 +1,5 @@ import { InsightModel } from '~/types' -import { useFeatureFlags, useStorybookMocks } from '~/mocks/browser' +import { setFeatureFlags, useStorybookMocks } from '~/mocks/browser' import { useEffect } from 'react' import { router } from 'kea-router' import { App } from 'scenes/App' @@ -27,7 +27,7 @@ export function createInsightStory( ], }, }) - useFeatureFlags([FEATURE_FLAGS.RETENTION_BREAKDOWN]) + setFeatureFlags([FEATURE_FLAGS.RETENTION_BREAKDOWN]) useEffect(() => { router.actions.push(`/insights/${insight.short_id}${count}${mode === 'edit' ? '/edit' : ''}`) diff --git a/frontend/src/scenes/notebooks/NotebookSelectButton/NotebookSelectButton.stories.tsx b/frontend/src/scenes/notebooks/NotebookSelectButton/NotebookSelectButton.stories.tsx index 1baff1b2871f6..a68a60d9b5bdc 100644 --- a/frontend/src/scenes/notebooks/NotebookSelectButton/NotebookSelectButton.stories.tsx +++ b/frontend/src/scenes/notebooks/NotebookSelectButton/NotebookSelectButton.stories.tsx @@ -1,6 +1,6 @@ import { Meta, StoryFn } from '@storybook/react' import { NotebookSelectButton } from 'scenes/notebooks/NotebookSelectButton/NotebookSelectButton' -import { useFeatureFlags, useStorybookMocks } from '~/mocks/browser' +import { setFeatureFlags, useStorybookMocks } from '~/mocks/browser' import { NotebookNodeType } from '~/types' import { FEATURE_FLAGS } from 'lib/constants' @@ -37,7 +37,7 @@ const allNotebooks = [ ] const Template: StoryFn = (props) => { - useFeatureFlags([FEATURE_FLAGS.NOTEBOOKS]) + setFeatureFlags([FEATURE_FLAGS.NOTEBOOKS]) useStorybookMocks({ get: { '/api/projects/:team_id/notebooks/': (req, res, ctx) => {