mirror of
https://github.com/zadam/trilium.git
synced 2025-11-07 15:09:01 +01:00
chore(react/ribbon): working execute search button
This commit is contained in:
parent
c1b30db3d1
commit
759398d804
@ -848,7 +848,7 @@
|
|||||||
"debug": "调试",
|
"debug": "调试",
|
||||||
"debug_description": "调试将打印额外的调试信息到控制台,以帮助调试复杂查询",
|
"debug_description": "调试将打印额外的调试信息到控制台,以帮助调试复杂查询",
|
||||||
"action": "操作",
|
"action": "操作",
|
||||||
"search_button": "搜索 <kbd>回车</kbd>",
|
"search_button": "搜索",
|
||||||
"search_execute": "搜索并执行操作",
|
"search_execute": "搜索并执行操作",
|
||||||
"save_to_note": "保存到笔记",
|
"save_to_note": "保存到笔记",
|
||||||
"search_parameters": "搜索参数",
|
"search_parameters": "搜索参数",
|
||||||
|
|||||||
@ -828,7 +828,7 @@
|
|||||||
"debug": "debuggen",
|
"debug": "debuggen",
|
||||||
"debug_description": "Debug gibt zusätzliche Debuginformationen in die Konsole aus, um das Debuggen komplexer Abfragen zu erleichtern",
|
"debug_description": "Debug gibt zusätzliche Debuginformationen in die Konsole aus, um das Debuggen komplexer Abfragen zu erleichtern",
|
||||||
"action": "Aktion",
|
"action": "Aktion",
|
||||||
"search_button": "Suchen <kbd>Eingabetaste</kbd>",
|
"search_button": "Suchen",
|
||||||
"search_execute": "Aktionen suchen und ausführen",
|
"search_execute": "Aktionen suchen und ausführen",
|
||||||
"save_to_note": "Als Notiz speichern",
|
"save_to_note": "Als Notiz speichern",
|
||||||
"search_parameters": "Suchparameter",
|
"search_parameters": "Suchparameter",
|
||||||
|
|||||||
@ -848,7 +848,7 @@
|
|||||||
"debug": "debug",
|
"debug": "debug",
|
||||||
"debug_description": "Debug will print extra debugging information into the console to aid in debugging complex queries",
|
"debug_description": "Debug will print extra debugging information into the console to aid in debugging complex queries",
|
||||||
"action": "action",
|
"action": "action",
|
||||||
"search_button": "Search <kbd>enter</kbd>",
|
"search_button": "Search",
|
||||||
"search_execute": "Search & Execute actions",
|
"search_execute": "Search & Execute actions",
|
||||||
"save_to_note": "Save to note",
|
"save_to_note": "Save to note",
|
||||||
"search_parameters": "Search Parameters",
|
"search_parameters": "Search Parameters",
|
||||||
|
|||||||
@ -848,7 +848,7 @@
|
|||||||
"debug": "depurar",
|
"debug": "depurar",
|
||||||
"debug_description": "La depuración imprimirá información de depuración adicional en la consola para ayudar a depurar consultas complejas",
|
"debug_description": "La depuración imprimirá información de depuración adicional en la consola para ayudar a depurar consultas complejas",
|
||||||
"action": "acción",
|
"action": "acción",
|
||||||
"search_button": "Buscar <kbd>Enter</kbd>",
|
"search_button": "Buscar",
|
||||||
"search_execute": "Buscar y ejecutar acciones",
|
"search_execute": "Buscar y ejecutar acciones",
|
||||||
"save_to_note": "Guardar en nota",
|
"save_to_note": "Guardar en nota",
|
||||||
"search_parameters": "Parámetros de búsqueda",
|
"search_parameters": "Parámetros de búsqueda",
|
||||||
|
|||||||
@ -848,7 +848,7 @@
|
|||||||
"debug": "debug",
|
"debug": "debug",
|
||||||
"debug_description": "Debug imprimera des informations supplémentaires dans la console pour faciliter le débogage des requêtes complexes",
|
"debug_description": "Debug imprimera des informations supplémentaires dans la console pour faciliter le débogage des requêtes complexes",
|
||||||
"action": "action",
|
"action": "action",
|
||||||
"search_button": "Recherche <kbd>Entrée</kbd>",
|
"search_button": "Recherche",
|
||||||
"search_execute": "Rechercher et exécuter des actions",
|
"search_execute": "Rechercher et exécuter des actions",
|
||||||
"save_to_note": "Enregistrer dans la note",
|
"save_to_note": "Enregistrer dans la note",
|
||||||
"search_parameters": "Paramètres de recherche",
|
"search_parameters": "Paramètres de recherche",
|
||||||
|
|||||||
@ -185,7 +185,7 @@
|
|||||||
"debug": "デバッグ",
|
"debug": "デバッグ",
|
||||||
"debug_description": "デバッグは複雑なクエリのデバッグを支援するために、追加のデバッグ情報をコンソールに出力します",
|
"debug_description": "デバッグは複雑なクエリのデバッグを支援するために、追加のデバッグ情報をコンソールに出力します",
|
||||||
"action": "アクション",
|
"action": "アクション",
|
||||||
"search_button": "検索 <kbd>Enter</kbd>",
|
"search_button": "検索",
|
||||||
"search_execute": "検索とアクションの実行",
|
"search_execute": "検索とアクションの実行",
|
||||||
"save_to_note": "ノートに保存",
|
"save_to_note": "ノートに保存",
|
||||||
"search_parameters": "検索パラメータ",
|
"search_parameters": "検索パラメータ",
|
||||||
|
|||||||
@ -1006,7 +1006,7 @@
|
|||||||
"limit_description": "Limitar número de resultados",
|
"limit_description": "Limitar número de resultados",
|
||||||
"debug": "depurar",
|
"debug": "depurar",
|
||||||
"action": "ação",
|
"action": "ação",
|
||||||
"search_button": "Pesquisar <kbd>enter</kbd>",
|
"search_button": "Pesquisar",
|
||||||
"search_execute": "Pesquisar & Executar ações",
|
"search_execute": "Pesquisar & Executar ações",
|
||||||
"save_to_note": "Salvar para nota",
|
"save_to_note": "Salvar para nota",
|
||||||
"search_parameters": "Parâmetros de Pesquisa",
|
"search_parameters": "Parâmetros de Pesquisa",
|
||||||
|
|||||||
@ -1106,7 +1106,7 @@
|
|||||||
"limit_description": "Limitează numărul de rezultate",
|
"limit_description": "Limitează numărul de rezultate",
|
||||||
"order_by": "ordonează după",
|
"order_by": "ordonează după",
|
||||||
"save_to_note": "Salvează în notiță",
|
"save_to_note": "Salvează în notiță",
|
||||||
"search_button": "Căutare <kbd>Enter</kbd>",
|
"search_button": "Căutare",
|
||||||
"search_execute": "Caută și execută acțiunile",
|
"search_execute": "Caută și execută acțiunile",
|
||||||
"search_note_saved": "Notița de căutare a fost salvată în {{- notePathTitle}}",
|
"search_note_saved": "Notița de căutare a fost salvată în {{- notePathTitle}}",
|
||||||
"search_parameters": "Parametrii de căutare",
|
"search_parameters": "Parametrii de căutare",
|
||||||
|
|||||||
@ -1060,7 +1060,7 @@
|
|||||||
"fast_search": "быстрый поиск",
|
"fast_search": "быстрый поиск",
|
||||||
"include_archived": "включать архивированные",
|
"include_archived": "включать архивированные",
|
||||||
"order_by": "сортировать по",
|
"order_by": "сортировать по",
|
||||||
"search_button": "Поиск <kbd>enter</kbd>",
|
"search_button": "Поиск",
|
||||||
"search_parameters": "Параметры поиска",
|
"search_parameters": "Параметры поиска",
|
||||||
"ancestor": "предок",
|
"ancestor": "предок",
|
||||||
"action": "действие",
|
"action": "действие",
|
||||||
|
|||||||
@ -845,7 +845,7 @@
|
|||||||
"debug": "除錯",
|
"debug": "除錯",
|
||||||
"debug_description": "除錯將顯示額外的除錯資訊至控制台,以幫助除錯複雜查詢",
|
"debug_description": "除錯將顯示額外的除錯資訊至控制台,以幫助除錯複雜查詢",
|
||||||
"action": "操作",
|
"action": "操作",
|
||||||
"search_button": "搜尋 <kbd>Enter</kbd>",
|
"search_button": "搜尋",
|
||||||
"search_execute": "搜尋並執行操作",
|
"search_execute": "搜尋並執行操作",
|
||||||
"save_to_note": "儲存至筆記",
|
"save_to_note": "儲存至筆記",
|
||||||
"search_parameters": "搜尋參數",
|
"search_parameters": "搜尋參數",
|
||||||
|
|||||||
@ -960,7 +960,7 @@
|
|||||||
"debug": "debug",
|
"debug": "debug",
|
||||||
"debug_description": "Debug виведе додаткову інформацію для налагодження в консоль, щоб допомогти у налагодженні складних запитів",
|
"debug_description": "Debug виведе додаткову інформацію для налагодження в консоль, щоб допомогти у налагодженні складних запитів",
|
||||||
"action": "дія",
|
"action": "дія",
|
||||||
"search_button": "Пошук <kbd>enter</kbd>",
|
"search_button": "Пошук",
|
||||||
"search_execute": "Пошук & Виконання дій",
|
"search_execute": "Пошук & Виконання дій",
|
||||||
"save_to_note": "Зберегти до нотатки",
|
"save_to_note": "Зберегти до нотатки",
|
||||||
"search_parameters": "Параметри пошуку",
|
"search_parameters": "Параметри пошуку",
|
||||||
|
|||||||
@ -1,22 +1,26 @@
|
|||||||
interface FormTextAreaProps {
|
import { TextareaHTMLAttributes } from "preact/compat";
|
||||||
|
|
||||||
|
interface FormTextAreaProps extends Omit<TextareaHTMLAttributes, "onBlur" | "onChange"> {
|
||||||
id?: string;
|
id?: string;
|
||||||
currentValue: string;
|
currentValue: string;
|
||||||
|
onChange?(newValue: string): void;
|
||||||
onBlur?(newValue: string): void;
|
onBlur?(newValue: string): void;
|
||||||
rows: number;
|
rows: number;
|
||||||
className?: string;
|
|
||||||
placeholder?: string;
|
|
||||||
}
|
}
|
||||||
export default function FormTextArea({ id, onBlur, rows, currentValue, className, placeholder }: FormTextAreaProps) {
|
export default function FormTextArea({ id, onBlur, onChange, rows, currentValue, className, ...restProps }: FormTextAreaProps) {
|
||||||
return (
|
return (
|
||||||
<textarea
|
<textarea
|
||||||
id={id}
|
id={id}
|
||||||
rows={rows}
|
rows={rows}
|
||||||
className={`form-control ${className ?? ""}`}
|
className={`form-control ${className ?? ""}`}
|
||||||
|
onChange={(e) => {
|
||||||
|
onChange?.(e.currentTarget.value);
|
||||||
|
}}
|
||||||
onBlur={(e) => {
|
onBlur={(e) => {
|
||||||
onBlur?.(e.currentTarget.value);
|
onBlur?.(e.currentTarget.value);
|
||||||
}}
|
}}
|
||||||
style={{ width: "100%" }}
|
style={{ width: "100%" }}
|
||||||
placeholder={placeholder}
|
{...restProps}
|
||||||
>{currentValue}</textarea>
|
>{currentValue}</textarea>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -109,7 +109,7 @@ export function useTriliumEventBeta<T extends EventNames>(eventName: T | T[], ha
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function useSpacedUpdate(callback: () => Promise<void>, interval = 1000) {
|
export function useSpacedUpdate(callback: () => void | Promise<void>, interval = 1000) {
|
||||||
const callbackRef = useRef(callback);
|
const callbackRef = useRef(callback);
|
||||||
const spacedUpdateRef = useRef<SpacedUpdate>();
|
const spacedUpdateRef = useRef<SpacedUpdate>();
|
||||||
|
|
||||||
|
|||||||
@ -6,9 +6,16 @@ import Dropdown from "../react/Dropdown";
|
|||||||
import ActionButton from "../react/ActionButton";
|
import ActionButton from "../react/ActionButton";
|
||||||
import FormTextArea from "../react/FormTextArea";
|
import FormTextArea from "../react/FormTextArea";
|
||||||
import { AttributeType, OptionNames } from "@triliumnext/commons";
|
import { AttributeType, OptionNames } from "@triliumnext/commons";
|
||||||
import { removeOwnedAttributesByNameOrType } from "../../services/attributes";
|
import attributes, { removeOwnedAttributesByNameOrType } from "../../services/attributes";
|
||||||
import { note } from "mermaid/dist/rendering-util/rendering-elements/shapes/note.js";
|
import { note } from "mermaid/dist/rendering-util/rendering-elements/shapes/note.js";
|
||||||
import FNote from "../../entities/fnote";
|
import FNote from "../../entities/fnote";
|
||||||
|
import toast from "../../services/toast";
|
||||||
|
import froca from "../../services/froca";
|
||||||
|
import { useContext, useRef } from "preact/hooks";
|
||||||
|
import { ParentComponent } from "../react/react_utils";
|
||||||
|
import { useSpacedUpdate } from "../react/hooks";
|
||||||
|
import appContext from "../../components/app_context";
|
||||||
|
import server from "../../services/server";
|
||||||
|
|
||||||
interface SearchOption {
|
interface SearchOption {
|
||||||
searchOption: string;
|
searchOption: string;
|
||||||
@ -64,7 +71,29 @@ const SEARCH_OPTIONS: SearchOption[] = [
|
|||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
export default function SearchDefinitionTab({ note }: TabContext) {
|
export default function SearchDefinitionTab({ note, ntxId }: TabContext) {
|
||||||
|
const parentComponent = useContext(ParentComponent);
|
||||||
|
|
||||||
|
|
||||||
|
async function refreshResults() {
|
||||||
|
const noteId = note?.noteId;
|
||||||
|
if (!noteId) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const result = await froca.loadSearchNote(noteId);
|
||||||
|
|
||||||
|
if (result && result.error) {
|
||||||
|
//this.handleEvent("showSearchError", { error: result.error });
|
||||||
|
}
|
||||||
|
} catch (e: any) {
|
||||||
|
toast.showError(e.message);
|
||||||
|
}
|
||||||
|
|
||||||
|
parentComponent?.triggerEvent("searchRefreshed", { ntxId });
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="search-definition-widget">
|
<div className="search-definition-widget">
|
||||||
<div className="search-settings">
|
<div className="search-settings">
|
||||||
@ -82,7 +111,27 @@ export default function SearchDefinitionTab({ note }: TabContext) {
|
|||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tbody className="search-options">
|
<tbody className="search-options">
|
||||||
<SearchStringOption />
|
<SearchStringOption
|
||||||
|
refreshResults={refreshResults}
|
||||||
|
note={note}
|
||||||
|
/>
|
||||||
|
</tbody>
|
||||||
|
<tbody className="action-options">
|
||||||
|
|
||||||
|
</tbody>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td colSpan={3}>
|
||||||
|
<div style={{ display: "flex", justifyContent: "space-evenly" }}>
|
||||||
|
<Button
|
||||||
|
icon="bx bx-search"
|
||||||
|
text={t("search_definition.search_button")}
|
||||||
|
keyboardShortcut="Enter"
|
||||||
|
onClick={refreshResults}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
@ -114,7 +163,21 @@ function SearchOption({ note, title, children, help, attributeName, attributeTyp
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
function SearchStringOption() {
|
function SearchStringOption({ note, refreshResults }: { note: FNote, refreshResults: () => void }) {
|
||||||
|
const currentValue = useRef("");
|
||||||
|
const spacedUpdate = useSpacedUpdate(async () => {
|
||||||
|
const searchString = currentValue.current;
|
||||||
|
appContext.lastSearchString = searchString;
|
||||||
|
|
||||||
|
await attributes.setAttribute(note, "label", "searchString", searchString);
|
||||||
|
|
||||||
|
if (note.title.startsWith(t("search_string.search_prefix"))) {
|
||||||
|
await server.put(`notes/${note.noteId}/title`, {
|
||||||
|
title: `${t("search_string.search_prefix")} ${searchString.length < 30 ? searchString : `${searchString.substr(0, 30)}…`}`
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, 1000);
|
||||||
|
|
||||||
return <SearchOption
|
return <SearchOption
|
||||||
title={t("search_string.title_column")}
|
title={t("search_string.title_column")}
|
||||||
help={<>
|
help={<>
|
||||||
@ -133,6 +196,21 @@ function SearchStringOption() {
|
|||||||
<FormTextArea
|
<FormTextArea
|
||||||
className="search-string"
|
className="search-string"
|
||||||
placeholder={t("search_string.placeholder")}
|
placeholder={t("search_string.placeholder")}
|
||||||
|
onChange={text => {
|
||||||
|
currentValue.current = text;
|
||||||
|
spacedUpdate.scheduleUpdate();
|
||||||
|
}}
|
||||||
|
onKeyDown={async (e) => {
|
||||||
|
if (e.key === "Enter") {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
// this also in effect disallows new lines in query string.
|
||||||
|
// on one hand, this makes sense since search string is a label
|
||||||
|
// on the other hand, it could be nice for structuring long search string. It's probably a niche case though.
|
||||||
|
await spacedUpdate.updateNowIfNecessary();
|
||||||
|
refreshResults();
|
||||||
|
}
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
</SearchOption>
|
</SearchOption>
|
||||||
}
|
}
|
||||||
@ -43,7 +43,7 @@ const TPL = /*html*/`
|
|||||||
<div style="display: flex; justify-content: space-evenly">
|
<div style="display: flex; justify-content: space-evenly">
|
||||||
<button type="button" class="btn btn-sm search-button">
|
<button type="button" class="btn btn-sm search-button">
|
||||||
<span class="bx bx-search"></span>
|
<span class="bx bx-search"></span>
|
||||||
${t("search_definition.search_button")}
|
${}
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<button type="button" class="btn btn-sm search-and-execute-button">
|
<button type="button" class="btn btn-sm search-and-execute-button">
|
||||||
@ -126,9 +126,6 @@ export default class SearchDefinitionWidget extends NoteContextAwareWidget {
|
|||||||
this.$searchOptions = this.$widget.find(".search-options");
|
this.$searchOptions = this.$widget.find(".search-options");
|
||||||
this.$actionOptions = this.$widget.find(".action-options");
|
this.$actionOptions = this.$widget.find(".action-options");
|
||||||
|
|
||||||
this.$searchButton = this.$widget.find(".search-button");
|
|
||||||
this.$searchButton.on("click", () => this.triggerCommand("refreshResults"));
|
|
||||||
|
|
||||||
this.$searchAndExecuteButton = this.$widget.find(".search-and-execute-button");
|
this.$searchAndExecuteButton = this.$widget.find(".search-and-execute-button");
|
||||||
this.$searchAndExecuteButton.on("click", () => this.searchAndExecute());
|
this.$searchAndExecuteButton.on("click", () => this.searchAndExecute());
|
||||||
|
|
||||||
@ -145,24 +142,6 @@ export default class SearchDefinitionWidget extends NoteContextAwareWidget {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async refreshResultsCommand() {
|
|
||||||
if (!this.noteId) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
const result = await froca.loadSearchNote(this.noteId);
|
|
||||||
|
|
||||||
if (result && result.error) {
|
|
||||||
this.handleEvent("showSearchError", { error: result.error });
|
|
||||||
}
|
|
||||||
} catch (e: any) {
|
|
||||||
toastService.showError(e.message);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.triggerEvent("searchRefreshed", { ntxId: this.noteContext?.ntxId });
|
|
||||||
}
|
|
||||||
|
|
||||||
async refreshWithNote(note: FNote) {
|
async refreshWithNote(note: FNote) {
|
||||||
if (!this.note) {
|
if (!this.note) {
|
||||||
return;
|
return;
|
||||||
|
|||||||
@ -19,12 +19,6 @@ export default abstract class AbstractSearchOption extends Component {
|
|||||||
this.note = note;
|
this.note = note;
|
||||||
}
|
}
|
||||||
|
|
||||||
static async setAttribute(noteId: string, type: AttributeType, name: string, value: string = "") {
|
|
||||||
await server.put(`notes/${noteId}/set-attribute`, { type, name, value });
|
|
||||||
|
|
||||||
await ws.waitForMaxKnownEntityChangeId();
|
|
||||||
}
|
|
||||||
|
|
||||||
async setAttribute(type: AttributeType, name: string, value: string = "") {
|
async setAttribute(type: AttributeType, name: string, value: string = "") {
|
||||||
// TODO: Find a better pattern.
|
// TODO: Find a better pattern.
|
||||||
await (this.constructor as any).setAttribute(this.note.noteId, type, name, value);
|
await (this.constructor as any).setAttribute(this.note.noteId, type, name, value);
|
||||||
|
|||||||
@ -25,28 +25,9 @@ export default class SearchString extends AbstractSearchOption {
|
|||||||
doRender() {
|
doRender() {
|
||||||
const $option = $(TPL);
|
const $option = $(TPL);
|
||||||
this.$searchString = $option.find(".search-string");
|
this.$searchString = $option.find(".search-string");
|
||||||
this.$searchString.on("input", () => this.spacedUpdate.scheduleUpdate());
|
|
||||||
|
|
||||||
shortcutService.bindElShortcut(this.$searchString, "return", async () => {
|
|
||||||
// this also in effect disallows new lines in query string.
|
|
||||||
// on one hand, this makes sense since search string is a label
|
|
||||||
// on the other hand, it could be nice for structuring long search string. It's probably a niche case though.
|
|
||||||
await this.spacedUpdate.updateNowIfNecessary();
|
|
||||||
|
|
||||||
this.triggerCommand("refreshResults");
|
|
||||||
});
|
|
||||||
|
|
||||||
this.spacedUpdate = new SpacedUpdate(async () => {
|
this.spacedUpdate = new SpacedUpdate(async () => {
|
||||||
const searchString = String(this.$searchString.val());
|
|
||||||
appContext.lastSearchString = searchString;
|
|
||||||
|
|
||||||
await this.setAttribute("label", "searchString", searchString);
|
|
||||||
|
|
||||||
if (this.note.title.startsWith(t("search_string.search_prefix"))) {
|
|
||||||
await server.put(`notes/${this.note.noteId}/title`, {
|
|
||||||
title: `${t("search_string.search_prefix")} ${searchString.length < 30 ? searchString : `${searchString.substr(0, 30)}…`}`
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}, 1000);
|
}, 1000);
|
||||||
|
|
||||||
this.$searchString.val(this.note.getLabelValue("searchString") ?? "");
|
this.$searchString.val(this.note.getLabelValue("searchString") ?? "");
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user