diff --git a/public/components/custom_panels/helpers/utils.tsx b/public/components/custom_panels/helpers/utils.tsx
index 9abc0d8d7..e06c795df 100644
--- a/public/components/custom_panels/helpers/utils.tsx
+++ b/public/components/custom_panels/helpers/utils.tsx
@@ -259,25 +259,34 @@ const dynamicLayoutFromQueryData = (queryData) => {
};
};
-const createCatalogVisualizationMetaData = (
- catalogSource: string,
- visualizationQuery: string,
- visualizationType: string,
- visualizationTimeField: string,
- queryData: object
-) => {
+const createCatalogVisualizationMetaData = ({
+ catalogSource,
+ query,
+ type,
+ subType,
+ timeField,
+ queryData,
+}: {
+ catalogSource: string;
+ query: string;
+ type: string;
+ subType: string;
+ timeField: string;
+ queryData: object;
+}) => {
return {
name: catalogSource,
description: '',
- query: visualizationQuery,
- type: visualizationType,
+ query,
+ type,
+ subType,
selected_date_range: {
start: 'now/y',
end: 'now',
text: '',
},
selected_timestamp: {
- name: visualizationTimeField,
+ name: timeField,
type: 'timestamp',
},
selected_fields: {
@@ -332,6 +341,7 @@ export const renderCatalogVisualization = async ({
const visualizationType = 'line';
const visualizationTimeField = '@timestamp';
+ const visualizationSubType = visualization.subType;
const visualizationQuery = updateCatalogVisualizationQuery({
...visualization.queryMetaData,
@@ -357,15 +367,15 @@ export const renderCatalogVisualization = async ({
);
setVisualizationData(queryData);
- const visualizationMetaData = createCatalogVisualizationMetaData(
+ const visualizationMetaData = createCatalogVisualizationMetaData({
catalogSource,
- visualizationQuery,
- visualizationType,
- visualizationTimeField,
- queryData
- );
+ query: visualizationQuery,
+ type: visualizationType,
+ subType: visualization.subType,
+ timeField: visualizationTimeField,
+ queryData,
+ });
- console.log('renderCatalogVisualization', { visualizationMetaData });
setVisualizationMetaData(visualizationMetaData);
} catch (error) {
setIsError({ error });
diff --git a/public/components/custom_panels/panel_modules/visualization_container/visualization_container.tsx b/public/components/custom_panels/panel_modules/visualization_container/visualization_container.tsx
index 3d52f9edd..dd0a47300 100644
--- a/public/components/custom_panels/panel_modules/visualization_container/visualization_container.tsx
+++ b/public/components/custom_panels/panel_modules/visualization_container/visualization_container.tsx
@@ -37,7 +37,10 @@ import './visualization_container.scss';
import { VizContainerError } from '../../../../../common/types/custom_panels';
import { metricQuerySelector } from '../../../metrics/redux/slices/metrics_slice';
import { coreRefs } from '../../../../framework/core_refs';
-import { PROMQL_METRIC_SUBTYPE } from '../../../../../common/constants/shared';
+import {
+ observabilityMetricsID,
+ PROMQL_METRIC_SUBTYPE,
+} from '../../../../../common/constants/shared';
/*
* Visualization container - This module is a placeholder to add visualizations in react-grid-layout
@@ -78,6 +81,7 @@ interface Props {
removeVisualization?: (visualizationId: string) => void;
catalogVisualization?: boolean;
inlineEditor?: JSX.Element;
+ actionMenuType?: string;
}
export const VisualizationContainer = ({
@@ -98,6 +102,7 @@ export const VisualizationContainer = ({
removeVisualization,
catalogVisualization,
inlineEditor,
+ actionMenuType,
}: Props) => {
const [isPopoverOpen, setIsPopoverOpen] = useState(false);
const [visualizationTitle, setVisualizationTitle] = useState('');
@@ -175,7 +180,11 @@ export const VisualizationContainer = ({
disabled={editMode}
onClick={() => {
closeActionsMenu();
- onEditClick(savedVisualizationId);
+ if (visualizationMetaData?.subType === PROMQL_METRIC_SUBTYPE) {
+ window.location.assign(`${observabilityMetricsID}#/${savedVisualizationId}`);
+ } else {
+ onEditClick(savedVisualizationId);
+ }
}}
>
Edit
@@ -217,7 +226,10 @@ export const VisualizationContainer = ({
,
];
- if (visualizationMetaData?.subType === PROMQL_METRIC_SUBTYPE) {
+ if (
+ visualizationMetaData?.subType === PROMQL_METRIC_SUBTYPE &&
+ actionMenuType === 'metricsGrid'
+ ) {
popoverPanel = [showPPLQueryPanel];
} else if (usedInNotebooks) {
popoverPanel = [popoverPanel[0]];
diff --git a/public/components/metrics/redux/slices/metrics_slice.ts b/public/components/metrics/redux/slices/metrics_slice.ts
index 73972b2d1..f623585c3 100644
--- a/public/components/metrics/redux/slices/metrics_slice.ts
+++ b/public/components/metrics/redux/slices/metrics_slice.ts
@@ -3,8 +3,8 @@
* SPDX-License-Identifier: Apache-2.0
*/
-import { createAsyncThunk, createSlice } from '@reduxjs/toolkit';
-import { keyBy, mergeWith, pick, sortBy, merge } from 'lodash';
+import { createSlice } from '@reduxjs/toolkit';
+import { keyBy, mergeWith, pick, sortBy } from 'lodash';
import { ouiPaletteColorBlindBehindText } from '@elastic/eui';
import {
OBSERVABILITY_CUSTOM_METRIC,
@@ -18,7 +18,7 @@ import { ObservabilitySavedVisualization } from '../../../../services/saved_obje
import { pplServiceRequestor } from '../../helpers/utils';
import { coreRefs } from '../../../../framework/core_refs';
import { PPL_METRIC_SUBTYPE, PROMQL_METRIC_SUBTYPE } from '../../../../../common/constants/shared';
-import { getOSDHttp, getPPLService } from '../../../../../common/utils';
+import { getPPLService } from '../../../../../common/utils';
export interface IconAttributes {
color: string;
@@ -38,6 +38,14 @@ const coloredIconsFrom = (dataSources: string[]): { [dataSource: string]: IconAt
return Object.fromEntries(keyedIcons);
};
+export interface DateSpanFilter {
+ start: string;
+ end: string;
+ span: number;
+ resolution: string;
+ recentlyUsedRanges: string[];
+}
+
const initialState = {
metrics: {},
selectedIds: [],
@@ -66,8 +74,13 @@ const mergeMetricCustomizer = function (objValue, srcValue) {
: srcValue.availableAttributes,
};
};
+export const mergeMetrics = (newMetricMap) => (dispatch, getState) => {
+ const { metrics } = getState().metrics;
+ const modifiableMetricsMap = { ...metrics };
-const now = () => new Date().getMilliseconds();
+ const mergedMetrics = mergeWith(modifiableMetricsMap, newMetricMap, mergeMetricCustomizer);
+ dispatch(setMetrics(mergedMetrics));
+};
export const loadMetrics = () => async (dispatch) => {
const pplService = getPPLService();
@@ -81,15 +94,15 @@ export const loadMetrics = () => async (dispatch) => {
setDataSourceIcons(coloredIconsFrom([OBSERVABILITY_CUSTOM_METRIC, ...remoteDataSources]))
);
- const remoteDataRequests = fetchRemoteMetrics(remoteDataSources);
+ const remoteDataRequests = await fetchRemoteMetrics(remoteDataSources);
const metricsResultSet = await Promise.all([customDataRequest, ...remoteDataRequests]);
const metricsResult = metricsResultSet.flat();
const metricsMapById = keyBy(metricsResult.flat(), 'id');
- await dispatch(mergeMetrics(metricsMapById));
+ dispatch(mergeMetrics(metricsMapById));
const sortedIds = sortBy(metricsResult, 'catalog', 'id').map((m) => m.id);
- await dispatch(setSortedIds(sortedIds));
+ dispatch(setSortedIds(sortedIds));
};
const fetchCustomMetrics = async () => {
@@ -150,17 +163,9 @@ export const metricSlice = createSlice({
name: REDUX_SLICE_METRICS,
initialState,
reducers: {
- mergeMetrics: (state, { payload }) => {
- const { metrics } = state;
- const modifiableMetricsMap = { ...metrics };
-
- const mergedMetrics = mergeWith(modifiableMetricsMap, payload, mergeMetricCustomizer);
- state.metrics = mergedMetrics;
+ setMetrics: (state, { payload }) => {
+ state.metrics = payload;
},
-
- // setMetrics: (state, { payload }) => {
- // state.metrics = payload;
- // },
setMetric: (state, { payload }) => {
state.metrics[payload.id] = payload;
},
@@ -202,15 +207,19 @@ export const metricSlice = createSlice({
setDataSourceIcons: (state, { payload }) => {
state.dataSourceIcons = payload;
},
+ setDateSpan: (state, { payload }) => {
+ state.dateSpanFilter = { ...state.dateSpanFilter, ...payload };
+ },
+ setRefresh: (state) => {
+ state.refresh = Date.now();
+ },
},
});
export const {
- setMetrics,
deSelectMetric,
clearSelectedMetrics,
-
- mergeMetrics,
+ selectMetric,
moveMetric,
setSearch,
setDateSpan,
@@ -222,7 +231,7 @@ export const {
/** private actions */
-const { selectMetric, setMetric, setSortedIds } = metricSlice.actions;
+const { setMetrics, setMetric, setSortedIds } = metricSlice.actions;
const getAvailableAttributes = (id, metricIndex) => async (dispatch, getState) => {
const { toasts } = coreRefs;
@@ -295,16 +304,12 @@ export const availableMetricsSelector = (state) => {
export const selectedMetricsSelector = (state) =>
pick(state.metrics.metrics, state.metrics.selectedIds) ?? {};
-export const selectedMetricByIdSelector = (id) => (state) => state.metrics.metrics[id];
-
export const selectedMetricsIdsSelector = (state) => state.metrics.selectedIds ?? [];
export const searchSelector = (state) => state.metrics.search;
export const metricIconsSelector = (state) => state.metrics.dataSourceIcons;
-export const metricsLayoutSelector = (state) => state.metrics.metricsLayout;
-
export const dateSpanFilterSelector = (state) => state.metrics.dateSpanFilter;
export const refreshSelector = (state) => state.metrics.refresh;
diff --git a/public/components/metrics/sidebar/sidebar.tsx b/public/components/metrics/sidebar/sidebar.tsx
index 6afb40c1f..ac93037fc 100644
--- a/public/components/metrics/sidebar/sidebar.tsx
+++ b/public/components/metrics/sidebar/sidebar.tsx
@@ -43,10 +43,12 @@ export const Sidebar = ({
useEffect(() => {
if (additionalMetric) {
- dispatch(clearSelectedMetrics());
- dispatch(addSelectedMetric(additionalMetric));
+ (async function () {
+ await dispatch(clearSelectedMetrics());
+ await dispatch(addSelectedMetric(additionalMetric));
+ })();
}
- }, [additionalMetric]);
+ }, [additionalMetric?.id]);
const selectedMetricsList = useMemo(() => {
return selectedMetricsIds.map((id) => selectedMetrics[id]).filter((m) => m); // filter away null entries
diff --git a/public/components/metrics/view/metrics_grid.tsx b/public/components/metrics/view/metrics_grid.tsx
index 2c4122455..161431918 100644
--- a/public/components/metrics/view/metrics_grid.tsx
+++ b/public/components/metrics/view/metrics_grid.tsx
@@ -4,7 +4,7 @@
*/
import React, { useEffect, useMemo } from 'react';
-import { EuiDragDropContext, EuiDraggable, EuiDroppable } from '@elastic/eui';
+import { EuiContextMenuItem, EuiDragDropContext, EuiDraggable, EuiDroppable } from '@elastic/eui';
import { useObservable } from 'react-use';
import { connect } from 'react-redux';
import { CoreStart } from '../../../../../../src/core/public';
@@ -53,6 +53,19 @@ const visualizationFromMetric = (metric, dateSpanFilter): SavedVisualizationType
},
});
+const promQLActionMenu = [
+ {
+ closeActionsMenu();
+ showModal('catalogModal');
+ }}
+ >
+ View query
+ ,
+];
+
const navigateToEventExplorerVisualization = (savedVisualizationId: string) => {
window.location.assign(`${observabilityLogsID}#/explorer/${savedVisualizationId}`);
};
@@ -80,6 +93,7 @@ export const InnerGridVisualization = ({ id, idx, dateSpanFilter, metric, refres
inlineEditor={
metric.subType === PROMQL_METRIC_SUBTYPE &&
}
+ actionMenuType="metricsGrid"
/>
);
diff --git a/public/services/requests/ppl.ts b/public/services/requests/ppl.ts
index 72fb58f33..2ab46e8b3 100644
--- a/public/services/requests/ppl.ts
+++ b/public/services/requests/ppl.ts
@@ -9,6 +9,7 @@ import { PPL_BASE, PPL_SEARCH } from '../../../common/constants/shared';
/* eslint-disable import/no-default-export */
export default class PPLService {
private http;
+
constructor(http: CoreStart['http']) {
this.http = http;
}
@@ -20,7 +21,6 @@ export default class PPLService {
},
errorHandler?: (error: any) => void
) => {
- console.log('real fetch');
return this.http
.post(`${PPL_BASE}${PPL_SEARCH}`, {
body: JSON.stringify(params),