Skip to content

Commit

Permalink
Merge pull request #540 from refly-ai/fix/alert-issues-250228
Browse files Browse the repository at this point in the history
fix: alert issues
  • Loading branch information
mrcfps authored Feb 28, 2025
2 parents 95d5bbe + 3a9a74b commit 07fc1b9
Show file tree
Hide file tree
Showing 7 changed files with 132 additions and 41 deletions.
1 change: 1 addition & 0 deletions .github/workflows/build-image.yml
Original file line number Diff line number Diff line change
Expand Up @@ -60,3 +60,4 @@ jobs:
push: true
tags: |
reflyai/refly-${{ matrix.app }}:${{ github.sha }}
reflyai/refly-${{ matrix.app }}:nightly
30 changes: 23 additions & 7 deletions apps/api/src/canvas/canvas.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,13 +83,29 @@ export class CanvasService {
}

async getCanvasYDoc(stateStorageKey: string) {
const readable = await this.minio.client.getObject(stateStorageKey);
const state = await streamToBuffer(readable);
if (!stateStorageKey) {
return null;
}

const doc = new Y.Doc();
Y.applyUpdate(doc, state);
try {
const readable = await this.minio.client.getObject(stateStorageKey);
if (!readable) {
throw new Error('Canvas state not found');
}

return doc;
const state = await streamToBuffer(readable);
if (!state?.length) {
throw new Error('Canvas state is empty');
}

const doc = new Y.Doc();
Y.applyUpdate(doc, state);

return doc;
} catch (error) {
this.logger.warn(`Error getting canvas YDoc for key ${stateStorageKey}: ${error?.message}`);
return null;
}
}

async saveCanvasYDoc(stateStorageKey: string, doc: Y.Doc) {
Expand Down Expand Up @@ -122,8 +138,8 @@ export class CanvasService {

return {
title: canvas.title,
nodes: doc.getArray('nodes').toJSON(),
edges: doc.getArray('edges').toJSON(),
nodes: doc?.getArray('nodes').toJSON() ?? [],
edges: doc?.getArray('edges').toJSON() ?? [],
isPublic: canvas.isPublic,
};
}
Expand Down
34 changes: 25 additions & 9 deletions packages/ai-workspace-common/src/components/document/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -72,17 +72,33 @@ const StatusBar = memo(
}, [ydoc, docId, setDocumentReadOnly, provider?.status]);

const toggleReadOnly = () => {
ydoc?.transact(() => {
const yReadOnly = ydoc.getText('readOnly');
yReadOnly.delete(0, yReadOnly?.length ?? 0);
yReadOnly.insert(0, (!readOnly).toString());
});
if (!ydoc || provider?.status !== 'connected') {
message.error(t('knowledgeBase.note.connectionError') || 'Connection error');
return;
}

try {
ydoc.transact(() => {
const yReadOnly = ydoc.getText('readOnly');
if (!yReadOnly) return;

yReadOnly.delete(0, yReadOnly.length ?? 0);
yReadOnly.insert(0, (!readOnly).toString());
});

setDocumentReadOnly(docId, !readOnly);
setDocumentReadOnly(docId, !readOnly);

readOnly
? message.success(t('knowledgeBase.note.edit'))
: message.warning(t('knowledgeBase.note.readOnly'));
readOnly
? message.success(t('knowledgeBase.note.edit'))
: message.warning(t('knowledgeBase.note.readOnly'));
} catch (error) {
console.error('Transaction error when toggling read-only:', error);

if (error instanceof DOMException && error.name === 'InvalidStateError') {
console.warn('Database connection is closing. Transaction aborted.');
message.error(t('knowledgeBase.note.databaseError') || 'Database connection error');
}
}
};

const handleCopy = () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,12 @@ const UpdatedImage = Image.extend({
...this.parent?.(),
src: {
default: '',
parseHTML: (element) => element.getAttribute('src') || '',
parseHTML: (element) => {
const src = element?.getAttribute('src');
return src ?? '';
},
renderHTML: (attributes) => ({
src: attributes.src || '',
src: attributes?.src ?? '',
}),
},
width: {
Expand Down
50 changes: 40 additions & 10 deletions packages/ai-workspace-common/src/hooks/canvas/use-canvas-sync.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,27 +23,57 @@ export const useCanvasSync = () => {
}, [ydoc]);

const syncFunctions = useMemo(() => {
const isProviderActive = () => {
return ydoc && provider?.status === 'connected';
};

const safeTransaction = (transactionFn: () => void) => {
if (!isProviderActive()) return;

try {
ydoc?.transact(transactionFn);
} catch (error) {
// Log the error but don't crash the application
console.error('Transaction error:', error);

// If we get an InvalidStateError, we could implement reconnection logic here
if (error instanceof DOMException && error.name === 'InvalidStateError') {
console.warn('Database connection is closing. Transaction aborted.');
}
}
};

const syncTitleToYDoc = (title: string) => {
ydoc?.transact(() => {
safeTransaction(() => {
const yTitle = ydoc?.getText('title');
yTitle?.delete(0, yTitle?.length ?? 0);
yTitle?.insert(0, title);
if (!yTitle) return;

yTitle.delete(0, yTitle.length ?? 0);
yTitle.insert(0, title);
});
};

const syncNodesToYDoc = (nodes: CanvasNode<any>[]) => {
ydoc?.transact(() => {
if (!nodes?.length) return;

safeTransaction(() => {
const yNodes = ydoc?.getArray('nodes');
yNodes?.delete(0, yNodes?.length ?? 0);
yNodes?.push(nodes);
if (!yNodes) return;

yNodes.delete(0, yNodes.length ?? 0);
yNodes.push(nodes);
});
};

const syncEdgesToYDoc = (edges: Edge[]) => {
ydoc?.transact(() => {
if (!edges?.length) return;

safeTransaction(() => {
const yEdges = ydoc?.getArray('edges');
yEdges?.delete(0, yEdges?.length ?? 0);
yEdges?.push(edges.map((edge) => omit(edge, ['style'])));
if (!yEdges) return;

yEdges.delete(0, yEdges.length ?? 0);
yEdges.push(edges.map((edge) => omit(edge, ['style'])));
});
};

Expand All @@ -52,7 +82,7 @@ export const useCanvasSync = () => {
syncNodesToYDoc,
syncEdgesToYDoc,
};
}, [ydoc]);
}, [ydoc, provider]);

const throttledSyncNodesToYDoc = useThrottledCallback(syncFunctions.syncNodesToYDoc, 500, {
leading: true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,26 @@ export const usePatchNodeData = (selectedCanvasId?: string) => {

const syncNodesToYDoc = useCallback(
(nodes: any[]) => {
ydoc?.transact(() => {
const yNodes = ydoc?.getArray('nodes');
yNodes?.delete(0, yNodes?.length ?? 0);
yNodes?.push(nodes);
});
if (!nodes?.length || !ydoc || provider?.status !== 'connected') return;

try {
ydoc.transact(() => {
const yNodes = ydoc.getArray('nodes');
if (!yNodes) return;

yNodes.delete(0, yNodes.length ?? 0);
yNodes.push(nodes);
});
} catch (error) {
console.error('Transaction error when syncing nodes:', error);

// Special handling for database connection closing
if (error instanceof DOMException && error.name === 'InvalidStateError') {
console.warn('Database connection is closing. Transaction aborted.');
}
}
},
[ydoc],
[ydoc, provider],
);

return useCallback(
Expand Down
26 changes: 19 additions & 7 deletions packages/ai-workspace-common/src/hooks/use-document-sync.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,33 @@ import { useMemo } from 'react';
import { useDocumentContext } from '@refly-packages/ai-workspace-common/context/document';

export const useDocumentSync = () => {
const { ydoc } = useDocumentContext();
const { ydoc, provider } = useDocumentContext();

const syncFunctions = useMemo(() => {
const syncTitleToYDoc = (title: string) => {
ydoc?.transact(() => {
const yTitle = ydoc?.getText('title');
yTitle?.delete(0, yTitle?.length ?? 0);
yTitle?.insert(0, title);
});
if (!ydoc || provider?.status !== 'connected') return;

try {
ydoc.transact(() => {
const yTitle = ydoc.getText('title');
if (!yTitle) return;

yTitle.delete(0, yTitle.length ?? 0);
yTitle.insert(0, title);
});
} catch (error) {
console.error('Transaction error when syncing title:', error);

if (error instanceof DOMException && error.name === 'InvalidStateError') {
console.warn('Database connection is closing. Transaction aborted.');
}
}
};

return {
syncTitleToYDoc,
};
}, [ydoc]);
}, [ydoc, provider]);

return syncFunctions;
};

0 comments on commit 07fc1b9

Please sign in to comment.