mirror of
https://gitlab.com/bramw/baserow.git
synced 2025-04-07 06:15:36 +00:00
Add new Collection Field Type of Boolean
This commit is contained in:
parent
7e04a43b51
commit
cddcd8e3e5
12 changed files with 299 additions and 4 deletions
backend
src/baserow/contrib/builder
tests/baserow/contrib/builder/elements
changelog/entries/unreleased/feature
web-frontend/modules
builder
core/assets/scss/components/builder/elements/ab_components
|
@ -242,11 +242,13 @@ class BuilderConfig(AppConfig):
|
|||
builder_workflow_action_type_registry.register(LogoutWorkflowActionType())
|
||||
|
||||
from .elements.collection_field_types import (
|
||||
BooleanCollectionFieldType,
|
||||
LinkCollectionFieldType,
|
||||
TextCollectionFieldType,
|
||||
)
|
||||
from .elements.registries import collection_field_type_registry
|
||||
|
||||
collection_field_type_registry.register(BooleanCollectionFieldType())
|
||||
collection_field_type_registry.register(TextCollectionFieldType())
|
||||
collection_field_type_registry.register(LinkCollectionFieldType())
|
||||
|
||||
|
|
|
@ -6,6 +6,40 @@ from baserow.contrib.builder.formula_importer import import_formula
|
|||
from baserow.core.formula.serializers import FormulaSerializerField
|
||||
|
||||
|
||||
class BooleanCollectionFieldType(CollectionFieldType):
|
||||
type = "boolean"
|
||||
allowed_fields = ["value"]
|
||||
serializer_field_names = ["value"]
|
||||
|
||||
class SerializedDict(TypedDict):
|
||||
value: bool
|
||||
|
||||
@property
|
||||
def serializer_field_overrides(self):
|
||||
return {
|
||||
"value": FormulaSerializerField(
|
||||
help_text="The boolean value.",
|
||||
required=False,
|
||||
allow_blank=True,
|
||||
default=False,
|
||||
),
|
||||
}
|
||||
|
||||
def deserialize_property(
|
||||
self,
|
||||
prop_name: str,
|
||||
value: Any,
|
||||
id_mapping: Dict[str, Any],
|
||||
data_source_id: Optional[int] = None,
|
||||
) -> Any:
|
||||
if prop_name == "value" and data_source_id:
|
||||
return import_formula(value, id_mapping, data_source_id=data_source_id)
|
||||
|
||||
return super().deserialize_property(
|
||||
prop_name, value, id_mapping, data_source_id
|
||||
)
|
||||
|
||||
|
||||
class TextCollectionFieldType(CollectionFieldType):
|
||||
type = "text"
|
||||
allowed_fields = ["value"]
|
||||
|
|
|
@ -0,0 +1,132 @@
|
|||
"""
|
||||
Test the BooleanCollectionFieldType class.
|
||||
"""
|
||||
|
||||
from unittest.mock import patch
|
||||
|
||||
import pytest
|
||||
|
||||
from baserow.contrib.builder.elements.collection_field_types import (
|
||||
BooleanCollectionFieldType,
|
||||
)
|
||||
from baserow.core.formula.serializers import FormulaSerializerField
|
||||
|
||||
MODULE_PATH = "baserow.contrib.builder.elements.collection_field_types"
|
||||
|
||||
|
||||
def test_class_properties_are_set():
|
||||
"""
|
||||
Test that the properties of the class are correctly set.
|
||||
|
||||
Ensure the type, allowed_fields, and serializer_field_names properties
|
||||
are set to the correct values.
|
||||
"""
|
||||
|
||||
expected_type = "boolean"
|
||||
expected_allowed_fields = ["value"]
|
||||
expected_serializer_field_names = ["value"]
|
||||
|
||||
bool_field_type = BooleanCollectionFieldType()
|
||||
|
||||
assert bool_field_type.type == expected_type
|
||||
assert bool_field_type.allowed_fields == expected_allowed_fields
|
||||
assert bool_field_type.serializer_field_names == expected_serializer_field_names
|
||||
|
||||
|
||||
def test_serializer_field_overrides_returns_expected_value():
|
||||
"""
|
||||
Ensure the serializer_field_overrides() method returns the expected value.
|
||||
"""
|
||||
|
||||
result = BooleanCollectionFieldType().serializer_field_overrides
|
||||
field = result["value"]
|
||||
|
||||
assert type(field) == FormulaSerializerField
|
||||
assert field.allow_blank is True
|
||||
assert field.default is False
|
||||
assert field.required is False
|
||||
assert field.help_text == "The boolean value."
|
||||
|
||||
|
||||
@patch(f"{MODULE_PATH}.CollectionFieldType.deserialize_property")
|
||||
@patch(f"{MODULE_PATH}.import_formula")
|
||||
def test_deserialize_property_returns_value_from_import_formula(
|
||||
mock_import_formula, mock_super_deserialize
|
||||
):
|
||||
"""
|
||||
Ensure the deserialize_property() method uses import_formula() if the
|
||||
prop_name is 'value' and a data_source_id is provided.
|
||||
"""
|
||||
|
||||
mock_value = "foo"
|
||||
mock_import_formula.return_value = mock_value
|
||||
prop_name = "value"
|
||||
value = "foo"
|
||||
id_mapping = {}
|
||||
data_source_id = 1
|
||||
|
||||
result = BooleanCollectionFieldType().deserialize_property(
|
||||
prop_name,
|
||||
value,
|
||||
id_mapping,
|
||||
data_source_id,
|
||||
)
|
||||
|
||||
assert result == mock_value
|
||||
mock_import_formula.assert_called_once_with(
|
||||
value,
|
||||
id_mapping,
|
||||
data_source_id=data_source_id,
|
||||
)
|
||||
mock_super_deserialize.assert_not_called()
|
||||
|
||||
|
||||
@patch(f"{MODULE_PATH}.CollectionFieldType.deserialize_property")
|
||||
@patch(f"{MODULE_PATH}.import_formula")
|
||||
@pytest.mark.parametrize(
|
||||
"prop_name,data_source_id",
|
||||
[
|
||||
("", 1),
|
||||
(" ", 1),
|
||||
("", None),
|
||||
(" ", None),
|
||||
# Intentionally misspelt "value"
|
||||
("vallue", 1),
|
||||
("value", None),
|
||||
],
|
||||
)
|
||||
def test_deserialize_property_returns_value_from_super_method(
|
||||
mock_import_formula,
|
||||
mock_super_deserialize,
|
||||
prop_name,
|
||||
data_source_id,
|
||||
):
|
||||
"""
|
||||
Ensure that the value is returned by calling the parent class's
|
||||
deserialize_property() method.
|
||||
|
||||
If the prop_name is "value" *and* the data_source_id is not empty, the
|
||||
import_formula() is called. All other combinations should cause the
|
||||
super method to be called instead.
|
||||
"""
|
||||
|
||||
mock_value = "foo"
|
||||
mock_super_deserialize.return_value = mock_value
|
||||
value = "foo"
|
||||
id_mapping = {}
|
||||
|
||||
result = BooleanCollectionFieldType().deserialize_property(
|
||||
prop_name,
|
||||
value,
|
||||
id_mapping,
|
||||
data_source_id,
|
||||
)
|
||||
|
||||
assert result == mock_value
|
||||
mock_import_formula.assert_not_called()
|
||||
mock_super_deserialize.assert_called_once_with(
|
||||
prop_name,
|
||||
value,
|
||||
id_mapping,
|
||||
data_source_id,
|
||||
)
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"type": "feature",
|
||||
"message": "Add a new Collection Field Type of Boolean in Application Builder.",
|
||||
"issue_number": 2359,
|
||||
"bullet_points": [],
|
||||
"created_at": "2024-04-04"
|
||||
}
|
|
@ -1,9 +1,14 @@
|
|||
import { Registerable } from '@baserow/modules/core/registry'
|
||||
import BooleanField from '@baserow/modules/builder/components/elements/components/collectionField/BooleanField'
|
||||
import TextField from '@baserow/modules/builder/components/elements/components/collectionField/TextField'
|
||||
import LinkField from '@baserow/modules/builder/components/elements/components/collectionField/LinkField'
|
||||
import BooleanFieldForm from '@baserow/modules/builder/components/elements/components/collectionField/form/BooleanFieldForm'
|
||||
import TextFieldForm from '@baserow/modules/builder/components/elements/components/collectionField/form/TextFieldForm'
|
||||
import LinkFieldForm from '@baserow/modules/builder/components/elements/components/collectionField/form/LinkFieldForm'
|
||||
import { ensureString } from '@baserow/modules/core/utils/validator'
|
||||
import {
|
||||
ensureBoolean,
|
||||
ensureString,
|
||||
} from '@baserow/modules/core/utils/validator'
|
||||
import resolveElementUrl from '@baserow/modules/builder/utils/urlResolution'
|
||||
import { pathParametersInError } from '@baserow/modules/builder/utils/params'
|
||||
|
||||
|
@ -38,6 +43,36 @@ export class CollectionFieldType extends Registerable {
|
|||
}
|
||||
}
|
||||
|
||||
export class BooleanCollectionFieldType extends CollectionFieldType {
|
||||
static getType() {
|
||||
return 'boolean'
|
||||
}
|
||||
|
||||
get name() {
|
||||
return this.app.i18n.t('collectionFieldType.boolean')
|
||||
}
|
||||
|
||||
get component() {
|
||||
return BooleanField
|
||||
}
|
||||
|
||||
get formComponent() {
|
||||
return BooleanFieldForm
|
||||
}
|
||||
|
||||
getProps(field, { resolveFormula, applicationContext }) {
|
||||
try {
|
||||
return { value: ensureBoolean(resolveFormula(field.value)) }
|
||||
} catch (error) {
|
||||
return { value: false }
|
||||
}
|
||||
}
|
||||
|
||||
getOrder() {
|
||||
return 5
|
||||
}
|
||||
}
|
||||
|
||||
export class TextCollectionFieldType extends CollectionFieldType {
|
||||
static getType() {
|
||||
return 'text'
|
||||
|
|
|
@ -4,11 +4,13 @@
|
|||
type="checkbox"
|
||||
:checked="value"
|
||||
:required="required"
|
||||
:disabled="disabled"
|
||||
class="ab-checkbox__input"
|
||||
:disabled="disabled"
|
||||
:class="{
|
||||
'ab-checkbox--error': error,
|
||||
'ab-checkbox--readonly': readOnly,
|
||||
}"
|
||||
:aria-disabled="disabled"
|
||||
/>
|
||||
<label v-if="hasSlot" class="ab-checkbox__label">
|
||||
<slot></slot>
|
||||
|
@ -52,6 +54,14 @@ export default {
|
|||
required: false,
|
||||
default: false,
|
||||
},
|
||||
/**
|
||||
* Whether the checkbox is readonly.
|
||||
*/
|
||||
readOnly: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
hasSlot() {
|
||||
|
@ -60,7 +70,7 @@ export default {
|
|||
},
|
||||
methods: {
|
||||
toggle() {
|
||||
if (this.disabled) return
|
||||
if (this.disabled || this.readOnly) return
|
||||
this.$emit('input', !this.value)
|
||||
},
|
||||
},
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<ABCheckbox
|
||||
v-model="inputValue"
|
||||
:required="element.required"
|
||||
:disabled="isEditMode"
|
||||
:read-only="isEditMode"
|
||||
:error="displayFormDataError"
|
||||
class="checkbox-element"
|
||||
>
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
<template>
|
||||
<ABCheckbox :value="value" :read-only="true" />
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import ABCheckbox from '@baserow/modules/builder/components/elements/baseComponents/ABCheckbox'
|
||||
|
||||
export default {
|
||||
name: 'BooleanField',
|
||||
components: { ABCheckbox },
|
||||
props: {
|
||||
value: {
|
||||
type: Boolean,
|
||||
required: true,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
|
@ -0,0 +1,45 @@
|
|||
<template>
|
||||
<form @submit.prevent @keydown.enter.prevent>
|
||||
<ApplicationBuilderFormulaInputGroup
|
||||
v-model="values.value"
|
||||
:label="$t('textFieldForm.fieldValueLabel')"
|
||||
:placeholder="$t('textFieldForm.fieldValuePlaceholder')"
|
||||
:data-providers-allowed="DATA_PROVIDERS_ALLOWED_ELEMENTS"
|
||||
:application-context-additions="{
|
||||
element,
|
||||
}"
|
||||
horizontal
|
||||
/>
|
||||
</form>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { DATA_PROVIDERS_ALLOWED_ELEMENTS } from '@baserow/modules/builder/enums'
|
||||
import form from '@baserow/modules/core/mixins/form'
|
||||
import ApplicationBuilderFormulaInputGroup from '@baserow/modules/builder/components/ApplicationBuilderFormulaInputGroup'
|
||||
|
||||
export default {
|
||||
name: 'BooleanFieldForm',
|
||||
components: { ApplicationBuilderFormulaInputGroup },
|
||||
mixins: [form],
|
||||
props: {
|
||||
element: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
allowedValues: ['value'],
|
||||
values: {
|
||||
value: '',
|
||||
},
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
DATA_PROVIDERS_ALLOWED_ELEMENTS() {
|
||||
return DATA_PROVIDERS_ALLOWED_ELEMENTS
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
|
@ -430,6 +430,7 @@
|
|||
"addAction": "add action"
|
||||
},
|
||||
"collectionFieldType": {
|
||||
"boolean": "Boolean",
|
||||
"text": "Text",
|
||||
"link": "Link"
|
||||
},
|
||||
|
|
|
@ -93,6 +93,7 @@ import {
|
|||
} from '@baserow/modules/builder/workflowActionTypes'
|
||||
|
||||
import {
|
||||
BooleanCollectionFieldType,
|
||||
TextCollectionFieldType,
|
||||
LinkCollectionFieldType,
|
||||
} from '@baserow/modules/builder/collectionFieldTypes'
|
||||
|
@ -258,6 +259,10 @@ export default (context) => {
|
|||
new UpdateRowWorkflowActionType(context)
|
||||
)
|
||||
|
||||
app.$registry.register(
|
||||
'collectionField',
|
||||
new BooleanCollectionFieldType(context)
|
||||
)
|
||||
app.$registry.register(
|
||||
'collectionField',
|
||||
new TextCollectionFieldType(context)
|
||||
|
|
|
@ -13,6 +13,11 @@
|
|||
border-color: $color-error-300;
|
||||
}
|
||||
|
||||
.ab-checkbox--readonly {
|
||||
accent-color: $palette-blue-500;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.ab-checkbox__label {
|
||||
cursor: pointer;
|
||||
color: $black;
|
||||
|
|
Loading…
Add table
Reference in a new issue