@atlaskit/editor-synced-block-provider 0.1.3 → 0.3.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 (39) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/dist/cjs/common/schema.js +18 -0
  3. package/dist/cjs/common/syncBlockProvider.js +24 -12
  4. package/dist/cjs/common/syncBlockStoreManager.js +8 -5
  5. package/dist/cjs/index.js +33 -0
  6. package/dist/cjs/providers/confluenceContentAPI.js +238 -0
  7. package/dist/cjs/utils/ari.js +42 -0
  8. package/dist/cjs/utils/contentProperty.js +192 -0
  9. package/dist/es2019/common/schema.js +13 -0
  10. package/dist/es2019/common/syncBlockProvider.js +25 -13
  11. package/dist/es2019/common/syncBlockStoreManager.js +8 -5
  12. package/dist/es2019/index.js +4 -1
  13. package/dist/es2019/providers/confluenceContentAPI.js +150 -0
  14. package/dist/es2019/utils/ari.js +32 -0
  15. package/dist/es2019/utils/contentProperty.js +160 -0
  16. package/dist/esm/common/schema.js +13 -0
  17. package/dist/esm/common/syncBlockProvider.js +24 -12
  18. package/dist/esm/common/syncBlockStoreManager.js +8 -5
  19. package/dist/esm/index.js +4 -1
  20. package/dist/esm/providers/confluenceContentAPI.js +232 -0
  21. package/dist/esm/utils/ari.js +36 -0
  22. package/dist/esm/utils/contentProperty.js +185 -0
  23. package/dist/types/common/schema.d.ts +6 -0
  24. package/dist/types/common/syncBlockProvider.d.ts +3 -1
  25. package/dist/types/common/syncBlockStoreManager.d.ts +2 -1
  26. package/dist/types/common/types.d.ts +2 -0
  27. package/dist/types/index.d.ts +4 -1
  28. package/dist/types/providers/confluenceContentAPI.d.ts +41 -0
  29. package/dist/types/utils/ari.d.ts +10 -0
  30. package/dist/types/utils/contentProperty.d.ts +61 -0
  31. package/dist/types-ts4.5/common/schema.d.ts +6 -0
  32. package/dist/types-ts4.5/common/syncBlockProvider.d.ts +3 -1
  33. package/dist/types-ts4.5/common/syncBlockStoreManager.d.ts +2 -1
  34. package/dist/types-ts4.5/common/types.d.ts +2 -0
  35. package/dist/types-ts4.5/index.d.ts +4 -1
  36. package/dist/types-ts4.5/providers/confluenceContentAPI.d.ts +41 -0
  37. package/dist/types-ts4.5/utils/ari.d.ts +10 -0
  38. package/dist/types-ts4.5/utils/contentProperty.d.ts +61 -0
  39. package/package.json +2 -2
@@ -0,0 +1,13 @@
1
+ import { createSchema } from '@atlaskit/adf-schema';
2
+
3
+ /**
4
+ * We currently do not need any of the new features, like nested tables
5
+ * Otherwise we could import defaultSchemaConfig from '@atlaskit/adf-schema/schema-default';
6
+ * @returns
7
+ */
8
+ export const getDefaultSyncBlockSchema = () => {
9
+ return createSchema({
10
+ nodes: ['doc', 'paragraph', 'text', 'bulletList', 'orderedList', 'listItem', 'heading', 'blockquote', 'codeBlock', 'panel', 'rule', 'expand', 'nestedExpand', 'table', 'tableCell', 'tableHeader', 'tableRow', 'date', 'status', 'layoutSection', 'layoutColumn', 'unsupportedBlock', 'unsupportedInline'],
11
+ marks: ['link', 'em', 'strong', 'strike', 'subsup', 'underline', 'code', 'textColor', 'backgroundColor', 'alignment', 'indentation', 'border', 'unsupportedMark', 'unsupportedNodeAttribute', 'typeAheadQuery']
12
+ });
13
+ };
@@ -1,5 +1,5 @@
1
1
  import _defineProperty from "@babel/runtime/helpers/defineProperty";
2
- import { useEffect, useState } from 'react';
2
+ import { useEffect, useState, useMemo } from 'react';
3
3
  import { convertSyncBlockPMNodeToSyncBlockData } from '../utils/utils';
4
4
  import { SyncBlockDataProvider } from './types';
5
5
  export class SyncBlockProvider extends SyncBlockDataProvider {
@@ -32,6 +32,9 @@ export class SyncBlockProvider extends SyncBlockDataProvider {
32
32
  });
33
33
  return Promise.all(resourceIds);
34
34
  });
35
+ _defineProperty(this, "getSourceId", () => {
36
+ return this.sourceId;
37
+ });
35
38
  this.fetchProvider = fetchProvider;
36
39
  this.writeProvider = writeProvider;
37
40
  this.sourceId = sourceId;
@@ -39,26 +42,35 @@ export class SyncBlockProvider extends SyncBlockDataProvider {
39
42
  }
40
43
  export const useFetchDocNode = (editorView, node, defaultDocNode, provider) => {
41
44
  const [docNode, setDocNode] = useState(defaultDocNode);
45
+ const fetchNode = (editorView, node, provider) => {
46
+ const nodes = [convertSyncBlockPMNodeToSyncBlockData(node, false)];
47
+ provider === null || provider === void 0 ? void 0 : provider.fetchNodesData(nodes).then(data => {
48
+ var _data$;
49
+ if (data && (_data$ = data[0]) !== null && _data$ !== void 0 && _data$.content) {
50
+ const newNode = editorView.state.schema.nodeFromJSON(data[0].content);
51
+ setDocNode({
52
+ ...newNode.toJSON(),
53
+ version: 1
54
+ });
55
+ }
56
+ });
57
+ };
42
58
  useEffect(() => {
43
59
  if (!provider) {
44
60
  return;
45
61
  }
62
+ fetchNode(editorView, node, provider);
46
63
  const interval = window.setInterval(() => {
47
- const nodes = [convertSyncBlockPMNodeToSyncBlockData(node, false)];
48
- provider === null || provider === void 0 ? void 0 : provider.fetchNodesData(nodes).then(data => {
49
- var _data$;
50
- if (data && (_data$ = data[0]) !== null && _data$ !== void 0 && _data$.content) {
51
- const newNode = editorView.state.schema.nodeFromJSON(data[0].content);
52
- setDocNode({
53
- ...newNode.toJSON(),
54
- version: 1
55
- });
56
- }
57
- });
58
- }, 1000);
64
+ fetchNode(editorView, node, provider);
65
+ }, 3000);
59
66
  return () => {
60
67
  window.clearInterval(interval);
61
68
  };
62
69
  }, [editorView, node, provider]);
63
70
  return docNode;
71
+ };
72
+ export const useMemoizedSyncedBlockProvider = (fetchProvider, writeProvider, sourceId) => {
73
+ return useMemo(() => {
74
+ return new SyncBlockProvider(fetchProvider, writeProvider, sourceId);
75
+ }, [fetchProvider, writeProvider, sourceId]);
64
76
  };
@@ -9,14 +9,14 @@ import uuid from 'uuid';
9
9
  // Handles caching, debouncing updates, and publish/subscribe for local changes.
10
10
  // Ensures consistency between local and remote state, and can be used in both editor and renderer contexts.
11
11
  export class SyncBlockStoreManager {
12
- constructor(_dataProvider) {
12
+ constructor(dataProvider) {
13
13
  this.syncBlocks = new Map();
14
+ this.dataProvider = dataProvider;
14
15
  }
15
16
  setEditorView(editorView) {
16
17
  this.editorView = editorView;
17
18
  }
18
19
  isSourceBlock(node) {
19
- var _this$syncBlocks$get;
20
20
  if (node.type.name !== 'syncBlock') {
21
21
  return false;
22
22
  }
@@ -24,7 +24,7 @@ export class SyncBlockStoreManager {
24
24
  resourceId,
25
25
  localId
26
26
  } = node.attrs;
27
- return this.syncBlocks.has(resourceId) && ((_this$syncBlocks$get = this.syncBlocks.get(resourceId)) === null || _this$syncBlocks$get === void 0 ? void 0 : _this$syncBlocks$get.sourceLocalId) === localId;
27
+ return resourceId.includes(localId);
28
28
  }
29
29
  registerConfirmationCallback(callback) {
30
30
  this.confirmationCallback = callback;
@@ -36,15 +36,18 @@ export class SyncBlockStoreManager {
36
36
  return !!this.confirmationCallback;
37
37
  }
38
38
  createSyncBlockNode() {
39
+ var _this$dataProvider;
39
40
  // TODO: EDITOR-1644 - properly implement creation of the synced block
40
41
  // below is a temporary implementation for the creation of the synced block
41
42
  // the resource id needs to have pageId and content property key in it
43
+ // Note: If the data provider is not set, the resource id will be the local id
42
44
 
43
- const blockInstanceId = uuid();
44
45
  const localId = uuid();
46
+ const sourceId = (_this$dataProvider = this.dataProvider) === null || _this$dataProvider === void 0 ? void 0 : _this$dataProvider.getSourceId();
47
+ const resourceId = sourceId ? `${sourceId}/${localId}` : localId;
45
48
  const syncBlockNode = {
46
49
  attrs: {
47
- resourceId: `ari:cloud:confluence:fake_cloud_id:page/fake_page_id/${blockInstanceId}`,
50
+ resourceId,
48
51
  localId
49
52
  },
50
53
  type: 'syncBlock'
@@ -1,6 +1,9 @@
1
1
  /* eslint-disable @atlaskit/editor/no-re-export */
2
2
 
3
- export { SyncBlockProvider as SyncedBlockProvider, useFetchDocNode } from './common/syncBlockProvider';
3
+ export { SyncBlockProvider as SyncedBlockProvider, useFetchDocNode, useMemoizedSyncedBlockProvider } from './common/syncBlockProvider';
4
4
  export { SyncBlockStoreManager } from './common/syncBlockStoreManager';
5
5
  export { inMemoryFetchProvider, inMemoryWriteProvider } from './providers/inMemory';
6
+ export { getDefaultSyncBlockSchema } from './common/schema';
7
+ export { createContentAPIProvidersWithDefaultKey, useMemoizedContentAPIProviders } from './providers/confluenceContentAPI';
8
+ export { getConfluencePageAri } from './utils/ari';
6
9
  export { convertSyncBlockPMNodeToSyncBlockData, generateSyncBlockSourceUrl } from './utils/utils';
@@ -0,0 +1,150 @@
1
+ import _defineProperty from "@babel/runtime/helpers/defineProperty";
2
+ import { useMemo } from 'react';
3
+ import { getLocalIdFromAri, getPageIdFromAri } from '../utils/ari';
4
+ import { getContentProperty, createContentProperty, updateContentProperty } from '../utils/contentProperty';
5
+
6
+ /**
7
+ * Configuration for Content API providers
8
+ */
9
+
10
+ const getContentPropertyKey = (contentPropertyKey, localId) => {
11
+ return contentPropertyKey + '-' + localId;
12
+ };
13
+ const parseSyncedBlockContentPropertyValue = value => {
14
+ try {
15
+ if (typeof value === 'string') {
16
+ return JSON.parse(value);
17
+ }
18
+ return value;
19
+ } catch (error) {
20
+ // eslint-disable-next-line no-console
21
+ console.error('Failed to parse synced block content:', error);
22
+ return {
23
+ content: undefined
24
+ };
25
+ }
26
+ };
27
+
28
+ /**
29
+ * ADFFetchProvider implementation that fetches synced block data from Confluence Content API
30
+ */
31
+ class ConfluenceADFFetchProvider {
32
+ constructor(config) {
33
+ this.config = config;
34
+ }
35
+ async fetchData(resourceId) {
36
+ try {
37
+ var _contentProperty$data, _contentProperty$data2;
38
+ const pageId = getPageIdFromAri(resourceId);
39
+ const localId = getLocalIdFromAri(resourceId);
40
+ const key = getContentPropertyKey(this.config.contentPropertyKey, localId);
41
+ const options = {
42
+ pageId,
43
+ key,
44
+ cloudId: this.config.cloudId
45
+ };
46
+ const contentProperty = await getContentProperty(options);
47
+ const value = (_contentProperty$data = contentProperty.data.confluence.page.properties) === null || _contentProperty$data === void 0 ? void 0 : (_contentProperty$data2 = _contentProperty$data[0]) === null || _contentProperty$data2 === void 0 ? void 0 : _contentProperty$data2.value;
48
+ if (!value) {
49
+ throw new Error('Content property value does not exist');
50
+ }
51
+
52
+ // Parse the synced block content from the property value
53
+ const syncedBlockData = parseSyncedBlockContentPropertyValue(value);
54
+ return {
55
+ content: syncedBlockData.content
56
+ };
57
+ } catch (error) {
58
+ // eslint-disable-next-line no-console
59
+ console.error('Failed to fetch synced block data:', error);
60
+ return {
61
+ content: undefined
62
+ };
63
+ }
64
+ }
65
+ }
66
+
67
+ /**
68
+ * ADFWriteProvider implementation that writes synced block data to Confluence Content API
69
+ */
70
+ class ConfluenceADFWriteProvider {
71
+ constructor(config) {
72
+ _defineProperty(this, "createNewContentProperty", async (pageId, key, value) => {
73
+ var _contentProperty$data3;
74
+ const contentProperty = await createContentProperty({
75
+ pageId,
76
+ key,
77
+ value,
78
+ cloudId: this.config.cloudId
79
+ });
80
+ if (((_contentProperty$data3 = contentProperty.data.confluence.createPageProperty.pageProperty) === null || _contentProperty$data3 === void 0 ? void 0 : _contentProperty$data3.key) === key) {
81
+ return key;
82
+ } else {
83
+ throw new Error('Failed to create content property');
84
+ }
85
+ });
86
+ this.config = config;
87
+ }
88
+ async writeData(sourceId, localId, data, resourceId) {
89
+ try {
90
+ const pageId = getPageIdFromAri(sourceId);
91
+ const syncedBlockValue = JSON.stringify({
92
+ content: data
93
+ });
94
+ if (resourceId) {
95
+ var _contentProperty$data4;
96
+ // Update existing content property
97
+ const localId = getLocalIdFromAri(resourceId);
98
+ const key = getContentPropertyKey(this.config.contentPropertyKey, localId);
99
+ const contentProperty = await updateContentProperty({
100
+ pageId,
101
+ key,
102
+ value: syncedBlockValue,
103
+ cloudId: this.config.cloudId
104
+ });
105
+ if (((_contentProperty$data4 = contentProperty.data.confluence.updateValuePageProperty.pageProperty) === null || _contentProperty$data4 === void 0 ? void 0 : _contentProperty$data4.key) === key) {
106
+ return key;
107
+ } else if (contentProperty.data.confluence.updateValuePageProperty.pageProperty === null) {
108
+ return this.createNewContentProperty(pageId, key, syncedBlockValue);
109
+ } else {
110
+ throw new Error('Failed to update content property');
111
+ }
112
+ } else {
113
+ // Create new content property
114
+ const key = getContentPropertyKey(this.config.contentPropertyKey, localId);
115
+ return this.createNewContentProperty(pageId, key, syncedBlockValue);
116
+ }
117
+ } catch (error) {
118
+ // eslint-disable-next-line no-console
119
+ console.error('Failed to write synced block data:', error);
120
+ return Promise.reject(error);
121
+ }
122
+ }
123
+ }
124
+
125
+ /**
126
+ * Factory function to create both providers with shared configuration
127
+ */
128
+ const createContentAPIProviders = config => {
129
+ const fetchProvider = new ConfluenceADFFetchProvider(config);
130
+ const writeProvider = new ConfluenceADFWriteProvider(config);
131
+ return {
132
+ fetchProvider,
133
+ writeProvider
134
+ };
135
+ };
136
+
137
+ /**
138
+ * Convenience function to create providers with default content property key
139
+ */
140
+ export const createContentAPIProvidersWithDefaultKey = cloudId => {
141
+ return createContentAPIProviders({
142
+ cloudId,
143
+ contentPropertyKey: 'editor-synced-block'
144
+ });
145
+ };
146
+ export const useMemoizedContentAPIProviders = cloudId => {
147
+ return useMemo(() => {
148
+ return createContentAPIProvidersWithDefaultKey(cloudId);
149
+ }, [cloudId]);
150
+ };
@@ -0,0 +1,32 @@
1
+ export const getConfluencePageAri = (pageId, cloudId) => `ari:cloud:confluence:${cloudId}:page/${pageId}`;
2
+ export const getPageIdFromAri = ari => {
3
+ // eslint-disable-next-line require-unicode-regexp
4
+ const match = ari.match(/ari:cloud:confluence:[^:]+:page\/(\d+)/);
5
+ if (match !== null && match !== void 0 && match[1]) {
6
+ return match[1];
7
+ }
8
+ throw new Error(`Invalid page ARI: ${ari}`);
9
+ };
10
+
11
+ /**
12
+ *
13
+ * @param ari ari:cloud:confluence:<cloudId>:page/<pageId>/<localId>
14
+ * @returns
15
+ */
16
+ export const getLocalIdFromAri = ari => {
17
+ // eslint-disable-next-line require-unicode-regexp
18
+ const match = ari.match(/ari:cloud:confluence:[^:]+:page\/\d+\/([a-zA-Z0-9-]+)/);
19
+ if (match !== null && match !== void 0 && match[1]) {
20
+ return match[1];
21
+ }
22
+ throw new Error(`Invalid page ARI: ${ari}`);
23
+ };
24
+ export const getContentPropertyAri = (contentPropertyId, cloudId) => `ari:cloud:confluence:${cloudId}:content/${contentPropertyId}`;
25
+ export const getContentPropertyIdFromAri = ari => {
26
+ // eslint-disable-next-line require-unicode-regexp
27
+ const match = ari.match(/ari:cloud:confluence:[^:]+:content\/([^/]+)/);
28
+ if (match) {
29
+ return match[1];
30
+ }
31
+ throw new Error(`Invalid content property ARI: ${ari}`);
32
+ };
@@ -0,0 +1,160 @@
1
+ import { getConfluencePageAri } from './ari';
2
+ const COMMON_HEADERS = {
3
+ 'Content-Type': 'application/json',
4
+ Accept: 'application/json'
5
+ };
6
+ const AGG_HEADERS = {
7
+ 'X-ExperimentalApi': 'confluence-agg-beta'
8
+ };
9
+ const GRAPHQL_ENDPOINT = '/gateway/api/graphql';
10
+ const GET_OPERATION_NAME = 'EDITOR_SYNCED_BLOCK_GET';
11
+ const CREATE_OPERATION_NAME = 'EDITOR_SYNCED_BLOCK_CREATE';
12
+ const UPDATE_OPERATION_NAME = 'EDITOR_SYNCED_BLOCK_UPDATE';
13
+ /**
14
+ * Query to get the page property by key
15
+ * @param documentARI
16
+ * @param key
17
+ * @returns
18
+ */
19
+ const GET_QUERY = `query ${GET_OPERATION_NAME} ($id: ID!, $keys: [String]!) {
20
+ confluence {
21
+ page (id: $id) {
22
+ properties(keys: $keys) {
23
+ key,
24
+ value
25
+ }
26
+ }
27
+ }
28
+ }`;
29
+
30
+ /**
31
+ * Query to create a page property with key and value
32
+ * @param documentARI
33
+ * @param key
34
+ * @param value
35
+ * @returns
36
+ */
37
+ const CREATE_QUERY = `mutation ${CREATE_OPERATION_NAME} ($input: ConfluenceCreatePagePropertyInput!){
38
+ confluence {
39
+ createPageProperty(input: $input) {
40
+ pageProperty {
41
+ key,
42
+ value
43
+ }
44
+ }
45
+ }
46
+ }`;
47
+
48
+ /**
49
+ * Query to update a page property with key and value without bumping the version
50
+ * @param documentARI
51
+ * @param key
52
+ * @param value
53
+ * @returns
54
+ */
55
+ const UPDATE_QUERY = `mutation ${UPDATE_OPERATION_NAME} ($input: ConfluenceUpdateValuePagePropertyInput!) {
56
+ confluence {
57
+ updateValuePageProperty(input: $input) {
58
+ pageProperty {
59
+ key,
60
+ value
61
+ }
62
+ }
63
+ }
64
+ }`;
65
+ export const getContentProperty = async ({
66
+ pageId,
67
+ key,
68
+ cloudId
69
+ }) => {
70
+ const documentARI = getConfluencePageAri(pageId, cloudId);
71
+ const bodyData = {
72
+ query: GET_QUERY,
73
+ operationName: GET_OPERATION_NAME,
74
+ variables: {
75
+ id: documentARI,
76
+ keys: [key]
77
+ }
78
+ };
79
+ const response = await fetch(GRAPHQL_ENDPOINT, {
80
+ method: 'POST',
81
+ headers: {
82
+ ...COMMON_HEADERS,
83
+ ...AGG_HEADERS
84
+ },
85
+ body: JSON.stringify(bodyData)
86
+ });
87
+ if (!response.ok) {
88
+ throw new Error(`Failed to get content property: ${response.statusText}`);
89
+ }
90
+ const contentProperty = await response.json();
91
+ return contentProperty;
92
+ };
93
+ export const updateContentProperty = async ({
94
+ pageId,
95
+ key,
96
+ value,
97
+ cloudId
98
+ }) => {
99
+ const documentARI = getConfluencePageAri(pageId, cloudId);
100
+ const bodyData = {
101
+ query: UPDATE_QUERY,
102
+ operationName: UPDATE_OPERATION_NAME,
103
+ variables: {
104
+ input: {
105
+ pageId: documentARI,
106
+ key,
107
+ value,
108
+ useSameVersion: true
109
+ }
110
+ }
111
+ };
112
+ const response = await fetch(GRAPHQL_ENDPOINT, {
113
+ method: 'POST',
114
+ headers: {
115
+ ...COMMON_HEADERS,
116
+ ...AGG_HEADERS
117
+ },
118
+ body: JSON.stringify(bodyData)
119
+ });
120
+ if (!response.ok) {
121
+ throw new Error(`Failed to update content property: ${response.statusText}`);
122
+ }
123
+ const contentProperty = await response.json();
124
+ return contentProperty;
125
+ };
126
+ export const createContentProperty = async ({
127
+ pageId,
128
+ key,
129
+ value,
130
+ cloudId
131
+ }) => {
132
+ const documentARI = getConfluencePageAri(pageId, cloudId);
133
+
134
+ // eslint-disable-next-line require-unicode-regexp
135
+ const escapedValue = value.replace(/"/g, '\\"');
136
+ const bodyData = {
137
+ query: CREATE_QUERY,
138
+ operationName: CREATE_OPERATION_NAME,
139
+ variables: {
140
+ input: {
141
+ pageId: documentARI,
142
+ key,
143
+ value: escapedValue
144
+ }
145
+ }
146
+ };
147
+ const response = await fetch(GRAPHQL_ENDPOINT, {
148
+ method: 'POST',
149
+ headers: {
150
+ ...COMMON_HEADERS,
151
+ ...AGG_HEADERS
152
+ },
153
+ body: JSON.stringify(bodyData)
154
+ });
155
+ if (!response.ok) {
156
+ throw new Error(`Failed to create content property: ${response.statusText}`);
157
+ }
158
+ const contentProperty = await response.json();
159
+ return contentProperty;
160
+ };
@@ -0,0 +1,13 @@
1
+ import { createSchema } from '@atlaskit/adf-schema';
2
+
3
+ /**
4
+ * We currently do not need any of the new features, like nested tables
5
+ * Otherwise we could import defaultSchemaConfig from '@atlaskit/adf-schema/schema-default';
6
+ * @returns
7
+ */
8
+ export var getDefaultSyncBlockSchema = function getDefaultSyncBlockSchema() {
9
+ return createSchema({
10
+ nodes: ['doc', 'paragraph', 'text', 'bulletList', 'orderedList', 'listItem', 'heading', 'blockquote', 'codeBlock', 'panel', 'rule', 'expand', 'nestedExpand', 'table', 'tableCell', 'tableHeader', 'tableRow', 'date', 'status', 'layoutSection', 'layoutColumn', 'unsupportedBlock', 'unsupportedInline'],
11
+ marks: ['link', 'em', 'strong', 'strike', 'subsup', 'underline', 'code', 'textColor', 'backgroundColor', 'alignment', 'indentation', 'border', 'unsupportedMark', 'unsupportedNodeAttribute', 'typeAheadQuery']
12
+ });
13
+ };
@@ -9,7 +9,7 @@ function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbol
9
9
  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; }
10
10
  function _callSuper(t, o, e) { return o = _getPrototypeOf(o), _possibleConstructorReturn(t, _isNativeReflectConstruct() ? Reflect.construct(o, e || [], _getPrototypeOf(t).constructor) : o.apply(t, e)); }
11
11
  function _isNativeReflectConstruct() { try { var t = !Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); } catch (t) {} return (_isNativeReflectConstruct = function _isNativeReflectConstruct() { return !!t; })(); }
12
- import { useEffect, useState } from 'react';
12
+ import { useEffect, useState, useMemo } from 'react';
13
13
  import { convertSyncBlockPMNodeToSyncBlockData } from '../utils/utils';
14
14
  import { SyncBlockDataProvider } from './types';
15
15
  export var SyncBlockProvider = /*#__PURE__*/function (_SyncBlockDataProvide) {
@@ -48,6 +48,9 @@ export var SyncBlockProvider = /*#__PURE__*/function (_SyncBlockDataProvide) {
48
48
  });
49
49
  return Promise.all(resourceIds);
50
50
  });
51
+ _defineProperty(_this, "getSourceId", function () {
52
+ return _this.sourceId;
53
+ });
51
54
  _this.fetchProvider = fetchProvider;
52
55
  _this.writeProvider = writeProvider;
53
56
  _this.sourceId = sourceId;
@@ -61,25 +64,34 @@ export var useFetchDocNode = function useFetchDocNode(editorView, node, defaultD
61
64
  _useState2 = _slicedToArray(_useState, 2),
62
65
  docNode = _useState2[0],
63
66
  setDocNode = _useState2[1];
67
+ var fetchNode = function fetchNode(editorView, node, provider) {
68
+ var nodes = [convertSyncBlockPMNodeToSyncBlockData(node, false)];
69
+ provider === null || provider === void 0 || provider.fetchNodesData(nodes).then(function (data) {
70
+ var _data$;
71
+ if (data && (_data$ = data[0]) !== null && _data$ !== void 0 && _data$.content) {
72
+ var newNode = editorView.state.schema.nodeFromJSON(data[0].content);
73
+ setDocNode(_objectSpread(_objectSpread({}, newNode.toJSON()), {}, {
74
+ version: 1
75
+ }));
76
+ }
77
+ });
78
+ };
64
79
  useEffect(function () {
65
80
  if (!provider) {
66
81
  return;
67
82
  }
83
+ fetchNode(editorView, node, provider);
68
84
  var interval = window.setInterval(function () {
69
- var nodes = [convertSyncBlockPMNodeToSyncBlockData(node, false)];
70
- provider === null || provider === void 0 || provider.fetchNodesData(nodes).then(function (data) {
71
- var _data$;
72
- if (data && (_data$ = data[0]) !== null && _data$ !== void 0 && _data$.content) {
73
- var newNode = editorView.state.schema.nodeFromJSON(data[0].content);
74
- setDocNode(_objectSpread(_objectSpread({}, newNode.toJSON()), {}, {
75
- version: 1
76
- }));
77
- }
78
- });
79
- }, 1000);
85
+ fetchNode(editorView, node, provider);
86
+ }, 3000);
80
87
  return function () {
81
88
  window.clearInterval(interval);
82
89
  };
83
90
  }, [editorView, node, provider]);
84
91
  return docNode;
92
+ };
93
+ export var useMemoizedSyncedBlockProvider = function useMemoizedSyncedBlockProvider(fetchProvider, writeProvider, sourceId) {
94
+ return useMemo(function () {
95
+ return new SyncBlockProvider(fetchProvider, writeProvider, sourceId);
96
+ }, [fetchProvider, writeProvider, sourceId]);
85
97
  };
@@ -13,9 +13,10 @@ import uuid from 'uuid';
13
13
  // Handles caching, debouncing updates, and publish/subscribe for local changes.
14
14
  // Ensures consistency between local and remote state, and can be used in both editor and renderer contexts.
15
15
  export var SyncBlockStoreManager = /*#__PURE__*/function () {
16
- function SyncBlockStoreManager(_dataProvider) {
16
+ function SyncBlockStoreManager(dataProvider) {
17
17
  _classCallCheck(this, SyncBlockStoreManager);
18
18
  this.syncBlocks = new Map();
19
+ this.dataProvider = dataProvider;
19
20
  }
20
21
  return _createClass(SyncBlockStoreManager, [{
21
22
  key: "setEditorView",
@@ -25,14 +26,13 @@ export var SyncBlockStoreManager = /*#__PURE__*/function () {
25
26
  }, {
26
27
  key: "isSourceBlock",
27
28
  value: function isSourceBlock(node) {
28
- var _this$syncBlocks$get;
29
29
  if (node.type.name !== 'syncBlock') {
30
30
  return false;
31
31
  }
32
32
  var _node$attrs = node.attrs,
33
33
  resourceId = _node$attrs.resourceId,
34
34
  localId = _node$attrs.localId;
35
- return this.syncBlocks.has(resourceId) && ((_this$syncBlocks$get = this.syncBlocks.get(resourceId)) === null || _this$syncBlocks$get === void 0 ? void 0 : _this$syncBlocks$get.sourceLocalId) === localId;
35
+ return resourceId.includes(localId);
36
36
  }
37
37
  }, {
38
38
  key: "registerConfirmationCallback",
@@ -51,15 +51,18 @@ export var SyncBlockStoreManager = /*#__PURE__*/function () {
51
51
  }, {
52
52
  key: "createSyncBlockNode",
53
53
  value: function createSyncBlockNode() {
54
+ var _this$dataProvider;
54
55
  // TODO: EDITOR-1644 - properly implement creation of the synced block
55
56
  // below is a temporary implementation for the creation of the synced block
56
57
  // the resource id needs to have pageId and content property key in it
58
+ // Note: If the data provider is not set, the resource id will be the local id
57
59
 
58
- var blockInstanceId = uuid();
59
60
  var localId = uuid();
61
+ var sourceId = (_this$dataProvider = this.dataProvider) === null || _this$dataProvider === void 0 ? void 0 : _this$dataProvider.getSourceId();
62
+ var resourceId = sourceId ? "".concat(sourceId, "/").concat(localId) : localId;
60
63
  var syncBlockNode = {
61
64
  attrs: {
62
- resourceId: "ari:cloud:confluence:fake_cloud_id:page/fake_page_id/".concat(blockInstanceId),
65
+ resourceId: resourceId,
63
66
  localId: localId
64
67
  },
65
68
  type: 'syncBlock'
package/dist/esm/index.js CHANGED
@@ -1,6 +1,9 @@
1
1
  /* eslint-disable @atlaskit/editor/no-re-export */
2
2
 
3
- export { SyncBlockProvider as SyncedBlockProvider, useFetchDocNode } from './common/syncBlockProvider';
3
+ export { SyncBlockProvider as SyncedBlockProvider, useFetchDocNode, useMemoizedSyncedBlockProvider } from './common/syncBlockProvider';
4
4
  export { SyncBlockStoreManager } from './common/syncBlockStoreManager';
5
5
  export { inMemoryFetchProvider, inMemoryWriteProvider } from './providers/inMemory';
6
+ export { getDefaultSyncBlockSchema } from './common/schema';
7
+ export { createContentAPIProvidersWithDefaultKey, useMemoizedContentAPIProviders } from './providers/confluenceContentAPI';
8
+ export { getConfluencePageAri } from './utils/ari';
6
9
  export { convertSyncBlockPMNodeToSyncBlockData, generateSyncBlockSourceUrl } from './utils/utils';