-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(cdp): Native slack integration (#23103)
- Loading branch information
1 parent
99762c7
commit 80847e1
Showing
25 changed files
with
800 additions
and
346 deletions.
There are no files selected for viewing
Binary file modified
BIN
+3.4 KB
(120%)
.../__snapshots__/components-integrations-slack--slack-integration-added--dark.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified
BIN
+3.4 KB
(120%)
...__snapshots__/components-integrations-slack--slack-integration-added--light.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
130 changes: 130 additions & 0 deletions
130
frontend/src/lib/integrations/SlackIntegrationHelpers.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,130 @@ | ||
import { LemonBanner, LemonButton, LemonInputSelect, LemonInputSelectOption, Link } from '@posthog/lemon-ui' | ||
import { useActions, useValues } from 'kea' | ||
import { UserActivityIndicator } from 'lib/components/UserActivityIndicator/UserActivityIndicator' | ||
import { IconSlack, IconSlackExternal } from 'lib/lemon-ui/icons' | ||
import { useMemo } from 'react' | ||
|
||
import { IntegrationType, SlackChannelType } from '~/types' | ||
|
||
import { slackIntegrationLogic } from './slackIntegrationLogic' | ||
|
||
const getSlackChannelOptions = (slackChannels?: SlackChannelType[] | null): LemonInputSelectOption[] | null => { | ||
return slackChannels | ||
? slackChannels.map((x) => ({ | ||
key: `${x.id}|#${x.name}`, | ||
labelComponent: ( | ||
<span className="flex items-center"> | ||
{x.is_private ? `🔒${x.name}` : `#${x.name}`} | ||
{x.is_ext_shared ? <IconSlackExternal className="ml-2" /> : null} | ||
</span> | ||
), | ||
label: `${x.id} #${x.name}`, | ||
})) | ||
: null | ||
} | ||
|
||
export type SlackChannelPickerProps = { | ||
integration: IntegrationType | ||
value?: string | ||
onChange?: (value: string | null) => void | ||
disabled?: boolean | ||
} | ||
|
||
export function SlackChannelPicker({ onChange, value, integration, disabled }: SlackChannelPickerProps): JSX.Element { | ||
const { slackChannels, slackChannelsLoading, isMemberOfSlackChannel } = useValues( | ||
slackIntegrationLogic({ id: integration.id }) | ||
) | ||
const { loadSlackChannels } = useActions(slackIntegrationLogic({ id: integration.id })) | ||
|
||
// If slackChannels aren't loaded, make sure we display only the channel name and not the actual underlying value | ||
const slackChannelOptions = useMemo(() => getSlackChannelOptions(slackChannels), [slackChannels]) | ||
const showSlackMembershipWarning = value && isMemberOfSlackChannel(value) === false | ||
|
||
// Sometimes the parent will only store the channel ID and not the name, so we need to handle that | ||
|
||
const modifiedValue = useMemo(() => { | ||
if (value?.split('|').length === 1) { | ||
const channel = slackChannels?.find((x) => x.id === value) | ||
|
||
if (channel) { | ||
return `${channel.id}|#${channel.name}` | ||
} | ||
} | ||
|
||
return value | ||
}, [value, slackChannels]) | ||
|
||
return ( | ||
<> | ||
<LemonInputSelect | ||
onChange={(val) => onChange?.(val[0] ?? null)} | ||
value={modifiedValue ? [modifiedValue] : []} | ||
onFocus={() => !slackChannels && !slackChannelsLoading && loadSlackChannels()} | ||
disabled={disabled} | ||
mode="single" | ||
data-attr="select-slack-channel" | ||
placeholder="Select a channel..." | ||
options={ | ||
slackChannelOptions ?? | ||
(modifiedValue | ||
? [ | ||
{ | ||
key: modifiedValue, | ||
label: modifiedValue?.split('|')[1] ?? modifiedValue, | ||
}, | ||
] | ||
: []) | ||
} | ||
loading={slackChannelsLoading} | ||
/> | ||
|
||
{showSlackMembershipWarning ? ( | ||
<LemonBanner type="info"> | ||
<div className="flex gap-2 items-center"> | ||
<span> | ||
The PostHog Slack App is not in this channel. Please add it to the channel otherwise | ||
Subscriptions will fail to be delivered.{' '} | ||
<Link to="https://posthog.com/docs/webhooks/slack" target="_blank"> | ||
See the Docs for more information | ||
</Link> | ||
</span> | ||
<LemonButton type="secondary" onClick={loadSlackChannels} loading={slackChannelsLoading}> | ||
Check again | ||
</LemonButton> | ||
</div> | ||
</LemonBanner> | ||
) : null} | ||
</> | ||
) | ||
} | ||
|
||
export function SlackIntegrationView({ | ||
integration, | ||
suffix, | ||
}: { | ||
integration: IntegrationType | ||
suffix?: JSX.Element | ||
}): JSX.Element { | ||
return ( | ||
<div className="rounded border flex justify-between items-center p-2 bg-bg-light"> | ||
<div className="flex items-center gap-4 ml-2"> | ||
<IconSlack className="text-2xl" /> | ||
<div> | ||
<div> | ||
Connected to <strong>{integration.config.team.name}</strong> workspace | ||
</div> | ||
{integration.created_by ? ( | ||
<UserActivityIndicator | ||
at={integration.created_at} | ||
by={integration.created_by} | ||
prefix="Updated" | ||
className="text-muted" | ||
/> | ||
) : null} | ||
</div> | ||
</div> | ||
|
||
{suffix} | ||
</div> | ||
) | ||
} |
Oops, something went wrong.