mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
TableCell: show JSON rather than [object Object] (#23683)
This commit is contained in:
@@ -0,0 +1,43 @@
|
|||||||
|
import React, { FC } from 'react';
|
||||||
|
import { css, cx } from 'emotion';
|
||||||
|
import { TableCellProps } from './types';
|
||||||
|
import { Tooltip } from '../Tooltip/Tooltip';
|
||||||
|
import { JSONFormatter } from '../JSONFormatter/JSONFormatter';
|
||||||
|
|
||||||
|
export const JSONViewCell: FC<TableCellProps> = props => {
|
||||||
|
const { field, cell, tableStyles } = props;
|
||||||
|
|
||||||
|
if (!field.display) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const txt = css`
|
||||||
|
cursor: pointer;
|
||||||
|
font-family: monospace;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const displayValue = JSON.stringify(cell.value);
|
||||||
|
const content = <JSONTooltip value={cell.value} />;
|
||||||
|
return (
|
||||||
|
<div className={cx(txt, tableStyles.tableCell)}>
|
||||||
|
<Tooltip placement="auto" content={content} theme={'info'}>
|
||||||
|
<span>{displayValue}</span>
|
||||||
|
</Tooltip>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
interface PopupProps {
|
||||||
|
value: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
const JSONTooltip: FC<PopupProps> = props => {
|
||||||
|
const clazz = css`
|
||||||
|
padding: 10px;
|
||||||
|
`;
|
||||||
|
return (
|
||||||
|
<div className={clazz}>
|
||||||
|
<JSONFormatter json={props.value} open={4} />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -15,6 +15,7 @@ export enum TableCellDisplayMode {
|
|||||||
ColorBackground = 'color-background',
|
ColorBackground = 'color-background',
|
||||||
GradientGauge = 'gradient-gauge',
|
GradientGauge = 'gradient-gauge',
|
||||||
LcdGauge = 'lcd-gauge',
|
LcdGauge = 'lcd-gauge',
|
||||||
|
JSONView = 'json-view',
|
||||||
}
|
}
|
||||||
|
|
||||||
export type FieldTextAlignment = 'auto' | 'left' | 'right' | 'center';
|
export type FieldTextAlignment = 'auto' | 'left' | 'right' | 'center';
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import { TableCellDisplayMode, TableCellProps, TableFieldOptions } from './types
|
|||||||
import { css, cx } from 'emotion';
|
import { css, cx } from 'emotion';
|
||||||
import { withTableStyles } from './withTableStyles';
|
import { withTableStyles } from './withTableStyles';
|
||||||
import tinycolor from 'tinycolor2';
|
import tinycolor from 'tinycolor2';
|
||||||
|
import { JSONViewCell } from './JSONViewCell';
|
||||||
|
|
||||||
export function getTextAlign(field?: Field): TextAlignProperty {
|
export function getTextAlign(field?: Field): TextAlignProperty {
|
||||||
if (!field) {
|
if (!field) {
|
||||||
@@ -46,7 +47,7 @@ export function getColumns(data: DataFrame, availableWidth: number, columnMinWid
|
|||||||
fieldCountWithoutWidth -= 1;
|
fieldCountWithoutWidth -= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Cell = getCellComponent(fieldTableOptions.displayMode);
|
const Cell = getCellComponent(fieldTableOptions.displayMode, field);
|
||||||
|
|
||||||
columns.push({
|
columns.push({
|
||||||
Cell,
|
Cell,
|
||||||
@@ -71,7 +72,7 @@ export function getColumns(data: DataFrame, availableWidth: number, columnMinWid
|
|||||||
return columns;
|
return columns;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getCellComponent(displayMode: TableCellDisplayMode) {
|
function getCellComponent(displayMode: TableCellDisplayMode, field: Field) {
|
||||||
switch (displayMode) {
|
switch (displayMode) {
|
||||||
case TableCellDisplayMode.ColorText:
|
case TableCellDisplayMode.ColorText:
|
||||||
return withTableStyles(DefaultCell, getTextColorStyle);
|
return withTableStyles(DefaultCell, getTextColorStyle);
|
||||||
@@ -80,9 +81,15 @@ function getCellComponent(displayMode: TableCellDisplayMode) {
|
|||||||
case TableCellDisplayMode.LcdGauge:
|
case TableCellDisplayMode.LcdGauge:
|
||||||
case TableCellDisplayMode.GradientGauge:
|
case TableCellDisplayMode.GradientGauge:
|
||||||
return BarGaugeCell;
|
return BarGaugeCell;
|
||||||
default:
|
case TableCellDisplayMode.JSONView:
|
||||||
return DefaultCell;
|
return JSONViewCell;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Default or Auto
|
||||||
|
if (field.type === FieldType.other) {
|
||||||
|
return JSONViewCell;
|
||||||
|
}
|
||||||
|
return DefaultCell;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getTextColorStyle(props: TableCellProps) {
|
function getTextColorStyle(props: TableCellProps) {
|
||||||
|
|||||||
@@ -266,6 +266,15 @@ func init() {
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
registerScenario(&Scenario{
|
||||||
|
Id: "grafana_api",
|
||||||
|
Name: "Grafana API",
|
||||||
|
Handler: func(query *tsdb.Query, context *tsdb.TsdbQuery) *tsdb.QueryResult {
|
||||||
|
// Real work is in javascript client
|
||||||
|
return tsdb.NewQueryResult()
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
registerScenario(&Scenario{
|
registerScenario(&Scenario{
|
||||||
Id: "table_static",
|
Id: "table_static",
|
||||||
Name: "Table Static",
|
Name: "Table Static",
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ import {
|
|||||||
MetricFindValue,
|
MetricFindValue,
|
||||||
TableData,
|
TableData,
|
||||||
TimeSeries,
|
TimeSeries,
|
||||||
|
LoadingState,
|
||||||
|
ArrayDataFrame,
|
||||||
} from '@grafana/data';
|
} from '@grafana/data';
|
||||||
import { Scenario, TestDataQuery } from './types';
|
import { Scenario, TestDataQuery } from './types';
|
||||||
import { getBackendSrv } from '@grafana/runtime';
|
import { getBackendSrv } from '@grafana/runtime';
|
||||||
@@ -34,6 +36,8 @@ export class TestDataDataSource extends DataSourceApi<TestDataQuery> {
|
|||||||
}
|
}
|
||||||
if (target.scenarioId === 'streaming_client') {
|
if (target.scenarioId === 'streaming_client') {
|
||||||
streams.push(runStream(target, options));
|
streams.push(runStream(target, options));
|
||||||
|
} else if (target.scenarioId === 'grafana_api') {
|
||||||
|
streams.push(runGrafanaAPI(target, options));
|
||||||
} else {
|
} else {
|
||||||
queries.push({
|
queries.push({
|
||||||
...target,
|
...target,
|
||||||
@@ -145,3 +149,18 @@ export class TestDataDataSource extends DataSourceApi<TestDataQuery> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function runGrafanaAPI(target: TestDataQuery, req: DataQueryRequest<TestDataQuery>): Observable<DataQueryResponse> {
|
||||||
|
const url = `/api/${target.stringInput}`;
|
||||||
|
return from(
|
||||||
|
getBackendSrv()
|
||||||
|
.get(url)
|
||||||
|
.then(res => {
|
||||||
|
const frame = new ArrayDataFrame(res);
|
||||||
|
return {
|
||||||
|
state: LoadingState.Done,
|
||||||
|
data: [frame],
|
||||||
|
};
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|||||||
@@ -188,6 +188,21 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="gf-form-inline" ng-if="ctrl.scenario.id === 'grafana_api'">
|
||||||
|
<div class="gf-form gf-form">
|
||||||
|
<label class="gf-form-label query-keyword width-7">Endpoint</label>
|
||||||
|
<div class="gf-form-select-wrapper">
|
||||||
|
<select
|
||||||
|
ng-model="ctrl.target.stringInput"
|
||||||
|
class="gf-form-input"
|
||||||
|
ng-options="type for type in ['datasources', 'search', 'annotations']"
|
||||||
|
ng-change="ctrl.refresh()" />
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Predictable Pulse Scenario Options Form -->
|
<!-- Predictable Pulse Scenario Options Form -->
|
||||||
<div class="gf-form-inline" ng-if="ctrl.scenario.id === 'predictable_pulse'">
|
<div class="gf-form-inline" ng-if="ctrl.scenario.id === 'predictable_pulse'">
|
||||||
<div class="gf-form">
|
<div class="gf-form">
|
||||||
|
|||||||
@@ -115,6 +115,12 @@ export class TestDataQueryCtrl extends QueryCtrl {
|
|||||||
delete this.target.csvWave;
|
delete this.target.csvWave;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.target.scenarioId === 'grafana_api') {
|
||||||
|
this.target.stringInput = 'datasources';
|
||||||
|
} else {
|
||||||
|
delete this.target.stringInput;
|
||||||
|
}
|
||||||
|
|
||||||
this.refresh();
|
this.refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { PanelPlugin } from '@grafana/data';
|
|||||||
import { TablePanel } from './TablePanel';
|
import { TablePanel } from './TablePanel';
|
||||||
import { CustomFieldConfig, Options } from './types';
|
import { CustomFieldConfig, Options } from './types';
|
||||||
import { tablePanelChangedHandler, tableMigrationHandler } from './migrations';
|
import { tablePanelChangedHandler, tableMigrationHandler } from './migrations';
|
||||||
|
import { TableCellDisplayMode } from '@grafana/ui/src/components/Table/types';
|
||||||
|
|
||||||
export const plugin = new PanelPlugin<Options, CustomFieldConfig>(TablePanel)
|
export const plugin = new PanelPlugin<Options, CustomFieldConfig>(TablePanel)
|
||||||
.setPanelChangeHandler(tablePanelChangedHandler)
|
.setPanelChangeHandler(tablePanelChangedHandler)
|
||||||
@@ -39,11 +40,12 @@ export const plugin = new PanelPlugin<Options, CustomFieldConfig>(TablePanel)
|
|||||||
description: 'Color text, background, show as gauge, etc',
|
description: 'Color text, background, show as gauge, etc',
|
||||||
settings: {
|
settings: {
|
||||||
options: [
|
options: [
|
||||||
{ value: 'auto', label: 'Auto' },
|
{ value: TableCellDisplayMode.Auto, label: 'Auto' },
|
||||||
{ value: 'color-text', label: 'Color text' },
|
{ value: TableCellDisplayMode.ColorText, label: 'Color text' },
|
||||||
{ value: 'color-background', label: 'Color background' },
|
{ value: TableCellDisplayMode.ColorBackground, label: 'Color background' },
|
||||||
{ value: 'gradient-gauge', label: 'Gradient gauge' },
|
{ value: TableCellDisplayMode.GradientGauge, label: 'Gradient gauge' },
|
||||||
{ value: 'lcd-gauge', label: 'LCD gauge' },
|
{ value: TableCellDisplayMode.LcdGauge, label: 'LCD gauge' },
|
||||||
|
{ value: TableCellDisplayMode.JSONView, label: 'JSON View' },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user