+
>
diff --git a/dashboards-observability/public/components/event_analytics/explorer/visualizations/shared_components/__tests__/__snapshots__/shared_components.test.tsx.snap b/dashboards-observability/public/components/event_analytics/explorer/visualizations/shared_components/__tests__/__snapshots__/shared_components.test.tsx.snap
index 8ed6302b0..8511fbe6f 100644
--- a/dashboards-observability/public/components/event_analytics/explorer/visualizations/shared_components/__tests__/__snapshots__/shared_components.test.tsx.snap
+++ b/dashboards-observability/public/components/event_analytics/explorer/visualizations/shared_components/__tests__/__snapshots__/shared_components.test.tsx.snap
@@ -30,19 +30,19 @@ exports[`Shared components Renders empty placeholder component 1`] = `
>
diff --git a/dashboards-observability/public/components/event_analytics/explorer/visualizations/shared_components/empty_placeholder.scss b/dashboards-observability/public/components/event_analytics/explorer/visualizations/shared_components/empty_placeholder.scss
new file mode 100644
index 000000000..00045e476
--- /dev/null
+++ b/dashboards-observability/public/components/event_analytics/explorer/visualizations/shared_components/empty_placeholder.scss
@@ -0,0 +1,12 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+ .lnsChart__empty {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ height: 1180px;
+ font-size: 20px;
+}
diff --git a/dashboards-observability/public/components/event_analytics/explorer/visualizations/shared_components/empty_placeholder.tsx b/dashboards-observability/public/components/event_analytics/explorer/visualizations/shared_components/empty_placeholder.tsx
index 40d449ea7..bbfed2bb0 100644
--- a/dashboards-observability/public/components/event_analytics/explorer/visualizations/shared_components/empty_placeholder.tsx
+++ b/dashboards-observability/public/components/event_analytics/explorer/visualizations/shared_components/empty_placeholder.tsx
@@ -4,14 +4,15 @@
*/
import React from 'react';
-import { EuiIcon, EuiText, IconType, EuiSpacer } from '@elastic/eui';
+import { EuiIcon, EuiText, EuiSpacer } from '@elastic/eui';
import { FormattedMessage } from '@osd/i18n/react';
+import './empty_placeholder.scss';
export const EmptyPlaceholder = (props: {icon: string}) => (
<>
-
-
+
+
{
- return ;
+ return (
+
+ );
}, [visualizations]);
return (
@@ -64,11 +66,13 @@ export function WorkspacePanel({ visualizations }: IWorkSpacePanel) {
-
- {isTableViewOn ?
- : VisualizationPanel}
+
+ {isTableViewOn ? : VisualizationPanel}
diff --git a/dashboards-observability/public/components/event_analytics/home/home.tsx b/dashboards-observability/public/components/event_analytics/home/home.tsx
index f25aa4c32..ecd6f79c3 100644
--- a/dashboards-observability/public/components/event_analytics/home/home.tsx
+++ b/dashboards-observability/public/components/event_analytics/home/home.tsx
@@ -30,6 +30,7 @@ import {
EuiText,
EuiHorizontalRule,
} from '@elastic/eui';
+import { DeleteModal } from '../../common/helpers/delete_modal';
import { Search } from '../../common/search/search';
import {
RAW_QUERY,
@@ -55,7 +56,6 @@ import { init as initQueryResult, selectQueryResult } from '../redux/slices/quer
import { SavedQueryTable } from './saved_objects_table';
import { selectQueries } from '../redux/slices/query_slice';
import { setSelectedQueryTab } from '../redux/slices/query_tab_slice';
-import { DeletePanelModal } from '../../custom_panels/helpers/modal_containers';
import { CUSTOM_PANELS_API_PREFIX } from '../../../../common/constants/custom_panels';
import { getSampleDataModal } from '../../common/helpers/add_sample_modal';
import { parseGetSuggestions, onItemSelect } from '../../common/search/autocomplete_logic';
@@ -299,7 +299,7 @@ export const Home = (props: IHomeProps) => {
const deleteHistory = () => {
const customPanelString = `${selectedHistories.length > 1 ? 'histories' : 'history'}`;
setModalLayout(
- void
+ successHandler: (res: any) => void,
+ errorHandler: (error: any) => void
) => {
setIsVisLoading(true);
@@ -45,16 +46,16 @@ export const useFetchVisualizations = ({
.fetch({
query,
format,
+ }, (error) => {
+ errorHandler(error);
+ setIsVisLoading(false);
})
.then((res: any) => {
- handler(res);
- })
- .catch((err: any) => {
- console.error(err);
- })
- .finally(() => {
+ if (res && res.status === 200) {
+ successHandler(res);
+ }
setIsVisLoading(false);
- });
+ })
};
const getCountVisualizations = (interval: string) => {
@@ -74,7 +75,8 @@ export const useFetchVisualizations = ({
data: res,
})
);
- }
+ },
+ (error: Error) => {}
);
};
@@ -118,6 +120,14 @@ export const useFetchVisualizations = ({
})
);
});
+ },
+ (error: any) => {
+ dispatch(
+ renderExplorerVis({
+ tabId: requestParams.tabId,
+ data: error.body,
+ })
+ );
}
);
};
diff --git a/dashboards-observability/public/components/event_analytics/utils/utils.tsx b/dashboards-observability/public/components/event_analytics/utils/utils.tsx
index d142f472f..dafc1e2f2 100644
--- a/dashboards-observability/public/components/event_analytics/utils/utils.tsx
+++ b/dashboards-observability/public/components/event_analytics/utils/utils.tsx
@@ -1,3 +1,4 @@
+/* eslint-disable no-bitwise */
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
@@ -13,6 +14,7 @@ import { HttpStart } from '../../../../../../src/core/public';
import PPLService from '../../../services/requests/ppl';
import { TIME_INTERVAL_OPTIONS } from '../../../../common/constants/explorer';
import { PPL_DATE_FORMAT, PPL_INDEX_REGEX } from '../../../../common/constants/shared';
+import { ConfigTooltip } from '../explorer/visualizations/config_panel/config_panes/config_controls';
// Create Individual table rows for events datagrid and flyouts
export const getTrs = (
@@ -119,8 +121,8 @@ export const populateDataGrid = (
)}
{explorerFields?.queriedFields &&
- explorerFields?.queriedFields?.length > 0 &&
- explorerFields.selectedFields?.length === 0 ? null : (
+ explorerFields?.queriedFields?.length > 0 &&
+ explorerFields.selectedFields?.length === 0 ? null : (
{header2}
{body2}
@@ -285,3 +287,70 @@ export const findAutoInterval = (start: string = '', end: string = '') => {
return [minInterval, [{ text: 'Auto', value: 'auto_' + minInterval }, ...TIME_INTERVAL_OPTIONS]];
};
+
+export const hexToRgb = (
+ hex: string = '#3CA1C7',
+ opacity: number = 1,
+ colorWithOpacity: boolean = true
+) => {
+ // default color PLOTLY_COLOR[0]: '#3CA1C7'
+ const defaultColor = [hex, '60', '161', '199'];
+ const rgbElements = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex) || defaultColor;
+ const [, r, g, b] = rgbElements.map((color) => parseInt(color, 16));
+ const rgbaFormat = colorWithOpacity ? `rgba(${r},${g},${b},${opacity})` : `rgb(${r},${g},${b})`;
+ return rgbaFormat;
+};
+
+export const lightenColor = (color: string, percent: number) => {
+ const num = parseInt(color.replace('#', ''), 16);
+ const amt = Math.round(2.55 * percent);
+ const R = (num >> 16) + amt;
+ const B = ((num >> 8) & 0x00ff) + amt;
+ const G = (num & 0x0000ff) + amt;
+ return (
+ '#' +
+ (
+ 0x1000000 +
+ (R < 255 ? (R < 1 ? 0 : R) : 255) * 0x10000 +
+ (B < 255 ? (B < 1 ? 0 : B) : 255) * 0x100 +
+ (G < 255 ? (G < 1 ? 0 : G) : 255)
+ )
+ .toString(16)
+ .slice(1)
+ );
+};
+
+// Get config objects according to specific editor
+export const fetchConfigObject = (editor: string, propsOptions: any) => {
+ switch (editor) {
+ case 'Tooltip':
+ return {
+ id: 'tooltip_options',
+ name: 'Tooltip options',
+ editor: ConfigTooltip,
+ mapTo: 'tooltipOptions',
+ schemas: [
+ {
+ name: 'Tooltip mode',
+ component: null,
+ mapTo: 'tooltipMode',
+ props: {
+ options: [
+ { name: 'Show', id: 'show' },
+ { name: 'Hidden', id: 'hidden' },
+ ],
+ defaultSelections: [{ name: 'Show', id: 'show' }],
+ },
+ },
+ {
+ name: 'Tooltip text',
+ component: null,
+ mapTo: 'tooltipText',
+ props: propsOptions,
+ },
+ ],
+ };
+ default:
+ return null;
+ }
+};
diff --git a/dashboards-observability/public/components/trace_analytics/components/traces/__tests__/__snapshots__/span_detail_flyout.test.tsx.snap b/dashboards-observability/public/components/trace_analytics/components/traces/__tests__/__snapshots__/span_detail_flyout.test.tsx.snap
index e3c372ee1..cb4564c2e 100644
--- a/dashboards-observability/public/components/trace_analytics/components/traces/__tests__/__snapshots__/span_detail_flyout.test.tsx.snap
+++ b/dashboards-observability/public/components/trace_analytics/components/traces/__tests__/__snapshots__/span_detail_flyout.test.tsx.snap
@@ -15,7 +15,7 @@ exports[` spec renders the empty component 1`] = `
onClose={[MockFunction]}
size="s"
>
-
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 9a1ab2672..9a88fe43b 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
@@ -202,93 +202,275 @@ exports[`Bar component Renders bar component 1`] = `
"userConfigs": Object {},
},
"vis": Object {
+ "barwidth": 0.97,
"category": "Visualizations",
- "categoryAxis": "xaxis",
+ "categoryaxis": "xaxis",
"component": [Function],
- "editorConfig": Object {
+ "editorconfig": Object {
"panelTabs": Array [
Object {
"editor": [Function],
"id": "data-panel",
"mapTo": "dataConfig",
- "name": "Data",
+ "name": "Style",
"sections": Array [
Object {
"editor": [Function],
- "id": "value_options",
- "mapTo": "valueOptions",
- "name": "Value options",
+ "id": "tooltip_options",
+ "mapTo": "tooltipOptions",
+ "name": "Tooltip options",
"schemas": Array [
Object {
"component": null,
- "isSingleSelection": false,
- "mapTo": "xaxis",
- "name": "X-axis",
+ "mapTo": "tooltipMode",
+ "name": "Tooltip mode",
+ "props": Object {
+ "defaultSelections": Array [
+ Object {
+ "id": "show",
+ "name": "Show",
+ },
+ ],
+ "options": Array [
+ Object {
+ "id": "show",
+ "name": "Show",
+ },
+ Object {
+ "id": "hidden",
+ "name": "Hidden",
+ },
+ ],
+ },
},
Object {
"component": null,
- "isSingleSelection": false,
- "mapTo": "yaxis",
- "name": "Y-axis",
+ "mapTo": "tooltipText",
+ "name": "Tooltip text",
+ "props": Object {
+ "defaultSelections": Array [
+ Object {
+ "id": "all",
+ "name": "All",
+ },
+ ],
+ "options": Array [
+ Object {
+ "id": "all",
+ "name": "All",
+ },
+ Object {
+ "id": "x",
+ "name": "Dimension",
+ },
+ Object {
+ "id": "y",
+ "name": "Metrics",
+ },
+ ],
+ },
},
],
},
Object {
"editor": [Function],
- "id": "chart_options",
- "mapTo": "chartOptions",
- "name": "Chart options",
+ "id": "legend",
+ "mapTo": "legend",
+ "name": "Legend",
"schemas": Array [
Object {
"component": null,
- "isSingleSelection": true,
+ "mapTo": "showLegend",
+ "name": "Show legend",
+ "props": Object {
+ "defaultSelections": Array [
+ Object {
+ "id": "show",
+ "name": "Show",
+ },
+ ],
+ "options": Array [
+ Object {
+ "id": "show",
+ "name": "Show",
+ },
+ Object {
+ "id": "hidden",
+ "name": "Hidden",
+ },
+ ],
+ },
+ },
+ Object {
+ "component": null,
+ "mapTo": "position",
+ "name": "Position",
+ "props": Object {
+ "defaultSelections": Array [
+ Object {
+ "id": "v",
+ "name": "Right",
+ },
+ ],
+ "options": Array [
+ Object {
+ "id": "v",
+ "name": "Right",
+ },
+ Object {
+ "id": "h",
+ "name": "Bottom",
+ },
+ ],
+ },
+ },
+ ],
+ },
+ Object {
+ "editor": [Function],
+ "id": "chart_styles",
+ "mapTo": "chartStyles",
+ "name": "Chart styles",
+ "schemas": Array [
+ Object {
+ "component": [Function],
+ "eleType": "buttons",
"mapTo": "orientation",
"name": "Orientation",
"props": Object {
"defaultSelections": Array [
Object {
+ "id": "v",
"name": "Vertical",
- "orientationId": "v",
},
],
- "dropdownList": Array [
+ "options": Array [
Object {
+ "id": "v",
"name": "Vertical",
- "orientationId": "v",
},
Object {
+ "id": "h",
"name": "Horizontal",
- "orientationId": "h",
},
],
},
},
Object {
- "component": null,
- "isSingleSelection": true,
+ "component": [Function],
+ "eleType": "buttons",
"mapTo": "mode",
"name": "Mode",
"props": Object {
"defaultSelections": Array [
Object {
- "modeId": "group",
+ "id": "group",
"name": "Group",
},
],
- "dropdownList": Array [
+ "options": Array [
Object {
- "modeId": "group",
+ "id": "group",
"name": "Group",
},
Object {
- "modeId": "stack",
+ "id": "stack",
"name": "Stack",
},
],
},
},
+ Object {
+ "component": [Function],
+ "eleType": "input",
+ "mapTo": "labelSize",
+ "name": "Label size",
+ },
+ Object {
+ "component": [Function],
+ "defaultState": 0,
+ "eleType": "slider",
+ "mapTo": "rotateBarLabels",
+ "name": "Rotate bar labels",
+ "props": Object {
+ "max": 90,
+ "min": -90,
+ "showTicks": true,
+ "ticks": Array [
+ Object {
+ "label": "-90°",
+ "value": -90,
+ },
+ Object {
+ "label": "-45°",
+ "value": -45,
+ },
+ Object {
+ "label": "0°",
+ "value": 0,
+ },
+ Object {
+ "label": "45°",
+ "value": 45,
+ },
+ Object {
+ "label": "90°",
+ "value": 90,
+ },
+ ],
+ },
+ },
+ Object {
+ "component": [Function],
+ "defaultState": 0.7,
+ "eleType": "slider",
+ "mapTo": "groupWidth",
+ "name": "Group width",
+ "props": Object {
+ "max": 1,
+ "step": 0.01,
+ },
+ },
+ Object {
+ "component": [Function],
+ "defaultState": 0.97,
+ "eleType": "slider",
+ "mapTo": "barWidth",
+ "name": "Bar width",
+ "props": Object {
+ "max": 1,
+ "step": 0.01,
+ },
+ },
+ Object {
+ "component": [Function],
+ "defaultState": 1,
+ "eleType": "slider",
+ "mapTo": "lineWidth",
+ "name": "Line width",
+ "props": Object {
+ "max": 10,
+ },
+ },
+ Object {
+ "component": [Function],
+ "defaultState": 80,
+ "eleType": "slider",
+ "mapTo": "fillOpacity",
+ "name": "Fill opacity",
+ "props": Object {
+ "max": 100,
+ },
+ },
],
},
+ Object {
+ "editor": [Function],
+ "id": "color-theme",
+ "mapTo": "colorTheme",
+ "name": "Color theme",
+ "schemas": Array [],
+ },
],
},
Object {
@@ -306,26 +488,33 @@ exports[`Bar component Renders bar component 1`] = `
},
],
},
- "fullLabel": "Bar",
+ "fillOpacity": 80,
+ "fulllabel": "Vertical bar",
+ "groupwidth": 0.7,
"icon": [Function],
- "iconType": "visBarVerticalStacked",
+ "icontype": "visBarVerticalStacked",
"id": "bar",
- "label": "Bar",
+ "label": "Vertical bar",
+ "labelangle": 0,
+ "legendposition": "v",
+ "linewidth": 1,
+ "mode": "group",
"name": "bar",
"orientation": "v",
"selection": Object {
"dataLoss": "nothing",
},
- "seriesAxis": "yaxis",
+ "seriesaxis": "yaxis",
+ "showlegend": "show",
"type": "bar",
- "visConfig": Object {
+ "visconfig": Object {
"config": Object {
"displaylogo": false,
"responsive": true,
},
"isUniColor": false,
"layout": Object {
- "height": 500,
+ "height": 1180,
"legend": Object {
"orientation": "v",
"traceorder": "normal",
@@ -344,158 +533,79 @@ exports[`Bar component Renders bar component 1`] = `
}
}
>
-
-
+
-
-
+ className="euiText euiText--extraSmall lnsChart__empty"
+ data-test-subj="vizWorkspace__noData"
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ No results found
+
+
+
+
+
+
+
+
+
+
`;
diff --git a/dashboards-observability/public/components/visualizations/charts/__tests__/__snapshots__/data_table.test.tsx.snap b/dashboards-observability/public/components/visualizations/charts/__tests__/__snapshots__/data_table.test.tsx.snap
index f6f8243c1..d9be0e68b 100644
--- a/dashboards-observability/public/components/visualizations/charts/__tests__/__snapshots__/data_table.test.tsx.snap
+++ b/dashboards-observability/public/components/visualizations/charts/__tests__/__snapshots__/data_table.test.tsx.snap
@@ -1,504 +1,127 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Data table component Renders data table component 1`] = `
-
+
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ rowHeight={35}
+ suppressPaginationPanel={true}
+ />
+
+
`;
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 56fc05d26..881df5490 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
@@ -202,93 +202,275 @@ exports[`Heatmap component Renders heatmap component 1`] = `
"userConfigs": Object {},
},
"vis": Object {
+ "barwidth": 0.97,
"category": "Visualizations",
- "categoryAxis": "xaxis",
+ "categoryaxis": "xaxis",
"component": [Function],
- "editorConfig": Object {
+ "editorconfig": Object {
"panelTabs": Array [
Object {
"editor": [Function],
"id": "data-panel",
"mapTo": "dataConfig",
- "name": "Data",
+ "name": "Style",
"sections": Array [
Object {
"editor": [Function],
- "id": "value_options",
- "mapTo": "valueOptions",
- "name": "Value options",
+ "id": "tooltip_options",
+ "mapTo": "tooltipOptions",
+ "name": "Tooltip options",
"schemas": Array [
Object {
"component": null,
- "isSingleSelection": false,
- "mapTo": "xaxis",
- "name": "X-axis",
+ "mapTo": "tooltipMode",
+ "name": "Tooltip mode",
+ "props": Object {
+ "defaultSelections": Array [
+ Object {
+ "id": "show",
+ "name": "Show",
+ },
+ ],
+ "options": Array [
+ Object {
+ "id": "show",
+ "name": "Show",
+ },
+ Object {
+ "id": "hidden",
+ "name": "Hidden",
+ },
+ ],
+ },
},
Object {
"component": null,
- "isSingleSelection": false,
- "mapTo": "yaxis",
- "name": "Y-axis",
+ "mapTo": "tooltipText",
+ "name": "Tooltip text",
+ "props": Object {
+ "defaultSelections": Array [
+ Object {
+ "id": "all",
+ "name": "All",
+ },
+ ],
+ "options": Array [
+ Object {
+ "id": "all",
+ "name": "All",
+ },
+ Object {
+ "id": "x",
+ "name": "Dimension",
+ },
+ Object {
+ "id": "y",
+ "name": "Metrics",
+ },
+ ],
+ },
},
],
},
Object {
"editor": [Function],
- "id": "chart_options",
- "mapTo": "chartOptions",
- "name": "Chart options",
+ "id": "legend",
+ "mapTo": "legend",
+ "name": "Legend",
"schemas": Array [
Object {
"component": null,
- "isSingleSelection": true,
+ "mapTo": "showLegend",
+ "name": "Show legend",
+ "props": Object {
+ "defaultSelections": Array [
+ Object {
+ "id": "show",
+ "name": "Show",
+ },
+ ],
+ "options": Array [
+ Object {
+ "id": "show",
+ "name": "Show",
+ },
+ Object {
+ "id": "hidden",
+ "name": "Hidden",
+ },
+ ],
+ },
+ },
+ Object {
+ "component": null,
+ "mapTo": "position",
+ "name": "Position",
+ "props": Object {
+ "defaultSelections": Array [
+ Object {
+ "id": "v",
+ "name": "Right",
+ },
+ ],
+ "options": Array [
+ Object {
+ "id": "v",
+ "name": "Right",
+ },
+ Object {
+ "id": "h",
+ "name": "Bottom",
+ },
+ ],
+ },
+ },
+ ],
+ },
+ Object {
+ "editor": [Function],
+ "id": "chart_styles",
+ "mapTo": "chartStyles",
+ "name": "Chart styles",
+ "schemas": Array [
+ Object {
+ "component": [Function],
+ "eleType": "buttons",
"mapTo": "orientation",
"name": "Orientation",
"props": Object {
"defaultSelections": Array [
Object {
+ "id": "v",
"name": "Vertical",
- "orientationId": "v",
},
],
- "dropdownList": Array [
+ "options": Array [
Object {
+ "id": "v",
"name": "Vertical",
- "orientationId": "v",
},
Object {
+ "id": "h",
"name": "Horizontal",
- "orientationId": "h",
},
],
},
},
Object {
- "component": null,
- "isSingleSelection": true,
+ "component": [Function],
+ "eleType": "buttons",
"mapTo": "mode",
"name": "Mode",
"props": Object {
"defaultSelections": Array [
Object {
- "modeId": "group",
+ "id": "group",
"name": "Group",
},
],
- "dropdownList": Array [
+ "options": Array [
Object {
- "modeId": "group",
+ "id": "group",
"name": "Group",
},
Object {
- "modeId": "stack",
+ "id": "stack",
"name": "Stack",
},
],
},
},
+ Object {
+ "component": [Function],
+ "eleType": "input",
+ "mapTo": "labelSize",
+ "name": "Label size",
+ },
+ Object {
+ "component": [Function],
+ "defaultState": 0,
+ "eleType": "slider",
+ "mapTo": "rotateBarLabels",
+ "name": "Rotate bar labels",
+ "props": Object {
+ "max": 90,
+ "min": -90,
+ "showTicks": true,
+ "ticks": Array [
+ Object {
+ "label": "-90°",
+ "value": -90,
+ },
+ Object {
+ "label": "-45°",
+ "value": -45,
+ },
+ Object {
+ "label": "0°",
+ "value": 0,
+ },
+ Object {
+ "label": "45°",
+ "value": 45,
+ },
+ Object {
+ "label": "90°",
+ "value": 90,
+ },
+ ],
+ },
+ },
+ Object {
+ "component": [Function],
+ "defaultState": 0.7,
+ "eleType": "slider",
+ "mapTo": "groupWidth",
+ "name": "Group width",
+ "props": Object {
+ "max": 1,
+ "step": 0.01,
+ },
+ },
+ Object {
+ "component": [Function],
+ "defaultState": 0.97,
+ "eleType": "slider",
+ "mapTo": "barWidth",
+ "name": "Bar width",
+ "props": Object {
+ "max": 1,
+ "step": 0.01,
+ },
+ },
+ Object {
+ "component": [Function],
+ "defaultState": 1,
+ "eleType": "slider",
+ "mapTo": "lineWidth",
+ "name": "Line width",
+ "props": Object {
+ "max": 10,
+ },
+ },
+ Object {
+ "component": [Function],
+ "defaultState": 80,
+ "eleType": "slider",
+ "mapTo": "fillOpacity",
+ "name": "Fill opacity",
+ "props": Object {
+ "max": 100,
+ },
+ },
],
},
+ Object {
+ "editor": [Function],
+ "id": "color-theme",
+ "mapTo": "colorTheme",
+ "name": "Color theme",
+ "schemas": Array [],
+ },
],
},
Object {
@@ -306,26 +488,33 @@ exports[`Heatmap component Renders heatmap component 1`] = `
},
],
},
- "fullLabel": "Bar",
+ "fillOpacity": 80,
+ "fulllabel": "Vertical bar",
+ "groupwidth": 0.7,
"icon": [Function],
- "iconType": "visBarVerticalStacked",
+ "icontype": "visBarVerticalStacked",
"id": "bar",
- "label": "Bar",
+ "label": "Vertical bar",
+ "labelangle": 0,
+ "legendposition": "v",
+ "linewidth": 1,
+ "mode": "group",
"name": "bar",
"orientation": "v",
"selection": Object {
"dataLoss": "nothing",
},
- "seriesAxis": "yaxis",
+ "seriesaxis": "yaxis",
+ "showlegend": "show",
"type": "bar",
- "visConfig": Object {
+ "visconfig": Object {
"config": Object {
"displaylogo": false,
"responsive": true,
},
"isUniColor": false,
"layout": Object {
- "height": 500,
+ "height": 1180,
"legend": Object {
"orientation": "v",
"traceorder": "normal",
@@ -373,19 +562,19 @@ exports[`Heatmap component Renders heatmap component 1`] = `
>
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
new file mode 100644
index 000000000..16f79ad74
--- /dev/null
+++ b/dashboards-observability/public/components/visualizations/charts/__tests__/__snapshots__/histogram.test.tsx.snap
@@ -0,0 +1,672 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Histogram component Renders histogram component 1`] = `
+
+
+
+
+
+
+
+`;
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 d767d0c93..15f4453bf 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
@@ -202,93 +202,275 @@ exports[`Line component Renders line component 1`] = `
"userConfigs": Object {},
},
"vis": Object {
+ "barwidth": 0.97,
"category": "Visualizations",
- "categoryAxis": "xaxis",
+ "categoryaxis": "xaxis",
"component": [Function],
- "editorConfig": Object {
+ "editorconfig": Object {
"panelTabs": Array [
Object {
"editor": [Function],
"id": "data-panel",
"mapTo": "dataConfig",
- "name": "Data",
+ "name": "Style",
"sections": Array [
Object {
"editor": [Function],
- "id": "value_options",
- "mapTo": "valueOptions",
- "name": "Value options",
+ "id": "tooltip_options",
+ "mapTo": "tooltipOptions",
+ "name": "Tooltip options",
"schemas": Array [
Object {
"component": null,
- "isSingleSelection": false,
- "mapTo": "xaxis",
- "name": "X-axis",
+ "mapTo": "tooltipMode",
+ "name": "Tooltip mode",
+ "props": Object {
+ "defaultSelections": Array [
+ Object {
+ "id": "show",
+ "name": "Show",
+ },
+ ],
+ "options": Array [
+ Object {
+ "id": "show",
+ "name": "Show",
+ },
+ Object {
+ "id": "hidden",
+ "name": "Hidden",
+ },
+ ],
+ },
},
Object {
"component": null,
- "isSingleSelection": false,
- "mapTo": "yaxis",
- "name": "Y-axis",
+ "mapTo": "tooltipText",
+ "name": "Tooltip text",
+ "props": Object {
+ "defaultSelections": Array [
+ Object {
+ "id": "all",
+ "name": "All",
+ },
+ ],
+ "options": Array [
+ Object {
+ "id": "all",
+ "name": "All",
+ },
+ Object {
+ "id": "x",
+ "name": "Dimension",
+ },
+ Object {
+ "id": "y",
+ "name": "Metrics",
+ },
+ ],
+ },
},
],
},
Object {
"editor": [Function],
- "id": "chart_options",
- "mapTo": "chartOptions",
- "name": "Chart options",
+ "id": "legend",
+ "mapTo": "legend",
+ "name": "Legend",
"schemas": Array [
Object {
"component": null,
- "isSingleSelection": true,
+ "mapTo": "showLegend",
+ "name": "Show legend",
+ "props": Object {
+ "defaultSelections": Array [
+ Object {
+ "id": "show",
+ "name": "Show",
+ },
+ ],
+ "options": Array [
+ Object {
+ "id": "show",
+ "name": "Show",
+ },
+ Object {
+ "id": "hidden",
+ "name": "Hidden",
+ },
+ ],
+ },
+ },
+ Object {
+ "component": null,
+ "mapTo": "position",
+ "name": "Position",
+ "props": Object {
+ "defaultSelections": Array [
+ Object {
+ "id": "v",
+ "name": "Right",
+ },
+ ],
+ "options": Array [
+ Object {
+ "id": "v",
+ "name": "Right",
+ },
+ Object {
+ "id": "h",
+ "name": "Bottom",
+ },
+ ],
+ },
+ },
+ ],
+ },
+ Object {
+ "editor": [Function],
+ "id": "chart_styles",
+ "mapTo": "chartStyles",
+ "name": "Chart styles",
+ "schemas": Array [
+ Object {
+ "component": [Function],
+ "eleType": "buttons",
"mapTo": "orientation",
"name": "Orientation",
"props": Object {
"defaultSelections": Array [
Object {
+ "id": "v",
"name": "Vertical",
- "orientationId": "v",
},
],
- "dropdownList": Array [
+ "options": Array [
Object {
+ "id": "v",
"name": "Vertical",
- "orientationId": "v",
},
Object {
+ "id": "h",
"name": "Horizontal",
- "orientationId": "h",
},
],
},
},
Object {
- "component": null,
- "isSingleSelection": true,
+ "component": [Function],
+ "eleType": "buttons",
"mapTo": "mode",
"name": "Mode",
"props": Object {
"defaultSelections": Array [
Object {
- "modeId": "group",
+ "id": "group",
"name": "Group",
},
],
- "dropdownList": Array [
+ "options": Array [
Object {
- "modeId": "group",
+ "id": "group",
"name": "Group",
},
Object {
- "modeId": "stack",
+ "id": "stack",
"name": "Stack",
},
],
},
},
+ Object {
+ "component": [Function],
+ "eleType": "input",
+ "mapTo": "labelSize",
+ "name": "Label size",
+ },
+ Object {
+ "component": [Function],
+ "defaultState": 0,
+ "eleType": "slider",
+ "mapTo": "rotateBarLabels",
+ "name": "Rotate bar labels",
+ "props": Object {
+ "max": 90,
+ "min": -90,
+ "showTicks": true,
+ "ticks": Array [
+ Object {
+ "label": "-90°",
+ "value": -90,
+ },
+ Object {
+ "label": "-45°",
+ "value": -45,
+ },
+ Object {
+ "label": "0°",
+ "value": 0,
+ },
+ Object {
+ "label": "45°",
+ "value": 45,
+ },
+ Object {
+ "label": "90°",
+ "value": 90,
+ },
+ ],
+ },
+ },
+ Object {
+ "component": [Function],
+ "defaultState": 0.7,
+ "eleType": "slider",
+ "mapTo": "groupWidth",
+ "name": "Group width",
+ "props": Object {
+ "max": 1,
+ "step": 0.01,
+ },
+ },
+ Object {
+ "component": [Function],
+ "defaultState": 0.97,
+ "eleType": "slider",
+ "mapTo": "barWidth",
+ "name": "Bar width",
+ "props": Object {
+ "max": 1,
+ "step": 0.01,
+ },
+ },
+ Object {
+ "component": [Function],
+ "defaultState": 1,
+ "eleType": "slider",
+ "mapTo": "lineWidth",
+ "name": "Line width",
+ "props": Object {
+ "max": 10,
+ },
+ },
+ Object {
+ "component": [Function],
+ "defaultState": 80,
+ "eleType": "slider",
+ "mapTo": "fillOpacity",
+ "name": "Fill opacity",
+ "props": Object {
+ "max": 100,
+ },
+ },
],
},
+ Object {
+ "editor": [Function],
+ "id": "color-theme",
+ "mapTo": "colorTheme",
+ "name": "Color theme",
+ "schemas": Array [],
+ },
],
},
Object {
@@ -306,26 +488,33 @@ exports[`Line component Renders line component 1`] = `
},
],
},
- "fullLabel": "Bar",
+ "fillOpacity": 80,
+ "fulllabel": "Vertical bar",
+ "groupwidth": 0.7,
"icon": [Function],
- "iconType": "visBarVerticalStacked",
+ "icontype": "visBarVerticalStacked",
"id": "bar",
- "label": "Bar",
+ "label": "Vertical bar",
+ "labelangle": 0,
+ "legendposition": "v",
+ "linewidth": 1,
+ "mode": "group",
"name": "bar",
"orientation": "v",
"selection": Object {
"dataLoss": "nothing",
},
- "seriesAxis": "yaxis",
+ "seriesaxis": "yaxis",
+ "showlegend": "show",
"type": "bar",
- "visConfig": Object {
+ "visconfig": Object {
"config": Object {
"displaylogo": false,
"responsive": true,
},
"isUniColor": false,
"layout": Object {
- "height": 500,
+ "height": 1180,
"legend": Object {
"orientation": "v",
"traceorder": "normal",
@@ -344,137 +533,82 @@ exports[`Line component Renders line component 1`] = `
}
}
>
-
-
-
-
+ className="euiText euiText--extraSmall lnsChart__empty"
+ data-test-subj="vizWorkspace__noData"
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ No results found
+
+
+
+
+
+
+
+
+
+
`;
diff --git a/dashboards-observability/public/components/visualizations/charts/__tests__/__snapshots__/logs_view.test.tsx.snap b/dashboards-observability/public/components/visualizations/charts/__tests__/__snapshots__/logs_view.test.tsx.snap
new file mode 100644
index 000000000..bb2936a04
--- /dev/null
+++ b/dashboards-observability/public/components/visualizations/charts/__tests__/__snapshots__/logs_view.test.tsx.snap
@@ -0,0 +1,586 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Logs View component Renders logs view component 1`] = `
+
+
+
+
+
+
+
+
+
+ Time
+
+
+ _source
+
+
+
+
+
+
+
+
+
+
+`;
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 fffaeaa8e..60d2671fd 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
@@ -202,93 +202,275 @@ exports[`Pie component Renders pie component 1`] = `
"userConfigs": Object {},
},
"vis": Object {
+ "barwidth": 0.97,
"category": "Visualizations",
- "categoryAxis": "xaxis",
+ "categoryaxis": "xaxis",
"component": [Function],
- "editorConfig": Object {
+ "editorconfig": Object {
"panelTabs": Array [
Object {
"editor": [Function],
"id": "data-panel",
"mapTo": "dataConfig",
- "name": "Data",
+ "name": "Style",
"sections": Array [
Object {
"editor": [Function],
- "id": "value_options",
- "mapTo": "valueOptions",
- "name": "Value options",
+ "id": "tooltip_options",
+ "mapTo": "tooltipOptions",
+ "name": "Tooltip options",
"schemas": Array [
Object {
"component": null,
- "isSingleSelection": false,
- "mapTo": "xaxis",
- "name": "X-axis",
+ "mapTo": "tooltipMode",
+ "name": "Tooltip mode",
+ "props": Object {
+ "defaultSelections": Array [
+ Object {
+ "id": "show",
+ "name": "Show",
+ },
+ ],
+ "options": Array [
+ Object {
+ "id": "show",
+ "name": "Show",
+ },
+ Object {
+ "id": "hidden",
+ "name": "Hidden",
+ },
+ ],
+ },
},
Object {
"component": null,
- "isSingleSelection": false,
- "mapTo": "yaxis",
- "name": "Y-axis",
+ "mapTo": "tooltipText",
+ "name": "Tooltip text",
+ "props": Object {
+ "defaultSelections": Array [
+ Object {
+ "id": "all",
+ "name": "All",
+ },
+ ],
+ "options": Array [
+ Object {
+ "id": "all",
+ "name": "All",
+ },
+ Object {
+ "id": "x",
+ "name": "Dimension",
+ },
+ Object {
+ "id": "y",
+ "name": "Metrics",
+ },
+ ],
+ },
},
],
},
Object {
"editor": [Function],
- "id": "chart_options",
- "mapTo": "chartOptions",
- "name": "Chart options",
+ "id": "legend",
+ "mapTo": "legend",
+ "name": "Legend",
"schemas": Array [
Object {
"component": null,
- "isSingleSelection": true,
+ "mapTo": "showLegend",
+ "name": "Show legend",
+ "props": Object {
+ "defaultSelections": Array [
+ Object {
+ "id": "show",
+ "name": "Show",
+ },
+ ],
+ "options": Array [
+ Object {
+ "id": "show",
+ "name": "Show",
+ },
+ Object {
+ "id": "hidden",
+ "name": "Hidden",
+ },
+ ],
+ },
+ },
+ Object {
+ "component": null,
+ "mapTo": "position",
+ "name": "Position",
+ "props": Object {
+ "defaultSelections": Array [
+ Object {
+ "id": "v",
+ "name": "Right",
+ },
+ ],
+ "options": Array [
+ Object {
+ "id": "v",
+ "name": "Right",
+ },
+ Object {
+ "id": "h",
+ "name": "Bottom",
+ },
+ ],
+ },
+ },
+ ],
+ },
+ Object {
+ "editor": [Function],
+ "id": "chart_styles",
+ "mapTo": "chartStyles",
+ "name": "Chart styles",
+ "schemas": Array [
+ Object {
+ "component": [Function],
+ "eleType": "buttons",
"mapTo": "orientation",
"name": "Orientation",
"props": Object {
"defaultSelections": Array [
Object {
+ "id": "v",
"name": "Vertical",
- "orientationId": "v",
},
],
- "dropdownList": Array [
+ "options": Array [
Object {
+ "id": "v",
"name": "Vertical",
- "orientationId": "v",
},
Object {
+ "id": "h",
"name": "Horizontal",
- "orientationId": "h",
},
],
},
},
Object {
- "component": null,
- "isSingleSelection": true,
+ "component": [Function],
+ "eleType": "buttons",
"mapTo": "mode",
"name": "Mode",
"props": Object {
"defaultSelections": Array [
Object {
- "modeId": "group",
+ "id": "group",
"name": "Group",
},
],
- "dropdownList": Array [
+ "options": Array [
Object {
- "modeId": "group",
+ "id": "group",
"name": "Group",
},
Object {
- "modeId": "stack",
+ "id": "stack",
"name": "Stack",
},
],
},
},
+ Object {
+ "component": [Function],
+ "eleType": "input",
+ "mapTo": "labelSize",
+ "name": "Label size",
+ },
+ Object {
+ "component": [Function],
+ "defaultState": 0,
+ "eleType": "slider",
+ "mapTo": "rotateBarLabels",
+ "name": "Rotate bar labels",
+ "props": Object {
+ "max": 90,
+ "min": -90,
+ "showTicks": true,
+ "ticks": Array [
+ Object {
+ "label": "-90°",
+ "value": -90,
+ },
+ Object {
+ "label": "-45°",
+ "value": -45,
+ },
+ Object {
+ "label": "0°",
+ "value": 0,
+ },
+ Object {
+ "label": "45°",
+ "value": 45,
+ },
+ Object {
+ "label": "90°",
+ "value": 90,
+ },
+ ],
+ },
+ },
+ Object {
+ "component": [Function],
+ "defaultState": 0.7,
+ "eleType": "slider",
+ "mapTo": "groupWidth",
+ "name": "Group width",
+ "props": Object {
+ "max": 1,
+ "step": 0.01,
+ },
+ },
+ Object {
+ "component": [Function],
+ "defaultState": 0.97,
+ "eleType": "slider",
+ "mapTo": "barWidth",
+ "name": "Bar width",
+ "props": Object {
+ "max": 1,
+ "step": 0.01,
+ },
+ },
+ Object {
+ "component": [Function],
+ "defaultState": 1,
+ "eleType": "slider",
+ "mapTo": "lineWidth",
+ "name": "Line width",
+ "props": Object {
+ "max": 10,
+ },
+ },
+ Object {
+ "component": [Function],
+ "defaultState": 80,
+ "eleType": "slider",
+ "mapTo": "fillOpacity",
+ "name": "Fill opacity",
+ "props": Object {
+ "max": 100,
+ },
+ },
],
},
+ Object {
+ "editor": [Function],
+ "id": "color-theme",
+ "mapTo": "colorTheme",
+ "name": "Color theme",
+ "schemas": Array [],
+ },
],
},
Object {
@@ -306,26 +488,33 @@ exports[`Pie component Renders pie component 1`] = `
},
],
},
- "fullLabel": "Bar",
+ "fillOpacity": 80,
+ "fulllabel": "Vertical bar",
+ "groupwidth": 0.7,
"icon": [Function],
- "iconType": "visBarVerticalStacked",
+ "icontype": "visBarVerticalStacked",
"id": "bar",
- "label": "Bar",
+ "label": "Vertical bar",
+ "labelangle": 0,
+ "legendposition": "v",
+ "linewidth": 1,
+ "mode": "group",
"name": "bar",
"orientation": "v",
"selection": Object {
"dataLoss": "nothing",
},
- "seriesAxis": "yaxis",
+ "seriesaxis": "yaxis",
+ "showlegend": "show",
"type": "bar",
- "visConfig": Object {
+ "visconfig": Object {
"config": Object {
"displaylogo": false,
"responsive": true,
},
"isUniColor": false,
"layout": Object {
- "height": 500,
+ "height": 1180,
"legend": Object {
"orientation": "v",
"traceorder": "normal",
@@ -344,147 +533,82 @@ exports[`Pie component Renders pie component 1`] = `
}
}
>
-
-
-
-
+ className="euiText euiText--extraSmall lnsChart__empty"
+ data-test-subj="vizWorkspace__noData"
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ No results found
+
+
+
+
+
+
+
+
+
+
`;
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 d52e5c2d9..90a14da93 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
@@ -185,93 +185,275 @@ exports[`Text component Renders text component 1`] = `
"userConfigs": Object {},
},
"vis": Object {
+ "barwidth": 0.97,
"category": "Visualizations",
- "categoryAxis": "xaxis",
+ "categoryaxis": "xaxis",
"component": [Function],
- "editorConfig": Object {
+ "editorconfig": Object {
"panelTabs": Array [
Object {
"editor": [Function],
"id": "data-panel",
"mapTo": "dataConfig",
- "name": "Data",
+ "name": "Style",
"sections": Array [
Object {
"editor": [Function],
- "id": "value_options",
- "mapTo": "valueOptions",
- "name": "Value options",
+ "id": "tooltip_options",
+ "mapTo": "tooltipOptions",
+ "name": "Tooltip options",
"schemas": Array [
Object {
"component": null,
- "isSingleSelection": false,
- "mapTo": "xaxis",
- "name": "X-axis",
+ "mapTo": "tooltipMode",
+ "name": "Tooltip mode",
+ "props": Object {
+ "defaultSelections": Array [
+ Object {
+ "id": "show",
+ "name": "Show",
+ },
+ ],
+ "options": Array [
+ Object {
+ "id": "show",
+ "name": "Show",
+ },
+ Object {
+ "id": "hidden",
+ "name": "Hidden",
+ },
+ ],
+ },
},
Object {
"component": null,
- "isSingleSelection": false,
- "mapTo": "yaxis",
- "name": "Y-axis",
+ "mapTo": "tooltipText",
+ "name": "Tooltip text",
+ "props": Object {
+ "defaultSelections": Array [
+ Object {
+ "id": "all",
+ "name": "All",
+ },
+ ],
+ "options": Array [
+ Object {
+ "id": "all",
+ "name": "All",
+ },
+ Object {
+ "id": "x",
+ "name": "Dimension",
+ },
+ Object {
+ "id": "y",
+ "name": "Metrics",
+ },
+ ],
+ },
},
],
},
Object {
"editor": [Function],
- "id": "chart_options",
- "mapTo": "chartOptions",
- "name": "Chart options",
+ "id": "legend",
+ "mapTo": "legend",
+ "name": "Legend",
"schemas": Array [
Object {
"component": null,
- "isSingleSelection": true,
+ "mapTo": "showLegend",
+ "name": "Show legend",
+ "props": Object {
+ "defaultSelections": Array [
+ Object {
+ "id": "show",
+ "name": "Show",
+ },
+ ],
+ "options": Array [
+ Object {
+ "id": "show",
+ "name": "Show",
+ },
+ Object {
+ "id": "hidden",
+ "name": "Hidden",
+ },
+ ],
+ },
+ },
+ Object {
+ "component": null,
+ "mapTo": "position",
+ "name": "Position",
+ "props": Object {
+ "defaultSelections": Array [
+ Object {
+ "id": "v",
+ "name": "Right",
+ },
+ ],
+ "options": Array [
+ Object {
+ "id": "v",
+ "name": "Right",
+ },
+ Object {
+ "id": "h",
+ "name": "Bottom",
+ },
+ ],
+ },
+ },
+ ],
+ },
+ Object {
+ "editor": [Function],
+ "id": "chart_styles",
+ "mapTo": "chartStyles",
+ "name": "Chart styles",
+ "schemas": Array [
+ Object {
+ "component": [Function],
+ "eleType": "buttons",
"mapTo": "orientation",
"name": "Orientation",
"props": Object {
"defaultSelections": Array [
Object {
+ "id": "v",
"name": "Vertical",
- "orientationId": "v",
},
],
- "dropdownList": Array [
+ "options": Array [
Object {
+ "id": "v",
"name": "Vertical",
- "orientationId": "v",
},
Object {
+ "id": "h",
"name": "Horizontal",
- "orientationId": "h",
},
],
},
},
Object {
- "component": null,
- "isSingleSelection": true,
+ "component": [Function],
+ "eleType": "buttons",
"mapTo": "mode",
"name": "Mode",
"props": Object {
"defaultSelections": Array [
Object {
- "modeId": "group",
+ "id": "group",
"name": "Group",
},
],
- "dropdownList": Array [
+ "options": Array [
Object {
- "modeId": "group",
+ "id": "group",
"name": "Group",
},
Object {
- "modeId": "stack",
+ "id": "stack",
"name": "Stack",
},
],
},
},
+ Object {
+ "component": [Function],
+ "eleType": "input",
+ "mapTo": "labelSize",
+ "name": "Label size",
+ },
+ Object {
+ "component": [Function],
+ "defaultState": 0,
+ "eleType": "slider",
+ "mapTo": "rotateBarLabels",
+ "name": "Rotate bar labels",
+ "props": Object {
+ "max": 90,
+ "min": -90,
+ "showTicks": true,
+ "ticks": Array [
+ Object {
+ "label": "-90°",
+ "value": -90,
+ },
+ Object {
+ "label": "-45°",
+ "value": -45,
+ },
+ Object {
+ "label": "0°",
+ "value": 0,
+ },
+ Object {
+ "label": "45°",
+ "value": 45,
+ },
+ Object {
+ "label": "90°",
+ "value": 90,
+ },
+ ],
+ },
+ },
+ Object {
+ "component": [Function],
+ "defaultState": 0.7,
+ "eleType": "slider",
+ "mapTo": "groupWidth",
+ "name": "Group width",
+ "props": Object {
+ "max": 1,
+ "step": 0.01,
+ },
+ },
+ Object {
+ "component": [Function],
+ "defaultState": 0.97,
+ "eleType": "slider",
+ "mapTo": "barWidth",
+ "name": "Bar width",
+ "props": Object {
+ "max": 1,
+ "step": 0.01,
+ },
+ },
+ Object {
+ "component": [Function],
+ "defaultState": 1,
+ "eleType": "slider",
+ "mapTo": "lineWidth",
+ "name": "Line width",
+ "props": Object {
+ "max": 10,
+ },
+ },
+ Object {
+ "component": [Function],
+ "defaultState": 80,
+ "eleType": "slider",
+ "mapTo": "fillOpacity",
+ "name": "Fill opacity",
+ "props": Object {
+ "max": 100,
+ },
+ },
],
},
+ Object {
+ "editor": [Function],
+ "id": "color-theme",
+ "mapTo": "colorTheme",
+ "name": "Color theme",
+ "schemas": Array [],
+ },
],
},
Object {
@@ -289,26 +471,33 @@ exports[`Text component Renders text component 1`] = `
},
],
},
- "fullLabel": "Bar",
+ "fillOpacity": 80,
+ "fulllabel": "Vertical bar",
+ "groupwidth": 0.7,
"icon": [Function],
- "iconType": "visBarVerticalStacked",
+ "icontype": "visBarVerticalStacked",
"id": "bar",
- "label": "Bar",
+ "label": "Vertical bar",
+ "labelangle": 0,
+ "legendposition": "v",
+ "linewidth": 1,
+ "mode": "group",
"name": "bar",
"orientation": "v",
"selection": Object {
"dataLoss": "nothing",
},
- "seriesAxis": "yaxis",
+ "seriesaxis": "yaxis",
+ "showlegend": "show",
"type": "bar",
- "visConfig": Object {
+ "visconfig": Object {
"config": Object {
"displaylogo": false,
"responsive": true,
},
"isUniColor": false,
"layout": Object {
- "height": 500,
+ "height": 1180,
"legend": Object {
"orientation": "v",
"traceorder": "normal",
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
new file mode 100644
index 000000000..39626b437
--- /dev/null
+++ b/dashboards-observability/public/components/visualizations/charts/__tests__/__snapshots__/treemap.test.tsx.snap
@@ -0,0 +1,697 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Treemap component Renders treemap component 1`] = `
+
+
+
+
+
+
+
+`;
diff --git a/dashboards-observability/public/components/visualizations/charts/__tests__/data_table.test.tsx b/dashboards-observability/public/components/visualizations/charts/__tests__/data_table.test.tsx
index e6826ac2a..216a3fa29 100644
--- a/dashboards-observability/public/components/visualizations/charts/__tests__/data_table.test.tsx
+++ b/dashboards-observability/public/components/visualizations/charts/__tests__/data_table.test.tsx
@@ -3,27 +3,24 @@
* SPDX-License-Identifier: Apache-2.0
*/
-import { configure, mount } from 'enzyme';
+import { configure, mount, shallow } from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
import React from 'react';
import { waitFor } from '@testing-library/react';
import { DataTable } from '../data_table/data_table';
import { TEST_VISUALIZATIONS_DATA } from '../../../../../test/event_analytics_constants';
+import { AgGridReact } from 'ag-grid-react';
describe('Data table component', () => {
configure({ adapter: new Adapter() });
it('Renders data table component', async () => {
- const wrapper = mount(
-
- );
-
- wrapper.update();
-
+ const gridWrapper = shallow( );
+ const agGridReactObj = gridWrapper.find(AgGridReact);
+ agGridReactObj.simulate('gridReady');
+ expect(agGridReactObj).toBeTruthy();
await waitFor(() => {
- expect(wrapper).toMatchSnapshot();
+ expect(gridWrapper).toMatchSnapshot();
});
});
});
diff --git a/dashboards-observability/public/components/visualizations/charts/__tests__/histogram.test.tsx b/dashboards-observability/public/components/visualizations/charts/__tests__/histogram.test.tsx
new file mode 100644
index 000000000..6eb1ebfff
--- /dev/null
+++ b/dashboards-observability/public/components/visualizations/charts/__tests__/histogram.test.tsx
@@ -0,0 +1,30 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { configure, mount } from 'enzyme';
+import Adapter from 'enzyme-adapter-react-16';
+import React from 'react';
+import { waitFor } from '@testing-library/react';
+import { Histogram } from '../histogram/histogram';
+import {
+ LAYOUT_CONFIG,
+ TEST_VISUALIZATIONS_DATA,
+} from '../../../../../test/event_analytics_constants';
+
+describe('Histogram component', () => {
+ configure({ adapter: new Adapter() });
+
+ it('Renders histogram component', async () => {
+ const wrapper = mount(
+
+ );
+
+ wrapper.update();
+
+ await waitFor(() => {
+ expect(wrapper).toMatchSnapshot();
+ });
+ });
+});
diff --git a/dashboards-observability/public/components/visualizations/charts/__tests__/logs_view.test.tsx b/dashboards-observability/public/components/visualizations/charts/__tests__/logs_view.test.tsx
new file mode 100644
index 000000000..e467d6055
--- /dev/null
+++ b/dashboards-observability/public/components/visualizations/charts/__tests__/logs_view.test.tsx
@@ -0,0 +1,30 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { configure, mount } from 'enzyme';
+import Adapter from 'enzyme-adapter-react-16';
+import React from 'react';
+import { waitFor } from '@testing-library/react';
+import { LogsView } from '../logs_view/logs_view';
+import {
+ LAYOUT_CONFIG,
+ TEST_VISUALIZATIONS_DATA,
+} from '../../../../../test/event_analytics_constants';
+
+describe('Logs View component', () => {
+ configure({ adapter: new Adapter() });
+
+ it('Renders logs view component', async () => {
+ const wrapper = mount(
+
+ );
+
+ wrapper.update();
+
+ await waitFor(() => {
+ expect(wrapper).toMatchSnapshot();
+ });
+ });
+});
diff --git a/dashboards-observability/public/components/visualizations/charts/__tests__/treemap.test.tsx b/dashboards-observability/public/components/visualizations/charts/__tests__/treemap.test.tsx
new file mode 100644
index 000000000..5210bd416
--- /dev/null
+++ b/dashboards-observability/public/components/visualizations/charts/__tests__/treemap.test.tsx
@@ -0,0 +1,30 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { configure, mount } from 'enzyme';
+import Adapter from 'enzyme-adapter-react-16';
+import React from 'react';
+import { waitFor } from '@testing-library/react';
+import { TreeMap } from '../maps/treemaps';
+import {
+ LAYOUT_CONFIG,
+ TEST_VISUALIZATIONS_DATA,
+} from '../../../../../test/event_analytics_constants';
+
+describe('Treemap component', () => {
+ configure({ adapter: new Adapter() });
+
+ it('Renders treemap component', async () => {
+ const wrapper = mount(
+
+ );
+
+ wrapper.update();
+
+ await waitFor(() => {
+ expect(wrapper).toMatchSnapshot();
+ });
+ });
+});
diff --git a/dashboards-observability/public/components/visualizations/charts/bar/bar.tsx b/dashboards-observability/public/components/visualizations/charts/bar/bar.tsx
index 83ec1e393..f52409b89 100644
--- a/dashboards-observability/public/components/visualizations/charts/bar/bar.tsx
+++ b/dashboards-observability/public/components/visualizations/charts/bar/bar.tsx
@@ -3,71 +3,135 @@
* SPDX-License-Identifier: Apache-2.0
*/
-import React from 'react';
-import { isEmpty, last, take } from 'lodash';
+import React, { useMemo } from 'react';
+import { forEach, isEmpty, last, some, find } from 'lodash';
import { Plt } from '../../plotly/plot';
import { LONG_CHART_COLOR, PLOTLY_COLOR } from '../../../../../common/constants/shared';
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 { hexToRgb } from '../../../event_analytics/utils/utils';
+import { EmptyPlaceholder } from '../../../event_analytics/explorer/visualizations/shared_components/empty_placeholder';
+import { FILLOPACITY_DIV_FACTOR } from '../../../../../common/constants/shared';
+import { IVisualizationContainerProps } from '../../../../../common/types/explorer';
export const Bar = ({ visualizations, layout, config }: any) => {
- const { vis } = visualizations;
+ const DEFAULT_LABEL_SIZE = 10;
const {
- data,
- metadata: { fields },
- } = visualizations.data.rawVizData;
- const { isUniColor } = vis.visConfig;
+ data: {
+ defaultAxes,
+ indexFields,
+ query,
+ rawVizData: {
+ data: queriedVizData,
+ metadata: { fields },
+ },
+ userConfigs,
+ },
+ vis: visMetaData,
+ }: IVisualizationContainerProps = visualizations;
const lastIndex = fields.length - 1;
- const {
- dataConfig = {},
- layoutConfig = {},
- availabilityConfig = {},
- } = visualizations?.data?.userConfigs;
- const xaxis =
- dataConfig.valueOptions && dataConfig.valueOptions.xaxis ? dataConfig.valueOptions.xaxis : [];
- const yaxis =
- dataConfig.valueOptions && dataConfig.valueOptions.xaxis ? dataConfig?.valueOptions.yaxis : [];
- const barOrientation =
- dataConfig?.chartOptions?.orientation &&
- dataConfig.chartOptions.orientation[0] &&
- dataConfig.chartOptions.orientation[0].orientationId
- ? dataConfig.chartOptions.orientation[0].orientationId
- : visualizations.vis.orientation;
- const { defaultAxes } = visualizations.data;
-
- const isVertical = barOrientation === 'v';
-
- // Individual bars have different colors
- // when: stackLength = 1 and length of result buckets < 16 and chart is not unicolor
- // Else each stacked bar has its own color using colorway
- let marker = {};
- if (lastIndex === 1 && data[fields[lastIndex].name].length < 16 && !isUniColor) {
- marker = {
- color: data[fields[lastIndex].name].map((_: string, index: number) => {
- return PLOTLY_COLOR[index % PLOTLY_COLOR.length];
- }),
- };
- }
+ const { dataConfig = {}, layoutConfig = {}, availabilityConfig = {} } = userConfigs;
+ console.log('bar dataConfig: ', dataConfig);
- let valueSeries;
- if (!isEmpty(xaxis) && !isEmpty(yaxis)) {
- valueSeries = isVertical ? [...yaxis] : [...xaxis];
- } else {
- valueSeries = defaultAxes.yaxis || take(fields, lastIndex > 0 ? lastIndex : 1);
- }
+ if (
+ isEmpty(queriedVizData) ||
+ !Array.isArray(dataConfig.dimensions) ||
+ !Array.isArray(dataConfig.metrics) ||
+ (dataConfig.breakdowns && !Array.isArray(dataConfig.breakdowns))
+ )
+ return ;
+
+ /**
+ * determine stylings
+ */
+ const barOrientation = dataConfig.chartStyles?.orientation || visMetaData.orientation;
+ const isVertical = barOrientation === visMetaData.orientation;
+
+ const tickAngle = dataConfig?.chartStyles?.rotateBarLabels || visMetaData.labelangle;
+ const lineWidth = dataConfig?.chartStyles?.lineWidth || visMetaData.linewidth;
+ const fillOpacity =
+ dataConfig?.chartStyles?.fillOpacity !== undefined
+ ? dataConfig?.chartStyles?.fillOpacity / FILLOPACITY_DIV_FACTOR
+ : visMetaData.fillOpacity / FILLOPACITY_DIV_FACTOR;
+ const barWidth = 1 - (dataConfig?.chartStyles?.barWidth || visMetaData.barwidth);
+ const groupWidth = 1 - (dataConfig?.chartStyles?.groupWidth || visMetaData.groupwidth);
+ const showLegend = !(
+ dataConfig?.legend?.showLegend && dataConfig.legend.showLegend !== visMetaData.showlegend
+ );
+ const legendPosition = dataConfig?.legend?.position || visMetaData.legendposition;
+ visualizations.data?.rawVizData?.dataConfig?.metrics
+ ? visualizations.data?.rawVizData?.dataConfig?.metrics
+ : [];
+ const labelSize = dataConfig?.chartStyles?.labelSize || DEFAULT_LABEL_SIZE;
+
+ const getSelectedColorTheme = (field: any, index: number) =>
+ (dataConfig?.colorTheme?.length > 0 &&
+ dataConfig.colorTheme.find((colorSelected) => colorSelected.name.name === field.label)
+ ?.color) ||
+ PLOTLY_COLOR[index % PLOTLY_COLOR.length];
- // determine category axis
- let bars = valueSeries.map((field: any) => {
+ let bars, valueSeries, valueForXSeries;
+
+ /**
+ * determine x axis
+ */
+ const xaxes = useMemo(() => {
+ // breakdown selections
+ if (dataConfig.breakdowns) {
+ return [
+ ...dataConfig.dimensions.filter(
+ (dimension) =>
+ !some(dataConfig.breakdowns, (breakdown) => breakdown.label === dimension.label)
+ ),
+ ];
+ }
+
+ // span selection
+ const timestampField = find(fields, (field) => field.type === 'timestamp');
+ if (dataConfig.span && dataConfig.span.time_field && timestampField) {
+ return [timestampField, ...dataConfig.dimensions];
+ }
+
+ return [...dataConfig.dimensions];
+ }, [dataConfig.dimensions, dataConfig.breakdowns]);
+
+ /**
+ * determine y axis
+ */
+ const yaxes = useMemo(() => {
+ return Array.isArray(dataConfig.metrics) ? [...dataConfig.metrics] : [];
+ }, [dataConfig.metrics]);
+
+ /**
+ * prepare data for visualization, map x-xais to y-xais
+ */
+ const chartAxis = useMemo(() => {
+ return Array.isArray(queriedVizData[`${yaxes[0].aggregation}(${yaxes[0].name})`])
+ ? queriedVizData[`${yaxes[0].aggregation}(${yaxes[0].name})`].map((_, idx) => {
+ // let combineXaxis = '';
+ const xaxisName = xaxes.map((xaxis) => {
+ return queriedVizData[xaxis.name] && queriedVizData[xaxis.name][idx]
+ ? queriedVizData[xaxis.name][idx]
+ : '';
+ });
+ return xaxisName.join(', ');
+ })
+ : [];
+ }, [queriedVizData, xaxes, yaxes]);
+
+ bars = yaxes?.map((yMetric, idx) => {
return {
- x: isVertical
- ? data[!isEmpty(xaxis) ? xaxis[0].label : fields[lastIndex].name]
- : data[field.name],
- y: isVertical
- ? data[field.name]
- : data[!isEmpty(yaxis) ? yaxis[0]?.label : fields[lastIndex].name],
- type: vis.type,
- marker,
- name: field.name,
+ y: isVertical ? queriedVizData[`${yMetric.aggregation}(${yMetric.name})`] : chartAxis,
+ x: isVertical ? chartAxis : queriedVizData[`${yMetric.aggregation}(${yMetric.name})`],
+ type: visMetaData.type,
+ marker: {
+ color: getSelectedColorTheme(yMetric, idx),
+ line: {
+ color: getSelectedColorTheme(yMetric, idx),
+ width: lineWidth,
+ },
+ },
+ name: yMetric.name,
orientation: barOrientation,
};
});
@@ -75,21 +139,29 @@ export const Bar = ({ visualizations, layout, config }: any) => {
// If chart has length of result buckets < 16
// then use the LONG_CHART_COLOR for all the bars in the chart
const plotlyColorway =
- data[fields[lastIndex].name].length < 16 ? PLOTLY_COLOR : [LONG_CHART_COLOR];
+ queriedVizData[fields[lastIndex].name].length < 16 ? PLOTLY_COLOR : [LONG_CHART_COLOR];
const mergedLayout = {
colorway: plotlyColorway,
...layout,
...(layoutConfig.layout && layoutConfig.layout),
title: dataConfig?.panelOptions?.title || layoutConfig.layout?.title || '',
- barmode:
- dataConfig?.chartOptions?.mode &&
- dataConfig.chartOptions.mode[0] &&
- dataConfig.chartOptions.mode[0].modeId
- ? dataConfig.chartOptions.mode[0].modeId
- : '',
+ barmode: dataConfig?.chartStyles?.mode || visualizations.vis.mode,
+ font: {
+ size: labelSize,
+ },
+ xaxis: {
+ tickangle: tickAngle,
+ automargin: true,
+ },
+ bargap: groupWidth,
+ bargroupgap: barWidth,
+ legend: {
+ ...layout.legend,
+ orientation: legendPosition,
+ },
+ showlegend: showLegend,
};
-
if (dataConfig.thresholds || availabilityConfig.level) {
const thresholdTraces = {
x: [],
@@ -103,15 +175,17 @@ export const Bar = ({ visualizations, layout, config }: any) => {
const mapToLine = (list: ThresholdUnitType[] | AvailabilityUnitType[], lineStyle: any) => {
return list.map((thr: ThresholdUnitType) => {
thresholdTraces.x.push(
- data[!isEmpty(xaxis) ? xaxis[xaxis.length - 1]?.label : fields[lastIndex].name][0]
+ queriedVizData[
+ !isEmpty(xaxis) ? xaxis[xaxis.length - 1]?.label : fields[lastIndex].name
+ ][0]
);
thresholdTraces.y.push(thr.value * (1 + 0.06));
thresholdTraces.text.push(thr.name);
return {
type: 'line',
- x0: data[!isEmpty(xaxis) ? xaxis[0]?.label : fields[lastIndex].name][0],
+ x0: queriedVizData[!isEmpty(xaxis) ? xaxis[0]?.label : fields[lastIndex].name][0],
y0: thr.value,
- x1: last(data[!isEmpty(xaxis) ? xaxis[0]?.label : fields[lastIndex].name]),
+ x1: last(queriedVizData[!isEmpty(xaxis) ? xaxis[0]?.label : fields[lastIndex].name]),
y1: thr.value,
name: thr.name || '',
opacity: 0.7,
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 fb89427bc..2a0bc0c18 100644
--- a/dashboards-observability/public/components/visualizations/charts/bar/bar_type.ts
+++ b/dashboards-observability/public/components/visualizations/charts/bar/bar_type.ts
@@ -8,90 +8,201 @@ import { getPlotlySharedConfigs, getPlotlyCategory } from '../shared/shared_conf
import { LensIconChartBar } from '../../assets/chart_bar';
import { VizDataPanel } from '../../../event_analytics/explorer/visualizations/config_panel/config_panes/default_vis_editor';
import { ConfigEditor } from '../../../event_analytics/explorer/visualizations/config_panel/config_panes/json_editor';
-import { ConfigValueOptions } from '../../../event_analytics/explorer/visualizations/config_panel/config_panes/config_controls';
import { ConfigAvailability } from '../../../event_analytics/explorer/visualizations/config_panel/config_panes/config_controls/config_availability';
-
+import { ButtonGroupItem } from '../../../event_analytics/explorer/visualizations/config_panel/config_panes/config_controls/config_button_group';
+import { ConfigBarChartStyles } from '../../../event_analytics/explorer/visualizations/config_panel/config_panes/config_controls/config_bar_chart_styles';
+import { SliderConfig } from '../../../event_analytics/explorer/visualizations/config_panel/config_panes/config_controls/config_style_slider';
+import {
+ ConfigLegend,
+ InputFieldItem,
+} from '../../../event_analytics/explorer/visualizations/config_panel/config_panes/config_controls';
+import { DefaultChartStyles } from '../../../../../common/constants/shared';
+import { fetchConfigObject } from '../../../../components/event_analytics/utils/utils';
+import { ConfigColorTheme } from '../../../event_analytics/explorer/visualizations/config_panel/config_panes/config_controls/config_color_theme';
const sharedConfigs = getPlotlySharedConfigs();
const VIS_CATEGORY = getPlotlyCategory();
+const { LegendPosition, ShowLegend } = DefaultChartStyles;
export const createBarTypeDefinition = (params: any) => ({
name: 'bar',
type: 'bar',
id: 'bar',
- label: 'Bar',
- fullLabel: 'Bar',
- iconType: 'visBarVerticalStacked',
+ label: 'Vertical bar',
+ fulllabel: 'Vertical bar',
+ icontype: 'visBarVerticalStacked',
selection: {
dataLoss: 'nothing',
},
category: VIS_CATEGORY.BASICS,
icon: LensIconChartBar,
- categoryAxis: 'xaxis',
- seriesAxis: 'yaxis',
+ categoryaxis: 'xaxis',
+ seriesaxis: 'yaxis',
orientation: 'v',
+ mode: 'group',
+ labelangle: 0,
+ linewidth: 1,
+ fillOpacity: 80,
+ groupwidth: 0.7,
+ barwidth: 0.97,
+ showlegend: ShowLegend,
+ legendposition: LegendPosition,
component: Bar,
- editorConfig: {
+ editorconfig: {
panelTabs: [
{
id: 'data-panel',
- name: 'Data',
+ name: 'Style',
mapTo: 'dataConfig',
editor: VizDataPanel,
sections: [
+ fetchConfigObject('Tooltip', {
+ options: [
+ { name: 'All', id: 'all' },
+ { name: 'Dimension', id: 'x' },
+ { name: 'Metrics', id: 'y' },
+ ],
+ defaultSelections: [{ name: 'All', id: 'all' }],
+ }),
{
- id: 'value_options',
- name: 'Value options',
- editor: ConfigValueOptions,
- mapTo: 'valueOptions',
+ id: 'legend',
+ name: 'Legend',
+ editor: ConfigLegend,
+ mapTo: 'legend',
schemas: [
{
- name: 'X-axis',
- isSingleSelection: false,
+ name: 'Show legend',
+ mapTo: 'showLegend',
component: null,
- mapTo: 'xaxis',
+ props: {
+ options: [
+ { name: 'Show', id: 'show' },
+ { name: 'Hidden', id: 'hidden' },
+ ],
+ defaultSelections: [{ name: 'Show', id: ShowLegend }],
+ },
},
{
- name: 'Y-axis',
- isSingleSelection: false,
+ name: 'Position',
+ mapTo: 'position',
component: null,
- mapTo: 'yaxis',
+ props: {
+ options: [
+ { name: 'Right', id: 'v' },
+ { name: 'Bottom', id: 'h' },
+ ],
+ defaultSelections: [{ name: 'Right', id: LegendPosition }],
+ },
},
],
},
{
- id: 'chart_options',
- name: 'Chart options',
- editor: ConfigValueOptions,
- mapTo: 'chartOptions',
+ id: 'chart_styles',
+ name: 'Chart styles',
+ editor: ConfigBarChartStyles,
+ mapTo: 'chartStyles',
schemas: [
{
name: 'Orientation',
- isSingleSelection: true,
- component: null,
+ component: ButtonGroupItem,
mapTo: 'orientation',
+ eleType: 'buttons',
props: {
- dropdownList: [
- { name: 'Vertical', orientationId: 'v' },
- { name: 'Horizontal', orientationId: 'h' },
+ options: [
+ { name: 'Vertical', id: 'v' },
+ { name: 'Horizontal', id: 'h' },
],
- defaultSelections: [{ name: 'Vertical', orientationId: 'v' }],
+ defaultSelections: [{ name: 'Vertical', id: 'v' }],
},
},
{
name: 'Mode',
- isSingleSelection: true,
- component: null,
+ component: ButtonGroupItem,
mapTo: 'mode',
+ eleType: 'buttons',
props: {
- dropdownList: [
- { name: 'Group', modeId: 'group' },
- { name: 'Stack', modeId: 'stack' },
+ options: [
+ { name: 'Group', id: 'group' },
+ { name: 'Stack', id: 'stack' },
],
- defaultSelections: [{ name: 'Group', modeId: 'group' }],
+ defaultSelections: [{ name: 'Group', id: 'group' }],
},
},
+ {
+ name: 'Label size',
+ component: InputFieldItem,
+ mapTo: 'labelSize',
+ eleType: 'input',
+ },
+ {
+ name: 'Rotate bar labels',
+ component: SliderConfig,
+ mapTo: 'rotateBarLabels',
+ eleType: 'slider',
+ defaultState: 0,
+ props: {
+ ticks: [
+ { label: '-90°', value: -90 },
+ { label: '-45°', value: -45 },
+ { label: '0°', value: 0 },
+ { label: '45°', value: 45 },
+ { label: '90°', value: 90 },
+ ],
+ showTicks: true,
+ min: -90,
+ max: 90,
+ },
+ },
+ {
+ name: 'Group width',
+ component: SliderConfig,
+ mapTo: 'groupWidth',
+ defaultState: 0.7,
+ props: {
+ max: 1,
+ step: 0.01,
+ },
+ eleType: 'slider',
+ },
+ {
+ name: 'Bar width',
+ component: SliderConfig,
+ mapTo: 'barWidth',
+ defaultState: 0.97,
+ props: {
+ max: 1,
+ step: 0.01,
+ },
+ eleType: 'slider',
+ },
+ {
+ name: 'Line width',
+ component: SliderConfig,
+ mapTo: 'lineWidth',
+ defaultState: 1,
+ props: {
+ max: 10,
+ },
+ eleType: 'slider',
+ },
+ {
+ name: 'Fill opacity',
+ component: SliderConfig,
+ mapTo: 'fillOpacity',
+ defaultState: 80,
+ props: {
+ max: 100,
+ },
+ eleType: 'slider',
+ },
],
},
+ {
+ id: 'color-theme',
+ name: 'Color theme',
+ editor: ConfigColorTheme,
+ mapTo: 'colorTheme',
+ schemas: [],
+ },
],
},
{
@@ -109,7 +220,7 @@ export const createBarTypeDefinition = (params: any) => ({
},
],
},
- visConfig: {
+ visconfig: {
layout: {
...sharedConfigs.layout,
},
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..91168c7d2 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
@@ -15,22 +15,22 @@ export const createHorizontalBarTypeDefinition = (params: BarTypeParams = {}) =>
name: 'horizontal_bar',
type: 'bar',
label: 'Bar',
- fullLabel: 'Bar',
- iconType: 'visBarVerticalStacked',
+ fulllabel: 'Bar',
+ icontype: 'visBarVerticalStacked',
selection: {
dataLoss: 'nothing',
},
category: VIS_CATEGORY.BASICS,
icon: LensIconChartBar,
- categoryAxis: 'xaxis',
- seriesAxis: 'yaxis',
+ categoryaxis: 'xaxis',
+ seriesaxis: 'yaxis',
orientation: 'h',
component: Bar,
- editorConfig: {
+ editorconfig: {
panelTabs: [
{
id: 'data-panel',
- name: 'Data',
+ name: 'Style',
mapTo: 'dataConfig',
editor: VizDataPanel,
sections: [
@@ -99,7 +99,7 @@ export const createHorizontalBarTypeDefinition = (params: BarTypeParams = {}) =>
},
],
},
- visConfig: {
+ visconfig: {
layout: {
...sharedConfigs.layout,
},
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..b4cac8ded 100644
--- a/dashboards-observability/public/components/visualizations/charts/bubble/bubble_type.ts
+++ b/dashboards-observability/public/components/visualizations/charts/bubble/bubble_type.ts
@@ -18,16 +18,16 @@ export const createBubbleVisDefinition = () => ({
type: 'bubble',
id: 'bubble',
label: 'Bubble',
- fullLabel: 'Bubble',
+ fulllabel: 'Bubble',
category: VIS_CATEGORY.BASICS,
selection: {
dataLoss: 'nothing',
},
- editorConfig: {
+ editorconfig: {
panelTabs: [
{
id: 'data-panel',
- name: 'Data',
+ name: 'Style',
mapTo: 'dataConfig',
editor: VizDataPanel,
sections: [
@@ -63,7 +63,7 @@ export const createBubbleVisDefinition = () => ({
],
},
icon: LensIconChartPie,
- visConfig: {
+ visconfig: {
layout: {
...sharedConfigs.layout,
},
diff --git a/dashboards-observability/public/components/visualizations/charts/data_table/data_table.scss b/dashboards-observability/public/components/visualizations/charts/data_table/data_table.scss
new file mode 100644
index 000000000..86cb0b90e
--- /dev/null
+++ b/dashboards-observability/public/components/visualizations/charts/data_table/data_table.scss
@@ -0,0 +1,63 @@
+.pagination-wrapper {
+ display: flex;
+ justify-content: space-between;
+}
+.custom-pagination-container {
+ display: inline-flex;
+ padding: 10px 5px;
+}
+
+.custom-pagination-container li {
+ font-size: 14px;
+ padding: 0 5px;
+ display: flex;
+ align-items: flex-end;
+ font-weight: 600;
+}
+
+.custom-pagination-container .euiIcon:focus {
+ background: transparent !important;
+}
+.custom-pagination-container a:focus {
+ animation: none !important;
+}
+.custom-pagination-container a {
+ cursor: pointer;
+}
+
+.custom-pagination-container .disabled {
+ cursor: default;
+}
+.custom-pagination-container a {
+ color: #343741;
+}
+.dark-theme a {
+ color: #dfe5ef;
+}
+.custom-pagination-container .selected a {
+ color: #1ba9f5;
+ text-decoration: underline;
+ cursor: default;
+}
+
+.custom-overlay {
+ display: flex;
+ align-items: flex-start;
+ padding: 10px;
+ position: fixed;
+ top: 100px;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ z-index: 99999 !important;
+ overflow-y: scroll;
+ overflow-x: hidden;
+}
+
+.custom-overlay-light {
+ background-color: #fff;
+}
+
+.custom-overlay-dark {
+ background-color: #16171c;
+}
diff --git a/dashboards-observability/public/components/visualizations/charts/data_table/data_table.tsx b/dashboards-observability/public/components/visualizations/charts/data_table/data_table.tsx
index 912a9dc2c..e6121c21f 100644
--- a/dashboards-observability/public/components/visualizations/charts/data_table/data_table.tsx
+++ b/dashboards-observability/public/components/visualizations/charts/data_table/data_table.tsx
@@ -3,102 +3,225 @@
* SPDX-License-Identifier: Apache-2.0
*/
-import React, { useState, useMemo, useCallback } from 'react';
-import { EuiInMemoryTable, EuiDataGrid } from '@elastic/eui';
+import React, {
+ useState,
+ useMemo,
+ useCallback,
+ useRef,
+ useEffect,
+} from 'react';
+import {
+ EuiFlexGroup,
+ EuiFlexItem,
+} from '@elastic/eui';
-export const DataTable = ({ visualizations }: any) => {
+// ag-data-grid
+import { AgGridReact } from 'ag-grid-react';
+import 'ag-grid-community/dist/styles/ag-grid.css';
+import 'ag-grid-community/dist/styles/ag-theme-alpine.css';
+import 'ag-grid-community/dist/styles/ag-theme-alpine-dark.css';
+
+// styles
+import './data_table.scss';
+
+// grid elements
+import { CustomOverlay, RowConfigType, GridHeader, } from "./data_table_header"
+import { GridFooter } from "./data_table_footer"
+
+// constants
+import {
+ COLUMN_DEFAULT_MIN_WIDTH,
+ HEADER_HEIGHT,
+} from '../../../../../common/constants/explorer';
+
+
+const doubleValueGetter = (params) => {
+ return params.data[params.column.colId];
+};
+
+export const DataTable = ({ visualizations, layout, config }: any) => {
const {
data: vizData,
jsonData,
metadata: { fields = [] },
} = visualizations.data.rawVizData;
+ useEffect(() => {
+ document.addEventListener('keydown', hideGridFullScreenHandler);
+ return () => {
+ document.removeEventListener('keydown', hideGridFullScreenHandler);
+ };
+ }, []);
+
+ // rows and columns
const raw_data = [...jsonData];
- // Pagination
- const [pagination, setPagination] = useState({ pageIndex: 0, pageSize: 10 });
- const onChangeItemsPerPage = useCallback(
- (pageSize) =>
- setPagination((pagination) => ({
- ...pagination,
- pageSize,
- pageIndex: 0,
- })),
- [setPagination]
- );
- const onChangePage = useCallback(
- (pageIndex) => setPagination((pagination) => ({ ...pagination, pageIndex })),
- [setPagination]
- );
+ const columns = fields.map((field: any) => {
+ return {
+ lockVisible: true,
+ columnsMenuParams: {
+ suppressColumnFilter: true,
+ suppressColumnSelectAll: true,
+ suppressColumnExpandAll: true,
+ },
+ headerName: field.name,
+ field: field.name,
+ colId: field.name,
+ ...(field.type === 'double' && {
+ valueGetter: doubleValueGetter,
+ }),
+ };
+ });
- // Sorting
- const [sortingColumns, setSortingColumns] = useState([]);
- const onSort = useCallback(
- (sortingColumns) => {
- setSortingColumns(sortingColumns);
- },
- [setSortingColumns]
- );
+ // ag-grid-react bindings
+ const gridRef = useRef();
+ const gridRefFullScreen = useRef();
+ const [pageSize, setPageSize] = useState(10);
+ const [columnVisibility, setColumnVisibility] = useState([]);
+ const [isFullScreen, setIsFullScreen] = useState(false);
+ const [selectedRowDensity, setSelectedRowDensity] = useState({
+ icon: 'tableDensityCompact',
+ height: 35,
+ selected: true,
+ });
+ // pagination
+ const [activePage, setActivePage] = useState(0);
+ const pageCount = Math.ceil(raw_data.length / pageSize);
- // Sort data
- let data = useMemo(() => {
- return [...raw_data].sort((a, b) => {
- for (let i = 0; i < sortingColumns.length; i++) {
- const column = sortingColumns[i];
- const aValue = a[column.id];
- const bValue = b[column.id];
+ const defaultColDef = useMemo(() => {
+ return {
+ sortable: true,
+ resizable: true,
+ filter: true,
+ flex: 1,
+ suppressMenu: true,
+ minWidth: COLUMN_DEFAULT_MIN_WIDTH,
+ headerHeight: 400,
+ };
+ }, []);
- if (aValue < bValue) return column.direction === 'asc' ? -1 : 1;
- if (aValue > bValue) return column.direction === 'asc' ? 1 : -1;
+ const onPageSizeChanged = useCallback(
+ (val: number) => {
+ setPageSize(val);
+ gridRef.current.api.paginationSetPageSize(val);
+ setActivePage(0);
+ gridRef.current.api.paginationGoToPage(0);
+ if (isFullScreen) {
+ gridRefFullScreen.current.api.paginationSetPageSize(val);
+ gridRefFullScreen.current.api.paginationGoToPage(0);
}
+ },
+ [isFullScreen]
+ );
- return 0;
+ const selectDensityHandler = useCallback((value: RowConfigType) => {
+ setSelectedRowDensity({ ...value });
+ gridRef.current.api.forEachNode((rowNode) => {
+ if (rowNode.data) {
+ rowNode.setRowHeight(value.height);
+ }
});
- }, [sortingColumns]);
-
- // Pagination
- data = useMemo(() => {
- const rowStart = pagination.pageIndex * pagination.pageSize;
- const rowEnd = Math.min(rowStart + pagination.pageSize, data.length);
- return data.slice(rowStart, rowEnd);
- }, [data, pagination]);
-
- const columns = fields.map((field) => {
- return {
- id: field.name,
- };
- });
-
- // Column visibility
- const [visibleColumns, setVisibleColumns] = useState(columns.map(({ id }) => id));
+ gridRef.current.api.onRowHeightChanged();
+ }, []);
- const renderCellValue = useMemo(() => {
- return ({ rowIndex, columnId }) => {
- let adjustedRowIndex = rowIndex;
+ const columnVisiblityHandler = useCallback((visible: boolean, field: string) => {
+ const isExisting = columnVisibility.findIndex((column) => column === field);
+ if (visible) {
+ if (isExisting > -1) {
+ columnVisibility.splice(isExisting, 1);
+ gridRef?.current?.columnApi?.setColumnsVisible([field], true);
+ }
+ } else {
+ columnVisibility.push(field);
+ gridRef?.current?.columnApi?.setColumnsVisible([field], false);
+ }
+ setColumnVisibility([...columnVisibility]);
+ }, []);
- // If we are doing the pagination (instead of leaving that to the grid)
- // then the row index must be adjusted as `data` has already been pruned to the page size
- adjustedRowIndex = rowIndex - pagination.pageIndex * pagination.pageSize;
+ const goToPage = ({ selected }: { selected: number }) => {
+ setActivePage(selected);
+ gridRef.current.api.paginationGoToPage(selected);
+ if (isFullScreen) {
+ gridRefFullScreen.current.api.paginationGoToPage(selected);
+ }
+ };
- return data.hasOwnProperty(adjustedRowIndex) ? data[adjustedRowIndex][columnId] : null;
- };
- }, [data, pagination.pageIndex, pagination.pageSize]);
+ const setIsFullScreenHandler = (val: boolean) => {
+ setIsFullScreen(val);
+ };
+ const hideGridFullScreenHandler = (e: any) => {
+ if (e.key === 'Escape') {
+ setIsFullScreen(false);
+ }
+ };
return (
-
+ <>
+
+ {
+ gridRef?.current?.api.setHeaderHeight(HEADER_HEIGHT);
+ }}
+ />
+
+ {isFullScreen && (
+
+
+
+ {
+ gridRefFullScreen?.current?.api.setHeaderHeight(HEADER_HEIGHT);
+ }}
+ />
+
+
+
+
+
+
+ )}
+ >
);
};
+
+
diff --git a/dashboards-observability/public/components/visualizations/charts/data_table/data_table_footer.tsx b/dashboards-observability/public/components/visualizations/charts/data_table/data_table_footer.tsx
new file mode 100644
index 000000000..f8350ddd2
--- /dev/null
+++ b/dashboards-observability/public/components/visualizations/charts/data_table/data_table_footer.tsx
@@ -0,0 +1,126 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import React, { useState } from 'react';
+import {
+ EuiFlexGroup,
+ EuiFlexItem,
+ EuiButtonEmpty,
+ EuiPopover,
+ EuiIcon,
+ EuiContextMenuPanel,
+ EuiContextMenuItem,
+} from '@elastic/eui';
+
+// pagination
+import ReactPaginate from 'react-paginate';
+
+// theme
+import { uiSettingsService } from '../../../../../common/utils';
+
+// constants
+import {
+ GRID_PAGE_RANGE_DISPLAY,
+ GRID_PAGE_SIZES,
+} from '../../../../../common/constants/explorer';
+
+export const GridFooter = ({
+ onPageSizeChanged,
+ pageSize,
+ activePage,
+ goToPage,
+ pageCount,
+}: {
+ onPageSizeChanged: (val: number) => void;
+ goToPage: ({ selected }: { selected: number }) => void;
+ pageSize: number;
+ activePage: number;
+ pageCount: number;
+}) => {
+ return (
+
+
+
+
+
+ }
+ forcePage={activePage}
+ onPageChange={goToPage}
+ pageRangeDisplayed={GRID_PAGE_RANGE_DISPLAY}
+ pageCount={pageCount}
+ previousLabel={ }
+ renderOnZeroPageCount={null}
+ />
+
+
+ );
+};
+
+export const PageSizePopover = ({
+ onPageSizeChanged,
+ pageSize,
+}: {
+ onPageSizeChanged: (size: number) => void;
+ pageSize: number;
+}) => {
+ const [isPopoverOpen, setIsPopoverOpen] = useState(false);
+ const onButtonClick = () => setIsPopoverOpen((isPopoverOpen) => !isPopoverOpen);
+ const closePopover = () => setIsPopoverOpen(false);
+
+ const button = (
+
+ Rows per page: {pageSize}
+
+ );
+
+ const items = () => {
+ return GRID_PAGE_SIZES.map((i: number) => (
+ {
+ onPageSizeChanged(i);
+ closePopover();
+ }}
+ >
+ {i} rows
+
+ ));
+ };
+
+ return (
+
+
+
+ );
+};
diff --git a/dashboards-observability/public/components/visualizations/charts/data_table/data_table_header.tsx b/dashboards-observability/public/components/visualizations/charts/data_table/data_table_header.tsx
new file mode 100644
index 000000000..1c2d2b034
--- /dev/null
+++ b/dashboards-observability/public/components/visualizations/charts/data_table/data_table_header.tsx
@@ -0,0 +1,195 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import React, { useState, ReactChildren, ReactChild } from 'react';
+import {
+ EuiButtonIcon,
+ EuiFlexGroup,
+ EuiFlexItem,
+ EuiButtonEmpty,
+ EuiPopover,
+ EuiSwitch,
+ EuiIcon,
+} from '@elastic/eui';
+
+// theme
+import { uiSettingsService } from '../../../../../common/utils';
+
+// constants
+import {
+ GRID_HEADER_COLUMN_MAX_WIDTH,
+ ROW_DENSITIES,
+} from '../../../../../common/constants/explorer';
+
+export interface RowConfigType {
+ icon: string;
+ height: number;
+ selected: boolean;
+}
+
+export const CustomOverlay = ({
+ children,
+}: {
+ children: ReactChild | ReactChild[] | ReactChildren | ReactChildren[];
+}) => {
+ return (
+
+ {children}
+
+ );
+};
+
+export const GridHeader = ({
+ isFullScreen,
+ setIsFullScreenHandler,
+ selectedRowDensity,
+ selectDensityHandler,
+ columnVisiblityHandler,
+ columns,
+ columnVisibility,
+}: {
+ isFullScreen: boolean;
+ setIsFullScreenHandler: (v: boolean) => void;
+ selectedRowDensity: any;
+ selectDensityHandler: (v: RowConfigType) => void;
+ columnVisiblityHandler: (visible: boolean, field: string) => void;
+ columns: any;
+ columnVisibility: any;
+}) => {
+ return (
+
+
+
+
+
+
+
+
+ setIsFullScreenHandler(true)}
+ >
+ Full screen
+
+
+ {isFullScreen && (
+ setIsFullScreenHandler(false)}
+ style={{ position: 'absolute', right: 20, cursor: 'pointer', top: 20 }}
+ />
+ )}
+
+ );
+};
+
+export const DensityPopover = ({
+ selectDensityHandler,
+ selectedDensity,
+}: {
+ selectedDensity: any;
+ selectDensityHandler: (data: RowConfigType) => void;
+}) => {
+ const [isPopoverOpen, setIsPopoverOpen] = useState(false);
+ const onButtonClick = () => setIsPopoverOpen((isPopoverOpen) => !isPopoverOpen);
+ const closePopover = () => setIsPopoverOpen(false);
+
+ const button = (
+
+ Density
+
+ );
+
+ return (
+
+
+ {ROW_DENSITIES.map((i: RowConfigType, index: number) => (
+
+ selectDensityHandler(i)}
+ display={selectedDensity.icon === i.icon ? 'fill' : 'base'}
+ iconType={i.icon}
+ aria-label="Next"
+ />
+
+ ))}
+
+
+ );
+};
+
+export const ColumnVisiblityPopover = ({
+ columnVisibility,
+ columns,
+ columnVisiblityHandler,
+}: {
+ columns: any;
+ columnVisibility: any;
+ columnVisiblityHandler: (visible: boolean, field: string) => void;
+}) => {
+ const [isPopoverOpen, setIsPopoverOpen] = useState(false);
+ const onButtonClick = () => setIsPopoverOpen((isPopoverOpen) => !isPopoverOpen);
+ const closePopover = () => setIsPopoverOpen(false);
+
+ const button = (
+
+ Columns
+
+ );
+
+ return (
+
+
+ {columns.map((i: any, index: number) => {
+ return (
+
+ {
+ columnVisiblityHandler(e.target.checked, i.field);
+ }}
+ compressed
+ />
+
+ );
+ })}
+
+
+ );
+};
diff --git a/dashboards-observability/public/components/visualizations/charts/data_table/data_table_type.ts b/dashboards-observability/public/components/visualizations/charts/data_table/data_table_type.ts
index e3f03764a..d43b78f31 100644
--- a/dashboards-observability/public/components/visualizations/charts/data_table/data_table_type.ts
+++ b/dashboards-observability/public/components/visualizations/charts/data_table/data_table_type.ts
@@ -14,14 +14,14 @@ export const createDatatableTypeDefinition = (params: any = {}) => ({
type: 'data_table',
id: 'data_table',
label: 'Data Table',
- fullLabel: 'Data Table',
- iconType: 'visTable',
+ fulllabel: 'Data Table',
+ icontype: 'visTable',
category: VIS_CATEGORY.BASICS,
selection: {
dataLoss: 'nothing',
},
icon: LensIconChartDatatable,
- editorConfig: {
+ editorconfig: {
editor: null,
schemas: [
{
diff --git a/dashboards-observability/public/components/visualizations/charts/financial/gauge/gauge.tsx b/dashboards-observability/public/components/visualizations/charts/financial/gauge/gauge.tsx
index 711f4d9e2..7882f79c6 100644
--- a/dashboards-observability/public/components/visualizations/charts/financial/gauge/gauge.tsx
+++ b/dashboards-observability/public/components/visualizations/charts/financial/gauge/gauge.tsx
@@ -4,11 +4,20 @@
*/
import React, { useMemo } from 'react';
-import { indexOf } from 'lodash';
import Plotly from 'plotly.js-dist';
import { Plt } from '../../../plotly/plot';
-import { NUMERICAL_FIELDS } from '../../../../../../common/constants/shared';
import { PLOTLY_GAUGE_COLUMN_NUMBER } from '../../../../../../common/constants/explorer';
+import { DefaultGaugeChartParameters } from '../../../../../../common/constants/explorer';
+import { ThresholdUnitType } from '../../../../event_analytics/explorer/visualizations/config_panel/config_panes/config_controls/config_thresholds';
+import { EmptyPlaceholder } from '../../../../event_analytics/explorer/visualizations/shared_components/empty_placeholder';
+
+const {
+ GaugeTitleSize,
+ DisplayDefaultGauges,
+ OrientationDefault,
+ TickLength,
+ LegendPlacement,
+} = DefaultGaugeChartParameters;
export const Gauge = ({ visualizations, layout, config }: any) => {
const {
@@ -16,41 +25,66 @@ export const Gauge = ({ visualizations, layout, config }: any) => {
metadata: { fields },
} = visualizations.data.rawVizData;
+ // data config parametrs
const { dataConfig = {}, layoutConfig = {} } = visualizations.data.userConfigs;
+ const dimensions = dataConfig?.valueOptions?.dimensions
+ ? dataConfig.valueOptions.dimensions.filter((item) => item.name !== '')
+ : [];
+ const metrics = dataConfig?.valueOptions?.metrics
+ ? dataConfig.valueOptions.metrics.filter((item) => item.name !== '')
+ : [];
+ const dimensionsLength = dimensions.length;
+ const metricsLength = metrics.length;
+ const numberOfGauges = dataConfig?.panelOptions?.numberOfGauges || DisplayDefaultGauges;
- const series =
- dataConfig?.valueOptions && dataConfig?.valueOptions?.series
- ? dataConfig.valueOptions.series
- : [];
+ // style parameters
+ const thresholds = dataConfig?.thresholds || [];
+ const titleSize = dataConfig?.chartStyles?.titleSize || GaugeTitleSize;
+ const valueSize = dataConfig?.chartStyles?.valueSize;
+ const showThresholdMarkers = dataConfig?.chartStyles?.showThresholdMarkers || false;
+ const showThresholdLabels = dataConfig?.chartStyles?.showThresholdLabels || false;
+ const orientation = dataConfig?.chartStyles?.orientation || OrientationDefault;
+ const legendPlacement = dataConfig?.chartStyles?.legendPlacement || LegendPlacement;
- const value =
- dataConfig?.valueOptions && dataConfig?.valueOptions?.value
- ? dataConfig.valueOptions.value
- : [];
+ const isEmptyPlot = !metricsLength;
- const thresholds = dataConfig?.thresholds || [];
+ if (isEmptyPlot) return ;
const gaugeData: Plotly.Data[] = useMemo(() => {
let calculatedGaugeData: Plotly.Data[] = [];
- if (series && series[0] && value && value[0]) {
- if (indexOf(NUMERICAL_FIELDS, series[0].type) > 0) {
- calculatedGaugeData = [
- ...data[value[0].name].map((dimesionSlice, index) => ({
- field_name: dimesionSlice,
- value: data[series[0].name][index],
- })),
- ];
- } else {
- value.map((val) => {
- const selectedSeriesIndex = indexOf(data[series[0].name], val.name);
- fields.map((field) => {
- if (field.name !== series[0].name) {
- calculatedGaugeData.push({
- field_name: field.name,
- value: data[field.name][selectedSeriesIndex],
- });
- }
+ if (dimensionsLength || metricsLength) {
+ // case 1,2: no dimension, single/multiple metrics
+ if (!dimensionsLength && metricsLength >= 1) {
+ calculatedGaugeData = metrics.map((metric: any) => {
+ return {
+ field_name: metric.name,
+ value: data[metric.name][0],
+ };
+ });
+ }
+
+ // case 3: multiple dimensions and multiple metrics
+ if (dimensionsLength && metricsLength) {
+ const selectedDimensionsData = dimensions
+ .map((dimension: any) => data[dimension.name].slice(0, numberOfGauges))
+ .reduce((prev, cur) => {
+ return prev.map((i, j) => `${i}, ${cur[j]}`);
});
+
+ const selectedMetricsData = metrics.map((metric: any) =>
+ data[metric.name].slice(0, numberOfGauges)
+ );
+
+ selectedMetricsData.map((metricSlice: any, metricSliceIndex: number) => {
+ calculatedGaugeData = [
+ ...calculatedGaugeData,
+ ...metricSlice.map((metricSliceData: any, metricSliceDataIndex: number) => {
+ return {
+ field_name: `${selectedDimensionsData[metricSliceDataIndex]}, ${metrics[metricSliceIndex].name}`,
+ value: metricSliceData,
+ };
+ }),
+ ];
});
}
@@ -61,40 +95,92 @@ export const Gauge = ({ visualizations, layout, config }: any) => {
value: gauge.value || 0,
title: {
text: gauge.field_name,
- font: { size: 14 },
+ font: { size: titleSize },
+ align: legendPlacement,
},
+ ...(valueSize && {
+ number: {
+ font: {
+ size: valueSize,
+ },
+ },
+ }),
domain: {
- row: Math.floor(index / PLOTLY_GAUGE_COLUMN_NUMBER),
- column: index % PLOTLY_GAUGE_COLUMN_NUMBER,
+ ...(orientation === 'auto' || orientation === 'h'
+ ? {
+ row: Math.floor(index / PLOTLY_GAUGE_COLUMN_NUMBER),
+ column: index % PLOTLY_GAUGE_COLUMN_NUMBER,
+ }
+ : {
+ column: Math.floor(index / PLOTLY_GAUGE_COLUMN_NUMBER),
+ row: index % PLOTLY_GAUGE_COLUMN_NUMBER,
+ }),
},
gauge: {
- ...(thresholds && {
- threshold: {
- line: { color: thresholds[0]?.color || 'red', width: 4 },
- thickness: 0.75,
- value: thresholds[0]?.value || 0,
- },
- }),
+ ...(showThresholdMarkers &&
+ thresholds &&
+ thresholds.length && {
+ threshold: {
+ line: { color: thresholds[0]?.color || 'red', width: 4 },
+ thickness: 0.75,
+ value: thresholds[0]?.value || 0,
+ },
+ }),
+ //threshold labels
+ ...(showThresholdLabels && thresholds && thresholds.length
+ ? {
+ axis: {
+ ticktext: [gauge.value, ...thresholds.map((t: ThresholdUnitType) => t.name)],
+ tickvals: [gauge.value, ...thresholds.map((t: ThresholdUnitType) => t.value)],
+ ticklen: TickLength,
+ },
+ }
+ : {}),
},
};
});
}
return calculatedGaugeData;
- }, [series, value, data, fields, thresholds]);
+ }, [
+ dimensions,
+ metrics,
+ data,
+ fields,
+ thresholds,
+ showThresholdMarkers,
+ orientation,
+ showThresholdLabels,
+ titleSize,
+ valueSize,
+ ]);
const mergedLayout = useMemo(() => {
const isAtleastOneFullRow = Math.floor(gaugeData.length / PLOTLY_GAUGE_COLUMN_NUMBER) > 0;
return {
grid: {
- rows: Math.floor(gaugeData.length / PLOTLY_GAUGE_COLUMN_NUMBER) + 1,
- columns: isAtleastOneFullRow ? PLOTLY_GAUGE_COLUMN_NUMBER : gaugeData.length,
+ ...(orientation === 'auto' || orientation === 'h'
+ ? {
+ rows: Math.floor(gaugeData.length / PLOTLY_GAUGE_COLUMN_NUMBER) + 1,
+ columns: isAtleastOneFullRow ? PLOTLY_GAUGE_COLUMN_NUMBER : gaugeData.length,
+ }
+ : {
+ columns: Math.floor(gaugeData.length / PLOTLY_GAUGE_COLUMN_NUMBER) + 1,
+ rows: isAtleastOneFullRow ? PLOTLY_GAUGE_COLUMN_NUMBER : gaugeData.length,
+ }),
pattern: 'independent',
},
...layout,
...(layoutConfig.layout && layoutConfig.layout),
title: dataConfig?.panelOptions?.title || layoutConfig.layout?.title || '',
};
- }, [layout, gaugeData.length, layoutConfig.layout, dataConfig?.panelOptions?.title]);
+ }, [
+ data,
+ layout,
+ gaugeData.length,
+ layoutConfig.layout,
+ dataConfig?.panelOptions?.title,
+ orientation,
+ ]);
const mergedConfigs = {
...config,
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 e5e91b7db..835e75e91 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
@@ -9,54 +9,102 @@ import { LensIconChartLine } from '../../../assets/chart_line';
import { VizDataPanel } from '../../../../event_analytics/explorer/visualizations/config_panel/config_panes/default_vis_editor';
import { ConfigEditor } from '../../../../event_analytics/explorer/visualizations/config_panel/config_panes/json_editor';
import {
- ConfigValueOptions,
ConfigThresholds,
- ConfigGaugeValueOptions,
+ InputFieldItem,
+ SwitchButton,
+ ConfigChartOptions,
+ ButtonGroupItem,
} from '../../../../event_analytics/explorer/visualizations/config_panel/config_panes/config_controls';
+import { DefaultGaugeChartParameters } from '../../../../../../common/constants/explorer';
const sharedConfigs = getPlotlySharedConfigs();
const VIS_CATEGORY = getPlotlyCategory();
+const { ThresholdsMaxLimit } = DefaultGaugeChartParameters;
export const createGaugeTypeDefinition = (params: any = {}) => ({
name: 'Gauge',
type: 'indicator',
id: 'gauge',
label: 'Gauge',
- fullLabel: 'Gauge',
- iconType: 'visGauge',
+ fulllabel: 'Gauge',
+ icontype: 'visGauge',
category: VIS_CATEGORY.BASICS,
selection: {
dataLoss: 'nothing',
},
icon: LensIconChartLine,
- valueSeries: 'yaxis',
- editorConfig: {
+ valueseries: 'yaxis',
+ editorconfig: {
panelTabs: [
{
id: 'data-panel',
- name: 'Data',
+ name: 'Style',
mapTo: 'dataConfig',
editor: VizDataPanel,
sections: [
{
- id: 'value_options',
- name: 'Value options',
- editor: ConfigGaugeValueOptions,
- mapTo: 'valueOptions',
+ id: 'chart-styles',
+ name: 'Chart styles',
+ editor: ConfigChartOptions,
+ mapTo: 'chartStyles',
schemas: [
{
- name: 'Series',
- isSingleSelection: true,
- onChangeHandler: 'setXaxisSelections',
- component: null,
- mapTo: 'series',
+ name: 'Orientation',
+ component: ButtonGroupItem,
+ mapTo: 'orientation',
+ eleType: 'buttons',
+ props: {
+ options: [
+ { name: 'Auto', id: 'auto' },
+ { name: 'Vertical', id: 'v' },
+ { name: 'Horizontal', id: 'h' },
+ ],
+ defaultSelections: [{ name: 'Auto', id: 'auto' }],
+ },
},
{
- name: 'Value',
- isSingleSelection: false,
- onChangeHandler: 'setYaxisSelections',
- component: null,
- mapTo: 'value',
+ name: 'Legend placement',
+ component: ButtonGroupItem,
+ mapTo: 'legendPlacement',
+ eleType: 'buttons',
+ props: {
+ options: [
+ { name: 'Center', id: 'center' },
+ { name: 'Right', id: 'right' },
+ { name: 'Left', id: 'left' },
+ ],
+ defaultSelections: [{ name: 'Center', id: 'center' }],
+ },
+ },
+ {
+ title: 'Title size',
+ name: 'Title size',
+ component: InputFieldItem,
+ mapTo: 'titleSize',
+ eleType: 'input',
+ },
+ {
+ title: 'Value size',
+ name: 'Value size',
+ component: InputFieldItem,
+ mapTo: 'valueSize',
+ eleType: 'input',
+ },
+ {
+ title: 'Show threshold labels',
+ name: 'Show threshold labels',
+ component: SwitchButton,
+ mapTo: 'showThresholdLabels',
+ eleType: 'switchButton',
+ currentValue: false,
+ },
+ {
+ title: 'Show threshold markers',
+ name: 'Show threshold markers',
+ component: SwitchButton,
+ mapTo: 'showThresholdMarkers',
+ eleType: 'switchButton',
+ currentValue: true,
},
],
},
@@ -67,6 +115,9 @@ export const createGaugeTypeDefinition = (params: any = {}) => ({
mapTo: 'thresholds',
defaultState: [],
schemas: [],
+ props: {
+ maxLimit: ThresholdsMaxLimit,
+ },
},
],
},
@@ -79,7 +130,7 @@ export const createGaugeTypeDefinition = (params: any = {}) => ({
},
],
},
- visConfig: {
+ visconfig: {
layout: {
...sharedConfigs.layout,
},
diff --git a/dashboards-observability/public/components/visualizations/charts/helpers/viz_types.ts b/dashboards-observability/public/components/visualizations/charts/helpers/viz_types.ts
index 4b7eb2332..cd79672eb 100644
--- a/dashboards-observability/public/components/visualizations/charts/helpers/viz_types.ts
+++ b/dashboards-observability/public/components/visualizations/charts/helpers/viz_types.ts
@@ -5,7 +5,13 @@
import { isEmpty, take } from 'lodash';
import { getVisType } from '../vis_types';
-import { IVisualizationContainerProps, IField, IQuery } from '../../../../../common/types/explorer';
+import {
+ IVisualizationContainerProps,
+ IField,
+ IQuery,
+ ExplorerData,
+} from '../../../../../common/types/explorer';
+import { visChartTypes } from '../../../../../common/constants/shared';
interface IVizContainerProps {
vizId: string;
@@ -18,14 +24,123 @@ interface IVizContainerProps {
xaxis: IField[];
yaxis: IField[];
};
+ explorer?: ExplorerData;
}
-const getDefaultXYAxisLabels = (vizFields: string[]) => {
+const initialConfigEntry = {
+ label: '',
+ aggregation: '',
+ custom_label: '',
+ name: '',
+ side: 'right',
+ type: '',
+};
+
+const initialEntryTreemap = { label: '', name: '' };
+
+const getDefaultXYAxisLabels = (vizFields: IField[], visName: string) => {
if (isEmpty(vizFields)) return {};
- return {
- xaxis: [vizFields[vizFields.length - 1]] || [],
- yaxis: take(vizFields, vizFields.length - 1 > 0 ? vizFields.length - 1 : 1) || [],
+ const vizFieldsWithLabel: { [key: string]: string }[] = vizFields.map((vizField) => ({
+ ...vizField,
+ label: vizField.name,
+ }));
+
+ const mapXaxis = (): { [key: string]: string }[] => {
+ const xaxis = vizFieldsWithLabel.filter((field) => field.type === 'timestamp');
+ return visName === visChartTypes.Line
+ ? xaxis.length === 0
+ ? [initialConfigEntry]
+ : xaxis
+ : [vizFieldsWithLabel[vizFieldsWithLabel.length - 1]];
};
+
+ const mapYaxis = (): { [key: string]: string }[] =>
+ visName === visChartTypes.Line
+ ? vizFieldsWithLabel.filter((field) => field.type !== 'timestamp')
+ : take(
+ vizFieldsWithLabel,
+ vizFieldsWithLabel.length - 1 > 0 ? vizFieldsWithLabel.length - 1 : 1
+ ) || [];
+
+ return { xaxis: mapXaxis(), yaxis: mapYaxis() };
+};
+
+const getUserConfigs = (userSelectedConfigs: object, vizFields: IField[], visName: string) => {
+ let configOfUser = userSelectedConfigs;
+ const axesData = getDefaultXYAxisLabels(vizFields, visName);
+ if (!userSelectedConfigs.dataConfig?.valueOptions) {
+ switch (visName) {
+ case visChartTypes.HeatMap:
+ configOfUser = {
+ ...userSelectedConfigs,
+ dataConfig: {
+ ...userSelectedConfigs?.dataConfig,
+ valueOptions: {
+ dimensions: [initialConfigEntry, initialConfigEntry],
+ metrics: [initialConfigEntry],
+ },
+ },
+ };
+ break;
+ case visChartTypes.TreeMap:
+ configOfUser = {
+ ...userSelectedConfigs,
+ dataConfig: {
+ ...userSelectedConfigs?.dataConfig,
+ valueOptions: {
+ dimensions: [
+ {
+ childField: { ...(axesData.xaxis ? axesData.xaxis[0] : initialEntryTreemap) },
+ parentFields: [],
+ },
+ ],
+ metrics: [
+ { valueField: { ...(axesData.yaxis ? axesData.yaxis[0] : initialEntryTreemap) } },
+ ],
+ },
+ },
+ };
+ break;
+ case visChartTypes.Histogram:
+ configOfUser = {
+ ...userSelectedConfigs,
+ dataConfig: {
+ ...userSelectedConfigs?.dataConfig,
+ valueOptions: {
+ dimensions: [{ bucketSize: '', bucketOffset: '' }],
+ metrics: [],
+ },
+ },
+ };
+ break;
+ case visChartTypes.LogsView:
+ configOfUser = {
+ ...userSelectedConfigs,
+ dataConfig: {
+ ...userSelectedConfigs?.dataConfig,
+ valueOptions: {
+ dimensions:
+ axesData.xaxis && axesData.yaxis ? axesData.xaxis.concat(axesData.yaxis) : [],
+ metrics: [],
+ },
+ },
+ };
+ break;
+ default:
+ configOfUser = {
+ ...userSelectedConfigs,
+ dataConfig: {
+ ...userSelectedConfigs?.dataConfig,
+ valueOptions: {
+ metrics: axesData.yaxis ?? [],
+ dimensions: axesData.xaxis ?? [],
+ },
+ },
+ };
+ break;
+ }
+ }
+ return isEmpty(configOfUser) ? userSelectedConfigs : configOfUser;
};
export const getVizContainerProps = ({
@@ -35,20 +150,29 @@ export const getVizContainerProps = ({
indexFields = {},
userConfigs = {},
appData = {},
+ explorer = { explorerData: { jsonData: [], jsonDataAll: [] } },
}: IVizContainerProps): IVisualizationContainerProps => {
+ const getVisTypeData = () =>
+ vizId === visChartTypes.Line || vizId === visChartTypes.Scatter
+ ? { ...getVisType(vizId, { type: vizId }) }
+ : { ...getVisType(vizId) };
+
return {
data: {
appData: { ...appData },
rawVizData: { ...rawVizData },
query: { ...query },
indexFields: { ...indexFields },
- userConfigs: { ...userConfigs },
+ userConfigs: {
+ ...getUserConfigs(userConfigs, rawVizData?.metadata?.fields, getVisTypeData().name),
+ },
defaultAxes: {
- ...getDefaultXYAxisLabels(rawVizData?.metadata?.fields),
+ ...getDefaultXYAxisLabels(rawVizData?.metadata?.fields, getVisTypeData().name),
},
+ explorer: { ...explorer },
},
vis: {
- ...getVisType(vizId),
+ ...getVisTypeData(),
},
};
};
diff --git a/dashboards-observability/public/components/visualizations/charts/histogram/histogram.tsx b/dashboards-observability/public/components/visualizations/charts/histogram/histogram.tsx
index 28c9adb96..08a1930ee 100644
--- a/dashboards-observability/public/components/visualizations/charts/histogram/histogram.tsx
+++ b/dashboards-observability/public/components/visualizations/charts/histogram/histogram.tsx
@@ -3,40 +3,98 @@
* SPDX-License-Identifier: Apache-2.0
*/
-import React from 'react';
-import { take, merge, isEmpty } from 'lodash';
+import React, { useMemo } from 'react';
+import { take, isEmpty, last } from 'lodash';
import { Plt } from '../../plotly/plot';
-import { PLOTLY_COLOR } from '../../../../../common/constants/shared';
+import {
+ DefaultChartStyles,
+ PLOTLY_COLOR,
+ FILLOPACITY_DIV_FACTOR,
+ visChartTypes,
+} from '../../../../../common/constants/shared';
+import { hexToRgb } from '../../../../components/event_analytics/utils/utils';
export const Histogram = ({ visualizations, layout, config }: any) => {
- const { vis } = visualizations;
+ const { LineWidth, FillOpacity, LegendPosition, ShowLegend } = DefaultChartStyles;
const {
data = {},
metadata: { fields },
} = visualizations.data.rawVizData;
- const { defaultAxes } = visualizations.data.defaultAxes;
- const { xaxis = null, yaxis = null } = visualizations.data.userConfigs;
+ const { defaultAxes } = visualizations?.data;
+ const { dataConfig = {}, layoutConfig = {} } = visualizations?.data?.userConfigs;
const lastIndex = fields.length - 1;
+ const lineWidth = dataConfig?.chartStyles?.lineWidth || LineWidth;
+ const showLegend =
+ dataConfig?.legend?.showLegend && dataConfig.legend.showLegend !== ShowLegend ? false : true;
+ const legendPosition = dataConfig?.legend?.position || LegendPosition;
+ const fillOpacity =
+ (dataConfig?.chartStyles?.fillOpacity || FillOpacity) / FILLOPACITY_DIV_FACTOR;
+ const tooltipMode =
+ dataConfig?.tooltipOptions?.tooltipMode !== undefined
+ ? dataConfig.tooltipOptions.tooltipMode
+ : 'show';
+ const tooltipText =
+ dataConfig?.tooltipOptions?.tooltipText !== undefined
+ ? dataConfig.tooltipOptions.tooltipText
+ : 'all';
+ const valueSeries = defaultAxes?.yaxis || take(fields, lastIndex > 0 ? lastIndex : 1);
- let valueSeries;
- if (!isEmpty(xaxis) && !isEmpty(yaxis)) {
- valueSeries = [
- ...visualizations?.data?.userConfigs[vis.seriesAxis].map((item) => ({
- ...item,
- name: item.label,
- })),
- ];
- } else {
- valueSeries = defaultAxes?.yaxis || take(fields, lastIndex > 0 ? lastIndex : 1);
+ const xbins: any = {};
+ if (dataConfig?.valueOptions?.dimensions[0].bucketSize) {
+ xbins.size = dataConfig.valueOptions.dimensions[0].bucketSize;
+ }
+ if (dataConfig?.valueOptions?.dimensions[0].bucketOffset) {
+ xbins.start = dataConfig.valueOptions.dimensions[0].bucketOffset;
}
- const hisValues = valueSeries.map((field: any) => {
- return {
- x: data[xaxis ? xaxis[0]?.label : fields[lastIndex].name],
- type: 'histogram',
- name: field.name,
- };
- });
+ const selectedColorTheme = (field: any, index: number, opacity?: number) => {
+ let newColor;
+ if (dataConfig?.colorTheme && dataConfig?.colorTheme.length !== 0) {
+ newColor = dataConfig.colorTheme.find(
+ (colorSelected) => colorSelected.name.name === field.name
+ );
+ }
+ return hexToRgb(newColor ? newColor.color : PLOTLY_COLOR[index % PLOTLY_COLOR.length], opacity);
+ };
+
+ const hisValues = useMemo(
+ () =>
+ valueSeries.map((field: any, index: number) => ({
+ x: data[field.name],
+ type: visChartTypes.Histogram,
+ name: field.name,
+ hoverinfo: tooltipMode === 'hidden' ? 'none' : tooltipText,
+ marker: {
+ color: selectedColorTheme(field, index, fillOpacity),
+ line: {
+ color: selectedColorTheme(field, index),
+ width: lineWidth,
+ },
+ },
+ xbins: !isEmpty(xbins) ? xbins : undefined,
+ })),
+ [valueSeries, data, fillOpacity, lineWidth, xbins, selectedColorTheme]
+ );
+
+ const mergedLayout = {
+ ...layout,
+ ...(layoutConfig.layout && layoutConfig.layout),
+ title: dataConfig?.panelOptions?.title || layoutConfig.layout?.title || '',
+ barmode: 'group',
+ legend: {
+ ...layout.legend,
+ orientation: legendPosition,
+ },
+ showlegend: showLegend,
+ };
+
+ const mergedConfigs = useMemo(
+ () => ({
+ ...config,
+ ...(layoutConfig.config && layoutConfig.config),
+ }),
+ [config, layoutConfig.config]
+ );
- return ;
+ return ;
};
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 3e6e0d967..de9dcf0bc 100644
--- a/dashboards-observability/public/components/visualizations/charts/histogram/histogram_type.ts
+++ b/dashboards-observability/public/components/visualizations/charts/histogram/histogram_type.ts
@@ -5,51 +5,113 @@
import { Histogram } from './histogram';
import { getPlotlySharedConfigs, getPlotlyCategory } from '../shared/shared_configs';
-import { LensIconChartLine } from '../../assets/chart_line';
import { VizDataPanel } from '../../../event_analytics/explorer/visualizations/config_panel/config_panes/default_vis_editor';
import { ConfigEditor } from '../../../event_analytics/explorer/visualizations/config_panel/config_panes/json_editor';
-import { ConfigValueOptions } from '../../../event_analytics/explorer/visualizations/config_panel/config_panes/config_controls';
+import {
+ ConfigChartOptions,
+ ConfigLegend,
+ SliderConfig,
+ ConfigColorTheme,
+} from '../../../event_analytics/explorer/visualizations/config_panel/config_panes/config_controls';
+import { DefaultChartStyles } from '../../../../../common/constants/shared';
+import { fetchConfigObject } from '../../../../components/event_analytics/utils/utils';
const sharedConfigs = getPlotlySharedConfigs();
const VIS_CATEGORY = getPlotlyCategory();
+const { LineWidth, FillOpacity, ShowLegend, LegendPosition } = DefaultChartStyles;
export const createHistogramVisDefinition = (params = {}) => ({
name: 'histogram',
type: 'histogram',
id: 'histogram',
label: 'Histogram',
- fullLabel: 'Histogram',
+ fulllabel: 'Histogram',
category: VIS_CATEGORY.BASICS,
selection: {
dataLoss: 'nothing',
},
- valueSeries: 'yaxis',
- icon: LensIconChartLine,
- editorConfig: {
+ valueseries: 'yaxis',
+ icontype: 'visArea',
+ editorconfig: {
panelTabs: [
{
id: 'data-panel',
- name: 'Data',
+ name: 'Style',
mapTo: 'dataConfig',
editor: VizDataPanel,
sections: [
{
- id: 'value_options',
- name: 'Value options',
- editor: ConfigValueOptions,
- mapTo: 'valueOptions',
+ id: 'chart-styles',
+ name: 'Chart styles',
+ editor: ConfigChartOptions,
+ mapTo: 'chartStyles',
schemas: [
{
- name: 'X-axis',
- isSingleSelection: true,
+ name: 'Line width',
+ component: SliderConfig,
+ mapTo: 'lineWidth',
+ defaultState: LineWidth,
+ eleType: 'slider',
+ props: {
+ max: 10,
+ },
+ },
+ {
+ name: 'Fill opacity',
+ component: SliderConfig,
+ mapTo: 'fillOpacity',
+ defaultState: FillOpacity,
+ eleType: 'slider',
+ props: {
+ max: 100,
+ },
+ },
+ ],
+ },
+ {
+ id: 'color-theme',
+ name: 'Color theme',
+ editor: ConfigColorTheme,
+ mapTo: 'colorTheme',
+ schemas: [],
+ },
+ fetchConfigObject('Tooltip', {
+ options: [
+ { name: 'All', id: 'all' },
+ { name: 'Dimension', id: 'x' },
+ { name: 'Metrics', id: 'y' },
+ ],
+ defaultSelections: [{ name: 'All', id: 'all' }],
+ }),
+ {
+ id: 'legend',
+ name: 'Legend',
+ editor: ConfigLegend,
+ mapTo: 'legend',
+ schemas: [
+ {
+ name: 'Show legend',
+ mapTo: 'showLegend',
component: null,
- mapTo: 'xaxis',
+ props: {
+ options: [
+ { name: 'Show', id: 'show' },
+ { name: 'Hidden', id: 'hidden' },
+ ],
+ defaultSelections: [{ name: 'Show', id: ShowLegend }],
+ },
},
{
- name: 'Y-axis',
- isSingleSelection: false,
+ name: 'Position',
+ mapTo: 'position',
component: null,
- mapTo: 'yaxis',
+ props: {
+ options: [
+ { name: 'Right', id: 'v' },
+ { name: 'Bottom', id: 'h' },
+ ],
+ defaultSelections: [{ name: 'Right', id: LegendPosition }],
+ },
},
],
},
@@ -64,7 +126,7 @@ export const createHistogramVisDefinition = (params = {}) => ({
},
],
},
- visConfig: {
+ visconfig: {
layout: {
...sharedConfigs.layout,
},
diff --git a/dashboards-observability/public/components/visualizations/charts/lines/line.tsx b/dashboards-observability/public/components/visualizations/charts/lines/line.tsx
index 4ce620efd..80c22b8e8 100644
--- a/dashboards-observability/public/components/visualizations/charts/lines/line.tsx
+++ b/dashboards-observability/public/components/visualizations/charts/lines/line.tsx
@@ -8,8 +8,27 @@ import { take, isEmpty, last } from 'lodash';
import { Plt } from '../../plotly/plot';
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 {
+ DefaultChartStyles,
+ FILLOPACITY_DIV_FACTOR,
+ PLOTLY_COLOR,
+ visChartTypes,
+} from '../../../../../common/constants/shared';
+import { hexToRgb } from '../../../../components/event_analytics/utils/utils';
+import { EmptyPlaceholder } from '../../../event_analytics/explorer/visualizations/shared_components/empty_placeholder';
export const Line = ({ visualizations, layout, config }: any) => {
+ const {
+ DefaultModeLine,
+ Interpolation,
+ LineWidth,
+ FillOpacity,
+ MarkerSize,
+ LegendPosition,
+ ShowLegend,
+ DefaultModeScatter,
+ LabelAngle,
+ } = DefaultChartStyles;
const {
data = {},
metadata: { fields },
@@ -20,38 +39,149 @@ export const Line = ({ visualizations, layout, config }: any) => {
layoutConfig = {},
availabilityConfig = {},
} = visualizations?.data?.userConfigs;
- const xaxis =
- dataConfig?.valueOptions && dataConfig.valueOptions.xaxis ? dataConfig.valueOptions.xaxis : [];
- const yaxis =
- dataConfig?.valueOptions && dataConfig.valueOptions.xaxis ? dataConfig.valueOptions.yaxis : [];
+
+ const xaxis = dataConfig?.valueOptions?.dimensions
+ ? dataConfig.valueOptions.dimensions.filter((item) => item.label)
+ : [];
+ const yaxis = dataConfig?.valueOptions?.metrics
+ ? dataConfig.valueOptions.metrics.filter((item) => item.label)
+ : [];
+ const tooltipMode =
+ dataConfig?.tooltipOptions?.tooltipMode !== undefined
+ ? dataConfig.tooltipOptions.tooltipMode
+ : 'show';
+ const tooltipText =
+ dataConfig?.tooltipOptions?.tooltipText !== undefined
+ ? dataConfig.tooltipOptions.tooltipText
+ : 'all';
+
const lastIndex = fields.length - 1;
+
+ let visType: string = visualizations.vis.name;
const mode =
- dataConfig?.chartOptions && dataConfig.chartOptions.mode && dataConfig.chartOptions.mode[0]
- ? dataConfig.chartOptions.mode[0].modeId
- : 'line';
+ dataConfig?.chartStyles?.style ||
+ (visType === visChartTypes.Line ? DefaultModeLine : DefaultModeScatter);
+ const lineShape = dataConfig?.chartStyles?.interpolation || Interpolation;
+ const lineWidth = dataConfig?.chartStyles?.lineWidth || LineWidth;
+ const showLegend = !(
+ dataConfig?.legend?.showLegend && dataConfig.legend.showLegend !== ShowLegend
+ );
+ const legendPosition = dataConfig?.legend?.position || LegendPosition;
+ const markerSize = dataConfig?.chartStyles?.pointSize || MarkerSize;
+ const fillOpacity =
+ dataConfig?.chartStyles?.fillOpacity !== undefined
+ ? dataConfig?.chartStyles?.fillOpacity / FILLOPACITY_DIV_FACTOR
+ : FillOpacity / FILLOPACITY_DIV_FACTOR;
+ const tickAngle = dataConfig?.chartStyles?.rotateLabels || LabelAngle;
+ const labelSize = dataConfig?.chartStyles?.labelSize;
+ const legendSize = dataConfig?.legend?.legendSize;
+
+ const getSelectedColorTheme = (field: any, index: number) =>
+ (dataConfig?.colorTheme?.length > 0 &&
+ dataConfig.colorTheme.find((colorSelected) => colorSelected.name.name === field.name)
+ ?.color) ||
+ PLOTLY_COLOR[index % PLOTLY_COLOR.length];
+
+ if (isEmpty(xaxis) || isEmpty(yaxis))
+ return ;
let valueSeries;
if (!isEmpty(xaxis) && !isEmpty(yaxis)) {
valueSeries = [...yaxis];
} else {
- valueSeries = defaultAxes.yaxis || take(fields, lastIndex > 0 ? lastIndex : 1);
+ valueSeries = (
+ defaultAxes.yaxis || take(fields, lastIndex > 0 ? lastIndex : 1)
+ ).map((item, i) => ({ ...item, side: i === 0 ? 'left' : 'right' }));
}
+ const isDimensionTimestamp = isEmpty(xaxis)
+ ? defaultAxes?.xaxis?.length && defaultAxes.xaxis[0].type === 'timestamp'
+ : xaxis.length === 1 && xaxis[0].type === 'timestamp';
+
+ let multiMetrics = {};
const [calculatedLayout, lineValues] = useMemo(() => {
- let calculatedLineValues = valueSeries.map((field: any) => {
+ const isBarMode = mode === 'bar';
+ let calculatedLineValues = valueSeries.map((field: any, index: number) => {
+ const selectedColor = getSelectedColorTheme(field, index);
+ const fillColor = hexToRgb(selectedColor, fillOpacity);
+ const barMarker = {
+ color: fillColor,
+ line: {
+ color: selectedColor,
+ width: lineWidth,
+ },
+ };
+ const fillProperty = {
+ fill: 'tozeroy',
+ fillcolor: fillColor,
+ };
+ const multiYaxis = { yaxis: `y${index + 1}` };
+ multiMetrics = {
+ ...multiMetrics,
+ [`yaxis${index > 0 ? index + 1 : ''}`]: {
+ titlefont: {
+ color: selectedColor,
+ },
+ tickfont: {
+ color: selectedColor,
+ ...(labelSize && {
+ size: labelSize,
+ }),
+ },
+ overlaying: 'y',
+ side: field.side,
+ },
+ };
+
return {
x: data[!isEmpty(xaxis) ? xaxis[0]?.label : fields[lastIndex].name],
- y: data[field.name],
- type: 'line',
- name: field.name,
+ y: data[field.label],
+ type: isBarMode ? 'bar' : 'scatter',
+ name: field.label,
mode,
+ ...(!['bar', 'markers'].includes(mode) && fillProperty),
+ line: {
+ shape: lineShape,
+ width: lineWidth,
+ color: selectedColor,
+ },
+ hoverinfo: tooltipMode === 'hidden' ? 'none' : tooltipText,
+ marker: {
+ size: markerSize,
+ ...(isBarMode && barMarker),
+ },
+ ...(index >= 1 && multiYaxis),
};
});
+ let layoutForBarMode = {
+ barmode: 'group',
+ };
const mergedLayout = {
...layout,
...layoutConfig.layout,
title: dataConfig?.panelOptions?.title || layoutConfig.layout?.title || '',
+ legend: {
+ ...layout.legend,
+ orientation: legendPosition,
+ ...(legendSize && {
+ font: {
+ size: legendSize,
+ },
+ }),
+ },
+ xaxis: {
+ tickangle: tickAngle,
+ automargin: true,
+ tickfont: {
+ ...(labelSize && {
+ size: labelSize,
+ }),
+ },
+ },
+ showlegend: showLegend,
+ ...(isBarMode && layoutForBarMode),
+ ...(multiMetrics && multiMetrics),
};
if (dataConfig.thresholds || availabilityConfig.level) {
@@ -97,10 +227,17 @@ export const Line = ({ visualizations, layout, config }: any) => {
return [mergedLayout, calculatedLineValues];
}, [data, fields, lastIndex, layout, layoutConfig, xaxis, yaxis, mode, valueSeries]);
- const mergedConfigs = {
- ...config,
- ...(layoutConfig.config && layoutConfig.config),
- };
+ const mergedConfigs = useMemo(
+ () => ({
+ ...config,
+ ...(layoutConfig.config && layoutConfig.config),
+ }),
+ [config, layoutConfig.config]
+ );
- return ;
+ return isDimensionTimestamp ? (
+
+ ) : (
+
+ );
};
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 20e452388..4956075d6 100644
--- a/dashboards-observability/public/components/visualizations/charts/lines/line_type.ts
+++ b/dashboards-observability/public/components/visualizations/charts/lines/line_type.ts
@@ -6,82 +6,211 @@
import { Line } from './line';
import { getPlotlySharedConfigs, getPlotlyCategory } from '../shared/shared_configs';
import { LensIconChartLine } from '../../assets/chart_line';
-import { PLOTLY_COLOR } from '../../../../../common/constants/shared';
import { VizDataPanel } from '../../../event_analytics/explorer/visualizations/config_panel/config_panes/default_vis_editor';
import { ConfigEditor } from '../../../event_analytics/explorer/visualizations/config_panel/config_panes/json_editor';
import {
- ConfigValueOptions,
ConfigThresholds,
+ ConfigLineChartStyles,
+ ConfigLegend,
+ InputFieldItem,
+ ConfigColorTheme,
} from '../../../event_analytics/explorer/visualizations/config_panel/config_panes/config_controls';
import { ConfigAvailability } from '../../../event_analytics/explorer/visualizations/config_panel/config_panes/config_controls/config_availability';
-
+import {
+ DefaultChartStyles,
+ visChartTypes,
+ PLOTLY_COLOR,
+} from '../../../../../common/constants/shared';
+import { ButtonGroupItem } from '../../../../../public/components/event_analytics/explorer/visualizations/config_panel/config_panes/config_controls/config_button_group';
+import { SliderConfig } from '../../../../../public/components/event_analytics/explorer/visualizations/config_panel/config_panes/config_controls/config_style_slider';
+import { fetchConfigObject } from '../../../../components/event_analytics/utils/utils';
const sharedConfigs = getPlotlySharedConfigs();
const VIS_CATEGORY = getPlotlyCategory();
+const {
+ DefaultModeLine,
+ DefaultModeScatter,
+ Interpolation,
+ LineWidth,
+ FillOpacity,
+ MarkerSize,
+ LegendPosition,
+ ShowLegend,
+ LabelAngle,
+} = DefaultChartStyles;
export const createLineTypeDefinition = (params: any = {}) => ({
- name: 'line',
- type: 'line',
- id: 'line',
- label: 'Line',
- fullLabel: 'Line',
- iconType: 'visLine',
+ name: params.type,
+ type: params.type,
+ id: params.type,
+ label: params.type === visChartTypes.Line ? 'Time series' : 'Scatter',
+ fulllabel: params.type === visChartTypes.Line ? 'Time series' : 'Scatter',
+ icontype: 'visLine',
category: VIS_CATEGORY.BASICS,
selection: {
dataLoss: 'nothing',
},
icon: LensIconChartLine,
- categoryAxis: 'xaxis',
- seriesAxis: 'yaxis',
- editorConfig: {
+ categoryaxis: 'xaxis',
+ seriesaxis: 'yaxis',
+ editorconfig: {
panelTabs: [
{
id: 'data-panel',
- name: 'Data',
+ name: 'Style',
mapTo: 'dataConfig',
editor: VizDataPanel,
sections: [
{
- id: 'value_options',
- name: 'Value options',
- editor: ConfigValueOptions,
- mapTo: 'valueOptions',
+ id: 'legend',
+ name: 'Legend',
+ editor: ConfigLegend,
+ mapTo: 'legend',
schemas: [
{
- name: 'X-axis',
- isSingleSelection: true,
+ name: 'Show legend',
+ mapTo: 'showLegend',
component: null,
- mapTo: 'xaxis',
+ props: {
+ options: [
+ { name: 'Show', id: 'show' },
+ { name: 'Hidden', id: 'hidden' },
+ ],
+ defaultSelections: [{ name: 'Show', id: ShowLegend }],
+ },
},
{
- name: 'Y-axis',
- isSingleSelection: false,
+ name: 'Position',
+ mapTo: 'position',
component: null,
- mapTo: 'yaxis',
+ props: {
+ options: [
+ { name: 'Right', id: 'v' },
+ { name: 'Bottom', id: 'h' },
+ ],
+ defaultSelections: [{ name: 'Right', id: LegendPosition }],
+ },
+ },
+ {
+ title: 'Legend size',
+ name: 'Legend size',
+ component: InputFieldItem,
+ mapTo: 'legendSize',
+ eleType: 'input',
},
],
},
+ fetchConfigObject('Tooltip', {
+ options: [
+ { name: 'All', id: 'all' },
+ { name: 'Dimension', id: 'x' },
+ { name: 'Metrics', id: 'y' },
+ ],
+ defaultSelections: [{ name: 'All', id: 'all' }],
+ }),
{
- id: 'chart_options',
- name: 'Chart options',
- editor: ConfigValueOptions,
- mapTo: 'chartOptions',
+ id: 'chart_styles',
+ name: 'Chart styles',
+ editor: ConfigLineChartStyles,
+ mapTo: 'chartStyles',
schemas: [
{
name: 'Mode',
- isSingleSelection: true,
- component: null,
- mapTo: 'mode',
+ component: ButtonGroupItem,
+ mapTo: 'style',
+ eleType: 'buttons',
+ props: {
+ options: [
+ { name: 'Lines', id: 'lines' },
+ { name: 'Marker', id: 'markers' },
+ { name: 'Lines + Markers', id: 'lines+markers' },
+ ],
+ defaultSelections: [
+ params.type === visChartTypes.Line
+ ? { name: 'Lines', id: DefaultModeLine }
+ : { name: 'Marker', id: DefaultModeScatter },
+ ],
+ },
+ },
+ {
+ name: 'Interpolation',
+ component: ButtonGroupItem,
+ mapTo: 'interpolation',
+ eleType: 'buttons',
+ props: {
+ options: [
+ { name: 'Linear', id: 'linear' },
+ { name: 'Smooth', id: 'spline' },
+ { name: 'Step before', id: 'hv' },
+ { name: 'Step after', id: 'vh' },
+ ],
+ defaultSelections: [{ name: 'Smooth', id: Interpolation }],
+ },
+ },
+ {
+ name: 'Line width',
+ component: SliderConfig,
+ mapTo: 'lineWidth',
+ defaultState: LineWidth,
+ eleType: 'slider',
+ props: {
+ max: 10,
+ },
+ },
+ {
+ name: 'Fill opacity',
+ component: SliderConfig,
+ mapTo: 'fillOpacity',
+ defaultState: FillOpacity,
+ eleType: 'slider',
+ props: {
+ max: 100,
+ },
+ },
+ {
+ name: 'Point size',
+ component: SliderConfig,
+ mapTo: 'pointSize',
+ defaultState: MarkerSize,
+ eleType: 'slider',
+ props: {
+ max: 40,
+ },
+ },
+ {
+ title: 'Label size',
+ name: 'Label size',
+ component: InputFieldItem,
+ mapTo: 'labelSize',
+ eleType: 'input',
+ },
+ {
+ name: 'Rotate labels',
+ component: SliderConfig,
+ mapTo: 'rotateLabels',
+ eleType: 'slider',
+ defaultState: LabelAngle,
props: {
- dropdownList: [
- { name: 'Markers', modeId: 'markers' },
- { name: 'Lines', modeId: 'lines' },
- { name: 'Lines + Markers', modeId: 'lines+markers' },
+ ticks: [
+ { label: '-90°', value: -90 },
+ { label: '-45°', value: -45 },
+ { label: '0°', value: 0 },
+ { label: '45°', value: 45 },
+ { label: '90°', value: 90 },
],
- defaultSelections: [{ name: 'Lines', modeId: 'lines' }],
+ showTicks: true,
+ min: -90,
+ max: 90,
},
},
],
},
+ {
+ id: 'color-theme',
+ name: 'Color theme',
+ editor: ConfigColorTheme,
+ mapTo: 'colorTheme',
+ schemas: [],
+ },
{
id: 'thresholds',
name: 'Thresholds',
@@ -107,7 +236,7 @@ export const createLineTypeDefinition = (params: any = {}) => ({
},
],
},
- visConfig: {
+ visconfig: {
layout: {
...sharedConfigs.layout,
...{
@@ -129,7 +258,7 @@ export const createLineTypeDefinition = (params: any = {}) => ({
config: {
...sharedConfigs.config,
...{
- barmode: 'line',
+ barmode: params.type,
xaxis: {
automargin: true,
},
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..ae3ebebfb
--- /dev/null
+++ b/dashboards-observability/public/components/visualizations/charts/logs_view/logs_view.scss
@@ -0,0 +1,25 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+table {
+ border-collapse: collapse;
+ width: 100%;
+}
+
+th,
+td {
+ text-align: left;
+}
+
+th {
+ width: 30%;
+}
+
+tr:hover {
+ background-color: #ddd;
+}
+
+.logs-view-container {
+ font-size: 16px;
+}
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..13a6516b4
--- /dev/null
+++ b/dashboards-observability/public/components/visualizations/charts/logs_view/logs_view.tsx
@@ -0,0 +1,40 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+import { IExplorerFields } from '../../../../../common/types/explorer';
+import React from 'react';
+import { RAW_QUERY, SELECTED_TIMESTAMP } from '../../../../../common/constants/explorer';
+import { DataGrid } from '../../../../components/event_analytics/explorer/events_views/data_grid';
+import './logs_view.scss';
+
+export const LogsView = ({ visualizations }: any) => {
+ const explorer = visualizations?.data?.explorer;
+
+ const http = explorer?.http;
+ const pplService = explorer?.pplService;
+ const explorerData = explorer?.explorerData;
+ const explorerFields = explorer?.explorerFields;
+ const query = explorer?.query;
+
+ const emptyExplorerFields: IExplorerFields = {
+ availableFields: [],
+ queriedFields: explorerFields,
+ selectedFields: [],
+ unselectedFields: [],
+ };
+
+ return (
+
+
+
+ );
+};
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..a4ecad4b8
--- /dev/null
+++ b/dashboards-observability/public/components/visualizations/charts/logs_view/logs_view_type.ts
@@ -0,0 +1,69 @@
+/*
+ * 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';
+
+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: [],
+ },
+ ],
+ },
+ 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.tsx b/dashboards-observability/public/components/visualizations/charts/maps/heatmap.tsx
index db746b50f..11e6dfe48 100644
--- a/dashboards-observability/public/components/visualizations/charts/maps/heatmap.tsx
+++ b/dashboards-observability/public/components/visualizations/charts/maps/heatmap.tsx
@@ -4,11 +4,19 @@
*/
import React, { useMemo } from 'react';
-import { uniq, has, isArray, isEmpty } from 'lodash';
+import { uniq, has, isEmpty, indexOf } from 'lodash';
import Plotly from 'plotly.js-dist';
+import { colorPalette } from '@elastic/eui';
import { Plt } from '../../plotly/plot';
-import { PLOTLY_COLOR } from '../../../../../common/constants/shared';
import { EmptyPlaceholder } from '../../../event_analytics/explorer/visualizations/shared_components/empty_placeholder';
+import {
+ HEATMAP_PALETTE_COLOR,
+ SINGLE_COLOR_PALETTE,
+ OPACITY,
+ HEATMAP_SINGLE_COLOR,
+} from '../../../../../common/constants/colors';
+import { hexToRgb, lightenColor } from '../../../../components/event_analytics/utils/utils';
+import { NUMERICAL_FIELDS } from '../../../../../common/constants/shared';
export const HeatMap = ({ visualizations, layout, config }: any) => {
const {
@@ -17,38 +25,62 @@ export const HeatMap = ({ visualizations, layout, config }: any) => {
} = visualizations.data.rawVizData;
const { dataConfig = {}, layoutConfig = {} } = visualizations?.data?.userConfigs;
- if (fields.length < 3) return ;
+ if (fields.length < 3) return ;
- const xaxisField = fields[fields.length - 2];
- const yaxisField = fields[fields.length - 1];
- const zMetrics =
- dataConfig?.valueOptions && dataConfig?.valueOptions.zaxis
- ? dataConfig?.valueOptions.zaxis[0]
- : fields[fields.length - 3];
- const uniqueYaxis = uniq(data[yaxisField.name]);
- const uniqueXaxis = uniq(data[xaxisField.name]);
- const uniqueYaxisLength = uniqueYaxis.length;
- const uniqueXaxisLength = uniqueXaxis.length;
+ const xaxisField = dataConfig?.valueOptions?.dimensions[0];
+ const yaxisField = dataConfig?.valueOptions?.dimensions[1];
+ const zMetrics = dataConfig?.valueOptions?.metrics[0];
if (
isEmpty(xaxisField) ||
isEmpty(yaxisField) ||
isEmpty(zMetrics) ||
- isEmpty(data[xaxisField.name]) ||
- isEmpty(data[yaxisField.name]) ||
- isEmpty(data[zMetrics.name])
+ isEmpty(data[xaxisField.label]) ||
+ isEmpty(data[yaxisField.label]) ||
+ isEmpty(data[zMetrics.label]) ||
+ indexOf(NUMERICAL_FIELDS, zMetrics.type) < 0
)
- return ;
+ return ;
+
+ const uniqueYaxis = uniq(data[yaxisField.label]);
+ const uniqueXaxis = uniq(data[xaxisField.label]);
+ const uniqueYaxisLength = uniqueYaxis.length;
+ const uniqueXaxisLength = uniqueXaxis.length;
+ const tooltipMode =
+ dataConfig?.tooltipOptions?.tooltipMode !== undefined
+ ? dataConfig.tooltipOptions.tooltipMode
+ : 'show';
+ const tooltipText =
+ dataConfig?.tooltipOptions?.tooltipText !== undefined
+ ? dataConfig.tooltipOptions.tooltipText
+ : 'all';
+
+ const colorField = dataConfig?.chartStyles
+ ? dataConfig?.chartStyles.colorMode && dataConfig?.chartStyles.colorMode[0].name === OPACITY
+ ? dataConfig?.chartStyles.color ?? HEATMAP_SINGLE_COLOR
+ : dataConfig?.chartStyles.scheme ?? HEATMAP_PALETTE_COLOR
+ : HEATMAP_PALETTE_COLOR;
+ const showColorscale = dataConfig?.legend?.showLegend ?? 'show';
- const colorScaleValues = [...PLOTLY_COLOR.map((clr, index) => [index, clr])];
+ const traceColor: any = [];
+ if (colorField.name === SINGLE_COLOR_PALETTE) {
+ const colorsArray = colorPalette([lightenColor(colorField.color, 50), colorField.color], 10);
+ colorsArray.map((hexCode, index) => {
+ traceColor.push([
+ (index !== colorsArray.length - 1 ? index : 10) / 10,
+ hexToRgb(hexCode, 1, false),
+ ]);
+ });
+ }
const calculatedHeapMapZaxis: Plotly.Data[] = useMemo(() => {
const heapMapZaxis = [];
const buckets = {};
// maps bukcets to metrics
- for (let i = 0; i < data[xaxisField.name].length; i++) {
- buckets[`${data[xaxisField.name][i]},${data[yaxisField.name][i]}`] = data[zMetrics.name][i];
+ for (let i = 0; i < data[xaxisField.label].length; i++) {
+ buckets[`${data[xaxisField.label][i]},${data[yaxisField.label][i]}`] =
+ data[zMetrics.label][i];
}
// initialize empty 2 dimensional array, inner loop for each xaxis field, outer loop for yaxis
@@ -86,21 +118,24 @@ export const HeatMap = ({ visualizations, layout, config }: any) => {
z: calculatedHeapMapZaxis,
x: uniqueXaxis,
y: uniqueYaxis,
- colorscale: colorScaleValues,
+ hoverinfo: tooltipMode === 'hidden' ? 'none' : tooltipText,
+ colorscale: colorField.name === SINGLE_COLOR_PALETTE ? traceColor : colorField.name,
type: 'heatmap',
+ showscale: showColorscale === 'show',
},
];
const mergedLayout = {
...layout,
...(layoutConfig.layout && layoutConfig.layout),
- title: dataConfig?.panelOptions?.title || layoutConfig.layout?.title || zMetrics.name || '',
+ title: dataConfig?.panelOptions?.title || layoutConfig.layout?.title || '',
};
- const mergedConfigs = {
+
+ const mergedConfigs = useMemo(() => ({
...config,
...(layoutConfig.config && layoutConfig.config),
- };
+ }), [config, layoutConfig.config]);
return ;
};
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 269e429c2..1bb826a53 100644
--- a/dashboards-observability/public/components/visualizations/charts/maps/heatmap_type.ts
+++ b/dashboards-observability/public/components/visualizations/charts/maps/heatmap_type.ts
@@ -8,7 +8,20 @@ import { getPlotlySharedConfigs, getPlotlyCategory } from '../shared/shared_conf
import { LensIconChartPie } from '../../assets/chart_pie';
import { VizDataPanel } from '../../../event_analytics/explorer/visualizations/config_panel/config_panes/default_vis_editor';
import { ConfigEditor } from '../../../event_analytics/explorer/visualizations/config_panel/config_panes/json_editor';
-import { ConfigValueOptions } from '../../../event_analytics/explorer/visualizations/config_panel/config_panes/config_controls';
+import {
+ ConfigValueOptions,
+ HeatmapColorPalettePicker,
+ ConfigChartOptions,
+ PanelItem,
+ SingleColorPicker,
+ ConfigLegend,
+} from '../../../event_analytics/explorer/visualizations/config_panel/config_panes/config_controls';
+import {
+ COLOR_PALETTES,
+ HEATMAP_SINGLE_COLOR,
+ HEATMAP_PALETTE_COLOR,
+} from '../../../../../common/constants/colors';
+import { fetchConfigObject } from '../../../../components/event_analytics/utils/utils';
const sharedConfigs = getPlotlySharedConfigs();
const VIS_CATEGORY = getPlotlyCategory();
@@ -18,32 +31,85 @@ export const createMapsVisDefinition = () => ({
type: 'heatmap',
id: 'heatmap',
label: 'Heatmap',
- fullLabel: 'Hubble',
- iconType: 'heatmap',
+ fulllabel: 'Hubble',
+ icontype: 'heatmap',
category: VIS_CATEGORY.BASICS,
selection: {
dataLoss: 'nothing',
},
icon: LensIconChartPie,
- editorConfig: {
+ editorconfig: {
panelTabs: [
{
id: 'data-panel',
- name: 'Data',
+ name: 'Style',
mapTo: 'dataConfig',
editor: VizDataPanel,
sections: [
+ fetchConfigObject('Tooltip', {
+ options: [
+ { name: 'All', id: 'all' },
+ { name: 'Dim 1', id: 'x' },
+ { name: 'Dim 2', id: 'y' },
+ { name: 'Metrics', id: 'z' },
+ ],
+ defaultSelections: [{ name: 'All', id: 'all' }],
+ }),
{
- id: 'value_options',
- name: 'Value options',
- editor: ConfigValueOptions,
- mapTo: 'valueOptions',
+ id: 'legend',
+ name: 'Legend',
+ editor: ConfigLegend,
+ mapTo: 'legend',
schemas: [
{
- name: 'Z-axis',
- isSingleSelection: true,
+ name: 'Show colorscale',
+ mapTo: 'showLegend',
component: null,
- mapTo: 'zaxis',
+ props: {
+ options: [
+ { name: 'Show', id: 'show' },
+ { name: 'Hidden', id: 'hidden' },
+ ],
+ defaultSelections: [{ name: 'Show', id: 'show' }],
+ },
+ },
+ ],
+ },
+ {
+ id: 'chart_styles',
+ name: 'Chart styles',
+ editor: ConfigChartOptions,
+ mapTo: 'chartStyles',
+ schemas: [
+ {
+ name: 'Color mode',
+ component: PanelItem,
+ mapTo: 'colorMode',
+ eleType: 'list',
+ isSingleSelection: true,
+ options: [
+ { name: 'spectrum', label: 'spectrum', value: 'spectrum' },
+ { name: 'opacity', label: 'opacity', value: 'opacity' },
+ ],
+ defaultState: [{ name: 'spectrum', label: 'spectrum', value: 'spectrum' }],
+ props: {
+ isClearable: false,
+ },
+ },
+ {
+ name: 'Scheme',
+ component: HeatmapColorPalettePicker,
+ mapTo: 'scheme',
+ eleType: 'palettePicker',
+ options: COLOR_PALETTES.filter((color) => color.type !== 'text'),
+ defaultState: HEATMAP_PALETTE_COLOR,
+ },
+ {
+ name: 'Color',
+ component: SingleColorPicker,
+ mapTo: 'color',
+ eleType: 'singleColorPicker',
+ defaultState: HEATMAP_SINGLE_COLOR,
},
],
},
@@ -58,7 +124,7 @@ export const createMapsVisDefinition = () => ({
},
],
},
- visConfig: {
+ visconfig: {
layout: {
...sharedConfigs.layout,
...{
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 74330f342..338d39c9c 100644
--- a/dashboards-observability/public/components/visualizations/charts/maps/treemap_type.ts
+++ b/dashboards-observability/public/components/visualizations/charts/maps/treemap_type.ts
@@ -8,53 +8,129 @@ import { getPlotlySharedConfigs, getPlotlyCategory } from '../shared/shared_conf
import { LensIconChartBar } from '../../assets/chart_bar';
import { VizDataPanel } from '../../../event_analytics/explorer/visualizations/config_panel/config_panes/default_vis_editor';
import { ConfigEditor } from '../../../event_analytics/explorer/visualizations/config_panel/config_panes/json_editor';
-import { ConfigValueOptions } from '../../../event_analytics/explorer/visualizations/config_panel/config_panes/config_controls';
+import {
+ ConfigValueOptions,
+ ColorPalettePicker,
+ ConfigChartOptions,
+ ConfigLegend,
+} from '../../../event_analytics/explorer/visualizations/config_panel/config_panes/config_controls';
+import { DEFAULT_PALETTE, COLOR_PALETTES } from '../../../../../common/constants/colors';
+import { ButtonGroupItem } from '../../../../../public/components/event_analytics/explorer/visualizations/config_panel/config_panes/config_controls/config_button_group';
+import { DefaultChartStyles } from '../../../../../common/constants/shared';
+import { fetchConfigObject } from '../../../../components/event_analytics/utils/utils';
const sharedConfigs = getPlotlySharedConfigs();
const VIS_CATEGORY = getPlotlyCategory();
+const { SortSectors } = DefaultChartStyles;
+
export interface BarTypeParams {}
export const createTreeMapDefinition = (params: BarTypeParams = {}) => ({
name: 'tree_map',
type: 'tree_map',
id: 'tree_map',
- label: 'Tree Map',
- fullLabel: 'Tree Map',
+ label: 'Tree map',
+ fulllabel: 'Tree map',
selection: {
dataLoss: 'nothing',
},
category: VIS_CATEGORY.BASICS,
+ icontype: 'heatmap',
icon: LensIconChartBar,
- categoryAxis: 'xaxis',
- seriesAxis: 'yaxis',
+ categoryaxis: 'xaxis',
+ seriesaxis: 'yaxis',
orientation: 'v',
component: TreeMap,
- editorConfig: {
+ editorconfig: {
panelTabs: [
{
id: 'data-panel',
- name: 'Data',
+ name: 'Style',
mapTo: 'dataConfig',
editor: VizDataPanel,
sections: [
+ fetchConfigObject('Tooltip', {
+ options: [
+ { name: 'All', id: 'all' },
+ { name: 'Label', id: 'label' },
+ { name: 'Value', id: 'value' },
+ ],
+ defaultSelections: [{ name: 'All', id: 'all' }],
+ }),
+ {
+ id: 'legend',
+ name: 'Legend',
+ editor: ConfigLegend,
+ mapTo: 'legend',
+ schemas: [
+ {
+ name: 'Show colorscale',
+ mapTo: 'showLegend',
+ component: null,
+ props: {
+ options: [
+ { name: 'Show', id: 'show' },
+ { name: 'Hidden', id: 'hidden' },
+ ],
+ defaultSelections: [{ name: 'Show', id: 'show' }],
+ },
+ },
+ ],
+ },
{
- id: 'value_options',
- name: 'Value options',
+ id: 'treemap_options',
+ name: 'Treemap',
editor: ConfigValueOptions,
- mapTo: 'valueOptions',
+ mapTo: 'treemapOptions',
schemas: [
{
- name: 'X-axis',
+ name: 'Tiling algorithm',
isSingleSelection: true,
component: null,
- mapTo: 'xaxis',
+ mapTo: 'tilingAlgorithm',
+ options: [
+ { name: 'Squarify', value: 'squarify' },
+ { name: 'Binary', value: 'binary' },
+ { name: 'Dice', value: 'dice' },
+ { name: 'Slice', value: 'slice' },
+ { name: 'Slice Dice', value: 'slice-dice' },
+ { name: 'Dice Slice', value: 'dice-slice' },
+ ],
+ defaultState: [{ name: 'Squarify', label: 'Squarify', value: 'squarify' }],
+ props: {
+ isClearable: false,
+ },
},
{
- name: 'Y-axis',
- isSingleSelection: false,
- component: null,
- mapTo: 'yaxis',
+ name: 'Sort Sectors',
+ component: ButtonGroupItem,
+ mapTo: 'sort_sectors',
+ eleType: 'buttons',
+ props: {
+ options: [
+ { name: 'Largest to Smallest', id: 'largest_to_smallest' },
+ { name: 'Random', id: 'random' },
+ ],
+ defaultSelections: [{ name: 'Largest to Smallest', id: SortSectors }],
+ },
+ },
+ ],
+ },
+ {
+ id: 'chart_styles',
+ name: 'Chart styles',
+ editor: ConfigChartOptions,
+ mapTo: 'chartStyles',
+ schemas: [
+ {
+ name: 'Color theme',
+ isSingleSelection: true,
+ component: ColorPalettePicker,
+ mapTo: 'colorTheme',
+ eleType: 'treemapColorPicker',
+ options: COLOR_PALETTES,
+ defaultState: { name: DEFAULT_PALETTE },
},
],
},
@@ -69,7 +145,7 @@ export const createTreeMapDefinition = (params: BarTypeParams = {}) => ({
},
],
},
- visConfig: {
+ visconfig: {
layout: {
...sharedConfigs.layout,
},
diff --git a/dashboards-observability/public/components/visualizations/charts/maps/treemaps.tsx b/dashboards-observability/public/components/visualizations/charts/maps/treemaps.tsx
index bdd014e64..47e160bc1 100644
--- a/dashboards-observability/public/components/visualizations/charts/maps/treemaps.tsx
+++ b/dashboards-observability/public/components/visualizations/charts/maps/treemaps.tsx
@@ -3,57 +3,201 @@
* SPDX-License-Identifier: Apache-2.0
*/
-import React from 'react';
+import React, { useMemo } from 'react';
+import { indexOf, isEmpty, isEqual, isNull, uniq } from 'lodash';
import { Plt } from '../../plotly/plot';
+import { EmptyPlaceholder } from '../../../event_analytics/explorer/visualizations/shared_components/empty_placeholder';
+import { NUMERICAL_FIELDS } from '../../../../../common/constants/shared';
+import {
+ DEFAULT_PALETTE,
+ MULTI_COLOR_PALETTE,
+ SINGLE_COLOR_PALETTE,
+} from '../../../../../common/constants/colors';
+import { DefaultChartStyles } from '../../../../../common/constants/shared';
-export const TreeMap = ({ visualizations, layout, config }) => {
- const labels = ['Eve', 'Cain', 'Seth', 'Enos', 'Noam', 'Abel', 'Awan', 'Enoch', 'Azura'];
- const parents = ['', 'Eve', 'Eve', 'Seth', 'Seth', 'Eve', 'Eve', 'Awan', 'Eve'];
- const treemapData = [
- {
- type: 'treemap',
- labels,
- parents,
- values: [10, 14, 12, 10, 2, 6, 6, 1, 4],
- textinfo: 'label+value+percent parent+percent entry',
- domain: { x: [0, 0.48] },
- outsidetextfont: { size: 20, color: '#377eb8' },
- marker: { line: { width: 2 } },
- pathbar: { visible: false },
- },
- {
- type: 'treemap',
- branchvalues: 'total',
- labels,
- parents,
- domain: { x: [0.52, 1] },
- values: [65, 14, 12, 10, 2, 6, 6, 1, 4],
- textinfo: 'label+value+percent parent+percent entry',
- outsidetextfont: { size: 20, color: '#377eb8' },
- marker: { line: { width: 2 } },
- pathbar: { visible: false },
- },
- ];
- const finalLayout = {
- annotations: [
- {
- showarrow: false,
- text: 'branchvalues: remainder ',
- x: 0.25,
- xanchor: 'center',
- y: 1.1,
- yanchor: 'bottom',
- },
+export const TreeMap = ({ visualizations, layout, config }: any) => {
+ const { DefaultSortSectors } = DefaultChartStyles;
+
+ const {
+ data,
+ metadata: { fields },
+ } = visualizations.data.rawVizData;
+ const { dataConfig = {}, layoutConfig = {} } = visualizations?.data?.userConfigs;
+
+ const childField =
+ dataConfig?.valueOptions?.dimensions && dataConfig.valueOptions.dimensions[0].childField
+ ? dataConfig.valueOptions.dimensions[0].childField
+ : fields[fields.length - 1];
+
+ const parentFields =
+ dataConfig?.valueOptions?.dimensions && dataConfig.valueOptions.dimensions[0].parentFields
+ ? dataConfig.valueOptions.dimensions[0].parentFields
+ : [];
+ const tooltipMode =
+ dataConfig?.tooltipOptions?.tooltipMode !== undefined
+ ? dataConfig.tooltipOptions.tooltipMode
+ : 'show';
+ const tooltipText =
+ dataConfig?.tooltipOptions?.tooltipText !== undefined
+ ? dataConfig?.tooltipOptions?.tooltipText
+ : 'all';
+
+ const valueField =
+ dataConfig?.valueOptions?.metrics && dataConfig.valueOptions.metrics[0].valueField
+ ? dataConfig.valueOptions.metrics[0].valueField
+ : fields[0];
+
+ const colorField =
+ dataConfig?.chartStyles && dataConfig.chartStyles.colorTheme
+ ? dataConfig.chartStyles.colorTheme
+ : { name: DEFAULT_PALETTE };
+
+ const tilingAlgorithm =
+ dataConfig?.treemapOptions &&
+ dataConfig.treemapOptions.tilingAlgorithm &&
+ !isEmpty(dataConfig.treemapOptions.tilingAlgorithm)
+ ? dataConfig.treemapOptions.tilingAlgorithm[0]
+ : 'squarify';
+
+ const sortSectorsField = dataConfig?.treemapOptions?.sort_sectors || DefaultSortSectors;
+ const showColorscale = dataConfig?.legend?.showLegend ?? 'show';
+
+ const areParentFieldsInvalid =
+ new Set([...parentFields.map((field) => field.name)]).size !== parentFields.length ||
+ parentFields.some((field) => isEmpty(data[field.name]) || isEqual(childField.name, field.name));
+
+ if (
+ isEmpty(data[childField.name]) ||
+ isEmpty(data[valueField.name]) ||
+ indexOf(NUMERICAL_FIELDS, valueField.type) < 0 ||
+ areParentFieldsInvalid
+ )
+ return ;
+
+ const [treemapData, mergedLayout] = useMemo(() => {
+ let labelsArray: string[] = [],
+ parentsArray: string[] = [],
+ valuesArray: number[] = [],
+ colorsArray: string[] = [];
+
+ if (parentFields.length === 0) {
+ labelsArray = [...data[childField.name]];
+ parentsArray = [...Array(labelsArray.length).fill('')];
+ valuesArray = [...data[valueField.name]];
+ if (colorField.name === MULTI_COLOR_PALETTE) {
+ colorsArray = [...Array(data[childField.name].length).fill(colorField.childColor)];
+ }
+ } else {
+ let currentLevel = parentFields.length - 1;
+ let lastParentField = {};
+ parentFields
+ .slice(0)
+ .reverse()
+ .map((field, i) => {
+ const uniqueParents = uniq(data[field.name]) as string[];
+ labelsArray = [...labelsArray, ...uniqueParents];
+ if (i === 0) {
+ parentsArray = [...Array(uniqueParents.length).fill('')];
+ valuesArray = [...Array(uniqueParents.length).fill(0)];
+ colorsArray =
+ colorField.name === MULTI_COLOR_PALETTE
+ ? [
+ ...Array(uniqueParents.length).fill(
+ colorField.parentColors[currentLevel] ?? '#000000'
+ ),
+ ]
+ : [];
+ } else {
+ const currentParentIndices = uniqueParents.map((parent) =>
+ data[field.name].findIndex((index) => index === parent)
+ );
+ const lastParents = currentParentIndices.map(
+ (index) => data[lastParentField.name][index]
+ );
+ parentsArray = [...parentsArray, ...lastParents];
+ valuesArray = [...valuesArray, ...Array(lastParents.length).fill(0)];
+ colorsArray =
+ colorField.name === MULTI_COLOR_PALETTE
+ ? [
+ ...colorsArray,
+ ...Array(lastParents.length).fill(
+ colorField.parentColors[currentLevel] ?? '#000000'
+ ),
+ ]
+ : [];
+ }
+ currentLevel = currentLevel - 1;
+ lastParentField = field;
+ });
+
+ labelsArray = [...labelsArray, ...data[childField.name]];
+ valuesArray = [...valuesArray, ...data[valueField.name]];
+ parentsArray = [...parentsArray, ...data[lastParentField.name]];
+ colorsArray =
+ colorField.name === MULTI_COLOR_PALETTE
+ ? [...colorsArray, ...Array(data[childField.name].length).fill(colorField.childColor)]
+ : [];
+ }
+
+ if (colorField.name === SINGLE_COLOR_PALETTE) {
+ colorsArray = [...Array(valuesArray.length).fill(colorField.childColor)];
+ }
+
+ const markerColors =
+ colorField.name === MULTI_COLOR_PALETTE
+ ? { colors: colorsArray }
+ : ![DEFAULT_PALETTE, SINGLE_COLOR_PALETTE].includes(colorField.name)
+ ? {
+ colorscale: colorField.name,
+ colorbar: {
+ len: 1,
+ },
+ showscale: showColorscale === 'show',
+ }
+ : {};
+
+ const colorway = colorField.name === SINGLE_COLOR_PALETTE ? colorsArray : {};
+
+ const mapLayout = {
+ ...layout,
+ ...(layoutConfig.layout && layoutConfig.layout),
+ title: dataConfig?.panelOptions?.title || layoutConfig.layout?.title || '',
+ treemapcolorway: colorway,
+ };
+
+ const mapData = [
{
- showarrow: false,
- text: 'branchvalues: total ',
- x: 0.75,
- xanchor: 'center',
- y: 1.1,
- yanchor: 'bottom',
+ type: 'treemap',
+ labels: labelsArray,
+ parents: parentsArray,
+ values: valuesArray,
+ hoverinfo: tooltipMode === 'hidden' ? 'none' : tooltipText,
+ textinfo: 'label+value+percent parent+percent entry',
+ tiling: {
+ packing: tilingAlgorithm.value,
+ },
+ marker: markerColors,
+ sort: sortSectorsField === DefaultSortSectors,
},
- ],
+ ];
+
+ return [mapData, mapLayout];
+ }, [
+ data,
+ childField,
+ valueField,
+ parentFields,
+ colorField,
+ tilingAlgorithm,
+ dataConfig,
+ layoutConfig,
+ ]);
+
+ const mergedConfigs = {
+ ...config,
+ ...(layoutConfig.config && layoutConfig.config),
};
- return ;
+
+ return ;
};
diff --git a/dashboards-observability/public/components/visualizations/charts/pie/pie.tsx b/dashboards-observability/public/components/visualizations/charts/pie/pie.tsx
index 0c07892e9..912f3f6d2 100644
--- a/dashboards-observability/public/components/visualizations/charts/pie/pie.tsx
+++ b/dashboards-observability/public/components/visualizations/charts/pie/pie.tsx
@@ -3,9 +3,11 @@
* SPDX-License-Identifier: Apache-2.0
*/
-import React from 'react';
+import React, { useMemo } from 'react';
import { take, isEmpty } from 'lodash';
import { Plt } from '../../plotly/plot';
+import { DEFAULT_PALETTE, HEX_CONTRAST_COLOR } from '../../../../../common/constants/colors';
+import { EmptyPlaceholder } from '../../../event_analytics/explorer/visualizations/shared_components/empty_placeholder';
export const Pie = ({ visualizations, layout, config }: any) => {
const { vis } = visualizations;
@@ -15,41 +17,103 @@ export const Pie = ({ visualizations, layout, config }: any) => {
} = visualizations.data.rawVizData;
const { defaultAxes } = visualizations.data;
const { dataConfig = {}, layoutConfig = {} } = visualizations?.data?.userConfigs;
- const xaxis =
- dataConfig?.valueOptions && dataConfig.valueOptions.xaxis ? dataConfig.valueOptions.xaxis : [];
- const yaxis =
- dataConfig?.valueOptions && dataConfig.valueOptions.yaxis ? dataConfig.valueOptions.yaxis : [];
- const type = dataConfig?.chartOptions?.mode ? dataConfig?.chartOptions?.mode[0]?.modeId : 'pie';
+ const xaxis = dataConfig?.valueOptions?.dimensions
+ ? dataConfig.valueOptions.dimensions.filter((item) => item.label)
+ : [];
+ const yaxis = dataConfig?.valueOptions?.metrics
+ ? dataConfig.valueOptions.metrics.filter((item) => item.label)
+ : [];
+ const type = dataConfig?.chartStyles?.mode ? dataConfig?.chartStyles?.mode[0]?.modeId : 'pie';
const lastIndex = fields.length - 1;
+ const colorTheme = dataConfig?.chartStyles?.colorTheme
+ ? dataConfig?.chartStyles?.colorTheme
+ : { name: DEFAULT_PALETTE };
+ const showLegend = dataConfig?.legend?.showLegend === 'hidden' ? false : vis.showlegend;
+ const legendPosition = dataConfig?.legend?.position || vis.legendposition;
+ const legendSize = dataConfig?.legend?.size || vis.legendSize;
+ const labelSize = dataConfig?.chartStyles?.labelSize || vis.labelSize;
+ const tooltipMode =
+ dataConfig?.tooltipOptions?.tooltipMode !== undefined
+ ? dataConfig.tooltipOptions.tooltipMode
+ : 'show';
+ const tooltipText =
+ dataConfig?.tooltipOptions?.tooltipText !== undefined
+ ? dataConfig.tooltipOptions.tooltipText
+ : 'all';
- let valueSeries;
- if (!isEmpty(xaxis) && !isEmpty(yaxis)) {
- valueSeries = [...yaxis];
- } else {
- valueSeries = defaultAxes.yaxis || take(fields, lastIndex > 0 ? lastIndex : 1);
- }
+ if (isEmpty(xaxis) || isEmpty(yaxis))
+ return ;
- const pies = valueSeries.map((field: any, index) => {
+ let valueSeries;
+ if (!isEmpty(xaxis) && !isEmpty(yaxis)) {
+ valueSeries = [...yaxis];
+ } else {
+ valueSeries = defaultAxes.yaxis || take(fields, lastIndex > 0 ? lastIndex : 1);
+ }
+
+ const invertHex = (hex: string) =>
+ (Number(`0x1${hex}`) ^ HEX_CONTRAST_COLOR).toString(16).substr(1).toUpperCase();
+
+ const createLegendLabels = (dimLabels: string[], xaxisLables: string[]) => {
+ return dimLabels.map((label: string, index: number) => {
+ return [xaxisLables[index], label].join(',');
+ });
+ };
+
+ const labelsOfXAxis = useMemo(() => {
+ let legendLabels = [];
+ if (xaxis.length > 0) {
+ let dimLabelsArray = data[xaxis[0].label];
+ for (let i = 0; i < xaxis.length - 1; i++) {
+ dimLabelsArray = createLegendLabels(dimLabelsArray, data[xaxis[i + 1].label]);
+ }
+ legendLabels = dimLabelsArray;
+ } else {
+ legendLabels = data[fields[lastIndex].name];
+ }
+ return legendLabels;
+ }, [xaxis, data, fields, createLegendLabels]);
+
+ const hexColor = invertHex(colorTheme);
+ const pies = useMemo(() => valueSeries.map((field: any, index: number) => {
+ const marker =
+ colorTheme.name !== DEFAULT_PALETTE
+ ? {
+ marker: {
+ colors: [...Array(data[field.name].length).fill(colorTheme.childColor)],
+ line: {
+ color: hexColor,
+ width: 1,
+ },
+ },
+ }
+ : undefined;
return {
- labels: data[xaxis ? xaxis[0]?.label : fields[lastIndex].name],
- values: data[field.name],
+ labels: labelsOfXAxis,
+ values: data[field.label],
type: 'pie',
name: field.name,
hole: type === 'pie' ? 0 : 0.5,
text: field.name,
textinfo: 'percent',
+ hoverinfo: tooltipMode === 'hidden' ? 'none' : tooltipText,
automargin: true,
textposition: 'outside',
domain: {
row: Math.floor(index / 3),
column: index % 3,
},
+ ...marker,
+ outsidetextfont: {
+ size: labelSize,
+ },
};
- });
+ })
+ , [valueSeries, valueSeries, data, labelSize, labelsOfXAxis, colorTheme]);
const isAtleastOneFullRow = Math.floor(valueSeries.length / 3) > 0;
- const mergedLayout = {
+ const mergedLayout = useMemo(() => ({
grid: {
rows: Math.floor(valueSeries.length / 3) + 1,
columns: isAtleastOneFullRow ? 3 : valueSeries.length,
@@ -57,12 +121,28 @@ export const Pie = ({ visualizations, layout, config }: any) => {
...layout,
...(layoutConfig.layout && layoutConfig.layout),
title: dataConfig?.panelOptions?.title || layoutConfig.layout?.title || '',
- };
+ legend: {
+ ...layout.legend,
+ orientation: legendPosition,
+ font: { size: legendSize },
+ },
+ showlegend: showLegend,
+ }),
+ [
+ valueSeries,
+ isAtleastOneFullRow,
+ layoutConfig.layout,
+ dataConfig?.panelOptions?.title,
+ layoutConfig.layout?.title,
+ layout.legend,
+ legendPosition,
+ legendSize
+ ]);
- const mergedConfigs = {
+ const mergedConfigs = useMemo(() => ({
...config,
...(layoutConfig.config && layoutConfig.config),
- };
+ }), [config, layoutConfig.config]);
return ;
};
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 7dbc507aa..51c041e65 100644
--- a/dashboards-observability/public/components/visualizations/charts/pie/pie_type.ts
+++ b/dashboards-observability/public/components/visualizations/charts/pie/pie_type.ts
@@ -9,7 +9,14 @@ import { LensIconChartPie } from '../../assets/chart_pie';
import { PLOTLY_COLOR } from '../../../../../common/constants/shared';
import { VizDataPanel } from '../../../event_analytics/explorer/visualizations/config_panel/config_panes/default_vis_editor';
import { ConfigEditor } from '../../../event_analytics/explorer/visualizations/config_panel/config_panes/json_editor';
-import { ConfigValueOptions } from '../../../event_analytics/explorer/visualizations/config_panel/config_panes/config_controls';
+import {
+ ColorPalettePicker,
+ ConfigChartOptions,
+ ConfigLegend,
+ InputFieldItem,
+} from '../../../event_analytics/explorer/visualizations/config_panel/config_panes/config_controls';
+import { DEFAULT_PALETTE, PIE_PALETTES } from '../../../../../common/constants/colors';
+import { fetchConfigObject } from '../../../../components/event_analytics/utils/utils';
const sharedConfigs = getPlotlySharedConfigs();
const VIS_CATEGORY = getPlotlyCategory();
@@ -19,50 +26,77 @@ export const createPieTypeDefinition = (params: any) => ({
type: 'pie',
id: 'pie',
label: 'Pie',
- fullLabel: 'Pie',
- iconType: 'visPie',
+ fulllabel: 'Pie',
+ icontype: 'visPie',
category: VIS_CATEGORY.BASICS,
+ showlegend: true,
+ legendposition: 'v',
selection: {
dataLoss: 'nothing',
},
- categoryAxis: 'xaxis',
- seriesAxis: 'yaxis',
+ categoryaxis: 'xaxis',
+ seriesaxis: 'yaxis',
icon: LensIconChartPie,
- editorConfig: {
+ editorconfig: {
panelTabs: [
{
id: 'data-panel',
- name: 'Data',
+ name: 'Style',
mapTo: 'dataConfig',
editor: VizDataPanel,
sections: [
{
- id: 'value_options',
- name: 'Value options',
- editor: ConfigValueOptions,
- mapTo: 'valueOptions',
+ id: 'legend',
+ name: 'Legend',
+ editor: ConfigLegend,
+ mapTo: 'legend',
schemas: [
{
- name: 'Label',
- onChangeHandler: 'setXaxisSelections',
- isSingleSelection: false,
+ name: 'Show legend',
+ mapTo: 'showLegend',
component: null,
- mapTo: 'xaxis',
+ props: {
+ options: [
+ { name: 'Show', id: 'show' },
+ { name: 'Hidden', id: 'hidden' },
+ ],
+ defaultSelections: [{ name: 'Show', id: 'show' }],
+ },
},
{
- name: 'Value',
- onChangeHandler: 'setYaxisSelections',
- isSingleSelection: false,
+ name: 'Position',
+ mapTo: 'position',
component: null,
- mapTo: 'yaxis',
+ props: {
+ options: [
+ { name: 'Right', id: 'v' },
+ { name: 'Bottom', id: 'h' },
+ ],
+ defaultSelections: [{ name: 'Right', id: 'v' }],
+ },
+ },
+ {
+ name: 'Legend size',
+ component: InputFieldItem,
+ mapTo: 'size',
+ eleType: 'input',
},
],
},
+ fetchConfigObject('Tooltip', {
+ options: [
+ { name: 'All', id: 'all' },
+ { name: 'Label', id: 'label' },
+ { name: 'Value', id: 'value' },
+ { name: 'Percent', id: 'percent' },
+ ],
+ defaultSelections: [{ name: 'All', id: 'all' }],
+ }),
{
- id: 'chart_options',
- name: 'Chart options',
- editor: ConfigValueOptions,
- mapTo: 'chartOptions',
+ id: 'chart_styles',
+ name: 'Chart styles',
+ editor: ConfigChartOptions,
+ mapTo: 'chartStyles',
schemas: [
{
name: 'Mode',
@@ -74,8 +108,23 @@ export const createPieTypeDefinition = (params: any) => ({
{ name: 'Pie', modeId: 'pie' },
{ name: 'Donut', modeId: 'donut' },
],
- defaultSelections: [{ name: 'Pie', modeId: 'pie' }],
},
+ defaultState: [{ name: 'Pie', modeId: 'pie', label: 'Pie' }],
+ },
+ {
+ name: 'Label size',
+ component: InputFieldItem,
+ mapTo: 'labelSize',
+ eleType: 'input',
+ },
+ {
+ name: 'Color theme',
+ isSingleSelection: true,
+ component: ColorPalettePicker,
+ mapTo: 'colorTheme',
+ eleType: 'colorpicker',
+ options: PIE_PALETTES,
+ defaultState: { name: DEFAULT_PALETTE },
},
],
},
@@ -90,7 +139,7 @@ export const createPieTypeDefinition = (params: any) => ({
},
],
},
- visConfig: {
+ visconfig: {
layout: {
...sharedConfigs.layout,
...{
diff --git a/dashboards-observability/public/components/visualizations/charts/shared/shared_configs.ts b/dashboards-observability/public/components/visualizations/charts/shared/shared_configs.ts
index 062f38785..6730a5d60 100644
--- a/dashboards-observability/public/components/visualizations/charts/shared/shared_configs.ts
+++ b/dashboards-observability/public/components/visualizations/charts/shared/shared_configs.ts
@@ -16,7 +16,7 @@ export const getPlotlySharedConfigs = () => {
t: 50,
pad: 0,
},
- height: 500,
+ height: 1180,
legend: {
orientation: 'v',
traceorder: 'normal',
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..183fe9235 100644
--- a/dashboards-observability/public/components/visualizations/charts/text/text_type.ts
+++ b/dashboards-observability/public/components/visualizations/charts/text/text_type.ts
@@ -17,21 +17,21 @@ export const createTextTypeDefinition = (params: any = {}) => ({
name: 'text',
type: 'text',
id: 'text',
- label: 'Text',
- fullLabel: 'Text',
- iconType: 'visText',
+ label: 'Markdown',
+ fulllabel: 'Markdown',
+ icontype: 'visText',
category: VIS_CATEGORY.BASICS,
selection: {
dataLoss: 'nothing',
},
icon: LensIconChartLine,
- categoryAxis: 'xaxis',
- seriesAxis: 'yaxis',
- editorConfig: {
+ categoryaxis: 'xaxis',
+ seriesaxis: 'yaxis',
+ editorconfig: {
panelTabs: [
{
id: 'data-panel',
- name: 'Data',
+ name: 'Style',
mapTo: 'dataConfig',
editor: VizDataPanel,
sections: [
@@ -46,7 +46,7 @@ export const createTextTypeDefinition = (params: any = {}) => ({
},
],
},
- visConfig: {
+ visconfig: {
layout: {
...sharedConfigs.layout,
...{
diff --git a/dashboards-observability/public/components/visualizations/charts/vis_types.ts b/dashboards-observability/public/components/visualizations/charts/vis_types.ts
index 0d3998547..9f37f2fbb 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,8 @@ export const VIS_TYPES = {
heatmap: createMapsVisDefinition,
tree_map: createTreeMapDefinition,
text: createTextTypeDefinition,
+ scatter: createLineTypeDefinition,
+ 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..c3c13c4b9 100644
--- a/dashboards-observability/public/components/visualizations/visualization.tsx
+++ b/dashboards-observability/public/components/visualizations/visualization.tsx
@@ -7,6 +7,7 @@ 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 {}
@@ -23,10 +24,10 @@ 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..2b1b5bf6f 100644
--- a/dashboards-observability/public/components/visualizations/visualization_chart.tsx
+++ b/dashboards-observability/public/components/visualizations/visualization_chart.tsx
@@ -4,28 +4,24 @@
*/
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;
const finalFigureConfig = useMemo(() => {
return {
- ...vis.visConfig?.config,
+ ...vis.visconfig?.config,
...config,
};
}, [config, vis]);
const finalFigureLayout = useMemo(() => {
return {
- ...vis.visConfig?.layout,
+ ...vis.visconfig?.layout,
...layout,
};
}, [layout, vis]);
diff --git a/dashboards-observability/public/services/requests/ppl.ts b/dashboards-observability/public/services/requests/ppl.ts
index f9343bc93..4fe252f22 100644
--- a/dashboards-observability/public/services/requests/ppl.ts
+++ b/dashboards-observability/public/services/requests/ppl.ts
@@ -24,7 +24,7 @@ export default class PPLService {
body: JSON.stringify(params),
})
.catch((error) => {
- console.error(error);
+ console.error('fetch error: ', error.body);
if (errorHandler) errorHandler(error);
});
};
diff --git a/dashboards-observability/server/adaptors/application_analytics/app_analytics_adaptor.ts b/dashboards-observability/server/adaptors/application_analytics/app_analytics_adaptor.ts
index c01c4066d..45458564e 100644
--- a/dashboards-observability/server/adaptors/application_analytics/app_analytics_adaptor.ts
+++ b/dashboards-observability/server/adaptors/application_analytics/app_analytics_adaptor.ts
@@ -3,33 +3,37 @@
* SPDX-License-Identifier: Apache-2.0
*/
-import { ApplicationListType, ApplicationType } from '../../../common/types/app_analytics';
+import {
+ ApplicationRequestType,
+ ApplicationType,
+} from '../../../common/types/application_analytics';
import { ILegacyScopedClusterClient } from '../../../../../src/core/server';
export class AppAnalyticsAdaptor {
// Fetch all existing applications
- fetchApps = async (client: ILegacyScopedClusterClient): Promise => {
+ fetchApps = async (client: ILegacyScopedClusterClient): Promise => {
try {
const response = await client.callAsCurrentUser('observability.getObject', {
objectType: 'application',
});
- return response.observabilityObjectList.map((application: any) => {
- const composition: string[] = application.application.servicesEntities.concat(
- application.application.traceGroups
- );
- const decodedComposition = composition.map((rec) => decodeURI(rec));
+ return response.observabilityObjectList.map((object: any) => {
return {
- name: application.application.name,
- id: application.objectId,
- panelId: application.application.panelId,
- composition: decodedComposition,
+ id: object.objectId,
+ dateCreated: object.createdTimeMs,
+ dateModified: object.lastUpdatedTimeMs,
+ name: object.application.name,
+ description: object.application.description,
+ baseQuery: object.application.baseQuery,
+ servicesEntities: object.application.servicesEntities.map((rec: string) =>
+ decodeURI(rec)
+ ),
+ traceGroups: object.application.traceGroups.map((rec: string) => decodeURI(rec)),
+ panelId: object.application.panelId,
availability: {
name: '',
color: '',
- mainVisId: application.application.availabilityVisId || '',
+ availabilityVisId: object.application.availabilityVisId || '',
},
- dateModified: application.lastUpdatedTimeMs,
- dateCreated: application.createdTimeMs,
};
});
} catch (err: any) {
@@ -38,12 +42,31 @@ export class AppAnalyticsAdaptor {
};
// Fetch application by id
- fetchAppById = async (client: ILegacyScopedClusterClient, appId: string): Promise => {
+ fetchAppById = async (
+ client: ILegacyScopedClusterClient,
+ appId: string
+ ): Promise => {
try {
const response = await client.callAsCurrentUser('observability.getObjectById', {
objectId: appId,
});
- return response.observabilityObjectList[0];
+ const app = response.observabilityObjectList[0];
+ return {
+ id: appId,
+ dateCreated: app.createdTimeMs,
+ dateModified: app.lastUpdatedTimeMs,
+ name: app.application.name,
+ description: app.application.description,
+ baseQuery: app.application.baseQuery,
+ servicesEntities: app.application.servicesEntities.map((rec: string) => decodeURI(rec)),
+ traceGroups: app.application.traceGroups.map((rec: string) => decodeURI(rec)),
+ panelId: app.application.panelId,
+ availability: {
+ name: '',
+ color: '',
+ availabilityVisId: app.application.availabilityVisId || '',
+ },
+ };
} catch (err: any) {
throw new Error('Fetch Application By Id Error: ' + err);
}
@@ -52,22 +75,8 @@ export class AppAnalyticsAdaptor {
// Create a new application
createNewApp = async (
client: ILegacyScopedClusterClient,
- name: string,
- description: string,
- baseQuery: string,
- servicesEntities: string[],
- traceGroups: string[],
- availabilityVisId: string
+ appBody: Partial
) => {
- const appBody = {
- name,
- description,
- baseQuery,
- servicesEntities,
- traceGroups,
- availabilityVisId,
- };
-
try {
const response = await client.callAsCurrentUser('observability.createObject', {
body: {
@@ -102,7 +111,7 @@ export class AppAnalyticsAdaptor {
updateApp = async (
client: ILegacyScopedClusterClient,
appId: string,
- updateAppBody: Partial
+ updateAppBody: Partial
) => {
try {
const response = await client.callAsCurrentUser('observability.updateObjectById', {
diff --git a/dashboards-observability/server/routes/application_analytics/app_analytics_router.ts b/dashboards-observability/server/routes/application_analytics/app_analytics_router.ts
index 21bb8f17b..930e0d5f1 100644
--- a/dashboards-observability/server/routes/application_analytics/app_analytics_router.ts
+++ b/dashboards-observability/server/routes/application_analytics/app_analytics_router.ts
@@ -12,7 +12,7 @@ import {
ILegacyScopedClusterClient,
} from '../../../../../src/core/server';
import { APP_ANALYTICS_API_PREFIX as API_PREFIX } from '../../../common/constants/application_analytics';
-import { ApplicationListType } from '../../../common/types/app_analytics';
+import { ApplicationType } from '../../../common/types/application_analytics';
import { AppAnalyticsAdaptor } from '../../../server/adaptors/application_analytics/app_analytics_adaptor';
export function registerAppAnalyticsRouter(router: IRouter) {
@@ -32,7 +32,7 @@ export function registerAppAnalyticsRouter(router: IRouter) {
const opensearchClient: ILegacyScopedClusterClient = context.observability_plugin.observabilityClient.asScoped(
request
);
- let applicationsData: ApplicationListType[] = [];
+ let applicationsData: ApplicationType[] = [];
try {
applicationsData = await appAnalyticsBackend.fetchApps(opensearchClient);
return response.ok({
@@ -111,15 +111,7 @@ export function registerAppAnalyticsRouter(router: IRouter) {
);
try {
- const newAppId = await appAnalyticsBackend.createNewApp(
- opensearchClient,
- request.body.name,
- request.body.description || '',
- request.body.baseQuery,
- request.body.servicesEntities,
- request.body.traceGroups,
- request.body.availabilityVisId || ''
- );
+ const newAppId = await appAnalyticsBackend.createNewApp(opensearchClient, request.body);
return response.ok({
body: {
message: 'Application Created',
diff --git a/dashboards-observability/test/event_analytics_constants.ts b/dashboards-observability/test/event_analytics_constants.ts
index a8a3a70a6..f885dd37e 100644
--- a/dashboards-observability/test/event_analytics_constants.ts
+++ b/dashboards-observability/test/event_analytics_constants.ts
@@ -437,31 +437,31 @@ export const SAMPLE_VISUALIZATIONS = {
export const VISUALIZATION_TYPES = [
{
- fullLabel: 'Bar',
+ fulllabel: 'Bar',
id: 'bar',
label: 'bar',
selection: {
dataLoss: 'nothing'
},
- visualizationId: 'vis-bar-6636'
+ visualizationid: 'vis-bar-6636'
},
{
- fullLabel: 'H. Bar',
+ fulllabel: 'H. Bar',
id: 'horizontal_bar',
label: 'H. Bar',
selection: {
dataLoss: 'nothing'
},
- visualizationId: 'vis-bar-6637'
+ visualizationid: 'vis-bar-6637'
},
{
- fullLabel: 'Line',
+ fulllabel: 'Line',
id: 'line',
label: 'line',
selection: {
dataLoss: 'nothing'
},
- visualizationId: 'vis-bar-6638'
+ visualizationid: 'vis-bar-6638'
}
];
@@ -532,4 +532,3 @@ export const PIE_TEST_VISUALIZATIONS_DATA = {
...TEST_VISUALIZATIONS_DATA.vis
}
};
-
diff --git a/dashboards-observability/yarn.lock b/dashboards-observability/yarn.lock
index c205c9bf8..24d2a17b4 100644
--- a/dashboards-observability/yarn.lock
+++ b/dashboards-observability/yarn.lock
@@ -143,6 +143,11 @@
debug "^3.1.0"
lodash.once "^4.1.1"
+"@danieldietrich/copy@^0.4.2":
+ version "0.4.2"
+ resolved "https://registry.yarnpkg.com/@danieldietrich/copy/-/copy-0.4.2.tgz#c1cabfa499d8b473ba95413c446c1c1efae64d24"
+ integrity sha512-ZVNZIrgb2KeomfNahP77rL445ho6aQj0HHqU6hNlQ61o4rhvca+NS+ePj0d82zQDq2UPk1mjVZBTXgP+ErsDgw==
+
"@hypnosphi/create-react-context@^0.3.1":
version "0.3.1"
resolved "https://registry.yarnpkg.com/@hypnosphi/create-react-context/-/create-react-context-0.3.1.tgz#f8bfebdc7665f5d426cba3753e0e9c7d3154d7c6"
@@ -325,6 +330,18 @@ acorn@^7.1.1:
resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa"
integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==
+ag-grid-community@^27.3.0:
+ version "27.3.0"
+ resolved "https://registry.yarnpkg.com/ag-grid-community/-/ag-grid-community-27.3.0.tgz#b1e94a58026aaf2f0cd7920e35833325b5e762c7"
+ integrity sha512-R5oZMXEHXnOLrmhn91J8lR0bv6IAnRcU6maO+wKLMJxffRWaAYFAuw1jt7bdmcKCv8c65F6LEBx4ykSOALa9vA==
+
+ag-grid-react@^27.3.0:
+ version "27.3.0"
+ resolved "https://registry.yarnpkg.com/ag-grid-react/-/ag-grid-react-27.3.0.tgz#fe06647653f8b0b349b8e613aab8ea2e07915562"
+ integrity sha512-2bs9YfJ/shvBZQLLjny4NFvht+ic6VtpTPO0r3bHHOhlL3Fjx2rGvS6AHSwfvu+kJacHCta30PjaEbX8T3UDyw==
+ dependencies:
+ prop-types "^15.8.1"
+
ajv@^6.10.0, ajv@^6.10.2, ajv@^6.12.3:
version "6.12.6"
resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4"
@@ -384,6 +401,21 @@ ansi-to-react@^6.0.5:
anser "^1.4.1"
escape-carriage "^1.3.0"
+antlr4@4.8.0:
+ version "4.8.0"
+ resolved "https://registry.yarnpkg.com/antlr4/-/antlr4-4.8.0.tgz#f938ec171be7fc2855cd3a533e87647185b32b6a"
+ integrity sha512-en/MxQ4OkPgGJQ3wD/muzj1uDnFSzdFIhc2+c6bHZokWkuBb6RRvFjpWhPxWLbgQvaEzldJZ0GSQpfSAaE3hqg==
+
+antlr4ts-cli@^0.5.0-alpha.4:
+ version "0.5.0-alpha.4"
+ resolved "https://registry.yarnpkg.com/antlr4ts-cli/-/antlr4ts-cli-0.5.0-alpha.4.tgz#f3bfc37f10131e78d7b981c397a2aaa0450b67f6"
+ integrity sha512-lVPVBTA2CVHRYILSKilL6Jd4hAumhSZZWA7UbQNQrmaSSj7dPmmYaN4bOmZG79cOy0lS00i4LY68JZZjZMWVrw==
+
+antlr4ts@^0.5.0-alpha.4:
+ version "0.5.0-alpha.4"
+ resolved "https://registry.yarnpkg.com/antlr4ts/-/antlr4ts-0.5.0-alpha.4.tgz#71702865a87478ed0b40c0709f422cf14d51652a"
+ integrity sha512-WPQDt1B74OfPv/IMS2ekXAKkTZIHl88uMetg6q3OTqgFxZ/dxDXI0EWLyZid/1Pe6hTftyg5N7gel5wNAGxXyQ==
+
any-observable@^0.3.0:
version "0.3.0"
resolved "https://registry.yarnpkg.com/any-observable/-/any-observable-0.3.0.tgz#af933475e5806a67d0d7df090dd5e8bef65d119b"
@@ -1285,6 +1317,18 @@ glob@^7.1.3:
once "^1.3.0"
path-is-absolute "^1.0.0"
+glob@^7.1.7:
+ version "7.2.3"
+ resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b"
+ integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==
+ dependencies:
+ fs.realpath "^1.0.0"
+ inflight "^1.0.4"
+ inherits "2"
+ minimatch "^3.1.1"
+ once "^1.3.0"
+ path-is-absolute "^1.0.0"
+
global-dirs@^2.0.1:
version "2.1.0"
resolved "https://registry.yarnpkg.com/global-dirs/-/global-dirs-2.1.0.tgz#e9046a49c806ff04d6c1825e196c8f0091e8df4d"
@@ -1881,6 +1925,13 @@ minimatch@^3.0.4:
dependencies:
brace-expansion "^1.1.7"
+minimatch@^3.1.1:
+ version "3.1.2"
+ resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b"
+ integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==
+ dependencies:
+ brace-expansion "^1.1.7"
+
minimist@^1.2.5, minimist@^1.2.6:
version "1.2.6"
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44"
@@ -1901,9 +1952,9 @@ mkdirp@^0.5.4:
minimist "^1.2.5"
moment@^2.27.0:
- version "2.29.2"
- resolved "https://registry.yarnpkg.com/moment/-/moment-2.29.2.tgz#00910c60b20843bcba52d37d58c628b47b1f20e4"
- integrity sha512-UgzG4rvxYpN15jgCmVJwac49h9ly9NurikMWGPdVxm8GZD6XjkKPxDTjQQ43gtGgnV3X0cAyWDdP2Wexoquifg==
+ version "2.29.4"
+ resolved "https://registry.yarnpkg.com/moment/-/moment-2.29.4.tgz#3dbe052889fe7c1b2ed966fcb3a77328964ef108"
+ integrity sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==
ms@2.0.0:
version "2.0.0"
@@ -2099,6 +2150,17 @@ popper.js@^1.14.4, popper.js@^1.16.1:
resolved "https://registry.yarnpkg.com/popper.js/-/popper.js-1.16.1.tgz#2a223cb3dc7b6213d740e40372be40de43e65b1b"
integrity sha512-Wb4p1J4zyFTbM+u6WuO4XstYx4Ky9Cewe4DWrel7B0w6VVICvPwdOpotjzcf6eD8TsckVnIMNONQyPIUFOUbCQ==
+postinstall@^0.7.4:
+ version "0.7.4"
+ resolved "https://registry.yarnpkg.com/postinstall/-/postinstall-0.7.4.tgz#ab8de950f5d0350d753747c8b2606e347c80b3c8"
+ integrity sha512-jrItKnoJJCY6wuhP/LpTy5KyWJYUOOs+2477PUAXDCrJOZX2vgzCD3jgXawhJG4qdFxvAepaJLum1trieFbEuw==
+ dependencies:
+ "@danieldietrich/copy" "^0.4.2"
+ glob "^7.1.7"
+ minimist "^1.2.5"
+ resolve-from "^5.0.0"
+ resolve-pkg "^2.0.0"
+
prelude-ls@~1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54"
@@ -2133,6 +2195,15 @@ prop-types@^15.5.10, prop-types@^15.6.1, prop-types@^15.6.2, prop-types@^15.7.2:
object-assign "^4.1.1"
react-is "^16.8.1"
+prop-types@^15.8.1:
+ version "15.8.1"
+ resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5"
+ integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==
+ dependencies:
+ loose-envify "^1.4.0"
+ object-assign "^4.1.1"
+ react-is "^16.13.1"
+
property-information@^5.0.0:
version "5.6.0"
resolved "https://registry.yarnpkg.com/property-information/-/property-information-5.6.0.tgz#61675545fb23002f245c6540ec46077d4da3ed69"
@@ -2216,7 +2287,7 @@ react-graph-vis@^1.0.5:
vis-data "^7.1.2"
vis-network "^9.0.0"
-react-is@^16.8.1, react-is@^16.8.6:
+react-is@^16.13.1, react-is@^16.8.1, react-is@^16.8.6:
version "16.13.1"
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==
@@ -2248,6 +2319,13 @@ react-markdown@^4.0.0:
unist-util-visit "^1.3.0"
xtend "^4.0.1"
+react-paginate@^8.1.3:
+ version "8.1.3"
+ resolved "https://registry.yarnpkg.com/react-paginate/-/react-paginate-8.1.3.tgz#cd6f3cb8a56b47617a61a6a52e3d7c662ad9b91b"
+ integrity sha512-zBp80DBRcaeBnAeHUfbGKD0XHfbGNUolQ+S60Ymfs8o7rusYaJYZMAt1j93ADDNLlzRmJ0tMF/NeTlcdKf7dlQ==
+ dependencies:
+ prop-types "^15.6.1"
+
react-plotly.js@^2.5.1:
version "2.5.1"
resolved "https://registry.yarnpkg.com/react-plotly.js/-/react-plotly.js-2.5.1.tgz#11182bf599ef11a0dbfcd171c6f5645535a2b486"
@@ -2401,6 +2479,18 @@ resolve-from@^4.0.0:
resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6"
integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==
+resolve-from@^5.0.0:
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69"
+ integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==
+
+resolve-pkg@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/resolve-pkg/-/resolve-pkg-2.0.0.tgz#ac06991418a7623edc119084edc98b0e6bf05a41"
+ integrity sha512-+1lzwXehGCXSeryaISr6WujZzowloigEofRB+dj75y9RRa/obVcYgbHJd53tdYw8pvZj8GojXaaENws8Ktw/hQ==
+ dependencies:
+ resolve-from "^5.0.0"
+
restore-cursor@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-1.0.1.tgz#34661f46886327fed2991479152252df92daa541"
diff --git a/opensearch-observability/.gitignore b/opensearch-observability/.gitignore
index de6e7bf2c..74626e2b8 100644
--- a/opensearch-observability/.gitignore
+++ b/opensearch-observability/.gitignore
@@ -321,3 +321,5 @@ local.properties
local-test
.local-*
+
+/artifacts/
diff --git a/opensearch-observability/build.gradle b/opensearch-observability/build.gradle
index ea3d29465..4152a9054 100644
--- a/opensearch-observability/build.gradle
+++ b/opensearch-observability/build.gradle
@@ -10,7 +10,7 @@ import org.opensearch.gradle.testclusters.StandaloneRestIntegTestTask
buildscript {
ext {
isSnapshot = "true" == System.getProperty("build.snapshot", "true")
- opensearch_version = System.getProperty("opensearch.version", "2.0.0-SNAPSHOT")
+ opensearch_version = System.getProperty("opensearch.version", "2.2.0-SNAPSHOT")
buildVersionQualifier = System.getProperty("build.version_qualifier", "")
version_tokens = opensearch_version.tokenize('-')
opensearch_build = version_tokens[0] + '.0'
@@ -51,6 +51,7 @@ apply plugin: 'java'
apply plugin: 'jacoco'
apply plugin: 'idea'
apply plugin: 'opensearch.opensearchplugin'
+apply plugin: 'opensearch.pluginzip'
apply plugin: 'opensearch.testclusters'
apply plugin: 'io.gitlab.arturbosch.detekt'
apply plugin: 'org.jetbrains.kotlin.jvm'
@@ -68,6 +69,29 @@ opensearchplugin {
extendedPlugins = ['opensearch-job-scheduler']
}
+publishing {
+ publications {
+ pluginZip(MavenPublication) { publication ->
+ pom {
+ name = 'opensearch-observability'
+ description = 'OpenSearch Observability plugin'
+ licenses {
+ license {
+ name = 'The Apache License, Version 2.0'
+ url = 'http://www.apache.org/licenses/LICENSE-2.0.txt'
+ }
+ }
+ developers {
+ developer {
+ name = 'OpenSearch'
+ url = 'https://github.com/opensearch-project/observability'
+ }
+ }
+ }
+ }
+ }
+}
+
allOpen {
annotation("org.opensearch.observability.util.OpenForTesting")
}
@@ -91,6 +115,7 @@ configurations.all {
force "org.jetbrains.kotlin:kotlin-stdlib:${kotlin_version}"
force "org.jetbrains.kotlin:kotlin-stdlib-common:${kotlin_version}"
force "com.fasterxml.jackson.dataformat:jackson-dataformat-cbor:2.11.4"
+ force "org.mockito:mockito-core:4.6.1"
}
}
@@ -506,3 +531,20 @@ if (!usingRemoteCluster && !usingMultiNode) {
}
apply from: 'build-tools/pkgbuild.gradle'
+
+// updateVersion: Task to auto increment to the next development iteration
+task updateVersion {
+ onlyIf { System.getProperty('newVersion') }
+ doLast {
+ ext.newVersion = System.getProperty('newVersion')
+ println "Setting version to ${newVersion}."
+ // String tokenization to support -SNAPSHOT
+ ant.replaceregexp(file:'build.gradle', match: '"opensearch.version", "\\d.*"', replace: '"opensearch.version", "' + newVersion.tokenize('-')[0] + '-SNAPSHOT"', flags:'g', byline:true)
+ ant.replaceregexp(file:'../.github/workflows/dashboards-observability-test-and-build-workflow.yml', match:'OPENSEARCH_PLUGIN_VERSION: \\d+.\\d+.\\d+.\\d+', replace:'OPENSEARCH_PLUGIN_VERSION: ' + newVersion.tokenize('-')[0] + '.0', flags:'g', byline:true)
+ // Match key version in JSON files.
+ ant.replaceregexp(file:'../dashboards-observability/opensearch_dashboards.json', match:'"version": "\\d+.\\d+.\\d+.\\d+', replace:'"version": ' + '"' + newVersion.tokenize('-')[0] + '.0', flags:'g', byline:true)
+ ant.replaceregexp(file:'../dashboards-observability/package.json', match:'"version": "\\d+.\\d+.\\d+.\\d+', replace:'"version": ' + '"' + newVersion.tokenize('-')[0] + '.0', flags:'g', byline:true)
+ // Match key opensearchDashboardsVersion in JSON files.
+ ant.replaceregexp(file:'../dashboards-observability/opensearch_dashboards.json', match:'"opensearchDashboardsVersion": "\\d+.\\d+.\\d+', replace:'"opensearchDashboardsVersion": ' + '"' + newVersion.tokenize('-')[0], flags:'g', byline:true)
+ }
+}
diff --git a/opensearch-observability/gradle/wrapper/gradle-wrapper.properties b/opensearch-observability/gradle/wrapper/gradle-wrapper.properties
index 011069143..967533df8 100644
--- a/opensearch-observability/gradle/wrapper/gradle-wrapper.properties
+++ b/opensearch-observability/gradle/wrapper/gradle-wrapper.properties
@@ -4,7 +4,7 @@
##
#Wed Jul 29 13:30:55 PDT 2020
-distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-all.zip
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStorePath=wrapper/dists
diff --git a/opensearch-observability/scripts/build.sh b/opensearch-observability/scripts/build.sh
new file mode 100755
index 000000000..4b2893f30
--- /dev/null
+++ b/opensearch-observability/scripts/build.sh
@@ -0,0 +1,82 @@
+#!/bin/bash
+
+#
+# Copyright OpenSearch Contributors
+# SPDX-License-Identifier: Apache-2.0
+#
+
+set -ex
+
+function usage() {
+ echo "Usage: $0 [args]"
+ echo ""
+ echo "Arguments:"
+ echo -e "-v VERSION\t[Required] OpenSearch version."
+ echo -e "-q QUALIFIER\t[Optional] Version qualifier."
+ echo -e "-s SNAPSHOT\t[Optional] Build a snapshot, default is 'false'."
+ echo -e "-p PLATFORM\t[Optional] Platform, ignored."
+ echo -e "-a ARCHITECTURE\t[Optional] Build architecture, ignored."
+ echo -e "-o OUTPUT\t[Optional] Output path, default is 'artifacts'."
+ echo -e "-h help"
+}
+
+while getopts ":h:v:q:s:o:p:a:" arg; do
+ case $arg in
+ h)
+ usage
+ exit 1
+ ;;
+ v)
+ VERSION=$OPTARG
+ ;;
+ q)
+ QUALIFIER=$OPTARG
+ ;;
+ s)
+ SNAPSHOT=$OPTARG
+ ;;
+ o)
+ OUTPUT=$OPTARG
+ ;;
+ p)
+ PLATFORM=$OPTARG
+ ;;
+ a)
+ ARCHITECTURE=$OPTARG
+ ;;
+ :)
+ echo "Error: -${OPTARG} requires an argument"
+ usage
+ exit 1
+ ;;
+ ?)
+ echo "Invalid option: -${arg}"
+ exit 1
+ ;;
+ esac
+done
+
+if [ -z "$VERSION" ]; then
+ echo "Error: You must specify the OpenSearch version"
+ usage
+ exit 1
+fi
+
+[[ ! -z "$QUALIFIER" ]] && VERSION=$VERSION-$QUALIFIER
+[[ "$SNAPSHOT" == "true" ]] && VERSION=$VERSION-SNAPSHOT
+[ -z "$OUTPUT" ] && OUTPUT=artifacts
+
+mkdir -p $OUTPUT
+
+./gradlew assemble --no-daemon --refresh-dependencies -DskipTests=true -Dopensearch.version=$VERSION -Dbuild.snapshot=$SNAPSHOT -Dbuild.version_qualifier=$QUALIFIER
+
+zipPath=$(find . -path \*build/distributions/*.zip)
+distributions="$(dirname "${zipPath}")"
+
+echo "COPY ${distributions}/*.zip"
+mkdir -p $OUTPUT/plugins
+cp ${distributions}/*.zip ./$OUTPUT/plugins
+
+./gradlew publishPluginZipPublicationToZipStagingRepository -Dopensearch.version=$VERSION -Dbuild.snapshot=$SNAPSHOT -Dbuild.version_qualifier=$QUALIFIER
+mkdir -p $OUTPUT/maven/org/opensearch
+cp -r ./build/local-staging-repo/org/opensearch/. $OUTPUT/maven/org/opensearch
diff --git a/opensearch-observability/src/test/kotlin/org/opensearch/observability/PluginRestTestCase.kt b/opensearch-observability/src/test/kotlin/org/opensearch/observability/PluginRestTestCase.kt
index 759674eef..c5a1d4115 100644
--- a/opensearch-observability/src/test/kotlin/org/opensearch/observability/PluginRestTestCase.kt
+++ b/opensearch-observability/src/test/kotlin/org/opensearch/observability/PluginRestTestCase.kt
@@ -60,7 +60,7 @@ abstract class PluginRestTestCase : OpenSearchRestTestCase() {
open fun wipeAllOpenSearchIndices() {
if (preserveOpenSearchIndicesAfterTest()) return
val response = client().performRequest(Request("GET", "/_cat/indices?format=json&expand_wildcards=all"))
- val xContentType = XContentType.fromMediaTypeOrFormat(response.entity.contentType.value)
+ val xContentType = XContentType.fromMediaType(response.entity.contentType.value)
xContentType.xContent().createParser(
NamedXContentRegistry.EMPTY, DeprecationHandler.THROW_UNSUPPORTED_OPERATION,
response.entity.content
diff --git a/release-notes/opensearch-observability.release-notes-2.1.0.0.md b/release-notes/opensearch-observability.release-notes-2.1.0.0.md
new file mode 100644
index 000000000..fc8bc299a
--- /dev/null
+++ b/release-notes/opensearch-observability.release-notes-2.1.0.0.md
@@ -0,0 +1,15 @@
+## Version 2.1.0.0 Release Notes
+Compatible with OpenSearch and OpenSearch Dashboards Version 2.1.0
+
+### Enhancements
+* Add availability help flyout ([#734](https://github.com/opensearch-project/observability/pull/734))
+
+### Infrastructure
+* Uses custom plugin to publish zips to maven ([#786](https://github.com/opensearch-project/observability/pull/786))
+
+### Refactoring
+* Make common delete modal for components ([#766](https://github.com/opensearch-project/observability/pull/766))
+* Sync app and app list types ([#763](https://github.com/opensearch-project/observability/pull/763))
+
+### Maintenance
+* Bump version to 2.1.0 and gradle version to 7.4.2 ([#817](https://github.com/opensearch-project/observability/pull/817))
\ No newline at end of file
diff --git a/release-notes/opensearch-observability.release-notes-2.2.0.0.md b/release-notes/opensearch-observability.release-notes-2.2.0.0.md
new file mode 100644
index 000000000..239bd9fb9
--- /dev/null
+++ b/release-notes/opensearch-observability.release-notes-2.2.0.0.md
@@ -0,0 +1,5 @@
+## Version 2.2.0.0 Release Notes
+Compatible with OpenSearch and OpenSearch Dashboards Version 2.2.0
+
+### Maintenance
+* Bump version to 2.2.0 ([#918](https://github.com/opensearch-project/observability/pull/918))
\ No newline at end of file