diff --git a/desktop/flipper-plugin/src/ui/PowerSearch/PowerSearchConfig.tsx b/desktop/flipper-plugin/src/ui/PowerSearch/PowerSearchConfig.tsx index 67a65ca0a..a9602b3e7 100644 --- a/desktop/flipper-plugin/src/ui/PowerSearch/PowerSearchConfig.tsx +++ b/desktop/flipper-plugin/src/ui/PowerSearch/PowerSearchConfig.tsx @@ -64,6 +64,7 @@ export type EnumOperatorConfig = { key: string; label: string; enumLabels: EnumLabels; + allowFreeform?: boolean; }; export type AbsoluteDateOperatorConfig = { diff --git a/desktop/flipper-plugin/src/ui/PowerSearch/PowerSearchEnumSetTerm.tsx b/desktop/flipper-plugin/src/ui/PowerSearch/PowerSearchEnumSetTerm.tsx index 3ab8f9ec7..99a6c1fbc 100644 --- a/desktop/flipper-plugin/src/ui/PowerSearch/PowerSearchEnumSetTerm.tsx +++ b/desktop/flipper-plugin/src/ui/PowerSearch/PowerSearchEnumSetTerm.tsx @@ -16,6 +16,7 @@ type PowerSearchEnumSetTermProps = { onChange: (value: string[]) => void; enumLabels: EnumLabels; defaultValue?: string[]; + allowFreeform?: boolean; }; export const PowerSearchEnumSetTerm: React.FC = ({ @@ -23,6 +24,7 @@ export const PowerSearchEnumSetTerm: React.FC = ({ onChange, enumLabels, defaultValue, + allowFreeform, }) => { const options = React.useMemo(() => { return Object.entries(enumLabels).map(([key, label]) => ({ @@ -38,7 +40,7 @@ export const PowerSearchEnumSetTerm: React.FC = ({ return ( = ({ return ( ); }; diff --git a/desktop/flipper-plugin/src/ui/PowerSearch/PowerSearchTerm.tsx b/desktop/flipper-plugin/src/ui/PowerSearch/PowerSearchTerm.tsx index bef2230bf..1a9de9fe6 100644 --- a/desktop/flipper-plugin/src/ui/PowerSearch/PowerSearchTerm.tsx +++ b/desktop/flipper-plugin/src/ui/PowerSearch/PowerSearchTerm.tsx @@ -115,6 +115,7 @@ export const PowerSearchTerm: React.FC = ({ }); }} enumLabels={searchTerm.operator.enumLabels} + allowFreeform={searchTerm.operator.allowFreeform} defaultValue={searchTerm.searchValue} /> ); @@ -131,6 +132,7 @@ export const PowerSearchTerm: React.FC = ({ }); }} enumLabels={searchTerm.operator.enumLabels} + allowFreeform={searchTerm.operator.allowFreeform} defaultValue={searchTerm.searchValue} /> ); diff --git a/desktop/flipper-plugin/src/ui/data-table/DataTableDefaultPowerSearchOperators.tsx b/desktop/flipper-plugin/src/ui/data-table/DataTableDefaultPowerSearchOperators.tsx index c37c24ce7..1234ab969 100644 --- a/desktop/flipper-plugin/src/ui/data-table/DataTableDefaultPowerSearchOperators.tsx +++ b/desktop/flipper-plugin/src/ui/data-table/DataTableDefaultPowerSearchOperators.tsx @@ -123,42 +123,51 @@ export const dataTablePowerSearchOperators = { valueType: 'FLOAT', }), // { [enumValue]: enumLabel } - enum_is: (enumLabels: EnumLabels) => ({ + enum_is: (enumLabels: EnumLabels, allowFreeform?: boolean) => ({ label: 'is', key: 'enum_is', valueType: 'ENUM', enumLabels, + allowFreeform, }), - enum_is_nullish_or: (enumLabels: EnumLabels) => ({ + enum_is_nullish_or: (enumLabels: EnumLabels, allowFreeform?: boolean) => ({ label: 'is nullish or', key: 'enum_is_nullish_or', valueType: 'ENUM', enumLabels, + allowFreeform, }), - enum_is_not: (enumLabels: EnumLabels) => ({ + enum_is_not: (enumLabels: EnumLabels, allowFreeform?: boolean) => ({ label: 'is not', key: 'enum_is_not', valueType: 'ENUM', enumLabels, + allowFreeform, }), // TODO: Support logical operations (AND, OR, NOT) to combine primitive operators instead of adding new complex operators! - enum_set_is_nullish_or_any_of: (enumLabels: EnumLabels) => ({ + enum_set_is_nullish_or_any_of: ( + enumLabels: EnumLabels, + allowFreeform?: boolean, + ) => ({ label: 'is nullish or any of', key: 'enum_set_is_nullish_or_any_of', valueType: 'ENUM_SET', enumLabels, + allowFreeform, }), - enum_set_is_any_of: (enumLabels: EnumLabels) => ({ + enum_set_is_any_of: (enumLabels: EnumLabels, allowFreeform?: boolean) => ({ label: 'is any of', key: 'enum_set_is_any_of', valueType: 'ENUM_SET', enumLabels, + allowFreeform, }), - enum_set_is_none_of: (enumLabels: EnumLabels) => ({ + enum_set_is_none_of: (enumLabels: EnumLabels, allowFreeform?: boolean) => ({ label: 'is none of', key: 'enum_set_is_none_of', valueType: 'ENUM_SET', enumLabels, + allowFreeform, }), is_nullish: () => ({ label: 'is nullish', diff --git a/desktop/flipper-plugin/src/ui/data-table/DataTableWithPowerSearch.tsx b/desktop/flipper-plugin/src/ui/data-table/DataTableWithPowerSearch.tsx index 03844f789..76e04ec61 100644 --- a/desktop/flipper-plugin/src/ui/data-table/DataTableWithPowerSearch.tsx +++ b/desktop/flipper-plugin/src/ui/data-table/DataTableWithPowerSearch.tsx @@ -146,8 +146,18 @@ type DataTableInput = }; type PowerSearchSimplifiedConfig = - | {type: 'enum'; enumLabels: EnumLabels; inferEnumOptionsFromData?: false} - | {type: 'enum'; enumLabels?: never; inferEnumOptionsFromData: true} + | { + type: 'enum'; + enumLabels: EnumLabels; + inferEnumOptionsFromData?: false; + allowFreeform?: boolean; + } + | { + type: 'enum'; + enumLabels?: never; + inferEnumOptionsFromData: true; + allowFreeform?: boolean; + } | {type: 'int'} | {type: 'float'} | {type: 'string'} @@ -163,6 +173,12 @@ type PowerSearchExtendedConfig = { * See https://fburl.com/code/0waicx6p */ inferEnumOptionsFromData?: boolean; + /** + * Allows freeform entries for enum column types. Makes most sense together with `inferEnumOptionsFromData`. + * If `inferEnumOptionsFromData=true`, then it is `true` by default. + * See use-case https://fburl.com/workplace/0kx6fkhm + */ + allowFreeform?: boolean; }; const powerSearchConfigIsExtendedConfig = ( @@ -418,10 +434,12 @@ export function DataTable( inferredPowerSearchEnumLabelsForColumn && column.powerSearchConfig.inferEnumOptionsFromData ) { + const allowFreeform = column.powerSearchConfig.allowFreeform ?? true; columnPowerSearchOperators = columnPowerSearchOperators.map( (operator) => ({ ...operator, enumLabels: inferredPowerSearchEnumLabelsForColumn, + allowFreeform, }), ); } @@ -474,18 +492,30 @@ export function DataTable( } case 'enum': { let enumLabels: EnumLabels; + let allowFreeform = column.powerSearchConfig.allowFreeform; if (column.powerSearchConfig.inferEnumOptionsFromData) { enumLabels = inferredPowerSearchEnumLabels[column.key] ?? {}; + // Fallback to `true` by default when we use inferred labels + if (allowFreeform === undefined) { + allowFreeform = true; + } } else { enumLabels = column.powerSearchConfig.enumLabels; } columnPowerSearchOperators = [ - dataTablePowerSearchOperators.enum_set_is_any_of(enumLabels), - dataTablePowerSearchOperators.enum_set_is_none_of(enumLabels), + dataTablePowerSearchOperators.enum_set_is_any_of( + enumLabels, + allowFreeform, + ), + dataTablePowerSearchOperators.enum_set_is_none_of( + enumLabels, + allowFreeform, + ), dataTablePowerSearchOperators.enum_set_is_nullish_or_any_of( enumLabels, + allowFreeform, ), ]; break;