mirror of
https://github.com/makeplane/plane
synced 2025-08-07 19:59:33 +00:00
Compare commits
3 Commits
feat-chang
...
hyper-mode
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
733b725b5e | ||
|
|
3bee051ee9 | ||
|
|
6b902d458e |
@@ -3,37 +3,49 @@ import * as Comlink from "comlink";
|
||||
import set from "lodash/set";
|
||||
// plane
|
||||
import { EIssueGroupBYServerToProperty } from "@plane/constants";
|
||||
import { TIssue } from "@plane/types";
|
||||
// lib
|
||||
import { rootStore } from "@/lib/store-context";
|
||||
// services
|
||||
import { IssueService } from "@/services/issue/issue.service";
|
||||
//
|
||||
import { ARRAY_FIELDS, BOOLEAN_FIELDS } from "./utils/constants";
|
||||
import { getSubIssuesWithDistribution } from "./utils/data.utils";
|
||||
import createIndexes from "./utils/indexes";
|
||||
import { addIssuesBulk, syncDeletesToLocal } from "./utils/load-issues";
|
||||
import { loadWorkSpaceData } from "./utils/load-workspace";
|
||||
import { issueFilterCountQueryConstructor, issueFilterQueryConstructor } from "./utils/query-constructor";
|
||||
import { runQuery } from "./utils/query-executor";
|
||||
import { deleteOption, formatLocalIssue, getLastSyncTime, getOption, setOption } from "./utils/storage.sqlite.utils";
|
||||
import { createTables } from "./utils/tables";
|
||||
import { clearOPFS, getGroupedIssueResults, getSubGroupedIssueResults, log, logError } from "./utils/utils";
|
||||
|
||||
/** Database version for schema management */
|
||||
const DB_VERSION = 1;
|
||||
/** Number of items per page for pagination */
|
||||
const PAGE_SIZE = 500;
|
||||
/** Number of items to process in a single batch */
|
||||
const BATCH_SIZE = 50;
|
||||
|
||||
/** Project status type definition */
|
||||
type TProjectStatus = {
|
||||
issues: { status: undefined | "loading" | "ready" | "error" | "syncing"; sync: Promise<void> | undefined };
|
||||
issues: {
|
||||
status: undefined | "loading" | "ready" | "error" | "syncing";
|
||||
sync: Promise<void> | undefined;
|
||||
};
|
||||
};
|
||||
|
||||
/** Database status type definition */
|
||||
type TDBStatus = "initializing" | "ready" | "error" | undefined;
|
||||
|
||||
/**
|
||||
* Storage class for managing local SQLite database operations
|
||||
* Handles database initialization, synchronization, and CRUD operations for issues
|
||||
*/
|
||||
export class Storage {
|
||||
db: any;
|
||||
status: TDBStatus = undefined;
|
||||
dbName = "plane";
|
||||
projectStatus: Record<string, TProjectStatus> = {};
|
||||
workspaceSlug: string = "";
|
||||
public db: any;
|
||||
private status: TDBStatus = undefined;
|
||||
private dbName = "plane";
|
||||
private projectStatus: Record<string, TProjectStatus> = {};
|
||||
private workspaceSlug: string = "";
|
||||
|
||||
constructor() {
|
||||
this.db = null;
|
||||
@@ -43,13 +55,20 @@ export class Storage {
|
||||
}
|
||||
}
|
||||
|
||||
closeDBConnection = async () => {
|
||||
/**
|
||||
* Closes the database connection
|
||||
* @returns Promise<void>
|
||||
*/
|
||||
private closeDBConnection = async (): Promise<void> => {
|
||||
if (this.db) {
|
||||
await this.db.close();
|
||||
}
|
||||
};
|
||||
|
||||
reset = () => {
|
||||
/**
|
||||
* Resets the database state
|
||||
*/
|
||||
public reset = (): void => {
|
||||
if (this.db) {
|
||||
this.db.close();
|
||||
}
|
||||
@@ -59,17 +78,27 @@ export class Storage {
|
||||
this.workspaceSlug = "";
|
||||
};
|
||||
|
||||
clearStorage = async (force = false) => {
|
||||
/**
|
||||
* Clears the storage and resets the database
|
||||
* @param force - Force clear storage
|
||||
*/
|
||||
public clearStorage = async (force = false): Promise<void> => {
|
||||
try {
|
||||
await this.db?.close();
|
||||
await clearOPFS(force);
|
||||
this.reset();
|
||||
} catch (e) {
|
||||
console.error("Error clearing sqlite sync storage", e);
|
||||
} catch (error) {
|
||||
logError(error);
|
||||
console.error("Error clearing sqlite sync storage", error);
|
||||
}
|
||||
};
|
||||
|
||||
initialize = async (workspaceSlug: string): Promise<boolean> => {
|
||||
/**
|
||||
* Initializes the database for a given workspace
|
||||
* @param workspaceSlug - Workspace identifier
|
||||
* @returns Promise<boolean> - True if initialization is successful
|
||||
*/
|
||||
public initialize = async (workspaceSlug: string): Promise<boolean> => {
|
||||
if (!rootStore.user.localDBEnabled) return false; // return if the window gets hidden
|
||||
|
||||
if (workspaceSlug !== this.workspaceSlug) {
|
||||
@@ -86,7 +115,12 @@ export class Storage {
|
||||
}
|
||||
};
|
||||
|
||||
_initialize = async (workspaceSlug: string): Promise<boolean> => {
|
||||
/**
|
||||
* Initializes the database for a given workspace
|
||||
* @param workspaceSlug - Workspace identifier
|
||||
* @returns Promise<boolean> - True if initialization is successful
|
||||
*/
|
||||
private _initialize = async (workspaceSlug: string): Promise<boolean> => {
|
||||
if (this.status === "initializing") {
|
||||
console.warn(`Initialization already in progress for workspace ${workspaceSlug}`);
|
||||
return false;
|
||||
@@ -122,7 +156,7 @@ export class Storage {
|
||||
// Your SQLite code here.
|
||||
await createTables();
|
||||
|
||||
await this.setOption("DB_VERSION", DB_VERSION.toString());
|
||||
await setOption("DB_VERSION", DB_VERSION.toString());
|
||||
return true;
|
||||
} catch (error) {
|
||||
this.status = "error";
|
||||
@@ -131,7 +165,10 @@ export class Storage {
|
||||
}
|
||||
};
|
||||
|
||||
syncWorkspace = async () => {
|
||||
/**
|
||||
* Synchronizes the workspace data
|
||||
*/
|
||||
public syncWorkspace = async (): Promise<void> => {
|
||||
if (!rootStore.user.localDBEnabled) return;
|
||||
const syncInProgress = await this.getIsWriteInProgress("sync_workspace");
|
||||
if (syncInProgress) {
|
||||
@@ -140,23 +177,27 @@ export class Storage {
|
||||
}
|
||||
try {
|
||||
await startSpan({ name: "LOAD_WS", attributes: { slug: this.workspaceSlug } }, async () => {
|
||||
this.setOption("sync_workspace", new Date().toUTCString());
|
||||
setOption("sync_workspace", new Date().toUTCString());
|
||||
await loadWorkSpaceData(this.workspaceSlug);
|
||||
this.deleteOption("sync_workspace");
|
||||
deleteOption("sync_workspace");
|
||||
});
|
||||
} catch (e) {
|
||||
logError(e);
|
||||
this.deleteOption("sync_workspace");
|
||||
deleteOption("sync_workspace");
|
||||
}
|
||||
};
|
||||
|
||||
syncProject = async (projectId: string) => {
|
||||
/**
|
||||
* Synchronizes the project data
|
||||
* @param projectId - Project identifier
|
||||
*/
|
||||
public syncProject = async (projectId: string): Promise<void> => {
|
||||
if (
|
||||
// document.hidden ||
|
||||
!rootStore.user.localDBEnabled
|
||||
)
|
||||
return false; // return if the window gets hidden
|
||||
|
||||
) {
|
||||
return; // return if the window gets hidden
|
||||
}
|
||||
// Load labels, members, states, modules, cycles
|
||||
await this.syncIssues(projectId);
|
||||
|
||||
@@ -172,9 +213,13 @@ export class Storage {
|
||||
// this.setOption("workspace_synced_at", new Date().toISOString());
|
||||
};
|
||||
|
||||
syncIssues = async (projectId: string) => {
|
||||
/**
|
||||
* Synchronizes the issues for a project
|
||||
* @param projectId - Project identifier
|
||||
*/
|
||||
public syncIssues = async (projectId: string): Promise<void> => {
|
||||
if (!rootStore.user.localDBEnabled || !this.db) {
|
||||
return false;
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const sync = startSpan({ name: `SYNC_ISSUES` }, () => this._syncIssues(projectId));
|
||||
@@ -186,7 +231,11 @@ export class Storage {
|
||||
}
|
||||
};
|
||||
|
||||
_syncIssues = async (projectId: string) => {
|
||||
/**
|
||||
* Synchronizes the issues for a project
|
||||
* @param projectId - Project identifier
|
||||
*/
|
||||
private _syncIssues = async (projectId: string): Promise<void> => {
|
||||
const activeSpan = getActiveSpan();
|
||||
|
||||
log("### Sync started");
|
||||
@@ -207,8 +256,8 @@ export class Storage {
|
||||
description: true,
|
||||
};
|
||||
|
||||
const syncedAt = await this.getLastSyncTime(projectId);
|
||||
const projectSync = await this.getOption(projectId);
|
||||
const syncedAt = await getLastSyncTime(projectId);
|
||||
const projectSync = await getOption(projectId);
|
||||
|
||||
if (syncedAt) {
|
||||
queryParams["updated_at__gt"] = syncedAt;
|
||||
@@ -245,7 +294,7 @@ export class Storage {
|
||||
if (status === "loading") {
|
||||
await createIndexes();
|
||||
}
|
||||
this.setOption(projectId, "ready");
|
||||
setOption(projectId, "ready");
|
||||
this.setStatus(projectId, "ready");
|
||||
this.setSync(projectId, undefined);
|
||||
|
||||
@@ -255,31 +304,15 @@ export class Storage {
|
||||
});
|
||||
};
|
||||
|
||||
getIssueCount = async (projectId: string) => {
|
||||
const count = await runQuery(`select count(*) as count from issues where project_id='${projectId}'`);
|
||||
return count[0]["count"];
|
||||
};
|
||||
|
||||
getLastUpdatedIssue = async (projectId: string) => {
|
||||
const lastUpdatedIssue = await runQuery(
|
||||
`select id, name, updated_at , sequence_id from issues WHERE project_id='${projectId}' AND is_local_update IS NULL order by datetime(updated_at) desc limit 1 `
|
||||
);
|
||||
|
||||
if (lastUpdatedIssue.length) {
|
||||
return lastUpdatedIssue[0];
|
||||
}
|
||||
return;
|
||||
};
|
||||
|
||||
getLastSyncTime = async (projectId: string) => {
|
||||
const issue = await this.getLastUpdatedIssue(projectId);
|
||||
if (!issue) {
|
||||
return false;
|
||||
}
|
||||
return issue.updated_at;
|
||||
};
|
||||
|
||||
getIssues = async (workspaceSlug: string, projectId: string, queries: any, config: any) => {
|
||||
/**
|
||||
* Gets issues for a project
|
||||
* @param workspaceSlug - Workspace identifier
|
||||
* @param projectId - Project identifier
|
||||
* @param queries - Query parameters
|
||||
* @param config - Configuration options
|
||||
* @returns Promise<any> - Issues data
|
||||
*/
|
||||
public getIssues = async (workspaceSlug: string, projectId: string, queries: any, config: any): Promise<any> => {
|
||||
log("#### Queries", queries);
|
||||
|
||||
const currentProjectStatus = this.getStatus(projectId);
|
||||
@@ -387,7 +420,12 @@ export class Storage {
|
||||
return out;
|
||||
};
|
||||
|
||||
getIssue = async (issueId: string) => {
|
||||
/**
|
||||
* Gets an issue by ID
|
||||
* @param issueId - Issue identifier
|
||||
* @returns Promise<any | undefined> - Issue data or undefined
|
||||
*/
|
||||
public getIssue = async (issueId: string): Promise<any | undefined> => {
|
||||
try {
|
||||
if (!rootStore.user.localDBEnabled || this.status !== "ready") return;
|
||||
|
||||
@@ -403,8 +441,15 @@ export class Storage {
|
||||
return;
|
||||
};
|
||||
|
||||
getSubIssues = async (workspaceSlug: string, projectId: string, issueId: string) => {
|
||||
const workspace_synced_at = await this.getOption("workspace_synced_at");
|
||||
/**
|
||||
* Gets sub-issues for an issue
|
||||
* @param workspaceSlug - Workspace identifier
|
||||
* @param projectId - Project identifier
|
||||
* @param issueId - Issue identifier
|
||||
* @returns Promise<any> - Sub-issues data
|
||||
*/
|
||||
public getSubIssues = async (workspaceSlug: string, projectId: string, issueId: string): Promise<any> => {
|
||||
const workspace_synced_at = await getOption("workspace_synced_at");
|
||||
if (!workspace_synced_at) {
|
||||
const issueService = new IssueService();
|
||||
return await issueService.subIssues(workspaceSlug, projectId, issueId);
|
||||
@@ -412,74 +457,57 @@ export class Storage {
|
||||
return await getSubIssuesWithDistribution(issueId);
|
||||
};
|
||||
|
||||
getStatus = (projectId: string) => this.projectStatus[projectId]?.issues?.status || undefined;
|
||||
setStatus = (projectId: string, status: "loading" | "ready" | "error" | "syncing" | undefined = undefined) => {
|
||||
/**
|
||||
* Gets the status of a project
|
||||
* @param projectId - Project identifier
|
||||
* @returns Project status or undefined
|
||||
*/
|
||||
public getStatus = (projectId: string): "loading" | "ready" | "error" | "syncing" | undefined =>
|
||||
this.projectStatus[projectId]?.issues?.status || undefined;
|
||||
|
||||
/**
|
||||
* Sets the status of a project
|
||||
* @param projectId - Project identifier
|
||||
* @param status - New status
|
||||
*/
|
||||
public setStatus = (
|
||||
projectId: string,
|
||||
status: "loading" | "ready" | "error" | "syncing" | undefined = undefined
|
||||
): void => {
|
||||
set(this.projectStatus, `${projectId}.issues.status`, status);
|
||||
};
|
||||
|
||||
getSync = (projectId: string) => this.projectStatus[projectId]?.issues?.sync;
|
||||
setSync = (projectId: string, sync: Promise<void> | undefined) => {
|
||||
/**
|
||||
* Gets the sync promise for a project
|
||||
* @param projectId - Project identifier
|
||||
* @returns Sync promise or undefined
|
||||
*/
|
||||
public getSync = (projectId: string): Promise<void> | undefined => this.projectStatus[projectId]?.issues?.sync;
|
||||
|
||||
/**
|
||||
* Sets the sync promise for a project
|
||||
* @param projectId - Project identifier
|
||||
* @param sync - Sync promise
|
||||
*/
|
||||
public setSync = (projectId: string, sync: Promise<void> | undefined): void => {
|
||||
set(this.projectStatus, `${projectId}.issues.sync`, sync);
|
||||
};
|
||||
|
||||
getOption = async (key: string, fallback?: string | boolean | number) => {
|
||||
try {
|
||||
const options = await runQuery(`select * from options where key='${key}'`);
|
||||
if (options.length) {
|
||||
return options[0].value;
|
||||
}
|
||||
|
||||
return fallback;
|
||||
} catch (e) {
|
||||
return fallback;
|
||||
}
|
||||
};
|
||||
setOption = async (key: string, value: string) => {
|
||||
await runQuery(`insert or replace into options (key, value) values ('${key}', '${value}')`);
|
||||
};
|
||||
|
||||
deleteOption = async (key: string) => {
|
||||
await runQuery(` DELETE FROM options where key='${key}'`);
|
||||
};
|
||||
getOptions = async (keys: string[]) => {
|
||||
const options = await runQuery(`select * from options where key in ('${keys.join("','")}')`);
|
||||
return options.reduce((acc: any, option: any) => {
|
||||
acc[option.key] = option.value;
|
||||
return acc;
|
||||
}, {});
|
||||
};
|
||||
|
||||
getIsWriteInProgress = async (op: string) => {
|
||||
const writeStartTime = await this.getOption(op, false);
|
||||
/**
|
||||
* Checks if a write operation is in progress
|
||||
* @param op - Operation identifier
|
||||
* @returns Promise<boolean> - True if write is in progress
|
||||
*/
|
||||
public getIsWriteInProgress = async (op: string): Promise<boolean> => {
|
||||
const writeStartTime = (await getOption(op, "")) as string;
|
||||
if (writeStartTime) {
|
||||
// Check if it has been more than 5seconds
|
||||
const current = new Date();
|
||||
const start = new Date(writeStartTime);
|
||||
|
||||
if (current.getTime() - start.getTime() < 5000) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return current.getTime() - start.getTime() < 5000;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
}
|
||||
|
||||
export const persistence = new Storage();
|
||||
|
||||
/**
|
||||
* format the issue fetched from local db into an issue
|
||||
* @param issue
|
||||
* @returns
|
||||
*/
|
||||
export const formatLocalIssue = (issue: any) => {
|
||||
const currIssue = issue;
|
||||
ARRAY_FIELDS.forEach((field: string) => {
|
||||
currIssue[field] = currIssue[field] ? JSON.parse(currIssue[field]) : [];
|
||||
});
|
||||
// Convert boolean fields to actual boolean values
|
||||
BOOLEAN_FIELDS.forEach((field: string) => {
|
||||
currIssue[field] = currIssue[field] === 1;
|
||||
});
|
||||
return currIssue as TIssue & { group_id?: string; total_issues: number; sub_group_id?: string };
|
||||
};
|
||||
|
||||
116
web/core/local-db/utils/storage.sqlite.utils.ts
Normal file
116
web/core/local-db/utils/storage.sqlite.utils.ts
Normal file
@@ -0,0 +1,116 @@
|
||||
// Moving functions from storage.sqlite.ts to storage.sqlite.utils.ts
|
||||
import { TIssue } from "@plane/types";
|
||||
import { ARRAY_FIELDS, BOOLEAN_FIELDS } from "./constants";
|
||||
import { runQuery } from "./query-executor";
|
||||
|
||||
/**
|
||||
* Formats an issue fetched from local db into the required format
|
||||
* @param issue - Raw issue data from database
|
||||
* @returns Formatted issue with proper types
|
||||
*/
|
||||
|
||||
export const formatLocalIssue = (
|
||||
issue: any
|
||||
): TIssue & { group_id?: string; total_issues: number; sub_group_id?: string } => {
|
||||
const currIssue = { ...issue };
|
||||
|
||||
// Parse array fields from JSON strings
|
||||
ARRAY_FIELDS.forEach((field: string) => {
|
||||
currIssue[field] = currIssue[field] ? JSON.parse(currIssue[field]) : [];
|
||||
});
|
||||
|
||||
// Convert boolean fields to actual boolean values
|
||||
BOOLEAN_FIELDS.forEach((field: string) => {
|
||||
currIssue[field] = currIssue[field] === 1;
|
||||
});
|
||||
|
||||
return currIssue;
|
||||
};
|
||||
|
||||
/**
|
||||
* Gets the last updated issue for a project
|
||||
* @param projectId - Project identifier
|
||||
* @returns Promise<any | undefined> - Last updated issue or undefined
|
||||
*/
|
||||
export const getLastUpdatedIssue = async (projectId: string): Promise<any | undefined> => {
|
||||
const lastUpdatedIssue = await runQuery(
|
||||
`select id, name, updated_at, sequence_id from issues WHERE project_id='${projectId}' AND is_local_update IS NULL order by datetime(updated_at) desc limit 1`
|
||||
);
|
||||
|
||||
return lastUpdatedIssue.length ? lastUpdatedIssue[0] : undefined;
|
||||
};
|
||||
|
||||
/**
|
||||
* Gets the last sync time for a project
|
||||
* @param projectId - Project identifier
|
||||
* @returns Promise<string | false> - Last sync time or false
|
||||
*/
|
||||
export const getLastSyncTime = async (projectId: string): Promise<string | false> => {
|
||||
const issue = await getLastUpdatedIssue(projectId);
|
||||
if (!issue) {
|
||||
return false;
|
||||
}
|
||||
return issue.updated_at;
|
||||
};
|
||||
|
||||
/**
|
||||
* Gets the count of issues for a project
|
||||
* @param projectId - Project identifier
|
||||
* @returns Promise<number> - Count of issues
|
||||
*/
|
||||
export const getIssueCount = async (projectId: string): Promise<number> => {
|
||||
const count = await runQuery(`select count(*) as count from issues where project_id='${projectId}'`);
|
||||
return count[0]["count"];
|
||||
};
|
||||
|
||||
/**
|
||||
* Gets an option value
|
||||
* @param key - Option key
|
||||
* @param fallback - Fallback value
|
||||
* @returns Option value or fallback
|
||||
*/
|
||||
export const getOption = async (
|
||||
key: string,
|
||||
fallback?: string | boolean | number
|
||||
): Promise<string | boolean | number | undefined> => {
|
||||
try {
|
||||
const options = await runQuery(`select * from options where key='${key}'`);
|
||||
if (options.length) {
|
||||
return options[0].value;
|
||||
}
|
||||
|
||||
return fallback;
|
||||
} catch (e) {
|
||||
return fallback;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Sets an option value
|
||||
* @param key - Option key
|
||||
* @param value - Option value
|
||||
*/
|
||||
export const setOption = async (key: string, value: string): Promise<void> => {
|
||||
await runQuery(`insert or replace into options (key, value) values ('${key}', '${value}')`);
|
||||
};
|
||||
|
||||
/**
|
||||
* Deletes an option
|
||||
* @param key - Option key
|
||||
*/
|
||||
export const deleteOption = async (key: string): Promise<void> => {
|
||||
await runQuery(` DELETE FROM options where key='${key}'`);
|
||||
};
|
||||
|
||||
/**
|
||||
* Gets multiple options
|
||||
* @param keys - Option keys
|
||||
* @returns Options data
|
||||
*/
|
||||
export const getOptions = async (keys: string[]): Promise<Record<string, string | boolean | number>> => {
|
||||
const options = await runQuery(`select * from options where key in ('${keys.join("','")}')`);
|
||||
return options.reduce((acc: any, option: any) => {
|
||||
acc[option.key] = option.value;
|
||||
return acc;
|
||||
}, {});
|
||||
};
|
||||
@@ -19,7 +19,7 @@ export const logError = (e: any) => {
|
||||
};
|
||||
export const logInfo = console.info;
|
||||
|
||||
export const addIssueToPersistanceLayer = async (issue: TIssue) => {
|
||||
export const addIssueToPersistenceLayer = async (issue: TIssue) => {
|
||||
try {
|
||||
const issuePartial = pick({ ...JSON.parse(JSON.stringify(issue)) }, [
|
||||
"id",
|
||||
@@ -66,7 +66,7 @@ export const updatePersistentLayer = async (issueIds: string | string[]) => {
|
||||
const issue = rootStore.issue.issues.getIssueById(issueId);
|
||||
|
||||
if (issue) {
|
||||
addIssueToPersistanceLayer(issue);
|
||||
addIssueToPersistenceLayer(issue);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
@@ -72,6 +72,10 @@ export class DBClass {
|
||||
async exec(props: string | TQueryProps) {
|
||||
// @todo this will fail if the transaction is started any other way
|
||||
// eg: BEGIN, OR BEGIN TRANSACTION
|
||||
|
||||
// Below code ensures the transactions are queued
|
||||
// Ideally we should never have multiple transactions
|
||||
// running at the same time, in rare cases, it shouldn't be waiting for more than 1ms
|
||||
if (props === "BEGIN;") {
|
||||
let promiseToAwait;
|
||||
if (this.tp.length > 0) {
|
||||
|
||||
@@ -5,7 +5,7 @@ import { TIssue, TInboxIssue, TInboxIssueStatus, TInboxDuplicateIssueDetails } f
|
||||
// helpers
|
||||
import { EInboxIssueStatus } from "@/helpers/inbox.helper";
|
||||
// local db
|
||||
import { addIssueToPersistanceLayer } from "@/local-db/utils/utils";
|
||||
import { addIssueToPersistenceLayer } from "@/local-db/utils/utils";
|
||||
// services
|
||||
import { InboxIssueService } from "@/services/inbox";
|
||||
import { IssueService } from "@/services/issue";
|
||||
@@ -98,7 +98,7 @@ export class InboxIssueStore implements IInboxIssueStore {
|
||||
|
||||
// If issue accepted sync issue to local db
|
||||
if (status === EInboxIssueStatus.ACCEPTED) {
|
||||
addIssueToPersistanceLayer({ ...this.issue, ...inboxIssue.issue });
|
||||
addIssueToPersistenceLayer({ ...this.issue, ...inboxIssue.issue });
|
||||
}
|
||||
} catch {
|
||||
runInAction(() => set(this, "status", previousData.status));
|
||||
|
||||
@@ -23,7 +23,7 @@ import { EDraftIssuePaginationType } from "@/constants/workspace-drafts";
|
||||
// helpers
|
||||
import { getCurrentDateTimeInISO, convertToISODateString } from "@/helpers/date-time.helper";
|
||||
// local-db
|
||||
import { addIssueToPersistanceLayer } from "@/local-db/utils/utils";
|
||||
import { addIssueToPersistenceLayer } from "@/local-db/utils/utils";
|
||||
// services
|
||||
import workspaceDraftService from "@/services/issue/workspace_draft.service";
|
||||
// types
|
||||
@@ -352,7 +352,7 @@ export class WorkspaceDraftIssues implements IWorkspaceDraftIssues {
|
||||
}
|
||||
|
||||
// sync issue to local db
|
||||
addIssueToPersistanceLayer({ ...payload, ...response });
|
||||
addIssueToPersistenceLayer({ ...payload, ...response });
|
||||
|
||||
// Update draft issue count in workspaceUserInfo
|
||||
this.updateWorkspaceUserDraftIssueCount(workspaceSlug, -1);
|
||||
|
||||
Reference in New Issue
Block a user