aboutsummaryrefslogtreecommitdiffstats
path: root/apps/web/components/dashboard/lists/EditListModal.tsx
diff options
context:
space:
mode:
authorMohamed Bassem <me@mbassem.com>2025-01-02 13:00:58 +0200
committerGitHub <noreply@github.com>2025-01-02 13:00:58 +0200
commit5ecdc36b7d60aa66b49e01e9fec8ba61ad537376 (patch)
tree57577822bb104b95900ba577a265fb4f8cf70b78 /apps/web/components/dashboard/lists/EditListModal.tsx
parent5df0258b2cd884347eabfa866d7e7fbc7225cdb3 (diff)
downloadkarakeep-5ecdc36b7d60aa66b49e01e9fec8ba61ad537376.tar.zst
feat: Add support for smart lists (#802)
* feat: Add support for smart lists * i18n * Fix update list endpoint * Add a test for smart lists * Add header to the query explainer * Hide remove from lists in the smart context list * Add proper validation to list form --------- Co-authored-by: Deepak Kapoor <41769111+orthdron@users.noreply.github.com>
Diffstat (limited to 'apps/web/components/dashboard/lists/EditListModal.tsx')
-rw-r--r--apps/web/components/dashboard/lists/EditListModal.tsx119
1 files changed, 96 insertions, 23 deletions
diff --git a/apps/web/components/dashboard/lists/EditListModal.tsx b/apps/web/components/dashboard/lists/EditListModal.tsx
index d66d7096..98bb19be 100644
--- a/apps/web/components/dashboard/lists/EditListModal.tsx
+++ b/apps/web/components/dashboard/lists/EditListModal.tsx
@@ -25,6 +25,13 @@ import {
PopoverContent,
PopoverTrigger,
} from "@/components/ui/popover";
+import {
+ Select,
+ SelectContent,
+ SelectItem,
+ SelectTrigger,
+ SelectValue,
+} from "@/components/ui/select";
import { toast } from "@/components/ui/use-toast";
import { useTranslation } from "@/lib/i18n/client";
import data from "@emoji-mart/data";
@@ -38,7 +45,10 @@ import {
useCreateBookmarkList,
useEditBookmarkList,
} from "@hoarder/shared-react/hooks/lists";
-import { ZBookmarkList } from "@hoarder/shared/types/lists";
+import {
+ ZBookmarkList,
+ zNewBookmarkListSchema,
+} from "@hoarder/shared/types/lists";
import { BookmarkListSelector } from "./BookmarkListSelector";
@@ -46,13 +56,13 @@ export function EditListModal({
open: userOpen,
setOpen: userSetOpen,
list,
- parent,
+ prefill,
children,
}: {
open?: boolean;
setOpen?: (v: boolean) => void;
list?: ZBookmarkList;
- parent?: ZBookmarkList;
+ prefill?: Partial<Omit<ZBookmarkList, "id">>;
children?: React.ReactNode;
}) {
const { t } = useTranslation();
@@ -64,17 +74,14 @@ export function EditListModal({
throw new Error("You must provide both open and setOpen or neither");
}
const [customOpen, customSetOpen] = useState(false);
- const formSchema = z.object({
- name: z.string(),
- icon: z.string(),
- parentId: z.string().nullish(),
- });
- const form = useForm<z.infer<typeof formSchema>>({
- resolver: zodResolver(formSchema),
+ const form = useForm<z.infer<typeof zNewBookmarkListSchema>>({
+ resolver: zodResolver(zNewBookmarkListSchema),
defaultValues: {
- name: list?.name ?? "",
- icon: list?.icon ?? "🚀",
- parentId: list?.parentId ?? parent?.id,
+ name: list?.name ?? prefill?.name ?? "",
+ icon: list?.icon ?? prefill?.icon ?? "🚀",
+ parentId: list?.parentId ?? prefill?.parentId,
+ type: list?.type ?? prefill?.type ?? "manual",
+ query: list?.query ?? prefill?.query ?? undefined,
},
});
const [open, setOpen] = [
@@ -84,9 +91,11 @@ export function EditListModal({
useEffect(() => {
form.reset({
- name: list?.name ?? "",
- icon: list?.icon ?? "🚀",
- parentId: list?.parentId ?? parent?.id,
+ name: list?.name ?? prefill?.name ?? "",
+ icon: list?.icon ?? prefill?.icon ?? "🚀",
+ parentId: list?.parentId ?? prefill?.parentId,
+ type: list?.type ?? prefill?.type ?? "manual",
+ query: list?.query ?? prefill?.query ?? undefined,
});
}, [open]);
@@ -154,14 +163,24 @@ export function EditListModal({
}
},
});
+ const listType = form.watch("type");
+
+ useEffect(() => {
+ if (listType !== "smart") {
+ form.resetField("query");
+ }
+ }, [listType]);
const isEdit = !!list;
const isPending = isCreating || isEditing;
- const onSubmit = form.handleSubmit((value: z.infer<typeof formSchema>) => {
- value.parentId = value.parentId === "" ? null : value.parentId;
- isEdit ? editList({ ...value, listId: list.id }) : createList(value);
- });
+ const onSubmit = form.handleSubmit(
+ (value: z.infer<typeof zNewBookmarkListSchema>) => {
+ value.parentId = value.parentId === "" ? null : value.parentId;
+ value.query = value.type === "smart" ? value.query : undefined;
+ isEdit ? editList({ ...value, listId: list.id }) : createList(value);
+ },
+ );
return (
<Dialog
@@ -176,7 +195,9 @@ export function EditListModal({
<Form {...form}>
<form onSubmit={onSubmit}>
<DialogHeader>
- <DialogTitle>{isEdit ? "Edit" : "New"} List</DialogTitle>
+ <DialogTitle>
+ {isEdit ? t("lists.edit_list") : t("lists.new_list")}
+ </DialogTitle>
</DialogHeader>
<div className="flex w-full gap-2 py-4">
<FormField
@@ -232,7 +253,7 @@ export function EditListModal({
render={({ field }) => {
return (
<FormItem className="grow pb-4">
- <FormLabel>Parent</FormLabel>
+ <FormLabel>{t("lists.parent_list")}</FormLabel>
<div className="flex items-center gap-1">
<FormControl>
<BookmarkListSelector
@@ -240,7 +261,7 @@ export function EditListModal({
hideSubtreeOf={list ? list.id : undefined}
value={field.value}
onChange={field.onChange}
- placeholder={"No Parent"}
+ placeholder={t("lists.no_parent")}
/>
</FormControl>
<Button
@@ -258,6 +279,58 @@ export function EditListModal({
);
}}
/>
+ <FormField
+ control={form.control}
+ name="type"
+ render={({ field }) => {
+ return (
+ <FormItem className="grow pb-4">
+ <FormLabel>{t("lists.list_type")}</FormLabel>
+ <FormControl>
+ <Select
+ disabled={isEdit}
+ onValueChange={field.onChange}
+ value={field.value}
+ >
+ <SelectTrigger className="w-full">
+ <SelectValue />
+ </SelectTrigger>
+ <SelectContent>
+ <SelectItem value="manual">
+ {t("lists.manual_list")}
+ </SelectItem>
+ <SelectItem value="smart">
+ {t("lists.smart_list")}
+ </SelectItem>
+ </SelectContent>
+ </Select>
+ </FormControl>
+ <FormMessage />
+ </FormItem>
+ );
+ }}
+ />
+ {listType === "smart" && (
+ <FormField
+ control={form.control}
+ name="query"
+ render={({ field }) => {
+ return (
+ <FormItem className="grow pb-4">
+ <FormLabel>{t("lists.search_query")}</FormLabel>
+ <FormControl>
+ <Input
+ value={field.value}
+ onChange={field.onChange}
+ placeholder={t("lists.search_query")}
+ />
+ </FormControl>
+ <FormMessage />
+ </FormItem>
+ );
+ }}
+ />
+ )}
<DialogFooter className="sm:justify-end">
<DialogClose asChild>
<Button type="button" variant="secondary">