Bug fixes in the new filter interface (#8696)

* Bug fixes in the new filter interface

* Removed `eq`, `neq` filter for geometry type.

* Fixed tests for getFilterOperatorForType on geometry type.

* Removed `eq`, `neq`, `in`, `nin` filter operator for json

* Added `bigInteger` and `float` support in getFilterOperatorForType and fixed tests

* Added input regex pattern for numbers and uuid in filter input component
This commit is contained in:
Oreille
2021-10-12 15:53:18 +02:00
committed by GitHub
parent 475f6349f0
commit 9b66a77c39
6 changed files with 64 additions and 33 deletions

View File

@@ -10,7 +10,8 @@
<input
v-else-if="is === 'interface-input'"
ref="inputEl"
:type="type"
type="search"
:pattern="inputPattern"
:value="value"
:style="{ width }"
placeholder="--"
@@ -58,6 +59,10 @@ export default defineComponent({
type: [String, Number, Object, Boolean, Array] as PropType<string | number | Record<string, any> | boolean>,
default: null,
},
focus: {
type: Boolean,
default: true,
},
},
emits: ['input'],
setup(props, { emit }) {
@@ -76,20 +81,31 @@ export default defineComponent({
});
const width = computed(() => {
if (props.is === 'interface-input' && typeof props.value === 'string') {
return (props.value?.length >= 3 ? props.value.length + 1 : 3) + 'ch';
}
return (props.value?.toString().length || 2) + 1 + 'ch';
});
return 3 + 'ch';
const inputPattern = computed(() => {
switch (props.type) {
case 'integer':
case 'bigInteger':
return '[+-]?[0-9]+';
case 'decimal':
case 'float':
return '[+-]?[0-9]+\\.?[0-9]*';
case 'uuid':
return '[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}';
default:
return '';
}
});
onMounted(() => {
inputEl.value?.focus();
if (props.focus) inputEl.value?.focus();
});
const emitValueDebounced = debounce((val: unknown) => emitValue(val), 250);
return { displayValue, width, t, emitValueDebounced, inputEl };
return { displayValue, width, t, emitValueDebounced, inputEl, inputPattern };
function emitValue(val: unknown) {
if (val === '') {
@@ -140,6 +156,7 @@ input {
color: var(--primary);
font-family: var(--family-monospace);
line-height: 1em;
background-color: var(--background-page);
border: none;
&::placeholder {

View File

@@ -26,7 +26,13 @@
:class="{ moveComma: interfaceType === 'interface-input' }"
>
<div v-for="(val, index) in value" :key="index" class="value">
<input-component :is="interfaceType" :type="fieldInfo.type" :value="val" @input="setValueAt(index, $event)" />
<input-component
:is="interfaceType"
:type="fieldInfo.type"
:value="val"
:focus="false"
@input="setValueAt(index, $event)"
/>
</div>
</div>

View File

@@ -96,9 +96,10 @@ import { useFieldsStore } from '@/stores';
import { useI18n } from 'vue-i18n';
import { getFilterOperatorsForType } from '@directus/shared/utils';
import { get } from 'lodash';
import { FieldFilter, Filter, FilterOperator, LogicalFilterAND, LogicalFilterOR } from '@directus/shared/types';
import { FieldFilter, Filter, FieldFilterOperator, LogicalFilterAND, LogicalFilterOR } from '@directus/shared/types';
import { useSync } from '@directus/shared/composables';
import { fieldToFilter, getField, getNodeName, getComparator } from './utils';
import { toArray } from '@directus/shared/utils';
type FilterInfo =
| {
@@ -234,29 +235,38 @@ export default defineComponent({
}
}
function updateComparator(index: number, newVal: FilterOperator) {
function updateComparator(index: number, operator: keyof FieldFilterOperator) {
const nodeInfo = filterInfo.value[index];
if (nodeInfo.isField === false) return;
const valuePath = nodeInfo.field + '.' + nodeInfo.comparator;
const value = get(nodeInfo.node, valuePath);
let value = get(nodeInfo.node, valuePath);
if (['_in', '_nin'].includes(newVal)) {
if (Array.isArray(value) === false) update([value]);
} else if (['_between', '_nbetween'].includes(newVal)) {
if (Array.isArray(value) && value.length >= 2) update([value[0], value[1]]);
else update([null, null]);
} else if (Array.isArray(value) && value.length > 0) {
update(value[0]);
} else {
update(value);
switch (operator) {
case '_in':
case '_nin':
update(toArray(value) || []);
break;
case '_between':
case '_nbetween':
update((toArray(value) || []).slice(0, 2));
break;
case '_null':
case '_nnull':
case '_empty':
case '_nempty':
update(true);
break;
default:
update(Array.isArray(value) ? value[0] : value);
break;
}
function update(value: any) {
if (nodeInfo.isField === false) return;
filterSync.value = filterSync.value.map((filter, filterIndex) => {
if (filterIndex === index) return fieldToFilter(nodeInfo.field, newVal, value);
if (filterIndex === index) return fieldToFilter(nodeInfo.field, operator, value);
return filter;
});
}
@@ -310,7 +320,7 @@ export default defineComponent({
display: flex;
align-items: center;
width: fit-content;
margin-right: 12px;
margin-right: 18px;
margin-bottom: 8px;
padding: 2px 6px;
padding-right: 8px;

View File

@@ -123,8 +123,9 @@ export default defineComponent({
filterBorder,
};
function onClickOutside(e: { path: HTMLElement[] }) {
if (e.path.some((el) => el?.classList?.contains('v-menu-content'))) return false;
function onClickOutside(e: { path?: HTMLElement[]; composedPath?: () => HTMLElement[] }) {
const path = e.path || e.composedPath!();
if (path.some((el) => el?.classList?.contains('v-menu-content'))) return false;
return true;
}

View File

@@ -54,12 +54,8 @@ describe('', () => {
'lte',
'gt',
'gte',
'contains',
'ncontains',
'between',
'nbetween',
'empty',
'nempty',
'null',
'nnull',
'in',
@@ -85,7 +81,7 @@ describe('', () => {
});
it('returns the filter operators for json', () => {
expect(getFilterOperatorsForType(TYPES[8])).toStrictEqual(['eq', 'neq', 'null', 'nnull', 'in', 'nin']);
expect(getFilterOperatorsForType(TYPES[8])).toStrictEqual(['null', 'nnull']);
});
it('returns the filter operators for binary', () => {
@@ -109,8 +105,6 @@ describe('', () => {
it('returns the filter operators for geometry', () => {
expect(getFilterOperatorsForType(TYPES[17])).toStrictEqual([
'eq',
'neq',
'null',
'nnull',
'intersects',

View File

@@ -27,16 +27,19 @@ export function getFilterOperatorsForType(type: Type): ClientFilterOperator[] {
// JSON
// UUID
case 'uuid':
case 'json':
return ['eq', 'neq', 'null', 'nnull', 'in', 'nin'];
case 'json':
return ['null', 'nnull'];
// Boolean
case 'boolean':
return ['eq', 'neq', 'null', 'nnull'];
// Numbers
case 'bigInteger':
case 'integer':
case 'decimal':
case 'float':
return ['eq', 'neq', 'lt', 'lte', 'gt', 'gte', 'between', 'nbetween', 'null', 'nnull', 'in', 'nin'];
// Datetime
@@ -61,7 +64,7 @@ export function getFilterOperatorsForType(type: Type): ClientFilterOperator[] {
];
case 'geometry':
return ['eq', 'neq', 'null', 'nnull', 'intersects', 'nintersects', 'intersects_bbox', 'nintersects_bbox'];
return ['null', 'nnull', 'intersects', 'nintersects', 'intersects_bbox', 'nintersects_bbox'];
default:
return [