diff --git a/dashboards-observability/common/constants/shared.ts b/dashboards-observability/common/constants/shared.ts index 72a915343..8c1ea2081 100644 --- a/dashboards-observability/common/constants/shared.ts +++ b/dashboards-observability/common/constants/shared.ts @@ -82,7 +82,8 @@ export enum visChartTypes { Text = 'text', Gauge = 'gauge', Histogram = 'histogram', - TreeMap = 'tree_map' + TreeMap = 'tree_map', + LogsView = 'logs_view' } export interface ValueOptionsAxes { @@ -97,7 +98,7 @@ export interface ValueOptionsAxes { export const NUMERICAL_FIELDS = ['short', 'integer', 'long', 'float', 'double']; -export const ENABLED_VIS_TYPES = [visChartTypes.Bar, visChartTypes.HorizontalBar, visChartTypes.Line, visChartTypes.Pie, visChartTypes.HeatMap, visChartTypes.Text, visChartTypes.TreeMap, visChartTypes.Gauge, visChartTypes.Histogram]; +export const ENABLED_VIS_TYPES = [visChartTypes.Bar, visChartTypes.HorizontalBar, visChartTypes.Line, visChartTypes.Pie, visChartTypes.HeatMap, visChartTypes.Text, visChartTypes.TreeMap, visChartTypes.Gauge, visChartTypes.Histogram, visChartTypes.LogsView]; //Live tail constants export const LIVE_OPTIONS = [ diff --git a/dashboards-observability/common/types/explorer.ts b/dashboards-observability/common/types/explorer.ts index ade2c6db3..f16113c53 100644 --- a/dashboards-observability/common/types/explorer.ts +++ b/dashboards-observability/common/types/explorer.ts @@ -190,8 +190,8 @@ export interface IConfigPanelOptionSection { mapTo: string; props?: any; isSingleSelection?: boolean; - defaultState?: number; eleType?: string; + defaultState?: boolean | string; } export interface IVisualizationTypeDefination { diff --git a/dashboards-observability/public/components/custom_panels/helpers/__tests__/__snapshots__/utils.test.tsx.snap b/dashboards-observability/public/components/custom_panels/helpers/__tests__/__snapshots__/utils.test.tsx.snap index b2f78ed0b..b2e6cd98c 100644 --- a/dashboards-observability/public/components/custom_panels/helpers/__tests__/__snapshots__/utils.test.tsx.snap +++ b/dashboards-observability/public/components/custom_panels/helpers/__tests__/__snapshots__/utils.test.tsx.snap @@ -86,7 +86,7 @@ exports[`Utils helper functions renders displayVisualization function 1`] = ` "editor": [Function], "id": "data-panel", "mapTo": "dataConfig", - "name": "Data", + "name": "Style", "sections": Array [ Object { "editor": [Function], @@ -447,7 +447,7 @@ exports[`Utils helper functions renders displayVisualization function 1`] = ` "editor": [Function], "id": "data-panel", "mapTo": "dataConfig", - "name": "Data", + "name": "Style", "sections": Array [ Object { "editor": [Function], @@ -831,7 +831,7 @@ exports[`Utils helper functions renders displayVisualization function 1`] = ` "editor": [Function], "id": "data-panel", "mapTo": "dataConfig", - "name": "Data", + "name": "Style", "sections": Array [ Object { "editor": [Function], @@ -1373,7 +1373,7 @@ exports[`Utils helper functions renders displayVisualization function 2`] = ` "editor": [Function], "id": "data-panel", "mapTo": "dataConfig", - "name": "Data", + "name": "Style", "sections": Array [ Object { "editor": [Function], @@ -1706,7 +1706,7 @@ exports[`Utils helper functions renders displayVisualization function 2`] = ` "editor": [Function], "id": "data-panel", "mapTo": "dataConfig", - "name": "Data", + "name": "Style", "sections": Array [ Object { "editor": [Function], @@ -2093,7 +2093,7 @@ exports[`Utils helper functions renders displayVisualization function 2`] = ` "editor": [Function], "id": "data-panel", "mapTo": "dataConfig", - "name": "Data", + "name": "Style", "sections": Array [ Object { "editor": [Function], @@ -2511,7 +2511,7 @@ exports[`Utils helper functions renders displayVisualization function 3`] = ` "editor": [Function], "id": "data-panel", "mapTo": "dataConfig", - "name": "Data", + "name": "Style", "sections": Array [ Object { "editor": [Function], @@ -2721,7 +2721,7 @@ exports[`Utils helper functions renders displayVisualization function 3`] = ` "editor": [Function], "id": "data-panel", "mapTo": "dataConfig", - "name": "Data", + "name": "Style", "sections": Array [ Object { "editor": [Function], @@ -2954,7 +2954,7 @@ exports[`Utils helper functions renders displayVisualization function 3`] = ` "editor": [Function], "id": "data-panel", "mapTo": "dataConfig", - "name": "Data", + "name": "Style", "sections": Array [ Object { "editor": [Function], @@ -3319,7 +3319,7 @@ exports[`Utils helper functions renders displayVisualization function 4`] = ` "editor": [Function], "id": "data-panel", "mapTo": "dataConfig", - "name": "Data", + "name": "Style", "sections": Array [ Object { "editor": [Function], @@ -3502,7 +3502,7 @@ exports[`Utils helper functions renders displayVisualization function 4`] = ` "editor": [Function], "id": "data-panel", "mapTo": "dataConfig", - "name": "Data", + "name": "Style", "sections": Array [ Object { "editor": [Function], @@ -3708,7 +3708,7 @@ exports[`Utils helper functions renders displayVisualization function 4`] = ` "editor": [Function], "id": "data-panel", "mapTo": "dataConfig", - "name": "Data", + "name": "Style", "sections": Array [ Object { "editor": [Function], diff --git a/dashboards-observability/public/components/event_analytics/explorer/explorer.tsx b/dashboards-observability/public/components/event_analytics/explorer/explorer.tsx index 015bf48f5..1988e2a50 100644 --- a/dashboards-observability/public/components/event_analytics/explorer/explorer.tsx +++ b/dashboards-observability/public/components/event_analytics/explorer/explorer.tsx @@ -1136,6 +1136,8 @@ export const Explorer = ({ explorerVisualizations, setToast, pplService, + explorerFields, + explorerData }} >
diff --git a/dashboards-observability/public/components/event_analytics/explorer/visualizations/config_panel/__tests__/__snapshots__/config_panel.test.tsx.snap b/dashboards-observability/public/components/event_analytics/explorer/visualizations/config_panel/__tests__/__snapshots__/config_panel.test.tsx.snap index 41ed1a021..37aaf6491 100644 --- a/dashboards-observability/public/components/event_analytics/explorer/visualizations/config_panel/__tests__/__snapshots__/config_panel.test.tsx.snap +++ b/dashboards-observability/public/components/event_analytics/explorer/visualizations/config_panel/__tests__/__snapshots__/config_panel.test.tsx.snap @@ -211,7 +211,7 @@ exports[`Config panel component Renders config panel with visualization data 1`] "editor": [Function], "id": "data-panel", "mapTo": "dataConfig", - "name": "Data", + "name": "Style", "sections": Array [ Object { "editor": [Function], @@ -532,7 +532,7 @@ exports[`Config panel component Renders config panel with visualization data 1`] "editor": [Function], "id": "data-panel", "mapTo": "dataConfig", - "name": "Data", + "name": "Style", "sections": Array [ Object { "editor": [Function], @@ -816,7 +816,7 @@ exports[`Config panel component Renders config panel with visualization data 1`] "editor": [Function], "id": "data-panel", "mapTo": "dataConfig", - "name": "Data", + "name": "Style", "sections": Array [ Object { "editor": [Function], @@ -1073,7 +1073,7 @@ exports[`Config panel component Renders config panel with visualization data 1`] "editor": [Function], "id": "data-panel", "mapTo": "dataConfig", - "name": "Data", + "name": "Style", "sections": Array [ Object { "editor": [Function], @@ -1275,7 +1275,7 @@ exports[`Config panel component Renders config panel with visualization data 1`] "editor": [Function], "id": "data-panel", "mapTo": "dataConfig", - "name": "Data", + "name": "Style", "sections": Array [ Object { "editor": [Function], @@ -1603,7 +1603,7 @@ exports[`Config panel component Renders config panel with visualization data 1`] "editor": [Function], "id": "data-panel", "mapTo": "dataConfig", - "name": "Data", + "name": "Style", "sections": Array [ Object { "editor": [Function], @@ -1690,7 +1690,7 @@ exports[`Config panel component Renders config panel with visualization data 1`] "editor": [Function], "id": "data-panel", "mapTo": "dataConfig", - "name": "Data", + "name": "Style", "sections": Array [ Object { "editor": [Function], @@ -2103,7 +2103,7 @@ exports[`Config panel component Renders config panel with visualization data 1`] "editor": [Function], "id": "data-panel", "mapTo": "dataConfig", - "name": "Data", + "name": "Style", "sections": Array [ Object { "editor": [Function], @@ -2232,7 +2232,7 @@ exports[`Config panel component Renders config panel with visualization data 1`] "editor": [Function], "id": "data-panel", "mapTo": "dataConfig", - "name": "Data", + "name": "Style", "sections": Array [ Object { "editor": [Function], @@ -2366,6 +2366,142 @@ exports[`Config panel component Renders config panel with visualization data 1`] }, }, }, + Object { + "category": "Visualizations", + "categoryAxis": "xaxis", + "component": [Function], + "editorConfig": Object { + "panelTabs": Array [ + Object { + "editor": [Function], + "id": "data-panel", + "mapTo": "dataConfig", + "name": "Style", + "sections": Array [ + Object { + "editor": [Function], + "id": "chart_styles", + "mapTo": "chartStyles", + "name": "Chart styles", + "schemas": Array [ + Object { + "component": [Function], + "defaultState": true, + "eleType": "switch", + "mapTo": "time", + "name": "Time", + }, + Object { + "component": [Function], + "defaultState": true, + "eleType": "switch", + "mapTo": "enableLogDetails", + "name": "Log Details View", + }, + Object { + "component": [Function], + "eleType": "buttons", + "mapTo": "view", + "name": "View", + "props": Object { + "defaultSelections": Array [ + Object { + "id": "default", + "name": "Default", + }, + ], + "options": Array [ + Object { + "id": "default", + "name": "Default", + }, + Object { + "id": "wrapLines", + "name": "Wrap lines", + }, + Object { + "id": "prettifyJSON", + "name": "Prettify JSON", + }, + ], + }, + }, + Object { + "component": [Function], + "eleType": "input", + "mapTo": "labelSize", + "name": "Label Size", + }, + ], + }, + ], + }, + ], + }, + "fullLabel": "Logs View", + "icon": [Function], + "iconType": "visTable", + "id": "logs_view", + "label": "Logs View", + "name": "logs_view", + "selection": Object { + "dataLoss": "nothing", + }, + "seriesAxis": "yaxis", + "type": "logs_view", + "visConfig": Object { + "config": Object { + "barmode": "line", + "displaylogo": false, + "responsive": true, + "xaxis": Object { + "automargin": true, + }, + "yaxis": Object { + "automargin": true, + }, + }, + "layout": Object { + "colorway": Array [ + "#3CA1C7", + "#8C55A3", + "#DB748A", + "#F2BE4B", + "#68CCC2", + "#2A7866", + "#843769", + "#374FB8", + "#BD6F26", + "#4C636F", + ], + "height": 500, + "legend": Object { + "orientation": "v", + "traceorder": "normal", + }, + "margin": Object { + "b": 30, + "l": 60, + "pad": 0, + "r": 30, + "t": 50, + }, + "paper_bgcolor": "rgba(0, 0, 0, 0)", + "plot_bgcolor": "rgba(0, 0, 0, 0)", + "showlegend": true, + "xaxis": Object { + "fixedrange": true, + "showgrid": false, + "visible": true, + }, + "yaxis": Object { + "fixedrange": true, + "showgrid": false, + "visible": true, + }, + }, + }, + }, ] } placeholder="Select a chart" @@ -2383,7 +2519,7 @@ exports[`Config panel component Renders config panel with visualization data 1`] "editor": [Function], "id": "data-panel", "mapTo": "dataConfig", - "name": "Data", + "name": "Style", "sections": Array [ Object { "editor": [Function], @@ -2700,7 +2836,7 @@ exports[`Config panel component Renders config panel with visualization data 1`] "editor": [Function], "id": "data-panel", "mapTo": "dataConfig", - "name": "Data", + "name": "Style", "sections": Array [ Object { "editor": [Function], @@ -3022,7 +3158,7 @@ exports[`Config panel component Renders config panel with visualization data 1`] "editor": [Function], "id": "data-panel", "mapTo": "dataConfig", - "name": "Data", + "name": "Style", "sections": Array [ Object { "editor": [Function], @@ -3279,7 +3415,7 @@ exports[`Config panel component Renders config panel with visualization data 1`] "editor": [Function], "id": "data-panel", "mapTo": "dataConfig", - "name": "Data", + "name": "Style", "sections": Array [ Object { "editor": [Function], @@ -3602,7 +3738,7 @@ exports[`Config panel component Renders config panel with visualization data 1`] "editor": [Function], "id": "data-panel", "mapTo": "dataConfig", - "name": "Data", + "name": "Style", "sections": Array [ Object { "editor": [Function], @@ -3895,7 +4031,7 @@ exports[`Config panel component Renders config panel with visualization data 1`] "editor": [Function], "id": "data-panel", "mapTo": "dataConfig", - "name": "Data", + "name": "Style", "sections": Array [ Object { "editor": [Function], @@ -4371,7 +4507,7 @@ exports[`Config panel component Renders config panel with visualization data 1`] "editor": [Function], "id": "data-panel", "mapTo": "dataConfig", - "name": "Data", + "name": "Style", "sections": Array [ Object { "editor": [Function], @@ -4782,7 +4918,7 @@ exports[`Config panel component Renders config panel with visualization data 1`] "editor": [Function], "id": "data-panel", "mapTo": "dataConfig", - "name": "Data", + "name": "Style", "sections": Array [ Object { "editor": [Function], @@ -5065,7 +5201,7 @@ exports[`Config panel component Renders config panel with visualization data 1`] } />, "id": "data-panel", - "name": "Data", + "name": "Style", } } tabs={ @@ -5079,7 +5215,7 @@ exports[`Config panel component Renders config panel with visualization data 1`] "editor": [Function], "id": "data-panel", "mapTo": "dataConfig", - "name": "Data", + "name": "Style", "sections": Array [ Object { "editor": [Function], @@ -5490,7 +5626,7 @@ exports[`Config panel component Renders config panel with visualization data 1`] "editor": [Function], "id": "data-panel", "mapTo": "dataConfig", - "name": "Data", + "name": "Style", "sections": Array [ Object { "editor": [Function], @@ -5773,7 +5909,7 @@ exports[`Config panel component Renders config panel with visualization data 1`] } />, "id": "data-panel", - "name": "Data", + "name": "Style", }, Object { "content": - Data + Style @@ -6379,7 +6515,7 @@ exports[`Config panel component Renders config panel with visualization data 1`] "editor": [Function], "id": "data-panel", "mapTo": "dataConfig", - "name": "Data", + "name": "Style", "sections": Array [ Object { "editor": [Function], @@ -6790,7 +6926,7 @@ exports[`Config panel component Renders config panel with visualization data 1`] "editor": [Function], "id": "data-panel", "mapTo": "dataConfig", - "name": "Data", + "name": "Style", "sections": Array [ Object { "editor": [Function], @@ -7294,7 +7430,7 @@ exports[`Config panel component Renders config panel with visualization data 1`] "editor": [Function], "id": "data-panel", "mapTo": "dataConfig", - "name": "Data", + "name": "Style", "sections": Array [ Object { "editor": [Function], @@ -8042,7 +8178,7 @@ exports[`Config panel component Renders config panel with visualization data 1`] "editor": [Function], "id": "data-panel", "mapTo": "dataConfig", - "name": "Data", + "name": "Style", "sections": Array [ Object { "editor": [Function], @@ -9198,7 +9334,7 @@ exports[`Config panel component Renders config panel with visualization data 1`] "editor": [Function], "id": "data-panel", "mapTo": "dataConfig", - "name": "Data", + "name": "Style", "sections": Array [ Object { "editor": [Function], @@ -10452,7 +10588,7 @@ exports[`Config panel component Renders config panel with visualization data 1`] "editor": [Function], "id": "data-panel", "mapTo": "dataConfig", - "name": "Data", + "name": "Style", "sections": Array [ Object { "editor": [Function], @@ -13263,7 +13399,7 @@ exports[`Config panel component Renders config panel with visualization data 1`] "editor": [Function], "id": "data-panel", "mapTo": "dataConfig", - "name": "Data", + "name": "Style", "sections": Array [ Object { "editor": [Function], diff --git a/dashboards-observability/public/components/event_analytics/explorer/visualizations/config_panel/config_panel.tsx b/dashboards-observability/public/components/event_analytics/explorer/visualizations/config_panel/config_panel.tsx index e377e2427..0beb76fc0 100644 --- a/dashboards-observability/public/components/event_analytics/explorer/visualizations/config_panel/config_panel.tsx +++ b/dashboards-observability/public/components/event_analytics/explorer/visualizations/config_panel/config_panel.tsx @@ -127,7 +127,8 @@ export const ConfigPanel = ({ visualizations, setCurVisId, callback, changeIsVal bar: isValidValueOptionsXYAxes, line: isValidValueOptionsXYAxes, histogram: isValidValueOptionsXYAxes, - pie: isValidValueOptionsXYAxes + pie: isValidValueOptionsXYAxes, + logs_view: true } return isValid_valueOptions[curVisId]; }, [vizConfigs.dataConfig]); diff --git a/dashboards-observability/public/components/event_analytics/explorer/visualizations/config_panel/config_panes/config_controls/config_logs_view.tsx b/dashboards-observability/public/components/event_analytics/explorer/visualizations/config_panel/config_panes/config_controls/config_logs_view.tsx new file mode 100644 index 000000000..4f7de3107 --- /dev/null +++ b/dashboards-observability/public/components/event_analytics/explorer/visualizations/config_panel/config_panes/config_controls/config_logs_view.tsx @@ -0,0 +1,105 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React, { useCallback, useContext, useMemo } from 'react'; +import { EuiAccordion, EuiSpacer } from '@elastic/eui'; +import { IConfigPanelOptionSection } from '../../../../../../../../common/types/explorer'; +import { ButtonGroupItem } from './config_button_group'; +import { TabContext } from '../../../../../../event_analytics/hooks'; + +export const ConfigLogsView = ({ + visualizations, + schemas, + vizState, + handleConfigChange, + sectionName, + sectionId = 'chartStyles', +}) => { + const { explorerData } = useContext(TabContext); + const rawData = explorerData.jsonData; + + const handleConfigurationChange = useCallback( + (stateFiledName) => { + return (changes) => { + handleConfigChange({ + ...vizState, + [stateFiledName]: changes, + }); + }; + }, + [handleConfigChange, vizState] + ); + + const dimensions = useMemo( + () => + schemas.map((schema: IConfigPanelOptionSection, index: string) => { + let params = { + title: schema.name, + vizState, + ...schema.props, + }; + const DimensionComponent = schema.component || ButtonGroupItem; + if (schema.eleType === 'buttons') { + params = { + title: schema.name, + legend: schema.name, + groupOptions: schema?.props?.options.map((btn: { name: string }) => ({ + ...btn, + label: btn.name, + })), + idSelected: vizState[schema.mapTo] || schema?.props?.defaultSelections[0]?.id, + handleButtonChange: handleConfigurationChange(schema.mapTo), + vizState, + ...schema.props, + }; + } else if (schema.eleType === 'switch') { + let isDisabled = false; + if (schema.name === 'Time') { + const isTimeAvailable = + rawData && + rawData.find( + (data) => data.timestamp !== undefined || data.new_timestamp !== undefined + ); + isDisabled = isTimeAvailable === undefined; + } + params = { + label: schema.name, + disabled: isDisabled, + checked: + vizState[schema.mapTo] !== undefined ? vizState[schema.mapTo] : schema?.defaultState, + handleChange: handleConfigurationChange(schema.mapTo), + vizState, + ...schema.props, + }; + } else { + params = { + title: schema.name, + currentValue: vizState[schema.mapTo] || '', + handleInputChange: handleConfigurationChange(schema.mapTo), + vizState, + ...schema.props, + }; + } + return ( + <> + + + + ); + }), + [schemas, vizState, handleConfigurationChange] + ); + + return ( + + {dimensions} + + ); +}; diff --git a/dashboards-observability/public/components/event_analytics/explorer/visualizations/config_panel/config_panes/config_controls/config_number_input.tsx b/dashboards-observability/public/components/event_analytics/explorer/visualizations/config_panel/config_panes/config_controls/config_number_input.tsx index ffca76f7b..79cb59a31 100644 --- a/dashboards-observability/public/components/event_analytics/explorer/visualizations/config_panel/config_panes/config_controls/config_number_input.tsx +++ b/dashboards-observability/public/components/event_analytics/explorer/visualizations/config_panel/config_panes/config_controls/config_number_input.tsx @@ -30,6 +30,7 @@ export const InputFieldItem: React.FC = ({ fullWidth placeholder="auto" value={fieldValue} + min={1} onChange={(e) => setFieldValue(e.target.value)} onBlur={() => handleInputChange(fieldValue)} data-test-subj="valueFieldNumber" diff --git a/dashboards-observability/public/components/event_analytics/explorer/visualizations/config_panel/config_panes/config_controls/config_switch.tsx b/dashboards-observability/public/components/event_analytics/explorer/visualizations/config_panel/config_panes/config_controls/config_switch.tsx new file mode 100644 index 000000000..faa226ddf --- /dev/null +++ b/dashboards-observability/public/components/event_analytics/explorer/visualizations/config_panel/config_panes/config_controls/config_switch.tsx @@ -0,0 +1,31 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React from 'react'; +import { uniqueId } from 'lodash'; +import { EuiSpacer, EuiFormRow, EuiSwitch, EuiSwitchEvent } from '@elastic/eui'; + +interface EUISwitch { + label: string; + disabled: boolean; + checked: boolean; + handleChange: (event: EuiSwitchEvent) => void; +} +export const ConfigSwitch: React.FC = ({ label, disabled, checked, handleChange }) => ( + <> + + handleChange(e.target.checked)} + compressed + /> + + + +); diff --git a/dashboards-observability/public/components/visualizations/charts/__tests__/__snapshots__/bar.test.tsx.snap b/dashboards-observability/public/components/visualizations/charts/__tests__/__snapshots__/bar.test.tsx.snap index 1d19db62f..1baba62e2 100644 --- a/dashboards-observability/public/components/visualizations/charts/__tests__/__snapshots__/bar.test.tsx.snap +++ b/dashboards-observability/public/components/visualizations/charts/__tests__/__snapshots__/bar.test.tsx.snap @@ -212,7 +212,7 @@ exports[`Bar component Renders bar component 1`] = ` "editor": [Function], "id": "data-panel", "mapTo": "dataConfig", - "name": "Data", + "name": "Style", "sections": Array [ Object { "editor": [Function], diff --git a/dashboards-observability/public/components/visualizations/charts/__tests__/__snapshots__/heatmap.test.tsx.snap b/dashboards-observability/public/components/visualizations/charts/__tests__/__snapshots__/heatmap.test.tsx.snap index edcc736fb..d813401b5 100644 --- a/dashboards-observability/public/components/visualizations/charts/__tests__/__snapshots__/heatmap.test.tsx.snap +++ b/dashboards-observability/public/components/visualizations/charts/__tests__/__snapshots__/heatmap.test.tsx.snap @@ -212,7 +212,7 @@ exports[`Heatmap component Renders heatmap component 1`] = ` "editor": [Function], "id": "data-panel", "mapTo": "dataConfig", - "name": "Data", + "name": "Style", "sections": Array [ Object { "editor": [Function], diff --git a/dashboards-observability/public/components/visualizations/charts/__tests__/__snapshots__/histogram.test.tsx.snap b/dashboards-observability/public/components/visualizations/charts/__tests__/__snapshots__/histogram.test.tsx.snap index f33447ece..42bfba1f3 100644 --- a/dashboards-observability/public/components/visualizations/charts/__tests__/__snapshots__/histogram.test.tsx.snap +++ b/dashboards-observability/public/components/visualizations/charts/__tests__/__snapshots__/histogram.test.tsx.snap @@ -212,7 +212,7 @@ exports[`Histogram component Renders histogram component 1`] = ` "editor": [Function], "id": "data-panel", "mapTo": "dataConfig", - "name": "Data", + "name": "Style", "sections": Array [ Object { "editor": [Function], diff --git a/dashboards-observability/public/components/visualizations/charts/__tests__/__snapshots__/line.test.tsx.snap b/dashboards-observability/public/components/visualizations/charts/__tests__/__snapshots__/line.test.tsx.snap index 6a486d18d..c19e5d6e0 100644 --- a/dashboards-observability/public/components/visualizations/charts/__tests__/__snapshots__/line.test.tsx.snap +++ b/dashboards-observability/public/components/visualizations/charts/__tests__/__snapshots__/line.test.tsx.snap @@ -212,7 +212,7 @@ exports[`Line component Renders line component 1`] = ` "editor": [Function], "id": "data-panel", "mapTo": "dataConfig", - "name": "Data", + "name": "Style", "sections": Array [ Object { "editor": [Function], diff --git a/dashboards-observability/public/components/visualizations/charts/__tests__/__snapshots__/pie.test.tsx.snap b/dashboards-observability/public/components/visualizations/charts/__tests__/__snapshots__/pie.test.tsx.snap index 9e7b4976a..2f660be74 100644 --- a/dashboards-observability/public/components/visualizations/charts/__tests__/__snapshots__/pie.test.tsx.snap +++ b/dashboards-observability/public/components/visualizations/charts/__tests__/__snapshots__/pie.test.tsx.snap @@ -212,7 +212,7 @@ exports[`Pie component Renders pie component 1`] = ` "editor": [Function], "id": "data-panel", "mapTo": "dataConfig", - "name": "Data", + "name": "Style", "sections": Array [ Object { "editor": [Function], diff --git a/dashboards-observability/public/components/visualizations/charts/__tests__/__snapshots__/text.test.tsx.snap b/dashboards-observability/public/components/visualizations/charts/__tests__/__snapshots__/text.test.tsx.snap index 1438329ba..c5ac4eb66 100644 --- a/dashboards-observability/public/components/visualizations/charts/__tests__/__snapshots__/text.test.tsx.snap +++ b/dashboards-observability/public/components/visualizations/charts/__tests__/__snapshots__/text.test.tsx.snap @@ -195,7 +195,7 @@ exports[`Text component Renders text component 1`] = ` "editor": [Function], "id": "data-panel", "mapTo": "dataConfig", - "name": "Data", + "name": "Style", "sections": Array [ Object { "editor": [Function], diff --git a/dashboards-observability/public/components/visualizations/charts/__tests__/__snapshots__/treemap.test.tsx.snap b/dashboards-observability/public/components/visualizations/charts/__tests__/__snapshots__/treemap.test.tsx.snap index 183c9b4ad..e350516fc 100644 --- a/dashboards-observability/public/components/visualizations/charts/__tests__/__snapshots__/treemap.test.tsx.snap +++ b/dashboards-observability/public/components/visualizations/charts/__tests__/__snapshots__/treemap.test.tsx.snap @@ -212,7 +212,7 @@ exports[`Treemap component Renders treemap component 1`] = ` "editor": [Function], "id": "data-panel", "mapTo": "dataConfig", - "name": "Data", + "name": "Style", "sections": Array [ Object { "editor": [Function], diff --git a/dashboards-observability/public/components/visualizations/charts/bar/bar_type.ts b/dashboards-observability/public/components/visualizations/charts/bar/bar_type.ts index eef1db58c..922f3af31 100644 --- a/dashboards-observability/public/components/visualizations/charts/bar/bar_type.ts +++ b/dashboards-observability/public/components/visualizations/charts/bar/bar_type.ts @@ -48,7 +48,7 @@ export const createBarTypeDefinition = (params: any) => ({ panelTabs: [ { id: 'data-panel', - name: 'Data', + name: 'Style', mapTo: 'dataConfig', editor: VizDataPanel, sections: [ diff --git a/dashboards-observability/public/components/visualizations/charts/bar/horizontal_bar_type.ts b/dashboards-observability/public/components/visualizations/charts/bar/horizontal_bar_type.ts index cbc25a1dc..390a3e224 100644 --- a/dashboards-observability/public/components/visualizations/charts/bar/horizontal_bar_type.ts +++ b/dashboards-observability/public/components/visualizations/charts/bar/horizontal_bar_type.ts @@ -30,7 +30,7 @@ export const createHorizontalBarTypeDefinition = (params: BarTypeParams = {}) => panelTabs: [ { id: 'data-panel', - name: 'Data', + name: 'Style', mapTo: 'dataConfig', editor: VizDataPanel, sections: [ diff --git a/dashboards-observability/public/components/visualizations/charts/bubble/bubble_type.ts b/dashboards-observability/public/components/visualizations/charts/bubble/bubble_type.ts index 091298ce5..2fc6fcbbf 100644 --- a/dashboards-observability/public/components/visualizations/charts/bubble/bubble_type.ts +++ b/dashboards-observability/public/components/visualizations/charts/bubble/bubble_type.ts @@ -27,7 +27,7 @@ export const createBubbleVisDefinition = () => ({ panelTabs: [ { id: 'data-panel', - name: 'Data', + name: 'Style', mapTo: 'dataConfig', editor: VizDataPanel, sections: [ diff --git a/dashboards-observability/public/components/visualizations/charts/financial/gauge/gauge_type.ts b/dashboards-observability/public/components/visualizations/charts/financial/gauge/gauge_type.ts index 91d85dabb..6b4958744 100644 --- a/dashboards-observability/public/components/visualizations/charts/financial/gauge/gauge_type.ts +++ b/dashboards-observability/public/components/visualizations/charts/financial/gauge/gauge_type.ts @@ -36,7 +36,7 @@ export const createGaugeTypeDefinition = (params: any = {}) => ({ panelTabs: [ { id: 'data-panel', - name: 'Data', + name: 'Style', mapTo: 'dataConfig', editor: VizDataPanel, sections: [ diff --git a/dashboards-observability/public/components/visualizations/charts/histogram/histogram_type.ts b/dashboards-observability/public/components/visualizations/charts/histogram/histogram_type.ts index dccaf45d7..045f70618 100644 --- a/dashboards-observability/public/components/visualizations/charts/histogram/histogram_type.ts +++ b/dashboards-observability/public/components/visualizations/charts/histogram/histogram_type.ts @@ -36,7 +36,7 @@ export const createHistogramVisDefinition = (params = {}) => ({ panelTabs: [ { id: 'data-panel', - name: 'Data', + name: 'Style', mapTo: 'dataConfig', editor: VizDataPanel, sections: [ diff --git a/dashboards-observability/public/components/visualizations/charts/lines/line_type.ts b/dashboards-observability/public/components/visualizations/charts/lines/line_type.ts index ed8e1ed8d..e809b6b27 100644 --- a/dashboards-observability/public/components/visualizations/charts/lines/line_type.ts +++ b/dashboards-observability/public/components/visualizations/charts/lines/line_type.ts @@ -41,7 +41,7 @@ export const createLineTypeDefinition = (params: any = {}) => ({ panelTabs: [ { id: 'data-panel', - name: 'Data', + name: 'Style', mapTo: 'dataConfig', editor: VizDataPanel, sections: [ diff --git a/dashboards-observability/public/components/visualizations/charts/logs_view/logs_view.scss b/dashboards-observability/public/components/visualizations/charts/logs_view/logs_view.scss new file mode 100644 index 000000000..185d9ab98 --- /dev/null +++ b/dashboards-observability/public/components/visualizations/charts/logs_view/logs_view.scss @@ -0,0 +1,75 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +table { + border-collapse: collapse; + width: 100%; +} + +th, +td { + text-align: left; + padding: 8px; +} + +th { + width: 30%; +} + +tr:hover { + background-color: #ddd; +} + +.lvEuiAccordian_Panel { + border: 1px solid #D3DAE6 !important; +} + +.euiIEFlexWrapFix { + white-space: nowrap; + overflow: hidden; + margin-right: 10px; +} + +.rawlogData { + line-height: 1.5; + color: #343741; + word-break: break-all; + overflow: hidden; + margin-right: 5px; +} + +.euiAccordion__button { + font-size: inherit; +} + +.euiAccordion__iconWrapper { + align-self: flex-start; + padding-top: 9px; +} + +.euiAccordion__button:focus .euiAccordion__iconWrapper { + animation: none !important; +} + +.columnData { + padding-right: 10px; +} + +.timeColumn { + width: 200px; +} + +.wrapContent { + word-break: break-all; +} + +.noWrapContent { + white-space: nowrap; + overflow: hidden; +} + +.tableContainer { + white-space: normal; +} diff --git a/dashboards-observability/public/components/visualizations/charts/logs_view/logs_view.tsx b/dashboards-observability/public/components/visualizations/charts/logs_view/logs_view.tsx new file mode 100644 index 000000000..64dd9550f --- /dev/null +++ b/dashboards-observability/public/components/visualizations/charts/logs_view/logs_view.tsx @@ -0,0 +1,171 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ +import { EuiAccordion, EuiPanel, EuiSpacer, htmlIdGenerator } from '@elastic/eui'; +import React, { useContext } from 'react'; +import { TabContext } from '../../../event_analytics/hooks'; +import './logs_view.scss'; + +export const LogsView = ({ visualizations }: any) => { + const { explorerData } = useContext(TabContext); + const { dataConfig = {} } = visualizations?.data?.userConfigs; + const isTimeEnabled = + dataConfig?.chartStyles?.time !== undefined ? dataConfig?.chartStyles?.time : true; + const isWrapLinesEnabled = + dataConfig?.chartStyles?.view !== undefined && dataConfig?.chartStyles?.view === 'wrapLines'; + const isPrettifyJSONEnabled = + dataConfig?.chartStyles?.view !== undefined && dataConfig?.chartStyles?.view === 'prettifyJSON'; + const isLogDetailsEnabled = + dataConfig?.chartStyles?.enableLogDetails !== undefined + ? dataConfig?.chartStyles?.enableLogDetails + : true; + const labelSize = + dataConfig?.chartStyles?.labelSize !== undefined + ? dataConfig?.chartStyles?.labelSize + 'px' + : '14px'; + const rawData = explorerData.jsonData; + const { queriedFields = [], availableFields = [] } = visualizations?.data?.indexFields; + + const isTimestamp = (key: any) => { + if (queriedFields.length !== 0) { + for (const { name, type } of queriedFields) { + if (name === key && type === 'timestamp') return true; + } + } else { + for (const { name, type } of availableFields) { + if (name === key && type === 'timestamp') return true; + } + } + return false; + }; + + const fetchTimestamp = (obj: any) => { + for (const key of Object.keys(obj)) { + if (queriedFields.length !== 0) { + for (const { name, type } of queriedFields) { + if (name === key && type === 'timestamp') return key; + } + } + } + return null; + }; + + const logs = + rawData && + rawData.map((log, index) => { + let btnContent: JSX.Element; + if (isWrapLinesEnabled) { + const column1 = Object.keys(log).reduce((val, key) => { + if (isTimestamp(key)) return `${log[key]} `; + return val; + }, ''); + let column2 = ''; + for (const [key, val] of Object.entries(log)) { + if (!isTimestamp(key)) column2 += `${key}="${val}" `; + } + const jsxContent = column2 + .split(' ') + .map((ele) => {ele}); + btnContent = ( + + + {isTimeEnabled && column1 !== '' && ( + + )} + + +
+ {column1.indexOf('.') !== -1 + ? column1.substring(0, column1.indexOf('.')) + : column1} + {jsxContent}
+ ); + } else if (isPrettifyJSONEnabled) { + let columnContent; + let { timestamp } = log; + if (timestamp === undefined) timestamp = fetchTimestamp(log); + + let newLog: any = {}; + for (const key of Object.keys(log)) { + if (key !== timestamp) newLog[key] = log[key]; + } + + if (isTimeEnabled && timestamp !== null) { + columnContent = JSON.stringify({ timestamp: log[timestamp], ...newLog }, null, '\t'); + } else { + columnContent = JSON.stringify(newLog, null, '\t'); + } + + btnContent = ( + + + + +
+
{columnContent}
+
+ ); + } else { + let stringContent = ''; + if (isTimeEnabled) { + stringContent += Object.keys(log).reduce((val, key) => { + if (isTimestamp(key)) + return log[key].indexOf('.') !== -1 + ? log[key].substring(0, log[key].indexOf('.')) + ' ' + : log[key] + ' '; + return val; + }, ''); + } + for (const [key, val] of Object.entries(log)) { + if (isTimestamp(key)) continue; + stringContent += `${key}="${val}" `; + } + const jsxContent = stringContent + .split(' ') + .map((ele) => {ele}); + btnContent = ( + + + + +
{jsxContent}
+ ); + } + if (isLogDetailsEnabled) { + return ( + <> + + + + + + + {Object.entries(log).map(([key, value], index) => ( + + + + + ))} +
Detected fields
+

{key}

+
+

{value}

+
+
+
+ + + ); + } else { + return
{btnContent}
; + } + }); + + return
{logs}
; +}; diff --git a/dashboards-observability/public/components/visualizations/charts/logs_view/logs_view_type.ts b/dashboards-observability/public/components/visualizations/charts/logs_view/logs_view_type.ts new file mode 100644 index 000000000..6de9de0a7 --- /dev/null +++ b/dashboards-observability/public/components/visualizations/charts/logs_view/logs_view_type.ts @@ -0,0 +1,116 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { LogsView } from './logs_view'; +import { getPlotlyCategory, getPlotlySharedConfigs } from '../shared/shared_configs'; +import { LensIconChartDatatable } from '../../assets/chart_datatable'; +import { VizDataPanel } from '../../../event_analytics/explorer/visualizations/config_panel/config_panes/default_vis_editor'; +import { PLOTLY_COLOR } from '../../../../../common/constants/shared'; +import { ConfigLogsView } from '../../../event_analytics/explorer/visualizations/config_panel/config_panes/config_controls/config_logs_view'; +import { ButtonGroupItem } from '../../../event_analytics/explorer/visualizations/config_panel/config_panes/config_controls/config_button_group'; +import { ConfigSwitch } from '../../../event_analytics/explorer/visualizations/config_panel/config_panes/config_controls/config_switch'; +import { InputFieldItem } from '../../../event_analytics/explorer/visualizations/config_panel/config_panes/config_controls'; + +const sharedConfigs = getPlotlySharedConfigs(); +const VIS_CATEGORY = getPlotlyCategory(); + +export const createLogsViewTypeDefinition = (params: any = {}) => ({ + name: 'logs_view', + type: 'logs_view', + id: 'logs_view', + label: 'Logs View', + fullLabel: 'Logs View', + iconType: 'visTable', + category: VIS_CATEGORY.BASICS, + selection: { + dataLoss: 'nothing', + }, + icon: LensIconChartDatatable, + categoryAxis: 'xaxis', + seriesAxis: 'yaxis', + editorConfig: { + panelTabs: [ + { + id: 'data-panel', + name: 'Style', + mapTo: 'dataConfig', + editor: VizDataPanel, + sections: [ + { + id: 'chart_styles', + name: 'Chart styles', + editor: ConfigLogsView, + mapTo: 'chartStyles', + schemas: [ + { + name: 'Time', + component: ConfigSwitch, + mapTo: 'time', + defaultState: true, + eleType: 'switch', + }, + { + name: 'Log Details View', + component: ConfigSwitch, + mapTo: 'enableLogDetails', + defaultState: true, + eleType: 'switch', + }, + { + name: 'View', + mapTo: 'view', + component: ButtonGroupItem, + props: { + options: [ + { name: 'Default', id: 'default' }, + { name: 'Wrap lines', id: 'wrapLines' }, + { name: 'Prettify JSON', id: 'prettifyJSON' }, + ], + defaultSelections: [{ name: 'Default', id: 'default' }], + }, + eleType: 'buttons', + }, + { + name: 'Label Size', + component: InputFieldItem, + mapTo: 'labelSize', + eleType: 'input', + }, + ], + }, + ], + }, + ], + }, + visConfig: { + layout: { + ...sharedConfigs.layout, + colorway: PLOTLY_COLOR, + plot_bgcolor: 'rgba(0, 0, 0, 0)', + paper_bgcolor: 'rgba(0, 0, 0, 0)', + xaxis: { + fixedrange: true, + showgrid: false, + visible: true, + }, + yaxis: { + fixedrange: true, + showgrid: false, + visible: true, + }, + }, + config: { + ...sharedConfigs.config, + barmode: 'line', + xaxis: { + automargin: true, + }, + yaxis: { + automargin: true, + }, + }, + }, + component: LogsView, +}); diff --git a/dashboards-observability/public/components/visualizations/charts/maps/heatmap_type.ts b/dashboards-observability/public/components/visualizations/charts/maps/heatmap_type.ts index 8bcd56697..1c74aac7c 100644 --- a/dashboards-observability/public/components/visualizations/charts/maps/heatmap_type.ts +++ b/dashboards-observability/public/components/visualizations/charts/maps/heatmap_type.ts @@ -40,7 +40,7 @@ export const createMapsVisDefinition = () => ({ panelTabs: [ { id: 'data-panel', - name: 'Data', + name: 'Style', mapTo: 'dataConfig', editor: VizDataPanel, sections: [ diff --git a/dashboards-observability/public/components/visualizations/charts/maps/treemap_type.ts b/dashboards-observability/public/components/visualizations/charts/maps/treemap_type.ts index 57d14cc7b..8ad01df04 100644 --- a/dashboards-observability/public/components/visualizations/charts/maps/treemap_type.ts +++ b/dashboards-observability/public/components/visualizations/charts/maps/treemap_type.ts @@ -45,7 +45,7 @@ export const createTreeMapDefinition = (params: BarTypeParams = {}) => ({ panelTabs: [ { id: 'data-panel', - name: 'Data', + name: 'Style', mapTo: 'dataConfig', editor: VizDataPanel, sections: [ diff --git a/dashboards-observability/public/components/visualizations/charts/pie/pie_type.ts b/dashboards-observability/public/components/visualizations/charts/pie/pie_type.ts index 60a765cd8..a91a3191d 100644 --- a/dashboards-observability/public/components/visualizations/charts/pie/pie_type.ts +++ b/dashboards-observability/public/components/visualizations/charts/pie/pie_type.ts @@ -41,7 +41,7 @@ export const createPieTypeDefinition = (params: any) => ({ panelTabs: [ { id: 'data-panel', - name: 'Data', + name: 'Style', mapTo: 'dataConfig', editor: VizDataPanel, sections: [ diff --git a/dashboards-observability/public/components/visualizations/charts/text/text_type.ts b/dashboards-observability/public/components/visualizations/charts/text/text_type.ts index bc6b90ca9..9d75ba5e4 100644 --- a/dashboards-observability/public/components/visualizations/charts/text/text_type.ts +++ b/dashboards-observability/public/components/visualizations/charts/text/text_type.ts @@ -31,7 +31,7 @@ export const createTextTypeDefinition = (params: any = {}) => ({ panelTabs: [ { id: 'data-panel', - name: 'Data', + name: 'Style', mapTo: 'dataConfig', editor: VizDataPanel, sections: [ diff --git a/dashboards-observability/public/components/visualizations/charts/vis_types.ts b/dashboards-observability/public/components/visualizations/charts/vis_types.ts index 0d3998547..171119f7a 100644 --- a/dashboards-observability/public/components/visualizations/charts/vis_types.ts +++ b/dashboards-observability/public/components/visualizations/charts/vis_types.ts @@ -14,6 +14,7 @@ import { createDatatableTypeDefinition } from './data_table/data_table_type'; import { createGaugeTypeDefinition } from './financial/gauge/gauge_type'; import { createTreeMapDefinition } from './maps/treemap_type'; import { createTextTypeDefinition } from './text/text_type'; +import { createLogsViewTypeDefinition } from './logs_view/logs_view_type'; export const VIS_TYPES = { bar: createBarTypeDefinition, @@ -27,6 +28,7 @@ export const VIS_TYPES = { heatmap: createMapsVisDefinition, tree_map: createTreeMapDefinition, text: createTextTypeDefinition, + logs_view: createLogsViewTypeDefinition, }; export const getVisType = (visType: string, params: any = {}) => { diff --git a/dashboards-observability/public/components/visualizations/visualization.tsx b/dashboards-observability/public/components/visualizations/visualization.tsx index 329e6881b..099e2928d 100644 --- a/dashboards-observability/public/components/visualizations/visualization.tsx +++ b/dashboards-observability/public/components/visualizations/visualization.tsx @@ -7,8 +7,9 @@ import React from 'react'; import { isArray } from 'lodash'; import { VisualizationChart } from './visualization_chart'; import { EmptyPlaceholder } from '../event_analytics/explorer/visualizations/shared_components/empty_placeholder'; +import { visChartTypes } from '../../../common/constants/shared'; -interface IVisualizationProps {} +interface IVisualizationProps { } export const Visualization = ({ visualizations }: IVisualizationProps) => { const { data, vis } = visualizations; @@ -23,7 +24,7 @@ export const Visualization = ({ visualizations }: IVisualizationProps) => { return ( <> - {isVizDataValid && isVizFieldValid ? ( + {vis?.type === visChartTypes.LogsView || isVizDataValid && isVizFieldValid ? ( ) : ( diff --git a/dashboards-observability/public/components/visualizations/visualization_chart.tsx b/dashboards-observability/public/components/visualizations/visualization_chart.tsx index 88bb34edd..4365bee32 100644 --- a/dashboards-observability/public/components/visualizations/visualization_chart.tsx +++ b/dashboards-observability/public/components/visualizations/visualization_chart.tsx @@ -4,15 +4,11 @@ */ import React, { useMemo } from 'react'; -import { take, merge, isEmpty } from 'lodash'; interface IVisualizationChart {} export const VisualizationChart = ({ visualizations }: IVisualizationChart) => { - const { data, vis } = visualizations; - const { - metadata: { fields }, - } = visualizations?.data?.rawVizData; + const { vis } = visualizations; const { layout = {}, config = {} } = visualizations?.data?.userConfigs; const Visualization = visualizations?.vis?.component;