mirror of
https://github.com/zadam/trilium.git
synced 2025-10-29 02:28:57 +01:00
chore(react/ribbon): dynamic rendering of search options
This commit is contained in:
parent
759398d804
commit
b6d5a6ec2e
@ -1,4 +1,4 @@
|
|||||||
import { ComponentChildren } from "preact";
|
import { ComponentChildren, VNode } from "preact";
|
||||||
import { t } from "../../services/i18n";
|
import { t } from "../../services/i18n";
|
||||||
import Button from "../react/Button";
|
import Button from "../react/Button";
|
||||||
import { TabContext } from "./ribbon-interface";
|
import { TabContext } from "./ribbon-interface";
|
||||||
@ -18,53 +18,72 @@ import appContext from "../../components/app_context";
|
|||||||
import server from "../../services/server";
|
import server from "../../services/server";
|
||||||
|
|
||||||
interface SearchOption {
|
interface SearchOption {
|
||||||
searchOption: string;
|
attributeName: string;
|
||||||
|
attributeType: "label" | "relation";
|
||||||
icon: string;
|
icon: string;
|
||||||
label: string;
|
label: string;
|
||||||
tooltip?: 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[] = [
|
const SEARCH_OPTIONS: SearchOption[] = [
|
||||||
{
|
{
|
||||||
searchOption: "searchString",
|
attributeName: "searchString",
|
||||||
|
attributeType: "label",
|
||||||
icon: "bx bx-text",
|
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",
|
icon: "bx bx-code",
|
||||||
label: t("search_definition.search_script")
|
label: t("search_definition.search_script")
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
searchOption: "ancestor",
|
attributeName: "ancestor",
|
||||||
|
attributeType: "relation",
|
||||||
icon: "bx bx-filter-alt",
|
icon: "bx bx-filter-alt",
|
||||||
label: t("search_definition.ancestor")
|
label: t("search_definition.ancestor")
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
searchOption: "fastSearch",
|
attributeName: "fastSearch",
|
||||||
|
attributeType: "label",
|
||||||
icon: "bx bx-run",
|
icon: "bx bx-run",
|
||||||
label: t("search_definition.fast_search"),
|
label: t("search_definition.fast_search"),
|
||||||
tooltip: t("search_definition.fast_search_description")
|
tooltip: t("search_definition.fast_search_description")
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
searchOption: "includeArchivedNotes",
|
attributeName: "includeArchivedNotes",
|
||||||
|
attributeType: "label",
|
||||||
icon: "bx bx-archive",
|
icon: "bx bx-archive",
|
||||||
label: t("search_definition.include_archived"),
|
label: t("search_definition.include_archived"),
|
||||||
tooltip: t("search_definition.include_archived_notes_description")
|
tooltip: t("search_definition.include_archived_notes_description")
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
searchOption: "orderBy",
|
attributeName: "orderBy",
|
||||||
|
attributeType: "label",
|
||||||
icon: "bx bx-arrow-from-top",
|
icon: "bx bx-arrow-from-top",
|
||||||
label: t("search_definition.order_by")
|
label: t("search_definition.order_by")
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
searchOption: "limit",
|
attributeName: "limit",
|
||||||
|
attributeType: "label",
|
||||||
icon: "bx bx-stop",
|
icon: "bx bx-stop",
|
||||||
label: t("search_definition.limit"),
|
label: t("search_definition.limit"),
|
||||||
tooltip: t("search_definition.limit_description")
|
tooltip: t("search_definition.limit_description")
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
searchOption: "debug",
|
attributeName: "debug",
|
||||||
|
attributeType: "label",
|
||||||
icon: "bx bx-bug",
|
icon: "bx bx-bug",
|
||||||
label: t("search_definition.debug"),
|
label: t("search_definition.debug"),
|
||||||
tooltip: t("search_definition.debug_description")
|
tooltip: t("search_definition.debug_description")
|
||||||
@ -97,43 +116,52 @@ export default function SearchDefinitionTab({ note, ntxId }: TabContext) {
|
|||||||
return (
|
return (
|
||||||
<div className="search-definition-widget">
|
<div className="search-definition-widget">
|
||||||
<div className="search-settings">
|
<div className="search-settings">
|
||||||
<table className="search-setting-table">
|
{note &&
|
||||||
<tr>
|
<table className="search-setting-table">
|
||||||
<td className="title-column">{t("search_definition.add_search_option")}</td>
|
|
||||||
<td colSpan={2} className="add-search-option">
|
|
||||||
{SEARCH_OPTIONS.map(({ icon, label, tooltip }) => (
|
|
||||||
<Button
|
|
||||||
icon={icon}
|
|
||||||
text={label}
|
|
||||||
title={tooltip}
|
|
||||||
/>
|
|
||||||
))}
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tbody className="search-options">
|
|
||||||
<SearchStringOption
|
|
||||||
refreshResults={refreshResults}
|
|
||||||
note={note}
|
|
||||||
/>
|
|
||||||
</tbody>
|
|
||||||
<tbody className="action-options">
|
|
||||||
|
|
||||||
</tbody>
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
<tr>
|
||||||
<td colSpan={3}>
|
<td className="title-column">{t("search_definition.add_search_option")}</td>
|
||||||
<div style={{ display: "flex", justifyContent: "space-evenly" }}>
|
<td colSpan={2} className="add-search-option">
|
||||||
|
{SEARCH_OPTIONS.map(({ icon, label, tooltip }) => (
|
||||||
<Button
|
<Button
|
||||||
icon="bx bx-search"
|
icon={icon}
|
||||||
text={t("search_definition.search_button")}
|
text={label}
|
||||||
keyboardShortcut="Enter"
|
title={tooltip}
|
||||||
onClick={refreshResults}
|
|
||||||
/>
|
/>
|
||||||
</div>
|
))}
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
<tbody className="search-options">
|
||||||
</table>
|
{SEARCH_OPTIONS.map(({ attributeType, attributeName, component }) => {
|
||||||
|
const attr = note.getAttribute(attributeType, attributeName);
|
||||||
|
if (attr && component) {
|
||||||
|
return component({
|
||||||
|
attributeName,
|
||||||
|
attributeType,
|
||||||
|
note,
|
||||||
|
refreshResults
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})}
|
||||||
|
</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>
|
||||||
|
</table>
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
@ -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 currentValue = useRef("");
|
||||||
const spacedUpdate = useSpacedUpdate(async () => {
|
const spacedUpdate = useSpacedUpdate(async () => {
|
||||||
const searchString = currentValue.current;
|
const searchString = currentValue.current;
|
||||||
|
|||||||
@ -153,24 +153,6 @@ export default class SearchDefinitionWidget extends NoteContextAwareWidget {
|
|||||||
|
|
||||||
this.$searchOptions.empty();
|
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 actions = bulkActionService.parseActions(this.note);
|
||||||
const renderedEls = actions
|
const renderedEls = actions
|
||||||
.map((action) => renderReactWidget(this, action.doRender()))
|
.map((action) => renderReactWidget(this, action.doRender()))
|
||||||
|
|||||||
@ -51,13 +51,6 @@ const TPL = /*html*/`
|
|||||||
</tr>`;
|
</tr>`;
|
||||||
|
|
||||||
export default class Ancestor extends AbstractSearchOption {
|
export default class Ancestor extends AbstractSearchOption {
|
||||||
static get optionName() {
|
|
||||||
return "ancestor";
|
|
||||||
}
|
|
||||||
static get attributeType() {
|
|
||||||
return "relation";
|
|
||||||
}
|
|
||||||
|
|
||||||
static async create(noteId: string) {
|
static async create(noteId: string) {
|
||||||
await AbstractSearchOption.setAttribute(noteId, "relation", "ancestor", "root");
|
await AbstractSearchOption.setAttribute(noteId, "relation", "ancestor", "root");
|
||||||
}
|
}
|
||||||
|
|||||||
@ -20,13 +20,6 @@ const TPL = /*html*/`
|
|||||||
</tr>`;
|
</tr>`;
|
||||||
|
|
||||||
export default class Debug extends AbstractSearchOption {
|
export default class Debug extends AbstractSearchOption {
|
||||||
static get optionName() {
|
|
||||||
return "debug";
|
|
||||||
}
|
|
||||||
static get attributeType() {
|
|
||||||
return "label";
|
|
||||||
}
|
|
||||||
|
|
||||||
static async create(noteId: string) {
|
static async create(noteId: string) {
|
||||||
await AbstractSearchOption.setAttribute(noteId, "label", "debug");
|
await AbstractSearchOption.setAttribute(noteId, "label", "debug");
|
||||||
}
|
}
|
||||||
|
|||||||
@ -19,12 +19,6 @@ const TPL = /*html*/`
|
|||||||
</tr>`;
|
</tr>`;
|
||||||
|
|
||||||
export default class FastSearch extends AbstractSearchOption {
|
export default class FastSearch extends AbstractSearchOption {
|
||||||
static get optionName() {
|
|
||||||
return "fastSearch";
|
|
||||||
}
|
|
||||||
static get attributeType() {
|
|
||||||
return "label";
|
|
||||||
}
|
|
||||||
|
|
||||||
static async create(noteId: string) {
|
static async create(noteId: string) {
|
||||||
await AbstractSearchOption.setAttribute(noteId, "label", "fastSearch");
|
await AbstractSearchOption.setAttribute(noteId, "label", "fastSearch");
|
||||||
|
|||||||
@ -13,12 +13,6 @@ const TPL = /*html*/`
|
|||||||
</tr>`;
|
</tr>`;
|
||||||
|
|
||||||
export default class IncludeArchivedNotes extends AbstractSearchOption {
|
export default class IncludeArchivedNotes extends AbstractSearchOption {
|
||||||
static get optionName() {
|
|
||||||
return "includeArchivedNotes";
|
|
||||||
}
|
|
||||||
static get attributeType() {
|
|
||||||
return "label";
|
|
||||||
}
|
|
||||||
|
|
||||||
static async create(noteId: string) {
|
static async create(noteId: string) {
|
||||||
await AbstractSearchOption.setAttribute(noteId, "label", "includeArchivedNotes");
|
await AbstractSearchOption.setAttribute(noteId, "label", "includeArchivedNotes");
|
||||||
|
|||||||
@ -26,13 +26,6 @@ export default class Limit extends AbstractSearchOption {
|
|||||||
|
|
||||||
private $limit!: JQuery<HTMLElement>;
|
private $limit!: JQuery<HTMLElement>;
|
||||||
|
|
||||||
static get optionName() {
|
|
||||||
return "limit";
|
|
||||||
}
|
|
||||||
static get attributeType() {
|
|
||||||
return "label";
|
|
||||||
}
|
|
||||||
|
|
||||||
static async create(noteId: string) {
|
static async create(noteId: string) {
|
||||||
await AbstractSearchOption.setAttribute(noteId, "label", "limit", "10");
|
await AbstractSearchOption.setAttribute(noteId, "label", "limit", "10");
|
||||||
}
|
}
|
||||||
|
|||||||
@ -37,13 +37,6 @@ const TPL = /*html*/`
|
|||||||
|
|
||||||
export default class OrderBy extends AbstractSearchOption {
|
export default class OrderBy extends AbstractSearchOption {
|
||||||
|
|
||||||
static get optionName() {
|
|
||||||
return "orderBy";
|
|
||||||
}
|
|
||||||
static get attributeType() {
|
|
||||||
return "label";
|
|
||||||
}
|
|
||||||
|
|
||||||
static async create(noteId: string) {
|
static async create(noteId: string) {
|
||||||
await AbstractSearchOption.setAttribute(noteId, "label", "orderBy", "relevancy");
|
await AbstractSearchOption.setAttribute(noteId, "label", "orderBy", "relevancy");
|
||||||
await AbstractSearchOption.setAttribute(noteId, "label", "orderDirection", "asc");
|
await AbstractSearchOption.setAttribute(noteId, "label", "orderDirection", "asc");
|
||||||
|
|||||||
@ -33,12 +33,6 @@ const TPL = /*html*/`
|
|||||||
</tr>`;
|
</tr>`;
|
||||||
|
|
||||||
export default class SearchScript extends AbstractSearchOption {
|
export default class SearchScript extends AbstractSearchOption {
|
||||||
static get optionName() {
|
|
||||||
return "searchScript";
|
|
||||||
}
|
|
||||||
static get attributeType() {
|
|
||||||
return "relation";
|
|
||||||
}
|
|
||||||
|
|
||||||
static async create(noteId: string) {
|
static async create(noteId: string) {
|
||||||
await AbstractSearchOption.setAttribute(noteId, "relation", "searchScript", "root");
|
await AbstractSearchOption.setAttribute(noteId, "relation", "searchScript", "root");
|
||||||
|
|||||||
@ -11,13 +11,6 @@ export default class SearchString extends AbstractSearchOption {
|
|||||||
private $searchString!: JQuery<HTMLElement>;
|
private $searchString!: JQuery<HTMLElement>;
|
||||||
private spacedUpdate!: SpacedUpdate;
|
private spacedUpdate!: SpacedUpdate;
|
||||||
|
|
||||||
static get optionName() {
|
|
||||||
return "searchString";
|
|
||||||
}
|
|
||||||
static get attributeType() {
|
|
||||||
return "label";
|
|
||||||
}
|
|
||||||
|
|
||||||
static async create(noteId: string) {
|
static async create(noteId: string) {
|
||||||
await AbstractSearchOption.setAttribute(noteId, "label", "searchString");
|
await AbstractSearchOption.setAttribute(noteId, "label", "searchString");
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user