Refactor SearchFilterGroup type to be less verbose and more clearly named.
This commit is contained in:
parent
714029b9a0
commit
b7979f4719
|
@ -27,20 +27,18 @@ import {
|
||||||
ViewV2Schema,
|
ViewV2Schema,
|
||||||
ViewV2Type,
|
ViewV2Type,
|
||||||
JsonTypes,
|
JsonTypes,
|
||||||
FilterGroupLogicalOperator,
|
UILogicalOperator,
|
||||||
EmptyFilterOption,
|
EmptyFilterOption,
|
||||||
JsonFieldSubType,
|
JsonFieldSubType,
|
||||||
SearchFilterGroup,
|
UISearchFilter,
|
||||||
LegacyFilter,
|
LegacyFilter,
|
||||||
SearchViewRowRequest,
|
SearchViewRowRequest,
|
||||||
SearchFilterChild,
|
|
||||||
} from "@budibase/types"
|
} from "@budibase/types"
|
||||||
import { generator, mocks } from "@budibase/backend-core/tests"
|
import { generator, mocks } from "@budibase/backend-core/tests"
|
||||||
import { DatabaseName, getDatasource } from "../../../integrations/tests/utils"
|
import { DatabaseName, getDatasource } from "../../../integrations/tests/utils"
|
||||||
import merge from "lodash/merge"
|
import merge from "lodash/merge"
|
||||||
import { quotas } from "@budibase/pro"
|
import { quotas } from "@budibase/pro"
|
||||||
import { db, roles, features } from "@budibase/backend-core"
|
import { db, roles, features } from "@budibase/backend-core"
|
||||||
import { single } from "validate.js"
|
|
||||||
|
|
||||||
describe.each([
|
describe.each([
|
||||||
["lucene", undefined],
|
["lucene", undefined],
|
||||||
|
@ -158,11 +156,11 @@ describe.each([
|
||||||
tableId: table._id!,
|
tableId: table._id!,
|
||||||
primaryDisplay: "id",
|
primaryDisplay: "id",
|
||||||
queryUI: {
|
queryUI: {
|
||||||
logicalOperator: FilterGroupLogicalOperator.ALL,
|
logicalOperator: UILogicalOperator.ALL,
|
||||||
onEmptyFilter: EmptyFilterOption.RETURN_ALL,
|
onEmptyFilter: EmptyFilterOption.RETURN_ALL,
|
||||||
groups: [
|
groups: [
|
||||||
{
|
{
|
||||||
logicalOperator: FilterGroupLogicalOperator.ALL,
|
logicalOperator: UILogicalOperator.ALL,
|
||||||
filters: [
|
filters: [
|
||||||
{
|
{
|
||||||
operator: BasicOperator.EQUAL,
|
operator: BasicOperator.EQUAL,
|
||||||
|
@ -2388,10 +2386,10 @@ describe.each([
|
||||||
name: generator.guid(),
|
name: generator.guid(),
|
||||||
queryUI: {
|
queryUI: {
|
||||||
onEmptyFilter: EmptyFilterOption.RETURN_ALL,
|
onEmptyFilter: EmptyFilterOption.RETURN_ALL,
|
||||||
logicalOperator: FilterGroupLogicalOperator.ALL,
|
logicalOperator: UILogicalOperator.ALL,
|
||||||
groups: [
|
groups: [
|
||||||
{
|
{
|
||||||
logicalOperator: FilterGroupLogicalOperator.ALL,
|
logicalOperator: UILogicalOperator.ALL,
|
||||||
filters: [
|
filters: [
|
||||||
{
|
{
|
||||||
operator: BasicOperator.EQUAL,
|
operator: BasicOperator.EQUAL,
|
||||||
|
@ -2452,10 +2450,10 @@ describe.each([
|
||||||
name: generator.guid(),
|
name: generator.guid(),
|
||||||
queryUI: {
|
queryUI: {
|
||||||
onEmptyFilter: EmptyFilterOption.RETURN_ALL,
|
onEmptyFilter: EmptyFilterOption.RETURN_ALL,
|
||||||
logicalOperator: FilterGroupLogicalOperator.ALL,
|
logicalOperator: UILogicalOperator.ALL,
|
||||||
groups: [
|
groups: [
|
||||||
{
|
{
|
||||||
logicalOperator: FilterGroupLogicalOperator.ALL,
|
logicalOperator: UILogicalOperator.ALL,
|
||||||
filters: [
|
filters: [
|
||||||
{
|
{
|
||||||
operator: BasicOperator.EQUAL,
|
operator: BasicOperator.EQUAL,
|
||||||
|
@ -2741,10 +2739,10 @@ describe.each([
|
||||||
name: generator.guid(),
|
name: generator.guid(),
|
||||||
queryUI: {
|
queryUI: {
|
||||||
onEmptyFilter: EmptyFilterOption.RETURN_ALL,
|
onEmptyFilter: EmptyFilterOption.RETURN_ALL,
|
||||||
logicalOperator: FilterGroupLogicalOperator.ALL,
|
logicalOperator: UILogicalOperator.ALL,
|
||||||
groups: [
|
groups: [
|
||||||
{
|
{
|
||||||
logicalOperator: FilterGroupLogicalOperator.ALL,
|
logicalOperator: UILogicalOperator.ALL,
|
||||||
filters: [
|
filters: [
|
||||||
{
|
{
|
||||||
operator: BasicOperator.NOT_EQUAL,
|
operator: BasicOperator.NOT_EQUAL,
|
||||||
|
@ -2799,10 +2797,10 @@ describe.each([
|
||||||
name: generator.guid(),
|
name: generator.guid(),
|
||||||
queryUI: {
|
queryUI: {
|
||||||
onEmptyFilter: EmptyFilterOption.RETURN_ALL,
|
onEmptyFilter: EmptyFilterOption.RETURN_ALL,
|
||||||
logicalOperator: FilterGroupLogicalOperator.ALL,
|
logicalOperator: UILogicalOperator.ALL,
|
||||||
groups: [
|
groups: [
|
||||||
{
|
{
|
||||||
logicalOperator: FilterGroupLogicalOperator.ALL,
|
logicalOperator: UILogicalOperator.ALL,
|
||||||
filters: [
|
filters: [
|
||||||
{
|
{
|
||||||
operator: BasicOperator.NOT_EQUAL,
|
operator: BasicOperator.NOT_EQUAL,
|
||||||
|
@ -2894,10 +2892,10 @@ describe.each([
|
||||||
name: generator.guid(),
|
name: generator.guid(),
|
||||||
queryUI: {
|
queryUI: {
|
||||||
onEmptyFilter: EmptyFilterOption.RETURN_ALL,
|
onEmptyFilter: EmptyFilterOption.RETURN_ALL,
|
||||||
logicalOperator: FilterGroupLogicalOperator.ALL,
|
logicalOperator: UILogicalOperator.ALL,
|
||||||
groups: [
|
groups: [
|
||||||
{
|
{
|
||||||
logicalOperator: FilterGroupLogicalOperator.ALL,
|
logicalOperator: UILogicalOperator.ALL,
|
||||||
filters: [
|
filters: [
|
||||||
{
|
{
|
||||||
operator: BasicOperator.EQUAL,
|
operator: BasicOperator.EQUAL,
|
||||||
|
@ -3338,10 +3336,10 @@ describe.each([
|
||||||
type: ViewV2Type.CALCULATION,
|
type: ViewV2Type.CALCULATION,
|
||||||
queryUI: {
|
queryUI: {
|
||||||
onEmptyFilter: EmptyFilterOption.RETURN_ALL,
|
onEmptyFilter: EmptyFilterOption.RETURN_ALL,
|
||||||
logicalOperator: FilterGroupLogicalOperator.ALL,
|
logicalOperator: UILogicalOperator.ALL,
|
||||||
groups: [
|
groups: [
|
||||||
{
|
{
|
||||||
logicalOperator: FilterGroupLogicalOperator.ALL,
|
logicalOperator: UILogicalOperator.ALL,
|
||||||
filters: [
|
filters: [
|
||||||
{
|
{
|
||||||
operator: BasicOperator.EQUAL,
|
operator: BasicOperator.EQUAL,
|
||||||
|
@ -3631,10 +3629,10 @@ describe.each([
|
||||||
name: generator.guid(),
|
name: generator.guid(),
|
||||||
queryUI: {
|
queryUI: {
|
||||||
onEmptyFilter: EmptyFilterOption.RETURN_ALL,
|
onEmptyFilter: EmptyFilterOption.RETURN_ALL,
|
||||||
logicalOperator: FilterGroupLogicalOperator.ALL,
|
logicalOperator: UILogicalOperator.ALL,
|
||||||
groups: [
|
groups: [
|
||||||
{
|
{
|
||||||
logicalOperator: FilterGroupLogicalOperator.ALL,
|
logicalOperator: UILogicalOperator.ALL,
|
||||||
filters: [
|
filters: [
|
||||||
{
|
{
|
||||||
operator: BasicOperator.EQUAL,
|
operator: BasicOperator.EQUAL,
|
||||||
|
@ -3711,52 +3709,31 @@ describe.each([
|
||||||
|
|
||||||
interface TestCase {
|
interface TestCase {
|
||||||
name: string
|
name: string
|
||||||
query: SearchFilterGroup
|
query: UISearchFilter
|
||||||
insert: Row[]
|
insert: Row[]
|
||||||
expected: Row[]
|
expected: Row[]
|
||||||
searchOpts?: SearchViewRowRequest
|
searchOpts?: SearchViewRowRequest
|
||||||
}
|
}
|
||||||
|
|
||||||
function defaultQuery(
|
function simpleQuery(...filters: LegacyFilter[]): UISearchFilter {
|
||||||
query: Partial<SearchFilterGroup>
|
return { groups: [{ filters }] }
|
||||||
): SearchFilterGroup {
|
|
||||||
return {
|
|
||||||
onEmptyFilter: EmptyFilterOption.RETURN_ALL,
|
|
||||||
logicalOperator: FilterGroupLogicalOperator.ALL,
|
|
||||||
groups: [],
|
|
||||||
...query,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function defaultGroup(
|
|
||||||
group: Partial<SearchFilterChild>
|
|
||||||
): SearchFilterChild {
|
|
||||||
return {
|
|
||||||
logicalOperator: FilterGroupLogicalOperator.ALL,
|
|
||||||
filters: [],
|
|
||||||
...group,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function simpleQuery(...filters: LegacyFilter[]): SearchFilterGroup {
|
|
||||||
return defaultQuery({ groups: [defaultGroup({ filters })] })
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const testCases: TestCase[] = [
|
const testCases: TestCase[] = [
|
||||||
{
|
{
|
||||||
name: "empty query return all",
|
name: "empty query return all",
|
||||||
insert: [{ string: "foo" }],
|
insert: [{ string: "foo" }],
|
||||||
query: defaultQuery({
|
query: {
|
||||||
onEmptyFilter: EmptyFilterOption.RETURN_ALL,
|
onEmptyFilter: EmptyFilterOption.RETURN_ALL,
|
||||||
}),
|
},
|
||||||
expected: [{ string: "foo" }],
|
expected: [{ string: "foo" }],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "empty query return none",
|
name: "empty query return none",
|
||||||
insert: [{ string: "foo" }],
|
insert: [{ string: "foo" }],
|
||||||
query: defaultQuery({
|
query: {
|
||||||
onEmptyFilter: EmptyFilterOption.RETURN_NONE,
|
onEmptyFilter: EmptyFilterOption.RETURN_NONE,
|
||||||
}),
|
},
|
||||||
expected: [],
|
expected: [],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
@ -14,8 +14,8 @@ export function ensureQueryUISet(view: ViewV2) {
|
||||||
// We're changing it in the change that this comment is part of to also
|
// We're changing it in the change that this comment is part of to also
|
||||||
// include SearchFilters objects. These are created when we receive an
|
// include SearchFilters objects. These are created when we receive an
|
||||||
// update to a ViewV2 that contains a queryUI and not a query field. We
|
// update to a ViewV2 that contains a queryUI and not a query field. We
|
||||||
// can convert SearchFilterGroup (the type of queryUI) to SearchFilters,
|
// can convert UISearchFilter (the type of queryUI) to SearchFilters,
|
||||||
// but not LegacyFilter[], they are incompatible due to SearchFilterGroup
|
// but not LegacyFilter[], they are incompatible due to UISearchFilter
|
||||||
// and SearchFilters being recursive types.
|
// and SearchFilters being recursive types.
|
||||||
//
|
//
|
||||||
// So despite the type saying that `view.query` is a LegacyFilter[] |
|
// So despite the type saying that `view.query` is a LegacyFilter[] |
|
||||||
|
|
|
@ -19,8 +19,8 @@ import {
|
||||||
RangeOperator,
|
RangeOperator,
|
||||||
LogicalOperator,
|
LogicalOperator,
|
||||||
isLogicalSearchOperator,
|
isLogicalSearchOperator,
|
||||||
SearchFilterGroup,
|
UISearchFilter,
|
||||||
FilterGroupLogicalOperator,
|
UILogicalOperator,
|
||||||
isBasicSearchOperator,
|
isBasicSearchOperator,
|
||||||
isArraySearchOperator,
|
isArraySearchOperator,
|
||||||
isRangeSearchOperator,
|
isRangeSearchOperator,
|
||||||
|
@ -561,7 +561,7 @@ export const buildQueryLegacy = (
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Converts a **SearchFilterGroup** filter definition into a grouped
|
* Converts a **UISearchFilter** filter definition into a grouped
|
||||||
* search query of type **SearchFilters**
|
* search query of type **SearchFilters**
|
||||||
*
|
*
|
||||||
* Legacy support remains for the old **SearchFilter[]** format.
|
* Legacy support remains for the old **SearchFilter[]** format.
|
||||||
|
@ -573,49 +573,41 @@ export const buildQueryLegacy = (
|
||||||
*/
|
*/
|
||||||
export function buildQuery(filter: undefined): undefined
|
export function buildQuery(filter: undefined): undefined
|
||||||
export function buildQuery(
|
export function buildQuery(
|
||||||
filter: SearchFilterGroup | LegacyFilter[]
|
filter: UISearchFilter | LegacyFilter[]
|
||||||
): SearchFilters
|
): SearchFilters
|
||||||
export function buildQuery(
|
export function buildQuery(
|
||||||
filter?: SearchFilterGroup | LegacyFilter[]
|
filter?: UISearchFilter | LegacyFilter[]
|
||||||
): SearchFilters | undefined {
|
): SearchFilters | undefined {
|
||||||
if (!filter) {
|
if (!filter) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
let parsedFilter: SearchFilterGroup
|
let parsedFilter: UISearchFilter
|
||||||
if (Array.isArray(filter)) {
|
if (Array.isArray(filter)) {
|
||||||
parsedFilter = processSearchFilters(filter)
|
parsedFilter = processSearchFilters(filter)
|
||||||
} else {
|
} else {
|
||||||
parsedFilter = filter
|
parsedFilter = filter
|
||||||
}
|
}
|
||||||
|
|
||||||
const operatorMap = {
|
const operator = logicalOperatorFromUI(
|
||||||
[FilterGroupLogicalOperator.ALL]: LogicalOperator.AND,
|
parsedFilter.logicalOperator || UILogicalOperator.ALL
|
||||||
[FilterGroupLogicalOperator.ANY]: LogicalOperator.OR,
|
)
|
||||||
}
|
const groups = parsedFilter.groups || []
|
||||||
|
const conditions: SearchFilters[] = groups.map(group => {
|
||||||
|
const filters = group.filters || []
|
||||||
|
return { [operator]: { conditions: filters.map(x => buildCondition(x)) } }
|
||||||
|
})
|
||||||
|
|
||||||
const globalOnEmpty = parsedFilter.onEmptyFilter
|
|
||||||
? parsedFilter.onEmptyFilter
|
|
||||||
: null
|
|
||||||
|
|
||||||
const globalOperator = operatorMap[parsedFilter.logicalOperator]
|
|
||||||
|
|
||||||
const ret = {
|
|
||||||
...(globalOnEmpty ? { onEmptyFilter: globalOnEmpty } : {}),
|
|
||||||
[globalOperator]: {
|
|
||||||
conditions: parsedFilter.groups?.map(group => {
|
|
||||||
return {
|
return {
|
||||||
[operatorMap[group.logicalOperator]]: {
|
onEmptyFilter: parsedFilter.onEmptyFilter,
|
||||||
conditions: group.filters
|
[operator]: { conditions },
|
||||||
?.map(x => buildCondition(x))
|
|
||||||
.filter(filter => filter),
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}),
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret
|
function logicalOperatorFromUI(operator: UILogicalOperator): LogicalOperator {
|
||||||
|
return operator === UILogicalOperator.ALL
|
||||||
|
? LogicalOperator.AND
|
||||||
|
: LogicalOperator.OR
|
||||||
}
|
}
|
||||||
|
|
||||||
// The frontend can send single values for array fields sometimes, so to handle
|
// The frontend can send single values for array fields sometimes, so to handle
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
import {
|
import {
|
||||||
LegacyFilter,
|
LegacyFilter,
|
||||||
SearchFilterGroup,
|
UISearchFilter,
|
||||||
FilterGroupLogicalOperator,
|
UILogicalOperator,
|
||||||
SearchFilters,
|
SearchFilters,
|
||||||
BasicOperator,
|
BasicOperator,
|
||||||
ArrayOperator,
|
ArrayOperator,
|
||||||
isLogicalSearchOperator,
|
isLogicalSearchOperator,
|
||||||
EmptyFilterOption,
|
EmptyFilterOption,
|
||||||
SearchFilterChild,
|
SearchFilterGroup,
|
||||||
} from "@budibase/types"
|
} from "@budibase/types"
|
||||||
import * as Constants from "./constants"
|
import * as Constants from "./constants"
|
||||||
import { removeKeyNumbering } from "./filters"
|
import { removeKeyNumbering } from "./filters"
|
||||||
|
@ -132,18 +132,18 @@ export function isSupportedUserSearch(query: SearchFilters) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Processes the filter config. Filters are migrated from
|
* Processes the filter config. Filters are migrated from
|
||||||
* SearchFilter[] to SearchFilterGroup
|
* SearchFilter[] to UISearchFilter
|
||||||
*
|
*
|
||||||
* If filters is not an array, the migration is skipped
|
* If filters is not an array, the migration is skipped
|
||||||
*
|
*
|
||||||
* @param {LegacyFilter[] | SearchFilterGroup} filters
|
* @param {LegacyFilter[] | UISearchFilter} filters
|
||||||
*/
|
*/
|
||||||
export const processSearchFilters = (
|
export const processSearchFilters = (
|
||||||
filters: LegacyFilter[]
|
filters: LegacyFilter[]
|
||||||
): SearchFilterGroup => {
|
): UISearchFilter => {
|
||||||
// Base search config.
|
// Base search config.
|
||||||
const defaultCfg: SearchFilterGroup = {
|
const defaultCfg: UISearchFilter = {
|
||||||
logicalOperator: FilterGroupLogicalOperator.ALL,
|
logicalOperator: UILogicalOperator.ALL,
|
||||||
onEmptyFilter: EmptyFilterOption.RETURN_ALL,
|
onEmptyFilter: EmptyFilterOption.RETURN_ALL,
|
||||||
groups: [],
|
groups: [],
|
||||||
}
|
}
|
||||||
|
@ -159,11 +159,11 @@ export const processSearchFilters = (
|
||||||
"formulaType",
|
"formulaType",
|
||||||
]
|
]
|
||||||
|
|
||||||
let baseGroup: SearchFilterChild = {
|
let baseGroup: SearchFilterGroup = {
|
||||||
logicalOperator: FilterGroupLogicalOperator.ALL,
|
logicalOperator: UILogicalOperator.ALL,
|
||||||
}
|
}
|
||||||
|
|
||||||
return filters.reduce((acc: SearchFilterGroup, filter: LegacyFilter) => {
|
return filters.reduce((acc: UISearchFilter, filter: LegacyFilter) => {
|
||||||
// Sort the properties for easier debugging
|
// Sort the properties for easier debugging
|
||||||
const filterPropertyKeys = (Object.keys(filter) as (keyof LegacyFilter)[])
|
const filterPropertyKeys = (Object.keys(filter) as (keyof LegacyFilter)[])
|
||||||
.sort((a, b) => {
|
.sort((a, b) => {
|
||||||
|
@ -180,7 +180,7 @@ export const processSearchFilters = (
|
||||||
acc.onEmptyFilter = value
|
acc.onEmptyFilter = value
|
||||||
} else if (key === "operator" && value === "allOr") {
|
} else if (key === "operator" && value === "allOr") {
|
||||||
// Group 1 logical operator
|
// Group 1 logical operator
|
||||||
baseGroup.logicalOperator = FilterGroupLogicalOperator.ANY
|
baseGroup.logicalOperator = UILogicalOperator.ANY
|
||||||
}
|
}
|
||||||
|
|
||||||
return acc
|
return acc
|
||||||
|
|
|
@ -1,9 +1,5 @@
|
||||||
import { FieldType } from "../../documents"
|
import { FieldType } from "../../documents"
|
||||||
import {
|
import { EmptyFilterOption, UILogicalOperator, SearchFilters } from "../../sdk"
|
||||||
EmptyFilterOption,
|
|
||||||
FilterGroupLogicalOperator,
|
|
||||||
SearchFilters,
|
|
||||||
} from "../../sdk"
|
|
||||||
|
|
||||||
export type LegacyFilter = {
|
export type LegacyFilter = {
|
||||||
operator: keyof SearchFilters | "rangeLow" | "rangeHigh"
|
operator: keyof SearchFilters | "rangeLow" | "rangeHigh"
|
||||||
|
@ -14,15 +10,15 @@ export type LegacyFilter = {
|
||||||
externalType?: string
|
externalType?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export type SearchFilterChild = {
|
export type SearchFilterGroup = {
|
||||||
logicalOperator: FilterGroupLogicalOperator
|
logicalOperator?: UILogicalOperator
|
||||||
groups?: SearchFilterChild[]
|
groups?: SearchFilterGroup[]
|
||||||
filters?: LegacyFilter[]
|
filters?: LegacyFilter[]
|
||||||
}
|
}
|
||||||
|
|
||||||
// this is a type purely used by the UI
|
// this is a type purely used by the UI
|
||||||
export type SearchFilterGroup = {
|
export type UISearchFilter = {
|
||||||
logicalOperator: FilterGroupLogicalOperator
|
logicalOperator?: UILogicalOperator
|
||||||
onEmptyFilter: EmptyFilterOption
|
onEmptyFilter?: EmptyFilterOption
|
||||||
groups: SearchFilterChild[]
|
groups?: SearchFilterGroup[]
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { LegacyFilter, SearchFilterGroup, SortOrder, SortType } from "../../api"
|
import { LegacyFilter, UISearchFilter, SortOrder, SortType } from "../../api"
|
||||||
import { UIFieldMetadata } from "./table"
|
import { UIFieldMetadata } from "./table"
|
||||||
import { Document } from "../document"
|
import { Document } from "../document"
|
||||||
import { DBView, SearchFilters } from "../../sdk"
|
import { DBView, SearchFilters } from "../../sdk"
|
||||||
|
@ -92,7 +92,7 @@ export interface ViewV2 {
|
||||||
tableId: string
|
tableId: string
|
||||||
query?: LegacyFilter[] | SearchFilters
|
query?: LegacyFilter[] | SearchFilters
|
||||||
// duplicate to store UI information about filters
|
// duplicate to store UI information about filters
|
||||||
queryUI?: SearchFilterGroup
|
queryUI?: UISearchFilter
|
||||||
sort?: {
|
sort?: {
|
||||||
field: string
|
field: string
|
||||||
order?: SortOrder
|
order?: SortOrder
|
||||||
|
|
|
@ -203,7 +203,7 @@ export enum EmptyFilterOption {
|
||||||
RETURN_NONE = "none",
|
RETURN_NONE = "none",
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum FilterGroupLogicalOperator {
|
export enum UILogicalOperator {
|
||||||
ALL = "all",
|
ALL = "all",
|
||||||
ANY = "any",
|
ANY = "any",
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue