Merge f41f85344c into 076cd214fe
This commit is contained in:
commit
9c97b5e008
|
|
@ -222,12 +222,22 @@ function focus() {
|
|||
editor.value?.commands.focus()
|
||||
}
|
||||
|
||||
function insertText(text: string) {
|
||||
if (!editor.value) return
|
||||
editor.value.commands.insertContent(text + ' ')
|
||||
const content = editor.value.getText()
|
||||
const processed = processContent(content)
|
||||
lastEmittedValue = processed
|
||||
emit('update:modelValue', processed)
|
||||
}
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
editor.value?.destroy()
|
||||
})
|
||||
|
||||
defineExpose({
|
||||
focus,
|
||||
insertText,
|
||||
})
|
||||
</script>
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,153 @@
|
|||
<template>
|
||||
<div id="filter-quick-keywords" class="keywords mbe-2">
|
||||
<div class="keywords-section">
|
||||
<span class="keywords-label">{{ $t('filters.keywords.fields') }}</span>
|
||||
<div class="keywords-buttons">
|
||||
<BaseButton
|
||||
v-for="field in filterFields"
|
||||
:key="field"
|
||||
v-tooltip="{
|
||||
content: $t(`filters.query.help.fields.${field}`),
|
||||
container: '#filter-quick-keywords',
|
||||
}"
|
||||
size="small"
|
||||
variant="ghost"
|
||||
class="keyword-btn"
|
||||
@click.prevent.stop="$emit('insert', field + ' = ')"
|
||||
>
|
||||
{{ field }}
|
||||
</BaseButton>
|
||||
</div>
|
||||
</div>
|
||||
<div class="keywords-section">
|
||||
<span class="keywords-label">{{ $t('filters.keywords.operators') }}</span>
|
||||
<div class="keywords-buttons">
|
||||
<BaseButton
|
||||
v-for="op in filterOperators"
|
||||
:key="op"
|
||||
v-tooltip="{
|
||||
content: $t(`filters.query.help.operators.${operatorKey(op)}`),
|
||||
container: '#filter-quick-keywords',
|
||||
}"
|
||||
size="small"
|
||||
variant="ghost"
|
||||
class="keyword-btn"
|
||||
@click.prevent.stop="$emit('insert', ' ' + op + ' ')"
|
||||
>
|
||||
{{ op }}
|
||||
</BaseButton>
|
||||
</div>
|
||||
</div>
|
||||
<div class="keywords-section">
|
||||
<span class="keywords-label">{{ $t('filters.keywords.join') }}</span>
|
||||
<div class="keywords-buttons">
|
||||
<BaseButton
|
||||
v-for="join in filterJoinOperators"
|
||||
:key="join"
|
||||
v-tooltip="{
|
||||
content: $t(`filters.query.help.logicalOperators.${joinOperatorKey(join)}`),
|
||||
container: '#filter-quick-keywords',
|
||||
}"
|
||||
size="small"
|
||||
variant="ghost"
|
||||
class="keyword-btn"
|
||||
@click.prevent.stop="$emit('insert', join + ' ')"
|
||||
>
|
||||
{{ join }}
|
||||
</BaseButton>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import BaseButton from '@/components/base/BaseButton.vue'
|
||||
import {
|
||||
AVAILABLE_FILTER_FIELDS,
|
||||
FILTER_OPERATORS,
|
||||
FILTER_JOIN_OPERATOR,
|
||||
} from '@/helpers/filters'
|
||||
|
||||
defineEmits<{
|
||||
insert: [text: string],
|
||||
}>()
|
||||
|
||||
const filterFields = AVAILABLE_FILTER_FIELDS
|
||||
const filterOperators = FILTER_OPERATORS
|
||||
const filterJoinOperators = FILTER_JOIN_OPERATOR
|
||||
|
||||
// Map operator symbols to i18n keys
|
||||
function operatorKey(op: string): string {
|
||||
const mapping: Record<string, string> = {
|
||||
'!=': 'notEqual',
|
||||
'=': 'equal',
|
||||
'>': 'greaterThan',
|
||||
'>=': 'greaterThanOrEqual',
|
||||
'<': 'lessThan',
|
||||
'<=': 'lessThanOrEqual',
|
||||
like: 'like',
|
||||
'not in': 'notIn',
|
||||
in: 'in',
|
||||
'?=': 'equal',
|
||||
}
|
||||
return mapping[op] || 'equal'
|
||||
}
|
||||
|
||||
// Map join operators to i18n keys
|
||||
function joinOperatorKey(join: string): string {
|
||||
const mapping: Record<string, string> = {
|
||||
'&&': 'and',
|
||||
'||': 'or',
|
||||
'(': 'parentheses',
|
||||
')': 'parentheses',
|
||||
}
|
||||
return mapping[join] || 'and'
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.keywords {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.5rem;
|
||||
padding: 0.5rem;
|
||||
background: var(--grey-100);
|
||||
border-radius: var(--radius);
|
||||
}
|
||||
|
||||
.keywords-section {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.25rem;
|
||||
}
|
||||
|
||||
.keywords-label {
|
||||
font-size: 0.75rem;
|
||||
font-weight: 600;
|
||||
color: var(--grey-600);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.05em;
|
||||
}
|
||||
|
||||
.keywords-buttons {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.25rem;
|
||||
}
|
||||
|
||||
.keyword-btn {
|
||||
font-family: monospace;
|
||||
font-size: 0.75rem;
|
||||
padding: 0.25rem 0.5rem;
|
||||
background: var(--white);
|
||||
border: 1px solid var(--grey-300);
|
||||
border-radius: var(--radius);
|
||||
transition: all var(--transition);
|
||||
|
||||
&:hover {
|
||||
background: var(--primary-light);
|
||||
border-color: var(--primary);
|
||||
color: var(--primary);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -13,6 +13,9 @@
|
|||
class="mbe-2"
|
||||
@update:modelValue="() => change('modelValue')"
|
||||
/>
|
||||
|
||||
<FilterQuickKeywords @insert="insertFilterKeyword" />
|
||||
|
||||
<div
|
||||
v-if="filterFromView"
|
||||
class="tw:text-sm mbe-2"
|
||||
|
|
@ -68,6 +71,7 @@ import {
|
|||
} from '@/helpers/filters'
|
||||
import FilterInputDocs from '@/components/input/filter/FilterInputDocs.vue'
|
||||
import FilterInput from '@/components/input/filter/FilterInput.vue'
|
||||
import FilterQuickKeywords from '@/components/input/filter/FilterQuickKeywords.vue'
|
||||
|
||||
const props = withDefaults(defineProps<{
|
||||
modelValue: TaskFilterParams,
|
||||
|
|
@ -122,6 +126,11 @@ const projectStore = useProjectStore()
|
|||
|
||||
const filterInputRef = ref()
|
||||
|
||||
function insertFilterKeyword(text: string) {
|
||||
filterInputRef.value?.insertText(text)
|
||||
filterInputRef.value?.focus()
|
||||
}
|
||||
|
||||
// Using watchDebounced to prevent the filter re-triggering itself.
|
||||
watch(
|
||||
() => props.modelValue,
|
||||
|
|
|
|||
|
|
@ -573,6 +573,11 @@
|
|||
"noResults": "No results",
|
||||
"fromView": "The current view has a filter set as well:",
|
||||
"fromViewBoth": "It will be used in combination with what you enter here.",
|
||||
"keywords": {
|
||||
"fields": "Fields",
|
||||
"operators": "Operators",
|
||||
"join": "Combine"
|
||||
},
|
||||
"attributes": {
|
||||
"title": "Title",
|
||||
"titlePlaceholder": "The saved filter title goes here…",
|
||||
|
|
|
|||
Loading…
Reference in New Issue