Skip to content

Commit 3384b30

Browse files
authored
Fix sorting activities when they are grouped in either part grouping or livestreaming (#5635)
* Add sorting upsert algorithm * With webchat:internal:position * Update comment * Redux store backcompat * Add given-when-then * Allow HowTo without position * Upsert livestream activity based on sequence number * Should not move livestream if timestamp is undefined * Fix tests * Clean up Object.freeze() * Fix path * Allow reuse position * FIx update activity channel data * No reorder when concluding livestream does not have timestamp * Upsert as-is if no HowTo.position * Always reuse position including livestreaming * Fix @id * Fix typing indicator test with duplicate activity ID * Fix typing indicator scrolling test with duplicate activity ID * Fix typing indicator test with duplicate livestream activity ID * Fix collapsible test have bad livestreaming metadata * Remove CoT * Skip activity for finalized livestream * Update position for plain activity * Remove timestamp: undefined * Update timestamp algorithm * Sort by logical timestamp, followed by local timestamp * Fix test: livestream finalize should move it to bottom * Honor timestamp on finalizing livestream activity * Fix dupe ID * Add a clock tick before sending another message * Patch all activities with internal channel data and fix typing entries for reproducibility * Clean up * Update snapshots * Fix test: finalizing livestream will update timestamp * Add tick between outgoing activities * Fix unit test * Fix typings * Rename perma ID to local ID * Add comment * Fix test: part grouping will always have updated timestamp * Rename permaId to localId * Fix test: part grouping should use max timestamp * Initial delete activity * Rename activityInternalId to activityLocalId * Add clean up after delete * Delete livestream activities * Delete activities in part grouping with livestream * Reorganize tests * Wire up delete activity * Add clientActivityIdToLocalId index * Update doc * Fix ESLint * Add *.spec.* and *.test.* * Revert * Clean up comment * Use standard way to parse @id * Remove early return * Add multiple part grouping test * Remove unnecessary findBeforeAfter * Typo * Update doc * Fix part grouping ID * Update test: position to undefined should be unmoved * Refactor property types * Use property functions * Fix part ID * Local ID is blank node identifier * Use node identifier schema for local ID * Fix import path * Fix local ID * Clean up * Add typing to Map * Clean up * Clean up with generateLocalIdInActivity * Remove unused BlankNodeIdentifier * Clean up * Use queryLocalIdFromActivity for generateLocalIdInActivity * Patch activity on POST_ACTIVITY_PENDING * Update PR number * Incorporate PR changes * Add related read
1 parent 1ebbb68 commit 3384b30

File tree

99 files changed

+4670
-798
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

99 files changed

+4670
-798
lines changed

CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -330,7 +330,7 @@ Notes: web developers are advised to use [`~` (tilde range)](https://github.com/
330330
- Fixed citation links are not properly matched against markdown links, in PR [#5614](https://github.com/microsoft/BotFramework-WebChat/pull/5614), by [@OEvgeny](https://github.com/OEvgeny)
331331
- Fixed `botframework-webchat/decorator` import in legacy CommonJS environments, in [#5616](https://github.com/microsoft/BotFramework-WebChat/pull/5616), by [@OEvgeny](https://github.com/OEvgeny)
332332
- Fixed `npm start` for efficiency and reliability, in PR [#5621](https://github.com/microsoft/BotFramework-WebChat/pull/5621) and [#5629](https://github.com/microsoft/BotFramework-WebChat/pull/5629), by [@compulim](https://github.com/compulim)
333-
- Fixed activity sorting introduced in PR [#5622](https://github.com/microsoft/BotFramework-WebChat/pull/5622), part grouping, and livestreaming, by [@compulim](https://github.com/compulim) in PR [#XXX](https://github.com/microsoft/BotFramework-WebChat/pull/XXX)
333+
- Fixed activity sorting introduced in PR [#5622](https://github.com/microsoft/BotFramework-WebChat/pull/5622), part grouping, and livestreaming, by [@compulim](https://github.com/compulim) in PR [#5635](https://github.com/microsoft/BotFramework-WebChat/pull/5635)
334334

335335
### Removed
336336

__tests__/html2/activity/collapsible.html

Lines changed: 40 additions & 42 deletions
Large diffs are not rendered by default.

__tests__/html2/activityGrouping/activityGrouping.disableTimestamp.html

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,8 @@
5454
)
5555
).resolveAll();
5656

57+
clock.tick(1000);
58+
5759
const { resolveAll: resolveAll1 } = await directLine.emulateOutgoingActivity(
5860
'Elit adipisicing laborum sit anim.'
5961
);

__tests__/html2/activityGrouping/activityGrouping.groupingActivityStatus.html

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@
5050
await sendMessage1.echoBack();
5151
sendMessage1.resolvePostActivity();
5252

53+
clock.tick(1000);
54+
5355
const sendMessage2 = await directLine.emulateOutgoingActivity('A retry prompt must show on this activity.');
5456

5557
clock.tick(1000);
@@ -61,6 +63,8 @@
6163
await sendMessage3.echoBack();
6264
sendMessage3.resolvePostActivity();
6365

66+
clock.tick(1000);
67+
6468
const sendMessage4 = await directLine.emulateOutgoingActivity(
6569
'The timestamp is shown because the next activity is not sent. When it is sent, the timestamp will be hidden.'
6670
);
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
<!doctype html>
2+
<html lang="en-US">
3+
<head>
4+
<link href="/assets/index.css" rel="stylesheet" type="text/css" />
5+
</head>
6+
<body>
7+
<main id="webchat"></main>
8+
<script type="importmap">
9+
{
10+
"imports": {
11+
"botframework-webchat": "/__dist__/packages/bundle/static/botframework-webchat.js",
12+
"react": "/__dist__/packages/bundle/static/react.js",
13+
"react-dom": "/__dist__/packages/bundle/static/react-dom.js"
14+
}
15+
}
16+
</script>
17+
<script type="module">
18+
import '/test-harness.mjs';
19+
import '/test-page-object.mjs';
20+
21+
import { createDirectLine, createStoreWithOptions, renderWebChat } from 'botframework-webchat';
22+
import { version } from 'react';
23+
24+
run(async function () {
25+
const {
26+
testHelpers: { createDirectLineEmulator }
27+
} = window;
28+
29+
// TODO: This is for `createDirectLineEmulator` only, should find ways to eliminate this line.
30+
window.WebChat = { createStoreWithOptions };
31+
32+
const { directLine, store } = createDirectLineEmulator();
33+
34+
renderWebChat({ directLine, store }, document.getElementById('webchat'));
35+
36+
await pageConditions.uiConnected();
37+
38+
await directLine.emulateIncomingActivity({
39+
from: { role: 'bot' },
40+
id: 'a-00001',
41+
text: 'Hello, World!',
42+
timestamp: new Date(86_400_000).toISOString()
43+
});
44+
45+
await directLine.emulateIncomingActivity({
46+
channelData: {
47+
streamSequence: 1,
48+
streamType: 'streaming'
49+
},
50+
from: { role: 'bot' },
51+
id: 'a-00002',
52+
text: '`t=undefined`\n\nA quick',
53+
timestamp: undefined,
54+
type: 'typing'
55+
});
56+
57+
expect(pageElements.activityContents().map(({ textContent }) => textContent)).toEqual([
58+
'Hello, World!',
59+
't=undefined\nA quick'
60+
]);
61+
62+
// THEN: Screenshot should show no timestamp below the second message.
63+
await host.snapshot('local');
64+
65+
await directLine.emulateIncomingActivity({
66+
channelData: {
67+
streamId: 'a-00002',
68+
streamSequence: 2,
69+
streamType: 'streaming'
70+
},
71+
from: { role: 'bot' },
72+
id: 'a-00003',
73+
text: '`t=0`\n\nA quick brown fox',
74+
timestamp: new Date(0).toISOString(),
75+
type: 'typing'
76+
});
77+
78+
expect(pageElements.activityContents().map(({ textContent }) => textContent)).toEqual([
79+
'Hello, World!',
80+
't=0\nA quick brown fox'
81+
]);
82+
83+
// THEN: Should show the livestream message on second position as it should not be moved.
84+
await host.snapshot('local');
85+
86+
await directLine.emulateIncomingActivity({
87+
channelData: {
88+
streamId: 'a-00002',
89+
streamType: 'final'
90+
},
91+
from: { role: 'bot' },
92+
id: 'a-00004',
93+
text: '`t=0`\n\nA quick brown fox jumped over the lazy dogs.',
94+
timestamp: new Date(0).toISOString(),
95+
type: 'message'
96+
});
97+
98+
// THEN: Should have the livestream message as the first one.
99+
expect(pageElements.activityContents().map(({ textContent }) => textContent)).toEqual([
100+
't=0\nA quick brown fox jumped over the lazy dogs.',
101+
'Hello, World!'
102+
]);
103+
104+
await host.snapshot('local');
105+
});
106+
</script>
107+
</body>
108+
</html>
9.71 KB
Loading
10.2 KB
Loading
12.5 KB
Loading

__tests__/html2/activityOrdering/partGroupingAtTheEndOfChatHistory.html

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@
4242
'@id': '',
4343
'@type': 'Message',
4444
type: 'https://schema.org/Message',
45-
isPartOf: { '@id': 'c-00001', '@type': 'HowTo' },
45+
isPartOf: { '@id': '_:c-00001', '@type': 'HowTo' },
4646
position: 1
4747
}
4848
],
@@ -83,7 +83,7 @@
8383
'@id': '',
8484
'@type': 'Message',
8585
type: 'https://schema.org/Message',
86-
isPartOf: { '@id': 'c-00001', '@type': 'HowTo' },
86+
isPartOf: { '@id': '_:c-00001', '@type': 'HowTo' },
8787
position: 2
8888
}
8989
],
@@ -95,9 +95,9 @@
9595
});
9696

9797
expect(pageElements.activityContents().map(({ textContent }) => textContent)).toEqual([
98+
'a-00002: Hello, World at t = 1',
9899
'a-00001: Chain 1 thought 1 at t = 0',
99-
'a-00003: Chain 1 thought 2 at t = 2',
100-
'a-00002: Hello, World at t = 1'
100+
'a-00003: Chain 1 thought 2 at t = 2'
101101
]);
102102

103103
await host.snapshot('local');
@@ -109,7 +109,7 @@
109109
'@id': '',
110110
'@type': 'Message',
111111
type: 'https://schema.org/Message',
112-
isPartOf: { '@id': 'c-00002', '@type': 'HowTo' },
112+
isPartOf: { '@id': '_:c-00002', '@type': 'HowTo' },
113113
position: 1
114114
}
115115
],
@@ -121,9 +121,9 @@
121121
});
122122

123123
expect(pageElements.activityContents().map(({ textContent }) => textContent)).toEqual([
124+
'a-00002: Hello, World at t = 1',
124125
'a-00001: Chain 1 thought 1 at t = 0',
125126
'a-00003: Chain 1 thought 2 at t = 2',
126-
'a-00002: Hello, World at t = 1',
127127
'a-00004: Chain 2 thought 1 at t = 3'
128128
]);
129129

@@ -136,23 +136,24 @@
136136
'@id': '',
137137
'@type': 'Message',
138138
type: 'https://schema.org/Message',
139-
isPartOf: { '@id': 'c-00002', '@type': 'HowTo' },
139+
isPartOf: { '@id': '_:c-00002', '@type': 'HowTo' },
140140
position: 2
141141
}
142142
],
143143
from: { role: 'bot' },
144144
id: 'a-00005',
145145
text: 'a-00005: Chain 2 thought 2 at t = 0',
146146
// Intentionally roll back the date.
147-
// It should be grouped and not appear before "Hello, World!'
147+
// It should be grouped but not appear before "Hello, World!"
148+
// This is because the part grouping timestamp is max of all parts, i.e. 3 * 86_400_000.
148149
timestamp: new Date(0).toISOString(),
149150
type: 'message'
150151
});
151152

152153
expect(pageElements.activityContents().map(({ textContent }) => textContent)).toEqual([
154+
'a-00002: Hello, World at t = 1',
153155
'a-00001: Chain 1 thought 1 at t = 0',
154156
'a-00003: Chain 1 thought 2 at t = 2',
155-
'a-00002: Hello, World at t = 1',
156157
'a-00004: Chain 2 thought 1 at t = 3',
157158
'a-00005: Chain 2 thought 2 at t = 0'
158159
]);
145 Bytes
Loading

0 commit comments

Comments
 (0)