Merge pull request #183 from shariquerik/quick-filters
feat: Quick filters on List View
This commit is contained in:
commit
7f10d75354
@ -126,6 +126,30 @@ def get_fields_meta(DocField, doctype, allowed_fieldtypes, restricted_fields):
|
||||
.run(as_dict=True)
|
||||
)
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_quick_filters(doctype: str):
|
||||
meta = frappe.get_meta(doctype)
|
||||
fields = [field for field in meta.fields if field.in_standard_filter]
|
||||
quick_filters = []
|
||||
|
||||
for field in fields:
|
||||
|
||||
if field.fieldtype == "Select":
|
||||
field.options = field.options.split("\n")
|
||||
field.options = [{"label": option, "value": option} for option in field.options]
|
||||
field.options.insert(0, {"label": "", "value": ""})
|
||||
quick_filters.append({
|
||||
"label": _(field.label),
|
||||
"name": field.fieldname,
|
||||
"type": field.fieldtype,
|
||||
"options": field.options,
|
||||
})
|
||||
|
||||
if doctype == "CRM Lead":
|
||||
quick_filters = [filter for filter in quick_filters if filter.get("name") != "converted"]
|
||||
|
||||
return quick_filters
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_list_data(
|
||||
doctype: str,
|
||||
|
||||
@ -14,6 +14,7 @@
|
||||
'form-input block h-7 w-full cursor-pointer select-none rounded border-gray-400 text-sm placeholder-gray-500',
|
||||
inputClass,
|
||||
]"
|
||||
v-bind="$attrs"
|
||||
/>
|
||||
</template>
|
||||
<template #body="{ togglePopover }">
|
||||
|
||||
@ -178,7 +178,7 @@ function convertFilters(data, allFilters) {
|
||||
let field = data.find((f) => f.fieldname === key)
|
||||
if (typeof value !== 'object') {
|
||||
value = ['=', value]
|
||||
if (field.fieldtype === 'Check') {
|
||||
if (field?.fieldtype === 'Check') {
|
||||
value = ['equals', value[1] ? 'Yes' : 'No']
|
||||
}
|
||||
}
|
||||
@ -276,6 +276,8 @@ function getOperators(fieldtype, fieldname) {
|
||||
if (typeDate.includes(fieldtype)) {
|
||||
options.push(
|
||||
...[
|
||||
{ label: __('Equals'), value: 'equals' },
|
||||
{ label: __('Not Equals'), value: 'not equals' },
|
||||
{ label: __('Is'), value: 'is' },
|
||||
{ label: __('>'), value: '>' },
|
||||
{ label: __('<'), value: '<' },
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="flex items-center justify-between px-5 py-4">
|
||||
<div class="flex items-center justify-between gap-2 px-5 py-4">
|
||||
<div class="flex items-center gap-2">
|
||||
<Dropdown :options="viewsDropdownOptions">
|
||||
<template #default="{ open }">
|
||||
@ -22,6 +22,64 @@
|
||||
</template>
|
||||
</Dropdown>
|
||||
</div>
|
||||
<div class="-mr-2 h-[70%] border-l" />
|
||||
<div
|
||||
class="flex flex-1 items-center overflow-x-auto px-1"
|
||||
style="
|
||||
mask-image: linear-gradient(
|
||||
to right,
|
||||
black calc(100% - 20px),
|
||||
transparent 100%
|
||||
);
|
||||
"
|
||||
>
|
||||
<div
|
||||
v-for="filter in quickFilterList"
|
||||
:key="filter.name"
|
||||
class="m-1 min-w-36"
|
||||
>
|
||||
<FormControl
|
||||
v-if="filter.type == 'Check'"
|
||||
:label="filter.label"
|
||||
type="checkbox"
|
||||
v-model="filter.value"
|
||||
@change.stop="applyQuickFilter(filter, $event.target.checked)"
|
||||
/>
|
||||
<FormControl
|
||||
v-else-if="filter.type === 'Select'"
|
||||
class="form-control cursor-pointer [&_select]:cursor-pointer"
|
||||
type="select"
|
||||
v-model="filter.value"
|
||||
:options="filter.options"
|
||||
:placeholder="filter.label"
|
||||
@change.stop="applyQuickFilter(filter, $event.target.value)"
|
||||
/>
|
||||
<Link
|
||||
v-else-if="filter.type === 'Link'"
|
||||
:value="filter.value"
|
||||
:doctype="filter.options"
|
||||
:placeholder="filter.label"
|
||||
@change="(data) => applyQuickFilter(filter, data)"
|
||||
/>
|
||||
<component
|
||||
v-else-if="['Date', 'Datetime'].includes(filter.type)"
|
||||
class="border-none"
|
||||
:is="filter.type === 'Date' ? DatePicker : DatetimePicker"
|
||||
:value="filter.value"
|
||||
@change="(v) => applyQuickFilter(filter, v)"
|
||||
:placeholder="filter.label"
|
||||
/>
|
||||
<FormControl
|
||||
v-else
|
||||
:value="filter.value"
|
||||
type="text"
|
||||
:placeholder="filter.label"
|
||||
:debounce="500"
|
||||
@change.stop="applyQuickFilter(filter, $event.target.value)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="-ml-2 h-[70%] border-l" />
|
||||
<div class="flex items-center gap-2">
|
||||
<div
|
||||
v-if="viewUpdated && route.query.view && (!view.public || isManager())"
|
||||
@ -131,6 +189,9 @@
|
||||
</Dialog>
|
||||
</template>
|
||||
<script setup>
|
||||
import DatePicker from '@/components/Controls/DatePicker.vue'
|
||||
import DatetimePicker from '@/components/Controls/DatetimePicker.vue'
|
||||
import Link from '@/components/Controls/Link.vue'
|
||||
import RefreshIcon from '@/components/Icons/RefreshIcon.vue'
|
||||
import EditIcon from '@/components/Icons/EditIcon.vue'
|
||||
import DuplicateIcon from '@/components/Icons/DuplicateIcon.vue'
|
||||
@ -384,6 +445,51 @@ const viewsDropdownOptions = computed(() => {
|
||||
return _views
|
||||
})
|
||||
|
||||
const quickFilterList = computed(() => {
|
||||
let filters = [{ name: 'name', label: __('ID') }]
|
||||
if (quickFilters.data) {
|
||||
filters.push(...quickFilters.data)
|
||||
}
|
||||
|
||||
filters.forEach((filter) => {
|
||||
filter['value'] = filter.type == 'Check' ? false : ''
|
||||
if (list.value.params?.filters[filter.name]) {
|
||||
let value = list.value.params.filters[filter.name]
|
||||
if (Array.isArray(value)) {
|
||||
filter['value'] = value[1].replace(/%/g, '')
|
||||
} else {
|
||||
filter['value'] = value.replace(/%/g, '')
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
return filters
|
||||
})
|
||||
|
||||
const quickFilters = createResource({
|
||||
url: 'crm.api.doc.get_quick_filters',
|
||||
params: { doctype: props.doctype },
|
||||
cache: ['Quick Filters', props.doctype],
|
||||
auto: true,
|
||||
})
|
||||
|
||||
function applyQuickFilter(filter, value) {
|
||||
let filters = { ...list.value.params.filters }
|
||||
let field = filter.name
|
||||
if (value) {
|
||||
if (['Check', 'Select', 'Link', 'Date', 'Datetime'].includes(filter.type)) {
|
||||
filters[field] = value
|
||||
} else {
|
||||
filters[field] = ['LIKE', `%${value}%`]
|
||||
}
|
||||
filter['value'] = value
|
||||
} else {
|
||||
delete filters[field]
|
||||
filter['value'] = ''
|
||||
}
|
||||
updateFilter(filters)
|
||||
}
|
||||
|
||||
function updateFilter(filters) {
|
||||
viewUpdated.value = true
|
||||
if (!defaultParams.value) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user