Skip to content

Commit 55e3fba

Browse files
authored
Merge branch 'main' into fix/provide-plugin-lang-to-change-forms
2 parents 94b9d3a + 91bd664 commit 55e3fba

File tree

10 files changed

+134
-13
lines changed

10 files changed

+134
-13
lines changed

.github/workflows/codeql.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,10 @@ name: "CodeQL"
1313

1414
on:
1515
push:
16-
branches: [ "master" ]
16+
branches: [ "main" ]
1717
pull_request:
1818
# The branches below must be a subset of the branches above
19-
branches: [ "master" ]
19+
branches: [ "main" ]
2020
schedule:
2121
- cron: '34 0 * * 1'
2222

CHANGELOG.rst

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,25 @@
22
Changelog
33
=========
44

5+
2.1.3 (2025-07-20)
6+
==================
7+
8+
* feat: simpler component configuration by @fsbraun in https://github.com/django-cms/djangocms-frontend/pull/279
9+
* feat: Add support for ``choices`` in template components. by @fsbraun in https://github.com/django-cms/djangocms-frontend/pull/282
10+
* feat: Make template component folder configurable by @fsbraun in https://github.com/django-cms/djangocms-frontend/pull/285
11+
* fix: AttributeError CMSPlugin (EditorNotePlugin) object has no attribute config by @zbohm in https://github.com/django-cms/djangocms-frontend/pull/280
12+
* chore: Add test for editor note plugin by @fsbraun in https://github.com/django-cms/djangocms-frontend/pull/281
13+
* chore: Fix some style issues by @fsbraun in https://github.com/django-cms/djangocms-frontend/pull/283
14+
* chore: Introduce dynamic badges from shields.io by @mrbazzan in https://github.com/django-cms/djangocms-frontend/pull/287
15+
* chore: Move setup info to pyproject.toml exclude docs and tests from wheel by @fsbraun in https://github.com/django-cms/djangocms-frontend/pull/290
16+
* chore: fix column per row not been saved and added tests by @mrbazzan in https://github.com/django-cms/djangocms-frontend/pull/291
17+
* chore: Increase specificity for admin urls (django 5.2) by @fsbraun in https://github.com/django-cms/djangocms-frontend/pull/278
18+
19+
**New Contributors**
20+
21+
* @zbohm made their first contribution in https://github.com/django-cms/djangocms-frontend/pull/280
22+
* @mrbazzan made their first contribution in https://github.com/django-cms/djangocms-frontend/pull/287
23+
524
2.1.2 (2025-05-05)
625
==================
726

djangocms_frontend/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,4 +19,4 @@
1919
13. Github actions will publish the new package to pypi
2020
"""
2121

22-
__version__ = "2.1.2"
22+
__version__ = "2.1.3"

djangocms_frontend/contrib/carousel/frameworks/bootstrap5.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ def render(self, context, instance, placeholder):
2323
instance.add_classes("carousel-item")
2424
if is_first_child(instance, parent):
2525
instance.add_classes("active")
26-
context["link"] = instance.get_link()
26+
context["mixin_link"] = instance.get_link()
2727
context["aspect_ratio"] = str(width / height)
2828
context["options"] = {"crop": 10, "size": (width, height), "upscale": True}
2929
return super().render(context, instance, placeholder)

djangocms_frontend/contrib/carousel/templates/djangocms_frontend/bootstrap5/carousel/default/slide.html

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
{% load cms_tags frontend %}
22
<{{ instance.tag_type }}{{ instance.get_attributes }}>
3-
{% if link %}
4-
<a href="{{ link }}"{% if instance.target %} target="{{ instance.target }}"{% endif %}>
3+
{% if mixin_link %}
4+
<a href="{{ mixin_link }}"{% if instance.target %} target="{{ instance.target }}"{% endif %}>
55
{% endif %}
66
{% with image=carousel_image.image %}
77
{% include "djangocms_frontend/bootstrap5/carousel/default/image.html" %}
88
{% endwith %}
9-
{% if link %}
9+
{% if mixin_link %}
1010
</a>
1111
{% endif %}
1212
<div class="carousel-caption d-none d-md-block">

djangocms_frontend/contrib/grid/forms.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -127,11 +127,11 @@ class Meta:
127127
)
128128

129129

130-
GridRowBaseForm.Meta.entangled_fields["config"] += extra_fields_column.keys()
130+
GridRowBaseForm._meta.entangled_fields["config"] += extra_fields_column.keys()
131131

132132

133133
GridRowForm = type(
134-
"GridRowBaseForm",
134+
"GridRowForm",
135135
(GridRowBaseForm,),
136136
copy(extra_fields_column),
137137
)
@@ -226,10 +226,10 @@ def clean(self):
226226
widget=forms.HiddenInput() if "{size}_me" in getattr(settings, "EXCL_COL_PROP", ()) else forms.CheckboxInput(),
227227
)
228228

229+
GridColumnBaseForm._meta.entangled_fields["config"] += extra_fields_column.keys()
230+
229231
GridColumnForm = type(
230232
"GridColumnForm",
231233
(GridColumnBaseForm,),
232234
copy(extra_fields_column),
233235
)
234-
235-
GridColumnForm._meta.entangled_fields["config"] += extra_fields_column.keys()
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
{% load cms_tags frontend %}{% if mixin_link %}<a href="{{ mixin_link }}"{% if instance.target %} target="{{ instance.target }}"{% endif %}{{ instance.get_attributes }}>{% endif %}{% if instance.icon_left %}{% include "djangocms_frontend/bootstrap5/link/default/icon.html" with icon_class=instance.icon_left attribute_class="me-1" %}{% endif %}{% for plugin in instance.child_plugin_instances %}{% render_plugin plugin %}{% empty %}{{ instance.name }}{% endfor %}{% if instance.icon_right %}{% include "djangocms_frontend/bootstrap5/link/default/icon.html" with icon_class=instance.icon_right attribute_class="ms-1" %}{% endif %}{% if link %}</a>{% endif %}
1+
{% load cms_tags frontend %}{% if mixin_link %}<a href="{{ mixin_link }}"{% if instance.target %} target="{{ instance.target }}"{% endif %}{{ instance.get_attributes }}>{% endif %}{% if instance.icon_left %}{% include "djangocms_frontend/bootstrap5/link/default/icon.html" with icon_class=instance.icon_left attribute_class="me-1" %}{% endif %}{% for plugin in instance.child_plugin_instances %}{% render_plugin plugin %}{% empty %}{{ instance.name }}{% endfor %}{% if instance.icon_right %}{% include "djangocms_frontend/bootstrap5/link/default/icon.html" with icon_class=instance.icon_right attribute_class="ms-1" %}{% endif %}{% if mixin_link %}</a>{% endif %}

tests/carousel/test_plugins.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,3 +104,28 @@ def test_carousel_slide_plugin(self):
104104
or ('<div class="carousel slide"' in response.content.decode("utf-8")),
105105
f'<div class="slide carousel" not found in {response.content.decode("utf-8")}',
106106
)
107+
108+
# Now testing if links are working
109+
row = add_plugin(
110+
placeholder=self.placeholder,
111+
plugin_type=CarouselPlugin.__name__,
112+
language=self.language,
113+
)
114+
row.initialize_from_form(CarouselForm).save()
115+
plugin = add_plugin(
116+
target=row,
117+
placeholder=self.placeholder,
118+
plugin_type=CarouselSlidePlugin.__name__,
119+
language=self.language,
120+
config=dict(
121+
carousel_image=dict(pk=self.image.id, model="filer.Image"),
122+
link=dict(external_link="https://www.divio.com"),
123+
),
124+
)
125+
plugin.initialize_from_form(CarouselSlideForm).save()
126+
self.publish(self.page, self.language)
127+
128+
with self.login_user_context(self.superuser):
129+
response = self.client.get(self.request_url)
130+
self.assertEqual(response.status_code, 200)
131+
self.assertContains(response, 'href="https://www.divio.com"')

tests/grid/test_forms.py

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
from django.test import TestCase
2+
3+
from djangocms_frontend.contrib.grid.forms import (
4+
GridColumnForm,
5+
GridRowForm,
6+
GridContainerForm)
7+
8+
9+
class GridFormTestCase(TestCase):
10+
def test_grid_container_form(self):
11+
form = GridContainerForm(data={
12+
"container_type": "container",
13+
"tag_type": "div",
14+
"margin_devices": ['xl'],
15+
"padding_devices": ['xs'],
16+
})
17+
self.assertTrue(form.is_valid())
18+
self.assertIn("container_type", form.instance.config)
19+
self.assertEqual(form.instance.container_type, "container")
20+
21+
def test_grid_row_form(self):
22+
form = GridRowForm(data={
23+
"margin_devices": ['xl'],
24+
"padding_devices": ['xs'],
25+
"row_cols_xs": 5,
26+
})
27+
self.assertTrue(form.is_valid())
28+
self.assertIn("row_cols_xs", form.instance.config)
29+
self.assertIn("row_cols_xxl", form.instance.config)
30+
self.assertEqual(form.instance.row_cols_xs, 5)
31+
32+
def test_grid_column_form(self):
33+
form = GridColumnForm(data={
34+
"margin_devices": ['xl'],
35+
"padding_devices": ['xs'],
36+
"text_alignment": "",
37+
"xs_col": "6",
38+
"xl_offset": "",
39+
40+
})
41+
42+
self.assertTrue(form.is_valid())
43+
self.assertIn("md_me", form.instance.config)
44+
self.assertEqual(form.instance.xs_col, 6)

tests/test_fields.py

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
1+
from django import forms
12
from django.test import TestCase
23

3-
from djangocms_frontend.fields import AttributesField, TagTypeField, TagTypeFormField
4+
from djangocms_frontend.settings import DEVICE_CHOICES
5+
from djangocms_frontend.fields import (
6+
AttributesField, TagTypeField,
7+
TagTypeFormField, DeviceChoiceField, OptionalDeviceChoiceField)
48

59

610
class FieldsTestCase(TestCase):
@@ -31,3 +35,32 @@ def test_tag_type_field(self):
3135
("aside", "aside"),
3236
],
3337
)
38+
39+
def test_optional_device_choice_field(self):
40+
class Form(forms.Form):
41+
odc = OptionalDeviceChoiceField()
42+
odc_not_required = OptionalDeviceChoiceField(required=False)
43+
44+
form = Form(data={"odc": [size for size, _ in DEVICE_CHOICES]})
45+
self.assertTrue(form.is_valid(), form.errors)
46+
self.assertEqual(form.cleaned_data["odc"], None)
47+
48+
form_1 = Form(data={"odc": ['xs', 'sm']})
49+
self.assertTrue(form_1.is_valid(), form_1.errors)
50+
self.assertEqual(form_1.cleaned_data["odc"], ['xs', 'sm'])
51+
52+
def test_device_choice_field(self):
53+
class Form(forms.Form):
54+
dc = DeviceChoiceField()
55+
56+
class Form2(forms.Form):
57+
dc_not_required = DeviceChoiceField(required=False)
58+
59+
form = Form(data={"dc": ["xs"]})
60+
self.assertTrue(form.is_valid(), form.errors)
61+
self.assertEqual(form.cleaned_data["dc"], ["xs"])
62+
63+
form_1 = Form2(data={})
64+
self.assertFalse(form_1.is_valid())
65+
self.assertFormError(form_1, "dc_not_required",
66+
["Please select at least one device size"])

0 commit comments

Comments
 (0)