From 5ecdc36b7d60aa66b49e01e9fec8ba61ad537376 Mon Sep 17 00:00:00 2001 From: Mohamed Bassem Date: Thu, 2 Jan 2025 13:00:58 +0200 Subject: 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> --- packages/shared/types/lists.ts | 82 +++++++++++++++++++++++++++++++++--------- 1 file changed, 65 insertions(+), 17 deletions(-) (limited to 'packages/shared') diff --git a/packages/shared/types/lists.ts b/packages/shared/types/lists.ts index d2041907..bd6786b0 100644 --- a/packages/shared/types/lists.ts +++ b/packages/shared/types/lists.ts @@ -1,28 +1,76 @@ import { z } from "zod"; -export const zNewBookmarkListSchema = z.object({ - name: z - .string() - .min(1, "List name can't be empty") - .max(40, "List name is at most 40 chars"), - icon: z.string(), - parentId: z.string().nullish(), -}); +import { parseSearchQuery } from "../searchQueryParser"; + +export const zNewBookmarkListSchema = z + .object({ + name: z + .string() + .min(1, "List name can't be empty") + .max(40, "List name is at most 40 chars"), + icon: z.string(), + type: z.enum(["manual", "smart"]).optional().default("manual"), + query: z.string().min(1).optional(), + parentId: z.string().nullish(), + }) + .refine((val) => val.type === "smart" || !val.query, { + message: "Manual lists cannot have a query", + path: ["query"], + }) + .refine((val) => val.type === "manual" || val.query, { + message: "Smart lists must have a query", + path: ["query"], + }) + .refine( + (val) => !val.query || parseSearchQuery(val.query).result === "full", + { + message: "Smart search query is not valid", + path: ["query"], + }, + ) + .refine((val) => !val.query || parseSearchQuery(val.query).text.length == 0, { + message: + "Smart lists cannot have unqualified terms (aka full text search terms) in the query", + path: ["query"], + }); export const zBookmarkListSchema = z.object({ id: z.string(), name: z.string(), icon: z.string(), parentId: z.string().nullable(), + type: z.enum(["manual", "smart"]).default("manual"), + query: z.string().nullish(), }); -export const zBookmarkListWithBookmarksSchema = zBookmarkListSchema.merge( - z.object({ - bookmarks: z.array(z.string()), - }), -); - export type ZBookmarkList = z.infer; -export type ZBookmarkListWithBookmarks = z.infer< - typeof zBookmarkListWithBookmarksSchema ->; + +export const zEditBookmarkListSchema = z.object({ + listId: z.string(), + name: z + .string() + .min(1, "List name can't be empty") + .max(40, "List name is at most 40 chars") + .optional(), + icon: z.string().optional(), + parentId: z.string().nullish(), + query: z.string().min(1).optional(), +}); + +export const zEditBookmarkListSchemaWithValidation = zEditBookmarkListSchema + .refine((val) => val.parentId != val.listId, { + message: "List can't be its own parent", + path: ["parentId"], + }) + .refine( + (val) => !val.query || parseSearchQuery(val.query).result === "full", + { + message: "Smart search query is not valid", + path: ["query"], + }, + ) + .refine((val) => !val.query || parseSearchQuery(val.query).text.length == 0, { + message: + "Smart lists cannot have unqualified terms (aka full text search terms) in the query", + path: ["query"], + }); -- cgit v1.2.3-70-g09d2