From be8f069fbe1cedd363bdc7d587b11b099359940d Mon Sep 17 00:00:00 2001 From: Satish Gandham Date: Thu, 26 Sep 2024 18:55:49 +0530 Subject: [PATCH 1/8] - Handle single quotes in load workspace queries - Add IS null where condition in query utils --- web/core/local-db/utils/load-workspace.ts | 4 ++-- web/core/local-db/utils/query.utils.ts | 5 ++++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/web/core/local-db/utils/load-workspace.ts b/web/core/local-db/utils/load-workspace.ts index 36d2aabce95..87231161c6f 100644 --- a/web/core/local-db/utils/load-workspace.ts +++ b/web/core/local-db/utils/load-workspace.ts @@ -27,10 +27,10 @@ const stageInserts = (table: string, schema: Schema, data: any) => { return ""; } if (typeof value === "object") { - return `'${JSON.stringify(value)}'`; + return `'${JSON.stringify(value).replace(/'/g, "''")}'`; } if (typeof value === "string") { - return `'${value}'`; + return `'${value.replace(/'/g, "''")}'`; } return value; }) diff --git a/web/core/local-db/utils/query.utils.ts b/web/core/local-db/utils/query.utils.ts index e95174bc7fa..eaaf11a1c87 100644 --- a/web/core/local-db/utils/query.utils.ts +++ b/web/core/local-db/utils/query.utils.ts @@ -238,7 +238,10 @@ export const singleFilterConstructor = (queries: any) => { keys.forEach((key) => { const value = filters[key] ? filters[key].split(",") : ""; - if (!value) return; + if (!value) { + sql += ` AND ${key} IS NULL`; + return; + } if (!ARRAY_FIELDS.includes(key)) { sql += ` AND ${key} in ('${value.join("','")}') `; From 215889c9dfd96ced873b65f134a21ea64543ef79 Mon Sep 17 00:00:00 2001 From: Satish Gandham Date: Thu, 26 Sep 2024 19:09:43 +0530 Subject: [PATCH 2/8] Fix description_html being lost --- web/core/local-db/utils/utils.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/web/core/local-db/utils/utils.ts b/web/core/local-db/utils/utils.ts index 619ec9af8d5..f1e05274e82 100644 --- a/web/core/local-db/utils/utils.ts +++ b/web/core/local-db/utils/utils.ts @@ -47,6 +47,7 @@ export const updatePersistentLayer = async (issueIds: string | string[]) => { "label_ids", "module_ids", "type_id", + "description_html", ]); updateIssue({ ...issuePartial, is_local_update: 1 }); } From 00c48c385d8b5aca34d54776f8e9c31c70b7e40c Mon Sep 17 00:00:00 2001 From: Satish Gandham Date: Fri, 27 Sep 2024 08:16:24 +0530 Subject: [PATCH 3/8] Change secondary order to sequence_id --- web/core/local-db/utils/indexes.ts | 1 + web/core/local-db/utils/query.utils.ts | 12 ++++-------- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/web/core/local-db/utils/indexes.ts b/web/core/local-db/utils/indexes.ts index aeff6992e9a..214bacb44f5 100644 --- a/web/core/local-db/utils/indexes.ts +++ b/web/core/local-db/utils/indexes.ts @@ -10,6 +10,7 @@ export const createIssueIndexes = async () => { "project_id", "created_by", "cycle_id", + "sequence_id", ]; const promises: Promise[] = []; diff --git a/web/core/local-db/utils/query.utils.ts b/web/core/local-db/utils/query.utils.ts index eaaf11a1c87..ad012a30a90 100644 --- a/web/core/local-db/utils/query.utils.ts +++ b/web/core/local-db/utils/query.utils.ts @@ -47,9 +47,9 @@ export const getOrderByFragment = (order_by: string, table = "") => { if (!order_by) return orderByString; if (order_by.startsWith("-")) { - orderByString += ` ORDER BY ${wrapDateTime(order_by.slice(1))} DESC NULLS LAST, datetime(${table}created_at) DESC`; + orderByString += ` ORDER BY ${wrapDateTime(order_by.slice(1))} DESC NULLS LAST, ${table}sequence_id DESC`; } else { - orderByString += ` ORDER BY ${wrapDateTime(order_by)} ASC NULLS LAST, datetime(${table}created_at) DESC`; + orderByString += ` ORDER BY ${wrapDateTime(order_by)} ASC NULLS LAST, ${table}sequence_id DESC`; } return orderByString; }; @@ -130,7 +130,7 @@ export const getFilteredRowsForGrouping = (projectId: string, queries: any) => { let sql = ""; if (!joinsRequired) { - sql = `WITH fi as (SELECT i.id,i.created_at ${issueTableFilterFields}`; + sql = `WITH fi as (SELECT i.id,i.created_at, i.sequence_id ${issueTableFilterFields}`; if (group_by) { if (group_by === "target_date") { sql += `, date(i.${group_by}) as group_id`; @@ -153,7 +153,7 @@ export const getFilteredRowsForGrouping = (projectId: string, queries: any) => { } sql = `WITH fi AS (`; - sql += `SELECT i.id,i.created_at ${issueTableFilterFields} `; + sql += `SELECT i.id,i.created_at,i.sequence_id ${issueTableFilterFields} `; if (group_by) { if (ARRAY_FIELDS.includes(group_by)) { sql += `, ${group_by}.value as group_id @@ -252,10 +252,6 @@ export const singleFilterConstructor = (queries: any) => { return sql; }; -// let q = '2_months;after;fromnow,1_months;after;fromnow,2024-09-01;after,2024-10-06;after,2_weeks;after;fromnow' - -// ["2_months;after;fromnow", "1_months;after;fromnow", "2024-09-01;after", "2024-10-06;before", "2_weeks;after;fromnow"]; - const createDateFilter = (key: string, q: string) => { let sql = " "; // get todays date in YYYY-MM-DD format From 5cece0f37dce74828a0990d24a970d3d1ef2a83c Mon Sep 17 00:00:00 2001 From: Satish Gandham Date: Fri, 27 Sep 2024 08:58:40 +0530 Subject: [PATCH 4/8] Fix update persistence layer --- web/core/local-db/utils/utils.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/web/core/local-db/utils/utils.ts b/web/core/local-db/utils/utils.ts index f1e05274e82..368a19e7fa2 100644 --- a/web/core/local-db/utils/utils.ts +++ b/web/core/local-db/utils/utils.ts @@ -1,6 +1,7 @@ import pick from "lodash/pick"; import { TIssue } from "@plane/types"; import { rootStore } from "@/lib/store-context"; +import { persistence } from "../storage.sqlite"; import { updateIssue } from "./load-issues"; export const log = (...args: any) => { @@ -15,11 +16,13 @@ export const updatePersistentLayer = async (issueIds: string | string[]) => { if (typeof issueIds === "string") { issueIds = [issueIds]; } - issueIds.forEach((issueId) => { + issueIds.forEach(async (issueId) => { + const dbIssue = await persistence.getIssue(issueId); const issue = rootStore.issue.issues.getIssueById(issueId); if (issue) { - const issuePartial = pick(JSON.parse(JSON.stringify(issue)), [ + // JSON.parse(JSON.stringify(issue)) is used to remove the mobx observables + const issuePartial = pick({ ...dbIssue, ...JSON.parse(JSON.stringify(issue)) }, [ "id", "name", "state_id", From 44a22440d8b881cb34be228744dfc8361bcc79f2 Mon Sep 17 00:00:00 2001 From: Satish Gandham Date: Fri, 27 Sep 2024 14:18:58 +0530 Subject: [PATCH 5/8] Fix issue types filter Fix none filter --- web/core/local-db/utils/query.utils.ts | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/web/core/local-db/utils/query.utils.ts b/web/core/local-db/utils/query.utils.ts index ad012a30a90..c97669ae729 100644 --- a/web/core/local-db/utils/query.utils.ts +++ b/web/core/local-db/utils/query.utils.ts @@ -4,7 +4,8 @@ import { issueSchema } from "./schemas"; import { wrapDateTime } from "./utils"; export const translateQueryParams = (queries: any) => { - const { group_by, sub_group_by, labels, assignees, state, cycle, module, priority, type, ...otherProps } = queries; + const { group_by, sub_group_by, labels, assignees, state, cycle, module, priority, type, issue_type, ...otherProps } = + queries; const order_by = queries.order_by; if (state) otherProps.state_id = state; @@ -23,6 +24,9 @@ export const translateQueryParams = (queries: any) => { if (type) { otherProps.state_group = type === "backlog" ? "backlog" : "unstarted,started"; } + if (issue_type) { + otherProps.type_id = issue_type; + } if (order_by?.includes("priority")) { otherProps.order_by = order_by.replace("priority", "priority_proxy"); @@ -238,11 +242,11 @@ export const singleFilterConstructor = (queries: any) => { keys.forEach((key) => { const value = filters[key] ? filters[key].split(",") : ""; - if (!value) { - sql += ` AND ${key} IS NULL`; - return; - } if (!ARRAY_FIELDS.includes(key)) { + if (!value) { + sql += ` AND ${key} IS NULL`; + return; + } sql += ` AND ${key} in ('${value.join("','")}') `; } From 1bc6a0b2e75d51e680319887e7393c9a8eb824b9 Mon Sep 17 00:00:00 2001 From: rahulramesha Date: Fri, 27 Sep 2024 14:55:17 +0530 Subject: [PATCH 6/8] add local cache toggle in help section --- .../workspace/sidebar/help-section.tsx | 25 +++++++++++++++++-- web/core/store/user/settings.store.ts | 12 ++++++--- 2 files changed, 32 insertions(+), 5 deletions(-) diff --git a/web/core/components/workspace/sidebar/help-section.tsx b/web/core/components/workspace/sidebar/help-section.tsx index c2af0c3b5ef..ed4ee2ccf80 100644 --- a/web/core/components/workspace/sidebar/help-section.tsx +++ b/web/core/components/workspace/sidebar/help-section.tsx @@ -2,29 +2,33 @@ import React, { useState } from "react"; import { observer } from "mobx-react"; +import { useParams } from "next/navigation"; import { FileText, HelpCircle, MessagesSquare, MoveLeft, User } from "lucide-react"; // ui -import { CustomMenu, Tooltip } from "@plane/ui"; +import { CustomMenu, ToggleSwitch, Tooltip } from "@plane/ui"; // helpers import { cn } from "@/helpers/common.helper"; // hooks -import { useAppTheme, useCommandPalette, useInstance, useTransient } from "@/hooks/store"; +import { useAppTheme, useCommandPalette, useInstance, useTransient, useUserSettings } from "@/hooks/store"; import { usePlatformOS } from "@/hooks/use-platform-os"; // plane web components import { PlaneVersionNumber, ProductUpdates, ProductUpdatesModal } from "@/plane-web/components/global"; import { WorkspaceEditionBadge } from "@/plane-web/components/workspace"; +import { ENABLE_LOCAL_DB_CACHE } from "@/plane-web/constants/issues"; export interface WorkspaceHelpSectionProps { setSidebarActive?: React.Dispatch>; } export const SidebarHelpSection: React.FC = observer(() => { + const { workspaceSlug, projectId } = useParams(); // store hooks const { sidebarCollapsed, toggleSidebar } = useAppTheme(); const { toggleShortcutModal } = useCommandPalette(); const { isMobile } = usePlatformOS(); const { config } = useInstance(); const { isIntercomToggle, toggleIntercom } = useTransient(); + const { canUseLocalDB, toggleLocalDB } = useUserSettings(); // states const [isNeedHelpOpen, setIsNeedHelpOpen] = useState(false); const [isChangeLogOpen, setIsChangeLogOpen] = useState(false); @@ -105,6 +109,23 @@ export const SidebarHelpSection: React.FC = observer(
+ {ENABLE_LOCAL_DB_CACHE && ( + +
{ + e.preventDefault(); + e.stopPropagation(); + }} + className="flex w-full items-center justify-between text-xs hover:bg-custom-background-80" + > + Local Cache + toggleLocalDB(workspaceSlug?.toString(), projectId?.toString())} + /> +
+
+ )}
- {ENABLE_LOCAL_DB_CACHE && ( - - {({ open }) => ( - <> - - Local Cache - - - - -
- - Toggled on by default to keep Plane performant. Disable this if you are facing any issues with - Plane. Applicable only to this device. - - toggleLocalDB()} /> -
-
-
- - )} -
- )} {({ open }) => ( <> From 594ea319aa858c8f84cbfb5e1a644a373940b15d Mon Sep 17 00:00:00 2001 From: Satish Gandham Date: Fri, 27 Sep 2024 15:07:04 +0530 Subject: [PATCH 8/8] Reset storage class on disabling local --- web/core/local-db/storage.sqlite.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/web/core/local-db/storage.sqlite.ts b/web/core/local-db/storage.sqlite.ts index 70a96942fe4..59b02a7555e 100644 --- a/web/core/local-db/storage.sqlite.ts +++ b/web/core/local-db/storage.sqlite.ts @@ -54,6 +54,7 @@ export class Storage { const fileSystemDirectoryHandle = await storageManager.getDirectory(); //@ts-expect-error , clear local issue cache await fileSystemDirectoryHandle.remove({ recursive: true }); + this.reset(); } catch (e) { console.error("Error clearing sqlite sync storage", e); }