mirror of
https://github.com/zadam/trilium.git
synced 2025-10-21 07:38:53 +02:00
chore(react/ribbon): save search to note
This commit is contained in:
parent
3f105f7b8b
commit
04fbc82d7c
@ -5,7 +5,7 @@ import { TabContext } from "./ribbon-interface";
|
|||||||
import Dropdown from "../react/Dropdown";
|
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, SaveSearchNoteResponse } from "@triliumnext/commons";
|
||||||
import attributes, { 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";
|
||||||
@ -17,6 +17,8 @@ import { useNoteLabel, useSpacedUpdate, useTooltip, useTriliumEventBeta } from "
|
|||||||
import appContext from "../../components/app_context";
|
import appContext from "../../components/app_context";
|
||||||
import server from "../../services/server";
|
import server from "../../services/server";
|
||||||
import { tooltip } from "leaflet";
|
import { tooltip } from "leaflet";
|
||||||
|
import ws from "../../services/ws";
|
||||||
|
import tree from "../../services/tree";
|
||||||
|
|
||||||
interface SearchOption {
|
interface SearchOption {
|
||||||
attributeName: string;
|
attributeName: string;
|
||||||
@ -195,6 +197,24 @@ export default function SearchDefinitionTab({ note, ntxId }: TabContext) {
|
|||||||
toast.showMessage(t("search_definition.actions_executed"), 3000);
|
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>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
@ -37,29 +37,12 @@ const TPL = /*html*/`
|
|||||||
</tr>
|
</tr>
|
||||||
<tbody class="search-options"></tbody>
|
<tbody class="search-options"></tbody>
|
||||||
<tbody class="action-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>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</div>`;
|
</div>`;
|
||||||
|
|
||||||
const OPTION_CLASSES = [SearchString, SearchScript, Ancestor, FastSearch, IncludeArchivedNotes, OrderBy, Limit, Debug];
|
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 {
|
export default class SearchDefinitionWidget extends NoteContextAwareWidget {
|
||||||
|
|
||||||
private $component!: JQuery<HTMLElement>;
|
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) => {
|
this.$widget.on("click", "[data-action-add]", async (event) => {
|
||||||
Dropdown.getOrCreateInstance(this.$widget.find(".action-add-toggle")[0]);
|
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.$searchOptions = this.$widget.find(".search-options");
|
||||||
this.$actionOptions = this.$widget.find(".action-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) {
|
async refreshWithNote(note: FNote) {
|
||||||
@ -134,12 +92,6 @@ export default class SearchDefinitionWidget extends NoteContextAwareWidget {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.$component.show();
|
|
||||||
|
|
||||||
this.$saveToNoteButton.toggle(note.isHiddenCompletely());
|
|
||||||
|
|
||||||
this.$searchOptions.empty();
|
|
||||||
|
|
||||||
const actions = bulkActionService.parseActions(this.note);
|
const actions = bulkActionService.parseActions(this.note);
|
||||||
const renderedEls = actions
|
const renderedEls = actions
|
||||||
.map((action) => renderReactWidget(this, action.doRender()))
|
.map((action) => renderReactWidget(this, action.doRender()))
|
||||||
|
@ -14,12 +14,12 @@ import TaskContext from "../../services/task_context.js";
|
|||||||
import dayjs from "dayjs";
|
import dayjs from "dayjs";
|
||||||
import utc from "dayjs/plugin/utc.js";
|
import utc from "dayjs/plugin/utc.js";
|
||||||
import eventService from "../../services/events.js";
|
import eventService from "../../services/events.js";
|
||||||
import type { AttachmentRow, AttributeType, NoteRow, NoteType, RevisionRow } from "@triliumnext/commons";
|
import type { AttachmentRow, AttributeType, CloneResponse, NoteRow, NoteType, RevisionRow } from "@triliumnext/commons";
|
||||||
import type BBranch from "./bbranch.js";
|
import type BBranch from "./bbranch.js";
|
||||||
import BAttribute from "./battribute.js";
|
import BAttribute from "./battribute.js";
|
||||||
import type { NotePojo } from "../becca-interface.js";
|
import type { NotePojo } from "../becca-interface.js";
|
||||||
import searchService from "../../services/search/services/search.js";
|
import searchService from "../../services/search/services/search.js";
|
||||||
import cloningService, { type CloneResponse } from "../../services/cloning.js";
|
import cloningService from "../../services/cloning.js";
|
||||||
import noteService from "../../services/notes.js";
|
import noteService from "../../services/notes.js";
|
||||||
import handlers from "../../services/handlers.js";
|
import handlers from "../../services/handlers.js";
|
||||||
dayjs.extend(utc);
|
dayjs.extend(utc);
|
||||||
|
@ -6,13 +6,7 @@ import treeService from "./tree.js";
|
|||||||
import BBranch from "../becca/entities/bbranch.js";
|
import BBranch from "../becca/entities/bbranch.js";
|
||||||
import becca from "../becca/becca.js";
|
import becca from "../becca/becca.js";
|
||||||
import log from "./log.js";
|
import log from "./log.js";
|
||||||
|
import { CloneResponse } from "@triliumnext/commons";
|
||||||
export interface CloneResponse {
|
|
||||||
success: boolean;
|
|
||||||
message?: string;
|
|
||||||
branchId?: string;
|
|
||||||
notePath?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
function cloneNoteToParentNote(noteId: string, parentNoteId: string, prefix: string | null = null): CloneResponse {
|
function cloneNoteToParentNote(noteId: string, parentNoteId: string, prefix: string | null = null): CloneResponse {
|
||||||
if (!(noteId in becca.notes) || !(parentNoteId in becca.notes)) {
|
if (!(noteId in becca.notes) || !(parentNoteId in becca.notes)) {
|
||||||
|
@ -10,6 +10,7 @@ import SearchContext from "./search/search_context.js";
|
|||||||
import { LBTPL_NOTE_LAUNCHER, LBTPL_CUSTOM_WIDGET, LBTPL_SPACER, LBTPL_SCRIPT } from "./hidden_subtree.js";
|
import { LBTPL_NOTE_LAUNCHER, LBTPL_CUSTOM_WIDGET, LBTPL_SPACER, LBTPL_SCRIPT } from "./hidden_subtree.js";
|
||||||
import { t } from "i18next";
|
import { t } from "i18next";
|
||||||
import { BNote } from "./backend_script_entrypoint.js";
|
import { BNote } from "./backend_script_entrypoint.js";
|
||||||
|
import { SaveSearchNoteResponse } from "@triliumnext/commons";
|
||||||
|
|
||||||
function getInboxNote(date: string) {
|
function getInboxNote(date: string) {
|
||||||
const workspaceNote = hoistedNoteService.getWorkspaceNote();
|
const workspaceNote = hoistedNoteService.getWorkspaceNote();
|
||||||
@ -119,7 +120,7 @@ function saveSearchNote(searchNoteId: string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result satisfies SaveSearchNoteResponse;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getMonthlyParentNoteId(rootNoteId: string, prefix: string) {
|
function getMonthlyParentNoteId(rootNoteId: string, prefix: string) {
|
||||||
|
@ -193,3 +193,12 @@ export interface SimilarNote {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export type SimilarNoteResponse = (SimilarNote[] | undefined);
|
export type SimilarNoteResponse = (SimilarNote[] | undefined);
|
||||||
|
|
||||||
|
export type SaveSearchNoteResponse = CloneResponse;
|
||||||
|
|
||||||
|
export interface CloneResponse {
|
||||||
|
success: boolean;
|
||||||
|
message?: string;
|
||||||
|
branchId?: string;
|
||||||
|
notePath?: string;
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user