jhu-bids / TermHub

Web app and CLI tools for working with biomedical terminologies. https://github.com/orgs/jhu-bids/projects/9/views/7
https://bit.ly/termhub
GNU General Public License v3.0
11 stars 10 forks source link

Bug: Create new cset: + sign on "unlinked" #966

Open joeflack4 opened 6 days ago

joeflack4 commented 6 days ago

Overview

On the cset comparison page, when I am creating a new cset, I can encounter an issue where I get a white screen of death.

Error message

Uncaught TypeError: Cannot convert undefined or null to object (AppState.jsx:404:16)

More

``` Uncaught TypeError: Cannot convert undefined or null to object at Function.entries () at AppState.jsx:404:16 at Array.map () at newCsetAtlasJson (AppState.jsx:399:46) at newCsetAtlasWidget (NewCset.jsx:593:21) at CsetComparisonPage (CsetComparisonPage.jsx:485:25) at renderWithHooks (chunk-W6L2VRDA.js?v=2dedd740:11548:26) at updateFunctionComponent (chunk-W6L2VRDA.js?v=2dedd740:14582:28) at beginWork (chunk-W6L2VRDA.js?v=2dedd740:15924:22) at HTMLUnknownElement.callCallback2 (chunk-W6L2VRDA.js?v=2dedd740:3674:22) ```

Replication

  1. Load this cset comparison page: http://localhost:3000/cset-comparison?codeset_ids=479356
  2. Click "Create new concept set or version"
  3. Click the + sign next to "unlinked" ("Concepts included but not linked to other concepts")
Screenshots

1 2

Cset obj printed in console

```json { "codeset_id": -1, "concept_set_version_title": "New Cset (Draft)", "concept_set_name": "New Cset", "alias": "New Cset", "source_application": "TermHub", "source_application_version": "0.4.0 (Beta)", "codeset_intention": "From VS-Hub", "limitations": "From VS-Hub", "update_message": "VS-Hub testing", "is_draft": true, "researchers": [], "counts": { "Expression items": 2 }, "intersecting_concepts": 0, "precision": 0, "recall": 0, "definitions": { "4179963": { "codeset_id": -1, "concept_id": 4179963, "csm": false, "item": true, "includeDescendants": true, "includeMapped": false, "isExcluded": false, "stagedAction": "Add" }, "unlinked": { "codeset_id": -1, "concept_id": "unlinked", "csm": false, "item": true, "includeDescendants": false, "includeMapped": false, "isExcluded": false, "stagedAction": "Add" } } } ```

Possible Solutions

a. + sign next to "unlinked"

Remove (preferably) or deactivate the + sign next to "unlinked" ("Concepts included but not linked to other concepts")

b. LLM proposal

@Sigfried I think my solutions is better, but check this out!

This is a new Chrome feature. I clicked "understand this error".

Screenshot 2024-11-09 at 7 58 33 PM

Check out its response! I think it might well have a solution:

Chrome LLM response

Screenshot 2024-11-09 at 7 58 45 PM ### Explanation The error "Uncaught TypeError: Cannot convert undefined or null to object" at line 404 of your `AppState.jsx` file indicates that `concept` is likely `undefined` or `null` when you try to iterate over its entries using `Object.entries(concept).forEach(...)`. Let's break down why this happens and how to fix it: `conceptLookup[d.concept_id]` might be undefined: The `conceptLookup` object likely contains concept data based on their IDs. If `d.concept_id` doesn't exist as a key in `conceptLookup`, the result of `conceptLookup[d.concept_id]` will be `undefined`. `Object.entries()` on undefined/null: The `Object.entries()` method expects an object as input. When you try to call `Object.entries()` on `undefined` or `null`, it throws the "Cannot convert undefined or null to object" error. **Solution:** You need to add a check to ensure that concept is a valid object before attempting to iterate over its entries. Here's how you can modify your code: _Copy code_ ```js if (isEmpty(cset.definitions)) { return; } let defs = Object.values(cset.definitions).map(d => { let item = pick(d, ['includeDescendants', 'includeMapped', 'isExcluded']); let concept = conceptLookup[d.concept_id]; let atlasConcept = {}; if (concept) { // Check if concept is defined Object.entries(concept).forEach(([k, v]) => { atlasConcept[k.toUpperCase()] = v; }); atlasConcept = pick(atlasConcept, [ "CONCEPT_CLASS_ID", "CONCEPT_CODE", "CONCEPT_ID", "CONCEPT_NAME", "DOMAIN_ID", "INVALID_REASON", "INVALID_REASON_CAPTION", "STANDARD_CONCEPT", "STANDARD_CONCEPT_CAPTION", "VOCABULARY_ID", "VALID_START_DATE", "VALID_END_DATE", ]); } item.concept = atlasConcept; return item; }); const jsonObj = { items: defs }; ``` Use code snippets with caution (link) **Explanation of the fix:** We added if (concept) to check if concept is defined before proceeding with Object.entries(). If concept is undefined or null, the code inside the if block will be skipped, preventing the error. In this case, atlasConcept will remain an empty object, which is likely what you want if the corresponding concept data is missing. By implementing this check, you ensure that your code handles cases where conceptLookup[d.concept_id] might not be found, preventing the "Cannot convert undefined or null to object" error and making your application more robust. **Data used to understand this message** Console message (link) Stacktrace (link) Related code (link)

joeflack4 commented 4 days ago

Siggie couldn't replicate.

Perhaps you need to click the + sign next to the newly added concept "family history of breast cancer" and click "d" first, then click the + sign on unlinked. This is how I did it at first. But then I replicated it without needing to go through that step. But maybe it still retained some knowledge of that via the cache? IDK