+
{fieldBox && hasErrors ? (
{formattedErrors}
@@ -87,7 +86,6 @@ Field.propTypes = {
label: PropTypes.node,
children: PropTypes.element.isRequired,
helpText: PropTypes.node,
- title: PropTypes.string,
required: PropTypes.bool,
errors: PropTypes.oneOfType([
PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.string, PropTypes.array])),
diff --git a/src/openforms/js/components/admin/forms/Field.stories.mdx b/src/openforms/js/components/admin/forms/Field.stories.mdx
index 7b8c2e9677..e3e6af9e5a 100644
--- a/src/openforms/js/components/admin/forms/Field.stories.mdx
+++ b/src/openforms/js/components/admin/forms/Field.stories.mdx
@@ -25,7 +25,6 @@ export const Template = args => (
name: 'Field',
label: 'Input field',
helpText: 'Lorem ipsum',
- title: 'Title',
errorClassPrefix: '',
errorClassModifier: '',
}}
From 3534fb32fdd8dcd251373902a238d06d0286a3d0 Mon Sep 17 00:00:00 2001
From: Viicos <65306057+Viicos@users.noreply.github.com>
Date: Thu, 26 Oct 2023 17:19:45 +0200
Subject: [PATCH 07/10] =?UTF-8?q?=E2=9C=A8=20Apply=20feedback?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../forms/api/serializers/form_step.py | 3 ++
src/openforms/forms/api/validators.py | 13 +++++++
.../forms/tests/test_api_formsteps.py | 39 +++++++++++++++++++
src/openforms/forms/tests/test_models.py | 7 +++-
.../components/admin/form_design/FormStep.js | 1 -
5 files changed, 61 insertions(+), 2 deletions(-)
diff --git a/src/openforms/forms/api/serializers/form_step.py b/src/openforms/forms/api/serializers/form_step.py
index d98de0d739..56061c0a75 100644
--- a/src/openforms/forms/api/serializers/form_step.py
+++ b/src/openforms/forms/api/serializers/form_step.py
@@ -12,6 +12,7 @@
from ...models import FormDefinition, FormStep
from ...validators import validate_no_duplicate_keys_across_steps
from .button_text import ButtonTextSerializer
+from ..validators import FormStepIsApplicableIfFirstValidator
class FormStepLiteralsSerializer(serializers.Serializer):
@@ -54,6 +55,7 @@ class Meta:
"index",
"literals",
"url",
+ "is_applicable",
)
extra_kwargs = {
"uuid": {
@@ -140,6 +142,7 @@ class Meta:
"read_only": True,
},
}
+ validators = [FormStepIsApplicableIfFirstValidator()]
def create(self, validated_data):
validated_data["form"] = self.context["form"]
diff --git a/src/openforms/forms/api/validators.py b/src/openforms/forms/api/validators.py
index 3f18fa2bb4..350d71e896 100644
--- a/src/openforms/forms/api/validators.py
+++ b/src/openforms/forms/api/validators.py
@@ -190,6 +190,19 @@ def __call__(self, attrs: dict, serializer: serializers.Serializer):
)
+class FormStepIsApplicableIfFirstValidator:
+ def __call__(self, attrs: dict):
+ if not attrs.get("is_applicable", True) and attrs.get("order") == 0:
+ raise serializers.ValidationError(
+ {
+ "is_applicable": serializers.ErrorDetail(
+ _("First form step must be applicable."),
+ code="invalid",
+ ),
+ }
+ )
+
+
def validate_template_expressions(configuration: JSONObject) -> None:
"""
Validate that any template expressions in supported properties are correct.
diff --git a/src/openforms/forms/tests/test_api_formsteps.py b/src/openforms/forms/tests/test_api_formsteps.py
index 193af20435..59a299f2fd 100644
--- a/src/openforms/forms/tests/test_api_formsteps.py
+++ b/src/openforms/forms/tests/test_api_formsteps.py
@@ -1092,3 +1092,42 @@ def test_update_with_translations_validate_literals(self, _mock):
for error in expected:
with self.subTest(field=error["name"], code=error["code"]):
self.assertIn(error, invalid_params)
+
+
+class FormStepsAPIApplicabilityTests(APITestCase):
+ def setUp(self):
+ super().setUp()
+
+ self.user = UserFactory.create()
+ self.form = FormFactory.create()
+ self.form_definition = FormDefinitionFactory.create()
+ self.client.force_authenticate(user=self.user)
+
+ def test_create_form_step_not_applicable_as_first_unsucessful(self):
+ self.user.user_permissions.add(Permission.objects.get(codename="change_form"))
+ self.user.is_staff = True
+ self.user.save()
+ url = reverse(
+ "api:form-steps-list", kwargs={"form_uuid_or_slug": self.form.uuid}
+ )
+
+ form_detail_url = reverse(
+ "api:formdefinition-detail",
+ kwargs={"uuid": self.form_definition.uuid},
+ )
+ data = {
+ "formDefinition": f"http://testserver{form_detail_url}",
+ "index": 0,
+ "isApplicable": False,
+ }
+ response = self.client.post(url, data=data)
+
+ self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
+ self.assertEqual(
+ response.json()["invalidParams"][0],
+ {
+ "name": "isApplicable",
+ "code": "invalid",
+ "reason": "First form step must be applicable.",
+ },
+ )
diff --git a/src/openforms/forms/tests/test_models.py b/src/openforms/forms/tests/test_models.py
index b9621f259e..da11720415 100644
--- a/src/openforms/forms/tests/test_models.py
+++ b/src/openforms/forms/tests/test_models.py
@@ -426,10 +426,15 @@ def test_clean(self):
order=0,
is_applicable=True,
)
+ step_ok_order_1 = FormStepFactory.create(
+ order=1,
+ is_applicable=False,
+ )
with self.subTest("clean raises"):
self.assertRaises(ValidationError, step_raises.clean)
- with self.subTest("clean does not raises"):
+ with self.subTest("clean does not raise"):
step_ok.clean()
+ step_ok_order_1.clean()
class FormLogicTests(TestCase):
diff --git a/src/openforms/js/components/admin/form_design/FormStep.js b/src/openforms/js/components/admin/form_design/FormStep.js
index f77a714fcd..4dd4202c62 100644
--- a/src/openforms/js/components/admin/form_design/FormStep.js
+++ b/src/openforms/js/components/admin/form_design/FormStep.js
@@ -23,7 +23,6 @@ const FormStep = ({data, onEdit, onComponentMutated, onFieldChange, onReplace})
validationErrors = [],
componentTranslations,
} = data;
- console.log(_generatedId);
const previousFormDefinition = usePrevious(formDefinition);
let forceBuilderUpdate = false;
if (previousFormDefinition && previousFormDefinition != formDefinition) {
From 02b6724a364b186323047208716bf597b75d9f83 Mon Sep 17 00:00:00 2001
From: Viicos <65306057+Viicos@users.noreply.github.com>
Date: Fri, 27 Oct 2023 09:24:02 +0200
Subject: [PATCH 08/10] =?UTF-8?q?=F0=9F=90=9B=20Fix=20OpenAPI=20spec?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/openapi.yaml | 11 +++++++++++
src/openforms/forms/api/serializers/form_step.py | 2 +-
2 files changed, 12 insertions(+), 1 deletion(-)
diff --git a/src/openapi.yaml b/src/openapi.yaml
index 08e06d7b43..8bc9fa9a28 100644
--- a/src/openapi.yaml
+++ b/src/openapi.yaml
@@ -7422,6 +7422,9 @@ components:
type: string
format: uri
readOnly: true
+ isApplicable:
+ type: boolean
+ description: Whether the step is applicable by default.
loginRequired:
type: boolean
readOnly: true
@@ -7763,6 +7766,7 @@ components:
disable-next: '#/components/schemas/LogicActionPolymorphicGenericObject'
property: '#/components/schemas/LogicActionPolymorphicLogicPropertyAction'
step-not-applicable: '#/components/schemas/LogicActionPolymorphicGenericObject'
+ step-applicable: '#/components/schemas/LogicActionPolymorphicGenericObject'
variable: '#/components/schemas/LogicActionPolymorphicLogicValueAction'
fetch-from-service: '#/components/schemas/LogicActionPolymorphicLogicFetchAction'
set-registration-backend: '#/components/schemas/LogicActionPolymorphicLogicSetRegistrationBackendAction'
@@ -7816,6 +7820,7 @@ components:
LogicActionPolymorphicSharedTypeEnum:
enum:
- step-not-applicable
+ - step-applicable
- disable-next
- property
- variable
@@ -8003,6 +8008,9 @@ components:
url:
type: string
format: uri
+ isApplicable:
+ type: boolean
+ description: Whether the step is applicable by default.
required:
- formDefinition
- index
@@ -8421,6 +8429,9 @@ components:
type: string
format: uri
readOnly: true
+ isApplicable:
+ type: boolean
+ description: Whether the step is applicable by default.
loginRequired:
type: boolean
readOnly: true
diff --git a/src/openforms/forms/api/serializers/form_step.py b/src/openforms/forms/api/serializers/form_step.py
index 56061c0a75..f66bb439ee 100644
--- a/src/openforms/forms/api/serializers/form_step.py
+++ b/src/openforms/forms/api/serializers/form_step.py
@@ -11,8 +11,8 @@
from ...models import FormDefinition, FormStep
from ...validators import validate_no_duplicate_keys_across_steps
-from .button_text import ButtonTextSerializer
from ..validators import FormStepIsApplicableIfFirstValidator
+from .button_text import ButtonTextSerializer
class FormStepLiteralsSerializer(serializers.Serializer):
From 01261436d0801b7d717b8dc776d744b4932c4cb7 Mon Sep 17 00:00:00 2001
From: Viicos <65306057+Viicos@users.noreply.github.com>
Date: Fri, 27 Oct 2023 11:52:49 +0200
Subject: [PATCH 09/10] =?UTF-8?q?=E2=9C=A8=20Apply=20new=20feedback?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../forms/tests/test_api_formsteps.py | 33 ++++++++++---------
1 file changed, 18 insertions(+), 15 deletions(-)
diff --git a/src/openforms/forms/tests/test_api_formsteps.py b/src/openforms/forms/tests/test_api_formsteps.py
index 59a299f2fd..7312bef000 100644
--- a/src/openforms/forms/tests/test_api_formsteps.py
+++ b/src/openforms/forms/tests/test_api_formsteps.py
@@ -1095,25 +1095,19 @@ def test_update_with_translations_validate_literals(self, _mock):
class FormStepsAPIApplicabilityTests(APITestCase):
- def setUp(self):
- super().setUp()
-
- self.user = UserFactory.create()
- self.form = FormFactory.create()
- self.form_definition = FormDefinitionFactory.create()
- self.client.force_authenticate(user=self.user)
-
def test_create_form_step_not_applicable_as_first_unsucessful(self):
- self.user.user_permissions.add(Permission.objects.get(codename="change_form"))
- self.user.is_staff = True
- self.user.save()
- url = reverse(
- "api:form-steps-list", kwargs={"form_uuid_or_slug": self.form.uuid}
- )
+ user = UserFactory.create()
+ form = FormFactory.create()
+ form_definition = FormDefinitionFactory.create()
+ self.client.force_authenticate(user=user)
+ user.user_permissions.add(Permission.objects.get(codename="change_form"))
+ user.is_staff = True
+ user.save()
+ url = reverse("api:form-steps-list", kwargs={"form_uuid_or_slug": form.uuid})
form_detail_url = reverse(
"api:formdefinition-detail",
- kwargs={"uuid": self.form_definition.uuid},
+ kwargs={"uuid": form_definition.uuid},
)
data = {
"formDefinition": f"http://testserver{form_detail_url}",
@@ -1131,3 +1125,12 @@ def test_create_form_step_not_applicable_as_first_unsucessful(self):
"reason": "First form step must be applicable.",
},
)
+
+ data = {
+ "formDefinition": f"http://testserver{form_detail_url}",
+ "index": 0,
+ "isApplicable": True,
+ }
+ response = self.client.post(url, data=data)
+
+ self.assertEqual(response.status_code, status.HTTP_201_CREATED)
From badfe8407e34bea3d796e934cbf378a2b616b178 Mon Sep 17 00:00:00 2001
From: Viicos <65306057+Viicos@users.noreply.github.com>
Date: Fri, 27 Oct 2023 15:27:45 +0200
Subject: [PATCH 10/10] =?UTF-8?q?=E2=8F=AA=EF=B8=8F=20Do=20not=20raise=20o?=
=?UTF-8?q?n=20property=20setter?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/openforms/submissions/models/submission_step.py | 2 --
src/openforms/submissions/tests/test_submission_steps_state.py | 2 --
2 files changed, 4 deletions(-)
diff --git a/src/openforms/submissions/models/submission_step.py b/src/openforms/submissions/models/submission_step.py
index ac27c6a1a7..e457a2d46d 100644
--- a/src/openforms/submissions/models/submission_step.py
+++ b/src/openforms/submissions/models/submission_step.py
@@ -202,8 +202,6 @@ def is_applicable(self) -> bool:
@is_applicable.setter
def is_applicable(self, value: bool) -> None:
- if not isinstance(value, bool):
- raise ValueError(f"'is_applicable' expects a boolean value, got {value}")
self._is_applicable = value
def reset(self):
diff --git a/src/openforms/submissions/tests/test_submission_steps_state.py b/src/openforms/submissions/tests/test_submission_steps_state.py
index 149f61ca9b..6baf240ba0 100644
--- a/src/openforms/submissions/tests/test_submission_steps_state.py
+++ b/src/openforms/submissions/tests/test_submission_steps_state.py
@@ -86,5 +86,3 @@ def test_step_set_applicable(self):
self.assertTrue(submission_step.is_applicable)
submission_step.is_applicable = False
self.assertFalse(submission_step.is_applicable)
- with self.assertRaises(ValueError):
- submission_step.is_applicable = None