Browse Source

Explore: Fixes so Show context shows results again (#18675)

* Fix: Fixes so Show context shows results again
Fixes: #18656

* Refactor: Removes unused import that made it thrugh the pre-commit somehow
Hugo Häggmark 6 years ago
parent
commit
774b7267df

+ 27 - 1
packages/grafana-data/src/utils/dataFrameHelper.test.ts

@@ -1,4 +1,4 @@
-import { FieldType, DataFrameDTO, FieldDTO } from '../types/index';
+import { DataFrameDTO, FieldDTO, FieldType } from '../types';
 import { DataFrameHelper } from './dataFrameHelper';
 
 describe('dataFrameHelper', () => {
@@ -87,3 +87,29 @@ describe('FieldCache', () => {
     expect(fieldCache.getFieldByName('null')).toBeUndefined();
   });
 });
+
+describe('reverse', () => {
+  describe('when called with a DataFrame', () => {
+    it('then it should reverse the order of values in all fields', () => {
+      const frame: DataFrameDTO = {
+        fields: [
+          { name: 'time', type: FieldType.time, values: [100, 200, 300] },
+          { name: 'name', type: FieldType.string, values: ['a', 'b', 'c'] },
+          { name: 'value', type: FieldType.number, values: [1, 2, 3] },
+        ],
+      };
+
+      const helper = new DataFrameHelper(frame);
+
+      expect(helper.getFieldByName('time')!.values.toArray()).toEqual([100, 200, 300]);
+      expect(helper.getFieldByName('name')!.values.toArray()).toEqual(['a', 'b', 'c']);
+      expect(helper.getFieldByName('value')!.values.toArray()).toEqual([1, 2, 3]);
+
+      helper.reverse();
+
+      expect(helper.getFieldByName('time')!.values.toArray()).toEqual([300, 200, 100]);
+      expect(helper.getFieldByName('name')!.values.toArray()).toEqual(['c', 'b', 'a']);
+      expect(helper.getFieldByName('value')!.values.toArray()).toEqual([3, 2, 1]);
+    });
+  });
+});

+ 1 - 4
packages/grafana-data/src/utils/dataFrameHelper.ts

@@ -44,10 +44,7 @@ export class DataFrameHelper implements DataFrame {
    */
   reverse() {
     for (const f of this.fields) {
-      if (isArray(f.values)) {
-        const arr = f.values as any[];
-        arr.reverse();
-      }
+      f.values.toArray().reverse();
     }
   }
 

+ 74 - 0
public/app/features/explore/LogRowContextProvider.test.ts

@@ -0,0 +1,74 @@
+import { DataFrameHelper, FieldType, LogRowModel } from '@grafana/data';
+import { getRowContexts } from './LogRowContextProvider';
+
+describe('getRowContexts', () => {
+  describe('when called with a DataFrame and results are returned', () => {
+    it('then the result should be in correct format', async () => {
+      const firstResult = new DataFrameHelper({
+        refId: 'B',
+        labels: {},
+        fields: [
+          { name: 'ts', type: FieldType.time, values: [3, 2, 1] },
+          { name: 'line', type: FieldType.string, values: ['3', '2', '1'] },
+        ],
+      });
+      const secondResult = new DataFrameHelper({
+        refId: 'B',
+        labels: {},
+        fields: [
+          { name: 'ts', type: FieldType.time, values: [6, 5, 4] },
+          { name: 'line', type: FieldType.string, values: ['6', '5', '4'] },
+        ],
+      });
+      const row: LogRowModel = {
+        entry: '4',
+        labels: null,
+        hasAnsi: false,
+        raw: '4',
+        logLevel: null,
+        timeEpochMs: 4,
+        timeFromNow: '',
+        timeLocal: '',
+        timeUtc: '',
+        timestamp: '4',
+      };
+
+      const getRowContext = jest
+        .fn()
+        .mockResolvedValueOnce({ data: [firstResult] })
+        .mockResolvedValueOnce({ data: [secondResult] });
+
+      const result = await getRowContexts(getRowContext, row, 10);
+
+      expect(result).toEqual({ data: [[['3', '2', '1']], [['6', '5', '4']]], errors: [null, null] });
+    });
+  });
+
+  describe('when called with a DataFrame and errors occur', () => {
+    it('then the result should be in correct format', async () => {
+      const firstError = new Error('Error 1');
+      const secondError = new Error('Error 2');
+      const row: LogRowModel = {
+        entry: '4',
+        labels: null,
+        hasAnsi: false,
+        raw: '4',
+        logLevel: null,
+        timeEpochMs: 4,
+        timeFromNow: '',
+        timeLocal: '',
+        timeUtc: '',
+        timestamp: '4',
+      };
+
+      const getRowContext = jest
+        .fn()
+        .mockRejectedValueOnce(firstError)
+        .mockRejectedValueOnce(secondError);
+
+      const result = await getRowContexts(getRowContext, row, 10);
+
+      expect(result).toEqual({ data: [[], []], errors: ['Error 1', 'Error 2'] });
+    });
+  });
+});

+ 29 - 9
public/app/features/explore/LogRowContextProvider.tsx

@@ -1,5 +1,5 @@
 import { DataQueryResponse, DataQueryError } from '@grafana/ui';
-import { LogRowModel } from '@grafana/data';
+import { LogRowModel, toDataFrame, Field } from '@grafana/data';
 import { useState, useEffect } from 'react';
 import flatten from 'lodash/flatten';
 import useAsync from 'react-use/lib/useAsync';
@@ -47,19 +47,39 @@ export const getRowContexts = async (
   const results: Array<DataQueryResponse | DataQueryError> = await Promise.all(promises.map(p => p.catch(e => e)));
 
   return {
-    data: results.map((result, index) => {
+    data: results.map(result => {
       const dataResult: DataQueryResponse = result as DataQueryResponse;
       if (!dataResult.data) {
         return [];
       }
 
-      // We need to filter out the row we're basing our search from because of how start/end params work in Loki API
-      // see https://github.com/grafana/loki/issues/597#issuecomment-506408980
-      // the alternative to create our own add 1 nanosecond method to the a timestamp string would be quite complex
-      return dataResult.data.map(series => {
-        const filteredRows = series.rows.filter((r: any) => r[0] !== row.timestamp);
-        return filteredRows.map((row: any) => row[1]);
-      });
+      const data: any[] = [];
+      for (let index = 0; index < dataResult.data.length; index++) {
+        const dataFrame = toDataFrame(dataResult.data[index]);
+        const timestampField: Field<string> = dataFrame.fields.filter(field => field.name === 'ts')[0];
+
+        for (let fieldIndex = 0; fieldIndex < timestampField.values.length; fieldIndex++) {
+          const timestamp = timestampField.values.get(fieldIndex);
+
+          // We need to filter out the row we're basing our search from because of how start/end params work in Loki API
+          // see https://github.com/grafana/loki/issues/597#issuecomment-506408980
+          // the alternative to create our own add 1 nanosecond method to the a timestamp string would be quite complex
+          if (timestamp === row.timestamp) {
+            continue;
+          }
+
+          const lineField: Field<string> = dataFrame.fields.filter(field => field.name === 'line')[0];
+          const line = lineField.values.get(fieldIndex); // assuming that both fields have same length
+
+          if (data.length === 0) {
+            data[0] = [line];
+          } else {
+            data[0].push(line);
+          }
+        }
+      }
+
+      return data;
     }),
     errors: results.map(result => {
       const errorResult: DataQueryError = result as DataQueryError;