diff --git a/dashboards-observability/.cypress/integration/app_analytics.spec.js b/dashboards-observability/.cypress/integration/app_analytics.spec.js index c4da9da56..205d36fd1 100644 --- a/dashboards-observability/.cypress/integration/app_analytics.spec.js +++ b/dashboards-observability/.cypress/integration/app_analytics.spec.js @@ -27,7 +27,7 @@ import { visName, composition, newName, -} from '../utils/panel_constants'; +} from '../utils/app_constants'; import { supressResizeObserverIssue } from '../utils/constants'; describe('Creating application', () => { @@ -214,6 +214,7 @@ describe('Viewing application', () => { it('Opens trace detail flyout when Trace ID is clicked', () => { cy.get('.euiTab').contains('Traces & Spans').click(); + supressResizeObserverIssue(); cy.wait(delay); cy.get('[title="03f9c770db5ee2f1caac0afc36db49ba"]').click(); cy.get('.euiFlyout').contains('Trace detail').should('be.visible'); diff --git a/dashboards-observability/.cypress/utils/app_constants.js b/dashboards-observability/.cypress/utils/app_constants.js index 3a93b59cf..621d272c0 100644 --- a/dashboards-observability/.cypress/utils/app_constants.js +++ b/dashboards-observability/.cypress/utils/app_constants.js @@ -3,6 +3,8 @@ * SPDX-License-Identifier: Apache-2.0 */ +import { supressResizeObserverIssue } from './constants'; + export const delay = 700; export const moveToHomePage = () => { diff --git a/dashboards-observability/common/types/custom_panels.ts b/dashboards-observability/common/types/custom_panels.ts index 034fc02cf..e397b0607 100644 --- a/dashboards-observability/common/types/custom_panels.ts +++ b/dashboards-observability/common/types/custom_panels.ts @@ -33,6 +33,7 @@ export interface SavedVisualizationType { name: string; query: string; type: string; + selected_date_range: { start: string; end: string; text: string }; timeField: string; application_id?: string; user_configs: any; diff --git a/dashboards-observability/public/components/application_analytics/helpers/utils.tsx b/dashboards-observability/public/components/application_analytics/helpers/utils.tsx index b22eecb16..f368b3c70 100644 --- a/dashboards-observability/public/components/application_analytics/helpers/utils.tsx +++ b/dashboards-observability/public/components/application_analytics/helpers/utils.tsx @@ -10,6 +10,7 @@ import { FilterType } from 'public/components/trace_analytics/components/common/ import React, { Dispatch, ReactChild } from 'react'; import { batch } from 'react-redux'; import PPLService from 'public/services/requests/ppl'; +import { preprocessQuery } from '../../../../common/utils/query_utils'; import { SPAN_REGEX } from '../../../../common/constants/shared'; import { fetchVisualizationById } from '../../../components/custom_panels/helpers/utils'; import { CUSTOM_PANELS_API_PREFIX } from '../../../../common/constants/custom_panels'; @@ -210,10 +211,17 @@ export const calculateAvailability = async ( // If there are thresholds, we get the current value if (visData.user_configs.dataConfig?.hasOwnProperty('thresholds')) { const thresholds = visData.user_configs.dataConfig.thresholds.reverse(); - let currValue = ''; + let currValue = Number.MIN_VALUE; + const finalQuery = preprocessQuery({ + rawQuery: visData.query, + startTime: visData.selected_date_range.start, + endTime: visData.selected_date_range.end, + timeField: visData.timeField, + isLiveQuery: false, + }); await pplService .fetch({ - query: visData.query, + query: finalQuery, format: 'viz', }) .then((res) => { @@ -237,7 +245,7 @@ export const calculateAvailability = async ( const expression = threshold.expression; switch (expression) { case '>': - if (currValue > threshold.value) { + if (currValue > parseFloat(threshold.value)) { availability = { name: threshold.name, color: threshold.color, @@ -247,7 +255,7 @@ export const calculateAvailability = async ( } break; case '<': - if (currValue < threshold.value) { + if (currValue < parseFloat(threshold.value)) { availability = { name: threshold.name, color: threshold.color, @@ -257,7 +265,7 @@ export const calculateAvailability = async ( } break; case '=': - if (currValue === threshold.value) { + if (currValue === parseFloat(threshold.value)) { availability = { name: threshold.name, color: threshold.color, diff --git a/dashboards-observability/public/components/common/search/search.scss b/dashboards-observability/public/components/common/search/search.scss index 9becdf19d..1b0666a6d 100644 --- a/dashboards-observability/public/components/common/search/search.scss +++ b/dashboards-observability/public/components/common/search/search.scss @@ -28,7 +28,7 @@ #autocomplete-textarea { width: 100%; outline: none; - min-height: 45px; + min-height: 48px; max-width: unset; height: 45px; resize: vertical; diff --git a/dashboards-observability/public/components/custom_panels/custom_panel_view.tsx b/dashboards-observability/public/components/custom_panels/custom_panel_view.tsx index d2f442b1f..28d4b249c 100644 --- a/dashboards-observability/public/components/custom_panels/custom_panel_view.tsx +++ b/dashboards-observability/public/components/custom_panels/custom_panel_view.tsx @@ -462,6 +462,8 @@ export const CustomPanelView = ({ setPanelVisualizations={setPanelVisualizations} isFlyoutReplacement={isFlyoutReplacement} replaceVisualizationId={replaceVisualizationId} + appPanel={appPanel} + appId={appId} /> ); } @@ -678,15 +680,34 @@ export const CustomPanelView = ({ {appPanel && ( <> - - editPanel('edit')} - isDisabled={editDisabled} - > - Edit - - + {editMode ? ( + <> + + editPanel('cancel')} + > + Cancel + + + + editPanel('save')}> + Save + + + + ) : ( + + editPanel('edit')} + disabled={editDisabled} + > + Edit + + + )} { http={httpClientMock} pplService={pplService} isFlyoutReplacement={isFlyoutReplacement} + appPanel={false} /> ); @@ -68,6 +69,7 @@ describe('Visualization Flyout Component', () => { pplService={pplService} isFlyoutReplacement={isFlyoutReplacement} replaceVisualizationId={replaceVisualizationId} + appPanel={false} /> ); diff --git a/dashboards-observability/public/components/custom_panels/panel_modules/visualization_flyout/visualization_flyout.tsx b/dashboards-observability/public/components/custom_panels/panel_modules/visualization_flyout/visualization_flyout.tsx index 6a1cdd208..4fbea7141 100644 --- a/dashboards-observability/public/components/custom_panels/panel_modules/visualization_flyout/visualization_flyout.tsx +++ b/dashboards-observability/public/components/custom_panels/panel_modules/visualization_flyout/visualization_flyout.tsx @@ -2,6 +2,8 @@ * Copyright OpenSearch Contributors * SPDX-License-Identifier: Apache-2.0 */ +/* eslint-disable no-console */ +/* eslint-disable react-hooks/exhaustive-deps */ import { EuiButton, @@ -56,7 +58,7 @@ import { uiSettingsService } from '../../../../../common/utils'; * replaceVisualizationId: string id of the visualization to be replaced */ -type Props = { +interface VisualizationFlyoutProps { panelId: string; pplFilterValue: string; closeFlyout: () => void; @@ -73,10 +75,14 @@ type Props = { setPanelVisualizations: React.Dispatch>; isFlyoutReplacement?: boolean | undefined; replaceVisualizationId?: string | undefined; -}; + appPanel: boolean; + appId?: string; +} export const VisaulizationFlyout = ({ panelId, + appId, + appPanel, pplFilterValue, closeFlyout, start, @@ -87,11 +93,11 @@ export const VisaulizationFlyout = ({ setPanelVisualizations, isFlyoutReplacement, replaceVisualizationId, -}: Props) => { +}: VisualizationFlyoutProps) => { const [newVisualizationTitle, setNewVisualizationTitle] = useState(''); const [newVisualizationType, setNewVisualizationType] = useState(''); const [newVisualizationTimeField, setNewVisualizationTimeField] = useState(''); - const [previewMetaData, setPreviewMetaData] = useState(); + const [previewMetaData, setPreviewMetaData] = useState(); const [pplQuery, setPPLQuery] = useState(''); const [previewData, setPreviewData] = useState({} as pplResponse); const [previewArea, setPreviewArea] = useState(<>); @@ -125,7 +131,7 @@ export const VisaulizationFlyout = ({ http .post(`${CUSTOM_PANELS_API_PREFIX}/visualizations/replace`, { body: JSON.stringify({ - panelId: panelId, + panelId, savedVisualizationId: selectValue, oldVisualizationId: replaceVisualizationId, }), @@ -142,7 +148,7 @@ export const VisaulizationFlyout = ({ http .post(`${CUSTOM_PANELS_API_PREFIX}/visualizations`, { body: JSON.stringify({ - panelId: panelId, + panelId, savedVisualizationId: selectValue, }), }) @@ -259,7 +265,7 @@ export const VisaulizationFlyout = ({ ) : ( <> -
Please use the "create new visualization" option in add visualization menu.
+
{'Please use the "create new visualization" option in add visualization menu.'}
); @@ -286,8 +292,15 @@ export const VisaulizationFlyout = ({ .then((res) => { if (res.visualizations.length > 0) { setSavedVisualizations(res.visualizations); + const filterAppVis = res.visualizations.filter((vis: SavedVisualizationType) => { + return appPanel + ? vis.hasOwnProperty('application_id') + ? vis.application_id === appId + : false + : !vis.hasOwnProperty('application_id'); + }); setVisualizationOptions( - res.visualizations.map((visualization: SavedVisualizationType) => { + filterAppVis.map((visualization: SavedVisualizationType) => { return { value: visualization.id, text: visualization.name }; }) ); @@ -306,7 +319,7 @@ export const VisaulizationFlyout = ({ {previewLoading ? ( - ) : isPreviewError != '' ? ( + ) : isPreviewError !== '' ? (
@@ -328,7 +341,7 @@ export const VisaulizationFlyout = ({ // On change of selected visualization change options useEffect(() => { - for (var i = 0; i < savedVisualizations.length; i++) { + for (let i = 0; i < savedVisualizations.length; i++) { const visualization = savedVisualizations[i]; if (visualization.id === selectValue) { setPPLQuery(visualization.query); diff --git a/dashboards-observability/public/components/explorer/visualizations/config_panel/config_editor/config_controls/config_thresholds.tsx b/dashboards-observability/public/components/explorer/visualizations/config_panel/config_editor/config_controls/config_thresholds.tsx index 81906ed66..db2aaf2b2 100644 --- a/dashboards-observability/public/components/explorer/visualizations/config_panel/config_editor/config_controls/config_thresholds.tsx +++ b/dashboards-observability/public/components/explorer/visualizations/config_panel/config_editor/config_controls/config_thresholds.tsx @@ -67,7 +67,7 @@ export const ConfigThresholds = ({ if (thrId !== th.thid) return th; return { ...th, - [thrName]: event?.target?.value || '', + [thrName]: (thrName === 'color' ? event : event?.target?.value) || '', }; }), ]); @@ -139,7 +139,7 @@ export const ConfigThresholds = ({ { await http .get(`${CUSTOM_PANELS_API_PREFIX}/visualizations`) .then((res) => { - opt2 = res.visualizations.map((vizObject) => ({ + const noAppVisualizations = res.visualizations.filter((vis) => { + return !!!vis.application_id; + }); + opt2 = noAppVisualizations.map((vizObject) => ({ label: vizObject.name, key: vizObject.id, className: 'OBSERVABILITY_VISUALIZATION', diff --git a/dashboards-observability/public/components/trace_analytics/components/dashboard/dashboard_table.tsx b/dashboards-observability/public/components/trace_analytics/components/dashboard/dashboard_table.tsx index 43315aeec..55af82ba4 100644 --- a/dashboards-observability/public/components/trace_analytics/components/dashboard/dashboard_table.tsx +++ b/dashboards-observability/public/components/trace_analytics/components/dashboard/dashboard_table.tsx @@ -112,7 +112,11 @@ export function DashboardTable(props: { }) } > - {item.length < 48 ? item :
{_.truncate(item, { length: 48 })}
} + {item.length < 48 ? ( + decodeURI(item) + ) : ( +
{_.truncate(decodeURI(item), { length: 48 })}
+ )} ) : ( '-' diff --git a/dashboards-observability/server/adaptors/custom_panels/custom_panel_adaptor.ts b/dashboards-observability/server/adaptors/custom_panels/custom_panel_adaptor.ts index 15847404a..a11bff645 100644 --- a/dashboards-observability/server/adaptors/custom_panels/custom_panel_adaptor.ts +++ b/dashboards-observability/server/adaptors/custom_panels/custom_panel_adaptor.ts @@ -4,11 +4,7 @@ */ import { v4 as uuidv4 } from 'uuid'; -import { - CustomPanelListType, - PanelType, - VisualizationType, -} from '../../../common/types/custom_panels'; +import { PanelType, VisualizationType } from '../../../common/types/custom_panels'; import { ILegacyScopedClusterClient } from '../../../../../src/core/server'; import { createDemoPanel } from '../../common/helpers/custom_panels/sample_panels'; @@ -211,7 +207,7 @@ export class CustomPanelsAdaptor { } }; - // parses fetched saved visualization + // parses fetched saved visualization parseSavedVisualizations = (visualization: any) => { return { id: visualization.objectId, @@ -224,6 +220,9 @@ export class CustomPanelsAdaptor { user_configs: visualization.savedVisualization.hasOwnProperty('user_configs') ? JSON.parse(visualization.savedVisualization.user_configs) : {}, + ...(visualization.savedVisualization.application_id + ? { application_id: visualization.savedVisualization.application_id } + : {}), }; }; @@ -233,11 +232,9 @@ export class CustomPanelsAdaptor { const response = await client.callAsCurrentUser('observability.getObject', { objectType: 'savedVisualization', }); - return response.observabilityObjectList - .filter((visualization: any) => { - return !!!visualization.savedVisualization.application_id; - }) - .map((visualization: any) => this.parseSavedVisualizations(visualization)); + return response.observabilityObjectList.map((visualization: any) => + this.parseSavedVisualizations(visualization) + ); } catch (error) { throw new Error('View Saved Visualizations Error:' + error); } @@ -334,13 +331,13 @@ export class CustomPanelsAdaptor { const allPanelVisualizations = await this.getVisualizations(client, panelId); let newDimensions; - let visualizationsList = []; + let visualizationsList = [] as VisualizationType[]; if (oldVisualizationId === undefined) { newDimensions = this.getNewVizDimensions(allPanelVisualizations); visualizationsList = allPanelVisualizations; } else { allPanelVisualizations.map((visualization: VisualizationType) => { - if (visualization.id != oldVisualizationId) { + if (visualization.id !== oldVisualizationId) { visualizationsList.push(visualization); } else { newDimensions = { @@ -383,7 +380,7 @@ export class CustomPanelsAdaptor { ) => { try { const allPanelVisualizations = await this.getVisualizations(client, panelId); - const filteredPanelVisualizations = []; + const filteredPanelVisualizations = [] as VisualizationType[]; for (let i = 0; i < allPanelVisualizations.length; i++) { for (let j = 0; j < visualizationParams.length; j++) {