mirror of
https://github.com/directus/directus.git
synced 2026-04-25 03:00:53 -04:00
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:
@@ -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 {
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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 [
|
||||
|
||||
Reference in New Issue
Block a user