Просмотр исходного кода

Fixes #4743 - Background color for avatars is different in different places

Vladimir Sheremet 1 год назад
Родитель
Сommit
9f1886012b

+ 3 - 0
app/frontend/apps/mobile/components/layout/__tests__/LayoutBottomNavigation.spec.ts

@@ -6,6 +6,7 @@ import type { UserData } from '#shared/types/store.ts'
 import { renderComponent } from '#tests/support/components/index.ts'
 import { mockGraphQLSubscription } from '#tests/support/mock-graphql-api.ts'
 import { flushPromises } from '@vue/test-utils'
+import { convertToGraphQLId } from '#shared/graphql/utils.ts'
 import LayoutBottomNavigation from '../LayoutBottomNavigation.vue'
 
 describe('bottom navigation in layout', () => {
@@ -18,6 +19,7 @@ describe('bottom navigation in layout', () => {
     const store = useSessionStore()
 
     store.user = {
+      id: convertToGraphQLId('User', 100),
       firstname: 'User',
       lastname: 'Test',
     } as UserData
@@ -46,6 +48,7 @@ describe('bottom navigation in layout', () => {
     const store = useSessionStore()
 
     store.user = {
+      id: convertToGraphQLId('User', 100),
       firstname: 'User',
       lastname: 'Test',
     } as UserData

+ 27 - 20
app/frontend/apps/mobile/pages/online-notification/components/__tests__/NotificationItem.spec.ts

@@ -1,12 +1,16 @@
 // Copyright (C) 2012-2023 Zammad Foundation, https://zammad-foundation.org/
 
 import { renderComponent } from '#tests/support/components/index.ts'
-import type { Scalars } from '#shared/graphql/types.ts'
+import type { Scalars, Ticket } from '#shared/graphql/types.ts'
 import { OnlineNotificationDeleteDocument } from '#shared/entities/online-notification/graphql/mutations/delete.api.ts'
 import { mockGraphQLApi } from '#tests/support/mock-graphql-api.ts'
+import { convertToGraphQLId } from '#shared/graphql/utils.ts'
+import { generateObjectData } from '#tests/graphql/index.ts'
 import NotificationItem from '../NotificationItem.vue'
 import type { Props } from '../NotificationItem.vue'
 
+const userId = convertToGraphQLId('User', 100)
+
 const renderNotificationItem = (props: Partial<Props> = {}) => {
   mockGraphQLApi(OnlineNotificationDeleteDocument).willResolve({
     onlineNotificationDelete: {
@@ -15,26 +19,29 @@ const renderNotificationItem = (props: Partial<Props> = {}) => {
     },
   })
 
-  return renderComponent(NotificationItem, {
-    props: {
-      itemId: '111',
-      objectName: 'Ticket',
-      typeName: 'update',
-      seen: false,
-      createdBy: {
-        fullname: 'John Doe',
-        firstname: 'John',
-        lastname: 'Doe',
-        active: true,
-      },
-      createdAt: new Date('2019-12-30 00:00:00').toISOString(),
-      metaObject: {
-        title: 'Ticket Title',
-        id: '1',
-        internalId: 1,
-      },
-      ...props,
+  const finishedProps: Props = {
+    itemId: '111',
+    objectName: 'Ticket',
+    typeName: 'update',
+    seen: false,
+    createdBy: {
+      id: userId,
+      fullname: 'John Doe',
+      firstname: 'John',
+      lastname: 'Doe',
+      active: true,
     },
+    createdAt: new Date('2019-12-30 00:00:00').toISOString(),
+    metaObject: generateObjectData<Ticket>('Ticket', {
+      title: 'Ticket Title',
+      id: convertToGraphQLId('Ticket', 1),
+      internalId: 1,
+    }),
+    ...props,
+  }
+
+  return renderComponent(NotificationItem, {
+    props: finishedProps,
     router: true,
   })
 }

+ 34 - 21
app/frontend/shared/components/ActivityMessage/__tests__/ActivityMessage.spec.ts

@@ -1,32 +1,45 @@
 // Copyright (C) 2012-2023 Zammad Foundation, https://zammad-foundation.org/
 
+import type { Ticket } from '#shared/graphql/types.ts'
+import { convertToGraphQLId } from '#shared/graphql/utils.ts'
+import { generateObjectData } from '#tests/graphql/index.ts'
+import { renderComponent } from '#tests/support/components/index.ts'
 import type { Props } from '../ActivityMessage.vue'
+import ActivityMessage from '../ActivityMessage.vue'
 
-const now = new Date('2022-01-03 00:00:00')
-vi.setSystemTime(now)
+const now = vi.hoisted(() => {
+  const now = new Date('2022-01-03 00:00:00')
+  vi.setSystemTime(now)
+  return now
+})
+
+// this is not required, but Vitest is bugged and does not hoist "now" otherwise
+// https://github.com/vitest-dev/vitest/pull/4285/files
+vi.mock('non-existing')
 
-const { default: ActivityMessage } = await import('../ActivityMessage.vue')
-const { renderComponent } = await import('#tests/support/components/index.ts')
+const userId = convertToGraphQLId('User', 100)
 
 const renderActivityMessage = (props: Partial<Props> = {}) => {
-  return renderComponent(ActivityMessage, {
-    props: {
-      objectName: 'Ticket',
-      typeName: 'update',
-      createdBy: {
-        fullname: 'John Doe',
-        firstname: 'John',
-        lastname: 'Doe',
-        active: true,
-      },
-      createdAt: new Date('2022-01-01 00:00:00').toISOString(),
-      metaObject: {
-        title: 'Ticket Title',
-        id: '1',
-        internalId: 1,
-      },
-      ...props,
+  const finishedProps: Props = {
+    objectName: 'Ticket',
+    typeName: 'update',
+    createdBy: {
+      id: userId,
+      fullname: 'John Doe',
+      firstname: 'John',
+      lastname: 'Doe',
+      active: true,
     },
+    createdAt: new Date('2022-01-01 00:00:00').toISOString(),
+    metaObject: generateObjectData<Ticket>('Ticket', {
+      title: 'Ticket Title',
+      id: convertToGraphQLId('Ticket', '1'),
+      internalId: 1,
+    }),
+    ...props,
+  }
+  return renderComponent(ActivityMessage, {
+    props: finishedProps,
     router: true,
   })
 }

+ 10 - 8
app/frontend/shared/components/CommonUserAvatar/CommonUserAvatar.vue

@@ -5,6 +5,11 @@ import { computed } from 'vue'
 import { useApplicationStore } from '#shared/stores/application.ts'
 import { getInitials } from '#shared/utils/formatter.ts'
 import { i18n } from '#shared/i18n.ts'
+import {
+  SYSTEM_USER_ID,
+  SYSTEM_USER_INTERNAL_ID,
+} from '#shared/utils/constants.ts'
+import { getIdFromGraphQLId } from '#shared/graphql/utils.ts'
 import CommonAvatar from '../CommonAvatar/CommonAvatar.vue'
 import type { AvatarSize } from '../CommonAvatar/index.ts'
 import type { AvatarUser } from './types.ts'
@@ -42,18 +47,15 @@ const fullName = computed(() => {
 })
 
 const colorClass = computed(() => {
-  const { email, id } = props.entity
+  const { id } = props.entity
 
-  // TODO ID is mangled by gql, maybe backend should send "isSystem"-like property?
-  if (id === '1') return 'bg-white'
+  const internalId = getIdFromGraphQLId(id)
 
-  // TODO it's better to use ID, so if someone changes name the color won't change
-  const name = [fullName.value, email].filter(Boolean).join('')
+  if (internalId === SYSTEM_USER_INTERNAL_ID) return 'bg-white'
 
-  if (!name || name === ' ' || name === '-') return colors[0]
   // get color based on mod of the fullname length
   // so it stays consistent between different interfaces and logins
-  return colors[name.length % 5]
+  return colors[internalId % (colors.length - 1)]
 })
 
 const sources = ['facebook', 'twitter']
@@ -68,7 +70,7 @@ const application = useApplicationStore()
 
 const image = computed(() => {
   if (icon.value) return null
-  if (props.entity.id === '1') return logo
+  if (props.entity.id === SYSTEM_USER_ID) return logo
   if (!props.entity.image) return null
 
   // Support the inline data URI as an image source.

+ 15 - 11
app/frontend/shared/components/CommonUserAvatar/__tests__/CommonUserAvatar.spec.ts

@@ -1,14 +1,18 @@
 // Copyright (C) 2012-2023 Zammad Foundation, https://zammad-foundation.org/
 
+import { convertToGraphQLId } from '#shared/graphql/utils.ts'
+import { SYSTEM_USER_ID } from '#shared/utils/constants.ts'
 import { renderComponent } from '#tests/support/components/index.ts'
 import CommonUserAvatar, { type Props } from '../CommonUserAvatar.vue'
 
+const USER_ID = convertToGraphQLId('User', '123')
+
 describe('CommonUserAvatar', () => {
   it('renders user avatar', async () => {
     const view = renderComponent(CommonUserAvatar, {
       props: <Props>{
         entity: {
-          id: '123',
+          id: USER_ID,
           firstname: 'John',
           lastname: 'Doe',
         },
@@ -22,7 +26,7 @@ describe('CommonUserAvatar', () => {
 
     await view.rerender(<Props>{
       entity: {
-        id: '123',
+        id: USER_ID,
         image: '100.png',
         firstname: 'John',
         lastname: 'Doe',
@@ -39,7 +43,7 @@ describe('CommonUserAvatar', () => {
     const view = renderComponent(CommonUserAvatar, {
       props: <Props>{
         entity: {
-          id: '1',
+          id: SYSTEM_USER_ID,
         },
       },
     })
@@ -56,7 +60,7 @@ describe('CommonUserAvatar', () => {
     const view = renderComponent(CommonUserAvatar, {
       props: <Props>{
         entity: {
-          id: '123',
+          id: USER_ID,
           source: 'twitter',
         },
       },
@@ -66,7 +70,7 @@ describe('CommonUserAvatar', () => {
 
     await view.rerender(<Props>{
       entity: {
-        id: '123',
+        id: USER_ID,
         source: 'facebook',
       },
     })
@@ -75,7 +79,7 @@ describe('CommonUserAvatar', () => {
 
     await view.rerender(<Props>{
       entity: {
-        id: '123',
+        id: USER_ID,
         source: 'some-unknown-source',
       },
     })
@@ -89,7 +93,7 @@ describe('CommonUserAvatar', () => {
     const view = renderComponent(CommonUserAvatar, {
       props: <Props>{
         entity: {
-          id: '123',
+          id: USER_ID,
           active: true,
         },
       },
@@ -102,7 +106,7 @@ describe('CommonUserAvatar', () => {
 
     await view.rerender(<Props>{
       entity: {
-        id: '123',
+        id: USER_ID,
         active: false,
         outOfOffice: true,
       },
@@ -112,7 +116,7 @@ describe('CommonUserAvatar', () => {
 
     await view.rerender(<Props>{
       entity: {
-        id: '123',
+        id: USER_ID,
         active: false,
         outOfOffice: false,
       },
@@ -125,7 +129,7 @@ describe('CommonUserAvatar', () => {
     const view = renderComponent(CommonUserAvatar, {
       props: <Props>{
         entity: {
-          id: '123',
+          id: USER_ID,
           vip: true,
         },
       },
@@ -135,7 +139,7 @@ describe('CommonUserAvatar', () => {
 
     await view.rerender(<Props>{
       entity: {
-        id: '123',
+        id: USER_ID,
         vip: true,
       },
       personal: true,

+ 9 - 0
app/frontend/shared/utils/constants.ts

@@ -0,0 +1,9 @@
+// Copyright (C) 2012-2023 Zammad Foundation, https://zammad-foundation.org/
+
+import { convertToGraphQLId } from '#shared/graphql/utils.ts'
+
+export const SYSTEM_USER_INTERNAL_ID = 1
+export const SYSTEM_USER_ID = convertToGraphQLId(
+  'User',
+  SYSTEM_USER_INTERNAL_ID,
+)