@atlaskit/editor-plugin-synced-block 1.0.0 → 2.0.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 (103) hide show
  1. package/CHANGELOG.md +5 -21
  2. package/afm-cc/tsconfig.json +0 -15
  3. package/afm-dev-agents/tsconfig.json +0 -15
  4. package/afm-jira/tsconfig.json +0 -15
  5. package/afm-passionfruit/tsconfig.json +0 -15
  6. package/afm-post-office/tsconfig.json +0 -15
  7. package/afm-rovo-extension/tsconfig.json +0 -15
  8. package/afm-townsquare/tsconfig.json +0 -15
  9. package/dist/cjs/nodeviews/syncedBlock.js +20 -0
  10. package/dist/cjs/pm-plugins/main.js +0 -21
  11. package/dist/cjs/syncedBlockPlugin.js +9 -5
  12. package/dist/cjs/ui/floating-toolbar.js +39 -0
  13. package/dist/es2019/nodeviews/syncedBlock.js +10 -0
  14. package/dist/es2019/pm-plugins/main.js +0 -24
  15. package/dist/es2019/syncedBlockPlugin.js +18 -15
  16. package/dist/es2019/ui/floating-toolbar.js +31 -0
  17. package/dist/esm/nodeviews/syncedBlock.js +13 -0
  18. package/dist/esm/pm-plugins/main.js +0 -21
  19. package/dist/esm/syncedBlockPlugin.js +9 -4
  20. package/dist/esm/ui/floating-toolbar.js +32 -0
  21. package/dist/types/index.d.ts +0 -1
  22. package/dist/types/nodeviews/syncedBlock.d.ts +11 -0
  23. package/dist/types/ui/floating-toolbar.d.ts +2 -0
  24. package/dist/types-ts4.5/index.d.ts +0 -1
  25. package/dist/types-ts4.5/nodeviews/syncedBlock.d.ts +11 -0
  26. package/dist/types-ts4.5/ui/floating-toolbar.d.ts +2 -0
  27. package/package.json +3 -9
  28. package/SyncedBlock/package.json +0 -15
  29. package/dist/cjs/pm-plugins/SyncClient.js +0 -167
  30. package/dist/cjs/pm-plugins/utils.js +0 -19
  31. package/dist/cjs/types/index.js +0 -1
  32. package/dist/cjs/ui/extensions/synced-block/components/GlobalStyles.js +0 -25
  33. package/dist/cjs/ui/extensions/synced-block/components/SyncedBlockLiveView.js +0 -25
  34. package/dist/cjs/ui/extensions/synced-block/components/SyncedBlockRenderer.js +0 -25
  35. package/dist/cjs/ui/extensions/synced-block/constants.js +0 -32
  36. package/dist/cjs/ui/extensions/synced-block/getSyncedBlockExtensionProvider.js +0 -11
  37. package/dist/cjs/ui/extensions/synced-block/hooks/useLiveSyncedBlockContent.js +0 -29
  38. package/dist/cjs/ui/extensions/synced-block/hooks/usePollContentProperty.js +0 -121
  39. package/dist/cjs/ui/extensions/synced-block/index.js +0 -19
  40. package/dist/cjs/ui/extensions/synced-block/manifest.js +0 -281
  41. package/dist/cjs/ui/extensions/synced-block/utils/ari.js +0 -29
  42. package/dist/cjs/ui/extensions/synced-block/utils/content-property.js +0 -159
  43. package/dist/cjs/ui/extensions/synced-block/utils/synced-block.js +0 -65
  44. package/dist/es2019/pm-plugins/SyncClient.js +0 -102
  45. package/dist/es2019/pm-plugins/utils.js +0 -13
  46. package/dist/es2019/types/index.js +0 -0
  47. package/dist/es2019/ui/extensions/synced-block/components/GlobalStyles.js +0 -18
  48. package/dist/es2019/ui/extensions/synced-block/components/SyncedBlockLiveView.js +0 -19
  49. package/dist/es2019/ui/extensions/synced-block/components/SyncedBlockRenderer.js +0 -19
  50. package/dist/es2019/ui/extensions/synced-block/constants.js +0 -26
  51. package/dist/es2019/ui/extensions/synced-block/getSyncedBlockExtensionProvider.js +0 -5
  52. package/dist/es2019/ui/extensions/synced-block/hooks/useLiveSyncedBlockContent.js +0 -24
  53. package/dist/es2019/ui/extensions/synced-block/hooks/usePollContentProperty.js +0 -107
  54. package/dist/es2019/ui/extensions/synced-block/index.js +0 -5
  55. package/dist/es2019/ui/extensions/synced-block/manifest.js +0 -172
  56. package/dist/es2019/ui/extensions/synced-block/utils/ari.js +0 -19
  57. package/dist/es2019/ui/extensions/synced-block/utils/content-property.js +0 -108
  58. package/dist/es2019/ui/extensions/synced-block/utils/synced-block.js +0 -57
  59. package/dist/esm/pm-plugins/SyncClient.js +0 -160
  60. package/dist/esm/pm-plugins/utils.js +0 -13
  61. package/dist/esm/types/index.js +0 -0
  62. package/dist/esm/ui/extensions/synced-block/components/GlobalStyles.js +0 -18
  63. package/dist/esm/ui/extensions/synced-block/components/SyncedBlockLiveView.js +0 -18
  64. package/dist/esm/ui/extensions/synced-block/components/SyncedBlockRenderer.js +0 -18
  65. package/dist/esm/ui/extensions/synced-block/constants.js +0 -26
  66. package/dist/esm/ui/extensions/synced-block/getSyncedBlockExtensionProvider.js +0 -5
  67. package/dist/esm/ui/extensions/synced-block/hooks/useLiveSyncedBlockContent.js +0 -23
  68. package/dist/esm/ui/extensions/synced-block/hooks/usePollContentProperty.js +0 -114
  69. package/dist/esm/ui/extensions/synced-block/index.js +0 -5
  70. package/dist/esm/ui/extensions/synced-block/manifest.js +0 -274
  71. package/dist/esm/ui/extensions/synced-block/utils/ari.js +0 -23
  72. package/dist/esm/ui/extensions/synced-block/utils/content-property.js +0 -153
  73. package/dist/esm/ui/extensions/synced-block/utils/synced-block.js +0 -58
  74. package/dist/types/pm-plugins/SyncClient.d.ts +0 -14
  75. package/dist/types/pm-plugins/utils.d.ts +0 -5
  76. package/dist/types/types/index.d.ts +0 -3
  77. package/dist/types/ui/extensions/synced-block/components/GlobalStyles.d.ts +0 -6
  78. package/dist/types/ui/extensions/synced-block/components/SyncedBlockLiveView.d.ts +0 -7
  79. package/dist/types/ui/extensions/synced-block/components/SyncedBlockRenderer.d.ts +0 -7
  80. package/dist/types/ui/extensions/synced-block/constants.d.ts +0 -8
  81. package/dist/types/ui/extensions/synced-block/getSyncedBlockExtensionProvider.d.ts +0 -3
  82. package/dist/types/ui/extensions/synced-block/hooks/useLiveSyncedBlockContent.d.ts +0 -6
  83. package/dist/types/ui/extensions/synced-block/hooks/usePollContentProperty.d.ts +0 -7
  84. package/dist/types/ui/extensions/synced-block/index.d.ts +0 -2
  85. package/dist/types/ui/extensions/synced-block/manifest.d.ts +0 -3
  86. package/dist/types/ui/extensions/synced-block/utils/ari.d.ts +0 -4
  87. package/dist/types/ui/extensions/synced-block/utils/content-property.d.ts +0 -33
  88. package/dist/types/ui/extensions/synced-block/utils/synced-block.d.ts +0 -24
  89. package/dist/types-ts4.5/pm-plugins/SyncClient.d.ts +0 -14
  90. package/dist/types-ts4.5/pm-plugins/utils.d.ts +0 -5
  91. package/dist/types-ts4.5/types/index.d.ts +0 -3
  92. package/dist/types-ts4.5/ui/extensions/synced-block/components/GlobalStyles.d.ts +0 -6
  93. package/dist/types-ts4.5/ui/extensions/synced-block/components/SyncedBlockLiveView.d.ts +0 -7
  94. package/dist/types-ts4.5/ui/extensions/synced-block/components/SyncedBlockRenderer.d.ts +0 -7
  95. package/dist/types-ts4.5/ui/extensions/synced-block/constants.d.ts +0 -8
  96. package/dist/types-ts4.5/ui/extensions/synced-block/getSyncedBlockExtensionProvider.d.ts +0 -3
  97. package/dist/types-ts4.5/ui/extensions/synced-block/hooks/useLiveSyncedBlockContent.d.ts +0 -6
  98. package/dist/types-ts4.5/ui/extensions/synced-block/hooks/usePollContentProperty.d.ts +0 -7
  99. package/dist/types-ts4.5/ui/extensions/synced-block/index.d.ts +0 -2
  100. package/dist/types-ts4.5/ui/extensions/synced-block/manifest.d.ts +0 -3
  101. package/dist/types-ts4.5/ui/extensions/synced-block/utils/ari.d.ts +0 -4
  102. package/dist/types-ts4.5/ui/extensions/synced-block/utils/content-property.d.ts +0 -33
  103. package/dist/types-ts4.5/ui/extensions/synced-block/utils/synced-block.d.ts +0 -24
@@ -1,19 +0,0 @@
1
- import React from 'react';
2
- import { useLiveSyncedBlockContent } from '../hooks/useLiveSyncedBlockContent';
3
- import SyncedBlockRenderer from './SyncedBlockRenderer';
4
- const SyncedBlockLiveView = ({
5
- sourceDocumentAri,
6
- contentAri
7
- }) => {
8
- const syncedBlockContent = useLiveSyncedBlockContent({
9
- sourceDocumentAri,
10
- contentAri
11
- });
12
- if (!syncedBlockContent) {
13
- return /*#__PURE__*/React.createElement("div", null, "Loading...");
14
- }
15
- return /*#__PURE__*/React.createElement(SyncedBlockRenderer, {
16
- syncedBlockContent: syncedBlockContent
17
- });
18
- };
19
- export default SyncedBlockLiveView;
@@ -1,19 +0,0 @@
1
- import React from 'react';
2
- import { ReactRenderer } from '@atlaskit/renderer';
3
- import { RendererActionsContext } from '@atlaskit/renderer/actions';
4
- const SyncedBlockRenderer = ({
5
- syncedBlockContent
6
- }) => {
7
- return /*#__PURE__*/React.createElement(RendererActionsContext, null, /*#__PURE__*/React.createElement(ReactRenderer, {
8
- adfStage: "stage0"
9
- // @ts-ignore
10
- ,
11
- document: {
12
- type: 'doc',
13
- version: 1,
14
- content: syncedBlockContent.adf.content
15
- },
16
- appearance: "full-page"
17
- }));
18
- };
19
- export default SyncedBlockRenderer;
@@ -1,26 +0,0 @@
1
- // hello.atlassian.net cloud id
2
- const HELLO_CLOUD_ID = 'a436116f-02ce-4520-8fbb-7301462a1674';
3
-
4
- // spike page https://hello.atlassian.net/wiki/spaces/~7120208ef57ce4d614485e876489301a16b906/pages/5626233808
5
- const TEST_PAGE_ID = '5626233808';
6
- export const getPageId = () => {
7
- var _window$location$href, _window$location$href2, _window$location$path;
8
- return (
9
- // eslint-disable-next-line require-unicode-regexp
10
- ((_window$location$href = window.location.href.match(/pageId=(\d+)/)) === null || _window$location$href === void 0 ? void 0 : _window$location$href[1]) || ( // eslint-disable-next-line require-unicode-regexp
11
- (_window$location$href2 = window.location.href.match(/pages\/edit-v2\/(\d+)/)) === null || _window$location$href2 === void 0 ? void 0 : _window$location$href2[1]) || ( // eslint-disable-next-line require-unicode-regexp
12
- (_window$location$path = window.location.pathname.match(/pages\/(\d+)/)) === null || _window$location$path === void 0 ? void 0 : _window$location$path[1]) ||
13
- // view page or live doc
14
- TEST_PAGE_ID
15
- );
16
- };
17
- /**
18
- * This by no means is a stable way to get the cloud id, but it works for now.
19
- * We should switch passing the cloud id from Confluence to a Editor plugin,
20
- * for instance the user preferences plugin would have a seperate place for user and cloud info
21
- * @returns the cloud id from the initial state
22
- */
23
- export const getCloudId = () => {
24
- var _INITIAL_STATE__, _INITIAL_STATE__$meta;
25
- return ((_INITIAL_STATE__ = window.__INITIAL_STATE__) === null || _INITIAL_STATE__ === void 0 ? void 0 : (_INITIAL_STATE__$meta = _INITIAL_STATE__.meta) === null || _INITIAL_STATE__$meta === void 0 ? void 0 : _INITIAL_STATE__$meta['cloud-id']) || HELLO_CLOUD_ID;
26
- };
@@ -1,5 +0,0 @@
1
- import { DefaultExtensionProvider } from '@atlaskit/editor-common/extensions';
2
- import { getSyncedBlockManifest } from './manifest';
3
- export const getSyncedBlockExtensionProvider = schema => {
4
- return new DefaultExtensionProvider([getSyncedBlockManifest(schema)]);
5
- };
@@ -1,24 +0,0 @@
1
- import { useMemo } from 'react';
2
- import { usePollContentProperty } from '../hooks/usePollContentProperty';
3
- import { parseSyncedBlockContentPropertyValue } from '../utils/synced-block';
4
- export const useLiveSyncedBlockContent = ({
5
- sourceDocumentAri,
6
- contentAri
7
- }) => {
8
- const contentProperty = usePollContentProperty({
9
- sourceDocumentAri,
10
- contentAri
11
- });
12
- return useMemo(() => {
13
- if (!contentProperty) {
14
- return null;
15
- }
16
- try {
17
- return parseSyncedBlockContentPropertyValue(contentProperty.value);
18
- } catch (error) {
19
- // eslint-disable-next-line no-console
20
- console.error('Failed to extract synced block content:', error);
21
- return null;
22
- }
23
- }, [contentProperty]);
24
- };
@@ -1,107 +0,0 @@
1
- import { useEffect, useRef, useState } from 'react';
2
- import { getContentPropertyIdFromAri, getPageIdFromAri } from '../utils/ari';
3
- import { getContentProperty } from '../utils/content-property';
4
- const POLLING_INTERVAL = 1000;
5
- const cache = new Map();
6
- const inFlightRequests = new Map();
7
- const subscribers = new Map();
8
- const pollingTimeouts = new Map();
9
- const lastRequestTimes = new Map();
10
- const getRequestKey = (pageId, contentPropertyId) => `${pageId}:${contentPropertyId}`;
11
- const fetchContentPropertyWithDedup = (pageId, contentPropertyId) => {
12
- const requestKey = getRequestKey(pageId, contentPropertyId);
13
- lastRequestTimes.set(requestKey, Date.now());
14
- const inFlightRequest = inFlightRequests.get(requestKey);
15
- if (inFlightRequest) {
16
- return inFlightRequest;
17
- }
18
- const requestPromise = getContentProperty({
19
- pageId,
20
- contentPropertyId
21
- }).then(result => {
22
- cache.set(requestKey, result);
23
- const subscribersForKey = subscribers.get(requestKey);
24
- if (subscribersForKey) {
25
- subscribersForKey.forEach(callback => callback(result));
26
- }
27
- inFlightRequests.delete(requestKey);
28
- if (subscribersForKey && subscribersForKey.size > 0) {
29
- scheduleNextPoll(pageId, contentPropertyId);
30
- }
31
- return result;
32
- }).catch(error => {
33
- inFlightRequests.delete(requestKey);
34
- const subscribersForKey = subscribers.get(requestKey);
35
- if (subscribersForKey && subscribersForKey.size > 0) {
36
- scheduleNextPoll(pageId, contentPropertyId);
37
- }
38
- throw error;
39
- });
40
- inFlightRequests.set(requestKey, requestPromise);
41
- return requestPromise;
42
- };
43
- const scheduleNextPoll = (pageId, contentPropertyId) => {
44
- const requestKey = getRequestKey(pageId, contentPropertyId);
45
- const existingTimeout = pollingTimeouts.get(requestKey);
46
- if (existingTimeout) {
47
- clearTimeout(existingTimeout);
48
- }
49
- const lastRequestTime = lastRequestTimes.get(requestKey) || 0;
50
- const timeElapsed = Date.now() - lastRequestTime;
51
- const delay = Math.max(100, POLLING_INTERVAL - timeElapsed);
52
- const timeout = setTimeout(() => {
53
- const subscribersForKey = subscribers.get(requestKey);
54
- if (subscribersForKey && subscribersForKey.size > 0) {
55
- fetchContentPropertyWithDedup(pageId, contentPropertyId).catch(error => {
56
- // eslint-disable-next-line no-console
57
- console.error('Failed to fetch content property:', error);
58
- });
59
- } else {
60
- pollingTimeouts.delete(requestKey);
61
- }
62
- }, delay);
63
- pollingTimeouts.set(requestKey, timeout);
64
- };
65
- export const usePollContentProperty = ({
66
- sourceDocumentAri,
67
- contentAri
68
- }) => {
69
- const [contentProperty, setContentProperty] = useState();
70
- const initializedRef = useRef(false);
71
- useEffect(() => {
72
- const pageId = getPageIdFromAri(sourceDocumentAri);
73
- const contentPropertyId = getContentPropertyIdFromAri(contentAri);
74
- const requestKey = getRequestKey(pageId, contentPropertyId);
75
- const subscribersForKey = subscribers.get(requestKey) || new Set();
76
- if (!subscribers.has(requestKey)) {
77
- subscribers.set(requestKey, subscribersForKey);
78
- }
79
- subscribersForKey.add(setContentProperty);
80
- const cachedValue = cache.get(requestKey);
81
- if (cachedValue) {
82
- setContentProperty(cachedValue);
83
- }
84
- if (subscribersForKey.size === 1 || !initializedRef.current) {
85
- initializedRef.current = true;
86
- fetchContentPropertyWithDedup(pageId, contentPropertyId).catch(error => {
87
- // eslint-disable-next-line no-console
88
- console.error('Failed to fetch content property:', error);
89
- });
90
- }
91
- return () => {
92
- subscribersForKey.delete(setContentProperty);
93
- if (subscribersForKey.size === 0) {
94
- subscribers.delete(requestKey);
95
- const existingTimeout = pollingTimeouts.get(requestKey);
96
- if (existingTimeout) {
97
- clearTimeout(existingTimeout);
98
- pollingTimeouts.delete(requestKey);
99
- }
100
- }
101
- };
102
- }, [sourceDocumentAri, contentAri]);
103
- const pageId = getPageIdFromAri(sourceDocumentAri);
104
- const contentPropertyId = getContentPropertyIdFromAri(contentAri);
105
- const requestKey = getRequestKey(pageId, contentPropertyId);
106
- return contentProperty || cache.get(requestKey);
107
- };
@@ -1,5 +0,0 @@
1
- // Disable no-re-export rule for entry point files
2
- /* eslint-disable @atlaskit/editor/no-re-export */
3
-
4
- export { getSyncedBlockExtensionProvider } from './getSyncedBlockExtensionProvider';
5
- export { getSyncedBlockManifest } from './manifest';
@@ -1,172 +0,0 @@
1
- import React from 'react';
2
- import { copyHTMLToClipboard } from '@atlaskit/editor-common/clipboard';
3
- import { DOMSerializer, Fragment, Mark } from '@atlaskit/editor-prosemirror/model';
4
- import SmartLinkIcon from '@atlaskit/icon/core/smart-link';
5
- import SyncedBlockLiveView from './components/SyncedBlockLiveView';
6
- import { getPageId } from './constants';
7
- import { getConfluencePageAri, getContentPropertyAri } from './utils/ari';
8
- import { createContentProperty } from './utils/content-property';
9
- import { SYNCED_BLOCK_EXTENSION_KEY, SYNCED_BLOCK_EXTENSION_TYPE, SYNCED_BLOCK_REFERENCE_KEY, SYNCED_BLOCK_REFERENCE_NODE, SYNCED_BLOCK_SOURCE_KEY, SYNCED_BLOCK_SOURCE_NODE, getDefaultSyncedBlockContent, isSyncedBlockAttributes, stringifySyncedBlockContentPropertyValue } from './utils/synced-block';
10
- const getRandomId = () => {
11
- if (!globalThis.crypto || typeof globalThis.crypto.randomUUID !== 'function') {
12
- return new Date().toISOString();
13
- }
14
- return globalThis.crypto.randomUUID();
15
- };
16
- const copyToClipboard = (adf, schema) => {
17
- if (!schema) {
18
- throw new Error('copyToClipboard(): Schema is required.');
19
- }
20
-
21
- // Validate the given ADF
22
- const nodeType = schema.nodes[adf.type];
23
- if (!nodeType) {
24
- throw new Error(`copyToClipboard(): Invalid ADF type '${adf.type}'.`);
25
- }
26
- const fragment = Fragment.fromJSON(schema, adf.content);
27
- const marks = (adf.marks || []).map(markEntity => Mark.fromJSON(schema, markEntity));
28
- const newNode = nodeType === null || nodeType === void 0 ? void 0 : nodeType.createChecked(adf.attrs, fragment, marks);
29
- if (!newNode) {
30
- throw new Error('copyToClipboard(): Could not create a node for given ADFEntity.');
31
- }
32
- const domNode = DOMSerializer.fromSchema(schema).serializeNode(newNode);
33
- const div = document.createElement('div');
34
- div.appendChild(domNode);
35
- copyHTMLToClipboard(div);
36
- };
37
-
38
- // Remaining tasks
39
- // - Better location for content sync implementation – currently done in SyncedBlockSource renderer which won't work in editor
40
- // - Could implement an editor plugin to do this, if there's no native way to do it with extensions
41
- // - Implement separate content property for storage of the metadata of a synced block, separate from the content
42
- // - Update polling to use the metadata content property, then if metadata updated, fetch the content property
43
- // - Investigate re-rendering of SyncedBlockReference in editor on every document change (is this just atlaskit behavior?)
44
- // - On copy of the synced block, transform into a reference
45
- // - Move implementation into Confluence and test in branch environment
46
- // - Dealing with orphaned synced block content properties data
47
- // - Getting current page id in editor context and the cloud id
48
- // - Explore hiding the frame for the extension in the editor, currently using `__hideFrame: true` and commented code to enable
49
- export const getSyncedBlockManifest = schema => ({
50
- title: 'Synced Block',
51
- type: SYNCED_BLOCK_EXTENSION_TYPE,
52
- key: SYNCED_BLOCK_EXTENSION_KEY,
53
- description: 'Synced block spike',
54
- icons: {
55
- // Ignored via go/ees005
56
- // eslint-disable-next-line require-await
57
- '48': async () => () => /*#__PURE__*/React.createElement(SmartLinkIcon, {
58
- label: "Synced Block",
59
- size: "medium"
60
- })
61
- },
62
- modules: {
63
- quickInsert: [{
64
- key: 'quick-insert-synced-block-source',
65
- action: async _api => {
66
- const contentPropertyKey = `synced-block-` + getRandomId();
67
- const content = getDefaultSyncedBlockContent();
68
- const value = stringifySyncedBlockContentPropertyValue({
69
- adf: content
70
- });
71
- const contentProperty = await createContentProperty({
72
- pageId: getPageId(),
73
- key: contentPropertyKey,
74
- value
75
- });
76
- const attributes = {
77
- extensionType: SYNCED_BLOCK_EXTENSION_TYPE,
78
- extensionKey: SYNCED_BLOCK_SOURCE_KEY,
79
- parameters: {
80
- sourceDocumentAri: getConfluencePageAri(getPageId()),
81
- contentAri: getContentPropertyAri(contentProperty.id),
82
- contentPropertyKey
83
- },
84
- localId: 'testId'
85
- };
86
- content.attrs = attributes;
87
- return content;
88
- }
89
- }],
90
- nodes: {
91
- [SYNCED_BLOCK_SOURCE_NODE]: {
92
- type: 'bodiedExtension',
93
- // Ignored via go/ees005
94
- // eslint-disable-next-line require-await
95
- render: async () => props => {
96
- if (!isSyncedBlockAttributes(props.node)) {
97
- return null;
98
- }
99
- const {
100
- sourceDocumentAri,
101
- contentAri
102
- } = props.node.parameters;
103
- return /*#__PURE__*/React.createElement(SyncedBlockLiveView, {
104
- sourceDocumentAri: sourceDocumentAri,
105
- contentAri: contentAri
106
- });
107
- },
108
- // @ts-expect-error
109
- __hideFrame: true
110
- },
111
- [SYNCED_BLOCK_REFERENCE_NODE]: {
112
- type: 'extension',
113
- // Ignored via go/ees005
114
- // eslint-disable-next-line require-await
115
- render: async () => props => {
116
- if (!isSyncedBlockAttributes(props.node)) {
117
- return null;
118
- }
119
- const {
120
- sourceDocumentAri,
121
- contentAri
122
- } = props.node.parameters;
123
- return /*#__PURE__*/React.createElement(SyncedBlockLiveView, {
124
- sourceDocumentAri: sourceDocumentAri,
125
- contentAri: contentAri
126
- });
127
- },
128
- // @ts-expect-error
129
- __hideFrame: true
130
- }
131
- },
132
- contextualToolbars: [{
133
- context: {
134
- type: 'extension',
135
- nodeType: 'bodiedExtension',
136
- extensionType: SYNCED_BLOCK_EXTENSION_TYPE,
137
- extensionKey: SYNCED_BLOCK_SOURCE_KEY
138
- },
139
- toolbarItems: [{
140
- key: 'toolbar-item-key',
141
- label: 'Referenece',
142
- display: 'icon',
143
- tooltip: 'Copy reference to clipboard',
144
- // Ignored via go/ees005
145
- // eslint-disable-next-line require-await
146
- icon: async () => () => /*#__PURE__*/React.createElement(SmartLinkIcon, {
147
- label: "Synced Block",
148
- size: "medium"
149
- }),
150
- // Ignored via go/ees005
151
- // eslint-disable-next-line require-await
152
- action: async contextNode => {
153
- try {
154
- var _contextNode$attrs, _contextNode$attrs$pa, _contextNode$attrs2, _contextNode$attrs2$p;
155
- copyToClipboard({
156
- type: 'extension',
157
- attrs: {
158
- extensionType: SYNCED_BLOCK_EXTENSION_TYPE,
159
- extensionKey: SYNCED_BLOCK_REFERENCE_KEY,
160
- parameters: {
161
- sourceDocumentAri: (_contextNode$attrs = contextNode.attrs) === null || _contextNode$attrs === void 0 ? void 0 : (_contextNode$attrs$pa = _contextNode$attrs.parameters) === null || _contextNode$attrs$pa === void 0 ? void 0 : _contextNode$attrs$pa.sourceDocumentAri,
162
- contentAri: (_contextNode$attrs2 = contextNode.attrs) === null || _contextNode$attrs2 === void 0 ? void 0 : (_contextNode$attrs2$p = _contextNode$attrs2.parameters) === null || _contextNode$attrs2$p === void 0 ? void 0 : _contextNode$attrs2$p.contentAri
163
- },
164
- localId: 'testId'
165
- }
166
- }, schema);
167
- } catch (e) {}
168
- }
169
- }]
170
- }]
171
- }
172
- });
@@ -1,19 +0,0 @@
1
- import { getCloudId } from '../constants';
2
- export const getConfluencePageAri = pageId => `ari:cloud:confluence:${getCloudId()}:page/${pageId}`;
3
- export const getPageIdFromAri = ari => {
4
- // eslint-disable-next-line require-unicode-regexp
5
- const match = ari.match(/ari:cloud:confluence:[^:]+:page\/(\d+)/);
6
- if (match) {
7
- return match[1];
8
- }
9
- throw new Error(`Invalid page ARI: ${ari}`);
10
- };
11
- export const getContentPropertyAri = contentPropertyId => `ari:cloud:confluence:${getCloudId()}:content/${contentPropertyId}`;
12
- export const getContentPropertyIdFromAri = ari => {
13
- // eslint-disable-next-line require-unicode-regexp
14
- const match = ari.match(/ari:cloud:confluence:[^:]+:content\/([^/]+)/);
15
- if (match) {
16
- return match[1];
17
- }
18
- throw new Error(`Invalid content property ARI: ${ari}`);
19
- };
@@ -1,108 +0,0 @@
1
- import { getCloudId } from '../constants';
2
- import { getConfluencePageAri } from './ari';
3
-
4
- // Uncomment for proxy in Atlaskit, which will route to hello.atlassian.net
5
- // const BASE_URL = 'https://localhost:9876';
6
- const BASE_URL = `/gateway/api/ex/confluence/${getCloudId()}`;
7
- const API_BASE_URL = `${BASE_URL}/wiki/api/v2`;
8
- const COMMON_HEADERS = {
9
- 'Content-Type': 'application/json',
10
- Accept: 'application/json'
11
- };
12
- const getContentPropertiesUrl = ({
13
- pageId,
14
- contentPropertyId
15
- }) => {
16
- const url = `${API_BASE_URL}/pages/${pageId}/properties`;
17
- if (contentPropertyId) {
18
- return `${url}/${contentPropertyId}`;
19
- }
20
- return url;
21
- };
22
- const getGraphQLPropertiesUrl = () => {
23
- return `/cgraphql/api/graphql`;
24
- };
25
- export const createContentProperty = async ({
26
- pageId,
27
- key,
28
- value
29
- }) => {
30
- const url = getContentPropertiesUrl({
31
- pageId
32
- });
33
- const body = JSON.stringify({
34
- key,
35
- value
36
- });
37
- const response = await fetch(url, {
38
- method: 'POST',
39
- headers: COMMON_HEADERS,
40
- body
41
- });
42
- if (!response.ok) {
43
- throw new Error(`Failed to create content property: ${response.statusText}`);
44
- }
45
- const contentProperty = await response.json();
46
- return contentProperty;
47
- };
48
- export const getContentProperty = async ({
49
- pageId,
50
- contentPropertyId,
51
- signal
52
- }) => {
53
- const url = getContentPropertiesUrl({
54
- pageId,
55
- contentPropertyId
56
- });
57
- const response = await fetch(url, {
58
- method: 'GET',
59
- headers: COMMON_HEADERS,
60
- signal
61
- });
62
- if (!response.ok) {
63
- throw new Error(`Failed to get content property: ${response.statusText}`);
64
- }
65
- const contentProperty = await response.json();
66
- return contentProperty;
67
- };
68
- const getQuery = (documentARI, key, value) => {
69
- return `mutation {
70
- confluence {
71
- updateValuePageProperty(input: {
72
- pageId: "${documentARI}",
73
- key: "${key}",
74
- value: "${value}",
75
- useSameVersion: true
76
- }) {
77
- pageProperty {
78
- key,
79
- value
80
- }
81
- }
82
- }
83
- }`;
84
- };
85
- export const updateContentProperty = async ({
86
- pageId,
87
- key,
88
- value
89
- }) => {
90
- const url = getGraphQLPropertiesUrl();
91
- const documentARI = getConfluencePageAri(pageId);
92
-
93
- // eslint-disable-next-line require-unicode-regexp
94
- const query = getQuery(documentARI, key, value.replace(/"/g, '\\"'));
95
- const bodyData = {
96
- query
97
- };
98
- const response = await fetch(url, {
99
- method: 'POST',
100
- headers: COMMON_HEADERS,
101
- body: JSON.stringify(bodyData)
102
- });
103
- if (!response.ok) {
104
- throw new Error(`Failed to update content property: ${response.statusText}`);
105
- }
106
- const contentProperty = await response.json();
107
- return contentProperty;
108
- };
@@ -1,57 +0,0 @@
1
- export const SYNCED_BLOCK_EXTENSION_TYPE = 'com.atlassian.platform.extensions';
2
- export const SYNCED_BLOCK_EXTENSION_KEY = 'synced-block';
3
- export const SYNCED_BLOCK_SOURCE_NODE = 'source';
4
- export const SYNCED_BLOCK_SOURCE_KEY = `${SYNCED_BLOCK_EXTENSION_KEY}:${SYNCED_BLOCK_SOURCE_NODE}`;
5
- export const SYNCED_BLOCK_REFERENCE_NODE = 'reference';
6
- export const SYNCED_BLOCK_REFERENCE_KEY = `${SYNCED_BLOCK_EXTENSION_KEY}:${SYNCED_BLOCK_REFERENCE_NODE}`;
7
- export const isSyncedBlockAttributes = attributes => {
8
- return !!attributes && typeof attributes === 'object' && 'extensionKey' in attributes && (attributes.extensionKey === SYNCED_BLOCK_SOURCE_KEY || attributes.extensionKey === SYNCED_BLOCK_REFERENCE_KEY);
9
- };
10
- export const getDefaultSyncedBlockContent = () => {
11
- const attributes = {
12
- extensionType: SYNCED_BLOCK_EXTENSION_TYPE,
13
- extensionKey: SYNCED_BLOCK_SOURCE_KEY,
14
- parameters: {
15
- sourceDocumentAri: '',
16
- contentAri: '',
17
- contentPropertyKey: ''
18
- },
19
- localId: ''
20
- };
21
- return {
22
- type: 'bodiedExtension',
23
- attrs: attributes,
24
- content: [{
25
- type: 'paragraph',
26
- content: [{
27
- type: 'text',
28
- text: 'This is a synced block. Please edit the source document to update the content.'
29
- }]
30
- }]
31
- };
32
- };
33
- export const parseSyncedBlockContentPropertyValue = value => {
34
- try {
35
- if (typeof value === 'string') {
36
- return JSON.parse(value);
37
- }
38
- return value;
39
- } catch (error) {
40
- // eslint-disable-next-line no-console
41
- console.error('Failed to parse synced block content:', error);
42
- return {
43
- adf: getDefaultSyncedBlockContent()
44
- };
45
- }
46
- };
47
- export const stringifySyncedBlockContentPropertyValue = value => {
48
- try {
49
- return JSON.stringify(value);
50
- } catch (error) {
51
- // eslint-disable-next-line no-console
52
- console.error('Failed to serialize synced block content:', error);
53
- return JSON.stringify({
54
- adf: getDefaultSyncedBlockContent()
55
- });
56
- }
57
- };