mirror of
https://github.com/laurent22/joplin.git
synced 2024-12-18 09:35:20 +02:00
e11e57f1d8
The implementation uses / symbol as a nesting separator. I.e. tag/subtag is a nested tag, where tag is the parent tag and subtag is its child. Creating a tag named tag/subtag/subsubtag creates three tags, one for each level. The tags are associated using parent_id field. In the app, viewing notes with a tag will also show all notes that are associated with any of the tag's descendant tags (same for the note count). Deleting a tag will also delete all its descendant tags. In the desktop app the tags are shown nested just like the notebooks.
110 lines
3.6 KiB
JavaScript
110 lines
3.6 KiB
JavaScript
const Setting = require('lib/models/Setting');
|
|
const Tag = require('lib/models/Tag');
|
|
const BaseModel = require('lib/BaseModel');
|
|
const Note = require('lib/models/Note');
|
|
const { reg } = require('lib/registry.js');
|
|
const ResourceFetcher = require('lib/services/ResourceFetcher');
|
|
const DecryptionWorker = require('lib/services/DecryptionWorker');
|
|
|
|
const reduxSharedMiddleware = async function(store, next, action) {
|
|
const newState = store.getState();
|
|
|
|
let refreshTags = false;
|
|
|
|
if (action.type == 'FOLDER_SET_COLLAPSED' || action.type == 'FOLDER_TOGGLE') {
|
|
Setting.setValue('collapsedFolderIds', newState.collapsedFolderIds);
|
|
}
|
|
|
|
if (action.type == 'TAG_SET_COLLAPSED' || action.type == 'TAG_TOGGLE') {
|
|
Setting.setValue('collapsedTagIds', newState.collapsedTagIds);
|
|
}
|
|
|
|
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) {
|
|
DecryptionWorker.instance().scheduleStart();
|
|
}
|
|
|
|
if (action.type == 'NOTE_DELETE' ||
|
|
action.type == 'NOTE_UPDATE_ONE' ||
|
|
action.type == 'NOTE_UPDATE_ALL' ||
|
|
action.type == 'NOTE_TAG_REMOVE' ||
|
|
action.type == 'TAG_UPDATE_ONE') {
|
|
refreshTags = 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) {
|
|
ResourceFetcher.instance().autoAddResources();
|
|
}
|
|
|
|
if (refreshTags) {
|
|
store.dispatch({
|
|
type: 'TAG_UPDATE_ALL',
|
|
items: await Tag.allWithNotes(),
|
|
});
|
|
}
|
|
|
|
// 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);
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
module.exports = reduxSharedMiddleware;
|
|
|