chore(react/ribbon): refresh options

This commit is contained in:
Elian Doran 2025-08-24 16:17:10 +03:00
parent 80ad87671a
commit e1fa188244
No known key found for this signature in database
2 changed files with 40 additions and 22 deletions

View File

@ -11,9 +11,9 @@ import { note } from "mermaid/dist/rendering-util/rendering-elements/shapes/note
import FNote from "../../entities/fnote"; import FNote from "../../entities/fnote";
import toast from "../../services/toast"; import toast from "../../services/toast";
import froca from "../../services/froca"; import froca from "../../services/froca";
import { useContext, useRef } from "preact/hooks"; import { useContext, useEffect, useRef, useState } from "preact/hooks";
import { ParentComponent } from "../react/react_utils"; import { ParentComponent } from "../react/react_utils";
import { useSpacedUpdate } from "../react/hooks"; import { useSpacedUpdate, useTriliumEventBeta } from "../react/hooks";
import appContext from "../../components/app_context"; import appContext from "../../components/app_context";
import server from "../../services/server"; import server from "../../services/server";
@ -92,7 +92,25 @@ const SEARCH_OPTIONS: SearchOption[] = [
export default function SearchDefinitionTab({ note, ntxId }: TabContext) { export default function SearchDefinitionTab({ note, ntxId }: TabContext) {
const parentComponent = useContext(ParentComponent); const parentComponent = useContext(ParentComponent);
const [ searchOptions, setSearchOptions ] = useState<{ availableOptions: SearchOption[], activeOptions: SearchOption[] }>();
function refreshOptions() {
if (!note) return;
const availableOptions: SearchOption[] = [];
const activeOptions: SearchOption[] = [];
for (const searchOption of SEARCH_OPTIONS) {
const attr = note.getAttribute(searchOption.attributeType, searchOption.attributeName);
if (attr && searchOption.component) {
activeOptions.push(searchOption);
} else {
availableOptions.push(searchOption);
}
}
setSearchOptions({ availableOptions, activeOptions });
}
async function refreshResults() { async function refreshResults() {
const noteId = note?.noteId; const noteId = note?.noteId;
@ -113,6 +131,14 @@ export default function SearchDefinitionTab({ note, ntxId }: TabContext) {
parentComponent?.triggerEvent("searchRefreshed", { ntxId }); parentComponent?.triggerEvent("searchRefreshed", { ntxId });
} }
// Refresh the list of available and active options.
useEffect(refreshOptions, [ note ]);
useTriliumEventBeta("entitiesReloaded", ({ loadResults }) => {
if (loadResults.getAttributeRows().find((attrRow) => attributes.isAffecting(attrRow, note))) {
refreshOptions();
}
});
return ( return (
<div className="search-definition-widget"> <div className="search-definition-widget">
<div className="search-settings"> <div className="search-settings">
@ -121,7 +147,7 @@ export default function SearchDefinitionTab({ note, ntxId }: TabContext) {
<tr> <tr>
<td className="title-column">{t("search_definition.add_search_option")}</td> <td className="title-column">{t("search_definition.add_search_option")}</td>
<td colSpan={2} className="add-search-option"> <td colSpan={2} className="add-search-option">
{SEARCH_OPTIONS.map(({ icon, label, tooltip }) => ( {searchOptions?.availableOptions.map(({ icon, label, tooltip }) => (
<Button <Button
icon={icon} icon={icon}
text={label} text={label}
@ -131,16 +157,13 @@ export default function SearchDefinitionTab({ note, ntxId }: TabContext) {
</td> </td>
</tr> </tr>
<tbody className="search-options"> <tbody className="search-options">
{SEARCH_OPTIONS.map(({ attributeType, attributeName, component }) => { {searchOptions?.activeOptions.map(({ attributeType, attributeName, component }) => {
const attr = note.getAttribute(attributeType, attributeName); return component?.({
if (attr && component) { attributeName,
return component({ attributeType,
attributeName, note,
attributeType, refreshResults
note, });
refreshResults
});
}
})} })}
</tbody> </tbody>
<tbody className="action-options"> <tbody className="action-options">
@ -201,7 +224,7 @@ function SearchOption({ note, title, children, help, attributeName, attributeTyp
) )
} }
function SearchStringOption({ note, refreshResults }: SearchOptionProps) { function SearchStringOption({ note, refreshResults, ...restProps }: SearchOptionProps) {
const currentValue = useRef(""); const currentValue = useRef("");
const spacedUpdate = useSpacedUpdate(async () => { const spacedUpdate = useSpacedUpdate(async () => {
const searchString = currentValue.current; const searchString = currentValue.current;
@ -230,6 +253,7 @@ function SearchStringOption({ note, refreshResults }: SearchOptionProps) {
<li><code>note.dateCreated &gt;= MONTH-1</code> - {t("search_string.label_date_created")}</li> <li><code>note.dateCreated &gt;= MONTH-1</code> - {t("search_string.label_date_created")}</li>
</ul> </ul>
</>} </>}
note={note} {...restProps}
> >
<FormTextArea <FormTextArea
className="search-string" className="search-string"

View File

@ -149,10 +149,4 @@ export default class SearchDefinitionWidget extends NoteContextAwareWidget {
this.$searchAndExecuteButton.css("visibility", actions.length > 0 ? "visible" : "_hidden"); this.$searchAndExecuteButton.css("visibility", actions.length > 0 ? "visible" : "_hidden");
} }
entitiesReloadedEvent({ loadResults }: EventData<"entitiesReloaded">) {
// only refreshing deleted attrs, otherwise components update themselves
if (loadResults.getAttributeRows().find((attrRow) => attrRow.type === "label" && attrRow.name === "action" && attrRow.isDeleted)) {
this.refresh();
}
}
} }