diff --git a/docs/use-cases/observability/clickstack/managed-onboarding/setting-up-your-opentelemetry-collector.md b/docs/use-cases/observability/clickstack/managed-onboarding/setting-up-your-opentelemetry-collector.md index f532467677b..184746697fc 100644 --- a/docs/use-cases/observability/clickstack/managed-onboarding/setting-up-your-opentelemetry-collector.md +++ b/docs/use-cases/observability/clickstack/managed-onboarding/setting-up-your-opentelemetry-collector.md @@ -19,6 +19,19 @@ import ConfirmInUI from '@site/docs/use-cases/observability/clickstack/managed-o This guide walks you through deploying an OpenTelemetry collector against an existing Managed ClickStack service, or adapting your existing collector, before verifying that data is flowing through. + + The collector runs as a **gateway**: a single OTLP endpoint that your applications, SDKs, and agent collectors send to. The gateway batches events, applies any processing you've configured, and writes them to ClickHouse via the [ClickHouse exporter](https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/exporter/clickhouseexporter). This pattern keeps collection logic out of your application code and lets you scale ingestion independently of the workloads producing data. For background on gateway versus agent roles, see [Collector roles](/use-cases/observability/clickstack/ingesting-data/otel-collector#collector-roles). :::note Existing collector diff --git a/src/components/AgentPrompt/AgentPrompt.tsx b/src/components/AgentPrompt/AgentPrompt.tsx new file mode 100644 index 00000000000..25086e84715 --- /dev/null +++ b/src/components/AgentPrompt/AgentPrompt.tsx @@ -0,0 +1,131 @@ +import React, { useCallback, useState } from 'react'; +import styles from './styles.module.scss'; + +interface AgentPromptProps { + prompt: string; + title?: string; + description?: React.ReactNode; + outline?: string[]; + outlineLabel?: string; +} + +const CopyIcon = () => ( + +); + +const CheckIcon = () => ( + +); + +const AgentPrompt: React.FC = ({ + prompt, + title = 'Agent-Assisted Setup', + description, + outline, + outlineLabel = 'What the agent will do', +}) => { + const [copied, setCopied] = useState(false); + + const handleCopy = useCallback(async () => { + try { + if (navigator?.clipboard?.writeText) { + await navigator.clipboard.writeText(prompt); + } else { + const ta = document.createElement('textarea'); + ta.value = prompt; + ta.style.position = 'fixed'; + ta.style.opacity = '0'; + document.body.appendChild(ta); + ta.select(); + document.execCommand('copy'); + document.body.removeChild(ta); + } + setCopied(true); + window.setTimeout(() => setCopied(false), 2000); + } catch { + /* swallow — fallback already attempted */ + } + }, [prompt]); + + return ( +
+
+
+ {title} +
+
+ {prompt} +
+ +
+ {description && ( +
+ {description} +
+ )} + {outline && outline.length > 0 && ( +
+ + + {outlineLabel} + +
    + {outline.map((item, i) => ( +
  1. {item}
  2. + ))} +
+
+ )} +
+ ); +}; + +export default AgentPrompt; diff --git a/src/components/AgentPrompt/index.ts b/src/components/AgentPrompt/index.ts new file mode 100644 index 00000000000..2e183e57678 --- /dev/null +++ b/src/components/AgentPrompt/index.ts @@ -0,0 +1 @@ +export { default } from './AgentPrompt'; diff --git a/src/components/AgentPrompt/styles.module.scss b/src/components/AgentPrompt/styles.module.scss new file mode 100644 index 00000000000..48ac2aae796 --- /dev/null +++ b/src/components/AgentPrompt/styles.module.scss @@ -0,0 +1,195 @@ +// AgentPrompt — ClickStack yellow agent-prompt callout. +// Mirrors the principle of Sentry's "Agent-Assisted Setup" widget but +// rebranded to ClickStack's brand yellow (--palette_brand_350 / 300 / 50). + +.wrapper { + --agent-accent: var(--palette_brand_350); // #FBFF46 + --agent-accent-soft: var(--palette_brand_300); // #FCFF74 + --agent-accent-bg: var(--palette_brand_50); // #FFFFE8 + --agent-accent-bg-strong: var(--palette_brand_100); // #FEFFBA + --agent-text: var(--palette_slate_900); + --agent-text-muted: var(--palette_slate_600); + --agent-prompt-bg: #FFFFFF; + --agent-prompt-border: var(--palette_brand_300); + --agent-button-bg: var(--palette_brand_350); + --agent-button-bg-hover: var(--palette_brand_400); + --agent-button-text: var(--palette_slate_900); + + border: 1px solid var(--agent-accent); + background: var(--agent-accent-bg); + border-radius: 8px; + padding: 14px 16px; + margin: 1.25rem 0 1.75rem; + display: flex; + flex-direction: column; + gap: 10px; + box-sizing: border-box; +} + +.mainRow { + display: flex; + align-items: center; + gap: 12px; + flex-wrap: nowrap; +} + +.left { + flex-shrink: 0; +} + +.title { + font-weight: 600; + font-size: 0.875rem; + color: var(--agent-text); + white-space: nowrap; +} + +.promptArea { + flex: 1 1 auto; + min-width: 0; + background: var(--agent-prompt-bg); + border: 1px solid var(--agent-prompt-border); + border-radius: 6px; + padding: 6px 10px; + overflow-x: auto; + + // Hide scrollbar but keep scrollability + scrollbar-width: thin; + &::-webkit-scrollbar { height: 6px; } + &::-webkit-scrollbar-thumb { + background: var(--palette_brand_300); + border-radius: 3px; + } +} + +.promptText { + font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; + font-size: 0.8125rem; + color: var(--agent-text); + background: transparent; + border: none; + padding: 0; + white-space: nowrap; + display: block; +} + +.copyButton { + flex-shrink: 0; + display: inline-flex; + align-items: center; + gap: 6px; + background: var(--agent-button-bg); + color: var(--agent-button-text); + border: 1px solid var(--agent-accent); + border-radius: 6px; + padding: 7px 12px; + font-size: 0.8125rem; + font-weight: 600; + cursor: pointer; + transition: background-color 120ms ease, transform 80ms ease; + + &:hover { + background: var(--agent-button-bg-hover); + } + &:active { + transform: translateY(1px); + } + &:focus-visible { + outline: 2px solid var(--palette_info_400); + outline-offset: 2px; + } +} + +.subRow { + padding-left: 2px; +} + +.description { + font-size: 0.8125rem; + color: var(--agent-text-muted); + line-height: 1.4; +} + +.outline { + border-top: 1px dashed var(--agent-prompt-border); + padding-top: 8px; + margin-top: 2px; +} + +.outlineSummary { + display: inline-flex; + align-items: center; + gap: 6px; + cursor: pointer; + font-size: 0.8125rem; + font-weight: 600; + color: var(--agent-text); + list-style: none; + user-select: none; + padding: 2px 0; + + &::-webkit-details-marker { display: none; } + &:hover { opacity: 0.85; } + &:focus-visible { + outline: 2px solid var(--palette_info_400); + outline-offset: 2px; + border-radius: 3px; + } +} + +.outlineChevron { + transition: transform 150ms ease; + flex-shrink: 0; +} + +details[open] > .outlineSummary > .outlineChevron { + transform: rotate(90deg); +} + +.outlineList { + margin: 8px 0 2px 0; + padding-left: 1.4rem; + font-size: 0.8125rem; + color: var(--agent-text-muted); + line-height: 1.5; + + li { + margin: 2px 0; + padding-left: 2px; + } + li::marker { + color: var(--agent-text); + font-weight: 600; + } +} + +@media (max-width: 768px) { + .mainRow { + flex-wrap: wrap; + } + .promptArea { + order: 3; + width: 100%; + flex-basis: 100%; + } + .copyButton { + margin-left: auto; + } + .promptText { + white-space: pre-wrap; + word-break: break-all; + } +} + +[data-theme='dark'] .wrapper { + --agent-accent: var(--palette_brand_300); + --agent-accent-bg: rgba(251, 255, 70, 0.06); + --agent-text: var(--palette_neutral_0); + --agent-text-muted: var(--palette_neutral_200); + --agent-prompt-bg: var(--palette_neutral_800); + --agent-prompt-border: rgba(251, 255, 70, 0.35); + --agent-button-bg: var(--palette_brand_300); + --agent-button-bg-hover: var(--palette_brand_350); + --agent-button-text: var(--palette_neutral_900); +} + diff --git a/src/theme/MDXComponents.js b/src/theme/MDXComponents.js index ad70b5366cf..385703752e8 100644 --- a/src/theme/MDXComponents.js +++ b/src/theme/MDXComponents.js @@ -7,10 +7,12 @@ import MDXComponents from '@theme-original/MDXComponents'; import VStepper from '@site/src/components/Stepper/Stepper'; import GlossaryTooltip from '@site/src/components/GlossaryTooltip/GlossaryTooltip'; import KapaLink from '@site/src/components/KapaAI/KapaLink'; +import AgentPrompt from '@site/src/components/AgentPrompt'; // Define the enhanced components const enhancedComponents = { ...MDXComponents, + AgentPrompt, KapaLink, GlossaryTooltip, ul: (props) =>