diff --git a/CHANGES.rst b/CHANGES.rst
index 97d929fb..4b48d841 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -5,7 +5,16 @@ Changelog
1.4.56 (unreleased)
-------------------
-- Nothing changed yet.
+- WEBBDC-2835: REFACTOR : Move the contact-section row schemas, row helpers, grid form
+ mixin, frozen-label widget and ``*DisplayColumns`` vocabularies to
+ ``imio.smartweb.common`` so ``events`` and ``news`` can reuse them.
+ [boulch]
+
+- WEBBDC-2835: Add read-only phones/mails/urls datagrids to the contact section,
+ loaded from the related contacts with a dedicated button, with a per-row
+ checkbox column choosing which columns are displayed. Unchecking every column
+ hides the row.
+ [boulch]
1.4.55 (2026-07-28)
diff --git a/base.cfg b/base.cfg
index bb54f922..00d63bb3 100644
--- a/base.cfg
+++ b/base.cfg
@@ -67,6 +67,5 @@ scripts =
# Don't use a released version of imio.smartweb.core
imio.smartweb.core =
-[remotes]
-imio = https://github.com/IMIO
-imio_push = git@github.com:IMIO
+[sources]
+imio.smartweb.common = git https://github.com/IMIO/imio.smartweb.common.git pushurl=git@github.com:IMIO/imio.smartweb.common.git branch=WEBBDC-2835
\ No newline at end of file
diff --git a/src/imio/smartweb/core/contents/sections/contact/content.py b/src/imio/smartweb/core/contents/sections/contact/content.py
index b9c327dc..bf3bd9ca 100644
--- a/src/imio/smartweb/core/contents/sections/contact/content.py
+++ b/src/imio/smartweb/core/contents/sections/contact/content.py
@@ -1,5 +1,6 @@
# -*- coding: utf-8 -*-
+from imio.smartweb.common.contact.rows import IContactInformationsGrids
from imio.smartweb.common.widgets.select import TranslatedAjaxSelectWidget
from imio.smartweb.core.contents.sections.base import ISection
from imio.smartweb.core.contents.sections.base import Section
@@ -11,8 +12,14 @@
from zope.interface import implementer
-class ISectionContact(ISection):
- """Marker interface and Dexterity Python Schema for SectionContact"""
+class ISectionContact(ISection, IContactInformationsGrids):
+ """Marker interface and Dexterity Python Schema for SectionContact
+
+ The `contact_informations` fieldset and its three read-only datagrids come
+ from IContactInformationsGrids, shared with imio.events.core. Here the
+ stored data columns are RESIDUE: the page render always re-reads the live
+ directory payload and only `visible_columns` is authoritative.
+ """
directives.widget(
"related_contacts",
diff --git a/src/imio/smartweb/core/contents/sections/contact/forms.py b/src/imio/smartweb/core/contents/sections/contact/forms.py
index 4b3bea5d..fc1b6840 100644
--- a/src/imio/smartweb/core/contents/sections/contact/forms.py
+++ b/src/imio/smartweb/core/contents/sections/contact/forms.py
@@ -1,17 +1,33 @@
# -*- coding: utf-8 -*-
from imio.smartweb.common.browser.forms import CustomAddForm
+from imio.smartweb.common.contact.forms import ContactInformationsGridMixin
from imio.smartweb.core.browser.forms import SmartwebCustomEditForm
+from imio.smartweb.locales import SmartwebMessageFactory as _
from plone.dexterity.browser.add import DefaultAddView
from plone.z3cform import layout
+from z3c.form import button
from z3c.form.interfaces import HIDDEN_MODE
-class ContactCustomAddForm(CustomAddForm):
- portal_type = "imio.smartweb.SectionContact"
+class SectionContactGridMixin(ContactInformationsGridMixin):
+ """The section's own bits: `related_contacts` and the hidden hide_title.
+
+ The grid-reloading machinery itself lives in
+ imio.smartweb.common.contact.forms, shared with imio.events.core.
+
+ `hide_title` is hidden after the widgets exist, which both concrete forms
+ need and neither may forget. It belongs to the Section base and does not
+ exist outside one, which is why it is not in the shared mixin.
+ """
+
+ contact_uids_field = "related_contacts"
def update(self):
- super(ContactCustomAddForm, self).update()
+ super().update()
+ self._hide_hide_title()
+
+ def _hide_hide_title(self):
# We hide hide_title field so no one can change the value for contact
# and set True value (single checkbox)
for group in self.groups:
@@ -20,19 +36,39 @@ def update(self):
group.widgets["hide_title"].value = ["selected"]
+class ContactCustomAddForm(SectionContactGridMixin, CustomAddForm):
+ portal_type = "imio.smartweb.SectionContact"
+
+ # Both MUST be copied before the decorator runs: @buttonAndHandler does a
+ # setdefault on the `buttons` AND on the `handlers` name of the class body
+ # being defined. Without the copies it would create fresh, empty managers
+ # that shadow the base ones -- the form would lose the Save / Cancel
+ # buttons (buttons) and, more silently, their handlers (handlers), so
+ # pressing Save would render the form again without saving anything.
+ buttons = CustomAddForm.buttons.copy()
+ handlers = CustomAddForm.handlers.copy()
+
+ @button.buttonAndHandler(
+ _("Load contact information"), name="load_contact_informations"
+ )
+ def handleLoadContactInformations(self, action):
+ """No-op: the grids were already rebuilt in update()."""
+
+
class ContactCustomAddView(DefaultAddView):
form = ContactCustomAddForm
-class ContactCustomEditForm(SmartwebCustomEditForm):
- def update(self):
- super(ContactCustomEditForm, self).update()
- # We hide hide_title field so no one can change the value for contact
- # and set True value (single checkbox)
- for group in self.groups:
- if group.__name__ == "layout":
- group.widgets["hide_title"].mode = HIDDEN_MODE
- group.widgets["hide_title"].value = ["selected"]
+class ContactCustomEditForm(SectionContactGridMixin, SmartwebCustomEditForm):
+ # See ContactCustomAddForm for why both managers are copied here.
+ buttons = SmartwebCustomEditForm.buttons.copy()
+ handlers = SmartwebCustomEditForm.handlers.copy()
+
+ @button.buttonAndHandler(
+ _("Load contact information"), name="load_contact_informations"
+ )
+ def handleLoadContactInformations(self, action):
+ """No-op: the grids were already rebuilt in update()."""
ContactCustomEditView = layout.wrap_form(ContactCustomEditForm)
diff --git a/src/imio/smartweb/core/contents/sections/contact/macros.pt b/src/imio/smartweb/core/contents/sections/contact/macros.pt
index 8274a70c..7cb11c88 100644
--- a/src/imio/smartweb/core/contents/sections/contact/macros.pt
+++ b/src/imio/smartweb/core/contents/sections/contact/macros.pt
@@ -51,8 +51,17 @@
tal:content="subtitle">
+