diff --git a/apps/obsidian/src/components/DiscourseContextView.tsx b/apps/obsidian/src/components/DiscourseContextView.tsx
index 26a32d88a..c9e7c715b 100644
--- a/apps/obsidian/src/components/DiscourseContextView.tsx
+++ b/apps/obsidian/src/components/DiscourseContextView.tsx
@@ -3,7 +3,6 @@ import {
TFile,
WorkspaceLeaf,
Notice,
- FrontMatterCache,
setIcon,
setTooltip,
} from "obsidian";
@@ -19,9 +18,9 @@ import {
getUserNameById,
} from "~/utils/typeUtils";
import { refreshImportedFile } from "~/utils/importNodes";
-import { publishNode } from "~/utils/publishNode";
+import { PublishGroupDropdown } from "~/components/PublishGroupDropdown";
import { createBaseForNodeType } from "~/utils/baseForNodeType";
-import { useState, useEffect } from "react";
+import { useState } from "react";
type DiscourseContextProps = {
activeFile: TFile | null;
@@ -45,28 +44,6 @@ export const InfoTooltip = ({ content }: InfoTooltipProps) => (
const DiscourseContext = ({ activeFile }: DiscourseContextProps) => {
const plugin = usePlugin();
const [isRefreshing, setIsRefreshing] = useState(false);
- const [isPublishing, setIsPublishing] = useState(false);
- const [isPublished, setIsPublished] = useState(false);
-
- useEffect(() => {
- if (!activeFile || !plugin) {
- setIsPublished(false);
- return;
- }
- const fileMetadata = plugin.app.metadataCache.getFileCache(activeFile);
- const frontmatter = fileMetadata?.frontmatter;
- if (!frontmatter) {
- setIsPublished(false);
- return;
- }
- const isImported = !!frontmatter.importedFromRid;
- const publishedToGroups = frontmatter.publishedToGroups as unknown;
- const published =
- !isImported &&
- Array.isArray(publishedToGroups) &&
- publishedToGroups.length > 0;
- setIsPublished(published);
- }, [activeFile, plugin]);
const extractContentFromTitle = (format: string, title: string): string => {
if (!format) return "";
@@ -99,29 +76,6 @@ const DiscourseContext = ({ activeFile }: DiscourseContextProps) => {
}
};
- const handlePublish = async (frontmatter: FrontMatterCache) => {
- if (!activeFile || isPublishing) return;
-
- if (!frontmatter.nodeInstanceId) {
- new Notice("Please sync the node first", 5000);
- return;
- }
-
- setIsPublishing(true);
- try {
- await publishNode({ plugin, file: activeFile, frontmatter });
- new Notice("Published successfully", 3000);
- setIsPublished(true);
- } catch (error) {
- const errorMessage =
- error instanceof Error ? error.message : String(error);
- new Notice(`Publish failed: ${errorMessage}`, 5000);
- console.error("Publish failed:", error);
- } finally {
- setIsPublishing(false);
- }
- };
-
const renderContent = () => {
if (!activeFile) {
return
No file is open
;
@@ -212,28 +166,7 @@ const DiscourseContext = ({ activeFile }: DiscourseContextProps) => {
)}
{canPublish && (
-
+
)}
diff --git a/apps/obsidian/src/components/PublishGroupDropdown.tsx b/apps/obsidian/src/components/PublishGroupDropdown.tsx
new file mode 100644
index 000000000..fe7655908
--- /dev/null
+++ b/apps/obsidian/src/components/PublishGroupDropdown.tsx
@@ -0,0 +1,237 @@
+import { useCallback, useEffect, useMemo, useRef, useState } from "react";
+import { type TFile } from "obsidian";
+import type DiscourseGraphPlugin from "~/index";
+import {
+ getPublishedToGroups,
+ getPublishToAllTitle,
+ getUnpublishedGroups,
+ loadMyGroups,
+ notifyPublishError,
+ publishToAllGroupsWithNotice,
+ publishToSelectedGroupWithNotice,
+ withPublishedState,
+} from "~/utils/publishGroupSelection";
+import type { MyGroup } from "~/utils/importNodes";
+
+type PublishGroupDropdownProps = {
+ plugin: DiscourseGraphPlugin;
+ file: TFile;
+};
+
+export const PublishGroupDropdown = ({
+ plugin,
+ file,
+}: PublishGroupDropdownProps) => {
+ const containerRef = useRef(null);
+ const [groups, setGroups] = useState([]);
+ const [isOpen, setIsOpen] = useState(false);
+ const [isLoading, setIsLoading] = useState(false);
+ const [isPublishing, setIsPublishing] = useState(false);
+ const [loadError, setLoadError] = useState(null);
+ const [, setMetadataVersion] = useState(0);
+
+ const frontmatter = plugin.app.metadataCache.getFileCache(file)?.frontmatter;
+ const publishedToGroups = useMemo(
+ () => (frontmatter ? getPublishedToGroups(frontmatter) : []),
+ [frontmatter],
+ );
+ const groupsWithPublishedState = withPublishedState(
+ groups,
+ publishedToGroups,
+ );
+ const unpublishedGroups = getUnpublishedGroups(groupsWithPublishedState);
+
+ useEffect(() => {
+ const ref = plugin.app.metadataCache.on("changed", (changedFile) => {
+ if (changedFile.path === file.path) {
+ setMetadataVersion((version) => version + 1);
+ }
+ });
+
+ return () => {
+ plugin.app.metadataCache.offref(ref);
+ };
+ }, [plugin.app.metadataCache, file.path]);
+
+ useEffect(() => {
+ if (!isOpen) return;
+
+ let cancelled = false;
+
+ const loadGroups = async () => {
+ setIsLoading(true);
+ setLoadError(null);
+ try {
+ const myGroups = await loadMyGroups(plugin);
+ if (!cancelled) {
+ setGroups(myGroups);
+ }
+ } catch (error) {
+ if (!cancelled) {
+ setLoadError(error instanceof Error ? error.message : String(error));
+ setGroups([]);
+ }
+ } finally {
+ if (!cancelled) {
+ setIsLoading(false);
+ }
+ }
+ };
+
+ void loadGroups();
+
+ return () => {
+ cancelled = true;
+ };
+ }, [plugin, isOpen]);
+
+ useEffect(() => {
+ if (!isOpen) return;
+
+ const handlePointerDown = (event: PointerEvent) => {
+ if (
+ containerRef.current &&
+ !containerRef.current.contains(event.target as Node)
+ ) {
+ setIsOpen(false);
+ }
+ };
+
+ document.addEventListener("pointerdown", handlePointerDown);
+ return () => document.removeEventListener("pointerdown", handlePointerDown);
+ }, [isOpen]);
+
+ const runPublishAction = useCallback(
+ async (action: () => Promise, onSuccess?: () => void) => {
+ if (isPublishing) return;
+
+ setIsPublishing(true);
+ try {
+ await action();
+ onSuccess?.();
+ } catch (error) {
+ notifyPublishError(error);
+ } finally {
+ setIsPublishing(false);
+ }
+ },
+ [isPublishing],
+ );
+
+ const handlePublishToGroup = useCallback(
+ (groupId: string) => {
+ if (publishedToGroups.includes(groupId)) return;
+
+ void runPublishAction(async () => {
+ await publishToSelectedGroupWithNotice({ plugin, file, groupId });
+ setIsOpen(false);
+ });
+ },
+ [plugin, file, publishedToGroups, runPublishAction],
+ );
+
+ const handlePublishToAllGroups = useCallback(() => {
+ if (isLoading || unpublishedGroups.length === 0) return;
+
+ void runPublishAction(async () => {
+ await publishToAllGroupsWithNotice({ plugin, file });
+ setIsOpen(false);
+ });
+ }, [plugin, file, isLoading, unpublishedGroups.length, runPublishAction]);
+
+ if (!frontmatter) {
+ return null;
+ }
+
+ const publishedCount = publishedToGroups.length;
+ const triggerLabel =
+ publishedCount > 0 ? `Published (${publishedCount})` : "Publish";
+
+ return (
+
+
+
+ {isOpen && (
+
+
handlePublishToAllGroups()}
+ onKeyDown={(event) => {
+ if (event.key === "Enter" || event.key === " ") {
+ event.preventDefault();
+ handlePublishToAllGroups();
+ }
+ }}
+ className={`border-b border-gray-200 px-3 py-1.5 text-xs font-medium dark:border-gray-600 ${
+ isLoading || isPublishing || unpublishedGroups.length === 0
+ ? "cursor-default text-gray-400 dark:text-gray-500"
+ : "cursor-pointer text-gray-900 hover:bg-gray-100 dark:text-gray-100 dark:hover:bg-gray-800"
+ }`}
+ title={getPublishToAllTitle(unpublishedGroups.length)}
+ >
+ Publish to all groups
+
+
+ {isLoading && (
+
+ Loading groups...
+
+ )}
+
+ {loadError && (
+
+ {loadError}
+
+ )}
+
+ {!isLoading &&
+ !loadError &&
+ groupsWithPublishedState.length === 0 && (
+
+ You are not a member of any groups.
+
+ )}
+
+ {!isLoading &&
+ !loadError &&
+ groupsWithPublishedState.map((group) => (
+
+ ))}
+
+ )}
+
+ );
+};
diff --git a/apps/obsidian/src/components/PublishGroupSuggestModal.tsx b/apps/obsidian/src/components/PublishGroupSuggestModal.tsx
new file mode 100644
index 000000000..0f1f3a7c9
--- /dev/null
+++ b/apps/obsidian/src/components/PublishGroupSuggestModal.tsx
@@ -0,0 +1,60 @@
+import { App, SuggestModal } from "obsidian";
+import type { PublishGroupSuggestItem } from "~/utils/publishGroupSelection";
+
+type PublishGroupSuggestModalParams = {
+ app: App;
+ items: PublishGroupSuggestItem[];
+ onChoose: (item: PublishGroupSuggestItem) => void | Promise;
+};
+
+export class PublishGroupSuggestModal extends SuggestModal {
+ private items: PublishGroupSuggestItem[];
+ private onChoose: (item: PublishGroupSuggestItem) => void | Promise;
+
+ constructor({ app, items, onChoose }: PublishGroupSuggestModalParams) {
+ super(app);
+ this.items = items;
+ this.onChoose = onChoose;
+ this.setPlaceholder("Choose a group to share with");
+ }
+
+ getItemText(item: PublishGroupSuggestItem): string {
+ if (item.isPublishToAll) {
+ return item.name;
+ }
+ return item.isPublished ? `${item.name} (shared)` : item.name;
+ }
+
+ getSuggestions(query: string): PublishGroupSuggestItem[] {
+ const normalizedQuery = query.toLowerCase();
+ return this.items.filter((item) =>
+ item.name.toLowerCase().includes(normalizedQuery),
+ );
+ }
+
+ renderSuggestion(item: PublishGroupSuggestItem, el: HTMLElement): void {
+ const row = el.createDiv({
+ cls: item.isPublishToAll
+ ? "border-b border-border pb-1 font-medium"
+ : "flex items-center gap-2",
+ });
+
+ if (item.isPublishToAll) {
+ row.createSpan({ text: item.name });
+ return;
+ }
+
+ row.createSpan({
+ cls: "inline-flex w-4 shrink-0 justify-center",
+ text: item.isPublished ? "✓" : "",
+ });
+ row.createSpan({ text: item.name });
+ }
+
+ onChooseSuggestion(item: PublishGroupSuggestItem): void {
+ if (item.isPublished) {
+ return;
+ }
+ void this.onChoose(item);
+ }
+}
diff --git a/apps/obsidian/src/utils/importNodes.ts b/apps/obsidian/src/utils/importNodes.ts
index 4cb8c7df3..1502a3417 100644
--- a/apps/obsidian/src/utils/importNodes.ts
+++ b/apps/obsidian/src/utils/importNodes.ts
@@ -21,6 +21,11 @@ import {
import { createTemplateFile } from "./templates";
import { resolveFolderForSpaceUri } from "./importFolderMetadata";
+export type MyGroup = {
+ id: string;
+ name: string;
+};
+
export const getAvailableGroupIds = async (
client: DGSupabaseClient,
): Promise => {
@@ -37,6 +42,33 @@ export const getAvailableGroupIds = async (
return (data || []).map((g) => g.group_id);
};
+export const getMyGroups = async (
+ client: DGSupabaseClient,
+): Promise => {
+ const userId = (await client.auth.getUser()).data.user?.id ?? "";
+ const { data, error } = await client
+ .from("group_membership")
+ .select("group_id, my_groups!group_id(name)")
+ .eq("member_id", userId);
+
+ if (error) {
+ console.error("Error fetching groups:", error);
+ throw new Error(`Failed to fetch groups: ${error.message}`);
+ }
+
+ return (data ?? [])
+ .filter(
+ (row): row is { group_id: string; my_groups: { name: string | null } } =>
+ typeof row.group_id === "string" &&
+ row.my_groups !== null &&
+ typeof row.my_groups === "object",
+ )
+ .map((row) => ({
+ id: row.group_id,
+ name: row.my_groups.name ?? row.group_id,
+ }));
+};
+
type PublishedNode = {
source_local_id: string;
space_id: number;
diff --git a/apps/obsidian/src/utils/publishGroupSelection.ts b/apps/obsidian/src/utils/publishGroupSelection.ts
new file mode 100644
index 000000000..09adcba56
--- /dev/null
+++ b/apps/obsidian/src/utils/publishGroupSelection.ts
@@ -0,0 +1,253 @@
+import { Notice, type FrontMatterCache, type TFile } from "obsidian";
+import type DiscourseGraphPlugin from "~/index";
+import { PublishGroupSuggestModal } from "~/components/PublishGroupSuggestModal";
+import {
+ getAvailableGroupIds,
+ getMyGroups,
+ type MyGroup,
+} from "~/utils/importNodes";
+import { getLoggedInClient } from "~/utils/supabaseContext";
+import {
+ getPublishedToGroups,
+ publishNode,
+ publishNodeToGroup,
+} from "~/utils/publishNode";
+import { syncAllNodesAndRelations } from "~/utils/syncDgNodesToSupabase";
+
+export type PublishGroupOption = MyGroup & {
+ isPublished: boolean;
+};
+
+export const PUBLISH_TO_ALL_ITEM_ID = "__publish_to_all_groups__";
+
+export type PublishGroupSuggestItem = PublishGroupOption & {
+ isPublishToAll?: boolean;
+};
+
+export { getPublishedToGroups };
+
+const getErrorMessage = (error: unknown): string =>
+ error instanceof Error ? error.message : String(error);
+
+export const notifyPublishError = (error: unknown): void => {
+ new Notice(`Publish failed: ${getErrorMessage(error)}`, 5000);
+ console.error("Publish failed:", error);
+};
+
+export const getUnpublishedGroups = (
+ groups: PublishGroupOption[],
+): PublishGroupOption[] => groups.filter((group) => !group.isPublished);
+
+export const getPublishToAllTitle = (unpublishedCount: number): string =>
+ unpublishedCount === 0
+ ? "Already published to all groups"
+ : `Publish to ${unpublishedCount} group${unpublishedCount === 1 ? "" : "s"}`;
+
+export const buildPublishGroupPickerItems = (
+ groups: PublishGroupOption[],
+): PublishGroupSuggestItem[] => {
+ const unpublishedGroups = getUnpublishedGroups(groups);
+ return [
+ {
+ id: PUBLISH_TO_ALL_ITEM_ID,
+ name: "Publish to all groups",
+ isPublished: unpublishedGroups.length === 0,
+ isPublishToAll: true,
+ },
+ ...groups,
+ ];
+};
+
+export const isPublishToAllItem = (
+ item: PublishGroupSuggestItem,
+): item is PublishGroupSuggestItem & { isPublishToAll: true } =>
+ item.isPublishToAll === true;
+
+export const loadMyGroups = async (
+ plugin: DiscourseGraphPlugin,
+): Promise => {
+ const client = await getLoggedInClient(plugin);
+ if (!client) {
+ throw new Error("Cannot connect to database");
+ }
+ return getMyGroups(client);
+};
+
+export const withPublishedState = (
+ groups: MyGroup[],
+ publishedToGroups: string[],
+): PublishGroupOption[] =>
+ groups.map((group) => ({
+ ...group,
+ isPublished: publishedToGroups.includes(group.id),
+ }));
+
+export const publishNodeToSelectedGroup = async ({
+ plugin,
+ file,
+ frontmatter,
+ groupId,
+}: {
+ plugin: DiscourseGraphPlugin;
+ file: TFile;
+ frontmatter: FrontMatterCache | Record;
+ groupId: string;
+}): Promise => {
+ const publishedToGroups = getPublishedToGroups(frontmatter);
+ if (publishedToGroups.includes(groupId)) {
+ throw new Error("Already shared with this group");
+ }
+
+ if (!frontmatter.nodeInstanceId) {
+ throw new Error("Please sync the node first");
+ }
+
+ await publishNode({
+ plugin,
+ file,
+ frontmatter: frontmatter as FrontMatterCache,
+ groupId,
+ });
+};
+
+export const publishNodeToAllGroups = async ({
+ plugin,
+ file,
+}: {
+ plugin: DiscourseGraphPlugin;
+ file: TFile;
+}): Promise => {
+ const frontmatter = plugin.app.metadataCache.getFileCache(file)?.frontmatter;
+ if (!frontmatter) {
+ throw new Error("File metadata not available");
+ }
+
+ const client = await getLoggedInClient(plugin);
+ if (!client) {
+ throw new Error("Cannot connect to database");
+ }
+
+ const memberGroupIds = await getAvailableGroupIds(client);
+ const existingPublish = getPublishedToGroups(frontmatter);
+ const toPublish = memberGroupIds.filter(
+ (groupId) => !existingPublish.includes(groupId),
+ );
+
+ if (toPublish.length === 0) {
+ return 0;
+ }
+
+ if (!frontmatter.nodeInstanceId) {
+ throw new Error("Please sync the node first");
+ }
+
+ await syncAllNodesAndRelations(plugin);
+
+ for (const groupId of toPublish) {
+ await publishNodeToGroup({
+ plugin,
+ file,
+ frontmatter,
+ myGroup: groupId,
+ skipFrontmatterUpdate: true,
+ });
+ }
+
+ await plugin.app.fileManager.processFrontMatter(
+ file,
+ (fm: Record) => {
+ const current = getPublishedToGroups(fm);
+ fm.publishedToGroups = [...new Set([...current, ...toPublish])];
+ },
+ );
+
+ return toPublish.length;
+};
+
+export const publishToSelectedGroupWithNotice = async ({
+ plugin,
+ file,
+ groupId,
+}: {
+ plugin: DiscourseGraphPlugin;
+ file: TFile;
+ groupId: string;
+}): Promise => {
+ const frontmatter = plugin.app.metadataCache.getFileCache(file)?.frontmatter;
+ if (!frontmatter) {
+ throw new Error("File metadata not available");
+ }
+
+ await publishNodeToSelectedGroup({
+ plugin,
+ file,
+ frontmatter,
+ groupId,
+ });
+ new Notice("Published successfully", 3000);
+};
+
+export const publishToAllGroupsWithNotice = async ({
+ plugin,
+ file,
+}: {
+ plugin: DiscourseGraphPlugin;
+ file: TFile;
+}): Promise => {
+ const publishedCount = await publishNodeToAllGroups({ plugin, file });
+ if (publishedCount === 0) {
+ new Notice("Already published to all groups", 3000);
+ return;
+ }
+ new Notice(
+ `Published to ${publishedCount} group${publishedCount === 1 ? "" : "s"}`,
+ 3000,
+ );
+};
+
+export const openPublishGroupPicker = async ({
+ plugin,
+ file,
+}: {
+ plugin: DiscourseGraphPlugin;
+ file: TFile;
+}): Promise => {
+ let groups: PublishGroupOption[];
+ try {
+ const myGroups = await loadMyGroups(plugin);
+ const frontmatter =
+ plugin.app.metadataCache.getFileCache(file)?.frontmatter ?? {};
+ groups = withPublishedState(myGroups, getPublishedToGroups(frontmatter));
+ } catch (error) {
+ new Notice(getErrorMessage(error), 5000);
+ return;
+ }
+
+ if (groups.length === 0) {
+ new Notice("You are not a member of any groups", 5000);
+ return;
+ }
+
+ new PublishGroupSuggestModal({
+ app: plugin.app,
+ items: buildPublishGroupPickerItems(groups),
+ onChoose: async (item: PublishGroupSuggestItem) => {
+ try {
+ if (isPublishToAllItem(item)) {
+ await publishToAllGroupsWithNotice({ plugin, file });
+ return;
+ }
+ if (item.isPublished) {
+ return;
+ }
+ await publishToSelectedGroupWithNotice({
+ plugin,
+ file,
+ groupId: item.id,
+ });
+ } catch (error) {
+ notifyPublishError(error);
+ }
+ },
+ }).open();
+};
diff --git a/apps/obsidian/src/utils/publishNode.ts b/apps/obsidian/src/utils/publishNode.ts
index 78e0c86f8..160a27dab 100644
--- a/apps/obsidian/src/utils/publishNode.ts
+++ b/apps/obsidian/src/utils/publishNode.ts
@@ -23,6 +23,14 @@ import type { DiscourseNodeInVault } from "./getDiscourseNodes";
import type { SupabaseContext } from "./supabaseContext";
import type { TablesInsert } from "@repo/database/dbTypes";
+export const getPublishedToGroups = (
+ frontmatter: FrontMatterCache | Record,
+): string[] => {
+ const publishedToGroups = frontmatter.publishedToGroups as unknown;
+ if (!Array.isArray(publishedToGroups)) return [];
+ return publishedToGroups.filter((g): g is string => typeof g === "string");
+};
+
const publishSchema = async ({
client,
spaceId,
@@ -229,10 +237,12 @@ export const publishNode = async ({
plugin,
file,
frontmatter,
+ groupId,
}: {
plugin: DiscourseGraphPlugin;
file: TFile;
frontmatter: FrontMatterCache;
+ groupId?: string;
}): Promise => {
const client = await getLoggedInClient(plugin);
if (!client) throw new Error("Cannot get client");
@@ -243,8 +253,11 @@ export const publishNode = async ({
// Hopefully temporary workaround for sync bug
await syncAllNodesAndRelations(plugin);
const commonGroups = existingPublish.filter((g) => myGroups.has(g));
- // temporary single-group assumption
- const myGroup = (commonGroups.length > 0 ? commonGroups : [...myGroups])[0]!;
+ const myGroup =
+ groupId ?? (commonGroups.length > 0 ? commonGroups : [...myGroups])[0]!;
+ if (!myGroups.has(myGroup)) {
+ throw new Error("You are not a member of that group");
+ }
return await publishNodeToGroup({ plugin, file, frontmatter, myGroup });
};
@@ -391,11 +404,13 @@ export const publishNodeToGroup = async ({
file,
frontmatter,
myGroup,
+ skipFrontmatterUpdate = false,
}: {
plugin: DiscourseGraphPlugin;
file: TFile;
frontmatter: FrontMatterCache;
myGroup: string;
+ skipFrontmatterUpdate?: boolean;
}): Promise => {
const nodeId = frontmatter.nodeInstanceId as string | undefined;
if (!nodeId) throw new Error("Please sync the node first");
@@ -488,11 +503,15 @@ export const publishNodeToGroup = async ({
file,
attachments,
});
- if (!existingPublish.includes(myGroup))
+ if (!skipFrontmatterUpdate && !existingPublish.includes(myGroup)) {
await plugin.app.fileManager.processFrontMatter(
file,
(fm: Record) => {
- fm.publishedToGroups = [...existingPublish, myGroup];
+ const current = getPublishedToGroups(fm);
+ if (!current.includes(myGroup)) {
+ fm.publishedToGroups = [...current, myGroup];
+ }
},
);
+ }
};
diff --git a/apps/obsidian/src/utils/registerCommands.ts b/apps/obsidian/src/utils/registerCommands.ts
index a4707a331..ea7e019f6 100644
--- a/apps/obsidian/src/utils/registerCommands.ts
+++ b/apps/obsidian/src/utils/registerCommands.ts
@@ -9,7 +9,7 @@ import { refreshAllImportedFiles } from "./importNodes";
import { VIEW_TYPE_MARKDOWN, VIEW_TYPE_TLDRAW_DG_PREVIEW } from "~/constants";
import { createCanvas } from "~/components/canvas/utils/tldraw";
import { syncAllNodesAndRelations } from "./syncDgNodesToSupabase";
-import { publishNode } from "./publishNode";
+import { openPublishGroupPicker } from "./publishGroupSelection";
import { addRelationIfRequested } from "~/components/canvas/utils/relationJsonUtils";
import type { DiscourseNode } from "~/types";
import { TldrawView } from "~/components/canvas/TldrawView";
@@ -307,23 +307,15 @@ export const registerCommands = (plugin: DiscourseGraphPlugin) => {
if (!frontmatter.nodeTypeId) {
return false;
}
+ if (frontmatter.importedFromRid) {
+ return false;
+ }
if (!checking) {
if (!frontmatter.nodeInstanceId) {
new Notice("Please sync the node first");
return true;
}
- // TODO (in follow-up PRs):
- // Maybe sync the node now if unsynced
- // Ensure that the node schema is synced to the database, and shared
- // sync the assets to the database
- publishNode({ plugin, file, frontmatter })
- .then(() => {
- new Notice("Published");
- })
- .catch((error: Error) => {
- new Notice(error.message);
- console.error(error);
- });
+ void openPublishGroupPicker({ plugin, file });
}
return true;
},