Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
6193573
[DI-29170] - Changes for value field limitation
venkymano-akamai Feb 4, 2026
338ffc1
[DI-29170] - Changes for value field limitation
venkymano-akamai Feb 4, 2026
aaa90f5
[DI-29170] - Changes for value field limitation
venkymano-akamai Feb 4, 2026
584545e
Merge branch 'develop' into value_field_dimension_filter_limit
venkymano-akamai Feb 4, 2026
99b7128
[DI-29170] - Changes for value field limitation
venkymano-akamai Feb 4, 2026
7b76be2
Merge branch 'value_field_dimension_filter_limit' of github.com:venky…
venkymano-akamai Feb 4, 2026
6f408a4
Merge branch 'develop' into value_field_dimension_filter_limit
venkymano-akamai Feb 4, 2026
bcc9c0c
[DI-29170] - Message change
venkymano-akamai Feb 4, 2026
1d6b769
Merge branch 'value_field_dimension_filter_limit' of github.com:venky…
venkymano-akamai Feb 4, 2026
2972e44
[DI-29170] - Message change
venkymano-akamai Feb 4, 2026
e4d5212
[DI-29170] - Move logic to constants
venkymano-akamai Feb 4, 2026
0e7068a
[DI-29170] - Changes for utils
venkymano-akamai Feb 4, 2026
d0f93c0
[DI-29170] - removed not needed test
venkymano-akamai Feb 5, 2026
5ca74eb
Merge branch 'develop' of github.com:linode/manager into value_field_…
venkymano-akamai Feb 5, 2026
31ecc0b
Merge branch 'develop' into value_field_dimension_filter_limit
agorthi-akamai Feb 9, 2026
b03a234
Merge branch 'develop' into value_field_dimension_filter_limit
venkymano-akamai Feb 10, 2026
90b514b
[DI-29170] - Add a test dimension helpful for testing
venkymano-akamai Feb 10, 2026
7c320b4
Merge branch 'value_field_dimension_filter_limit' of github.com:venky…
venkymano-akamai Feb 10, 2026
0e4382a
[DI-29170] - Address PR comments
venkymano-akamai Feb 11, 2026
0f04b3e
[DI-29170] - Address PR comments
venkymano-akamai Feb 11, 2026
929812b
Merge branch 'develop' into value_field_dimension_filter_limit
venkymano-akamai Feb 11, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions packages/manager/.changeset/pr-13361-added-1770207290291.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@linode/manager": Added
---

Ability to restrict the number of selectable values in cloudpulse metrics and alerts dimension filter value field ([#13361](https://github.com/linode/manager/pull/13361))
1 change: 1 addition & 0 deletions packages/manager/src/featureFlags.ts
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,7 @@ interface AclpAlerting {
alertDefinitions: boolean;
beta: boolean;
editDisabledStatuses?: AlertStatusType[];
maxDimensionFiltersValues?: number;
maxEmailChannelRecipients?: number;
notificationChannels: boolean;
recentActivity: boolean;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,12 @@ import React from 'react';

import { useBlockStorageFetchOptions } from './useBlockStorageFetchOptions';
import { useCleanupStaleValues } from './useCleanupStaleValues';
import { handleValueChange, resolveSelectedValues } from './utils';
import {
handleValueChange,
isMaxSelectionsReached,
isOptionDisabled,
resolveSelectedValues,
} from './utils';

import type { DimensionFilterAutocompleteProps } from './constants';

Expand All @@ -26,6 +31,7 @@ export const BlockStorageDimensionFilterAutocomplete = (
selectedRegions,
serviceType,
type,
maxSelections,
} = props;

const { data: regions } = useRegionsQuery();
Expand All @@ -47,14 +53,40 @@ export const BlockStorageDimensionFilterAutocomplete = (
isLoading,
});

const maxReached = React.useMemo(() => {
return isMaxSelectionsReached(
multiple ?? false,
fieldValue ?? '',
maxSelections
);
}, [fieldValue, maxSelections, multiple]);

const showHelperText = !errorText && maxSelections !== undefined && multiple;
const disableSelectAll =
maxSelections !== undefined && multiple
? values.length > maxSelections
: false;

return (
<Autocomplete
data-qa-dimension-filter={`${name}-value`}
data-testid="value"
disabled={disabled}
disableSelectAll={disableSelectAll}
errorText={
errorText ?? (isError ? 'Failed to fetch the values.' : undefined)
}
getOptionDisabled={(option) => {
return isOptionDisabled({
maxReached,
value: fieldValue ?? undefined,
multiple: multiple ?? false,
option,
});
}}
helperText={
showHelperText ? `Select up to ${maxSelections} values` : undefined
}
isOptionEqualToValue={(option, value) => value.value === option.value}
label="Value"
limitTags={1}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import React, { useMemo } from 'react';
import {
getStaticOptions,
handleValueChange,
isMaxSelectionsReached,
isOptionDisabled,
resolveSelectedValues,
} from './utils';

Expand All @@ -28,18 +30,44 @@ export const DimensionFilterAutocomplete = (
serviceType,
dimensionLabel,
values,
maxSelections,
} = props;

const options = useMemo(
() => getStaticOptions(serviceType, dimensionLabel ?? '', values ?? []),
[dimensionLabel, serviceType, values]
);
const maxReached = React.useMemo(() => {
return isMaxSelectionsReached(
multiple ?? false,
fieldValue ?? '',
maxSelections
);
}, [fieldValue, maxSelections, multiple]);

const showHelperText = !errorText && maxSelections !== undefined && multiple;
const disableSelectAll =
maxSelections !== undefined && multiple
? options.length > maxSelections
: false;
return (
<Autocomplete
data-qa-dimension-filter={`${name}-value`}
data-testid="value"
disabled={disabled}
disableSelectAll={disableSelectAll}
errorText={errorText}
getOptionDisabled={(option) => {
return isOptionDisabled({
maxReached,
value: fieldValue ?? undefined,
multiple: multiple ?? false,
option,
});
}}
helperText={
showHelperText ? `Select up to ${maxSelections} values` : undefined
}
isOptionEqualToValue={(option, value) => value.value === option.value}
label="Value"
limitTags={1}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,12 @@ import React from 'react';

import { useCleanupStaleValues } from './useCleanupStaleValues';
import { useFirewallFetchOptions } from './useFirewallFetchOptions';
import { handleValueChange, resolveSelectedValues } from './utils';
import {
handleValueChange,
isMaxSelectionsReached,
isOptionDisabled,
resolveSelectedValues,
} from './utils';

import type { DimensionFilterAutocompleteProps } from './constants';

Expand All @@ -31,6 +36,7 @@ export const FirewallDimensionFilterAutocomplete = (
serviceType,
type,
selectedRegions,
maxSelections,
} = props;

const { data: regions } = useRegionsQuery();
Expand All @@ -55,14 +61,40 @@ export const FirewallDimensionFilterAutocomplete = (
isLoading,
});

const maxReached = React.useMemo(() => {
return isMaxSelectionsReached(
multiple ?? false,
fieldValue ?? '',
maxSelections
);
}, [fieldValue, maxSelections, multiple]);

const showHelperText = !errorText && maxSelections !== undefined && multiple;
const disableSelectAll =
maxSelections !== undefined && multiple
? values.length > maxSelections
: false;

return (
<Autocomplete
data-qa-dimension-filter={`${name}-value`}
data-testid="value"
disabled={disabled}
disableSelectAll={disableSelectAll}
errorText={
errorText ?? (isError ? 'Failed to fetch the values.' : undefined)
}
getOptionDisabled={(option) => {
return isOptionDisabled({
maxReached,
value: fieldValue ?? undefined,
multiple: multiple ?? false,
option,
});
}}
helperText={
showHelperText ? `Select up to ${maxSelections} values` : undefined
}
isOptionEqualToValue={(option, value) => value.value === option.value}
label="Value"
limitTags={1}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,12 @@ import React from 'react';

import { useCleanupStaleValues } from './useCleanupStaleValues';
import { useObjectStorageFetchOptions } from './useObjectStorageFetchOptions';
import { handleValueChange, resolveSelectedValues } from './utils';
import {
handleValueChange,
isMaxSelectionsReached,
isOptionDisabled,
resolveSelectedValues,
} from './utils';

import type { DimensionFilterAutocompleteProps } from './constants';

Expand All @@ -29,6 +34,7 @@ export const ObjectStorageDimensionFilterAutocomplete = (
selectedRegions,
serviceType,
type,
maxSelections,
} = props;

const { data: regions } = useRegionsQuery();
Expand All @@ -50,15 +56,41 @@ export const ObjectStorageDimensionFilterAutocomplete = (
isLoading,
});

const maxReached = React.useMemo(() => {
return isMaxSelectionsReached(
multiple ?? false,
fieldValue ?? '',
maxSelections
);
}, [fieldValue, maxSelections, multiple]);

const showHelperText = !errorText && maxSelections !== undefined && multiple;
const disableSelectAll =
maxSelections !== undefined && multiple
? values.length > maxSelections
: false;

return (
<Autocomplete
data-qa-dimension-filter={`${name}-value`}
data-testid="value"
disabled={disabled}
disableSelectAll={disableSelectAll}
errorText={
errorText ??
(isError ? 'Failed to fetch Object Storage endpoints.' : undefined)
}
getOptionDisabled={(option) => {
return isOptionDisabled({
maxReached,
value: fieldValue ?? undefined,
multiple: multiple ?? false,
option,
});
}}
helperText={
showHelperText ? `Select up to ${maxSelections} values` : undefined
}
isOptionEqualToValue={(option, value) => value.value === option.value}
label="Value"
limitTags={1}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { TextField } from '@linode/ui';
import React from 'react';

import { useFlags } from 'src/hooks/useFlags';

import { BlockStorageDimensionFilterAutocomplete } from './BlockStorageDimensionFilterAutocomplete';
import {
MULTISELECT_PLACEHOLDER_TEXT,
Expand Down Expand Up @@ -102,12 +104,18 @@ export const ValueFieldRenderer = (props: ValueFieldRendererProps) => {
onChange,
operator,
scope,
selectedRegions,
serviceType,
type = 'alerts',
value,
values,
type = 'alerts',
selectedRegions,
serviceType,
} = props;

const flags = useFlags();

const maxDimensionFiltersValues =
flags.aclpAlerting?.maxDimensionFiltersValues ?? undefined;

// Use operator group for config lookup
const operatorGroup = getOperatorGroup(operator);
let dimensionConfig: Record<OperatorGroup, ValueFieldConfig>;
Expand Down Expand Up @@ -165,6 +173,7 @@ export const ValueFieldRenderer = (props: ValueFieldRendererProps) => {
placeholderText: config.placeholder ?? autocompletePlaceholder,
serviceType: serviceType ?? null,
type,
maxSelections: maxDimensionFiltersValues,
};

// Determine custom fetch behaviour if there are same dimension_labels across service types
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -272,5 +272,35 @@ export const getDimensionFilterValueSchema = ({
if (['endswith', 'startswith'].includes(operator)) {
return string().max(100, LENGTH_ERROR_MESSAGE).concat(baseValueSchema);
}

if (operator === 'in') {
// here it is always autocomplete with comma separated values
return string()
.test(
'max-comma-values',
'More than max values selected',
function (value) {
if (!value) return true;

const { maxDimensionFilterValues } = this.options.context ?? {};

if (!maxDimensionFilterValues) return true; // if not passed, skip the check

const count = value
.split(',')
.map((s) => s.trim())
.filter(Boolean).length;
Comment thread
venkymano-akamai marked this conversation as resolved.

return (
count <= maxDimensionFilterValues ||
this.createError({
message: `Select up to ${maxDimensionFilterValues} values`,
})
);
}
)
.concat(baseValueSchema);
}

return baseValueSchema;
};
Original file line number Diff line number Diff line change
Expand Up @@ -428,6 +428,10 @@ export interface DimensionFilterAutocompleteProps {
* Current raw string value (or null) from the form state.
*/
fieldValue: null | string;
/**
* The maximum number of selections allowed (for multi-select).
*/
maxSelections?: number;
/**
* To control single-select/multi-select in the Autocomplete.
*/
Expand Down
Loading