Skip to content

Commit

Permalink
- Fixes #672
Browse files Browse the repository at this point in the history
- There's a lot of messy code (that miraculously still worked) from
  when you edited existing codesets instead of only being able to
  create a new one. I cleaned some of it up. More clean up could
  be done. But I needed to make it simpler in order to add the
  checkmark in all places where the concept would be included in
  the expansion.
  • Loading branch information
Sigfried committed Nov 20, 2024
1 parent 17c1abf commit 6b55feb
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 120 deletions.
22 changes: 1 addition & 21 deletions backend/routes/db.py
Original file line number Diff line number Diff line change
Expand Up @@ -398,9 +398,7 @@ def db_refresh_route():

FLAGS = ['includeDescendants', 'includeMapped', 'isExcluded']
@router.get("/cset-download")
def cset_download(codeset_id: int, csetEditState: str = None,
atlas_items=True, # atlas_items_only=False,
sort_json: bool = False, include_metadata = False) -> Dict:
def cset_download(codeset_id: int, atlas_items=True, sort_json: bool = False) -> Dict:
"""Download concept set
Had deleted this, but it's used for atlas-json download for existing concept sets
"""
Expand All @@ -412,24 +410,6 @@ def cset_download(codeset_id: int, csetEditState: str = None,

items = get_concept_set_version_expression_items(codeset_id, return_detail='full', handle_paginated=True)
items = [i['properties'] for i in items]
if csetEditState:
edits = json.loads(csetEditState)
edits = edits[str(codeset_id)]

deletes = [i['concept_id'] for i in edits.values() if i['stagedAction'] in ['Remove', 'Update']]
items = [i for i in items if i['conceptId'] not in deletes]
adds: List[Dict] = [i for i in edits.values() if i['stagedAction'] in ['Add', 'Update']]
# items is object api format but the edits from the UI are in dataset format
# so, convert the edits to object api format for consistency
for item in adds:
# set flags to false if they don't appear in item
for flag in FLAGS:
if flag not in item:
item[flag] = False
adds = convert_rows('concept_set_version_item',
'OmopConceptSetVersionItem',
adds)
items.extend(adds)
if sort_json:
items.sort(key=lambda i: i['conceptId'])

Expand Down
10 changes: 6 additions & 4 deletions frontend/src/components/CsetComparisonPage.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import React, {
useEffect,
useRef,
useState,
Profiler,
useMemo,
} from 'react';
import DataTable, {createTheme} from 'react-data-table-component';
import AddCircle from '@mui/icons-material/AddCircle';
Expand Down Expand Up @@ -301,6 +301,10 @@ export function CsetComparisonPage() {
infoPanelRef.current,
(infoPanelRef.current ? infoPanelRef.current.offsetHeight : 0)]);

const atlasWidget = useMemo(() =>
!isEmpty(newCset) && !isEmpty(conceptLookup) &&
newCsetAtlasWidget(newCset, conceptLookup), [newCset, conceptLookup]);

if (!gc || isEmpty(graphOptions) || isEmpty(displayedRows) ||
isEmpty(concepts)) {
// sometimes selected_csets and some other data disappears when the page is reloaded
Expand Down Expand Up @@ -466,7 +470,7 @@ export function CsetComparisonPage() {
if (editingCset) {
infoPanels.push(
<FlexibleContainer key="cset" title="New concept set"
startHidden={false}
startHidden={true}
hideShowPrefix={true}
style={{width: '80%', resize: 'both'}}
position={panelPosition}
Expand All @@ -491,8 +495,6 @@ export function CsetComparisonPage() {
</FlexibleContainer>
); */

const atlasWidget = newCsetAtlasWidget(newCset, conceptLookup);

infoPanels.push(
<FlexibleContainer key="instructions"
title="Instructions to save new concept set"
Expand Down
143 changes: 52 additions & 91 deletions frontend/src/components/NewCset.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,6 @@ export function getCodesetEditActionFunc({ newCset, newCsetDispatch, csmi }) {


let definition = get(csmi, [codeset_id, concept_id]);
let _clickAction = clickAction; // because this code was in a function
// that locally changed clickAction
if (clickAction) {
definition = { ...definition };
if (clickAction.startsWith("Cancel")) {
Expand All @@ -107,15 +105,6 @@ export function getCodesetEditActionFunc({ newCset, newCsetDispatch, csmi }) {
definition[flag] = false;
});
}
if (definition.stagedAction === "Add" && clickAction === "Update") {
_clickAction = "Add";
}
if (definition.stagedAction && definition.stagedAction !== _clickAction) {
throw new Error("wasn't expecting a different action");
}
}
if (definition) {
definition.stagedAction = _clickAction;
}
}

Expand Down Expand Up @@ -194,8 +183,7 @@ function OptionIcon(props) {
editing,
cset_col: { codeset_id },
row: { concept_id },
editCodesetId,
editAction,
onClick,
} = props;
const icon = ICONS[flag];
if (flag == "block") {
Expand All @@ -207,13 +195,7 @@ function OptionIcon(props) {
return (
<Tooltip label={icon.tt + " =" + (on ? "True" : "False")}>
<IconButton
onClick={
editing && !item.fakeItem
? (evt) => {
editAction({evt, ...props, clickAction: "Update"})
}
: null
}
onClick={onClick}
size="9px"
// color={on ? 'primary' : 'secondary'}
sx={{
Expand Down Expand Up @@ -247,7 +229,7 @@ function cellInfo(props) {
const item = get(csmi, [codeset_id, concept_id]);
const editing = codeset_id === get(newCset, ['codeset_id']);

return { editing, item };
return { editing, item, codeset_id, concept_id };
}
export const defaultCellStyle = {
// https://stackoverflow.com/questions/19461521/how-to-center-an-element-horizontally-and-vertically
Expand All @@ -272,18 +254,6 @@ function _cellStyle(item, editing) {
} else if (item.item) {
style.backgroundColor = "plum";
}
/*
editing = editing ?? item.editing;
if (editing) {
if (item.stagedAction === "Add") {
style.backgroundColor = "lightgreen";
} else if (item.stagedAction === "Remove") {
style.backgroundColor = "pink";
} else if (item.stagedAction === "Update") {
style.backgroundColor = "lightblue";
}
}
*/
return style;
}

Expand Down Expand Up @@ -323,8 +293,8 @@ function flagAbbrev(letter) {
return FLAG_ABBREV[letter];
}
function fakeCell(props) {
let { editing, stagedAction, flags = "DMX" } = props;
let item = { fakeItem: true, stagedAction, item: !!stagedAction };
let { editing, flags = "DMX" } = props;
let item = { fakeItem: true, };
flags.split("").forEach((f) => {
item[flagAbbrev(f)] = true;
});
Expand Down Expand Up @@ -404,7 +374,6 @@ export function Legend({editing=false}) {
"Click to toggle isExcluded": {
content: <div style={{textAlign: 'center', paddingTop: '3px'}}>X</div>
},
*/
"Concept added": {
content: fakeCell({editing: true, flags: "i", stagedAction: "Add"}),
},
Expand Down Expand Up @@ -477,8 +446,8 @@ export function cellContents(props) {
- If staged for deletion:
- Just the word 'Deleted', clicking cancels deletion
*/
const { editAction } = props;
const { item, editing } = cellInfo(props);
const { editAction, newCset, newCsetDispatch } = props;
const { item, editing, codeset_id, concept_id } = cellInfo(props);
let removeIcon, clickAction, contents;
let flags = Object.keys(FLAGS);
if (!editing) {
Expand All @@ -490,7 +459,8 @@ export function cellContents(props) {
);
});
} else if (item && item.csm) {
contents = checkmark;
// contents = checkmark;
// adding checkmark later now
} else if (item) {
throw new Error("Impossible: item has neither csm nor item set to true");
} else {
Expand All @@ -499,67 +469,59 @@ export function cellContents(props) {
} else {
// editing
if (!item || !item.item) {
clickAction = "Add";
contents = (
<Add
style={{ cursor: "pointer" }}
onClick={(evt) => editAction({ evt, ...props, clickAction })}
onClick={(evt) => {
let definition = {
codeset_id,
concept_id,
csm: true,
item: true,
};
Object.keys(FLAGS).forEach((flag) => {
definition[flag] = false;
});
newCsetDispatch({type: 'addDefinition', definition});

//editAction({ evt, ...props, clickAction })}
}}
/>
);
// return contents;
} else {
// item is an item, either existing or staged for addition
if (item.stagedAction) {
// staged edits
clickAction = `Cancel ${item.stagedAction}`;
if (item.stagedAction === "Remove") {
contents = (
<Tooltip label={clickAction}>
<span style={{ cursor: 'pointer' /*, width:'70px', ...centered */}}
onClick={(evt) => editAction({ evt, ...props, item, clickAction })}
>
Deleted
</span>
</Tooltip>
);
return contents;
}
} else {
clickAction = "Remove";
}
}
removeIcon = // if any staged edit, this icon cancels, otherwise icon removes existing item
clickAction === "Add" ? null : (
<Tooltip label={clickAction}>
<BlockIcon
onClick={(evt) => editAction({ evt, ...props, item, clickAction })}
sx={{
width: "12px",
height: "12px",
marginBottom: "1px",
padding: 0,
}}
/>
</Tooltip>
clickAction = "Remove";
removeIcon = (
<Tooltip label={clickAction}>
<BlockIcon
onClick={(evt) => newCsetDispatch({type: 'deleteDefinition', concept_id: item.concept_id})}
// editAction({ evt, ...props, item, clickAction })}
sx={{
width: "12px",
height: "12px",
marginBottom: "1px",
padding: 0,
}}
/>
</Tooltip>
);
const flagButtons = flags.map((flag) => (
<OptionIcon {...props} {...{ item, flag, editing }} key={flag}
onClick={(evt) => {
console.log("clicking flag");
newCsetDispatch({type: 'toggleFlag', concept_id: item.concept_id, flag})
}}
/>));
contents = <span>{removeIcon}{flagButtons}</span>;
}
}
if (item?.csm) {
contents = <span>{checkmark}{contents}</span>;
}
const cellStuff = (
<div onClick={(evt) => { editAction({ evt, ...props, clickAction, no_action: true });}}
let cellStuff = (
<div //onClick={(evt) => { editAction({ evt, ...props, clickAction, no_action: true });}}
style={{display: "flex", alignItems: "center", gap: "4px", marginTop: "1px"}}
>
{removeIcon}
{contents || contents === ""
? contents
: flags.map((flag) => {
//Object.keys(ICONS).map((flag) => {}
if (!item) {
throw new Error("that's not expected");
}
// either contents already set, or ready to get flag icons
return (
<OptionIcon {...props} {...{ item, flag, editing }} key={flag} />
);
})}
{contents}
</div>
);
return cellStuff;
Expand Down Expand Up @@ -590,7 +552,6 @@ export function copyConceptsFromWidget(cset, selected_csets, csmi, newCsetDispat
}
let newDef = {...def};
newDef.codeset_id = cset.codeset_id;
newDef.stagedAction = 'Add';
newDefs[concept_id] = newDef;
});
newCsetDispatch({type: 'addDefinitions', definitions: newDefs})
Expand Down
11 changes: 7 additions & 4 deletions frontend/src/state/AppState.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -230,17 +230,14 @@ const newCsetReducer = (state, action) => {
/*
state structure in storageProvider.newCset should look like:
{
codeset_id: 1234,
codeset_id: -1,
concept_set_name: 'New Cset',
...
definitions: {
concept_id: 12345,
includeDescendants: true,
...
},
members: {
// this won't work for a while
},
}
*/
if (!action || !action.type) return state;
Expand Down Expand Up @@ -297,6 +294,12 @@ const newCsetReducer = (state, action) => {
state = {...state, definitions, };
break;
}
case "toggleFlag": {
let definition = {...state.definitions[action.concept_id]};
definition[action.flag] = !definition[action.flag];
state = {...state, definitions: {...state.definitions, [action.concept_id]: definition} };
break;
}
}

// const restoreUrl = urlWithSessionStorage();
Expand Down

0 comments on commit 6b55feb

Please sign in to comment.