From 854d091d43574eee43e22371492eba6846032c5a Mon Sep 17 00:00:00 2001 From: Reto Tschuppert Date: Fri, 17 Jul 2026 14:36:35 +0200 Subject: [PATCH 01/11] Adds caerus wab production server to maintenance schedule config --- maintenance-schedule.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/maintenance-schedule.yml b/maintenance-schedule.yml index 49e8a7b75c..aa420cf599 100644 --- a/maintenance-schedule.yml +++ b/maintenance-schedule.yml @@ -16,6 +16,7 @@ schedule: - caicias - caicinus - caicus + - caerus - carcinus - date: Monday +7 days at 7:00 nodes: From e0edc68087d027acaef9d848094d13e3354fb8cd Mon Sep 17 00:00:00 2001 From: Reto Tschuppert Date: Fri, 17 Jul 2026 14:59:10 +0200 Subject: [PATCH 02/11] Change icon for directory configuration menu --- src/onegov/org/theme/styles/org.scss | 2 +- src/onegov/town6/theme/styles/header.scss | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/onegov/org/theme/styles/org.scss b/src/onegov/org/theme/styles/org.scss index e9632b473f..ab92ffe759 100644 --- a/src/onegov/org/theme/styles/org.scss +++ b/src/onegov/org/theme/styles/org.scss @@ -1696,7 +1696,7 @@ $cleanup-link-icon: '\f0d0'; $copy-link-icon: '\f0c5'; $delete-link-icon: '\f014'; $disabled-icon: '\f05e'; -$edit-link-icon: '\f040'; +$edit-link-icon: '\f03a'; $save-link-icon: '\f0c7'; $cancel-link-icon: '\f00d'; $export-link-icon: '\f019'; diff --git a/src/onegov/town6/theme/styles/header.scss b/src/onegov/town6/theme/styles/header.scss index cb1f023402..167750a9cb 100644 --- a/src/onegov/town6/theme/styles/header.scss +++ b/src/onegov/town6/theme/styles/header.scss @@ -12,7 +12,7 @@ $cleanup-link-icon: '\f0d0'; $copy-link-icon: '\f0c5'; $delete-link-icon: '\f2ed'; $disabled-icon: '\f05e'; -$edit-link-icon: '\f044'; +$edit-link-icon: '\f03a'; $save-link-icon: '\f0c7'; $cancel-link-icon: '\f00d'; $export-link-icon: '\f019'; @@ -551,7 +551,7 @@ $editbar-fg-color-active: $white; .cleanup-link::before { @include icon-bold($cleanup-link-icon); } .copy-link::before { @include icon($copy-link-icon); } .delete-link::before { @include icon($delete-link-icon); } - .edit-link::before { @include icon($edit-link-icon); } + .edit-link::before { @include icon_bold($edit-link-icon); } .save-link::before { @include icon($save-link-icon); } .cancel-link::before { @include icon-bold($cancel-link-icon); } .move-link::before { @include icon-bold($move-link-icon); } From b3c6dcfb713e2c2e8025c0cc2a81b69bfd87edd8 Mon Sep 17 00:00:00 2001 From: Reto Tschuppert Date: Fri, 17 Jul 2026 15:03:50 +0200 Subject: [PATCH 03/11] Resources: Move add menu far right --- src/onegov/org/layout.py | 50 ++++++++++++++++++---------------------- 1 file changed, 23 insertions(+), 27 deletions(-) diff --git a/src/onegov/org/layout.py b/src/onegov/org/layout.py index 7988edf8f7..d40a9c93b8 100644 --- a/src/onegov/org/layout.py +++ b/src/onegov/org/layout.py @@ -2281,34 +2281,38 @@ def editbar_links(self) -> list[Link | LinkGroup] | None: Link( text=_('Recipients'), url=self.request.class_link(ResourceRecipientCollection), - attrs={'class': 'manage-recipients'} + attrs={'class': 'manage-recipients'}, + ), + Link( + text=_('Export All'), + url=self.request.link(self.model, name='export-all'), + ), + IFrameLink( + text=_('iFrame'), + url=self.request.link(self.model), + attrs={'class': 'new-iframe'}, ), LinkGroup( title=_('Add'), links=[ Link( text=_('Room'), - url=self.request.link( - self.model, - name='new-room' - ), - attrs={'class': 'new-room'} + url=self.request.link(self.model, name='new-room'), + attrs={'class': 'new-room'}, ), Link( text=_('Daypass'), url=self.request.link( - self.model, - name='new-daypass' + self.model, name='new-daypass' ), - attrs={'class': 'new-daypass'} + attrs={'class': 'new-daypass'}, ), Link( text=_('Resource Item'), url=self.request.link( - self.model, - name='new-daily-item' + self.model, name='new-daily-item' ), - attrs={'class': 'new-daily-item'} + attrs={'class': 'new-daily-item'}, ), Link( text=_('External resource link'), @@ -2317,24 +2321,16 @@ def editbar_links(self) -> list[Link | LinkGroup] | None: query_params={ 'to': self.resources_url, 'title': self.request.translate( - _('New external resource')), - 'type': 'resource' + _('New external resource') + ), + 'type': 'resource', }, - name='new' + name='new', ), - attrs={'class': 'new-resource-link'} - ) - ] - ), - Link( - text=_('Export All'), - url=self.request.link(self.model, name='export-all'), + attrs={'class': 'new-resource-link'}, + ), + ], ), - IFrameLink( - text=_('iFrame'), - url=self.request.link(self.model), - attrs={'class': 'new-iframe'} - ) ] return None From 6ad9d66eafe31f8ae8e39a6f4a13c5fb0e09358e Mon Sep 17 00:00:00 2001 From: Reto Tschuppert Date: Fri, 17 Jul 2026 15:11:30 +0200 Subject: [PATCH 04/11] Newsletter: Settings first; Edit first --- src/onegov/org/layout.py | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/src/onegov/org/layout.py b/src/onegov/org/layout.py index d40a9c93b8..f86578b8f2 100644 --- a/src/onegov/org/layout.py +++ b/src/onegov/org/layout.py @@ -3047,16 +3047,17 @@ def editbar_links(self) -> list[Link | LinkGroup] | None: if self.is_collection: links: list[Link | LinkGroup] = [ - Link( - text=_('Subscribers'), - url=self.request.link(self.recipients), - attrs={'class': 'manage-subscribers'} - ), Link( text=_('Settings'), url=self.request.link( - self.request.app.org, 'newsletter-settings'), - attrs={'class': 'settings-link'} + self.request.app.org, 'newsletter-settings' + ), + attrs={'class': 'settings-link'}, + ), + Link( + text=_('Subscribers'), + url=self.request.link(self.recipients), + attrs={'class': 'manage-subscribers'}, ), ] @@ -3096,6 +3097,11 @@ def editbar_links(self) -> list[Link | LinkGroup] | None: return [] return [ + Link( + text=_('Edit'), + url=self.request.link(self.model, 'edit'), + attrs={'class': 'edit-link'} + ), Link( text=_('Schedule email delivery'), url=self.request.link(self.model, 'send'), @@ -3115,11 +3121,6 @@ def editbar_links(self) -> list[Link | LinkGroup] | None: ), attrs={'class': 'copy-link'}, ), - Link( - text=_('Edit'), - url=self.request.link(self.model, 'edit'), - attrs={'class': 'edit-link'} - ), Link( text=_('Delete'), url=self.csrf_protected_url( From d58757029b782a515aaf0ffcc3aefb8f560dafc2 Mon Sep 17 00:00:00 2001 From: Reto Tschuppert Date: Fri, 17 Jul 2026 15:25:22 +0200 Subject: [PATCH 05/11] Album: Edit far left --- src/onegov/org/layout.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/onegov/org/layout.py b/src/onegov/org/layout.py index f86578b8f2..17ec67227d 100644 --- a/src/onegov/org/layout.py +++ b/src/onegov/org/layout.py @@ -3239,11 +3239,6 @@ def breadcrumbs(self) -> list[Link]: def editbar_links(self) -> list[Link | LinkGroup] | None: if self.request.is_manager: return [ - Link( - text=_('Choose images'), - url=self.request.link(self.model, 'select'), - attrs={'class': 'select'} - ), Link( text=_('Edit'), url=self.request.link( @@ -3252,6 +3247,11 @@ def editbar_links(self) -> list[Link | LinkGroup] | None: ), attrs={'class': 'edit-link'} ), + Link( + text=_('Choose images'), + url=self.request.link(self.model, 'select'), + attrs={'class': 'select'} + ), Link( text=_('Delete'), url=self.csrf_protected_url( From 0863dddb8f11b0cd53333ab3fd050d4be1e6cff4 Mon Sep 17 00:00:00 2001 From: Reto Tschuppert Date: Mon, 20 Jul 2026 07:26:15 +0200 Subject: [PATCH 06/11] Events: Merge filter with general event settings, add return-to --- src/onegov/org/assets/js/code_editor.js | 4 + src/onegov/org/forms/event.py | 34 ---- src/onegov/org/forms/settings.py | 68 ++++++-- src/onegov/org/layout.py | 16 +- src/onegov/org/views/occurrence.py | 155 +----------------- src/onegov/org/views/settings.py | 150 ++++++++++++++++- .../shared/assets/js/form_dependencies.js | 6 +- src/onegov/town6/views/occurrence.py | 21 +-- tests/onegov/org/test_api.py | 12 +- tests/onegov/org/test_views_event.py | 50 +++--- tests/onegov/org/test_views_forms.py | 10 +- 11 files changed, 252 insertions(+), 274 deletions(-) diff --git a/src/onegov/org/assets/js/code_editor.js b/src/onegov/org/assets/js/code_editor.js index 2a9aa5eadf..c86de17f0e 100644 --- a/src/onegov/org/assets/js/code_editor.js +++ b/src/onegov/org/assets/js/code_editor.js @@ -5,6 +5,10 @@ $(function() { var readonly = textarea.is('[readonly]'); textarea.css('display', 'none'); + // the editor replaces the textarea with its own widget, so make sure + // the field-dependency handling never re-shows the raw textarea + textarea.attr('data-always-hidden', ''); + var outside = $('
'); var inside = $('
'); inside.position('absolute'); diff --git a/src/onegov/org/forms/event.py b/src/onegov/org/forms/event.py index 47308e2ce0..853202fa4a 100644 --- a/src/onegov/org/forms/event.py +++ b/src/onegov/org/forms/event.py @@ -19,13 +19,11 @@ from onegov.form.fields import TimeField from onegov.form.fields import UploadField from onegov.form.fields import UploadFileWithORMSupport -from onegov.form.utils import get_fields_from_class from onegov.file.attachments import IMAGE_MAX_SIZE from onegov.form.validators import ( FileSizeLimit, ImageSizeLimit, ValidPhoneNumber, - ValidFilterFormDefinition, MIME_TYPES_EXCEL, MIME_TYPES_PDF, ) @@ -684,35 +682,3 @@ def get(line: DefaultRow, column: str, attribute: str) -> Any: transaction.abort() return count, errors - - -class EventConfigurationForm(Form): - """ Form to configure filters for events view. """ - - definition = TextAreaField( - label=_('Definition'), - fieldset=_('General'), - validators=[ - InputRequired(), - ValidFilterFormDefinition( - require_email_field=False, - require_title_fields=False, - reserved_fields={name for name, _ in - get_fields_from_class(EventForm)} - | {'syndicate', 'highlight'} - ) - ], - render_kw={'rows': 32, 'data-editor': 'form'}) - - keyword_fields = TextAreaField( - label=_('Filters'), - fieldset=_('Display'), - render_kw={ - 'class_': 'formcode-select', - 'data-fields-include': 'radio,checkbox' - }) - - force_remove = BooleanField( - label=_('Remove these filters from all affected events'), - fieldset=_('Confirmation'), - ) diff --git a/src/onegov/org/forms/settings.py b/src/onegov/org/forms/settings.py index ef66dd647a..2b7176c967 100644 --- a/src/onegov/org/forms/settings.py +++ b/src/onegov/org/forms/settings.py @@ -25,11 +25,14 @@ from onegov.form.fields import TagsField from onegov.form.fields import TranslatedSelectField from onegov.form.fields import URLField +from onegov.form.utils import get_fields_from_class from onegov.form.validators import If from onegov.form.validators import StrictOptional +from onegov.form.validators import ValidFilterFormDefinition from onegov.form.validators import ValidHostname from onegov.gis import CoordinatesField from onegov.org import _, log +from onegov.org.forms.event import EventForm from onegov.org.forms.fields import ( HtmlField, UploadOrSelectExistingMultipleFilesField, @@ -2067,21 +2070,6 @@ class EventSettingsForm(Form): default=False ) - event_locations = TagsField( - label=_('Values of the location filter'), - ) - - event_filter_type = RadioField( - label=_("Choose the filter type for events (default is 'Tags')"), - choices=( - ('tags', _('A predefined set of tags')), - ('filters', _('Manually configurable filters')), - ('tags_and_filters', _('Both, predefined tags as well as ' - 'configurable filters')), - ), - default='tags' - ) - event_header_title = StringField( label=_('Title of text above event list'), description=_('General information about the event calendar'), @@ -2104,6 +2092,56 @@ class EventSettingsForm(Form): fieldset=_('Information below the event list') ) + event_locations = TagsField( + label=_('Values of the location filter'), + fieldset=_('Filters'), + ) + + event_filter_type = RadioField( + label=_("Choose the filter type for events (default is 'Tags')"), + fieldset=_('Filters'), + choices=( + ('tags', _('A predefined set of tags')), + ('filters', _('Manually configurable filters')), + ('tags_and_filters', _('Both, predefined tags as well as ' + 'configurable filters')), + ), + default='tags' + ) + + event_filter_definition = TextAreaField( + label=_('Definition'), + fieldset=_('Filters'), + depends_on=('event_filter_type', '!tags'), + validators=[ + ValidFilterFormDefinition( + require_email_field=False, + require_title_fields=False, + reserved_fields={name for name, _ in + get_fields_from_class(EventForm)} + | {'syndicate', 'highlight'} + ) + ], + render_kw={'rows': 16, 'data-editor': 'form'} + ) + + keyword_fields = TextAreaField( + label=_('Filters'), + fieldset=_('Filters'), + depends_on=('event_filter_type', '!tags'), + render_kw={ + 'class_': 'formcode-select', + 'data-fields-include': 'radio,checkbox' + } + ) + + force_remove = BooleanField( + label=_('Remove these filters from all affected events'), + fieldset=_('Filters'), + ) + + # FIXME: keep this last; its upload widget emits a split