From 4fe89314405e8b7b1df3869e39565c5963c4c3b4 Mon Sep 17 00:00:00 2001 From: "Misha M.-Kupriyanov" Date: Thu, 19 Feb 2026 12:43:58 +0100 Subject: [PATCH 01/11] IONOS(ionos-mail): refactor(ui): Enhance mailbox list UI with improved structure and styling Refactor the mailbox list UI to use a more semantic structure with divs instead of tables, implement sticky headers, and improve styling for better usability and consistency. This change aims to enhance the user experience by providing a clearer layout and more intuitive interaction with mailbox items. Signed-off-by: Misha M.-Kupriyanov --- .../provider/mailbox/ProviderMailboxAdmin.vue | 156 ++++---- .../mailbox/ProviderMailboxListItem.vue | 339 +++++++++--------- 2 files changed, 263 insertions(+), 232 deletions(-) diff --git a/src/components/provider/mailbox/ProviderMailboxAdmin.vue b/src/components/provider/mailbox/ProviderMailboxAdmin.vue index 745069a430..1240903e4b 100644 --- a/src/components/provider/mailbox/ProviderMailboxAdmin.vue +++ b/src/components/provider/mailbox/ProviderMailboxAdmin.vue @@ -7,8 +7,6 @@
-

{{ t('mail', 'Manage Emails') }}

- - +
- - - - - - - - - +
+ +
+
+ +
+ {{ t('mail', 'Display Name') }} +
+
+ {{ t('mail', 'Linked User') }} +
+
+ {{ t('mail', 'Status') }} +
+
+ {{ t('mail', 'Actions') }} +
+
- + + +
-
-
{{ t('mail', 'Email Address') }}{{ t('mail', 'Display Name') }}{{ t('mail', 'Linked User') }} - {{ t('mail', 'Status') }} - - {{ t('mail', 'Actions') }} -
+
+ + + + + {{ n('mail', '%n mailbox', '%n mailboxes', mailboxes.length) }} + + +
@@ -82,6 +100,7 @@ From ce68e3d482de15ba5939c3a851d8a3cacdc324f2 Mon Sep 17 00:00:00 2001 From: "Misha M.-Kupriyanov" Date: Thu, 19 Feb 2026 13:01:34 +0100 Subject: [PATCH 02/11] IONOS(ionos-mail): fix(ui): Update mailbox icon to use dark variant for better visibility Signed-off-by: Misha M.-Kupriyanov --- lib/Settings/Section/MailProviderAccountsSection.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Settings/Section/MailProviderAccountsSection.php b/lib/Settings/Section/MailProviderAccountsSection.php index e17a28d12b..d797199cff 100644 --- a/lib/Settings/Section/MailProviderAccountsSection.php +++ b/lib/Settings/Section/MailProviderAccountsSection.php @@ -40,6 +40,6 @@ public function getPriority(): int { #[\Override] public function getIcon(): string { - return $this->urlGenerator->imagePath('mail', 'mail.svg'); + return $this->urlGenerator->imagePath('mail', 'mail-dark.svg'); } } From fb522671c8f6d7280c94249f1b746b745f6f3cba Mon Sep 17 00:00:00 2001 From: "Misha M.-Kupriyanov" Date: Thu, 19 Feb 2026 15:06:04 +0100 Subject: [PATCH 03/11] IONOS(ionos-mail): fix(controller): Improve error handling for mailbox update Special handling for 404 errors has been added to provide a more helpful message when the mailbox cannot be found. This enhances user experience by guiding users to verify mailbox existence or contact support. Signed-off-by: Misha M.-Kupriyanov --- .../Ionos/Service/Core/IonosAccountMutationService.php | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/lib/Provider/MailAccountProvider/Implementations/Ionos/Service/Core/IonosAccountMutationService.php b/lib/Provider/MailAccountProvider/Implementations/Ionos/Service/Core/IonosAccountMutationService.php index 3babb0a77f..be90f38c12 100644 --- a/lib/Provider/MailAccountProvider/Implementations/Ionos/Service/Core/IonosAccountMutationService.php +++ b/lib/Provider/MailAccountProvider/Implementations/Ionos/Service/Core/IonosAccountMutationService.php @@ -424,6 +424,14 @@ public function updateMailboxLocalpart(string $userId, string $newLocalpart): st 'userId' => $userId, 'newEmail' => $newEmail, ]); + + // Special handling for 404 errors to provide a more helpful message + if ($e->getCode() === 404) { + $errorMessage = 'The IONOS API could not find the mailbox to update. This may be a backend API issue. ' + . 'Please verify the mailbox exists in the IONOS system or contact IONOS support.'; + throw new ServiceException($errorMessage, $e->getCode(), $e); + } + throw new ServiceException('Failed to update IONOS mailbox: ' . $e->getMessage(), $e->getCode(), $e); } catch (\Exception $e) { $this->logger->error('Exception when updating mailbox localpart', [ From 73e3ff671092856f869d072504895f99ab8a09d6 Mon Sep 17 00:00:00 2001 From: "Misha M.-Kupriyanov" Date: Thu, 19 Feb 2026 15:40:37 +0100 Subject: [PATCH 04/11] IONOS(ionos-mail): feat(ui): Implement virtualized mailbox list with header and footer components This update introduces a virtualized mailbox list to enhance performance when rendering large datasets. The new structure includes a dedicated header and footer component for better organization and user experience. The mailbox list now efficiently handles scrolling and loading states. Additionally, the styling has been improved for better visual consistency across the mailbox administration interface. Signed-off-by: Misha M.-Kupriyanov --- .../provider/mailbox/ProviderMailboxAdmin.vue | 167 ++++++---------- .../mailbox/ProviderMailboxListItem.vue | 56 ++++-- .../mailbox/shared/MailboxListFooter.vue | 109 +++++++++++ .../mailbox/shared/MailboxListHeader.vue | 96 ++++++++++ .../provider/mailbox/shared/VirtualList.vue | 181 ++++++++++++++++++ .../provider/mailbox/shared/styles.scss | 93 +++++++++ 6 files changed, 574 insertions(+), 128 deletions(-) create mode 100644 src/components/provider/mailbox/shared/MailboxListFooter.vue create mode 100644 src/components/provider/mailbox/shared/MailboxListHeader.vue create mode 100644 src/components/provider/mailbox/shared/VirtualList.vue create mode 100644 src/components/provider/mailbox/shared/styles.scss diff --git a/src/components/provider/mailbox/ProviderMailboxAdmin.vue b/src/components/provider/mailbox/ProviderMailboxAdmin.vue index 1240903e4b..071e197d55 100644 --- a/src/components/provider/mailbox/ProviderMailboxAdmin.vue +++ b/src/components/provider/mailbox/ProviderMailboxAdmin.vue @@ -42,52 +42,34 @@ -
-
- - -
- -
- {{ t('mail', 'Display Name') }} -
-
- {{ t('mail', 'Linked User') }} -
-
- {{ t('mail', 'Status') }} -
-
- {{ t('mail', 'Actions') }} -
-
- + + - -
- -
+ - - - - {{ n('mail', '%n mailbox', '%n mailboxes', mailboxes.length) }} - - -
-
+ + diff --git a/src/components/provider/mailbox/ProviderMailboxListItem.vue b/src/components/provider/mailbox/ProviderMailboxListItem.vue index 0d8fdd4d77..1430980c5c 100644 --- a/src/components/provider/mailbox/ProviderMailboxListItem.vue +++ b/src/components/provider/mailbox/ProviderMailboxListItem.vue @@ -4,11 +4,11 @@ --> - + -
-
+ -
- + - -
+
@@ -96,10 +97,11 @@ {{ accountStatusLabel }}
- + -
@@ -122,8 +124,8 @@ {{ t('mail', 'Delete') }} -
- + + + + diff --git a/src/components/provider/mailbox/shared/MailboxListHeader.vue b/src/components/provider/mailbox/shared/MailboxListHeader.vue new file mode 100644 index 0000000000..c4565171e8 --- /dev/null +++ b/src/components/provider/mailbox/shared/MailboxListHeader.vue @@ -0,0 +1,96 @@ + + + + + + + diff --git a/src/components/provider/mailbox/shared/VirtualList.vue b/src/components/provider/mailbox/shared/VirtualList.vue new file mode 100644 index 0000000000..f53d273f75 --- /dev/null +++ b/src/components/provider/mailbox/shared/VirtualList.vue @@ -0,0 +1,181 @@ + + + + + + + diff --git a/src/components/provider/mailbox/shared/styles.scss b/src/components/provider/mailbox/shared/styles.scss new file mode 100644 index 0000000000..9b59962969 --- /dev/null +++ b/src/components/provider/mailbox/shared/styles.scss @@ -0,0 +1,93 @@ +/** + * SPDX-FileCopyrightText: 2026 STRATO GmbH + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +@mixin row { + position: relative; + display: flex; + min-width: 100%; + width: fit-content; + min-height: var(--row-height); + background-color: var(--color-main-background); +} + +@mixin cell { + &__cell { + display: flex; + flex-direction: column; + justify-content: center; + padding: 4px var(--cell-padding); + min-width: var(--cell-width); + width: var(--cell-width); + flex-shrink: 0; + color: var(--color-main-text); + + &--displayname { + min-width: var(--cell-width); + width: var(--cell-width); + border-inline-end: 1px solid var(--color-border); + } + + &--linked-user { + min-width: var(--cell-width-large); + width: var(--cell-width-large); + flex-grow: 1; + } + + &--status { + min-width: var(--cell-width); + width: var(--cell-width); + } + + &--actions { + position: sticky; + inset-inline-end: 0; + z-index: var(--sticky-column-z-index); + display: flex; + flex-direction: row; + align-items: center; + min-width: 110px; + width: 110px; + flex-shrink: 0; + background-color: var(--color-main-background); + border-inline-start: 1px solid var(--color-border); + + &-end { + // Push the single button to align with the overflow (...) button position + // in the 2-button layout by reserving one button-width on the left. + padding-inline-start: 48px; + } + } + + // Fill remaining row space with cell + &--fill { + min-width: var(--cell-width-large); + width: 100%; + } + + strong, + span, + label { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + overflow-wrap: anywhere; + } + } + + // Sticky email column on left: enabled on wide viewports + @media (min-width: 670px) { + &__cell--email { + position: sticky; + inset-inline-start: 0; + z-index: var(--sticky-column-z-index); + background-color: var(--color-main-background); + border-inline-end: 1px solid var(--color-border); + } + } + + &__subtitle { + color: var(--color-text-maxcontrast); + } +} From a6f967ece33601084079f62220a8e2bd2787bce4 Mon Sep 17 00:00:00 2001 From: Tatjana Kaschperko Lindt Date: Mon, 23 Feb 2026 10:33:15 +0100 Subject: [PATCH 05/11] FIX-UP(scss): replace deprecated @import with @use in drag-and-drop styles Sass @import is deprecated and will be removed in Dart Sass 3.0.0. Using @use is the modern replacement and avoids the deprecation warning emitted during webpack compilation. Signed-off-by: Tatjana Kaschperko Lindt --- src/directives/drag-and-drop/styles/drag-and-drop.scss | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/directives/drag-and-drop/styles/drag-and-drop.scss b/src/directives/drag-and-drop/styles/drag-and-drop.scss index cc2f057b5e..cd6f021388 100644 --- a/src/directives/drag-and-drop/styles/drag-and-drop.scss +++ b/src/directives/drag-and-drop/styles/drag-and-drop.scss @@ -2,5 +2,5 @@ * SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later */ -@import 'draggable-envelope'; -@import 'droppable-mailbox'; +@use 'draggable-envelope'; +@use 'droppable-mailbox'; From 49faf4cbec600aeb3f2b0591e0ee7cafd609be44 Mon Sep 17 00:00:00 2001 From: Tatjana Kaschperko Lindt Date: Mon, 23 Feb 2026 10:33:46 +0100 Subject: [PATCH 06/11] FIX-UP(scss): move background-color before @media in ComposerSessionIndicator Sass is changing behavior for declarations that appear after nested rules to match the CSS spec. Moving background-color above the @media block keeps the existing behavior and eliminates the mixed-decls warning. Signed-off-by: Tatjana Kaschperko Lindt --- src/components/ComposerSessionIndicator.vue | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/components/ComposerSessionIndicator.vue b/src/components/ComposerSessionIndicator.vue index be5699f42c..89516f13c1 100644 --- a/src/components/ComposerSessionIndicator.vue +++ b/src/components/ComposerSessionIndicator.vue @@ -105,15 +105,15 @@ export default { // Retain border radius from outer body container for visual consistency border-radius: var(--body-container-radius); + // Conditional hover and pointer styles + background-color: var(--color-primary-element-light); + // Mobile @media (max-width: 1024px) { width: calc(100% - 2 * var(--default-grid-baseline)); height: 44px; border-radius: var(--border-radius-pill); } - - // Conditional hover and pointer styles - background-color: var(--color-primary-element-light); &:not(&--disabled) { &:hover { background-color: var(--color-primary-element-light-hover); From 94fe32e6118b2aa79e964bb53dc4f090437e92f7 Mon Sep 17 00:00:00 2001 From: Tatjana Kaschperko Lindt Date: Mon, 23 Feb 2026 10:33:53 +0100 Subject: [PATCH 07/11] FIX-UP(scss): move border-top before @include calls in MailboxListFooter Sass emits a mixed-decls warning when plain declarations appear after nested rules (produced by @include). Moving border-top above the @include statements keeps correct rendering and silences the warning. Signed-off-by: Tatjana Kaschperko Lindt --- src/components/provider/mailbox/shared/MailboxListFooter.vue | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/provider/mailbox/shared/MailboxListFooter.vue b/src/components/provider/mailbox/shared/MailboxListFooter.vue index 502c663ffb..d4993b38f8 100644 --- a/src/components/provider/mailbox/shared/MailboxListFooter.vue +++ b/src/components/provider/mailbox/shared/MailboxListFooter.vue @@ -80,11 +80,11 @@ export default { @use './styles'; .footer { + border-top: 1px solid var(--color-border); + @include styles.row; @include styles.cell; - border-top: 1px solid var(--color-border); - &__cell { position: sticky; color: var(--color-text-maxcontrast); From a2d8519642f87771295f95dddaae70d0d091f799 Mon Sep 17 00:00:00 2001 From: Tatjana Kaschperko Lindt Date: Mon, 23 Feb 2026 10:34:16 +0100 Subject: [PATCH 08/11] FIX-UP(webpack): specify translationsOutputFile for CKEditorWebpackPlugin CKEditorWebpackPlugin requires a strategy when multiple JS entry points are present. Using translationsOutputFile targeting mail.js appends CKEditor translations to that bundle, resolving the 'Too many JS assets' error during compilation. Signed-off-by: Tatjana Kaschperko Lindt --- webpack.common.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/webpack.common.js b/webpack.common.js index b4fd9fcd32..533788bd25 100644 --- a/webpack.common.js +++ b/webpack.common.js @@ -26,6 +26,8 @@ const plugins = [ new CKEditorWebpackPlugin({ // See https://ckeditor.com/docs/ckeditor5/latest/features/ui-language.html language: 'en', + // Multiple JS entry points require specifying which asset receives translations + translationsOutputFile: /^mail\.js$/, }), new VueLoaderPlugin(), From bf95f15d5ab850f2e300361e42326cd3b5aa3c8c Mon Sep 17 00:00:00 2001 From: Tatjana Kaschperko Lindt Date: Mon, 23 Feb 2026 13:29:59 +0100 Subject: [PATCH 09/11] FIX-UP(scss): override max-width for mailbox administration section Signed-off-by: Tatjana Kaschperko Lindt --- src/components/provider/mailbox/ProviderMailboxAdmin.vue | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/components/provider/mailbox/ProviderMailboxAdmin.vue b/src/components/provider/mailbox/ProviderMailboxAdmin.vue index 071e197d55..8c1843a6f6 100644 --- a/src/components/provider/mailbox/ProviderMailboxAdmin.vue +++ b/src/components/provider/mailbox/ProviderMailboxAdmin.vue @@ -230,6 +230,9 @@ export default { .mailbox-administration { display: flex; flex-direction: column; + // NcSettingsSection forces max-width: 900px on all direct children on NC≥30 + // (forceLimitWidth ignores the :limit-width prop). Override it here. + max-width: none !important; .provider-selector { margin-bottom: 20px; From 3fdcf3426d9967fafefeb8e02851492deca34b4a Mon Sep 17 00:00:00 2001 From: Tatjana Kaschperko Lindt Date: Mon, 23 Feb 2026 13:40:09 +0100 Subject: [PATCH 10/11] FIX-UP(ProviderMailboxListItem): make user-details one liner Signed-off-by: Tatjana Kaschperko Lindt --- .../mailbox/ProviderMailboxListItem.vue | 25 +++++++++---------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/src/components/provider/mailbox/ProviderMailboxListItem.vue b/src/components/provider/mailbox/ProviderMailboxListItem.vue index 1430980c5c..3f9a066329 100644 --- a/src/components/provider/mailbox/ProviderMailboxListItem.vue +++ b/src/components/provider/mailbox/ProviderMailboxListItem.vue @@ -71,12 +71,10 @@ -
- - {{ mailbox.userName }} - - {{ mailbox.userId }} -
+ + {{ mailbox.userName }} + ({{ mailbox.userId }}) + @@ -396,17 +394,18 @@ export default { flex-shrink: 0; } - .user-details { - display: flex; - flex-direction: column; + .user-label { min-width: 0; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; .user-display { font-weight: 500; - font-size: 14px; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; + } + + .row__subtitle { + margin-inline-start: 0.25em; } } } From 2c8cccd61310a298eaaea6d71d621802d28d8719 Mon Sep 17 00:00:00 2001 From: Tatjana Kaschperko Lindt Date: Mon, 23 Feb 2026 15:11:40 +0100 Subject: [PATCH 11/11] FIX-UP(ProviderMailboxListItem): remove unnecessary props from NcAvatar component this breaks info-popover by clicking on user icon Signed-off-by: Tatjana Kaschperko Lindt --- src/components/provider/mailbox/ProviderMailboxListItem.vue | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/components/provider/mailbox/ProviderMailboxListItem.vue b/src/components/provider/mailbox/ProviderMailboxListItem.vue index 3f9a066329..54bbd2fb7a 100644 --- a/src/components/provider/mailbox/ProviderMailboxListItem.vue +++ b/src/components/provider/mailbox/ProviderMailboxListItem.vue @@ -64,9 +64,7 @@ + :display-name="mailbox.userName || mailbox.userId" />