1
0
forked from test/crm

Merge pull request #62 from shariquerik/datetime-in-filter

fix: Allow more fieldtypes in filter
This commit is contained in:
Shariq Ansari 2024-01-28 20:22:06 +05:30 committed by GitHub
commit 6ffb2e8b37
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 794 additions and 30 deletions

View File

@ -40,12 +40,16 @@ def get_filterable_fields(doctype: str):
"Data",
"Float",
"Int",
"Currency",
"Link",
"Long Text",
"Select",
"Small Text",
"Text Editor",
"Text",
"Duration",
"Date",
"Datetime",
]
c = get_controller(doctype)
@ -84,6 +88,8 @@ def get_filterable_fields(doctype: str):
{"fieldname": "_liked_by", "fieldtype": "Data", "label": "Liked By"},
{"fieldname": "_comments", "fieldtype": "Text", "label": "Comments"},
{"fieldname": "_assign", "fieldtype": "Text", "label": "Assigned To"},
{"fieldname": "creation", "fieldtype": "Datetime", "label": "Created On"},
{"fieldname": "modified", "fieldtype": "Datetime", "label": "Last Updated On"},
]
for field in standard_fields:
if (

View File

@ -134,15 +134,13 @@
"fieldname": "no_of_employees",
"fieldtype": "Select",
"label": "No. of Employees",
"options": "1-10\n11-50\n51-200\n201-500\n501-1000\n1000+",
"read_only": 1
"options": "1-10\n11-50\n51-200\n201-500\n501-1000\n1000+"
},
{
"fetch_from": "organization.annual_revenue",
"fieldname": "annual_revenue",
"fieldtype": "Currency",
"label": "Annual Revenue",
"read_only": 1
"label": "Annual Revenue"
},
{
"fieldname": "lead_owner",
@ -294,7 +292,7 @@
"image_field": "image",
"index_web_pages_for_search": 1,
"links": [],
"modified": "2024-01-22 14:33:21.980634",
"modified": "2024-01-28 18:35:02.604536",
"modified_by": "Administrator",
"module": "FCRM",
"name": "CRM Lead",

View File

@ -0,0 +1,265 @@
<template>
<Popover
@open="selectCurrentMonthYear"
class="flex w-full [&>div:first-child]:w-full"
>
<template #target="{ togglePopover }">
<input
readonly
type="text"
:placeholder="placeholder"
:value="value && formatter ? formatter(value) : value"
@focus="!readonly ? togglePopover() : null"
:class="[
'form-input block h-7 w-full cursor-pointer select-none rounded border-gray-400 text-sm placeholder-gray-500',
inputClass,
]"
/>
</template>
<template #body="{ togglePopover }">
<div
class="my-2 w-fit select-none space-y-3 rounded border border-gray-50 bg-white p-3 text-base shadow"
>
<div class="flex items-center text-gray-700">
<div
class="flex h-6 w-6 cursor-pointer items-center justify-center rounded hover:bg-gray-100"
>
<FeatherIcon
@click="prevMonth"
name="chevron-left"
class="h-5 w-5"
/>
</div>
<div class="flex-1 text-center text-lg font-medium text-blue-500">
{{ formatMonth }}
</div>
<div
class="flex h-6 w-6 cursor-pointer items-center justify-center rounded hover:bg-gray-100"
>
<FeatherIcon
@click="nextMonth"
name="chevron-right"
class="h-5 w-5"
/>
</div>
</div>
<div class="flex space-x-2">
<Input
type="text"
:value="value"
@change="selectDate(getDate($event)) || togglePopover()"
></Input>
<Button class="h-7" @click="selectDate(getDate()) || togglePopover()">
Today
</Button>
</div>
<div class="mt-2 flex flex-col items-center justify-center text-base">
<div class="flex w-full items-center space-x-1 text-gray-600">
<div
class="flex h-[30px] w-[30px] items-center justify-center text-center"
v-for="(d, i) in ['S', 'M', 'T', 'W', 'T', 'F', 'S']"
:key="i"
>
{{ d }}
</div>
</div>
<div v-for="(week, i) in datesAsWeeks" :key="i" class="mt-1">
<div class="flex w-full items-center">
<div
v-for="date in week"
:key="toValue(date)"
class="mr-1 flex h-[30px] w-[30px] cursor-pointer items-center justify-center rounded last:mr-0 hover:bg-blue-50 hover:text-blue-500"
:class="{
'text-gray-600': date.getMonth() !== currentMonth - 1,
'text-blue-500': toValue(date) === toValue(today),
'bg-blue-50 font-semibold text-blue-500':
toValue(date) === value,
}"
@click="
() => {
selectDate(date)
togglePopover()
}
"
>
{{ date.getDate() }}
</div>
</div>
</div>
</div>
<div class="mt-1 flex w-full justify-end">
<div
class="cursor-pointer rounded px-2 py-1 hover:bg-gray-100"
@click="
() => {
selectDate('')
togglePopover()
}
"
>
Clear
</div>
</div>
</div>
</template>
</Popover>
</template>
<script>
import { Popover } from 'frappe-ui'
export default {
name: 'DatePicker',
props: ['value', 'placeholder', 'formatter', 'readonly', 'inputClass'],
emits: ['change'],
components: {
Popover,
},
data() {
return {
currentYear: null,
currentMonth: null,
}
},
created() {
this.selectCurrentMonthYear()
},
computed: {
today() {
return this.getDate()
},
datesAsWeeks() {
let datesAsWeeks = []
let dates = this.dates.slice()
while (dates.length) {
let week = dates.splice(0, 7)
datesAsWeeks.push(week)
}
return datesAsWeeks
},
dates() {
if (!(this.currentYear && this.currentMonth)) {
return []
}
let monthIndex = this.currentMonth - 1
let year = this.currentYear
let firstDayOfMonth = this.getDate(year, monthIndex, 1)
let lastDayOfMonth = this.getDate(year, monthIndex + 1, 0)
let leftPaddingCount = firstDayOfMonth.getDay()
let rightPaddingCount = 6 - lastDayOfMonth.getDay()
let leftPadding = this.getDatesAfter(firstDayOfMonth, -leftPaddingCount)
let rightPadding = this.getDatesAfter(lastDayOfMonth, rightPaddingCount)
let daysInMonth = this.getDaysInMonth(monthIndex, year)
let datesInMonth = this.getDatesAfter(firstDayOfMonth, daysInMonth - 1)
let dates = [
...leftPadding,
firstDayOfMonth,
...datesInMonth,
...rightPadding,
]
if (dates.length < 42) {
const finalPadding = this.getDatesAfter(dates.at(-1), 42 - dates.length)
dates = dates.concat(...finalPadding)
}
return dates
},
formatMonth() {
let date = this.getDate(this.currentYear, this.currentMonth - 1, 1)
return date.toLocaleString('en-US', {
month: 'short',
year: 'numeric',
})
},
},
methods: {
selectDate(date) {
this.$emit('change', this.toValue(date))
},
selectCurrentMonthYear() {
let date = this.value ? this.getDate(this.value) : this.getDate()
if (date === 'Invalid Date') {
date = this.getDate()
}
this.currentYear = date.getFullYear()
this.currentMonth = date.getMonth() + 1
},
prevMonth() {
this.changeMonth(-1)
},
nextMonth() {
this.changeMonth(1)
},
changeMonth(adder) {
this.currentMonth = this.currentMonth + adder
if (this.currentMonth < 1) {
this.currentMonth = 12
this.currentYear = this.currentYear - 1
}
if (this.currentMonth > 12) {
this.currentMonth = 1
this.currentYear = this.currentYear + 1
}
},
getDatesAfter(date, count) {
let incrementer = 1
if (count < 0) {
incrementer = -1
count = Math.abs(count)
}
let dates = []
while (count) {
date = this.getDate(
date.getFullYear(),
date.getMonth(),
date.getDate() + incrementer
)
dates.push(date)
count--
}
if (incrementer === -1) {
return dates.reverse()
}
return dates
},
getDaysInMonth(monthIndex, year) {
let daysInMonthMap = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
let daysInMonth = daysInMonthMap[monthIndex]
if (monthIndex === 1 && this.isLeapYear(year)) {
return 29
}
return daysInMonth
},
isLeapYear(year) {
if (year % 400 === 0) return true
if (year % 100 === 0) return false
if (year % 4 === 0) return true
return false
},
toValue(date) {
if (!date) {
return ''
}
// toISOString is buggy and reduces the day by one
// this is because it considers the UTC timestamp
// in order to circumvent that we need to use luxon/moment
// but that refactor could take some time, so fixing the time difference
// as suggested in this answer.
// https://stackoverflow.com/a/16084846/3541205
date.setHours(0, -date.getTimezoneOffset(), 0, 0)
return date.toISOString().slice(0, 10)
},
getDate(...args) {
let d = new Date(...args)
return d
},
},
}
</script>

View File

@ -0,0 +1,313 @@
<template>
<Popover
@open="selectCurrentMonthYear"
class="flex w-full [&>div:first-child]:w-full"
>
<template #target="{ togglePopover }">
<input
readonly
type="text"
:placeholder="placeholder"
:value="formatter ? formatDates(value) : value"
@focus="!readonly ? togglePopover() : null"
:class="[
'form-input block h-7 w-full cursor-pointer select-none rounded border-gray-400 text-sm placeholder-gray-500 ',
inputClass,
]"
/>
</template>
<template #body="{ togglePopover }">
<div
class="my-2 w-[16rem] select-none space-y-3 rounded border border-gray-50 bg-white p-3 text-base shadow"
>
<div class="flex items-center text-gray-700">
<div
class="flex h-6 w-6 cursor-pointer items-center justify-center rounded hover:bg-gray-100"
>
<FeatherIcon
@click="prevMonth"
name="chevron-left"
class="h-5 w-5"
/>
</div>
<div class="flex-1 text-center text-lg font-medium text-blue-500">
{{ formatMonth }}
</div>
<div
class="flex h-6 w-6 cursor-pointer items-center justify-center rounded hover:bg-gray-100"
>
<FeatherIcon
@click="nextMonth"
name="chevron-right"
class="h-5 w-5"
/>
</div>
</div>
<div class="flex space-x-2">
<Input type="text" v-model="fromDate"></Input>
<Input type="text" v-model="toDate"></Input>
</div>
<div class="mt-2 flex flex-col items-center justify-center text-base">
<div
class="flex w-full items-center justify-center space-x-1 text-gray-600"
>
<div
class="flex h-[30px] w-[30px] items-center justify-center text-center"
v-for="(d, i) in ['S', 'M', 'T', 'W', 'T', 'F', 'S']"
:key="i"
>
{{ d }}
</div>
</div>
<div v-for="(week, i) in datesAsWeeks" :key="i">
<div class="flex w-full items-center">
<div
v-for="date in week"
:key="toValue(date)"
class="flex h-[30px] w-[30px] cursor-pointer items-center justify-center hover:bg-blue-50 hover:text-blue-500"
:class="{
'text-gray-600': date.getMonth() !== currentMonth - 1,
'text-blue-500': toValue(date) === toValue(today),
'bg-blue-50 text-blue-500': isInRange(date),
'rounded-l-md bg-blue-100':
fromDate && toValue(date) === toValue(fromDate),
'rounded-r-md bg-blue-100':
toDate && toValue(date) === toValue(toDate),
}"
@click="() => handleDateClick(date)"
>
{{ date.getDate() }}
</div>
</div>
</div>
</div>
<div class="mt-1 flex w-full justify-end space-x-2">
<Button @click="() => clearDates()" :disabled="!value">
Clear
</Button>
<Button
@click="() => selectDates() | togglePopover()"
:disabled="!fromDate || !toDate"
variant="solid"
>
Apply
</Button>
</div>
</div>
</template>
</Popover>
</template>
<script>
import { Popover } from 'frappe-ui'
export default {
name: 'DateRangePicker',
props: ['value', 'placeholder', 'formatter', 'readonly', 'inputClass'],
emits: ['change'],
components: {
Popover,
},
data() {
const fromDate = this.value ? this.value.split(',')[0] : ''
const toDate = this.value ? this.value.split(',')[1] : ''
return {
currentYear: null,
currentMonth: null,
fromDate,
toDate,
}
},
created() {
this.selectCurrentMonthYear()
},
computed: {
today() {
return this.getDate()
},
datesAsWeeks() {
let datesAsWeeks = []
let dates = this.dates.slice()
while (dates.length) {
let week = dates.splice(0, 7)
datesAsWeeks.push(week)
}
return datesAsWeeks
},
dates() {
if (!(this.currentYear && this.currentMonth)) {
return []
}
let monthIndex = this.currentMonth - 1
let year = this.currentYear
let firstDayOfMonth = this.getDate(year, monthIndex, 1)
let lastDayOfMonth = this.getDate(year, monthIndex + 1, 0)
let leftPaddingCount = firstDayOfMonth.getDay()
let rightPaddingCount = 6 - lastDayOfMonth.getDay()
let leftPadding = this.getDatesAfter(firstDayOfMonth, -leftPaddingCount)
let rightPadding = this.getDatesAfter(lastDayOfMonth, rightPaddingCount)
let daysInMonth = this.getDaysInMonth(monthIndex, year)
let datesInMonth = this.getDatesAfter(firstDayOfMonth, daysInMonth - 1)
let dates = [
...leftPadding,
firstDayOfMonth,
...datesInMonth,
...rightPadding,
]
if (dates.length < 42) {
const finalPadding = this.getDatesAfter(dates.at(-1), 42 - dates.length)
dates = dates.concat(...finalPadding)
}
return dates
},
formatMonth() {
let date = this.getDate(this.currentYear, this.currentMonth - 1, 1)
return date.toLocaleString('en-US', {
month: 'short',
year: 'numeric',
})
},
},
methods: {
handleDateClick(date) {
if (this.fromDate && this.toDate) {
this.fromDate = this.toValue(date)
this.toDate = ''
} else if (this.fromDate && !this.toDate) {
this.toDate = this.toValue(date)
} else {
this.fromDate = this.toValue(date)
}
this.swapDatesIfNecessary()
},
selectDates() {
if (!this.fromDate && !this.toDate) {
return this.$emit('change', '')
}
this.$emit('change', `${this.fromDate},${this.toDate}`)
},
swapDatesIfNecessary() {
if (!this.fromDate || !this.toDate) {
return
}
// if fromDate is greater than toDate, swap them
let fromDate = this.getDate(this.fromDate)
let toDate = this.getDate(this.toDate)
if (fromDate > toDate) {
let temp = fromDate
fromDate = toDate
toDate = temp
}
this.fromDate = this.toValue(fromDate)
this.toDate = this.toValue(toDate)
},
selectCurrentMonthYear() {
let date = this.toDate ? this.getDate(this.toDate) : this.today
this.currentYear = date.getFullYear()
this.currentMonth = date.getMonth() + 1
},
prevMonth() {
this.changeMonth(-1)
},
nextMonth() {
this.changeMonth(1)
},
changeMonth(adder) {
this.currentMonth = this.currentMonth + adder
if (this.currentMonth < 1) {
this.currentMonth = 12
this.currentYear = this.currentYear - 1
}
if (this.currentMonth > 12) {
this.currentMonth = 1
this.currentYear = this.currentYear + 1
}
},
getDatesAfter(date, count) {
let incrementer = 1
if (count < 0) {
incrementer = -1
count = Math.abs(count)
}
let dates = []
while (count) {
date = this.getDate(
date.getFullYear(),
date.getMonth(),
date.getDate() + incrementer
)
dates.push(date)
count--
}
if (incrementer === -1) {
return dates.reverse()
}
return dates
},
getDaysInMonth(monthIndex, year) {
let daysInMonthMap = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
let daysInMonth = daysInMonthMap[monthIndex]
if (monthIndex === 1 && this.isLeapYear(year)) {
return 29
}
return daysInMonth
},
isLeapYear(year) {
if (year % 400 === 0) return true
if (year % 100 === 0) return false
if (year % 4 === 0) return true
return false
},
toValue(date) {
if (!date) {
return ''
}
if (typeof date === 'string') {
return date
}
// toISOString is buggy and reduces the day by one
// this is because it considers the UTC timestamp
// in order to circumvent that we need to use luxon/moment
// but that refactor could take some time, so fixing the time difference
// as suggested in this answer.
// https://stackoverflow.com/a/16084846/3541205
date.setHours(0, -date.getTimezoneOffset(), 0, 0)
return date.toISOString().slice(0, 10)
},
getDate(...args) {
let d = new Date(...args)
return d
},
isInRange(date) {
if (!this.fromDate || !this.toDate) {
return false
}
return (
date >= this.getDate(this.fromDate) && date <= this.getDate(this.toDate)
)
},
formatDates(value) {
if (!value) {
return ''
}
const values = value.split(',')
return this.formatter(values[0]) + ' to ' + this.formatter(values[1])
},
clearDates() {
this.fromDate = ''
this.toDate = ''
this.selectDates()
},
},
}
</script>

View File

@ -44,19 +44,10 @@
/>
</div>
<div id="value" class="!min-w-[140px]">
<Link
v-if="typeLink.includes(f.field.fieldtype)"
class="form-control"
:value="f.value"
:doctype="f.field.options"
@change="(v) => updateValue(v, f)"
placeholder="Value"
/>
<component
v-else
:is="getValSelect(f.field.fieldtype, f.field.options)"
:is="getValSelect(f)"
:value="f.value"
@change="(e) => updateValue(e.target.value, f)"
@change="(v) => updateValue(v, f)"
placeholder="Value"
/>
</div>
@ -103,6 +94,8 @@
</NestedPopover>
</template>
<script setup>
import DatePicker from '@/components/Controls/DatePicker.vue'
import DateRangePicker from '@/components/Controls/DateRangePicker.vue'
import NestedPopover from '@/components/NestedPopover.vue'
import FilterIcon from '@/components/Icons/FilterIcon.vue'
import Link from '@/components/Controls/Link.vue'
@ -111,9 +104,10 @@ import { h, defineModel, computed } from 'vue'
const typeCheck = ['Check']
const typeLink = ['Link']
const typeNumber = ['Float', 'Int']
const typeNumber = ['Float', 'Int', 'Currency', 'Percent']
const typeSelect = ['Select']
const typeString = ['Data', 'Long Text', 'Small Text', 'Text Editor', 'Text']
const typeDate = ['Date', 'Datetime']
const props = defineProps({
doctype: {
@ -181,6 +175,10 @@ function convertFilters(data, allFilters) {
value = ['equals', value[1] ? 'Yes' : 'No']
}
}
if (value[0] === 'LIKE' || value[0] === 'NOT LIKE') {
value[1] = value[1].replace(/%/g, '')
}
if (field) {
f.push({
field,
@ -202,13 +200,16 @@ function getOperators(fieldtype, fieldname) {
{ label: 'Not Equals', value: 'not equals' },
{ label: 'Like', value: 'like' },
{ label: 'Not Like', value: 'not like' },
{ label: 'Is', value: 'is' },
]
)
}
if (fieldname === '_assign') {
// TODO: make equals and not equals work
options = [
{ label: 'Like', value: 'like' },
{ label: 'Not Like', value: 'not like' },
{ label: 'Is', value: 'is' },
]
}
if (typeNumber.includes(fieldtype)) {
@ -223,22 +224,79 @@ function getOperators(fieldtype, fieldname) {
]
)
}
if (typeSelect.includes(fieldtype) || typeLink.includes(fieldtype)) {
if (typeSelect.includes(fieldtype)) {
options.push(
...[
{ label: 'Equals', value: 'equals' },
{ label: 'Not Equals', value: 'not equals' },
{ label: 'Is', value: 'is' },
{ label: 'Is Not', value: 'is not' },
]
)
}
if (typeLink.includes(fieldtype)) {
options.push(
...[
{ label: 'Equals', value: 'equals' },
{ label: 'Not Equals', value: 'not equals' },
{ label: 'Is', value: 'is' },
{ label: 'Like', value: 'like' },
{ label: 'Not Like', value: 'not like' },
]
)
}
if (typeCheck.includes(fieldtype)) {
options.push(...[{ label: 'Equals', value: 'equals' }])
}
if (['Duration'].includes(fieldtype)) {
options.push(
...[
{ label: 'Like', value: 'like' },
{ label: 'Not Like', value: 'not like' },
{ label: 'Is', value: 'is' },
]
)
}
if (typeDate.includes(fieldtype)) {
options.push(
...[
{ label: 'Is', value: 'is' },
{ label: '>', value: '>' },
{ label: '<', value: '<' },
{ label: '>=', value: '>=' },
{ label: '<=', value: '<=' },
{ label: 'Between', value: 'between' },
{ label: 'Timespan', value: 'timespan' },
]
)
}
return options
}
function getValSelect(fieldtype, options) {
if (typeSelect.includes(fieldtype) || typeCheck.includes(fieldtype)) {
function getValSelect(f) {
const { field, operator } = f
const { fieldtype, options } = field
if (operator == 'is') {
return h(FormControl, {
type: 'select',
options: [
{
label: 'Set',
value: 'set',
},
{
label: 'Not Set',
value: 'not set',
},
],
})
} else if (operator == 'timespan') {
return h(FormControl, {
type: 'select',
options: timespanOptions,
})
} else if (operator == 'like') {
return h(FormControl, { type: 'text' })
} else if (typeSelect.includes(fieldtype) || typeCheck.includes(fieldtype)) {
const _options =
fieldtype == 'Check' ? ['Yes', 'No'] : getSelectOptions(options)
return h(FormControl, {
@ -248,6 +306,14 @@ function getValSelect(fieldtype, options) {
value: o,
})),
})
} else if (typeLink.includes(fieldtype)) {
return h(Link, { class: 'form-control', doctype: options })
} else if (typeNumber.includes(fieldtype)) {
return h(FormControl, { type: 'number' })
} else if (typeDate.includes(fieldtype) && operator == 'between') {
return h(DateRangePicker)
} else if (typeDate.includes(fieldtype)) {
return h(DatePicker)
} else {
return h(FormControl, { type: 'text' })
}
@ -260,16 +326,22 @@ function getDefaultValue(field) {
if (typeCheck.includes(field.fieldtype)) {
return 'Yes'
}
if (typeDate.includes(field.fieldtype)) {
return null
}
return ''
}
function getDefaultOperator(fieldtype) {
if (typeSelect.includes(fieldtype) || typeLink.includes(fieldtype)) {
return 'is'
if (typeSelect.includes(fieldtype)) {
return 'equals'
}
if (typeCheck.includes(fieldtype) || typeNumber.includes(fieldtype)) {
return 'equals'
}
if (typeDate.includes(fieldtype)) {
return 'between'
}
return 'like'
}
@ -278,6 +350,7 @@ function getSelectOptions(options) {
}
function setfilter(data) {
if (!data) return
filters.value.add({
field: {
label: data.label,
@ -320,15 +393,47 @@ function clearfilter(close) {
}
function updateValue(value, filter) {
filter.value = value
value = value.target ? value.target.value : value
if (filter.operator === 'between') {
filter.value = [value.split(',')[0], value.split(',')[1]]
} else {
filter.value = value
}
apply()
}
function updateOperator(event, filter) {
let oldOperatorValue = event.target._value
let newOperatorValue = event.target.value
filter.operator = event.target.value
if (!isSameTypeOperator(oldOperatorValue, newOperatorValue)) {
filter.value = getDefaultValue(filter.field)
}
if (newOperatorValue === 'is' || newOperatorValue === 'is not') {
filter.value = 'set'
}
apply()
}
function isSameTypeOperator(oldOperator, newOperator) {
let textOperators = [
'like',
'not like',
'equals',
'not equals',
'>',
'<',
'>=',
'<=',
]
if (
textOperators.includes(oldOperator) &&
textOperators.includes(newOperator)
)
return true
return false
}
function apply() {
let _filters = []
filters.value.forEach((f) => {
@ -342,8 +447,8 @@ function apply() {
}
function parseFilters(filters) {
const l__ = Array.from(filters)
const obj = l__.map(transformIn).reduce((p, c) => {
const filtersArray = Array.from(filters)
const obj = filtersArray.map(transformIn).reduce((p, c) => {
if (['equals', '='].includes(c.operator)) {
p[c.fieldname] =
c.value == 'Yes' ? true : c.value == 'No' ? false : c.value
@ -364,8 +469,8 @@ function transformIn(f) {
}
const operatorMap = {
is: '=',
'is not': '!=',
is: 'is',
'is not': 'is not',
equals: '=',
'not equals': '!=',
yes: true,
@ -376,12 +481,16 @@ const operatorMap = {
'<': '<',
'>=': '>=',
'<=': '<=',
between: 'between',
timespan: 'timespan',
}
const oppositeOperatorMap = {
'=': 'is',
is: 'is',
'=': 'equals',
'!=': 'not equals',
equals: 'equals',
'!=': 'is not',
'is not': 'is not',
true: 'yes',
false: 'no',
LIKE: 'like',
@ -390,5 +499,78 @@ const oppositeOperatorMap = {
'<': '<',
'>=': '>=',
'<=': '<=',
between: 'between',
timespan: 'timespan',
}
const timespanOptions = [
{
label: 'Last Week',
value: 'last week',
},
{
label: 'Last Month',
value: 'last month',
},
{
label: 'Last Quarter',
value: 'last quarter',
},
{
label: 'Last 6 Months',
value: 'last 6 months',
},
{
label: 'Last Year',
value: 'last year',
},
{
label: 'Yesterday',
value: 'yesterday',
},
{
label: 'Today',
value: 'today',
},
{
label: 'Tomorrow',
value: 'tomorrow',
},
{
label: 'This Week',
value: 'this week',
},
{
label: 'This Month',
value: 'this month',
},
{
label: 'This Quarter',
value: 'this quarter',
},
{
label: 'This Year',
value: 'this year',
},
{
label: 'Next Week',
value: 'next week',
},
{
label: 'Next Month',
value: 'next month',
},
{
label: 'Next Quarter',
value: 'next quarter',
},
{
label: 'Next 6 Months',
value: 'next 6 months',
},
{
label: 'Next Year',
value: 'next year',
},
]
</script>