1import React from 'react'; 2import { merge } from 'lodash'; 3import { Table } from '@grafana/ui'; 4import { withCenteredStory } from '../../utils/storybook/withCenteredStory'; 5import { Meta, Story } from '@storybook/react'; 6import { useTheme2 } from '../../themes'; 7import mdx from './Table.mdx'; 8import { 9 DataFrame, 10 FieldType, 11 GrafanaTheme2, 12 MutableDataFrame, 13 ThresholdsConfig, 14 ThresholdsMode, 15 FieldConfig, 16 formattedValueToString, 17} from '@grafana/data'; 18import { prepDataForStorybook } from '../../utils/storybook/data'; 19import { FooterItem } from './types'; 20 21export default { 22 title: 'Visualizations/Table', 23 component: Table, 24 decorators: [withCenteredStory], 25 parameters: { 26 controls: { 27 exclude: ['onColumnResize', 'onSortByChange', 'onCellFilterAdded', 'ariaLabel', 'data', 'initialSortBy'], 28 }, 29 docs: { 30 page: mdx, 31 }, 32 }, 33 args: { 34 width: 700, 35 height: 500, 36 columnMinWidth: 150, 37 }, 38} as Meta; 39 40function buildData(theme: GrafanaTheme2, config: Record<string, FieldConfig>): DataFrame { 41 const data = new MutableDataFrame({ 42 fields: [ 43 { name: 'Time', type: FieldType.time, values: [] }, // The time field 44 { 45 name: 'Quantity', 46 type: FieldType.number, 47 values: [], 48 config: { 49 decimals: 0, 50 custom: { 51 align: 'center', 52 width: 80, 53 }, 54 }, 55 }, 56 { name: 'Status', type: FieldType.string, values: [] }, // The time field 57 { 58 name: 'Value', 59 type: FieldType.number, 60 values: [], 61 config: { 62 decimals: 2, 63 }, 64 }, 65 { 66 name: 'Progress', 67 type: FieldType.number, 68 values: [], 69 config: { 70 unit: 'percent', 71 min: 0, 72 max: 100, 73 custom: { 74 width: 150, 75 }, 76 }, 77 }, 78 ], 79 }); 80 81 for (const field of data.fields) { 82 field.config = merge(field.config, config[field.name]); 83 } 84 85 for (let i = 0; i < 1000; i++) { 86 data.appendRow([ 87 new Date().getTime(), 88 Math.random() * 2, 89 Math.random() > 0.7 ? 'Active' : 'Cancelled', 90 Math.random() * 100, 91 Math.random() * 100, 92 ]); 93 } 94 95 return prepDataForStorybook([data], theme)[0]; 96} 97 98function buildFooterData(data: DataFrame): FooterItem[] { 99 const values = data.fields[3].values.toArray(); 100 const valueSum = values.reduce((prev, curr) => { 101 return prev + curr; 102 }, 0); 103 104 const valueField = data.fields[3]; 105 const displayValue = valueField.display ? valueField.display(valueSum) : valueSum; 106 const val = valueField.display ? formattedValueToString(displayValue) : displayValue; 107 108 const sum = { sum: val }; 109 const min = { min: String(5.2) }; 110 const valCell = [sum, min]; 111 112 return ['Totals', '10', undefined, valCell, '100%']; 113} 114 115const defaultThresholds: ThresholdsConfig = { 116 steps: [ 117 { 118 color: 'blue', 119 value: -Infinity, 120 }, 121 { 122 color: 'green', 123 value: 20, 124 }, 125 ], 126 mode: ThresholdsMode.Absolute, 127}; 128 129export const Basic: Story = (args) => { 130 const theme = useTheme2(); 131 const data = buildData(theme, {}); 132 133 return ( 134 <div className="panel-container" style={{ width: 'auto' }}> 135 <Table data={data} height={args.height} width={args.width} {...args} /> 136 </div> 137 ); 138}; 139 140export const BarGaugeCell: Story = (args) => { 141 const theme = useTheme2(); 142 const data = buildData(theme, { 143 Progress: { 144 custom: { 145 width: 200, 146 displayMode: 'gradient-gauge', 147 }, 148 thresholds: defaultThresholds, 149 }, 150 }); 151 152 return ( 153 <div className="panel-container" style={{ width: 'auto' }}> 154 <Table data={data} height={args.height} width={args.width} {...args} /> 155 </div> 156 ); 157}; 158 159export const ColoredCells: Story = (args) => { 160 const theme = useTheme2(); 161 const data = buildData(theme, { 162 Progress: { 163 custom: { 164 width: 80, 165 displayMode: 'color-background', 166 }, 167 thresholds: defaultThresholds, 168 }, 169 }); 170 171 return ( 172 <div className="panel-container" style={{ width: 'auto' }}> 173 <Table data={data} height={args.height} width={args.width} {...args} /> 174 </div> 175 ); 176}; 177 178export const Footer: Story = (args) => { 179 const theme = useTheme2(); 180 const data = buildData(theme, {}); 181 const footer = buildFooterData(data); 182 183 return ( 184 <div className="panel-container" style={{ width: 'auto', height: 'unset' }}> 185 <Table data={data} height={args.height} width={args.width} footerValues={footer} {...args} /> 186 </div> 187 ); 188}; 189