Skip to content

Commit

Permalink
feat(cdp): site destinations (#26572)
Browse files Browse the repository at this point in the history
  • Loading branch information
mariusandra authored Dec 3, 2024
1 parent a3e9d05 commit baea930
Show file tree
Hide file tree
Showing 49 changed files with 1,226 additions and 261 deletions.
22 changes: 15 additions & 7 deletions frontend/src/lib/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1764,11 +1764,17 @@ const api = {
},
},
hogFunctions: {
async list(params?: {
filters?: any
type?: HogFunctionTypeType
}): Promise<PaginatedResponse<HogFunctionType>> {
return await new ApiRequest().hogFunctions().withQueryString(params).get()
async list(
filters?: any,
type?: HogFunctionTypeType | HogFunctionTypeType[]
): Promise<PaginatedResponse<HogFunctionType>> {
return await new ApiRequest()
.hogFunctions()
.withQueryString({
filters: filters,
...(type ? (Array.isArray(type) ? { types: type.join(',') } : { type }) : {}),
})
.get()
},
async get(id: HogFunctionType['id']): Promise<HogFunctionType> {
return await new ApiRequest().hogFunction(id).get()
Expand Down Expand Up @@ -1797,10 +1803,12 @@ const api = {
): Promise<AppMetricsTotalsV2Response> {
return await new ApiRequest().hogFunction(id).withAction('metrics/totals').withQueryString(params).get()
},
async listTemplates(type?: HogFunctionTypeType): Promise<PaginatedResponse<HogFunctionTemplateType>> {
async listTemplates(
type?: HogFunctionTypeType | HogFunctionTypeType[]
): Promise<PaginatedResponse<HogFunctionTemplateType>> {
return new ApiRequest()
.hogFunctionTemplates()
.withQueryString({ type: type ?? 'destination' })
.withQueryString(Array.isArray(type) ? { types: type.join(',') } : { type: type ?? 'destination' })
.get()
},
async getTemplate(id: HogFunctionTemplateType['id']): Promise<HogFunctionTemplateType> {
Expand Down
1 change: 1 addition & 0 deletions frontend/src/lib/constants.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,7 @@ export const FEATURE_FLAGS = {
EXPERIMENTS_MULTIPLE_METRICS: 'experiments-multiple-metrics', // owner: @jurajmajerik #team-experiments
WEB_ANALYTICS_WARN_CUSTOM_EVENT_NO_SESSION: 'web-analytics-warn-custom-event-no-session', // owner: @robbie-c #team-web-analytics
TWO_FACTOR_UI: 'two-factor-ui', // owner: @zach
SITE_DESTINATIONS: 'site-destinations', // owner: @mariusandra #team-cdp
} as const
export type FeatureFlagKey = (typeof FEATURE_FLAGS)[keyof typeof FEATURE_FLAGS]

Expand Down
2 changes: 1 addition & 1 deletion frontend/src/scenes/actions/actionLogic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ export const actionLogic = kea<actionLogicType>([
null as HogFunctionType[] | null,
{
loadMatchingHogFunctions: async () => {
const res = await api.hogFunctions.list({ filters: { actions: [{ id: `${props.id}` }] } })
const res = await api.hogFunctions.list({ actions: [{ id: `${props.id}` }] })

return res.results
},
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/scenes/messaging/functionsTableLogic.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ export const functionsTableLogic = kea<functionsTableLogicType>([
{
loadHogFunctions: async () => {
// TODO: pagination?
return (await api.hogFunctions.list({ type: props.type ?? 'destination' })).results
return (await api.hogFunctions.list(undefined, props.type ?? 'destination')).results
},
deleteHogFunction: async ({ hogFunction }) => {
await deleteWithUndo({
Expand Down
2 changes: 2 additions & 0 deletions frontend/src/scenes/pipeline/destinations/DestinationTag.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ export function DestinationTag({ status }: { status: HogFunctionTemplateStatus }
return <LemonTag type="completion">Beta</LemonTag>
case 'stable':
return <LemonTag type="highlight">New</LemonTag> // Once Hog Functions are fully released we can remove the new label
case 'client-side':
return <LemonTag type="success">Client-Side</LemonTag>
default:
return status ? <LemonTag type="highlight">{capitalizeFirstLetter(status)}</LemonTag> : null
}
Expand Down
4 changes: 4 additions & 0 deletions frontend/src/scenes/pipeline/destinations/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { HogFunctionTypeType } from '~/types'

export const getDestinationTypes = (featureFlagEnabled: boolean): HogFunctionTypeType[] =>
featureFlagEnabled ? ['destination', 'site_destination'] : ['destination']
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import {
WebhookDestination,
} from '../types'
import { captureBatchExportEvent, capturePluginEvent, loadPluginsFromUrl } from '../utils'
import { getDestinationTypes } from './constants'
import { destinationsFiltersLogic } from './destinationsFiltersLogic'
import type { pipelineDestinationsLogicType } from './destinationsLogicType'

Expand Down Expand Up @@ -166,8 +167,8 @@ export const pipelineDestinationsLogic = kea<pipelineDestinationsLogicType>([
[] as HogFunctionType[],
{
loadHogFunctions: async () => {
// TODO: Support pagination?
return (await api.hogFunctions.list({ type: 'destination' })).results
const destinationTypes = getDestinationTypes(!!values.featureFlags[FEATURE_FLAGS.SITE_DESTINATIONS])
return (await api.hogFunctions.list(undefined, destinationTypes)).results
},

deleteNodeHogFunction: async ({ destination }) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import { humanizeBatchExportName } from '../batch-exports/utils'
import { HogFunctionIcon } from '../hogfunctions/HogFunctionIcon'
import { PipelineBackend } from '../types'
import { RenderBatchExportIcon } from '../utils'
import { getDestinationTypes } from './constants'
import { destinationsFiltersLogic } from './destinationsFiltersLogic'
import type { newDestinationsLogicType } from './newDestinationsLogicType'

Expand All @@ -43,20 +44,21 @@ export const newDestinationsLogic = kea<newDestinationsLogicType>([
actions({
openFeedbackDialog: true,
}),
loaders({
loaders(({ values }) => ({
hogFunctionTemplates: [
{} as Record<string, HogFunctionTemplateType>,
{
loadHogFunctionTemplates: async () => {
const templates = await api.hogFunctions.listTemplates()
const destinationTypes = getDestinationTypes(!!values.featureFlags[FEATURE_FLAGS.SITE_DESTINATIONS])
const templates = await api.hogFunctions.listTemplates(destinationTypes)
return templates.results.reduce((acc, template) => {
acc[template.id] = template
return acc
}, {} as Record<string, HogFunctionTemplateType>)
},
},
],
}),
})),

selectors(() => ({
loading: [(s) => [s.hogFunctionTemplatesLoading], (hogFunctionTemplatesLoading) => hogFunctionTemplatesLoading],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -151,11 +151,14 @@ export function HogFunctionConfiguration({ templateId, id }: HogFunctionConfigur
return <PayGateMini feature={AvailableFeature.DATA_PIPELINES} />
}

const showFilters = type === 'destination' || type === 'broadcast'
const showExpectedVolume = type === 'destination'
const showEnabled = type === 'destination' || type === 'email'
const canEditSource = type === 'destination' || type === 'email'
const showFilters = type === 'destination' || type === 'site_destination' || type === 'broadcast'
const showExpectedVolume = type === 'destination' || type === 'site_destination'
const showStatus = type === 'destination' || type === 'email'
const showEnabled = type === 'destination' || type === 'email' || type === 'site_destination' || type === 'site_app'
const canEditSource =
type === 'destination' || type === 'email' || type === 'site_destination' || type === 'site_app'
const showPersonsCount = type === 'broadcast'
const showTesting = type === 'destination' || type === 'broadcast' || type === 'email'

return (
<div className="space-y-3">
Expand Down Expand Up @@ -210,7 +213,7 @@ export function HogFunctionConfiguration({ templateId, id }: HogFunctionConfigur
{template && <DestinationTag status={template.status} />}
</div>

{showEnabled && <HogFunctionStatusIndicator hogFunction={hogFunction} />}
{showStatus && <HogFunctionStatusIndicator hogFunction={hogFunction} />}
{showEnabled && (
<LemonField name="enabled">
{({ value, onChange }) => (
Expand All @@ -236,7 +239,7 @@ export function HogFunctionConfiguration({ templateId, id }: HogFunctionConfigur
<LemonTextArea disabled={loading} />
</LemonField>

{hogFunction?.template ? (
{hogFunction?.template && !hogFunction.template.id.startsWith('template-blank-') ? (
<LemonDropdown
showArrow
overlay={
Expand Down Expand Up @@ -458,14 +461,16 @@ export function HogFunctionConfiguration({ templateId, id }: HogFunctionConfigur
<LemonField name="hog">
{({ value, onChange }) => (
<>
<span className="text-xs text-muted-alt">
This is the underlying Hog code that will run whenever the
filters match.{' '}
<Link to="https://posthog.com/docs/hog">See the docs</Link> for
more info
</span>
{!type.startsWith('site_') ? (
<span className="text-xs text-muted-alt">
This is the underlying Hog code that will run whenever the
filters match.{' '}
<Link to="https://posthog.com/docs/hog">See the docs</Link>{' '}
for more info
</span>
) : null}
<CodeEditorResizeable
language="hog"
language={type.startsWith('site_') ? 'typescript' : 'hog'}
value={value ?? ''}
onChange={(v) => onChange(v ?? '')}
globals={globalsWithInputs}
Expand All @@ -489,8 +494,13 @@ export function HogFunctionConfiguration({ templateId, id }: HogFunctionConfigur
) : null}
</div>
)}

{!id || id === 'new' ? <HogFunctionTestPlaceholder /> : <HogFunctionTest id={id} />}
{showTesting ? (
!id || id === 'new' ? (
<HogFunctionTestPlaceholder />
) : (
<HogFunctionTest id={id} />
)
) : null}
<div className="flex gap-2 justify-end">{saveButtons}</div>
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -313,7 +313,7 @@ export function HogFunctionInputWithSchema({ schema }: HogFunctionInputWithSchem
const { attributes, listeners, setNodeRef, transform, transition } = useSortable({ id: schema.key })
const { showSource, configuration } = useValues(hogFunctionConfigurationLogic)
const { setConfigurationValue } = useActions(hogFunctionConfigurationLogic)
const [editing, setEditing] = useState(showSource)
const [editing, setEditing] = useState(false)

const value = configuration.inputs?.[schema.key]

Expand Down
Loading

0 comments on commit baea930

Please sign in to comment.