@atlaskit/editor-plugin-collab-edit
Version:
Collab Edit plugin for @atlaskit/editor-core
338 lines (335 loc) • 17.6 kB
JavaScript
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.collabEditPlugin = void 0;
var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator"));
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator"));
var _analytics = require("@atlaskit/editor-common/analytics");
var _utils = require("@atlaskit/editor-common/utils");
var _editorJsonTransformer = require("@atlaskit/editor-json-transformer");
var _transform = require("@atlaskit/editor-prosemirror/transform");
var _platformFeatureFlags = require("@atlaskit/platform-feature-flags");
var _prosemirrorCollab = require("@atlaskit/prosemirror-collab");
var _expValEquals = require("@atlaskit/tmp-editor-statsig/exp-val-equals");
var _experiments = require("@atlaskit/tmp-editor-statsig/experiments");
var _analytics2 = require("./pm-plugins/analytics");
var _sendTransaction = require("./pm-plugins/events/send-transaction");
var _filterAnalytics = require("./pm-plugins/filterAnalytics");
var _main = require("./pm-plugins/main");
var _pluginKey = require("./pm-plugins/main/plugin-key");
var _mergeUnconfirmed = require("./pm-plugins/mergeUnconfirmed");
var _monitorOrganicChanges = require("./pm-plugins/monitor-organic-changes");
var _nativeCollabProviderPlugin = require("./pm-plugins/native-collab-provider-plugin");
var _trackAndFilterSpammingSteps = require("./pm-plugins/track-and-filter-spamming-steps");
var _trackLastOrganicChange = require("./pm-plugins/track-last-organic-change");
var _trackNcsInitialization = require("./pm-plugins/track-ncs-initialization");
var _trackReconnectionConflict = require("./pm-plugins/track-reconnection-conflict");
var _trackSteps = require("./pm-plugins/track-steps");
var _utils2 = require("./pm-plugins/utils");
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; }
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; }
var providerBuilder = function providerBuilder(collabEditProviderPromise) {
return /*#__PURE__*/function () {
var _ref = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee(codeToExecute, onError) {
var provider;
return _regenerator.default.wrap(function _callee$(_context) {
while (1) switch (_context.prev = _context.next) {
case 0:
_context.prev = 0;
_context.next = 3;
return collabEditProviderPromise;
case 3:
provider = _context.sent;
if (!provider) {
_context.next = 6;
break;
}
return _context.abrupt("return", codeToExecute(provider));
case 6:
_context.next = 11;
break;
case 8:
_context.prev = 8;
_context.t0 = _context["catch"](0);
if (onError) {
onError(_context.t0);
} else {
// eslint-disable-next-line no-console
console.error(_context.t0);
}
case 11:
case "end":
return _context.stop();
}
}, _callee, null, [[0, 8]]);
}));
return function (_x, _x2) {
return _ref.apply(this, arguments);
};
}();
};
var createAddInlineCommentMark = function createAddInlineCommentMark(providerPromise) {
return function (_ref2) {
var from = _ref2.from,
to = _ref2.to,
mark = _ref2.mark;
providerPromise.then(function (provider) {
var _provider$api;
var commentMark = new _transform.AddMarkStep(Math.min(from, to), Math.max(from, to), mark);
// @ts-expect-error 2339: Property 'api' does not exist on type 'CollabEditProvider<CollabEvents>'.
(_provider$api = provider.api) === null || _provider$api === void 0 || _provider$api.addComment([commentMark]);
});
return false;
};
};
var createAddInlineCommentNodeMark = function createAddInlineCommentNodeMark(providerPromise) {
return function (_ref3) {
var pos = _ref3.pos,
mark = _ref3.mark;
providerPromise.then(function (provider) {
var _provider$api2;
var commentMark = new _transform.AddNodeMarkStep(pos, mark);
// @ts-expect-error 2339: Property 'api' does not exist on type 'CollabEditProvider<CollabEvents>'.
(_provider$api2 = provider.api) === null || _provider$api2 === void 0 || _provider$api2.addComment([commentMark]);
});
return false;
};
};
var collabEditPlugin = exports.collabEditPlugin = function collabEditPlugin(_ref4) {
var _api$featureFlags;
var options = _ref4.config,
api = _ref4.api;
var featureFlags = (api === null || api === void 0 || (_api$featureFlags = api.featureFlags) === null || _api$featureFlags === void 0 ? void 0 : _api$featureFlags.sharedState.currentState()) || {};
var providerResolver = function providerResolver() {};
var editorViewRef = {
current: null
};
var collabEditProviderPromise = new Promise(function (_providerResolver) {
providerResolver = _providerResolver;
});
var executeProviderCode = providerBuilder(collabEditProviderPromise);
return {
name: 'collabEdit',
getSharedState: function getSharedState(state) {
if (!state) {
return {
initialised: {
collabInitialisedAt: null,
firstChangeAfterInitAt: null,
firstContentBodyChangeAfterInitAt: null,
lastLocalOrganicChangeAt: null,
lastRemoteOrganicChangeAt: null,
lastLocalOrganicBodyChangeAt: null,
lastRemoteOrganicBodyChangeAt: null
},
activeParticipants: undefined,
sessionId: undefined,
lastReconnectionConflictMetadata: undefined
};
}
var collabPluginState = _pluginKey.pluginKey.getState(state);
var metadata = _trackNcsInitialization.trackNCSInitializationPluginKey.getState(state);
var lastOrganicChangeState = _trackLastOrganicChange.trackLastOrganicChangePluginKey.getState(state);
var lastRemoteConflict = _trackReconnectionConflict.trackLastRemoteConflictPluginKey.getState(state);
return {
activeParticipants: collabPluginState === null || collabPluginState === void 0 ? void 0 : collabPluginState.activeParticipants,
sessionId: collabPluginState === null || collabPluginState === void 0 ? void 0 : collabPluginState.sessionId,
initialised: {
collabInitialisedAt: (metadata === null || metadata === void 0 ? void 0 : metadata.collabInitialisedAt) || null,
firstChangeAfterInitAt: (metadata === null || metadata === void 0 ? void 0 : metadata.firstChangeAfterInitAt) || null,
firstContentBodyChangeAfterInitAt: (metadata === null || metadata === void 0 ? void 0 : metadata.firstContentBodyChangeAfterInitAt) || null,
lastLocalOrganicChangeAt: (lastOrganicChangeState === null || lastOrganicChangeState === void 0 ? void 0 : lastOrganicChangeState.lastLocalOrganicChangeAt) || null,
lastRemoteOrganicChangeAt: (lastOrganicChangeState === null || lastOrganicChangeState === void 0 ? void 0 : lastOrganicChangeState.lastRemoteOrganicChangeAt) || null,
lastLocalOrganicBodyChangeAt: (lastOrganicChangeState === null || lastOrganicChangeState === void 0 ? void 0 : lastOrganicChangeState.lastLocalOrganicBodyChangeAt) || null,
lastRemoteOrganicBodyChangeAt: (lastOrganicChangeState === null || lastOrganicChangeState === void 0 ? void 0 : lastOrganicChangeState.lastRemoteOrganicBodyChangeAt) || null
},
lastReconnectionConflictMetadata: lastRemoteConflict
};
},
actions: {
getAvatarColor: _utils2.getAvatarColor,
addInlineCommentMark: createAddInlineCommentMark(collabEditProviderPromise),
addInlineCommentNodeMark: createAddInlineCommentNodeMark(collabEditProviderPromise),
isRemoteReplaceDocumentTransaction: function isRemoteReplaceDocumentTransaction(tr) {
return tr.getMeta('isRemote') && tr.getMeta('replaceDocument');
},
getCurrentCollabState: function getCurrentCollabState() {
var _getCollabState;
// Ignored via go/ees005
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
var adfDocument = new _editorJsonTransformer.JSONTransformer().encode(editorViewRef.current.state.doc);
return {
content: adfDocument,
// Ignored via go/ees005
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
version: ((_getCollabState = (0, _prosemirrorCollab.getCollabState)(editorViewRef.current.state)) === null || _getCollabState === void 0 ? void 0 : _getCollabState.version) || 0,
// Ignored via go/ees005
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
sendableSteps: (0, _prosemirrorCollab.sendableSteps)(editorViewRef.current.state)
};
},
// Ignored via go/ees005
// eslint-disable-next-line @typescript-eslint/no-explicit-any
validatePMJSONDocument: function validatePMJSONDocument(doc) {
// Ignored via go/ees005
// eslint-disable-next-line @typescript-eslint/no-explicit-any
var content = (doc.content || []).map(function (child) {
return (
// Ignored via go/ees005
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
// Ignored via go/ees005
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
editorViewRef.current.state.schema.nodeFromJSON(child)
);
});
return content.every(function (node) {
try {
node.check(); // this will throw an error if the node is invalid
} catch (_unused) {
return false;
}
return true;
});
}
},
pmPlugins: function pmPlugins() {
var _ref5 = options || {},
_ref5$useNativePlugin = _ref5.useNativePlugin,
useNativePlugin = _ref5$useNativePlugin === void 0 ? false : _ref5$useNativePlugin,
_ref5$userId = _ref5.userId,
userId = _ref5$userId === void 0 ? null : _ref5$userId;
var transformUnconfirmed = function transformUnconfirmed(steps) {
var transformed = steps;
if ((0, _experiments.editorExperiment)('platform_editor_reduce_noisy_steps_ncs', true, {
exposure: true
})) {
transformed = (0, _filterAnalytics.filterAnalyticsSteps)(transformed);
}
if ((0, _experiments.editorExperiment)('platform_editor_offline_editing_web', true) || (0, _expValEquals.expValEquals)('platform_editor_enable_single_player_step_merging', 'isEnabled', true)) {
transformed = (0, _mergeUnconfirmed.mergeUnconfirmedSteps)(transformed, api);
}
return transformed;
};
var plugins = [].concat((0, _toConsumableArray2.default)(useNativePlugin ? [{
name: 'pmCollab',
plugin: function plugin() {
return (0, _prosemirrorCollab.collab)({
clientID: userId,
transformUnconfirmed: transformUnconfirmed
});
}
}, {
name: 'nativeCollabProviderPlugin',
plugin: function plugin() {
return (0, _nativeCollabProviderPlugin.nativeCollabProviderPlugin)({
providerPromise: collabEditProviderPromise
});
}
}] : []), [{
name: 'collab',
plugin: function plugin(_ref6) {
var dispatch = _ref6.dispatch,
providerFactory = _ref6.providerFactory;
return (0, _main.createPlugin)(dispatch, providerFactory, providerResolver, executeProviderCode, options, featureFlags, api);
}
}, {
name: 'collabTrackNCSInitializationPlugin',
plugin: _trackNcsInitialization.createPlugin
}]);
plugins.push({
name: 'trackAndFilterSpammingSteps',
plugin: function plugin() {
return (0, _trackAndFilterSpammingSteps.createPlugin)(function (tr) {
var _api$analytics;
var sanitizedSteps = tr.steps.map(function (step) {
return (0, _trackAndFilterSpammingSteps.sanitizeFilteredStep)(step);
});
api === null || api === void 0 || (_api$analytics = api.analytics) === null || _api$analytics === void 0 || (_api$analytics = _api$analytics.actions) === null || _api$analytics === void 0 || _api$analytics.fireAnalyticsEvent({
action: _analytics.ACTION.STEPS_FILTERED,
actionSubject: _analytics.ACTION_SUBJECT.COLLAB,
attributes: {
steps: sanitizedSteps
},
eventType: _analytics.EVENT_TYPE.OPERATIONAL
});
});
}
});
plugins.push({
name: 'collabTrackLastOrganicChangePlugin',
plugin: _trackLastOrganicChange.createPlugin
});
if ((0, _experiments.editorExperiment)('platform_editor_offline_editing_web', true)) {
plugins.push({
name: 'trackLastRemoteConflictPlugin',
plugin: _trackReconnectionConflict.createPlugin
});
}
return plugins;
},
onEditorViewStateUpdated: function onEditorViewStateUpdated(props) {
var _api$analytics2, _api$editorViewMode, _options$useNativePlu, _options$hideTelecurs;
var addErrorAnalytics = (0, _analytics2.addSynchronyErrorAnalytics)(props.newEditorState, props.newEditorState.tr, featureFlags, api === null || api === void 0 || (_api$analytics2 = api.analytics) === null || _api$analytics2 === void 0 ? void 0 : _api$analytics2.actions);
var isEmptyDoc = (0, _utils.isEmptyDocument)(props.newEditorState.doc);
var viewMode = api === null || api === void 0 || (_api$editorViewMode = api.editorViewMode) === null || _api$editorViewMode === void 0 || (_api$editorViewMode = _api$editorViewMode.sharedState.currentState()) === null || _api$editorViewMode === void 0 ? void 0 : _api$editorViewMode.mode;
executeProviderCode((0, _sendTransaction.sendTransaction)({
originalTransaction: props.originalTransaction,
transactions: props.transactions,
oldEditorState: props.oldEditorState,
newEditorState: props.newEditorState,
useNativePlugin: (_options$useNativePlu = options.useNativePlugin) !== null && _options$useNativePlu !== void 0 ? _options$useNativePlu : false,
hideTelecursorOnLoad: !isEmptyDoc && ((_options$hideTelecurs = options.hideTelecursorOnLoad) !== null && _options$hideTelecurs !== void 0 ? _options$hideTelecurs : false),
viewMode: viewMode
}), addErrorAnalytics);
if (!(0, _expValEquals.expValEquals)('platform_editor_remove_collab_step_metrics', 'isEnabled', true)) {
(0, _trackSteps.track)(_objectSpread(_objectSpread({
api: api
}, props), {}, {
onTrackDataProcessed: function onTrackDataProcessed(steps) {
var _api$analytics3;
api === null || api === void 0 || (_api$analytics3 = api.analytics) === null || _api$analytics3 === void 0 || (_api$analytics3 = _api$analytics3.actions) === null || _api$analytics3 === void 0 || _api$analytics3.fireAnalyticsEvent({
action: _analytics.ACTION.STEPS_TRACKED,
actionSubject: _analytics.ACTION_SUBJECT.COLLAB,
attributes: {
steps: steps
},
eventType: _analytics.EVENT_TYPE.OPERATIONAL
});
}
}));
}
if ((0, _platformFeatureFlags.fg)('platform_editor_collab_organic_change_reporting')) {
(0, _monitorOrganicChanges.monitorOrganic)(_objectSpread(_objectSpread({
api: api
}, props), {}, {
onDataProcessed: function onDataProcessed(data) {
var _api$analytics4;
api === null || api === void 0 || (_api$analytics4 = api.analytics) === null || _api$analytics4 === void 0 || (_api$analytics4 = _api$analytics4.actions) === null || _api$analytics4 === void 0 || _api$analytics4.fireAnalyticsEvent({
action: _analytics.ACTION.ORGANIC_CHANGES_TRACKED,
actionSubject: _analytics.ACTION_SUBJECT.COLLAB,
attributes: {
organicChanges: data
},
eventType: _analytics.EVENT_TYPE.OPERATIONAL
});
}
}));
}
},
commands: {
nudgeTelepointer: function nudgeTelepointer(sessionId) {
return function (_ref7) {
var tr = _ref7.tr;
tr.setMeta('nudgeTelepointer', {
sessionId: sessionId
});
return tr;
};
}
}
};
};