Skip to content

Commit

Permalink
feat(pipeline-ui): Destinations list view (#19171)
Browse files Browse the repository at this point in the history
* feat(pipeline-ui): Destinations list view

* Update UI snapshots for `chromium` (1)

---------

Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com>
  • Loading branch information
tiina303 and github-actions[bot] authored Dec 14, 2023
1 parent 7eb0c5f commit af66a97
Show file tree
Hide file tree
Showing 13 changed files with 413 additions and 48 deletions.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
245 changes: 245 additions & 0 deletions frontend/src/scenes/pipeline/Destinations.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,245 @@
import {
LemonButton,
LemonDivider,
LemonTable,
LemonTableColumn,
LemonTag,
LemonTagType,
Link,
Tooltip,
} from '@posthog/lemon-ui'
import { useActions, useValues } from 'kea'
import { ProductIntroduction } from 'lib/components/ProductIntroduction/ProductIntroduction'
import { More } from 'lib/lemon-ui/LemonButton/More'
import { LemonMarkdown } from 'lib/lemon-ui/LemonMarkdown/LemonMarkdown'
import { updatedAtColumn } from 'lib/lemon-ui/LemonTable/columnUtils'
import { deleteWithUndo } from 'lib/utils/deleteWithUndo'
import { urls } from 'scenes/urls'

import { PipelineAppTabs, PipelineTabs, PluginConfigTypeNew, ProductKey } from '~/types'

import { pipelineDestinationsLogic } from './destinationsLogic'
import { NewButton } from './NewButton'
import { RenderApp } from './utils'

export function Destinations(): JSX.Element {
const { enabledPluginConfigs, disabledPluginConfigs, shouldShowProductIntroduction } =
useValues(pipelineDestinationsLogic)

const shouldShowEmptyState = enabledPluginConfigs.length === 0 && disabledPluginConfigs.length === 0

return (
<>
{(shouldShowEmptyState || shouldShowProductIntroduction) && (
<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 tab={PipelineTabs.Destinations} />}
isEmpty={true}
/>
)}
<AppsTable />
<BatchExportsTable />
</>
)
}

function BatchExportsTable(): JSX.Element {
return (
<>
<h2>Batch exports</h2>

<h2>Backfills</h2>
</>
)
}

function AppsTable(): JSX.Element {
const { loading, enabledPluginConfigs, disabledPluginConfigs, plugins, canConfigurePlugins } =
useValues(pipelineDestinationsLogic)
const { toggleEnabled, loadPluginConfigs } = useActions(pipelineDestinationsLogic)

if (enabledPluginConfigs.length === 0 && disabledPluginConfigs.length === 0) {
return <></>
}

return (
<>
<h2>Webhooks</h2>
<LemonTable
dataSource={[...enabledPluginConfigs, ...disabledPluginConfigs]}
size="xs"
loading={loading}
columns={[
{
title: 'Name',
sticky: true,
render: function RenderPluginName(_, pluginConfig) {
return (
<>
<Tooltip title={'Click to update configuration, view metrics, and more'}>
<Link to={urls.pipelineApp(pluginConfig.id, PipelineAppTabs.Configuration)}>
<span className="row-name">{pluginConfig.name}</span>
</Link>
</Tooltip>
{pluginConfig.description && (
<LemonMarkdown className="row-description" lowKeyHeadings>
{pluginConfig.description}
</LemonMarkdown>
)}
</>
)
},
},
{
title: 'App',
render: function RenderAppInfo(_, pluginConfig) {
return <RenderApp plugin={plugins[pluginConfig.plugin]} />
},
},
{
title: '24h',
render: function Render24hDeliveryRate(_, pluginConfig) {
let tooltip = 'No events exported in the past 24 hours'
let value = '-'
let tagType: LemonTagType = 'muted'
if (
pluginConfig.delivery_rate_24h !== null &&
pluginConfig.delivery_rate_24h !== undefined
) {
const deliveryRate = pluginConfig.delivery_rate_24h
value = `${Math.floor(deliveryRate * 100)}%`
tooltip = 'Success rate for past 24 hours'
if (deliveryRate >= 0.99) {
tagType = 'success'
} else if (deliveryRate >= 0.75) {
tagType = 'warning'
} else {
tagType = 'danger'
}
}
return (
<Tooltip title={tooltip}>
<Link to={urls.pipelineApp(pluginConfig.id, PipelineAppTabs.Metrics)}>
<LemonTag type={tagType}>{value}</LemonTag>
</Link>
</Tooltip>
)
},
},
updatedAtColumn() as LemonTableColumn<PluginConfigTypeNew, any>,
{
title: 'Status',
render: function RenderStatus(_, pluginConfig) {
return (
<>
{pluginConfig.enabled ? (
<LemonTag type="success" className="uppercase">
Enabled
</LemonTag>
) : (
<LemonTag type="default" className="uppercase">
Disabled
</LemonTag>
)}
</>
)
},
},
{
width: 0,
render: function Render(_, pluginConfig) {
return (
<More
overlay={
<>
<LemonButton
status="stealth"
onClick={() => {
toggleEnabled({
enabled: !pluginConfig.enabled,
id: pluginConfig.id,
})
}}
id={`app-${pluginConfig.id}-enable-switch`}
disabledReason={
canConfigurePlugins
? undefined
: 'You do not have permission to enable/disable apps.'
}
fullWidth
>
{pluginConfig.enabled ? 'Disable' : 'Enable'} app
</LemonButton>
<LemonButton
status="stealth"
to={urls.pipelineApp(pluginConfig.id, PipelineAppTabs.Configuration)}
id={`app-${pluginConfig.id}-configuration`}
fullWidth
>
{canConfigurePlugins ? 'Edit' : 'View'} app configuration
</LemonButton>
<LemonButton
status="stealth"
to={urls.pipelineApp(pluginConfig.id, PipelineAppTabs.Metrics)}
id={`app-${pluginConfig.id}-metrics`}
fullWidth
>
View app metrics
</LemonButton>
<LemonButton
status="stealth"
to={urls.pipelineApp(pluginConfig.id, PipelineAppTabs.Logs)}
id={`app-${pluginConfig.id}-logs`}
fullWidth
>
View app logs
</LemonButton>
{plugins[pluginConfig.plugin].url && (
<LemonButton
status="stealth"
to={plugins[pluginConfig.plugin].url}
targetBlank={true}
id={`app-${pluginConfig.id}-source-code`}
fullWidth
>
View app source code
</LemonButton>
)}
<LemonDivider />
<LemonButton
status="danger"
onClick={() => {
void deleteWithUndo({
endpoint: `plugin_config`,
object: {
id: pluginConfig.id,
name: pluginConfig.name,
},
callback: loadPluginConfigs,
})
}}
id={`app-reorder`}
disabledReason={
canConfigurePlugins
? undefined
: 'You do not have permission to delete apps.'
}
fullWidth
>
Delete app
</LemonButton>
</>
}
/>
)
},
},
]}
/>
</>
)
}
13 changes: 13 additions & 0 deletions frontend/src/scenes/pipeline/Pipeline.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,19 @@ export function PipelineTransformationsPage(): JSX.Element {
}, [])
return <App />
}
export function PipelineDestinationsPage(): JSX.Element {
useStorybookMocks({
get: {
'api/organizations/@current/pipeline_destinations/': require('./__mocks__/plugins.json'),
'api/projects/:team_id/pipeline_destinations_configs/': require('./__mocks__/transformationPluginConfigs.json'),
},
})
useEffect(() => {
router.actions.push(urls.pipeline(PipelineTabs.Destinations))
pipelineLogic.mount()
}, [])
return <App />
}

export function PipelineAppConfiguration(): JSX.Element {
useEffect(() => {
Expand Down
3 changes: 2 additions & 1 deletion frontend/src/scenes/pipeline/Pipeline.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { urls } from 'scenes/urls'
import { PipelineTabs } from '~/types'

import { AppsManagement } from './AppsManagement'
import { Destinations } from './Destinations'
import { NewButton } from './NewButton'
import { humanFriendlyTabName, pipelineLogic } from './pipelineLogic'
import { Transformations } from './Transformations'
Expand All @@ -18,7 +19,7 @@ export function Pipeline(): JSX.Element {
const tab_to_content: Record<PipelineTabs, JSX.Element> = {
[PipelineTabs.Filters]: <div>Coming soon</div>,
[PipelineTabs.Transformations]: <Transformations />,
[PipelineTabs.Destinations]: <div>Coming soon</div>,
[PipelineTabs.Destinations]: <Destinations />,
[PipelineTabs.AppsManagement]: <AppsManagement />,
}

Expand Down
31 changes: 0 additions & 31 deletions frontend/src/scenes/pipeline/Transformations.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,9 @@ import {
} from '@posthog/lemon-ui'
import { useActions, useValues } from 'kea'
import { ProductIntroduction } from 'lib/components/ProductIntroduction/ProductIntroduction'
import { dayjs } from 'lib/dayjs'
import { More } from 'lib/lemon-ui/LemonButton/More'
import { LemonMarkdown } from 'lib/lemon-ui/LemonMarkdown/LemonMarkdown'
import { updatedAtColumn } from 'lib/lemon-ui/LemonTable/columnUtils'
import { humanFriendlyDetailedTime } from 'lib/utils'
import { deleteWithUndo } from 'lib/utils/deleteWithUndo'
import { PluginImage } from 'scenes/plugins/plugin/PluginImage'
import { urls } from 'scenes/urls'
Expand Down Expand Up @@ -132,11 +130,6 @@ export function Transformations(): JSX.Element {
{
title: 'Status',
render: function RenderStatus(_, pluginConfig) {
// We're not very good at cleaning up the errors, so let's not show it if more than 7 days have passed
const days_since_error = pluginConfig.error
? dayjs().diff(dayjs(pluginConfig.error.time), 'day')
: null
const show_error: boolean = !(days_since_error && days_since_error < 7)
return (
<>
{pluginConfig.enabled ? (
Expand All @@ -148,30 +141,6 @@ export function Transformations(): JSX.Element {
Disabled
</LemonTag>
)}
{pluginConfig.error && show_error && (
<>
<br />
<Tooltip
title={
<>
Click to see logs.
<br />
{humanFriendlyDetailedTime(
pluginConfig.error.time
)}: {pluginConfig.error.message}
</>
}
>
<Link
to={urls.pipelineApp(pluginConfig.id, PipelineAppTabs.Logs)}
>
<LemonTag type="danger" className="uppercase">
Error
</LemonTag>
</Link>
</Tooltip>
</>
)}
</>
)
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
"error": null,
"team_id": 1,
"plugin_info": null,
"delivery_rate_24h": 1.0,
"delivery_rate_24h": 0.3333333,
"created_at": "2021-04-07T13:37:36.250380Z",
"updated_at": "2023-02-15T17:40:45.167743Z",
"name": null,
Expand All @@ -28,7 +28,7 @@
"error": null,
"team_id": 1,
"plugin_info": null,
"delivery_rate_24h": 1.0,
"delivery_rate_24h": 0.99,
"created_at": "2021-04-07T13:37:36.250380Z",
"updated_at": "2023-02-15T17:40:45.167743Z",
"name": "custom name",
Expand All @@ -52,7 +52,7 @@
},
"team_id": 1,
"plugin_info": null,
"delivery_rate_24h": 1.0,
"delivery_rate_24h": null,
"created_at": "2021-04-07T13:37:36.250380Z",
"updated_at": "2023-02-15T17:40:45.167743Z",
"name": "another of plugin 2",
Expand All @@ -68,7 +68,7 @@
"error": null,
"team_id": 1,
"plugin_info": null,
"delivery_rate_24h": 1.0,
"delivery_rate_24h": 0.88,
"created_at": "2021-04-07T13:37:36.250380Z",
"updated_at": "2023-02-15T17:40:45.167743Z",
"name": "disabled",
Expand All @@ -84,7 +84,7 @@
"error": null,
"team_id": 1,
"plugin_info": null,
"delivery_rate_24h": 1.0,
"delivery_rate_24h": 0,
"created_at": "2022-07-05T11:18:22.059158Z",
"updated_at": "2023-01-03T17:37:41.553035Z",
"name": "another disabled one",
Expand Down
Loading

0 comments on commit af66a97

Please sign in to comment.