Multi select field in registry setting

Plone 6.2.2. I have a control panel settings page that needs a multi value, ordered field. I've tried both from plone.app.z3cform.widgets.select.AjaxSelectFieldWidget and Select2FieldWidget. They are both broken in different ways.

Select2FieldWidget does not correctly order. The UI appears to show it doing so, but the actual form data is not reordered and sent to the server that way.

AjaxSelectFieldWidget orders correctly but has a validation error:

Traceback (innermost last):
  Module ZPublisher.WSGIPublisher, line 179, in transaction_pubevents
  Module ZPublisher.WSGIPublisher, line 388, in publish_module
  Module ZPublisher.WSGIPublisher, line 282, in publish
  Module ZPublisher.mapply, line 98, in mapply
  Module ZPublisher.WSGIPublisher, line 68, in call_object
  Module plone.app.content.browser.vocabulary, line 156, in __call__
  Module plone.app.content.browser.vocabulary, line 317, in get_vocabulary
  Module plone.app.dexterity.permissions, line 89, in validate
AttributeError: No such field: primary_idps

The Select2FieldWidget has been an issue before, but I thought that was related to an old version of select2.

With the Ajax version, it appears to be trying to get the field schema from the context - which is just the portal root. It's using the default Dexterity validator here.

Is there any easy way to get around this, or some other widget I should be using in the control panels?

I am not really sure but have you tried setting the ignoreContext attribute in your form class to True?

More info from this link

An alternative would be to create your own custom widget. To do that

In interfaces.py:

from plone.app.z3cform.interfaces import IAjaxSelectWidget

class ICustomAjaxSelectWidget(IAjaxSelectWidget):
"""Custom IAjaxSelectWidget widget"""

In configuration.zcml (example for the display view of the widget):

<z3c:widgetTemplate layer="plone.app.z3cform.interfaces.IPloneFormLayer"
mode="display"
template="customajaxselect_display.pt"
widget="my.package.interfaces.ICustomAjaxSelectWidget"
/>

In your widget py:

from my.package.interfaces import ICustomAjaxSelectWidget
from plone.app.z3cform.widgets.select import AjaxSelectWidget

@implementer_only(ICustomAjaxSelectWidget)
class AjaxSelectFileWidget(AjaxSelectWidget):

#override attributes/methods
def display_items(self):
   ...

I haven't used ignoreContext on control panel views, but I tried it here.

class SettingsEditForm(controlpanel.RegistryEditForm):
    schema = ISSOSettings
    label = _("SSO Settings")


class ControlPanel(layout.FormWrapper):
    form = SettingsEditForm
    index = ViewPageTemplateFile("settings.pt")
    label = _("SSO Settings")

I tried it on each of these classes and it didn't seem to make a difference. I don't think this would make sense anyway, with what is in plone.app.content.browser.

It works if I do this, though surely this is not the intended way?

from plone.app.content.browser.vocabulary import PERMISSIONS

PERMISSIONS["ims.sso.idps"] = "View"

I have come across vocabulary permissions issues in earlier versions of p.a.z3cform. I discussed it here. It is old but there are similarities to what you described above.

Fall back to a DataGrid? Not the prettiest of solutions, depends on how often and who needs it...

Example from a 5.1 instance:

and in the registry:

Thanks for the responses. I tried to modernize @1letter 's custom field validator from that post, but was unable to get it to hit my validator. It could be that I misconfigured the zope component architecture, but I think it might be because the vocabulary view looks for a validator based on context, not a specific form:

permission_checker = queryAdapter(context, IFieldPermissionChecker)

so I don't know how to register it to find my permission checker just for this form. I also looked at DataGridField's approach and they appear to just override the default Dexterity validator.