1// Libraries 2import React, { PureComponent } from 'react'; 3 4// Types 5import { 6 CoreApp, 7 DataQuery, 8 DataSourceInstanceSettings, 9 EventBusExtended, 10 HistoryItem, 11 PanelData, 12} from '@grafana/data'; 13import { QueryEditorRow } from './QueryEditorRow'; 14import { DragDropContext, Droppable, DropResult } from 'react-beautiful-dnd'; 15import { getDataSourceSrv } from '@grafana/runtime'; 16 17interface Props { 18 // The query configuration 19 queries: DataQuery[]; 20 dsSettings: DataSourceInstanceSettings; 21 22 // Query editing 23 onQueriesChange: (queries: DataQuery[]) => void; 24 onAddQuery: (query: DataQuery) => void; 25 onRunQueries: () => void; 26 27 // Query Response Data 28 data: PanelData; 29 30 // Misc 31 app?: CoreApp; 32 history?: Array<HistoryItem<DataQuery>>; 33 eventBus?: EventBusExtended; 34} 35 36export class QueryEditorRows extends PureComponent<Props> { 37 onRemoveQuery = (query: DataQuery) => { 38 this.props.onQueriesChange(this.props.queries.filter((item) => item !== query)); 39 }; 40 41 onChangeQuery(query: DataQuery, index: number) { 42 const { queries, onQueriesChange } = this.props; 43 44 // update query in array 45 onQueriesChange( 46 queries.map((item, itemIndex) => { 47 if (itemIndex === index) { 48 return query; 49 } 50 return item; 51 }) 52 ); 53 } 54 55 onDataSourceChange(dataSource: DataSourceInstanceSettings, index: number) { 56 const { queries, onQueriesChange } = this.props; 57 58 onQueriesChange( 59 queries.map((item, itemIndex) => { 60 if (itemIndex !== index) { 61 return item; 62 } 63 64 if (item.datasource) { 65 const previous = getDataSourceSrv().getInstanceSettings(item.datasource); 66 67 if (previous?.type === dataSource.type) { 68 return { 69 ...item, 70 datasource: { uid: dataSource.uid }, 71 }; 72 } 73 } 74 75 return { 76 refId: item.refId, 77 hide: item.hide, 78 datasource: { uid: dataSource.uid }, 79 }; 80 }) 81 ); 82 } 83 84 onDragEnd = (result: DropResult) => { 85 const { queries, onQueriesChange } = this.props; 86 87 if (!result || !result.destination) { 88 return; 89 } 90 91 const startIndex = result.source.index; 92 const endIndex = result.destination.index; 93 if (startIndex === endIndex) { 94 return; 95 } 96 97 const update = Array.from(queries); 98 const [removed] = update.splice(startIndex, 1); 99 update.splice(endIndex, 0, removed); 100 onQueriesChange(update); 101 }; 102 103 render() { 104 const { dsSettings, data, queries, app, history, eventBus } = this.props; 105 106 return ( 107 <DragDropContext onDragEnd={this.onDragEnd}> 108 <Droppable droppableId="transformations-list" direction="vertical"> 109 {(provided) => { 110 return ( 111 <div ref={provided.innerRef} {...provided.droppableProps}> 112 {queries.map((query, index) => { 113 const dataSourceSettings = getDataSourceSettings(query, dsSettings); 114 const onChangeDataSourceSettings = dsSettings.meta.mixed 115 ? (settings: DataSourceInstanceSettings) => this.onDataSourceChange(settings, index) 116 : undefined; 117 118 return ( 119 <QueryEditorRow 120 id={query.refId} 121 index={index} 122 key={query.refId} 123 data={data} 124 query={query} 125 dataSource={dataSourceSettings} 126 onChangeDataSource={onChangeDataSourceSettings} 127 onChange={(query) => this.onChangeQuery(query, index)} 128 onRemoveQuery={this.onRemoveQuery} 129 onAddQuery={this.props.onAddQuery} 130 onRunQuery={this.props.onRunQueries} 131 queries={queries} 132 app={app} 133 history={history} 134 eventBus={eventBus} 135 /> 136 ); 137 })} 138 {provided.placeholder} 139 </div> 140 ); 141 }} 142 </Droppable> 143 </DragDropContext> 144 ); 145 } 146} 147 148const getDataSourceSettings = ( 149 query: DataQuery, 150 groupSettings: DataSourceInstanceSettings 151): DataSourceInstanceSettings => { 152 if (!query.datasource) { 153 return groupSettings; 154 } 155 const querySettings = getDataSourceSrv().getInstanceSettings(query.datasource); 156 return querySettings || groupSettings; 157}; 158