1
0
mirror of https://github.com/laurent22/joplin.git synced 2024-12-12 08:54:00 +02:00
joplin/packages/lib/components/shared/reduxSharedMiddleware.ts

144 lines
4.8 KiB
TypeScript

import Setting from '../../models/Setting';
import Tag from '../../models/Tag';
import BaseModel from '../../BaseModel';
import Note from '../../models/Note';
import { reg } from '../../registry.js';
import ResourceFetcher from '../../services/ResourceFetcher';
import DecryptionWorker from '../../services/DecryptionWorker';
import eventManager from '../../eventManager';
import BaseItem from '../../models/BaseItem';
import shim from '../../shim';
import { Dispatch } from 'redux';
import { State } from '../../reducer';
let sortNoteListTimeout: any = null;
export default async (store: any, _next: any, action: any, dispatch: Dispatch) => {
const newState: State = store.getState();
eventManager.appStateEmit(newState);
let refreshTags = false;
let sortNoteList = false;
if (action.type === 'FOLDER_SET_COLLAPSED' || action.type === 'FOLDER_TOGGLE') {
Setting.setValue('collapsedFolderIds', newState.collapsedFolderIds);
}
if (action.type === 'SETTING_UPDATE_ONE' && !!action.key.match(/^sync\.\d+\.path$/)) {
reg.resetSyncTarget();
}
let mustAutoAddResources = false;
if (action.type === 'SETTING_UPDATE_ONE' && action.key === 'sync.resourceDownloadMode') {
mustAutoAddResources = true;
}
if (action.type === 'DECRYPTION_WORKER_SET' && action.state === 'idle' && action.decryptedItemCounts && !!action.decryptedItemCounts[BaseModel.TYPE_NOTE]) {
mustAutoAddResources = true;
}
// In general the DecryptionWorker is started via events, such as when an encrypted note
// is received via sync, or after an encrypted has been downloaded. However, in some cases,
// in particular when an item cannot be decrypted, the service won't retry automatically,
// since it's not useful because the data most likely is corrupted. In some
// cases the user might want to retry anyway, so we enable this by starting the service
// automatically after each full sync (which is triggered when the user presses the sync
// button, but not when a note is saved).
if (action.type === 'SYNC_COMPLETED' && action.isFullSync) {
void DecryptionWorker.instance().scheduleStart();
}
if (action.type === 'NOTE_DELETE' ||
action.type === 'NOTE_UPDATE_ALL' ||
action.type === 'NOTE_TAG_REMOVE' ||
action.type === 'TAG_UPDATE_ONE') {
refreshTags = true;
}
// handle the case when the selected note has been moved to another
// folder and a new one is now selected, need to show correct tags for it
if (action.type === 'NOTE_UPDATE_ONE' && action.changedFields.indexOf('parent_id') >= 0) {
refreshTags = true;
}
if (action.type === 'NOTE_UPDATE_ONE') {
sortNoteList = true;
}
if (action.type === 'NOTE_SELECT' || action.type === 'NAV_BACK') {
const noteIds = newState.provisionalNoteIds.slice();
for (const noteId of noteIds) {
if (action.id === noteId) continue;
reg.logger().info('Provisional was not modified - deleting it');
await Note.delete(noteId);
}
}
if (action.type === 'NOTE_DELETE' ||
action.type === 'NOTE_SELECT' ||
action.type === 'NOTE_SELECT_TOGGLE' ||
action.type === 'TAG_UPDATE_ONE' ||
action.type === 'TAG_UPDATE_ALL') {
let noteTags = [];
// We don't need to show tags unless only one note is selected.
// For new notes, the old note is still selected, but we don't want to show any tags.
if (newState.selectedNoteIds &&
newState.selectedNoteIds.length === 1) {
noteTags = await Tag.tagsByNoteId(newState.selectedNoteIds[0]);
}
store.dispatch({
type: 'SET_NOTE_TAGS',
items: noteTags,
});
}
if (mustAutoAddResources) {
void ResourceFetcher.instance().autoAddResources();
}
if (refreshTags) {
store.dispatch({
type: 'TAG_UPDATE_ALL',
items: await Tag.allWithNotes(),
});
}
if (sortNoteList) {
if (sortNoteListTimeout) shim.clearTimeout(sortNoteListTimeout);
sortNoteListTimeout = null;
// We sort the note lists with two seconds debounce because doing can be
// very slow and would have to be done every time a note is added.
if (Date.now() - newState.noteListLastSortTime > 10000) {
dispatch({ type: 'NOTE_SORT' });
} else {
sortNoteListTimeout = shim.setTimeout(() => {
sortNoteListTimeout = null;
dispatch({ type: 'NOTE_SORT' });
}, 2000);
}
}
if (action.type.startsWith('SHARE_')) {
const serialized = JSON.stringify(newState.shareService);
Setting.setValue('sync.shareCache', serialized);
BaseItem.syncShareCache = JSON.parse(serialized);
}
// For debugging purposes: it seems in some case an empty note is saved to
// the note array, so in that case display a log statements so that it can
// be debugged.
// https://discourse.joplinapp.org/t/how-to-recover-corrupted-database/9367/3?u=laurent
if (action.type.indexOf('NOTE_') === 0) {
for (const note of newState.notes) {
if (!note) {
reg.logger().error('Detected empty element in note array', action);
}
}
}
};