@atlaskit/editor-plugin-synced-block 5.1.9 → 5.1.10

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.
Files changed (55) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/dist/cjs/editor-commands/index.js +2 -2
  3. package/dist/cjs/pm-plugins/experience-tracking/create-reference-experience.js +26 -26
  4. package/dist/cjs/pm-plugins/experience-tracking/create-source-experience.js +14 -30
  5. package/dist/cjs/pm-plugins/experience-tracking/delete-reference-experience.js +175 -0
  6. package/dist/cjs/pm-plugins/experience-tracking/delete-source-experience.js +103 -0
  7. package/dist/cjs/pm-plugins/experience-tracking/get-experience-tracking-plugins.js +30 -0
  8. package/dist/cjs/pm-plugins/experience-tracking/provider-only-experiences.js +128 -0
  9. package/dist/cjs/pm-plugins/utils/experience-tracking-utils.js +85 -0
  10. package/dist/cjs/types/index.js +5 -2
  11. package/dist/cjs/ui/CreateSyncedBlockDropdownItem.js +40 -8
  12. package/dist/cjs/ui/DeleteConfirmationModal.js +3 -1
  13. package/dist/cjs/ui/floating-toolbar.js +4 -2
  14. package/dist/es2019/editor-commands/index.js +2 -2
  15. package/dist/es2019/pm-plugins/experience-tracking/create-reference-experience.js +27 -23
  16. package/dist/es2019/pm-plugins/experience-tracking/create-source-experience.js +14 -27
  17. package/dist/es2019/pm-plugins/experience-tracking/delete-reference-experience.js +181 -0
  18. package/dist/es2019/pm-plugins/experience-tracking/delete-source-experience.js +98 -0
  19. package/dist/es2019/pm-plugins/experience-tracking/get-experience-tracking-plugins.js +24 -0
  20. package/dist/es2019/pm-plugins/experience-tracking/provider-only-experiences.js +127 -0
  21. package/dist/es2019/pm-plugins/utils/experience-tracking-utils.js +65 -0
  22. package/dist/es2019/types/index.js +4 -1
  23. package/dist/es2019/ui/CreateSyncedBlockDropdownItem.js +38 -3
  24. package/dist/es2019/ui/DeleteConfirmationModal.js +3 -1
  25. package/dist/es2019/ui/floating-toolbar.js +3 -1
  26. package/dist/esm/editor-commands/index.js +2 -2
  27. package/dist/esm/pm-plugins/experience-tracking/create-reference-experience.js +26 -25
  28. package/dist/esm/pm-plugins/experience-tracking/create-source-experience.js +14 -29
  29. package/dist/esm/pm-plugins/experience-tracking/delete-reference-experience.js +169 -0
  30. package/dist/esm/pm-plugins/experience-tracking/delete-source-experience.js +97 -0
  31. package/dist/esm/pm-plugins/experience-tracking/get-experience-tracking-plugins.js +30 -0
  32. package/dist/esm/pm-plugins/experience-tracking/provider-only-experiences.js +122 -0
  33. package/dist/esm/pm-plugins/utils/experience-tracking-utils.js +79 -0
  34. package/dist/esm/types/index.js +4 -1
  35. package/dist/esm/ui/CreateSyncedBlockDropdownItem.js +40 -8
  36. package/dist/esm/ui/DeleteConfirmationModal.js +3 -1
  37. package/dist/esm/ui/floating-toolbar.js +4 -2
  38. package/dist/types/pm-plugins/experience-tracking/create-reference-experience.d.ts +2 -9
  39. package/dist/types/pm-plugins/experience-tracking/create-source-experience.d.ts +4 -15
  40. package/dist/types/pm-plugins/experience-tracking/delete-reference-experience.d.ts +13 -0
  41. package/dist/types/pm-plugins/experience-tracking/delete-source-experience.d.ts +12 -0
  42. package/dist/types/pm-plugins/experience-tracking/get-experience-tracking-plugins.d.ts +2 -13
  43. package/dist/types/pm-plugins/experience-tracking/provider-only-experiences.d.ts +3 -0
  44. package/dist/types/pm-plugins/utils/experience-tracking-utils.d.ts +9 -0
  45. package/dist/types/types/index.d.ts +15 -0
  46. package/dist/types-ts4.5/pm-plugins/experience-tracking/create-reference-experience.d.ts +2 -9
  47. package/dist/types-ts4.5/pm-plugins/experience-tracking/create-source-experience.d.ts +4 -15
  48. package/dist/types-ts4.5/pm-plugins/experience-tracking/delete-reference-experience.d.ts +13 -0
  49. package/dist/types-ts4.5/pm-plugins/experience-tracking/delete-source-experience.d.ts +12 -0
  50. package/dist/types-ts4.5/pm-plugins/experience-tracking/get-experience-tracking-plugins.d.ts +2 -13
  51. package/dist/types-ts4.5/pm-plugins/experience-tracking/provider-only-experiences.d.ts +3 -0
  52. package/dist/types-ts4.5/pm-plugins/utils/experience-tracking-utils.d.ts +9 -0
  53. package/dist/types-ts4.5/types/index.d.ts +15 -0
  54. package/package.json +5 -5
  55. package/build/tsconfig.json +0 -22
@@ -0,0 +1,98 @@
1
+ import { bind } from 'bind-event-listener';
2
+ import { ACTION_SUBJECT, ACTION_SUBJECT_ID } from '@atlaskit/editor-common/analytics';
3
+ import { Experience, ExperienceCheckDomMutation, ExperienceCheckTimeout } from '@atlaskit/editor-common/experiences';
4
+ import { SafePlugin } from '@atlaskit/editor-common/safe-plugin';
5
+ import { PluginKey } from '@atlaskit/editor-prosemirror/state';
6
+ import { EXPERIENCE_ABORT_REASON } from '../../types';
7
+ import { getRemovedResourceIds, getTarget } from '../utils/experience-tracking-utils';
8
+ const pluginKey = new PluginKey('deleteSourceSyncBlockExperience');
9
+ const START_METHOD = {
10
+ DELETE_CONFIRM_BUTTON: 'delete-confirm-button'
11
+ };
12
+
13
+ /**
14
+ * This experience tracks when a source sync block is deleted.
15
+ *
16
+ * Start: When user clicks the delete button in the delete modal
17
+ * Success: When the sync block is removed from the DOM within 2000ms of start
18
+ * Failure: When 2000ms passes without the source sync block being removed from the DOM
19
+ */
20
+ export const getDeleteSourceExperiencePlugin = ({
21
+ refs,
22
+ dispatchAnalyticsEvent,
23
+ syncBlockStore
24
+ }) => {
25
+ const experience = getDeleteSourceExperience({
26
+ refs,
27
+ dispatchAnalyticsEvent
28
+ });
29
+ syncBlockStore.sourceManager.setDeleteExperience(experience);
30
+ const unbindClickListener = bind(document, {
31
+ type: 'click',
32
+ listener: event => {
33
+ const target = event.target;
34
+ if (!target) {
35
+ return;
36
+ }
37
+ const button = target.closest('button[data-testid]');
38
+ if (!button || !(button instanceof HTMLButtonElement)) {
39
+ return;
40
+ }
41
+ const testId = button.dataset.testid;
42
+ if (isSyncedBlockDeleteButtonId(testId)) {
43
+ experience.start({
44
+ method: START_METHOD.DELETE_CONFIRM_BUTTON
45
+ });
46
+ }
47
+ }
48
+ });
49
+ return new SafePlugin({
50
+ key: pluginKey,
51
+ view: () => {
52
+ return {
53
+ destroy: () => {
54
+ experience.abort({
55
+ reason: EXPERIENCE_ABORT_REASON.EDITOR_DESTROYED
56
+ });
57
+ unbindClickListener();
58
+ }
59
+ };
60
+ }
61
+ });
62
+ };
63
+ export const getDeleteSourceExperience = ({
64
+ refs,
65
+ dispatchAnalyticsEvent
66
+ }) => {
67
+ return new Experience(ACTION_SUBJECT.SYNCED_BLOCK, {
68
+ actionSubjectId: ACTION_SUBJECT_ID.SYNCED_BLOCK_DELETE,
69
+ dispatchAnalyticsEvent,
70
+ checks: [new ExperienceCheckTimeout({
71
+ durationMs: 2000
72
+ }), new ExperienceCheckDomMutation({
73
+ onDomMutation: ({
74
+ mutations
75
+ }) => {
76
+ const deletedResourceIds = getRemovedResourceIds(mutations, '[data-prosemirror-node-name="bodiedSyncBlock"]');
77
+ if (deletedResourceIds.length > 0) {
78
+ return {
79
+ status: 'success',
80
+ metadata: {
81
+ deletedResourceIds
82
+ }
83
+ };
84
+ }
85
+ return undefined;
86
+ },
87
+ observeConfig: () => {
88
+ return {
89
+ target: getTarget(refs.containerElement),
90
+ options: {
91
+ childList: true
92
+ }
93
+ };
94
+ }
95
+ })]
96
+ });
97
+ };
98
+ const isSyncedBlockDeleteButtonId = testId => testId === 'synced-block-delete-confirmation-modal-delete-button';
@@ -1,5 +1,8 @@
1
1
  import { getCreateReferenceExperiencePlugin } from "./create-reference-experience";
2
2
  import { getCreateSourceExperiencePlugin } from "./create-source-experience";
3
+ import { getDeleteReferenceExperiencePlugin } from "./delete-reference-experience";
4
+ import { getDeleteSourceExperiencePlugin } from "./delete-source-experience";
5
+ import { getProviderOnlyExperiencesPlugin } from "./provider-only-experiences";
3
6
  export const getExperienceTrackingPlugins = ({
4
7
  refs,
5
8
  dispatchAnalyticsEvent,
@@ -18,5 +21,26 @@ export const getExperienceTrackingPlugins = ({
18
21
  dispatchAnalyticsEvent,
19
22
  syncBlockStore
20
23
  })
24
+ }, {
25
+ name: 'deleteSourceExperiencePlugin',
26
+ plugin: () => getDeleteSourceExperiencePlugin({
27
+ refs,
28
+ dispatchAnalyticsEvent,
29
+ syncBlockStore
30
+ })
31
+ }, {
32
+ name: 'deleteReferenceExperiencePlugin',
33
+ plugin: () => getDeleteReferenceExperiencePlugin({
34
+ refs,
35
+ dispatchAnalyticsEvent,
36
+ syncBlockStore
37
+ })
38
+ }, {
39
+ name: 'providerOnlySyncedBlockExperiencesPlugin',
40
+ plugin: () => getProviderOnlyExperiencesPlugin({
41
+ refs,
42
+ dispatchAnalyticsEvent,
43
+ syncBlockStore
44
+ })
21
45
  }];
22
46
  };
@@ -0,0 +1,127 @@
1
+ import { ACTION_SUBJECT, ACTION_SUBJECT_ID } from '@atlaskit/editor-common/analytics';
2
+ import { Experience, ExperienceCheckTimeout } from '@atlaskit/editor-common/experiences';
3
+ import { SafePlugin } from '@atlaskit/editor-common/safe-plugin';
4
+ import { PluginKey } from '@atlaskit/editor-prosemirror/state';
5
+ import { EXPERIENCE_ABORT_REASON } from '../../types';
6
+ const pluginKey = new PluginKey('providerOnlySyncBlockExperiences');
7
+ export const getProviderOnlyExperiencesPlugin = ({
8
+ refs,
9
+ dispatchAnalyticsEvent,
10
+ syncBlockStore
11
+ }) => {
12
+ const saveSourceExperience = getSaveSourceExperience({
13
+ refs,
14
+ dispatchAnalyticsEvent
15
+ });
16
+ syncBlockStore.sourceManager.setSaveExperience(saveSourceExperience);
17
+ const saveReferenceExperience = getSaveReferenceExperience({
18
+ refs,
19
+ dispatchAnalyticsEvent
20
+ });
21
+ const fetchExperience = getFetchExperience({
22
+ refs,
23
+ dispatchAnalyticsEvent
24
+ });
25
+ const fetchSourceInfoExperience = getFetchSourceInfoExperience({
26
+ refs,
27
+ dispatchAnalyticsEvent
28
+ });
29
+ syncBlockStore.referenceManager.setExperiences(fetchExperience, fetchSourceInfoExperience, saveReferenceExperience);
30
+ return new SafePlugin({
31
+ key: pluginKey,
32
+ view: () => {
33
+ return {
34
+ destroy: () => {
35
+ saveSourceExperience.abort({
36
+ reason: EXPERIENCE_ABORT_REASON.EDITOR_DESTROYED
37
+ });
38
+ saveReferenceExperience.abort({
39
+ reason: EXPERIENCE_ABORT_REASON.EDITOR_DESTROYED
40
+ });
41
+ fetchExperience.abort({
42
+ reason: EXPERIENCE_ABORT_REASON.EDITOR_DESTROYED
43
+ });
44
+ fetchSourceInfoExperience.abort({
45
+ reason: EXPERIENCE_ABORT_REASON.EDITOR_DESTROYED
46
+ });
47
+ }
48
+ };
49
+ }
50
+ });
51
+ };
52
+
53
+ /**
54
+ * This experience tracks when a source sync block is saved to the BE.
55
+ *
56
+ * Start: When the flush source sync block function is called.
57
+ * Success: When the sync block save is successful within 1500ms of start.
58
+ * Failure: When 1500ms passes without the sync block being successfully saved
59
+ */
60
+ const getSaveSourceExperience = ({
61
+ dispatchAnalyticsEvent
62
+ }) => {
63
+ return new Experience(ACTION_SUBJECT.SYNCED_BLOCK, {
64
+ actionSubjectId: ACTION_SUBJECT_ID.SYNCED_BLOCK_UPDATE,
65
+ dispatchAnalyticsEvent,
66
+ checks: [new ExperienceCheckTimeout({
67
+ durationMs: 1500
68
+ })]
69
+ });
70
+ };
71
+
72
+ /**
73
+ * This experience tracks when a reference sync block is saved to the BE.
74
+ *
75
+ * Start: When the flush sync block function is called.
76
+ * Success: When the sync block save is successful within 1500ms of start.
77
+ * Failure: When 1500ms passes without the sync block being successfully saved
78
+ */
79
+ const getSaveReferenceExperience = ({
80
+ dispatchAnalyticsEvent
81
+ }) => {
82
+ return new Experience(ACTION_SUBJECT.SYNCED_BLOCK, {
83
+ actionSubjectId: ACTION_SUBJECT_ID.REFERENCE_SYNCED_BLOCK_UPDATE,
84
+ dispatchAnalyticsEvent,
85
+ checks: [new ExperienceCheckTimeout({
86
+ durationMs: 1500
87
+ })]
88
+ });
89
+ };
90
+
91
+ /**
92
+ * This experience tracks when a reference sync block data is fetched from the BE.
93
+ *
94
+ * Start: When the fetchNodesData function is called.
95
+ * Success: When the fetching the data is successful within 1500ms of start.
96
+ * Failure: When 1500ms passes without the data being successfully fetched, or the fetch fails
97
+ */
98
+ const getFetchExperience = ({
99
+ dispatchAnalyticsEvent
100
+ }) => {
101
+ return new Experience(ACTION_SUBJECT.SYNCED_BLOCK, {
102
+ actionSubjectId: ACTION_SUBJECT_ID.SYNCED_BLOCK_FETCH,
103
+ dispatchAnalyticsEvent,
104
+ checks: [new ExperienceCheckTimeout({
105
+ durationMs: 1500
106
+ })]
107
+ });
108
+ };
109
+
110
+ /**
111
+ * This experience tracks when a reference sync block source info data (title, url) is fetched from the BE.
112
+ *
113
+ * Start: When the fetchSourceInfo function is called.
114
+ * Success: When the fetching the data is successful within 2500ms of start.
115
+ * Failure: When 2500ms passes without the data being successfully fetched, or the fetch fails
116
+ */
117
+ const getFetchSourceInfoExperience = ({
118
+ dispatchAnalyticsEvent
119
+ }) => {
120
+ return new Experience(ACTION_SUBJECT.SYNCED_BLOCK, {
121
+ actionSubjectId: ACTION_SUBJECT_ID.SYNCED_BLOCK_GET_SOURCE_INFO,
122
+ dispatchAnalyticsEvent,
123
+ checks: [new ExperienceCheckTimeout({
124
+ durationMs: 2500
125
+ })]
126
+ });
127
+ };
@@ -0,0 +1,65 @@
1
+ import { pmHistoryPluginKey } from '@atlaskit/editor-common/utils';
2
+ import { findChildren } from '@atlaskit/editor-prosemirror/utils';
3
+ let targetEl;
4
+ export const getTarget = containerElement => {
5
+ if (!targetEl) {
6
+ const element = containerElement === null || containerElement === void 0 ? void 0 : containerElement.querySelector('.ProseMirror');
7
+ if (!element || !(element instanceof HTMLElement)) {
8
+ return null;
9
+ }
10
+ targetEl = element;
11
+ }
12
+ return targetEl;
13
+ };
14
+ export const wasSyncBlockDeletedOrAddedByHistory = (tr, oldState, newState) => {
15
+ const historyMeta = tr.getMeta(pmHistoryPluginKey);
16
+ if (!Boolean(historyMeta)) {
17
+ return {};
18
+ }
19
+ const {
20
+ syncBlock
21
+ } = newState.schema.nodes;
22
+ const oldSyncBlockNodes = findChildren(oldState.doc, node => node.type === syncBlock);
23
+ const newSyncBlockNodes = findChildren(newState.doc, node => node.type === syncBlock);
24
+ const oldSyncBlockIds = new Set(oldSyncBlockNodes.map(nodeWithPos => nodeWithPos.node.attrs.localId).filter(localId => Boolean(localId)));
25
+ const newSyncBlockIds = new Set(newSyncBlockNodes.map(nodeWithPos => nodeWithPos.node.attrs.localId).filter(localId => Boolean(localId)));
26
+ const hasDeletedSyncBlock = Array.from(oldSyncBlockIds).some(localId => !newSyncBlockIds.has(localId));
27
+ const hasAddedSyncBlock = Array.from(newSyncBlockIds).some(localId => !oldSyncBlockIds.has(localId));
28
+ return {
29
+ hasDeletedSyncBlock,
30
+ hasAddedSyncBlock,
31
+ isUndo: historyMeta.redo === false
32
+ };
33
+ };
34
+ const getResourceIds = (nodes, resourceIds, query) => {
35
+ nodes.forEach(node => {
36
+ if (!(node instanceof HTMLElement)) {
37
+ return;
38
+ }
39
+ const syncBlockElements = node.querySelectorAll(query);
40
+ syncBlockElements.forEach(element => {
41
+ const resourceId = element.getAttribute('resourceid');
42
+ if (resourceId) {
43
+ resourceIds.push(resourceId);
44
+ }
45
+ });
46
+ });
47
+ };
48
+ export const getAddedResourceIds = (mutations, query) => {
49
+ const resourceIds = [];
50
+ mutations.forEach(mutation => {
51
+ if (mutation.type === 'childList') {
52
+ getResourceIds(mutation.addedNodes, resourceIds, query);
53
+ }
54
+ });
55
+ return resourceIds;
56
+ };
57
+ export const getRemovedResourceIds = (mutations, query) => {
58
+ const resourceIds = [];
59
+ mutations.forEach(mutation => {
60
+ if (mutation.type === 'childList') {
61
+ getResourceIds(mutation.removedNodes, resourceIds, query);
62
+ }
63
+ });
64
+ return resourceIds;
65
+ };
@@ -5,4 +5,7 @@ export let FLAG_ID = /*#__PURE__*/function (FLAG_ID) {
5
5
  FLAG_ID["FAIL_TO_DELETE"] = "fail-to-delete";
6
6
  FLAG_ID["SYNC_BLOCK_COPIED"] = "sync-block-copied";
7
7
  return FLAG_ID;
8
- }({});
8
+ }({});
9
+ export const EXPERIENCE_ABORT_REASON = {
10
+ EDITOR_DESTROYED: 'editor-destroyed'
11
+ };
@@ -43,17 +43,48 @@ const CreateSyncedBlockDropdownItem = ({
43
43
  }),
44
44
  onClick: onClick,
45
45
  isDisabled: isOffline,
46
- testId: 'create-synced-block-block-menu-btn',
46
+ testId: "create-synced-block-block-menu-btn",
47
47
  elemAfter: /*#__PURE__*/React.createElement(Lozenge, {
48
48
  appearance: "new"
49
49
  }, formatMessage(blockMenuMessages.newLozenge))
50
50
  }, formatMessage(blockMenuMessages.createSyncedBlock));
51
51
  };
52
+ const CopySyncedBlockDropdownItem = ({
53
+ api
54
+ }) => {
55
+ const {
56
+ formatMessage
57
+ } = useIntl();
58
+ const {
59
+ mode
60
+ } = useSharedPluginStateWithSelector(api, ['connectivity'], states => {
61
+ var _states$connectivityS2;
62
+ return {
63
+ mode: (_states$connectivityS2 = states.connectivityState) === null || _states$connectivityS2 === void 0 ? void 0 : _states$connectivityS2.mode
64
+ };
65
+ });
66
+ const onClick = () => {
67
+ var _api$core3, _api$core4, _api$blockControls2, _api$blockControls2$c;
68
+ api === null || api === void 0 ? void 0 : (_api$core3 = api.core) === null || _api$core3 === void 0 ? void 0 : _api$core3.actions.execute(api === null || api === void 0 ? void 0 : api.syncedBlock.commands.copySyncedBlockReferenceToClipboard());
69
+ api === null || api === void 0 ? void 0 : (_api$core4 = api.core) === null || _api$core4 === void 0 ? void 0 : _api$core4.actions.execute(api === null || api === void 0 ? void 0 : (_api$blockControls2 = api.blockControls) === null || _api$blockControls2 === void 0 ? void 0 : (_api$blockControls2$c = _api$blockControls2.commands) === null || _api$blockControls2$c === void 0 ? void 0 : _api$blockControls2$c.toggleBlockMenu({
70
+ closeMenu: true
71
+ }));
72
+ };
73
+ return /*#__PURE__*/React.createElement(ToolbarDropdownItem, {
74
+ elemBefore: /*#__PURE__*/React.createElement(SyncBlocksIcon, {
75
+ label: ""
76
+ }),
77
+ onClick: onClick,
78
+ isDisabled: isOfflineMode(mode),
79
+ elemAfter: /*#__PURE__*/React.createElement(Lozenge, {
80
+ appearance: "new"
81
+ }, formatMessage(blockMenuMessages.newLozenge))
82
+ }, formatMessage(blockMenuMessages.copySyncedBlock));
83
+ };
52
84
  export const CreateOrCopySyncedBlockDropdownItem = ({
53
85
  api,
54
86
  enableSourceSyncedBlockCreation
55
87
  }) => {
56
- var _menuTriggerByNode$no;
57
88
  const {
58
89
  menuTriggerByNode
59
90
  } = useSharedPluginStateWithSelector(api, ['blockControls'], states => {
@@ -62,7 +93,11 @@ export const CreateOrCopySyncedBlockDropdownItem = ({
62
93
  menuTriggerByNode: (_states$blockControls3 = (_states$blockControls4 = states.blockControlsState) === null || _states$blockControls4 === void 0 ? void 0 : _states$blockControls4.menuTriggerByNode) !== null && _states$blockControls3 !== void 0 ? _states$blockControls3 : undefined
63
94
  };
64
95
  });
65
- if (!['syncBlock', 'bodiedSyncBlock'].includes((_menuTriggerByNode$no = menuTriggerByNode === null || menuTriggerByNode === void 0 ? void 0 : menuTriggerByNode.nodeType) !== null && _menuTriggerByNode$no !== void 0 ? _menuTriggerByNode$no : '') && enableSourceSyncedBlockCreation) {
96
+ if ((menuTriggerByNode === null || menuTriggerByNode === void 0 ? void 0 : menuTriggerByNode.nodeType) === 'syncBlock' || (menuTriggerByNode === null || menuTriggerByNode === void 0 ? void 0 : menuTriggerByNode.nodeType) === 'bodiedSyncBlock') {
97
+ return /*#__PURE__*/React.createElement(CopySyncedBlockDropdownItem, {
98
+ api: api
99
+ });
100
+ } else if (enableSourceSyncedBlockCreation) {
66
101
  return /*#__PURE__*/React.createElement(CreateSyncedBlockDropdownItem, {
67
102
  api: api
68
103
  });
@@ -5,6 +5,7 @@ import { useSharedPluginStateWithSelector } from '@atlaskit/editor-common/hooks'
5
5
  import { syncBlockMessages as messages } from '@atlaskit/editor-common/messages';
6
6
  import { isOfflineMode } from '@atlaskit/editor-plugin-connectivity';
7
7
  import ModalDialog, { ModalBody, ModalFooter, ModalHeader, ModalTitle, ModalTransition } from '@atlaskit/modal-dialog';
8
+ import { fg } from '@atlaskit/platform-feature-flags';
8
9
  import { Text } from '@atlaskit/primitives/compiled';
9
10
  import { syncedBlockPluginKey } from '../pm-plugins/main';
10
11
  export const DeleteConfirmationModal = ({
@@ -105,6 +106,7 @@ export const DeleteConfirmationModal = ({
105
106
  onClick: handleClick(true),
106
107
  autoFocus: true,
107
108
  isDisabled: isOfflineMode(mode),
108
- isLoading: bodiedSyncBlockDeletionStatus === 'processing'
109
+ isLoading: bodiedSyncBlockDeletionStatus === 'processing',
110
+ testId: fg('platform_synced_block_dogfooding') ? 'synced-block-delete-confirmation-modal-delete-button' : undefined
109
111
  }, formatMessage(messages.deleteConfirmationModalDeleteButton)))));
110
112
  };
@@ -6,6 +6,7 @@ import { SyncBlockError } from '@atlaskit/editor-synced-block-provider';
6
6
  import CopyIcon from '@atlaskit/icon/core/copy';
7
7
  import DeleteIcon from '@atlaskit/icon/core/delete';
8
8
  import EditIcon from '@atlaskit/icon/core/edit';
9
+ import { fg } from '@atlaskit/platform-feature-flags';
9
10
  import { copySyncedBlockReferenceToClipboard, editSyncedBlockSource, removeSyncedBlock } from '../editor-commands';
10
11
  import { findSyncBlockOrBodiedSyncBlock, isBodiedSyncBlockNode } from '../pm-plugins/utils/utils';
11
12
  export const getToolbarConfig = (state, intl, api, syncBlockStore) => {
@@ -42,6 +43,7 @@ export const getToolbarConfig = (state, intl, api, syncBlockStore) => {
42
43
  title: formatMessage(commonMessages.delete),
43
44
  onClick: removeSyncedBlock(api),
44
45
  icon: DeleteIcon,
46
+ testId: fg('platform_synced_block_dogfooding') ? 'reference-synced-block-delete-button' : undefined,
45
47
  ...hoverDecorationProps(nodeType, akEditorSelectedNodeClassName)
46
48
  };
47
49
  items.push(deleteButton);
@@ -53,7 +55,7 @@ export const getToolbarConfig = (state, intl, api, syncBlockStore) => {
53
55
  icon: CopyIcon,
54
56
  title: formatMessage(messages.copySyncBlockLabel),
55
57
  showTitle: false,
56
- tooltipContent: formatMessage(messages.copySyncBlockTooltip),
58
+ tooltipContent: formatMessage(messages.copySyncedBlockTooltip),
57
59
  onClick: copySyncedBlockReferenceToClipboard(syncBlockStore, api),
58
60
  ...hoverDecorationProps(nodeType, akEditorSelectedNodeClassName)
59
61
  };
@@ -53,8 +53,8 @@ export var createSyncedBlock = function createSyncedBlock(_ref) {
53
53
  syncBlockStore.sourceManager.createBodiedSyncBlockNode(_attrs);
54
54
  tr.replaceWith(conversionInfo.from > 0 ? conversionInfo.from - 1 : 0, conversionInfo.to, _newBodiedSyncBlockNode).scrollIntoView();
55
55
 
56
- // set selection to the end of the previous selection + 1 for the position taken up by the start of the new synced block
57
- tr.setSelection(TextSelection.create(tr.doc, conversionInfo.to + 1));
56
+ // set selection to the start of the previous selection for the position taken up by the start of the new synced block
57
+ tr.setSelection(TextSelection.create(tr.doc, conversionInfo.from));
58
58
  }
59
59
 
60
60
  // This transaction will be intercepted in filterTransaction and dispatched when saving to backend succeeds
@@ -1,17 +1,17 @@
1
- import _toConsumableArray from "@babel/runtime/helpers/toConsumableArray";
2
1
  import { ACTION_SUBJECT, ACTION_SUBJECT_ID } from '@atlaskit/editor-common/analytics';
3
2
  import { Experience, ExperienceCheckDomMutation, ExperienceCheckTimeout } from '@atlaskit/editor-common/experiences';
4
3
  import { SafePlugin } from '@atlaskit/editor-common/safe-plugin';
5
4
  import { PluginKey } from '@atlaskit/editor-prosemirror/state';
5
+ import { EXPERIENCE_ABORT_REASON } from '../../types';
6
+ import { getAddedResourceIds, wasSyncBlockDeletedOrAddedByHistory, getTarget } from '../utils/experience-tracking-utils';
6
7
  var isPastedFromFabricEditor = function isPastedFromFabricEditor(html) {
7
8
  return !!html && html.indexOf('data-pm-slice="') >= 0;
8
9
  };
9
10
  var pluginKey = new PluginKey('createReferenceSyncBlockExperience');
10
11
  var START_METHOD = {
11
- PASTE: 'paste'
12
- };
13
- var ABORT_REASON = {
14
- EDITOR_DESTROYED: 'editor-destroyed'
12
+ PASTE: 'paste',
13
+ UNDO: 'undo',
14
+ REDO: 'redo'
15
15
  };
16
16
 
17
17
  /**
@@ -34,7 +34,7 @@ export var getCreateReferenceExperiencePlugin = function getCreateReferenceExper
34
34
  return {
35
35
  destroy: function destroy() {
36
36
  experience.abort({
37
- reason: ABORT_REASON.EDITOR_DESTROYED
37
+ reason: EXPERIENCE_ABORT_REASON.EDITOR_DESTROYED
38
38
  });
39
39
  }
40
40
  };
@@ -56,6 +56,19 @@ export var getCreateReferenceExperiencePlugin = function getCreateReferenceExper
56
56
  });
57
57
  }
58
58
  }
59
+ },
60
+ appendTransaction: function appendTransaction(transactions, oldState, newState) {
61
+ transactions.forEach(function (tr) {
62
+ var _wasSyncBlockDeletedO = wasSyncBlockDeletedOrAddedByHistory(tr, oldState, newState),
63
+ hasAddedSyncBlock = _wasSyncBlockDeletedO.hasAddedSyncBlock,
64
+ isUndo = _wasSyncBlockDeletedO.isUndo;
65
+ if (hasAddedSyncBlock) {
66
+ experience.start({
67
+ method: isUndo ? START_METHOD.UNDO : START_METHOD.REDO
68
+ });
69
+ }
70
+ });
71
+ return null;
59
72
  }
60
73
  });
61
74
  };
@@ -70,21 +83,20 @@ var getCreateReferenceExperience = function getCreateReferenceExperience(_ref2)
70
83
  }), new ExperienceCheckDomMutation({
71
84
  onDomMutation: function onDomMutation(_ref3) {
72
85
  var mutations = _ref3.mutations;
73
- if (mutations.some(isReferenceSyncBlockAddedInMutation)) {
86
+ var insertedResourceIds = getAddedResourceIds(mutations, '[data-prosemirror-node-name="syncBlock"]');
87
+ if (insertedResourceIds.length > 0) {
74
88
  return {
75
- status: 'success'
89
+ status: 'success',
90
+ metadata: {
91
+ insertedResourceIds: insertedResourceIds
92
+ }
76
93
  };
77
94
  }
78
95
  return undefined;
79
96
  },
80
97
  observeConfig: function observeConfig() {
81
- var _refs$containerElemen;
82
- var proseMirrorElement = (_refs$containerElemen = refs.containerElement) === null || _refs$containerElemen === void 0 ? void 0 : _refs$containerElemen.querySelector('.ProseMirror');
83
- if (!proseMirrorElement || !(proseMirrorElement instanceof HTMLElement)) {
84
- return null;
85
- }
86
98
  return {
87
- target: proseMirrorElement,
99
+ target: getTarget(refs.containerElement),
88
100
  options: {
89
101
  childList: true
90
102
  }
@@ -92,15 +104,4 @@ var getCreateReferenceExperience = function getCreateReferenceExperience(_ref2)
92
104
  }
93
105
  })]
94
106
  });
95
- };
96
- var isReferenceSyncBlockAddedInMutation = function isReferenceSyncBlockAddedInMutation(_ref4) {
97
- var type = _ref4.type,
98
- addedNodes = _ref4.addedNodes;
99
- return type === 'childList' && _toConsumableArray(addedNodes).some(isReferenceSyncBlockNode);
100
- };
101
- var isReferenceSyncBlockNode = function isReferenceSyncBlockNode(node) {
102
- if (!(node instanceof HTMLElement)) {
103
- return false;
104
- }
105
- return !!node.querySelector('[data-prosemirror-node-name="syncBlock"]');
106
107
  };
@@ -1,13 +1,11 @@
1
- import _toConsumableArray from "@babel/runtime/helpers/toConsumableArray";
2
1
  import { bind } from 'bind-event-listener';
3
2
  import { ACTION_SUBJECT, ACTION_SUBJECT_ID } from '@atlaskit/editor-common/analytics';
4
3
  import { Experience, ExperienceCheckDomMutation, ExperienceCheckTimeout, getPopupContainerFromEditorView, popupWithNestedElement } from '@atlaskit/editor-common/experiences';
5
4
  import { SafePlugin } from '@atlaskit/editor-common/safe-plugin';
6
5
  import { PluginKey } from '@atlaskit/editor-prosemirror/state';
6
+ import { EXPERIENCE_ABORT_REASON } from '../../types';
7
+ import { getAddedResourceIds, getTarget } from '../utils/experience-tracking-utils';
7
8
  var pluginKey = new PluginKey('createSourceSyncBlockExperience');
8
- var ABORT_REASON = {
9
- EDITOR_DESTROYED: 'editor-destroyed'
10
- };
11
9
  var START_METHOD = {
12
10
  BLOCK_MENU: 'block-menu',
13
11
  PINNED_TOOLBAR: 'pinned-toolbar',
@@ -20,8 +18,8 @@ var syncedBlockCreateButtonIds = new Set(SYNCED_BLOCK_CREATE_BUTTON_IDS);
20
18
  * This experience tracks when a source sync block is inserted.
21
19
  *
22
20
  * Start: When user inserts a sync block via block menu, quick insert or pinned toolbar
23
- * Success: When the sync block is added to the DOM within 2000ms of start
24
- * Failure: When 500ms passes without the source sync block being added to the DOM
21
+ * Success: When the sync block is added to the DOM within 3000ms of start
22
+ * Failure: When 3000ms passes without the source sync block being added to the DOM
25
23
  */
26
24
  export var getCreateSourceExperiencePlugin = function getCreateSourceExperiencePlugin(_ref) {
27
25
  var refs = _ref.refs,
@@ -37,8 +35,7 @@ export var getCreateSourceExperiencePlugin = function getCreateSourceExperienceP
37
35
  };
38
36
  var experience = getCreateSourceExperience({
39
37
  refs: refs,
40
- dispatchAnalyticsEvent: dispatchAnalyticsEvent,
41
- syncBlockStore: syncBlockStore
38
+ dispatchAnalyticsEvent: dispatchAnalyticsEvent
42
39
  });
43
40
  syncBlockStore.sourceManager.setCreateExperience(experience);
44
41
  var unbindClickListener = bind(document, {
@@ -90,7 +87,7 @@ export var getCreateSourceExperiencePlugin = function getCreateSourceExperienceP
90
87
  return {
91
88
  destroy: function destroy() {
92
89
  experience.abort({
93
- reason: ABORT_REASON.EDITOR_DESTROYED
90
+ reason: EXPERIENCE_ABORT_REASON.EDITOR_DESTROYED
94
91
  });
95
92
  unbindClickListener();
96
93
  unbindKeydownListener();
@@ -106,25 +103,24 @@ var getCreateSourceExperience = function getCreateSourceExperience(_ref2) {
106
103
  actionSubjectId: ACTION_SUBJECT_ID.SYNCED_BLOCK_CREATE,
107
104
  dispatchAnalyticsEvent: dispatchAnalyticsEvent,
108
105
  checks: [new ExperienceCheckTimeout({
109
- durationMs: 2000
106
+ durationMs: 3000
110
107
  }), new ExperienceCheckDomMutation({
111
108
  onDomMutation: function onDomMutation(_ref3) {
112
109
  var mutations = _ref3.mutations;
113
- if (mutations.some(isSourceSyncBlockAddedInMutation)) {
110
+ var createdResourceIds = getAddedResourceIds(mutations, '[data-prosemirror-node-name="bodiedSyncBlock"]');
111
+ if (createdResourceIds.length > 0) {
114
112
  return {
115
- status: 'success'
113
+ status: 'success',
114
+ metadata: {
115
+ createdResourceIds: createdResourceIds
116
+ }
116
117
  };
117
118
  }
118
119
  return undefined;
119
120
  },
120
121
  observeConfig: function observeConfig() {
121
- var _refs$containerElemen;
122
- var proseMirrorElement = (_refs$containerElemen = refs.containerElement) === null || _refs$containerElemen === void 0 ? void 0 : _refs$containerElemen.querySelector('.ProseMirror');
123
- if (!proseMirrorElement || !(proseMirrorElement instanceof HTMLElement)) {
124
- return null;
125
- }
126
122
  return {
127
- target: proseMirrorElement,
123
+ target: getTarget(refs.containerElement),
128
124
  options: {
129
125
  childList: true
130
126
  }
@@ -164,15 +160,4 @@ var handleButtonClick = function handleButtonClick(testId, experience) {
164
160
  };
165
161
  var isEnterKey = function isEnterKey(key) {
166
162
  return key === 'Enter';
167
- };
168
- var isSourceSyncBlockAddedInMutation = function isSourceSyncBlockAddedInMutation(_ref4) {
169
- var type = _ref4.type,
170
- addedNodes = _ref4.addedNodes;
171
- return type === 'childList' && _toConsumableArray(addedNodes).some(isSourceSyncBlockNode);
172
- };
173
- var isSourceSyncBlockNode = function isSourceSyncBlockNode(node) {
174
- if (!(node instanceof HTMLElement)) {
175
- return false;
176
- }
177
- return !!node.querySelector('[data-prosemirror-node-name="bodiedSyncBlock"]');
178
163
  };