Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 25 additions & 19 deletions backend/src/baserow/contrib/integrations/local_baserow/mixins.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,26 +130,32 @@ def deserialize_filters(self, value, id_mapping):
:return: the deserialized version for the filter.
"""

return [
{
**f,
"field_id": (
id_mapping["database_fields"][f["field_id"]]
if "database_fields" in id_mapping
else f["field_id"]
),
"value": (
id_mapping["database_field_select_options"].get(
int(f["value"]["formula"]), f["value"]["formula"]
result = []

for f in value:
formula = BaserowFormulaObject.to_formula(f["value"])
field_id = id_mapping.get("database_fields", {}).get(
f["field_id"], f["field_id"]
)

if (
f["value_is_formula"]
or not formula["formula"].isdigit()
or "database_field_select_options" not in id_mapping
):
val = formula
else:
val = BaserowFormulaObject.create(
formula=str(
id_mapping["database_field_select_options"].get(
int(formula["formula"]), formula["formula"]
)
)
if "database_field_select_options" in id_mapping
and f["value"]["formula"].isdigit()
and not f["value_is_formula"]
else f["value"]["formula"]
),
}
for f in value
]
)

result.append({**f, "field_id": field_id, "value": val})

return result

def create_instance_from_serialized(
self,
Expand Down
24 changes: 22 additions & 2 deletions backend/src/baserow/core/formula/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,9 +78,29 @@ def execute(self, context: FormulaContext, args: FormulaArgs) -> Any:


class BaserowFormulaObject(TypedDict):
version: str
mode: BaserowFormulaMode
formula: BaserowFormula
mode: BaserowFormulaMode
version: str

@classmethod
def create(
cls,
formula: str = "",
mode: BaserowFormulaMode = BASEROW_FORMULA_MODE_SIMPLE,
version: str = "0.1",
) -> "BaserowFormulaObject":
return BaserowFormulaObject(formula=formula, mode=mode, version=version)

@classmethod
def to_formula(cls, value) -> "BaserowFormulaObject":
"""
Return a formula object even if it was a string.
"""

if isinstance(value, dict):
return value
else:
return cls.create(formula=value)


class BaserowFormulaMinified(TypedDict):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -132,14 +132,23 @@ def test_local_baserow_table_service_filterable_mixin_import_export(data_fixture
page=page, table=table, integration=integration
)
data_fixture.create_local_baserow_table_service_filter(
service=data_source.service, field=text_field, value="'foobar'", order=0
service=data_source.service,
field=text_field,
value="'foobar'",
order=0,
value_is_formula=True,
)
data_fixture.create_local_baserow_table_service_filter(
service=data_source.service, field=text_field, value="123", order=1
service=data_source.service,
field=text_field,
value="123",
order=1,
value_is_formula=True,
)
data_fixture.create_local_baserow_table_service_filter(
service=data_source.service,
field=single_select_field,
value_is_formula=False,
value=str(single_option.id),
order=2,
)
Expand Down Expand Up @@ -181,18 +190,24 @@ def test_local_baserow_table_service_filterable_mixin_import_export(data_fixture
imported_page = imported_builder.visible_pages.get()
imported_datasource = imported_page.datasource_set.get()
imported_filters = [
{"field_id": sf.field_id, "value": sf.value}
{
"field_id": sf.field_id,
"value": sf.value,
"value_is_formula": sf.value_is_formula,
}
for sf in imported_datasource.service.service_filters.all()
]

assert imported_filters == [
{
"field_id": imported_text_field.id,
"value": {"mode": "simple", "version": "0.1", "formula": "'foobar'"},
"value_is_formula": True,
},
{
"field_id": imported_text_field.id,
"value": {"mode": "simple", "version": "0.1", "formula": "123"},
"value_is_formula": True,
},
{
"field_id": imported_single_select_field.id,
Expand All @@ -201,6 +216,59 @@ def test_local_baserow_table_service_filterable_mixin_import_export(data_fixture
"version": "0.1",
"formula": str(imported_select_option.id),
},
"value_is_formula": False,
},
]


@pytest.mark.django_db()
def test_local_baserow_table_service_filterable_mixin_compat():
mixin = LocalBaserowTableServiceFilterableMixin()

id_mapping = {
"database_field_select_options": {1: 42},
"database_fields": {1: 41, 2: 42, 3: 43, 4: 44},
}

value_to_test = [
{"field_id": 1, "value": "'Formula as string'", "value_is_formula": True},
{"field_id": 2, "value": "1", "value_is_formula": False},
{"field_id": 3, "value": "", "value_is_formula": True},
{
"field_id": 4,
"value": {"mode": "simple", "version": "0.1", "formula": "'foobar'"},
"value_is_formula": True,
},
]

result = json.loads(
json.dumps(mixin.deserialize_filters(value_to_test, id_mapping))
)

assert result == [
{
"field_id": 41,
"value": {
"formula": "'Formula as string'",
"mode": "simple",
"version": "0.1",
},
"value_is_formula": True,
},
{
"field_id": 42,
"value": {"formula": "42", "mode": "simple", "version": "0.1"},
"value_is_formula": False,
},
{
"field_id": 43,
"value": {"formula": "", "mode": "simple", "version": "0.1"},
"value_is_formula": True,
},
{
"field_id": 44,
"value": {"mode": "simple", "version": "0.1", "formula": "'foobar'"},
"value_is_formula": True,
},
]

Expand Down
2 changes: 1 addition & 1 deletion web-frontend/modules/core/assets/scss/components/form.scss
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@

.control__elements--flex {
display: flex;
align-items: flex-start;
align-items: center;
gap: 5px;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
@input="emitAdvancedChange"
/>

<div v-if="enableAdvancedMode" class="margin-top-1">
<div v-if="showAdvancedCheckbox" class="margin-top-1">
<label class="checkbox">
<Checkbox
:checked="isAdvancedMode"
Expand Down Expand Up @@ -72,6 +72,7 @@ import DataExplorer from '@baserow/modules/core/components/dataExplorer/DataExpl
import { RuntimeGet } from '@baserow/modules/core/runtimeFormulaTypes'
import { isElement, onClickOutside } from '@baserow/modules/core/utils/dom'
import { isFormulaValid } from '@baserow/modules/core/formula'
import { FF_ADVANCED_FORMULA } from '@baserow/modules/core/plugins/featureFlags'

export default {
name: 'FormulaInputField',
Expand Down Expand Up @@ -222,6 +223,12 @@ export default {
nodeSelected() {
return this.dataNodeSelected?.attrs?.path || null
},
showAdvancedCheckbox() {
return (
this.enableAdvancedMode &&
this.$featureFlagIsEnabled(FF_ADVANCED_FORMULA)
)
},
},
watch: {
disabled(newValue) {
Expand Down
1 change: 0 additions & 1 deletion web-frontend/modules/core/formula/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ export const resolveFormula = (
const tree = parseBaserowFormula(formulaCtx.formula)
return new JavascriptExecutor(functions, RuntimeFormulaContext).visit(tree)
} catch (err) {
console.log('Error while parsing or executing formula:', err)
return ''
}
}
Expand Down
1 change: 1 addition & 0 deletions web-frontend/modules/core/plugins/featureFlags.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ export const FF_AUTOMATION = 'automation'
export const FF_ASSISTANT = 'assistant'
export const FF_WORKSPACE_SEARCH = 'workspace-search'
export const FF_DATE_DEPENDENCY = 'date_dependency'
export const FF_ADVANCED_FORMULA = 'advanced-formula'

/**
* A comma separated list of feature flags used to enable in-progress or not ready
Expand Down
Loading