From 9debc08d8dabe630682a6be614d2d670f591f3c5 Mon Sep 17 00:00:00 2001 From: Ruslan Forostianov Date: Wed, 2 Oct 2024 17:18:58 +0200 Subject: [PATCH 1/5] Implement RFC85 Dynamic Virtual Study Added option to select a dynamic type of virtual study while creating it Static type (the legacy one) is the default one --- src/globalStyles/global.scss | 8 ++ .../studyView/virtualStudy/VirtualStudy.tsx | 85 +++++++++++++++++++ 2 files changed, 93 insertions(+) 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/virtualStudy/VirtualStudy.tsx b/src/pages/studyView/virtualStudy/VirtualStudy.tsx index 4a492d847c4..b933c17cf98 100644 --- a/src/pages/studyView/virtualStudy/VirtualStudy.tsx +++ b/src/pages/studyView/virtualStudy/VirtualStudy.tsx @@ -98,6 +98,7 @@ export default class VirtualStudy extends React.Component< > { @observable.ref private name: string; @observable.ref private description: string; + @observable.ref private isDynamic: boolean = false; @observable private saving = false; @observable private sharing = false; @@ -167,6 +168,7 @@ export default class VirtualStudy extends React.Component< study => study.studyId ), studies: studies, + isDynamic: this.isDynamic, }; return await sessionServiceClient.saveVirtualStudy( parameters, @@ -298,6 +300,89 @@ export default class VirtualStudy extends React.Component< /> +
+ + + + +

+ + Type of Virtual + Study: + +

+

+ A Virtual Study is a + set of sample IDs + derived from + selected studies. + This set can be + defined as either + static or dynamic: +

+
    +
  • + + Static + {' '} + – Sample IDs are + captured at the + time of creation + and do not + update, even + when the data in + the parent + studies changes. +
  • +
  • + + Dynamic + {' '} + – Sample IDs are + automatically + refreshed to + reflect any + changes in the + parent studies, + ensuring the + virtual study + stays + up-to-date. +
  • +
+
+ } + > + + + +
{this.showSaveButton && (
From 4b49f4fb01a94fb39bd9aea00bc0c74338ced210 Mon Sep 17 00:00:00 2001 From: Ruslan Forostianov Date: Wed, 23 Oct 2024 19:48:32 +0200 Subject: [PATCH 4/5] Update description for dynamic/static VS if blank or default --- src/pages/studyView/StudyViewUtils.tsx | 16 +++---- .../studyView/virtualStudy/VirtualStudy.tsx | 44 +++++++++++-------- 2 files changed, 32 insertions(+), 28 deletions(-) diff --git a/src/pages/studyView/StudyViewUtils.tsx b/src/pages/studyView/StudyViewUtils.tsx index e2e8b78bc78..d25188b0b29 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,13 @@ 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' : ''})` + descriptionLines.push(`- ${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 3b78421e729..6079ffa8800 100644 --- a/src/pages/studyView/virtualStudy/VirtualStudy.tsx +++ b/src/pages/studyView/virtualStudy/VirtualStudy.tsx @@ -97,7 +97,7 @@ export default class VirtualStudy extends React.Component< {} > { @observable.ref private name: string; - @observable.ref private description: string; + @observable.ref private description: string = ''; @observable.ref private dynamic: boolean = false; @observable private saving = false; @@ -108,17 +108,7 @@ 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 - ); + this.setDynamicTypeTo(false); } @computed get namePlaceHolder() { @@ -233,6 +223,28 @@ export default class VirtualStudy extends React.Component< ); } + updateDescriptionIfBlankOrDefault(hideSampleCounts: boolean) { + const getVirtualStudyDescriptionWithCounts = getVirtualStudyDescription.bind(null, + this.props.description, + this.props.studyWithSamples, + this.props.filter, + this.attributeNamesSet, + this.props.molecularProfileNameSet, + this.props.caseListNameSet, + this.props.user + ); + const blankOrDefaultDescription = !this.description || !this.description.trim() || this.description === getVirtualStudyDescriptionWithCounts(!hideSampleCounts); + if (blankOrDefaultDescription) { + this.description = getVirtualStudyDescriptionWithCounts(hideSampleCounts); + } + } + + setDynamicTypeTo(dynamic: boolean) { + this.dynamic = dynamic; + + this.updateDescriptionIfBlankOrDefault(dynamic); + } + render() { return (
- (this.dynamic = false) - } + onChange={_ => this.setDynamicTypeTo(false) } />{' '} Static @@ -320,9 +330,7 @@ export default class VirtualStudy extends React.Component< name="option" value="dynamic" checked={this.dynamic} - onChange={_ => - (this.dynamic = true) - } + onChange={_ => this.setDynamicTypeTo(true) } />{' '} Dynamic From 869cf79c44e414a1a9066abc8c5b6ece31176b2a Mon Sep 17 00:00:00 2001 From: Ruslan Forostianov Date: Tue, 5 Nov 2024 21:52:12 +0100 Subject: [PATCH 5/5] Make VS code Prettier --- src/pages/studyView/StudyViewUtils.tsx | 19 ++++- .../studyView/virtualStudy/VirtualStudy.tsx | 73 ++++++++++++++----- 2 files changed, 68 insertions(+), 24 deletions(-) diff --git a/src/pages/studyView/StudyViewUtils.tsx b/src/pages/studyView/StudyViewUtils.tsx index d25188b0b29..06c56f02131 100644 --- a/src/pages/studyView/StudyViewUtils.tsx +++ b/src/pages/studyView/StudyViewUtils.tsx @@ -918,13 +918,24 @@ export function getVirtualStudyDescription( _.flatMap(studyWithSamples, study => study.uniqueSampleKeys) ); descriptionLines.push( - (hideSampleCounts ? 'Samples' : `${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}` - + (hideSampleCounts ? '' : ` (${studyObj.uniqueSampleKeys.length} sample${uniqueSampleKeys.length > 1 ? 's' : ''})`) + descriptionLines.push( + `- ${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 6079ffa8800..bd5898cd8ae 100644 --- a/src/pages/studyView/virtualStudy/VirtualStudy.tsx +++ b/src/pages/studyView/virtualStudy/VirtualStudy.tsx @@ -224,7 +224,8 @@ export default class VirtualStudy extends React.Component< } updateDescriptionIfBlankOrDefault(hideSampleCounts: boolean) { - const getVirtualStudyDescriptionWithCounts = getVirtualStudyDescription.bind(null, + const getVirtualStudyDescriptionWithCounts = getVirtualStudyDescription.bind( + null, this.props.description, this.props.studyWithSamples, this.props.filter, @@ -233,9 +234,15 @@ export default class VirtualStudy extends React.Component< this.props.caseListNameSet, this.props.user ); - const blankOrDefaultDescription = !this.description || !this.description.trim() || this.description === getVirtualStudyDescriptionWithCounts(!hideSampleCounts); + const blankOrDefaultDescription = + !this.description || + !this.description.trim() || + this.description === + getVirtualStudyDescriptionWithCounts(!hideSampleCounts); if (blankOrDefaultDescription) { - this.description = getVirtualStudyDescriptionWithCounts(hideSampleCounts); + this.description = getVirtualStudyDescriptionWithCounts( + hideSampleCounts + ); } } @@ -320,7 +327,11 @@ export default class VirtualStudy extends React.Component< name="option" value="static" checked={!this.dynamic} - onChange={_ => this.setDynamicTypeTo(false) } + onChange={_ => + this.setDynamicTypeTo( + false + ) + } />{' '} Static @@ -330,7 +341,11 @@ export default class VirtualStudy extends React.Component< name="option" value="dynamic" checked={this.dynamic} - onChange={_ => this.setDynamicTypeTo(true) } + onChange={_ => + this.setDynamicTypeTo( + true + ) + } />{' '} Dynamic @@ -346,12 +361,14 @@ export default class VirtualStudy extends React.Component<

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

  • @@ -359,22 +376,38 @@ export default class VirtualStudy extends React.Component< 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. + 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. + – 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.