From b6d5a6ec2ebf6c55d3909073428d40f597a9e8b3 Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Sun, 24 Aug 2025 15:59:22 +0300 Subject: [PATCH] chore(react/ribbon): dynamic rendering of search options --- .../widgets/ribbon/SearchDefinitionTab.tsx | 116 +++++++++++------- .../ribbon_widgets/search_definition.ts | 18 --- .../src/widgets/search_options/ancestor.ts | 7 -- .../src/widgets/search_options/debug.ts | 7 -- .../src/widgets/search_options/fast_search.ts | 6 - .../search_options/include_archived_notes.ts | 6 - .../src/widgets/search_options/limit.ts | 7 -- .../src/widgets/search_options/order_by.ts | 7 -- .../widgets/search_options/search_script.ts | 6 - .../widgets/search_options/search_string.ts | 7 -- 10 files changed, 72 insertions(+), 115 deletions(-) diff --git a/apps/client/src/widgets/ribbon/SearchDefinitionTab.tsx b/apps/client/src/widgets/ribbon/SearchDefinitionTab.tsx index 5ef43f6f0..9607f3784 100644 --- a/apps/client/src/widgets/ribbon/SearchDefinitionTab.tsx +++ b/apps/client/src/widgets/ribbon/SearchDefinitionTab.tsx @@ -1,4 +1,4 @@ -import { ComponentChildren } from "preact"; +import { ComponentChildren, VNode } from "preact"; import { t } from "../../services/i18n"; import Button from "../react/Button"; import { TabContext } from "./ribbon-interface"; @@ -18,53 +18,72 @@ import appContext from "../../components/app_context"; import server from "../../services/server"; interface SearchOption { - searchOption: string; + attributeName: string; + attributeType: "label" | "relation"; icon: string; label: string; tooltip?: string; + // TODO: Make mandatory once all components are ported. + component?: (props: SearchOptionProps) => VNode; +} + +interface SearchOptionProps { + note: FNote; + refreshResults: () => void; + attributeName: string; + attributeType: "label" | "relation"; } const SEARCH_OPTIONS: SearchOption[] = [ { - searchOption: "searchString", + attributeName: "searchString", + attributeType: "label", icon: "bx bx-text", - label: t("search_definition.search_string") + label: t("search_definition.search_string"), + component: SearchStringOption }, { - searchOption: "searchScript", + attributeName: "searchScript", + attributeType: "relation", icon: "bx bx-code", label: t("search_definition.search_script") }, { - searchOption: "ancestor", + attributeName: "ancestor", + attributeType: "relation", icon: "bx bx-filter-alt", label: t("search_definition.ancestor") }, { - searchOption: "fastSearch", + attributeName: "fastSearch", + attributeType: "label", icon: "bx bx-run", label: t("search_definition.fast_search"), tooltip: t("search_definition.fast_search_description") }, { - searchOption: "includeArchivedNotes", + attributeName: "includeArchivedNotes", + attributeType: "label", icon: "bx bx-archive", label: t("search_definition.include_archived"), tooltip: t("search_definition.include_archived_notes_description") }, { - searchOption: "orderBy", + attributeName: "orderBy", + attributeType: "label", icon: "bx bx-arrow-from-top", label: t("search_definition.order_by") }, { - searchOption: "limit", + attributeName: "limit", + attributeType: "label", icon: "bx bx-stop", label: t("search_definition.limit"), tooltip: t("search_definition.limit_description") }, { - searchOption: "debug", + attributeName: "debug", + attributeType: "label", icon: "bx bx-bug", label: t("search_definition.debug"), tooltip: t("search_definition.debug_description") @@ -97,43 +116,52 @@ export default function SearchDefinitionTab({ note, ntxId }: TabContext) { return (
- - - - - - - - - - - - + {note && +
{t("search_definition.add_search_option")} - {SEARCH_OPTIONS.map(({ icon, label, tooltip }) => ( -
- + - -
-
+
{t("search_definition.add_search_option")} + {SEARCH_OPTIONS.map(({ icon, label, tooltip }) => (
+ + {SEARCH_OPTIONS.map(({ attributeType, attributeName, component }) => { + const attr = note.getAttribute(attributeType, attributeName); + if (attr && component) { + return component({ + attributeName, + attributeType, + note, + refreshResults + }); + } + })} + + + + + + + +
+
+ + + + + }
) @@ -163,7 +191,7 @@ function SearchOption({ note, title, children, help, attributeName, attributeTyp ) } -function SearchStringOption({ note, refreshResults }: { note: FNote, refreshResults: () => void }) { +function SearchStringOption({ note, refreshResults }: SearchOptionProps) { const currentValue = useRef(""); const spacedUpdate = useSpacedUpdate(async () => { const searchString = currentValue.current; diff --git a/apps/client/src/widgets/ribbon_widgets/search_definition.ts b/apps/client/src/widgets/ribbon_widgets/search_definition.ts index ed3f3dde7..a77ebc743 100644 --- a/apps/client/src/widgets/ribbon_widgets/search_definition.ts +++ b/apps/client/src/widgets/ribbon_widgets/search_definition.ts @@ -153,24 +153,6 @@ export default class SearchDefinitionWidget extends NoteContextAwareWidget { this.$searchOptions.empty(); - for (const OptionClass of OPTION_CLASSES) { - const { attributeType, optionName } = OptionClass; - - const attr = this.note.getAttribute(attributeType as AttributeType, optionName); - - this.$widget.find(`[data-search-option-add='${optionName}'`).toggle(!attr); - - if (attr) { - const searchOption = new OptionClass(attr, this.note).setParent(this); - this.child(searchOption); - - const renderedEl = searchOption.render(); - if (renderedEl) { - this.$searchOptions.append(renderedEl); - } - } - } - const actions = bulkActionService.parseActions(this.note); const renderedEls = actions .map((action) => renderReactWidget(this, action.doRender())) diff --git a/apps/client/src/widgets/search_options/ancestor.ts b/apps/client/src/widgets/search_options/ancestor.ts index 8a29b675a..fa9fc672e 100644 --- a/apps/client/src/widgets/search_options/ancestor.ts +++ b/apps/client/src/widgets/search_options/ancestor.ts @@ -51,13 +51,6 @@ const TPL = /*html*/` `; export default class Ancestor extends AbstractSearchOption { - static get optionName() { - return "ancestor"; - } - static get attributeType() { - return "relation"; - } - static async create(noteId: string) { await AbstractSearchOption.setAttribute(noteId, "relation", "ancestor", "root"); } diff --git a/apps/client/src/widgets/search_options/debug.ts b/apps/client/src/widgets/search_options/debug.ts index fb19541b4..bdcf585e4 100644 --- a/apps/client/src/widgets/search_options/debug.ts +++ b/apps/client/src/widgets/search_options/debug.ts @@ -20,13 +20,6 @@ const TPL = /*html*/` `; export default class Debug extends AbstractSearchOption { - static get optionName() { - return "debug"; - } - static get attributeType() { - return "label"; - } - static async create(noteId: string) { await AbstractSearchOption.setAttribute(noteId, "label", "debug"); } diff --git a/apps/client/src/widgets/search_options/fast_search.ts b/apps/client/src/widgets/search_options/fast_search.ts index 52cc4acfc..7b77b1ca8 100644 --- a/apps/client/src/widgets/search_options/fast_search.ts +++ b/apps/client/src/widgets/search_options/fast_search.ts @@ -19,12 +19,6 @@ const TPL = /*html*/` `; export default class FastSearch extends AbstractSearchOption { - static get optionName() { - return "fastSearch"; - } - static get attributeType() { - return "label"; - } static async create(noteId: string) { await AbstractSearchOption.setAttribute(noteId, "label", "fastSearch"); diff --git a/apps/client/src/widgets/search_options/include_archived_notes.ts b/apps/client/src/widgets/search_options/include_archived_notes.ts index 7e8eea778..98f33f4d6 100644 --- a/apps/client/src/widgets/search_options/include_archived_notes.ts +++ b/apps/client/src/widgets/search_options/include_archived_notes.ts @@ -13,12 +13,6 @@ const TPL = /*html*/` `; export default class IncludeArchivedNotes extends AbstractSearchOption { - static get optionName() { - return "includeArchivedNotes"; - } - static get attributeType() { - return "label"; - } static async create(noteId: string) { await AbstractSearchOption.setAttribute(noteId, "label", "includeArchivedNotes"); diff --git a/apps/client/src/widgets/search_options/limit.ts b/apps/client/src/widgets/search_options/limit.ts index 20fe0ec0a..1925f29f1 100644 --- a/apps/client/src/widgets/search_options/limit.ts +++ b/apps/client/src/widgets/search_options/limit.ts @@ -26,13 +26,6 @@ export default class Limit extends AbstractSearchOption { private $limit!: JQuery; - static get optionName() { - return "limit"; - } - static get attributeType() { - return "label"; - } - static async create(noteId: string) { await AbstractSearchOption.setAttribute(noteId, "label", "limit", "10"); } diff --git a/apps/client/src/widgets/search_options/order_by.ts b/apps/client/src/widgets/search_options/order_by.ts index 491693c84..1c6ddd46d 100644 --- a/apps/client/src/widgets/search_options/order_by.ts +++ b/apps/client/src/widgets/search_options/order_by.ts @@ -37,13 +37,6 @@ const TPL = /*html*/` export default class OrderBy extends AbstractSearchOption { - static get optionName() { - return "orderBy"; - } - static get attributeType() { - return "label"; - } - static async create(noteId: string) { await AbstractSearchOption.setAttribute(noteId, "label", "orderBy", "relevancy"); await AbstractSearchOption.setAttribute(noteId, "label", "orderDirection", "asc"); diff --git a/apps/client/src/widgets/search_options/search_script.ts b/apps/client/src/widgets/search_options/search_script.ts index d93a64a83..931886424 100644 --- a/apps/client/src/widgets/search_options/search_script.ts +++ b/apps/client/src/widgets/search_options/search_script.ts @@ -33,12 +33,6 @@ const TPL = /*html*/` `; export default class SearchScript extends AbstractSearchOption { - static get optionName() { - return "searchScript"; - } - static get attributeType() { - return "relation"; - } static async create(noteId: string) { await AbstractSearchOption.setAttribute(noteId, "relation", "searchScript", "root"); diff --git a/apps/client/src/widgets/search_options/search_string.ts b/apps/client/src/widgets/search_options/search_string.ts index 913dcb249..fe5dcf57b 100644 --- a/apps/client/src/widgets/search_options/search_string.ts +++ b/apps/client/src/widgets/search_options/search_string.ts @@ -11,13 +11,6 @@ export default class SearchString extends AbstractSearchOption { private $searchString!: JQuery; private spacedUpdate!: SpacedUpdate; - static get optionName() { - return "searchString"; - } - static get attributeType() { - return "label"; - } - static async create(noteId: string) { await AbstractSearchOption.setAttribute(noteId, "label", "searchString"); }