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="••••••••"
- />
-