From 666e23fc12d0c80d3db0ae6412ae08c7964de65c Mon Sep 17 00:00:00 2001 From: Emir Karabeg Date: Tue, 18 Feb 2025 20:02:46 -0800 Subject: [PATCH] feat(sync): syncing workflow deletion --- app/api/db/sync/route.ts | 17 ++++++++++++++--- stores/index.ts | 10 ++++++++-- stores/sync-manager.ts | 14 +++++++++++++- stores/workflow/registry/store.ts | 4 ++++ 4 files changed, 39 insertions(+), 6 deletions(-) diff --git a/app/api/db/sync/route.ts b/app/api/db/sync/route.ts index 2bcac86ef..0e2c61bc3 100644 --- a/app/api/db/sync/route.ts +++ b/app/api/db/sync/route.ts @@ -1,5 +1,5 @@ import { NextResponse } from 'next/server' -import { eq } from 'drizzle-orm' +import { eq, sql } from 'drizzle-orm' import { z } from 'zod' import { getSession } from '@/lib/auth' import { db } from '@/db' @@ -16,6 +16,7 @@ const WorkflowSchema = z.object({ // Define the schema for batch sync const BatchSyncSchema = z.object({ workflows: z.array(WorkflowSchema), + deletedWorkflowIds: z.array(z.string()).optional(), }) export async function POST(request: Request) { @@ -26,11 +27,21 @@ export async function POST(request: Request) { } const body = await request.json() - const { workflows } = BatchSyncSchema.parse(body) + const { workflows, deletedWorkflowIds } = BatchSyncSchema.parse(body) const now = new Date() - // Process all workflows in a single transaction + // Process all operations in a single transaction await db.transaction(async (tx) => { + // Handle deletions first + if (deletedWorkflowIds?.length) { + await tx + .delete(workflow) + .where( + sql`${workflow.id} IN ${deletedWorkflowIds} AND ${workflow.userId} = ${session.user.id}` + ) + } + + // Handle updates/inserts for (const workflowData of workflows) { await tx .insert(workflow) diff --git a/stores/index.ts b/stores/index.ts index 085a70760..4b0926553 100644 --- a/stores/index.ts +++ b/stores/index.ts @@ -4,7 +4,7 @@ import { useExecutionStore } from './execution/store' import { useNotificationStore } from './notifications/store' import { useEnvironmentStore } from './settings/environment/store' import { useGeneralStore } from './settings/general/store' -import { initializeSyncManager } from './sync-manager' +import { addDeletedWorkflow, initializeSyncManager } from './sync-manager' import { useWorkflowRegistry } from './workflow/registry/store' import { useWorkflowStore } from './workflow/store' @@ -15,8 +15,14 @@ if (typeof window !== 'undefined') { // Reset all application stores to their initial state export const resetAllStores = () => { - // Selectively clear localStorage items + // Track all workflow IDs for deletion before clearing if (typeof window !== 'undefined') { + const workflowRegistry = useWorkflowRegistry.getState().workflows + Object.keys(workflowRegistry).forEach((id) => { + addDeletedWorkflow(id) + }) + + // Selectively clear localStorage items const keysToKeep = ['next-favicon'] const keysToRemove = Object.keys(localStorage).filter((key) => !keysToKeep.includes(key)) keysToRemove.forEach((key) => localStorage.removeItem(key)) diff --git a/stores/sync-manager.ts b/stores/sync-manager.ts index cb14e1d5e..065c34246 100644 --- a/stores/sync-manager.ts +++ b/stores/sync-manager.ts @@ -8,12 +8,22 @@ interface WorkflowSyncPayload { state: string } +// Track deleted workflow IDs until they're synced +const deletedWorkflowIds = new Set() + +export function addDeletedWorkflow(id: string) { + deletedWorkflowIds.add(id) +} + async function syncWorkflowsToServer(payloads: WorkflowSyncPayload[]): Promise { try { const response = await fetch('/api/db/sync', { method: 'POST', headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ workflows: payloads }), + body: JSON.stringify({ + workflows: payloads, + deletedWorkflowIds: Array.from(deletedWorkflowIds), + }), keepalive: true, }) @@ -25,6 +35,8 @@ async function syncWorkflowsToServer(payloads: WorkflowSyncPayload[]): Promise()( const newWorkflows = { ...state.workflows } delete newWorkflows[id] + // Track deletion for next sync + addDeletedWorkflow(id) + // Remove workflow state from localStorage localStorage.removeItem(`workflow-${id}`)