1- import { useProfile } from '@linode/queries' ;
1+ import { useProfile , useRegionsQuery } from '@linode/queries' ;
22import { Box , Paper , Typography } from '@linode/ui' ;
33import { GridLegacy , Stack , useTheme } from '@mui/material' ;
44import { DateTime } from 'luxon' ;
@@ -7,6 +7,8 @@ import React from 'react';
77import { useFlags } from 'src/hooks/useFlags' ;
88import { useCloudPulseMetricsQuery } from 'src/queries/cloudpulse/metrics' ;
99
10+ import { useBlockStorageFetchOptions } from '../Alerts/CreateAlert/Criteria/DimensionFilterValue/useBlockStorageFetchOptions' ;
11+ import { useFirewallFetchOptions } from '../Alerts/CreateAlert/Criteria/DimensionFilterValue/useFirewallFetchOptions' ;
1012import { WidgetFilterGroupByRenderer } from '../GroupBy/WidgetFilterGroupByRenderer' ;
1113import {
1214 generateGraphData ,
@@ -18,10 +20,17 @@ import {
1820 SIZE ,
1921 TIME_GRANULARITY ,
2022} from '../Utils/constants' ;
21- import { constructAdditionalRequestFilters } from '../Utils/FilterBuilder' ;
23+ import {
24+ constructAdditionalRequestFilters ,
25+ constructWidgetDimensionFilters ,
26+ } from '../Utils/FilterBuilder' ;
27+ import { FILTER_CONFIG } from '../Utils/FilterConfig' ;
2228import { generateCurrentUnit } from '../Utils/unitConversion' ;
2329import { useAclpPreference } from '../Utils/UserPreference' ;
24- import { convertStringToCamelCasesWithSpaces } from '../Utils/utils' ;
30+ import {
31+ convertStringToCamelCasesWithSpaces ,
32+ getFilteredDimensions ,
33+ } from '../Utils/utils' ;
2534import { CloudPulseAggregateFunction } from './components/CloudPulseAggregateFunction' ;
2635import { CloudPulseIntervalSelect } from './components/CloudPulseIntervalSelect' ;
2736import { CloudPulseLineGraph } from './components/CloudPulseLineGraph' ;
@@ -30,6 +39,7 @@ import { ZoomIcon } from './components/Zoomer';
3039
3140import type { FilterValueType } from '../Dashboard/CloudPulseDashboardLanding' ;
3241import type { CloudPulseResources } from '../shared/CloudPulseResourcesSelect' ;
42+ import type { MetricsDimensionFilter } from './components/DimensionFilters/types' ;
3343import type {
3444 CloudPulseServiceType ,
3545 DateTimeWithPreset ,
@@ -183,6 +193,9 @@ export const CloudPulseWidget = (props: CloudPulseWidgetProperties) => {
183193 dashboardId,
184194 region,
185195 } = props ;
196+ const [ dimensionFilters , setDimensionFilters ] = React . useState <
197+ MetricsDimensionFilter [ ] | undefined
198+ > ( widget . filters ) ;
186199
187200 const timezone =
188201 duration . timeZone ?? profile ?. timezone ?? DateTime . local ( ) . zoneName ;
@@ -191,13 +204,93 @@ export const CloudPulseWidget = (props: CloudPulseWidgetProperties) => {
191204 const scaledWidgetUnit = React . useRef ( generateCurrentUnit ( unit ) ) ;
192205
193206 const jweTokenExpiryError = 'Token expired' ;
194- const filters : Filters [ ] | undefined =
195- additionalFilters ?. length || widget ?. filters ?. length
207+ const { data : regions } = useRegionsQuery ( ) ;
208+ const linodesFetch = useFirewallFetchOptions ( {
209+ dimensionLabel : 'linode_id' ,
210+ type : 'metrics' ,
211+ entities : entityIds ,
212+ regions : regions ?. filter ( ( region ) => region . id === linodeRegion ) ?? [ ] ,
213+ scope : 'entity' ,
214+ serviceType,
215+ associatedEntityType : FILTER_CONFIG . get ( dashboardId ) ?. associatedEntityType ,
216+ } ) ;
217+ const vpcFetch = useFirewallFetchOptions ( {
218+ dimensionLabel : 'vpc_subnet_id' ,
219+ type : 'metrics' ,
220+ entities : entityIds ,
221+ regions : regions ?. filter ( ( region ) => region . id === linodeRegion ) ?? [ ] ,
222+ scope : 'entity' ,
223+ serviceType,
224+ associatedEntityType : FILTER_CONFIG . get ( dashboardId ) ?. associatedEntityType ,
225+ } ) ;
226+ const linodeFromVolumes = useBlockStorageFetchOptions ( {
227+ entities : entityIds ,
228+ dimensionLabel : 'linode_id' ,
229+ regions : regions ?. filter ( ( { id } ) => id === region ) ?? [ ] ,
230+ type : 'metrics' ,
231+ scope : 'entity' ,
232+ serviceType,
233+ } ) ;
234+ // Determine which fetch object is relevant for linodes
235+ const activeLinodeFetch =
236+ serviceType === 'blockstorage' ? linodeFromVolumes : linodesFetch ;
237+
238+ // Combine loading states
239+ const isLoadingFilters = activeLinodeFetch . isLoading || vpcFetch . isLoading ;
240+
241+ const excludeDimensionFilters = React . useMemo ( ( ) => {
242+ return (
243+ FILTER_CONFIG . get ( dashboardId )
244+ ?. filters . filter (
245+ ( { configuration } ) => configuration . dimensionKey !== undefined
246+ )
247+ . map ( ( { configuration } ) => configuration . dimensionKey ) ?? [ ]
248+ ) ;
249+ } , [ dashboardId ] ) ;
250+ const filteredDimensions = React . useMemo ( ( ) => {
251+ return excludeDimensionFilters && excludeDimensionFilters . length > 0
252+ ? availableMetrics ?. dimensions . filter (
253+ ( { dimension_label : dimensionLabel } ) =>
254+ ! excludeDimensionFilters . includes ( dimensionLabel )
255+ )
256+ : availableMetrics ?. dimensions ;
257+ } , [ availableMetrics ?. dimensions , excludeDimensionFilters ] ) ;
258+
259+ const filteredSelections = React . useMemo ( ( ) => {
260+ if ( isLoadingFilters || ! flags . aclp ?. showWidgetDimensionFilters ) {
261+ return dimensionFilters ?? [ ] ;
262+ }
263+
264+ return getFilteredDimensions ( {
265+ dimensions : filteredDimensions ?? [ ] ,
266+ linodes : activeLinodeFetch ,
267+ vpcs : vpcFetch ,
268+ dimensionFilters,
269+ } ) ;
270+ } , [
271+ activeLinodeFetch ,
272+ dimensionFilters ,
273+ filteredDimensions ,
274+ flags . aclp ?. showWidgetDimensionFilters ,
275+ isLoadingFilters ,
276+ vpcFetch ,
277+ ] ) ;
278+
279+ const filters : Filters [ ] | undefined = React . useMemo ( ( ) => {
280+ return additionalFilters ?. length ||
281+ widget ?. filters ?. length ||
282+ dimensionFilters ?. length
196283 ? [
197284 ...constructAdditionalRequestFilters ( additionalFilters ?? [ ] ) ,
198- ...( widget . filters ?? [ ] ) ,
285+ ...[ ... ( constructWidgetDimensionFilters ( filteredSelections ) ?? [ ] ) ] , // dashboard level filters followed by widget filters
199286 ]
200287 : undefined ;
288+ } , [
289+ additionalFilters ,
290+ widget ?. filters ?. length ,
291+ dimensionFilters ?. length ,
292+ filteredSelections ,
293+ ] ) ;
201294
202295 /**
203296 *
@@ -274,6 +367,34 @@ export const CloudPulseWidget = (props: CloudPulseWidgetProperties) => {
274367 } ,
275368 [ ]
276369 ) ;
370+
371+ const handleDimensionFiltersChange = React . useCallback (
372+ ( selectedFilters : MetricsDimensionFilter [ ] ) => {
373+ if ( savePref ) {
374+ updatePreferences ( widget . label , {
375+ filters : selectedFilters
376+ . map ( ( filter ) => {
377+ if (
378+ filter . value !== null &&
379+ filter . dimension_label !== null &&
380+ filter . operator !== null
381+ ) {
382+ return {
383+ dimension_label : filter . dimension_label ,
384+ operator : filter . operator ,
385+ value : filter . value ,
386+ } ;
387+ } else {
388+ return undefined ;
389+ }
390+ } )
391+ . filter ( ( filter ) => filter !== undefined ) ,
392+ } ) ;
393+ }
394+ setDimensionFilters ( selectedFilters ) ;
395+ } ,
396+ [ savePref , updatePreferences , widget . label ]
397+ ) ;
277398 const {
278399 data : metricsList ,
279400 error,
@@ -295,6 +416,7 @@ export const CloudPulseWidget = (props: CloudPulseWidgetProperties) => {
295416 filters, // any additional dimension filters will be constructed and passed here
296417 } ,
297418 {
419+ isFiltersLoading : isLoadingFilters ,
298420 authToken,
299421 isFlags : Boolean ( flags && ! isJweTokenFetching ) ,
300422 label : widget . label ,
@@ -332,6 +454,24 @@ export const CloudPulseWidget = (props: CloudPulseWidgetProperties) => {
332454 const end = DateTime . fromISO ( duration . end , { zone : 'GMT' } ) ;
333455 const hours = end . diff ( start , 'hours' ) . hours ;
334456 const tickFormat = hours <= 24 ? 'hh:mm a' : 'LLL dd' ;
457+
458+ React . useEffect ( ( ) => {
459+ if (
460+ filteredSelections . length !== ( dimensionFilters ?. length ?? 0 ) &&
461+ ! linodesFetch . isLoading &&
462+ ! vpcFetch . isLoading &&
463+ ! linodeFromVolumes . isLoading
464+ ) {
465+ handleDimensionFiltersChange ( filteredSelections ) ;
466+ }
467+ } , [
468+ filteredSelections ,
469+ dimensionFilters ,
470+ handleDimensionFiltersChange ,
471+ linodesFetch . isLoading ,
472+ vpcFetch . isLoading ,
473+ linodeFromVolumes . isLoading ,
474+ ] ) ;
335475 return (
336476 < GridLegacy container item lg = { widget . size } xs = { 12 } >
337477 < Stack
@@ -394,11 +534,12 @@ export const CloudPulseWidget = (props: CloudPulseWidgetProperties) => {
394534 ) }
395535 < Box sx = { { display : 'flex' , gap : 2 } } >
396536 { flags . aclp ?. showWidgetDimensionFilters && (
397- < CloudPulseDimensionFiltersSelect // upcoming: Need to pass selected dimensions from widget in upcoming PR
398- dimensionOptions = { availableMetrics ?. dimensions ?? [ ] }
537+ < CloudPulseDimensionFiltersSelect
538+ dashboardId = { dashboardId }
539+ dimensionOptions = { filteredDimensions ?? [ ] }
399540 drawerLabel = { availableMetrics ?. label ?? '' }
400- handleSelectionChange = { ( ) => { } }
401- selectedDimensions = { [ ] }
541+ handleSelectionChange = { handleDimensionFiltersChange }
542+ selectedDimensions = { filteredSelections }
402543 selectedEntities = { entityIds }
403544 selectedRegions = { linodeRegion ? [ linodeRegion ] : undefined }
404545 serviceType = { serviceType }
0 commit comments