Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F85805087
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Award Token
Flag For Later
Size
13 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/src/components/chat_message_list/chat_message_list.js b/src/components/chat_message_list/chat_message_list.js
index 96dfb2c1cc..fe984020ea 100644
--- a/src/components/chat_message_list/chat_message_list.js
+++ b/src/components/chat_message_list/chat_message_list.js
@@ -1,151 +1,154 @@
import { computed, inject, ref, toRefs, useTemplateRef } from 'vue'
import ChatMessage from 'src/components/chat_message/chat_message.vue'
import { useInterfaceSizes } from 'src/composables/useInterfaceSizes.js'
import { useVirtualScrolling } from 'src/composables/useVirtualScrolling.js'
const ChatMessageList = {
components: {
ChatMessage,
},
props: {
pending: Boolean,
messages: Array,
headerDate: Boolean,
focusedId: String,
repliedId: String,
},
emits: ['replyRequested'],
setup(props, { emit }) {
const { messages, headerDate } = toRefs(props)
const hoveredMessageChainId = ref(null)
const chatItems = computed(() => {
return messages.value
.reduceRight((acc, message, index) => {
const date = new Date(message.created_at)
const olderMessage = messages.value[index - 1]
const newerItem = acc.at(-1)
const diff = olderMessage
? message.created_at - olderMessage.created_at
: null
const MAX_DIFF = 1000 * 60 * 5 // 5 minutes
const dateDiffs = (() => {
if (olderMessage) {
const newerDate = new Date(message.created_at)
const olderDate = new Date(olderMessage.created_at)
newerDate.setHours(0, 0, 0, 0)
olderDate.setHours(0, 0, 0, 0)
return newerDate.toISOString() !== olderDate.toISOString()
} else {
return true
}
})()
const chatItem = {
type: 'message',
data: message,
date,
id: message.id,
isTail: true,
isHead: true,
olderMessage,
}
if (newerItem == null) {
chatItem.messageChainId = message.id
} else if (newerItem.type === 'date') {
chatItem.messageChainId = message.id
} else if (newerItem.type === 'message') {
const newerUser =
newerItem.data.account_id || newerItem.data.user.id
const olderUser = message.account_id || message.user.id
if (newerUser !== olderUser) {
chatItem.messageChainId = message.id
} else {
chatItem.messageChainId = newerItem.messageChainId
chatItem.isTail = false
newerItem.isHead = false
}
}
if (diff > MAX_DIFF || (!olderMessage && headerDate.value)) {
return [
...acc,
chatItem,
{
type: 'date',
date,
isDate: dateDiffs,
isTime: diff > MAX_DIFF && !dateDiffs,
id: 'fake-date-' + date.getTime().toString(),
},
]
} else {
return [...acc, chatItem]
}
}, [])
.reverse()
})
const chatItemsIndex = computed(() =>
chatItems.value.reduce((map, value) => {
map.set(value.id, value)
return map
}, new Map()),
)
const getCurrentItem = (id) => chatItemsIndex.value.get(id)
const scroller = inject('bodyScrollPosition')
const body = useTemplateRef('body')
const { fontSize } = useInterfaceSizes()
const normalHeight = computed(() => fontSize.value * 3)
const dateHeight = computed(() => fontSize.value * 1.5)
const getPlaceholderHeight = (id) =>
id?.startsWith('fake-date-') ? dateHeight : normalHeight
const { pending } = toRefs(props)
const { heightChart, changeSuspendState, updateVirtualHeight } =
useVirtualScrolling({
name: pending.value
? 'ChatMessageList<Pending>'
: 'ChatMessageList<Real>',
enabled: ref(true),
list: chatItems,
body,
scrollPositionInstance: scroller,
scrollCompensation: true,
getPlaceholderHeight,
invertDirection: true,
})
const { focusedId, repliedId } = toRefs(props)
const onMessageHover = ({ isHovered, messageChainId }) => {
hoveredMessageChainId.value = isHovered ? messageChainId : undefined
}
const onReplyRequested = (message) => emit('replyRequested', message)
return {
heightChart,
updateVirtualHeight,
getCurrentItem,
hoveredMessageChainId,
changeSuspendState,
focusedId,
repliedId,
onReplyRequested,
onMessageHover,
+ _test: {
+ chatItems,
+ },
}
},
}
export default ChatMessageList
diff --git a/test/unit/specs/components/chat_message_list.spec.js b/test/unit/specs/components/chat_message_list.spec.js
index 126332b958..6e381ea4a5 100644
--- a/test/unit/specs/components/chat_message_list.spec.js
+++ b/test/unit/specs/components/chat_message_list.spec.js
@@ -1,244 +1,205 @@
+import { createTestingPinia } from '@pinia/testing'
+import { setActivePinia } from 'pinia'
import { shallowMount } from '@vue/test-utils'
+import { ref } from 'vue'
import ChatMessageList from 'src/components/chat_message_list/chat_message_list.vue'
+const scrollPositionInstance = {
+ x: ref(0),
+ y: ref(0),
+ vHeight: ref(768),
+ vWidth: ref(1024),
+ vHeight: ref(768),
+ vWidth: ref(1024),
+ scrollBy: vi.fn(),
+ hasReachedTop: ref(false),
+ hasReachedBottom: ref(false),
+}
+const global = {
+ provide: {
+ bodyScrollPosition: scrollPositionInstance
+ }
+}
describe('ChatMessageList', () => {
- describe('computed.chatItems', () => {
+ beforeEach(() => {
+ setActivePinia(createTestingPinia({ stubActions: false }))
+ })
+
+ describe('computed.chatItems.value', () => {
it('Inserts date separators', () => {
const component = shallowMount(ChatMessageList, {
+ global,
props: {
messages: [
{
id: '0',
account_id: 'Alice',
created_at: new Date('2020-06-22T20:00:00.000Z'),
},
{
id: '1',
account_id: 'Alice',
created_at: new Date('2020-06-22T20:01:00.000Z'),
},
{
id: '2',
account_id: 'Alice',
created_at: new Date('2020-06-23T20:00:00.000Z'),
},
],
},
})
- expect(component.vm.chatItems.map((i) => i.type)).to.eql([
+ expect(component.vm._test.chatItems.value.map((i) => i.type)).to.eql([
'message',
'message',
'date',
'message',
])
})
it('Inserts date header if needed', () => {
const component = shallowMount(ChatMessageList, {
+ global,
props: {
headerDate: true,
messages: [
{
id: '0',
account_id: 'Alice',
created_at: new Date('2020-06-23T20:00:00.000Z'),
},
],
},
})
- expect(component.vm.chatItems.map((i) => i.type)).to.eql([
+ expect(component.vm._test.chatItems.value.map((i) => i.type)).to.eql([
'date',
'message',
])
})
it('Inserts time separators if messages were sent with considerable delay (5 minutes)', () => {
const component = shallowMount(ChatMessageList, {
+ global,
props: {
messages: [
{
id: '0',
account_id: 'Alice',
created_at: new Date('2020-06-22T20:00:00.000Z'),
},
{
id: '1',
account_id: 'Alice',
created_at: new Date('2020-06-22T20:06:00.000Z'),
},
{
id: '2',
account_id: 'Alice',
created_at: new Date('2020-06-23T20:00:00.000Z'),
},
],
},
})
- expect(component.vm.chatItems.map((i) => i.type)).to.eql([
+ expect(component.vm._test.chatItems.value.map((i) => i.type)).to.eql([
'message',
'date',
'message',
'date',
'message',
])
- expect(component.vm.chatItems.map((i) => i.isTime)).to.eql([
+ expect(component.vm._test.chatItems.value.map((i) => i.isTime)).to.eql([
undefined,
true,
undefined,
false,
undefined,
])
})
it('Groups message chains by time and author', () => {
const component = shallowMount(ChatMessageList, {
+ global,
props: {
messages: [
{
id: '0',
account_id: 'Alice',
created_at: new Date('2020-06-22T20:00:00.000Z'),
},
{
id: '1',
account_id: 'Alice',
created_at: new Date('2020-06-22T20:06:00.000Z'),
},
{
id: '2',
account_id: 'Alice',
created_at: new Date('2020-06-23T20:00:00.000Z'),
},
{
id: '3',
account_id: 'Bob',
created_at: new Date('2020-06-23T20:01:00.000Z'),
},
{
id: '4',
account_id: 'Bob',
created_at: new Date('2020-06-23T20:02:00.000Z'),
},
{
id: '5',
account_id: 'Bob',
created_at: new Date('2020-06-23T20:03:00.000Z'),
},
{
id: '6',
account_id: 'Eve',
created_at: new Date('2020-06-23T20:04:00.000Z'),
},
],
},
})
// Type check
- expect(component.vm.chatItems.map((i) => i.type)).to.eql([
+ expect(component.vm._test.chatItems.value.map((i) => i.type)).to.eql([
'message',
'date',
'message',
'date',
'message',
'message',
'message',
'message',
'message',
])
// Chain head/Tail checks
- expect(component.vm.chatItems.map((i) => [i.isHead, i.isTail])).to.eql([
+ expect(component.vm._test.chatItems.value.map((i) => [i.isHead, i.isTail])).to.eql([
[true, true],
[undefined, undefined],
[true, true],
[undefined, undefined],
[true, true],
[true, false],
[false, false],
[false, true],
[true, true],
])
// Unique ID is randomly generated so we have to compare data against itself
// Two messages from Bob next to each other
- expect(component.vm.chatItems[5].messageChainId).to.eql(
- component.vm.chatItems[6].messageChainId,
+ expect(component.vm._test.chatItems.value[5].messageChainId).to.eql(
+ component.vm._test.chatItems.value[6].messageChainId,
)
// Message from Even right after Bob
- expect(component.vm.chatItems[7].messageChainId).to.not.eql(
- component.vm.chatItems[8].messageChainId,
+ expect(component.vm._test.chatItems.value[7].messageChainId).to.not.eql(
+ component.vm._test.chatItems.value[8].messageChainId,
)
})
})
- describe('methods.getPreviousItem', () => {
- describe('Finds correct previous meaningful (non-separator) message in the chatlist', () => {
- let component
-
- beforeEach(() => {
- component = shallowMount(ChatMessageList, {
- props: {
- messages: [
- {
- id: '0',
- account_id: 'Alice',
- created_at: new Date('2020-06-22T20:00:00.000Z'),
- },
- {
- // Separator
- id: '1', // 2
- account_id: 'Alice',
- created_at: new Date('2020-06-22T20:06:00.000Z'),
- },
- {
- // Separator
- id: '2', // 4
- account_id: 'Alice',
- created_at: new Date('2020-06-23T20:00:00.000Z'),
- },
- {
- id: '3', // 5
- account_id: 'Bob',
- created_at: new Date('2020-06-23T20:01:00.000Z'),
- },
- {
- id: '4', // 6
- account_id: 'Bob',
- created_at: new Date('2020-06-23T20:02:00.000Z'),
- },
- {
- id: '5', // 7
- account_id: 'Bob',
- created_at: new Date('2020-06-23T20:03:00.000Z'),
- },
- {
- id: '6', // 8
- account_id: 'Eve',
- created_at: new Date('2020-06-23T20:04:00.000Z'),
- },
- ],
- },
- })
- })
-
- it('Directly next to each other', () => {
- const correct = component.vm.chatItems[6]
- expect(component.vm.getPreviousItem(7)).to.eql(correct)
- })
-
- it('Across separator', () => {
- const correct = component.vm.chatItems[2]
- expect(component.vm.getPreviousItem(4)).to.eql(correct)
- })
-
- it('Returns null if no previous item exist', () => {
- const correct = null
- expect(component.vm.getPreviousItem(0)).to.eql(correct)
- })
- })
- })
})
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Sat, Oct 10, 11:45 PM (1 d, 10 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1785509
Default Alt Text
(13 KB)
Attached To
Mode
rPUFE pleroma-fe-upstream
Attached
Detach File
Event Timeline
Log In to Comment