chore: adjust discover (#151)
* fix: add time range to suggestions's request * fix: adjust DatePicker's display * chore: hide search info automatically in discover * chore: adjust discover's histogram * chore: update release notes --------- Co-authored-by: yaojiping <yaojiping@infini.ltd> Co-authored-by: Hardy <luohoufu@infinilabs.com>
This commit is contained in:
parent
1cd1f98af4
commit
932a2a46e1
|
@ -18,9 +18,11 @@ Information about release notes of INFINI Console is provided here.
|
||||||
### Bug fix
|
### Bug fix
|
||||||
- Fixed the error when querying empty metric data (#144)
|
- Fixed the error when querying empty metric data (#144)
|
||||||
- Fixed empty host when setup step finishes (#147)
|
- Fixed empty host when setup step finishes (#147)
|
||||||
|
- Fixed the error of obtaining suggestions of field's value in discover
|
||||||
|
|
||||||
### Improvements
|
### Improvements
|
||||||
- Update agent config with cluster name (#148)
|
- Update agent config with cluster name (#148)
|
||||||
|
- Optimize UI of histogram and datepicker in discover (#151)
|
||||||
- Support viewing logs for cluster, node, index health change events (#150)
|
- Support viewing logs for cluster, node, index health change events (#150)
|
||||||
|
|
||||||
## 1.28.2 (2025-02-15)
|
## 1.28.2 (2025-02-15)
|
||||||
|
|
|
@ -18,12 +18,13 @@ title: "版本历史"
|
||||||
### Bug fix
|
### Bug fix
|
||||||
- 修复指标数据为空时的查询错误 (#144)
|
- 修复指标数据为空时的查询错误 (#144)
|
||||||
- 修复初始化结束步骤中主机显示为错误的问题 (#147)
|
- 修复初始化结束步骤中主机显示为错误的问题 (#147)
|
||||||
|
- 修复数据探索中获取字段值建议的错误
|
||||||
|
|
||||||
### Improvements
|
### Improvements
|
||||||
- 优化下发给 Agent 的配置,增加集群名称 (#148)
|
- 优化下发给 Agent 的配置,增加集群名称 (#148)
|
||||||
|
- 优化柱状图和时间选择器的 UI (#151)
|
||||||
- 集群,节点,索引健康状态变更支持查看日志 (#150)
|
- 集群,节点,索引健康状态变更支持查看日志 (#150)
|
||||||
|
|
||||||
|
|
||||||
## 1.28.2 (2025-02-15)
|
## 1.28.2 (2025-02-15)
|
||||||
|
|
||||||
### Features
|
### Features
|
||||||
|
|
|
@ -215,7 +215,7 @@ const DatePicker = (props) => {
|
||||||
isMinimum ? styles.minimum : ""
|
isMinimum ? styles.minimum : ""
|
||||||
} ${className}`}
|
} ${className}`}
|
||||||
>
|
>
|
||||||
<Button.Group className={styles.RangeBox}>
|
<Button.Group className={styles.RangeBox} style={{ width: onRefresh ? 'calc(100% - 64px)' : 'calc(100% - 32px)'}}>
|
||||||
{!isMinimum && (
|
{!isMinimum && (
|
||||||
<Button
|
<Button
|
||||||
className={`${styles.iconBtn} common-ui-datepicker-backward`}
|
className={`${styles.iconBtn} common-ui-datepicker-backward`}
|
||||||
|
|
|
@ -42,8 +42,8 @@
|
||||||
align-items: center;
|
align-items: center;
|
||||||
margin-left: 4px !important;
|
margin-left: 4px !important;
|
||||||
.play {
|
.play {
|
||||||
min-width: 30px;
|
min-width: 32px;
|
||||||
max-width: 30px;
|
max-width: 32px;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
color: #1890ff;
|
color: #1890ff;
|
||||||
|
|
|
@ -121,6 +121,9 @@ function FilterBarUI(props: Props) {
|
||||||
onCancel={() => setIsAddFilterPopoverOpen(false)}
|
onCancel={() => setIsAddFilterPopoverOpen(false)}
|
||||||
key={JSON.stringify(newFilter)}
|
key={JSON.stringify(newFilter)}
|
||||||
services={props.services}
|
services={props.services}
|
||||||
|
dateRangeFrom={props.dateRangeFrom}
|
||||||
|
dateRangeTo={props.dateRangeTo}
|
||||||
|
timeField={props.timeField}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</EuiFlexItem>
|
</EuiFlexItem>
|
||||||
|
|
|
@ -313,6 +313,9 @@ class FilterEditorUI extends Component<Props, State> {
|
||||||
onChange={this.onParamsChange}
|
onChange={this.onParamsChange}
|
||||||
data-test-subj="phraseValueInput"
|
data-test-subj="phraseValueInput"
|
||||||
services={this.props.services}
|
services={this.props.services}
|
||||||
|
dateRangeFrom={this.props.dateRangeFrom}
|
||||||
|
dateRangeTo={this.props.dateRangeTo}
|
||||||
|
timeField={this.props.timeField}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
case 'phrases':
|
case 'phrases':
|
||||||
|
@ -323,6 +326,9 @@ class FilterEditorUI extends Component<Props, State> {
|
||||||
values={this.state.params}
|
values={this.state.params}
|
||||||
onChange={this.onParamsChange}
|
onChange={this.onParamsChange}
|
||||||
services={this.props.services}
|
services={this.props.services}
|
||||||
|
dateRangeFrom={this.props.dateRangeFrom}
|
||||||
|
dateRangeTo={this.props.dateRangeTo}
|
||||||
|
timeField={this.props.timeField}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
case 'range':
|
case 'range':
|
||||||
|
|
|
@ -82,17 +82,30 @@ export class PhraseSuggestorUI<
|
||||||
protected updateSuggestions = debounce(async (query: string = "") => {
|
protected updateSuggestions = debounce(async (query: string = "") => {
|
||||||
if (this.abortController) this.abortController.abort();
|
if (this.abortController) this.abortController.abort();
|
||||||
this.abortController = new AbortController();
|
this.abortController = new AbortController();
|
||||||
const { indexPattern, field } = this.props as PhraseSuggestorProps;
|
const { indexPattern, field, dateRangeFrom, dateRangeTo, timeField } = this.props as PhraseSuggestorProps;
|
||||||
if (!field || !this.isSuggestingValues()) {
|
if (!field || !this.isSuggestingValues()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.setState({ isLoading: true });
|
this.setState({ isLoading: true });
|
||||||
|
|
||||||
|
const boolFilter = []
|
||||||
|
if (dateRangeFrom && dateRangeTo && timeField) {
|
||||||
|
boolFilter.push({
|
||||||
|
"range": {
|
||||||
|
[timeField]: {
|
||||||
|
"gte": dateRangeFrom,
|
||||||
|
"lte": dateRangeTo
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
const suggestions = await this.props.services.data.autocomplete.getValueSuggestions(
|
const suggestions = await this.props.services.data.autocomplete.getValueSuggestions(
|
||||||
{
|
{
|
||||||
indexPattern,
|
indexPattern,
|
||||||
field,
|
field,
|
||||||
query,
|
query,
|
||||||
|
boolFilter,
|
||||||
signal: this.abortController.signal,
|
signal: this.abortController.signal,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
|
@ -50,8 +50,7 @@ class PhraseValueInputUI extends PhraseSuggestorUI<Props> {
|
||||||
}
|
}
|
||||||
|
|
||||||
private renderWithSuggestions() {
|
private renderWithSuggestions() {
|
||||||
let { suggestions } = this.state;
|
const suggestions = Array.isArray(this.state.suggestions) ? this.state.suggestions : []
|
||||||
suggestions = suggestions || [];
|
|
||||||
const { value, intl, onChange } = this.props;
|
const { value, intl, onChange } = this.props;
|
||||||
// there are cases when the value is a number, this would cause an exception
|
// there are cases when the value is a number, this would cause an exception
|
||||||
const valueAsStr = String(value);
|
const valueAsStr = String(value);
|
||||||
|
|
|
@ -59,7 +59,7 @@
|
||||||
@include euiBreakpoint("m", "l", "xl") {
|
@include euiBreakpoint("m", "l", "xl") {
|
||||||
.kbnQueryBar__datePickerWrapper {
|
.kbnQueryBar__datePickerWrapper {
|
||||||
// sass-lint:disable-block no-important
|
// sass-lint:disable-block no-important
|
||||||
max-width: 340px;
|
max-width: 400px;
|
||||||
flex-grow: 0 !important;
|
flex-grow: 0 !important;
|
||||||
flex-basis: auto !important;
|
flex-basis: auto !important;
|
||||||
margin-right: -$euiSizeXS;
|
margin-right: -$euiSizeXS;
|
||||||
|
|
|
@ -264,7 +264,7 @@ export default function QueryBarTopRow(props: QueryBarTopRowProps) {
|
||||||
return (
|
return (
|
||||||
<NoDataPopover storage={storage} showNoDataPopover={props.indicateNoData}>
|
<NoDataPopover storage={storage} showNoDataPopover={props.indicateNoData}>
|
||||||
<EuiFlexGroup responsive={false} gutterSize="s">
|
<EuiFlexGroup responsive={false} gutterSize="s">
|
||||||
{renderHistogram()}
|
{/* {renderHistogram()} */}
|
||||||
{renderDatePicker()}
|
{renderDatePicker()}
|
||||||
<EuiFlexItem grow={false}>{button}</EuiFlexItem>
|
<EuiFlexItem grow={false}>{button}</EuiFlexItem>
|
||||||
</EuiFlexGroup>
|
</EuiFlexGroup>
|
||||||
|
|
|
@ -484,6 +484,9 @@ class SearchBarUI extends Component<SearchBarProps, State> {
|
||||||
filters={this.props.filters!}
|
filters={this.props.filters!}
|
||||||
onFiltersUpdated={this.props.onFiltersUpdated}
|
onFiltersUpdated={this.props.onFiltersUpdated}
|
||||||
indexPatterns={this.props.indexPatterns!}
|
indexPatterns={this.props.indexPatterns!}
|
||||||
|
dateRangeFrom={this.state.dateRangeFrom}
|
||||||
|
dateRangeTo={this.state.dateRangeTo}
|
||||||
|
timeField={this.props.timeSetting?.timeField}
|
||||||
services={this.props.services}
|
services={this.props.services}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1122,7 +1122,7 @@ const Discover = (props) => {
|
||||||
getVisualizations={() => visRef?.current?.getVisualizations()}
|
getVisualizations={() => visRef?.current?.getVisualizations()}
|
||||||
searchInfo={{
|
searchInfo={{
|
||||||
took,
|
took,
|
||||||
hits,
|
total: hits,
|
||||||
...timeChartProps,
|
...timeChartProps,
|
||||||
}}
|
}}
|
||||||
selectedQueriesId={selectedQueriesId}
|
selectedQueriesId={selectedQueriesId}
|
||||||
|
@ -1160,6 +1160,10 @@ const Discover = (props) => {
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
showLayoutListIcon={false}
|
showLayoutListIcon={false}
|
||||||
|
histogramProps={{
|
||||||
|
histogramData,
|
||||||
|
timefilterUpdateHandler
|
||||||
|
}}
|
||||||
// viewLayout={viewLayout}
|
// viewLayout={viewLayout}
|
||||||
// onViewLayoutChange={(layout) => {
|
// onViewLayoutChange={(layout) => {
|
||||||
// if (layout) {
|
// if (layout) {
|
||||||
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
import { DiscoverHistogram } from "@/components/vendor/discover/public/application/components/histogram/histogram";
|
||||||
|
import { Icon, Popover } from "antd"
|
||||||
|
import { useEffect, useRef, useState } from "react";
|
||||||
|
import styles from "./index.less";
|
||||||
|
|
||||||
|
export default (props) => {
|
||||||
|
|
||||||
|
const { histogramData, timefilterUpdateHandler } = props
|
||||||
|
|
||||||
|
const [visible, setVisible] = useState(false)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Popover
|
||||||
|
visible={visible}
|
||||||
|
placement="left"
|
||||||
|
title={null}
|
||||||
|
overlayClassName={styles.histogram}
|
||||||
|
content={(
|
||||||
|
<DiscoverHistogram
|
||||||
|
chartData={histogramData}
|
||||||
|
timefilterUpdateHandler={timefilterUpdateHandler}
|
||||||
|
/>
|
||||||
|
)}>
|
||||||
|
<Icon type="bar-chart" style={{color: '#006BB4', cursor: 'pointer'}} onClick={() => {
|
||||||
|
setVisible(!visible)
|
||||||
|
}}/>
|
||||||
|
</Popover>
|
||||||
|
)
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
.histogram {
|
||||||
|
z-index: 1;
|
||||||
|
:global {
|
||||||
|
.ant-popover-inner-content {
|
||||||
|
width: 400px;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,9 +5,9 @@ import InsightConfig, { ISearchConfig } from "../InsightConfig";
|
||||||
import styles from './index.less';
|
import styles from './index.less';
|
||||||
import { create, list, remove, update } from "../services/queries";
|
import { create, list, remove, update } from "../services/queries";
|
||||||
import FullScreen from "../FullScreen";
|
import FullScreen from "../FullScreen";
|
||||||
import ModeHandler from "../ModeHandler";
|
|
||||||
import { Icon, message } from "antd";
|
import { Icon, message } from "antd";
|
||||||
import SearchInfo from "../SearchInfo";
|
import SearchInfo from "../SearchInfo";
|
||||||
|
import Histogram from "../Histogram";
|
||||||
import ViewLayout from "../ViewLayout";
|
import ViewLayout from "../ViewLayout";
|
||||||
|
|
||||||
export interface IQueries {
|
export interface IQueries {
|
||||||
|
@ -72,7 +72,8 @@ export default forwardRef((props: IProps, ref: any) => {
|
||||||
onSearchConfigChange,
|
onSearchConfigChange,
|
||||||
showLayoutListIcon,
|
showLayoutListIcon,
|
||||||
viewLayout,
|
viewLayout,
|
||||||
onViewLayoutChange
|
onViewLayoutChange,
|
||||||
|
histogramProps = {}
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
const {
|
const {
|
||||||
|
@ -183,6 +184,7 @@ export default forwardRef((props: IProps, ref: any) => {
|
||||||
return (
|
return (
|
||||||
<div className={styles.bar}>
|
<div className={styles.bar}>
|
||||||
<SearchInfo {...searchInfo} loading={searchLoading}/>
|
<SearchInfo {...searchInfo} loading={searchLoading}/>
|
||||||
|
{ histogramProps?.histogramData && <Histogram {...histogramProps}/>}
|
||||||
<SaveQueries
|
<SaveQueries
|
||||||
tags={tags}
|
tags={tags}
|
||||||
onTagsChange={setTags}
|
onTagsChange={setTags}
|
||||||
|
|
|
@ -30,7 +30,7 @@ export interface IProps {
|
||||||
* selected interval
|
* selected interval
|
||||||
*/
|
*/
|
||||||
stateInterval: string;
|
stateInterval: string;
|
||||||
hits: number;
|
total: number;
|
||||||
took?: number;
|
took?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,7 +39,7 @@ export default ({
|
||||||
dateFormat,
|
dateFormat,
|
||||||
timeRange,
|
timeRange,
|
||||||
stateInterval,
|
stateInterval,
|
||||||
hits,
|
total,
|
||||||
took,
|
took,
|
||||||
}: IProps) => {
|
}: IProps) => {
|
||||||
const [interval, setInterval] = useState(stateInterval);
|
const [interval, setInterval] = useState(stateInterval);
|
||||||
|
@ -69,7 +69,7 @@ export default ({
|
||||||
>
|
>
|
||||||
<EuiFlexItem grow={false}>
|
<EuiFlexItem grow={false}>
|
||||||
<div style={{ fontSize: 12}}>
|
<div style={{ fontSize: 12}}>
|
||||||
Found <span style={{fontWeight: "bold" }}>{hits}</span>{" "}
|
Found <span style={{fontWeight: "bold" }}>{total}</span>{" "}
|
||||||
records {took && (
|
records {took && (
|
||||||
<span style={{marginLeft: 5 }}>
|
<span style={{marginLeft: 5 }}>
|
||||||
({took} milliscond)
|
({took} milliscond)
|
||||||
|
|
|
@ -1,17 +1,40 @@
|
||||||
import { Icon, Popover } from "antd"
|
import { Icon, Popover } from "antd"
|
||||||
import { useState } from "react";
|
import { useEffect, useRef, useState } from "react";
|
||||||
import Info, { IProps } from "./Info";
|
import Info, { IProps } from "./Info";
|
||||||
import styles from './index.scss';
|
import styles from './index.scss';
|
||||||
|
|
||||||
export default (props: IProps & { loading: boolean }) => {
|
export default (props: IProps & { loading: boolean }) => {
|
||||||
|
|
||||||
const [showResultCount, setShowResultCount] = useState(true);
|
const { loading, total } = props
|
||||||
|
|
||||||
if (typeof props.hits !== 'number' || props.hits <= 0) return null;
|
const [showResultCount, setShowResultCount] = useState(true);
|
||||||
|
const timerRef = useRef(null)
|
||||||
|
const autoHiddenRef = useRef(true)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (timerRef.current) {
|
||||||
|
clearTimeout(timerRef.current)
|
||||||
|
}
|
||||||
|
if (showResultCount) {
|
||||||
|
timerRef.current = setTimeout(() => {
|
||||||
|
if (autoHiddenRef.current) {
|
||||||
|
setShowResultCount(false)
|
||||||
|
}
|
||||||
|
}, 3000);
|
||||||
|
}
|
||||||
|
}, [showResultCount])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (loading) {
|
||||||
|
autoHiddenRef.current = true
|
||||||
|
}
|
||||||
|
}, [loading])
|
||||||
|
|
||||||
|
if (typeof total !== 'number' || total <= 0) return null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Popover
|
<Popover
|
||||||
visible={!props.loading && showResultCount}
|
visible={!loading && showResultCount}
|
||||||
placement="left"
|
placement="left"
|
||||||
title={null}
|
title={null}
|
||||||
overlayClassName={styles.searchInfo}
|
overlayClassName={styles.searchInfo}
|
||||||
|
@ -21,7 +44,14 @@ export default (props: IProps & { loading: boolean }) => {
|
||||||
dateFormat={"YYYY-MM-DD H:mm"}
|
dateFormat={"YYYY-MM-DD H:mm"}
|
||||||
/>
|
/>
|
||||||
)}>
|
)}>
|
||||||
<Icon type="info-circle" style={{color: '#006BB4', cursor: 'pointer'}} onClick={() => setShowResultCount(!showResultCount)}/>
|
<Icon type="info-circle" style={{color: '#006BB4', cursor: 'pointer'}} onClick={() => {
|
||||||
|
if (showResultCount) {
|
||||||
|
autoHiddenRef.current = true
|
||||||
|
} else {
|
||||||
|
autoHiddenRef.current = false
|
||||||
|
}
|
||||||
|
setShowResultCount(!showResultCount)
|
||||||
|
}}/>
|
||||||
</Popover>
|
</Popover>
|
||||||
)
|
)
|
||||||
}
|
}
|
Loading…
Reference in New Issue