import { t } from "../../services/i18n"; import Button from "../react/Button"; import { TabContext } from "./ribbon-interface"; import { SaveSearchNoteResponse } from "@triliumnext/commons"; import attributes from "../../services/attributes"; import FNote from "../../entities/fnote"; import toast from "../../services/toast"; import froca from "../../services/froca"; import { useContext, useEffect, useState } from "preact/hooks"; import { ParentComponent } from "../react/react_utils"; import { useTriliumEvent } from "../react/hooks"; import appContext from "../../components/app_context"; import server from "../../services/server"; import ws from "../../services/ws"; import tree from "../../services/tree"; import { SEARCH_OPTIONS, SearchOption } from "./SearchDefinitionOptions"; import Dropdown from "../react/Dropdown"; import Icon from "../react/Icon"; import bulk_action, { ACTION_GROUPS } from "../../services/bulk_action"; import { FormListHeader, FormListItem } from "../react/FormList"; import RenameNoteBulkAction from "../bulk_actions/note/rename_note"; import { getErrorMessage } from "../../services/utils"; export default function SearchDefinitionTab({ note, ntxId }: TabContext) { const parentComponent = useContext(ParentComponent); const [ searchOptions, setSearchOptions ] = useState<{ availableOptions: SearchOption[], activeOptions: SearchOption[] }>(); const [ error, setError ] = useState<{ message: string }>(); 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() { const noteId = note?.noteId; if (!noteId) { return; } try { const result = await froca.loadSearchNote(noteId); if (result?.error) { setError({ message: result?.error}) } else { setError(undefined); } } catch (e: unknown) { toast.showError(getErrorMessage(e)); } parentComponent?.triggerEvent("searchRefreshed", { ntxId }); } // Refresh the list of available and active options. useEffect(refreshOptions, [ note ]); useTriliumEvent("entitiesReloaded", ({ loadResults }) => { if (loadResults.getAttributeRows().find((attrRow) => attributes.isAffecting(attrRow, note))) { refreshOptions(); } }); return (
{note && {searchOptions?.activeOptions.map(({ attributeType, attributeName, component, additionalAttributesToDelete, defaultValue }) => { const Component = component; return ; })}
{t("search_definition.add_search_option")} {searchOptions?.availableOptions.map(({ icon, label, tooltip, attributeName, attributeType, defaultValue }) => (
}
) } function BulkActionsList({ note }: { note: FNote }) { const [ bulkActions, setBulkActions ] = useState(); function refreshBulkActions() { if (note) { setBulkActions(bulk_action.parseActions(note)); } } // React to changes. useEffect(refreshBulkActions, [ note ]); useTriliumEvent("entitiesReloaded", ({loadResults}) => { if (loadResults.getAttributeRows().find(attr => attr.type === "label" && attr.name === "action" && attributes.isAffecting(attr, note))) { refreshBulkActions(); } }); return ( {bulkActions?.map(bulkAction => ( bulkAction.doRender() ))} ) } function AddBulkActionButton({ note }: { note: FNote }) { return ( {" "}{t("search_definition.action")}} noSelectButtonStyle > {ACTION_GROUPS.map(({ actions, title }) => ( <> {actions.map(({ actionName, actionTitle }) => ( bulk_action.addAction(note.noteId, actionName)}>{actionTitle} ))} ))} ) }