diff --git a/apps/roam/src/components/DiscourseContext.tsx b/apps/roam/src/components/DiscourseContext.tsx index 151daabe5..c11f4b214 100644 --- a/apps/roam/src/components/DiscourseContext.tsx +++ b/apps/roam/src/components/DiscourseContext.tsx @@ -273,7 +273,7 @@ const ContextTab = ({ columns={columns} onRefresh={onRefresh} header={ - <> +

{r.label} - +

} /> ); @@ -324,32 +324,35 @@ export const ContextContent = ({ uid, results }: Props) => { const [loading, setLoading] = useState(true); const debouncedLoading = useDebounce(loading, 150); + const addLabels = useCallback((result: DiscourseContextResults[number]) => { + setRawQueryResults((prev) => ({ + ...prev, + [result.label]: { + label: result.label, + results: { + ...(prev[result.label]?.results || {}), + ...result.results, + }, + }, + })); + }, []); + const onRefresh = useCallback(() => { setRawQueryResults({}); getDiscourseContextResults({ uid, - onResult: (result) => { - setRawQueryResults((prev) => ({ - ...prev, - [result.label]: { - label: result.label, - results: { - ...(prev[result.label]?.results || {}), - ...result.results, - }, - }, - })); - }, + onResult: addLabels, }).finally(() => setLoading(false)); - }, [uid, setRawQueryResults, setLoading]); + }, [uid, setRawQueryResults, setLoading, addLabels]); useEffect(() => { if (!results) { onRefresh(); } else { + results.forEach(addLabels); setLoading(false); } - }, [onRefresh, results, setLoading]); + }, [onRefresh, results, setLoading, loading, addLabels]); const [tabId, setTabId] = useState(0); const [groupByTarget, setGroupByTarget] = useState(false); return queryResults.length ? ( @@ -406,7 +409,7 @@ export const ContextContent = ({ uid, results }: Props) => { /> ) : ( -
No discourse relations found.
+
No discourse relations found.
); }; diff --git a/apps/roam/src/components/DiscourseContextOverlay.tsx b/apps/roam/src/components/DiscourseContextOverlay.tsx index a458dfa84..fee01d104 100644 --- a/apps/roam/src/components/DiscourseContextOverlay.tsx +++ b/apps/roam/src/components/DiscourseContextOverlay.tsx @@ -1,4 +1,4 @@ -import { Button, Popover, Position, Tooltip } from "@blueprintjs/core"; +import { Button, Icon, Popover, Position, Tooltip } from "@blueprintjs/core"; import React, { useCallback, useEffect, useMemo, useState } from "react"; import ReactDOM from "react-dom"; import { ContextContent } from "./DiscourseContext"; @@ -38,6 +38,7 @@ const getOverlayInfo = (tag: string, id: string): Promise => { if (cache[tag]) return Promise.resolve(cache[tag]); const relations = getDiscourseRelations(); const nodes = getDiscourseNodes(relations); + return new Promise((resolve) => { const triggerNow = overlayQueue.length === 0; overlayQueue.push({ @@ -46,9 +47,16 @@ const getOverlayInfo = (tag: string, id: string): Promise => { end: 0, mid: 0, queued: new Date().valueOf(), - callback() { + async callback() { const self = this; const start = (self.start = new Date().valueOf()); + // @ts-ignore + const queryResult = await window.roamAlphaAPI.data.async.q( + `[:find ?a :where [?b :node/title "${normalizePageTitle( + tag, + )}"] [?a :block/refs ?b]]`, + ); + const refs = queryResult.length; return getDiscourseContextResults({ uid: getPageUidByPageTitle(tag), nodes, @@ -57,11 +65,8 @@ const getOverlayInfo = (tag: string, id: string): Promise => { self.mid = new Date().valueOf(); const output = (cache[tag] = { results, - refs: window.roamAlphaAPI.data.fast.q( - `[:find ?a :where [?b :node/title "${normalizePageTitle( - tag, - )}"] [?a :block/refs ?b]]`, - ).length, + + refs, }); const runTime = (self.end = new Date().valueOf() - start); setTimeout(() => { @@ -161,38 +166,33 @@ const DiscourseContextOverlay = ({ tag, id }: { tag: string; id: string }) => { autoFocus={false} content={
- - -
} target={ } position={Position.BOTTOM} /> @@ -211,14 +211,19 @@ const Wrapper = ({ parent, tag }: { parent: HTMLElement; tag: string }) => { ) : ( ); }; diff --git a/apps/roam/src/components/QueryDrawer.tsx b/apps/roam/src/components/QueryDrawer.tsx index 7ae5c2477..3f11740a5 100644 --- a/apps/roam/src/components/QueryDrawer.tsx +++ b/apps/roam/src/components/QueryDrawer.tsx @@ -87,15 +87,18 @@ const SavedQuery = ({ }} > {error} +

+
{error}
+

) : ( - <> +

{isEditingLabel ? ( )} -
+
{!isSavedToPage && ( <> @@ -185,7 +188,7 @@ const SavedQuery = ({ )}
- +

) } onDeleteQuery={onDelete} diff --git a/apps/roam/src/components/results-view/ResultsView.tsx b/apps/roam/src/components/results-view/ResultsView.tsx index f121f685a..5c6752fbd 100644 --- a/apps/roam/src/components/results-view/ResultsView.tsx +++ b/apps/roam/src/components/results-view/ResultsView.tsx @@ -226,6 +226,7 @@ type ResultsViewComponent = (props: { header?: React.ReactNode; results: Result[]; hideResults?: boolean; + hideMenu?: boolean; preventSavingSettings?: boolean; onEdit?: () => void; onDeleteQuery?: () => void; @@ -267,6 +268,7 @@ const ResultsView: ResultsViewComponent = ({ header, results, hideResults = false, + hideMenu = false, preventSavingSettings = false, onEdit, onDeleteQuery, @@ -315,7 +317,8 @@ const ResultsView: ResultsViewComponent = ({ const [columnFilters, setColumnFilters] = useState(settings.columnFilters); const [searchFilter, setSearchFilter] = useState(settings.searchFilter); const [showInterface, setShowInterface] = useState(settings.showInterface); - const [showMenuIcons, setShowMenuIcons] = useState(false); + const [revealMenuIcons, setRevealMenuIcons] = useState(false); + const hideMenuIcons = hideMenu || (!revealMenuIcons && !showInterface); const { allProcessedResults, paginatedResults } = useMemo(() => { return postProcessResults(results, { @@ -410,8 +413,8 @@ const ResultsView: ResultsViewComponent = ({
setShowMenuIcons(true)} - onMouseLeave={() => setShowMenuIcons(false)} + onMouseEnter={() => setRevealMenuIcons(true)} + onMouseLeave={() => setRevealMenuIcons(false)} > {isEditSearchFilter && (
+ {header}
{onRefresh && ( @@ -1134,18 +1138,7 @@ const ResultsView: ResultsViewComponent = ({ } />
- {header && ( -

- {header} -

- )} + {!hideResults && ( <> {results.length !== 0 ? ( diff --git a/apps/roam/src/components/settings/GeneralSettings.tsx b/apps/roam/src/components/settings/GeneralSettings.tsx index 32c970bdc..655353218 100644 --- a/apps/roam/src/components/settings/GeneralSettings.tsx +++ b/apps/roam/src/components/settings/GeneralSettings.tsx @@ -2,6 +2,8 @@ import React, { useMemo } from "react"; import FlagPanel from "roamjs-components/components/ConfigPanels/FlagPanel"; import TextPanel from "roamjs-components/components/ConfigPanels/TextPanel"; import { getFormattedConfigTree } from "~/utils/discourseConfigRef"; +import { onPageRefObserverChange } from "~/utils/pageRefObserverHandlers"; +import { previewPageRefHandler } from "~/utils/pageRefObserverHandlers"; import refreshConfigTree from "~/utils/refreshConfigTree"; const DiscourseGraphHome = () => { @@ -28,16 +30,9 @@ const DiscourseGraphHome = () => { uid={settings.preview.uid} parentUid={settings.settingsUid} value={settings.preview.value || false} - /> -
{ +const HomePersonalSettings = ({ onloadArgs }: { onloadArgs: OnloadArgs }) => { + const extensionAPI = onloadArgs.extensionAPI; const getInitCanvasPage = () => { const savedFormat = extensionAPI.settings.get( CANVAS_PAGE_FORMAT_KEY, @@ -22,6 +21,8 @@ const HomePersonalSettings = ({ extensionAPI.settings.set(CANVAS_PAGE_FORMAT_KEY, e); setCanvasPage(e); }; + const overlayHandler = getOverlayHandler(onloadArgs); + return (
+ { + const target = e.target as HTMLInputElement; + extensionAPI.settings.set( + "discourse-context-overlay", + target.checked, + ); + + onPageRefObserverChange(overlayHandler)(target.checked); + }} + labelElement={ + <> + Overlay + + + } + />
); }; diff --git a/apps/roam/src/components/settings/Settings.tsx b/apps/roam/src/components/settings/Settings.tsx index 511582ccf..ef63a2678 100644 --- a/apps/roam/src/components/settings/Settings.tsx +++ b/apps/roam/src/components/settings/Settings.tsx @@ -93,7 +93,7 @@ export const SettingsDialog = ({ id="discourse-graph-home-personal" title="Home" className="overflow-y-auto" - panel={} + panel={} /> { const isEncrypted = window.roamAlphaAPI.graph.isEncrypted; const isOffline = window.roamAlphaAPI.graph.type === "offline"; - console.log("isEncrypted", isEncrypted); - console.log("isOffline", isOffline); if (!isEncrypted && !isOffline) { initPostHog(); posthog.capture("Extension Loaded", { diff --git a/apps/roam/src/utils/configPageTabs.ts b/apps/roam/src/utils/configPageTabs.ts index e2b3239b1..c4095b7cc 100644 --- a/apps/roam/src/utils/configPageTabs.ts +++ b/apps/roam/src/utils/configPageTabs.ts @@ -11,7 +11,6 @@ import DEFAULT_RELATION_VALUES from "~/data/defaultDiscourseRelations"; import { onPageRefObserverChange, previewPageRefHandler, - overlayPageRefHandler, } from "~/utils/pageRefObserverHandlers"; import { ConfigTab } from "roamjs-components/components/ConfigPage"; import { @@ -73,20 +72,6 @@ export const configPageTabs = (args: OnloadArgs): ConfigTab[] => [ component: DiscourseRelationConfigPanel, }, } as Field, - // @ts-ignore - { - title: "overlay", - Panel: FlagPanel, - // description: - // "Whether to overlay discourse context information over node references", - description: "Currently disabled. Being reworked.", - disabled: true, - options: { - onChange: (val) => { - onPageRefObserverChange((s) => overlayPageRefHandler(s, args))(val); - }, - }, - } as Field, ], }, { diff --git a/apps/roam/src/utils/discourseConfigRef.ts b/apps/roam/src/utils/discourseConfigRef.ts index 8be543837..650d9b904 100644 --- a/apps/roam/src/utils/discourseConfigRef.ts +++ b/apps/roam/src/utils/discourseConfigRef.ts @@ -23,7 +23,6 @@ type FormattedConfigTree = { trigger: StringSetting; preview: BooleanSetting; disableSidebarOpen: BooleanSetting; - overlay: BooleanSetting; export: ExportConfigWithUids; }; @@ -54,10 +53,7 @@ export const getFormattedConfigTree = (): FormattedConfigTree => { tree: configTreeRef.tree, text: "preview", }), - overlay: getUidAndBooleanSetting({ - tree: grammarNode?.children || [], - text: "overlay", - }), + export: getExportSettingsAndUids(), }; }; diff --git a/apps/roam/src/utils/findDiscourseNode.ts b/apps/roam/src/utils/findDiscourseNode.ts index ec28d654d..aaaf73ef3 100644 --- a/apps/roam/src/utils/findDiscourseNode.ts +++ b/apps/roam/src/utils/findDiscourseNode.ts @@ -3,10 +3,16 @@ import matchDiscourseNode from "./matchDiscourseNode"; const discourseNodeTypeCache: Record = {}; -const findDiscourseNode = (uid = "", nodes = getDiscourseNodes()) => - typeof discourseNodeTypeCache[uid] !== "undefined" - ? discourseNodeTypeCache[uid] - : (discourseNodeTypeCache[uid] = - nodes.find((n) => matchDiscourseNode({ ...n, uid })) || false); +const findDiscourseNode = (uid = "", nodes = getDiscourseNodes()) => { + if (typeof discourseNodeTypeCache[uid] !== "undefined") { + return discourseNodeTypeCache[uid]; + } + const matchingNode = nodes.find((node) => + matchDiscourseNode({ ...node, uid }), + ); + + discourseNodeTypeCache[uid] = matchingNode || false; + return discourseNodeTypeCache[uid]; +}; export default findDiscourseNode; diff --git a/apps/roam/src/utils/getDiscourseNodes.ts b/apps/roam/src/utils/getDiscourseNodes.ts index 8751db5d7..2879ee76a 100644 --- a/apps/roam/src/utils/getDiscourseNodes.ts +++ b/apps/roam/src/utils/getDiscourseNodes.ts @@ -2,9 +2,9 @@ import getSettingValueFromTree from "roamjs-components/util/getSettingValueFromT import getSubTree from "roamjs-components/util/getSubTree"; import discourseConfigRef from "./discourseConfigRef"; import getDiscourseRelations from "./getDiscourseRelations"; -import parseQuery from "./parseQuery"; +import { roamNodeToCondition } from "./parseQuery"; import { Condition } from "./types"; -import { InputTextNode } from "roamjs-components/types"; +import { InputTextNode, RoamBasicNode } from "roamjs-components/types"; export const excludeDefaultNodes = (node: DiscourseNode) => { return node.backedBy !== "default"; @@ -64,22 +64,29 @@ const DEFAULT_NODES: DiscourseNode[] = [ }, ]; +const getSpecification = (children: RoamBasicNode[] | undefined) => { + const spec = getSubTree({ + tree: children, + key: "specification", + }); + const scratchNode = getSubTree({ tree: spec.children, key: "scratch" }); + const conditionsNode = getSubTree({ + tree: scratchNode.children, + key: "conditions", + }); + const specs = conditionsNode.children.map(roamNodeToCondition); + return specs; +}; + const getDiscourseNodes = (relations = getDiscourseRelations()) => { const configuredNodes = Object.entries(discourseConfigRef.nodes) .map(([type, { text, children }]): DiscourseNode => { - const spec = getSubTree({ - tree: children, - key: "specification", - }); - const specTree = spec.children; return { format: getSettingValueFromTree({ tree: children, key: "format" }), text, shortcut: getSettingValueFromTree({ tree: children, key: "shortcut" }), type, - specification: !!getSubTree({ tree: specTree, key: "enabled" }).uid - ? parseQuery(spec.uid).conditions - : [], + specification: getSpecification(children), backedBy: "user", canvasSettings: Object.fromEntries( getSubTree({ tree: children, key: "canvas" }).children.map( diff --git a/apps/roam/src/utils/initializeObserversAndListeners.ts b/apps/roam/src/utils/initializeObserversAndListeners.ts index 5d8f865a6..ae2303a8a 100644 --- a/apps/roam/src/utils/initializeObserversAndListeners.ts +++ b/apps/roam/src/utils/initializeObserversAndListeners.ts @@ -21,6 +21,7 @@ import { addPageRefObserver, getPageRefObserversSize, previewPageRefHandler, + overlayPageRefHandler, } from "~/utils/pageRefObserverHandlers"; import getDiscourseNodes from "~/utils/getDiscourseNodes"; import { OnloadArgs } from "roamjs-components/types"; @@ -104,10 +105,9 @@ export const initObservers = async ({ }); if (isFlagEnabled("preview")) addPageRefObserver(previewPageRefHandler); - // TODO: grammar overlay being refactored - // if (isFlagEnabled("grammar.overlay")) { - // addPageRefObserver((s) => overlayPageRefHandler(s, onloadArgs)); - // } + if (onloadArgs.extensionAPI.settings.get("discourse-context-overlay")) { + addPageRefObserver((s) => overlayPageRefHandler(s, onloadArgs)); + } if (!!getPageRefObserversSize()) enablePageRefObserver(); const { pageUid: configPageUid, observer: configPageObserver } = diff --git a/apps/roam/src/utils/pageRefObserverHandlers.ts b/apps/roam/src/utils/pageRefObserverHandlers.ts index be173ee58..f5438d33f 100644 --- a/apps/roam/src/utils/pageRefObserverHandlers.ts +++ b/apps/roam/src/utils/pageRefObserverHandlers.ts @@ -10,7 +10,17 @@ const pageRefObserverRef: { current?: MutationObserver } = { current: undefined, }; -export const overlayPageRefHandler = (s: HTMLSpanElement, args: OnloadArgs) => { +// Public handler (stable reference) +let cachedHandler: ((s: HTMLSpanElement) => void) | undefined; +export const getOverlayHandler = (onloadArgs: OnloadArgs) => + cachedHandler || + (cachedHandler = (s: HTMLSpanElement) => + overlayPageRefHandler(s, onloadArgs)); + +export const overlayPageRefHandler = ( + s: HTMLSpanElement, + onloadArgs: OnloadArgs, +) => { if (s.parentElement && !s.parentElement.closest(".rm-page-ref")) { const tag = s.getAttribute("data-tag") || @@ -25,7 +35,7 @@ export const overlayPageRefHandler = (s: HTMLSpanElement, args: OnloadArgs) => { discourseOverlayRender({ parent, tag: tag.replace(/\\"/g, '"'), - onloadArgs: args, + onloadArgs, }); if (s.hasAttribute("data-tag")) { s.appendChild(parent); @@ -83,19 +93,6 @@ export const onPageRefObserverChange = export const addPageRefObserver = (handler: (s: HTMLSpanElement) => void) => { pageRefObservers.add(handler); - if (pageRefObservers.size === 1) enablePageRefObserver(); -}; - -export const removePageRefObserver = ( - handler: (s: HTMLSpanElement) => void, -) => { - pageRefObservers.delete(handler); - if (pageRefObservers.size === 0) disablePageRefObserver(); -}; - -export const clearPageRefObservers = () => { - disablePageRefObserver(); - pageRefObservers.clear(); }; export const getPageRefObserversSize = () => pageRefObservers.size; diff --git a/apps/roam/src/utils/parseQuery.ts b/apps/roam/src/utils/parseQuery.ts index e7268ed15..4c16639d4 100644 --- a/apps/roam/src/utils/parseQuery.ts +++ b/apps/roam/src/utils/parseQuery.ts @@ -4,7 +4,7 @@ import getSubTree from "roamjs-components/util/getSubTree"; import createBlock from "roamjs-components/writes/createBlock"; import { Column, Condition, Selection } from "./types"; -const roamNodeToCondition = ({ +export const roamNodeToCondition = ({ uid, children, text,