Skip to content

Commit d7b325c

Browse files
committed
eng-1461 use Rid instead of just spaceUri as mark of import
1 parent 1662562 commit d7b325c

13 files changed

Lines changed: 162 additions & 103 deletions

apps/obsidian/src/components/DiscourseContextView.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ const DiscourseContext = ({ activeFile }: DiscourseContextProps) => {
3737
setIsPublished(false);
3838
return;
3939
}
40-
const isImported = !!frontmatter.importedFromSpaceUri;
40+
const isImported = !!frontmatter.importedFromRid;
4141
const publishedToGroups = frontmatter.publishedToGroups as unknown;
4242
const published =
4343
!isImported &&
@@ -125,7 +125,7 @@ const DiscourseContext = ({ activeFile }: DiscourseContextProps) => {
125125
return <div>Unknown node type: {frontmatter.nodeTypeId}</div>;
126126
}
127127

128-
const isImported = !!frontmatter.importedFromSpaceUri;
128+
const isImported = !!frontmatter.importedFromRid;
129129
const modifiedAt =
130130
typeof frontmatter.lastModified === "number"
131131
? frontmatter.lastModified

apps/obsidian/src/components/NodeTypeSettings.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ const generateTagPlaceholder = (format: string, nodeName?: string): string => {
2727

2828
type EditableFieldKey = keyof Omit<
2929
DiscourseNode,
30-
"id" | "shortcut" | "modified" | "created"
30+
"id" | "shortcut" | "modified" | "created" | "importedFromRid"
3131
>;
3232

3333
type BaseFieldConfig = {

apps/obsidian/src/components/RelationshipSettings.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ const RelationshipSettings = () => {
2121

2222
type EditableFieldKey = keyof Omit<
2323
DiscourseRelation,
24-
"id" | "modified" | "created"
24+
"id" | "modified" | "created" | "importedFromRid"
2525
>;
2626

2727
const handleRelationChange = async (

apps/obsidian/src/components/RelationshipTypeSettings.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ const RelationshipTypeSettings = () => {
9999

100100
type EditableFieldKey = keyof Omit<
101101
DiscourseRelationType,
102-
"id" | "modified" | "created"
102+
"id" | "modified" | "created" | "importedFromRid"
103103
>;
104104

105105
const handleRelationTypeChange = (

apps/obsidian/src/index.ts

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@ import { initializeSupabaseSync } from "~/utils/syncDgNodesToSupabase";
2727
import { FileChangeListener } from "~/utils/fileChangeListener";
2828
import generateUid from "~/utils/generateUid";
2929
import { migrateFrontmatterRelationsToRelationsJson } from "~/utils/relationsStore";
30+
import {
31+
type DiscourseNodeInVault,
32+
collectDiscourseNodesFromVault,
33+
} from "~/utils/getDiscourseNodes";
3034

3135
export default class DiscourseGraphPlugin extends Plugin {
3236
settings: Settings = { ...DEFAULT_SETTINGS };
@@ -43,6 +47,10 @@ export default class DiscourseGraphPlugin extends Plugin {
4347
console.error("Failed to migrate frontmatter relations:", error);
4448
});
4549

50+
await this.migrateImportedFromFrontMatter().catch((error) => {
51+
console.error("Failed to migrate frontmatter:", error);
52+
});
53+
4654
if (this.settings.syncModeEnabled === true) {
4755
void initializeSupabaseSync(this).catch((error) => {
4856
console.error("Failed to initialize Supabase sync:", error);
@@ -275,7 +283,7 @@ export default class DiscourseGraphPlugin extends Plugin {
275283
keysToHide.push(
276284
...[
277285
"nodeTypeId",
278-
"importedFromSpaceUri",
286+
"importedFromRid",
279287
"nodeInstanceId",
280288
"publishedToGroups",
281289
"lastModified",
@@ -395,6 +403,37 @@ export default class DiscourseGraphPlugin extends Plugin {
395403
this.currentViewActions = [];
396404
}
397405

406+
async migrateImportedFromFrontMatter() {
407+
const nodes = await collectDiscourseNodesFromVault(this, true);
408+
for (const node of nodes) {
409+
if (typeof node.frontmatter.importedFromSpaceUri === "string") {
410+
await this.app.fileManager.processFrontMatter(
411+
node.file,
412+
(frontmatter: Record<string, unknown>) => {
413+
const oldUri = frontmatter.importedFromSpaceUri as string;
414+
// note: we fortunately reused the original Id here.
415+
const nodeId = frontmatter.nodeInstanceId;
416+
if (typeof nodeId !== "string") {
417+
console.error(
418+
`error: missing nodeInstanceId on node ${node.file.path}`,
419+
);
420+
return;
421+
}
422+
if (!oldUri.startsWith("obsidian:")) {
423+
console.error(
424+
`error: unexpected value ${oldUri} for importedFromSpaceUri`,
425+
);
426+
return;
427+
}
428+
const spaceUri = "orn:obsidian.note:" + oldUri.substring(9);
429+
frontmatter.importedFromRid = `${spaceUri}/${nodeId}`;
430+
delete frontmatter.importedFromSpaceUri;
431+
},
432+
);
433+
}
434+
}
435+
}
436+
398437
async onunload() {
399438
this.cleanupViewActions();
400439
if (this.styleElement) {

apps/obsidian/src/services/QueryEngine.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -297,17 +297,17 @@ export class QueryEngine {
297297
*/
298298
findExistingImportedFile = (
299299
nodeInstanceId: string,
300-
importedFromSpaceUri: string,
300+
importedFromRid: string,
301301
): TFile | null => {
302302
if (this.dc) {
303303
try {
304304
const safeId = nodeInstanceId
305305
.replace(/\\/g, "\\\\")
306306
.replace(/"/g, '\\"');
307-
const safeUri = importedFromSpaceUri
307+
const safeUri = importedFromRid
308308
.replace(/\\/g, "\\\\")
309309
.replace(/"/g, '\\"');
310-
const dcQuery = `@page and nodeInstanceId = "${safeId}" and importedFromSpaceUri = "${safeUri}"`;
310+
const dcQuery = `@page and nodeInstanceId = "${safeId}" and importedFromRid = "${safeUri}"`;
311311
const results = this.dc.query(dcQuery);
312312

313313
for (const page of results) {
@@ -329,7 +329,7 @@ export class QueryEngine {
329329
const fm = this.app.metadataCache.getFileCache(f)?.frontmatter;
330330
if (
331331
fm?.nodeInstanceId === nodeInstanceId &&
332-
fm.importedFromSpaceUri === importedFromSpaceUri
332+
fm.importedFromRid === importedFromRid
333333
) {
334334
return f;
335335
}

apps/obsidian/src/types.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ export type DiscourseNode = {
1313
keyImage?: boolean;
1414
created: number;
1515
modified: number;
16+
importedFromRid?: string;
1617
};
1718

1819
export type DiscourseRelationType = {
@@ -22,6 +23,7 @@ export type DiscourseRelationType = {
2223
color: TldrawColorName;
2324
created: number;
2425
modified: number;
26+
importedFromRid?: string;
2527
};
2628

2729
export type DiscourseRelation = {
@@ -31,6 +33,19 @@ export type DiscourseRelation = {
3133
relationshipTypeId: string;
3234
created: number;
3335
modified: number;
36+
importedFromRid?: string;
37+
};
38+
39+
export type RelationInstance = {
40+
id: string;
41+
type: string;
42+
source: string;
43+
destination: string;
44+
created: number;
45+
author: string;
46+
lastModified?: number;
47+
publishedToGroupId?: string[];
48+
importedFromRid?: string;
3449
};
3550

3651
export type Settings = {

apps/obsidian/src/utils/fileChangeListener.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ export class FileChangeListener {
9898
return false;
9999
}
100100

101-
if (frontmatter?.importedFromSpaceUri) {
101+
if (frontmatter?.importedFromRid) {
102102
return false;
103103
}
104104

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import type { TFile } from "obsidian";
2+
import type DiscourseGraphPlugin from "~/index";
3+
import { ensureNodeInstanceId } from "./nodeInstanceId";
4+
5+
export type DiscourseNodeInVault = {
6+
file: TFile;
7+
frontmatter: Record<string, unknown>;
8+
nodeTypeId: string;
9+
nodeInstanceId: string;
10+
};
11+
12+
/**
13+
* Step 1: Collect all discourse nodes from the vault
14+
* Filters markdown files that have nodeTypeId in frontmatter
15+
*/
16+
export const collectDiscourseNodesFromVault = async (
17+
plugin: DiscourseGraphPlugin,
18+
includeImported?: boolean,
19+
): Promise<DiscourseNodeInVault[]> => {
20+
const allFiles = plugin.app.vault.getMarkdownFiles();
21+
const dgNodes: DiscourseNodeInVault[] = [];
22+
23+
for (const file of allFiles) {
24+
const cache = plugin.app.metadataCache.getFileCache(file);
25+
const frontmatter = cache?.frontmatter;
26+
27+
// Not a discourse node
28+
if (!frontmatter?.nodeTypeId) {
29+
continue;
30+
}
31+
32+
if (frontmatter.importedFromRid && includeImported !== true) {
33+
continue;
34+
}
35+
36+
const nodeTypeId = frontmatter.nodeTypeId as string;
37+
if (!nodeTypeId) {
38+
continue;
39+
}
40+
41+
const nodeInstanceId = await ensureNodeInstanceId(
42+
plugin,
43+
file,
44+
frontmatter as Record<string, unknown>,
45+
);
46+
47+
dgNodes.push({
48+
file,
49+
frontmatter: frontmatter as Record<string, unknown>,
50+
nodeTypeId,
51+
nodeInstanceId,
52+
});
53+
}
54+
55+
return dgNodes;
56+
};

apps/obsidian/src/utils/importNodes.ts

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -163,10 +163,13 @@ export const getSpaceNameFromId = async (
163163
return data.name;
164164
};
165165

166-
export const getSpaceNameIdFromUri = async (
166+
export const getSpaceNameIdFromRid = async (
167167
client: DGSupabaseClient,
168-
spaceUri: string,
168+
rid: string,
169169
): Promise<{ spaceName: string; spaceId: number }> => {
170+
const parts = rid.split("/");
171+
parts.pop();
172+
const spaceUri = parts.join("/");
170173
const { data, error } = await client
171174
.from("Space")
172175
.select("name, id")
@@ -296,9 +299,7 @@ export const fetchNodeContentWithMetadata = async ({
296299

297300
return {
298301
content: data.text,
299-
createdAt: data.created
300-
? new Date(data.created + "Z").valueOf()
301-
: 0,
302+
createdAt: data.created ? new Date(data.created + "Z").valueOf() : 0,
302303
modifiedAt: data.last_modified
303304
? new Date(data.last_modified + "Z").valueOf()
304305
: 0,
@@ -382,15 +383,15 @@ const fetchNodeContentForImport = async ({
382383
export const getSourceContentDates = async ({
383384
plugin,
384385
nodeInstanceId,
385-
spaceUri,
386+
importedFromRid,
386387
}: {
387388
plugin: DiscourseGraphPlugin;
388389
nodeInstanceId: string;
389-
spaceUri: string;
390+
importedFromRid: string;
390391
}): Promise<{ createdAt: string; modifiedAt: string } | null> => {
391392
const client = await getLoggedInClient(plugin);
392393
if (!client) return null;
393-
const { spaceId } = await getSpaceNameIdFromUri(client, spaceUri);
394+
const { spaceId } = await getSpaceNameIdFromRid(client, importedFromRid);
394395
if (spaceId < 0) return null;
395396
const { data, error } = await client
396397
.from("my_contents")
@@ -1074,6 +1075,7 @@ const processFileContent = async ({
10741075
// often empty immediately after create/modify), then map nodeTypeId and update frontmatter.
10751076
const { frontmatter } = parseFrontmatter(rawContent);
10761077
const sourceNodeTypeId = frontmatter.nodeTypeId;
1078+
const sourceNodeId = frontmatter.nodeInstanceId;
10771079

10781080
let mappedNodeTypeId: string | undefined;
10791081
if (sourceNodeTypeId && typeof sourceNodeTypeId === "string") {
@@ -1092,7 +1094,7 @@ const processFileContent = async ({
10921094
if (mappedNodeTypeId !== undefined) {
10931095
record.nodeTypeId = mappedNodeTypeId;
10941096
}
1095-
record.importedFromSpaceUri = sourceSpaceUri;
1097+
record.importedFromRid = `${sourceSpaceUri}/${sourceNodeId}`;
10961098
record.lastModified = importedModifiedAt;
10971099
},
10981100
stat,
@@ -1321,24 +1323,24 @@ export const refreshImportedFile = async ({
13211323
}
13221324
const cache = plugin.app.metadataCache.getFileCache(file);
13231325
const frontmatter = cache?.frontmatter as Record<string, unknown> | undefined;
1324-
if (!frontmatter?.importedFromSpaceUri || !frontmatter?.nodeInstanceId) {
1326+
if (!frontmatter?.importedFromRid || !frontmatter?.nodeInstanceId) {
13251327
return {
13261328
success: false,
1327-
error: "Missing frontmatter: importedFromSpaceUri or nodeInstanceId",
1329+
error: "Missing frontmatter: importedFromRid or nodeInstanceId",
13281330
};
13291331
}
13301332
if (
1331-
typeof frontmatter.importedFromSpaceUri !== "string" ||
1333+
typeof frontmatter.importedFromRid !== "string" ||
13321334
typeof frontmatter.nodeInstanceId !== "string"
13331335
) {
13341336
return {
13351337
success: false,
1336-
error: "Non-string frontmatter: importedFromSpaceUri or nodeInstanceId",
1338+
error: "Non-string frontmatter: importedFromRid or nodeInstanceId",
13371339
};
13381340
}
1339-
const { spaceName, spaceId } = await getSpaceNameIdFromUri(
1341+
const { spaceName, spaceId } = await getSpaceNameIdFromRid(
13401342
supabaseClient,
1341-
frontmatter.importedFromSpaceUri,
1343+
frontmatter.importedFromRid,
13421344
);
13431345
if (spaceId === -1) {
13441346
return { success: false, error: "Could not get the space Id" };
@@ -1397,7 +1399,7 @@ export const refreshAllImportedFiles = async (
13971399
for (const file of allFiles) {
13981400
const cache = plugin.app.metadataCache.getFileCache(file);
13991401
const frontmatter = cache?.frontmatter;
1400-
if (frontmatter?.importedFromSpaceUri && frontmatter?.nodeInstanceId) {
1402+
if (frontmatter?.importedFromRid && frontmatter?.nodeInstanceId) {
14011403
importedFiles.push(file);
14021404
}
14031405
}

0 commit comments

Comments
 (0)