1
0
Fork 0
mirror of https://gitlab.com/bramw/baserow.git synced 2025-05-01 07:39:50 +00:00
bramw_baserow/web-frontend/modules/database/components/field/FieldFormulaSubForm.vue

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

220 lines
6.3 KiB
Vue
Raw Normal View History

2021-10-05 11:31:44 +00:00
<template>
<div>
<FieldFormulaInitialSubForm
:default-values="mergedTypeOptions"
:formula="values.formula"
:error="formulaError"
2021-10-05 11:31:44 +00:00
:formula-type="localOrServerFormulaType"
:table="table"
:view="view"
:primary="primary"
2021-10-05 11:31:44 +00:00
:loading="refreshingFormula"
:formula-type-refresh-needed="formulaTypeRefreshNeeded"
2024-04-02 19:50:44 +00:00
:all-fields-in-table="allFieldsInTable"
:database="database"
2021-10-05 11:31:44 +00:00
@open-advanced-context="
$refs.advancedFormulaEditContext.openContext($event)
"
@refresh-formula-type="refreshFormulaType"
2024-05-02 14:37:53 +00:00
@update-formula="values.formula = $event"
2021-10-05 11:31:44 +00:00
>
</FieldFormulaInitialSubForm>
<FormulaAdvancedEditContext
ref="advancedFormulaEditContext"
v-model="values.formula"
:table="table"
:fields="fieldsUsableInFormula"
:error="formulaError"
:database="database"
2025-02-17 13:17:35 +00:00
@blur="v$.values.formula.$touch()"
@hidden="v$.values.formula.$touch()"
2021-10-05 11:31:44 +00:00
>
</FormulaAdvancedEditContext>
</div>
</template>
<script>
2025-02-17 13:17:35 +00:00
import { required } from '@vuelidate/validators'
import { useVuelidate } from '@vuelidate/core'
2021-10-05 11:31:44 +00:00
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'
2023-09-04 12:17:41 +00:00
import parseBaserowFormula from '@baserow/modules/core/formula/parser/parser'
2021-10-05 11:31:44 +00:00
export default {
name: 'FieldFormulaSubForm',
components: {
FieldFormulaInitialSubForm,
FormulaAdvancedEditContext,
},
mixins: [form, fieldSubForm],
props: {
name: {
required: true,
type: String,
},
},
2025-02-17 13:17:35 +00:00
setup() {
return { v$: useVuelidate({ $lazy: true }) }
},
2021-10-05 11:31:44 +00:00
data() {
return {
allowedValues: ['formula'],
values: {
formula: '',
},
fetchedTypeOptions: { error: null },
mergedTypeOptions: { ...this.defaultValues },
2021-10-05 11:31:44 +00:00
parsingError: null,
previousValidParsedFormula: this.defaultValues.formula,
formulaTypeRefreshNeeded: false,
2021-10-05 11:31:44 +00:00
refreshingFormula: false,
}
},
computed: {
localOrServerFormulaType() {
return (
this.mergedTypeOptions.array_formula_type ||
this.mergedTypeOptions.formula_type
)
2021-10-05 11:31:44 +00:00
},
fieldsUsableInFormula() {
2024-04-02 19:50:44 +00:00
return this.allFieldsInTable.filter((f) => {
2021-10-05 11:31:44 +00:00
const isNotThisField = f.id !== this.defaultValues.id
2021-11-24 10:53:00 +00:00
const canBeReferencedByFormulaField = this.$registry
.get('field', f.type)
.canBeReferencedByFormulaField(f)
2021-11-24 10:53:00 +00:00
return isNotThisField && canBeReferencedByFormulaField
2021-10-05 11:31:44 +00:00
})
},
formulaError() {
2025-02-17 13:17:35 +00:00
if (this.v$.values.formula.required.$invalid) {
2021-10-05 11:31:44 +00:00
return 'Please enter a formula'
2025-02-17 13:17:35 +00:00
} else if (this.v$.values.formula.parseFormula.$invalid) {
2021-10-05 11:31:44 +00:00
return (
`Error in the formula on line ${this.parsingError.line} starting at
letter ${this.parsingError.character}` +
'\n' +
this.toHumanReadableErrorMessage(this.parsingError)
)
} else if (this.mergedTypeOptions.error) {
return this.mergedTypeOptions.error
2021-10-05 11:31:44 +00:00
} else {
return null
}
},
},
watch: {
defaultValues: {
deep: true,
handler(newValue) {
this.mergedTypeOptions = { ...newValue, ...this.fetchedTypeOptions }
},
2021-10-05 11:31:44 +00:00
},
fetchedTypeOptions: {
deep: true,
handler(newValue) {
this.mergedTypeOptions = { ...this.defaultValues, ...newValue }
},
2021-10-05 11:31:44 +00:00
},
},
methods: {
parseFormula(value) {
if (value == null) {
return false
}
if (!value.trim()) {
return false
}
try {
parseBaserowFormula(value)
this.parsingError = null
if (this.previousValidParsedFormula !== value) {
this.formulaTypeRefreshNeeded = true
this.previousValidParsedFormula = value
}
2021-10-05 11:31:44 +00:00
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) {
2021-11-24 10:53:00 +00:00
if (
[
'ERROR_WITH_FORMULA',
'ERROR_FIELD_SELF_REFERENCE',
'ERROR_FIELD_CIRCULAR_REFERENCE',
].includes(error.handler.code)
) {
this.fetchedTypeOptions.error = error.handler.detail
this.formulaTypeRefreshNeeded = false
2021-10-05 11:31:44 +00:00
return true
} else {
return false
}
},
reset() {
this.fetchedTypeOptions = { error: null }
this.formulaTypeRefreshNeeded = false
Object.assign(this.mergedTypeOptions, this.defaultValues)
2021-10-05 11:31:44 +00:00
form.methods.reset.call(this)
},
async refreshFormulaType() {
if (!this.name) {
this.$emit('validate')
return
}
2021-10-05 11:31:44 +00:00
try {
this.refreshingFormula = true
const { data } = await FormulaService(this.$client).type(
this.table.id,
this.name,
2021-10-05 11:31:44 +00:00
this.values.formula
)
this.fetchedTypeOptions = data
this.formulaTypeRefreshNeeded = false
2021-10-05 11:31:44 +00:00
} catch (e) {
if (!this.handleErrorByForm(e)) {
notifyIf(e, 'field')
} else {
this.formulaTypeRefreshNeeded = false
2021-10-05 11:31:44 +00:00
}
}
this.refreshingFormula = false
},
},
validations() {
return {
values: {
formula: {
required,
parseFormula: this.parseFormula,
},
},
}
},
}
</script>