/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */ import memoizeOne from 'memoize-one' ; import { DataRecord , extractTimegrain , GenericDataType , getMetricLabel , getNumberFormatter , getTimeFormatter , getTimeFormatterForGranularity , NumberFormats , QueryMode , smartDateFormatter , TimeFormats , TimeFormatter , } from '@superset-ui/core' ; import { getColorFormatters } from '@superset-ui/chart-controls' ; import isEqualColumns from './utils/isEqualColumns' ; import DateWithFormatter from './utils/DateWithFormatter' ; import { DataColumnMeta , TableChartProps , TableChartTransformedProps , } from './types' ; const { PERCENT_3_POINT } = NumberFormats ; const { DATABASE_DATETIME } = TimeFormats ; function isNumeric ( key , data = [ ] ) { return data . every ( x => x [ key ] === null || x [ key ] === undefined || typeof x [ key ] === 'number' ) ; } const processDataRecords = memoizeOne ( function processDataRecords ( data , columns ) { if ( ! data || ! data [ 0 ] ) { return data || [ ] ; } const timeColumns = columns . filter ( column => column . dataType === GenericDataType . TEMPORAL ) ; if ( timeColumns . length > 0 ) { return data . map ( x => { const datum = { ... x } ; timeColumns . forEach ( ( { key , formatter } ) => { datum [ key ] = new DateWithFormatter ( x [ key ] , { formatter : formatter as TimeFormatter , } ) ; } ) ; return datum ; } ) ; } return data ; } ) ; const processColumns = memoizeOne ( function processColumns ( props ) { const { datasource : { columnFormats , verboseMap } , rawFormData : { table_timestamp_format : tableTimestampFormat , metrics : metrics_ , percent_metrics : percentMetrics_ , column_config : columnConfig = { } , } , queriesData , } = props ; const granularity = extractTimegrain ( props . rawFormData ) ; const { data : records , colnames , coltypes } = queriesData [ 0 ] || { } ; const metrics = ( metrics_ ?? [ ] ) . map ( getMetricLabel ) ; const rawPercentMetrics = ( percentMetrics_ ?? [ ] ) . map ( getMetricLabel ) ; const percentMetrics = rawPercentMetrics . map ( ( x ) => `%${ x }` ) ; const metricsSet = new Set ( metrics ) ; const percentMetricsSet = new Set ( percentMetrics ) ; const rawPercentMetricsSet = new Set ( rawPercentMetrics ) ; const columns = ( colnames || [ ] ) . filter ( key => ! ( rawPercentMetricsSet . has ( key ) && ! metricsSet . has ( key ) ) ) . map ( ( key , i ) => { const label = verboseMap ?. [ key ] || key ; const dataType = coltypes [ i ] ; const config = columnConfig [ key ] || { } ; const isMetric = metricsSet . has ( key ) && isNumeric ( key , records ) ; const isPercentMetric = percentMetricsSet . has ( key ) ; const isTime = dataType === GenericDataType . TEMPORAL ; const savedFormat = columnFormats ?. [ key ] ; const numberFormat = config . d3NumberFormat || savedFormat ; let formatter ; if ( isTime || config . d3TimeFormat ) { const customFormat = config . d3TimeFormat || savedFormat ; const timeFormat = customFormat || tableTimestampFormat ; if ( timeFormat === smartDateFormatter . id ) { if ( granularity ) { formatter = getTimeFormatterForGranularity ( granularity ) ; } else if ( customFormat ) { formatter = getTimeFormatter ( customFormat ) ; } else if ( isNumeric ( key , records ) ) { formatter = getTimeFormatter ( DATABASE_DATETIME ) ; } else { formatter = String ; } } else if ( timeFormat ) { formatter = getTimeFormatter ( timeFormat ) ; } } else if ( isPercentMetric ) { formatter = getNumberFormatter ( numberFormat || PERCENT_3_POINT ) ; } else if ( isMetric || numberFormat ) { formatter = getNumberFormatter ( numberFormat ) ; } return { key , label , dataType , isNumeric : dataType === GenericDataType . NUMERIC , isMetric , isPercentMetric , formatter , config , } ; } ) ; return [ metrics , percentMetrics , columns ] as [ typeof metrics , typeof percentMetrics , typeof columns ] ; } , isEqualColumns ) ; /**
 * Automatically set page size based on number of cells.
 */ const getPageSize = ( pageSize , numRecords , numColumns ) => { if ( typeof pageSize === 'number' ) { return pageSize || 0 ; } if ( typeof pageSize === 'string' ) { return Number ( pageSize ) || 0 ; } return numRecords * numColumns > 5000 ? 200 : 0 ; } ; const transformProps = ( chartProps ) : TableChartTransformedProps => { const { height , width , rawFormData : formData , queriesData = [ ] , filterState , ownState : serverPaginationData = { } , hooks : { onAddFilter : onChangeFilter , setDataMask = ( ) => { } } , } = chartProps ; const { align_pn : alignPositiveNegative = true , color_pn : colorPositiveNegative = true , show_cell_bars : showCellBars = true , include_search : includeSearch = false , page_length : pageLength , emit_filter : emitFilter , server_pagination : serverPagination = false , server_page_length : serverPageLength = 10 , order_desc : sortDesc = false , query_mode : queryMode , show_totals : showTotals , conditional_formatting : conditionalFormatting , } = formData ; const timeGrain = extractTimegrain ( formData ) ; const [ metrics , percentMetrics , columns ] = processColumns ( chartProps ) ; let baseQuery ; let countQuery ; let totalQuery ; let rowCount ; if ( serverPagination ) { [ baseQuery , countQuery , totalQuery ] = queriesData ; rowCount = ( countQuery ?. data ?. [ 0 ] ?. rowcount as number ) ?? 0 ; } else { [ baseQuery , totalQuery ] = queriesData ; rowCount = baseQuery ?. rowcount ?? 0 ; } const data = processDataRecords ( baseQuery ?. data , columns ) ; const totals = showTotals && queryMode === QueryMode . aggregate ? totalQuery ?. data [ 0 ] : undefined ; const columnColorFormatters = getColorFormatters ( conditionalFormatting , data ) ?? [ ] ; return { height , width , isRawRecords : queryMode === QueryMode . raw , data , totals , columns , serverPagination , metrics , percentMetrics , serverPaginationData , setDataMask , alignPositiveNegative , colorPositiveNegative , showCellBars , sortDesc , includeSearch , rowCount , pageSize : serverPagination ? serverPageLength : getPageSize ( pageLength , data . length , columns . length ) , filters : filterState . filters , emitFilter , onChangeFilter , columnColorFormatters , timeGrain , } ; } ; export default transformProps ;