diff --git a/components/editor.tsx b/components/editor.tsx index ebc80d8..c55a457 100644 --- a/components/editor.tsx +++ b/components/editor.tsx @@ -1,8 +1,15 @@ import AceEditor from 'react-ace'; import 'ace-builds/src-noconflict/mode-yaml'; import 'ace-builds/src-noconflict/theme-tomorrow_night_bright'; -import { packageJsToYaml, packageYamlToJs, PackageVersion, RegistryType } from '@open-audio-stack/core'; -import { Dispatch, SetStateAction, useEffect, useState, useRef } from 'react'; +import { + packageErrors, + packageJsToYaml, + packageRecommendations, + packageYamlToJs, + PackageVersion, + RegistryType, +} from '@open-audio-stack/core'; +import { Dispatch, SetStateAction, useEffect, useMemo, useState, useRef } from 'react'; import { Button } from '@mui/material'; import styles from '../styles/components/editor.module.css'; import Image from 'next/image'; @@ -70,6 +77,22 @@ const Editor = ({ form, pkgType, setForm, version }: EditorProps) => { const [yamlValue, setYamlValue] = useState(packageJsToYaml(form)); const debounceRef = useRef(null); + // Validation errors block submission-worthiness (missing/invalid required fields). + // Recommendations are non-blocking suggestions (e.g. missing arm64 support). + const errors = useMemo(() => packageErrors(form), [form]); + const recs = useMemo(() => packageRecommendations(form), [form]); + + // Only surface errors/recommendations once the user has actually changed a value, + // rather than immediately flooding a freshly loaded (or blank) form with warnings. + // Loading a different template/version resets the baseline to compare against. + const baselineRef = useRef(JSON.stringify(form)); + const prevVersionRef = useRef(version); + if (prevVersionRef.current !== version) { + prevVersionRef.current = version; + baselineRef.current = JSON.stringify(form); + } + const touched = JSON.stringify(form) !== baselineRef.current; + useEffect(() => { setYamlValue(packageJsToYaml(form)); }, [form]); @@ -104,6 +127,30 @@ const Editor = ({ form, pkgType, setForm, version }: EditorProps) => { }} /> {yamlError &&
YAML Error: {yamlError}
} + {touched && errors.length > 0 && ( +
+ {errors.length === 1 ? 'Error' : `${errors.length} errors`} +
    + {errors.map((error, index) => ( +
  • + {error.path.join('.') || 'package'}: {error.message} +
  • + ))} +
+
+ )} + {touched && recs.length > 0 && ( +
+ {recs.length === 1 ? 'Recommendation' : `${recs.length} recommendations`} +
    + {recs.map((rec, index) => ( +
  • + {rec.field}: {rec.rec} +
  • + ))} +
+
+ )}