Skip to content

Commit cca8501

Browse files
committed
OpenConceptLab/ocl_issues#1949 | Copied references view
1 parent 75e2a6b commit cca8501

7 files changed

Lines changed: 127 additions & 10 deletions

File tree

src/components/app/App.jsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ const App = props => {
117117

118118

119119

120-
const repoTabs = ['concepts', 'mappings', 'versions', 'summary', 'about']
120+
const repoTabs = ['concepts', 'mappings', 'versions', 'summary', 'about', 'references']
121121
const orgTabs = ['repos']
122122
const repoTabsStr = repoTabs.join('|')
123123
const orgTabsStr = orgTabs.join('|')
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import React from 'react';
2+
import { Chip } from '@mui/material';
3+
import {
4+
LocalOffer as LocalOfferIcon, Link as LinkIcon,
5+
} from '@mui/icons-material';
6+
import { toFullAPIURL, copyURL } from '../../common/utils';
7+
8+
const ReferenceChip = props => {
9+
const isReference = !props.notReference
10+
const isResolved = Boolean(props.last_resolved_at)
11+
const type = props.reference_type;
12+
const expression = isResolved ? props.expression : `${props.expression} (unresolved)`;
13+
let icon = <span />;
14+
if(type && type.toLowerCase() === 'mappings')
15+
icon = <LinkIcon fontSize="small" />;
16+
else if(type && type.toLowerCase() === 'concepts')
17+
icon = <LocalOfferIcon fontSize='small' color='primary' />;
18+
19+
const chip = <Chip
20+
className='clickable'
21+
icon={icon}
22+
label={expression}
23+
variant='outlined'
24+
color='primary'
25+
style={{border: 'none'}}
26+
/>
27+
return (
28+
<span>
29+
<a href={toFullAPIURL(props.uri)} target='_blank' rel='noopener noreferrer'>
30+
{chip}
31+
</a>
32+
{
33+
isReference && (
34+
props.include ?
35+
<Chip size='small' variant='outlined' color='success' label='include' /> :
36+
<Chip size='small' variant='outlined' color='error' label='exclude' />
37+
)
38+
}
39+
{
40+
isReference &&
41+
<Chip size='small' color='primary' variant='outlined' label='copy expression' onClick={() => copyURL(toFullAPIURL(props.expression))} style={{marginLeft: '5px'}} />
42+
43+
}
44+
</span>
45+
)
46+
}
47+
48+
export default ReferenceChip;
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import React from 'react';
2+
import { Chip } from '@mui/material';
3+
import {
4+
LocalOffer as LocalOfferIcon, Link as LinkIcon,
5+
} from '@mui/icons-material';
6+
import { toFullAPIURL, copyURL } from '../../common/utils';
7+
8+
const ReferenceTranslation = props => {
9+
const isReference = !props.notReference
10+
const isResolved = Boolean(props.last_resolved_at)
11+
const type = props.reference_type;
12+
const expression = isResolved ? props.translation : `${props.translation} (unresolved)`;
13+
let icon = <span />;
14+
if(type && type.toLowerCase() === 'mappings')
15+
icon = <LinkIcon fontSize="small" />;
16+
else if(type && type.toLowerCase() === 'concepts')
17+
icon = <LocalOfferIcon fontSize='small' color='primary' />;
18+
19+
const chip = <Chip
20+
className='clickable'
21+
icon={icon}
22+
label={expression}
23+
variant='outlined'
24+
color='primary'
25+
style={{border: 'none'}}
26+
classes={{label: 'chip-label-wrapped'}}
27+
/>
28+
return (
29+
<span style={{display: 'flex', alignItems: 'center'}}>
30+
<a href={toFullAPIURL(props.uri)} target='_blank' rel='noopener noreferrer'>
31+
{chip}
32+
</a>
33+
{
34+
isReference &&
35+
<Chip size='small' color='primary' variant='outlined' label='copy expression' onClick={() => copyURL(toFullAPIURL(props.expression))} style={{marginLeft: '5px'}} />
36+
37+
}
38+
</span>
39+
)
40+
}
41+
42+
export default ReferenceTranslation;

src/components/repos/RepoHome.jsx

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,9 @@ const RepoHome = () => {
3333
{key: 'concepts', label: t('concept.concepts')},
3434
{key: 'mappings', label: t('mapping.mappings')},
3535
]
36-
const TAB_KEYS = TABS.map(tab => tab.key)
37-
const findTab = () => TAB_KEYS.includes(params?.tab || params?.repoVersion) ? params.tab || params.repoVersion : 'concepts'
38-
const versionFromURL = (TAB_KEYS.includes(params?.repoVersion) ? '' : params.repoVersion) || ''
39-
const [tab, setTab] = React.useState(findTab)
36+
const isCollection = params.repoType === 'collections'
37+
38+
const [tabs, setTabs] = React.useState(isCollection ? [...TABS, {key: 'references', label: t('reference.references')}] : [...TABS])
4039
const [status, setStatus] = React.useState(false)
4140
const [repo, setRepo] = React.useState(false)
4241
const [owner, setOwner] = React.useState(false)
@@ -51,6 +50,11 @@ const RepoHome = () => {
5150
const [releaseVersion, setReleaseVersion] = React.useState(false)
5251
const [showSummary, setShowSummary] = React.useState(true)
5352

53+
const TAB_KEYS = tabs.map(tab => tab.key)
54+
const findTab = () => TAB_KEYS.includes(params?.tab || params?.repoVersion) ? params.tab || params.repoVersion : 'concepts'
55+
const versionFromURL = (TAB_KEYS.includes(params?.repoVersion) ? '' : params.repoVersion) || ''
56+
57+
const [tab, setTab] = React.useState(findTab)
5458
const { setAlert } = React.useContext(OperationsContext);
5559

5660
const getURL = () => ((toParentURI(location.pathname) + '/').replace('//', '/') + versionFromURL + '/').replace('//', '/')
@@ -65,6 +69,11 @@ const RepoHome = () => {
6569
setRepo(_repo)
6670
fetchOwner()
6771
fetchRepoSummary()
72+
if(isCollection)
73+
setTabs([...TABS, {key: 'references', label: t('reference.references')}])
74+
else
75+
setTabs([...TABS])
76+
6877
if(isConceptURL || isMappingURL)
6978
setShowItem(true)
7079
})
@@ -101,6 +110,8 @@ const RepoHome = () => {
101110
setTab('concepts')
102111
if(location.pathname.includes('/mappings'))
103112
setTab('mappings')
113+
if(location.pathname.includes('/references'))
114+
setTab('references')
104115
}
105116
fetchRepo()
106117
fetchVersions()
@@ -112,7 +123,7 @@ const RepoHome = () => {
112123
let url = version.version_url
113124
if(reload && version?.version === 'HEAD')
114125
url += 'HEAD/'
115-
history.push(url + tab)
126+
history.push(url + (tab || 'concepts'))
116127
}
117128

118129
const onTabChange = (event, newTab) => {
@@ -204,11 +215,14 @@ const RepoHome = () => {
204215

205216
const isConceptURL = tab === 'concepts'
206217
const isMappingURL = tab === 'mappings'
218+
const isReferenceURL = tab === 'references'
207219
const getConceptURLFromMainURL = () => (isConceptURL && params.resource) ? getURL() + 'concepts/' + params.resource + '/' : false
208220
const getMappingURLFromMainURL = () => (isMappingURL && params.resource) ? getURL() + 'mappings/' + params.resource + '/' : false
221+
const getReferenceURLFromMainURL = () => (isReferenceURL && params.resource) ? getURL() + 'references/' + params.resource + '/' : false
209222
const showConceptURL = ((showItem?.concept_class || params.resource) && isConceptURL) ? showItem?.version_url || showItem?.url || getConceptURLFromMainURL() : false
210223
const showMappingURL = ((showItem?.map_type || params.resource) && isMappingURL) ? showItem?.version_url || showItem?.url || getMappingURLFromMainURL() : false
211-
const isSplitView = conceptForm || mappingForm || showConceptURL || showMappingURL || versionForm
224+
const showReferenceURL = ((showItem?.expression || params.resource) && isReferenceURL) ? showItem?.version_url || showItem?.url || getReferenceURLFromMainURL() : false
225+
const isSplitView = conceptForm || mappingForm || showConceptURL || showMappingURL || showReferenceURL || versionForm
212226

213227
const onVersionEditClick = () => isVersion && setVersionForm(true)
214228
const onReleaseVersionClick = () => isVersion && setReleaseVersion(true)
@@ -233,9 +247,9 @@ const RepoHome = () => {
233247
onReleaseVersionClick={() => onReleaseVersionClick()}
234248
/>
235249
<div className='padding-0 col-xs-12' style={{width: isSplitView ? '100%' : (showSummary ? 'calc(100% - 272px)' : 'calc(100% - 12px)')}}>
236-
<CommonTabs TABS={TABS} value={tab} onChange={onTabChange} />
250+
<CommonTabs TABS={tabs} value={tab} onChange={onTabChange} />
237251
{
238-
repo?.id && ['concepts', 'mappings'].includes(tab) &&
252+
repo?.id && ['concepts', 'mappings', 'references'].includes(tab) &&
239253
<Search
240254
loading={loading}
241255
summary={repoSummary || repo?.summary}

src/components/search/ResultConstants.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ import OwnerIcon from '../common/OwnerIcon';
99
import RepoVersionButton from '../repos/RepoVersionButton';
1010
import FromAndTargetSource from '../mappings/FromAndTargetSource'
1111
import ConceptCell from '../mappings/ConceptCell'
12+
import ReferenceChip from '../common/ReferenceChip';
13+
import ReferenceTranslation from '../common/ReferenceTranslation';
14+
1215

1316
const getLocale = (concept, synonym) => {
1417
let cleaned = synonym.replaceAll('<em>', '').replaceAll('</em>', '')
@@ -48,6 +51,11 @@ export const ALL_COLUMNS = {
4851
{id: 'mapType', labelKey: 'mapping.map_type', value: 'map_type', sortable: true},
4952
{id: 'toConcept', labelKey: 'mapping.toConcept', value: 'toConceptCode', className: 'searchable', sortable: false, renderer: item => <ConceptCell mapping={item} direction='to' />},
5053
],
54+
references: [
55+
{id: 'expression', labelKey: 'reference.reference', value: 'expression', sortable: false, translation: true, renderer: (reference, translation) => translation ? <ReferenceTranslation {...reference} /> : <ReferenceChip {...reference} />},
56+
{id: 'concepts', labelKey: 'concept.concepts', value: 'concepts', sortable: false, align: 'center', renderer: reference => reference.last_resolved_at ? <ReferenceChip uri={reference.uri + 'concepts/'} reference_type='concepts' last_resolved_at expression={reference.concepts} notReference /> : '-'},
57+
{id: 'mappings', labelKey: 'mapping.mappings', value: 'mappings', sortable: false, align: 'center', renderer: reference => reference.last_resolved_at ? <ReferenceChip uri={reference.uri + 'mappings/'} reference_type='mappings' last_resolved_at expression={reference.mappings} notReference /> : '-'}
58+
],
5159
repos: [
5260
{id: 'id', labelKey: 'common.id', value: 'id', sortOn: 'id', className: 'searchable'},
5361
{id: 'name', labelKey: 'common.name', value: 'name', sortOn: 'name', className: 'searchable'},

src/components/search/Search.jsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -235,7 +235,7 @@ const Search = props => {
235235
setResult(prev => {
236236
return {...prev, [__resource]: {...result[__resource], results: []}}
237237
})
238-
if(['users', 'orgs'].includes(__resource))
238+
if(['users', 'orgs', 'references'].includes(__resource))
239239
params.verbose = true
240240
APIService.new().overrideURL(getURL(__resource)).get(null, null, params).then(response => {
241241
if(response?.detail) {

src/i18n/locales/en/translations.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,10 @@
241241
"fromAndTargetSource": "From and target Source",
242242
"edit_mapping": "Edit Mapping"
243243
},
244+
"reference": {
245+
"references": "References",
246+
"reference": "Reference"
247+
},
244248
"checksums": {
245249
"standard": "Standard Checksum",
246250
"smart": "Smart Checksum"
@@ -403,6 +407,7 @@
403407
"filters": "Filters",
404408
"concepts": "Concepts",
405409
"mappings": "Mappings",
410+
"references": "References",
406411
"repos": "Repositories",
407412
"orgs": "Organizations",
408413
"users": "Users",

0 commit comments

Comments
 (0)