From f721df51a91e9463d7bad96c562e7282003e09e8 Mon Sep 17 00:00:00 2001 From: Tony Dang Date: Sun, 31 May 2026 14:25:50 -0700 Subject: [PATCH 1/4] feat(templates): add "Open prompt in" dropdown with Replit Agent support Templates that ship a replit-prompt.md now render an "Open prompt in" dropdown next to Copy prompt. The Replit menu item opens replit.com with the prompt lz-string-compressed into the URL, so Replit Agent picks it up on landing. Plumbing: - readReplitPrompt(rootDir, tier, slug) reads from any of the three template tiers (examples, recipes, cookbooks) - replitPromptsBySlug exposed by both the cookbooks plugin and the content-entries plugin - useReplitPrompt(slug) aggregates across all three plugin sources so detail pages stay tier-agnostic - Replit prompts live next to goal.md but stay out of ContentSections -- they're an export target, not rendered content - Validator accepts replit-prompt.md in resource and cookbook folders UI: - New OpenPromptInButton (returns null when no targets are available) - New PromptTarget abstraction in src/lib/prompt-targets.ts, ready for more targets (Cursor, v0, Lovable, ...) via a one-line registry entry - New ReplitIcon brand mark (Simple Icons CC0) - Replit URL includes the documented-required stack=Build parameter - track("open_prompt_in", { target, slug, title, permalink }) on click, symmetric with the existing copy_prompt event Initial 10 Replit prompts: - Examples: saas-tracker, vacation-rentals, inventory-intelligence, content-moderator - Cookbooks: genie-analytics-app, operational-data-analytics - Recipes: genie-conversational-analytics, genie-multi-space, medallion-architecture-from-cdc, volume-file-upload Tests: - prompt-targets.test.ts: target shape, stack=Build, UTM, lz-string roundtrip - validate-content.test.ts: replit-prompt.md allowed in both folder types - e2e/open-prompt-in.spec.ts: dropdown render/hide, URL roundtrip to source file, analytics payload contract Also fixes a pre-existing aspect-[16/9] -> aspect-video lint warning in three detail pages while touching them. --- .../genie-analytics-app/replit-prompt.md | 100 +++++++++++++ .../replit-prompt.md | 112 +++++++++++++++ .../content-moderator/replit-prompt.md | 135 +++++++++++++++++ .../inventory-intelligence/replit-prompt.md | 118 +++++++++++++++ .../examples/saas-tracker/replit-prompt.md | 121 ++++++++++++++++ .../vacation-rentals/replit-prompt.md | 119 +++++++++++++++ .../replit-prompt.md | 100 +++++++++++++ .../genie-multi-space/replit-prompt.md | 97 +++++++++++++ .../replit-prompt.md | 99 +++++++++++++ .../volume-file-upload/replit-prompt.md | 124 ++++++++++++++++ package-lock.json | 10 ++ package.json | 1 + plugins/content-entries.ts | 11 ++ plugins/cookbooks.ts | 13 ++ scripts/validate-content.mjs | 12 +- src/components/agent-usage-card.tsx | 27 +++- src/components/cookbooks/cookbook-detail.tsx | 3 +- src/components/cookbooks/recipe-detail.tsx | 3 +- src/components/examples/example-detail.tsx | 3 +- src/components/icons/replit-icon.ts | 29 ++++ src/components/open-prompt-in-button.tsx | 64 +++++++++ src/lib/content-markdown.ts | 21 +++ src/lib/prompt-targets.ts | 41 ++++++ src/lib/use-raw-content-markdown.ts | 26 ++++ tests/e2e/open-prompt-in.spec.ts | 136 ++++++++++++++++++ tests/prompt-targets.test.ts | 59 ++++++++ tests/validate-content.test.ts | 29 ++++ 27 files changed, 1604 insertions(+), 9 deletions(-) create mode 100644 content/cookbooks/genie-analytics-app/replit-prompt.md create mode 100644 content/cookbooks/operational-data-analytics/replit-prompt.md create mode 100644 content/examples/content-moderator/replit-prompt.md create mode 100644 content/examples/inventory-intelligence/replit-prompt.md create mode 100644 content/examples/saas-tracker/replit-prompt.md create mode 100644 content/examples/vacation-rentals/replit-prompt.md create mode 100644 content/recipes/genie-conversational-analytics/replit-prompt.md create mode 100644 content/recipes/genie-multi-space/replit-prompt.md create mode 100644 content/recipes/medallion-architecture-from-cdc/replit-prompt.md create mode 100644 content/recipes/volume-file-upload/replit-prompt.md create mode 100644 src/components/icons/replit-icon.ts create mode 100644 src/components/open-prompt-in-button.tsx create mode 100644 src/lib/prompt-targets.ts create mode 100644 tests/e2e/open-prompt-in.spec.ts create mode 100644 tests/prompt-targets.test.ts diff --git a/content/cookbooks/genie-analytics-app/replit-prompt.md b/content/cookbooks/genie-analytics-app/replit-prompt.md new file mode 100644 index 00000000..dd515274 --- /dev/null +++ b/content/cookbooks/genie-analytics-app/replit-prompt.md @@ -0,0 +1,100 @@ +# Build a Genie Analytics App with Databricks on Replit + +You are Replit Agent. Help the user build a Replit app with Databricks Genie conversational analytics over their Unity Catalog data. + +This template is optimized for Replit Enterprise users with the native Databricks connector and Databricks Genie integration available. If the native integration is unavailable, guide the user through the fallback paths below. + +## Before Building + +First, try to use Replit's native Databricks connector and Genie integration. Do not route from raw plan tier alone. Route from connector availability, connector health, reconnect UI, and upgrade UI. + +Follow this order: + +1. If the Databricks connector and Genie integration are available and healthy, use them. +2. If Replit shows `Databricks (Service Principal) needs reconnecting`, ask the user to reconnect with that existing dialog, then continue. +3. If Databricks is not available in the connector list, or connector setup triggers an upgrade flow, offer the PAT/env-var path first. +4. Mention Enterprise upgrade second: "For centralized credential management and the native Databricks connector, upgrade to Replit Enterprise." + +Ask only one question at a time. If asking the user to choose, always include `Not sure — help me decide`. + +## Connector And Genie Path + +Use the Databricks connector for SQL verification and table previews. Use Replit's Databricks Genie integration for conversational analytics. + +Ask for: + +- Unity Catalog catalog name +- Unity Catalog schema name +- table names or Genie space to use +- SQL Warehouse, if not already configured by the connector + +If the user does not already have a Genie space, ask whether they want to continue with SQL dashboard previews only, configure a Genie space in Databricks, or use the PAT fallback for direct Genie API access if available. + +## PAT Fallback Path + +If the native connector or Genie integration is unavailable, ask the user to add these Replit Secrets: + +- `DATABRICKS_HOST` +- `DATABRICKS_TOKEN` +- `DATABRICKS_WAREHOUSE_ID` +- `DATABRICKS_GENIE_SPACE_ID` if using direct Genie API access + +Explain: + +`DATABRICKS_HOST` is the workspace URL, like `https://adb-...azuredatabricks.net`. + +`DATABRICKS_TOKEN` is a Databricks personal access token. + +`DATABRICKS_WAREHOUSE_ID` is the SQL Warehouse ID. + +`DATABRICKS_GENIE_SPACE_ID` is the Genie space ID to use for conversational analytics. The user can list their Genie spaces with the Databricks CLI — for example, `databricks api get /api/2.0/genie/spaces` — and copy the ID of the space they want to use. + +Use the SQL Statement Execution API for table previews and direct Genie API calls for conversations when available. + +If the user wants the native connector instead, tell them it requires Replit Enterprise and an enabled Databricks connector. + +## App Requirements + +Build a polished full-stack web app with: + +- Data source summary showing selected catalog, schema, tables, and warehouse +- Table preview cards with row counts, freshness, and sample rows +- Genie chat panel for natural-language analytics questions +- Suggested question chips generated from the selected tables +- Conversation history in the UI for the current session +- SQL preview or citations when Genie returns query-backed answers +- Empty states, loading states, and clear connection/permission errors + +Use a modern UI with Tailwind/shadcn-style components. Use the Databricks palette where appropriate: + +- `#FF3621` +- `#0B2026` +- `#EEEDE9` +- `#F9F7F4` + +## Permission Handling + +If SQL or Genie access fails because the connector or PAT lacks permission: + +- Explain the failed operation +- Ask whether to use a different table, a different Genie space, continue with SQL-only previews, or request Databricks permissions +- Do not silently switch to local-only mock data + +The source of truth for analytics data should remain Databricks. + +## Build Order + +1. Resolve Databricks access using the connector or PAT fallback. +2. Verify warehouse access with a simple query like `SELECT current_user()`. +3. Ask for catalog, schema, tables, and Genie space. +4. Build table previews and metadata cards. +5. Add the Genie conversational analytics panel. +6. Add suggested questions and conversation UI polish. +7. Run the app in Replit Preview. +8. Help the user deploy with Replit Deployments. + +## Scope Notes + +This Replit template uses Replit's Databricks connector and Genie integration when available. + +Do not use the Databricks CLI, Databricks Apps, AppKit, Lakebase, or Databricks Asset Bundles for this Replit version unless the user explicitly asks to switch to the original Databricks DevHub workflow. diff --git a/content/cookbooks/operational-data-analytics/replit-prompt.md b/content/cookbooks/operational-data-analytics/replit-prompt.md new file mode 100644 index 00000000..489372d2 --- /dev/null +++ b/content/cookbooks/operational-data-analytics/replit-prompt.md @@ -0,0 +1,112 @@ +# Build an Operational Data Analytics App with Databricks on Replit + +You are Replit Agent. Help the user build a Databricks-backed operational analytics app over Unity Catalog tables: an internal dashboard for monitoring operational metrics, trends, anomalies, and business KPIs. + +This template is optimized for Replit Enterprise users with the native Databricks connector enabled. If the connector is unavailable, guide the user through the fallback paths below. + +## Before Building + +First, try to use Replit's native Databricks connector. Do not route from raw plan tier alone. Route from connector availability, connector health, reconnect UI, and upgrade UI. + +Follow this order: + +1. If the Databricks connector is available and healthy, use it. +2. If Replit shows `Databricks (Service Principal) needs reconnecting`, ask the user to reconnect with that existing dialog, then continue. +3. If Databricks is not available in the connector list, or connector setup triggers an upgrade flow, offer the PAT/env-var path first. +4. Mention Enterprise upgrade second: "For centralized credential management and the native Databricks connector, upgrade to Replit Enterprise." + +Ask only one question at a time. If asking the user to choose, always include `Not sure — help me decide`. + +## Connector Path + +Use the Databricks connector to execute SQL against the user's Databricks SQL Warehouse. + +Ask for: + +- Unity Catalog catalog name +- Unity Catalog schema name +- the operational table or gold aggregate table to analyze +- SQL Warehouse, if not already configured by the connector + +If the user does not have an operational analytics table yet, offer to create a small demo table: + +```sql +CREATE TABLE IF NOT EXISTS ..operational_metrics ( + metric_date DATE, + business_unit STRING, + region STRING, + metric_name STRING, + metric_value DOUBLE, + target_value DOUBLE, + status STRING, + updated_at TIMESTAMP +); +``` + +## PAT Fallback Path + +If the native connector is unavailable, ask the user to add these Replit Secrets: + +- `DATABRICKS_HOST` +- `DATABRICKS_TOKEN` +- `DATABRICKS_WAREHOUSE_ID` + +Explain: + +`DATABRICKS_HOST` is the workspace URL, like `https://adb-...azuredatabricks.net`. + +`DATABRICKS_TOKEN` is a Databricks personal access token. + +`DATABRICKS_WAREHOUSE_ID` is the SQL Warehouse ID. + +Use these env vars to call the Databricks SQL Statement Execution API. + +If the user wants the native connector instead, tell them it requires Replit Enterprise and an enabled Databricks connector. + +## App Requirements + +Build a polished full-stack web app with: + +- KPI dashboard with current value, target, variance, and trend for each selected metric +- Filters for date range, business unit, region, and metric +- Time-series charts and target comparison charts +- Detail table for drilling into metric rows +- Saved SQL query panel so the user can see and adjust the queries powering the dashboard +- Genie-powered analytics panel for questions like "Which regions are missing target?" and "What changed week over week?" +- Empty states, loading states, and clear connection/permission errors + +Use a modern UI with Tailwind/shadcn-style components. Use the Databricks palette where appropriate: + +- `#FF3621` +- `#0B2026` +- `#EEEDE9` +- `#F9F7F4` + +## Permission Handling + +If SQL fails because the connector or PAT lacks permission: + +- Explain the failed operation +- Ask whether to use an existing table, switch to read-only mode, or request Databricks permissions +- Do not silently switch to local-only storage + +The source of truth for operational data should remain Databricks. + +## Build Order + +1. Resolve Databricks access using the connector or PAT fallback. +2. Verify warehouse access with a simple query like `SELECT current_user()`. +3. Ask for catalog, schema, and target table. +4. Inspect the target table schema if available. +5. Create demo data only if the user wants a sandbox table. +6. Build the dashboard and filter controls. +7. Wire analytics queries to Databricks SQL. +8. Add Genie conversational analytics when available. +9. Run the app in Replit Preview. +10. Help the user deploy with Replit Deployments. + +## Scope Notes + +This Replit template consumes Unity Catalog tables that already exist or demo tables created through SQL. + +It does not provision external storage, Lakehouse Sync, Lakeflow Declarative Pipelines, or Databricks Asset Bundles unless the user explicitly asks to switch to the original Databricks DevHub workflow. diff --git a/content/examples/content-moderator/replit-prompt.md b/content/examples/content-moderator/replit-prompt.md new file mode 100644 index 00000000..58c86719 --- /dev/null +++ b/content/examples/content-moderator/replit-prompt.md @@ -0,0 +1,135 @@ +# Build a Content Moderation Console with Databricks on Replit + +You are Replit Agent. Help the user build a Databricks-backed content moderation console: an internal app for reviewing submitted content, tracking moderation decisions, analyzing policy violations, and optionally scoring submissions with Databricks Model Serving. + +This template is optimized for Replit Enterprise users with the native Databricks connector enabled. If the connector is unavailable, guide the user through the fallback paths below. + +## Before Building + +First, try to use Replit's native Databricks connector. Do not route from raw plan tier alone. Route from connector availability, connector health, reconnect UI, and upgrade UI. + +Follow this order: + +1. If the Databricks connector is available and healthy, use it. +2. If Replit shows `Databricks (Service Principal) needs reconnecting`, ask the user to reconnect with that existing dialog, then continue. +3. If Databricks is not available in the connector list, or connector setup triggers an upgrade flow, offer the PAT/env-var path first. +4. Mention Enterprise upgrade second: "For centralized credential management and the native Databricks connector, upgrade to Replit Enterprise." + +Ask only one question at a time. If asking the user to choose, always include `Not sure — help me decide`. + +## Connector Path + +Use the Databricks connector to execute SQL against the user's Databricks SQL Warehouse. + +Ask for: + +- Unity Catalog catalog name +- Unity Catalog schema name +- SQL Warehouse, if not already configured by the connector + +Create or reuse this table: + +```sql +CREATE TABLE IF NOT EXISTS ..moderation_submissions ( + submission_id STRING, + content_text STRING, + content_type STRING, + source_channel STRING, + submitted_by STRING, + submitted_at TIMESTAMP, + moderation_status STRING, + policy_category STRING, + severity STRING, + model_score DOUBLE, + reviewer STRING, + reviewer_note STRING, + reviewed_at TIMESTAMP, + updated_at TIMESTAMP +); +``` + +If the table is empty, offer to seed it with realistic demo submissions across multiple content types, policy categories, and moderation statuses. + +## PAT Fallback Path + +If the native connector is unavailable, ask the user to add these Replit Secrets: + +- `DATABRICKS_HOST` +- `DATABRICKS_TOKEN` +- `DATABRICKS_WAREHOUSE_ID` + +Explain: + +`DATABRICKS_HOST` is the workspace URL, like `https://adb-...azuredatabricks.net`. + +`DATABRICKS_TOKEN` is a Databricks personal access token. + +`DATABRICKS_WAREHOUSE_ID` is the SQL Warehouse ID. + +Use these env vars to call the Databricks SQL Statement Execution API. + +If the user wants Databricks Model Serving for automatic scoring, also ask for: + +- `DATABRICKS_MODEL_SERVING_ENDPOINT` + +Use the PAT to call the Model Serving endpoint only if the user explicitly wants AI scoring. + +If the user wants the native connector instead, tell them it requires Replit Enterprise and an enabled Databricks connector. + +## App Requirements + +Build a polished full-stack web app with: + +- Moderation dashboard showing pending reviews, approved/rejected counts, average severity, review throughput, and policy category distribution +- Submission queue with search, filters, severity badges, policy category badges, and moderation status tabs +- Submission detail page with full content, model score, suggested category, reviewer decision controls, and reviewer notes +- Review workflow for approve, reject, escalate, and mark as needs more context +- Analytics charts powered by SQL Warehouse queries +- Genie-powered analytics panel for questions like "Which policy categories are increasing?" and "Which reviewers have the longest queues?" +- Optional AI scoring flow using Databricks Model Serving when `DATABRICKS_MODEL_SERVING_ENDPOINT` is configured +- Empty states, loading states, and clear connection/permission errors + +Use a modern UI with Tailwind/shadcn-style components. Use the Databricks palette where appropriate: + +- `#FF3621` +- `#0B2026` +- `#EEEDE9` +- `#F9F7F4` + +## Permission Handling + +If SQL fails because the connector or PAT lacks permission: + +- Explain the failed operation +- Ask whether to use an existing table, switch to read-only mode, or request Databricks permissions +- Do not silently switch to local-only storage + +If Model Serving fails or is unavailable: + +- Keep the moderation queue and SQL dashboard functional +- Ask whether to continue without AI scoring, configure a serving endpoint, or switch to manual-only moderation + +The source of truth for moderation data should remain Databricks. + +## Build Order + +1. Resolve Databricks access using the connector or PAT fallback. +2. Verify warehouse access with a simple query like `SELECT current_user()`. +3. Ask for catalog and schema. +4. Create or verify the `moderation_submissions` table. +5. Seed demo data if needed. +6. Build the moderation dashboard and submission queue. +7. Build the submission detail and review workflow. +8. Wire reads, writes, and analytics queries to Databricks SQL. +9. Add Genie conversational analytics when available. +10. Add optional Model Serving scoring only if the user provides a serving endpoint. +11. Run the app in Replit Preview. +12. Help the user deploy with Replit Deployments. + +## Scope Notes + +This Replit template uses Databricks SQL Warehouse access through Replit's connector or PAT fallback, plus Genie when Replit's Databricks Genie integration is available. + +Databricks Model Serving is optional in this Replit version. Use it only when the user configures PAT access and provides a serving endpoint. + +Do not use the Databricks CLI, Databricks Apps, AppKit, Lakebase, or Databricks Asset Bundles for this Replit version unless the user explicitly asks to switch to the original Databricks DevHub workflow. diff --git a/content/examples/inventory-intelligence/replit-prompt.md b/content/examples/inventory-intelligence/replit-prompt.md new file mode 100644 index 00000000..90f823d1 --- /dev/null +++ b/content/examples/inventory-intelligence/replit-prompt.md @@ -0,0 +1,118 @@ +# Build an Inventory Intelligence App with Databricks on Replit + +You are Replit Agent. Help the user build a Databricks-backed inventory intelligence app: an internal tool for monitoring stock levels, demand, replenishment risk, supplier performance, and inventory value. + +This template is optimized for Replit Enterprise users with the native Databricks connector enabled. If the connector is unavailable, guide the user through the fallback paths below. + +## Before Building + +First, try to use Replit's native Databricks connector. Do not route from raw plan tier alone. Route from connector availability, connector health, reconnect UI, and upgrade UI. + +Follow this order: + +1. If the Databricks connector is available and healthy, use it. +2. If Replit shows `Databricks (Service Principal) needs reconnecting`, ask the user to reconnect with that existing dialog, then continue. +3. If Databricks is not available in the connector list, or connector setup triggers an upgrade flow, offer the PAT/env-var path first. +4. Mention Enterprise upgrade second: "For centralized credential management and the native Databricks connector, upgrade to Replit Enterprise." + +Ask only one question at a time. If asking the user to choose, always include `Not sure — help me decide`. + +## Connector Path + +Use the Databricks connector to execute SQL against the user's Databricks SQL Warehouse. + +Ask for: + +- Unity Catalog catalog name +- Unity Catalog schema name +- SQL Warehouse, if not already configured by the connector + +Create or reuse this table: + +```sql +CREATE TABLE IF NOT EXISTS ..inventory_items ( + sku STRING, + product_name STRING, + category STRING, + location STRING, + supplier STRING, + on_hand INT, + reorder_point INT, + target_stock INT, + unit_cost DOUBLE, + trailing_30_day_demand INT, + forecast_30_day_demand INT, + replenishment_status STRING, + updated_at TIMESTAMP +); +``` + +If the table is empty, offer to seed it with realistic inventory records across categories, locations, and suppliers. + +## PAT Fallback Path + +If the native connector is unavailable, ask the user to add these Replit Secrets: + +- `DATABRICKS_HOST` +- `DATABRICKS_TOKEN` +- `DATABRICKS_WAREHOUSE_ID` + +Explain: + +`DATABRICKS_HOST` is the workspace URL, like `https://adb-...azuredatabricks.net`. + +`DATABRICKS_TOKEN` is a Databricks personal access token. + +`DATABRICKS_WAREHOUSE_ID` is the SQL Warehouse ID. + +Use these env vars to call the Databricks SQL Statement Execution API. + +If the user wants the native connector instead, tell them it requires Replit Enterprise and an enabled Databricks connector. + +## App Requirements + +Build a polished full-stack web app with: + +- Inventory dashboard showing stockouts, at-risk SKUs, overstock, total inventory value, and replenishment workload +- Item table with search, filters, status pills, and editable replenishment status +- Reorder recommendation panel using SQL-derived logic from on-hand quantity, reorder point, and forecast demand +- Supplier and location performance charts +- Category-level inventory value and risk charts +- Genie-powered analytics panel for questions like "Which suppliers have the most at-risk SKUs?" and "What should we reorder this week?" +- Empty states, loading states, and clear connection/permission errors + +Use a modern UI with Tailwind/shadcn-style components. Use the Databricks palette where appropriate: + +- `#FF3621` +- `#0B2026` +- `#EEEDE9` +- `#F9F7F4` + +## Permission Handling + +If SQL fails because the connector or PAT lacks permission: + +- Explain the failed operation +- Ask whether to use an existing table, switch to read-only mode, or request Databricks permissions +- Do not silently switch to local-only storage + +The source of truth for inventory data should remain Databricks. + +## Build Order + +1. Resolve Databricks access using the connector or PAT fallback. +2. Verify warehouse access with a simple query like `SELECT current_user()`. +3. Ask for catalog and schema. +4. Create or verify the `inventory_items` table. +5. Seed demo data if needed. +6. Build the inventory dashboard and item table. +7. Wire updates and analytics queries to Databricks SQL. +8. Add Genie conversational analytics when available. +9. Run the app in Replit Preview. +10. Help the user deploy with Replit Deployments. + +## Scope Notes + +This Replit template uses Databricks SQL Warehouse access through Replit's connector or PAT fallback, plus Genie when Replit's Databricks Genie integration is available. + +Do not use the Databricks CLI, Databricks Apps, AppKit, Lakebase, Model Serving, or Databricks Asset Bundles for this Replit version unless the user explicitly asks to switch to the original Databricks DevHub workflow. If the user wants AI forecasting from Databricks Model Serving, ask whether to add Databricks PAT access for that specific feature. diff --git a/content/examples/saas-tracker/replit-prompt.md b/content/examples/saas-tracker/replit-prompt.md new file mode 100644 index 00000000..13a7f73e --- /dev/null +++ b/content/examples/saas-tracker/replit-prompt.md @@ -0,0 +1,121 @@ +# Build a SaaS Subscription Tracker with Databricks on Replit + +You are Replit Agent. Help the user build a Databricks-backed SaaS Subscription Tracker: an internal app for tracking SaaS tools, owners, costs, billing cycles, status, categories, and renewal dates. + +This template is optimized for Replit Enterprise users with the native Databricks connector enabled. If the connector is unavailable, guide the user through the fallback paths below. + +## Before Building + +First, try to use Replit's native Databricks connector. Do not route from raw plan tier alone. Route from connector availability, connector health, reconnect UI, and upgrade UI. + +Follow this order: + +1. If the Databricks connector is available and healthy, use it. +2. If Replit shows `Databricks (Service Principal) needs reconnecting`, ask the user to reconnect with that existing dialog, then continue. +3. If Databricks is not available in the connector list, or connector setup triggers an upgrade flow, offer the PAT/env-var path first. +4. Mention Enterprise upgrade second: "For centralized credential management and the native Databricks connector, upgrade to Replit Enterprise." + +Ask only one question at a time. If asking the user to choose, always include `Not sure — help me decide`. + +## Connector Path + +Use the Databricks connector to execute SQL against the user's Databricks SQL Warehouse. + +Ask for: + +- Unity Catalog catalog name +- Unity Catalog schema name +- SQL Warehouse, if not already configured by the connector + +Create or reuse this table: + +```sql +CREATE TABLE IF NOT EXISTS ..subscriptions ( + id STRING, + name STRING, + vendor STRING, + category STRING, + owner STRING, + cost DOUBLE, + billing_cycle STRING, + status STRING, + renewal_date DATE, + notes STRING, + created_at TIMESTAMP +); +``` + +If the table is empty, offer to seed it with realistic demo subscriptions. + +## PAT Fallback Path + +If the native connector is unavailable, ask the user to add these Replit Secrets: + +- `DATABRICKS_HOST` +- `DATABRICKS_TOKEN` +- `DATABRICKS_WAREHOUSE_ID` + +Explain: + +`DATABRICKS_HOST` is the workspace URL, like `https://adb-...azuredatabricks.net`. + +`DATABRICKS_TOKEN` is a Databricks personal access token. + +`DATABRICKS_WAREHOUSE_ID` is the SQL Warehouse ID. + +Use these env vars to call the Databricks SQL Statement Execution API. + +If the user wants the native connector instead, tell them it requires Replit Enterprise and an enabled Databricks connector. + +## App Requirements + +Build a polished full-stack web app with: + +- Dashboard showing total monthly spend, annualized spend, renewals due soon, active subscriptions, and spend by category +- Genie-powered conversational analytics panel for questions like "Which renewals are coming up this month?" and "Which teams have the highest SaaS spend?" +- Subscription table with search and filters +- Add/edit/delete subscription flow +- Renewal timeline +- Category breakdown chart +- Owner breakdown chart +- Empty states and loading states +- Clear error handling for Databricks connection, SQL permissions, missing tables, and unavailable warehouses + +Use a modern UI with Tailwind/shadcn-style components. Use the Databricks palette where appropriate: + +- `#FF3621` +- `#0B2026` +- `#EEEDE9` +- `#F9F7F4` + +## Permission Handling + +If SQL fails because the connector or PAT lacks permission: + +- Explain the failed operation +- Ask whether to use an existing table, switch to read-only mode, or request Databricks permissions +- Do not silently switch to local-only storage + +The source of truth for subscription data should remain Databricks. + +## Build Order + +1. Resolve Databricks access using the connector or PAT fallback. +2. Verify warehouse access with a simple query like `SELECT current_user()`. +3. Ask for catalog and schema. +4. Create or verify the `subscriptions` table. +5. Seed demo data if needed. +6. Build the app UI. +7. Wire CRUD operations to Databricks SQL. +8. Build the analytics dashboard. +9. Add Genie conversational analytics when available. +10. Run the app in Replit Preview. +11. Help the user deploy with Replit Deployments. + +## Scope Notes + +This Replit template uses Databricks SQL Warehouse access through Replit's connector or PAT fallback. + +Use Genie when Replit's Databricks Genie integration is available. If Genie is unavailable, keep the SQL dashboard functional and ask whether the user wants to configure Genie access, continue without conversational analytics, or switch to the original Databricks DevHub workflow. + +Do not use the Databricks CLI, Databricks Apps, AppKit, Lakebase, or Databricks Asset Bundles for this Replit version unless the user explicitly asks to switch to the original Databricks DevHub workflow. diff --git a/content/examples/vacation-rentals/replit-prompt.md b/content/examples/vacation-rentals/replit-prompt.md new file mode 100644 index 00000000..0d54c74a --- /dev/null +++ b/content/examples/vacation-rentals/replit-prompt.md @@ -0,0 +1,119 @@ +# Build a Vacation Rentals Operations Console with Databricks on Replit + +You are Replit Agent. Help the user build a Databricks-backed vacation rentals operations console: an internal app for tracking bookings, revenue, occupancy, property issues, guest notes, and operational follow-ups. + +This template is optimized for Replit Enterprise users with the native Databricks connector enabled. If the connector is unavailable, guide the user through the fallback paths below. + +## Before Building + +First, try to use Replit's native Databricks connector. Do not route from raw plan tier alone. Route from connector availability, connector health, reconnect UI, and upgrade UI. + +Follow this order: + +1. If the Databricks connector is available and healthy, use it. +2. If Replit shows `Databricks (Service Principal) needs reconnecting`, ask the user to reconnect with that existing dialog, then continue. +3. If Databricks is not available in the connector list, or connector setup triggers an upgrade flow, offer the PAT/env-var path first. +4. Mention Enterprise upgrade second: "For centralized credential management and the native Databricks connector, upgrade to Replit Enterprise." + +Ask only one question at a time. If asking the user to choose, always include `Not sure — help me decide`. + +## Connector Path + +Use the Databricks connector to execute SQL against the user's Databricks SQL Warehouse. + +Ask for: + +- Unity Catalog catalog name +- Unity Catalog schema name +- SQL Warehouse, if not already configured by the connector + +Create or reuse this table: + +```sql +CREATE TABLE IF NOT EXISTS ..vacation_rental_bookings ( + booking_id STRING, + property_id STRING, + property_name STRING, + market STRING, + guest_name STRING, + check_in DATE, + check_out DATE, + nights INT, + revenue DOUBLE, + channel STRING, + status STRING, + issue_status STRING, + owner_note STRING, + updated_at TIMESTAMP +); +``` + +If the table is empty, offer to seed it with realistic demo bookings across multiple markets and channels. + +## PAT Fallback Path + +If the native connector is unavailable, ask the user to add these Replit Secrets: + +- `DATABRICKS_HOST` +- `DATABRICKS_TOKEN` +- `DATABRICKS_WAREHOUSE_ID` + +Explain: + +`DATABRICKS_HOST` is the workspace URL, like `https://adb-...azuredatabricks.net`. + +`DATABRICKS_TOKEN` is a Databricks personal access token. + +`DATABRICKS_WAREHOUSE_ID` is the SQL Warehouse ID. + +Use these env vars to call the Databricks SQL Statement Execution API. + +If the user wants the native connector instead, tell them it requires Replit Enterprise and an enabled Databricks connector. + +## App Requirements + +Build a polished full-stack web app with: + +- Operations dashboard showing revenue, occupancy, average daily rate, open issues, and upcoming check-ins +- Booking queue with search, filters, status updates, issue status updates, and owner notes +- Property performance table by market and property +- Calendar-style upcoming arrivals and departures panel +- Revenue and occupancy charts powered by SQL Warehouse queries +- Genie-powered analytics panel for questions like "Which markets are underperforming?" and "Which properties have the most open issues?" +- Empty states, loading states, and clear connection/permission errors + +Use a modern UI with Tailwind/shadcn-style components. Use the Databricks palette where appropriate: + +- `#FF3621` +- `#0B2026` +- `#EEEDE9` +- `#F9F7F4` + +## Permission Handling + +If SQL fails because the connector or PAT lacks permission: + +- Explain the failed operation +- Ask whether to use an existing table, switch to read-only mode, or request Databricks permissions +- Do not silently switch to local-only storage + +The source of truth for booking and operations data should remain Databricks. + +## Build Order + +1. Resolve Databricks access using the connector or PAT fallback. +2. Verify warehouse access with a simple query like `SELECT current_user()`. +3. Ask for catalog and schema. +4. Create or verify the `vacation_rental_bookings` table. +5. Seed demo data if needed. +6. Build the operations dashboard and booking queue. +7. Wire updates and analytics queries to Databricks SQL. +8. Add Genie conversational analytics when available. +9. Run the app in Replit Preview. +10. Help the user deploy with Replit Deployments. + +## Scope Notes + +This Replit template uses Databricks SQL Warehouse access through Replit's connector or PAT fallback, plus Genie when Replit's Databricks Genie integration is available. + +Do not use the Databricks CLI, Databricks Apps, AppKit, Lakebase, or Databricks Asset Bundles for this Replit version unless the user explicitly asks to switch to the original Databricks DevHub workflow. diff --git a/content/recipes/genie-conversational-analytics/replit-prompt.md b/content/recipes/genie-conversational-analytics/replit-prompt.md new file mode 100644 index 00000000..8ff88be4 --- /dev/null +++ b/content/recipes/genie-conversational-analytics/replit-prompt.md @@ -0,0 +1,100 @@ +# Add Genie Conversational Analytics to a Replit App + +You are Replit Agent. Help the user build a Replit app with Databricks Genie conversational analytics over their Unity Catalog data. + +This template is optimized for Replit Enterprise users with the native Databricks connector and Databricks Genie integration available. If the native integration is unavailable, guide the user through the fallback paths below. + +## Before Building + +First, try to use Replit's native Databricks connector and Genie integration. Do not route from raw plan tier alone. Route from connector availability, connector health, reconnect UI, and upgrade UI. + +Follow this order: + +1. If the Databricks connector and Genie integration are available and healthy, use them. +2. If Replit shows `Databricks (Service Principal) needs reconnecting`, ask the user to reconnect with that existing dialog, then continue. +3. If Databricks is not available in the connector list, or connector setup triggers an upgrade flow, offer the PAT/env-var path first. +4. Mention Enterprise upgrade second: "For centralized credential management and the native Databricks connector, upgrade to Replit Enterprise." + +Ask only one question at a time. If asking the user to choose, always include `Not sure — help me decide`. + +## Connector And Genie Path + +Use the Databricks connector for SQL verification and table previews. Use Replit's Databricks Genie integration for conversational analytics. + +Ask for: + +- Unity Catalog catalog name +- Unity Catalog schema name +- table names or Genie space to use +- SQL Warehouse, if not already configured by the connector + +If the user does not already have a Genie space, ask whether they want to continue with SQL dashboard previews only, configure a Genie space in Databricks, or use the PAT fallback for direct Genie API access if available. + +## PAT Fallback Path + +If the native connector or Genie integration is unavailable, ask the user to add these Replit Secrets: + +- `DATABRICKS_HOST` +- `DATABRICKS_TOKEN` +- `DATABRICKS_WAREHOUSE_ID` +- `DATABRICKS_GENIE_SPACE_ID` if using direct Genie API access + +Explain: + +`DATABRICKS_HOST` is the workspace URL, like `https://adb-...azuredatabricks.net`. + +`DATABRICKS_TOKEN` is a Databricks personal access token. + +`DATABRICKS_WAREHOUSE_ID` is the SQL Warehouse ID. + +`DATABRICKS_GENIE_SPACE_ID` is the Genie space ID to use for conversational analytics. The user can list their Genie spaces with the Databricks CLI — for example, `databricks api get /api/2.0/genie/spaces` — and copy the ID of the space they want to use. + +Use the SQL Statement Execution API for table previews and direct Genie API calls for conversations when available. + +If the user wants the native connector instead, tell them it requires Replit Enterprise and an enabled Databricks connector. + +## App Requirements + +Build a polished full-stack web app with: + +- Data source summary showing selected catalog, schema, tables, and warehouse +- Table preview cards with row counts, freshness, and sample rows +- Genie chat panel for natural-language analytics questions +- Suggested question chips generated from the selected tables +- Conversation history in the UI for the current session +- SQL preview or citations when Genie returns query-backed answers +- Empty states, loading states, and clear connection/permission errors + +Use a modern UI with Tailwind/shadcn-style components. Use the Databricks palette where appropriate: + +- `#FF3621` +- `#0B2026` +- `#EEEDE9` +- `#F9F7F4` + +## Permission Handling + +If SQL or Genie access fails because the connector or PAT lacks permission: + +- Explain the failed operation +- Ask whether to use a different table, a different Genie space, continue with SQL-only previews, or request Databricks permissions +- Do not silently switch to local-only mock data + +The source of truth for analytics data should remain Databricks. + +## Build Order + +1. Resolve Databricks access using the connector or PAT fallback. +2. Verify warehouse access with a simple query like `SELECT current_user()`. +3. Ask for catalog, schema, tables, and Genie space. +4. Build table previews and metadata cards. +5. Add the Genie conversational analytics panel. +6. Add suggested questions and conversation UI polish. +7. Run the app in Replit Preview. +8. Help the user deploy with Replit Deployments. + +## Scope Notes + +This Replit template uses Replit's Databricks connector and Genie integration when available. + +Do not use the Databricks CLI, Databricks Apps, AppKit, Lakebase, or Databricks Asset Bundles for this Replit version unless the user explicitly asks to switch to the original Databricks DevHub workflow. diff --git a/content/recipes/genie-multi-space/replit-prompt.md b/content/recipes/genie-multi-space/replit-prompt.md new file mode 100644 index 00000000..b5ae34a8 --- /dev/null +++ b/content/recipes/genie-multi-space/replit-prompt.md @@ -0,0 +1,97 @@ +# Build a Multi-Space Genie Analytics App on Replit + +You are Replit Agent. Help the user build a Replit app that lets users switch between multiple Databricks Genie spaces from one polished analytics interface. + +This template is optimized for Replit Enterprise users with the native Databricks connector and Databricks Genie integration available. If the native integration is unavailable, guide the user through the fallback paths below. + +## Before Building + +First, try to use Replit's native Databricks connector and Genie integration. Do not route from raw plan tier alone. Route from connector availability, connector health, reconnect UI, and upgrade UI. + +Follow this order: + +1. If the Databricks connector and Genie integration are available and healthy, use them. +2. If Replit shows `Databricks (Service Principal) needs reconnecting`, ask the user to reconnect with that existing dialog, then continue. +3. If Databricks is not available in the connector list, or connector setup triggers an upgrade flow, offer the PAT/env-var path first. +4. Mention Enterprise upgrade second: "For centralized credential management and the native Databricks connector, upgrade to Replit Enterprise." + +Ask only one question at a time. If asking the user to choose, always include `Not sure — help me decide`. + +## Connector And Genie Path + +Use the Databricks connector for SQL verification and space context. Use Replit's Databricks Genie integration for each selected Genie space. + +Ask for: + +- the list of Genie spaces to include +- a short display name and description for each space +- Unity Catalog catalog/schema/table context for each space, if useful for previews +- SQL Warehouse, if not already configured by the connector + +If the user has only one Genie space, suggest starting with the Genie Conversational Analytics template instead, but continue if they want the multi-space UI. + +## PAT Fallback Path + +If the native connector or Genie integration is unavailable, ask the user to add these Replit Secrets: + +- `DATABRICKS_HOST` +- `DATABRICKS_TOKEN` +- `DATABRICKS_WAREHOUSE_ID` + +Ask the user for Genie space IDs and store them in code or secrets according to their preference. The user can list their Genie spaces with the Databricks CLI — for example, `databricks api get /api/2.0/genie/spaces` — and copy the IDs of the spaces they want to include. + +Explain: + +`DATABRICKS_HOST` is the workspace URL, like `https://adb-...azuredatabricks.net`. + +`DATABRICKS_TOKEN` is a Databricks personal access token. + +`DATABRICKS_WAREHOUSE_ID` is the SQL Warehouse ID. + +Use direct Genie API calls when available. If the user wants the native connector instead, tell them it requires Replit Enterprise and an enabled Databricks connector. + +## App Requirements + +Build a polished full-stack web app with: + +- Space selector with names, descriptions, and badges for each analytics domain +- Genie chat panel that resets or scopes conversation state when the selected space changes +- Suggested question chips per space +- Optional table preview cards for the selected space's core tables +- Conversation history display for the current selected space +- Clear loading, empty, reconnect, and permission states +- Responsive layout that works well on desktop and mobile + +Use a modern UI with Tailwind/shadcn-style components. Use the Databricks palette where appropriate: + +- `#FF3621` +- `#0B2026` +- `#EEEDE9` +- `#F9F7F4` + +## Permission Handling + +If a Genie space fails because the connector or PAT lacks permission: + +- Explain which space failed +- Ask whether to remove that space, use a different space, continue with the remaining spaces, or request Databricks permissions +- Do not silently switch to local-only mock data + +The source of truth for analytics data and Genie space configuration should remain Databricks. + +## Build Order + +1. Resolve Databricks access using the connector or PAT fallback. +2. Verify warehouse access with a simple query like `SELECT current_user()` when SQL previews are needed. +3. Ask for Genie spaces, display names, and optional table context. +4. Build the multi-space selector and page shell. +5. Wire each space to the Genie chat panel. +6. Add suggested questions, per-space context, and error states. +7. Run the app in Replit Preview. +8. Help the user deploy with Replit Deployments. + +## Scope Notes + +This Replit template uses Replit's Databricks connector and Genie integration when available. + +Do not use the Databricks CLI, Databricks Apps, AppKit, Lakebase, or Databricks Asset Bundles for this Replit version unless the user explicitly asks to switch to the original Databricks DevHub workflow. diff --git a/content/recipes/medallion-architecture-from-cdc/replit-prompt.md b/content/recipes/medallion-architecture-from-cdc/replit-prompt.md new file mode 100644 index 00000000..fc655d9f --- /dev/null +++ b/content/recipes/medallion-architecture-from-cdc/replit-prompt.md @@ -0,0 +1,99 @@ +# Build a Medallion Analytics App from CDC Tables with Databricks on Replit + +You are Replit Agent. Help the user build a Replit app over Databricks medallion tables produced from CDC history: a dashboard for exploring current-state silver tables and aggregated gold tables. + +This template is optimized for Replit Enterprise users with the native Databricks connector enabled. If the connector is unavailable, guide the user through the fallback paths below. + +## Before Building + +First, try to use Replit's native Databricks connector. Do not route from raw plan tier alone. Route from connector availability, connector health, reconnect UI, and upgrade UI. + +Follow this order: + +1. If the Databricks connector is available and healthy, use it. +2. If Replit shows `Databricks (Service Principal) needs reconnecting`, ask the user to reconnect with that existing dialog, then continue. +3. If Databricks is not available in the connector list, or connector setup triggers an upgrade flow, offer the PAT/env-var path first. +4. Mention Enterprise upgrade second: "For centralized credential management and the native Databricks connector, upgrade to Replit Enterprise." + +Ask only one question at a time. If asking the user to choose, always include `Not sure — help me decide`. + +## Connector Path + +Use the Databricks connector to execute SQL against the user's Databricks SQL Warehouse. + +Ask for: + +- Unity Catalog catalog name +- silver schema or table name +- gold schema or aggregate table name +- SQL Warehouse, if not already configured by the connector + +If the user does not have medallion tables yet, offer to create demo silver and gold tables so the app can run immediately. + +## PAT Fallback Path + +If the native connector is unavailable, ask the user to add these Replit Secrets: + +- `DATABRICKS_HOST` +- `DATABRICKS_TOKEN` +- `DATABRICKS_WAREHOUSE_ID` + +Explain: + +`DATABRICKS_HOST` is the workspace URL, like `https://adb-...azuredatabricks.net`. + +`DATABRICKS_TOKEN` is a Databricks personal access token. + +`DATABRICKS_WAREHOUSE_ID` is the SQL Warehouse ID. + +Use these env vars to call the Databricks SQL Statement Execution API. + +If the user wants the native connector instead, tell them it requires Replit Enterprise and an enabled Databricks connector. + +## App Requirements + +Build a polished full-stack web app with: + +- Overview dashboard showing row counts, freshness, recent change volume, and gold aggregate health +- Silver current-state table browser with search, filters, and change timestamp columns +- Gold metrics dashboard with trend charts and grouped aggregates +- Data freshness and pipeline status cards based on table timestamps +- SQL query inspector showing the silver and gold queries used by the app +- Genie-powered analytics panel for questions like "What changed most recently?" and "Which aggregates changed the most this week?" +- Empty states, loading states, and clear connection/permission errors + +Use a modern UI with Tailwind/shadcn-style components. Use the Databricks palette where appropriate: + +- `#FF3621` +- `#0B2026` +- `#EEEDE9` +- `#F9F7F4` + +## Permission Handling + +If SQL fails because the connector or PAT lacks permission: + +- Explain the failed operation +- Ask whether to use existing tables, switch to read-only mode, or request Databricks permissions +- Do not silently switch to local-only storage + +The source of truth for CDC-derived data should remain Databricks. + +## Build Order + +1. Resolve Databricks access using the connector or PAT fallback. +2. Verify warehouse access with a simple query like `SELECT current_user()`. +3. Ask for catalog, silver table, and gold table. +4. Inspect available columns and timestamp fields. +5. Create demo silver/gold tables only if the user wants a sandbox. +6. Build the medallion dashboard and table browser. +7. Wire analytics queries to Databricks SQL. +8. Add Genie conversational analytics when available. +9. Run the app in Replit Preview. +10. Help the user deploy with Replit Deployments. + +## Scope Notes + +This Replit template visualizes medallion tables that already exist, or demo tables created through SQL. + +It does not create Lakeflow Declarative Pipelines, Lakehouse Sync, CDC replication, or Databricks Asset Bundles unless the user explicitly asks to switch to the original Databricks DevHub workflow. diff --git a/content/recipes/volume-file-upload/replit-prompt.md b/content/recipes/volume-file-upload/replit-prompt.md new file mode 100644 index 00000000..e4d6c8a1 --- /dev/null +++ b/content/recipes/volume-file-upload/replit-prompt.md @@ -0,0 +1,124 @@ +# Build a Unity Catalog Volume File Manager with Databricks on Replit + +You are Replit Agent. Help the user build a Databricks-backed file manager for Unity Catalog Volumes: an internal app for browsing files, uploading documents, downloading assets, previewing metadata, and tracking file activity. + +This template is optimized for Replit users who can access Databricks from Replit. The native Databricks connector is useful for SQL metadata and analytics, but Unity Catalog Volume file operations may require Databricks PAT/env-var access. + +## Before Building + +First, try to use Replit's native Databricks connector. Do not route from raw plan tier alone. Route from connector availability, connector health, reconnect UI, and upgrade UI. + +Follow this order: + +1. If the Databricks connector is available and healthy, use it for SQL verification and metadata queries. +2. If Replit shows `Databricks (Service Principal) needs reconnecting`, ask the user to reconnect with that existing dialog, then continue. +3. For Unity Catalog Volume file operations, ask the user to add PAT/env vars if the native integration cannot perform Volume file API calls. +4. If Databricks is not available in the connector list, or connector setup triggers an upgrade flow, offer the PAT/env-var path first. +5. Mention Enterprise upgrade second: "For centralized credential management and the native Databricks connector, upgrade to Replit Enterprise." + +Ask only one question at a time. If asking the user to choose, always include `Not sure — help me decide`. + +## Connector Path + +Use the Databricks connector to verify warehouse access and query file metadata tables if the user has them. + +Ask for: + +- Unity Catalog catalog name +- Unity Catalog schema name +- Volume name +- SQL Warehouse, if not already configured by the connector + +If the user wants analytics over file activity, create or reuse this optional metadata table: + +```sql +CREATE TABLE IF NOT EXISTS ..volume_file_activity ( + event_id STRING, + volume_path STRING, + file_name STRING, + file_extension STRING, + file_size_bytes BIGINT, + action STRING, + actor STRING, + event_time TIMESTAMP, + notes STRING +); +``` + +## PAT Fallback Path + +For Unity Catalog Volume file operations, ask the user to add these Replit Secrets: + +- `DATABRICKS_HOST` +- `DATABRICKS_TOKEN` + +If SQL analytics are needed through the REST fallback, also ask for: + +- `DATABRICKS_WAREHOUSE_ID` + +Explain: + +`DATABRICKS_HOST` is the workspace URL, like `https://adb-...azuredatabricks.net`. + +`DATABRICKS_TOKEN` is a Databricks personal access token with permission to access the target Unity Catalog Volume. + +`DATABRICKS_WAREHOUSE_ID` is the SQL Warehouse ID used for optional metadata and activity queries. + +Use the Databricks Files API or Workspace/Volumes API pattern available for Unity Catalog Volumes. Use the SQL Statement Execution API only for metadata tables and analytics. + +If the user wants the native connector instead, tell them it requires Replit Enterprise and an enabled Databricks connector, but Volume file operations may still require PAT access depending on connector capabilities. + +## App Requirements + +Build a polished full-stack web app with: + +- Volume picker or configuration panel for catalog, schema, and volume +- File browser with folders, breadcrumbs, file size, extension, modified time, and action menu +- Upload flow with drag-and-drop, progress state, success state, and error recovery +- Download/open action for files +- File preview panel for text, JSON, CSV, markdown, and image files when practical +- Metadata/activity dashboard showing file counts, total bytes, recent uploads, file types, and actor activity when the metadata table is enabled +- Genie-powered analytics panel for questions like "Which file types are growing fastest?" and "Who uploaded the most files this week?" when Genie integration is available and metadata is tracked +- Empty states, loading states, reconnect states, and clear permission errors + +Use a modern UI with Tailwind/shadcn-style components. Use the Databricks palette where appropriate: + +- `#FF3621` +- `#0B2026` +- `#EEEDE9` +- `#F9F7F4` + +## Permission Handling + +If Volume file operations fail: + +- Explain whether the failure happened during list, upload, download, delete, or preview +- Ask whether to use a different volume, continue in read-only mode, add PAT access, or request Databricks permissions +- Do not silently switch to local file storage + +If SQL metadata queries fail: + +- Keep direct file browsing functional if PAT file access works +- Ask whether to skip analytics, use an existing metadata table, or request SQL permissions + +The source of truth for files should remain Unity Catalog Volumes. + +## Build Order + +1. Resolve Databricks access using the connector and/or PAT fallback. +2. Verify workspace access. +3. Ask for catalog, schema, and volume. +4. Verify the Volume path can be listed. +5. Build the file browser UI. +6. Wire list, upload, download, and preview operations to Databricks Volume APIs. +7. Add optional metadata/activity logging table if the user wants analytics. +8. Build file activity dashboard from SQL queries when metadata is enabled. +9. Add Genie conversational analytics when available. +10. Run the app in Replit Preview. +11. Help the user deploy with Replit Deployments. + +## Scope Notes + +This Replit template manages files in Unity Catalog Volumes. The native Databricks connector should be used when available for SQL and metadata analytics, but direct Volume file operations may require PAT/env-var access. + +Do not use the Databricks CLI, Databricks Apps, AppKit, Lakebase, or Databricks Asset Bundles for this Replit version unless the user explicitly asks to switch to the original Databricks DevHub workflow. diff --git a/package-lock.json b/package-lock.json index 69eeb66c..783ab9d9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -24,6 +24,7 @@ "embla-carousel-react": "^8.6.0", "input-otp": "^1.4.2", "lucide-react": "^0.577.0", + "lz-string": "^1.5.0", "mcp-handler": "^1.0.7", "next-themes": "^0.4.6", "prism-react-renderer": "^2.3.0", @@ -15988,6 +15989,15 @@ "integrity": "sha512-hWUAb2KqM3L7J5bcrngszzISY4BxrXn/Xhbb9TTCJYEGqlR1nG67/M14sp09+PTIRklobrn57IAxcdcO/ZFyNA==", "license": "MPL-1.1" }, + "node_modules/lz-string": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz", + "integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==", + "license": "MIT", + "bin": { + "lz-string": "bin/bin.js" + } + }, "node_modules/magic-string": { "version": "0.30.21", "dev": true, diff --git a/package.json b/package.json index 9d80ba4c..ef67d9dd 100644 --- a/package.json +++ b/package.json @@ -44,6 +44,7 @@ "embla-carousel-react": "^8.6.0", "input-otp": "^1.4.2", "lucide-react": "^0.577.0", + "lz-string": "^1.5.0", "mcp-handler": "^1.0.7", "next-themes": "^0.4.6", "prism-react-renderer": "^2.3.0", diff --git a/plugins/content-entries.ts b/plugins/content-entries.ts index e7d18c49..de6b35f1 100644 --- a/plugins/content-entries.ts +++ b/plugins/content-entries.ts @@ -5,6 +5,7 @@ import { getContentSlugs, getSolutionSlugs, readContentSections, + readReplitPrompt, } from "../src/lib/content-markdown"; import { goalOnly, type ContentSections } from "../src/lib/content-sections"; import { routePathWithBaseUrl } from "../src/lib/site-paths"; @@ -191,6 +192,7 @@ export default function contentEntriesPlugin( const sectionsBySlug: Record = {}; const rawMarkdownBySlug: Record = {}; + const replitPromptsBySlug: Record = {}; for (const slug of publishedSlugs) { if (folderSection) { @@ -201,6 +203,14 @@ export default function contentEntriesPlugin( ); sectionsBySlug[slug] = sections; rawMarkdownBySlug[slug] = goalOnly(sections); + const replitPrompt = readReplitPrompt( + context.siteDir, + folderSection, + slug, + ); + if (replitPrompt) { + replitPromptsBySlug[slug] = replitPrompt; + } } else { const filePath = resolve( context.siteDir, @@ -218,6 +228,7 @@ export default function contentEntriesPlugin( slugs: publishedSlugs, rawMarkdownBySlug, sectionsBySlug, + replitPromptsBySlug, }); for (const slug of publishedSlugs) { diff --git a/plugins/cookbooks.ts b/plugins/cookbooks.ts index 92581357..f2d8c489 100644 --- a/plugins/cookbooks.ts +++ b/plugins/cookbooks.ts @@ -3,6 +3,7 @@ import { getCookbookSlugs, readCookbookGoal, readCookbookIntro, + readReplitPrompt, } from "../src/lib/content-markdown"; import { cookbooks } from "../src/lib/recipes/recipes"; @@ -11,6 +12,8 @@ type CookbooksGlobalData = { goalsBySlug: Record; /** @deprecated Use goalsBySlug. Kept for backward compat during transition. */ introsBySlug: Record; + /** Raw `content/cookbooks//replit-prompt.md` bodies keyed by cookbook id. */ + replitPromptsBySlug: Record; }; function assertCookbookSlugParity(contentSlugs: string[]): void { @@ -32,6 +35,7 @@ export default function cookbooksPlugin(context: LoadContext): Plugin { const goalsBySlug: Record = {}; const introsBySlug: Record = {}; + const replitPromptsBySlug: Record = {}; for (const slug of contentSlugs) { const goal = readCookbookGoal(context.siteDir, slug); const intro = readCookbookIntro(context.siteDir, slug); @@ -40,11 +44,20 @@ export default function cookbooksPlugin(context: LoadContext): Plugin { goalsBySlug[slug] = text; introsBySlug[slug] = text; } + const replitPrompt = readReplitPrompt( + context.siteDir, + "cookbooks", + slug, + ); + if (replitPrompt) { + replitPromptsBySlug[slug] = replitPrompt; + } } actions.setGlobalData({ goalsBySlug, introsBySlug, + replitPromptsBySlug, } satisfies CookbooksGlobalData); }, }; diff --git a/scripts/validate-content.mjs b/scripts/validate-content.mjs index fdce1de5..6f39943d 100644 --- a/scripts/validate-content.mjs +++ b/scripts/validate-content.mjs @@ -11,12 +11,20 @@ if (!existsSync(resolve(ROOT, "content"))) { process.exit(1); } -const RESOURCE_ALLOWED_FILES = new Set(["goal.md", "prerequisites.md"]); +const RESOURCE_ALLOWED_FILES = new Set([ + "goal.md", + "prerequisites.md", + "replit-prompt.md", +]); /** A folder must have at least one of these to be published. */ const RESOURCE_REQUIRED_FILES = ["goal.md"]; const RESOURCE_SECTIONS = /** @type {const} */ (["recipes", "examples"]); -const COOKBOOK_ALLOWED_FILES = new Set(["goal.md", "intro.md"]); +const COOKBOOK_ALLOWED_FILES = new Set([ + "goal.md", + "intro.md", + "replit-prompt.md", +]); /** @type {string[]} */ const errors = []; diff --git a/src/components/agent-usage-card.tsx b/src/components/agent-usage-card.tsx index 8ab2caa7..03efab10 100644 --- a/src/components/agent-usage-card.tsx +++ b/src/components/agent-usage-card.tsx @@ -4,10 +4,23 @@ import { CopyPromptButton, type CopyPromptButtonProps, } from "@/components/copy-prompt-button"; +import { OpenPromptInButton } from "@/components/open-prompt-in-button"; +import { useReplitPrompt } from "@/lib/use-raw-content-markdown"; -type AgentUsageCardProps = Omit; +type AgentUsageCardProps = Omit< + CopyPromptButtonProps, + "className" | "label" +> & { + /** Template slug used to look up the optional Replit prompt. */ + slug: string; +}; + +export function AgentUsageCard({ + slug, + ...copyPromptProps +}: AgentUsageCardProps): ReactNode { + const replitPrompt = useReplitPrompt(slug); -export function AgentUsageCard(props: AgentUsageCardProps): ReactNode { return (
@@ -32,12 +45,18 @@ export function AgentUsageCard(props: AgentUsageCardProps): ReactNode { what you want -
+
+
diff --git a/src/components/cookbooks/cookbook-detail.tsx b/src/components/cookbooks/cookbook-detail.tsx index 5937267f..1aee0e19 100644 --- a/src/components/cookbooks/cookbook-detail.tsx +++ b/src/components/cookbooks/cookbook-detail.tsx @@ -46,6 +46,7 @@ export function CookbookDetail({

-
+
-
+
) : ( -
+
) { + return createElement( + "svg", + { + role: "img", + viewBox: "0 0 24 24", + xmlns: "http://www.w3.org/2000/svg", + fill: "currentColor", + "aria-hidden": "true", + ...props, + }, + createElement("path", { d: REPLIT_PATH }), + ); +} diff --git a/src/components/open-prompt-in-button.tsx b/src/components/open-prompt-in-button.tsx new file mode 100644 index 00000000..2f969062 --- /dev/null +++ b/src/components/open-prompt-in-button.tsx @@ -0,0 +1,64 @@ +import { ChevronDown } from "lucide-react"; +import { track } from "@vercel/analytics"; +import { Button } from "@/components/ui/button"; +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuTrigger, +} from "@/components/ui/dropdown-menu"; +import { getPromptTargets } from "@/lib/prompt-targets"; + +type OpenPromptInButtonProps = { + replitPrompt?: string; + slug: string; + title: string; + permalink: string; +}; + +export function OpenPromptInButton({ + replitPrompt, + slug, + title, + permalink, +}: OpenPromptInButtonProps) { + const targets = getPromptTargets({ replitPrompt }); + if (targets.length === 0) return null; + + return ( + + + + + + {targets.map((target) => { + const Icon = target.icon; + return ( + + + track("open_prompt_in", { + target: target.id, + slug, + title, + permalink, + }) + } + > + + {target.label} + + + ); + })} + + + ); +} diff --git a/src/lib/content-markdown.ts b/src/lib/content-markdown.ts index 8d7d686c..87cdc243 100644 --- a/src/lib/content-markdown.ts +++ b/src/lib/content-markdown.ts @@ -107,6 +107,27 @@ export function readCookbookGoal( return readFileSync(filePath, "utf-8"); } +type ReplitPromptTier = "recipes" | "examples" | "cookbooks"; + +/** + * Reads `content///replit-prompt.md` if present. Replit prompts + * are an opt-in export target, not a content section, so they live next to + * `goal.md` but stay out of `ContentSections` / `readContentSections`. + */ +export function readReplitPrompt( + rootDir: string, + tier: ReplitPromptTier, + slug: string, +): string | undefined { + const dir = + tier === "cookbooks" + ? cookbookDirectory(rootDir) + : markdownDirectory(rootDir, tier); + const filePath = resolve(dir, slug, "replit-prompt.md"); + if (!existsSync(filePath)) return undefined; + return readFileSync(filePath, "utf-8"); +} + /** Reads all present section files; throws when goal.md is missing. */ export function readContentSections( rootDir: string, diff --git a/src/lib/prompt-targets.ts b/src/lib/prompt-targets.ts new file mode 100644 index 00000000..1f1ff171 --- /dev/null +++ b/src/lib/prompt-targets.ts @@ -0,0 +1,41 @@ +import type { ComponentType, SVGProps } from "react"; +import { compressToEncodedURIComponent } from "lz-string"; +import { ReplitIcon } from "@/components/icons/replit-icon"; + +type PromptTarget = { + id: string; + label: string; + icon: ComponentType>; + href: string; +}; + +/** + * Builds the "Open in Replit" URL per the Open in Replit protocol. + * `stack=Build` selects Agent (Build mode); without it Replit may silently + * fail to fill the prompt. See https://docs.replit.com/references/integrations/open-in-replit. + */ +function buildReplitUrl(prompt: string): string { + const encoded = compressToEncodedURIComponent(prompt); + // Action-named utm_content (rather than component-named) so analytics + // history stays continuous if the dropdown is ever relocated. + const utm = + "utm_source=devhub&utm_medium=docs&utm_campaign=run-on-replit&utm_content=open-prompt-in"; + return `https://replit.com/?stack=Build&prompt=${encoded}&referrer=devhub&${utm}`; +} + +export function getPromptTargets({ + replitPrompt, +}: { + replitPrompt?: string; +}): PromptTarget[] { + const targets: PromptTarget[] = []; + if (replitPrompt) { + targets.push({ + id: "replit", + label: "Replit", + icon: ReplitIcon, + href: buildReplitUrl(replitPrompt), + }); + } + return targets; +} diff --git a/src/lib/use-raw-content-markdown.ts b/src/lib/use-raw-content-markdown.ts index 14405b13..8139e0d7 100644 --- a/src/lib/use-raw-content-markdown.ts +++ b/src/lib/use-raw-content-markdown.ts @@ -7,6 +7,7 @@ type ContentEntriesGlobalData = { slugs: string[]; rawMarkdownBySlug: Record; sectionsBySlug: Record; + replitPromptsBySlug: Record; }; export function useRawRecipeMarkdown(slug: string): string | undefined { @@ -36,6 +37,7 @@ export function useRawSolutionMarkdown(slug: string): string | undefined { type CookbooksGlobalData = { goalsBySlug: Record; introsBySlug: Record; + replitPromptsBySlug: Record; }; export function useCookbookGoal(slug: string): string | undefined { @@ -52,3 +54,27 @@ export function useExampleSections(slug: string): ContentSections | undefined { ) as ContentEntriesGlobalData; return data.sectionsBySlug[slug]; } + +/** + * Returns the raw `replit-prompt.md` body for a template, regardless of + * tier. Aggregates across the three plugin sources so detail pages don't + * have to know whether the slug is an example, recipe, or cookbook. + */ +export function useReplitPrompt(slug: string): string | undefined { + const examples = usePluginData( + "docusaurus-plugin-content-entries", + "examples", + ) as ContentEntriesGlobalData; + const recipes = usePluginData( + "docusaurus-plugin-content-entries", + "recipes", + ) as ContentEntriesGlobalData; + const cookbooks = usePluginData( + "docusaurus-plugin-cookbooks", + ) as CookbooksGlobalData; + return ( + examples.replitPromptsBySlug?.[slug] ?? + recipes.replitPromptsBySlug?.[slug] ?? + cookbooks.replitPromptsBySlug?.[slug] + ); +} diff --git a/tests/e2e/open-prompt-in.spec.ts b/tests/e2e/open-prompt-in.spec.ts new file mode 100644 index 00000000..88f80874 --- /dev/null +++ b/tests/e2e/open-prompt-in.spec.ts @@ -0,0 +1,136 @@ +import { test, expect, type Page } from "@playwright/test"; +import { readFileSync } from "node:fs"; +import { resolve } from "node:path"; +import { decompressFromEncodedURIComponent } from "lz-string"; + +// Playwright is run from the repo root (per package.json scripts and CI). +const REPO_ROOT = process.cwd(); + +type VaEvent = [string, { name: string; data: Record }]; +type WindowWithSpy = Window & { __vaEvents?: VaEvent[] }; + +/** + * Spies on `window.va` (the global function `@vercel/analytics` uses under + * the hood) so `track(...)` calls land in `window.__vaEvents`. Uses a + * configurable property so the analytics SDK can still assign its own + * implementation later without overwriting our spy. + */ +function setupAnalyticsSpy(page: Page) { + return page.addInitScript(() => { + const events: VaEvent[] = []; + (window as WindowWithSpy).__vaEvents = events; + let realVa: ((...args: unknown[]) => void) | undefined; + Object.defineProperty(window, "va", { + configurable: true, + get() { + return (...args: unknown[]) => { + events.push(args as VaEvent); + if (realVa) realVa(...args); + }; + }, + set(fn: (...args: unknown[]) => void) { + realVa = fn; + }, + }); + }); +} + +function getAnalyticsEvents(page: Page): Promise { + return page.evaluate(() => (window as WindowWithSpy).__vaEvents ?? []); +} + +test.describe("Open prompt in dropdown", () => { + test("renders on a Replit-enabled template; the Replit menu item links to a stack=Build URL that decodes back to the source file", async ({ + page, + }) => { + await page.goto("/templates/saas-tracker"); + + const trigger = page.getByRole("button", { name: "Open prompt in" }); + await expect(trigger).toBeVisible(); + await trigger.click(); + + const item = page.getByRole("menuitem", { name: "Replit" }); + await expect(item).toBeVisible(); + + const href = await item.getAttribute("href"); + expect(href, "Replit menu item should be a real anchor").toBeTruthy(); + + const url = new URL(href!); + expect(url.origin + url.pathname).toBe("https://replit.com/"); + // Replit's Open in Replit protocol requires stack=Build for Agent mode. + // Without it Replit may silently fail to fill the prompt. + expect(url.searchParams.get("stack")).toBe("Build"); + expect(url.searchParams.get("referrer")).toBe("devhub"); + expect(url.searchParams.get("utm_source")).toBe("devhub"); + + const encoded = url.searchParams.get("prompt"); + expect(encoded).toBeTruthy(); + + // End-to-end roundtrip: the prompt Replit Agent will see after decoding + // must equal the on-disk replit-prompt.md byte-for-byte. Catches any + // future regression in lz-string encoding, the plugin pipeline, the + // useReplitPrompt aggregator, or the buildReplitUrl helper. + const decoded = decompressFromEncodedURIComponent(encoded!); + const onDisk = readFileSync( + resolve(REPO_ROOT, "content/examples/saas-tracker/replit-prompt.md"), + "utf-8", + ); + expect(decoded).toBe(onDisk); + }); + + test("does not render on a template without a replit-prompt.md", async ({ + page, + }) => { + await page.goto("/templates/set-up-your-local-dev-environment"); + await expect( + page.getByRole("button", { name: "Copy prompt" }), + ).toBeVisible(); + await expect( + page.getByRole("button", { name: "Open prompt in" }), + ).toHaveCount(0); + }); + + test("clicking the Replit menu item fires an open_prompt_in analytics event with the expected payload", async ({ + page, + }) => { + await setupAnalyticsSpy(page); + await page.goto("/templates/saas-tracker"); + + await page.getByRole("button", { name: "Open prompt in" }).click(); + const item = page.getByRole("menuitem", { name: "Replit" }); + await expect(item).toBeVisible(); + + // Block the actual navigation so the test stays on the page after click. + // The track() call runs before the listener resolves, so blocking nav + // doesn't suppress the event. + await page.evaluate(() => { + document + .querySelectorAll( + "[data-slot=dropdown-menu-content] a", + ) + .forEach((a) => { + a.addEventListener("click", (e) => e.preventDefault(), { + once: true, + }); + }); + }); + + await item.click(); + + const events = await getAnalyticsEvents(page); + const openEvent = events.find( + ([action, payload]) => + action === "event" && payload?.name === "open_prompt_in", + ); + expect( + openEvent, + "open_prompt_in event should have been recorded", + ).toBeTruthy(); + expect(openEvent![1].data).toEqual({ + target: "replit", + slug: "saas-tracker", + title: "SaaS Subscription Tracker", + permalink: "/templates/saas-tracker", + }); + }); +}); diff --git a/tests/prompt-targets.test.ts b/tests/prompt-targets.test.ts new file mode 100644 index 00000000..dfd4c29e --- /dev/null +++ b/tests/prompt-targets.test.ts @@ -0,0 +1,59 @@ +import { describe, expect, test } from "vitest"; +import { decompressFromEncodedURIComponent } from "lz-string"; +import { getPromptTargets } from "../src/lib/prompt-targets"; + +describe("getPromptTargets", () => { + test("returns an empty array when no replitPrompt is provided", () => { + expect(getPromptTargets({})).toEqual([]); + expect(getPromptTargets({ replitPrompt: undefined })).toEqual([]); + expect(getPromptTargets({ replitPrompt: "" })).toEqual([]); + }); + + test("returns a single Replit target when replitPrompt is provided", () => { + const targets = getPromptTargets({ replitPrompt: "Hello Replit" }); + expect(targets).toHaveLength(1); + expect(targets[0]).toMatchObject({ id: "replit", label: "Replit" }); + expect(targets[0].icon).toBeDefined(); + expect(targets[0].href).toMatch(/^https:\/\/replit\.com\/\?/); + }); + + test("Replit URL includes the required stack=Build parameter", () => { + // The Open in Replit protocol requires stack=Build for Agent (Build) mode. + // Without it Replit may silently fail to fill the prompt. See + // https://docs.replit.com/references/integrations/open-in-replit. + const targets = getPromptTargets({ replitPrompt: "Build me an app" }); + const url = new URL(targets[0].href); + expect(url.searchParams.get("stack")).toBe("Build"); + }); + + test("Replit URL includes referrer and full UTM attribution", () => { + const targets = getPromptTargets({ replitPrompt: "x" }); + const url = new URL(targets[0].href); + expect(url.searchParams.get("referrer")).toBe("devhub"); + expect(url.searchParams.get("utm_source")).toBe("devhub"); + expect(url.searchParams.get("utm_medium")).toBe("docs"); + expect(url.searchParams.get("utm_campaign")).toBe("run-on-replit"); + expect(url.searchParams.get("utm_content")).toBeTruthy(); + }); + + test("the encoded prompt param losslessly roundtrips to the original input", () => { + // Full pipeline: prompt text → lz-string encode → URL param → Replit's + // decode must equal the original. If this breaks, Replit Agent sees + // garbage instead of the template's instructions. + const original = [ + "# Build a Databricks app on Replit", + "", + "Steps:", + "1. Configure Replit Secrets `DATABRICKS_HOST` and `DATABRICKS_TOKEN`.", + "2. Run `SELECT current_user()` to verify the warehouse.", + "", + "Use the Databricks palette: #FF3621, #0B2026, #EEEDE9, #F9F7F4.", + "", + 'Ask: "Not sure — help me decide".', + ].join("\n"); + const targets = getPromptTargets({ replitPrompt: original }); + const encoded = new URL(targets[0].href).searchParams.get("prompt"); + expect(encoded).toBeTruthy(); + expect(decompressFromEncodedURIComponent(encoded!)).toBe(original); + }); +}); diff --git a/tests/validate-content.test.ts b/tests/validate-content.test.ts index 153f4ef0..3eec3853 100644 --- a/tests/validate-content.test.ts +++ b/tests/validate-content.test.ts @@ -120,6 +120,21 @@ describe("validate-content script", () => { expect(result.stderr).toContain("not an allowed filename"); }); + test("accepts replit-prompt.md alongside goal.md in a resource folder", () => { + seedFixture(workDir, { + "content/recipes/with-replit/goal.md": "Build it.\n", + "content/recipes/with-replit/replit-prompt.md": + "You are Replit Agent. Build...\n", + "content/examples/also-replit/goal.md": "Build it.\n", + "content/examples/also-replit/replit-prompt.md": + "You are Replit Agent. Build...\n", + }); + + const result = runValidator(workDir); + expect(result.status).toBe(0); + expect(result.stdout).toContain("validation passed"); + }); + test("accepts content/cookbooks//intro.md", () => { seedFixture(workDir, { "content/recipes/r/goal.md": "Build it.\n", @@ -142,6 +157,20 @@ describe("validate-content script", () => { expect(result.stderr).toContain("not a directory"); }); + test("accepts replit-prompt.md alongside intro.md in a cookbook folder", () => { + seedFixture(workDir, { + "content/recipes/r/goal.md": "Build it.\n", + "content/examples/e/goal.md": "Build it.\n", + "content/cookbooks/with-replit/intro.md": "## Intro\n", + "content/cookbooks/with-replit/replit-prompt.md": + "You are Replit Agent. Build...\n", + }); + + const result = runValidator(workDir); + expect(result.status).toBe(0); + expect(result.stdout).toContain("validation passed"); + }); + test("fails when a cookbook folder has a disallowed filename", () => { seedFixture(workDir, { "content/cookbooks/my-cookbook/intro.md": "## Intro\n", From 808e8577918ae9a03f31c22712f5bb040e58655c Mon Sep 17 00:00:00 2001 From: Tony Dang Date: Mon, 1 Jun 2026 14:27:52 -0700 Subject: [PATCH 2/4] fix(open-prompt-in): match dropdown width to its trigger Using Radix's --radix-dropdown-menu-trigger-width CSS variable makes the dropdown's width track the "Open prompt in" trigger button exactly, so the menu tucks under it with matching left and right edges. Replaces the prior min-w-44 (176px) which overhung the trigger on the right, then a brief intermediate state where dropping the override fell back to the shadcn default min-w-[8rem] (128px) and left the dropdown narrower than the trigger. --- src/components/open-prompt-in-button.tsx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/components/open-prompt-in-button.tsx b/src/components/open-prompt-in-button.tsx index 2f969062..1519ce4d 100644 --- a/src/components/open-prompt-in-button.tsx +++ b/src/components/open-prompt-in-button.tsx @@ -33,7 +33,10 @@ export function OpenPromptInButton({ - + {targets.map((target) => { const Icon = target.icon; return ( From 8583bee4c29adbd2f1fa5c7d9a5133c1c9699972 Mon Sep 17 00:00:00 2001 From: Tony Dang Date: Mon, 1 Jun 2026 17:38:56 -0700 Subject: [PATCH 3/4] refactor(replit-prompts): extract shared preamble + tighten per-template files Addresses review feedback on PR #106 about copy-pasted boilerplate across the 10 Replit prompt files. Every universal block (Before Building routing, PAT Fallback Path, Permission Handling, Style guide, Out of Scope) now lives in a single content/replit-shared/preamble.md. Per-template files hold only the unique task: title, hero, Data, optional Additional Secrets, Features, Build Order, optional Notes. Architecture matches the existing composeAgentPrompt pattern used by the Copy prompt feature: shared boilerplate + per-template body, joined by readReplitPrompt() with a fixed --- separator. No markers, no per-section splicing. Per-template files shrink from ~100-130 lines to ~30-60 lines. Updating any shared section is now a single-file edit (was 10-file edit). Content quality improvements while restructuring: - Normalize heading case to Title Case across all per-template files - Drop DevHub-template cross-references that don't reach Replit Agent - Tighten content-moderator Model Serving handling (was mentioned 5x) - Restructure volume-file-upload Notes into structured sub-points - Differentiate genie-analytics-app cookbook (full multi-tab app) from genie-conversational-analytics recipe (focused panel addition) - Normalize hero formula and section ordering across all 10 templates - Concrete env-var names in genie-multi-space Additional Secrets Reader: - readReplitPrompt composes preamble + --- + per-template task - Throws a clear error when the shared preamble file is missing - e2e roundtrip test now compares URL prompt against composed output Tests: - tests/replit-prompt-composition.test.ts (NEW): 8 cases covering composition contract, tier coverage, whitespace trimming, and the missing-preamble error path --- .../genie-analytics-app/replit-prompt.md | 108 +++++----------- .../replit-prompt.md | 74 ++--------- .../content-moderator/replit-prompt.md | 89 +++---------- .../inventory-intelligence/replit-prompt.md | 76 ++--------- .../examples/saas-tracker/replit-prompt.md | 91 +++----------- .../vacation-rentals/replit-prompt.md | 76 ++--------- .../replit-prompt.md | 104 ++++----------- .../genie-multi-space/replit-prompt.md | 72 ++--------- .../replit-prompt.md | 74 ++--------- .../volume-file-upload/replit-prompt.md | 81 ++---------- content/replit-shared/preamble.md | 52 ++++++++ src/lib/content-markdown.ts | 39 +++++- tests/e2e/open-prompt-in.spec.ts | 21 ++-- tests/replit-prompt-composition.test.ts | 118 ++++++++++++++++++ 14 files changed, 361 insertions(+), 714 deletions(-) create mode 100644 content/replit-shared/preamble.md create mode 100644 tests/replit-prompt-composition.test.ts diff --git a/content/cookbooks/genie-analytics-app/replit-prompt.md b/content/cookbooks/genie-analytics-app/replit-prompt.md index dd515274..afda4611 100644 --- a/content/cookbooks/genie-analytics-app/replit-prompt.md +++ b/content/cookbooks/genie-analytics-app/replit-prompt.md @@ -1,100 +1,50 @@ -# Build a Genie Analytics App with Databricks on Replit +# Build a Genie Analytics App -You are Replit Agent. Help the user build a Replit app with Databricks Genie conversational analytics over their Unity Catalog data. +Help the user build a Databricks-backed Genie analytics app: a full internal app over Unity Catalog data with a SQL KPI dashboard, table previews, a Genie chat panel, and saved questions. -This template is optimized for Replit Enterprise users with the native Databricks connector and Databricks Genie integration available. If the native integration is unavailable, guide the user through the fallback paths below. +## Data -## Before Building - -First, try to use Replit's native Databricks connector and Genie integration. Do not route from raw plan tier alone. Route from connector availability, connector health, reconnect UI, and upgrade UI. - -Follow this order: - -1. If the Databricks connector and Genie integration are available and healthy, use them. -2. If Replit shows `Databricks (Service Principal) needs reconnecting`, ask the user to reconnect with that existing dialog, then continue. -3. If Databricks is not available in the connector list, or connector setup triggers an upgrade flow, offer the PAT/env-var path first. -4. Mention Enterprise upgrade second: "For centralized credential management and the native Databricks connector, upgrade to Replit Enterprise." - -Ask only one question at a time. If asking the user to choose, always include `Not sure — help me decide`. - -## Connector And Genie Path - -Use the Databricks connector for SQL verification and table previews. Use Replit's Databricks Genie integration for conversational analytics. +Use the Databricks connector for SQL verification and table previews. Use Replit's Databricks Genie integration for the conversational analytics panel. Ask for: - Unity Catalog catalog name - Unity Catalog schema name -- table names or Genie space to use +- the primary table(s) to analyze +- the Genie space (or table set) to use for natural-language questions - SQL Warehouse, if not already configured by the connector -If the user does not already have a Genie space, ask whether they want to continue with SQL dashboard previews only, configure a Genie space in Databricks, or use the PAT fallback for direct Genie API access if available. - -## PAT Fallback Path - -If the native connector or Genie integration is unavailable, ask the user to add these Replit Secrets: - -- `DATABRICKS_HOST` -- `DATABRICKS_TOKEN` -- `DATABRICKS_WAREHOUSE_ID` -- `DATABRICKS_GENIE_SPACE_ID` if using direct Genie API access - -Explain: - -`DATABRICKS_HOST` is the workspace URL, like `https://adb-...azuredatabricks.net`. +If the user does not already have a Genie space, ask whether they want to continue with SQL-only dashboard and previews, configure a Genie space in Databricks first, or use the PAT fallback for direct Genie API access if available. -`DATABRICKS_TOKEN` is a Databricks personal access token. +## Additional Secrets -`DATABRICKS_WAREHOUSE_ID` is the SQL Warehouse ID. +If the user is on the PAT fallback path and wants direct Genie API access, also ask for: -`DATABRICKS_GENIE_SPACE_ID` is the Genie space ID to use for conversational analytics. The user can list their Genie spaces with the Databricks CLI — for example, `databricks api get /api/2.0/genie/spaces` — and copy the ID of the space they want to use. +- `DATABRICKS_GENIE_SPACE_ID` — the Genie space ID to use for conversational analytics. The user can list their Genie spaces with the Databricks CLI — for example, `databricks api get /api/2.0/genie/spaces` — and copy the ID of the space they want to use. -Use the SQL Statement Execution API for table previews and direct Genie API calls for conversations when available. - -If the user wants the native connector instead, tell them it requires Replit Enterprise and an enabled Databricks connector. - -## App Requirements +## Features Build a polished full-stack web app with: -- Data source summary showing selected catalog, schema, tables, and warehouse -- Table preview cards with row counts, freshness, and sample rows -- Genie chat panel for natural-language analytics questions -- Suggested question chips generated from the selected tables -- Conversation history in the UI for the current session -- SQL preview or citations when Genie returns query-backed answers -- Empty states, loading states, and clear connection/permission errors - -Use a modern UI with Tailwind/shadcn-style components. Use the Databricks palette where appropriate: - -- `#FF3621` -- `#0B2026` -- `#EEEDE9` -- `#F9F7F4` - -## Permission Handling - -If SQL or Genie access fails because the connector or PAT lacks permission: - -- Explain the failed operation -- Ask whether to use a different table, a different Genie space, continue with SQL-only previews, or request Databricks permissions -- Do not silently switch to local-only mock data - -The source of truth for analytics data should remain Databricks. +- Multi-tab layout: **Dashboard**, **Tables**, **Ask Genie**, **History** +- Dashboard tab with SQL-driven KPI cards, trend charts, and a free-form filter row +- Tables tab with one preview card per selected table: row count, freshness, schema, and sample rows +- Ask Genie tab with a chat panel for natural-language analytics questions, suggested-question chips generated from the selected tables, and SQL preview/citations when Genie returns query-backed answers +- History tab listing the current session's Genie conversations with the ability to re-run a question or copy its SQL +- A persistent saved-questions sidebar in the Ask Genie tab (kept in browser local storage; no extra Databricks tables required) +- Shareable conversation links so a teammate can open the same question with the same Genie answer +- Empty states, loading states, reconnect states, and clear connection/permission errors ## Build Order -1. Resolve Databricks access using the connector or PAT fallback. -2. Verify warehouse access with a simple query like `SELECT current_user()`. +1. Resolve Databricks access per the general routing above. +2. Verify warehouse access with `SELECT current_user()`. 3. Ask for catalog, schema, tables, and Genie space. -4. Build table previews and metadata cards. -5. Add the Genie conversational analytics panel. -6. Add suggested questions and conversation UI polish. -7. Run the app in Replit Preview. -8. Help the user deploy with Replit Deployments. - -## Scope Notes - -This Replit template uses Replit's Databricks connector and Genie integration when available. - -Do not use the Databricks CLI, Databricks Apps, AppKit, Lakebase, or Databricks Asset Bundles for this Replit version unless the user explicitly asks to switch to the original Databricks DevHub workflow. +4. Build the app shell with the four tabs and shared navigation. +5. Build the Tables tab (preview cards) backed by SQL warehouse queries. +6. Build the Dashboard tab (KPI cards + trend charts) backed by SQL warehouse queries. +7. Add the Genie conversational analytics panel in the Ask Genie tab, with suggested-question chips and SQL preview/citations. +8. Add the History tab and the saved-questions sidebar (local storage). +9. Add shareable conversation links. +10. Run the app in Replit Preview. +11. Help the user deploy with Replit Deployments. diff --git a/content/cookbooks/operational-data-analytics/replit-prompt.md b/content/cookbooks/operational-data-analytics/replit-prompt.md index 489372d2..b45fd30c 100644 --- a/content/cookbooks/operational-data-analytics/replit-prompt.md +++ b/content/cookbooks/operational-data-analytics/replit-prompt.md @@ -1,25 +1,10 @@ -# Build an Operational Data Analytics App with Databricks on Replit +# Build an Operational Data Analytics App -You are Replit Agent. Help the user build a Databricks-backed operational analytics app over Unity Catalog tables: an internal dashboard for monitoring operational metrics, trends, anomalies, and business KPIs. +Help the user build a Databricks-backed operational analytics app over Unity Catalog tables: an internal dashboard for monitoring operational metrics, trends, anomalies, and business KPIs. -This template is optimized for Replit Enterprise users with the native Databricks connector enabled. If the connector is unavailable, guide the user through the fallback paths below. +## Data -## Before Building - -First, try to use Replit's native Databricks connector. Do not route from raw plan tier alone. Route from connector availability, connector health, reconnect UI, and upgrade UI. - -Follow this order: - -1. If the Databricks connector is available and healthy, use it. -2. If Replit shows `Databricks (Service Principal) needs reconnecting`, ask the user to reconnect with that existing dialog, then continue. -3. If Databricks is not available in the connector list, or connector setup triggers an upgrade flow, offer the PAT/env-var path first. -4. Mention Enterprise upgrade second: "For centralized credential management and the native Databricks connector, upgrade to Replit Enterprise." - -Ask only one question at a time. If asking the user to choose, always include `Not sure — help me decide`. - -## Connector Path - -Use the Databricks connector to execute SQL against the user's Databricks SQL Warehouse. +Use the Databricks connector (or PAT fallback) to execute SQL against the user's SQL Warehouse. Ask for: @@ -43,27 +28,7 @@ CREATE TABLE IF NOT EXISTS ..operational_metrics ( ); ``` -## PAT Fallback Path - -If the native connector is unavailable, ask the user to add these Replit Secrets: - -- `DATABRICKS_HOST` -- `DATABRICKS_TOKEN` -- `DATABRICKS_WAREHOUSE_ID` - -Explain: - -`DATABRICKS_HOST` is the workspace URL, like `https://adb-...azuredatabricks.net`. - -`DATABRICKS_TOKEN` is a Databricks personal access token. - -`DATABRICKS_WAREHOUSE_ID` is the SQL Warehouse ID. - -Use these env vars to call the Databricks SQL Statement Execution API. - -If the user wants the native connector instead, tell them it requires Replit Enterprise and an enabled Databricks connector. - -## App Requirements +## Features Build a polished full-stack web app with: @@ -73,29 +38,12 @@ Build a polished full-stack web app with: - Detail table for drilling into metric rows - Saved SQL query panel so the user can see and adjust the queries powering the dashboard - Genie-powered analytics panel for questions like "Which regions are missing target?" and "What changed week over week?" -- Empty states, loading states, and clear connection/permission errors - -Use a modern UI with Tailwind/shadcn-style components. Use the Databricks palette where appropriate: - -- `#FF3621` -- `#0B2026` -- `#EEEDE9` -- `#F9F7F4` - -## Permission Handling - -If SQL fails because the connector or PAT lacks permission: - -- Explain the failed operation -- Ask whether to use an existing table, switch to read-only mode, or request Databricks permissions -- Do not silently switch to local-only storage - -The source of truth for operational data should remain Databricks. +- Empty states, loading states, clear connection/permission errors ## Build Order -1. Resolve Databricks access using the connector or PAT fallback. -2. Verify warehouse access with a simple query like `SELECT current_user()`. +1. Resolve Databricks access per the general routing above. +2. Verify warehouse access with `SELECT current_user()`. 3. Ask for catalog, schema, and target table. 4. Inspect the target table schema if available. 5. Create demo data only if the user wants a sandbox table. @@ -105,8 +53,6 @@ The source of truth for operational data should remain Databricks. 9. Run the app in Replit Preview. 10. Help the user deploy with Replit Deployments. -## Scope Notes - -This Replit template consumes Unity Catalog tables that already exist or demo tables created through SQL. +## Notes -It does not provision external storage, Lakehouse Sync, Lakeflow Declarative Pipelines, or Databricks Asset Bundles unless the user explicitly asks to switch to the original Databricks DevHub workflow. +This template consumes Unity Catalog tables that already exist or demo tables created through SQL. It does not provision external storage, Lakehouse Sync, or Lakeflow Declarative Pipelines for this Replit version. diff --git a/content/examples/content-moderator/replit-prompt.md b/content/examples/content-moderator/replit-prompt.md index 58c86719..c9e5c339 100644 --- a/content/examples/content-moderator/replit-prompt.md +++ b/content/examples/content-moderator/replit-prompt.md @@ -1,25 +1,10 @@ -# Build a Content Moderation Console with Databricks on Replit +# Build a Content Moderation Console -You are Replit Agent. Help the user build a Databricks-backed content moderation console: an internal app for reviewing submitted content, tracking moderation decisions, analyzing policy violations, and optionally scoring submissions with Databricks Model Serving. +Help the user build a Databricks-backed content moderation console: an internal app for reviewing submitted content, tracking moderation decisions, and analyzing policy violations. -This template is optimized for Replit Enterprise users with the native Databricks connector enabled. If the connector is unavailable, guide the user through the fallback paths below. +## Data -## Before Building - -First, try to use Replit's native Databricks connector. Do not route from raw plan tier alone. Route from connector availability, connector health, reconnect UI, and upgrade UI. - -Follow this order: - -1. If the Databricks connector is available and healthy, use it. -2. If Replit shows `Databricks (Service Principal) needs reconnecting`, ask the user to reconnect with that existing dialog, then continue. -3. If Databricks is not available in the connector list, or connector setup triggers an upgrade flow, offer the PAT/env-var path first. -4. Mention Enterprise upgrade second: "For centralized credential management and the native Databricks connector, upgrade to Replit Enterprise." - -Ask only one question at a time. If asking the user to choose, always include `Not sure — help me decide`. - -## Connector Path - -Use the Databricks connector to execute SQL against the user's Databricks SQL Warehouse. +Use the Databricks connector (or PAT fallback) to execute SQL against the user's SQL Warehouse. Ask for: @@ -50,71 +35,31 @@ CREATE TABLE IF NOT EXISTS ..moderation_submissions ( If the table is empty, offer to seed it with realistic demo submissions across multiple content types, policy categories, and moderation statuses. -## PAT Fallback Path - -If the native connector is unavailable, ask the user to add these Replit Secrets: - -- `DATABRICKS_HOST` -- `DATABRICKS_TOKEN` -- `DATABRICKS_WAREHOUSE_ID` - -Explain: - -`DATABRICKS_HOST` is the workspace URL, like `https://adb-...azuredatabricks.net`. - -`DATABRICKS_TOKEN` is a Databricks personal access token. - -`DATABRICKS_WAREHOUSE_ID` is the SQL Warehouse ID. - -Use these env vars to call the Databricks SQL Statement Execution API. +## Additional Secrets If the user wants Databricks Model Serving for automatic scoring, also ask for: -- `DATABRICKS_MODEL_SERVING_ENDPOINT` - -Use the PAT to call the Model Serving endpoint only if the user explicitly wants AI scoring. +- `DATABRICKS_MODEL_SERVING_ENDPOINT` — the Model Serving endpoint URL. -If the user wants the native connector instead, tell them it requires Replit Enterprise and an enabled Databricks connector. +Model Serving is opt-in; only configure it when the user explicitly asks for AI scoring. -## App Requirements +## Features Build a polished full-stack web app with: -- Moderation dashboard showing pending reviews, approved/rejected counts, average severity, review throughput, and policy category distribution +- Moderation dashboard: pending reviews, approved/rejected counts, average severity, review throughput, policy category distribution - Submission queue with search, filters, severity badges, policy category badges, and moderation status tabs - Submission detail page with full content, model score, suggested category, reviewer decision controls, and reviewer notes -- Review workflow for approve, reject, escalate, and mark as needs more context +- Review workflow with approve, reject, escalate, and "needs more context" actions - Analytics charts powered by SQL Warehouse queries - Genie-powered analytics panel for questions like "Which policy categories are increasing?" and "Which reviewers have the longest queues?" - Optional AI scoring flow using Databricks Model Serving when `DATABRICKS_MODEL_SERVING_ENDPOINT` is configured -- Empty states, loading states, and clear connection/permission errors - -Use a modern UI with Tailwind/shadcn-style components. Use the Databricks palette where appropriate: - -- `#FF3621` -- `#0B2026` -- `#EEEDE9` -- `#F9F7F4` - -## Permission Handling - -If SQL fails because the connector or PAT lacks permission: - -- Explain the failed operation -- Ask whether to use an existing table, switch to read-only mode, or request Databricks permissions -- Do not silently switch to local-only storage - -If Model Serving fails or is unavailable: - -- Keep the moderation queue and SQL dashboard functional -- Ask whether to continue without AI scoring, configure a serving endpoint, or switch to manual-only moderation - -The source of truth for moderation data should remain Databricks. +- Empty states, loading states, clear connection/permission errors ## Build Order -1. Resolve Databricks access using the connector or PAT fallback. -2. Verify warehouse access with a simple query like `SELECT current_user()`. +1. Resolve Databricks access per the general routing above. +2. Verify warehouse access with `SELECT current_user()`. 3. Ask for catalog and schema. 4. Create or verify the `moderation_submissions` table. 5. Seed demo data if needed. @@ -126,10 +71,6 @@ The source of truth for moderation data should remain Databricks. 11. Run the app in Replit Preview. 12. Help the user deploy with Replit Deployments. -## Scope Notes - -This Replit template uses Databricks SQL Warehouse access through Replit's connector or PAT fallback, plus Genie when Replit's Databricks Genie integration is available. - -Databricks Model Serving is optional in this Replit version. Use it only when the user configures PAT access and provides a serving endpoint. +## Notes -Do not use the Databricks CLI, Databricks Apps, AppKit, Lakebase, or Databricks Asset Bundles for this Replit version unless the user explicitly asks to switch to the original Databricks DevHub workflow. +If Model Serving fails or is unavailable, keep the moderation queue and SQL dashboard functional and ask whether to continue without AI scoring, configure a serving endpoint, or switch to manual-only moderation. diff --git a/content/examples/inventory-intelligence/replit-prompt.md b/content/examples/inventory-intelligence/replit-prompt.md index 90f823d1..0fb0ff7c 100644 --- a/content/examples/inventory-intelligence/replit-prompt.md +++ b/content/examples/inventory-intelligence/replit-prompt.md @@ -1,25 +1,10 @@ -# Build an Inventory Intelligence App with Databricks on Replit +# Build an Inventory Intelligence App -You are Replit Agent. Help the user build a Databricks-backed inventory intelligence app: an internal tool for monitoring stock levels, demand, replenishment risk, supplier performance, and inventory value. +Help the user build a Databricks-backed inventory intelligence app: an internal tool for monitoring stock levels, demand, replenishment risk, supplier performance, and inventory value. -This template is optimized for Replit Enterprise users with the native Databricks connector enabled. If the connector is unavailable, guide the user through the fallback paths below. +## Data -## Before Building - -First, try to use Replit's native Databricks connector. Do not route from raw plan tier alone. Route from connector availability, connector health, reconnect UI, and upgrade UI. - -Follow this order: - -1. If the Databricks connector is available and healthy, use it. -2. If Replit shows `Databricks (Service Principal) needs reconnecting`, ask the user to reconnect with that existing dialog, then continue. -3. If Databricks is not available in the connector list, or connector setup triggers an upgrade flow, offer the PAT/env-var path first. -4. Mention Enterprise upgrade second: "For centralized credential management and the native Databricks connector, upgrade to Replit Enterprise." - -Ask only one question at a time. If asking the user to choose, always include `Not sure — help me decide`. - -## Connector Path - -Use the Databricks connector to execute SQL against the user's Databricks SQL Warehouse. +Use the Databricks connector (or PAT fallback) to execute SQL against the user's SQL Warehouse. Ask for: @@ -49,59 +34,22 @@ CREATE TABLE IF NOT EXISTS ..inventory_items ( If the table is empty, offer to seed it with realistic inventory records across categories, locations, and suppliers. -## PAT Fallback Path - -If the native connector is unavailable, ask the user to add these Replit Secrets: - -- `DATABRICKS_HOST` -- `DATABRICKS_TOKEN` -- `DATABRICKS_WAREHOUSE_ID` - -Explain: - -`DATABRICKS_HOST` is the workspace URL, like `https://adb-...azuredatabricks.net`. - -`DATABRICKS_TOKEN` is a Databricks personal access token. - -`DATABRICKS_WAREHOUSE_ID` is the SQL Warehouse ID. - -Use these env vars to call the Databricks SQL Statement Execution API. - -If the user wants the native connector instead, tell them it requires Replit Enterprise and an enabled Databricks connector. - -## App Requirements +## Features Build a polished full-stack web app with: -- Inventory dashboard showing stockouts, at-risk SKUs, overstock, total inventory value, and replenishment workload +- Inventory dashboard: stockouts, at-risk SKUs, overstock, total inventory value, replenishment workload - Item table with search, filters, status pills, and editable replenishment status - Reorder recommendation panel using SQL-derived logic from on-hand quantity, reorder point, and forecast demand - Supplier and location performance charts - Category-level inventory value and risk charts - Genie-powered analytics panel for questions like "Which suppliers have the most at-risk SKUs?" and "What should we reorder this week?" -- Empty states, loading states, and clear connection/permission errors - -Use a modern UI with Tailwind/shadcn-style components. Use the Databricks palette where appropriate: - -- `#FF3621` -- `#0B2026` -- `#EEEDE9` -- `#F9F7F4` - -## Permission Handling - -If SQL fails because the connector or PAT lacks permission: - -- Explain the failed operation -- Ask whether to use an existing table, switch to read-only mode, or request Databricks permissions -- Do not silently switch to local-only storage - -The source of truth for inventory data should remain Databricks. +- Empty states, loading states, clear connection/permission errors ## Build Order -1. Resolve Databricks access using the connector or PAT fallback. -2. Verify warehouse access with a simple query like `SELECT current_user()`. +1. Resolve Databricks access per the general routing above. +2. Verify warehouse access with `SELECT current_user()`. 3. Ask for catalog and schema. 4. Create or verify the `inventory_items` table. 5. Seed demo data if needed. @@ -111,8 +59,6 @@ The source of truth for inventory data should remain Databricks. 9. Run the app in Replit Preview. 10. Help the user deploy with Replit Deployments. -## Scope Notes - -This Replit template uses Databricks SQL Warehouse access through Replit's connector or PAT fallback, plus Genie when Replit's Databricks Genie integration is available. +## Notes -Do not use the Databricks CLI, Databricks Apps, AppKit, Lakebase, Model Serving, or Databricks Asset Bundles for this Replit version unless the user explicitly asks to switch to the original Databricks DevHub workflow. If the user wants AI forecasting from Databricks Model Serving, ask whether to add Databricks PAT access for that specific feature. +If the user wants AI forecasting from Databricks Model Serving, ask whether to add Databricks PAT access for that specific feature. Otherwise, Model Serving is out of scope for this Replit version. diff --git a/content/examples/saas-tracker/replit-prompt.md b/content/examples/saas-tracker/replit-prompt.md index 13a7f73e..54d0f532 100644 --- a/content/examples/saas-tracker/replit-prompt.md +++ b/content/examples/saas-tracker/replit-prompt.md @@ -1,25 +1,10 @@ -# Build a SaaS Subscription Tracker with Databricks on Replit +# Build a SaaS Subscription Tracker -You are Replit Agent. Help the user build a Databricks-backed SaaS Subscription Tracker: an internal app for tracking SaaS tools, owners, costs, billing cycles, status, categories, and renewal dates. +Help the user build a Databricks-backed SaaS Subscription Tracker: an internal app for tracking SaaS tools, owners, costs, billing cycles, status, categories, and renewal dates. -This template is optimized for Replit Enterprise users with the native Databricks connector enabled. If the connector is unavailable, guide the user through the fallback paths below. +## Data -## Before Building - -First, try to use Replit's native Databricks connector. Do not route from raw plan tier alone. Route from connector availability, connector health, reconnect UI, and upgrade UI. - -Follow this order: - -1. If the Databricks connector is available and healthy, use it. -2. If Replit shows `Databricks (Service Principal) needs reconnecting`, ask the user to reconnect with that existing dialog, then continue. -3. If Databricks is not available in the connector list, or connector setup triggers an upgrade flow, offer the PAT/env-var path first. -4. Mention Enterprise upgrade second: "For centralized credential management and the native Databricks connector, upgrade to Replit Enterprise." - -Ask only one question at a time. If asking the user to choose, always include `Not sure — help me decide`. - -## Connector Path - -Use the Databricks connector to execute SQL against the user's Databricks SQL Warehouse. +Use the Databricks connector (or PAT fallback) to execute SQL against the user's SQL Warehouse. Ask for: @@ -47,75 +32,31 @@ CREATE TABLE IF NOT EXISTS ..subscriptions ( If the table is empty, offer to seed it with realistic demo subscriptions. -## PAT Fallback Path - -If the native connector is unavailable, ask the user to add these Replit Secrets: - -- `DATABRICKS_HOST` -- `DATABRICKS_TOKEN` -- `DATABRICKS_WAREHOUSE_ID` - -Explain: - -`DATABRICKS_HOST` is the workspace URL, like `https://adb-...azuredatabricks.net`. - -`DATABRICKS_TOKEN` is a Databricks personal access token. - -`DATABRICKS_WAREHOUSE_ID` is the SQL Warehouse ID. - -Use these env vars to call the Databricks SQL Statement Execution API. - -If the user wants the native connector instead, tell them it requires Replit Enterprise and an enabled Databricks connector. - -## App Requirements +## Features Build a polished full-stack web app with: -- Dashboard showing total monthly spend, annualized spend, renewals due soon, active subscriptions, and spend by category +- Dashboard: total monthly spend, annualized spend, renewals due soon, active subscriptions, spend by category - Genie-powered conversational analytics panel for questions like "Which renewals are coming up this month?" and "Which teams have the highest SaaS spend?" - Subscription table with search and filters - Add/edit/delete subscription flow - Renewal timeline -- Category breakdown chart -- Owner breakdown chart -- Empty states and loading states -- Clear error handling for Databricks connection, SQL permissions, missing tables, and unavailable warehouses - -Use a modern UI with Tailwind/shadcn-style components. Use the Databricks palette where appropriate: - -- `#FF3621` -- `#0B2026` -- `#EEEDE9` -- `#F9F7F4` - -## Permission Handling - -If SQL fails because the connector or PAT lacks permission: - -- Explain the failed operation -- Ask whether to use an existing table, switch to read-only mode, or request Databricks permissions -- Do not silently switch to local-only storage - -The source of truth for subscription data should remain Databricks. +- Category and owner breakdown charts +- Empty states, loading states, clear error handling ## Build Order -1. Resolve Databricks access using the connector or PAT fallback. -2. Verify warehouse access with a simple query like `SELECT current_user()`. +1. Resolve Databricks access per the general routing above. +2. Verify warehouse access with `SELECT current_user()`. 3. Ask for catalog and schema. 4. Create or verify the `subscriptions` table. 5. Seed demo data if needed. 6. Build the app UI. -7. Wire CRUD operations to Databricks SQL. -8. Build the analytics dashboard. -9. Add Genie conversational analytics when available. -10. Run the app in Replit Preview. -11. Help the user deploy with Replit Deployments. - -## Scope Notes - -This Replit template uses Databricks SQL Warehouse access through Replit's connector or PAT fallback. +7. Wire CRUD and analytics queries to Databricks SQL. +8. Add Genie conversational analytics when available. +9. Run the app in Replit Preview. +10. Help the user deploy with Replit Deployments. -Use Genie when Replit's Databricks Genie integration is available. If Genie is unavailable, keep the SQL dashboard functional and ask whether the user wants to configure Genie access, continue without conversational analytics, or switch to the original Databricks DevHub workflow. +## Notes -Do not use the Databricks CLI, Databricks Apps, AppKit, Lakebase, or Databricks Asset Bundles for this Replit version unless the user explicitly asks to switch to the original Databricks DevHub workflow. +Genie is the preferred path for conversational analytics. If Replit's Databricks Genie integration is unavailable, keep the SQL dashboard functional and ask the user whether to configure Genie access, continue without it, or switch to the original Databricks DevHub workflow. diff --git a/content/examples/vacation-rentals/replit-prompt.md b/content/examples/vacation-rentals/replit-prompt.md index 0d54c74a..1067936c 100644 --- a/content/examples/vacation-rentals/replit-prompt.md +++ b/content/examples/vacation-rentals/replit-prompt.md @@ -1,25 +1,10 @@ -# Build a Vacation Rentals Operations Console with Databricks on Replit +# Build a Vacation Rentals Operations Console -You are Replit Agent. Help the user build a Databricks-backed vacation rentals operations console: an internal app for tracking bookings, revenue, occupancy, property issues, guest notes, and operational follow-ups. +Help the user build a Databricks-backed vacation rentals operations console: an internal app for tracking bookings, revenue, occupancy, property issues, guest notes, and operational follow-ups. -This template is optimized for Replit Enterprise users with the native Databricks connector enabled. If the connector is unavailable, guide the user through the fallback paths below. +## Data -## Before Building - -First, try to use Replit's native Databricks connector. Do not route from raw plan tier alone. Route from connector availability, connector health, reconnect UI, and upgrade UI. - -Follow this order: - -1. If the Databricks connector is available and healthy, use it. -2. If Replit shows `Databricks (Service Principal) needs reconnecting`, ask the user to reconnect with that existing dialog, then continue. -3. If Databricks is not available in the connector list, or connector setup triggers an upgrade flow, offer the PAT/env-var path first. -4. Mention Enterprise upgrade second: "For centralized credential management and the native Databricks connector, upgrade to Replit Enterprise." - -Ask only one question at a time. If asking the user to choose, always include `Not sure — help me decide`. - -## Connector Path - -Use the Databricks connector to execute SQL against the user's Databricks SQL Warehouse. +Use the Databricks connector (or PAT fallback) to execute SQL against the user's SQL Warehouse. Ask for: @@ -50,59 +35,22 @@ CREATE TABLE IF NOT EXISTS ..vacation_rental_bookings ( If the table is empty, offer to seed it with realistic demo bookings across multiple markets and channels. -## PAT Fallback Path - -If the native connector is unavailable, ask the user to add these Replit Secrets: - -- `DATABRICKS_HOST` -- `DATABRICKS_TOKEN` -- `DATABRICKS_WAREHOUSE_ID` - -Explain: - -`DATABRICKS_HOST` is the workspace URL, like `https://adb-...azuredatabricks.net`. - -`DATABRICKS_TOKEN` is a Databricks personal access token. - -`DATABRICKS_WAREHOUSE_ID` is the SQL Warehouse ID. - -Use these env vars to call the Databricks SQL Statement Execution API. - -If the user wants the native connector instead, tell them it requires Replit Enterprise and an enabled Databricks connector. - -## App Requirements +## Features Build a polished full-stack web app with: -- Operations dashboard showing revenue, occupancy, average daily rate, open issues, and upcoming check-ins +- Operations dashboard: revenue, occupancy, average daily rate, open issues, upcoming check-ins - Booking queue with search, filters, status updates, issue status updates, and owner notes - Property performance table by market and property - Calendar-style upcoming arrivals and departures panel - Revenue and occupancy charts powered by SQL Warehouse queries - Genie-powered analytics panel for questions like "Which markets are underperforming?" and "Which properties have the most open issues?" -- Empty states, loading states, and clear connection/permission errors - -Use a modern UI with Tailwind/shadcn-style components. Use the Databricks palette where appropriate: - -- `#FF3621` -- `#0B2026` -- `#EEEDE9` -- `#F9F7F4` - -## Permission Handling - -If SQL fails because the connector or PAT lacks permission: - -- Explain the failed operation -- Ask whether to use an existing table, switch to read-only mode, or request Databricks permissions -- Do not silently switch to local-only storage - -The source of truth for booking and operations data should remain Databricks. +- Empty states, loading states, clear connection/permission errors ## Build Order -1. Resolve Databricks access using the connector or PAT fallback. -2. Verify warehouse access with a simple query like `SELECT current_user()`. +1. Resolve Databricks access per the general routing above. +2. Verify warehouse access with `SELECT current_user()`. 3. Ask for catalog and schema. 4. Create or verify the `vacation_rental_bookings` table. 5. Seed demo data if needed. @@ -111,9 +59,3 @@ The source of truth for booking and operations data should remain Databricks. 8. Add Genie conversational analytics when available. 9. Run the app in Replit Preview. 10. Help the user deploy with Replit Deployments. - -## Scope Notes - -This Replit template uses Databricks SQL Warehouse access through Replit's connector or PAT fallback, plus Genie when Replit's Databricks Genie integration is available. - -Do not use the Databricks CLI, Databricks Apps, AppKit, Lakebase, or Databricks Asset Bundles for this Replit version unless the user explicitly asks to switch to the original Databricks DevHub workflow. diff --git a/content/recipes/genie-conversational-analytics/replit-prompt.md b/content/recipes/genie-conversational-analytics/replit-prompt.md index 8ff88be4..90679bcd 100644 --- a/content/recipes/genie-conversational-analytics/replit-prompt.md +++ b/content/recipes/genie-conversational-analytics/replit-prompt.md @@ -1,100 +1,44 @@ # Add Genie Conversational Analytics to a Replit App -You are Replit Agent. Help the user build a Replit app with Databricks Genie conversational analytics over their Unity Catalog data. +Help the user add a Databricks Genie conversational analytics panel to a Replit app that already reads from Unity Catalog. Scope is intentionally narrow: this recipe adds the chat panel and a few small affordances around it — it does NOT build a full analytics dashboard. -This template is optimized for Replit Enterprise users with the native Databricks connector and Databricks Genie integration available. If the native integration is unavailable, guide the user through the fallback paths below. +## Data -## Before Building - -First, try to use Replit's native Databricks connector and Genie integration. Do not route from raw plan tier alone. Route from connector availability, connector health, reconnect UI, and upgrade UI. - -Follow this order: - -1. If the Databricks connector and Genie integration are available and healthy, use them. -2. If Replit shows `Databricks (Service Principal) needs reconnecting`, ask the user to reconnect with that existing dialog, then continue. -3. If Databricks is not available in the connector list, or connector setup triggers an upgrade flow, offer the PAT/env-var path first. -4. Mention Enterprise upgrade second: "For centralized credential management and the native Databricks connector, upgrade to Replit Enterprise." - -Ask only one question at a time. If asking the user to choose, always include `Not sure — help me decide`. - -## Connector And Genie Path - -Use the Databricks connector for SQL verification and table previews. Use Replit's Databricks Genie integration for conversational analytics. +Use the Databricks connector for SQL verification of the existing tables, and use Replit's Databricks Genie integration to power the chat panel. Ask for: -- Unity Catalog catalog name -- Unity Catalog schema name -- table names or Genie space to use +- which Unity Catalog catalog/schema/tables the app already reads from +- the Genie space to use for natural-language questions - SQL Warehouse, if not already configured by the connector -If the user does not already have a Genie space, ask whether they want to continue with SQL dashboard previews only, configure a Genie space in Databricks, or use the PAT fallback for direct Genie API access if available. - -## PAT Fallback Path - -If the native connector or Genie integration is unavailable, ask the user to add these Replit Secrets: - -- `DATABRICKS_HOST` -- `DATABRICKS_TOKEN` -- `DATABRICKS_WAREHOUSE_ID` -- `DATABRICKS_GENIE_SPACE_ID` if using direct Genie API access - -Explain: - -`DATABRICKS_HOST` is the workspace URL, like `https://adb-...azuredatabricks.net`. +If the user does not already have a Genie space, ask whether to continue without conversational analytics, configure a Genie space in Databricks first, or use the PAT fallback for direct Genie API access if available. -`DATABRICKS_TOKEN` is a Databricks personal access token. +## Additional Secrets -`DATABRICKS_WAREHOUSE_ID` is the SQL Warehouse ID. +If the user is on the PAT fallback path and wants direct Genie API access, also ask for: -`DATABRICKS_GENIE_SPACE_ID` is the Genie space ID to use for conversational analytics. The user can list their Genie spaces with the Databricks CLI — for example, `databricks api get /api/2.0/genie/spaces` — and copy the ID of the space they want to use. +- `DATABRICKS_GENIE_SPACE_ID` — the Genie space ID to use for conversational analytics. The user can list their Genie spaces with the Databricks CLI — for example, `databricks api get /api/2.0/genie/spaces` — and copy the ID of the space they want to use. -Use the SQL Statement Execution API for table previews and direct Genie API calls for conversations when available. +## Features -If the user wants the native connector instead, tell them it requires Replit Enterprise and an enabled Databricks connector. +Add this to the existing app: -## App Requirements +- A Genie chat panel for natural-language analytics questions over the configured tables +- Suggested-question chips generated from the selected tables (rendered above the chat input) +- SQL preview or citations beneath each Genie answer when the answer is query-backed +- Conversation history for the current session (the panel resets when the user navigates away) +- Empty state, loading state, and clear permission/error states for the panel -Build a polished full-stack web app with: - -- Data source summary showing selected catalog, schema, tables, and warehouse -- Table preview cards with row counts, freshness, and sample rows -- Genie chat panel for natural-language analytics questions -- Suggested question chips generated from the selected tables -- Conversation history in the UI for the current session -- SQL preview or citations when Genie returns query-backed answers -- Empty states, loading states, and clear connection/permission errors - -Use a modern UI with Tailwind/shadcn-style components. Use the Databricks palette where appropriate: - -- `#FF3621` -- `#0B2026` -- `#EEEDE9` -- `#F9F7F4` - -## Permission Handling - -If SQL or Genie access fails because the connector or PAT lacks permission: - -- Explain the failed operation -- Ask whether to use a different table, a different Genie space, continue with SQL-only previews, or request Databricks permissions -- Do not silently switch to local-only mock data - -The source of truth for analytics data should remain Databricks. +The panel should integrate into the existing app's layout (sidebar, modal, drawer, or dedicated route) without restyling the rest of the app. ## Build Order -1. Resolve Databricks access using the connector or PAT fallback. -2. Verify warehouse access with a simple query like `SELECT current_user()`. -3. Ask for catalog, schema, tables, and Genie space. -4. Build table previews and metadata cards. -5. Add the Genie conversational analytics panel. -6. Add suggested questions and conversation UI polish. +1. Resolve Databricks access per the general routing above. +2. Verify warehouse access with `SELECT current_user()`. +3. Ask for the existing tables and the Genie space. +4. Add the Genie chat panel component and wire it into the existing app's layout. +5. Add suggested-question chips generated from the configured tables. +6. Add SQL preview/citations beneath query-backed answers. 7. Run the app in Replit Preview. -8. Help the user deploy with Replit Deployments. - -## Scope Notes - -This Replit template uses Replit's Databricks connector and Genie integration when available. - -Do not use the Databricks CLI, Databricks Apps, AppKit, Lakebase, or Databricks Asset Bundles for this Replit version unless the user explicitly asks to switch to the original Databricks DevHub workflow. +8. Help the user verify the panel against their existing app's flow. diff --git a/content/recipes/genie-multi-space/replit-prompt.md b/content/recipes/genie-multi-space/replit-prompt.md index b5ae34a8..15629dfa 100644 --- a/content/recipes/genie-multi-space/replit-prompt.md +++ b/content/recipes/genie-multi-space/replit-prompt.md @@ -1,23 +1,8 @@ -# Build a Multi-Space Genie Analytics App on Replit +# Build a Multi-Space Genie Analytics App -You are Replit Agent. Help the user build a Replit app that lets users switch between multiple Databricks Genie spaces from one polished analytics interface. +Help the user build a Databricks-backed multi-space Genie analytics app: an internal tool that lets users switch between multiple Databricks Genie spaces from one polished interface. -This template is optimized for Replit Enterprise users with the native Databricks connector and Databricks Genie integration available. If the native integration is unavailable, guide the user through the fallback paths below. - -## Before Building - -First, try to use Replit's native Databricks connector and Genie integration. Do not route from raw plan tier alone. Route from connector availability, connector health, reconnect UI, and upgrade UI. - -Follow this order: - -1. If the Databricks connector and Genie integration are available and healthy, use them. -2. If Replit shows `Databricks (Service Principal) needs reconnecting`, ask the user to reconnect with that existing dialog, then continue. -3. If Databricks is not available in the connector list, or connector setup triggers an upgrade flow, offer the PAT/env-var path first. -4. Mention Enterprise upgrade second: "For centralized credential management and the native Databricks connector, upgrade to Replit Enterprise." - -Ask only one question at a time. If asking the user to choose, always include `Not sure — help me decide`. - -## Connector And Genie Path +## Data Use the Databricks connector for SQL verification and space context. Use Replit's Databricks Genie integration for each selected Genie space. @@ -28,29 +13,15 @@ Ask for: - Unity Catalog catalog/schema/table context for each space, if useful for previews - SQL Warehouse, if not already configured by the connector -If the user has only one Genie space, suggest starting with the Genie Conversational Analytics template instead, but continue if they want the multi-space UI. - -## PAT Fallback Path - -If the native connector or Genie integration is unavailable, ask the user to add these Replit Secrets: - -- `DATABRICKS_HOST` -- `DATABRICKS_TOKEN` -- `DATABRICKS_WAREHOUSE_ID` - -Ask the user for Genie space IDs and store them in code or secrets according to their preference. The user can list their Genie spaces with the Databricks CLI — for example, `databricks api get /api/2.0/genie/spaces` — and copy the IDs of the spaces they want to include. +If the user has only one Genie space, mention that the multi-space UI is overkill for a single space and suggest building a single-Genie-space app instead, but continue if they still want the multi-space UI. -Explain: +## Additional Secrets -`DATABRICKS_HOST` is the workspace URL, like `https://adb-...azuredatabricks.net`. +If the user is on the PAT fallback path, also ask for: -`DATABRICKS_TOKEN` is a Databricks personal access token. +- `DATABRICKS_GENIE_SPACE_IDS` — a comma-separated list of Genie space IDs to include. The user can list their Genie spaces with the Databricks CLI — for example, `databricks api get /api/2.0/genie/spaces` — and copy the IDs of the spaces they want to include. -`DATABRICKS_WAREHOUSE_ID` is the SQL Warehouse ID. - -Use direct Genie API calls when available. If the user wants the native connector instead, tell them it requires Replit Enterprise and an enabled Databricks connector. - -## App Requirements +## Features Build a polished full-stack web app with: @@ -62,27 +33,10 @@ Build a polished full-stack web app with: - Clear loading, empty, reconnect, and permission states - Responsive layout that works well on desktop and mobile -Use a modern UI with Tailwind/shadcn-style components. Use the Databricks palette where appropriate: - -- `#FF3621` -- `#0B2026` -- `#EEEDE9` -- `#F9F7F4` - -## Permission Handling - -If a Genie space fails because the connector or PAT lacks permission: - -- Explain which space failed -- Ask whether to remove that space, use a different space, continue with the remaining spaces, or request Databricks permissions -- Do not silently switch to local-only mock data - -The source of truth for analytics data and Genie space configuration should remain Databricks. - ## Build Order -1. Resolve Databricks access using the connector or PAT fallback. -2. Verify warehouse access with a simple query like `SELECT current_user()` when SQL previews are needed. +1. Resolve Databricks access per the general routing above. +2. Verify warehouse access with `SELECT current_user()` when SQL previews are needed. 3. Ask for Genie spaces, display names, and optional table context. 4. Build the multi-space selector and page shell. 5. Wire each space to the Genie chat panel. @@ -90,8 +44,6 @@ The source of truth for analytics data and Genie space configuration should rema 7. Run the app in Replit Preview. 8. Help the user deploy with Replit Deployments. -## Scope Notes - -This Replit template uses Replit's Databricks connector and Genie integration when available. +## Notes -Do not use the Databricks CLI, Databricks Apps, AppKit, Lakebase, or Databricks Asset Bundles for this Replit version unless the user explicitly asks to switch to the original Databricks DevHub workflow. +For multi-space failures: also offer to remove the failing space or continue with the remaining spaces (in addition to the standard "use a different space" option from the preamble's permission handling). diff --git a/content/recipes/medallion-architecture-from-cdc/replit-prompt.md b/content/recipes/medallion-architecture-from-cdc/replit-prompt.md index fc655d9f..7c35d874 100644 --- a/content/recipes/medallion-architecture-from-cdc/replit-prompt.md +++ b/content/recipes/medallion-architecture-from-cdc/replit-prompt.md @@ -1,25 +1,10 @@ -# Build a Medallion Analytics App from CDC Tables with Databricks on Replit +# Build a Medallion Analytics App from CDC Tables -You are Replit Agent. Help the user build a Replit app over Databricks medallion tables produced from CDC history: a dashboard for exploring current-state silver tables and aggregated gold tables. +Help the user build a Databricks-backed medallion analytics app: a dashboard for exploring current-state silver tables and aggregated gold tables sourced from CDC history. -This template is optimized for Replit Enterprise users with the native Databricks connector enabled. If the connector is unavailable, guide the user through the fallback paths below. +## Data -## Before Building - -First, try to use Replit's native Databricks connector. Do not route from raw plan tier alone. Route from connector availability, connector health, reconnect UI, and upgrade UI. - -Follow this order: - -1. If the Databricks connector is available and healthy, use it. -2. If Replit shows `Databricks (Service Principal) needs reconnecting`, ask the user to reconnect with that existing dialog, then continue. -3. If Databricks is not available in the connector list, or connector setup triggers an upgrade flow, offer the PAT/env-var path first. -4. Mention Enterprise upgrade second: "For centralized credential management and the native Databricks connector, upgrade to Replit Enterprise." - -Ask only one question at a time. If asking the user to choose, always include `Not sure — help me decide`. - -## Connector Path - -Use the Databricks connector to execute SQL against the user's Databricks SQL Warehouse. +Use the Databricks connector (or PAT fallback) to execute SQL against the user's SQL Warehouse. Ask for: @@ -30,27 +15,7 @@ Ask for: If the user does not have medallion tables yet, offer to create demo silver and gold tables so the app can run immediately. -## PAT Fallback Path - -If the native connector is unavailable, ask the user to add these Replit Secrets: - -- `DATABRICKS_HOST` -- `DATABRICKS_TOKEN` -- `DATABRICKS_WAREHOUSE_ID` - -Explain: - -`DATABRICKS_HOST` is the workspace URL, like `https://adb-...azuredatabricks.net`. - -`DATABRICKS_TOKEN` is a Databricks personal access token. - -`DATABRICKS_WAREHOUSE_ID` is the SQL Warehouse ID. - -Use these env vars to call the Databricks SQL Statement Execution API. - -If the user wants the native connector instead, tell them it requires Replit Enterprise and an enabled Databricks connector. - -## App Requirements +## Features Build a polished full-stack web app with: @@ -60,29 +25,12 @@ Build a polished full-stack web app with: - Data freshness and pipeline status cards based on table timestamps - SQL query inspector showing the silver and gold queries used by the app - Genie-powered analytics panel for questions like "What changed most recently?" and "Which aggregates changed the most this week?" -- Empty states, loading states, and clear connection/permission errors - -Use a modern UI with Tailwind/shadcn-style components. Use the Databricks palette where appropriate: - -- `#FF3621` -- `#0B2026` -- `#EEEDE9` -- `#F9F7F4` - -## Permission Handling - -If SQL fails because the connector or PAT lacks permission: - -- Explain the failed operation -- Ask whether to use existing tables, switch to read-only mode, or request Databricks permissions -- Do not silently switch to local-only storage - -The source of truth for CDC-derived data should remain Databricks. +- Empty states, loading states, clear connection/permission errors ## Build Order -1. Resolve Databricks access using the connector or PAT fallback. -2. Verify warehouse access with a simple query like `SELECT current_user()`. +1. Resolve Databricks access per the general routing above. +2. Verify warehouse access with `SELECT current_user()`. 3. Ask for catalog, silver table, and gold table. 4. Inspect available columns and timestamp fields. 5. Create demo silver/gold tables only if the user wants a sandbox. @@ -92,8 +40,6 @@ The source of truth for CDC-derived data should remain Databricks. 9. Run the app in Replit Preview. 10. Help the user deploy with Replit Deployments. -## Scope Notes - -This Replit template visualizes medallion tables that already exist, or demo tables created through SQL. +## Notes -It does not create Lakeflow Declarative Pipelines, Lakehouse Sync, CDC replication, or Databricks Asset Bundles unless the user explicitly asks to switch to the original Databricks DevHub workflow. +This template visualizes medallion tables that already exist, or demo tables created through SQL. It does not create Lakeflow Declarative Pipelines, Lakehouse Sync, or CDC replication for this Replit version. diff --git a/content/recipes/volume-file-upload/replit-prompt.md b/content/recipes/volume-file-upload/replit-prompt.md index e4d6c8a1..4eafe58f 100644 --- a/content/recipes/volume-file-upload/replit-prompt.md +++ b/content/recipes/volume-file-upload/replit-prompt.md @@ -1,24 +1,8 @@ -# Build a Unity Catalog Volume File Manager with Databricks on Replit +# Build a Unity Catalog Volume File Manager -You are Replit Agent. Help the user build a Databricks-backed file manager for Unity Catalog Volumes: an internal app for browsing files, uploading documents, downloading assets, previewing metadata, and tracking file activity. +Help the user build a Databricks-backed file manager for Unity Catalog Volumes: an internal app for browsing files, uploading documents, downloading assets, previewing metadata, and tracking file activity. -This template is optimized for Replit users who can access Databricks from Replit. The native Databricks connector is useful for SQL metadata and analytics, but Unity Catalog Volume file operations may require Databricks PAT/env-var access. - -## Before Building - -First, try to use Replit's native Databricks connector. Do not route from raw plan tier alone. Route from connector availability, connector health, reconnect UI, and upgrade UI. - -Follow this order: - -1. If the Databricks connector is available and healthy, use it for SQL verification and metadata queries. -2. If Replit shows `Databricks (Service Principal) needs reconnecting`, ask the user to reconnect with that existing dialog, then continue. -3. For Unity Catalog Volume file operations, ask the user to add PAT/env vars if the native integration cannot perform Volume file API calls. -4. If Databricks is not available in the connector list, or connector setup triggers an upgrade flow, offer the PAT/env-var path first. -5. Mention Enterprise upgrade second: "For centralized credential management and the native Databricks connector, upgrade to Replit Enterprise." - -Ask only one question at a time. If asking the user to choose, always include `Not sure — help me decide`. - -## Connector Path +## Data Use the Databricks connector to verify warehouse access and query file metadata tables if the user has them. @@ -45,30 +29,7 @@ CREATE TABLE IF NOT EXISTS ..volume_file_activity ( ); ``` -## PAT Fallback Path - -For Unity Catalog Volume file operations, ask the user to add these Replit Secrets: - -- `DATABRICKS_HOST` -- `DATABRICKS_TOKEN` - -If SQL analytics are needed through the REST fallback, also ask for: - -- `DATABRICKS_WAREHOUSE_ID` - -Explain: - -`DATABRICKS_HOST` is the workspace URL, like `https://adb-...azuredatabricks.net`. - -`DATABRICKS_TOKEN` is a Databricks personal access token with permission to access the target Unity Catalog Volume. - -`DATABRICKS_WAREHOUSE_ID` is the SQL Warehouse ID used for optional metadata and activity queries. - -Use the Databricks Files API or Workspace/Volumes API pattern available for Unity Catalog Volumes. Use the SQL Statement Execution API only for metadata tables and analytics. - -If the user wants the native connector instead, tell them it requires Replit Enterprise and an enabled Databricks connector, but Volume file operations may still require PAT access depending on connector capabilities. - -## App Requirements +## Features Build a polished full-stack web app with: @@ -79,33 +40,11 @@ Build a polished full-stack web app with: - File preview panel for text, JSON, CSV, markdown, and image files when practical - Metadata/activity dashboard showing file counts, total bytes, recent uploads, file types, and actor activity when the metadata table is enabled - Genie-powered analytics panel for questions like "Which file types are growing fastest?" and "Who uploaded the most files this week?" when Genie integration is available and metadata is tracked -- Empty states, loading states, reconnect states, and clear permission errors - -Use a modern UI with Tailwind/shadcn-style components. Use the Databricks palette where appropriate: - -- `#FF3621` -- `#0B2026` -- `#EEEDE9` -- `#F9F7F4` - -## Permission Handling - -If Volume file operations fail: - -- Explain whether the failure happened during list, upload, download, delete, or preview -- Ask whether to use a different volume, continue in read-only mode, add PAT access, or request Databricks permissions -- Do not silently switch to local file storage - -If SQL metadata queries fail: - -- Keep direct file browsing functional if PAT file access works -- Ask whether to skip analytics, use an existing metadata table, or request SQL permissions - -The source of truth for files should remain Unity Catalog Volumes. +- Empty states, loading states, reconnect states, clear permission errors ## Build Order -1. Resolve Databricks access using the connector and/or PAT fallback. +1. Resolve Databricks access per the general routing above. 2. Verify workspace access. 3. Ask for catalog, schema, and volume. 4. Verify the Volume path can be listed. @@ -117,8 +56,10 @@ The source of truth for files should remain Unity Catalog Volumes. 10. Run the app in Replit Preview. 11. Help the user deploy with Replit Deployments. -## Scope Notes +## Notes + +**Access.** Unity Catalog Volume file operations usually require PAT access even when the Databricks connector is otherwise healthy. `DATABRICKS_TOKEN` must have permission on the target Volume. Use the Databricks Files API or Workspace/Volumes API for Volume operations; reserve the SQL Statement Execution API for the optional metadata table and analytics. -This Replit template manages files in Unity Catalog Volumes. The native Databricks connector should be used when available for SQL and metadata analytics, but direct Volume file operations may require PAT/env-var access. +**Volume operation failures.** If list/upload/download/delete/preview fails, explain which operation failed and ask whether to use a different volume, continue in read-only mode, add PAT access, or request Databricks permissions. -Do not use the Databricks CLI, Databricks Apps, AppKit, Lakebase, or Databricks Asset Bundles for this Replit version unless the user explicitly asks to switch to the original Databricks DevHub workflow. +**Metadata query failures.** If SQL metadata queries fail but file operations still work, keep the file browser functional and ask whether to skip analytics, use an existing metadata table, or request SQL permissions. diff --git a/content/replit-shared/preamble.md b/content/replit-shared/preamble.md new file mode 100644 index 00000000..2cb4fb39 --- /dev/null +++ b/content/replit-shared/preamble.md @@ -0,0 +1,52 @@ +You are Replit Agent. The user wants to build a Databricks-backed app on Replit, described in the task below. + +## Before Building + +First, try to use Replit's native Databricks integrations (the Databricks connector for SQL, and the Databricks Genie integration for conversational analytics where applicable). Do not route from raw plan tier alone. Route from integration availability, integration health, reconnect UI, and upgrade UI. + +Follow this order: + +1. If the relevant Databricks integrations are available and healthy, use them. +2. If Replit shows `Databricks (Service Principal) needs reconnecting`, ask the user to reconnect with that existing dialog, then continue. +3. If a needed Databricks API isn't reachable through the connector (e.g. Unity Catalog Volume file operations), fall back to PAT/env-var access for that API. +4. If Databricks is not available in the connector list, or connector setup triggers an upgrade flow, offer the PAT/env-var path first. +5. Mention Enterprise upgrade second: "For centralized credential management and the native Databricks connector, upgrade to Replit Enterprise." + +Ask only one question at a time. If asking the user to choose, always include `Not sure — help me decide`. + +## PAT Fallback Path + +If the native connector is unavailable, ask the user to add these Replit Secrets: + +- `DATABRICKS_HOST` — the workspace URL, like `https://adb-...azuredatabricks.net` +- `DATABRICKS_TOKEN` — a Databricks personal access token +- `DATABRICKS_WAREHOUSE_ID` — the SQL Warehouse ID + +If the per-template task below lists any "Additional Secrets", ask the user for those too. + +Use these env vars to call the relevant Databricks REST APIs (e.g. SQL Statement Execution, Genie, Volume Files). + +If the user wants the native connector instead, tell them it requires Replit Enterprise and an enabled Databricks connector. + +## Permission Handling + +If a Databricks call fails because the connector or PAT lacks permission: + +- Explain the failed operation +- Ask whether to use a different table/space/volume, switch to read-only mode, or request Databricks permissions +- Do not silently switch to local-only mock data or storage + +The source of truth for the data, files, and analytics this app shows should remain Databricks. + +## Style + +Use a modern UI with Tailwind/shadcn-style components. Use the Databricks palette where appropriate: + +- `#FF3621` +- `#0B2026` +- `#EEEDE9` +- `#F9F7F4` + +## Out of Scope + +Do not use the Databricks CLI, Databricks Apps, AppKit, Lakebase, or Databricks Asset Bundles for this Replit version unless the user explicitly asks to switch to the original Databricks DevHub workflow. diff --git a/src/lib/content-markdown.ts b/src/lib/content-markdown.ts index 87cdc243..333d3ae3 100644 --- a/src/lib/content-markdown.ts +++ b/src/lib/content-markdown.ts @@ -110,9 +110,21 @@ export function readCookbookGoal( type ReplitPromptTier = "recipes" | "examples" | "cookbooks"; /** - * Reads `content///replit-prompt.md` if present. Replit prompts - * are an opt-in export target, not a content section, so they live next to - * `goal.md` but stay out of `ContentSections` / `readContentSections`. + * Reads `content///replit-prompt.md` if present, prepended with + * the shared `content/replit-shared/preamble.md` separated by `---`. This + * mirrors the "shared boilerplate + per-template body" composition that + * `composeAgentPrompt` uses for the Copy prompt feature: each per-template + * file holds only the unique task; universal routing, PAT fallback, + * permission handling, style, and out-of-scope rules live in the preamble. + * + * Replit prompts are an opt-in export target, not a content section, so + * they live next to `goal.md` but stay out of `ContentSections` / + * `readContentSections`. + * + * Composition order: + * + * --- + * */ export function readReplitPrompt( rootDir: string, @@ -123,9 +135,24 @@ export function readReplitPrompt( tier === "cookbooks" ? cookbookDirectory(rootDir) : markdownDirectory(rootDir, tier); - const filePath = resolve(dir, slug, "replit-prompt.md"); - if (!existsSync(filePath)) return undefined; - return readFileSync(filePath, "utf-8"); + const perTemplatePath = resolve(dir, slug, "replit-prompt.md"); + if (!existsSync(perTemplatePath)) return undefined; + + const preamblePath = resolve( + rootDir, + "content", + "replit-shared", + "preamble.md", + ); + if (!existsSync(preamblePath)) { + throw new Error( + `Required shared file missing: ${preamblePath}. ` + + `Every replit-prompt.md composes against this preamble; restore the file or remove the per-template prompts.`, + ); + } + const preamble = readFileSync(preamblePath, "utf-8").trimEnd(); + const perTemplate = readFileSync(perTemplatePath, "utf-8").trimEnd(); + return `${preamble}\n\n---\n\n${perTemplate}\n`; } /** Reads all present section files; throws when goal.md is missing. */ diff --git a/tests/e2e/open-prompt-in.spec.ts b/tests/e2e/open-prompt-in.spec.ts index 88f80874..54556bc2 100644 --- a/tests/e2e/open-prompt-in.spec.ts +++ b/tests/e2e/open-prompt-in.spec.ts @@ -1,7 +1,6 @@ import { test, expect, type Page } from "@playwright/test"; -import { readFileSync } from "node:fs"; -import { resolve } from "node:path"; import { decompressFromEncodedURIComponent } from "lz-string"; +import { readReplitPrompt } from "../../src/lib/content-markdown"; // Playwright is run from the repo root (per package.json scripts and CI). const REPO_ROOT = process.cwd(); @@ -67,15 +66,17 @@ test.describe("Open prompt in dropdown", () => { expect(encoded).toBeTruthy(); // End-to-end roundtrip: the prompt Replit Agent will see after decoding - // must equal the on-disk replit-prompt.md byte-for-byte. Catches any - // future regression in lz-string encoding, the plugin pipeline, the - // useReplitPrompt aggregator, or the buildReplitUrl helper. + // must equal the COMPOSED replit-prompt (shared preamble + --- + + // per-template task) byte-for-byte. Catches any future regression in + // lz-string encoding, the plugin pipeline, the useReplitPrompt + // aggregator, the buildReplitUrl helper, or the preamble composition. const decoded = decompressFromEncodedURIComponent(encoded!); - const onDisk = readFileSync( - resolve(REPO_ROOT, "content/examples/saas-tracker/replit-prompt.md"), - "utf-8", - ); - expect(decoded).toBe(onDisk); + const composed = readReplitPrompt(REPO_ROOT, "examples", "saas-tracker"); + expect( + composed, + "saas-tracker should ship a replit-prompt.md", + ).toBeTruthy(); + expect(decoded).toBe(composed); }); test("does not render on a template without a replit-prompt.md", async ({ diff --git a/tests/replit-prompt-composition.test.ts b/tests/replit-prompt-composition.test.ts new file mode 100644 index 00000000..6aa205d0 --- /dev/null +++ b/tests/replit-prompt-composition.test.ts @@ -0,0 +1,118 @@ +import { + mkdtempSync, + mkdirSync, + writeFileSync, + rmSync, + unlinkSync, +} from "node:fs"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; +import { afterEach, beforeEach, describe, expect, test } from "vitest"; +import { readReplitPrompt } from "../src/lib/content-markdown"; + +/** + * Seeds a tempdir with a tiny content/ tree and exercises readReplitPrompt's + * preamble + --- + per-template composition contract. + */ +function seedFixture(root: string, files: Record): void { + for (const [relativePath, contents] of Object.entries(files)) { + const filePath = join(root, relativePath); + mkdirSync(join(filePath, ".."), { recursive: true }); + writeFileSync(filePath, contents, "utf-8"); + } +} + +const PREAMBLE = "shared preamble body"; + +describe("readReplitPrompt composition", () => { + let workDir: string; + + beforeEach(() => { + workDir = mkdtempSync(join(tmpdir(), "devhub-replit-compose-")); + seedFixture(workDir, { + "content/replit-shared/preamble.md": PREAMBLE, + }); + }); + + afterEach(() => { + rmSync(workDir, { recursive: true, force: true }); + }); + + test("returns undefined when the per-template file is missing", () => { + expect(readReplitPrompt(workDir, "examples", "missing")).toBe(undefined); + }); + + test("composes preamble + --- + per-template task in fixed order", () => { + seedFixture(workDir, { + "content/examples/demo/replit-prompt.md": "# Task\n\nDo the thing.", + }); + + expect(readReplitPrompt(workDir, "examples", "demo")).toBe( + "shared preamble body\n\n---\n\n# Task\n\nDo the thing.\n", + ); + }); + + test("starts with the preamble's opening line", () => { + seedFixture(workDir, { + "content/examples/demo/replit-prompt.md": "task", + }); + const composed = readReplitPrompt(workDir, "examples", "demo"); + expect(composed?.startsWith(PREAMBLE)).toBe(true); + }); + + test("contains exactly one '---' separator between preamble and task", () => { + seedFixture(workDir, { + "content/examples/demo/replit-prompt.md": "task line one\ntask line two", + }); + const composed = readReplitPrompt(workDir, "examples", "demo"); + expect(composed).toBeTruthy(); + expect(composed!.match(/^---$/gm)?.length).toBe(1); + }); + + test("ends with the per-template task body followed by a trailing newline", () => { + seedFixture(workDir, { + "content/recipes/demo/replit-prompt.md": "## Task\n\nFinal line of task.", + }); + const composed = readReplitPrompt(workDir, "recipes", "demo"); + expect(composed?.endsWith("Final line of task.\n")).toBe(true); + }); + + test("works across all three tiers (examples, recipes, cookbooks)", () => { + seedFixture(workDir, { + "content/examples/ex/replit-prompt.md": "example task", + "content/recipes/rc/replit-prompt.md": "recipe task", + "content/cookbooks/ck/replit-prompt.md": "cookbook task", + }); + + expect(readReplitPrompt(workDir, "examples", "ex")).toContain( + "example task", + ); + expect(readReplitPrompt(workDir, "recipes", "rc")).toContain("recipe task"); + expect(readReplitPrompt(workDir, "cookbooks", "ck")).toContain( + "cookbook task", + ); + }); + + test("trims trailing whitespace from both files before joining", () => { + seedFixture(workDir, { + "content/replit-shared/preamble.md": "preamble\n\n\n", + "content/examples/demo/replit-prompt.md": "task\n\n\n\n", + }); + expect(readReplitPrompt(workDir, "examples", "demo")).toBe( + "preamble\n\n---\n\ntask\n", + ); + }); + + test("throws a clear error when the shared preamble is missing", () => { + // Per-template file exists, but preamble was deleted — should fail loud + // with a useful message rather than an opaque ENOENT. + unlinkSync(join(workDir, "content/replit-shared/preamble.md")); + seedFixture(workDir, { + "content/examples/orphan/replit-prompt.md": "task", + }); + + expect(() => readReplitPrompt(workDir, "examples", "orphan")).toThrow( + /Required shared file missing.*preamble\.md/, + ); + }); +}); From 1da3ba559fea23fd33a97b89496428df6493b3aa Mon Sep 17 00:00:00 2001 From: Tony Dang Date: Mon, 1 Jun 2026 17:51:34 -0700 Subject: [PATCH 4/4] feat(templates): add "Build with > Replit" filter on templates index MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds a sidebar filter under a new "Build with" section that narrows the templates grid to entries with a Replit prompt (content///replit-prompt.md). Derived from plugin data via a new useReplitTemplateIds() hook — no separate registry flag; authors only need to drop a replit-prompt.md next to their goal.md and it shows up in the filter automatically. UI: - New "Build with > Replit" checkbox in the sidebar, positioned after Services - Removable "Replit" chip in the active-filters bar (Databricks red, matches the existing services-chip styling) - Participates in the mobile filter badge count and Clear all Tests: - Two new e2e cases in tests/e2e/resources-filters.spec.ts: - Checking "Replit" narrows the grid to templates with a replit prompt and shows a removable chip - The Replit filter participates in Clear all --- src/components/templates/active-filters.tsx | 22 +++++++++- src/components/templates/template-filters.tsx | 19 +++++++++ src/lib/use-raw-content-markdown.ts | 31 ++++++++++++++ src/pages/templates/index.tsx | 37 +++++++++++++---- tests/e2e/resources-filters.spec.ts | 40 +++++++++++++++++++ 5 files changed, 141 insertions(+), 8 deletions(-) diff --git a/src/components/templates/active-filters.tsx b/src/components/templates/active-filters.tsx index 4557f46a..f3eb0981 100644 --- a/src/components/templates/active-filters.tsx +++ b/src/components/templates/active-filters.tsx @@ -7,20 +7,40 @@ export function ActiveFilters({ onRemoveTag, selectedServices, onRemoveService, + replitOnly, + onRemoveReplitOnly, onClearAll, }: { activeTags: Set; onRemoveTag: (tag: string) => void; selectedServices: Set; onRemoveService: (service: Service) => void; + replitOnly: boolean; + onRemoveReplitOnly: () => void; onClearAll: () => void; }) { - const hasFilters = activeTags.size > 0 || selectedServices.size > 0; + const hasFilters = + activeTags.size > 0 || selectedServices.size > 0 || replitOnly; if (!hasFilters) return null; return (
+ {replitOnly && ( + + )} {[...selectedServices].map((service) => (
+
+

+ Build with +

+
+ +
+
); } diff --git a/src/lib/use-raw-content-markdown.ts b/src/lib/use-raw-content-markdown.ts index 8139e0d7..d798e561 100644 --- a/src/lib/use-raw-content-markdown.ts +++ b/src/lib/use-raw-content-markdown.ts @@ -78,3 +78,34 @@ export function useReplitPrompt(slug: string): string | undefined { cookbooks.replitPromptsBySlug?.[slug] ); } + +/** + * Set of every template slug that ships a `replit-prompt.md`. Powers the + * "Build with > Replit Apps" filter on /templates. Derived from plugin + * data so authors only need to drop a `replit-prompt.md` next to their + * `goal.md` — no separate registry flag to maintain. + */ +export function useReplitTemplateIds(): ReadonlySet { + const examples = usePluginData( + "docusaurus-plugin-content-entries", + "examples", + ) as ContentEntriesGlobalData; + const recipes = usePluginData( + "docusaurus-plugin-content-entries", + "recipes", + ) as ContentEntriesGlobalData; + const cookbooks = usePluginData( + "docusaurus-plugin-cookbooks", + ) as CookbooksGlobalData; + const ids = new Set(); + for (const slug of Object.keys(examples.replitPromptsBySlug ?? {})) { + ids.add(slug); + } + for (const slug of Object.keys(recipes.replitPromptsBySlug ?? {})) { + ids.add(slug); + } + for (const slug of Object.keys(cookbooks.replitPromptsBySlug ?? {})) { + ids.add(slug); + } + return ids; +} diff --git a/src/pages/templates/index.tsx b/src/pages/templates/index.tsx index 8ce6793b..cc650c50 100644 --- a/src/pages/templates/index.tsx +++ b/src/pages/templates/index.tsx @@ -29,6 +29,7 @@ import { type Service, } from "@/lib/recipes/recipes"; import { useFeatureFlags } from "@/lib/feature-flags"; +import { useReplitTemplateIds } from "@/lib/use-raw-content-markdown"; function OfficialTemplatesCallout(): ReactNode { return ( @@ -101,9 +102,11 @@ export default function TemplatesPage(): ReactNode { new Set(), ); const [activeTags, setActiveTags] = useState>(new Set()); + const [replitOnly, setReplitOnly] = useState(false); const [mobileFiltersOpen, setMobileFiltersOpen] = useState(false); const { showDrafts: includeDrafts } = useFeatureFlags(); + const replitTemplateIds = useReplitTemplateIds(); const ALL_ITEMS = useMemo( () => buildTemplateItems(includeDrafts), @@ -112,14 +115,22 @@ export default function TemplatesPage(): ReactNode { const filteredItems = useMemo( () => - ALL_ITEMS.filter((item) => - matchesTemplateFilter(item.data, { + ALL_ITEMS.filter((item) => { + if (replitOnly && !replitTemplateIds.has(item.data.id)) return false; + return matchesTemplateFilter(item.data, { searchQuery, selectedServices, activeTags, - }), - ), - [searchQuery, selectedServices, activeTags, ALL_ITEMS], + }); + }), + [ + searchQuery, + selectedServices, + activeTags, + replitOnly, + replitTemplateIds, + ALL_ITEMS, + ], ); const handleToggleService = useCallback((service: Service) => { @@ -139,18 +150,26 @@ export default function TemplatesPage(): ReactNode { }); }, []); + const handleToggleReplitOnly = useCallback(() => { + setReplitOnly((prev) => !prev); + }, []); + const handleClearAllFilters = useCallback(() => { setSelectedServices(new Set()); setActiveTags(new Set()); setSearchQuery(""); + setReplitOnly(false); }, []); - const hasActiveFilters = activeTags.size > 0 || selectedServices.size > 0; + const hasActiveFilters = + activeTags.size > 0 || selectedServices.size > 0 || replitOnly; const filtersSidebar = ( ); @@ -199,7 +218,9 @@ export default function TemplatesPage(): ReactNode { Filters {hasActiveFilters && ( - {selectedServices.size + activeTags.size} + {selectedServices.size + + activeTags.size + + (replitOnly ? 1 : 0)} )} @@ -216,6 +237,8 @@ export default function TemplatesPage(): ReactNode { onRemoveTag={handleRemoveTag} selectedServices={selectedServices} onRemoveService={handleToggleService} + replitOnly={replitOnly} + onRemoveReplitOnly={handleToggleReplitOnly} onClearAll={handleClearAllFilters} />
diff --git a/tests/e2e/resources-filters.spec.ts b/tests/e2e/resources-filters.spec.ts index 6d62fe07..e987c9d2 100644 --- a/tests/e2e/resources-filters.spec.ts +++ b/tests/e2e/resources-filters.spec.ts @@ -151,3 +151,43 @@ test.describe("templates page clear all filters", () => { await expect(page.getByRole("button", { name: "Clear all" })).toBeHidden(); }); }); + +test.describe("templates page Build-with Replit filter", () => { + test("checking 'Replit' narrows the grid to templates with a replit prompt and shows a removable chip", async ({ + page, + }) => { + await page.goto("/templates"); + await expect(page.getByText(TOTAL_TEMPLATES)).toBeVisible(); + + await page.getByRole("checkbox", { name: "Replit", exact: true }).check(); + + // saas-tracker ships a replit-prompt.md, so it should still be visible. + await expect( + page.locator('a[href="/templates/saas-tracker"]'), + ).toBeVisible(); + // set-up-your-local-dev-environment does NOT ship one, so it should hide. + await expect( + page.locator('a[href="/templates/set-up-your-local-dev-environment"]'), + ).toBeHidden(); + + // The active-filters chip should appear and clicking it should turn the + // filter back off. + const chip = page.getByRole("button", { name: /^Replit$/ }); + await expect(chip).toBeVisible(); + await chip.click(); + await expect(page.getByText(TOTAL_TEMPLATES)).toBeVisible(); + }); + + test("Build-with Replit filter participates in 'Clear all'", async ({ + page, + }) => { + await page.goto("/templates"); + + await page.getByRole("checkbox", { name: "Replit", exact: true }).check(); + await expect(page.getByRole("button", { name: "Clear all" })).toBeVisible(); + + await page.getByRole("button", { name: "Clear all" }).click(); + await expect(page.getByText(TOTAL_TEMPLATES)).toBeVisible(); + await expect(page.getByRole("button", { name: "Clear all" })).toBeHidden(); + }); +});