mirror of
https://github.com/SigNoz/signoz.git
synced 2025-12-19 16:36:45 +00:00
* feat: added new Select component for multi and single select * feat: refactored code and added keyboard navigations in single select * feat: different state handling in single select * feat: updated the playground page * feat: multi-select updates * feat: fixed multiselect selection issues * feat: multiselect cleanup * feat: multiselect key navigation cleanup * feat: added tokenization in multiselect * feat: add on enter and handle duplicates * feat: design update to the components * feat: design update to the components * feat: design update to the components * feat: updated the playground page * feat: edited playground data * feat: edited styles * feat: code cleanup * feat: added shift + keys navigation and selection * feat: improved styles and added darkmode styles * feat: removed scroll bar hover style * feat: added scroll bar on hover * feat: added regex wrapper support * feat: fixed right arrow navigation across chips * feat: addressed all the single select feedbacks * feat: addressed all the single select feedbacks * feat: added only-all-toggle feat with ALL selection tag * feat: remove clear, update footer info content and style and misc fixes * feat: misc style fixes * feat: added quotes exception to the multiselect tagging * feat: removing demo page, and cleanup PR for reviews * feat: resolved comments and refactoring * feat: added test cases
136 lines
3.7 KiB
TypeScript
136 lines
3.7 KiB
TypeScript
/* eslint-disable sonarjs/cognitive-complexity */
|
|
import { OptionData } from './types';
|
|
|
|
export const SPACEKEY = ' ';
|
|
|
|
export const prioritizeOrAddOptionForSingleSelect = (
|
|
options: OptionData[],
|
|
value: string,
|
|
label?: string,
|
|
): OptionData[] => {
|
|
let foundOption: OptionData | null = null;
|
|
|
|
// Separate the found option and the rest
|
|
const filteredOptions = options
|
|
.map((option) => {
|
|
if ('options' in option && Array.isArray(option.options)) {
|
|
// Filter out the value from nested options
|
|
const remainingSubOptions = option.options.filter(
|
|
(subOption) => subOption.value !== value,
|
|
);
|
|
const extractedOption = option.options.find(
|
|
(subOption) => subOption.value === value,
|
|
);
|
|
|
|
if (extractedOption) foundOption = extractedOption;
|
|
|
|
// Keep the group if it still has remaining options
|
|
return remainingSubOptions.length > 0
|
|
? { ...option, options: remainingSubOptions }
|
|
: null;
|
|
}
|
|
|
|
// Check top-level options
|
|
if (option.value === value) {
|
|
foundOption = option;
|
|
return null; // Remove it from the list
|
|
}
|
|
|
|
return option;
|
|
})
|
|
.filter(Boolean) as OptionData[]; // Remove null values
|
|
|
|
// If not found, create a new option
|
|
if (!foundOption) {
|
|
foundOption = { value, label: label ?? value };
|
|
}
|
|
|
|
// Add the found/new option at the top
|
|
return [foundOption, ...filteredOptions];
|
|
};
|
|
|
|
export const prioritizeOrAddOptionForMultiSelect = (
|
|
options: OptionData[],
|
|
values: string[], // Only supports multiple values (string[])
|
|
labels?: Record<string, string>,
|
|
): OptionData[] => {
|
|
const foundOptions: OptionData[] = [];
|
|
|
|
// Separate the found options and the rest
|
|
const filteredOptions = options
|
|
.map((option) => {
|
|
if ('options' in option && Array.isArray(option.options)) {
|
|
// Filter out selected values from nested options
|
|
const remainingSubOptions = option.options.filter(
|
|
(subOption) => subOption.value && !values.includes(subOption.value),
|
|
);
|
|
const extractedOptions = option.options.filter(
|
|
(subOption) => subOption.value && values.includes(subOption.value),
|
|
);
|
|
|
|
if (extractedOptions.length > 0) {
|
|
foundOptions.push(...extractedOptions);
|
|
}
|
|
|
|
// Keep the group if it still has remaining options
|
|
return remainingSubOptions.length > 0
|
|
? { ...option, options: remainingSubOptions }
|
|
: null;
|
|
}
|
|
|
|
// Check top-level options
|
|
if (option.value && values.includes(option.value)) {
|
|
foundOptions.push(option);
|
|
return null; // Remove it from the list
|
|
}
|
|
|
|
return option;
|
|
})
|
|
.filter(Boolean) as OptionData[]; // Remove null values
|
|
|
|
// Find missing values that were not present in the original options and create new ones
|
|
const missingValues = values.filter(
|
|
(value) => !foundOptions.some((opt) => opt.value === value),
|
|
);
|
|
|
|
const newOptions = missingValues.map((value) => ({
|
|
value,
|
|
label: labels?.[value] ?? value, // Use provided label or default to value
|
|
}));
|
|
|
|
// Add found & new options to the top
|
|
return [...newOptions, ...foundOptions, ...filteredOptions];
|
|
};
|
|
|
|
/**
|
|
* Filters options based on search text
|
|
*/
|
|
export const filterOptionsBySearch = (
|
|
options: OptionData[],
|
|
searchText: string,
|
|
): OptionData[] => {
|
|
if (!searchText.trim()) return options;
|
|
|
|
const lowerSearchText = searchText.toLowerCase();
|
|
|
|
return options
|
|
.map((option) => {
|
|
if ('options' in option && Array.isArray(option.options)) {
|
|
// Filter nested options
|
|
const filteredSubOptions = option.options.filter((subOption) =>
|
|
subOption.label.toLowerCase().includes(lowerSearchText),
|
|
);
|
|
|
|
return filteredSubOptions.length > 0
|
|
? { ...option, options: filteredSubOptions }
|
|
: undefined;
|
|
}
|
|
|
|
// Filter top-level options
|
|
return option.label.toLowerCase().includes(lowerSearchText)
|
|
? option
|
|
: undefined;
|
|
})
|
|
.filter(Boolean) as OptionData[];
|
|
};
|