@atlaskit/editor-plugin-mentions 14.0.0 → 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 +11 -0
- package/dist/cjs/pm-plugins/main.js +252 -47
- package/dist/cjs/ui/type-ahead/index.js +21 -10
- package/dist/es2019/pm-plugins/main.js +242 -39
- package/dist/es2019/ui/type-ahead/index.js +18 -7
- package/dist/esm/pm-plugins/main.js +252 -47
- package/dist/esm/ui/type-ahead/index.js +21 -10
- package/dist/types/pm-plugins/main.d.ts +2 -0
- package/dist/types/types/index.d.ts +24 -0
- package/package.json +3 -3
|
@@ -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
|
}
|
|
@@ -12,6 +12,8 @@ import { fg } from '@atlaskit/platform-feature-flags';
|
|
|
12
12
|
import { editorExperiment } from '@atlaskit/tmp-editor-statsig/experiments';
|
|
13
13
|
import { expVal } from '@atlaskit/tmp-editor-statsig/expVal';
|
|
14
14
|
import { createSingleMentionFragment } from '../../editor-commands';
|
|
15
|
+
import { mentionPluginKey } from '../../pm-plugins/key';
|
|
16
|
+
import { ACTIONS } from '../../pm-plugins/main';
|
|
15
17
|
import { mentionPlaceholderPluginKey, MENTION_PLACEHOLDER_ACTIONS } from '../../pm-plugins/mentionPlaceholder';
|
|
16
18
|
import { getMentionPluginState } from '../../pm-plugins/utils';
|
|
17
19
|
import InviteItem, { INVITE_ITEM_DESCRIPTION } from '../InviteItem';
|
|
@@ -362,10 +364,10 @@ export const createTypeAheadConfig = ({
|
|
|
362
364
|
sessionId
|
|
363
365
|
};
|
|
364
366
|
const isAgentMentionsExperimentEnabled = expVal('platform_editor_agent_mentions', 'isEnabled', false);
|
|
365
|
-
const
|
|
367
|
+
const isAgentMentionInsertion = isAgentMentionsExperimentEnabled && isAgentMention(item.mention);
|
|
366
368
|
// userType can be missing for provider-only agent mentions. Copy/paste cannot
|
|
367
369
|
// see appType, so persist APP only when there is no explicit userType.
|
|
368
|
-
const persistedUserType =
|
|
370
|
+
const persistedUserType = isAgentMentionInsertion && userType == null ? 'APP' : userType;
|
|
369
371
|
if (mentionProvider && !isInviteItem(item.mention)) {
|
|
370
372
|
mentionProvider.recordMentionSelection(item.mention, mentionContext);
|
|
371
373
|
}
|
|
@@ -424,7 +426,7 @@ export const createTypeAheadConfig = ({
|
|
|
424
426
|
localId: mentionLocalId,
|
|
425
427
|
method: 'typed',
|
|
426
428
|
type: 'added',
|
|
427
|
-
...(
|
|
429
|
+
...(isAgentMentionInsertion ? {
|
|
428
430
|
shouldSuppressMentionNotification: true
|
|
429
431
|
} : {})
|
|
430
432
|
};
|
|
@@ -437,22 +439,22 @@ export const createTypeAheadConfig = ({
|
|
|
437
439
|
handleMentionsChanged([mentionChange]);
|
|
438
440
|
}
|
|
439
441
|
}
|
|
440
|
-
fireEvent(buildTypeAheadInsertedPayload(pickerElapsedTime, stats.keyCount.arrowUp, stats.keyCount.arrowDown, sessionId, mode, item.mention, mentionLocalId, sourceListItem.map(x => x.mention), query, contextIdentifierProvider, taskListId, taskItemId,
|
|
442
|
+
fireEvent(buildTypeAheadInsertedPayload(pickerElapsedTime, stats.keyCount.arrowUp, stats.keyCount.arrowDown, sessionId, mode, item.mention, mentionLocalId, sourceListItem.map(x => x.mention), query, contextIdentifierProvider, taskListId, taskItemId, isAgentMentionInsertion));
|
|
441
443
|
|
|
442
444
|
// eslint-disable-next-line @atlaskit/platform/prefer-crypto-random-uuid -- Use crypto.randomUUID instead
|
|
443
445
|
sessionId = uuid();
|
|
444
446
|
if (mentionProvider && isTeamType(userType)) {
|
|
445
447
|
return insert(buildNodesForTeamMention(schema, item.mention, mentionProvider, sanitizePrivateContent));
|
|
446
448
|
}
|
|
447
|
-
if (!
|
|
449
|
+
if (!isAgentMentionInsertion && isXProductUser && mentionProvider && mentionProvider.inviteXProductUser) {
|
|
448
450
|
mentionProvider.inviteXProductUser(id, name);
|
|
449
451
|
}
|
|
450
|
-
|
|
452
|
+
const tr = insert(createSingleMentionFragment({
|
|
451
453
|
mentionProvider,
|
|
452
454
|
mentionInsertDisplayName,
|
|
453
455
|
tr: state.tr,
|
|
454
456
|
sanitizePrivateContent,
|
|
455
|
-
suppressInviteXProductUser:
|
|
457
|
+
suppressInviteXProductUser: isAgentMentionInsertion
|
|
456
458
|
})({
|
|
457
459
|
name,
|
|
458
460
|
id,
|
|
@@ -462,6 +464,15 @@ export const createTypeAheadConfig = ({
|
|
|
462
464
|
accessLevel,
|
|
463
465
|
isXProductUser
|
|
464
466
|
}));
|
|
467
|
+
if (isAgentMentionInsertion) {
|
|
468
|
+
tr.setMeta(mentionPluginKey, {
|
|
469
|
+
action: ACTIONS.SET_PENDING_TYPED_AGENT_MENTION,
|
|
470
|
+
params: {
|
|
471
|
+
localId: mentionLocalId
|
|
472
|
+
}
|
|
473
|
+
});
|
|
474
|
+
}
|
|
475
|
+
return tr;
|
|
465
476
|
},
|
|
466
477
|
dismiss({
|
|
467
478
|
editorState,
|