@atlaskit/editor-synced-block-provider 4.3.2 → 4.3.4
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/AGENTS.md +33 -73
- package/CHANGELOG.md +16 -0
- package/dist/cjs/store-manager/sourceSyncBlockStoreManager.js +8 -4
- package/dist/es2019/store-manager/sourceSyncBlockStoreManager.js +9 -5
- package/dist/esm/store-manager/sourceSyncBlockStoreManager.js +8 -4
- package/dist/types/store-manager/sourceSyncBlockStoreManager.d.ts +3 -1
- package/dist/types-ts4.5/store-manager/sourceSyncBlockStoreManager.d.ts +3 -1
- package/package.json +3 -6
package/AGENTS.md
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# Synced Block Provider — Developer Agent Guide
|
|
2
2
|
|
|
3
|
-
> **Package**: `@atlaskit/editor-synced-block-provider`
|
|
4
|
-
>
|
|
5
|
-
>
|
|
6
|
-
>
|
|
3
|
+
> **Package**: `@atlaskit/editor-synced-block-provider`
|
|
4
|
+
>
|
|
5
|
+
> **For workflow guidance, debugging, and cross-package task guides, load the `synced-blocks` skill:**
|
|
6
|
+
> `get_skill(skill_name_or_path="platform/packages/editor/.rovodev/skills/synced-blocks/SKILL.md")`
|
|
7
7
|
|
|
8
8
|
---
|
|
9
9
|
|
|
@@ -19,29 +19,29 @@ plugin and the renderer across Confluence and Jira.
|
|
|
19
19
|
|
|
20
20
|
```
|
|
21
21
|
src/
|
|
22
|
-
├── index.ts
|
|
22
|
+
├── index.ts # Barrel export
|
|
23
23
|
├── store-manager/
|
|
24
|
-
│ ├── syncBlockStoreManager.ts
|
|
25
|
-
│ ├── referenceSyncBlockStoreManager.ts
|
|
26
|
-
│ └── sourceSyncBlockStoreManager.ts
|
|
24
|
+
│ ├── syncBlockStoreManager.ts # Parent coordinator for source + reference managers
|
|
25
|
+
│ ├── referenceSyncBlockStoreManager.ts # Reference block lifecycle, cache, subscriptions, flush
|
|
26
|
+
│ └── sourceSyncBlockStoreManager.ts # Source block create, update, delete, flush
|
|
27
27
|
├── clients/
|
|
28
28
|
│ ├── block-service/
|
|
29
|
-
│ │ ├── blockService.ts
|
|
30
|
-
│ │ └── ari.ts
|
|
29
|
+
│ │ ├── blockService.ts # Block service API client (fetch, batch, CRUD)
|
|
30
|
+
│ │ └── ari.ts # Block ARI generation/parsing
|
|
31
31
|
│ ├── confluence/
|
|
32
|
-
│ │ ├── ari.ts
|
|
33
|
-
│ │ └── fetchMediaToken.ts
|
|
32
|
+
│ │ ├── ari.ts # Confluence page ARI generation/parsing
|
|
33
|
+
│ │ └── fetchMediaToken.ts # Media token fetching via GraphQL (MediaUploadTokenQuery)
|
|
34
34
|
│ └── jira/
|
|
35
|
-
│ └── ari.ts
|
|
35
|
+
│ └── ari.ts # Jira work item ARI generation/parsing
|
|
36
36
|
├── providers/
|
|
37
37
|
│ └── block-service/
|
|
38
|
-
│ └── blockServiceAPI.ts
|
|
39
|
-
└── types/
|
|
38
|
+
│ └── blockServiceAPI.ts # Provider factory and API helpers
|
|
39
|
+
└── types/ # Shared types
|
|
40
40
|
```
|
|
41
41
|
|
|
42
42
|
---
|
|
43
43
|
|
|
44
|
-
## Key
|
|
44
|
+
## Key Exports and Types
|
|
45
45
|
|
|
46
46
|
### Store Manager Hierarchy
|
|
47
47
|
|
|
@@ -49,81 +49,41 @@ src/
|
|
|
49
49
|
SyncBlockStoreManager (parent coordinator)
|
|
50
50
|
├── SourceSyncBlockStoreManager
|
|
51
51
|
│ ├── create(content) → Block Service API → returns resourceId
|
|
52
|
-
│ ├──
|
|
53
|
-
│ ├──
|
|
54
|
-
│
|
|
52
|
+
│ ├── updateSyncBlockData(node) → marks isDirty, caches content
|
|
53
|
+
│ ├── flush() → persist all dirty changes to backend
|
|
54
|
+
│ ├── hasUnsavedChanges() → checks isDirty + hasReceivedContentChange
|
|
55
|
+
│ └── delete(resourceId) → soft delete with confirmation
|
|
55
56
|
└── ReferenceSyncBlockStoreManager
|
|
56
57
|
├── fetchSyncBlocksData(nodes) → batch fetch with deduplication
|
|
57
|
-
├── subscribeToSyncBlock(resourceId,
|
|
58
|
+
├── subscribeToSyncBlock(resourceId, callback) → AGG WebSocket
|
|
58
59
|
├── fetchSyncBlockSourceInfo(resourceId) → title, URL metadata
|
|
59
|
-
├── getFromCache(resourceId) → retrieve cached data
|
|
60
|
-
├── flush() → save reference changes to backend
|
|
61
60
|
└── destroy() → cleanup subscriptions and batchers
|
|
62
61
|
```
|
|
63
62
|
|
|
64
|
-
### ARI
|
|
63
|
+
### ARI Utilities
|
|
65
64
|
|
|
66
|
-
| Function |
|
|
67
|
-
| ------------------------------------------------------------ |
|
|
68
|
-
| `generateBlockAri({cloudId, parentId, product, resourceId})` |
|
|
69
|
-
| `generateBlockAriFromReference({cloudId, resourceId})` |
|
|
70
|
-
| `getConfluencePageAri({pageId, cloudId, pageType})` | Confluence page
|
|
71
|
-
| `getJiraWorkItemAri({cloudId, workItemId})` | Jira issue
|
|
72
|
-
| `getJiraWorkItemIdFromAri(ari)` | Extract issue ID from ARI | — |
|
|
65
|
+
| Function | Purpose |
|
|
66
|
+
| ------------------------------------------------------------ | -------------------------- |
|
|
67
|
+
| `generateBlockAri({cloudId, parentId, product, resourceId})` | Generate source block ARI |
|
|
68
|
+
| `generateBlockAriFromReference({cloudId, resourceId})` | Generate reference ARI |
|
|
69
|
+
| `getConfluencePageAri({pageId, cloudId, pageType})` | Confluence page ARI |
|
|
70
|
+
| `getJiraWorkItemAri({cloudId, workItemId})` | Jira issue ARI |
|
|
73
71
|
|
|
74
72
|
### Block Service API
|
|
75
73
|
|
|
76
74
|
The client in `clients/block-service/blockService.ts` communicates via GraphQL at
|
|
77
|
-
`/gateway/api/graphql`:
|
|
78
|
-
|
|
79
|
-
- **Fetch**: Single or batch block content retrieval
|
|
80
|
-
- **Create**: Register new source block with content
|
|
81
|
-
- **Update**: Push content changes (debounced 3s)
|
|
82
|
-
- **Delete**: Soft delete a source block
|
|
83
|
-
- **Source Info**: Fetch metadata (source page title, URL)
|
|
84
|
-
- **References Info**: Fetch list of locations referencing a block
|
|
75
|
+
`/gateway/api/graphql`: Fetch, Create, Update (debounced 3s), Delete, Source Info, References Info.
|
|
85
76
|
|
|
86
77
|
### Media Token Fetching
|
|
87
78
|
|
|
88
79
|
`fetchMediaToken(contentId)` → GraphQL `MediaUploadTokenQuery` → returns
|
|
89
80
|
`{token, config: {clientId, fileStoreUrl}, collectionId}`
|
|
90
81
|
|
|
91
|
-
Used when synced blocks contain media (images, files) — the reference needs a valid token to render
|
|
92
|
-
media from the source page.
|
|
93
|
-
|
|
94
|
-
---
|
|
95
|
-
|
|
96
|
-
## Common Tasks
|
|
97
|
-
|
|
98
|
-
### Adding a new API method
|
|
99
|
-
|
|
100
|
-
1. Add the GraphQL query/mutation in `clients/block-service/blockService.ts`
|
|
101
|
-
2. Expose it through the appropriate store manager
|
|
102
|
-
3. Export from `src/index.ts` if needed by product integrations
|
|
103
|
-
4. Add tests in `editor-synced-block-provider-tests`
|
|
104
|
-
|
|
105
|
-
### Debugging data issues
|
|
106
|
-
|
|
107
|
-
1. Check `ReferenceSyncBlockStoreManager` cache state
|
|
108
|
-
2. Verify ARI format matches expected pattern for the product
|
|
109
|
-
3. Check Block Service API responses in network tab (look for `/gateway/api/graphql`)
|
|
110
|
-
4. Use analytics:
|
|
111
|
-
[HOW-TO: Debug errors](https://hello.atlassian.net/wiki/spaces/egcuc/pages/6342760320)
|
|
112
|
-
|
|
113
|
-
### Adding support for a new product
|
|
114
|
-
|
|
115
|
-
1. Create ARI utilities in `clients/{product}/ari.ts`
|
|
116
|
-
2. Ensure `generateBlockAri` supports the new product type
|
|
117
|
-
3. Add media token fetching if the product has media content
|
|
118
|
-
4. Update store managers if the product has unique lifecycle requirements
|
|
119
|
-
|
|
120
82
|
---
|
|
121
83
|
|
|
122
84
|
## Related Packages
|
|
123
85
|
|
|
124
|
-
- **Plugin**: `platform/packages/editor/editor-plugin-synced-block/`
|
|
125
|
-
- **Renderer**: `platform/packages/editor/editor-synced-block-renderer/`
|
|
126
|
-
- **Confluence**: `confluence/next/packages/fabric-providers/src/SyncedBlockProvider.ts`
|
|
127
|
-
|
|
128
|
-
- **Jira**: `jira/src/packages/issue/issue-view-synced-block-provider/` — wraps this provider with
|
|
129
|
-
Relay
|
|
86
|
+
- **Plugin**: `platform/packages/editor/editor-plugin-synced-block/`
|
|
87
|
+
- **Renderer**: `platform/packages/editor/editor-synced-block-renderer/`
|
|
88
|
+
- **Confluence**: `confluence/next/packages/fabric-providers/src/SyncedBlockProvider.ts`
|
|
89
|
+
- **Jira**: `jira/src/packages/issue/issue-view-synced-block-provider/`
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
# @atlaskit/editor-synced-block-provider
|
|
2
2
|
|
|
3
|
+
## 4.3.4
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [`ef5f5792a6aaf`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/ef5f5792a6aaf) -
|
|
8
|
+
Clean up platform_synced_block_patch_7 feature gate
|
|
9
|
+
|
|
10
|
+
## 4.3.3
|
|
11
|
+
|
|
12
|
+
### Patch Changes
|
|
13
|
+
|
|
14
|
+
- [`15deee785151b`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/15deee785151b) -
|
|
15
|
+
EDITOR-6174 Pass node to createBodiedSyncBlockNode to cache content on creation, preventing false
|
|
16
|
+
unsaved changes on page refresh
|
|
17
|
+
- Updated dependencies
|
|
18
|
+
|
|
3
19
|
## 4.3.2
|
|
4
20
|
|
|
5
21
|
### Patch Changes
|
|
@@ -237,9 +237,7 @@ var SourceSyncBlockStoreManager = exports.SourceSyncBlockStoreManager = /*#__PUR
|
|
|
237
237
|
return _context.abrupt("return", false);
|
|
238
238
|
case 31:
|
|
239
239
|
_context.prev = 31;
|
|
240
|
-
|
|
241
|
-
(_this$flushCompletion = this.flushCompletionCallback) === null || _this$flushCompletion === void 0 || _this$flushCompletion.call(this);
|
|
242
|
-
}
|
|
240
|
+
(_this$flushCompletion = this.flushCompletionCallback) === null || _this$flushCompletion === void 0 || _this$flushCompletion.call(this);
|
|
243
241
|
return _context.finish(31);
|
|
244
242
|
case 34:
|
|
245
243
|
case "end":
|
|
@@ -339,10 +337,12 @@ var SourceSyncBlockStoreManager = exports.SourceSyncBlockStoreManager = /*#__PUR
|
|
|
339
337
|
/**
|
|
340
338
|
* Create a bodiedSyncBlock node with empty content to backend
|
|
341
339
|
* @param attrs attributes Ids of the node
|
|
340
|
+
* @param node the ProseMirror node to cache
|
|
341
|
+
* @param onCompletion callback invoked when creation completes
|
|
342
342
|
*/
|
|
343
343
|
}, {
|
|
344
344
|
key: "createBodiedSyncBlockNode",
|
|
345
|
-
value: function createBodiedSyncBlockNode(attrs, onCompletion) {
|
|
345
|
+
value: function createBodiedSyncBlockNode(attrs, node, onCompletion) {
|
|
346
346
|
var _this4 = this;
|
|
347
347
|
if (this.viewMode === 'view' && (0, _platformFeatureFlags.fg)('platform_synced_block_patch_8')) {
|
|
348
348
|
return;
|
|
@@ -354,6 +354,10 @@ var SourceSyncBlockStoreManager = exports.SourceSyncBlockStoreManager = /*#__PUR
|
|
|
354
354
|
if (!this.dataProvider) {
|
|
355
355
|
throw new Error('Data provider not set');
|
|
356
356
|
}
|
|
357
|
+
if ((0, _platformFeatureFlags.fg)('platform_synced_block_update_refactor')) {
|
|
358
|
+
// add the node to the cache
|
|
359
|
+
this.updateSyncBlockData(node);
|
|
360
|
+
}
|
|
357
361
|
this.creationCompletionCallbacks.set(resourceId, onCompletion);
|
|
358
362
|
(_this$createExperienc = this.createExperience) === null || _this$createExperienc === void 0 || _this$createExperienc.start({});
|
|
359
363
|
this.dataProvider.createNodeData({
|
|
@@ -190,10 +190,8 @@ export class SourceSyncBlockStoreManager {
|
|
|
190
190
|
(_this$fireAnalyticsEv4 = this.fireAnalyticsEvent) === null || _this$fireAnalyticsEv4 === void 0 ? void 0 : _this$fireAnalyticsEv4.call(this, updateErrorPayload(error.message));
|
|
191
191
|
return false;
|
|
192
192
|
} finally {
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
(_this$flushCompletion = this.flushCompletionCallback) === null || _this$flushCompletion === void 0 ? void 0 : _this$flushCompletion.call(this);
|
|
196
|
-
}
|
|
193
|
+
var _this$flushCompletion;
|
|
194
|
+
(_this$flushCompletion = this.flushCompletionCallback) === null || _this$flushCompletion === void 0 ? void 0 : _this$flushCompletion.call(this);
|
|
197
195
|
}
|
|
198
196
|
}
|
|
199
197
|
hasUnsavedChanges() {
|
|
@@ -269,8 +267,10 @@ export class SourceSyncBlockStoreManager {
|
|
|
269
267
|
/**
|
|
270
268
|
* Create a bodiedSyncBlock node with empty content to backend
|
|
271
269
|
* @param attrs attributes Ids of the node
|
|
270
|
+
* @param node the ProseMirror node to cache
|
|
271
|
+
* @param onCompletion callback invoked when creation completes
|
|
272
272
|
*/
|
|
273
|
-
createBodiedSyncBlockNode(attrs, onCompletion) {
|
|
273
|
+
createBodiedSyncBlockNode(attrs, node, onCompletion) {
|
|
274
274
|
if (this.viewMode === 'view' && fg('platform_synced_block_patch_8')) {
|
|
275
275
|
return;
|
|
276
276
|
}
|
|
@@ -283,6 +283,10 @@ export class SourceSyncBlockStoreManager {
|
|
|
283
283
|
if (!this.dataProvider) {
|
|
284
284
|
throw new Error('Data provider not set');
|
|
285
285
|
}
|
|
286
|
+
if (fg('platform_synced_block_update_refactor')) {
|
|
287
|
+
// add the node to the cache
|
|
288
|
+
this.updateSyncBlockData(node);
|
|
289
|
+
}
|
|
286
290
|
this.creationCompletionCallbacks.set(resourceId, onCompletion);
|
|
287
291
|
(_this$createExperienc = this.createExperience) === null || _this$createExperienc === void 0 ? void 0 : _this$createExperienc.start({});
|
|
288
292
|
this.dataProvider.createNodeData({
|
|
@@ -230,9 +230,7 @@ export var SourceSyncBlockStoreManager = /*#__PURE__*/function () {
|
|
|
230
230
|
return _context.abrupt("return", false);
|
|
231
231
|
case 31:
|
|
232
232
|
_context.prev = 31;
|
|
233
|
-
|
|
234
|
-
(_this$flushCompletion = this.flushCompletionCallback) === null || _this$flushCompletion === void 0 || _this$flushCompletion.call(this);
|
|
235
|
-
}
|
|
233
|
+
(_this$flushCompletion = this.flushCompletionCallback) === null || _this$flushCompletion === void 0 || _this$flushCompletion.call(this);
|
|
236
234
|
return _context.finish(31);
|
|
237
235
|
case 34:
|
|
238
236
|
case "end":
|
|
@@ -332,10 +330,12 @@ export var SourceSyncBlockStoreManager = /*#__PURE__*/function () {
|
|
|
332
330
|
/**
|
|
333
331
|
* Create a bodiedSyncBlock node with empty content to backend
|
|
334
332
|
* @param attrs attributes Ids of the node
|
|
333
|
+
* @param node the ProseMirror node to cache
|
|
334
|
+
* @param onCompletion callback invoked when creation completes
|
|
335
335
|
*/
|
|
336
336
|
}, {
|
|
337
337
|
key: "createBodiedSyncBlockNode",
|
|
338
|
-
value: function createBodiedSyncBlockNode(attrs, onCompletion) {
|
|
338
|
+
value: function createBodiedSyncBlockNode(attrs, node, onCompletion) {
|
|
339
339
|
var _this4 = this;
|
|
340
340
|
if (this.viewMode === 'view' && fg('platform_synced_block_patch_8')) {
|
|
341
341
|
return;
|
|
@@ -347,6 +347,10 @@ export var SourceSyncBlockStoreManager = /*#__PURE__*/function () {
|
|
|
347
347
|
if (!this.dataProvider) {
|
|
348
348
|
throw new Error('Data provider not set');
|
|
349
349
|
}
|
|
350
|
+
if (fg('platform_synced_block_update_refactor')) {
|
|
351
|
+
// add the node to the cache
|
|
352
|
+
this.updateSyncBlockData(node);
|
|
353
|
+
}
|
|
350
354
|
this.creationCompletionCallbacks.set(resourceId, onCompletion);
|
|
351
355
|
(_this$createExperienc = this.createExperience) === null || _this$createExperienc === void 0 || _this$createExperienc.start({});
|
|
352
356
|
this.dataProvider.createNodeData({
|
|
@@ -57,8 +57,10 @@ export declare class SourceSyncBlockStoreManager {
|
|
|
57
57
|
/**
|
|
58
58
|
* Create a bodiedSyncBlock node with empty content to backend
|
|
59
59
|
* @param attrs attributes Ids of the node
|
|
60
|
+
* @param node the ProseMirror node to cache
|
|
61
|
+
* @param onCompletion callback invoked when creation completes
|
|
60
62
|
*/
|
|
61
|
-
createBodiedSyncBlockNode(attrs: SyncBlockAttrs, onCompletion: OnCompletion): void;
|
|
63
|
+
createBodiedSyncBlockNode(attrs: SyncBlockAttrs, node: PMNode, onCompletion: OnCompletion): void;
|
|
62
64
|
private setPendingDeletion;
|
|
63
65
|
private delete;
|
|
64
66
|
isRetryingDeletion(): boolean;
|
|
@@ -57,8 +57,10 @@ export declare class SourceSyncBlockStoreManager {
|
|
|
57
57
|
/**
|
|
58
58
|
* Create a bodiedSyncBlock node with empty content to backend
|
|
59
59
|
* @param attrs attributes Ids of the node
|
|
60
|
+
* @param node the ProseMirror node to cache
|
|
61
|
+
* @param onCompletion callback invoked when creation completes
|
|
60
62
|
*/
|
|
61
|
-
createBodiedSyncBlockNode(attrs: SyncBlockAttrs, onCompletion: OnCompletion): void;
|
|
63
|
+
createBodiedSyncBlockNode(attrs: SyncBlockAttrs, node: PMNode, onCompletion: OnCompletion): void;
|
|
62
64
|
private setPendingDeletion;
|
|
63
65
|
private delete;
|
|
64
66
|
isRetryingDeletion(): boolean;
|
package/package.json
CHANGED
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
"@atlaskit/editor-prosemirror": "^7.3.0",
|
|
30
30
|
"@atlaskit/node-data-provider": "^9.0.0",
|
|
31
31
|
"@atlaskit/platform-feature-flags": "^1.1.0",
|
|
32
|
-
"@atlaskit/tmp-editor-statsig": "^54.
|
|
32
|
+
"@atlaskit/tmp-editor-statsig": "^54.5.0",
|
|
33
33
|
"@babel/runtime": "^7.0.0",
|
|
34
34
|
"@compiled/react": "^0.20.0",
|
|
35
35
|
"graphql-ws": "^5.14.2",
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
"uuid": "^3.1.0"
|
|
39
39
|
},
|
|
40
40
|
"peerDependencies": {
|
|
41
|
-
"@atlaskit/editor-common": "^112.
|
|
41
|
+
"@atlaskit/editor-common": "^112.18.0",
|
|
42
42
|
"react": "^18.2.0"
|
|
43
43
|
},
|
|
44
44
|
"devDependencies": {
|
|
@@ -81,7 +81,7 @@
|
|
|
81
81
|
}
|
|
82
82
|
},
|
|
83
83
|
"name": "@atlaskit/editor-synced-block-provider",
|
|
84
|
-
"version": "4.3.
|
|
84
|
+
"version": "4.3.4",
|
|
85
85
|
"description": "Synced Block Provider for @atlaskit/editor-plugin-synced-block",
|
|
86
86
|
"author": "Atlassian Pty Ltd",
|
|
87
87
|
"license": "Apache-2.0",
|
|
@@ -92,9 +92,6 @@
|
|
|
92
92
|
"block_service_source_repair": {
|
|
93
93
|
"type": "boolean"
|
|
94
94
|
},
|
|
95
|
-
"platform_synced_block_patch_7": {
|
|
96
|
-
"type": "boolean"
|
|
97
|
-
},
|
|
98
95
|
"platform_synced_block_update_refactor": {
|
|
99
96
|
"type": "boolean"
|
|
100
97
|
},
|