Allow freeform entries for enum terms
Summary: Solves https://fb.workplace.com/groups/flippersupport/posts/1726178417862809/?comment_id=1726429847837666&reply_comment_id=1730206487460002 Reviewed By: passy Differential Revision: D51497924 fbshipit-source-id: d0737b2b82f29ff8ae654e7cad2ef1daa8244756
This commit is contained in:
committed by
Facebook GitHub Bot
parent
864e296f35
commit
294f39eceb
@@ -64,6 +64,7 @@ export type EnumOperatorConfig = {
|
||||
key: string;
|
||||
label: string;
|
||||
enumLabels: EnumLabels;
|
||||
allowFreeform?: boolean;
|
||||
};
|
||||
|
||||
export type AbsoluteDateOperatorConfig = {
|
||||
|
||||
@@ -16,6 +16,7 @@ type PowerSearchEnumSetTermProps = {
|
||||
onChange: (value: string[]) => void;
|
||||
enumLabels: EnumLabels;
|
||||
defaultValue?: string[];
|
||||
allowFreeform?: boolean;
|
||||
};
|
||||
|
||||
export const PowerSearchEnumSetTerm: React.FC<PowerSearchEnumSetTermProps> = ({
|
||||
@@ -23,6 +24,7 @@ export const PowerSearchEnumSetTerm: React.FC<PowerSearchEnumSetTermProps> = ({
|
||||
onChange,
|
||||
enumLabels,
|
||||
defaultValue,
|
||||
allowFreeform,
|
||||
}) => {
|
||||
const options = React.useMemo(() => {
|
||||
return Object.entries(enumLabels).map(([key, label]) => ({
|
||||
@@ -38,7 +40,7 @@ export const PowerSearchEnumSetTerm: React.FC<PowerSearchEnumSetTermProps> = ({
|
||||
|
||||
return (
|
||||
<Select
|
||||
mode="multiple"
|
||||
mode={allowFreeform ? 'tags' : 'multiple'}
|
||||
autoFocus={!defaultValue}
|
||||
style={{minWidth: 100}}
|
||||
placeholder="..."
|
||||
|
||||
@@ -16,6 +16,7 @@ type PowerSearchEnumTermProps = {
|
||||
onChange: (value: string) => void;
|
||||
enumLabels: EnumLabels;
|
||||
defaultValue?: string;
|
||||
allowFreeform?: boolean;
|
||||
};
|
||||
|
||||
export const PowerSearchEnumTerm: React.FC<PowerSearchEnumTermProps> = ({
|
||||
@@ -23,6 +24,7 @@ export const PowerSearchEnumTerm: React.FC<PowerSearchEnumTermProps> = ({
|
||||
onChange,
|
||||
enumLabels,
|
||||
defaultValue,
|
||||
allowFreeform,
|
||||
}) => {
|
||||
const [editing, setEditing] = React.useState(!defaultValue);
|
||||
|
||||
@@ -72,6 +74,7 @@ export const PowerSearchEnumTerm: React.FC<PowerSearchEnumTermProps> = ({
|
||||
if (editing) {
|
||||
return (
|
||||
<Select
|
||||
mode={allowFreeform ? 'tags' : undefined}
|
||||
autoFocus
|
||||
style={{width}}
|
||||
placeholder="..."
|
||||
@@ -100,7 +103,7 @@ export const PowerSearchEnumTerm: React.FC<PowerSearchEnumTermProps> = ({
|
||||
return (
|
||||
<Button onClick={() => setEditing(true)}>
|
||||
{/* eslint-disable-next-line @typescript-eslint/no-non-null-assertion */}
|
||||
{enumLabels[defaultValue!]}
|
||||
{enumLabels[defaultValue!] ?? defaultValue}
|
||||
</Button>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -115,6 +115,7 @@ export const PowerSearchTerm: React.FC<PowerSearchTermProps> = ({
|
||||
});
|
||||
}}
|
||||
enumLabels={searchTerm.operator.enumLabels}
|
||||
allowFreeform={searchTerm.operator.allowFreeform}
|
||||
defaultValue={searchTerm.searchValue}
|
||||
/>
|
||||
);
|
||||
@@ -131,6 +132,7 @@ export const PowerSearchTerm: React.FC<PowerSearchTermProps> = ({
|
||||
});
|
||||
}}
|
||||
enumLabels={searchTerm.operator.enumLabels}
|
||||
allowFreeform={searchTerm.operator.allowFreeform}
|
||||
defaultValue={searchTerm.searchValue}
|
||||
/>
|
||||
);
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -146,8 +146,18 @@ type DataTableInput<T = any> =
|
||||
};
|
||||
|
||||
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<T extends object>(
|
||||
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<T extends object>(
|
||||
}
|
||||
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;
|
||||
|
||||
Reference in New Issue
Block a user