diff --git a/src/components/BreadCrumbs/index.js b/src/components/BreadCrumbs/index.js index 8d93d3830..260f08230 100644 --- a/src/components/BreadCrumbs/index.js +++ b/src/components/BreadCrumbs/index.js @@ -55,10 +55,7 @@ const locationType = T.shape({ other: T.arrayOf(T.string), }); const BreadCrumb = ( - { - to, - children, - } /*: { + { to, children } /*: { children: any, to?: function | {description: Object}} */, ) => { @@ -107,7 +104,8 @@ const BreadCrumbsForSearchOrResult = ( { location } /*: {location: Location} */, ) => { if (!['search', 'result'].includes(location?.main?.key)) return null; - const key /*: 'search' | 'result' */ = (location.main.key /*: any */); + //$FlowFixMe[incompatible-type] + const key /*: 'search' | 'result' */ = location.main.key; const { type, value, accession } = location[key]; return ( <> @@ -224,10 +222,12 @@ BreadCrumbForEntityDetail.propTypes = { const BreadCrumbForSecondPart = ({ location } /*: {location: Location} */) => { const { accession, detail } = location[location.main.key]; const filters = Object.keys(location) - .filter((ep) => (location[ep] /*: any */)?.isFilter) + //$FlowFixMe[prop-missing] + .filter((ep) => location[ep]?.isFilter) .sort( (ep1, ep2) => - (location[ep1] /*: any */)?.order - (location[ep2] /*: any */).order, + //$FlowFixMe[prop-missing] + location[ep1]?.order - location[ep2].order, ); return (
@@ -266,7 +266,10 @@ const BreadCrumbsForBrowse = ({ location } /*: {location: Location} */) => { description: { main: { key: endpoint }, [endpoint]: { db } }, }} > - By {endpoint}{' '} + By{' '} + {db && db.toLowerCase() === 'pfam' && endpoint.toLowerCase() === 'set' + ? 'clan' + : endpoint}{' '} should render 1`] = ` } } isFirstLevel={true} - name="By Set" + name="By Clan/Set" to={[Function]} /> diff --git a/src/components/Description/DescriptionFromIntegrated/index.tsx b/src/components/Description/DescriptionFromIntegrated/index.tsx index 68c9da01a..b6a30f93b 100644 --- a/src/components/Description/DescriptionFromIntegrated/index.tsx +++ b/src/components/Description/DescriptionFromIntegrated/index.tsx @@ -25,7 +25,7 @@ const css = cssBinder(ipro, local, fonts); const ImportedTag = ({ accession }: { accession: string }) => { return ( @@ -57,6 +57,7 @@ const ImportedTag = ({ accession }: { accession: string }) => { type Props = { integrated: string | null; setIntegratedCitations?: (citations: string[]) => void; + headerText?: string; }; interface IntegratedProps @@ -67,6 +68,7 @@ const DescriptionFromIntegrated = ({ integrated, data, setIntegratedCitations = (_: string[]) => null, + headerText, }: IntegratedProps) => { const { loading, payload } = data || {}; useEffect(() => { @@ -87,7 +89,7 @@ const DescriptionFromIntegrated = ({ return ( <>

- Description + {headerText || 'Description'}

should render 1`] = ` + +
+
+
+ + +

+ This description has been automatically generated using + + + GPT-4 + + , an AI language model, and is based on data extracted from + + + UniProtKB/Swiss-Prot + + . It has not undergone a thorough review by curators. Please exercise discretion when interpreting the information provided and consider it as preliminary. +
+ + Read more on description generation + +

+
+
+
+ The function of the family is not clear.

", + ] + } + /> +
+`; diff --git a/src/components/Description/DescriptionLLM/index.tsx b/src/components/Description/DescriptionLLM/index.tsx new file mode 100644 index 000000000..8e5004cab --- /dev/null +++ b/src/components/Description/DescriptionLLM/index.tsx @@ -0,0 +1,75 @@ +import React, { PureComponent } from 'react'; + +import cssBinder from 'styles/cssBinder'; +import globalStyles from 'styles/interpro-vf.css'; +import fonts from 'EBI-Icon-fonts/fonts.css'; +import Link from 'components/generic/Link'; + +import Description from '..'; +import config from 'config'; + +const css = cssBinder(globalStyles, fonts); + +type Props = { + text: string; +}; + +class DescriptionLLM extends PureComponent { + render() { + const text = this.props.text || ''; + if (text.length === 0) return null; + + return ( + <> +
+
+
+ {' '} +

+ This description has been automatically generated using{' '} + + GPT-4 + + , an AI language model, and is based on data extracted from{' '} + + UniProtKB/Swiss-Prot + + . It has not undergone a thorough review by curators. Please + exercise discretion when interpreting the information provided + and consider it as preliminary. +
+ + Read more on description generation + +

+
+
+
+ + + ); + } +} + +export default DescriptionLLM; diff --git a/src/components/Description/DescriptionLLM/test.js b/src/components/Description/DescriptionLLM/test.js new file mode 100644 index 000000000..5e5cbcace --- /dev/null +++ b/src/components/Description/DescriptionLLM/test.js @@ -0,0 +1,14 @@ +import React from 'react'; +import ShallowRenderer from 'react-test-renderer/shallow'; + +import DescriptionLLM from '.'; + +const renderer = new ShallowRenderer(); +const description = '

The function of the family is not clear.

'; + +describe('', () => { + test('should render', () => { + renderer.render(); + expect(renderer.getRenderOutput()).toMatchSnapshot(); + }); +}); diff --git a/src/components/Entry/RemovedEntrySummary/index.js b/src/components/Entry/RemovedEntrySummary/index.js index c56e50a58..2e656bc16 100644 --- a/src/components/Entry/RemovedEntrySummary/index.js +++ b/src/components/Entry/RemovedEntrySummary/index.js @@ -11,28 +11,47 @@ import ebiGlobalStyles from 'ebi-framework/css/ebi-global.css'; const f = foundationPartial(ebiGlobalStyles, fonts); -const RemovedEntrySummary = ({ detail, accession, date, history, dbInfo }) => { +const RemovedEntrySummary = ({ + accession, + source_database, + type, + name, + short_name, + deletion_date, + history, + dbInfo, +}) => { + const allNames = (history?.names || []).concat(history?.short_names || []); + const formerNames = allNames.filter((n) => n !== name && n !== short_name); + const listWrap = (n) => `
  • ${n}
  • `; const metadata = { accession: accession.toUpperCase(), - name: { name: history?.names?.[0] || '???' }, - source_database: 'Removed', - type: 'unknown', + name: { + name: name, + short: short_name, + }, + source_database: source_database, + type: type, member_databases: history?.signatures, - description: [ - `Removed: ${date}`, - 'Used names:', - ...(history?.names || []).map((n) => ` * ${n}`), - ], + description: + formerNames.length !== 0 + ? [`
      ${formerNames.map(listWrap).join('')}
    `] + : [], + is_removed: true, }; - const regex = /ipr[0-9]{6}/gi; - const detailF = (detail || '').replace(regex, accession.toUpperCase()); + const date = new Date(deletion_date).toLocaleDateString('en-GB', { + month: 'long', + year: 'numeric', + }); + const message = `${metadata.accession} is obsolete since ${date}.`; return (
    - + <SummaryEntry - data={{ metadata: { ...metadata, source_database: 'interpro' } }} + data={{ metadata: metadata }} + headerText={'Former names'} loading={false} dbInfo={dbInfo} /> @@ -42,12 +61,16 @@ const RemovedEntrySummary = ({ detail, accession, date, history, dbInfo }) => { }; RemovedEntrySummary.propTypes = { - detail: T.string, accession: T.string, - date: T.string, + source_database: T.string, + type: T.string, + name: T.string, + short_name: T.string, + deletion_date: T.string, history: T.shape({ - signatures: T.arrayOf(T.object), names: T.arrayOf(T.string), + short_names: T.arrayOf(T.string), + signatures: T.object, }), dbInfo: T.object, }; diff --git a/src/components/Entry/Summary/MemberDBSubtitle/index.tsx b/src/components/Entry/Summary/MemberDBSubtitle/index.tsx index 916c67538..db8e318af 100644 --- a/src/components/Entry/Summary/MemberDBSubtitle/index.tsx +++ b/src/components/Entry/Summary/MemberDBSubtitle/index.tsx @@ -70,7 +70,11 @@ const MemberDBSubtitle = ({ )} {metadata?.counters?.sets ? ( <tr> - <td>Set</td> + <td> + {metadata.source_database.toLowerCase() === 'pfam' + ? 'Clan' + : 'Set'} + </td> <td> {metadata.set_info ? ( <Link diff --git a/src/components/Entry/Summary/SidePanel/index.tsx b/src/components/Entry/Summary/SidePanel/index.tsx index ab8e60cf0..cfd724a1d 100644 --- a/src/components/Entry/Summary/SidePanel/index.tsx +++ b/src/components/Entry/Summary/SidePanel/index.tsx @@ -48,12 +48,14 @@ const SidePanel = ({ pathname: `${root}/mail/`, }); const entry = `${metadata.name.name} (${metadata.accession})`; + const queue = metadata.source_database.toLowerCase(); const handleSubmit = (event: FormEvent) => { if (!event.target) return; event.preventDefault(); const data = new FormData(event.target as HTMLFormElement); data.append('subject', `Add annotation, ${entry}`); + data.append('queue', queue); fetch(apiUrl, { method: 'POST', body: data, @@ -96,80 +98,90 @@ const SidePanel = ({ {['interpro', 'pfam'].includes( // Only receiving new annotations for pfam and interpro metadata.source_database.toLowerCase() - ) && ( - <div> - <Tooltip - title={ - 'You may suggest updates to the annotation of this entry using this form. Suggestions will be sent to ' + - 'our curators for review and, if acceptable, will be included in the next public release of InterPro. It is ' + - 'helpful if you can include literature references supporting your annotation suggestion.' - } - > - <DropDownButton - label="Add your annotation" - icon="" - extraClasses={css('annotation')} + ) && + !metadata.is_removed && ( + <div> + <Tooltip + title={`You can suggest annotation updates for this entry using the provided form. + Our curators will review and, if suitable, include them in the next + ${ + metadata.source_database.toLowerCase() === 'interpro' + ? 'InterPro' + : 'Pfam' + } release. + Please include supporting literature references for better accuracy.`} > - <form - onSubmit={handleSubmit} - className={css('vf-stack', 'vf-stack--200')} + <DropDownButton + label="Add your annotation" + icon="" + extraClasses={css('annotation')} > - <label - className={css('vf-form__label', 'vf-form__label--required')} - htmlFor="message" - > - Your annotation - </label> - <textarea - id="message" - name="message" - value={message} - onChange={handleFields} - className={css('vf-form__textarea')} - rows={5} - required - /> - <label - className={css('vf-form__label', 'vf-form__label--required')} - htmlFor="from_email" + <form + onSubmit={handleSubmit} + className={css('vf-stack', 'vf-stack--200')} > - Email address - </label> - <input - id="from_email" - name="from_email" - type="email" - value={email} - onChange={handleFields} - className={css('vf-form__input')} - required - /> - <div className={css('flex-space-evenly')}> - <button + <label className={css( - 'vf-button', - 'vf-button--primary', - 'vf-button--sm' + 'vf-form__label', + 'vf-form__label--required' )} + htmlFor="message" > - Submit - </button> - <button + Your annotation + </label> + <textarea + id="message" + name="message" + value={message} + onChange={handleFields} + className={css('vf-form__textarea')} + rows={5} + required + /> + <label className={css( - 'vf-button', - 'vf-button--secondary', - 'vf-button--sm' + 'vf-form__label', + 'vf-form__label--required' )} - onClick={clearFields} + htmlFor="from_email" > - Clear - </button> - </div> - </form> - </DropDownButton> - </Tooltip> - </div> - )} + Email address + </label> + <input + id="from_email" + name="from_email" + type="email" + value={email} + onChange={handleFields} + className={css('vf-form__input')} + required + /> + <div className={css('flex-space-evenly')}> + <button + className={css( + 'vf-button', + 'vf-button--primary', + 'vf-button--sm' + )} + > + Submit + </button> + <button + className={css( + 'vf-button', + 'vf-button--secondary', + 'vf-button--sm' + )} + onClick={clearFields} + > + Clear + </button> + </div> + </form> + </DropDownButton> + </Tooltip> + </div> + )} {metadata.integrated && <Integration intr={metadata.integrated} />} {!['interpro', 'pfam', 'antifam'].includes( metadata.source_database.toLowerCase() diff --git a/src/components/Entry/Summary/index.tsx b/src/components/Entry/Summary/index.tsx index 69383dc28..a02ecffb6 100644 --- a/src/components/Entry/Summary/index.tsx +++ b/src/components/Entry/Summary/index.tsx @@ -3,6 +3,7 @@ import React, { useState, useEffect } from 'react'; import GoTerms from 'components/GoTerms'; import Description from 'components/Description'; import DescriptionFromIntegrated from 'components/Description/DescriptionFromIntegrated'; +import DescriptionLLM from 'components/Description/DescriptionLLM'; import Literature, { getLiteratureIdsFromDescription, splitCitations, @@ -72,12 +73,14 @@ type SummaryEntryProps = { data: { metadata: EntryMetadata; }; + headerText?: string; loading: boolean; dbInfo: DBInfo; }; const SummaryEntry = ({ data: { metadata }, + headerText, dbInfo, loading, }: SummaryEntryProps) => { @@ -99,6 +102,38 @@ const SummaryEntry = ({ (included as Array<[string, Reference]>).sort( (a, b) => desc.indexOf(a[0]) - desc.indexOf(b[0]) ); + + const selectDescriptionComponent = () => { + if ((metadata.description || []).length) { + return ( + <> + <h4>{headerText || 'Description'}</h4> + <Description + textBlocks={metadata.description} + literature={included as Array<[string, Reference]>} + accession={metadata.accession} + /> + </> + ); + } else if (metadata.integrated) { + return ( + <DescriptionFromIntegrated + integrated={metadata.integrated} + setIntegratedCitations={setIntegratedCitations} + headerText={headerText || 'Description'} + /> + ); + } else if (metadata.llm_description) { + return ( + <> + <h4>{headerText || 'Description'}</h4> + <DescriptionLLM text={metadata.llm_description} /> + </> + ); + } + return null; + }; + return ( <div className={css('vf-stack', 'vf-stack--400')}> <section className={css('vf-grid', 'summary-grid')}> @@ -108,26 +143,7 @@ const SummaryEntry = ({ ) : ( <MemberDBSubtitle metadata={metadata} dbInfo={dbInfo} /> )} - <section> - { - // doesn't work for some HAMAP as they have enpty <P> tag - (metadata.description || []).length ? ( - <> - <h4>Description</h4> - <Description - textBlocks={metadata.description} - literature={included as Array<[string, Reference]>} - accession={metadata.accession} - /> - </> - ) : ( - <DescriptionFromIntegrated - integrated={metadata.integrated} - setIntegratedCitations={setIntegratedCitations} - /> - ) - } - </section> + <section>{selectDescriptionComponent()}</section> </div> <div className={css('vf-stack')}> <SidePanel metadata={metadata} dbInfo={dbInfo} /> diff --git a/src/components/GoTerms/style.css b/src/components/GoTerms/style.css index 04db9e76a..c5752dcd2 100644 --- a/src/components/GoTerms/style.css +++ b/src/components/GoTerms/style.css @@ -15,6 +15,7 @@ body a.go-terms:focus { body a.go-terms:hover { border-bottom: 1px #222 solid; + text-decoration: none; } .go-title { diff --git a/src/components/Menu/DynamicMenu/__snapshots__/test.js.snap b/src/components/Menu/DynamicMenu/__snapshots__/test.js.snap index e5983f840..3e7dbc0e2 100644 --- a/src/components/Menu/DynamicMenu/__snapshots__/test.js.snap +++ b/src/components/Menu/DynamicMenu/__snapshots__/test.js.snap @@ -117,7 +117,7 @@ exports[`<DynamicMenu /> should render 1`] = ` "to": [Function], }, { - "name": "By Set", + "name": "By Clan/Set", "to": [Function], }, ] diff --git a/src/components/Menu/EntitiesMenu/__snapshots__/test.js.snap b/src/components/Menu/EntitiesMenu/__snapshots__/test.js.snap index bd9b07a75..44447ef08 100644 --- a/src/components/Menu/EntitiesMenu/__snapshots__/test.js.snap +++ b/src/components/Menu/EntitiesMenu/__snapshots__/test.js.snap @@ -55,7 +55,7 @@ exports[`<EntitiesMenu /> should render 1`] = ` activeClass="active" to={[Function]} > - By Set + By Clan/Set </Memo(Connect(MenuItem))> </li> </ul> diff --git a/src/components/ProteinViewer/grid.css b/src/components/ProteinViewer/grid.css index ae012c9ab..fe41d6d90 100644 --- a/src/components/ProteinViewer/grid.css +++ b/src/components/ProteinViewer/grid.css @@ -82,6 +82,7 @@ .protvista-grid .track-label a:hover { border-bottom: 1px var(--colors-dark) solid; + text-decoration: none; } .protvista-grid .track-label .track-accession-child { diff --git a/src/components/ProteinViewer/utils.ts b/src/components/ProteinViewer/utils.ts index de1c71d0d..2b5cb675c 100644 --- a/src/components/ProteinViewer/utils.ts +++ b/src/components/ProteinViewer/utils.ts @@ -3,59 +3,31 @@ import { toPlural } from 'utils/pages/toPlural'; import { NOT_MEMBER_DBS } from 'menuConfig'; import { getTrackColor, EntryColorMode } from 'utils/entry-color'; -const dbs4SingleDomain = [ - 'pfam', - 'smart', - 'pirsf', - 'ncbifam', - 'hamap', - 'sfld', - 'cdd', - 'profile', -]; - const selectRepresentativeDomains = (domains: Record<string, unknown>[]) => { const flatDomains = []; for (const domain of domains) { const { accession, short_name, name, source_database, integrated } = domain; for (const location of domain.entry_protein_locations as Array<ProtVistaLocation>) { for (const fragment of location.fragments) { - const { start, end } = fragment; - flatDomains.push({ - accession, - short_name, - name, - source_database, - integrated, - start, - end, - color: getTrackColor({ source_database }, EntryColorMode.MEMBER_DB), - length: end - start + 1, - keep: true, - }); - } - } - } - for (const dom1 of flatDomains) { - for (const dom2 of flatDomains) { - if (dom1 === dom2 || !dom1.keep || !dom2.keep) continue; - const overlap = - Math.min(dom1.end, dom2.end) - Math.max(dom1.start, dom2.start) + 1; - if (overlap > 0) { - if (overlap > 0.7 * dom1.length && overlap > 0.7 * dom2.length) { - if ( - dom1.length < dom2.length || - (dom1.length === dom2.length && dom2.source_database === 'pfam') - ) { - dom1.keep = false; - } - } else if (overlap > 0.7 * dom1.length && overlap < 0.7 * dom2.length) { - dom1.keep = false; + const { start, end, representative } = fragment; + if (representative) { + flatDomains.push({ + accession, + short_name, + name, + source_database, + integrated, + start, + end, + color: getTrackColor({ source_database }, EntryColorMode.MEMBER_DB), + length: end - start + 1, + }); } } } } - return flatDomains.filter(({ keep }) => keep); + + return flatDomains; }; export const useProcessData = <M = Metadata>( results: EndpointWithMatchesPayload<M, MatchI>[] | undefined, @@ -87,15 +59,7 @@ const processData = <M = Metadata>( 'interpro' ); - const representativeDomains = selectRepresentativeDomains( - results.filter( - (entry) => - dbs4SingleDomain.includes( - (entry as unknown as Metadata).source_database.toLowerCase() - ) && - (entry as unknown as EntryMetadata)?.type?.toLowerCase() !== 'family' - ) - ); + const representativeDomains = selectRepresentativeDomains(results); const interproMap = new Map( interpro.map((ipro) => [ `${ipro.accession}-${ipro.chain}-${ipro.protein}`, diff --git a/src/components/SimpleCommonComponents/Tooltip/index.tsx b/src/components/SimpleCommonComponents/Tooltip/index.tsx index f0e2e083f..af6308d68 100644 --- a/src/components/SimpleCommonComponents/Tooltip/index.tsx +++ b/src/components/SimpleCommonComponents/Tooltip/index.tsx @@ -6,6 +6,7 @@ import { autoPlacement, arrow, offset, + size, } from '@floating-ui/react'; import useStateRef from 'utils/hooks/useStateRef'; @@ -24,6 +25,7 @@ const Tooltip = ({ children, distance = 0, interactive = false, + classNames = [], ...rest }: PropsWithChildren<{ html?: React.ReactElement | string | number; @@ -31,6 +33,7 @@ const Tooltip = ({ useContext?: boolean; distance?: number; interactive?: boolean; + classNames?: string[]; }>) => { const arrowRef = useRef(null); const [_, setOverTooltip, overTooltipRef] = useStateRef(false); @@ -45,6 +48,14 @@ const Tooltip = ({ arrow({ element: arrowRef, }), + size({ + apply({ availableWidth, availableHeight, elements }) { + Object.assign(elements.floating.style, { + maxWidth: `${availableWidth}px`, + maxHeight: `${availableHeight}px`, + }); + }, + }), ], }); @@ -72,7 +83,7 @@ const Tooltip = ({ <div ref={refs.setFloating} style={floatingStyles} - className={css('popper')} + className={css('popper', ...classNames)} onMouseEnter={() => setOverTooltip(true)} onMouseLeave={() => setOverTooltip(false)} > diff --git a/src/components/Title/TitleTag/index.tsx b/src/components/Title/TitleTag/index.tsx index fbb48239c..b176734bd 100644 --- a/src/components/Title/TitleTag/index.tsx +++ b/src/components/Title/TitleTag/index.tsx @@ -27,7 +27,12 @@ type Props = { const TitleTag = ({ db, mainType, dbLabel }: Props) => { const isEntry = mainType === 'entry'; - const isInterPro = db && db.toLowerCase() === 'interpro'; + let isInterPro = false; + let isPfam = false; + if (db) { + if (db.toLowerCase() === 'interpro') isInterPro = true; + else if (db.toLowerCase() === 'pfam') isPfam = true; + } let rtdLink = ''; if (isEntry) { rtdLink = rtdLinks.entry[isInterPro ? 'interpro' : 'dbs']; @@ -43,11 +48,15 @@ const TitleTag = ({ db, mainType, dbLabel }: Props) => { 'md-p': isEntry && !isInterPro, })} > - {dbLabel} {mainType} + {dbLabel} {mainType === 'set' && isPfam ? 'clan' : mainType} { // Set mainType === 'set' && ( - <Tooltip title="A set is defined as a group of evolutionary related entries"> + <Tooltip + title={`A ${ + isPfam ? 'clan' : 'set' + } is defined as a group of evolutionary related entries`} + > {' '} <span className={css('small', 'icon', 'icon-common')} diff --git a/src/custom.d.ts b/src/custom.d.ts index 435421052..54535c4ee 100644 --- a/src/custom.d.ts +++ b/src/custom.d.ts @@ -299,6 +299,8 @@ interface EntryMetadata extends Metadata { accession: string; name: string; }; + llm_description: string | null; + is_removed?: boolean; } type SourceOrganism = { @@ -597,6 +599,7 @@ type ProtVistaFragment = { residues?: string; seq_feature?: string; fill?: string; + representative?: boolean; }; type ProtVistaLocation = { diff --git a/src/higherOrder/loadData/defaults/index.js b/src/higherOrder/loadData/defaults/index.js index f4ec16bdd..5522b054f 100644 --- a/src/higherOrder/loadData/defaults/index.js +++ b/src/higherOrder/loadData/defaults/index.js @@ -176,7 +176,7 @@ export const getReversedUrl = createSelector( }, }); if (description.main.key === 'set' && description?.entry?.isFilter) { - url = url.replace('counters', 'counters,short_name'); + url = url.replace('counters', 'short_name'); } if (description.main.key === 'entry' && newMain === 'taxonomy') { url = url.replace('/entry/', '/protein/entry/'); diff --git a/src/menuConfig.js b/src/menuConfig.js index b9a2b6a94..00f279503 100644 --- a/src/menuConfig.js +++ b/src/menuConfig.js @@ -158,13 +158,13 @@ export const entities /*: Array<Object> */ = [ customLocation.description?.entry?.db?.toLowerCase(), ) ? customLocation.description.entry.db - : 'All', + : 'Pfam', }, }, hash: customLocation.hash, }; }, - name: 'By Set', + name: 'By Clan/Set', }, ]; diff --git a/src/pages/endpoint-page.js b/src/pages/endpoint-page.js index 50947327f..e28bd0d3d 100644 --- a/src/pages/endpoint-page.js +++ b/src/pages/endpoint-page.js @@ -104,8 +104,7 @@ class Summary extends PureComponent { render() { const { data: { status, loading, payload }, - // dataOrganism: { loading: loadingOrg, payload: payloadOrg }, - dataBase, + dataBase: { payload: payloadDB, loading: loadingDB }, customLocation, subPagesForEndpoint, } = this.props; @@ -114,15 +113,33 @@ class Summary extends PureComponent { main: { key: endpoint }, }, } = customLocation; - const databases = dataBase?.payload?.databases; - if (status === STATUS_GONE) { - return <RemovedEntrySummary {...payload} dbInfo={databases} />; + + if (loading) { + return <Loading />; + } + + if (payload && status === STATUS_GONE) { + const db = + (!loadingDB && + payloadDB && + payloadDB.databases && + payloadDB.databases[customLocation.description.entry.db]) || + {}; + + return <RemovedEntrySummary {...payload} dbInfo={db} />; + } + + if (edgeCases.has(status)) { + const edgeCaseText = edgeCases.get(status); + if (edgeCaseText) { + return <EdgeCase text={edgeCaseText} status={status} />; + } } - const edgeCaseText = edgeCases.get(status); - if (edgeCaseText) return <EdgeCase text={edgeCaseText} status={status} />; - if (loading || (!locationhasDetailOrFilter(customLocation) && !payload)) { + + if (!locationhasDetailOrFilter(customLocation) && !payload) { return <Loading />; } + return ( <> {payload?.metadata?.accession && (