diff --git a/src/components/home/features/index.tsx b/src/components/home/features/index.tsx index ae75c357..b3afaf34 100644 --- a/src/components/home/features/index.tsx +++ b/src/components/home/features/index.tsx @@ -20,7 +20,7 @@ const FEATURES = [ title: "Managed Postgres, colocated with your Lakehouse.", description: "Provision with the CLI, connect like any Postgres. Instant branching, scales to zero, and change data feed to Unity Catalog.", - href: "/product/data-lakehouse", + href: "/product/lakebase", visual: "lakebase", }, { diff --git a/src/components/products/testimonials-slider.tsx b/src/components/products/testimonials-slider.tsx index 14e43936..ae654796 100644 --- a/src/components/products/testimonials-slider.tsx +++ b/src/components/products/testimonials-slider.tsx @@ -29,6 +29,40 @@ const testimonialLogoAssets = [ src: "/img/products/testimonials/yipitdata.svg", width: 197, }, + // TODO(design): the SVGs below do not exist yet. Add the real brand logos to + // /static/img/products/testimonials/ before publishing the Databricks Apps + // and Agent Bricks pages, or these logos will 404. Registering them here + // prevents the wrong yipitDATA fallback logo from rendering in the meantime. + { + match: "sae", + src: "/img/products/testimonials/sae-international.svg", + width: 158, + }, + { + match: "e.on", + src: "/img/products/testimonials/eon.svg", + width: 160, + }, + { + match: "addi", + src: "/img/products/testimonials/addi.svg", + width: 128, + }, + { + match: "astrazeneca", + src: "/img/products/testimonials/astrazeneca.svg", + width: 193, + }, + { + match: "flo health", + src: "/img/products/testimonials/flo-health.svg", + width: 104, + }, + { + match: "lippert", + src: "/img/products/testimonials/lippert.svg", + width: 160, + }, ] as const; function getTestimonialLogoAsset(company: string) { diff --git a/src/components/theme/mobile-nav.tsx b/src/components/theme/mobile-nav.tsx index 79658429..859559c2 100644 --- a/src/components/theme/mobile-nav.tsx +++ b/src/components/theme/mobile-nav.tsx @@ -5,7 +5,9 @@ import { useLocation } from "@docusaurus/router"; import { DocsSidebarSearch } from "@/components/docs/sidebar-search"; import { + getActiveProductHref, isHeaderNavItemActive, + PRODUCT_LINKS, type HeaderNavItem, } from "@/lib/header-navigation"; import { cn } from "@/lib/utils"; @@ -126,7 +128,10 @@ function MobileTreeText({ export function MobileNav({ items, open, onOpenChange }: MobileNavProps) { const menuId = useId(); const { pathname } = useLocation(); + const activeProductHref = getActiveProductHref(pathname); const isHomeActive = pathname === "/"; + const productItem = items.find(({ label }) => label === "Product"); + const sectionItems = items.filter(({ label }) => label !== "Product"); useEffect(() => { onOpenChange(false); @@ -218,7 +223,7 @@ export function MobileNav({ items, open, onOpenChange }: MobileNavProps) { }; }, [onOpenChange, open]); - if (items.length === 0) { + if (!productItem || items.length === 0) { return null; } @@ -245,17 +250,15 @@ export function MobileNav({ items, open, onOpenChange }: MobileNavProps) { className="relative w-full h-full flex justify-between font-mono text-[20px] leading-none font-normal tracking-[-0.4px]" aria-label="Main navigation" > - {/* - Product nav section temporarily removed while product pages are - unpublished. This menu was reflowed (tree-line positions retuned) - for the shorter HOME + Solutions/Templates/Docs list. To restore - Product, revert this file to its pre-PR-114 version and uncomment - the Product entry in header-navigation.ts. - */} - - - - + + + + + + + + + - {items.map((item, index) => { + + {productItem.label.toLowerCase()} + + + {PRODUCT_LINKS.map((product, index) => { + const isActive = product.href === activeProductHref; + + return ( + + {product.label.toLowerCase()} + + ); + })} + + {sectionItems.map((item, index) => { const isActive = isHeaderNavItemActive(item, pathname); return ( @@ -278,9 +311,9 @@ export function MobileNav({ items, open, onOpenChange }: MobileNavProps) { aria-current={isActive ? "page" : undefined} className={cn( "left-[61px] right-5 md:left-[63px] md:right-[22px]", - index === 0 && "top-[58px]", - index === 1 && "top-[92px]", - index === 2 && "top-[126px]", + index === 0 && "top-[180px]", + index === 1 && "top-[214px]", + index === 2 && "top-[248px]", )} data-mobile-menu-section-link="true" key={item.href} diff --git a/src/components/theme/nav.tsx b/src/components/theme/nav.tsx index 96bff856..98ffe239 100644 --- a/src/components/theme/nav.tsx +++ b/src/components/theme/nav.tsx @@ -268,10 +268,7 @@ function Nav({ className, items }: HeaderNavProps) { {items.map((item) => { const { href, label } = item; - // The "Product" entry is temporarily commented out of HEADER_LINKS, - // so this branch never renders. Kept (with a widened comparison) so - // re-enabling Product is a one-line revert in header-navigation.ts. - if ((label as string) === "Product") { + if (label === "Product") { const isActive = Boolean(activeProductHref); return ( diff --git a/src/lib/header-navigation.ts b/src/lib/header-navigation.ts index 62dd1f98..1bbf0856 100644 --- a/src/lib/header-navigation.ts +++ b/src/lib/header-navigation.ts @@ -1,6 +1,5 @@ export const HEADER_LINKS = [ - // Temporarily hidden while product pages are unpublished. - // { label: "Product", href: "/product/data-lakehouse" }, + { label: "Product", href: "/product/lakebase" }, { label: "Solutions", href: "/solutions" }, { label: "Templates", href: "/templates" }, { label: "Docs", href: "/docs/start-here", activePath: "/docs" }, @@ -9,7 +8,7 @@ export const HEADER_LINKS = [ export type HeaderNavItem = (typeof HEADER_LINKS)[number]; export const PRODUCT_LINKS = [ - { label: "Lakebase", href: "/product/data-lakehouse" }, + { label: "Lakebase", href: "/product/lakebase" }, { label: "Agent Bricks", href: "/product/agent-bricks" }, { label: "Databricks Apps", href: "/product/databricks-apps" }, ] as const; diff --git a/src/lib/products/agent-bricks.ts b/src/lib/products/agent-bricks.ts index a8365136..0f0f5516 100644 --- a/src/lib/products/agent-bricks.ts +++ b/src/lib/products/agent-bricks.ts @@ -68,10 +68,10 @@ export const agentBricksProduct: ProductPageContent = { title: "Use the right model for every task.", description: "Switch between leading models like GPT, Claude, Llama, and more.", - body: "Send requests through a single API and route each task to the best-fitting model — without building your own orchestration layer.", + body: "Send requests through a single API and route across models by cost, performance, or availability — without building your own orchestration layer.", details: [ "Access models from multiple providers in one place", - "Route requests by task, cost, or performance", + "Route requests by cost, performance, or availability", "Built-in fallback and usage controls", ], visual: "multi-model", @@ -160,25 +160,25 @@ export const agentBricksProduct: ProductPageContent = { }, testimonials: [ { - company: "tibber", + company: "AstraZeneca", quote: - "At Tibber, empowering customers to take control of their energy consumption requires a flexible data infrastructure. Lakebase's integration with Databricks makes it easy to serve analytical and transactional data, helping us deliver real-time insights to our customers.", - attributionName: "Niklas Nordansjo", - attributionTitle: "Data Platform Lead", + "With Agent Bricks, our teams were able to parse through more than 400,000 clinical trial documents and extract structured data points — without writing a single line of code. In just under 60 minutes, we had a working agent that can transform complex unstructured data usable for Analytics.", + attributionName: "Joseph Roemer", + attributionTitle: "Head of Data & AI, Commercial IT", }, { - company: "Ensemble Health Partners", + company: "Flo Health", quote: - "Lakebase lets an agentic team quickly self-serve the data they need for their models, whether it's historical claims or real-time transactions, and that's really powerful.", - attributionName: "Dragon Sky", - attributionTitle: "Chief Architect", + "Agent Bricks enabled us to double our medical accuracy over standard commercial LLMs, while meeting Flo Health's high internal standards for clinical accuracy, safety, privacy, and security.", + attributionName: "Roman Bugaev", + attributionTitle: "CTO", }, { - company: "yipitDATA", + company: "Lippert", quote: - "Lakebase gives us a durable, low-latency store for application state, so our data apps load quickly, refresh seamlessly and even support shared page links between users.", - attributionName: "Bobby Muldoon", - attributionTitle: "VP of Engineering", + "With Agent Bricks, we can quickly productionize domain-specific AI agents for tasks like extracting insights from customer support calls — something that used to take weeks of manual review.", + attributionName: "Chris Nishnick", + attributionTitle: "Director of AI", }, ], }; diff --git a/src/lib/products/databricks-apps.ts b/src/lib/products/databricks-apps.ts index c0cf5520..bd2d9785 100644 --- a/src/lib/products/databricks-apps.ts +++ b/src/lib/products/databricks-apps.ts @@ -67,12 +67,12 @@ export const databricksAppsProduct: ProductPageContent = { index: "01", title: "Run your app inside Databricks.", description: - "Serverless hosting for full-stack apps, with compute, routing, and deployment handled.", + "Serverless hosting for full-stack apps, with compute, TLS, and deployment handled.", body: "Apps run inside your workspace — no infrastructure to manage and no separate hosting to maintain.", details: [ "Containerized runtime with managed compute", - "Built-in routing, TLS, and app URLs", - "Built-in routing, TLS, and app URLs", + "Built-in TLS and automatic HTTPS app URLs", + "Automatic builds and deploys from source", ], visual: "serverless", }, @@ -155,31 +155,30 @@ export const databricksAppsProduct: ProductPageContent = { ], testimonialsIntro: { eyebrow: "Testimonials", - titleLead: "Lakebase powers applications.", - titleMuted: - "See how teams use it to bring data directly into user experiences.", + titleLead: "Databricks Apps powers real applications.", + titleMuted: "See how teams ship data and AI apps on the platform.", }, testimonials: [ { - company: "tibber", + company: "SAE International", quote: - "At Tibber, empowering customers to take control of their energy consumption requires a flexible data infrastructure. Lakebase's integration with Databricks makes it easy to serve analytical and transactional data, helping us deliver real-time insights to our customers.", - attributionName: "Niklas Nordansjo", - attributionTitle: "Data Platform Lead", + "Databricks Apps helped me turn my RAG proof of concept into a polished and branded application. We built a RAG system to answer user questions by utilizing our company's extensive knowledge base.", + attributionName: "Heather Gomer", + attributionTitle: "Senior Data Scientist", }, { - company: "Ensemble Health Partners", + company: "E.ON Digital Technology", quote: - "Lakebase lets an agentic team quickly self-serve the data they need for their models, whether it's historical claims or real-time transactions, and that's really powerful.", - attributionName: "Dragon Sky", - attributionTitle: "Chief Architect", + "The seamless integration of Databricks Apps into our DevOps processes enables us to quickly demonstrate and test new features with users while also providing a secure, production-ready front end for the internal application — all without needing additional infrastructure.", + attributionName: "Lukas Heidegger", + attributionTitle: "Data and MLOps Engineer", }, { - company: "yipitDATA", + company: "Addi", quote: - "Lakebase gives us a durable, low-latency store for application state, so our data apps load quickly, refresh seamlessly and even support shared page links between users.", - attributionName: "Bobby Muldoon", - attributionTitle: "VP of Engineering", + "By using Databricks Apps, we saved many rounds with the security and infrastructure team and were able to instantly share our app with stakeholders in production.", + attributionName: "Cesar Augusto Charalla Olazo", + attributionTitle: "Senior Machine Learning Engineer", }, ], }; diff --git a/src/lib/products/lakebase.ts b/src/lib/products/lakebase.ts index 58062c76..c28421d4 100644 --- a/src/lib/products/lakebase.ts +++ b/src/lib/products/lakebase.ts @@ -82,7 +82,7 @@ export const lakebaseProduct: ProductPageContent = { title: "Right-size your compute automatically.", description: "Demand-driven, scaled to zero on idle, milliseconds to wake.", - body: "Lakebase tracks load in real time and adjusts capacity within the range you set, billing per active second.", + body: "Lakebase tracks load in real time and adjusts capacity within the range you set, with no compute cost while idle.", details: [ "Non-disruptive scaling within range", "Independent autoscaling per replica", @@ -94,7 +94,8 @@ export const lakebaseProduct: ProductPageContent = { eyebrow: "Lakehouse sync", index: "03", title: "Connect your app to your Lakehouse.", - description: "Two-way, fully managed, governed by Unity Catalog.", + description: + "Inbound and outbound, fully managed, governed by Unity Catalog.", body: "Both directions are managed by Databricks, no external pipelines, no jobs you have to operate, no glue code to maintain.", details: [ "Snapshot, triggered, or continuous sync", diff --git a/src/pages/index.tsx b/src/pages/index.tsx index ec40363c..27440a74 100644 --- a/src/pages/index.tsx +++ b/src/pages/index.tsx @@ -56,7 +56,7 @@ export default function Home(): ReactNode {
- {/* */} +
+ + + + + + + + ); +} diff --git a/src/pages/product/_databricks-apps.tsx b/src/pages/product/databricks-apps.tsx similarity index 100% rename from src/pages/product/_databricks-apps.tsx rename to src/pages/product/databricks-apps.tsx diff --git a/src/pages/product/_data-lakehouse.tsx b/src/pages/product/lakebase.tsx similarity index 100% rename from src/pages/product/_data-lakehouse.tsx rename to src/pages/product/lakebase.tsx diff --git a/static/img/products/testimonials/addi.svg b/static/img/products/testimonials/addi.svg new file mode 100644 index 00000000..3260eedf --- /dev/null +++ b/static/img/products/testimonials/addi.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/static/img/products/testimonials/astrazeneca.svg b/static/img/products/testimonials/astrazeneca.svg new file mode 100644 index 00000000..0f33d8b4 --- /dev/null +++ b/static/img/products/testimonials/astrazeneca.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/static/img/products/testimonials/eon.svg b/static/img/products/testimonials/eon.svg new file mode 100644 index 00000000..01f1cb26 --- /dev/null +++ b/static/img/products/testimonials/eon.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/static/img/products/testimonials/flo-health.svg b/static/img/products/testimonials/flo-health.svg new file mode 100644 index 00000000..7412697b --- /dev/null +++ b/static/img/products/testimonials/flo-health.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/static/img/products/testimonials/lippert.svg b/static/img/products/testimonials/lippert.svg new file mode 100644 index 00000000..d94cb6b4 --- /dev/null +++ b/static/img/products/testimonials/lippert.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/static/img/products/testimonials/sae-international.svg b/static/img/products/testimonials/sae-international.svg new file mode 100644 index 00000000..9da4a5b6 --- /dev/null +++ b/static/img/products/testimonials/sae-international.svg @@ -0,0 +1 @@ + diff --git a/tests/e2e/navigation.spec.ts b/tests/e2e/navigation.spec.ts index bfa4fddc..f31bbf4b 100644 --- a/tests/e2e/navigation.spec.ts +++ b/tests/e2e/navigation.spec.ts @@ -65,12 +65,11 @@ test.describe("navbar navigation", () => { }); } - // Skipped while the Product nav dropdown is hidden. - test.skip("product dropdown hover state is visible in production CSS", async ({ + test("product dropdown hover state is visible in production CSS", async ({ page, }) => { await page.setViewportSize({ width: 1440, height: 900 }); - await page.goto("/product/data-lakehouse"); + await page.goto("/product/lakebase"); await page.getByRole("button", { name: "[Product]" }).hover(); const productMenu = page.locator('[data-slot="navigation-menu-content"]'); @@ -184,7 +183,7 @@ test.describe.skip("mobile navigation", () => { width: viewport.width, height: viewport.height, }); - await page.goto("/product/data-lakehouse"); + await page.goto("/product/lakebase"); await page.getByRole("button", { name: "Open menu" }).click(); @@ -538,19 +537,18 @@ test.describe("home page link navigation", () => { expect(finalCopiedText).toContain("llms.txt"); }); - // Skipped while the home Features pillar cards and product pages are hidden. - test.skip("pillar card Lakebase navigates to /product/data-lakehouse", async ({ + test("pillar card Lakebase navigates to /product/lakebase", async ({ page, }) => { await page.goto("/"); - const link = page.locator('a[href="/product/data-lakehouse"]').first(); + const link = page.locator('a[href="/product/lakebase"]').first(); await link.waitFor({ state: "visible" }); await link.click(); - await page.waitForURL("**/product/data-lakehouse"); - expect(new URL(page.url()).pathname).toBe("/product/data-lakehouse"); + await page.waitForURL("**/product/lakebase"); + expect(new URL(page.url()).pathname).toBe("/product/lakebase"); }); - test.skip("pillar card Agent Bricks navigates to /product/agent-bricks", async ({ + test("pillar card Agent Bricks navigates to /product/agent-bricks", async ({ page, }) => { await page.goto("/"); @@ -559,7 +557,7 @@ test.describe("home page link navigation", () => { expect(new URL(page.url()).pathname).toBe("/product/agent-bricks"); }); - test.skip("pillar card Databricks Apps navigates to /product/databricks-apps", async ({ + test("pillar card Databricks Apps navigates to /product/databricks-apps", async ({ page, }) => { await page.goto("/"); diff --git a/tests/e2e/pages.spec.ts b/tests/e2e/pages.spec.ts index f83a4fb3..a1fb7642 100644 --- a/tests/e2e/pages.spec.ts +++ b/tests/e2e/pages.spec.ts @@ -2,10 +2,9 @@ import { test, expect } from "@playwright/test"; const PAGES = [ { path: "/", title: "Databricks Developer" }, - // Product pages temporarily unpublished (hidden via `_` prefix). - // { path: "/product/data-lakehouse", title: "Lakebase" }, - // { path: "/product/agent-bricks", title: "Agent Bricks" }, - // { path: "/product/databricks-apps", title: "Databricks Apps" }, + { path: "/product/lakebase", title: "Lakebase" }, + { path: "/product/agent-bricks", title: "Agent Bricks" }, + { path: "/product/databricks-apps", title: "Databricks Apps" }, { path: "/solutions", title: "Solutions" }, { path: "/solutions/devhub-launch", @@ -121,6 +120,17 @@ test.describe("static assets load correctly", () => { }); }); +test.describe("legacy redirects", () => { + test("/product/data-lakehouse redirects to /product/lakebase", async ({ + page, + }) => { + await page.goto("/product/data-lakehouse"); + await page.waitForURL("**/product/lakebase"); + expect(new URL(page.url()).pathname).toBe("/product/lakebase"); + await expect(page).toHaveTitle(/Lakebase/); + }); +}); + test.describe("solutions RSS", () => { test("RSS action links to the generated feed", async ({ page }) => { await page.goto("/solutions");