diff --git a/src/components/modal/configureOutputModal/ConfigureOutputModal.tsx b/src/components/modal/configureOutputModal/ConfigureOutputModal.tsx index 216da42..d9bac1b 100644 --- a/src/components/modal/configureOutputModal/ConfigureOutputModal.tsx +++ b/src/components/modal/configureOutputModal/ConfigureOutputModal.tsx @@ -67,6 +67,9 @@ export function ConfigureOutputModal({ defaultState(preset.pipelines) ); const [multiviews, setMultiviews] = useState([]); + const [portDuplicateIndexes, setPortDuplicateIndexes] = useState( + [] + ); const t = useTranslate(); useEffect(() => { @@ -110,6 +113,11 @@ export function ConfigureOutputModal({ return; } + if (portDuplicateIndexes.length > 0) { + toast.error(t('preset.no_port_selected')); + return; + } + presetToUpdate.pipelines[0].multiview = multiviews.map( (singleMultiview) => { return singleMultiview; @@ -192,6 +200,30 @@ export function ConfigureOutputModal({ ); }; + const findDuplicateValues = (data: MultiviewSettings[]) => { + const ports = data.map( + (item: MultiviewSettings) => + item.output.local_ip + ':' + item.output.local_port.toString() + ); + const duplicateIndices: number[] = []; + const seenPorts = new Set(); + + ports.forEach((port, index) => { + if (seenPorts.has(port)) { + duplicateIndices.push(index); + // Also include the first occurrence if it's not already included + const firstIndex = ports.indexOf(port); + if (!duplicateIndices.includes(firstIndex)) { + duplicateIndices.push(firstIndex); + } + } else { + seenPorts.add(port); + } + }); + + return duplicateIndices; + }; + const handleUpdateMultiview = ( multiview: MultiviewSettings, index: number @@ -199,6 +231,17 @@ export function ConfigureOutputModal({ const updatedMultiviews = multiviews.map((item, i) => i === index ? { ...item, ...multiview } : item ); + + const hasDuplicates = findDuplicateValues(updatedMultiviews); + + if (hasDuplicates.length > 0) { + setPortDuplicateIndexes(hasDuplicates); + } + + if (hasDuplicates.length === 0) { + setPortDuplicateIndexes([]); + } + setMultiviews(updatedMultiviews); }; @@ -245,6 +288,11 @@ export function ConfigureOutputModal({ handleUpdateMultiview={(input) => handleUpdateMultiview(input, index) } + portDuplicateError={ + portDuplicateIndexes.length > 0 + ? portDuplicateIndexes.includes(index) + : false + } />
void; onKeyDown?: (e: KeyboardEvent) => void; size?: 'small' | 'large'; + inputError?: boolean; } export default function Input({ @@ -15,8 +16,11 @@ export default function Input({ update, type = 'text', onKeyDown, - size = 'small' + size = 'small', + inputError }: IInput) { + const errorCss = 'border-red-500 focus:border-red-500 focus:outline'; + return (
@@ -27,7 +31,9 @@ export default function Input({ onChange={(e) => update(e.target.value)} className={`cursor-pointer border text-sm rounded-lg ${ size === 'small' ? 'w-6/12' : 'w-7/12' - } pl-2 pt-1 pb-1 bg-gray-700 border-gray-600 placeholder-gray-400 text-white focus:border-gray-400 focus:outline-none`} + } pl-2 pt-1 pb-1 bg-gray-700 border-gray-600 placeholder-gray-400 text-white focus:border-gray-400 focus:outline-none ${ + inputError ? errorCss : '' + }`} />
); diff --git a/src/components/modal/configureOutputModal/MultiviewSettings.tsx b/src/components/modal/configureOutputModal/MultiviewSettings.tsx index 0333700..e742005 100644 --- a/src/components/modal/configureOutputModal/MultiviewSettings.tsx +++ b/src/components/modal/configureOutputModal/MultiviewSettings.tsx @@ -10,11 +10,13 @@ import toast from 'react-hot-toast'; type MultiviewSettingsProps = { multiview?: MultiviewSettings; handleUpdateMultiview: (multiview: MultiviewSettings) => void; + portDuplicateError: boolean; }; export default function MultiviewSettingsConfig({ multiview, - handleUpdateMultiview + handleUpdateMultiview, + portDuplicateError }: MultiviewSettingsProps) { const t = useTranslate(); const [multiviewPresets, loading] = useMultiviewPresets(); @@ -183,6 +185,7 @@ export default function MultiviewSettingsConfig({ />