diff --git a/src/components/map-projects/MultiAlgoSelector.jsx b/src/components/map-projects/MultiAlgoSelector.jsx index bf9a930..f9c11ff 100644 --- a/src/components/map-projects/MultiAlgoSelector.jsx +++ b/src/components/map-projects/MultiAlgoSelector.jsx @@ -34,6 +34,7 @@ import orderBy from 'lodash/orderBy' import ConceptIcon from '../concepts/ConceptIcon' +import APIService from '../../services/APIService'; /** * MultiAlgoSelector (MUI5) @@ -78,6 +79,7 @@ export default function MultiAlgoSelector({ const { t } = useTranslation() const [expanded, setExpanded] = useState(() => new Map()); const [errors, setErrors] = React.useState({}) + const [customAlgoMeta, setCustomAlgoMeta] = React.useState({}) const normalizedValue = useMemo(() => { let changed = false; @@ -152,6 +154,7 @@ export default function MultiAlgoSelector({ const removeSelected = (key) => { const next = (value || []).filter((v) => v.__key !== key); onChange(next); + setCustomAlgoMeta(prev => omit(prev, [key])); setExpanded((prev) => { const n = new Map(prev); @@ -219,6 +222,68 @@ export default function MultiAlgoSelector({ return }; + + const setCustomAlgoState = (key, patch) => { + setCustomAlgoMeta(prev => ({...prev, [key]: {...prev[key], ...patch}})); + }; + + const verifyCustomAlgorithm = async (key, tokenOverride) => { + const selected = normalizedValue.find(v => v.__key === key); + if(!selected?.url) + return; + + const token = tokenOverride ?? selected?.token; + setCustomAlgoState(key, {isLoading: true, requestError: '', requestSuccess: '', tokenRequired: false}); + + const service = APIService.new(); + service.URL = selected.url; + + const response = await service.get(token || false, {}, undefined, true); + const status = response?.response?.status || response?.status; + + if([401, 403].includes(status)) { + setCustomAlgoState(key, { + isLoading: false, + tokenRequired: true, + requestError: '', + requestSuccess: '', + }); + return; + } + + if(response?.response || response?.detail || response?.message === 'Network Error' || typeof response === 'string') { + setCustomAlgoState(key, { + isLoading: false, + tokenRequired: false, + requestError: response?.response?.data?.detail || response?.detail || response?.message || response || t('unknown_error'), + requestSuccess: '', + }); + return; + } + + const data = response?.data || response; + if(!data?.name || !(data?.ID || data?.id)) { + setCustomAlgoState(key, { + isLoading: false, + tokenRequired: false, + requestError: t('unknown_error'), + requestSuccess: '', + }); + return; + } + + updateSelected(key, { + id: data.ID || data.id || '', + name: data.name || '', + description: data.description || '', + }); + setCustomAlgoState(key, { + isLoading: false, + tokenRequired: false, + requestError: '', + requestSuccess: t('common.saved'), + }); + }; return ( @@ -228,6 +293,7 @@ export default function MultiAlgoSelector({ const isOpen = expanded.get(sel.__key) ?? false; const hasErrors = errors[sel.__key]?.id || errors[sel.__key]?.name + const customMeta = customAlgoMeta[sel.__key] || {} return ( + + { + updateSelected(sel.__key, { url: e.target.value }); + if(customMeta.requestError || customMeta.requestSuccess || customMeta.tokenRequired) { + setCustomAlgoState(sel.__key, { + requestError: '', + requestSuccess: '', + tokenRequired: false, + }); + } + }} + onBlur={() => verifyCustomAlgorithm(sel.__key)} + placeholder="https://example.com/match" + error={Boolean(customMeta.requestError)} + helperText={customMeta.requestError || customMeta.requestSuccess || ''} + /> + { + updateSelected(sel.__key, { token: e.target.value }); + if(customMeta.requestError || customMeta.requestSuccess) { + setCustomAlgoState(sel.__key, { + requestError: '', + requestSuccess: '', + }); + } + }} + onBlur={() => { + if(sel.url && eHasValue(sel.token || '')) { + verifyCustomAlgorithm(sel.__key, sel.token); + } + }} + placeholder="••••••••" + error={Boolean(customMeta.tokenRequired && !sel.token)} + helperText={customMeta.tokenRequired && !sel.token ? 'Authentication is required for this algorithm.' : ''} + /> - - updateSelected(sel.__key, { id: e.target.value || '' }) + updateSelected(sel.__key, { description: e.target.value || '' }) } /> - - - updateSelected(sel.__key, { url: e.target.value })} - placeholder="https://example.com/match" - /> - updateSelected(sel.__key, { token: e.target.value })} - placeholder="••••••••" - /> -