Skip to content

Commit

Permalink
Improve keyboard nav with poke search
Browse files Browse the repository at this point in the history
  • Loading branch information
Fraggle committed Nov 29, 2024
1 parent 150c14f commit c48476d
Show file tree
Hide file tree
Showing 16 changed files with 311 additions and 261 deletions.
22 changes: 20 additions & 2 deletions front/components/UserMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,11 @@ import {
import { useSendNotification } from "@dust-tt/sparkle";
import type { UserType, WorkspaceType } from "@dust-tt/types";
import { isOnlyAdmin, isOnlyBuilder, isOnlyUser } from "@dust-tt/types";
import { BugIcon } from "lucide-react";
import { useRouter } from "next/router";
import { useMemo } from "react";

import { canForceUserRole, forceUserRole } from "@app/lib/development";
import { forceUserRole, showDebugTools } from "@app/lib/development";
import { useFeatureFlags } from "@app/lib/swr/workspaces";

export function UserMenu({
Expand All @@ -28,6 +30,7 @@ export function UserMenu({
user: UserType;
owner: WorkspaceType;
}) {
const router = useRouter();
const { featureFlags } = useFeatureFlags({ workspaceId: owner.sId });

const hasBetaAccess = featureFlags.some((flag: string) =>
Expand Down Expand Up @@ -92,9 +95,24 @@ export function UserMenu({
</>
)}

{canForceUserRole(owner) && (
{showDebugTools(owner) && (
<>
<DropdownMenuLabel label="Dev Tools" />
{router.route === "/w/[wId]/assistant/[cId]" && (
<DropdownMenuItem
label="Debug conversation"
onClick={() => {
const regexp = new RegExp(`/w/([^/]+)/assistant/([^/]+)`);
const match = window.location.href.match(regexp);
if (match) {
void router.push(
`/poke/${match[1]}/conversations/${match[2]}`
);
}
}}
icon={BugIcon}
/>
)}
{!isOnlyAdmin(owner) && (
<DropdownMenuItem
label="Become Admin"
Expand Down
20 changes: 0 additions & 20 deletions front/components/assistant/conversation/ConversationTitle.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,11 @@ import {
} from "@dust-tt/sparkle";
import type { ConversationType } from "@dust-tt/types";
import type { WorkspaceType } from "@dust-tt/types";
import { isDevelopment } from "@dust-tt/types";
import { BugIcon } from "lucide-react";
import { useRouter } from "next/router";
import type { MouseEvent } from "react";
import React, { useRef, useState } from "react";
import { useSWRConfig } from "swr";

import { ConversationParticipants } from "@app/components/assistant/conversation/ConversationParticipants";
import { isADustProdWorkspace } from "@app/lib/development";
import { classNames } from "@app/lib/utils";

export function ConversationTitle({
Expand All @@ -35,7 +31,6 @@ export function ConversationTitle({
shareLink: string;
onDelete?: (conversationId: string) => void;
}) {
const router = useRouter();
const { mutate } = useSWRConfig();

const [copyLinkSuccess, setCopyLinkSuccess] = useState<boolean>(false);
Expand Down Expand Up @@ -194,21 +189,6 @@ export function ConversationTitle({
/>
)}
</div>
{(isDevelopment() || isADustProdWorkspace(owner)) && (
<div className="hidden lg:flex">
<Button
size="sm"
variant="ghost"
tooltip="Debug in Poke"
icon={BugIcon}
onClick={() =>
void router.push(
`/poke/${conversation.owner.sId}/conversations/${conversation.sId}`
)
}
/>
</div>
)}
<Popover
popoverTriggerAsChild
trigger={
Expand Down
96 changes: 62 additions & 34 deletions front/components/poke/PokeNavbar.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { Button, Logo } from "@dust-tt/sparkle";
import { Button, Logo, Spinner } from "@dust-tt/sparkle";
import { isDevelopment } from "@dust-tt/types";
import Link from "next/link";
import { useEffect, useState } from "react";
import { useRouter } from "next/navigation";
import { useCallback, useEffect, useState } from "react";

import { PokeButton } from "@app/components/poke/shadcn/ui/button";
import {
Expand Down Expand Up @@ -37,70 +38,97 @@ export const PokeNavbar: React.FC = () => (
export default PokeNavbar;

export function PokeSearchCommand() {
const router = useRouter();
const [open, setOpen] = useState(false);
const [searchTerm, setSearchTerm] = useState("");
const [isNavigating, setIsNavigating] = useState(false);

const { isError, isLoading, results } = usePokeSearch({
// Disable search until the user has typed at least 2 characters.
disabled: searchTerm.length < 2,
search: searchTerm,
});

const navigateTo = useCallback(
async (link: string) => {
setIsNavigating(true);
await router.push(link);
setIsNavigating(false);
},
[router]
);

useEffect(() => {
const down = (e: KeyboardEvent) => {
if (e.key === "k" && (e.metaKey || e.ctrlKey)) {
e.preventDefault();
setOpen((open) => !open);
} else if (
open &&
results.length > 0 &&
e.key === "Enter" &&
results[0].link
) {
e.preventDefault();
void navigateTo(results[0].link);
}
};
document.addEventListener("keydown", down);
return () => document.removeEventListener("keydown", down);
}, []);
}, [navigateTo, open, results]);

return (
<>
<PokeButton variant="outline" size="sm" onClick={() => setOpen(true)}>
Search
Search (⌘K)
</PokeButton>
<PokeCommandDialog
open={open}
onOpenChange={setOpen}
className="bg-structure-50 sm:max-w-[600px]"
shouldFilter={false}
>
<PokeCommandInput
placeholder="Type a command or search..."
onValueChange={(value) => setSearchTerm(value)}
className="border-none focus:outline-none focus:ring-0"
/>
<PokeCommandList>
{isLoading && <div className="p-4 text-sm">Searching...</div>}
{searchTerm &&
searchTerm.length >= 2 &&
!isError &&
!isLoading &&
results.length === 0 && (
<div className="p-4 text-sm">No results found.</div>
)}
{isError && <div className="p-4 text-sm">Something went wrong.</div>}
{searchTerm.length < 2 && (
<div className="p-4 text-sm">Enter at least 2 characters...</div>
)}
{isNavigating ? (
<div className="m-4 flex items-center justify-center">
<Spinner size="md" />
</div>
) : (
<>
<PokeCommandInput
placeholder="Type a command or search..."
onValueChange={(value) => setSearchTerm(value)}
className="border-none focus:outline-none focus:ring-0"
/>
<PokeCommandList>
{isLoading && <div className="p-4 text-sm">Searching...</div>}
{searchTerm &&
searchTerm.length >= 2 &&
!isError &&
!isLoading &&
results.length === 0 && (
<div className="p-4 text-sm">No results found.</div>
)}
{isError && (
<div className="p-4 text-sm">Something went wrong.</div>
)}
{searchTerm.length < 2 && (
<div className="p-4 text-sm">
Enter at least 2 characters...
</div>
)}

{results.map(({ id, link, name }) =>
link ? (
<Link href={link} key={id}>
<PokeCommandItem value={name}>
{results.map(({ id, link, name }) => (
<PokeCommandItem
key={id}
value={name}
onClick={() => (link ? navigateTo(link) : null)}
>
{name} (id: {id})
</PokeCommandItem>
</Link>
) : (
<PokeCommandItem key={id} value={name}>
{name} (id: {id})
</PokeCommandItem>
)
)}
</PokeCommandList>
))}
</PokeCommandList>
</>
)}
</PokeCommandDialog>
</>
);
Expand Down
Loading

0 comments on commit c48476d

Please sign in to comment.