mirror of
https://github.com/supabase/supabase.git
synced 2026-10-05 17:35:10 +03:00
## I have read the [CONTRIBUTING.md](https://github.com/supabase/supabase/blob/master/CONTRIBUTING.md) file. YES ## What kind of change does this PR introduce? Add telemetry for `PromptPanel` to help us understand how people interact with our AI prompts better. Relates to DOCS-1393 Dashboard(restricted access): [Docs: AI prompt affordances](https://eu.posthog.com/project/34344/dashboard/957235) ## What is the current behavior? The docs homepage cover renders a setup panel with "AI Prompt" and "CLI" tabs, and guides render `AiPrompt` blocks. Both are built on the shared `PromptPanel`, whose copy button called `copyToClipboard` and nothing else. Copying was therefore unmeasured, while the neighbouring affordances (`ask_ai_clicked`, `agent_setup_clicked`, `copy_as_markdown_clicked`) are already instrumented. ## What is the new behavior? `PromptPanel` takes an optional `telemetry` prop. When it is set, the panel sends a new docs-owned event after a **successful** clipboard write, so instrumentation lives in the shared component instead of a forked homepage copy button. New event in `packages/common/telemetry-constants.ts`: | | | | --- | --- | | `action` | `docs_ai_prompt_copied` | | `source` | `homepage` \| `guide` \| `agent_setup` | | `tab` | `prompt` \| `cli` (omitted for panes outside that set) | | `promptId` | prompt id, when the panel comes from an `AiPrompt` block | Wired consumers: `HomePageCover` (`homepage`), `AiPrompt` (`guide` by default, plus `promptId`), and `AgentSetup` (`agent_setup`). No prompt body text and no PII is sent. Studio's existing `ai_prompt_copied` event is deliberately left alone: it has a different owner and surface, and merging the two would blend unrelated funnels. ### Proof it works ``` $ pnpm run test:local:unwatch features/ui/PromptPanel.telemetry.test.ts RUN v5.0.0 /apps/docs Test Files 1 passed (1) Tests 4 passed (4) Duration 775ms ``` ## Additional context Test plan, run against a local docs server with a stub telemetry endpoint so the request bodies could be read directly: | Case | Observed payload | | --- | --- | | Homepage, AI Prompt tab | `{"source":"homepage","tab":"prompt"}` | | Homepage, CLI tab | `{"source":"homepage","tab":"cli"}` | | Next.js quickstart `AiPrompt` | `{"source":"guide","tab":"prompt","promptId":"nextjs"}` | | `automate-with-agents/health` `AgentSetup` | `{"source":"agent_setup","tab":"prompt","promptId":"monitoring-agent-health"}` | | Clipboard write rejected | no request sent, error toast shown, button does not flip to "copied" | The failure case was re-checked with a control click on the same page after restoring a working clipboard, which did send the event, so the negative result is not just a missed handler. Also run: `turbo typecheck --filter=docs --filter=common` (passes), Prettier check on the touched files (passes), and ESLint on the touched docs files (no new findings; the one warning on `HomePageCover` is the pre-existing default export). <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Successful prompt copies are now tracked across the homepage, documentation guides, and agent setup experiences. * Copy activity records the prompt’s source, selected format, and associated prompt when available, providing more complete usage insights. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: Nik Richers <nik@validmind.ai>
70 lines
2.3 KiB
TypeScript
70 lines
2.3 KiB
TypeScript
'use client'
|
|
|
|
import {
|
|
Prompt,
|
|
PromptContent,
|
|
PromptCopy,
|
|
PromptMarkdown,
|
|
PromptPanel,
|
|
PromptTitle,
|
|
} from '~/features/ui/PromptPanel'
|
|
import { isFeatureEnabled } from 'common'
|
|
import { type ReactNode } from 'react'
|
|
|
|
import { getCustomContent } from '../lib/custom-content/getCustomContent'
|
|
import DocsCoverLogo from './DocsCoverLogo'
|
|
import { setupCommands, setupPrompt } from './HomePageCover.constants'
|
|
|
|
const fullGettingStartedEnabled = isFeatureEnabled('docs:full_getting_started')
|
|
|
|
function SetupPrompt({ cliCode }: { cliCode: ReactNode }) {
|
|
return (
|
|
<PromptPanel telemetry={{ source: 'homepage' }}>
|
|
<Prompt value="prompt" expandable>
|
|
<PromptTitle>Agent Prompt</PromptTitle>
|
|
<PromptCopy>{setupPrompt}</PromptCopy>
|
|
<PromptContent>
|
|
<PromptMarkdown>{setupPrompt}</PromptMarkdown>
|
|
</PromptContent>
|
|
</Prompt>
|
|
<Prompt value="cli">
|
|
<PromptTitle>CLI</PromptTitle>
|
|
<PromptCopy>{setupCommands}</PromptCopy>
|
|
<PromptContent shimmer={false}>{cliCode}</PromptContent>
|
|
</Prompt>
|
|
</PromptPanel>
|
|
)
|
|
}
|
|
|
|
const HomePageCover = ({ title, cliCode }: { title: string; cliCode: ReactNode }) => {
|
|
const { homepageHeading } = getCustomContent(['homepage:heading'])
|
|
|
|
return (
|
|
<div className="w-full border-b bg-muted/10">
|
|
<div className="mx-auto max-w-7xl px-6 py-16">
|
|
<div className="flex flex-col gap-10 lg:flex-row lg:items-start lg:gap-12 xl:gap-16">
|
|
<div className="flex w-full min-w-0 flex-1 items-center gap-4 sm:gap-8 mt-10">
|
|
<DocsCoverLogo aria-hidden="true" className="w-12 shrink-0 sm:w-[60px] md:w-[100px]" />
|
|
<div className="flex min-w-0 flex-col">
|
|
<h1 className="m-0 text-3xl text-foreground sm:text-4xl">
|
|
{homepageHeading || title}
|
|
</h1>
|
|
<p className="m-0 mt-2 text-base leading-7 text-foreground-light sm:mt-3 sm:text-xl">
|
|
Learn how to get up and running with Supabase through tutorials, APIs and platform
|
|
resources.
|
|
</p>
|
|
</div>
|
|
</div>
|
|
{fullGettingStartedEnabled && (
|
|
<div className="w-full lg:max-w-[478px] lg:shrink-0">
|
|
<SetupPrompt cliCode={cliCode} />
|
|
</div>
|
|
)}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
export default HomePageCover
|