You've already forked joplin
							
							
				mirror of
				https://github.com/laurent22/joplin.git
				synced 2025-10-31 00:07:48 +02:00 
			
		
		
		
	Chore: Refactor folder related functions to TypeScript
This commit is contained in:
		| @@ -674,6 +674,7 @@ packages/lib/file-api-driver-memory.js | ||||
| packages/lib/file-api-driver.test.js | ||||
| packages/lib/file-api.test.js | ||||
| packages/lib/file-api.js | ||||
| packages/lib/folders-screen-utils.js | ||||
| packages/lib/fs-driver-base.js | ||||
| packages/lib/fs-driver-node.js | ||||
| packages/lib/fsDriver.test.js | ||||
|   | ||||
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -654,6 +654,7 @@ packages/lib/file-api-driver-memory.js | ||||
| packages/lib/file-api-driver.test.js | ||||
| packages/lib/file-api.test.js | ||||
| packages/lib/file-api.js | ||||
| packages/lib/folders-screen-utils.js | ||||
| packages/lib/fs-driver-base.js | ||||
| packages/lib/fs-driver-node.js | ||||
| packages/lib/fsDriver.test.js | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| const BaseApplication = require('@joplin/lib/BaseApplication').default; | ||||
| const { FoldersScreenUtils } = require('@joplin/lib/folders-screen-utils.js'); | ||||
| const { refreshFolders } = require('@joplin/lib/folders-screen-utils.js'); | ||||
| const ResourceService = require('@joplin/lib/services/ResourceService').default; | ||||
| const BaseModel = require('@joplin/lib/BaseModel').default; | ||||
| const Folder = require('@joplin/lib/models/Folder').default; | ||||
| @@ -435,7 +435,7 @@ class Application extends BaseApplication { | ||||
| 			// initialised. So we manually call dispatchUpdateAll() to force an update. | ||||
| 			Setting.dispatchUpdateAll(); | ||||
|  | ||||
| 			await FoldersScreenUtils.refreshFolders(); | ||||
| 			await refreshFolders((action) => { this.store().dispatch(action); }); | ||||
|  | ||||
| 			const tags = await Tag.allWithNotes(); | ||||
|  | ||||
|   | ||||
| @@ -22,7 +22,6 @@ import stateToWhenClauseContext from './services/commands/stateToWhenClauseConte | ||||
| import ResourceService from '@joplin/lib/services/ResourceService'; | ||||
| import ExternalEditWatcher from '@joplin/lib/services/ExternalEditWatcher'; | ||||
| import appReducer, { createAppDefaultState } from './app.reducer'; | ||||
| const { FoldersScreenUtils } = require('@joplin/lib/folders-screen-utils.js'); | ||||
| import Folder from '@joplin/lib/models/Folder'; | ||||
| import Tag from '@joplin/lib/models/Tag'; | ||||
| import { reg } from '@joplin/lib/registry'; | ||||
| @@ -72,6 +71,7 @@ import OcrService from '@joplin/lib/services/ocr/OcrService'; | ||||
| import OcrDriverTesseract from '@joplin/lib/services/ocr/drivers/OcrDriverTesseract'; | ||||
| import SearchEngine from '@joplin/lib/services/search/SearchEngine'; | ||||
| import { PackageInfo } from '@joplin/lib/versionInfo'; | ||||
| import { refreshFolders } from '@joplin/lib/folders-screen-utils'; | ||||
|  | ||||
| const pluginClasses = [ | ||||
| 	require('./plugins/GotoAnything').default, | ||||
| @@ -482,7 +482,7 @@ class Application extends BaseApplication { | ||||
| 		// manually call dispatchUpdateAll() to force an update. | ||||
| 		Setting.dispatchUpdateAll(); | ||||
|  | ||||
| 		await FoldersScreenUtils.refreshFolders(); | ||||
| 		await refreshFolders((action: any) => this.dispatch(action)); | ||||
|  | ||||
| 		const tags = await Tag.allWithNotes(); | ||||
|  | ||||
|   | ||||
| @@ -122,6 +122,7 @@ import { ReactNode } from 'react'; | ||||
| import { parseShareCache } from '@joplin/lib/services/share/reducer'; | ||||
| import autodetectTheme, { onSystemColorSchemeChange } from './utils/autodetectTheme'; | ||||
| import runOnDeviceFsDriverTests from './utils/fs-driver/runOnDeviceTests'; | ||||
| import { refreshFolders } from '@joplin/lib/folders-screen-utils'; | ||||
|  | ||||
| type SideMenuPosition = 'left' | 'right'; | ||||
|  | ||||
| @@ -637,7 +638,7 @@ async function initialize(dispatch: Function) { | ||||
|  | ||||
| 		reg.logger().info('Loading folders...'); | ||||
|  | ||||
| 		await FoldersScreenUtils.refreshFolders(); | ||||
| 		await refreshFolders((action: any) => dispatch(action)); | ||||
|  | ||||
| 		const tags = await Tag.allWithNotes(); | ||||
|  | ||||
| @@ -999,7 +1000,7 @@ class AppComponent extends React.Component { | ||||
|  | ||||
| 	public UNSAFE_componentWillReceiveProps(newProps: any) { | ||||
| 		if (newProps.syncStarted !== this.lastSyncStarted_) { | ||||
| 			if (!newProps.syncStarted) FoldersScreenUtils.refreshFolders(); | ||||
| 			if (!newProps.syncStarted) void refreshFolders((action: any) => this.props.dispatch(action)); | ||||
| 			this.lastSyncStarted_ = newProps.syncStarted; | ||||
| 		} | ||||
| 	} | ||||
|   | ||||
| @@ -13,7 +13,7 @@ import SyncTargetOneDrive from './SyncTargetOneDrive'; | ||||
| import { createStore, applyMiddleware, Store } from 'redux'; | ||||
| const { defaultState, stateUtils } = require('./reducer'); | ||||
| import JoplinDatabase from './JoplinDatabase'; | ||||
| const { FoldersScreenUtils } = require('./folders-screen-utils.js'); | ||||
| import { cancelTimers as folderScreenUtilsCancelTimers, refreshFolders, scheduleRefreshFolders } from './folders-screen-utils'; | ||||
| const { DatabaseDriverNode } = require('./database-driver-node.js'); | ||||
| import BaseModel from './BaseModel'; | ||||
| import Folder from './models/Folder'; | ||||
| @@ -107,7 +107,7 @@ export default class BaseApplication { | ||||
| 		await ResourceFetcher.instance().destroy(); | ||||
| 		await SearchEngine.instance().destroy(); | ||||
| 		await DecryptionWorker.instance().destroy(); | ||||
| 		await FoldersScreenUtils.cancelTimers(); | ||||
| 		await folderScreenUtilsCancelTimers(); | ||||
| 		await BaseItem.revisionService_.cancelTimers(); | ||||
| 		await ResourceService.instance().cancelTimers(); | ||||
| 		await reg.cancelTimers(); | ||||
| @@ -418,8 +418,7 @@ export default class BaseApplication { | ||||
|  | ||||
| 		const result = next(action); | ||||
| 		let refreshNotes = false; | ||||
| 		let refreshFolders: boolean | string = false; | ||||
| 		// let refreshTags = false; | ||||
| 		let doRefreshFolders: boolean | string = false; | ||||
| 		let refreshNotesUseSelectedNoteId = false; | ||||
| 		let refreshNotesHash = ''; | ||||
|  | ||||
| @@ -434,7 +433,7 @@ export default class BaseApplication { | ||||
| 		// Don't add FOLDER_UPDATE_ALL as refreshFolders() is calling it too, which | ||||
| 		// would cause the sidebar to refresh all the time. | ||||
| 		if (this.hasGui() && ['FOLDER_UPDATE_ONE'].indexOf(action.type) >= 0) { | ||||
| 			refreshFolders = true; | ||||
| 			doRefreshFolders = true; | ||||
| 		} | ||||
|  | ||||
| 		if (action.type === 'HISTORY_BACKWARD' || action.type === 'HISTORY_FORWARD') { | ||||
| @@ -510,23 +509,23 @@ export default class BaseApplication { | ||||
| 				action.changedFields.includes('encryption_applied') || | ||||
| 				action.changedFields.includes('is_conflict') | ||||
| 			) { | ||||
| 				refreshFolders = true; | ||||
| 				doRefreshFolders = true; | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		if (action.type === 'NOTE_DELETE') { | ||||
| 			refreshFolders = true; | ||||
| 			doRefreshFolders = true; | ||||
| 		} | ||||
|  | ||||
| 		if (this.hasGui() && action.type === 'SETTING_UPDATE_ALL') { | ||||
| 			refreshFolders = 'now'; | ||||
| 			doRefreshFolders = 'now'; | ||||
| 		} | ||||
|  | ||||
| 		if (this.hasGui() && action.type === 'SETTING_UPDATE_ONE' && ( | ||||
| 			action.key.indexOf('folders.sortOrder') === 0 || | ||||
| 			action.key === 'showNoteCounts' || | ||||
| 			action.key === 'showCompletedTodos')) { | ||||
| 			refreshFolders = 'now'; | ||||
| 			doRefreshFolders = 'now'; | ||||
| 		} | ||||
|  | ||||
| 		if (this.hasGui() && action.type === 'SYNC_GOT_ENCRYPTED_ITEM') { | ||||
| @@ -543,11 +542,11 @@ export default class BaseApplication { | ||||
| 			await this.applySettingsSideEffects(); | ||||
| 		} | ||||
|  | ||||
| 		if (refreshFolders) { | ||||
| 			if (refreshFolders === 'now') { | ||||
| 				await FoldersScreenUtils.refreshFolders(); | ||||
| 		if (doRefreshFolders) { | ||||
| 			if (doRefreshFolders === 'now') { | ||||
| 				await refreshFolders((action: any) => this.dispatch(action)); | ||||
| 			} else { | ||||
| 				await FoldersScreenUtils.scheduleRefreshFolders(); | ||||
| 				await scheduleRefreshFolders((action: any) => this.dispatch(action)); | ||||
| 			} | ||||
| 		} | ||||
| 		return result; | ||||
| @@ -571,8 +570,6 @@ export default class BaseApplication { | ||||
| 		}); | ||||
|  | ||||
| 		BaseModel.dispatch = this.store().dispatch; | ||||
| 		FoldersScreenUtils.dispatch = this.store().dispatch; | ||||
| 		// reg.dispatch = this.store().dispatch; | ||||
| 		BaseSyncTarget.dispatch = this.store().dispatch; | ||||
| 		DecryptionWorker.instance().dispatch = this.store().dispatch; | ||||
| 		ResourceFetcher.instance().dispatch = this.store().dispatch; | ||||
| @@ -582,8 +579,6 @@ export default class BaseApplication { | ||||
| 	public deinitRedux() { | ||||
| 		this.store_ = null; | ||||
| 		BaseModel.dispatch = function() {}; | ||||
| 		FoldersScreenUtils.dispatch = function() {}; | ||||
| 		// reg.dispatch = function() {}; | ||||
| 		BaseSyncTarget.dispatch = function() {}; | ||||
| 		DecryptionWorker.instance().dispatch = function() {}; | ||||
| 		ResourceFetcher.instance().dispatch = function() {}; | ||||
|   | ||||
| @@ -1,5 +1,4 @@ | ||||
| import paginationToSql from './models/utils/paginationToSql'; | ||||
|  | ||||
| import Database from './database'; | ||||
| import uuid from './uuid'; | ||||
| import time from './time'; | ||||
| @@ -271,11 +270,15 @@ class BaseModel { | ||||
| 		return this.modelSelectAll(`SELECT * FROM \`${this.tableName()}\` WHERE \`id\` LIKE ?`, [`${partialId}%`]); | ||||
| 	} | ||||
|  | ||||
| 	public static applySqlOptions(options: any, sql: string, params: any[] = null) { | ||||
| 	public static applySqlOptions(options: LoadOptions, sql: string, params: any[] = null) { | ||||
| 		if (!options) options = {}; | ||||
|  | ||||
| 		if (options.order && options.order.length) { | ||||
| 			sql += ` ORDER BY ${paginationToSql(options)}`; | ||||
| 			sql += ` ORDER BY ${paginationToSql({ | ||||
| 				limit: options.limit, | ||||
| 				order: options.order as any, | ||||
| 				page: 1, | ||||
| 			})}`; | ||||
| 		} | ||||
|  | ||||
| 		if (options.limit) sql += ` LIMIT ${options.limit}`; | ||||
| @@ -289,7 +292,7 @@ class BaseModel { | ||||
| 		return rows.map((r: any) => r.id); | ||||
| 	} | ||||
|  | ||||
| 	public static async all(options: any = null) { | ||||
| 	public static async all(options: LoadOptions = null) { | ||||
| 		if (!options) options = {}; | ||||
| 		if (!options.fields) options.fields = '*'; | ||||
|  | ||||
|   | ||||
| @@ -1,75 +0,0 @@ | ||||
| const Folder = require('./models/Folder').default; | ||||
| const Setting = require('./models/Setting').default; | ||||
| const shim = require('./shim').default; | ||||
|  | ||||
| class FoldersScreenUtils { | ||||
| 	static async allForDisplay(options = {}) { | ||||
| 		const orderDir = Setting.value('folders.sortOrder.reverse') ? 'DESC' : 'ASC'; | ||||
|  | ||||
| 		const folderOptions = { | ||||
|  | ||||
| 			caseInsensitive: true, | ||||
| 			order: [ | ||||
| 				{ | ||||
| 					by: 'title', | ||||
| 					dir: orderDir, | ||||
| 				}, | ||||
| 			], | ||||
| 			...options, | ||||
| 		}; | ||||
|  | ||||
| 		let folders = await Folder.all(folderOptions); | ||||
|  | ||||
| 		if (Setting.value('folders.sortOrder.field') === 'last_note_user_updated_time') { | ||||
| 			folders = await Folder.orderByLastModified(folders, orderDir); | ||||
| 		} | ||||
|  | ||||
| 		if (Setting.value('showNoteCounts')) { | ||||
| 			await Folder.addNoteCounts(folders, | ||||
| 				Setting.value('showCompletedTodos')); | ||||
| 		} | ||||
|  | ||||
| 		return folders; | ||||
| 	} | ||||
|  | ||||
| 	static async refreshFolders() { | ||||
| 		FoldersScreenUtils.refreshCalls_.push(true); | ||||
| 		try { | ||||
| 			const folders = await this.allForDisplay({ includeConflictFolder: true }); | ||||
|  | ||||
| 			this.dispatch({ | ||||
| 				type: 'FOLDER_UPDATE_ALL', | ||||
| 				items: folders, | ||||
| 			}); | ||||
| 		} finally { | ||||
| 			FoldersScreenUtils.refreshCalls_.pop(); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	static scheduleRefreshFolders() { | ||||
| 		if (this.scheduleRefreshFoldersIID_) shim.clearTimeout(this.scheduleRefreshFoldersIID_); | ||||
| 		this.scheduleRefreshFoldersIID_ = shim.setTimeout(() => { | ||||
| 			this.scheduleRefreshFoldersIID_ = null; | ||||
| 			this.refreshFolders(); | ||||
| 		}, 1000); | ||||
| 	} | ||||
|  | ||||
| 	static async cancelTimers() { | ||||
| 		if (this.scheduleRefreshFoldersIID_) { | ||||
| 			shim.clearTimeout(this.scheduleRefreshFoldersIID_); | ||||
| 			this.scheduleRefreshFoldersIID_ = null; | ||||
| 		} | ||||
| 		return new Promise((resolve) => { | ||||
| 			const iid = shim.setInterval(() => { | ||||
| 				if (!FoldersScreenUtils.refreshCalls_.length) { | ||||
| 					shim.clearInterval(iid); | ||||
| 					resolve(); | ||||
| 				} | ||||
| 			}, 100); | ||||
| 		}); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| FoldersScreenUtils.refreshCalls_ = []; | ||||
|  | ||||
| module.exports = { FoldersScreenUtils }; | ||||
							
								
								
									
										73
									
								
								packages/lib/folders-screen-utils.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										73
									
								
								packages/lib/folders-screen-utils.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,73 @@ | ||||
| import { Dispatch } from 'redux'; | ||||
| import Folder from './models/Folder'; | ||||
| import Setting from './models/Setting'; | ||||
| import shim from './shim'; | ||||
| import { FolderLoadOptions } from './models/utils/types'; | ||||
|  | ||||
| const refreshCalls_: boolean[] = []; | ||||
| let scheduleRefreshFoldersIID_: any = null; | ||||
|  | ||||
| export const allForDisplay = async (options: FolderLoadOptions = {}) => { | ||||
| 	const orderDir = Setting.value('folders.sortOrder.reverse') ? 'DESC' : 'ASC'; | ||||
|  | ||||
| 	const folderOptions: FolderLoadOptions = { | ||||
| 		caseInsensitive: true, | ||||
| 		order: [ | ||||
| 			{ | ||||
| 				by: 'title', | ||||
| 				dir: orderDir, | ||||
| 			}, | ||||
| 		], | ||||
| 		...options, | ||||
| 	}; | ||||
|  | ||||
| 	let folders = await Folder.all(folderOptions); | ||||
|  | ||||
| 	if (Setting.value('folders.sortOrder.field') === 'last_note_user_updated_time') { | ||||
| 		folders = await Folder.orderByLastModified(folders, orderDir); | ||||
| 	} | ||||
|  | ||||
| 	if (Setting.value('showNoteCounts')) { | ||||
| 		await Folder.addNoteCounts(folders, | ||||
| 			Setting.value('showCompletedTodos')); | ||||
| 	} | ||||
|  | ||||
| 	return folders; | ||||
| }; | ||||
|  | ||||
| export const refreshFolders = async (dispatch: Dispatch) => { | ||||
| 	refreshCalls_.push(true); | ||||
| 	try { | ||||
| 		const folders = await allForDisplay({ includeConflictFolder: true }); | ||||
|  | ||||
| 		dispatch({ | ||||
| 			type: 'FOLDER_UPDATE_ALL', | ||||
| 			items: folders, | ||||
| 		}); | ||||
| 	} finally { | ||||
| 		refreshCalls_.pop(); | ||||
| 	} | ||||
| }; | ||||
|  | ||||
| export const scheduleRefreshFolders = async (dispatch: Dispatch) => { | ||||
| 	if (scheduleRefreshFoldersIID_) shim.clearTimeout(scheduleRefreshFoldersIID_); | ||||
| 	scheduleRefreshFoldersIID_ = shim.setTimeout(() => { | ||||
| 		scheduleRefreshFoldersIID_ = null; | ||||
| 		void refreshFolders(dispatch); | ||||
| 	}, 1000); | ||||
| }; | ||||
|  | ||||
| export const cancelTimers = async () => { | ||||
| 	if (scheduleRefreshFoldersIID_) { | ||||
| 		shim.clearTimeout(scheduleRefreshFoldersIID_); | ||||
| 		scheduleRefreshFoldersIID_ = null; | ||||
| 	} | ||||
| 	return new Promise((resolve) => { | ||||
| 		const iid = shim.setInterval(() => { | ||||
| 			if (!refreshCalls_.length) { | ||||
| 				shim.clearInterval(iid); | ||||
| 				resolve(null); | ||||
| 			} | ||||
| 		}, 100); | ||||
| 	}); | ||||
| }; | ||||
| @@ -1,5 +1,6 @@ | ||||
| import { defaultFolderIcon, FolderEntity, FolderIcon, NoteEntity, ResourceEntity } from '../services/database/types'; | ||||
| import BaseModel, { DeleteOptions } from '../BaseModel'; | ||||
| import { FolderLoadOptions } from './utils/types'; | ||||
| import time from '../time'; | ||||
| import { _ } from '../locale'; | ||||
| import Note from './Note'; | ||||
| @@ -249,7 +250,7 @@ export default class Folder extends BaseItem { | ||||
| 		return output; | ||||
| 	} | ||||
|  | ||||
| 	public static async all(options: any = null) { | ||||
| 	public static async all(options: FolderLoadOptions = null) { | ||||
| 		const output = await super.all(options); | ||||
| 		if (options && options.includeConflictFolder) { | ||||
| 			const conflictCount = await Note.conflictedCount(); | ||||
|   | ||||
| @@ -21,6 +21,18 @@ export interface Pagination { | ||||
| export interface LoadOptions { | ||||
| 	caseInsensitive?: boolean; | ||||
| 	fields?: string | string[]; | ||||
| 	where?: string; | ||||
| 	whereParams?: any[]; | ||||
| 	order?: { | ||||
| 		by: string; | ||||
| 		dir: string; | ||||
| 		caseInsensitive?: boolean; | ||||
| 	}[]; | ||||
| 	limit?: number; | ||||
| } | ||||
|  | ||||
| export interface FolderLoadOptions extends LoadOptions { | ||||
| 	includeConflictFolder?: boolean; | ||||
| } | ||||
|  | ||||
| export interface SaveOptions { | ||||
|   | ||||
| @@ -296,7 +296,7 @@ export default class ReportService { | ||||
| 		section = { title: _('Folders'), body: [] }; | ||||
|  | ||||
| 		const folders = await Folder.all({ | ||||
| 			order: { by: 'title', dir: 'ASC' }, | ||||
| 			order: [{ by: 'title', dir: 'ASC' }], | ||||
| 			caseInsensitive: true, | ||||
| 		}); | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user