ENG-1455: Dual-read from old-system settings and from blockprops#812
Conversation
|
This pull request has been ignored for the connected project Preview Branches by Supabase. |
| initializeSupabaseSync(); | ||
| } | ||
|
|
||
| const { extensionAPI } = onloadArgs; |
There was a problem hiding this comment.
For testing add
const debugWindow = window as unknown as { [key: string]: unknown };
debugWindow["__DG_DEBUG__"] = {
runDualReadProbe,
};
then go to browser console and do
const report = window.__DG_DEBUG__.runDualReadProbe();
report.summary; // this provides a summary
report.mismatches; // if there are any mismatches we will see them
report.rows; // will print all the values we read from the graph in personal/global/discourse node + blockprops form
apps/roam/src/index.ts
Outdated
| @@ -43,6 +43,7 @@ | |||
| } from "./data/userSettings"; | |||
| import { initSchema } from "./components/settings/utils/init"; | |||
| import { setupPullWatchOnSettingsPage } from "./components/settings/utils/pullWatchers"; | |||
There was a problem hiding this comment.
for testing add
import { runDualReadProbe } from "./components/settings/utils/accessors";
| } | ||
|
|
||
| return nodes; | ||
| }; |
There was a problem hiding this comment.
For testing add the following here
type DualReadProbeCase = { keys: string[] };
type DualReadProbeNodeCase = {
nodeType: string;
keys: string[];
};
type DualReadProbeItem = {
scope: "personal" | "global" | "discourseNode";
keys: string[];
nodeType?: string;
legacyValue?: unknown;
blockPropsValue?: unknown;
legacyError?: string;
blockPropsError?: string;
match: boolean;
};
const normalizeProbeError = (error: unknown): string => {
return error instanceof Error ? error.message : String(error);
};
const safeSerialize = (value: unknown): string => {
try {
return JSON.stringify(value);
} catch {
return String(value);
}
};
const normalizeForComparison = (value: unknown): unknown => {
if (Array.isArray(value)) {
return value.map(normalizeForComparison);
}
if (isRecord(value)) {
return Object.keys(value)
.sort()
.reduce<Record<string, unknown>>((acc, key) => {
acc[key] = normalizeForComparison(value[key]);
return acc;
}, {});
}
return value;
};
const runProbeRead = (
reader: () => unknown,
): {
value?: unknown;
error?: string;
} => {
try {
return { value: reader() };
} catch (error) {
return { error: normalizeProbeError(error) };
}
};
const hasProbeMatch = ({
legacyError,
blockPropsError,
legacyValue,
blockPropsValue,
}: {
legacyError?: string;
blockPropsError?: string;
legacyValue?: unknown;
blockPropsValue?: unknown;
}): boolean => {
if (legacyError || blockPropsError) return false;
return (
safeSerialize(normalizeForComparison(legacyValue)) ===
safeSerialize(normalizeForComparison(blockPropsValue))
);
};
const DEFAULT_DISCOURSE_NODE_PROBE_TYPE = "Claim";
const DEFAULT_DISCOURSE_NODE_PROBE_KEYS: string[][] = [
["description"],
["shortcut"],
["tag"],
["index"],
["format"],
["specification", "enabled"],
["specification", "query"],
["template"],
["attributes"],
["overlay"],
["canvasSettings", "color"],
["canvasSettings", "alias"],
["canvasSettings", "key-image"],
["canvasSettings", "key-image-option"],
["canvasSettings", "query-builder-alias"],
["graphOverview"],
["suggestiveRules", "embeddingRef"],
["suggestiveRules", "isFirstChild"],
];
export const runDualReadProbe = ({
personalCases = [
{ keys: ["Discourse context overlay"] },
{ keys: ["Suggestive mode overlay"] },
{ keys: ["Text selection popup"] },
{ keys: ["Disable sidebar open"] },
{ keys: ["Page preview"] },
{ keys: ["Hide feedback button"] },
{ keys: ["Auto canvas relations"] },
{ keys: ["Overlay in canvas"] },
{ keys: ["Streamline styling"] },
{ keys: ["Disable product diagnostics"] },
{ keys: ["Discourse tool shortcut"] },
{ keys: ["Personal node menu trigger"] },
{ keys: ["Node search menu trigger"] },
{ keys: ["Query"] },
{ keys: ["Query", "Hide query metadata"] },
{ keys: ["Query", "Default page size"] },
{ keys: ["Query", "Query pages"] },
{ keys: ["Query", "Default filters"] },
{ keys: ["Left sidebar"] },
],
globalCases = [
{ keys: ["Trigger"] },
{ keys: ["Canvas page format"] },
{ keys: ["Left sidebar"] },
{ keys: ["Left sidebar", "Children"] },
{ keys: ["Left sidebar", "Settings", "Collapsable"] },
{ keys: ["Left sidebar", "Settings", "Folded"] },
{ keys: ["Export"] },
{ keys: ["Export", "Remove special characters"] },
{ keys: ["Export", "Resolve block references"] },
{ keys: ["Export", "Resolve block embeds"] },
{ keys: ["Export", "Append referenced node"] },
{ keys: ["Export", "Link type"] },
{ keys: ["Export", "Max filename length"] },
{ keys: ["Export", "Frontmatter"] },
{ keys: ["Suggestive mode"] },
{ keys: ["Suggestive mode", "Include current page relations"] },
{ keys: ["Suggestive mode", "Include parent and child blocks"] },
{ keys: ["Suggestive mode", "Page groups"] },
{ keys: ["Relations"] },
],
discourseNodeCases = DEFAULT_DISCOURSE_NODE_PROBE_KEYS.map((keys) => ({
nodeType: DEFAULT_DISCOURSE_NODE_PROBE_TYPE,
keys,
})),
}: {
personalCases?: DualReadProbeCase[];
globalCases?: DualReadProbeCase[];
discourseNodeCases?: DualReadProbeNodeCase[];
} = {}) => {
const rows: DualReadProbeItem[] = [];
personalCases.forEach(({ keys }) => {
const legacy = runProbeRead(() => getLegacyPersonalSetting(keys));
const blockProps = runProbeRead(() =>
readPathValue(getPersonalSettings(), keys),
);
rows.push({
scope: "personal",
keys,
legacyValue: legacy.value,
blockPropsValue: blockProps.value,
legacyError: legacy.error,
blockPropsError: blockProps.error,
match: hasProbeMatch({
legacyError: legacy.error,
blockPropsError: blockProps.error,
legacyValue: legacy.value,
blockPropsValue: blockProps.value,
}),
});
});
globalCases.forEach(({ keys }) => {
const legacy = runProbeRead(() => getLegacyGlobalSetting(keys));
const blockProps = runProbeRead(() =>
readPathValue(getGlobalSettings(), keys),
);
rows.push({
scope: "global",
keys,
legacyValue: legacy.value,
blockPropsValue: blockProps.value,
legacyError: legacy.error,
blockPropsError: blockProps.error,
match: hasProbeMatch({
legacyError: legacy.error,
blockPropsError: blockProps.error,
legacyValue: legacy.value,
blockPropsValue: blockProps.value,
}),
});
});
discourseNodeCases.forEach(({ nodeType, keys }) => {
const legacy = runProbeRead(() =>
getLegacyDiscourseNodeSetting(nodeType, keys),
);
const blockProps = runProbeRead(() =>
readPathValue(getDiscourseNodeSettings(nodeType), keys),
);
rows.push({
scope: "discourseNode",
nodeType,
keys,
legacyValue: legacy.value,
blockPropsValue: blockProps.value,
legacyError: legacy.error,
blockPropsError: blockProps.error,
match: hasProbeMatch({
legacyError: legacy.error,
blockPropsError: blockProps.error,
legacyValue: legacy.value,
blockPropsValue: blockProps.value,
}),
});
});
const mismatches = rows.filter((row) => !row.match);
return {
dualReadEnabled: isDualReadEnabled(),
summary: {
total: rows.length,
matches: rows.filter((row) => row.match).length,
mismatches: mismatches.length,
},
rows,
mismatches,
};
};
|
@coderabbitai full review |
✅ Actions performedFull review triggered. |
📝 WalkthroughWalkthroughIntroduces dual-read compatibility for settings by adding extensive legacy reading paths and helper functions. When dual-read is disabled, the system falls back to legacy settings resolution for Personal, Global, and Discourse Node configurations. Updates query-related default values and introduces a new dual-read feature flag. Changes
Estimated code review effort🎯 4 (Complex) | ⏱️ ~50 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
5a02381 to
b67fd5f
Compare
3f08f30 to
23d75a0
Compare
b67fd5f to
adf5fb5
Compare
23d75a0 to
9dddded
Compare
adf5fb5 to
75d22ad
Compare
9dddded to
41691df
Compare
75d22ad to
cc8a3f2
Compare
41691df to
176d0d1
Compare
0ff501b to
017e4da
Compare
4475ce3 to
7160d5e
Compare
017e4da to
990543f
Compare
|
|
||
| export const QuerySettingsSchema = z.object({ | ||
| "Hide query metadata": z.boolean().default(false), | ||
| "Hide query metadata": z.boolean().default(true), |
There was a problem hiding this comment.
same default as legacy settings
| "Hide query metadata": z.boolean().default(true), | ||
| "Default page size": z.number().default(10), | ||
| "Query pages": z.array(z.string()).default([]), | ||
| "Query pages": z.array(z.string()).default(["discourse-graph/queries/*"]), |
There was a problem hiding this comment.
same defaults as legacy settings
| // which returns a flat DiscourseRelation[] with a different structure (one entry per | ||
| // if-block, triples at top level, no nodePositions). When migrating getDiscourseRelations() | ||
| // to read from block props, it will need a conversion from this shape to the flat array. | ||
| const getLegacyRelationsSetting = (): Record<string, unknown> => { |
There was a problem hiding this comment.
the plan is to eventually merge to main with the blockprop version so not sure about the performance worries, if any. Will do caching if said so
7160d5e to
b86b56f
Compare
mdroidian
left a comment
There was a problem hiding this comment.
As per our last meeting, I was under the impression that the plan for Wed was to
- merge the 5 PR's that were in review (this is complete)
- rebase/restack ENG-1454, 1466+
- Then create a pulse update for the project
Is this related to #2, rebase/restack? If so, could you explain to in what way it is related?
From this image, it doesn't look like it is part of "rebase/restack ENG-1454, 1466", as the root of that restack should be the base getters PR. Nor is it mentioned in "Land Orphaned ..." PR.
990543f to
1491bbf
Compare
feb69cc to
aac3698
Compare
aac3698 to
847359f
Compare
| if (rawValue === undefined) { | ||
| const legacyValue = getLegacyGlobalSetting(keys); | ||
| if (legacyValue !== undefined) { | ||
| throw new Error(getMissingSettingError({ context: "Global", keys })); |
There was a problem hiding this comment.
explicit throw, we want to know when this happens as it should never happen and not pass through dev testing
…egacy and block props are same
Discussed in meeting: no longer using graphite which means this is a non issue. |


https://www.loom.com/share/1894f6a6fef2493e97ad1bf06fed851f
Summary by CodeRabbit