Skip to content

Commit 1e8fcd2

Browse files
committed
revert stubs, remove logs
1 parent 9095d0b commit 1e8fcd2

2 files changed

Lines changed: 197 additions & 30 deletions

File tree

apps/roam/src/components/settings/components/BlockPropSettingPanels.tsx

Lines changed: 195 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React, { useState } from "react";
1+
import React, { useState, useCallback, useRef } from "react";
22
import {
33
Checkbox,
44
InputGroup,
@@ -10,6 +10,8 @@ import {
1010
} from "@blueprintjs/core";
1111
import Description from "roamjs-components/components/Description";
1212
import idToTitle from "roamjs-components/util/idToTitle";
13+
import useSingleChildValue from "roamjs-components/components/ConfigPanels/useSingleChildValue";
14+
import getShallowTreeByParentUid from "roamjs-components/queries/getShallowTreeByParentUid";
1315
import {
1416
getGlobalSetting,
1517
setGlobalSetting,
@@ -20,6 +22,12 @@ import {
2022
} from "../utils/accessors";
2123
import type { FeatureFlags } from "../utils/zodSchema";
2224

25+
type RoamBlockSyncProps = {
26+
parentUid?: string;
27+
uid?: string;
28+
order?: number;
29+
};
30+
2331
type TextGetter = (keys: string[]) => string | undefined;
2432
type TextSetter = (keys: string[], value: string) => void;
2533

@@ -40,7 +48,7 @@ type BaseTextPanelProps = {
4048
setter: TextSetter;
4149
defaultValue?: string;
4250
placeholder?: string;
43-
};
51+
} & RoamBlockSyncProps;
4452

4553
type BaseFlagPanelProps = {
4654
title: string;
@@ -52,7 +60,7 @@ type BaseFlagPanelProps = {
5260
disabled?: boolean;
5361
onBeforeChange?: (checked: boolean) => Promise<boolean>;
5462
onChange?: (checked: boolean) => void;
55-
};
63+
} & RoamBlockSyncProps;
5664

5765
type BaseNumberPanelProps = {
5866
title: string;
@@ -63,7 +71,7 @@ type BaseNumberPanelProps = {
6371
defaultValue?: number;
6472
min?: number;
6573
max?: number;
66-
};
74+
} & RoamBlockSyncProps;
6775

6876
type BaseSelectPanelProps = {
6977
title: string;
@@ -73,7 +81,7 @@ type BaseSelectPanelProps = {
7381
setter: TextSetter;
7482
options: string[];
7583
defaultValue?: string;
76-
};
84+
} & RoamBlockSyncProps;
7785

7886
type BaseMultiTextPanelProps = {
7987
title: string;
@@ -82,8 +90,7 @@ type BaseMultiTextPanelProps = {
8290
getter: MultiTextGetter;
8391
setter: MultiTextSetter;
8492
defaultValue?: string[];
85-
};
86-
93+
} & RoamBlockSyncProps;
8794

8895
const BaseTextPanel = ({
8996
title,
@@ -93,13 +100,33 @@ const BaseTextPanel = ({
93100
setter,
94101
defaultValue = "",
95102
placeholder,
103+
parentUid,
104+
uid,
105+
order,
96106
}: BaseTextPanelProps) => {
97107
const [value, setValue] = useState(() => getter(settingKeys) ?? defaultValue);
108+
const hasBlockSync = parentUid !== undefined && order !== undefined;
109+
const { onChange: syncToBlock } = useSingleChildValue({
110+
title,
111+
parentUid: parentUid ?? "",
112+
order: order ?? 0,
113+
uid,
114+
defaultValue,
115+
transform: (s: string) => s,
116+
toStr: (s: string) => s,
117+
});
98118

99119
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
100120
const newValue = e.target.value;
101121
setValue(newValue);
102122
setter(settingKeys, newValue);
123+
if (hasBlockSync) {
124+
syncToBlock(newValue);
125+
}
126+
// TODO: remove debug logging
127+
setTimeout(() => {
128+
console.log(`[TextPanel] "${title}" blockProp:`, getter(settingKeys));
129+
}, 500);
103130
};
104131

105132
return (
@@ -125,8 +152,34 @@ const BaseFlagPanel = ({
125152
disabled = false,
126153
onBeforeChange,
127154
onChange,
155+
parentUid,
156+
uid: initialBlockUid,
157+
order,
128158
}: BaseFlagPanelProps) => {
129159
const [value, setValue] = useState(() => getter(settingKeys) ?? defaultValue);
160+
const blockUidRef = useRef(initialBlockUid);
161+
162+
const syncFlagToBlock = useCallback(
163+
(checked: boolean) => {
164+
if (parentUid === undefined || order === undefined) return;
165+
if (checked) {
166+
if (blockUidRef.current) return;
167+
const newUid = window.roamAlphaAPI.util.generateUID();
168+
void window.roamAlphaAPI.createBlock({
169+
block: { string: title, uid: newUid },
170+
// eslint-disable-next-line @typescript-eslint/naming-convention
171+
location: { order, "parent-uid": parentUid },
172+
});
173+
blockUidRef.current = newUid;
174+
} else if (blockUidRef.current) {
175+
void window.roamAlphaAPI.deleteBlock({
176+
block: { uid: blockUidRef.current },
177+
});
178+
blockUidRef.current = undefined;
179+
}
180+
},
181+
[title, parentUid, order],
182+
);
130183

131184
const handleChange = async (e: React.FormEvent<HTMLInputElement>) => {
132185
const { checked } = e.target as HTMLInputElement;
@@ -138,7 +191,12 @@ const BaseFlagPanel = ({
138191

139192
setValue(checked);
140193
setter(settingKeys, checked);
194+
syncFlagToBlock(checked);
141195
onChange?.(checked);
196+
// TODO: remove debug logging
197+
setTimeout(() => {
198+
console.log(`[FlagPanel] "${title}" blockProp:`, getter(settingKeys));
199+
}, 500);
142200
};
143201

144202
return (
@@ -165,13 +223,33 @@ const BaseNumberPanel = ({
165223
defaultValue = 0,
166224
min,
167225
max,
226+
parentUid,
227+
uid,
228+
order,
168229
}: BaseNumberPanelProps) => {
169230
const [value, setValue] = useState(() => getter(settingKeys) ?? defaultValue);
231+
const hasBlockSync = parentUid !== undefined && order !== undefined;
232+
const { onChange: syncToBlock } = useSingleChildValue({
233+
title,
234+
parentUid: parentUid ?? "",
235+
order: order ?? 0,
236+
uid,
237+
defaultValue,
238+
transform: (s: string) => parseInt(s, 10),
239+
toStr: (v: number) => `${v}`,
240+
});
170241

171242
const handleChange = (valueAsNumber: number) => {
172243
if (Number.isNaN(valueAsNumber)) return;
173244
setValue(valueAsNumber);
174245
setter(settingKeys, valueAsNumber);
246+
if (hasBlockSync) {
247+
syncToBlock(valueAsNumber);
248+
}
249+
// TODO: remove debug logging
250+
setTimeout(() => {
251+
console.log(`[NumberPanel] "${title}" blockProp:`, getter(settingKeys));
252+
}, 500);
175253
};
176254

177255
return (
@@ -197,22 +275,47 @@ const BaseSelectPanel = ({
197275
setter,
198276
options,
199277
defaultValue,
278+
parentUid,
279+
uid,
280+
order,
200281
}: BaseSelectPanelProps) => {
201282
const [value, setValue] = useState(
202283
() => getter(settingKeys) ?? defaultValue ?? options[0],
203284
);
285+
const hasBlockSync = parentUid !== undefined && order !== undefined;
286+
const { onChange: syncToBlock } = useSingleChildValue({
287+
title,
288+
parentUid: parentUid ?? "",
289+
order: order ?? 0,
290+
uid,
291+
defaultValue: defaultValue ?? options[0] ?? "",
292+
transform: (s: string) => s,
293+
toStr: (s: string) => s,
294+
});
204295

205296
const handleChange = (e: React.ChangeEvent<HTMLSelectElement>) => {
206297
const newValue = e.target.value;
207298
setValue(newValue);
208299
setter(settingKeys, newValue);
300+
if (hasBlockSync) {
301+
syncToBlock(newValue);
302+
}
303+
// TODO: remove debug logging
304+
setTimeout(() => {
305+
console.log(`[SelectPanel] "${title}" blockProp:`, getter(settingKeys));
306+
}, 500);
209307
};
210308

211309
return (
212310
<Label>
213311
{idToTitle(title)}
214312
<Description description={description} />
215-
<HTMLSelect value={value} onChange={handleChange} fill options={options} />
313+
<HTMLSelect
314+
value={value}
315+
onChange={handleChange}
316+
fill
317+
options={options}
318+
/>
216319
</Label>
217320
);
218321
};
@@ -224,18 +327,67 @@ const BaseMultiTextPanel = ({
224327
getter,
225328
setter,
226329
defaultValue = [],
330+
parentUid,
331+
uid: initialBlockUid,
332+
order,
227333
}: BaseMultiTextPanelProps) => {
228334
const [values, setValues] = useState<string[]>(
229335
() => getter(settingKeys) ?? defaultValue,
230336
);
231337
const [inputValue, setInputValue] = useState("");
338+
const hasBlockSync = parentUid !== undefined && order !== undefined;
339+
const blockUidRef = useRef(initialBlockUid);
340+
const childUidsRef = useRef<string[]>(
341+
initialBlockUid
342+
? getShallowTreeByParentUid(initialBlockUid).map(
343+
(c: { uid: string }) => c.uid,
344+
)
345+
: [],
346+
);
232347

233-
const handleAdd = () => {
348+
const ensureParentBlock = useCallback(async (): Promise<
349+
string | undefined
350+
> => {
351+
if (blockUidRef.current) return blockUidRef.current;
352+
if (parentUid === undefined || order === undefined) return undefined;
353+
const newUid = window.roamAlphaAPI.util.generateUID();
354+
await window.roamAlphaAPI.createBlock({
355+
block: { string: title, uid: newUid },
356+
// eslint-disable-next-line @typescript-eslint/naming-convention
357+
location: { order, "parent-uid": parentUid },
358+
});
359+
blockUidRef.current = newUid;
360+
return newUid;
361+
}, [title, parentUid, order]);
362+
363+
const handleAdd = async () => {
234364
if (inputValue.trim() && !values.includes(inputValue.trim())) {
235-
const newValues = [...values, inputValue.trim()];
365+
const trimmed = inputValue.trim();
366+
const newValues = [...values, trimmed];
236367
setValues(newValues);
237368
setter(settingKeys, newValues);
238369
setInputValue("");
370+
371+
const parent = await ensureParentBlock();
372+
if (parent) {
373+
const valueUid = window.roamAlphaAPI.util.generateUID();
374+
void window.roamAlphaAPI.createBlock({
375+
block: { string: trimmed, uid: valueUid },
376+
location: {
377+
order: childUidsRef.current.length,
378+
// eslint-disable-next-line @typescript-eslint/naming-convention
379+
"parent-uid": parent,
380+
},
381+
});
382+
childUidsRef.current = [...childUidsRef.current, valueUid];
383+
}
384+
// TODO: remove debug logging
385+
setTimeout(() => {
386+
console.log(
387+
`[MultiTextPanel] "${title}" blockProp:`,
388+
getter(settingKeys),
389+
);
390+
}, 500);
239391
}
240392
};
241393

@@ -244,12 +396,30 @@ const BaseMultiTextPanel = ({
244396
const newValues = values.filter((_, i) => i !== index);
245397
setValues(newValues);
246398
setter(settingKeys, newValues);
399+
400+
if (hasBlockSync) {
401+
const removedUid = childUidsRef.current[index];
402+
if (removedUid) {
403+
void window.roamAlphaAPI.deleteBlock({ block: { uid: removedUid } });
404+
}
405+
childUidsRef.current = childUidsRef.current.filter(
406+
// eslint-disable-next-line @typescript-eslint/naming-convention
407+
(_, i) => i !== index,
408+
);
409+
}
410+
// TODO: remove debug logging
411+
setTimeout(() => {
412+
console.log(
413+
`[MultiTextPanel] "${title}" blockProp:`,
414+
getter(settingKeys),
415+
);
416+
}, 500);
247417
};
248418

249419
const handleKeyDown = (e: React.KeyboardEvent) => {
250420
if (e.key === "Enter") {
251421
e.preventDefault();
252-
handleAdd();
422+
void handleAdd();
253423
}
254424
};
255425

@@ -265,7 +435,11 @@ const BaseMultiTextPanel = ({
265435
placeholder="Add new item..."
266436
className="flex-grow"
267437
/>
268-
<Button icon="plus" onClick={handleAdd} disabled={!inputValue.trim()} />
438+
<Button
439+
icon="plus"
440+
onClick={() => void handleAdd()}
441+
disabled={!inputValue.trim()}
442+
/>
269443
</div>
270444
{values.length > 0 && (
271445
<div className="mt-2 flex flex-wrap gap-1">
@@ -337,15 +511,16 @@ export const FeatureFlagPanel = ({
337511
onBeforeEnable?: () => Promise<boolean>;
338512
onAfterChange?: (checked: boolean) => void;
339513
}) => {
340-
const handleBeforeChange: ((checked: boolean) => Promise<boolean>) | undefined =
341-
onBeforeEnable
342-
? async (checked) => {
343-
if (checked) {
344-
return onBeforeEnable();
345-
}
346-
return true;
514+
const handleBeforeChange:
515+
| ((checked: boolean) => Promise<boolean>)
516+
| undefined = onBeforeEnable
517+
? async (checked) => {
518+
if (checked) {
519+
return onBeforeEnable();
347520
}
348-
: undefined;
521+
return true;
522+
}
523+
: undefined;
349524

350525
return (
351526
<BaseFlagPanel

0 commit comments

Comments
 (0)