|
| 1 | +import { useEffect } from 'react' |
| 2 | + |
| 3 | +import { IconLaptop } from '@posthog/icons' |
| 4 | + |
| 5 | +import { BridgePage } from 'lib/components/BridgePage/BridgePage' |
| 6 | +import { LemonButton } from 'lib/lemon-ui/LemonButton' |
| 7 | +import { SceneExport } from 'scenes/sceneTypes' |
| 8 | + |
| 9 | +export interface CodeCanvasLinkProps { |
| 10 | + channelId: string |
| 11 | + dashboardId: string |
| 12 | +} |
| 13 | + |
| 14 | +export const scene: SceneExport<CodeCanvasLinkProps> = { |
| 15 | + component: CodeCanvasLink, |
| 16 | + paramsToProps: ({ params: { channelId, dashboardId } }) => ({ |
| 17 | + channelId: channelId ?? '', |
| 18 | + dashboardId: dashboardId ?? '', |
| 19 | + }), |
| 20 | +} |
| 21 | + |
| 22 | +// The desktop app registers a different custom scheme per build: production |
| 23 | +// installs use `posthog-code://`, local dev builds use `posthog-code-dev://`. |
| 24 | +// A dev frontend (./bin/start) is exactly when you're testing against a dev |
| 25 | +// desktop build, so target that scheme there. Build-time constant, so it never |
| 26 | +// flips after mount and double-fires. |
| 27 | +const DESKTOP_SCHEME = process.env.NODE_ENV === 'development' ? 'posthog-code-dev' : 'posthog-code' |
| 28 | + |
| 29 | +function canvasDeepLink(channelId: string, dashboardId: string): string { |
| 30 | + return `${DESKTOP_SCHEME}://canvas/${encodeURIComponent(channelId)}/${encodeURIComponent(dashboardId)}` |
| 31 | +} |
| 32 | + |
| 33 | +/** |
| 34 | + * Public, unauthenticated bridge for desktop-app "canvas" share links |
| 35 | + * (`/code/canvas/<channelId>/<dashboardId>`). On mount it deep-links into the desktop |
| 36 | + * app via the `posthog-code(-dev)://` custom scheme; for visitors without the app it |
| 37 | + * shows an explanation, a manual "open" button (in case the browser blocks the |
| 38 | + * auto-redirect), and a download link. The canvas itself only exists in the desktop |
| 39 | + * app, so nothing is rendered here beyond this interstitial. |
| 40 | + */ |
| 41 | +export function CodeCanvasLink({ channelId, dashboardId }: CodeCanvasLinkProps): JSX.Element { |
| 42 | + // Null when a param is missing (a partial URL or params not yet resolved) — |
| 43 | + // firing with an empty id would send a malformed `<scheme>://canvas//`. |
| 44 | + const deepLink = channelId && dashboardId ? canvasDeepLink(channelId, dashboardId) : null |
| 45 | + |
| 46 | + useEffect(() => { |
| 47 | + if (deepLink) { |
| 48 | + window.location.href = deepLink |
| 49 | + } |
| 50 | + }, [deepLink]) |
| 51 | + |
| 52 | + return ( |
| 53 | + <BridgePage view="code-canvas-link"> |
| 54 | + <div className="flex flex-col items-center gap-4 text-center max-w-lg mx-auto"> |
| 55 | + <IconLaptop className="text-5xl shrink-0" /> |
| 56 | + <h2 className="text-xl font-semibold m-0">Opening in PostHog Code…</h2> |
| 57 | + <p className="text-muted mb-0"> |
| 58 | + Canvases live in the PostHog Code desktop app. If it's installed, it should open automatically. If |
| 59 | + it didn't, use the button below — or download the app. |
| 60 | + </p> |
| 61 | + <div className="flex flex-col items-center gap-2"> |
| 62 | + {deepLink && ( |
| 63 | + <LemonButton |
| 64 | + type="primary" |
| 65 | + onClick={() => { |
| 66 | + window.location.href = deepLink |
| 67 | + }} |
| 68 | + > |
| 69 | + Open in PostHog Code |
| 70 | + </LemonButton> |
| 71 | + )} |
| 72 | + <LemonButton type="secondary" to="https://posthog.com/code" targetBlank> |
| 73 | + Download PostHog Code |
| 74 | + </LemonButton> |
| 75 | + </div> |
| 76 | + </div> |
| 77 | + </BridgePage> |
| 78 | + ) |
| 79 | +} |
| 80 | + |
| 81 | +export default CodeCanvasLink |
0 commit comments