Skip to content

Commit

Permalink
Merge branch 'restyle-oncoprint-annotation-menu' of https://github.co…
Browse files Browse the repository at this point in the history
…m/BasLee/cbioportal-frontend into restyle-oncoprint-annotation-menu
  • Loading branch information
Bas Leenknegt committed Aug 31, 2023
2 parents 4906912 + 64c97e8 commit b05bf02
Show file tree
Hide file tree
Showing 6 changed files with 186 additions and 71 deletions.
5 changes: 1 addition & 4 deletions end-to-end-test/local/runtime-config/portal.properties
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,8 @@ app.name=cbioportal
# database
db.user=cbio_user
db.password=somepassword
db.host=cbioportal-database-container
db.portal_db_name=cbioportal
db.driver=com.mysql.jdbc.Driver
db.connection_string=jdbc:mysql://cbioportal-database-container/
db.connection_string=jdbc:mysql://cbioportal-database:3306/cbioportal?useSSL=false&allowPublicKeyRetrieval=true
# set tomcat_resource_name when using dbconnector=jndi instead of the default
# dbconnector=dbcp. Note that dbconnector needs to be set in CATLINA_OPTS when
# using Tomcat (CATALINA_OPTS="-Ddbconnector=jndi"). It does not get picked up
Expand All @@ -18,7 +16,6 @@ db.connection_string=jdbc:mysql://cbioportal-database-container/

# this should normally be set to false. In some cases you could set this to true (e.g. for testing a feature of a newer release that is not related to the schema change in expected db version above):
db.suppress_schema_version_mismatch_errors=false
db.use_ssl=false
# web page cosmetics
skin.title=Local cBioPortal instance
skin.email_contact=cbioportal at googlegroups dot com
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
237 changes: 181 additions & 56 deletions src/pages/patientView/PatientViewPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,16 @@ import _ from 'lodash';
import { DiscreteCopyNumberData, ResourceData } from 'cbioportal-ts-api-client';
import { PaginationControls } from '../../shared/components/paginationControls/PaginationControls';
import { IColumnVisibilityDef } from 'shared/components/columnVisibilityControls/ColumnVisibilityControls';
import { toggleColumnVisibility } from 'cbioportal-frontend-commons';
import {
DefaultTooltip,
toggleColumnVisibility,
} from 'cbioportal-frontend-commons';
import {
PatientViewPageStore,
buildCohortIdsFromNavCaseIds,
} from './clinicalInformation/PatientViewPageStore';
import { inject, observer } from 'mobx-react';
import { action, computed, observable, makeObservable } from 'mobx';
import { action, computed, observable, makeObservable, toJS } from 'mobx';
import { default as PatientViewMutationTable } from './mutation/PatientViewMutationTable';
import { MSKTab } from '../../shared/components/MSKTabs/MSKTabs';
import ValidationAlert from 'shared/components/ValidationAlert';
Expand All @@ -18,7 +21,11 @@ import PatientViewCnaDataStore from './copyNumberAlterations/PatientViewCnaDataS

import './patient.scss';

import { getWholeSlideViewerUrl } from '../../shared/api/urls';
import {
buildCBioPortalPageUrl,
getPatientViewUrl,
getWholeSlideViewerUrl,
} from '../../shared/api/urls';
import { PageLayout } from '../../shared/components/PageLayout/PageLayout';
import Helmet from 'react-helmet';
import { getServerConfig } from '../../config/config';
Expand Down Expand Up @@ -55,11 +62,13 @@ import { prepareCustomTabConfigurations } from 'shared/lib/customTabs/customTabH
import setWindowVariable from 'shared/lib/setWindowVariable';
import { getNavCaseIdsCache } from 'shared/lib/handleLongUrls';
import PatientViewPageHeader from 'pages/patientView/PatientViewPageHeader';
import { MAX_URL_LENGTH } from 'pages/studyView/studyPageHeader/ActionButtons';

export interface IPatientViewPageProps {
routing: any;
appStore: AppStore;
cohortIds?: string[];
onCohortIdsUpdate: (ids: string[]) => void;
}

export interface IGenePanelModal {
Expand Down Expand Up @@ -87,15 +96,14 @@ export default class PatientViewPage extends React.Component<
IPatientViewPageProps,
{}
> {
cohortIds: string[] | undefined;
@observable cohortIds: string[] | undefined;

constructor(props: IPatientViewPageProps) {
super(props);

makeObservable(this);
const postData = getBrowserWindow().clientPostedData;

const urlData = getNavCaseIdsCache();

if (postData && postData.navCaseIds) {
this.cohortIds = buildCohortIdsFromNavCaseIds(postData.navCaseIds);
getBrowserWindow().clientPostedData = null;
Expand All @@ -104,12 +112,18 @@ export default class PatientViewPage extends React.Component<
}
}

@action.bound
updateCohortIds(newCohortIds: string[]) {
this.cohortIds = newCohortIds;
}

render() {
return (
<PatientViewPageInner
key={`${this.props.routing.query.caseId}-${this.props.routing.query.studyId}-${this.props.routing.query.sampleId}`}
{...this.props}
cohortIds={this.cohortIds}
onCohortIdsUpdate={this.updateCohortIds}
/>
);
}
Expand Down Expand Up @@ -544,6 +558,70 @@ export class PatientViewPageInner extends React.Component<
return this.patientViewPageStore;
}

@action.bound
private handleReturnToStudyView() {
const patientIdentifiers = this.pageStore.patientIdsInCohort.map(p => {
const patientIdParts = p.split(':');
return {
patientId: patientIdParts[1],
studyId: patientIdParts[0],
};
});
const queriedStudies: Set<string> = new Set(
patientIdentifiers.map(p => p.studyId)
);

// We need to do this because of url length limits. We post the data to the new window once it is opened.
const studyPage = window.open(
buildCBioPortalPageUrl(`study`, {
id: Array.from(queriedStudies).join(','),
}),
'_blank'
);
if (patientIdentifiers.length > 0) {
(studyPage as any).studyPageFilter = `filterJson=${JSON.stringify({
patientIdentifiers,
})}`;
}
}

@action.bound
private handleDeletePatient(deleteAtIndex: number) {
var newCohortIdList = toJS(this.pageStore.patientIdsInCohort);
newCohortIdList.splice(deleteAtIndex, 1);
let currentIndex =
deleteAtIndex > newCohortIdList.length - 1
? deleteAtIndex - 1
: deleteAtIndex;

let navCaseIds = newCohortIdList.map(p => {
const patientIdParts = p.split(':');
return {
patientId: patientIdParts[1],
studyId: patientIdParts[0],
};
});
const url = getPatientViewUrl(
navCaseIds[currentIndex].studyId,
navCaseIds[currentIndex].patientId,
navCaseIds
);

// Because of url length limits, we can only maintain the list in the url hash for small sets of ids.
// TODO: adapt updateURL to allow for hash mutation so that we don't have manipulate window.location.hash directly
this.props.onCohortIdsUpdate(newCohortIdList);
if (url.length <= MAX_URL_LENGTH) {
getBrowserWindow().location.hash = url.substring(
url.indexOf('#') + 1
);
}
this.urlWrapper.updateURL({
studyId: navCaseIds[currentIndex].studyId,
caseId: navCaseIds[currentIndex].patientId,
sampleId: undefined,
});
}

@computed
public get cohortNav() {
if (
Expand All @@ -554,58 +632,105 @@ export class PatientViewPageInner extends React.Component<
this.pageStore.studyId + ':' + this.pageStore.patientId
);
return (
<PaginationControls
currentPage={indexInCohort + 1}
showMoreButton={false}
showItemsPerPageSelector={false}
showFirstPage={true}
showLastPage={true}
textBetweenButtons={` of ${this.pageStore.patientIdsInCohort.length} patients`}
firstPageDisabled={indexInCohort === 0}
previousPageDisabled={indexInCohort === 0}
nextPageDisabled={
indexInCohort ===
this.pageStore.patientIdsInCohort.length - 1
}
lastPageDisabled={
indexInCohort ===
this.pageStore.patientIdsInCohort.length - 1
}
onFirstPageClick={() =>
this.handlePatientClick(
this.pageStore.patientIdsInCohort[0]
)
}
onPreviousPageClick={() =>
this.handlePatientClick(
this.pageStore.patientIdsInCohort[indexInCohort - 1]
)
}
onNextPageClick={() =>
this.handlePatientClick(
this.pageStore.patientIdsInCohort[indexInCohort + 1]
)
}
onLastPageClick={() =>
this.handlePatientClick(
this.pageStore.patientIdsInCohort[
this.pageStore.patientIdsInCohort.length - 1
]
)
}
onChangeCurrentPage={newPage => {
if (
newPage > 0 &&
newPage <= this.pageStore.patientIdsInCohort.length
) {
<div
style={{
display: 'flex',
justifyContent: 'flex-end',
alignItems: 'center',
}}
>
<PaginationControls
currentPage={indexInCohort + 1}
showMoreButton={false}
showItemsPerPageSelector={false}
showFirstPage={true}
showLastPage={true}
textBetweenButtons={
<>
<span> of </span>
<DefaultTooltip
placement="bottom"
overlay="Open all patients in study view"
>
<a
onClick={this.handleReturnToStudyView}
target={'_blank'}
>
{`${this.pageStore.patientIdsInCohort.length} patients`}
</a>
</DefaultTooltip>
</>
}
firstPageDisabled={indexInCohort === 0}
previousPageDisabled={indexInCohort === 0}
nextPageDisabled={
indexInCohort ===
this.pageStore.patientIdsInCohort.length - 1
}
lastPageDisabled={
indexInCohort ===
this.pageStore.patientIdsInCohort.length - 1
}
onFirstPageClick={() =>
this.handlePatientClick(
this.pageStore.patientIdsInCohort[newPage - 1]
);
this.pageStore.patientIdsInCohort[0]
)
}
}}
pageNumberEditable={true}
className="cohortNav"
/>
onPreviousPageClick={() =>
this.handlePatientClick(
this.pageStore.patientIdsInCohort[
indexInCohort - 1
]
)
}
onNextPageClick={() =>
this.handlePatientClick(
this.pageStore.patientIdsInCohort[
indexInCohort + 1
]
)
}
onLastPageClick={() =>
this.handlePatientClick(
this.pageStore.patientIdsInCohort[
this.pageStore.patientIdsInCohort.length - 1
]
)
}
onChangeCurrentPage={newPage => {
if (
newPage > 0 &&
newPage <=
this.pageStore.patientIdsInCohort.length
) {
this.handlePatientClick(
this.pageStore.patientIdsInCohort[
newPage - 1
]
);
}
}}
pageNumberEditable={true}
className="cohortNav"
/>
<DefaultTooltip
placement="bottom"
overlay="Exclude the current patient"
>
<span
style={{
marginLeft: '5px',
display: 'inline-block',
cursor: 'pointer',
}}
onClick={() =>
this.handleDeletePatient(indexInCohort)
}
>
<i className={'fa fa-minus-circle'} />
</span>
</DefaultTooltip>
</div>
);
}
}
Expand Down
4 changes: 3 additions & 1 deletion src/shared/alterationFiltering/SettingsMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,9 @@ export default class SettingsMenu extends React.Component<
display: 'inline-block',
marginLeft: 6,
}}
tooltip={<>Exclude germline samples</>}
tooltip={
<>Exclude germline mutations</>
}
/>
</label>
</div>
Expand Down
9 changes: 0 additions & 9 deletions src/shared/components/lazyMobXTable/LazyMobXTable.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -125,15 +125,6 @@ function getNumVisibleRows(table: ReactWrapper<any, any>): number {
return getVisibleRows(table).length;
}

function getTextBetweenButtons(
table: ReactWrapper<any, any>
): string | undefined {
return table
.find(PaginationControls)
.filterWhere(x => x.hasClass('topPagination'))
.props().textBetweenButtons;
}

function getTextBeforeButtons(
table: ReactWrapper<any, any>
): string | undefined {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export interface IPaginationControlsProps {
showAllOption?: boolean;
showMoreButton?: boolean;
textBeforeButtons?: string;
textBetweenButtons?: string;
textBetweenButtons?: string | JSX.Element;
firstButtonContent?: string | JSX.Element;
previousButtonContent?: string | JSX.Element;
nextButtonContent?: string | JSX.Element;
Expand Down

0 comments on commit b05bf02

Please sign in to comment.