mirror of
https://gitlab.com/bramw/baserow.git
synced 2025-04-12 16:28:06 +00:00
231 lines
6.7 KiB
Vue
231 lines
6.7 KiB
Vue
<template>
|
|
<div>
|
|
<FieldFormulaInitialSubForm
|
|
:default-values="mergedTypeOptions"
|
|
:formula="values.formula"
|
|
:error="localOrServerError"
|
|
:formula-type="localOrServerFormulaType"
|
|
:table="table"
|
|
:loading="refreshingFormula"
|
|
:formula-type-refresh-needed="formulaTypeRefreshNeeded"
|
|
@open-advanced-context="
|
|
$refs.advancedFormulaEditContext.openContext($event)
|
|
"
|
|
@refresh-formula-type="refreshFormulaType"
|
|
>
|
|
</FieldFormulaInitialSubForm>
|
|
<FormulaAdvancedEditContext
|
|
ref="advancedFormulaEditContext"
|
|
v-model="values.formula"
|
|
:table="table"
|
|
:fields="fieldsUsableInFormula"
|
|
:error="localOrServerError"
|
|
@blur="$v.values.formula.$touch()"
|
|
>
|
|
</FormulaAdvancedEditContext>
|
|
</div>
|
|
</template>
|
|
|
|
<script>
|
|
import { required } from 'vuelidate/lib/validators'
|
|
import { mapGetters } from 'vuex'
|
|
|
|
import form from '@baserow/modules/core/mixins/form'
|
|
import { notifyIf } from '@baserow/modules/core/utils/error'
|
|
|
|
import fieldSubForm from '@baserow/modules/database/mixins/fieldSubForm'
|
|
import FieldFormulaInitialSubForm from '@baserow/modules/database/components/formula/FieldFormulaInitialSubForm'
|
|
import FormulaAdvancedEditContext from '@baserow/modules/database/components/formula/FormulaAdvancedEditContext'
|
|
import FormulaService from '@baserow/modules/database/services/formula'
|
|
import parseBaserowFormula from '@baserow/modules/database/formula/parser/parser'
|
|
|
|
export default {
|
|
name: 'FieldFormulaSubForm',
|
|
components: {
|
|
FieldFormulaInitialSubForm,
|
|
FormulaAdvancedEditContext,
|
|
},
|
|
mixins: [form, fieldSubForm],
|
|
data() {
|
|
return {
|
|
allowedValues: ['formula'],
|
|
values: {
|
|
formula: '',
|
|
},
|
|
typeOptions: {},
|
|
mergedTypeOptions: Object.assign({}, this.defaultValues),
|
|
parsingError: null,
|
|
errorFromServer: null,
|
|
localFormulaType: null,
|
|
localArrayFormulaType: null,
|
|
initialFormula: null,
|
|
refreshingFormula: false,
|
|
}
|
|
},
|
|
computed: {
|
|
...mapGetters({
|
|
rawFields: 'field/getAllWithPrimary',
|
|
}),
|
|
localOrServerFormulaType() {
|
|
return this.localFormulaType
|
|
? this.localArrayFormulaType || this.localFormulaType
|
|
: this.defaultValues.array_formula_type ||
|
|
this.defaultValues.formula_type
|
|
},
|
|
fieldsUsableInFormula() {
|
|
return this.rawFields.filter((f) => {
|
|
const isNotThisField = f.id !== this.defaultValues.id
|
|
const canBeReferencedByFormulaField = this.$registry
|
|
.get('field', f.type)
|
|
.canBeReferencedByFormulaField()
|
|
return isNotThisField && canBeReferencedByFormulaField
|
|
})
|
|
},
|
|
localOrServerError() {
|
|
const dirty = this.$v.values.formula.$dirty
|
|
if (dirty && !this.$v.values.formula.required) {
|
|
return 'Please enter a formula'
|
|
} else if (dirty && !this.$v.values.formula.parseFormula) {
|
|
return (
|
|
`Error in the formula on line ${this.parsingError.line} starting at
|
|
letter ${this.parsingError.character}` +
|
|
'\n' +
|
|
this.toHumanReadableErrorMessage(this.parsingError)
|
|
)
|
|
} else if (this.errorFromServer) {
|
|
return this.errorFromServer
|
|
} else if (this.defaultValues.error) {
|
|
return this.defaultValues.error
|
|
} else {
|
|
return null
|
|
}
|
|
},
|
|
formulaChanged() {
|
|
return (
|
|
this.initialFormula !== null &&
|
|
this.values.formula !== this.initialFormula
|
|
)
|
|
},
|
|
updatingExistingFormula() {
|
|
return !!this.defaultValues.id
|
|
},
|
|
formulaTypeRefreshNeeded() {
|
|
return (
|
|
this.formulaChanged &&
|
|
!this.parsingError &&
|
|
this.updatingExistingFormula
|
|
)
|
|
},
|
|
},
|
|
watch: {
|
|
defaultValues(newValue, oldValue) {
|
|
this.mergedTypeOptions = Object.assign({}, newValue)
|
|
},
|
|
'values.formula'(newValue, oldValue) {
|
|
this.parseFormula(newValue)
|
|
},
|
|
},
|
|
methods: {
|
|
parseFormula(value) {
|
|
if (value == null) {
|
|
return false
|
|
}
|
|
if (!value.trim()) {
|
|
return false
|
|
}
|
|
try {
|
|
parseBaserowFormula(value)
|
|
if (!this.initialFormula) {
|
|
this.initialFormula = this.values.formula
|
|
}
|
|
this.parsingError = null
|
|
return true
|
|
} catch (e) {
|
|
this.parsingError = e
|
|
return false
|
|
}
|
|
},
|
|
toHumanReadableErrorMessage(error) {
|
|
const s = error.message
|
|
.replace('extraneous', 'Invalid')
|
|
.replace('input', 'letters')
|
|
.replace(' expecting', ', was instead expecting ')
|
|
.replace("'<EOF>'", 'the end of the formula')
|
|
.replace('<EOF>', 'the end of the formula')
|
|
.replace('mismatched letters', 'Unexpected')
|
|
.replace('Unexpected the', 'Unexpected')
|
|
.replace('SINGLEQ_STRING_LITERAL', 'a single quoted string')
|
|
.replace('DOUBLEQ_STRING_LITERAL', 'a double quoted string')
|
|
.replace('IDENTIFIER', 'a function')
|
|
.replace('IDENTIFIER_UNICODE', '')
|
|
.replace('{', '')
|
|
.replace('}', '')
|
|
return s + '.'
|
|
},
|
|
handleErrorByForm(error) {
|
|
if (
|
|
[
|
|
'ERROR_WITH_FORMULA',
|
|
'ERROR_FIELD_SELF_REFERENCE',
|
|
'ERROR_FIELD_CIRCULAR_REFERENCE',
|
|
].includes(error.handler.code)
|
|
) {
|
|
this.errorFromServer = error.handler.detail
|
|
return true
|
|
} else {
|
|
return false
|
|
}
|
|
},
|
|
reset() {
|
|
const formula = this.values.formula
|
|
form.methods.reset.call(this)
|
|
this.errorFromServer = null
|
|
this.initialFormula = formula
|
|
this.values.formula = formula
|
|
},
|
|
async refreshFormulaType() {
|
|
try {
|
|
this.refreshingFormula = true
|
|
const { data } = await FormulaService(this.$client).type(
|
|
this.defaultValues.id,
|
|
this.values.formula
|
|
)
|
|
// eslint-disable-next-line camelcase
|
|
const { formula_type, array_formula_type, error, ...otherTypeOptions } =
|
|
data
|
|
|
|
this.mergedTypeOptions = Object.assign(
|
|
{},
|
|
this.mergedTypeOptions,
|
|
otherTypeOptions
|
|
)
|
|
if (error) {
|
|
this.errorFromServer = `Error with formula: ${error}.`
|
|
} else {
|
|
this.errorFromServer = null
|
|
}
|
|
// eslint-disable-next-line camelcase
|
|
this.localFormulaType = formula_type
|
|
// eslint-disable-next-line camelcase
|
|
this.localArrayFormulaType = array_formula_type
|
|
} catch (e) {
|
|
if (!this.handleErrorByForm(e)) {
|
|
notifyIf(e, 'field')
|
|
}
|
|
}
|
|
this.initialFormula = this.values.formula
|
|
this.refreshingFormula = false
|
|
},
|
|
},
|
|
validations() {
|
|
return {
|
|
values: {
|
|
formula: {
|
|
required,
|
|
parseFormula: this.parseFormula,
|
|
},
|
|
},
|
|
}
|
|
},
|
|
}
|
|
</script>
|