Skip to content

Commit 13f9a8e

Browse files
authored
Graph backend phase 1 (#5622)
* Add api-graph * Add JSON-LD schemas * Add flattenedNodeObject * Fail when flattening array * Add more tests for flattening * Expect no warn/error * Add doc * Add expandArray * Add doc * Add test * Add isOfType * Rename to FlatNodeObject * Comment * Use flatNodeObject * Add GraphProvider.mergeNode * Add graph * Add isPartOf auto-linking * More opinions * Update comments * Clean up * Add test * Remove edge if needed * Add specific test case for coloring * Clean up * Better test result * Add slantNodeWithFix schema * Simplify * Clean up * Clean up comment * Reorder * Clean up * Fix comment * Fix comment * Fix comment * First working graph * Add react-hooks * Add Graph2 * Add Graph2.middleware * Use Map for middleware * Clean up * Support JSON literals * Update npm start dependencies * Activity as JSON literal * Sort * Test assumptions * Clean up * Fixed node reference * Clean up schema * Add @see * Add validation schema * Move to SlantGraph * Validate middleware result * Validate middleware request/result * Auto-inversing and no flatten node reference * Update opinion text * npm start without transient local dependencies * Deprecate Graph1 * Reorganize files * Clean up * Clean up auto-inversion * Add crypto.randomUUID * Fix randomUUID * Hide console log * Remove obsoleted Graph1 * Clean up * Ponyfill * Use uuid.v4() * Handle event activity * Fix race condition on setOrderedActivities * readonly activities[] * Skip test * Allow typing activity * Allow optional identifier * Fix freeze SlantNode * Fix initial subscribe not processing graph * Fix duplicated line * Use sequence ID to sort, add webchat:internal:position * Fix ESLint * Graph to support replace activity * Fix replace activity for activity without ID * Support replace activity with clientActivityId * Fix replacing undefined client activity ID * Add permanent ID * Clean u9p * Add comment * Use uuid instead of crypto.randomUUID * Add new property to fix typing * Assign random value if no activity.id * Keep activity when receive echoback * Keep outgoing pending activity at same position * Set outgoing pending with sequence ID instead of timestamp * Fix sort fallback properly * Fix get timestamp of 0 * Trigger subscriber after transaction is closed * Handle unknown activity type * Add activity.id for dedupe while remount * Allow activity.timestamp: undefined * Ordering should not take account into activities without timestamp * Add snapshot * Fix ESLint * Allow-warn timestamp of type Date * Allow act/upsert during subscribe() call * Fix test * Compare position * Add debugging * Revert debugging * Assert with Redux * Clean up * Clean up * Add freeze and clean up * Clean up * Fix typing * Move freeze to base/valibot * Typo * Remove TODO * Add terminator middleware * Clean up * Fix assertion, clean ordered activities on remount * Clean up internal properties if passed in * Rename to upserting from incoming * Clean up * Clean up by removing compose() * Add entry * Extract and cache schema object * Remove commented code
1 parent 228887d commit 13f9a8e

File tree

95 files changed

+4274
-131
lines changed

Some content is hidden

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

95 files changed

+4274
-131
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,7 @@ Notes: web developers are advised to use [`~` (tilde range)](https://github.com/
147147
- Cleaned up `<ThemeProvider>` and various CSS related code, in PR [#5611](https://github.com/microsoft/BotFramework-WebChat/pull/5611), by [@compulim](https://github.com/compulim)
148148
- (Experimental) Reworked the copilot variant to align with the modern Copilot UX, in PR [#5630](https://github.com/microsoft/BotFramework-WebChat/pull/5630), by [@OEvgeny](https://github.com/OEvgeny)
149149
- The legacy design is temporarily available as `copilot-deprecated` for migration
150+
- New JSON-LD graph backend, by [@compulim](https://github.com/compulim) in PR [#5622](https://github.com/microsoft/BotFramework-WebChat/pull/5622)
150151

151152
### Changed
152153

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
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+
const now = Date.now();
39+
40+
await directLine.emulateIncomingActivity({
41+
from: { role: 'bot' },
42+
text: '1 without timestamp.',
43+
timestamp: undefined,
44+
type: 'message'
45+
});
46+
47+
await directLine.emulateIncomingActivity({
48+
from: { role: 'bot' },
49+
text: '2 with t = 0.',
50+
timestamp: new Date(now).toISOString(),
51+
type: 'message'
52+
});
53+
54+
await directLine.emulateIncomingActivity({
55+
from: { role: 'bot' },
56+
text: '4 with t = 2.',
57+
timestamp: new Date(now + 2).toISOString(),
58+
type: 'message'
59+
});
60+
61+
await directLine.emulateIncomingActivity({
62+
from: { role: 'bot' },
63+
text: '5 without timestamp.',
64+
timestamp: undefined,
65+
type: 'message'
66+
});
67+
68+
await directLine.emulateIncomingActivity({
69+
from: { role: 'bot' },
70+
text: '3 with t = 1.',
71+
timestamp: new Date(now + 1).toISOString(),
72+
type: 'message'
73+
});
74+
75+
expect(pageElements.activityContents().map(({ textContent }) => textContent)).toEqual([
76+
'1 without timestamp.',
77+
'2 with t = 0.',
78+
'3 with t = 1.',
79+
'4 with t = 2.',
80+
'5 without timestamp.'
81+
]);
82+
83+
await host.snapshot('local');
84+
});
85+
</script>
86+
</body>
87+
</html>
12.7 KB
Loading
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
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.emulateOutgoingActivity('One.');
39+
40+
await pageConditions.numActivitiesShown(1);
41+
42+
await directLine.emulateOutgoingActivity('Two.');
43+
44+
await pageConditions.numActivitiesShown(2);
45+
46+
expect(pageElements.activityContents().map(({ textContent }) => textContent)).toEqual(['One.', 'Two.']);
47+
});
48+
</script>
49+
</body>
50+
</html>

__tests__/html2/basic/remount.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
() =>
2727
createDirectLineWithTranscript([
2828
{
29+
id: 'a-00001', // ID is needed to make sure activity is not added twice when remounted and resubscribed.
2930
text: `Hello, World!`,
3031
type: 'message',
3132
timestamp: '2000-01-23T12:34:56.12345Z'

__tests__/html2/chatAdapter/sequenceId.directLine.outgoing.html

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,8 @@
7878
await pageObjects.sendMessageViaSendBox('User activity has timestamp of 1.', { waitForSend: false });
7979
await pageObjects.sendMessageViaSendBox('User activity has timestamp of 0.', { waitForSend: false });
8080

81+
await pageConditions.numActivitiesShown(3);
82+
8183
const { activities } = store.getState();
8284

8385
// THEN: The first outgoing message should be the second, after the bot's message.
@@ -86,14 +88,16 @@
8688
// THEN: The second outgoing message should be the third.
8789
expect(activities[2].text).toBe('User activity has timestamp of 0.');
8890

89-
// THEN: The first outgoing message should have a smaller sequence ID than the bot's message.
91+
// THEN: The first outgoing message should have a smaller position than the bot's message.
9092
expect(
91-
activities[0].channelData['webchat:sequence-id'] < activities[1].channelData['webchat:sequence-id']
93+
activities[0].channelData['webchat:internal:position'] <
94+
activities[1].channelData['webchat:internal:position']
9295
).toBe(true);
9396

94-
// THEN: The first outgoing message should have a smaller sequence ID than the second outgoing message.
97+
// THEN: The first outgoing message should have a smaller position than the second outgoing message.
9598
expect(
96-
activities[1].channelData['webchat:sequence-id'] < activities[2].channelData['webchat:sequence-id']
99+
activities[1].channelData['webchat:internal:position'] <
100+
activities[2].channelData['webchat:internal:position']
97101
).toBe(true);
98102

99103
// THEN: Both outgoing messages should not send "webchat:sequence-id" and "state".

__tests__/html2/part-grouping/position.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -278,4 +278,4 @@
278278
</script>
279279
</body>
280280

281-
</html>
281+
</html>

__tests__/html2/preact/activity/feedback.status.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,7 @@
136136
);
137137

138138
await pageConditions.uiConnected();
139+
await pageConditions.numActivitiesShown(3);
139140

140141
await host.snapshot('local');
141142

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { v4 } from 'uuid';
2+
3+
// In browser, only works in secure context.
4+
if (!global.crypto?.randomUUID) {
5+
global.crypto = {
6+
...global.crypto,
7+
randomUUID() {
8+
return v4();
9+
}
10+
};
11+
}

jest.legacy.config.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,14 +63,17 @@ module.exports = {
6363
'<rootDir>/__tests__/setup/setupGlobalAgent.js',
6464
'<rootDir>/__tests__/setup/preSetupTestFramework.js',
6565
'<rootDir>/__tests__/setup/setupCryptoGetRandomValues.js',
66+
'<rootDir>/__tests__/setup/setupCryptoRandomUUID.js',
6667
'<rootDir>/__tests__/setup/setupImageSnapshot.js',
6768
'<rootDir>/__tests__/setup/setupTestNightly.js',
6869
'<rootDir>/__tests__/setup/setupTimeout.js'
6970
],
7071
testMatch: ['**/__tests__/**/*.?([mc])[jt]s?(x)', '**/?(*.)+(spec|test).?([mc])[jt]s?(x)'],
7172
testPathIgnorePatterns: [
73+
'/dist/',
7274
'/lib/',
7375
'/node_modules/',
76+
'/static/',
7477
'<rootDir>/__tests__/html/.*?(\\.html)',
7578
'<rootDir>/__tests__/html/__dist__',
7679
'<rootDir>/__tests__/html/__jest__',

0 commit comments

Comments
 (0)