1
0
mirror of https://gitlab.com/bramw/baserow.git synced 2024-11-22 15:52:34 +00:00
bramw_baserow/web-frontend/modules/integrations/localBaserow/components/services/LocalBaserowTableServiceConditionalForm.vue
2024-10-17 15:49:51 +00:00

233 lines
7.6 KiB
Vue

<template>
<div v-if="value">
<div v-if="value.length === 0">
<div class="filters__none">
<div class="filters__none-title">
{{ $t('localBaserowTableServiceConditionalForm.noFilterTitle') }}
</div>
<div class="filters__none-description">
{{ $t('localBaserowTableServiceConditionalForm.noFilterText') }}
</div>
</div>
</div>
<ViewFieldConditionsForm
:filters="getSortedDataSourceFilters()"
:disable-filter="false"
:filter-type="filterType"
:fields="fields"
:read-only="false"
class="filters__items"
:prepare-value="prepareValue"
@deleteFilter="deleteFilter($event)"
@updateFilter="updateFilter($event)"
@updateFilterType="$emit('update:filterType', $event.value)"
>
<template
#filterInputComponent="{
slotProps: { filter, filterType: propFilterType },
}"
>
<InjectedFormulaInput
v-if="filter.value_is_formula && propFilterType.hasEditableValue"
v-model="filter.value"
class="filters__value--formula-input"
:placeholder="
$t(
'localBaserowTableServiceConditionalForm.formulaFilterInputPlaceholder'
)
"
/>
</template>
<template
#afterValueInput="{
slotProps: { filter, filterType: propFilterType, emitUpdate },
}"
>
<a
v-if="
propFilterType.hasEditableValue && !propFilterType.isDeprecated()
"
:title="
!filter.value_is_formula
? $t('localBaserowTableServiceConditionalForm.useFormulaForValue')
: $t('localBaserowTableServiceConditionalForm.useDefaultForValue')
"
class="filters__value--formula-toggle"
:class="{
'filters__value-formula-toggle--disabled': !filter.value_is_formula,
}"
@click="handleFormulaToggleClick(filter, emitUpdate)"
>
<i class="iconoir-sigma-function"></i>
</a>
</template>
</ViewFieldConditionsForm>
<div class="filters_footer">
<ButtonText
type="secondary"
size="small"
icon="iconoir-plus"
class="filters__add"
@click.prevent="addFilter()"
>
{{ $t('localBaserowTableServiceConditionalForm.addFilter') }}
</ButtonText>
</div>
</div>
</template>
<script>
import ViewFieldConditionsForm from '@baserow/modules/database/components/view/ViewFieldConditionsForm.vue'
import { hasCompatibleFilterTypes } from '@baserow/modules/database/utils/field'
import { notifyIf } from '@baserow/modules/core/utils/error'
import { v1 as uuidv1 } from 'uuid'
import InjectedFormulaInput from '@baserow/modules/core/components/formula/InjectedFormulaInput'
export default {
name: 'LocalBaserowTableServiceConditionalForm',
components: {
InjectedFormulaInput,
ViewFieldConditionsForm,
},
props: {
value: {
type: Array,
required: true,
},
fields: {
type: Array,
required: true,
},
filterType: {
type: String,
required: true,
},
},
computed: {
filterTypes() {
return this.$registry.getAll('viewFilter')
},
databaseSelected() {
return this.databases.find(
(database) => database.id === this.databaseSelectedId
)
},
tables() {
return this.databaseSelected?.tables || []
},
},
methods: {
/*
* Responsible for returning the first compatible field we have in
* our schema fields. Used by `addFilter` to decide what the newly
* added filter's field should be.
*/
getFirstCompatibleField(fields) {
return fields
.slice()
.sort((a, b) => b.primary - a.primary)
.find((field) => hasCompatibleFilterTypes(field, this.filterTypes))
},
/*
* Responsible for returning all current data source filters, but
* sorted by their `order`. Without the sorting, `ViewFieldConditionsForm`
* will add/update them in a haphazard way.
*/
getSortedDataSourceFilters() {
const dataSourceFilters = [...this.value]
return dataSourceFilters.sort((a, b) => a.order - b.order)
},
/*
* Responsible for asynchronously adding a new data source filter.
* By default it'll be for the first compatible field, of type equal,
* and value blank.
*/
async addFilter() {
try {
const field = this.getFirstCompatibleField(this.fields)
if (field === undefined) {
await this.$store.dispatch('toast/error', {
title: this.$t(
'localBaserowTableServiceConditionalForm.noCompatibleFilterTypesErrorTitle'
),
message: this.$t(
'localBaserowTableServiceConditionalForm.noCompatibleFilterTypesErrorMessage'
),
})
} else {
const newFilters = [...this.value]
// Setting an `id` of `uuidv1` is necessary for two reasons:
// 1) So that we can distinguish between filters locally
// 2) It has to match what is sorted against `sortNumbersAndUuid1Asc`.
newFilters.push({
id: uuidv1(),
field: field.id,
type: 'equal',
value: '',
value_is_formula: false,
})
this.$emit('input', newFilters)
}
} catch (error) {
notifyIf(error, 'dataSource')
}
},
/*
* Responsible for removing the chosen filter from the data source's filters.
*/
deleteFilter(filter) {
const newFilters = this.value.filter(({ id }) => {
return id !== filter.id
})
this.$emit('input', newFilters)
},
/*
* Responsible for updating the chosen filter in the data source's filters.
*/
updateFilter({ filter, values }) {
const newFilters = this.value.map((filterConf) => {
if (filterConf.id === filter.id) {
return { ...filterConf, ...values }
}
return filterConf
})
this.$emit('input', newFilters)
},
/*
* When the formula toggle is clicked, this is responsible for flipping
* the `value_is_formula` value and then tweaking the filter value, depending
* on the current state of `value_is_formula`.
*/
handleFormulaToggleClick(filter, emitUpdate) {
// If we're changing from a formula to a non-formula, we'll reset the value.
// If we're changing from a non-formula to a formula, we'll convert the value.
let newValue = filter.value
if (filter.value_is_formula) {
newValue = ''
} else if (filter.value) {
newValue = `'${filter.value}'`
}
emitUpdate({
value: newValue,
value_is_formula: !filter.value_is_formula,
})
},
/*
* Responsible for bypassing the `ViewFieldConditionsForm` component's
* `updateFilter` method behaviour if the field is a formula. By default,
* when a filter is updated, `filterType.prepareValue` is called. This is
* problematic because when formulas are introduced to filters, we don't
* want any additional processing to happen when the value is reset. For example,
* when a filter on a date is added, `LocalizedDateViewFilterType.prepareValue`
* will always add the timezone and `DATE_FILTER_TIMEZONE_VALUE_SEPARATOR`.
*/
prepareValue(value, filter, field, filterType) {
// When a filter is not editable (e.g. empty/not empty), ordinarily the
// value is reset to a blank string by prepareValue. As we want to skip
// this function, we have to reset manually here.
return filterType.hasEditableValue ? value : ''
},
},
}
</script>