mirror of
https://github.com/PostHog/posthog.git
synced 2024-11-24 00:47:50 +01:00
new site apps
This commit is contained in:
parent
da084ed77e
commit
42579b88ad
BIN
frontend/public/services/pineapple-rain.png
Normal file
BIN
frontend/public/services/pineapple-rain.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 186 KiB |
Binary file not shown.
Before Width: | Height: | Size: 209 KiB After Width: | Height: | Size: 184 KiB |
@ -9,7 +9,7 @@ import { ActivityScope, PipelineTab } from '~/types'
|
||||
|
||||
import { AppsManagement } from './AppsManagement'
|
||||
import { FrontendApps } from './FrontendApps'
|
||||
import { DESTINATION_TYPES } from './hog-functions-list/constants'
|
||||
import { DESTINATION_TYPES, SITE_APP_TYPES } from './hog-functions-list/constants'
|
||||
import { HogFunctionsList } from './hog-functions-list/HogFunctionsList'
|
||||
import { ImportApps } from './ImportApps'
|
||||
import { importAppsLogic } from './importAppsLogic'
|
||||
@ -29,7 +29,8 @@ export function Pipeline(): JSX.Element {
|
||||
{ key: PipelineTab.Sources, content: <Sources /> },
|
||||
{ key: PipelineTab.Transformations, content: <Transformations /> },
|
||||
{ key: PipelineTab.Destinations, content: <HogFunctionsList types={DESTINATION_TYPES} /> },
|
||||
{ key: PipelineTab.SiteApps, content: <FrontendApps /> },
|
||||
{ key: PipelineTab.SiteApps, content: <HogFunctionsList types={SITE_APP_TYPES} /> },
|
||||
{ key: PipelineTab.SiteAppsOld, content: <FrontendApps /> },
|
||||
]
|
||||
|
||||
// Import apps are deprecated, we only show the tab if there are some still enabled
|
||||
|
@ -14,7 +14,7 @@ import { urls } from 'scenes/urls'
|
||||
import { AvailableFeature, PipelineStage, PluginType } from '~/types'
|
||||
|
||||
import { frontendAppsLogic } from './frontendAppsLogic'
|
||||
import { DESTINATION_TYPES } from './hog-functions-list/constants'
|
||||
import { DESTINATION_TYPES, SITE_APP_TYPES } from './hog-functions-list/constants'
|
||||
import { NewFunctionsList } from './hog-functions-list/NewHogFunction'
|
||||
import { HogFunctionConfiguration } from './hogfunctions/HogFunctionConfiguration'
|
||||
import { PipelineBatchExportConfiguration } from './PipelineBatchExportConfiguration'
|
||||
@ -106,6 +106,8 @@ export function PipelineNodeNew(params: { stage?: string; id?: string } = {}): J
|
||||
} else if (stage === PipelineStage.Destination) {
|
||||
return <NewFunctionsList types={DESTINATION_TYPES} />
|
||||
} else if (stage === PipelineStage.SiteApp) {
|
||||
return <NewFunctionsList types={SITE_APP_TYPES} />
|
||||
} else if (stage === PipelineStage.SiteAppOld) {
|
||||
return <SiteAppOptionsTable />
|
||||
} else if (stage === PipelineStage.Source) {
|
||||
return <NewSourceWizardScene />
|
||||
|
@ -33,24 +33,44 @@ export function HogFunctionsList({ types }: HogFunctionsListProps): JSX.Element
|
||||
|
||||
return (
|
||||
<>
|
||||
<PageHeader
|
||||
caption="Send your data in real time or in batches to destinations outside of PostHog."
|
||||
buttons={<NewButton stage={PipelineStage.Destination} />}
|
||||
/>
|
||||
<PayGateMini feature={AvailableFeature.DATA_PIPELINES} className="mb-2">
|
||||
<ProductIntroduction
|
||||
productName="Pipeline destinations"
|
||||
thingName="destination"
|
||||
productKey={ProductKey.PIPELINE_DESTINATIONS}
|
||||
description="Pipeline destinations allow you to export data outside of PostHog, such as webhooks to Slack."
|
||||
docsURL="https://posthog.com/docs/cdp"
|
||||
actionElementOverride={<NewButton stage={PipelineStage.Destination} />}
|
||||
isEmpty={destinations.length === 0 && !loading}
|
||||
{types.includes('destination') ? (
|
||||
<>
|
||||
<PageHeader
|
||||
caption="Send your data in real time or in batches to destinations outside of PostHog."
|
||||
buttons={<NewButton stage={PipelineStage.Destination} />}
|
||||
/>
|
||||
<PayGateMini feature={AvailableFeature.DATA_PIPELINES} className="mb-2">
|
||||
<ProductIntroduction
|
||||
productName="Pipeline destinations"
|
||||
thingName="destination"
|
||||
productKey={ProductKey.PIPELINE_DESTINATIONS}
|
||||
description="Pipeline destinations allow you to export data outside of PostHog, such as webhooks to Slack."
|
||||
docsURL="https://posthog.com/docs/cdp"
|
||||
actionElementOverride={<NewButton stage={PipelineStage.Destination} />}
|
||||
isEmpty={destinations.length === 0 && !loading}
|
||||
/>
|
||||
</PayGateMini>
|
||||
</>
|
||||
) : types.includes('site_app') ? (
|
||||
<PageHeader
|
||||
caption="Run custom scripts on your website."
|
||||
buttons={<NewButton stage={PipelineStage.SiteApp} />}
|
||||
/>
|
||||
</PayGateMini>
|
||||
) : (
|
||||
<PageHeader
|
||||
caption="Run custom scripts on your website or send your data in real time or in batches to destinations outside of PostHog."
|
||||
buttons={<NewButton stage={PipelineStage.SiteApp} />}
|
||||
/>
|
||||
)}
|
||||
<HogFunctionsListTable types={types} />
|
||||
<div className="mt-4" />
|
||||
<h2>New destinations</h2>
|
||||
<h2>
|
||||
{types.includes('destination')
|
||||
? 'New destinations'
|
||||
: types.includes('site_app')
|
||||
? 'New site app'
|
||||
: 'New Hog function'}
|
||||
</h2>
|
||||
<NewFunctionsListTable types={types} />
|
||||
</>
|
||||
)
|
||||
@ -64,9 +84,11 @@ export function HogFunctionsListTable({ types }: HogFunctionsListProps): JSX.Ele
|
||||
const { toggleNode, deleteNode } = useActions(hogFunctionsListLogic({ types }))
|
||||
const { resetFilters } = useActions(hogFunctionsListFiltersLogic({ types }))
|
||||
|
||||
const isDestination = types.includes('destination')
|
||||
|
||||
return (
|
||||
<div className="space-y-2">
|
||||
<HogFunctionsListFilters types={types} />
|
||||
<HogFunctionsListFilters types={types} hideKind={types.includes('site_app')} />
|
||||
|
||||
<LemonTable
|
||||
dataSource={filteredDestinations}
|
||||
@ -115,33 +137,41 @@ export function HogFunctionsListTable({ types }: HogFunctionsListProps): JSX.Ele
|
||||
)
|
||||
},
|
||||
},
|
||||
{
|
||||
title: 'Frequency',
|
||||
key: 'interval',
|
||||
render: function RenderFrequency(_, destination) {
|
||||
return destination.interval
|
||||
},
|
||||
},
|
||||
{
|
||||
title: 'Last 7 days',
|
||||
render: function RenderSuccessRate(_, destination) {
|
||||
return (
|
||||
<Link
|
||||
to={urls.pipelineNode(
|
||||
PipelineStage.Destination,
|
||||
destination.id,
|
||||
PipelineNodeTab.Metrics
|
||||
)}
|
||||
>
|
||||
{destination.backend === PipelineBackend.HogFunction ? (
|
||||
<AppMetricSparkLineV2 id={destination.hog_function.id} />
|
||||
) : (
|
||||
<AppMetricSparkLine pipelineNode={destination} />
|
||||
)}
|
||||
</Link>
|
||||
)
|
||||
},
|
||||
},
|
||||
...(isDestination
|
||||
? [
|
||||
{
|
||||
title: 'Frequency',
|
||||
key: 'interval',
|
||||
render: function RenderFrequency(_, destination) {
|
||||
return destination.interval
|
||||
},
|
||||
} as LemonTableColumn<Destination, any>,
|
||||
]
|
||||
: []),
|
||||
...(isDestination
|
||||
? [
|
||||
{
|
||||
title: 'Last 7 days',
|
||||
render: function RenderSuccessRate(_, destination) {
|
||||
return (
|
||||
<Link
|
||||
to={urls.pipelineNode(
|
||||
PipelineStage.Destination,
|
||||
destination.id,
|
||||
PipelineNodeTab.Metrics
|
||||
)}
|
||||
>
|
||||
{destination.backend === PipelineBackend.HogFunction ? (
|
||||
<AppMetricSparkLineV2 id={destination.hog_function.id} />
|
||||
) : (
|
||||
<AppMetricSparkLine pipelineNode={destination} />
|
||||
)}
|
||||
</Link>
|
||||
)
|
||||
},
|
||||
} as LemonTableColumn<Destination, any>,
|
||||
]
|
||||
: []),
|
||||
updatedAtColumn() as LemonTableColumn<Destination, any>,
|
||||
{
|
||||
title: 'Status',
|
||||
|
@ -20,7 +20,7 @@ export type NewFunctionsListProps = {
|
||||
export function NewFunctionsList({ types }: NewFunctionsListProps): JSX.Element {
|
||||
return (
|
||||
<div className="space-y-2">
|
||||
<PayGateMini feature={AvailableFeature.DATA_PIPELINES} />
|
||||
{types.includes('destination') ? <PayGateMini feature={AvailableFeature.DATA_PIPELINES} /> : null}
|
||||
<HogFunctionsListFilters types={types} hideShowPaused />
|
||||
<NewFunctionsListTable types={types} />
|
||||
</div>
|
||||
|
@ -68,7 +68,7 @@ export const hogFunctionsListLogic = kea<hogFunctionsListLogicType>([
|
||||
updatePluginConfig: (pluginConfig: PluginConfigTypeNew) => ({ pluginConfig }),
|
||||
updateBatchExportConfig: (batchExportConfig: BatchExportConfiguration) => ({ batchExportConfig }),
|
||||
}),
|
||||
loaders(({ values, actions }) => ({
|
||||
loaders(({ values, actions, props }) => ({
|
||||
plugins: [
|
||||
{} as Record<number, PluginType>,
|
||||
{
|
||||
@ -173,7 +173,7 @@ export const hogFunctionsListLogic = kea<hogFunctionsListLogicType>([
|
||||
{
|
||||
loadHogFunctions: async () => {
|
||||
// TODO: Support pagination?
|
||||
return (await api.hogFunctions.list(undefined, ['destination', 'site_destination'])).results
|
||||
return (await api.hogFunctions.list(undefined, props.types)).results
|
||||
},
|
||||
|
||||
deleteNodeHogFunction: async ({ destination }) => {
|
||||
|
@ -239,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={
|
||||
|
@ -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]
|
||||
|
||||
|
@ -189,9 +189,9 @@ export const hogFunctionConfigurationLogic = kea<hogFunctionConfigurationLogicTy
|
||||
persistForUnload: true,
|
||||
setSampleGlobalsError: (error) => ({ error }),
|
||||
}),
|
||||
reducers({
|
||||
reducers(({ props }) => ({
|
||||
showSource: [
|
||||
false,
|
||||
(props.templateId?.startsWith('template-blank-') ? true : false) && !props.id,
|
||||
{
|
||||
setShowSource: (_, { showSource }) => showSource,
|
||||
},
|
||||
@ -226,7 +226,7 @@ export const hogFunctionConfigurationLogic = kea<hogFunctionConfigurationLogicTy
|
||||
setSampleGlobalsError: (_, { error }) => error,
|
||||
},
|
||||
],
|
||||
}),
|
||||
})),
|
||||
loaders(({ actions, props, values }) => ({
|
||||
template: [
|
||||
null as HogFunctionTemplateType | null,
|
||||
|
@ -11,7 +11,11 @@ import { ActivityScope, Breadcrumb, PipelineTab } from '~/types'
|
||||
import type { pipelineLogicType } from './pipelineLogicType'
|
||||
|
||||
export const humanFriendlyTabName = (tab: PipelineTab): string => {
|
||||
return capitalizeFirstLetter(tab).replace(/[-_]/g, ' ')
|
||||
const label = capitalizeFirstLetter(tab).replace(/[-_]/g, ' ')
|
||||
if (label.endsWith(' old')) {
|
||||
return label.slice(0, -4) + ' (old)'
|
||||
}
|
||||
return label
|
||||
}
|
||||
|
||||
export const pipelineLogic = kea<pipelineLogicType>([
|
||||
|
@ -17,7 +17,7 @@ import {
|
||||
getPluginConfigFormData,
|
||||
} from './configUtils'
|
||||
import { frontendAppsLogic } from './frontendAppsLogic'
|
||||
import { DESTINATION_TYPES } from './hog-functions-list/constants'
|
||||
import { DESTINATION_TYPES, SITE_APP_TYPES } from './hog-functions-list/constants'
|
||||
import { hogFunctionsListLogic } from './hog-functions-list/hogFunctionsListLogic'
|
||||
import { importAppsLogic } from './importAppsLogic'
|
||||
import { pipelineAccessLogic } from './pipelineAccessLogic'
|
||||
@ -174,6 +174,8 @@ export const pipelinePluginConfigurationLogic = kea<pipelinePluginConfigurationL
|
||||
.findMounted({ types: DESTINATION_TYPES })
|
||||
?.actions.updatePluginConfig(pluginConfig)
|
||||
} else if (props.stage === PipelineStage.SiteApp) {
|
||||
hogFunctionsListLogic.findMounted({ types: SITE_APP_TYPES })?.actions.updatePluginConfig(pluginConfig)
|
||||
} else if (props.stage === PipelineStage.SiteAppOld) {
|
||||
frontendAppsLogic.findMounted()?.actions.updatePluginConfig(pluginConfig)
|
||||
} else if (props.stage === PipelineStage.ImportApp) {
|
||||
importAppsLogic.findMounted()?.actions.updatePluginConfig(pluginConfig)
|
||||
|
@ -707,6 +707,7 @@ export enum PipelineTab {
|
||||
Transformations = 'transformations',
|
||||
Destinations = 'destinations',
|
||||
SiteApps = 'site-apps',
|
||||
SiteAppsOld = 'site-apps-old',
|
||||
Sources = 'sources',
|
||||
ImportApps = 'legacy-sources',
|
||||
AppsManagement = 'apps-management',
|
||||
@ -718,6 +719,7 @@ export enum PipelineStage {
|
||||
Destination = 'destination',
|
||||
Source = 'source',
|
||||
SiteApp = 'site-app',
|
||||
SiteAppOld = 'site-app-old',
|
||||
ImportApp = 'legacy-source',
|
||||
}
|
||||
|
||||
|
@ -40,11 +40,14 @@ from .google_cloud_storage.template_google_cloud_storage import (
|
||||
from .airtable.template_airtable import template as airtable
|
||||
from .brevo.template_brevo import template as brevo
|
||||
from .pineapple.template_pineapple_analytics import template as pineapple_analytics
|
||||
from .pineapple.template_pineapple_mode import template as pineapple_mode
|
||||
from .pineapple.template_pineapple_rain import template as pineapple_rain
|
||||
from ._internal.template_broadcast import template_new_broadcast as _broadcast
|
||||
from ._internal.template_blank import blank_site_destination, blank_site_app
|
||||
|
||||
HOG_FUNCTION_TEMPLATES = [
|
||||
_broadcast,
|
||||
blank_site_app,
|
||||
blank_site_destination,
|
||||
slack,
|
||||
webhook,
|
||||
activecampaign,
|
||||
@ -78,7 +81,7 @@ HOG_FUNCTION_TEMPLATES = [
|
||||
meta_ads,
|
||||
microsoft_teams,
|
||||
pineapple_analytics,
|
||||
pineapple_mode,
|
||||
pineapple_rain,
|
||||
posthog,
|
||||
rudderstack,
|
||||
salesforce_create,
|
||||
|
56
posthog/cdp/templates/_internal/template_blank.py
Normal file
56
posthog/cdp/templates/_internal/template_blank.py
Normal file
@ -0,0 +1,56 @@
|
||||
from posthog.cdp.templates.hog_function_template import HogFunctionTemplate
|
||||
|
||||
blank_site_app: HogFunctionTemplate = HogFunctionTemplate(
|
||||
status="free",
|
||||
type="site_app",
|
||||
id="template-blank-site-app",
|
||||
name="Blank Site App",
|
||||
description="Run custom code on your website",
|
||||
icon_url="/static/hedgehog/builder-hog-03.png",
|
||||
category=["Custom", "Analytics"],
|
||||
hog="""
|
||||
export function onLoad({ inputs, posthog }) {
|
||||
console.log(`Hello ${inputs.name} from your new Site App!`)
|
||||
}
|
||||
""".strip(),
|
||||
inputs_schema=[
|
||||
{
|
||||
"key": "name",
|
||||
"type": "string",
|
||||
"label": "Name",
|
||||
"description": "What's your name?",
|
||||
"default": "Max",
|
||||
},
|
||||
],
|
||||
)
|
||||
|
||||
blank_site_destination: HogFunctionTemplate = HogFunctionTemplate(
|
||||
status="free",
|
||||
type="site_destination",
|
||||
id="template-blank-site-destination",
|
||||
name="Blank Site Destination",
|
||||
description="Run code on your site when an event is sent to PostHog",
|
||||
icon_url="/static/hedgehog/builder-hog-01.png",
|
||||
category=["Custom", "Analytics"],
|
||||
hog="""
|
||||
export async function onLoad({ inputs, posthog }) {
|
||||
console.log('🦔 Loading (takes 1 sec)', { inputs })
|
||||
// onEvent will not be called until this function resolves
|
||||
await new Promise((resolve) => window.setTimeout(resolve, 1000))
|
||||
console.log("🦔 Script loaded")
|
||||
}
|
||||
|
||||
export function onEvent({ posthog, ...globals }) {
|
||||
console.log(`🦔 Sending event: ${globals.event.event}`, globals)
|
||||
}
|
||||
""".strip(),
|
||||
inputs_schema=[
|
||||
{
|
||||
"key": "name",
|
||||
"type": "string",
|
||||
"label": "Name",
|
||||
"description": "What's your name?",
|
||||
"default": "Max",
|
||||
},
|
||||
],
|
||||
)
|
@ -3,10 +3,10 @@ from posthog.cdp.templates.hog_function_template import HogFunctionTemplate
|
||||
template: HogFunctionTemplate = HogFunctionTemplate(
|
||||
status="free",
|
||||
type="site_app",
|
||||
id="template-pineapple-mode",
|
||||
name="Pineapple Mode",
|
||||
description="Make any website better by adding pineapples",
|
||||
icon_url="/static/services/pineapple.png",
|
||||
id="template-pineapple-rain",
|
||||
name="Pineapple Rain",
|
||||
description="Make any website better by adding raining pineapples",
|
||||
icon_url="/static/services/pineapple-rain.png",
|
||||
category=["Custom", "Analytics"],
|
||||
hog="""
|
||||
const style = `
|
Loading…
Reference in New Issue
Block a user