Add a search source
Make your module's records, cards or pages show up in the global search palette, grouped under their own heading.
- Register a source in
src/server/search-source.ts. It reuses your module's own search and applies its own access checks:
Buildimport { registerSearchSource } from "@monark/common"; import { requireOrg } from "@monark/organizations/server"; import { requirePermission } from "@monark/rbac/server"; export function registerPostsSearchSource(): void { registerSearchSource({ module: "posts", groupId: "posts", label: "Posts", run: async (ctx, query, limit) => { if (!ctx.userId) return []; const org = await requireOrg({ userId: ctx.userId, activeOrganizationId: ctx.activeOrganizationId }); await requirePermission(ctx, "posts.view", org.id); const posts = await searchPosts(org.id, query); return posts.slice(0, limit).map((p) => ({ id: p.id, title: p.title, href: `/posts/${p.id}` })); }, }); }hrefon the server. Add asubtitlefor context, such as the board a card is on. - Call the helper in
services/api/src/server.ts, in the search-sources block. The order there is the order of groups in the palette. - Add the group's heading,
globalSearch.groups.posts, to every catalog inservices/web/src/messages/. - Add an icon for the group to the icon map in
services/web/src/components/global-search/global-search-dialog.tsx. - Open the palette in the app and type part of a title. Your hits appear under their heading.
Good to know:
- A source that fails or is denied doesn't break the palette; the other groups still show.
- A module with a page also needs a navigation entry; that entry makes the page reachable by name in the palette too.