@atlaskit/editor-plugin-synced-block 5.3.7 → 5.3.9

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.
@@ -1,7 +1,9 @@
1
+ import { expandSelectionToBlockRange } from '@atlaskit/editor-common/selection';
1
2
  import { Fragment } from '@atlaskit/editor-prosemirror/model';
2
3
  import { TextSelection } from '@atlaskit/editor-prosemirror/state';
3
4
  import { findParentNodeOfType, findSelectedNodeOfType } from '@atlaskit/editor-prosemirror/utils';
4
5
  import { CellSelection, findTable } from '@atlaskit/editor-tables';
6
+ import { fg } from '@atlaskit/platform-feature-flags';
5
7
  export const findSyncBlock = (schema, selection) => {
6
8
  const {
7
9
  syncBlock
@@ -26,6 +28,9 @@ const UNSUPPORTED_NODE_TYPES = new Set(['inlineExtension', 'extension', 'bodiedE
26
28
  * or false if conversion is not possible
27
29
  */
28
30
  export const canBeConvertedToSyncBlock = selection => {
31
+ return fg('platform_synced_block_dogfooding') ? canBeConvertedToSyncBlockNew(selection) : canBeConvertedToSyncBlockOld(selection);
32
+ };
33
+ export const canBeConvertedToSyncBlockOld = selection => {
29
34
  const schema = selection.$from.doc.type.schema;
30
35
  const {
31
36
  nodes
@@ -66,6 +71,33 @@ export const canBeConvertedToSyncBlock = selection => {
66
71
  to
67
72
  };
68
73
  };
74
+ export const canBeConvertedToSyncBlockNew = selection => {
75
+ const {
76
+ $from,
77
+ range
78
+ } = expandSelectionToBlockRange(selection);
79
+ if (!range) {
80
+ return false;
81
+ }
82
+ const from = range.start;
83
+ const to = range.end;
84
+ let canBeConverted = true;
85
+ $from.doc.nodesBetween(from, to, node => {
86
+ if (UNSUPPORTED_NODE_TYPES.has(node.type.name)) {
87
+ canBeConverted = false;
88
+ return false;
89
+ }
90
+ });
91
+ if (!canBeConverted) {
92
+ return false;
93
+ }
94
+ const contentToInclude = removeBreakoutMarks($from.doc.slice(from, to).content);
95
+ return {
96
+ contentToInclude,
97
+ from,
98
+ to
99
+ };
100
+ };
69
101
  const removeBreakoutMarks = content => {
70
102
  const nodes = [];
71
103
 
@@ -14,10 +14,10 @@ import Spinner from '@atlaskit/spinner';
14
14
  import { syncedBlockPluginKey } from '../pm-plugins/main';
15
15
  const modalContentMap = {
16
16
  'source-block-deleted': {
17
- titleMultiple: messages.deleteConfirmationModalTitleSingle,
17
+ titleMultiple: messages.deleteConfirmationModalTitleMultiple,
18
18
  titleSingle: messages.deleteConfirmationModalTitleSingle,
19
19
  descriptionSingle: messages.deleteConfirmationModalDescriptionNoRef,
20
- descriptionMultiple: messages.deleteConfirmationModalDescription,
20
+ descriptionMultiple: messages.deleteConfirmationModalDescriptionMultiple,
21
21
  confirmButtonLabel: messages.deleteConfirmationModalDeleteButton
22
22
  },
23
23
  'source-block-unsynced': {
@@ -40,7 +40,6 @@ export const DeleteConfirmationModal = ({
40
40
  const [syncBlockIds, setSyncBlockIds] = useState(undefined);
41
41
  const [referenceCount, setReferenceCount] = useState(undefined);
42
42
  const [deleteReason, setDeleteReason] = useState('source-block-deleted');
43
- const [fetchStatus, setFetchStatus] = useState('none');
44
43
  const {
45
44
  mode,
46
45
  bodiedSyncBlockDeletionStatus,
@@ -65,7 +64,6 @@ export const DeleteConfirmationModal = ({
65
64
  }
66
65
  if (!confirm) {
67
66
  setIsOpen(false);
68
- setFetchStatus('none');
69
67
  setReferenceCount(undefined);
70
68
  }
71
69
  api === null || api === void 0 ? void 0 : (_api$core = api.core) === null || _api$core === void 0 ? void 0 : _api$core.actions.execute(({
@@ -110,7 +108,6 @@ export const DeleteConfirmationModal = ({
110
108
  var _api$core5;
111
109
  // auto close modal once deletion is successful
112
110
  setIsOpen(false);
113
- setFetchStatus('none');
114
111
  api === null || api === void 0 ? void 0 : (_api$core5 = api.core) === null || _api$core5 === void 0 ? void 0 : _api$core5.actions.execute(({
115
112
  tr
116
113
  }) => {
@@ -123,28 +120,24 @@ export const DeleteConfirmationModal = ({
123
120
  }, [api === null || api === void 0 ? void 0 : (_api$core6 = api.core) === null || _api$core6 === void 0 ? void 0 : _api$core6.actions, bodiedSyncBlockDeletionStatus, isOpen]);
124
121
  useEffect(() => {
125
122
  if (isOpen && syncBlockIds !== undefined && fg('platform_synced_block_dogfooding')) {
126
- let referenceCount = 0;
127
- setFetchStatus('loading');
128
- let fetchFailed = false;
129
- syncBlockIds.forEach(async syncBlockId => {
130
- if (fetchFailed) {
131
- return;
123
+ const fetchReferences = async () => {
124
+ try {
125
+ const references = await Promise.all(syncBlockIds.map(async syncBlockId => {
126
+ var _references$reference, _references$reference2;
127
+ const references = await syncBlockStoreManager.sourceManager.fetchReferences(syncBlockId.resourceId);
128
+ if (references !== null && references !== void 0 && references.error) {
129
+ // Consider fetch fails as soon as one of the fetches fails
130
+ throw new Error();
131
+ }
132
+ return (_references$reference = (_references$reference2 = references.references) === null || _references$reference2 === void 0 ? void 0 : _references$reference2.length) !== null && _references$reference !== void 0 ? _references$reference : 0;
133
+ }));
134
+ const totalCount = references.reduce((sum, count) => sum + count, 0);
135
+ setReferenceCount(totalCount);
136
+ } catch {
137
+ setReferenceCount(0);
132
138
  }
133
- const references = await syncBlockStoreManager.sourceManager.fetchReferences(syncBlockId.resourceId);
134
- if (references.error) {
135
- // Consider fetch fails as soon as one of the fetches fails
136
- setFetchStatus('error');
137
- fetchFailed = true;
138
- return;
139
- } else {
140
- var _references$reference, _references$reference2;
141
- referenceCount += (_references$reference = (_references$reference2 = references.references) === null || _references$reference2 === void 0 ? void 0 : _references$reference2.length) !== null && _references$reference !== void 0 ? _references$reference : 0;
142
- }
143
- });
144
- if (!fetchFailed) {
145
- setReferenceCount(referenceCount);
146
- setFetchStatus('success');
147
- }
139
+ };
140
+ fetchReferences();
148
141
  }
149
142
  }, [isOpen, syncBlockIds, syncBlockStoreManager.sourceManager]);
150
143
  return /*#__PURE__*/React.createElement(ModalTransition, null, isOpen && /*#__PURE__*/React.createElement(ModalDialog, {
@@ -163,7 +156,7 @@ export const DeleteConfirmationModal = ({
163
156
  isDeleting: bodiedSyncBlockDeletionStatus === 'processing',
164
157
  isDisabled: isOfflineMode(mode),
165
158
  deleteReason: deleteReason,
166
- failToFetch: fetchStatus === 'error'
159
+ sourceCount: (syncBlockIds === null || syncBlockIds === void 0 ? void 0 : syncBlockIds.length) || 0
167
160
  })) : /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(ModalHeader, {
168
161
  hasCloseButton: true
169
162
  }, /*#__PURE__*/React.createElement(ModalTitle, {
@@ -189,7 +182,7 @@ const ModalContent = ({
189
182
  isDeleting,
190
183
  isDisabled,
191
184
  deleteReason,
192
- failToFetch
185
+ sourceCount
193
186
  }) => {
194
187
  const {
195
188
  titleMultiple,
@@ -198,15 +191,16 @@ const ModalContent = ({
198
191
  descriptionMultiple,
199
192
  confirmButtonLabel
200
193
  } = content;
201
- const hasNoReferenceOrFailToFetch = referenceCount === 0 || failToFetch;
194
+ const hasNoReferenceOrFailToFetch = referenceCount === 0;
195
+ const syncBlockCount = deleteReason === 'source-block-deleted' ? referenceCount + sourceCount : referenceCount;
202
196
  return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(ModalHeader, {
203
197
  hasCloseButton: true
204
198
  }, /*#__PURE__*/React.createElement(ModalTitle, {
205
199
  appearance: "warning"
206
200
  }, hasNoReferenceOrFailToFetch ? formatMessage(titleSingle) : formatMessage(titleMultiple, {
207
- count: referenceCount
201
+ count: syncBlockCount
208
202
  }))), /*#__PURE__*/React.createElement(ModalBody, null, /*#__PURE__*/React.createElement(Text, null, hasNoReferenceOrFailToFetch ? formatMessage(descriptionSingle) : formatMessage(descriptionMultiple, {
209
- syncBlockCount: referenceCount
203
+ syncBlockCount
210
204
  }))), /*#__PURE__*/React.createElement(ModalFooter, null, /*#__PURE__*/React.createElement(Button, {
211
205
  appearance: "subtle",
212
206
  onClick: handleClick(false)
@@ -1,4 +1,4 @@
1
- import React, { useCallback, useState } from 'react';
1
+ import React, { useCallback, useMemo, useState } from 'react';
2
2
  import { useIntl } from 'react-intl-next';
3
3
  import { syncBlockMessages as messages } from '@atlaskit/editor-common/messages';
4
4
  import { SyncBlockLabelSharedCssClassName } from '@atlaskit/editor-common/sync-block';
@@ -13,7 +13,8 @@ const SyncBlockLabelComponent = ({
13
13
  contentUpdatedAt,
14
14
  isSource,
15
15
  localId,
16
- title
16
+ title,
17
+ isUnsyncedBlock
17
18
  }) => {
18
19
  const intl = useIntl();
19
20
  const {
@@ -50,6 +51,25 @@ const SyncBlockLabelComponent = ({
50
51
  setTooltipContent(tooltipContent);
51
52
  }, [contentUpdatedAt, formatMessage, intl, tooltipMessage]);
52
53
  const ariaDescribedById = `sync-block-label-description-${localId}`;
54
+ const getLabelContent = useMemo(() => {
55
+ if (isUnsyncedBlock && fg('platform_synced_block_dogfooding')) {
56
+ return /*#__PURE__*/React.createElement(Text, {
57
+ size: "small",
58
+ color: "color.text.subtle"
59
+ }, formatMessage(messages.unsyncedBlockLabel));
60
+ }
61
+ if (isSource || !title) {
62
+ return /*#__PURE__*/React.createElement(Text, {
63
+ size: "small",
64
+ color: "color.text.subtle"
65
+ }, formatMessage(messages.syncedBlockLabel));
66
+ }
67
+ return /*#__PURE__*/React.createElement(Text, {
68
+ maxLines: 1,
69
+ size: "small",
70
+ color: "color.text.subtle"
71
+ }, title);
72
+ }, [formatMessage, isSource, isUnsyncedBlock, title]);
53
73
  const label = /*#__PURE__*/React.createElement("div", {
54
74
  "data-testid": SyncBlockLabelDataId
55
75
  // eslint-disable-next-line @atlaskit/ui-styling-standard/no-classname-prop
@@ -60,15 +80,8 @@ const SyncBlockLabelComponent = ({
60
80
  color: "var(--ds-icon-subtle, #505258)",
61
81
  size: "small",
62
82
  label: ""
63
- }), isSource || !title ? /*#__PURE__*/React.createElement(Text, {
64
- size: "small",
65
- color: "color.text.subtle"
66
- }, formatMessage(messages.syncedBlockLabel)) : /*#__PURE__*/React.createElement(Text, {
67
- maxLines: 1,
68
- size: "small",
69
- color: "color.text.subtle"
70
- }, title));
71
- if (isSource && fg('platform_synced_block_dogfooding')) {
83
+ }), getLabelContent);
84
+ if ((isSource || isUnsyncedBlock) && fg('platform_synced_block_dogfooding')) {
72
85
  return label;
73
86
  }
74
87
  return /*#__PURE__*/React.createElement(Tooltip, {
@@ -1,5 +1,6 @@
1
1
  import React from 'react';
2
2
  import { SyncBlockSharedCssClassName } from '@atlaskit/editor-common/sync-block';
3
+ import { SyncBlockError } from '@atlaskit/editor-synced-block-provider';
3
4
  import { SyncBlockLabel } from './SyncBlockLabel';
4
5
  const SyncBlockRendererWrapperDataId = 'sync-block-plugin-renderer-wrapper';
5
6
  const SyncBlockRendererWrapperComponent = ({
@@ -9,10 +10,12 @@ const SyncBlockRendererWrapperComponent = ({
9
10
  localId,
10
11
  api
11
12
  }) => {
12
- var _syncBlockFetchResult, _syncBlockFetchResult2;
13
+ var _syncBlockFetchResult, _syncBlockFetchResult2, _syncBlockFetchResult3, _syncBlockFetchResult4, _syncBlockFetchResult5, _syncBlockFetchResult6;
13
14
  const syncBlockFetchResult = useFetchSyncBlockData();
14
15
  const title = useFetchSyncBlockTitle === null || useFetchSyncBlockTitle === void 0 ? void 0 : useFetchSyncBlockTitle();
15
16
  const contentUpdatedAt = syncBlockFetchResult === null || syncBlockFetchResult === void 0 ? void 0 : (_syncBlockFetchResult = syncBlockFetchResult.syncBlockInstance) === null || _syncBlockFetchResult === void 0 ? void 0 : (_syncBlockFetchResult2 = _syncBlockFetchResult.data) === null || _syncBlockFetchResult2 === void 0 ? void 0 : _syncBlockFetchResult2.contentUpdatedAt;
17
+ const isUnpublishedBlock = ((_syncBlockFetchResult3 = syncBlockFetchResult.syncBlockInstance) === null || _syncBlockFetchResult3 === void 0 ? void 0 : (_syncBlockFetchResult4 = _syncBlockFetchResult3.data) === null || _syncBlockFetchResult4 === void 0 ? void 0 : _syncBlockFetchResult4.status) === 'unpublished';
18
+ const isUnsyncedBlock = isUnpublishedBlock || (syncBlockFetchResult === null || syncBlockFetchResult === void 0 ? void 0 : (_syncBlockFetchResult5 = syncBlockFetchResult.syncBlockInstance) === null || _syncBlockFetchResult5 === void 0 ? void 0 : (_syncBlockFetchResult6 = _syncBlockFetchResult5.error) === null || _syncBlockFetchResult6 === void 0 ? void 0 : _syncBlockFetchResult6.type) === SyncBlockError.NotFound;
16
19
  return /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("div", {
17
20
  "data-testid": SyncBlockRendererWrapperDataId
18
21
  // eslint-disable-next-line @atlaskit/ui-styling-standard/no-classname-prop
@@ -25,7 +28,8 @@ const SyncBlockRendererWrapperComponent = ({
25
28
  isSource: false,
26
29
  title: title,
27
30
  contentUpdatedAt: contentUpdatedAt,
28
- localId: localId
31
+ localId: localId,
32
+ isUnsyncedBlock: isUnsyncedBlock
29
33
  }));
30
34
  };
31
35
  export const SyncBlockRendererWrapper = /*#__PURE__*/React.memo(SyncBlockRendererWrapperComponent);
@@ -24,6 +24,17 @@ export var createSyncedBlock = function createSyncedBlock(_ref) {
24
24
  var paragraphNode = paragraph.createAndFill({});
25
25
  var newBodiedSyncBlockNode = bodiedSyncBlock.createAndFill(attrs, paragraphNode ? [paragraphNode] : []);
26
26
  if (!newBodiedSyncBlockNode) {
27
+ if (fg('platform_synced_block_dogfooding')) {
28
+ fireAnalyticsEvent === null || fireAnalyticsEvent === void 0 || fireAnalyticsEvent({
29
+ action: ACTION.ERROR,
30
+ actionSubject: ACTION_SUBJECT.SYNCED_BLOCK,
31
+ actionSubjectId: ACTION_SUBJECT_ID.SYNCED_BLOCK_CREATE,
32
+ attributes: {
33
+ error: 'Create and fill for empty content failed'
34
+ },
35
+ eventType: EVENT_TYPE.OPERATIONAL
36
+ });
37
+ }
27
38
  return false;
28
39
  }
29
40
 
@@ -54,6 +65,17 @@ export var createSyncedBlock = function createSyncedBlock(_ref) {
54
65
  var _attrs = syncBlockStore.sourceManager.generateBodiedSyncBlockAttrs();
55
66
  var _newBodiedSyncBlockNode = bodiedSyncBlock.createAndFill(_attrs, conversionInfo.contentToInclude);
56
67
  if (!_newBodiedSyncBlockNode) {
68
+ if (fg('platform_synced_block_dogfooding')) {
69
+ fireAnalyticsEvent === null || fireAnalyticsEvent === void 0 || fireAnalyticsEvent({
70
+ action: ACTION.ERROR,
71
+ actionSubject: ACTION_SUBJECT.SYNCED_BLOCK,
72
+ actionSubjectId: ACTION_SUBJECT_ID.SYNCED_BLOCK_CREATE,
73
+ attributes: {
74
+ error: 'Create and fill for content failed'
75
+ },
76
+ eventType: EVENT_TYPE.OPERATIONAL
77
+ });
78
+ }
57
79
  return false;
58
80
  }
59
81
 
@@ -172,7 +194,17 @@ export var removeSyncedBlock = function removeSyncedBlock(api) {
172
194
  return true;
173
195
  };
174
196
  };
175
-
197
+ export var removeSyncedBlockAtPos = function removeSyncedBlockAtPos(api, pos) {
198
+ api === null || api === void 0 || api.core.actions.execute(function (_ref4) {
199
+ var tr = _ref4.tr;
200
+ var node = tr.doc.nodeAt(pos);
201
+ if ((node === null || node === void 0 ? void 0 : node.type.name) === 'syncBlock') {
202
+ var _node$nodeSize;
203
+ return tr.replace(pos, pos + ((_node$nodeSize = node === null || node === void 0 ? void 0 : node.nodeSize) !== null && _node$nodeSize !== void 0 ? _node$nodeSize : 0));
204
+ }
205
+ return tr;
206
+ });
207
+ };
176
208
  /**
177
209
  * Deletes (bodied)SyncBlock node and paste its content to the editor
178
210
  */
@@ -11,9 +11,10 @@ import React from 'react';
11
11
  import { ACTION_SUBJECT } from '@atlaskit/editor-common/analytics';
12
12
  import { ErrorBoundary } from '@atlaskit/editor-common/error-boundary';
13
13
  import ReactNodeView from '@atlaskit/editor-common/react-node-view';
14
- import { SyncBlockSharedCssClassName } from '@atlaskit/editor-common/sync-block';
14
+ import { SyncBlockSharedCssClassName, SyncBlockActionsProvider } from '@atlaskit/editor-common/sync-block';
15
15
  import { useFetchSyncBlockData as _useFetchSyncBlockData, useFetchSyncBlockTitle as _useFetchSyncBlockTitle } from '@atlaskit/editor-synced-block-provider';
16
16
  import { fg } from '@atlaskit/platform-feature-flags';
17
+ import { removeSyncedBlockAtPos } from '../editor-commands';
17
18
  import { SyncBlockRendererWrapper } from '../ui/SyncBlockRendererWrapper';
18
19
  export var SyncBlock = /*#__PURE__*/function (_ReactNodeView) {
19
20
  function SyncBlock(props) {
@@ -35,14 +36,15 @@ export var SyncBlock = /*#__PURE__*/function (_ReactNodeView) {
35
36
  }
36
37
  }, {
37
38
  key: "render",
38
- value: function render() {
39
+ value: function render(_ref) {
39
40
  var _this$options,
40
41
  _this$api$syncedBlock,
41
42
  _this$api,
42
43
  _this$api2,
43
- _this$options2,
44
44
  _this2 = this,
45
+ _this$options2,
45
46
  _this$options3;
47
+ var getPos = _ref.getPos;
46
48
  if (!((_this$options = this.options) !== null && _this$options !== void 0 && _this$options.syncedBlockRenderer)) {
47
49
  return null;
48
50
  }
@@ -63,6 +65,16 @@ export var SyncBlock = /*#__PURE__*/function (_ReactNodeView) {
63
65
  component: ACTION_SUBJECT.SYNCED_BLOCK,
64
66
  dispatchAnalyticsEvent: (_this$api2 = this.api) === null || _this$api2 === void 0 || (_this$api2 = _this$api2.analytics) === null || _this$api2 === void 0 ? void 0 : _this$api2.actions.fireAnalyticsEvent,
65
67
  fallbackComponent: null
68
+ }, /*#__PURE__*/React.createElement(SyncBlockActionsProvider, {
69
+ removeSyncBlock: function removeSyncBlock() {
70
+ var pos = getPos();
71
+ if (pos !== undefined) {
72
+ removeSyncedBlockAtPos(_this2.api, pos);
73
+ }
74
+ },
75
+ fetchSyncBlockSourceInfo: function fetchSyncBlockSourceInfo(sourceAri) {
76
+ return syncBlockStore.referenceManager.fetchSyncBlockSourceInfoBySourceAri(sourceAri);
77
+ }
66
78
  }, /*#__PURE__*/React.createElement(SyncBlockRendererWrapper, {
67
79
  localId: this.node.attrs.localId,
68
80
  syncedBlockRenderer: (_this$options2 = this.options) === null || _this$options2 === void 0 ? void 0 : _this$options2.syncedBlockRenderer,
@@ -74,7 +86,7 @@ export var SyncBlock = /*#__PURE__*/function (_ReactNodeView) {
74
86
  return _useFetchSyncBlockData(syncBlockStore, resourceId, localId, (_this2$api = _this2.api) === null || _this2$api === void 0 || (_this2$api = _this2$api.analytics) === null || _this2$api === void 0 || (_this2$api = _this2$api.actions) === null || _this2$api === void 0 ? void 0 : _this2$api.fireAnalyticsEvent);
75
87
  },
76
88
  api: this.api
77
- })) : /*#__PURE__*/React.createElement(SyncBlockRendererWrapper, {
89
+ }))) : /*#__PURE__*/React.createElement(SyncBlockRendererWrapper, {
78
90
  localId: this.node.attrs.localId,
79
91
  syncedBlockRenderer: (_this$options3 = this.options) === null || _this$options3 === void 0 ? void 0 : _this$options3.syncedBlockRenderer,
80
92
  useFetchSyncBlockTitle: function useFetchSyncBlockTitle() {
@@ -96,10 +108,10 @@ export var SyncBlock = /*#__PURE__*/function (_ReactNodeView) {
96
108
  }
97
109
  }]);
98
110
  }(ReactNodeView);
99
- export var syncBlockNodeView = function syncBlockNodeView(_ref) {
100
- var options = _ref.options,
101
- pmPluginFactoryParams = _ref.pmPluginFactoryParams,
102
- api = _ref.api;
111
+ export var syncBlockNodeView = function syncBlockNodeView(_ref2) {
112
+ var options = _ref2.options,
113
+ pmPluginFactoryParams = _ref2.pmPluginFactoryParams,
114
+ api = _ref2.api;
103
115
  return function (node, view, getPos) {
104
116
  var portalProviderAPI = pmPluginFactoryParams.portalProviderAPI,
105
117
  eventDispatcher = pmPluginFactoryParams.eventDispatcher;
@@ -1,7 +1,9 @@
1
+ import { expandSelectionToBlockRange } from '@atlaskit/editor-common/selection';
1
2
  import { Fragment } from '@atlaskit/editor-prosemirror/model';
2
3
  import { TextSelection } from '@atlaskit/editor-prosemirror/state';
3
4
  import { findParentNodeOfType, findSelectedNodeOfType } from '@atlaskit/editor-prosemirror/utils';
4
5
  import { CellSelection, findTable } from '@atlaskit/editor-tables';
6
+ import { fg } from '@atlaskit/platform-feature-flags';
5
7
  export var findSyncBlock = function findSyncBlock(schema, selection) {
6
8
  var syncBlock = schema.nodes.syncBlock;
7
9
  return findSelectedNodeOfType(syncBlock)(selection);
@@ -26,6 +28,9 @@ var UNSUPPORTED_NODE_TYPES = new Set(['inlineExtension', 'extension', 'bodiedExt
26
28
  * or false if conversion is not possible
27
29
  */
28
30
  export var canBeConvertedToSyncBlock = function canBeConvertedToSyncBlock(selection) {
31
+ return fg('platform_synced_block_dogfooding') ? canBeConvertedToSyncBlockNew(selection) : canBeConvertedToSyncBlockOld(selection);
32
+ };
33
+ export var canBeConvertedToSyncBlockOld = function canBeConvertedToSyncBlockOld(selection) {
29
34
  var schema = selection.$from.doc.type.schema;
30
35
  var nodes = schema.nodes;
31
36
  var from = selection.from;
@@ -64,6 +69,32 @@ export var canBeConvertedToSyncBlock = function canBeConvertedToSyncBlock(select
64
69
  to: to
65
70
  };
66
71
  };
72
+ export var canBeConvertedToSyncBlockNew = function canBeConvertedToSyncBlockNew(selection) {
73
+ var _expandSelectionToBlo = expandSelectionToBlockRange(selection),
74
+ $from = _expandSelectionToBlo.$from,
75
+ range = _expandSelectionToBlo.range;
76
+ if (!range) {
77
+ return false;
78
+ }
79
+ var from = range.start;
80
+ var to = range.end;
81
+ var canBeConverted = true;
82
+ $from.doc.nodesBetween(from, to, function (node) {
83
+ if (UNSUPPORTED_NODE_TYPES.has(node.type.name)) {
84
+ canBeConverted = false;
85
+ return false;
86
+ }
87
+ });
88
+ if (!canBeConverted) {
89
+ return false;
90
+ }
91
+ var contentToInclude = removeBreakoutMarks($from.doc.slice(from, to).content);
92
+ return {
93
+ contentToInclude: contentToInclude,
94
+ from: from,
95
+ to: to
96
+ };
97
+ };
67
98
  var removeBreakoutMarks = function removeBreakoutMarks(content) {
68
99
  var nodes = [];
69
100
 
@@ -17,10 +17,10 @@ import Spinner from '@atlaskit/spinner';
17
17
  import { syncedBlockPluginKey } from '../pm-plugins/main';
18
18
  var modalContentMap = {
19
19
  'source-block-deleted': {
20
- titleMultiple: messages.deleteConfirmationModalTitleSingle,
20
+ titleMultiple: messages.deleteConfirmationModalTitleMultiple,
21
21
  titleSingle: messages.deleteConfirmationModalTitleSingle,
22
22
  descriptionSingle: messages.deleteConfirmationModalDescriptionNoRef,
23
- descriptionMultiple: messages.deleteConfirmationModalDescription,
23
+ descriptionMultiple: messages.deleteConfirmationModalDescriptionMultiple,
24
24
  confirmButtonLabel: messages.deleteConfirmationModalDeleteButton
25
25
  },
26
26
  'source-block-unsynced': {
@@ -54,10 +54,6 @@ export var DeleteConfirmationModal = function DeleteConfirmationModal(_ref) {
54
54
  _useState8 = _slicedToArray(_useState7, 2),
55
55
  deleteReason = _useState8[0],
56
56
  setDeleteReason = _useState8[1];
57
- var _useState9 = useState('none'),
58
- _useState0 = _slicedToArray(_useState9, 2),
59
- fetchStatus = _useState0[0],
60
- setFetchStatus = _useState0[1];
61
57
  var _useSharedPluginState = useSharedPluginStateWithSelector(api, ['connectivity', 'syncedBlock'], function (states) {
62
58
  var _states$connectivityS, _states$syncedBlockSt, _states$syncedBlockSt2;
63
59
  return {
@@ -81,7 +77,6 @@ export var DeleteConfirmationModal = function DeleteConfirmationModal(_ref) {
81
77
  }
82
78
  if (!confirm) {
83
79
  setIsOpen(false);
84
- setFetchStatus('none');
85
80
  setReferenceCount(undefined);
86
81
  }
87
82
  api === null || api === void 0 || (_api$core = api.core) === null || _api$core === void 0 || _api$core.actions.execute(function (_ref2) {
@@ -125,7 +120,6 @@ export var DeleteConfirmationModal = function DeleteConfirmationModal(_ref) {
125
120
  var _api$core5;
126
121
  // auto close modal once deletion is successful
127
122
  setIsOpen(false);
128
- setFetchStatus('none');
129
123
  api === null || api === void 0 || (_api$core5 = api.core) === null || _api$core5 === void 0 || _api$core5.actions.execute(function (_ref4) {
130
124
  var tr = _ref4.tr;
131
125
  return tr.setMeta(syncedBlockPluginKey, {
@@ -137,49 +131,65 @@ export var DeleteConfirmationModal = function DeleteConfirmationModal(_ref) {
137
131
  }, [api === null || api === void 0 || (_api$core6 = api.core) === null || _api$core6 === void 0 ? void 0 : _api$core6.actions, bodiedSyncBlockDeletionStatus, isOpen]);
138
132
  useEffect(function () {
139
133
  if (isOpen && syncBlockIds !== undefined && fg('platform_synced_block_dogfooding')) {
140
- var _referenceCount = 0;
141
- setFetchStatus('loading');
142
- var fetchFailed = false;
143
- syncBlockIds.forEach( /*#__PURE__*/function () {
144
- var _ref5 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee(syncBlockId) {
145
- var references, _references$reference, _references$reference2;
146
- return _regeneratorRuntime.wrap(function _callee$(_context) {
147
- while (1) switch (_context.prev = _context.next) {
134
+ var fetchReferences = /*#__PURE__*/function () {
135
+ var _ref5 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee2() {
136
+ var references, totalCount;
137
+ return _regeneratorRuntime.wrap(function _callee2$(_context2) {
138
+ while (1) switch (_context2.prev = _context2.next) {
148
139
  case 0:
149
- if (!fetchFailed) {
150
- _context.next = 2;
151
- break;
152
- }
153
- return _context.abrupt("return");
154
- case 2:
155
- _context.next = 4;
156
- return syncBlockStoreManager.sourceManager.fetchReferences(syncBlockId.resourceId);
157
- case 4:
158
- references = _context.sent;
159
- if (!references.error) {
160
- _context.next = 11;
161
- break;
162
- }
163
- // Consider fetch fails as soon as one of the fetches fails
164
- setFetchStatus('error');
165
- fetchFailed = true;
166
- return _context.abrupt("return");
140
+ _context2.prev = 0;
141
+ _context2.next = 3;
142
+ return Promise.all(syncBlockIds.map( /*#__PURE__*/function () {
143
+ var _ref6 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee(syncBlockId) {
144
+ var _references$reference, _references$reference2;
145
+ var references;
146
+ return _regeneratorRuntime.wrap(function _callee$(_context) {
147
+ while (1) switch (_context.prev = _context.next) {
148
+ case 0:
149
+ _context.next = 2;
150
+ return syncBlockStoreManager.sourceManager.fetchReferences(syncBlockId.resourceId);
151
+ case 2:
152
+ references = _context.sent;
153
+ if (!(references !== null && references !== void 0 && references.error)) {
154
+ _context.next = 5;
155
+ break;
156
+ }
157
+ throw new Error();
158
+ case 5:
159
+ return _context.abrupt("return", (_references$reference = (_references$reference2 = references.references) === null || _references$reference2 === void 0 ? void 0 : _references$reference2.length) !== null && _references$reference !== void 0 ? _references$reference : 0);
160
+ case 6:
161
+ case "end":
162
+ return _context.stop();
163
+ }
164
+ }, _callee);
165
+ }));
166
+ return function (_x) {
167
+ return _ref6.apply(this, arguments);
168
+ };
169
+ }()));
170
+ case 3:
171
+ references = _context2.sent;
172
+ totalCount = references.reduce(function (sum, count) {
173
+ return sum + count;
174
+ }, 0);
175
+ setReferenceCount(totalCount);
176
+ _context2.next = 11;
177
+ break;
178
+ case 8:
179
+ _context2.prev = 8;
180
+ _context2.t0 = _context2["catch"](0);
181
+ setReferenceCount(0);
167
182
  case 11:
168
- _referenceCount += (_references$reference = (_references$reference2 = references.references) === null || _references$reference2 === void 0 ? void 0 : _references$reference2.length) !== null && _references$reference !== void 0 ? _references$reference : 0;
169
- case 12:
170
183
  case "end":
171
- return _context.stop();
184
+ return _context2.stop();
172
185
  }
173
- }, _callee);
186
+ }, _callee2, null, [[0, 8]]);
174
187
  }));
175
- return function (_x) {
188
+ return function fetchReferences() {
176
189
  return _ref5.apply(this, arguments);
177
190
  };
178
- }());
179
- if (!fetchFailed) {
180
- setReferenceCount(_referenceCount);
181
- setFetchStatus('success');
182
- }
191
+ }();
192
+ fetchReferences();
183
193
  }
184
194
  }, [isOpen, syncBlockIds, syncBlockStoreManager.sourceManager]);
185
195
  return /*#__PURE__*/React.createElement(ModalTransition, null, isOpen && /*#__PURE__*/React.createElement(ModalDialog, {
@@ -198,7 +208,7 @@ export var DeleteConfirmationModal = function DeleteConfirmationModal(_ref) {
198
208
  isDeleting: bodiedSyncBlockDeletionStatus === 'processing',
199
209
  isDisabled: isOfflineMode(mode),
200
210
  deleteReason: deleteReason,
201
- failToFetch: fetchStatus === 'error'
211
+ sourceCount: (syncBlockIds === null || syncBlockIds === void 0 ? void 0 : syncBlockIds.length) || 0
202
212
  })) : /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(ModalHeader, {
203
213
  hasCloseButton: true
204
214
  }, /*#__PURE__*/React.createElement(ModalTitle, {
@@ -216,29 +226,30 @@ export var DeleteConfirmationModal = function DeleteConfirmationModal(_ref) {
216
226
  isLoading: bodiedSyncBlockDeletionStatus === 'processing'
217
227
  }, formatMessage(messages.deleteConfirmationModalDeleteButton))))));
218
228
  };
219
- var ModalContent = function ModalContent(_ref6) {
220
- var content = _ref6.content,
221
- referenceCount = _ref6.referenceCount,
222
- handleClick = _ref6.handleClick,
223
- formatMessage = _ref6.formatMessage,
224
- isDeleting = _ref6.isDeleting,
225
- isDisabled = _ref6.isDisabled,
226
- deleteReason = _ref6.deleteReason,
227
- failToFetch = _ref6.failToFetch;
229
+ var ModalContent = function ModalContent(_ref7) {
230
+ var content = _ref7.content,
231
+ referenceCount = _ref7.referenceCount,
232
+ handleClick = _ref7.handleClick,
233
+ formatMessage = _ref7.formatMessage,
234
+ isDeleting = _ref7.isDeleting,
235
+ isDisabled = _ref7.isDisabled,
236
+ deleteReason = _ref7.deleteReason,
237
+ sourceCount = _ref7.sourceCount;
228
238
  var titleMultiple = content.titleMultiple,
229
239
  titleSingle = content.titleSingle,
230
240
  descriptionSingle = content.descriptionSingle,
231
241
  descriptionMultiple = content.descriptionMultiple,
232
242
  confirmButtonLabel = content.confirmButtonLabel;
233
- var hasNoReferenceOrFailToFetch = referenceCount === 0 || failToFetch;
243
+ var hasNoReferenceOrFailToFetch = referenceCount === 0;
244
+ var syncBlockCount = deleteReason === 'source-block-deleted' ? referenceCount + sourceCount : referenceCount;
234
245
  return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(ModalHeader, {
235
246
  hasCloseButton: true
236
247
  }, /*#__PURE__*/React.createElement(ModalTitle, {
237
248
  appearance: "warning"
238
249
  }, hasNoReferenceOrFailToFetch ? formatMessage(titleSingle) : formatMessage(titleMultiple, {
239
- count: referenceCount
250
+ count: syncBlockCount
240
251
  }))), /*#__PURE__*/React.createElement(ModalBody, null, /*#__PURE__*/React.createElement(Text, null, hasNoReferenceOrFailToFetch ? formatMessage(descriptionSingle) : formatMessage(descriptionMultiple, {
241
- syncBlockCount: referenceCount
252
+ syncBlockCount: syncBlockCount
242
253
  }))), /*#__PURE__*/React.createElement(ModalFooter, null, /*#__PURE__*/React.createElement(Button, {
243
254
  appearance: "subtle",
244
255
  onClick: handleClick(false)