From 5fe5c9ff6b162aee19568fc8d4ef412e7554068d Mon Sep 17 00:00:00 2001 From: Dimitrie Hoekstra Date: Thu, 27 Aug 2026 16:15:49 +0200 Subject: [PATCH 1/9] ai: extract the agent picker into a shared content component The tabs and their three setup steps were inline in the /ai page. They are now AgentSetupTabs in nuxt/components/content/, so markdown can use them too, and the changelog entry does instead of listing the agents as links. excludeExpert drops the FlowFuse Expert tab on surfaces that are specifically about connecting your own agent. surface prefixes the PostHog positions everywhere except /ai, whose existing positions are left alone. --- nuxt/components/content/AgentSetupTabs.vue | 189 ++++++++++++++++++ nuxt/pages/ai/index.vue | 156 +-------------- .../2026/08/connect-your-own-ai-agent.md | 7 +- 3 files changed, 199 insertions(+), 153 deletions(-) create mode 100644 nuxt/components/content/AgentSetupTabs.vue diff --git a/nuxt/components/content/AgentSetupTabs.vue b/nuxt/components/content/AgentSetupTabs.vue new file mode 100644 index 0000000000..bd5df9ae3b --- /dev/null +++ b/nuxt/components/content/AgentSetupTabs.vue @@ -0,0 +1,189 @@ + + + diff --git a/nuxt/pages/ai/index.vue b/nuxt/pages/ai/index.vue index abcbddd699..ed3ea81a3d 100644 --- a/nuxt/pages/ai/index.vue +++ b/nuxt/pages/ai/index.vue @@ -6,8 +6,9 @@ import { getAllBlogPosts } from '~/utils/sharedContent' // What the port changes on purpose: // - The two hand-rolled DOM scripts (agent tabs, showcase rotation) become // reactive state. That was ~120 lines of querySelectorAll in the .njk. -// - The copy button becomes , shared with the changelog and any other -// markdown page, instead of markup plus a copy helper pasted per page. +// - The copy button becomes , and the whole agent picker becomes +// , both shared with the changelog and the docs page instead +// of markup plus a copy helper pasted per page. // - jsonld.njk's meta.faq becomes useSchemaOrg, which escapes properly. The 11ty // partial interpolated answers straight into a JSON string. // - Sign-up buttons become , so the copy is the site's fixed "Try it @@ -52,92 +53,8 @@ useSchemaOrg([ ...FAQ.map(item => defineQuestion({ question: item.question, answer: item.answer })), ]) -const ENDPOINT = 'https://app.flowfuse.com/mcp' - -const STEP1 = { - title: 'Copy the FlowFuse connector URL', - description: 'You will paste this into your agent in the next step.', -} -const STEP3 = { - title: 'Sign in and choose what it reaches', - description: 'Which teams the agent may act on, and whether it has editing rights or read access only.', -} - -// A client renders `logo` as a brand mark when set, `icon` as our own glyph when not. -// A brand mark keeps its own colours so it stays an ; the glyph inherits -// currentColor and turns white with the label when its tab is active. -const CLIENTS = [ - { - id: 'expert', - logo: '/images/ai/agents/flowfuse-expert.svg', - name: 'FlowFuse Expert', - builtIn: true, - step1Title: 'Sign in to FlowFuse', - step1Body: 'A new account puts you in a hosted instance with Expert already in the editor. Nothing to add, no connector, no token.', - step2Title: 'Or start with the Device Agent', - step2Body: 'Already running Node-RED on your own hardware? Connect it as a remote instance and Expert works there in the same way.', - step2Label: 'Install the Device Agent', - step2Url: '/docs/device-agent/quickstart/', - step3Title: 'Ask for what you need', - step3Body: 'Build a flow, explain one you inherited, write the Function node, or ask what is running on the floor. Every write waits for you to approve, edit or reject.', - noStep3Cta: true, - }, - { - id: 'copilot', - logo: '/images/ai/agents/microsoft-copilot.svg', - name: 'Microsoft Copilot', - step2Title: 'Copilot Studio, Tools, Add a tool', - step2Body: 'Choose Model Context Protocol and paste the URL. Describe what it is for: the orchestrator reads that to decide when to call it.', - step2Label: 'Open Copilot Studio', - step2Url: 'https://copilotstudio.microsoft.com/', - }, - { - id: 'chatgpt', - logo: '/images/ai/agents/chatgpt.svg', - name: 'ChatGPT', - step2Title: 'Settings, Connectors', - step2Body: 'An administrator enables custom connectors first, under Permissions and Roles.', - step2Label: 'Open ChatGPT', - step2Url: 'https://chatgpt.com/', - }, - { - id: 'claude', - logo: '/images/ai/agents/claude.svg', - name: 'Claude', - step2Title: 'Settings, Customize, Connectors', - step2Body: 'Add a custom connector and paste the URL. On Team and Enterprise an owner adds it once for everyone.', - step2Label: 'Open Claude connectors', - step2Url: 'https://claude.ai/settings/connectors', - }, - { - id: 'gemini', - logo: '/images/ai/agents/gemini.svg', - name: 'Gemini', - step2Title: 'Settings, Manage team, Connected apps', - step2Body: 'Add the FlowFuse URL as an MCP server.', - step2Label: 'Open Gemini', - step2Url: 'https://gemini.google.com/', - }, - { - id: 'local', - icon: 'i-lucide-server', - name: 'Local and Custom Agents', - step2Title: "Your MCP client's config", - step2Body: 'Any MCP-capable client works, pointed at your own model, so nothing has to leave your network.', - step2Label: 'See the documentation', - step2Url: '/docs/user/expert/', - }, -] - const CODING_NOTE = 'Command-line and editor agents such as Claude Code, Cursor, Visual Studio Code and Gemini CLI connect to the same URL.' -const activeClient = ref(CLIENTS[0].id) - -function selectClient (id: string) { - activeClient.value = id - capture('cta-ai-agent-tab', { position: id }) -} - const GOVERNANCE = { title: 'AI Governance you can prove', subtitle: 'The control plane every AI action runs through, the same one that governs your teams.', @@ -289,72 +206,7 @@ onUnmounted(() => { -
-
- -
- -
-
-

01

-

{{ client.builtIn ? client.step1Title : STEP1.title }}

-

{{ client.builtIn ? client.step1Body : STEP1.description }}

-
- -
-
- -
-
- -
-

02

-

{{ client.step2Title }}

-

{{ client.step2Body }}

- -
- -
-

03

-

{{ client.step3Title || STEP3.title }}

-

{{ client.step3Body || STEP3.description }}

-
- -
-
-
-
+ - +