mirror of
https://gitlab.com/bramw/baserow.git
synced 2025-03-31 19:35:02 +00:00
Resolve "Higher than and lower than frontend filters are not working with formulas"
This commit is contained in:
parent
59192c94f3
commit
709e895494
9 changed files with 174 additions and 55 deletions
changelog/entries/unreleased/bug
web-frontend
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"type": "bug",
|
||||
"message": "Fix higher_than and lower_than frontend view filters for formula fields.",
|
||||
"issue_number": 2289,
|
||||
"bullet_points": [],
|
||||
"created_at": "2024-01-17"
|
||||
}
|
|
@ -144,8 +144,6 @@ export default {
|
|||
this.$registry
|
||||
)
|
||||
|
||||
console.log(newRowValues)
|
||||
|
||||
this.$store.dispatch('rowModal/updated', {
|
||||
tableId: this.tableId,
|
||||
values: newRowValues,
|
||||
|
|
|
@ -36,7 +36,11 @@ export default {
|
|||
methods: {
|
||||
formattedDuration(value) {
|
||||
const metadata = this.entry.fields_metadata[this.fieldIdentifier]
|
||||
return DurationFieldType.formatValue(metadata, value)
|
||||
const durationFieldType = this.$registry.get(
|
||||
'field',
|
||||
DurationFieldType.getType()
|
||||
)
|
||||
return durationFieldType.formatValue(metadata, value)
|
||||
},
|
||||
},
|
||||
}
|
||||
|
|
|
@ -7,14 +7,14 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import { DurationFieldType } from '@baserow/modules/database/fieldTypes'
|
||||
import { formatDurationValue } from '@baserow/modules/database/utils/duration'
|
||||
|
||||
export default {
|
||||
name: 'FunctionalGridViewFieldDuration',
|
||||
functional: true,
|
||||
methods: {
|
||||
formatValue(field, value) {
|
||||
return DurationFieldType.formatValue(field, value)
|
||||
return formatDurationValue(value, field.duration_format)
|
||||
},
|
||||
},
|
||||
}
|
||||
|
|
|
@ -741,7 +741,7 @@ export class FieldType extends Registerable {
|
|||
* moment object, or a duration field can accept a string like '1:30' to
|
||||
* convert it to a number of seconds.
|
||||
*/
|
||||
static parseInputValue(field, value) {
|
||||
parseInputValue(field, value) {
|
||||
return value
|
||||
}
|
||||
}
|
||||
|
@ -1351,7 +1351,7 @@ export class NumberFieldType extends FieldType {
|
|||
return true
|
||||
}
|
||||
|
||||
static parseInputValue(field, value) {
|
||||
parseInputValue(field, value) {
|
||||
return parseFloat(value)
|
||||
}
|
||||
}
|
||||
|
@ -1683,8 +1683,8 @@ class BaseDateFieldType extends FieldType {
|
|||
* correct format for the field. If it can't be parsed null is returned.
|
||||
*/
|
||||
prepareValueForPaste(field, clipboardData, richClipboardData) {
|
||||
const dateValue = DateFieldType.parseInputValue(field, clipboardData || '')
|
||||
return DateFieldType.formatDate(field, dateValue)
|
||||
const dateValue = this.parseInputValue(field, clipboardData || '')
|
||||
return this.formatValue(field, dateValue)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1724,7 +1724,7 @@ class BaseDateFieldType extends FieldType {
|
|||
return formats
|
||||
}
|
||||
|
||||
static parseInputValue(field, dateString) {
|
||||
parseInputValue(field, dateString) {
|
||||
const formats = DateFieldType.getDateFormatsOptionsForValue(
|
||||
field,
|
||||
dateString
|
||||
|
@ -1751,8 +1751,8 @@ class BaseDateFieldType extends FieldType {
|
|||
return date
|
||||
}
|
||||
|
||||
static formatDate(field, date) {
|
||||
const momentDate = moment.utc(date)
|
||||
formatValue(field, value) {
|
||||
const momentDate = moment.utc(value)
|
||||
if (momentDate.isValid()) {
|
||||
return field.date_include_time
|
||||
? momentDate.format()
|
||||
|
@ -1838,9 +1838,9 @@ export class DateFieldType extends BaseDateFieldType {
|
|||
}
|
||||
|
||||
parseQueryParameter(field, value) {
|
||||
return DateFieldType.formatDate(
|
||||
return this.formatValue(
|
||||
field.field,
|
||||
DateFieldType.parseInputValue(field.field, value)
|
||||
this.parseInputValue(field.field, value)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -2280,11 +2280,11 @@ export class DurationFieldType extends FieldType {
|
|||
}
|
||||
|
||||
parseQueryParameter(field, value, options) {
|
||||
return DurationFieldType.parseInputValue(field, value)
|
||||
return this.parseInputValue(field.field, value)
|
||||
}
|
||||
|
||||
toSearchableString(field, value, delimiter = ', ') {
|
||||
return DurationFieldType.formatValue(field, value)
|
||||
return this.formatValue(field, value)
|
||||
}
|
||||
|
||||
getSort(name, order) {
|
||||
|
@ -2350,22 +2350,22 @@ export class DurationFieldType extends FieldType {
|
|||
return RowHistoryFieldDuration
|
||||
}
|
||||
|
||||
static formatValue(field, value) {
|
||||
formatValue(field, value) {
|
||||
return formatDurationValue(value, field.duration_format)
|
||||
}
|
||||
|
||||
static parseInputValue(field, value) {
|
||||
parseInputValue(field, value) {
|
||||
const format = field.duration_format
|
||||
const preparedValue = parseDurationValue(value, format)
|
||||
return roundDurationValueToFormat(preparedValue, format)
|
||||
}
|
||||
|
||||
toHumanReadableString(field, value, delimiter = ', ') {
|
||||
return DurationFieldType.formatValue(field, value)
|
||||
return this.formatValue(field, value)
|
||||
}
|
||||
|
||||
prepareValueForCopy(field, value) {
|
||||
return DurationFieldType.formatValue(field, value)
|
||||
return this.formatValue(field, value)
|
||||
}
|
||||
|
||||
prepareRichValueForCopy(field, value) {
|
||||
|
@ -2376,7 +2376,7 @@ export class DurationFieldType extends FieldType {
|
|||
if (richClipboardData && isNumeric(richClipboardData)) {
|
||||
return richClipboardData
|
||||
}
|
||||
return DurationFieldType.parseInputValue(field, clipboardData)
|
||||
return this.parseInputValue(field, clipboardData)
|
||||
}
|
||||
|
||||
getCanGroupByInView(field) {
|
||||
|
@ -3543,6 +3543,14 @@ export class FormulaFieldType extends FieldType {
|
|||
const subType = this.app.$registry.get('formula_type', field.formula_type)
|
||||
return subType.canGroupByInView(field)
|
||||
}
|
||||
|
||||
parseInputValue(field, value) {
|
||||
const underlyingFieldType = this.app.$registry.get(
|
||||
'field',
|
||||
this._mapFormulaTypeToFieldType(field.formula_type)
|
||||
)
|
||||
return underlyingFieldType.parseInputValue(field, value)
|
||||
}
|
||||
}
|
||||
|
||||
export class CountFieldType extends FormulaFieldType {
|
||||
|
|
|
@ -12,6 +12,11 @@ export default {
|
|||
formattedValue: '',
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
fieldType() {
|
||||
return this.$registry.get('field', DurationFieldType.getType())
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
value(value) {
|
||||
this.updateFormattedValue(this.field, value)
|
||||
|
@ -31,7 +36,7 @@ export default {
|
|||
return this.errorMsg
|
||||
},
|
||||
formatValue(field, value) {
|
||||
return DurationFieldType.formatValue(field, value)
|
||||
return this.fieldType.formatValue(field, value)
|
||||
},
|
||||
updateFormattedValue(field, value) {
|
||||
this.formattedValue = this.formatValue(field, value)
|
||||
|
@ -41,7 +46,7 @@ export default {
|
|||
if (this.errorMsg !== null) {
|
||||
return
|
||||
}
|
||||
const newCopy = DurationFieldType.parseInputValue(field, value)
|
||||
const newCopy = this.fieldType.parseInputValue(field, value)
|
||||
if (newCopy !== this.copy) {
|
||||
this.copy = newCopy
|
||||
return newCopy
|
||||
|
|
|
@ -1341,13 +1341,9 @@ export class HigherThanViewFilterType extends ViewFilterType {
|
|||
return true
|
||||
}
|
||||
|
||||
rowValue = fieldType.constructor.parseInputValue(field, rowValue)
|
||||
filterValue = fieldType.constructor.parseInputValue(field, filterValue)
|
||||
return (
|
||||
Number.isFinite(rowValue) &&
|
||||
Number.isFinite(filterValue) &&
|
||||
rowValue > filterValue
|
||||
)
|
||||
const rowVal = fieldType.parseInputValue(field, rowValue)
|
||||
const fltVal = fieldType.parseInputValue(field, filterValue)
|
||||
return Number.isFinite(rowVal) && Number.isFinite(fltVal) && rowVal > fltVal
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1388,13 +1384,9 @@ export class LowerThanViewFilterType extends ViewFilterType {
|
|||
return true
|
||||
}
|
||||
|
||||
rowValue = fieldType.constructor.parseInputValue(field, rowValue)
|
||||
filterValue = fieldType.constructor.parseInputValue(field, filterValue)
|
||||
return (
|
||||
Number.isFinite(rowValue) &&
|
||||
Number.isFinite(filterValue) &&
|
||||
rowValue < filterValue
|
||||
)
|
||||
const rowVal = fieldType.parseInputValue(field, rowValue)
|
||||
const fltVal = fieldType.parseInputValue(field, filterValue)
|
||||
return Number.isFinite(rowVal) && Number.isFinite(fltVal) && rowVal < fltVal
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -603,17 +603,20 @@ const queryParametersForParsing = [
|
|||
},
|
||||
{
|
||||
fieldType: new DurationFieldType(),
|
||||
input: { value: '1:01', field: { duration_format: 'h:mm' } },
|
||||
input: { value: '1:01', field: { field: { duration_format: 'h:mm' } } },
|
||||
output: 3660,
|
||||
},
|
||||
{
|
||||
fieldType: new DurationFieldType(),
|
||||
input: { value: '1:01:01', field: { duration_format: 'h:mm:ss' } },
|
||||
input: {
|
||||
value: '1:01:01',
|
||||
field: { field: { duration_format: 'h:mm:ss' } },
|
||||
},
|
||||
output: 3661,
|
||||
},
|
||||
{
|
||||
fieldType: new DurationFieldType(),
|
||||
input: { value: 61, field: { duration_format: 'h:mm' } },
|
||||
input: { value: 61, field: { field: { duration_format: 'h:mm' } } },
|
||||
output: 60, // the value is rounded according to the duration format
|
||||
},
|
||||
]
|
||||
|
|
|
@ -31,7 +31,11 @@ import {
|
|||
HigherThanViewFilterType,
|
||||
LowerThanViewFilterType,
|
||||
} from '@baserow/modules/database/viewFilters'
|
||||
import { DurationFieldType } from '@baserow/modules/database/fieldTypes'
|
||||
import {
|
||||
DurationFieldType,
|
||||
NumberFieldType,
|
||||
FormulaFieldType,
|
||||
} from '@baserow/modules/database/fieldTypes'
|
||||
|
||||
const dateBeforeCases = [
|
||||
{
|
||||
|
@ -1126,6 +1130,42 @@ const durationLowerThanCases = [
|
|||
},
|
||||
]
|
||||
|
||||
const numberValueIsHigherThanCases = [
|
||||
{
|
||||
rowValue: 2,
|
||||
filterValue: 0,
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
rowValue: null,
|
||||
filterValue: 0,
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
rowValue: 0,
|
||||
filterValue: '0',
|
||||
expected: false,
|
||||
},
|
||||
]
|
||||
|
||||
const numberValueIsLowerThanCases = [
|
||||
{
|
||||
rowValue: 1,
|
||||
filterValue: '2',
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
rowValue: null,
|
||||
filterValue: 0,
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
rowValue: 0,
|
||||
filterValue: '0',
|
||||
expected: false,
|
||||
},
|
||||
]
|
||||
|
||||
describe('All Tests', () => {
|
||||
let testApp = null
|
||||
|
||||
|
@ -1405,10 +1445,28 @@ describe('All Tests', () => {
|
|||
).toBe(true)
|
||||
})
|
||||
|
||||
test.each(durationHigherThanCases)('HigherThanFilterType', (values) => {
|
||||
const fieldType = new DurationFieldType()
|
||||
test.each(durationHigherThanCases)(
|
||||
'DurationHigherThanFilterType',
|
||||
(values) => {
|
||||
const fieldType = new DurationFieldType({
|
||||
app: testApp,
|
||||
})
|
||||
const { field } = values.context
|
||||
const result = new HigherThanViewFilterType({ app: testApp }).matches(
|
||||
values.rowValue,
|
||||
values.filterValue,
|
||||
field,
|
||||
fieldType
|
||||
)
|
||||
expect(result).toBe(values.expected)
|
||||
}
|
||||
)
|
||||
|
||||
test.each(durationLowerThanCases)('DurationLowerThanFilterType', (values) => {
|
||||
const app = testApp.getApp()
|
||||
const fieldType = new DurationFieldType({ app })
|
||||
const { field } = values.context
|
||||
const result = new HigherThanViewFilterType({ app: testApp }).matches(
|
||||
const result = new LowerThanViewFilterType({ app }).matches(
|
||||
values.rowValue,
|
||||
values.filterValue,
|
||||
field,
|
||||
|
@ -1417,15 +1475,59 @@ describe('All Tests', () => {
|
|||
expect(result).toBe(values.expected)
|
||||
})
|
||||
|
||||
test.each(durationLowerThanCases)('LowerThanFilterType', (values) => {
|
||||
const fieldType = new DurationFieldType()
|
||||
const { field } = values.context
|
||||
const result = new LowerThanViewFilterType({ app: testApp }).matches(
|
||||
values.rowValue,
|
||||
values.filterValue,
|
||||
field,
|
||||
fieldType
|
||||
)
|
||||
expect(result).toBe(values.expected)
|
||||
})
|
||||
test.each(numberValueIsHigherThanCases)(
|
||||
'NumberHigherThanFilterType',
|
||||
(values) => {
|
||||
const app = testApp.getApp()
|
||||
const result = new HigherThanViewFilterType({ app }).matches(
|
||||
values.rowValue,
|
||||
values.filterValue,
|
||||
{ type: 'number' },
|
||||
new NumberFieldType({ app })
|
||||
)
|
||||
expect(result).toBe(values.expected)
|
||||
}
|
||||
)
|
||||
|
||||
test.each(numberValueIsHigherThanCases)(
|
||||
'FormulaNumberHigherThanFilterType',
|
||||
(values) => {
|
||||
const app = testApp.getApp()
|
||||
const result = new HigherThanViewFilterType({ app }).matches(
|
||||
values.rowValue,
|
||||
values.filterValue,
|
||||
{ type: 'formula', formula_type: 'number' },
|
||||
new FormulaFieldType({ app })
|
||||
)
|
||||
expect(result).toBe(values.expected)
|
||||
}
|
||||
)
|
||||
|
||||
test.each(numberValueIsLowerThanCases)(
|
||||
'NumberLowerThanFilterType',
|
||||
(values) => {
|
||||
const app = testApp.getApp()
|
||||
const result = new LowerThanViewFilterType({ app }).matches(
|
||||
values.rowValue,
|
||||
values.filterValue,
|
||||
{ type: 'number' },
|
||||
new NumberFieldType({ app })
|
||||
)
|
||||
expect(result).toBe(values.expected)
|
||||
}
|
||||
)
|
||||
|
||||
test.each(numberValueIsLowerThanCases)(
|
||||
'FormulaNumberLowerThanFilterType',
|
||||
(values) => {
|
||||
const app = testApp.getApp()
|
||||
const result = new LowerThanViewFilterType({ app }).matches(
|
||||
values.rowValue,
|
||||
values.filterValue,
|
||||
{ type: 'formula', formula_type: 'number' },
|
||||
new FormulaFieldType({ app })
|
||||
)
|
||||
expect(result).toBe(values.expected)
|
||||
}
|
||||
)
|
||||
})
|
||||
|
|
Loading…
Add table
Reference in a new issue