initial integration of note list renderer into search results

This commit is contained in:
zadam 2020-10-25 23:02:12 +01:00
parent 37e111d8a9
commit 4281111344
7 changed files with 118 additions and 29 deletions

View File

@ -34,10 +34,18 @@ async function createSqlConsole() {
return await treeCache.getNote(note.noteId);
}
/** @return {NoteShort} */
async function createSearchNote() {
const note = await server.post('search-note');
return await treeCache.getNote(note.noteId);
}
export default {
getTodayNote,
getDateNote,
getMonthNote,
getYearNote,
createSqlConsole
}
createSqlConsole,
createSearchNote
}

View File

@ -67,6 +67,15 @@ export default class DialogCommandExecutor extends Component {
appContext.triggerCommand('focusOnDetail', {tabId: tabContext.tabId});
}
async searchNotesCommand() {
const searchNote = await dateNoteService.createSearchNote();
const tabContext = await appContext.tabManager.openTabWithNote(searchNote.noteId, true);
appContext.triggerCommand('focusOnDetail', {tabId: tabContext.tabId});
}
showBackendLogCommand() {
import("../dialogs/backend_log.js").then(d => d.showDialog());
}

View File

@ -135,12 +135,20 @@ const TPL = `
</div>`;
class NoteListRenderer {
constructor(parentNote, notes) {
/*
* We're using noteIds so that it's not necessary to load all notes at once when paging
*/
constructor(parentNote, noteIds) {
this.$noteList = $(TPL);
this.parentNote = parentNote;
this.notes = notes;
this.noteIds = noteIds;
this.page = 1;
this.pageSize = 6;
this.pageSize = parseInt(parentNote.getLabelValue('pageSize'));
if (!this.pageSize || this.pageSize < 1 || this.pageSize > 10000) {
this.pageSize = 10;
}
this.viewType = parentNote.getLabelValue('viewType');
if (!['list', 'grid'].includes(this.viewType)) {
@ -205,7 +213,8 @@ class NoteListRenderer {
const startIdx = (this.page - 1) * this.pageSize;
const endIdx = startIdx + this.pageSize;
const pageNotes = this.notes.slice(startIdx, Math.min(endIdx, this.notes.length));
const pageNoteIds = this.noteIds.slice(startIdx, Math.min(endIdx, this.noteIds.length));
const pageNotes = await treeCache.getNotes(pageNoteIds);
for (const note of pageNotes) {
// image is already visible in the parent note so no need to display it separately in the book
@ -213,7 +222,7 @@ class NoteListRenderer {
continue;
}
const $card = await this.renderNote(note);
const $card = await this.renderNote(note, this.parentNote.hasLabel('expanded'));
$container.append($card);
}
@ -225,7 +234,7 @@ class NoteListRenderer {
renderPager() {
const $pager = this.$noteList.find('.note-list-pager').empty();
const pageCount = Math.ceil(this.notes.length / this.pageSize);
const pageCount = Math.ceil(this.noteIds.length / this.pageSize);
$pager.toggle(pageCount > 1);
@ -255,7 +264,8 @@ class NoteListRenderer {
}
// TODO: we should also render (promoted) attributes
async renderNote(note) {
// FIXME: showing specific path might be necessary because of a match in the patch
async renderNote(note, expand = false) {
const notePath = /*this.notePath + '/' + */ note.noteId;
const $expander = $('<span class="note-expander bx bx-chevron-right"></span>');
@ -270,7 +280,7 @@ class NoteListRenderer {
$expander.on('click', () => this.toggleContent($card, note, !$card.hasClass("expanded")));
await this.toggleContent($card, note, this.parentNote.hasLabel('expanded'));
await this.toggleContent($card, note, expand);
return $card;
}

View File

@ -164,9 +164,9 @@ export default class SearchBoxWidget extends BasicWidget {
}
}
searchNotesEvent() {
this.toggleSearchEvent();
}
// searchNotesEvent() {
// this.toggleSearchEvent();
// }
resetSearchEvent() {
this.$searchInput.val("");

View File

@ -1,11 +1,18 @@
import TypeWidget from "./type_widget.js";
import noteAutocompleteService from "../../services/note_autocomplete.js";
import SpacedUpdate from "../../services/spaced_update.js";
import server from "../../services/server.js";
import toastService from "../../services/toast.js";
import NoteListRenderer from "../../services/note_list_renderer.js";
const TPL = `
<div class="note-detail-search note-detail-printable">
<style>
.note-detail-search {
padding: 7px;
height: 100%;
display: flex;
flex-direction: column;
}
.search-setting-table {
@ -48,6 +55,11 @@ const TPL = `
.search-setting-expander:hover .search-setting-expander-text {
color: var(--main-text-color);
}
.note-result-wrapper {
height: 100%;
overflow: auto;
}
</style>
<div class="area-expander">
@ -63,7 +75,7 @@ const TPL = `
<tr>
<td>Search string:</td>
<td colspan="3">
<input type="text" class="form-control">
<input type="text" class="form-control search-string">
</td>
</tr>
<tr>
@ -85,6 +97,8 @@ const TPL = `
<hr class="w-100 search-setting-empty-expander" style="margin-bottom: 10px;">
</div>
<div class="note-result-wrapper"></div>
</div>`;
export default class SearchTypeWidget extends TypeWidget {
@ -93,13 +107,26 @@ export default class SearchTypeWidget extends TypeWidget {
doRender() {
this.$widget = $(TPL);
this.$searchString = this.$widget.find(".search-string");
this.$searchString.on('input', () => this.spacedUpdate.scheduleUpdate());
this.$component = this.$widget.find('.note-detail-search');
this.$settingsArea = this.$widget.find('.search-settings');
this.spacedUpdate = new SpacedUpdate(() => this.updateSearch(), 2000);
this.$limitSearchToSubtree = this.$widget.find('.limit-search-to-subtree');
noteAutocompleteService.initNoteAutocomplete(this.$limitSearchToSubtree);
this.$limitSearchToSubtree.on('autocomplete:closed', e => {
this.spacedUpdate.scheduleUpdate();
});
this.$searchWithinNoteContent = this.$widget.find('.search-within-note-content');
this.$searchWithinNoteContent.on('change', () => {
this.spacedUpdate.scheduleUpdate();
});
this.$settingExpander = this.$widget.find('.area-expander');
this.$settingExpander.on('click', async () => {
const collapse = this.$settingsArea.is(":visible");
@ -110,25 +137,42 @@ export default class SearchTypeWidget extends TypeWidget {
this.$settingsArea.slideDown(200);
}
});
this.$noteResultWrapper = this.$widget.find('.note-result-wrapper');
}
async updateSearch() {
const searchString = this.$searchString.val();
const subNoteId = this.$limitSearchToSubtree.getSelectedNoteId();
const includeNoteContent = this.$searchWithinNoteContent.is(":checked");
const response = await server.get(`search/${encodeURIComponent(searchString)}?includeNoteContent=${includeNoteContent}&excludeArchived=true&fuzzyAttributeSearch=false`);
if (!response.success) {
toastService.showError("Search failed: " + response.message, 10000);
// even in this case we'll show the results
}
const resultNoteIds = response.results.map(res => res.notePathArray[res.notePathArray.length - 1]);
const noteListRenderer = new NoteListRenderer(this.note, resultNoteIds);
this.$noteResultWrapper.empty().append(await noteListRenderer.renderList());
}
async doRefresh(note) {
this.$help.html(window.glob.SEARCH_HELP_TEXT);
this.$component.show();
try {
const noteComplement = await this.tabContext.getNoteComplement();
const json = JSON.parse(noteComplement.content);
this.$searchString.val(json.searchString);
}
catch (e) {
console.log(e);
this.$searchString.val('');
}
this.$searchString.on('input', () => this.spacedUpdate.scheduleUpdate());
// try {
// const noteComplement = await this.tabContext.getNoteComplement();
// const json = JSON.parse(noteComplement.content);
//
// this.$searchString.val(json.searchString);
// }
// catch (e) {
// console.log(e);
// this.$searchString.val('');
// }
}
getContent() {

View File

@ -51,10 +51,27 @@ function createSqlConsole() {
return note;
}
function createSearchNote() {
const today = dateUtils.localNowDate();
const todayNote = dateNoteService.getDateNote(today);
const {note} = noteService.createNewNote({
parentNoteId: todayNote.noteId,
title: 'Search',
content: "",
type: 'search',
mime: 'application/json'
});
return note;
}
module.exports = {
getDateNote,
getMonthNote,
getYearNote,
getDateNotesForMonth,
createSqlConsole
createSqlConsole,
createSearchNote
};

View File

@ -190,6 +190,7 @@ function register(app) {
apiRoute(GET, '/api/date-notes/year/:year', dateNotesRoute.getYearNote);
apiRoute(GET, '/api/date-notes/notes-for-month/:month', dateNotesRoute.getDateNotesForMonth);
apiRoute(POST, '/api/sql-console', dateNotesRoute.createSqlConsole);
apiRoute(POST, '/api/search-note', dateNotesRoute.createSearchNote);
route(GET, '/api/images/:noteId/:filename', [auth.checkApiAuthOrElectron], imageRoute.returnImage);
route(POST, '/api/images', [auth.checkApiAuthOrElectron, uploadMiddleware, csrfMiddleware], imageRoute.uploadImage, apiResultHandler);