@atlaskit/link-datasource 1.1.7 → 1.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/dist/cjs/analytics/constants.js +1 -1
  3. package/dist/cjs/analytics/ufoExperiences/index.js +51 -0
  4. package/dist/cjs/analytics/ufoExperiences/types.js +5 -0
  5. package/dist/cjs/analytics/ufoExperiences/useDataRenderedUfoExperience.js +52 -0
  6. package/dist/cjs/ui/assets-modal/modal/index.js +1 -1
  7. package/dist/cjs/ui/datasource-table-view/datasourceTableView.js +21 -1
  8. package/dist/cjs/ui/issue-like-table/index.js +10 -1
  9. package/dist/cjs/ui/jira-issues-modal/modal/index.js +33 -9
  10. package/dist/es2019/analytics/constants.js +1 -1
  11. package/dist/es2019/analytics/ufoExperiences/index.js +45 -0
  12. package/dist/es2019/analytics/ufoExperiences/types.js +1 -0
  13. package/dist/es2019/analytics/ufoExperiences/useDataRenderedUfoExperience.js +46 -0
  14. package/dist/es2019/ui/assets-modal/modal/index.js +1 -1
  15. package/dist/es2019/ui/datasource-table-view/datasourceTableView.js +22 -1
  16. package/dist/es2019/ui/issue-like-table/index.js +10 -1
  17. package/dist/es2019/ui/jira-issues-modal/modal/index.js +34 -9
  18. package/dist/esm/analytics/constants.js +1 -1
  19. package/dist/esm/analytics/ufoExperiences/index.js +41 -0
  20. package/dist/esm/analytics/ufoExperiences/types.js +1 -0
  21. package/dist/esm/analytics/ufoExperiences/useDataRenderedUfoExperience.js +45 -0
  22. package/dist/esm/ui/assets-modal/modal/index.js +1 -1
  23. package/dist/esm/ui/datasource-table-view/datasourceTableView.js +21 -1
  24. package/dist/esm/ui/issue-like-table/index.js +10 -1
  25. package/dist/esm/ui/jira-issues-modal/modal/index.js +33 -9
  26. package/dist/types/analytics/ufoExperiences/index.d.ts +5 -0
  27. package/dist/types/analytics/ufoExperiences/types.d.ts +8 -0
  28. package/dist/types/analytics/ufoExperiences/useDataRenderedUfoExperience.d.ts +22 -0
  29. package/dist/types/ui/issue-like-table/index.d.ts +1 -1
  30. package/dist/types/ui/issue-like-table/types.d.ts +4 -0
  31. package/dist/types/ui/jira-issues-modal/types.d.ts +2 -1
  32. package/dist/types-ts4.5/analytics/ufoExperiences/index.d.ts +5 -0
  33. package/dist/types-ts4.5/analytics/ufoExperiences/types.d.ts +8 -0
  34. package/dist/types-ts4.5/analytics/ufoExperiences/useDataRenderedUfoExperience.d.ts +22 -0
  35. package/dist/types-ts4.5/ui/issue-like-table/index.d.ts +1 -1
  36. package/dist/types-ts4.5/ui/issue-like-table/types.d.ts +4 -0
  37. package/dist/types-ts4.5/ui/jira-issues-modal/types.d.ts +2 -1
  38. package/package.json +5 -4
  39. package/report.api.md +5 -1
  40. package/tmp/api-report-tmp.d.ts +2 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,18 @@
1
1
  # @atlaskit/link-datasource
2
2
 
3
+ ## 1.2.1
4
+
5
+ ### Patch Changes
6
+
7
+ - [`103618b094f`](https://bitbucket.org/atlassian/atlassian-frontend/commits/103618b094f) - Add UFO metrics to measure datasource rendering performance.
8
+ - Updated dependencies
9
+
10
+ ## 1.2.0
11
+
12
+ ### Minor Changes
13
+
14
+ - [`bab3ac9e64e`](https://bitbucket.org/atlassian/atlassian-frontend/commits/bab3ac9e64e) - Passing analytic events with attributes from link-datasource modal to editor.
15
+
3
16
  ## 1.1.7
4
17
 
5
18
  ### Patch Changes
@@ -8,6 +8,6 @@ var EVENT_CHANNEL = 'media';
8
8
  exports.EVENT_CHANNEL = EVENT_CHANNEL;
9
9
  var packageMetaData = {
10
10
  packageName: "@atlaskit/link-datasource",
11
- packageVersion: "1.1.7"
11
+ packageVersion: "1.2.1"
12
12
  };
13
13
  exports.packageMetaData = packageMetaData;
@@ -0,0 +1,51 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.succeedUfoExperience = exports.startUfoExperience = exports.failUfoExperience = exports.addMetadataToExperience = void 0;
7
+ var _ufo = require("@atlaskit/ufo");
8
+ var datasourcePageSegmentLoadExperienceConfig = {
9
+ platform: {
10
+ component: 'datasource'
11
+ },
12
+ type: _ufo.ExperienceTypes.Load,
13
+ performanceType: _ufo.ExperiencePerformanceTypes.PageSegmentLoad
14
+ };
15
+ var ufoExperiences = {
16
+ 'datasource-rendered': new _ufo.ConcurrentExperience('datasource-rendered', datasourcePageSegmentLoadExperienceConfig)
17
+ };
18
+ var startUfoExperience = function startUfoExperience(_ref, id) {
19
+ var name = _ref.name,
20
+ metadata = _ref.metadata;
21
+ var experienceInstance = ufoExperiences[name].getInstance(id);
22
+ experienceInstance.start();
23
+ if (metadata) {
24
+ experienceInstance.addMetadata(metadata);
25
+ }
26
+ };
27
+ exports.startUfoExperience = startUfoExperience;
28
+ var succeedUfoExperience = function succeedUfoExperience(_ref2, id) {
29
+ var name = _ref2.name,
30
+ metadata = _ref2.metadata;
31
+ var experienceInstance = ufoExperiences[name].getInstance(id);
32
+ experienceInstance.success({
33
+ metadata: metadata
34
+ });
35
+ };
36
+ exports.succeedUfoExperience = succeedUfoExperience;
37
+ var failUfoExperience = function failUfoExperience(_ref3, id) {
38
+ var name = _ref3.name,
39
+ metadata = _ref3.metadata;
40
+ var experienceInstance = ufoExperiences[name].getInstance(id);
41
+ experienceInstance.failure({
42
+ metadata: metadata
43
+ });
44
+ };
45
+ exports.failUfoExperience = failUfoExperience;
46
+ var addMetadataToExperience = function addMetadataToExperience(_ref4, id) {
47
+ var name = _ref4.name,
48
+ metadata = _ref4.metadata;
49
+ ufoExperiences[name].getInstance(id).addMetadata(metadata);
50
+ };
51
+ exports.addMetadataToExperience = addMetadataToExperience;
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
@@ -0,0 +1,52 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.useDataRenderedUfoExperience = void 0;
7
+ var _react = require("react");
8
+ var _index = require("./index");
9
+ /**
10
+ * Hook to mark DataRendered UFO experience as either Success or Failure
11
+ * 1. Success when
12
+ * * its rendered as a link
13
+ * * it returns empty results
14
+ * * the request is unauthorized
15
+ * 2. Fail when
16
+ * * request is rejected
17
+ *
18
+ * Note:
19
+ * * When the request is resolved as a datasource table, it will be marked success in the table component, every other success case is marked by this hook
20
+ */
21
+ var useDataRenderedUfoExperience = function useDataRenderedUfoExperience(_ref) {
22
+ var status = _ref.status,
23
+ experienceId = _ref.experienceId,
24
+ itemCount = _ref.itemCount,
25
+ canBeLink = _ref.canBeLink,
26
+ extensionKey = _ref.extensionKey;
27
+ (0, _react.useEffect)(function () {
28
+ var isEmptyResult = status === 'resolved' && itemCount === 0;
29
+ var isLink = status === 'resolved' && (itemCount === 1 || canBeLink); // this will take care of count-mode/single-item smart-link rendering
30
+ var isUnauthorized = status === 'unauthorized';
31
+ var shouldSucceedUfoExperience = isEmptyResult || isLink || isUnauthorized;
32
+ var shouldFailUfoExperience = status === 'rejected';
33
+ if (extensionKey) {
34
+ (0, _index.addMetadataToExperience)({
35
+ name: 'datasource-rendered',
36
+ metadata: {
37
+ extensionKey: extensionKey
38
+ }
39
+ }, experienceId);
40
+ }
41
+ if (shouldFailUfoExperience) {
42
+ (0, _index.failUfoExperience)({
43
+ name: 'datasource-rendered'
44
+ }, experienceId);
45
+ } else if (shouldSucceedUfoExperience) {
46
+ (0, _index.succeedUfoExperience)({
47
+ name: 'datasource-rendered'
48
+ }, experienceId);
49
+ }
50
+ }, [canBeLink, experienceId, extensionKey, itemCount, status]);
51
+ };
52
+ exports.useDataRenderedUfoExperience = useDataRenderedUfoExperience;
@@ -231,7 +231,7 @@ var analyticsContextAttributes = {
231
231
  };
232
232
  var analyticsContextData = {
233
233
  packageName: "@atlaskit/link-datasource",
234
- packageVersion: "1.1.7",
234
+ packageVersion: "1.2.1",
235
235
  source: 'datasourceConfigModal'
236
236
  };
237
237
  var contextData = _objectSpread(_objectSpread({}, analyticsContextData), {}, {
@@ -7,9 +7,12 @@ Object.defineProperty(exports, "__esModule", {
7
7
  exports.DatasourceTableView = void 0;
8
8
  var _react = require("react");
9
9
  var _react2 = require("@emotion/react");
10
+ var _uuid = require("uuid");
10
11
  var _analyticsNext = require("@atlaskit/analytics-next");
11
12
  var _analytics = require("../../analytics");
12
13
  var _constants = require("../../analytics/constants");
14
+ var _ufoExperiences = require("../../analytics/ufoExperiences");
15
+ var _useDataRenderedUfoExperience = require("../../analytics/ufoExperiences/useDataRenderedUfoExperience");
13
16
  var _useDatasourceTableState = require("../../hooks/useDatasourceTableState");
14
17
  var _accessRequired = require("../common/error-state/access-required");
15
18
  var _loadingError = require("../common/error-state/loading-error");
@@ -43,6 +46,8 @@ var DatasourceTableViewWithoutAnalytics = function DatasourceTableViewWithoutAna
43
46
  destinationObjectTypes = _useDatasourceTableSt.destinationObjectTypes;
44
47
  var _useDatasourceAnalyti = (0, _analytics.useDatasourceAnalyticsEvents)(),
45
48
  fireEvent = _useDatasourceAnalyti.fireEvent;
49
+ var _useRef = (0, _react.useRef)((0, _uuid.v4)()),
50
+ tableRenderInstanceId = _useRef.current;
46
51
 
47
52
  /* Need this to make sure that the datasource in the editor gets updated new info if any edits are made in the modal
48
53
  But we don't want to call it on initial load. This screws up useDatasourceTableState's internal
@@ -60,6 +65,20 @@ var DatasourceTableViewWithoutAnalytics = function DatasourceTableViewWithoutAna
60
65
  onVisibleColumnKeysChange(defaultVisibleColumnKeys);
61
66
  }
62
67
  }, [visibleColumnKeys, defaultVisibleColumnKeys, onVisibleColumnKeysChange]);
68
+ (0, _react.useEffect)(function () {
69
+ var shouldStartUfoExperience = datasourceId && parameters && visibleColumnKeys && status === 'loading';
70
+ if (shouldStartUfoExperience) {
71
+ (0, _ufoExperiences.startUfoExperience)({
72
+ name: 'datasource-rendered'
73
+ }, tableRenderInstanceId);
74
+ }
75
+ }, [datasourceId, parameters, status, tableRenderInstanceId, visibleColumnKeys]);
76
+ (0, _useDataRenderedUfoExperience.useDataRenderedUfoExperience)({
77
+ status: status,
78
+ experienceId: tableRenderInstanceId,
79
+ itemCount: responseItems.length,
80
+ extensionKey: extensionKey
81
+ });
63
82
  var forcedReset = (0, _react.useCallback)(function () {
64
83
  fireEvent('ui.button.clicked.sync', {
65
84
  extensionKey: extensionKey,
@@ -97,7 +116,8 @@ var DatasourceTableViewWithoutAnalytics = function DatasourceTableViewWithoutAna
97
116
  columns: columns,
98
117
  visibleColumnKeys: visibleColumnKeys || defaultVisibleColumnKeys,
99
118
  onVisibleColumnKeysChange: onVisibleColumnKeysChange,
100
- scrollableContainerHeight: 590
119
+ scrollableContainerHeight: 590,
120
+ parentContainerRenderInstanceId: tableRenderInstanceId
101
121
  }) : (0, _react2.jsx)(_emptyState.default, {
102
122
  testId: "datasource-table-view-skeleton",
103
123
  isCompact: true,
@@ -24,6 +24,7 @@ var _element = require("@atlaskit/pragmatic-drag-and-drop/adapter/element");
24
24
  var _combine = require("@atlaskit/pragmatic-drag-and-drop/util/combine");
25
25
  var _colors = require("@atlaskit/theme/colors");
26
26
  var _tooltip = _interopRequireDefault(require("@atlaskit/tooltip"));
27
+ var _ufoExperiences = require("../../analytics/ufoExperiences");
27
28
  var _columnPicker = require("./column-picker");
28
29
  var _dragColumnPreview = require("./drag-column-preview");
29
30
  var _draggableTableHeading = require("./draggable-table-heading");
@@ -122,7 +123,8 @@ var IssueLikeDataTableView = function IssueLikeDataTableView(_ref2) {
122
123
  onVisibleColumnKeysChange = _ref2.onVisibleColumnKeysChange,
123
124
  status = _ref2.status,
124
125
  hasNextPage = _ref2.hasNextPage,
125
- scrollableContainerHeight = _ref2.scrollableContainerHeight;
126
+ scrollableContainerHeight = _ref2.scrollableContainerHeight,
127
+ parentContainerRenderInstanceId = _ref2.parentContainerRenderInstanceId;
126
128
  var tableId = (0, _react.useMemo)(function () {
127
129
  return Symbol('unique-id');
128
130
  }, []);
@@ -145,6 +147,13 @@ var IssueLikeDataTableView = function IssueLikeDataTableView(_ref2) {
145
147
  (0, _react.useEffect)(function () {
146
148
  setOrderedColumns(orderColumns((0, _toConsumableArray2.default)(columns), (0, _toConsumableArray2.default)(visibleColumnKeys)));
147
149
  }, [columns, visibleColumnKeys]);
150
+ (0, _react.useEffect)(function () {
151
+ if (parentContainerRenderInstanceId && status === 'resolved') {
152
+ (0, _ufoExperiences.succeedUfoExperience)({
153
+ name: 'datasource-rendered'
154
+ }, parentContainerRenderInstanceId);
155
+ }
156
+ }, [parentContainerRenderInstanceId, status]);
148
157
  var visibleSortedColumns = (0, _react.useMemo)(function () {
149
158
  return visibleColumnKeys.map(function (visibleKey) {
150
159
  return orderedColumns.find(function (_ref3) {
@@ -14,6 +14,7 @@ var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/sli
14
14
  var _react = require("react");
15
15
  var _react2 = require("@emotion/react");
16
16
  var _reactIntlNext = require("react-intl-next");
17
+ var _uuid = require("uuid");
17
18
  var _analyticsNext = require("@atlaskit/analytics-next");
18
19
  var _standardButton = _interopRequireDefault(require("@atlaskit/button/standard-button"));
19
20
  var _modalDialog = _interopRequireWildcard(require("@atlaskit/modal-dialog"));
@@ -21,6 +22,8 @@ var _colors = require("@atlaskit/theme/colors");
21
22
  var _analytics = require("../../../analytics");
22
23
  var _constants = require("../../../analytics/constants");
23
24
  var _types = require("../../../analytics/types");
25
+ var _ufoExperiences = require("../../../analytics/ufoExperiences");
26
+ var _useDataRenderedUfoExperience = require("../../../analytics/ufoExperiences/useDataRenderedUfoExperience");
24
27
  var _utils = require("../../../analytics/utils");
25
28
  var _useDatasourceTableState = require("../../../hooks/useDatasourceTableState");
26
29
  var _getAvailableJiraSites = require("../../../services/getAvailableJiraSites");
@@ -145,6 +148,8 @@ var PlainJiraIssuesConfigModal = function PlainJiraIssuesConfigModal(props) {
145
148
  formatMessage = _useIntl.formatMessage;
146
149
  var _useDatasourceAnalyti = (0, _analytics.useDatasourceAnalyticsEvents)(),
147
150
  fireEvent = _useDatasourceAnalyti.fireEvent;
151
+ var _useRef = (0, _react.useRef)((0, _uuid.v4)()),
152
+ modalRenderInstanceId = _useRef.current;
148
153
  var selectedJiraSite = (0, _react.useMemo)(function () {
149
154
  if (cloudId) {
150
155
  // if the cloud id we're editing isn't in available sites then user is likely unauthorized for that site
@@ -162,14 +167,28 @@ var PlainJiraIssuesConfigModal = function PlainJiraIssuesConfigModal(props) {
162
167
  var buttonClickedAnalyticsPayload = (0, _react.useMemo)(function () {
163
168
  return {
164
169
  extensionKey: extensionKey,
165
- destinationObjectTypes: destinationObjectTypes,
166
- actions: userInteractionActions.current
170
+ destinationObjectTypes: destinationObjectTypes
167
171
  };
168
172
  }, [destinationObjectTypes, extensionKey]);
169
173
  var resolvedWithNoResults = status === 'resolved' && !responseItems.length;
170
174
  var jqlUrl = selectedJiraSite && jql && "".concat(selectedJiraSite.url, "/issues/?jql=").concat(encodeURI(jql));
171
175
  var isInsertDisabled = !isParametersSet || status === 'rejected' || status === 'unauthorized' || status === 'loading' || resolvedWithNoResults;
172
176
  var shouldShowIssueCount = !!totalCount && totalCount !== 1 && currentViewMode === 'issue';
177
+ (0, _react.useEffect)(function () {
178
+ var shouldStartUfoExperience = status === 'loading';
179
+ if (shouldStartUfoExperience) {
180
+ (0, _ufoExperiences.startUfoExperience)({
181
+ name: 'datasource-rendered'
182
+ }, modalRenderInstanceId);
183
+ }
184
+ }, [modalRenderInstanceId, status]);
185
+ (0, _useDataRenderedUfoExperience.useDataRenderedUfoExperience)({
186
+ status: status,
187
+ experienceId: modalRenderInstanceId,
188
+ itemCount: responseItems.length,
189
+ canBeLink: currentViewMode === 'count',
190
+ extensionKey: extensionKey
191
+ });
173
192
  (0, _react.useEffect)(function () {
174
193
  fireEvent('screen.datasourceModalDialog.viewed', {});
175
194
  }, [fireEvent]);
@@ -252,6 +271,7 @@ var PlainJiraIssuesConfigModal = function PlainJiraIssuesConfigModal(props) {
252
271
  eventType: 'ui',
253
272
  actionSubjectId: 'cancel',
254
273
  attributes: _objectSpread(_objectSpread({}, buttonClickedAnalyticsPayload), {}, {
274
+ actions: Array.from(userInteractionActions.current),
255
275
  searchCount: searchCount.current
256
276
  })
257
277
  }).fire(_analytics.EVENT_CHANNEL);
@@ -271,13 +291,15 @@ var PlainJiraIssuesConfigModal = function PlainJiraIssuesConfigModal(props) {
271
291
  // agreement with BE that we will use `key` for rendering smartlink
272
292
  return data === null || data === void 0 ? void 0 : (_data$key = data.key) === null || _data$key === void 0 ? void 0 : (_data$key$data = _data$key.data) === null || _data$key$data === void 0 ? void 0 : _data$key$data.url;
273
293
  }, [responseItems]);
274
- var onInsertPressed = (0, _react.useCallback)(function (e, analyticEvent) {
294
+ var onInsertPressed = (0, _react.useCallback)(function (e, analyticsEvent) {
295
+ var _insertButtonClickedE;
275
296
  if (!isParametersSet || !jql || !selectedJiraSite) {
276
297
  return;
277
298
  }
278
- var insertButtonClickedEvent = analyticEvent.update({
299
+ var insertButtonClickedEvent = analyticsEvent.update({
279
300
  actionSubjectId: 'insert',
280
301
  attributes: _objectSpread(_objectSpread({}, buttonClickedAnalyticsPayload), {}, {
302
+ actions: Array.from(userInteractionActions.current),
281
303
  totalItemCount: totalCount || 0,
282
304
  displayedColumnCount: (visibleColumnKeys === null || visibleColumnKeys === void 0 ? void 0 : visibleColumnKeys.length) || 0,
283
305
  display: getDisplayValue(currentViewMode, totalCount || 0),
@@ -286,6 +308,7 @@ var PlainJiraIssuesConfigModal = function PlainJiraIssuesConfigModal(props) {
286
308
  }),
287
309
  eventType: 'ui'
288
310
  });
311
+ var consumerEvent = (_insertButtonClickedE = insertButtonClickedEvent.clone()) !== null && _insertButtonClickedE !== void 0 ? _insertButtonClickedE : undefined;
289
312
  insertButtonClickedEvent.fire(_analytics.EVENT_CHANNEL);
290
313
  var firstIssueUrl = retrieveUrlForSmartCardRender();
291
314
  if (currentViewMode === 'count') {
@@ -294,14 +317,14 @@ var PlainJiraIssuesConfigModal = function PlainJiraIssuesConfigModal(props) {
294
317
  attrs: {
295
318
  url: jqlUrl
296
319
  }
297
- });
320
+ }, consumerEvent);
298
321
  } else if (responseItems.length === 1 && firstIssueUrl) {
299
322
  onInsert({
300
323
  type: 'inlineCard',
301
324
  attrs: {
302
325
  url: firstIssueUrl
303
326
  }
304
- });
327
+ }, consumerEvent);
305
328
  } else {
306
329
  onInsert({
307
330
  type: 'blockCard',
@@ -326,7 +349,7 @@ var PlainJiraIssuesConfigModal = function PlainJiraIssuesConfigModal(props) {
326
349
  }]
327
350
  }
328
351
  }
329
- });
352
+ }, consumerEvent);
330
353
  }
331
354
  }, [isParametersSet, jql, selectedJiraSite, buttonClickedAnalyticsPayload, totalCount, visibleColumnKeys, currentViewMode, retrieveUrlForSmartCardRender, responseItems.length, onInsert, jqlUrl, datasourceId, cloudId]);
332
355
  var handleViewModeChange = function handleViewModeChange(selectedMode) {
@@ -355,9 +378,10 @@ var PlainJiraIssuesConfigModal = function PlainJiraIssuesConfigModal(props) {
355
378
  visibleColumnKeys: visibleColumnKeys || defaultVisibleColumnKeys,
356
379
  onNextPage: handleOnNextPage,
357
380
  onLoadDatasourceDetails: loadDatasourceDetails,
358
- onVisibleColumnKeysChange: handleVisibleColumnKeysChange
381
+ onVisibleColumnKeysChange: handleVisibleColumnKeysChange,
382
+ parentContainerRenderInstanceId: modalRenderInstanceId
359
383
  }));
360
- }, [columns, defaultVisibleColumnKeys, hasNextPage, handleVisibleColumnKeysChange, loadDatasourceDetails, handleOnNextPage, responseItems, status, visibleColumnKeys]);
384
+ }, [columns, defaultVisibleColumnKeys, handleOnNextPage, handleVisibleColumnKeysChange, hasNextPage, loadDatasourceDetails, modalRenderInstanceId, responseItems, status, visibleColumnKeys]);
361
385
  var renderCountModeContent = (0, _react.useCallback)(function () {
362
386
  var url = selectedJiraSite === null || selectedJiraSite === void 0 ? void 0 : selectedJiraSite.url;
363
387
  if (status === 'unauthorized') {
@@ -1,5 +1,5 @@
1
1
  export const EVENT_CHANNEL = 'media';
2
2
  export const packageMetaData = {
3
3
  packageName: "@atlaskit/link-datasource",
4
- packageVersion: "1.1.7"
4
+ packageVersion: "1.2.1"
5
5
  };
@@ -0,0 +1,45 @@
1
+ import { ConcurrentExperience, ExperiencePerformanceTypes, ExperienceTypes } from '@atlaskit/ufo';
2
+ const datasourcePageSegmentLoadExperienceConfig = {
3
+ platform: {
4
+ component: 'datasource'
5
+ },
6
+ type: ExperienceTypes.Load,
7
+ performanceType: ExperiencePerformanceTypes.PageSegmentLoad
8
+ };
9
+ const ufoExperiences = {
10
+ 'datasource-rendered': new ConcurrentExperience('datasource-rendered', datasourcePageSegmentLoadExperienceConfig)
11
+ };
12
+ export const startUfoExperience = ({
13
+ name,
14
+ metadata
15
+ }, id) => {
16
+ const experienceInstance = ufoExperiences[name].getInstance(id);
17
+ experienceInstance.start();
18
+ if (metadata) {
19
+ experienceInstance.addMetadata(metadata);
20
+ }
21
+ };
22
+ export const succeedUfoExperience = ({
23
+ name,
24
+ metadata
25
+ }, id) => {
26
+ const experienceInstance = ufoExperiences[name].getInstance(id);
27
+ experienceInstance.success({
28
+ metadata
29
+ });
30
+ };
31
+ export const failUfoExperience = ({
32
+ name,
33
+ metadata
34
+ }, id) => {
35
+ const experienceInstance = ufoExperiences[name].getInstance(id);
36
+ experienceInstance.failure({
37
+ metadata
38
+ });
39
+ };
40
+ export const addMetadataToExperience = ({
41
+ name,
42
+ metadata
43
+ }, id) => {
44
+ ufoExperiences[name].getInstance(id).addMetadata(metadata);
45
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,46 @@
1
+ import { useEffect } from 'react';
2
+ import { addMetadataToExperience, failUfoExperience, succeedUfoExperience } from './index';
3
+ /**
4
+ * Hook to mark DataRendered UFO experience as either Success or Failure
5
+ * 1. Success when
6
+ * * its rendered as a link
7
+ * * it returns empty results
8
+ * * the request is unauthorized
9
+ * 2. Fail when
10
+ * * request is rejected
11
+ *
12
+ * Note:
13
+ * * When the request is resolved as a datasource table, it will be marked success in the table component, every other success case is marked by this hook
14
+ */
15
+ export const useDataRenderedUfoExperience = ({
16
+ status,
17
+ experienceId,
18
+ itemCount,
19
+ canBeLink,
20
+ extensionKey
21
+ }) => {
22
+ useEffect(() => {
23
+ const isEmptyResult = status === 'resolved' && itemCount === 0;
24
+ const isLink = status === 'resolved' && (itemCount === 1 || canBeLink); // this will take care of count-mode/single-item smart-link rendering
25
+ const isUnauthorized = status === 'unauthorized';
26
+ const shouldSucceedUfoExperience = isEmptyResult || isLink || isUnauthorized;
27
+ const shouldFailUfoExperience = status === 'rejected';
28
+ if (extensionKey) {
29
+ addMetadataToExperience({
30
+ name: 'datasource-rendered',
31
+ metadata: {
32
+ extensionKey
33
+ }
34
+ }, experienceId);
35
+ }
36
+ if (shouldFailUfoExperience) {
37
+ failUfoExperience({
38
+ name: 'datasource-rendered'
39
+ }, experienceId);
40
+ } else if (shouldSucceedUfoExperience) {
41
+ succeedUfoExperience({
42
+ name: 'datasource-rendered'
43
+ }, experienceId);
44
+ }
45
+ }, [canBeLink, experienceId, extensionKey, itemCount, status]);
46
+ };
@@ -205,7 +205,7 @@ const analyticsContextAttributes = {
205
205
  };
206
206
  const analyticsContextData = {
207
207
  packageName: "@atlaskit/link-datasource",
208
- packageVersion: "1.1.7",
208
+ packageVersion: "1.2.1",
209
209
  source: 'datasourceConfigModal'
210
210
  };
211
211
  const contextData = {
@@ -1,9 +1,12 @@
1
1
  /** @jsx jsx */
2
2
  import { useCallback, useEffect, useRef } from 'react';
3
3
  import { jsx } from '@emotion/react';
4
+ import { v4 as uuidv4 } from 'uuid';
4
5
  import { withAnalyticsContext } from '@atlaskit/analytics-next';
5
6
  import { useDatasourceAnalyticsEvents } from '../../analytics';
6
7
  import { packageMetaData } from '../../analytics/constants';
8
+ import { startUfoExperience } from '../../analytics/ufoExperiences';
9
+ import { useDataRenderedUfoExperience } from '../../analytics/ufoExperiences/useDataRenderedUfoExperience';
7
10
  import { useDatasourceTableState } from '../../hooks/useDatasourceTableState';
8
11
  import { AccessRequired } from '../common/error-state/access-required';
9
12
  import { LoadingError } from '../common/error-state/loading-error';
@@ -37,6 +40,9 @@ const DatasourceTableViewWithoutAnalytics = ({
37
40
  const {
38
41
  fireEvent
39
42
  } = useDatasourceAnalyticsEvents();
43
+ const {
44
+ current: tableRenderInstanceId
45
+ } = useRef(uuidv4());
40
46
 
41
47
  /* Need this to make sure that the datasource in the editor gets updated new info if any edits are made in the modal
42
48
  But we don't want to call it on initial load. This screws up useDatasourceTableState's internal
@@ -54,6 +60,20 @@ const DatasourceTableViewWithoutAnalytics = ({
54
60
  onVisibleColumnKeysChange(defaultVisibleColumnKeys);
55
61
  }
56
62
  }, [visibleColumnKeys, defaultVisibleColumnKeys, onVisibleColumnKeysChange]);
63
+ useEffect(() => {
64
+ const shouldStartUfoExperience = datasourceId && parameters && visibleColumnKeys && status === 'loading';
65
+ if (shouldStartUfoExperience) {
66
+ startUfoExperience({
67
+ name: 'datasource-rendered'
68
+ }, tableRenderInstanceId);
69
+ }
70
+ }, [datasourceId, parameters, status, tableRenderInstanceId, visibleColumnKeys]);
71
+ useDataRenderedUfoExperience({
72
+ status,
73
+ experienceId: tableRenderInstanceId,
74
+ itemCount: responseItems.length,
75
+ extensionKey
76
+ });
57
77
  const forcedReset = useCallback(() => {
58
78
  fireEvent('ui.button.clicked.sync', {
59
79
  extensionKey,
@@ -91,7 +111,8 @@ const DatasourceTableViewWithoutAnalytics = ({
91
111
  columns: columns,
92
112
  visibleColumnKeys: visibleColumnKeys || defaultVisibleColumnKeys,
93
113
  onVisibleColumnKeysChange: onVisibleColumnKeysChange,
94
- scrollableContainerHeight: 590
114
+ scrollableContainerHeight: 590,
115
+ parentContainerRenderInstanceId: tableRenderInstanceId
95
116
  }) : jsx(EmptyState, {
96
117
  testId: "datasource-table-view-skeleton",
97
118
  isCompact: true,
@@ -12,6 +12,7 @@ import { monitorForElements } from '@atlaskit/pragmatic-drag-and-drop/adapter/el
12
12
  import { combine } from '@atlaskit/pragmatic-drag-and-drop/util/combine';
13
13
  import { N40 } from '@atlaskit/theme/colors';
14
14
  import Tooltip from '@atlaskit/tooltip';
15
+ import { succeedUfoExperience } from '../../analytics/ufoExperiences';
15
16
  import { ColumnPicker } from './column-picker';
16
17
  import { DragColumnPreview } from './drag-column-preview';
17
18
  import { DraggableTableHeading } from './draggable-table-heading';
@@ -123,7 +124,8 @@ export const IssueLikeDataTableView = ({
123
124
  onVisibleColumnKeysChange,
124
125
  status,
125
126
  hasNextPage,
126
- scrollableContainerHeight
127
+ scrollableContainerHeight,
128
+ parentContainerRenderInstanceId
127
129
  }) => {
128
130
  const tableId = useMemo(() => Symbol('unique-id'), []);
129
131
  const [lastRowElement, setLastRowElement] = useState(null);
@@ -134,6 +136,13 @@ export const IssueLikeDataTableView = ({
134
136
  useEffect(() => {
135
137
  setOrderedColumns(orderColumns([...columns], [...visibleColumnKeys]));
136
138
  }, [columns, visibleColumnKeys]);
139
+ useEffect(() => {
140
+ if (parentContainerRenderInstanceId && status === 'resolved') {
141
+ succeedUfoExperience({
142
+ name: 'datasource-rendered'
143
+ }, parentContainerRenderInstanceId);
144
+ }
145
+ }, [parentContainerRenderInstanceId, status]);
137
146
  const visibleSortedColumns = useMemo(() => visibleColumnKeys.map(visibleKey => orderedColumns.find(({
138
147
  key
139
148
  }) => visibleKey === key)).filter(Boolean), [orderedColumns, visibleColumnKeys]);
@@ -3,6 +3,7 @@ import _extends from "@babel/runtime/helpers/extends";
3
3
  import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
4
4
  import { css, jsx } from '@emotion/react';
5
5
  import { FormattedMessage, FormattedNumber, useIntl } from 'react-intl-next';
6
+ import { v4 as uuidv4 } from 'uuid';
6
7
  import { withAnalyticsContext } from '@atlaskit/analytics-next';
7
8
  import Button from '@atlaskit/button/standard-button';
8
9
  import Modal, { ModalBody, ModalFooter, ModalHeader, ModalTitle, ModalTransition } from '@atlaskit/modal-dialog';
@@ -10,6 +11,8 @@ import { B400, N0, N40, N800 } from '@atlaskit/theme/colors';
10
11
  import { EVENT_CHANNEL, useDatasourceAnalyticsEvents } from '../../../analytics';
11
12
  import { packageMetaData } from '../../../analytics/constants';
12
13
  import { DatasourceAction, DatasourceDisplay } from '../../../analytics/types';
14
+ import { startUfoExperience } from '../../../analytics/ufoExperiences';
15
+ import { useDataRenderedUfoExperience } from '../../../analytics/ufoExperiences/useDataRenderedUfoExperience';
13
16
  import { mapSearchMethod } from '../../../analytics/utils';
14
17
  import { useDatasourceTableState } from '../../../hooks/useDatasourceTableState';
15
18
  import { getAvailableJiraSites } from '../../../services/getAvailableJiraSites';
@@ -116,6 +119,9 @@ export const PlainJiraIssuesConfigModal = props => {
116
119
  const {
117
120
  fireEvent
118
121
  } = useDatasourceAnalyticsEvents();
122
+ const {
123
+ current: modalRenderInstanceId
124
+ } = useRef(uuidv4());
119
125
  const selectedJiraSite = useMemo(() => {
120
126
  if (cloudId) {
121
127
  // if the cloud id we're editing isn't in available sites then user is likely unauthorized for that site
@@ -129,14 +135,28 @@ export const PlainJiraIssuesConfigModal = props => {
129
135
  const buttonClickedAnalyticsPayload = useMemo(() => {
130
136
  return {
131
137
  extensionKey: extensionKey,
132
- destinationObjectTypes: destinationObjectTypes,
133
- actions: userInteractionActions.current
138
+ destinationObjectTypes: destinationObjectTypes
134
139
  };
135
140
  }, [destinationObjectTypes, extensionKey]);
136
141
  const resolvedWithNoResults = status === 'resolved' && !responseItems.length;
137
142
  const jqlUrl = selectedJiraSite && jql && `${selectedJiraSite.url}/issues/?jql=${encodeURI(jql)}`;
138
143
  const isInsertDisabled = !isParametersSet || status === 'rejected' || status === 'unauthorized' || status === 'loading' || resolvedWithNoResults;
139
144
  const shouldShowIssueCount = !!totalCount && totalCount !== 1 && currentViewMode === 'issue';
145
+ useEffect(() => {
146
+ const shouldStartUfoExperience = status === 'loading';
147
+ if (shouldStartUfoExperience) {
148
+ startUfoExperience({
149
+ name: 'datasource-rendered'
150
+ }, modalRenderInstanceId);
151
+ }
152
+ }, [modalRenderInstanceId, status]);
153
+ useDataRenderedUfoExperience({
154
+ status,
155
+ experienceId: modalRenderInstanceId,
156
+ itemCount: responseItems.length,
157
+ canBeLink: currentViewMode === 'count',
158
+ extensionKey
159
+ });
140
160
  useEffect(() => {
141
161
  fireEvent('screen.datasourceModalDialog.viewed', {});
142
162
  }, [fireEvent]);
@@ -203,6 +223,7 @@ export const PlainJiraIssuesConfigModal = props => {
203
223
  actionSubjectId: 'cancel',
204
224
  attributes: {
205
225
  ...buttonClickedAnalyticsPayload,
226
+ actions: Array.from(userInteractionActions.current),
206
227
  searchCount: searchCount.current
207
228
  }
208
229
  }).fire(EVENT_CHANNEL);
@@ -221,14 +242,16 @@ export const PlainJiraIssuesConfigModal = props => {
221
242
  // agreement with BE that we will use `key` for rendering smartlink
222
243
  return data === null || data === void 0 ? void 0 : (_data$key = data.key) === null || _data$key === void 0 ? void 0 : (_data$key$data = _data$key.data) === null || _data$key$data === void 0 ? void 0 : _data$key$data.url;
223
244
  }, [responseItems]);
224
- const onInsertPressed = useCallback((e, analyticEvent) => {
245
+ const onInsertPressed = useCallback((e, analyticsEvent) => {
246
+ var _insertButtonClickedE;
225
247
  if (!isParametersSet || !jql || !selectedJiraSite) {
226
248
  return;
227
249
  }
228
- const insertButtonClickedEvent = analyticEvent.update({
250
+ const insertButtonClickedEvent = analyticsEvent.update({
229
251
  actionSubjectId: 'insert',
230
252
  attributes: {
231
253
  ...buttonClickedAnalyticsPayload,
254
+ actions: Array.from(userInteractionActions.current),
232
255
  totalItemCount: totalCount || 0,
233
256
  displayedColumnCount: (visibleColumnKeys === null || visibleColumnKeys === void 0 ? void 0 : visibleColumnKeys.length) || 0,
234
257
  display: getDisplayValue(currentViewMode, totalCount || 0),
@@ -237,6 +260,7 @@ export const PlainJiraIssuesConfigModal = props => {
237
260
  },
238
261
  eventType: 'ui'
239
262
  });
263
+ const consumerEvent = (_insertButtonClickedE = insertButtonClickedEvent.clone()) !== null && _insertButtonClickedE !== void 0 ? _insertButtonClickedE : undefined;
240
264
  insertButtonClickedEvent.fire(EVENT_CHANNEL);
241
265
  const firstIssueUrl = retrieveUrlForSmartCardRender();
242
266
  if (currentViewMode === 'count') {
@@ -245,14 +269,14 @@ export const PlainJiraIssuesConfigModal = props => {
245
269
  attrs: {
246
270
  url: jqlUrl
247
271
  }
248
- });
272
+ }, consumerEvent);
249
273
  } else if (responseItems.length === 1 && firstIssueUrl) {
250
274
  onInsert({
251
275
  type: 'inlineCard',
252
276
  attrs: {
253
277
  url: firstIssueUrl
254
278
  }
255
- });
279
+ }, consumerEvent);
256
280
  } else {
257
281
  onInsert({
258
282
  type: 'blockCard',
@@ -275,7 +299,7 @@ export const PlainJiraIssuesConfigModal = props => {
275
299
  }]
276
300
  }
277
301
  }
278
- });
302
+ }, consumerEvent);
279
303
  }
280
304
  }, [isParametersSet, jql, selectedJiraSite, buttonClickedAnalyticsPayload, totalCount, visibleColumnKeys, currentViewMode, retrieveUrlForSmartCardRender, responseItems.length, onInsert, jqlUrl, datasourceId, cloudId]);
281
305
  const handleViewModeChange = selectedMode => {
@@ -302,8 +326,9 @@ export const PlainJiraIssuesConfigModal = props => {
302
326
  visibleColumnKeys: visibleColumnKeys || defaultVisibleColumnKeys,
303
327
  onNextPage: handleOnNextPage,
304
328
  onLoadDatasourceDetails: loadDatasourceDetails,
305
- onVisibleColumnKeysChange: handleVisibleColumnKeysChange
306
- })), [columns, defaultVisibleColumnKeys, hasNextPage, handleVisibleColumnKeysChange, loadDatasourceDetails, handleOnNextPage, responseItems, status, visibleColumnKeys]);
329
+ onVisibleColumnKeysChange: handleVisibleColumnKeysChange,
330
+ parentContainerRenderInstanceId: modalRenderInstanceId
331
+ })), [columns, defaultVisibleColumnKeys, handleOnNextPage, handleVisibleColumnKeysChange, hasNextPage, loadDatasourceDetails, modalRenderInstanceId, responseItems, status, visibleColumnKeys]);
307
332
  const renderCountModeContent = useCallback(() => {
308
333
  const url = selectedJiraSite === null || selectedJiraSite === void 0 ? void 0 : selectedJiraSite.url;
309
334
  if (status === 'unauthorized') {
@@ -1,5 +1,5 @@
1
1
  export var EVENT_CHANNEL = 'media';
2
2
  export var packageMetaData = {
3
3
  packageName: "@atlaskit/link-datasource",
4
- packageVersion: "1.1.7"
4
+ packageVersion: "1.2.1"
5
5
  };
@@ -0,0 +1,41 @@
1
+ import { ConcurrentExperience, ExperiencePerformanceTypes, ExperienceTypes } from '@atlaskit/ufo';
2
+ var datasourcePageSegmentLoadExperienceConfig = {
3
+ platform: {
4
+ component: 'datasource'
5
+ },
6
+ type: ExperienceTypes.Load,
7
+ performanceType: ExperiencePerformanceTypes.PageSegmentLoad
8
+ };
9
+ var ufoExperiences = {
10
+ 'datasource-rendered': new ConcurrentExperience('datasource-rendered', datasourcePageSegmentLoadExperienceConfig)
11
+ };
12
+ export var startUfoExperience = function startUfoExperience(_ref, id) {
13
+ var name = _ref.name,
14
+ metadata = _ref.metadata;
15
+ var experienceInstance = ufoExperiences[name].getInstance(id);
16
+ experienceInstance.start();
17
+ if (metadata) {
18
+ experienceInstance.addMetadata(metadata);
19
+ }
20
+ };
21
+ export var succeedUfoExperience = function succeedUfoExperience(_ref2, id) {
22
+ var name = _ref2.name,
23
+ metadata = _ref2.metadata;
24
+ var experienceInstance = ufoExperiences[name].getInstance(id);
25
+ experienceInstance.success({
26
+ metadata: metadata
27
+ });
28
+ };
29
+ export var failUfoExperience = function failUfoExperience(_ref3, id) {
30
+ var name = _ref3.name,
31
+ metadata = _ref3.metadata;
32
+ var experienceInstance = ufoExperiences[name].getInstance(id);
33
+ experienceInstance.failure({
34
+ metadata: metadata
35
+ });
36
+ };
37
+ export var addMetadataToExperience = function addMetadataToExperience(_ref4, id) {
38
+ var name = _ref4.name,
39
+ metadata = _ref4.metadata;
40
+ ufoExperiences[name].getInstance(id).addMetadata(metadata);
41
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,45 @@
1
+ import { useEffect } from 'react';
2
+ import { addMetadataToExperience, failUfoExperience, succeedUfoExperience } from './index';
3
+ /**
4
+ * Hook to mark DataRendered UFO experience as either Success or Failure
5
+ * 1. Success when
6
+ * * its rendered as a link
7
+ * * it returns empty results
8
+ * * the request is unauthorized
9
+ * 2. Fail when
10
+ * * request is rejected
11
+ *
12
+ * Note:
13
+ * * When the request is resolved as a datasource table, it will be marked success in the table component, every other success case is marked by this hook
14
+ */
15
+ export var useDataRenderedUfoExperience = function useDataRenderedUfoExperience(_ref) {
16
+ var status = _ref.status,
17
+ experienceId = _ref.experienceId,
18
+ itemCount = _ref.itemCount,
19
+ canBeLink = _ref.canBeLink,
20
+ extensionKey = _ref.extensionKey;
21
+ useEffect(function () {
22
+ var isEmptyResult = status === 'resolved' && itemCount === 0;
23
+ var isLink = status === 'resolved' && (itemCount === 1 || canBeLink); // this will take care of count-mode/single-item smart-link rendering
24
+ var isUnauthorized = status === 'unauthorized';
25
+ var shouldSucceedUfoExperience = isEmptyResult || isLink || isUnauthorized;
26
+ var shouldFailUfoExperience = status === 'rejected';
27
+ if (extensionKey) {
28
+ addMetadataToExperience({
29
+ name: 'datasource-rendered',
30
+ metadata: {
31
+ extensionKey: extensionKey
32
+ }
33
+ }, experienceId);
34
+ }
35
+ if (shouldFailUfoExperience) {
36
+ failUfoExperience({
37
+ name: 'datasource-rendered'
38
+ }, experienceId);
39
+ } else if (shouldSucceedUfoExperience) {
40
+ succeedUfoExperience({
41
+ name: 'datasource-rendered'
42
+ }, experienceId);
43
+ }
44
+ }, [canBeLink, experienceId, extensionKey, itemCount, status]);
45
+ };
@@ -222,7 +222,7 @@ var analyticsContextAttributes = {
222
222
  };
223
223
  var analyticsContextData = {
224
224
  packageName: "@atlaskit/link-datasource",
225
- packageVersion: "1.1.7",
225
+ packageVersion: "1.2.1",
226
226
  source: 'datasourceConfigModal'
227
227
  };
228
228
  var contextData = _objectSpread(_objectSpread({}, analyticsContextData), {}, {
@@ -1,9 +1,12 @@
1
1
  /** @jsx jsx */
2
2
  import { useCallback, useEffect, useRef } from 'react';
3
3
  import { jsx } from '@emotion/react';
4
+ import { v4 as uuidv4 } from 'uuid';
4
5
  import { withAnalyticsContext } from '@atlaskit/analytics-next';
5
6
  import { useDatasourceAnalyticsEvents } from '../../analytics';
6
7
  import { packageMetaData } from '../../analytics/constants';
8
+ import { startUfoExperience } from '../../analytics/ufoExperiences';
9
+ import { useDataRenderedUfoExperience } from '../../analytics/ufoExperiences/useDataRenderedUfoExperience';
7
10
  import { useDatasourceTableState } from '../../hooks/useDatasourceTableState';
8
11
  import { AccessRequired } from '../common/error-state/access-required';
9
12
  import { LoadingError } from '../common/error-state/loading-error';
@@ -35,6 +38,8 @@ var DatasourceTableViewWithoutAnalytics = function DatasourceTableViewWithoutAna
35
38
  destinationObjectTypes = _useDatasourceTableSt.destinationObjectTypes;
36
39
  var _useDatasourceAnalyti = useDatasourceAnalyticsEvents(),
37
40
  fireEvent = _useDatasourceAnalyti.fireEvent;
41
+ var _useRef = useRef(uuidv4()),
42
+ tableRenderInstanceId = _useRef.current;
38
43
 
39
44
  /* Need this to make sure that the datasource in the editor gets updated new info if any edits are made in the modal
40
45
  But we don't want to call it on initial load. This screws up useDatasourceTableState's internal
@@ -52,6 +57,20 @@ var DatasourceTableViewWithoutAnalytics = function DatasourceTableViewWithoutAna
52
57
  onVisibleColumnKeysChange(defaultVisibleColumnKeys);
53
58
  }
54
59
  }, [visibleColumnKeys, defaultVisibleColumnKeys, onVisibleColumnKeysChange]);
60
+ useEffect(function () {
61
+ var shouldStartUfoExperience = datasourceId && parameters && visibleColumnKeys && status === 'loading';
62
+ if (shouldStartUfoExperience) {
63
+ startUfoExperience({
64
+ name: 'datasource-rendered'
65
+ }, tableRenderInstanceId);
66
+ }
67
+ }, [datasourceId, parameters, status, tableRenderInstanceId, visibleColumnKeys]);
68
+ useDataRenderedUfoExperience({
69
+ status: status,
70
+ experienceId: tableRenderInstanceId,
71
+ itemCount: responseItems.length,
72
+ extensionKey: extensionKey
73
+ });
55
74
  var forcedReset = useCallback(function () {
56
75
  fireEvent('ui.button.clicked.sync', {
57
76
  extensionKey: extensionKey,
@@ -89,7 +108,8 @@ var DatasourceTableViewWithoutAnalytics = function DatasourceTableViewWithoutAna
89
108
  columns: columns,
90
109
  visibleColumnKeys: visibleColumnKeys || defaultVisibleColumnKeys,
91
110
  onVisibleColumnKeysChange: onVisibleColumnKeysChange,
92
- scrollableContainerHeight: 590
111
+ scrollableContainerHeight: 590,
112
+ parentContainerRenderInstanceId: tableRenderInstanceId
93
113
  }) : jsx(EmptyState, {
94
114
  testId: "datasource-table-view-skeleton",
95
115
  isCompact: true,
@@ -21,6 +21,7 @@ import { monitorForElements } from '@atlaskit/pragmatic-drag-and-drop/adapter/el
21
21
  import { combine } from '@atlaskit/pragmatic-drag-and-drop/util/combine';
22
22
  import { N40 } from '@atlaskit/theme/colors';
23
23
  import Tooltip from '@atlaskit/tooltip';
24
+ import { succeedUfoExperience } from '../../analytics/ufoExperiences';
24
25
  import { ColumnPicker } from './column-picker';
25
26
  import { DragColumnPreview } from './drag-column-preview';
26
27
  import { DraggableTableHeading } from './draggable-table-heading';
@@ -115,7 +116,8 @@ export var IssueLikeDataTableView = function IssueLikeDataTableView(_ref2) {
115
116
  onVisibleColumnKeysChange = _ref2.onVisibleColumnKeysChange,
116
117
  status = _ref2.status,
117
118
  hasNextPage = _ref2.hasNextPage,
118
- scrollableContainerHeight = _ref2.scrollableContainerHeight;
119
+ scrollableContainerHeight = _ref2.scrollableContainerHeight,
120
+ parentContainerRenderInstanceId = _ref2.parentContainerRenderInstanceId;
119
121
  var tableId = useMemo(function () {
120
122
  return Symbol('unique-id');
121
123
  }, []);
@@ -138,6 +140,13 @@ export var IssueLikeDataTableView = function IssueLikeDataTableView(_ref2) {
138
140
  useEffect(function () {
139
141
  setOrderedColumns(orderColumns(_toConsumableArray(columns), _toConsumableArray(visibleColumnKeys)));
140
142
  }, [columns, visibleColumnKeys]);
143
+ useEffect(function () {
144
+ if (parentContainerRenderInstanceId && status === 'resolved') {
145
+ succeedUfoExperience({
146
+ name: 'datasource-rendered'
147
+ }, parentContainerRenderInstanceId);
148
+ }
149
+ }, [parentContainerRenderInstanceId, status]);
141
150
  var visibleSortedColumns = useMemo(function () {
142
151
  return visibleColumnKeys.map(function (visibleKey) {
143
152
  return orderedColumns.find(function (_ref3) {
@@ -9,6 +9,7 @@ import _regeneratorRuntime from "@babel/runtime/regenerator";
9
9
  import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
10
10
  import { css, jsx } from '@emotion/react';
11
11
  import { FormattedMessage, FormattedNumber, useIntl } from 'react-intl-next';
12
+ import { v4 as uuidv4 } from 'uuid';
12
13
  import { withAnalyticsContext } from '@atlaskit/analytics-next';
13
14
  import Button from '@atlaskit/button/standard-button';
14
15
  import Modal, { ModalBody, ModalFooter, ModalHeader, ModalTitle, ModalTransition } from '@atlaskit/modal-dialog';
@@ -16,6 +17,8 @@ import { B400, N0, N40, N800 } from '@atlaskit/theme/colors';
16
17
  import { EVENT_CHANNEL, useDatasourceAnalyticsEvents } from '../../../analytics';
17
18
  import { packageMetaData } from '../../../analytics/constants';
18
19
  import { DatasourceAction, DatasourceDisplay } from '../../../analytics/types';
20
+ import { startUfoExperience } from '../../../analytics/ufoExperiences';
21
+ import { useDataRenderedUfoExperience } from '../../../analytics/ufoExperiences/useDataRenderedUfoExperience';
19
22
  import { mapSearchMethod } from '../../../analytics/utils';
20
23
  import { useDatasourceTableState } from '../../../hooks/useDatasourceTableState';
21
24
  import { getAvailableJiraSites } from '../../../services/getAvailableJiraSites';
@@ -135,6 +138,8 @@ export var PlainJiraIssuesConfigModal = function PlainJiraIssuesConfigModal(prop
135
138
  formatMessage = _useIntl.formatMessage;
136
139
  var _useDatasourceAnalyti = useDatasourceAnalyticsEvents(),
137
140
  fireEvent = _useDatasourceAnalyti.fireEvent;
141
+ var _useRef = useRef(uuidv4()),
142
+ modalRenderInstanceId = _useRef.current;
138
143
  var selectedJiraSite = useMemo(function () {
139
144
  if (cloudId) {
140
145
  // if the cloud id we're editing isn't in available sites then user is likely unauthorized for that site
@@ -152,14 +157,28 @@ export var PlainJiraIssuesConfigModal = function PlainJiraIssuesConfigModal(prop
152
157
  var buttonClickedAnalyticsPayload = useMemo(function () {
153
158
  return {
154
159
  extensionKey: extensionKey,
155
- destinationObjectTypes: destinationObjectTypes,
156
- actions: userInteractionActions.current
160
+ destinationObjectTypes: destinationObjectTypes
157
161
  };
158
162
  }, [destinationObjectTypes, extensionKey]);
159
163
  var resolvedWithNoResults = status === 'resolved' && !responseItems.length;
160
164
  var jqlUrl = selectedJiraSite && jql && "".concat(selectedJiraSite.url, "/issues/?jql=").concat(encodeURI(jql));
161
165
  var isInsertDisabled = !isParametersSet || status === 'rejected' || status === 'unauthorized' || status === 'loading' || resolvedWithNoResults;
162
166
  var shouldShowIssueCount = !!totalCount && totalCount !== 1 && currentViewMode === 'issue';
167
+ useEffect(function () {
168
+ var shouldStartUfoExperience = status === 'loading';
169
+ if (shouldStartUfoExperience) {
170
+ startUfoExperience({
171
+ name: 'datasource-rendered'
172
+ }, modalRenderInstanceId);
173
+ }
174
+ }, [modalRenderInstanceId, status]);
175
+ useDataRenderedUfoExperience({
176
+ status: status,
177
+ experienceId: modalRenderInstanceId,
178
+ itemCount: responseItems.length,
179
+ canBeLink: currentViewMode === 'count',
180
+ extensionKey: extensionKey
181
+ });
163
182
  useEffect(function () {
164
183
  fireEvent('screen.datasourceModalDialog.viewed', {});
165
184
  }, [fireEvent]);
@@ -242,6 +261,7 @@ export var PlainJiraIssuesConfigModal = function PlainJiraIssuesConfigModal(prop
242
261
  eventType: 'ui',
243
262
  actionSubjectId: 'cancel',
244
263
  attributes: _objectSpread(_objectSpread({}, buttonClickedAnalyticsPayload), {}, {
264
+ actions: Array.from(userInteractionActions.current),
245
265
  searchCount: searchCount.current
246
266
  })
247
267
  }).fire(EVENT_CHANNEL);
@@ -261,13 +281,15 @@ export var PlainJiraIssuesConfigModal = function PlainJiraIssuesConfigModal(prop
261
281
  // agreement with BE that we will use `key` for rendering smartlink
262
282
  return data === null || data === void 0 ? void 0 : (_data$key = data.key) === null || _data$key === void 0 ? void 0 : (_data$key$data = _data$key.data) === null || _data$key$data === void 0 ? void 0 : _data$key$data.url;
263
283
  }, [responseItems]);
264
- var onInsertPressed = useCallback(function (e, analyticEvent) {
284
+ var onInsertPressed = useCallback(function (e, analyticsEvent) {
285
+ var _insertButtonClickedE;
265
286
  if (!isParametersSet || !jql || !selectedJiraSite) {
266
287
  return;
267
288
  }
268
- var insertButtonClickedEvent = analyticEvent.update({
289
+ var insertButtonClickedEvent = analyticsEvent.update({
269
290
  actionSubjectId: 'insert',
270
291
  attributes: _objectSpread(_objectSpread({}, buttonClickedAnalyticsPayload), {}, {
292
+ actions: Array.from(userInteractionActions.current),
271
293
  totalItemCount: totalCount || 0,
272
294
  displayedColumnCount: (visibleColumnKeys === null || visibleColumnKeys === void 0 ? void 0 : visibleColumnKeys.length) || 0,
273
295
  display: getDisplayValue(currentViewMode, totalCount || 0),
@@ -276,6 +298,7 @@ export var PlainJiraIssuesConfigModal = function PlainJiraIssuesConfigModal(prop
276
298
  }),
277
299
  eventType: 'ui'
278
300
  });
301
+ var consumerEvent = (_insertButtonClickedE = insertButtonClickedEvent.clone()) !== null && _insertButtonClickedE !== void 0 ? _insertButtonClickedE : undefined;
279
302
  insertButtonClickedEvent.fire(EVENT_CHANNEL);
280
303
  var firstIssueUrl = retrieveUrlForSmartCardRender();
281
304
  if (currentViewMode === 'count') {
@@ -284,14 +307,14 @@ export var PlainJiraIssuesConfigModal = function PlainJiraIssuesConfigModal(prop
284
307
  attrs: {
285
308
  url: jqlUrl
286
309
  }
287
- });
310
+ }, consumerEvent);
288
311
  } else if (responseItems.length === 1 && firstIssueUrl) {
289
312
  onInsert({
290
313
  type: 'inlineCard',
291
314
  attrs: {
292
315
  url: firstIssueUrl
293
316
  }
294
- });
317
+ }, consumerEvent);
295
318
  } else {
296
319
  onInsert({
297
320
  type: 'blockCard',
@@ -316,7 +339,7 @@ export var PlainJiraIssuesConfigModal = function PlainJiraIssuesConfigModal(prop
316
339
  }]
317
340
  }
318
341
  }
319
- });
342
+ }, consumerEvent);
320
343
  }
321
344
  }, [isParametersSet, jql, selectedJiraSite, buttonClickedAnalyticsPayload, totalCount, visibleColumnKeys, currentViewMode, retrieveUrlForSmartCardRender, responseItems.length, onInsert, jqlUrl, datasourceId, cloudId]);
322
345
  var handleViewModeChange = function handleViewModeChange(selectedMode) {
@@ -345,9 +368,10 @@ export var PlainJiraIssuesConfigModal = function PlainJiraIssuesConfigModal(prop
345
368
  visibleColumnKeys: visibleColumnKeys || defaultVisibleColumnKeys,
346
369
  onNextPage: handleOnNextPage,
347
370
  onLoadDatasourceDetails: loadDatasourceDetails,
348
- onVisibleColumnKeysChange: handleVisibleColumnKeysChange
371
+ onVisibleColumnKeysChange: handleVisibleColumnKeysChange,
372
+ parentContainerRenderInstanceId: modalRenderInstanceId
349
373
  }));
350
- }, [columns, defaultVisibleColumnKeys, hasNextPage, handleVisibleColumnKeysChange, loadDatasourceDetails, handleOnNextPage, responseItems, status, visibleColumnKeys]);
374
+ }, [columns, defaultVisibleColumnKeys, handleOnNextPage, handleVisibleColumnKeysChange, hasNextPage, loadDatasourceDetails, modalRenderInstanceId, responseItems, status, visibleColumnKeys]);
351
375
  var renderCountModeContent = useCallback(function () {
352
376
  var url = selectedJiraSite === null || selectedJiraSite === void 0 ? void 0 : selectedJiraSite.url;
353
377
  if (status === 'unauthorized') {
@@ -0,0 +1,5 @@
1
+ import type { UfoExperience } from './types';
2
+ export declare const startUfoExperience: ({ name, metadata }: UfoExperience, id: string) => void;
3
+ export declare const succeedUfoExperience: ({ name, metadata }: UfoExperience, id: string) => void;
4
+ export declare const failUfoExperience: ({ name, metadata }: UfoExperience, id: string) => void;
5
+ export declare const addMetadataToExperience: ({ name, metadata }: UfoExperience, id: string) => void;
@@ -0,0 +1,8 @@
1
+ interface DatasourceRendered {
2
+ name: 'datasource-rendered';
3
+ metadata?: {
4
+ extensionKey?: string;
5
+ };
6
+ }
7
+ export type UfoExperience = DatasourceRendered;
8
+ export {};
@@ -0,0 +1,22 @@
1
+ import { DatasourceTableStatusType } from '@atlaskit/linking-types';
2
+ interface DataRenderedUfoExperienceProps {
3
+ status: DatasourceTableStatusType;
4
+ experienceId: string;
5
+ itemCount: number;
6
+ canBeLink?: boolean;
7
+ extensionKey?: string | null;
8
+ }
9
+ /**
10
+ * Hook to mark DataRendered UFO experience as either Success or Failure
11
+ * 1. Success when
12
+ * * its rendered as a link
13
+ * * it returns empty results
14
+ * * the request is unauthorized
15
+ * 2. Fail when
16
+ * * request is rejected
17
+ *
18
+ * Note:
19
+ * * When the request is resolved as a datasource table, it will be marked success in the table component, every other success case is marked by this hook
20
+ */
21
+ export declare const useDataRenderedUfoExperience: ({ status, experienceId, itemCount, canBeLink, extensionKey, }: DataRenderedUfoExperienceProps) => void;
22
+ export {};
@@ -12,5 +12,5 @@ export interface RowCellType {
12
12
  content?: React.ReactNode | string;
13
13
  maxWidth?: number;
14
14
  }
15
- export declare const IssueLikeDataTableView: ({ testId, onNextPage, onLoadDatasourceDetails, items, columns, renderItem, visibleColumnKeys, onVisibleColumnKeysChange, status, hasNextPage, scrollableContainerHeight, }: IssueLikeDataTableViewProps) => jsx.JSX.Element;
15
+ export declare const IssueLikeDataTableView: ({ testId, onNextPage, onLoadDatasourceDetails, items, columns, renderItem, visibleColumnKeys, onVisibleColumnKeysChange, status, hasNextPage, scrollableContainerHeight, parentContainerRenderInstanceId, }: IssueLikeDataTableViewProps) => jsx.JSX.Element;
16
16
  export declare const EmptyState: ({ isCompact, isLoading, testId }: import("./empty-state").Props) => jsx.JSX.Element;
@@ -4,6 +4,10 @@ import { NextPageType } from '../../hooks/useDatasourceTableState';
4
4
  export type TableViewPropsRenderType = (item: DatasourceType) => React.ReactNode;
5
5
  export interface IssueLikeDataTableViewProps {
6
6
  testId?: string;
7
+ /**
8
+ * Unique ID to indicate parent component instance to be used for UFO experiences
9
+ */
10
+ parentContainerRenderInstanceId?: string;
7
11
  /**
8
12
  * All available columns/properties.
9
13
  * Consumer should not reorder these columns to align with `visibleColumnKeys`.
@@ -1,3 +1,4 @@
1
+ import type { UIAnalyticsEvent } from '@atlaskit/analytics-next';
1
2
  import { DatasourceAdf, InlineCardAdf } from '@atlaskit/linking-common/types';
2
3
  type XOR<T1, T2> = (T1 & {
3
4
  [k in Exclude<keyof T2, keyof T1>]?: never;
@@ -37,6 +38,6 @@ export interface JiraIssuesConfigModalProps {
37
38
  visibleColumnKeys?: string[];
38
39
  parameters?: JiraIssueDatasourceParameters;
39
40
  onCancel: () => void;
40
- onInsert: (adf: InlineCardAdf | JiraIssuesDatasourceAdf) => void;
41
+ onInsert: (adf: InlineCardAdf | JiraIssuesDatasourceAdf, analyticsEvent?: UIAnalyticsEvent) => void;
41
42
  }
42
43
  export {};
@@ -0,0 +1,5 @@
1
+ import type { UfoExperience } from './types';
2
+ export declare const startUfoExperience: ({ name, metadata }: UfoExperience, id: string) => void;
3
+ export declare const succeedUfoExperience: ({ name, metadata }: UfoExperience, id: string) => void;
4
+ export declare const failUfoExperience: ({ name, metadata }: UfoExperience, id: string) => void;
5
+ export declare const addMetadataToExperience: ({ name, metadata }: UfoExperience, id: string) => void;
@@ -0,0 +1,8 @@
1
+ interface DatasourceRendered {
2
+ name: 'datasource-rendered';
3
+ metadata?: {
4
+ extensionKey?: string;
5
+ };
6
+ }
7
+ export type UfoExperience = DatasourceRendered;
8
+ export {};
@@ -0,0 +1,22 @@
1
+ import { DatasourceTableStatusType } from '@atlaskit/linking-types';
2
+ interface DataRenderedUfoExperienceProps {
3
+ status: DatasourceTableStatusType;
4
+ experienceId: string;
5
+ itemCount: number;
6
+ canBeLink?: boolean;
7
+ extensionKey?: string | null;
8
+ }
9
+ /**
10
+ * Hook to mark DataRendered UFO experience as either Success or Failure
11
+ * 1. Success when
12
+ * * its rendered as a link
13
+ * * it returns empty results
14
+ * * the request is unauthorized
15
+ * 2. Fail when
16
+ * * request is rejected
17
+ *
18
+ * Note:
19
+ * * When the request is resolved as a datasource table, it will be marked success in the table component, every other success case is marked by this hook
20
+ */
21
+ export declare const useDataRenderedUfoExperience: ({ status, experienceId, itemCount, canBeLink, extensionKey, }: DataRenderedUfoExperienceProps) => void;
22
+ export {};
@@ -12,5 +12,5 @@ export interface RowCellType {
12
12
  content?: React.ReactNode | string;
13
13
  maxWidth?: number;
14
14
  }
15
- export declare const IssueLikeDataTableView: ({ testId, onNextPage, onLoadDatasourceDetails, items, columns, renderItem, visibleColumnKeys, onVisibleColumnKeysChange, status, hasNextPage, scrollableContainerHeight, }: IssueLikeDataTableViewProps) => jsx.JSX.Element;
15
+ export declare const IssueLikeDataTableView: ({ testId, onNextPage, onLoadDatasourceDetails, items, columns, renderItem, visibleColumnKeys, onVisibleColumnKeysChange, status, hasNextPage, scrollableContainerHeight, parentContainerRenderInstanceId, }: IssueLikeDataTableViewProps) => jsx.JSX.Element;
16
16
  export declare const EmptyState: ({ isCompact, isLoading, testId }: import("./empty-state").Props) => jsx.JSX.Element;
@@ -4,6 +4,10 @@ import { NextPageType } from '../../hooks/useDatasourceTableState';
4
4
  export type TableViewPropsRenderType = (item: DatasourceType) => React.ReactNode;
5
5
  export interface IssueLikeDataTableViewProps {
6
6
  testId?: string;
7
+ /**
8
+ * Unique ID to indicate parent component instance to be used for UFO experiences
9
+ */
10
+ parentContainerRenderInstanceId?: string;
7
11
  /**
8
12
  * All available columns/properties.
9
13
  * Consumer should not reorder these columns to align with `visibleColumnKeys`.
@@ -1,3 +1,4 @@
1
+ import type { UIAnalyticsEvent } from '@atlaskit/analytics-next';
1
2
  import { DatasourceAdf, InlineCardAdf } from '@atlaskit/linking-common/types';
2
3
  type XOR<T1, T2> = (T1 & {
3
4
  [k in Exclude<keyof T2, keyof T1>]?: never;
@@ -37,6 +38,6 @@ export interface JiraIssuesConfigModalProps {
37
38
  visibleColumnKeys?: string[];
38
39
  parameters?: JiraIssueDatasourceParameters;
39
40
  onCancel: () => void;
40
- onInsert: (adf: InlineCardAdf | JiraIssuesDatasourceAdf) => void;
41
+ onInsert: (adf: InlineCardAdf | JiraIssuesDatasourceAdf, analyticsEvent?: UIAnalyticsEvent) => void;
41
42
  }
42
43
  export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlaskit/link-datasource",
3
- "version": "1.1.7",
3
+ "version": "1.2.1",
4
4
  "description": "UI Components to support linking platform dataset feature",
5
5
  "publishConfig": {
6
6
  "registry": "https://registry.npmjs.org/"
@@ -52,7 +52,7 @@
52
52
  "@atlaskit/pragmatic-drag-and-drop-hitbox": "^0.11.0",
53
53
  "@atlaskit/pragmatic-drag-and-drop-react-beautiful-dnd-autoscroll": "^0.6.0",
54
54
  "@atlaskit/pragmatic-drag-and-drop-react-indicator": "^0.16.0",
55
- "@atlaskit/select": "^16.6.0",
55
+ "@atlaskit/select": "^16.7.0",
56
56
  "@atlaskit/smart-card": "^26.26.0",
57
57
  "@atlaskit/spinner": "^15.5.0",
58
58
  "@atlaskit/tag": "^11.6.0",
@@ -60,13 +60,15 @@
60
60
  "@atlaskit/theme": "^12.6.0",
61
61
  "@atlaskit/tokens": "^1.22.0",
62
62
  "@atlaskit/tooltip": "^17.8.0",
63
+ "@atlaskit/ufo": "^0.2.4",
63
64
  "@atlassianlabs/jql-editor": "^2.0.1",
64
65
  "@babel/runtime": "^7.0.0",
65
66
  "@emotion/react": "^11.7.1",
66
67
  "@emotion/styled": "^11.0.0",
67
68
  "debounce-promise": "^3.1.2",
68
69
  "react-dom": "^16.8.0",
69
- "tiny-invariant": "^1.2.0"
70
+ "tiny-invariant": "^1.2.0",
71
+ "uuid": "^3.1.0"
70
72
  },
71
73
  "peerDependencies": {
72
74
  "react": "^16.8.0",
@@ -88,7 +90,6 @@
88
90
  "jest-fetch-mock": "^3.0.3",
89
91
  "json-ld-types": "3.9.1",
90
92
  "typescript": "~4.9.5",
91
- "uuid": "^3.1.0",
92
93
  "wait-for-expect": "^1.2.0"
93
94
  },
94
95
  "techstack": {
package/report.api.md CHANGED
@@ -21,6 +21,7 @@ import { DatasourceAdf } from '@atlaskit/linking-common/types';
21
21
  import { DatasourceAdfTableView } from '@atlaskit/linking-common/types';
22
22
  import { DatasourceAdfView } from '@atlaskit/linking-common/types';
23
23
  import { InlineCardAdf } from '@atlaskit/linking-common/types';
24
+ import type { UIAnalyticsEvent } from '@atlaskit/analytics-next';
24
25
 
25
26
  // @public (undocumented)
26
27
  export const ASSETS_LIST_OF_LINKS_DATASOURCE_ID =
@@ -126,7 +127,10 @@ interface JiraIssuesConfigModalProps {
126
127
  // (undocumented)
127
128
  onCancel: () => void;
128
129
  // (undocumented)
129
- onInsert: (adf: InlineCardAdf | JiraIssuesDatasourceAdf) => void;
130
+ onInsert: (
131
+ adf: InlineCardAdf | JiraIssuesDatasourceAdf,
132
+ analyticsEvent?: UIAnalyticsEvent,
133
+ ) => void;
130
134
  // (undocumented)
131
135
  parameters?: JiraIssueDatasourceParameters;
132
136
  // (undocumented)
@@ -10,6 +10,7 @@ import { DatasourceAdf } from '@atlaskit/linking-common/types';
10
10
  import { DatasourceAdfTableView } from '@atlaskit/linking-common/types';
11
11
  import { DatasourceAdfView } from '@atlaskit/linking-common/types';
12
12
  import { InlineCardAdf } from '@atlaskit/linking-common/types';
13
+ import type { UIAnalyticsEvent } from '@atlaskit/analytics-next';
13
14
 
14
15
  // @public (undocumented)
15
16
  export const ASSETS_LIST_OF_LINKS_DATASOURCE_ID = "361d618a-3c04-40ad-9b27-3c8ea6927020";
@@ -104,7 +105,7 @@ interface JiraIssuesConfigModalProps {
104
105
  // (undocumented)
105
106
  onCancel: () => void;
106
107
  // (undocumented)
107
- onInsert: (adf: InlineCardAdf | JiraIssuesDatasourceAdf) => void;
108
+ onInsert: (adf: InlineCardAdf | JiraIssuesDatasourceAdf, analyticsEvent?: UIAnalyticsEvent) => void;
108
109
  // (undocumented)
109
110
  parameters?: JiraIssueDatasourceParameters;
110
111
  // (undocumented)