We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Can't edit the modal property of an action in Plone UI
Most settings of actions can be edited in the actions control panel in the Plone UI. See the classic demo:
https://6-classic.demo.plone.org/@@actions-controlpanel

Some actions have a modal property, for example the `object_buttons/delete` action. You can see it in the ZMI:
https://6-classic.demo.plone.org/portal_actions/object_buttons/delete/manage_propertiesForm
The property value is this:

```
{"actionOptions": {"disableAjaxFormSubmit":true, "redirectOnResponse":true}}
```

It would be nice if this could also be edited in the control panel.  Currently this property is now shown at all.
I guess there could be other non-standard properties as well, so bonus points if this shows all properties.

My use case today was actually on Plone 5.2 where I wanted to change the modal property of `user/login`. In Plone 6.0.0 this is an empty dictionary, but on 5.2 it was this:

```
{"prependContent": ".portalMessage", "title": "Log in", "width": "26em", "actionOptions": {"redirectOnResponse": true}}
```

I had to change the width to 18em in a client project today because their base font size was a lot bigger, which led to the login modal being only half visible on mobile. :-)

With my release manager hat on: no I don't want this changed in 5.2, people will have to use the ZMI there. Depending on scale and impact of the needed changes, a fix for this could be done either in a 6.0.x bugfix release, or in 6.1.

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `Products/CMFPlone/controlpanel/browser/actions.py`
Content:
```
1 from plone.autoform.form import AutoExtensibleForm
2 from plone.base.interfaces import IActionSchema
3 from plone.base.interfaces import INewActionSchema
4 from Products.CMFCore.ActionInformation import Action
5 from Products.CMFCore.interfaces import IAction
6 from Products.CMFCore.interfaces import IActionCategory
7 from Products.CMFCore.utils import getToolByName
8 from Products.CMFPlone import PloneMessageFactory as _
9 from Products.Five import BrowserView
10 from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile
11 from z3c.form import form
12 from zope.component import adapts
13 from zope.event import notify
14 from zope.interface import implementer
15 from zope.lifecycleevent import ObjectCreatedEvent
16 
17 
18 class ActionListControlPanel(BrowserView):
19     """Control panel for the portal actions."""
20 
21     template = ViewPageTemplateFile("actions.pt")
22 
23     def __init__(self, context, request):
24         self.context = context
25         self.request = request
26         self.portal_actions = getToolByName(self.context, 'portal_actions')
27 
28     def display(self):
29         actions = []
30         for category in self.portal_actions.objectValues():
31             if category.id == 'controlpanel':
32                 continue
33             if not IActionCategory.providedBy(category):
34                 continue
35             cat_infos = {
36                 'id': category.id,
37                 'title': category.title or category.id,
38             }
39             action_list = []
40             for action in category.objectValues():
41                 if IAction.providedBy(action):
42                     action_list.append({
43                         'id': action.id,
44                         'title': action.title,
45                         'url': action.absolute_url(),
46                         'visible': action.visible,
47                     })
48             cat_infos['actions'] = action_list
49             actions.append(cat_infos)
50 
51         self.actions = actions
52         return self.template()
53 
54     def __call__(self):
55         if self.request.get('delete'):
56             action_id = self.request['actionid']
57             category = self.portal_actions[self.request['category']]
58             category.manage_delObjects([action_id])
59             self.request.RESPONSE.redirect('@@actions-controlpanel')
60         if self.request.get('hide'):
61             action_id = self.request['actionid']
62             category = self.portal_actions[self.request['category']]
63             category[action_id].visible = False
64             self.request.RESPONSE.redirect('@@actions-controlpanel')
65         if self.request.get('show'):
66             action_id = self.request['actionid']
67             category = self.portal_actions[self.request['category']]
68             category[action_id].visible = True
69             self.request.RESPONSE.redirect('@@actions-controlpanel')
70         return self.display()
71 
72 
73 @implementer(IActionSchema)
74 class ActionControlPanelAdapter:
75     """Adapter for action form."""
76 
77     adapts(IAction)
78 
79     def __init__(self, context):
80         self.context = context
81         self.current_category = self.context.getParentNode()
82 
83     def get_category(self):
84         return self.current_category.id
85 
86     def set_category(self, value):
87         portal_actions = getToolByName(self.context, 'portal_actions')
88         new_category = portal_actions.get(value)
89         cookie = self.current_category.manage_cutObjects(ids=[self.context.id])
90         new_category.manage_pasteObjects(cookie)
91 
92     category = property(get_category, set_category)
93 
94     def get_title(self):
95         return self.context.title
96 
97     def set_title(self, value):
98         self.context._setPropValue('title', value)
99 
100     title = property(get_title, set_title)
101 
102     def get_description(self):
103         return self.context.description
104 
105     def set_description(self, value):
106         self.context._setPropValue('description', value)
107 
108     description = property(get_description, set_description)
109 
110     def get_i18n_domain(self):
111         return self.context.i18n_domain
112 
113     def set_i18n_domain(self, value):
114         self.context._setPropValue('i18n_domain', value)
115 
116     i18n_domain = property(get_i18n_domain, set_i18n_domain)
117 
118     def get_url_expr(self):
119         return self.context.url_expr
120 
121     def set_url_expr(self, value):
122         self.context._setPropValue('url_expr', value)
123 
124     url_expr = property(get_url_expr, set_url_expr)
125 
126     def get_available_expr(self):
127         return self.context.available_expr
128 
129     def set_available_expr(self, value):
130         self.context._setPropValue('available_expr', value)
131 
132     available_expr = property(get_available_expr, set_available_expr)
133 
134     def get_permissions(self):
135         return self.context.permissions
136 
137     def set_permissions(self, value):
138         self.context._setPropValue('permissions', value)
139 
140     permissions = property(get_permissions, set_permissions)
141 
142     def get_visible(self):
143         return self.context.visible
144 
145     def set_visible(self, value):
146         self.context._setPropValue('visible', value)
147 
148     visible = property(get_visible, set_visible)
149 
150     def get_position(self):
151         position = self.current_category.objectIds().index(self.context.id)
152         return position + 1
153 
154     def set_position(self, value):
155         current_position = self.current_category.objectIds().index(
156             self.context.id)
157         all_actions = list(self.current_category._objects)
158         current_action = all_actions.pop(current_position)
159         new_position = value - 1
160         all_actions = all_actions[0:new_position] + [current_action] + \
161             all_actions[new_position:]
162         self.current_category._objects = tuple(all_actions)
163 
164     position = property(get_position, set_position)
165 
166 
167 class ActionControlPanel(AutoExtensibleForm, form.EditForm):
168     """A form to edit a portal action."""
169 
170     schema = IActionSchema
171     ignoreContext = False
172     label = _('Action Settings')
173 
174 
175 class NewActionControlPanel(AutoExtensibleForm, form.AddForm):
176     """A form to add a new portal action."""
177 
178     schema = INewActionSchema
179     ignoreContext = True
180     label = _('New action')
181 
182     def createAndAdd(self, data):
183         portal_actions = getToolByName(self.context, 'portal_actions')
184         category = portal_actions.get(data['category'])
185         action_id = data['id']
186         action = Action(
187             action_id,
188             title=action_id,
189             i18n_domain='plone',
190             permissions=['View'],
191         )
192         category[action_id] = action
193         notify(ObjectCreatedEvent(action))
194
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/Products/CMFPlone/controlpanel/browser/actions.py b/Products/CMFPlone/controlpanel/browser/actions.py
--- a/Products/CMFPlone/controlpanel/browser/actions.py
+++ b/Products/CMFPlone/controlpanel/browser/actions.py
@@ -1,6 +1,7 @@
 from plone.autoform.form import AutoExtensibleForm
 from plone.base.interfaces import IActionSchema
 from plone.base.interfaces import INewActionSchema
+from plone.base.utils import base_hasattr
 from Products.CMFCore.ActionInformation import Action
 from Products.CMFCore.interfaces import IAction
 from Products.CMFCore.interfaces import IActionCategory
@@ -14,6 +15,8 @@
 from zope.interface import implementer
 from zope.lifecycleevent import ObjectCreatedEvent
 
+import json
+
 
 class ActionListControlPanel(BrowserView):
     """Control panel for the portal actions."""
@@ -163,6 +166,22 @@
 
     position = property(get_position, set_position)
 
+    def get_modal(self):
+        return self.context.modal
+
+    def set_modal(self, value):
+        # This property may not exist yet on the context.
+        if not self.context.hasProperty("modal"):
+            if base_hasattr(self.context, "modal"):
+                # We cannot define a property when an attribute with the same
+                # name already exists.
+                delattr(self.context, "modal")
+            self.context._setProperty('modal', value, 'string')
+        else:
+            self.context._setPropValue('modal', value)
+
+    modal = property(get_modal, set_modal)
+
 
 class ActionControlPanel(AutoExtensibleForm, form.EditForm):
     """A form to edit a portal action."""

{"golden_diff": "diff --git a/Products/CMFPlone/controlpanel/browser/actions.py b/Products/CMFPlone/controlpanel/browser/actions.py\n--- a/Products/CMFPlone/controlpanel/browser/actions.py\n+++ b/Products/CMFPlone/controlpanel/browser/actions.py\n@@ -1,6 +1,7 @@\n from plone.autoform.form import AutoExtensibleForm\n from plone.base.interfaces import IActionSchema\n from plone.base.interfaces import INewActionSchema\n+from plone.base.utils import base_hasattr\n from Products.CMFCore.ActionInformation import Action\n from Products.CMFCore.interfaces import IAction\n from Products.CMFCore.interfaces import IActionCategory\n@@ -14,6 +15,8 @@\n from zope.interface import implementer\n from zope.lifecycleevent import ObjectCreatedEvent\n \n+import json\n+\n \n class ActionListControlPanel(BrowserView):\n     \"\"\"Control panel for the portal actions.\"\"\"\n@@ -163,6 +166,22 @@\n \n     position = property(get_position, set_position)\n \n+    def get_modal(self):\n+        return self.context.modal\n+\n+    def set_modal(self, value):\n+        # This property may not exist yet on the context.\n+        if not self.context.hasProperty(\"modal\"):\n+            if base_hasattr(self.context, \"modal\"):\n+                # We cannot define a property when an attribute with the same\n+                # name already exists.\n+                delattr(self.context, \"modal\")\n+            self.context._setProperty('modal', value, 'string')\n+        else:\n+            self.context._setPropValue('modal', value)\n+\n+    modal = property(get_modal, set_modal)\n+\n \n class ActionControlPanel(AutoExtensibleForm, form.EditForm):\n     \"\"\"A form to edit a portal action.\"\"\"\n", "issue": "Can't edit the modal property of an action in Plone UI\nMost settings of actions can be edited in the actions control panel in the Plone UI. See the classic demo:\r\nhttps://6-classic.demo.plone.org/@@actions-controlpanel\r\n\r\nSome actions have a modal property, for example the `object_buttons/delete` action. You can see it in the ZMI:\r\nhttps://6-classic.demo.plone.org/portal_actions/object_buttons/delete/manage_propertiesForm\r\nThe property value is this:\r\n\r\n```\r\n{\"actionOptions\": {\"disableAjaxFormSubmit\":true, \"redirectOnResponse\":true}}\r\n```\r\n\r\nIt would be nice if this could also be edited in the control panel.  Currently this property is now shown at all.\r\nI guess there could be other non-standard properties as well, so bonus points if this shows all properties.\r\n\r\nMy use case today was actually on Plone 5.2 where I wanted to change the modal property of `user/login`. In Plone 6.0.0 this is an empty dictionary, but on 5.2 it was this:\r\n\r\n```\r\n{\"prependContent\": \".portalMessage\", \"title\": \"Log in\", \"width\": \"26em\", \"actionOptions\": {\"redirectOnResponse\": true}}\r\n```\r\n\r\nI had to change the width to 18em in a client project today because their base font size was a lot bigger, which led to the login modal being only half visible on mobile. :-)\r\n\r\nWith my release manager hat on: no I don't want this changed in 5.2, people will have to use the ZMI there. Depending on scale and impact of the needed changes, a fix for this could be done either in a 6.0.x bugfix release, or in 6.1.\n", "before_files": [{"content": "from plone.autoform.form import AutoExtensibleForm\nfrom plone.base.interfaces import IActionSchema\nfrom plone.base.interfaces import INewActionSchema\nfrom Products.CMFCore.ActionInformation import Action\nfrom Products.CMFCore.interfaces import IAction\nfrom Products.CMFCore.interfaces import IActionCategory\nfrom Products.CMFCore.utils import getToolByName\nfrom Products.CMFPlone import PloneMessageFactory as _\nfrom Products.Five import BrowserView\nfrom Products.Five.browser.pagetemplatefile import ViewPageTemplateFile\nfrom z3c.form import form\nfrom zope.component import adapts\nfrom zope.event import notify\nfrom zope.interface import implementer\nfrom zope.lifecycleevent import ObjectCreatedEvent\n\n\nclass ActionListControlPanel(BrowserView):\n    \"\"\"Control panel for the portal actions.\"\"\"\n\n    template = ViewPageTemplateFile(\"actions.pt\")\n\n    def __init__(self, context, request):\n        self.context = context\n        self.request = request\n        self.portal_actions = getToolByName(self.context, 'portal_actions')\n\n    def display(self):\n        actions = []\n        for category in self.portal_actions.objectValues():\n            if category.id == 'controlpanel':\n                continue\n            if not IActionCategory.providedBy(category):\n                continue\n            cat_infos = {\n                'id': category.id,\n                'title': category.title or category.id,\n            }\n            action_list = []\n            for action in category.objectValues():\n                if IAction.providedBy(action):\n                    action_list.append({\n                        'id': action.id,\n                        'title': action.title,\n                        'url': action.absolute_url(),\n                        'visible': action.visible,\n                    })\n            cat_infos['actions'] = action_list\n            actions.append(cat_infos)\n\n        self.actions = actions\n        return self.template()\n\n    def __call__(self):\n        if self.request.get('delete'):\n            action_id = self.request['actionid']\n            category = self.portal_actions[self.request['category']]\n            category.manage_delObjects([action_id])\n            self.request.RESPONSE.redirect('@@actions-controlpanel')\n        if self.request.get('hide'):\n            action_id = self.request['actionid']\n            category = self.portal_actions[self.request['category']]\n            category[action_id].visible = False\n            self.request.RESPONSE.redirect('@@actions-controlpanel')\n        if self.request.get('show'):\n            action_id = self.request['actionid']\n            category = self.portal_actions[self.request['category']]\n            category[action_id].visible = True\n            self.request.RESPONSE.redirect('@@actions-controlpanel')\n        return self.display()\n\n\n@implementer(IActionSchema)\nclass ActionControlPanelAdapter:\n    \"\"\"Adapter for action form.\"\"\"\n\n    adapts(IAction)\n\n    def __init__(self, context):\n        self.context = context\n        self.current_category = self.context.getParentNode()\n\n    def get_category(self):\n        return self.current_category.id\n\n    def set_category(self, value):\n        portal_actions = getToolByName(self.context, 'portal_actions')\n        new_category = portal_actions.get(value)\n        cookie = self.current_category.manage_cutObjects(ids=[self.context.id])\n        new_category.manage_pasteObjects(cookie)\n\n    category = property(get_category, set_category)\n\n    def get_title(self):\n        return self.context.title\n\n    def set_title(self, value):\n        self.context._setPropValue('title', value)\n\n    title = property(get_title, set_title)\n\n    def get_description(self):\n        return self.context.description\n\n    def set_description(self, value):\n        self.context._setPropValue('description', value)\n\n    description = property(get_description, set_description)\n\n    def get_i18n_domain(self):\n        return self.context.i18n_domain\n\n    def set_i18n_domain(self, value):\n        self.context._setPropValue('i18n_domain', value)\n\n    i18n_domain = property(get_i18n_domain, set_i18n_domain)\n\n    def get_url_expr(self):\n        return self.context.url_expr\n\n    def set_url_expr(self, value):\n        self.context._setPropValue('url_expr', value)\n\n    url_expr = property(get_url_expr, set_url_expr)\n\n    def get_available_expr(self):\n        return self.context.available_expr\n\n    def set_available_expr(self, value):\n        self.context._setPropValue('available_expr', value)\n\n    available_expr = property(get_available_expr, set_available_expr)\n\n    def get_permissions(self):\n        return self.context.permissions\n\n    def set_permissions(self, value):\n        self.context._setPropValue('permissions', value)\n\n    permissions = property(get_permissions, set_permissions)\n\n    def get_visible(self):\n        return self.context.visible\n\n    def set_visible(self, value):\n        self.context._setPropValue('visible', value)\n\n    visible = property(get_visible, set_visible)\n\n    def get_position(self):\n        position = self.current_category.objectIds().index(self.context.id)\n        return position + 1\n\n    def set_position(self, value):\n        current_position = self.current_category.objectIds().index(\n            self.context.id)\n        all_actions = list(self.current_category._objects)\n        current_action = all_actions.pop(current_position)\n        new_position = value - 1\n        all_actions = all_actions[0:new_position] + [current_action] + \\\n            all_actions[new_position:]\n        self.current_category._objects = tuple(all_actions)\n\n    position = property(get_position, set_position)\n\n\nclass ActionControlPanel(AutoExtensibleForm, form.EditForm):\n    \"\"\"A form to edit a portal action.\"\"\"\n\n    schema = IActionSchema\n    ignoreContext = False\n    label = _('Action Settings')\n\n\nclass NewActionControlPanel(AutoExtensibleForm, form.AddForm):\n    \"\"\"A form to add a new portal action.\"\"\"\n\n    schema = INewActionSchema\n    ignoreContext = True\n    label = _('New action')\n\n    def createAndAdd(self, data):\n        portal_actions = getToolByName(self.context, 'portal_actions')\n        category = portal_actions.get(data['category'])\n        action_id = data['id']\n        action = Action(\n            action_id,\n            title=action_id,\n            i18n_domain='plone',\n            permissions=['View'],\n        )\n        category[action_id] = action\n        notify(ObjectCreatedEvent(action))\n", "path": "Products/CMFPlone/controlpanel/browser/actions.py"}], "after_files": [{"content": "from plone.autoform.form import AutoExtensibleForm\nfrom plone.base.interfaces import IActionSchema\nfrom plone.base.interfaces import INewActionSchema\nfrom plone.base.utils import base_hasattr\nfrom Products.CMFCore.ActionInformation import Action\nfrom Products.CMFCore.interfaces import IAction\nfrom Products.CMFCore.interfaces import IActionCategory\nfrom Products.CMFCore.utils import getToolByName\nfrom Products.CMFPlone import PloneMessageFactory as _\nfrom Products.Five import BrowserView\nfrom Products.Five.browser.pagetemplatefile import ViewPageTemplateFile\nfrom z3c.form import form\nfrom zope.component import adapts\nfrom zope.event import notify\nfrom zope.interface import implementer\nfrom zope.lifecycleevent import ObjectCreatedEvent\n\nimport json\n\n\nclass ActionListControlPanel(BrowserView):\n    \"\"\"Control panel for the portal actions.\"\"\"\n\n    template = ViewPageTemplateFile(\"actions.pt\")\n\n    def __init__(self, context, request):\n        self.context = context\n        self.request = request\n        self.portal_actions = getToolByName(self.context, 'portal_actions')\n\n    def display(self):\n        actions = []\n        for category in self.portal_actions.objectValues():\n            if category.id == 'controlpanel':\n                continue\n            if not IActionCategory.providedBy(category):\n                continue\n            cat_infos = {\n                'id': category.id,\n                'title': category.title or category.id,\n            }\n            action_list = []\n            for action in category.objectValues():\n                if IAction.providedBy(action):\n                    action_list.append({\n                        'id': action.id,\n                        'title': action.title,\n                        'url': action.absolute_url(),\n                        'visible': action.visible,\n                    })\n            cat_infos['actions'] = action_list\n            actions.append(cat_infos)\n\n        self.actions = actions\n        return self.template()\n\n    def __call__(self):\n        if self.request.get('delete'):\n            action_id = self.request['actionid']\n            category = self.portal_actions[self.request['category']]\n            category.manage_delObjects([action_id])\n            self.request.RESPONSE.redirect('@@actions-controlpanel')\n        if self.request.get('hide'):\n            action_id = self.request['actionid']\n            category = self.portal_actions[self.request['category']]\n            category[action_id].visible = False\n            self.request.RESPONSE.redirect('@@actions-controlpanel')\n        if self.request.get('show'):\n            action_id = self.request['actionid']\n            category = self.portal_actions[self.request['category']]\n            category[action_id].visible = True\n            self.request.RESPONSE.redirect('@@actions-controlpanel')\n        return self.display()\n\n\n@implementer(IActionSchema)\nclass ActionControlPanelAdapter:\n    \"\"\"Adapter for action form.\"\"\"\n\n    adapts(IAction)\n\n    def __init__(self, context):\n        self.context = context\n        self.current_category = self.context.getParentNode()\n\n    def get_category(self):\n        return self.current_category.id\n\n    def set_category(self, value):\n        portal_actions = getToolByName(self.context, 'portal_actions')\n        new_category = portal_actions.get(value)\n        cookie = self.current_category.manage_cutObjects(ids=[self.context.id])\n        new_category.manage_pasteObjects(cookie)\n\n    category = property(get_category, set_category)\n\n    def get_title(self):\n        return self.context.title\n\n    def set_title(self, value):\n        self.context._setPropValue('title', value)\n\n    title = property(get_title, set_title)\n\n    def get_description(self):\n        return self.context.description\n\n    def set_description(self, value):\n        self.context._setPropValue('description', value)\n\n    description = property(get_description, set_description)\n\n    def get_i18n_domain(self):\n        return self.context.i18n_domain\n\n    def set_i18n_domain(self, value):\n        self.context._setPropValue('i18n_domain', value)\n\n    i18n_domain = property(get_i18n_domain, set_i18n_domain)\n\n    def get_url_expr(self):\n        return self.context.url_expr\n\n    def set_url_expr(self, value):\n        self.context._setPropValue('url_expr', value)\n\n    url_expr = property(get_url_expr, set_url_expr)\n\n    def get_available_expr(self):\n        return self.context.available_expr\n\n    def set_available_expr(self, value):\n        self.context._setPropValue('available_expr', value)\n\n    available_expr = property(get_available_expr, set_available_expr)\n\n    def get_permissions(self):\n        return self.context.permissions\n\n    def set_permissions(self, value):\n        self.context._setPropValue('permissions', value)\n\n    permissions = property(get_permissions, set_permissions)\n\n    def get_visible(self):\n        return self.context.visible\n\n    def set_visible(self, value):\n        self.context._setPropValue('visible', value)\n\n    visible = property(get_visible, set_visible)\n\n    def get_position(self):\n        position = self.current_category.objectIds().index(self.context.id)\n        return position + 1\n\n    def set_position(self, value):\n        current_position = self.current_category.objectIds().index(\n            self.context.id)\n        all_actions = list(self.current_category._objects)\n        current_action = all_actions.pop(current_position)\n        new_position = value - 1\n        all_actions = all_actions[0:new_position] + [current_action] + \\\n            all_actions[new_position:]\n        self.current_category._objects = tuple(all_actions)\n\n    position = property(get_position, set_position)\n\n    def get_modal(self):\n        return self.context.modal\n\n    def set_modal(self, value):\n        # This property may not exist yet on the context.\n        if not self.context.hasProperty(\"modal\"):\n            if base_hasattr(self.context, \"modal\"):\n                # We cannot define a property when an attribute with the same\n                # name already exists.\n                delattr(self.context, \"modal\")\n            self.context._setProperty('modal', value, 'string')\n        else:\n            self.context._setPropValue('modal', value)\n\n    modal = property(get_modal, set_modal)\n\n\nclass ActionControlPanel(AutoExtensibleForm, form.EditForm):\n    \"\"\"A form to edit a portal action.\"\"\"\n\n    schema = IActionSchema\n    ignoreContext = False\n    label = _('Action Settings')\n\n\nclass NewActionControlPanel(AutoExtensibleForm, form.AddForm):\n    \"\"\"A form to add a new portal action.\"\"\"\n\n    schema = INewActionSchema\n    ignoreContext = True\n    label = _('New action')\n\n    def createAndAdd(self, data):\n        portal_actions = getToolByName(self.context, 'portal_actions')\n        category = portal_actions.get(data['category'])\n        action_id = data['id']\n        action = Action(\n            action_id,\n            title=action_id,\n            i18n_domain='plone',\n            permissions=['View'],\n        )\n        category[action_id] = action\n        notify(ObjectCreatedEvent(action))\n", "path": "Products/CMFPlone/controlpanel/browser/actions.py"}]}