Skip to content
Closed
Show file tree
Hide file tree
Changes from 4 commits
Commits
Show all changes
68 commits
Select commit Hold shift + click to select a range
e2b9b37
settings for context and page groups
sid597 Aug 8, 2025
da54c72
node settings
sid597 Aug 9, 2025
f83a007
address review
sid597 Aug 10, 2025
ee58296
fix node creation if it does not exist
sid597 Aug 10, 2025
87f38d3
remove unused, refactor
sid597 Aug 10, 2025
5a6bfdd
address coderabbit review
sid597 Aug 10, 2025
9815656
unify spelling, handle fallback
sid597 Aug 11, 2025
b50cd2e
first working but not good solution
sid597 Aug 14, 2025
b8fce33
working better code need to self review, use --full instead of --large
sid597 Aug 14, 2025
622de13
seems good, will find after review what i missed
sid597 Aug 16, 2025
f7143d1
fix highlighting, fix button highlight
sid597 Aug 16, 2025
37aa7e0
sync
sid597 Aug 17, 2025
4f2807b
address coderabbit code
sid597 Aug 17, 2025
3e430c9
address lint errors
sid597 Aug 19, 2025
0425eee
use async instead of backend
sid597 Aug 19, 2025
5622c64
address review
sid597 Aug 21, 2025
2a177c5
Merge branch 'main' into eng-733-glue-ui-components-to-data-extractio…
sid597 Aug 21, 2025
5ce74d5
Merge branch 'main' into eng-709-settings-panel-for-suggestive-mode
sid597 Aug 21, 2025
590848c
address review
sid597 Aug 21, 2025
e3f7352
bug fixes
sid597 Aug 22, 2025
0f2938f
bug fixes
sid597 Aug 22, 2025
36fc757
Merge branch 'eng-733-glue-ui-components-to-data-extraction-and-datab…
sid597 Aug 22, 2025
4422b0a
unused import
sid597 Aug 22, 2025
ec8109d
Add an input type for platform accounts
maparent Aug 23, 2025
bdb0180
Add an input type for platform accounts
maparent Aug 23, 2025
474dccc
Merge branch 'main' into eng-733-glue-ui-components-to-data-extractio…
sid597 Aug 23, 2025
aa573c8
Merge branch 'eng-764-bulk-account-uploading' of https://github.com/D…
sid597 Aug 23, 2025
c6a806d
Merge branch 'eng-764-bulk-account-uploading' into eng-733-glue-ui-co…
sid597 Aug 23, 2025
18a0d92
Add an input type for platform accounts
maparent Aug 23, 2025
cba3232
Merge branch 'eng-764-bulk-account-uploading' of https://github.com/D…
sid597 Aug 23, 2025
4b7cf9b
Merge branch 'eng-764-bulk-account-uploading' into eng-733-glue-ui-co…
sid597 Aug 23, 2025
a0ea409
bulk upsert accounts, use database function imports
sid597 Aug 24, 2025
6efd37c
Merge branch 'main' into eng-733-glue-ui-components-to-data-extractio…
sid597 Aug 24, 2025
29e8151
add comment for future
sid597 Aug 24, 2025
a11142a
use better import method
sid597 Aug 24, 2025
814149b
Merge branch 'eng-733-glue-ui-components-to-data-extraction-and-datab…
sid597 Aug 24, 2025
92f28d6
commonjs-to-esm
sid597 Aug 24, 2025
d8837f0
Merge branch 'main' into eng-709-settings-panel-for-suggestive-mode
sid597 Aug 24, 2025
3e0ae6f
fix merge errors, fix tree config setting extraction, test functional…
sid597 Aug 24, 2025
0f56967
add progress toaster, use space existence condition for on load sync
sid597 Aug 24, 2025
99c1ae5
defaultvalue
sid597 Aug 24, 2025
d045b21
address review, leaving out update embeddings from here
sid597 Aug 28, 2025
209da92
Merge branch 'main' into eng-709-settings-panel-for-suggestive-mode
sid597 Aug 28, 2025
89e4b3b
Merge branch 'main' into eng-732-left-side-panel-for-suggestive-mode
sid597 Aug 28, 2025
6406595
Merge branch 'main' into eng-709-settings-panel-for-suggestive-mode
sid597 Aug 29, 2025
3e142de
update embeddings
sid597 Aug 29, 2025
9c6dc0e
Merge branch 'eng-709-settings-panel-for-suggestive-mode' into eng-73…
sid597 Aug 29, 2025
3905290
Merge branch 'main' into eng-732-left-side-panel-for-suggestive-mode
sid597 Aug 29, 2025
ffa0122
seperate
sid597 Aug 30, 2025
a0e191a
Merge branch 'main' into eng-709-settings-panel-for-suggestive-mode
sid597 Aug 31, 2025
e1b6a58
Merge branch 'eng-709-settings-panel-for-suggestive-mode' into eng-73…
sid597 Aug 31, 2025
70de753
remove initialisation from wrong place
sid597 Aug 31, 2025
e9fc56a
panel manager
sid597 Aug 31, 2025
ac9636a
individual suggestive panel body
sid597 Aug 31, 2025
9a4294e
individual suggestive panel body
sid597 Aug 31, 2025
7947ae9
right data extraction
sid597 Aug 31, 2025
835a398
remove unused
sid597 Aug 31, 2025
824d117
observer to carry over different pages
sid597 Aug 31, 2025
48d9a86
set all pages
sid597 Aug 31, 2025
569df7a
ENG-818: Declare dbDotEnv as mjs explicitly
maparent Sep 1, 2025
d6ff391
Merge branch 'main' into eng-709-settings-panel-for-suggestive-mode
sid597 Sep 1, 2025
f65a5c1
Merge branch 'eng-818-make-dbdotenv-explicitly-a-module' into eng-709…
sid597 Sep 1, 2025
b130596
Merge branch 'main' into eng-732-left-side-panel-for-suggestive-mode
sid597 Sep 7, 2025
37cb5a2
address review partially
sid597 Sep 8, 2025
58d119b
Merge branch 'main' into eng-709-settings-panel-for-suggestive-mode
sid597 Sep 8, 2025
319ea90
Merge branch 'eng-709-settings-panel-for-suggestive-mode' into eng-73…
sid597 Sep 8, 2025
246226c
address reviews
sid597 Sep 8, 2025
9c955c5
Merge branch 'main' into eng-732-left-side-panel-for-suggestive-mode
sid597 Sep 28, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
175 changes: 87 additions & 88 deletions apps/roam/src/components/DiscourseContextOverlay.tsx
Original file line number Diff line number Diff line change
@@ -1,99 +1,61 @@
import { Button, Icon, Popover, Position, Tooltip } from "@blueprintjs/core";
import React, { useCallback, useEffect, useMemo, useState } from "react";
import React, { useCallback, useMemo, useState } from "react";
import ReactDOM from "react-dom";
import { ContextContent } from "./DiscourseContext";
import useInViewport from "react-in-viewport/dist/es/lib/useInViewport";
import normalizePageTitle from "roamjs-components/queries/normalizePageTitle";
import deriveDiscourseNodeAttribute from "~/utils/deriveDiscourseNodeAttribute";
import getSettingValueFromTree from "roamjs-components/util/getSettingValueFromTree";
import getBasicTreeByParentUid from "roamjs-components/queries/getBasicTreeByParentUid";
import nanoid from "nanoid";
import getPageUidByPageTitle from "roamjs-components/queries/getPageUidByPageTitle";
import getDiscourseContextResults from "~/utils/getDiscourseContextResults";
import findDiscourseNode from "~/utils/findDiscourseNode";
import getDiscourseNodes from "~/utils/getDiscourseNodes";
import getDiscourseRelations from "~/utils/getDiscourseRelations";
import ExtensionApiContextProvider from "roamjs-components/components/ExtensionApiContext";
import { OnloadArgs } from "roamjs-components/types/native";
import { getBlockUidFromTarget } from "roamjs-components/dom";
import { useDiscourseData } from "~/utils/useDiscourseData";
import { panelManager } from "./PanelManager";

type DiscourseData = {
results: Awaited<ReturnType<typeof getDiscourseContextResults>>;
refs: number;
};

const cache: {
[tag: string]: DiscourseData;
} = {};

const getOverlayInfo = async (tag: string): Promise<DiscourseData> => {
try {
if (cache[tag]) return cache[tag];

const relations = getDiscourseRelations();
const nodes = getDiscourseNodes(relations);

const [results, refs] = await Promise.all([
getDiscourseContextResults({
uid: getPageUidByPageTitle(tag),
nodes,
relations,
}),
// @ts-ignore - backend to be added to roamjs-components
window.roamAlphaAPI.data.backend.q(
`[:find ?a :where [?b :node/title "${normalizePageTitle(tag)}"] [?a :block/refs ?b]]`,
),
]);
const DiscourseContextOverlay = ({
tag,
id,
parentEl,
onloadArgs,
}: {
tag: string;
id: string;
parentEl: HTMLElement;
onloadArgs: OnloadArgs;
}) => {
const blockUid = useMemo(() => getBlockUidFromTarget(parentEl), [parentEl]);
const { loading, score, refs, results, tagUid } = useDiscourseData(tag);
const [isPanelOpen, setIsPanelOpen] = useState(() =>
panelManager.isOpen(tag),
);

return (cache[tag] = {
results,
refs: refs.length,
});
} catch (error) {
console.error(`Error getting overlay info for ${tag}:`, error);
return {
results: [],
refs: 0,
};
}
};
const toggleHighlight = useCallback(
(on: boolean) => {
const nodes = document.querySelectorAll(
`[data-dg-block-uid="${blockUid}"]`,
);
nodes.forEach((el) => {
const elem = el as HTMLElement;
if (
elem.classList.contains("roamjs-discourse-context-overlay") ||
elem.closest(".roamjs-discourse-context-overlay")
)
return;
elem.classList.toggle("dg-highlight", on);
});
},
[blockUid],
);

const DiscourseContextOverlay = ({ tag, id }: { tag: string; id: string }) => {
const tagUid = useMemo(() => getPageUidByPageTitle(tag), [tag]);
const [loading, setLoading] = useState(true);
const [results, setResults] = useState<DiscourseData["results"]>([]);
const [refs, setRefs] = useState(0);
const [score, setScore] = useState<number | string>(0);
const getInfo = useCallback(
() =>
getOverlayInfo(tag)
.then(({ refs, results }) => {
const discourseNode = findDiscourseNode(tagUid);
if (discourseNode) {
const attribute = getSettingValueFromTree({
tree: getBasicTreeByParentUid(discourseNode.type),
key: "Overlay",
defaultValue: "Overlay",
});
return deriveDiscourseNodeAttribute({
uid: tagUid,
attribute,
}).then((score) => {
setResults(results);
setRefs(refs);
setScore(score);
});
}
})
.finally(() => setLoading(false)),
[tag, setResults, setLoading, setRefs, setScore],
const handleTogglePanel = useCallback(
(e: React.MouseEvent) => {
e.stopPropagation();
e.preventDefault();
toggleHighlight(false);
panelManager.toggle({ tag, blockUid, onloadArgs });
setIsPanelOpen(panelManager.isOpen(tag));
},
[tag, blockUid, onloadArgs, toggleHighlight],
);
const refresh = useCallback(() => {
setLoading(true);
getInfo();
}, [getInfo, setLoading]);
useEffect(() => {
getInfo();
}, [refresh, getInfo]);

return (
<Popover
autoFocus={false}
Expand All @@ -113,19 +75,43 @@ const DiscourseContextOverlay = ({ tag, id }: { tag: string; id: string }) => {
className={`roamjs-discourse-context-overlay ${
loading ? "animate-pulse" : ""
}`}
{...{ "data-dg-block-uid": blockUid }}
style={{
minHeight: "initial",
paddingTop: ".25rem",
paddingBottom: ".25rem",
}}
minimal
disabled={loading}
onMouseEnter={() => toggleHighlight(true)}
onMouseLeave={() => toggleHighlight(false)}
>
<div className="flex items-center gap-1.5">
<Icon icon={"diagram-tree"} />
<span className="mr-1 leading-none">{loading ? "-" : score}</span>
<Icon icon={"link"} />
<span className="leading-none">{loading ? "-" : refs}</span>
<Tooltip
content={
isPanelOpen
? "Close suggestions panel"
: "Open suggestions panel"
}
hoverOpenDelay={200}
hoverCloseDelay={0}
position={Position.RIGHT}
>
<Button
data-dg-role="panel-toggle"
data-dg-tag={tag}
data-dg-panel-open={isPanelOpen ? "true" : "false"}
icon={isPanelOpen ? "panel-table" : "panel-stats"}
minimal
small
intent={isPanelOpen ? "primary" : "none"}
onClick={handleTogglePanel}
/>
</Tooltip>
</div>
</Button>
}
Expand All @@ -134,7 +120,15 @@ const DiscourseContextOverlay = ({ tag, id }: { tag: string; id: string }) => {
);
};

const Wrapper = ({ parent, tag }: { parent: HTMLElement; tag: string }) => {
const Wrapper = ({
parent,
tag,
onloadArgs,
}: {
parent: HTMLElement;
tag: string;
onloadArgs: OnloadArgs;
}) => {
const id = useMemo(() => nanoid(), []);
const { inViewport } = useInViewport(
{ current: parent },
Expand All @@ -143,7 +137,12 @@ const Wrapper = ({ parent, tag }: { parent: HTMLElement; tag: string }) => {
{},
);
return inViewport ? (
<DiscourseContextOverlay tag={tag} id={id} />
<DiscourseContextOverlay
tag={tag}
id={id}
parentEl={parent}
onloadArgs={onloadArgs}
/>
) : (
<Button
small
Expand Down Expand Up @@ -175,7 +174,7 @@ export const render = ({
parent.onmousedown = (e) => e.stopPropagation();
ReactDOM.render(
<ExtensionApiContextProvider {...onloadArgs}>
<Wrapper tag={tag} parent={parent} />
<Wrapper tag={tag} parent={parent} onloadArgs={onloadArgs} />
</ExtensionApiContextProvider>,
parent,
);
Expand Down
115 changes: 115 additions & 0 deletions apps/roam/src/components/DiscourseSuggestionsPanel.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
import {
Alignment,
Card,
Classes,
Button,
Navbar,
Collapse,
} from "@blueprintjs/core";
import React, { useState, useCallback } from "react";
import SuggestionsBody from "./SuggestionsBody";
import { useDiscourseData } from "~/utils/useDiscourseData";

export const DiscourseSuggestionsPanel = ({
tag,
blockUid,
onClose,
}: {
tag: string;
blockUid: string;
onClose: () => void;
}) => {
const [isOpen, setIsOpen] = useState(true);
const { results, loading } = useDiscourseData(tag);

const toggleHighlight = useCallback(
(on: boolean) => {
document
.querySelectorAll(`[data-dg-block-uid="${blockUid}"]`)
.forEach((el) => el.classList.toggle("dg-highlight", on));
},
[blockUid],
);

return (
<Card
{...{ "data-dg-block-uid": blockUid }}
style={{
backgroundColor: "#fff",
display: "flex",
flexDirection: "column",
padding: "8px",
}}
onMouseEnter={() => toggleHighlight(true)}
onMouseLeave={() => toggleHighlight(false)}
className="roamjs-discourse-suggestions-panel"
>
<Navbar
style={{
borderBottom: "1px solid #d8e1e8",
boxShadow: "none",
paddingRight: 0,
display: "flex",
flexWrap: "nowrap",
alignItems: "center",
}}
>
<Navbar.Group align={Alignment.LEFT} style={{ flex: 1, minWidth: 0 }}>
<Navbar.Heading
className="truncate"
style={{
fontSize: "13px",
margin: 0,
fontWeight: 600,
cursor: "pointer",
}}
onClick={() => setIsOpen((prev) => !prev)}
>
{tag}
</Navbar.Heading>
</Navbar.Group>
<Navbar.Group
align={Alignment.RIGHT}
style={{
marginRight: "5px",
flexShrink: 0,
display: "flex",
gap: "4px",
}}
>
<Button
icon={isOpen ? "chevron-up" : "chevron-down"}
minimal
small
onClick={() => setIsOpen((prev) => !prev)}
title={isOpen ? "Collapse" : "Expand"}
/>
<Button
icon="cross"
minimal={true}
title="Close Panel"
onClick={onClose}
small={true}
/>
</Navbar.Group>
</Navbar>
<Collapse
isOpen={isOpen}
keepChildrenMounted={true}
transitionDuration={150}
>
<div
className={Classes.CARD}
style={{ flexGrow: 1, overflowY: "auto", padding: "6px" }}
>
<SuggestionsBody
tag={tag}
blockUid={blockUid}
existingResults={results}
loading={loading}
/>
</div>
</Collapse>
</Card>
);
};
Loading