Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
41057bf
OpenConceptLab/ocl_issues#2337 | PR2b: read-side flip + ensureLoaded …
paynejd May 11, 2026
d7180d7
OpenConceptLab/ocl_issues#2337 | PR2b review feedback: correctness + …
paynejd May 12, 2026
2d96c09
OpenConceptLab/ocl_issues#2337 | PR2b: fixes for engineer review feed…
paynejd May 12, 2026
104a7c9
OpenConceptLab/ocl_issues#2337 | PR2b: round 2 of engineer review fixes
paynejd May 12, 2026
fdc60b8
OpenConceptLab/ocl_issues#2337 | PR2b: helper text decoding + bridge …
paynejd May 12, 2026
9fcdbb2
OpenConceptLab/ocl_issues#2337 | PR2b: drop score*100 fallback in uni…
paynejd May 12, 2026
b0e8d52
OpenConceptLab/ocl_issues#2337 | PR2b: stop re-running scispacy on ta…
paynejd May 12, 2026
f29a801
OpenConceptLab/ocl_issues#2337 | PR2b: restore unified-score chip on …
paynejd May 12, 2026
832edc1
OpenConceptLab/ocl_issues#2337 | PR2b: stop synthesizing rerank_score…
paynejd May 12, 2026
4b019fd
OpenConceptLab/ocl_issues#2337 | PR2b: fix Sort toolbar + sort bridge…
paynejd May 12, 2026
571a12b
OpenConceptLab/ocl_issues#2337 | PR2b: bridge framing in Quality view
paynejd May 12, 2026
8b41e72
OpenConceptLab/ocl_issues#2337 | PR2b: capture schema-specific proper…
paynejd May 12, 2026
0f122e5
OpenConceptLab/ocl_issues#2337 | PR2b: ignore per-algo search_normali…
paynejd May 12, 2026
0ae57dd
OpenConceptLab/ocl_issues#2337 | PR2b: rerank only ConceptRows that l…
paynejd May 12, 2026
6697c52
OpenConceptLab/ocl_issues#2337 | PR2b: align fetchAllCandidatesForRow…
paynejd May 12, 2026
ef22c18
OpenConceptLab/ocl_issues#2337 | PR2b: onDecisionTabChange typo + in-…
paynejd May 12, 2026
eb5e3d6
OpenConceptLab/ocl_issues#2337 | PR2b: fix auto-match regression afte…
paynejd May 12, 2026
22eaa6a
OpenConceptLab/ocl_issues#2337 | PR2b: compact map-type chip + algo-v…
paynejd May 12, 2026
1cd8aee
OpenConceptLab/ocl_issues#2337 | PR2b: Unranked Candidates bucket in …
paynejd May 12, 2026
45416ea
OpenConceptLab/ocl_issues#2337 | PR2b: re-normalize legacy candidates…
paynejd May 12, 2026
a7d827c
OpenConceptLab/ocl_issues#2337 | PR2b: three small follow-ups from ga…
paynejd May 12, 2026
e2ccf71
OpenConceptLab/ocl_issues#2337 | PR2b: round 4 of engineer review fixes
paynejd May 12, 2026
48dc6b5
OpenConceptLab/ocl_issues#2337 | PR2b: round 5 of engineer review fixes
paynejd May 12, 2026
0e5805e
OpenConceptLab/ocl_issues#2337 | PR2b: round 6 of engineer review fixes
paynejd May 12, 2026
f0681c4
OpenConceptLab/ocl_issues#2337 | PR2b: revert bridge_child indent att…
paynejd May 12, 2026
aecbebc
OpenConceptLab/ocl_issues#2337 | fixing score on top
snyaggarwal May 13, 2026
0993ffb
OpenConceptLab/ocl_issues#2337 | removed unused
snyaggarwal May 13, 2026
61ef1e9
OpenConceptLab/ocl_issues#2337 | removed hardcoded fallback text
snyaggarwal May 13, 2026
5f31a96
OpenConceptLab/ocl_issues#2337 | fixing lookup config and advanced se…
snyaggarwal May 13, 2026
2a8d86d
Merge branch 'main' into issues#2337-pr2b
snyaggarwal May 13, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/common/colors.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ export const VERY_LIGHT_GRAY = '#5e5c71'
export const RECOMMEND_COLOR = 'rgb(172,212,182)'
export const AVAILABLE_COLOR = 'rgb(250,224,148)'
export const UNRANKED_COLOR = 'rgb(235, 162, 150)'
// Neutral gray for candidates that haven't been ranked yet (rerank pending).
// Distinct from UNRANKED_COLOR (which is misnamed historically — it's the
// pink used for the low-ranked / not-recommended bucket).
export const PENDING_RERANK_COLOR = 'rgb(189, 189, 189)'
export const PRIMARY_COLORS = {
main: '#4836ff',
light: '#4836ff',
Expand Down
40 changes: 40 additions & 0 deletions src/components/map-projects/AdvancedSettings.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import React from 'react'
import { useTranslation } from 'react-i18next'
import TextField from '@mui/material/TextField'
import Collapse from '@mui/material/Collapse'
import Button from '@mui/material/Button'
import UpIcon from '@mui/icons-material/ArrowDropUp';
import DownIcon from '@mui/icons-material/ArrowDropDown';


const AdvancedSettings = ({ namespaceValue, setNamespace, defaultNamespace }) => {
const { t } = useTranslation()
const [open, setOpen] = React.useState(false)

return (
<div className='col-xs-12 padding-0' style={{marginBottom: '16px', marginTop: '4px'}}>
<Button size='small' variant='text' color={open ? 'primary' : 'secondary'} endIcon={open ? <UpIcon fontSize='inherit' /> : <DownIcon fontSize='inherit' />} onClick={() => setOpen(!open)} sx={{textTransform: 'none'}}>
{t('map_project.advanced_settings')}
</Button>
<Collapse in={open}>
<div className='col-xs-12 padding-0' style={{marginTop: '4px'}}>
<TextField
fullWidth
size='small'
sx={{marginTop: '4px'}}
label={t('map_project.resolution_namespace', 'Resolution Namespace')}
value={namespaceValue}
onChange={event => setNamespace(event.target.value || '')}
placeholder={defaultNamespace}
helperText={t('map_project.resolution_namespace_description', {
owner: defaultNamespace || 'the project owner',
defaultValue: 'Namespace passed to $resolveReference. When blank, defaults to {{owner}}. Drives which URL Registry entries apply when resolving canonical URLs.'
})}
/>
</div>
</Collapse>
</div>
)
}

export default AdvancedSettings;
339 changes: 231 additions & 108 deletions src/components/map-projects/Candidates.jsx

Large diffs are not rendered by default.

415 changes: 270 additions & 145 deletions src/components/map-projects/Concept.jsx

Large diffs are not rendered by default.

127 changes: 124 additions & 3 deletions src/components/map-projects/ConfigurationForm.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,17 @@ import SettingsIcon from '@mui/icons-material/Settings';
import SaveIcon from '@mui/icons-material/Save';
import OpenInNewIcon from '@mui/icons-material/OpenInNew';

import Stack from '@mui/material/Stack'
import Alert from '@mui/material/Alert'
import Tooltip from '@mui/material/Tooltip'
import InfoOutlinedIcon from '@mui/icons-material/InfoOutlined'

import isEmpty from 'lodash/isEmpty'
import omit from 'lodash/omit'
import filter from 'lodash/filter'

import { toV3URL } from '../../common/utils'
import { getProjectConfigErrors } from './algorithms'
import NamespaceDropdown from '../common/NamespaceDropdown'
import RepoSearchAutocomplete from '../repos/RepoSearchAutocomplete'
import RepoVersionSearchAutocomplete from '../repos/RepoVersionSearchAutocomplete'
Expand All @@ -32,6 +39,7 @@ import { SCORES_COLOR } from './constants'
import FilterTable from './FilterTable'
import MultiAlgoSelector from './MultiAlgoSelector'
import LookupConfig from './LookupConfig'
import AdvancedSettings from './AdvancedSettings'
import RerankerConfig from './RerankerConfig'
import AIAssistantSelectorPanel from './AIAssistantSelectorPanel'

Expand All @@ -48,10 +56,24 @@ const VisuallyHiddenInput = styled('input')({
});


const ConfigurationForm = ({ project, handleFileUpload, file, owner, setOwner, name, setName, description, setDescription, repo, onRepoChange, repoVersion, setRepoVersion, versions, mappedSources, targetSourcesFromRows, algosSelected, setAlgosSelected, sx, algos, validColumns, columns, isValidColumnValue, updateColumn, configure, setConfigure, columnVisibilityModel, setColumnVisibilityModel, onSave, isSaving, candidatesScore, onScoreChange, includeDefaultFilter, setIncludeDefaultFilter, filters, setFilters, locales, isLoadingLocales, setAIAssistantColumns, AIAssistantColumns, inAIAssistantGroup, lookupConfig, setLookupConfig, encoderModel, setEncoderModel, isCoreUser, canBridge, canScispacy, promptTemplates, promptTemplate, onPromptTemplateChange, AIModels, AIModel, setAIModel }) => {
const deriveCanonicalUrl = relativeUrl => relativeUrl ? `https://ns.openconceptlab.org${relativeUrl}` : ''

const ConfigurationForm = ({ project, handleFileUpload, file, owner, setOwner, name, setName, description, setDescription, repo, onRepoChange, repoVersion, setRepoVersion, versions, mappedSources, targetSourcesFromRows, algosSelected, setAlgosSelected, sx, algos, validColumns, columns, isValidColumnValue, updateColumn, configure, setConfigure, columnVisibilityModel, setColumnVisibilityModel, onSave, isSaving, candidatesScore, onScoreChange, includeDefaultFilter, setIncludeDefaultFilter, filters, setFilters, locales, isLoadingLocales, setAIAssistantColumns, AIAssistantColumns, inAIAssistantGroup, lookupConfig, setLookupConfig, encoderModel, setEncoderModel, isCoreUser, canBridge, canScispacy, promptTemplates, promptTemplate, onPromptTemplateChange, AIModels, AIModel, setAIModel, namespace, setNamespace }) => {
const { t } = useTranslation();
const isLLMAlgoNotAllowed = !repoVersion?.match_algorithms?.includes('llm')
const appliedLocales = filters?.locale ? filters?.locale?.split(',') : []
const targetCanonicalFromRepo = repo?.canonical_url
const targetCanonicalDerived = !targetCanonicalFromRepo && repo?.url ? deriveCanonicalUrl(repo.url) : ''
const effectiveTargetCanonical = targetCanonicalFromRepo || targetCanonicalDerived
const bridgeAlgos = filter(algosSelected || [], a => a?.type && a.type.includes('bridge'))
const defaultNamespace = owner || ''
const namespaceValue = namespace || ''

// Project-config validation. Currently flags custom algos with missing /
// malformed canonical_url. Returned as a structured list so the banner
// can name the specific algorithms.
const configErrors = getProjectConfigErrors(algosSelected)
const hasConfigErrors = configErrors.length > 0
const getAlgos = () => {
return algos.map(algo => {
if(algo.type === 'ocl-semantic')
Expand Down Expand Up @@ -151,6 +173,79 @@ const ConfigurationForm = ({ project, handleFileUpload, file, owner, setOwner, n

<RepoSearchAutocomplete label={t('map_project.repository')} size='small' onChange={(id, item) => onRepoChange(item)} value={repo} sx={{marginTop: '12px'}}/>
<RepoVersionSearchAutocomplete versions={versions} label={t('common.version')} size='small' onChange={(id, item) => setRepoVersion(item)} value={repoVersion} sx={{marginTop: '12px'}} />
{
effectiveTargetCanonical &&
<Stack direction='row' spacing={0.75} alignItems='center' sx={{marginTop: '6px', marginLeft: '8px', minWidth: 0}}>
<InfoOutlinedIcon sx={{fontSize: '14px', color: 'text.secondary', flexShrink: 0}} />
<Typography component='span' sx={{fontSize: '12px', color: 'text.secondary', flexShrink: 0}}>
{t('map_project.target_canonical_url', 'Canonical:')}
</Typography>
<Tooltip title={effectiveTargetCanonical} placement='top'>
<Typography
component='code'
sx={{
fontSize: '12px',
fontFamily: 'monospace',
color: 'text.primary',
overflow: 'hidden',
textOverflow: 'ellipsis',
whiteSpace: 'nowrap',
minWidth: 0
}}
>
{effectiveTargetCanonical}
</Typography>
</Tooltip>
{
!targetCanonicalFromRepo &&
<Typography component='span' sx={{fontSize: '11px', color: 'text.secondary', fontStyle: 'italic', flexShrink: 0}}>
· {t('map_project.canonical_auto_derived_short', 'derived')}
</Typography>
}
</Stack>
}
{
bridgeAlgos.length > 0 &&
<Stack spacing={0.25} sx={{marginTop: '4px', marginLeft: '8px', minWidth: 0}}>
{
bridgeAlgos.map(b => {
const bridgeCanonical = b?.bridge_repo?.canonical_url || deriveCanonicalUrl(b?.target_repo_url)
const isDerived = !b?.bridge_repo?.canonical_url
const tooltipText = `${b.target_repo_url || ''} → ${bridgeCanonical || ''}`
return (
<Stack key={b.__key || b.id} direction='row' spacing={0.75} alignItems='center' sx={{minWidth: 0}}>
<InfoOutlinedIcon sx={{fontSize: '14px', color: 'text.secondary', flexShrink: 0}} />
<Typography component='span' sx={{fontSize: '12px', color: 'text.secondary', flexShrink: 0}}>
{t('map_project.bridge_canonical_short', 'Bridge:')}
</Typography>
<Tooltip title={tooltipText} placement='top'>
<Typography
component='code'
sx={{
fontSize: '12px',
fontFamily: 'monospace',
color: 'text.primary',
overflow: 'hidden',
textOverflow: 'ellipsis',
whiteSpace: 'nowrap',
minWidth: 0
}}
>
{b.target_repo_url || '—'} → {bridgeCanonical}
</Typography>
</Tooltip>
{
isDerived &&
<Typography component='span' sx={{fontSize: '11px', color: 'text.secondary', fontStyle: 'italic', flexShrink: 0}}>
· {t('map_project.canonical_auto_derived_short', 'derived')}
</Typography>
}
</Stack>
)
})
}
</Stack>
}
{
isLLMAlgoNotAllowed && repoVersion?.version_url &&
<FormHelperText sx={{marginTop: '4px', marginLeft: '8px', color: 'warning.main'}}>
Expand Down Expand Up @@ -211,7 +306,10 @@ const ConfigurationForm = ({ project, handleFileUpload, file, owner, setOwner, n
}

<LookupConfig value={lookupConfig} onChange={setLookupConfig}/>

{
setNamespace &&
<AdvancedSettings namespaceValue={namespaceValue} setNamespace={setNamespace} defaultNamespace={defaultNamespace} />
}
{
inAIAssistantGroup && isCoreUser && promptTemplates?.length > 0 &&
<>
Expand Down Expand Up @@ -295,6 +393,29 @@ const ConfigurationForm = ({ project, handleFileUpload, file, owner, setOwner, n
/>
</>
}
{
hasConfigErrors &&
<Alert severity='error' sx={{marginTop: '16px'}}>
<Typography component='div' sx={{fontSize: '13px', fontWeight: 500, marginBottom: '4px'}}>
{t('map_project.config_errors_title', 'Project configuration is incomplete')}
</Typography>
<ul style={{margin: 0, paddingLeft: '20px', fontSize: '12px'}}>
{
configErrors.map(({algo, reason}) => (
<li key={algo.__key || algo.id}>
{reason === 'missing_canonical_url'
? t('map_project.config_error_missing_canonical', {
name: algo.name || algo.id,
defaultValue: `Custom algorithm "${algo.name || algo.id}" is missing a valid canonical URL.`
})
: reason
}
</li>
))
}
</ul>
</Alert>
}
<div className='col-xs-12 padding-0' style={{textAlign: 'right'}}>
<Button
variant='contained'
Expand All @@ -303,7 +424,7 @@ const ConfigurationForm = ({ project, handleFileUpload, file, owner, setOwner, n
sx={{textTransform: 'none', margin: '20px 5px 5px 0px'}}
startIcon={<SaveIcon />}
onClick={onSave}
disabled={!name || !file?.name || !owner}
disabled={!name || !file?.name || !owner || hasConfigErrors}
loading={isSaving}
loadingPosition="start"
>
Expand Down
Loading