Skip to content

Commit b74f185

Browse files
committed
fix lint, prettier, remove the complexity from nodeconfig.tsx
1 parent 26971c9 commit b74f185

4 files changed

Lines changed: 65 additions & 54 deletions

File tree

apps/roam/src/components/DiscourseNodeSearchMenu.tsx

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,6 @@ import getDiscourseNodeFormatExpression from "~/utils/getDiscourseNodeFormatExpr
2626
import { Result } from "~/utils/types";
2727
import { getSetting } from "~/utils/extensionSettings";
2828
import MiniSearch from "minisearch";
29-
import {
30-
getPersonalSetting,
31-
setPersonalSetting,
32-
} from "~/components/settings/utils/accessors";
3329

3430
type Props = {
3531
textarea: HTMLTextAreaElement;

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

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,13 @@ export const formatHexColor = (color: string) => {
2525
return "";
2626
};
2727

28-
const DiscourseNodeCanvasSettings = ({ nodeType, uid }: { nodeType: string; uid: string }) => {
28+
const DiscourseNodeCanvasSettings = ({
29+
nodeType,
30+
uid,
31+
}: {
32+
nodeType: string;
33+
uid: string;
34+
}) => {
2935
const tree = useMemo(() => getBasicTreeByParentUid(uid), [uid]);
3036
const [color, setColor] = useState<string>(() => {
3137
const color = getSettingValueFromTree({ tree, key: "color" });

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

Lines changed: 30 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -6,26 +6,26 @@ import React, {
66
useMemo,
77
} from "react";
88
import { DiscourseNode } from "~/utils/getDiscourseNodes";
9+
import SelectPanel from "roamjs-components/components/ConfigPanels/SelectPanel";
910
import BlocksPanel from "roamjs-components/components/ConfigPanels/BlocksPanel";
1011
import { getSubTree } from "roamjs-components/util";
1112
import Description from "roamjs-components/components/Description";
1213
import { Label, Tabs, Tab, TabId, InputGroup } from "@blueprintjs/core";
13-
import getBasicTreeByParentUid from "roamjs-components/queries/getBasicTreeByParentUid";
1414
import DiscourseNodeSpecification from "./DiscourseNodeSpecification";
1515
import DiscourseNodeAttributes from "./DiscourseNodeAttributes";
16-
import SelectPanel from "roamjs-components/components/ConfigPanels/SelectPanel";
1716
import DiscourseNodeCanvasSettings from "./DiscourseNodeCanvasSettings";
1817
import DiscourseNodeIndex from "./DiscourseNodeIndex";
1918
import { OnloadArgs } from "roamjs-components/types";
19+
import getBasicTreeByParentUid from "roamjs-components/queries/getBasicTreeByParentUid";
20+
import createBlock from "roamjs-components/writes/createBlock";
21+
import updateBlock from "roamjs-components/writes/updateBlock";
2022
import DiscourseNodeSuggestiveRules from "./DiscourseNodeSuggestiveRules";
2123
import { getFormattedConfigTree } from "~/utils/discourseConfigRef";
2224
import refreshConfigTree from "~/utils/refreshConfigTree";
2325
import {
2426
DiscourseNodeTextPanel,
2527
DiscourseNodeFlagPanel,
2628
} from "./components/BlockPropSettingPanels";
27-
import createBlock from "roamjs-components/writes/createBlock";
28-
import updateBlock from "roamjs-components/writes/updateBlock";
2929

3030
export const getCleanTagText = (tag: string): string => {
3131
return tag.replace(/^#+/, "").trim().toUpperCase();
@@ -65,7 +65,9 @@ const ValidatedInputPanel = ({
6565
</div>
6666
);
6767

68-
const useDebouncedRoamUpdater = (
68+
const useDebouncedRoamUpdater = <
69+
T extends HTMLInputElement | HTMLTextAreaElement,
70+
>(
6971
uid: string,
7072
initialValue: string,
7173
isValid: boolean,
@@ -99,7 +101,7 @@ const useDebouncedRoamUpdater = (
99101
);
100102

101103
const handleChange = useCallback(
102-
(e: React.ChangeEvent<HTMLInputElement>) => {
104+
(e: React.ChangeEvent<T>) => {
103105
const newValue = e.target.value;
104106
setValue(newValue);
105107
saveToRoam(newValue, true);
@@ -160,34 +162,21 @@ const NodeConfig = ({
160162
});
161163

162164
const [selectedTabId, setSelectedTabId] = useState<TabId>("general");
165+
const [tagError, setTagError] = useState("");
163166
const [formatError, setFormatError] = useState("");
164-
const [tagValue, setTagValue] = useState(node.tag || "");
167+
const isConfigurationValid = !tagError && !formatError;
165168

169+
const [tagValue, setTagValue] = useState(node.tag || "");
166170
const {
167171
value: formatValue,
168172
handleChange: handleFormatChange,
169173
handleBlur: handleFormatBlurFromHook,
170-
} = useDebouncedRoamUpdater(formatUid, node.format, !formatError);
171-
172-
const validateTag = useCallback(
173-
(tag: string): string | undefined => {
174-
const cleanTag = getCleanTagText(tag);
175-
if (!cleanTag) return undefined;
176-
const roamTagRegex = /#?\[\[(.*?)\]\]|#(\S+)/g;
177-
const formatTags: string[] = [];
178-
for (const match of formatValue.matchAll(roamTagRegex)) {
179-
const tagName = match[1] || match[2];
180-
if (tagName) formatTags.push(tagName.toUpperCase());
181-
}
182-
if (formatTags.includes(cleanTag)) {
183-
return `The tag "${tag}" is referenced in the format. Please use a different tag or format.`;
184-
}
185-
return undefined;
186-
},
187-
[formatValue],
174+
} = useDebouncedRoamUpdater<HTMLInputElement>(
175+
formatUid,
176+
node.format,
177+
isConfigurationValid,
188178
);
189-
190-
const validateFormat = useCallback(
179+
const validate = useCallback(
191180
({
192181
tag,
193182
format,
@@ -203,12 +192,14 @@ const NodeConfig = ({
203192
key: "enabled",
204193
})?.uid?.length;
205194
if (format.trim().length === 0 && !isSpecificationEnabled) {
195+
setTagError("");
206196
setFormatError("Error: you must set either a format or specification");
207197
return;
208198
}
209199
const cleanTag = getCleanTagText(tag);
210200

211201
if (!cleanTag) {
202+
setTagError("");
212203
setFormatError("");
213204
return;
214205
}
@@ -229,21 +220,25 @@ const NodeConfig = ({
229220
setFormatError(
230221
`The format references the node's tag "${tag}". Please use a different format or tag.`,
231222
);
223+
setTagError(
224+
`The tag "${tag}" is referenced in the format. Please use a different tag or format.`,
225+
);
232226
} else {
227+
setTagError("");
233228
setFormatError("");
234229
}
235230
},
236231
[specificationUid],
237232
);
238233

239234
useEffect(() => {
240-
validateFormat({ tag: tagValue, format: formatValue });
241-
}, [tagValue, formatValue, validateFormat]);
235+
validate({ tag: tagValue, format: formatValue });
236+
}, [tagValue, formatValue, validate]);
242237

243238
const handleFormatBlur = useCallback(() => {
244239
handleFormatBlurFromHook();
245-
validateFormat({ tag: tagValue, format: formatValue });
246-
}, [handleFormatBlurFromHook, tagValue, formatValue, validateFormat]);
240+
validate({ tag: tagValue, format: formatValue });
241+
}, [handleFormatBlurFromHook, tagValue, formatValue, validate]);
247242

248243
return (
249244
<>
@@ -263,6 +258,7 @@ const NodeConfig = ({
263258
description={`Describing what the ${node.text} node represents in your graph.`}
264259
settingKeys={["description"]}
265260
initialValue={node.description}
261+
multiline
266262
order={1}
267263
parentUid={node.type}
268264
uid={descriptionUid}
@@ -284,7 +280,7 @@ const NodeConfig = ({
284280
settingKeys={["tag"]}
285281
initialValue={node.tag}
286282
placeholder={generateTagPlaceholder(node)}
287-
getValidationError={validateTag}
283+
error={tagError}
288284
onChange={setTagValue}
289285
order={2}
290286
parentUid={node.type}
@@ -330,7 +326,7 @@ const NodeConfig = ({
330326
node={node}
331327
parentUid={specificationUid}
332328
parentSetEnabled={(isSpecificationEnabled) => {
333-
validateFormat({
329+
validate({
334330
tag: tagValue,
335331
format: formatValue,
336332
isSpecificationEnabled,
@@ -388,7 +384,7 @@ const NodeConfig = ({
388384
<DiscourseNodeFlagPanel
389385
nodeType={node.type}
390386
title="Graph Overview"
391-
description="Whether to color the node in the graph overview based on canvas color. This is based on the node's plain title as described by a `has title` condition in its specification."
387+
description="Whether to color the node in the graph overview based on canvas color. This is based on the node's plain title as described by a \`has title\` condition in its specification."
392388
settingKeys={["graphOverview"]}
393389
initialValue={node.graphOverview}
394390
order={0}

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

Lines changed: 28 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import {
1313
HTMLSelect,
1414
Button,
1515
Tag,
16+
TextArea,
1617
} from "@blueprintjs/core";
1718
import Description from "roamjs-components/components/Description";
1819
import useSingleChildValue from "roamjs-components/components/ConfigPanels/useSingleChildValue";
@@ -39,17 +40,15 @@ type FlagSetter = (keys: string[], value: boolean) => void;
3940
type NumberSetter = (keys: string[], value: number) => void;
4041

4142
type MultiTextSetter = (keys: string[], value: string[]) => void;
42-
type ValidationError = string;
43-
type Validator<T> = (value: T) => ValidationError | undefined;
44-
4543
type BaseTextPanelProps = {
4644
title: string;
4745
description: string;
4846
settingKeys: string[];
4947
setter: TextSetter;
5048
initialValue?: string;
5149
placeholder?: string;
52-
getValidationError?: Validator<string>;
50+
multiline?: boolean;
51+
error?: string;
5352
onChange?: (value: string) => void;
5453
} & RoamBlockSyncProps;
5554

@@ -103,14 +102,16 @@ const BaseTextPanel = ({
103102
setter,
104103
initialValue,
105104
placeholder,
106-
getValidationError,
105+
multiline,
106+
error,
107107
onChange,
108108
parentUid,
109109
uid,
110110
order,
111111
}: BaseTextPanelProps) => {
112112
const [value, setValue] = useState(() => initialValue ?? "");
113-
const error = getValidationError?.(value);
113+
const errorRef = useRef(error);
114+
errorRef.current = error;
114115
const debounceRef = useRef(0);
115116
const hasBlockSync = parentUid !== undefined && order !== undefined;
116117
const { onChange: rawSyncToBlock } = useSingleChildValue({
@@ -128,15 +129,16 @@ const BaseTextPanel = ({
128129
return () => window.clearTimeout(debounceRef.current);
129130
}, []);
130131

131-
const handleChange = (e: ChangeEvent<HTMLInputElement>) => {
132+
const handleChange = (
133+
e: ChangeEvent<HTMLInputElement | HTMLTextAreaElement>,
134+
) => {
132135
const newValue = e.target.value;
133136
setValue(newValue);
134137
onChange?.(newValue);
135138

136-
if (getValidationError?.(newValue)) return;
137-
138139
window.clearTimeout(debounceRef.current);
139140
debounceRef.current = window.setTimeout(() => {
141+
if (errorRef.current) return;
140142
setter(settingKeys, newValue);
141143
syncToBlock?.(newValue);
142144
}, DEBOUNCE_MS);
@@ -147,11 +149,21 @@ const BaseTextPanel = ({
147149
<Label>
148150
{title}
149151
<Description description={description} />
150-
<InputGroup
151-
value={value}
152-
onChange={handleChange}
153-
placeholder={placeholder || initialValue}
154-
/>
152+
{multiline ? (
153+
<TextArea
154+
value={value}
155+
onChange={handleChange}
156+
placeholder={placeholder || initialValue}
157+
className="w-full"
158+
style={{ minHeight: 80, resize: "vertical" }}
159+
/>
160+
) : (
161+
<InputGroup
162+
value={value}
163+
onChange={handleChange}
164+
placeholder={placeholder || initialValue}
165+
/>
166+
)}
155167
</Label>
156168
{error && (
157169
<div className="mt-1 text-sm font-medium text-red-600">{error}</div>
@@ -584,7 +596,8 @@ export const DiscourseNodeTextPanel = ({
584596
RoamBlockSyncProps & {
585597
initialValue?: string;
586598
placeholder?: string;
587-
getValidationError?: Validator<string>;
599+
multiline?: boolean;
600+
error?: string;
588601
onChange?: (value: string) => void;
589602
}) => (
590603
<BaseTextPanel {...props} setter={createDiscourseNodeSetter(nodeType)} />

0 commit comments

Comments
 (0)