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