Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion nuxt/components/AppHeader.vue
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ onMounted(() => {
<li class="pl-3 title border-l-2 border-gray-200" :class="col.titleGrid"><span class="flex items-center gap-2"><span class="ff-nav-label">{{ col.title }}</span></span></li>
<li class="contents">
<ul class="sub-menu grid grid-rows-subgrid ml-7 auto-rows-auto border-l-2 border-gray-200" :class="col.listClasses">
<li v-for="item in col.links" :key="item.label"><a class="flex items-center gap-2" :href="resolveHref(item.href)"><NavIcon :name="item.icon" :solid="!!item.solid" /><span class="ff-nav-label">{{ item.label }}</span></a></li>
<li v-for="item in col.links" :key="item.label" :class="{ 'nav-indent': item.indent }"><a class="flex items-center gap-2" :href="resolveHref(item.href)"><NavIcon :name="item.icon" :solid="!!item.solid" /><span class="ff-nav-label">{{ item.label }}</span></a></li>
</ul>
</li>
</template>
Expand Down
4 changes: 3 additions & 1 deletion nuxt/components/CertifiedNodes.vue
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
<script setup lang="ts">
const props = withDefaults(defineProps<{ defaultTier?: 'it' | 'ot' }>(), { defaultTier: 'it' })

const { data } = await useAsyncData('certified-nodes', () => queryCollection('certifiedNodes').first())

const bundles = computed(() => data.value?.bundles ?? [])
type Bundle = typeof bundles.value[number]

const active = ref<'it' | 'ot'>('it')
const active = ref<'it' | 'ot'>(props.defaultTier)
const activeBundle = computed(() => bundles.value.find(b => b.id === active.value) ?? bundles.value[0])
const nodeCount = (b?: Bundle) => b ? b.groups.reduce((n, g) => n + g.nodes.length, 0) : 0

Expand Down
35 changes: 35 additions & 0 deletions nuxt/content.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,41 @@ export default defineContentConfig({
bestFitFor: z.array(z.string()).optional(),
})
}),
products: defineCollection({
type: 'data',
source: 'products/*.yml',
schema: z.object({
tierId: z.string(),
label: z.string(),
metaDescription: z.string(),
eyebrow: z.string(),
headingLead: z.string(),
headingHighlight: z.string(),
description: z.string(),
heroImage: z.object({
src: z.string(),
alt: z.string(),
}),
quote: z.object({
text: z.string(),
author: z.string(),
role: z.string(),
avatar: z.string().optional(),
}),
fitYes: z.array(z.string()),
fitNo: z.array(z.string()),
included: z.array(z.object({
title: z.string(),
chips: z.array(z.union([
z.string(),
z.object({ label: z.string(), href: z.string() }),
])),
})),
certifiedDefault: z.enum(['it', 'ot']).optional(),
crossLinkEyebrow: z.string(),
crossLinkDescription: z.string(),
})
}),
featureCatalog: defineCollection({
type: 'data',
source: 'feature-catalog.yml',
Expand Down
58 changes: 58 additions & 0 deletions nuxt/content/products/edge.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
tierId: edge
label: FlowFuse Edge
metaDescription: "Run the plant floor and standardize it everywhere. FlowFuse Edge connects your PLCs, machines, and controllers and governs the data between them, built for how OT teams work."
eyebrow: "For OT & Digitalization Leadership"
headingLead: "Run the plant floor."
headingHighlight: "Standardize it everywhere."
description: "FlowFuse Edge connects your PLCs, machines, and controllers and governs the data between them. Designed for how OT teams work. If you're looking for an IT solution instead, check out <a class=\"text-indigo-600 hover:underline\" href=\"/product/hub/\">FlowFuse Hub</a>."
heroImage:
src: /images/home/home-scada.png
alt: "FlowFuse Edge: industrial edge connectivity"
quote:
text: "The ability to edit once and deploy everywhere has added real efficiency to how we manage integrations. This is how enterprises scale automation."
author: "Sevan Petrosian"
role: "Sr. Application Engineer, Arch Systems"
avatar: /images/customer-headshots/servan-petrosian-arch-systems.png
fitYes:
- "Data originates at machines on the plant floor: PLCs, SCADA, sensors, and controllers."
- "You need OT-certified industrial protocol connectivity: OPC-UA, Modbus, EtherNet/IP, and more."
- "OT or digitalization teams are standardizing production across multiple sites."
fitNo:
- "Your data moves purely between software systems, like ERPs, databases, and cloud APIs. That's <a class=\"text-indigo-600 hover:underline\" href=\"/product/hub/\">FlowFuse Hub</a>."
- "Managing large fleets of distributed devices is your primary unit of scale. That's <a class=\"text-indigo-600 hover:underline\" href=\"/product/fleet/\">FlowFuse Fleet</a>."
- "You have no industrial hardware to connect. A pure IT integration project belongs on <a class=\"text-indigo-600 hover:underline\" href=\"/product/hub/\">FlowFuse Hub</a>."
included:
- title: "Connect the plant floor"
chips:
- label: "Certified OT Connections (OPC-UA, Modbus, EtherNet/IP, RTSP)"
href: "/integrations/?product=edge&certified=1"
- label: "MQTT Broker"
href: "/docs/user/teambroker/"
- label: "HTTP Request"
href: "/node-red/core-nodes/http-request/"
- title: "Develop & deploy at the edge"
chips:
- label: "Edge Development (remote editor proxy)"
href: "/docs/device-agent/running/"
- label: "Edge Instances"
href: "/docs/device-agent/deploy/"
- label: "Snapshots & Rollback"
href: "/docs/user/snapshots/"
- title: "Manage devices across sites"
chips:
- label: "Device Fleet Updates"
href: "/docs/device-agent/deploy/"
- label: "Device Group Management"
href: "/docs/user/device-groups/"
- "Performance Monitoring & Alerts"
- title: "Built to collaborate"
chips:
- label: "OT App Blueprints"
href: "/blueprints/"
- label: "Team Library"
href: "/docs/user/shared-library/"
- label: "Everything in the core FlowFuse platform"
href: "/product/"
certifiedDefault: ot
crossLinkEyebrow: "For OT Teams"
crossLinkDescription: "Connect PLCs, machines, and controllers and standardize automation across every site."
56 changes: 56 additions & 0 deletions nuxt/content/products/fleet.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
tierId: fleet
label: FlowFuse Fleet
metaDescription: "Manage a Node-RED fleet and ship updates everywhere. FlowFuse Fleet runs Node-RED across thousands of distributed devices with remote updates, rollback, and fleet-wide visibility, built for hardware OEMs, partners, and asset operators."
eyebrow: "For Hardware OEMs & Asset Operators"
headingLead: "Manage a Node-RED fleet."
headingHighlight: "Ship updates everywhere."
description: "FlowFuse Fleet runs Node-RED across thousands of distributed devices in the field, with remote updates, rollback, and fleet-wide visibility. Built for hardware OEMs, partners, and asset operators. If you're connecting a single plant floor, see <a class=\"text-indigo-600 hover:underline\" href=\"/product/edge/\">FlowFuse Edge</a>."
heroImage:
src: /images/product/fleet.jpg
alt: "FlowFuse Fleet: device fleet management console"
quote:
text: "We knew we needed a solution to help us manage our edge devices as well as our central control system. FlowFuse has helped us take our Node-RED from proof-of-concept through to a reliable, scalable solution for the future."
author: "Robert VanHofwegen"
role: "Paloma Irrigation District"
fitYes:
- "You operate large numbers of distributed devices across remote sites."
- "You ship Node-RED inside your own product, as an OEM or solution builder."
- "You need remote updates, rollback, and fleet-wide visibility without firmware releases."
fitNo:
- "Your work is integrating software systems centrally, like ERPs, databases, and APIs. That's <a class=\"text-indigo-600 hover:underline\" href=\"/product/hub/\">FlowFuse Hub</a>."
- "You're connecting machines on a single plant floor. That's <a class=\"text-indigo-600 hover:underline\" href=\"/product/edge/\">FlowFuse Edge</a>."
- "You manage a handful of instances, not a fleet. The core platform likely already covers you."
included:
- title: "Manage devices at scale"
chips:
- label: "Remote Device & Instance Management"
href: "/docs/device-agent/deploy/"
- label: "Device Fleet Updates"
href: "/docs/device-agent/deploy/"
- label: "Device Group Management"
href: "/docs/user/device-groups/"
- title: "Ship & roll back safely"
chips:
- label: "Snapshot & Rollback"
href: "/docs/user/snapshots/"
- label: "DevOps Pipelines"
href: "/docs/user/devops-pipelines/"
- label: "Edge Development"
href: "/docs/device-agent/running/"
- title: "Monitor the fleet"
chips:
- label: "Live Monitoring"
href: "/docs/user/instance-states/"
- "Performance Monitoring & Alerts"
- label: "Audit Log"
href: "/docs/user/logs/#team-audit-log"
- title: "Built to collaborate"
chips:
- label: "Team Library"
href: "/docs/user/shared-library/"
- label: "Blueprints"
href: "/blueprints/"
- label: "Everything in the core FlowFuse platform"
href: "/product/"
crossLinkEyebrow: "For Device Fleets"
crossLinkDescription: "Push flows, ship updates, and roll back remotely across thousands of distributed devices."
67 changes: 67 additions & 0 deletions nuxt/content/products/hub.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
tierId: hub
label: FlowFuse Hub
metaDescription: "Move data across the business and govern it centrally. FlowFuse Hub connects your ERPs, databases, and cloud APIs into one governed system, built for central IT and enterprise architecture teams."
eyebrow: "For IT & Integration Teams"
headingLead: "Move data across the business."
headingHighlight: "Govern it centrally."
description: "FlowFuse Hub connects your ERPs, databases, and cloud APIs into one governed system. Built for central IT and enterprise architecture teams. If you're looking for plant floor connectivity, see <a class=\"text-indigo-600 hover:underline\" href=\"/product/edge/\">FlowFuse Edge</a>."
heroImage:
src: /images/product/hub.jpg
alt: "FlowFuse Hub: enterprise data integration"
quote:
text: "FlowFuse allows us to rapidly roll out updates to clients without burdening our development team. We can deliver custom dashboards to customers without involving any of our core developers."
author: "Dave Olsen"
role: "Product Manager, Wenco"
avatar: /images/customer-headshots/dave-olsen-wenco.png
fitYes:
- "Data moves between software systems: ERPs, databases, cloud APIs, message queues."
- "You're building governed integration, not point-to-point scripts."
- "Central IT or an integration team is sponsoring the project."
fitNo:
- "Data originates at machines on a plant floor. That's <a class=\"text-indigo-600 hover:underline\" href=\"/product/edge/\">FlowFuse Edge</a>, even if an ERP sits at the far end of the pipeline."
- "Devices are your primary unit of scale (fleets of sensors, remote sites). That's <a class=\"text-indigo-600 hover:underline\" href=\"/product/fleet/\">FlowFuse Fleet</a>."
- "You need PLC, SCADA, or industrial protocol connectivity. Hub doesn't include OT-certified nodes."
included:
- title: "Move data, reliably"
chips:
- label: "Git Integration"
href: "/docs/user/devops-pipelines/#git-repository-stage"
- label: "High Availability"
href: "/docs/user/high-availability/"
- label: "DevOps Pipelines"
href: "/docs/user/devops-pipelines/"
- label: "Private NPM Registry"
href: "/docs/user/custom-npm-packages/"
- label: "FlowFuse Tables"
href: "/docs/user/ff-tables/"
- title: "Certified for IT systems"
chips:
- label: "MQTT"
href: "/node-red/flowfuse/mqtt/"
- label: "HTTP Request"
href: "/node-red/core-nodes/http-request/"
- "Kafka"
- label: "Redis"
href: "/node-red/flowfuse/hub/redis/"
- label: "AI nodes (Gemini, Claude, ChatGPT, Ollama)"
href: "/node-red/flowfuse/ai/llm-nodes/"
- title: "Governed by default"
chips:
- label: "Application-Level RBAC"
href: "/docs/user/role-based-access-control/"
- label: "Endpoint Security"
href: "/docs/user/instance-settings/#flowfuse-user-authentication"
- "BAA for HIPAA"
- label: "Protected Instances"
href: "/docs/user/devops-pipelines/#protected-instances"
- title: "Built to collaborate"
chips:
- label: "Team Library"
href: "/docs/user/shared-library/"
- label: "IT App Blueprints"
href: "/blueprints/"
- label: "Everything in the core FlowFuse platform"
href: "/product/"
certifiedDefault: it
crossLinkEyebrow: "For IT Teams"
crossLinkDescription: "Integrate and orchestrate data across ERPs, databases, and cloud APIs, governed centrally."
15 changes: 15 additions & 0 deletions nuxt/nuxt.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,20 @@ function collectApplicationGuideRoutes(dir: string): string[] {
return routes
}

// The product tier pages (/product/[tier]/) are a `data` collection (see content.config.ts),
// so their routes aren't discoverable from @nuxt/content page paths either. Derive them from
// each file's `tierId` field rather than the filename, since that's the field the page route
// actually queries on.
function collectProductRoutes (dir: string): string[] {
const routes: string[] = []
for (const file of readdirSync(dir)) {
if (!file.endsWith('.yml')) continue
const { tierId } = parseYaml(readFileSync(join(dir, file), 'utf8'))
routes.push(`/product/${tierId}/`)
}
return routes
}

// Same idea for blog posts. Each entry also carries its `tags` so the 13 tag-listing
// pages (and their own pagination, 19 entries/page) can be sized correctly, and its
// `authors` so the /blog/author/{slug}/ pages can be enumerated.
Expand Down Expand Up @@ -320,6 +334,7 @@ export default defineNuxtConfig({
'/integrations',
'/pricing',
'/product',
...collectProductRoutes(join(__dirname, 'content/products')),
// Without this, @nuxtjs/sitemap only bakes /sitemap.xml statically when
// isNuxtGenerate() is true, which checks for nitro.static/preset "static" -
// the netlify preset here is hybrid (prerendered pages + a fallback
Expand Down
Loading
Loading