Skip to content

Commit d4ddf3a

Browse files
authored
Merge pull request #97 from quickwit-oss/ddelemeny/log-end-selector
Improve log limits UX : select log end & raised limit
2 parents 9f7e8f0 + 591421b commit d4ddf3a

File tree

10 files changed

+124
-85
lines changed

10 files changed

+124
-85
lines changed

src/LogContext/LogContextProvider.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import {
1313
rangeUtil,
1414
} from '@grafana/data';
1515

16-
import { ElasticsearchQuery, Logs} from '../types';
16+
import { ElasticsearchQuery, Logs, LogsSortDirection} from '../types';
1717

1818
import { LogContextUI } from './components/LogContextUI';
1919

@@ -64,7 +64,7 @@ export class LogContextProvider {
6464
settings: {
6565
limit: options?.limit ? options?.limit.toString() : '10',
6666
// Sorting of results in the context query
67-
sortDirection: direction === LogRowContextQueryDirection.Backward ? 'desc' : 'asc',
67+
sortDirection: direction === LogRowContextQueryDirection.Backward ? LogsSortDirection.DESC : LogsSortDirection.ASC,
6868
// Used to get the next log lines before/after the current log line using sort field of selected log line
6969
searchAfter: searchAfter,
7070
},
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import { css } from "@emotion/css";
2+
import { RadioButtonGroup } from "@grafana/ui";
3+
import React from "react";
4+
import { Logs, LogsSortDirection, LogsEnd } from "types";
5+
import { SettingField } from "./SettingField";
6+
import { useDispatch } from "hooks/useStatelessReducer";
7+
import { changeMetricSetting } from '../state/actions';
8+
import { metricAggregationConfig } from "../utils";
9+
10+
11+
// type LogsSortDirection = 'asc' | 'desc'
12+
13+
interface Props { metric: Logs }
14+
15+
export const LogsSettingsEditor = ({metric}: Props)=>{
16+
const config = metricAggregationConfig['logs']
17+
const dispatch = useDispatch();
18+
return (
19+
<div className={css({display:"inline-flex", justifyContent:"start", gap:"4px", height:"100%"})} >
20+
<RadioButtonGroup
21+
className={css({height:"100%"})}
22+
options={Object.values(LogsSortDirection).map((v)=>({label:LogsEnd[v], value:v}))}
23+
value={metric.settings?.sortDirection || config.defaults.settings?.sortDirection }
24+
onChange={(v)=>{ dispatch(
25+
changeMetricSetting({ metric, settingName: 'sortDirection', newValue: v })
26+
)}}/>
27+
<SettingField label="Limit" metric={metric} settingName="limit" placeholder={config.defaults.settings?.limit} />
28+
</div>
29+
)
30+
31+
}

src/components/QueryEditor/MetricAggregationsEditor/SettingsEditor/index.tsx

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,10 @@ import { MovingAverageSettingsEditor } from './MovingAverageSettingsEditor';
1616
import { SettingField } from './SettingField';
1717
import { TopMetricsSettingsEditor } from './TopMetricsSettingsEditor';
1818
import { useDescription } from './useDescription';
19+
import { LogsSettingsEditor } from './LogsSettingsEditor';
1920

2021
// TODO: Move this somewhere and share it with BucketsAggregation Editor
21-
const inlineFieldProps: Partial<ComponentProps<typeof InlineField>> = {
22+
export const inlineFieldProps: Partial<ComponentProps<typeof InlineField>> = {
2223
labelWidth: 16,
2324
};
2425

@@ -84,7 +85,9 @@ export const SettingsEditor = ({ metric, previousMetrics }: Props) => {
8485
</InlineField>
8586
)}
8687

87-
{metric.type === 'logs' && <SettingField label="Limit" metric={metric} settingName="limit" placeholder="100" />}
88+
{metric.type === 'logs' && (
89+
<LogsSettingsEditor metric={metric}></LogsSettingsEditor>
90+
)}
8891

8992
{metric.type === 'cardinality' && (
9093
<SettingField label="Precision Threshold" metric={metric} settingName="precision_threshold" />

src/components/QueryEditor/MetricAggregationsEditor/SettingsEditor/useDescription.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { extendedStats } from 'queryDef';
2-
import { MetricAggregation } from '@/types';
2+
import { Logs, LogsEnd, MetricAggregation } from '@/types';
3+
import { metricAggregationConfig } from '../utils';
34

45
const hasValue = (value: string) => (object: { value: string }) => object.value === value;
56

@@ -34,6 +35,14 @@ export const useDescription = (metric: MetricAggregation): string => {
3435
return `Size: ${size}`;
3536
}
3637

38+
case 'logs': {
39+
const config = metricAggregationConfig['logs']
40+
const logsmetric: Logs = metric
41+
const sort = LogsEnd[logsmetric.settings?.sortDirection || config.defaults.settings!.sortDirection!]
42+
const limit = logsmetric.settings?.limit || 100
43+
return `${sort} ${limit}`
44+
}
45+
3746
default:
3847
return 'Options';
3948
}

src/components/QueryEditor/MetricAggregationsEditor/index.tsx

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,13 @@ import React from 'react';
33
import { useDispatch } from '@/hooks/useStatelessReducer';
44
import { IconButton } from '../../IconButton';
55
import { useQuery } from '../ElasticsearchQueryContext';
6-
import { QueryEditorRow } from '../QueryEditorRow';
6+
import { QueryEditorRow, QueryEditorBaseRow } from '../QueryEditorRow';
77

88
import { MetricAggregation } from '@/types';
99
import { MetricEditor } from './MetricEditor';
1010
import { addMetric, removeMetric, toggleMetricVisibility } from './state/actions';
1111
import { metricAggregationConfig } from './utils';
12-
import { QueryEditorSpecialMetricRow } from '../QueryEditorSpecialMetricRow';
12+
import { SettingsEditor } from './SettingsEditor';
1313

1414
interface Props {
1515
nextId: MetricAggregation['id'];
@@ -25,9 +25,13 @@ export const MetricAggregationsEditor = ({ nextId }: Props) => {
2525
{metrics?.map((metric, index) => {
2626
switch (metric.type) {
2727
case 'logs':
28-
return <QueryEditorSpecialMetricRow key={`${metric.type}-${metric.id}`} name="Logs" metric={metric} />;
28+
return <QueryEditorBaseRow key={`${metric.type}-${metric.id}`} label="Logs">
29+
<SettingsEditor metric={metric} previousMetrics={[]} />
30+
</QueryEditorBaseRow>;
2931
case 'raw_data':
30-
return <QueryEditorSpecialMetricRow key={`${metric.type}-${metric.id}`} name="Raw Data" metric={metric} />;
32+
return <QueryEditorBaseRow key={`${metric.type}-${metric.id}`} label="Raw Data">
33+
<SettingsEditor metric={metric} previousMetrics={[]} />
34+
</QueryEditorBaseRow>;
3135
default:
3236
return (
3337
<QueryEditorRow

src/components/QueryEditor/MetricAggregationsEditor/utils.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { MetricsConfiguration, MetricAggregation, PipelineMetricAggregationType } from '@/types';
1+
import { MetricsConfiguration, MetricAggregation, PipelineMetricAggregationType, LogsSortDirection } from '@/types';
22

33
import {
44
defaultPipelineVariable,
@@ -243,7 +243,8 @@ export const metricAggregationConfig: MetricsConfiguration = {
243243
hasMeta: false,
244244
defaults: {
245245
settings: {
246-
limit: '100',
246+
limit: '1000',
247+
sortDirection:'desc' as LogsSortDirection
247248
},
248249
},
249250
},
Lines changed: 51 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,68 +1,79 @@
11
import { css } from '@emotion/css';
22
import { noop } from 'lodash';
3-
import React, { PropsWithChildren } from 'react';
3+
import React, { PropsWithChildren, ReactNode } from 'react';
44

55
import { GrafanaTheme2 } from '@grafana/data';
66
import { IconButton, InlineFieldRow, InlineLabel, InlineSegmentGroup, useStyles2 } from '@grafana/ui';
77

8-
interface Props {
9-
label: string;
8+
const getStyles = (theme: GrafanaTheme2) => {
9+
return {
10+
iconWrapper: css`
11+
display: flex;
12+
`,
13+
icon: css`
14+
color: ${theme.colors.text.secondary};
15+
margin-left: ${theme.spacing(0.25)};
16+
`,
17+
};
18+
};
19+
20+
interface BaseRowProps { label: ReactNode; };
21+
export const QueryEditorBaseRow = ({ label, children }: PropsWithChildren<BaseRowProps>) => {
22+
return (
23+
<InlineFieldRow>
24+
<InlineSegmentGroup>
25+
<InlineLabel width={17} as="div">
26+
{label}
27+
</InlineLabel>
28+
</InlineSegmentGroup>
29+
{children}
30+
</InlineFieldRow>
31+
);
32+
};
33+
34+
interface RowProps extends BaseRowProps {
1035
onRemoveClick?: false | (() => void);
1136
onHideClick?: false | (() => void);
1237
hidden?: boolean;
1338
}
14-
1539
export const QueryEditorRow = ({
1640
children,
1741
label,
1842
onRemoveClick,
1943
onHideClick,
2044
hidden = false,
21-
}: PropsWithChildren<Props>) => {
45+
}: PropsWithChildren<RowProps>) => {
2246
const styles = useStyles2(getStyles);
2347

2448
return (
25-
<InlineFieldRow>
26-
<InlineSegmentGroup>
27-
<InlineLabel width={17} as="div">
28-
<span>{label}</span>
29-
<span className={styles.iconWrapper}>
30-
{onHideClick && (
31-
<IconButton
32-
name={hidden ? 'eye-slash' : 'eye'}
33-
onClick={onHideClick}
34-
size="sm"
35-
aria-pressed={hidden}
36-
aria-label="hide metric"
37-
className={styles.icon}
38-
type="button"
39-
/>
40-
)}
49+
<QueryEditorBaseRow label={(<>
50+
<span>{label}</span>
51+
<span className={styles.iconWrapper}>
52+
{onHideClick && (
4153
<IconButton
42-
name="trash-alt"
54+
name={hidden ? 'eye-slash' : 'eye'}
55+
onClick={onHideClick}
4356
size="sm"
57+
aria-pressed={hidden}
58+
aria-label="hide metric"
4459
className={styles.icon}
45-
onClick={onRemoveClick || noop}
46-
disabled={!onRemoveClick}
47-
aria-label="remove metric"
4860
type="button"
4961
/>
50-
</span>
51-
</InlineLabel>
52-
</InlineSegmentGroup>
62+
)}
63+
<IconButton
64+
name="trash-alt"
65+
size="sm"
66+
className={styles.icon}
67+
onClick={onRemoveClick || noop}
68+
disabled={!onRemoveClick}
69+
aria-label="remove metric"
70+
type="button"
71+
/>
72+
</span>
73+
</>)}>
5374
{children}
54-
</InlineFieldRow>
75+
</QueryEditorBaseRow>
5576
);
5677
};
5778

58-
const getStyles = (theme: GrafanaTheme2) => {
59-
return {
60-
iconWrapper: css`
61-
display: flex;
62-
`,
63-
icon: css`
64-
color: ${theme.colors.text.secondary};
65-
margin-left: ${theme.spacing(0.25)};
66-
`,
67-
};
68-
};
79+

src/components/QueryEditor/QueryEditorSpecialMetricRow.tsx

Lines changed: 0 additions & 30 deletions
This file was deleted.

src/queryDef.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ export function defaultMetricAgg(id = '1'): MetricAggregation {
3232
}
3333

3434
export function defaultLogsAgg(id = '1'): MetricAggregation {
35-
return { type: 'logs', id };
35+
return { type: 'logs', id, ...metricAggregationConfig['logs'].defaults };
3636
}
3737

3838
export function defaultBucketAgg(id = '1'): DateHistogram {

src/types.ts

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,24 @@ import {
1515
} from './dataquery.gen';
1616

1717
export * from './dataquery.gen';
18-
export { Elasticsearch as ElasticsearchQuery } from './dataquery.gen';
18+
export { type Elasticsearch as ElasticsearchQuery } from './dataquery.gen';
1919

2020
// We want to extend the settings of the Logs query with additional properties that
2121
// are not part of the schema. This is a workaround, because exporting LogsSettings
2222
// from dataquery.gen.ts and extending that produces error in SettingKeyOf.
23+
export enum LogsSortDirection {
24+
DESC = 'desc',
25+
ASC = 'asc',
26+
}
27+
28+
export const LogsEnd = {
29+
[LogsSortDirection.ASC]: 'Head',
30+
[LogsSortDirection.DESC]: 'Tail'
31+
}
32+
2333
type ExtendedLogsSettings = SchemaLogs['settings'] & {
2434
searchAfter?: unknown[];
25-
sortDirection?: 'asc' | 'desc';
35+
sortDirection?: LogsSortDirection;
2636
};
2737

2838
export interface Logs extends SchemaLogs {
@@ -65,7 +75,7 @@ interface MetricConfiguration<T extends MetricAggregationType> {
6575
impliedQueryType: QueryType;
6676
hasSettings: boolean;
6777
hasMeta: boolean;
68-
defaults: Omit<Extract<MetricAggregation, { type: T }>, 'id' | 'type'>;
78+
defaults: Omit<Extract<Exclude<MetricAggregation,SchemaLogs>|Logs, { type: T }>, 'id' | 'type'>;
6979
}
7080

7181
type BucketConfiguration<T extends BucketAggregationType> = {

0 commit comments

Comments
 (0)