@atlaskit/editor-plugin-mentions 13.3.15 → 14.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +44 -0
- package/dist/cjs/pm-plugins/main.js +252 -47
- package/dist/cjs/ui/type-ahead/analytics.js +7 -4
- package/dist/cjs/ui/type-ahead/index.js +46 -24
- package/dist/es2019/pm-plugins/main.js +242 -39
- package/dist/es2019/ui/type-ahead/analytics.js +4 -1
- package/dist/es2019/ui/type-ahead/index.js +35 -17
- package/dist/esm/pm-plugins/main.js +252 -47
- package/dist/esm/ui/type-ahead/analytics.js +7 -4
- package/dist/esm/ui/type-ahead/index.js +46 -24
- package/dist/types/pm-plugins/main.d.ts +2 -0
- package/dist/types/types/index.d.ts +24 -0
- package/dist/types/ui/type-ahead/analytics.d.ts +1 -1
- package/package.json +25 -33
|
@@ -22,6 +22,8 @@ var _platformFeatureFlags = require("@atlaskit/platform-feature-flags");
|
|
|
22
22
|
var _experiments = require("@atlaskit/tmp-editor-statsig/experiments");
|
|
23
23
|
var _expVal = require("@atlaskit/tmp-editor-statsig/expVal");
|
|
24
24
|
var _editorCommands = require("../../editor-commands");
|
|
25
|
+
var _key = require("../../pm-plugins/key");
|
|
26
|
+
var _main = require("../../pm-plugins/main");
|
|
25
27
|
var _mentionPlaceholder = require("../../pm-plugins/mentionPlaceholder");
|
|
26
28
|
var _utils2 = require("../../pm-plugins/utils");
|
|
27
29
|
var _InviteItem = _interopRequireWildcard(require("../InviteItem"));
|
|
@@ -40,6 +42,9 @@ var isAgentUserType = function isAgentUserType(userType) {
|
|
|
40
42
|
var isAgentMention = function isAgentMention(mention) {
|
|
41
43
|
return isAgentUserType(mention.userType) || mention.appType === 'agent';
|
|
42
44
|
};
|
|
45
|
+
var isAgentTypeAheadItem = function isAgentTypeAheadItem(item) {
|
|
46
|
+
return item.mention ? isAgentMention(item.mention) : false;
|
|
47
|
+
};
|
|
43
48
|
var createInviteItem = function createInviteItem(_ref) {
|
|
44
49
|
var mentionProvider = _ref.mentionProvider,
|
|
45
50
|
onInviteItemMount = _ref.onInviteItemMount,
|
|
@@ -326,23 +331,31 @@ var createTypeAheadConfig = exports.createTypeAheadConfig = function createTypeA
|
|
|
326
331
|
},
|
|
327
332
|
getSections: function getSections(_ref9) {
|
|
328
333
|
var intl = _ref9.intl;
|
|
329
|
-
return [{
|
|
334
|
+
return [_objectSpread({
|
|
330
335
|
id: 'people',
|
|
331
336
|
title: intl.formatMessage(_messages.mentionMessages.typeAheadSectionPeople),
|
|
332
337
|
filter: function filter(item) {
|
|
333
|
-
|
|
334
|
-
return !isAgentUserType(((_item$mention = item.mention) === null || _item$mention === void 0 ? void 0 : _item$mention.userType) || '');
|
|
338
|
+
return !isAgentTypeAheadItem(item);
|
|
335
339
|
},
|
|
336
340
|
limit: (0, _expVal.expVal)('platform_editor_agent_mentions', 'isEnabled', false) ? 5 : 6
|
|
337
|
-
}, {
|
|
341
|
+
}, (0, _expVal.expVal)('platform_editor_agent_mentions', 'isEnabled', false) ? {
|
|
342
|
+
sectionTitleDisplay: {
|
|
343
|
+
showWhenQueryPresent: false,
|
|
344
|
+
showWhenOnlySection: true
|
|
345
|
+
}
|
|
346
|
+
} : {}), _objectSpread({
|
|
338
347
|
id: 'agents',
|
|
339
348
|
title: intl.formatMessage(_messages.mentionMessages.typeAheadSectionAgents),
|
|
340
349
|
filter: function filter(item) {
|
|
341
|
-
|
|
342
|
-
return isAgentUserType(((_item$mention2 = item.mention) === null || _item$mention2 === void 0 ? void 0 : _item$mention2.userType) || '');
|
|
350
|
+
return isAgentTypeAheadItem(item);
|
|
343
351
|
},
|
|
344
352
|
limit: (0, _expVal.expVal)('platform_editor_agent_mentions', 'isEnabled', false) ? 5 : undefined
|
|
345
|
-
}
|
|
353
|
+
}, (0, _expVal.expVal)('platform_editor_agent_mentions', 'isEnabled', false) ? {
|
|
354
|
+
sectionTitleDisplay: {
|
|
355
|
+
showWhenQueryPresent: false,
|
|
356
|
+
showWhenOnlySection: true
|
|
357
|
+
}
|
|
358
|
+
} : {})];
|
|
346
359
|
},
|
|
347
360
|
onOpen: function onOpen() {
|
|
348
361
|
firstQueryWithoutResults = null;
|
|
@@ -356,23 +369,23 @@ var createTypeAheadConfig = exports.createTypeAheadConfig = function createTypeA
|
|
|
356
369
|
var schema = state.schema;
|
|
357
370
|
var pluginState = (0, _utils2.getMentionPluginState)(state);
|
|
358
371
|
var mentionProvider = pluginState.mentionProvider;
|
|
359
|
-
var _item$
|
|
360
|
-
id = _item$
|
|
361
|
-
name = _item$
|
|
362
|
-
nickname = _item$
|
|
363
|
-
accessLevel = _item$
|
|
364
|
-
userType = _item$
|
|
365
|
-
isXProductUser = _item$
|
|
372
|
+
var _item$mention = item.mention,
|
|
373
|
+
id = _item$mention.id,
|
|
374
|
+
name = _item$mention.name,
|
|
375
|
+
nickname = _item$mention.nickname,
|
|
376
|
+
accessLevel = _item$mention.accessLevel,
|
|
377
|
+
userType = _item$mention.userType,
|
|
378
|
+
isXProductUser = _item$mention.isXProductUser;
|
|
366
379
|
var _ref1 = (_api$contextIdentifie3 = api === null || api === void 0 || (_api$contextIdentifie4 = api.contextIdentifier) === null || _api$contextIdentifie4 === void 0 ? void 0 : _api$contextIdentifie4.sharedState.currentState()) !== null && _api$contextIdentifie3 !== void 0 ? _api$contextIdentifie3 : {},
|
|
367
380
|
contextIdentifierProvider = _ref1.contextIdentifierProvider;
|
|
368
381
|
var mentionContext = _objectSpread(_objectSpread({}, contextIdentifierProvider), {}, {
|
|
369
382
|
sessionId: sessionId
|
|
370
383
|
});
|
|
371
384
|
var isAgentMentionsExperimentEnabled = (0, _expVal.expVal)('platform_editor_agent_mentions', 'isEnabled', false);
|
|
372
|
-
var
|
|
385
|
+
var isAgentMentionInsertion = isAgentMentionsExperimentEnabled && isAgentMention(item.mention);
|
|
373
386
|
// userType can be missing for provider-only agent mentions. Copy/paste cannot
|
|
374
387
|
// see appType, so persist APP only when there is no explicit userType.
|
|
375
|
-
var persistedUserType =
|
|
388
|
+
var persistedUserType = isAgentMentionInsertion && userType == null ? 'APP' : userType;
|
|
376
389
|
if (mentionProvider && !(0, _utils3.isInviteItem)(item.mention)) {
|
|
377
390
|
mentionProvider.recordMentionSelection(item.mention, mentionContext);
|
|
378
391
|
}
|
|
@@ -397,12 +410,12 @@ var createTypeAheadConfig = exports.createTypeAheadConfig = function createTypeA
|
|
|
397
410
|
// If query already includes @, use it as is
|
|
398
411
|
if (email && mentionProvider.showInlineInviteRecaptcha) {
|
|
399
412
|
mentionProvider.showInlineInviteRecaptcha(email);
|
|
400
|
-
var
|
|
401
|
-
|
|
413
|
+
var _tr = state.tr;
|
|
414
|
+
_tr.setMeta(_mentionPlaceholder.mentionPlaceholderPluginKey, {
|
|
402
415
|
action: _mentionPlaceholder.MENTION_PLACEHOLDER_ACTIONS.SHOW_PLACEHOLDER,
|
|
403
416
|
placeholder: "@".concat(query)
|
|
404
417
|
});
|
|
405
|
-
return
|
|
418
|
+
return _tr;
|
|
406
419
|
}
|
|
407
420
|
} else if (mentionProvider.onInviteItemClick) {
|
|
408
421
|
// Fallback to old behavior for backward compatibility
|
|
@@ -429,7 +442,7 @@ var createTypeAheadConfig = exports.createTypeAheadConfig = function createTypeA
|
|
|
429
442
|
localId: mentionLocalId,
|
|
430
443
|
method: 'typed',
|
|
431
444
|
type: 'added'
|
|
432
|
-
},
|
|
445
|
+
}, isAgentMentionInsertion ? {
|
|
433
446
|
shouldSuppressMentionNotification: true
|
|
434
447
|
} : {});
|
|
435
448
|
if (taskItemId) {
|
|
@@ -442,22 +455,22 @@ var createTypeAheadConfig = exports.createTypeAheadConfig = function createTypeA
|
|
|
442
455
|
}
|
|
443
456
|
fireEvent((0, _analytics.buildTypeAheadInsertedPayload)(pickerElapsedTime, stats.keyCount.arrowUp, stats.keyCount.arrowDown, sessionId, mode, item.mention, mentionLocalId, sourceListItem.map(function (x) {
|
|
444
457
|
return x.mention;
|
|
445
|
-
}), query, contextIdentifierProvider, taskListId, taskItemId));
|
|
458
|
+
}), query, contextIdentifierProvider, taskListId, taskItemId, isAgentMentionInsertion));
|
|
446
459
|
|
|
447
460
|
// eslint-disable-next-line @atlaskit/platform/prefer-crypto-random-uuid -- Use crypto.randomUUID instead
|
|
448
461
|
sessionId = (0, _uuid.default)();
|
|
449
462
|
if (mentionProvider && (0, _utils3.isTeamType)(userType)) {
|
|
450
463
|
return insert(buildNodesForTeamMention(schema, item.mention, mentionProvider, sanitizePrivateContent));
|
|
451
464
|
}
|
|
452
|
-
if (!
|
|
465
|
+
if (!isAgentMentionInsertion && isXProductUser && mentionProvider && mentionProvider.inviteXProductUser) {
|
|
453
466
|
mentionProvider.inviteXProductUser(id, name);
|
|
454
467
|
}
|
|
455
|
-
|
|
468
|
+
var tr = insert((0, _editorCommands.createSingleMentionFragment)({
|
|
456
469
|
mentionProvider: mentionProvider,
|
|
457
470
|
mentionInsertDisplayName: mentionInsertDisplayName,
|
|
458
471
|
tr: state.tr,
|
|
459
472
|
sanitizePrivateContent: sanitizePrivateContent,
|
|
460
|
-
suppressInviteXProductUser:
|
|
473
|
+
suppressInviteXProductUser: isAgentMentionInsertion
|
|
461
474
|
})({
|
|
462
475
|
name: name,
|
|
463
476
|
id: id,
|
|
@@ -467,6 +480,15 @@ var createTypeAheadConfig = exports.createTypeAheadConfig = function createTypeA
|
|
|
467
480
|
accessLevel: accessLevel,
|
|
468
481
|
isXProductUser: isXProductUser
|
|
469
482
|
}));
|
|
483
|
+
if (isAgentMentionInsertion) {
|
|
484
|
+
tr.setMeta(_key.mentionPluginKey, {
|
|
485
|
+
action: _main.ACTIONS.SET_PENDING_TYPED_AGENT_MENTION,
|
|
486
|
+
params: {
|
|
487
|
+
localId: mentionLocalId
|
|
488
|
+
}
|
|
489
|
+
});
|
|
490
|
+
}
|
|
491
|
+
return tr;
|
|
470
492
|
},
|
|
471
493
|
dismiss: function dismiss(_ref10) {
|
|
472
494
|
var editorState = _ref10.editorState,
|
|
@@ -10,14 +10,17 @@ import { MENTION_PROVIDER_REJECTED, MENTION_PROVIDER_UNDEFINED } from '../types'
|
|
|
10
10
|
import { mentionPluginKey } from './key';
|
|
11
11
|
import { canMentionBeCreatedInRange } from './utils';
|
|
12
12
|
export const ACTIONS = {
|
|
13
|
+
COMMIT_PENDING_TYPED_AGENT_MENTION: 'COMMIT_PENDING_TYPED_AGENT_MENTION',
|
|
14
|
+
SET_PENDING_TYPED_AGENT_MENTION: 'SET_PENDING_TYPED_AGENT_MENTION',
|
|
13
15
|
SET_PROVIDER: 'SET_PROVIDER'
|
|
14
16
|
};
|
|
15
17
|
|
|
16
18
|
// 'AGENT' is not in the ADF schema UserType enum but is used at runtime.
|
|
17
19
|
const AGENT_USER_TYPES = new Set(['APP', 'AGENT']);
|
|
18
20
|
const AI_STREAMING_TRANSFORMATION_META_KEY = 'isAIStreamingTransformation';
|
|
21
|
+
const AGENT_MENTION_INACTIVITY_MS = 3000;
|
|
19
22
|
const PACKAGE_NAME = "@atlaskit/editor-plugin-mentions";
|
|
20
|
-
const PACKAGE_VERSION = "
|
|
23
|
+
const PACKAGE_VERSION = "14.0.0";
|
|
21
24
|
const setProvider = provider => (state, dispatch) => {
|
|
22
25
|
if (dispatch) {
|
|
23
26
|
dispatch(state.tr.setMeta(mentionPluginKey, {
|
|
@@ -29,6 +32,89 @@ const setProvider = provider => (state, dispatch) => {
|
|
|
29
32
|
}
|
|
30
33
|
return true;
|
|
31
34
|
};
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Returns true when a transaction represents a local user document edit that
|
|
38
|
+
* should restart pending agent-mention inactivity tracking.
|
|
39
|
+
*
|
|
40
|
+
* Remote/collab updates, replace-document transactions, AI streaming transforms,
|
|
41
|
+
* selection-only movements, and metadata-only transactions are intentionally ignored.
|
|
42
|
+
*/
|
|
43
|
+
const isQualifyingLocalUserDocChange = tr => {
|
|
44
|
+
const isAIStreaming = Boolean(tr.getMeta(AI_STREAMING_TRANSFORMATION_META_KEY));
|
|
45
|
+
return tr.docChanged && !tr.getMeta('isRemote') && !tr.getMeta('replaceDocument') && !isAIStreaming;
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Reads agent-mention details from a known document position without traversing
|
|
50
|
+
* the document. Callers pass a matcher so mapped positions are only accepted
|
|
51
|
+
* when they still point at the same pending/tracked mention.
|
|
52
|
+
*/
|
|
53
|
+
const getAgentMentionDetailsAtPos = (state, pos, matchesMention) => {
|
|
54
|
+
var _parentNode$type$name;
|
|
55
|
+
if (pos < 0 || pos > state.doc.content.size) {
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
const node = state.doc.nodeAt(pos);
|
|
59
|
+
const mentionSchema = state.schema.nodes.mention;
|
|
60
|
+
if ((node === null || node === void 0 ? void 0 : node.type) !== mentionSchema || !AGENT_USER_TYPES.has(node.attrs.userType) || !matchesMention(node.attrs) || !node.attrs.id) {
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
const $mentionPos = state.doc.resolve(pos);
|
|
64
|
+
const parentNode = $mentionPos.node($mentionPos.depth);
|
|
65
|
+
return {
|
|
66
|
+
id: node.attrs.id,
|
|
67
|
+
context: parentNode.textContent.trim() || null,
|
|
68
|
+
nodeSize: node.nodeSize,
|
|
69
|
+
parentNodeType: (_parentNode$type$name = parentNode.type.name) !== null && _parentNode$type$name !== void 0 ? _parentNode$type$name : null,
|
|
70
|
+
pos
|
|
71
|
+
};
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Finds an agent mention that survived a document change when the changed-range
|
|
76
|
+
* scan did not find one. Prefers the previously tracked mention ID when present;
|
|
77
|
+
* otherwise returns a surviving agent mention using the existing traversal order.
|
|
78
|
+
*/
|
|
79
|
+
const getSurvivingAgentMentionDetails = (state, preferredId) => {
|
|
80
|
+
const mentionSchema = state.schema.nodes.mention;
|
|
81
|
+
let result = null;
|
|
82
|
+
state.doc.descendants((node, pos) => {
|
|
83
|
+
var _result, _result2;
|
|
84
|
+
if (((_result = result) === null || _result === void 0 ? void 0 : _result.id) === preferredId) {
|
|
85
|
+
return false;
|
|
86
|
+
}
|
|
87
|
+
if (node.type !== mentionSchema || !AGENT_USER_TYPES.has(node.attrs.userType) || !node.attrs.id) {
|
|
88
|
+
return true;
|
|
89
|
+
}
|
|
90
|
+
result = getAgentMentionDetailsAtPos(state, pos, attrs => attrs.id === node.attrs.id);
|
|
91
|
+
return ((_result2 = result) === null || _result2 === void 0 ? void 0 : _result2.id) !== preferredId;
|
|
92
|
+
});
|
|
93
|
+
return result;
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Maps a pending typed agent mention through a document-changing transaction and
|
|
98
|
+
* returns the updated pending state. If the mapped position was deleted or no
|
|
99
|
+
* longer points at the same local mention, the pending mention is cleared.
|
|
100
|
+
*/
|
|
101
|
+
const getPendingTypedAgentMentionAfterDocChange = (state, tr, pendingTypedAgentMention, {
|
|
102
|
+
resetTimer
|
|
103
|
+
}) => {
|
|
104
|
+
const mappedPos = tr.mapping.mapResult(pendingTypedAgentMention.pos, 1);
|
|
105
|
+
const resetCount = resetTimer ? pendingTypedAgentMention.resetCount + 1 : pendingTypedAgentMention.resetCount;
|
|
106
|
+
if (mappedPos.deleted) {
|
|
107
|
+
return null;
|
|
108
|
+
}
|
|
109
|
+
const pendingMentionDetails = getAgentMentionDetailsAtPos(state, mappedPos.pos, attrs => attrs.localId === pendingTypedAgentMention.localId);
|
|
110
|
+
return pendingMentionDetails ? {
|
|
111
|
+
id: pendingMentionDetails.id,
|
|
112
|
+
localId: pendingTypedAgentMention.localId,
|
|
113
|
+
nodeSize: pendingMentionDetails.nodeSize,
|
|
114
|
+
pos: pendingMentionDetails.pos,
|
|
115
|
+
resetCount
|
|
116
|
+
} : null;
|
|
117
|
+
};
|
|
32
118
|
export function createMentionPlugin({
|
|
33
119
|
pmPluginFactoryParams,
|
|
34
120
|
fireEvent,
|
|
@@ -68,32 +154,71 @@ export function createMentionPlugin({
|
|
|
68
154
|
action: null,
|
|
69
155
|
params: null
|
|
70
156
|
};
|
|
71
|
-
let
|
|
157
|
+
let hasPublicPluginStateChanged = false;
|
|
72
158
|
let newPluginState = pluginState;
|
|
159
|
+
const isAgentMentionsExperimentEnabled = editorExperiment('platform_editor_agent_mentions', true);
|
|
73
160
|
const hasPositionChanged = oldState.selection.from !== newState.selection.from || oldState.selection.to !== newState.selection.to;
|
|
74
161
|
if (tr.docChanged || tr.selectionSet && hasPositionChanged) {
|
|
75
162
|
newPluginState = {
|
|
76
163
|
...pluginState,
|
|
77
164
|
canInsertMention: canMentionBeCreatedInRange(newState.selection.from, newState.selection.to)(newState)
|
|
78
165
|
};
|
|
79
|
-
|
|
166
|
+
hasPublicPluginStateChanged = true;
|
|
80
167
|
}
|
|
81
168
|
switch (action) {
|
|
169
|
+
case ACTIONS.COMMIT_PENDING_TYPED_AGENT_MENTION:
|
|
170
|
+
{
|
|
171
|
+
var _newPluginState$lastA;
|
|
172
|
+
const pendingTypedAgentMention = newPluginState.pendingTypedAgentMention;
|
|
173
|
+
// Ignore stale timer callbacks. The localId and resetCount must still match the
|
|
174
|
+
// current pending mention so older timers cannot publish after later user edits.
|
|
175
|
+
if (!isAgentMentionsExperimentEnabled || !pendingTypedAgentMention || pendingTypedAgentMention.localId !== (params === null || params === void 0 ? void 0 : params.localId) || pendingTypedAgentMention.resetCount !== (params === null || params === void 0 ? void 0 : params.resetCount)) {
|
|
176
|
+
break;
|
|
177
|
+
}
|
|
178
|
+
const pendingMentionDetails = getAgentMentionDetailsAtPos(newState, pendingTypedAgentMention.pos, attrs => attrs.localId === pendingTypedAgentMention.localId);
|
|
179
|
+
if (!pendingMentionDetails) {
|
|
180
|
+
newPluginState = {
|
|
181
|
+
...newPluginState,
|
|
182
|
+
pendingTypedAgentMention: null
|
|
183
|
+
};
|
|
184
|
+
break;
|
|
185
|
+
}
|
|
186
|
+
newPluginState = {
|
|
187
|
+
...newPluginState,
|
|
188
|
+
pendingTypedAgentMention: null,
|
|
189
|
+
lastInsertedAgentMentionId: pendingMentionDetails.id,
|
|
190
|
+
lastInsertedAgentMentionContext: pendingMentionDetails.context,
|
|
191
|
+
lastInsertedAgentMentionParentNodeType: pendingMentionDetails.parentNodeType,
|
|
192
|
+
lastAgentMentionInsertionCount: ((_newPluginState$lastA = newPluginState.lastAgentMentionInsertionCount) !== null && _newPluginState$lastA !== void 0 ? _newPluginState$lastA : 0) + 1
|
|
193
|
+
};
|
|
194
|
+
hasPublicPluginStateChanged = true;
|
|
195
|
+
break;
|
|
196
|
+
}
|
|
82
197
|
case ACTIONS.SET_PROVIDER:
|
|
83
198
|
newPluginState = {
|
|
84
199
|
...newPluginState,
|
|
85
200
|
mentionProvider: params.provider
|
|
86
201
|
};
|
|
87
|
-
|
|
202
|
+
hasPublicPluginStateChanged = true;
|
|
88
203
|
break;
|
|
89
204
|
}
|
|
90
205
|
|
|
91
206
|
// When the agent mentions experiment is off, dispatch immediately (original behaviour).
|
|
92
207
|
// When it's on, defer dispatch to after the agent tracking block below so that
|
|
93
208
|
// agent-mention state changes are included in the notification.
|
|
94
|
-
if (
|
|
209
|
+
if (hasPublicPluginStateChanged && !isAgentMentionsExperimentEnabled) {
|
|
95
210
|
pmPluginFactoryParams.dispatch(mentionPluginKey, newPluginState);
|
|
96
211
|
}
|
|
212
|
+
if (isAgentMentionsExperimentEnabled && tr.docChanged && tr.getMeta('replaceDocument')) {
|
|
213
|
+
newPluginState = {
|
|
214
|
+
...newPluginState,
|
|
215
|
+
pendingTypedAgentMention: null,
|
|
216
|
+
lastInsertedAgentMentionId: null,
|
|
217
|
+
lastInsertedAgentMentionContext: null,
|
|
218
|
+
lastInsertedAgentMentionParentNodeType: null
|
|
219
|
+
};
|
|
220
|
+
hasPublicPluginStateChanged = true;
|
|
221
|
+
}
|
|
97
222
|
if (options !== null && options !== void 0 && options.handleMentionsChanged && tr.docChanged) {
|
|
98
223
|
var _insm$session, _insm$session2;
|
|
99
224
|
(_insm$session = insm.session) === null || _insm$session === void 0 ? void 0 : _insm$session.startFeature('mentionDeletionDetection');
|
|
@@ -152,7 +277,7 @@ export function createMentionPlugin({
|
|
|
152
277
|
(_insm$session2 = insm.session) === null || _insm$session2 === void 0 ? void 0 : _insm$session2.endFeature('mentionDeletionDetection');
|
|
153
278
|
}
|
|
154
279
|
const isAIStreaming = Boolean(tr.getMeta(AI_STREAMING_TRANSFORMATION_META_KEY));
|
|
155
|
-
if (tr.docChanged && !tr.getMeta('replaceDocument') && !isAIStreaming &&
|
|
280
|
+
if (tr.docChanged && !tr.getMeta('replaceDocument') && !isAIStreaming && isAgentMentionsExperimentEnabled) {
|
|
156
281
|
const mentionSchema = newState.schema.nodes.mention;
|
|
157
282
|
const newDocRanges = [];
|
|
158
283
|
const oldDocRanges = [];
|
|
@@ -198,28 +323,36 @@ export function createMentionPlugin({
|
|
|
198
323
|
oldDocRanges.push(...stepOldRanges);
|
|
199
324
|
}
|
|
200
325
|
});
|
|
201
|
-
|
|
202
|
-
|
|
326
|
+
const shouldResolveAgentMentionState = stepsTouchMentions || Boolean(newPluginState.lastInsertedAgentMentionId);
|
|
327
|
+
if (shouldResolveAgentMentionState) {
|
|
328
|
+
var _newPluginState$lastA2, _newPluginState$lastI, _newPluginState$lastI2, _newPluginState$lastI3;
|
|
203
329
|
let agentMentionId = null;
|
|
204
330
|
let agentMentionContext = null;
|
|
205
331
|
let agentMentionParentNodeType = null;
|
|
206
332
|
let newCount = 0;
|
|
207
333
|
let oldAgentMentionId = null;
|
|
208
334
|
let oldCount = 0;
|
|
335
|
+
const pendingTypedAgentMentionDetails = {};
|
|
209
336
|
if (stepsTouchMentions) {
|
|
210
337
|
for (const [from, to] of newDocRanges) {
|
|
211
338
|
const clampedTo = Math.min(to, newState.doc.content.size);
|
|
212
339
|
if (from >= clampedTo) continue;
|
|
213
|
-
newState.doc.nodesBetween(from, clampedTo, (node,
|
|
340
|
+
newState.doc.nodesBetween(from, clampedTo, (node, pos) => {
|
|
214
341
|
if (node.type !== mentionSchema || !AGENT_USER_TYPES.has(node.attrs.userType)) {
|
|
215
342
|
return true;
|
|
216
343
|
}
|
|
217
344
|
newCount++;
|
|
345
|
+
if (pendingTypedAgentMentionDetails.current === undefined && action === ACTIONS.SET_PENDING_TYPED_AGENT_MENTION && node.attrs.localId === (params === null || params === void 0 ? void 0 : params.localId)) {
|
|
346
|
+
var _getAgentMentionDetai;
|
|
347
|
+
pendingTypedAgentMentionDetails.current = (_getAgentMentionDetai = getAgentMentionDetailsAtPos(newState, pos, attrs => attrs.localId === params.localId)) !== null && _getAgentMentionDetai !== void 0 ? _getAgentMentionDetai : undefined;
|
|
348
|
+
}
|
|
218
349
|
if (agentMentionId === null && node.attrs.id) {
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
350
|
+
const agentMentionDetails = getAgentMentionDetailsAtPos(newState, pos, attrs => attrs.id === node.attrs.id);
|
|
351
|
+
if (agentMentionDetails) {
|
|
352
|
+
agentMentionId = agentMentionDetails.id;
|
|
353
|
+
agentMentionContext = agentMentionDetails.context;
|
|
354
|
+
agentMentionParentNodeType = agentMentionDetails.parentNodeType;
|
|
355
|
+
}
|
|
223
356
|
}
|
|
224
357
|
return true;
|
|
225
358
|
});
|
|
@@ -243,33 +376,46 @@ export function createMentionPlugin({
|
|
|
243
376
|
// When a deletion collapses the new-doc range to a zero-width point, or when
|
|
244
377
|
// the doc changed but no step covered the tracked mention, the new-doc scan
|
|
245
378
|
// above finds nothing. Check whether any agent mention survived in the document.
|
|
246
|
-
let
|
|
379
|
+
let resolvedFromFullDocFallback = false;
|
|
247
380
|
if (agentMentionId === null && newPluginState.lastInsertedAgentMentionId) {
|
|
248
|
-
const
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
if (node.type === mentionSchema && AGENT_USER_TYPES.has(node.attrs.userType)) {
|
|
255
|
-
var _parent$type$name2;
|
|
256
|
-
// Prefer the previously tracked ID; otherwise keep the first found.
|
|
257
|
-
survivorId = node.attrs.id;
|
|
258
|
-
survivorParentNodeType = (_parent$type$name2 = parent === null || parent === void 0 ? void 0 : parent.type.name) !== null && _parent$type$name2 !== void 0 ? _parent$type$name2 : null;
|
|
259
|
-
survivorContext = (parent === null || parent === void 0 ? void 0 : parent.textContent.trim()) || null;
|
|
260
|
-
}
|
|
261
|
-
return survivorId !== prevId;
|
|
262
|
-
});
|
|
263
|
-
if (survivorId !== null) {
|
|
264
|
-
agentMentionId = survivorId;
|
|
265
|
-
agentMentionContext = survivorContext;
|
|
266
|
-
agentMentionParentNodeType = survivorParentNodeType;
|
|
267
|
-
resolvedFromSurvivor = true;
|
|
381
|
+
const survivorDetails = getSurvivingAgentMentionDetails(newState, newPluginState.lastInsertedAgentMentionId);
|
|
382
|
+
if (survivorDetails) {
|
|
383
|
+
agentMentionId = survivorDetails.id;
|
|
384
|
+
agentMentionContext = survivorDetails.context;
|
|
385
|
+
agentMentionParentNodeType = survivorDetails.parentNodeType;
|
|
386
|
+
resolvedFromFullDocFallback = true;
|
|
268
387
|
}
|
|
269
388
|
}
|
|
270
|
-
const isNewInsertion = agentMentionId !== null && !
|
|
271
|
-
const
|
|
272
|
-
|
|
389
|
+
const isNewInsertion = agentMentionId !== null && !resolvedFromFullDocFallback && (oldAgentMentionId !== agentMentionId || newCount > oldCount);
|
|
390
|
+
const isPendingTypedAgentMentionInsertion = isNewInsertion && action === ACTIONS.SET_PENDING_TYPED_AGENT_MENTION && typeof (params === null || params === void 0 ? void 0 : params.localId) === 'string';
|
|
391
|
+
const newInsertionCount = isNewInsertion ? ((_newPluginState$lastA2 = newPluginState.lastAgentMentionInsertionCount) !== null && _newPluginState$lastA2 !== void 0 ? _newPluginState$lastA2 : 0) + 1 : undefined;
|
|
392
|
+
if (isPendingTypedAgentMentionInsertion && pendingTypedAgentMentionDetails.current) {
|
|
393
|
+
const pendingTypedAgentMentionLocalId = params === null || params === void 0 ? void 0 : params.localId;
|
|
394
|
+
newPluginState = {
|
|
395
|
+
...newPluginState,
|
|
396
|
+
pendingTypedAgentMention: {
|
|
397
|
+
id: pendingTypedAgentMentionDetails.current.id,
|
|
398
|
+
localId: pendingTypedAgentMentionLocalId,
|
|
399
|
+
nodeSize: pendingTypedAgentMentionDetails.current.nodeSize,
|
|
400
|
+
pos: pendingTypedAgentMentionDetails.current.pos,
|
|
401
|
+
resetCount: 1
|
|
402
|
+
}
|
|
403
|
+
};
|
|
404
|
+
} else if (isPendingTypedAgentMentionInsertion) {
|
|
405
|
+
// Fallback: if the localId-specific scan missed the typed mention,
|
|
406
|
+
// publish immediately so the insertion is not dropped.
|
|
407
|
+
newPluginState = {
|
|
408
|
+
...newPluginState,
|
|
409
|
+
pendingTypedAgentMention: null,
|
|
410
|
+
lastInsertedAgentMentionId: agentMentionId,
|
|
411
|
+
lastInsertedAgentMentionContext: agentMentionContext,
|
|
412
|
+
lastInsertedAgentMentionParentNodeType: agentMentionParentNodeType,
|
|
413
|
+
...(newInsertionCount !== undefined ? {
|
|
414
|
+
lastAgentMentionInsertionCount: newInsertionCount
|
|
415
|
+
} : {})
|
|
416
|
+
};
|
|
417
|
+
hasPublicPluginStateChanged = true;
|
|
418
|
+
} else if (agentMentionId !== ((_newPluginState$lastI = newPluginState.lastInsertedAgentMentionId) !== null && _newPluginState$lastI !== void 0 ? _newPluginState$lastI : null) || agentMentionContext !== ((_newPluginState$lastI2 = newPluginState.lastInsertedAgentMentionContext) !== null && _newPluginState$lastI2 !== void 0 ? _newPluginState$lastI2 : null) || agentMentionParentNodeType !== ((_newPluginState$lastI3 = newPluginState.lastInsertedAgentMentionParentNodeType) !== null && _newPluginState$lastI3 !== void 0 ? _newPluginState$lastI3 : null) || newInsertionCount !== undefined) {
|
|
273
419
|
newPluginState = {
|
|
274
420
|
...newPluginState,
|
|
275
421
|
lastInsertedAgentMentionId: agentMentionId,
|
|
@@ -279,11 +425,19 @@ export function createMentionPlugin({
|
|
|
279
425
|
lastAgentMentionInsertionCount: newInsertionCount
|
|
280
426
|
} : {})
|
|
281
427
|
};
|
|
282
|
-
|
|
428
|
+
hasPublicPluginStateChanged = true;
|
|
283
429
|
}
|
|
284
430
|
}
|
|
285
431
|
}
|
|
286
|
-
if (
|
|
432
|
+
if (isAgentMentionsExperimentEnabled && newPluginState.pendingTypedAgentMention && action !== ACTIONS.SET_PENDING_TYPED_AGENT_MENTION && action !== ACTIONS.COMMIT_PENDING_TYPED_AGENT_MENTION && tr.docChanged) {
|
|
433
|
+
newPluginState = {
|
|
434
|
+
...newPluginState,
|
|
435
|
+
pendingTypedAgentMention: getPendingTypedAgentMentionAfterDocChange(newState, tr, newPluginState.pendingTypedAgentMention, {
|
|
436
|
+
resetTimer: isQualifyingLocalUserDocChange(tr)
|
|
437
|
+
})
|
|
438
|
+
};
|
|
439
|
+
}
|
|
440
|
+
if (hasPublicPluginStateChanged && isAgentMentionsExperimentEnabled) {
|
|
287
441
|
pmPluginFactoryParams.dispatch(mentionPluginKey, newPluginState);
|
|
288
442
|
}
|
|
289
443
|
return newPluginState;
|
|
@@ -301,6 +455,47 @@ export function createMentionPlugin({
|
|
|
301
455
|
}
|
|
302
456
|
},
|
|
303
457
|
view(editorView) {
|
|
458
|
+
const isAgentMentionsEnabled = editorExperiment('platform_editor_agent_mentions', true);
|
|
459
|
+
let pendingTypedAgentMentionTimer;
|
|
460
|
+
let pendingTypedAgentMentionTimerKey = null;
|
|
461
|
+
const clearPendingTypedAgentMentionTimer = () => {
|
|
462
|
+
if (pendingTypedAgentMentionTimer) {
|
|
463
|
+
clearTimeout(pendingTypedAgentMentionTimer);
|
|
464
|
+
pendingTypedAgentMentionTimer = undefined;
|
|
465
|
+
}
|
|
466
|
+
pendingTypedAgentMentionTimerKey = null;
|
|
467
|
+
};
|
|
468
|
+
const schedulePendingTypedAgentMentionTimer = mentionPluginState => {
|
|
469
|
+
if (!isAgentMentionsEnabled) {
|
|
470
|
+
clearPendingTypedAgentMentionTimer();
|
|
471
|
+
return;
|
|
472
|
+
}
|
|
473
|
+
const pendingTypedAgentMention = mentionPluginState === null || mentionPluginState === void 0 ? void 0 : mentionPluginState.pendingTypedAgentMention;
|
|
474
|
+
if (!pendingTypedAgentMention) {
|
|
475
|
+
clearPendingTypedAgentMentionTimer();
|
|
476
|
+
return;
|
|
477
|
+
}
|
|
478
|
+
const timerKey = `${pendingTypedAgentMention.localId}:${pendingTypedAgentMention.resetCount}`;
|
|
479
|
+
if (timerKey === pendingTypedAgentMentionTimerKey) {
|
|
480
|
+
return;
|
|
481
|
+
}
|
|
482
|
+
clearPendingTypedAgentMentionTimer();
|
|
483
|
+
pendingTypedAgentMentionTimerKey = timerKey;
|
|
484
|
+
pendingTypedAgentMentionTimer = setTimeout(() => {
|
|
485
|
+
var _mentionPluginKey$get;
|
|
486
|
+
const latestPendingTypedAgentMention = (_mentionPluginKey$get = mentionPluginKey.getState(editorView.state)) === null || _mentionPluginKey$get === void 0 ? void 0 : _mentionPluginKey$get.pendingTypedAgentMention;
|
|
487
|
+
if (!latestPendingTypedAgentMention || latestPendingTypedAgentMention.localId !== pendingTypedAgentMention.localId || latestPendingTypedAgentMention.resetCount !== pendingTypedAgentMention.resetCount) {
|
|
488
|
+
return;
|
|
489
|
+
}
|
|
490
|
+
editorView.dispatch(editorView.state.tr.setMeta(mentionPluginKey, {
|
|
491
|
+
action: ACTIONS.COMMIT_PENDING_TYPED_AGENT_MENTION,
|
|
492
|
+
params: {
|
|
493
|
+
localId: pendingTypedAgentMention.localId,
|
|
494
|
+
resetCount: pendingTypedAgentMention.resetCount
|
|
495
|
+
}
|
|
496
|
+
}));
|
|
497
|
+
}, AGENT_MENTION_INACTIVITY_MS);
|
|
498
|
+
};
|
|
304
499
|
const providerHandler = (name, providerPromise) => {
|
|
305
500
|
switch (name) {
|
|
306
501
|
case 'mentionProvider':
|
|
@@ -346,7 +541,15 @@ export function createMentionPlugin({
|
|
|
346
541
|
pmPluginFactoryParams.providerFactory.subscribe('mentionProvider', providerHandler);
|
|
347
542
|
}
|
|
348
543
|
return {
|
|
544
|
+
update(view, prevState) {
|
|
545
|
+
const mentionPluginState = mentionPluginKey.getState(view.state);
|
|
546
|
+
if (mentionPluginState === mentionPluginKey.getState(prevState)) {
|
|
547
|
+
return;
|
|
548
|
+
}
|
|
549
|
+
schedulePendingTypedAgentMentionTimer(mentionPluginState);
|
|
550
|
+
},
|
|
349
551
|
destroy() {
|
|
552
|
+
clearPendingTypedAgentMentionTimer();
|
|
350
553
|
if (pmPluginFactoryParams.providerFactory) {
|
|
351
554
|
pmPluginFactoryParams.providerFactory.unsubscribe('mentionProvider', providerHandler);
|
|
352
555
|
}
|
|
@@ -97,7 +97,7 @@ export const buildTypeAheadInviteItemClickedPayload = (duration, upKeyCount, dow
|
|
|
97
97
|
}
|
|
98
98
|
};
|
|
99
99
|
};
|
|
100
|
-
export const buildTypeAheadInsertedPayload = (duration, upKeyCount, downKeyCount, sessionId, insertType, mention, mentionLocalId, mentionList, query, contextIdentifierProvider, taskListId, taskItemId) => {
|
|
100
|
+
export const buildTypeAheadInsertedPayload = (duration, upKeyCount, downKeyCount, sessionId, insertType, mention, mentionLocalId, mentionList, query, contextIdentifierProvider, taskListId, taskItemId, isAgent) => {
|
|
101
101
|
const {
|
|
102
102
|
queryLength,
|
|
103
103
|
spaceInQuery
|
|
@@ -133,6 +133,9 @@ export const buildTypeAheadInsertedPayload = (duration, upKeyCount, downKeyCount
|
|
|
133
133
|
downKeyCount,
|
|
134
134
|
memberCount: isTeamType(mention.userType) && mention.context ? mention.context.memberCount : null,
|
|
135
135
|
includesYou: isTeamType(mention.userType) && mention.context ? mention.context.includesYou : null,
|
|
136
|
+
...(isAgent ? {
|
|
137
|
+
isAgent
|
|
138
|
+
} : {}),
|
|
136
139
|
taskListId,
|
|
137
140
|
taskItemId,
|
|
138
141
|
localId: mentionLocalId,
|