Skip to content

Commit 015387d

Browse files
committed
sync all nodes on load
1 parent 1006400 commit 015387d

File tree

5 files changed

+718
-7
lines changed

5 files changed

+718
-7
lines changed
Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
/* eslint-disable @typescript-eslint/naming-convention */
2+
import { TFile } from "obsidian";
3+
import { DiscourseNode } from "~/types";
4+
import { SupabaseContext } from "./supabaseContext";
5+
import { LocalConceptDataInput } from "@repo/database/inputTypes";
6+
import { ObsidianDiscourseNodeData } from "./syncDgNodesToSupabase";
7+
8+
/**
9+
* Get extra data (author, timestamps) from file metadata
10+
*/
11+
const getNodeExtraData = (
12+
file: TFile,
13+
accountLocalId: string,
14+
): {
15+
author_local_id: string;
16+
created: string;
17+
last_modified: string;
18+
} => {
19+
return {
20+
author_local_id: accountLocalId,
21+
created: new Date(file.stat.ctime).toISOString(),
22+
last_modified: new Date(file.stat.mtime).toISOString(),
23+
};
24+
};
25+
26+
export const discourseNodeSchemaToLocalConcept = ({
27+
context,
28+
node,
29+
accountLocalId,
30+
}: {
31+
context: SupabaseContext;
32+
node: DiscourseNode;
33+
accountLocalId: string;
34+
}): LocalConceptDataInput => {
35+
const now = new Date().toISOString();
36+
return {
37+
space_id: context.spaceId,
38+
name: node.name,
39+
represented_by_local_id: node.id,
40+
is_schema: true,
41+
author_local_id: accountLocalId,
42+
created: now,
43+
// TODO: get the template or any other info to put into literal_content jsonb
44+
last_modified: now,
45+
};
46+
};
47+
48+
/**
49+
* Convert discourse node instance (file) to LocalConceptDataInput
50+
*/
51+
export const discourseNodeInstanceToLocalConcept = ({
52+
context,
53+
nodeData,
54+
accountLocalId,
55+
}: {
56+
context: SupabaseContext;
57+
nodeData: ObsidianDiscourseNodeData;
58+
accountLocalId: string;
59+
}): LocalConceptDataInput => {
60+
const extraData = getNodeExtraData(nodeData.file, accountLocalId);
61+
const concept = {
62+
space_id: context.spaceId,
63+
name: nodeData.file.basename,
64+
represented_by_local_id: nodeData.nodeInstanceId,
65+
schema_represented_by_local_id: nodeData.nodeTypeId,
66+
is_schema: false,
67+
...extraData,
68+
};
69+
console.log(
70+
`[discourseNodeInstanceToLocalConcept] Converting concept: represented_by_local_id=${nodeData.nodeInstanceId}, name="${nodeData.file.basename}"`,
71+
);
72+
return concept;
73+
};
74+
75+
export const relatedConcepts = (concept: LocalConceptDataInput): string[] => {
76+
const relations = Object.values(
77+
concept.local_reference_content || {},
78+
).flat() as string[];
79+
if (concept.schema_represented_by_local_id) {
80+
relations.push(concept.schema_represented_by_local_id);
81+
}
82+
// remove duplicates
83+
return [...new Set(relations)];
84+
};
85+
86+
/**
87+
* Recursively order concepts by dependency
88+
*/
89+
const orderConceptsRec = (
90+
ordered: LocalConceptDataInput[],
91+
concept: LocalConceptDataInput,
92+
remainder: { [key: string]: LocalConceptDataInput },
93+
): Set<string> => {
94+
const relatedConceptIds = relatedConcepts(concept);
95+
let missing: Set<string> = new Set();
96+
while (relatedConceptIds.length > 0) {
97+
const relatedConceptId = relatedConceptIds.shift()!;
98+
const relatedConcept = remainder[relatedConceptId];
99+
if (relatedConcept === undefined) {
100+
missing.add(relatedConceptId);
101+
} else {
102+
missing = new Set([
103+
...missing,
104+
...orderConceptsRec(ordered, relatedConcept, remainder),
105+
]);
106+
delete remainder[relatedConceptId];
107+
}
108+
}
109+
ordered.push(concept);
110+
delete remainder[concept.represented_by_local_id!];
111+
return missing;
112+
};
113+
114+
export const orderConceptsByDependency = (
115+
concepts: LocalConceptDataInput[],
116+
): { ordered: LocalConceptDataInput[]; missing: string[] } => {
117+
if (concepts.length === 0) return { ordered: concepts, missing: [] };
118+
const conceptById: { [key: string]: LocalConceptDataInput } =
119+
Object.fromEntries(
120+
concepts
121+
.filter((c) => c.represented_by_local_id)
122+
.map((c) => [c.represented_by_local_id!, c]),
123+
);
124+
const ordered: LocalConceptDataInput[] = [];
125+
let missing: Set<string> = new Set();
126+
while (Object.keys(conceptById).length > 0) {
127+
const first = Object.values(conceptById)[0];
128+
if (!first) break;
129+
missing = new Set([
130+
...missing,
131+
...orderConceptsRec(ordered, first, conceptById),
132+
]);
133+
}
134+
return { ordered, missing: Array.from(missing) };
135+
};

apps/obsidian/src/utils/registerCommands.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ import { BulkIdentifyDiscourseNodesModal } from "~/components/BulkIdentifyDiscou
66
import { createDiscourseNode } from "./createNode";
77
import { VIEW_TYPE_MARKDOWN, VIEW_TYPE_TLDRAW_DG_PREVIEW } from "~/constants";
88
import { createCanvas } from "~/components/canvas/utils/tldraw";
9+
import { createOrUpdateDiscourseEmbedding } from "./syncDgNodesToSupabase";
10+
import { Notice } from "obsidian";
911

1012
export const registerCommands = (plugin: DiscourseGraphPlugin) => {
1113
plugin.addCommand({
@@ -130,4 +132,27 @@ export const registerCommands = (plugin: DiscourseGraphPlugin) => {
130132
icon: "layout-dashboard", // Using Lucide icon as per style guide
131133
callback: () => createCanvas(plugin),
132134
});
135+
136+
plugin.addCommand({
137+
id: "sync-discourse-nodes-to-supabase",
138+
name: "Sync Discourse Nodes to Supabase",
139+
checkCallback: (checking: boolean) => {
140+
if (!plugin.settings.syncModeEnabled) {
141+
return false;
142+
}
143+
if (!checking) {
144+
void createOrUpdateDiscourseEmbedding(plugin)
145+
.then(() => {
146+
new Notice("Discourse nodes synced successfully", 3000);
147+
})
148+
.catch((error) => {
149+
const errorMessage =
150+
error instanceof Error ? error.message : String(error);
151+
new Notice(`Sync failed: ${errorMessage}`, 5000);
152+
console.error("Manual sync failed:", error);
153+
});
154+
}
155+
return true;
156+
},
157+
});
133158
};

0 commit comments

Comments
 (0)