diff --git a/messages/en-US.json b/messages/en-US.json index e6567cc08..cf32d15fd 100644 --- a/messages/en-US.json +++ b/messages/en-US.json @@ -1626,6 +1626,7 @@ "commandBilling": "Billing", "commandEnterpriseLicenses": "Licenses", "commandSettings": "Settings", + "commandSearchResults": "Search Results", "alertingTitle": "Alerting", "alertingDescription": "Define sources, triggers, and actions for notifications", "alertingRules": "Alert rules", diff --git a/src/components/command-palette/CommandPalette.tsx b/src/components/command-palette/CommandPalette.tsx index 726d1c999..816c83fb3 100644 --- a/src/components/command-palette/CommandPalette.tsx +++ b/src/components/command-palette/CommandPalette.tsx @@ -15,6 +15,15 @@ import { } from "@app/components/ui/command"; import { cn } from "@app/lib/cn"; import { ListUserOrgsResponse } from "@server/routers/org"; +import { + ChevronRightIcon, + GlobeIcon, + GlobeLockIcon, + LaptopIcon, + PlugIcon, + ServerIcon, + UserIcon +} from "lucide-react"; import { useTranslations } from "next-intl"; import { useRouter } from "next/navigation"; import React, { @@ -28,7 +37,7 @@ import React, { import { useCommandPaletteActions } from "./useCommandPaletteActions"; import { useCommandPaletteNavigation } from "./useCommandPaletteNavigation"; import { useCommandPaletteSearch } from "./useCommandPaletteSearch"; -import { search } from "jmespath"; +import { resources } from "@server/db"; type CommandPaletteProps = { orgId?: string; @@ -54,12 +63,21 @@ export function CommandPalette({ orgId, orgs, navItems }: CommandPaletteProps) { const navigationGroups = useCommandPaletteNavigation(navItems); // const organizations = useCommandPaletteOrganizations(orgs); const actions = useCommandPaletteActions(orgId, orgs); - const { shouldSearch, sites, resources, users, machineClients, isLoading } = - useCommandPaletteSearch({ - orgId, - query: search.substring(1), - enabled: open && isActionMode - }); + const { + shouldSearch, + sites, + publicResources, + privateResources, + users, + machineClients, + userDevices, + isLoading, + hasResults: hasEntityResults + } = useCommandPaletteSearch({ + orgId, + query: search, + enabled: !isActionMode && open + }); const handleOpenChange = useCallback( (nextOpen: boolean) => { @@ -80,15 +98,9 @@ export function CommandPalette({ orgId, orgs, navItems }: CommandPaletteProps) { [setOpen] ); - // const hasEntityResults = - // sites.length > 0 || - // resources.length > 0 || - // users.length > 0 || - // machineClients.length > 0; - return ( - + {t("commandPaletteNoResults")} {!isActionMode && - navigationGroups.map((group, groupIndex) => { - console.log({ - groupIndex, - groupHeading: group.heading - }); - return ( - - {groupIndex > 0 && } - 0 && - "[&_[cmdk-group-heading]]:pt-3" - )} - > - {group.items.map((item) => ( - - runCommand(() => - router.push(item.href) - ) - } - className="h-9" - > - {item.icon} - {item.title} - - ))} - - - ); - })} + navigationGroups.map((group, groupIndex) => ( + + {groupIndex > 0 && } + 0 && + "[&_[cmdk-group-heading]]:pt-3" + )} + > + {group.items.map((item) => ( + + runCommand(() => + router.push(item.href) + ) + } + className="h-9" + > + {item.icon} + {item.title} + + ))} + + + ))} {/* {organizations.length > 1 && ( <> @@ -200,118 +206,157 @@ export function CommandPalette({ orgId, orgs, navItems }: CommandPaletteProps) { )} */} - {/* {shouldSearch && orgId && ( - <> - - {isLoading && !hasEntityResults ? ( -
- - {t("commandPaletteSearching")} -
- ) : ( - <> - {sites.length > 0 && ( - - {sites.map((site) => ( - - runCommand(() => - router.push(site.href) - ) - } - > - - {site.name} - - - ))} - - )} - {resources.length > 0 && ( - - {resources.map((resource) => ( - - runCommand(() => - router.push( - resource.href - ) - ) - } - > - - {resource.name} - - - ))} - - )} - {users.length > 0 && ( - - {users.map((user) => ( - - runCommand(() => - router.push(user.href) - ) - } - > -
- - {user.name} - - - {user.email} - -
-
- ))} -
- )} - {machineClients.length > 0 && ( - - {machineClients.map((client) => ( - - runCommand(() => - router.push(client.href) - ) - } - > - - {client.name} - - - ))} - - )} - + {!isActionMode && shouldSearch && orgId && hasEntityResults && ( + - )} */} + > + {sites.map((site) => ( + + runCommand(() => router.push(site.href)) + } + className="h-9" + > +
+ + + {t("commandSites")} + + + + {site.name} + +
+
+ ))} + {publicResources.map((resource) => ( + + runCommand(() => router.push(resource.href)) + } + className="h-9" + > +
+ + + {t("commandProxyResources")} + + + + {resource.name} + +
+
+ ))} + {privateResources.map((resource) => ( + + runCommand(() => router.push(resource.href)) + } + className="h-9" + > +
+ + + {t("commandClientResources")} + + + + {resource.name} + +
+
+ ))} + {users.map((user) => ( + + runCommand(() => router.push(user.href)) + } + className="h-9" + > +
+ + + {t("commandUsers")} + + +
+ + {user.name} + + + · + + + {user.email} + +
+
+
+ ))} + {machineClients.map((client) => ( + + runCommand(() => router.push(client.href)) + } + className="h-9" + > +
+ + + {t("commandMachineClients")} + + + + {client.name} + +
+
+ ))} + {userDevices.map((device) => ( + + runCommand(() => router.push(device.href)) + } + className="h-9" + > +
+ + + {t("commandUserDevices")} + + + + {device.name} + +
+
+ ))} +
+ )} {isActionMode && actions.length > 0 && ( <> - {actions.map((action) => ( {action.icon} {action.label} @@ -387,7 +433,7 @@ export function CommandPaletteProvider({ orgs, navItems }: CommandPaletteProviderProps) { - const [open, setOpen] = useState(false); + const [open, setOpen] = useState(true); // FIXME: should be set to `false` by default, this is temporary const toggle = useCallback(() => { setOpen((current) => !current); diff --git a/src/components/command-palette/useCommandPaletteSearch.ts b/src/components/command-palette/useCommandPaletteSearch.ts index 984892354..7471438d5 100644 --- a/src/components/command-palette/useCommandPaletteSearch.ts +++ b/src/components/command-palette/useCommandPaletteSearch.ts @@ -47,7 +47,14 @@ export function useCommandPaletteSearch({ const shouldSearch = enabled && !!orgId && trimmedQuery.length >= MIN_QUERY_LENGTH; - const [sitesQuery, resourcesQuery, usersQuery, clientsQuery] = useQueries({ + const [ + sitesQuery, + proxyResourcesQuery, + privateResourcesQuery, + usersQuery, + clientsQuery, + userDevicesQuery + ] = useQueries({ queries: [ { ...orgQueries.sites({ @@ -58,7 +65,15 @@ export function useCommandPaletteSearch({ enabled: shouldSearch }, { - ...orgQueries.resources({ + ...orgQueries.proxyResources({ + orgId: orgId ?? "", + query: trimmedQuery, + perPage: SEARCH_PER_PAGE + }), + enabled: shouldSearch + }, + { + ...orgQueries.privateResources({ orgId: orgId ?? "", query: trimmedQuery, perPage: SEARCH_PER_PAGE @@ -80,6 +95,14 @@ export function useCommandPaletteSearch({ perPage: SEARCH_PER_PAGE }), enabled: shouldSearch + }, + { + ...orgQueries.userDevices({ + orgId: orgId ?? "", + query: trimmedQuery, + perPage: SEARCH_PER_PAGE + }), + enabled: shouldSearch } ] }); @@ -93,14 +116,23 @@ export function useCommandPaletteSearch({ })); }, [orgId, sitesQuery.data]); - const resources = useMemo((): ResourceSearchResult[] => { - if (!orgId || !resourcesQuery.data) return []; - return resourcesQuery.data.map((resource) => ({ + const publicResources = useMemo((): ResourceSearchResult[] => { + if (!orgId || !proxyResourcesQuery.data) return []; + return proxyResourcesQuery.data.map((resource) => ({ id: `resource-${resource.resourceId}`, name: resource.name, href: `/${orgId}/settings/resources/proxy/${resource.niceId}` })); - }, [orgId, resourcesQuery.data]); + }, [orgId, proxyResourcesQuery.data]); + + const privateResources = useMemo((): ResourceSearchResult[] => { + if (!orgId || !privateResourcesQuery.data) return []; + return privateResourcesQuery.data.map((resource) => ({ + id: `site-resource-${resource.siteResourceId}`, + name: resource.name, + href: `/${orgId}/settings/resources/private?query=${resource.name}` + })); + }, [orgId, privateResourcesQuery.data]); const users = useMemo((): UserSearchResult[] => { if (!orgId || !usersQuery.data) return []; @@ -123,20 +155,44 @@ export function useCommandPaletteSearch({ })); }, [orgId, clientsQuery.data]); + const userDevices = useMemo((): ClientSearchResult[] => { + if (!orgId || !userDevicesQuery.data) return []; + return userDevicesQuery.data + .filter((client) => !client.userId) + .map((client) => ({ + id: `client-${client.clientId}`, + name: client.name, + href: `/${orgId}/settings/clients/user/${client.niceId}` + })); + }, [orgId, userDevicesQuery.data]); + const isLoading = shouldSearch && (sitesQuery.isFetching || - resourcesQuery.isFetching || + proxyResourcesQuery.isFetching || + privateResourcesQuery.isFetching || usersQuery.isFetching || + userDevicesQuery.isFetching || clientsQuery.isFetching); + const hasResults = + sites.length > 0 || + publicResources.length > 0 || + users.length > 0 || + privateResources.length > 0 || + userDevices.length > 0 || + machineClients.length > 0; + return { debouncedQuery: trimmedQuery, shouldSearch, sites, - resources, + publicResources, + privateResources, users, machineClients, - isLoading + userDevices, + isLoading, + hasResults }; }