1
0
mirror of https://github.com/laurent22/joplin.git synced 2025-08-13 22:12:50 +02:00

Improve browsing of notes

This commit is contained in:
Laurent Cozic
2017-06-25 10:00:54 +01:00
parent 79e0bb2e65
commit cf494cfd17
5 changed files with 83 additions and 27 deletions

View File

@@ -196,18 +196,13 @@ async function main() {
usage: 'use <notebook-title>', usage: 'use <notebook-title>',
aliases: ['cd'], aliases: ['cd'],
description: 'Switches to [notebook-title] - all further operations will happen within this notebook.', description: 'Switches to [notebook-title] - all further operations will happen within this notebook.',
action: function(args, end) { action: async function(args, end) {
let folderTitle = args['notebook-title']; let folderTitle = args['notebook-title'];
if (folderTitle == '.' || folderTitle == '..') { let folder = await Folder.loadByField('title', folderTitle);
end(); if (!folder) return commandError(this, _('Invalid folder title: %s', folderTitle), end);
return;
}
Folder.loadByField('title', folderTitle).then((folder) => {
switchCurrentFolder(folder); switchCurrentFolder(folder);
end(); end();
});
}, },
autocomplete: autocompleteFolders, autocomplete: autocompleteFolders,
}); });
@@ -355,14 +350,32 @@ async function main() {
description: 'Displays the notes in [notebook-title]. Use `ls ..` to display the list of notebooks.', description: 'Displays the notes in [notebook-title]. Use `ls ..` to display the list of notebooks.',
options: [ options: [
['-n, --lines <num>', 'Displays only the first top <num> lines.'], ['-n, --lines <num>', 'Displays only the first top <num> lines.'],
['-s, --sort <field>', 'Sorts the item by <field> (eg. title, updated_time, created_time).'],
['-r, --reverse', 'Reverses the sorting order.'],
['-t, --type <type>', 'Displays only the items of the specific type(s). Can be `n` for notes, `t` for todos, or `nt` for notes and todos (eg. `-tt` would display only the todos, while `-ttd` would display notes and todos.'],
], ],
action: async function(args, end) { action: async function(args, end) {
let folderTitle = args['notebook-title']; let folderTitle = args['notebook-title'];
let suffix = ''; let suffix = '';
let items = []; let items = [];
let options = args.options;
let queryOptions = {};
if (options.lines) queryOptions.limit = options.lines;
if (options.sort) {
queryOptions.orderBy = options.sort;
queryOptions.orderByDir = 'ASC';
}
if (options.reverse === true) queryOptions.orderByDir = queryOptions.orderByDir == 'ASC' ? 'DESC' : 'ASC';
queryOptions.caseInsensitive = true;
if (options.type) {
queryOptions.itemTypes = [];
if (options.type.indexOf('n') >= 0) queryOptions.itemTypes.push('note');
if (options.type.indexOf('t') >= 0) queryOptions.itemTypes.push('todo');
}
if (folderTitle == '..') { if (folderTitle == '..') {
items = await Folder.all(); items = await Folder.all(queryOptions);
suffix = '/'; suffix = '/';
} else { } else {
let folder = null; let folder = null;
@@ -375,12 +388,17 @@ async function main() {
if (!folder) return commandError(this, _('Unknown notebook: "%s"', folderTitle), end); if (!folder) return commandError(this, _('Unknown notebook: "%s"', folderTitle), end);
items = await Note.previews(folder.id); items = await Note.previews(folder.id, queryOptions);
} }
for (let i = 0; i < items.length; i++) { for (let i = 0; i < items.length; i++) {
let item = items[i]; let item = items[i];
this.log(item.title + suffix); let line = '';
if (!!item.is_todo) {
line += sprintf('[%s] ', !!item.todo_completed ? 'X' : ' ');
}
line += item.title + suffix;
this.log(line);
} }
end(); end();

View File

@@ -46,7 +46,7 @@ describe('Synchronizer', function() {
let folder = await Folder.save({ title: "folder1" }); let folder = await Folder.save({ title: "folder1" });
await Note.save({ title: "un", parent_id: folder.id }); await Note.save({ title: "un", parent_id: folder.id });
let all = await Folder.all(true); let all = await Folder.all({ includeNotes: true });
await synchronizer().start(); await synchronizer().start();
@@ -64,7 +64,7 @@ describe('Synchronizer', function() {
await Note.save({ title: "un UPDATE", id: note.id }); await Note.save({ title: "un UPDATE", id: note.id });
let all = await Folder.all(true); let all = await Folder.all({ includeNotes: true });
await synchronizer().start(); await synchronizer().start();
await localItemsSameAsRemote(all, expect); await localItemsSameAsRemote(all, expect);
@@ -81,7 +81,7 @@ describe('Synchronizer', function() {
await synchronizer().start(); await synchronizer().start();
let all = await Folder.all(true); let all = await Folder.all({ includeNotes: true });
await localItemsSameAsRemote(all, expect); await localItemsSameAsRemote(all, expect);
done(); done();
@@ -109,7 +109,7 @@ describe('Synchronizer', function() {
await synchronizer().start(); await synchronizer().start();
let all = await Folder.all(true); let all = await Folder.all({ includeNotes: true });
let files = await fileApi().list(); let files = await fileApi().list();
await localItemsSameAsRemote(all, expect); await localItemsSameAsRemote(all, expect);
@@ -250,7 +250,7 @@ describe('Synchronizer', function() {
await synchronizer().start(); await synchronizer().start();
let items = await Folder.all(true); let items = await Folder.all({ includeNotes: true });
expect(items.length).toBe(1); expect(items.length).toBe(1);
@@ -288,7 +288,7 @@ describe('Synchronizer', function() {
expect(conflictedNotes.length).toBe(1); expect(conflictedNotes.length).toBe(1);
expect(conflictedNotes[0].title).toBe(newTitle); expect(conflictedNotes[0].title).toBe(newTitle);
let items = await Folder.all(true); let items = await Folder.all({ includeNotes: true });
expect(items.length).toBe(1); expect(items.length).toBe(1);
@@ -319,7 +319,7 @@ describe('Synchronizer', function() {
await synchronizer().start(); await synchronizer().start();
let items = await Folder.all(true); let items = await Folder.all({ includeNotes: true });
expect(items.length).toBe(0); expect(items.length).toBe(0);

View File

@@ -120,6 +120,24 @@ class BaseModel {
return this.loadByField('id', id); return this.loadByField('id', id);
} }
static applySqlOptions(options, sql, params = null) {
if (!options) options = {};
if (options.orderBy) {
sql += ' ORDER BY ' + options.orderBy;
if (options.caseInsensitive === true) sql += ' COLLATE NOCASE';
if (options.orderByDir) sql += ' ' + options.orderByDir;
}
if (options.limit) sql += ' LIMIT ' + options.limit;
return { sql: sql, params: params };
}
static async all(options = null) {
let q = this.applySqlOptions(options, 'SELECT * FROM `' + this.tableName() + '`');
return await this.modelSelectAll(q.sql);
}
static modelSelectOne(sql, params = null) { static modelSelectOne(sql, params = null) {
if (params === null) params = []; if (params === null) params = [];
return this.db().selectOne(sql, params).then((model) => { return this.db().selectOne(sql, params).then((model) => {

View File

@@ -81,11 +81,15 @@ class Folder extends BaseItem {
return this.modelSelectOne('SELECT * FROM notes WHERE is_conflict = 0 AND `parent_id` = ? AND `' + field + '` = ?', [folderId, value]); return this.modelSelectOne('SELECT * FROM notes WHERE is_conflict = 0 AND `parent_id` = ? AND `' + field + '` = ?', [folderId, value]);
} }
static async all(includeNotes = false) { static async all(options = null) {
let folders = await Folder.modelSelectAll('SELECT * FROM folders'); if (!options) options = {};
if (!includeNotes) return folders;
let notes = await Note.modelSelectAll('SELECT * FROM notes WHERE is_conflict = 0'); let folders = await super.all(options);
if (!options.includeNotes) return folders;
if (options.limit) options.limit -= folders.length;
let notes = await Note.all(options);
return folders.concat(notes); return folders.concat(notes);
} }

View File

@@ -43,8 +43,24 @@ class Note extends BaseItem {
return '`id`, `title`, `body`, `is_todo`, `todo_completed`, `parent_id`, `updated_time`' return '`id`, `title`, `body`, `is_todo`, `todo_completed`, `parent_id`, `updated_time`'
} }
static previews(parentId) { static previews(parentId, options = null) {
return this.modelSelectAll('SELECT ' + this.previewFieldsSql() + ' FROM notes WHERE is_conflict = 0 AND parent_id = ?', [parentId]); if (!options) options = {};
if (!options.orderBy) options.orderBy = 'updated_time';
if (!options.orderByDir) options.orderByDir = 'DESC';
let sql = 'SELECT ' + this.previewFieldsSql() + ' FROM notes WHERE is_conflict = 0 AND parent_id = ?';
if (options.itemTypes && options.itemTypes.length) {
if (options.itemTypes.indexOf('note') >= 0 && options.itemTypes.indexOf('todo') >= 0) {
// Fetch everything
} else if (options.itemTypes.indexOf('note') >= 0) {
sql += ' AND is_todo = 0';
} else if (options.itemTypes.indexOf('todo') >= 0) {
sql += ' AND is_todo = 1';
}
}
let query = this.applySqlOptions(options, sql, [parentId]);
return this.modelSelectAll(query.sql, query.params);
} }
static preview(noteId) { static preview(noteId) {