2024-08-06 10:39:15 +08:00
|
|
|
import { t } from "../../services/i18n.js";
|
2021-01-30 15:50:46 +01:00
|
|
|
import server from "../../services/server.js";
|
2021-05-22 12:35:41 +02:00
|
|
|
import NoteContextAwareWidget from "../note_context_aware_widget.js";
|
2021-04-16 23:01:56 +02:00
|
|
|
import froca from "../../services/froca.js";
|
2021-01-30 15:50:46 +01:00
|
|
|
import ws from "../../services/ws.js";
|
|
|
|
import toastService from "../../services/toast.js";
|
2021-06-06 11:01:10 +02:00
|
|
|
import treeService from "../../services/tree.js";
|
2021-01-24 22:30:53 +01:00
|
|
|
|
2021-01-30 15:50:46 +01:00
|
|
|
import SearchString from "../search_options/search_string.js";
|
|
|
|
import FastSearch from "../search_options/fast_search.js";
|
|
|
|
import Ancestor from "../search_options/ancestor.js";
|
|
|
|
import IncludeArchivedNotes from "../search_options/include_archived_notes.js";
|
|
|
|
import OrderBy from "../search_options/order_by.js";
|
|
|
|
import SearchScript from "../search_options/search_script.js";
|
2021-02-13 23:52:52 +01:00
|
|
|
import Limit from "../search_options/limit.js";
|
2021-02-18 22:10:49 +01:00
|
|
|
import Debug from "../search_options/debug.js";
|
2022-12-01 13:07:23 +01:00
|
|
|
import appContext from "../../components/app_context.js";
|
2022-06-03 17:29:08 +02:00
|
|
|
import bulkActionService from "../../services/bulk_action.js";
|
2020-11-26 23:00:27 +01:00
|
|
|
|
|
|
|
const TPL = `
|
|
|
|
<div class="search-definition-widget">
|
2021-01-20 20:31:24 +01:00
|
|
|
<style>
|
2020-11-26 23:00:27 +01:00
|
|
|
.search-setting-table {
|
2021-01-26 22:22:17 +01:00
|
|
|
margin-top: 0;
|
2020-12-17 15:19:22 +01:00
|
|
|
margin-bottom: 7px;
|
2020-11-26 23:00:27 +01:00
|
|
|
width: 100%;
|
|
|
|
border-collapse: separate;
|
|
|
|
border-spacing: 10px;
|
|
|
|
}
|
|
|
|
|
2021-01-26 15:54:41 +01:00
|
|
|
.search-setting-table div {
|
|
|
|
white-space: nowrap;
|
|
|
|
}
|
|
|
|
|
2021-01-26 14:10:34 +01:00
|
|
|
.search-setting-table .button-column {
|
|
|
|
/* minimal width so that table remains static sized and most space remains for middle column with settings */
|
|
|
|
width: 50px;
|
|
|
|
white-space: nowrap;
|
|
|
|
text-align: right;
|
|
|
|
}
|
|
|
|
|
|
|
|
.search-setting-table .title-column {
|
|
|
|
/* minimal width so that table remains static sized and most space remains for middle column with settings */
|
|
|
|
width: 50px;
|
|
|
|
white-space: nowrap;
|
|
|
|
}
|
|
|
|
|
|
|
|
.search-setting-table .button-column .dropdown-menu {
|
|
|
|
white-space: normal;
|
|
|
|
}
|
|
|
|
|
2020-11-26 23:00:27 +01:00
|
|
|
.attribute-list hr {
|
|
|
|
height: 1px;
|
|
|
|
border-color: var(--main-border-color);
|
|
|
|
position: relative;
|
|
|
|
top: 4px;
|
|
|
|
margin-top: 5px;
|
|
|
|
margin-bottom: 0;
|
|
|
|
}
|
2021-01-20 20:31:24 +01:00
|
|
|
|
|
|
|
.search-definition-widget input:invalid {
|
|
|
|
border: 3px solid red;
|
|
|
|
}
|
2021-01-26 22:22:17 +01:00
|
|
|
|
|
|
|
.add-search-option button {
|
|
|
|
margin-top: 5px; /* to give some spacing when buttons overflow on the next line */
|
|
|
|
}
|
2022-06-05 23:36:46 +02:00
|
|
|
|
|
|
|
.dropdown-header {
|
|
|
|
background-color: var(--accented-background-color);
|
|
|
|
}
|
2020-11-26 23:00:27 +01:00
|
|
|
</style>
|
|
|
|
|
|
|
|
<div class="search-settings">
|
|
|
|
<table class="search-setting-table">
|
|
|
|
<tr>
|
2024-08-06 10:39:15 +08:00
|
|
|
<td class="title-column">${t('search_definition.add_search_option')}</td>
|
2021-01-17 21:11:01 +01:00
|
|
|
<td colspan="2" class="add-search-option">
|
2021-01-24 22:30:53 +01:00
|
|
|
<button type="button" class="btn btn-sm" data-search-option-add="searchString">
|
|
|
|
<span class="bx bx-text"></span>
|
2024-08-06 10:39:15 +08:00
|
|
|
${t('search_definition.search_string')}
|
2021-01-24 22:30:53 +01:00
|
|
|
</button>
|
|
|
|
|
2021-01-26 22:22:17 +01:00
|
|
|
<button type="button" class="btn btn-sm" data-search-option-add="searchScript">
|
|
|
|
<span class="bx bx-code"></span>
|
2024-08-06 10:39:15 +08:00
|
|
|
${t('search_definition.search_script')}
|
2021-01-26 22:22:17 +01:00
|
|
|
</button>
|
|
|
|
|
2021-01-18 22:52:07 +01:00
|
|
|
<button type="button" class="btn btn-sm" data-search-option-add="ancestor">
|
2021-01-08 19:57:49 +01:00
|
|
|
<span class="bx bx-filter-alt"></span>
|
2024-08-06 10:39:15 +08:00
|
|
|
${t('search_definition.ancestor')}
|
2021-01-08 19:57:49 +01:00
|
|
|
</button>
|
|
|
|
|
2021-01-17 21:11:01 +01:00
|
|
|
<button type="button" class="btn btn-sm" data-search-option-add="fastSearch"
|
2024-08-06 10:39:15 +08:00
|
|
|
title="${t('search_definition.fast_search_description')}">
|
2021-01-08 19:57:49 +01:00
|
|
|
<span class="bx bx-run"></span>
|
2024-08-06 10:39:15 +08:00
|
|
|
${t('search_definition.fast_search')}
|
2021-01-08 19:57:49 +01:00
|
|
|
</button>
|
|
|
|
|
2021-01-17 21:11:01 +01:00
|
|
|
<button type="button" class="btn btn-sm" data-search-option-add="includeArchivedNotes"
|
2024-08-06 10:39:15 +08:00
|
|
|
title="${t('search_definition.include_archived_notes_description')}">
|
2021-01-08 19:57:49 +01:00
|
|
|
<span class="bx bx-archive"></span>
|
2024-08-06 10:39:15 +08:00
|
|
|
${t('search_definition.include_archived')}
|
2021-01-08 19:57:49 +01:00
|
|
|
</button>
|
|
|
|
|
2021-01-17 21:11:01 +01:00
|
|
|
<button type="button" class="btn btn-sm" data-search-option-add="orderBy">
|
2021-01-08 19:57:49 +01:00
|
|
|
<span class="bx bx-arrow-from-top"></span>
|
2024-08-06 10:39:15 +08:00
|
|
|
${t('search_definition.order_by')}
|
2021-01-08 19:57:49 +01:00
|
|
|
</button>
|
|
|
|
|
2024-08-06 10:39:15 +08:00
|
|
|
<button type="button" class="btn btn-sm" data-search-option-add="limit" title="${t('search_definition.limit_description')}">
|
2021-02-13 23:52:52 +01:00
|
|
|
<span class="bx bx-stop"></span>
|
2024-08-06 10:39:15 +08:00
|
|
|
${t('search_definition.limit')}
|
2021-02-13 23:52:52 +01:00
|
|
|
</button>
|
|
|
|
|
2024-08-06 10:39:15 +08:00
|
|
|
<button type="button" class="btn btn-sm" data-search-option-add="debug" title="${t('search_definition.debug_description')}">
|
2021-02-18 22:10:49 +01:00
|
|
|
<span class="bx bx-bug"></span>
|
2024-08-06 10:39:15 +08:00
|
|
|
${t('search_definition.debug')}
|
2021-02-18 22:10:49 +01:00
|
|
|
</button>
|
|
|
|
|
2021-01-08 19:57:49 +01:00
|
|
|
<div class="dropdown" style="display: inline-block;">
|
2021-01-17 23:01:01 +01:00
|
|
|
<button class="btn btn-sm dropdown-toggle action-add-toggle" type="button" id="dropdownMenuButton" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
2021-01-08 19:57:49 +01:00
|
|
|
<span class="bx bxs-zap"></span>
|
2024-08-06 10:39:15 +08:00
|
|
|
${t('search_definition.action')}
|
2021-01-08 19:57:49 +01:00
|
|
|
</button>
|
2022-06-03 17:29:08 +02:00
|
|
|
<div class="dropdown-menu action-list"></div>
|
2021-01-08 19:57:49 +01:00
|
|
|
</div>
|
|
|
|
</td>
|
|
|
|
</tr>
|
2021-01-24 22:30:53 +01:00
|
|
|
<tbody class="search-options"></tbody>
|
2021-01-19 22:10:24 +01:00
|
|
|
<tbody class="action-options"></tbody>
|
2021-01-18 22:52:07 +01:00
|
|
|
<tbody>
|
2021-01-17 23:01:01 +01:00
|
|
|
<tr>
|
|
|
|
<td colspan="3">
|
|
|
|
<div style="display: flex; justify-content: space-evenly">
|
2021-01-18 22:52:07 +01:00
|
|
|
<button type="button" class="btn btn-sm search-button">
|
2021-01-17 23:01:01 +01:00
|
|
|
<span class="bx bx-search"></span>
|
2024-08-06 10:39:15 +08:00
|
|
|
${t('search_definition.search')}
|
2021-01-17 23:01:01 +01:00
|
|
|
|
2024-08-06 10:39:15 +08:00
|
|
|
<kbd>${t('search_definition.enter')}</kbd>
|
2021-01-17 23:01:01 +01:00
|
|
|
</button>
|
|
|
|
|
2021-01-18 22:52:07 +01:00
|
|
|
<button type="button" class="btn btn-sm search-and-execute-button">
|
2021-01-17 23:01:01 +01:00
|
|
|
<span class="bx bxs-zap"></span>
|
2024-08-06 10:39:15 +08:00
|
|
|
${t('search_definition.search_execute')}
|
2021-01-17 23:01:01 +01:00
|
|
|
</button>
|
2021-06-06 11:01:10 +02:00
|
|
|
|
|
|
|
<button type="button" class="btn btn-sm save-to-note-button">
|
|
|
|
<span class="bx bx-save"></span>
|
2024-08-06 10:39:15 +08:00
|
|
|
${t('search_definition.save_to_note')}
|
2021-06-06 11:01:10 +02:00
|
|
|
</button>
|
2021-01-17 23:01:01 +01:00
|
|
|
</div>
|
|
|
|
</td>
|
|
|
|
</tr>
|
|
|
|
</tbody>
|
2020-11-26 23:00:27 +01:00
|
|
|
</table>
|
|
|
|
</div>
|
|
|
|
</div>`;
|
|
|
|
|
2021-01-24 22:30:53 +01:00
|
|
|
const OPTION_CLASSES = [
|
|
|
|
SearchString,
|
2021-01-26 22:22:17 +01:00
|
|
|
SearchScript,
|
2021-01-24 22:30:53 +01:00
|
|
|
Ancestor,
|
|
|
|
FastSearch,
|
|
|
|
IncludeArchivedNotes,
|
2021-02-13 23:52:52 +01:00
|
|
|
OrderBy,
|
2021-02-18 22:10:49 +01:00
|
|
|
Limit,
|
|
|
|
Debug
|
2021-01-24 22:30:53 +01:00
|
|
|
];
|
|
|
|
|
2021-05-22 12:35:41 +02:00
|
|
|
export default class SearchDefinitionWidget extends NoteContextAwareWidget {
|
2022-06-08 23:44:43 +02:00
|
|
|
get name() {
|
|
|
|
return "searchDefinition";
|
|
|
|
}
|
|
|
|
|
2021-01-31 20:07:56 +01:00
|
|
|
isEnabled() {
|
|
|
|
return this.note && this.note.type === 'search';
|
|
|
|
}
|
|
|
|
|
2021-05-23 23:41:01 +02:00
|
|
|
getTitle() {
|
2020-11-26 23:00:27 +01:00
|
|
|
return {
|
2021-01-31 20:07:56 +01:00
|
|
|
show: this.isEnabled(),
|
2020-11-26 23:00:27 +01:00
|
|
|
activate: true,
|
2024-08-06 10:39:15 +08:00
|
|
|
title: t('search_definition.search_parameters'),
|
2021-05-23 23:41:01 +02:00
|
|
|
icon: 'bx bx-search'
|
2020-11-26 23:00:27 +01:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
doRender() {
|
|
|
|
this.$widget = $(TPL);
|
2021-06-13 22:55:31 +02:00
|
|
|
this.contentSized();
|
2021-01-17 21:11:01 +01:00
|
|
|
this.$component = this.$widget.find('.search-definition-widget');
|
2022-06-03 17:29:08 +02:00
|
|
|
this.$actionList = this.$widget.find('.action-list');
|
|
|
|
|
2022-06-05 23:36:46 +02:00
|
|
|
for (const actionGroup of bulkActionService.ACTION_GROUPS) {
|
|
|
|
this.$actionList.append($('<h6 class="dropdown-header">').append(actionGroup.title));
|
|
|
|
|
|
|
|
for (const action of actionGroup.actions) {
|
|
|
|
this.$actionList.append(
|
|
|
|
$('<a class="dropdown-item" href="#">')
|
|
|
|
.attr('data-action-add', action.actionName)
|
2024-08-14 22:17:20 +03:00
|
|
|
.text(action.actionTitle)
|
2022-06-05 23:36:46 +02:00
|
|
|
);
|
|
|
|
}
|
2022-06-03 17:29:08 +02:00
|
|
|
}
|
2021-01-17 21:11:01 +01:00
|
|
|
|
|
|
|
this.$widget.on('click', '[data-search-option-add]', async event => {
|
2021-01-24 22:30:53 +01:00
|
|
|
const searchOptionName = $(event.target).attr('data-search-option-add');
|
|
|
|
const clazz = OPTION_CLASSES.find(SearchOptionClass => SearchOptionClass.optionName === searchOptionName);
|
2021-01-17 21:11:01 +01:00
|
|
|
|
2021-01-24 22:30:53 +01:00
|
|
|
if (clazz) {
|
|
|
|
await clazz.create(this.noteId);
|
2021-01-17 21:11:01 +01:00
|
|
|
}
|
2021-01-24 22:30:53 +01:00
|
|
|
else {
|
2024-08-06 10:39:15 +08:00
|
|
|
logError(t('search_definition.unknown_search_option', { searchOptionName }));
|
2021-01-17 21:11:01 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
this.refresh();
|
|
|
|
});
|
|
|
|
|
2021-01-25 21:24:02 +01:00
|
|
|
this.$widget.on('click', '[data-action-add]', async event => {
|
|
|
|
this.$widget.find('.action-add-toggle').dropdown('toggle');
|
|
|
|
|
2022-06-03 17:29:08 +02:00
|
|
|
const actionName = $(event.target).attr('data-action-add');
|
|
|
|
|
|
|
|
await bulkActionService.addAction(this.noteId, actionName);
|
2021-01-25 21:24:02 +01:00
|
|
|
|
|
|
|
this.refresh();
|
|
|
|
});
|
|
|
|
|
|
|
|
this.$searchOptions = this.$widget.find('.search-options');
|
|
|
|
this.$actionOptions = this.$widget.find('.action-options');
|
|
|
|
|
2021-01-18 22:52:07 +01:00
|
|
|
this.$searchButton = this.$widget.find('.search-button');
|
2021-01-25 21:24:02 +01:00
|
|
|
this.$searchButton.on('click', () => this.triggerCommand('refreshResults'));
|
2021-01-18 22:52:07 +01:00
|
|
|
|
|
|
|
this.$searchAndExecuteButton = this.$widget.find('.search-and-execute-button');
|
2021-01-20 20:31:24 +01:00
|
|
|
this.$searchAndExecuteButton.on('click', () => this.searchAndExecute());
|
2021-06-06 11:01:10 +02:00
|
|
|
|
|
|
|
this.$saveToNoteButton = this.$widget.find('.save-to-note-button');
|
|
|
|
this.$saveToNoteButton.on('click', async () => {
|
2021-09-16 21:59:34 +02:00
|
|
|
const {notePath} = await server.post("special-notes/save-search-note", {searchNoteId: this.noteId});
|
2021-06-06 11:01:10 +02:00
|
|
|
|
|
|
|
await ws.waitForMaxKnownEntityChangeId();
|
|
|
|
|
|
|
|
await appContext.tabManager.getActiveContext().setNote(notePath);
|
2024-08-06 10:39:15 +08:00
|
|
|
// Note the {{- notePathTitle}} in json file is not typo, it's unescaping
|
|
|
|
// See https://www.i18next.com/translation-function/interpolation#unescape
|
|
|
|
toastService.showMessage(t('search_definition.search_note_saved', { notePathTitle: await treeService.getNotePathTitle(notePath) }));
|
2021-06-06 11:01:10 +02:00
|
|
|
});
|
2020-11-26 23:00:27 +01:00
|
|
|
}
|
|
|
|
|
2021-01-25 21:24:02 +01:00
|
|
|
async refreshResultsCommand() {
|
2021-01-26 22:22:17 +01:00
|
|
|
try {
|
2022-12-17 13:07:42 +01:00
|
|
|
const {error} = await froca.loadSearchNote(this.noteId);
|
|
|
|
|
|
|
|
if (error) {
|
|
|
|
this.handleEvent('showSearchError', { error });
|
|
|
|
}
|
2021-01-26 22:22:17 +01:00
|
|
|
}
|
|
|
|
catch (e) {
|
|
|
|
toastService.showError(e.message);
|
|
|
|
}
|
2021-01-18 22:52:07 +01:00
|
|
|
|
2021-05-22 12:26:45 +02:00
|
|
|
this.triggerEvent('searchRefreshed', {ntxId: this.noteContext.ntxId});
|
2020-11-26 23:00:27 +01:00
|
|
|
}
|
|
|
|
|
2021-01-26 10:42:55 +01:00
|
|
|
async refreshSearchDefinitionCommand() {
|
|
|
|
await this.refresh();
|
|
|
|
}
|
|
|
|
|
2020-11-30 23:20:12 +01:00
|
|
|
async refreshWithNote(note) {
|
2020-11-26 23:00:27 +01:00
|
|
|
this.$component.show();
|
2020-12-05 23:00:28 +01:00
|
|
|
|
2023-01-13 10:09:41 +01:00
|
|
|
this.$saveToNoteButton.toggle(note.isHiddenCompletely());
|
2021-06-06 11:01:10 +02:00
|
|
|
|
2021-01-24 22:30:53 +01:00
|
|
|
this.$searchOptions.empty();
|
2021-01-17 21:11:01 +01:00
|
|
|
|
2021-01-24 22:30:53 +01:00
|
|
|
for (const OptionClass of OPTION_CLASSES) {
|
|
|
|
const {attributeType, optionName} = OptionClass;
|
2021-01-17 21:11:01 +01:00
|
|
|
|
2021-01-24 22:30:53 +01:00
|
|
|
const attr = this.note.getAttribute(attributeType, optionName);
|
2021-01-17 21:11:01 +01:00
|
|
|
|
2021-01-24 22:30:53 +01:00
|
|
|
this.$widget.find(`[data-search-option-add='${optionName}'`).toggle(!attr);
|
2021-01-25 21:24:02 +01:00
|
|
|
|
2021-01-24 22:30:53 +01:00
|
|
|
if (attr) {
|
2021-01-25 21:24:02 +01:00
|
|
|
const searchOption = new OptionClass(attr, this.note).setParent(this);
|
|
|
|
this.child(searchOption);
|
2020-12-05 23:00:28 +01:00
|
|
|
|
2021-01-24 22:30:53 +01:00
|
|
|
this.$searchOptions.append(searchOption.render());
|
|
|
|
}
|
2021-01-17 21:11:01 +01:00
|
|
|
}
|
2020-12-04 22:57:54 +01:00
|
|
|
|
2022-06-03 17:29:08 +02:00
|
|
|
const actions = bulkActionService.parseActions(this.note);
|
2021-01-18 22:52:07 +01:00
|
|
|
|
2022-06-03 17:29:08 +02:00
|
|
|
this.$actionOptions
|
|
|
|
.empty()
|
|
|
|
.append(...actions.map(action => action.render()));
|
2021-01-17 23:01:01 +01:00
|
|
|
|
2022-12-21 16:11:00 +01:00
|
|
|
this.$searchAndExecuteButton.css('visibility', actions.length > 0 ? 'visible' : '_hidden');
|
2020-12-04 22:57:54 +01:00
|
|
|
}
|
|
|
|
|
2020-11-26 23:00:27 +01:00
|
|
|
getContent() {
|
2021-01-08 19:57:49 +01:00
|
|
|
return '';
|
2020-11-26 23:00:27 +01:00
|
|
|
}
|
2021-01-20 20:31:24 +01:00
|
|
|
|
|
|
|
async searchAndExecute() {
|
|
|
|
await server.post(`search-and-execute-note/${this.noteId}`);
|
|
|
|
|
2021-01-25 21:24:02 +01:00
|
|
|
this.triggerCommand('refreshResults');
|
2021-01-20 20:31:24 +01:00
|
|
|
|
2024-08-06 10:39:15 +08:00
|
|
|
toastService.showMessage(t('search_definition.actions_executed'), 3000);
|
2021-01-20 20:31:24 +01:00
|
|
|
}
|
2022-06-11 23:29:52 +02:00
|
|
|
|
|
|
|
entitiesReloadedEvent({loadResults}) {
|
2022-06-12 00:05:46 +02:00
|
|
|
// only refreshing deleted attrs, otherwise components update themselves
|
2023-06-05 16:26:05 +02:00
|
|
|
if (loadResults.getAttributeRows().find(attrRow =>
|
|
|
|
attrRow.type === 'label' && attrRow.name === 'action' && attrRow.isDeleted)) {
|
|
|
|
|
2022-06-11 23:29:52 +02:00
|
|
|
this.refresh();
|
|
|
|
}
|
|
|
|
}
|
2020-11-26 23:00:27 +01:00
|
|
|
}
|