@@ -10,12 +10,14 @@ import {
1010 validateVariableName ,
1111} from '@hyperdx/common-utils/dist/filters' ;
1212import {
13+ ChartVariable ,
1314 DashboardFilter ,
1415 MetricsDataType ,
1516 SourceKind ,
1617 TSource ,
1718} from '@hyperdx/common-utils/dist/types' ;
1819import {
20+ Alert ,
1921 Box ,
2022 Button ,
2123 Center ,
@@ -33,6 +35,7 @@ import {
3335 UnstyledButton ,
3436} from '@mantine/core' ;
3537import {
38+ IconAlertTriangle ,
3639 IconFilter ,
3740 IconInfoCircle ,
3841 IconPencil ,
@@ -46,6 +49,7 @@ import SearchWhereInput, {
4649 getStoredLanguage ,
4750} from '@/components/SearchInput/SearchWhereInput' ;
4851import { SQLInlineEditorControlled } from '@/components/SQLEditor/SQLInlineEditor' ;
52+ import { SqlVariablesProvider } from '@/components/SQLEditor/variableCompletions' ;
4953
5054import { SourceMultiSelectControlled } from './components/SourceMultiSelect' ;
5155import SourceSchemaPreview , {
@@ -158,11 +162,30 @@ const DashboardFilterEditForm = ({
158162 [ filters , filter . id ] ,
159163 ) ;
160164
161- const [ formFilterName , formIsBroadCastEnabled , formIsVariableEnabled ] =
162- useWatch ( {
163- control,
164- name : [ 'name' , 'isBroadcastEnabled' , 'isVariableEnabled' ] ,
165- } ) ;
165+ const [
166+ formFilterName ,
167+ formIsBroadCastEnabled ,
168+ formIsVariableEnabled ,
169+ formAppliesToSourceIds ,
170+ ] = useWatch ( {
171+ control,
172+ name : [
173+ 'name' ,
174+ 'isBroadcastEnabled' ,
175+ 'isVariableEnabled' ,
176+ 'appliesToSourceIds' ,
177+ ] ,
178+ } ) ;
179+
180+ // Both modes on with an unrestricted broadcast is almost always a mistake:
181+ // broadcast already reaches every tile, so the variable adds nothing and the
182+ // tiles that reference it get filtered twice over. Scoping the broadcast is
183+ // what makes the pair meaningful, so nudge toward "Applies to sources".
184+ const showUnscopedBroadcastWarning =
185+ showVariableOptions &&
186+ formIsBroadCastEnabled !== false &&
187+ formIsVariableEnabled === true &&
188+ ! formAppliesToSourceIds ?. some ( id => ! ! id ?. length ) ;
166189
167190 const derivedVariableName = deriveVariableName ( formFilterName ?? '' ) ;
168191
@@ -359,7 +382,7 @@ const DashboardFilterEditForm = ({
359382
360383 < CustomInputWrapper
361384 label = "Dropdown values filter"
362- tooltipText = "Optional condition used to filter the rows from which available filter values are queried"
385+ tooltipText = "Optional condition used to filter the rows from which available filter values are queried. May reference the dashboard's other variables. "
363386 >
364387 < SearchWhereInput
365388 tableConnection = { tableConnection }
@@ -371,6 +394,7 @@ const DashboardFilterEditForm = ({
371394 allowMultiline = { true }
372395 sqlPlaceholder = "Filter for dropdown values"
373396 lucenePlaceholder = "Filter for dropdown values"
397+ enableVariables = { showVariableOptions }
374398 />
375399 </ CustomInputWrapper >
376400
@@ -382,7 +406,7 @@ const DashboardFilterEditForm = ({
382406 name = "isBroadcastEnabled"
383407 size = "xs"
384408 label = "Broadcast filter condition"
385- description = "Apply the selected value as a filter condition on each tile."
409+ description = "Automatically apply the selected value to every query builder tile, and to every Raw SQL tile that uses the $__filters macro. Optionally, narrow to tiles that use specific sources ."
386410 data-testid = "filter-broadcast-checkbox"
387411 />
388412 </ >
@@ -396,7 +420,7 @@ const DashboardFilterEditForm = ({
396420 < Box ml = { showVariableOptions ? 'xl' : undefined } >
397421 < CustomInputWrapper
398422 label = "Applies to sources"
399- tooltipText = "Leave empty to apply to all tiles. Selecting one or more sources restricts the filter to only tiles using those sources."
423+ tooltipText = "Which tiles the broadcast reaches. Leave empty to broadcast to all tiles. Selecting one or more sources restricts the broadcast to tiles using those sources."
400424 >
401425 < SourceMultiSelectControlled
402426 control = { control }
@@ -422,7 +446,7 @@ const DashboardFilterEditForm = ({
422446 name = "isVariableEnabled"
423447 size = "xs"
424448 label = "Available as variable"
425- description = "Expose the selected value a $variable."
449+ description = "Expose the selected value as a $variable. Selections only affect tiles that reference the variable explicitly, typically via the $__filter or $__conditionalAll macros ."
426450 data-testid = "filter-variable-enabled-checkbox"
427451 rules = { { validate : validateFilterModes } }
428452 />
@@ -444,6 +468,19 @@ const DashboardFilterEditForm = ({
444468 </ CustomInputWrapper >
445469 </ Box >
446470 ) }
471+ { showUnscopedBroadcastWarning && (
472+ < Alert
473+ variant = "warning"
474+ icon = { < IconAlertTriangle size = { 16 } /> }
475+ data-testid = "filter-unscoped-broadcast-warning"
476+ >
477+ Broadcast already applies this filter to every tile,
478+ including the ones that reference the variable. Set “Applies
479+ to sources” to limit which tiles the broadcast reaches, or
480+ turn off broadcast so only tiles that reference the variable
481+ are filtered.
482+ </ Alert >
483+ ) }
447484 </ >
448485 ) }
449486
@@ -652,6 +689,8 @@ interface DashboardFiltersEditModalProps {
652689 source ?: TSource ;
653690 /** Whether to offer the broadcast / variable controls. */
654691 showVariableOptions : boolean ;
692+ /** The dashboard's variables, if any */
693+ variables ?: ChartVariable [ ] ;
655694 onClose : ( ) => void ;
656695 onSaveFilter : ( filter : DashboardFilter ) => void ;
657696 onRemoveFilter : ( id : string ) => void ;
@@ -665,6 +704,7 @@ const DashboardFiltersModal = ({
665704 isLoading,
666705 source,
667706 showVariableOptions,
707+ variables,
668708 onClose,
669709 onSaveFilter,
670710 onRemoveFilter,
@@ -694,10 +734,7 @@ const DashboardFiltersModal = ({
694734 where : '' ,
695735 whereLanguage : getStoredLanguage ( ) ?? 'sql' ,
696736 isBroadcastEnabled : true ,
697- // New filters are variable-enabled wherever the controls are available, so
698- // the checkbox is controlled from the first render. Callers that hide the
699- // controls get false, since their UI offers no way to turn it back off.
700- isVariableEnabled : showVariableOptions ,
737+ isVariableEnabled : false ,
701738 } ) ;
702739 } ;
703740
@@ -719,16 +756,18 @@ const DashboardFiltersModal = ({
719756 return < EmptyState onCreateFilter = { handleAddNewFilter } onClose = { onClose } /> ;
720757 } else if ( selectedFilter ) {
721758 return (
722- < DashboardFilterEditForm
723- filter = { selectedFilter }
724- onSave = { handleSaveFilter }
725- onCancel = { ( ) => setSelectedFilter ( undefined ) }
726- onClose = { onClose }
727- isNew = { selectedFilter . id === NEW_FILTER_ID }
728- source = { source }
729- filters = { filters }
730- showVariableOptions = { showVariableOptions }
731- />
759+ < SqlVariablesProvider variables = { variables } >
760+ < DashboardFilterEditForm
761+ filter = { selectedFilter }
762+ onSave = { handleSaveFilter }
763+ onCancel = { ( ) => setSelectedFilter ( undefined ) }
764+ onClose = { onClose }
765+ isNew = { selectedFilter . id === NEW_FILTER_ID }
766+ source = { source }
767+ filters = { filters }
768+ showVariableOptions = { showVariableOptions }
769+ />
770+ </ SqlVariablesProvider >
732771 ) ;
733772 } else {
734773 return (
0 commit comments