@@ -3,7 +3,9 @@ import getShallowTreeByParentUid from "roamjs-components/queries/getShallowTreeB
33import { createPage , createBlock } from "roamjs-components/writes" ;
44import setBlockProps from "~/utils/setBlockProps" ;
55import getBlockProps from "~/utils/getBlockProps" ;
6+ import type { json } from "~/utils/getBlockProps" ;
67import INITIAL_NODE_VALUES from "~/data/defaultDiscourseNodes" ;
8+ import DEFAULT_RELATIONS_BLOCK_PROPS from "~/components/settings/data/defaultRelationsBlockProps" ;
79import { getAllDiscourseNodes } from "./accessors" ;
810import {
911 DiscourseNodeSchema ,
@@ -13,6 +15,7 @@ import {
1315 DG_BLOCK_PROP_SETTINGS_PAGE_TITLE ,
1416 DISCOURSE_NODE_PAGE_PREFIX ,
1517} from "./zodSchema" ;
18+ import toFlexRegex from "roamjs-components/util/toFlexRegex" ;
1619
1720const ensurePageExists = async ( pageTitle : string ) : Promise < string > => {
1821 let pageUid = getPageUidByPageTitle ( pageTitle ) ;
@@ -66,6 +69,7 @@ const buildBlockMap = (pageUid: string): Record<string, string> => {
6669} ;
6770
6871const initializeSettingsBlockProps = (
72+ pageUid : string ,
6973 blockMap : Record < string , string > ,
7074) : void => {
7175 const configs = getTopLevelBlockPropsConfig ( ) ;
@@ -74,10 +78,25 @@ const initializeSettingsBlockProps = (
7478 const uid = blockMap [ key ] ;
7579 if ( uid ) {
7680 const existingProps = getBlockProps ( uid ) ;
81+ const defaults = schema . parse ( { } ) ;
82+
7783 if ( ! existingProps || Object . keys ( existingProps ) . length === 0 ) {
78- const defaults = schema . parse ( { } ) ;
7984 setBlockProps ( uid , defaults , false ) ;
8085 }
86+
87+ // Reconcile placeholder relation keys with real block UIDs.
88+ // TODO: remove this when fully migrated to blockprops, as the keys won't need to match block UIDs anymore and the defaults can use any stable IDs.
89+ if ( key === "Global" ) {
90+ const relations = ( ( existingProps as Record < string , json > | null ) ?. [
91+ "Relations"
92+ ] ?? ( defaults as Record < string , json > ) [ "Relations" ] ) as Record <
93+ string ,
94+ json
95+ > ;
96+ if ( relations ) {
97+ reconcileRelationKeys ( pageUid , uid , relations ) ;
98+ }
99+ }
81100 }
82101 }
83102} ;
@@ -89,7 +108,7 @@ const initSettingsPageBlocks = async (): Promise<Record<string, string>> => {
89108 const topLevelBlocks = getTopLevelBlockPropsConfig ( ) . map ( ( { key } ) => key ) ;
90109 await ensureBlocksExist ( pageUid , topLevelBlocks , blockMap ) ;
91110
92- initializeSettingsBlockProps ( blockMap ) ;
111+ initializeSettingsBlockProps ( pageUid , blockMap ) ;
93112
94113 return blockMap ;
95114} ;
@@ -150,6 +169,74 @@ const initDiscourseNodePages = async (): Promise<Record<string, string>> => {
150169 return nodePageUids ;
151170} ;
152171
172+ /**
173+ * Replace placeholder relation keys (_INFO-rel, etc.) in the Global blockprops
174+ * with the actual block UIDs from the grammar > relations block tree.
175+ *
176+ * TODO: Remove this when fully migrated to blockprops. Once relations are read
177+ * exclusively from blockprops, the keys won't need to match block UIDs anymore
178+ * and the defaults can use any stable IDs.
179+ */
180+ const reconcileRelationKeys = (
181+ pageUid : string ,
182+ globalBlockUid : string ,
183+ relations : Record < string , json > ,
184+ ) : void => {
185+ const placeholderKeys = Object . keys ( DEFAULT_RELATIONS_BLOCK_PROPS ) ;
186+ const hasPlaceholders = placeholderKeys . some ( ( k ) => k in relations ) ;
187+ if ( ! hasPlaceholders ) {
188+ return ;
189+ }
190+
191+ const pageChildren = getShallowTreeByParentUid ( pageUid ) ;
192+ const grammarBlock = pageChildren . find ( ( c ) =>
193+ toFlexRegex ( "grammar" ) . test ( c . text ) ,
194+ ) ;
195+ if ( ! grammarBlock ) {
196+ return ;
197+ }
198+
199+ const grammarChildren = getShallowTreeByParentUid ( grammarBlock . uid ) ;
200+ const relationsBlock = grammarChildren . find ( ( c ) =>
201+ toFlexRegex ( "relations" ) . test ( c . text ) ,
202+ ) ;
203+ if ( ! relationsBlock ) {
204+ return ;
205+ }
206+
207+ const relationBlocks = getShallowTreeByParentUid ( relationsBlock . uid ) ;
208+
209+ const labelToUid : Record < string , string > = { } ;
210+ for ( const block of relationBlocks ) {
211+ labelToUid [ block . text ] = block . uid ;
212+ }
213+
214+ const placeholderToLabel : Record < string , string > = { } ;
215+ for ( const [ key , value ] of Object . entries ( DEFAULT_RELATIONS_BLOCK_PROPS ) ) {
216+ placeholderToLabel [ key ] = value . label ;
217+ }
218+
219+ const reconciledRelations : Record < string , json > = { } ;
220+ let changed = false ;
221+
222+ for ( const [ key , value ] of Object . entries ( relations ) ) {
223+ if ( placeholderKeys . includes ( key ) ) {
224+ const label = placeholderToLabel [ key ] ;
225+ const realUid = label ? labelToUid [ label ] : undefined ;
226+ if ( realUid ) {
227+ reconciledRelations [ realUid ] = value ;
228+ changed = true ;
229+ continue ;
230+ }
231+ }
232+ reconciledRelations [ key ] = value ;
233+ }
234+
235+ if ( changed ) {
236+ setBlockProps ( globalBlockUid , { Relations : reconciledRelations } , false ) ;
237+ }
238+ } ;
239+
153240export type InitSchemaResult = {
154241 blockUids : Record < string , string > ;
155242 nodePageUids : Record < string , string > ;
0 commit comments