From 91842dfbb374afa700128cf19262a225d1d9ad3c Mon Sep 17 00:00:00 2001 From: Michael Lee Date: Tue, 21 Apr 2020 14:58:03 -0700 Subject: [PATCH] added query plot nav --- .eslintrc.json | 2 +- .prettierrc | 3 +- .../containers/DownloadConfirmation.test.tsx | 4 +- .../playground/QueryWrapperPlotNavDemo.tsx | 87 ++++--- src/lib/containers/CardContainer.tsx | 1 + src/lib/containers/CardContainerLogic.tsx | 6 +- src/lib/containers/Facets.tsx | 4 +- src/lib/containers/QueryWrapper.tsx | 9 +- src/lib/containers/QueryWrapperPlotNav.tsx | 73 ------ src/lib/containers/TotalQueryResults.tsx | 57 +++-- .../query_wrapper_plot_nav/FilterAndView.tsx | 44 ++++ .../QueryWrapperPlotNav.tsx | 136 +++++++++++ src/lib/containers/table/SynapseTable.tsx | 120 +++++----- .../containers/widgets/facet-nav/FacetNav.tsx | 214 ++++++++++-------- .../widgets/facet-nav/FacetNavPanel.tsx | 30 ++- .../facet-nav/SelectionCriteriaPill.tsx | 18 +- .../widgets/query-filter/QueryFilter.tsx | 22 +- src/lib/style/components/_all.scss | 4 +- .../components/_query-wrapper-plot-nav.scss | 20 ++ 19 files changed, 509 insertions(+), 345 deletions(-) delete mode 100644 src/lib/containers/QueryWrapperPlotNav.tsx create mode 100644 src/lib/containers/query_wrapper_plot_nav/FilterAndView.tsx create mode 100644 src/lib/containers/query_wrapper_plot_nav/QueryWrapperPlotNav.tsx create mode 100644 src/lib/style/components/_query-wrapper-plot-nav.scss diff --git a/.eslintrc.json b/.eslintrc.json index d34cb6b23d..dacf10860d 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -1,6 +1,6 @@ { "extends": ["react-app", "eslint:recommended", "plugin:react/recommended"], - "plugins": ["react", "react-hooks"], + "plugins": ["react", "react-hooks"], "parserOptions": { "ecmaFeatures": { "jsx": true diff --git a/.prettierrc b/.prettierrc index 2876780095..b3b9004522 100644 --- a/.prettierrc +++ b/.prettierrc @@ -2,5 +2,6 @@ "semi": false, "trailingComma": "all", "singleQuote": true, - "printWidth": 80 + "printWidth": 80, + "arrowParens": "avoid" } diff --git a/src/__tests__/lib/containers/DownloadConfirmation.test.tsx b/src/__tests__/lib/containers/DownloadConfirmation.test.tsx index 67761eb165..4b3b31caca 100644 --- a/src/__tests__/lib/containers/DownloadConfirmation.test.tsx +++ b/src/__tests__/lib/containers/DownloadConfirmation.test.tsx @@ -90,7 +90,7 @@ const resolveAllPending = async ( await act( async (): Promise => { await Promise.resolve(wrapper) - await new Promise(resolve => setImmediate(resolve)) + await new Promise((resolve) => setImmediate(resolve)) wrapper.update() return wrapper }, @@ -110,7 +110,7 @@ describe('it performs the expected functionality', () => { const props: DownloadConfirmationProps = { fnClose: mockClose, token: '12345', - queryBundleRequest: queryBundleRequest, + lastQueryRequest: queryBundleRequest, } beforeEach(() => { diff --git a/src/demo/containers/playground/QueryWrapperPlotNavDemo.tsx b/src/demo/containers/playground/QueryWrapperPlotNavDemo.tsx index 11d141d115..804a6b9629 100644 --- a/src/demo/containers/playground/QueryWrapperPlotNavDemo.tsx +++ b/src/demo/containers/playground/QueryWrapperPlotNavDemo.tsx @@ -1,61 +1,65 @@ import * as React from 'react' -import { SynapseConstants } from '../../../lib/utils' -import QueryWrapperPlotNav, { QueryWrapperPlotNavProps } from 'lib/containers/QueryWrapperPlotNav' +import QueryWrapperPlotNav, { + QueryWrapperPlotNavProps, +} from 'lib/containers/query_wrapper_plot_nav/QueryWrapperPlotNav' +import { SynapseConstants } from 'lib' type DemoState = { ownerId: string isLoading: boolean showMarkdown: boolean - version: number - tableProps: QueryWrapperPlotNavProps - activeTab: number + propsWithTable: QueryWrapperPlotNavProps + propsWithCards: QueryWrapperPlotNavProps + showCards: boolean } /** * Demo of features that can be used from src/demo/utils/SynapseClient * module */ -class QueryWrapperPlotNavDemo extends React.Component<{}, - DemoState -> { +class QueryWrapperPlotNavDemo extends React.Component<{}, DemoState> { /** * Maintain internal state of user session */ constructor(props: any) { super(props) - const sql:string = - "SELECT * FROM syn16858331" + const sql: string = 'SELECT * FROM syn16858331' this.state = { isLoading: true, ownerId: '', showMarkdown: true, - activeTab: 3, - version: 0, - tableProps: - { - title: 'Test only', + showCards: false, + propsWithTable: { + tableConfiguration: { + loadingScreen: <> I'm loading as fast as I can!!!! , + }, + rgbIndex: 1, + name: 'PlotNav Demo', + sqlOperator: '=', + sql, + entityId: 'syn16858331', + // facetsToPlot: ['assay', 'dataType'], + loadingScreen: ( +
+
Im loading as fast I can !!!{' '} +
+ ), + frontText: 'Showing', + }, + propsWithCards: { + rgbIndex: 1, + name: 'PlotNav Demo', sqlOperator: '=', - unitDescription: 'datum', - initQueryRequest:{ - entityId: 'syn16858331', - concreteType: - 'org.sagebionetworks.repo.model.table.QueryBundleRequest', - partMask: - SynapseConstants.BUNDLE_MASK_QUERY_COLUMN_MODELS | - SynapseConstants.BUNDLE_MASK_QUERY_FACETS | - SynapseConstants.BUNDLE_MASK_QUERY_SELECT_COLUMNS | - SynapseConstants.BUNDLE_MASK_QUERY_COUNT | - SynapseConstants.BUNDLE_MASK_QUERY_RESULTS, - query: { - sql, - limit: 25, - offset: 0, + sql, + entityId: 'syn16858331', + cardConfiguration: { + type: SynapseConstants.GENERIC_CARD, + genericCardSchema: { + title: 'id', + type: SynapseConstants.STUDY, }, }, - enableLeftFacetFilter: true, - rgbIndex: 5, - // facetsToPlot: ['assay', 'dataType'], - loadingScreen:
Im loading as fast I can !!!
- } + frontText: 'Showing', + }, } this.handleChange = this.handleChange.bind(this) this.removeHandler = this.removeHandler.bind(this) @@ -74,10 +78,21 @@ class QueryWrapperPlotNavDemo extends React.Component<{}, } public render(): JSX.Element { + const { showCards } = this.state + const propsForPlotNav = this.state.showCards + ? this.state.propsWithCards + : this.state.propsWithTable return (

Demo of plot nav table

- + +
) } diff --git a/src/lib/containers/CardContainer.tsx b/src/lib/containers/CardContainer.tsx index c9435cbbe6..6b0a02e688 100644 --- a/src/lib/containers/CardContainer.tsx +++ b/src/lib/containers/CardContainer.tsx @@ -23,6 +23,7 @@ export type CardContainerProps = { facetAliases?: {} getLastQueryRequest?: () => QueryBundleRequest getNextPageOfData?: (queryRequest: QueryBundleRequest) => void + lastQueryRequest?: QueryBundleRequest isLoading?: boolean facet?: string unitDescription?: string diff --git a/src/lib/containers/CardContainerLogic.tsx b/src/lib/containers/CardContainerLogic.tsx index 7b75061915..ab987379b7 100644 --- a/src/lib/containers/CardContainerLogic.tsx +++ b/src/lib/containers/CardContainerLogic.tsx @@ -43,6 +43,7 @@ export type CommonCardProps = { } export type CardConfiguration = { + enableLeftFacetFilter?: boolean type: string hasInternalLink?: boolean iconOptions?: IconOptions @@ -164,7 +165,7 @@ export default class CardContainerLogic extends React.Component< queryRequest, this.state.data!, this.props.token, - ).then(newState => { + ).then((newState) => { this.setState({ ...newState, isLoading: false, @@ -233,7 +234,7 @@ export default class CardContainerLogic extends React.Component< } this.setState(newState) }) - .catch(err => { + .catch((err) => { console.log('Failed to get data ', err) }) } @@ -251,6 +252,7 @@ export default class CardContainerLogic extends React.Component< token={token} getLastQueryRequest={this.getLastQueryRequest} getNextPageOfData={this.getNextPageOfData} + lastQueryRequest={cloneDeep(this.state.queryRequest)} hasMoreData={this.state.hasMoreData} isLoading={this.state.isLoading} /> diff --git a/src/lib/containers/Facets.tsx b/src/lib/containers/Facets.tsx index 5d9b79928c..7df75293a4 100644 --- a/src/lib/containers/Facets.tsx +++ b/src/lib/containers/Facets.tsx @@ -166,7 +166,7 @@ class Facets extends React.Component { } // Find the facetcolumn result according to the input filter const facetColumnResult = this.props.data!.facets!.find( - el => + (el) => el.columnName === this.props.facet && el.facetType === 'enumeration', ) as FacetColumnResultValues if (!facetColumnResult) { @@ -283,7 +283,7 @@ class Facets extends React.Component { ) } const curFacetsIndex = facets.findIndex( - curFacet => + (curFacet) => curFacet.columnName === facet && curFacet.facetType === 'enumeration', ) // cast is necessary because filter returns an array of arrays diff --git a/src/lib/containers/QueryWrapper.tsx b/src/lib/containers/QueryWrapper.tsx index e6562928c4..a4264f94ec 100644 --- a/src/lib/containers/QueryWrapper.tsx +++ b/src/lib/containers/QueryWrapper.tsx @@ -185,14 +185,15 @@ export default class QueryWrapper extends React.Component< * @memberof QueryWrapper */ public executeQueryRequest(queryRequest: QueryBundleRequest) { + const clonedQueryRequest = cloneDeep(queryRequest) this.setState({ isLoading: true, - lastQueryRequest: cloneDeep(queryRequest), + lastQueryRequest: clonedQueryRequest, }) - if (queryRequest.query) { + if (clonedQueryRequest.query) { const stringifiedQuery = encodeURIComponent( - JSON.stringify(queryRequest.query), + JSON.stringify(clonedQueryRequest.query), ) if (this.props.shouldDeepLink) { DeepLinkingUtils.updateUrlWithNewSearchParam( @@ -203,7 +204,7 @@ export default class QueryWrapper extends React.Component< } } return SynapseClient.getQueryTableResults( - queryRequest, + clonedQueryRequest, this.props.token, this.updateParentState, ) diff --git a/src/lib/containers/QueryWrapperPlotNav.tsx b/src/lib/containers/QueryWrapperPlotNav.tsx deleted file mode 100644 index 2a23be68fe..0000000000 --- a/src/lib/containers/QueryWrapperPlotNav.tsx +++ /dev/null @@ -1,73 +0,0 @@ -import * as React from 'react' -import { QueryWrapperProps } from './QueryWrapper' -import QueryWrapper from './QueryWrapper' -//import FacetsPlotNav, { FacetsPlotNavProps } from './FacetsPlotNav' - -import FacetNav, {FacetNavOwnProps} from './widgets/facet-nav/FacetNav' -import { SynapseTableProps } from './table/SynapseTable' -import SynapseTable from './table/SynapseTable' -import { - insertConditionsFromSearchParams, - SQLOperator, -} from '../utils/functions/sqlFunctions' - -type SearchParams = { - searchParams?: { - facetValue: string - } -} -type Operator = { - sqlOperator: SQLOperator -} -export type QueryWrapperPlotNavProps = QueryWrapperProps & - Partial & - Partial & - SearchParams & - Operator - -const QueryWrapperPlotNav: React.FunctionComponent = props => { - const { - title, - searchParams, - initQueryRequest, - sqlOperator, - facetsToPlot, - enableLeftFacetFilter, - loadingScreen, - ...rest - } = props - if (searchParams) { - let sqlUsed = initQueryRequest.query.sql - if (searchParams) { - sqlUsed = insertConditionsFromSearchParams( - searchParams, - initQueryRequest.query.sql, - sqlOperator, - ) - } - initQueryRequest.query.sql = sqlUsed - } - return ( - - {} - - { - /**/ - } - {title ? ( - - ) : ( - <> - )} - - ) -} - -export default QueryWrapperPlotNav diff --git a/src/lib/containers/TotalQueryResults.tsx b/src/lib/containers/TotalQueryResults.tsx index 91387d078b..6f3f258e28 100644 --- a/src/lib/containers/TotalQueryResults.tsx +++ b/src/lib/containers/TotalQueryResults.tsx @@ -7,9 +7,13 @@ import { UserProfile, FacetColumnResult, ColumnModel, + FacetColumnRequest, } from '../utils/synapseTypes' import { SynapseClient, SynapseConstants } from '../' -import { getStoredEntityHeaders, getStoredUserProfiles } from '../utils/functions/getDataFromFromStorage' +import { + getStoredEntityHeaders, + getStoredUserProfiles, +} from '../utils/functions/getDataFromFromStorage' import useDeepCompareEffect from 'use-deep-compare-effect' import { cloneDeep } from 'lodash-es' import SelectionCriteriaPill, { @@ -25,8 +29,8 @@ import { useState, FunctionComponent } from 'react' export type TotalQueryResultsProps = { isLoading: boolean style?: React.CSSProperties - //getLastQueryRequest: (() => QueryBundleRequest) | undefined lastQueryRequest: QueryBundleRequest + executeQueryRequest?: (param: QueryBundleRequest) => void token: string | undefined unitDescription: string frontText: string @@ -43,21 +47,30 @@ const TotalQueryResults: FunctionComponent = ({ lastQueryRequest, token, isLoading: parentLoading, - applyChanges = () => '', + executeQueryRequest, }) => { - const [total, setTotal] = useState(0) + const [total, setTotal] = useState(undefined) // undefined to start const [isLoading, setIsLoading] = useState(false) - const [selectedFacets, setSelectedFacets] = useState([]) + const [facetsWithSelection, setFacetsWithSelection] = useState< + FacetWithSelection[] + >([]) + + const applyChanges = (facets: FacetColumnRequest[]) => { + const queryRequest: QueryBundleRequest = cloneDeep(lastQueryRequest) + queryRequest.query.selectedFacets = facets + executeQueryRequest!(queryRequest) + } const getEnumFacetsWithSelections = ( facets: FacetColumnResult[], ): FacetColumnResultValues[] => { const enumFacets = facets.filter( - facet => facet.facetType === 'enumeration', + (facet) => facet.facetType === 'enumeration', ) as FacetColumnResultValues[] const enumFacetsWithSelections = enumFacets.filter( - facet => - facet.facetValues.filter(value => value.isSelected === true).length > 0, + (facet) => + facet.facetValues.filter((value) => value.isSelected === true).length > + 0, ) return enumFacetsWithSelections } @@ -66,10 +79,10 @@ const TotalQueryResults: FunctionComponent = ({ facets: FacetColumnResult[], ): FacetColumnResultRange[] => { const rangeFacets = facets.filter( - facet => facet.facetType === 'range', + (facet) => facet.facetType === 'range', ) as FacetColumnResultRange[] const rangeFacetsWithSelections = rangeFacets.filter( - facet => facet.selectedMax || facet.selectedMin, + (facet) => facet.selectedMax || facet.selectedMin, ) return rangeFacetsWithSelections } @@ -78,7 +91,7 @@ const TotalQueryResults: FunctionComponent = ({ entityHeaders: EntityHeader[], facetValue: string, ): string => { - const entity = entityHeaders.find(item => item.id === facetValue) + const entity = entityHeaders.find((item) => item.id === facetValue) return entity?.name || facetValue } @@ -86,7 +99,7 @@ const TotalQueryResults: FunctionComponent = ({ userProfiles: UserProfile[], facetValue: string, ): string => { - const userProfile = userProfiles.find(item => item.ownerId === facetValue) + const userProfile = userProfiles.find((item) => item.ownerId === facetValue) return userProfile?.userName || facetValue } @@ -96,12 +109,12 @@ const TotalQueryResults: FunctionComponent = ({ ): FacetWithSelection[] => { const lookUpEntityHeaders = getStoredEntityHeaders() const lookUpUserProfiles = getStoredUserProfiles() - let filteredEnumWithSelectedValuesOnly: FacetWithSelection[] = [] - facets.forEach(facet => { + const filteredEnumWithSelectedValuesOnly: FacetWithSelection[] = [] + facets.forEach((facet) => { const columnModel = columnModels.find( - model => model.name === facet.columnName, + (model) => model.name === facet.columnName, ) - facet.facetValues.forEach(facetValue => { + facet.facetValues.forEach((facetValue) => { if (facetValue.isSelected) { let displayValue = facetValue.value if (columnModel?.columnType === 'ENTITYID') { @@ -134,7 +147,7 @@ const TotalQueryResults: FunctionComponent = ({ SynapseConstants.BUNDLE_MASK_QUERY_COUNT | SynapseConstants.BUNDLE_MASK_QUERY_FACETS | SynapseConstants.BUNDLE_MASK_QUERY_COLUMN_MODELS - if (!parentLoading) { + if (parentLoading || total === undefined) { setIsLoading(true) SynapseClient.getQueryTableResults(cloneLastQueryRequest, token) .then((data) => { @@ -146,14 +159,14 @@ const TotalQueryResults: FunctionComponent = ({ data.facets!, ) const rangeFacetsForDisplay = rangeFacetsWithSelections.map( - facet => ({ facet: facet }), + (facet) => ({ facet }), ) const enumFacetsForDisplay = transformEnumFacetsForSelectionDisplay( enumFacetsWithSelections, data.columnModels!, ) - setSelectedFacets([ + setFacetsWithSelection([ ...rangeFacetsForDisplay, ...enumFacetsForDisplay, ]) @@ -196,10 +209,10 @@ const TotalQueryResults: FunctionComponent = ({ {frontText} {total} {unitDescription}{' '}
- {selectedFacets.map((facet, index) => ( + {facetsWithSelection.map((selectedFacet, index) => ( diff --git a/src/lib/containers/query_wrapper_plot_nav/FilterAndView.tsx b/src/lib/containers/query_wrapper_plot_nav/FilterAndView.tsx new file mode 100644 index 0000000000..2c59493976 --- /dev/null +++ b/src/lib/containers/query_wrapper_plot_nav/FilterAndView.tsx @@ -0,0 +1,44 @@ +import * as React from 'react' +import { QueryWrapperChildProps } from '../QueryWrapper' +import CardContainer from '../CardContainer' +import SynapseTable, { SynapseTableProps } from '../table/SynapseTable' +import { QueryFilter } from '../widgets/query-filter/QueryFilter' +import { CardConfiguration } from '../CardContainerLogic' + +export type OwnProps = { + tableConfiguration: SynapseTableProps | undefined + cardConfiguration: CardConfiguration | undefined + showFilter: boolean +} + +const FilterAndView = (props: QueryWrapperChildProps & OwnProps) => { + const { showFilter, tableConfiguration, cardConfiguration, ...rest } = props + return ( +
+
+ +
+
+ {tableConfiguration ? ( + + ) : ( + <> + )} + {cardConfiguration ? ( + + ) : ( + <> + )} +
+
+ ) +} + +export default FilterAndView diff --git a/src/lib/containers/query_wrapper_plot_nav/QueryWrapperPlotNav.tsx b/src/lib/containers/query_wrapper_plot_nav/QueryWrapperPlotNav.tsx new file mode 100644 index 0000000000..cad8987851 --- /dev/null +++ b/src/lib/containers/query_wrapper_plot_nav/QueryWrapperPlotNav.tsx @@ -0,0 +1,136 @@ +import * as React from 'react' +import QueryWrapper from '../QueryWrapper' +import FacetNav, { FacetNavOwnProps } from '../widgets/facet-nav/FacetNav' +import { SynapseTableProps } from '../table/SynapseTable' +import { + insertConditionsFromSearchParams, + SQLOperator, +} from '../../utils/functions/sqlFunctions' +import { SynapseConstants } from 'lib' +import QueryCount from '../QueryCount' +import { QueryBundleRequest } from 'lib/utils/synapseTypes' +import { CardConfiguration } from '../CardContainerLogic' +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' +import { library } from '@fortawesome/fontawesome-svg-core' +import { + faSearch, + faFilter, + faChartBar, + faDownload, +} from '@fortawesome/free-solid-svg-icons' +import FilterAndView from './FilterAndView' +// import { DownloadConfirmation } from '../download_list' + +library.add(faSearch) +library.add(faFilter) +library.add(faChartBar) +library.add(faDownload) + +type OwnProps = { + name: string + sql: string + entityId: string + tableConfiguration?: SynapseTableProps + cardConfiguration?: CardConfiguration + token?: string + rgbIndex?: number + frontText: string +} + +type SearchParams = { + searchParams?: { + facetValue: string + } +} +type Operator = { + sqlOperator: SQLOperator +} +export type QueryWrapperPlotNavProps = SearchParams & + Partial & + Operator & + OwnProps + +const QueryWrapperPlotNav: React.FunctionComponent = props => { + // const [showSearch, setShowSearch] = React.useState(true) + const [showVisualization, setShowVisualization] = React.useState(true) + const [showFilter, setShowFilter] = React.useState(true) + // const [showDownload, setShowDownload] = React.useState(false) + + const { + searchParams, + sql, + sqlOperator, + facetsToPlot, + tableConfiguration, + loadingScreen, + entityId, + name, + token, + cardConfiguration, + frontText, + ...rest + } = props + let sqlUsed = sql + if (searchParams) { + if (searchParams) { + sqlUsed = insertConditionsFromSearchParams( + searchParams, + sqlUsed, + sqlOperator, + ) + } + } + const initQueryRequest: QueryBundleRequest = { + entityId, + concreteType: 'org.sagebionetworks.repo.model.table.QueryBundleRequest', + partMask: + SynapseConstants.BUNDLE_MASK_QUERY_COLUMN_MODELS | + SynapseConstants.BUNDLE_MASK_QUERY_FACETS | + SynapseConstants.BUNDLE_MASK_QUERY_SELECT_COLUMNS | + SynapseConstants.BUNDLE_MASK_QUERY_COUNT | + SynapseConstants.BUNDLE_MASK_QUERY_RESULTS, + query: { + sql: sqlUsed, + limit: 25, + offset: 0, + }, + } + return ( +
+

+
+ +
+
+ {/* */} + + + {/* */} +
+

+ + + + +
+ ) +} + +export default QueryWrapperPlotNav diff --git a/src/lib/containers/table/SynapseTable.tsx b/src/lib/containers/table/SynapseTable.tsx index 1d40921dbe..9204aea0b8 100644 --- a/src/lib/containers/table/SynapseTable.tsx +++ b/src/lib/containers/table/SynapseTable.tsx @@ -53,7 +53,6 @@ import { ExpandTable, } from './table-top/' import FacetFilter from './table-top/FacetFilter' -import { QueryFilter } from '../widgets/query-filter/QueryFilter' import NoData from '../../assets/icons/file-dotted.svg' import { renderTableCell } from '../synapse_table_functions/renderTableCell' import { getUniqueEntities } from '../synapse_table_functions/getUniqueEntities' @@ -108,12 +107,11 @@ export type SynapseTableState = { mapEntityIdToHeader: Dictionary mapUserIdToHeader: Dictionary> showColumnSelection: boolean - isShowLeftFilter?: boolean isUserModifiedQuery?: boolean //flag to signal that the selection criterial has been defined by user and if no records are returned do not hide the table } export type SynapseTableProps = { visibleColumnCount?: number - title: string + title?: string loadingScreen?: JSX.Element showAccessColumn?: boolean markdownColumns?: string[] // array of column names which should render as markdown @@ -152,7 +150,6 @@ export default class SynapseTable extends React.Component< isDownloadConfirmationOpen: false, isExpanded: false, showColumnSelection: false, - isShowLeftFilter: this.props.enableLeftFacetFilter, isFileView: false, // sortedColumnSelection contains the columns which are // selected currently and their sort status as eithet @@ -218,18 +215,18 @@ export default class SynapseTable extends React.Component< // Make call to resolve entity ids if (distinctEntityIds.size > 0) { const referenceList: ReferenceList = Array.from(distinctEntityIds).map( - (id) => { + id => { return { targetId: id } }, ) try { // initialize mapEntityIdToHeader - referenceList.forEach((el) => { + referenceList.forEach(el => { mapEntityIdToHeader[el.targetId] = EMPTY_HEADER }) const data = await SynapseClient.getEntityHeader(referenceList, token) const { results } = data - results.forEach((el) => { + results.forEach(el => { mapEntityIdToHeader[el.id] = el }) } catch (err) { @@ -248,7 +245,7 @@ export default class SynapseTable extends React.Component< // TODO: Grab Team Badge try { const data = await SynapseClient.getGroupHeadersBatch(ids, token) - data.children.forEach((el) => { + data.children.forEach(el => { if (el.isIndividual) { userPorfileIds.push(el.ownerId) } else { @@ -293,6 +290,7 @@ export default class SynapseTable extends React.Component< unitDescription, token, showBarChart, + enableLeftFacetFilter, } = this.props const { queryResult } = data const { queryResults } = queryResult @@ -303,7 +301,7 @@ export default class SynapseTable extends React.Component< const queryRequest = this.props.getLastQueryRequest!() const { sql, selectedFacets } = queryRequest.query - let className = 'SRC-marginTopMinusTen' + let className = '' if (showBarChart) { className = 'SRC-marginBottomTop' } @@ -321,51 +319,48 @@ export default class SynapseTable extends React.Component< const content = ( <>
-
- {unitDescription && !isGroupByInSql(queryRequest.query.sql) && ( - - this.applyChangesFromQueryFilter(newFacets) - } - /> - )} -
- {this.renderTableTop(headers, this.props.enableLeftFacetFilter)} -
- {this.state.isShowLeftFilter && ( + {!enableLeftFacetFilter && + unitDescription && + !isGroupByInSql(queryRequest.query.sql) && (
- { - - } + ( + + this.applyChangesFromQueryFilter(newFacets) + } + /> + )
)} -
+ {!enableLeftFacetFilter && + this.renderTableTop(headers, enableLeftFacetFilter)} + {!enableLeftFacetFilter && ( +
+
+ {this.renderTable(headers, facets, rows)} +
+
+ )} + {enableLeftFacetFilter && ( +
{this.renderTable(headers, facets, rows)}
-
+ )}
) @@ -473,7 +468,7 @@ export default class SynapseTable extends React.Component< facets: FacetColumnResult[], rows: Row[], ) => { - const lastQueryRequest = this.props.getLastQueryRequest!() + const lastQueryRequest = this.props.getLastQueryRequest?.()! // handle displaying the previous button -- if offset is zero then it // shouldn't be displayed const pastZero: boolean = lastQueryRequest.query.offset! > 0 @@ -555,7 +550,7 @@ export default class SynapseTable extends React.Component< return (
@@ -579,16 +574,6 @@ export default class SynapseTable extends React.Component< callbackFn={this.advancedSearch} tooltipText={'Open Advanced Search in Synapse'} /> - - this.setState({ - isShowLeftFilter: !this.state.isShowLeftFilter, - }) - } - tooltipText={'Toggle Search Panel'} - /> )} {this.renderDropdownDownloadOptions(isFileView)} @@ -625,8 +610,8 @@ export default class SynapseTable extends React.Component< const indexes: number[] = [] if (isGroupByInSql(originalSql)) { const tokens: string[][] = lexer.tokenize(originalSql) - const selectIndex = tokens.findIndex((el) => el[0] === 'SELECT') - const fromIndex = tokens.findIndex((el) => el[0] === 'FROM') + const selectIndex = tokens.findIndex(el => el[0] === 'SELECT') + const fromIndex = tokens.findIndex(el => el[0] === 'FROM') let columnIndex = 0 for ( let index = selectIndex + 1; @@ -651,8 +636,8 @@ export default class SynapseTable extends React.Component< originalSql: string, ): { synId: string; newSql: string } { let tokens: string[][] = lexer.tokenize(originalSql) - const selectIndex = tokens.findIndex((el) => el[0] === 'SELECT') - const fromIndex = tokens.findIndex((el) => el[0] === 'FROM') + const selectIndex = tokens.findIndex(el => el[0] === 'SELECT') + const fromIndex = tokens.findIndex(el => el[0] === 'FROM') // gather all of the column names literals between select and from (and their indices) const columnReferences: ColumnReference[] = [] @@ -684,7 +669,7 @@ export default class SynapseTable extends React.Component< // remove all tokens after (and including) group tokens = tokens.slice( 0, - tokens.findIndex((el) => el[0] === 'GROUP'), + tokens.findIndex(el => el[0] === 'GROUP'), ) // replace all columns with * tokens.splice(selectIndex + 1, fromIndex - selectIndex - 1, [ @@ -697,7 +682,7 @@ export default class SynapseTable extends React.Component< if (this.props.data === undefined) { return { synId: '', newSql: '' } } - const whereIndex = tokens.findIndex((el) => el[0] === 'WHERE') + const whereIndex = tokens.findIndex(el => el[0] === 'WHERE') if (whereIndex === -1) { // does not contain a where clause tokens.push(['WHERE', 'WHERE', '1']) @@ -729,7 +714,7 @@ export default class SynapseTable extends React.Component< // remove the last AND tokens.pop() // remove backtick from output sql (for table name): `syn1234` becomes syn1234 - const synId = tokens[tokens.findIndex((el) => el[0] === 'FROM') + 1][1] + const synId = tokens[tokens.findIndex(el => el[0] === 'FROM') + 1][1] tokens.push(['EOF', '', '1']) return { synId, newSql: formatSQLFromParser(tokens) } } @@ -977,7 +962,6 @@ export default class SynapseTable extends React.Component<
{isFacetSelection && - !this.props.enableLeftFacetFilter && this.configureFacetDropdown(facets, facetIndex)} = ({ loadingScreen, isLoading, executeQueryRequest, + token, asyncJobStatus, - facetsToPlot, + frontText, + show, }: FacetNavProps): JSX.Element => { const [facetUiStateArray, setFacetUiStateArray] = useState([]) const [expandedFacets, setExpandedFacets] = useState([]) const [isFirstTime, setIsFirstTime] = useState(true) const request = getLastQueryRequest!() - const getFacets = (data: QueryResultBundle | undefined): FacetColumnResult[] => { + const getFacets = ( + data: QueryResultBundle | undefined, + ): FacetColumnResult[] => { const result = data?.facets?.filter( - item => - item.facetType === 'enumeration' && - (!facetsToPlot?.length || facetsToPlot.indexOf(item.columnName) > -1) + (item) => item.facetType === 'enumeration', ) if (!result) { return [] } else { return result } - } useEffect(() => { - let result = data?.facets?.filter( - item => - item.facetType === 'enumeration' && - (!facetsToPlot?.length || facetsToPlot.indexOf(item.columnName) > -1), + const result = data?.facets?.filter( + (item) => item.facetType === 'enumeration', ) if (!result) { console.log('no data') @@ -82,18 +83,18 @@ const FacetNav: React.FunctionComponent = ({ ) setIsFirstTime(false) } - }, [data]) + }, [data, isFirstTime]) // when 'show more/less' is clicked const showMore = (shouldShowMore: boolean) => { if (shouldShowMore) { - setFacetUiStateArray(facetUiStateArray => - facetUiStateArray.map(item => { + setFacetUiStateArray((facetUiStateArray) => + facetUiStateArray.map((item) => { return { ...item, isHidden: false } }), ) } else { - setFacetUiStateArray(facetUiStateArray => + setFacetUiStateArray((facetUiStateArray) => facetUiStateArray.map((item, index) => index >= 4 ? { ...item, isHidden: true } : { ...item }, ), @@ -110,7 +111,7 @@ const FacetNav: React.FunctionComponent = ({ // don't show expanded or hidden facets const isFacetHiddenInGrid = (columnName: string) => { const itemHidden = facetUiStateArray.find( - item => + (item) => item.name === columnName && (item.isHidden === true || item.isExpanded === true), ) @@ -123,7 +124,7 @@ const FacetNav: React.FunctionComponent = ({ return 'NONE' } if ( - facetUiStateArray.find(item => item.isHidden === true) || + facetUiStateArray.find((item) => item.isHidden === true) || getFacets(data).length < facetUiStateArray.length ) { return 'MORE' @@ -133,15 +134,17 @@ const FacetNav: React.FunctionComponent = ({ // hides expanded facet under 'show more' const hideExpandedFacet = (facet: FacetColumnResult, index: number) => { - setFacetUiStateArray(facetUiStateArray => - facetUiStateArray.map(item => + setFacetUiStateArray((facetUiStateArray) => + facetUiStateArray.map((item) => item.name === facet.columnName ? { ...item, isExpanded: false, isHidden: true } : item, ), ) - setExpandedFacets(expandedFacets => - expandedFacets.filter(item => item.facet.columnName != facet.columnName), + setExpandedFacets((expandedFacets) => + expandedFacets.filter( + (item) => item.facet.columnName != facet.columnName, + ), ) } @@ -157,7 +160,7 @@ const FacetNav: React.FunctionComponent = ({ } else { setExpandedFacets( expandedFacets.filter( - item => item.facet.columnName != facet.columnName, + (item) => item.facet.columnName != facet.columnName, ), ) } @@ -173,95 +176,112 @@ const FacetNav: React.FunctionComponent = ({ propName: 'isHidden' | 'isExpanded', value: boolean, ) => { - - setFacetUiStateArray(facetUiStateArray => - facetUiStateArray.map(item => + setFacetUiStateArray((facetUiStateArray) => + facetUiStateArray.map((item) => item.name === columnName ? { ...item, [propName]: value } : item, ), ) } + const lastQueryRequest = getLastQueryRequest?.()! + const hasSelectedFacets = + lastQueryRequest.query.selectedFacets !== undefined && + lastQueryRequest.query.selectedFacets.length > 0 if (isLoadingNewData || !data) { return (
{loadingScreen} - {asyncJobStatus?.progressMessage &&
{asyncJobStatus.progressMessage}
} + {asyncJobStatus?.progressMessage && ( +
{asyncJobStatus.progressMessage}
+ )}
) } else { return ( -
-
- {expandedFacets.map(item => ( -
- hideExpandedFacet(item.facet, item.index)} - onCollapse={() => - toggleExpandFacet(item.facet, item.index, false) - } - facetToPlot={item.facet as FacetColumnResultValues} - applyChanges={( - facet: FacetColumnResultValues, - value: FacetColumnResultValueCount, - ) => - applyChangesToValuesColumn( - request, - facet, - applyChangesFromQueryFilter, - value.value, - !value.isSelected, - ) - } - > -
- ))} + <> +
+
+ {expandedFacets.map((item) => ( +
+ hideExpandedFacet(item.facet, item.index)} + onCollapse={() => + toggleExpandFacet(item.facet, item.index, false) + } + facetToPlot={item.facet as FacetColumnResultValues} + applyChanges={( + facet: FacetColumnResultValues, + value: FacetColumnResultValueCount, + ) => + applyChangesToValuesColumn( + request, + facet, + applyChangesFromQueryFilter, + value.value, + !value.isSelected, + ) + } + > +
+ ))} +
+
+ {getFacets(data).map((item, index) => ( +
+ hideFacetInGrid(item.columnName)} + onExpand={() => toggleExpandFacet(item, index, true)} + facetToPlot={item as FacetColumnResultValues} + applyChanges={( + facet: FacetColumnResultValues, + value: FacetColumnResultValueCount | undefined, + isSelected: boolean, + ) => + applyChangesToValuesColumn( + request, + facet, + applyChangesFromQueryFilter, + value?.value, + isSelected, + ) + } + > +
+ ))} +
+
+ {getShowMoreState() !== 'NONE' && ( + + )} +
-
- {getFacets(data).map((item, index) => ( -
- hideFacetInGrid(item.columnName)} - onExpand={() => toggleExpandFacet(item, index, true)} - facetToPlot={item as FacetColumnResultValues} - applyChanges={( - facet: FacetColumnResultValues, - value: FacetColumnResultValueCount | undefined, - isSelected: boolean - ) => - applyChangesToValuesColumn( - request, - facet, - applyChangesFromQueryFilter, - value?.value, - isSelected, - ) - } - > -
- ))} -
-
- {getShowMoreState() !== 'NONE' && ( - - )} -
-
+ + ) } } diff --git a/src/lib/containers/widgets/facet-nav/FacetNavPanel.tsx b/src/lib/containers/widgets/facet-nav/FacetNavPanel.tsx index 223b1c1542..4ce4b8f891 100644 --- a/src/lib/containers/widgets/facet-nav/FacetNavPanel.tsx +++ b/src/lib/containers/widgets/facet-nav/FacetNavPanel.tsx @@ -73,7 +73,6 @@ function extractPlotDataArray( index: number, plotType: PlotType, ) { - console.log(columnType) const { colorPalette } = getColorPallette( index, facetToPlot.facetValues.length, @@ -83,7 +82,7 @@ function extractPlotDataArray( facetValues: FacetColumnResultValueCount[], columnType?: ColumnType, ): string[] => { - return facetValues.map(facetValue => getLabel(facetValue, columnType)) + return facetValues.map((facetValue) => getLabel(facetValue, columnType)) } const getLabel = ( @@ -98,7 +97,7 @@ function extractPlotDataArray( const lookup = getStoredEntityHeaders() return ( - lookup.find(item => item.id === facetValue.value)?.name || + lookup.find((item) => item.id === facetValue.value)?.name || facetValue.value ) } @@ -106,7 +105,7 @@ function extractPlotDataArray( if (columnType === 'USERID') { const lookup = getStoredUserProfiles() return ( - lookup.find(item => item.ownerId === facetValue.value)?.userName || + lookup.find((item) => item.ownerId === facetValue.value)?.userName || facetValue.value ) } @@ -116,20 +115,20 @@ function extractPlotDataArray( const singleChartData: PlotlyTyped.Data = { values: plotType === 'PIE' - ? facetToPlot.facetValues.map(facet => facet.count) + ? facetToPlot.facetValues.map((facet) => facet.count) : undefined, labels: getLabels(facetToPlot.facetValues, columnType), x: plotType === 'BAR' - ? facetToPlot.facetValues.map(facet => getLabel(facet, columnType)) + ? facetToPlot.facetValues.map((facet) => getLabel(facet, columnType)) : undefined, y: plotType === 'BAR' - ? facetToPlot.facetValues.map(facet => facet.count) + ? facetToPlot.facetValues.map((facet) => facet.count) : undefined, // @ts-ignore facetEnumerationValues: facetToPlot.facetValues.map( - facetValue => facetValue.value, + (facetValue) => facetValue.value, ), name: facetToPlot.columnName, hovertemplate: @@ -146,14 +145,14 @@ function extractPlotDataArray( colors: plotType === 'PIE' ? colorPalette : undefined, color: plotType === 'BAR' ? colorPalette : undefined, line: { - width: facetToPlot.facetValues.map(facetValue => + width: facetToPlot.facetValues.map((facetValue) => facetValue.isSelected ? 1 : 0, ), }, }, pull: plotType === 'PIE' - ? facetToPlot.facetValues.map(facetValue => + ? facetToPlot.facetValues.map((facetValue) => facetValue.isSelected ? 0.04 : 0, ) : undefined, @@ -167,7 +166,6 @@ function extractPlotDataArray( ? (singleChartData.marker?.colors as string[]) : (singleChartData.marker?.color as string[]), } - console.log(result) return result } @@ -181,7 +179,7 @@ const applyFacetFilter = ( const facetValueClickedValue = plotPointData.data.facetEnumerationValues[plotPointData.pointNumber] const facetValueClicked = allFacetValues.facetValues.find( - facet => facet.value === facetValueClickedValue, + (facet) => facet.value === facetValueClickedValue, ) callbackApplyFn( allFacetValues, @@ -198,7 +196,7 @@ const applyDropdownFilter = ( ) => { if (evt.target.value) { const facetValueClicked = allFacetValues.facetValues.find( - facet => facet.value === evt.target.value, + (facet) => facet.value === evt.target.value, ) callbackApplyFn(allFacetValues, facetValueClicked, evt.target.checked) } @@ -273,7 +271,7 @@ const FacetNavPanel: React.FunctionComponent = ({ const getColumnType = (): ColumnType | undefined => data?.columnModels?.find( - columnModel => columnModel.name === facetToPlot.columnName, + (columnModel) => columnModel.name === facetToPlot.columnName, )?.columnType as ColumnType useEffect(() => { @@ -353,7 +351,7 @@ const FacetNavPanel: React.FunctionComponent = ({ evt: React.ChangeEvent, ) => applyDropdownFilter(evt, facetToPlot, applyChanges)} isAllFilterSelectedForFacet={ - facetToPlot.facetValues.filter(item => item.isSelected) + facetToPlot.facetValues.filter((item) => item.isSelected) .length === 0 } facetColumnResult={facetToPlot} @@ -385,7 +383,7 @@ const FacetNavPanel: React.FunctionComponent = ({ style={getPlotStyle(size.width, plotType)} config={{ displayModeBar: false, responsive: true }} useResizeHandler={true} - onClick={evt => + onClick={(evt) => applyFacetFilter(evt, facetToPlot, applyChanges) } > diff --git a/src/lib/containers/widgets/facet-nav/SelectionCriteriaPill.tsx b/src/lib/containers/widgets/facet-nav/SelectionCriteriaPill.tsx index 81aa0891df..4c2f654bb5 100644 --- a/src/lib/containers/widgets/facet-nav/SelectionCriteriaPill.tsx +++ b/src/lib/containers/widgets/facet-nav/SelectionCriteriaPill.tsx @@ -19,28 +19,30 @@ export type FacetWithSelection = { } export type SelectionCriteriaPillProps = { - facet: FacetWithSelection + facetWithSelection: FacetWithSelection index: number className?: string onRemove: Function } const SelectionCriteriaPill: FunctionComponent = ({ - facet, + facetWithSelection, index, onRemove, }) => { let innerText, tooltipText: string | null = '' - if (facet.facet.facetType === 'enumeration') { - innerText = facet.displayValue || '' + if (facetWithSelection.facet.facetType === 'enumeration') { + innerText = facetWithSelection.displayValue || '' } else { innerText = - (facet.facet as FacetColumnResultRange).selectedMin + + (facetWithSelection.facet as FacetColumnResultRange).selectedMin + ' - ' + - (facet.facet as FacetColumnResultRange).selectedMax + (facetWithSelection.facet as FacetColumnResultRange).selectedMax } - tooltipText = `${unCamelCase(facet.facet.columnName)}: ${innerText}` + tooltipText = `${unCamelCase( + facetWithSelection.facet.columnName, + )}: ${innerText}` return ( = ({ > {innerText}