Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .capy-cache/dependencies.sha256
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
8620910f03b78c62ebc5462fc6ef8351843f0a2525ee8213a01b0cfc28ba250b
19 changes: 19 additions & 0 deletions .capy-cache/docker-compose.capy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
services:
clickhouse:
mem_limit: !reset null
cpus: !reset null
proxy:
extra_hosts: !override
- 'plugins:host-gateway'
- 'capture:host-gateway'
- 'capture-ai:host-gateway'
- 'capture-logs:host-gateway'
- 'replay-capture:host-gateway'
- 'feature-flags:host-gateway'
- 'hypercache-server:host-gateway'
web:
image: caddy:latest
Comment thread
capy-ai[bot] marked this conversation as resolved.
Outdated
entrypoint: socat
Comment thread
capy-ai[bot] marked this conversation as resolved.
Outdated
command: ['TCP-LISTEN:8000,fork,reuseaddr', 'TCP:host.docker.internal:8011']
extra_hosts:
- 'host.docker.internal:host-gateway'
36 changes: 36 additions & 0 deletions frontend/src/generated/core/api.schemas.ts

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

37 changes: 37 additions & 0 deletions frontend/src/generated/core/api.ts

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

108 changes: 104 additions & 4 deletions frontend/src/scenes/data-management/definition/DefinitionView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,15 @@ import ViewRecordingsPlaylistButton from 'lib/components/ViewRecordingButton/Vie
import { FEATURE_FLAGS } from 'lib/constants'
import { LemonButton } from 'lib/lemon-ui/LemonButton'
import { LemonDialog } from 'lib/lemon-ui/LemonDialog'
import { LemonTable, LemonTableColumns } from 'lib/lemon-ui/LemonTable'
import { LemonTableLink } from 'lib/lemon-ui/LemonTable/LemonTableLink'
import { SpinnerOverlay } from 'lib/lemon-ui/Spinner/Spinner'
import { getPrimaryPropertyForEvent } from 'lib/utils/primaryEventProperty'
import { DefinitionLogicProps, definitionLogic } from 'scenes/data-management/definition/definitionLogic'
import {
DefinitionLogicProps,
PROPERTY_USAGE_EVENTS_PER_PAGE,
definitionLogic,
} from 'scenes/data-management/definition/definitionLogic'
import { EventDefinitionExperiments } from 'scenes/data-management/events/EventDefinitionExperiments'
import { EventDefinitionInsights } from 'scenes/data-management/events/EventDefinitionInsights'
import { EventDefinitionProperties } from 'scenes/data-management/events/EventDefinitionProperties'
Expand All @@ -28,6 +34,7 @@ import { LinkedHogFunctions } from 'scenes/hog-functions/list/LinkedHogFunctions
import { SceneExport } from 'scenes/sceneTypes'
import { urls } from 'scenes/urls'

import type { PropertyDefinitionEventUsageApi } from '~/generated/core/api.schemas'
import { SceneContent } from '~/layout/scenes/components/SceneContent'
import { SceneDivider } from '~/layout/scenes/components/SceneDivider'
import { SceneSection } from '~/layout/scenes/components/SceneSection'
Expand Down Expand Up @@ -122,11 +129,92 @@ function PrimaryPropertyDetail({ definition }: { definition: EventDefinition }):
)
}

function PropertyDefinitionUsageEvents({
events,
eventCount,
page,
loading,
onPageChange,
}: {
events: PropertyDefinitionEventUsageApi[]
eventCount: number
page: number
loading: boolean
onPageChange: (page: number) => void
}): JSX.Element {
const columns: LemonTableColumns<PropertyDefinitionEventUsageApi> = [
{
title: 'Event',
key: 'name',
render: function renderName(_, event) {
const title = getFilterLabel(event.name, TaxonomicFilterGroupType.Events) || event.name

return event.id ? (
<LemonTableLink to={urls.eventDefinition(event.id)} title={title} description={event.name} />
) : (
<span>{title}</span>
)
},
},
{
title: 'Last seen',
key: 'last_seen_at',
render: function renderLastSeen(_, event) {
return event.last_seen_at ? (
<div className="whitespace-nowrap">
<TZLabel time={event.last_seen_at} />
</div>
) : (
<span className="text-secondary">—</span>
)
},
},
]

return (
<SceneSection
title="Events using this property"
description="Events where PostHog has seen this event property."
>
<LemonTable
id="property-definition-events-table"
data-attr="property-definition-events-table"
columns={columns}
dataSource={events}
loading={loading}
pagination={{
controlled: true,
currentPage: page,
entryCount: eventCount,
pageSize: PROPERTY_USAGE_EVENTS_PER_PAGE,
onForward:
page * PROPERTY_USAGE_EVENTS_PER_PAGE < eventCount ? () => onPageChange(page + 1) : undefined,
onBackward: page > 1 ? () => onPageChange(page - 1) : undefined,
}}
rowKey="name"
nouns={['event', 'events']}
emptyState="No events use this property yet"
/>
</SceneSection>
)
}

export function DefinitionView(props: DefinitionLogicProps): JSX.Element {
const logic = definitionLogic(props)
const { definition, definitionLoading, definitionMissing, singular, isEvent, isProperty, metrics, metricsLoading } =
useValues(logic)
const { deleteDefinition } = useActions(logic)
const {
definition,
definitionLoading,
definitionMissing,
singular,
isEvent,
isProperty,
metrics,
metricsLoading,
propertyUsageEvents,
propertyUsageEventsLoading,
propertyUsageEventsPage,
} = useValues(logic)
const { deleteDefinition, setPropertyUsageEventsPage } = useActions(logic)

const memoizedQuery = useMemo(() => {
const columnsToUse =
Expand Down Expand Up @@ -434,6 +522,18 @@ export function DefinitionView(props: DefinitionLogicProps): JSX.Element {
</SceneSection>
</>
)}

{isProperty && definition.id !== 'new' && (
<>
<PropertyDefinitionUsageEvents
events={propertyUsageEvents.results}
eventCount={propertyUsageEvents.count}
page={propertyUsageEventsPage}
loading={propertyUsageEventsLoading}
onPageChange={setPropertyUsageEventsPage}
/>
</>
)}
</SceneContent>
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,15 @@ describe('definitionLogic', () => {
useMocks({
get: {
'/api/projects/:team/event_definitions/:id': mockEventDefinitions[0],
'/api/projects/:team/event_definitions/:id/metrics/': {},
'/api/projects/:team/object_media_previews': { results: [] },
'/api/projects/:team/property_definitions/:id': mockEventPropertyDefinition,
'/api/projects/:team/property_definitions/:id/events/': {
count: 1,
results: [
{ id: mockEventDefinitions[0].id, name: mockEventDefinitions[0].name, last_seen_at: null },
],
},
},
})
initKeaTests()
Expand Down Expand Up @@ -49,9 +57,24 @@ describe('definitionLogic', () => {
router.actions.push(urls.propertyDefinition('1'))
logic = definitionLogic({ id: '1' })
logic.mount()
await expectLogic(logic).toDispatchActions(['loadDefinition', 'loadDefinitionSuccess']).toMatchValues({
definition: mockEventPropertyDefinition,
})
await expectLogic(logic)
.toDispatchActions([
'loadDefinition',
'loadDefinitionSuccess',
'setPropertyUsageEventsPage',
'loadPropertyUsageEvents',
'loadPropertyUsageEventsSuccess',
])
.toMatchValues({
definition: mockEventPropertyDefinition,
propertyUsageEvents: {
count: 1,
results: [
{ id: mockEventDefinitions[0].id, name: mockEventDefinitions[0].name, last_seen_at: null },
],
},
propertyUsageEventsPage: 1,
})
})

it('load new definition on mount', async () => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
import { actions, afterMount, kea, key, listeners, path, props, reducers, selectors } from 'kea'
import { actions, afterMount, connect, kea, key, listeners, path, props, reducers, selectors } from 'kea'
import { loaders } from 'kea-loaders'
import { router } from 'kea-router'

import api from 'lib/api'
import { TaxonomicFilterGroupType } from 'lib/components/TaxonomicFilter/types'
import { lemonToast } from 'lib/lemon-ui/LemonToast/LemonToast'
import { Scene } from 'scenes/sceneTypes'
import { teamLogic } from 'scenes/teamLogic'
import { urls } from 'scenes/urls'

import { propertyDefinitionsEventsRetrieve } from '~/generated/core/api'
import type { PropertyDefinitionEventUsageResponseApi } from '~/generated/core/api.schemas'
import { updatePropertyDefinitions } from '~/models/propertyDefinitionsModel'
import { getFilterLabel } from '~/taxonomy/helpers'
import { Breadcrumb, Definition, EventDefinitionMetrics, ObjectMediaPreview, PropertyDefinition } from '~/types'
Expand All @@ -17,6 +20,8 @@ import { eventDefinitionsTableLogic } from '../events/eventDefinitionsTableLogic
import { propertyDefinitionsTableLogic } from '../properties/propertyDefinitionsTableLogic'
import type { definitionLogicType } from './definitionLogicType'

export const PROPERTY_USAGE_EVENTS_PER_PAGE = 100

export const createNewDefinition = (isEvent: boolean): Definition => ({
id: 'new',
name: `New ${isEvent ? 'Event' : 'Event property'}`,
Expand All @@ -36,10 +41,15 @@ export const definitionLogic = kea<definitionLogicType>([
path(['scenes', 'data-management', 'definition', 'definitionViewLogic']),
props({} as DefinitionLogicProps),
key((props) => props.id || 'new'),
connect(() => ({
values: [teamLogic, ['currentTeamIdStrict']],
})),
actions({
setDefinition: (definition: Partial<Definition>, options: SetDefinitionProps = {}) => ({ definition, options }),
loadDefinition: (id: Definition['id']) => ({ id }),
loadMetrics: (id: Definition['id']) => ({ id }),
loadPropertyUsageEvents: (id: Definition['id'], page = 1) => ({ id, page }),
setPropertyUsageEventsPage: (page: number) => ({ page }),
setDefinitionMissing: true,
loadPreviews: true,
createMediaPreview: (uploadedMediaId: string, metadata?: Record<string, any>) => ({
Expand All @@ -55,6 +65,12 @@ export const definitionLogic = kea<definitionLogicType>([
setDefinitionMissing: () => true,
},
],
propertyUsageEventsPage: [
1,
{
setPropertyUsageEventsPage: (_, { page }) => page,
},
],
})),
loaders(({ values, actions }) => ({
definition: [
Expand Down Expand Up @@ -116,6 +132,21 @@ export const definitionLogic = kea<definitionLogicType>([
},
},
],
propertyUsageEvents: [
{ count: 0, results: [] } as PropertyDefinitionEventUsageResponseApi,
{
loadPropertyUsageEvents: async ({ id, page }) => {
if (values.isEvent || !id || id === 'new') {
return { count: 0, results: [] }
}

return await propertyDefinitionsEventsRetrieve(String(values.currentTeamIdStrict), String(id), {
limit: PROPERTY_USAGE_EVENTS_PER_PAGE,
offset: (page - 1) * PROPERTY_USAGE_EVENTS_PER_PAGE,
})
},
},
],
previews: [
[] as ObjectMediaPreview[],
{
Expand Down Expand Up @@ -186,6 +217,13 @@ export const definitionLogic = kea<definitionLogicType>([
loadDefinitionSuccess: () => {
if (values.isEvent && values.definition.id && values.definition.id !== 'new') {
actions.loadPreviews()
} else if (values.isProperty && values.definition.id && values.definition.id !== 'new') {
actions.setPropertyUsageEventsPage(1)
}
},
setPropertyUsageEventsPage: ({ page }) => {
if (values.isProperty && values.definition.id && values.definition.id !== 'new') {
actions.loadPropertyUsageEvents(values.definition.id, page)
}
},
createMediaPreviewSuccess: () => {
Expand Down
Loading