refactor(nbstore): improve doc state management (#12359)

Move the `waitForSynced` method from `frontend` to `nbstore worker` to make the wait more reliable

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->
## Summary by CodeRabbit

- **New Features**
  - Added explicit tracking of document updating state to indicate when data is being applied or saved.
  - Introduced new methods to wait for update and synchronization completion with abort support.

- **Improvements**
  - Applied throttling with leading and trailing emissions to state observables for smoother UI updates.
  - Refined synchronization waiting logic for clearer separation between update completion and sync completion.
  - Removed throttling in workspace selector component for more immediate state feedback.
  - Updated import and clipper services to use the new synchronization waiting methods.
  - Simplified asynchronous waiting logic in indexer synchronization methods.

- **Bug Fixes**
  - Enhanced accuracy and reliability of document update and sync status indicators.

- **Tests**
  - Increased wait timeout in avatar selection test to improve stability.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
EYHN
2025-05-20 07:33:20 +00:00
parent 151f499154
commit 59ef4b227b
10 changed files with 157 additions and 167 deletions

View File

@@ -88,7 +88,7 @@ const useSyncEngineSyncProgress = (meta: WorkspaceMetadata) => {
const engineState = useLiveData(
useMemo(() => {
return workspace
? LiveData.from(workspace.engine.doc.state$, null).throttleTime(500)
? LiveData.from(workspace.engine.doc.state$, null)
: null;
}, [workspace])
);

View File

@@ -8,15 +8,7 @@ import {
onStart,
} from '@toeverything/infra';
import { fileTypeFromBuffer } from 'file-type';
import {
filter,
firstValueFrom,
fromEvent,
map,
switchMap,
takeUntil,
tap,
} from 'rxjs';
import { switchMap, tap } from 'rxjs';
import type { DocsSearchService } from '../../docs-search';
import type { WorkspaceService } from '../../workspace';
@@ -85,15 +77,7 @@ export class UnusedBlobs extends Entity {
async getUnusedBlobs(abortSignal?: AbortSignal) {
// Wait for both sync and indexing to complete
const ready$ = this.workspaceService.workspace.engine.doc.state$
.pipe(filter(state => state.syncing === 0 && !state.syncRetrying))
.pipe(map(() => true));
await firstValueFrom(
abortSignal
? ready$.pipe(takeUntil(fromEvent(abortSignal, 'abort')))
: ready$
);
await this.workspaceService.workspace.engine.doc.waitForSynced();
await this.docsSearchService.indexer.waitForCompleted(abortSignal);

View File

@@ -44,8 +44,8 @@ export class ImportClipperService extends Service {
docsService.list.setPrimaryMode(docId, 'page');
workspace.engine.doc.addPriority(workspace.id, 100);
workspace.engine.doc.addPriority(docId, 100);
await workspace.engine.doc.waitForDocSynced(workspace.id);
await workspace.engine.doc.waitForDocSynced(docId);
await workspace.engine.doc.waitForSynced(workspace.id);
await workspace.engine.doc.waitForSynced(docId);
disposeWorkspace();
return docId;
} else {