| 
									
										
										
										
											2020-09-01 23:06:35 +08:00
										 |  |  | import { Column, Row } from 'react-table'; | 
					
						
							|  |  |  | import memoizeOne from 'memoize-one'; | 
					
						
							| 
									
										
										
										
											2020-09-25 02:09:01 +08:00
										 |  |  | import { ContentPosition } from 'csstype'; | 
					
						
							| 
									
										
										
										
											2020-09-01 23:06:35 +08:00
										 |  |  | import { | 
					
						
							|  |  |  |   DataFrame, | 
					
						
							|  |  |  |   Field, | 
					
						
							|  |  |  |   FieldType, | 
					
						
							|  |  |  |   formattedValueToString, | 
					
						
							|  |  |  |   getFieldDisplayName, | 
					
						
							|  |  |  |   SelectableValue, | 
					
						
							|  |  |  | } from '@grafana/data'; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-13 18:12:19 +08:00
										 |  |  | import { DefaultCell } from './DefaultCell'; | 
					
						
							| 
									
										
										
										
											2019-12-23 13:22:54 +08:00
										 |  |  | import { BarGaugeCell } from './BarGaugeCell'; | 
					
						
							| 
									
										
										
										
											2021-09-01 00:37:10 +08:00
										 |  |  | import { CellComponent, TableCellDisplayMode, TableFieldOptions, FooterItem } from './types'; | 
					
						
							| 
									
										
										
										
											2020-04-21 02:10:03 +08:00
										 |  |  | import { JSONViewCell } from './JSONViewCell'; | 
					
						
							| 
									
										
										
										
											2020-09-25 02:09:01 +08:00
										 |  |  | import { ImageCell } from './ImageCell'; | 
					
						
							| 
									
										
										
										
											2021-09-01 00:37:10 +08:00
										 |  |  | import { getFooterValue } from './FooterRow'; | 
					
						
							| 
									
										
										
										
											2019-12-23 13:22:54 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-25 02:09:01 +08:00
										 |  |  | export function getTextAlign(field?: Field): ContentPosition { | 
					
						
							| 
									
										
										
										
											2020-04-01 20:24:17 +08:00
										 |  |  |   if (!field) { | 
					
						
							| 
									
										
										
										
											2020-09-25 02:09:01 +08:00
										 |  |  |     return 'flex-start'; | 
					
						
							| 
									
										
										
										
											2020-04-01 20:24:17 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-12-23 13:22:54 +08:00
										 |  |  |   if (field.config.custom) { | 
					
						
							|  |  |  |     const custom = field.config.custom as TableFieldOptions; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     switch (custom.align) { | 
					
						
							|  |  |  |       case 'right': | 
					
						
							| 
									
										
										
										
											2020-09-25 02:09:01 +08:00
										 |  |  |         return 'flex-end'; | 
					
						
							| 
									
										
										
										
											2019-12-23 13:22:54 +08:00
										 |  |  |       case 'left': | 
					
						
							| 
									
										
										
										
											2020-09-25 02:09:01 +08:00
										 |  |  |         return 'flex-start'; | 
					
						
							| 
									
										
										
										
											2019-12-23 13:22:54 +08:00
										 |  |  |       case 'center': | 
					
						
							|  |  |  |         return 'center'; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (field.type === FieldType.number) { | 
					
						
							| 
									
										
										
										
											2020-09-25 02:09:01 +08:00
										 |  |  |     return 'flex-end'; | 
					
						
							| 
									
										
										
										
											2019-12-23 13:22:54 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-25 02:09:01 +08:00
										 |  |  |   return 'flex-start'; | 
					
						
							| 
									
										
										
										
											2019-12-23 13:22:54 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-01 00:37:10 +08:00
										 |  |  | export function getColumns( | 
					
						
							|  |  |  |   data: DataFrame, | 
					
						
							|  |  |  |   availableWidth: number, | 
					
						
							|  |  |  |   columnMinWidth: number, | 
					
						
							|  |  |  |   footerValues?: FooterItem[] | 
					
						
							|  |  |  | ): Column[] { | 
					
						
							| 
									
										
										
										
											2020-06-08 20:28:45 +08:00
										 |  |  |   const columns: any[] = []; | 
					
						
							| 
									
										
										
										
											2019-12-23 13:22:54 +08:00
										 |  |  |   let fieldCountWithoutWidth = data.fields.length; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-13 21:34:23 +08:00
										 |  |  |   for (const [fieldIndex, field] of data.fields.entries()) { | 
					
						
							| 
									
										
										
										
											2019-12-23 13:22:54 +08:00
										 |  |  |     const fieldTableOptions = (field.config.custom || {}) as TableFieldOptions; | 
					
						
							| 
									
										
										
										
											2020-04-20 15:27:40 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-13 21:34:23 +08:00
										 |  |  |     if (fieldTableOptions.hidden) { | 
					
						
							|  |  |  |       continue; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-12-23 13:22:54 +08:00
										 |  |  |     if (fieldTableOptions.width) { | 
					
						
							|  |  |  |       availableWidth -= fieldTableOptions.width; | 
					
						
							|  |  |  |       fieldCountWithoutWidth -= 1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-08 20:28:45 +08:00
										 |  |  |     const selectSortType = (type: FieldType): string => { | 
					
						
							|  |  |  |       switch (type) { | 
					
						
							|  |  |  |         case FieldType.number: | 
					
						
							| 
									
										
										
										
											2021-05-31 12:12:56 +08:00
										 |  |  |           return 'number'; | 
					
						
							| 
									
										
										
										
											2020-06-08 20:28:45 +08:00
										 |  |  |         case FieldType.time: | 
					
						
							|  |  |  |           return 'basic'; | 
					
						
							|  |  |  |         default: | 
					
						
							| 
									
										
										
										
											2021-04-07 21:28:51 +08:00
										 |  |  |           return 'alphanumeric-insensitive'; | 
					
						
							| 
									
										
										
										
											2020-06-08 20:28:45 +08:00
										 |  |  |       } | 
					
						
							|  |  |  |     }; | 
					
						
							| 
									
										
										
										
											2020-09-25 02:09:01 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-21 02:10:03 +08:00
										 |  |  |     const Cell = getCellComponent(fieldTableOptions.displayMode, field); | 
					
						
							| 
									
										
										
										
											2020-01-13 18:12:19 +08:00
										 |  |  |     columns.push({ | 
					
						
							| 
									
										
										
										
											2019-12-23 13:22:54 +08:00
										 |  |  |       Cell, | 
					
						
							| 
									
										
										
										
											2020-04-20 15:27:40 +08:00
										 |  |  |       id: fieldIndex.toString(), | 
					
						
							| 
									
										
										
										
											2020-05-12 19:52:53 +08:00
										 |  |  |       Header: getFieldDisplayName(field, data), | 
					
						
							| 
									
										
										
										
											2020-04-20 15:27:40 +08:00
										 |  |  |       accessor: (row: any, i: number) => { | 
					
						
							|  |  |  |         return field.values.get(i); | 
					
						
							|  |  |  |       }, | 
					
						
							| 
									
										
										
										
											2020-06-08 20:28:45 +08:00
										 |  |  |       sortType: selectSortType(field.type), | 
					
						
							| 
									
										
										
										
											2019-12-23 13:22:54 +08:00
										 |  |  |       width: fieldTableOptions.width, | 
					
						
							| 
									
										
										
										
											2021-07-12 15:46:23 +08:00
										 |  |  |       minWidth: fieldTableOptions.minWidth || columnMinWidth, | 
					
						
							| 
									
										
										
										
											2020-11-02 14:26:58 +08:00
										 |  |  |       filter: memoizeOne(filterByValue(field)), | 
					
						
							| 
									
										
										
										
											2020-09-25 02:09:01 +08:00
										 |  |  |       justifyContent: getTextAlign(field), | 
					
						
							| 
									
										
										
										
											2021-09-01 00:37:10 +08:00
										 |  |  |       Footer: getFooterValue(fieldIndex, footerValues), | 
					
						
							| 
									
										
										
										
											2019-12-23 13:22:54 +08:00
										 |  |  |     }); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-12 15:46:23 +08:00
										 |  |  |   // set columns that are at minimum width
 | 
					
						
							|  |  |  |   let sharedWidth = availableWidth / fieldCountWithoutWidth; | 
					
						
							|  |  |  |   for (let i = fieldCountWithoutWidth; i > 0; i--) { | 
					
						
							|  |  |  |     for (const column of columns) { | 
					
						
							|  |  |  |       if (!column.width && column.minWidth > sharedWidth) { | 
					
						
							|  |  |  |         column.width = column.minWidth; | 
					
						
							|  |  |  |         availableWidth -= column.width; | 
					
						
							|  |  |  |         fieldCountWithoutWidth -= 1; | 
					
						
							|  |  |  |         sharedWidth = availableWidth / fieldCountWithoutWidth; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-12-23 13:22:54 +08:00
										 |  |  |   // divide up the rest of the space
 | 
					
						
							| 
									
										
										
										
											2020-01-13 18:12:19 +08:00
										 |  |  |   for (const column of columns) { | 
					
						
							| 
									
										
										
										
											2019-12-23 13:22:54 +08:00
										 |  |  |     if (!column.width) { | 
					
						
							| 
									
										
										
										
											2021-07-12 15:46:23 +08:00
										 |  |  |       column.width = sharedWidth; | 
					
						
							| 
									
										
										
										
											2019-12-23 13:22:54 +08:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2021-07-12 15:46:23 +08:00
										 |  |  |     column.minWidth = 50; | 
					
						
							| 
									
										
										
										
											2019-12-23 13:22:54 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-13 18:12:19 +08:00
										 |  |  |   return columns; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-01 00:37:10 +08:00
										 |  |  | function getCellComponent(displayMode: TableCellDisplayMode, field: Field): CellComponent { | 
					
						
							| 
									
										
										
										
											2020-01-13 18:12:19 +08:00
										 |  |  |   switch (displayMode) { | 
					
						
							| 
									
										
										
										
											2020-04-09 13:42:31 +08:00
										 |  |  |     case TableCellDisplayMode.ColorText: | 
					
						
							| 
									
										
										
										
											2020-01-13 18:12:19 +08:00
										 |  |  |     case TableCellDisplayMode.ColorBackground: | 
					
						
							| 
									
										
										
										
											2020-09-25 02:09:01 +08:00
										 |  |  |       return DefaultCell; | 
					
						
							|  |  |  |     case TableCellDisplayMode.Image: | 
					
						
							|  |  |  |       return ImageCell; | 
					
						
							| 
									
										
										
										
											2020-01-13 18:12:19 +08:00
										 |  |  |     case TableCellDisplayMode.LcdGauge: | 
					
						
							| 
									
										
										
										
											2020-07-26 22:52:42 +08:00
										 |  |  |     case TableCellDisplayMode.BasicGauge: | 
					
						
							| 
									
										
										
										
											2020-01-13 18:12:19 +08:00
										 |  |  |     case TableCellDisplayMode.GradientGauge: | 
					
						
							|  |  |  |       return BarGaugeCell; | 
					
						
							| 
									
										
										
										
											2020-04-21 02:10:03 +08:00
										 |  |  |     case TableCellDisplayMode.JSONView: | 
					
						
							|  |  |  |       return JSONViewCell; | 
					
						
							| 
									
										
										
										
											2020-01-13 18:12:19 +08:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2020-04-21 02:10:03 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   // Default or Auto
 | 
					
						
							|  |  |  |   if (field.type === FieldType.other) { | 
					
						
							|  |  |  |     return JSONViewCell; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   return DefaultCell; | 
					
						
							| 
									
										
										
										
											2019-12-23 13:22:54 +08:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2020-04-09 13:42:31 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-02 14:26:58 +08:00
										 |  |  | export function filterByValue(field?: Field) { | 
					
						
							| 
									
										
										
										
											2021-01-20 14:59:48 +08:00
										 |  |  |   return function (rows: Row[], id: string, filterValues?: SelectableValue[]) { | 
					
						
							| 
									
										
										
										
											2020-11-02 14:26:58 +08:00
										 |  |  |     if (rows.length === 0) { | 
					
						
							|  |  |  |       return rows; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-09-01 23:06:35 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-02 14:26:58 +08:00
										 |  |  |     if (!filterValues) { | 
					
						
							|  |  |  |       return rows; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-09-01 23:06:35 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-02 14:26:58 +08:00
										 |  |  |     if (!field) { | 
					
						
							|  |  |  |       return rows; | 
					
						
							| 
									
										
										
										
											2020-09-01 23:06:35 +08:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-20 14:59:48 +08:00
										 |  |  |     return rows.filter((row) => { | 
					
						
							| 
									
										
										
										
											2020-11-02 14:26:58 +08:00
										 |  |  |       if (!row.values.hasOwnProperty(id)) { | 
					
						
							|  |  |  |         return false; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       const value = rowToFieldValue(row, field); | 
					
						
							| 
									
										
										
										
											2021-01-20 14:59:48 +08:00
										 |  |  |       return filterValues.find((filter) => filter.value === value) !== undefined; | 
					
						
							| 
									
										
										
										
											2020-11-02 14:26:58 +08:00
										 |  |  |     }); | 
					
						
							|  |  |  |   }; | 
					
						
							| 
									
										
										
										
											2020-09-01 23:06:35 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | export function calculateUniqueFieldValues(rows: any[], field?: Field) { | 
					
						
							|  |  |  |   if (!field || rows.length === 0) { | 
					
						
							|  |  |  |     return {}; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const set: Record<string, any> = {}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   for (let index = 0; index < rows.length; index++) { | 
					
						
							| 
									
										
										
										
											2020-11-02 14:26:58 +08:00
										 |  |  |     const value = rowToFieldValue(rows[index], field); | 
					
						
							|  |  |  |     set[value || '(Blanks)'] = value; | 
					
						
							| 
									
										
										
										
											2020-09-01 23:06:35 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return set; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-02 14:26:58 +08:00
										 |  |  | export function rowToFieldValue(row: any, field?: Field): string { | 
					
						
							|  |  |  |   if (!field || !row) { | 
					
						
							|  |  |  |     return ''; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const fieldValue = field.values.get(row.index); | 
					
						
							|  |  |  |   const displayValue = field.display ? field.display(fieldValue) : fieldValue; | 
					
						
							|  |  |  |   const value = field.display ? formattedValueToString(displayValue) : displayValue; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return value; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-01 23:06:35 +08:00
										 |  |  | export function valuesToOptions(unique: Record<string, any>): SelectableValue[] { | 
					
						
							|  |  |  |   return Object.keys(unique) | 
					
						
							|  |  |  |     .reduce((all, key) => all.concat({ value: unique[key], label: key }), [] as SelectableValue[]) | 
					
						
							|  |  |  |     .sort(sortOptions); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | export function sortOptions(a: SelectableValue, b: SelectableValue): number { | 
					
						
							|  |  |  |   if (a.label === undefined && b.label === undefined) { | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (a.label === undefined && b.label !== undefined) { | 
					
						
							|  |  |  |     return -1; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (a.label !== undefined && b.label === undefined) { | 
					
						
							|  |  |  |     return 1; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (a.label! < b.label!) { | 
					
						
							|  |  |  |     return -1; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (a.label! > b.label!) { | 
					
						
							|  |  |  |     return 1; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | export function getFilteredOptions(options: SelectableValue[], filterValues?: SelectableValue[]): SelectableValue[] { | 
					
						
							|  |  |  |   if (!filterValues) { | 
					
						
							|  |  |  |     return []; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-20 14:59:48 +08:00
										 |  |  |   return options.filter((option) => filterValues.some((filtered) => filtered.value === option.value)); | 
					
						
							| 
									
										
										
										
											2020-09-01 23:06:35 +08:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2021-04-07 21:28:51 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | export function sortCaseInsensitive(a: Row<any>, b: Row<any>, id: string) { | 
					
						
							|  |  |  |   return String(a.values[id]).localeCompare(String(b.values[id]), undefined, { sensitivity: 'base' }); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2021-05-31 12:12:56 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | // sortNumber needs to have great performance as it is called a lot
 | 
					
						
							|  |  |  | export function sortNumber(rowA: Row<any>, rowB: Row<any>, id: string) { | 
					
						
							|  |  |  |   const a = toNumber(rowA.values[id]); | 
					
						
							|  |  |  |   const b = toNumber(rowB.values[id]); | 
					
						
							|  |  |  |   return a === b ? 0 : a > b ? 1 : -1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function toNumber(value: any): number { | 
					
						
							|  |  |  |   if (typeof value === 'number') { | 
					
						
							|  |  |  |     return value; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (value === null || value === undefined || value === '' || isNaN(value)) { | 
					
						
							|  |  |  |     return Number.NEGATIVE_INFINITY; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return Number(value); | 
					
						
							|  |  |  | } |