Browse Source

Maintenance: Desktop View - Add online notifications integration specs

Co-authored-by: Benjamin Scharf <bs@zammad.com>
Co-authored-by: Dusan Vuckovic <dv@zammad.com>
Benjamin Scharf 3 months ago
parent
commit
923c41aea2

+ 40 - 2
app/frontend/shared/entities/online-notification/composables/useOnlineNotificationActions.ts

@@ -7,6 +7,7 @@ import { useOnlineNotificationMarkAllAsSeenMutation } from '#shared/entities/onl
 import { useOnlineNotificationSeenMutation } from '#shared/entities/online-notification/graphql/mutations/seen.api.ts'
 import { OnlineNotificationsDocument } from '#shared/entities/online-notification/graphql/queries/onlineNotifications.api.ts'
 import type {
+  OnlineNotification,
   OnlineNotificationsQuery,
   Scalars,
 } from '#shared/graphql/types.ts'
@@ -91,6 +92,38 @@ export const useOnlineNotificationActions = () => {
     }
   }
 
+  const updateSeenNotificationCache = (id: Scalars['ID']['output']) => {
+    const data = getCacheData()
+
+    if (!data) return
+
+    const { queryOptions, oldQueryCache, existingQueryCache } = data
+
+    const clonedQueryCache = cloneDeep(existingQueryCache)
+
+    clonedQueryCache.onlineNotifications.edges.forEach(({ node }) => {
+      if ((node.metaObject as OnlineNotification['metaObject'])?.id === id) {
+        node.seen = true
+      }
+    })
+
+    cache.writeQuery({
+      ...queryOptions,
+      data: {
+        onlineNotifications: {
+          ...clonedQueryCache.onlineNotifications,
+        },
+      },
+    })
+
+    return () => {
+      cache.writeQuery({
+        ...queryOptions,
+        data: oldQueryCache,
+      })
+    }
+  }
+
   const seenNotificationMutation = new MutationHandler(
     useOnlineNotificationSeenMutation(),
     {
@@ -100,8 +133,13 @@ export const useOnlineNotificationActions = () => {
     },
   )
 
-  const seenNotification = async (id: Scalars['ID']['output']) =>
-    seenNotificationMutation.send({ objectId: id })
+  const seenNotification = async (id: Scalars['ID']['output']) => {
+    const revertCache = updateSeenNotificationCache(id)
+
+    return seenNotificationMutation
+      .send({ objectId: id })
+      .catch(() => revertCache)
+  }
 
   const markAllSeenMutation = new MutationHandler(
     useOnlineNotificationMarkAllAsSeenMutation(),

+ 16 - 16
i18n/zammad.pot

@@ -1253,8 +1253,8 @@ msgstr ""
 msgid "Agent idle timeout"
 msgstr ""
 
-#: app/models/role.rb:154
-#: app/models/user.rb:704
+#: app/models/role.rb:156
+#: app/models/user.rb:705
 msgid "Agent limit exceeded, please check your account settings."
 msgstr ""
 
@@ -1740,7 +1740,7 @@ msgstr ""
 msgid "Assignment timeout in minutes if assigned agent is not working on it. Ticket will be shown as unassigend."
 msgstr ""
 
-#: app/models/user.rb:607
+#: app/models/user.rb:608
 msgid "At least one identifier (firstname, lastname, phone, mobile or email) for user is required."
 msgstr ""
 
@@ -1752,8 +1752,8 @@ msgstr ""
 msgid "At least one object must be selected."
 msgstr ""
 
-#: app/models/role.rb:126
-#: app/models/user.rb:678
+#: app/models/role.rb:128
+#: app/models/user.rb:679
 msgid "At least one user needs to have admin permissions."
 msgstr ""
 
@@ -2468,7 +2468,7 @@ msgstr ""
 msgid "Cannot process external data source %s. %s"
 msgstr ""
 
-#: app/frontend/shared/entities/online-notification/composables/useOnlineNotificationActions.ts:109
+#: app/frontend/shared/entities/online-notification/composables/useOnlineNotificationActions.ts:147
 msgid "Cannot set online notifications as seen"
 msgstr ""
 
@@ -5499,7 +5499,7 @@ msgstr ""
 msgid "Email address"
 msgstr ""
 
-#: app/models/user.rb:617
+#: app/models/user.rb:618
 msgid "Email address '%{email}' is already used for another user."
 msgstr ""
 
@@ -7378,7 +7378,7 @@ msgstr ""
 msgid "Ignore Escalation/SLA Information"
 msgstr ""
 
-#: app/assets/javascripts/app/controllers/_ui_element/postmaster_set.coffee:45
+#: app/assets/javascripts/app/controllers/_ui_element/postmaster_set.coffee:48
 msgid "Ignore Message"
 msgstr ""
 
@@ -7841,7 +7841,7 @@ msgstr ""
 msgid "Invalid client_id received!"
 msgstr ""
 
-#: app/models/user.rb:562
+#: app/models/user.rb:563
 msgid "Invalid email '%{email}'"
 msgstr ""
 
@@ -9317,7 +9317,7 @@ msgstr ""
 msgid "More information can be found here."
 msgstr ""
 
-#: app/models/user.rb:630
+#: app/models/user.rb:631
 msgid "More than 250 secondary organizations are not allowed."
 msgstr ""
 
@@ -9897,7 +9897,7 @@ msgstr ""
 msgid "No content to show"
 msgstr ""
 
-#: app/models/group.rb:34
+#: app/models/group.rb:36
 msgid "No double colons (::) allowed, reserved delimiter"
 msgstr ""
 
@@ -12570,7 +12570,7 @@ msgstr ""
 msgid "Secondary organizations"
 msgstr ""
 
-#: app/models/user.rb:624
+#: app/models/user.rb:625
 msgid "Secondary organizations are only allowed when the primary organization is given."
 msgstr ""
 
@@ -14630,7 +14630,7 @@ msgstr ""
 msgid "The object could not be updated."
 msgstr ""
 
-#: app/frontend/shared/entities/online-notification/composables/useOnlineNotificationActions.ts:98
+#: app/frontend/shared/entities/online-notification/composables/useOnlineNotificationActions.ts:131
 msgid "The online notification could not be marked as seen."
 msgstr ""
 
@@ -14895,7 +14895,7 @@ msgstr ""
 msgid "The required parameter 'link_type' is missing."
 msgstr ""
 
-#: app/models/text_module.rb:29
+#: app/models/text_module.rb:31
 msgid "The required parameter 'locale' is missing."
 msgstr ""
 
@@ -15520,7 +15520,7 @@ msgstr ""
 msgid "This group has no email address configured for outgoing communication."
 msgstr ""
 
-#: app/models/group.rb:81
+#: app/models/group.rb:83
 msgid "This group or its children exceed the allowed nesting depth."
 msgstr ""
 
@@ -18870,7 +18870,7 @@ msgstr ""
 msgid "is the wrong length (should be 1 character)"
 msgstr ""
 
-#: app/models/user.rb:828
+#: app/models/user.rb:829
 msgid "is too long"
 msgstr ""
 

+ 99 - 0
spec/system/apps/desktop/personal_setting/online_notifications_spec.rb

@@ -0,0 +1,99 @@
+# Copyright (C) 2012-2024 Zammad Foundation, https://zammad-foundation.org/
+
+require 'rails_helper'
+
+RSpec.describe 'Desktop > Ticket > Online Notifications', app: :desktop_view, authenticated_as: :agent, type: :system do
+  let(:group)    { create(:group) }
+  let(:agent)    { create(:agent, groups: [group]) }
+  let(:agent_b)  { create(:agent, groups: [group]) }
+  let(:ticket)   { create(:ticket, group:, title: 'Ticket A') }
+  let(:ticket_b) { create(:ticket, group:, title: 'Ticket B') }
+
+  let(:online_notification)            { create(:online_notification, user: agent, created_by: agent_b, updated_by: agent_b, o: ticket, type_name: 'update') }
+  let(:online_notification_new_ticket) { create(:online_notification, user: agent, created_by: agent_b, updated_by: agent_b, o: ticket_b, type_name: 'create') }
+
+  context 'when receiving a new ticket notification' do
+    before do
+      online_notification
+
+      visit '/'
+
+      # Initial subscription request will fetch the new online notification,
+      #   which is why we must wait for the update flag instead of the start.
+      wait_for_subscription_update('onlineNotificationsCount', number: 1)
+    end
+
+    it 'receives an online notification' do
+      expect(find('[aria-label="Unseen notifications count"]')).to have_text('1')
+
+      find('button[aria-label="Show notifications"]').click
+
+      within('[role="region"]') do
+        expect(page).to have_text("#{agent_b.fullname} updated ticket Ticket A")
+        click_on 'mark all as read'
+        wait_for_mutation('onlineNotificationMarkAllAsSeen')
+      end
+
+      find('button[aria-label="Show notifications"]').click
+
+      within('[role="region"]') do
+        expect(page).to have_css('a', text: "#{agent_b.fullname} updated ticket Ticket A", style: { opacity: '0.3' })
+      end
+
+      find("[aria-label='#{Capybara::Selector::CSS.escape(agent.fullname)}']").click
+
+      click_on 'Profile settings'
+
+      click_on 'Notifications'
+
+      find('label', text: 'New ticket - All tickets').click
+      find('label', text: 'Ticket update - All tickets').click
+
+      click_on 'Save Notifications'
+
+      wait_for_mutation('userCurrentNotificationPreferencesUpdate', number: 1)
+
+      expect(agent.preferences['notification_config']['matrix']).to include(
+        'create'           => include(
+          'criteria' => include('owned_by_me' => true, 'owned_by_nobody' => true, 'subscribed' => true, 'no' => false),
+          'channel'  => include('email' => true, 'online' => true)
+        ),
+        'update'           => include(
+          'criteria' => include('owned_by_me' => true, 'owned_by_nobody' => true, 'subscribed' => true, 'no' => false),
+          'channel'  => include('email' => true, 'online' => true)
+        ),
+        'reminder_reached' => include(
+          'criteria' => include('owned_by_me' => true, 'owned_by_nobody' => false, 'subscribed' => false, 'no' => false),
+          'channel'  => include('email' => true, 'online' => true)
+        ),
+        'escalation'       => include(
+          'criteria' => include('owned_by_me' => true, 'owned_by_nobody' => false, 'subscribed' => false, 'no' => false),
+          'channel'  => include('email' => true, 'online' => true)
+        )
+      )
+
+      online_notification_new_ticket
+
+      wait_for_subscription_update('onlineNotificationsCount', number: 2)
+
+      expect(find('[aria-label="Unseen notifications count"]')).to have_text('1')
+
+      find('button[aria-label="Show notifications"]').click
+
+      within('[role="region"]') do
+        click_on "#{agent_b.fullname} created ticket Ticket B"
+      end
+
+      wait_for_mutation('onlineNotificationSeen')
+      wait_for_subscription_update('onlineNotificationsCount', number: 3)
+
+      expect(page).to have_current_path("/desktop/tickets/#{ticket_b.id}")
+
+      find('button[aria-label="Show notifications"]').click
+
+      within('[role="region"]') do
+        expect(page).to have_css('a', text: "#{agent_b.fullname} created ticket Ticket B", style: { opacity: '0.3' })
+      end
+    end
+  end
+end