Skip to content
This repository has been archived by the owner on Apr 29, 2024. It is now read-only.

Commit

Permalink
Merge remote-tracking branch 'upstream/master'
Browse files Browse the repository at this point in the history
* upstream/master:
  Sync and remove all non-FOSS parts
  fix: Use explicit encoding for exclude_events (#17302)
  feat(plugin-server): add new ValueMatcher<T> helper (#17226)
  chore(plugin-server): disable preflightSchedules on cloud roles (#17278)
  feat: Implement unpause/pause in BatchExportsListScene (#17299)
  feat: insight viz notebooks (#17290)
  chore: need the session being loaded (#17296)
  chore: report when falling back (#17293)
  • Loading branch information
karambir committed Sep 4, 2023
2 parents 3ae45f5 + 2329189 commit 0d04b3b
Show file tree
Hide file tree
Showing 18 changed files with 161 additions and 47 deletions.
9 changes: 8 additions & 1 deletion .storybook/test-runner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,14 @@ declare module '@storybook/types' {
}

const RETRY_TIMES = 5
const LOADER_SELECTORS = ['.ant-skeleton', '.Spinner', '.LemonSkeleton', '.LemonTableLoader', '[aria-busy="true"]']
const LOADER_SELECTORS = [
'.ant-skeleton',
'.Spinner',
'.LemonSkeleton',
'.LemonTableLoader',
'[aria-busy="true"]',
'.SessionRecordingPlayer--buffering',
]

const customSnapshotsDir = `${process.cwd()}/frontend/__snapshots__`

Expand Down
7 changes: 5 additions & 2 deletions frontend/src/scenes/batch_exports/BatchExportsListScene.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { SceneExport } from 'scenes/sceneTypes'
import { PageHeader } from 'lib/components/PageHeader'
import { LemonButton, LemonTable, Link } from '@posthog/lemon-ui'
import { urls } from 'scenes/urls'
import { useValues } from 'kea'
import { useActions, useValues } from 'kea'
import { batchExportsListLogic } from './batchExportsListLogic'
import { LemonMenu, LemonMenuItems } from 'lib/lemon-ui/LemonMenu'
import { IconEllipsis } from 'lib/lemon-ui/icons'
Expand Down Expand Up @@ -34,6 +34,7 @@ export function BatchExportsListScene(): JSX.Element {

export function BatchExportsList(): JSX.Element {
const { batchExportConfigs, batchExportConfigsLoading, pagination } = useValues(batchExportsListLogic)
const { unpause, pause } = useActions(batchExportsListLogic)

return (
<>
Expand Down Expand Up @@ -114,7 +115,9 @@ export function BatchExportsList(): JSX.Element {
{
label: batchExport.paused ? 'Resume' : 'Pause',
status: batchExport.paused ? 'primary' : 'danger',
onClick: () => {},
onClick: () => {
batchExport.paused ? unpause(batchExport) : pause(batchExport)
},
},
]
return (
Expand Down
29 changes: 28 additions & 1 deletion frontend/src/scenes/batch_exports/batchExportsListLogic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import api, { CountedPaginatedResponse } from 'lib/api'

import type { batchExportsListLogicType } from './batchExportsListLogicType'
import { PaginationManual } from 'lib/lemon-ui/PaginationControl'
import { lemonToast } from '@posthog/lemon-ui'

const PAGE_SIZE = 10
// Refresh the current page of exports periodically to see whats up.
Expand All @@ -27,7 +28,7 @@ export const batchExportsListLogic = kea<batchExportsListLogicType>([
],
}),

loaders(() => ({
loaders(({ values }) => ({
batchExportConfigs: [
null as null | CountedPaginatedResponse<BatchExportConfiguration>,
{
Expand All @@ -40,6 +41,32 @@ export const batchExportsListLogic = kea<batchExportsListLogicType>([
})
return res
},

pause: async (batchExport: BatchExportConfiguration) => {
await api.batchExports.pause(batchExport.id)
lemonToast.success('Batch export paused. No future runs will be scheduled')

const found = values.batchExportConfigs?.results.find((config) => config.id === batchExport.id)

if (found) {
found.paused = true
}

return values.batchExportConfigs
},

unpause: async (batchExport: BatchExportConfiguration) => {
await api.batchExports.unpause(batchExport.id)
lemonToast.success('Batch export unpaused. Future runs will be scheduled')

const found = values.batchExportConfigs?.results.find((config) => config.id === batchExport.id)

if (found) {
found.paused = false
}

return values.batchExportConfigs
},
},
],
})),
Expand Down
35 changes: 20 additions & 15 deletions frontend/src/scenes/notebooks/Nodes/NotebookNodeQuery.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import { Query } from '~/queries/Query/Query'
import { DataTableNode, NodeKind, QuerySchema } from '~/queries/schema'
import { DataTableNode, InsightVizNode, NodeKind, QuerySchema } from '~/queries/schema'
import { createPostHogWidgetNode } from 'scenes/notebooks/Nodes/NodeWrapper'
import { NotebookNodeType } from '~/types'
import { BindLogic, useMountedLogic, useValues } from 'kea'
import { insightLogic } from 'scenes/insights/insightLogic'
import { useValues } from 'kea'
import { useJsonNodeState } from './utils'
import { useMemo } from 'react'
import { notebookNodeLogic } from './notebookNodeLogic'
Expand All @@ -24,10 +23,7 @@ const DEFAULT_QUERY: QuerySchema = {

const Component = (props: NotebookNodeViewProps<NotebookNodeQueryAttributes>): JSX.Element | null => {
const [query] = useJsonNodeState<QuerySchema>(props.node.attrs, props.updateAttributes, 'query')
const logic = insightLogic({ dashboardItemId: 'new' })
const { insightProps } = useValues(logic)
const nodeLogic = useMountedLogic(notebookNodeLogic)
const { expanded } = useValues(nodeLogic)
const { expanded } = useValues(notebookNodeLogic)

const modifiedQuery = useMemo(() => {
const modifiedQuery = { ...query }
Expand All @@ -38,6 +34,12 @@ const Component = (props: NotebookNodeViewProps<NotebookNodeQueryAttributes>): J
modifiedQuery.full = false
modifiedQuery.showHogQLEditor = false
modifiedQuery.embedded = true
} else if (NodeKind.InsightVizNode === modifiedQuery.kind) {
modifiedQuery.showFilters = false
modifiedQuery.showHeader = false
modifiedQuery.showTable = false
modifiedQuery.showCorrelationTable = false
modifiedQuery.embedded = true
}

return modifiedQuery
Expand All @@ -48,11 +50,11 @@ const Component = (props: NotebookNodeViewProps<NotebookNodeQueryAttributes>): J
}

return (
<BindLogic logic={insightLogic} props={insightProps}>
<div className={clsx('flex flex-1 flex-col overflow-hidden')}>
<Query query={modifiedQuery} uniqueKey={nodeLogic.props.nodeId} />
</div>
</BindLogic>
<div
className={clsx('flex flex-1 flex-col', NodeKind.DataTableNode === modifiedQuery.kind && 'overflow-hidden')}
>
<Query query={modifiedQuery} uniqueKey={props.node.attrs.nodeId} />
</div>
)
}

Expand All @@ -75,6 +77,10 @@ export const Settings = ({
modifiedQuery.showHogQLEditor = true
modifiedQuery.showResultsTable = false
modifiedQuery.showReload = true
} else if (NodeKind.InsightVizNode === modifiedQuery.kind) {
modifiedQuery.showFilters = true
modifiedQuery.showResults = false
modifiedQuery.embedded = true
}

return modifiedQuery
Expand All @@ -85,10 +91,9 @@ export const Settings = ({
<Query
query={modifiedQuery}
setQuery={(t) => {
if (t.kind === NodeKind.DataTableNode) {
setQuery({ ...query, source: (t as DataTableNode).source } as QuerySchema)
}
setQuery({ ...query, source: (t as DataTableNode | InsightVizNode).source } as QuerySchema)
}}
readOnly={false}
uniqueKey={attributes.nodeId}
/>
</div>
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/scenes/notebooks/Notebook/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export type CustomNotebookNodeAttributes = Record<string, any>

export type NotebookNodeAttributes<T extends CustomNotebookNodeAttributes> = T & {
nodeId: string
title: string | null
title: string | ((attributes: T) => Promise<string>)
height?: string | number
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ export function SessionRecordingPlayer(props: SessionRecordingPlayerProps): JSX.
closeExplorer,
} = useActions(sessionRecordingPlayerLogic(logicProps))
const { isNotFound } = useValues(sessionRecordingDataLogic(logicProps))
const { isFullScreen, explorerMode } = useValues(sessionRecordingPlayerLogic(logicProps))
const { isFullScreen, explorerMode, isBuffering } = useValues(sessionRecordingPlayerLogic(logicProps))
const speedHotkeys = useMemo(() => createPlaybackSpeedKey(setSpeed), [setSpeed])

useKeyboardHotkeys(
Expand Down Expand Up @@ -149,6 +149,7 @@ export function SessionRecordingPlayer(props: SessionRecordingPlayerProps): JSX.
'SessionRecordingPlayer--widescreen': !isFullScreen && size !== 'small',
'SessionRecordingPlayer--inspector-focus': inspectorFocus,
'SessionRecordingPlayer--inspector-hidden': noInspector,
'SessionRecordingPlayer--buffering': isBuffering,
})}
onClick={incrementClickCount}
>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,10 @@ export const sessionRecordingDataLogic = kea<sessionRecordingDataLogicType>([
if (snapshots && !snapshots.length && sources?.length === 1) {
// We got the snapshot response for realtime, and it was empty, so we fall back to the old API
// Until we migrate over we need to fall back to the old API if the new one returns no snapshots
posthog.capture('recording_snapshots_v2_empty_response', {
source: sources[0],
})

actions.loadRecordingSnapshotsV1()
return
}
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/styles/vars.scss
Original file line number Diff line number Diff line change
Expand Up @@ -321,5 +321,5 @@ $_lifecycle_dormant: $_danger;

// Notebooks
--notebook-popover-transition-properties: 150ms cubic-bezier(0, 0.5, 0.5, 1);
--notebook-sidebar-width: 20rem;
--notebook-sidebar-width: 27rem;
}
1 change: 1 addition & 0 deletions plugin-server/src/capabilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ export function getPluginServerCapabilities(config: PluginsServerConfig): Plugin
sessionRecordingIngestion: true,
sessionRecordingBlobIngestion: true,
transpileFrontendApps: true,
preflightSchedules: true,
...sharedCapabilities,
}
case PluginServerMode.ingestion:
Expand Down
17 changes: 16 additions & 1 deletion plugin-server/src/config/config.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { LogLevel, PluginsServerConfig, stringToPluginServerMode } from '../types'
import { LogLevel, PluginsServerConfig, stringToPluginServerMode, ValueMatcher } from '../types'
import { isDevEnv, isTestEnv, stringToBoolean } from '../utils/env-utils'
import { KAFKAJS_LOG_LEVEL_MAPPING } from './constants'
import {
Expand Down Expand Up @@ -206,3 +206,18 @@ export function overrideWithEnv(
}
return newConfig
}

export function buildIntegerMatcher(config: string, allowStar: boolean): ValueMatcher<number> {
// Builds a ValueMatcher on a coma-separated list of values.
// Optionally, supports a '*' value to match everything
if (!config) {
return () => false
} else if (allowStar && config === '*') {
return () => true
} else {
const values = new Set(config.split(',').map((n) => parseInt(n)))
return (v: number) => {
return values.has(v)
}
}
}
4 changes: 3 additions & 1 deletion plugin-server/src/main/pluginsServer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -370,7 +370,9 @@ export async function startPluginsServer(

await pubSub.start()

startPreflightSchedules(hub)
if (capabilities.preflightSchedules) {
startPreflightSchedules(hub)
}

if (hub.statsd) {
stopEventLoopMetrics = captureEventLoopMetrics(hub.statsd, hub.instanceId)
Expand Down
5 changes: 5 additions & 0 deletions plugin-server/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,7 @@ export interface PluginServerCapabilities {
sessionRecordingIngestion?: boolean
sessionRecordingBlobIngestion?: boolean
transpileFrontendApps?: boolean // TODO: move this away from pod startup, into a graphile job
preflightSchedules?: boolean // Used for instance health checks on hobby deploy, not useful on cloud
http?: boolean
mmdb?: boolean
}
Expand Down Expand Up @@ -1143,3 +1144,7 @@ export type RRWebEvent = Record<string, any> & {
type: number
data: any
}

export interface ValueMatcher<T> {
(value: T): boolean
}
29 changes: 28 additions & 1 deletion plugin-server/tests/config.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { getDefaultConfig, overrideWithEnv } from '../src/config/config'
import { buildIntegerMatcher, getDefaultConfig, overrideWithEnv } from '../src/config/config'

describe('config', () => {
test('overrideWithEnv 1', () => {
Expand Down Expand Up @@ -64,3 +64,30 @@ describe('config', () => {
})
})
})

describe('buildIntegerMatcher', () => {
test('empty input', () => {
const matcher = buildIntegerMatcher('', false)
expect(matcher(2)).toBe(false)
})
test('ignores star star when not allowed', () => {
const matcher = buildIntegerMatcher('*', false)
expect(matcher(2)).toBe(false)
})
test('matches star when allowed', () => {
const matcher = buildIntegerMatcher('*', true)
expect(matcher(2)).toBe(true)
})
test('can match on a single value', () => {
const matcher = buildIntegerMatcher('2', true)
expect(matcher(2)).toBe(true)
expect(matcher(3)).toBe(false)
})
test('can match on several values', () => {
const matcher = buildIntegerMatcher('2,3,4', true)
expect(matcher(2)).toBe(true)
expect(matcher(3)).toBe(true)
expect(matcher(4)).toBe(true)
expect(matcher(5)).toBe(false)
})
})
31 changes: 18 additions & 13 deletions posthog/api/session_recording.py
Original file line number Diff line number Diff line change
Expand Up @@ -251,15 +251,18 @@ def _snapshots_v2(self, request: request.Request):
This path only supports loading from S3 or Redis based on query params
"""

event_properties = {"team_id": self.team.pk}

if request.headers.get("X-POSTHOG-SESSION-ID"):
event_properties["$session_id"] = request.headers["X-POSTHOG-SESSION-ID"]

recording = self.get_object()
response_data = {}
source = request.GET.get("source")
event_properties["request_source"] = source

event_properties = {
"team_id": self.team.pk,
"request_source": source,
"session_being_loaded": recording.session_id,
}

if request.headers.get("X-POSTHOG-SESSION-ID"):
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
Expand Down Expand Up @@ -365,13 +368,6 @@ def snapshots(self, request: request.Request, **kwargs):
if request.GET.get("version") == "2":
return self._snapshots_v2(request)

event_properties = {"team_id": self.team.pk}
if request.headers.get("X-POSTHOG-SESSION-ID"):
event_properties["$session_id"] = request.headers["X-POSTHOG-SESSION-ID"]
posthoganalytics.capture(
self._distinct_id_from_request(request), "v1 session recording snapshots viewed", event_properties
)

recording = self.get_object()

# TODO: Determine if we should try Redis or not based on the recording start time and the S3 responses
Expand All @@ -393,6 +389,15 @@ def snapshots(self, request: request.Request, **kwargs):
limit = filter.limit if filter.limit else DEFAULT_RECORDING_CHUNK_LIMIT
offset = filter.offset if filter.offset else 0

event_properties = {"team_id": self.team.pk, "session_being_loaded": recording.session_id, "offset": offset}

if request.headers.get("X-POSTHOG-SESSION-ID"):
event_properties["$session_id"] = request.headers["X-POSTHOG-SESSION-ID"]

posthoganalytics.capture(
self._distinct_id_from_request(request), "v1 session recording snapshots viewed", event_properties
)

# Optimisation step if passed to speed up retrieval of CH data
if not recording.start_time:
recording_start_time = (
Expand Down
Loading

0 comments on commit 0d04b3b

Please sign in to comment.