Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
27 changes: 15 additions & 12 deletions apps/roam/src/components/DiscourseNodeMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import updateBlock from "roamjs-components/writes/updateBlock";
import { getCoordsFromTextarea } from "roamjs-components/components/CursorMenu";
import getDiscourseNodes from "~/utils/getDiscourseNodes";
import createDiscourseNode from "~/utils/createDiscourseNode";
import { getNewDiscourseNodeText } from "~/utils/formatUtils";
import { resolveNewDiscourseNodeText } from "~/utils/formatUtils";
import { OnloadArgs } from "roamjs-components/types";
import { formatHexColor } from "./settings/DiscourseNodeCanvasSettings";
import posthog from "posthog-js";
Expand Down Expand Up @@ -126,12 +126,13 @@ const NodeMenu = ({
if (document.activeElement === textarea) document.body.click();

const createNodeAndUpdateBlock = async () => {
const pageName = await getNewDiscourseNodeText({
text: highlighted,
nodeType: nodeUid,
blockUid: targetBlockUid,
skipBlockUpdate: true,
});
const { text: pageName, handledByDialog } =
await resolveNewDiscourseNodeText({
text: highlighted,
nodeType: nodeUid,
blockUid: targetBlockUid,
skipBlockUpdate: true,
});
if (!pageName) return;

const latestBlockText = getTextByBlockUid(targetBlockUid);
Expand All @@ -141,11 +142,13 @@ const NodeMenu = ({
selectionStart,
)}[[${pageName}]]${latestBlockText.substring(selectionEnd)}`;

await createDiscourseNode({
text: pageName,
configPageUid: nodeUid,
extensionAPI,
});
if (!handledByDialog) {
await createDiscourseNode({
text: pageName,
configPageUid: nodeUid,
extensionAPI,
});
}
void updateBlock({ text: newText, uid: targetBlockUid });
posthog.capture("Discourse Node: Created via Node Menu", {
nodeType: nodeUid,
Expand Down
48 changes: 48 additions & 0 deletions apps/roam/src/utils/__tests__/formatUtils.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { beforeEach, describe, expect, it, vi } from "vitest";
import { resolveNewDiscourseNodeText } from "~/utils/formatUtils";
import type { ModifyNodeDialogProps } from "~/components/ModifyNodeDialog";

const { renderFormDialog } = vi.hoisted(() => ({
renderFormDialog: vi.fn<(props: ModifyNodeDialogProps) => void>(),
}));

vi.mock("roamjs-components/util/createOverlayRender", () => ({
default: () => renderFormDialog,
}));
vi.mock("roamjs-components/util/extensionApiContext", () => ({
default: vi.fn(() => undefined),
}));
vi.mock("~/components/ModifyNodeDialog", () => ({
default: vi.fn(),
}));
vi.mock("~/utils/getDiscourseNodes", () => ({
default: vi.fn(() => []),
}));

describe("resolveNewDiscourseNodeText", () => {
beforeEach(() => {
renderFormDialog.mockReset();
});

it("reports when an empty selection is handled by the creation dialog", async () => {
const resultPromise = resolveNewDiscourseNodeText({
text: "",
nodeType: "issue",
blockUid: "source-block",
skipBlockUpdate: true,
});
const dialogProps = renderFormDialog.mock.calls[0][0];

await dialogProps.onSuccess({
text: "Test issue",
uid: "test-issue-uid",
action: "create",
});
dialogProps.onClose();

await expect(resultPromise).resolves.toEqual({
text: "Test issue",
handledByDialog: true,
});
});
});
41 changes: 27 additions & 14 deletions apps/roam/src/utils/formatUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,23 +20,29 @@ const renderFormDialog = createOverlayRender<ModifyNodeDialogProps>(
ModifyNodeDialog,
);

export const getNewDiscourseNodeText = async ({
text,
nodeType,
blockUid,
skipBlockUpdate = false,
}: {
export type ResolvedDiscourseNodeText = {
text: string;
handledByDialog: boolean;
};

type GetNewDiscourseNodeTextArgs = {
text: string;
nodeType: string;
blockUid?: string;
skipBlockUpdate?: boolean;
}) => {
};

export const resolveNewDiscourseNodeText = async ({
text,
nodeType,
blockUid,
skipBlockUpdate = false,
}: GetNewDiscourseNodeTextArgs): Promise<ResolvedDiscourseNodeText> => {
const discourseNodes = getDiscourseNodes();
let newText = text;
let textFromDialog = false;
const handledByDialog = !text;

if (!text) {
textFromDialog = true;
if (handledByDialog) {
newText = await new Promise<string>((resolve) => {
let resolvedText = "";
renderFormDialog({
Expand All @@ -57,10 +63,10 @@ export const getNewDiscourseNodeText = async ({
}

if (!newText || !newText.trim()) {
return "";
return { text: "", handledByDialog };
}
if (textFromDialog) {
return newText;
if (handledByDialog) {
return { text: newText, handledByDialog };
}

const indexedByType = Object.fromEntries(
Expand Down Expand Up @@ -90,7 +96,14 @@ export const getNewDiscourseNodeText = async ({
}
return "";
});
return formattedText;
return { text: formattedText, handledByDialog };
};

export const getNewDiscourseNodeText = async (
args: GetNewDiscourseNodeTextArgs,
): Promise<string> => {
const { text } = await resolveNewDiscourseNodeText(args);
return text;
};

export const getReferencedNodeInFormat = ({
Expand Down