From 10c0bde6032d844d5505c325b202f7483c614514 Mon Sep 17 00:00:00 2001 From: Dave Falke Date: Tue, 31 Oct 2023 15:24:49 -0400 Subject: [PATCH] Add a record page that can be embedded in popups --- .../wdk-client/src/Actions/RecordActions.ts | 21 ++++++-- .../src/Controllers/RecordController.tsx | 52 ++++++++++++++++--- packages/libs/wdk-client/src/Core/routes.tsx | 20 +++++++ .../js/client/componentWrappers.jsx | 47 +++++++---------- 4 files changed, 99 insertions(+), 41 deletions(-) diff --git a/packages/libs/wdk-client/src/Actions/RecordActions.ts b/packages/libs/wdk-client/src/Actions/RecordActions.ts index 0baac023fe..efec321c3a 100644 --- a/packages/libs/wdk-client/src/Actions/RecordActions.ts +++ b/packages/libs/wdk-client/src/Actions/RecordActions.ts @@ -325,17 +325,23 @@ interface RequestRequestOptionsGetter { ): RecordRequestOptions[]; } +interface CategoryTreePruner { + (recordClass: RecordClass, categoryTree: CategoryTreeNode): CategoryTreeNode; +} + /** Fetch page data from services */ export function loadRecordData( recordClass: string, primaryKeyValues: string[], - getRecordRequestOptions: RequestRequestOptionsGetter + getRecordRequestOptions: RequestRequestOptionsGetter, + pruneCategoryTree: CategoryTreePruner ): ActionThunk { return function run({ wdkService }) { return setActiveRecord( recordClass, primaryKeyValues, - getRecordRequestOptions + getRecordRequestOptions, + pruneCategoryTree ); }; } @@ -350,7 +356,8 @@ export function loadRecordData( function setActiveRecord( recordClassUrlSegment: string, primaryKeyValues: string[], - getRecordRequestOptions: RequestRequestOptionsGetter + getRecordRequestOptions: RequestRequestOptionsGetter, + pruneCategoryTree: CategoryTreePruner ): ActionThunk { return ({ wdkService }) => { const id = uniqueId('recordViewId'); @@ -364,10 +371,14 @@ function setActiveRecord( getCategoryTree(wdkService, recordClassUrlSegment), ]).then( ([recordClass, primaryKey, fullCategoryTree]) => { + const prunedCategoryTree = pruneCategoryTree( + recordClass, + fullCategoryTree + ); const [initialOptions, ...additionalOptions] = - getRecordRequestOptions(recordClass, fullCategoryTree); + getRecordRequestOptions(recordClass, prunedCategoryTree); const categoryTree = getTree( - { name: '__', tree: fullCategoryTree }, + { name: '__', tree: prunedCategoryTree }, isNotInternalNode ); const initialAction$ = wdkService diff --git a/packages/libs/wdk-client/src/Controllers/RecordController.tsx b/packages/libs/wdk-client/src/Controllers/RecordController.tsx index 6453d0ac2b..fa60096a42 100644 --- a/packages/libs/wdk-client/src/Controllers/RecordController.tsx +++ b/packages/libs/wdk-client/src/Controllers/RecordController.tsx @@ -1,3 +1,4 @@ +// TODO When in "embed mode", disable coallpsing, hiding, and TOC import { isEqual } from 'lodash'; import * as React from 'react'; import { connect } from 'react-redux'; @@ -18,7 +19,12 @@ import { requestPartialRecord, } from '../Actions/RecordActions'; -import { CategoryTreeNode } from '../Utils/CategoryUtils'; +import { + CategoryTreeNode, + getNodeId, + getRecordClassName, + getScopes, +} from '../Utils/CategoryUtils'; import { stripHTML } from '../Utils/DomUtils'; import { RecordClass } from '../Utils/WdkModel'; import { @@ -27,6 +33,7 @@ import { getTableNames, } from '../Views/Records/RecordUtils'; import { RootState } from '../Core/State/Types'; +import { preorderSeq } from '../Utils/TreeUtils'; const ActionCreators = { ...UserActionCreators, @@ -42,7 +49,12 @@ const ActionCreators = { type StateProps = RootState['record']; type DispatchProps = typeof ActionCreators; -type OwnProps = { recordClass: string; primaryKey: string }; +type OwnProps = { + recordClass: string; + primaryKey: string; + attributes?: string[]; + tables?: string[]; +}; type Props = { ownProps: OwnProps } & StateProps & DispatchProps; // FIXME Remove when RecordUI is converted to Typescript @@ -77,16 +89,39 @@ class RecordController extends PageController { // all attributes { attributes: getAttributeNames(categoryTree), - tables: [], - }, - // all tables - { - attributes: [], tables: getTableNames(categoryTree), }, ]; } + pruneCategoryTree( + recordClass: RecordClass, + categoryTree: CategoryTreeNode + ): CategoryTreeNode { + const { attributes, tables } = this.props.ownProps; + if (attributes || tables) { + const nodes = preorderSeq(categoryTree) + .filter((node) => { + const recordClassName = getRecordClassName(node); + const id = getNodeId(node); + const scopes = getScopes(node); + if (recordClassName !== recordClass.fullName) return false; + return ( + attributes?.includes(id) || + tables?.includes(id) || + scopes.includes('record-internal') + ); + }) + .toArray(); + const root: CategoryTreeNode = { + properties: {}, + children: nodes, + }; + return root; + } + return categoryTree; + } + isRenderDataLoaded() { return ( this.props.recordClass != null && @@ -133,7 +168,8 @@ class RecordController extends PageController { this.props.loadRecordData( recordClass, pkValues, - this.getRecordRequestOptions + this.getRecordRequestOptions.bind(this), + this.pruneCategoryTree.bind(this) ); } } diff --git a/packages/libs/wdk-client/src/Core/routes.tsx b/packages/libs/wdk-client/src/Core/routes.tsx index c1a594cfa4..da3522871d 100644 --- a/packages/libs/wdk-client/src/Core/routes.tsx +++ b/packages/libs/wdk-client/src/Core/routes.tsx @@ -146,6 +146,26 @@ const routes: RouteEntry[] = [ ) => , }, + { + path: '/embed-record/:recordClass/:primaryKey+', + isFullscreen: true, + component: ( + props: RouteComponentProps<{ recordClass: string; primaryKey: string }> + ) => { + const { attributes = '', tables = '' } = parseQueryString(props); + return ( +
+ +
+ ); + }, + }, + { path: '/step/:stepId(\\d+)/download', component: (props: RouteComponentProps<{ stepId: string }>) => { diff --git a/packages/sites/genomics-site/webapp/wdkCustomization/js/client/componentWrappers.jsx b/packages/sites/genomics-site/webapp/wdkCustomization/js/client/componentWrappers.jsx index 769fff2723..09d2dc5338 100644 --- a/packages/sites/genomics-site/webapp/wdkCustomization/js/client/componentWrappers.jsx +++ b/packages/sites/genomics-site/webapp/wdkCustomization/js/client/componentWrappers.jsx @@ -65,11 +65,19 @@ export function RecordController(WdkRecordController) { recordClass, categoryTree ); + + // This is a request for a custom page, so use default + // request props. + if (this.props.attributes || this.props.tables) { + return requestOptions; + } + if ( recordClass.urlSegment !== 'gene' && recordClass.urlSegment !== 'dataset' - ) + ) { return requestOptions; + } // Dataset records if (recordClass.urlSegment === 'dataset') { @@ -84,34 +92,17 @@ export function RecordController(WdkRecordController) { // Gene records return [ { + // This includes all attributes attributes: requestOptions[0].attributes, - tables: requestOptions[0].tables - .concat(['MetaTable']) - .concat( - 'TranscriptionSummary' in recordClass.tablesMap - ? ['TranscriptionSummary'] - : [] - ) - .concat( - 'ExpressionGraphs' in recordClass.tablesMap - ? ['ExpressionGraphs'] - : [] - ) - .concat( - 'PhenotypeGraphs' in recordClass.tablesMap - ? ['PhenotypeGraphs'] - : [] - ) - .concat( - 'CrisprPhenotypeGraphs' in recordClass.tablesMap - ? ['CrisprPhenotypeGraphs'] - : [] - ) - .concat( - 'FungiVBOrgLinkoutsTable' in recordClass.tablesMap - ? ['FungiVBOrgLinkoutsTable'] - : [] - ), + // Preload these tables. Others are lazy-loaded. + tables: [ + 'MetaTable', + 'TranscriptionSummary', + 'ExpressionGraphs', + 'PhenotypeGraphs', + 'CrisprPhenotypeGraphs', + 'FungiVBOrgLinkoutsTable', + ].filter((tableName) => tableName in recordClass.tablesMap), }, ]; }