From e0ad9eae5aecdfed4674adcdc7f033918cef3dfd Mon Sep 17 00:00:00 2001 From: Henry Heino Date: Mon, 9 Dec 2024 22:24:39 -0800 Subject: [PATCH 1/8] WIP: Improve sync status message --- packages/lib/Synchronizer.ts | 88 ++++++++++++++++--- .../synchronizer/utils/syncDeleteStep.ts | 2 +- .../lib/services/synchronizer/utils/types.ts | 12 +++ 3 files changed, 87 insertions(+), 15 deletions(-) diff --git a/packages/lib/Synchronizer.ts b/packages/lib/Synchronizer.ts index afef7ac757..001a305d28 100644 --- a/packages/lib/Synchronizer.ts +++ b/packages/lib/Synchronizer.ts @@ -30,7 +30,7 @@ import handleConflictAction from './services/synchronizer/utils/handleConflictAc import resourceRemotePath from './services/synchronizer/utils/resourceRemotePath'; import syncDeleteStep from './services/synchronizer/utils/syncDeleteStep'; import { ErrorCode } from './errors'; -import { SyncAction } from './services/synchronizer/utils/types'; +import { SyncAction, SyncReport, SyncReportItemCounts } from './services/synchronizer/utils/types'; import checkDisabledSyncItemsNotification from './services/synchronizer/utils/checkDisabledSyncItemsNotification'; const { sprintf } = require('sprintf-js'); const { Dirnames } = require('./services/synchronizer/utils/types'); @@ -193,15 +193,62 @@ export default class Synchronizer { return `${duration}ms`; } - // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied - public static reportToLines(report: any) { + public static reportToLines(report: SyncReport) { + const formatItemCounts = (counts: SyncReportItemCounts) => { + const includedKeyNames: string[] = []; + let hasOther = false; + + let sum = 0; + for (const [key, value] of Object.entries(counts)) { + if (value) { + sum += value; + + if (key === 'Revision') { + includedKeyNames.push(_('revisions')); + } else if (key === 'Note') { + includedKeyNames.push(_('notes')); + } else if (key === 'Resource') { + includedKeyNames.push(_('resources')); + } else if (key === 'Folder') { + includedKeyNames.push(_('notebooks')); + } else { + hasOther = true; + } + } + } + + // In some cases, no type information is available (e.g. when creating local items). + // In these cases, avoid logging "other", because that might be inaccurate. + if (hasOther && includedKeyNames.length > 0) { + includedKeyNames.push(_('other')); + } + + if (includedKeyNames.length > 0) { + return _('%d (%s)', sum, includedKeyNames.join(', ')); + } else { + return _('%d', sum); + } + }; + const lines = []; - if (report.createLocal) lines.push(_('Created local items: %d.', report.createLocal)); - if (report.updateLocal) lines.push(_('Updated local items: %d.', report.updateLocal)); - if (report.createRemote) lines.push(_('Created remote items: %d.', report.createRemote)); - if (report.updateRemote) lines.push(_('Updated remote items: %d.', report.updateRemote)); - if (report.deleteLocal) lines.push(_('Deleted local items: %d.', report.deleteLocal)); - if (report.deleteRemote) lines.push(_('Deleted remote items: %d.', report.deleteRemote)); + if (report.createLocal) { + lines.push(_('Created local: %s.', formatItemCounts(report.createLocal))); + } + if (report.updateLocal) { + lines.push(_('Updated local: %s.', formatItemCounts(report.updateLocal))); + } + if (report.createRemote) { + lines.push(_('Created remote: %s.', formatItemCounts(report.createRemote))); + } + if (report.updateRemote) { + lines.push(_('Updated remote: %s.', formatItemCounts(report.updateRemote))); + } + if (report.deleteLocal) { + lines.push(_('Deleted local: %s.', formatItemCounts(report.deleteLocal))); + } + if (report.deleteRemote) { + lines.push(_('Deleted remote: %s.', formatItemCounts(report.deleteRemote))); + } if (report.fetchingTotal && report.fetchingProcessed) lines.push(_('Fetched items: %d/%d.', report.fetchingProcessed, report.fetchingTotal)); if (report.cancelling && !report.completedTime) lines.push(_('Cancelling...')); if (report.completedTime) lines.push(_('Completed: %s (%s)', time.formatMsToLocal(report.completedTime), this.completionTime(report))); @@ -216,10 +263,13 @@ export default class Synchronizer { line.push(action); if (message) line.push(message); - let type = local && local.type_ ? local.type_ : null; - if (!type) type = remote && remote.type_ ? remote.type_ : null; + const type: ModelType|null = local?.type_ ?? remote?.type_ ?? null; - if (type) line.push(BaseItem.modelTypeToClassName(type)); + let modelName = 'unknown'; + if (type) { + modelName = BaseItem.modelTypeToClassName(type); + line.push(modelName); + } if (local) { const s = []; @@ -241,8 +291,18 @@ export default class Synchronizer { if (!['fetchingProcessed', 'fetchingTotal'].includes(action)) syncDebugLog.info(line.join(': ')); - if (!this.progressReport_[action]) this.progressReport_[action] = 0; - this.progressReport_[action] += actionCount; + // Actions that are categorized by per-item-type + const itemActions: string[] = [ + SyncAction.CreateLocal, SyncAction.CreateRemote, SyncAction.UpdateLocal, SyncAction.UpdateRemote, SyncAction.DeleteLocal, SyncAction.DeleteRemote, + ]; + if (itemActions.includes(action)) { + this.progressReport_[action] = { ...this.progressReport_[action] }; + this.progressReport_[action][modelName] ??= 0; + this.progressReport_[action][modelName] += actionCount; + } else { + this.progressReport_[action] ??= 0; + this.progressReport_[action] += actionCount; + } this.progressReport_.state = this.state(); this.onProgress_(this.progressReport_); diff --git a/packages/lib/services/synchronizer/utils/syncDeleteStep.ts b/packages/lib/services/synchronizer/utils/syncDeleteStep.ts index 63f16b091d..22d45f1e01 100644 --- a/packages/lib/services/synchronizer/utils/syncDeleteStep.ts +++ b/packages/lib/services/synchronizer/utils/syncDeleteStep.ts @@ -24,7 +24,7 @@ export default async (syncTargetId: number, cancelling: boolean, logSyncOperatio await apiCall('delete', remoteContentPath); } - logSyncOperation(SyncAction.DeleteRemote, null, { id: item.item_id }, 'local has been deleted'); + logSyncOperation(SyncAction.DeleteRemote, null, { type_: item.item_type, id: item.item_id }, 'local has been deleted'); } catch (error) { if (error.code === 'isReadOnly') { let remoteContent = await apiCall('get', path); diff --git a/packages/lib/services/synchronizer/utils/types.ts b/packages/lib/services/synchronizer/utils/types.ts index c7b2aed74f..77e98ca572 100644 --- a/packages/lib/services/synchronizer/utils/types.ts +++ b/packages/lib/services/synchronizer/utils/types.ts @@ -18,6 +18,18 @@ export enum SyncAction { DeleteLocal = 'deleteLocal', } +export type SyncReportItemCounts = Record; +type SyncReportItemSection = Partial>; + +export type SyncReport = SyncReportItemSection & { + fetchingTotal?: number; + fetchingProcessed?: number; + cancelling?: boolean; + startTime?: number; + completedTime?: number; + errors?: string[]; +}; + // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied export type LogSyncOperationFunction = (action: SyncAction, local?: any, remote?: RemoteItem, message?: string, actionCount?: number)=> void; From 2a389945542028cc25669948114cd4cc7c961b58 Mon Sep 17 00:00:00 2001 From: Henry Heino Date: Tue, 10 Dec 2024 21:00:09 -0800 Subject: [PATCH 2/8] Attempt to make sync status message less confusing --- packages/lib/Synchronizer.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/lib/Synchronizer.ts b/packages/lib/Synchronizer.ts index 001a305d28..db7192dc4f 100644 --- a/packages/lib/Synchronizer.ts +++ b/packages/lib/Synchronizer.ts @@ -32,6 +32,7 @@ import syncDeleteStep from './services/synchronizer/utils/syncDeleteStep'; import { ErrorCode } from './errors'; import { SyncAction, SyncReport, SyncReportItemCounts } from './services/synchronizer/utils/types'; import checkDisabledSyncItemsNotification from './services/synchronizer/utils/checkDisabledSyncItemsNotification'; +import { substrWithEllipsis } from './string-utils'; const { sprintf } = require('sprintf-js'); const { Dirnames } = require('./services/synchronizer/utils/types'); @@ -204,7 +205,7 @@ export default class Synchronizer { sum += value; if (key === 'Revision') { - includedKeyNames.push(_('revisions')); + includedKeyNames.push(_('old note versions')); } else if (key === 'Note') { includedKeyNames.push(_('notes')); } else if (key === 'Resource') { @@ -224,7 +225,8 @@ export default class Synchronizer { } if (includedKeyNames.length > 0) { - return _('%d (%s)', sum, includedKeyNames.join(', ')); + const shortenedDescription = substrWithEllipsis(includedKeyNames.join(', '), 0, 24); + return _('%d (%s)', sum, shortenedDescription); } else { return _('%d', sum); } From 6389817b4319f6aca5bcbf6c3b4460f8808a1884 Mon Sep 17 00:00:00 2001 From: Henry Heino Date: Tue, 10 Dec 2024 22:12:50 -0800 Subject: [PATCH 3/8] Refactoring and testing --- .eslintignore | 1 + .gitignore | 1 + .../utils/testing/createMockReduxStore.ts | 9 +-- packages/lib/Synchronizer.ts | 28 ++++---- .../synchronizer/Synchronizer.report.test.ts | 65 +++++++++++++++++++ .../lib/services/synchronizer/utils/types.ts | 11 +++- packages/lib/testing/test-utils.ts | 11 +++- 7 files changed, 103 insertions(+), 23 deletions(-) create mode 100644 packages/lib/services/synchronizer/Synchronizer.report.test.ts diff --git a/.eslintignore b/.eslintignore index fa88ee67e3..8ac59edcf9 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1345,6 +1345,7 @@ packages/lib/services/synchronizer/Synchronizer.basics.test.js packages/lib/services/synchronizer/Synchronizer.conflicts.test.js packages/lib/services/synchronizer/Synchronizer.e2ee.test.js packages/lib/services/synchronizer/Synchronizer.ppk.test.js +packages/lib/services/synchronizer/Synchronizer.report.test.js packages/lib/services/synchronizer/Synchronizer.resources.test.js packages/lib/services/synchronizer/Synchronizer.revisions.test.js packages/lib/services/synchronizer/Synchronizer.sharing.test.js diff --git a/.gitignore b/.gitignore index daf97879a7..390745b72e 100644 --- a/.gitignore +++ b/.gitignore @@ -1321,6 +1321,7 @@ packages/lib/services/synchronizer/Synchronizer.basics.test.js packages/lib/services/synchronizer/Synchronizer.conflicts.test.js packages/lib/services/synchronizer/Synchronizer.e2ee.test.js packages/lib/services/synchronizer/Synchronizer.ppk.test.js +packages/lib/services/synchronizer/Synchronizer.report.test.js packages/lib/services/synchronizer/Synchronizer.resources.test.js packages/lib/services/synchronizer/Synchronizer.revisions.test.js packages/lib/services/synchronizer/Synchronizer.sharing.test.js diff --git a/packages/app-mobile/utils/testing/createMockReduxStore.ts b/packages/app-mobile/utils/testing/createMockReduxStore.ts index a4c41d45d7..ea9a5937e2 100644 --- a/packages/app-mobile/utils/testing/createMockReduxStore.ts +++ b/packages/app-mobile/utils/testing/createMockReduxStore.ts @@ -1,5 +1,4 @@ -import reducer from '@joplin/lib/reducer'; -import { createStore } from 'redux'; +import { createReduxStore } from '@joplin/lib/testing/test-utils'; import appDefaultState from '../appDefaultState'; import Setting from '@joplin/lib/models/Setting'; @@ -9,11 +8,7 @@ const defaultState = { settings: { theme: Setting.THEME_LIGHT }, }; -const testReducer = (state = defaultState, action: unknown) => { - return reducer(state, action); -}; - const createMockReduxStore = () => { - return createStore(testReducer); + return createReduxStore(defaultState); }; export default createMockReduxStore; diff --git a/packages/lib/Synchronizer.ts b/packages/lib/Synchronizer.ts index db7192dc4f..0576b080a5 100644 --- a/packages/lib/Synchronizer.ts +++ b/packages/lib/Synchronizer.ts @@ -30,7 +30,7 @@ import handleConflictAction from './services/synchronizer/utils/handleConflictAc import resourceRemotePath from './services/synchronizer/utils/resourceRemotePath'; import syncDeleteStep from './services/synchronizer/utils/syncDeleteStep'; import { ErrorCode } from './errors'; -import { SyncAction, SyncReport, SyncReportItemCounts } from './services/synchronizer/utils/types'; +import { SyncAction, SyncReport, ItemCountPerType } from './services/synchronizer/utils/types'; import checkDisabledSyncItemsNotification from './services/synchronizer/utils/checkDisabledSyncItemsNotification'; import { substrWithEllipsis } from './string-utils'; const { sprintf } = require('sprintf-js'); @@ -83,8 +83,7 @@ export default class Synchronizer { // eslint-disable-next-line @typescript-eslint/ban-types -- Old code before rule was applied private onProgress_: Function; - // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied - private progressReport_: any = {}; + private progressReport_: SyncReport = {}; // eslint-disable-next-line @typescript-eslint/ban-types -- Old code before rule was applied public dispatch: Function; @@ -195,7 +194,7 @@ export default class Synchronizer { } public static reportToLines(report: SyncReport) { - const formatItemCounts = (counts: SyncReportItemCounts) => { + const formatItemCounts = (counts: ItemCountPerType) => { const includedKeyNames: string[] = []; let hasOther = false; @@ -294,14 +293,15 @@ export default class Synchronizer { if (!['fetchingProcessed', 'fetchingTotal'].includes(action)) syncDebugLog.info(line.join(': ')); // Actions that are categorized by per-item-type - const itemActions: string[] = [ - SyncAction.CreateLocal, SyncAction.CreateRemote, SyncAction.UpdateLocal, SyncAction.UpdateRemote, SyncAction.DeleteLocal, SyncAction.DeleteRemote, - ]; - if (itemActions.includes(action)) { + const isItemAction = (testAction: string): testAction is SyncAction => { + const syncActions: string[] = Object.values(SyncAction); + return syncActions.includes(testAction); + }; + if (isItemAction(action)) { this.progressReport_[action] = { ...this.progressReport_[action] }; this.progressReport_[action][modelName] ??= 0; this.progressReport_[action][modelName] += actionCount; - } else { + } else if (action === 'fetchingProcessed' || action === 'fetchingTotal') { this.progressReport_[action] ??= 0; this.progressReport_[action] += actionCount; } @@ -313,13 +313,14 @@ export default class Synchronizer { // for this but for now this simple fix will do. // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied const reportCopy: any = {}; - for (const n in this.progressReport_) reportCopy[n] = this.progressReport_[n]; + for (const [key, value] of Object.entries(this.progressReport_)) { + reportCopy[key] = value; + } if (reportCopy.errors) reportCopy.errors = this.progressReport_.errors.slice(); this.dispatch({ type: 'SYNC_REPORT_UPDATE', report: reportCopy }); } - // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied - public async logSyncSummary(report: any) { + public async logSyncSummary(report: SyncReport) { logger.info('Operations completed: '); for (const n in report) { if (!report.hasOwnProperty(n)) continue; @@ -329,7 +330,8 @@ export default class Synchronizer { if (n === 'state') continue; if (n === 'startTime') continue; if (n === 'completedTime') continue; - logger.info(`${n}: ${report[n] ? report[n] : '-'}`); + const key = n as keyof typeof report; + logger.info(`${n}: ${report[key] ? report[key] : '-'}`); } const folderCount = await Folder.count(); const noteCount = await Note.count(); diff --git a/packages/lib/services/synchronizer/Synchronizer.report.test.ts b/packages/lib/services/synchronizer/Synchronizer.report.test.ts new file mode 100644 index 0000000000..9d257028bc --- /dev/null +++ b/packages/lib/services/synchronizer/Synchronizer.report.test.ts @@ -0,0 +1,65 @@ +import { Store } from 'redux'; +import { State } from '../../reducer'; +import Folder from '../../models/Folder'; +import Note from '../../models/Note'; +import Synchronizer from '../../Synchronizer'; +import { createReduxStore, setupDatabaseAndSynchronizer, switchClient, synchronizer, synchronizerStart } from '../../testing/test-utils'; + +let appStoreClient2: Store; +const getClient2SyncReport = () => { + return appStoreClient2.getState().syncReport; +}; + +describe('Synchronizer.report', () => { + + beforeEach(async () => { + await setupDatabaseAndSynchronizer(1); + await setupDatabaseAndSynchronizer(2); + await switchClient(1); + + appStoreClient2 = createReduxStore(); + synchronizer(2).dispatch = appStoreClient2.dispatch; + }); + + test('should list the different kinds of items that were deleted', async () => { + const folder = await Folder.save({ title: 'Test folder' }); + await Note.save({ title: 'Note 1', parent_id: folder.id }); + const note2 = await Note.save({ title: 'Note 2' }); + + // Ensure that client 2 creates the items + await synchronizerStart(); + await switchClient(2); + await synchronizerStart(); + + await Note.delete(note2.id, { toTrash: false }); + await synchronizerStart(); + + // Deleting a remote item: Should list item types + expect(getClient2SyncReport()).toMatchObject({ + deleteRemote: { + Note: 1, + }, + }); + expect(Synchronizer.reportToLines(getClient2SyncReport())[0]).toBe( + 'Deleted remote: 1 (notes).', + ); + + // Delete a remote folder + await switchClient(1); + await Folder.delete(folder.id); + await synchronizerStart(); + await switchClient(2); + + // Deleting local items: Sync report should include type descriptions: + await synchronizerStart(); + expect(getClient2SyncReport()).toMatchObject({ + deleteLocal: { + Note: 1, + Folder: 1, + }, + }); + expect(Synchronizer.reportToLines(getClient2SyncReport())[0]).toBe( + 'Deleted local: 2 (notes, notebooks).', + ); + }); +}); diff --git a/packages/lib/services/synchronizer/utils/types.ts b/packages/lib/services/synchronizer/utils/types.ts index 77e98ca572..a3a7cfd42a 100644 --- a/packages/lib/services/synchronizer/utils/types.ts +++ b/packages/lib/services/synchronizer/utils/types.ts @@ -18,12 +18,19 @@ export enum SyncAction { DeleteLocal = 'deleteLocal', } -export type SyncReportItemCounts = Record; -type SyncReportItemSection = Partial>; +export interface ItemCountPerType { + [modelType: string]: number; +} + +type SyncReportItemSection = { + [action in SyncAction]?: ItemCountPerType; +}; export type SyncReport = SyncReportItemSection & { fetchingTotal?: number; fetchingProcessed?: number; + + state?: string; cancelling?: boolean; startTime?: number; completedTime?: number; diff --git a/packages/lib/testing/test-utils.ts b/packages/lib/testing/test-utils.ts index 9812a78e65..1bc22e1d97 100644 --- a/packages/lib/testing/test-utils.ts +++ b/packages/lib/testing/test-utils.ts @@ -67,7 +67,8 @@ import OcrDriverTesseract from '../services/ocr/drivers/OcrDriverTesseract'; import OcrService from '../services/ocr/OcrService'; import { createWorker } from 'tesseract.js'; import { reg } from '../registry'; -import { Store } from 'redux'; +import { createStore, Store } from 'redux'; +import reducer, { defaultState as defaultAppState, State as AppState } from '../reducer'; // Each suite has its own separate data and temp directory so that multiple // suites can be run at the same time. suiteName is what is used to @@ -453,6 +454,14 @@ const createNoteAndResource = async (options: CreateNoteAndResourceOptions = nul return { note, resource }; }; +export const createReduxStore = (defaultState: AppState = defaultAppState) => { + const mockReducer = (state: AppState = defaultState, action: unknown) => { + return reducer(state, action); + }; + + return createStore(mockReducer); +}; + // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied async function setupDatabaseAndSynchronizer(id: number, options: any = null) { if (id === null) id = currentClient_; From 7c9a31895ac58eb1867952c23ebf0451c637a571 Mon Sep 17 00:00:00 2001 From: Henry Heino Date: Tue, 10 Dec 2024 22:18:01 -0800 Subject: [PATCH 4/8] Change description of note revisions to "note history" --- packages/lib/Synchronizer.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/lib/Synchronizer.ts b/packages/lib/Synchronizer.ts index 0576b080a5..8046ab2321 100644 --- a/packages/lib/Synchronizer.ts +++ b/packages/lib/Synchronizer.ts @@ -204,7 +204,7 @@ export default class Synchronizer { sum += value; if (key === 'Revision') { - includedKeyNames.push(_('old note versions')); + includedKeyNames.push(_('note history')); } else if (key === 'Note') { includedKeyNames.push(_('notes')); } else if (key === 'Resource') { From 06407390ca32e0335359acf1ef76908e1d0f79fa Mon Sep 17 00:00:00 2001 From: Henry Heino Date: Tue, 10 Dec 2024 22:28:44 -0800 Subject: [PATCH 5/8] Remove possibly-confusing message truncation --- packages/lib/Synchronizer.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/lib/Synchronizer.ts b/packages/lib/Synchronizer.ts index 8046ab2321..44526529de 100644 --- a/packages/lib/Synchronizer.ts +++ b/packages/lib/Synchronizer.ts @@ -32,7 +32,6 @@ import syncDeleteStep from './services/synchronizer/utils/syncDeleteStep'; import { ErrorCode } from './errors'; import { SyncAction, SyncReport, ItemCountPerType } from './services/synchronizer/utils/types'; import checkDisabledSyncItemsNotification from './services/synchronizer/utils/checkDisabledSyncItemsNotification'; -import { substrWithEllipsis } from './string-utils'; const { sprintf } = require('sprintf-js'); const { Dirnames } = require('./services/synchronizer/utils/types'); @@ -224,8 +223,7 @@ export default class Synchronizer { } if (includedKeyNames.length > 0) { - const shortenedDescription = substrWithEllipsis(includedKeyNames.join(', '), 0, 24); - return _('%d (%s)', sum, shortenedDescription); + return _('%d (%s)', sum, includedKeyNames.join(', ')); } else { return _('%d', sum); } From b00db061a7212ad6fe6cc05084fe7b0f976c3a3b Mon Sep 17 00:00:00 2001 From: Henry Heino Date: Tue, 10 Dec 2024 22:44:03 -0800 Subject: [PATCH 6/8] Rename includedKeyNames -> modifiedItemNames --- packages/lib/Synchronizer.ts | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/packages/lib/Synchronizer.ts b/packages/lib/Synchronizer.ts index 44526529de..2cda0ca8ab 100644 --- a/packages/lib/Synchronizer.ts +++ b/packages/lib/Synchronizer.ts @@ -194,7 +194,7 @@ export default class Synchronizer { public static reportToLines(report: SyncReport) { const formatItemCounts = (counts: ItemCountPerType) => { - const includedKeyNames: string[] = []; + const modifiedItemNames: string[] = []; let hasOther = false; let sum = 0; @@ -203,13 +203,13 @@ export default class Synchronizer { sum += value; if (key === 'Revision') { - includedKeyNames.push(_('note history')); + modifiedItemNames.push(_('note history')); } else if (key === 'Note') { - includedKeyNames.push(_('notes')); + modifiedItemNames.push(_('notes')); } else if (key === 'Resource') { - includedKeyNames.push(_('resources')); + modifiedItemNames.push(_('resources')); } else if (key === 'Folder') { - includedKeyNames.push(_('notebooks')); + modifiedItemNames.push(_('notebooks')); } else { hasOther = true; } @@ -218,12 +218,12 @@ export default class Synchronizer { // In some cases, no type information is available (e.g. when creating local items). // In these cases, avoid logging "other", because that might be inaccurate. - if (hasOther && includedKeyNames.length > 0) { - includedKeyNames.push(_('other')); + if (hasOther && modifiedItemNames.length > 0) { + modifiedItemNames.push(_('other')); } - if (includedKeyNames.length > 0) { - return _('%d (%s)', sum, includedKeyNames.join(', ')); + if (modifiedItemNames.length > 0) { + return _('%d (%s)', sum, modifiedItemNames.join(', ')); } else { return _('%d', sum); } From 6021955187a69da291d1319a189853ed93c2beb5 Mon Sep 17 00:00:00 2001 From: Henry Heino Date: Tue, 10 Dec 2024 22:46:19 -0800 Subject: [PATCH 7/8] Simplify sync report test --- .../services/synchronizer/Synchronizer.report.test.ts | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/packages/lib/services/synchronizer/Synchronizer.report.test.ts b/packages/lib/services/synchronizer/Synchronizer.report.test.ts index 9d257028bc..eafc93e178 100644 --- a/packages/lib/services/synchronizer/Synchronizer.report.test.ts +++ b/packages/lib/services/synchronizer/Synchronizer.report.test.ts @@ -35,11 +35,6 @@ describe('Synchronizer.report', () => { await synchronizerStart(); // Deleting a remote item: Should list item types - expect(getClient2SyncReport()).toMatchObject({ - deleteRemote: { - Note: 1, - }, - }); expect(Synchronizer.reportToLines(getClient2SyncReport())[0]).toBe( 'Deleted remote: 1 (notes).', ); @@ -52,12 +47,6 @@ describe('Synchronizer.report', () => { // Deleting local items: Sync report should include type descriptions: await synchronizerStart(); - expect(getClient2SyncReport()).toMatchObject({ - deleteLocal: { - Note: 1, - Folder: 1, - }, - }); expect(Synchronizer.reportToLines(getClient2SyncReport())[0]).toBe( 'Deleted local: 2 (notes, notebooks).', ); From 4fd9e4537e5980403dfc3ac79fdded84379dc9ca Mon Sep 17 00:00:00 2001 From: Henry Heino Date: Tue, 10 Dec 2024 22:55:58 -0800 Subject: [PATCH 8/8] Fix tsc errors --- packages/lib/testing/test-utils.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/lib/testing/test-utils.ts b/packages/lib/testing/test-utils.ts index 1bc22e1d97..f621167415 100644 --- a/packages/lib/testing/test-utils.ts +++ b/packages/lib/testing/test-utils.ts @@ -454,12 +454,14 @@ const createNoteAndResource = async (options: CreateNoteAndResourceOptions = nul return { note, resource }; }; -export const createReduxStore = (defaultState: AppState = defaultAppState) => { +export const createReduxStore = ( + defaultState: StateType = defaultAppState as StateType, +) => { const mockReducer = (state: AppState = defaultState, action: unknown) => { return reducer(state, action); }; - return createStore(mockReducer); + return createStore(mockReducer) as Store; }; // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied