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" ;
2021-06-06 11:01:10 +02:00
import appContext from "../../services/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 : 7 px ;
2020-11-26 23:00:27 +01:00
width : 100 % ;
border - collapse : separate ;
border - spacing : 10 px ;
}
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 : 50 px ;
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 : 50 px ;
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 : 1 px ;
border - color : var ( -- main - border - color ) ;
position : relative ;
top : 4 px ;
margin - top : 5 px ;
margin - bottom : 0 ;
}
2021-01-20 20:31:24 +01:00
. search - definition - widget input : invalid {
border : 3 px solid red ;
}
2021-01-26 22:22:17 +01:00
. add - search - option button {
margin - top : 5 px ; /* 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
< / s t y l e >
< div class = "search-settings" >
< table class = "search-setting-table" >
< tr >
2021-01-26 14:10:34 +01:00
< td class = "title-column" > Add search option : < / t d >
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" > < / s p a n >
search string
< / b u t t o n >
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" > < / s p a n >
search script
< / b u t t o n >
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" > < / s p a n >
2021-01-18 22:52:07 +01:00
ancestor
2021-01-08 19:57:49 +01:00
< / b u t t o n >
2021-01-17 21:11:01 +01:00
< button type = "button" class = "btn btn-sm" data - search - option - add = "fastSearch"
2021-01-08 19:57:49 +01:00
title = "Fast search option disables full text search of note contents which might speed up searching in large databases." >
< span class = "bx bx-run" > < / s p a n >
fast search
< / b u t t o n >
2021-01-17 21:11:01 +01:00
< button type = "button" class = "btn btn-sm" data - search - option - add = "includeArchivedNotes"
2021-01-08 19:57:49 +01:00
title = "Archived notes are by default excluded from search results, with this option they will be included." >
< span class = "bx bx-archive" > < / s p a n >
include archived
< / b u t t o n >
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" > < / s p a n >
order by
< / b u t t o n >
2021-02-13 23:52:52 +01:00
< button type = "button" class = "btn btn-sm" data - search - option - add = "limit" title = "Limit number of results" >
< span class = "bx bx-stop" > < / s p a n >
limit
< / b u t t o n >
2021-02-18 22:10:49 +01:00
< button type = "button" class = "btn btn-sm" data - search - option - add = "debug" title = "Debug will print extra debugging information into the console to aid in debugging complex queries" >
< span class = "bx bx-bug" > < / s p a n >
debug
< / b u t t o n >
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" > < / s p a n >
action
< / b u t t o n >
2022-06-03 17:29:08 +02:00
< div class = "dropdown-menu action-list" > < / d i v >
2021-01-08 19:57:49 +01:00
< / d i v >
< / t d >
< / t r >
2021-01-24 22:30:53 +01:00
< tbody class = "search-options" > < / t b o d y >
2021-01-19 22:10:24 +01:00
< tbody class = "action-options" > < / t b o d y >
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" > < / s p a n >
Search
< kbd > enter < / k b d >
< / b u t t o n >
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" > < / s p a n >
Search & Execute actions
< / b u t t o n >
2021-06-06 11:01:10 +02:00
< button type = "button" class = "btn btn-sm save-to-note-button" >
< span class = "bx bx-save" > < / s p a n >
Save to note
< / b u t t o n >
2021-01-17 23:01:01 +01:00
< / d i v >
< / t d >
< / t r >
< / t b o d y >
2020-11-26 23:00:27 +01:00
< / t a b l e >
< / d i v >
< / d i v > ` ;
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 ,
2021-05-28 23:19:11 +02:00
title : '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 )
. text ( action . actionTitle )
) ;
}
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 {
logError ( ` 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 ) ;
toastService . showMessage ( "Search note has been saved into " + await treeService . getNotePathTitle ( notePath ) ) ;
} ) ;
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 {
2021-04-16 22:57:37 +02:00
await froca . loadSearchNote ( this . noteId ) ;
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
2021-06-06 11:01:10 +02:00
this . $saveToNoteButton . toggle ( ! note . getAllNotePaths ( ) . find ( notePathArr => ! notePathArr . includes ( "hidden" ) ) ) ;
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-06-03 17:29:08 +02: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
toastService . showMessage ( 'Actions have been executed.' , 3000 ) ;
}
2022-06-11 23:29:52 +02:00
entitiesReloadedEvent ( { loadResults } ) {
if ( loadResults . getAttributes ( ) . find ( attr => attr . type === 'label' && attr . name === 'action' ) ) {
this . refresh ( ) ;
}
}
2020-11-26 23:00:27 +01:00
}