StatPanel.tsx 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. import { isNumber } from 'lodash';
  2. import React, { PureComponent } from 'react';
  3. import {
  4. DisplayValueAlignmentFactors,
  5. FieldDisplay,
  6. FieldType,
  7. getDisplayValueAlignmentFactors,
  8. getFieldDisplayValues,
  9. NumericRange,
  10. PanelProps,
  11. } from '@grafana/data';
  12. import { findNumericFieldMinMax } from '@grafana/data/src/field/fieldOverrides';
  13. import {
  14. BigValue,
  15. BigValueGraphMode,
  16. DataLinksContextMenu,
  17. VizRepeater,
  18. VizRepeaterRenderValueProps,
  19. BigValueTextMode,
  20. } from '@grafana/ui';
  21. import { DataLinksContextMenuApi } from '@grafana/ui/src/components/DataLinks/DataLinksContextMenu';
  22. import { config } from 'app/core/config';
  23. import { StatPanelOptions } from './types';
  24. export class StatPanel extends PureComponent<PanelProps<StatPanelOptions>> {
  25. renderComponent = (
  26. valueProps: VizRepeaterRenderValueProps<FieldDisplay, DisplayValueAlignmentFactors>,
  27. menuProps: DataLinksContextMenuApi
  28. ): JSX.Element => {
  29. const { timeRange, options } = this.props;
  30. const { value, alignmentFactors, width, height, count } = valueProps;
  31. const { openMenu, targetClassName } = menuProps;
  32. let sparkline = value.sparkline;
  33. if (sparkline) {
  34. sparkline.timeRange = timeRange;
  35. }
  36. return (
  37. <BigValue
  38. value={value.display}
  39. count={count}
  40. sparkline={sparkline}
  41. colorMode={options.colorMode}
  42. graphMode={options.graphMode}
  43. justifyMode={options.justifyMode}
  44. textMode={this.getTextMode()}
  45. alignmentFactors={alignmentFactors}
  46. text={options.text}
  47. width={width}
  48. height={height}
  49. theme={config.theme2}
  50. onClick={openMenu}
  51. className={targetClassName}
  52. />
  53. );
  54. };
  55. getTextMode() {
  56. const { options, fieldConfig, title } = this.props;
  57. // If we have manually set displayName or panel title switch text mode to value and name
  58. if (options.textMode === BigValueTextMode.Auto && (fieldConfig.defaults.displayName || !title)) {
  59. return BigValueTextMode.ValueAndName;
  60. }
  61. return options.textMode;
  62. }
  63. renderValue = (valueProps: VizRepeaterRenderValueProps<FieldDisplay, DisplayValueAlignmentFactors>): JSX.Element => {
  64. const { value } = valueProps;
  65. const { getLinks, hasLinks } = value;
  66. if (hasLinks && getLinks) {
  67. return (
  68. <DataLinksContextMenu links={getLinks} config={value.field}>
  69. {(api) => {
  70. return this.renderComponent(valueProps, api);
  71. }}
  72. </DataLinksContextMenu>
  73. );
  74. }
  75. return this.renderComponent(valueProps, {});
  76. };
  77. getValues = (): FieldDisplay[] => {
  78. const { data, options, replaceVariables, fieldConfig, timeZone } = this.props;
  79. let globalRange: NumericRange | undefined = undefined;
  80. for (let frame of data.series) {
  81. for (let field of frame.fields) {
  82. let { config } = field;
  83. // mostly copied from fieldOverrides, since they are skipped during streaming
  84. // Set the Min/Max value automatically
  85. if (field.type === FieldType.number) {
  86. if (field.state?.range) {
  87. continue;
  88. }
  89. if (!globalRange && (!isNumber(config.min) || !isNumber(config.max))) {
  90. globalRange = findNumericFieldMinMax(data.series);
  91. }
  92. const min = config.min ?? globalRange!.min;
  93. const max = config.max ?? globalRange!.max;
  94. field.state = field.state ?? {};
  95. field.state.range = { min, max, delta: max! - min! };
  96. }
  97. }
  98. }
  99. return getFieldDisplayValues({
  100. fieldConfig,
  101. reduceOptions: options.reduceOptions,
  102. replaceVariables,
  103. theme: config.theme2,
  104. data: data.series,
  105. sparkline: options.graphMode !== BigValueGraphMode.None,
  106. timeZone,
  107. });
  108. };
  109. render() {
  110. const { height, options, width, data, renderCounter } = this.props;
  111. return (
  112. <VizRepeater
  113. getValues={this.getValues}
  114. getAlignmentFactors={getDisplayValueAlignmentFactors}
  115. renderValue={this.renderValue}
  116. width={width}
  117. height={height}
  118. source={data}
  119. itemSpacing={3}
  120. renderCounter={renderCounter}
  121. autoGrid={true}
  122. orientation={options.orientation}
  123. />
  124. );
  125. }
  126. }