feat(mongodb): add range and list operators to document filters

This commit is contained in:
zipg authored and GitHub committed 2026-09-18 22:47:51 +08:00
1 parent ef086865dd
commit 6d8e0d886a
7 files changed
+242 -9

No files matched your search

@@ -39,6 +39,8 @@ import {
searchDocumentFieldPathTree,
documentFilterModeNeedsValue,
documentFilterModeOptionsFor,
documentFilterModeUsesList,
documentFilterModeUsesRange,
documentFilterValueTypeOptions,
documentStoreProviderFor,
elasticsearchBoolClauseOptions,
@@ -893,6 +895,7 @@ function updateDocumentFilterRule(ruleId: string, patch: Partial<DocumentFilterR
} else {
if (patch.fieldName !== undefined && patch.fieldName !== rule.fieldName) next.valueType = "auto";
if (!documentFilterModeNeedsValue(next.mode)) next.rawValue = "";
if (!documentFilterModeUsesRange(next.mode)) next.rawEndValue = "";
}
return next;
});
@@ -3092,8 +3095,39 @@ defineExpose({ focusSearch });
</SelectContent>
</Select>
<div v-if="documentStoreProvider.kind !== 'elasticsearch' && documentFilterModeUsesRange(rule.mode)" class="flex min-w-0 items-center gap-1.5">
<Input
:model-value="rule.rawValue"
class="h-8 min-w-0 flex-1 text-xs"
:placeholder="t('grid.filterBuilderRangeStart')"
@update:model-value="(value) => updateDocumentFilterRule(rule.id, { rawValue: String(value ?? '') })"
@compositionend="endDocumentFilterImeComposition(`value-start:${rule.id}`)"
@compositionstart="startDocumentFilterImeComposition(`value-start:${rule.id}`)"
@keydown="handleDocumentFilterValueKeydown($event, rule.id)"
/>
<span class="shrink-0 text-[10px] text-muted-foreground">—</span>
<Input
:model-value="rule.rawEndValue"
class="h-8 min-w-0 flex-1 text-xs"
:placeholder="t('grid.filterBuilderRangeEnd')"
@update:model-value="(value) => updateDocumentFilterRule(rule.id, { rawEndValue: String(value ?? '') })"
@compositionend="endDocumentFilterImeComposition(`value-end:${rule.id}`)"
@compositionstart="startDocumentFilterImeComposition(`value-end:${rule.id}`)"
@keydown="handleDocumentFilterValueKeydown($event, rule.id)"
/>
</div>
<textarea
v-else-if="documentStoreProvider.kind !== 'elasticsearch' && documentFilterModeUsesList(rule.mode)"
:value="rule.rawValue"
rows="2"
class="min-h-8 w-full min-w-0 resize-y rounded-md border bg-background px-2 py-1 text-xs outline-none"
:placeholder="t('grid.filterBuilderValues')"
@input="updateDocumentFilterRule(rule.id, { rawValue: ($event.target as HTMLTextAreaElement).value })"
@keydown.ctrl.enter.prevent="applyDocumentStructuredFilters"
@keydown.meta.enter.prevent="applyDocumentStructuredFilters"
/>
<Input
v-if="documentStoreProvider.kind === 'elasticsearch' ? elasticsearchQueryTypeNeedsValue(rule.elasticsearchQueryType) : documentFilterModeNeedsValue(rule.mode)"
v-else-if="documentStoreProvider.kind === 'elasticsearch' ? elasticsearchQueryTypeNeedsValue(rule.elasticsearchQueryType) : documentFilterModeNeedsValue(rule.mode)"
:model-value="rule.rawValue"
class="h-8 min-w-0 text-xs"
:placeholder="t('grid.filterBuilderValue')"
@@ -8,7 +8,18 @@ import { Input } from "@/components/ui/input";
import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover";
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
import { useToast } from "@/composables/useToast";
import { buildDocumentFilterCondition, currentDocumentFilterJson, currentDocumentSortJson, documentFilterModeNeedsValue, documentFilterModeOptions, documentStoreProviderFor, type DocumentFilterMode, type DocumentFilterRule } from "@/lib/app/documentStoreProvider";
import {
buildDocumentFilterCondition,
currentDocumentFilterJson,
currentDocumentSortJson,
documentFilterModeNeedsValue,
documentFilterModeOptions,
documentFilterModeUsesList,
documentFilterModeUsesRange,
documentStoreProviderFor,
type DocumentFilterMode,
type DocumentFilterRule,
} from "@/lib/app/documentStoreProvider";
import { isTauriRuntime } from "@/lib/backend/tauriRuntime";
import * as api from "@/lib/backend/api";
import { uuid } from "@/lib/common/utils";
@@ -147,6 +158,7 @@ function updateFilterRule(ruleId: string, patch: Partial<DocumentFilterRule>) {
if (rule.id !== ruleId) return rule;
const next = { ...rule, ...patch };
if (!documentFilterModeNeedsValue(next.mode)) next.rawValue = "";
if (!documentFilterModeUsesRange(next.mode)) next.rawEndValue = "";
return next;
});
}
@@ -548,8 +560,23 @@ watch(
</SelectContent>
</Select>
<div v-if="documentFilterModeUsesRange(rule.mode)" class="flex min-w-0 items-center gap-1.5">
<Input :model-value="rule.rawValue" class="h-8 min-w-0 flex-1 text-xs" :placeholder="t('grid.filterBuilderRangeStart')" @update:model-value="(value) => updateFilterRule(rule.id, { rawValue: String(value ?? '') })" @keydown.enter.prevent="applyStructuredFilters" />
<span class="shrink-0 text-[10px] text-muted-foreground">—</span>
<Input :model-value="rule.rawEndValue" class="h-8 min-w-0 flex-1 text-xs" :placeholder="t('grid.filterBuilderRangeEnd')" @update:model-value="(value) => updateFilterRule(rule.id, { rawEndValue: String(value ?? '') })" @keydown.enter.prevent="applyStructuredFilters" />
</div>
<textarea
v-else-if="documentFilterModeUsesList(rule.mode)"
:value="rule.rawValue"
rows="2"
class="min-h-8 w-full min-w-0 resize-y rounded-md border bg-background px-2 py-1 text-xs outline-none"
:placeholder="t('grid.filterBuilderValues')"
@input="updateFilterRule(rule.id, { rawValue: ($event.target as HTMLTextAreaElement).value })"
@keydown.ctrl.enter.prevent="applyStructuredFilters"
@keydown.meta.enter.prevent="applyStructuredFilters"
/>
<Input
v-if="documentFilterModeNeedsValue(rule.mode)"
v-else-if="documentFilterModeNeedsValue(rule.mode)"
:model-value="rule.rawValue"
class="h-8 min-w-0 text-xs"
:placeholder="t('grid.filterBuilderValue')"