chore(react/ribbon): save search to note

This commit is contained in:
Elian Doran
2025-08-24 16:56:22 +03:00
parent 3f105f7b8b
commit 04fbc82d7c
6 changed files with 35 additions and 59 deletions

View File

@@ -5,7 +5,7 @@ import { TabContext } from "./ribbon-interface";
import Dropdown from "../react/Dropdown";
import ActionButton from "../react/ActionButton";
import FormTextArea from "../react/FormTextArea";
import { AttributeType, OptionNames } from "@triliumnext/commons";
import { AttributeType, OptionNames, SaveSearchNoteResponse } from "@triliumnext/commons";
import attributes, { removeOwnedAttributesByNameOrType } from "../../services/attributes";
import { note } from "mermaid/dist/rendering-util/rendering-elements/shapes/note.js";
import FNote from "../../entities/fnote";
@@ -17,6 +17,8 @@ import { useNoteLabel, useSpacedUpdate, useTooltip, useTriliumEventBeta } from "
import appContext from "../../components/app_context";
import server from "../../services/server";
import { tooltip } from "leaflet";
import ws from "../../services/ws";
import tree from "../../services/tree";
interface SearchOption {
attributeName: string;
@@ -195,6 +197,24 @@ export default function SearchDefinitionTab({ note, ntxId }: TabContext) {
toast.showMessage(t("search_definition.actions_executed"), 3000);
}}
/>
{note.isHiddenCompletely() && <Button
icon="bx bx-save"
text={t("search_definition.save_to_note")}
onClick={async () => {
const { notePath } = await server.post<SaveSearchNoteResponse>("special-notes/save-search-note", { searchNoteId: note.noteId });
if (!notePath) {
return;
}
await ws.waitForMaxKnownEntityChangeId();
await appContext.tabManager.getActiveContext()?.setNote(notePath);
// Note the {{- notePathTitle}} in json file is not typo, it's unescaping
// See https://www.i18next.com/translation-function/interpolation#unescape
toast.showMessage(t("search_definition.search_note_saved", { notePathTitle: await tree.getNotePathTitle(notePath) }));
}}
/>}
</div>
</td>
</tr>

View File

@@ -37,29 +37,12 @@ const TPL = /*html*/`
</tr>
<tbody class="search-options"></tbody>
<tbody class="action-options"></tbody>
<tbody>
<tr>
<td colspan="3">
<div style="display: flex; justify-content: space-evenly">
<button type="button" class="btn btn-sm save-to-note-button">
<span class="bx bx-save"></span>
${t("search_definition.save_to_note")}
</button>
</div>
</td>
</tr>
</tbody>
</table>
</div>
</div>`;
const OPTION_CLASSES = [SearchString, SearchScript, Ancestor, FastSearch, IncludeArchivedNotes, OrderBy, Limit, Debug];
// TODO: Deduplicate with server
interface SaveSearchNoteResponse {
notePath: string;
}
export default class SearchDefinitionWidget extends NoteContextAwareWidget {
private $component!: JQuery<HTMLElement>;
@@ -88,19 +71,6 @@ export default class SearchDefinitionWidget extends NoteContextAwareWidget {
}
}
this.$widget.on("click", "[data-search-option-add]", async (event) => {
const searchOptionName = $(event.target).attr("data-search-option-add");
const clazz = OPTION_CLASSES.find((SearchOptionClass) => SearchOptionClass.optionName === searchOptionName);
if (clazz && this.noteId) {
await clazz.create(this.noteId);
} else {
logError(t("search_definition.unknown_search_option", { searchOptionName }));
}
this.refresh();
});
this.$widget.on("click", "[data-action-add]", async (event) => {
Dropdown.getOrCreateInstance(this.$widget.find(".action-add-toggle")[0]);
@@ -115,18 +85,6 @@ export default class SearchDefinitionWidget extends NoteContextAwareWidget {
this.$searchOptions = this.$widget.find(".search-options");
this.$actionOptions = this.$widget.find(".action-options");
this.$saveToNoteButton = this.$widget.find(".save-to-note-button");
this.$saveToNoteButton.on("click", async () => {
const { notePath } = await server.post<SaveSearchNoteResponse>("special-notes/save-search-note", { searchNoteId: this.noteId });
await ws.waitForMaxKnownEntityChangeId();
await appContext.tabManager.getActiveContext()?.setNote(notePath);
// 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) }));
});
}
async refreshWithNote(note: FNote) {
@@ -134,12 +92,6 @@ export default class SearchDefinitionWidget extends NoteContextAwareWidget {
return;
}
this.$component.show();
this.$saveToNoteButton.toggle(note.isHiddenCompletely());
this.$searchOptions.empty();
const actions = bulkActionService.parseActions(this.note);
const renderedEls = actions
.map((action) => renderReactWidget(this, action.doRender()))