@atlaskit/editor-synced-block-provider 3.12.0 → 3.13.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.
- package/CHANGELOG.md +25 -0
- package/dist/cjs/clients/block-service/blockSubscription.js +124 -0
- package/dist/cjs/clients/jira/sourceInfo.js +152 -0
- package/dist/cjs/providers/block-service/blockServiceAPI.js +43 -6
- package/dist/cjs/providers/syncBlockProvider.js +40 -8
- package/dist/cjs/store-manager/referenceSyncBlockStoreManager.js +393 -204
- package/dist/cjs/store-manager/sourceSyncBlockStoreManager.js +95 -124
- package/dist/cjs/store-manager/syncBlockStoreManager.js +2 -2
- package/dist/cjs/utils/errorHandling.js +79 -19
- package/dist/cjs/utils/experienceTracking.js +119 -0
- package/dist/cjs/utils/resolveSyncBlockInstance.js +1 -1
- package/dist/es2019/clients/block-service/blockSubscription.js +125 -0
- package/dist/es2019/clients/jira/sourceInfo.js +87 -0
- package/dist/es2019/providers/block-service/blockServiceAPI.js +40 -5
- package/dist/es2019/providers/syncBlockProvider.js +26 -2
- package/dist/es2019/store-manager/referenceSyncBlockStoreManager.js +286 -139
- package/dist/es2019/store-manager/sourceSyncBlockStoreManager.js +80 -89
- package/dist/es2019/store-manager/syncBlockStoreManager.js +2 -2
- package/dist/es2019/utils/errorHandling.js +61 -10
- package/dist/es2019/utils/experienceTracking.js +113 -0
- package/dist/es2019/utils/resolveSyncBlockInstance.js +1 -1
- package/dist/esm/clients/block-service/blockSubscription.js +118 -0
- package/dist/esm/clients/jira/sourceInfo.js +147 -0
- package/dist/esm/providers/block-service/blockServiceAPI.js +43 -6
- package/dist/esm/providers/syncBlockProvider.js +38 -6
- package/dist/esm/store-manager/referenceSyncBlockStoreManager.js +394 -205
- package/dist/esm/store-manager/sourceSyncBlockStoreManager.js +96 -125
- package/dist/esm/store-manager/syncBlockStoreManager.js +2 -2
- package/dist/esm/utils/errorHandling.js +77 -18
- package/dist/esm/utils/experienceTracking.js +113 -0
- package/dist/esm/utils/resolveSyncBlockInstance.js +1 -1
- package/dist/types/clients/block-service/blockService.d.ts +2 -2
- package/dist/types/clients/block-service/blockSubscription.d.ts +38 -0
- package/dist/types/clients/jira/sourceInfo.d.ts +2 -0
- package/dist/types/common/types.d.ts +4 -2
- package/dist/types/index.d.ts +2 -2
- package/dist/types/providers/block-service/blockServiceAPI.d.ts +8 -0
- package/dist/types/providers/syncBlockProvider.d.ts +9 -1
- package/dist/types/providers/types.d.ts +22 -6
- package/dist/types/store-manager/referenceSyncBlockStoreManager.d.ts +59 -1
- package/dist/types/store-manager/sourceSyncBlockStoreManager.d.ts +1 -5
- package/dist/types/utils/errorHandling.d.ts +14 -9
- package/dist/types/utils/experienceTracking.d.ts +51 -0
- package/dist/types-ts4.5/clients/block-service/blockService.d.ts +2 -2
- package/dist/types-ts4.5/clients/block-service/blockSubscription.d.ts +38 -0
- package/dist/types-ts4.5/clients/jira/sourceInfo.d.ts +2 -0
- package/dist/types-ts4.5/common/types.d.ts +4 -2
- package/dist/types-ts4.5/index.d.ts +2 -2
- package/dist/types-ts4.5/providers/block-service/blockServiceAPI.d.ts +8 -0
- package/dist/types-ts4.5/providers/syncBlockProvider.d.ts +9 -1
- package/dist/types-ts4.5/providers/types.d.ts +22 -6
- package/dist/types-ts4.5/store-manager/referenceSyncBlockStoreManager.d.ts +59 -1
- package/dist/types-ts4.5/store-manager/sourceSyncBlockStoreManager.d.ts +1 -5
- package/dist/types-ts4.5/utils/errorHandling.d.ts +14 -9
- package/dist/types-ts4.5/utils/experienceTracking.d.ts +51 -0
- package/package.json +2 -1
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.getSaveSourceExperience = exports.getSaveReferenceExperience = exports.getFetchSourceInfoExperience = exports.getFetchExperience = exports.getDeleteSourceExperience = exports.getCreateSourceExperience = exports.createExperienceDispatcher = void 0;
|
|
7
|
+
var _analytics = require("@atlaskit/editor-common/analytics");
|
|
8
|
+
var _experiences = require("@atlaskit/editor-common/experiences");
|
|
9
|
+
var TIMEOUT_DURATION = 30000;
|
|
10
|
+
var createExperienceDispatcher = exports.createExperienceDispatcher = function createExperienceDispatcher(fireAnalyticsEvent) {
|
|
11
|
+
return function (payload) {
|
|
12
|
+
// Runtime type guard - only forward experience events
|
|
13
|
+
if (payload.action === _analytics.ACTION.EXPERIENCE_MEASURED || payload.action === _analytics.ACTION.EXPERIENCE_SAMPLED) {
|
|
14
|
+
fireAnalyticsEvent === null || fireAnalyticsEvent === void 0 || fireAnalyticsEvent(payload);
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* This experience tracks when a source sync block is saved to the BE.
|
|
21
|
+
*
|
|
22
|
+
* Start: When the flush source sync block function is called.
|
|
23
|
+
* Success: When the sync block save is successful within the timeout duration of start.
|
|
24
|
+
* Failure: When the timeout duration passes without the sync block being successfully saved
|
|
25
|
+
*/
|
|
26
|
+
var getSaveSourceExperience = exports.getSaveSourceExperience = function getSaveSourceExperience(fireAnalyticsEvent) {
|
|
27
|
+
return new _experiences.Experience(_experiences.EXPERIENCE_ID.ASYNC_OPERATION, {
|
|
28
|
+
action: _analytics.ACTION.SYNCED_BLOCK_UPDATE,
|
|
29
|
+
dispatchAnalyticsEvent: createExperienceDispatcher(fireAnalyticsEvent),
|
|
30
|
+
checks: [new _experiences.ExperienceCheckTimeout({
|
|
31
|
+
durationMs: TIMEOUT_DURATION
|
|
32
|
+
})]
|
|
33
|
+
});
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* This experience tracks when a reference sync block is saved to the BE.
|
|
38
|
+
*
|
|
39
|
+
* Start: When the flush sync block function is called.
|
|
40
|
+
* Success: When the sync block save is successful within the timeout duration of start.
|
|
41
|
+
* Failure: When the timeout duration passes without the sync block being successfully saved
|
|
42
|
+
*/
|
|
43
|
+
var getSaveReferenceExperience = exports.getSaveReferenceExperience = function getSaveReferenceExperience(fireAnalyticsEvent) {
|
|
44
|
+
return new _experiences.Experience(_experiences.EXPERIENCE_ID.ASYNC_OPERATION, {
|
|
45
|
+
action: _analytics.ACTION.REFERENCE_SYNCED_BLOCK_UPDATE,
|
|
46
|
+
dispatchAnalyticsEvent: createExperienceDispatcher(fireAnalyticsEvent),
|
|
47
|
+
checks: [new _experiences.ExperienceCheckTimeout({
|
|
48
|
+
durationMs: TIMEOUT_DURATION
|
|
49
|
+
})]
|
|
50
|
+
});
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* This experience tracks when a reference sync block data is fetched from the BE.
|
|
55
|
+
*
|
|
56
|
+
* Start: When the fetchNodesData function is called.
|
|
57
|
+
* Success: When the fetching the data is successful within the timeout duration of start.
|
|
58
|
+
* Failure: When the timeout duration passes without the data being successfully fetched, or the fetch fails
|
|
59
|
+
*/
|
|
60
|
+
var getFetchExperience = exports.getFetchExperience = function getFetchExperience(fireAnalyticsEvent) {
|
|
61
|
+
return new _experiences.Experience(_experiences.EXPERIENCE_ID.ASYNC_OPERATION, {
|
|
62
|
+
action: _analytics.ACTION.SYNCED_BLOCK_FETCH,
|
|
63
|
+
dispatchAnalyticsEvent: createExperienceDispatcher(fireAnalyticsEvent),
|
|
64
|
+
checks: [new _experiences.ExperienceCheckTimeout({
|
|
65
|
+
durationMs: TIMEOUT_DURATION
|
|
66
|
+
})]
|
|
67
|
+
});
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* This experience tracks when a reference sync block source info data (title, url) is fetched from the BE.
|
|
72
|
+
*
|
|
73
|
+
* Start: When the fetchSourceInfo function is called.
|
|
74
|
+
* Success: When the fetching the data is successful within the timeout duration of start.
|
|
75
|
+
* Failure: When the timeout duration passes without the data being successfully fetched, or the fetch fails
|
|
76
|
+
*/
|
|
77
|
+
var getFetchSourceInfoExperience = exports.getFetchSourceInfoExperience = function getFetchSourceInfoExperience(fireAnalyticsEvent) {
|
|
78
|
+
return new _experiences.Experience(_experiences.EXPERIENCE_ID.ASYNC_OPERATION, {
|
|
79
|
+
action: _analytics.ACTION.SYNCED_BLOCK_GET_SOURCE_INFO,
|
|
80
|
+
dispatchAnalyticsEvent: createExperienceDispatcher(fireAnalyticsEvent),
|
|
81
|
+
checks: [new _experiences.ExperienceCheckTimeout({
|
|
82
|
+
durationMs: TIMEOUT_DURATION
|
|
83
|
+
})]
|
|
84
|
+
});
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* This experience tracks when a source sync block is deleted from the BE.
|
|
89
|
+
*
|
|
90
|
+
* Start: When the fetchSourceInfo function is called.
|
|
91
|
+
* Success: When the fetching the data is successful within the timeout duration of start.
|
|
92
|
+
* Failure: When the timeout duration passes without the data being successfully fetched, or the fetch fails
|
|
93
|
+
*/
|
|
94
|
+
var getDeleteSourceExperience = exports.getDeleteSourceExperience = function getDeleteSourceExperience(fireAnalyticsEvent) {
|
|
95
|
+
return new _experiences.Experience(_experiences.EXPERIENCE_ID.ASYNC_OPERATION, {
|
|
96
|
+
action: _analytics.ACTION.SYNCED_BLOCK_DELETE,
|
|
97
|
+
dispatchAnalyticsEvent: createExperienceDispatcher(fireAnalyticsEvent),
|
|
98
|
+
checks: [new _experiences.ExperienceCheckTimeout({
|
|
99
|
+
durationMs: TIMEOUT_DURATION
|
|
100
|
+
})]
|
|
101
|
+
});
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* This experience tracks when a source sync block is created and registered to the BE.
|
|
106
|
+
*
|
|
107
|
+
* Start: When the fetchSourceInfo function is called.
|
|
108
|
+
* Success: When the fetching the data is successful within the timeout duration of start.
|
|
109
|
+
* Failure: When the timeout duration passes without the data being successfully fetched, or the fetch fails
|
|
110
|
+
*/
|
|
111
|
+
var getCreateSourceExperience = exports.getCreateSourceExperience = function getCreateSourceExperience(fireAnalyticsEvent) {
|
|
112
|
+
return new _experiences.Experience(_experiences.EXPERIENCE_ID.ASYNC_OPERATION, {
|
|
113
|
+
action: _analytics.ACTION.SYNCED_BLOCK_CREATE,
|
|
114
|
+
dispatchAnalyticsEvent: createExperienceDispatcher(fireAnalyticsEvent),
|
|
115
|
+
checks: [new _experiences.ExperienceCheckTimeout({
|
|
116
|
+
durationMs: TIMEOUT_DURATION
|
|
117
|
+
})]
|
|
118
|
+
});
|
|
119
|
+
};
|
|
@@ -41,7 +41,7 @@ var resolveSyncBlockInstance = exports.resolveSyncBlockInstance = function resol
|
|
|
41
41
|
sourceTitle: ((_newResult$data2 = newResult.data) === null || _newResult$data2 === void 0 ? void 0 : _newResult$data2.sourceTitle) || ((_oldResult$data2 = oldResult.data) === null || _oldResult$data2 === void 0 ? void 0 : _oldResult$data2.sourceTitle) || undefined
|
|
42
42
|
}, (0, _platformFeatureFlags.fg)('platform_synced_block_dogfooding') && {
|
|
43
43
|
sourceSubType: ((_newResult$data3 = newResult.data) === null || _newResult$data3 === void 0 ? void 0 : _newResult$data3.sourceSubType) || ((_oldResult$data3 = oldResult.data) === null || _oldResult$data3 === void 0 ? void 0 : _oldResult$data3.sourceSubType) || undefined,
|
|
44
|
-
|
|
44
|
+
onSameDocument: ((_newResult$data4 = newResult.data) === null || _newResult$data4 === void 0 ? void 0 : _newResult$data4.onSameDocument) || ((_oldResult$data4 = oldResult.data) === null || _oldResult$data4 === void 0 ? void 0 : _oldResult$data4.onSameDocument) || undefined
|
|
45
45
|
})
|
|
46
46
|
});
|
|
47
47
|
};
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { createClient } from 'graphql-ws';
|
|
2
|
+
const GRAPHQL_WS_ENDPOINT = '/gateway/api/graphql/subscriptions';
|
|
3
|
+
let blockServiceClient = null;
|
|
4
|
+
const getBlockServiceClient = () => {
|
|
5
|
+
// Don't create client during SSR
|
|
6
|
+
if (typeof window === 'undefined') {
|
|
7
|
+
return null;
|
|
8
|
+
}
|
|
9
|
+
if (!blockServiceClient) {
|
|
10
|
+
const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
|
|
11
|
+
const wsUrl = `${protocol}//${window.location.host}${GRAPHQL_WS_ENDPOINT}`;
|
|
12
|
+
blockServiceClient = createClient({
|
|
13
|
+
url: wsUrl,
|
|
14
|
+
lazy: true,
|
|
15
|
+
retryAttempts: 3
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
return blockServiceClient;
|
|
19
|
+
};
|
|
20
|
+
const SUBSCRIPTION_QUERY = `
|
|
21
|
+
subscription EDITOR_SYNCED_BLOCK_ON_BLOCK_UPDATED($resourceId: ID!) {
|
|
22
|
+
blockService_onBlockUpdated(resourceId: $resourceId) {
|
|
23
|
+
blockAri
|
|
24
|
+
blockInstanceId
|
|
25
|
+
content
|
|
26
|
+
contentUpdatedAt
|
|
27
|
+
createdAt
|
|
28
|
+
createdBy
|
|
29
|
+
deletionReason
|
|
30
|
+
product
|
|
31
|
+
sourceAri
|
|
32
|
+
status
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
`;
|
|
36
|
+
/**
|
|
37
|
+
* Extracts the resourceId from a block ARI.
|
|
38
|
+
* Block ARI format: ari:cloud:blocks:<cloudId>:synced-block/<resourceId>
|
|
39
|
+
* @param blockAri - The block ARI string
|
|
40
|
+
* @returns The resourceId portion of the ARI
|
|
41
|
+
*/
|
|
42
|
+
const extractResourceIdFromBlockAri = blockAri => {
|
|
43
|
+
// eslint-disable-next-line require-unicode-regexp
|
|
44
|
+
const match = blockAri.match(/ari:cloud:blocks:[^:]+:synced-block\/(.+)$/);
|
|
45
|
+
return (match === null || match === void 0 ? void 0 : match[1]) || null;
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Parses the subscription payload into a standardized format.
|
|
50
|
+
* @param payload - The raw subscription payload
|
|
51
|
+
* @returns Parsed block data or null if parsing fails
|
|
52
|
+
*/
|
|
53
|
+
const parseSubscriptionPayload = payload => {
|
|
54
|
+
try {
|
|
55
|
+
const resourceId = extractResourceIdFromBlockAri(payload.blockAri);
|
|
56
|
+
if (!resourceId) {
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
let createdAt;
|
|
60
|
+
if (payload.createdAt !== undefined && payload.createdAt !== null) {
|
|
61
|
+
try {
|
|
62
|
+
// BE returns microseconds, convert to milliseconds
|
|
63
|
+
createdAt = new Date(payload.createdAt / 1000).toISOString();
|
|
64
|
+
} catch {
|
|
65
|
+
createdAt = undefined;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
return {
|
|
69
|
+
blockAri: payload.blockAri,
|
|
70
|
+
blockInstanceId: payload.blockInstanceId,
|
|
71
|
+
content: JSON.parse(payload.content),
|
|
72
|
+
createdAt,
|
|
73
|
+
createdBy: payload.createdBy,
|
|
74
|
+
product: payload.product,
|
|
75
|
+
resourceId,
|
|
76
|
+
sourceAri: payload.sourceAri,
|
|
77
|
+
status: payload.status
|
|
78
|
+
};
|
|
79
|
+
} catch {
|
|
80
|
+
return null;
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Creates a GraphQL subscription to block updates using the shared graphql-ws client.
|
|
86
|
+
*
|
|
87
|
+
* @param blockAri - The full block ARI to subscribe to (ari:cloud:blocks:{cloudId}:synced-block/{resourceId})
|
|
88
|
+
* @param onData - Callback function invoked when block data is updated
|
|
89
|
+
* @param onError - Optional callback function invoked on subscription errors
|
|
90
|
+
* @returns Unsubscribe function to close the subscription
|
|
91
|
+
*/
|
|
92
|
+
export const subscribeToBlockUpdates = (blockAri, onData, onError) => {
|
|
93
|
+
const client = getBlockServiceClient();
|
|
94
|
+
if (!client) {
|
|
95
|
+
// Return a no-op unsubscribe if client is not available (e.g., SSR)
|
|
96
|
+
return () => {};
|
|
97
|
+
}
|
|
98
|
+
const unsubscribe = client.subscribe({
|
|
99
|
+
query: SUBSCRIPTION_QUERY,
|
|
100
|
+
variables: {
|
|
101
|
+
resourceId: blockAri
|
|
102
|
+
},
|
|
103
|
+
operationName: 'EDITOR_SYNCED_BLOCK_ON_BLOCK_UPDATED'
|
|
104
|
+
}, {
|
|
105
|
+
next: value => {
|
|
106
|
+
var _value$data;
|
|
107
|
+
if ((_value$data = value.data) !== null && _value$data !== void 0 && _value$data.blockService_onBlockUpdated) {
|
|
108
|
+
const parsed = parseSubscriptionPayload(value.data.blockService_onBlockUpdated);
|
|
109
|
+
if (parsed !== null) {
|
|
110
|
+
onData(parsed);
|
|
111
|
+
} else {
|
|
112
|
+
onError === null || onError === void 0 ? void 0 : onError(new Error('Failed to parse block subscription payload'));
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
},
|
|
116
|
+
error: error => {
|
|
117
|
+
const errorMessage = error instanceof Error ? error.message : 'GraphQL subscription error';
|
|
118
|
+
onError === null || onError === void 0 ? void 0 : onError(new Error(errorMessage));
|
|
119
|
+
},
|
|
120
|
+
complete: () => {
|
|
121
|
+
// Subscription completed
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
return unsubscribe;
|
|
125
|
+
};
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/* eslint-disable require-unicode-regexp */
|
|
2
|
+
|
|
3
|
+
import { fetchWithRetry } from '../../utils/retry';
|
|
4
|
+
const COMMON_HEADERS = {
|
|
5
|
+
'Content-Type': 'application/json',
|
|
6
|
+
Accept: 'application/json'
|
|
7
|
+
};
|
|
8
|
+
const AGG_HEADERS = {
|
|
9
|
+
'X-ExperimentalApi': 'confluence-agg-beta'
|
|
10
|
+
};
|
|
11
|
+
const GRAPHQL_ENDPOINT = '/gateway/api/graphql';
|
|
12
|
+
const GET_SOURCE_INFO_OPERATION_NAME = 'EDITOR_SYNCED_BLOCK_GET_SOURCE_INFO';
|
|
13
|
+
/**
|
|
14
|
+
* Query to get the work item url by id
|
|
15
|
+
* @param id - the ID of the work item
|
|
16
|
+
* @returns url of the work item
|
|
17
|
+
*/
|
|
18
|
+
const GET_SOURCE_INFO_QUERY = `query ${GET_SOURCE_INFO_OPERATION_NAME} ($id: ID!) {
|
|
19
|
+
jira {
|
|
20
|
+
issueById(id: $id) {
|
|
21
|
+
id
|
|
22
|
+
webUrl
|
|
23
|
+
summary
|
|
24
|
+
}
|
|
25
|
+
}}`;
|
|
26
|
+
const getJiraWorkItemSourceInfo = async ari => {
|
|
27
|
+
const bodyData = {
|
|
28
|
+
query: GET_SOURCE_INFO_QUERY,
|
|
29
|
+
operationName: GET_SOURCE_INFO_OPERATION_NAME,
|
|
30
|
+
variables: {
|
|
31
|
+
id: ari
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
const response = await fetchWithRetry(GRAPHQL_ENDPOINT, {
|
|
35
|
+
method: 'POST',
|
|
36
|
+
headers: {
|
|
37
|
+
...COMMON_HEADERS,
|
|
38
|
+
...AGG_HEADERS
|
|
39
|
+
},
|
|
40
|
+
body: JSON.stringify(bodyData)
|
|
41
|
+
});
|
|
42
|
+
if (!response.ok) {
|
|
43
|
+
throw new Error(`Failed to get url: ${response.statusText}`);
|
|
44
|
+
}
|
|
45
|
+
return await response.json();
|
|
46
|
+
};
|
|
47
|
+
const resolveNoAccessWorkItemInfo = async ari => {
|
|
48
|
+
const response = await fetch('/gateway/api/object-resolver/resolve/ari', {
|
|
49
|
+
method: 'POST',
|
|
50
|
+
headers: {
|
|
51
|
+
'Content-Type': 'application/json',
|
|
52
|
+
Accept: 'application/json'
|
|
53
|
+
},
|
|
54
|
+
body: JSON.stringify({
|
|
55
|
+
ari
|
|
56
|
+
})
|
|
57
|
+
});
|
|
58
|
+
if (response.ok) {
|
|
59
|
+
var _payload$data, _payload$data2;
|
|
60
|
+
const payload = await response.json();
|
|
61
|
+
const url = payload === null || payload === void 0 ? void 0 : (_payload$data = payload.data) === null || _payload$data === void 0 ? void 0 : _payload$data.url;
|
|
62
|
+
const title = payload === null || payload === void 0 ? void 0 : (_payload$data2 = payload.data) === null || _payload$data2 === void 0 ? void 0 : _payload$data2.name;
|
|
63
|
+
return {
|
|
64
|
+
url: typeof url === 'string' ? url : undefined,
|
|
65
|
+
title: typeof title === 'string' ? title : undefined,
|
|
66
|
+
sourceAri: ari
|
|
67
|
+
};
|
|
68
|
+
} else {
|
|
69
|
+
throw new Error(`Failed to resolve ari: ${response.statusText}`);
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
export const fetchJiraWorkItemInfo = async (workItemAri, hasAccess) => {
|
|
73
|
+
if (hasAccess) {
|
|
74
|
+
var _response$data, _response$data$jira;
|
|
75
|
+
const response = await getJiraWorkItemSourceInfo(workItemAri);
|
|
76
|
+
const contentData = (_response$data = response.data) === null || _response$data === void 0 ? void 0 : (_response$data$jira = _response$data.jira) === null || _response$data$jira === void 0 ? void 0 : _response$data$jira.issueById;
|
|
77
|
+
const webUrl = contentData === null || contentData === void 0 ? void 0 : contentData.webUrl;
|
|
78
|
+
const summary = contentData === null || contentData === void 0 ? void 0 : contentData.summary;
|
|
79
|
+
return Promise.resolve({
|
|
80
|
+
url: webUrl,
|
|
81
|
+
sourceAri: workItemAri,
|
|
82
|
+
title: summary
|
|
83
|
+
});
|
|
84
|
+
} else {
|
|
85
|
+
return await resolveNoAccessWorkItemInfo(workItemAri);
|
|
86
|
+
}
|
|
87
|
+
};
|
|
@@ -3,6 +3,7 @@ import { useMemo } from 'react';
|
|
|
3
3
|
import { fg } from '@atlaskit/platform-feature-flags';
|
|
4
4
|
import { generateBlockAri, generateBlockAriFromReference } from '../../clients/block-service/ari';
|
|
5
5
|
import { batchRetrieveSyncedBlocks, BlockError, createSyncedBlock, deleteSyncedBlock, getReferenceSyncedBlocks, getReferenceSyncedBlocksByBlockAri, getSyncedBlockContent, updateReferenceSyncedBlockOnDocument, updateSyncedBlock } from '../../clients/block-service/blockService';
|
|
6
|
+
import { subscribeToBlockUpdates as subscribeToBlockUpdatesWS } from '../../clients/block-service/blockSubscription';
|
|
6
7
|
import { SyncBlockError } from '../../common/types';
|
|
7
8
|
import { stringifyError } from '../../utils/errorHandling';
|
|
8
9
|
import { createResourceIdForReference } from '../../utils/resourceId';
|
|
@@ -100,7 +101,8 @@ export const convertToSyncBlockData = (data, resourceId) => {
|
|
|
100
101
|
createdBy: data.createdBy,
|
|
101
102
|
product: data.product,
|
|
102
103
|
resourceId,
|
|
103
|
-
sourceAri: data.sourceAri
|
|
104
|
+
sourceAri: data.sourceAri,
|
|
105
|
+
status: data.status
|
|
104
106
|
};
|
|
105
107
|
};
|
|
106
108
|
export const fetchReferences = async documentAri => {
|
|
@@ -186,7 +188,8 @@ class BlockServiceADFFetchProvider {
|
|
|
186
188
|
blockInstanceId: blockContentResponse.blockInstanceId,
|
|
187
189
|
// this was the node's localId, but has become the resourceId.
|
|
188
190
|
sourceAri: blockContentResponse.sourceAri,
|
|
189
|
-
product: blockContentResponse.product
|
|
191
|
+
product: blockContentResponse.product,
|
|
192
|
+
status: blockContentResponse.status
|
|
190
193
|
},
|
|
191
194
|
resourceId
|
|
192
195
|
};
|
|
@@ -217,7 +220,7 @@ class BlockServiceADFFetchProvider {
|
|
|
217
220
|
references.push({
|
|
218
221
|
...reference,
|
|
219
222
|
hasAccess: true,
|
|
220
|
-
|
|
223
|
+
onSameDocument: this.parentAri === reference.documentAri
|
|
221
224
|
});
|
|
222
225
|
});
|
|
223
226
|
response.errors.forEach(reference => {
|
|
@@ -226,7 +229,7 @@ class BlockServiceADFFetchProvider {
|
|
|
226
229
|
blockAri: reference.blockAri,
|
|
227
230
|
documentAri: reference.documentAri,
|
|
228
231
|
hasAccess: false,
|
|
229
|
-
|
|
232
|
+
onSameDocument: false
|
|
230
233
|
});
|
|
231
234
|
}
|
|
232
235
|
});
|
|
@@ -311,7 +314,8 @@ class BlockServiceADFFetchProvider {
|
|
|
311
314
|
resourceId: blockContentResponse.blockAri,
|
|
312
315
|
blockInstanceId: blockContentResponse.blockInstanceId,
|
|
313
316
|
sourceAri: blockContentResponse.sourceAri,
|
|
314
|
-
product: blockContentResponse.product
|
|
317
|
+
product: blockContentResponse.product,
|
|
318
|
+
status: blockContentResponse.status
|
|
315
319
|
},
|
|
316
320
|
resourceId
|
|
317
321
|
});
|
|
@@ -358,6 +362,37 @@ class BlockServiceADFFetchProvider {
|
|
|
358
362
|
}));
|
|
359
363
|
}
|
|
360
364
|
}
|
|
365
|
+
|
|
366
|
+
/**
|
|
367
|
+
* Subscribes to real-time updates for a specific block using GraphQL WebSocket subscriptions.
|
|
368
|
+
* @param resourceId - The resource ID of the block to subscribe to
|
|
369
|
+
* @param onUpdate - Callback function invoked when the block is updated
|
|
370
|
+
* @param onError - Optional callback function invoked on subscription errors
|
|
371
|
+
* @returns Unsubscribe function to stop receiving updates
|
|
372
|
+
*/
|
|
373
|
+
subscribeToBlockUpdates(resourceId, onUpdate, onError) {
|
|
374
|
+
const blockAri = generateBlockAriFromReference({
|
|
375
|
+
cloudId: this.cloudId,
|
|
376
|
+
resourceId
|
|
377
|
+
});
|
|
378
|
+
return subscribeToBlockUpdatesWS(blockAri, parsedData => {
|
|
379
|
+
// Convert ParsedBlockSubscriptionData to SyncBlockInstance
|
|
380
|
+
const syncBlockInstance = {
|
|
381
|
+
data: {
|
|
382
|
+
content: parsedData.content,
|
|
383
|
+
resourceId: parsedData.blockAri,
|
|
384
|
+
blockInstanceId: parsedData.blockInstanceId,
|
|
385
|
+
sourceAri: parsedData.sourceAri,
|
|
386
|
+
product: parsedData.product,
|
|
387
|
+
createdAt: parsedData.createdAt,
|
|
388
|
+
createdBy: parsedData.createdBy,
|
|
389
|
+
status: parsedData.status
|
|
390
|
+
},
|
|
391
|
+
resourceId: parsedData.resourceId
|
|
392
|
+
};
|
|
393
|
+
onUpdate(syncBlockInstance);
|
|
394
|
+
}, onError);
|
|
395
|
+
}
|
|
361
396
|
}
|
|
362
397
|
/**
|
|
363
398
|
* ADFWriteProvider implementation that writes synced block data to Block Service API
|
|
@@ -4,6 +4,7 @@ import { fg } from '@atlaskit/platform-feature-flags';
|
|
|
4
4
|
import { getProductFromSourceAri } from '../clients/block-service/ari';
|
|
5
5
|
import { getPageIdAndTypeFromConfluencePageAri } from '../clients/confluence/ari';
|
|
6
6
|
import { fetchConfluencePageInfo } from '../clients/confluence/sourceInfo';
|
|
7
|
+
import { fetchJiraWorkItemInfo } from '../clients/jira/sourceInfo';
|
|
7
8
|
import { SyncBlockError } from '../common/types';
|
|
8
9
|
import { SyncBlockDataProvider } from './types';
|
|
9
10
|
export class SyncBlockProvider extends SyncBlockDataProvider {
|
|
@@ -204,7 +205,7 @@ export class SyncBlockProvider extends SyncBlockDataProvider {
|
|
|
204
205
|
}
|
|
205
206
|
return {
|
|
206
207
|
...sourceInfo,
|
|
207
|
-
|
|
208
|
+
onSameDocument: ((_this$writeProvider3 = this.writeProvider) === null || _this$writeProvider3 === void 0 ? void 0 : _this$writeProvider3.parentAri) === ari,
|
|
208
209
|
productType: product
|
|
209
210
|
};
|
|
210
211
|
} else {
|
|
@@ -213,7 +214,16 @@ export class SyncBlockProvider extends SyncBlockDataProvider {
|
|
|
213
214
|
}
|
|
214
215
|
case 'jira-work-item':
|
|
215
216
|
if (fg('platform_synced_block_dogfooding')) {
|
|
216
|
-
|
|
217
|
+
var _this$writeProvider4;
|
|
218
|
+
const sourceInfo = await fetchJiraWorkItemInfo(ari, hasAccess);
|
|
219
|
+
if (!sourceInfo) {
|
|
220
|
+
return Promise.resolve(undefined);
|
|
221
|
+
}
|
|
222
|
+
return {
|
|
223
|
+
...sourceInfo,
|
|
224
|
+
onSameDocument: ((_this$writeProvider4 = this.writeProvider) === null || _this$writeProvider4 === void 0 ? void 0 : _this$writeProvider4.parentAri) === ari,
|
|
225
|
+
productType: product
|
|
226
|
+
};
|
|
217
227
|
}
|
|
218
228
|
return Promise.reject(new Error('Jira work item source product not supported'));
|
|
219
229
|
default:
|
|
@@ -282,6 +292,20 @@ export class SyncBlockProvider extends SyncBlockDataProvider {
|
|
|
282
292
|
}
|
|
283
293
|
return this.fetchProvider.fetchReferences(isSource ? this.generateResourceIdForReference(resourceId) : resourceId);
|
|
284
294
|
}
|
|
295
|
+
|
|
296
|
+
/**
|
|
297
|
+
* Subscribes to real-time updates for a specific block.
|
|
298
|
+
* @param resourceId - The resource ID of the block to subscribe to
|
|
299
|
+
* @param onUpdate - Callback function invoked when the block is updated
|
|
300
|
+
* @param onError - Optional callback function invoked on subscription errors
|
|
301
|
+
* @returns Unsubscribe function to stop receiving updates, or undefined if not supported
|
|
302
|
+
*/
|
|
303
|
+
subscribeToBlockUpdates(resourceId, onUpdate, onError) {
|
|
304
|
+
if (this.fetchProvider.subscribeToBlockUpdates) {
|
|
305
|
+
return this.fetchProvider.subscribeToBlockUpdates(resourceId, onUpdate, onError);
|
|
306
|
+
}
|
|
307
|
+
return undefined;
|
|
308
|
+
}
|
|
285
309
|
}
|
|
286
310
|
const createSyncedBlockProvider = ({
|
|
287
311
|
fetchProvider,
|