import styled from '@emotion/styled'; import type {Polarity} from 'sentry/components/percentChange'; import {Tooltip} from 'sentry/components/tooltip'; import {defined} from 'sentry/utils'; import type {MetaType} from 'sentry/utils/discover/eventView'; import {getFieldRenderer} from 'sentry/utils/discover/fieldRenderers'; import {useLocation} from 'sentry/utils/useLocation'; import useOrganization from 'sentry/utils/useOrganization'; import {AutoSizedText} from 'sentry/views/dashboards/widgetCard/autoSizedText'; import {DifferenceToPreviousPeriodValue} from 'sentry/views/dashboards/widgets/bigNumberWidget/differenceToPreviousPeriodValue'; import type { Meta, TableData, Thresholds, } from 'sentry/views/dashboards/widgets/common/types'; import {X_GUTTER, Y_GUTTER} from '../common/settings'; import {ThresholdsIndicator} from './thresholdsIndicator'; export interface BigNumberWidgetVisualizationProps { field: string; value: number | string; maximumValue?: number; meta?: Meta; preferredPolarity?: Polarity; previousPeriodValue?: number | string; thresholds?: Thresholds; } export function BigNumberWidgetVisualization(props: BigNumberWidgetVisualizationProps) { const { field, value, previousPeriodValue, maximumValue = Number.MAX_VALUE, preferredPolarity, meta, } = props; const location = useLocation(); const organization = useOrganization(); // TODO: meta as MetaType is a white lie. `MetaType` doesn't know that types can be null, but they can! const fieldRenderer = meta ? getFieldRenderer(field, meta as MetaType, false) : renderableValue => renderableValue.toString(); const unit = meta?.units?.[field]; const type = meta?.fields?.[field]; const baggage = { location, organization, unit: unit ?? undefined, // TODO: Field formatters think units can't be null but they can }; // String values don't support differences, thresholds, max values, or anything else. if (typeof value === 'string') { return ( {fieldRenderer( { [field]: value, }, baggage )} ); } const doesValueHitMaximum = maximumValue ? value >= maximumValue : false; const clampedValue = Math.min(value, maximumValue); return ( {defined(props.thresholds?.max_values.max1) && defined(props.thresholds?.max_values.max2) && ( )} {doesValueHitMaximum ? '>' : ''} {fieldRenderer( { [field]: clampedValue, }, baggage )} {defined(previousPeriodValue) && typeof previousPeriodValue === 'number' && Number.isFinite(previousPeriodValue) && !Number.isNaN(previousPeriodValue) && !doesValueHitMaximum && ( fieldRenderer(previousDatum, baggage) } /> )} ); } function Wrapper({children}) { return ( {children} ); } const AutoResizeParent = styled('div')` position: absolute; inset: ${Y_GUTTER} ${X_GUTTER} ${Y_GUTTER} ${X_GUTTER}; color: ${p => p.theme.headingColor}; container-type: size; container-name: auto-resize-parent; * { line-height: 1; text-align: left !important; } `; const NumberAndDifferenceContainer = styled('div')` display: flex; align-items: flex-end; gap: min(8px, 3cqw); `; const NumberContainerOverride = styled('div')` display: inline-flex; * { text-overflow: clip !important; display: inline; white-space: nowrap; } `;