diff --git a/src/LogContext/LogContextProvider.ts b/src/LogContext/LogContextProvider.ts index 6919e29..5401550 100644 --- a/src/LogContext/LogContextProvider.ts +++ b/src/LogContext/LogContextProvider.ts @@ -13,7 +13,7 @@ import { rangeUtil, } from '@grafana/data'; -import { ElasticsearchQuery, Logs} from '../types'; +import { ElasticsearchQuery, Logs, LogsSortDirection} from '../types'; import { LogContextUI } from './components/LogContextUI'; @@ -64,7 +64,7 @@ export class LogContextProvider { settings: { limit: options?.limit ? options?.limit.toString() : '10', // Sorting of results in the context query - sortDirection: direction === LogRowContextQueryDirection.Backward ? 'desc' : 'asc', + sortDirection: direction === LogRowContextQueryDirection.Backward ? LogsSortDirection.DESC : LogsSortDirection.ASC, // Used to get the next log lines before/after the current log line using sort field of selected log line searchAfter: searchAfter, }, diff --git a/src/components/QueryEditor/MetricAggregationsEditor/SettingsEditor/LogsSettingsEditor.tsx b/src/components/QueryEditor/MetricAggregationsEditor/SettingsEditor/LogsSettingsEditor.tsx new file mode 100644 index 0000000..09055a5 --- /dev/null +++ b/src/components/QueryEditor/MetricAggregationsEditor/SettingsEditor/LogsSettingsEditor.tsx @@ -0,0 +1,31 @@ +import { css } from "@emotion/css"; +import { RadioButtonGroup } from "@grafana/ui"; +import React from "react"; +import { Logs, LogsSortDirection, LogsEnd } from "types"; +import { SettingField } from "./SettingField"; +import { useDispatch } from "hooks/useStatelessReducer"; +import { changeMetricSetting } from '../state/actions'; +import { metricAggregationConfig } from "../utils"; + + +// type LogsSortDirection = 'asc' | 'desc' + +interface Props { metric: Logs } + +export const LogsSettingsEditor = ({metric}: Props)=>{ + const config = metricAggregationConfig['logs'] + const dispatch = useDispatch(); + return ( +
+ ({label:LogsEnd[v], value:v}))} + value={metric.settings?.sortDirection || config.defaults.settings?.sortDirection } + onChange={(v)=>{ dispatch( + changeMetricSetting({ metric, settingName: 'sortDirection', newValue: v }) + )}}/> + +
+ ) + +} diff --git a/src/components/QueryEditor/MetricAggregationsEditor/SettingsEditor/index.tsx b/src/components/QueryEditor/MetricAggregationsEditor/SettingsEditor/index.tsx index 3d56d04..9b5b8c4 100644 --- a/src/components/QueryEditor/MetricAggregationsEditor/SettingsEditor/index.tsx +++ b/src/components/QueryEditor/MetricAggregationsEditor/SettingsEditor/index.tsx @@ -16,9 +16,10 @@ import { MovingAverageSettingsEditor } from './MovingAverageSettingsEditor'; import { SettingField } from './SettingField'; import { TopMetricsSettingsEditor } from './TopMetricsSettingsEditor'; import { useDescription } from './useDescription'; +import { LogsSettingsEditor } from './LogsSettingsEditor'; // TODO: Move this somewhere and share it with BucketsAggregation Editor -const inlineFieldProps: Partial> = { +export const inlineFieldProps: Partial> = { labelWidth: 16, }; @@ -84,7 +85,9 @@ export const SettingsEditor = ({ metric, previousMetrics }: Props) => { )} - {metric.type === 'logs' && } + {metric.type === 'logs' && ( + + )} {metric.type === 'cardinality' && ( diff --git a/src/components/QueryEditor/MetricAggregationsEditor/SettingsEditor/useDescription.ts b/src/components/QueryEditor/MetricAggregationsEditor/SettingsEditor/useDescription.ts index b143c59..6cf1e16 100644 --- a/src/components/QueryEditor/MetricAggregationsEditor/SettingsEditor/useDescription.ts +++ b/src/components/QueryEditor/MetricAggregationsEditor/SettingsEditor/useDescription.ts @@ -1,5 +1,6 @@ import { extendedStats } from 'queryDef'; -import { MetricAggregation } from '@/types'; +import { Logs, LogsEnd, MetricAggregation } from '@/types'; +import { metricAggregationConfig } from '../utils'; const hasValue = (value: string) => (object: { value: string }) => object.value === value; @@ -34,6 +35,14 @@ export const useDescription = (metric: MetricAggregation): string => { return `Size: ${size}`; } + case 'logs': { + const config = metricAggregationConfig['logs'] + const logsmetric: Logs = metric + const sort = LogsEnd[logsmetric.settings?.sortDirection || config.defaults.settings!.sortDirection!] + const limit = logsmetric.settings?.limit || 100 + return `${sort} ${limit}` + } + default: return 'Options'; } diff --git a/src/components/QueryEditor/MetricAggregationsEditor/index.tsx b/src/components/QueryEditor/MetricAggregationsEditor/index.tsx index 3296612..2c877b5 100644 --- a/src/components/QueryEditor/MetricAggregationsEditor/index.tsx +++ b/src/components/QueryEditor/MetricAggregationsEditor/index.tsx @@ -3,13 +3,13 @@ import React from 'react'; import { useDispatch } from '@/hooks/useStatelessReducer'; import { IconButton } from '../../IconButton'; import { useQuery } from '../ElasticsearchQueryContext'; -import { QueryEditorRow } from '../QueryEditorRow'; +import { QueryEditorRow, QueryEditorBaseRow } from '../QueryEditorRow'; import { MetricAggregation } from '@/types'; import { MetricEditor } from './MetricEditor'; import { addMetric, removeMetric, toggleMetricVisibility } from './state/actions'; import { metricAggregationConfig } from './utils'; -import { QueryEditorSpecialMetricRow } from '../QueryEditorSpecialMetricRow'; +import { SettingsEditor } from './SettingsEditor'; interface Props { nextId: MetricAggregation['id']; @@ -25,9 +25,13 @@ export const MetricAggregationsEditor = ({ nextId }: Props) => { {metrics?.map((metric, index) => { switch (metric.type) { case 'logs': - return ; + return + + ; case 'raw_data': - return ; + return + + ; default: return ( { + return { + iconWrapper: css` + display: flex; + `, + icon: css` + color: ${theme.colors.text.secondary}; + margin-left: ${theme.spacing(0.25)}; + `, + }; +}; + +interface BaseRowProps { label: ReactNode; }; +export const QueryEditorBaseRow = ({ label, children }: PropsWithChildren) => { + return ( + + + + {label} + + + {children} + + ); +}; + +interface RowProps extends BaseRowProps { onRemoveClick?: false | (() => void); onHideClick?: false | (() => void); hidden?: boolean; } - export const QueryEditorRow = ({ children, label, onRemoveClick, onHideClick, hidden = false, -}: PropsWithChildren) => { +}: PropsWithChildren) => { const styles = useStyles2(getStyles); return ( - - - - {label} - - {onHideClick && ( - - )} + + {label} + + {onHideClick && ( - - - + )} + + + )}> {children} - + ); }; -const getStyles = (theme: GrafanaTheme2) => { - return { - iconWrapper: css` - display: flex; - `, - icon: css` - color: ${theme.colors.text.secondary}; - margin-left: ${theme.spacing(0.25)}; - `, - }; -}; + diff --git a/src/components/QueryEditor/QueryEditorSpecialMetricRow.tsx b/src/components/QueryEditor/QueryEditorSpecialMetricRow.tsx deleted file mode 100644 index ab34c00..0000000 --- a/src/components/QueryEditor/QueryEditorSpecialMetricRow.tsx +++ /dev/null @@ -1,30 +0,0 @@ -import React from 'react'; - -import { InlineFieldRow, InlineLabel, InlineSegmentGroup } from '@grafana/ui'; - -import { MetricAggregation } from '@/types'; - -import { SettingsEditor } from './MetricAggregationsEditor/SettingsEditor'; - -type Props = { - name: string; - metric: MetricAggregation; -}; - -export const QueryEditorSpecialMetricRow = ({ name, metric }: Props) => { - // this widget is only used in scenarios when there is only a single - // metric, so the array of "previousMetrics" (meaning all the metrics - // before the current metric), is an ampty-array - const previousMetrics: MetricAggregation[] = []; - - return ( - - - - {name} - - - - - ); -}; diff --git a/src/queryDef.ts b/src/queryDef.ts index 66e5160..780253a 100644 --- a/src/queryDef.ts +++ b/src/queryDef.ts @@ -32,7 +32,7 @@ export function defaultMetricAgg(id = '1'): MetricAggregation { } export function defaultLogsAgg(id = '1'): MetricAggregation { - return { type: 'logs', id }; + return { type: 'logs', id, ...metricAggregationConfig['logs'].defaults }; } export function defaultBucketAgg(id = '1'): DateHistogram { diff --git a/src/types.ts b/src/types.ts index 1dba31c..ed57465 100644 --- a/src/types.ts +++ b/src/types.ts @@ -15,14 +15,24 @@ import { } from './dataquery.gen'; export * from './dataquery.gen'; -export { Elasticsearch as ElasticsearchQuery } from './dataquery.gen'; +export { type Elasticsearch as ElasticsearchQuery } from './dataquery.gen'; // We want to extend the settings of the Logs query with additional properties that // are not part of the schema. This is a workaround, because exporting LogsSettings // from dataquery.gen.ts and extending that produces error in SettingKeyOf. +export enum LogsSortDirection { + DESC = 'desc', + ASC = 'asc', +} + +export const LogsEnd = { + [LogsSortDirection.ASC]: 'Head', + [LogsSortDirection.DESC]: 'Tail' +} + type ExtendedLogsSettings = SchemaLogs['settings'] & { searchAfter?: unknown[]; - sortDirection?: 'asc' | 'desc'; + sortDirection?: LogsSortDirection; }; export interface Logs extends SchemaLogs { @@ -65,7 +75,7 @@ interface MetricConfiguration { impliedQueryType: QueryType; hasSettings: boolean; hasMeta: boolean; - defaults: Omit, 'id' | 'type'>; + defaults: Omit|Logs, { type: T }>, 'id' | 'type'>; } type BucketConfiguration = {