@atlaskit/editor-plugin-synced-block 5.2.2 → 5.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +24 -0
- package/dist/cjs/editor-commands/index.js +33 -1
- package/dist/cjs/editor-commands/utils.js +20 -0
- package/dist/cjs/ui/SyncBlockLabel.js +103 -9
- package/dist/cjs/ui/SyncBlockRefresher.js +18 -4
- package/dist/cjs/ui/SyncBlockRendererWrapper.js +6 -2
- package/dist/cjs/ui/SyncedLocationDropdown.js +14 -11
- package/dist/cjs/ui/floating-toolbar.js +19 -1
- package/dist/es2019/editor-commands/index.js +34 -0
- package/dist/es2019/editor-commands/utils.js +14 -0
- package/dist/es2019/ui/SyncBlockLabel.js +96 -7
- package/dist/es2019/ui/SyncBlockRefresher.js +18 -4
- package/dist/es2019/ui/SyncBlockRendererWrapper.js +6 -2
- package/dist/es2019/ui/SyncedLocationDropdown.js +14 -11
- package/dist/es2019/ui/floating-toolbar.js +18 -2
- package/dist/esm/editor-commands/index.js +32 -0
- package/dist/esm/editor-commands/utils.js +14 -0
- package/dist/esm/ui/SyncBlockLabel.js +100 -8
- package/dist/esm/ui/SyncBlockRefresher.js +18 -4
- package/dist/esm/ui/SyncBlockRendererWrapper.js +6 -2
- package/dist/esm/ui/SyncedLocationDropdown.js +14 -11
- package/dist/esm/ui/floating-toolbar.js +20 -2
- package/dist/types/editor-commands/index.d.ts +5 -0
- package/dist/types/editor-commands/utils.d.ts +2 -0
- package/dist/types/syncedBlockPluginType.d.ts +1 -1
- package/dist/types/ui/SyncBlockLabel.d.ts +4 -1
- package/dist/types/ui/SyncBlockRendererWrapper.d.ts +1 -1
- package/dist/types-ts4.5/editor-commands/index.d.ts +5 -0
- package/dist/types-ts4.5/editor-commands/utils.d.ts +2 -0
- package/dist/types-ts4.5/syncedBlockPluginType.d.ts +1 -1
- package/dist/types-ts4.5/ui/SyncBlockLabel.d.ts +4 -1
- package/dist/types-ts4.5/ui/SyncBlockRendererWrapper.d.ts +1 -1
- package/package.json +7 -6
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
import { useEffect } from 'react';
|
|
2
2
|
import { useSharedPluginStateWithSelector } from '@atlaskit/editor-common/hooks';
|
|
3
|
+
import { isOfflineMode } from '@atlaskit/editor-plugin-connectivity';
|
|
4
|
+
import { fg } from '@atlaskit/platform-feature-flags';
|
|
3
5
|
export const SYNC_BLOCK_FETCH_INTERVAL = 3000;
|
|
4
6
|
|
|
5
|
-
// Component that
|
|
6
|
-
//
|
|
7
|
+
// Component that manages synced block data synchronization.
|
|
8
|
+
// When the feature flag 'platform_synced_block_dogfooding' is enabled,
|
|
9
|
+
// it uses provider-based GraphQL subscriptions for updates.
|
|
10
|
+
// When disabled, it falls back to polling at regular intervals.
|
|
7
11
|
export const SyncBlockRefresher = ({
|
|
8
12
|
syncBlockStoreManager,
|
|
9
13
|
api
|
|
@@ -16,9 +20,19 @@ export const SyncBlockRefresher = ({
|
|
|
16
20
|
mode: (_states$connectivityS = states.connectivityState) === null || _states$connectivityS === void 0 ? void 0 : _states$connectivityS.mode
|
|
17
21
|
};
|
|
18
22
|
});
|
|
23
|
+
const featureFlagEnabled = fg('platform_synced_block_dogfooding');
|
|
24
|
+
const isOnline = !isOfflineMode(mode);
|
|
19
25
|
useEffect(() => {
|
|
26
|
+
const useRealTimeSubscriptions = featureFlagEnabled && isOnline;
|
|
27
|
+
syncBlockStoreManager.referenceManager.setRealTimeSubscriptionsEnabled(useRealTimeSubscriptions);
|
|
28
|
+
}, [syncBlockStoreManager, featureFlagEnabled, isOnline]);
|
|
29
|
+
useEffect(() => {
|
|
30
|
+
const useRealTimeSubscriptions = featureFlagEnabled && isOnline;
|
|
31
|
+
if (useRealTimeSubscriptions) {
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
20
34
|
let interval = -1;
|
|
21
|
-
if (
|
|
35
|
+
if (isOnline) {
|
|
22
36
|
interval = window.setInterval(() => {
|
|
23
37
|
var _document;
|
|
24
38
|
// check if document is visible to avoid unnecessary refreshes
|
|
@@ -32,6 +46,6 @@ export const SyncBlockRefresher = ({
|
|
|
32
46
|
return () => {
|
|
33
47
|
window.clearInterval(interval);
|
|
34
48
|
};
|
|
35
|
-
}, [syncBlockStoreManager,
|
|
49
|
+
}, [syncBlockStoreManager, isOnline, featureFlagEnabled]);
|
|
36
50
|
return null;
|
|
37
51
|
};
|
|
@@ -5,21 +5,25 @@ const SyncBlockRendererWrapperDataId = 'sync-block-plugin-renderer-wrapper';
|
|
|
5
5
|
const SyncBlockRendererWrapperComponent = ({
|
|
6
6
|
syncedBlockRenderer,
|
|
7
7
|
useFetchSyncBlockData,
|
|
8
|
-
localId,
|
|
9
8
|
useFetchSyncBlockTitle,
|
|
9
|
+
localId,
|
|
10
10
|
api
|
|
11
11
|
}) => {
|
|
12
|
+
var _syncBlockFetchResult, _syncBlockFetchResult2;
|
|
13
|
+
const syncBlockFetchResult = useFetchSyncBlockData();
|
|
14
|
+
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;
|
|
12
15
|
return /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("div", {
|
|
13
16
|
"data-testid": SyncBlockRendererWrapperDataId
|
|
14
17
|
// eslint-disable-next-line @atlaskit/ui-styling-standard/no-classname-prop
|
|
15
18
|
,
|
|
16
19
|
className: SyncBlockSharedCssClassName.renderer
|
|
17
20
|
}, syncedBlockRenderer({
|
|
18
|
-
|
|
21
|
+
syncBlockFetchResult,
|
|
19
22
|
api
|
|
20
23
|
})), /*#__PURE__*/React.createElement(SyncBlockLabel, {
|
|
21
24
|
isSource: false,
|
|
22
25
|
useFetchSyncBlockTitle: useFetchSyncBlockTitle,
|
|
26
|
+
contentUpdatedAt: contentUpdatedAt,
|
|
23
27
|
localId: localId
|
|
24
28
|
}));
|
|
25
29
|
};
|
|
@@ -39,17 +39,18 @@ const styles = {
|
|
|
39
39
|
const ItemTitle = ({
|
|
40
40
|
title,
|
|
41
41
|
formatMessage,
|
|
42
|
-
|
|
42
|
+
onSameDocument,
|
|
43
43
|
isSource,
|
|
44
|
-
hasAccess
|
|
44
|
+
hasAccess,
|
|
45
|
+
productType
|
|
45
46
|
}) => {
|
|
46
47
|
return /*#__PURE__*/React.createElement(Inline, null, /*#__PURE__*/React.createElement(Box, {
|
|
47
48
|
as: "span",
|
|
48
49
|
xcss: styles.title
|
|
49
|
-
}, title),
|
|
50
|
+
}, title), onSameDocument && /*#__PURE__*/React.createElement(Box, {
|
|
50
51
|
as: "span",
|
|
51
52
|
xcss: styles.note
|
|
52
|
-
}, "\xA0- ", formatMessage(messages.
|
|
53
|
+
}, "\xA0- ", formatMessage(productType === 'confluence-page' ? messages.syncedLocationDropdownTitleNoteForConfluencePage : messages.syncedLocationDropdownTitleNoteForJiraWorkItem)), isSource && /*#__PURE__*/React.createElement(Box, {
|
|
53
54
|
as: "span",
|
|
54
55
|
xcss: styles.lozenge
|
|
55
56
|
}, /*#__PURE__*/React.createElement(Lozenge, null, formatMessage(messages.syncedLocationDropdownSourceLozenge))), !hasAccess && /*#__PURE__*/React.createElement(Box, {
|
|
@@ -66,7 +67,7 @@ const subTypeIconMap = {
|
|
|
66
67
|
page: PageIcon,
|
|
67
68
|
blogpost: QuotationMarkIcon
|
|
68
69
|
};
|
|
69
|
-
const
|
|
70
|
+
const getConfluenceSubTypeIcon = subType => {
|
|
70
71
|
return subType && subType in subTypeIconMap ? subTypeIconMap[subType] : PageIcon;
|
|
71
72
|
};
|
|
72
73
|
const ProductIcon = ({
|
|
@@ -86,18 +87,19 @@ const ItemIcon = ({
|
|
|
86
87
|
}) => {
|
|
87
88
|
const {
|
|
88
89
|
hasAccess,
|
|
89
|
-
subType
|
|
90
|
+
subType,
|
|
91
|
+
productType
|
|
90
92
|
} = reference;
|
|
91
|
-
if (hasAccess) {
|
|
93
|
+
if (productType === 'confluence-page' && hasAccess) {
|
|
92
94
|
return /*#__PURE__*/React.createElement(IconTile, {
|
|
93
|
-
icon:
|
|
95
|
+
icon: getConfluenceSubTypeIcon(subType),
|
|
94
96
|
label: "",
|
|
95
97
|
appearance: 'gray',
|
|
96
98
|
size: "xsmall"
|
|
97
99
|
});
|
|
98
100
|
}
|
|
99
101
|
return /*#__PURE__*/React.createElement(ProductIcon, {
|
|
100
|
-
product:
|
|
102
|
+
product: productType
|
|
101
103
|
});
|
|
102
104
|
};
|
|
103
105
|
export const processReferenceData = (referenceData, intl) => {
|
|
@@ -230,9 +232,10 @@ const DropdownContent = ({
|
|
|
230
232
|
}, /*#__PURE__*/React.createElement(ItemTitle, {
|
|
231
233
|
title: reference.title || reference.url || '',
|
|
232
234
|
formatMessage: formatMessage,
|
|
233
|
-
|
|
235
|
+
onSameDocument: reference.onSameDocument,
|
|
234
236
|
isSource: reference.isSource,
|
|
235
|
-
hasAccess: reference.hasAccess
|
|
237
|
+
hasAccess: reference.hasAccess,
|
|
238
|
+
productType: reference.productType
|
|
236
239
|
})))))));
|
|
237
240
|
} else {
|
|
238
241
|
return /*#__PURE__*/React.createElement(NoResultScreen, {
|
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import commonMessages, { syncBlockMessages as messages } from '@atlaskit/editor-common/messages';
|
|
3
|
+
import { FloatingToolbarButton as Button } from '@atlaskit/editor-common/ui';
|
|
3
4
|
import { findDomRefAtPos } from '@atlaskit/editor-prosemirror/utils';
|
|
4
5
|
import { akEditorSelectedNodeClassName } from '@atlaskit/editor-shared-styles/consts';
|
|
5
6
|
import { SyncBlockError } from '@atlaskit/editor-synced-block-provider';
|
|
6
7
|
import CopyIcon from '@atlaskit/icon/core/copy';
|
|
7
8
|
import DeleteIcon from '@atlaskit/icon/core/delete';
|
|
8
9
|
import EditIcon from '@atlaskit/icon/core/edit';
|
|
10
|
+
import LinkBrokenIcon from '@atlaskit/icon/core/link-broken';
|
|
9
11
|
import { fg } from '@atlaskit/platform-feature-flags';
|
|
10
|
-
import { copySyncedBlockReferenceToClipboard, editSyncedBlockSource, removeSyncedBlock } from '../editor-commands';
|
|
12
|
+
import { copySyncedBlockReferenceToClipboard, editSyncedBlockSource, removeSyncedBlock, unsync } from '../editor-commands';
|
|
11
13
|
import { findSyncBlockOrBodiedSyncBlock, isBodiedSyncBlockNode } from '../pm-plugins/utils/utils';
|
|
12
14
|
import { SYNCED_BLOCK_BUTTON_TEST_ID } from '../types';
|
|
13
15
|
import { SyncedLocationDropdown } from './SyncedLocationDropdown';
|
|
@@ -69,7 +71,21 @@ export const getToolbarConfig = (state, intl, api, syncBlockStore) => {
|
|
|
69
71
|
});
|
|
70
72
|
}
|
|
71
73
|
};
|
|
72
|
-
|
|
74
|
+
const unsyncButton = {
|
|
75
|
+
type: 'custom',
|
|
76
|
+
fallback: [],
|
|
77
|
+
render: view => {
|
|
78
|
+
return /*#__PURE__*/React.createElement(Button, {
|
|
79
|
+
areAnyNewToolbarFlagsEnabled: true,
|
|
80
|
+
icon: /*#__PURE__*/React.createElement(LinkBrokenIcon, {
|
|
81
|
+
label: ""
|
|
82
|
+
}),
|
|
83
|
+
title: formatMessage(messages.unsyncButton),
|
|
84
|
+
onClick: () => unsync(syncBlockStore, isBodiedSyncBlock, view)
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
items.push(syncedLocation, unsyncButton);
|
|
73
89
|
}
|
|
74
90
|
const copyButton = {
|
|
75
91
|
id: 'editor.syncedBlock.copy',
|
|
@@ -1,11 +1,14 @@
|
|
|
1
|
+
import { defaultSchema } from '@atlaskit/adf-schema/schema-default';
|
|
1
2
|
import { ACTION, ACTION_SUBJECT, ACTION_SUBJECT_ID, EVENT_TYPE } from '@atlaskit/editor-common/analytics';
|
|
2
3
|
import { copyDomNode, toDOM } from '@atlaskit/editor-common/copy-button';
|
|
4
|
+
import { DOMSerializer, Fragment } from '@atlaskit/editor-prosemirror/model';
|
|
3
5
|
import { TextSelection } from '@atlaskit/editor-prosemirror/state';
|
|
4
6
|
import { findSelectedNodeOfType, removeParentNodeOfType, removeSelectedNode, safeInsert } from '@atlaskit/editor-prosemirror/utils';
|
|
5
7
|
import { fg } from '@atlaskit/platform-feature-flags';
|
|
6
8
|
import { syncedBlockPluginKey } from '../pm-plugins/main';
|
|
7
9
|
import { canBeConvertedToSyncBlock, findSyncBlock, findSyncBlockOrBodiedSyncBlock, isBodiedSyncBlockNode } from '../pm-plugins/utils/utils';
|
|
8
10
|
import { FLAG_ID } from '../types';
|
|
11
|
+
import { pasteSyncBlockHTMLContent } from './utils';
|
|
9
12
|
export var createSyncedBlock = function createSyncedBlock(_ref) {
|
|
10
13
|
var tr = _ref.tr,
|
|
11
14
|
syncBlockStore = _ref.syncBlockStore,
|
|
@@ -168,4 +171,33 @@ export var removeSyncedBlock = function removeSyncedBlock(api) {
|
|
|
168
171
|
api === null || api === void 0 || api.core.actions.focus();
|
|
169
172
|
return true;
|
|
170
173
|
};
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Deletes (bodied)SyncBlock node and paste its content to the editor
|
|
178
|
+
*/
|
|
179
|
+
export var unsync = function unsync(storeManager, isBodiedSyncBlock, view) {
|
|
180
|
+
var _storeManager$referen;
|
|
181
|
+
if (!view) {
|
|
182
|
+
return false;
|
|
183
|
+
}
|
|
184
|
+
var state = view.state;
|
|
185
|
+
var syncBlock = findSyncBlockOrBodiedSyncBlock(state.schema, state.selection);
|
|
186
|
+
if (!syncBlock) {
|
|
187
|
+
return false;
|
|
188
|
+
}
|
|
189
|
+
if (isBodiedSyncBlock) {
|
|
190
|
+
return true;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// handle syncBlock unsync
|
|
194
|
+
var syncBlockContent = (_storeManager$referen = storeManager.referenceManager.getFromCache(syncBlock.node.attrs.resourceId)) === null || _storeManager$referen === void 0 || (_storeManager$referen = _storeManager$referen.data) === null || _storeManager$referen === void 0 ? void 0 : _storeManager$referen.content;
|
|
195
|
+
if (!syncBlockContent) {
|
|
196
|
+
return false;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// use defaultSchema for serialization so we can serialize any type of nodes and marks despite current editor's schema might not allow it
|
|
200
|
+
var contentFragment = Fragment.fromJSON(defaultSchema, syncBlockContent);
|
|
201
|
+
var contentDOM = DOMSerializer.fromSchema(defaultSchema).serializeFragment(contentFragment);
|
|
202
|
+
return pasteSyncBlockHTMLContent(contentDOM, view);
|
|
171
203
|
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export var pasteSyncBlockHTMLContent = function pasteSyncBlockHTMLContent(contentDOM, view) {
|
|
2
|
+
var tmpDiv = document.createElement('div');
|
|
3
|
+
tmpDiv.appendChild(contentDOM);
|
|
4
|
+
|
|
5
|
+
// This is required so that prosemirror can read the fragment context and slice properly
|
|
6
|
+
if (tmpDiv.firstChild instanceof HTMLElement) {
|
|
7
|
+
tmpDiv.firstChild.setAttribute('data-pm-slice', '0 0 []');
|
|
8
|
+
|
|
9
|
+
// As per requirement - when unsync reference block, it should render its content as copy&paste behaviour
|
|
10
|
+
// Hence here we call pasteHTML to evoke editor paste logic that handles any unsupported nodes/marks
|
|
11
|
+
return view.pasteHTML(tmpDiv.innerHTML);
|
|
12
|
+
}
|
|
13
|
+
return false;
|
|
14
|
+
};
|
|
@@ -1,31 +1,123 @@
|
|
|
1
|
-
import
|
|
1
|
+
import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
|
|
2
|
+
import React, { useCallback, useState } from 'react';
|
|
3
|
+
import isYesterday from 'date-fns/isYesterday';
|
|
2
4
|
import { useIntl } from 'react-intl-next';
|
|
3
5
|
import { syncBlockMessages as messages } from '@atlaskit/editor-common/messages';
|
|
4
6
|
import { SyncBlockLabelSharedCssClassName } from '@atlaskit/editor-common/sync-block';
|
|
5
7
|
import BlockSyncedIcon from '@atlaskit/icon-lab/core/block-synced';
|
|
8
|
+
import { fg } from '@atlaskit/platform-feature-flags';
|
|
6
9
|
import { Text } from '@atlaskit/primitives/compiled';
|
|
7
10
|
import Tooltip from '@atlaskit/tooltip';
|
|
8
11
|
import VisuallyHidden from '@atlaskit/visually-hidden';
|
|
9
12
|
var SyncBlockLabelDataId = 'sync-block-label';
|
|
13
|
+
var SECONDS_IN_MINUTE = 60;
|
|
14
|
+
var SECONDS_IN_HOUR = SECONDS_IN_MINUTE * 60;
|
|
15
|
+
var SECONDS_IN_DAY = SECONDS_IN_HOUR * 24;
|
|
16
|
+
var SECONDS_IN_WEEK = SECONDS_IN_DAY * 7;
|
|
17
|
+
var SECONDS_IN_MONTH = SECONDS_IN_DAY * 30;
|
|
18
|
+
var SECONDS_IN_YEAR = SECONDS_IN_DAY * 365;
|
|
19
|
+
export var formatElapsedTime = function formatElapsedTime(isoDate, intl) {
|
|
20
|
+
var now = Date.now();
|
|
21
|
+
var date = new Date(isoDate).getTime();
|
|
22
|
+
var diffInSeconds = Math.floor((now - date) / 1000);
|
|
23
|
+
var dateObj = new Date(isoDate);
|
|
24
|
+
|
|
25
|
+
// Show "yesterday" when timestamp is from the previous calendar day
|
|
26
|
+
if (isYesterday(dateObj) && diffInSeconds >= SECONDS_IN_DAY) {
|
|
27
|
+
return intl.formatRelativeTime(-1, 'day', {
|
|
28
|
+
numeric: 'auto',
|
|
29
|
+
style: 'long'
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
if (diffInSeconds < SECONDS_IN_MINUTE) {
|
|
33
|
+
return intl.formatRelativeTime(-Math.max(diffInSeconds, 1), 'second', {
|
|
34
|
+
style: 'long'
|
|
35
|
+
});
|
|
36
|
+
} else if (diffInSeconds < SECONDS_IN_HOUR) {
|
|
37
|
+
var minutes = Math.floor(diffInSeconds / SECONDS_IN_MINUTE);
|
|
38
|
+
return intl.formatRelativeTime(-minutes, 'minute', {
|
|
39
|
+
style: 'long'
|
|
40
|
+
});
|
|
41
|
+
} else if (diffInSeconds < SECONDS_IN_DAY) {
|
|
42
|
+
var hours = Math.floor(diffInSeconds / SECONDS_IN_HOUR);
|
|
43
|
+
return intl.formatRelativeTime(-hours, 'hour', {
|
|
44
|
+
style: 'long'
|
|
45
|
+
});
|
|
46
|
+
} else if (diffInSeconds < SECONDS_IN_WEEK) {
|
|
47
|
+
var days = Math.floor(diffInSeconds / SECONDS_IN_DAY);
|
|
48
|
+
return intl.formatRelativeTime(-days, 'day', {
|
|
49
|
+
style: 'long'
|
|
50
|
+
});
|
|
51
|
+
} else if (diffInSeconds < SECONDS_IN_MONTH) {
|
|
52
|
+
var weeks = Math.floor(diffInSeconds / SECONDS_IN_WEEK);
|
|
53
|
+
return intl.formatRelativeTime(-weeks, 'week', {
|
|
54
|
+
style: 'long'
|
|
55
|
+
});
|
|
56
|
+
} else if (diffInSeconds < SECONDS_IN_YEAR) {
|
|
57
|
+
var months = Math.floor(diffInSeconds / SECONDS_IN_MONTH);
|
|
58
|
+
return intl.formatRelativeTime(-months, 'month', {
|
|
59
|
+
style: 'long'
|
|
60
|
+
});
|
|
61
|
+
} else {
|
|
62
|
+
var years = Math.floor(diffInSeconds / SECONDS_IN_YEAR);
|
|
63
|
+
return intl.formatRelativeTime(-years, 'year', {
|
|
64
|
+
style: 'long'
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
};
|
|
10
68
|
var SyncBlockLabelComponent = function SyncBlockLabelComponent(_ref) {
|
|
11
69
|
var isSource = _ref.isSource,
|
|
12
70
|
useFetchSyncBlockTitle = _ref.useFetchSyncBlockTitle,
|
|
13
|
-
localId = _ref.localId
|
|
14
|
-
|
|
15
|
-
|
|
71
|
+
localId = _ref.localId,
|
|
72
|
+
contentUpdatedAt = _ref.contentUpdatedAt;
|
|
73
|
+
var intl = useIntl();
|
|
74
|
+
var formatMessage = intl.formatMessage;
|
|
16
75
|
var title = useFetchSyncBlockTitle === null || useFetchSyncBlockTitle === void 0 ? void 0 : useFetchSyncBlockTitle();
|
|
17
|
-
var
|
|
18
|
-
|
|
19
|
-
|
|
76
|
+
var _useState = useState(formatMessage(messages.defaultSyncBlockTooltip)),
|
|
77
|
+
_useState2 = _slicedToArray(_useState, 2),
|
|
78
|
+
tooltipContent = _useState2[0],
|
|
79
|
+
setTooltipContent = _useState2[1];
|
|
80
|
+
var tooltipMessage = formatMessage(messages.defaultSyncBlockTooltip);
|
|
81
|
+
if (isSource) {
|
|
82
|
+
tooltipMessage = formatMessage(messages.sourceSyncBlockTooltip);
|
|
83
|
+
} else if (title) {
|
|
84
|
+
tooltipMessage = formatMessage(messages.referenceSyncBlockTooltip, {
|
|
85
|
+
title: title
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
var updateTooltipContent = useCallback(function () {
|
|
89
|
+
if (!fg('platform_synced_block_dogfooding')) {
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
var tooltipContent = tooltipMessage;
|
|
93
|
+
if (contentUpdatedAt) {
|
|
94
|
+
var elapsedTime = formatElapsedTime(contentUpdatedAt, intl);
|
|
95
|
+
tooltipContent = /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement(Text, {
|
|
96
|
+
size: "small",
|
|
97
|
+
color: "color.text.inverse"
|
|
98
|
+
}, tooltipMessage), /*#__PURE__*/React.createElement("br", null), /*#__PURE__*/React.createElement("br", null), /*#__PURE__*/React.createElement(Text, {
|
|
99
|
+
size: "small",
|
|
100
|
+
color: "color.text.inverse",
|
|
101
|
+
weight: "bold"
|
|
102
|
+
}, formatMessage(messages.referenceSyncBlockLastEdited)), /*#__PURE__*/React.createElement(Text, {
|
|
103
|
+
size: "small",
|
|
104
|
+
color: "color.text.inverse"
|
|
105
|
+
}, elapsedTime));
|
|
106
|
+
}
|
|
107
|
+
setTooltipContent(tooltipContent);
|
|
108
|
+
}, [contentUpdatedAt, formatMessage, intl, tooltipMessage]);
|
|
20
109
|
var ariaDescribedById = "sync-block-label-description-".concat(localId);
|
|
21
110
|
return /*#__PURE__*/React.createElement(Tooltip, {
|
|
22
111
|
position: "top",
|
|
23
|
-
content: tooltipContent
|
|
112
|
+
content: fg('platform_synced_block_dogfooding') ? tooltipContent : tooltipMessage
|
|
24
113
|
// workaround because tooltip adds aria-describedby with a new id every time the tooltip is opened
|
|
25
114
|
// this causes an infinite rerender loop because of the forwardRef from the node view we are inside in bodiedSyncBlock
|
|
26
115
|
// tooltip content is available for screen readers in visually hidden content after the label
|
|
27
116
|
,
|
|
28
117
|
isScreenReaderAnnouncementDisabled: true
|
|
118
|
+
// using this to ensure that the 'last edited' time is updated when the tooltip is opened
|
|
119
|
+
,
|
|
120
|
+
onShow: updateTooltipContent
|
|
29
121
|
}, /*#__PURE__*/React.createElement("div", {
|
|
30
122
|
"data-testid": SyncBlockLabelDataId
|
|
31
123
|
// eslint-disable-next-line @atlaskit/ui-styling-standard/no-classname-prop
|
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
import { useEffect } from 'react';
|
|
2
2
|
import { useSharedPluginStateWithSelector } from '@atlaskit/editor-common/hooks';
|
|
3
|
+
import { isOfflineMode } from '@atlaskit/editor-plugin-connectivity';
|
|
4
|
+
import { fg } from '@atlaskit/platform-feature-flags';
|
|
3
5
|
export var SYNC_BLOCK_FETCH_INTERVAL = 3000;
|
|
4
6
|
|
|
5
|
-
// Component that
|
|
6
|
-
//
|
|
7
|
+
// Component that manages synced block data synchronization.
|
|
8
|
+
// When the feature flag 'platform_synced_block_dogfooding' is enabled,
|
|
9
|
+
// it uses provider-based GraphQL subscriptions for updates.
|
|
10
|
+
// When disabled, it falls back to polling at regular intervals.
|
|
7
11
|
export var SyncBlockRefresher = function SyncBlockRefresher(_ref) {
|
|
8
12
|
var syncBlockStoreManager = _ref.syncBlockStoreManager,
|
|
9
13
|
api = _ref.api;
|
|
@@ -14,9 +18,19 @@ export var SyncBlockRefresher = function SyncBlockRefresher(_ref) {
|
|
|
14
18
|
};
|
|
15
19
|
}),
|
|
16
20
|
mode = _useSharedPluginState.mode;
|
|
21
|
+
var featureFlagEnabled = fg('platform_synced_block_dogfooding');
|
|
22
|
+
var isOnline = !isOfflineMode(mode);
|
|
17
23
|
useEffect(function () {
|
|
24
|
+
var useRealTimeSubscriptions = featureFlagEnabled && isOnline;
|
|
25
|
+
syncBlockStoreManager.referenceManager.setRealTimeSubscriptionsEnabled(useRealTimeSubscriptions);
|
|
26
|
+
}, [syncBlockStoreManager, featureFlagEnabled, isOnline]);
|
|
27
|
+
useEffect(function () {
|
|
28
|
+
var useRealTimeSubscriptions = featureFlagEnabled && isOnline;
|
|
29
|
+
if (useRealTimeSubscriptions) {
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
18
32
|
var interval = -1;
|
|
19
|
-
if (
|
|
33
|
+
if (isOnline) {
|
|
20
34
|
interval = window.setInterval(function () {
|
|
21
35
|
var _document;
|
|
22
36
|
// check if document is visible to avoid unnecessary refreshes
|
|
@@ -30,6 +44,6 @@ export var SyncBlockRefresher = function SyncBlockRefresher(_ref) {
|
|
|
30
44
|
return function () {
|
|
31
45
|
window.clearInterval(interval);
|
|
32
46
|
};
|
|
33
|
-
}, [syncBlockStoreManager,
|
|
47
|
+
}, [syncBlockStoreManager, isOnline, featureFlagEnabled]);
|
|
34
48
|
return null;
|
|
35
49
|
};
|
|
@@ -3,22 +3,26 @@ import { SyncBlockSharedCssClassName } from '@atlaskit/editor-common/sync-block'
|
|
|
3
3
|
import { SyncBlockLabel } from './SyncBlockLabel';
|
|
4
4
|
var SyncBlockRendererWrapperDataId = 'sync-block-plugin-renderer-wrapper';
|
|
5
5
|
var SyncBlockRendererWrapperComponent = function SyncBlockRendererWrapperComponent(_ref) {
|
|
6
|
+
var _syncBlockFetchResult;
|
|
6
7
|
var syncedBlockRenderer = _ref.syncedBlockRenderer,
|
|
7
8
|
useFetchSyncBlockData = _ref.useFetchSyncBlockData,
|
|
8
|
-
localId = _ref.localId,
|
|
9
9
|
useFetchSyncBlockTitle = _ref.useFetchSyncBlockTitle,
|
|
10
|
+
localId = _ref.localId,
|
|
10
11
|
api = _ref.api;
|
|
12
|
+
var syncBlockFetchResult = useFetchSyncBlockData();
|
|
13
|
+
var contentUpdatedAt = syncBlockFetchResult === null || syncBlockFetchResult === void 0 || (_syncBlockFetchResult = syncBlockFetchResult.syncBlockInstance) === null || _syncBlockFetchResult === void 0 || (_syncBlockFetchResult = _syncBlockFetchResult.data) === null || _syncBlockFetchResult === void 0 ? void 0 : _syncBlockFetchResult.contentUpdatedAt;
|
|
11
14
|
return /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("div", {
|
|
12
15
|
"data-testid": SyncBlockRendererWrapperDataId
|
|
13
16
|
// eslint-disable-next-line @atlaskit/ui-styling-standard/no-classname-prop
|
|
14
17
|
,
|
|
15
18
|
className: SyncBlockSharedCssClassName.renderer
|
|
16
19
|
}, syncedBlockRenderer({
|
|
17
|
-
|
|
20
|
+
syncBlockFetchResult: syncBlockFetchResult,
|
|
18
21
|
api: api
|
|
19
22
|
})), /*#__PURE__*/React.createElement(SyncBlockLabel, {
|
|
20
23
|
isSource: false,
|
|
21
24
|
useFetchSyncBlockTitle: useFetchSyncBlockTitle,
|
|
25
|
+
contentUpdatedAt: contentUpdatedAt,
|
|
22
26
|
localId: localId
|
|
23
27
|
}));
|
|
24
28
|
};
|
|
@@ -47,16 +47,17 @@ var styles = {
|
|
|
47
47
|
var ItemTitle = function ItemTitle(_ref) {
|
|
48
48
|
var title = _ref.title,
|
|
49
49
|
formatMessage = _ref.formatMessage,
|
|
50
|
-
|
|
50
|
+
onSameDocument = _ref.onSameDocument,
|
|
51
51
|
isSource = _ref.isSource,
|
|
52
|
-
hasAccess = _ref.hasAccess
|
|
52
|
+
hasAccess = _ref.hasAccess,
|
|
53
|
+
productType = _ref.productType;
|
|
53
54
|
return /*#__PURE__*/React.createElement(Inline, null, /*#__PURE__*/React.createElement(Box, {
|
|
54
55
|
as: "span",
|
|
55
56
|
xcss: styles.title
|
|
56
|
-
}, title),
|
|
57
|
+
}, title), onSameDocument && /*#__PURE__*/React.createElement(Box, {
|
|
57
58
|
as: "span",
|
|
58
59
|
xcss: styles.note
|
|
59
|
-
}, "\xA0- ", formatMessage(messages.
|
|
60
|
+
}, "\xA0- ", formatMessage(productType === 'confluence-page' ? messages.syncedLocationDropdownTitleNoteForConfluencePage : messages.syncedLocationDropdownTitleNoteForJiraWorkItem)), isSource && /*#__PURE__*/React.createElement(Box, {
|
|
60
61
|
as: "span",
|
|
61
62
|
xcss: styles.lozenge
|
|
62
63
|
}, /*#__PURE__*/React.createElement(Lozenge, null, formatMessage(messages.syncedLocationDropdownSourceLozenge))), !hasAccess && /*#__PURE__*/React.createElement(Box, {
|
|
@@ -73,7 +74,7 @@ var subTypeIconMap = {
|
|
|
73
74
|
page: PageIcon,
|
|
74
75
|
blogpost: QuotationMarkIcon
|
|
75
76
|
};
|
|
76
|
-
var
|
|
77
|
+
var getConfluenceSubTypeIcon = function getConfluenceSubTypeIcon(subType) {
|
|
77
78
|
return subType && subType in subTypeIconMap ? subTypeIconMap[subType] : PageIcon;
|
|
78
79
|
};
|
|
79
80
|
var ProductIcon = function ProductIcon(_ref2) {
|
|
@@ -90,17 +91,18 @@ var ProductIcon = function ProductIcon(_ref2) {
|
|
|
90
91
|
var ItemIcon = function ItemIcon(_ref3) {
|
|
91
92
|
var reference = _ref3.reference;
|
|
92
93
|
var hasAccess = reference.hasAccess,
|
|
93
|
-
subType = reference.subType
|
|
94
|
-
|
|
94
|
+
subType = reference.subType,
|
|
95
|
+
productType = reference.productType;
|
|
96
|
+
if (productType === 'confluence-page' && hasAccess) {
|
|
95
97
|
return /*#__PURE__*/React.createElement(IconTile, {
|
|
96
|
-
icon:
|
|
98
|
+
icon: getConfluenceSubTypeIcon(subType),
|
|
97
99
|
label: "",
|
|
98
100
|
appearance: 'gray',
|
|
99
101
|
size: "xsmall"
|
|
100
102
|
});
|
|
101
103
|
}
|
|
102
104
|
return /*#__PURE__*/React.createElement(ProductIcon, {
|
|
103
|
-
product:
|
|
105
|
+
product: productType
|
|
104
106
|
});
|
|
105
107
|
};
|
|
106
108
|
export var processReferenceData = function processReferenceData(referenceData, intl) {
|
|
@@ -268,9 +270,10 @@ var DropdownContent = function DropdownContent(_ref7) {
|
|
|
268
270
|
}, /*#__PURE__*/React.createElement(ItemTitle, {
|
|
269
271
|
title: reference.title || reference.url || '',
|
|
270
272
|
formatMessage: formatMessage,
|
|
271
|
-
|
|
273
|
+
onSameDocument: reference.onSameDocument,
|
|
272
274
|
isSource: reference.isSource,
|
|
273
|
-
hasAccess: reference.hasAccess
|
|
275
|
+
hasAccess: reference.hasAccess,
|
|
276
|
+
productType: reference.productType
|
|
274
277
|
}))));
|
|
275
278
|
})));
|
|
276
279
|
} else {
|
|
@@ -3,14 +3,16 @@ function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbol
|
|
|
3
3
|
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) { _defineProperty(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; }
|
|
4
4
|
import React from 'react';
|
|
5
5
|
import commonMessages, { syncBlockMessages as messages } from '@atlaskit/editor-common/messages';
|
|
6
|
+
import { FloatingToolbarButton as Button } from '@atlaskit/editor-common/ui';
|
|
6
7
|
import { findDomRefAtPos } from '@atlaskit/editor-prosemirror/utils';
|
|
7
8
|
import { akEditorSelectedNodeClassName } from '@atlaskit/editor-shared-styles/consts';
|
|
8
9
|
import { SyncBlockError } from '@atlaskit/editor-synced-block-provider';
|
|
9
10
|
import CopyIcon from '@atlaskit/icon/core/copy';
|
|
10
11
|
import DeleteIcon from '@atlaskit/icon/core/delete';
|
|
11
12
|
import EditIcon from '@atlaskit/icon/core/edit';
|
|
13
|
+
import LinkBrokenIcon from '@atlaskit/icon/core/link-broken';
|
|
12
14
|
import { fg } from '@atlaskit/platform-feature-flags';
|
|
13
|
-
import { copySyncedBlockReferenceToClipboard, editSyncedBlockSource, removeSyncedBlock } from '../editor-commands';
|
|
15
|
+
import { copySyncedBlockReferenceToClipboard, editSyncedBlockSource, removeSyncedBlock, unsync } from '../editor-commands';
|
|
14
16
|
import { findSyncBlockOrBodiedSyncBlock, isBodiedSyncBlockNode } from '../pm-plugins/utils/utils';
|
|
15
17
|
import { SYNCED_BLOCK_BUTTON_TEST_ID } from '../types';
|
|
16
18
|
import { SyncedLocationDropdown } from './SyncedLocationDropdown';
|
|
@@ -64,7 +66,23 @@ export var getToolbarConfig = function getToolbarConfig(state, intl, api, syncBl
|
|
|
64
66
|
});
|
|
65
67
|
}
|
|
66
68
|
};
|
|
67
|
-
|
|
69
|
+
var unsyncButton = {
|
|
70
|
+
type: 'custom',
|
|
71
|
+
fallback: [],
|
|
72
|
+
render: function render(view) {
|
|
73
|
+
return /*#__PURE__*/React.createElement(Button, {
|
|
74
|
+
areAnyNewToolbarFlagsEnabled: true,
|
|
75
|
+
icon: /*#__PURE__*/React.createElement(LinkBrokenIcon, {
|
|
76
|
+
label: ""
|
|
77
|
+
}),
|
|
78
|
+
title: formatMessage(messages.unsyncButton),
|
|
79
|
+
onClick: function onClick() {
|
|
80
|
+
return unsync(syncBlockStore, isBodiedSyncBlock, view);
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
items.push(syncedLocation, unsyncButton);
|
|
68
86
|
}
|
|
69
87
|
var copyButton = _objectSpread({
|
|
70
88
|
id: 'editor.syncedBlock.copy',
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { type DispatchAnalyticsEvent } from '@atlaskit/editor-common/analytics';
|
|
2
2
|
import type { Command, EditorCommand, ExtractInjectionAPI, TypeAheadInsert } from '@atlaskit/editor-common/types';
|
|
3
3
|
import { type Transaction } from '@atlaskit/editor-prosemirror/state';
|
|
4
|
+
import type { EditorView } from '@atlaskit/editor-prosemirror/view';
|
|
4
5
|
import type { SyncBlockStoreManager } from '@atlaskit/editor-synced-block-provider';
|
|
5
6
|
import type { SyncedBlockPlugin } from '../syncedBlockPluginType';
|
|
6
7
|
type createSyncedBlockProps = {
|
|
@@ -14,4 +15,8 @@ export declare const copySyncedBlockReferenceToClipboardEditorCommand: (syncBloc
|
|
|
14
15
|
export declare const copySyncedBlockReferenceToClipboard: (syncBlockStore: SyncBlockStoreManager, api?: ExtractInjectionAPI<SyncedBlockPlugin>) => Command;
|
|
15
16
|
export declare const editSyncedBlockSource: (syncBlockStore: SyncBlockStoreManager, api?: ExtractInjectionAPI<SyncedBlockPlugin>) => Command;
|
|
16
17
|
export declare const removeSyncedBlock: (api?: ExtractInjectionAPI<SyncedBlockPlugin>) => Command;
|
|
18
|
+
/**
|
|
19
|
+
* Deletes (bodied)SyncBlock node and paste its content to the editor
|
|
20
|
+
*/
|
|
21
|
+
export declare const unsync: (storeManager: SyncBlockStoreManager, isBodiedSyncBlock: boolean, view?: EditorView) => boolean;
|
|
17
22
|
export {};
|
|
@@ -37,7 +37,7 @@ export type SyncedBlockEditorProps = {
|
|
|
37
37
|
};
|
|
38
38
|
export type SyncedBlockRendererProps = {
|
|
39
39
|
api?: ExtractInjectionAPI<SyncedBlockPlugin>;
|
|
40
|
-
|
|
40
|
+
syncBlockFetchResult: UseFetchSyncBlockDataResult;
|
|
41
41
|
};
|
|
42
42
|
export interface SyncedBlockPluginOptions extends LongPressSelectionPluginOptions {
|
|
43
43
|
enableSourceCreation?: boolean;
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
+
import { type IntlShape } from 'react-intl-next';
|
|
3
|
+
export declare const formatElapsedTime: (isoDate: string, intl: IntlShape) => string;
|
|
2
4
|
type SyncBlockLabelProps = {
|
|
5
|
+
contentUpdatedAt?: string;
|
|
3
6
|
isSource: boolean;
|
|
4
7
|
localId: string;
|
|
5
8
|
useFetchSyncBlockTitle?: () => string | undefined;
|
|
6
9
|
};
|
|
7
|
-
export declare const SyncBlockLabel: React.MemoExoticComponent<({ isSource, useFetchSyncBlockTitle, localId, }: SyncBlockLabelProps) => React.JSX.Element>;
|
|
10
|
+
export declare const SyncBlockLabel: React.MemoExoticComponent<({ isSource, useFetchSyncBlockTitle, localId, contentUpdatedAt, }: SyncBlockLabelProps) => React.JSX.Element>;
|
|
8
11
|
export {};
|
|
@@ -9,5 +9,5 @@ type Props = {
|
|
|
9
9
|
useFetchSyncBlockData: () => UseFetchSyncBlockDataResult;
|
|
10
10
|
useFetchSyncBlockTitle: () => string | undefined;
|
|
11
11
|
};
|
|
12
|
-
export declare const SyncBlockRendererWrapper: React.MemoExoticComponent<({ syncedBlockRenderer, useFetchSyncBlockData,
|
|
12
|
+
export declare const SyncBlockRendererWrapper: React.MemoExoticComponent<({ syncedBlockRenderer, useFetchSyncBlockData, useFetchSyncBlockTitle, localId, api, }: Props) => React.JSX.Element>;
|
|
13
13
|
export {};
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { type DispatchAnalyticsEvent } from '@atlaskit/editor-common/analytics';
|
|
2
2
|
import type { Command, EditorCommand, ExtractInjectionAPI, TypeAheadInsert } from '@atlaskit/editor-common/types';
|
|
3
3
|
import { type Transaction } from '@atlaskit/editor-prosemirror/state';
|
|
4
|
+
import type { EditorView } from '@atlaskit/editor-prosemirror/view';
|
|
4
5
|
import type { SyncBlockStoreManager } from '@atlaskit/editor-synced-block-provider';
|
|
5
6
|
import type { SyncedBlockPlugin } from '../syncedBlockPluginType';
|
|
6
7
|
type createSyncedBlockProps = {
|
|
@@ -14,4 +15,8 @@ export declare const copySyncedBlockReferenceToClipboardEditorCommand: (syncBloc
|
|
|
14
15
|
export declare const copySyncedBlockReferenceToClipboard: (syncBlockStore: SyncBlockStoreManager, api?: ExtractInjectionAPI<SyncedBlockPlugin>) => Command;
|
|
15
16
|
export declare const editSyncedBlockSource: (syncBlockStore: SyncBlockStoreManager, api?: ExtractInjectionAPI<SyncedBlockPlugin>) => Command;
|
|
16
17
|
export declare const removeSyncedBlock: (api?: ExtractInjectionAPI<SyncedBlockPlugin>) => Command;
|
|
18
|
+
/**
|
|
19
|
+
* Deletes (bodied)SyncBlock node and paste its content to the editor
|
|
20
|
+
*/
|
|
21
|
+
export declare const unsync: (storeManager: SyncBlockStoreManager, isBodiedSyncBlock: boolean, view?: EditorView) => boolean;
|
|
17
22
|
export {};
|
|
@@ -37,7 +37,7 @@ export type SyncedBlockEditorProps = {
|
|
|
37
37
|
};
|
|
38
38
|
export type SyncedBlockRendererProps = {
|
|
39
39
|
api?: ExtractInjectionAPI<SyncedBlockPlugin>;
|
|
40
|
-
|
|
40
|
+
syncBlockFetchResult: UseFetchSyncBlockDataResult;
|
|
41
41
|
};
|
|
42
42
|
export interface SyncedBlockPluginOptions extends LongPressSelectionPluginOptions {
|
|
43
43
|
enableSourceCreation?: boolean;
|