From 5c938193fce11f916b67780c219e4bda43ec5cad Mon Sep 17 00:00:00 2001 From: Dylan Phelan Date: Thu, 3 Oct 2019 15:41:40 -0400 Subject: [PATCH 1/5] Implement missing patient information and general information section --- src/context/ContextGetHelp.jsx | 136 +++++++++++++++----------- src/context/ContextGetHelp.scss | 12 ++- src/shortcuts/CreatorBase.jsx | 4 + src/shortcuts/CreatorIntermediary.jsx | 4 + 4 files changed, 94 insertions(+), 62 deletions(-) diff --git a/src/context/ContextGetHelp.jsx b/src/context/ContextGetHelp.jsx index 2e3d473011..a0d72bb041 100644 --- a/src/context/ContextGetHelp.jsx +++ b/src/context/ContextGetHelp.jsx @@ -108,85 +108,107 @@ class ContextGetHelp extends React.Component { } } - renderOptions() { - // if getHelp is not selected, don't show the additional options - if (this.state.selectedIndex === -1) return null; + renderOptionsWithGetHelp = () => { + // Get name of the shortcut for the getHelp text + const initiatingTrigger = this.props.shortcut.getDisplayText(); - return ( - - {this.state.getHelpOptions.map((option, index) => { - // the parent 'get help' option is not included in the getHelpOptions array - // but it is included as a selectedIndex, so there is an off by one that needs - // to be calculated, hence the updatedIndex + 1 from the index of the getHelpOptions - const updatedIndex = index + 1; - return ( -
  • { this.setSelectedIndex(updatedIndex); }} - > - {option.text} -
  • - ); - })} -
    - ); - } + // Determine if we should display anything other than the getHelp option + const isGetHelpClosed = this.state.selectedIndex === -1; + // For any informational flags, define them here and chain them together into a single variable + // This variable will determine if we display a horizontal bar, separating information from actions + const isMissingParent = this.props.shortcut.isMissingParent; + const isInformationAvailable = isMissingParent || false; + + // Create our icon class to signal the expanding/collapsing getHelp option, based on open/closedness + let iconClass = 'fa fa-angle-'; + isGetHelpClosed ? iconClass += 'down' : iconClass += 'up'; - renderIsCompleteMessage() { - const initiatingTrigger = this.props.shortcut.getDisplayText(); return ( - + + + {!isGetHelpClosed && this.state.getHelpOptions.map((option, index) => { + // the parent 'get help' option is not included in the getHelpOptions array + // but it is included as a selectedIndex, so there is an off by one that needs + // to be calculated, hence the updatedIndex + 1 from the index of the getHelpOptions + const updatedIndex = index + 1; + return ( +
  • { this.setSelectedIndex(updatedIndex); }} + > + {option.text} +
  • + ); + })} +
    + {(!isGetHelpClosed && isInformationAvailable) && this.renderHorizontalLine()} + {(!isGetHelpClosed && isMissingParent) && this.renderIsMissingParent()} + ); } - renderIsMissingParent() { + renderIsCompleteMessage() { const initiatingTrigger = this.props.shortcut.getDisplayText(); + const infoIconiconClass = "fa fa-info-circle"; return ( - +
  • + + + {initiatingTrigger} is already complete + +
  • ); } + renderIsMissingParent() { + const initiatingTrigger = this.props.shortcut.getDisplayText(); + const infoIconiconClass = "fa fa-info-circle"; + return ( +
  • + + + {initiatingTrigger} is missing a parent + +
  • + ); + } + renderHorizontalLine() { + return ( +
    + ); + } render() { - // If the shortcut we're responsible for is missing a parent, display a message to the user to avoid confusion - if (!this.props.shortcut.hasParentContext() && this.props.shortcut.hasChildren()) return this.renderIsMissingParent(); - // If the shortcut we're responsible for is complete, display a message to the user to avoid confusion - if (this.props.shortcut.isComplete) return this.renderIsCompleteMessage(); - // Else we should display all our getHelp message - const initiatingTrigger = this.props.shortcut.getDisplayText(); - let iconClass = 'fa fa-angle-'; - this.state.selectedIndex === -1 ? iconClass += 'down' : iconClass += 'up'; + // Decide the list content and render whatever it is in the UL element + let listContent = null; + if (this.props.shortcut.isMissingParent && this.props.shortcut.hasChildren()) { + // If the shortcut we're responsible for is missing a parent but is already expanded, display a message to the user to avoid confusion + listContent = this.renderIsMissingParent(); + } else if (this.props.shortcut.isComplete) { + // Else, if the shortcut we're responsible for is complete, display a message to the user to avoid confusion + listContent = this.renderIsCompleteMessage(); + } else { + // Else we should display all our getHelp message + listContent = this.renderOptionsWithGetHelp(); + } + return ( ); } diff --git a/src/context/ContextGetHelp.scss b/src/context/ContextGetHelp.scss index 76f51120e9..da074eee13 100644 --- a/src/context/ContextGetHelp.scss +++ b/src/context/ContextGetHelp.scss @@ -28,17 +28,19 @@ ul.context-get-help { margin-bottom: 5px; .context-get-help-text { - span { + span.fa-angle-up, span.fa-angle-down { + padding: 0; padding-left: 15px; } } + .context-information-text { + span.fa-info-circle { + padding: 0 5px 0 0; + } + } } .context-get-help-options { - li:first-child { - border-top: 1px solid $line-gray; - } - li:last-child { margin-bottom: 5px; } diff --git a/src/shortcuts/CreatorBase.jsx b/src/shortcuts/CreatorBase.jsx index a366e745e5..36d3ddb64a 100644 --- a/src/shortcuts/CreatorBase.jsx +++ b/src/shortcuts/CreatorBase.jsx @@ -22,4 +22,8 @@ export default class CreatorBase extends EntryShortcut { get isComplete() { return this.hasParentContext() && this.hasChildren(); } + + get isMissingParent() { + return !this.hasParentContext(); + } } diff --git a/src/shortcuts/CreatorIntermediary.jsx b/src/shortcuts/CreatorIntermediary.jsx index 188601ab54..15a113b637 100644 --- a/src/shortcuts/CreatorIntermediary.jsx +++ b/src/shortcuts/CreatorIntermediary.jsx @@ -121,4 +121,8 @@ export default class CreatorIntermediary extends Shortcut { get isComplete() { return this.hasParentContext() && this.hasChildren(); } + + get isMissingParent() { + return !this.hasParentContext(); + } } From 61dc4f333b2a4023347a55742bd1d997ffc986c0 Mon Sep 17 00:00:00 2001 From: Dylan Phelan Date: Mon, 7 Oct 2019 11:15:57 -0400 Subject: [PATCH 2/5] initial fix of the label for shortcuts --- src/context/ContextGetHelp.jsx | 6 +++-- src/notes/FluxNotesEditor.jsx | 1 + ...SuggestionPortalPlaceholderSearchIndex.jsx | 2 +- .../SuggestionPortalShortcutSearchIndex.jsx | 2 +- src/shortcuts/CreatorBase.jsx | 15 +++++++++++ src/shortcuts/CreatorIntermediary.jsx | 21 ++++++++++++--- src/shortcuts/ShortcutManager.js | 26 ++++++++++++++----- src/shortcuts/Shortcuts.json | 1 + 8 files changed, 60 insertions(+), 14 deletions(-) diff --git a/src/context/ContextGetHelp.jsx b/src/context/ContextGetHelp.jsx index a0d72bb041..6b8abb31d7 100644 --- a/src/context/ContextGetHelp.jsx +++ b/src/context/ContextGetHelp.jsx @@ -174,13 +174,15 @@ class ContextGetHelp extends React.Component { } renderIsMissingParent() { - const initiatingTrigger = this.props.shortcut.getDisplayText(); + const shortcut = this.props.shortcut; + const initiatingTrigger = shortcut.getDisplayText(); + const potentialParentText = shortcut.potentialParents.map(parentID => this.props.shortcutManager.getShortcutLabel(parentID)).join(", or"); const infoIconiconClass = "fa fa-info-circle"; return (
  • - {initiatingTrigger} is missing a parent + {initiatingTrigger} needs more context, try mentioning {potentialParentText} beforehand
  • ); diff --git a/src/notes/FluxNotesEditor.jsx b/src/notes/FluxNotesEditor.jsx index 7eb07be909..29dcb8589d 100644 --- a/src/notes/FluxNotesEditor.jsx +++ b/src/notes/FluxNotesEditor.jsx @@ -1787,6 +1787,7 @@ class FluxNotesEditor extends React.Component { onSelected={this.onCompletionComponentValueSelection} closePortal={this.closeCompletionPortal} shortcut={this.state.completionComponentShortcut} + shortcutManager={this.props.shortcutManager} state={this.state.state} insertShortcut={this.insertShortcut} /> diff --git a/src/notes/SuggestionPortalPlaceholderSearchIndex.jsx b/src/notes/SuggestionPortalPlaceholderSearchIndex.jsx index f7e27b432f..24d84e2173 100644 --- a/src/notes/SuggestionPortalPlaceholderSearchIndex.jsx +++ b/src/notes/SuggestionPortalPlaceholderSearchIndex.jsx @@ -15,7 +15,7 @@ class SuggestionPortalPlaceholderSearchIndex extends SuggestionPortalSearchIndex const relevantShortcuts = []; placeholders.forEach((placeholder) => { - const triggers = this.shortcutManager.getTriggersForShortcut(placeholder.id); + const triggers = this.shortcutManager.getTriggersWithoutLabelForShortcut(placeholder.id); triggers.forEach((trigger) => { const triggerNoPrefix = trigger.name.substring(1); relevantShortcuts.push({ diff --git a/src/notes/SuggestionPortalShortcutSearchIndex.jsx b/src/notes/SuggestionPortalShortcutSearchIndex.jsx index 19e185b63f..e8943e5b35 100644 --- a/src/notes/SuggestionPortalShortcutSearchIndex.jsx +++ b/src/notes/SuggestionPortalShortcutSearchIndex.jsx @@ -20,7 +20,7 @@ class SuggestionPortalShortcutSearchIndex extends SuggestionPortalSearchIndex { allShortcutObjs.forEach((shortcutObj) => { const shortcutId = shortcutObj.id; const shortcutMetadata = this.shortcutManager.getShortcutMetadata(shortcutId); - const triggers = this.shortcutManager.getTriggersForShortcut(shortcutId); + const triggers = this.shortcutManager.getTriggersWithoutLabelForShortcut(shortcutId); // Scores get sorted from smallest to greatest // ActiveContexts is sorted from most recent to least recent // We want shortcuts for the most recent shortcuts to have the smallest bonus score, so as to appear earlier diff --git a/src/shortcuts/CreatorBase.jsx b/src/shortcuts/CreatorBase.jsx index 36d3ddb64a..adae51e7bf 100644 --- a/src/shortcuts/CreatorBase.jsx +++ b/src/shortcuts/CreatorBase.jsx @@ -1,4 +1,5 @@ import EntryShortcut from './EntryShortcut'; +import _ from 'lodash'; export default class CreatorBase extends EntryShortcut { constructor(onUpdate, metadata, patient, shortcutData) { @@ -26,4 +27,18 @@ export default class CreatorBase extends EntryShortcut { get isMissingParent() { return !this.hasParentContext(); } + + get potentialParents() { + const knownParent = this.metadata["knownParentContexts"]; + if (knownParent === 'Patient' || knownParent === undefined) return []; + console.log(knownParent); + if (_.isArray(knownParent)) { + return knownParent; + } else if (_.isString(knownParent)) { + return [knownParent]; + } else { + console.warn("unknown type for knownParent: element looks like ", knownParent); + return []; + } + } } diff --git a/src/shortcuts/CreatorIntermediary.jsx b/src/shortcuts/CreatorIntermediary.jsx index 15a113b637..d44c2dfdae 100644 --- a/src/shortcuts/CreatorIntermediary.jsx +++ b/src/shortcuts/CreatorIntermediary.jsx @@ -1,5 +1,5 @@ import Shortcut from './Shortcut'; -import Lang from 'lodash'; +import _ from 'lodash'; export default class CreatorIntermediary extends Shortcut { constructor(onUpdate, metadata) { @@ -15,11 +15,11 @@ export default class CreatorIntermediary extends Shortcut { initialize(contextManager, trigger = undefined, updatePatient = true) { super.initialize(contextManager, trigger, updatePatient); - if (Lang.isUndefined(this.parentContext)) { + if (_.isUndefined(this.parentContext)) { super.determineParentContext(contextManager, this.metadata["knownParentContexts"], this.metadata["parentAttribute"]); } - if (!Lang.isUndefined(this.parentContext) && this.parentContext.children.indexOf(this) === -1) { + if (!_.isUndefined(this.parentContext) && this.parentContext.children.indexOf(this) === -1) { this.parentContext.setAttributeValue(this.metadata["parentAttribute"], true, false, updatePatient); this.parentContext.addChild(this); } @@ -115,7 +115,7 @@ export default class CreatorIntermediary extends Shortcut { } hasValueObjectAttributes() { - return !Lang.isEmpty(this.metadata["valueObjectAttributes"]); + return !_.isEmpty(this.metadata["valueObjectAttributes"]); } get isComplete() { @@ -125,4 +125,17 @@ export default class CreatorIntermediary extends Shortcut { get isMissingParent() { return !this.hasParentContext(); } + get potentialParents() { + const knownParent = this.metadata["knownParentContexts"]; + if (knownParent === 'Patient' || knownParent === undefined) return []; + console.log(knownParent); + if (_.isArray(knownParent)) { + return knownParent; + } else if (_.isString(knownParent)) { + return [knownParent]; + } else { + console.warn("unknown type for knownParent: element looks like ", knownParent); + return []; + } + } } diff --git a/src/shortcuts/ShortcutManager.js b/src/shortcuts/ShortcutManager.js index 0a910e209c..545254baf0 100644 --- a/src/shortcuts/ShortcutManager.js +++ b/src/shortcuts/ShortcutManager.js @@ -6,7 +6,7 @@ import UpdaterBase from './UpdaterBase'; import Placeholder from './Placeholder'; import ValueSetManager from '../lib/ValueSetManager'; import shortcutMetadata from './Shortcuts.json'; -import _ from 'lodash'; +import _ from 'lodash'; import NLPHashtag from './NLPHashtag'; // Given a trigger object, add it and any subsidiary trigger objects to our triggersPerShortcut map @@ -268,6 +268,7 @@ class ShortcutManager { } else { addTriggerForCurrentShortcut.bind(this)(triggers, item); } + // If this shortcut has a label, then add the label as a shortcut. if (item.label) { // Add a string trigger for incomplete placeholder addTriggerForCurrentShortcut.bind(this)({ @@ -341,7 +342,6 @@ class ShortcutManager { } let numberOfValidTriggers; if (this.triggersPerShortcut[shortcutId]) { - // If the shortcut has a label defined, don't include in in the list of valid triggers per shortcut numberOfValidTriggers = this.triggersPerShortcut[shortcutId].length - (shortcut.label ? 1 : 0); } else { numberOfValidTriggers = shortcut.label ? 1 : 0; @@ -402,10 +402,20 @@ class ShortcutManager { // stringTriggers is directly from shortcut metadata const stringTriggers = this.shortcuts[shortcutId].stringTriggers; // triggers is the computed options based on the valueset defined in metadata - const triggers = this.getTriggersForShortcut(shortcutId, context); - - // Filter out the label from triggers if there are defined stringTriggers that can be added - return triggers.filter(t => stringTriggers.length === 0 || t.name !== label); + // Clone this information so we aren't changing anything by reference + const triggers = [...this.getTriggersForShortcut(shortcutId, context)]; + + // Get the index of the label in the triggers list + const indexOfLabel = _.findIndex(triggers, t => t.name === label) + // If there is an instance of the label, and the stringTriggers isn't empty then we want to remove this instance of the label + // When stringTriggers doesn't have a length, we might be using the label as a shorthand for writing down the string trigger as well + if (indexOfLabel !== -1 && stringTriggers.length !== 0) { + // We only splice out this one instance of it in case the string trigger itself happens to match the label + // In this case there will be two instances of the label in our list and we want to remove one of them + // In the case where there is just one instance, then we can remove it safely + triggers.splice(indexOfLabel, 1) + } + return triggers; } getKeywordsForShortcut(shortcutId, context) { @@ -439,6 +449,10 @@ class ShortcutManager { return this.shortcuts[shortcutId]["shortcutGroupName"]; } + getShortcutLabel(shortcutId) { + return this.shortcuts[shortcutId].label; + } + getShortcutMetadata(shortcutId) { return this.shortcuts[shortcutId]; } diff --git a/src/shortcuts/Shortcuts.json b/src/shortcuts/Shortcuts.json index ce752774e1..81f7def7ea 100644 --- a/src/shortcuts/Shortcuts.json +++ b/src/shortcuts/Shortcuts.json @@ -354,6 +354,7 @@ { "type": "InsertValue", "subtype": "choice", "id": "ConditionInserter", + "label": "@condition", "getData": {"object": "patient", "method": "getConditions", "itemKey": "entryInfo.entryId.id", "itemContext":"type", "dateLabel": "diagnosisDate"}, "isContext": true, "isGlobalContext": true, From e8254cbd60f9d70814850ca92829fcb7ddeb7935 Mon Sep 17 00:00:00 2001 From: Dylan Phelan Date: Mon, 7 Oct 2019 12:02:26 -0400 Subject: [PATCH 3/5] linting --- src/shortcuts/ShortcutManager.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/shortcuts/ShortcutManager.js b/src/shortcuts/ShortcutManager.js index 545254baf0..3821176f7b 100644 --- a/src/shortcuts/ShortcutManager.js +++ b/src/shortcuts/ShortcutManager.js @@ -6,7 +6,7 @@ import UpdaterBase from './UpdaterBase'; import Placeholder from './Placeholder'; import ValueSetManager from '../lib/ValueSetManager'; import shortcutMetadata from './Shortcuts.json'; -import _ from 'lodash'; +import _ from 'lodash'; import NLPHashtag from './NLPHashtag'; // Given a trigger object, add it and any subsidiary trigger objects to our triggersPerShortcut map @@ -406,15 +406,15 @@ class ShortcutManager { const triggers = [...this.getTriggersForShortcut(shortcutId, context)]; // Get the index of the label in the triggers list - const indexOfLabel = _.findIndex(triggers, t => t.name === label) - // If there is an instance of the label, and the stringTriggers isn't empty then we want to remove this instance of the label + const indexOfLabel = _.findIndex(triggers, t => t.name === label); + // If there is an instance of the label, and the stringTriggers isn't empty then we want to remove this instance of the label // When stringTriggers doesn't have a length, we might be using the label as a shorthand for writing down the string trigger as well if (indexOfLabel !== -1 && stringTriggers.length !== 0) { // We only splice out this one instance of it in case the string trigger itself happens to match the label // In this case there will be two instances of the label in our list and we want to remove one of them // In the case where there is just one instance, then we can remove it safely - triggers.splice(indexOfLabel, 1) - } + triggers.splice(indexOfLabel, 1); + } return triggers; } From f764ac373bc5004f53ae4ce5cfc1a87d020ca8ca Mon Sep 17 00:00:00 2001 From: Dylan Phelan Date: Mon, 7 Oct 2019 12:19:53 -0400 Subject: [PATCH 4/5] Added labels for multiple shortcuts; added comment back and removed log --- src/shortcuts/CreatorBase.jsx | 1 - src/shortcuts/ShortcutManager.js | 1 + src/shortcuts/Shortcuts.json | 4 ++++ 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/shortcuts/CreatorBase.jsx b/src/shortcuts/CreatorBase.jsx index adae51e7bf..9a7fe39f7e 100644 --- a/src/shortcuts/CreatorBase.jsx +++ b/src/shortcuts/CreatorBase.jsx @@ -31,7 +31,6 @@ export default class CreatorBase extends EntryShortcut { get potentialParents() { const knownParent = this.metadata["knownParentContexts"]; if (knownParent === 'Patient' || knownParent === undefined) return []; - console.log(knownParent); if (_.isArray(knownParent)) { return knownParent; } else if (_.isString(knownParent)) { diff --git a/src/shortcuts/ShortcutManager.js b/src/shortcuts/ShortcutManager.js index 3821176f7b..7e199ae735 100644 --- a/src/shortcuts/ShortcutManager.js +++ b/src/shortcuts/ShortcutManager.js @@ -342,6 +342,7 @@ class ShortcutManager { } let numberOfValidTriggers; if (this.triggersPerShortcut[shortcutId]) { + // If the shortcut has a label defined, don't include in in the list of valid triggers per shortcut numberOfValidTriggers = this.triggersPerShortcut[shortcutId].length - (shortcut.label ? 1 : 0); } else { numberOfValidTriggers = shortcut.label ? 1 : 0; diff --git a/src/shortcuts/Shortcuts.json b/src/shortcuts/Shortcuts.json index 81f7def7ea..6e8215297b 100644 --- a/src/shortcuts/Shortcuts.json +++ b/src/shortcuts/Shortcuts.json @@ -48,6 +48,7 @@ }, { "type": "CreatorBase", "id": "StagingCreator", + "label": "#staging", "name": "staging", "subtype": "menu", "getData": null, @@ -113,6 +114,7 @@ }, { "type": "CreatorBase", "id": "ProgressionCreator", + "label": "#disease status", "name": "disease status", "subtype": "menu", "getData": null, @@ -193,6 +195,7 @@ }, { "type": "CreatorBase", "id": "ToxicityCreator", + "label": "#toxicity", "name": "toxicity", "subtype": "menu", "getData": null, @@ -563,6 +566,7 @@ }, { "type": "CreatorBase", "id": "MedicationChangeReduceCreator", + "label": "#reduce medication", "name": "reduce medication", "subtype": "menu", "getData": null, From 6c88a5109b78093358f6d87ccfac36b683b03a84 Mon Sep 17 00:00:00 2001 From: Dylan Phelan Date: Tue, 15 Oct 2019 13:02:43 -0400 Subject: [PATCH 5/5] removed logs --- src/shortcuts/CreatorIntermediary.jsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/shortcuts/CreatorIntermediary.jsx b/src/shortcuts/CreatorIntermediary.jsx index d44c2dfdae..e1ef4ee005 100644 --- a/src/shortcuts/CreatorIntermediary.jsx +++ b/src/shortcuts/CreatorIntermediary.jsx @@ -128,7 +128,6 @@ export default class CreatorIntermediary extends Shortcut { get potentialParents() { const knownParent = this.metadata["knownParentContexts"]; if (knownParent === 'Patient' || knownParent === undefined) return []; - console.log(knownParent); if (_.isArray(knownParent)) { return knownParent; } else if (_.isString(knownParent)) {