{"templateId":"markdown","sharedDataIds":{},"props":{"metadata":{"markdoc":{"tagList":["ConnectorCatalog"]},"type":"markdown"},"seo":{"title":"Marketplace navigation and searchable catalog — design","siteUrl":"https://developers.frontegg.com/","llmstxt":{"title":"Frontegg Developer Documentation","description":"Authentication, authorization, and user management for Customer Identity, plus Agen for SaaS and Agen for Work. Guides, SDKs, and API references.","sections":[{"title":"Customer Identity (CIAM)","description":"Auth, SSO, SCIM, entitlements, and user management — guides, SDKs, and APIs.","includeFiles":["ciam/**/*.md"],"excludeFiles":[]},{"title":"Agen for SaaS","description":"Agentic access and authorization for SaaS products.","includeFiles":["agen-for-saas/**/*.md"],"excludeFiles":[]},{"title":"Agen for Work","description":"Agentic access and authorization for internal and workforce use.","includeFiles":["agen-for-work/**/*.md"],"excludeFiles":[]},{"title":"Platform","description":"Shared platform overview.","includeFiles":["platform/**/*.md"],"excludeFiles":[]}],"excludeFiles":["internal-docs/**","ciam/guides/env-settings/inject-client-ip.md","CLAUDE.md",".claude/**","**/images/**"],"hide":false}},"dynamicMarkdocComponents":[],"compilationErrors":[],"ast":{"$$mdtype":"Tag","name":"article","attributes":{},"children":[{"$$mdtype":"Tag","name":"Heading","attributes":{"level":1,"id":"marketplace-navigation-and-searchable-catalog--design","__idx":0},"children":["Marketplace navigation and searchable catalog — design"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Date:"]}," 2026-05-13"," ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Area:"]}," ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["agen-for-work/connectors/"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["@theme/"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["scripts/"]}," ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Type:"]}," Documentation IA + tooling addition"]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"problem","__idx":1},"children":["Problem"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["agen-for-work/connectors/marketplace/"]}," contains 96 integration guides. They are"," ","all listed alphabetically as a flat list inside the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["Marketplace"]}," group in"," ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["agen-for-work/sidebars.yaml"]}," (lines 53–268), producing a 96-item \"wall of"," ","text\" in the sidebar."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["For a user who knows the integration they need (\"find Slack\"), this is slow:"," ","scroll an unsegmented list of 96 items, or use the global Redocly search and"," ","hope it ranks the connector page first. For a user evaluating coverage (\"do you"," ","support any CRM?\"), there is no overview by domain — they cannot scan"," ","categories."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The product UI already groups connectors by category (see"," ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["agen-for-work/sources/overview.md"]}," and the Marketplace tab → Category dropdown"," ","in-product), but no such structure exists in documentation."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"goals","__idx":2},"children":["Goals"]},{"$$mdtype":"Tag","name":"ol","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Reorganize the sidebar so the 96-item flat list becomes 22 collapsible"," ","category groups, collapsed by default; Redocly auto-expands the group of"," ","the active page."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Introduce a single landing page ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["agen-for-work/connectors/marketplace.md"]}," ","that renders a searchable, category-sectioned catalog of all connectors."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Reuse the authoritative category taxonomy that exists in the dashboard"," ","codebase (",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["ConnectorCategory"]}," enum and ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["IntegrationCategoryMap"]}," in"," ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["dashboard/app/v2/src/tools/stores/envStore/workforceApp/workforceApp.types.ts"]},"),"," ","so docs and product agree on category names without ad-hoc curation."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Make the catalog data derive from per-file frontmatter (single source of"," ","truth in each connector's markdown), regenerated to a TypeScript data file"," ","by an explicit ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["npm run generate:connectors"]}," step."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Add CI validation so a connector cannot be added without a valid category."]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"non-goals","__idx":3},"children":["Non-goals"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["No icon or logo assets per integration. The docs repo has none today"," ","(",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["static/"]}," contains only Frontegg logos and one stray ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["slack.svg"]},"); sourcing"," ","and licensing 96 third-party brand assets is a separate project."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["No per-connector ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["description:"]}," on tiles. Names alone suffice for the"," ","\"knows the name\" path; descriptions can be added later as another optional"," ","frontmatter field."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["No equivalent catalog for ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["ciam/"]}," or ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["agen-for-saas/"]},". If this pattern"," ","works, replicate it there afterwards."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["No localization. Catalog UI strings (\"Search 96 connectors…\", \"All"," ","categories\", \"No connectors match your search\") are English."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["No live sync with the dashboard repo. We copy the taxonomy into docs once"," ","(via bootstrap) and treat docs frontmatter as the source of truth thereafter."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["No e2e or visual-regression tests. Smoke verification via ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["npm run dev"]}," ","preview is enough for v1."]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"design","__idx":4},"children":["Design"]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"1-frontmatter-schema","__idx":5},"children":["1. Frontmatter schema"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Today none of the 96 marketplace markdown files have any frontmatter — they"," ","start straight with ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["## Connector_name integration"]},". The bootstrap (Phase 2)"," ","adds a frontmatter block to every file:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"yaml","header":{"controls":{"copy":{}}},"source":"---\ncategory: Communication                  # NEW — required, string from enum\ndisplayName: Slack                       # NEW — optional, overrides humanized filename\n---\n","lang":"yaml"},"children":[]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["category"]}," must be one of the 30 strings in ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["ConnectorCategory"]}," (in dashboard"," ","enum) — values like ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["Productivity"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["Communication"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["Project Management"]},","," ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["CRM"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["Development"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["Storage"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["Finance"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["Customer Support"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["Marketing"]},","," ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["E-commerce"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["Analytics"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["Monitoring"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["DevOps"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["HR"]},","," ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["Video Conferencing"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["Scheduling"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["Identity"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["Design"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["Forms"]},","," ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["IT Service Management"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["Documents"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["Automation"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["Data"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["Social Media"]},","," ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["Feature Flags"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["Content Management"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["Sales Intelligence"]},","," ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["Product Management"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["Infrastructure"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["AI"]},". (Only 22 of these are"," ","populated by current docs.)"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["displayName"]}," overrides the filename-derived label (e.g. ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["monday"]}," →"," ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["monday.com"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["bamboohr"]}," → ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["BambooHR"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["microsoft-todo"]}," → ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["Microsoft To Do"]},")."]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["A one-time bootstrap script reads the dashboard's ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["IntegrationCategoryMap"]}," and"," ","inserts ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["category"]}," into all 96 files. After that, frontmatter is hand-maintained."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"2-source-of-truth--category-enum","__idx":6},"children":["2. Source of truth — category enum"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The 30 categories live in"," ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["dashboard/app/v2/src/tools/stores/envStore/workforceApp/workforceApp.types.ts"]}," ","as the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["ConnectorCategory"]}," enum. We copy the enum verbatim (string values only)"," ","into a small file in this repo so the validator and component can reference it"," ","without depending on the dashboard package:"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["@theme/markdoc/components/ConnectorCatalog/categories.ts"]},":"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"typescript","header":{"controls":{"copy":{}}},"source":"export const CONNECTOR_CATEGORIES = [\n  'Productivity',\n  'Communication',\n  'Project Management',\n  // ... 27 more, in the same order as the dashboard enum\n] as const\n\nexport type ConnectorCategory = (typeof CONNECTOR_CATEGORIES)[number]\n","lang":"typescript"},"children":[]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Order is the enum's source order; this is also the order used by sidebar groups"," ","and on the landing page."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"3-generator--scriptsgenerate-connectorsmjs","__idx":7},"children":["3. Generator — ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["scripts/generate-connectors.mjs"]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Inputs: ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["agen-for-work/connectors/marketplace/*.md"]},"."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Outputs: ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["@theme/markdoc/components/ConnectorCatalog/connectors.generated.ts"]},","," ","shape:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"typescript","header":{"controls":{"copy":{}}},"source":"import type { ConnectorCategory } from './categories'\n\nexport interface ConnectorEntry {\n  id: string            // filename without .md, e.g. 'slack'\n  name: string          // displayName from frontmatter, or humanized id\n  category: ConnectorCategory\n  href: string          // 'connectors/marketplace/slack.md'\n}\n\nexport const CONNECTORS: ConnectorEntry[] = [/* generated */]\n","lang":"typescript"},"children":[]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Behavior:"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Reads each markdown, extracts frontmatter via ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["gray-matter"]}," (already"," ","available via Redocly toolchain — confirm during phase 0, otherwise add the"," ","dep)."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Validates each file has ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["category"]}," and that it is in"," ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["CONNECTOR_CATEGORIES"]},"; fails the run otherwise."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Sorts entries by ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["(category index in CONNECTOR_CATEGORIES, name)"]},"."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Writes the data file with a ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["// AUTO-GENERATED — do not edit"]}," header."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Idempotent: running twice produces identical output."]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The script is exposed as ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["npm run generate:connectors"]}," in ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["package.json"]},"."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"4-ci-freshness-check--scriptscheck-marketplace-frontmattermjs","__idx":8},"children":["4. CI freshness check — ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["scripts/check-marketplace-frontmatter.mjs"]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Exposed as ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["npm run check:marketplace-frontmatter"]},". Pattern matches the existing"," ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["check:content-style"]}," script: a standalone Node script invoked separately"," ","(not bundled into ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["npm run test"]},", which is reserved for ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["redocly lint"]},"). CI"," ","runs all three checks (",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["test"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["check:content-style"]},","," ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["check:marketplace-frontmatter"]},") and fails on any."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Responsibilities:"]},{"$$mdtype":"Tag","name":"ol","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Re-run the generator into an in-memory string."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Compare against the committed ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["connectors.generated.ts"]},". Fail with a clear"," ","message if they differ: ",{"$$mdtype":"Tag","name":"em","attributes":{},"children":["\"connectors.generated.ts is stale — run"," ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["npm run generate:connectors"]}," and commit the result.\""]}]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Validate that every file in ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["agen-for-work/connectors/marketplace/*.md"]},":",{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["has ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["category"]}," in frontmatter;"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["category"]}," is in ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["CONNECTOR_CATEGORIES"]},";"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["is referenced exactly once in ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["agen-for-work/sidebars.yaml"]},"."]}]}]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Validate that every entry under the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["Marketplace"]}," group in ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["sidebars.yaml"]}," ","points to a file that exists on disk."]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["No new tooling beyond ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["gray-matter"]}," and ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["js-yaml"]}," (the latter likely already"," ","present for Redocly config parsing — verify in phase 0)."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"5-react-component--thememarkdoccomponentsconnectorcatalog","__idx":9},"children":["5. React component — ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["@theme/markdoc/components/ConnectorCatalog/"]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Files:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"header":{"controls":{"copy":{}}},"source":"ConnectorCatalog/\n├── ConnectorCatalog.tsx         # React component (styled-components)\n├── ConnectorCatalog.markdoc.ts  # Markdoc schema (no attributes)\n├── categories.ts                # CONNECTOR_CATEGORIES, ConnectorCategory type\n├── connectors.generated.ts      # generated, committed\n└── index.ts                     # barrel export\n"},"children":[]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Registered in ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["@theme/markdoc/components.tsx"]}," and ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["@theme/markdoc/schema.ts"]}," ","following the existing ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["ProductCard"]}," pattern."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Component behavior:"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Imports ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["CONNECTORS"]}," from ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["connectors.generated.ts"]}," and ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["CONNECTOR_CATEGORIES"]}," ","from ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["categories.ts"]},". No props."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Internal state: ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["query: string"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["category: 'all' | ConnectorCategory"]},"."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Top bar (sticky? no — keep simple): search input"," ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["aria-label=\"Search connectors\""]}," and a ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["<select>"]}," populated from the"," ","categories that are actually present in ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["CONNECTORS"]}," (skip empty ones), in"," ","enum order, prefixed by an ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["All categories"]}," option."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Body:",{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["No filters active"]}," (default): render an ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["<h3>"]}," section per category"," ","that has entries, followed by a grid of tiles. Tiles are plain"," ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["<a href={connector.href}>"]}," with the connector name centered."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Search input non-empty"]},": collapse all sections into one alphabetically"," ","sorted flat grid of matches. Match is case-insensitive substring on"," ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["name"]},"."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Category dropdown set"]},": render only that one category's section (still"," ","show the H3 for context)."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Both active"]},": filter by category, then by query, render as a flat"," ","grid under one H3."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Empty result"]},": show ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["<p>No connectors match your search.</p>"]}," followed"," ","by a ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["Clear filters"]}," button that resets both state values."]}]}]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Styling matches ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["ProductCard"]}," conventions (",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["styled-components"]},","," ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["var(--icon-card-*)"]}," theme variables). Tile is a bordered rounded box with"," ","hover state; grid uses CSS ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["grid-template-columns: repeat(auto-fill, minmax(160px, 1fr))"]},"."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["No animations beyond the standard 0.2s border-color transition on hover."]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The Markdoc tag has zero attributes:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"typescript","header":{"controls":{"copy":{}}},"source":"export const ConnectorCatalog: Schema & { tagName: string } = {\n  attributes: {},\n  render: 'ConnectorCatalog',\n  tagName: 'ConnectorCatalog',\n}\n","lang":"typescript"},"children":[]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Usage in markdown: ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["{% ConnectorCatalog /%}"]},"."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"6-new-landing-page--agen-for-workconnectorsmarketplacemd","__idx":10},"children":["6. New landing page — ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["agen-for-work/connectors/marketplace.md"]}]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"markdown","header":{"controls":{"copy":{}}},"source":"---\ntitle: Marketplace\n---\n\n## Marketplace\n\nBrowse all available connectors. Use the search field to find a connector by\nname, or filter by category.\n\n","lang":"markdown"},"children":[]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Heading rules from ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["scripts/check-content-style.mjs"]}," are respected (first H2,"," ","no H1, no emojis)."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"7-sidebar-restructure--agen-for-worksidebarsyaml","__idx":11},"children":["7. Sidebar restructure — ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["agen-for-work/sidebars.yaml"]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The current flat ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["Marketplace"]}," group (one ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["items:"]}," block with 96 entries) is"," ","replaced by a ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["Marketplace"]}," group whose ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["page:"]}," is the new landing and whose"," ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["items:"]}," is a list of 22 category subgroups, in enum order:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"yaml","header":{"controls":{"copy":{}}},"source":"- group: Marketplace\n  page: connectors/marketplace.md\n  expanded: false\n  items:\n    - group: Productivity\n      expanded: false\n      items:\n        - label: Airtable\n          page: connectors/marketplace/airtable.md\n        - label: Confluence\n          page: connectors/marketplace/confluence.md\n        # … alphabetical within group\n    - group: Communication\n      expanded: false\n      items:\n        - label: Discord\n          page: connectors/marketplace/discord.md\n        # …\n    # … 20 more category subgroups in enum order\n","lang":"yaml"},"children":[]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Within each category, items are alphabetical by ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["label"]},". Category groups appear"," ","in ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["CONNECTOR_CATEGORIES"]}," order. Categories with no docs entries are omitted."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Redocly Realm auto-expands the group containing the active page, so no custom"," ","behaviour is needed for the \"collapsed-but-active-group-open\" UX."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"8-updates-to-existing-pages","__idx":12},"children":["8. Updates to existing pages"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["agen-for-work/sources/overview.md"]}," — keep as-is. The Marketplace section"," ","there describes the product UI; the new landing page describes the docs"," ","catalog. They co-exist without overlap."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["No changes to the 96 connector markdown files beyond the new frontmatter"," ","fields. Body content is untouched."]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"9-execution-phases-one-pr-atomic-commits","__idx":13},"children":["9. Execution phases (one PR, atomic commits)"]},{"$$mdtype":"Tag","name":"ol","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Phase 0 — verify deps."]}," Confirm ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["gray-matter"]}," and ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["js-yaml"]}," are"," ","available in the toolchain; add them as devDependencies if not."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Phase 1 — taxonomy + generator + validator."]}," Add ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["categories.ts"]},","," ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["scripts/generate-connectors.mjs"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["scripts/check-marketplace-frontmatter.mjs"]},"."," ","Add ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["generate:connectors"]}," and ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["check:marketplace-frontmatter"]}," to"," ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["package.json"]}," scripts (each standalone, matching the existing"," ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["check:content-style"]}," pattern)."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Phase 2 — bootstrap frontmatter."]}," One-shot script that reads"," ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["IntegrationCategoryMap"]}," from the dashboard repo (path supplied via env"," ","var) and writes ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["category:"]}," into all 96 markdown files. The script lives"," ","in ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["scripts/bootstrap-connector-categories.mjs"]}," and is deleted after the"," ","PR merges (one-time use)."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Phase 3 — component."]}," Add ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["ConnectorCatalog.tsx"]},","," ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["ConnectorCatalog.markdoc.ts"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["index.ts"]},"; register in"," ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["@theme/markdoc/components.tsx"]}," and ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["schema.ts"]},"."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Phase 4 — landing page."]}," Add ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["agen-for-work/connectors/marketplace.md"]},"."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Phase 5 — sidebar restructure."]}," Replace the flat list in"," ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["agen-for-work/sidebars.yaml"]}," with category subgroups."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Phase 6 — generate + commit data file."]}," Run"," ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["npm run generate:connectors"]},", commit ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["connectors.generated.ts"]},"."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Phase 7 — validation."]}," ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["npm run test"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["npm run check:content-style"]},","," ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["npm run dev"]}," smoke-check."]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"validation","__idx":14},"children":["Validation"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["npm run test"]}," — Redocly lint. Must pass."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["npm run check:content-style"]}," — unchanged rules; new ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["marketplace.md"]}," and"," ","any other touched markdown must pass."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["npm run check:marketplace-frontmatter"]}," — new validator. Must pass."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Local smoke (",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["npm run dev"]},"):",{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["/agen-for-work/connectors/marketplace"]}," renders the catalog with 96 tiles"," ","distributed across 22 H3 sections, in enum order."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Typing in the search input filters tiles live, with no flicker."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Selecting a category in the dropdown narrows to that section."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Empty result state appears for nonsense queries."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Sidebar shows ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["Marketplace"]}," collapsed; expanding shows 22 collapsed"," ","subgroups; clicking any connector auto-expands its category group."]}]}]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"open-risks","__idx":15},"children":["Open risks"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["gray-matter"]},"/",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["js-yaml"]}," availability."]}," Either is a small dep, but if"," ","Redocly's Markdoc pipeline strips them at runtime we may need to bundle"," ","frontmatter parsing into the generator only (which runs at dev time, so this"," ","is fine). Resolve in Phase 0."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Bootstrap reliability."]}," The bootstrap script depends on a sibling"," ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["dashboard/"]}," checkout at a known relative path. Document the env var"," ","(",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["DASHBOARD_REPO=/path/to/dashboard"]},") in the script. If the path is wrong,"," ","fail loud."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Category drift."]}," Once docs frontmatter is the source of truth, future"," ","dashboard renames are not auto-propagated. The validator only checks"," ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["CONNECTOR_CATEGORIES"]},", so an out-of-date ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["categories.ts"]}," will silently"," ","diverge from product. Mitigation: include a comment in ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["categories.ts"]}," ","pointing at the dashboard file and a date stamp; refresh manually when product"," ","changes are announced."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Sidebar diff size."]}," Replacing 216 lines of flat YAML with a nested"," ","structure makes the PR diff noisy. Acceptable cost; review by reading the"," ","rendered preview rather than the YAML diff."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Search performance."]}," 96 entries × substring match is trivial; no"," ","debouncing or indexing needed. If the catalog grows past ~500, revisit."]}]}]},"headings":[{"value":"Marketplace navigation and searchable catalog — design","id":"marketplace-navigation-and-searchable-catalog--design","depth":1},{"value":"Problem","id":"problem","depth":2},{"value":"Goals","id":"goals","depth":2},{"value":"Non-goals","id":"non-goals","depth":2},{"value":"Design","id":"design","depth":2},{"value":"1. Frontmatter schema","id":"1-frontmatter-schema","depth":3},{"value":"2. Source of truth — category enum","id":"2-source-of-truth--category-enum","depth":3},{"value":"3. Generator — scripts/generate-connectors.mjs","id":"3-generator--scriptsgenerate-connectorsmjs","depth":3},{"value":"4. CI freshness check — scripts/check-marketplace-frontmatter.mjs","id":"4-ci-freshness-check--scriptscheck-marketplace-frontmattermjs","depth":3},{"value":"5. React component — @theme/markdoc/components/ConnectorCatalog/","id":"5-react-component--thememarkdoccomponentsconnectorcatalog","depth":3},{"value":"6. New landing page — agen-for-work/connectors/marketplace.md","id":"6-new-landing-page--agen-for-workconnectorsmarketplacemd","depth":3},{"value":"7. Sidebar restructure — agen-for-work/sidebars.yaml","id":"7-sidebar-restructure--agen-for-worksidebarsyaml","depth":3},{"value":"8. Updates to existing pages","id":"8-updates-to-existing-pages","depth":3},{"value":"9. Execution phases (one PR, atomic commits)","id":"9-execution-phases-one-pr-atomic-commits","depth":3},{"value":"Validation","id":"validation","depth":2},{"value":"Open risks","id":"open-risks","depth":2}],"frontmatter":{"seo":{"title":"Marketplace navigation and searchable catalog — design"}},"lastModified":"2026-05-19T15:06:34.000Z","pagePropGetterError":{"message":"","name":""}},"slug":"/docs/superpowers/specs/2026-05-13-marketplace-search-design","userData":{"isAuthenticated":false,"teams":["anonymous"]},"isPublic":true}