diff --git a/main.go b/main.go index 953ca539..d5ad4d2e 100644 --- a/main.go +++ b/main.go @@ -105,6 +105,7 @@ func main() { orm.RegisterSchemaWithIndexName(alerting.Alert{}, "alerting-alerts") orm.RegisterSchemaWithIndexName(alerting.AlertingHistory{}, "alerting-alert-history") orm.RegisterSchema(elastic.CommonCommand{}) + orm.RegisterSchemaWithIndexName(elastic.TraceMeta{}, "traces") alertSrv.GetScheduler().Start() },nil){ app.Run() diff --git a/web/config/router.config.js b/web/config/router.config.js index 8349240b..4b761074 100644 --- a/web/config/router.config.js +++ b/web/config/router.config.js @@ -127,64 +127,64 @@ export default [ // ], // }, - //data - // { - // path: "/data", - // name: "data", - // icon: "database", - // routes: [ - // // { - // // path: '/data/overview', - // // name: 'overview', - // // component: './DataManagement/IndexSummary', - // // routes:[ - // // { path: '/', redirect: '/' }, - // // ], - // // }, - // { - // path: "/data/index", - // name: "index", - // component: "./DataManagement/Index", - // routes: [{ path: "/", redirect: "/" }], - // }, - // // { - // // path: '/data/document', - // // name: 'document', - // // component: './DataManagement/Document', - // // routes:[ - // // { path: '/', redirect: '/' }, - // // ], - // // }, - // // { - // // path: '/data/template', - // // name: 'template', - // // component: './DataManagement/IndexTemplate', - // // routes:[ - // // { path: '/', redirect: '/' }, - // // ], - // // }, - // // { - // // path: '/data/lifecycle', - // // name: 'lifecycle', - // // component: './DataManagement/IndexLifeCycle', - // // routes:[ - // // { path: '/', redirect: '/' }, - // // ], - // // }, - // { - // routes: [{ path: "/", redirect: "/" }], - // path: "/data/discover", - // name: "discover", - // component: "./DataManagement/Discover", - // }, - // { - // routes: [{ path: "/", redirect: "/" }], - // path: "/data/views/", - // name: "indexPatterns", - // component: "./DataManagement/IndexPatterns", - // }, - // ], - // }, + // data + { + path: "/data", + name: "data", + icon: "database", + routes: [ + // { + // path: '/data/overview', + // name: 'overview', + // component: './DataManagement/IndexSummary', + // routes:[ + // { path: '/', redirect: '/' }, + // ], + // }, + { + path: "/data/index", + name: "index", + component: "./DataManagement/Index", + routes: [{ path: "/", redirect: "/" }], + }, + // { + // path: '/data/document', + // name: 'document', + // component: './DataManagement/Document', + // routes:[ + // { path: '/', redirect: '/' }, + // ], + // }, + // { + // path: '/data/template', + // name: 'template', + // component: './DataManagement/IndexTemplate', + // routes:[ + // { path: '/', redirect: '/' }, + // ], + // }, + // { + // path: '/data/lifecycle', + // name: 'lifecycle', + // component: './DataManagement/IndexLifeCycle', + // routes:[ + // { path: '/', redirect: '/' }, + // ], + // }, + { + routes: [{ path: "/", redirect: "/" }], + path: "/data/discover", + name: "discover", + component: "./DataManagement/Discover", + }, + { + routes: [{ path: "/", redirect: "/" }], + path: "/data/views/", + name: "indexPatterns", + component: "./DataManagement/IndexPatterns", + }, + ], + }, //search // { diff --git a/web/src/components/kibana/data/public/ui/filter_bar/filter_item.tsx b/web/src/components/kibana/data/public/ui/filter_bar/filter_item.tsx index f647082a..53eea0ad 100644 --- a/web/src/components/kibana/data/public/ui/filter_bar/filter_item.tsx +++ b/web/src/components/kibana/data/public/ui/filter_bar/filter_item.tsx @@ -17,14 +17,14 @@ * under the License. */ -import { EuiContextMenu, EuiPopover } from '@elastic/eui'; -import { InjectedIntl } from '@kbn/i18n/react'; -import classNames from 'classnames'; -import React, { MouseEvent, useState, useEffect } from 'react'; -import { IUiSettingsClient } from 'src/core/public'; -import { FilterEditor } from './filter_editor'; -import { FilterView } from './filter_view'; -import { IIndexPattern } from '../..'; +import { EuiContextMenu, EuiPopover } from "@elastic/eui"; +import { InjectedIntl } from "@kbn/i18n/react"; +import classNames from "classnames"; +import React, { MouseEvent, useState, useEffect } from "react"; +import { IUiSettingsClient } from "src/core/public"; +import { FilterEditor } from "./filter_editor"; +import { FilterView } from "./filter_view"; +import { IIndexPattern } from "../.."; import { Filter, isFilterPinned, @@ -33,8 +33,8 @@ import { toggleFilterPinned, toggleFilterDisabled, getIndexPatternFromFilter, -} from '../../../common'; -import { getIndexPatterns } from '../../services'; +} from "../../../common"; +import { getIndexPatterns } from "../../services"; interface Props { id: string; @@ -53,9 +53,9 @@ interface LabelOptions { message?: string; } -const FILTER_ITEM_OK = ''; -const FILTER_ITEM_WARNING = 'warn'; -const FILTER_ITEM_ERROR = 'error'; +const FILTER_ITEM_OK = ""; +const FILTER_ITEM_WARNING = "warn"; +const FILTER_ITEM_ERROR = "error"; export type FilterLabelStatus = | typeof FILTER_ITEM_OK @@ -64,7 +64,9 @@ export type FilterLabelStatus = export function FilterItem(props: Props) { const [isPopoverOpen, setIsPopoverOpen] = useState(false); - const [indexPatternExists, setIndexPatternExists] = useState(undefined); + const [indexPatternExists, setIndexPatternExists] = useState< + boolean | undefined + >(undefined); const { id, filter, indexPatterns } = props; useEffect(() => { @@ -123,26 +125,35 @@ export function FilterItem(props: Props) { function getClasses(negate: boolean, labelConfig: LabelOptions) { return classNames( - 'globalFilterItem', + "globalFilterItem", { - 'globalFilterItem-isDisabled': isDisabled(labelConfig), - 'globalFilterItem-isError': labelConfig.status === FILTER_ITEM_ERROR, - 'globalFilterItem-isWarning': labelConfig.status === FILTER_ITEM_WARNING, - 'globalFilterItem-isPinned': isFilterPinned(filter), - 'globalFilterItem-isExcluded': negate, + "globalFilterItem-isDisabled": isDisabled(labelConfig), + "globalFilterItem-isError": labelConfig.status === FILTER_ITEM_ERROR, + "globalFilterItem-isWarning": + labelConfig.status === FILTER_ITEM_WARNING, + "globalFilterItem-isPinned": isFilterPinned(filter), + "globalFilterItem-isExcluded": negate, }, props.className ); } function getDataTestSubj(labelConfig: LabelOptions) { - const dataTestSubjKey = filter.meta.key ? `filter-key-${filter.meta.key}` : ''; + const dataTestSubjKey = filter.meta.key + ? `filter-key-${filter.meta.key}` + : ""; const dataTestSubjValue = filter.meta.value - ? `filter-value-${isValidLabel(labelConfig) ? labelConfig.title : labelConfig.status}` - : ''; - const dataTestSubjNegated = filter.meta.negate ? 'filter-negated' : ''; - const dataTestSubjDisabled = `filter-${isDisabled(labelConfig) ? 'disabled' : 'enabled'}`; - const dataTestSubjPinned = `filter-${isFilterPinned(filter) ? 'pinned' : 'unpinned'}`; + ? `filter-value-${ + isValidLabel(labelConfig) ? labelConfig.title : labelConfig.status + }` + : ""; + const dataTestSubjNegated = filter.meta.negate ? "filter-negated" : ""; + const dataTestSubjDisabled = `filter-${ + isDisabled(labelConfig) ? "disabled" : "enabled" + }`; + const dataTestSubjPinned = `filter-${ + isFilterPinned(filter) ? "pinned" : "unpinned" + }`; return `filter ${dataTestSubjDisabled} ${dataTestSubjKey} ${dataTestSubjValue} ${dataTestSubjPinned} ${dataTestSubjNegated}`; } @@ -153,52 +164,46 @@ export function FilterItem(props: Props) { id: 0, items: [ { - name: isFilterPinned(filter) - ? 'Unpin' - : 'Pin across all apps', - icon: 'pin', + name: isFilterPinned(filter) ? "Unpin" : "Pin across all apps", + icon: "pin", onClick: () => { setIsPopoverOpen(false); onTogglePinned(); }, - 'data-test-subj': 'pinFilter', + "data-test-subj": "pinFilter", }, { - name: 'Edit filter', - icon: 'pencil', + name: "Edit filter", + icon: "pencil", panel: 1, - 'data-test-subj': 'editFilter', + "data-test-subj": "editFilter", }, { - name: negate - ? 'Include results' - : 'Exclude results', - icon: negate ? 'plusInCircle' : 'minusInCircle', + name: negate ? "Include results" : "Exclude results", + icon: negate ? "plusInCircle" : "minusInCircle", onClick: () => { setIsPopoverOpen(false); onToggleNegated(); }, - 'data-test-subj': 'negateFilter', + "data-test-subj": "negateFilter", }, { - name: disabled - ? 'Re-enable' - : 'Temporarily disable', - icon: `${disabled ? 'eye' : 'eyeClosed'}`, + name: disabled ? "Re-enable" : "Temporarily disable", + icon: `${disabled ? "eye" : "eyeClosed"}`, onClick: () => { setIsPopoverOpen(false); onToggleDisabled(); }, - 'data-test-subj': 'disableFilter', + "data-test-subj": "disableFilter", }, { - name: 'Delete', - icon: 'trash', + name: "Delete", + icon: "trash", onClick: () => { setIsPopoverOpen(false); props.onRemove(); }, - 'data-test-subj': 'deleteFilter', + "data-test-subj": "deleteFilter", }, ], }, @@ -236,31 +241,23 @@ export function FilterItem(props: Props) { const allFields = indexPatterns.map((indexPattern) => { return indexPattern.fields.map((field) => field.name); }); - const flatFields = allFields.reduce((acc: string[], it: string[]) => [...acc, ...it], []); - return flatFields.includes(filter.meta?.key || ''); + const flatFields = allFields.reduce( + (acc: string[], it: string[]) => [...acc, ...it], + [] + ); + return flatFields.includes(filter.meta?.key || ""); } function getValueLabel(): LabelOptions { const label: LabelOptions = { - title: '', - message: '', + title: "", + message: "", status: FILTER_ITEM_OK, }; if (indexPatternExists === false) { label.status = FILTER_ITEM_ERROR; - label.title = props.intl.formatMessage({ - id: 'data.filter.filterBar.labelErrorText', - defaultMessage: `Error`, - }); - label.message = props.intl.formatMessage( - { - id: 'data.filter.filterBar.labelErrorInfo', - defaultMessage: 'Index pattern {indexPattern} not found', - }, - { - indexPattern: filter.meta.index, - } - ); + label.title = "Error"; + label.message = "Index pattern not found"; } else if (isFilterApplicable()) { try { label.title = getDisplayValueFromFilter(filter, indexPatterns); diff --git a/web/src/components/kibana/data/public/ui/search_bar/create_search_bar.tsx b/web/src/components/kibana/data/public/ui/search_bar/create_search_bar.tsx index 929cc8d3..1f15186e 100644 --- a/web/src/components/kibana/data/public/ui/search_bar/create_search_bar.tsx +++ b/web/src/components/kibana/data/public/ui/search_bar/create_search_bar.tsx @@ -17,29 +17,28 @@ * under the License. */ -import _ from 'lodash'; -import React, { useEffect, useRef } from 'react'; -import { QueryStart, SavedQuery } from '../../query'; -import { SearchBar } from './'; -import { useFilterManager } from './lib/use_filter_manager'; -import { useTimefilter } from './lib/use_timefilter'; +import _ from "lodash"; +import React, { useEffect, useRef } from "react"; +import { QueryStart, SavedQuery } from "../../query"; +import { SearchBar } from "./"; +import { useFilterManager } from "./lib/use_filter_manager"; +import { useTimefilter } from "./lib/use_timefilter"; // import { useSavedQuery } from './lib/use_saved_query'; -import { Filter, Query, TimeRange } from '../../../common'; -import { useQueryStringManager } from './lib/use_query_string_manager'; +import { Filter, Query, TimeRange } from "../../../common"; +import { useQueryStringManager } from "./lib/use_query_string_manager"; // Respond to user changing the filters const defaultFiltersUpdated = (props) => { return (filters: Filter[]) => { props.filterManager.setFilters(filters); - if (props.onQuerySubmit) - props.onQuerySubmit(); + if (props.onQuerySubmit) props.onQuerySubmit(); }; }; // Respond to user changing the refresh settings const defaultOnRefreshChange = (props) => { // const { timefilter } = props.timefilter; - const timefilter = props.timefilter + const timefilter = props.timefilter; return (options: { isPaused: boolean; refreshInterval: number }) => { timefilter.setRefreshInterval({ value: options.refreshInterval, @@ -49,14 +48,11 @@ const defaultOnRefreshChange = (props) => { }; // Respond to user changing the query string or time settings -const defaultOnQuerySubmit = ( - props, - currentQuery -) => { +const defaultOnQuerySubmit = (props, currentQuery) => { if (!props.useDefaultBehaviors) return props.onQuerySubmit; //const { timefilter } = props.timefilter; - const timefilter = props.timefilter; + const timefilter = props.timefilter; return (payload: { dateRange: TimeRange; query?: Query }) => { const isUpdate = @@ -69,8 +65,7 @@ const defaultOnQuerySubmit = ( } else { props.queryString.clearQuery(); } - } - else { + } else { // Refresh button triggered for an update if (props.onQuerySubmit) props.onQuerySubmit( @@ -143,7 +138,7 @@ export function createSearchBar() { useEffect(() => { if (!useDefaultBehaviors || !props.onQuerySubmit) return; //!onQuerySubmitRef.current //onQuerySubmitRef.current( - props.onQuerySubmit( + props.onQuerySubmit( { dateRange: timeRange, query, @@ -153,34 +148,34 @@ export function createSearchBar() { }, [query, timeRange, useDefaultBehaviors, props.onQuerySubmit]); return ( - + ); }; } diff --git a/web/src/components/kibana/discover/public/application/components/sidebar/change_indexpattern.tsx b/web/src/components/kibana/discover/public/application/components/sidebar/change_indexpattern.tsx index 32c815af..a7bd9451 100644 --- a/web/src/components/kibana/discover/public/application/components/sidebar/change_indexpattern.tsx +++ b/web/src/components/kibana/discover/public/application/components/sidebar/change_indexpattern.tsx @@ -17,7 +17,7 @@ * under the License. */ -import React, { useState } from 'react'; +import React, { useState } from "react"; import { EuiButtonEmpty, EuiPopover, @@ -28,10 +28,9 @@ import { EuiTabbedContent, EuiTab, EuiSwitch, -} from '@elastic/eui'; -import { EuiSelectableProps } from '@elastic/eui/src/components/selectable/selectable'; -import { IndexPatternRef } from './types'; - +} from "@elastic/eui"; +import { EuiSelectableProps } from "@elastic/eui/src/components/selectable/selectable"; +import { IndexPatternRef } from "./types"; export type ChangeIndexPatternTriggerProps = EuiButtonEmptyProps & { label: string; @@ -55,7 +54,7 @@ export function ChangeIndexPattern({ }) { const [isPopoverOpen, setPopoverIsOpen] = useState(false); - const createTrigger = function () { + const createTrigger = function() { const { label, title, ...rest } = trigger; return ( ); }; - - const [selectedTabId, setSelectedTabId] = useState(indices.includes(indexPatternId) ? 1 :0); + const indexNames = (indexPatternId || "").split(","); + const [selectedTabId, setSelectedTabId] = useState( + indexNames.every((index) => indices.includes(index)) ? 1 : 0 + ); + const singleSelection = React.useMemo(() => { + return indexNames.length > 1 ? true : "always"; + }, [indexNames]); const onSelectedTabChanged = (id: number) => { setSelectedTabId(id); }; - const [includeSystemIndex, setIncludeSystemIndex] = useState(false); + const [includeSystemIndex, setIncludeSystemIndex] = useState(false); - const tabs = React.useMemo(()=>{ - const showIndices = includeSystemIndex ? indices: indices.filter(key=>!key.startsWith(".")); + const tabs = React.useMemo(() => { + const showIndices = includeSystemIndex + ? indices + : indices.filter((key) => !key.startsWith(".")); const tabs = [ { - id: 'view', - name: 'View', + id: "view", + name: "View", disabled: false, - content: ( ({ - label: viewName, - key: id, - value: id, - checked: id === indexPatternId ? 'on' : undefined, - }))} - onChange={(choices) => { - const choice = (choices.find(({ checked }) => checked) as unknown) as { - value: string; - }; - onChangeIndexPattern(choice.value, 'view'); - setPopoverIsOpen(false); - }} - searchProps={{ - compressed: true, - ...(selectableProps ? selectableProps.searchProps : undefined), - }} - > - {(list, search) => ( - <> - {search} - {list} - - )} - ), + content: ( + ({ + label: viewName, + key: id, + value: id, + checked: id === indexPatternId ? "on" : undefined, + }))} + onChange={(choices) => { + const choice = (choices.find( + ({ checked }) => checked + ) as unknown) as { + value: string; + }; + onChangeIndexPattern(choice.value, "view"); + setPopoverIsOpen(false); + }} + searchProps={{ + compressed: true, + ...(selectableProps ? selectableProps.searchProps : undefined), + }} + > + {(list, search) => ( + <> + {search} + {list} + + )} + + ), }, { - id: 'index', - name: 'Index', + id: "index", + name: "Index", disabled: false, - content:( + content: (
-
- setIncludeSystemIndex(!includeSystemIndex)} - /> +
+ setIncludeSystemIndex(!includeSystemIndex)} + />
- - ({ - label: indexName, - key: indexName, - value: indexName, - checked: indexName === indexPatternId ? 'on' : undefined, - }))} - onChange={(choices) => { - const choice = (choices.find(({ checked }) => checked) as unknown) as { - value: string; - }; - onChangeIndexPattern(choice.value, 'index'); - setPopoverIsOpen(false); - }} - searchProps={{ - compressed: true, - ...(selectableProps ? selectableProps.searchProps : undefined), - }} - > - {(list, search) => ( - <> - {search} - {list} - - )} -
), + + ({ + label: indexName, + key: indexName, + value: indexName, + checked: indexNames.includes(indexName) ? "on" : undefined, + }))} + onChange={(choices) => { + // const choice = (choices.find( + // ({ checked }) => checked + // ) as unknown) as { + // value: string; + // }; + const values = choices + .filter(({ checked }) => checked) + .map((choice) => { + return choice.value; + }); + onChangeIndexPattern(values.join(","), "index"); + setPopoverIsOpen(false); + }} + searchProps={{ + compressed: true, + ...(selectableProps ? selectableProps.searchProps : undefined), + }} + > + {(list, search) => ( + <> + {search} + {list} + + )} + +
+ ), }, ]; return tabs; - },[selectableProps, indexPatternId, indexPatternRefs, indices, includeSystemIndex]) + }, [ + selectableProps, + indexPatternId, + indexPatternRefs, + indices, + includeSystemIndex, + singleSelection, + ]); const selectedTabContent = React.useMemo(() => { return tabs.find((obj) => obj.id === selectedTabId)?.content; @@ -199,15 +231,15 @@ export function ChangeIndexPattern({ {/* 选择视图 */} - {/* + {/* {renderTabs()} */} - { - const idx = tabs.findIndex(item=>item.id == tab.id); + const idx = tabs.findIndex((item) => item.id == tab.id); setSelectedTabId(idx); }} /> diff --git a/web/src/components/kibana/discover/public/application/components/sidebar/discover_index_pattern.tsx b/web/src/components/kibana/discover/public/application/components/sidebar/discover_index_pattern.tsx index ae3b3b2b..760bd155 100644 --- a/web/src/components/kibana/discover/public/application/components/sidebar/discover_index_pattern.tsx +++ b/web/src/components/kibana/discover/public/application/components/sidebar/discover_index_pattern.tsx @@ -16,12 +16,12 @@ * specific language governing permissions and limitations * under the License. */ -import React, { useState, useEffect } from 'react'; -import { SavedObject } from 'kibana/public'; -import { IIndexPattern, IndexPatternAttributes } from 'src/plugins/data/public'; +import React, { useState, useEffect } from "react"; +import { SavedObject } from "kibana/public"; +import { IIndexPattern, IndexPatternAttributes } from "src/plugins/data/public"; -import { IndexPatternRef } from './types'; -import { ChangeIndexPattern } from './change_indexpattern'; +import { IndexPatternRef } from "./types"; +import { ChangeIndexPattern } from "./change_indexpattern"; export interface DiscoverIndexPatternProps { /** * list of available index patterns, if length > 1, component offers a "change" link @@ -56,7 +56,7 @@ export function DiscoverIndexPattern({ const [selected, setSelected] = useState({ id: selectedId, - title: selectedTitle || '', + title: selectedTitle || "", }); useEffect(() => { const { id, title, viewName } = selectedIndexPattern; @@ -68,37 +68,37 @@ export function DiscoverIndexPattern({ return (
- { - let indexPattern = null; - if(typ == 'index'){ - indices.forEach((indexName)=>{ - if(indexName == id){ - indexPattern = { - id: indexName, - title: indexName, - viewName: indexName, - } - } - }) - }else{ - indexPattern = options.find((pattern) => pattern.id === id); - } - if (indexPattern) { - setIndexPattern(id, typ); - setSelected(indexPattern); - } - }} - indices={indices} - /> + { + let indexPattern = null; + if (typ == "index") { + // indices.forEach((indexName)=>{ + // if(indexName == id){ + indexPattern = { + id: id, + title: id, + viewName: id, + }; + // } + // }) + } else { + indexPattern = options.find((pattern) => pattern.id === id); + } + if (indexPattern) { + setIndexPattern(id, typ); + setSelected(indexPattern); + } + }} + indices={indices} + />
); } diff --git a/web/src/pages/DataManagement/Discover.jsx b/web/src/pages/DataManagement/Discover.jsx index 33225ef4..4c753cc8 100644 --- a/web/src/pages/DataManagement/Discover.jsx +++ b/web/src/pages/DataManagement/Discover.jsx @@ -32,7 +32,17 @@ import * as styles from "./discover.scss"; import { Subscription } from "rxjs"; import { connect } from "dva"; -import { Card, Spin, message, Select, Icon, Popover } from "antd"; +import { + Card, + Spin, + message, + Select, + Icon, + Popover, + Tabs, + Input, + Button, +} from "antd"; // import DiscoverGrid from './Components/discover_grid'; import { flattenHitWrapper } from "../../components/kibana/data/common/index_patterns/index_patterns"; import { getStateColumnActions } from "../../components/kibana/discover/public/application/angular/doc_table/actions/columns"; @@ -85,7 +95,9 @@ const Discover = (props) => { const [state, setState] = useState({ columns: columnsParam || ["_source"], //['name', 'address'], interval: "auto", + activeTabKey: "normal", }); + const [searchType, setSearchType] = React.useState("normal"); // const [sort, setSort] = useState(null); @@ -100,7 +112,7 @@ const Discover = (props) => { ); return subscriptions; }, [props.indexPattern]); - const setIndexPattern = async (id, typ) => { + const setIndexPattern = async (id, typ, filters, isReset = false) => { const IP = await services.indexPatternService.get( id, typ, @@ -113,6 +125,14 @@ const Discover = (props) => { columns: ["_source"], sort: [], }); + if (filters && filters.length > 0) { + if (isReset) { + filterManager.setFilters(filters); + } else { + filterManager.addFilters(filters); + } + } + updateQuery(); }; const onTimeFieldChange = async (id, timeField) => { const IP = await services.indexPatternService.get( @@ -130,6 +150,8 @@ const Discover = (props) => { const indexPatterns = [indexPattern]; const indexPatternList = props.indexPatternList; const contentCentered = false; //resultState != 'ready'; + const indexPatternRef = React.useRef(); + indexPatternRef.current = indexPattern; indexPatterns.get = (id) => { return Promise.resolve(indexPatterns.find((ip) => ip.id == id)); @@ -143,12 +165,12 @@ const Discover = (props) => { const updateQuery = useCallback( async (_payload) => { - if (!indexPattern) { + if (!indexPatternRef.current) { return; } setResultState("loading"); const params = getSearchParams( - _payload?.indexPattern || indexPattern, + _payload?.indexPattern || indexPatternRef.current, _payload?.interval || state.interval, _payload?.sort ); @@ -171,7 +193,7 @@ const Discover = (props) => { // console.log(getEsQuery(indexPattern)); // console.log(timefilter.createFilter(indexPattern)); }, - [indexPattern, state.interval] + [state.interval] ); const onChangeInterval = useCallback( @@ -406,34 +428,82 @@ const Discover = (props) => { }, [saveDocument, deleteDocument]); const [settingsVisible, setSettingsVisible] = React.useState(false); + const onTraceIDSearch = React.useCallback( + async (value) => { + const { http } = getContext(); + const indexNames = await http + .fetch(http.getServerBasePath() + "/search/trace_id", { + query: { + traceID: value, + }, + }) + .catch((err) => { + console.log(err); + }); + if (indexNames && indexNames.length > 0) { + const newFilters = generateFilters( + filterManager, + "trace_id", + value, + "+", + indexNames.join(",") + ); + setIndexPattern(indexNames.join(","), "index", newFilters, true); + setSearchType("normal"); + } + }, + [setIndexPattern] + ); return ( - + + + + + + + 搜索 + + } + size="large" + onSearch={onTraceIDSearch} + /> + + @@ -658,6 +728,9 @@ const Discover = (props) => { }; const DiscoverUI = (props) => { + if (!props.selectedCluster.id) { + return null; + } const [viewID, setViewID] = useQueryParam("viewID", StringParam); const [index, setIndex] = useQueryParam("index", StringParam); // const [type, setType] = useQueryParam('type', StringParam); diff --git a/web/src/pages/DataManagement/context.js b/web/src/pages/DataManagement/context.js index 04871132..9e421b40 100644 --- a/web/src/pages/DataManagement/context.js +++ b/web/src/pages/DataManagement/context.js @@ -1,79 +1,85 @@ -import {AutocompleteService} from '../../components/kibana/data/public/autocomplete'; -import {FilterManager} from '../../components/kibana/data/public/query/filter_manager/filter_manager'; -import {QueryStringManager} from '../../components/kibana/data/public/query/query_string/query_string_manager'; -import {Timefilter, TimeHistory} from '../../components/kibana/data/public/query/timefilter'; -import { useState, useEffect, createContext } from 'react'; -import { Subscription } from 'rxjs'; -import {buildEsQuery} from '../../components/kibana/data/common/es_query/es_query/build_es_query'; -import {getCalculateAutoTimeExpression} from '../../components/kibana/data/common/search/aggs/utils/calculate_auto_time_expression'; -import {intervalOptions} from '../../components/kibana/data/common/search/aggs/buckets/_interval_options'; -import {TimeBuckets} from '../../components/kibana/data/common/search/aggs/buckets/lib/time_buckets/time_buckets'; -import moment from 'moment'; +import { AutocompleteService } from "../../components/kibana/data/public/autocomplete"; +import { FilterManager } from "../../components/kibana/data/public/query/filter_manager/filter_manager"; +import { QueryStringManager } from "../../components/kibana/data/public/query/query_string/query_string_manager"; +import { + Timefilter, + TimeHistory, +} from "../../components/kibana/data/public/query/timefilter"; +import { useState, useEffect, createContext } from "react"; +import { Subscription } from "rxjs"; +import { buildEsQuery } from "../../components/kibana/data/common/es_query/es_query/build_es_query"; +import { getCalculateAutoTimeExpression } from "../../components/kibana/data/common/search/aggs/utils/calculate_auto_time_expression"; +import { intervalOptions } from "../../components/kibana/data/common/search/aggs/buckets/_interval_options"; +import { TimeBuckets } from "../../components/kibana/data/common/search/aggs/buckets/lib/time_buckets/time_buckets"; +import moment from "moment"; // import { fetch } from 'umi-request'; -import {Fetch} from '../../components/kibana/core/public/http/fetch'; -import {SavedObjectsClient} from '../../components/kibana/core/public/saved_objects/saved_objects_client'; -import {getIndexPatterns, setIndexPatterns} from '../../components/kibana/data/public/services'; +import { Fetch } from "../../components/kibana/core/public/http/fetch"; +import { SavedObjectsClient } from "../../components/kibana/core/public/saved_objects/saved_objects_client"; +import { + getIndexPatterns, + setIndexPatterns, +} from "../../components/kibana/data/public/services"; import { IndexPatternsService, onRedirectNoIndexPattern, onUnsupportedTimePattern, IndexPatternsApiClient, - SavedObjectsClientPublicToCommon -} from '../../components/kibana/data/public/index_patterns'; -import {FieldFormatsRegistry,} from '../../components/kibana/data/common/field_formats'; -import {baseFormattersPublic} from '../../components/kibana/data/public/field_formats'; -import { deserializeFieldFormat } from '../../components/kibana/data/public/field_formats/utils/deserialize'; -import {ESPrefix} from '@/services/common' + SavedObjectsClientPublicToCommon, +} from "../../components/kibana/data/public/index_patterns"; +import { FieldFormatsRegistry } from "../../components/kibana/data/common/field_formats"; +import { baseFormattersPublic } from "../../components/kibana/data/public/field_formats"; +import { deserializeFieldFormat } from "../../components/kibana/data/public/field_formats/utils/deserialize"; +import { ESPrefix } from "@/services/common"; const timeBucketConfig = { - 'histogram:maxBars': 100, - 'histogram:barTarget': 50, - dateFormat: 'YYYY-MM-DD', - 'dateFormat:scaled': [ - ['', 'HH:mm:ss.SSS'], - ['PT1S', 'HH:mm:ss'], - ['PT1M', 'HH:mm'], - ['PT1H', 'YYYY-MM-DD HH:mm'], - ['P1DT', 'YYYY-MM-DD'], - ['P1YT', 'YYYY'], + "histogram:maxBars": 100, + "histogram:barTarget": 50, + dateFormat: "YYYY-MM-DD", + "dateFormat:scaled": [ + ["", "HH:mm:ss.SSS"], + ["PT1S", "HH:mm:ss"], + ["PT1M", "HH:mm"], + ["PT1H", "YYYY-MM-DD HH:mm"], + ["P1DT", "YYYY-MM-DD"], + ["P1YT", "YYYY"], ], }; const basePath = { - get:()=>{ - return ''; + get: () => { + return ""; }, - prepend: (path)=>{ + prepend: (path) => { return path; }, - remove: (url)=>{ + remove: (url) => { return url; }, - serverBasePath: '/api/', -} + serverBasePath: "/api/", +}; const http = new Fetch({ basePath, }); const savedObjects = new SavedObjectsClient(http); const savedObjectsClient = new SavedObjectsClientPublicToCommon(savedObjects); -const getFieldFormatsConfig = (key)=>{ +const getFieldFormatsConfig = (key) => { return { - ['format:defaultTypeMap']: { - "ip": { "id": "ip", "params": {} }, - "date": { "id": "date", "params": {} }, - "date_nanos": { "id": "date_nanos", "params": {}, "es": true }, - "number": { "id": "number", "params": {} }, - "boolean": { "id": "boolean", "params": {} }, - "histogram": { "id": "histogram", "params": {} }, - "_source": { "id": "_source", "params": {} }, - "_default_": { "id": "string", "params": {} } + ["format:defaultTypeMap"]: { + ip: { id: "ip", params: {} }, + date: { id: "date", params: {} }, + date_nanos: { id: "date_nanos", params: {}, es: true }, + number: { id: "number", params: {} }, + boolean: { id: "boolean", params: {} }, + histogram: { id: "histogram", params: {} }, + _source: { id: "_source", params: {} }, + _default_: { id: "string", params: {} }, }, - 'format:number:defaultPattern': '0,0.[000]', - 'format:percent:defaultPattern': '0,0.[000]%', - 'format:bytes:defaultPattern': '0,0.[0]b', - 'format:currency:defaultPattern': '($0,0.[00])', + "format:number:defaultPattern": "0,0.[000]", + "format:percent:defaultPattern": "0,0.[000]%", + "format:bytes:defaultPattern": "0,0.[0]b", + "format:currency:defaultPattern": "($0,0.[00])", }[key]; -} +}; const fieldFormats = new FieldFormatsRegistry(); fieldFormats.init( @@ -86,39 +92,36 @@ fieldFormats.init( }, }, baseFormattersPublic - ); - fieldFormats.deserialize = deserializeFieldFormat.bind( - fieldFormats - ); +); +fieldFormats.deserialize = deserializeFieldFormat.bind(fieldFormats); const indexPatternsApiClient = new IndexPatternsApiClient(http); const uiconfigs = { - ['metaFields']: ['_source', '_id', '_type', '_index'],//'_score' - defaultIndex: '', + ["metaFields"]: ["_source", "_id", "_type", "_index"], //'_score' + defaultIndex: "", }; const uiSettings = { - get: (key)=>{ - return uiconfigs[key] + get: (key) => { + return uiconfigs[key]; }, - set: (key, val)=>{ - return uiconfigs[key] = val; + set: (key, val) => { + return (uiconfigs[key] = val); }, - getAll: ()=>{ + getAll: () => { return uiconfigs; - } + }, }; const indexPatternService = new IndexPatternsService({ uiSettings, savedObjectsClient, apiClient: indexPatternsApiClient, fieldFormats, - onNotification:()=>{}, - onError:()=>{}, + onNotification: () => {}, + onError: () => {}, onUnsupportedTimePattern, onRedirectNoIndexPattern, }); - export class Storage { store; @@ -126,7 +129,7 @@ export class Storage { this.store = store; } - get = (key) => { + get = (key) => { if (!this.store) { return null; } @@ -160,33 +163,35 @@ export class Storage { }; } - const filterManager = new FilterManager(); -const storage = new Storage(localStorage); +const storage = new Storage(localStorage); const queryStringManager = new QueryStringManager(storage); const timefilterConfig = { - timeDefaults: { from: 'now-15m', to: 'now' }, + timeDefaults: { from: "now-15m", to: "now" }, refreshIntervalDefaults: { pause: true, value: 10000 }, }; const timeHistory = new TimeHistory(storage); const timefilter = new Timefilter(timefilterConfig, timeHistory); const autocomplete = new AutocompleteService(); -autocomplete.setup({autocomplete: autocomplete, http:http}, { - timefilter, -}); +autocomplete.setup( + { autocomplete: autocomplete, http: http }, + { + timefilter, + } +); -const getConfig = (key)=>{ +const getConfig = (key) => { const kvals = { - "histogram:maxBars": 100, - "histogram:barTarget": 50, - dateFormat: 'strict_date_optional_time',//'YYYY-MM-DD HH:mm:ss', - 'dateFormat:scaled': true, + "histogram:maxBars": 100, + "histogram:barTarget": 50, + dateFormat: "strict_date_optional_time", //'YYYY-MM-DD HH:mm:ss', + "dateFormat:scaled": true, }; - return kvals[key] || ''; + return kvals[key] || ""; }; -const calculateAutoTimeExpression = getCalculateAutoTimeExpression(getConfig) +const calculateAutoTimeExpression = getCalculateAutoTimeExpression(getConfig); // console.log(calculateAutoTimeExpression({ // from: timefilter.getTime().from, // to: timefilter.getTime().to, @@ -203,8 +208,7 @@ const getTimeBuckets = (interval) => { timeBuckets.setBounds(bounds); timeBuckets.setInterval(interval); return timeBuckets; //.getInterval(true); -} - +}; const defaultFiltersUpdated = () => { return (filters) => { @@ -215,7 +219,7 @@ const defaultFiltersUpdated = () => { // const [getIndexPatterns, setIndexPatterns] = createGetterSetter('IndexPatterns'); -export const getContext = ()=>{ +export const getContext = () => { return { autocomplete: autocomplete, filterManager, @@ -227,14 +231,14 @@ export const getContext = ()=>{ storage, timefilter, getEsQuery, - //calculateAutoTimeExpression, + //calculateAutoTimeExpression, getSearchParams, intervalOptions, //createAggConfigs, getTimeBuckets, fetchESRequest, services: { - savedObjects:{ + savedObjects: { client: savedObjects, savedObjectsClient, }, @@ -244,76 +248,83 @@ export const getContext = ()=>{ indexPatternService, }, http, - } -} - + }; +}; const getEsQuery = (indexPattern) => { const timeFilter = timefilter.createFilter(indexPattern); return buildEsQuery( indexPattern, queryStringManager.getQuery(), - [...filterManager.getFilters(), ...(timeFilter ? [timeFilter] : [])], - // getEsQueryConfig(getUiSettings()) + [...filterManager.getFilters(), ...(timeFilter ? [timeFilter] : [])] + // getEsQueryConfig(getUiSettings()) ); -} +}; -const getSearchParams = (indexPattern, internal, sort) =>{ +const getSearchParams = (indexPattern, internal, sort) => { // const timeExp = calculateAutoTimeExpression(timefilter.getTime()); const timeExp = getTimeBuckets(internal).getInterval(true).expression; // console.log(timeExp, internal) - let esSort = indexPattern.timeFieldName ? [{[indexPattern.timeFieldName]: {order: "desc"}}]: []; - if(sort){ - esSort = sort.reduce((sorts, s)=>{ + let esSort = indexPattern.timeFieldName + ? [{ [indexPattern.timeFieldName]: { order: "desc" } }] + : []; + if (sort) { + esSort = sort.reduce((sorts, s) => { const [sortField, sortDeriction] = s; sorts.push({ - [sortField]: {order: sortDeriction} - }) + [sortField]: { order: sortDeriction }, + }); return sorts; - }, []) + }, []); } - const isCalendarInterval = timeExp.includes('w') || timeExp.includes('d') || timeExp.includes('y') || timeExp.includes('M'); + const isCalendarInterval = + timeExp.includes("w") || + timeExp.includes("d") || + timeExp.includes("y") || + timeExp.includes("M"); let aggs = { 2: { date_histogram: { - //calendar_interval: - [isCalendarInterval? 'calendar_interval' : 'fixed_interval']: timeExp, + //calendar_interval: + [isCalendarInterval ? "calendar_interval" : "fixed_interval"]: timeExp, field: indexPattern.timeFieldName, min_doc_count: 1, - time_zone: "Asia/Shanghai" - } - } + time_zone: "Asia/Shanghai", + }, + }, }; let esRequest = { index: indexPattern.index || indexPattern.title, - body:{ + body: { query: getEsQuery(indexPattern), size: 500, - - highlight:{ - pre_tags:["@highlighted-field@"], - post_tags:["@highlighted-field@"] + + highlight: { + pre_tags: ["@highlighted-field@"], + post_tags: ["@highlighted-field@"], }, - sort: esSort,// - } - } - if(indexPattern.timeFieldName){ - esRequest.body['aggs']=aggs; + sort: esSort, // + }, + }; + if (indexPattern.timeFieldName) { + esRequest.body["aggs"] = aggs; } return esRequest; -} +}; const fetchESRequest = (params, clusterID) => { return fetch(`${ESPrefix}/${clusterID}/search/ese`, { - headers:{ - 'Content-Type': 'application/json', + headers: { + "Content-Type": "application/json", }, - method: 'POST', + method: "POST", body: JSON.stringify(params), - }).then( res => { - return res.json() - }).then(resJson=>{ - return resJson; }) -} \ No newline at end of file + .then((res) => { + return res.json(); + }) + .then((resJson) => { + return resJson; + }); +};