Skip to content
Snippets Groups Projects
Select Git revision
  • 8f35a3ec8ca135d455e4c8097c746bc5eeaceee0
  • master default protected
  • release
3 results

transformProps.ts

Blame
  • transformProps.ts 6.28 KiB
    /**
     * 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 dayjs from 'dayjs';
    import utc from 'dayjs/plugin/utc';
    import {
      ChartProps,
      getMetricLabel,
      getValueFormatter,
      getNumberFormatter,
      SimpleAdhocFilter,
      ensureIsArray,
    } from '@superset-ui/core';
    import { getComparisonFontSize, getHeaderFontSize } from './utils';
    
    dayjs.extend(utc);
    
    export const parseMetricValue = (metricValue: number | string | null) => {
      if (typeof metricValue === 'string') {
        const dateObject = dayjs.utc(metricValue, undefined, true);
        if (dateObject.isValid()) {
          return dateObject.valueOf();
        }
        return 0;
      }
      return metricValue ?? 0;
    };
    
    export default function transformProps(chartProps: ChartProps) {
      /**
       * This function is called after a successful response has been
       * received from the chart data endpoint, and is used to transform
       * the incoming data prior to being sent to the Visualization.
       *
       * The transformProps function is also quite useful to return
       * additional/modified props to your data viz component. The formData
       * can also be accessed from your CustomViz.tsx file, but
       * doing supplying custom props here is often handy for integrating third
       * party libraries that rely on specific props.
       *
       * A description of properties in `chartProps`:
       * - `height`, `width`: the height/width of the DOM element in which
       *   the chart is located
       * - `formData`: the chart data request payload that was sent to the
       *   backend.
       * - `queriesData`: the chart data response payload that was received
       *   from the backend. Some notable properties of `queriesData`:
       *   - `data`: an array with data, each row with an object mapping
       *     the column/alias to its value. Example:
       *     `[{ col1: 'abc', metric1: 10 }, { col1: 'xyz', metric1: 20 }]`
       *   - `rowcount`: the number of rows in `data`
       *   - `query`: the query that was issued.
       *
       * Please note: the transformProps function gets cached when the
       * application loads. When making changes to the `transformProps`
       * function during development with hot reloading, changes won't
       * be seen until restarting the development server.
       */
      const {
        width,
        height,
        formData,
        queriesData,
        datasource: { currencyFormats = {}, columnFormats = {} },
      } = chartProps;
      const {
        boldText,
        headerFontSize,
        headerText,
        metric,
        yAxisFormat,
        currencyFormat,
        subheaderFontSize,
        comparisonColorScheme,
        comparisonColorEnabled,
        percentDifferenceFormat,
        columnConfig,
      } = formData;
      const { data: dataA = [] } = queriesData[0];
      const data = dataA;
      const metricName = metric ? getMetricLabel(metric) : '';
      const timeComparison = ensureIsArray(chartProps.rawFormData?.time_compare)[0];
      const startDateOffset = chartProps.rawFormData?.start_date_offset;
      const currentTimeRangeFilter = chartProps.rawFormData?.adhoc_filters?.filter(
        (adhoc_filter: SimpleAdhocFilter) =>
          adhoc_filter.operator === 'TEMPORAL_RANGE',
      )?.[0];
    
      const isCustomOrInherit =
        timeComparison === 'custom' || timeComparison === 'inherit';
      let dataOffset: string[] = [];
      if (isCustomOrInherit) {
        if (timeComparison && timeComparison === 'custom') {
          dataOffset = [startDateOffset];
        } else {
          dataOffset = ensureIsArray(timeComparison) || [];
        }
      }
    
      const { value1, value2 } = data.reduce(
        (acc: { value1: number; value2: number }, curr: { [x: string]: any }) => {
          Object.keys(curr).forEach(key => {
            if (
              key.includes(
                `${metricName}__${
                  !isCustomOrInherit ? timeComparison : dataOffset[0]
                }`,
              )
            ) {
              acc.value2 += curr[key];
            } else if (key.includes(metricName)) {
              acc.value1 += curr[key];
            }
          });
          return acc;
        },
        { value1: 0, value2: 0 },
      );
    
      let bigNumber: number | string =
        data.length === 0 ? 0 : parseMetricValue(value1);
      let prevNumber: number | string =
        data.length === 0 ? 0 : parseMetricValue(value2);
    
      const numberFormatter = getValueFormatter(
        metric,
        currencyFormats,
        columnFormats,
        yAxisFormat,
        currencyFormat,
      );
    
      const compTitles = {
        r: 'Range' as string,
        y: 'Year' as string,
        m: 'Month' as string,
        w: 'Week' as string,
      };
    
      const formatPercentChange = getNumberFormatter(percentDifferenceFormat);
    
      let valueDifference: number | string = bigNumber - prevNumber;
    
      let percentDifferenceNum;
    
      if (!bigNumber && !prevNumber) {
        percentDifferenceNum = 0;
      } else if (!bigNumber || !prevNumber) {
        percentDifferenceNum = bigNumber ? 1 : -1;
      } else {
        percentDifferenceNum = (bigNumber - prevNumber) / Math.abs(prevNumber);
      }
    
      const compType =
        compTitles[formData.timeComparison as keyof typeof compTitles];
      bigNumber = numberFormatter(bigNumber);
      prevNumber = numberFormatter(prevNumber);
      valueDifference = numberFormatter(valueDifference);
      const percentDifference: string = formatPercentChange(percentDifferenceNum);
    
      return {
        width,
        height,
        data,
        metricName,
        bigNumber,
        prevNumber,
        valueDifference,
        percentDifferenceFormattedString: percentDifference,
        boldText,
        headerFontSize: getHeaderFontSize(headerFontSize),
        subheaderFontSize: getComparisonFontSize(subheaderFontSize),
        headerText,
        compType,
        comparisonColorEnabled,
        comparisonColorScheme,
        percentDifferenceNumber: percentDifferenceNum,
        currentTimeRangeFilter,
        startDateOffset,
        shift: timeComparison,
        dashboardTimeRange: formData?.extraFormData?.time_range,
        columnConfig,
      };
    }