diff --git a/docs/getting-started/try-it-out/on-k3d-locally.mdx b/docs/getting-started/try-it-out/on-k3d-locally.mdx index e34daf50..90a6f786 100644 --- a/docs/getting-started/try-it-out/on-k3d-locally.mdx +++ b/docs/getting-started/try-it-out/on-k3d-locally.mdx @@ -10,39 +10,46 @@ import Tabs from "@theme/Tabs"; import TabItem from "@theme/TabItem"; import { versions, defaultCredentials } from "../../_constants.mdx"; import AgentSetupBuilder from "@site/src/components/AgentSetupBuilder"; -import AgentCallout from "@site/src/components/AgentCallout"; +import { + SetupSwitch, + SetupAgent, + SetupManual, +} from "@site/src/components/SetupSwitch"; # Run OpenChoreo on K3d Locally -This guide walks you through setting up OpenChoreo on your machine with k3d. You will install each plane one at a time, and after each one you will do something real with it: log in, deploy a service, or trigger a build. +This guide runs all four OpenChoreo planes on your machine, in a single k3d cluster. OpenChoreo has four planes: - **Control Plane** runs the API, console, identity provider, and controllers. - **Data Plane** runs your workloads and routes traffic to them. - **Workflow Plane** builds container images from source using Argo Workflows. -- **Observability Plane** collects logs and metrics from all other planes. +- **Observability Plane** collects logs and metrics from the other planes. -By the end you will have all four running in a single k3d cluster. +By the end you'll have a working installation on localhost: a web app you can open in your browser, a source-to-image build pipeline, and log collection. -**What you will get:** +Pick how you want to install it: -- A working OpenChoreo installation on localhost -- A deployed web app you can open in your browser -- A source-to-image build pipeline -- Log collection and querying + - + -Install the skill, pick your planes, and paste the prompt into your agent (Claude Code, Codex, Cursor, or any coding agent). +Install the `openchoreo-setup` skill. ```bash -npx skills add openchoreo/skills --skill openchoreo-setup +npx skills add openchoreo/skills --skill openchoreo-setup -g ``` +Then pick your planes and copy the prompt into your agent. + - + + + + +Install OpenChoreo by hand, one plane at a time. Start with the prerequisites, then work through each step in order. ## Prerequisites @@ -1002,3 +1009,7 @@ k3d cluster delete openchoreo - Explore the sample applications - Read the [Deployment Topology](../../platform-engineer-guide/deployment-topology.mdx) guide for production setups - Learn about [Multi-Cluster Connectivity](../../platform-engineer-guide/multi-cluster-connectivity.mdx) for separating planes across clusters + + + + diff --git a/docs/getting-started/try-it-out/on-your-environment.mdx b/docs/getting-started/try-it-out/on-your-environment.mdx index 9db540b0..baed4c26 100644 --- a/docs/getting-started/try-it-out/on-your-environment.mdx +++ b/docs/getting-started/try-it-out/on-your-environment.mdx @@ -8,41 +8,48 @@ import CodeBlock from "@theme/CodeBlock"; import Link from "@docusaurus/Link"; import { versions, defaultCredentials } from "../../_constants.mdx"; import AgentSetupBuilder from "@site/src/components/AgentSetupBuilder"; -import AgentCallout from "@site/src/components/AgentCallout"; +import { + SetupSwitch, + SetupAgent, + SetupManual, +} from "@site/src/components/SetupSwitch"; # Run OpenChoreo in Your Environment -This guide walks you through setting up OpenChoreo on any Kubernetes cluster (k3s, GKE, EKS, DOKS, AKS, or self-managed). You will install each plane one at a time, and after each one you will do something real with it: log in, deploy a service, or trigger a build. +This guide runs OpenChoreo on any Kubernetes cluster (k3s, GKE, EKS, DOKS, AKS, or self-managed), using a **single-cluster topology** with all planes in one cluster. For split-cluster setups, follow [Multi-Cluster Connectivity](../../platform-engineer-guide/multi-cluster-connectivity.mdx). -It uses a **single-cluster topology** (all planes in one cluster). For split-cluster setups, follow [Multi-Cluster Connectivity](../../platform-engineer-guide/multi-cluster-connectivity.mdx). - -All gateways are configured with HTTPS using self-signed certificates by default. You can replace them with certificates from a real CA later. +Gateways use HTTPS with self-signed certificates by default; you can swap in certificates from a real CA later. OpenChoreo has four planes: - **Control Plane** runs the API, console, identity provider, and controllers. - **Data Plane** runs your workloads and routes traffic to them. - **Workflow Plane** builds container images from source using Argo Workflows. -- **Observability Plane** collects logs and metrics from all other planes. +- **Observability Plane** collects logs and metrics from the other planes. + +By the end you'll have OpenChoreo running on your cluster over HTTPS, reachable at a console URL through your LoadBalancer, with a web app deployed and, optionally, a source-to-image build pipeline and log collection. -**What you will get:** +Pick how you want to install it: -- OpenChoreo running on your Kubernetes cluster with HTTPS -- A reachable console URL over your cluster LoadBalancer -- A deployed web app you can open in your browser -- Optional source-to-image build pipeline and log collection + - + -Install the skill, pick your environment and planes, and paste the prompt into your agent (Claude Code, Codex, Cursor, or any coding agent). +Install the `openchoreo-setup` skill. ```bash -npx skills add openchoreo/skills --skill openchoreo-setup +npx skills add openchoreo/skills --skill openchoreo-setup -g ``` +Then pick your environment and planes, and copy the prompt into your agent. + - + + + + +Install OpenChoreo by hand, one plane at a time. Start with the prerequisites, then work through each step in order. ## Prerequisites @@ -1253,3 +1260,7 @@ kubectl delete namespace \ - Follow [Deploy and Explore](../deploy-and-explore.mdx) to understand the resources OpenChoreo creates - Explore the sample applications - Move to multi-cluster isolation using [Multi-Cluster Connectivity](../../platform-engineer-guide/multi-cluster-connectivity.mdx) + + + + diff --git a/plugins/docusaurus-plugin-markdown-export/mdxProcessor.js b/plugins/docusaurus-plugin-markdown-export/mdxProcessor.js index f7f320aa..a6135474 100644 --- a/plugins/docusaurus-plugin-markdown-export/mdxProcessor.js +++ b/plugins/docusaurus-plugin-markdown-export/mdxProcessor.js @@ -60,6 +60,11 @@ async function processMarkdownFile(content, constants, sourceDir, linkContext) { const { frontmatter, body } = extractFrontmatter(result); result = body; + // Step 2.5: Unwrap the interactive setup-switch. Drop the agent panel + // (interactive prompt builder — not meaningful as markdown) and strip the + // switch/manual container tags so the manual guide stays as clean markdown. + result = processSetupSwitch(result); + // Step 3: Process CodeBlock components result = processCodeBlocks(result, constants); @@ -118,6 +123,18 @@ function extractFrontmatter(content) { return { frontmatter, body }; } +function processSetupSwitch(content) { + let result = content; + // Remove the entire agent panel (prompt builder, npx, etc.). + result = result.replace(/[\s\S]*?<\/SetupAgent>/g, ''); + // Unwrap the switch + manual containers, keeping their markdown children. + result = result.replace(/<\/?SetupSwitch>/g, ''); + result = result.replace(/<\/?SetupManual>/g, ''); + // Drop any stray self-closing component tags (e.g. the plane builder). + result = result.replace(/]*\/>/g, ''); + return result; +} + function removeImports(content) { // Remove all import statements (single and multi-line) return content.replace(/^import\s+[\s\S]*?from\s+['"][^'"]+['"];?\s*$/gm, ''); diff --git a/src/components/AgentCallout/styles.module.css b/src/components/AgentCallout/styles.module.css index 9b15aa9d..c3b32dcd 100644 --- a/src/components/AgentCallout/styles.module.css +++ b/src/components/AgentCallout/styles.module.css @@ -47,3 +47,13 @@ .content { margin-top: 0.75rem; } + +.content :global([class*="codeBlockContainer"]) { + background: var(--ifm-background-surface-color); + border: 1px solid var(--ifm-color-emphasis-300); + box-shadow: none; +} + +.content :global(.prism-code) { + background: var(--ifm-background-surface-color); +} diff --git a/src/components/AgentSetupBuilder/index.tsx b/src/components/AgentSetupBuilder/index.tsx index 118b3857..99f891c3 100644 --- a/src/components/AgentSetupBuilder/index.tsx +++ b/src/components/AgentSetupBuilder/index.tsx @@ -139,9 +139,11 @@ export default function AgentSetupBuilder({ currentVersion, fixedEnv }: Props) { )} - {p.label} + + {p.label} + {p.required && (required)} + {p.desc} - {p.required && required} ); })} diff --git a/src/components/AgentSetupBuilder/styles.module.css b/src/components/AgentSetupBuilder/styles.module.css index 7c1d8d31..63b30d02 100644 --- a/src/components/AgentSetupBuilder/styles.module.css +++ b/src/components/AgentSetupBuilder/styles.module.css @@ -1,7 +1,7 @@ .builder { display: flex; flex-direction: column; - gap: 0.75rem; + gap: 1rem; margin-top: 0.75rem; } @@ -64,7 +64,7 @@ .planesGrid { display: grid; grid-template-columns: 1fr 1fr; - gap: 0.4rem; + gap: 0.55rem; } @media (max-width: 480px) { @@ -75,11 +75,11 @@ position: relative; display: flex; flex-direction: column; - gap: 0.1rem; - padding: 0.5rem 0.5rem 0.5rem 2rem; + gap: 0.2rem; + padding: 0.7rem 0.75rem 0.7rem 2.1rem; border-radius: 8px; - border: 1px solid var(--ifm-color-emphasis-200); - background: var(--ifm-color-emphasis-100); + border: 1px solid var(--ifm-color-emphasis-300); + background: var(--ifm-background-surface-color); cursor: pointer; text-align: left; transition: border-color 0.12s, background 0.12s, opacity 0.12s; @@ -87,14 +87,13 @@ .planeCardRequired { cursor: default; - opacity: 0.55; } .planeCard:not(.planeCardRequired):hover { border-color: var(--ifm-color-primary); } -.planeCardOn:not(.planeCardRequired) { +.planeCardOn { border-color: var(--ifm-color-primary); background: rgba(43, 140, 247, 0.08); } @@ -133,10 +132,9 @@ color: var(--ifm-color-emphasis-600); } -.planeReqBadge { - font-size: 0.65rem; - color: var(--ifm-color-emphasis-500); - font-style: italic; +.planeReqInline { + font-weight: 400; + color: var(--ifm-color-emphasis-600); } .builder :global(.prism-code) { diff --git a/src/components/SetupSwitch/index.tsx b/src/components/SetupSwitch/index.tsx new file mode 100644 index 00000000..5852ddbd --- /dev/null +++ b/src/components/SetupSwitch/index.tsx @@ -0,0 +1,93 @@ +import React, { createContext, useContext, useEffect, useRef, useState } from "react"; +import styles from "./styles.module.css"; + +// Split switch for the install pages. Both panels stay in the DOM and toggle +// via `hidden` (not unmounted) so the manual guide stays crawlable. + +type Choice = "agent" | "manual"; + +const SwitchCtx = createContext<{ sel: Choice; setSel: (s: Choice) => void }>({ + sel: "agent", + setSel: () => {}, +}); + +export function SetupSwitch({ children }: { children: React.ReactNode }) { + const [sel, setSel] = useState("agent"); + + // Expose the active pane on so the page TOC (rendered outside this + // component) can hide the manual headings while the agent panel is showing. + useEffect(() => { + const root = document.documentElement; + root.setAttribute("data-setup-pane", sel); + return () => root.removeAttribute("data-setup-pane"); + }, [sel]); + + return ( + +
+ + +
+ {children} +
+ ); +} + +export function SetupAgent({ children }: { children: React.ReactNode }) { + const { sel } = useContext(SwitchCtx); + return ; +} + +export function SetupManual({ children }: { children: React.ReactNode }) { + const { sel, setSel } = useContext(SwitchCtx); + const ref = useRef(null); + const pendingId = useRef(null); + + // A deep link or TOC click to a manual heading should reveal this panel. + useEffect(() => { + const reveal = () => { + const id = decodeURIComponent(window.location.hash.slice(1)); + if (!id || !ref.current) return; + const target = document.getElementById(id); + if (target && ref.current.hidden && ref.current.contains(target)) { + pendingId.current = id; + setSel("manual"); + } + }; + reveal(); + window.addEventListener("hashchange", reveal); + return () => window.removeEventListener("hashchange", reveal); + }, [setSel]); + + useEffect(() => { + if (sel === "manual" && pendingId.current) { + const target = document.getElementById(pendingId.current); + pendingId.current = null; + if (target) target.scrollIntoView(); + } + }, [sel]); + + return ( + + ); +} diff --git a/src/components/SetupSwitch/styles.module.css b/src/components/SetupSwitch/styles.module.css new file mode 100644 index 00000000..fcb398a6 --- /dev/null +++ b/src/components/SetupSwitch/styles.module.css @@ -0,0 +1,43 @@ +.band { + display: grid; + grid-template-columns: 1fr 1fr; + border: 1px solid var(--ifm-color-emphasis-300); + border-radius: 12px; + overflow: hidden; + margin: 1.25rem 0 1.5rem; +} + +@media (max-width: 600px) { + .band { grid-template-columns: 1fr; } +} + +.half { + padding: 1.1rem 1.2rem; + display: flex; + flex-direction: column; + gap: 0.35rem; + background: var(--ifm-background-surface-color); + cursor: pointer; + text-align: left; + border: none; + font: inherit; + color: inherit; + transition: background 0.12s; +} + +.half:first-child { border-right: 1px solid var(--ifm-color-emphasis-200); } + +@media (max-width: 600px) { + .half:first-child { border-right: none; border-bottom: 1px solid var(--ifm-color-emphasis-200); } +} + +.half:not([aria-selected="true"]):hover { background: var(--ifm-color-emphasis-100); } + +.half[aria-selected="true"] { + background: rgba(43, 140, 247, 0.10); +} + +.half[aria-selected="true"] .title { color: var(--ifm-color-primary); } + +.title { font-weight: 700; } +.desc { color: var(--ifm-color-emphasis-700); font-size: 0.86rem; } diff --git a/src/css/custom.css b/src/css/custom.css index 2ee54ce6..595756a6 100644 --- a/src/css/custom.css +++ b/src/css/custom.css @@ -330,3 +330,11 @@ html:not([data-theme='dark']) .DocSearch-Sidepanel-Prompt--submit { html:not([data-theme='dark']) .DocSearch-Sidepanel-Prompt--stop { background-color: #fff; } + +/* Install pages: hide the page TOC while the "agent" setup pane is active, + since every TOC entry belongs to the (hidden) manual guide. The TOC column + width is kept, so toggling panes does not reflow the content. */ +html[data-setup-pane='agent'] .theme-doc-toc-desktop, +html[data-setup-pane='agent'] .theme-doc-toc-mobile { + display: none; +}