mirror of https://github.com/grafana/grafana.git
New Logs Panel: remove sibling visualization (#110444)
* New Logs Panel: remove sibling visualization * More removals * Update provisioned dashboard * Update translations
This commit is contained in:
parent
600137919e
commit
df685757ff
|
@ -949,7 +949,6 @@ playwright.storybook.config.ts @grafana/grafana-frontend-platform
|
|||
/public/app/plugins/panel/heatmap/ @grafana/dataviz-squad
|
||||
/public/app/plugins/panel/histogram/ @grafana/dataviz-squad
|
||||
/public/app/plugins/panel/logs/ @grafana/observability-logs
|
||||
/public/app/plugins/panel/logs-new/ @grafana/observability-logs
|
||||
/public/app/plugins/panel/nodeGraph/ @grafana/observability-traces-and-profiling @grafana/app-o11y-visualizations
|
||||
/public/app/plugins/panel/traces/ @grafana/observability-traces-and-profiling
|
||||
/public/app/plugins/panel/flamegraph/ @grafana/observability-traces-and-profiling
|
||||
|
|
|
@ -919,7 +919,7 @@
|
|||
}
|
||||
],
|
||||
"title": "Requests",
|
||||
"type": "logs-new"
|
||||
"type": "logs"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
|
@ -962,7 +962,7 @@
|
|||
}
|
||||
],
|
||||
"title": "grafana-api requests",
|
||||
"type": "logs-new"
|
||||
"type": "logs"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
|
@ -1317,7 +1317,7 @@
|
|||
}
|
||||
],
|
||||
"title": "frontend-service errors",
|
||||
"type": "logs-new"
|
||||
"type": "logs"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
|
@ -1360,7 +1360,7 @@
|
|||
}
|
||||
],
|
||||
"title": "grafana-api errors",
|
||||
"type": "logs-new"
|
||||
"type": "logs"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
|
@ -1403,7 +1403,7 @@
|
|||
}
|
||||
],
|
||||
"title": "All frontend-service logs",
|
||||
"type": "logs-new"
|
||||
"type": "logs"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
|
@ -1446,7 +1446,7 @@
|
|||
}
|
||||
],
|
||||
"title": "All grafana-api logs",
|
||||
"type": "logs-new"
|
||||
"type": "logs"
|
||||
}
|
||||
],
|
||||
"preload": false,
|
||||
|
|
|
@ -248,16 +248,6 @@ func GetComposableKinds() ([]ComposableKind, error) {
|
|||
CueFile: logsCue,
|
||||
})
|
||||
|
||||
logsnewCue, err := loadCueFileWithCommon(root, filepath.Join(root, "./public/app/plugins/panel/logs-new/panelcfg.cue"))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
kinds = append(kinds, ComposableKind{
|
||||
Name: "logsnew",
|
||||
Filename: "panelcfg.cue",
|
||||
CueFile: logsnewCue,
|
||||
})
|
||||
|
||||
newsCue, err := loadCueFileWithCommon(root, filepath.Join(root, "./public/app/plugins/panel/news/panelcfg.cue"))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
|
@ -227,7 +227,6 @@ func verifyCorePluginCatalogue(t *testing.T, ctx context.Context, ps *pluginstor
|
|||
"histogram": {},
|
||||
"live": {},
|
||||
"logs": {},
|
||||
"logs-new": {},
|
||||
"candlestick": {},
|
||||
"news": {},
|
||||
"nodeGraph": {},
|
||||
|
|
|
@ -44,8 +44,6 @@ const histogramPanel = async () =>
|
|||
await import(/* webpackChunkName: "histogramPanel" */ 'app/plugins/panel/histogram/module');
|
||||
const livePanel = async () => await import(/* webpackChunkName: "livePanel" */ 'app/plugins/panel/live/module');
|
||||
const logsPanel = async () => await import(/* webpackChunkName: "logsPanel" */ 'app/plugins/panel/logs/module');
|
||||
const newLogsPanel = async () =>
|
||||
await import(/* webpackChunkName: "newLogsPanel" */ 'app/plugins/panel/logs-new/module');
|
||||
const newsPanel = async () => await import(/* webpackChunkName: "newsPanel" */ 'app/plugins/panel/news/module');
|
||||
const pieChartPanel = async () =>
|
||||
await import(/* webpackChunkName: "pieChartPanel" */ 'app/plugins/panel/piechart/module');
|
||||
|
@ -111,7 +109,6 @@ const builtInPlugins: Record<string, System.Module | (() => Promise<System.Modul
|
|||
'core:plugin/bargauge': barGaugePanel,
|
||||
'core:plugin/barchart': barChartPanel,
|
||||
'core:plugin/logs': logsPanel,
|
||||
'core:plugin/logs-new': newLogsPanel,
|
||||
'core:plugin/traces': tracesPanel,
|
||||
'core:plugin/welcome': welcomeBanner,
|
||||
'core:plugin/nodeGraph': nodeGraph,
|
||||
|
|
|
@ -1,164 +0,0 @@
|
|||
import { render, screen } from '@testing-library/react';
|
||||
import { ComponentProps } from 'react';
|
||||
|
||||
import {
|
||||
LoadingState,
|
||||
createDataFrame,
|
||||
FieldType,
|
||||
LogsSortOrder,
|
||||
getDefaultTimeRange,
|
||||
LogsDedupStrategy,
|
||||
EventBusSrv,
|
||||
DataFrameType,
|
||||
LogSortOrderChangeEvent,
|
||||
} from '@grafana/data';
|
||||
import { getAppEvents } from '@grafana/runtime';
|
||||
|
||||
import { LogsPanel } from './LogsPanel';
|
||||
|
||||
type LogsPanelProps = ComponentProps<typeof LogsPanel>;
|
||||
|
||||
jest.mock('@grafana/assistant', () => ({
|
||||
...jest.requireActual('@grafana/assistant'),
|
||||
useAssistant: jest.fn(() => [true, jest.fn()]),
|
||||
}));
|
||||
|
||||
jest.mock('@grafana/runtime', () => ({
|
||||
...jest.requireActual('@grafana/runtime'),
|
||||
getAppEvents: jest.fn(),
|
||||
}));
|
||||
|
||||
const defaultProps = {
|
||||
data: {
|
||||
error: undefined,
|
||||
request: {
|
||||
panelId: 4,
|
||||
app: 'dashboard',
|
||||
requestId: 'A',
|
||||
timezone: 'browser',
|
||||
interval: '30s',
|
||||
intervalMs: 30000,
|
||||
maxDataPoints: 823,
|
||||
targets: [],
|
||||
range: getDefaultTimeRange(),
|
||||
scopedVars: {},
|
||||
startTime: 1,
|
||||
},
|
||||
series: [
|
||||
createDataFrame({
|
||||
refId: 'A',
|
||||
fields: [
|
||||
{
|
||||
name: 'timestamp',
|
||||
type: FieldType.time,
|
||||
values: ['2019-04-26T09:28:11.352440161Z'],
|
||||
},
|
||||
{
|
||||
name: 'body',
|
||||
type: FieldType.string,
|
||||
values: ['logline text'],
|
||||
},
|
||||
{
|
||||
name: 'labels',
|
||||
type: FieldType.other,
|
||||
values: [
|
||||
{
|
||||
app: 'common_app',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
meta: {
|
||||
type: DataFrameType.LogLines,
|
||||
},
|
||||
}),
|
||||
],
|
||||
state: LoadingState.Done,
|
||||
timeRange: getDefaultTimeRange(),
|
||||
},
|
||||
timeZone: 'utc',
|
||||
timeRange: getDefaultTimeRange(),
|
||||
options: {
|
||||
showLabels: false,
|
||||
showTime: false,
|
||||
wrapLogMessage: false,
|
||||
sortOrder: LogsSortOrder.Descending,
|
||||
dedupStrategy: LogsDedupStrategy.none,
|
||||
enableLogDetails: false,
|
||||
enableInfiniteScrolling: false,
|
||||
showControls: false,
|
||||
syntaxHighlighting: false,
|
||||
},
|
||||
title: 'Logs panel',
|
||||
id: 1,
|
||||
transparent: false,
|
||||
width: 400,
|
||||
height: 100,
|
||||
renderCounter: 0,
|
||||
fieldConfig: {
|
||||
defaults: {},
|
||||
overrides: [],
|
||||
},
|
||||
eventBus: new EventBusSrv(),
|
||||
onOptionsChange: jest.fn(),
|
||||
onFieldConfigChange: jest.fn(),
|
||||
replaceVariables: jest.fn(),
|
||||
onChangeTimeRange: jest.fn(),
|
||||
};
|
||||
|
||||
const publishMock = jest.fn();
|
||||
beforeAll(() => {
|
||||
jest.mocked(getAppEvents).mockReturnValue({
|
||||
publish: publishMock,
|
||||
getStream: jest.fn(),
|
||||
subscribe: jest.fn(),
|
||||
removeAllListeners: jest.fn(),
|
||||
newScopedBus: jest.fn(),
|
||||
});
|
||||
});
|
||||
|
||||
describe('LogsPanel', () => {
|
||||
test('Renders a list of logs without controls ', async () => {
|
||||
setup();
|
||||
await screen.findByText('logline text');
|
||||
expect(screen.queryByLabelText('Scroll to bottom')).not.toBeInTheDocument();
|
||||
expect(screen.queryByLabelText('Display levels')).not.toBeInTheDocument();
|
||||
expect(screen.queryByLabelText('Scroll to top')).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
test('Renders a list of logs with controls', async () => {
|
||||
setup({ options: { ...defaultProps.options, showControls: true } });
|
||||
await screen.findByText('logline text');
|
||||
expect(screen.getByLabelText('Scroll to bottom')).toBeInTheDocument();
|
||||
expect(screen.getByLabelText('Display levels')).toBeInTheDocument();
|
||||
expect(screen.getByLabelText('Scroll to top')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
test('Publishes an event with the current sort order', async () => {
|
||||
publishMock.mockClear();
|
||||
setup();
|
||||
|
||||
await screen.findByText('logline text');
|
||||
|
||||
expect(publishMock).toHaveBeenCalledTimes(1);
|
||||
expect(publishMock).toHaveBeenCalledWith(
|
||||
new LogSortOrderChangeEvent({
|
||||
order: LogsSortOrder.Descending,
|
||||
})
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
const setup = (propsOverrides?: Partial<LogsPanelProps>) => {
|
||||
const props: LogsPanelProps = {
|
||||
...defaultProps,
|
||||
data: {
|
||||
...(propsOverrides?.data || defaultProps.data),
|
||||
},
|
||||
options: {
|
||||
...(propsOverrides?.options || defaultProps.options),
|
||||
},
|
||||
};
|
||||
|
||||
return { ...render(<LogsPanel {...props} />), props };
|
||||
};
|
|
@ -1,185 +0,0 @@
|
|||
import { css } from '@emotion/css';
|
||||
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||
|
||||
import {
|
||||
AbsoluteTimeRange,
|
||||
CoreApp,
|
||||
DataFrame,
|
||||
DataHoverEvent,
|
||||
GrafanaTheme2,
|
||||
LoadingState,
|
||||
LogRowModel,
|
||||
LogSortOrderChangeEvent,
|
||||
LogsSortOrder,
|
||||
PanelProps,
|
||||
} from '@grafana/data';
|
||||
import { config, getAppEvents } from '@grafana/runtime';
|
||||
import { usePanelContext, useStyles2 } from '@grafana/ui';
|
||||
import { LogList } from 'app/features/logs/components/panel/LogList';
|
||||
import { PanelDataErrorView } from 'app/features/panel/components/PanelDataErrorView';
|
||||
|
||||
import { dataFrameToLogsModel, dedupLogRows } from '../../../features/logs/logsModel';
|
||||
import { requestMoreLogs } from '../logs/LogsPanel';
|
||||
import { useDatasourcesFromTargets } from '../logs/useDatasourcesFromTargets';
|
||||
|
||||
import { Options } from './panelcfg.gen';
|
||||
import { isCoreApp, isLogsGrammar, isOnLogOptionsChange, isOnNewLogsReceivedType } from './types';
|
||||
|
||||
interface LogsPanelProps extends PanelProps<Options> {}
|
||||
|
||||
export const LogsPanel = ({
|
||||
data,
|
||||
timeZone,
|
||||
fieldConfig,
|
||||
options: {
|
||||
controlsStorageKey,
|
||||
dedupStrategy,
|
||||
enableInfiniteScrolling,
|
||||
grammar,
|
||||
onLogOptionsChange,
|
||||
onNewLogsReceived,
|
||||
showControls,
|
||||
showTime,
|
||||
sortOrder,
|
||||
syntaxHighlighting,
|
||||
wrapLogMessage,
|
||||
},
|
||||
id,
|
||||
}: LogsPanelProps) => {
|
||||
const style = useStyles2(getStyles);
|
||||
const [logsContainer, setLogsContainer] = useState<HTMLDivElement | null>(null);
|
||||
const [panelData, setPanelData] = useState(data);
|
||||
const dataSourcesMap = useDatasourcesFromTargets(data.request?.targets);
|
||||
// Prevents the scroll position to change when new data from infinite scrolling is received
|
||||
const keepScrollPositionRef = useRef(false);
|
||||
// Loading ref to prevent firing multiple requests
|
||||
const loadingRef = useRef(false);
|
||||
const { app, eventBus } = usePanelContext();
|
||||
|
||||
const logs = useMemo(() => {
|
||||
const logsModel = panelData
|
||||
? dataFrameToLogsModel(panelData.series, panelData.request?.intervalMs, undefined, panelData.request?.targets)
|
||||
: null;
|
||||
return logsModel ? dedupLogRows(logsModel.rows, dedupStrategy) : [];
|
||||
}, [dedupStrategy, panelData]);
|
||||
|
||||
useEffect(() => {
|
||||
getAppEvents().publish(
|
||||
new LogSortOrderChangeEvent({
|
||||
order: sortOrder,
|
||||
})
|
||||
);
|
||||
}, [sortOrder]);
|
||||
|
||||
useEffect(() => {
|
||||
if (data.state !== LoadingState.Loading) {
|
||||
setPanelData(data);
|
||||
}
|
||||
}, [data]);
|
||||
|
||||
const loadMoreLogs = useCallback(
|
||||
async (scrollRange: AbsoluteTimeRange) => {
|
||||
if (!data.request || !config.featureToggles.logsInfiniteScrolling || loadingRef.current) {
|
||||
return;
|
||||
}
|
||||
loadingRef.current = true;
|
||||
|
||||
const onNewLogsReceivedCallback = isOnNewLogsReceivedType(onNewLogsReceived) ? onNewLogsReceived : undefined;
|
||||
|
||||
let newSeries: DataFrame[] = [];
|
||||
try {
|
||||
newSeries = await requestMoreLogs(dataSourcesMap, panelData, scrollRange, timeZone, onNewLogsReceivedCallback);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
} finally {
|
||||
loadingRef.current = false;
|
||||
}
|
||||
|
||||
keepScrollPositionRef.current = true;
|
||||
setPanelData({
|
||||
...panelData,
|
||||
series: newSeries,
|
||||
});
|
||||
},
|
||||
[data.request, dataSourcesMap, onNewLogsReceived, panelData, timeZone]
|
||||
);
|
||||
|
||||
const onLogRowHover = useCallback(
|
||||
(row?: LogRowModel) => {
|
||||
if (row) {
|
||||
eventBus.publish(
|
||||
new DataHoverEvent({
|
||||
point: {
|
||||
time: row.timeEpochMs,
|
||||
},
|
||||
})
|
||||
);
|
||||
}
|
||||
},
|
||||
[eventBus]
|
||||
);
|
||||
|
||||
const initialScrollPosition = useMemo(() => {
|
||||
/**
|
||||
* In dashboards, users with newest logs at the bottom have the expectation of keeping the scroll at the bottom
|
||||
* when new data is received. See https://github.com/grafana/grafana/pull/37634
|
||||
*/
|
||||
if (data.request?.app === CoreApp.Dashboard || data.request?.app === CoreApp.PanelEditor) {
|
||||
return sortOrder === LogsSortOrder.Ascending ? 'bottom' : 'top';
|
||||
}
|
||||
return 'top';
|
||||
}, [data.request?.app, sortOrder]);
|
||||
|
||||
const storageKey = useMemo(() => {
|
||||
if (controlsStorageKey) {
|
||||
return controlsStorageKey;
|
||||
}
|
||||
if (!data.request) {
|
||||
return undefined;
|
||||
}
|
||||
return `${data.request?.dashboardUID}.${id}`;
|
||||
}, [controlsStorageKey, data.request, id]);
|
||||
|
||||
if (!logs.length) {
|
||||
return <PanelDataErrorView fieldConfig={fieldConfig} panelId={id} data={data} needsStringField />;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={style.container} ref={(element: HTMLDivElement) => setLogsContainer(element)}>
|
||||
{logs.length > 0 && logsContainer && (
|
||||
<LogList
|
||||
app={isCoreApp(app) ? app : CoreApp.Dashboard}
|
||||
containerElement={logsContainer}
|
||||
dedupStrategy={dedupStrategy}
|
||||
displayedFields={[]}
|
||||
enableLogDetails
|
||||
grammar={isLogsGrammar(grammar) ? grammar : undefined}
|
||||
initialScrollPosition={initialScrollPosition}
|
||||
logs={logs}
|
||||
loadMore={enableInfiniteScrolling ? loadMoreLogs : undefined}
|
||||
onLogOptionsChange={isOnLogOptionsChange(onLogOptionsChange) ? onLogOptionsChange : undefined}
|
||||
onLogLineHover={onLogRowHover}
|
||||
showControls={showControls}
|
||||
showTime={showTime}
|
||||
sortOrder={sortOrder}
|
||||
logOptionsStorageKey={storageKey}
|
||||
syntaxHighlighting={syntaxHighlighting}
|
||||
timeRange={data.timeRange}
|
||||
timeZone={timeZone}
|
||||
wrapLogMessage={wrapLogMessage}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const getStyles = (theme: GrafanaTheme2) => ({
|
||||
container: css({
|
||||
marginBottom: theme.spacing(1.5),
|
||||
minHeight: '100%',
|
||||
maxHeight: '100%',
|
||||
display: 'flex',
|
||||
flex: 1,
|
||||
flexDirection: 'column',
|
||||
}),
|
||||
});
|
|
@ -1 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 80.49 80.99"><defs><style>.cls-1{fill:#3865ab;}.cls-2{fill:#8ab8ff;}.cls-3{fill:url(#linear-gradient);}.cls-4{fill:url(#linear-gradient-2);}.cls-5{fill:#3a76d0;}</style><linearGradient id="linear-gradient" x1="-3918.19" y1="8047.29" x2="-3910.1" y2="8047.29" gradientTransform="translate(-3910.1 8051.33) rotate(180)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#f2cc0c"/><stop offset="1" stop-color="#ff9830"/></linearGradient><linearGradient id="linear-gradient-2" x1="-3918.19" y1="8010.84" x2="-3910.1" y2="8010.84" xlink:href="#linear-gradient"/></defs><g id="Layer_2" data-name="Layer 2"><g id="Layer_1-2" data-name="Layer 1"><path class="cls-1" d="M79.49,8H14.54V0H79.49a1,1,0,0,1,1,1V7A1,1,0,0,1,79.49,8Z"/><path class="cls-1" d="M59.49,26.27H14.54v-8h45a1,1,0,0,1,1,1v6A1,1,0,0,1,59.49,26.27Z"/><path class="cls-2" d="M6.92,19.38a4,4,0,0,0-1.34-.85,4.1,4.1,0,0,0-3.08,0,4,4,0,0,0-1.33.85,4,4,0,0,0-.85,1.34,4,4,0,0,0,.85,4.41A4.44,4.44,0,0,0,2.5,26a3.76,3.76,0,0,0,3.08,0,4.61,4.61,0,0,0,1.34-.85,4.19,4.19,0,0,0,0-5.75Z"/><path class="cls-1" d="M48.49,44.49H14.54v-8h34a1,1,0,0,1,1,1v6A1,1,0,0,1,48.49,44.49Z"/><path class="cls-1" d="M79.49,81H14.54V73H79.49a1,1,0,0,1,1,1v6A1,1,0,0,1,79.49,81Z"/><path class="cls-2" d="M7.77,75.4a4,4,0,0,1-.85,4.41,4.61,4.61,0,0,1-1.34.85,3.76,3.76,0,0,1-3.08,0,4.44,4.44,0,0,1-1.33-.85A4,4,0,0,1,.32,75.4a4,4,0,0,1,.85-1.34,4,4,0,0,1,1.33-.85,4.1,4.1,0,0,1,3.08,0,4,4,0,0,1,1.34.85A4,4,0,0,1,7.77,75.4Z"/><path class="cls-3" d="M6.92,1.15A4.36,4.36,0,0,0,5.58.3,4.1,4.1,0,0,0,2.5.3a4.32,4.32,0,0,0-1.33.85A4,4,0,0,0,.32,2.49a4,4,0,0,0,.85,4.42,4.87,4.87,0,0,0,1.33.85,3.84,3.84,0,0,0,3.08,0,5.07,5.07,0,0,0,1.34-.85,4.07,4.07,0,0,0,.85-4.42A4,4,0,0,0,6.92,1.15Z"/><path class="cls-4" d="M6.92,37.61a4,4,0,0,0-1.34-.85,4,4,0,0,0-3.08,0,4,4,0,0,0-1.33.85,4,4,0,0,0-.85,1.33,4,4,0,0,0,.85,4.42,4.64,4.64,0,0,0,1.33.85,3.84,3.84,0,0,0,3.08,0,4.83,4.83,0,0,0,1.34-.85,4.07,4.07,0,0,0,.85-4.42A4,4,0,0,0,6.92,37.61Z"/><path class="cls-1" d="M70.49,62.72H14.54v-8h56a1,1,0,0,1,1,1v6A1,1,0,0,1,70.49,62.72Z"/><path class="cls-5" d="M6.92,55.83A4.36,4.36,0,0,0,5.58,55,4.1,4.1,0,0,0,2.5,55a4.32,4.32,0,0,0-1.33.85,4.2,4.2,0,0,0,0,5.76,4.87,4.87,0,0,0,1.33.85,3.84,3.84,0,0,0,3.08,0,5.07,5.07,0,0,0,1.34-.85,4.07,4.07,0,0,0,.85-4.42A4,4,0,0,0,6.92,55.83Z"/></g></g></svg>
|
Before Width: | Height: | Size: 2.4 KiB |
|
@ -1,108 +0,0 @@
|
|||
import { PanelPlugin, LogsSortOrder, LogsDedupStrategy, LogsDedupDescription } from '@grafana/data';
|
||||
import { t } from '@grafana/i18n';
|
||||
|
||||
import { LogsPanel } from './LogsPanel';
|
||||
import { Options } from './panelcfg.gen';
|
||||
import { LogsPanelSuggestionsSupplier } from './suggestions';
|
||||
|
||||
export const plugin = new PanelPlugin<Options>(LogsPanel)
|
||||
.setPanelOptions((builder) => {
|
||||
const category = [t('logs-new.category-logs', 'Logs')];
|
||||
builder
|
||||
.addBooleanSwitch({
|
||||
path: 'showTime',
|
||||
name: t('logs-new.name-time', 'Time'),
|
||||
category,
|
||||
description: '',
|
||||
defaultValue: false,
|
||||
})
|
||||
.addBooleanSwitch({
|
||||
path: 'wrapLogMessage',
|
||||
name: t('logs-new.name-wrap-lines', 'Wrap lines'),
|
||||
category,
|
||||
description: '',
|
||||
defaultValue: false,
|
||||
})
|
||||
.addBooleanSwitch({
|
||||
path: 'syntaxHighlighting',
|
||||
name: t('logs-new.name-syntax-highlighting', 'Enable syntax highlighting'),
|
||||
category,
|
||||
description: t(
|
||||
'logs-new.description-syntax-highlighting',
|
||||
'Use a predefined syntax coloring grammar to highlight relevant parts of the log lines'
|
||||
),
|
||||
defaultValue: true,
|
||||
})
|
||||
.addBooleanSwitch({
|
||||
path: 'enableLogDetails',
|
||||
name: t('logs-new.name-enable-log-details', 'Enable log details'),
|
||||
category,
|
||||
description: '',
|
||||
defaultValue: true,
|
||||
})
|
||||
.addBooleanSwitch({
|
||||
path: 'showControls',
|
||||
name: t('logs-new.name-show-controls', 'Show controls'),
|
||||
category,
|
||||
description: t(
|
||||
'logs-new.description-show-controls',
|
||||
'Display controls to jump to the last or first log line, and filters by log level'
|
||||
),
|
||||
defaultValue: false,
|
||||
})
|
||||
.addBooleanSwitch({
|
||||
path: 'enableInfiniteScrolling',
|
||||
name: t('logs-new.name-infinite-scrolling', 'Enable infinite scrolling'),
|
||||
category,
|
||||
description: t(
|
||||
'logs-new.description-infinite-scrolling',
|
||||
'Experimental. Request more results by scrolling to the bottom of the logs list.'
|
||||
),
|
||||
defaultValue: false,
|
||||
})
|
||||
.addRadio({
|
||||
path: 'dedupStrategy',
|
||||
name: t('logs-new.name-deduplication', 'Deduplication'),
|
||||
category,
|
||||
description: '',
|
||||
settings: {
|
||||
options: [
|
||||
{
|
||||
value: LogsDedupStrategy.none,
|
||||
label: t('logs-new.deduplication-options.label-none', 'None'),
|
||||
description: LogsDedupDescription[LogsDedupStrategy.none],
|
||||
},
|
||||
{
|
||||
value: LogsDedupStrategy.exact,
|
||||
label: t('logs-new.deduplication-options.label-exact', 'Exact'),
|
||||
description: LogsDedupDescription[LogsDedupStrategy.exact],
|
||||
},
|
||||
{
|
||||
value: LogsDedupStrategy.numbers,
|
||||
label: t('logs-new.deduplication-options.label-numbers', 'Numbers'),
|
||||
description: LogsDedupDescription[LogsDedupStrategy.numbers],
|
||||
},
|
||||
{
|
||||
value: LogsDedupStrategy.signature,
|
||||
label: t('logs-new.deduplication-options.label-signature', 'Signature'),
|
||||
description: LogsDedupDescription[LogsDedupStrategy.signature],
|
||||
},
|
||||
],
|
||||
},
|
||||
defaultValue: LogsDedupStrategy.none,
|
||||
})
|
||||
.addRadio({
|
||||
path: 'sortOrder',
|
||||
name: t('logs-new.name-order', 'Order'),
|
||||
category,
|
||||
description: '',
|
||||
settings: {
|
||||
options: [
|
||||
{ value: LogsSortOrder.Descending, label: t('logs-new.order-options.label-newest-first', 'Newest first') },
|
||||
{ value: LogsSortOrder.Ascending, label: t('logs-new.order-options.label-oldest-first', 'Oldest first') },
|
||||
],
|
||||
},
|
||||
defaultValue: LogsSortOrder.Descending,
|
||||
});
|
||||
})
|
||||
.setSuggestionsSupplier(new LogsPanelSuggestionsSupplier());
|
|
@ -1,46 +0,0 @@
|
|||
// Copyright 2023 Grafana Labs
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License")
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package grafanaplugin
|
||||
|
||||
import (
|
||||
"github.com/grafana/grafana/packages/grafana-schema/src/common"
|
||||
)
|
||||
|
||||
composableKinds: PanelCfg: {
|
||||
maturity: "experimental"
|
||||
|
||||
lineage: {
|
||||
schemas: [{
|
||||
version: [0, 0]
|
||||
schema: {
|
||||
Options: {
|
||||
showControls: bool
|
||||
showTime: bool
|
||||
wrapLogMessage: bool
|
||||
enableLogDetails: bool
|
||||
syntaxHighlighting: bool
|
||||
sortOrder: common.LogsSortOrder
|
||||
dedupStrategy: common.LogsDedupStrategy
|
||||
grammar?: _
|
||||
enableInfiniteScrolling?: bool
|
||||
onLogOptionsChange?: _
|
||||
onNewLogsReceived?: _
|
||||
controlsStorageKey?: string
|
||||
} @cuetsy(kind="interface")
|
||||
}
|
||||
}]
|
||||
lenses: []
|
||||
}
|
||||
}
|
|
@ -1,26 +0,0 @@
|
|||
// Code generated - EDITING IS FUTILE. DO NOT EDIT.
|
||||
//
|
||||
// Generated by:
|
||||
// public/app/plugins/gen.go
|
||||
// Using jennies:
|
||||
// TSTypesJenny
|
||||
// PluginTsTypesJenny
|
||||
//
|
||||
// Run 'make gen-cue' from repository root to regenerate.
|
||||
|
||||
import * as common from '@grafana/schema';
|
||||
|
||||
export interface Options {
|
||||
controlsStorageKey?: string;
|
||||
dedupStrategy: common.LogsDedupStrategy;
|
||||
enableInfiniteScrolling?: boolean;
|
||||
enableLogDetails: boolean;
|
||||
grammar?: unknown;
|
||||
onLogOptionsChange?: unknown;
|
||||
onNewLogsReceived?: unknown;
|
||||
showControls: boolean;
|
||||
showTime: boolean;
|
||||
sortOrder: common.LogsSortOrder;
|
||||
syntaxHighlighting: boolean;
|
||||
wrapLogMessage: boolean;
|
||||
}
|
|
@ -1,24 +0,0 @@
|
|||
{
|
||||
"type": "panel",
|
||||
"name": "Logs new",
|
||||
"id": "logs-new",
|
||||
"state": "alpha",
|
||||
|
||||
"info": {
|
||||
"author": {
|
||||
"name": "Grafana Labs",
|
||||
"url": "https://grafana.com"
|
||||
},
|
||||
"logos": {
|
||||
"small": "img/icn-logs-panel.svg",
|
||||
"large": "img/icn-logs-panel.svg"
|
||||
},
|
||||
"links": [
|
||||
{ "name": "Raise issue", "url": "https://github.com/grafana/grafana/issues/new" },
|
||||
{
|
||||
"name": "Documentation",
|
||||
"url": "https://grafana.com/docs/grafana/latest/panels-visualizations/visualizations/logs/"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
|
@ -1,33 +0,0 @@
|
|||
import { VisualizationSuggestionsBuilder, VisualizationSuggestionScore } from '@grafana/data';
|
||||
import { SuggestionName } from 'app/types/suggestions';
|
||||
|
||||
import { Options } from './panelcfg.gen';
|
||||
|
||||
export class LogsPanelSuggestionsSupplier {
|
||||
getSuggestionsForData(builder: VisualizationSuggestionsBuilder) {
|
||||
const list = builder.getListAppender<Options, {}>({
|
||||
name: '',
|
||||
pluginId: 'logs-new',
|
||||
options: {},
|
||||
fieldConfig: {
|
||||
defaults: {
|
||||
custom: {},
|
||||
},
|
||||
overrides: [],
|
||||
},
|
||||
});
|
||||
|
||||
const { dataSummary: ds } = builder;
|
||||
|
||||
// Require a string & time field
|
||||
if (!ds.hasData || !ds.hasTimeField || !ds.hasStringField) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (ds.preferredVisualisationType === 'logs') {
|
||||
list.append({ name: SuggestionName.Logs, score: VisualizationSuggestionScore.Best });
|
||||
} else {
|
||||
list.append({ name: SuggestionName.Logs });
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,24 +0,0 @@
|
|||
import { Grammar } from 'prismjs';
|
||||
|
||||
import { CoreApp, DataFrame } from '@grafana/data';
|
||||
import { LogListControlOptions } from 'app/features/logs/components/panel/LogList';
|
||||
|
||||
type onNewLogsReceivedType = (allLogs: DataFrame[], newLogs: DataFrame[]) => void;
|
||||
type onLogOptionsChangeType = (option: LogListControlOptions, value: string | boolean | string[]) => void;
|
||||
|
||||
export function isOnNewLogsReceivedType(callback: unknown): callback is onNewLogsReceivedType {
|
||||
return typeof callback === 'function';
|
||||
}
|
||||
|
||||
export function isOnLogOptionsChange(callback: unknown): callback is onLogOptionsChangeType {
|
||||
return typeof callback === 'function';
|
||||
}
|
||||
|
||||
export function isLogsGrammar(grammar: unknown): grammar is Grammar {
|
||||
return grammar !== null && typeof grammar === 'object' && Object.getPrototypeOf(grammar) === Object.prototype;
|
||||
}
|
||||
|
||||
export function isCoreApp(app: unknown): app is CoreApp {
|
||||
const apps = Object.values(CoreApp).map((coreApp) => coreApp.toString());
|
||||
return typeof app === 'string' && apps.includes(app);
|
||||
}
|
|
@ -9734,30 +9734,6 @@
|
|||
"label-log-stats": "{{label}}: {{total}} of {{rowCount}} rows have that label"
|
||||
}
|
||||
},
|
||||
"logs-new": {
|
||||
"category-logs": "Logs",
|
||||
"deduplication-options": {
|
||||
"label-exact": "Exact",
|
||||
"label-none": "None",
|
||||
"label-numbers": "Numbers",
|
||||
"label-signature": "Signature"
|
||||
},
|
||||
"description-infinite-scrolling": "Experimental. Request more results by scrolling to the bottom of the logs list.",
|
||||
"description-show-controls": "Display controls to jump to the last or first log line, and filters by log level",
|
||||
"description-syntax-highlighting": "Use a predefined syntax coloring grammar to highlight relevant parts of the log lines",
|
||||
"name-deduplication": "Deduplication",
|
||||
"name-enable-log-details": "Enable log details",
|
||||
"name-infinite-scrolling": "Enable infinite scrolling",
|
||||
"name-order": "Order",
|
||||
"name-show-controls": "Show controls",
|
||||
"name-syntax-highlighting": "Enable syntax highlighting",
|
||||
"name-time": "Time",
|
||||
"name-wrap-lines": "Wrap lines",
|
||||
"order-options": {
|
||||
"label-newest-first": "Newest first",
|
||||
"label-oldest-first": "Oldest first"
|
||||
}
|
||||
},
|
||||
"manage-dashbaords": {
|
||||
"import-dashboard-form": {
|
||||
"description-existing-library-panels": "List of existing library panels. These panels are not affected by the import."
|
||||
|
|
Loading…
Reference in New Issue