@atlaskit/editor-plugin-synced-block 4.4.0 → 4.5.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.
Files changed (45) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/afm-cc/tsconfig.json +2 -1
  3. package/afm-jira/tsconfig.json +2 -1
  4. package/afm-products/tsconfig.json +2 -1
  5. package/dist/cjs/nodeviews/syncedBlock.js +2 -1
  6. package/dist/cjs/pm-plugins/main.js +57 -36
  7. package/dist/cjs/pm-plugins/utils/handle-bodied-sync-block-removal.js +87 -0
  8. package/dist/cjs/syncedBlockPlugin.js +6 -4
  9. package/dist/cjs/types/index.js +1 -0
  10. package/dist/cjs/ui/DeleteConfirmationModal.js +53 -12
  11. package/dist/cjs/ui/Flag.js +44 -17
  12. package/dist/cjs/ui/SyncBlockRendererWrapper.js +4 -2
  13. package/dist/es2019/nodeviews/syncedBlock.js +2 -1
  14. package/dist/es2019/pm-plugins/main.js +56 -33
  15. package/dist/es2019/pm-plugins/utils/handle-bodied-sync-block-removal.js +74 -0
  16. package/dist/es2019/syncedBlockPlugin.js +6 -4
  17. package/dist/es2019/types/index.js +1 -0
  18. package/dist/es2019/ui/DeleteConfirmationModal.js +56 -12
  19. package/dist/es2019/ui/Flag.js +43 -13
  20. package/dist/es2019/ui/SyncBlockRendererWrapper.js +4 -2
  21. package/dist/esm/nodeviews/syncedBlock.js +2 -1
  22. package/dist/esm/pm-plugins/main.js +57 -37
  23. package/dist/esm/pm-plugins/utils/handle-bodied-sync-block-removal.js +80 -0
  24. package/dist/esm/syncedBlockPlugin.js +6 -4
  25. package/dist/esm/types/index.js +1 -0
  26. package/dist/esm/ui/DeleteConfirmationModal.js +53 -12
  27. package/dist/esm/ui/Flag.js +44 -17
  28. package/dist/esm/ui/SyncBlockRendererWrapper.js +4 -2
  29. package/dist/types/pm-plugins/main.d.ts +3 -2
  30. package/dist/types/pm-plugins/utils/handle-bodied-sync-block-removal.d.ts +9 -0
  31. package/dist/types/pm-plugins/utils/track-sync-blocks.d.ts +2 -11
  32. package/dist/types/syncedBlockPluginType.d.ts +2 -5
  33. package/dist/types/types/index.d.ts +28 -2
  34. package/dist/types/ui/CreateSyncedBlockButton.d.ts +1 -1
  35. package/dist/types/ui/OverflowMenuSection.d.ts +1 -1
  36. package/dist/types/ui/SyncBlockRendererWrapper.d.ts +5 -3
  37. package/dist/types-ts4.5/pm-plugins/main.d.ts +3 -2
  38. package/dist/types-ts4.5/pm-plugins/utils/handle-bodied-sync-block-removal.d.ts +9 -0
  39. package/dist/types-ts4.5/pm-plugins/utils/track-sync-blocks.d.ts +2 -11
  40. package/dist/types-ts4.5/syncedBlockPluginType.d.ts +2 -5
  41. package/dist/types-ts4.5/types/index.d.ts +28 -2
  42. package/dist/types-ts4.5/ui/CreateSyncedBlockButton.d.ts +1 -1
  43. package/dist/types-ts4.5/ui/OverflowMenuSection.d.ts +1 -1
  44. package/dist/types-ts4.5/ui/SyncBlockRendererWrapper.d.ts +5 -3
  45. package/package.json +7 -7
@@ -1,13 +1,14 @@
1
1
  import { SafePlugin } from '@atlaskit/editor-common/safe-plugin';
2
2
  import { createSelectionClickHandler } from '@atlaskit/editor-common/selection';
3
3
  import { BodiedSyncBlockSharedCssClassName, SyncBlockStateCssClassName } from '@atlaskit/editor-common/sync-block';
4
- import { pmHistoryPluginKey } from '@atlaskit/editor-common/utils';
4
+ import { mapSlice, pmHistoryPluginKey } from '@atlaskit/editor-common/utils';
5
5
  import { PluginKey } from '@atlaskit/editor-prosemirror/state';
6
6
  import { DecorationSet, Decoration } from '@atlaskit/editor-prosemirror/view';
7
7
  import { convertPMNodesToSyncBlockNodes, rebaseTransaction } from '@atlaskit/editor-synced-block-provider';
8
8
  import { lazyBodiedSyncBlockView } from '../nodeviews/bodiedLazySyncedBlock';
9
9
  import { lazySyncBlockView } from '../nodeviews/lazySyncedBlock';
10
10
  import { FLAG_ID } from '../types';
11
+ import { handleBodiedSyncBlockRemoval } from './utils/handle-bodied-sync-block-removal';
11
12
  import { shouldIgnoreDomEvent } from './utils/ignore-dom-event';
12
13
  import { calculateDecorations } from './utils/selection-decorations';
13
14
  import { hasEditInSyncBlock, trackSyncBlocks } from './utils/track-sync-blocks';
@@ -16,7 +17,9 @@ export const createPlugin = (options, pmPluginFactoryParams, syncBlockStore, api
16
17
  const {
17
18
  useLongPressSelection = false
18
19
  } = options || {};
19
- let confirmationTransaction;
20
+ const confirmationTransactionRef = {
21
+ current: undefined
22
+ };
20
23
  return new SafePlugin({
21
24
  key: syncedBlockPluginKey,
22
25
  state: {
@@ -25,25 +28,27 @@ export const createPlugin = (options, pmPluginFactoryParams, syncBlockStore, api
25
28
  syncBlockStore.referenceManager.fetchSyncBlocksData(convertPMNodesToSyncBlockNodes(syncBlockNodes));
26
29
  return {
27
30
  selectionDecorationSet: calculateDecorations(instance.doc, instance.selection, instance.schema),
28
- showFlag: false,
31
+ activeFlag: false,
29
32
  syncBlockStore: syncBlockStore
30
33
  };
31
34
  },
32
35
  apply: (tr, currentPluginState, oldEditorState) => {
33
- var _meta$showFlag;
36
+ var _meta$activeFlag, _meta$bodiedSyncBlock;
34
37
  const meta = tr.getMeta(syncedBlockPluginKey);
35
38
  const {
36
- showFlag,
37
- selectionDecorationSet
39
+ activeFlag,
40
+ selectionDecorationSet,
41
+ bodiedSyncBlockDeletionStatus
38
42
  } = currentPluginState;
39
43
  let newDecorationSet = selectionDecorationSet.map(tr.mapping, tr.doc);
40
44
  if (!tr.selection.eq(oldEditorState.selection)) {
41
45
  newDecorationSet = calculateDecorations(tr.doc, tr.selection, tr.doc.type.schema);
42
46
  }
43
47
  return {
44
- showFlag: (_meta$showFlag = meta === null || meta === void 0 ? void 0 : meta.showFlag) !== null && _meta$showFlag !== void 0 ? _meta$showFlag : showFlag,
48
+ activeFlag: (_meta$activeFlag = meta === null || meta === void 0 ? void 0 : meta.activeFlag) !== null && _meta$activeFlag !== void 0 ? _meta$activeFlag : activeFlag,
45
49
  selectionDecorationSet: newDecorationSet,
46
- syncBlockStore: syncBlockStore
50
+ syncBlockStore: syncBlockStore,
51
+ bodiedSyncBlockDeletionStatus: (_meta$bodiedSyncBlock = meta === null || meta === void 0 ? void 0 : meta.bodiedSyncBlockDeletionStatus) !== null && _meta$bodiedSyncBlock !== void 0 ? _meta$bodiedSyncBlock : bodiedSyncBlockDeletionStatus
47
52
  };
48
53
  }
49
54
  },
@@ -94,6 +99,40 @@ export const createPlugin = (options, pmPluginFactoryParams, syncBlockStore, api
94
99
  mousedown(view, event) {
95
100
  return shouldIgnoreDomEvent(view, event, api);
96
101
  }
102
+ },
103
+ transformCopied: (slice, {
104
+ state
105
+ }) => {
106
+ const pluginState = syncedBlockPluginKey.getState(state);
107
+ const syncBlockStore = pluginState === null || pluginState === void 0 ? void 0 : pluginState.syncBlockStore;
108
+ const {
109
+ schema
110
+ } = state;
111
+ if (!syncBlockStore) {
112
+ return slice;
113
+ }
114
+ return mapSlice(slice, node => {
115
+ if (node.type.name === 'bodiedSyncBlock' && node.attrs.resourceId) {
116
+ try {
117
+ const newResourceId = syncBlockStore.referenceManager.generateResourceIdForReference(node.attrs.resourceId);
118
+ // Convert bodiedSyncBlock to syncBlock
119
+ // The paste transformation will regenrate the localId
120
+ const newAttrs = {
121
+ ...node.attrs,
122
+ resourceId: newResourceId
123
+ };
124
+ const newMarks = schema.nodes.syncBlock.markSet ? node.marks.filter(mark => {
125
+ var _schema$nodes$syncBlo;
126
+ return (_schema$nodes$syncBlo = schema.nodes.syncBlock.markSet) === null || _schema$nodes$syncBlo === void 0 ? void 0 : _schema$nodes$syncBlo.includes(mark.type);
127
+ }) : node.marks;
128
+ return schema.nodes.syncBlock.create(newAttrs, null, newMarks);
129
+ } catch (error) {
130
+ // If generateResourceIdForReference died, return the original node
131
+ return node;
132
+ }
133
+ }
134
+ return node;
135
+ });
97
136
  }
98
137
  },
99
138
  filterTransaction: (tr, state) => {
@@ -113,26 +152,8 @@ export const createPlugin = (options, pmPluginFactoryParams, syncBlockStore, api
113
152
  } = trackSyncBlocks(syncBlockStore.sourceManager.isSourceBlock, tr, state);
114
153
  if (!isOffline) {
115
154
  if (bodiedSyncBlockRemoved.length > 0) {
116
- // If there are source sync blocks being removed, and we need to confirm with user before deleting,
117
- // we block the transaction here, and wait for user confirmation to proceed with deletion.
118
- // See editor-common/src/sync-block/sync-block-store-manager.ts for how we handle user confirmation and
119
- // proceed with deletion.
120
- confirmationTransaction = tr;
121
- syncBlockStore.sourceManager.deleteSyncBlocksWithConfirmation(bodiedSyncBlockRemoved.map(node => node.attrs), () => {
122
- var _api$core;
123
- api === null || api === void 0 ? void 0 : (_api$core = api.core) === null || _api$core === void 0 ? void 0 : _api$core.actions.execute(() => {
124
- const trToDispatch = tr.setMeta('isConfirmedSyncBlockDeletion', true);
125
- if (!trToDispatch.getMeta(pmHistoryPluginKey)) {
126
- // bodiedSyncBlock deletion is expected to be permanent (cannot undo)
127
- // For a normal deletion (not triggered by undo), remove it from history so that it cannot be undone
128
- trToDispatch.setMeta('addToHistory', false);
129
- }
130
- return trToDispatch;
131
- });
132
- }).finally(() => {
133
- confirmationTransaction = undefined;
134
- });
135
- return false;
155
+ confirmationTransactionRef.current = tr;
156
+ return handleBodiedSyncBlockRemoval(tr, bodiedSyncBlockRemoved, syncBlockStore, api, confirmationTransactionRef);
136
157
  }
137
158
  if (bodiedSyncBlockAdded.length > 0) {
138
159
  if (Boolean(tr.getMeta(pmHistoryPluginKey))) {
@@ -146,8 +167,8 @@ export const createPlugin = (options, pmPluginFactoryParams, syncBlockStore, api
146
167
  // we need to intercept the transaction and save it in insert callback so that we only insert it to the document when backend call if backend call is successful
147
168
  // The callback will be evoked by in SourceSyncBlockStoreManager.commitPendingCreation
148
169
  syncBlockStore.sourceManager.registerCreationCallback(() => {
149
- var _api$core2;
150
- api === null || api === void 0 ? void 0 : (_api$core2 = api.core) === null || _api$core2 === void 0 ? void 0 : _api$core2.actions.execute(() => {
170
+ var _api$core;
171
+ api === null || api === void 0 ? void 0 : (_api$core = api.core) === null || _api$core === void 0 ? void 0 : _api$core.actions.execute(() => {
151
172
  return tr.setMeta('isCommitSyncBlockCreation', true);
152
173
  });
153
174
  api === null || api === void 0 ? void 0 : api.core.actions.focus();
@@ -176,7 +197,9 @@ export const createPlugin = (options, pmPluginFactoryParams, syncBlockStore, api
176
197
  tr
177
198
  }) => {
178
199
  return tr.setMeta(syncedBlockPluginKey, {
179
- showFlag: errorFlag
200
+ activeFlag: {
201
+ id: errorFlag
202
+ }
180
203
  });
181
204
  });
182
205
  }, 0);
@@ -187,8 +210,8 @@ export const createPlugin = (options, pmPluginFactoryParams, syncBlockStore, api
187
210
  },
188
211
  appendTransaction: (trs, oldState, newState) => {
189
212
  trs.filter(tr => tr.docChanged).forEach(tr => {
190
- if (confirmationTransaction) {
191
- confirmationTransaction = rebaseTransaction(confirmationTransaction, tr, newState);
213
+ if (confirmationTransactionRef.current) {
214
+ confirmationTransactionRef.current = rebaseTransaction(confirmationTransactionRef.current, tr, newState);
192
215
  }
193
216
  });
194
217
  for (const tr of trs) {
@@ -0,0 +1,74 @@
1
+ import { pmHistoryPluginKey } from '@atlaskit/editor-common/utils';
2
+ import { FLAG_ID } from '../../types';
3
+ import { syncedBlockPluginKey } from '../main';
4
+ const onRetry = (api, syncBlockStore) => () => {
5
+ var _api$core;
6
+ api === null || api === void 0 ? void 0 : (_api$core = api.core) === null || _api$core === void 0 ? void 0 : _api$core.actions.execute(({
7
+ tr
8
+ }) => {
9
+ return tr.setMeta(syncedBlockPluginKey, {
10
+ bodiedSyncBlockDeletionStatus: 'processing',
11
+ activeFlag: false
12
+ });
13
+ });
14
+ syncBlockStore.sourceManager.retryDeletion();
15
+ };
16
+ const onDismissed = syncBlockStore => tr => {
17
+ syncBlockStore.sourceManager.clearPendingDeletion();
18
+ return tr.setMeta(syncedBlockPluginKey, {
19
+ bodiedSyncBlockDeletionStatus: 'none'
20
+ });
21
+ };
22
+ export const handleBodiedSyncBlockRemoval = (tr, bodiedSyncBlockRemoved, syncBlockStore, api, confirmationTransactionRef) => {
23
+ // Clear potential old pending deletion to retreat the deletion as first attempt
24
+ syncBlockStore.sourceManager.clearPendingDeletion();
25
+
26
+ // If there are source sync blocks being removed, and we need to confirm with user before deleting,
27
+ // we block the transaction here, and wait for user confirmation to proceed with deletion.
28
+ // See editor-common/src/sync-block/sync-block-store-manager.ts for how we handle user confirmation and
29
+ // proceed with deletion.
30
+ syncBlockStore.sourceManager.deleteSyncBlocksWithConfirmation(bodiedSyncBlockRemoved.map(node => node.attrs), () => {
31
+ var _api$core2;
32
+ const confirmationTransaction = confirmationTransactionRef.current;
33
+ if (!confirmationTransaction) {
34
+ return;
35
+ }
36
+ api === null || api === void 0 ? void 0 : (_api$core2 = api.core) === null || _api$core2 === void 0 ? void 0 : _api$core2.actions.execute(() => {
37
+ const trToDispatch = confirmationTransaction.setMeta('isConfirmedSyncBlockDeletion', true);
38
+ if (!trToDispatch.getMeta(pmHistoryPluginKey)) {
39
+ // bodiedSyncBlock deletion is expected to be permanent (cannot undo)
40
+ // For a normal deletion (not triggered by undo), remove it from history so that it cannot be undone
41
+ trToDispatch.setMeta('addToHistory', false);
42
+ }
43
+ return trToDispatch;
44
+ });
45
+ }, success => {
46
+ var _api$core3;
47
+ api === null || api === void 0 ? void 0 : (_api$core3 = api.core) === null || _api$core3 === void 0 ? void 0 : _api$core3.actions.execute(({
48
+ tr
49
+ }) => {
50
+ let newState;
51
+ if (!success) {
52
+ newState = {
53
+ activeFlag: {
54
+ id: FLAG_ID.FAIL_TO_DELETE,
55
+ onRetry: onRetry(api, syncBlockStore),
56
+ onDismissed: onDismissed(syncBlockStore)
57
+ }
58
+ };
59
+ }
60
+ newState = {
61
+ ...newState,
62
+ bodiedSyncBlockDeletionStatus: syncBlockStore.sourceManager.isRetryingDeletion() ?
63
+ // For retry, reset to none directly to clean up the status
64
+ 'none' :
65
+ // For the first attempt, set to completed for deletion modal can close the modal
66
+ 'completed'
67
+ };
68
+ return tr.setMeta(syncedBlockPluginKey, newState);
69
+ });
70
+ }, () => {
71
+ confirmationTransactionRef.current = undefined;
72
+ });
73
+ return false;
74
+ };
@@ -95,12 +95,14 @@ export const syncedBlockPlugin = ({
95
95
  return;
96
96
  }
97
97
  const {
98
- showFlag,
99
- syncBlockStore: currentSyncBlockStore
98
+ activeFlag,
99
+ syncBlockStore: currentSyncBlockStore,
100
+ bodiedSyncBlockDeletionStatus
100
101
  } = syncedBlockPluginKey.getState(editorState);
101
102
  return {
102
- showFlag,
103
- syncBlockStore: currentSyncBlockStore
103
+ activeFlag,
104
+ syncBlockStore: currentSyncBlockStore,
105
+ bodiedSyncBlockDeletionStatus
104
106
  };
105
107
  }
106
108
  };
@@ -2,5 +2,6 @@ export let FLAG_ID = /*#__PURE__*/function (FLAG_ID) {
2
2
  FLAG_ID["CANNOT_DELETE_WHEN_OFFLINE"] = "cannot-delete-when-offline";
3
3
  FLAG_ID["CANNOT_EDIT_WHEN_OFFLINE"] = "cannot-edit-when-offline";
4
4
  FLAG_ID["CANNOT_CREATE_WHEN_OFFLINE"] = "cannot-create-when-offline";
5
+ FLAG_ID["FAIL_TO_DELETE"] = "fail-to-delete";
5
6
  return FLAG_ID;
6
7
  }({});
@@ -5,47 +5,90 @@ import { useSharedPluginStateWithSelector } from '@atlaskit/editor-common/hooks'
5
5
  import { syncBlockMessages as messages } from '@atlaskit/editor-common/messages';
6
6
  import ModalDialog, { ModalBody, ModalFooter, ModalHeader, ModalTitle, ModalTransition } from '@atlaskit/modal-dialog';
7
7
  import { Text } from '@atlaskit/primitives/compiled';
8
+ import { syncedBlockPluginKey } from '../pm-plugins/main';
8
9
  export const DeleteConfirmationModal = ({
9
10
  syncBlockStoreManager,
10
11
  api
11
12
  }) => {
13
+ var _api$core2, _api$core4, _api$core6;
12
14
  const [isOpen, setIsOpen] = useState(false);
13
15
  const [syncBlockCount, setSyncBlockCount] = useState(1);
14
16
  const {
15
- mode
16
- } = useSharedPluginStateWithSelector(api, ['connectivity'], states => {
17
- var _states$connectivityS;
17
+ mode,
18
+ bodiedSyncBlockDeletionStatus,
19
+ activeFlag
20
+ } = useSharedPluginStateWithSelector(api, ['connectivity', 'syncedBlock'], states => {
21
+ var _states$connectivityS, _states$syncedBlockSt, _states$syncedBlockSt2;
18
22
  return {
19
- mode: (_states$connectivityS = states.connectivityState) === null || _states$connectivityS === void 0 ? void 0 : _states$connectivityS.mode
23
+ mode: (_states$connectivityS = states.connectivityState) === null || _states$connectivityS === void 0 ? void 0 : _states$connectivityS.mode,
24
+ bodiedSyncBlockDeletionStatus: (_states$syncedBlockSt = states.syncedBlockState) === null || _states$syncedBlockSt === void 0 ? void 0 : _states$syncedBlockSt.bodiedSyncBlockDeletionStatus,
25
+ activeFlag: (_states$syncedBlockSt2 = states.syncedBlockState) === null || _states$syncedBlockSt2 === void 0 ? void 0 : _states$syncedBlockSt2.activeFlag
20
26
  };
21
27
  });
22
28
  const {
23
29
  formatMessage
24
30
  } = useIntl();
25
31
  const resolverRef = React.useRef(undefined);
26
- const handleClose = useCallback(confirm => () => {
32
+ const handleClick = useCallback(confirm => () => {
33
+ var _api$core;
27
34
  if (resolverRef.current) {
28
35
  resolverRef.current(confirm);
29
36
  resolverRef.current = undefined;
30
37
  }
31
- setIsOpen(false);
32
- }, []);
38
+ if (!confirm) {
39
+ setIsOpen(false);
40
+ }
41
+ api === null || api === void 0 ? void 0 : (_api$core = api.core) === null || _api$core === void 0 ? void 0 : _api$core.actions.execute(({
42
+ tr
43
+ }) => {
44
+ return tr.setMeta(syncedBlockPluginKey, {
45
+ bodiedSyncBlockDeletionStatus: confirm ? 'processing' : 'none',
46
+ activeFlag: false
47
+ });
48
+ });
49
+ }, [api === null || api === void 0 ? void 0 : (_api$core2 = api.core) === null || _api$core2 === void 0 ? void 0 : _api$core2.actions]);
33
50
  const confirmationCallback = useCallback(syncBlockCount => {
34
51
  setIsOpen(true);
35
52
  setSyncBlockCount(syncBlockCount);
36
53
  const confirmedPromise = new Promise(resolve => {
37
54
  resolverRef.current = resolve;
38
55
  });
56
+ if (activeFlag) {
57
+ var _api$core3;
58
+ api === null || api === void 0 ? void 0 : (_api$core3 = api.core) === null || _api$core3 === void 0 ? void 0 : _api$core3.actions.execute(({
59
+ tr
60
+ }) => {
61
+ return tr.setMeta(syncedBlockPluginKey, {
62
+ // Clear flag to avoid potential retry deletion of different blocks
63
+ activeFlag: false
64
+ });
65
+ });
66
+ }
39
67
  return confirmedPromise;
40
- }, []);
68
+ }, [activeFlag, api === null || api === void 0 ? void 0 : (_api$core4 = api.core) === null || _api$core4 === void 0 ? void 0 : _api$core4.actions]);
41
69
  useEffect(() => {
42
70
  const unregister = syncBlockStoreManager.sourceManager.registerConfirmationCallback(confirmationCallback);
43
71
  return () => {
44
72
  unregister();
45
73
  };
46
74
  }, [syncBlockStoreManager, confirmationCallback]);
75
+ useEffect(() => {
76
+ if (bodiedSyncBlockDeletionStatus === 'completed' && isOpen) {
77
+ var _api$core5;
78
+ // auto close modal once deletion is successful
79
+ setIsOpen(false);
80
+ api === null || api === void 0 ? void 0 : (_api$core5 = api.core) === null || _api$core5 === void 0 ? void 0 : _api$core5.actions.execute(({
81
+ tr
82
+ }) => {
83
+ return tr.setMeta(syncedBlockPluginKey, {
84
+ // Reset deletion status to have a clean state for next deletion
85
+ bodiedSyncBlockDeletionStatus: 'none'
86
+ });
87
+ });
88
+ }
89
+ }, [api === null || api === void 0 ? void 0 : (_api$core6 = api.core) === null || _api$core6 === void 0 ? void 0 : _api$core6.actions, bodiedSyncBlockDeletionStatus, isOpen]);
47
90
  return /*#__PURE__*/React.createElement(ModalTransition, null, isOpen && /*#__PURE__*/React.createElement(ModalDialog, {
48
- onClose: handleClose(false),
91
+ onClose: handleClick(false),
49
92
  testId: "sync-block-delete-confirmation"
50
93
  }, /*#__PURE__*/React.createElement(ModalHeader, {
51
94
  hasCloseButton: true
@@ -55,11 +98,12 @@ export const DeleteConfirmationModal = ({
55
98
  syncBlockCount
56
99
  }))), /*#__PURE__*/React.createElement(ModalFooter, null, /*#__PURE__*/React.createElement(Button, {
57
100
  appearance: "subtle",
58
- onClick: handleClose(false)
101
+ onClick: handleClick(false)
59
102
  }, formatMessage(messages.deleteConfirmationModalCancelButton)), /*#__PURE__*/React.createElement(Button, {
60
103
  appearance: "warning",
61
- onClick: handleClose(true),
104
+ onClick: handleClick(true),
62
105
  autoFocus: true,
63
- isDisabled: mode === 'offline'
106
+ isDisabled: mode === 'offline',
107
+ isLoading: bodiedSyncBlockDeletionStatus === 'processing'
64
108
  }, formatMessage(messages.deleteConfirmationModalDeleteButton)))));
65
109
  };
@@ -3,7 +3,7 @@ import { useIntl } from 'react-intl-next';
3
3
  import { useSharedPluginStateWithSelector } from '@atlaskit/editor-common/hooks';
4
4
  import { syncBlockMessages as messages } from '@atlaskit/editor-common/messages';
5
5
  import AkFlag, { FlagGroup } from '@atlaskit/flag';
6
- import StatusErrorIcon from '@atlaskit/icon/core/status-error';
6
+ import StatusWarningIcon from '@atlaskit/icon/core/status-warning';
7
7
  import { syncedBlockPluginKey } from '../pm-plugins/main';
8
8
  import { FLAG_ID } from '../types';
9
9
  const flagMap = {
@@ -18,35 +18,61 @@ const flagMap = {
18
18
  [FLAG_ID.CANNOT_CREATE_WHEN_OFFLINE]: {
19
19
  title: messages.failToCreateTitle,
20
20
  description: messages.failToCreateWhenOfflineDescription
21
+ },
22
+ [FLAG_ID.FAIL_TO_DELETE]: {
23
+ title: messages.cannotDeleteTitle,
24
+ description: messages.cannotDeleteDescription
21
25
  }
22
26
  };
23
27
  export const Flag = ({
24
28
  api
25
29
  }) => {
26
30
  const {
27
- showFlag
28
- } = useSharedPluginStateWithSelector(api, ['syncedBlock'], states => {
29
- var _states$syncedBlockSt;
31
+ activeFlag,
32
+ mode
33
+ } = useSharedPluginStateWithSelector(api, ['syncedBlock', 'connectivity'], states => {
34
+ var _states$syncedBlockSt, _states$connectivityS;
30
35
  return {
31
- showFlag: (_states$syncedBlockSt = states.syncedBlockState) === null || _states$syncedBlockSt === void 0 ? void 0 : _states$syncedBlockSt.showFlag
36
+ activeFlag: (_states$syncedBlockSt = states.syncedBlockState) === null || _states$syncedBlockSt === void 0 ? void 0 : _states$syncedBlockSt.activeFlag,
37
+ mode: (_states$connectivityS = states.connectivityState) === null || _states$connectivityS === void 0 ? void 0 : _states$connectivityS.mode
32
38
  };
33
39
  });
34
40
  const {
35
41
  formatMessage
36
42
  } = useIntl();
37
- if (!showFlag) {
43
+ if (!activeFlag) {
38
44
  return;
39
45
  }
40
46
  const {
41
47
  title,
42
48
  description
43
- } = flagMap[showFlag];
49
+ } = flagMap[activeFlag.id];
50
+ const {
51
+ onRetry,
52
+ onDismissed: onDismissedCallback
53
+ } = activeFlag;
54
+
55
+ // Retry button often involves network request, hence we dismiss the flag in offline mode to avoid retry
56
+ if (mode === 'offline' && !!onRetry) {
57
+ api === null || api === void 0 ? void 0 : api.core.actions.execute(({
58
+ tr
59
+ }) => {
60
+ tr.setMeta(syncedBlockPluginKey, {
61
+ activeFlag: false
62
+ });
63
+ return tr;
64
+ });
65
+ return;
66
+ }
44
67
  const onDismissed = () => {
45
68
  api === null || api === void 0 ? void 0 : api.core.actions.execute(({
46
69
  tr
47
70
  }) => {
71
+ onDismissedCallback === null || onDismissedCallback === void 0 ? void 0 : onDismissedCallback(tr);
72
+ const oldMeta = tr.getMeta(syncedBlockPluginKey);
48
73
  tr.setMeta(syncedBlockPluginKey, {
49
- showFlag: false
74
+ ...oldMeta,
75
+ activeFlag: false
50
76
  });
51
77
  return tr;
52
78
  });
@@ -56,11 +82,15 @@ export const Flag = ({
56
82
  onDismissed: onDismissed,
57
83
  title: formatMessage(title),
58
84
  description: formatMessage(description),
59
- id: showFlag,
60
- testId: showFlag,
61
- icon: /*#__PURE__*/React.createElement(StatusErrorIcon, {
85
+ id: activeFlag.id,
86
+ testId: activeFlag.id,
87
+ icon: /*#__PURE__*/React.createElement(StatusWarningIcon, {
62
88
  label: "",
63
- color: "var(--ds-icon-danger, #C9372C)"
64
- })
89
+ color: "var(--ds-icon-warning, #E06C00)"
90
+ }),
91
+ actions: onRetry ? [{
92
+ content: formatMessage(messages.deleteRetryButton),
93
+ onClick: onRetry
94
+ }] : undefined
65
95
  }));
66
96
  };
@@ -6,7 +6,8 @@ const SyncBlockRendererWrapperComponent = ({
6
6
  syncedBlockRenderer,
7
7
  useFetchSyncBlockData,
8
8
  localId,
9
- useFetchSyncBlockTitle
9
+ useFetchSyncBlockTitle,
10
+ api
10
11
  }) => {
11
12
  return /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("div", {
12
13
  "data-testid": SyncBlockRendererWrapperDataId
@@ -14,7 +15,8 @@ const SyncBlockRendererWrapperComponent = ({
14
15
  ,
15
16
  className: SyncBlockSharedCssClassName.renderer
16
17
  }, syncedBlockRenderer({
17
- useFetchSyncBlockData
18
+ useFetchSyncBlockData,
19
+ api
18
20
  })), /*#__PURE__*/React.createElement(SyncBlockLabel, {
19
21
  isSource: false,
20
22
  useFetchSyncBlockTitle: useFetchSyncBlockTitle,
@@ -60,7 +60,8 @@ var SyncBlock = /*#__PURE__*/function (_ReactNodeView) {
60
60
  useFetchSyncBlockData: function useFetchSyncBlockData() {
61
61
  var _this2$api;
62
62
  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);
63
- }
63
+ },
64
+ api: this.api
64
65
  });
65
66
  }
66
67
  }, {