From 30968c01c9a035cf95a9e5875baa6c254947adac Mon Sep 17 00:00:00 2001 From: Eric Wei Date: Tue, 7 Mar 2023 15:38:40 -0800 Subject: [PATCH 01/73] use jdbc format Signed-off-by: Eric Wei --- .../visualizations/charts/bar/bar.tsx | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/public/components/visualizations/charts/bar/bar.tsx b/public/components/visualizations/charts/bar/bar.tsx index 720063d318..e26fd115ef 100644 --- a/public/components/visualizations/charts/bar/bar.tsx +++ b/public/components/visualizations/charts/bar/bar.tsx @@ -4,7 +4,7 @@ */ import React, { useMemo } from 'react'; -import { isEmpty, last } from 'lodash'; +import { last } from 'lodash'; import { AGGREGATIONS, BREAKDOWNS, @@ -14,7 +14,6 @@ import { import { BarOrientation, FILLOPACITY_DIV_FACTOR, - LONG_CHART_COLOR, PLOTLY_COLOR, THRESHOLD_LINE_OPACITY, THRESHOLD_LINE_WIDTH, @@ -23,7 +22,6 @@ import { import { IVisualizationContainerProps } from '../../../../../common/types/explorer'; import { AvailabilityUnitType } from '../../../event_analytics/explorer/visualizations/config_panel/config_panes/config_controls/config_availability'; import { ThresholdUnitType } from '../../../event_analytics/explorer/visualizations/config_panel/config_panes/config_controls/config_thresholds'; -import { VisCanvassPlaceholder } from '../../../event_analytics/explorer/visualizations/shared_components'; import { hexToRgb } from '../../../event_analytics/utils/utils'; import { Plt } from '../../plotly/plot'; import { transformPreprocessedDataToTraces, preprocessJsonData } from '../shared/common'; @@ -31,10 +29,8 @@ import { transformPreprocessedDataToTraces, preprocessJsonData } from '../shared export const Bar = ({ visualizations, layout, config }: any) => { const { data: { - rawVizData: { - data: queriedVizData, - jsonData, - metadata: { fields }, + explorer: { + explorerData: { jsonData }, }, userConfigs: { dataConfig: { @@ -67,8 +63,6 @@ export const Bar = ({ visualizations, layout, config }: any) => { }, }: IVisualizationContainerProps = visualizations; - const lastIndex = fields.length - 1; - /** * determine stylings */ @@ -93,10 +87,6 @@ export const Bar = ({ visualizations, layout, config }: any) => { (colorTheme.length > 0 && colorTheme.find((colorSelected) => colorSelected.name.label === field)?.color) || PLOTLY_COLOR[index % PLOTLY_COLOR.length]; - // If chart has length of result buckets < 16 - // then use the LONG_CHART_COLOR for all the bars in the chart - const plotlyColorway = - queriedVizData[fields[lastIndex].name].length < 16 ? PLOTLY_COLOR : [LONG_CHART_COLOR]; const addStylesToTraces = (traces, traceStyles) => { const { @@ -150,7 +140,7 @@ export const Bar = ({ visualizations, layout, config }: any) => { const mergedLayout = useMemo(() => { return { - colorway: plotlyColorway, + colorway: PLOTLY_COLOR, ...layout, title: panelOptions.title || layoutConfig.layout?.title || '', barmode: chartStyles.mode || visualizations.vis.mode, From 31ad03ac2624dd97cd5fbc28bd0f4d20b7ae663c Mon Sep 17 00:00:00 2001 From: Eric Wei Date: Tue, 7 Mar 2023 15:44:23 -0800 Subject: [PATCH 02/73] use jdbc format for line Signed-off-by: Eric Wei --- public/components/visualizations/charts/lines/line.tsx | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/public/components/visualizations/charts/lines/line.tsx b/public/components/visualizations/charts/lines/line.tsx index bc06b2e984..94b348c8d9 100644 --- a/public/components/visualizations/charts/lines/line.tsx +++ b/public/components/visualizations/charts/lines/line.tsx @@ -3,7 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { isEmpty, last } from 'lodash'; +import { last } from 'lodash'; import React, { useMemo } from 'react'; import { AGGREGATIONS, GROUPBY } from '../../../../../common/constants/explorer'; import { @@ -17,7 +17,6 @@ import { IVisualizationContainerProps } from '../../../../../common/types/explor import { hexToRgb } from '../../../../components/event_analytics/utils/utils'; import { AvailabilityUnitType } from '../../../event_analytics/explorer/visualizations/config_panel/config_panes/config_controls/config_availability'; import { ThresholdUnitType } from '../../../event_analytics/explorer/visualizations/config_panel/config_panes/config_controls/config_thresholds'; -import { VisCanvassPlaceholder } from '../../../event_analytics/explorer/visualizations/shared_components'; import { Plt } from '../../plotly/plot'; import { transformPreprocessedDataToTraces, preprocessJsonData } from '../shared/common'; @@ -36,10 +35,8 @@ export const Line = ({ visualizations, layout, config }: any) => { const { data: { - rawVizData: { - data: queriedVizData, - jsonData, - metadata: { fields }, + explorer: { + explorerData: { jsonData }, }, userConfigs: { dataConfig: { From eddeb8d5a0b972bb6d880a4759106182acbb8d61 Mon Sep 17 00:00:00 2001 From: Eric Wei Date: Thu, 9 Mar 2023 13:47:17 -0800 Subject: [PATCH 03/73] use josn for pie and add changes for related rendering flows Signed-off-by: Eric Wei --- common/types/explorer.ts | 5 + .../data_configurations_panel.tsx | 6 +- .../hooks/use_render_visualizations.ts | 33 ++--- .../visualizations/charts/bar/bar.tsx | 12 +- .../visualizations/charts/lines/line.tsx | 10 +- .../visualizations/charts/pie/pie.tsx | 114 ++++++------------ .../visualizations/charts/shared/common.ts | 43 ++++--- 7 files changed, 104 insertions(+), 119 deletions(-) diff --git a/common/types/explorer.ts b/common/types/explorer.ts index ab378016f3..31c7a85850 100644 --- a/common/types/explorer.ts +++ b/common/types/explorer.ts @@ -385,3 +385,8 @@ export interface VisualizationState { visConfMetadata: ConfigList; visMeta: VisMeta; } + +export interface VisSpecificMetaData { + x_coordinate: string; + y_coordinate: string; +} diff --git a/public/components/event_analytics/explorer/visualizations/config_panel/config_panes/config_controls/data_configurations_panel.tsx b/public/components/event_analytics/explorer/visualizations/config_panel/config_panes/config_controls/data_configurations_panel.tsx index b8ac5343d5..e5374811ed 100644 --- a/public/components/event_analytics/explorer/visualizations/config_panel/config_panes/config_controls/data_configurations_panel.tsx +++ b/public/components/event_analytics/explorer/visualizations/config_panel/config_panes/config_controls/data_configurations_panel.tsx @@ -47,7 +47,6 @@ import { import { TabContext, useRenderVisualization } from '../../../../../hooks'; import { DataConfigItemClickPanel } from '../config_controls/data_config_item_click_panel'; import { DataConfigPanelFields } from '../config_controls/data_config_panel_fields'; -import { ButtonGroupItem } from './config_button_group'; import { composeFinalQuery } from '../../../../../../../../common/utils'; const initialDimensionEntry = { @@ -285,9 +284,9 @@ export const DataConfigPanelItem = ({ handleQueryChange(newQueryString); getVisualizations({ query: nextQueryState[FINAL_QUERY], - callback: (res) => { + successCallback: (res) => { updateVisUIState({ - visData: res, + visData: { ...res }, queryState: nextQueryState, visConfMetadata: { ...configList, @@ -297,6 +296,7 @@ export const DataConfigPanelItem = ({ }, }); }, + errorCallback: (err) => {}, }); }, [configList, query, visualizations]); diff --git a/public/components/event_analytics/hooks/use_render_visualizations.ts b/public/components/event_analytics/hooks/use_render_visualizations.ts index 09aec41461..bd870d1b45 100644 --- a/public/components/event_analytics/hooks/use_render_visualizations.ts +++ b/public/components/event_analytics/hooks/use_render_visualizations.ts @@ -6,15 +6,15 @@ import { batch, useDispatch } from 'react-redux'; import { VisualizationState } from 'common/types/explorer'; import { updateFields, sortFields } from '../redux/slices/field_slice'; -import { render as renderExplorerVis } from '../redux/slices/visualization_slice'; import { fetchSuccess } from '../redux/slices/query_result_slice'; import { QUERIED_FIELDS, SELECTED_FIELDS } from '../../../../common/constants/explorer'; import { change as changeVizConfig } from '../redux/slices/viualization_config_slice'; import { changeQuery } from '../redux/slices/query_slice'; -export interface IVisualizationParams { +export interface IVisFetchParams { query: string; - callback: (res: any) => void | null; + successCallback: (res: any) => any; + errorCallback: (err: any) => any; } export const useRenderVisualization = ({ pplService, requestParams }) => { @@ -42,22 +42,15 @@ export const useRenderVisualization = ({ pplService, requestParams }) => { }); }; - const getVisualizations = ({ query, callback }: IVisualizationParams) => { + const getVisualizations = ({ query, successCallback, errorCallback }: IVisFetchParams) => { fetchVisualizations( - { - query, - }, - 'viz', + { query }, + 'jdbc', (res: any) => { - if (callback) callback(res); + successCallback(res); }, (error: any) => { - dispatch( - renderExplorerVis({ - tabId: requestParams.tabId, - data: error.body, - }) - ); + errorCallback(error); } ); }; @@ -77,20 +70,12 @@ export const useRenderVisualization = ({ pplService, requestParams }) => { }) ); - // explorerVisualization - dispatch( - renderExplorerVis({ - tabId: requestParams.tabId, - data: visData, - }) - ); - // queryResults dispatch( fetchSuccess({ tabId: requestParams.tabId, data: { - jsonData: visData?.jsonData || {}, + ...visData, }, }) ); diff --git a/public/components/visualizations/charts/bar/bar.tsx b/public/components/visualizations/charts/bar/bar.tsx index e26fd115ef..10c6a6f7e3 100644 --- a/public/components/visualizations/charts/bar/bar.tsx +++ b/public/components/visualizations/charts/bar/bar.tsx @@ -117,7 +117,7 @@ export const Bar = ({ visualizations, layout, config }: any) => { }; let bars = useMemo(() => { - const visConfig = { + const visPanelConfig = { dimensions, series, breakdowns, @@ -131,9 +131,17 @@ export const Bar = ({ visualizations, layout, config }: any) => { tooltipText, lineWidth, }; + const barSpecficMetaData = { + x_coordinate: 'x', + y_coordinate: 'y', + }; return addStylesToTraces( - transformPreprocessedDataToTraces(preprocessJsonData(jsonData, visConfig), visConfig), + transformPreprocessedDataToTraces( + preprocessJsonData(jsonData, visPanelConfig), + visPanelConfig, + barSpecficMetaData + ), { ...traceStyles } ); }, [chartStyles, jsonData, dimensions, series, breakdowns, span, tooltipOptions]); diff --git a/public/components/visualizations/charts/lines/line.tsx b/public/components/visualizations/charts/lines/line.tsx index 94b348c8d9..9c3e3041f9 100644 --- a/public/components/visualizations/charts/lines/line.tsx +++ b/public/components/visualizations/charts/lines/line.tsx @@ -137,9 +137,17 @@ export const Line = ({ visualizations, layout, config }: any) => { lineWidth, markerSize, }; + const lineSpecficMetaData = { + x_coordinate: 'x', + y_coordinate: 'y', + }; return addStylesToTraces( - transformPreprocessedDataToTraces(preprocessJsonData(jsonData, visConfig), visConfig), + transformPreprocessedDataToTraces( + preprocessJsonData(jsonData, visConfig), + visConfig, + lineSpecficMetaData + ), traceStyles ); }, [chartStyles, jsonData, dimensions, series, span, breakdowns, panelOptions, tooltipOptions]); diff --git a/public/components/visualizations/charts/pie/pie.tsx b/public/components/visualizations/charts/pie/pie.tsx index 3b8fb2db13..eefdef4767 100644 --- a/public/components/visualizations/charts/pie/pie.tsx +++ b/public/components/visualizations/charts/pie/pie.tsx @@ -3,9 +3,8 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { find, forEach } from 'lodash'; import React, { useMemo } from 'react'; -import { DEFAULT_PALETTE, HEX_CONTRAST_COLOR } from '../../../../../common/constants/colors'; +import { DEFAULT_PALETTE } from '../../../../../common/constants/colors'; import { AGGREGATIONS, GROUPBY, @@ -13,24 +12,17 @@ import { PIE_YAXIS_GAP, PLOTLY_PIE_COLUMN_NUMBER, } from '../../../../../common/constants/explorer'; -import { PLOT_MARGIN } from '../../../../../common/constants/shared'; -import { - ConfigListEntry, - IVisualizationContainerProps, -} from '../../../../../common/types/explorer'; -import { getPropName, getTooltipHoverInfo } from '../../../event_analytics/utils/utils'; +import { PLOT_MARGIN, PLOTLY_COLOR } from '../../../../../common/constants/shared'; +import { IVisualizationContainerProps } from '../../../../../common/types/explorer'; +import { getTooltipHoverInfo } from '../../../event_analytics/utils/utils'; import { Plt } from '../../plotly/plot'; -import { removeBacktick } from '../../../../../common/utils'; +import { transformPreprocessedDataToTraces, preprocessJsonData } from '../shared/common'; export const Pie = ({ visualizations, layout, config }: any) => { const { data: { - defaultAxes, - indexFields, - query, - rawVizData: { - data: queriedVizData, - metadata: { fields }, + explorer: { + explorerData: { jsonData: fieldValueMapList }, }, userConfigs: { dataConfig: { @@ -45,7 +37,7 @@ export const Pie = ({ visualizations, layout, config }: any) => { layoutConfig = {}, } = {}, } = {}, - vis: { mode, icontype, showlegend, legendSize, labelSize, legendposition }, + vis: { mode, showlegend, legendSize, labelSize, legendposition }, }: IVisualizationContainerProps = visualizations; const type = chartStyles.mode || mode; @@ -54,65 +46,37 @@ export const Pie = ({ visualizations, layout, config }: any) => { const chartLegendSize = legend.size || legendSize; const chartLabelSize = chartStyles.labelSize || labelSize; const title = panelOptions.title || layoutConfig.layout?.title || ''; - const timestampField = find(fields, (field) => field.type === 'timestamp'); - - const backtickRemovedVisData = {}; - forEach(queriedVizData, (value, key) => { - backtickRemovedVisData[removeBacktick(key)] = value; - }); - - /** - * determine x axis - */ - let xaxes: ConfigListEntry[] = []; - if (span && span.time_field && timestampField) { - xaxes = [timestampField, ...dimensions]; - } else { - xaxes = dimensions; - } - - const invertHex = (hex: string) => - (Number(`0x1${hex}`) ^ HEX_CONTRAST_COLOR).toString(16).substr(1).toUpperCase(); // eslint-disable-line no-bitwise - const labelsOfXAxis = xaxes.reduce((prev, cur) => { - if (backtickRemovedVisData[removeBacktick(cur.name)]) { - if (prev.length === 0) return backtickRemovedVisData[removeBacktick(cur.name)].flat(); - return prev.map( - (item: string | number, index: number) => - `${item}, ${backtickRemovedVisData[removeBacktick(cur.name)][index]}` - ); - } - }, []); + const pieTreaces = useMemo(() => { + const chartConfigs = { + dimensions, + series, + breakdowns: [], // pie doesn't support breakdowns + span, + isVertical: true, + }; + const pieSpecificMetaData = { + x_coordinate: 'labels', + y_coordinate: 'values', + }; - const hexColor = invertHex(colorTheme); + return transformPreprocessedDataToTraces( + preprocessJsonData(fieldValueMapList, chartConfigs), + chartConfigs, + pieSpecificMetaData + ); + }, [chartStyles, fieldValueMapList, dimensions, series, [], span, tooltipOptions]); const pies = useMemo( () => - series.map((field: any, index: number) => { - const fieldName = getPropName(field); - const marker = - colorTheme.name !== DEFAULT_PALETTE - ? { - marker: { - colors: [ - ...Array(backtickRemovedVisData[removeBacktick(fieldName)].length).fill( - colorTheme.childColor - ), - ], - line: { - color: hexColor, - width: 1, - }, - }, - } - : undefined; + pieTreaces.map((pieTrace: any, index: number) => { return { - labels: labelsOfXAxis, - values: backtickRemovedVisData[removeBacktick(fieldName)], + labels: pieTrace.labels, + values: pieTrace.values, type: 'pie', - name: getPropName(field), + name: pieTrace.name, hole: type === 'pie' ? 0 : 0.5, - text: fieldName, + text: pieTrace.name, textinfo: 'percent', hoverinfo: getTooltipHoverInfo({ tooltipMode: tooltipOptions.tooltipMode, @@ -120,28 +84,30 @@ export const Pie = ({ visualizations, layout, config }: any) => { }), automargin: true, textposition: 'outside', - title: { text: fieldName }, + title: { text: pieTrace.name }, domain: { row: Math.floor(index / PLOTLY_PIE_COLUMN_NUMBER), column: index % PLOTLY_PIE_COLUMN_NUMBER, }, - ...marker, + marker: { + colors: [...PLOTLY_COLOR], + }, outsidetextfont: { size: chartLabelSize, }, }; }), - [series, backtickRemovedVisData, chartLabelSize, labelsOfXAxis, colorTheme] + [chartLabelSize, colorTheme] ); const mergedLayout = useMemo(() => { - const isAtleastOneFullRow = Math.floor(series.length / PLOTLY_PIE_COLUMN_NUMBER) > 0; + const isAtleastOneFullRow = Math.floor(pieTreaces.length / PLOTLY_PIE_COLUMN_NUMBER) > 0; return { grid: { xgap: PIE_XAXIS_GAP, ygap: PIE_YAXIS_GAP, - rows: Math.floor(series.length / PLOTLY_PIE_COLUMN_NUMBER) + 1, - columns: isAtleastOneFullRow ? PLOTLY_PIE_COLUMN_NUMBER : series.length, + rows: Math.floor(pieTreaces.length / PLOTLY_PIE_COLUMN_NUMBER) + 1, + columns: isAtleastOneFullRow ? PLOTLY_PIE_COLUMN_NUMBER : pieTreaces.length, pattern: 'independent', }, ...layout, @@ -168,7 +134,7 @@ export const Pie = ({ visualizations, layout, config }: any) => { yref: 'container', }, }; - }, [series, layoutConfig.layout, title, layout.legend]); + }, [layoutConfig.layout, title, layout.legend]); const mergedConfigs = useMemo( () => ({ diff --git a/public/components/visualizations/charts/shared/common.ts b/public/components/visualizations/charts/shared/common.ts index 6d782b41a3..b5a24436fb 100644 --- a/public/components/visualizations/charts/shared/common.ts +++ b/public/components/visualizations/charts/shared/common.ts @@ -3,9 +3,13 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { isEmpty, forEach } from 'lodash'; +import { isEmpty, forEach, mapKeys } from 'lodash'; import { CUSTOM_LABEL } from '../../../../../common/constants/explorer'; -import { ConfigList, DimensionSpan } from '../../../../../common/types/explorer'; +import { + ConfigList, + DimensionSpan, + VisSpecificMetaData, +} from '../../../../../common/types/explorer'; import { removeBacktick } from '../../../../../common/utils'; export const getCompleteTimespanKey = (span: DimensionSpan) => { @@ -22,30 +26,40 @@ export const getCompleteTimespanKey = (span: DimensionSpan) => { * @returns traces. */ export const transformPreprocessedDataToTraces = ( - intermediateVisData: Array, - { breakdowns, isVertical = true }: Partial + intermediateVisData: any[], + { breakdowns, isVertical = true }: Partial, + visTypeMetaData: VisSpecificMetaData ) => { const traceMap = new Map(); const hasBreakdown = !isEmpty(breakdowns); forEach(intermediateVisData, (entry) => { const traceKey = hasBreakdown ? [entry.breakdown, entry.aggName].join(',') : entry.aggName; + const xCoordinate = visTypeMetaData.x_coordinate; + const yCoordinate = visTypeMetaData.y_coordinate; + if (isEmpty(traceMap.get(traceKey))) { traceMap.set(traceKey, { - x: isVertical ? [entry.x] : [entry.value], - y: isVertical ? [entry.value] : [entry.x], + [xCoordinate]: isVertical ? [entry.x] : [entry.value], + [yCoordinate]: isVertical ? [entry.value] : [entry.x], name: hasBreakdown ? [entry.breakdown, entry.aggName].join(',') : `${traceKey}`, }); } else { const curTrace = traceMap.get(traceKey); const xaxisValue = isVertical ? entry.x : entry.value; const yaxisValue = isVertical ? entry.value : entry.x; - curTrace!.x.push(xaxisValue); - curTrace!.y.push(yaxisValue); + curTrace![xCoordinate].push(xaxisValue); + curTrace![yCoordinate].push(yaxisValue); } }); return [...traceMap.values()]; }; +export const removeBackTick = (entry: any) => { + return { + ...mapKeys(entry, (val: any, key: string) => removeBacktick(key)), + }; +}; + /** * preprocess json data to * 1. concatenate dimensions to generate one dimension @@ -56,16 +70,15 @@ export const transformPreprocessedDataToTraces = ( * @returns intermediate visualization json data */ export const preprocessJsonData = ( - visJson: Array, + jdbcFieldValueMapList: any[], { dimensions, series, breakdowns, span }: Partial ) => { const seriesFlattenedEntries = []; - forEach(visJson, (entry) => { - const backtickRemovedEntry = {}; - // remove backtick, so data in jsonData can be accessed through using field name - forEach(entry, (value, key) => { - backtickRemovedEntry[removeBacktick(key)] = value; - }); + forEach(jdbcFieldValueMapList, (entry: any) => { + const backtickRemovedEntry = { + ...removeBackTick(entry), + }; + forEach(series, (sr) => { let tabularVizData = {}; const serieKey = sr[CUSTOM_LABEL] ? sr[CUSTOM_LABEL] : `${sr.aggregation}(${sr.name})`; From d77e0d0908681194b55f4c0e16ba55ef02ffad04 Mon Sep 17 00:00:00 2001 From: Eric Wei Date: Fri, 10 Mar 2023 17:06:30 -0800 Subject: [PATCH 04/73] use jdbc for heatmap Signed-off-by: Eric Wei --- .../hooks/use_render_visualizations.ts | 16 +-- .../visualizations/charts/maps/heatmap.tsx | 108 +++++++----------- .../visualizations/visualization.tsx | 2 - 3 files changed, 48 insertions(+), 78 deletions(-) diff --git a/public/components/event_analytics/hooks/use_render_visualizations.ts b/public/components/event_analytics/hooks/use_render_visualizations.ts index bd870d1b45..13a593d599 100644 --- a/public/components/event_analytics/hooks/use_render_visualizations.ts +++ b/public/components/event_analytics/hooks/use_render_visualizations.ts @@ -26,19 +26,11 @@ export const useRenderVisualization = ({ pplService, requestParams }) => { errorHandler: (error: any) => void ) => { await pplService - .fetch( - { - query, - format, - }, - (error) => { - errorHandler(error); - } - ) + .fetch({ query, format }, (error) => { + errorHandler(error); + }) .then((res: any) => { - if (res && res.status === 200) { - successHandler(res); - } + successHandler(res); }); }; diff --git a/public/components/visualizations/charts/maps/heatmap.tsx b/public/components/visualizations/charts/maps/heatmap.tsx index ad08ac26f1..9bca96d8fb 100644 --- a/public/components/visualizations/charts/maps/heatmap.tsx +++ b/public/components/visualizations/charts/maps/heatmap.tsx @@ -4,7 +4,7 @@ */ import React, { useMemo } from 'react'; import { colorPalette } from '@elastic/eui'; -import { forEach, has, isEmpty, isEqual, uniq } from 'lodash'; +import { forEach, isEmpty, isEqual, map } from 'lodash'; import Plotly from 'plotly.js-dist'; import { HEATMAP_PALETTE_COLOR, @@ -22,15 +22,17 @@ import { VisCanvassPlaceholder } from '../../../event_analytics/explorer/visuali import { Plt } from '../../plotly/plot'; import { AGGREGATIONS, GROUPBY } from '../../../../../common/constants/explorer'; import { PLOT_MARGIN } from '../../../../../common/constants/shared'; -import { getCompleteTimespanKey } from '../../../visualizations/charts/shared/common'; +import { + getCompleteTimespanKey, + removeBackTick, +} from '../../../visualizations/charts/shared/common'; import { removeBacktick } from '../../../../../common/utils'; export const HeatMap = ({ visualizations, layout, config }: any) => { const { data: { - rawVizData: { - data: queriedVizData, - metadata: { fields }, + explorer: { + explorerData: { jsonData: fieldValueMapList }, }, userConfigs: { dataConfig: { @@ -48,33 +50,14 @@ export const HeatMap = ({ visualizations, layout, config }: any) => { vis: { icontype }, }: IVisualizationContainerProps = visualizations; - const backtickRemovedVisData = {}; - forEach(queriedVizData, (value, key) => { - backtickRemovedVisData[removeBacktick(key)] = value; - }); - const combinedDemensions = [ ...(!isEmpty(span) ? [getCompleteTimespanKey(span)] : []), ...dimensions, ]; - if (!isEqual(combinedDemensions.length, 2) || !isEqual(series.length, 1)) - return ; + const xaxisField = { ...combinedDemensions[0] }; const yaxisField = { ...combinedDemensions[1] }; const zMetrics = { ...series[0] }; - if ( - isEmpty(xaxisField) || - isEmpty(yaxisField) || - isEmpty(zMetrics) || - isEmpty(backtickRemovedVisData[removeBacktick(xaxisField.label)]) || - isEmpty(backtickRemovedVisData[removeBacktick(yaxisField.label)]) - ) - return ; - - const uniqueYaxis = uniq(backtickRemovedVisData[removeBacktick(yaxisField.label)]); - const uniqueXaxis = uniq(backtickRemovedVisData[removeBacktick(xaxisField.label)]); - const uniqueYaxisLength = uniqueYaxis.length; - const uniqueXaxisLength = uniqueXaxis.length; const tooltipMode = tooltipOptions.tooltipMode !== undefined ? tooltipOptions.tooltipMode : 'show'; const tooltipText = tooltipOptions.tooltipText !== undefined ? tooltipOptions.tooltipText : 'all'; @@ -97,51 +80,48 @@ export const HeatMap = ({ visualizations, layout, config }: any) => { }); } - const calculatedHeapMapZaxis: Plotly.Data[] = useMemo(() => { - const heapMapZaxis = []; - const buckets = {}; + const heatMapAxes = useMemo(() => { + const dmaps = new Map(); // key: values of 1st and 2nd group-by fields combined + const uniqueXaxisVals = new Set(); // any value for a field + const uniqueYaxisVals = new Set(); // any value for a field + const zKey = getPropName(zMetrics); - // maps bukcets to metrics - for (let i = 0; i < backtickRemovedVisData[removeBacktick(xaxisField.label)].length; i++) { - buckets[`${backtickRemovedVisData[removeBacktick(xaxisField.label)][i]},${backtickRemovedVisData[removeBacktick(yaxisField.label)][i]}`] = - backtickRemovedVisData[getPropName(zMetrics)][i]; - } + forEach(fieldValueMapList, (entry) => { + const backtickRemovedEntry = removeBackTick(entry); + const xKey = removeBacktick(xaxisField.label); + const yKey = removeBacktick(yaxisField.label); - // initialize empty 2 dimensional array, inner loop for each xaxis field, outer loop for yaxis - for (let i = 0; i < uniqueYaxisLength; i++) { - const innerBuckets = []; - for (let j = 0; j < uniqueXaxisLength; j++) { - innerBuckets.push(null); - } - heapMapZaxis.push(innerBuckets); - } + // collect unique values from all values of 1st and 2nd group-by fields + // for later composing 2 dimensional heatmap x, y axes + uniqueXaxisVals.add(backtickRemovedEntry[xKey]); + uniqueYaxisVals.add(backtickRemovedEntry[yKey]); - // fill in each bucket - for (let i = 0; i < uniqueYaxisLength; i++) { - for (let j = 0; j < uniqueXaxisLength; j++) { - if (has(buckets, `${uniqueXaxis[j]},${uniqueYaxis[i]}`)) { - heapMapZaxis[i][j] = buckets[`${uniqueXaxis[j]},${uniqueYaxis[i]}`]; - } - } - } + // establish 1st,2nd -> data entry mapping for later filling in + // corresponding aggregations to 2 dimensional heatmap zaxis + dmaps.set( + `${backtickRemovedEntry[xKey]},${backtickRemovedEntry[yKey]}`, + backtickRemovedEntry + ); + }); + + const xAxis = [...uniqueXaxisVals]; + const yAxis = [...uniqueYaxisVals]; + const zaxis = map(yAxis, (yvalue) => { + return map(xAxis, (xvalue) => { + return dmaps.get(`${xvalue},${yvalue}`) ? dmaps.get(`${xvalue},${yvalue}`)[zKey] : null; + }); + }); - return heapMapZaxis; - }, [ - backtickRemovedVisData, - uniqueYaxis, - uniqueXaxis, - uniqueYaxisLength, - uniqueXaxisLength, - xaxisField, - yaxisField, - zMetrics, - ]); + return { + z: zaxis, + x: xAxis, + y: yAxis, + }; + }, [fieldValueMapList]); - const heapMapData = [ + const heapMapData: Plotly.Data[] = [ { - z: calculatedHeapMapZaxis, - x: uniqueXaxis, - y: uniqueYaxis, + ...heatMapAxes, hoverinfo: tooltipMode === 'hidden' ? 'none' : tooltipText, colorscale: colorField.name === SINGLE_COLOR_PALETTE ? traceColor : colorField.name, type: 'heatmap', diff --git a/public/components/visualizations/visualization.tsx b/public/components/visualizations/visualization.tsx index f1107908b9..05e8733bab 100644 --- a/public/components/visualizations/visualization.tsx +++ b/public/components/visualizations/visualization.tsx @@ -30,8 +30,6 @@ export const Visualization = ({ // Markdown, it does not depend on if there is data if (vis.id === VIS_CHART_TYPES.Text) return [true, '']; - if (isEmpty(queriedVizData)) return [false, VISUALIZATION_ERROR.NO_DATA]; - if (isEmpty(series)) return [false, VISUALIZATION_ERROR.INVALID_DATA]; // series is required to any visualization type // bars, pie From bcbd556694e8980bed0e95fa2c238929a5adb693 Mon Sep 17 00:00:00 2001 From: Eric Wei Date: Sun, 12 Mar 2023 23:09:28 -0700 Subject: [PATCH 05/73] change viz to jdbc elsewhere and make related changes to use jdbc data Signed-off-by: Eric Wei --- common/constants/shared.ts | 4 +-- .../application_analytics/helpers/utils.tsx | 2 +- .../custom_panels/helpers/utils.tsx | 8 ++--- .../event_analytics/explorer/explorer.tsx | 33 +++++++------------ .../explorer/sidebar/field_insights.tsx | 26 +++++++-------- .../workspace_panel/workspace_panel.tsx | 2 +- .../hooks/use_fetch_visualizations.ts | 22 +++++++------ .../charts/data_table/data_table.tsx | 13 ++++---- .../visualizations/visualization.tsx | 5 --- 9 files changed, 51 insertions(+), 64 deletions(-) diff --git a/common/constants/shared.ts b/common/constants/shared.ts index 5a48e6b962..f1e936e123 100644 --- a/common/constants/shared.ts +++ b/common/constants/shared.ts @@ -160,8 +160,8 @@ export interface DefaultChartStylesProps { export const DEFAULT_CHART_STYLES: DefaultChartStylesProps = { DefaultModeLine: 'lines', Interpolation: 'spline', - LineWidth: 2, - FillOpacity: 70, + LineWidth: 0, + FillOpacity: 100, MarkerSize: 5, ShowLegend: 'show', LegendPosition: 'v', diff --git a/public/components/application_analytics/helpers/utils.tsx b/public/components/application_analytics/helpers/utils.tsx index a9df996b16..42d38f37ee 100644 --- a/public/components/application_analytics/helpers/utils.tsx +++ b/public/components/application_analytics/helpers/utils.tsx @@ -237,7 +237,7 @@ export const calculateAvailability = async ( await pplService .fetch({ query: finalQuery, - format: 'viz', + format: 'jdbc', }) .then((res) => { const stat = res.metadata.fields.filter( diff --git a/public/components/custom_panels/helpers/utils.tsx b/public/components/custom_panels/helpers/utils.tsx index fc6f923b1f..06f58d084d 100644 --- a/public/components/custom_panels/helpers/utils.tsx +++ b/public/components/custom_panels/helpers/utils.tsx @@ -145,7 +145,7 @@ const pplServiceRequestor = async ( setIsError: React.Dispatch> ) => { await pplService - .fetch({ query: finalQuery, format: 'viz' }) + .fetch({ query: finalQuery, format: 'jdbc' }) .then((res) => { if (res === undefined) setIsError({ errorMessage: 'Please check the validity of PPL Filter' }); @@ -206,7 +206,7 @@ export const getQueryResponse = ( finalQuery = queryAccumulator(query, timestampField, startTime, endTime, filterQuery); } catch (error) { const errorMessage = 'Issue in building final query'; - setIsError({ errorMessage: errorMessage }); + setIsError({ errorMessage }); console.error(errorMessage, error); setIsLoading(false); return; @@ -371,7 +371,7 @@ export const onTimeChange = ( setStart: React.Dispatch>, setEnd: React.Dispatch> ) => { - let recentlyUsedRangeObject = recentlyUsedRanges.filter((recentlyUsedRange) => { + const recentlyUsedRangeObject = recentlyUsedRanges.filter((recentlyUsedRange) => { const isDuplicate = recentlyUsedRange.start === start && recentlyUsedRange.end === end; return !isDuplicate; }); @@ -479,7 +479,7 @@ export const displayVisualization = (metaData: any, data: any, type: string) => query: { rawQuery: metaData.query }, indexFields: {}, userConfigs: mixedUserConfigs, - explorer: { explorerData: data, explorerFields: data.metadata.fields }, + explorer: { explorerData: data, explorerFields: data.schema }, })} /> ); diff --git a/public/components/event_analytics/explorer/explorer.tsx b/public/components/event_analytics/explorer/explorer.tsx index 0808a1787e..8c6ec2ed3c 100644 --- a/public/components/event_analytics/explorer/explorer.tsx +++ b/public/components/event_analytics/explorer/explorer.tsx @@ -426,25 +426,19 @@ export const Explorer = ({ } }); - // search - if (finalQuery.match(PPL_STATS_REGEX)) { - getVisualizations(); - getAvailableFields(`search source=${curIndex}`); + if (!selectedIntervalRef.current || selectedIntervalRef.current.text === 'Auto') { + findAutoInterval(startingTime, endingTime); + } + if (isLiveTailOnRef.current) { + getLiveTail(undefined, getErrorHandler('Error fetching events')); } else { - if (!selectedIntervalRef.current || selectedIntervalRef.current.text === 'Auto') { - findAutoInterval(startingTime, endingTime); - } - if (isLiveTailOnRef.current) { - getLiveTail(undefined, getErrorHandler('Error fetching events')); - } else { - getEvents(undefined, getErrorHandler('Error fetching events')); - } - getCountVisualizations(selectedIntervalRef.current!.value.replace(/^auto_/, '')); + getEvents(undefined, getErrorHandler('Error fetching events')); + } + getCountVisualizations(selectedIntervalRef.current!.value.replace(/^auto_/, '')); - // to fetch patterns data on current query - if (!finalQuery.match(PATTERNS_REGEX)) { - getPatterns(selectedIntervalRef.current!.value.replace(/^auto_/, '')); - } + // to fetch patterns data on current query + if (!finalQuery.match(PATTERNS_REGEX)) { + getPatterns(selectedIntervalRef.current!.value.replace(/^auto_/, '')); } // for comparing usage if for the same tab, user changed index from one to another @@ -1081,10 +1075,7 @@ export const Explorer = ({ // update custom panel - query } } else if (isEqual(selectedContentTabId, TAB_CHART_ID)) { - if ( - (isEmpty(currQuery![RAW_QUERY]) && isEmpty(appBaseQuery)) || - isEmpty(explorerVisualizations) - ) { + if (isEmpty(currQuery![RAW_QUERY]) && isEmpty(appBaseQuery)) { setToast(`There is no query or(and) visualization to save`, 'danger'); return; } diff --git a/public/components/event_analytics/explorer/sidebar/field_insights.tsx b/public/components/event_analytics/explorer/sidebar/field_insights.tsx index b9414ba708..1b1fdcae62 100644 --- a/public/components/event_analytics/explorer/sidebar/field_insights.tsx +++ b/public/components/event_analytics/explorer/sidebar/field_insights.tsx @@ -33,19 +33,19 @@ export const FieldInsights = ({ field, query }: any) => { id: 'average', name: 'Average overtime', query: `source = ${index} | stats avg(${field.name})`, - format: 'viz', + format: 'jdbc', }, { id: 'maximum', name: 'Maximum overtime', query: `source = ${index} | stats max(${field.name})`, - format: 'viz', + format: 'jdbc', }, { id: 'minimum', name: 'Minimum overtime', query: `source = ${index} | stats min(${field.name})`, - format: 'viz', + format: 'jdbc', }, ]; const NUMERICAL_TYPES = ['short', 'integer', 'long', 'float', 'double']; @@ -58,7 +58,7 @@ export const FieldInsights = ({ field, query }: any) => { id: 'stats', name: 'Stats', query: `source = ${index} | stats avg(${field.name}), max(${field.name}), min(${field.name})`, - format: 'viz', + format: 'jdbc', }, ]; @@ -80,20 +80,20 @@ export const FieldInsights = ({ field, query }: any) => { fetchData(requests) .then((res) => { // numerical field - generalReports.map((report, index) => { - if (!res[index]?.jsonData) return; + generalReports.map((report, idx) => { + if (!res[idx]?.jsonData) return; setReportContent((staleState) => { return { ...staleState, - [report.id]: res[index]?.jsonData || {}, + [report.id]: res[idx]?.jsonData || {}, }; }); }); if (res.length > 2) { const statsRes = last(res); if (!statsRes?.metadata) return; - numericalOnlyReports.map((rep, index) => { - const fieldName = statsRes.metadata?.fields[index]?.name; + numericalOnlyReports.map((rep, idx) => { + const fieldName = statsRes.metadata?.fields[idx]?.name; setReportContent((staleState) => { return { ...staleState, @@ -103,14 +103,14 @@ export const FieldInsights = ({ field, query }: any) => { }); } }) - .catch((error) => console.error(error)); + .catch((error) => {}); }, []); - const getInsights = async (query: string) => { + const getInsights = async (queryStr: string) => { try { - return await pplService.fetch(query); + return await pplService.fetch(queryStr); } catch (error) { - console.error(error); + // to-do, for now just a placeholder to bypass linting } }; diff --git a/public/components/event_analytics/explorer/visualizations/workspace_panel/workspace_panel.tsx b/public/components/event_analytics/explorer/visualizations/workspace_panel/workspace_panel.tsx index a5fdd3f001..6beea57c10 100644 --- a/public/components/event_analytics/explorer/visualizations/workspace_panel/workspace_panel.tsx +++ b/public/components/event_analytics/explorer/visualizations/workspace_panel/workspace_panel.tsx @@ -31,7 +31,7 @@ export function WorkspacePanel({ visualizations }: IWorkSpacePanel) { className="ws__visCanvasControl--switch" label="Table view" type="button" - disabled={isEmpty(visualizations?.data?.rawVizData)} + disabled={isEmpty(visualizations?.data?.explorer?.explorerData)} checked={isTableViewOn} onChange={() => { setIsTableViewOn((staleState) => !staleState); diff --git a/public/components/event_analytics/hooks/use_fetch_visualizations.ts b/public/components/event_analytics/hooks/use_fetch_visualizations.ts index 1586bb7688..8ef331d64c 100644 --- a/public/components/event_analytics/hooks/use_fetch_visualizations.ts +++ b/public/components/event_analytics/hooks/use_fetch_visualizations.ts @@ -8,7 +8,6 @@ import { batch, useDispatch, useSelector } from 'react-redux'; import { FINAL_QUERY, QUERIED_FIELDS, - RAW_QUERY, SELECTED_FIELDS, SELECTED_TIMESTAMP, } from '../../../../common/constants/explorer'; @@ -18,7 +17,7 @@ import { render as renderExplorerVis } from '../redux/slices/visualization_slice import { updateFields, sortFields } from '../redux/slices/field_slice'; import PPLService from '../../../services/requests/ppl'; import { fetchSuccess } from '../redux/slices/query_result_slice'; -import { setPatterns, reset as patternsReset } from '../redux/slices/patterns_slice'; +import { reset as patternsReset } from '../redux/slices/patterns_slice'; interface IFetchVisualizationsParams { pplService: PPLService; @@ -44,19 +43,22 @@ export const useFetchVisualizations = ({ setIsVisLoading(true); await pplService - .fetch({ - query, - format, - }, (error) => { - errorHandler(error); - setIsVisLoading(false); - }) + .fetch( + { + query, + format, + }, + (error) => { + errorHandler(error); + setIsVisLoading(false); + } + ) .then((res: any) => { if (res && res.status === 200) { successHandler(res); } setIsVisLoading(false); - }) + }); }; const getCountVisualizations = (interval: string) => { diff --git a/public/components/visualizations/charts/data_table/data_table.tsx b/public/components/visualizations/charts/data_table/data_table.tsx index 2efa8bbaf0..c340ff0d05 100644 --- a/public/components/visualizations/charts/data_table/data_table.tsx +++ b/public/components/visualizations/charts/data_table/data_table.tsx @@ -30,12 +30,11 @@ const doubleValueGetter = (params) => { export const DataTable = ({ visualizations, layout, config }: any) => { const { data: { - rawVizData: { - jsonData = [], - metadata: { fields = [] } = {}, - } = {}, + explorer: { + explorerData: { jsonData = [], schema = [] }, + }, userConfigs: { dataConfig: { chartStyles = {} } = {} } = {}, - } = {} + } = {}, }: IVisualizationContainerProps = visualizations; const enablePagination = @@ -72,7 +71,7 @@ export const DataTable = ({ visualizations, layout, config }: any) => { const columns = useMemo( () => - fields.map((field: IField) => { + schema.map((field: IField) => { return { lockVisible: true, columnsMenuParams: { @@ -88,7 +87,7 @@ export const DataTable = ({ visualizations, layout, config }: any) => { }), }; }), - [fields] + [schema] ); // ag-grid-react bindings diff --git a/public/components/visualizations/visualization.tsx b/public/components/visualizations/visualization.tsx index 05e8733bab..9845788fe5 100644 --- a/public/components/visualizations/visualization.tsx +++ b/public/components/visualizations/visualization.tsx @@ -19,7 +19,6 @@ export const Visualization = ({ const isVisDataValid = (vs: IVisualizationContainerProps) => { const { data: { - rawVizData: { data: queriedVizData }, userConfigs: { dataConfig: { span = {}, [GROUPBY]: dimensions = [], [AGGREGATIONS]: series = [] } = {}, } = {}, @@ -35,10 +34,6 @@ export const Visualization = ({ // bars, pie if (dimensions.length < 1 && isEmpty(span)) return [false, VISUALIZATION_ERROR.INVALID_DATA]; - // heatmap - if (vis.id === VIS_CHART_TYPES.HeatMap && (series.length !== 1 || dimensions.length !== 2)) - return [false, VISUALIZATION_ERROR.INVALID_DATA]; - return [true, '']; }; From ed12d1f7f346611b0e5d10a20c12b84d99bf8011 Mon Sep 17 00:00:00 2001 From: Eric Wei Date: Mon, 13 Mar 2023 12:51:47 -0700 Subject: [PATCH 06/73] correct suppress naming Signed-off-by: Eric Wei --- .../integration/1_event_analytics.spec.js | 40 +++++++++---------- .cypress/integration/3_panels.spec.js | 10 ++--- .cypress/integration/7_app_analytics.spec.js | 16 ++++---- .cypress/utils/app_constants.js | 8 ++-- .cypress/utils/constants.js | 2 +- .cypress/utils/event_analytics/constants.js | 5 ++- 6 files changed, 41 insertions(+), 40 deletions(-) diff --git a/.cypress/integration/1_event_analytics.spec.js b/.cypress/integration/1_event_analytics.spec.js index 8056c32993..b8d4f87723 100644 --- a/.cypress/integration/1_event_analytics.spec.js +++ b/.cypress/integration/1_event_analytics.spec.js @@ -35,7 +35,7 @@ import { FIELD_HOST, FIELD_AGENT } from '../utils/event_analytics/constants'; -import { supressResizeObserverIssue, COMMAND_TIMEOUT_LONG } from '../utils/constants'; +import { suppressResizeObserverIssue, COMMAND_TIMEOUT_LONG } from '../utils/constants'; import { clearQuerySearchBoxText } from '../utils/event_analytics/helpers'; describe('Adding sample data and visualization', () => { @@ -90,7 +90,7 @@ describe('Open flyout for a data row to see details', () => { it('Should be able to open flyout and see data, json and traces', () => { cy.get('[data-test-subj="docTable"] tbody tr button.euiButtonIcon').first().click(); - supressResizeObserverIssue(); + suppressResizeObserverIssue(); cy.get('.observability-flyout').should('exist'); cy.get('.observability-flyout .osdDocViewer .euiTabs span.euiTab__content') .contains('Table') @@ -117,7 +117,7 @@ describe('Open flyout for a data row to see details', () => { describe('Add/delete/switch explorer top level tabs', () => { before(() => { landOnEventExplorer(); - supressResizeObserverIssue(); + suppressResizeObserverIssue(); }); it('Add a new tab', () => { @@ -138,7 +138,7 @@ describe('Add/delete/switch explorer top level tabs', () => { .find('button.euiTab') .first() .click(); - supressResizeObserverIssue(); + suppressResizeObserverIssue(); cy.get('[data-test-subj="eventExplorer__topLevelTabbing"]') .find('button.euiTab') .first() @@ -223,14 +223,14 @@ describe('Saves a query on explorer page', () => { it('Saves a visualization on visualization tab of explorer page', () => { landOnEventExplorer(); querySearch(TEST_QUERIES[1].query, TEST_QUERIES[1].dateRangeDOM); - supressResizeObserverIssue(); + suppressResizeObserverIssue(); cy.get('button[id="main-content-vis"]').contains('Visualizations').click(); cy.get('[data-test-subj="eventExplorer__saveManagementPopover"]').click(); cy.get('[data-test-subj="eventExplorer__querySaveName"]') .focus() .type(SAVE_QUERY2, { force: true }); cy.get('[data-test-subj="eventExplorer__querySaveConfirm"]').click({ force: true }); - cy.get('.euiToastHeader__title').should('contain', 'successfully'); + cy.get('.euiToastHeader__title').contains('successfully').should('exist'); landOnEventHome(); cy.get('[data-test-subj="eventHome__savedQueryTableName"]').first().contains(SAVE_QUERY2); }); @@ -245,7 +245,7 @@ describe('Saves a query on explorer page', () => { cy.wait(delay); landOnEventExplorer(); querySearch(TEST_QUERIES[1].query, TEST_QUERIES[1].dateRangeDOM); - supressResizeObserverIssue(); + suppressResizeObserverIssue(); cy.get('button[id="main-content-vis"]', { timeout: COMMAND_TIMEOUT_LONG }) .contains('Visualizations') .click(); @@ -261,7 +261,7 @@ describe('Saves a query on explorer page', () => { it('Saves a query on event tab of explorer page', () => { landOnEventExplorer(); - supressResizeObserverIssue(); + suppressResizeObserverIssue(); querySearch(TEST_QUERIES[0].query, TEST_QUERIES[0].dateRangeDOM); cy.get('.tab-title').contains('Events').click(); @@ -281,7 +281,7 @@ describe('Saves a query on explorer page', () => { it('Click on a saved query from event analytics home', () => { landOnEventExplorer(); - supressResizeObserverIssue(); + suppressResizeObserverIssue(); querySearch(TEST_QUERIES[0].query, TEST_QUERIES[0].dateRangeDOM); cy.get('.tab-title').contains('Events').click(); @@ -310,7 +310,7 @@ describe('Saves a query on explorer page', () => { describe('Override timestamp for an index', () => { it('Click override button to override default timestamp', () => { landOnEventExplorer(); - supressResizeObserverIssue(); + suppressResizeObserverIssue(); clearQuerySearchBoxText('searchAutocompleteTextArea'); cy.get('[data-test-subj="searchAutocompleteTextArea"]').type(TEST_QUERIES[2].query); cy.get('[data-test-subj="superDatePickerApplyTimeButton"]').contains('Refresh').click(); @@ -330,7 +330,7 @@ describe('Override timestamp for an index', () => { describe('Toggle sidebar fields', () => { it('Toggle fields between available and selected section', () => { landOnEventExplorer(); - supressResizeObserverIssue(); + suppressResizeObserverIssue(); querySearch(TEST_QUERIES[0].query, YEAR_TO_DATE_DOM_ID); cy.get('[data-test-subj="fieldToggle-AvgTicketPrice"]').click(); cy.get('[data-test-subj="field-AvgTicketPrice"]').should('exist'); @@ -344,7 +344,7 @@ describe('Toggle sidebar fields', () => { describe('Search fields in sidebar', () => { it('Search a field', () => { landOnEventExplorer(); - supressResizeObserverIssue(); + suppressResizeObserverIssue(); querySearch(TEST_QUERIES[0].query, YEAR_TO_DATE_DOM_ID); cy.get('[data-test-subj="eventExplorer__sidebarSearch"]').type('A'); cy.get('[data-test-subj="field-Cancelled"]').should('not.exist'); @@ -373,7 +373,7 @@ describe('Delete saved objects', () => { describe('Click to view field insights', () => { beforeEach(() => { landOnEventExplorer(); - supressResizeObserverIssue(); + suppressResizeObserverIssue(); querySearch(TEST_QUERIES[2].query, YEAR_TO_DATE_DOM_ID); }); @@ -411,7 +411,7 @@ describe('Click to view field insights', () => { describe('Switch on and off livetail', () => { it('Switch on and off in live tail', () => { landOnEventExplorer(); - supressResizeObserverIssue(); + suppressResizeObserverIssue(); cy.get('[data-test-subj="searchAutocompleteTextArea"]').type(TEST_QUERIES[1].query); cy.get('[data-test-subj=eventLiveTail]').click(); cy.get('[data-test-subj=eventLiveTail__delay10s]').click(); @@ -424,7 +424,7 @@ describe('Switch on and off livetail', () => { describe('Live tail stop automatically', () => { it('Moving to other tab should stop live tail automatically', () => { landOnEventExplorer(); - supressResizeObserverIssue(); + suppressResizeObserverIssue(); clearQuerySearchBoxText('searchAutocompleteTextArea'); cy.get('[data-test-subj="searchAutocompleteTextArea"]').type(TEST_QUERIES[1].query); cy.get('[data-test-subj=eventLiveTail]').click(); @@ -433,7 +433,7 @@ describe('Live tail stop automatically', () => { }); it('Add a new tab', () => { - supressResizeObserverIssue(); + suppressResizeObserverIssue(); cy.get('[data-test-subj="eventExplorer__topLevelTabbing"]') .find('button.euiTab') .then((lists) => { @@ -453,7 +453,7 @@ describe('Live tail stop automatically', () => { .find('button.euiTab') .first() .click(); - supressResizeObserverIssue(); + suppressResizeObserverIssue(); cy.get('[data-test-subj="eventExplorer__topLevelTabbing"]') .find('button.euiTab') @@ -474,7 +474,7 @@ describe('Live tail stop automatically', () => { const initialLength = Cypress.$(lists).length; cy.get('[data-test-subj="eventExplorer__topLevelTabbing"] button.euiTab').eq(1).click(); cy.get('button.euiTab-isSelected [data-test-subj="eventExplorer__tabClose"]').click(); - supressResizeObserverIssue(); + suppressResizeObserverIssue(); cy.get('[data-test-subj="eventExplorer__topLevelTabbing"]') .find('button.euiTab') .should('have.length', initialLength - 1); @@ -542,7 +542,7 @@ describe('Visualizing data', () => { cy.get(`input[value="${FIELD_AGENT}"]`).click(); cy.get('[data-test-subj="panelCloseBtn"]').click(); cy.get('[data-test-subj="visualizeEditorRenderButton"]').click(); - supressResizeObserverIssue(); + suppressResizeObserverIssue(); cy.get('.infolayer .legendtext').as('legandTxt'); cy.get('@legandTxt').should('contain', BAR_LEG_TEXT_1); @@ -577,7 +577,7 @@ describe('Visualizing data', () => { it('Visualize heatmap chart', () => { cy.get('[data-test-subj="comboBoxInput"]').click(); cy.get('[data-test-subj="comboBoxOptionsList "] span').contains(VIS_TYPE_HEATMAP).click(); - supressResizeObserverIssue(); + suppressResizeObserverIssue(); cy.get('g.cartesianlayer g.xy g.xaxislayer-above g.xtick text').as('legandXTxt'); cy.get('@legandXTxt').should('contain', HOST_TEXT_1); cy.get('@legandXTxt').should('contain', HOST_TEXT_3); diff --git a/.cypress/integration/3_panels.spec.js b/.cypress/integration/3_panels.spec.js index 023a4d2ae9..900472fa27 100644 --- a/.cypress/integration/3_panels.spec.js +++ b/.cypress/integration/3_panels.spec.js @@ -16,7 +16,7 @@ import { SAMPLE_VISUALIZATIONS_NAMES, } from '../utils/panel_constants'; -import { supressResizeObserverIssue } from '../utils/constants'; +import { suppressResizeObserverIssue } from '../utils/constants'; const moveToEventsHome = () => { cy.visit(`${Cypress.env('opensearchDashboards')}/app/observability-dashboards#/event_analytics/`); @@ -59,7 +59,7 @@ describe('Creating visualizations', () => { }); cy.get('.euiButton__text').contains('Refresh').trigger('mouseover').click(); cy.wait(delay); - supressResizeObserverIssue(); + suppressResizeObserverIssue(); cy.get('button[id="main-content-vis"]').contains('Visualizations').trigger('mouseover').click(); cy.wait(delay * 2); cy.get('[data-test-subj="eventExplorer__saveManagementPopover"]').trigger('mouseover').click(); @@ -80,7 +80,7 @@ describe('Creating visualizations', () => { }); cy.get('.euiButton__text').contains('Refresh').trigger('mouseover').click(); cy.wait(delay); - supressResizeObserverIssue(); + suppressResizeObserverIssue(); cy.get('button[id="main-content-vis"]').contains('Visualizations').trigger('mouseover').click(); cy.wait(delay); cy.get('[data-test-subj="eventExplorer__saveManagementPopover"]').trigger('mouseover').click(); @@ -384,7 +384,7 @@ describe('Testing a panel', () => { }); cy.get('button[data-test-subj="superDatePickerApplyTimeButton"]').click(); - supressResizeObserverIssue(); + suppressResizeObserverIssue(); cy.get('button[id="main-content-vis"]').contains('Visualizations').trigger('mouseover').click(); cy.wait(delay * 2); cy.get('[data-test-subj="eventExplorer__saveManagementPopover"]').trigger('mouseover').click(); @@ -420,7 +420,7 @@ describe('Testing a panel', () => { .contains(PPL_VISUALIZATIONS_NAMES[0]) .should('exist'); cy.get('button[aria-label="actionMenuButton"]').eq(0).trigger('mouseover').click(); - supressResizeObserverIssue(); + suppressResizeObserverIssue(); cy.get('button[data-test-subj="editVizContextMenuItem"]').click(); cy.wait(delay * 3); cy.url().should('match', new RegExp('(.*)#/event_analytics/explorer')); diff --git a/.cypress/integration/7_app_analytics.spec.js b/.cypress/integration/7_app_analytics.spec.js index 377b2d3237..e3a41a49b8 100644 --- a/.cypress/integration/7_app_analytics.spec.js +++ b/.cypress/integration/7_app_analytics.spec.js @@ -33,7 +33,7 @@ import { TYPING_DELAY, timeoutDelay } from '../utils/app_constants'; -import { supressResizeObserverIssue } from '../utils/constants'; +import { suppressResizeObserverIssue } from '../utils/constants'; describe('Creating application', () => { beforeEach(() => { @@ -233,7 +233,7 @@ describe('Viewing application', () => { cy.get('[data-test-subj="app-analytics-serviceTab"]').click(); cy.get('[data-test-subj="superDatePickerShowDatesButton"]').should('contain', 'Last 24 months'); cy.get('[data-test-subj="app-analytics-traceTab"]').click(); - supressResizeObserverIssue(); + suppressResizeObserverIssue(); cy.get('[data-test-subj="superDatePickerShowDatesButton"]').should('contain', 'Last 24 months'); cy.get('[data-test-subj="app-analytics-logTab"]').click(); cy.get('[data-test-subj="superDatePickerShowDatesButton"]').should('contain', 'Last 24 months'); @@ -262,7 +262,7 @@ describe('Viewing application', () => { cy.get('[data-test-subj="app-analytics-serviceTab"]').click(); cy.wait(delay); cy.get('.euiLink').contains('authentication').click(); - supressResizeObserverIssue(); + suppressResizeObserverIssue(); cy.get('[data-test-subj="serviceDetailFlyoutTitle"]').should('be.visible'); cy.get('[data-test-subj="serviceDetailFlyout"]').within(($flyout) => { cy.get('[data-test-subj="Number of connected servicesDescriptionList"]').should('contain', '3'); @@ -279,7 +279,7 @@ describe('Viewing application', () => { it('Opens trace detail flyout when Trace ID is clicked', () => { cy.get('[data-test-subj="app-analytics-traceTab"]').click(); - supressResizeObserverIssue(); + suppressResizeObserverIssue(); cy.wait(delay); cy.get('[title="03f9c770db5ee2f1caac0afc36db49ba"]').click(); cy.get('[data-test-subj="traceDetailFlyoutTitle"]').should('be.visible'); @@ -300,7 +300,7 @@ describe('Viewing application', () => { it('Opens span detail flyout when Span ID is clicked', () => { cy.get('[data-test-subj="app-analytics-traceTab"]').click(); - supressResizeObserverIssue(); + suppressResizeObserverIssue(); cy.wait(delay); cy.get('[data-test-subj="dataGridRowCell"]').contains('5ff3516909562c60').click(); cy.get('[data-test-subj="spanDetailFlyout"]').should('be.visible'); @@ -334,7 +334,7 @@ describe('Viewing application', () => { changeTimeTo24('months'); cy.wait(delay * 2); cy.get('[data-test-subj="main-content-visTab"]').click(); - supressResizeObserverIssue(); + suppressResizeObserverIssue(); cy.get('[data-test-subj="eventExplorer__saveManagementPopover"]').click(); cy.get('[data-test-subj="eventExplorer__querySaveName"]').click().type(visOneName); cy.wait(delay); @@ -351,7 +351,7 @@ describe('Viewing application', () => { cy.get('[data-test-subj="app-analytics-panelTab"]').click(); cy.get('[aria-label="actionMenuButton"]').click(); cy.get('[data-test-subj="editVizContextMenuItem"]').click(); - supressResizeObserverIssue(); + suppressResizeObserverIssue(); cy.get('[data-test-subj="superDatePickerShowDatesButton"]').should('contain', 'Last 24 months'); cy.get('.euiTab[id="availability-panel"]').click(); cy.get('[title="Bar"]').click(); @@ -389,7 +389,7 @@ describe('Viewing application', () => { cy.get('[data-test-subj="superDatePickerApplyTimeButton"]').click(); cy.wait(delay); cy.get('[data-test-subj="main-content-visTab"]').click(); - supressResizeObserverIssue(); + suppressResizeObserverIssue(); cy.get('.euiTab[id="availability-panel"]').click(); cy.get('[title="Bar"]').click(); cy.focused().type('{downArrow}'); diff --git a/.cypress/utils/app_constants.js b/.cypress/utils/app_constants.js index f874324097..4d20359f46 100644 --- a/.cypress/utils/app_constants.js +++ b/.cypress/utils/app_constants.js @@ -3,7 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { supressResizeObserverIssue } from './constants'; +import { suppressResizeObserverIssue } from './constants'; export const delay = 1000; export const timeoutDelay = 30000; @@ -18,13 +18,13 @@ export const moveToHomePage = () => { export const moveToCreatePage = () => { cy.visit(`${Cypress.env('opensearchDashboards')}/app/observability-dashboards#/application_analytics/`); cy.get('.euiButton[href="#/application_analytics/create"]').eq(0).click(); - supressResizeObserverIssue(); + suppressResizeObserverIssue(); cy.get('[data-test-subj="createPageTitle"]').should('contain', 'Create application'); }; export const moveToApplication = (name) => { cy.visit(`${Cypress.env('opensearchDashboards')}/app/observability-dashboards#/application_analytics/`); - supressResizeObserverIssue(); + suppressResizeObserverIssue(); cy.wait(delay * 6); cy.get(`[data-test-subj="${name}ApplicationLink"]`).click(); cy.wait(delay); @@ -36,7 +36,7 @@ export const moveToEditPage = () => { moveToApplication(nameOne); cy.get('[data-test-subj="app-analytics-configTab"]').click(); cy.get('[data-test-subj="editApplicationButton"]').click(); - supressResizeObserverIssue(); + suppressResizeObserverIssue(); cy.wait(delay); cy.get('[data-test-subj="createPageTitle"]').should('contain', 'Edit application'); }; diff --git a/.cypress/utils/constants.js b/.cypress/utils/constants.js index 4f9487ceb0..5d6f692ff1 100644 --- a/.cypress/utils/constants.js +++ b/.cypress/utils/constants.js @@ -110,7 +110,7 @@ export const PPL_QUERY_TEXT = `%ppl source=opensearch_dashboards_sample_data_flights ` -export const supressResizeObserverIssue = () => { +export const suppressResizeObserverIssue = () => { // exception is thrown on loading EuiDataGrid in cypress only, ignore for now cy.on('uncaught:exception', (err, runnable) => { if (err.message.includes('ResizeObserver loop')) return false; diff --git a/.cypress/utils/event_analytics/constants.js b/.cypress/utils/event_analytics/constants.js index 4168fa74ab..f425438b70 100644 --- a/.cypress/utils/event_analytics/constants.js +++ b/.cypress/utils/event_analytics/constants.js @@ -3,7 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { COMMAND_TIMEOUT_LONG, supressResizeObserverIssue } from '../constants'; +import { COMMAND_TIMEOUT_LONG, suppressResizeObserverIssue } from '../constants'; export const delay = 1000; export const YEAR_TO_DATE_DOM_ID = '[data-test-subj="superDatePickerCommonlyUsed_Year_to date"]'; @@ -77,6 +77,7 @@ export const querySearch = (query, rangeSelected) => { .clear() .focus() .type(query, { delay: 50 }); + suppressResizeObserverIssue(); cy.get('[data-test-subj="superDatePickerToggleQuickMenuButton"]').click(); cy.get(rangeSelected).click(); cy.get('[data-test-subj="superDatePickerApplyTimeButton"]').contains('Refresh').click(); @@ -96,7 +97,7 @@ export const landOnEventVisualizations = () => { cy.visit( `${Cypress.env('opensearchDashboards')}/app/observability-dashboards#/event_analytics/explorer` ); - supressResizeObserverIssue(); // have to add + suppressResizeObserverIssue(); // have to add cy.get('button[id="main-content-vis"]').contains('Visualizations').click(); }; From aa672f0ddd27576481d4394a0c473860d801d8a5 Mon Sep 17 00:00:00 2001 From: Eric Wei Date: Mon, 13 Mar 2023 12:52:51 -0700 Subject: [PATCH 07/73] added download path for issue causing app reloads Signed-off-by: Eric Wei --- cypress.json | 1 + 1 file changed, 1 insertion(+) diff --git a/cypress.json b/cypress.json index 5c55805ba6..dbe41c79b7 100644 --- a/cypress.json +++ b/cypress.json @@ -8,6 +8,7 @@ "screenshotsFolder": ".cypress/screenshots", "supportFile": ".cypress/support/index.js", "videosFolder": ".cypress/videos", + "downloadsFolder": ".cypress/downloads", "viewportWidth": 2000, "viewportHeight": 1320, "requestTimeout": 60000, From 62b142836f49f7682c5c67e7caa57e4530b870eb Mon Sep 17 00:00:00 2001 From: Eric Wei Date: Mon, 13 Mar 2023 16:27:22 -0700 Subject: [PATCH 08/73] quick resolution for few tests Signed-off-by: Eric Wei --- .../integration/1_event_analytics.spec.js | 48 +------------------ 1 file changed, 2 insertions(+), 46 deletions(-) diff --git a/.cypress/integration/1_event_analytics.spec.js b/.cypress/integration/1_event_analytics.spec.js index b8d4f87723..57fc0ad763 100644 --- a/.cypress/integration/1_event_analytics.spec.js +++ b/.cypress/integration/1_event_analytics.spec.js @@ -22,16 +22,11 @@ import { HOST_TEXT_2, HOST_TEXT_3, HOST_TEXT_4, - AGENT_TEXT_1, - AGENT_TEXT_2, - AGENT_TEXT_3, BAR_LEG_TEXT_1, BAR_LEG_TEXT_2, BAR_LEG_TEXT_3, VIS_TYPE_PIE, - VIS_TYPE_HBAR, VIS_TYPE_VBAR, - VIS_TYPE_HEATMAP, FIELD_HOST, FIELD_AGENT } from '../utils/event_analytics/constants'; @@ -215,7 +210,7 @@ describe('Click actions', () => { cy.get('[data-test-subj="eventHomeAction__delete"]').click(); cy.get('[data-test-subj="popoverModal__deleteTextInput"]').type('delete'); cy.get('[data-test-subj="popoverModal__deleteButton"').click(); - cy.get('.euiToastHeader__title').contains('successfully').should('exist'); + cy.get('.euiToastHeader__title').should('contain', 'successfully'); }); }); @@ -487,7 +482,7 @@ describe('Live tail stop automatically', () => { }); describe('Visualizing data', () => { - before(() => { + beforeEach(() => { landOnEventVisualizations(); querySearch(TEST_QUERIES[2].query, YEAR_TO_DATE_DOM_ID); }); @@ -549,43 +544,4 @@ describe('Visualizing data', () => { cy.get('@legandTxt').should('contain', BAR_LEG_TEXT_2); cy.get('@legandTxt').should('contain', BAR_LEG_TEXT_3); }); - - it('Visualize horizontal bar chart', () => { - cy.get('[data-test-subj="comboBoxInput"]').click(); - cy.get('[data-test-subj="comboBoxOptionsList "] span').contains(VIS_TYPE_HBAR).click(); - cy.get('[data-test-subj="vizConfigSection-dimensions"]') - .find('[data-test-subj="viz-config-section"]') - .eq(1) - .find('[data-test-subj="viz-config-delete-btn"]') - .click(); - cy.get('[data-test-subj="vizConfigSection-breakdowns"]') - .find('[data-test-subj="viz-config-add-btn"]') - .click(); - cy.get('[data-test-subj="explorer__vizDataConfig-panel"]') - .find('[data-test-subj="comboBoxInput"]') - .click() - .type(FIELD_AGENT); - cy.get(`input[value="${FIELD_AGENT}"]`).click(); - cy.get('[data-test-subj="panelCloseBtn"]').click(); - cy.get('[data-test-subj="visualizeEditorRenderButton"]').click(); - cy.get('.infolayer .legendtext').as('legandTxt'); - cy.get('@legandTxt').should('contain', BAR_LEG_TEXT_1); - cy.get('@legandTxt').should('contain', BAR_LEG_TEXT_2); - cy.get('@legandTxt').should('contain', BAR_LEG_TEXT_3); - }); - - it('Visualize heatmap chart', () => { - cy.get('[data-test-subj="comboBoxInput"]').click(); - cy.get('[data-test-subj="comboBoxOptionsList "] span').contains(VIS_TYPE_HEATMAP).click(); - suppressResizeObserverIssue(); - cy.get('g.cartesianlayer g.xy g.xaxislayer-above g.xtick text').as('legandXTxt'); - cy.get('@legandXTxt').should('contain', HOST_TEXT_1); - cy.get('@legandXTxt').should('contain', HOST_TEXT_3); - cy.get('@legandXTxt').should('contain', HOST_TEXT_4); - cy.get('@legandXTxt').should('contain', HOST_TEXT_2); - cy.get('g.cartesianlayer g.xy g.yaxislayer-above g.ytick text').as('legandYTxt'); - cy.get('@legandYTxt').should('contain', AGENT_TEXT_1); - cy.get('@legandYTxt').should('contain', AGENT_TEXT_2); - cy.get('@legandYTxt').should('contain', AGENT_TEXT_3); - }); }); From 0fd0f1dc980e0b02314c7d9c5b8eda10b28bb45c Mon Sep 17 00:00:00 2001 From: Eric Wei Date: Mon, 13 Mar 2023 16:47:23 -0700 Subject: [PATCH 09/73] update jest tests/snapshots Signed-off-by: Eric Wei --- .../__snapshots__/utils.test.tsx.snap | 191 +- .../__snapshots__/config_panel.test.tsx.snap | 1592 +++++++++++++++-- .../__tests__/__snapshots__/bar.test.tsx.snap | 160 +- .../__snapshots__/data_table.test.tsx.snap | 269 ++- .../__snapshots__/gauge.test.tsx.snap | 152 ++ .../__snapshots__/heatmap.test.tsx.snap | 355 +++- .../__snapshots__/histogram.test.tsx.snap | 168 +- .../horizontal_bar.test.tsx.snap | 160 +- .../__snapshots__/line.test.tsx.snap | 160 +- .../__snapshots__/logs_view.test.tsx.snap | 1584 +++++++++++++++- .../__snapshots__/metrics.test.tsx.snap | 152 ++ .../__tests__/__snapshots__/pie.test.tsx.snap | 160 +- .../__snapshots__/text.test.tsx.snap | 160 +- .../__snapshots__/treemap.test.tsx.snap | 160 +- test/event_analytics_constants.ts | 3 + 15 files changed, 5054 insertions(+), 372 deletions(-) diff --git a/public/components/custom_panels/helpers/__tests__/__snapshots__/utils.test.tsx.snap b/public/components/custom_panels/helpers/__tests__/__snapshots__/utils.test.tsx.snap index 5876133be8..ae12e1b7df 100644 --- a/public/components/custom_panels/helpers/__tests__/__snapshots__/utils.test.tsx.snap +++ b/public/components/custom_panels/helpers/__tests__/__snapshots__/utils.test.tsx.snap @@ -72,16 +72,7 @@ exports[`Utils helper functions renders displayVisualization function 1`] = ` "size": 4, "status": 200, }, - "explorerFields": Array [ - Object { - "name": "avg(FlightDelayMin)", - "type": "double", - }, - Object { - "name": "Carrier", - "type": "keyword", - }, - ], + "explorerFields": undefined, }, "indexFields": Object {}, "query": Object { @@ -385,7 +376,7 @@ exports[`Utils helper functions renders displayVisualization function 1`] = ` }, Object { "component": [Function], - "defaultState": 2, + "defaultState": 0, "eleType": "slider", "mapTo": "lineWidth", "name": "Line width", @@ -395,7 +386,7 @@ exports[`Utils helper functions renders displayVisualization function 1`] = ` }, Object { "component": [Function], - "defaultState": 70, + "defaultState": 100, "eleType": "slider", "mapTo": "fillOpacity", "name": "Fill opacity", @@ -422,7 +413,7 @@ exports[`Utils helper functions renders displayVisualization function 1`] = ` }, ], }, - "fillopacity": 70, + "fillopacity": 100, "fulllabel": "Vertical bar", "groupwidth": 0.7, "icon": [Function], @@ -431,7 +422,7 @@ exports[`Utils helper functions renders displayVisualization function 1`] = ` "label": "Vertical bar", "labelangle": 0, "legendposition": "v", - "linewidth": 2, + "linewidth": 0, "mode": "group", "name": "bar", "orientation": "v", @@ -537,16 +528,7 @@ exports[`Utils helper functions renders displayVisualization function 1`] = ` "size": 4, "status": 200, }, - "explorerFields": Array [ - Object { - "name": "avg(FlightDelayMin)", - "type": "double", - }, - Object { - "name": "Carrier", - "type": "keyword", - }, - ], + "explorerFields": undefined, }, "indexFields": Object {}, "query": Object { @@ -850,7 +832,7 @@ exports[`Utils helper functions renders displayVisualization function 1`] = ` }, Object { "component": [Function], - "defaultState": 2, + "defaultState": 0, "eleType": "slider", "mapTo": "lineWidth", "name": "Line width", @@ -860,7 +842,7 @@ exports[`Utils helper functions renders displayVisualization function 1`] = ` }, Object { "component": [Function], - "defaultState": 70, + "defaultState": 100, "eleType": "slider", "mapTo": "fillOpacity", "name": "Fill opacity", @@ -887,7 +869,7 @@ exports[`Utils helper functions renders displayVisualization function 1`] = ` }, ], }, - "fillopacity": 70, + "fillopacity": 100, "fulllabel": "Vertical bar", "groupwidth": 0.7, "icon": [Function], @@ -896,7 +878,7 @@ exports[`Utils helper functions renders displayVisualization function 1`] = ` "label": "Vertical bar", "labelangle": 0, "legendposition": "v", - "linewidth": 2, + "linewidth": 0, "mode": "group", "name": "bar", "orientation": "v", @@ -1009,16 +991,7 @@ exports[`Utils helper functions renders displayVisualization function 1`] = ` "size": 4, "status": 200, }, - "explorerFields": Array [ - Object { - "name": "avg(FlightDelayMin)", - "type": "double", - }, - Object { - "name": "Carrier", - "type": "keyword", - }, - ], + "explorerFields": undefined, }, "indexFields": Object {}, "query": Object { @@ -1322,7 +1295,7 @@ exports[`Utils helper functions renders displayVisualization function 1`] = ` }, Object { "component": [Function], - "defaultState": 2, + "defaultState": 0, "eleType": "slider", "mapTo": "lineWidth", "name": "Line width", @@ -1332,7 +1305,7 @@ exports[`Utils helper functions renders displayVisualization function 1`] = ` }, Object { "component": [Function], - "defaultState": 70, + "defaultState": 100, "eleType": "slider", "mapTo": "fillOpacity", "name": "Fill opacity", @@ -1359,7 +1332,7 @@ exports[`Utils helper functions renders displayVisualization function 1`] = ` }, ], }, - "fillopacity": 70, + "fillopacity": 100, "fulllabel": "Vertical bar", "groupwidth": 0.7, "icon": [Function], @@ -1368,7 +1341,7 @@ exports[`Utils helper functions renders displayVisualization function 1`] = ` "label": "Vertical bar", "labelangle": 0, "legendposition": "v", - "linewidth": 2, + "linewidth": 0, "mode": "group", "name": "bar", "orientation": "v", @@ -1416,10 +1389,10 @@ exports[`Utils helper functions renders displayVisualization function 1`] = ` Object { "hoverinfo": "all", "marker": Object { - "color": "rgba(60,161,199,0.35)", + "color": "rgba(60,161,199,0.5)", "line": Object { "color": "#3CA1C7", - "width": 2, + "width": 0, }, }, "name": "delays", @@ -1506,10 +1479,10 @@ exports[`Utils helper functions renders displayVisualization function 1`] = ` Object { "hoverinfo": "all", "marker": Object { - "color": "rgba(60,161,199,0.35)", + "color": "rgba(60,161,199,0.5)", "line": Object { "color": "#3CA1C7", - "width": 2, + "width": 0, }, }, "name": "delays", @@ -1686,16 +1659,7 @@ exports[`Utils helper functions renders displayVisualization function 2`] = ` "size": 4, "status": 200, }, - "explorerFields": Array [ - Object { - "name": "avg(FlightDelayMin)", - "type": "double", - }, - Object { - "name": "Carrier", - "type": "keyword", - }, - ], + "explorerFields": undefined, }, "indexFields": Object {}, "query": Object { @@ -1982,7 +1946,7 @@ exports[`Utils helper functions renders displayVisualization function 2`] = ` }, Object { "component": [Function], - "defaultState": 2, + "defaultState": 0, "eleType": "slider", "mapTo": "lineWidth", "name": "Line width", @@ -1992,7 +1956,7 @@ exports[`Utils helper functions renders displayVisualization function 2`] = ` }, Object { "component": [Function], - "defaultState": 70, + "defaultState": 100, "eleType": "slider", "mapTo": "fillOpacity", "name": "Fill opacity", @@ -2212,16 +2176,7 @@ exports[`Utils helper functions renders displayVisualization function 2`] = ` "size": 4, "status": 200, }, - "explorerFields": Array [ - Object { - "name": "avg(FlightDelayMin)", - "type": "double", - }, - Object { - "name": "Carrier", - "type": "keyword", - }, - ], + "explorerFields": undefined, }, "indexFields": Object {}, "query": Object { @@ -2508,7 +2463,7 @@ exports[`Utils helper functions renders displayVisualization function 2`] = ` }, Object { "component": [Function], - "defaultState": 2, + "defaultState": 0, "eleType": "slider", "mapTo": "lineWidth", "name": "Line width", @@ -2518,7 +2473,7 @@ exports[`Utils helper functions renders displayVisualization function 2`] = ` }, Object { "component": [Function], - "defaultState": 70, + "defaultState": 100, "eleType": "slider", "mapTo": "fillOpacity", "name": "Fill opacity", @@ -2752,16 +2707,7 @@ exports[`Utils helper functions renders displayVisualization function 2`] = ` "size": 4, "status": 200, }, - "explorerFields": Array [ - Object { - "name": "avg(FlightDelayMin)", - "type": "double", - }, - Object { - "name": "Carrier", - "type": "keyword", - }, - ], + "explorerFields": undefined, }, "indexFields": Object {}, "query": Object { @@ -3048,7 +2994,7 @@ exports[`Utils helper functions renders displayVisualization function 2`] = ` }, Object { "component": [Function], - "defaultState": 2, + "defaultState": 0, "eleType": "slider", "mapTo": "lineWidth", "name": "Line width", @@ -3058,7 +3004,7 @@ exports[`Utils helper functions renders displayVisualization function 2`] = ` }, Object { "component": [Function], - "defaultState": 70, + "defaultState": 100, "eleType": "slider", "mapTo": "fillOpacity", "name": "Fill opacity", @@ -3222,18 +3168,18 @@ exports[`Utils helper functions renders displayVisualization function 2`] = ` Array [ Object { "fill": "tozeroy", - "fillcolor": "rgba(60,161,199,0.35)", + "fillcolor": "rgba(60,161,199,0.5)", "hoverinfo": "all", "line": Object { "color": "#3CA1C7", "shape": "spline", - "width": 2, + "width": 0, }, "marker": Object { - "color": "rgba(60,161,199,0.35)", + "color": "rgba(60,161,199,0.5)", "line": Object { "color": "#3CA1C7", - "width": 2, + "width": 0, }, "size": 5, }, @@ -3309,18 +3255,18 @@ exports[`Utils helper functions renders displayVisualization function 2`] = ` Array [ Object { "fill": "tozeroy", - "fillcolor": "rgba(60,161,199,0.35)", + "fillcolor": "rgba(60,161,199,0.5)", "hoverinfo": "all", "line": Object { "color": "#3CA1C7", "shape": "spline", - "width": 2, + "width": 0, }, "marker": Object { - "color": "rgba(60,161,199,0.35)", + "color": "rgba(60,161,199,0.5)", "line": Object { "color": "#3CA1C7", - "width": 2, + "width": 0, }, "size": 5, }, @@ -3477,16 +3423,7 @@ exports[`Utils helper functions renders displayVisualization function 3`] = ` "size": 4, "status": 200, }, - "explorerFields": Array [ - Object { - "name": "avg(FlightDelayMin)", - "type": "double", - }, - Object { - "name": "Carrier", - "type": "keyword", - }, - ], + "explorerFields": undefined, }, "indexFields": Object {}, "query": Object { @@ -3790,7 +3727,7 @@ exports[`Utils helper functions renders displayVisualization function 3`] = ` }, Object { "component": [Function], - "defaultState": 2, + "defaultState": 0, "eleType": "slider", "mapTo": "lineWidth", "name": "Line width", @@ -3800,7 +3737,7 @@ exports[`Utils helper functions renders displayVisualization function 3`] = ` }, Object { "component": [Function], - "defaultState": 70, + "defaultState": 100, "eleType": "slider", "mapTo": "fillOpacity", "name": "Fill opacity", @@ -3827,7 +3764,7 @@ exports[`Utils helper functions renders displayVisualization function 3`] = ` }, ], }, - "fillopacity": 70, + "fillopacity": 100, "fulllabel": "Horizontal bar", "groupwidth": 0.7, "icon": [Function], @@ -3836,7 +3773,7 @@ exports[`Utils helper functions renders displayVisualization function 3`] = ` "label": "Horizontal bar", "labelangle": 0, "legendposition": "v", - "linewidth": 2, + "linewidth": 0, "mode": "group", "name": "horizontal_bar", "orientation": "h", @@ -3942,16 +3879,7 @@ exports[`Utils helper functions renders displayVisualization function 3`] = ` "size": 4, "status": 200, }, - "explorerFields": Array [ - Object { - "name": "avg(FlightDelayMin)", - "type": "double", - }, - Object { - "name": "Carrier", - "type": "keyword", - }, - ], + "explorerFields": undefined, }, "indexFields": Object {}, "query": Object { @@ -4255,7 +4183,7 @@ exports[`Utils helper functions renders displayVisualization function 3`] = ` }, Object { "component": [Function], - "defaultState": 2, + "defaultState": 0, "eleType": "slider", "mapTo": "lineWidth", "name": "Line width", @@ -4265,7 +4193,7 @@ exports[`Utils helper functions renders displayVisualization function 3`] = ` }, Object { "component": [Function], - "defaultState": 70, + "defaultState": 100, "eleType": "slider", "mapTo": "fillOpacity", "name": "Fill opacity", @@ -4292,7 +4220,7 @@ exports[`Utils helper functions renders displayVisualization function 3`] = ` }, ], }, - "fillopacity": 70, + "fillopacity": 100, "fulllabel": "Horizontal bar", "groupwidth": 0.7, "icon": [Function], @@ -4301,7 +4229,7 @@ exports[`Utils helper functions renders displayVisualization function 3`] = ` "label": "Horizontal bar", "labelangle": 0, "legendposition": "v", - "linewidth": 2, + "linewidth": 0, "mode": "group", "name": "horizontal_bar", "orientation": "h", @@ -4414,16 +4342,7 @@ exports[`Utils helper functions renders displayVisualization function 3`] = ` "size": 4, "status": 200, }, - "explorerFields": Array [ - Object { - "name": "avg(FlightDelayMin)", - "type": "double", - }, - Object { - "name": "Carrier", - "type": "keyword", - }, - ], + "explorerFields": undefined, }, "indexFields": Object {}, "query": Object { @@ -4727,7 +4646,7 @@ exports[`Utils helper functions renders displayVisualization function 3`] = ` }, Object { "component": [Function], - "defaultState": 2, + "defaultState": 0, "eleType": "slider", "mapTo": "lineWidth", "name": "Line width", @@ -4737,7 +4656,7 @@ exports[`Utils helper functions renders displayVisualization function 3`] = ` }, Object { "component": [Function], - "defaultState": 70, + "defaultState": 100, "eleType": "slider", "mapTo": "fillOpacity", "name": "Fill opacity", @@ -4764,7 +4683,7 @@ exports[`Utils helper functions renders displayVisualization function 3`] = ` }, ], }, - "fillopacity": 70, + "fillopacity": 100, "fulllabel": "Horizontal bar", "groupwidth": 0.7, "icon": [Function], @@ -4773,7 +4692,7 @@ exports[`Utils helper functions renders displayVisualization function 3`] = ` "label": "Horizontal bar", "labelangle": 0, "legendposition": "v", - "linewidth": 2, + "linewidth": 0, "mode": "group", "name": "horizontal_bar", "orientation": "h", @@ -4821,10 +4740,10 @@ exports[`Utils helper functions renders displayVisualization function 3`] = ` Object { "hoverinfo": "all", "marker": Object { - "color": "rgba(60,161,199,0.35)", + "color": "rgba(60,161,199,0.5)", "line": Object { "color": "#3CA1C7", - "width": 2, + "width": 0, }, }, "name": "avg(machine.ram)", @@ -4911,10 +4830,10 @@ exports[`Utils helper functions renders displayVisualization function 3`] = ` Object { "hoverinfo": "all", "marker": Object { - "color": "rgba(60,161,199,0.35)", + "color": "rgba(60,161,199,0.5)", "line": Object { "color": "#3CA1C7", - "width": 2, + "width": 0, }, }, "name": "avg(machine.ram)", diff --git a/public/components/event_analytics/explorer/visualizations/config_panel/__tests__/__snapshots__/config_panel.test.tsx.snap b/public/components/event_analytics/explorer/visualizations/config_panel/__tests__/__snapshots__/config_panel.test.tsx.snap index ecdc438c50..7dfcd0eb80 100644 --- a/public/components/event_analytics/explorer/visualizations/config_panel/__tests__/__snapshots__/config_panel.test.tsx.snap +++ b/public/components/event_analytics/explorer/visualizations/config_panel/__tests__/__snapshots__/config_panel.test.tsx.snap @@ -11,6 +11,158 @@ exports[`Config panel component Renders config panel with visualization data 1`] "fromApp": false, }, "defaultAxes": Object {}, + "explorer": Object { + "explorerData": Object { + "jsonData": Array [ + Object { + "double_per_ip_bytes": 11606, + "host": "artifacts.opensearch.org", + "ip_count": 176, + "per_ip_bytes": 5803, + "resp_code": "404", + "sum_bytes": 1021420, + }, + Object { + "double_per_ip_bytes": 10100, + "host": "www.opensearch.org", + "ip_count": 111, + "per_ip_bytes": 5050, + "resp_code": "404", + "sum_bytes": 560638, + }, + Object { + "double_per_ip_bytes": 0, + "host": "artifacts.opensearch.org", + "ip_count": 94, + "per_ip_bytes": 0, + "resp_code": "503", + "sum_bytes": 0, + }, + Object { + "double_per_ip_bytes": 0, + "host": "www.opensearch.org", + "ip_count": 78, + "per_ip_bytes": 0, + "resp_code": "503", + "sum_bytes": 0, + }, + Object { + "double_per_ip_bytes": 11526, + "host": "cdn.opensearch-opensearch-opensearch.org", + "ip_count": 43, + "per_ip_bytes": 5763, + "resp_code": "404", + "sum_bytes": 247840, + }, + Object { + "double_per_ip_bytes": 0, + "host": "cdn.opensearch-opensearch-opensearch.org", + "ip_count": 34, + "per_ip_bytes": 0, + "resp_code": "503", + "sum_bytes": 0, + }, + Object { + "double_per_ip_bytes": 8882, + "host": "opensearch-opensearch-opensearch.org", + "ip_count": 13, + "per_ip_bytes": 4441, + "resp_code": "404", + "sum_bytes": 57735, + }, + Object { + "double_per_ip_bytes": 0, + "host": "opensearch-opensearch-opensearch.org", + "ip_count": 6, + "per_ip_bytes": 0, + "resp_code": "503", + "sum_bytes": 0, + }, + ], + "schema": Array [ + Object { + "name": "agent", + "type": "string", + }, + Object { + "name": "bytes", + "type": "long", + }, + Object { + "name": "clientip", + "type": "ip", + }, + Object { + "name": "event", + "type": "struct", + }, + Object { + "name": "extension", + "type": "string", + }, + Object { + "name": "geo", + "type": "struct", + }, + Object { + "name": "host", + "type": "string", + }, + Object { + "name": "index", + "type": "string", + }, + Object { + "name": "ip", + "type": "ip", + }, + Object { + "name": "machine", + "type": "struct", + }, + Object { + "name": "memory", + "type": "double", + }, + Object { + "name": "message", + "type": "string", + }, + Object { + "name": "phpmemory", + "type": "long", + }, + Object { + "name": "referer", + "type": "string", + }, + Object { + "name": "request", + "type": "string", + }, + Object { + "name": "response", + "type": "string", + }, + Object { + "name": "tags", + "type": "string", + }, + Object { + "name": "timestamp", + "type": "timestamp", + }, + Object { + "name": "url", + "type": "string", + }, + Object { + "name": "utc_time", + "type": "timestamp", + }, + ], + }, + }, "indexFields": Object { "availableFields": Array [ Object { @@ -432,7 +584,7 @@ exports[`Config panel component Renders config panel with visualization data 1`] }, Object { "component": [Function], - "defaultState": 2, + "defaultState": 0, "eleType": "slider", "mapTo": "lineWidth", "name": "Line width", @@ -442,7 +594,7 @@ exports[`Config panel component Renders config panel with visualization data 1`] }, Object { "component": [Function], - "defaultState": 70, + "defaultState": 100, "eleType": "slider", "mapTo": "fillOpacity", "name": "Fill opacity", @@ -469,7 +621,7 @@ exports[`Config panel component Renders config panel with visualization data 1`] }, ], }, - "fillopacity": 70, + "fillopacity": 100, "fulllabel": "Vertical bar", "groupwidth": 0.7, "icon": [Function], @@ -478,7 +630,7 @@ exports[`Config panel component Renders config panel with visualization data 1`] "label": "Vertical bar", "labelangle": 0, "legendposition": "v", - "linewidth": 2, + "linewidth": 0, "mode": "group", "name": "bar", "orientation": "v", @@ -755,7 +907,7 @@ exports[`Config panel component Renders config panel with visualization data 1`] }, Object { "component": [Function], - "defaultState": 2, + "defaultState": 0, "eleType": "slider", "mapTo": "lineWidth", "name": "Line width", @@ -765,7 +917,7 @@ exports[`Config panel component Renders config panel with visualization data 1`] }, Object { "component": [Function], - "defaultState": 70, + "defaultState": 100, "eleType": "slider", "mapTo": "fillOpacity", "name": "Fill opacity", @@ -792,7 +944,7 @@ exports[`Config panel component Renders config panel with visualization data 1`] }, ], }, - "fillopacity": 70, + "fillopacity": 100, "fulllabel": "Vertical bar", "groupwidth": 0.7, "icon": [Function], @@ -802,7 +954,7 @@ exports[`Config panel component Renders config panel with visualization data 1`] "label": "Vertical bar", "labelangle": 0, "legendposition": "v", - "linewidth": 2, + "linewidth": 0, "mode": "group", "name": "bar", "orientation": "v", @@ -1061,7 +1213,7 @@ exports[`Config panel component Renders config panel with visualization data 1`] }, Object { "component": [Function], - "defaultState": 2, + "defaultState": 0, "eleType": "slider", "mapTo": "lineWidth", "name": "Line width", @@ -1071,7 +1223,7 @@ exports[`Config panel component Renders config panel with visualization data 1`] }, Object { "component": [Function], - "defaultState": 70, + "defaultState": 100, "eleType": "slider", "mapTo": "fillOpacity", "name": "Fill opacity", @@ -1098,7 +1250,7 @@ exports[`Config panel component Renders config panel with visualization data 1`] }, ], }, - "fillopacity": 70, + "fillopacity": 100, "fulllabel": "Horizontal bar", "groupwidth": 0.7, "icon": [Function], @@ -1107,7 +1259,7 @@ exports[`Config panel component Renders config panel with visualization data 1`] "label": "Horizontal bar", "labelangle": 0, "legendposition": "v", - "linewidth": 2, + "linewidth": 0, "mode": "group", "name": "horizontal_bar", "orientation": "h", @@ -1339,7 +1491,7 @@ exports[`Config panel component Renders config panel with visualization data 1`] }, Object { "component": [Function], - "defaultState": 2, + "defaultState": 0, "eleType": "slider", "mapTo": "lineWidth", "name": "Line width", @@ -1349,7 +1501,7 @@ exports[`Config panel component Renders config panel with visualization data 1`] }, Object { "component": [Function], - "defaultState": 70, + "defaultState": 100, "eleType": "slider", "mapTo": "fillOpacity", "name": "Fill opacity", @@ -2458,7 +2610,7 @@ exports[`Config panel component Renders config panel with visualization data 1`] }, Object { "component": [Function], - "defaultState": 2, + "defaultState": 0, "eleType": "slider", "mapTo": "lineWidth", "name": "Line width", @@ -2468,7 +2620,7 @@ exports[`Config panel component Renders config panel with visualization data 1`] }, Object { "component": [Function], - "defaultState": 70, + "defaultState": 100, "eleType": "slider", "mapTo": "fillOpacity", "name": "Fill opacity", @@ -2495,7 +2647,7 @@ exports[`Config panel component Renders config panel with visualization data 1`] }, ], }, - "fillopacity": 70, + "fillopacity": 100, "fulllabel": "Vertical bar", "groupwidth": 0.7, "icon": [Function], @@ -2505,7 +2657,7 @@ exports[`Config panel component Renders config panel with visualization data 1`] "label": "Vertical bar", "labelangle": 0, "legendposition": "v", - "linewidth": 2, + "linewidth": 0, "mode": "group", "name": "bar", "orientation": "v", @@ -2796,7 +2948,7 @@ exports[`Config panel component Renders config panel with visualization data 1`] }, Object { "component": [Function], - "defaultState": 2, + "defaultState": 0, "eleType": "slider", "mapTo": "lineWidth", "name": "Line width", @@ -2806,7 +2958,7 @@ exports[`Config panel component Renders config panel with visualization data 1`] }, Object { "component": [Function], - "defaultState": 70, + "defaultState": 100, "eleType": "slider", "mapTo": "fillOpacity", "name": "Fill opacity", @@ -2833,7 +2985,7 @@ exports[`Config panel component Renders config panel with visualization data 1`] }, ], }, - "fillopacity": 70, + "fillopacity": 100, "fulllabel": "Vertical bar", "groupwidth": 0.7, "icon": [Function], @@ -2843,7 +2995,7 @@ exports[`Config panel component Renders config panel with visualization data 1`] "label": "Vertical bar", "labelangle": 0, "legendposition": "v", - "linewidth": 2, + "linewidth": 0, "mode": "group", "name": "bar", "orientation": "v", @@ -3139,7 +3291,7 @@ exports[`Config panel component Renders config panel with visualization data 1`] }, Object { "component": [Function], - "defaultState": 2, + "defaultState": 0, "eleType": "slider", "mapTo": "lineWidth", "name": "Line width", @@ -3149,7 +3301,7 @@ exports[`Config panel component Renders config panel with visualization data 1`] }, Object { "component": [Function], - "defaultState": 70, + "defaultState": 100, "eleType": "slider", "mapTo": "fillOpacity", "name": "Fill opacity", @@ -3177,7 +3329,7 @@ exports[`Config panel component Renders config panel with visualization data 1`] ], } } - fillopacity={70} + fillopacity={100} fulllabel="Vertical bar" groupwidth={0.7} icon={[Function]} @@ -3187,7 +3339,7 @@ exports[`Config panel component Renders config panel with visualization data 1`] key="vertical bar" labelangle={0} legendposition="v" - linewidth={2} + linewidth={0} mode="group" name="bar" option={ @@ -3417,7 +3569,7 @@ exports[`Config panel component Renders config panel with visualization data 1`] }, Object { "component": [Function], - "defaultState": 2, + "defaultState": 0, "eleType": "slider", "mapTo": "lineWidth", "name": "Line width", @@ -3427,7 +3579,7 @@ exports[`Config panel component Renders config panel with visualization data 1`] }, Object { "component": [Function], - "defaultState": 70, + "defaultState": 100, "eleType": "slider", "mapTo": "fillOpacity", "name": "Fill opacity", @@ -3454,7 +3606,7 @@ exports[`Config panel component Renders config panel with visualization data 1`] }, ], }, - "fillopacity": 70, + "fillopacity": 100, "fulllabel": "Vertical bar", "groupwidth": 0.7, "icon": [Function], @@ -3464,7 +3616,7 @@ exports[`Config panel component Renders config panel with visualization data 1`] "label": "Vertical bar", "labelangle": 0, "legendposition": "v", - "linewidth": 2, + "linewidth": 0, "mode": "group", "name": "bar", "orientation": "v", @@ -3761,7 +3913,7 @@ exports[`Config panel component Renders config panel with visualization data 1`] }, Object { "component": [Function], - "defaultState": 2, + "defaultState": 0, "eleType": "slider", "mapTo": "lineWidth", "name": "Line width", @@ -3771,7 +3923,7 @@ exports[`Config panel component Renders config panel with visualization data 1`] }, Object { "component": [Function], - "defaultState": 70, + "defaultState": 100, "eleType": "slider", "mapTo": "fillOpacity", "name": "Fill opacity", @@ -3799,7 +3951,7 @@ exports[`Config panel component Renders config panel with visualization data 1`] ], } } - fillopacity={70} + fillopacity={100} fulllabel="Vertical bar" groupwidth={0.7} icon={[Function]} @@ -3808,7 +3960,7 @@ exports[`Config panel component Renders config panel with visualization data 1`] id="bar" labelangle={0} legendposition="v" - linewidth={2} + linewidth={0} mode="group" name="bar" orientation="v" @@ -4075,7 +4227,7 @@ exports[`Config panel component Renders config panel with visualization data 1`] }, Object { "component": [Function], - "defaultState": 2, + "defaultState": 0, "eleType": "slider", "mapTo": "lineWidth", "name": "Line width", @@ -4085,7 +4237,7 @@ exports[`Config panel component Renders config panel with visualization data 1`] }, Object { "component": [Function], - "defaultState": 70, + "defaultState": 100, "eleType": "slider", "mapTo": "fillOpacity", "name": "Fill opacity", @@ -4113,7 +4265,7 @@ exports[`Config panel component Renders config panel with visualization data 1`] ], } } - fillopacity={70} + fillopacity={100} fulllabel="Vertical bar" groupwidth={0.7} icon={[Function]} @@ -4121,7 +4273,7 @@ exports[`Config panel component Renders config panel with visualization data 1`] id="bar" labelangle={0} legendposition="v" - linewidth={2} + linewidth={0} mode="group" name="bar" orientation="v" @@ -4557,7 +4709,7 @@ exports[`Config panel component Renders config panel with visualization data 1`] }, Object { "component": [Function], - "defaultState": 2, + "defaultState": 0, "eleType": "slider", "mapTo": "lineWidth", "name": "Line width", @@ -4567,7 +4719,7 @@ exports[`Config panel component Renders config panel with visualization data 1`] }, Object { "component": [Function], - "defaultState": 70, + "defaultState": 100, "eleType": "slider", "mapTo": "fillOpacity", "name": "Fill opacity", @@ -4594,6 +4746,158 @@ exports[`Config panel component Renders config panel with visualization data 1`] "fromApp": false, }, "defaultAxes": Object {}, + "explorer": Object { + "explorerData": Object { + "jsonData": Array [ + Object { + "double_per_ip_bytes": 11606, + "host": "artifacts.opensearch.org", + "ip_count": 176, + "per_ip_bytes": 5803, + "resp_code": "404", + "sum_bytes": 1021420, + }, + Object { + "double_per_ip_bytes": 10100, + "host": "www.opensearch.org", + "ip_count": 111, + "per_ip_bytes": 5050, + "resp_code": "404", + "sum_bytes": 560638, + }, + Object { + "double_per_ip_bytes": 0, + "host": "artifacts.opensearch.org", + "ip_count": 94, + "per_ip_bytes": 0, + "resp_code": "503", + "sum_bytes": 0, + }, + Object { + "double_per_ip_bytes": 0, + "host": "www.opensearch.org", + "ip_count": 78, + "per_ip_bytes": 0, + "resp_code": "503", + "sum_bytes": 0, + }, + Object { + "double_per_ip_bytes": 11526, + "host": "cdn.opensearch-opensearch-opensearch.org", + "ip_count": 43, + "per_ip_bytes": 5763, + "resp_code": "404", + "sum_bytes": 247840, + }, + Object { + "double_per_ip_bytes": 0, + "host": "cdn.opensearch-opensearch-opensearch.org", + "ip_count": 34, + "per_ip_bytes": 0, + "resp_code": "503", + "sum_bytes": 0, + }, + Object { + "double_per_ip_bytes": 8882, + "host": "opensearch-opensearch-opensearch.org", + "ip_count": 13, + "per_ip_bytes": 4441, + "resp_code": "404", + "sum_bytes": 57735, + }, + Object { + "double_per_ip_bytes": 0, + "host": "opensearch-opensearch-opensearch.org", + "ip_count": 6, + "per_ip_bytes": 0, + "resp_code": "503", + "sum_bytes": 0, + }, + ], + "schema": Array [ + Object { + "name": "agent", + "type": "string", + }, + Object { + "name": "bytes", + "type": "long", + }, + Object { + "name": "clientip", + "type": "ip", + }, + Object { + "name": "event", + "type": "struct", + }, + Object { + "name": "extension", + "type": "string", + }, + Object { + "name": "geo", + "type": "struct", + }, + Object { + "name": "host", + "type": "string", + }, + Object { + "name": "index", + "type": "string", + }, + Object { + "name": "ip", + "type": "ip", + }, + Object { + "name": "machine", + "type": "struct", + }, + Object { + "name": "memory", + "type": "double", + }, + Object { + "name": "message", + "type": "string", + }, + Object { + "name": "phpmemory", + "type": "long", + }, + Object { + "name": "referer", + "type": "string", + }, + Object { + "name": "request", + "type": "string", + }, + Object { + "name": "response", + "type": "string", + }, + Object { + "name": "tags", + "type": "string", + }, + Object { + "name": "timestamp", + "type": "timestamp", + }, + Object { + "name": "url", + "type": "string", + }, + Object { + "name": "utc_time", + "type": "timestamp", + }, + ], + }, + }, "indexFields": Object { "availableFields": Array [ Object { @@ -5015,7 +5319,7 @@ exports[`Config panel component Renders config panel with visualization data 1`] }, Object { "component": [Function], - "defaultState": 2, + "defaultState": 0, "eleType": "slider", "mapTo": "lineWidth", "name": "Line width", @@ -5025,7 +5329,7 @@ exports[`Config panel component Renders config panel with visualization data 1`] }, Object { "component": [Function], - "defaultState": 70, + "defaultState": 100, "eleType": "slider", "mapTo": "fillOpacity", "name": "Fill opacity", @@ -5052,7 +5356,7 @@ exports[`Config panel component Renders config panel with visualization data 1`] }, ], }, - "fillopacity": 70, + "fillopacity": 100, "fulllabel": "Vertical bar", "groupwidth": 0.7, "icon": [Function], @@ -5061,7 +5365,7 @@ exports[`Config panel component Renders config panel with visualization data 1`] "label": "Vertical bar", "labelangle": 0, "legendposition": "v", - "linewidth": 2, + "linewidth": 0, "mode": "group", "name": "bar", "orientation": "v", @@ -5348,7 +5652,7 @@ exports[`Config panel component Renders config panel with visualization data 1`] }, Object { "component": [Function], - "defaultState": 2, + "defaultState": 0, "eleType": "slider", "mapTo": "lineWidth", "name": "Line width", @@ -5358,7 +5662,7 @@ exports[`Config panel component Renders config panel with visualization data 1`] }, Object { "component": [Function], - "defaultState": 70, + "defaultState": 100, "eleType": "slider", "mapTo": "fillOpacity", "name": "Fill opacity", @@ -5385,6 +5689,158 @@ exports[`Config panel component Renders config panel with visualization data 1`] "fromApp": false, }, "defaultAxes": Object {}, + "explorer": Object { + "explorerData": Object { + "jsonData": Array [ + Object { + "double_per_ip_bytes": 11606, + "host": "artifacts.opensearch.org", + "ip_count": 176, + "per_ip_bytes": 5803, + "resp_code": "404", + "sum_bytes": 1021420, + }, + Object { + "double_per_ip_bytes": 10100, + "host": "www.opensearch.org", + "ip_count": 111, + "per_ip_bytes": 5050, + "resp_code": "404", + "sum_bytes": 560638, + }, + Object { + "double_per_ip_bytes": 0, + "host": "artifacts.opensearch.org", + "ip_count": 94, + "per_ip_bytes": 0, + "resp_code": "503", + "sum_bytes": 0, + }, + Object { + "double_per_ip_bytes": 0, + "host": "www.opensearch.org", + "ip_count": 78, + "per_ip_bytes": 0, + "resp_code": "503", + "sum_bytes": 0, + }, + Object { + "double_per_ip_bytes": 11526, + "host": "cdn.opensearch-opensearch-opensearch.org", + "ip_count": 43, + "per_ip_bytes": 5763, + "resp_code": "404", + "sum_bytes": 247840, + }, + Object { + "double_per_ip_bytes": 0, + "host": "cdn.opensearch-opensearch-opensearch.org", + "ip_count": 34, + "per_ip_bytes": 0, + "resp_code": "503", + "sum_bytes": 0, + }, + Object { + "double_per_ip_bytes": 8882, + "host": "opensearch-opensearch-opensearch.org", + "ip_count": 13, + "per_ip_bytes": 4441, + "resp_code": "404", + "sum_bytes": 57735, + }, + Object { + "double_per_ip_bytes": 0, + "host": "opensearch-opensearch-opensearch.org", + "ip_count": 6, + "per_ip_bytes": 0, + "resp_code": "503", + "sum_bytes": 0, + }, + ], + "schema": Array [ + Object { + "name": "agent", + "type": "string", + }, + Object { + "name": "bytes", + "type": "long", + }, + Object { + "name": "clientip", + "type": "ip", + }, + Object { + "name": "event", + "type": "struct", + }, + Object { + "name": "extension", + "type": "string", + }, + Object { + "name": "geo", + "type": "struct", + }, + Object { + "name": "host", + "type": "string", + }, + Object { + "name": "index", + "type": "string", + }, + Object { + "name": "ip", + "type": "ip", + }, + Object { + "name": "machine", + "type": "struct", + }, + Object { + "name": "memory", + "type": "double", + }, + Object { + "name": "message", + "type": "string", + }, + Object { + "name": "phpmemory", + "type": "long", + }, + Object { + "name": "referer", + "type": "string", + }, + Object { + "name": "request", + "type": "string", + }, + Object { + "name": "response", + "type": "string", + }, + Object { + "name": "tags", + "type": "string", + }, + Object { + "name": "timestamp", + "type": "timestamp", + }, + Object { + "name": "url", + "type": "string", + }, + Object { + "name": "utc_time", + "type": "timestamp", + }, + ], + }, + }, "indexFields": Object { "availableFields": Array [ Object { @@ -5806,7 +6262,7 @@ exports[`Config panel component Renders config panel with visualization data 1`] }, Object { "component": [Function], - "defaultState": 2, + "defaultState": 0, "eleType": "slider", "mapTo": "lineWidth", "name": "Line width", @@ -5816,7 +6272,7 @@ exports[`Config panel component Renders config panel with visualization data 1`] }, Object { "component": [Function], - "defaultState": 70, + "defaultState": 100, "eleType": "slider", "mapTo": "fillOpacity", "name": "Fill opacity", @@ -5843,7 +6299,7 @@ exports[`Config panel component Renders config panel with visualization data 1`] }, ], }, - "fillopacity": 70, + "fillopacity": 100, "fulllabel": "Vertical bar", "groupwidth": 0.7, "icon": [Function], @@ -5852,7 +6308,7 @@ exports[`Config panel component Renders config panel with visualization data 1`] "label": "Vertical bar", "labelangle": 0, "legendposition": "v", - "linewidth": 2, + "linewidth": 0, "mode": "group", "name": "bar", "orientation": "v", @@ -6180,7 +6636,7 @@ exports[`Config panel component Renders config panel with visualization data 1`] }, Object { "component": [Function], - "defaultState": 2, + "defaultState": 0, "eleType": "slider", "mapTo": "lineWidth", "name": "Line width", @@ -6190,7 +6646,7 @@ exports[`Config panel component Renders config panel with visualization data 1`] }, Object { "component": [Function], - "defaultState": 70, + "defaultState": 100, "eleType": "slider", "mapTo": "fillOpacity", "name": "Fill opacity", @@ -6217,24 +6673,176 @@ exports[`Config panel component Renders config panel with visualization data 1`] "fromApp": false, }, "defaultAxes": Object {}, - "indexFields": Object { - "availableFields": Array [ - Object { - "name": "agent", - "type": "string", - }, - Object { - "name": "bytes", - "type": "long", - }, - Object { - "name": "clientip", - "type": "ip", - }, - Object { - "name": "event", - "type": "struct", - }, + "explorer": Object { + "explorerData": Object { + "jsonData": Array [ + Object { + "double_per_ip_bytes": 11606, + "host": "artifacts.opensearch.org", + "ip_count": 176, + "per_ip_bytes": 5803, + "resp_code": "404", + "sum_bytes": 1021420, + }, + Object { + "double_per_ip_bytes": 10100, + "host": "www.opensearch.org", + "ip_count": 111, + "per_ip_bytes": 5050, + "resp_code": "404", + "sum_bytes": 560638, + }, + Object { + "double_per_ip_bytes": 0, + "host": "artifacts.opensearch.org", + "ip_count": 94, + "per_ip_bytes": 0, + "resp_code": "503", + "sum_bytes": 0, + }, + Object { + "double_per_ip_bytes": 0, + "host": "www.opensearch.org", + "ip_count": 78, + "per_ip_bytes": 0, + "resp_code": "503", + "sum_bytes": 0, + }, + Object { + "double_per_ip_bytes": 11526, + "host": "cdn.opensearch-opensearch-opensearch.org", + "ip_count": 43, + "per_ip_bytes": 5763, + "resp_code": "404", + "sum_bytes": 247840, + }, + Object { + "double_per_ip_bytes": 0, + "host": "cdn.opensearch-opensearch-opensearch.org", + "ip_count": 34, + "per_ip_bytes": 0, + "resp_code": "503", + "sum_bytes": 0, + }, + Object { + "double_per_ip_bytes": 8882, + "host": "opensearch-opensearch-opensearch.org", + "ip_count": 13, + "per_ip_bytes": 4441, + "resp_code": "404", + "sum_bytes": 57735, + }, + Object { + "double_per_ip_bytes": 0, + "host": "opensearch-opensearch-opensearch.org", + "ip_count": 6, + "per_ip_bytes": 0, + "resp_code": "503", + "sum_bytes": 0, + }, + ], + "schema": Array [ + Object { + "name": "agent", + "type": "string", + }, + Object { + "name": "bytes", + "type": "long", + }, + Object { + "name": "clientip", + "type": "ip", + }, + Object { + "name": "event", + "type": "struct", + }, + Object { + "name": "extension", + "type": "string", + }, + Object { + "name": "geo", + "type": "struct", + }, + Object { + "name": "host", + "type": "string", + }, + Object { + "name": "index", + "type": "string", + }, + Object { + "name": "ip", + "type": "ip", + }, + Object { + "name": "machine", + "type": "struct", + }, + Object { + "name": "memory", + "type": "double", + }, + Object { + "name": "message", + "type": "string", + }, + Object { + "name": "phpmemory", + "type": "long", + }, + Object { + "name": "referer", + "type": "string", + }, + Object { + "name": "request", + "type": "string", + }, + Object { + "name": "response", + "type": "string", + }, + Object { + "name": "tags", + "type": "string", + }, + Object { + "name": "timestamp", + "type": "timestamp", + }, + Object { + "name": "url", + "type": "string", + }, + Object { + "name": "utc_time", + "type": "timestamp", + }, + ], + }, + }, + "indexFields": Object { + "availableFields": Array [ + Object { + "name": "agent", + "type": "string", + }, + Object { + "name": "bytes", + "type": "long", + }, + Object { + "name": "clientip", + "type": "ip", + }, + Object { + "name": "event", + "type": "struct", + }, Object { "name": "extension", "type": "string", @@ -6638,7 +7246,7 @@ exports[`Config panel component Renders config panel with visualization data 1`] }, Object { "component": [Function], - "defaultState": 2, + "defaultState": 0, "eleType": "slider", "mapTo": "lineWidth", "name": "Line width", @@ -6648,7 +7256,7 @@ exports[`Config panel component Renders config panel with visualization data 1`] }, Object { "component": [Function], - "defaultState": 70, + "defaultState": 100, "eleType": "slider", "mapTo": "fillOpacity", "name": "Fill opacity", @@ -6675,7 +7283,7 @@ exports[`Config panel component Renders config panel with visualization data 1`] }, ], }, - "fillopacity": 70, + "fillopacity": 100, "fulllabel": "Vertical bar", "groupwidth": 0.7, "icon": [Function], @@ -6684,7 +7292,7 @@ exports[`Config panel component Renders config panel with visualization data 1`] "label": "Vertical bar", "labelangle": 0, "legendposition": "v", - "linewidth": 2, + "linewidth": 0, "mode": "group", "name": "bar", "orientation": "v", @@ -6777,6 +7385,158 @@ exports[`Config panel component Renders config panel with visualization data 1`] "fromApp": false, }, "defaultAxes": Object {}, + "explorer": Object { + "explorerData": Object { + "jsonData": Array [ + Object { + "double_per_ip_bytes": 11606, + "host": "artifacts.opensearch.org", + "ip_count": 176, + "per_ip_bytes": 5803, + "resp_code": "404", + "sum_bytes": 1021420, + }, + Object { + "double_per_ip_bytes": 10100, + "host": "www.opensearch.org", + "ip_count": 111, + "per_ip_bytes": 5050, + "resp_code": "404", + "sum_bytes": 560638, + }, + Object { + "double_per_ip_bytes": 0, + "host": "artifacts.opensearch.org", + "ip_count": 94, + "per_ip_bytes": 0, + "resp_code": "503", + "sum_bytes": 0, + }, + Object { + "double_per_ip_bytes": 0, + "host": "www.opensearch.org", + "ip_count": 78, + "per_ip_bytes": 0, + "resp_code": "503", + "sum_bytes": 0, + }, + Object { + "double_per_ip_bytes": 11526, + "host": "cdn.opensearch-opensearch-opensearch.org", + "ip_count": 43, + "per_ip_bytes": 5763, + "resp_code": "404", + "sum_bytes": 247840, + }, + Object { + "double_per_ip_bytes": 0, + "host": "cdn.opensearch-opensearch-opensearch.org", + "ip_count": 34, + "per_ip_bytes": 0, + "resp_code": "503", + "sum_bytes": 0, + }, + Object { + "double_per_ip_bytes": 8882, + "host": "opensearch-opensearch-opensearch.org", + "ip_count": 13, + "per_ip_bytes": 4441, + "resp_code": "404", + "sum_bytes": 57735, + }, + Object { + "double_per_ip_bytes": 0, + "host": "opensearch-opensearch-opensearch.org", + "ip_count": 6, + "per_ip_bytes": 0, + "resp_code": "503", + "sum_bytes": 0, + }, + ], + "schema": Array [ + Object { + "name": "agent", + "type": "string", + }, + Object { + "name": "bytes", + "type": "long", + }, + Object { + "name": "clientip", + "type": "ip", + }, + Object { + "name": "event", + "type": "struct", + }, + Object { + "name": "extension", + "type": "string", + }, + Object { + "name": "geo", + "type": "struct", + }, + Object { + "name": "host", + "type": "string", + }, + Object { + "name": "index", + "type": "string", + }, + Object { + "name": "ip", + "type": "ip", + }, + Object { + "name": "machine", + "type": "struct", + }, + Object { + "name": "memory", + "type": "double", + }, + Object { + "name": "message", + "type": "string", + }, + Object { + "name": "phpmemory", + "type": "long", + }, + Object { + "name": "referer", + "type": "string", + }, + Object { + "name": "request", + "type": "string", + }, + Object { + "name": "response", + "type": "string", + }, + Object { + "name": "tags", + "type": "string", + }, + Object { + "name": "timestamp", + "type": "timestamp", + }, + Object { + "name": "url", + "type": "string", + }, + Object { + "name": "utc_time", + "type": "timestamp", + }, + ], + }, + }, "indexFields": Object { "availableFields": Array [ Object { @@ -7198,7 +7958,7 @@ exports[`Config panel component Renders config panel with visualization data 1`] }, Object { "component": [Function], - "defaultState": 2, + "defaultState": 0, "eleType": "slider", "mapTo": "lineWidth", "name": "Line width", @@ -7208,7 +7968,7 @@ exports[`Config panel component Renders config panel with visualization data 1`] }, Object { "component": [Function], - "defaultState": 70, + "defaultState": 100, "eleType": "slider", "mapTo": "fillOpacity", "name": "Fill opacity", @@ -7235,7 +7995,7 @@ exports[`Config panel component Renders config panel with visualization data 1`] }, ], }, - "fillopacity": 70, + "fillopacity": 100, "fulllabel": "Vertical bar", "groupwidth": 0.7, "icon": [Function], @@ -7244,7 +8004,7 @@ exports[`Config panel component Renders config panel with visualization data 1`] "label": "Vertical bar", "labelangle": 0, "legendposition": "v", - "linewidth": 2, + "linewidth": 0, "mode": "group", "name": "bar", "orientation": "v", @@ -7604,6 +8364,158 @@ exports[`Config panel component Renders config panel with visualization data 1`] "fromApp": false, }, "defaultAxes": Object {}, + "explorer": Object { + "explorerData": Object { + "jsonData": Array [ + Object { + "double_per_ip_bytes": 11606, + "host": "artifacts.opensearch.org", + "ip_count": 176, + "per_ip_bytes": 5803, + "resp_code": "404", + "sum_bytes": 1021420, + }, + Object { + "double_per_ip_bytes": 10100, + "host": "www.opensearch.org", + "ip_count": 111, + "per_ip_bytes": 5050, + "resp_code": "404", + "sum_bytes": 560638, + }, + Object { + "double_per_ip_bytes": 0, + "host": "artifacts.opensearch.org", + "ip_count": 94, + "per_ip_bytes": 0, + "resp_code": "503", + "sum_bytes": 0, + }, + Object { + "double_per_ip_bytes": 0, + "host": "www.opensearch.org", + "ip_count": 78, + "per_ip_bytes": 0, + "resp_code": "503", + "sum_bytes": 0, + }, + Object { + "double_per_ip_bytes": 11526, + "host": "cdn.opensearch-opensearch-opensearch.org", + "ip_count": 43, + "per_ip_bytes": 5763, + "resp_code": "404", + "sum_bytes": 247840, + }, + Object { + "double_per_ip_bytes": 0, + "host": "cdn.opensearch-opensearch-opensearch.org", + "ip_count": 34, + "per_ip_bytes": 0, + "resp_code": "503", + "sum_bytes": 0, + }, + Object { + "double_per_ip_bytes": 8882, + "host": "opensearch-opensearch-opensearch.org", + "ip_count": 13, + "per_ip_bytes": 4441, + "resp_code": "404", + "sum_bytes": 57735, + }, + Object { + "double_per_ip_bytes": 0, + "host": "opensearch-opensearch-opensearch.org", + "ip_count": 6, + "per_ip_bytes": 0, + "resp_code": "503", + "sum_bytes": 0, + }, + ], + "schema": Array [ + Object { + "name": "agent", + "type": "string", + }, + Object { + "name": "bytes", + "type": "long", + }, + Object { + "name": "clientip", + "type": "ip", + }, + Object { + "name": "event", + "type": "struct", + }, + Object { + "name": "extension", + "type": "string", + }, + Object { + "name": "geo", + "type": "struct", + }, + Object { + "name": "host", + "type": "string", + }, + Object { + "name": "index", + "type": "string", + }, + Object { + "name": "ip", + "type": "ip", + }, + Object { + "name": "machine", + "type": "struct", + }, + Object { + "name": "memory", + "type": "double", + }, + Object { + "name": "message", + "type": "string", + }, + Object { + "name": "phpmemory", + "type": "long", + }, + Object { + "name": "referer", + "type": "string", + }, + Object { + "name": "request", + "type": "string", + }, + Object { + "name": "response", + "type": "string", + }, + Object { + "name": "tags", + "type": "string", + }, + Object { + "name": "timestamp", + "type": "timestamp", + }, + Object { + "name": "url", + "type": "string", + }, + Object { + "name": "utc_time", + "type": "timestamp", + }, + ], + }, + }, "indexFields": Object { "availableFields": Array [ Object { @@ -8025,7 +8937,7 @@ exports[`Config panel component Renders config panel with visualization data 1`] }, Object { "component": [Function], - "defaultState": 2, + "defaultState": 0, "eleType": "slider", "mapTo": "lineWidth", "name": "Line width", @@ -8035,7 +8947,7 @@ exports[`Config panel component Renders config panel with visualization data 1`] }, Object { "component": [Function], - "defaultState": 70, + "defaultState": 100, "eleType": "slider", "mapTo": "fillOpacity", "name": "Fill opacity", @@ -8062,7 +8974,7 @@ exports[`Config panel component Renders config panel with visualization data 1`] }, ], }, - "fillopacity": 70, + "fillopacity": 100, "fulllabel": "Vertical bar", "groupwidth": 0.7, "icon": [Function], @@ -8071,7 +8983,7 @@ exports[`Config panel component Renders config panel with visualization data 1`] "label": "Vertical bar", "labelangle": 0, "legendposition": "v", - "linewidth": 2, + "linewidth": 0, "mode": "group", "name": "bar", "orientation": "v", @@ -8930,6 +9842,158 @@ exports[`Config panel component Renders config panel with visualization data 1`] "fromApp": false, }, "defaultAxes": Object {}, + "explorer": Object { + "explorerData": Object { + "jsonData": Array [ + Object { + "double_per_ip_bytes": 11606, + "host": "artifacts.opensearch.org", + "ip_count": 176, + "per_ip_bytes": 5803, + "resp_code": "404", + "sum_bytes": 1021420, + }, + Object { + "double_per_ip_bytes": 10100, + "host": "www.opensearch.org", + "ip_count": 111, + "per_ip_bytes": 5050, + "resp_code": "404", + "sum_bytes": 560638, + }, + Object { + "double_per_ip_bytes": 0, + "host": "artifacts.opensearch.org", + "ip_count": 94, + "per_ip_bytes": 0, + "resp_code": "503", + "sum_bytes": 0, + }, + Object { + "double_per_ip_bytes": 0, + "host": "www.opensearch.org", + "ip_count": 78, + "per_ip_bytes": 0, + "resp_code": "503", + "sum_bytes": 0, + }, + Object { + "double_per_ip_bytes": 11526, + "host": "cdn.opensearch-opensearch-opensearch.org", + "ip_count": 43, + "per_ip_bytes": 5763, + "resp_code": "404", + "sum_bytes": 247840, + }, + Object { + "double_per_ip_bytes": 0, + "host": "cdn.opensearch-opensearch-opensearch.org", + "ip_count": 34, + "per_ip_bytes": 0, + "resp_code": "503", + "sum_bytes": 0, + }, + Object { + "double_per_ip_bytes": 8882, + "host": "opensearch-opensearch-opensearch.org", + "ip_count": 13, + "per_ip_bytes": 4441, + "resp_code": "404", + "sum_bytes": 57735, + }, + Object { + "double_per_ip_bytes": 0, + "host": "opensearch-opensearch-opensearch.org", + "ip_count": 6, + "per_ip_bytes": 0, + "resp_code": "503", + "sum_bytes": 0, + }, + ], + "schema": Array [ + Object { + "name": "agent", + "type": "string", + }, + Object { + "name": "bytes", + "type": "long", + }, + Object { + "name": "clientip", + "type": "ip", + }, + Object { + "name": "event", + "type": "struct", + }, + Object { + "name": "extension", + "type": "string", + }, + Object { + "name": "geo", + "type": "struct", + }, + Object { + "name": "host", + "type": "string", + }, + Object { + "name": "index", + "type": "string", + }, + Object { + "name": "ip", + "type": "ip", + }, + Object { + "name": "machine", + "type": "struct", + }, + Object { + "name": "memory", + "type": "double", + }, + Object { + "name": "message", + "type": "string", + }, + Object { + "name": "phpmemory", + "type": "long", + }, + Object { + "name": "referer", + "type": "string", + }, + Object { + "name": "request", + "type": "string", + }, + Object { + "name": "response", + "type": "string", + }, + Object { + "name": "tags", + "type": "string", + }, + Object { + "name": "timestamp", + "type": "timestamp", + }, + Object { + "name": "url", + "type": "string", + }, + Object { + "name": "utc_time", + "type": "timestamp", + }, + ], + }, + }, "indexFields": Object { "availableFields": Array [ Object { @@ -9351,7 +10415,7 @@ exports[`Config panel component Renders config panel with visualization data 1`] }, Object { "component": [Function], - "defaultState": 2, + "defaultState": 0, "eleType": "slider", "mapTo": "lineWidth", "name": "Line width", @@ -9361,7 +10425,7 @@ exports[`Config panel component Renders config panel with visualization data 1`] }, Object { "component": [Function], - "defaultState": 70, + "defaultState": 100, "eleType": "slider", "mapTo": "fillOpacity", "name": "Fill opacity", @@ -9388,7 +10452,7 @@ exports[`Config panel component Renders config panel with visualization data 1`] }, ], }, - "fillopacity": 70, + "fillopacity": 100, "fulllabel": "Vertical bar", "groupwidth": 0.7, "icon": [Function], @@ -9397,7 +10461,7 @@ exports[`Config panel component Renders config panel with visualization data 1`] "label": "Vertical bar", "labelangle": 0, "legendposition": "v", - "linewidth": 2, + "linewidth": 0, "mode": "group", "name": "bar", "orientation": "v", @@ -10248,7 +11312,7 @@ exports[`Config panel component Renders config panel with visualization data 1`] }, Object { "component": [Function], - "defaultState": 2, + "defaultState": 0, "eleType": "slider", "mapTo": "lineWidth", "name": "Line width", @@ -10258,7 +11322,7 @@ exports[`Config panel component Renders config panel with visualization data 1`] }, Object { "component": [Function], - "defaultState": 70, + "defaultState": 100, "eleType": "slider", "mapTo": "fillOpacity", "name": "Fill opacity", @@ -10277,6 +11341,158 @@ exports[`Config panel component Renders config panel with visualization data 1`] "fromApp": false, }, "defaultAxes": Object {}, + "explorer": Object { + "explorerData": Object { + "jsonData": Array [ + Object { + "double_per_ip_bytes": 11606, + "host": "artifacts.opensearch.org", + "ip_count": 176, + "per_ip_bytes": 5803, + "resp_code": "404", + "sum_bytes": 1021420, + }, + Object { + "double_per_ip_bytes": 10100, + "host": "www.opensearch.org", + "ip_count": 111, + "per_ip_bytes": 5050, + "resp_code": "404", + "sum_bytes": 560638, + }, + Object { + "double_per_ip_bytes": 0, + "host": "artifacts.opensearch.org", + "ip_count": 94, + "per_ip_bytes": 0, + "resp_code": "503", + "sum_bytes": 0, + }, + Object { + "double_per_ip_bytes": 0, + "host": "www.opensearch.org", + "ip_count": 78, + "per_ip_bytes": 0, + "resp_code": "503", + "sum_bytes": 0, + }, + Object { + "double_per_ip_bytes": 11526, + "host": "cdn.opensearch-opensearch-opensearch.org", + "ip_count": 43, + "per_ip_bytes": 5763, + "resp_code": "404", + "sum_bytes": 247840, + }, + Object { + "double_per_ip_bytes": 0, + "host": "cdn.opensearch-opensearch-opensearch.org", + "ip_count": 34, + "per_ip_bytes": 0, + "resp_code": "503", + "sum_bytes": 0, + }, + Object { + "double_per_ip_bytes": 8882, + "host": "opensearch-opensearch-opensearch.org", + "ip_count": 13, + "per_ip_bytes": 4441, + "resp_code": "404", + "sum_bytes": 57735, + }, + Object { + "double_per_ip_bytes": 0, + "host": "opensearch-opensearch-opensearch.org", + "ip_count": 6, + "per_ip_bytes": 0, + "resp_code": "503", + "sum_bytes": 0, + }, + ], + "schema": Array [ + Object { + "name": "agent", + "type": "string", + }, + Object { + "name": "bytes", + "type": "long", + }, + Object { + "name": "clientip", + "type": "ip", + }, + Object { + "name": "event", + "type": "struct", + }, + Object { + "name": "extension", + "type": "string", + }, + Object { + "name": "geo", + "type": "struct", + }, + Object { + "name": "host", + "type": "string", + }, + Object { + "name": "index", + "type": "string", + }, + Object { + "name": "ip", + "type": "ip", + }, + Object { + "name": "machine", + "type": "struct", + }, + Object { + "name": "memory", + "type": "double", + }, + Object { + "name": "message", + "type": "string", + }, + Object { + "name": "phpmemory", + "type": "long", + }, + Object { + "name": "referer", + "type": "string", + }, + Object { + "name": "request", + "type": "string", + }, + Object { + "name": "response", + "type": "string", + }, + Object { + "name": "tags", + "type": "string", + }, + Object { + "name": "timestamp", + "type": "timestamp", + }, + Object { + "name": "url", + "type": "string", + }, + Object { + "name": "utc_time", + "type": "timestamp", + }, + ], + }, + }, "indexFields": Object { "availableFields": Array [ Object { @@ -10698,7 +11914,7 @@ exports[`Config panel component Renders config panel with visualization data 1`] }, Object { "component": [Function], - "defaultState": 2, + "defaultState": 0, "eleType": "slider", "mapTo": "lineWidth", "name": "Line width", @@ -10708,7 +11924,7 @@ exports[`Config panel component Renders config panel with visualization data 1`] }, Object { "component": [Function], - "defaultState": 70, + "defaultState": 100, "eleType": "slider", "mapTo": "fillOpacity", "name": "Fill opacity", @@ -10735,7 +11951,7 @@ exports[`Config panel component Renders config panel with visualization data 1`] }, ], }, - "fillopacity": 70, + "fillopacity": 100, "fulllabel": "Vertical bar", "groupwidth": 0.7, "icon": [Function], @@ -10744,7 +11960,7 @@ exports[`Config panel component Renders config panel with visualization data 1`] "label": "Vertical bar", "labelangle": 0, "legendposition": "v", - "linewidth": 2, + "linewidth": 0, "mode": "group", "name": "bar", "orientation": "v", @@ -12667,7 +13883,7 @@ exports[`Config panel component Renders config panel with visualization data 1`] />
@@ -12835,7 +14051,7 @@ exports[`Config panel component Renders config panel with visualization data 1`] name="Line width" onChange={[Function]} step={1} - value={2} + value={0} >
@@ -13076,7 +14292,7 @@ exports[`Config panel component Renders config panel with visualization data 1`] name="Fill opacity" onChange={[Function]} step={1} - value={70} + value={100} > - -
- -
- -
- - - - - - -
- -

- Invalid data, heatmap can only have exact 2 dimensions and 1 series -

-
- -
- -
- - + id="explorerPlotComponent" + style={ + Object { + "height": "100%", + "width": "100%", + } + } + /> + + `; diff --git a/public/components/visualizations/charts/__tests__/__snapshots__/histogram.test.tsx.snap b/public/components/visualizations/charts/__tests__/__snapshots__/histogram.test.tsx.snap index 419ff3c03b..9710a10004 100644 --- a/public/components/visualizations/charts/__tests__/__snapshots__/histogram.test.tsx.snap +++ b/public/components/visualizations/charts/__tests__/__snapshots__/histogram.test.tsx.snap @@ -26,6 +26,158 @@ exports[`Histogram component Renders histogram component 1`] = ` "fromApp": false, }, "defaultAxes": Object {}, + "explorer": Object { + "explorerData": Object { + "jsonData": Array [ + Object { + "double_per_ip_bytes": 11606, + "host": "artifacts.opensearch.org", + "ip_count": 176, + "per_ip_bytes": 5803, + "resp_code": "404", + "sum_bytes": 1021420, + }, + Object { + "double_per_ip_bytes": 10100, + "host": "www.opensearch.org", + "ip_count": 111, + "per_ip_bytes": 5050, + "resp_code": "404", + "sum_bytes": 560638, + }, + Object { + "double_per_ip_bytes": 0, + "host": "artifacts.opensearch.org", + "ip_count": 94, + "per_ip_bytes": 0, + "resp_code": "503", + "sum_bytes": 0, + }, + Object { + "double_per_ip_bytes": 0, + "host": "www.opensearch.org", + "ip_count": 78, + "per_ip_bytes": 0, + "resp_code": "503", + "sum_bytes": 0, + }, + Object { + "double_per_ip_bytes": 11526, + "host": "cdn.opensearch-opensearch-opensearch.org", + "ip_count": 43, + "per_ip_bytes": 5763, + "resp_code": "404", + "sum_bytes": 247840, + }, + Object { + "double_per_ip_bytes": 0, + "host": "cdn.opensearch-opensearch-opensearch.org", + "ip_count": 34, + "per_ip_bytes": 0, + "resp_code": "503", + "sum_bytes": 0, + }, + Object { + "double_per_ip_bytes": 8882, + "host": "opensearch-opensearch-opensearch.org", + "ip_count": 13, + "per_ip_bytes": 4441, + "resp_code": "404", + "sum_bytes": 57735, + }, + Object { + "double_per_ip_bytes": 0, + "host": "opensearch-opensearch-opensearch.org", + "ip_count": 6, + "per_ip_bytes": 0, + "resp_code": "503", + "sum_bytes": 0, + }, + ], + "schema": Array [ + Object { + "name": "agent", + "type": "string", + }, + Object { + "name": "bytes", + "type": "long", + }, + Object { + "name": "clientip", + "type": "ip", + }, + Object { + "name": "event", + "type": "struct", + }, + Object { + "name": "extension", + "type": "string", + }, + Object { + "name": "geo", + "type": "struct", + }, + Object { + "name": "host", + "type": "string", + }, + Object { + "name": "index", + "type": "string", + }, + Object { + "name": "ip", + "type": "ip", + }, + Object { + "name": "machine", + "type": "struct", + }, + Object { + "name": "memory", + "type": "double", + }, + Object { + "name": "message", + "type": "string", + }, + Object { + "name": "phpmemory", + "type": "long", + }, + Object { + "name": "referer", + "type": "string", + }, + Object { + "name": "request", + "type": "string", + }, + Object { + "name": "response", + "type": "string", + }, + Object { + "name": "tags", + "type": "string", + }, + Object { + "name": "timestamp", + "type": "timestamp", + }, + Object { + "name": "url", + "type": "string", + }, + Object { + "name": "utc_time", + "type": "timestamp", + }, + ], + }, + }, "indexFields": Object { "availableFields": Array [ Object { @@ -447,7 +599,7 @@ exports[`Histogram component Renders histogram component 1`] = ` }, Object { "component": [Function], - "defaultState": 2, + "defaultState": 0, "eleType": "slider", "mapTo": "lineWidth", "name": "Line width", @@ -457,7 +609,7 @@ exports[`Histogram component Renders histogram component 1`] = ` }, Object { "component": [Function], - "defaultState": 70, + "defaultState": 100, "eleType": "slider", "mapTo": "fillOpacity", "name": "Fill opacity", @@ -484,7 +636,7 @@ exports[`Histogram component Renders histogram component 1`] = ` }, ], }, - "fillopacity": 70, + "fillopacity": 100, "fulllabel": "Vertical bar", "groupwidth": 0.7, "icon": [Function], @@ -493,7 +645,7 @@ exports[`Histogram component Renders histogram component 1`] = ` "label": "Vertical bar", "labelangle": 0, "legendposition": "v", - "linewidth": 2, + "linewidth": 0, "mode": "group", "name": "bar", "orientation": "v", @@ -536,10 +688,10 @@ exports[`Histogram component Renders histogram component 1`] = ` Object { "hoverinfo": "all", "marker": Object { - "color": "rgba(60,161,199,0.35)", + "color": "rgba(60,161,199,0.5)", "line": Object { "color": "rgba(60,161,199,1)", - "width": 2, + "width": 0, }, }, "name": "count()", @@ -589,10 +741,10 @@ exports[`Histogram component Renders histogram component 1`] = ` Object { "hoverinfo": "all", "marker": Object { - "color": "rgba(60,161,199,0.35)", + "color": "rgba(60,161,199,0.5)", "line": Object { "color": "rgba(60,161,199,1)", - "width": 2, + "width": 0, }, }, "name": "count()", diff --git a/public/components/visualizations/charts/__tests__/__snapshots__/horizontal_bar.test.tsx.snap b/public/components/visualizations/charts/__tests__/__snapshots__/horizontal_bar.test.tsx.snap index e9a120c071..0049049be4 100644 --- a/public/components/visualizations/charts/__tests__/__snapshots__/horizontal_bar.test.tsx.snap +++ b/public/components/visualizations/charts/__tests__/__snapshots__/horizontal_bar.test.tsx.snap @@ -26,6 +26,158 @@ exports[`Horizontal bar component Renders horizontal bar component 1`] = ` "fromApp": false, }, "defaultAxes": Object {}, + "explorer": Object { + "explorerData": Object { + "jsonData": Array [ + Object { + "double_per_ip_bytes": 11606, + "host": "artifacts.opensearch.org", + "ip_count": 176, + "per_ip_bytes": 5803, + "resp_code": "404", + "sum_bytes": 1021420, + }, + Object { + "double_per_ip_bytes": 10100, + "host": "www.opensearch.org", + "ip_count": 111, + "per_ip_bytes": 5050, + "resp_code": "404", + "sum_bytes": 560638, + }, + Object { + "double_per_ip_bytes": 0, + "host": "artifacts.opensearch.org", + "ip_count": 94, + "per_ip_bytes": 0, + "resp_code": "503", + "sum_bytes": 0, + }, + Object { + "double_per_ip_bytes": 0, + "host": "www.opensearch.org", + "ip_count": 78, + "per_ip_bytes": 0, + "resp_code": "503", + "sum_bytes": 0, + }, + Object { + "double_per_ip_bytes": 11526, + "host": "cdn.opensearch-opensearch-opensearch.org", + "ip_count": 43, + "per_ip_bytes": 5763, + "resp_code": "404", + "sum_bytes": 247840, + }, + Object { + "double_per_ip_bytes": 0, + "host": "cdn.opensearch-opensearch-opensearch.org", + "ip_count": 34, + "per_ip_bytes": 0, + "resp_code": "503", + "sum_bytes": 0, + }, + Object { + "double_per_ip_bytes": 8882, + "host": "opensearch-opensearch-opensearch.org", + "ip_count": 13, + "per_ip_bytes": 4441, + "resp_code": "404", + "sum_bytes": 57735, + }, + Object { + "double_per_ip_bytes": 0, + "host": "opensearch-opensearch-opensearch.org", + "ip_count": 6, + "per_ip_bytes": 0, + "resp_code": "503", + "sum_bytes": 0, + }, + ], + "schema": Array [ + Object { + "name": "agent", + "type": "string", + }, + Object { + "name": "bytes", + "type": "long", + }, + Object { + "name": "clientip", + "type": "ip", + }, + Object { + "name": "event", + "type": "struct", + }, + Object { + "name": "extension", + "type": "string", + }, + Object { + "name": "geo", + "type": "struct", + }, + Object { + "name": "host", + "type": "string", + }, + Object { + "name": "index", + "type": "string", + }, + Object { + "name": "ip", + "type": "ip", + }, + Object { + "name": "machine", + "type": "struct", + }, + Object { + "name": "memory", + "type": "double", + }, + Object { + "name": "message", + "type": "string", + }, + Object { + "name": "phpmemory", + "type": "long", + }, + Object { + "name": "referer", + "type": "string", + }, + Object { + "name": "request", + "type": "string", + }, + Object { + "name": "response", + "type": "string", + }, + Object { + "name": "tags", + "type": "string", + }, + Object { + "name": "timestamp", + "type": "timestamp", + }, + Object { + "name": "url", + "type": "string", + }, + Object { + "name": "utc_time", + "type": "timestamp", + }, + ], + }, + }, "indexFields": Object { "availableFields": Array [ Object { @@ -447,7 +599,7 @@ exports[`Horizontal bar component Renders horizontal bar component 1`] = ` }, Object { "component": [Function], - "defaultState": 2, + "defaultState": 0, "eleType": "slider", "mapTo": "lineWidth", "name": "Line width", @@ -457,7 +609,7 @@ exports[`Horizontal bar component Renders horizontal bar component 1`] = ` }, Object { "component": [Function], - "defaultState": 70, + "defaultState": 100, "eleType": "slider", "mapTo": "fillOpacity", "name": "Fill opacity", @@ -484,7 +636,7 @@ exports[`Horizontal bar component Renders horizontal bar component 1`] = ` }, ], }, - "fillopacity": 70, + "fillopacity": 100, "fulllabel": "Horizontal bar", "groupwidth": 0.7, "icon": [Function], @@ -493,7 +645,7 @@ exports[`Horizontal bar component Renders horizontal bar component 1`] = ` "label": "Horizontal bar", "labelangle": 0, "legendposition": "v", - "linewidth": 2, + "linewidth": 0, "mode": "group", "name": "horizontal_bar", "orientation": "h", diff --git a/public/components/visualizations/charts/__tests__/__snapshots__/line.test.tsx.snap b/public/components/visualizations/charts/__tests__/__snapshots__/line.test.tsx.snap index c87a070c8f..8a495d3f97 100644 --- a/public/components/visualizations/charts/__tests__/__snapshots__/line.test.tsx.snap +++ b/public/components/visualizations/charts/__tests__/__snapshots__/line.test.tsx.snap @@ -26,6 +26,158 @@ exports[`Line component Renders line component 1`] = ` "fromApp": false, }, "defaultAxes": Object {}, + "explorer": Object { + "explorerData": Object { + "jsonData": Array [ + Object { + "double_per_ip_bytes": 11606, + "host": "artifacts.opensearch.org", + "ip_count": 176, + "per_ip_bytes": 5803, + "resp_code": "404", + "sum_bytes": 1021420, + }, + Object { + "double_per_ip_bytes": 10100, + "host": "www.opensearch.org", + "ip_count": 111, + "per_ip_bytes": 5050, + "resp_code": "404", + "sum_bytes": 560638, + }, + Object { + "double_per_ip_bytes": 0, + "host": "artifacts.opensearch.org", + "ip_count": 94, + "per_ip_bytes": 0, + "resp_code": "503", + "sum_bytes": 0, + }, + Object { + "double_per_ip_bytes": 0, + "host": "www.opensearch.org", + "ip_count": 78, + "per_ip_bytes": 0, + "resp_code": "503", + "sum_bytes": 0, + }, + Object { + "double_per_ip_bytes": 11526, + "host": "cdn.opensearch-opensearch-opensearch.org", + "ip_count": 43, + "per_ip_bytes": 5763, + "resp_code": "404", + "sum_bytes": 247840, + }, + Object { + "double_per_ip_bytes": 0, + "host": "cdn.opensearch-opensearch-opensearch.org", + "ip_count": 34, + "per_ip_bytes": 0, + "resp_code": "503", + "sum_bytes": 0, + }, + Object { + "double_per_ip_bytes": 8882, + "host": "opensearch-opensearch-opensearch.org", + "ip_count": 13, + "per_ip_bytes": 4441, + "resp_code": "404", + "sum_bytes": 57735, + }, + Object { + "double_per_ip_bytes": 0, + "host": "opensearch-opensearch-opensearch.org", + "ip_count": 6, + "per_ip_bytes": 0, + "resp_code": "503", + "sum_bytes": 0, + }, + ], + "schema": Array [ + Object { + "name": "agent", + "type": "string", + }, + Object { + "name": "bytes", + "type": "long", + }, + Object { + "name": "clientip", + "type": "ip", + }, + Object { + "name": "event", + "type": "struct", + }, + Object { + "name": "extension", + "type": "string", + }, + Object { + "name": "geo", + "type": "struct", + }, + Object { + "name": "host", + "type": "string", + }, + Object { + "name": "index", + "type": "string", + }, + Object { + "name": "ip", + "type": "ip", + }, + Object { + "name": "machine", + "type": "struct", + }, + Object { + "name": "memory", + "type": "double", + }, + Object { + "name": "message", + "type": "string", + }, + Object { + "name": "phpmemory", + "type": "long", + }, + Object { + "name": "referer", + "type": "string", + }, + Object { + "name": "request", + "type": "string", + }, + Object { + "name": "response", + "type": "string", + }, + Object { + "name": "tags", + "type": "string", + }, + Object { + "name": "timestamp", + "type": "timestamp", + }, + Object { + "name": "url", + "type": "string", + }, + Object { + "name": "utc_time", + "type": "timestamp", + }, + ], + }, + }, "indexFields": Object { "availableFields": Array [ Object { @@ -447,7 +599,7 @@ exports[`Line component Renders line component 1`] = ` }, Object { "component": [Function], - "defaultState": 2, + "defaultState": 0, "eleType": "slider", "mapTo": "lineWidth", "name": "Line width", @@ -457,7 +609,7 @@ exports[`Line component Renders line component 1`] = ` }, Object { "component": [Function], - "defaultState": 70, + "defaultState": 100, "eleType": "slider", "mapTo": "fillOpacity", "name": "Fill opacity", @@ -484,7 +636,7 @@ exports[`Line component Renders line component 1`] = ` }, ], }, - "fillopacity": 70, + "fillopacity": 100, "fulllabel": "Vertical bar", "groupwidth": 0.7, "icon": [Function], @@ -493,7 +645,7 @@ exports[`Line component Renders line component 1`] = ` "label": "Vertical bar", "labelangle": 0, "legendposition": "v", - "linewidth": 2, + "linewidth": 0, "mode": "group", "name": "bar", "orientation": "v", diff --git a/public/components/visualizations/charts/__tests__/__snapshots__/logs_view.test.tsx.snap b/public/components/visualizations/charts/__tests__/__snapshots__/logs_view.test.tsx.snap index cd618eefc6..b1885bd3d6 100644 --- a/public/components/visualizations/charts/__tests__/__snapshots__/logs_view.test.tsx.snap +++ b/public/components/visualizations/charts/__tests__/__snapshots__/logs_view.test.tsx.snap @@ -26,6 +26,158 @@ exports[`Logs View component Renders logs view component 1`] = ` "fromApp": false, }, "defaultAxes": Object {}, + "explorer": Object { + "explorerData": Object { + "jsonData": Array [ + Object { + "double_per_ip_bytes": 11606, + "host": "artifacts.opensearch.org", + "ip_count": 176, + "per_ip_bytes": 5803, + "resp_code": "404", + "sum_bytes": 1021420, + }, + Object { + "double_per_ip_bytes": 10100, + "host": "www.opensearch.org", + "ip_count": 111, + "per_ip_bytes": 5050, + "resp_code": "404", + "sum_bytes": 560638, + }, + Object { + "double_per_ip_bytes": 0, + "host": "artifacts.opensearch.org", + "ip_count": 94, + "per_ip_bytes": 0, + "resp_code": "503", + "sum_bytes": 0, + }, + Object { + "double_per_ip_bytes": 0, + "host": "www.opensearch.org", + "ip_count": 78, + "per_ip_bytes": 0, + "resp_code": "503", + "sum_bytes": 0, + }, + Object { + "double_per_ip_bytes": 11526, + "host": "cdn.opensearch-opensearch-opensearch.org", + "ip_count": 43, + "per_ip_bytes": 5763, + "resp_code": "404", + "sum_bytes": 247840, + }, + Object { + "double_per_ip_bytes": 0, + "host": "cdn.opensearch-opensearch-opensearch.org", + "ip_count": 34, + "per_ip_bytes": 0, + "resp_code": "503", + "sum_bytes": 0, + }, + Object { + "double_per_ip_bytes": 8882, + "host": "opensearch-opensearch-opensearch.org", + "ip_count": 13, + "per_ip_bytes": 4441, + "resp_code": "404", + "sum_bytes": 57735, + }, + Object { + "double_per_ip_bytes": 0, + "host": "opensearch-opensearch-opensearch.org", + "ip_count": 6, + "per_ip_bytes": 0, + "resp_code": "503", + "sum_bytes": 0, + }, + ], + "schema": Array [ + Object { + "name": "agent", + "type": "string", + }, + Object { + "name": "bytes", + "type": "long", + }, + Object { + "name": "clientip", + "type": "ip", + }, + Object { + "name": "event", + "type": "struct", + }, + Object { + "name": "extension", + "type": "string", + }, + Object { + "name": "geo", + "type": "struct", + }, + Object { + "name": "host", + "type": "string", + }, + Object { + "name": "index", + "type": "string", + }, + Object { + "name": "ip", + "type": "ip", + }, + Object { + "name": "machine", + "type": "struct", + }, + Object { + "name": "memory", + "type": "double", + }, + Object { + "name": "message", + "type": "string", + }, + Object { + "name": "phpmemory", + "type": "long", + }, + Object { + "name": "referer", + "type": "string", + }, + Object { + "name": "request", + "type": "string", + }, + Object { + "name": "response", + "type": "string", + }, + Object { + "name": "tags", + "type": "string", + }, + Object { + "name": "timestamp", + "type": "timestamp", + }, + Object { + "name": "url", + "type": "string", + }, + Object { + "name": "utc_time", + "type": "timestamp", + }, + ], + }, + }, "indexFields": Object { "availableFields": Array [ Object { @@ -447,7 +599,7 @@ exports[`Logs View component Renders logs view component 1`] = ` }, Object { "component": [Function], - "defaultState": 2, + "defaultState": 0, "eleType": "slider", "mapTo": "lineWidth", "name": "Line width", @@ -457,7 +609,7 @@ exports[`Logs View component Renders logs view component 1`] = ` }, Object { "component": [Function], - "defaultState": 70, + "defaultState": 100, "eleType": "slider", "mapTo": "fillOpacity", "name": "Fill opacity", @@ -484,7 +636,7 @@ exports[`Logs View component Renders logs view component 1`] = ` }, ], }, - "fillopacity": 70, + "fillopacity": 100, "fulllabel": "Vertical bar", "groupwidth": 0.7, "icon": [Function], @@ -493,7 +645,7 @@ exports[`Logs View component Renders logs view component 1`] = ` "label": "Vertical bar", "labelangle": 0, "legendposition": "v", - "linewidth": 2, + "linewidth": 0, "mode": "group", "name": "bar", "orientation": "v", @@ -542,7 +694,74 @@ exports[`Logs View component Renders logs view component 1`] = ` } } rawQuery="" - rows={Array []} + rows={ + Array [ + Object { + "double_per_ip_bytes": 11606, + "host": "artifacts.opensearch.org", + "ip_count": 176, + "per_ip_bytes": 5803, + "resp_code": "404", + "sum_bytes": 1021420, + }, + Object { + "double_per_ip_bytes": 10100, + "host": "www.opensearch.org", + "ip_count": 111, + "per_ip_bytes": 5050, + "resp_code": "404", + "sum_bytes": 560638, + }, + Object { + "double_per_ip_bytes": 0, + "host": "artifacts.opensearch.org", + "ip_count": 94, + "per_ip_bytes": 0, + "resp_code": "503", + "sum_bytes": 0, + }, + Object { + "double_per_ip_bytes": 0, + "host": "www.opensearch.org", + "ip_count": 78, + "per_ip_bytes": 0, + "resp_code": "503", + "sum_bytes": 0, + }, + Object { + "double_per_ip_bytes": 11526, + "host": "cdn.opensearch-opensearch-opensearch.org", + "ip_count": 43, + "per_ip_bytes": 5763, + "resp_code": "404", + "sum_bytes": 247840, + }, + Object { + "double_per_ip_bytes": 0, + "host": "cdn.opensearch-opensearch-opensearch.org", + "ip_count": 34, + "per_ip_bytes": 0, + "resp_code": "503", + "sum_bytes": 0, + }, + Object { + "double_per_ip_bytes": 8882, + "host": "opensearch-opensearch-opensearch.org", + "ip_count": 13, + "per_ip_bytes": 4441, + "resp_code": "404", + "sum_bytes": 57735, + }, + Object { + "double_per_ip_bytes": 0, + "host": "opensearch-opensearch-opensearch.org", + "ip_count": 6, + "per_ip_bytes": 0, + "resp_code": "503", + "sum_bytes": 0, + }, + ] + } rowsAll={Array []} timeStampField="" > @@ -572,7 +791,1360 @@ exports[`Logs View component Renders logs view component 1`] = ` - + + + + + + + + + +
+ +
+ +
+ ip_count + : +
+
+ + 176 + +
+
+ +
+ sum_bytes + : +
+
+ + 1021420 + +
+
+ +
+ host + : +
+
+ + artifacts.opensearch.org + +
+
+ +
+ resp_code + : +
+
+ + 404 + +
+
+ +
+ per_ip_bytes + : +
+
+ + 5803 + +
+
+ +
+ double_per_ip_bytes + : +
+
+ + 11606 + +
+
+
+
+
+ + +
+ + + + + + + + +
+ +
+ +
+ ip_count + : +
+
+ + 111 + +
+
+ +
+ sum_bytes + : +
+
+ + 560638 + +
+
+ +
+ host + : +
+
+ + www.opensearch.org + +
+
+ +
+ resp_code + : +
+
+ + 404 + +
+
+ +
+ per_ip_bytes + : +
+
+ + 5050 + +
+
+ +
+ double_per_ip_bytes + : +
+
+ + 10100 + +
+
+
+
+
+ + +
+ + + + + + + + +
+ +
+ +
+ ip_count + : +
+
+ + 94 + +
+
+ +
+ sum_bytes + : +
+
+ + 0 + +
+
+ +
+ host + : +
+
+ + artifacts.opensearch.org + +
+
+ +
+ resp_code + : +
+
+ + 503 + +
+
+ +
+ per_ip_bytes + : +
+
+ + 0 + +
+
+ +
+ double_per_ip_bytes + : +
+
+ + 0 + +
+
+
+
+
+ + +
+ + + + + + + + +
+ +
+ +
+ ip_count + : +
+
+ + 78 + +
+
+ +
+ sum_bytes + : +
+
+ + 0 + +
+
+ +
+ host + : +
+
+ + www.opensearch.org + +
+
+ +
+ resp_code + : +
+
+ + 503 + +
+
+ +
+ per_ip_bytes + : +
+
+ + 0 + +
+
+ +
+ double_per_ip_bytes + : +
+
+ + 0 + +
+
+
+
+
+ + +
+ + + + + + + + +
+ +
+ +
+ ip_count + : +
+
+ + 43 + +
+
+ +
+ sum_bytes + : +
+
+ + 247840 + +
+
+ +
+ host + : +
+
+ + cdn.opensearch-opensearch-opensearch.org + +
+
+ +
+ resp_code + : +
+
+ + 404 + +
+
+ +
+ per_ip_bytes + : +
+
+ + 5763 + +
+
+ +
+ double_per_ip_bytes + : +
+
+ + 11526 + +
+
+
+
+
+ + +
+ + + + + + + + +
+ +
+ +
+ ip_count + : +
+
+ + 34 + +
+
+ +
+ sum_bytes + : +
+
+ + 0 + +
+
+ +
+ host + : +
+
+ + cdn.opensearch-opensearch-opensearch.org + +
+
+ +
+ resp_code + : +
+
+ + 503 + +
+
+ +
+ per_ip_bytes + : +
+
+ + 0 + +
+
+ +
+ double_per_ip_bytes + : +
+
+ + 0 + +
+
+
+
+
+ + +
+ + + + + + + + +
+ +
+ +
+ ip_count + : +
+
+ + 13 + +
+
+ +
+ sum_bytes + : +
+
+ + 57735 + +
+
+ +
+ host + : +
+
+ + opensearch-opensearch-opensearch.org + +
+
+ +
+ resp_code + : +
+
+ + 404 + +
+
+ +
+ per_ip_bytes + : +
+
+ + 4441 + +
+
+ +
+ double_per_ip_bytes + : +
+
+ + 8882 + +
+
+
+
+
+ + +
+ + + + + + + + +
+ +
+ +
+ ip_count + : +
+
+ + 6 + +
+
+ +
+ sum_bytes + : +
+
+ + 0 + +
+
+ +
+ host + : +
+
+ + opensearch-opensearch-opensearch.org + +
+
+ +
+ resp_code + : +
+
+ + 503 + +
+
+ +
+ per_ip_bytes + : +
+
+ + 0 + +
+
+ +
+ double_per_ip_bytes + : +
+
+ + 0 + +
+
+
+
+
+ + +
+
diff --git a/public/components/visualizations/charts/__tests__/__snapshots__/metrics.test.tsx.snap b/public/components/visualizations/charts/__tests__/__snapshots__/metrics.test.tsx.snap index c001a02af1..551cc8879b 100644 --- a/public/components/visualizations/charts/__tests__/__snapshots__/metrics.test.tsx.snap +++ b/public/components/visualizations/charts/__tests__/__snapshots__/metrics.test.tsx.snap @@ -26,6 +26,158 @@ exports[`Metrics component Renders Metrics component 1`] = ` "fromApp": false, }, "defaultAxes": Object {}, + "explorer": Object { + "explorerData": Object { + "jsonData": Array [ + Object { + "double_per_ip_bytes": 11606, + "host": "artifacts.opensearch.org", + "ip_count": 176, + "per_ip_bytes": 5803, + "resp_code": "404", + "sum_bytes": 1021420, + }, + Object { + "double_per_ip_bytes": 10100, + "host": "www.opensearch.org", + "ip_count": 111, + "per_ip_bytes": 5050, + "resp_code": "404", + "sum_bytes": 560638, + }, + Object { + "double_per_ip_bytes": 0, + "host": "artifacts.opensearch.org", + "ip_count": 94, + "per_ip_bytes": 0, + "resp_code": "503", + "sum_bytes": 0, + }, + Object { + "double_per_ip_bytes": 0, + "host": "www.opensearch.org", + "ip_count": 78, + "per_ip_bytes": 0, + "resp_code": "503", + "sum_bytes": 0, + }, + Object { + "double_per_ip_bytes": 11526, + "host": "cdn.opensearch-opensearch-opensearch.org", + "ip_count": 43, + "per_ip_bytes": 5763, + "resp_code": "404", + "sum_bytes": 247840, + }, + Object { + "double_per_ip_bytes": 0, + "host": "cdn.opensearch-opensearch-opensearch.org", + "ip_count": 34, + "per_ip_bytes": 0, + "resp_code": "503", + "sum_bytes": 0, + }, + Object { + "double_per_ip_bytes": 8882, + "host": "opensearch-opensearch-opensearch.org", + "ip_count": 13, + "per_ip_bytes": 4441, + "resp_code": "404", + "sum_bytes": 57735, + }, + Object { + "double_per_ip_bytes": 0, + "host": "opensearch-opensearch-opensearch.org", + "ip_count": 6, + "per_ip_bytes": 0, + "resp_code": "503", + "sum_bytes": 0, + }, + ], + "schema": Array [ + Object { + "name": "agent", + "type": "string", + }, + Object { + "name": "bytes", + "type": "long", + }, + Object { + "name": "clientip", + "type": "ip", + }, + Object { + "name": "event", + "type": "struct", + }, + Object { + "name": "extension", + "type": "string", + }, + Object { + "name": "geo", + "type": "struct", + }, + Object { + "name": "host", + "type": "string", + }, + Object { + "name": "index", + "type": "string", + }, + Object { + "name": "ip", + "type": "ip", + }, + Object { + "name": "machine", + "type": "struct", + }, + Object { + "name": "memory", + "type": "double", + }, + Object { + "name": "message", + "type": "string", + }, + Object { + "name": "phpmemory", + "type": "long", + }, + Object { + "name": "referer", + "type": "string", + }, + Object { + "name": "request", + "type": "string", + }, + Object { + "name": "response", + "type": "string", + }, + Object { + "name": "tags", + "type": "string", + }, + Object { + "name": "timestamp", + "type": "timestamp", + }, + Object { + "name": "url", + "type": "string", + }, + Object { + "name": "utc_time", + "type": "timestamp", + }, + ], + }, + }, "indexFields": Object { "availableFields": Array [ Object { diff --git a/public/components/visualizations/charts/__tests__/__snapshots__/pie.test.tsx.snap b/public/components/visualizations/charts/__tests__/__snapshots__/pie.test.tsx.snap index 6a90d37ef5..9103460eaa 100644 --- a/public/components/visualizations/charts/__tests__/__snapshots__/pie.test.tsx.snap +++ b/public/components/visualizations/charts/__tests__/__snapshots__/pie.test.tsx.snap @@ -26,6 +26,158 @@ exports[`Pie component Renders pie component 1`] = ` "fromApp": false, }, "defaultAxes": Object {}, + "explorer": Object { + "explorerData": Object { + "jsonData": Array [ + Object { + "double_per_ip_bytes": 11606, + "host": "artifacts.opensearch.org", + "ip_count": 176, + "per_ip_bytes": 5803, + "resp_code": "404", + "sum_bytes": 1021420, + }, + Object { + "double_per_ip_bytes": 10100, + "host": "www.opensearch.org", + "ip_count": 111, + "per_ip_bytes": 5050, + "resp_code": "404", + "sum_bytes": 560638, + }, + Object { + "double_per_ip_bytes": 0, + "host": "artifacts.opensearch.org", + "ip_count": 94, + "per_ip_bytes": 0, + "resp_code": "503", + "sum_bytes": 0, + }, + Object { + "double_per_ip_bytes": 0, + "host": "www.opensearch.org", + "ip_count": 78, + "per_ip_bytes": 0, + "resp_code": "503", + "sum_bytes": 0, + }, + Object { + "double_per_ip_bytes": 11526, + "host": "cdn.opensearch-opensearch-opensearch.org", + "ip_count": 43, + "per_ip_bytes": 5763, + "resp_code": "404", + "sum_bytes": 247840, + }, + Object { + "double_per_ip_bytes": 0, + "host": "cdn.opensearch-opensearch-opensearch.org", + "ip_count": 34, + "per_ip_bytes": 0, + "resp_code": "503", + "sum_bytes": 0, + }, + Object { + "double_per_ip_bytes": 8882, + "host": "opensearch-opensearch-opensearch.org", + "ip_count": 13, + "per_ip_bytes": 4441, + "resp_code": "404", + "sum_bytes": 57735, + }, + Object { + "double_per_ip_bytes": 0, + "host": "opensearch-opensearch-opensearch.org", + "ip_count": 6, + "per_ip_bytes": 0, + "resp_code": "503", + "sum_bytes": 0, + }, + ], + "schema": Array [ + Object { + "name": "agent", + "type": "string", + }, + Object { + "name": "bytes", + "type": "long", + }, + Object { + "name": "clientip", + "type": "ip", + }, + Object { + "name": "event", + "type": "struct", + }, + Object { + "name": "extension", + "type": "string", + }, + Object { + "name": "geo", + "type": "struct", + }, + Object { + "name": "host", + "type": "string", + }, + Object { + "name": "index", + "type": "string", + }, + Object { + "name": "ip", + "type": "ip", + }, + Object { + "name": "machine", + "type": "struct", + }, + Object { + "name": "memory", + "type": "double", + }, + Object { + "name": "message", + "type": "string", + }, + Object { + "name": "phpmemory", + "type": "long", + }, + Object { + "name": "referer", + "type": "string", + }, + Object { + "name": "request", + "type": "string", + }, + Object { + "name": "response", + "type": "string", + }, + Object { + "name": "tags", + "type": "string", + }, + Object { + "name": "timestamp", + "type": "timestamp", + }, + Object { + "name": "url", + "type": "string", + }, + Object { + "name": "utc_time", + "type": "timestamp", + }, + ], + }, + }, "indexFields": Object { "availableFields": Array [ Object { @@ -447,7 +599,7 @@ exports[`Pie component Renders pie component 1`] = ` }, Object { "component": [Function], - "defaultState": 2, + "defaultState": 0, "eleType": "slider", "mapTo": "lineWidth", "name": "Line width", @@ -457,7 +609,7 @@ exports[`Pie component Renders pie component 1`] = ` }, Object { "component": [Function], - "defaultState": 70, + "defaultState": 100, "eleType": "slider", "mapTo": "fillOpacity", "name": "Fill opacity", @@ -484,7 +636,7 @@ exports[`Pie component Renders pie component 1`] = ` }, ], }, - "fillopacity": 70, + "fillopacity": 100, "fulllabel": "Vertical bar", "groupwidth": 0.7, "icon": [Function], @@ -493,7 +645,7 @@ exports[`Pie component Renders pie component 1`] = ` "label": "Vertical bar", "labelangle": 0, "legendposition": "v", - "linewidth": 2, + "linewidth": 0, "mode": "group", "name": "bar", "orientation": "v", diff --git a/public/components/visualizations/charts/__tests__/__snapshots__/text.test.tsx.snap b/public/components/visualizations/charts/__tests__/__snapshots__/text.test.tsx.snap index 762a463168..083750cfd9 100644 --- a/public/components/visualizations/charts/__tests__/__snapshots__/text.test.tsx.snap +++ b/public/components/visualizations/charts/__tests__/__snapshots__/text.test.tsx.snap @@ -9,6 +9,158 @@ exports[`Text component Renders text component 1`] = ` "fromApp": false, }, "defaultAxes": Object {}, + "explorer": Object { + "explorerData": Object { + "jsonData": Array [ + Object { + "double_per_ip_bytes": 11606, + "host": "artifacts.opensearch.org", + "ip_count": 176, + "per_ip_bytes": 5803, + "resp_code": "404", + "sum_bytes": 1021420, + }, + Object { + "double_per_ip_bytes": 10100, + "host": "www.opensearch.org", + "ip_count": 111, + "per_ip_bytes": 5050, + "resp_code": "404", + "sum_bytes": 560638, + }, + Object { + "double_per_ip_bytes": 0, + "host": "artifacts.opensearch.org", + "ip_count": 94, + "per_ip_bytes": 0, + "resp_code": "503", + "sum_bytes": 0, + }, + Object { + "double_per_ip_bytes": 0, + "host": "www.opensearch.org", + "ip_count": 78, + "per_ip_bytes": 0, + "resp_code": "503", + "sum_bytes": 0, + }, + Object { + "double_per_ip_bytes": 11526, + "host": "cdn.opensearch-opensearch-opensearch.org", + "ip_count": 43, + "per_ip_bytes": 5763, + "resp_code": "404", + "sum_bytes": 247840, + }, + Object { + "double_per_ip_bytes": 0, + "host": "cdn.opensearch-opensearch-opensearch.org", + "ip_count": 34, + "per_ip_bytes": 0, + "resp_code": "503", + "sum_bytes": 0, + }, + Object { + "double_per_ip_bytes": 8882, + "host": "opensearch-opensearch-opensearch.org", + "ip_count": 13, + "per_ip_bytes": 4441, + "resp_code": "404", + "sum_bytes": 57735, + }, + Object { + "double_per_ip_bytes": 0, + "host": "opensearch-opensearch-opensearch.org", + "ip_count": 6, + "per_ip_bytes": 0, + "resp_code": "503", + "sum_bytes": 0, + }, + ], + "schema": Array [ + Object { + "name": "agent", + "type": "string", + }, + Object { + "name": "bytes", + "type": "long", + }, + Object { + "name": "clientip", + "type": "ip", + }, + Object { + "name": "event", + "type": "struct", + }, + Object { + "name": "extension", + "type": "string", + }, + Object { + "name": "geo", + "type": "struct", + }, + Object { + "name": "host", + "type": "string", + }, + Object { + "name": "index", + "type": "string", + }, + Object { + "name": "ip", + "type": "ip", + }, + Object { + "name": "machine", + "type": "struct", + }, + Object { + "name": "memory", + "type": "double", + }, + Object { + "name": "message", + "type": "string", + }, + Object { + "name": "phpmemory", + "type": "long", + }, + Object { + "name": "referer", + "type": "string", + }, + Object { + "name": "request", + "type": "string", + }, + Object { + "name": "response", + "type": "string", + }, + Object { + "name": "tags", + "type": "string", + }, + Object { + "name": "timestamp", + "type": "timestamp", + }, + Object { + "name": "url", + "type": "string", + }, + Object { + "name": "utc_time", + "type": "timestamp", + }, + ], + }, + }, "indexFields": Object { "availableFields": Array [ Object { @@ -430,7 +582,7 @@ exports[`Text component Renders text component 1`] = ` }, Object { "component": [Function], - "defaultState": 2, + "defaultState": 0, "eleType": "slider", "mapTo": "lineWidth", "name": "Line width", @@ -440,7 +592,7 @@ exports[`Text component Renders text component 1`] = ` }, Object { "component": [Function], - "defaultState": 70, + "defaultState": 100, "eleType": "slider", "mapTo": "fillOpacity", "name": "Fill opacity", @@ -467,7 +619,7 @@ exports[`Text component Renders text component 1`] = ` }, ], }, - "fillopacity": 70, + "fillopacity": 100, "fulllabel": "Vertical bar", "groupwidth": 0.7, "icon": [Function], @@ -476,7 +628,7 @@ exports[`Text component Renders text component 1`] = ` "label": "Vertical bar", "labelangle": 0, "legendposition": "v", - "linewidth": 2, + "linewidth": 0, "mode": "group", "name": "bar", "orientation": "v", diff --git a/public/components/visualizations/charts/__tests__/__snapshots__/treemap.test.tsx.snap b/public/components/visualizations/charts/__tests__/__snapshots__/treemap.test.tsx.snap index 23d4f693af..5560d66b91 100644 --- a/public/components/visualizations/charts/__tests__/__snapshots__/treemap.test.tsx.snap +++ b/public/components/visualizations/charts/__tests__/__snapshots__/treemap.test.tsx.snap @@ -26,6 +26,158 @@ exports[`Treemap component Renders treemap component 1`] = ` "fromApp": false, }, "defaultAxes": Object {}, + "explorer": Object { + "explorerData": Object { + "jsonData": Array [ + Object { + "double_per_ip_bytes": 11606, + "host": "artifacts.opensearch.org", + "ip_count": 176, + "per_ip_bytes": 5803, + "resp_code": "404", + "sum_bytes": 1021420, + }, + Object { + "double_per_ip_bytes": 10100, + "host": "www.opensearch.org", + "ip_count": 111, + "per_ip_bytes": 5050, + "resp_code": "404", + "sum_bytes": 560638, + }, + Object { + "double_per_ip_bytes": 0, + "host": "artifacts.opensearch.org", + "ip_count": 94, + "per_ip_bytes": 0, + "resp_code": "503", + "sum_bytes": 0, + }, + Object { + "double_per_ip_bytes": 0, + "host": "www.opensearch.org", + "ip_count": 78, + "per_ip_bytes": 0, + "resp_code": "503", + "sum_bytes": 0, + }, + Object { + "double_per_ip_bytes": 11526, + "host": "cdn.opensearch-opensearch-opensearch.org", + "ip_count": 43, + "per_ip_bytes": 5763, + "resp_code": "404", + "sum_bytes": 247840, + }, + Object { + "double_per_ip_bytes": 0, + "host": "cdn.opensearch-opensearch-opensearch.org", + "ip_count": 34, + "per_ip_bytes": 0, + "resp_code": "503", + "sum_bytes": 0, + }, + Object { + "double_per_ip_bytes": 8882, + "host": "opensearch-opensearch-opensearch.org", + "ip_count": 13, + "per_ip_bytes": 4441, + "resp_code": "404", + "sum_bytes": 57735, + }, + Object { + "double_per_ip_bytes": 0, + "host": "opensearch-opensearch-opensearch.org", + "ip_count": 6, + "per_ip_bytes": 0, + "resp_code": "503", + "sum_bytes": 0, + }, + ], + "schema": Array [ + Object { + "name": "agent", + "type": "string", + }, + Object { + "name": "bytes", + "type": "long", + }, + Object { + "name": "clientip", + "type": "ip", + }, + Object { + "name": "event", + "type": "struct", + }, + Object { + "name": "extension", + "type": "string", + }, + Object { + "name": "geo", + "type": "struct", + }, + Object { + "name": "host", + "type": "string", + }, + Object { + "name": "index", + "type": "string", + }, + Object { + "name": "ip", + "type": "ip", + }, + Object { + "name": "machine", + "type": "struct", + }, + Object { + "name": "memory", + "type": "double", + }, + Object { + "name": "message", + "type": "string", + }, + Object { + "name": "phpmemory", + "type": "long", + }, + Object { + "name": "referer", + "type": "string", + }, + Object { + "name": "request", + "type": "string", + }, + Object { + "name": "response", + "type": "string", + }, + Object { + "name": "tags", + "type": "string", + }, + Object { + "name": "timestamp", + "type": "timestamp", + }, + Object { + "name": "url", + "type": "string", + }, + Object { + "name": "utc_time", + "type": "timestamp", + }, + ], + }, + }, "indexFields": Object { "availableFields": Array [ Object { @@ -447,7 +599,7 @@ exports[`Treemap component Renders treemap component 1`] = ` }, Object { "component": [Function], - "defaultState": 2, + "defaultState": 0, "eleType": "slider", "mapTo": "lineWidth", "name": "Line width", @@ -457,7 +609,7 @@ exports[`Treemap component Renders treemap component 1`] = ` }, Object { "component": [Function], - "defaultState": 70, + "defaultState": 100, "eleType": "slider", "mapTo": "fillOpacity", "name": "Fill opacity", @@ -484,7 +636,7 @@ exports[`Treemap component Renders treemap component 1`] = ` }, ], }, - "fillopacity": 70, + "fillopacity": 100, "fulllabel": "Vertical bar", "groupwidth": 0.7, "icon": [Function], @@ -493,7 +645,7 @@ exports[`Treemap component Renders treemap component 1`] = ` "label": "Vertical bar", "labelangle": 0, "legendposition": "v", - "linewidth": 2, + "linewidth": 0, "mode": "group", "name": "bar", "orientation": "v", diff --git a/test/event_analytics_constants.ts b/test/event_analytics_constants.ts index bcb75afafa..cf8df8a0e1 100644 --- a/test/event_analytics_constants.ts +++ b/test/event_analytics_constants.ts @@ -523,6 +523,9 @@ export const VALUE_OPTIONS = { export const TEST_VISUALIZATIONS_DATA = { data: { appData: { fromApp: false }, + explorer: { + explorerData: { jsonData: JSON_DATA, schema: AVAILABLE_FIELDS }, + }, defaultAxes: {}, indexFields: EXPLORER_FIELDS, query: {}, From e27a98d7f4b5abfb22ffa335c172e26a6f3a0e98 Mon Sep 17 00:00:00 2001 From: Eric Wei Date: Mon, 13 Mar 2023 17:29:58 -0700 Subject: [PATCH 10/73] keep viz for on calculating availability for now Signed-off-by: Eric Wei --- public/components/application_analytics/helpers/utils.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/components/application_analytics/helpers/utils.tsx b/public/components/application_analytics/helpers/utils.tsx index 42d38f37ee..a9df996b16 100644 --- a/public/components/application_analytics/helpers/utils.tsx +++ b/public/components/application_analytics/helpers/utils.tsx @@ -237,7 +237,7 @@ export const calculateAvailability = async ( await pplService .fetch({ query: finalQuery, - format: 'jdbc', + format: 'viz', }) .then((res) => { const stat = res.metadata.fields.filter( From 928fb518ce58b32f776065ef3150ad1d633c87dd Mon Sep 17 00:00:00 2001 From: Eric Wei Date: Tue, 14 Mar 2023 11:26:49 -0700 Subject: [PATCH 11/73] add cypress downloads to gitignore Signed-off-by: Eric Wei --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 83a6e387b0..8466c1c43c 100644 --- a/.gitignore +++ b/.gitignore @@ -4,5 +4,6 @@ build/ coverage/ .cypress/screenshots .cypress/videos +.cypress/downloads common/query_manager/antlr/output .eslintcache From c0a544f9ef31599812b75fc4d06b585299f1cb69 Mon Sep 17 00:00:00 2001 From: Eric Wei Date: Tue, 14 Mar 2023 11:39:13 -0700 Subject: [PATCH 12/73] disable no-console Signed-off-by: Eric Wei --- .eslintrc.js | 9 ++++++++- .../event_analytics/explorer/sidebar/field_insights.tsx | 6 ++++-- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index 4d8297eb33..f8dd0a6814 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -10,5 +10,12 @@ module.exports = { 'plugin:@elastic/eui/recommended', 'plugin:react-hooks/recommended', ], + overrides: [ + { + files: ['**/*.{js,ts,tsx}'], + rules: { + 'no-console': 0, + }, + }, + ], }; - diff --git a/public/components/event_analytics/explorer/sidebar/field_insights.tsx b/public/components/event_analytics/explorer/sidebar/field_insights.tsx index 1b1fdcae62..6c4f5ea341 100644 --- a/public/components/event_analytics/explorer/sidebar/field_insights.tsx +++ b/public/components/event_analytics/explorer/sidebar/field_insights.tsx @@ -103,14 +103,16 @@ export const FieldInsights = ({ field, query }: any) => { }); } }) - .catch((error) => {}); + .catch((error) => { + console.error(error); + }); }, []); const getInsights = async (queryStr: string) => { try { return await pplService.fetch(queryStr); } catch (error) { - // to-do, for now just a placeholder to bypass linting + console.error(error); } }; From 79862f72c1d35a131525501fe2d32e8974312924 Mon Sep 17 00:00:00 2001 From: Eric Wei Date: Tue, 14 Mar 2023 11:57:51 -0700 Subject: [PATCH 13/73] better naming and type defination Signed-off-by: Eric Wei --- .../explorer/sidebar/field_insights.tsx | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/public/components/event_analytics/explorer/sidebar/field_insights.tsx b/public/components/event_analytics/explorer/sidebar/field_insights.tsx index 6c4f5ea341..dd0f423309 100644 --- a/public/components/event_analytics/explorer/sidebar/field_insights.tsx +++ b/public/components/event_analytics/explorer/sidebar/field_insights.tsx @@ -9,6 +9,15 @@ import { EuiFlexGroup, EuiFlexItem, EuiLink, EuiBasicTable } from '@elastic/eui' import { getIndexPatternFromRawQuery } from '../../../../../common/utils/query_utils'; import { TabContext } from '../../hooks/use_tab_context'; +interface IInsightsReq { + id: string; + name: string; + format: string; + query: string; +} + +type IInsightsReqParams = Pick; + export const FieldInsights = ({ field, query }: any) => { const { pplService } = useContext(TabContext); const { rawQuery } = query; @@ -62,9 +71,9 @@ export const FieldInsights = ({ field, query }: any) => { }, ]; - const fetchData = async (requests) => { + const fetchData = async (requests: IInsightsReq[]) => { return await Promise.all( - requests.map((reqQuery) => { + requests.map((reqQuery: IInsightsReq) => { const req = { format: reqQuery.format, query: reqQuery.query, @@ -108,9 +117,9 @@ export const FieldInsights = ({ field, query }: any) => { }); }, []); - const getInsights = async (queryStr: string) => { + const getInsights = async (insightParams: IInsightsReqParams) => { try { - return await pplService.fetch(queryStr); + return await pplService.fetch(insightParams); } catch (error) { console.error(error); } From 4d30c97bda3edd1c96893a16171bbabf4982a3e9 Mon Sep 17 00:00:00 2001 From: Eric Wei Date: Tue, 14 Mar 2023 12:30:22 -0700 Subject: [PATCH 14/73] update function doc and types Signed-off-by: Eric Wei --- common/types/explorer.ts | 1 + .../visualizations/charts/shared/common.ts | 48 +++++++++++-------- 2 files changed, 30 insertions(+), 19 deletions(-) diff --git a/common/types/explorer.ts b/common/types/explorer.ts index 31c7a85850..d4b2ef5934 100644 --- a/common/types/explorer.ts +++ b/common/types/explorer.ts @@ -318,6 +318,7 @@ export interface ConfigList { [AGGREGATIONS]?: ConfigListEntry[]; [BREAKDOWNS]?: ConfigListEntry[] | HistogramConfigList[]; span?: DimensionSpan; + isVertical?: boolean; } export interface Breadcrumbs { diff --git a/public/components/visualizations/charts/shared/common.ts b/public/components/visualizations/charts/shared/common.ts index b5a24436fb..50790511e9 100644 --- a/public/components/visualizations/charts/shared/common.ts +++ b/public/components/visualizations/charts/shared/common.ts @@ -12,6 +12,15 @@ import { } from '../../../../../common/types/explorer'; import { removeBacktick } from '../../../../../common/utils'; +interface IIntermediateMapping { + value: number; + x: string; + breakdown: string; + aggName: string; +} + +type PlotlyTrace = Partial; + export const getCompleteTimespanKey = (span: DimensionSpan) => { if (isEmpty(span) || isEmpty(span.time_field) || isEmpty(span.interval) || isEmpty(span.unit)) return ''; @@ -21,15 +30,16 @@ export const getCompleteTimespanKey = (span: DimensionSpan) => { /** * Transform to traces that can be consumed by plotly. - * @param intermediateVisData preprocessed json data that has dimensions to single aggregation mapping. - * @param param1 required visualization configurations. - * @returns traces. + * @param intermediateVisData intermediate visualization mapping data. + * @param configList visualization configurations from config panel UI. + * @param visTypeMetaData contains info related to how to prepare traces for this specifc visualizaton type. + * @returns plotly traces. */ export const transformPreprocessedDataToTraces = ( - intermediateVisData: any[], + intermediateVisData: IIntermediateMapping[], { breakdowns, isVertical = true }: Partial, visTypeMetaData: VisSpecificMetaData -) => { +): PlotlyTrace[] => { const traceMap = new Map(); const hasBreakdown = !isEmpty(breakdowns); forEach(intermediateVisData, (entry) => { @@ -61,26 +71,32 @@ export const removeBackTick = (entry: any) => { }; /** - * preprocess json data to + * preprocess raw schema-data, key-value mapping to form an intermediate, + * dimension - breakdown - aggregation, key-value mapping. * 1. concatenate dimensions to generate one dimension - * 2. concatenate breakdowns (if there's any) generate one breakdown + * 2. concatenate breakdowns (if there's any) to generate one breakdown * 3. map dimension/breakdown to aggregations - * @param visJson raw json data from data fetching - * @param param1 required visualization configurations. - * @returns intermediate visualization json data + * @param jdbcFieldValueMapList raw jsonData comes from fetched data that has schema to data mapping + * @param configList visualization configurations from config panel UI. + * @returns intermediate visualization mapping data */ export const preprocessJsonData = ( jdbcFieldValueMapList: any[], { dimensions, series, breakdowns, span }: Partial -) => { - const seriesFlattenedEntries = []; +): IIntermediateMapping[] => { + const seriesFlattenedEntries: IIntermediateMapping[] = []; forEach(jdbcFieldValueMapList, (entry: any) => { const backtickRemovedEntry = { ...removeBackTick(entry), }; forEach(series, (sr) => { - let tabularVizData = {}; + let tabularVizData: IIntermediateMapping = { + value: 0, + x: '', + breakdown: '', + aggName: '', + }; const serieKey = sr[CUSTOM_LABEL] ? sr[CUSTOM_LABEL] : `${sr.aggregation}(${sr.name})`; if (!isEmpty(serieKey)) { const concatedXaxisLabel = [ @@ -102,12 +118,6 @@ export const preprocessJsonData = ( breakdown: concatedBreakdownLabel, aggName: serieKey, }; - } else { - tabularVizData = { - value: 0, - x: '', - breakdown: '', - }; } seriesFlattenedEntries.push(tabularVizData); }); From 187af1389f58da75f0a6c67b571b6294a38c5d40 Mon Sep 17 00:00:00 2001 From: Eric Wei Date: Tue, 14 Mar 2023 17:58:20 -0700 Subject: [PATCH 15/73] move fields toggle from explorer to under sidebar Signed-off-by: Eric Wei --- .../event_analytics/explorer/explorer.tsx | 52 ++----------- .../explorer/sidebar/sidebar.tsx | 77 +++++++++++++++++-- .../explorer/visualizations/index.tsx | 6 -- 3 files changed, 77 insertions(+), 58 deletions(-) diff --git a/public/components/event_analytics/explorer/explorer.tsx b/public/components/event_analytics/explorer/explorer.tsx index 8c6ec2ed3c..67066b0aa7 100644 --- a/public/components/event_analytics/explorer/explorer.tsx +++ b/public/components/event_analytics/explorer/explorer.tsx @@ -20,11 +20,10 @@ import { } from '@elastic/eui'; import { FormattedMessage } from '@osd/i18n/react'; import classNames from 'classnames'; -import { cloneDeep, has, isEmpty, isEqual, reduce } from 'lodash'; +import { has, isEmpty, isEqual, reduce } from 'lodash'; import React, { ReactElement, useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { batch, useDispatch, useSelector } from 'react-redux'; import { - AVAILABLE_FIELDS, DATE_PICKER_FORMAT, DEFAULT_AVAILABILITY_QUERY, EVENT_ANALYTICS_DOCUMENTATION_URL, @@ -33,7 +32,6 @@ import { PATTERNS_EXTRACTOR_REGEX, PATTERNS_REGEX, PATTERN_REGEX, - PPL_DEFAULT_PATTERN_REGEX_FILETER, RAW_QUERY, SAVED_OBJECT_ID, SAVED_OBJECT_TYPE, @@ -74,8 +72,7 @@ import { Search } from '../../common/search/search'; import { getVizContainerProps } from '../../visualizations/charts/helpers'; import { TabContext, useFetchEvents, useFetchPatterns, useFetchVisualizations } from '../hooks'; import { selectCountDistribution } from '../redux/slices/count_distribution_slice'; -import { selectFields, sortFields, updateFields } from '../redux/slices/field_slice'; -import { selectPatterns } from '../redux/slices/patterns_slice'; +import { selectFields, updateFields } from '../redux/slices/field_slice'; import { selectQueryResult } from '../redux/slices/query_result_slice'; import { changeDateRange, changeQuery, selectQueries } from '../redux/slices/query_slice'; import { updateTabName } from '../redux/slices/query_tab_slice'; @@ -129,11 +126,11 @@ export const Explorer = ({ }: IExplorerProps) => { const dispatch = useDispatch(); const requestParams = { tabId }; - const { getLiveTail, getEvents, getAvailableFields, isEventsLoading } = useFetchEvents({ + const { getLiveTail, getEvents } = useFetchEvents({ pplService, requestParams, }); - const { getVisualizations, getCountVisualizations, isVisLoading } = useFetchVisualizations({ + const { getCountVisualizations } = useFetchVisualizations({ pplService, requestParams, }); @@ -506,11 +503,6 @@ export const Explorer = ({ } }, [savedObjectId]); - const handleAddField = (field: IField) => toggleFields(field, AVAILABLE_FIELDS, SELECTED_FIELDS); - - const handleRemoveField = (field: IField) => - toggleFields(field, SELECTED_FIELDS, AVAILABLE_FIELDS); - const handleTimePickerChange = async (timeRange: string[]) => { if (appLogEvents) { setStartTime(timeRange[0]); @@ -558,36 +550,6 @@ export const Explorer = ({ } }; - /** - * Toggle fields between selected and unselected sets - * @param field field to be toggled - * @param FieldSetToRemove set where this field to be removed from - * @param FieldSetToAdd set where this field to be added - */ - const toggleFields = (field: IField, FieldSetToRemove: string, FieldSetToAdd: string) => { - const nextFields = cloneDeep(explorerFields); - const thisFieldSet = nextFields[FieldSetToRemove]; - const nextFieldSet = thisFieldSet.filter((fd: IField) => fd.name !== field.name); - nextFields[FieldSetToRemove] = nextFieldSet; - nextFields[FieldSetToAdd].push(field); - batch(() => { - dispatch( - updateFields({ - tabId, - data: { - ...nextFields, - }, - }) - ); - dispatch( - sortFields({ - tabId, - data: [FieldSetToAdd], - }) - ); - }); - }; - const sidebarClassName = classNames({ closed: isSidebarClosed, }); @@ -686,8 +648,6 @@ export const Explorer = ({ selectedPattern={query[SELECTED_PATTERN_FIELD]} handleOverrideTimestamp={handleOverrideTimestamp} handleOverridePattern={handleOverridePattern} - handleAddField={(field: IField) => handleAddField(field)} - handleRemoveField={(field: IField) => handleRemoveField(field)} isOverridingTimestamp={isOverridingTimestamp} isOverridingPattern={isOverridingPattern} isFieldToggleButtonDisabled={ @@ -891,8 +851,8 @@ export const Explorer = ({ explorerFields={explorerFields} explorerVis={explorerVisualizations} explorerData={explorerData} - handleAddField={handleAddField} - handleRemoveField={handleRemoveField} + // handleAddField={handleAddField} + // handleRemoveField={handleRemoveField} visualizations={visualizations} handleOverrideTimestamp={handleOverrideTimestamp} callback={callbackForConfig} diff --git a/public/components/event_analytics/explorer/sidebar/sidebar.tsx b/public/components/event_analytics/explorer/sidebar/sidebar.tsx index 9b57aae095..f949047f56 100644 --- a/public/components/event_analytics/explorer/sidebar/sidebar.tsx +++ b/public/components/event_analytics/explorer/sidebar/sidebar.tsx @@ -3,12 +3,16 @@ * SPDX-License-Identifier: Apache-2.0 */ -import React, { useState } from 'react'; +import React, { useState, useCallback, useContext } from 'react'; +import { batch, useDispatch } from 'react-redux'; import { isEmpty } from 'lodash'; import { EuiTitle, EuiSpacer, EuiFieldSearch, EuiAccordion } from '@elastic/eui'; import { I18nProvider } from '@osd/i18n/react'; import { Field } from './field'; -import { IExplorerFields, IField } from '../../../../../common/types/explorer'; +import { ExplorerFields, IExplorerFields, IField } from '../../../../../common/types/explorer'; +import { AVAILABLE_FIELDS, SELECTED_FIELDS } from '../../../../../common/constants/explorer'; +import { sortFields, updateFields } from '../../redux/slices/field_slice'; +import { TabContext } from '../../hooks/use_tab_context'; interface ISidebarProps { query: string; @@ -21,8 +25,6 @@ interface ISidebarProps { isFieldToggleButtonDisabled: boolean; handleOverridePattern: (pattern: IField) => void; handleOverrideTimestamp: (timestamp: IField) => void; - handleAddField: (field: IField) => void; - handleRemoveField: (field: IField) => void; } export const Sidebar = (props: ISidebarProps) => { @@ -37,13 +39,76 @@ export const Sidebar = (props: ISidebarProps) => { isFieldToggleButtonDisabled, handleOverridePattern, handleOverrideTimestamp, - handleAddField, - handleRemoveField, } = props; + const dispatch = useDispatch(); + const { tabId } = useContext(TabContext); const [showFields, setShowFields] = useState(false); const [searchTerm, setSearchTerm] = useState(''); + /** + * Toggle fields between selected and unselected sets + * @param fieldState all fields in store + * @param field field to be toggled + * @param FieldSetToRemove the set where this field to be removed from + * @param FieldSetToAdd the set where this field to be added to + * returns new fields state + */ + const toggleFields = ( + fieldState: ExplorerFields, + field: IField, + fieldSetToRemove: string, + fieldSetToAdd: string + ): ExplorerFields => { + const nextFields = { ...fieldState }; + nextFields[fieldSetToRemove] = nextFields[fieldSetToRemove].filter( + (fd: IField) => fd.name !== field.name + ); + nextFields[fieldSetToAdd] = [...nextFields[fieldSetToAdd], field]; + return nextFields; + }; + + const updateStoreFields = (fieldsData: ExplorerFields, tabID: string, modifiedField: string) => { + batch(() => { + dispatch( + updateFields({ + tabId: tabID, + data: { + ...fieldsData, + }, + }) + ); + dispatch( + sortFields({ + tabId: tabID, + data: [modifiedField], + }) + ); + }); + }; + + const handleAddField = useCallback( + (field: IField) => { + updateStoreFields( + toggleFields(explorerFields, field, AVAILABLE_FIELDS, SELECTED_FIELDS), + tabId, + SELECTED_FIELDS + ); + }, + [explorerFields, tabId] + ); + + const handleRemoveField = useCallback( + (field: IField) => { + updateStoreFields( + toggleFields(explorerFields, field, SELECTED_FIELDS, AVAILABLE_FIELDS), + tabId, + AVAILABLE_FIELDS + ); + }, + [explorerFields, tabId] + ); + return (
diff --git a/public/components/event_analytics/explorer/visualizations/index.tsx b/public/components/event_analytics/explorer/visualizations/index.tsx index 11efb16f27..41b6eab6aa 100644 --- a/public/components/event_analytics/explorer/visualizations/index.tsx +++ b/public/components/event_analytics/explorer/visualizations/index.tsx @@ -29,8 +29,6 @@ interface IExplorerVisualizationsProps { explorerVis: any; explorerFields: ExplorerFields; explorerData: any; - handleAddField: (field: IField) => void; - handleRemoveField: (field: IField) => void; visualizations: IVisualizationContainerProps; handleOverrideTimestamp: (field: IField) => void; callback?: any; @@ -44,8 +42,6 @@ export const ExplorerVisualizations = ({ explorerVis, explorerFields, explorerData, - handleAddField, - handleRemoveField, visualizations, handleOverrideTimestamp, callback, @@ -111,8 +107,6 @@ export const ExplorerVisualizations = ({ explorerData={explorerData} selectedTimestamp={visualizations?.data?.query[SELECTED_TIMESTAMP] || ''} handleOverrideTimestamp={handleOverrideTimestamp} - handleAddField={(field: IField) => handleAddField(field)} - handleRemoveField={(field: IField) => handleRemoveField(field)} isFieldToggleButtonDisabled={ vis.name === VIS_CHART_TYPES.LogsView ? isEmpty(explorerData.jsonData) || From 040ccffc6ae569d25115935e64f47436c050850c Mon Sep 17 00:00:00 2001 From: Eric Wei Date: Tue, 14 Mar 2023 18:11:33 -0700 Subject: [PATCH 16/73] missed comments removal Signed-off-by: Eric Wei --- public/components/event_analytics/explorer/explorer.tsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/public/components/event_analytics/explorer/explorer.tsx b/public/components/event_analytics/explorer/explorer.tsx index 67066b0aa7..9bd371ecd0 100644 --- a/public/components/event_analytics/explorer/explorer.tsx +++ b/public/components/event_analytics/explorer/explorer.tsx @@ -851,8 +851,6 @@ export const Explorer = ({ explorerFields={explorerFields} explorerVis={explorerVisualizations} explorerData={explorerData} - // handleAddField={handleAddField} - // handleRemoveField={handleRemoveField} visualizations={visualizations} handleOverrideTimestamp={handleOverrideTimestamp} callback={callbackForConfig} From 83cf1c9dfc0e4f36823777b2ce71753cccaffec2 Mon Sep 17 00:00:00 2001 From: Eric Wei Date: Tue, 14 Mar 2023 18:12:51 -0700 Subject: [PATCH 17/73] fix the bug when switching index seeing fields from old index Signed-off-by: Eric Wei --- public/components/event_analytics/hooks/use_fetch_events.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/public/components/event_analytics/hooks/use_fetch_events.ts b/public/components/event_analytics/hooks/use_fetch_events.ts index 4bab880845..bbcbb4b785 100644 --- a/public/components/event_analytics/hooks/use_fetch_events.ts +++ b/public/components/event_analytics/hooks/use_fetch_events.ts @@ -83,6 +83,7 @@ export const useFetchEvents = ({ pplService, requestParams }: IFetchEventsParams [UNSELECTED_FIELDS]: res?.schema ? [...res.schema] : [], [QUERIED_FIELDS]: [], [AVAILABLE_FIELDS]: res?.schema || [], + [SELECTED_FIELDS]: [], }, }) ); From 41af428e9e500498cb2954342820b6bfcce664e8 Mon Sep 17 00:00:00 2001 From: Eric Wei Date: Tue, 14 Mar 2023 18:48:35 -0700 Subject: [PATCH 18/73] update tests/snapshots Signed-off-by: Eric Wei --- .../__snapshots__/sidebar.test.tsx.snap | 14502 ++++++++-------- .../sidebar/__tests__/sidebar.test.tsx | 84 +- 2 files changed, 7308 insertions(+), 7278 deletions(-) diff --git a/public/components/event_analytics/explorer/sidebar/__tests__/__snapshots__/sidebar.test.tsx.snap b/public/components/event_analytics/explorer/sidebar/__tests__/__snapshots__/sidebar.test.tsx.snap index 556467262e..1d5a67a003 100644 --- a/public/components/event_analytics/explorer/sidebar/__tests__/__snapshots__/sidebar.test.tsx.snap +++ b/public/components/event_analytics/explorer/sidebar/__tests__/__snapshots__/sidebar.test.tsx.snap @@ -1,857 +1,803 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`Siderbar component Renders empty sidebar component 1`] = ` - - - + + - -
-
+ +
- - -
- - - - -
- + + + +
- - - - -
-
+ > + + + + +
+
+
+
-
- - -
- +
+ + + +
+
- -
- - - - - + + + + + + `; exports[`Siderbar component Renders sidebar component 1`] = ` - - - + + - -
-
+ +
- - -
- - - - -
- + + + +
- - - - -
-
+ + + + + + +
+
+
+
-
- - -
- -
- -
- - - Query fields - - - } - id="fieldSelector__queriedFields" - initialIsOpen={true} - isLoading={false} - isLoadingMessage={false} - paddingSize="xs" + + +
+
+ +
+ + + Query fields + + + } + id="fieldSelector__queriedFields" + initialIsOpen={true} + isLoading={false} + isLoadingMessage={false} + paddingSize="xs" >
- -
-
- + Query fields + + + + +
+
-
-
-
    +
    +
    -
  • - - - - - - - - - - - - - - - } - fieldIcon={ - - } - fieldName={ - - double_per_ip_bytes - - } - isActive={false} - onClick={[Function]} - size="m" - /> + -
    -
    + + } + closePopover={[Function]} + display="block" + hasArrow={true} + isOpen={false} + ownFocus={true} + panelClassName="dscSidebarItem__fieldPopoverPanel" + panelPaddingSize="m" + > +
    +
    -
    + + + + + + + + + + + + + } + fieldIcon={ + + } + fieldName={ + + double_per_ip_bytes + + } + isActive={false} + onClick={[Function]} + size="m" > - -
    - - - - - - - - +
    + - + + + + + + - - - - + > + + + + + + + +
    -
    - + +
    -
    - - -
  • -
  • - + +
  • +
  • - - - - - - - - - - - - - - } - fieldIcon={ - - } - fieldName={ - - host - - } - isActive={false} - onClick={[Function]} - size="m" - /> + -
    -
    + + } + closePopover={[Function]} + display="block" + hasArrow={true} + isOpen={false} + ownFocus={true} + panelClassName="dscSidebarItem__fieldPopoverPanel" + panelPaddingSize="m" + > +
    +
    -
    + + + + + + + + + + + + + } + fieldIcon={ + + } + fieldName={ + + host + + } + isActive={false} + onClick={[Function]} + size="m" > - -
    - - - - - - - - +
    + - + + + + + + - - - - + > + + + + + + + +
    -
    - + +
    -
    - - -
  • -
  • - + +
  • +
  • - - - - - - - - - - - - - - } - fieldIcon={ - - } - fieldName={ - - ip_count - - } - isActive={false} - onClick={[Function]} - size="m" - /> + -
    -
    + + } + closePopover={[Function]} + display="block" + hasArrow={true} + isOpen={false} + ownFocus={true} + panelClassName="dscSidebarItem__fieldPopoverPanel" + panelPaddingSize="m" + > +
    +
    -
    + + + + + + + + + + + + + } + fieldIcon={ + + } + fieldName={ + + ip_count + + } + isActive={false} + onClick={[Function]} + size="m" > - -
    - - - - - - - - +
    + - + + + + + + - - - - + > + + + + + + + +
    -
    - + +
    -
    - - -
  • -
  • - + +
  • +
  • - - - - - - - - - - - - - - } - fieldIcon={ - - } - fieldName={ - - per_ip_bytes - - } - isActive={false} - onClick={[Function]} - size="m" - /> + -
    -
    + + } + closePopover={[Function]} + display="block" + hasArrow={true} + isOpen={false} + ownFocus={true} + panelClassName="dscSidebarItem__fieldPopoverPanel" + panelPaddingSize="m" + > +
    +
    -
    + + + + + + + + + + + + + } + fieldIcon={ + + } + fieldName={ + + per_ip_bytes + + } + isActive={false} + onClick={[Function]} + size="m" > - -
    - - - - - - - - +
    + - + + + + + + - - - - + > + + + + + + + +
    -
    - + +
    -
    - - -
  • -
  • - + +
  • +
  • - - - - - - - - - - - - - - } - fieldIcon={ - - } - fieldName={ - - resp_code - - } - isActive={false} - onClick={[Function]} - size="m" - /> + -
    -
    + + } + closePopover={[Function]} + display="block" + hasArrow={true} + isOpen={false} + ownFocus={true} + panelClassName="dscSidebarItem__fieldPopoverPanel" + panelPaddingSize="m" + > +
    +
    -
    + + + + + + + + + + + + + } + fieldIcon={ + + } + fieldName={ + + resp_code + + } + isActive={false} + onClick={[Function]} + size="m" > - -
    + +
    + + + + + + + + + + + + + +
    +
    + +
    +
    + + +
  • +
  • + + - + - + - + - - - - -
  • -
    - -
-
- - - -
  • - - - - - - - - - - - - - - - } - fieldIcon={ - - } - fieldName={ - - sum_bytes - - } - isActive={false} - onClick={[Function]} - size="m" - /> - } - closePopover={[Function]} - display="block" - hasArrow={true} - isOpen={false} - ownFocus={true} - panelClassName="dscSidebarItem__fieldPopoverPanel" - panelPaddingSize="m" - > -
    -
    - - - - - - - - - - + } + closePopover={[Function]} + display="block" + hasArrow={true} + isOpen={false} + ownFocus={true} + panelClassName="dscSidebarItem__fieldPopoverPanel" + panelPaddingSize="m" + > +
    +
    -
    + + + + + + + + + + + + + } + fieldIcon={ + + } + fieldName={ + + sum_bytes + + } + isActive={false} + onClick={[Function]} + size="m" > - -
    - - - - - - - - +
    + - + + + + + + - - - - + > + + + + + + + +
    -
    - + +
    -
    - - -
  • - + + + + +
    -
    - + +
    -
    - - -
    - - - - Selected Fields - - - } - id="fieldSelector__selectedFields" - initialIsOpen={true} - isLoading={false} - isLoadingMessage={false} - paddingSize="xs" - > -
    +
    + + + + Selected Fields + + + } + id="fieldSelector__selectedFields" + initialIsOpen={true} + isLoading={false} + isLoadingMessage={false} + paddingSize="xs" + > +
    - -
    -
    - + Selected Fields + + + + +
    +
    -
    -
    -
      + +
      +
      +
        +
      -
    - + +
    -
    - - -
    - - - - Available Fields - - - } - id="fieldSelector__availableFields" - initialIsOpen={true} - isLoading={false} - isLoadingMessage={false} - paddingSize="xs" - > -
    +
    + + + + Available Fields + + + } + id="fieldSelector__availableFields" + initialIsOpen={true} + isLoading={false} + isLoadingMessage={false} + paddingSize="xs" + > +
    - -
    -
    - + Available Fields + + + + +
    +
    -
    -
    -
      +
      +
      -
    • - - - - - - Override - - - - - - - - - - - - - } - fieldIcon={ - - } - fieldName={ - - agent - - } - isActive={false} - onClick={[Function]} - size="m" - /> + -
      -
      + + } + closePopover={[Function]} + display="block" + hasArrow={true} + isOpen={false} + ownFocus={true} + panelClassName="dscSidebarItem__fieldPopoverPanel" + panelPaddingSize="m" + > +
      +
      -
      + + + + Override + + + + + + + + + + + + + } + fieldIcon={ + + } + fieldName={ + + agent + + } + isActive={false} + onClick={[Function]} + size="m" > - -
      - - +
      + - - - - - - - - - - + + + + + + + + - + + + - - - - + > + + + + + + + +
      -
      - + +
      -
      - - -
    • -
    • - + +
    • +
    • - - - - - - - - - - - - - - } - fieldIcon={ - - } - fieldName={ - - bytes - - } - isActive={false} - onClick={[Function]} - size="m" - /> + -
      -
      + + } + closePopover={[Function]} + display="block" + hasArrow={true} + isOpen={false} + ownFocus={true} + panelClassName="dscSidebarItem__fieldPopoverPanel" + panelPaddingSize="m" + > +
      +
      -
      - + } + isActive={false} + onClick={[Function]} + size="m" + >
      - - - - - - + className="osdFieldButton__fieldIcon" + > + + + + + + + + + + + + - + bytes + + + +
      + + + + + + + + - - - - + > + + + + + + + +
      -
      - + +
      -
      - - -
    • -
    • - + +
    • +
    • - - - - - - - - - - - - - - } - fieldIcon={ - - } - fieldName={ - - clientip - - } - isActive={false} - onClick={[Function]} - size="m" - /> + -
      -
      + + } + closePopover={[Function]} + display="block" + hasArrow={true} + isOpen={false} + ownFocus={true} + panelClassName="dscSidebarItem__fieldPopoverPanel" + panelPaddingSize="m" + > +
      +
      -
      + + + + + + + + + + + + + } + fieldIcon={ + + } + fieldName={ + + clientip + + } + isActive={false} + onClick={[Function]} + size="m" > - -
      - - - - - - - - +
      + - + + + + + + - - - - + > + + + + + + + +
      -
      - + +
      -
      - - -
    • -
    • - + +
    • +
    • - - - - - - - - - - - - - - } - fieldIcon={ - - } - fieldName={ - - event - - } - isActive={false} - onClick={[Function]} - size="m" - /> + -
      -
      + + } + closePopover={[Function]} + display="block" + hasArrow={true} + isOpen={false} + ownFocus={true} + panelClassName="dscSidebarItem__fieldPopoverPanel" + panelPaddingSize="m" + > +
      +
      -
      + + + + + + + + + + + + + } + fieldIcon={ + + } + fieldName={ + + event + + } + isActive={false} + onClick={[Function]} + size="m" > - -
      - - - - - - - - +
      + - + + + + + + - - - - + > + + + + + + + +
      -
      - + +
      -
      - - -
    • -
    • - + +
    • +
    • - - - - - Override - - - - - - - - - - - - - } - fieldIcon={ - - } - fieldName={ - - extension - - } - isActive={false} - onClick={[Function]} - size="m" - /> + -
      -
      + + } + closePopover={[Function]} + display="block" + hasArrow={true} + isOpen={false} + ownFocus={true} + panelClassName="dscSidebarItem__fieldPopoverPanel" + panelPaddingSize="m" + > +
      +
      -
      + + + + Override + + + + + + + + + + + + + } + fieldIcon={ + + } + fieldName={ + + extension + + } + isActive={false} + onClick={[Function]} + size="m" > - -
      - - +
      + - - - - - - - - - - + + + + + + + + - + + + - - - - + > + + + + + + + +
      -
      - + +
      -
      - - -
    • -
    • - + +
    • +
    • - - - - - - - - - - - - - - } - fieldIcon={ - - } - fieldName={ - - geo - - } - isActive={false} - onClick={[Function]} - size="m" - /> + -
      -
      + + } + closePopover={[Function]} + display="block" + hasArrow={true} + isOpen={false} + ownFocus={true} + panelClassName="dscSidebarItem__fieldPopoverPanel" + panelPaddingSize="m" + > +
      +
      -
      + + + + + + + + + + + + + } + fieldIcon={ + + } + fieldName={ + + geo + + } + isActive={false} + onClick={[Function]} + size="m" > - -
      - - - - - - - - +
      + - + + + + + + - - - - + > + + + + + + + +
      -
      - + +
      -
      - - -
    • -
    • - + +
    • +
    • - - - - - Override - - - - - - - - - - - - - } - fieldIcon={ - - } - fieldName={ - - host - - } - isActive={false} - onClick={[Function]} - size="m" - /> + -
      -
      + + } + closePopover={[Function]} + display="block" + hasArrow={true} + isOpen={false} + ownFocus={true} + panelClassName="dscSidebarItem__fieldPopoverPanel" + panelPaddingSize="m" + > +
      +
      -
      + + + + Override + + + + + + + + + + + + + } + fieldIcon={ + + } + fieldName={ + + host + + } + isActive={false} + onClick={[Function]} + size="m" > - -
      - - +
      + - - - - - - - - - - + + + + + + + + - + + + - - - - + > + + + + + + + +
      -
      - + +
      -
      - - -
    • -
    • - + +
    • +
    • - - - - - Override - - - - - - - - - - - - - } - fieldIcon={ - - } - fieldName={ - - index - - } - isActive={false} - onClick={[Function]} - size="m" - /> + -
      -
      + + } + closePopover={[Function]} + display="block" + hasArrow={true} + isOpen={false} + ownFocus={true} + panelClassName="dscSidebarItem__fieldPopoverPanel" + panelPaddingSize="m" + > +
      +
      -
      + + + + Override + + + + + + + + + + + + + } + fieldIcon={ + + } + fieldName={ + + index + + } + isActive={false} + onClick={[Function]} + size="m" > - -
      - - +
      + - - - - - - - - - - + + - + + + - - - - + > + + + + + + + +
      -
      - + +
      -
      - - -
    • -
    • - + +
    • +
    • - - - - - - - - - - - - - - } - fieldIcon={ - - } - fieldName={ - - ip - - } - isActive={false} - onClick={[Function]} - size="m" - /> + -
      -
      + + } + closePopover={[Function]} + display="block" + hasArrow={true} + isOpen={false} + ownFocus={true} + panelClassName="dscSidebarItem__fieldPopoverPanel" + panelPaddingSize="m" + > +
      +
      -
      + + + + + + + + + + + + + } + fieldIcon={ + + } + fieldName={ + + ip + + } + isActive={false} + onClick={[Function]} + size="m" > - -
      - - - - - - - - +
      + - + + + + + + - - - - + > + + + + + + + +
      -
      - + +
      -
      - - -
    • -
    • - + +
    • +
    • - - - - - - - - - - - - - - } - fieldIcon={ - - } - fieldName={ - - machine - - } - isActive={false} - onClick={[Function]} - size="m" - /> + -
      -
      + + } + closePopover={[Function]} + display="block" + hasArrow={true} + isOpen={false} + ownFocus={true} + panelClassName="dscSidebarItem__fieldPopoverPanel" + panelPaddingSize="m" + > +
      +
      -
      + + + + + + + + + + + + + } + fieldIcon={ + + } + fieldName={ + + machine + + } + isActive={false} + onClick={[Function]} + size="m" > - -
      - - - - - - - - +
      + - + + + + + + - - - - + > + + + + + + + +
      -
      - + +
      -
      - - -
    • -
    • - + +
    • +
    • - - - - - - - - - - - - - - } - fieldIcon={ - - } - fieldName={ - - memory - - } - isActive={false} - onClick={[Function]} - size="m" - /> + -
      -
      + + } + closePopover={[Function]} + display="block" + hasArrow={true} + isOpen={false} + ownFocus={true} + panelClassName="dscSidebarItem__fieldPopoverPanel" + panelPaddingSize="m" + > +
      +
      -
      + + + + + + + + + + + + + } + fieldIcon={ + + } + fieldName={ + + memory + + } + isActive={false} + onClick={[Function]} + size="m" > - -
      - - - - - - - - +
      + - + + + + + + - - - - + > + + + + + + + +
      -
      - + +
      -
      - - -
    • -
    • - + +
    • +
    • - - - - - Override - - - - - - - - - - - - - } - fieldIcon={ - - } - fieldName={ - - message - - } - isActive={false} - onClick={[Function]} - size="m" - /> + -
      -
      + + } + closePopover={[Function]} + display="block" + hasArrow={true} + isOpen={false} + ownFocus={true} + panelClassName="dscSidebarItem__fieldPopoverPanel" + panelPaddingSize="m" + > +
      +
      -
      + + + + Override + + + + + + + + + + + + + } + fieldIcon={ + + } + fieldName={ + + message + + } + isActive={false} + onClick={[Function]} + size="m" > - -
      - - +
      + - - - - - - - - - - + + + + + + + + - + + + - - - - + > + + + + + + + +
      -
      - + +
      -
      - - -
    • -
    • - + +
    • +
    • - - - - - - - - - - - - - - } - fieldIcon={ - - } - fieldName={ - - phpmemory - - } - isActive={false} - onClick={[Function]} - size="m" - /> + -
      -
      + + } + closePopover={[Function]} + display="block" + hasArrow={true} + isOpen={false} + ownFocus={true} + panelClassName="dscSidebarItem__fieldPopoverPanel" + panelPaddingSize="m" + > +
      +
      -
      + + + + + + + + + + + + + } + fieldIcon={ + + } + fieldName={ + + phpmemory + + } + isActive={false} + onClick={[Function]} + size="m" > - -
      - - - - - - - - +
      + - + + + + + + - - - - + > + + + + + + + +
      -
      - + +
      -
      - - -
    • -
    • - + +
    • +
    • - - - - - Override - - - - - - - - - - - - - } - fieldIcon={ - - } - fieldName={ - - referer - - } - isActive={false} - onClick={[Function]} - size="m" - /> + -
      -
      + + } + closePopover={[Function]} + display="block" + hasArrow={true} + isOpen={false} + ownFocus={true} + panelClassName="dscSidebarItem__fieldPopoverPanel" + panelPaddingSize="m" + > +
      +
      -
      + + + + Override + + + + + + + + + + + + + } + fieldIcon={ + + } + fieldName={ + + referer + + } + isActive={false} + onClick={[Function]} + size="m" > - -
      - - +
      + - - - - - - - - - - + + + + + + + + - + + + - - - - + > + + + + + + + +
      -
      - + +
      -
      - - -
    • -
    • - + +
    • +
    • - - - - - Override - - - - - - - - - - - - - } - fieldIcon={ - - } - fieldName={ - - request - - } - isActive={false} - onClick={[Function]} - size="m" - /> + -
      -
      + + } + closePopover={[Function]} + display="block" + hasArrow={true} + isOpen={false} + ownFocus={true} + panelClassName="dscSidebarItem__fieldPopoverPanel" + panelPaddingSize="m" + > +
      +
      -
      + + + + Override + + + + + + + + + + + + + } + fieldIcon={ + + } + fieldName={ + + request + + } + isActive={false} + onClick={[Function]} + size="m" > - -
      - - +
      + - - - - - - - - - - + + + + + + + + - + + + - - - - + > + + + + + + + +
      -
      - + +
      -
      - - -
    • -
    • - + +
    • +
    • - - - - - Override - - - - - - - - - - - - - } - fieldIcon={ - - } - fieldName={ - - response - - } - isActive={false} - onClick={[Function]} - size="m" - /> + -
      -
      + + } + closePopover={[Function]} + display="block" + hasArrow={true} + isOpen={false} + ownFocus={true} + panelClassName="dscSidebarItem__fieldPopoverPanel" + panelPaddingSize="m" + > +
      +
      -
      + + + + Override + + + + + + + + + + + + + } + fieldIcon={ + + } + fieldName={ + + response + + } + isActive={false} + onClick={[Function]} + size="m" > - -
      - - +
      + - - - - - - - - - - + + + + + + + + - + + + - - - - + > + + + + + + + +
      -
      - + +
      -
      - - -
    • -
    • - + +
    • +
    • - - - - - Override - - - - - - - - - - - - - } - fieldIcon={ - - } - fieldName={ - - tags - - } - isActive={false} - onClick={[Function]} - size="m" - /> + -
      -
      + + } + closePopover={[Function]} + display="block" + hasArrow={true} + isOpen={false} + ownFocus={true} + panelClassName="dscSidebarItem__fieldPopoverPanel" + panelPaddingSize="m" + > +
      +
      -
      + + + + Override + + + + + + + + + + + + + } + fieldIcon={ + + } + fieldName={ + + tags + + } + isActive={false} + onClick={[Function]} + size="m" > - -
      - - +
      + - - - - - - - - - - + + + + + + + + - + + + - - - - -
      -
      - -
      -
      - - -
    • -
    • - - - - - - - - - Default Timestamp - - - - - - - - - - } - fieldIcon={ - - } - fieldName={ - - timestamp - - } - isActive={false} - onClick={[Function]} - size="m" - /> + + + + + +
    • +
      + +
    +
    + + + +
  • + -
    -
    + + } + closePopover={[Function]} + display="block" + hasArrow={true} + isOpen={false} + ownFocus={true} + panelClassName="dscSidebarItem__fieldPopoverPanel" + panelPaddingSize="m" + > +
    +
    -
    + + + + + + + Default Timestamp + + + + + + + + + + } + fieldIcon={ + + } + fieldName={ + + timestamp + + } + isActive={false} + onClick={[Function]} + size="m" > - -
    - - - - - +
    + - + + + - - Default Timestamp - - - - - - + Default Timestamp + + + + + - - - - - + > + + + + + + + +
    -
    - + +
    -
    - - -
  • -
  • - + +
  • +
  • - - - - - Override - - - - - - - - - - - - - } - fieldIcon={ - - } - fieldName={ - - url - - } - isActive={false} - onClick={[Function]} - size="m" - /> + -
    -
    + + } + closePopover={[Function]} + display="block" + hasArrow={true} + isOpen={false} + ownFocus={true} + panelClassName="dscSidebarItem__fieldPopoverPanel" + panelPaddingSize="m" + > +
    +
    -
    + + + + Override + + + + + + + + + + + + + } + fieldIcon={ + + } + fieldName={ + + url + + } + isActive={false} + onClick={[Function]} + size="m" > - -
    - - +
    + - - - - - - - - - - + + + + + + + + - + + + - - - - + > + + + + + + + +
    -
    - + +
    -
    - - -
  • -
  • - + +
  • +
  • - - - - - - - - Override - - - - - - - - - - } - fieldIcon={ - - } - fieldName={ - - utc_time - - } - isActive={false} - onClick={[Function]} - size="m" - /> + -
    -
    + + } + closePopover={[Function]} + display="block" + hasArrow={true} + isOpen={false} + ownFocus={true} + panelClassName="dscSidebarItem__fieldPopoverPanel" + panelPaddingSize="m" + > +
    +
    -
    + + + + + + + Override + + + + + + + + + + } + fieldIcon={ + + } + fieldName={ + + utc_time + + } + isActive={false} + onClick={[Function]} + size="m" > - -
    - - - - - +
    + - + + + - - - - - - + + + + + + + + - - - - - + > + + + + + + + +
    -
    - + +
    -
    - - -
  • - + + + + +
    -
    - + +
    -
    - - - - - - - + + + + + + + + `; diff --git a/public/components/event_analytics/explorer/sidebar/__tests__/sidebar.test.tsx b/public/components/event_analytics/explorer/sidebar/__tests__/sidebar.test.tsx index 6e1b9c5c7d..ae18768c19 100644 --- a/public/components/event_analytics/explorer/sidebar/__tests__/sidebar.test.tsx +++ b/public/components/event_analytics/explorer/sidebar/__tests__/sidebar.test.tsx @@ -4,52 +4,64 @@ */ import { configure, mount } from 'enzyme'; +import { useDispatch, Provider } from 'react-redux'; +import { configureStore } from '@reduxjs/toolkit'; import Adapter from 'enzyme-adapter-react-16'; import React from 'react'; import { waitFor } from '@testing-library/react'; import { Sidebar } from '../sidebar'; -import { - SELECTED_FIELDS, +import { + SELECTED_FIELDS, AVAILABLE_FIELDS, UNSELECTED_FIELDS, - QUERIED_FIELDS + QUERIED_FIELDS, } from '../../../../../../common/constants/explorer'; -import { +import { AVAILABLE_FIELDS as SIDEBAR_AVAILABLE_FIELDS, QUERY_FIELDS, JSON_DATA, - JSON_DATA_ALL + JSON_DATA_ALL, } from '../../../../../../test/event_analytics_constants'; +jest.mock('react-redux', () => ({ + ...jest.requireActual('react-redux'), + useDispatch: jest.fn(), +})); + describe('Siderbar component', () => { configure({ adapter: new Adapter() }); + const store = configureStore({ + reducer: jest.fn(), + }); + beforeEach(() => { + useDispatch.mockClear(); + useDispatch.mockReturnValue(jest.fn()); + }); it('Renders empty sidebar component', async () => { const explorerFields = { [SELECTED_FIELDS]: [], [AVAILABLE_FIELDS]: [], [UNSELECTED_FIELDS]: [], - [QUERIED_FIELDS]: [] + [QUERIED_FIELDS]: [], }; - const handleAddField = jest.fn(); const handleOverrideTimestamp = jest.fn(); const selectedTimestamp = 'timestamp'; const explorerData = {}; - const handleRemoveField = jest.fn(); - + const wrapper = mount( - + + + ); - + wrapper.update(); await waitFor(() => { @@ -62,32 +74,30 @@ describe('Siderbar component', () => { [SELECTED_FIELDS]: [], [UNSELECTED_FIELDS]: [], [AVAILABLE_FIELDS]: SIDEBAR_AVAILABLE_FIELDS, - [QUERIED_FIELDS]: QUERY_FIELDS + [QUERIED_FIELDS]: QUERY_FIELDS, }; - const handleAddField = jest.fn(); const handleOverrideTimestamp = jest.fn(); const selectedTimestamp = 'timestamp'; const explorerData = { - 'jsonData': JSON_DATA, - 'jsonDataAll': JSON_DATA_ALL + jsonData: JSON_DATA, + jsonDataAll: JSON_DATA_ALL, }; - const handleRemoveField = jest.fn(); - + const wrapper = mount( - + + + ); await waitFor(() => { expect(wrapper).toMatchSnapshot(); }); }); -}); \ No newline at end of file +}); From bc43414f57dbd9e77efd40da72b8a7c57f245981 Mon Sep 17 00:00:00 2001 From: Eric Wei Date: Tue, 14 Mar 2023 21:44:16 -0700 Subject: [PATCH 19/73] remove unused pattern function Signed-off-by: Eric Wei --- .../event_analytics/explorer/explorer.tsx | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/public/components/event_analytics/explorer/explorer.tsx b/public/components/event_analytics/explorer/explorer.tsx index 9bd371ecd0..153600dd46 100644 --- a/public/components/event_analytics/explorer/explorer.tsx +++ b/public/components/event_analytics/explorer/explorer.tsx @@ -612,23 +612,6 @@ export const Explorer = ({ return 0; }, [countDistribution?.data]); - const onPatternSelection = async (pattern: string) => { - if (queryRef.current![FILTERED_PATTERN] === pattern) { - return; - } - dispatch( - changeQuery({ - tabId, - query: { - [FILTERED_PATTERN]: pattern, - }, - }) - ); - // workaround to refresh callback and trigger fetch data - await setTempQuery(queryRef.current![RAW_QUERY]); - await handleTimeRangePickerRefresh(true); - }; - const getMainContent = () => { return (
    From 9eb68bfffd66278f710596ff66456ba3e042b7fa Mon Sep 17 00:00:00 2001 From: Eric Wei Date: Tue, 14 Mar 2023 23:07:11 -0700 Subject: [PATCH 20/73] move get data range logic to utils and resolve some linting errors Signed-off-by: Eric Wei --- .../event_analytics/explorer/explorer.tsx | 8 ++--- .../event_analytics/utils/utils.tsx | 30 +++++++++++++++---- 2 files changed, 27 insertions(+), 11 deletions(-) diff --git a/public/components/event_analytics/explorer/explorer.tsx b/public/components/event_analytics/explorer/explorer.tsx index 153600dd46..91a7217a5c 100644 --- a/public/components/event_analytics/explorer/explorer.tsx +++ b/public/components/event_analytics/explorer/explorer.tsx @@ -94,6 +94,7 @@ import { CountDistribution } from './visualizations/count_distribution'; import { QueryManager } from '../../../../common/query_manager'; import { uiSettingsService } from '../../../../common/utils'; import { LogPatterns } from './log_patterns/log_patterns'; +import { getDateRange } from '../utils/utils'; const TYPE_TAB_MAPPING = { [SAVED_QUERY]: TAB_EVENT_ID, @@ -1199,12 +1200,7 @@ export const Explorer = ({ ); }); - const dateRange = - isEmpty(startTime) || isEmpty(endTime) - ? isEmpty(query.selectedDateRange) - ? ['now-15m', 'now'] - : [query.selectedDateRange[0], query.selectedDateRange[1]] - : [startTime, endTime]; + const dateRange = getDateRange(startTime, endTime, query); const handleLiveTailSearch = useCallback( async (startingTime: string, endingTime: string) => { diff --git a/public/components/event_analytics/utils/utils.tsx b/public/components/event_analytics/utils/utils.tsx index 494d1e06a1..fde9ff6dc4 100644 --- a/public/components/event_analytics/utils/utils.tsx +++ b/public/components/event_analytics/utils/utils.tsx @@ -22,6 +22,7 @@ import { GetTooltipHoverInfoType, IExplorerFields, IField, + IQuery, } from '../../../../common/types/explorer'; import PPLService from '../../../services/requests/ppl'; import { DocViewRow, IDocType } from '../explorer/events_views'; @@ -39,7 +40,7 @@ export const getTrs = ( explorerFields: IField[], limit: number, setLimit: React.Dispatch>, - PAGE_SIZE: number, + pageSize: number, timeStampField: any, explorerFieldsFull: IExplorerFields, pplService: PPLService, @@ -65,10 +66,10 @@ export const getTrs = ( if (prevTrs.length >= docs.length) return prevTrs; // reset limit if no previous table rows - if (prevTrs.length === 0 && limit !== PAGE_SIZE) setLimit(PAGE_SIZE); + if (prevTrs.length === 0 && limit !== pageSize) setLimit(pageSize); const trs = prevTrs.slice(); - const upperLimit = Math.min(trs.length === 0 ? PAGE_SIZE : limit, docs.length); + const upperLimit = Math.min(trs.length === 0 ? pageSize : limit, docs.length); const tempRefs = rowRefs; for (let i = trs.length; i < upperLimit; i++) { const docId = uniqueId('doc_view'); @@ -228,7 +229,7 @@ export const fetchSurroundingData = async ( await pplService .fetch({ query: finalQuery, format: 'jdbc' }) .then((res) => { - const resuleData = typeOfDocs == 'new' ? res.jsonData.reverse() : res.jsonData; + const resuleData = typeOfDocs === 'new' ? res.jsonData.reverse() : res.jsonData; resultCount = resuleData.length; setEventsData(createTds(resuleData, selectedCols, getTds)); }) @@ -407,7 +408,7 @@ export const getDefaultVisConfig = (statsToken: statsChunk) => { const getSpanValue = (groupByToken: GroupByChunk) => { const timeUnitValue = TIME_INTERVAL_OPTIONS.find( - (time_unit) => time_unit.value === groupByToken?.span?.span_expression.time_unit + (timeUnit) => timeUnit.value === groupByToken?.span?.span_expression.time_unit )?.text; return !isEmpty(groupByToken?.span) ? { @@ -429,3 +430,22 @@ const getSpanValue = (groupByToken: GroupByChunk) => { } : undefined; }; + +/** + * Use startTime and endTime as date range if both exists, else use selectDatarange + * in query state, if this is also empty then use default 15mins as default date range + * @param startTime + * @param endTime + * @param queryState + * @returns [startTime, endTime] + */ +export const getDateRange = ( + startTime: string | undefined, + endTime: string | undefined, + queryState: IQuery +) => { + if (startTime && endTime) return [startTime, endTime]; + const { selectedDateRange } = queryState; + if (!isEmpty(selectedDateRange)) return [selectedDateRange[0], selectedDateRange[1]]; + return ['now-15m', 'now']; +}; From a2b9858b0a1bdcc353497dd74eaec3d8f984975e Mon Sep 17 00:00:00 2001 From: Eric Wei Date: Wed, 15 Mar 2023 10:03:29 -0700 Subject: [PATCH 21/73] move fields toggle from explorer to under sidebar Signed-off-by: Eric Wei --- .../event_analytics/explorer/explorer.tsx | 50 +----------- .../explorer/sidebar/sidebar.tsx | 77 +++++++++++++++++-- .../explorer/visualizations/index.tsx | 6 -- 3 files changed, 75 insertions(+), 58 deletions(-) diff --git a/public/components/event_analytics/explorer/explorer.tsx b/public/components/event_analytics/explorer/explorer.tsx index 8c6ec2ed3c..9bd371ecd0 100644 --- a/public/components/event_analytics/explorer/explorer.tsx +++ b/public/components/event_analytics/explorer/explorer.tsx @@ -20,11 +20,10 @@ import { } from '@elastic/eui'; import { FormattedMessage } from '@osd/i18n/react'; import classNames from 'classnames'; -import { cloneDeep, has, isEmpty, isEqual, reduce } from 'lodash'; +import { has, isEmpty, isEqual, reduce } from 'lodash'; import React, { ReactElement, useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { batch, useDispatch, useSelector } from 'react-redux'; import { - AVAILABLE_FIELDS, DATE_PICKER_FORMAT, DEFAULT_AVAILABILITY_QUERY, EVENT_ANALYTICS_DOCUMENTATION_URL, @@ -33,7 +32,6 @@ import { PATTERNS_EXTRACTOR_REGEX, PATTERNS_REGEX, PATTERN_REGEX, - PPL_DEFAULT_PATTERN_REGEX_FILETER, RAW_QUERY, SAVED_OBJECT_ID, SAVED_OBJECT_TYPE, @@ -74,8 +72,7 @@ import { Search } from '../../common/search/search'; import { getVizContainerProps } from '../../visualizations/charts/helpers'; import { TabContext, useFetchEvents, useFetchPatterns, useFetchVisualizations } from '../hooks'; import { selectCountDistribution } from '../redux/slices/count_distribution_slice'; -import { selectFields, sortFields, updateFields } from '../redux/slices/field_slice'; -import { selectPatterns } from '../redux/slices/patterns_slice'; +import { selectFields, updateFields } from '../redux/slices/field_slice'; import { selectQueryResult } from '../redux/slices/query_result_slice'; import { changeDateRange, changeQuery, selectQueries } from '../redux/slices/query_slice'; import { updateTabName } from '../redux/slices/query_tab_slice'; @@ -129,11 +126,11 @@ export const Explorer = ({ }: IExplorerProps) => { const dispatch = useDispatch(); const requestParams = { tabId }; - const { getLiveTail, getEvents, getAvailableFields, isEventsLoading } = useFetchEvents({ + const { getLiveTail, getEvents } = useFetchEvents({ pplService, requestParams, }); - const { getVisualizations, getCountVisualizations, isVisLoading } = useFetchVisualizations({ + const { getCountVisualizations } = useFetchVisualizations({ pplService, requestParams, }); @@ -506,11 +503,6 @@ export const Explorer = ({ } }, [savedObjectId]); - const handleAddField = (field: IField) => toggleFields(field, AVAILABLE_FIELDS, SELECTED_FIELDS); - - const handleRemoveField = (field: IField) => - toggleFields(field, SELECTED_FIELDS, AVAILABLE_FIELDS); - const handleTimePickerChange = async (timeRange: string[]) => { if (appLogEvents) { setStartTime(timeRange[0]); @@ -558,36 +550,6 @@ export const Explorer = ({ } }; - /** - * Toggle fields between selected and unselected sets - * @param field field to be toggled - * @param FieldSetToRemove set where this field to be removed from - * @param FieldSetToAdd set where this field to be added - */ - const toggleFields = (field: IField, FieldSetToRemove: string, FieldSetToAdd: string) => { - const nextFields = cloneDeep(explorerFields); - const thisFieldSet = nextFields[FieldSetToRemove]; - const nextFieldSet = thisFieldSet.filter((fd: IField) => fd.name !== field.name); - nextFields[FieldSetToRemove] = nextFieldSet; - nextFields[FieldSetToAdd].push(field); - batch(() => { - dispatch( - updateFields({ - tabId, - data: { - ...nextFields, - }, - }) - ); - dispatch( - sortFields({ - tabId, - data: [FieldSetToAdd], - }) - ); - }); - }; - const sidebarClassName = classNames({ closed: isSidebarClosed, }); @@ -686,8 +648,6 @@ export const Explorer = ({ selectedPattern={query[SELECTED_PATTERN_FIELD]} handleOverrideTimestamp={handleOverrideTimestamp} handleOverridePattern={handleOverridePattern} - handleAddField={(field: IField) => handleAddField(field)} - handleRemoveField={(field: IField) => handleRemoveField(field)} isOverridingTimestamp={isOverridingTimestamp} isOverridingPattern={isOverridingPattern} isFieldToggleButtonDisabled={ @@ -891,8 +851,6 @@ export const Explorer = ({ explorerFields={explorerFields} explorerVis={explorerVisualizations} explorerData={explorerData} - handleAddField={handleAddField} - handleRemoveField={handleRemoveField} visualizations={visualizations} handleOverrideTimestamp={handleOverrideTimestamp} callback={callbackForConfig} diff --git a/public/components/event_analytics/explorer/sidebar/sidebar.tsx b/public/components/event_analytics/explorer/sidebar/sidebar.tsx index 9b57aae095..f949047f56 100644 --- a/public/components/event_analytics/explorer/sidebar/sidebar.tsx +++ b/public/components/event_analytics/explorer/sidebar/sidebar.tsx @@ -3,12 +3,16 @@ * SPDX-License-Identifier: Apache-2.0 */ -import React, { useState } from 'react'; +import React, { useState, useCallback, useContext } from 'react'; +import { batch, useDispatch } from 'react-redux'; import { isEmpty } from 'lodash'; import { EuiTitle, EuiSpacer, EuiFieldSearch, EuiAccordion } from '@elastic/eui'; import { I18nProvider } from '@osd/i18n/react'; import { Field } from './field'; -import { IExplorerFields, IField } from '../../../../../common/types/explorer'; +import { ExplorerFields, IExplorerFields, IField } from '../../../../../common/types/explorer'; +import { AVAILABLE_FIELDS, SELECTED_FIELDS } from '../../../../../common/constants/explorer'; +import { sortFields, updateFields } from '../../redux/slices/field_slice'; +import { TabContext } from '../../hooks/use_tab_context'; interface ISidebarProps { query: string; @@ -21,8 +25,6 @@ interface ISidebarProps { isFieldToggleButtonDisabled: boolean; handleOverridePattern: (pattern: IField) => void; handleOverrideTimestamp: (timestamp: IField) => void; - handleAddField: (field: IField) => void; - handleRemoveField: (field: IField) => void; } export const Sidebar = (props: ISidebarProps) => { @@ -37,13 +39,76 @@ export const Sidebar = (props: ISidebarProps) => { isFieldToggleButtonDisabled, handleOverridePattern, handleOverrideTimestamp, - handleAddField, - handleRemoveField, } = props; + const dispatch = useDispatch(); + const { tabId } = useContext(TabContext); const [showFields, setShowFields] = useState(false); const [searchTerm, setSearchTerm] = useState(''); + /** + * Toggle fields between selected and unselected sets + * @param fieldState all fields in store + * @param field field to be toggled + * @param FieldSetToRemove the set where this field to be removed from + * @param FieldSetToAdd the set where this field to be added to + * returns new fields state + */ + const toggleFields = ( + fieldState: ExplorerFields, + field: IField, + fieldSetToRemove: string, + fieldSetToAdd: string + ): ExplorerFields => { + const nextFields = { ...fieldState }; + nextFields[fieldSetToRemove] = nextFields[fieldSetToRemove].filter( + (fd: IField) => fd.name !== field.name + ); + nextFields[fieldSetToAdd] = [...nextFields[fieldSetToAdd], field]; + return nextFields; + }; + + const updateStoreFields = (fieldsData: ExplorerFields, tabID: string, modifiedField: string) => { + batch(() => { + dispatch( + updateFields({ + tabId: tabID, + data: { + ...fieldsData, + }, + }) + ); + dispatch( + sortFields({ + tabId: tabID, + data: [modifiedField], + }) + ); + }); + }; + + const handleAddField = useCallback( + (field: IField) => { + updateStoreFields( + toggleFields(explorerFields, field, AVAILABLE_FIELDS, SELECTED_FIELDS), + tabId, + SELECTED_FIELDS + ); + }, + [explorerFields, tabId] + ); + + const handleRemoveField = useCallback( + (field: IField) => { + updateStoreFields( + toggleFields(explorerFields, field, SELECTED_FIELDS, AVAILABLE_FIELDS), + tabId, + AVAILABLE_FIELDS + ); + }, + [explorerFields, tabId] + ); + return (
    diff --git a/public/components/event_analytics/explorer/visualizations/index.tsx b/public/components/event_analytics/explorer/visualizations/index.tsx index 11efb16f27..41b6eab6aa 100644 --- a/public/components/event_analytics/explorer/visualizations/index.tsx +++ b/public/components/event_analytics/explorer/visualizations/index.tsx @@ -29,8 +29,6 @@ interface IExplorerVisualizationsProps { explorerVis: any; explorerFields: ExplorerFields; explorerData: any; - handleAddField: (field: IField) => void; - handleRemoveField: (field: IField) => void; visualizations: IVisualizationContainerProps; handleOverrideTimestamp: (field: IField) => void; callback?: any; @@ -44,8 +42,6 @@ export const ExplorerVisualizations = ({ explorerVis, explorerFields, explorerData, - handleAddField, - handleRemoveField, visualizations, handleOverrideTimestamp, callback, @@ -111,8 +107,6 @@ export const ExplorerVisualizations = ({ explorerData={explorerData} selectedTimestamp={visualizations?.data?.query[SELECTED_TIMESTAMP] || ''} handleOverrideTimestamp={handleOverrideTimestamp} - handleAddField={(field: IField) => handleAddField(field)} - handleRemoveField={(field: IField) => handleRemoveField(field)} isFieldToggleButtonDisabled={ vis.name === VIS_CHART_TYPES.LogsView ? isEmpty(explorerData.jsonData) || From dac21f43bd02599f8215e15d9dee145702fcaa0e Mon Sep 17 00:00:00 2001 From: Eric Wei Date: Wed, 15 Mar 2023 10:04:06 -0700 Subject: [PATCH 22/73] fix the bug when switching index seeing fields from old index Signed-off-by: Eric Wei --- public/components/event_analytics/hooks/use_fetch_events.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/public/components/event_analytics/hooks/use_fetch_events.ts b/public/components/event_analytics/hooks/use_fetch_events.ts index 4bab880845..bbcbb4b785 100644 --- a/public/components/event_analytics/hooks/use_fetch_events.ts +++ b/public/components/event_analytics/hooks/use_fetch_events.ts @@ -83,6 +83,7 @@ export const useFetchEvents = ({ pplService, requestParams }: IFetchEventsParams [UNSELECTED_FIELDS]: res?.schema ? [...res.schema] : [], [QUERIED_FIELDS]: [], [AVAILABLE_FIELDS]: res?.schema || [], + [SELECTED_FIELDS]: [], }, }) ); From 436bf2b00bf17f6ea4282396d917dadeb1f2a60b Mon Sep 17 00:00:00 2001 From: Eric Wei Date: Wed, 15 Mar 2023 10:04:42 -0700 Subject: [PATCH 23/73] update tests/snapshots Signed-off-by: Eric Wei --- .../__snapshots__/sidebar.test.tsx.snap | 14502 ++++++++-------- .../sidebar/__tests__/sidebar.test.tsx | 84 +- 2 files changed, 7308 insertions(+), 7278 deletions(-) diff --git a/public/components/event_analytics/explorer/sidebar/__tests__/__snapshots__/sidebar.test.tsx.snap b/public/components/event_analytics/explorer/sidebar/__tests__/__snapshots__/sidebar.test.tsx.snap index 556467262e..1d5a67a003 100644 --- a/public/components/event_analytics/explorer/sidebar/__tests__/__snapshots__/sidebar.test.tsx.snap +++ b/public/components/event_analytics/explorer/sidebar/__tests__/__snapshots__/sidebar.test.tsx.snap @@ -1,857 +1,803 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`Siderbar component Renders empty sidebar component 1`] = ` - - - + + - -
    -
    + +
    - - -
    - - - - -
    - + + + +
    - - - - -
    -
    + > + + + + +
    +
    +
    +
    -
    - - - - + + + + +
    +
    - -
    -
    -
    -
    -
    -
    +
    + + +
    + + `; exports[`Siderbar component Renders sidebar component 1`] = ` - - - + + - -
    -
    + +
    - - -
    - - - - -
    - + + + +
    - - - - -
    -
    + + + + + + +
    +
    +
    +
    -
    - - - - -
    - -
    - - - Query fields - - - } - id="fieldSelector__queriedFields" - initialIsOpen={true} - isLoading={false} - isLoadingMessage={false} - paddingSize="xs" + + +
    +
    + +
    + + + Query fields + + + } + id="fieldSelector__queriedFields" + initialIsOpen={true} + isLoading={false} + isLoadingMessage={false} + paddingSize="xs" >
    - -
    -
    - + Query fields + + + + +
    +
    -
    -
    -
      +
      +
      -
    • - - - - - - - - - - - - - - - } - fieldIcon={ - - } - fieldName={ - - double_per_ip_bytes - - } - isActive={false} - onClick={[Function]} - size="m" - /> + -
      -
      + + } + closePopover={[Function]} + display="block" + hasArrow={true} + isOpen={false} + ownFocus={true} + panelClassName="dscSidebarItem__fieldPopoverPanel" + panelPaddingSize="m" + > +
      +
      -
      + + + + + + + + + + + + + } + fieldIcon={ + + } + fieldName={ + + double_per_ip_bytes + + } + isActive={false} + onClick={[Function]} + size="m" > - -
      - - - - - - - - +
      + - + + + + + + - - - - + > + + + + + + + +
      -
      - + +
      -
      - - -
    • -
    • - + +
    • +
    • - - - - - - - - - - - - - - } - fieldIcon={ - - } - fieldName={ - - host - - } - isActive={false} - onClick={[Function]} - size="m" - /> + -
      -
      + + } + closePopover={[Function]} + display="block" + hasArrow={true} + isOpen={false} + ownFocus={true} + panelClassName="dscSidebarItem__fieldPopoverPanel" + panelPaddingSize="m" + > +
      +
      -
      + + + + + + + + + + + + + } + fieldIcon={ + + } + fieldName={ + + host + + } + isActive={false} + onClick={[Function]} + size="m" > - -
      - - - - - - - - +
      + - + + + + + + - - - - + > + + + + + + + +
      -
      - + +
      -
      - - -
    • -
    • - + +
    • +
    • - - - - - - - - - - - - - - } - fieldIcon={ - - } - fieldName={ - - ip_count - - } - isActive={false} - onClick={[Function]} - size="m" - /> + -
      -
      + + } + closePopover={[Function]} + display="block" + hasArrow={true} + isOpen={false} + ownFocus={true} + panelClassName="dscSidebarItem__fieldPopoverPanel" + panelPaddingSize="m" + > +
      +
      -
      + + + + + + + + + + + + + } + fieldIcon={ + + } + fieldName={ + + ip_count + + } + isActive={false} + onClick={[Function]} + size="m" > - -
      - - - - - - - - +
      + - + + + + + + - - - - + > + + + + + + + +
      -
      - + +
      -
      - - -
    • -
    • - + +
    • +
    • - - - - - - - - - - - - - - } - fieldIcon={ - - } - fieldName={ - - per_ip_bytes - - } - isActive={false} - onClick={[Function]} - size="m" - /> + -
      -
      + + } + closePopover={[Function]} + display="block" + hasArrow={true} + isOpen={false} + ownFocus={true} + panelClassName="dscSidebarItem__fieldPopoverPanel" + panelPaddingSize="m" + > +
      +
      -
      + + + + + + + + + + + + + } + fieldIcon={ + + } + fieldName={ + + per_ip_bytes + + } + isActive={false} + onClick={[Function]} + size="m" > - -
      - - - - - - - - +
      + - + + + + + + - - - - + > + + + + + + + +
      -
      - + +
      -
      - - -
    • -
    • - + +
    • +
    • - - - - - - - - - - - - - - } - fieldIcon={ - - } - fieldName={ - - resp_code - - } - isActive={false} - onClick={[Function]} - size="m" - /> + -
      -
      + + } + closePopover={[Function]} + display="block" + hasArrow={true} + isOpen={false} + ownFocus={true} + panelClassName="dscSidebarItem__fieldPopoverPanel" + panelPaddingSize="m" + > +
      +
      -
      + + + + + + + + + + + + + } + fieldIcon={ + + } + fieldName={ + + resp_code + + } + isActive={false} + onClick={[Function]} + size="m" > - -
      + +
      + + + + + + + + + + + + + +
      +
      + +
      +
      + + +
    • +
    • + + - + - + - + - - - - -
    • -
      - -
    -
    - - - -
  • - - - - - - - - - - - - - - - } - fieldIcon={ - - } - fieldName={ - - sum_bytes - - } - isActive={false} - onClick={[Function]} - size="m" - /> - } - closePopover={[Function]} - display="block" - hasArrow={true} - isOpen={false} - ownFocus={true} - panelClassName="dscSidebarItem__fieldPopoverPanel" - panelPaddingSize="m" - > -
    -
    - - - - - - - - - - + } + closePopover={[Function]} + display="block" + hasArrow={true} + isOpen={false} + ownFocus={true} + panelClassName="dscSidebarItem__fieldPopoverPanel" + panelPaddingSize="m" + > +
    +
    -
    + + + + + + + + + + + + + } + fieldIcon={ + + } + fieldName={ + + sum_bytes + + } + isActive={false} + onClick={[Function]} + size="m" > - -
    - - - - - - - - +
    + - + + + + + + - - - - + > + + + + + + + +
    -
    - + +
    -
    - - -
  • - + + + + +
    -
    - + +
    - - - -
    - - - - Selected Fields - - - } - id="fieldSelector__selectedFields" - initialIsOpen={true} - isLoading={false} - isLoadingMessage={false} - paddingSize="xs" - > -
    +
    + + + + Selected Fields + + + } + id="fieldSelector__selectedFields" + initialIsOpen={true} + isLoading={false} + isLoadingMessage={false} + paddingSize="xs" + > +
    - -
    -
    - + Selected Fields + + + + +
    +
    -
    -
    -
      + +
      +
      +
        +
      -
    - + +
    -
    - - -
    - - - - Available Fields - - - } - id="fieldSelector__availableFields" - initialIsOpen={true} - isLoading={false} - isLoadingMessage={false} - paddingSize="xs" - > -
    +
    + + + + Available Fields + + + } + id="fieldSelector__availableFields" + initialIsOpen={true} + isLoading={false} + isLoadingMessage={false} + paddingSize="xs" + > +
    - -
    -
    - + Available Fields + + + + +
    +
    -
    -
    -
      +
      +
      -
    • - - - - - - Override - - - - - - - - - - - - - } - fieldIcon={ - - } - fieldName={ - - agent - - } - isActive={false} - onClick={[Function]} - size="m" - /> + -
      -
      + + } + closePopover={[Function]} + display="block" + hasArrow={true} + isOpen={false} + ownFocus={true} + panelClassName="dscSidebarItem__fieldPopoverPanel" + panelPaddingSize="m" + > +
      +
      -
      + + + + Override + + + + + + + + + + + + + } + fieldIcon={ + + } + fieldName={ + + agent + + } + isActive={false} + onClick={[Function]} + size="m" > - -
      - - +
      + - - - - - - - - - - + + + + + + + + - + + + - - - - + > + + + + + + + +
      -
      - + +
      -
      - - -
    • -
    • - + +
    • +
    • - - - - - - - - - - - - - - } - fieldIcon={ - - } - fieldName={ - - bytes - - } - isActive={false} - onClick={[Function]} - size="m" - /> + -
      -
      + + } + closePopover={[Function]} + display="block" + hasArrow={true} + isOpen={false} + ownFocus={true} + panelClassName="dscSidebarItem__fieldPopoverPanel" + panelPaddingSize="m" + > +
      +
      -
      - + } + isActive={false} + onClick={[Function]} + size="m" + >
      - - - - - - + className="osdFieldButton__fieldIcon" + > + + + + + + + + + + + + - + bytes + + + +
      + + + + + + + + - - - - + > + + + + + + + +
      -
      - + +
      -
      - - -
    • -
    • - + +
    • +
    • - - - - - - - - - - - - - - } - fieldIcon={ - - } - fieldName={ - - clientip - - } - isActive={false} - onClick={[Function]} - size="m" - /> + -
      -
      + + } + closePopover={[Function]} + display="block" + hasArrow={true} + isOpen={false} + ownFocus={true} + panelClassName="dscSidebarItem__fieldPopoverPanel" + panelPaddingSize="m" + > +
      +
      -
      + + + + + + + + + + + + + } + fieldIcon={ + + } + fieldName={ + + clientip + + } + isActive={false} + onClick={[Function]} + size="m" > - -
      - - - - - - - - +
      + - + + + + + + - - - - + > + + + + + + + +
      -
      - + +
      -
      - - -
    • -
    • - + +
    • +
    • - - - - - - - - - - - - - - } - fieldIcon={ - - } - fieldName={ - - event - - } - isActive={false} - onClick={[Function]} - size="m" - /> + -
      -
      + + } + closePopover={[Function]} + display="block" + hasArrow={true} + isOpen={false} + ownFocus={true} + panelClassName="dscSidebarItem__fieldPopoverPanel" + panelPaddingSize="m" + > +
      +
      -
      + + + + + + + + + + + + + } + fieldIcon={ + + } + fieldName={ + + event + + } + isActive={false} + onClick={[Function]} + size="m" > - -
      - - - - - - - - +
      + - + + + + + + - - - - + > + + + + + + + +
      -
      - + +
      -
      - - -
    • -
    • - + +
    • +
    • - - - - - Override - - - - - - - - - - - - - } - fieldIcon={ - - } - fieldName={ - - extension - - } - isActive={false} - onClick={[Function]} - size="m" - /> + -
      -
      + + } + closePopover={[Function]} + display="block" + hasArrow={true} + isOpen={false} + ownFocus={true} + panelClassName="dscSidebarItem__fieldPopoverPanel" + panelPaddingSize="m" + > +
      +
      -
      + + + + Override + + + + + + + + + + + + + } + fieldIcon={ + + } + fieldName={ + + extension + + } + isActive={false} + onClick={[Function]} + size="m" > - -
      - - +
      + - - - - - - - - - - + + + + + + + + - + + + - - - - + > + + + + + + + +
      -
      - + +
      -
      - - -
    • -
    • - + +
    • +
    • - - - - - - - - - - - - - - } - fieldIcon={ - - } - fieldName={ - - geo - - } - isActive={false} - onClick={[Function]} - size="m" - /> + -
      -
      + + } + closePopover={[Function]} + display="block" + hasArrow={true} + isOpen={false} + ownFocus={true} + panelClassName="dscSidebarItem__fieldPopoverPanel" + panelPaddingSize="m" + > +
      +
      -
      + + + + + + + + + + + + + } + fieldIcon={ + + } + fieldName={ + + geo + + } + isActive={false} + onClick={[Function]} + size="m" > - -
      - - - - - - - - +
      + - + + + + + + - - - - + > + + + + + + + +
      -
      - + +
      -
      - - -
    • -
    • - + +
    • +
    • - - - - - Override - - - - - - - - - - - - - } - fieldIcon={ - - } - fieldName={ - - host - - } - isActive={false} - onClick={[Function]} - size="m" - /> + -
      -
      + + } + closePopover={[Function]} + display="block" + hasArrow={true} + isOpen={false} + ownFocus={true} + panelClassName="dscSidebarItem__fieldPopoverPanel" + panelPaddingSize="m" + > +
      +
      -
      + + + + Override + + + + + + + + + + + + + } + fieldIcon={ + + } + fieldName={ + + host + + } + isActive={false} + onClick={[Function]} + size="m" > - -
      - - +
      + - - - - - - - - - - + + + + + + + + - + + + - - - - + > + + + + + + + +
      -
      - + +
      -
      - - -
    • -
    • - + +
    • +
    • - - - - - Override - - - - - - - - - - - - - } - fieldIcon={ - - } - fieldName={ - - index - - } - isActive={false} - onClick={[Function]} - size="m" - /> + -
      -
      + + } + closePopover={[Function]} + display="block" + hasArrow={true} + isOpen={false} + ownFocus={true} + panelClassName="dscSidebarItem__fieldPopoverPanel" + panelPaddingSize="m" + > +
      +
      -
      + + + + Override + + + + + + + + + + + + + } + fieldIcon={ + + } + fieldName={ + + index + + } + isActive={false} + onClick={[Function]} + size="m" > - -
      - - +
      + - - - - - - - - - - + + - + + + - - - - + > + + + + + + + +
      -
      - + +
      -
      - - -
    • -
    • - + +
    • +
    • - - - - - - - - - - - - - - } - fieldIcon={ - - } - fieldName={ - - ip - - } - isActive={false} - onClick={[Function]} - size="m" - /> + -
      -
      + + } + closePopover={[Function]} + display="block" + hasArrow={true} + isOpen={false} + ownFocus={true} + panelClassName="dscSidebarItem__fieldPopoverPanel" + panelPaddingSize="m" + > +
      +
      -
      + + + + + + + + + + + + + } + fieldIcon={ + + } + fieldName={ + + ip + + } + isActive={false} + onClick={[Function]} + size="m" > - -
      - - - - - - - - +
      + - + + + + + + - - - - + > + + + + + + + +
      -
      - + +
      -
      - - -
    • -
    • - + +
    • +
    • - - - - - - - - - - - - - - } - fieldIcon={ - - } - fieldName={ - - machine - - } - isActive={false} - onClick={[Function]} - size="m" - /> + -
      -
      + + } + closePopover={[Function]} + display="block" + hasArrow={true} + isOpen={false} + ownFocus={true} + panelClassName="dscSidebarItem__fieldPopoverPanel" + panelPaddingSize="m" + > +
      +
      -
      + + + + + + + + + + + + + } + fieldIcon={ + + } + fieldName={ + + machine + + } + isActive={false} + onClick={[Function]} + size="m" > - -
      - - - - - - - - +
      + - + + + + + + - - - - + > + + + + + + + +
      -
      - + +
      -
      - - -
    • -
    • - + +
    • +
    • - - - - - - - - - - - - - - } - fieldIcon={ - - } - fieldName={ - - memory - - } - isActive={false} - onClick={[Function]} - size="m" - /> + -
      -
      + + } + closePopover={[Function]} + display="block" + hasArrow={true} + isOpen={false} + ownFocus={true} + panelClassName="dscSidebarItem__fieldPopoverPanel" + panelPaddingSize="m" + > +
      +
      -
      + + + + + + + + + + + + + } + fieldIcon={ + + } + fieldName={ + + memory + + } + isActive={false} + onClick={[Function]} + size="m" > - -
      - - - - - - - - +
      + - + + + + + + - - - - + > + + + + + + + +
      -
      - + +
      -
      - - -
    • -
    • - + +
    • +
    • - - - - - Override - - - - - - - - - - - - - } - fieldIcon={ - - } - fieldName={ - - message - - } - isActive={false} - onClick={[Function]} - size="m" - /> + -
      -
      + + } + closePopover={[Function]} + display="block" + hasArrow={true} + isOpen={false} + ownFocus={true} + panelClassName="dscSidebarItem__fieldPopoverPanel" + panelPaddingSize="m" + > +
      +
      -
      + + + + Override + + + + + + + + + + + + + } + fieldIcon={ + + } + fieldName={ + + message + + } + isActive={false} + onClick={[Function]} + size="m" > - -
      - - +
      + - - - - - - - - - - + + + + + + + + - + + + - - - - + > + + + + + + + +
      -
      - + +
      -
      - - -
    • -
    • - + +
    • +
    • - - - - - - - - - - - - - - } - fieldIcon={ - - } - fieldName={ - - phpmemory - - } - isActive={false} - onClick={[Function]} - size="m" - /> + -
      -
      + + } + closePopover={[Function]} + display="block" + hasArrow={true} + isOpen={false} + ownFocus={true} + panelClassName="dscSidebarItem__fieldPopoverPanel" + panelPaddingSize="m" + > +
      +
      -
      + + + + + + + + + + + + + } + fieldIcon={ + + } + fieldName={ + + phpmemory + + } + isActive={false} + onClick={[Function]} + size="m" > - -
      - - - - - - - - +
      + - + + + + + + - - - - + > + + + + + + + +
      -
      - + +
      -
      - - -
    • -
    • - + +
    • +
    • - - - - - Override - - - - - - - - - - - - - } - fieldIcon={ - - } - fieldName={ - - referer - - } - isActive={false} - onClick={[Function]} - size="m" - /> + -
      -
      + + } + closePopover={[Function]} + display="block" + hasArrow={true} + isOpen={false} + ownFocus={true} + panelClassName="dscSidebarItem__fieldPopoverPanel" + panelPaddingSize="m" + > +
      +
      -
      + + + + Override + + + + + + + + + + + + + } + fieldIcon={ + + } + fieldName={ + + referer + + } + isActive={false} + onClick={[Function]} + size="m" > - -
      - - +
      + - - - - - - - - - - + + + + + + + + - + + + - - - - + > + + + + + + + +
      -
      - + +
      -
      - - -
    • -
    • - + +
    • +
    • - - - - - Override - - - - - - - - - - - - - } - fieldIcon={ - - } - fieldName={ - - request - - } - isActive={false} - onClick={[Function]} - size="m" - /> + -
      -
      + + } + closePopover={[Function]} + display="block" + hasArrow={true} + isOpen={false} + ownFocus={true} + panelClassName="dscSidebarItem__fieldPopoverPanel" + panelPaddingSize="m" + > +
      +
      -
      + + + + Override + + + + + + + + + + + + + } + fieldIcon={ + + } + fieldName={ + + request + + } + isActive={false} + onClick={[Function]} + size="m" > - -
      - - +
      + - - - - - - - - - - + + + + + + + + - + + + - - - - + > + + + + + + + +
      -
      - + +
      -
      - - -
    • -
    • - + +
    • +
    • - - - - - Override - - - - - - - - - - - - - } - fieldIcon={ - - } - fieldName={ - - response - - } - isActive={false} - onClick={[Function]} - size="m" - /> + -
      -
      + + } + closePopover={[Function]} + display="block" + hasArrow={true} + isOpen={false} + ownFocus={true} + panelClassName="dscSidebarItem__fieldPopoverPanel" + panelPaddingSize="m" + > +
      +
      -
      + + + + Override + + + + + + + + + + + + + } + fieldIcon={ + + } + fieldName={ + + response + + } + isActive={false} + onClick={[Function]} + size="m" > - -
      - - +
      + - - - - - - - - - - + + + + + + + + - + + + - - - - + > + + + + + + + +
      -
      - + +
      -
      - - -
    • -
    • - + +
    • +
    • - - - - - Override - - - - - - - - - - - - - } - fieldIcon={ - - } - fieldName={ - - tags - - } - isActive={false} - onClick={[Function]} - size="m" - /> + -
      -
      + + } + closePopover={[Function]} + display="block" + hasArrow={true} + isOpen={false} + ownFocus={true} + panelClassName="dscSidebarItem__fieldPopoverPanel" + panelPaddingSize="m" + > +
      +
      -
      + + + + Override + + + + + + + + + + + + + } + fieldIcon={ + + } + fieldName={ + + tags + + } + isActive={false} + onClick={[Function]} + size="m" > - -
      - - +
      + - - - - - - - - - - + + + + + + + + - + + + - - - - -
      -
      - -
      -
      - - -
    • -
    • - - - - - - - - - Default Timestamp - - - - - - - - - - } - fieldIcon={ - - } - fieldName={ - - timestamp - - } - isActive={false} - onClick={[Function]} - size="m" - /> + + + + + +
    • +
      + +
    +
    + + + +
  • + -
    -
    + + } + closePopover={[Function]} + display="block" + hasArrow={true} + isOpen={false} + ownFocus={true} + panelClassName="dscSidebarItem__fieldPopoverPanel" + panelPaddingSize="m" + > +
    +
    -
    + + + + + + + Default Timestamp + + + + + + + + + + } + fieldIcon={ + + } + fieldName={ + + timestamp + + } + isActive={false} + onClick={[Function]} + size="m" > - -
    - - - - - +
    + - + + + - - Default Timestamp - - - - - - + Default Timestamp + + + + + - - - - - + > + + + + + + + +
    -
    - + +
    -
    - - -
  • -
  • - + +
  • +
  • - - - - - Override - - - - - - - - - - - - - } - fieldIcon={ - - } - fieldName={ - - url - - } - isActive={false} - onClick={[Function]} - size="m" - /> + -
    -
    + + } + closePopover={[Function]} + display="block" + hasArrow={true} + isOpen={false} + ownFocus={true} + panelClassName="dscSidebarItem__fieldPopoverPanel" + panelPaddingSize="m" + > +
    +
    -
    + + + + Override + + + + + + + + + + + + + } + fieldIcon={ + + } + fieldName={ + + url + + } + isActive={false} + onClick={[Function]} + size="m" > - -
    - - +
    + - - - - - - - - - - + + + + + + + + - + + + - - - - + > + + + + + + + +
    -
    - + +
    -
    - - -
  • -
  • - + +
  • +
  • - - - - - - - - Override - - - - - - - - - - } - fieldIcon={ - - } - fieldName={ - - utc_time - - } - isActive={false} - onClick={[Function]} - size="m" - /> + -
    -
    + + } + closePopover={[Function]} + display="block" + hasArrow={true} + isOpen={false} + ownFocus={true} + panelClassName="dscSidebarItem__fieldPopoverPanel" + panelPaddingSize="m" + > +
    +
    -
    + + + + + + + Override + + + + + + + + + + } + fieldIcon={ + + } + fieldName={ + + utc_time + + } + isActive={false} + onClick={[Function]} + size="m" > - -
    - - - - - +
    + - + + + - - - - - - + + + + + + + + - - - - - + > + + + + + + + +
    -
    - + +
    -
    - - -
  • - + + + + +
    -
    - + +
    -
    - - -
    -
    -
    -
    -
    + + + + + + + + `; diff --git a/public/components/event_analytics/explorer/sidebar/__tests__/sidebar.test.tsx b/public/components/event_analytics/explorer/sidebar/__tests__/sidebar.test.tsx index 6e1b9c5c7d..ae18768c19 100644 --- a/public/components/event_analytics/explorer/sidebar/__tests__/sidebar.test.tsx +++ b/public/components/event_analytics/explorer/sidebar/__tests__/sidebar.test.tsx @@ -4,52 +4,64 @@ */ import { configure, mount } from 'enzyme'; +import { useDispatch, Provider } from 'react-redux'; +import { configureStore } from '@reduxjs/toolkit'; import Adapter from 'enzyme-adapter-react-16'; import React from 'react'; import { waitFor } from '@testing-library/react'; import { Sidebar } from '../sidebar'; -import { - SELECTED_FIELDS, +import { + SELECTED_FIELDS, AVAILABLE_FIELDS, UNSELECTED_FIELDS, - QUERIED_FIELDS + QUERIED_FIELDS, } from '../../../../../../common/constants/explorer'; -import { +import { AVAILABLE_FIELDS as SIDEBAR_AVAILABLE_FIELDS, QUERY_FIELDS, JSON_DATA, - JSON_DATA_ALL + JSON_DATA_ALL, } from '../../../../../../test/event_analytics_constants'; +jest.mock('react-redux', () => ({ + ...jest.requireActual('react-redux'), + useDispatch: jest.fn(), +})); + describe('Siderbar component', () => { configure({ adapter: new Adapter() }); + const store = configureStore({ + reducer: jest.fn(), + }); + beforeEach(() => { + useDispatch.mockClear(); + useDispatch.mockReturnValue(jest.fn()); + }); it('Renders empty sidebar component', async () => { const explorerFields = { [SELECTED_FIELDS]: [], [AVAILABLE_FIELDS]: [], [UNSELECTED_FIELDS]: [], - [QUERIED_FIELDS]: [] + [QUERIED_FIELDS]: [], }; - const handleAddField = jest.fn(); const handleOverrideTimestamp = jest.fn(); const selectedTimestamp = 'timestamp'; const explorerData = {}; - const handleRemoveField = jest.fn(); - + const wrapper = mount( - + + + ); - + wrapper.update(); await waitFor(() => { @@ -62,32 +74,30 @@ describe('Siderbar component', () => { [SELECTED_FIELDS]: [], [UNSELECTED_FIELDS]: [], [AVAILABLE_FIELDS]: SIDEBAR_AVAILABLE_FIELDS, - [QUERIED_FIELDS]: QUERY_FIELDS + [QUERIED_FIELDS]: QUERY_FIELDS, }; - const handleAddField = jest.fn(); const handleOverrideTimestamp = jest.fn(); const selectedTimestamp = 'timestamp'; const explorerData = { - 'jsonData': JSON_DATA, - 'jsonDataAll': JSON_DATA_ALL + jsonData: JSON_DATA, + jsonDataAll: JSON_DATA_ALL, }; - const handleRemoveField = jest.fn(); - + const wrapper = mount( - + + + ); await waitFor(() => { expect(wrapper).toMatchSnapshot(); }); }); -}); \ No newline at end of file +}); From 7027b0158e4526338c8c11eb8e79013c05080c39 Mon Sep 17 00:00:00 2001 From: Eric Wei Date: Wed, 15 Mar 2023 13:21:31 -0700 Subject: [PATCH 24/73] move tab constants to constant file Signed-off-by: Eric Wei --- common/constants/explorer.ts | 5 +++++ public/components/event_analytics/explorer/explorer.tsx | 6 +----- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/common/constants/explorer.ts b/common/constants/explorer.ts index a26677c898..a9a44d2433 100644 --- a/common/constants/explorer.ts +++ b/common/constants/explorer.ts @@ -309,3 +309,8 @@ export const sampleLogPatternData = { "Mozilla/5.0 (X11; Linux x86_64; rv:6.0a1) Gecko/20110421 Firefox/6.0a1"', anomalyCount: 0, }; + +export const TYPE_TAB_MAPPING = { + [SAVED_QUERY]: TAB_EVENT_ID, + [SAVED_VISUALIZATION]: TAB_CHART_ID, +}; diff --git a/public/components/event_analytics/explorer/explorer.tsx b/public/components/event_analytics/explorer/explorer.tsx index 91a7217a5c..4bf80a231d 100644 --- a/public/components/event_analytics/explorer/explorer.tsx +++ b/public/components/event_analytics/explorer/explorer.tsx @@ -47,6 +47,7 @@ import { TAB_EVENT_ID, TAB_EVENT_TITLE, TIME_INTERVAL_OPTIONS, + TYPE_TAB_MAPPING, } from '../../../../common/constants/explorer'; import { LIVE_END_TIME, @@ -96,11 +97,6 @@ import { uiSettingsService } from '../../../../common/utils'; import { LogPatterns } from './log_patterns/log_patterns'; import { getDateRange } from '../utils/utils'; -const TYPE_TAB_MAPPING = { - [SAVED_QUERY]: TAB_EVENT_ID, - [SAVED_VISUALIZATION]: TAB_CHART_ID, -}; - export const Explorer = ({ pplService, dslService, From bb31a6d07f3845efc3296997f2d87f8061778882 Mon Sep 17 00:00:00 2001 From: Eric Wei Date: Wed, 15 Mar 2023 21:38:19 -0700 Subject: [PATCH 25/73] proper browser focus attach/detach handler Signed-off-by: Eric Wei --- .../event_analytics/explorer/explorer.tsx | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/public/components/event_analytics/explorer/explorer.tsx b/public/components/event_analytics/explorer/explorer.tsx index 4bf80a231d..2d414c63e5 100644 --- a/public/components/event_analytics/explorer/explorer.tsx +++ b/public/components/event_analytics/explorer/explorer.tsx @@ -217,14 +217,15 @@ export const Explorer = ({ }; useEffect(() => { - document.addEventListener('visibilitychange', function () { - if (document.hidden) { - setBrowserTabFocus(false); - } else { - setBrowserTabFocus(true); - } - }); - }); + const handleSetBrowserTabFocus = () => { + if (document.hidden) setBrowserTabFocus(false); + else setBrowserTabFocus(true); + }; + document.addEventListener('visibilitychange', handleSetBrowserTabFocus); + return () => { + document.removeEventListener('visibilitychange', handleSetBrowserTabFocus); + }; + }, []); const getErrorHandler = (title: string) => { return (error: any) => { From cf9bd1890f441a71fce2a2d466ceccb838ee74f9 Mon Sep 17 00:00:00 2001 From: Eric Wei Date: Mon, 20 Mar 2023 18:53:34 -0700 Subject: [PATCH 26/73] remove unused functions Signed-off-by: Eric Wei --- .../event_analytics/saved_objects.ts | 62 +------------------ 1 file changed, 2 insertions(+), 60 deletions(-) diff --git a/public/services/saved_objects/event_analytics/saved_objects.ts b/public/services/saved_objects/event_analytics/saved_objects.ts index 0f207ab793..d1dd343959 100644 --- a/public/services/saved_objects/event_analytics/saved_objects.ts +++ b/public/services/saved_objects/event_analytics/saved_objects.ts @@ -150,28 +150,6 @@ export default class SavedObjects { ); } - async bulkUpdateSavedVisualization(params: IBulkUpdateSavedVisualizationRquest) { - const finalParams = this.buildRequestBody({ - query: params.query, - fields: params.fields, - dateRange: params.dateRange, - chartType: params.type, - name: params.name, - }); - - return await Promise.all( - params.savedObjectList.map((objectToUpdate) => { - finalParams.object_id = objectToUpdate.saved_object.objectId; - return this.http.put( - `${OBSERVABILITY_BASE}${EVENT_ANALYTICS}${SAVED_OBJECTS}${SAVED_VISUALIZATION}`, - { - body: JSON.stringify(finalParams), - } - ); - }) - ); - } - async updateSavedVisualizationById(params: any) { const finalParams = this.buildRequestBody({ query: params.query, @@ -184,7 +162,7 @@ export default class SavedObjects { description: params.description, subType: params.subType, unitsOfMeasure: params.unitsOfMeasure, - selectedLabels: params.selectedLabels + selectedLabels: params.selectedLabels, }); finalParams.object_id = params.objectId; @@ -247,7 +225,7 @@ export default class SavedObjects { description: params.description, subType: params.subType, unitsOfMeasure: params.unitsOfMeasure, - selectedLabels: params.selectedLabels + selectedLabels: params.selectedLabels, }); return await this.http.post( @@ -258,40 +236,6 @@ export default class SavedObjects { ); } - async createSavedTimestamp(params: any) { - const finalParams = { - index: params.index, - name: params.name, - type: params.type, - dsl_type: params.dsl_type, - }; - - return await this.http.post( - `${OBSERVABILITY_BASE}${EVENT_ANALYTICS}${SAVED_OBJECTS}/timestamp`, - { - body: JSON.stringify(finalParams), - } - ); - } - - async updateTimestamp(params: any) { - const finalParams = { - objectId: params.index, - timestamp: { - name: params.name, - index: params.index, - type: params.type, - dsl_type: params.dsl_type, - }, - }; - return await this.http.put( - `${OBSERVABILITY_BASE}${EVENT_ANALYTICS}${SAVED_OBJECTS}/timestamp`, - { - body: JSON.stringify(finalParams), - } - ); - } - async deleteSavedObjectsList(deleteObjectRequest: any) { return await this.http.delete( `${OBSERVABILITY_BASE}${EVENT_ANALYTICS}${SAVED_OBJECTS}/${deleteObjectRequest.objectIdList.join( @@ -299,6 +243,4 @@ export default class SavedObjects { )}` ); } - - deleteSavedObjectsByIdList(deleteObjectRequesList: any) {} } From 7138ea64d012c7bb0847ed08c8dbd3b1cd2dbb6a Mon Sep 17 00:00:00 2001 From: Eric Wei Date: Mon, 20 Mar 2023 23:33:26 -0700 Subject: [PATCH 27/73] add new savedObject client for refactoring Signed-off-by: Eric Wei --- .../saved_object_client/client_base.ts | 16 +++ .../saved_object_client/client_interface.ts | 14 +++ .../saved_object_client/ppl/index.ts | 9 ++ .../saved_object_client/ppl/panels.ts | 42 ++++++++ .../saved_object_client/ppl/ppl_client.ts | 102 ++++++++++++++++++ .../saved_object_client/ppl/saved_query.ts | 63 +++++++++++ .../ppl/saved_visualization.ts | 81 ++++++++++++++ 7 files changed, 327 insertions(+) create mode 100644 public/services/saved_objects/saved_object_client/client_base.ts create mode 100644 public/services/saved_objects/saved_object_client/client_interface.ts create mode 100644 public/services/saved_objects/saved_object_client/ppl/index.ts create mode 100644 public/services/saved_objects/saved_object_client/ppl/panels.ts create mode 100644 public/services/saved_objects/saved_object_client/ppl/ppl_client.ts create mode 100644 public/services/saved_objects/saved_object_client/ppl/saved_query.ts create mode 100644 public/services/saved_objects/saved_object_client/ppl/saved_visualization.ts diff --git a/public/services/saved_objects/saved_object_client/client_base.ts b/public/services/saved_objects/saved_object_client/client_base.ts new file mode 100644 index 0000000000..05d6e8a1c6 --- /dev/null +++ b/public/services/saved_objects/saved_object_client/client_base.ts @@ -0,0 +1,16 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { ISavedObjectsClient } from './client_interface'; + +export abstract class SavedObjectClientBase implements ISavedObjectsClient { + abstract create(params: any): Promise; + abstract get(params: any): Promise; + abstract getBulk(params: any): Promise>>; + abstract update(params: any): Promise; + abstract updateBulk(params: any): Promise>>; + abstract delete(params: any): Promise; + abstract deleteBulk(params: any): Promise>>; +} diff --git a/public/services/saved_objects/saved_object_client/client_interface.ts b/public/services/saved_objects/saved_object_client/client_interface.ts new file mode 100644 index 0000000000..4856639c12 --- /dev/null +++ b/public/services/saved_objects/saved_object_client/client_interface.ts @@ -0,0 +1,14 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +export interface ISavedObjectsClient { + create: (params: any) => Promise; + get: (params: any) => Promise; + getBulk: (params: any) => Promise>>; + update: (params: any) => Promise; + updateBulk: (params: any) => Promise>>; + delete: (params: any) => Promise; + deleteBulk: (params: any) => Promise>>; +} diff --git a/public/services/saved_objects/saved_object_client/ppl/index.ts b/public/services/saved_objects/saved_object_client/ppl/index.ts new file mode 100644 index 0000000000..36ebb3f4ec --- /dev/null +++ b/public/services/saved_objects/saved_object_client/ppl/index.ts @@ -0,0 +1,9 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +export { PPLSavedObjectClient } from './ppl_client'; +export { PPLSavedQueryClient } from './saved_query'; +export { PPLSavedVisualizationClient } from './saved_visualization'; +export { PanelSavedObjectClient } from './panels'; diff --git a/public/services/saved_objects/saved_object_client/ppl/panels.ts b/public/services/saved_objects/saved_object_client/ppl/panels.ts new file mode 100644 index 0000000000..076eb54017 --- /dev/null +++ b/public/services/saved_objects/saved_object_client/ppl/panels.ts @@ -0,0 +1,42 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { PPLSavedObjectClient } from './ppl_client'; +import { CUSTOM_PANELS_API_PREFIX } from '../../../../../common/constants/custom_panels'; + +interface PanelRaw { + dateCreated: number; + dateModified: number; + id: string; + name: string; +} + +interface Panel { + label: string; + panel: PanelRaw; +} + +interface CommonParams { + panelId: string; + savedVisualizationId: string; + selectedCustomPanels: Panel[]; +} + +type BulkUpdateParams = CommonParams; + +export class PanelSavedObjectClient extends PPLSavedObjectClient { + async updateBulk(params: BulkUpdateParams): Promise>> { + return await Promise.all( + params.selectedCustomPanels.map((panel: Panel) => { + return this.client.post(`${CUSTOM_PANELS_API_PREFIX}/visualizations`, { + body: JSON.stringify({ + savedVisualizationId: params.savedVisualizationId, + panelId: panel.panel.id, + }), + }); + }) + ); + } +} diff --git a/public/services/saved_objects/saved_object_client/ppl/ppl_client.ts b/public/services/saved_objects/saved_object_client/ppl/ppl_client.ts new file mode 100644 index 0000000000..3a26e5afeb --- /dev/null +++ b/public/services/saved_objects/saved_object_client/ppl/ppl_client.ts @@ -0,0 +1,102 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { isEmpty } from 'lodash'; +import { SavedObjectClientBase } from '../client_base'; +import { ISavedObjectsClient } from '../client_interface'; +import { HttpStart } from '../../../../../../../src/core/public'; + +export class PPLSavedObjectClient extends SavedObjectClientBase implements ISavedObjectsClient { + constructor(protected readonly client: HttpStart) { + super(); + } + create(params: any): Promise { + throw new Error('Method not implemented.'); + } + get(params: any): Promise { + throw new Error('Method not implemented.'); + } + getBulk(params: any): Promise>> { + throw new Error('Method not implemented.'); + } + update(params: any): Promise { + throw new Error('Method not implemented.'); + } + updateBulk(params: any): Promise>> { + throw new Error('Method not implemented.'); + } + delete(params: any): Promise { + throw new Error('Method not implemented.'); + } + deleteBulk(params: any): Promise>> { + throw new Error('Method not implemented.'); + } + buildRequestBody({ + query, + fields, + dateRange, + timestamp, + name = '', + chartType = '', + description = '', + applicationId = '', + userConfigs = '', + subType = '', + unitsOfMeasure = '', + selectedLabels, + objectId = '', + }: any) { + const objRequest: any = { + object: { + query, + selected_date_range: { + start: dateRange[0] || 'now/15m', + end: dateRange[1] || 'now', + text: '', + }, + selected_timestamp: { + name: timestamp || '', + type: 'timestamp', + }, + selected_fields: { + tokens: fields, + text: '', + }, + name: name || '', + description: description || '', + }, + }; + + if (!isEmpty(chartType)) { + objRequest.object.type = chartType; + } + + if (!isEmpty(applicationId)) { + objRequest.object.application_id = applicationId; + } + + if (!isEmpty(userConfigs)) { + objRequest.object.user_configs = userConfigs; + } + + if (!isEmpty(subType)) { + objRequest.object.sub_type = subType; + } + + if (!isEmpty(unitsOfMeasure)) { + objRequest.object.units_of_measure = unitsOfMeasure; + } + + if (!isEmpty(selectedLabels)) { + objRequest.object.selected_labels = selectedLabels; + } + + if (!isEmpty(objectId)) { + objRequest.object_id = objectId; + } + + return objRequest; + } +} diff --git a/public/services/saved_objects/saved_object_client/ppl/saved_query.ts b/public/services/saved_objects/saved_object_client/ppl/saved_query.ts new file mode 100644 index 0000000000..e2d52b18c1 --- /dev/null +++ b/public/services/saved_objects/saved_object_client/ppl/saved_query.ts @@ -0,0 +1,63 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { IField } from '../../../../../common/types/explorer'; +import { PPLSavedObjectClient } from './ppl_client'; +import { + OBSERVABILITY_BASE, + EVENT_ANALYTICS, + SAVED_OBJECTS, + SAVED_QUERY, +} from '../../../../../common/constants/shared'; + +interface CommonParams { + query: string; + fields: IField[]; + dateRange: [string, string]; + name: string; + timestamp: string; +} + +type CreateQueryParams = CommonParams; +type UpdateQueryParams = CommonParams & { + objectId: string; +}; + +export class PPLSavedQueryClient extends PPLSavedObjectClient { + async create(params: CreateQueryParams): Promise { + return await this.client.post( + `${OBSERVABILITY_BASE}${EVENT_ANALYTICS}${SAVED_OBJECTS}${SAVED_QUERY}`, + { + body: JSON.stringify( + this.buildRequestBody({ + query: params.query, + fields: params.fields, + dateRange: params.dateRange, + name: params.name, + timestamp: params.timestamp, + }) + ), + } + ); + } + + async update(params: UpdateQueryParams): Promise { + return await this.client.put( + `${OBSERVABILITY_BASE}${EVENT_ANALYTICS}${SAVED_OBJECTS}${SAVED_QUERY}`, + { + body: JSON.stringify( + this.buildRequestBody({ + query: params.query, + fields: params.fields, + dateRange: params.dateRange, + name: params.name, + timestamp: params.timestamp, + objectId: params.objectId, + }) + ), + } + ); + } +} diff --git a/public/services/saved_objects/saved_object_client/ppl/saved_visualization.ts b/public/services/saved_objects/saved_object_client/ppl/saved_visualization.ts new file mode 100644 index 0000000000..36c68576e5 --- /dev/null +++ b/public/services/saved_objects/saved_object_client/ppl/saved_visualization.ts @@ -0,0 +1,81 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { IField } from '../../../../../common/types/explorer'; +import { + OBSERVABILITY_BASE, + EVENT_ANALYTICS, + SAVED_OBJECTS, + SAVED_VISUALIZATION, +} from '../../../../../common/constants/shared'; +import { PPLSavedObjectClient } from './ppl_client'; + +interface CommonParams { + query: string; + fields: IField[]; + dateRange: [string, string]; + type: string; + name: string; + timestamp: string; + applicationId: string; + userConfigs: any; + description: string; + subType: string; + unitsOfMeasure: string; + selectedLabels: string; +} + +type CreateParams = CommonParams & { applicationId: string }; +type UpdateParams = CommonParams & { objectId: string }; + +export class PPLSavedVisualizationClient extends PPLSavedObjectClient { + async create(params: CreateParams): Promise { + return await this.client.post( + `${OBSERVABILITY_BASE}${EVENT_ANALYTICS}${SAVED_OBJECTS}${SAVED_VISUALIZATION}`, + { + body: JSON.stringify( + this.buildRequestBody({ + query: params.query, + fields: params.fields, + dateRange: params.dateRange, + chartType: params.type, + name: params.name, + timestamp: params.timestamp, + applicationId: params.applicationId, + userConfigs: params.userConfigs, + description: params.description, + subType: params.subType, + unitsOfMeasure: params.unitsOfMeasure, + selectedLabels: params.selectedLabels, + }) + ), + } + ); + } + + async update(params: UpdateParams): Promise { + return await this.client.put( + `${OBSERVABILITY_BASE}${EVENT_ANALYTICS}${SAVED_OBJECTS}${SAVED_VISUALIZATION}`, + { + body: JSON.stringify( + this.buildRequestBody({ + query: params.query, + fields: params.fields, + dateRange: params.dateRange, + chartType: params.type, + name: params.name, + timestamp: params.timestamp, + userConfigs: params.userConfigs, + description: params.description, + subType: params.subType, + unitsOfMeasure: params.unitsOfMeasure, + selectedLabels: params.selectedLabels, + objectId: params.objectId, + }) + ), + } + ); + } +} From 4eb6ff811538f3fe55c96b839d27f1990ae2266b Mon Sep 17 00:00:00 2001 From: Eric Wei Date: Thu, 23 Mar 2023 16:54:25 -0700 Subject: [PATCH 28/73] object saver Signed-off-by: Eric Wei --- .../event_analytics/explorer/explorer.tsx | 290 ++++++------------ .../saved_object_client/ppl/panels.ts | 1 - .../saved_object_savers/index.ts | 12 + .../ppl/save_as_current_vis.ts | 64 ++++ .../ppl/save_as_new_query.ts | 66 ++++ .../ppl/save_as_new_vis.ts | 96 ++++++ .../ppl/save_current_query.ts | 42 +++ .../ppl/saved_query_saver.ts | 13 + .../saved_object_savers/saver_base.ts | 23 ++ .../saved_object_savers/saver_interface.ts | 8 + 10 files changed, 412 insertions(+), 203 deletions(-) create mode 100644 public/services/saved_objects/saved_object_savers/index.ts create mode 100644 public/services/saved_objects/saved_object_savers/ppl/save_as_current_vis.ts create mode 100644 public/services/saved_objects/saved_object_savers/ppl/save_as_new_query.ts create mode 100644 public/services/saved_objects/saved_object_savers/ppl/save_as_new_vis.ts create mode 100644 public/services/saved_objects/saved_object_savers/ppl/save_current_query.ts create mode 100644 public/services/saved_objects/saved_object_savers/ppl/saved_query_saver.ts create mode 100644 public/services/saved_objects/saved_object_savers/saver_base.ts create mode 100644 public/services/saved_objects/saved_object_savers/saver_interface.ts diff --git a/public/components/event_analytics/explorer/explorer.tsx b/public/components/event_analytics/explorer/explorer.tsx index 693aa81de5..3c757b9da1 100644 --- a/public/components/event_analytics/explorer/explorer.tsx +++ b/public/components/event_analytics/explorer/explorer.tsx @@ -57,8 +57,10 @@ import { } from '../../../../common/constants/shared'; import { IDefaultTimestampState, + IExplorerFields, IExplorerProps, IField, + IQuery, IQueryTab, IVisualizationContainerProps, } from '../../../../common/types/explorer'; @@ -96,6 +98,17 @@ import { QueryManager } from '../../../../common/query_manager'; import { uiSettingsService } from '../../../../common/utils'; import { LogPatterns } from './log_patterns/log_patterns'; import { getDateRange } from '../utils/utils'; +import { + PPLSavedQueryClient, + PPLSavedVisualizationClient, + PanelSavedObjectClient, +} from '../../../services/saved_objects/saved_object_client/ppl'; +import { SaveAsNewQuery } from '../../../services/saved_objects/saved_object_savers/ppl/save_as_new_query'; +import { + SaveAsCurrenQuery, + SaveAsCurrentVisualization, + SaveAsNewVisualization, +} from '../../../services/saved_objects/saved_object_savers'; export const Explorer = ({ pplService, @@ -917,218 +930,91 @@ export const Explorer = ({ const handleQueryChange = async (newQuery: string) => setTempQuery(newQuery); - const handleSavingObject = async () => { - const currQuery = queryRef.current; - const currFields = explorerFieldsRef.current; - if (isEmpty(currQuery![RAW_QUERY]) && isEmpty(appBaseQuery)) { - setToast('No query to save.', 'danger'); - return; - } - if (isEmpty(selectedPanelNameRef.current)) { - setIsPanelTextFieldInvalid(true); - setToast('Name field cannot be empty.', 'danger'); - return; - } - setIsPanelTextFieldInvalid(false); - if (isEqual(selectedContentTabId, TAB_EVENT_ID)) { - const isTabMatchingSavedType = isEqual(currQuery![SAVED_OBJECT_TYPE], SAVED_QUERY); - if (!isEmpty(currQuery![SAVED_OBJECT_ID]) && isTabMatchingSavedType) { - await savedObjects - .updateSavedQueryById({ - query: currQuery![RAW_QUERY], - fields: currFields![SELECTED_FIELDS], - dateRange: currQuery![SELECTED_DATE_RANGE], - name: selectedPanelNameRef.current, - timestamp: currQuery![SELECTED_TIMESTAMP], - objectId: currQuery![SAVED_OBJECT_ID], - type: '', - }) - .then((res: any) => { - setToast( - `Query '${selectedPanelNameRef.current}' has been successfully updated.`, - 'success' - ); - dispatch( - updateTabName({ - tabId, - tabName: selectedPanelNameRef.current, - }) - ); - return res; - }) - .catch((error: any) => { - notifications.toasts.addError(error, { - title: `Cannot update query '${selectedPanelNameRef.current}'`, - }); - }); + const getSavingCommonParams = ( + queryState: IQuery, + fields: IExplorerFields, + savingTitle: string + ) => { + return { + query: queryState[RAW_QUERY], + fields: fields[SELECTED_FIELDS], + dateRange: queryState[SELECTED_DATE_RANGE], + name: savingTitle, + timestamp: queryState[SELECTED_TIMESTAMP], + }; + }; + + const handleSavingObject = useCallback(() => { + const isOnEventPage = isEqual(selectedContentTabId, TAB_EVENT_ID); + const isObjTypeMatchQuery = isEqual(query[SAVED_OBJECT_TYPE], SAVED_QUERY); + const isObjTypeMatchVis = isEqual(query[SAVED_OBJECT_TYPE], SAVED_VISUALIZATION); + const isTabHasObjID = !isEmpty(query[SAVED_OBJECT_ID]); + const commonParams = getSavingCommonParams(query, explorerFields, selectedPanelNameRef.current); + + let soClient; + if (isOnEventPage) { + if (isTabHasObjID && isObjTypeMatchQuery) { + soClient = new SaveAsCurrenQuery( + { tabId, notifications }, + { dispatch, updateTabName }, + new PPLSavedQueryClient(http), + { + ...commonParams, + objectId: query[SAVED_OBJECT_ID], + } + ); } else { - // create new saved query - savedObjects - .createSavedQuery({ - query: currQuery![RAW_QUERY], - fields: currFields![SELECTED_FIELDS], - dateRange: currQuery![SELECTED_DATE_RANGE], - name: selectedPanelNameRef.current, - timestamp: currQuery![SELECTED_TIMESTAMP], - objectId: '', - type: '', - }) - .then((res: any) => { - history.replace(`/event_analytics/explorer/${res.objectId}`); - setToast( - `New query '${selectedPanelNameRef.current}' has been successfully saved.`, - 'success' - ); - batch(() => { - dispatch( - changeQuery({ - tabId, - query: { - [SAVED_OBJECT_ID]: res.objectId, - [SAVED_OBJECT_TYPE]: SAVED_QUERY, - }, - }) - ); - dispatch( - updateTabName({ - tabId, - tabName: selectedPanelNameRef.current, - }) - ); - }); - history.replace(`/event_analytics/explorer/${res.objectId}`); - return res; - }) - .catch((error: any) => { - if (error?.body?.statusCode === 403) { - showPermissionErrorToast(); - } else { - notifications.toasts.addError(error, { - title: `Cannot save query '${selectedPanelNameRef.current}'`, - }); - } - }); - } - // to-dos - update selected custom panel - if (!isEmpty(selectedCustomPanelOptions)) { - // update custom panel - query - } - } else if (isEqual(selectedContentTabId, TAB_CHART_ID)) { - if (isEmpty(currQuery![RAW_QUERY]) && isEmpty(appBaseQuery)) { - setToast(`There is no query or(and) visualization to save`, 'danger'); - return; + soClient = new SaveAsNewQuery( + { tabId, history, notifications, showPermissionErrorToast }, + { batch, dispatch, changeQuery, updateTabName }, + new PPLSavedQueryClient(http), + { ...commonParams } + ); } - let savingVisRes; - const vizDescription = userVizConfigs[curVisId]?.dataConfig?.panelOptions?.description || ''; - const isTabMatchingSavedType = isEqual(currQuery![SAVED_OBJECT_TYPE], SAVED_VISUALIZATION); - if (!isEmpty(currQuery![SAVED_OBJECT_ID]) && isTabMatchingSavedType) { - savingVisRes = await savedObjects - .updateSavedVisualizationById({ - query: buildQuery('', currQuery![RAW_QUERY]), - fields: currFields![SELECTED_FIELDS], - dateRange: currQuery![SELECTED_DATE_RANGE], - name: selectedPanelNameRef.current, - timestamp: currQuery![SELECTED_TIMESTAMP], - objectId: currQuery![SAVED_OBJECT_ID], + } else { + if (isTabHasObjID && isObjTypeMatchVis) { + soClient = new SaveAsCurrentVisualization( + { tabId, history, notifications, showPermissionErrorToast }, + { batch, dispatch, changeQuery, updateTabName }, + new PPLSavedVisualizationClient(http), + new PanelSavedObjectClient(http), + { + ...commonParams, + objectId: query[SAVED_OBJECT_ID], type: curVisId, - userConfigs: userVizConfigs.hasOwnProperty(curVisId) - ? JSON.stringify(userVizConfigs[curVisId]) - : JSON.stringify({}), - description: vizDescription, + userConfigs: JSON.stringify(userVizConfigs[curVisId]), + description: userVizConfigs[curVisId]?.dataConfig?.panelOptions?.description || '', subType, - }) - .then((res: any) => { - setToast( - `Visualization '${selectedPanelNameRef.current}' has been successfully updated.`, - 'success' - ); - dispatch( - updateTabName({ - tabId, - tabName: selectedPanelNameRef.current, - }) - ); - return res; - }) - .catch((error: any) => { - notifications.toasts.addError(error, { - title: `Cannot update Visualization '${selectedPanelNameRef.current}'`, - }); - }); + } + ); } else { - // create new saved visualization - savingVisRes = await savedObjects - .createSavedVisualization({ - query: buildQuery('', currQuery![RAW_QUERY]), - fields: currFields![SELECTED_FIELDS], - dateRange: currQuery![SELECTED_DATE_RANGE], + soClient = new SaveAsNewVisualization( + { tabId, history, notifications, showPermissionErrorToast, appLogEvents }, + { batch, dispatch, changeQuery, updateTabName }, + new PPLSavedVisualizationClient(http), + new PanelSavedObjectClient(http), + { + ...commonParams, type: curVisId, - name: selectedPanelNameRef.current, - timestamp: currQuery![SELECTED_TIMESTAMP], applicationId: appId, - userConfigs: userVizConfigs.hasOwnProperty(curVisId) - ? JSON.stringify(userVizConfigs[curVisId]) - : JSON.stringify({}), - description: vizDescription, + userConfigs: JSON.stringify(userVizConfigs[curVisId]), + description: userVizConfigs[curVisId]?.dataConfig?.panelOptions?.description || '', subType, - }) - .then((res: any) => { - batch(() => { - dispatch( - changeQuery({ - tabId, - query: { - [SAVED_OBJECT_ID]: res.objectId, - [SAVED_OBJECT_TYPE]: SAVED_VISUALIZATION, - }, - }) - ); - dispatch( - updateTabName({ - tabId, - tabName: selectedPanelNameRef.current, - }) - ); - }); - if (appLogEvents) { - addVisualizationToPanel(res.objectId, selectedPanelNameRef.current); - } else { - history.replace(`/event_analytics/explorer/${res.objectId}`); - } - setToast( - `New visualization '${selectedPanelNameRef.current}' has been successfully saved.`, - 'success' - ); - return res; - }) - .catch((error: any) => { - notifications.toasts.addError(error, { - title: `Cannot save Visualization '${selectedPanelNameRef.current}'`, - }); - }); - } - if (!has(savingVisRes, 'objectId')) return; - // update custom panel - visualization - if (!isEmpty(selectedCustomPanelOptions)) { - savedObjects - .bulkUpdateCustomPanel({ - selectedCustomPanels: selectedCustomPanelOptions, - savedVisualizationId: savingVisRes.objectId, - }) - .then((res: any) => { - setToast( - `Visualization '${selectedPanelNameRef.current}' has been successfully saved to operation panels.`, - 'success' - ); - }) - .catch((error: any) => { - notifications.toasts.addError(error, { - title: `Cannot add Visualization '${selectedPanelNameRef.current}' to operation panels`, - }); - }); + selectedPanels: selectedCustomPanelOptions, + } + ); } } - }; + + soClient.save(); + }, [ + query, + curVisId, + userVizConfigs, + selectedContentTabId, + explorerFields, + selectedCustomPanelOptions, + ]); const liveTailLoop = async ( name: string, diff --git a/public/services/saved_objects/saved_object_client/ppl/panels.ts b/public/services/saved_objects/saved_object_client/ppl/panels.ts index 076eb54017..92d1c6941c 100644 --- a/public/services/saved_objects/saved_object_client/ppl/panels.ts +++ b/public/services/saved_objects/saved_object_client/ppl/panels.ts @@ -19,7 +19,6 @@ interface Panel { } interface CommonParams { - panelId: string; savedVisualizationId: string; selectedCustomPanels: Panel[]; } diff --git a/public/services/saved_objects/saved_object_savers/index.ts b/public/services/saved_objects/saved_object_savers/index.ts new file mode 100644 index 0000000000..74f10f32ea --- /dev/null +++ b/public/services/saved_objects/saved_object_savers/index.ts @@ -0,0 +1,12 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +export { ISavedObjectSaver } from './saver_interface'; +export { SavedObjectSaverBase } from './saver_base'; +export { SavedQuerySaver } from './ppl/saved_query_saver'; +export { SaveAsNewQuery } from './ppl/save_as_new_query'; +export { SaveAsCurrenQuery } from './ppl/save_current_query'; +export { SaveAsNewVisualization } from './ppl/save_as_new_vis'; +export { SaveAsCurrentVisualization } from './ppl/save_as_current_vis'; diff --git a/public/services/saved_objects/saved_object_savers/ppl/save_as_current_vis.ts b/public/services/saved_objects/saved_object_savers/ppl/save_as_current_vis.ts new file mode 100644 index 0000000000..2d6d5d3aa2 --- /dev/null +++ b/public/services/saved_objects/saved_object_savers/ppl/save_as_current_vis.ts @@ -0,0 +1,64 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { SavedQuerySaver } from './saved_query_saver'; + +export class SaveAsCurrentVisualization extends SavedQuerySaver { + constructor( + private readonly saveContext, + protected readonly dispatchers, + private readonly saveClient, + private readonly panelClient, + private readonly saveParams + ) { + super(dispatchers); + } + + save(): void { + const { dispatch, updateTabName } = this.dispatchers; + const { tabId, notifications } = this.saveContext; + const { name } = this.saveParams; + this.saveClient + .update({ ...this.saveParams }) + .then((res: any) => { + notifications.toasts.addSuccess({ + title: 'Saved successfully.', + text: `Visualization '${name}' has been successfully updated.`, + }); + dispatch( + updateTabName({ + tabId, + tabName: name, + }) + ); + }) + .catch((error: any) => { + notifications.toasts.addError(error, { + title: `Cannot update Visualization '${name}'`, + }); + }); + } + + addToPanel({ selectedPanels, saveTitle, notifications, visId }) { + console.log('selectedPanels: ', selectedPanels, ', visId: ', visId); + this.panelClient + .updateBulk({ + selectedCustomPanels: selectedPanels, + savedVisualizationId: visId, + }) + .then((res: any) => { + notifications.toasts.addSuccess({ + title: 'Saved successfully.', + text: `Visualization '${saveTitle}' has been successfully saved to operation panels.`, + }); + }) + .catch((error: any) => { + notifications.toasts.addError(error, { + title: 'Failed to save', + text: `Cannot add Visualization '${saveTitle}' to operation panels`, + }); + }); + } +} diff --git a/public/services/saved_objects/saved_object_savers/ppl/save_as_new_query.ts b/public/services/saved_objects/saved_object_savers/ppl/save_as_new_query.ts new file mode 100644 index 0000000000..1c174438d0 --- /dev/null +++ b/public/services/saved_objects/saved_object_savers/ppl/save_as_new_query.ts @@ -0,0 +1,66 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { + SAVED_OBJECT_ID, + SAVED_OBJECT_TYPE, + SAVED_QUERY, +} from '../../../../../common/constants/explorer'; +import { SavedQuerySaver } from './saved_query_saver'; + +export class SaveAsNewQuery extends SavedQuerySaver { + constructor( + private readonly saveContext, + protected readonly dispatchers, + private readonly saveClient, + private readonly saveParams + ) { + super(dispatchers); + } + + save(): void { + const { batch, dispatch, changeQuery, updateTabName } = this.dispatchers; + const { tabId, history, notifications, showPermissionErrorToast } = this.saveContext; + const { name } = this.saveParams; + console.log('this.saveParams: ', this.saveParams); + this.saveClient + .create({ ...this.saveParams }) + .then((res: any) => { + history.replace(`/event_analytics/explorer/${res.objectId}`); + notifications.toasts.addSuccess({ + title: 'Saved successfully.', + text: `New query '${name}' has been successfully saved.`, + }); + batch(() => { + dispatch( + changeQuery({ + tabId, + query: { + [SAVED_OBJECT_ID]: res.objectId, + [SAVED_OBJECT_TYPE]: SAVED_QUERY, + }, + }) + ); + dispatch( + updateTabName({ + tabId, + tabName: name, + }) + ); + }); + history.replace(`/event_analytics/explorer/${res.objectId}`); + return res; + }) + .catch((error: any) => { + if (error?.body?.statusCode === 403) { + showPermissionErrorToast(); + } else { + notifications.toasts.addError(error, { + title: `Cannot save query '${name}'`, + }); + } + }); + } +} diff --git a/public/services/saved_objects/saved_object_savers/ppl/save_as_new_vis.ts b/public/services/saved_objects/saved_object_savers/ppl/save_as_new_vis.ts new file mode 100644 index 0000000000..ab7ebe4e9b --- /dev/null +++ b/public/services/saved_objects/saved_object_savers/ppl/save_as_new_vis.ts @@ -0,0 +1,96 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { + SAVED_OBJECT_ID, + SAVED_OBJECT_TYPE, + SAVED_VISUALIZATION, +} from '../../../../../common/constants/explorer'; +import { SavedQuerySaver } from './saved_query_saver'; + +export class SaveAsNewVisualization extends SavedQuerySaver { + constructor( + private readonly saveContext, + protected readonly dispatchers, + private readonly saveClient, + private readonly panelClient, + private readonly saveParams + ) { + super(dispatchers); + } + + save(): void { + const { batch, dispatch, changeQuery, updateTabName } = this.dispatchers; + const { + tabId, + history, + notifications, + addVisualizationToPanel, + appLogEvents, + } = this.saveContext; + const { name, selectedPanels } = this.saveParams; + + this.saveClient + .create({ ...this.saveParams }) + .then((res: any) => { + notifications.toasts.addSuccess({ + title: 'Saved successfully.', + text: `New visualization '${name}' has been successfully saved.`, + }); + + if (selectedPanels) + this.addToPanel({ selectedPanels, saveTitle: name, notifications, visId: res.objectId }); + + if (appLogEvents) { + addVisualizationToPanel(res.objectId, name); + } else { + history.replace(`/event_analytics/explorer/${res.objectId}`); + } + + batch(() => { + dispatch( + changeQuery({ + tabId, + query: { + [SAVED_OBJECT_ID]: res.objectId, + [SAVED_OBJECT_TYPE]: SAVED_VISUALIZATION, + }, + }) + ); + dispatch( + updateTabName({ + tabId, + tabName: name, + }) + ); + }); + }) + .catch((error: any) => { + notifications.toasts.addError(error, { + title: `Cannot save Visualization '${name}'`, + }); + }); + } + + addToPanel({ selectedPanels, saveTitle, notifications, visId }) { + this.panelClient + .updateBulk({ + selectedCustomPanels: selectedPanels, + savedVisualizationId: visId, + }) + .then((res: any) => { + notifications.toasts.addSuccess({ + title: 'Saved successfully.', + text: `Visualization '${saveTitle}' has been successfully saved to operation panels.`, + }); + }) + .catch((error: any) => { + notifications.toasts.addError(error, { + title: 'Failed to save', + text: `Cannot add Visualization '${saveTitle}' to operation panels`, + }); + }); + } +} diff --git a/public/services/saved_objects/saved_object_savers/ppl/save_current_query.ts b/public/services/saved_objects/saved_object_savers/ppl/save_current_query.ts new file mode 100644 index 0000000000..717c2fb074 --- /dev/null +++ b/public/services/saved_objects/saved_object_savers/ppl/save_current_query.ts @@ -0,0 +1,42 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { SavedQuerySaver } from './saved_query_saver'; + +export class SaveAsCurrenQuery extends SavedQuerySaver { + constructor( + private readonly saveContext, + protected readonly dispatchers, + private readonly saveClient, + private readonly saveParams + ) { + super(dispatchers); + } + + save(): void { + const { dispatch, updateTabName } = this.dispatchers; + const { tabId, notifications } = this.saveContext; + const { name } = this.saveParams; + this.saveClient + .update({ ...this.saveParams }) + .then((res: any) => { + notifications.toasts.addSuccess({ + title: 'Saved successfully.', + text: `Query '${name}' has been successfully updated.`, + }); + dispatch( + updateTabName({ + tabId, + tabName: name, + }) + ); + }) + .catch((error: any) => { + notifications.toasts.addError(error, { + title: `Cannot update query '${name}'`, + }); + }); + } +} diff --git a/public/services/saved_objects/saved_object_savers/ppl/saved_query_saver.ts b/public/services/saved_objects/saved_object_savers/ppl/saved_query_saver.ts new file mode 100644 index 0000000000..23036a0d3d --- /dev/null +++ b/public/services/saved_objects/saved_object_savers/ppl/saved_query_saver.ts @@ -0,0 +1,13 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { ISavedObjectSaver } from '../saver_interface'; +import { SavedObjectSaverBase } from '../saver_base'; + +export class SavedQuerySaver extends SavedObjectSaverBase implements ISavedObjectSaver { + save() { + throw new Error('Method not implemented.'); + } +} diff --git a/public/services/saved_objects/saved_object_savers/saver_base.ts b/public/services/saved_objects/saved_object_savers/saver_base.ts new file mode 100644 index 0000000000..e1bbc85fde --- /dev/null +++ b/public/services/saved_objects/saved_object_savers/saver_base.ts @@ -0,0 +1,23 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { capitalize } from 'lodash'; +import { CoreStart } from '../../../../../../src/core/public'; +import { ISavedObjectSaver } from './saver_interface'; + +export abstract class SavedObjectSaverBase implements ISavedObjectSaver { + constructor(protected readonly dispatchers) {} + abstract save(): any; + handleResponse( + notification: CoreStart['notifications'], + type: 'success' | 'danger', + msg: string + ) { + notification.toasts[`add${capitalize(type)}`]({ + title: 'Saving objects', + text: msg, + }); + } +} diff --git a/public/services/saved_objects/saved_object_savers/saver_interface.ts b/public/services/saved_objects/saved_object_savers/saver_interface.ts new file mode 100644 index 0000000000..9eb7c60351 --- /dev/null +++ b/public/services/saved_objects/saved_object_savers/saver_interface.ts @@ -0,0 +1,8 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +export interface ISavedObjectSaver { + save: () => void; +} From 2ddab524e96d3fd25c764215d0a3e7b3756ded34 Mon Sep 17 00:00:00 2001 From: Eric Wei Date: Thu, 23 Mar 2023 19:54:33 -0700 Subject: [PATCH 29/73] remove some extra but not required code Signed-off-by: Eric Wei --- .../event_analytics/explorer/explorer.tsx | 470 ++++++++---------- .../explorer/sidebar/sidebar.scss | 12 - .../event_analytics/utils/utils.tsx | 12 +- .../ppl/save_as_current_vis.ts | 1 - 4 files changed, 215 insertions(+), 280 deletions(-) diff --git a/public/components/event_analytics/explorer/explorer.tsx b/public/components/event_analytics/explorer/explorer.tsx index 3c757b9da1..11fbee83ae 100644 --- a/public/components/event_analytics/explorer/explorer.tsx +++ b/public/components/event_analytics/explorer/explorer.tsx @@ -97,7 +97,7 @@ import { CountDistribution } from './visualizations/count_distribution'; import { QueryManager } from '../../../../common/query_manager'; import { uiSettingsService } from '../../../../common/utils'; import { LogPatterns } from './log_patterns/log_patterns'; -import { getDateRange } from '../utils/utils'; +import { getContentTabTitle, getDateRange } from '../utils/utils'; import { PPLSavedQueryClient, PPLSavedVisualizationClient, @@ -571,16 +571,7 @@ export const Explorer = ({ }); const handleOverrideTimestamp = async (timestamp: IField) => { - const curQuery = queryRef.current; - const rawQueryStr = buildQuery(appBaseQuery, curQuery![RAW_QUERY]); - const curIndex = getIndexPatternFromRawQuery(rawQueryStr); - if (isEmpty(rawQueryStr) || isEmpty(curIndex)) { - setToast('Cannot override timestamp because there was no valid index found.', 'danger'); - return; - } - setIsOverridingTimestamp(true); - await dispatch( changeQuery({ tabId, @@ -589,7 +580,6 @@ export const Explorer = ({ }, }) ); - setIsOverridingTimestamp(false); handleQuerySearch(); }; @@ -623,195 +613,177 @@ export const Explorer = ({ return 0; }, [countDistribution?.data]); - const getMainContent = () => { + const mainContent = useMemo(() => { return ( -
    -
    -
    - {!isSidebarClosed && ( -
    - -
    - )} - { - setIsSidebarClosed((staleState) => { - return !staleState; - }); - }} - data-test-subj="collapseSideBarButton" - aria-controls="discover-sidebar" - aria-expanded={isSidebarClosed ? 'false' : 'true'} - aria-label="Toggle sidebar" - className="dscCollapsibleSidebar__collapseButton" - /> -
    -
    - {explorerData && !isEmpty(explorerData.jsonData) ? ( -
    -
    - {countDistribution?.data && !isLiveTailOnRef.current && ( - <> - - - +
    + {!isSidebarClosed && ( +
    + +
    + )} + { + setIsSidebarClosed((staleState) => { + return !staleState; + }); + }} + data-test-subj="collapseSideBarButton" + aria-controls="discover-sidebar" + aria-expanded={isSidebarClosed ? 'false' : 'true'} + aria-label="Toggle sidebar" + className="dscCollapsibleSidebar__collapseButton" + /> +
    +
    + {explorerData && !isEmpty(explorerData.jsonData) ? ( +
    +
    + {countDistribution?.data && !isLiveTailOnRef.current && ( + <> + + + { + return sum + n; + }, + 0 + )} + showResetButton={false} + onResetQuery={() => {}} + /> + + + { + const intervalOptionsIndex = timeIntervalOptions.findIndex( + (item) => item.value === selectedIntrv + ); + const intrv = selectedIntrv.replace(/^auto_/, ''); + getCountVisualizations(intrv); + selectedIntervalRef.current = timeIntervalOptions[intervalOptionsIndex]; + getPatterns(intrv, getErrorHandler('Error fetching patterns')); + }} + stateInterval={selectedIntervalRef.current?.value} + /> + + + + + + + )} + +
    +

    + +

    +
    + {isLiveTailOnRef.current && ( + <> + + + + +   Live streaming + + + {}} + /> + + since {liveTimestamp} + + + + )} + {countDistribution?.data && ( + +

    + Events + + {' '} + ( + {reduce( countDistribution.data['count()'], (sum, n) => { return sum + n; }, 0 )} - showResetButton={false} - onResetQuery={() => {}} - /> - - - { - const intervalOptionsIndex = timeIntervalOptions.findIndex( - (item) => item.value === selectedIntrv - ); - const intrv = selectedIntrv.replace(/^auto_/, ''); - getCountVisualizations(intrv); - selectedIntervalRef.current = - timeIntervalOptions[intervalOptionsIndex]; - getPatterns(intrv, getErrorHandler('Error fetching patterns')); - }} - stateInterval={selectedIntervalRef.current?.value} - /> - - - - - - - )} - -
    -

    - -

    -
    - {isLiveTailOnRef.current && ( - <> - - - - -   Live streaming - - - {}} - /> - - since {liveTimestamp} - - - - )} - {countDistribution?.data && ( - -

    - Events - - {' '} - ( - {reduce( - countDistribution.data['count()'], - (sum, n) => { - return sum + n; - }, - 0 - )} - ) - -

    -
    - )} - - - - ​ - -
    -
    -

    + ) + + + + )} + + + + ​ + +
    +
    - ) : ( - - )} -
    +
    + ) : ( + + )}
    -
    + ); - }; - - function getMainContentTab({ - tabID, - tabTitle, - getContent, - }: { - tabID: string; - tabTitle: string; - getContent: () => JSX.Element; - }) { - return { - id: tabID, - name: ( - <> - - {tabTitle} - - - ), - content: <>{getContent()}, - }; - } + }, [ + isPanelTextFieldInvalid, + explorerData, + explorerFields, + isSidebarClosed, + countDistribution, + explorerVisualizations, + isOverridingTimestamp, + query, + isLiveTailOnRef.current, + ]); const visualizations: IVisualizationContainerProps = useMemo(() => { return getVizContainerProps({ @@ -836,7 +808,7 @@ export const Explorer = ({ } }; - const getExplorerVis = () => { + const explorerVis = useMemo(() => { return ( ); - }; + }, [query, curVisId, explorerFields, explorerVisualizations, explorerData, visualizations]); - const getMainContentTabs = () => { - return [ - getMainContentTab({ - tabID: TAB_EVENT_ID, - tabTitle: TAB_EVENT_TITLE, - getContent: () => getMainContent(), - }), - getMainContentTab({ - tabID: TAB_CHART_ID, - tabTitle: TAB_CHART_TITLE, - getContent: () => getExplorerVis(), - }), - ]; - }; + const contentTabs = [ + { + id: TAB_EVENT_ID, + name: getContentTabTitle(TAB_EVENT_ID, TAB_EVENT_TITLE), + content: mainContent, + }, + { + id: TAB_CHART_ID, + name: getContentTabTitle(TAB_CHART_ID, TAB_CHART_TITLE), + content: explorerVis, + }, + ]; - const memorizedMainContentTabs = useMemo(() => { - return getMainContentTabs(); - }, [ - curVisId, - isPanelTextFieldInvalid, - explorerData, - explorerFields, - isSidebarClosed, - countDistribution, - explorerVisualizations, - selectedContentTabId, - isOverridingTimestamp, - visualizations, - query, - isLiveTailOnRef.current, - userVizConfigs, - ]); const handleContentTabClick = (selectedTab: IQueryTab) => setSelectedContentTab(selectedTab.id); const updateQueryInStore = async (updateQuery: string) => { @@ -898,29 +851,21 @@ export const Explorer = ({ ); }; - const updateCurrentTimeStamp = async (timestamp: string) => { - await dispatch( - changeQuery({ - tabId, - query: { - [SELECTED_TIMESTAMP]: timestamp, - }, - }) - ); - }; - const handleQuerySearch = useCallback( async (availability?: boolean) => { // clear previous selected timestamp when index pattern changes - if ( - !isEmpty(tempQuery) && - !isEmpty(query[RAW_QUERY]) && - isIndexPatternChanged(tempQuery, query[RAW_QUERY]) - ) { - await updateCurrentTimeStamp(''); + if (isIndexPatternChanged(tempQuery, query[RAW_QUERY])) { + await dispatch( + changeQuery({ + tabId, + query: { + [SELECTED_TIMESTAMP]: '', + }, + }) + ); await setDefaultPatternsField('', ''); } - if (availability !== true) { + if (!availability) { await updateQueryInStore(tempQuery); } await fetchData(); @@ -989,7 +934,14 @@ export const Explorer = ({ ); } else { soClient = new SaveAsNewVisualization( - { tabId, history, notifications, showPermissionErrorToast, appLogEvents }, + { + tabId, + history, + notifications, + showPermissionErrorToast, + appLogEvents, + addVisualizationToPanel, + }, { batch, dispatch, changeQuery, updateTabName }, new PPLSavedVisualizationClient(http), new PanelSavedObjectClient(http), @@ -1005,7 +957,6 @@ export const Explorer = ({ ); } } - soClient.save(); }, [ query, @@ -1093,15 +1044,12 @@ export const Explorer = ({ [tempQuery] ); - const generateViewQuery = (queryString: string) => { - if (queryString.includes(appBaseQuery)) { - if (queryString.includes('|')) { - // Some scenarios have ' | ' after base query and some have '| ' - return queryString.replace(' | ', '| ').replace(appBaseQuery + '| ', ''); - } - return ''; - } - return queryString; + const processAppAnalyticsQuery = (queryString: string) => { + if (!queryString.includes(appBaseQuery)) return queryString; + if (queryString.includes(appBaseQuery) && queryString.includes('|')) + // Some scenarios have ' | ' after base query and some have '| ' + return queryString.replace(' | ', '| ').replace(appBaseQuery + '| ', ''); + return ''; }; return ( @@ -1109,19 +1057,9 @@ export const Explorer = ({ value={{ tabId, curVisId, - dispatch, changeVisualizationConfig, - explorerVisualizations, setToast, pplService, - handleQuerySearch, - handleQueryChange, - setTempQuery, - fetchData, - explorerFields, - explorerData, - http, - query, notifications, }} > @@ -1132,7 +1070,7 @@ export const Explorer = ({ > tab.id === selectedContentTabId)} + initialSelectedTab={contentTabs[0]} + selectedTab={contentTabs.find((tab) => tab.id === selectedContentTabId)} onTabClick={(selectedTab: EuiTabbedContentTab) => handleContentTabClick(selectedTab)} - tabs={memorizedMainContentTabs} + tabs={contentTabs} /> diff --git a/public/components/event_analytics/explorer/sidebar/sidebar.scss b/public/components/event_analytics/explorer/sidebar/sidebar.scss index ac5b4326ce..cc9557c25f 100644 --- a/public/components/event_analytics/explorer/sidebar/sidebar.scss +++ b/public/components/event_analytics/explorer/sidebar/sidebar.scss @@ -3,14 +3,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -.dscSidebar__container { - padding-left: 0 !important; - padding-right: 0 !important; - background-color: transparent; - border-right-color: transparent; - border-bottom-color: transparent; -} - .dscIndexPattern__container { display: flex; align-items: center; @@ -97,10 +89,6 @@ vertical-align: middle; } -.explorerFieldSelector { - padding: $euiSizeS; -} - #vis__mainContent { .explorer__insights { .explorerFieldSelector, .explorer__vizDataConfig { diff --git a/public/components/event_analytics/utils/utils.tsx b/public/components/event_analytics/utils/utils.tsx index fde9ff6dc4..cc786f0d8d 100644 --- a/public/components/event_analytics/utils/utils.tsx +++ b/public/components/event_analytics/utils/utils.tsx @@ -4,10 +4,10 @@ * SPDX-License-Identifier: Apache-2.0 */ -import dateMath from '@elastic/datemath'; import { uniqueId, isEmpty } from 'lodash'; import moment from 'moment'; import React from 'react'; +import { EuiText } from '@elastic/eui'; import { HttpStart } from '../../../../../../src/core/public'; import { CUSTOM_LABEL, @@ -449,3 +449,13 @@ export const getDateRange = ( if (!isEmpty(selectedDateRange)) return [selectedDateRange[0], selectedDateRange[1]]; return ['now-15m', 'now']; }; + +export const getContentTabTitle = (tabID: string, tabTitle: string) => { + return ( + <> + + {tabTitle} + + + ); +}; diff --git a/public/services/saved_objects/saved_object_savers/ppl/save_as_current_vis.ts b/public/services/saved_objects/saved_object_savers/ppl/save_as_current_vis.ts index 2d6d5d3aa2..b741466dc1 100644 --- a/public/services/saved_objects/saved_object_savers/ppl/save_as_current_vis.ts +++ b/public/services/saved_objects/saved_object_savers/ppl/save_as_current_vis.ts @@ -42,7 +42,6 @@ export class SaveAsCurrentVisualization extends SavedQuerySaver { } addToPanel({ selectedPanels, saveTitle, notifications, visId }) { - console.log('selectedPanels: ', selectedPanels, ', visId: ', visId); this.panelClient .updateBulk({ selectedCustomPanels: selectedPanels, From 2cb37dc6a7ba5233e1806620f3d7ff920e533b0a Mon Sep 17 00:00:00 2001 From: Joshua Li Date: Thu, 30 Mar 2023 22:14:33 +0000 Subject: [PATCH 30/73] Add observability visualization saved object and embeddable --- common/types/explorer.ts | 27 +--- .../observability_saved_object_attributes.ts | 18 +++ common/utils/core_services.ts | 41 +++++ common/utils/index.ts | 3 +- common/utils/query_utils.ts | 11 +- common/utils/settings_service.ts | 25 --- opensearch_dashboards.json | 10 +- .../saved_object_visualization.tsx | 103 +++++++++++++ public/embeddable/filters/filter_parser.ts | 49 ++++++ .../embeddable/observability_embeddable.tsx | 112 ++++++++++++++ .../observability_embeddable_component.tsx | 41 +++++ .../observability_embeddable_factory.tsx | 142 ++++++++++++++++++ public/plugin.ts | 85 +++++++++-- public/types.ts | 16 ++ server/plugin.ts | 8 +- .../event_analytics/event_analytics_router.ts | 23 +-- .../observability_saved_object.ts | 26 ++++ server/services/facets/saved_objects.ts | 11 +- 18 files changed, 667 insertions(+), 84 deletions(-) create mode 100644 common/types/observability_saved_object_attributes.ts create mode 100644 common/utils/core_services.ts delete mode 100644 common/utils/settings_service.ts create mode 100644 public/components/visualizations/saved_object_visualization.tsx create mode 100644 public/embeddable/filters/filter_parser.ts create mode 100644 public/embeddable/observability_embeddable.tsx create mode 100644 public/embeddable/observability_embeddable_component.tsx create mode 100644 public/embeddable/observability_embeddable_factory.tsx create mode 100644 server/saved_objects/observability_saved_object.ts diff --git a/common/types/explorer.ts b/common/types/explorer.ts index d4b2ef5934..4d343ff061 100644 --- a/common/types/explorer.ts +++ b/common/types/explorer.ts @@ -33,7 +33,10 @@ import SavedObjects from '../../public/services/saved_objects/event_analytics/sa import TimestampUtils from '../../public/services/timestamp/timestamp'; import PPLService from '../../public/services/requests/ppl'; import DSLService from '../../public/services/requests/dsl'; -import { SavedObjectsStart } from '../../../../src/core/public/saved_objects'; +import { + SavedObjectAttributes, + SavedObjectsStart, +} from '../../../../src/core/public/saved_objects'; export interface IQueryTab { id: string; @@ -41,7 +44,7 @@ export interface IQueryTab { content: React.ReactNode; } -export interface IField { +export interface IField extends SavedObjectAttributes { name: string; type: string; label?: string; @@ -152,7 +155,7 @@ export interface SavedQuery { selected_timestamp: IField; } -export interface SavedVisualization { +export interface SavedVisualization extends SavedObjectAttributes { description: string; name: string; query: string; @@ -160,25 +163,11 @@ export interface SavedVisualization { selected_fields: { text: string; tokens: [] }; selected_timestamp: IField; type: string; + sub_type: 'metric' | 'visualization'; + user_configs?: string; application_id?: string; } -export interface SavedQueryRes { - createdTimeMs: number; - lastUpdatedTimeMs: number; - objectId: string; - savedQuery: SavedQuery; - tenant: string; -} - -export interface SavedVizRes { - createdTimeMs: number; - lastUpdatedTimeMs: number; - objectId: string; - savedVisualization: SavedVisualization; - tenant: string; -} - export interface ExplorerDataType { jsonData: object[]; jsonDataAll: object[]; diff --git a/common/types/observability_saved_object_attributes.ts b/common/types/observability_saved_object_attributes.ts new file mode 100644 index 0000000000..293a2d5fb6 --- /dev/null +++ b/common/types/observability_saved_object_attributes.ts @@ -0,0 +1,18 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { SavedObjectAttributes } from '../../../../src/core/types'; +import { SavedVisualization } from './explorer'; + +export const VISUALIZATION_SAVED_OBJECT = 'observability-visualization'; +export const SAVED_OBJECT_VERSION = 1; + +export interface VisualizationSavedObjectAttributes extends SavedObjectAttributes { + title: string; + description: string; + version: number; + createdTimeMs: number; + savedVisualization?: SavedVisualization; +} diff --git a/common/utils/core_services.ts b/common/utils/core_services.ts new file mode 100644 index 0000000000..3b772d2254 --- /dev/null +++ b/common/utils/core_services.ts @@ -0,0 +1,41 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { + HttpStart, + IUiSettingsClient, + NotificationsStart, + SavedObjectsClientContract, + ToastInput, +} from '../../../../src/core/public'; +import { createGetterSetter } from '../../../../src/plugins/opensearch_dashboards_utils/common'; +import PPLService from '../../public/services/requests/ppl'; +import { QueryManager } from '../query_manager'; + +let uiSettings: IUiSettingsClient; +let notifications: NotificationsStart; + +export const uiSettingsService = { + init: (client: IUiSettingsClient, notificationsStart: NotificationsStart) => { + uiSettings = client; + notifications = notificationsStart; + }, + get: (key: string, defaultOverride?: any) => { + return uiSettings?.get(key, defaultOverride) || ''; + }, + set: (key: string, value: any) => { + return uiSettings?.set(key, value) || Promise.reject('uiSettings client not initialized.'); + }, + addToast: (toast: ToastInput) => { + return notifications.toasts.add(toast); + }, +}; + +export const [getPPLService, setPPLService] = createGetterSetter('PPLService'); +export const [getOSDHttp, setOSDHttp] = createGetterSetter('http'); +export const [getOSDSavedObjectsClient, setOSDSavedObjectsClient] = createGetterSetter< + SavedObjectsClientContract +>('SavedObjectsClient'); +export const [getQueryManager, setQueryManager] = createGetterSetter('QueryManager'); diff --git a/common/utils/index.ts b/common/utils/index.ts index 8ec98b14ff..91caccf22d 100644 --- a/common/utils/index.ts +++ b/common/utils/index.ts @@ -10,4 +10,5 @@ export { composeFinalQuery, removeBacktick, } from './query_utils'; -export { uiSettingsService } from './settings_service'; + +export * from './core_services'; diff --git a/common/utils/query_utils.ts b/common/utils/query_utils.ts index eec15aa2d7..81853112cc 100644 --- a/common/utils/query_utils.ts +++ b/common/utils/query_utils.ts @@ -13,7 +13,6 @@ import { PPL_INDEX_INSERT_POINT_REGEX, PPL_INDEX_REGEX, PPL_NEWLINE_REGEX, - PPL_STATS_REGEX, } from '../../common/constants/shared'; /** @@ -42,6 +41,7 @@ export const preprocessQuery = ({ selectedPatternField, patternRegex, filteredPattern, + whereClause, }: { rawQuery: string; startTime: string; @@ -51,6 +51,7 @@ export const preprocessQuery = ({ selectedPatternField?: string; patternRegex?: string; filteredPattern?: string; + whereClause?: string; }) => { let finalQuery = ''; @@ -65,7 +66,13 @@ export const preprocessQuery = ({ finalQuery = `${tokens![1]}=${ tokens![2] - } | where ${timeField} >= '${start}' and ${timeField} <= '${end}'${tokens![3]}`; + } | where ${timeField} >= '${start}' and ${timeField} <= '${end}'`; + + if (whereClause) { + finalQuery += ` AND ${whereClause}`; + } + + finalQuery += tokens![3]; if (isLiveQuery) { finalQuery = finalQuery + ` | sort - ${timeField}`; diff --git a/common/utils/settings_service.ts b/common/utils/settings_service.ts deleted file mode 100644 index f22912127d..0000000000 --- a/common/utils/settings_service.ts +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import { IUiSettingsClient, NotificationsStart, ToastInput } from '../../../../src/core/public'; - -let uiSettings: IUiSettingsClient; -let notifications: NotificationsStart; - -export const uiSettingsService = { - init: (client: IUiSettingsClient, notificationsStart: NotificationsStart) => { - uiSettings = client; - notifications = notificationsStart; - }, - get: (key: string, defaultOverride?: any) => { - return uiSettings?.get(key, defaultOverride) || ''; - }, - set: (key: string, value: any) => { - return uiSettings?.set(key, value) || Promise.reject("uiSettings client not initialized."); - }, - addToast: (toast: ToastInput) => { - return notifications.toasts.add(toast); - } -}; \ No newline at end of file diff --git a/opensearch_dashboards.json b/opensearch_dashboards.json index 0d145f1a91..4b1a35e914 100644 --- a/opensearch_dashboards.json +++ b/opensearch_dashboards.json @@ -6,14 +6,16 @@ "ui": true, "requiredPlugins": [ "charts", + "dashboard", "data", "embeddable", "inspector", - "urlForwarding", "navigation", + "opensearchDashboardsReact", + "opensearchDashboardsUtils", + "savedObjects", "uiActions", - "dashboard", - "visualizations", - "opensearchDashboardsReact" + "urlForwarding", + "visualizations" ] } diff --git a/public/components/visualizations/saved_object_visualization.tsx b/public/components/visualizations/saved_object_visualization.tsx new file mode 100644 index 0000000000..1b30e9d760 --- /dev/null +++ b/public/components/visualizations/saved_object_visualization.tsx @@ -0,0 +1,103 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import _ from 'lodash'; +import React, { useEffect, useState } from 'react'; +import { SizeMe } from 'react-sizeme'; +import { Filter, Query, TimeRange } from '../../../../../src/plugins/data/common'; +import { QueryManager } from '../../../common/query_manager'; +import { IVisualizationContainerProps, SavedVisualization } from '../../../common/types/explorer'; +import { getPPLService, preprocessQuery, removeBacktick } from '../../../common/utils'; +import { getDefaultVisConfig } from '../event_analytics/utils'; +import { getVizContainerProps } from './charts/helpers'; +import { Visualization } from './visualization'; + +interface SavedObjectVisualizationProps { + savedVisualization: SavedVisualization; + timeRange?: TimeRange; + filters?: Filter[]; + query?: Query; + whereClause?: string; +} + +/** + * Renders a visualization from a {@link SavedVisualization}. + */ +export const SavedObjectVisualization: React.FC = (props) => { + const [visContainerProps, setVisContainerProps] = useState(); + + useEffect(() => { + const pplService = getPPLService(); + const metaData = { ...props.savedVisualization, query: props.savedVisualization.query }; + const userConfigs = metaData.user_configs ? JSON.parse(metaData.user_configs) : {}; + const dataConfig = { ...(userConfigs.dataConfig || {}) }; + const hasBreakdowns = !_.isEmpty(dataConfig.breakdowns); + const realTimeParsedStats = { + ...getDefaultVisConfig(new QueryManager().queryParser().parse(metaData.query).getStats()), + }; + let finalDimensions = [...(realTimeParsedStats.dimensions || [])]; + const breakdowns = [...(dataConfig.breakdowns || [])]; + + // filter out breakdowns from dimnesions + if (hasBreakdowns) { + finalDimensions = _.differenceWith(finalDimensions, breakdowns, (dimn, brkdwn) => + _.isEqual(removeBacktick(dimn.name), removeBacktick(brkdwn.name)) + ); + } + + const finalDataConfig = { + ...dataConfig, + ...realTimeParsedStats, + dimensions: finalDimensions, + breakdowns, + }; + + const mixedUserConfigs = { + availabilityConfig: { + ...(userConfigs.availabilityConfig || {}), + }, + dataConfig: { + ...finalDataConfig, + }, + layoutConfig: { + ...(userConfigs.layoutConfig || {}), + }, + }; + + let query = metaData.query; + + if (props.timeRange) { + query = preprocessQuery({ + rawQuery: metaData.query, + startTime: props.timeRange.from, + endTime: props.timeRange.to, + timeField: props.savedVisualization.selected_timestamp.name, + isLiveQuery: false, + whereClause: props.whereClause, + }); + } + + pplService + .fetch({ query, format: 'jdbc' }) + .then((data) => { + const container = getVizContainerProps({ + vizId: props.savedVisualization.type, + rawVizData: data, + query: { rawQuery: metaData.query }, + indexFields: {}, + userConfigs: mixedUserConfigs, + explorer: { explorerData: data, explorerFields: data.schema }, + }); + setVisContainerProps(container); + }) + .catch((error: Error) => { + console.error(error); + }); + }, [props]); + + return visContainerProps ? ( + {({ size }) => } + ) : null; +}; diff --git a/public/embeddable/filters/filter_parser.ts b/public/embeddable/filters/filter_parser.ts new file mode 100644 index 0000000000..c83a7bc651 --- /dev/null +++ b/public/embeddable/filters/filter_parser.ts @@ -0,0 +1,49 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { Filter, getFilterField } from '../../../../../src/plugins/data/common'; + +export const parseFilters = (filters?: Filter[]) => { + if (!filters) return ''; + return filters + .filter((filter) => !filter.meta.disabled) + .map(parseFilter) + .join(' AND '); +}; + +const parseFilter = (filter: Filter): string => { + const meta = filter.meta; + const field = getFilterField(filter); + if (!meta.negate) { + switch (meta.type) { + case 'phrase': + return `\`${field}\` = '${meta.params.query}'`; + case 'phrases': + return meta.params.map((query: string) => `\`${field}\` = '${query}'`).join(' OR '); + case 'range': + const ranges = []; + if (meta.params.gte != null) ranges.push(`\`${field}\` >= ${meta.params.gte}`); + if (meta.params.lt != null) ranges.push(`\`${field}\` < ${meta.params.lt}`); + return ranges.join(' AND '); + case 'exists': + return `isnotnull(\`${field}\`)`; + } + } else { + switch (meta.type) { + case 'phrase': + return `\`${field}\` != '${meta.params.query}'`; + case 'phrases': + return meta.params.map((query: string) => `\`${field}\` != '${query}'`).join(' AND '); + case 'range': + const ranges = []; + if (meta.params.gte != null) ranges.push(`\`${field}\` < ${meta.params.gte}`); + if (meta.params.lt != null) ranges.push(`\`${field}\` >= ${meta.params.lt}`); + return ranges.join(' OR '); + case 'exists': + return `isnotnull(\`${field}\`)`; + } + } + return ''; +}; diff --git a/public/embeddable/observability_embeddable.tsx b/public/embeddable/observability_embeddable.tsx new file mode 100644 index 0000000000..bba27f0105 --- /dev/null +++ b/public/embeddable/observability_embeddable.tsx @@ -0,0 +1,112 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React from 'react'; +import ReactDOM from 'react-dom'; +import { Subscription } from 'rxjs'; +import { AttributeService } from '../../../../src/plugins/dashboard/public'; +import { + Embeddable, + EmbeddableOutput, + IContainer, + ReferenceOrValueEmbeddable, + SavedObjectEmbeddableInput, +} from '../../../../src/plugins/embeddable/public'; +import { + VisualizationSavedObjectAttributes, + VISUALIZATION_SAVED_OBJECT, +} from '../../common/types/observability_saved_object_attributes'; +import { ObservabilityEmbeddableComponent } from './observability_embeddable_component'; + +// Apparently this needs to match the saved object type for the clone and replace panel actions to work +export const OBSERVABILITY_EMBEDDABLE = VISUALIZATION_SAVED_OBJECT; + +export interface ObservabilityEmbeddableConfiguration { + savedVisBuilder: VisualizationSavedObjectAttributes; + // TODO: add indexPatterns as part of configuration + // indexPatterns?: IIndexPattern[]; + editPath: string; + editUrl: string; + editable: boolean; +} + +export type ObservabilityByValueInput = { + attributes: VisualizationSavedObjectAttributes; +} & SavedObjectEmbeddableInput; + +export interface ObservabilityOutput extends EmbeddableOutput { + /** + * Will contain the saved object attributes of the Observability Saved Object that matches + * `input.savedObjectId`. If the id is invalid, this may be undefined. + */ + attributes?: VisualizationSavedObjectAttributes; +} + +type ObservabilityEmbeddableConfig = Required< + Pick +>; + +export class ObservabilityEmbeddable extends Embeddable< + SavedObjectEmbeddableInput, + ObservabilityOutput +> { + public readonly type = OBSERVABILITY_EMBEDDABLE; + private subscription: Subscription; + private node?: HTMLElement; + public savedObjectId?: string; + private attributes?: VisualizationSavedObjectAttributes; + + constructor( + config: ObservabilityEmbeddableConfig, + initialInput: SavedObjectEmbeddableInput, + private attributeService: AttributeService, + { + parent, + }: { + parent?: IContainer; + } + ) { + super(initialInput, { editable: true, ...config }, parent); + + this.subscription = this.getInput$().subscribe(async () => { + const savedObjectId = this.getInput().savedObjectId; + const attributes = (this.getInput() as ObservabilityByValueInput).attributes; + if (this.attributes !== attributes || this.savedObjectId !== savedObjectId) { + this.savedObjectId = savedObjectId; + this.reload(); + } else { + this.updateOutput({ + attributes: this.attributes, + title: this.input.title || this.attributes.title, + }); + } + }); + } + + public render(node: HTMLElement) { + if (this.node) { + ReactDOM.unmountComponentAtNode(this.node); + } + this.node = node; + ReactDOM.render(, node); + } + + public async reload() { + this.attributes = await this.attributeService.unwrapAttributes(this.input); + + this.updateOutput({ + attributes: this.attributes, + title: this.input.title || this.attributes.title, + }); + } + + public destroy() { + super.destroy(); + this.subscription.unsubscribe(); + if (this.node) { + ReactDOM.unmountComponentAtNode(this.node); + } + } +} diff --git a/public/embeddable/observability_embeddable_component.tsx b/public/embeddable/observability_embeddable_component.tsx new file mode 100644 index 0000000000..276539be89 --- /dev/null +++ b/public/embeddable/observability_embeddable_component.tsx @@ -0,0 +1,41 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React from 'react'; +import { + SavedObjectEmbeddableInput, + withEmbeddableSubscription, +} from '../../../../src/plugins/embeddable/public'; +import { SavedObjectVisualization } from '../components/visualizations/saved_object_visualization'; +import { parseFilters } from './filters/filter_parser'; +import { ObservabilityEmbeddable, ObservabilityOutput } from './observability_embeddable'; + +interface ObservabilityEmbeddableComponentProps { + input: SavedObjectEmbeddableInput; + output: ObservabilityOutput; + embeddable: ObservabilityEmbeddable; +} + +const ObservabilityEmbeddableComponentInner: React.FC = ( + props +) => { + const visualization = props.output.attributes?.savedVisualization; + return visualization ? ( + + ) : null; +}; + +export const ObservabilityEmbeddableComponent = withEmbeddableSubscription< + SavedObjectEmbeddableInput, + ObservabilityOutput, + ObservabilityEmbeddable, + {} +>(ObservabilityEmbeddableComponentInner); diff --git a/public/embeddable/observability_embeddable_factory.tsx b/public/embeddable/observability_embeddable_factory.tsx new file mode 100644 index 0000000000..81c5857a62 --- /dev/null +++ b/public/embeddable/observability_embeddable_factory.tsx @@ -0,0 +1,142 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { + OverlayStart, + SavedObjectsClientContract, + SimpleSavedObject, +} from '../../../../src/core/public'; +import { AttributeService, DashboardStart } from '../../../../src/plugins/dashboard/public'; +import { + EmbeddableFactoryDefinition, + EmbeddableOutput, + ErrorEmbeddable, + IContainer, + SavedObjectEmbeddableInput, +} from '../../../../src/plugins/embeddable/public'; +import { + checkForDuplicateTitle, + OnSaveProps, + SavedObjectMetaData, +} from '../../../../src/plugins/saved_objects/public'; +import { observabilityID } from '../../common/constants/shared'; +import { + VisualizationSavedObjectAttributes, + VISUALIZATION_SAVED_OBJECT, +} from '../../common/types/observability_saved_object_attributes'; +import { + ObservabilityEmbeddable, + ObservabilityOutput, + OBSERVABILITY_EMBEDDABLE, +} from './observability_embeddable'; + +interface StartServices { + getAttributeService: DashboardStart['getAttributeService']; + savedObjectsClient: SavedObjectsClientContract; + overlays: OverlayStart; +} + +export class ObservabilityEmbeddableFactoryDefinition + implements + EmbeddableFactoryDefinition< + SavedObjectEmbeddableInput, + ObservabilityOutput | EmbeddableOutput, + ObservabilityEmbeddable, + VisualizationSavedObjectAttributes + > { + public readonly type = OBSERVABILITY_EMBEDDABLE; + public readonly savedObjectMetaData: SavedObjectMetaData = { + name: 'SQL/PPL Visualizations', + includeFields: [], + type: VISUALIZATION_SAVED_OBJECT, // saved object type for finding embeddables in Dashboard + getIconForSavedObject: () => 'lensApp', + }; + private attributeService?: AttributeService; + + constructor(private getStartServices: () => Promise) {} + + async createFromSavedObject( + savedObjectId: string, + input: SavedObjectEmbeddableInput, + parent?: IContainer + ) { + const editPath = `#/event_analytics/explorer/${savedObjectId}`; + const editUrl = `/app/${observabilityID}${editPath}`; + return new ObservabilityEmbeddable( + { + editUrl, + editPath, + editApp: observabilityID, + }, + input, + await this.getAttributeService(), + { parent } + ); + } + + async create(initialInput: SavedObjectEmbeddableInput, parent?: IContainer) { + return new ErrorEmbeddable( + 'Saved searches can only be created from a saved object', + initialInput + ); + } + + async isEditable() { + return true; + } + + getDisplayName() { + return 'Observability'; + } + + private async saveMethod(attributes: VisualizationSavedObjectAttributes, savedObjectId?: string) { + const { savedObjectsClient } = await this.getStartServices(); + if (savedObjectId) { + return savedObjectsClient.update(this.type, savedObjectId, attributes); + } + return savedObjectsClient.create(this.type, attributes); + } + + private async unwrapMethod(savedObjectId: string): Promise { + const { savedObjectsClient } = await this.getStartServices(); + const savedObject: SimpleSavedObject = await savedObjectsClient.get< + VisualizationSavedObjectAttributes + >(this.type, savedObjectId); + return { ...savedObject.attributes }; + } + + private async checkForDuplicateTitleMethod(props: OnSaveProps): Promise { + const start = await this.getStartServices(); + const { savedObjectsClient, overlays } = start; + return checkForDuplicateTitle( + { + title: props.newTitle, + copyOnSave: false, + lastSavedTitle: '', + getOpenSearchType: () => this.type, + getDisplayName: this.getDisplayName || (() => this.type), + }, + props.isTitleDuplicateConfirmed, + props.onTitleDuplicate, + { + savedObjectsClient, + overlays, + } + ); + } + + private async getAttributeService() { + if (!this.attributeService) { + this.attributeService = (await this.getStartServices()).getAttributeService< + VisualizationSavedObjectAttributes + >(this.type, { + saveMethod: this.saveMethod.bind(this), + unwrapMethod: this.unwrapMethod.bind(this), + checkForDuplicateTitle: this.checkForDuplicateTitleMethod.bind(this), + }); + } + return this.attributeService!; + } +} diff --git a/public/plugin.ts b/public/plugin.ts index 1610c0dbf8..dee85204a4 100644 --- a/public/plugin.ts +++ b/public/plugin.ts @@ -3,26 +3,51 @@ * SPDX-License-Identifier: Apache-2.0 */ -import './index.scss'; - import { AppMountParameters, CoreSetup, CoreStart, Plugin } from '../../../src/core/public'; import { observabilityID, observabilityPluginOrder, observabilityTitle, } from '../common/constants/shared'; -import PPLService from './services/requests/ppl'; -import DSLService from './services/requests/dsl'; -import TimestampUtils from './services/timestamp/timestamp'; -import SavedObjects from './services/saved_objects/event_analytics/saved_objects'; -import { AppPluginStartDependencies, ObservabilitySetup, ObservabilityStart } from './types'; +import { QueryManager } from '../common/query_manager'; +import { VISUALIZATION_SAVED_OBJECT } from '../common/types/observability_saved_object_attributes'; +import { + setOSDHttp, + setOSDSavedObjectsClient, + setPPLService, + uiSettingsService, +} from '../common/utils'; import { convertLegacyNotebooksUrl } from './components/notebooks/components/helpers/legacy_route_helpers'; import { convertLegacyTraceAnalyticsUrl } from './components/trace_analytics/components/common/legacy_route_helpers'; -import { uiSettingsService } from '../common/utils'; -import { QueryManager } from '../common/query_manager'; -export class ObservabilityPlugin implements Plugin { - public setup(core: CoreSetup): ObservabilitySetup { +import { OBSERVABILITY_EMBEDDABLE } from './embeddable/observability_embeddable'; +import { ObservabilityEmbeddableFactoryDefinition } from './embeddable/observability_embeddable_factory'; +import './index.scss'; +import DSLService from './services/requests/dsl'; +import PPLService from './services/requests/ppl'; +import SavedObjects from './services/saved_objects/event_analytics/saved_objects'; +import TimestampUtils from './services/timestamp/timestamp'; +import { + AppPluginStartDependencies, + ObservabilitySetup, + ObservabilityStart, + SetupDependencies, +} from './types'; + +export class ObservabilityPlugin + implements + Plugin { + public setup( + core: CoreSetup, + setupDeps: SetupDependencies + ): ObservabilitySetup { uiSettingsService.init(core.uiSettings, core.notifications); + const pplService = new PPLService(core.http); + const qm = new QueryManager(); + setPPLService(pplService); + setOSDHttp(core.http); + core.getStartServices().then(([coreStart]) => { + setOSDSavedObjectsClient(coreStart.savedObjects.client); + }); // redirect legacy notebooks URL to current URL under observability if (window.location.pathname.includes('notebooks-dashboards')) { @@ -46,14 +71,12 @@ export class ObservabilityPlugin implements Plugin ({ + getAttributeService: (await core.getStartServices())[1].dashboard.getAttributeService, + savedObjectsClient: (await core.getStartServices())[0].savedObjects.client, + overlays: (await core.getStartServices())[0].overlays, + })); + setupDeps.embeddable.registerEmbeddableFactory(OBSERVABILITY_EMBEDDABLE, embeddableFactory); + + setupDeps.visualizations.registerAlias({ + name: observabilityID, + title: observabilityTitle, + description: 'create a visualization with Piped processigng language', + icon: 'pencil', + aliasApp: observabilityID, + aliasPath: '#/event_analytics/explorer', + stage: 'production', + appExtensions: { + visualizations: { + docTypes: [VISUALIZATION_SAVED_OBJECT], + toListItem: ({ id, attributes, updated_at: updatedAt }) => ({ + description: attributes?.description, + editApp: observabilityID, + editUrl: `#/event_analytics/explorer/${encodeURIComponent(id)}`, + icon: 'pencil', + id, + savedObjectType: VISUALIZATION_SAVED_OBJECT, + title: attributes?.title, + typeTitle: observabilityTitle, + stage: 'production', + updated_at: updatedAt, + }), + }, + }, + }); + // Return methods that should be available to other plugins return {}; } diff --git a/public/types.ts b/public/types.ts index 82bd6543a4..48f0ad9de6 100644 --- a/public/types.ts +++ b/public/types.ts @@ -3,14 +3,30 @@ * SPDX-License-Identifier: Apache-2.0 */ +import { SavedObjectsClient } from '../../../src/core/server'; import { DashboardStart } from '../../../src/plugins/dashboard/public'; +import { DataPublicPluginSetup } from '../../../src/plugins/data/public'; +import { EmbeddableSetup, EmbeddableStart } from '../../../src/plugins/embeddable/public'; import { NavigationPublicPluginStart } from '../../../src/plugins/navigation/public'; +import { UiActionsStart } from '../../../src/plugins/ui_actions/public'; +import { VisualizationsSetup } from '../../../src/plugins/visualizations/public'; export interface AppPluginStartDependencies { navigation: NavigationPublicPluginStart; + embeddable: EmbeddableStart; dashboard: DashboardStart; + savedObjectsClient: SavedObjectsClient; } +export interface SetupDependencies { + embeddable: EmbeddableSetup; + visualizations: VisualizationsSetup; + data: DataPublicPluginSetup; + uiActions: UiActionsStart; +} + +// eslint-disable-next-line @typescript-eslint/no-empty-interface export interface ObservabilitySetup {} +// eslint-disable-next-line @typescript-eslint/no-empty-interface export interface ObservabilityStart {} diff --git a/server/plugin.ts b/server/plugin.ts index 69738f73e8..d48296c6b3 100644 --- a/server/plugin.ts +++ b/server/plugin.ts @@ -14,6 +14,7 @@ import { import { OpenSearchObservabilityPlugin } from './adaptors/opensearch_observability_plugin'; import { PPLPlugin } from './adaptors/ppl_plugin'; import { setupRoutes } from './routes/index'; +import { visualizationSavedObject } from './saved_objects/observability_saved_object'; import { ObservabilityPluginSetup, ObservabilityPluginStart } from './types'; export class ObservabilityPlugin @@ -30,10 +31,7 @@ export class ObservabilityPlugin const openSearchObservabilityClient: ILegacyClusterClient = core.opensearch.legacy.createClient( 'opensearch_observability', { - plugins: [ - PPLPlugin, - OpenSearchObservabilityPlugin, - ], + plugins: [PPLPlugin, OpenSearchObservabilityPlugin], } ); @@ -48,6 +46,8 @@ export class ObservabilityPlugin // Register server side APIs setupRoutes({ router, client: openSearchObservabilityClient }); + core.savedObjects.registerType(visualizationSavedObject); + return {}; } diff --git a/server/routes/event_analytics/event_analytics_router.ts b/server/routes/event_analytics/event_analytics_router.ts index c2fd7c2d2c..03933649d5 100644 --- a/server/routes/event_analytics/event_analytics_router.ts +++ b/server/routes/event_analytics/event_analytics_router.ts @@ -25,7 +25,6 @@ export const registerEventAnalyticsRouter = ({ router: IRouter; savedObjectFacet: SavedObjectFacet; }) => { - router.get( { path: `${OBSERVABILITY_BASE}${EVENT_ANALYTICS}${SAVED_OBJECTS}`, @@ -46,7 +45,7 @@ export const registerEventAnalyticsRouter = ({ return res.custom(result); } ); - + router.get( { path: `${OBSERVABILITY_BASE}${EVENT_ANALYTICS}${SAVED_OBJECTS}/{objectId}`, @@ -138,12 +137,14 @@ export const registerEventAnalyticsRouter = ({ name: schema.string(), description: schema.string(), application_id: schema.maybe(schema.string()), - user_configs: schema.string(), + user_configs: schema.maybe(schema.string()), sub_type: schema.string(), units_of_measure: schema.maybe(schema.string()), - selected_labels: schema.maybe(schema.object({ - label: schema.arrayOf(schema.object({}, { unknowns: 'allow' })), - })), + selected_labels: schema.maybe( + schema.object({ + label: schema.arrayOf(schema.object({}, { unknowns: 'allow' })), + }) + ), }), }), }, @@ -230,12 +231,14 @@ export const registerEventAnalyticsRouter = ({ name: schema.string(), description: schema.string(), application_id: schema.maybe(schema.string()), - user_configs: schema.string(), + user_configs: schema.maybe(schema.string()), sub_type: schema.string(), units_of_measure: schema.maybe(schema.string()), - selected_labels: schema.maybe(schema.object({ - labels: schema.arrayOf(schema.object({}, { unknowns: 'allow' })), - })), + selected_labels: schema.maybe( + schema.object({ + labels: schema.arrayOf(schema.object({}, { unknowns: 'allow' })), + }) + ), }), }), }, diff --git a/server/saved_objects/observability_saved_object.ts b/server/saved_objects/observability_saved_object.ts new file mode 100644 index 0000000000..4ebcffddcb --- /dev/null +++ b/server/saved_objects/observability_saved_object.ts @@ -0,0 +1,26 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { SavedObjectsType } from '../../../../src/core/server'; +import { VISUALIZATION_SAVED_OBJECT } from '../../common/types/observability_saved_object_attributes'; + +export const visualizationSavedObject: SavedObjectsType = { + name: VISUALIZATION_SAVED_OBJECT, + hidden: false, + namespaceType: 'single', + mappings: { + dynamic: false, + properties: { + title: { + type: 'text', + }, + description: { + type: 'text', + }, + version: { type: 'integer' }, + }, + }, + migrations: {}, +}; diff --git a/server/services/facets/saved_objects.ts b/server/services/facets/saved_objects.ts index 30286d21b8..ee4363c4da 100644 --- a/server/services/facets/saved_objects.ts +++ b/server/services/facets/saved_objects.ts @@ -3,6 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ +import { ILegacyClusterClient, ScopeableRequest } from '../../../../../src/core/server'; import { sampleQueries, sampleVisualizations, @@ -10,11 +11,11 @@ import { // eslint-disable-next-line import/no-default-export export default class SavedObjectFacet { - constructor(private client: any) { + constructor(private client: ILegacyClusterClient) { this.client = client; } - fetch = async (request: any, params: any, format: string) => { + fetch = async (request: ScopeableRequest, params: Record, format: string) => { const res = { success: false, data: {}, @@ -152,7 +153,7 @@ export default class SavedObjectFacet { const savedQueryIds: any[] = []; if (['panels', 'event_analytics'].includes(request.params.sampleRequestor)) { - for (var i = 0; i < sampleVisualizations.length; i++) { + for (let i = 0; i < sampleVisualizations.length; i++) { const params = { body: { savedVisualization: { @@ -164,7 +165,7 @@ export default class SavedObjectFacet { savedVizIds.push(savedVizRes.objectId); } - for (var i = 0; i < sampleQueries.length; i++) { + for (let i = 0; i < sampleQueries.length; i++) { const params = { body: { savedQuery: { @@ -196,7 +197,7 @@ export default class SavedObjectFacet { return this.fetch( request, { - ...params + ...params, }, 'observability.getObject' ); From d65345f3ebebb70ff56d398a423b561e1965d053 Mon Sep 17 00:00:00 2001 From: Joshua Li Date: Thu, 30 Mar 2023 22:18:46 +0000 Subject: [PATCH 31/73] Add osd visualizations saved object client Signed-off-by: Joshua Li --- .../event_analytics/explorer/explorer.tsx | 46 +++--- .../components/event_analytics/home/home.tsx | 85 +++++----- .../saved_object_client/client_base.ts | 15 +- .../saved_object_client/client_factory.ts | 56 +++++++ .../saved_object_client/client_interface.ts | 12 +- .../osd_saved_object_client.ts | 108 +++++++++++++ .../osd_saved_objects/saved_visualization.ts | 153 ++++++++++++++++++ .../osd_saved_objects/types.ts | 17 ++ .../saved_object_client/ppl/ppl_client.ts | 21 ++- .../ppl/saved_visualization.ts | 5 +- .../saved_object_client/types.ts | 28 ++++ .../ppl/save_as_new_vis.ts | 3 +- 12 files changed, 471 insertions(+), 78 deletions(-) create mode 100644 public/services/saved_objects/saved_object_client/client_factory.ts create mode 100644 public/services/saved_objects/saved_object_client/osd_saved_objects/osd_saved_object_client.ts create mode 100644 public/services/saved_objects/saved_object_client/osd_saved_objects/saved_visualization.ts create mode 100644 public/services/saved_objects/saved_object_client/osd_saved_objects/types.ts create mode 100644 public/services/saved_objects/saved_object_client/types.ts diff --git a/public/components/event_analytics/explorer/explorer.tsx b/public/components/event_analytics/explorer/explorer.tsx index 11fbee83ae..7f38f450aa 100644 --- a/public/components/event_analytics/explorer/explorer.tsx +++ b/public/components/event_analytics/explorer/explorer.tsx @@ -55,6 +55,7 @@ import { PPL_NEWLINE_REGEX, PPL_STATS_REGEX, } from '../../../../common/constants/shared'; +import { QueryManager } from '../../../../common/query_manager'; import { IDefaultTimestampState, IExplorerFields, @@ -68,7 +69,21 @@ import { buildQuery, composeFinalQuery, getIndexPatternFromRawQuery, + getOSDSavedObjectsClient, + uiSettingsService, } from '../../../../common/utils'; +import { getSavedObjectsClient } from '../../../services/saved_objects/saved_object_client/client_factory'; +import { OSDSavedVisualizationClient } from '../../../services/saved_objects/saved_object_client/osd_saved_objects/saved_visualization'; +import { + PanelSavedObjectClient, + PPLSavedQueryClient, +} from '../../../services/saved_objects/saved_object_client/ppl'; +import { + SaveAsCurrenQuery, + SaveAsCurrentVisualization, + SaveAsNewVisualization, +} from '../../../services/saved_objects/saved_object_savers'; +import { SaveAsNewQuery } from '../../../services/saved_objects/saved_object_savers/ppl/save_as_new_query'; import { sleep } from '../../common/live_tail/live_tail_button'; import { onItemSelect, parseGetSuggestions } from '../../common/search/autocomplete_logic'; import { Search } from '../../common/search/search'; @@ -87,28 +102,15 @@ import { selectVisualizationConfig, } from '../redux/slices/viualization_config_slice'; import { formatError, getDefaultVisConfig } from '../utils'; +import { getContentTabTitle, getDateRange } from '../utils/utils'; import { DataGrid } from './events_views/data_grid'; import { HitsCounter } from './hits_counter/hits_counter'; +import { LogPatterns } from './log_patterns/log_patterns'; import { NoResults } from './no_results'; import { Sidebar } from './sidebar'; import { TimechartHeader } from './timechart_header'; import { ExplorerVisualizations } from './visualizations'; import { CountDistribution } from './visualizations/count_distribution'; -import { QueryManager } from '../../../../common/query_manager'; -import { uiSettingsService } from '../../../../common/utils'; -import { LogPatterns } from './log_patterns/log_patterns'; -import { getContentTabTitle, getDateRange } from '../utils/utils'; -import { - PPLSavedQueryClient, - PPLSavedVisualizationClient, - PanelSavedObjectClient, -} from '../../../services/saved_objects/saved_object_client/ppl'; -import { SaveAsNewQuery } from '../../../services/saved_objects/saved_object_savers/ppl/save_as_new_query'; -import { - SaveAsCurrenQuery, - SaveAsCurrentVisualization, - SaveAsNewVisualization, -} from '../../../services/saved_objects/saved_object_savers'; export const Explorer = ({ pplService, @@ -251,10 +253,8 @@ export const Explorer = ({ const getSavedDataById = async (objectId: string) => { // load saved query/visualization if object id exists - await savedObjects - .fetchSavedObjects({ - objectId, - }) + await getSavedObjectsClient({ objectId, objectType: 'savedQuery' }) + .get({ objectId }) .then(async (res) => { const savedData = res.observabilityObjectList[0]; const isSavedQuery = has(savedData, SAVED_QUERY); @@ -921,7 +921,10 @@ export const Explorer = ({ soClient = new SaveAsCurrentVisualization( { tabId, history, notifications, showPermissionErrorToast }, { batch, dispatch, changeQuery, updateTabName }, - new PPLSavedVisualizationClient(http), + getSavedObjectsClient({ + objectId: query[SAVED_OBJECT_ID], + objectType: 'savedVisualization', + }), new PanelSavedObjectClient(http), { ...commonParams, @@ -943,7 +946,7 @@ export const Explorer = ({ addVisualizationToPanel, }, { batch, dispatch, changeQuery, updateTabName }, - new PPLSavedVisualizationClient(http), + new OSDSavedVisualizationClient(getOSDSavedObjectsClient()), new PanelSavedObjectClient(http), { ...commonParams, @@ -1061,6 +1064,7 @@ export const Explorer = ({ setToast, pplService, notifications, + dispatch, }} >
    { }; const fetchHistories = async () => { - const res = await savedObjects.fetchSavedObjects({ + const observabilityObjects = await savedObjects.fetchSavedObjects({ objectType: ['savedQuery', 'savedVisualization'], sortOrder: 'desc', fromIndex: 0, }); - const nonAppObjects = res.observabilityObjectList.filter( - (object: SavedQueryRes | SavedVizRes) => + const osdObjects = await new OSDSavedVisualizationClient(getOSDSavedObjectsClient()).getBulk( + {} + ); + observabilityObjects.observabilityObjectList = [ + ...osdObjects.observabilityObjectList, + ...observabilityObjects.observabilityObjectList, + ]; + const nonAppObjects = observabilityObjects.observabilityObjectList.filter( + (object: ObservabilitySavedObject) => (object.savedVisualization && !object.savedVisualization.application_id) || object.savedQuery ); @@ -274,8 +280,11 @@ const EventAnalyticsHome = (props: IHomeProps) => { }), }); + // wait for flush + await new Promise((resolve) => setTimeout(resolve, 1000)); + const res = await savedObjects.fetchSavedObjects({ - objectIdList: [...resp?.savedVizIds, ...resp?.savedQueryIds] || [], + // objectIdList: [...resp?.savedVizIds, ...resp?.savedQueryIds] || [], objectType: ['savedQuery', 'savedVisualization'], sortOrder: 'desc', fromIndex: 0, diff --git a/public/services/saved_objects/saved_object_client/client_base.ts b/public/services/saved_objects/saved_object_client/client_base.ts index 05d6e8a1c6..443c64c20f 100644 --- a/public/services/saved_objects/saved_object_client/client_base.ts +++ b/public/services/saved_objects/saved_object_client/client_base.ts @@ -4,13 +4,14 @@ */ import { ISavedObjectsClient } from './client_interface'; +import { SavedObjectsCreateResponse, SavedObjectsGetResponse } from './types'; export abstract class SavedObjectClientBase implements ISavedObjectsClient { - abstract create(params: any): Promise; - abstract get(params: any): Promise; - abstract getBulk(params: any): Promise>>; - abstract update(params: any): Promise; - abstract updateBulk(params: any): Promise>>; - abstract delete(params: any): Promise; - abstract deleteBulk(params: any): Promise>>; + abstract create(params: unknown): Promise; + abstract get(params: unknown): Promise; + abstract getBulk(params: unknown): Promise; + abstract update(params: unknown): Promise; + abstract updateBulk(params: unknown): Promise>>; + abstract delete(params: unknown): Promise; + abstract deleteBulk(params: unknown): Promise; } diff --git a/public/services/saved_objects/saved_object_client/client_factory.ts b/public/services/saved_objects/saved_object_client/client_factory.ts new file mode 100644 index 0000000000..fc1cb8012b --- /dev/null +++ b/public/services/saved_objects/saved_object_client/client_factory.ts @@ -0,0 +1,56 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { getOSDHttp, getOSDSavedObjectsClient } from '../../../../common/utils'; +import { ISavedObjectsClient } from './client_interface'; +import { OSDSavedVisualizationClient } from './osd_saved_objects/saved_visualization'; +import { PPLSavedQueryClient, PPLSavedVisualizationClient } from './ppl'; + +type SavedObjectsClientType = 'osd' | 'ppl'; +type SavedObjectsType = 'savedQuery' | 'savedVisualization'; + +interface GetSavedObjectsClientOptions { + objectId: string; + objectType: SavedObjectsType; +} + +const UUID_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-5][0-9a-f]{3}-[089ab][0-9a-f]{3}-[0-9a-f]{12}$/i; + +const getTypeById = (objectId: string): SavedObjectsClientType => { + if (UUID_REGEX.test(objectId)) { + return 'osd'; + } + return 'ppl'; +}; + +let osdSavedVisualizationClient: OSDSavedVisualizationClient; +let pplSavedQueryClient: PPLSavedQueryClient; +let pplSavedVisualizationClient: PPLSavedVisualizationClient; + +export const getSavedObjectsClient = ( + options: GetSavedObjectsClientOptions +): ISavedObjectsClient => { + const clientType = getTypeById(options.objectId); + + if (clientType === 'osd') { + if (osdSavedVisualizationClient === undefined) { + osdSavedVisualizationClient = new OSDSavedVisualizationClient(getOSDSavedObjectsClient()); + } + return osdSavedVisualizationClient; + } + + switch (options.objectType) { + case 'savedQuery': + if (pplSavedQueryClient === undefined) { + pplSavedQueryClient = new PPLSavedQueryClient(getOSDHttp()); + } + return pplSavedQueryClient; + default: + if (pplSavedVisualizationClient === undefined) { + pplSavedVisualizationClient = new PPLSavedVisualizationClient(getOSDHttp()); + } + return pplSavedVisualizationClient; + } +}; diff --git a/public/services/saved_objects/saved_object_client/client_interface.ts b/public/services/saved_objects/saved_object_client/client_interface.ts index 4856639c12..bdf609dd5a 100644 --- a/public/services/saved_objects/saved_object_client/client_interface.ts +++ b/public/services/saved_objects/saved_object_client/client_interface.ts @@ -3,12 +3,14 @@ * SPDX-License-Identifier: Apache-2.0 */ +import { SavedObjectsCreateResponse, SavedObjectsGetResponse } from './types'; + export interface ISavedObjectsClient { - create: (params: any) => Promise; - get: (params: any) => Promise; - getBulk: (params: any) => Promise>>; + create: (params: any) => Promise; + get: (params: any) => Promise; + getBulk: (params: any) => Promise; update: (params: any) => Promise; - updateBulk: (params: any) => Promise>>; + updateBulk: (params: any) => Promise; delete: (params: any) => Promise; - deleteBulk: (params: any) => Promise>>; + deleteBulk: (params: any) => Promise; } diff --git a/public/services/saved_objects/saved_object_client/osd_saved_objects/osd_saved_object_client.ts b/public/services/saved_objects/saved_object_client/osd_saved_objects/osd_saved_object_client.ts new file mode 100644 index 0000000000..1be96a1e47 --- /dev/null +++ b/public/services/saved_objects/saved_object_client/osd_saved_objects/osd_saved_object_client.ts @@ -0,0 +1,108 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { isEmpty } from 'lodash'; +import { + SavedObjectsClientContract, + SimpleSavedObject, +} from '../../../../../../../src/core/public'; +import { SavedObjectClientBase } from '../client_base'; +import { SavedObjectsGetResponse, SavedObjectsCreateResponse } from '../types'; + +export class OSDSavedObjectClient extends SavedObjectClientBase { + constructor(protected readonly client: SavedObjectsClientContract) { + super(); + } + create(params: unknown): Promise { + throw new Error('Method not implemented.'); + } + get(params: unknown): Promise { + throw new Error('Method not implemented.'); + } + getBulk(params: unknown): Promise { + throw new Error('Method not implemented.'); + } + update(params: unknown): Promise { + throw new Error('Method not implemented.'); + } + updateBulk(params: unknown): Promise>> { + throw new Error('Method not implemented.'); + } + delete(params: unknown): Promise { + throw new Error('Method not implemented.'); + } + deleteBulk(params: unknown): Promise { + throw new Error('Method not implemented.'); + } + convertToLastUpdatedMs(updatedAt: SimpleSavedObject['updated_at']) { + return (updatedAt ? new Date(updatedAt) : new Date()).getTime(); + } + buildRequestBody({ + query, + fields, + dateRange, + timestamp, + name = '', + chartType = '', + description = '', + applicationId = '', + userConfigs = '', + subType = '', + unitsOfMeasure = '', + selectedLabels, + objectId = '', + }: any) { + const objRequest: any = { + object: { + query, + selected_date_range: { + start: dateRange[0] || 'now/15m', + end: dateRange[1] || 'now', + text: '', + }, + selected_timestamp: { + name: timestamp || '', + type: 'timestamp', + }, + selected_fields: { + tokens: fields, + text: '', + }, + name: name || '', + description: description || '', + }, + }; + + if (!isEmpty(chartType)) { + objRequest.object.type = chartType; + } + + if (!isEmpty(applicationId)) { + objRequest.object.application_id = applicationId; + } + + if (!isEmpty(userConfigs)) { + objRequest.object.user_configs = userConfigs; + } + + if (!isEmpty(subType)) { + objRequest.object.sub_type = subType; + } + + if (!isEmpty(unitsOfMeasure)) { + objRequest.object.units_of_measure = unitsOfMeasure; + } + + if (!isEmpty(selectedLabels)) { + objRequest.object.selected_labels = selectedLabels; + } + + if (!isEmpty(objectId)) { + objRequest.object_id = objectId; + } + + return objRequest; + } +} diff --git a/public/services/saved_objects/saved_object_client/osd_saved_objects/saved_visualization.ts b/public/services/saved_objects/saved_object_client/osd_saved_objects/saved_visualization.ts new file mode 100644 index 0000000000..63242727c4 --- /dev/null +++ b/public/services/saved_objects/saved_object_client/osd_saved_objects/saved_visualization.ts @@ -0,0 +1,153 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { SavedObjectsFindOptions } from '../../../../../../../src/core/public'; +import { IField } from '../../../../../common/types/explorer'; +import { + SAVED_OBJECT_VERSION, + VisualizationSavedObjectAttributes, + VISUALIZATION_SAVED_OBJECT, +} from '../../../../../common/types/observability_saved_object_attributes'; +import { SavedObjectsGetResponse } from '../types'; +import { OSDSavedObjectClient } from './osd_saved_object_client'; +import { OSDSavedObjectCreateResponse, OSDSavedObjectUpdateResponse } from './types'; + +interface CommonParams { + query: string; + fields: IField[]; + dateRange: [string, string]; + type: string; + name: string; + timestamp: string; + applicationId: string; + userConfigs: any; + description: string; + subType: string; + unitsOfMeasure: string; + selectedLabels: string; +} + +type CreateParams = CommonParams & { applicationId: string }; +type UpdateParams = Partial & { objectId: string }; + +interface GetParams { + objectId: string; +} + +export class OSDSavedVisualizationClient extends OSDSavedObjectClient { + async create( + params: CreateParams + ): Promise> { + const body = this.buildRequestBody({ + query: params.query, + fields: params.fields, + dateRange: params.dateRange, + chartType: params.type, + name: params.name, + timestamp: params.timestamp, + applicationId: params.applicationId, + userConfigs: params.userConfigs, + description: params.description, + subType: params.subType, + unitsOfMeasure: params.unitsOfMeasure, + selectedLabels: params.selectedLabels, + }); + + const response = await this.client.create( + VISUALIZATION_SAVED_OBJECT, + { + title: params.name, + description: params.description, + version: SAVED_OBJECT_VERSION, + createdTimeMs: new Date().getTime(), + savedVisualization: { + ...body.object, + }, + } + ); + + return { + objectId: response.id, + object: response, + }; + } + + async update( + params: UpdateParams + ): Promise> { + const body = this.buildRequestBody({ + query: params.query, + fields: params.fields, + dateRange: params.dateRange, + chartType: params.type, + name: params.name, + timestamp: params.timestamp, + applicationId: params.applicationId, + userConfigs: params.userConfigs, + description: params.description, + subType: params.subType, + unitsOfMeasure: params.unitsOfMeasure, + selectedLabels: params.selectedLabels, + }); + + const response = await this.client.update>( + VISUALIZATION_SAVED_OBJECT, + params.objectId, + { + title: params.name, + description: params.description, + version: SAVED_OBJECT_VERSION, + savedVisualization: body.object, + } + ); + + return { + objectId: response.id, + object: response, + }; + } + + async get(params: GetParams): Promise { + const response = await this.client.get( + VISUALIZATION_SAVED_OBJECT, + params.objectId + ); + return { + observabilityObjectList: [ + { + objectId: response.id, + createdTimeMs: response.attributes.createdTimeMs, + lastUpdatedTimeMs: this.convertToLastUpdatedMs(response.updated_at), + savedVisualization: response.attributes.savedVisualization, + }, + ], + }; + } + + async getBulk(params: Partial): Promise { + const observabilityObjectList = await this.client + .find({ + ...params, + type: VISUALIZATION_SAVED_OBJECT, + }) + .then((findRes) => + findRes.savedObjects.map((o) => ({ + objectId: o.id, + createdTimeMs: o.attributes.createdTimeMs, + lastUpdatedTimeMs: this.convertToLastUpdatedMs(o.updated_at), + savedVisualization: o.attributes.savedVisualization, + })) + ); + return { observabilityObjectList }; + } + + async delete(params: { objectId: string }): Promise { + return this.client.delete(VISUALIZATION_SAVED_OBJECT, params.objectId); + } + + async deleteBulk(params: { objectIdList: string[] }): Promise { + return params.objectIdList.map((id) => this.client.delete(VISUALIZATION_SAVED_OBJECT, id)); + } +} diff --git a/public/services/saved_objects/saved_object_client/osd_saved_objects/types.ts b/public/services/saved_objects/saved_object_client/osd_saved_objects/types.ts new file mode 100644 index 0000000000..4764681c41 --- /dev/null +++ b/public/services/saved_objects/saved_object_client/osd_saved_objects/types.ts @@ -0,0 +1,17 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { SavedObjectAttributes, SimpleSavedObject } from '../../../../../../../src/core/public'; +import { SavedObjectsCreateResponse } from '../types'; + +export interface OSDSavedObjectCreateResponse + extends SavedObjectsCreateResponse { + object: SimpleSavedObject; +} + +export interface OSDSavedObjectUpdateResponse + extends SavedObjectsCreateResponse { + object: SimpleSavedObject>; +} diff --git a/public/services/saved_objects/saved_object_client/ppl/ppl_client.ts b/public/services/saved_objects/saved_object_client/ppl/ppl_client.ts index 3a26e5afeb..a9f91d454a 100644 --- a/public/services/saved_objects/saved_object_client/ppl/ppl_client.ts +++ b/public/services/saved_objects/saved_object_client/ppl/ppl_client.ts @@ -4,9 +4,14 @@ */ import { isEmpty } from 'lodash'; +import { HttpStart } from '../../../../../../../src/core/public'; +import { + EVENT_ANALYTICS, + OBSERVABILITY_BASE, + SAVED_OBJECTS, +} from '../../../../../common/constants/shared'; import { SavedObjectClientBase } from '../client_base'; import { ISavedObjectsClient } from '../client_interface'; -import { HttpStart } from '../../../../../../../src/core/public'; export class PPLSavedObjectClient extends SavedObjectClientBase implements ISavedObjectsClient { constructor(protected readonly client: HttpStart) { @@ -16,10 +21,18 @@ export class PPLSavedObjectClient extends SavedObjectClientBase implements ISave throw new Error('Method not implemented.'); } get(params: any): Promise { - throw new Error('Method not implemented.'); + return this.client.get(`${OBSERVABILITY_BASE}${EVENT_ANALYTICS}${SAVED_OBJECTS}`, { + query: { + ...params, + }, + }); } - getBulk(params: any): Promise>> { - throw new Error('Method not implemented.'); + getBulk(params: any): Promise { + return this.client.get(`${OBSERVABILITY_BASE}${EVENT_ANALYTICS}${SAVED_OBJECTS}`, { + query: { + ...params, + }, + }); } update(params: any): Promise { throw new Error('Method not implemented.'); diff --git a/public/services/saved_objects/saved_object_client/ppl/saved_visualization.ts b/public/services/saved_objects/saved_object_client/ppl/saved_visualization.ts index 36c68576e5..affba23034 100644 --- a/public/services/saved_objects/saved_object_client/ppl/saved_visualization.ts +++ b/public/services/saved_objects/saved_object_client/ppl/saved_visualization.ts @@ -11,6 +11,7 @@ import { SAVED_VISUALIZATION, } from '../../../../../common/constants/shared'; import { PPLSavedObjectClient } from './ppl_client'; +import { SavedObjectsCreateResponse, SavedObjectsUpdateResponse } from '../types'; interface CommonParams { query: string; @@ -31,7 +32,7 @@ type CreateParams = CommonParams & { applicationId: string }; type UpdateParams = CommonParams & { objectId: string }; export class PPLSavedVisualizationClient extends PPLSavedObjectClient { - async create(params: CreateParams): Promise { + async create(params: CreateParams): Promise { return await this.client.post( `${OBSERVABILITY_BASE}${EVENT_ANALYTICS}${SAVED_OBJECTS}${SAVED_VISUALIZATION}`, { @@ -55,7 +56,7 @@ export class PPLSavedVisualizationClient extends PPLSavedObjectClient { ); } - async update(params: UpdateParams): Promise { + async update(params: UpdateParams): Promise { return await this.client.put( `${OBSERVABILITY_BASE}${EVENT_ANALYTICS}${SAVED_OBJECTS}${SAVED_VISUALIZATION}`, { diff --git a/public/services/saved_objects/saved_object_client/types.ts b/public/services/saved_objects/saved_object_client/types.ts new file mode 100644 index 0000000000..a02d5144fc --- /dev/null +++ b/public/services/saved_objects/saved_object_client/types.ts @@ -0,0 +1,28 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { SavedQuery, SavedVisualization } from '../../../../common/types/explorer'; + +export interface SavedObjectsCreateResponse { + objectId: string; +} + +export type SavedObjectsUpdateResponse = SavedObjectsCreateResponse; + +export interface ObservabilitySavedObject { + createdTimeMs: number; + lastUpdatedTimeMs: number; + objectId: string; + tenant?: string; + savedVisualization?: SavedVisualization; + savedQuery?: SavedQuery; +} + +export interface SavedObjectsGetResponse { + startIndex?: number; + totalHits?: number; + totalHitRelation?: 'eq' | 'gte'; + observabilityObjectList: ObservabilitySavedObject[]; +} diff --git a/public/services/saved_objects/saved_object_savers/ppl/save_as_new_vis.ts b/public/services/saved_objects/saved_object_savers/ppl/save_as_new_vis.ts index ab7ebe4e9b..316a7e829a 100644 --- a/public/services/saved_objects/saved_object_savers/ppl/save_as_new_vis.ts +++ b/public/services/saved_objects/saved_object_savers/ppl/save_as_new_vis.ts @@ -8,13 +8,14 @@ import { SAVED_OBJECT_TYPE, SAVED_VISUALIZATION, } from '../../../../../common/constants/explorer'; +import { ISavedObjectsClient } from '../../saved_object_client/client_interface'; import { SavedQuerySaver } from './saved_query_saver'; export class SaveAsNewVisualization extends SavedQuerySaver { constructor( private readonly saveContext, protected readonly dispatchers, - private readonly saveClient, + private readonly saveClient: ISavedObjectsClient, private readonly panelClient, private readonly saveParams ) { From aa6b04797e41c15d02739561950f0de6a5b1f8e0 Mon Sep 17 00:00:00 2001 From: Joshua Li Date: Thu, 30 Mar 2023 23:23:27 +0000 Subject: [PATCH 32/73] Add temporary workaround for deleting objects Signed-off-by: Joshua Li --- .../components/event_analytics/home/home.tsx | 7 ++++++- .../osd_saved_objects/saved_visualization.ts | 21 ++++++++++++++----- .../saved_object_client/ppl/ppl_client.ts | 4 +++- .../saved_object_client/types.ts | 6 ++++++ 4 files changed, 31 insertions(+), 7 deletions(-) diff --git a/public/components/event_analytics/home/home.tsx b/public/components/event_analytics/home/home.tsx index 8696ef805f..15281bce25 100644 --- a/public/components/event_analytics/home/home.tsx +++ b/public/components/event_analytics/home/home.tsx @@ -139,7 +139,12 @@ const EventAnalyticsHome = (props: IHomeProps) => { const objectIdsToDelete = selectedHistories.map((hstry) => hstry.data.objectId); await savedObjects .deleteSavedObjectsList({ objectIdList: objectIdsToDelete }) - .then(async (res) => { + .catch(() => + new OSDSavedVisualizationClient(getOSDSavedObjectsClient()).deleteBulk({ + objectIdList: objectIdsToDelete, + }) + ) + .then(async () => { setSavedHistories((staleHistories) => { return staleHistories.filter((his) => { return !objectIdsToDelete.includes(his.objectId); diff --git a/public/services/saved_objects/saved_object_client/osd_saved_objects/saved_visualization.ts b/public/services/saved_objects/saved_object_client/osd_saved_objects/saved_visualization.ts index 63242727c4..d07ef8cffe 100644 --- a/public/services/saved_objects/saved_object_client/osd_saved_objects/saved_visualization.ts +++ b/public/services/saved_objects/saved_object_client/osd_saved_objects/saved_visualization.ts @@ -10,7 +10,7 @@ import { VisualizationSavedObjectAttributes, VISUALIZATION_SAVED_OBJECT, } from '../../../../../common/types/observability_saved_object_attributes'; -import { SavedObjectsGetResponse } from '../types'; +import { SavedObjectsDeleteResponse, SavedObjectsGetResponse } from '../types'; import { OSDSavedObjectClient } from './osd_saved_object_client'; import { OSDSavedObjectCreateResponse, OSDSavedObjectUpdateResponse } from './types'; @@ -143,11 +143,22 @@ export class OSDSavedVisualizationClient extends OSDSavedObjectClient { return { observabilityObjectList }; } - async delete(params: { objectId: string }): Promise { - return this.client.delete(VISUALIZATION_SAVED_OBJECT, params.objectId); + async delete(params: { objectId: string }): Promise { + return this.client + .delete(VISUALIZATION_SAVED_OBJECT, params.objectId) + .then((res) => ({ deleteResponseList: { [params.objectId]: 'OK' } })) + .catch((res) => ({ deleteResponseList: { [params.objectId]: res } })); } - async deleteBulk(params: { objectIdList: string[] }): Promise { - return params.objectIdList.map((id) => this.client.delete(VISUALIZATION_SAVED_OBJECT, id)); + async deleteBulk(params: { objectIdList: string[] }): Promise { + const deleteResponseList: SavedObjectsDeleteResponse['deleteResponseList'] = {}; + const x = await Promise.allSettled( + params.objectIdList.map((objectId) => this.delete({ objectId })) + ).then((res) => { + res.map((r, i) => { + deleteResponseList[params.objectIdList[i]] = r.status === 'fulfilled' ? r.value : r.reason; + }); + }); + return { deleteResponseList }; } } diff --git a/public/services/saved_objects/saved_object_client/ppl/ppl_client.ts b/public/services/saved_objects/saved_object_client/ppl/ppl_client.ts index a9f91d454a..5728a2b48d 100644 --- a/public/services/saved_objects/saved_object_client/ppl/ppl_client.ts +++ b/public/services/saved_objects/saved_object_client/ppl/ppl_client.ts @@ -44,7 +44,9 @@ export class PPLSavedObjectClient extends SavedObjectClientBase implements ISave throw new Error('Method not implemented.'); } deleteBulk(params: any): Promise>> { - throw new Error('Method not implemented.'); + return this.client.delete( + `${OBSERVABILITY_BASE}${EVENT_ANALYTICS}${SAVED_OBJECTS}/${params.objectIdList.join(',')}` + ); } buildRequestBody({ query, diff --git a/public/services/saved_objects/saved_object_client/types.ts b/public/services/saved_objects/saved_object_client/types.ts index a02d5144fc..ff2e0ea491 100644 --- a/public/services/saved_objects/saved_object_client/types.ts +++ b/public/services/saved_objects/saved_object_client/types.ts @@ -26,3 +26,9 @@ export interface SavedObjectsGetResponse { totalHitRelation?: 'eq' | 'gte'; observabilityObjectList: ObservabilitySavedObject[]; } + +export interface SavedObjectsDeleteResponse { + deleteResponseList: { + [objectId: string]: string; // org.opensearch.rest.RestStatus, e.g. 'OK' + }; +} From 2880b2fcce7611879cf28f01b49fbc3727d01a7d Mon Sep 17 00:00:00 2001 From: Eric Wei Date: Fri, 31 Mar 2023 13:40:13 -0700 Subject: [PATCH 33/73] explorer saved object loader Signed-off-by: Eric Wei --- .../event_analytics/explorer/explorer.tsx | 130 +++------- .../saved_object_loaders/loader_base.ts | 11 + .../saved_object_loaders/loader_interface.ts | 8 + .../saved_object_loaders/ppl/index.ts | 4 + .../saved_object_loaders/ppl/ppl_loader.ts | 224 ++++++++++++++++++ 5 files changed, 278 insertions(+), 99 deletions(-) create mode 100644 public/services/saved_objects/saved_object_loaders/loader_base.ts create mode 100644 public/services/saved_objects/saved_object_loaders/loader_interface.ts create mode 100644 public/services/saved_objects/saved_object_loaders/ppl/index.ts create mode 100644 public/services/saved_objects/saved_object_loaders/ppl/ppl_loader.ts diff --git a/public/components/event_analytics/explorer/explorer.tsx b/public/components/event_analytics/explorer/explorer.tsx index 7f38f450aa..070060f83d 100644 --- a/public/components/event_analytics/explorer/explorer.tsx +++ b/public/components/event_analytics/explorer/explorer.tsx @@ -20,7 +20,7 @@ import { } from '@elastic/eui'; import { FormattedMessage } from '@osd/i18n/react'; import classNames from 'classnames'; -import { has, isEmpty, isEqual, reduce } from 'lodash'; +import { isEmpty, isEqual, reduce } from 'lodash'; import React, { ReactElement, useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { batch, useDispatch, useSelector } from 'react-redux'; import { @@ -47,7 +47,6 @@ import { TAB_EVENT_ID, TAB_EVENT_TITLE, TIME_INTERVAL_OPTIONS, - TYPE_TAB_MAPPING, } from '../../../../common/constants/explorer'; import { LIVE_END_TIME, @@ -111,6 +110,7 @@ import { Sidebar } from './sidebar'; import { TimechartHeader } from './timechart_header'; import { ExplorerVisualizations } from './visualizations'; import { CountDistribution } from './visualizations/count_distribution'; +import { PPLSavedObjectLoader } from '../../../services/saved_objects/saved_object_loaders/ppl/ppl_loader'; export const Explorer = ({ pplService, @@ -251,102 +251,6 @@ export const Explorer = ({ }; }; - const getSavedDataById = async (objectId: string) => { - // load saved query/visualization if object id exists - await getSavedObjectsClient({ objectId, objectType: 'savedQuery' }) - .get({ objectId }) - .then(async (res) => { - const savedData = res.observabilityObjectList[0]; - const isSavedQuery = has(savedData, SAVED_QUERY); - const savedType = isSavedQuery ? SAVED_QUERY : SAVED_VISUALIZATION; - const objectData = isSavedQuery ? savedData.savedQuery : savedData.savedVisualization; - const isSavedVisualization = savedData.savedVisualization; - const currQuery = objectData?.query || ''; - - if (appLogEvents) { - if (objectData?.selected_date_range?.start && objectData?.selected_date_range?.end) { - setStartTime(objectData.selected_date_range.start); - setEndTime(objectData.selected_date_range.end); - } - } - - // update redux - batch(async () => { - await dispatch( - changeQuery({ - tabId, - query: { - [RAW_QUERY]: currQuery, - [SELECTED_TIMESTAMP]: objectData?.selected_timestamp?.name || 'timestamp', - [SAVED_OBJECT_ID]: objectId, - [SAVED_OBJECT_TYPE]: savedType, - [SELECTED_DATE_RANGE]: - objectData?.selected_date_range?.start && objectData?.selected_date_range?.end - ? [objectData.selected_date_range.start, objectData.selected_date_range.end] - : ['now-15m', 'now'], - }, - }) - ); - await dispatch( - updateFields({ - tabId, - data: { - [SELECTED_FIELDS]: [...objectData?.selected_fields?.tokens], - }, - }) - ); - await dispatch( - updateTabName({ - tabId, - tabName: objectData.name, - }) - ); - // fill saved user configs - if (objectData?.type) { - let visConfig = {}; - const customConfig = objectData.user_configs ? JSON.parse(objectData.user_configs) : {}; - if (!isEmpty(customConfig.dataConfig) && !isEmpty(customConfig.dataConfig?.series)) { - visConfig = { ...customConfig }; - } else { - const statsTokens = queryManager.queryParser().parse(objectData.query).getStats(); - visConfig = { dataConfig: { ...getDefaultVisConfig(statsTokens) } }; - } - await dispatch( - updateVizConfig({ - tabId, - vizId: objectData?.type, - data: visConfig, - }) - ); - } - }); - - // update UI state with saved data - setSelectedPanelName(objectData?.name || ''); - setCurVisId(objectData?.type || 'bar'); - setTempQuery((staleTempQuery: string) => { - return objectData?.query || staleTempQuery; - }); - if (isSavedVisualization?.sub_type) { - if (isSavedVisualization?.sub_type === 'metric') { - setMetricChecked(true); - setMetricMeasure(isSavedVisualization?.units_of_measure); - } - setSubType(isSavedVisualization?.sub_type); - } - const tabToBeFocused = isSavedQuery - ? TYPE_TAB_MAPPING[SAVED_QUERY] - : TYPE_TAB_MAPPING[SAVED_VISUALIZATION]; - setSelectedContentTab(tabToBeFocused); - await fetchData(); - }) - .catch((error) => { - notifications.toasts.addError(error, { - title: `Cannot get saved data for object id: ${objectId}`, - }); - }); - }; - const getDefaultTimestampByIndexPattern = async ( indexPattern: string ): Promise => await timestampUtils.getTimestamp(indexPattern); @@ -469,7 +373,35 @@ export const Explorer = ({ !isEqual(getIndexPatternFromRawQuery(currentQuery), getIndexPatternFromRawQuery(prevTabQuery)); const updateTabData = async (objectId: string) => { - await getSavedDataById(objectId); + await new PPLSavedObjectLoader( + await getSavedObjectsClient({ objectId, objectType: 'savedQuery' }), + notifications, + { + batch, + dispatch, + changeQuery, + updateFields, + updateTabName, + updateVizConfig, + }, + { objectId }, + { + tabId, + appLogEvents, + setStartTime, + setEndTime, + queryManager, + getDefaultVisConfig, + setSelectedPanelName, + setCurVisId, + setTempQuery, + setMetricChecked, + setMetricMeasure, + setSubType, + setSelectedContentTab, + fetchData, + } + ).load(); }; const prepareAvailability = async () => { diff --git a/public/services/saved_objects/saved_object_loaders/loader_base.ts b/public/services/saved_objects/saved_object_loaders/loader_base.ts new file mode 100644 index 0000000000..a3c221c534 --- /dev/null +++ b/public/services/saved_objects/saved_object_loaders/loader_base.ts @@ -0,0 +1,11 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { ISavedObjectLoader } from './loader_interface'; + +export abstract class SavedObjectLoaderBase implements ISavedObjectLoader { + constructor() {} + abstract load(): void; +} diff --git a/public/services/saved_objects/saved_object_loaders/loader_interface.ts b/public/services/saved_objects/saved_object_loaders/loader_interface.ts new file mode 100644 index 0000000000..93dfc613b5 --- /dev/null +++ b/public/services/saved_objects/saved_object_loaders/loader_interface.ts @@ -0,0 +1,8 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +export interface ISavedObjectLoader { + load: () => void; +} diff --git a/public/services/saved_objects/saved_object_loaders/ppl/index.ts b/public/services/saved_objects/saved_object_loaders/ppl/index.ts new file mode 100644 index 0000000000..a850c1690e --- /dev/null +++ b/public/services/saved_objects/saved_object_loaders/ppl/index.ts @@ -0,0 +1,4 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ diff --git a/public/services/saved_objects/saved_object_loaders/ppl/ppl_loader.ts b/public/services/saved_objects/saved_object_loaders/ppl/ppl_loader.ts new file mode 100644 index 0000000000..29b0df90b3 --- /dev/null +++ b/public/services/saved_objects/saved_object_loaders/ppl/ppl_loader.ts @@ -0,0 +1,224 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { has, isEmpty } from 'lodash'; +import { batch as Batch } from 'react-redux'; +import { changeQuery as changeQueryAction } from 'public/components/event_analytics/redux/slices/query_slice'; +import { updateFields as updateFieldsAction } from 'public/components/event_analytics/redux/slices/field_slice'; +import { updateTabName as updateTabNameAction } from 'public/components/event_analytics/redux/slices/query_tab_slice'; +import { change as updateVizConfigAction } from 'public/components/event_analytics/redux/slices/viualization_config_slice'; +import { ISavedObjectsClient } from '../../saved_object_client/client_interface'; +import { SavedObjectLoaderBase } from '../loader_base'; +import { ISavedObjectLoader } from '../loader_interface'; +import { + GROUPBY, + RAW_QUERY, + SAVED_OBJECT_ID, + SAVED_OBJECT_TYPE, + SAVED_QUERY, + SAVED_VISUALIZATION, + SELECTED_DATE_RANGE, + SELECTED_FIELDS, + SELECTED_TIMESTAMP, + TYPE_TAB_MAPPING, + AGGREGATIONS, + BREAKDOWNS, +} from '../../../../../common/constants/explorer'; +import { NotificationsStart } from '../../../../../../../src/core/public'; +import { QueryManager } from '../../../../../common/query_manager'; +import { statsChunk } from '../../../../../common/query_manager/ast/types/stats'; +import { IField } from '../../../../../common/types/explorer'; +import { AppDispatch } from '../../../../framework/redux/store'; +import { SavedObjectsGetResponse } from '../../saved_object_client/types'; + +interface LoadParams { + objectId: string; +} + +interface LoadContext { + tabId: string; + appLogEvents: boolean; + setStartTime: (startTime: string) => void; + setEndTime: (endTime: string) => void; + queryManager: QueryManager; + getDefaultVisConfig: ( + statsToken: statsChunk + ) => { [AGGREGATIONS]: IField[]; [GROUPBY]: IField[]; [BREAKDOWNS]?: IField[]; span?: any }; + setSelectedPanelName: (savedObjectName: string) => void; + setCurVisId: (visId: string) => void; + setTempQuery: (tmpQuery: string) => void; + setMetricChecked: (metricChecked: boolean) => void; + setMetricMeasure: (metricMeasure: string) => void; + setSubType: (type: string) => void; + setSelectedContentTab: (curTab: string) => void; + fetchData: () => void; +} + +interface Dispatchers { + batch: typeof Batch; + dispatch: AppDispatch; + changeQuery: typeof changeQueryAction; + updateFields: typeof updateFieldsAction; + updateTabName: typeof updateTabNameAction; + updateVizConfig: typeof updateVizConfigAction; +} + +type SavedObjectData = SavedObjectsGetResponse; + +export class PPLSavedObjectLoader extends SavedObjectLoaderBase implements ISavedObjectLoader { + constructor( + protected readonly savedObjectClient: ISavedObjectsClient, + protected readonly notifications: NotificationsStart, + protected readonly dispatchers: Dispatchers, + protected readonly loadParams: LoadParams, + protected readonly loadContext: LoadContext + ) { + super(); + } + + async load() { + await this.getSavedObjectById(this.loadParams.objectId); + } + + async getSavedObjectById(objectId: string) { + try { + const res = await this.savedObjectClient.get({ + objectId, + }); + await this.processSavedData(res.observabilityObjectList[0]); + } catch (error) { + this.notifications.toasts.addError(error, { + title: `Cannot get saved data for object id: ${objectId}`, + }); + } + } + + updateAppAnalyticSelectedDateRange(selectedDateRange: { start: string; end: string }) { + const { setStartTime, setEndTime } = this.loadContext; + setStartTime(selectedDateRange.start); + setEndTime(selectedDateRange.end); + } + + async processSavedData(savedObjectData: SavedObjectData) { + const isSavedQuery = has(savedObjectData, SAVED_QUERY); + const savedType = isSavedQuery ? SAVED_QUERY : SAVED_VISUALIZATION; + const objectData = isSavedQuery + ? savedObjectData.savedQuery + : savedObjectData.savedVisualization; + const currQuery = objectData?.query || ''; + const { appLogEvents } = this.loadContext; + + // app analytics specific + if (appLogEvents && savedObjectData.selected_date_range) { + this.updateAppAnalyticSelectedDateRange(savedObjectData.selected_date_range); + } + + // update redux store with this saved object data + await this.updateReduxState(savedType, objectData, currQuery); + + // update UI state with this saved object data + await this.updateUIState(savedObjectData); + + // fetch data based on saved object data + await this.loadDataFromSavedObject(); + } + + async updateReduxState(savedType: string, objectData: SavedObjectData, currQuery: string) { + const { batch, dispatch, changeQuery, updateFields, updateTabName } = this.dispatchers; + const { tabId } = this.loadContext; + const { objectId } = this.loadParams; + batch(async () => { + await dispatch( + changeQuery({ + tabId, + query: { + [RAW_QUERY]: currQuery, + [SELECTED_TIMESTAMP]: objectData?.selected_timestamp?.name || 'timestamp', + [SAVED_OBJECT_ID]: objectId, + [SAVED_OBJECT_TYPE]: savedType, + [SELECTED_DATE_RANGE]: + objectData?.selected_date_range?.start && objectData?.selected_date_range?.end + ? [objectData.selected_date_range.start, objectData.selected_date_range.end] + : ['now-15m', 'now'], + }, + }) + ); + await dispatch( + updateFields({ + tabId, + data: { + [SELECTED_FIELDS]: [...objectData?.selected_fields?.tokens], + }, + }) + ); + await dispatch( + updateTabName({ + tabId, + tabName: objectData.name, + }) + ); + await this.updateVisualizationConfig(objectData); + }); + } + + async updateVisualizationConfig(objectData: SavedObjectData) { + const { dispatch, updateVizConfig } = this.dispatchers; + const { tabId, queryManager, getDefaultVisConfig } = this.loadContext; + // fill saved user configs + if (objectData.type) { + let visConfig = {}; + const customConfig = objectData.user_configs ? JSON.parse(objectData.user_configs) : {}; + if (!isEmpty(customConfig.dataConfig) && !isEmpty(customConfig.dataConfig?.series)) { + visConfig = { ...customConfig }; + } else { + const statsTokens = queryManager.queryParser().parse(objectData.query).getStats(); + visConfig = { dataConfig: { ...getDefaultVisConfig(statsTokens) } }; + } + await dispatch( + updateVizConfig({ + tabId, + vizId: objectData?.type, + data: visConfig, + }) + ); + } + } + + async updateUIState(objectData: SavedObjectData) { + const { + setSelectedPanelName, + setCurVisId, + setTempQuery, + setMetricChecked, + setMetricMeasure, + setSubType, + setSelectedContentTab, + } = this.loadContext; + const isSavedQuery = has(objectData, SAVED_QUERY); + const savedVisualization = objectData.savedVisualization; + // update UI state with saved data + setSelectedPanelName(objectData?.name || ''); + setCurVisId(objectData?.type || 'bar'); + setTempQuery((staleTempQuery) => { + return objectData?.query || staleTempQuery; + }); + if (savedVisualization?.sub_type) { + if (savedVisualization?.sub_type === 'metric') { + setMetricChecked(true); + setMetricMeasure(savedVisualization?.units_of_measure); + } + setSubType(savedVisualization?.sub_type); + } + const tabToBeFocused = isSavedQuery + ? TYPE_TAB_MAPPING[SAVED_QUERY] + : TYPE_TAB_MAPPING[SAVED_VISUALIZATION]; + setSelectedContentTab(tabToBeFocused); + } + + async loadDataFromSavedObject() { + const { fetchData } = this.loadContext; + await fetchData(); + } +} From 5f0b804aa66c98628df2b96f1ee2c91c92460e0a Mon Sep 17 00:00:00 2001 From: Joshua Li Date: Fri, 31 Mar 2023 20:58:13 +0000 Subject: [PATCH 34/73] Fix type in loader and remove redundent await Signed-off-by: Joshua Li --- public/components/event_analytics/explorer/explorer.tsx | 2 +- .../saved_objects/saved_object_loaders/ppl/ppl_loader.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/public/components/event_analytics/explorer/explorer.tsx b/public/components/event_analytics/explorer/explorer.tsx index 070060f83d..2015f77527 100644 --- a/public/components/event_analytics/explorer/explorer.tsx +++ b/public/components/event_analytics/explorer/explorer.tsx @@ -374,7 +374,7 @@ export const Explorer = ({ const updateTabData = async (objectId: string) => { await new PPLSavedObjectLoader( - await getSavedObjectsClient({ objectId, objectType: 'savedQuery' }), + getSavedObjectsClient({ objectId, objectType: 'savedQuery' }), notifications, { batch, diff --git a/public/services/saved_objects/saved_object_loaders/ppl/ppl_loader.ts b/public/services/saved_objects/saved_object_loaders/ppl/ppl_loader.ts index 29b0df90b3..909c347a58 100644 --- a/public/services/saved_objects/saved_object_loaders/ppl/ppl_loader.ts +++ b/public/services/saved_objects/saved_object_loaders/ppl/ppl_loader.ts @@ -31,7 +31,7 @@ import { QueryManager } from '../../../../../common/query_manager'; import { statsChunk } from '../../../../../common/query_manager/ast/types/stats'; import { IField } from '../../../../../common/types/explorer'; import { AppDispatch } from '../../../../framework/redux/store'; -import { SavedObjectsGetResponse } from '../../saved_object_client/types'; +import { ObservabilitySavedObject } from '../../saved_object_client/types'; interface LoadParams { objectId: string; @@ -65,7 +65,7 @@ interface Dispatchers { updateVizConfig: typeof updateVizConfigAction; } -type SavedObjectData = SavedObjectsGetResponse; +type SavedObjectData = ObservabilitySavedObject; export class PPLSavedObjectLoader extends SavedObjectLoaderBase implements ISavedObjectLoader { constructor( From 4d8ba6faf50d1c9eddbf5bf0699d7bc95cf0a680 Mon Sep 17 00:00:00 2001 From: Joshua Li Date: Fri, 31 Mar 2023 22:38:16 +0000 Subject: [PATCH 35/73] Refactor to use saved object client factory and actions in explorer Signed-off-by: Joshua Li --- .../observability_saved_object_attributes.ts | 1 + .../components/event_analytics/home/home.tsx | 24 +--- .../observability_embeddable_factory.tsx | 2 +- .../event_analytics/saved_objects.ts | 2 +- .../saved_object_client/client_factory.ts | 47 +++---- .../osd_saved_object_client.ts | 66 ++++++---- .../osd_saved_objects/saved_visualization.ts | 76 +++++++---- .../osd_saved_objects/types.ts | 3 + .../saved_object_client/ppl/ppl_client.ts | 34 ++++- .../saved_object_client/ppl/saved_query.ts | 10 ++ .../ppl/saved_visualization.ts | 10 ++ .../saved_objects_actions.ts | 119 ++++++++++++++++++ .../saved_object_client/types.ts | 12 ++ 13 files changed, 299 insertions(+), 107 deletions(-) create mode 100644 public/services/saved_objects/saved_object_client/saved_objects_actions.ts diff --git a/common/types/observability_saved_object_attributes.ts b/common/types/observability_saved_object_attributes.ts index 293a2d5fb6..829184d1c2 100644 --- a/common/types/observability_saved_object_attributes.ts +++ b/common/types/observability_saved_object_attributes.ts @@ -7,6 +7,7 @@ import { SavedObjectAttributes } from '../../../../src/core/types'; import { SavedVisualization } from './explorer'; export const VISUALIZATION_SAVED_OBJECT = 'observability-visualization'; +export const OBSERVABILTY_SAVED_OBJECTS = [VISUALIZATION_SAVED_OBJECT] as const; export const SAVED_OBJECT_VERSION = 1; export interface VisualizationSavedObjectAttributes extends SavedObjectAttributes { diff --git a/public/components/event_analytics/home/home.tsx b/public/components/event_analytics/home/home.tsx index 15281bce25..69df9f9441 100644 --- a/public/components/event_analytics/home/home.tsx +++ b/public/components/event_analytics/home/home.tsx @@ -52,6 +52,8 @@ import { import { getOSDSavedObjectsClient } from '../../../../common/utils'; import SavedObjects from '../../../services/saved_objects/event_analytics/saved_objects'; import { OSDSavedVisualizationClient } from '../../../services/saved_objects/saved_object_client/osd_saved_objects/saved_visualization'; +import { PPLSavedQueryClient } from '../../../services/saved_objects/saved_object_client/ppl'; +import { SavedObjectsActions } from '../../../services/saved_objects/saved_object_client/saved_objects_actions'; import { ObservabilitySavedObject } from '../../../services/saved_objects/saved_object_client/types'; import { getSampleDataModal } from '../../common/helpers/add_sample_modal'; import { DeleteModal } from '../../common/helpers/delete_modal'; @@ -115,18 +117,11 @@ const EventAnalyticsHome = (props: IHomeProps) => { }; const fetchHistories = async () => { - const observabilityObjects = await savedObjects.fetchSavedObjects({ + const observabilityObjects = await SavedObjectsActions.getBulk({ objectType: ['savedQuery', 'savedVisualization'], sortOrder: 'desc', fromIndex: 0, }); - const osdObjects = await new OSDSavedVisualizationClient(getOSDSavedObjectsClient()).getBulk( - {} - ); - observabilityObjects.observabilityObjectList = [ - ...osdObjects.observabilityObjectList, - ...observabilityObjects.observabilityObjectList, - ]; const nonAppObjects = observabilityObjects.observabilityObjectList.filter( (object: ObservabilitySavedObject) => (object.savedVisualization && !object.savedVisualization.application_id) || @@ -137,13 +132,7 @@ const EventAnalyticsHome = (props: IHomeProps) => { const deleteHistoryList = async () => { const objectIdsToDelete = selectedHistories.map((hstry) => hstry.data.objectId); - await savedObjects - .deleteSavedObjectsList({ objectIdList: objectIdsToDelete }) - .catch(() => - new OSDSavedVisualizationClient(getOSDSavedObjectsClient()).deleteBulk({ - objectIdList: objectIdsToDelete, - }) - ) + await SavedObjectsActions.deleteBulk({ objectIdList: objectIdsToDelete }) .then(async () => { setSavedHistories((staleHistories) => { return staleHistories.filter((his) => { @@ -285,11 +274,10 @@ const EventAnalyticsHome = (props: IHomeProps) => { }), }); - // wait for flush + // wait for sample data to flush to index await new Promise((resolve) => setTimeout(resolve, 1000)); - const res = await savedObjects.fetchSavedObjects({ - // objectIdList: [...resp?.savedVizIds, ...resp?.savedQueryIds] || [], + const res = await SavedObjectsActions.getBulk({ objectType: ['savedQuery', 'savedVisualization'], sortOrder: 'desc', fromIndex: 0, diff --git a/public/embeddable/observability_embeddable_factory.tsx b/public/embeddable/observability_embeddable_factory.tsx index 81c5857a62..f5cbdf8c78 100644 --- a/public/embeddable/observability_embeddable_factory.tsx +++ b/public/embeddable/observability_embeddable_factory.tsx @@ -62,7 +62,7 @@ export class ObservabilityEmbeddableFactoryDefinition input: SavedObjectEmbeddableInput, parent?: IContainer ) { - const editPath = `#/event_analytics/explorer/${savedObjectId}`; + const editPath = `#/event_analytics/explorer/${VISUALIZATION_SAVED_OBJECT}:${savedObjectId}`; const editUrl = `/app/${observabilityID}${editPath}`; return new ObservabilityEmbeddable( { diff --git a/public/services/saved_objects/event_analytics/saved_objects.ts b/public/services/saved_objects/event_analytics/saved_objects.ts index d1dd343959..1741723f31 100644 --- a/public/services/saved_objects/event_analytics/saved_objects.ts +++ b/public/services/saved_objects/event_analytics/saved_objects.ts @@ -16,7 +16,7 @@ import { CUSTOM_PANELS_API_PREFIX } from '../../../../common/constants/custom_pa const CONCAT_FIELDS = ['objectIdList', 'objectType']; -interface ISavedObjectRequestParams { +export interface ISavedObjectRequestParams { objectId?: string; objectIdList?: string[] | string; objectType?: string[] | string; diff --git a/public/services/saved_objects/saved_object_client/client_factory.ts b/public/services/saved_objects/saved_object_client/client_factory.ts index fc1cb8012b..4af366a83e 100644 --- a/public/services/saved_objects/saved_object_client/client_factory.ts +++ b/public/services/saved_objects/saved_object_client/client_factory.ts @@ -3,54 +3,35 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { getOSDHttp, getOSDSavedObjectsClient } from '../../../../common/utils'; +import { VISUALIZATION_SAVED_OBJECT } from '../../../../common/types/observability_saved_object_attributes'; import { ISavedObjectsClient } from './client_interface'; +import { OSDSavedObjectClient } from './osd_saved_objects/osd_saved_object_client'; import { OSDSavedVisualizationClient } from './osd_saved_objects/saved_visualization'; import { PPLSavedQueryClient, PPLSavedVisualizationClient } from './ppl'; -type SavedObjectsClientType = 'osd' | 'ppl'; -type SavedObjectsType = 'savedQuery' | 'savedVisualization'; - interface GetSavedObjectsClientOptions { objectId: string; - objectType: SavedObjectsType; + objectType?: string; // only required for non OSD saved objects } -const UUID_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-5][0-9a-f]{3}-[089ab][0-9a-f]{3}-[0-9a-f]{12}$/i; - -const getTypeById = (objectId: string): SavedObjectsClientType => { - if (UUID_REGEX.test(objectId)) { - return 'osd'; - } - return 'ppl'; -}; - -let osdSavedVisualizationClient: OSDSavedVisualizationClient; -let pplSavedQueryClient: PPLSavedQueryClient; -let pplSavedVisualizationClient: PPLSavedVisualizationClient; - export const getSavedObjectsClient = ( options: GetSavedObjectsClientOptions ): ISavedObjectsClient => { - const clientType = getTypeById(options.objectId); + const type = OSDSavedObjectClient.extractType(options.objectId); + + switch (type) { + case VISUALIZATION_SAVED_OBJECT: + return OSDSavedVisualizationClient.getInstance(); - if (clientType === 'osd') { - if (osdSavedVisualizationClient === undefined) { - osdSavedVisualizationClient = new OSDSavedVisualizationClient(getOSDSavedObjectsClient()); - } - return osdSavedVisualizationClient; + default: + break; } switch (options.objectType) { - case 'savedQuery': - if (pplSavedQueryClient === undefined) { - pplSavedQueryClient = new PPLSavedQueryClient(getOSDHttp()); - } - return pplSavedQueryClient; + case 'savedVisualization': + return PPLSavedVisualizationClient.getInstance(); + default: - if (pplSavedVisualizationClient === undefined) { - pplSavedVisualizationClient = new PPLSavedVisualizationClient(getOSDHttp()); - } - return pplSavedVisualizationClient; + return PPLSavedQueryClient.getInstance(); } }; diff --git a/public/services/saved_objects/saved_object_client/osd_saved_objects/osd_saved_object_client.ts b/public/services/saved_objects/saved_object_client/osd_saved_objects/osd_saved_object_client.ts index 1be96a1e47..f0d0baa047 100644 --- a/public/services/saved_objects/saved_object_client/osd_saved_objects/osd_saved_object_client.ts +++ b/public/services/saved_objects/saved_object_client/osd_saved_objects/osd_saved_object_client.ts @@ -8,37 +8,59 @@ import { SavedObjectsClientContract, SimpleSavedObject, } from '../../../../../../../src/core/public'; +import { OBSERVABILTY_SAVED_OBJECTS } from '../../../../../common/types/observability_saved_object_attributes'; import { SavedObjectClientBase } from '../client_base'; -import { SavedObjectsGetResponse, SavedObjectsCreateResponse } from '../types'; +import { ObservabilitySavedObjectsType } from './types'; + +export abstract class OSDSavedObjectClient extends SavedObjectClientBase { + private static TYPE_ID_REGEX = new RegExp( + `(${OBSERVABILTY_SAVED_OBJECTS.join( + '|' + )}):([0-9a-f]{8}-[0-9a-f]{4}-[0-5][0-9a-f]{3}-[089ab][0-9a-f]{3}-[0-9a-f]{12}$)` + ); -export class OSDSavedObjectClient extends SavedObjectClientBase { constructor(protected readonly client: SavedObjectsClientContract) { super(); } - create(params: unknown): Promise { - throw new Error('Method not implemented.'); - } - get(params: unknown): Promise { - throw new Error('Method not implemented.'); - } - getBulk(params: unknown): Promise { - throw new Error('Method not implemented.'); - } - update(params: unknown): Promise { - throw new Error('Method not implemented.'); - } - updateBulk(params: unknown): Promise>> { - throw new Error('Method not implemented.'); - } - delete(params: unknown): Promise { - throw new Error('Method not implemented.'); + + /** + * OSD saved object client operations requires object type. Type is part of + * the document id but not in operation response id (see + * https://github.com/opensearch-project/opensearch-dashboards/blob/11b98ec05483269917c335fcb1900bf98da8cac6/src/core/server/saved_objects/serialization/serializer.ts#L141). + * In Observability most components only uses id without explicit type. Prepend + * type to id to make it easier to call OSD saved object client. + * + * @param objectId - objectId in the format of id only + * @returns id in the format of 'SavedObjectType:id' + */ + protected abstract prependTypeToId(objectId: string): string; + + protected static extractTypeAndUUID( + objectId: string + ): { + type: '' | ObservabilitySavedObjectsType; + uuid: string; + } { + const matches = objectId.match(OSDSavedObjectClient.TYPE_ID_REGEX); + if (matches === null) { + return { type: '', uuid: objectId }; + } + return { type: matches[1] as ObservabilitySavedObjectsType, uuid: matches[2] }; } - deleteBulk(params: unknown): Promise { - throw new Error('Method not implemented.'); + + /** + * @param objectId - objectId in the format of 'SavedObjectType:UUID' + * @returns ObservabilitySavedObjectsType or empty string if objectId + * is not in expected format. + */ + public static extractType(objectId: string) { + return this.extractTypeAndUUID(objectId).type; } - convertToLastUpdatedMs(updatedAt: SimpleSavedObject['updated_at']) { + + protected static convertToLastUpdatedMs(updatedAt: SimpleSavedObject['updated_at']) { return (updatedAt ? new Date(updatedAt) : new Date()).getTime(); } + buildRequestBody({ query, fields, diff --git a/public/services/saved_objects/saved_object_client/osd_saved_objects/saved_visualization.ts b/public/services/saved_objects/saved_object_client/osd_saved_objects/saved_visualization.ts index d07ef8cffe..9949a36cec 100644 --- a/public/services/saved_objects/saved_object_client/osd_saved_objects/saved_visualization.ts +++ b/public/services/saved_objects/saved_object_client/osd_saved_objects/saved_visualization.ts @@ -10,7 +10,14 @@ import { VisualizationSavedObjectAttributes, VISUALIZATION_SAVED_OBJECT, } from '../../../../../common/types/observability_saved_object_attributes'; -import { SavedObjectsDeleteResponse, SavedObjectsGetResponse } from '../types'; +import { getOSDSavedObjectsClient } from '../../../../../common/utils'; +import { + SavedObjectsDeleteBulkParams, + SavedObjectsDeleteParams, + SavedObjectsDeleteResponse, + SavedObjectsGetParams, + SavedObjectsGetResponse, +} from '../types'; import { OSDSavedObjectClient } from './osd_saved_object_client'; import { OSDSavedObjectCreateResponse, OSDSavedObjectUpdateResponse } from './types'; @@ -32,11 +39,13 @@ interface CommonParams { type CreateParams = CommonParams & { applicationId: string }; type UpdateParams = Partial & { objectId: string }; -interface GetParams { - objectId: string; -} - export class OSDSavedVisualizationClient extends OSDSavedObjectClient { + private static instance: OSDSavedVisualizationClient; + + protected prependTypeToId(objectId: string) { + return `${VISUALIZATION_SAVED_OBJECT}:${objectId}`; + } + async create( params: CreateParams ): Promise> { @@ -69,7 +78,7 @@ export class OSDSavedVisualizationClient extends OSDSavedObjectClient { ); return { - objectId: response.id, + objectId: this.prependTypeToId(response.id), object: response, }; } @@ -94,7 +103,7 @@ export class OSDSavedVisualizationClient extends OSDSavedObjectClient { const response = await this.client.update>( VISUALIZATION_SAVED_OBJECT, - params.objectId, + OSDSavedObjectClient.extractTypeAndUUID(params.objectId).uuid, { title: params.name, description: params.description, @@ -104,29 +113,33 @@ export class OSDSavedVisualizationClient extends OSDSavedObjectClient { ); return { - objectId: response.id, + objectId: this.prependTypeToId(response.id), object: response, }; } - async get(params: GetParams): Promise { + updateBulk(params: unknown): Promise>> { + throw new Error('Method not implemented.'); + } + + async get(params: SavedObjectsGetParams): Promise { const response = await this.client.get( VISUALIZATION_SAVED_OBJECT, - params.objectId + OSDSavedObjectClient.extractTypeAndUUID(params.objectId).uuid ); return { observabilityObjectList: [ { - objectId: response.id, + objectId: this.prependTypeToId(response.id), createdTimeMs: response.attributes.createdTimeMs, - lastUpdatedTimeMs: this.convertToLastUpdatedMs(response.updated_at), + lastUpdatedTimeMs: OSDSavedObjectClient.convertToLastUpdatedMs(response.updated_at), savedVisualization: response.attributes.savedVisualization, }, ], }; } - async getBulk(params: Partial): Promise { + async getBulk(params: Partial = {}): Promise { const observabilityObjectList = await this.client .find({ ...params, @@ -134,31 +147,42 @@ export class OSDSavedVisualizationClient extends OSDSavedObjectClient { }) .then((findRes) => findRes.savedObjects.map((o) => ({ - objectId: o.id, + objectId: this.prependTypeToId(o.id), createdTimeMs: o.attributes.createdTimeMs, - lastUpdatedTimeMs: this.convertToLastUpdatedMs(o.updated_at), + lastUpdatedTimeMs: OSDSavedObjectClient.convertToLastUpdatedMs(o.updated_at), savedVisualization: o.attributes.savedVisualization, })) ); return { observabilityObjectList }; } - async delete(params: { objectId: string }): Promise { + async delete(params: SavedObjectsDeleteParams): Promise { + const uuid = OSDSavedObjectClient.extractTypeAndUUID(params.objectId).uuid; return this.client - .delete(VISUALIZATION_SAVED_OBJECT, params.objectId) - .then((res) => ({ deleteResponseList: { [params.objectId]: 'OK' } })) + .delete(VISUALIZATION_SAVED_OBJECT, uuid) + .then(() => ({ deleteResponseList: { [params.objectId]: 'OK' } })) .catch((res) => ({ deleteResponseList: { [params.objectId]: res } })); } - async deleteBulk(params: { objectIdList: string[] }): Promise { + async deleteBulk(params: SavedObjectsDeleteBulkParams): Promise { const deleteResponseList: SavedObjectsDeleteResponse['deleteResponseList'] = {}; - const x = await Promise.allSettled( - params.objectIdList.map((objectId) => this.delete({ objectId })) - ).then((res) => { - res.map((r, i) => { - deleteResponseList[params.objectIdList[i]] = r.status === 'fulfilled' ? r.value : r.reason; - }); - }); + await Promise.allSettled(params.objectIdList.map((objectId) => this.delete({ objectId }))).then( + (res) => { + res.forEach((r, i) => { + deleteResponseList[params.objectIdList[i]] = + r.status === 'fulfilled' + ? r.value.deleteResponseList[params.objectIdList[i]] + : r.reason; + }); + } + ); return { deleteResponseList }; } + + static getInstance() { + if (!this.instance) { + this.instance = new this(getOSDSavedObjectsClient()); + } + return this.instance; + } } diff --git a/public/services/saved_objects/saved_object_client/osd_saved_objects/types.ts b/public/services/saved_objects/saved_object_client/osd_saved_objects/types.ts index 4764681c41..3e60d19dbd 100644 --- a/public/services/saved_objects/saved_object_client/osd_saved_objects/types.ts +++ b/public/services/saved_objects/saved_object_client/osd_saved_objects/types.ts @@ -4,8 +4,11 @@ */ import { SavedObjectAttributes, SimpleSavedObject } from '../../../../../../../src/core/public'; +import { OBSERVABILTY_SAVED_OBJECTS } from '../../../../../common/types/observability_saved_object_attributes'; import { SavedObjectsCreateResponse } from '../types'; +export type ObservabilitySavedObjectsType = typeof OBSERVABILTY_SAVED_OBJECTS[number]; + export interface OSDSavedObjectCreateResponse extends SavedObjectsCreateResponse { object: SimpleSavedObject; diff --git a/public/services/saved_objects/saved_object_client/ppl/ppl_client.ts b/public/services/saved_objects/saved_object_client/ppl/ppl_client.ts index 5728a2b48d..3416def295 100644 --- a/public/services/saved_objects/saved_object_client/ppl/ppl_client.ts +++ b/public/services/saved_objects/saved_object_client/ppl/ppl_client.ts @@ -3,15 +3,24 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { isEmpty } from 'lodash'; +import { has, isArray, isEmpty } from 'lodash'; import { HttpStart } from '../../../../../../../src/core/public'; import { EVENT_ANALYTICS, OBSERVABILITY_BASE, SAVED_OBJECTS, } from '../../../../../common/constants/shared'; +import { ISavedObjectRequestParams } from '../../event_analytics/saved_objects'; import { SavedObjectClientBase } from '../client_base'; import { ISavedObjectsClient } from '../client_interface'; +import { + SavedObjectsDeleteBulkParams, + SavedObjectsDeleteParams, + SavedObjectsDeleteResponse, + SavedObjectsGetResponse, +} from '../types'; + +const CONCAT_FIELDS = ['objectIdList', 'objectType']; export class PPLSavedObjectClient extends SavedObjectClientBase implements ISavedObjectsClient { constructor(protected readonly client: HttpStart) { @@ -20,14 +29,18 @@ export class PPLSavedObjectClient extends SavedObjectClientBase implements ISave create(params: any): Promise { throw new Error('Method not implemented.'); } - get(params: any): Promise { + get(params: ISavedObjectRequestParams): Promise { return this.client.get(`${OBSERVABILITY_BASE}${EVENT_ANALYTICS}${SAVED_OBJECTS}`, { query: { ...params, }, }); } - getBulk(params: any): Promise { + getBulk(params: ISavedObjectRequestParams): Promise { + CONCAT_FIELDS.map((arrayField) => { + this.stringifyList(params, arrayField, ','); + }); + return this.client.get(`${OBSERVABILITY_BASE}${EVENT_ANALYTICS}${SAVED_OBJECTS}`, { query: { ...params, @@ -40,10 +53,12 @@ export class PPLSavedObjectClient extends SavedObjectClientBase implements ISave updateBulk(params: any): Promise>> { throw new Error('Method not implemented.'); } - delete(params: any): Promise { - throw new Error('Method not implemented.'); + delete(params: SavedObjectsDeleteParams): Promise { + return this.client.delete( + `${OBSERVABILITY_BASE}${EVENT_ANALYTICS}${SAVED_OBJECTS}/${params.objectId}` + ); } - deleteBulk(params: any): Promise>> { + deleteBulk(params: SavedObjectsDeleteBulkParams): Promise { return this.client.delete( `${OBSERVABILITY_BASE}${EVENT_ANALYTICS}${SAVED_OBJECTS}/${params.objectIdList.join(',')}` ); @@ -114,4 +129,11 @@ export class PPLSavedObjectClient extends SavedObjectClientBase implements ISave return objRequest; } + + private stringifyList(targetObj: any, key: string, joinBy: string) { + if (has(targetObj, key) && isArray(targetObj[key])) { + targetObj[key] = targetObj[key].join(joinBy); + } + return targetObj; + } } diff --git a/public/services/saved_objects/saved_object_client/ppl/saved_query.ts b/public/services/saved_objects/saved_object_client/ppl/saved_query.ts index e2d52b18c1..4b0f97c036 100644 --- a/public/services/saved_objects/saved_object_client/ppl/saved_query.ts +++ b/public/services/saved_objects/saved_object_client/ppl/saved_query.ts @@ -11,6 +11,7 @@ import { SAVED_OBJECTS, SAVED_QUERY, } from '../../../../../common/constants/shared'; +import { getOSDHttp } from '../../../../../common/utils'; interface CommonParams { query: string; @@ -26,6 +27,8 @@ type UpdateQueryParams = CommonParams & { }; export class PPLSavedQueryClient extends PPLSavedObjectClient { + private static instance: PPLSavedQueryClient; + async create(params: CreateQueryParams): Promise { return await this.client.post( `${OBSERVABILITY_BASE}${EVENT_ANALYTICS}${SAVED_OBJECTS}${SAVED_QUERY}`, @@ -60,4 +63,11 @@ export class PPLSavedQueryClient extends PPLSavedObjectClient { } ); } + + static getInstance() { + if (!this.instance) { + this.instance = new this(getOSDHttp()); + } + return this.instance; + } } diff --git a/public/services/saved_objects/saved_object_client/ppl/saved_visualization.ts b/public/services/saved_objects/saved_object_client/ppl/saved_visualization.ts index affba23034..5540412940 100644 --- a/public/services/saved_objects/saved_object_client/ppl/saved_visualization.ts +++ b/public/services/saved_objects/saved_object_client/ppl/saved_visualization.ts @@ -12,6 +12,7 @@ import { } from '../../../../../common/constants/shared'; import { PPLSavedObjectClient } from './ppl_client'; import { SavedObjectsCreateResponse, SavedObjectsUpdateResponse } from '../types'; +import { getOSDHttp } from '../../../../../common/utils'; interface CommonParams { query: string; @@ -32,6 +33,8 @@ type CreateParams = CommonParams & { applicationId: string }; type UpdateParams = CommonParams & { objectId: string }; export class PPLSavedVisualizationClient extends PPLSavedObjectClient { + private static instance: PPLSavedVisualizationClient; + async create(params: CreateParams): Promise { return await this.client.post( `${OBSERVABILITY_BASE}${EVENT_ANALYTICS}${SAVED_OBJECTS}${SAVED_VISUALIZATION}`, @@ -79,4 +82,11 @@ export class PPLSavedVisualizationClient extends PPLSavedObjectClient { } ); } + + static getInstance() { + if (!this.instance) { + this.instance = new this(getOSDHttp()); + } + return this.instance; + } } diff --git a/public/services/saved_objects/saved_object_client/saved_objects_actions.ts b/public/services/saved_objects/saved_object_client/saved_objects_actions.ts new file mode 100644 index 0000000000..262f31f1c6 --- /dev/null +++ b/public/services/saved_objects/saved_object_client/saved_objects_actions.ts @@ -0,0 +1,119 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { VISUALIZATION_SAVED_OBJECT } from '../../../../common/types/observability_saved_object_attributes'; +import { ISavedObjectRequestParams } from '../event_analytics/saved_objects'; +import { OSDSavedObjectClient } from './osd_saved_objects/osd_saved_object_client'; +import { OSDSavedVisualizationClient } from './osd_saved_objects/saved_visualization'; +import { ObservabilitySavedObjectsType } from './osd_saved_objects/types'; +import { PPLSavedQueryClient } from './ppl'; +import { + SavedObjectsDeleteBulkParams, + SavedObjectsDeleteParams, + SavedObjectsDeleteResponse, + SavedObjectsGetParams, + SavedObjectsGetResponse, +} from './types'; + +/** + * Helper class that dynamically determines which saved object client to use + * for get and delete operations. This servers as a compatibility layer before + * the .opensearch-observability index is deprecated. + */ +export class SavedObjectsActions { + static get(params: SavedObjectsGetParams): Promise { + const type = OSDSavedObjectClient.extractType(params.objectId); + switch (type) { + case VISUALIZATION_SAVED_OBJECT: + return OSDSavedVisualizationClient.getInstance().get(params); + + default: + // for non-osd objects it does not matter which client implementation + // is used for get() + return PPLSavedQueryClient.getInstance().get(params); + } + } + + static async getBulk(params: ISavedObjectRequestParams): Promise { + const objects = await PPLSavedQueryClient.getInstance().getBulk(params); + if (params.objectType?.includes('savedVisualization')) { + const osdVisualizationObjects = await OSDSavedVisualizationClient.getInstance().getBulk(); + if (objects.totalHits && osdVisualizationObjects.totalHits) { + objects.totalHits += osdVisualizationObjects.totalHits; + } + objects.observabilityObjectList = [ + ...objects.observabilityObjectList, + ...osdVisualizationObjects.observabilityObjectList, + ]; + } + + if (params.sortOrder === 'asc') { + objects.observabilityObjectList.sort((a, b) => a.lastUpdatedTimeMs - b.lastUpdatedTimeMs); + } else { + objects.observabilityObjectList.sort((a, b) => b.lastUpdatedTimeMs - a.lastUpdatedTimeMs); + } + return objects; + } + + static delete(params: SavedObjectsDeleteParams): Promise { + const type = OSDSavedObjectClient.extractType(params.objectId); + switch (type) { + case VISUALIZATION_SAVED_OBJECT: + return OSDSavedVisualizationClient.getInstance().delete(params); + + default: + return PPLSavedQueryClient.getInstance().delete(params); + } + } + + /** + * Delete a list of objects. Assumes object is osd visualization if id is a + * UUID. Rest and failed ids will then be deleted by PPL client. + * + * @param params - SavedObjectsDeleteBulkParams + * @returns SavedObjectsDeleteResponse + */ + static async deleteBulk( + params: SavedObjectsDeleteBulkParams + ): Promise { + const idMap = params.objectIdList.reduce((prev, id) => { + const type = OSDSavedObjectClient.extractType(id); + const key = type === '' ? 'non_osd' : type; + return { ...prev, [key]: [...(prev[key] || []), id] }; + }, {} as { [k in 'non_osd' | ObservabilitySavedObjectsType]: string[] }); + + const responses: SavedObjectsDeleteResponse = { deleteResponseList: {} }; + + if (idMap[VISUALIZATION_SAVED_OBJECT]?.length) { + const visualizationDeleteResponses = await OSDSavedVisualizationClient.getInstance().deleteBulk( + { objectIdList: idMap[VISUALIZATION_SAVED_OBJECT] } + ); + responses.deleteResponseList = { + ...responses.deleteResponseList, + ...visualizationDeleteResponses.deleteResponseList, + }; + } + + const remainingObjectIds = [ + ...new Set( + idMap.non_osd.concat( + Object.entries(responses.deleteResponseList) + .filter(([_, status]) => status !== 'OK') + .map(([id, _]) => id) + ) + ), + ]; + if (remainingObjectIds.length) { + const remainingDeleteResponses = await PPLSavedQueryClient.getInstance().deleteBulk({ + objectIdList: remainingObjectIds, + }); + responses.deleteResponseList = { + ...responses.deleteResponseList, + ...remainingDeleteResponses.deleteResponseList, + }; + } + return responses; + } +} diff --git a/public/services/saved_objects/saved_object_client/types.ts b/public/services/saved_objects/saved_object_client/types.ts index ff2e0ea491..1033270dca 100644 --- a/public/services/saved_objects/saved_object_client/types.ts +++ b/public/services/saved_objects/saved_object_client/types.ts @@ -20,6 +20,10 @@ export interface ObservabilitySavedObject { savedQuery?: SavedQuery; } +export interface SavedObjectsGetParams { + objectId: string; +} + export interface SavedObjectsGetResponse { startIndex?: number; totalHits?: number; @@ -27,6 +31,14 @@ export interface SavedObjectsGetResponse { observabilityObjectList: ObservabilitySavedObject[]; } +export interface SavedObjectsDeleteParams { + objectId: string; +} + +export interface SavedObjectsDeleteBulkParams { + objectIdList: string[]; +} + export interface SavedObjectsDeleteResponse { deleteResponseList: { [objectId: string]: string; // org.opensearch.rest.RestStatus, e.g. 'OK' From b3dccec36271f727b7dd439ac3c701a3c30b8754 Mon Sep 17 00:00:00 2001 From: Joshua Li Date: Fri, 31 Mar 2023 23:36:42 +0000 Subject: [PATCH 36/73] Replace saved object client instantiate with getInstance Signed-off-by: Joshua Li --- public/components/event_analytics/explorer/explorer.tsx | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/public/components/event_analytics/explorer/explorer.tsx b/public/components/event_analytics/explorer/explorer.tsx index 2015f77527..6b32331c5e 100644 --- a/public/components/event_analytics/explorer/explorer.tsx +++ b/public/components/event_analytics/explorer/explorer.tsx @@ -68,7 +68,6 @@ import { buildQuery, composeFinalQuery, getIndexPatternFromRawQuery, - getOSDSavedObjectsClient, uiSettingsService, } from '../../../../common/utils'; import { getSavedObjectsClient } from '../../../services/saved_objects/saved_object_client/client_factory'; @@ -834,7 +833,7 @@ export const Explorer = ({ soClient = new SaveAsCurrenQuery( { tabId, notifications }, { dispatch, updateTabName }, - new PPLSavedQueryClient(http), + PPLSavedQueryClient.getInstance(), { ...commonParams, objectId: query[SAVED_OBJECT_ID], @@ -878,7 +877,7 @@ export const Explorer = ({ addVisualizationToPanel, }, { batch, dispatch, changeQuery, updateTabName }, - new OSDSavedVisualizationClient(getOSDSavedObjectsClient()), + OSDSavedVisualizationClient.getInstance(), new PanelSavedObjectClient(http), { ...commonParams, From 6a24e75438143a0164bb90f01c27ca51f8151009 Mon Sep 17 00:00:00 2001 From: Joshua Li Date: Mon, 3 Apr 2023 20:35:23 +0000 Subject: [PATCH 37/73] Disable create new for observability visualizations in core Observability visualization is already an option in create panel in visualize, so no need to show another duplicated create button. The other option is to still show it but redirect to observability plugin. Signed-off-by: Joshua Li --- public/embeddable/observability_embeddable_factory.tsx | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/public/embeddable/observability_embeddable_factory.tsx b/public/embeddable/observability_embeddable_factory.tsx index f5cbdf8c78..9fca4d9c80 100644 --- a/public/embeddable/observability_embeddable_factory.tsx +++ b/public/embeddable/observability_embeddable_factory.tsx @@ -76,11 +76,12 @@ export class ObservabilityEmbeddableFactoryDefinition ); } + public canCreateNew() { + return false; + } + async create(initialInput: SavedObjectEmbeddableInput, parent?: IContainer) { - return new ErrorEmbeddable( - 'Saved searches can only be created from a saved object', - initialInput - ); + return undefined; } async isEditable() { From 947764f6fbc5580baf171d3cfef039bdb71265a6 Mon Sep 17 00:00:00 2001 From: Joshua Li Date: Mon, 3 Apr 2023 20:51:52 +0000 Subject: [PATCH 38/73] Use consistent display name and visualization title Signed-off-by: Joshua Li --- public/embeddable/observability_embeddable.tsx | 15 +++------------ .../observability_embeddable_factory.tsx | 7 +++---- 2 files changed, 6 insertions(+), 16 deletions(-) diff --git a/public/embeddable/observability_embeddable.tsx b/public/embeddable/observability_embeddable.tsx index bba27f0105..441c401f83 100644 --- a/public/embeddable/observability_embeddable.tsx +++ b/public/embeddable/observability_embeddable.tsx @@ -11,7 +11,6 @@ import { Embeddable, EmbeddableOutput, IContainer, - ReferenceOrValueEmbeddable, SavedObjectEmbeddableInput, } from '../../../../src/plugins/embeddable/public'; import { @@ -71,17 +70,8 @@ export class ObservabilityEmbeddable extends Embeddable< super(initialInput, { editable: true, ...config }, parent); this.subscription = this.getInput$().subscribe(async () => { - const savedObjectId = this.getInput().savedObjectId; - const attributes = (this.getInput() as ObservabilityByValueInput).attributes; - if (this.attributes !== attributes || this.savedObjectId !== savedObjectId) { - this.savedObjectId = savedObjectId; - this.reload(); - } else { - this.updateOutput({ - attributes: this.attributes, - title: this.input.title || this.attributes.title, - }); - } + this.savedObjectId = this.getInput().savedObjectId; + this.reload(); }); } @@ -99,6 +89,7 @@ export class ObservabilityEmbeddable extends Embeddable< this.updateOutput({ attributes: this.attributes, title: this.input.title || this.attributes.title, + defaultTitle: this.attributes.title, }); } diff --git a/public/embeddable/observability_embeddable_factory.tsx b/public/embeddable/observability_embeddable_factory.tsx index 9fca4d9c80..00ff1c00ef 100644 --- a/public/embeddable/observability_embeddable_factory.tsx +++ b/public/embeddable/observability_embeddable_factory.tsx @@ -12,7 +12,6 @@ import { AttributeService, DashboardStart } from '../../../../src/plugins/dashbo import { EmbeddableFactoryDefinition, EmbeddableOutput, - ErrorEmbeddable, IContainer, SavedObjectEmbeddableInput, } from '../../../../src/plugins/embeddable/public'; @@ -21,7 +20,7 @@ import { OnSaveProps, SavedObjectMetaData, } from '../../../../src/plugins/saved_objects/public'; -import { observabilityID } from '../../common/constants/shared'; +import { observabilityID, observabilityTitle } from '../../common/constants/shared'; import { VisualizationSavedObjectAttributes, VISUALIZATION_SAVED_OBJECT, @@ -48,7 +47,7 @@ export class ObservabilityEmbeddableFactoryDefinition > { public readonly type = OBSERVABILITY_EMBEDDABLE; public readonly savedObjectMetaData: SavedObjectMetaData = { - name: 'SQL/PPL Visualizations', + name: observabilityTitle, includeFields: [], type: VISUALIZATION_SAVED_OBJECT, // saved object type for finding embeddables in Dashboard getIconForSavedObject: () => 'lensApp', @@ -89,7 +88,7 @@ export class ObservabilityEmbeddableFactoryDefinition } getDisplayName() { - return 'Observability'; + return observabilityTitle; } private async saveMethod(attributes: VisualizationSavedObjectAttributes, savedObjectId?: string) { From 8abc0c3485ad2154ade35ebd99d553380dbb1db0 Mon Sep 17 00:00:00 2001 From: Peter Fitzgibbons Date: Fri, 24 Mar 2023 05:42:43 -0700 Subject: [PATCH 39/73] Lint Notebook and NotebookTable in preparation for refactoring (#333) * Lint Notebook and NotebookTable in preparation for refactoring Signed-off-by: Peter Fitzgibbons Signed-off-by: Peter Fitzgibbons Co-authored-by: Peter Fitzgibbons --- .../notebooks/components/note_table.tsx | 45 ++++++++++++------- .../notebooks/components/notebook.tsx | 40 +++++++---------- 2 files changed, 43 insertions(+), 42 deletions(-) diff --git a/public/components/notebooks/components/note_table.tsx b/public/components/notebooks/components/note_table.tsx index 3c5da6df8f..ee6a3eef53 100644 --- a/public/components/notebooks/components/note_table.tsx +++ b/public/components/notebooks/components/note_table.tsx @@ -30,6 +30,7 @@ import { import _ from 'lodash'; import moment from 'moment'; import React, { ReactElement, useEffect, useState } from 'react'; +import { useHistory, useLocation } from 'react-router-dom'; import { ChromeBreadcrumb } from '../../../../../../src/core/public'; import { CREATE_NOTE_MESSAGE, @@ -43,7 +44,6 @@ import { } from './helpers/modal_containers'; import { NotebookType } from './main'; import { pageStyles } from '../../../../common/constants/shared'; -import { useHistory, useLocation } from 'react-router-dom'; interface NoteTableProps { loading: boolean; @@ -56,10 +56,21 @@ interface NoteTableProps { deleteNotebook: (noteList: string[], toastMessage?: string) => void; parentBreadcrumb: ChromeBreadcrumb; setBreadcrumbs: (newBreadcrumbs: ChromeBreadcrumb[]) => void; - setToast: (title: string, color?: string, text?: string) => void; + // setToast: (title: string, color?: string, text?: string) => void; } -export function NoteTable(props: NoteTableProps) { +export function NoteTable({ + loading, + fetchNotebooks, + addSampleNotebooks, + notebooks, + createNotebook, + renameNotebook, + cloneNotebook, + deleteNotebook, + parentBreadcrumb, + setBreadcrumbs, +}: NoteTableProps) { const [isModalVisible, setIsModalVisible] = useState(false); // Modal Toggle const [modalLayout, setModalLayout] = useState(); // Modal Layout const [isActionsPopoverOpen, setIsActionsPopoverOpen] = useState(false); @@ -67,22 +78,21 @@ export function NoteTable(props: NoteTableProps) { const [searchQuery, setSearchQuery] = useState(''); const location = useLocation(); const history = useHistory(); - const { notebooks, createNotebook, renameNotebook, cloneNotebook, deleteNotebook } = props; useEffect(() => { - props.setBreadcrumbs([ - props.parentBreadcrumb, + setBreadcrumbs([ + parentBreadcrumb, { text: 'Notebooks', href: '#/notebooks', }, ]); - props.fetchNotebooks(); - }, []); + fetchNotebooks(); + }, [setBreadcrumbs, parentBreadcrumb, fetchNotebooks]); useEffect(() => { - const url = window.location.hash.split('/') - if (url[url.length-1] === 'create') { + const url = window.location.hash.split('/'); + if (url[url.length - 1] === 'create') { createNote(); } }, [location]); @@ -125,7 +135,7 @@ export function NoteTable(props: NoteTableProps) { getCustomModal( onCreate, () => { - closeModal() + closeModal(); history.goBack(); }, 'Name', @@ -184,11 +194,11 @@ export function NoteTable(props: NoteTableProps) { showModal(); }; - const addSampleNotebooks = async () => { + const addSampleNotebooksModal = async () => { setModalLayout( getSampleNotebooksModal(closeModal, async () => { closeModal(); - await props.addSampleNotebooks(); + await addSampleNotebooks(); }) ); showModal(); @@ -239,7 +249,7 @@ export function NoteTable(props: NoteTableProps) { key="addSample" onClick={() => { setIsActionsPopoverOpen(false); - addSampleNotebooks(); + addSampleNotebooksModal(); }} > Add samples @@ -337,7 +347,7 @@ export function NoteTable(props: NoteTableProps) { /> @@ -380,7 +390,8 @@ export function NoteTable(props: NoteTableProps) { - @@ -388,7 +399,7 @@ export function NoteTable(props: NoteTableProps) { - addSampleNotebooks()}> + addSampleNotebooksModal()}> Add samples diff --git a/public/components/notebooks/components/notebook.tsx b/public/components/notebooks/components/notebook.tsx index b97ab17234..fc124588df 100644 --- a/public/components/notebooks/components/notebook.tsx +++ b/public/components/notebooks/components/notebook.tsx @@ -24,10 +24,10 @@ import { } from '@elastic/eui'; import CSS from 'csstype'; import moment from 'moment'; -import PPLService from '../../../services/requests/ppl'; import queryString from 'query-string'; import React, { Component } from 'react'; import { RouteComponentProps } from 'react-router-dom'; +import PPLService from '../../../services/requests/ppl'; import { ChromeBreadcrumb, CoreStart } from '../../../../../../src/core/public'; import { DashboardStart } from '../../../../../../src/plugins/dashboard/public'; import { @@ -68,7 +68,7 @@ const pageStyles: CSS.Properties = { * http object - for making API requests * setBreadcrumbs - sets breadcrumbs on top */ -type NotebookProps = { +interface NotebookProps { pplService: PPLService; openedNoteId: string; DashboardContainerByValueRenderer: DashboardStart['DashboardContainerByValueRenderer']; @@ -81,15 +81,15 @@ type NotebookProps = { setToast: (title: string, color?: string, text?: string) => void; location: RouteComponentProps['location']; history: RouteComponentProps['history']; -}; +} -type NotebookState = { +interface NotebookState { selectedViewId: string; path: string; dateCreated: string; dateModified: string; paragraphs: any; // notebook paragraphs fetched from API - parsedPara: Array; // paragraphs parsed to a common format + parsedPara: ParaType[]; // paragraphs parsed to a common format vizPrefix: string; // prefix for visualizations in Zeppelin Adaptor isAddParaPopoverOpen: boolean; isParaActionsPopoverOpen: boolean; @@ -101,7 +101,7 @@ type NotebookState = { modalLayout: React.ReactNode; showQueryParagraphError: boolean; queryParagraphErrorMessage: string; -}; +} export class Notebook extends Component { constructor(props: Readonly) { super(props); @@ -120,7 +120,7 @@ export class Notebook extends Component { isReportingActionsPopoverOpen: false, isReportingLoadingModalOpen: false, isModalVisible: false, - modalLayout: , + modalLayout: , showQueryParagraphError: false, queryParagraphErrorMessage: '', }; @@ -131,7 +131,7 @@ export class Notebook extends Component { }; parseAllParagraphs = () => { - let parsedPara = this.parseParagraphs(this.state.paragraphs); + const parsedPara = this.parseParagraphs(this.state.paragraphs); this.setState({ parsedPara }); }; @@ -157,7 +157,6 @@ export class Notebook extends Component { 'Error parsing paragraphs, please make sure you have the correct permission.', 'danger' ); - console.error(err); this.setState({ parsedPara: [] }); return []; } @@ -165,7 +164,7 @@ export class Notebook extends Component { // Assigns Loading, Running & inQueue for paragraphs in current notebook showParagraphRunning = (param: number | string) => { - let parsedPara = this.state.parsedPara; + const parsedPara = this.state.parsedPara; this.state.parsedPara.map((_: ParaType, index: number) => { if (param === 'queue') { parsedPara[index].inQueue = true; @@ -183,7 +182,7 @@ export class Notebook extends Component { // Sets a paragraph to selected and deselects all others paragraphSelector = (index: number) => { - let parsedPara = this.state.parsedPara; + const parsedPara = this.state.parsedPara; this.state.parsedPara.map((_: ParaType, idx: number) => { if (index === idx) parsedPara[idx].isSelected = true; else parsedPara[idx].isSelected = false; @@ -213,7 +212,6 @@ export class Notebook extends Component { 'Error deleting paragraph, please make sure you have the correct permission.', 'danger' ); - console.error(err.body.message); }); } }; @@ -255,7 +253,6 @@ export class Notebook extends Component { 'Error deleting paragraph, please make sure you have the correct permission.', 'danger' ); - console.error(err.body.message); }); }, 'Delete all paragraphs', @@ -360,7 +357,6 @@ export class Notebook extends Component { 'Error deleting visualization, please make sure you have the correct permission.', 'danger' ); - console.error(err.body.message); }); }; @@ -395,7 +391,6 @@ export class Notebook extends Component { 'Error adding paragraph, please make sure you have the correct permission.', 'danger' ); - console.error(err.body.message); }); }; @@ -436,7 +431,6 @@ export class Notebook extends Component { 'Error moving paragraphs, please make sure you have the correct permission.', 'danger' ); - console.error(err.body.message); }); }; @@ -469,7 +463,6 @@ export class Notebook extends Component { 'Error clearing paragraphs, please make sure you have the correct permission.', 'danger' ); - console.error(err.body.message); }); }; @@ -518,7 +511,6 @@ export class Notebook extends Component { 'Error running paragraph, please make sure you have the correct permission.', 'danger' ); - console.error(err.body.message); }); }; @@ -550,7 +542,7 @@ export class Notebook extends Component { // Handles text editor value and syncs with paragraph input textValueEditor = (evt: React.ChangeEvent, index: number) => { if (!(evt.key === 'Enter' && evt.shiftKey)) { - let parsedPara = this.state.parsedPara; + const parsedPara = this.state.parsedPara; parsedPara[index].inp = evt.target.value; this.setState({ parsedPara }); } @@ -566,7 +558,7 @@ export class Notebook extends Component { // update view mode, scrolls to paragraph and expands input if scrollToIndex is given updateView = (selectedViewId: string, scrollToIndex?: number) => { this.configureViewParameter(selectedViewId); - let parsedPara = [...this.state.parsedPara]; + const parsedPara = [...this.state.parsedPara]; this.state.parsedPara.map((para: ParaType, index: number) => { parsedPara[index].isInputExpanded = selectedViewId === 'input_only'; }); @@ -599,7 +591,6 @@ export class Notebook extends Component { 'Error fetching notebooks, please make sure you have the correct permission.', 'danger' ); - console.error(err?.body?.message || err); }); }; @@ -616,7 +607,6 @@ export class Notebook extends Component { }) .catch((err) => { this.props.setToast('Error getting query output', 'danger'); - console.error(err); }); }; @@ -667,7 +657,7 @@ export class Notebook extends Component { } }) .catch((error) => { - console.log('error is', error); + this.props.setToast('Error checking Reporting Plugin Installation status.', 'danger'); }); } @@ -683,7 +673,7 @@ export class Notebook extends Component { this.loadNotebook(); this.checkIfReportingPluginIsInstalled(); const searchParams = queryString.parse(this.props.location.search); - const view = searchParams['view']; + const view = searchParams.view; if (!view) { this.configureViewParameter('view_both'); } @@ -1005,7 +995,7 @@ export class Notebook extends Component { ref={this.state.parsedPara[index].paraRef} pplService={this.props.pplService} para={para} - setPara={(para: ParaType) => this.setPara(para, index)} + setPara={(pr: ParaType) => this.setPara(pr, index)} dateModified={this.state.paragraphs[index]?.dateModified} index={index} paraCount={this.state.parsedPara.length} From 2d6c7a9c33366c7ab760748ce960606e5b570201 Mon Sep 17 00:00:00 2001 From: Shenoy Pratik Date: Mon, 27 Mar 2023 13:03:28 -0700 Subject: [PATCH 40/73] [Backport main] move performance now to run time dep (#309) (#311) * move performance now to run time dep (#309) * move performance now to run time dep Signed-off-by: Derek Ho * update release notes for this PR and CI fix PR Signed-off-by: Derek Ho --------- Signed-off-by: Derek Ho (cherry picked from commit c0464990e3ba502d6def838edf14a0d7ef5bea92) * remove duplicate jest-dom Signed-off-by: Shenoy Pratik * updated snapshots for notebooks Signed-off-by: Shenoy Pratik --------- Signed-off-by: Shenoy Pratik Co-authored-by: Derek Ho --- package.json | 6 ++-- .../__snapshots__/para_input.test.tsx.snap | 8 +++--- .../__snapshots__/para_output.test.tsx.snap | 2 +- .../__snapshots__/paragraphs.test.tsx.snap | 4 +-- ...rch-observability.release-notes-2.6.0.0.md | 28 +++++++++++++++++++ 5 files changed, 38 insertions(+), 10 deletions(-) create mode 100644 release-notes/opensearch-observability.release-notes-2.6.0.0.md diff --git a/package.json b/package.json index af2c782e08..b909396096 100644 --- a/package.json +++ b/package.json @@ -35,7 +35,8 @@ "react-graph-vis": "^1.0.5", "react-paginate": "^8.1.3", "react-plotly.js": "^2.5.1", - "redux-persist": "^6.0.0" + "redux-persist": "^6.0.0", + "performance-now": "^2.1.0" }, "devDependencies": { "@cypress/skip-test": "^2.6.1", @@ -47,8 +48,7 @@ "eslint": "^6.8.0", "husky": "6.0.0", "jest-dom": "^4.0.0", - "lint-staged": "^13.1.0", - "performance-now": "^2.1.0" + "lint-staged": "^13.1.0" }, "resolutions": { "react-syntax-highlighter": "^15.4.3", diff --git a/public/components/notebooks/components/paragraph_components/__tests__/__snapshots__/para_input.test.tsx.snap b/public/components/notebooks/components/paragraph_components/__tests__/__snapshots__/para_input.test.tsx.snap index 813c41868f..a328c3d42b 100644 --- a/public/components/notebooks/components/paragraph_components/__tests__/__snapshots__/para_input.test.tsx.snap +++ b/public/components/notebooks/components/paragraph_components/__tests__/__snapshots__/para_input.test.tsx.snap @@ -2,10 +2,10 @@ exports[` spec renders the markdown component 1`] = `
    spec renders the markdown component 1`] = ` exports[` spec renders the visualization component 1`] = `
    spec renders other types of outputs 1`] = ` class="euiText euiText--medium" >
    `; diff --git a/public/components/notebooks/components/paragraph_components/__tests__/__snapshots__/paragraphs.test.tsx.snap b/public/components/notebooks/components/paragraph_components/__tests__/__snapshots__/paragraphs.test.tsx.snap index ce102f0b7d..0fb4568101 100644 --- a/public/components/notebooks/components/paragraph_components/__tests__/__snapshots__/paragraphs.test.tsx.snap +++ b/public/components/notebooks/components/paragraph_components/__tests__/__snapshots__/paragraphs.test.tsx.snap @@ -79,10 +79,10 @@ exports[` spec renders the component 1`] = ` class="euiFormRow__fieldWrapper" >
    Date: Fri, 31 Mar 2023 15:22:27 -0400 Subject: [PATCH 41/73] baseline repo permissions and groups (#314) * baseline repo permissions and groups Signed-off-by: Derek Ho * update baseline Signed-off-by: Derek Ho * fix up codeowners Signed-off-by: Derek Ho --------- Signed-off-by: Derek Ho --- .github/CODEOWNERS | 2 -- CODEOWNERS | 2 ++ MAINTAINERS.md | 11 ++++++++++- 3 files changed, 12 insertions(+), 3 deletions(-) delete mode 100644 .github/CODEOWNERS create mode 100644 CODEOWNERS diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS deleted file mode 100644 index 1dc11731b8..0000000000 --- a/.github/CODEOWNERS +++ /dev/null @@ -1,2 +0,0 @@ -# This should match the owning team set up in https://github.com/orgs/opensearch-project/teams -* @opensearch-project/observability \ No newline at end of file diff --git a/CODEOWNERS b/CODEOWNERS new file mode 100644 index 0000000000..1f9a96bf70 --- /dev/null +++ b/CODEOWNERS @@ -0,0 +1,2 @@ +# This should match the owning team set up in https://github.com/orgs/opensearch-project/teams +* @pjfitzgibbons @anirudha @ps48 @kavithacm @derek-ho @joshuali925 @dai-chen @YANG-DB @rupal-bq @mengweieric @vamsi-amazon @swiddis \ No newline at end of file diff --git a/MAINTAINERS.md b/MAINTAINERS.md index 5a909064fc..f124096678 100644 --- a/MAINTAINERS.md +++ b/MAINTAINERS.md @@ -15,4 +15,13 @@ This document contains a list of maintainers in this repo. See [opensearch-proje | Rupal Mahajan | [rupal-bq](https://github.com/rupal-bq) | Amazon | | Derek Ho | [derek-ho](https://github.com/derek-ho) | Amazon | | Lior Perry | [YANG-DB](https://github.com/YANG-DB) | Amazon | -| Peter Fitzgibbons | [pjfitzgibbons](https://github.com/pjfitzgibbons) | Amazon | \ No newline at end of file +| Peter Fitzgibbons | [pjfitzgibbons](https://github.com/pjfitzgibbons) | Amazon | +| Simeon Widdis | [swiddis] (https://github.com/swiddis) | Amazon | + +## Emeritus Maintainers + +| Maintainer | GitHub ID | Affiliation | +| ----------------- | ------------------------------------------------------- | ----------- | +| Charlotte Henkle | [CEHENKLE](https://github.com/CEHENKLE) | Amazon | +| Anirudha Jadhav | [anirudha](https://github.com/anirudha) | Amazon | +| Nick Knize | [nknize](https://github.com/nknize) | Amazon | From 0cb11bdbb6eee3a593d97b0cf5c62f6460e948a9 Mon Sep 17 00:00:00 2001 From: Joshua Li Date: Mon, 3 Apr 2023 22:53:02 +0000 Subject: [PATCH 42/73] Update observability visualization id and displayed name Signed-off-by: Joshua Li --- .../embeddable/observability_embeddable.tsx | 19 +++++-------------- .../observability_embeddable_factory.tsx | 9 +++++---- public/plugin.ts | 15 ++++++++++----- 3 files changed, 20 insertions(+), 23 deletions(-) diff --git a/public/embeddable/observability_embeddable.tsx b/public/embeddable/observability_embeddable.tsx index 441c401f83..5bed6bd5d8 100644 --- a/public/embeddable/observability_embeddable.tsx +++ b/public/embeddable/observability_embeddable.tsx @@ -19,21 +19,12 @@ import { } from '../../common/types/observability_saved_object_attributes'; import { ObservabilityEmbeddableComponent } from './observability_embeddable_component'; -// Apparently this needs to match the saved object type for the clone and replace panel actions to work +// this needs to match the saved object type for the clone and replace panel actions to work export const OBSERVABILITY_EMBEDDABLE = VISUALIZATION_SAVED_OBJECT; - -export interface ObservabilityEmbeddableConfiguration { - savedVisBuilder: VisualizationSavedObjectAttributes; - // TODO: add indexPatterns as part of configuration - // indexPatterns?: IIndexPattern[]; - editPath: string; - editUrl: string; - editable: boolean; -} - -export type ObservabilityByValueInput = { - attributes: VisualizationSavedObjectAttributes; -} & SavedObjectEmbeddableInput; +export const OBSERVABILITY_EMBEDDABLE_ID = 'observability-ppl'; +export const OBSERVABILITY_EMBEDDABLE_DISPLAY_NAME = 'PPL'; +export const OBSERVABILITY_EMBEDDABLE_DESCRIPTION = + 'Create a visualization with Piped Processing Language (PPL). PPL can query data in your indices and also supports federated data sources like Prometheus'; export interface ObservabilityOutput extends EmbeddableOutput { /** diff --git a/public/embeddable/observability_embeddable_factory.tsx b/public/embeddable/observability_embeddable_factory.tsx index 00ff1c00ef..919db7c02b 100644 --- a/public/embeddable/observability_embeddable_factory.tsx +++ b/public/embeddable/observability_embeddable_factory.tsx @@ -20,7 +20,7 @@ import { OnSaveProps, SavedObjectMetaData, } from '../../../../src/plugins/saved_objects/public'; -import { observabilityID, observabilityTitle } from '../../common/constants/shared'; +import { observabilityID } from '../../common/constants/shared'; import { VisualizationSavedObjectAttributes, VISUALIZATION_SAVED_OBJECT, @@ -29,6 +29,7 @@ import { ObservabilityEmbeddable, ObservabilityOutput, OBSERVABILITY_EMBEDDABLE, + OBSERVABILITY_EMBEDDABLE_DISPLAY_NAME, } from './observability_embeddable'; interface StartServices { @@ -47,7 +48,7 @@ export class ObservabilityEmbeddableFactoryDefinition > { public readonly type = OBSERVABILITY_EMBEDDABLE; public readonly savedObjectMetaData: SavedObjectMetaData = { - name: observabilityTitle, + name: OBSERVABILITY_EMBEDDABLE_DISPLAY_NAME, includeFields: [], type: VISUALIZATION_SAVED_OBJECT, // saved object type for finding embeddables in Dashboard getIconForSavedObject: () => 'lensApp', @@ -79,7 +80,7 @@ export class ObservabilityEmbeddableFactoryDefinition return false; } - async create(initialInput: SavedObjectEmbeddableInput, parent?: IContainer) { + async create(_initialInput: SavedObjectEmbeddableInput, _parent?: IContainer) { return undefined; } @@ -88,7 +89,7 @@ export class ObservabilityEmbeddableFactoryDefinition } getDisplayName() { - return observabilityTitle; + return OBSERVABILITY_EMBEDDABLE_DISPLAY_NAME; } private async saveMethod(attributes: VisualizationSavedObjectAttributes, savedObjectId?: string) { diff --git a/public/plugin.ts b/public/plugin.ts index dee85204a4..bfab7a4533 100644 --- a/public/plugin.ts +++ b/public/plugin.ts @@ -19,7 +19,12 @@ import { } from '../common/utils'; import { convertLegacyNotebooksUrl } from './components/notebooks/components/helpers/legacy_route_helpers'; import { convertLegacyTraceAnalyticsUrl } from './components/trace_analytics/components/common/legacy_route_helpers'; -import { OBSERVABILITY_EMBEDDABLE } from './embeddable/observability_embeddable'; +import { + OBSERVABILITY_EMBEDDABLE, + OBSERVABILITY_EMBEDDABLE_DESCRIPTION, + OBSERVABILITY_EMBEDDABLE_DISPLAY_NAME, + OBSERVABILITY_EMBEDDABLE_ID, +} from './embeddable/observability_embeddable'; import { ObservabilityEmbeddableFactoryDefinition } from './embeddable/observability_embeddable_factory'; import './index.scss'; import DSLService from './services/requests/dsl'; @@ -95,9 +100,9 @@ export class ObservabilityPlugin setupDeps.embeddable.registerEmbeddableFactory(OBSERVABILITY_EMBEDDABLE, embeddableFactory); setupDeps.visualizations.registerAlias({ - name: observabilityID, - title: observabilityTitle, - description: 'create a visualization with Piped processigng language', + name: OBSERVABILITY_EMBEDDABLE_ID, + title: OBSERVABILITY_EMBEDDABLE_DISPLAY_NAME, + description: OBSERVABILITY_EMBEDDABLE_DESCRIPTION, icon: 'pencil', aliasApp: observabilityID, aliasPath: '#/event_analytics/explorer', @@ -113,7 +118,7 @@ export class ObservabilityPlugin id, savedObjectType: VISUALIZATION_SAVED_OBJECT, title: attributes?.title, - typeTitle: observabilityTitle, + typeTitle: OBSERVABILITY_EMBEDDABLE_DISPLAY_NAME, stage: 'production', updated_at: updatedAt, }), From 331251fa231889b8dc539aa090d9da65b2a4783f Mon Sep 17 00:00:00 2001 From: Joshua Li Date: Tue, 4 Apr 2023 00:21:30 +0000 Subject: [PATCH 43/73] Fix types and object property access in ppl loader Signed-off-by: Joshua Li --- common/types/explorer.ts | 1 + .../saved_object_client/types.ts | 15 ++- .../saved_object_loaders/ppl/ppl_loader.ts | 110 ++++++++++-------- 3 files changed, 77 insertions(+), 49 deletions(-) diff --git a/common/types/explorer.ts b/common/types/explorer.ts index 4d343ff061..4c40ad5952 100644 --- a/common/types/explorer.ts +++ b/common/types/explorer.ts @@ -165,6 +165,7 @@ export interface SavedVisualization extends SavedObjectAttributes { type: string; sub_type: 'metric' | 'visualization'; user_configs?: string; + units_of_measure?: string; application_id?: string; } diff --git a/public/services/saved_objects/saved_object_client/types.ts b/public/services/saved_objects/saved_object_client/types.ts index 1033270dca..6257011d12 100644 --- a/public/services/saved_objects/saved_object_client/types.ts +++ b/public/services/saved_objects/saved_object_client/types.ts @@ -4,6 +4,7 @@ */ import { SavedQuery, SavedVisualization } from '../../../../common/types/explorer'; +import { SAVED_QUERY, SAVED_VISUALIZATION } from '../../../../common/constants/explorer'; export interface SavedObjectsCreateResponse { objectId: string; @@ -11,15 +12,23 @@ export interface SavedObjectsCreateResponse { export type SavedObjectsUpdateResponse = SavedObjectsCreateResponse; -export interface ObservabilitySavedObject { +interface ObservabilitySavedObjectBase { createdTimeMs: number; lastUpdatedTimeMs: number; objectId: string; tenant?: string; - savedVisualization?: SavedVisualization; - savedQuery?: SavedQuery; } +export interface ObservabilitySavedVisualization extends ObservabilitySavedObjectBase { + [SAVED_VISUALIZATION]: SavedVisualization; +} + +export interface ObservabilitySavedQuery extends ObservabilitySavedObjectBase { + [SAVED_QUERY]: SavedQuery; +} + +export type ObservabilitySavedObject = ObservabilitySavedVisualization | ObservabilitySavedQuery; + export interface SavedObjectsGetParams { objectId: string; } diff --git a/public/services/saved_objects/saved_object_loaders/ppl/ppl_loader.ts b/public/services/saved_objects/saved_object_loaders/ppl/ppl_loader.ts index 909c347a58..21fc4b27ae 100644 --- a/public/services/saved_objects/saved_object_loaders/ppl/ppl_loader.ts +++ b/public/services/saved_objects/saved_object_loaders/ppl/ppl_loader.ts @@ -4,15 +4,15 @@ */ import { has, isEmpty } from 'lodash'; -import { batch as Batch } from 'react-redux'; -import { changeQuery as changeQueryAction } from 'public/components/event_analytics/redux/slices/query_slice'; import { updateFields as updateFieldsAction } from 'public/components/event_analytics/redux/slices/field_slice'; +import { changeQuery as changeQueryAction } from 'public/components/event_analytics/redux/slices/query_slice'; import { updateTabName as updateTabNameAction } from 'public/components/event_analytics/redux/slices/query_tab_slice'; import { change as updateVizConfigAction } from 'public/components/event_analytics/redux/slices/viualization_config_slice'; -import { ISavedObjectsClient } from '../../saved_object_client/client_interface'; -import { SavedObjectLoaderBase } from '../loader_base'; -import { ISavedObjectLoader } from '../loader_interface'; +import { batch as Batch } from 'react-redux'; +import { NotificationsStart } from '../../../../../../../src/core/public'; import { + AGGREGATIONS, + BREAKDOWNS, GROUPBY, RAW_QUERY, SAVED_OBJECT_ID, @@ -23,15 +23,15 @@ import { SELECTED_FIELDS, SELECTED_TIMESTAMP, TYPE_TAB_MAPPING, - AGGREGATIONS, - BREAKDOWNS, } from '../../../../../common/constants/explorer'; -import { NotificationsStart } from '../../../../../../../src/core/public'; import { QueryManager } from '../../../../../common/query_manager'; import { statsChunk } from '../../../../../common/query_manager/ast/types/stats'; -import { IField } from '../../../../../common/types/explorer'; +import { IField, SavedQuery, SavedVisualization } from '../../../../../common/types/explorer'; import { AppDispatch } from '../../../../framework/redux/store'; -import { ObservabilitySavedObject } from '../../saved_object_client/types'; +import { ISavedObjectsClient } from '../../saved_object_client/client_interface'; +import { ObservabilitySavedObject, ObservabilitySavedQuery } from '../../saved_object_client/types'; +import { SavedObjectLoaderBase } from '../loader_base'; +import { ISavedObjectLoader } from '../loader_interface'; interface LoadParams { objectId: string; @@ -45,7 +45,12 @@ interface LoadContext { queryManager: QueryManager; getDefaultVisConfig: ( statsToken: statsChunk - ) => { [AGGREGATIONS]: IField[]; [GROUPBY]: IField[]; [BREAKDOWNS]?: IField[]; span?: any }; + ) => { + [AGGREGATIONS]: IField[]; + [GROUPBY]: IField[]; + [BREAKDOWNS]?: IField[]; + span?: any; + }; setSelectedPanelName: (savedObjectName: string) => void; setCurVisId: (visId: string) => void; setTempQuery: (tmpQuery: string) => void; @@ -67,6 +72,18 @@ interface Dispatchers { type SavedObjectData = ObservabilitySavedObject; +function isObjectSavedQuery( + savedObjectData: SavedObjectData +): savedObjectData is ObservabilitySavedQuery { + return SAVED_QUERY in savedObjectData; +} + +function isInnerObjectSavedVisualization( + objectData: SavedQuery | SavedVisualization +): objectData is SavedVisualization { + return 'type' in objectData; +} + export class PPLSavedObjectLoader extends SavedObjectLoaderBase implements ISavedObjectLoader { constructor( protected readonly savedObjectClient: ISavedObjectsClient, @@ -102,30 +119,33 @@ export class PPLSavedObjectLoader extends SavedObjectLoaderBase implements ISave } async processSavedData(savedObjectData: SavedObjectData) { - const isSavedQuery = has(savedObjectData, SAVED_QUERY); - const savedType = isSavedQuery ? SAVED_QUERY : SAVED_VISUALIZATION; - const objectData = isSavedQuery + const savedType = isObjectSavedQuery(savedObjectData) ? SAVED_QUERY : SAVED_VISUALIZATION; + const objectData = isObjectSavedQuery(savedObjectData) ? savedObjectData.savedQuery : savedObjectData.savedVisualization; const currQuery = objectData?.query || ''; const { appLogEvents } = this.loadContext; // app analytics specific - if (appLogEvents && savedObjectData.selected_date_range) { - this.updateAppAnalyticSelectedDateRange(savedObjectData.selected_date_range); + if (appLogEvents && objectData.selected_date_range) { + this.updateAppAnalyticSelectedDateRange(objectData.selected_date_range); } // update redux store with this saved object data await this.updateReduxState(savedType, objectData, currQuery); // update UI state with this saved object data - await this.updateUIState(savedObjectData); + await this.updateUIState(objectData); // fetch data based on saved object data await this.loadDataFromSavedObject(); } - async updateReduxState(savedType: string, objectData: SavedObjectData, currQuery: string) { + async updateReduxState( + savedType: typeof SAVED_QUERY | typeof SAVED_VISUALIZATION, + objectData: SavedQuery | SavedVisualization, + currQuery: string + ) { const { batch, dispatch, changeQuery, updateFields, updateTabName } = this.dispatchers; const { tabId } = this.loadContext; const { objectId } = this.loadParams; @@ -159,34 +179,34 @@ export class PPLSavedObjectLoader extends SavedObjectLoaderBase implements ISave tabName: objectData.name, }) ); - await this.updateVisualizationConfig(objectData); + if (isInnerObjectSavedVisualization(objectData)) { + await this.updateVisualizationConfig(objectData); + } }); } - async updateVisualizationConfig(objectData: SavedObjectData) { + async updateVisualizationConfig(objectData: SavedVisualization) { const { dispatch, updateVizConfig } = this.dispatchers; const { tabId, queryManager, getDefaultVisConfig } = this.loadContext; // fill saved user configs - if (objectData.type) { - let visConfig = {}; - const customConfig = objectData.user_configs ? JSON.parse(objectData.user_configs) : {}; - if (!isEmpty(customConfig.dataConfig) && !isEmpty(customConfig.dataConfig?.series)) { - visConfig = { ...customConfig }; - } else { - const statsTokens = queryManager.queryParser().parse(objectData.query).getStats(); - visConfig = { dataConfig: { ...getDefaultVisConfig(statsTokens) } }; - } - await dispatch( - updateVizConfig({ - tabId, - vizId: objectData?.type, - data: visConfig, - }) - ); + let visConfig = {}; + const customConfig = objectData.user_configs ? JSON.parse(objectData.user_configs) : {}; + if (!isEmpty(customConfig.dataConfig) && !isEmpty(customConfig.dataConfig?.series)) { + visConfig = { ...customConfig }; + } else { + const statsTokens = queryManager.queryParser().parse(objectData.query).getStats(); + visConfig = { dataConfig: { ...getDefaultVisConfig(statsTokens) } }; } + await dispatch( + updateVizConfig({ + tabId, + vizId: objectData?.type, + data: visConfig, + }) + ); } - async updateUIState(objectData: SavedObjectData) { + async updateUIState(objectData: SavedQuery | SavedVisualization) { const { setSelectedPanelName, setCurVisId, @@ -196,24 +216,22 @@ export class PPLSavedObjectLoader extends SavedObjectLoaderBase implements ISave setSubType, setSelectedContentTab, } = this.loadContext; - const isSavedQuery = has(objectData, SAVED_QUERY); - const savedVisualization = objectData.savedVisualization; // update UI state with saved data setSelectedPanelName(objectData?.name || ''); setCurVisId(objectData?.type || 'bar'); setTempQuery((staleTempQuery) => { return objectData?.query || staleTempQuery; }); - if (savedVisualization?.sub_type) { - if (savedVisualization?.sub_type === 'metric') { + if (isInnerObjectSavedVisualization(objectData)) { + if (objectData.sub_type === 'metric') { setMetricChecked(true); - setMetricMeasure(savedVisualization?.units_of_measure); + setMetricMeasure(objectData.units_of_measure || ''); } - setSubType(savedVisualization?.sub_type); + setSubType(objectData.sub_type); } - const tabToBeFocused = isSavedQuery - ? TYPE_TAB_MAPPING[SAVED_QUERY] - : TYPE_TAB_MAPPING[SAVED_VISUALIZATION]; + const tabToBeFocused = isInnerObjectSavedVisualization(objectData) + ? TYPE_TAB_MAPPING[SAVED_VISUALIZATION] + : TYPE_TAB_MAPPING[SAVED_QUERY]; setSelectedContentTab(tabToBeFocused); } From ced9040e753e76f0e1330b46f71753db6d8ebd60 Mon Sep 17 00:00:00 2001 From: Joshua Li Date: Tue, 4 Apr 2023 00:48:07 +0000 Subject: [PATCH 44/73] Fix type definition for VisualizationSavedObjectAttributes Signed-off-by: Joshua Li --- common/types/observability_saved_object_attributes.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/types/observability_saved_object_attributes.ts b/common/types/observability_saved_object_attributes.ts index 829184d1c2..520f922bc7 100644 --- a/common/types/observability_saved_object_attributes.ts +++ b/common/types/observability_saved_object_attributes.ts @@ -15,5 +15,5 @@ export interface VisualizationSavedObjectAttributes extends SavedObjectAttribute description: string; version: number; createdTimeMs: number; - savedVisualization?: SavedVisualization; + savedVisualization: SavedVisualization; } From 35e2e3ac0bedff6ba40230dc739ecae39b391fd2 Mon Sep 17 00:00:00 2001 From: Eric Wei Date: Mon, 3 Apr 2023 22:17:12 -0700 Subject: [PATCH 45/73] data fetcher Signed-off-by: Eric Wei --- .../event_analytics/explorer/explorer.tsx | 156 ++++---------- .../services/data_fetchers/fetch_interface.ts | 8 + public/services/data_fetchers/fetcher_base.ts | 11 + .../data_fetchers/ppl/ppl_data_fetcher.ts | 204 ++++++++++++++++++ 4 files changed, 260 insertions(+), 119 deletions(-) create mode 100644 public/services/data_fetchers/fetch_interface.ts create mode 100644 public/services/data_fetchers/fetcher_base.ts create mode 100644 public/services/data_fetchers/ppl/ppl_data_fetcher.ts diff --git a/public/components/event_analytics/explorer/explorer.tsx b/public/components/event_analytics/explorer/explorer.tsx index 6b32331c5e..ee52bd1f31 100644 --- a/public/components/event_analytics/explorer/explorer.tsx +++ b/public/components/event_analytics/explorer/explorer.tsx @@ -27,11 +27,9 @@ import { DATE_PICKER_FORMAT, DEFAULT_AVAILABILITY_QUERY, EVENT_ANALYTICS_DOCUMENTATION_URL, - FILTERED_PATTERN, NEW_TAB, PATTERNS_EXTRACTOR_REGEX, PATTERNS_REGEX, - PATTERN_REGEX, RAW_QUERY, SAVED_OBJECT_ID, SAVED_OBJECT_TYPE, @@ -56,7 +54,6 @@ import { } from '../../../../common/constants/shared'; import { QueryManager } from '../../../../common/query_manager'; import { - IDefaultTimestampState, IExplorerFields, IExplorerProps, IField, @@ -66,7 +63,6 @@ import { } from '../../../../common/types/explorer'; import { buildQuery, - composeFinalQuery, getIndexPatternFromRawQuery, uiSettingsService, } from '../../../../common/utils'; @@ -110,6 +106,7 @@ import { TimechartHeader } from './timechart_header'; import { ExplorerVisualizations } from './visualizations'; import { CountDistribution } from './visualizations/count_distribution'; import { PPLSavedObjectLoader } from '../../../services/saved_objects/saved_object_loaders/ppl/ppl_loader'; +import { PPLDataFetcher } from '../../../services/data_fetchers/ppl/ppl_data_fetcher'; export const Explorer = ({ pplService, @@ -164,7 +161,6 @@ export const Explorer = ({ const [selectedCustomPanelOptions, setSelectedCustomPanelOptions] = useState([]); const [selectedPanelName, setSelectedPanelName] = useState(''); const [curVisId, setCurVisId] = useState('bar'); - const [prevIndex, setPrevIndex] = useState(''); const [isPanelTextFieldInvalid, setIsPanelTextFieldInvalid] = useState(false); const [isSidebarClosed, setIsSidebarClosed] = useState(false); const [timeIntervalOptions, setTimeIntervalOptions] = useState(TIME_INTERVAL_OPTIONS); @@ -250,122 +246,39 @@ export const Explorer = ({ }; }; - const getDefaultTimestampByIndexPattern = async ( - indexPattern: string - ): Promise => await timestampUtils.getTimestamp(indexPattern); - const fetchData = async (startingTime?: string, endingTime?: string) => { - const curQuery = queryRef.current; + const curQuery: IQuery = queryRef.current!; const rawQueryStr = (curQuery![RAW_QUERY] as string).includes(appBaseQuery) ? curQuery![RAW_QUERY] : buildQuery(appBasedRef.current, curQuery![RAW_QUERY]); - const curIndex = getIndexPatternFromRawQuery(rawQueryStr); - - if (isEmpty(rawQueryStr)) return; - - if (isEmpty(curIndex)) { - setToast('Query does not include valid index.', 'danger'); - return; - } - - let curTimestamp: string = curQuery![SELECTED_TIMESTAMP]; - if (isEmpty(curTimestamp)) { - const defaultTimestamp = await getDefaultTimestampByIndexPattern(curIndex); - if (isEmpty(defaultTimestamp.default_timestamp)) { - setToast(defaultTimestamp.message, 'danger'); - return; - } - curTimestamp = defaultTimestamp.default_timestamp; - if (defaultTimestamp.hasSchemaConflict) { - setToast(defaultTimestamp.message, 'danger'); - } - } - - let curPattern: string = curQuery![SELECTED_PATTERN_FIELD]; - - if (isEmpty(curPattern)) { - const patternErrorHandler = getErrorHandler('Error fetching default pattern field'); - await setDefaultPatternsField(curIndex, '', patternErrorHandler); - const newQuery = queryRef.current; - curPattern = newQuery![SELECTED_PATTERN_FIELD]; - if (isEmpty(curPattern)) { - setToast('Index does not contain a valid pattern field.', 'danger'); - return; - } - } - - if (isEqual(typeof startingTime, 'undefined') && isEqual(typeof endingTime, 'undefined')) { - startingTime = curQuery![SELECTED_DATE_RANGE][0]; - endingTime = curQuery![SELECTED_DATE_RANGE][1]; - } - - // compose final query - const finalQuery = composeFinalQuery( - curQuery![RAW_QUERY], - startingTime!, - endingTime!, - curTimestamp, - isLiveTailOnRef.current, - appBasedRef.current, - curQuery![SELECTED_PATTERN_FIELD], - curQuery![PATTERN_REGEX], - curQuery![FILTERED_PATTERN] - ); - - batch(() => { - dispatch( - changeQuery({ - tabId, - query: { - finalQuery, - [RAW_QUERY]: rawQueryStr, - [SELECTED_TIMESTAMP]: curTimestamp, - }, - }) - ); - if (selectedContentTabId === TAB_CHART_ID) { - // parse stats section on every search - const statsTokens = queryManager.queryParser().parse(rawQueryStr).getStats(); - const updatedDataConfig = getDefaultVisConfig(statsTokens); - dispatch( - changeVizConfig({ - tabId, - vizId: curVisId, - data: { dataConfig: { ...updatedDataConfig } }, - }) - ); - } - }); - - if (!selectedIntervalRef.current || selectedIntervalRef.current.text === 'Auto') { - findAutoInterval(startingTime, endingTime); - } - if (isLiveTailOnRef.current) { - getLiveTail(undefined, getErrorHandler('Error fetching events')); - } else { - getEvents(undefined, getErrorHandler('Error fetching events')); - } - getCountVisualizations(selectedIntervalRef.current!.value.replace(/^auto_/, '')); - - // to fetch patterns data on current query - if (!finalQuery.match(PATTERNS_REGEX)) { - getPatterns(selectedIntervalRef.current!.value.replace(/^auto_/, '')); - } - - // for comparing usage if for the same tab, user changed index from one to another - if (!isLiveTailOnRef.current) { - setPrevIndex(curTimestamp); - if (!queryRef.current!.isLoaded) { - dispatch( - changeQuery({ - tabId, - query: { - isLoaded: true, - }, - }) - ); - } - } + new PPLDataFetcher( + { ...curQuery }, + { batch, dispatch, changeQuery, changeVizConfig }, + { + tabId, + findAutoInterval, + getCountVisualizations, + getLiveTail, + getEvents, + getErrorHandler, + getPatterns, + setDefaultPatternsField, + timestampUtils, + curVisId, + selectedContentTabId, + queryManager, + getDefaultVisConfig, + }, + { + appBaseQuery, + query: rawQueryStr, + startingTime, + endingTime, + isLiveTailOn: isLiveTailOnRef.current, + selectedInterval: selectedIntervalRef.current, + }, + notifications + ).search(); }; const isIndexPatternChanged = (currentQuery: string, prevTabQuery: string) => @@ -435,7 +348,12 @@ export const Explorer = ({ } else { fetchData(); } - }, []); + if (savedObjectId) { + updateTabData(savedObjectId); + } else { + fetchData(); + } + }, [savedObjectId]); useEffect(() => { if (appLogEvents) { @@ -796,7 +714,7 @@ export const Explorer = ({ ); await setDefaultPatternsField('', ''); } - if (!availability) { + if (availability !== true) { await updateQueryInStore(tempQuery); } await fetchData(); diff --git a/public/services/data_fetchers/fetch_interface.ts b/public/services/data_fetchers/fetch_interface.ts new file mode 100644 index 0000000000..3bf4589c96 --- /dev/null +++ b/public/services/data_fetchers/fetch_interface.ts @@ -0,0 +1,8 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +export interface IDataFetcher { + search: () => void; +} diff --git a/public/services/data_fetchers/fetcher_base.ts b/public/services/data_fetchers/fetcher_base.ts new file mode 100644 index 0000000000..81a0464e08 --- /dev/null +++ b/public/services/data_fetchers/fetcher_base.ts @@ -0,0 +1,11 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { IDataFetcher } from './fetch_interface'; + +export abstract class DataFetcherBase implements IDataFetcher { + constructor() {} + abstract search(): void; +} diff --git a/public/services/data_fetchers/ppl/ppl_data_fetcher.ts b/public/services/data_fetchers/ppl/ppl_data_fetcher.ts new file mode 100644 index 0000000000..cc9f2cf909 --- /dev/null +++ b/public/services/data_fetchers/ppl/ppl_data_fetcher.ts @@ -0,0 +1,204 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { isEmpty } from 'lodash'; +import { IDefaultTimestampState, IQuery } from '../../../../common/types/explorer'; +import { IDataFetcher } from '../fetch_interface'; +import { DataFetcherBase } from '../fetcher_base'; +import { composeFinalQuery, getIndexPatternFromRawQuery } from '../../../../common/utils'; +import { + FILTERED_PATTERN, + PATTERNS_REGEX, + PATTERN_REGEX, + RAW_QUERY, + SELECTED_DATE_RANGE, + SELECTED_PATTERN_FIELD, + SELECTED_TIMESTAMP, + TAB_CHART_ID, +} from '../../../../common/constants/explorer'; + +export class PPLDataFetcher extends DataFetcherBase implements IDataFetcher { + protected queryIndex: string; + protected timestamp!: string; + constructor( + protected readonly query: IQuery, + protected readonly storeContext, + protected readonly searchContext, + protected readonly searchParams, + protected readonly notifications + ) { + super(); + // index/index patterns for this search + this.queryIndex = this.getIndex(this.searchParams.query); + } + + async setTimestamp(index: string) { + try { + const defaultTimestamp = await this.getTimestamp(index); + this.timestamp = defaultTimestamp.default_timestamp || ''; + // schema conflicts for multiple indexes + if (defaultTimestamp.hasSchemaConflict) { + this.notifications.toasts.addError({ + title: 'Schema conflicts', + text: `Schema conflicts detected while fetching default timestamp, ${defaultTimestamp.message}`, + }); + } + } catch (error) { + this.notifications.toasts.addError(error, { + title: 'Unable to get default timestamp', + }); + } + } + + async search() { + const { + query, + appBaseQuery, + startingTime, + endingTime, + isLiveTailOn, + selectedInterval, + } = this.searchParams; + + if (isEmpty(query)) return; + + const { + tabId, + findAutoInterval, + getCountVisualizations, + getLiveTail, + getEvents, + getErrorHandler, + getPatterns, + } = this.searchContext; + const { dispatch, changeQuery } = this.storeContext; + + await this.processTimestamp(query); + if (isEmpty(this.timestamp)) return; + + const curStartTime = startingTime || this.query[SELECTED_DATE_RANGE][0]; + const curEndTime = endingTime || this.query[SELECTED_DATE_RANGE][1]; + + // compose final query + const finalQuery = composeFinalQuery( + this.query[RAW_QUERY], + curStartTime, + curEndTime, + this.timestamp, + isLiveTailOn, + appBaseQuery, + this.query[SELECTED_PATTERN_FIELD], + this.query[PATTERN_REGEX], + this.query[FILTERED_PATTERN] + ); + + // update UI with new query state + await this.updateQueryState(this.query[RAW_QUERY], finalQuery, this.timestamp); + // calculate proper time interval for count distribution + if (!selectedInterval || selectedInterval.text === 'Auto') { + findAutoInterval(curStartTime, curEndTime); + } + + // get query data + if (isLiveTailOn) { + getLiveTail(finalQuery, getErrorHandler('Error fetching events')); + } else { + getEvents(finalQuery, getErrorHandler('Error fetching events')); + } + getCountVisualizations(selectedInterval.value.replace(/^auto_/, '')); + // patterns + this.setLogPattern(this.query, this.queryIndex, finalQuery); + if (!finalQuery.match(PATTERNS_REGEX)) { + getPatterns(selectedInterval.value.replace(/^auto_/, '')); + } + + // live tail - for comparing usage if for the same tab, user changed index from one to another + if (!isLiveTailOn && !this.query.isLoaded) { + dispatch( + changeQuery({ + tabId, + query: { + isLoaded: true, + }, + }) + ); + } + } + + async setLogPattern(query: IQuery, index: string, finalQuery: string) { + const { getErrorHandler, setDefaultPatternsField } = this.searchContext; + // set pattern + if (isEmpty(query[SELECTED_PATTERN_FIELD])) { + await setDefaultPatternsField( + index, + '', + getErrorHandler('Error fetching default pattern field') + ); + } + + // check if above setDefaultPatternsField correctly gets valid patterns + if (isEmpty(query[SELECTED_PATTERN_FIELD])) { + this.notifications.toasts.addError({ + title: 'Invalid pattern field', + text: 'Index does not contain a valid pattern field.', + }); + return; + } + } + + async processTimestamp(query: IQuery) { + if (query[SELECTED_TIMESTAMP]) { + this.timestamp = query[SELECTED_TIMESTAMP]; + } else { + await this.setTimestamp(this.queryIndex); + } + } + + getIndex(query: string) { + return getIndexPatternFromRawQuery(query); + } + + async getTimestamp(indexPattern: string): Promise { + const { timestampUtils } = this.searchContext; + return await timestampUtils.getTimestamp(indexPattern); + } + + async updateQueryState(rawQuery: string, finalQuery: string, curTimestamp: string) { + const { batch, dispatch, changeQuery, changeVizConfig } = this.storeContext; + const { query } = this.searchParams; + const { + tabId, + curVisId, + selectedContentTabId, + queryManager, + getDefaultVisConfig, + } = this.searchContext; + + await batch(() => { + dispatch( + changeQuery({ + tabId, + query: { + finalQuery, + [RAW_QUERY]: query, + [SELECTED_TIMESTAMP]: curTimestamp, + }, + }) + ); + if (selectedContentTabId === TAB_CHART_ID) { + // parse stats section on every search + const statsTokens = queryManager.queryParser().parse(rawQuery).getStats(); + const updatedDataConfig = getDefaultVisConfig(statsTokens); + dispatch( + changeVizConfig({ + tabId, + vizId: curVisId, + data: { dataConfig: { ...updatedDataConfig } }, + }) + ); + } + }); + } +} From c90b58f9e9e89ecdc3bdb8088df1b833afd9ef1c Mon Sep 17 00:00:00 2001 From: Eric Wei Date: Tue, 4 Apr 2023 10:47:28 -0700 Subject: [PATCH 46/73] use new saved object client in panel for getting visualizations Signed-off-by: Eric Wei --- public/components/custom_panels/helpers/utils.tsx | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/public/components/custom_panels/helpers/utils.tsx b/public/components/custom_panels/helpers/utils.tsx index 06f58d084d..f8908252fc 100644 --- a/public/components/custom_panels/helpers/utils.tsx +++ b/public/components/custom_panels/helpers/utils.tsx @@ -2,7 +2,6 @@ * Copyright OpenSearch Contributors * SPDX-License-Identifier: Apache-2.0 */ -/* eslint-disable no-console */ import dateMath from '@elastic/datemath'; import { ShortDate } from '@elastic/eui'; @@ -18,7 +17,6 @@ import { } from '../../../../common/constants/shared'; import PPLService from '../../../services/requests/ppl'; import { CoreStart } from '../../../../../../src/core/public'; -import { CUSTOM_PANELS_API_PREFIX } from '../../../../common/constants/custom_panels'; import { VisualizationType, SavedVisualizationType, @@ -29,6 +27,7 @@ import { getVizContainerProps } from '../../../components/visualizations/charts/ import { QueryManager } from '../../../../common/query_manager'; import { getDefaultVisConfig } from '../../event_analytics/utils'; import { removeBacktick } from '../../../../common/utils'; +import { getSavedObjectsClient } from '../../../services/saved_objects/saved_object_client/client_factory'; /* * "Utils" This file contains different reused functions in operational panels @@ -171,10 +170,12 @@ export const fetchVisualizationById = async ( setIsError: (error: VizContainerError) => void ) => { let savedVisualization = {} as SavedVisualizationType; - await http - .get(`${CUSTOM_PANELS_API_PREFIX}/visualizations/${savedVisualizationId}`) + await getSavedObjectsClient({ objectId: savedVisualizationId, objectType: 'savedQuery' }) + .get({ objectId: savedVisualizationId }) .then((res) => { - savedVisualization = res.visualization; + savedVisualization = { ...res.observabilityObjectList[0]?.savedVisualization }; + savedVisualization.id = res.observabilityObjectList[0].objectId; + savedVisualization.timeField = res.observabilityObjectList[0]?.selected_timestamp?.name; }) .catch((err) => { setIsError({ From 50dce4981c4bef5e2b7d7428d46c05b2b6b0b268 Mon Sep 17 00:00:00 2001 From: Joshua Li Date: Tue, 4 Apr 2023 17:51:32 +0000 Subject: [PATCH 47/73] Use placeholder icon for visualization embeddable Signed-off-by: Joshua Li --- public/embeddable/filters/filter_parser.ts | 4 ++++ public/embeddable/observability_embeddable.tsx | 1 + public/embeddable/observability_embeddable_factory.tsx | 3 ++- public/plugin.ts | 7 ++++--- 4 files changed, 11 insertions(+), 4 deletions(-) diff --git a/public/embeddable/filters/filter_parser.ts b/public/embeddable/filters/filter_parser.ts index c83a7bc651..15f7f8a24b 100644 --- a/public/embeddable/filters/filter_parser.ts +++ b/public/embeddable/filters/filter_parser.ts @@ -5,6 +5,10 @@ import { Filter, getFilterField } from '../../../../../src/plugins/data/common'; +/** + * Parse core {@link Filter} and convert to a PPL where clause. Only supports + * non DSL filters. + */ export const parseFilters = (filters?: Filter[]) => { if (!filters) return ''; return filters diff --git a/public/embeddable/observability_embeddable.tsx b/public/embeddable/observability_embeddable.tsx index 5bed6bd5d8..a36755744d 100644 --- a/public/embeddable/observability_embeddable.tsx +++ b/public/embeddable/observability_embeddable.tsx @@ -25,6 +25,7 @@ export const OBSERVABILITY_EMBEDDABLE_ID = 'observability-ppl'; export const OBSERVABILITY_EMBEDDABLE_DISPLAY_NAME = 'PPL'; export const OBSERVABILITY_EMBEDDABLE_DESCRIPTION = 'Create a visualization with Piped Processing Language (PPL). PPL can query data in your indices and also supports federated data sources like Prometheus'; +export const OBSERVABILITY_EMBEDDABLE_ICON = 'lensApp'; export interface ObservabilityOutput extends EmbeddableOutput { /** diff --git a/public/embeddable/observability_embeddable_factory.tsx b/public/embeddable/observability_embeddable_factory.tsx index 919db7c02b..53e7b7859f 100644 --- a/public/embeddable/observability_embeddable_factory.tsx +++ b/public/embeddable/observability_embeddable_factory.tsx @@ -30,6 +30,7 @@ import { ObservabilityOutput, OBSERVABILITY_EMBEDDABLE, OBSERVABILITY_EMBEDDABLE_DISPLAY_NAME, + OBSERVABILITY_EMBEDDABLE_ICON, } from './observability_embeddable'; interface StartServices { @@ -51,7 +52,7 @@ export class ObservabilityEmbeddableFactoryDefinition name: OBSERVABILITY_EMBEDDABLE_DISPLAY_NAME, includeFields: [], type: VISUALIZATION_SAVED_OBJECT, // saved object type for finding embeddables in Dashboard - getIconForSavedObject: () => 'lensApp', + getIconForSavedObject: () => OBSERVABILITY_EMBEDDABLE_ICON, }; private attributeService?: AttributeService; diff --git a/public/plugin.ts b/public/plugin.ts index bfab7a4533..a7d15bc666 100644 --- a/public/plugin.ts +++ b/public/plugin.ts @@ -23,6 +23,7 @@ import { OBSERVABILITY_EMBEDDABLE, OBSERVABILITY_EMBEDDABLE_DESCRIPTION, OBSERVABILITY_EMBEDDABLE_DISPLAY_NAME, + OBSERVABILITY_EMBEDDABLE_ICON, OBSERVABILITY_EMBEDDABLE_ID, } from './embeddable/observability_embeddable'; import { ObservabilityEmbeddableFactoryDefinition } from './embeddable/observability_embeddable_factory'; @@ -103,7 +104,7 @@ export class ObservabilityPlugin name: OBSERVABILITY_EMBEDDABLE_ID, title: OBSERVABILITY_EMBEDDABLE_DISPLAY_NAME, description: OBSERVABILITY_EMBEDDABLE_DESCRIPTION, - icon: 'pencil', + icon: OBSERVABILITY_EMBEDDABLE_ICON, aliasApp: observabilityID, aliasPath: '#/event_analytics/explorer', stage: 'production', @@ -113,8 +114,8 @@ export class ObservabilityPlugin toListItem: ({ id, attributes, updated_at: updatedAt }) => ({ description: attributes?.description, editApp: observabilityID, - editUrl: `#/event_analytics/explorer/${encodeURIComponent(id)}`, - icon: 'pencil', + editUrl: `#/event_analytics/explorer/${id}`, + icon: OBSERVABILITY_EMBEDDABLE_ICON, id, savedObjectType: VISUALIZATION_SAVED_OBJECT, title: attributes?.title, From ebdd3eab37131302969d325a5ca6212b268c5871 Mon Sep 17 00:00:00 2001 From: Joshua Li Date: Tue, 4 Apr 2023 18:36:24 +0000 Subject: [PATCH 48/73] Update panels to support vis saved in .kibana and .observability Signed-off-by: Joshua Li --- .../custom_panels/helpers/utils.tsx | 32 ++++++----- .../visualization_flyout.tsx | 55 ++++++++++++++++--- 2 files changed, 65 insertions(+), 22 deletions(-) diff --git a/public/components/custom_panels/helpers/utils.tsx b/public/components/custom_panels/helpers/utils.tsx index f8908252fc..740499bbd2 100644 --- a/public/components/custom_panels/helpers/utils.tsx +++ b/public/components/custom_panels/helpers/utils.tsx @@ -10,24 +10,26 @@ import _, { isEmpty } from 'lodash'; import { Moment } from 'moment-timezone'; import React from 'react'; import { Layout } from 'react-grid-layout'; +import { CoreStart } from '../../../../../../src/core/public'; import { PPL_DATE_FORMAT, PPL_INDEX_REGEX, PPL_WHERE_CLAUSE_REGEX, } from '../../../../common/constants/shared'; -import PPLService from '../../../services/requests/ppl'; -import { CoreStart } from '../../../../../../src/core/public'; +import { QueryManager } from '../../../../common/query_manager'; import { - VisualizationType, SavedVisualizationType, + VisualizationType, VizContainerError, } from '../../../../common/types/custom_panels'; -import { Visualization } from '../../visualizations/visualization'; +import { SavedVisualization } from '../../../../common/types/explorer'; +import { removeBacktick } from '../../../../common/utils'; import { getVizContainerProps } from '../../../components/visualizations/charts/helpers'; -import { QueryManager } from '../../../../common/query_manager'; +import PPLService from '../../../services/requests/ppl'; +import { SavedObjectsActions } from '../../../services/saved_objects/saved_object_client/saved_objects_actions'; +import { ObservabilitySavedVisualization } from '../../../services/saved_objects/saved_object_client/types'; import { getDefaultVisConfig } from '../../event_analytics/utils'; -import { removeBacktick } from '../../../../common/utils'; -import { getSavedObjectsClient } from '../../../services/saved_objects/saved_object_client/client_factory'; +import { Visualization } from '../../visualizations/visualization'; /* * "Utils" This file contains different reused functions in operational panels @@ -169,13 +171,17 @@ export const fetchVisualizationById = async ( savedVisualizationId: string, setIsError: (error: VizContainerError) => void ) => { - let savedVisualization = {} as SavedVisualizationType; - await getSavedObjectsClient({ objectId: savedVisualizationId, objectType: 'savedQuery' }) - .get({ objectId: savedVisualizationId }) + let savedVisualization = {} as SavedVisualization; + + await SavedObjectsActions.get({ objectId: savedVisualizationId }) .then((res) => { - savedVisualization = { ...res.observabilityObjectList[0]?.savedVisualization }; - savedVisualization.id = res.observabilityObjectList[0].objectId; - savedVisualization.timeField = res.observabilityObjectList[0]?.selected_timestamp?.name; + const visualization = (res.observabilityObjectList[0] as ObservabilitySavedVisualization) + .savedVisualization; + savedVisualization = { + ...visualization, + id: res.observabilityObjectList[0].objectId, + timeField: visualization.selected_timestamp.name, + }; }) .catch((err) => { setIsError({ diff --git a/public/components/custom_panels/panel_modules/visualization_flyout/visualization_flyout.tsx b/public/components/custom_panels/panel_modules/visualization_flyout/visualization_flyout.tsx index db31f0d713..a372866c68 100644 --- a/public/components/custom_panels/panel_modules/visualization_flyout/visualization_flyout.tsx +++ b/public/components/custom_panels/panel_modules/visualization_flyout/visualization_flyout.tsx @@ -2,7 +2,6 @@ * Copyright OpenSearch Contributors * SPDX-License-Identifier: Apache-2.0 */ -/* eslint-disable no-console */ /* eslint-disable react-hooks/exhaustive-deps */ import { @@ -33,12 +32,8 @@ import { EuiToolTip, ShortDate, } from '@elastic/eui'; -import _, { isError } from 'lodash'; +import _ from 'lodash'; import React, { useEffect, useState } from 'react'; -import { FlyoutContainers } from '../../../common/flyout_containers'; -import { displayVisualization, getQueryResponse, isDateValid } from '../../helpers/utils'; -import { convertDateTime } from '../../helpers/utils'; -import PPLService from '../../../../services/requests/ppl'; import { CoreStart } from '../../../../../../../src/core/public'; import { CUSTOM_PANELS_API_PREFIX } from '../../../../../common/constants/custom_panels'; import { @@ -47,8 +42,18 @@ import { VisualizationType, VizContainerError, } from '../../../../../common/types/custom_panels'; -import './visualization_flyout.scss'; import { uiSettingsService } from '../../../../../common/utils'; +import PPLService from '../../../../services/requests/ppl'; +import { SavedObjectsActions } from '../../../../services/saved_objects/saved_object_client/saved_objects_actions'; +import { ObservabilitySavedVisualization } from '../../../../services/saved_objects/saved_object_client/types'; +import { FlyoutContainers } from '../../../common/flyout_containers'; +import { + convertDateTime, + displayVisualization, + getQueryResponse, + isDateValid, +} from '../../helpers/utils'; +import './visualization_flyout.scss'; /* * VisaulizationFlyout - This module create a flyout to add visualization @@ -332,10 +337,42 @@ export const VisaulizationFlyout = ({ ); + const parseSavedVisualizations = (visualization: ObservabilitySavedVisualization) => { + return { + id: visualization.objectId, + name: visualization.savedVisualization.name, + query: visualization.savedVisualization.query, + type: visualization.savedVisualization.type, + timeField: visualization.savedVisualization.selected_timestamp.name, + selected_date_range: visualization.savedVisualization.selected_date_range, + selected_fields: visualization.savedVisualization.selected_fields, + user_configs: visualization.savedVisualization.user_configs + ? JSON.parse(visualization.savedVisualization.user_configs) + : {}, + sub_type: visualization.savedVisualization.hasOwnProperty('sub_type') + ? visualization.savedVisualization.sub_type + : '', + units_of_measure: visualization.savedVisualization.hasOwnProperty('units_of_measure') + ? visualization.savedVisualization.units_of_measure + : '', + ...(visualization.savedVisualization.application_id + ? { application_id: visualization.savedVisualization.application_id } + : {}), + }; + }; + // Fetch all saved visualizations const fetchSavedVisualizations = async () => { - return http - .get(`${CUSTOM_PANELS_API_PREFIX}/visualizations`) + return SavedObjectsActions.getBulk({ + objectType: ['savedVisualization'], + sortOrder: 'desc', + fromIndex: 0, + }) + .then((response) => ({ + visualizations: response.observabilityObjectList.map((visualization) => + parseSavedVisualizations(visualization as ObservabilitySavedVisualization) + ), + })) .then((res) => { if (res.visualizations.length > 0) { setSavedVisualizations(res.visualizations); From bdfce75af6d235194f44b9934c1b2721206ec17c Mon Sep 17 00:00:00 2001 From: Joshua Li Date: Tue, 4 Apr 2023 20:50:15 +0000 Subject: [PATCH 49/73] Remove duplicated logic for loading a saved object in explorer Signed-off-by: Joshua Li --- public/components/event_analytics/explorer/explorer.tsx | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/public/components/event_analytics/explorer/explorer.tsx b/public/components/event_analytics/explorer/explorer.tsx index ee52bd1f31..75945e661b 100644 --- a/public/components/event_analytics/explorer/explorer.tsx +++ b/public/components/event_analytics/explorer/explorer.tsx @@ -348,12 +348,7 @@ export const Explorer = ({ } else { fetchData(); } - if (savedObjectId) { - updateTabData(savedObjectId); - } else { - fetchData(); - } - }, [savedObjectId]); + }, []); useEffect(() => { if (appLogEvents) { From 27b2505d101822e49e46d97fead221b76b69674f Mon Sep 17 00:00:00 2001 From: Joshua Li Date: Tue, 4 Apr 2023 21:24:03 +0000 Subject: [PATCH 50/73] Allow adding updated visualizations to panels Signed-off-by: Joshua Li --- public/components/event_analytics/explorer/explorer.tsx | 1 + .../saved_object_savers/ppl/save_as_current_vis.ts | 6 +++++- .../saved_object_savers/ppl/save_as_new_vis.ts | 2 +- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/public/components/event_analytics/explorer/explorer.tsx b/public/components/event_analytics/explorer/explorer.tsx index 75945e661b..9a9aa155c6 100644 --- a/public/components/event_analytics/explorer/explorer.tsx +++ b/public/components/event_analytics/explorer/explorer.tsx @@ -777,6 +777,7 @@ export const Explorer = ({ userConfigs: JSON.stringify(userVizConfigs[curVisId]), description: userVizConfigs[curVisId]?.dataConfig?.panelOptions?.description || '', subType, + selectedPanels: selectedCustomPanelOptions, } ); } else { diff --git a/public/services/saved_objects/saved_object_savers/ppl/save_as_current_vis.ts b/public/services/saved_objects/saved_object_savers/ppl/save_as_current_vis.ts index b741466dc1..d6708ae4fe 100644 --- a/public/services/saved_objects/saved_object_savers/ppl/save_as_current_vis.ts +++ b/public/services/saved_objects/saved_object_savers/ppl/save_as_current_vis.ts @@ -19,7 +19,7 @@ export class SaveAsCurrentVisualization extends SavedQuerySaver { save(): void { const { dispatch, updateTabName } = this.dispatchers; const { tabId, notifications } = this.saveContext; - const { name } = this.saveParams; + const { name, selectedPanels } = this.saveParams; this.saveClient .update({ ...this.saveParams }) .then((res: any) => { @@ -27,6 +27,10 @@ export class SaveAsCurrentVisualization extends SavedQuerySaver { title: 'Saved successfully.', text: `Visualization '${name}' has been successfully updated.`, }); + + if (selectedPanels?.length) + this.addToPanel({ selectedPanels, saveTitle: name, notifications, visId: res.objectId }); + dispatch( updateTabName({ tabId, diff --git a/public/services/saved_objects/saved_object_savers/ppl/save_as_new_vis.ts b/public/services/saved_objects/saved_object_savers/ppl/save_as_new_vis.ts index 316a7e829a..b0c57d4c7d 100644 --- a/public/services/saved_objects/saved_object_savers/ppl/save_as_new_vis.ts +++ b/public/services/saved_objects/saved_object_savers/ppl/save_as_new_vis.ts @@ -41,7 +41,7 @@ export class SaveAsNewVisualization extends SavedQuerySaver { text: `New visualization '${name}' has been successfully saved.`, }); - if (selectedPanels) + if (selectedPanels?.length) this.addToPanel({ selectedPanels, saveTitle: name, notifications, visId: res.objectId }); if (appLogEvents) { From 87de64800a1f0c856cbe5d1529c0e27d7449448e Mon Sep 17 00:00:00 2001 From: Joshua Li Date: Tue, 4 Apr 2023 22:14:39 +0000 Subject: [PATCH 51/73] Make visualization.sub_type optional Signed-off-by: Joshua Li --- common/types/explorer.ts | 2 +- server/routes/event_analytics/event_analytics_router.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/common/types/explorer.ts b/common/types/explorer.ts index 4c40ad5952..53dfe2ca20 100644 --- a/common/types/explorer.ts +++ b/common/types/explorer.ts @@ -163,7 +163,7 @@ export interface SavedVisualization extends SavedObjectAttributes { selected_fields: { text: string; tokens: [] }; selected_timestamp: IField; type: string; - sub_type: 'metric' | 'visualization'; + sub_type?: 'metric' | 'visualization'; // exists if sub type is metric user_configs?: string; units_of_measure?: string; application_id?: string; diff --git a/server/routes/event_analytics/event_analytics_router.ts b/server/routes/event_analytics/event_analytics_router.ts index 03933649d5..f180f88b5d 100644 --- a/server/routes/event_analytics/event_analytics_router.ts +++ b/server/routes/event_analytics/event_analytics_router.ts @@ -138,7 +138,7 @@ export const registerEventAnalyticsRouter = ({ description: schema.string(), application_id: schema.maybe(schema.string()), user_configs: schema.maybe(schema.string()), - sub_type: schema.string(), + sub_type: schema.maybe(schema.string()), units_of_measure: schema.maybe(schema.string()), selected_labels: schema.maybe( schema.object({ @@ -232,7 +232,7 @@ export const registerEventAnalyticsRouter = ({ description: schema.string(), application_id: schema.maybe(schema.string()), user_configs: schema.maybe(schema.string()), - sub_type: schema.string(), + sub_type: schema.maybe(schema.string()), units_of_measure: schema.maybe(schema.string()), selected_labels: schema.maybe( schema.object({ From 941f497de29ead5b4bef69894c4937c8a2e12dbe Mon Sep 17 00:00:00 2001 From: Joshua Li Date: Tue, 4 Apr 2023 22:41:28 +0000 Subject: [PATCH 52/73] Pass currently selected time interval ref instead of value Signed-off-by: Joshua Li --- public/components/event_analytics/explorer/explorer.tsx | 2 +- public/services/data_fetchers/ppl/ppl_data_fetcher.ts | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/public/components/event_analytics/explorer/explorer.tsx b/public/components/event_analytics/explorer/explorer.tsx index 9a9aa155c6..b7206ea33f 100644 --- a/public/components/event_analytics/explorer/explorer.tsx +++ b/public/components/event_analytics/explorer/explorer.tsx @@ -275,7 +275,7 @@ export const Explorer = ({ startingTime, endingTime, isLiveTailOn: isLiveTailOnRef.current, - selectedInterval: selectedIntervalRef.current, + selectedInterval: selectedIntervalRef, }, notifications ).search(); diff --git a/public/services/data_fetchers/ppl/ppl_data_fetcher.ts b/public/services/data_fetchers/ppl/ppl_data_fetcher.ts index cc9f2cf909..d63a5200a0 100644 --- a/public/services/data_fetchers/ppl/ppl_data_fetcher.ts +++ b/public/services/data_fetchers/ppl/ppl_data_fetcher.ts @@ -97,7 +97,7 @@ export class PPLDataFetcher extends DataFetcherBase implements IDataFetcher { // update UI with new query state await this.updateQueryState(this.query[RAW_QUERY], finalQuery, this.timestamp); // calculate proper time interval for count distribution - if (!selectedInterval || selectedInterval.text === 'Auto') { + if (!selectedInterval.current || selectedInterval.current.text === 'Auto') { findAutoInterval(curStartTime, curEndTime); } @@ -107,11 +107,11 @@ export class PPLDataFetcher extends DataFetcherBase implements IDataFetcher { } else { getEvents(finalQuery, getErrorHandler('Error fetching events')); } - getCountVisualizations(selectedInterval.value.replace(/^auto_/, '')); + getCountVisualizations(selectedInterval.current.value.replace(/^auto_/, '')); // patterns this.setLogPattern(this.query, this.queryIndex, finalQuery); if (!finalQuery.match(PATTERNS_REGEX)) { - getPatterns(selectedInterval.value.replace(/^auto_/, '')); + getPatterns(selectedInterval.current.value.replace(/^auto_/, '')); } // live tail - for comparing usage if for the same tab, user changed index from one to another From dde94bc948b6d1a124bb71351d5145c72eb2fd01 Mon Sep 17 00:00:00 2001 From: Joshua Li Date: Tue, 4 Apr 2023 23:05:36 +0000 Subject: [PATCH 53/73] Parse user configs field in app analytics Signed-off-by: Joshua Li --- .../application_analytics/helpers/utils.tsx | 42 +++++++++---------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/public/components/application_analytics/helpers/utils.tsx b/public/components/application_analytics/helpers/utils.tsx index a9df996b16..5bdbcf7061 100644 --- a/public/components/application_analytics/helpers/utils.tsx +++ b/public/components/application_analytics/helpers/utils.tsx @@ -2,45 +2,44 @@ * Copyright OpenSearch Contributors * SPDX-License-Identifier: Apache-2.0 */ -/* eslint-disable no-console */ import { EuiDescriptionList, EuiSelectOption, EuiSpacer, EuiText } from '@elastic/eui'; import { ApplicationType, AvailabilityType } from 'common/types/application_analytics'; import { FilterType } from 'public/components/trace_analytics/components/common/filters/filters'; +import PPLService from 'public/services/requests/ppl'; import React, { Dispatch, ReactChild } from 'react'; import { batch } from 'react-redux'; -import PPLService from 'public/services/requests/ppl'; +import { HttpSetup } from '../../../../../../src/core/public'; +import { APP_ANALYTICS_API_PREFIX } from '../../../../common/constants/application_analytics'; +import { CUSTOM_PANELS_API_PREFIX } from '../../../../common/constants/custom_panels'; +import { NEW_SELECTED_QUERY_TAB, TAB_CREATED_TYPE } from '../../../../common/constants/explorer'; +import { SPAN_REGEX } from '../../../../common/constants/shared'; +import { VisualizationType } from '../../../../common/types/custom_panels'; import { IField } from '../../../../common/types/explorer'; import { preprocessQuery } from '../../../../common/utils/query_utils'; -import { SPAN_REGEX } from '../../../../common/constants/shared'; import { fetchVisualizationById } from '../../../components/custom_panels/helpers/utils'; -import { CUSTOM_PANELS_API_PREFIX } from '../../../../common/constants/custom_panels'; -import { VisualizationType } from '../../../../common/types/custom_panels'; -import { NEW_SELECTED_QUERY_TAB, TAB_CREATED_TYPE } from '../../../../common/constants/explorer'; -import { APP_ANALYTICS_API_PREFIX } from '../../../../common/constants/application_analytics'; -import { HttpSetup } from '../../../../../../src/core/public'; import { init as initFields, remove as removefields, } from '../../event_analytics/redux/slices/field_slice'; import { - init as initVisualizationConfig, - reset as resetVisualizationConfig, -} from '../../event_analytics/redux/slices/viualization_config_slice'; -import { - init as initQuery, - remove as removeQuery, - changeQuery, -} from '../../event_analytics/redux/slices/query_slice'; + init as initPatterns, + remove as removePatterns, +} from '../../event_analytics/redux/slices/patterns_slice'; import { init as initQueryResult, remove as removeQueryResult, } from '../../event_analytics/redux/slices/query_result_slice'; +import { + changeQuery, + init as initQuery, + remove as removeQuery, +} from '../../event_analytics/redux/slices/query_slice'; import { addTab, removeTab } from '../../event_analytics/redux/slices/query_tab_slice'; import { - init as initPatterns, - remove as removePatterns, -} from '../../event_analytics/redux/slices/patterns_slice'; + init as initVisualizationConfig, + reset as resetVisualizationConfig, +} from '../../event_analytics/redux/slices/viualization_config_slice'; // Name validation export const isNameValid = (name: string, existingNames: string[]) => { @@ -219,13 +218,14 @@ export const calculateAvailability = async ( const visData = await fetchVisualizationById(http, visualizationId, (value: string) => console.error(value) ); + const userConfigs = visData.user_configs ? JSON.parse(visData.user_configs) : {}; // If there are levels, we get the current value - if (visData.user_configs.availabilityConfig?.hasOwnProperty('level')) { + if (userConfigs.availabilityConfig?.hasOwnProperty('level')) { // For every saved visualization with availability levels we push it to visWithAvailability // This is used to populate the options in configuration visWithAvailability.push({ value: visualizationId, text: visData.name }); - const levels = visData.user_configs.availabilityConfig.level.reverse(); + const levels = userConfigs.availabilityConfig.level.reverse(); let currValue = Number.MIN_VALUE; const finalQuery = preprocessQuery({ rawQuery: visData.query, From 9f829cb9f2739fbd7b6b52f26b562527697f56f0 Mon Sep 17 00:00:00 2001 From: Joshua Li Date: Tue, 4 Apr 2023 23:24:18 +0000 Subject: [PATCH 54/73] Fix visualizations icon in explorer home Signed-off-by: Joshua Li --- .../home/saved_objects_table.tsx | 39 +++++++++---------- 1 file changed, 18 insertions(+), 21 deletions(-) diff --git a/public/components/event_analytics/home/saved_objects_table.tsx b/public/components/event_analytics/home/saved_objects_table.tsx index afe00992fb..62207a7538 100644 --- a/public/components/event_analytics/home/saved_objects_table.tsx +++ b/public/components/event_analytics/home/saved_objects_table.tsx @@ -3,17 +3,17 @@ * SPDX-License-Identifier: Apache-2.0 */ -import React, { useState, useRef } from 'react'; -import { EuiLink, EuiInMemoryTable, EuiIcon } from '@elastic/eui'; -import { FILTER_OPTIONS } from '../../../../common/constants/explorer'; +import { EuiIcon, EuiInMemoryTable, EuiLink } from '@elastic/eui'; import { isEmpty } from 'lodash'; +import React, { useRef, useState } from 'react'; +import { FILTER_OPTIONS } from '../../../../common/constants/explorer'; -interface savedQueryTableProps { - savedHistories: Array; +interface SavedQueryTableProps { + savedHistories: any[]; handleHistoryClick: (objectId: string) => void; - handleSelectHistory: (selectedHistories: Array) => void; + handleSelectHistory: (selectedHistories: any[]) => void; isTableLoading: boolean; - selectedHistories: Array; + selectedHistories: History[]; } export function SavedQueryTable({ @@ -21,7 +21,7 @@ export function SavedQueryTable({ handleHistoryClick, handleSelectHistory, isTableLoading, -}: savedQueryTableProps) { +}: SavedQueryTableProps) { const [pageIndex, setPageIndex] = useState(0); const [pageSize, setPageSize] = useState(10); const pageIndexRef = useRef(); @@ -30,10 +30,10 @@ export function SavedQueryTable({ pageSizeRef.current = pageSize; const onTableChange = ({ page = {} }) => { - const { index: pageIndex, size: pageSize } = page; + const { index, size } = page; - setPageIndex(pageIndex); - setPageSize(pageSize); + setPageIndex(page); + setPageSize(size); }; const columns = [ @@ -43,7 +43,7 @@ export function SavedQueryTable({ sortable: true, width: '40px', render: (item: any) => { - if (item == 'Visualization') { + if (item === 'Visualization') { return (
    @@ -87,14 +87,11 @@ export function SavedQueryTable({ const isSavedVisualization = h.hasOwnProperty('savedVisualization'); const savedObject = isSavedVisualization ? h.savedVisualization : h.savedQuery; const curType = isSavedVisualization ? 'savedVisualization' : 'savedQuery'; - var subType = ''; - if (isSavedVisualization) { - if (savedObject?.sub_type === 'metric') { - subType = 'Metric' - } else { - subType = savedObject?.sub_type; - } - } + const displayType = !isSavedVisualization + ? 'Query' + : savedObject?.sub_type === 'metric' + ? 'Metric' + : 'Visualization'; const record = { objectId: h.objectId, objectType: curType, @@ -109,7 +106,7 @@ export function SavedQueryTable({ id: h.objectId, data: record, name: savedObject.name, - type: isSavedVisualization ? (!isEmpty(subType)) ? subType: 'Visualization' : 'Query', + type: displayType, }; }); From 11891391449dcd7ab6865ae2b8f80af5d5eddb96 Mon Sep 17 00:00:00 2001 From: Joshua Li Date: Wed, 5 Apr 2023 00:28:54 +0000 Subject: [PATCH 55/73] Allow notebooks to read saved visualiations from .kibana index Signed-off-by: Joshua Li --- .../custom_panels/helpers/utils.tsx | 30 +++++++++ .../visualization_flyout.tsx | 25 +------- .../paragraph_components/paragraphs.tsx | 64 +++++++++---------- 3 files changed, 63 insertions(+), 56 deletions(-) diff --git a/public/components/custom_panels/helpers/utils.tsx b/public/components/custom_panels/helpers/utils.tsx index 740499bbd2..51e94409a4 100644 --- a/public/components/custom_panels/helpers/utils.tsx +++ b/public/components/custom_panels/helpers/utils.tsx @@ -389,6 +389,36 @@ export const onTimeChange = ( setRecentlyUsedRanges(recentlyUsedRangeObject.slice(0, 9)); }; +/** + * Convert an ObservabilitySavedVisualization into SavedVisualizationType, + * which is used in panels. + */ +export const parseSavedVisualizations = ( + visualization: ObservabilitySavedVisualization +): SavedVisualizationType => { + return { + id: visualization.objectId, + name: visualization.savedVisualization.name, + query: visualization.savedVisualization.query, + type: visualization.savedVisualization.type, + timeField: visualization.savedVisualization.selected_timestamp.name, + selected_date_range: visualization.savedVisualization.selected_date_range, + selected_fields: visualization.savedVisualization.selected_fields, + user_configs: visualization.savedVisualization.user_configs + ? JSON.parse(visualization.savedVisualization.user_configs) + : {}, + sub_type: visualization.savedVisualization.hasOwnProperty('sub_type') + ? visualization.savedVisualization.sub_type + : '', + units_of_measure: visualization.savedVisualization.hasOwnProperty('units_of_measure') + ? visualization.savedVisualization.units_of_measure + : '', + ...(visualization.savedVisualization.application_id + ? { application_id: visualization.savedVisualization.application_id } + : {}), + }; +}; + // Function to check date validity export const isDateValid = ( start: string | Moment | undefined, diff --git a/public/components/custom_panels/panel_modules/visualization_flyout/visualization_flyout.tsx b/public/components/custom_panels/panel_modules/visualization_flyout/visualization_flyout.tsx index a372866c68..9bbb236c44 100644 --- a/public/components/custom_panels/panel_modules/visualization_flyout/visualization_flyout.tsx +++ b/public/components/custom_panels/panel_modules/visualization_flyout/visualization_flyout.tsx @@ -52,6 +52,7 @@ import { displayVisualization, getQueryResponse, isDateValid, + parseSavedVisualizations, } from '../../helpers/utils'; import './visualization_flyout.scss'; @@ -337,30 +338,6 @@ export const VisaulizationFlyout = ({ ); - const parseSavedVisualizations = (visualization: ObservabilitySavedVisualization) => { - return { - id: visualization.objectId, - name: visualization.savedVisualization.name, - query: visualization.savedVisualization.query, - type: visualization.savedVisualization.type, - timeField: visualization.savedVisualization.selected_timestamp.name, - selected_date_range: visualization.savedVisualization.selected_date_range, - selected_fields: visualization.savedVisualization.selected_fields, - user_configs: visualization.savedVisualization.user_configs - ? JSON.parse(visualization.savedVisualization.user_configs) - : {}, - sub_type: visualization.savedVisualization.hasOwnProperty('sub_type') - ? visualization.savedVisualization.sub_type - : '', - units_of_measure: visualization.savedVisualization.hasOwnProperty('units_of_measure') - ? visualization.savedVisualization.units_of_measure - : '', - ...(visualization.savedVisualization.application_id - ? { application_id: visualization.savedVisualization.application_id } - : {}), - }; - }; - // Fetch all saved visualizations const fetchSavedVisualizations = async () => { return SavedObjectsActions.getBulk({ diff --git a/public/components/notebooks/components/paragraph_components/paragraphs.tsx b/public/components/notebooks/components/paragraph_components/paragraphs.tsx index 7926ef2633..76a33480f5 100644 --- a/public/components/notebooks/components/paragraph_components/paragraphs.tsx +++ b/public/components/notebooks/components/paragraph_components/paragraphs.tsx @@ -21,6 +21,7 @@ import { EuiText, htmlIdGenerator, } from '@elastic/eui'; +import _ from 'lodash'; import moment from 'moment'; import React, { forwardRef, useEffect, useImperativeHandle, useState } from 'react'; import { CoreStart } from '../../../../../../../src/core/public'; @@ -37,11 +38,11 @@ import { } from '../../../../../common/constants/shared'; import { ParaType } from '../../../../../common/types/notebooks'; import { uiSettingsService } from '../../../../../common/utils'; +import PPLService from '../../../../services/requests/ppl'; +import { SavedObjectsActions } from '../../../../services/saved_objects/saved_object_client/saved_objects_actions'; +import { ObservabilitySavedVisualization } from '../../../../services/saved_objects/saved_object_client/types'; import { ParaInput } from './para_input'; import { ParaOutput } from './para_output'; -import { CUSTOM_PANELS_API_PREFIX } from '../../../../../common/constants/custom_panels'; -import PPLService from '../../../../services/requests/ppl'; -import _ from 'lodash'; /* * "Paragraphs" component is used to render cells of the notebook open and "add para div" between paragraphs @@ -67,7 +68,7 @@ import _ from 'lodash'; * Cell component of nteract used as a container for paragraphs in notebook UI. * https://components.nteract.io/#cell */ -type ParagraphProps = { +interface ParagraphProps { pplService: PPLService; para: ParaType; setPara: (para: ParaType) => void; @@ -89,7 +90,7 @@ type ParagraphProps = { movePara: (index: number, targetIndex: number) => void; showQueryParagraphError: boolean; queryParagraphErrorMessage: string; -}; +} export const Paragraphs = forwardRef((props: ParagraphProps, ref) => { const { @@ -137,17 +138,15 @@ export const Paragraphs = forwardRef((props: ParagraphProps, ref) => { }) .catch((err) => console.error('Fetching dashboard visualization issue', err.body.message)); - await http - .get(`${CUSTOM_PANELS_API_PREFIX}/visualizations`) + await SavedObjectsActions.getBulk({ objectType: ['savedVisualization'] }) .then((res) => { - const noAppVisualizations = res.visualizations.filter((vis) => { - return !!!vis.application_id; - }); - opt2 = noAppVisualizations.map((vizObject) => ({ - label: vizObject.name, - key: vizObject.id, - className: 'OBSERVABILITY_VISUALIZATION', - })); + opt2 = (res.observabilityObjectList as ObservabilitySavedVisualization[]) + .filter((visualization) => !visualization.savedVisualization.application_id) + .map((visualization) => ({ + label: visualization.savedVisualization.name, + key: visualization.objectId, + className: 'OBSERVABILITY_VISUALIZATION', + })); }) .catch((err) => console.error('Fetching observability visualization issue', err.body.message) @@ -225,7 +224,7 @@ export const Paragraphs = forwardRef((props: ParagraphProps, ref) => { setRunParaError(true); return; } - let newVisObjectInput = undefined; + let newVisObjectInput; if (para.isVizualisation) { const inputTemp = createDashboardVizObject(selectedVisOption[0].key); setVisInput(inputTemp); @@ -270,7 +269,7 @@ export const Paragraphs = forwardRef((props: ParagraphProps, ref) => { return paraOutput; } - const renderParaHeader = (type: string, index: number) => { + const renderParaHeader = (type: string, idx: number) => { const panels: EuiContextMenuPanelDescriptor[] = [ { id: 0, @@ -293,48 +292,48 @@ export const Paragraphs = forwardRef((props: ParagraphProps, ref) => { }, { name: 'Move up', - disabled: index === 0, + disabled: idx === 0, onClick: () => { setIsPopoverOpen(false); - props.movePara(index, index - 1); + props.movePara(idx, idx - 1); }, }, { name: 'Move to top', - disabled: index === 0, + disabled: idx === 0, onClick: () => { setIsPopoverOpen(false); - props.movePara(index, 0); + props.movePara(idx, 0); }, }, { name: 'Move down', - disabled: index === props.paraCount - 1, + disabled: idx === props.paraCount - 1, onClick: () => { setIsPopoverOpen(false); - props.movePara(index, index + 1); + props.movePara(idx, idx + 1); }, }, { name: 'Move to bottom', - disabled: index === props.paraCount - 1, + disabled: idx === props.paraCount - 1, onClick: () => { setIsPopoverOpen(false); - props.movePara(index, props.paraCount - 1); + props.movePara(idx, props.paraCount - 1); }, }, { name: 'Duplicate', onClick: () => { setIsPopoverOpen(false); - props.clonePara(para, index + 1); + props.clonePara(para, idx + 1); }, }, { name: 'Delete', onClick: () => { setIsPopoverOpen(false); - props.deletePara(para, index); + props.deletePara(para, idx); }, }, ], @@ -347,14 +346,14 @@ export const Paragraphs = forwardRef((props: ParagraphProps, ref) => { name: 'Code block', onClick: () => { setIsPopoverOpen(false); - props.addPara(index, '', 'CODE'); + props.addPara(idx, '', 'CODE'); }, }, { name: 'Visualization', onClick: () => { setIsPopoverOpen(false); - props.addPara(index, '', 'VISUALIZATION'); + props.addPara(idx, '', 'VISUALIZATION'); }, }, ], @@ -367,14 +366,14 @@ export const Paragraphs = forwardRef((props: ParagraphProps, ref) => { name: 'Code block', onClick: () => { setIsPopoverOpen(false); - props.addPara(index + 1, '', 'CODE'); + props.addPara(idx + 1, '', 'CODE'); }, }, { name: 'Visualization', onClick: () => { setIsPopoverOpen(false); - props.addPara(index + 1, '', 'VISUALIZATION'); + props.addPara(idx + 1, '', 'VISUALIZATION'); }, }, ], @@ -386,7 +385,7 @@ export const Paragraphs = forwardRef((props: ParagraphProps, ref) => { - {`[${index + 1}] ${type} `} + {`[${idx + 1}] ${type} `} { <> {renderParaHeader(!para.isVizualisation ? 'Code block' : 'Visualization', index)} + {/* eslint-disable-next-line jsx-a11y/click-events-have-key-events */}
    paragraphSelector(index)}> {para.isInputExpanded && ( <> From 6bcefe32de2ceb45bfbe04d0ddd83ebb279c7b63 Mon Sep 17 00:00:00 2001 From: Eric Wei Date: Tue, 4 Apr 2023 17:39:40 -0700 Subject: [PATCH 56/73] adjust tab size Signed-off-by: Eric Wei --- public/components/common/search/search.scss | 2 +- public/components/event_analytics/explorer/explorer.tsx | 1 + public/components/event_analytics/explorer/log_explorer.tsx | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/public/components/common/search/search.scss b/public/components/common/search/search.scss index 1b0666a6d1..f079dec512 100644 --- a/public/components/common/search/search.scss +++ b/public/components/common/search/search.scss @@ -4,7 +4,7 @@ */ .globalQueryBar { - margin: .5rem 0; + margin: 0; padding: .5rem; } .aa-Autocomplete { diff --git a/public/components/event_analytics/explorer/explorer.tsx b/public/components/event_analytics/explorer/explorer.tsx index b7206ea33f..d941b90ad5 100644 --- a/public/components/event_analytics/explorer/explorer.tsx +++ b/public/components/event_analytics/explorer/explorer.tsx @@ -958,6 +958,7 @@ export const Explorer = ({ selectedTab={contentTabs.find((tab) => tab.id === selectedContentTabId)} onTabClick={(selectedTab: EuiTabbedContentTab) => handleContentTabClick(selectedTab)} tabs={contentTabs} + size="s" />
    diff --git a/public/components/event_analytics/explorer/log_explorer.tsx b/public/components/event_analytics/explorer/log_explorer.tsx index b9e20a37ac..05ff167563 100644 --- a/public/components/event_analytics/explorer/log_explorer.tsx +++ b/public/components/event_analytics/explorer/log_explorer.tsx @@ -218,6 +218,7 @@ export const LogExplorer = ({ selectedTab={memorizedTabs.find((tab) => tab.id === curSelectedTabId)} onTabClick={(selectedTab: EuiTabbedContentTab) => handleTabClick(selectedTab)} data-test-subj="eventExplorer__topLevelTabbing" + size="s" /> ); From 786034dc6ea4d3ea74fa04758ee2234865aa029d Mon Sep 17 00:00:00 2001 From: Eric Wei Date: Wed, 5 Apr 2023 09:08:19 -0700 Subject: [PATCH 57/73] use scss variable, make query tab more condense Signed-off-by: Eric Wei --- .../event_analytics/explorer/log_explorer.scss | 6 +++--- public/variables.scss | 9 +++++++++ 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/public/components/event_analytics/explorer/log_explorer.scss b/public/components/event_analytics/explorer/log_explorer.scss index 772a5b873b..f8c25dac73 100644 --- a/public/components/event_analytics/explorer/log_explorer.scss +++ b/public/components/event_analytics/explorer/log_explorer.scss @@ -14,12 +14,12 @@ svg { vertical-align: inherit; } - .linkNewTag{ + .linkNewTag { display: inline-block; text-align: center; font-size: 0.875rem; - line-height: 3.5; - padding: 0.5rem; + line-height: $tab-new-line-height; + padding: $tab-new-padding; // align with content tab with small size min-width: 6rem; } } diff --git a/public/variables.scss b/public/variables.scss index 943d507498..066b77f13f 100644 --- a/public/variables.scss +++ b/public/variables.scss @@ -3,5 +3,14 @@ * SPDX-License-Identifier: Apache-2.0 */ +/** Shard **/ +$content-tab-padding: 8px; + // dark mode border color $border-color-on-dark: #343741; + +/** Event Analytics **/ + +// add-new tab +$tab-new-line-height: 3; +$tab-new-padding: $content-tab-padding; \ No newline at end of file From 4578974a5700680a191275bd6580495b034dc86d Mon Sep 17 00:00:00 2001 From: Eric Wei Date: Wed, 5 Apr 2023 09:22:21 -0700 Subject: [PATCH 58/73] adjust line height again to make tab more condense to address review feedback Signed-off-by: Eric Wei --- public/variables.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/variables.scss b/public/variables.scss index 066b77f13f..8849b6e197 100644 --- a/public/variables.scss +++ b/public/variables.scss @@ -12,5 +12,5 @@ $border-color-on-dark: #343741; /** Event Analytics **/ // add-new tab -$tab-new-line-height: 3; +$tab-new-line-height: 2.7; $tab-new-padding: $content-tab-padding; \ No newline at end of file From 8d0e51728a394e55dd9a919eee5211fa030ba36b Mon Sep 17 00:00:00 2001 From: Eric Wei Date: Wed, 5 Apr 2023 12:02:34 -0700 Subject: [PATCH 59/73] fix update viz button issue Signed-off-by: Eric Wei --- public/components/event_analytics/explorer/explorer.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/public/components/event_analytics/explorer/explorer.tsx b/public/components/event_analytics/explorer/explorer.tsx index d941b90ad5..50086e805f 100644 --- a/public/components/event_analytics/explorer/explorer.tsx +++ b/public/components/event_analytics/explorer/explorer.tsx @@ -910,6 +910,7 @@ export const Explorer = ({ pplService, notifications, dispatch, + handleQueryChange, }} >
    Date: Thu, 6 Apr 2023 21:51:33 +0000 Subject: [PATCH 60/73] Update ppl icon Signed-off-by: Joshua Li --- public/embeddable/observability_embeddable.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/embeddable/observability_embeddable.tsx b/public/embeddable/observability_embeddable.tsx index a36755744d..42664f8111 100644 --- a/public/embeddable/observability_embeddable.tsx +++ b/public/embeddable/observability_embeddable.tsx @@ -25,7 +25,7 @@ export const OBSERVABILITY_EMBEDDABLE_ID = 'observability-ppl'; export const OBSERVABILITY_EMBEDDABLE_DISPLAY_NAME = 'PPL'; export const OBSERVABILITY_EMBEDDABLE_DESCRIPTION = 'Create a visualization with Piped Processing Language (PPL). PPL can query data in your indices and also supports federated data sources like Prometheus'; -export const OBSERVABILITY_EMBEDDABLE_ICON = 'lensApp'; +export const OBSERVABILITY_EMBEDDABLE_ICON = 'visQueryPPL'; export interface ObservabilityOutput extends EmbeddableOutput { /** From a939098ff3ac04dd5fe53c446ac08b672ca4a1bb Mon Sep 17 00:00:00 2001 From: Joshua Li Date: Thu, 6 Apr 2023 23:55:54 +0000 Subject: [PATCH 61/73] Add mocks for unit test setup Signed-off-by: Joshua Li --- package.json | 7 +- test/__mocks__/coreMocks.ts | 22 ++---- test/jest.config.js | 7 +- test/setup.jest.ts | 22 +++++- yarn.lock | 143 +++++++++++++++++++++++++++++++++++- 5 files changed, 176 insertions(+), 25 deletions(-) diff --git a/package.json b/package.json index b909396096..cdd01ec2c6 100644 --- a/package.json +++ b/package.json @@ -30,13 +30,13 @@ "ag-grid-react": "^27.3.0", "antlr4": "4.8.0", "antlr4ts": "^0.5.0-alpha.4", + "performance-now": "^2.1.0", "plotly.js-dist": "^2.2.0", "postinstall": "^0.7.4", "react-graph-vis": "^1.0.5", "react-paginate": "^8.1.3", "react-plotly.js": "^2.5.1", - "redux-persist": "^6.0.0", - "performance-now": "^2.1.0" + "redux-persist": "^6.0.0" }, "devDependencies": { "@cypress/skip-test": "^2.6.1", @@ -48,7 +48,8 @@ "eslint": "^6.8.0", "husky": "6.0.0", "jest-dom": "^4.0.0", - "lint-staged": "^13.1.0" + "lint-staged": "^13.1.0", + "ts-jest": "^29.1.0" }, "resolutions": { "react-syntax-highlighter": "^15.4.3", diff --git a/test/__mocks__/coreMocks.ts b/test/__mocks__/coreMocks.ts index 5e2a10d8d1..101c27a127 100644 --- a/test/__mocks__/coreMocks.ts +++ b/test/__mocks__/coreMocks.ts @@ -3,25 +3,17 @@ * SPDX-License-Identifier: Apache-2.0 */ +import { of } from 'rxjs'; import { CoreStart } from '../../../../src/core/public'; +import { coreMock } from '../../../../src/core/public/mocks'; import httpClientMock from './httpClientMock'; -import { of } from 'rxjs'; +const coreStart = coreMock.createStart(); +coreStart.savedObjects.client.find = jest.fn(() => Promise.resolve({ savedObjects: [] })) as any; + +// TODO use coreMock for http const coreStartMock = ({ - uiSettings: { - get: jest.fn(), - }, - chrome: { - setBreadcrumbs: jest.fn(), - getIsNavDrawerLocked$: jest.fn(() => of(true)), - }, - notifications: { - toasts: { - addDanger: jest.fn().mockName('addDanger'), - addSuccess: jest.fn().mockName('addSuccess'), - addError: jest.fn().mockName('addError'), - }, - }, + ...coreStart, http: httpClientMock, } as unknown) as CoreStart; diff --git a/test/jest.config.js b/test/jest.config.js index 7ce1f85d8e..b6fc147c15 100644 --- a/test/jest.config.js +++ b/test/jest.config.js @@ -21,12 +21,15 @@ module.exports = { '/test/', '/public/requests/', ], + transform: { + '^.+\\.tsx?$': ['ts-jest', { diagnostics: false }], + }, transformIgnorePatterns: ['/node_modules'], moduleNameMapper: { '\\.(css|less|sass|scss)$': '/test/__mocks__/styleMock.js', '\\.(gif|ttf|eot|svg|png)$': '/test/__mocks__/fileMock.js', '\\@algolia/autocomplete-theme-classic$': '/test/__mocks__/styleMock.js', - "^!!raw-loader!.*": "jest-raw-loader", + '^!!raw-loader!.*': 'jest-raw-loader', }, - testEnvironment: "jsdom", + testEnvironment: 'jsdom', }; diff --git a/test/setup.jest.ts b/test/setup.jest.ts index 4d14132895..7f612f9085 100644 --- a/test/setup.jest.ts +++ b/test/setup.jest.ts @@ -5,11 +5,13 @@ // import '@testing-library/jest-dom/extend-expect'; import { configure } from '@testing-library/react'; +import { setOSDHttp, setOSDSavedObjectsClient } from '../common/utils'; +import { coreStartMock } from './__mocks__/coreMocks'; configure({ testIdAttribute: 'data-test-subj' }); window.URL.createObjectURL = () => ''; -HTMLCanvasElement.prototype.getContext = () => ''; +HTMLCanvasElement.prototype.getContext = () => '' as any; window.IntersectionObserver = class IntersectionObserver { constructor() {} @@ -28,7 +30,7 @@ window.IntersectionObserver = class IntersectionObserver { unobserve() { return null; } -}; +} as any; jest.mock('@elastic/eui/lib/components/form/form_row/make_id', () => () => 'random-id'); @@ -38,4 +40,20 @@ jest.mock('@elastic/eui/lib/services/accessibility/html_id_generator', () => ({ }, })); +jest.mock('../public/services/saved_objects/saved_object_client/saved_objects_actions', () => { + return { + SavedObjectsActions: { + get: jest.fn().mockResolvedValue({ + observabilityObjectList: [], + }), + getBulk: jest.fn().mockResolvedValue({ + observabilityObjectList: [], + }), + }, + }; +}); + jest.setTimeout(30000); + +setOSDHttp(coreStartMock.http); +setOSDSavedObjectsClient(coreStartMock.savedObjects.client); diff --git a/yarn.lock b/yarn.lock index 6d0a6a27fb..13d4f5ca6e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -156,6 +156,25 @@ gud "^1.0.0" warning "^4.0.3" +"@jest/schemas@^29.4.3": + version "29.4.3" + resolved "https://registry.yarnpkg.com/@jest/schemas/-/schemas-29.4.3.tgz#39cf1b8469afc40b6f5a2baaa146e332c4151788" + integrity sha512-VLYKXQmtmuEz6IxJsrZwzG9NvtkQsWNnWMsKxqWNu3+CnfzJQhp0WDDKWLVV9hLKr0l3SLLFRqcYHjhtyuDVxg== + dependencies: + "@sinclair/typebox" "^0.25.16" + +"@jest/types@^29.5.0": + version "29.5.0" + resolved "https://registry.yarnpkg.com/@jest/types/-/types-29.5.0.tgz#f59ef9b031ced83047c67032700d8c807d6e1593" + integrity sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog== + dependencies: + "@jest/schemas" "^29.4.3" + "@types/istanbul-lib-coverage" "^2.0.0" + "@types/istanbul-reports" "^3.0.0" + "@types/node" "*" + "@types/yargs" "^17.0.8" + chalk "^4.0.0" + "@nteract/markdown@^4.5.2": version "4.6.2" resolved "https://registry.yarnpkg.com/@nteract/markdown/-/markdown-4.6.2.tgz#5e3dc44047f7af761b3fb8cf76f6d239e7bb65c3" @@ -211,6 +230,11 @@ dependencies: any-observable "^0.3.0" +"@sinclair/typebox@^0.25.16": + version "0.25.24" + resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.25.24.tgz#8c7688559979f7079aacaf31aa881c3aa410b718" + integrity sha512-XJfwUVUKDHF5ugKwIcxEgc9k8b7HbznCp6eUfWgu710hMPNIO4aw4/zB5RogDQz8nd6gyCDpU9O/m6qYEWY6yQ== + "@types/cheerio@*": version "0.22.30" resolved "https://registry.yarnpkg.com/@types/cheerio/-/cheerio-0.22.30.tgz#6c1ded70d20d890337f0f5144be2c5e9ce0936e6" @@ -250,6 +274,25 @@ dependencies: "@types/unist" "*" +"@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0": + version "2.0.4" + resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz#8467d4b3c087805d63580480890791277ce35c44" + integrity sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g== + +"@types/istanbul-lib-report@*": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz#c14c24f18ea8190c118ee7562b7ff99a36552686" + integrity sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg== + dependencies: + "@types/istanbul-lib-coverage" "*" + +"@types/istanbul-reports@^3.0.0": + version "3.0.1" + resolved "https://registry.yarnpkg.com/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz#9153fe98bba2bd565a63add9436d6f0d7f8468ff" + integrity sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw== + dependencies: + "@types/istanbul-lib-report" "*" + "@types/node@*": version "16.7.2" resolved "https://registry.yarnpkg.com/@types/node/-/node-16.7.2.tgz#0465a39b5456b61a04d98bd5545f8b34be340cb7" @@ -325,6 +368,18 @@ resolved "https://registry.yarnpkg.com/@types/unist/-/unist-2.0.6.tgz#250a7b16c3b91f672a24552ec64678eeb1d3a08d" integrity sha512-PBjIUxZHOuj0R15/xuwJYjFi+KZdNFrehocChv4g5hu6aFroHue8m0lBP0POdK2nKzbw0cgV1mws8+V/JAcEkQ== +"@types/yargs-parser@*": + version "21.0.0" + resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-21.0.0.tgz#0c60e537fa790f5f9472ed2776c2b71ec117351b" + integrity sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA== + +"@types/yargs@^17.0.8": + version "17.0.24" + resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-17.0.24.tgz#b3ef8d50ad4aa6aecf6ddc97c580a00f5aa11902" + integrity sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw== + dependencies: + "@types/yargs-parser" "*" + acorn-jsx@^5.2.0: version "5.3.2" resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" @@ -545,6 +600,13 @@ braces@^3.0.2: dependencies: fill-range "^7.0.1" +bs-logger@0.x: + version "0.2.6" + resolved "https://registry.yarnpkg.com/bs-logger/-/bs-logger-0.2.6.tgz#eb7d365307a72cf974cc6cda76b68354ad336bd8" + integrity sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog== + dependencies: + fast-json-stable-stringify "2.x" + buffer-crc32@~0.2.3: version "0.2.13" resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242" @@ -598,7 +660,7 @@ chalk@^2.0.0, chalk@^2.1.0, chalk@^2.4.1: escape-string-regexp "^1.0.5" supports-color "^5.3.0" -chalk@^4.1.0: +chalk@^4.0.0, chalk@^4.1.0: version "4.1.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== @@ -636,6 +698,11 @@ ci-info@^2.0.0: resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-2.0.0.tgz#67a9e964be31a51e15e5010d58e6f12834002f46" integrity sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ== +ci-info@^3.2.0: + version "3.8.0" + resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.8.0.tgz#81408265a5380c929f0bc665d62256628ce9ef91" + integrity sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw== + classnames@^2.2, classnames@^2.2.5, classnames@^2.2.6: version "2.3.1" resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.3.1.tgz#dfcfa3891e306ec1dad105d0e88f4417b8535e8e" @@ -1224,7 +1291,7 @@ fast-deep-equal@^3.1.1: resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== -fast-json-stable-stringify@^2.0.0: +fast-json-stable-stringify@2.x, fast-json-stable-stringify@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== @@ -1432,6 +1499,11 @@ graceful-fs@^4.1.6, graceful-fs@^4.2.0: resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.8.tgz#e412b8d33f5e006593cbd3cee6df9f2cebbe802a" integrity sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg== +graceful-fs@^4.2.9: + version "4.2.11" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" + integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== + gud@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/gud/-/gud-1.0.0.tgz#a489581b17e6a70beca9abe3ae57de7a499852c0" @@ -1810,6 +1882,18 @@ jest-dom@^4.0.0: resolved "https://registry.yarnpkg.com/jest-dom/-/jest-dom-4.0.0.tgz#94eba3cbc6576e7bd6821867c92d176de28920eb" integrity sha512-gBxYZlZB1Jgvf2gP2pRfjjUWF8woGBHj/g5rAQgFPB/0K2atGuhVcPO+BItyjWeKg9zM+dokgcMOH01vrWVMFA== +jest-util@^29.0.0: + version "29.5.0" + resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-29.5.0.tgz#24a4d3d92fc39ce90425311b23c27a6e0ef16b8f" + integrity sha512-RYMgG/MTadOr5t8KdhejfvUU82MxsCu5MF6KuDUHl+NuwzUt+Sm6jJWxTJVrDR1j5M/gJVCPKQEpWXY+yIQ6lQ== + dependencies: + "@jest/types" "^29.5.0" + "@types/node" "*" + chalk "^4.0.0" + ci-info "^3.2.0" + graceful-fs "^4.2.9" + picomatch "^2.2.3" + "js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" @@ -1848,6 +1932,11 @@ json-stringify-safe@~5.0.1: resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus= +json5@^2.2.3: + version "2.2.3" + resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283" + integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== + jsonfile@^6.0.1: version "6.1.0" resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-6.1.0.tgz#bc55b2634793c679ec6403094eb13698a6ec0aae" @@ -1982,6 +2071,11 @@ lodash.flow@^3.5.0: resolved "https://registry.yarnpkg.com/lodash.flow/-/lodash.flow-3.5.0.tgz#87bf40292b8cf83e4e8ce1a3ae4209e20071675a" integrity sha1-h79AKSuM+D5OjOGjrkIJ4gBxZ1o= +lodash.memoize@4.x: + version "4.1.2" + resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe" + integrity sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag== + lodash.once@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/lodash.once/-/lodash.once-4.1.1.tgz#0dd3971213c7c56df880977d504c88fb471a97ac" @@ -2041,6 +2135,18 @@ lowlight@^1.17.0: fault "^1.0.0" highlight.js "~10.7.0" +lru-cache@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" + integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== + dependencies: + yallist "^4.0.0" + +make-error@1.x: + version "1.3.6" + resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" + integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== + markdown-escapes@^1.0.0: version "1.0.4" resolved "https://registry.yarnpkg.com/markdown-escapes/-/markdown-escapes-1.0.4.tgz#c95415ef451499d7602b91095f3c8e8975f78535" @@ -2329,7 +2435,7 @@ performance-now@^2.1.0: resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns= -picomatch@^2.3.1: +picomatch@^2.2.3, picomatch@^2.3.1: version "2.3.1" resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== @@ -2777,6 +2883,13 @@ safe-buffer@~5.1.0, safe-buffer@~5.1.1: resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== +semver@7.x: + version "7.3.8" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.8.tgz#07a78feafb3f7b32347d725e33de7e2a2df67798" + integrity sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A== + dependencies: + lru-cache "^6.0.0" + semver@^5.5.0: version "5.7.1" resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" @@ -3106,6 +3219,20 @@ trough@^1.0.0: resolved "https://registry.yarnpkg.com/trough/-/trough-1.0.5.tgz#b8b639cefad7d0bb2abd37d433ff8293efa5f406" integrity sha512-rvuRbTarPXmMb79SmzEp8aqXNKcK+y0XaB298IXueQ8I2PsrATcPBCSPyK/dDNa2iWOhKlfNnOjdAOTBU/nkFA== +ts-jest@^29.1.0: + version "29.1.0" + resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-29.1.0.tgz#4a9db4104a49b76d2b368ea775b6c9535c603891" + integrity sha512-ZhNr7Z4PcYa+JjMl62ir+zPiNJfXJN6E8hSLnaUKhOgqcn8vb3e537cpkd0FuAfRK3sR1LSqM1MOhliXNgOFPA== + dependencies: + bs-logger "0.x" + fast-json-stable-stringify "2.x" + jest-util "^29.0.0" + json5 "^2.2.3" + lodash.memoize "4.x" + make-error "1.x" + semver "7.x" + yargs-parser "^21.0.1" + tslib@^1.9.0: version "1.14.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" @@ -3376,11 +3503,21 @@ xtend@^4.0.0, xtend@^4.0.1: resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== +yallist@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" + integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== + yaml@^2.1.3: version "2.2.1" resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.2.1.tgz#3014bf0482dcd15147aa8e56109ce8632cd60ce4" integrity sha512-e0WHiYql7+9wr4cWMx3TVQrNwejKaEe7/rHNmQmqRjazfOP5W8PB6Jpebb5o6fIapbz9o9+2ipcaTM2ZwDI6lw== +yargs-parser@^21.0.1: + version "21.1.1" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.1.1.tgz#9096bceebf990d21bb31fa9516e0ede294a77d35" + integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw== + yauzl@^2.10.0: version "2.10.0" resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.10.0.tgz#c7eb17c93e112cb1086fa6d8e51fb0667b79a5f9" From 0ab84f2029d0fb563ffe37c35058f9591bff29a2 Mon Sep 17 00:00:00 2001 From: Joshua Li Date: Thu, 6 Apr 2023 23:56:14 +0000 Subject: [PATCH 62/73] Update jest snapshots Signed-off-by: Joshua Li --- .../__snapshots__/log_config.test.tsx.snap | 104 +- .../service_config.test.tsx.snap | 96 +- .../__snapshots__/trace_config.test.tsx.snap | 96 +- .../live_tail_button.test.tsx.snap | 12 +- .../custom_panel_table.test.tsx.snap | 8 +- .../custom_panel_view.test.tsx.snap | 1042 +++++++++++++++-- .../__snapshots__/utils.test.tsx.snap | 36 +- .../__snapshots__/empty_panel.test.tsx.snap | 16 +- .../__snapshots__/panel_grid.test.tsx.snap | 197 +++- .../visualization_container.test.tsx.snap | 4 +- .../visualization_flyout.test.tsx.snap | 16 +- .../__snapshots__/no_results.test.tsx.snap | 4 +- .../patterns_header.test.tsx.snap | 4 +- .../__snapshots__/save_panel.test.tsx.snap | 4 +- .../__snapshots__/field.test.tsx.snap | 4 +- .../__snapshots__/sidebar.test.tsx.snap | 112 +- .../__snapshots__/config_panel.test.tsx.snap | 80 +- .../count_distribution.test.tsx.snap | 6 +- .../shared_components.test.tsx.snap | 12 +- .../__snapshots__/searchbar.test.tsx.snap | 8 +- .../__snapshots__/sidebar.test.tsx.snap | 16 +- .../metrics_export_panel.test.tsx.snap | 4 +- .../__snapshots__/top_menu.test.tsx.snap | 24 +- .../__snapshots__/empty_view.test.tsx.snap | 4 +- .../__snapshots__/metrics_grid.test.tsx.snap | 209 +++- .../__snapshots__/dashboard.test.tsx.snap | 264 +++++ .../__snapshots__/services.test.tsx.snap | 264 +++++ .../__snapshots__/traces.test.tsx.snap | 264 +++++ .../__snapshots__/assets.test.tsx.snap | 12 +- .../__tests__/__snapshots__/bar.test.tsx.snap | 4 +- .../__snapshots__/gauge.test.tsx.snap | 8 +- .../__snapshots__/heatmap.test.tsx.snap | 4 +- .../__snapshots__/histogram.test.tsx.snap | 4 +- .../horizontal_bar.test.tsx.snap | 4 +- .../__snapshots__/line.test.tsx.snap | 4 +- .../__snapshots__/metrics.test.tsx.snap | 8 +- .../__tests__/__snapshots__/pie.test.tsx.snap | 4 +- .../__snapshots__/text.test.tsx.snap | 4 +- .../__snapshots__/treemap.test.tsx.snap | 4 +- 39 files changed, 2619 insertions(+), 351 deletions(-) diff --git a/public/components/application_analytics/__tests__/__snapshots__/log_config.test.tsx.snap b/public/components/application_analytics/__tests__/__snapshots__/log_config.test.tsx.snap index 18c3c8847e..22fb592954 100644 --- a/public/components/application_analytics/__tests__/__snapshots__/log_config.test.tsx.snap +++ b/public/components/application_analytics/__tests__/__snapshots__/log_config.test.tsx.snap @@ -1,12 +1,56 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`Log Config component renders empty log config 1`] = ` - -
    - +
    - + `; exports[`Log Config component renders with query 1`] = ` - -
    - +
    - + `; diff --git a/public/components/application_analytics/__tests__/__snapshots__/service_config.test.tsx.snap b/public/components/application_analytics/__tests__/__snapshots__/service_config.test.tsx.snap index 8b128989e8..f6bc62f39e 100644 --- a/public/components/application_analytics/__tests__/__snapshots__/service_config.test.tsx.snap +++ b/public/components/application_analytics/__tests__/__snapshots__/service_config.test.tsx.snap @@ -1,12 +1,56 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`Service Config component renders empty service config 1`] = ` -
    - + `; exports[`Service Config component renders with one service selected 1`] = ` -
    - + `; diff --git a/public/components/application_analytics/__tests__/__snapshots__/trace_config.test.tsx.snap b/public/components/application_analytics/__tests__/__snapshots__/trace_config.test.tsx.snap index ef6b391eeb..b0856bbf70 100644 --- a/public/components/application_analytics/__tests__/__snapshots__/trace_config.test.tsx.snap +++ b/public/components/application_analytics/__tests__/__snapshots__/trace_config.test.tsx.snap @@ -1,11 +1,55 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`Trace Config component renders empty trace config 1`] = ` -
    - + `; exports[`Trace Config component renders with one trace selected 1`] = ` -
    - + `; diff --git a/public/components/common/live_tail/__tests__/__snapshots__/live_tail_button.test.tsx.snap b/public/components/common/live_tail/__tests__/__snapshots__/live_tail_button.test.tsx.snap index 78104e6528..11e8fae851 100644 --- a/public/components/common/live_tail/__tests__/__snapshots__/live_tail_button.test.tsx.snap +++ b/public/components/common/live_tail/__tests__/__snapshots__/live_tail_button.test.tsx.snap @@ -1,7 +1,7 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`Live tail button change live tail to 10s interval 1`] = ` - - + `; exports[`Live tail button starts live tail with 5s interval 1`] = ` - - + `; exports[`Live tail off button stop live tail 1`] = ` - @@ -271,5 +271,5 @@ exports[`Live tail off button stop live tail 1`] = ` - + `; diff --git a/public/components/custom_panels/__tests__/__snapshots__/custom_panel_table.test.tsx.snap b/public/components/custom_panels/__tests__/__snapshots__/custom_panel_table.test.tsx.snap index 334a937749..337b013063 100644 --- a/public/components/custom_panels/__tests__/__snapshots__/custom_panel_table.test.tsx.snap +++ b/public/components/custom_panels/__tests__/__snapshots__/custom_panel_table.test.tsx.snap @@ -1,7 +1,7 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`Panels Table Component renders empty panel table container 1`] = ` -
    - + `; exports[`Panels Table Component renders panel table container 1`] = ` -
    - + `; diff --git a/public/components/custom_panels/__tests__/__snapshots__/custom_panel_view.test.tsx.snap b/public/components/custom_panels/__tests__/__snapshots__/custom_panel_view.test.tsx.snap index ab362302d2..7b2eda6f26 100644 --- a/public/components/custom_panels/__tests__/__snapshots__/custom_panel_view.test.tsx.snap +++ b/public/components/custom_panels/__tests__/__snapshots__/custom_panel_view.test.tsx.snap @@ -1,47 +1,319 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`Panels View Component renders panel view container with visualizations 1`] = ` - - @@ -501,7 +777,7 @@ exports[`Panels View Component renders panel view container with visualizations
    - + @@ -524,7 +800,7 @@ exports[`Panels View Component renders panel view container with visualizations
    -
    - + - @@ -1304,7 +1580,7 @@ exports[`Panels View Component renders panel view container with visualizations
    - @@ -1423,7 +1699,7 @@ exports[`Panels View Component renders panel view container with visualizations
    - +
    @@ -1436,48 +1712,320 @@ exports[`Panels View Component renders panel view container with visualizations /> - - + - + @@ -1639,51 +2191,212 @@ exports[`Panels View Component renders panel view container with visualizations - + `; exports[`Panels View Component renders panel view container without visualizations 1`] = ` - - @@ -2129,7 +2846,7 @@ exports[`Panels View Component renders panel view container without visualizatio - + @@ -2152,7 +2869,7 @@ exports[`Panels View Component renders panel view container without visualizatio
    -
    - + - @@ -2918,7 +3635,7 @@ exports[`Panels View Component renders panel view container without visualizatio
    - @@ -3032,7 +3749,7 @@ exports[`Panels View Component renders panel view container without visualizatio
    - +
    @@ -3045,48 +3762,209 @@ exports[`Panels View Component renders panel view container without visualizatio /> - - + - + @@ -3248,5 +4130,5 @@ exports[`Panels View Component renders panel view container without visualizatio -
    + `; diff --git a/public/components/custom_panels/helpers/__tests__/__snapshots__/utils.test.tsx.snap b/public/components/custom_panels/helpers/__tests__/__snapshots__/utils.test.tsx.snap index ae12e1b7df..b701ecfa49 100644 --- a/public/components/custom_panels/helpers/__tests__/__snapshots__/utils.test.tsx.snap +++ b/public/components/custom_panels/helpers/__tests__/__snapshots__/utils.test.tsx.snap @@ -2,7 +2,7 @@ exports[`Utils helper functions renders displayVisualization function 1`] = `
    - - - - - - + + +
    `; exports[`Utils helper functions renders displayVisualization function 2`] = `
    - - - - - - + + +
    `; exports[`Utils helper functions renders displayVisualization function 3`] = `
    - - - - - - + + +
    `; diff --git a/public/components/custom_panels/panel_modules/__tests__/__snapshots__/empty_panel.test.tsx.snap b/public/components/custom_panels/panel_modules/__tests__/__snapshots__/empty_panel.test.tsx.snap index 3992459037..b9c1ad5905 100644 --- a/public/components/custom_panels/panel_modules/__tests__/__snapshots__/empty_panel.test.tsx.snap +++ b/public/components/custom_panels/panel_modules/__tests__/__snapshots__/empty_panel.test.tsx.snap @@ -1,7 +1,7 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`Empty panel view component renders empty panel view with disabled popover 1`] = ` - @@ -79,7 +79,7 @@ exports[`Empty panel view component renders empty panel view with disabled popov
    - @@ -193,7 +193,7 @@ exports[`Empty panel view component renders empty panel view with disabled popov
    - + @@ -206,11 +206,11 @@ exports[`Empty panel view component renders empty panel view with disabled popov /> -
    + `; exports[`Empty panel view component renders empty panel view with enabled popover 1`] = ` - @@ -288,7 +288,7 @@ exports[`Empty panel view component renders empty panel view with enabled popove
    - @@ -407,7 +407,7 @@ exports[`Empty panel view component renders empty panel view with enabled popove
    - + @@ -420,5 +420,5 @@ exports[`Empty panel view component renders empty panel view with enabled popove /> -
    + `; diff --git a/public/components/custom_panels/panel_modules/panel_grid/__tests__/__snapshots__/panel_grid.test.tsx.snap b/public/components/custom_panels/panel_modules/panel_grid/__tests__/__snapshots__/panel_grid.test.tsx.snap index b192dff2d8..04f722aaa3 100644 --- a/public/components/custom_panels/panel_modules/panel_grid/__tests__/__snapshots__/panel_grid.test.tsx.snap +++ b/public/components/custom_panels/panel_modules/panel_grid/__tests__/__snapshots__/panel_grid.test.tsx.snap @@ -1,48 +1,213 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`Panel Grid Component renders panel grid component with empty visualizations 1`] = ` - - + `; diff --git a/public/components/custom_panels/panel_modules/visualization_container/__tests__/__snapshots__/visualization_container.test.tsx.snap b/public/components/custom_panels/panel_modules/visualization_container/__tests__/__snapshots__/visualization_container.test.tsx.snap index 778d6e1674..4ba3e3ec34 100644 --- a/public/components/custom_panels/panel_modules/visualization_container/__tests__/__snapshots__/visualization_container.test.tsx.snap +++ b/public/components/custom_panels/panel_modules/visualization_container/__tests__/__snapshots__/visualization_container.test.tsx.snap @@ -1,7 +1,7 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`Visualization Container Component renders add visualization container 1`] = ` - - + `; diff --git a/public/components/custom_panels/panel_modules/visualization_flyout/__tests__/__snapshots__/visualization_flyout.test.tsx.snap b/public/components/custom_panels/panel_modules/visualization_flyout/__tests__/__snapshots__/visualization_flyout.test.tsx.snap index 6b9d3e801c..7049259cbd 100644 --- a/public/components/custom_panels/panel_modules/visualization_flyout/__tests__/__snapshots__/visualization_flyout.test.tsx.snap +++ b/public/components/custom_panels/panel_modules/visualization_flyout/__tests__/__snapshots__/visualization_flyout.test.tsx.snap @@ -1,7 +1,7 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`Visualization Flyout Component renders add visualization Flyout 1`] = ` - - - - + + `; exports[`Visualization Flyout Component renders replace visualization Flyout 1`] = ` - - - - + + `; diff --git a/public/components/event_analytics/__tests__/__snapshots__/no_results.test.tsx.snap b/public/components/event_analytics/__tests__/__snapshots__/no_results.test.tsx.snap index a128191e44..50c496076a 100644 --- a/public/components/event_analytics/__tests__/__snapshots__/no_results.test.tsx.snap +++ b/public/components/event_analytics/__tests__/__snapshots__/no_results.test.tsx.snap @@ -1,7 +1,7 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`No result component Renders No result component 1`] = ` - + - + `; diff --git a/public/components/event_analytics/explorer/log_patterns/__tests__/__snapshots__/patterns_header.test.tsx.snap b/public/components/event_analytics/explorer/log_patterns/__tests__/__snapshots__/patterns_header.test.tsx.snap index 8777405139..2ce4cbd870 100644 --- a/public/components/event_analytics/explorer/log_patterns/__tests__/__snapshots__/patterns_header.test.tsx.snap +++ b/public/components/event_analytics/explorer/log_patterns/__tests__/__snapshots__/patterns_header.test.tsx.snap @@ -1,7 +1,7 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`Patterns header component Renders header of log patterns 1`] = ` - - + `; diff --git a/public/components/event_analytics/explorer/save_panel/__tests__/__snapshots__/save_panel.test.tsx.snap b/public/components/event_analytics/explorer/save_panel/__tests__/__snapshots__/save_panel.test.tsx.snap index dce6acd735..acc9e820ea 100644 --- a/public/components/event_analytics/explorer/save_panel/__tests__/__snapshots__/save_panel.test.tsx.snap +++ b/public/components/event_analytics/explorer/save_panel/__tests__/__snapshots__/save_panel.test.tsx.snap @@ -1,7 +1,7 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`Saved query table component Renders saved query table 1`] = ` - - + `; diff --git a/public/components/event_analytics/explorer/sidebar/__tests__/__snapshots__/field.test.tsx.snap b/public/components/event_analytics/explorer/sidebar/__tests__/__snapshots__/field.test.tsx.snap index 35c8c3a91d..8ec133b20d 100644 --- a/public/components/event_analytics/explorer/sidebar/__tests__/__snapshots__/field.test.tsx.snap +++ b/public/components/event_analytics/explorer/sidebar/__tests__/__snapshots__/field.test.tsx.snap @@ -1,7 +1,7 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`Field component Renders a sidebar field 1`] = ` - - + `; diff --git a/public/components/event_analytics/explorer/sidebar/__tests__/__snapshots__/sidebar.test.tsx.snap b/public/components/event_analytics/explorer/sidebar/__tests__/__snapshots__/sidebar.test.tsx.snap index 1d5a67a003..cffedeeb51 100644 --- a/public/components/event_analytics/explorer/sidebar/__tests__/__snapshots__/sidebar.test.tsx.snap +++ b/public/components/event_analytics/explorer/sidebar/__tests__/__snapshots__/sidebar.test.tsx.snap @@ -12,7 +12,7 @@ exports[`Siderbar component Renders empty sidebar component 1`] = ` } } > - - + `; @@ -233,7 +233,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` } } > - - - +
  • - - +
  • - - +
  • - - +
  • - - +
  • - - +
  • @@ -2909,7 +2909,7 @@ exports[`Siderbar component Renders sidebar component 1`] = ` data-attr-field="agent" key="fieldagent" > - - +
  • - - +
  • - - +
  • - - +
  • - - +
  • - - +
  • - - +
  • - - +
  • - - +
  • - - +
  • - - +
  • - - +
  • - - +
  • - - +
  • - - +
  • - - +
  • - - +
  • - - +
  • - - +
  • - - +
  • @@ -10060,6 +10060,6 @@ exports[`Siderbar component Renders sidebar component 1`] = ` -
    + `; diff --git a/public/components/event_analytics/explorer/visualizations/config_panel/__tests__/__snapshots__/config_panel.test.tsx.snap b/public/components/event_analytics/explorer/visualizations/config_panel/__tests__/__snapshots__/config_panel.test.tsx.snap index 7dfcd0eb80..67c7e58376 100644 --- a/public/components/event_analytics/explorer/visualizations/config_panel/__tests__/__snapshots__/config_panel.test.tsx.snap +++ b/public/components/event_analytics/explorer/visualizations/config_panel/__tests__/__snapshots__/config_panel.test.tsx.snap @@ -1,7 +1,7 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`Config panel component Renders config panel with visualization data 1`] = ` - - - - + @@ -8295,7 +8295,7 @@ exports[`Config panel component Renders config panel with visualization data 1`]
    - -
    - + @@ -9375,7 +9375,7 @@ exports[`Config panel component Renders config panel with visualization data 1`]
    -
    - + @@ -9751,7 +9751,7 @@ exports[`Config panel component Renders config panel with visualization data 1`] - + @@ -9770,7 +9770,7 @@ exports[`Config panel component Renders config panel with visualization data 1`]
    - -
    - + @@ -10845,7 +10845,7 @@ exports[`Config panel component Renders config panel with visualization data 1`] className="euiSpacer euiSpacer--s" /> - - + @@ -11119,7 +11119,7 @@ exports[`Config panel component Renders config panel with visualization data 1`] className="euiSpacer euiSpacer--s" /> - - + @@ -11197,7 +11197,7 @@ exports[`Config panel component Renders config panel with visualization data 1`] - + @@ -11216,7 +11216,7 @@ exports[`Config panel component Renders config panel with visualization data 1`]
    - -
    - + @@ -12344,7 +12344,7 @@ exports[`Config panel component Renders config panel with visualization data 1`] className="euiSpacer euiSpacer--s" /> - - + @@ -12415,7 +12415,7 @@ exports[`Config panel component Renders config panel with visualization data 1`] className="euiSpacer euiSpacer--s" /> - - + @@ -13400,7 +13400,7 @@ exports[`Config panel component Renders config panel with visualization data 1`] className="euiSpacer euiSpacer--s" /> - - + @@ -13641,7 +13641,7 @@ exports[`Config panel component Renders config panel with visualization data 1`] className="euiSpacer euiSpacer--s" /> - - + @@ -13882,7 +13882,7 @@ exports[`Config panel component Renders config panel with visualization data 1`] className="euiSpacer euiSpacer--s" /> - - + @@ -14123,7 +14123,7 @@ exports[`Config panel component Renders config panel with visualization data 1`] className="euiSpacer euiSpacer--s" /> - - + @@ -14370,7 +14370,7 @@ exports[`Config panel component Renders config panel with visualization data 1`] - + @@ -14389,7 +14389,7 @@ exports[`Config panel component Renders config panel with visualization data 1`]
    -
    - + -
    +
    - + `; diff --git a/public/components/event_analytics/explorer/visualizations/count_distribution/__tests__/__snapshots__/count_distribution.test.tsx.snap b/public/components/event_analytics/explorer/visualizations/count_distribution/__tests__/__snapshots__/count_distribution.test.tsx.snap index caaac78ac4..03e9b3fb44 100644 --- a/public/components/event_analytics/explorer/visualizations/count_distribution/__tests__/__snapshots__/count_distribution.test.tsx.snap +++ b/public/components/event_analytics/explorer/visualizations/count_distribution/__tests__/__snapshots__/count_distribution.test.tsx.snap @@ -1,7 +1,7 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`Count distribution component Renders count distribution component with data 1`] = ` - - + `; -exports[`Count distribution component Renders empty count distribution component 1`] = ``; +exports[`Count distribution component Renders empty count distribution component 1`] = ``; diff --git a/public/components/event_analytics/explorer/visualizations/shared_components/__tests__/__snapshots__/shared_components.test.tsx.snap b/public/components/event_analytics/explorer/visualizations/shared_components/__tests__/__snapshots__/shared_components.test.tsx.snap index f409c4a8d0..adb37ebb1e 100644 --- a/public/components/event_analytics/explorer/visualizations/shared_components/__tests__/__snapshots__/shared_components.test.tsx.snap +++ b/public/components/event_analytics/explorer/visualizations/shared_components/__tests__/__snapshots__/shared_components.test.tsx.snap @@ -1,7 +1,7 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`Shared components Renders empty placeholder component 1`] = ` - - - + - + `; exports[`Shared components Renders tool bar button component 1`] = ` - @@ -203,5 +203,5 @@ exports[`Shared components Renders tool bar button component 1`] = ` - + `; diff --git a/public/components/metrics/sidebar/__tests__/__snapshots__/searchbar.test.tsx.snap b/public/components/metrics/sidebar/__tests__/__snapshots__/searchbar.test.tsx.snap index 1a271b63c5..c4fcb663bf 100644 --- a/public/components/metrics/sidebar/__tests__/__snapshots__/searchbar.test.tsx.snap +++ b/public/components/metrics/sidebar/__tests__/__snapshots__/searchbar.test.tsx.snap @@ -12,7 +12,7 @@ exports[`Search Bar Component Search Side Bar Component with available metrics 1 } } > -
    @@ -145,7 +145,7 @@ exports[`Search Bar Component Search Side Bar Component with available metrics 1
    -
    + `; @@ -161,7 +161,7 @@ exports[`Search Bar Component Search Side Bar Component with no available metric } } > -
    @@ -290,6 +290,6 @@ exports[`Search Bar Component Search Side Bar Component with no available metric
    -
    + `; diff --git a/public/components/metrics/sidebar/__tests__/__snapshots__/sidebar.test.tsx.snap b/public/components/metrics/sidebar/__tests__/__snapshots__/sidebar.test.tsx.snap index b4ba2e2b76..7ce02dc762 100644 --- a/public/components/metrics/sidebar/__tests__/__snapshots__/sidebar.test.tsx.snap +++ b/public/components/metrics/sidebar/__tests__/__snapshots__/sidebar.test.tsx.snap @@ -12,7 +12,7 @@ exports[`Side Bar Component renders Side Bar Component 1`] = ` } } > - - - + @@ -222,7 +222,7 @@ exports[`Side Bar Component renders Side Bar Component 1`] = ` className="euiSpacer euiSpacer--s" /> - - + @@ -333,7 +333,7 @@ exports[`Side Bar Component renders Side Bar Component 1`] = ` className="euiSpacer euiSpacer--s" /> - - + - + `; diff --git a/public/components/metrics/top_menu/__tests__/__snapshots__/metrics_export_panel.test.tsx.snap b/public/components/metrics/top_menu/__tests__/__snapshots__/metrics_export_panel.test.tsx.snap index f9101b0eab..2801c6f679 100644 --- a/public/components/metrics/top_menu/__tests__/__snapshots__/metrics_export_panel.test.tsx.snap +++ b/public/components/metrics/top_menu/__tests__/__snapshots__/metrics_export_panel.test.tsx.snap @@ -12,7 +12,7 @@ exports[`Export Metrics Panel Component renders Export Metrics Panel Component 1 } } > - - + `; diff --git a/public/components/metrics/top_menu/__tests__/__snapshots__/top_menu.test.tsx.snap b/public/components/metrics/top_menu/__tests__/__snapshots__/top_menu.test.tsx.snap index edf4f44904..1e637705f6 100644 --- a/public/components/metrics/top_menu/__tests__/__snapshots__/top_menu.test.tsx.snap +++ b/public/components/metrics/top_menu/__tests__/__snapshots__/top_menu.test.tsx.snap @@ -12,7 +12,7 @@ exports[`Metrics Top Menu Component renders Top Menu Component when disabled in } } > - - +
    -
    + @@ -1338,7 +1338,7 @@ exports[`Metrics Top Menu Component renders Top Menu Component when disabled in -
    + `; @@ -1354,7 +1354,7 @@ exports[`Metrics Top Menu Component renders Top Menu Component when disabled wit } } > - - +
    -
    + @@ -2570,7 +2570,7 @@ exports[`Metrics Top Menu Component renders Top Menu Component when disabled wit -
    + `; @@ -2586,7 +2586,7 @@ exports[`Metrics Top Menu Component renders Top Menu Component when enabled 1`] } } > - - +
    -
    + @@ -3794,6 +3794,6 @@ exports[`Metrics Top Menu Component renders Top Menu Component when enabled 1`] -
    + `; diff --git a/public/components/metrics/view/__tests__/__snapshots__/empty_view.test.tsx.snap b/public/components/metrics/view/__tests__/__snapshots__/empty_view.test.tsx.snap index c9427636e0..b8a327d4bb 100644 --- a/public/components/metrics/view/__tests__/__snapshots__/empty_view.test.tsx.snap +++ b/public/components/metrics/view/__tests__/__snapshots__/empty_view.test.tsx.snap @@ -1,7 +1,7 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`Empty View Component renders empty view container without metrics 1`] = ` - +
    -
    + `; diff --git a/public/components/metrics/view/__tests__/__snapshots__/metrics_grid.test.tsx.snap b/public/components/metrics/view/__tests__/__snapshots__/metrics_grid.test.tsx.snap index 381df4aae7..b8e25d8b37 100644 --- a/public/components/metrics/view/__tests__/__snapshots__/metrics_grid.test.tsx.snap +++ b/public/components/metrics/view/__tests__/__snapshots__/metrics_grid.test.tsx.snap @@ -12,48 +12,213 @@ exports[`Metrics Grid Component renders Metrics Grid Component 1`] = ` } } > - - - + - - + - - + - + `; diff --git a/public/components/trace_analytics/components/dashboard/__tests__/__snapshots__/dashboard.test.tsx.snap b/public/components/trace_analytics/components/dashboard/__tests__/__snapshots__/dashboard.test.tsx.snap index 452952c19a..f7e00be9bf 100644 --- a/public/components/trace_analytics/components/dashboard/__tests__/__snapshots__/dashboard.test.tsx.snap +++ b/public/components/trace_analytics/components/dashboard/__tests__/__snapshots__/dashboard.test.tsx.snap @@ -17,7 +17,47 @@ exports[`Dashboard component renders dashboard 1`] = ` } chrome={ Object { + "addApplicationClass": [MockFunction], + "docTitle": Object { + "change": [MockFunction], + "reset": [MockFunction], + }, + "getApplicationClasses$": [MockFunction], + "getBadge$": [MockFunction], + "getBrand$": [MockFunction], + "getBreadcrumbs$": [MockFunction], + "getCustomNavLink$": [MockFunction], + "getHeaderComponent": [MockFunction], + "getHelpExtension$": [MockFunction], "getIsNavDrawerLocked$": [MockFunction], + "getIsVisible$": [MockFunction], + "navControls": Object { + "getCenter$": [MockFunction], + "getLeft$": [MockFunction], + "getRight$": [MockFunction], + "registerCenter": [MockFunction], + "registerLeft": [MockFunction], + "registerRight": [MockFunction], + }, + "navLinks": Object { + "enableForcedAppSwitcherNavigation": [MockFunction], + "get": [MockFunction], + "getAll": [MockFunction], + "getForceAppSwitcherNavigation$": [MockFunction], + "getNavLinks$": [MockFunction], + "has": [MockFunction], + "showOnly": [MockFunction], + "update": [MockFunction], + }, + "recentlyAccessed": Object { + "add": [MockFunction], + "get": [MockFunction], + "get$": [MockFunction], + }, + "removeApplicationClass": [MockFunction], + "setAppTitle": [MockFunction], + "setBadge": [MockFunction], + "setBrand": [MockFunction], "setBreadcrumbs": [MockFunction] { "calls": Array [ Array [ @@ -44,6 +84,10 @@ exports[`Dashboard component renders dashboard 1`] = ` }, ], }, + "setCustomNavLink": [MockFunction], + "setHelpExtension": [MockFunction], + "setHelpSupportUrl": [MockFunction], + "setIsVisible": [MockFunction], } } dataPrepperIndicesExist={true} @@ -245,7 +289,47 @@ exports[`Dashboard component renders dashboard 1`] = ` } chrome={ Object { + "addApplicationClass": [MockFunction], + "docTitle": Object { + "change": [MockFunction], + "reset": [MockFunction], + }, + "getApplicationClasses$": [MockFunction], + "getBadge$": [MockFunction], + "getBrand$": [MockFunction], + "getBreadcrumbs$": [MockFunction], + "getCustomNavLink$": [MockFunction], + "getHeaderComponent": [MockFunction], + "getHelpExtension$": [MockFunction], "getIsNavDrawerLocked$": [MockFunction], + "getIsVisible$": [MockFunction], + "navControls": Object { + "getCenter$": [MockFunction], + "getLeft$": [MockFunction], + "getRight$": [MockFunction], + "registerCenter": [MockFunction], + "registerLeft": [MockFunction], + "registerRight": [MockFunction], + }, + "navLinks": Object { + "enableForcedAppSwitcherNavigation": [MockFunction], + "get": [MockFunction], + "getAll": [MockFunction], + "getForceAppSwitcherNavigation$": [MockFunction], + "getNavLinks$": [MockFunction], + "has": [MockFunction], + "showOnly": [MockFunction], + "update": [MockFunction], + }, + "recentlyAccessed": Object { + "add": [MockFunction], + "get": [MockFunction], + "get$": [MockFunction], + }, + "removeApplicationClass": [MockFunction], + "setAppTitle": [MockFunction], + "setBadge": [MockFunction], + "setBrand": [MockFunction], "setBreadcrumbs": [MockFunction] { "calls": Array [ Array [ @@ -272,6 +356,10 @@ exports[`Dashboard component renders dashboard 1`] = ` }, ], }, + "setCustomNavLink": [MockFunction], + "setHelpExtension": [MockFunction], + "setHelpSupportUrl": [MockFunction], + "setIsVisible": [MockFunction], } } dataPrepperIndicesExist={true} @@ -2293,7 +2381,47 @@ exports[`Dashboard component renders empty dashboard 1`] = ` } chrome={ Object { + "addApplicationClass": [MockFunction], + "docTitle": Object { + "change": [MockFunction], + "reset": [MockFunction], + }, + "getApplicationClasses$": [MockFunction], + "getBadge$": [MockFunction], + "getBrand$": [MockFunction], + "getBreadcrumbs$": [MockFunction], + "getCustomNavLink$": [MockFunction], + "getHeaderComponent": [MockFunction], + "getHelpExtension$": [MockFunction], "getIsNavDrawerLocked$": [MockFunction], + "getIsVisible$": [MockFunction], + "navControls": Object { + "getCenter$": [MockFunction], + "getLeft$": [MockFunction], + "getRight$": [MockFunction], + "registerCenter": [MockFunction], + "registerLeft": [MockFunction], + "registerRight": [MockFunction], + }, + "navLinks": Object { + "enableForcedAppSwitcherNavigation": [MockFunction], + "get": [MockFunction], + "getAll": [MockFunction], + "getForceAppSwitcherNavigation$": [MockFunction], + "getNavLinks$": [MockFunction], + "has": [MockFunction], + "showOnly": [MockFunction], + "update": [MockFunction], + }, + "recentlyAccessed": Object { + "add": [MockFunction], + "get": [MockFunction], + "get$": [MockFunction], + }, + "removeApplicationClass": [MockFunction], + "setAppTitle": [MockFunction], + "setBadge": [MockFunction], + "setBrand": [MockFunction], "setBreadcrumbs": [MockFunction] { "calls": Array [ Array [ @@ -2320,6 +2448,10 @@ exports[`Dashboard component renders empty dashboard 1`] = ` }, ], }, + "setCustomNavLink": [MockFunction], + "setHelpExtension": [MockFunction], + "setHelpSupportUrl": [MockFunction], + "setIsVisible": [MockFunction], } } dataPrepperIndicesExist={true} @@ -2516,7 +2648,47 @@ exports[`Dashboard component renders empty dashboard 1`] = ` } chrome={ Object { + "addApplicationClass": [MockFunction], + "docTitle": Object { + "change": [MockFunction], + "reset": [MockFunction], + }, + "getApplicationClasses$": [MockFunction], + "getBadge$": [MockFunction], + "getBrand$": [MockFunction], + "getBreadcrumbs$": [MockFunction], + "getCustomNavLink$": [MockFunction], + "getHeaderComponent": [MockFunction], + "getHelpExtension$": [MockFunction], "getIsNavDrawerLocked$": [MockFunction], + "getIsVisible$": [MockFunction], + "navControls": Object { + "getCenter$": [MockFunction], + "getLeft$": [MockFunction], + "getRight$": [MockFunction], + "registerCenter": [MockFunction], + "registerLeft": [MockFunction], + "registerRight": [MockFunction], + }, + "navLinks": Object { + "enableForcedAppSwitcherNavigation": [MockFunction], + "get": [MockFunction], + "getAll": [MockFunction], + "getForceAppSwitcherNavigation$": [MockFunction], + "getNavLinks$": [MockFunction], + "has": [MockFunction], + "showOnly": [MockFunction], + "update": [MockFunction], + }, + "recentlyAccessed": Object { + "add": [MockFunction], + "get": [MockFunction], + "get$": [MockFunction], + }, + "removeApplicationClass": [MockFunction], + "setAppTitle": [MockFunction], + "setBadge": [MockFunction], + "setBrand": [MockFunction], "setBreadcrumbs": [MockFunction] { "calls": Array [ Array [ @@ -2543,6 +2715,10 @@ exports[`Dashboard component renders empty dashboard 1`] = ` }, ], }, + "setCustomNavLink": [MockFunction], + "setHelpExtension": [MockFunction], + "setHelpSupportUrl": [MockFunction], + "setIsVisible": [MockFunction], } } dataPrepperIndicesExist={true} @@ -4537,7 +4713,47 @@ exports[`Dashboard component renders empty jaeger dashboard 1`] = ` } chrome={ Object { + "addApplicationClass": [MockFunction], + "docTitle": Object { + "change": [MockFunction], + "reset": [MockFunction], + }, + "getApplicationClasses$": [MockFunction], + "getBadge$": [MockFunction], + "getBrand$": [MockFunction], + "getBreadcrumbs$": [MockFunction], + "getCustomNavLink$": [MockFunction], + "getHeaderComponent": [MockFunction], + "getHelpExtension$": [MockFunction], "getIsNavDrawerLocked$": [MockFunction], + "getIsVisible$": [MockFunction], + "navControls": Object { + "getCenter$": [MockFunction], + "getLeft$": [MockFunction], + "getRight$": [MockFunction], + "registerCenter": [MockFunction], + "registerLeft": [MockFunction], + "registerRight": [MockFunction], + }, + "navLinks": Object { + "enableForcedAppSwitcherNavigation": [MockFunction], + "get": [MockFunction], + "getAll": [MockFunction], + "getForceAppSwitcherNavigation$": [MockFunction], + "getNavLinks$": [MockFunction], + "has": [MockFunction], + "showOnly": [MockFunction], + "update": [MockFunction], + }, + "recentlyAccessed": Object { + "add": [MockFunction], + "get": [MockFunction], + "get$": [MockFunction], + }, + "removeApplicationClass": [MockFunction], + "setAppTitle": [MockFunction], + "setBadge": [MockFunction], + "setBrand": [MockFunction], "setBreadcrumbs": [MockFunction] { "calls": Array [ Array [ @@ -4564,6 +4780,10 @@ exports[`Dashboard component renders empty jaeger dashboard 1`] = ` }, ], }, + "setCustomNavLink": [MockFunction], + "setHelpExtension": [MockFunction], + "setHelpSupportUrl": [MockFunction], + "setIsVisible": [MockFunction], } } dataPrepperIndicesExist={false} @@ -4766,7 +4986,47 @@ exports[`Dashboard component renders empty jaeger dashboard 1`] = ` } chrome={ Object { + "addApplicationClass": [MockFunction], + "docTitle": Object { + "change": [MockFunction], + "reset": [MockFunction], + }, + "getApplicationClasses$": [MockFunction], + "getBadge$": [MockFunction], + "getBrand$": [MockFunction], + "getBreadcrumbs$": [MockFunction], + "getCustomNavLink$": [MockFunction], + "getHeaderComponent": [MockFunction], + "getHelpExtension$": [MockFunction], "getIsNavDrawerLocked$": [MockFunction], + "getIsVisible$": [MockFunction], + "navControls": Object { + "getCenter$": [MockFunction], + "getLeft$": [MockFunction], + "getRight$": [MockFunction], + "registerCenter": [MockFunction], + "registerLeft": [MockFunction], + "registerRight": [MockFunction], + }, + "navLinks": Object { + "enableForcedAppSwitcherNavigation": [MockFunction], + "get": [MockFunction], + "getAll": [MockFunction], + "getForceAppSwitcherNavigation$": [MockFunction], + "getNavLinks$": [MockFunction], + "has": [MockFunction], + "showOnly": [MockFunction], + "update": [MockFunction], + }, + "recentlyAccessed": Object { + "add": [MockFunction], + "get": [MockFunction], + "get$": [MockFunction], + }, + "removeApplicationClass": [MockFunction], + "setAppTitle": [MockFunction], + "setBadge": [MockFunction], + "setBrand": [MockFunction], "setBreadcrumbs": [MockFunction] { "calls": Array [ Array [ @@ -4793,6 +5053,10 @@ exports[`Dashboard component renders empty jaeger dashboard 1`] = ` }, ], }, + "setCustomNavLink": [MockFunction], + "setHelpExtension": [MockFunction], + "setHelpSupportUrl": [MockFunction], + "setIsVisible": [MockFunction], } } dataPrepperIndicesExist={false} diff --git a/public/components/trace_analytics/components/services/__tests__/__snapshots__/services.test.tsx.snap b/public/components/trace_analytics/components/services/__tests__/__snapshots__/services.test.tsx.snap index 42291d3fa6..25deb6fbc7 100644 --- a/public/components/trace_analytics/components/services/__tests__/__snapshots__/services.test.tsx.snap +++ b/public/components/trace_analytics/components/services/__tests__/__snapshots__/services.test.tsx.snap @@ -17,7 +17,47 @@ exports[`Services component renders empty services page 1`] = ` } chrome={ Object { + "addApplicationClass": [MockFunction], + "docTitle": Object { + "change": [MockFunction], + "reset": [MockFunction], + }, + "getApplicationClasses$": [MockFunction], + "getBadge$": [MockFunction], + "getBrand$": [MockFunction], + "getBreadcrumbs$": [MockFunction], + "getCustomNavLink$": [MockFunction], + "getHeaderComponent": [MockFunction], + "getHelpExtension$": [MockFunction], "getIsNavDrawerLocked$": [MockFunction], + "getIsVisible$": [MockFunction], + "navControls": Object { + "getCenter$": [MockFunction], + "getLeft$": [MockFunction], + "getRight$": [MockFunction], + "registerCenter": [MockFunction], + "registerLeft": [MockFunction], + "registerRight": [MockFunction], + }, + "navLinks": Object { + "enableForcedAppSwitcherNavigation": [MockFunction], + "get": [MockFunction], + "getAll": [MockFunction], + "getForceAppSwitcherNavigation$": [MockFunction], + "getNavLinks$": [MockFunction], + "has": [MockFunction], + "showOnly": [MockFunction], + "update": [MockFunction], + }, + "recentlyAccessed": Object { + "add": [MockFunction], + "get": [MockFunction], + "get$": [MockFunction], + }, + "removeApplicationClass": [MockFunction], + "setAppTitle": [MockFunction], + "setBadge": [MockFunction], + "setBrand": [MockFunction], "setBreadcrumbs": [MockFunction] { "calls": Array [ Array [ @@ -44,6 +84,10 @@ exports[`Services component renders empty services page 1`] = ` }, ], }, + "setCustomNavLink": [MockFunction], + "setHelpExtension": [MockFunction], + "setHelpSupportUrl": [MockFunction], + "setIsVisible": [MockFunction], } } dataPrepperIndicesExist={true} @@ -242,7 +286,47 @@ exports[`Services component renders empty services page 1`] = ` } chrome={ Object { + "addApplicationClass": [MockFunction], + "docTitle": Object { + "change": [MockFunction], + "reset": [MockFunction], + }, + "getApplicationClasses$": [MockFunction], + "getBadge$": [MockFunction], + "getBrand$": [MockFunction], + "getBreadcrumbs$": [MockFunction], + "getCustomNavLink$": [MockFunction], + "getHeaderComponent": [MockFunction], + "getHelpExtension$": [MockFunction], "getIsNavDrawerLocked$": [MockFunction], + "getIsVisible$": [MockFunction], + "navControls": Object { + "getCenter$": [MockFunction], + "getLeft$": [MockFunction], + "getRight$": [MockFunction], + "registerCenter": [MockFunction], + "registerLeft": [MockFunction], + "registerRight": [MockFunction], + }, + "navLinks": Object { + "enableForcedAppSwitcherNavigation": [MockFunction], + "get": [MockFunction], + "getAll": [MockFunction], + "getForceAppSwitcherNavigation$": [MockFunction], + "getNavLinks$": [MockFunction], + "has": [MockFunction], + "showOnly": [MockFunction], + "update": [MockFunction], + }, + "recentlyAccessed": Object { + "add": [MockFunction], + "get": [MockFunction], + "get$": [MockFunction], + }, + "removeApplicationClass": [MockFunction], + "setAppTitle": [MockFunction], + "setBadge": [MockFunction], + "setBrand": [MockFunction], "setBreadcrumbs": [MockFunction] { "calls": Array [ Array [ @@ -269,6 +353,10 @@ exports[`Services component renders empty services page 1`] = ` }, ], }, + "setCustomNavLink": [MockFunction], + "setHelpExtension": [MockFunction], + "setHelpSupportUrl": [MockFunction], + "setIsVisible": [MockFunction], } } dataPrepperIndicesExist={true} @@ -1824,7 +1912,47 @@ exports[`Services component renders jaeger services page 1`] = ` } chrome={ Object { + "addApplicationClass": [MockFunction], + "docTitle": Object { + "change": [MockFunction], + "reset": [MockFunction], + }, + "getApplicationClasses$": [MockFunction], + "getBadge$": [MockFunction], + "getBrand$": [MockFunction], + "getBreadcrumbs$": [MockFunction], + "getCustomNavLink$": [MockFunction], + "getHeaderComponent": [MockFunction], + "getHelpExtension$": [MockFunction], "getIsNavDrawerLocked$": [MockFunction], + "getIsVisible$": [MockFunction], + "navControls": Object { + "getCenter$": [MockFunction], + "getLeft$": [MockFunction], + "getRight$": [MockFunction], + "registerCenter": [MockFunction], + "registerLeft": [MockFunction], + "registerRight": [MockFunction], + }, + "navLinks": Object { + "enableForcedAppSwitcherNavigation": [MockFunction], + "get": [MockFunction], + "getAll": [MockFunction], + "getForceAppSwitcherNavigation$": [MockFunction], + "getNavLinks$": [MockFunction], + "has": [MockFunction], + "showOnly": [MockFunction], + "update": [MockFunction], + }, + "recentlyAccessed": Object { + "add": [MockFunction], + "get": [MockFunction], + "get$": [MockFunction], + }, + "removeApplicationClass": [MockFunction], + "setAppTitle": [MockFunction], + "setBadge": [MockFunction], + "setBrand": [MockFunction], "setBreadcrumbs": [MockFunction] { "calls": Array [ Array [ @@ -1851,6 +1979,10 @@ exports[`Services component renders jaeger services page 1`] = ` }, ], }, + "setCustomNavLink": [MockFunction], + "setHelpExtension": [MockFunction], + "setHelpSupportUrl": [MockFunction], + "setIsVisible": [MockFunction], } } dataPrepperIndicesExist={false} @@ -2055,7 +2187,47 @@ exports[`Services component renders jaeger services page 1`] = ` } chrome={ Object { + "addApplicationClass": [MockFunction], + "docTitle": Object { + "change": [MockFunction], + "reset": [MockFunction], + }, + "getApplicationClasses$": [MockFunction], + "getBadge$": [MockFunction], + "getBrand$": [MockFunction], + "getBreadcrumbs$": [MockFunction], + "getCustomNavLink$": [MockFunction], + "getHeaderComponent": [MockFunction], + "getHelpExtension$": [MockFunction], "getIsNavDrawerLocked$": [MockFunction], + "getIsVisible$": [MockFunction], + "navControls": Object { + "getCenter$": [MockFunction], + "getLeft$": [MockFunction], + "getRight$": [MockFunction], + "registerCenter": [MockFunction], + "registerLeft": [MockFunction], + "registerRight": [MockFunction], + }, + "navLinks": Object { + "enableForcedAppSwitcherNavigation": [MockFunction], + "get": [MockFunction], + "getAll": [MockFunction], + "getForceAppSwitcherNavigation$": [MockFunction], + "getNavLinks$": [MockFunction], + "has": [MockFunction], + "showOnly": [MockFunction], + "update": [MockFunction], + }, + "recentlyAccessed": Object { + "add": [MockFunction], + "get": [MockFunction], + "get$": [MockFunction], + }, + "removeApplicationClass": [MockFunction], + "setAppTitle": [MockFunction], + "setBadge": [MockFunction], + "setBrand": [MockFunction], "setBreadcrumbs": [MockFunction] { "calls": Array [ Array [ @@ -2082,6 +2254,10 @@ exports[`Services component renders jaeger services page 1`] = ` }, ], }, + "setCustomNavLink": [MockFunction], + "setHelpExtension": [MockFunction], + "setHelpSupportUrl": [MockFunction], + "setIsVisible": [MockFunction], } } dataPrepperIndicesExist={false} @@ -3140,7 +3316,47 @@ exports[`Services component renders services page 1`] = ` } chrome={ Object { + "addApplicationClass": [MockFunction], + "docTitle": Object { + "change": [MockFunction], + "reset": [MockFunction], + }, + "getApplicationClasses$": [MockFunction], + "getBadge$": [MockFunction], + "getBrand$": [MockFunction], + "getBreadcrumbs$": [MockFunction], + "getCustomNavLink$": [MockFunction], + "getHeaderComponent": [MockFunction], + "getHelpExtension$": [MockFunction], "getIsNavDrawerLocked$": [MockFunction], + "getIsVisible$": [MockFunction], + "navControls": Object { + "getCenter$": [MockFunction], + "getLeft$": [MockFunction], + "getRight$": [MockFunction], + "registerCenter": [MockFunction], + "registerLeft": [MockFunction], + "registerRight": [MockFunction], + }, + "navLinks": Object { + "enableForcedAppSwitcherNavigation": [MockFunction], + "get": [MockFunction], + "getAll": [MockFunction], + "getForceAppSwitcherNavigation$": [MockFunction], + "getNavLinks$": [MockFunction], + "has": [MockFunction], + "showOnly": [MockFunction], + "update": [MockFunction], + }, + "recentlyAccessed": Object { + "add": [MockFunction], + "get": [MockFunction], + "get$": [MockFunction], + }, + "removeApplicationClass": [MockFunction], + "setAppTitle": [MockFunction], + "setBadge": [MockFunction], + "setBrand": [MockFunction], "setBreadcrumbs": [MockFunction] { "calls": Array [ Array [ @@ -3167,6 +3383,10 @@ exports[`Services component renders services page 1`] = ` }, ], }, + "setCustomNavLink": [MockFunction], + "setHelpExtension": [MockFunction], + "setHelpSupportUrl": [MockFunction], + "setIsVisible": [MockFunction], } } dataPrepperIndicesExist={true} @@ -3370,7 +3590,47 @@ exports[`Services component renders services page 1`] = ` } chrome={ Object { + "addApplicationClass": [MockFunction], + "docTitle": Object { + "change": [MockFunction], + "reset": [MockFunction], + }, + "getApplicationClasses$": [MockFunction], + "getBadge$": [MockFunction], + "getBrand$": [MockFunction], + "getBreadcrumbs$": [MockFunction], + "getCustomNavLink$": [MockFunction], + "getHeaderComponent": [MockFunction], + "getHelpExtension$": [MockFunction], "getIsNavDrawerLocked$": [MockFunction], + "getIsVisible$": [MockFunction], + "navControls": Object { + "getCenter$": [MockFunction], + "getLeft$": [MockFunction], + "getRight$": [MockFunction], + "registerCenter": [MockFunction], + "registerLeft": [MockFunction], + "registerRight": [MockFunction], + }, + "navLinks": Object { + "enableForcedAppSwitcherNavigation": [MockFunction], + "get": [MockFunction], + "getAll": [MockFunction], + "getForceAppSwitcherNavigation$": [MockFunction], + "getNavLinks$": [MockFunction], + "has": [MockFunction], + "showOnly": [MockFunction], + "update": [MockFunction], + }, + "recentlyAccessed": Object { + "add": [MockFunction], + "get": [MockFunction], + "get$": [MockFunction], + }, + "removeApplicationClass": [MockFunction], + "setAppTitle": [MockFunction], + "setBadge": [MockFunction], + "setBrand": [MockFunction], "setBreadcrumbs": [MockFunction] { "calls": Array [ Array [ @@ -3397,6 +3657,10 @@ exports[`Services component renders services page 1`] = ` }, ], }, + "setCustomNavLink": [MockFunction], + "setHelpExtension": [MockFunction], + "setHelpSupportUrl": [MockFunction], + "setIsVisible": [MockFunction], } } dataPrepperIndicesExist={true} diff --git a/public/components/trace_analytics/components/traces/__tests__/__snapshots__/traces.test.tsx.snap b/public/components/trace_analytics/components/traces/__tests__/__snapshots__/traces.test.tsx.snap index 1aeeab3f1d..e0acd2e97a 100644 --- a/public/components/trace_analytics/components/traces/__tests__/__snapshots__/traces.test.tsx.snap +++ b/public/components/trace_analytics/components/traces/__tests__/__snapshots__/traces.test.tsx.snap @@ -17,7 +17,47 @@ exports[`Traces component renders empty traces page 1`] = ` } chrome={ Object { + "addApplicationClass": [MockFunction], + "docTitle": Object { + "change": [MockFunction], + "reset": [MockFunction], + }, + "getApplicationClasses$": [MockFunction], + "getBadge$": [MockFunction], + "getBrand$": [MockFunction], + "getBreadcrumbs$": [MockFunction], + "getCustomNavLink$": [MockFunction], + "getHeaderComponent": [MockFunction], + "getHelpExtension$": [MockFunction], "getIsNavDrawerLocked$": [MockFunction], + "getIsVisible$": [MockFunction], + "navControls": Object { + "getCenter$": [MockFunction], + "getLeft$": [MockFunction], + "getRight$": [MockFunction], + "registerCenter": [MockFunction], + "registerLeft": [MockFunction], + "registerRight": [MockFunction], + }, + "navLinks": Object { + "enableForcedAppSwitcherNavigation": [MockFunction], + "get": [MockFunction], + "getAll": [MockFunction], + "getForceAppSwitcherNavigation$": [MockFunction], + "getNavLinks$": [MockFunction], + "has": [MockFunction], + "showOnly": [MockFunction], + "update": [MockFunction], + }, + "recentlyAccessed": Object { + "add": [MockFunction], + "get": [MockFunction], + "get$": [MockFunction], + }, + "removeApplicationClass": [MockFunction], + "setAppTitle": [MockFunction], + "setBadge": [MockFunction], + "setBrand": [MockFunction], "setBreadcrumbs": [MockFunction] { "calls": Array [ Array [ @@ -44,6 +84,10 @@ exports[`Traces component renders empty traces page 1`] = ` }, ], }, + "setCustomNavLink": [MockFunction], + "setHelpExtension": [MockFunction], + "setHelpSupportUrl": [MockFunction], + "setIsVisible": [MockFunction], } } dataPrepperIndicesExist={true} @@ -241,7 +285,47 @@ exports[`Traces component renders empty traces page 1`] = ` } chrome={ Object { + "addApplicationClass": [MockFunction], + "docTitle": Object { + "change": [MockFunction], + "reset": [MockFunction], + }, + "getApplicationClasses$": [MockFunction], + "getBadge$": [MockFunction], + "getBrand$": [MockFunction], + "getBreadcrumbs$": [MockFunction], + "getCustomNavLink$": [MockFunction], + "getHeaderComponent": [MockFunction], + "getHelpExtension$": [MockFunction], "getIsNavDrawerLocked$": [MockFunction], + "getIsVisible$": [MockFunction], + "navControls": Object { + "getCenter$": [MockFunction], + "getLeft$": [MockFunction], + "getRight$": [MockFunction], + "registerCenter": [MockFunction], + "registerLeft": [MockFunction], + "registerRight": [MockFunction], + }, + "navLinks": Object { + "enableForcedAppSwitcherNavigation": [MockFunction], + "get": [MockFunction], + "getAll": [MockFunction], + "getForceAppSwitcherNavigation$": [MockFunction], + "getNavLinks$": [MockFunction], + "has": [MockFunction], + "showOnly": [MockFunction], + "update": [MockFunction], + }, + "recentlyAccessed": Object { + "add": [MockFunction], + "get": [MockFunction], + "get$": [MockFunction], + }, + "removeApplicationClass": [MockFunction], + "setAppTitle": [MockFunction], + "setBadge": [MockFunction], + "setBrand": [MockFunction], "setBreadcrumbs": [MockFunction] { "calls": Array [ Array [ @@ -268,6 +352,10 @@ exports[`Traces component renders empty traces page 1`] = ` }, ], }, + "setCustomNavLink": [MockFunction], + "setHelpExtension": [MockFunction], + "setHelpSupportUrl": [MockFunction], + "setIsVisible": [MockFunction], } } dataPrepperIndicesExist={true} @@ -1290,7 +1378,47 @@ exports[`Traces component renders jaeger traces page 1`] = ` } chrome={ Object { + "addApplicationClass": [MockFunction], + "docTitle": Object { + "change": [MockFunction], + "reset": [MockFunction], + }, + "getApplicationClasses$": [MockFunction], + "getBadge$": [MockFunction], + "getBrand$": [MockFunction], + "getBreadcrumbs$": [MockFunction], + "getCustomNavLink$": [MockFunction], + "getHeaderComponent": [MockFunction], + "getHelpExtension$": [MockFunction], "getIsNavDrawerLocked$": [MockFunction], + "getIsVisible$": [MockFunction], + "navControls": Object { + "getCenter$": [MockFunction], + "getLeft$": [MockFunction], + "getRight$": [MockFunction], + "registerCenter": [MockFunction], + "registerLeft": [MockFunction], + "registerRight": [MockFunction], + }, + "navLinks": Object { + "enableForcedAppSwitcherNavigation": [MockFunction], + "get": [MockFunction], + "getAll": [MockFunction], + "getForceAppSwitcherNavigation$": [MockFunction], + "getNavLinks$": [MockFunction], + "has": [MockFunction], + "showOnly": [MockFunction], + "update": [MockFunction], + }, + "recentlyAccessed": Object { + "add": [MockFunction], + "get": [MockFunction], + "get$": [MockFunction], + }, + "removeApplicationClass": [MockFunction], + "setAppTitle": [MockFunction], + "setBadge": [MockFunction], + "setBrand": [MockFunction], "setBreadcrumbs": [MockFunction] { "calls": Array [ Array [ @@ -1317,6 +1445,10 @@ exports[`Traces component renders jaeger traces page 1`] = ` }, ], }, + "setCustomNavLink": [MockFunction], + "setHelpExtension": [MockFunction], + "setHelpSupportUrl": [MockFunction], + "setIsVisible": [MockFunction], } } dataPrepperIndicesExist={false} @@ -1520,7 +1652,47 @@ exports[`Traces component renders jaeger traces page 1`] = ` } chrome={ Object { + "addApplicationClass": [MockFunction], + "docTitle": Object { + "change": [MockFunction], + "reset": [MockFunction], + }, + "getApplicationClasses$": [MockFunction], + "getBadge$": [MockFunction], + "getBrand$": [MockFunction], + "getBreadcrumbs$": [MockFunction], + "getCustomNavLink$": [MockFunction], + "getHeaderComponent": [MockFunction], + "getHelpExtension$": [MockFunction], "getIsNavDrawerLocked$": [MockFunction], + "getIsVisible$": [MockFunction], + "navControls": Object { + "getCenter$": [MockFunction], + "getLeft$": [MockFunction], + "getRight$": [MockFunction], + "registerCenter": [MockFunction], + "registerLeft": [MockFunction], + "registerRight": [MockFunction], + }, + "navLinks": Object { + "enableForcedAppSwitcherNavigation": [MockFunction], + "get": [MockFunction], + "getAll": [MockFunction], + "getForceAppSwitcherNavigation$": [MockFunction], + "getNavLinks$": [MockFunction], + "has": [MockFunction], + "showOnly": [MockFunction], + "update": [MockFunction], + }, + "recentlyAccessed": Object { + "add": [MockFunction], + "get": [MockFunction], + "get$": [MockFunction], + }, + "removeApplicationClass": [MockFunction], + "setAppTitle": [MockFunction], + "setBadge": [MockFunction], + "setBrand": [MockFunction], "setBreadcrumbs": [MockFunction] { "calls": Array [ Array [ @@ -1547,6 +1719,10 @@ exports[`Traces component renders jaeger traces page 1`] = ` }, ], }, + "setCustomNavLink": [MockFunction], + "setHelpExtension": [MockFunction], + "setHelpSupportUrl": [MockFunction], + "setIsVisible": [MockFunction], } } dataPrepperIndicesExist={false} @@ -2594,7 +2770,47 @@ exports[`Traces component renders traces page 1`] = ` } chrome={ Object { + "addApplicationClass": [MockFunction], + "docTitle": Object { + "change": [MockFunction], + "reset": [MockFunction], + }, + "getApplicationClasses$": [MockFunction], + "getBadge$": [MockFunction], + "getBrand$": [MockFunction], + "getBreadcrumbs$": [MockFunction], + "getCustomNavLink$": [MockFunction], + "getHeaderComponent": [MockFunction], + "getHelpExtension$": [MockFunction], "getIsNavDrawerLocked$": [MockFunction], + "getIsVisible$": [MockFunction], + "navControls": Object { + "getCenter$": [MockFunction], + "getLeft$": [MockFunction], + "getRight$": [MockFunction], + "registerCenter": [MockFunction], + "registerLeft": [MockFunction], + "registerRight": [MockFunction], + }, + "navLinks": Object { + "enableForcedAppSwitcherNavigation": [MockFunction], + "get": [MockFunction], + "getAll": [MockFunction], + "getForceAppSwitcherNavigation$": [MockFunction], + "getNavLinks$": [MockFunction], + "has": [MockFunction], + "showOnly": [MockFunction], + "update": [MockFunction], + }, + "recentlyAccessed": Object { + "add": [MockFunction], + "get": [MockFunction], + "get$": [MockFunction], + }, + "removeApplicationClass": [MockFunction], + "setAppTitle": [MockFunction], + "setBadge": [MockFunction], + "setBrand": [MockFunction], "setBreadcrumbs": [MockFunction] { "calls": Array [ Array [ @@ -2621,6 +2837,10 @@ exports[`Traces component renders traces page 1`] = ` }, ], }, + "setCustomNavLink": [MockFunction], + "setHelpExtension": [MockFunction], + "setHelpSupportUrl": [MockFunction], + "setIsVisible": [MockFunction], } } dataPrepperIndicesExist={true} @@ -2823,7 +3043,47 @@ exports[`Traces component renders traces page 1`] = ` } chrome={ Object { + "addApplicationClass": [MockFunction], + "docTitle": Object { + "change": [MockFunction], + "reset": [MockFunction], + }, + "getApplicationClasses$": [MockFunction], + "getBadge$": [MockFunction], + "getBrand$": [MockFunction], + "getBreadcrumbs$": [MockFunction], + "getCustomNavLink$": [MockFunction], + "getHeaderComponent": [MockFunction], + "getHelpExtension$": [MockFunction], "getIsNavDrawerLocked$": [MockFunction], + "getIsVisible$": [MockFunction], + "navControls": Object { + "getCenter$": [MockFunction], + "getLeft$": [MockFunction], + "getRight$": [MockFunction], + "registerCenter": [MockFunction], + "registerLeft": [MockFunction], + "registerRight": [MockFunction], + }, + "navLinks": Object { + "enableForcedAppSwitcherNavigation": [MockFunction], + "get": [MockFunction], + "getAll": [MockFunction], + "getForceAppSwitcherNavigation$": [MockFunction], + "getNavLinks$": [MockFunction], + "has": [MockFunction], + "showOnly": [MockFunction], + "update": [MockFunction], + }, + "recentlyAccessed": Object { + "add": [MockFunction], + "get": [MockFunction], + "get$": [MockFunction], + }, + "removeApplicationClass": [MockFunction], + "setAppTitle": [MockFunction], + "setBadge": [MockFunction], + "setBrand": [MockFunction], "setBreadcrumbs": [MockFunction] { "calls": Array [ Array [ @@ -2850,6 +3110,10 @@ exports[`Traces component renders traces page 1`] = ` }, ], }, + "setCustomNavLink": [MockFunction], + "setHelpExtension": [MockFunction], + "setHelpSupportUrl": [MockFunction], + "setIsVisible": [MockFunction], } } dataPrepperIndicesExist={true} diff --git a/public/components/visualizations/assets/__tests__/__snapshots__/assets.test.tsx.snap b/public/components/visualizations/assets/__tests__/__snapshots__/assets.test.tsx.snap index 3b213ff7d2..4e61b41769 100644 --- a/public/components/visualizations/assets/__tests__/__snapshots__/assets.test.tsx.snap +++ b/public/components/visualizations/assets/__tests__/__snapshots__/assets.test.tsx.snap @@ -1,7 +1,7 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`Assets components Renders lens icon of bar component 1`] = ` - + - + `; exports[`Assets components Renders lens icon of horizontal bar component 1`] = ` - + - + `; exports[`Assets components Renders lens icon of line component 1`] = ` - + - + `; diff --git a/public/components/visualizations/charts/__tests__/__snapshots__/bar.test.tsx.snap b/public/components/visualizations/charts/__tests__/__snapshots__/bar.test.tsx.snap index bbc5c3cabd..cd1c5ad7cd 100644 --- a/public/components/visualizations/charts/__tests__/__snapshots__/bar.test.tsx.snap +++ b/public/components/visualizations/charts/__tests__/__snapshots__/bar.test.tsx.snap @@ -1,7 +1,7 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`Veritcal Bar component Renders veritcal bar component 1`] = ` - - + `; diff --git a/public/components/visualizations/charts/__tests__/__snapshots__/gauge.test.tsx.snap b/public/components/visualizations/charts/__tests__/__snapshots__/gauge.test.tsx.snap index 26727a324d..893fbd7621 100644 --- a/public/components/visualizations/charts/__tests__/__snapshots__/gauge.test.tsx.snap +++ b/public/components/visualizations/charts/__tests__/__snapshots__/gauge.test.tsx.snap @@ -1,7 +1,7 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`Gauge component Renders gauge component 1`] = ` - - - - + + `; diff --git a/public/components/visualizations/charts/__tests__/__snapshots__/heatmap.test.tsx.snap b/public/components/visualizations/charts/__tests__/__snapshots__/heatmap.test.tsx.snap index b14ca05893..1744e8b7fd 100644 --- a/public/components/visualizations/charts/__tests__/__snapshots__/heatmap.test.tsx.snap +++ b/public/components/visualizations/charts/__tests__/__snapshots__/heatmap.test.tsx.snap @@ -1,7 +1,7 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`Heatmap component Renders heatmap component 1`] = ` - - + `; diff --git a/public/components/visualizations/charts/__tests__/__snapshots__/histogram.test.tsx.snap b/public/components/visualizations/charts/__tests__/__snapshots__/histogram.test.tsx.snap index 9710a10004..21c9ef5f8e 100644 --- a/public/components/visualizations/charts/__tests__/__snapshots__/histogram.test.tsx.snap +++ b/public/components/visualizations/charts/__tests__/__snapshots__/histogram.test.tsx.snap @@ -1,7 +1,7 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`Histogram component Renders histogram component 1`] = ` - - + `; diff --git a/public/components/visualizations/charts/__tests__/__snapshots__/horizontal_bar.test.tsx.snap b/public/components/visualizations/charts/__tests__/__snapshots__/horizontal_bar.test.tsx.snap index 0049049be4..e60758d582 100644 --- a/public/components/visualizations/charts/__tests__/__snapshots__/horizontal_bar.test.tsx.snap +++ b/public/components/visualizations/charts/__tests__/__snapshots__/horizontal_bar.test.tsx.snap @@ -1,7 +1,7 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`Horizontal bar component Renders horizontal bar component 1`] = ` - - + `; diff --git a/public/components/visualizations/charts/__tests__/__snapshots__/line.test.tsx.snap b/public/components/visualizations/charts/__tests__/__snapshots__/line.test.tsx.snap index 8a495d3f97..bd74ceb6da 100644 --- a/public/components/visualizations/charts/__tests__/__snapshots__/line.test.tsx.snap +++ b/public/components/visualizations/charts/__tests__/__snapshots__/line.test.tsx.snap @@ -1,7 +1,7 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`Line component Renders line component 1`] = ` - - + `; diff --git a/public/components/visualizations/charts/__tests__/__snapshots__/metrics.test.tsx.snap b/public/components/visualizations/charts/__tests__/__snapshots__/metrics.test.tsx.snap index 551cc8879b..87fa482580 100644 --- a/public/components/visualizations/charts/__tests__/__snapshots__/metrics.test.tsx.snap +++ b/public/components/visualizations/charts/__tests__/__snapshots__/metrics.test.tsx.snap @@ -1,7 +1,7 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`Metrics component Renders Metrics component 1`] = ` - - - - + + `; diff --git a/public/components/visualizations/charts/__tests__/__snapshots__/pie.test.tsx.snap b/public/components/visualizations/charts/__tests__/__snapshots__/pie.test.tsx.snap index 9103460eaa..10a1068fbf 100644 --- a/public/components/visualizations/charts/__tests__/__snapshots__/pie.test.tsx.snap +++ b/public/components/visualizations/charts/__tests__/__snapshots__/pie.test.tsx.snap @@ -1,7 +1,7 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`Pie component Renders pie component 1`] = ` - - + `; diff --git a/public/components/visualizations/charts/__tests__/__snapshots__/text.test.tsx.snap b/public/components/visualizations/charts/__tests__/__snapshots__/text.test.tsx.snap index 083750cfd9..2180c9ceda 100644 --- a/public/components/visualizations/charts/__tests__/__snapshots__/text.test.tsx.snap +++ b/public/components/visualizations/charts/__tests__/__snapshots__/text.test.tsx.snap @@ -1,7 +1,7 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`Text component Renders text component 1`] = ` - - + `; diff --git a/public/components/visualizations/charts/__tests__/__snapshots__/treemap.test.tsx.snap b/public/components/visualizations/charts/__tests__/__snapshots__/treemap.test.tsx.snap index 5560d66b91..21fdca804b 100644 --- a/public/components/visualizations/charts/__tests__/__snapshots__/treemap.test.tsx.snap +++ b/public/components/visualizations/charts/__tests__/__snapshots__/treemap.test.tsx.snap @@ -1,7 +1,7 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`Treemap component Renders treemap component 1`] = ` - - + `; From 5c2605a079893c3f653faee08828b1147891a95e Mon Sep 17 00:00:00 2001 From: Eric Wei Date: Sun, 9 Apr 2023 09:35:57 -0700 Subject: [PATCH 63/73] fix bug for not getting all fields when query contains stats Signed-off-by: Eric Wei --- .../event_analytics/explorer/explorer.tsx | 3 ++- .../event_analytics/hooks/use_fetch_events.ts | 19 ++++++------------- .../data_fetchers/ppl/ppl_data_fetcher.ts | 4 ++++ 3 files changed, 12 insertions(+), 14 deletions(-) diff --git a/public/components/event_analytics/explorer/explorer.tsx b/public/components/event_analytics/explorer/explorer.tsx index 50086e805f..d07a177f07 100644 --- a/public/components/event_analytics/explorer/explorer.tsx +++ b/public/components/event_analytics/explorer/explorer.tsx @@ -134,7 +134,7 @@ export const Explorer = ({ }: IExplorerProps) => { const dispatch = useDispatch(); const requestParams = { tabId }; - const { getLiveTail, getEvents } = useFetchEvents({ + const { getLiveTail, getEvents, getAvailableFields } = useFetchEvents({ pplService, requestParams, }); @@ -268,6 +268,7 @@ export const Explorer = ({ selectedContentTabId, queryManager, getDefaultVisConfig, + getAvailableFields, }, { appBaseQuery, diff --git a/public/components/event_analytics/hooks/use_fetch_events.ts b/public/components/event_analytics/hooks/use_fetch_events.ts index bbcbb4b785..cfd229eb04 100644 --- a/public/components/event_analytics/hooks/use_fetch_events.ts +++ b/public/components/event_analytics/hooks/use_fetch_events.ts @@ -21,6 +21,7 @@ import { selectQueries } from '../redux/slices/query_slice'; import { reset as visualizationReset } from '../redux/slices/visualization_slice'; import { updateFields, sortFields, selectFields } from '../redux/slices/field_slice'; import PPLService from '../../../services/requests/ppl'; +import { PPL_STATS_REGEX } from '../../../../common/constants/shared'; interface IFetchEventsParams { pplService: PPLService; @@ -57,7 +58,7 @@ export const useFetchEvents = ({ pplService, requestParams }: IFetchEventsParams .finally(() => setIsEventsLoading(false)); }; - const dispatchOnGettingHis = (res: any) => { + const dispatchOnGettingHis = (res: any, query: string) => { const selectedFields: string[] = fieldsRef.current![requestParams.tabId][SELECTED_FIELDS].map( (field: IField) => field.name ); @@ -81,8 +82,8 @@ export const useFetchEvents = ({ pplService, requestParams }: IFetchEventsParams tabId: requestParams.tabId, data: { [UNSELECTED_FIELDS]: res?.schema ? [...res.schema] : [], - [QUERIED_FIELDS]: [], - [AVAILABLE_FIELDS]: res?.schema || [], + [QUERIED_FIELDS]: query.match(PPL_STATS_REGEX) ? [...res.schema] : [], // when query contains stats, need populate this + [AVAILABLE_FIELDS]: res?.schema ? [...res.schema] : [], [SELECTED_FIELDS]: [], }, }) @@ -153,7 +154,7 @@ export const useFetchEvents = ({ pplService, requestParams }: IFetchEventsParams res.total = res.total + responseRef.current.total; res.size = res.size + responseRef.current.size; } - dispatchOnGettingHis(res); + dispatchOnGettingHis(res, searchQuery); } if (isEmpty(res.jsonData) && isEmpty(responseRef.current)) { dispatchOnNoHis(res); @@ -171,7 +172,7 @@ export const useFetchEvents = ({ pplService, requestParams }: IFetchEventsParams 'jdbc', (res: any) => { if (!isEmpty(res.jsonData)) { - return dispatchOnGettingHis(res); + return dispatchOnGettingHis(res, searchQuery); } // when no hits and needs to get available fields to override default timestamp dispatchOnNoHis(res); @@ -183,14 +184,6 @@ export const useFetchEvents = ({ pplService, requestParams }: IFetchEventsParams const getAvailableFields = (query: string) => { fetchEvents({ query }, 'jdbc', (res: any) => { batch(() => { - dispatch( - fetchSuccess({ - tabId: requestParams.tabId, - data: { - jsonDataAll: res.jsonData, - }, - }) - ); dispatch( updateFields({ tabId: requestParams.tabId, diff --git a/public/services/data_fetchers/ppl/ppl_data_fetcher.ts b/public/services/data_fetchers/ppl/ppl_data_fetcher.ts index d63a5200a0..e83b45dc78 100644 --- a/public/services/data_fetchers/ppl/ppl_data_fetcher.ts +++ b/public/services/data_fetchers/ppl/ppl_data_fetcher.ts @@ -18,6 +18,7 @@ import { SELECTED_TIMESTAMP, TAB_CHART_ID, } from '../../../../common/constants/explorer'; +import { PPL_STATS_REGEX } from '../../../../common/constants/shared'; export class PPLDataFetcher extends DataFetcherBase implements IDataFetcher { protected queryIndex: string; @@ -72,6 +73,7 @@ export class PPLDataFetcher extends DataFetcherBase implements IDataFetcher { getEvents, getErrorHandler, getPatterns, + getAvailableFields, } = this.searchContext; const { dispatch, changeQuery } = this.storeContext; @@ -107,6 +109,8 @@ export class PPLDataFetcher extends DataFetcherBase implements IDataFetcher { } else { getEvents(finalQuery, getErrorHandler('Error fetching events')); } + // still need all fields when query contains stats + if (finalQuery.match(PPL_STATS_REGEX)) getAvailableFields(`search source=${this.queryIndex}`); getCountVisualizations(selectedInterval.current.value.replace(/^auto_/, '')); // patterns this.setLogPattern(this.query, this.queryIndex, finalQuery); From a18f38963ac03ab27dc491830f10ff58440050d9 Mon Sep 17 00:00:00 2001 From: Joshua Li Date: Fri, 7 Apr 2023 23:20:47 +0000 Subject: [PATCH 64/73] Add management section to saved object Signed-off-by: Joshua Li --- public/embeddable/observability_embeddable.tsx | 2 +- server/plugin.ts | 5 +++++ .../saved_objects/observability_saved_object.ts | 17 +++++++++++++++++ 3 files changed, 23 insertions(+), 1 deletion(-) diff --git a/public/embeddable/observability_embeddable.tsx b/public/embeddable/observability_embeddable.tsx index 42664f8111..49fbb75cb2 100644 --- a/public/embeddable/observability_embeddable.tsx +++ b/public/embeddable/observability_embeddable.tsx @@ -24,7 +24,7 @@ export const OBSERVABILITY_EMBEDDABLE = VISUALIZATION_SAVED_OBJECT; export const OBSERVABILITY_EMBEDDABLE_ID = 'observability-ppl'; export const OBSERVABILITY_EMBEDDABLE_DISPLAY_NAME = 'PPL'; export const OBSERVABILITY_EMBEDDABLE_DESCRIPTION = - 'Create a visualization with Piped Processing Language (PPL). PPL can query data in your indices and also supports federated data sources like Prometheus'; + 'Create a visualization with Piped Processing Language (PPL). PPL can query data in your indices and also supports federated data sources like Prometheus.'; export const OBSERVABILITY_EMBEDDABLE_ICON = 'visQueryPPL'; export interface ObservabilityOutput extends EmbeddableOutput { diff --git a/server/plugin.ts b/server/plugin.ts index d48296c6b3..bf86ea997b 100644 --- a/server/plugin.ts +++ b/server/plugin.ts @@ -47,6 +47,11 @@ export class ObservabilityPlugin setupRoutes({ router, client: openSearchObservabilityClient }); core.savedObjects.registerType(visualizationSavedObject); + core.capabilities.registerProvider(() => ({ + observability: { + show: true, + }, + })); return {}; } diff --git a/server/saved_objects/observability_saved_object.ts b/server/saved_objects/observability_saved_object.ts index 4ebcffddcb..5c47a0c223 100644 --- a/server/saved_objects/observability_saved_object.ts +++ b/server/saved_objects/observability_saved_object.ts @@ -4,12 +4,29 @@ */ import { SavedObjectsType } from '../../../../src/core/server'; +import { observabilityID } from '../../common/constants/shared'; import { VISUALIZATION_SAVED_OBJECT } from '../../common/types/observability_saved_object_attributes'; export const visualizationSavedObject: SavedObjectsType = { name: VISUALIZATION_SAVED_OBJECT, hidden: false, namespaceType: 'single', + management: { + defaultSearchField: 'title', + importableAndExportable: true, + icon: 'visQueryPPL', + getTitle(obj) { + return obj.attributes.title; + }, + getInAppUrl(obj) { + const editPath = `#/event_analytics/explorer/${VISUALIZATION_SAVED_OBJECT}:${obj.id}`; + const editUrl = `/app/${observabilityID}${editPath}`; + return { + path: editUrl, + uiCapabilitiesPath: 'observability.show', + }; + }, + }, mappings: { dynamic: false, properties: { From ece07f5034902c8d7267410f6150a1f78347666e Mon Sep 17 00:00:00 2001 From: Joshua Li Date: Mon, 10 Apr 2023 20:12:15 +0000 Subject: [PATCH 65/73] Create new vis tab when creating ppl in visualize Signed-off-by: Joshua Li --- common/constants/explorer.ts | 7 ++- .../event_analytics/explorer/explorer.tsx | 21 +++++++-- .../event_analytics/explorer/log_explorer.tsx | 45 +++++++++++------- public/components/event_analytics/index.tsx | 46 ++++++++++++------- public/plugin.ts | 3 +- 5 files changed, 84 insertions(+), 38 deletions(-) diff --git a/common/constants/explorer.ts b/common/constants/explorer.ts index a9a44d2433..f586f5fca9 100644 --- a/common/constants/explorer.ts +++ b/common/constants/explorer.ts @@ -4,8 +4,8 @@ */ import { htmlIdGenerator } from '@elastic/eui'; -import { VIS_CHART_TYPES } from './shared'; import { ThresholdUnitType } from '../../public/components/event_analytics/explorer/visualizations/config_panel/config_panes/config_controls/config_thresholds'; +import { VIS_CHART_TYPES } from './shared'; export const EVENT_ANALYTICS_DOCUMENTATION_URL = 'https://opensearch.org/docs/latest/observability-plugin/event-analytics/'; @@ -31,6 +31,11 @@ export const TAB_EVENT_ID_TXT_PFX = 'main-content-events-'; export const TAB_CHART_ID_TXT_PFX = 'main-content-vis-'; export const TAB_EVENT_ID = 'main-content-events'; export const TAB_CHART_ID = 'main-content-vis'; +export const CREATE_TAB_PARAM_KEY = 'create'; +export const CREATE_TAB_PARAM = { + [TAB_EVENT_ID]: 'events', + [TAB_CHART_ID]: 'visualizations', +} as const; export const HAS_SAVED_TIMESTAMP = 'hasSavedTimestamp'; export const FILTER_OPTIONS = ['Visualization', 'Query', 'Metric']; export const SAVED_QUERY = 'savedQuery'; diff --git a/public/components/event_analytics/explorer/explorer.tsx b/public/components/event_analytics/explorer/explorer.tsx index d07a177f07..6678b69705 100644 --- a/public/components/event_analytics/explorer/explorer.tsx +++ b/public/components/event_analytics/explorer/explorer.tsx @@ -21,9 +21,20 @@ import { import { FormattedMessage } from '@osd/i18n/react'; import classNames from 'classnames'; import { isEmpty, isEqual, reduce } from 'lodash'; -import React, { ReactElement, useCallback, useEffect, useMemo, useRef, useState } from 'react'; +import React, { + ReactElement, + useCallback, + useContext, + useEffect, + useMemo, + useRef, + useState, +} from 'react'; import { batch, useDispatch, useSelector } from 'react-redux'; +import { LogExplorerRouterContext } from '..'; import { + CREATE_TAB_PARAM, + CREATE_TAB_PARAM_KEY, DATE_PICKER_FORMAT, DEFAULT_AVAILABILITY_QUERY, EVENT_ANALYTICS_DOCUMENTATION_URL, @@ -66,12 +77,14 @@ import { getIndexPatternFromRawQuery, uiSettingsService, } from '../../../../common/utils'; +import { PPLDataFetcher } from '../../../services/data_fetchers/ppl/ppl_data_fetcher'; import { getSavedObjectsClient } from '../../../services/saved_objects/saved_object_client/client_factory'; import { OSDSavedVisualizationClient } from '../../../services/saved_objects/saved_object_client/osd_saved_objects/saved_visualization'; import { PanelSavedObjectClient, PPLSavedQueryClient, } from '../../../services/saved_objects/saved_object_client/ppl'; +import { PPLSavedObjectLoader } from '../../../services/saved_objects/saved_object_loaders/ppl/ppl_loader'; import { SaveAsCurrenQuery, SaveAsCurrentVisualization, @@ -105,8 +118,6 @@ import { Sidebar } from './sidebar'; import { TimechartHeader } from './timechart_header'; import { ExplorerVisualizations } from './visualizations'; import { CountDistribution } from './visualizations/count_distribution'; -import { PPLSavedObjectLoader } from '../../../services/saved_objects/saved_object_loaders/ppl/ppl_loader'; -import { PPLDataFetcher } from '../../../services/data_fetchers/ppl/ppl_data_fetcher'; export const Explorer = ({ pplService, @@ -132,6 +143,7 @@ export const Explorer = ({ callbackInApp, queryManager = new QueryManager(), }: IExplorerProps) => { + const routerContext = useContext(LogExplorerRouterContext)!; const dispatch = useDispatch(); const requestParams = { tabId }; const { getLiveTail, getEvents, getAvailableFields } = useFetchEvents({ @@ -349,6 +361,9 @@ export const Explorer = ({ } else { fetchData(); } + if (routerContext.searchParams.get(CREATE_TAB_PARAM_KEY) === CREATE_TAB_PARAM[TAB_CHART_ID]) { + setSelectedContentTab(TAB_CHART_ID); + } }, []); useEffect(() => { diff --git a/public/components/event_analytics/explorer/log_explorer.tsx b/public/components/event_analytics/explorer/log_explorer.tsx index 05ff167563..bade273377 100644 --- a/public/components/event_analytics/explorer/log_explorer.tsx +++ b/public/components/event_analytics/explorer/log_explorer.tsx @@ -4,33 +4,35 @@ */ /* eslint-disable react-hooks/exhaustive-deps */ -import React, { useEffect, useMemo, useRef, useState } from 'react'; -import { useDispatch, useSelector } from 'react-redux'; -import { map, isEmpty } from 'lodash'; -import $ from 'jquery'; import { EuiIcon, - EuiText, - EuiTabbedContentTab, EuiTabbedContent, + EuiTabbedContentTab, + EuiText, htmlIdGenerator, } from '@elastic/eui'; -import { Explorer } from './explorer'; -import { ILogExplorerProps } from '../../../../common/types/explorer'; +import $ from 'jquery'; +import { isEmpty, map } from 'lodash'; +import React, { useContext, useEffect, useMemo, useRef, useState } from 'react'; +import { useDispatch, useSelector } from 'react-redux'; +import { LogExplorerRouterContext } from '..'; import { - TAB_TITLE, - TAB_ID_TXT_PFX, - SAVED_OBJECT_ID, + APP_ANALYTICS_TAB_ID_REGEX, + CREATE_TAB_PARAM_KEY, NEW_TAB, REDIRECT_TAB, - TAB_EVENT_ID, + SAVED_OBJECT_ID, TAB_CHART_ID, - APP_ANALYTICS_TAB_ID_REGEX, + TAB_EVENT_ID, + TAB_ID_TXT_PFX, + TAB_TITLE, } from '../../../../common/constants/explorer'; -import { selectQueryTabs, setSelectedQueryTab } from '../redux/slices/query_tab_slice'; -import { selectQueries } from '../redux/slices/query_slice'; -import { selectQueryResult } from '../redux/slices/query_result_slice'; +import { ILogExplorerProps } from '../../../../common/types/explorer'; import { initializeTabData, removeTabData } from '../../application_analytics/helpers/utils'; +import { selectQueryResult } from '../redux/slices/query_result_slice'; +import { selectQueries } from '../redux/slices/query_slice'; +import { selectQueryTabs, setSelectedQueryTab } from '../redux/slices/query_tab_slice'; +import { Explorer } from './explorer'; const searchBarConfigs = { [TAB_EVENT_ID]: { @@ -56,6 +58,7 @@ export const LogExplorer = ({ http, queryManager, }: ILogExplorerProps) => { + const routerContext = useContext(LogExplorerRouterContext)!; const dispatch = useDispatch(); const tabIds = useSelector(selectQueryTabs).queryTabIds.filter( (tabid: string) => !tabid.match(APP_ANALYTICS_TAB_ID_REGEX) @@ -145,6 +148,16 @@ export const LogExplorer = ({ if (!isEmpty(savedObjectId)) { dispatchSavedObjectId(); } + if (routerContext.searchParams.has(CREATE_TAB_PARAM_KEY)) { + // need to wait for current redux event loop to finish + setImmediate(() => { + addNewTab(NEW_TAB); + routerContext.searchParams.delete(CREATE_TAB_PARAM_KEY); + routerContext.routerProps.history.replace({ + search: routerContext.searchParams.toString(), + }); + }); + } }, []); function getQueryTab({ diff --git a/public/components/event_analytics/index.tsx b/public/components/event_analytics/index.tsx index ff4c225136..711b891d12 100644 --- a/public/components/event_analytics/index.tsx +++ b/public/components/event_analytics/index.tsx @@ -7,12 +7,17 @@ import { EuiGlobalToastList } from '@elastic/eui'; import { Toast } from '@elastic/eui/src/components/toast/global_toast_list'; import { EmptyTabParams, EventAnalyticsProps } from 'common/types/explorer'; import { isEmpty } from 'lodash'; -import React, { ReactChild, useState } from 'react'; -import { HashRouter, Route, Switch, useHistory } from 'react-router-dom'; +import React, { createContext, ReactChild, useState } from 'react'; +import { HashRouter, Route, RouteComponentProps, Switch, useHistory } from 'react-router-dom'; import { RAW_QUERY } from '../../../common/constants/explorer'; import { ObservabilitySideBar } from '../common/side_nav'; -import { Home as EventExplorerHome } from './home/home'; import { LogExplorer } from './explorer/log_explorer'; +import { Home as EventExplorerHome } from './home/home'; + +export const LogExplorerRouterContext = createContext<{ + routerProps: RouteComponentProps; + searchParams: URLSearchParams; +} | null>(null); export const EventAnalytics = ({ chrome, @@ -64,7 +69,7 @@ export const EventAnalytics = ({ { + render={(routerProps) => { chrome.setBreadcrumbs([ ...parentBreadcrumbs, eventAnalyticsBreadcrumb, @@ -74,19 +79,26 @@ export const EventAnalytics = ({ }, ]); return ( - + + + ); }} /> diff --git a/public/plugin.ts b/public/plugin.ts index a7d15bc666..a6183062c3 100644 --- a/public/plugin.ts +++ b/public/plugin.ts @@ -4,6 +4,7 @@ */ import { AppMountParameters, CoreSetup, CoreStart, Plugin } from '../../../src/core/public'; +import { CREATE_TAB_PARAM, CREATE_TAB_PARAM_KEY, TAB_CHART_ID } from '../common/constants/explorer'; import { observabilityID, observabilityPluginOrder, @@ -106,7 +107,7 @@ export class ObservabilityPlugin description: OBSERVABILITY_EMBEDDABLE_DESCRIPTION, icon: OBSERVABILITY_EMBEDDABLE_ICON, aliasApp: observabilityID, - aliasPath: '#/event_analytics/explorer', + aliasPath: `#/event_analytics/explorer/?${CREATE_TAB_PARAM_KEY}=${CREATE_TAB_PARAM[TAB_CHART_ID]}`, stage: 'production', appExtensions: { visualizations: { From 5fe84f0df86ae2f612eaeaab831e183222fdea07 Mon Sep 17 00:00:00 2001 From: Joshua Li Date: Tue, 11 Apr 2023 20:19:26 +0000 Subject: [PATCH 66/73] Allow filter by time range without PPL query in panels Signed-off-by: Joshua Li --- .../components/custom_panels/helpers/__tests__/utils.test.tsx | 1 + public/components/custom_panels/helpers/utils.tsx | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/public/components/custom_panels/helpers/__tests__/utils.test.tsx b/public/components/custom_panels/helpers/__tests__/utils.test.tsx index 55e6349e06..ba4c6b27bd 100644 --- a/public/components/custom_panels/helpers/__tests__/utils.test.tsx +++ b/public/components/custom_panels/helpers/__tests__/utils.test.tsx @@ -104,6 +104,7 @@ describe('Utils helper functions', () => { const setToast = jest.fn(); expect(isPPLFilterValid(sampleSavedVisualization.visualization.query, setToast)).toBe(false); expect(isPPLFilterValid("where Carrier = 'OpenSearch-Air'", setToast)).toBe(true); + expect(isPPLFilterValid('', setToast)).toBe(true); }); it('renders displayVisualization function', () => { diff --git a/public/components/custom_panels/helpers/utils.tsx b/public/components/custom_panels/helpers/utils.tsx index 51e94409a4..3126f0899f 100644 --- a/public/components/custom_panels/helpers/utils.tsx +++ b/public/components/custom_panels/helpers/utils.tsx @@ -462,7 +462,7 @@ export const isPPLFilterValid = ( setToast('Please remove index from PPL Filter', 'danger', undefined); return false; } - if (!checkWhereClauseExists(query)) { + if (query && !checkWhereClauseExists(query)) { setToast('PPL filters should start with a where clause', 'danger', undefined); return false; } From 415e9e50906650e499a1d61752bbf369cee3c6ef Mon Sep 17 00:00:00 2001 From: Joshua Li Date: Tue, 11 Apr 2023 20:20:27 +0000 Subject: [PATCH 67/73] Fix not able to create metrics in event analytics Signed-off-by: Joshua Li --- public/components/event_analytics/explorer/explorer.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/public/components/event_analytics/explorer/explorer.tsx b/public/components/event_analytics/explorer/explorer.tsx index 6678b69705..d24b877ba4 100644 --- a/public/components/event_analytics/explorer/explorer.tsx +++ b/public/components/event_analytics/explorer/explorer.tsx @@ -828,6 +828,7 @@ export const Explorer = ({ userVizConfigs, selectedContentTabId, explorerFields, + subType, selectedCustomPanelOptions, ]); From e9647eff035fda8daf6ccd78ff062cb7da87fba5 Mon Sep 17 00:00:00 2001 From: Joshua Li Date: Tue, 11 Apr 2023 20:21:42 +0000 Subject: [PATCH 68/73] Accept generic type for saved objects get response Signed-off-by: Joshua Li --- .../visualization_flyout/visualization_flyout.tsx | 9 ++++----- .../components/paragraph_components/paragraphs.tsx | 6 ++++-- .../osd_saved_objects/saved_visualization.ts | 2 +- .../saved_object_client/saved_objects_actions.ts | 11 ++++++++--- .../saved_objects/saved_object_client/types.ts | 6 ++++-- 5 files changed, 21 insertions(+), 13 deletions(-) diff --git a/public/components/custom_panels/panel_modules/visualization_flyout/visualization_flyout.tsx b/public/components/custom_panels/panel_modules/visualization_flyout/visualization_flyout.tsx index 9bbb236c44..971c4821da 100644 --- a/public/components/custom_panels/panel_modules/visualization_flyout/visualization_flyout.tsx +++ b/public/components/custom_panels/panel_modules/visualization_flyout/visualization_flyout.tsx @@ -36,6 +36,7 @@ import _ from 'lodash'; import React, { useEffect, useState } from 'react'; import { CoreStart } from '../../../../../../../src/core/public'; import { CUSTOM_PANELS_API_PREFIX } from '../../../../../common/constants/custom_panels'; +import { SAVED_VISUALIZATION } from '../../../../../common/constants/explorer'; import { pplResponse, SavedVisualizationType, @@ -340,15 +341,13 @@ export const VisaulizationFlyout = ({ // Fetch all saved visualizations const fetchSavedVisualizations = async () => { - return SavedObjectsActions.getBulk({ - objectType: ['savedVisualization'], + return SavedObjectsActions.getBulk({ + objectType: [SAVED_VISUALIZATION], sortOrder: 'desc', fromIndex: 0, }) .then((response) => ({ - visualizations: response.observabilityObjectList.map((visualization) => - parseSavedVisualizations(visualization as ObservabilitySavedVisualization) - ), + visualizations: response.observabilityObjectList.map(parseSavedVisualizations), })) .then((res) => { if (res.visualizations.length > 0) { diff --git a/public/components/notebooks/components/paragraph_components/paragraphs.tsx b/public/components/notebooks/components/paragraph_components/paragraphs.tsx index 76a33480f5..333cb90deb 100644 --- a/public/components/notebooks/components/paragraph_components/paragraphs.tsx +++ b/public/components/notebooks/components/paragraph_components/paragraphs.tsx @@ -138,9 +138,11 @@ export const Paragraphs = forwardRef((props: ParagraphProps, ref) => { }) .catch((err) => console.error('Fetching dashboard visualization issue', err.body.message)); - await SavedObjectsActions.getBulk({ objectType: ['savedVisualization'] }) + await SavedObjectsActions.getBulk({ + objectType: ['savedVisualization'], + }) .then((res) => { - opt2 = (res.observabilityObjectList as ObservabilitySavedVisualization[]) + opt2 = res.observabilityObjectList .filter((visualization) => !visualization.savedVisualization.application_id) .map((visualization) => ({ label: visualization.savedVisualization.name, diff --git a/public/services/saved_objects/saved_object_client/osd_saved_objects/saved_visualization.ts b/public/services/saved_objects/saved_object_client/osd_saved_objects/saved_visualization.ts index 9949a36cec..635199c546 100644 --- a/public/services/saved_objects/saved_object_client/osd_saved_objects/saved_visualization.ts +++ b/public/services/saved_objects/saved_object_client/osd_saved_objects/saved_visualization.ts @@ -153,7 +153,7 @@ export class OSDSavedVisualizationClient extends OSDSavedObjectClient { savedVisualization: o.attributes.savedVisualization, })) ); - return { observabilityObjectList }; + return { totalHits: observabilityObjectList.length, observabilityObjectList }; } async delete(params: SavedObjectsDeleteParams): Promise { diff --git a/public/services/saved_objects/saved_object_client/saved_objects_actions.ts b/public/services/saved_objects/saved_object_client/saved_objects_actions.ts index 262f31f1c6..2b96c6a6c3 100644 --- a/public/services/saved_objects/saved_object_client/saved_objects_actions.ts +++ b/public/services/saved_objects/saved_object_client/saved_objects_actions.ts @@ -10,6 +10,7 @@ import { OSDSavedVisualizationClient } from './osd_saved_objects/saved_visualiza import { ObservabilitySavedObjectsType } from './osd_saved_objects/types'; import { PPLSavedQueryClient } from './ppl'; import { + ObservabilitySavedObject, SavedObjectsDeleteBulkParams, SavedObjectsDeleteParams, SavedObjectsDeleteResponse, @@ -36,7 +37,9 @@ export class SavedObjectsActions { } } - static async getBulk(params: ISavedObjectRequestParams): Promise { + static async getBulk( + params: ISavedObjectRequestParams + ): Promise> { const objects = await PPLSavedQueryClient.getInstance().getBulk(params); if (params.objectType?.includes('savedVisualization')) { const osdVisualizationObjects = await OSDSavedVisualizationClient.getInstance().getBulk(); @@ -54,7 +57,7 @@ export class SavedObjectsActions { } else { objects.observabilityObjectList.sort((a, b) => b.lastUpdatedTimeMs - a.lastUpdatedTimeMs); } - return objects; + return objects as SavedObjectsGetResponse; } static delete(params: SavedObjectsDeleteParams): Promise { @@ -88,7 +91,9 @@ export class SavedObjectsActions { if (idMap[VISUALIZATION_SAVED_OBJECT]?.length) { const visualizationDeleteResponses = await OSDSavedVisualizationClient.getInstance().deleteBulk( - { objectIdList: idMap[VISUALIZATION_SAVED_OBJECT] } + { + objectIdList: idMap[VISUALIZATION_SAVED_OBJECT], + } ); responses.deleteResponseList = { ...responses.deleteResponseList, diff --git a/public/services/saved_objects/saved_object_client/types.ts b/public/services/saved_objects/saved_object_client/types.ts index 6257011d12..81112fd67c 100644 --- a/public/services/saved_objects/saved_object_client/types.ts +++ b/public/services/saved_objects/saved_object_client/types.ts @@ -33,11 +33,13 @@ export interface SavedObjectsGetParams { objectId: string; } -export interface SavedObjectsGetResponse { +export interface SavedObjectsGetResponse< + T extends ObservabilitySavedObject = ObservabilitySavedObject +> { startIndex?: number; totalHits?: number; totalHitRelation?: 'eq' | 'gte'; - observabilityObjectList: ObservabilitySavedObject[]; + observabilityObjectList: T[]; } export interface SavedObjectsDeleteParams { From 2a251300327e545c2238325552b63f332ed7ba2d Mon Sep 17 00:00:00 2001 From: Joshua Li Date: Tue, 11 Apr 2023 20:23:11 +0000 Subject: [PATCH 69/73] Fetch vis from observability and OSD indices in metrics analytics Signed-off-by: Joshua Li --- .../metrics/redux/slices/metrics_slice.ts | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/public/components/metrics/redux/slices/metrics_slice.ts b/public/components/metrics/redux/slices/metrics_slice.ts index a443a806c6..3054b25b90 100644 --- a/public/components/metrics/redux/slices/metrics_slice.ts +++ b/public/components/metrics/redux/slices/metrics_slice.ts @@ -3,19 +3,17 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { createSlice, createAsyncThunk } from '@reduxjs/toolkit'; +import { createAsyncThunk, createSlice } from '@reduxjs/toolkit'; import { PPL_DATASOURCES_REQUEST, REDUX_SLICE_METRICS, + SAVED_VISUALIZATION, } from '../../../../../common/constants/metrics'; -import { - pplServiceRequestor, - getVisualizations, - getNewVizDimensions, - sortMetricLayout, -} from '../../helpers/utils'; -import PPLService from '../../../../services/requests/ppl'; import { MetricType } from '../../../../../common/types/metrics'; +import PPLService from '../../../../services/requests/ppl'; +import { SavedObjectsActions } from '../../../../services/saved_objects/saved_object_client/saved_objects_actions'; +import { ObservabilitySavedVisualization } from '../../../../services/saved_objects/saved_object_client/types'; +import { getNewVizDimensions, pplServiceRequestor, sortMetricLayout } from '../../helpers/utils'; const initialState = { pplService: PPLService, @@ -34,9 +32,11 @@ export const loadMetrics = createAsyncThunk('metrics/loadData', async (services: }); const fetchCustomMetrics = async (http: any) => { - const dataSet = await getVisualizations(http); + const dataSet = await SavedObjectsActions.getBulk({ + objectType: [SAVED_VISUALIZATION], + }); const savedMetrics = dataSet.observabilityObjectList.filter( - (obj: any) => obj.savedVisualization.sub_type === 'metric' + (obj) => obj.savedVisualization.sub_type === 'metric' ); const normalizedData = savedMetrics.map((obj: any) => ({ id: obj.objectId, From ad665d5012b6b893b0be542818dfac635860bbc1 Mon Sep 17 00:00:00 2001 From: Joshua Li Date: Tue, 11 Apr 2023 22:14:19 +0000 Subject: [PATCH 70/73] Check for routerContext existence Signed-off-by: Joshua Li --- public/components/event_analytics/explorer/explorer.tsx | 7 +++++-- .../components/event_analytics/explorer/log_explorer.tsx | 4 ++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/public/components/event_analytics/explorer/explorer.tsx b/public/components/event_analytics/explorer/explorer.tsx index d24b877ba4..29ce73d7dd 100644 --- a/public/components/event_analytics/explorer/explorer.tsx +++ b/public/components/event_analytics/explorer/explorer.tsx @@ -143,7 +143,7 @@ export const Explorer = ({ callbackInApp, queryManager = new QueryManager(), }: IExplorerProps) => { - const routerContext = useContext(LogExplorerRouterContext)!; + const routerContext = useContext(LogExplorerRouterContext); const dispatch = useDispatch(); const requestParams = { tabId }; const { getLiveTail, getEvents, getAvailableFields } = useFetchEvents({ @@ -361,7 +361,10 @@ export const Explorer = ({ } else { fetchData(); } - if (routerContext.searchParams.get(CREATE_TAB_PARAM_KEY) === CREATE_TAB_PARAM[TAB_CHART_ID]) { + if ( + routerContext && + routerContext.searchParams.get(CREATE_TAB_PARAM_KEY) === CREATE_TAB_PARAM[TAB_CHART_ID] + ) { setSelectedContentTab(TAB_CHART_ID); } }, []); diff --git a/public/components/event_analytics/explorer/log_explorer.tsx b/public/components/event_analytics/explorer/log_explorer.tsx index bade273377..ac9aa69bd9 100644 --- a/public/components/event_analytics/explorer/log_explorer.tsx +++ b/public/components/event_analytics/explorer/log_explorer.tsx @@ -58,7 +58,7 @@ export const LogExplorer = ({ http, queryManager, }: ILogExplorerProps) => { - const routerContext = useContext(LogExplorerRouterContext)!; + const routerContext = useContext(LogExplorerRouterContext); const dispatch = useDispatch(); const tabIds = useSelector(selectQueryTabs).queryTabIds.filter( (tabid: string) => !tabid.match(APP_ANALYTICS_TAB_ID_REGEX) @@ -148,7 +148,7 @@ export const LogExplorer = ({ if (!isEmpty(savedObjectId)) { dispatchSavedObjectId(); } - if (routerContext.searchParams.has(CREATE_TAB_PARAM_KEY)) { + if (routerContext && routerContext.searchParams.has(CREATE_TAB_PARAM_KEY)) { // need to wait for current redux event loop to finish setImmediate(() => { addNewTab(NEW_TAB); From 6813b031d742efc7ac4d497c91a7f92e4c8bd10d Mon Sep 17 00:00:00 2001 From: Joshua Li Date: Tue, 11 Apr 2023 22:31:00 +0000 Subject: [PATCH 71/73] Fix app analytics base query label position Signed-off-by: Joshua Li --- public/components/common/search/search.scss | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/public/components/common/search/search.scss b/public/components/common/search/search.scss index f079dec512..681a7f0b92 100644 --- a/public/components/common/search/search.scss +++ b/public/components/common/search/search.scss @@ -10,8 +10,6 @@ .aa-Autocomplete { width: 100%; position: relative; - margin: 4px; - margin-left: 8px; --aa-search-input-height: 38px; --aa-panel-border-color-rgb: rgba(227,230,238,255); --aa-input-background-color-rbg: rgba(250,251,253,255); @@ -72,8 +70,6 @@ .base-query-popover { border: unset; font-size: 17px; - position: absolute; - top: 20px; - left: 8px; + margin-top: 14px; background-color: transparent; } From a6552b9d74b427754b4d7f2f536bf86b7a420ab5 Mon Sep 17 00:00:00 2001 From: Joshua Li Date: Tue, 11 Apr 2023 23:02:55 +0000 Subject: [PATCH 72/73] Fix pagination in event analytics table Signed-off-by: Joshua Li --- .../event_analytics/home/saved_objects_table.tsx | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/public/components/event_analytics/home/saved_objects_table.tsx b/public/components/event_analytics/home/saved_objects_table.tsx index 62207a7538..9aa396264a 100644 --- a/public/components/event_analytics/home/saved_objects_table.tsx +++ b/public/components/event_analytics/home/saved_objects_table.tsx @@ -3,8 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { EuiIcon, EuiInMemoryTable, EuiLink } from '@elastic/eui'; -import { isEmpty } from 'lodash'; +import { Criteria, EuiIcon, EuiInMemoryTable, EuiLink } from '@elastic/eui'; import React, { useRef, useState } from 'react'; import { FILTER_OPTIONS } from '../../../../common/constants/explorer'; @@ -29,11 +28,12 @@ export function SavedQueryTable({ const pageSizeRef = useRef(); pageSizeRef.current = pageSize; - const onTableChange = ({ page = {} }) => { - const { index, size } = page; - - setPageIndex(page); - setPageSize(size); + const onTableChange = (criteria: Criteria) => { + if (criteria.page) { + const { index, size } = criteria.page; + setPageIndex(index); + setPageSize(size); + } }; const columns = [ From 617482f90860268c1ed479ec497297da1bab4a3d Mon Sep 17 00:00:00 2001 From: Joshua Li Date: Thu, 13 Apr 2023 17:26:40 +0000 Subject: [PATCH 73/73] Fix typo in SaveAsCurrentQuery Signed-off-by: Joshua Li --- public/components/event_analytics/explorer/explorer.tsx | 4 ++-- public/services/saved_objects/saved_object_savers/index.ts | 2 +- .../saved_object_savers/ppl/save_current_query.ts | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/public/components/event_analytics/explorer/explorer.tsx b/public/components/event_analytics/explorer/explorer.tsx index 29ce73d7dd..32423d6ffe 100644 --- a/public/components/event_analytics/explorer/explorer.tsx +++ b/public/components/event_analytics/explorer/explorer.tsx @@ -86,7 +86,7 @@ import { } from '../../../services/saved_objects/saved_object_client/ppl'; import { PPLSavedObjectLoader } from '../../../services/saved_objects/saved_object_loaders/ppl/ppl_loader'; import { - SaveAsCurrenQuery, + SaveAsCurrentQuery, SaveAsCurrentVisualization, SaveAsNewVisualization, } from '../../../services/saved_objects/saved_object_savers'; @@ -762,7 +762,7 @@ export const Explorer = ({ let soClient; if (isOnEventPage) { if (isTabHasObjID && isObjTypeMatchQuery) { - soClient = new SaveAsCurrenQuery( + soClient = new SaveAsCurrentQuery( { tabId, notifications }, { dispatch, updateTabName }, PPLSavedQueryClient.getInstance(), diff --git a/public/services/saved_objects/saved_object_savers/index.ts b/public/services/saved_objects/saved_object_savers/index.ts index 74f10f32ea..b20c5d91a1 100644 --- a/public/services/saved_objects/saved_object_savers/index.ts +++ b/public/services/saved_objects/saved_object_savers/index.ts @@ -7,6 +7,6 @@ export { ISavedObjectSaver } from './saver_interface'; export { SavedObjectSaverBase } from './saver_base'; export { SavedQuerySaver } from './ppl/saved_query_saver'; export { SaveAsNewQuery } from './ppl/save_as_new_query'; -export { SaveAsCurrenQuery } from './ppl/save_current_query'; +export { SaveAsCurrentQuery } from './ppl/save_current_query'; export { SaveAsNewVisualization } from './ppl/save_as_new_vis'; export { SaveAsCurrentVisualization } from './ppl/save_as_current_vis'; diff --git a/public/services/saved_objects/saved_object_savers/ppl/save_current_query.ts b/public/services/saved_objects/saved_object_savers/ppl/save_current_query.ts index 717c2fb074..05c2d3560a 100644 --- a/public/services/saved_objects/saved_object_savers/ppl/save_current_query.ts +++ b/public/services/saved_objects/saved_object_savers/ppl/save_current_query.ts @@ -5,7 +5,7 @@ import { SavedQuerySaver } from './saved_query_saver'; -export class SaveAsCurrenQuery extends SavedQuerySaver { +export class SaveAsCurrentQuery extends SavedQuerySaver { constructor( private readonly saveContext, protected readonly dispatchers,