From 958cdee7a6d9d04c34294902c37b5921a7dc2c0e Mon Sep 17 00:00:00 2001 From: sid597 Date: Mon, 21 Jul 2025 13:29:35 +0530 Subject: [PATCH 1/5] real time validation --- .../src/components/settings/NodeConfig.tsx | 112 ++++++++++++++++-- 1 file changed, 102 insertions(+), 10 deletions(-) diff --git a/apps/roam/src/components/settings/NodeConfig.tsx b/apps/roam/src/components/settings/NodeConfig.tsx index 8de66eae6..37910fdfc 100644 --- a/apps/roam/src/components/settings/NodeConfig.tsx +++ b/apps/roam/src/components/settings/NodeConfig.tsx @@ -1,4 +1,4 @@ -import React, { useState } from "react"; +import React, { useState, useMemo, useEffect } from "react"; import { DiscourseNode } from "~/utils/getDiscourseNodes"; import FlagPanel from "roamjs-components/components/ConfigPanels/FlagPanel"; import SelectPanel from "roamjs-components/components/ConfigPanels/SelectPanel"; @@ -12,6 +12,8 @@ import DiscourseNodeAttributes from "./DiscourseNodeAttributes"; import DiscourseNodeCanvasSettings from "./DiscourseNodeCanvasSettings"; import DiscourseNodeIndex from "./DiscourseNodeIndex"; import { OnloadArgs } from "roamjs-components/types"; +import getTextByBlockUid from "roamjs-components/queries/getTextByBlockUid"; +import getBasicTreeByParentUid from "roamjs-components/queries/getBasicTreeByParentUid"; const NodeConfig = ({ node, @@ -28,6 +30,7 @@ const NodeConfig = ({ const formatUid = getUid("Format"); const descriptionUid = getUid("Description"); const shortcutUid = getUid("Shortcut"); + const tagUid = getUid("Tag"); const templateUid = getUid("Template"); const overlayUid = getUid("Overlay"); const canvasUid = getUid("Canvas"); @@ -41,6 +44,73 @@ const NodeConfig = ({ const [selectedTabId, setSelectedTabId] = useState("general"); + // State for tracking current values and validation + const [currentTagValue, setCurrentTagValue] = useState(node.tag || ""); + const [currentFormatValue, setCurrentFormatValue] = useState( + node.format || "", + ); + + // Function to extract clean tag text (remove # if present) + const getCleanTagText = (tag: string): string => { + return tag.replace(/^#+/, "").trim().toUpperCase(); + }; + + // Function to check if tag text appears in format + const validateTagFormatConflict = useMemo(() => { + const cleanTag = getCleanTagText(currentTagValue); + if (!cleanTag) return { isValid: true, message: "" }; + + // Remove placeholders like {content} before validation + const formatWithoutPlaceholders = currentFormatValue.replace( + /{[^}]+}/g, + "", + ); + const formatUpper = formatWithoutPlaceholders.toUpperCase(); + + // Split format by non-alphanumeric characters to check for the exact tag + const formatParts = formatUpper.split(/[^A-Z0-9]/); + const hasConflict = formatParts.includes(cleanTag); + + let message = ""; + if (hasConflict) { + const formatForMessage = formatWithoutPlaceholders + .trim() + .replace(/(\s*-)*$/, ""); + if (selectedTabId === "format") { + message = `Format "${formatForMessage}" conflicts with tag: "${currentTagValue}". Please use some other format.`; + } else { + // Default message for 'general' tab and any other case + message = `Tag "${currentTagValue}" conflicts with format "${formatForMessage}". Please use some other tag.`; + } + } + + return { + isValid: !hasConflict, + message, + }; + }, [currentTagValue, currentFormatValue, selectedTabId]); + + // Effect to update current values when they change in the blocks + useEffect(() => { + const updateValues = () => { + try { + const tagValue = getBasicTreeByParentUid(tagUid)[0]?.text || ""; + const formatValue = getBasicTreeByParentUid(formatUid)[0]?.text || ""; + setCurrentTagValue(tagValue); + setCurrentFormatValue(formatValue); + } catch (error) { + // Handle case where blocks might not exist yet + console.warn("Error updating tag/format values:", error); + } + }; + + // Update values initially and set up periodic updates + updateValues(); + const interval = setInterval(updateValues, 500); + + return () => clearInterval(interval); + }, [tagUid, formatUid]); + return ( <> +
+
+ + {!validateTagFormatConflict.isValid && ( +
+ {validateTagFormatConflict.message} +
+ )} +
} /> @@ -90,14 +175,21 @@ const NodeConfig = ({ title="Format" panel={
- +
+ + {!validateTagFormatConflict.isValid && ( +
+ {validateTagFormatConflict.message} +
+ )} +