@atlaskit/editor-plugin-collab-edit 13.1.3 → 13.3.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 +57 -0
- package/dist/cjs/pm-plugins/actions.js +50 -14
- package/dist/cjs/pm-plugins/analytics.js +26 -1
- package/dist/cjs/pm-plugins/events/handlers.js +1 -1
- package/dist/cjs/pm-plugins/main/agent-shimmer-decorations.js +56 -17
- package/dist/cjs/pm-plugins/main/agent-shimmer-ranges.js +46 -27
- package/dist/cjs/pm-plugins/main/plugin-state.js +2 -1
- package/dist/es2019/pm-plugins/actions.js +49 -15
- package/dist/es2019/pm-plugins/analytics.js +23 -0
- package/dist/es2019/pm-plugins/events/handlers.js +1 -1
- package/dist/es2019/pm-plugins/main/agent-shimmer-decorations.js +52 -16
- package/dist/es2019/pm-plugins/main/agent-shimmer-ranges.js +42 -23
- package/dist/es2019/pm-plugins/main/plugin-state.js +3 -2
- package/dist/esm/pm-plugins/actions.js +51 -15
- package/dist/esm/pm-plugins/analytics.js +24 -0
- package/dist/esm/pm-plugins/events/handlers.js +1 -1
- package/dist/esm/pm-plugins/main/agent-shimmer-decorations.js +55 -16
- package/dist/esm/pm-plugins/main/agent-shimmer-ranges.js +46 -27
- package/dist/esm/pm-plugins/main/plugin-state.js +3 -2
- package/dist/types/pm-plugins/actions.d.ts +2 -2
- package/dist/types/pm-plugins/analytics.d.ts +9 -1
- package/dist/types/pm-plugins/main/agent-shimmer-decorations.d.ts +15 -4
- package/dist/types/pm-plugins/main/agent-shimmer-ranges.d.ts +2 -1
- package/package.json +12 -12
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,62 @@
|
|
|
1
1
|
# @atlaskit/editor-plugin-collab-edit
|
|
2
2
|
|
|
3
|
+
## 13.3.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [`51c33ef5349b6`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/51c33ef5349b6) -
|
|
8
|
+
Enable compatibility with React 19.2.0
|
|
9
|
+
|
|
10
|
+
### Patch Changes
|
|
11
|
+
|
|
12
|
+
- Updated dependencies
|
|
13
|
+
|
|
14
|
+
## 13.2.0
|
|
15
|
+
|
|
16
|
+
### Minor Changes
|
|
17
|
+
|
|
18
|
+
- [`782360c1111dc`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/782360c1111dc) -
|
|
19
|
+
Agent-edit shimmer review follow-ups (behind the default-OFF `platform_editor_agent_be_streaming`
|
|
20
|
+
experiment):
|
|
21
|
+
- Add a second shimmer phase: after the skeleton loader clears, the changed range shows a purple
|
|
22
|
+
"just edited" highlight (same colours as the editor AI "improve writing" in-editor highlight)
|
|
23
|
+
that eases in and out over its lifetime. The Rovo telepointer stays through both phases.
|
|
24
|
+
- The two phases are sized by independent experiment params: `shimmerDurationMs` (skeleton,
|
|
25
|
+
renamed from `durationMs`) and `highlightDurationMs` (highlight). `0` on either skips just that
|
|
26
|
+
phase, `0` on both shows nothing.
|
|
27
|
+
- Gate the agent-edit shimmer styles behind the experiment in both the emotion and compiled
|
|
28
|
+
`EditorContentContainer` style entries, using the no-exposure check on the hot render path.
|
|
29
|
+
- Add an `agentEditReceived` collab-provider analytics event, fired once per received transaction
|
|
30
|
+
that contains agent-authored steps, with non-PII attributes (agent ids, count, kinds,
|
|
31
|
+
agent/total step counts).
|
|
32
|
+
- Add an `agentEditShimmerNotShown` COLLAB operational analytics event for agent edits that apply
|
|
33
|
+
without the shimmer (`rebasedConcurrentEdit`, `nothingToShow`, `captureThrew`,
|
|
34
|
+
`tornDownMidAnimation`); neutral action + `reason`, non-PII attributes.
|
|
35
|
+
- Hoist the top-level block/position helpers in `agent-shimmer-ranges` to reusable module scope,
|
|
36
|
+
drop the redundant upper-bound clamp in `agent-shimmer-decorations`, and remove the empty
|
|
37
|
+
`@example` JSDoc tags added in the original PR.
|
|
38
|
+
|
|
39
|
+
`@atlaskit/editor-common` gains a new subpath export,
|
|
40
|
+
`@atlaskit/editor-common/analytics/types/agent-edit-shimmer-events`, exposing the
|
|
41
|
+
`agentEditShimmerNotShown` operational event types. Usage:
|
|
42
|
+
|
|
43
|
+
```ts
|
|
44
|
+
import { ACTION, ACTION_SUBJECT, EVENT_TYPE } from '@atlaskit/editor-common/analytics';
|
|
45
|
+
import type { AgentEditShimmerNotShownReason } from '@atlaskit/editor-common/analytics/types/agent-edit-shimmer-events';
|
|
46
|
+
|
|
47
|
+
const reason: AgentEditShimmerNotShownReason = 'captureThrew';
|
|
48
|
+
editorAnalyticsApi?.fireAnalyticsEvent({
|
|
49
|
+
action: ACTION.AGENT_EDIT_SHIMMER_NOT_SHOWN,
|
|
50
|
+
actionSubject: ACTION_SUBJECT.COLLAB,
|
|
51
|
+
eventType: EVENT_TYPE.OPERATIONAL,
|
|
52
|
+
attributes: { reason },
|
|
53
|
+
});
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### Patch Changes
|
|
57
|
+
|
|
58
|
+
- Updated dependencies
|
|
59
|
+
|
|
3
60
|
## 13.1.3
|
|
4
61
|
|
|
5
62
|
### Patch Changes
|
|
@@ -12,6 +12,7 @@ var _transform = require("@atlaskit/editor-prosemirror/transform");
|
|
|
12
12
|
var _prosemirrorCollab = require("@atlaskit/prosemirror-collab");
|
|
13
13
|
var _expValEquals = require("@atlaskit/tmp-editor-statsig/exp-val-equals");
|
|
14
14
|
var _expVal = require("@atlaskit/tmp-editor-statsig/expVal");
|
|
15
|
+
var _analytics = require("./analytics");
|
|
15
16
|
var _agentShimmerDecorations = require("./main/agent-shimmer-decorations");
|
|
16
17
|
var _agentShimmerRanges = require("./main/agent-shimmer-ranges");
|
|
17
18
|
var _utils = require("./utils");
|
|
@@ -40,7 +41,7 @@ var handleInit = exports.handleInit = function handleInit(initData, view, option
|
|
|
40
41
|
tr.setMeta('isRemote', true);
|
|
41
42
|
view.dispatch(tr);
|
|
42
43
|
} else if (json) {
|
|
43
|
-
applyRemoteSteps(json, view);
|
|
44
|
+
applyRemoteSteps(json, view, undefined, options, editorAnalyticsApi);
|
|
44
45
|
}
|
|
45
46
|
};
|
|
46
47
|
var handleConnection = exports.handleConnection = function handleConnection(connectionData, view) {
|
|
@@ -51,15 +52,15 @@ var handlePresence = exports.handlePresence = function handlePresence(presenceDa
|
|
|
51
52
|
var tr = view.state.tr;
|
|
52
53
|
view.dispatch(tr.setMeta('presence', presenceData));
|
|
53
54
|
};
|
|
54
|
-
var applyRemoteData = exports.applyRemoteData = function applyRemoteData(remoteData, view, options) {
|
|
55
|
+
var applyRemoteData = exports.applyRemoteData = function applyRemoteData(remoteData, view, options, editorAnalyticsApi) {
|
|
55
56
|
var json = remoteData.json,
|
|
56
57
|
_remoteData$userIds = remoteData.userIds,
|
|
57
58
|
userIds = _remoteData$userIds === void 0 ? [] : _remoteData$userIds;
|
|
58
59
|
if (json) {
|
|
59
|
-
applyRemoteSteps(json, view, userIds, options);
|
|
60
|
+
applyRemoteSteps(json, view, userIds, options, editorAnalyticsApi);
|
|
60
61
|
}
|
|
61
62
|
};
|
|
62
|
-
var applyRemoteSteps = exports.applyRemoteSteps = function applyRemoteSteps(json, view, userIds, options) {
|
|
63
|
+
var applyRemoteSteps = exports.applyRemoteSteps = function applyRemoteSteps(json, view, userIds, options, editorAnalyticsApi) {
|
|
63
64
|
if (!json || !json.length) {
|
|
64
65
|
return;
|
|
65
66
|
}
|
|
@@ -84,16 +85,28 @@ var applyRemoteSteps = exports.applyRemoteSteps = function applyRemoteSteps(json
|
|
|
84
85
|
tr.setMeta('isRemote', true);
|
|
85
86
|
|
|
86
87
|
// Agent edit shimmer: mark the ranges agent steps just wrote so the plugin reveals them with the
|
|
87
|
-
//
|
|
88
|
-
// off-experiment; off-path leaves `agentShimmers` empty and everything below
|
|
89
|
-
|
|
88
|
+
// skeleton loader, then (optionally) a purple "just edited" highlight. Gated as a whole so no
|
|
89
|
+
// experiment reads run off-experiment; off-path leaves `agentShimmers` empty and everything below
|
|
90
|
+
// is a no-op.
|
|
91
|
+
var shimmerDurationMs = 0;
|
|
92
|
+
var highlightDurationMs = 0;
|
|
90
93
|
var agentShimmers = [];
|
|
91
94
|
if ((0, _expValEquals.expValEquals)('platform_editor_agent_be_streaming', 'isEnabled', true)) {
|
|
92
|
-
|
|
95
|
+
// The skeleton and purple-highlight phases toggle independently. `shimmerDurationMs` is the
|
|
96
|
+
// skeleton lifetime; `0` skips the skeleton (an edit can still get the purple highlight).
|
|
97
|
+
shimmerDurationMs = (0, _expVal.expVal)('platform_editor_agent_be_streaming', 'shimmerDurationMs', _agentShimmerDecorations.AGENT_SHIMMER_DEFAULT_DURATION_MS);
|
|
98
|
+
// `highlightDurationMs` is the purple "just edited" highlight lifetime; `0` skips the highlight
|
|
99
|
+
// (the skeleton still shows). `0` on both shows nothing.
|
|
100
|
+
highlightDurationMs = (0, _expVal.expVal)('platform_editor_agent_be_streaming', 'highlightDurationMs', _agentShimmerDecorations.AGENT_EDIT_HIGHLIGHT_DEFAULT_DURATION_MS);
|
|
93
101
|
// Telepointer shown by default; `telepointerDisabled` hides it (inverted because `expVal`
|
|
94
102
|
// only permits `false` as a boolean default).
|
|
95
103
|
var telepointerEnabled = !(0, _expVal.expVal)('platform_editor_agent_be_streaming', 'telepointerDisabled', false);
|
|
96
|
-
agentShimmers = (0, _agentShimmerRanges.getAgentShimmerRanges)(json, steps, tr, view,
|
|
104
|
+
agentShimmers = (0, _agentShimmerRanges.getAgentShimmerRanges)(json, steps, tr, view, shimmerDurationMs, highlightDurationMs, telepointerEnabled,
|
|
105
|
+
// An agent edit that applied without the shimmer fires the operational event on the same
|
|
106
|
+
// transaction, so success stays event-free and only degrades are reported.
|
|
107
|
+
function (reason, agentType, error) {
|
|
108
|
+
return editorAnalyticsApi === null || editorAnalyticsApi === void 0 ? void 0 : editorAnalyticsApi.attachAnalyticsEvent((0, _analytics.getAgentEditShimmerNotShownPayload)(reason, agentType, error))(tr);
|
|
109
|
+
});
|
|
97
110
|
if (agentShimmers.length) {
|
|
98
111
|
tr.setMeta(_agentShimmerDecorations.ADD_AGENT_SHIMMER_META, agentShimmers);
|
|
99
112
|
}
|
|
@@ -109,22 +122,45 @@ var applyRemoteSteps = exports.applyRemoteSteps = function applyRemoteSteps(json
|
|
|
109
122
|
}
|
|
110
123
|
view.dispatch(tr);
|
|
111
124
|
|
|
112
|
-
//
|
|
125
|
+
// Schedule each shimmer's phase changes. `dispatchMeta` is guarded so a timer firing after
|
|
113
126
|
// teardown is a harmless no-op. Only reached when the gated block above produced ranges, so this
|
|
114
127
|
// whole path is off-experiment-safe.
|
|
115
128
|
if (agentShimmers.length) {
|
|
129
|
+
var tornDownReported = false;
|
|
116
130
|
var dispatchMeta = function dispatchMeta(metaKey, value) {
|
|
117
131
|
try {
|
|
118
132
|
view.dispatch(view.state.tr.setMeta(metaKey, value));
|
|
119
133
|
} catch (_unused) {
|
|
120
|
-
// View torn down before the timer fired — nothing to clean up.
|
|
134
|
+
// View torn down before the timer fired — nothing to clean up. Report once (not once
|
|
135
|
+
// per shimmer) so we can see how often shimmers are interrupted by teardown.
|
|
136
|
+
if (!tornDownReported) {
|
|
137
|
+
tornDownReported = true;
|
|
138
|
+
editorAnalyticsApi === null || editorAnalyticsApi === void 0 || editorAnalyticsApi.fireAnalyticsEvent((0, _analytics.getAgentEditShimmerNotShownPayload)('tornDownMidAnimation'));
|
|
139
|
+
}
|
|
121
140
|
}
|
|
122
141
|
};
|
|
123
142
|
agentShimmers.forEach(function (_ref) {
|
|
124
143
|
var shimmerId = _ref.shimmerId;
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
144
|
+
if (shimmerDurationMs > 0) {
|
|
145
|
+
// Skeleton first. When it clears, show the purple highlight (if enabled) then remove;
|
|
146
|
+
// otherwise remove straight away.
|
|
147
|
+
setTimeout(function () {
|
|
148
|
+
if (highlightDurationMs > 0) {
|
|
149
|
+
dispatchMeta(_agentShimmerDecorations.HIGHLIGHT_AGENT_SHIMMER_META, shimmerId);
|
|
150
|
+
setTimeout(function () {
|
|
151
|
+
dispatchMeta(_agentShimmerDecorations.REMOVE_AGENT_SHIMMER_META, shimmerId);
|
|
152
|
+
}, highlightDurationMs);
|
|
153
|
+
} else {
|
|
154
|
+
dispatchMeta(_agentShimmerDecorations.REMOVE_AGENT_SHIMMER_META, shimmerId);
|
|
155
|
+
}
|
|
156
|
+
}, shimmerDurationMs);
|
|
157
|
+
} else {
|
|
158
|
+
// Skeleton disabled: the range already starts in the highlight phase, so just time its
|
|
159
|
+
// removal. (Reached only when `highlightDurationMs > 0`, else no ranges were produced.)
|
|
160
|
+
setTimeout(function () {
|
|
161
|
+
dispatchMeta(_agentShimmerDecorations.REMOVE_AGENT_SHIMMER_META, shimmerId);
|
|
162
|
+
}, highlightDurationMs);
|
|
163
|
+
}
|
|
128
164
|
});
|
|
129
165
|
}
|
|
130
166
|
}
|
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
+
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
3
4
|
Object.defineProperty(exports, "__esModule", {
|
|
4
5
|
value: true
|
|
5
6
|
});
|
|
6
|
-
exports.addSynchronyErrorAnalytics = exports.addSynchronyEntityAnalytics = void 0;
|
|
7
|
+
exports.getAgentEditShimmerNotShownPayload = exports.addSynchronyErrorAnalytics = exports.addSynchronyEntityAnalytics = void 0;
|
|
8
|
+
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
|
|
7
9
|
var _analytics = require("@atlaskit/editor-common/analytics");
|
|
8
10
|
var _coreUtils = require("@atlaskit/editor-common/core-utils");
|
|
9
11
|
var _utils = require("@atlaskit/editor-common/utils");
|
|
12
|
+
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
|
13
|
+
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { (0, _defineProperty2.default)(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
|
|
10
14
|
var addSynchronyErrorAnalytics = exports.addSynchronyErrorAnalytics = function addSynchronyErrorAnalytics(state, tr, featureFlags, editorAnalyticsApi) {
|
|
11
15
|
return function (error) {
|
|
12
16
|
var browserExtensions = (0, _utils.sniffUserBrowserExtensions)({
|
|
@@ -32,6 +36,27 @@ var addSynchronyErrorAnalytics = exports.addSynchronyErrorAnalytics = function a
|
|
|
32
36
|
return tr;
|
|
33
37
|
};
|
|
34
38
|
};
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Builds the `agentEditShimmerNotShown` operational event fired when an agent-authored edit applied
|
|
42
|
+
* instantly without the skeleton shimmer/telepointer. Success is the ABSENCE of this event; a
|
|
43
|
+
* neutral action + `reason` keeps expected degrades out of error dashboards. Attributes are non-PII:
|
|
44
|
+
* only the agent kind and a sanitised error name/message (never the raw Error or any doc content).
|
|
45
|
+
*/
|
|
46
|
+
var getAgentEditShimmerNotShownPayload = exports.getAgentEditShimmerNotShownPayload = function getAgentEditShimmerNotShownPayload(reason, agentType, error) {
|
|
47
|
+
return {
|
|
48
|
+
action: _analytics.ACTION.AGENT_EDIT_SHIMMER_NOT_SHOWN,
|
|
49
|
+
actionSubject: _analytics.ACTION_SUBJECT.COLLAB,
|
|
50
|
+
eventType: _analytics.EVENT_TYPE.OPERATIONAL,
|
|
51
|
+
attributes: _objectSpread(_objectSpread({
|
|
52
|
+
reason: reason
|
|
53
|
+
}, agentType ? {
|
|
54
|
+
agentType: agentType
|
|
55
|
+
} : {}), error ? {
|
|
56
|
+
error: "".concat(error.name, ": ").concat(error.message)
|
|
57
|
+
} : {})
|
|
58
|
+
};
|
|
59
|
+
};
|
|
35
60
|
var addSynchronyEntityAnalytics = exports.addSynchronyEntityAnalytics = function addSynchronyEntityAnalytics(state, tr) {
|
|
36
61
|
return function (type, editorAnalyticsApi) {
|
|
37
62
|
editorAnalyticsApi === null || editorAnalyticsApi === void 0 || editorAnalyticsApi.attachAnalyticsEvent({
|
|
@@ -55,7 +55,7 @@ var subscribe = exports.subscribe = effect(function (view, provider, options, fe
|
|
|
55
55
|
return (0, _actions.handleConnection)(data, view);
|
|
56
56
|
},
|
|
57
57
|
dataHandler: function dataHandler(data) {
|
|
58
|
-
return (0, _actions.applyRemoteData)(data, view, options);
|
|
58
|
+
return (0, _actions.applyRemoteData)(data, view, options, editorAnalyticsApi);
|
|
59
59
|
},
|
|
60
60
|
presenceHandler: function presenceHandler(data) {
|
|
61
61
|
return (0, _actions.handlePresence)(data, view);
|
|
@@ -4,7 +4,7 @@ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefau
|
|
|
4
4
|
Object.defineProperty(exports, "__esModule", {
|
|
5
5
|
value: true
|
|
6
6
|
});
|
|
7
|
-
exports.reduceAgentShimmers = exports.buildAgentShimmerDecorations = exports.ROVO_AGENT_TELEPOINTER_LABEL_CLASS = exports.ROVO_AGENT_TELEPOINTER_CLASS = exports.REMOVE_AGENT_SHIMMER_META = exports.AGENT_SHIMMER_DEFAULT_DURATION_MS = exports.AGENT_SHIMMER_CLASS = exports.ADD_AGENT_SHIMMER_META = void 0;
|
|
7
|
+
exports.reduceAgentShimmers = exports.buildAgentShimmerDecorations = exports.ROVO_AGENT_TELEPOINTER_LABEL_CLASS = exports.ROVO_AGENT_TELEPOINTER_CLASS = exports.REMOVE_AGENT_SHIMMER_META = exports.HIGHLIGHT_AGENT_SHIMMER_META = exports.AGENT_SHIMMER_DEFAULT_DURATION_MS = exports.AGENT_SHIMMER_CLASS = exports.AGENT_EDIT_HIGHLIGHT_DEFAULT_DURATION_MS = exports.AGENT_EDIT_HIGHLIGHT_CLASS = exports.ADD_AGENT_SHIMMER_META = void 0;
|
|
8
8
|
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
|
|
9
9
|
var _view = require("@atlaskit/editor-prosemirror/view");
|
|
10
10
|
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
|
@@ -15,17 +15,31 @@ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t =
|
|
|
15
15
|
|
|
16
16
|
/** Default time the skeleton shimmer stays on the agent-authored content (ms). */
|
|
17
17
|
var AGENT_SHIMMER_DEFAULT_DURATION_MS = exports.AGENT_SHIMMER_DEFAULT_DURATION_MS = 3000;
|
|
18
|
+
/**
|
|
19
|
+
* Default time the purple "just edited" highlight stays after the skeleton clears (ms); `0` disables
|
|
20
|
+
* the highlight phase so the shimmer just reveals the content.
|
|
21
|
+
*/
|
|
22
|
+
var AGENT_EDIT_HIGHLIGHT_DEFAULT_DURATION_MS = exports.AGENT_EDIT_HIGHLIGHT_DEFAULT_DURATION_MS = 2000;
|
|
18
23
|
|
|
19
24
|
// Skeleton-loader bar over the agent-authored range, plus a Rovo AI telepointer at the end.
|
|
20
25
|
var AGENT_SHIMMER_CLASS = exports.AGENT_SHIMMER_CLASS = 'collab-agent-shimmer';
|
|
26
|
+
// Purple "just edited" highlight shown over the range after the skeleton clears — same style as the
|
|
27
|
+
// editor AI "improve writing" in-editor highlight (subtle purple background + dashed purple underline).
|
|
28
|
+
var AGENT_EDIT_HIGHLIGHT_CLASS = exports.AGENT_EDIT_HIGHLIGHT_CLASS = 'collab-agent-edit-highlight';
|
|
21
29
|
var ROVO_AGENT_TELEPOINTER_CLASS = exports.ROVO_AGENT_TELEPOINTER_CLASS = 'ai-in-editor-telepointer';
|
|
22
30
|
var ROVO_AGENT_TELEPOINTER_LABEL_CLASS = exports.ROVO_AGENT_TELEPOINTER_LABEL_CLASS = 'ai-in-editor-telepointer-label';
|
|
23
31
|
var ADD_AGENT_SHIMMER_META = exports.ADD_AGENT_SHIMMER_META = 'addAgentShimmer'; // register the shimmer decorations
|
|
32
|
+
var HIGHLIGHT_AGENT_SHIMMER_META = exports.HIGHLIGHT_AGENT_SHIMMER_META = 'highlightAgentShimmer'; // skeleton → purple highlight phase
|
|
24
33
|
var REMOVE_AGENT_SHIMMER_META = exports.REMOVE_AGENT_SHIMMER_META = 'removeAgentShimmer'; // remove them once the shimmer ends
|
|
25
34
|
|
|
26
|
-
// A
|
|
27
|
-
//
|
|
28
|
-
|
|
35
|
+
// A shimmer runs in two phases: the `skeleton` loader, then (optionally) the purple `highlight` over
|
|
36
|
+
// the revealed content, before removal.
|
|
37
|
+
|
|
38
|
+
// A range an agent step wrote; the shimmer decorations are drawn over `from`..`to` and kept until
|
|
39
|
+
// removal (so positions can be re-mapped). Pure data only. `phase` selects skeleton vs purple
|
|
40
|
+
// highlight. `telepointerLabel` is the label for the trailing agent telepointer (shown through both
|
|
41
|
+
// phases); when absent, no telepointer is shown. `highlightDurationMs` is the purple-highlight
|
|
42
|
+
// lifetime, used to size its ease in/out animation so it matches the removal timer.
|
|
29
43
|
|
|
30
44
|
// Rovo AI in-editor telepointer/cursor shown at the end of an agent-authored range (same DOM/style
|
|
31
45
|
// pattern as editor-plugin-ai's in-editor direct-streaming telepointer).
|
|
@@ -47,7 +61,7 @@ var createRovoAgentTelepointer = function createRovoAgentTelepointer(label) {
|
|
|
47
61
|
* supersedes any still-in-flight shimmer), and drops a range when its removal timer fires. Returns a
|
|
48
62
|
* fresh array (never mutates in place) plus whether anything changed.
|
|
49
63
|
*/
|
|
50
|
-
var reduceAgentShimmers = exports.reduceAgentShimmers = function reduceAgentShimmers(current, tr, added, removedShimmerId) {
|
|
64
|
+
var reduceAgentShimmers = exports.reduceAgentShimmers = function reduceAgentShimmers(current, tr, added, removedShimmerId, highlightShimmerId) {
|
|
51
65
|
var next = current;
|
|
52
66
|
var changed = false;
|
|
53
67
|
|
|
@@ -68,6 +82,19 @@ var reduceAgentShimmers = exports.reduceAgentShimmers = function reduceAgentShim
|
|
|
68
82
|
});
|
|
69
83
|
changed = true;
|
|
70
84
|
}
|
|
85
|
+
// Transition a shimmer from the skeleton phase to the purple highlight phase (skeleton timer fired).
|
|
86
|
+
// Guard on an actual match so a timer firing after the shimmer was already removed (superseded by a
|
|
87
|
+
// new batch, or cleared) doesn't rebuild the array and trigger a pointless decoration rebuild.
|
|
88
|
+
if (highlightShimmerId && next.some(function (shimmer) {
|
|
89
|
+
return shimmer.shimmerId === highlightShimmerId;
|
|
90
|
+
})) {
|
|
91
|
+
next = next.map(function (shimmer) {
|
|
92
|
+
return shimmer.shimmerId === highlightShimmerId ? _objectSpread(_objectSpread({}, shimmer), {}, {
|
|
93
|
+
phase: 'highlight'
|
|
94
|
+
}) : shimmer;
|
|
95
|
+
});
|
|
96
|
+
changed = true;
|
|
97
|
+
}
|
|
71
98
|
if (removedShimmerId) {
|
|
72
99
|
next = next.filter(function (shimmer) {
|
|
73
100
|
return shimmer.shimmerId !== removedShimmerId;
|
|
@@ -81,33 +108,45 @@ var reduceAgentShimmers = exports.reduceAgentShimmers = function reduceAgentShim
|
|
|
81
108
|
};
|
|
82
109
|
|
|
83
110
|
/**
|
|
84
|
-
* Builds the inline skeleton
|
|
85
|
-
* `getValidPos` clamps a raw position to a valid
|
|
86
|
-
* One bad range is isolated via `onError` so it can't
|
|
111
|
+
* Builds the inline decorations (skeleton bar or purple highlight, per phase) plus the trailing
|
|
112
|
+
* telepointer for the active shimmer ranges. `getValidPos` clamps a raw position to a valid
|
|
113
|
+
* decoration position (owned by `plugin-state`). One bad range is isolated via `onError` so it can't
|
|
114
|
+
* kill the others.
|
|
87
115
|
*/
|
|
88
116
|
var buildAgentShimmerDecorations = exports.buildAgentShimmerDecorations = function buildAgentShimmerDecorations(tr, shimmers, getValidPos, onError) {
|
|
89
117
|
var decorations = [];
|
|
90
|
-
var docEnd = tr.doc.nodeSize - 2;
|
|
91
118
|
shimmers.forEach(function (_ref) {
|
|
92
119
|
var shimmerId = _ref.shimmerId,
|
|
93
120
|
from = _ref.from,
|
|
94
121
|
to = _ref.to,
|
|
95
|
-
telepointerLabel = _ref.telepointerLabel
|
|
122
|
+
telepointerLabel = _ref.telepointerLabel,
|
|
123
|
+
phase = _ref.phase,
|
|
124
|
+
highlightDurationMs = _ref.highlightDurationMs;
|
|
96
125
|
try {
|
|
126
|
+
// `getValidPos` already clamps to the last valid position, so only the lower bound needs
|
|
127
|
+
// guarding here (a raw `from < 1` would throw in `doc.resolve`).
|
|
97
128
|
var validFrom = getValidPos(tr, Math.max(from, 1));
|
|
98
|
-
var validTo = getValidPos(tr,
|
|
129
|
+
var validTo = getValidPos(tr, to);
|
|
99
130
|
if (validTo <= validFrom) {
|
|
100
131
|
return;
|
|
101
132
|
}
|
|
102
|
-
//
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
133
|
+
// Inline decoration over the whole range: the grey skeleton loader, or (once revealed) the
|
|
134
|
+
// purple "just edited" highlight. The highlight eases in and out over its lifetime via a CSS
|
|
135
|
+
// animation whose duration is set inline so it matches the removal timer.
|
|
136
|
+
var isHighlight = phase === 'highlight';
|
|
137
|
+
var inlineAttrs = {
|
|
138
|
+
class: isHighlight ? AGENT_EDIT_HIGHLIGHT_CLASS : AGENT_SHIMMER_CLASS
|
|
139
|
+
};
|
|
140
|
+
if (isHighlight && highlightDurationMs > 0) {
|
|
141
|
+
inlineAttrs.style = "animation-duration: ".concat(highlightDurationMs, "ms");
|
|
142
|
+
}
|
|
143
|
+
decorations.push(_view.Decoration.inline(validFrom, validTo, inlineAttrs, {
|
|
106
144
|
isAgentShimmer: true,
|
|
107
145
|
shimmerId: shimmerId
|
|
108
146
|
}));
|
|
109
|
-
//
|
|
110
|
-
//
|
|
147
|
+
// Rovo AI telepointer/cursor (labelled with the agent's type) at the end of the range, shown
|
|
148
|
+
// through BOTH the skeleton and purple-highlight phases so the agent's cursor stays put until
|
|
149
|
+
// the edit is fully revealed.
|
|
111
150
|
if (telepointerLabel) {
|
|
112
151
|
decorations.push(_view.Decoration.widget(validTo, createRovoAgentTelepointer(telepointerLabel), {
|
|
113
152
|
isAgentShimmer: true,
|
|
@@ -8,8 +8,9 @@ var _prosemirrorCollab = require("@atlaskit/prosemirror-collab");
|
|
|
8
8
|
var _expValEquals = require("@atlaskit/tmp-editor-statsig/exp-val-equals");
|
|
9
9
|
// When an agent step lands we cover the top-level block(s) it wrote with a skeleton-loader shimmer
|
|
10
10
|
// (plus a Rovo agent telepointer at the end of the range), then remove it on a timer to reveal the
|
|
11
|
-
// content. Gated behind the `platform_editor_agent_be_streaming` experiment
|
|
12
|
-
//
|
|
11
|
+
// content. Gated behind the `platform_editor_agent_be_streaming` experiment. `shimmerDurationMs` and
|
|
12
|
+
// `highlightDurationMs` size the skeleton and purple-highlight phases and toggle independently: `0` on
|
|
13
|
+
// either skips that phase, `0` on both shows nothing.
|
|
13
14
|
var agentShimmerIdCounter = 0;
|
|
14
15
|
|
|
15
16
|
// A step is position-neutral when its StepMap changes no range's length — i.e. it shifts no
|
|
@@ -26,6 +27,26 @@ var isPositionNeutralStep = exports.isPositionNeutralStep = function isPositionN
|
|
|
26
27
|
return neutral;
|
|
27
28
|
};
|
|
28
29
|
|
|
30
|
+
// Top-level block/position helpers over a doc. Kept at module scope (rather than re-created as
|
|
31
|
+
// closures on every call) so they are defined once, reusable, and unit-testable. Each clamps into
|
|
32
|
+
// valid document coordinates before resolving.
|
|
33
|
+
var clampToDoc = function clampToDoc(doc, pos) {
|
|
34
|
+
return Math.min(Math.max(pos, 1), doc.content.size);
|
|
35
|
+
};
|
|
36
|
+
var topLevelBlockIndexAt = function topLevelBlockIndexAt(doc, pos) {
|
|
37
|
+
return doc.resolve(clampToDoc(doc, pos)).index(0);
|
|
38
|
+
};
|
|
39
|
+
// Start of the content of the top-level block containing `pos`, so the whole block is covered.
|
|
40
|
+
var topLevelBlockContentStart = function topLevelBlockContentStart(doc, pos) {
|
|
41
|
+
var $pos = doc.resolve(clampToDoc(doc, pos));
|
|
42
|
+
return $pos.depth >= 1 ? $pos.start(1) : pos;
|
|
43
|
+
};
|
|
44
|
+
// End of the content of the top-level block containing `pos`, so the whole block is covered.
|
|
45
|
+
var topLevelBlockContentEnd = function topLevelBlockContentEnd(doc, pos) {
|
|
46
|
+
var $pos = doc.resolve(clampToDoc(doc, pos));
|
|
47
|
+
return $pos.depth >= 1 ? $pos.end(1) : pos;
|
|
48
|
+
};
|
|
49
|
+
|
|
29
50
|
/**
|
|
30
51
|
* Derive the shimmer ranges for the agent-authored steps in a received batch, in final-doc
|
|
31
52
|
* coordinates. `agentType` present ⇒ agent-authored (per the NCS↔Editor steps contract). Each
|
|
@@ -42,15 +63,20 @@ var isPositionNeutralStep = exports.isPositionNeutralStep = function isPositionN
|
|
|
42
63
|
* rebased local step changed sizes (a rare, safe degrade). Any unexpected error also degrades to no
|
|
43
64
|
* shimmer, so this never throws into the shared remote-step handler.
|
|
44
65
|
*/
|
|
45
|
-
var getAgentShimmerRanges = exports.getAgentShimmerRanges = function getAgentShimmerRanges(json, steps, tr, view,
|
|
66
|
+
var getAgentShimmerRanges = exports.getAgentShimmerRanges = function getAgentShimmerRanges(json, steps, tr, view, shimmerDurationMs, highlightDurationMs, telepointerEnabled, onNotShown) {
|
|
46
67
|
var _json$find;
|
|
47
68
|
if (!(0, _expValEquals.expValEquals)('platform_editor_agent_be_streaming', 'isEnabled', true)) {
|
|
48
69
|
return [];
|
|
49
70
|
}
|
|
50
|
-
//
|
|
51
|
-
|
|
71
|
+
// The two phases toggle independently: `shimmerDurationMs` sizes the skeleton, `highlightDurationMs`
|
|
72
|
+
// sizes the purple highlight, and `0` on either skips just that phase. Nothing to reveal only when
|
|
73
|
+
// both are off.
|
|
74
|
+
if (shimmerDurationMs <= 0 && highlightDurationMs <= 0) {
|
|
52
75
|
return [];
|
|
53
76
|
}
|
|
77
|
+
// Start in the skeleton phase when it's enabled, otherwise straight into the purple highlight phase
|
|
78
|
+
// (skeleton toggled off, highlight on).
|
|
79
|
+
var initialPhase = shimmerDurationMs > 0 ? 'skeleton' : 'highlight';
|
|
54
80
|
// Telepointer label = the agent's type upper-cased (e.g. `mcp` → "MCP"), falling back to a generic
|
|
55
81
|
// "Agent"; `undefined` when the telepointer is disabled, so the plugin skips it. `agentType` is the
|
|
56
82
|
// same on every step of an agent batch, so read it from the first agent-authored step.
|
|
@@ -58,7 +84,11 @@ var getAgentShimmerRanges = exports.getAgentShimmerRanges = function getAgentShi
|
|
|
58
84
|
var agentType = (_json$find = json.find(function (step) {
|
|
59
85
|
return typeof (step === null || step === void 0 ? void 0 : step.agentType) === 'string';
|
|
60
86
|
})) === null || _json$find === void 0 ? void 0 : _json$find.agentType;
|
|
61
|
-
|
|
87
|
+
// No agent-authored steps in this batch — nothing to shimmer, and not a "not shown" case.
|
|
88
|
+
if (agentType === undefined) {
|
|
89
|
+
return [];
|
|
90
|
+
}
|
|
91
|
+
var telepointerLabel = telepointerEnabled ? agentType.toUpperCase() || 'Agent' : undefined;
|
|
62
92
|
// When the batch was rebased over local unconfirmed steps, our index-based range math is only
|
|
63
93
|
// valid if those local steps shifted no positions. Attribute-only steps (e.g. `localId`) and
|
|
64
94
|
// same-size replacements are position-neutral, so the shimmer stays correct. Skip only when a
|
|
@@ -69,6 +99,7 @@ var getAgentShimmerRanges = exports.getAgentShimmerRanges = function getAgentShi
|
|
|
69
99
|
if (unconfirmed.some(function (entry) {
|
|
70
100
|
return !isPositionNeutralStep(entry.step);
|
|
71
101
|
})) {
|
|
102
|
+
onNotShown === null || onNotShown === void 0 || onNotShown('rebasedConcurrentEdit', agentType);
|
|
72
103
|
return [];
|
|
73
104
|
}
|
|
74
105
|
}
|
|
@@ -108,6 +139,7 @@ var getAgentShimmerRanges = exports.getAgentShimmerRanges = function getAgentShi
|
|
|
108
139
|
});
|
|
109
140
|
});
|
|
110
141
|
if (!infos.length) {
|
|
142
|
+
onNotShown === null || onNotShown === void 0 || onNotShown('nothingToShow', agentType);
|
|
111
143
|
return [];
|
|
112
144
|
}
|
|
113
145
|
|
|
@@ -119,28 +151,12 @@ var getAgentShimmerRanges = exports.getAgentShimmerRanges = function getAgentShi
|
|
|
119
151
|
// touched blocks (index n and n+1) merge into one group so a multi-block rewrite reveals together;
|
|
120
152
|
// a genuinely untouched block in between (index gap > 1) splits the run, so far-apart edits stay
|
|
121
153
|
// independent.
|
|
122
|
-
var docSize = tr.doc.content.size;
|
|
123
|
-
var clampPos = function clampPos(pos) {
|
|
124
|
-
return Math.min(Math.max(pos, 1), docSize);
|
|
125
|
-
};
|
|
126
|
-
var blockIndexAt = function blockIndexAt(pos) {
|
|
127
|
-
return tr.doc.resolve(clampPos(pos)).index(0);
|
|
128
|
-
};
|
|
129
|
-
// Start/end of the content of the top-level block containing `pos`, so the whole block is covered.
|
|
130
|
-
var blockContentStart = function blockContentStart(pos) {
|
|
131
|
-
var $pos = tr.doc.resolve(clampPos(pos));
|
|
132
|
-
return $pos.depth >= 1 ? $pos.start(1) : pos;
|
|
133
|
-
};
|
|
134
|
-
var blockContentEnd = function blockContentEnd(pos) {
|
|
135
|
-
var $pos = tr.doc.resolve(clampPos(pos));
|
|
136
|
-
return $pos.depth >= 1 ? $pos.end(1) : pos;
|
|
137
|
-
};
|
|
138
154
|
var sorted = [].concat(infos).sort(function (a, b) {
|
|
139
155
|
return a.from - b.from || a.to - b.to;
|
|
140
156
|
});
|
|
141
157
|
var groups = [];
|
|
142
158
|
sorted.forEach(function (info) {
|
|
143
|
-
var block =
|
|
159
|
+
var block = topLevelBlockIndexAt(tr.doc, info.from);
|
|
144
160
|
var current = groups[groups.length - 1];
|
|
145
161
|
if (current && block <= current.maxBlock + 1) {
|
|
146
162
|
current.to = Math.max(current.to, info.to);
|
|
@@ -156,14 +172,17 @@ var getAgentShimmerRanges = exports.getAgentShimmerRanges = function getAgentShi
|
|
|
156
172
|
return groups.map(function (group) {
|
|
157
173
|
return {
|
|
158
174
|
shimmerId: "agent-shimmer-".concat(agentShimmerIdCounter++),
|
|
159
|
-
from:
|
|
160
|
-
to:
|
|
161
|
-
telepointerLabel: telepointerLabel
|
|
175
|
+
from: topLevelBlockContentStart(tr.doc, group.from),
|
|
176
|
+
to: topLevelBlockContentEnd(tr.doc, group.to),
|
|
177
|
+
telepointerLabel: telepointerLabel,
|
|
178
|
+
phase: initialPhase,
|
|
179
|
+
highlightDurationMs: highlightDurationMs
|
|
162
180
|
};
|
|
163
181
|
});
|
|
164
|
-
} catch (
|
|
182
|
+
} catch (err) {
|
|
165
183
|
// Never let shimmer range derivation throw into the shared remote-step handler; degrade to no
|
|
166
184
|
// shimmer.
|
|
185
|
+
onNotShown === null || onNotShown === void 0 || onNotShown('captureThrew', agentType, err);
|
|
167
186
|
return [];
|
|
168
187
|
}
|
|
169
188
|
};
|
|
@@ -97,6 +97,7 @@ var PluginState = exports.PluginState = /*#__PURE__*/function () {
|
|
|
97
97
|
var nudgeTelepointerData = tr.getMeta('nudgeTelepointer');
|
|
98
98
|
var agentShimmerData = tr.getMeta(_agentShimmerDecorations.ADD_AGENT_SHIMMER_META);
|
|
99
99
|
var removeAgentShimmerId = tr.getMeta(_agentShimmerDecorations.REMOVE_AGENT_SHIMMER_META);
|
|
100
|
+
var highlightAgentShimmerId = tr.getMeta(_agentShimmerDecorations.HIGHLIGHT_AGENT_SHIMMER_META);
|
|
100
101
|
var sessionIdData = tr.getMeta('sessionId');
|
|
101
102
|
var collabInitialised = tr.getMeta('collabInitialised');
|
|
102
103
|
if (typeof collabInitialised !== 'boolean') {
|
|
@@ -239,7 +240,7 @@ var PluginState = exports.PluginState = /*#__PURE__*/function () {
|
|
|
239
240
|
// here can never corrupt telepointer decorations or the shared decoration set. Never mutates
|
|
240
241
|
// shimmer entries in place: each change produces a fresh array of fresh objects.
|
|
241
242
|
try {
|
|
242
|
-
var _reduceAgentShimmers = (0, _agentShimmerDecorations.reduceAgentShimmers)(this.agentShimmers, tr, agentShimmerData, removeAgentShimmerId),
|
|
243
|
+
var _reduceAgentShimmers = (0, _agentShimmerDecorations.reduceAgentShimmers)(this.agentShimmers, tr, agentShimmerData, removeAgentShimmerId, highlightAgentShimmerId),
|
|
243
244
|
changed = _reduceAgentShimmers.changed,
|
|
244
245
|
next = _reduceAgentShimmers.next;
|
|
245
246
|
if (changed) {
|