Skip to content

Commit

Permalink
feat(messaging): different types of hog functions (#25788)
Browse files Browse the repository at this point in the history
Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com>
  • Loading branch information
mariusandra and github-actions[bot] authored Oct 25, 2024
1 parent ab177f6 commit e72783b
Show file tree
Hide file tree
Showing 65 changed files with 440 additions and 87 deletions.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
14 changes: 10 additions & 4 deletions frontend/src/lib/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ import {
HogFunctionStatus,
HogFunctionTemplateType,
HogFunctionType,
HogFunctionTypeType,
InsightModel,
IntegrationType,
ListOrganizationMembersParams,
Expand Down Expand Up @@ -1744,7 +1745,10 @@ const api = {
},
},
hogFunctions: {
async list(params?: { filters?: any }): Promise<PaginatedResponse<HogFunctionType>> {
async list(params?: {
filters?: any
type?: HogFunctionTypeType
}): Promise<PaginatedResponse<HogFunctionType>> {
return await new ApiRequest().hogFunctions().withQueryString(params).get()
},
async get(id: HogFunctionType['id']): Promise<HogFunctionType> {
Expand Down Expand Up @@ -1774,9 +1778,11 @@ const api = {
): Promise<AppMetricsTotalsV2Response> {
return await new ApiRequest().hogFunction(id).withAction('metrics/totals').withQueryString(params).get()
},

async listTemplates(): Promise<PaginatedResponse<HogFunctionTemplateType>> {
return await new ApiRequest().hogFunctionTemplates().get()
async listTemplates(type?: HogFunctionTypeType): Promise<PaginatedResponse<HogFunctionTemplateType>> {
return new ApiRequest()
.hogFunctionTemplates()
.withQueryString({ type: type ?? 'destination' })
.get()
},
async getTemplate(id: HogFunctionTemplateType['id']): Promise<HogFunctionTemplateType> {
return await new ApiRequest().hogFunctionTemplate(id).get()
Expand Down
1 change: 1 addition & 0 deletions frontend/src/scenes/actions/ActionHogFunctions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ export function ActionHogFunctions(): JSX.Element | null {
) : null}

<LinkedHogFunctions
type="destination"
filters={filters}
newDisabledReason={
hasCohortFilters
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,7 @@ export function DefinitionView(props: DefinitionLogicProps = {}): JSX.Element {
<p>Get notified via Slack, webhooks or more whenever this event is captured.</p>

<LinkedHogFunctions
type="destination"
filters={{
events: [
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -331,6 +331,7 @@ export function EarlyAccessFeature({ id }: { id?: string } = {}): JSX.Element {
<h3>Notifications</h3>
<p>Get notified when people opt in or out of your feature.</p>
<LinkedHogFunctions
type="destination"
filters={destinationFilters}
subTemplateId="early_access_feature_enrollment"
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ export const pipelineDestinationsLogic = kea<pipelineDestinationsLogicType>([
{
loadHogFunctions: async () => {
// TODO: Support pagination?
return (await api.hogFunctions.list()).results
return (await api.hogFunctions.list({ type: 'destination' })).results
},

deleteNodeHogFunction: async ({ destination }) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,12 @@ import { HogFunctionTest, HogFunctionTestPlaceholder } from './HogFunctionTest'

const EVENT_THRESHOLD_ALERT_LEVEL = 8000

export function HogFunctionConfiguration({ templateId, id }: { templateId?: string; id?: string }): JSX.Element {
export interface HogFunctionConfigurationProps {
templateId?: string | null
id?: string | null
}

export function HogFunctionConfiguration({ templateId, id }: HogFunctionConfigurationProps): JSX.Element {
const logicProps = { templateId, id }
const logic = hogFunctionConfigurationLogic(logicProps)
const {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ const HOG_TEMPLATE: HogFunctionTemplateType = {
],
status: 'beta',
id: 'template-webhook',
type: 'destination',
name: 'HTTP Webhook',
description: 'Sends a webhook templated by the incoming event data',
hog: "let res := fetch(inputs.url, {\n 'headers': inputs.headers,\n 'body': inputs.body,\n 'method': inputs.method\n});\n\nif (inputs.debug) {\n print('Response', res.status, res.body);\n}",
Expand Down Expand Up @@ -170,6 +171,7 @@ describe('hogFunctionConfigurationLogic', () => {
expect(logic.values.template).toEqual(HOG_TEMPLATE)
expect(logic.values.configuration).toEqual({
name: HOG_TEMPLATE.name,
type: HOG_TEMPLATE.type,
description: HOG_TEMPLATE.description,
inputs_schema: HOG_TEMPLATE.inputs_schema,
filters: null,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,16 +46,17 @@ import { EmailTemplate } from './email-templater/emailTemplaterLogic'
import type { hogFunctionConfigurationLogicType } from './hogFunctionConfigurationLogicType'

export interface HogFunctionConfigurationLogicProps {
templateId?: string
subTemplateId?: string
id?: string
templateId?: string | null
subTemplateId?: string | null
id?: string | null
}

export const EVENT_VOLUME_DAILY_WARNING_THRESHOLD = 1000
const UNSAVED_CONFIGURATION_TTL = 1000 * 60 * 5

const NEW_FUNCTION_TEMPLATE: HogFunctionTemplateType = {
id: 'new',
type: 'destination',
name: '',
description: '',
inputs_schema: [],
Expand Down Expand Up @@ -118,6 +119,7 @@ const templateToConfiguration = (
})

return {
type: template.type ?? 'destination',
name: subTemplate?.name ?? template.name,
description: subTemplate?.name ?? template.description,
inputs_schema: template.inputs_schema,
Expand Down Expand Up @@ -403,6 +405,10 @@ export const hogFunctionConfigurationLogic = kea<hogFunctionConfigurationLogicTy
})),
selectors(() => ({
logicProps: [() => [(_, props) => props], (props): HogFunctionConfigurationLogicProps => props],
type: [
(s) => [s.configuration, s.hogFunction],
(configuration, hogFunction) => configuration?.type ?? hogFunction?.type ?? 'loading',
],
hasAddon: [
(s) => [s.hasAvailableFeature],
(hasAvailableFeature) => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,20 @@
import { LemonButton } from '@posthog/lemon-ui'
import { useState } from 'react'

import { HogFunctionFiltersType, HogFunctionSubTemplateIdType } from '~/types'
import { HogFunctionFiltersType, HogFunctionSubTemplateIdType, HogFunctionTypeType } from '~/types'

import { HogFunctionList } from './HogFunctionsList'
import { HogFunctionTemplateList } from './HogFunctionTemplateList'

export type LinkedHogFunctionsProps = {
type: HogFunctionTypeType
filters: HogFunctionFiltersType
subTemplateId?: HogFunctionSubTemplateIdType
newDisabledReason?: string
}

export function LinkedHogFunctions({
type,
filters,
subTemplateId,
newDisabledReason,
Expand All @@ -22,6 +24,7 @@ export function LinkedHogFunctions({
return showNewDestination ? (
<HogFunctionTemplateList
defaultFilters={{}}
type={type}
forceFilters={{ filters, subTemplateId }}
extraControls={
<>
Expand All @@ -34,6 +37,7 @@ export function LinkedHogFunctions({
) : (
<HogFunctionList
forceFilters={{ filters }}
type={type}
extraControls={
<>
<LemonButton
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { pipelineAccessLogic } from 'scenes/pipeline/pipelineAccessLogic'
import { teamLogic } from 'scenes/teamLogic'
import { userLogic } from 'scenes/userLogic'

import { HogFunctionType } from '~/types'
import { HogFunctionType, HogFunctionTypeType } from '~/types'

import type { hogFunctionListLogicType } from './hogFunctionListLogicType'

Expand All @@ -25,6 +25,7 @@ export type HogFunctionListFilters = {
}

export type HogFunctionListLogicProps = {
type: HogFunctionTypeType
defaultFilters?: HogFunctionListFilters
forceFilters?: HogFunctionListFilters
syncFiltersWithUrl?: boolean
Expand Down Expand Up @@ -68,14 +69,15 @@ export const hogFunctionListLogic = kea<hogFunctionListLogicType>([
},
],
})),
loaders(({ values, actions }) => ({
loaders(({ values, actions, props }) => ({
hogFunctions: [
[] as HogFunctionType[],
{
loadHogFunctions: async () => {
return (
await api.hogFunctions.list({
filters: values.filters?.filters,
type: props.type,
})
).results
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { objectsEqual } from 'lib/utils'
import { pipelineAccessLogic } from 'scenes/pipeline/pipelineAccessLogic'
import { urls } from 'scenes/urls'

import { HogFunctionTemplateType, PipelineStage } from '~/types'
import { HogFunctionTemplateType, HogFunctionTypeType, PipelineStage } from '~/types'

import type { hogFunctionTemplateListLogicType } from './hogFunctionTemplateListLogicType'

Expand All @@ -22,14 +22,15 @@ export type HogFunctionTemplateListFilters = {
}

export type HogFunctionTemplateListLogicProps = {
type: HogFunctionTypeType
defaultFilters?: HogFunctionTemplateListFilters
forceFilters?: HogFunctionTemplateListFilters
syncFiltersWithUrl?: boolean
}

export const hogFunctionTemplateListLogic = kea<hogFunctionTemplateListLogicType>([
props({} as HogFunctionTemplateListLogicProps),
key((props) => (props.syncFiltersWithUrl ? 'scene' : 'default')),
key((props) => `${props.syncFiltersWithUrl ? 'scene' : 'default'}/${props.type ?? 'destination'}`),
path((id) => ['scenes', 'pipeline', 'destinationsLogic', id]),
connect({
values: [pipelineAccessLogic, ['canEnableNewDestinations'], featureFlagLogic, ['featureFlags']],
Expand All @@ -53,12 +54,12 @@ export const hogFunctionTemplateListLogic = kea<hogFunctionTemplateListLogicType
},
],
})),
loaders(() => ({
loaders(({ props }) => ({
rawTemplates: [
[] as HogFunctionTemplateType[],
{
loadHogFunctionTemplates: async () => {
return (await api.hogFunctions.listTemplates()).results
return (await api.hogFunctions.listTemplates(props.type)).results
},
},
],
Expand Down
1 change: 1 addition & 0 deletions frontend/src/scenes/surveys/SurveyView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -403,6 +403,7 @@ export function SurveyView({ id }: { id: string }): JSX.Element {
<div>
<p>Get notified whenever a survey result is submitted</p>
<LinkedHogFunctions
type="destination"
subTemplateId="survey_response"
filters={{
events: [
Expand Down
1 change: 1 addition & 0 deletions frontend/src/scenes/surveys/Surveys.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,7 @@ export function Surveys(): JSX.Element {
<>
<p>Get notified whenever a survey result is submitted</p>
<LinkedHogFunctions
type="destination"
subTemplateId="survey_response"
filters={{
events: [
Expand Down
5 changes: 4 additions & 1 deletion frontend/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4505,8 +4505,11 @@ export interface HogFunctionFiltersType {
bytecode_error?: string
}

export type HogFunctionTypeType = 'destination' | 'email' | 'sms' | 'push' | 'activity' | 'alert' | 'broadcast'

export type HogFunctionType = {
id: string
type: HogFunctionTypeType
icon_url?: string
name: string
description: string
Expand Down Expand Up @@ -4543,7 +4546,7 @@ export type HogFunctionSubTemplateType = Pick<HogFunctionType, 'filters' | 'inpu

export type HogFunctionTemplateType = Pick<
HogFunctionType,
'id' | 'name' | 'description' | 'hog' | 'inputs_schema' | 'filters' | 'icon_url' | 'masking'
'id' | 'type' | 'name' | 'description' | 'hog' | 'inputs_schema' | 'filters' | 'icon_url' | 'masking'
> & {
status: HogFunctionTemplateStatus
sub_templates?: HogFunctionSubTemplateType[]
Expand Down
2 changes: 1 addition & 1 deletion latest_migrations.manifest
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ contenttypes: 0002_remove_content_type_name
ee: 0016_rolemembership_organization_member
otp_static: 0002_throttling
otp_totp: 0002_auto_20190420_0723
posthog: 0498_errortrackingissuefingerprint_and_more
posthog: 0499_hog_function_type
sessions: 0001_initial
social_django: 0010_uid_db_index
two_factor: 0007_auto_20201201_1019
2 changes: 1 addition & 1 deletion plugin-server/src/cdp/cdp-consumers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -548,7 +548,7 @@ export class CdpProcessedEventsConsumer extends CdpConsumerBase {
try {
const clickHouseEvent = JSON.parse(message.value!.toString()) as RawClickHouseEvent

if (!this.hogFunctionManager.teamHasHogFunctions(clickHouseEvent.team_id)) {
if (!this.hogFunctionManager.teamHasHogDestinations(clickHouseEvent.team_id)) {
// No need to continue if the team doesn't have any functions
return
}
Expand Down
2 changes: 1 addition & 1 deletion plugin-server/src/cdp/hog-executor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ export class HogExecutor {
nonMatchingFunctions: HogFunctionType[]
erroredFunctions: HogFunctionType[]
} {
const allFunctionsForTeam = this.hogFunctionManager.getTeamHogFunctions(event.project.id)
const allFunctionsForTeam = this.hogFunctionManager.getTeamHogDestinations(event.project.id)
const filtersGlobals = convertToHogFunctionFilterGlobal(event)

const nonMatchingFunctions: HogFunctionType[] = []
Expand Down
15 changes: 11 additions & 4 deletions plugin-server/src/cdp/hog-function-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,11 @@ const HOG_FUNCTION_FIELDS = [
'filters',
'bytecode',
'masking',
'type',
]

const RELOAD_HOG_FUNCTION_TYPES = ['destination', 'email']

export class HogFunctionManager {
private started: boolean
private ready: boolean
Expand Down Expand Up @@ -93,6 +96,10 @@ export class HogFunctionManager {
.filter((x) => !!x) as HogFunctionType[]
}

public getTeamHogDestinations(teamId: Team['id']): HogFunctionType[] {
return this.getTeamHogFunctions(teamId).filter((x) => x.type === 'destination' || !x.type)
}

public getHogFunction(id: HogFunctionType['id']): HogFunctionType | undefined {
if (!this.ready) {
throw new Error('HogFunctionManager is not ready! Run HogFunctionManager.start() before this')
Expand All @@ -112,8 +119,8 @@ export class HogFunctionManager {
}
}

public teamHasHogFunctions(teamId: Team['id']): boolean {
return !!Object.keys(this.getTeamHogFunctions(teamId)).length
public teamHasHogDestinations(teamId: Team['id']): boolean {
return !!Object.keys(this.getTeamHogDestinations(teamId)).length
}

public async reloadAllHogFunctions(): Promise<void> {
Expand All @@ -123,9 +130,9 @@ export class HogFunctionManager {
`
SELECT ${HOG_FUNCTION_FIELDS.join(', ')}
FROM posthog_hogfunction
WHERE deleted = FALSE AND enabled = TRUE
WHERE deleted = FALSE AND enabled = TRUE AND (type is NULL or type = ANY($1))
`,
[],
[RELOAD_HOG_FUNCTION_TYPES],
'fetchAllHogFunctions'
)
).rows
Expand Down
5 changes: 4 additions & 1 deletion plugin-server/src/cdp/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,7 @@ export type HogFunctionInvocationSerializedCompressed = {

// Mostly copied from frontend types
export type HogFunctionInputSchemaType = {
type: 'string' | 'boolean' | 'dictionary' | 'choice' | 'json' | 'integration' | 'integration_field'
type: 'string' | 'boolean' | 'dictionary' | 'choice' | 'json' | 'integration' | 'integration_field' | 'email'
key: string
label?: string
choices?: { value: string; label: string }[]
Expand All @@ -252,8 +252,11 @@ export type HogFunctionInputSchemaType = {
integration_field?: 'slack_channel'
}

export type HogFunctionTypeType = 'destination' | 'email' | 'sms' | 'push' | 'activity' | 'alert' | 'broadcast'

export type HogFunctionType = {
id: string
type: HogFunctionTypeType
team_id: number
name: string
enabled: boolean
Expand Down
1 change: 1 addition & 0 deletions plugin-server/tests/cdp/fixtures.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { insertRow } from '../helpers/sql'
export const createHogFunction = (hogFunction: Partial<HogFunctionType>) => {
const item: HogFunctionType = {
id: randomUUID(),
type: 'destination',
name: 'Hog Function',
team_id: 1,
enabled: true,
Expand Down
Loading

0 comments on commit e72783b

Please sign in to comment.