1import { useMemo } from 'react'; 2import { DataFrame, Field, getFieldDisplayName, SelectableValue } from '@grafana/data'; 3import { getFieldTypeIcon } from '../../types'; 4 5/** 6 * @internal 7 */ 8export interface FrameFieldsDisplayNames { 9 // The display names 10 display: Set<string>; 11 12 // raw field names (that are explicitly not visible) 13 raw: Set<string>; 14 15 // Field mappings (duplicates are not supported) 16 fields: Map<string, Field>; 17} 18 19/** 20 * @internal 21 */ 22export function frameHasName(name: string | undefined, names: FrameFieldsDisplayNames) { 23 if (!name) { 24 return false; 25 } 26 return names.display.has(name) || names.raw.has(name); 27} 28 29/** 30 * Retuns the distinct names in a set of frames 31 */ 32function getFrameFieldsDisplayNames(data: DataFrame[], filter?: (field: Field) => boolean): FrameFieldsDisplayNames { 33 const names: FrameFieldsDisplayNames = { 34 display: new Set<string>(), 35 raw: new Set<string>(), 36 fields: new Map<string, Field>(), 37 }; 38 39 for (const frame of data) { 40 for (const field of frame.fields) { 41 if (filter && !filter(field)) { 42 continue; 43 } 44 const disp = getFieldDisplayName(field, frame, data); 45 names.display.add(disp); 46 names.fields.set(disp, field); 47 if (field.name && disp !== field.name) { 48 names.raw.add(field.name); 49 names.fields.set(field.name, field); 50 } 51 } 52 } 53 return names; 54} 55 56/** 57 * @internal 58 */ 59export function useFieldDisplayNames(data: DataFrame[], filter?: (field: Field) => boolean): FrameFieldsDisplayNames { 60 return useMemo(() => { 61 return getFrameFieldsDisplayNames(data, filter); 62 }, [data, filter]); 63} 64 65/** 66 * @internal 67 */ 68export function useSelectOptions( 69 displayNames: FrameFieldsDisplayNames, 70 currentName?: string, 71 firstItem?: SelectableValue<string>, 72 fieldType?: string 73): Array<SelectableValue<string>> { 74 return useMemo(() => { 75 let found = false; 76 const options: Array<SelectableValue<string>> = []; 77 if (firstItem) { 78 options.push(firstItem); 79 } 80 for (const name of displayNames.display) { 81 if (!found && name === currentName) { 82 found = true; 83 } 84 const field = displayNames.fields.get(name); 85 if (!fieldType || fieldType === field?.type) { 86 options.push({ 87 value: name, 88 label: name, 89 icon: field ? getFieldTypeIcon(field) : undefined, 90 }); 91 } 92 } 93 for (const name of displayNames.raw) { 94 if (!displayNames.display.has(name)) { 95 if (!found && name === currentName) { 96 found = true; 97 } 98 options.push({ 99 value: name, 100 label: `${name} (base field name)`, 101 }); 102 } 103 } 104 105 if (currentName && !found) { 106 options.push({ 107 value: currentName, 108 label: `${currentName} (not found)`, 109 }); 110 } 111 return options; 112 }, [displayNames, currentName, firstItem, fieldType]); 113} 114