diff --git a/packages/libs/coreui/src/components/Mesa/types.ts b/packages/libs/coreui/src/components/Mesa/types.ts index 8be8b6c6a4..26b6599a92 100644 --- a/packages/libs/coreui/src/components/Mesa/types.ts +++ b/packages/libs/coreui/src/components/Mesa/types.ts @@ -137,20 +137,21 @@ export interface MesaColumn< Value = DefaultColumnValue > { key: Key; - name?: string; + name?: ReactNode; type?: string; primary?: boolean; searchable?: boolean; sortable?: boolean; resizeable?: boolean; moveable?: boolean; - helpText?: string; + helpText?: ReactNode; htmlHelp?: string; style?: CSSProperties; headingStyle?: CSSProperties; className?: string; width?: CSSProperties['width']; hidden?: boolean; + inline?: boolean; truncated?: boolean | string; getValue?: (props: { row: Row; key: Key }) => Value; renderCell?: (cellProps: CellProps) => ReactNode; @@ -164,7 +165,18 @@ export interface MesaColumn< HelpTrigger: () => ReactElement | null; ClickBoundary: (props: { children: ReactNode }) => ReactElement; } - ) => ReactNode); + ) => ReactNode) + | Array< + ( + column: MesaColumn, + columnIndex: number, + components: { + SortTrigger: () => ReactElement | null; + HelpTrigger: () => ReactElement | null; + ClickBoundary: (props: { children: ReactNode }) => ReactElement; + } + ) => ReactNode + >; wrapCustomHeadings?: (props: { column: MesaColumn; columnIndex: number; diff --git a/packages/libs/wdk-client/src/Components/AttributeFilter/FieldFilter.tsx b/packages/libs/wdk-client/src/Components/AttributeFilter/FieldFilter.tsx index b119e96e13..2ee3866fd7 100644 --- a/packages/libs/wdk-client/src/Components/AttributeFilter/FieldFilter.tsx +++ b/packages/libs/wdk-client/src/Components/AttributeFilter/FieldFilter.tsx @@ -85,9 +85,55 @@ function FieldFilter(props: FieldFilterProps) { props.activeFieldState.summary == null && props.activeFieldState.leafSummaries == null) || props.dataCount == null ? null : isMulti(props.activeField) ? ( - + {})} + onMemberSort={(field, sort) => { + if (props.onMemberSort) { + props.onMemberSort(sort.columnKey); + } + }} + onMemberSearch={(field, searchTerm) => { + if (props.onMemberSearch) { + props.onMemberSearch(searchTerm); + } + }} + /> ) : ( - + {})} + selectByDefault={props.selectByDefault} + displayName={props.displayName} + dataCount={props.dataCount} + filteredDataCount={props.filteredDataCount} + onRangeScaleChange={props.onRangeScaleChange} + /> )} )} diff --git a/packages/libs/wdk-client/src/Components/AttributeFilter/FieldList.tsx b/packages/libs/wdk-client/src/Components/AttributeFilter/FieldList.tsx index a14232f980..cad19c8d34 100644 --- a/packages/libs/wdk-client/src/Components/AttributeFilter/FieldList.tsx +++ b/packages/libs/wdk-client/src/Components/AttributeFilter/FieldList.tsx @@ -141,40 +141,39 @@ export default class FieldList extends React.Component< return (
> - {...({ - ref: this.handleCheckboxTreeRef, - autoFocusSearchBox: autoFocus, - tree: fieldTree, - expandedList: this.state.expandedNodes, - getNodeId: this.getNodeId, - getNodeChildren: this.getNodeChildren, - onExpansionChange: this.handleExpansionChange, - isSelectable: false, - isSearchable: true, - searchBoxPlaceholder: 'Find a variable', - searchBoxHelp: makeSearchHelpText( - 'the variables by name or description' - ), - searchTerm: this.state.searchTerm, - onSearchTermChange: this.handleSearchTermChange, - searchPredicate: this.searchPredicate, - renderNode: (node: FieldTreeNode) => ( - - ), - linksPosition: LinksPosition.Top, - styleOverrides: { - treeNode: { - nodeWrapper: { - padding: 0, - }, + autoFocusSearchBox={autoFocus} + tree={fieldTree} + expandedList={this.state.expandedNodes} + getNodeId={this.getNodeId} + getNodeChildren={this.getNodeChildren} + onExpansionChange={this.handleExpansionChange} + isSelectable={false} + selectedList={[]} + onSelectionChange={() => {}} + isSearchable={true} + searchBoxPlaceholder="Find a variable" + searchBoxHelp={makeSearchHelpText( + 'the variables by name or description' + )} + searchTerm={this.state.searchTerm} + onSearchTermChange={this.handleSearchTermChange} + searchPredicate={this.searchPredicate} + renderNode={(node: FieldTreeNode) => ( + + )} + linksPosition={LinksPosition.Top} + styleOverrides={{ + treeNode: { + nodeWrapper: { + padding: 0, }, }, - } as any)} + }} />
); diff --git a/packages/libs/wdk-client/src/Components/AttributeFilter/Histogram.tsx b/packages/libs/wdk-client/src/Components/AttributeFilter/Histogram.tsx index 286371be15..8b6dfaa889 100644 --- a/packages/libs/wdk-client/src/Components/AttributeFilter/Histogram.tsx +++ b/packages/libs/wdk-client/src/Components/AttributeFilter/Histogram.tsx @@ -36,7 +36,7 @@ interface DistributionEntry { filteredCount: number; } -interface UIState { +export interface UIState { xaxisMin?: number; xaxisMax?: number; yaxisMin?: number; @@ -110,23 +110,23 @@ var Histogram = (function () { constructor(props: HistogramProps) { super(props); - this.handleResize = throttle(this.handleResize.bind(this), 100) as any; - this.emitStateChange = debounce(this.emitStateChange, 100) as any; + this.handleResize = throttle(this.handleResize.bind(this), 100); + this.emitStateChange = debounce(this.emitStateChange, 100); this.state = { uiState: this.getStateFromProps(props), showSettings: sessionStorage.getItem(PLOT_SETTINGS_OPEN_KEY) !== 'false', }; - this.getRange = memoize(this.getRange) as any; - this.getNumFixedDigits = memoize(this.getNumFixedDigits) as any; - this.getDefaultBinSize = memoize(this.getDefaultBinSize) as any; + this.getRange = memoize(this.getRange); + this.getNumFixedDigits = memoize(this.getNumFixedDigits); + this.getDefaultBinSize = memoize(this.getDefaultBinSize); } componentDidMount() { - ($ as any)(window).on('resize', this.handleResize); + $(window).on('resize', this.handleResize); const node = ReactDOM.findDOMNode(this); if (node) { - ($(node) as any) + $(node) .on('plotselected .chart', this.handlePlotSelected.bind(this)) .on('plotselecting .chart', this.handlePlotSelecting.bind(this)) .on('plotunselected .chart', this.handlePlotUnselected.bind(this)) @@ -485,7 +485,7 @@ var Histogram = (function () { const node = ReactDOM.findDOMNode(this); if (node) { - this.$chart = ($(node) as any).find('.chart'); + this.$chart = $(node).find('.chart'); this.plot = ($ as any).plot(this.$chart, seriesData, plotOptions); } } @@ -858,7 +858,11 @@ var Histogram = (function () { } } - (LazyHistogram as any).defaultProps = { + ( + LazyHistogram as typeof LazyHistogram & { + defaultProps: Partial; + } + ).defaultProps = { xaxisLabel: 'X-Axis', yaxisLabel: 'Y-Axis', selectedMin: null, diff --git a/packages/libs/wdk-client/src/Components/AttributeFilter/HistogramField.tsx b/packages/libs/wdk-client/src/Components/AttributeFilter/HistogramField.tsx index d13758b083..0c86015eec 100644 --- a/packages/libs/wdk-client/src/Components/AttributeFilter/HistogramField.tsx +++ b/packages/libs/wdk-client/src/Components/AttributeFilter/HistogramField.tsx @@ -1,7 +1,7 @@ import React from 'react'; import { clamp, debounce, get, noop } from 'lodash'; -import Histogram from '../../Components/AttributeFilter/Histogram'; +import Histogram, { UIState } from '../../Components/AttributeFilter/Histogram'; import FilterLegend from '../../Components/AttributeFilter/FilterLegend'; import UnknownCount from '../../Components/AttributeFilter/UnknownCount'; import { @@ -20,6 +20,15 @@ interface DistributionEntry { filteredCount: number; } +/** + * Converted distribution entry with numeric values for Histogram component + */ +interface ConvertedDistributionEntry { + value: number; + count: number; + filteredCount: number; +} + /** * Range value type for min/max values */ @@ -35,7 +44,7 @@ interface HistogramFieldProps { distribution: DistributionEntry[]; toFilterValue: (value: number) => number | string; toHistogramValue: (value: number | string) => number; - selectByDefault: boolean; + selectByDefault?: boolean; onChange: ( activeField: Field, range: RangeValue, @@ -45,12 +54,12 @@ interface HistogramFieldProps { activeField: Field; activeFieldState: { summary: OntologyTermSummary; - [key: string]: any; - }; + } & UIState; filter?: RangeFilter; overview: React.ReactNode; displayName: string; unknownCount: number; + dataCount?: number; timeformat?: string; onRangeScaleChange?: (activeField: Field, range: any) => void; histogramTruncateYAxisDefault?: boolean; @@ -77,7 +86,7 @@ export default class HistogramField extends React.Component< HistogramFieldProps, HistogramFieldState > { - convertedDistribution: DistributionEntry[] = []; + convertedDistribution: ConvertedDistributionEntry[] = []; convertedDistributionRange: { min: number; max: number } = { min: 0, max: 0, @@ -291,14 +300,6 @@ export default class HistogramField extends React.Component< var selectedMin = min == null ? null : this.props.toHistogramValue(min); var selectedMax = max == null ? null : this.props.toHistogramValue(max); - var selectionTotal = - filter && - (filter as any).selection && - ((filter as any).selection as any).length; - - var selection = - selectionTotal != null ? ' (' + selectionTotal + ' selected) ' : null; - return (
@@ -335,16 +336,21 @@ export default class HistogramField extends React.Component< Include {unknownCount} Unknown )} - {selection}
-
- -
+ {this.props.dataCount && ( +
+ +
+ )} headerRowIndex === 0, - renderHeading: useSearch - ? [this.renderValueHeading, this.renderValueHeadingSearch] - : this.renderValueHeading, - renderCell: this.renderValueCell, - }, - { - key: 'filteredCount', - sortable: useSort, - headingStyle: { maxWidth: '12em' }, - helpText: ( -
- The number of {this.props.displayName} that match the - filters applied for other variables -
- and have the given - {this.props.activeField.display} - {' '} - value -
- ), - wrapCustomHeadings: ({ - headerRowIndex, - }: { - headerRowIndex: number; - }) => headerRowIndex === 0, - renderHeading: - this.props.activeFieldState.summary.internalsFilteredCount != - null - ? [ - this.renderFilteredCountHeading1, - this.renderFilteredCountHeading2, - ] - : this.renderFilteredCountHeading1, - renderCell: this.renderFilteredCountCell, - }, - { - key: 'count', - sortable: useSort, - headingStyle: { maxWidth: '12em' }, - helpText: ( -
- The number of {this.props.displayName} in the dataset - that have the given {this.props.activeField.display}{' '} - value -
- ), - wrapCustomHeadings: ({ - headerRowIndex, - }: { - headerRowIndex: number; - }) => headerRowIndex === 0, - renderHeading: - this.props.activeFieldState.summary.internalsCount != null - ? [ - this.renderUnfilteredCountHeading1, - this.renderUnfilteredCountHeading2, - ] - : this.renderUnfilteredCountHeading1, - renderCell: this.renderUnfilteredCountCell, - }, - { - key: 'distribution', - name: 'Distribution', - width: '30%', - helpText: ( -
- The subset of {this.props.displayName} that have the - given {this.props.activeField.display} value when - other filters have been applied -
- ), - renderCell: this.renderDistributionCell, - }, - { - key: '%', - name: '', - width: '4em', - helpText: ( -
- The subset of {this.props.displayName} out of all{' '} - {this.props.displayName} that have the given{' '} - {this.props.activeField.display} value -
- ), - renderCell: this.renderPrecentageCell, - }, - ] as any - } + columns={[ + { + key: 'checked', + sortable: false, + width: '32px', + renderHeading: this.renderCheckboxHeading, + renderCell: this.renderCheckboxCell, + }, + { + key: 'value', + headingStyle: { minWidth: '12em' }, + inline: true, + sortable: useSort, + wrapCustomHeadings: ({ + headerRowIndex, + }: { + headerRowIndex: number; + }) => headerRowIndex === 0, + renderHeading: useSearch + ? [this.renderValueHeading, this.renderValueHeadingSearch] + : this.renderValueHeading, + renderCell: this.renderValueCell, + }, + { + key: 'filteredCount', + sortable: useSort, + headingStyle: { maxWidth: '12em' }, + helpText: ( +
+ The number of {this.props.displayName} that match the + filters applied for other variables +
+ and have the given + {this.props.activeField.display} + {' '} + value +
+ ), + wrapCustomHeadings: ({ + headerRowIndex, + }: { + headerRowIndex: number; + }) => headerRowIndex === 0, + renderHeading: + this.props.activeFieldState.summary.internalsFilteredCount != null + ? [ + this.renderFilteredCountHeading1, + this.renderFilteredCountHeading2, + ] + : this.renderFilteredCountHeading1, + renderCell: this.renderFilteredCountCell, + }, + { + key: 'count', + sortable: useSort, + headingStyle: { maxWidth: '12em' }, + helpText: ( +
+ The number of {this.props.displayName} in the dataset + that have the given {this.props.activeField.display}{' '} + value +
+ ), + wrapCustomHeadings: ({ + headerRowIndex, + }: { + headerRowIndex: number; + }) => headerRowIndex === 0, + renderHeading: + this.props.activeFieldState.summary.internalsCount != null + ? [ + this.renderUnfilteredCountHeading1, + this.renderUnfilteredCountHeading2, + ] + : this.renderUnfilteredCountHeading1, + renderCell: this.renderUnfilteredCountCell, + }, + { + key: 'distribution', + name: 'Distribution', + width: '30%', + helpText: ( +
+ The subset of {this.props.displayName} that have the + given {this.props.activeField.display} value when other + filters have been applied +
+ ), + renderCell: this.renderDistributionCell, + }, + { + key: '%', + name: '', + width: '4em', + helpText: ( +
+ The subset of {this.props.displayName} out of all{' '} + {this.props.displayName} that have the given{' '} + {this.props.activeField.display} value +
+ ), + renderCell: this.renderPrecentageCell, + }, + ]} > ); } diff --git a/packages/libs/wdk-client/src/Components/AttributeFilter/MultiFieldFilter.tsx b/packages/libs/wdk-client/src/Components/AttributeFilter/MultiFieldFilter.tsx index 2186542f4d..23d9408054 100644 --- a/packages/libs/wdk-client/src/Components/AttributeFilter/MultiFieldFilter.tsx +++ b/packages/libs/wdk-client/src/Components/AttributeFilter/MultiFieldFilter.tsx @@ -4,6 +4,7 @@ import React from 'react'; import { makeClassNameHelper } from '../../Utils/ComponentUtils'; import { Seq } from '../../Utils/IterableUtils'; import { MesaController as Mesa } from '@veupathdb/coreui/lib/components/Mesa'; +import type { MesaColumn } from '@veupathdb/coreui/lib/components/Mesa/types'; import RealTimeSearchBox from '../../Components/SearchBox/RealTimeSearchBox'; import StackedBar from '../../Components/AttributeFilter/StackedBar'; import { @@ -66,7 +67,7 @@ interface MultiFieldFilterState { /** * Type for row data used in Mesa table */ -interface TableRow { +interface TableRow extends Record { summary: OntologyTermSummary; value?: string | number | null; filter?: Filter; @@ -462,88 +463,86 @@ export default class MultiFieldFilter extends React.Component< }} rows={rows} filteredRows={filteredRows} - columns={ - [ - { - key: 'display', - sortable: true, - // width: '40%', - wrapCustomHeadings: ({ headingRowIndex }: any) => - headingRowIndex === 0, - renderHeading: [ - this.renderDisplayHeadingName, - this.renderDisplayHeadingSearch, - ], - renderCell: this.renderDisplayCell, - }, - { - key: 'filteredCount', - className: cx('CountCell'), - sortable: true, - width: '13em', - helpText: ( -
- The number of {this.props.displayName} that match - the filters applied for other variables -
- and that have the given value -
- ), - wrapCustomHeadings: ({ headingRowIndex }: any) => - headingRowIndex === 0, - name: ( -
- Subset of {this.props.displayName} -
- ), - renderCell: this.renderCountCell, - }, - { - key: 'count', - className: cx('CountCell'), - sortable: true, - width: '13em', - helpText: ( -
- The number of {this.props.displayName} in the - dataset that have the given value -
- ), - wrapCustomHeadings: ({ headingRowIndex }: any) => - headingRowIndex === 0, - name: ( -
- All {this.props.displayName} -
- ), - renderCell: this.renderCountCell, - }, - { - key: 'distribution', - name: 'Distribution', - width: '30%', - helpText: ( -
- The subset of {this.props.displayName} that have - the given value when other filters have been applied -
- ), - renderCell: this.renderDistributionCell, - }, - { - key: '%', - width: '4em', - name: '%', - helpText: ( -
- The subset of {this.props.displayName} out of all{' '} - {this.props.displayName} that have the given value -
- ), - renderCell: this.renderPercentCell, - }, - ] as any - } + columns={[ + { + key: 'display', + sortable: true, + // width: '40%', + wrapCustomHeadings: ({ headingRowIndex }: any) => + headingRowIndex === 0, + renderHeading: [ + this.renderDisplayHeadingName, + this.renderDisplayHeadingSearch, + ], + renderCell: this.renderDisplayCell, + }, + { + key: 'filteredCount', + className: cx('CountCell'), + sortable: true, + width: '13em', + helpText: ( +
+ The number of {this.props.displayName} that match the + filters applied for other variables +
+ and that have the given value +
+ ), + wrapCustomHeadings: ({ headingRowIndex }: any) => + headingRowIndex === 0, + name: ( +
+ Subset of {this.props.displayName} +
+ ), + renderCell: this.renderCountCell, + }, + { + key: 'count', + className: cx('CountCell'), + sortable: true, + width: '13em', + helpText: ( +
+ The number of {this.props.displayName} in the dataset + that have the given value +
+ ), + wrapCustomHeadings: ({ headingRowIndex }: any) => + headingRowIndex === 0, + name: ( +
+ All {this.props.displayName} +
+ ), + renderCell: this.renderCountCell, + }, + { + key: 'distribution', + name: 'Distribution', + width: '30%', + helpText: ( +
+ The subset of {this.props.displayName} that have the + given value when other filters have been applied +
+ ), + renderCell: this.renderDistributionCell, + }, + { + key: '%', + width: '4em', + name: '%', + helpText: ( +
+ The subset of {this.props.displayName} out of all{' '} + {this.props.displayName} that have the given value +
+ ), + renderCell: this.renderPercentCell, + }, + ]} /> ); diff --git a/packages/libs/wdk-client/src/Components/AttributeFilter/NumberField.tsx b/packages/libs/wdk-client/src/Components/AttributeFilter/NumberField.tsx index 27752e3304..c7820dada9 100644 --- a/packages/libs/wdk-client/src/Components/AttributeFilter/NumberField.tsx +++ b/packages/libs/wdk-client/src/Components/AttributeFilter/NumberField.tsx @@ -3,6 +3,7 @@ import { partition } from 'lodash'; import { formatNumber } from '../../Components/AttributeFilter/AttributeFilterUtils'; import HistogramField from '../../Components/AttributeFilter/HistogramField'; +import { UIState } from '../../Components/AttributeFilter/Histogram'; import { Field, RangeFilter, @@ -35,8 +36,7 @@ interface NumberFieldProps { activeField: Field; activeFieldState: { summary: OntologyTermSummary; - [key: string]: any; - }; + } & UIState; filter?: RangeFilter; onChange: ( activeField: Field, @@ -45,8 +45,11 @@ interface NumberFieldProps { valueCounts: ValueCounts ) => void; displayName: string; + dataCount?: number; selectByDefault?: boolean; - [key: string]: any; + onRangeScaleChange?: (activeField: Field, range: any) => void; + histogramTruncateYAxisDefault?: boolean; + histogramScaleYAxisDefault?: boolean; } /** @@ -141,7 +144,7 @@ export default class NumberField extends React.Component { return ( | null; return ( Component && ( diff --git a/packages/libs/wdk-client/src/Components/AttributeFilter/Types.ts b/packages/libs/wdk-client/src/Components/AttributeFilter/Types.ts index 755a03a9fa..87089df37e 100644 --- a/packages/libs/wdk-client/src/Components/AttributeFilter/Types.ts +++ b/packages/libs/wdk-client/src/Components/AttributeFilter/Types.ts @@ -142,11 +142,13 @@ export type Filter = MemberFilter | RangeFilter | MultiFilter; export type FilterWithFieldDisplayName = Filter & { fieldDisplayName?: string }; -export type ValueCounts = Array<{ - value: string | number | null; - count: number; - filteredCount: number; -}>; +export type ValueCounts = Array< + { + value: string | number | null; + count: number; + filteredCount: number; + } & Record +>; export type OntologyTermSummary = { term: string; diff --git a/packages/libs/wdk-client/src/Components/Display/Sticky.tsx b/packages/libs/wdk-client/src/Components/Display/Sticky.tsx index b719e6436e..4fe39b751f 100644 --- a/packages/libs/wdk-client/src/Components/Display/Sticky.tsx +++ b/packages/libs/wdk-client/src/Components/Display/Sticky.tsx @@ -22,27 +22,17 @@ class Sticky extends React.Component { componentDidMount() { this.node = ReactDOM.findDOMNode(this); - window.addEventListener('scroll', this.updateIsFixed, { - passive: true, - } as any); - window.addEventListener('wheel', this.updateIsFixed, { - passive: true, - } as any); - window.addEventListener('resize', this.updateIsFixed, { - passive: true, - } as any); + const options: AddEventListenerOptions = { passive: true }; + window.addEventListener('scroll', this.updateIsFixed, options); + window.addEventListener('wheel', this.updateIsFixed, options); + window.addEventListener('resize', this.updateIsFixed, options); } componentWillUnmount() { - window.removeEventListener('scroll', this.updateIsFixed, { - passive: true, - } as any); - window.removeEventListener('wheel', this.updateIsFixed, { - passive: true, - } as any); - window.removeEventListener('resize', this.updateIsFixed, { - passive: true, - } as any); + const options: AddEventListenerOptions = { passive: true }; + window.removeEventListener('scroll', this.updateIsFixed, options); + window.removeEventListener('wheel', this.updateIsFixed, options); + window.removeEventListener('resize', this.updateIsFixed, options); } // Set position to fixed if top is above threshold, otherwise diff --git a/packages/libs/wdk-client/src/Components/Shared/CommonResultTable.tsx b/packages/libs/wdk-client/src/Components/Shared/CommonResultTable.tsx index 963004b5be..224a515459 100644 --- a/packages/libs/wdk-client/src/Components/Shared/CommonResultTable.tsx +++ b/packages/libs/wdk-client/src/Components/Shared/CommonResultTable.tsx @@ -12,6 +12,7 @@ import { RealTimeSearchBox } from '../../Components'; import { compose, debounce } from 'lodash/fp'; import type { MesaColumn, + MesaSortObject, MesaStateProps, } from '@veupathdb/coreui/lib/components/Mesa/types'; @@ -77,7 +78,11 @@ export class CommonResultTable< ? ({ columnKey: this.props.initialSortColumnKey, direction: this.props.initialSortDirection || 'asc', - } as any) + } as MesaSortObject< + Extract extends string + ? Extract + : string + >) : undefined, pagination: this.props.pagination ? { diff --git a/packages/libs/wdk-client/src/Controllers/WordCloudAnalysisController.tsx b/packages/libs/wdk-client/src/Controllers/WordCloudAnalysisController.tsx index 20483eb1b8..c2ac3d07ce 100644 --- a/packages/libs/wdk-client/src/Controllers/WordCloudAnalysisController.tsx +++ b/packages/libs/wdk-client/src/Controllers/WordCloudAnalysisController.tsx @@ -89,7 +89,7 @@ class WordCloudAnalysisController extends React.PureComponent { { key: 'word', display: 'Word' }, { key: 'count', display: 'Occurrence' }, ], - data: tags as any, + data: tags, }} visualizationConfig={{ display: 'Word Cloud', diff --git a/packages/libs/wdk-client/src/Views/Answer/AnswerTable.tsx b/packages/libs/wdk-client/src/Views/Answer/AnswerTable.tsx index 0309870c8e..422807323c 100644 --- a/packages/libs/wdk-client/src/Views/Answer/AnswerTable.tsx +++ b/packages/libs/wdk-client/src/Views/Answer/AnswerTable.tsx @@ -269,7 +269,11 @@ class AnswerTable extends React.Component { } } -(AnswerTable as any).defaultProps = { +( + AnswerTable as typeof AnswerTable & { + defaultProps: Partial; + } +).defaultProps = { onSort: noop, onMoveColumn: noop, onChangeColumns: noop, diff --git a/packages/libs/wdk-client/src/Views/AttributeAnalysis/AttributeAnalysisTabs.tsx b/packages/libs/wdk-client/src/Views/AttributeAnalysis/AttributeAnalysisTabs.tsx index a692138835..bc464ec3c6 100644 --- a/packages/libs/wdk-client/src/Views/AttributeAnalysis/AttributeAnalysisTabs.tsx +++ b/packages/libs/wdk-client/src/Views/AttributeAnalysis/AttributeAnalysisTabs.tsx @@ -16,7 +16,10 @@ import { } from '../../Actions/AttributeAnalysisActions'; import '../../Views/AttributeAnalysis/AttributeAnalysisTabs.scss'; -import { MesaColumn } from '@veupathdb/coreui/lib/components/Mesa/types'; +import { + MesaColumn, + MesaSortObject, +} from '@veupathdb/coreui/lib/components/Mesa/types'; export interface TableState { currentPage: number; @@ -123,13 +126,10 @@ export default class AttributeAnalysisTabs< onRowsPerPageChange: this.onRowsPerPageChange, }, uiState: { - // Assertion needed: Mesa's conditional type for MesaSortObject - // cannot be satisfied at compile time, but the object structure - // is correct at runtime sort: { columnKey: tableState.sort.key, direction: tableState.sort.direction, - } as any, + } as MesaSortObject, pagination: { currentPage, rowsPerPage, diff --git a/packages/libs/wdk-client/src/Views/AttributeAnalysis/WordCloudAnalysis/WordCloudAnalysis.tsx b/packages/libs/wdk-client/src/Views/AttributeAnalysis/WordCloudAnalysis/WordCloudAnalysis.tsx index e90c87900c..52825a1a86 100644 --- a/packages/libs/wdk-client/src/Views/AttributeAnalysis/WordCloudAnalysis/WordCloudAnalysis.tsx +++ b/packages/libs/wdk-client/src/Views/AttributeAnalysis/WordCloudAnalysis/WordCloudAnalysis.tsx @@ -9,7 +9,7 @@ import { RankRange, Sort } from '../../../Actions/WordCloudAnalysisActions'; import '../../../Views/AttributeAnalysis/WordCloudAnalysis/WordCloudAnalysis.scss'; -export interface Tag { +export interface Tag extends Record { word: string; count: number; } diff --git a/packages/libs/wdk-client/src/Views/Records/RecordMain/RecordMainCategorySection.tsx b/packages/libs/wdk-client/src/Views/Records/RecordMain/RecordMainCategorySection.tsx index 9a9c203a86..c17138d84f 100644 --- a/packages/libs/wdk-client/src/Views/Records/RecordMain/RecordMainCategorySection.tsx +++ b/packages/libs/wdk-client/src/Views/Records/RecordMain/RecordMainCategorySection.tsx @@ -10,7 +10,12 @@ import { CategoryTreeNode, IndividualNode, } from '../../../Utils/CategoryUtils'; -import { RecordInstance, RecordClass } from '../../../Utils/WdkModel'; +import { + RecordInstance, + RecordClass, + AttributeField, + TableField, +} from '../../../Utils/WdkModel'; import { TableState } from '../../../StoreModules/RecordStoreModule'; export interface Props { @@ -67,7 +72,9 @@ class RecordMainCategorySection extends React.PureComponent { case 'attribute': return ( { const individualCategory = category as IndividualNode; return ( updateTableState(individualCategory.wdkReference.name, tableState) @@ -113,7 +120,7 @@ class RecordMainCategorySection extends React.PureComponent { ); if (depth === 0) { - const HeaderElement = Header as any; + const HeaderElement = Header as keyof JSX.IntrinsicElements; return ( <> diff --git a/packages/libs/wdk-client/src/Views/Records/RecordNavigation/RecordNavigationSection.tsx b/packages/libs/wdk-client/src/Views/Records/RecordNavigation/RecordNavigationSection.tsx index fc4ae3f31b..6d37e32139 100644 --- a/packages/libs/wdk-client/src/Views/Records/RecordNavigation/RecordNavigationSection.tsx +++ b/packages/libs/wdk-client/src/Views/Records/RecordNavigation/RecordNavigationSection.tsx @@ -69,40 +69,40 @@ class RecordNavigationSection extends React.PureComponent< {visibilityToggle} ( - {})} - checked={!includes(collapsedSections, getId(node))} - /> - ), - linksPosition: LinksPosition.Top, - styleOverrides: { - treeSection: { - ul: { - padding: '0 0 0 1em', - }, + disableHelp={true} + visibilityFilter={visibilityFilter} + searchBoxPlaceholder="Search section names..." + tree={categoryTree} + leafType="section" + isSelectable={false} + selectedLeaves={[]} + onChange={() => {}} + expandedBranches={navigationCategoriesExpanded} + onUiChange={onNavigationCategoryExpansionChange} + searchTerm={navigationQuery} + onSearchTermChange={this.handleSearchTermChange} + renderNode={(node: any, path: any) => ( + {})} + checked={!includes(collapsedSections, getId(node))} + /> + )} + linksPosition={LinksPosition.Top} + styleOverrides={{ + treeSection: { + ul: { + padding: '0 0 0 1em', }, - treeNode: { - nodeWrapper: { - alignItems: 'center', - }, + }, + treeNode: { + nodeWrapper: { + alignItems: 'center', }, }, - } as any)} + }} /> ); diff --git a/packages/libs/wdk-client/src/Views/Records/RecordTable/RecordTableSection.tsx b/packages/libs/wdk-client/src/Views/Records/RecordTable/RecordTableSection.tsx index e440f450ab..d37bf8167c 100644 --- a/packages/libs/wdk-client/src/Views/Records/RecordTable/RecordTableSection.tsx +++ b/packages/libs/wdk-client/src/Views/Records/RecordTable/RecordTableSection.tsx @@ -76,7 +76,9 @@ function RecordTableSection(props: Props) { > {isError ? (

diff --git a/packages/libs/wdk-client/src/Views/Records/RecordUI.tsx b/packages/libs/wdk-client/src/Views/Records/RecordUI.tsx index 9bf16a5f78..80a6de22de 100644 --- a/packages/libs/wdk-client/src/Views/Records/RecordUI.tsx +++ b/packages/libs/wdk-client/src/Views/Records/RecordUI.tsx @@ -87,15 +87,13 @@ class RecordUI extends Component { } monitorActiveSection(): void { - window.addEventListener('scroll', this._updateActiveSection, { - passive: true, - } as any); + const options: AddEventListenerOptions = { passive: true }; + window.addEventListener('scroll', this._updateActiveSection, options); } unmonitorActiveSection(): void { - window.removeEventListener('scroll', this._updateActiveSection, { - passive: true, - } as any); + const options: AddEventListenerOptions = { passive: true }; + window.removeEventListener('scroll', this._updateActiveSection, options); } getHeaderOffset(): number { @@ -224,27 +222,22 @@ class RecordUI extends Component {

{this.props.navigationVisible ? ( - this.props.updateSectionVisibility(id, value ?? false), - onNavigationVisibilityChange: - this.props.updateNavigationVisibility, - onNavigationCategoryExpansionChange: - this.props.updateNavigationCategoryExpansion, - onNavigationQueryChange: this.props.updateNavigationQuery, - requestPartialRecord: this.props.requestPartialRecord, - } as any)} + visibilityToggle={visibilityToggle} + heading={this.props.record.displayName} + categoryTree={this.props.categoryTree} + collapsedSections={this.props.collapsedSections} + activeSection={this.state.activeSectionId ?? ''} + navigationQuery={this.props.navigationQuery} + navigationCategoriesExpanded={ + this.props.navigationCategoriesExpanded + } + onSectionToggle={(id: string, value?: boolean) => + this.props.updateSectionVisibility(id, value ?? false) + } + onNavigationCategoryExpansionChange={ + this.props.updateNavigationCategoryExpansion + } + onNavigationQueryChange={this.props.updateNavigationQuery} /> ) : ( visibilityToggle @@ -252,17 +245,14 @@ class RecordUI extends Component {
(this.recordMainSectionNode = findDOMNode(c)), - record: this.props.record, - recordClass: this.props.recordClass, - categories: this.props.categoryTree.children, - collapsedSections: this.props.collapsedSections, - onSectionToggle: this.props.updateSectionVisibility, - requestPartialRecord: this.props.requestPartialRecord, - tableStates: this.props.tableStates, - updateTableState: this.props.updateTableState, - } as any)} + record={this.props.record} + recordClass={this.props.recordClass} + categories={this.props.categoryTree.children} + collapsedSections={this.props.collapsedSections} + onSectionToggle={this.props.updateSectionVisibility} + requestPartialRecord={this.props.requestPartialRecord} + tableStates={this.props.tableStates} + updateTableState={this.props.updateTableState} />
diff --git a/packages/libs/wdk-client/src/Views/Strategy/StrategyControls.tsx b/packages/libs/wdk-client/src/Views/Strategy/StrategyControls.tsx index e6284271ec..02041d522f 100644 --- a/packages/libs/wdk-client/src/Views/Strategy/StrategyControls.tsx +++ b/packages/libs/wdk-client/src/Views/Strategy/StrategyControls.tsx @@ -137,7 +137,7 @@ function ShareAction(props: ActionProps) { /> link