From 1f7e44ebd653dcd3ce58f3baa289cbba950dee75 Mon Sep 17 00:00:00 2001 From: Ruslan Forostianov Date: Thu, 21 Nov 2024 20:26:26 +0100 Subject: [PATCH] Implement RFC85 Dynamic Virtual Study (#5016) * Implement RFC85 Dynamic Virtual Study --------- Co-authored-by: pieterlukasse --- .../App/usageAgreements/StudyAgreement.tsx | 4 +- src/globalStyles/global.scss | 8 ++ src/pages/studyView/StudyViewUtils.tsx | 25 ++-- .../studyView/virtualStudy/VirtualStudy.tsx | 135 ++++++++++++++++-- .../virtualStudy/VirtualStudyModal.tsx | 108 +++++++------- 5 files changed, 205 insertions(+), 75 deletions(-) diff --git a/src/appShell/App/usageAgreements/StudyAgreement.tsx b/src/appShell/App/usageAgreements/StudyAgreement.tsx index b10dcf8819a..75ba1fcc0ec 100644 --- a/src/appShell/App/usageAgreements/StudyAgreement.tsx +++ b/src/appShell/App/usageAgreements/StudyAgreement.tsx @@ -71,8 +71,8 @@ export const StudyAgreement: React.FunctionComponent<{}> = function({}) { href="https://mskcc.sharepoint.com/sites/pub-ResearchDG/SitePages/Home.aspx?ga=1" target="_blank" > - MSK-IMPACT Memorial Hospital Research Data Governance publication - guidelines + MSK-IMPACT Memorial Hospital Research Data Governance + publication guidelines . , diff --git a/src/globalStyles/global.scss b/src/globalStyles/global.scss index 81f33b14a2d..7b1839b6d60 100755 --- a/src/globalStyles/global.scss +++ b/src/globalStyles/global.scss @@ -47,6 +47,14 @@ div:active { } } +.form-group-inline { + @extend .form-group; + + label { + margin-right: 6px; + } +} + .posRelative { position: relative; } diff --git a/src/pages/studyView/StudyViewUtils.tsx b/src/pages/studyView/StudyViewUtils.tsx index e2e8b78bc78..06c56f02131 100644 --- a/src/pages/studyView/StudyViewUtils.tsx +++ b/src/pages/studyView/StudyViewUtils.tsx @@ -903,7 +903,8 @@ export function getVirtualStudyDescription( attributeNamesSet: { [id: string]: string }, molecularProfileNameSet: { [id: string]: string }, caseListNameSet: { [key: string]: string }, - user?: string + user?: string, + hideSampleCounts: boolean = false ) { let descriptionLines: string[] = []; const createdOnStr = 'Created on'; @@ -917,18 +918,24 @@ export function getVirtualStudyDescription( _.flatMap(studyWithSamples, study => study.uniqueSampleKeys) ); descriptionLines.push( - `${uniqueSampleKeys.length} sample${ - uniqueSampleKeys.length > 1 ? 's' : '' - } from ${studyWithSamples.length} ${ - studyWithSamples.length > 1 ? 'studies:' : 'study:' - }` + (hideSampleCounts + ? 'Samples' + : `${uniqueSampleKeys.length} sample${ + uniqueSampleKeys.length > 1 ? 's' : '' + }`) + + ` from ${studyWithSamples.length} ${ + studyWithSamples.length > 1 ? 'studies:' : 'study:' + }` ); //add individual studies sample count studyWithSamples.forEach(studyObj => { descriptionLines.push( - `- ${studyObj.name} (${ - studyObj.uniqueSampleKeys.length - } sample${uniqueSampleKeys.length > 1 ? 's' : ''})` + `- ${studyObj.name}` + + (hideSampleCounts + ? '' + : ` (${studyObj.uniqueSampleKeys.length} sample${ + uniqueSampleKeys.length > 1 ? 's' : '' + })`) ); }); //add filters diff --git a/src/pages/studyView/virtualStudy/VirtualStudy.tsx b/src/pages/studyView/virtualStudy/VirtualStudy.tsx index 4a492d847c4..f55a3db3404 100644 --- a/src/pages/studyView/virtualStudy/VirtualStudy.tsx +++ b/src/pages/studyView/virtualStudy/VirtualStudy.tsx @@ -97,7 +97,8 @@ export default class VirtualStudy extends React.Component< {} > { @observable.ref private name: string; - @observable.ref private description: string; + @observable.ref private customDescription: string | undefined; + @observable.ref private dynamic: boolean = false; @observable private saving = false; @observable private sharing = false; @@ -107,17 +108,6 @@ export default class VirtualStudy extends React.Component< super(props); makeObservable(this); this.name = props.name || ''; - this.description = - props.description || - getVirtualStudyDescription( - this.props.description, - this.props.studyWithSamples, - this.props.filter, - this.attributeNamesSet, - this.props.molecularProfileNameSet, - this.props.caseListNameSet, - this.props.user - ); } @computed get namePlaceHolder() { @@ -167,6 +157,7 @@ export default class VirtualStudy extends React.Component< study => study.studyId ), studies: studies, + dynamic: this.dynamic, }; return await sessionServiceClient.saveVirtualStudy( parameters, @@ -231,6 +222,30 @@ export default class VirtualStudy extends React.Component< ); } + getDefuaultDescriptionByType(dynamic: boolean) { + return getVirtualStudyDescription( + this.props.description, + this.props.studyWithSamples, + this.props.filter, + this.attributeNamesSet, + this.props.molecularProfileNameSet, + this.props.caseListNameSet, + this.props.user, + dynamic + ); + } + + @computed get description() { + const noCustomDescriptionProvided = + this.customDescription == undefined || + this.customDescription === + this.getDefuaultDescriptionByType(!this.dynamic); + if (noCustomDescriptionProvided) { + return this.getDefuaultDescriptionByType(this.dynamic); + } + return this.customDescription || ''; + } + render() { return (
- (this.description = + (this.customDescription = event.currentTarget.value) } />
+
+ + + + +

+ + Type of Virtual + Study: + +

+

+ This Virtual Study + will contain the set + of sample IDs + currently selected. + Furthermore, you can + define this Virtual + Study to be either + static or dynamic: +

+
    +
  • + + Static + {' '} + – Sample IDs are + the ones + currently + selected and no + new samples are + added to this + Virtual Study + set, even if the + database gets + updated with new + samples that + match the same + filtering/selection + criteria as the + samples in the + current set. +
  • +
  • + + Dynamic + {' '} + – Unlike the + Static option, + any new samples + added to the + database that + match the + criteria of this + Virtual Study + will + automatically be + included in its + sample set. +
  • +
+
+ } + > + + + +
{this.showSaveButton && (