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 { useOnlineNotificationSeenMutation } from '#shared/entities/online-notification/graphql/mutations/seen.api.ts'
 import { OnlineNotificationsDocument } from '#shared/entities/online-notification/graphql/queries/onlineNotifications.api.ts'
 import { OnlineNotificationsDocument } from '#shared/entities/online-notification/graphql/queries/onlineNotifications.api.ts'
 import type {
 import type {
+  OnlineNotification,
   OnlineNotificationsQuery,
   OnlineNotificationsQuery,
   Scalars,
   Scalars,
 } from '#shared/graphql/types.ts'
 } 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(
   const seenNotificationMutation = new MutationHandler(
     useOnlineNotificationSeenMutation(),
     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(
   const markAllSeenMutation = new MutationHandler(
     useOnlineNotificationMarkAllAsSeenMutation(),
     useOnlineNotificationMarkAllAsSeenMutation(),

+ 16 - 16
i18n/zammad.pot

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