@atlaskit/link-datasource 1.25.0 → 1.25.2

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 (35) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/dist/cjs/ui/assets-modal/modal/index.js +11 -15
  3. package/dist/cjs/ui/assets-modal/modal/messages.js +0 -5
  4. package/dist/cjs/ui/common/modal/cancel-button/index.js +31 -0
  5. package/dist/cjs/ui/common/modal/cancel-button/messages.js +14 -0
  6. package/dist/cjs/ui/confluence-search-modal/modal/index.js +95 -13
  7. package/dist/cjs/ui/jira-issues-modal/modal/index.js +12 -15
  8. package/dist/cjs/ui/jira-issues-modal/modal/messages.js +0 -5
  9. package/dist/es2019/ui/assets-modal/modal/index.js +12 -16
  10. package/dist/es2019/ui/assets-modal/modal/messages.js +0 -5
  11. package/dist/es2019/ui/common/modal/cancel-button/index.js +25 -0
  12. package/dist/es2019/ui/common/modal/cancel-button/messages.js +8 -0
  13. package/dist/es2019/ui/confluence-search-modal/modal/index.js +96 -12
  14. package/dist/es2019/ui/jira-issues-modal/modal/index.js +17 -22
  15. package/dist/es2019/ui/jira-issues-modal/modal/messages.js +0 -5
  16. package/dist/esm/ui/assets-modal/modal/index.js +11 -15
  17. package/dist/esm/ui/assets-modal/modal/messages.js +0 -5
  18. package/dist/esm/ui/common/modal/cancel-button/index.js +23 -0
  19. package/dist/esm/ui/common/modal/cancel-button/messages.js +8 -0
  20. package/dist/esm/ui/confluence-search-modal/modal/index.js +94 -12
  21. package/dist/esm/ui/jira-issues-modal/modal/index.js +12 -15
  22. package/dist/esm/ui/jira-issues-modal/modal/messages.js +0 -5
  23. package/dist/types/analytics/generated/analytics.types.d.ts +1 -1
  24. package/dist/types/ui/assets-modal/modal/messages.d.ts +0 -5
  25. package/dist/types/ui/common/modal/cancel-button/index.d.ts +8 -0
  26. package/dist/types/ui/common/modal/cancel-button/messages.d.ts +7 -0
  27. package/dist/types/ui/confluence-search-modal/modal/index.d.ts +5 -1
  28. package/dist/types/ui/jira-issues-modal/modal/messages.d.ts +0 -5
  29. package/dist/types-ts4.5/analytics/generated/analytics.types.d.ts +1 -1
  30. package/dist/types-ts4.5/ui/assets-modal/modal/messages.d.ts +0 -5
  31. package/dist/types-ts4.5/ui/common/modal/cancel-button/index.d.ts +8 -0
  32. package/dist/types-ts4.5/ui/common/modal/cancel-button/messages.d.ts +7 -0
  33. package/dist/types-ts4.5/ui/confluence-search-modal/modal/index.d.ts +5 -1
  34. package/dist/types-ts4.5/ui/jira-issues-modal/modal/messages.d.ts +0 -5
  35. package/package.json +4 -4
@@ -4,6 +4,7 @@ import { Fragment, useCallback, useEffect, useMemo, useRef, useState } from 'rea
4
4
  import { jsx } from '@emotion/react';
5
5
  import { FormattedMessage, FormattedNumber } from 'react-intl-next';
6
6
  import { v4 as uuidv4 } from 'uuid';
7
+ import { withAnalyticsContext } from '@atlaskit/analytics-next';
7
8
  import Button from '@atlaskit/button/standard-button';
8
9
  import { IntlMessagesProvider } from '@atlaskit/intl-messages-provider';
9
10
  import Modal, { ModalBody, ModalFooter, ModalHeader, ModalTitle } from '@atlaskit/modal-dialog';
@@ -11,6 +12,9 @@ import { getBooleanFF } from '@atlaskit/platform-feature-flags';
11
12
  import { Box, xcss } from '@atlaskit/primitives';
12
13
  import LinkUrl from '@atlaskit/smart-card/link-url';
13
14
  import { N800 } from '@atlaskit/theme/colors';
15
+ import { EVENT_CHANNEL } from '../../../analytics';
16
+ import { componentMetadata } from '../../../analytics/constants';
17
+ import { DatasourceAction, DatasourceDisplay, DatasourceSearchMethod } from '../../../analytics/types';
14
18
  import { buildDatasourceAdf } from '../../../common/utils/adf';
15
19
  import { fetchMessagesForLocale } from '../../../common/utils/locale/fetch-messages-for-locale';
16
20
  import { useDatasourceTableState } from '../../../hooks/useDatasourceTableState';
@@ -21,6 +25,7 @@ import { ModalLoadingError } from '../../common/error-state/modal-loading-error'
21
25
  import { NoInstancesView } from '../../common/error-state/no-instances';
22
26
  import { NoResults } from '../../common/error-state/no-results';
23
27
  import { InitialStateView } from '../../common/initial-state-view';
28
+ import { CancelButton } from '../../common/modal/cancel-button';
24
29
  import { ContentContainer } from '../../common/modal/content-container';
25
30
  import { SiteSelector } from '../../common/modal/site-selector';
26
31
  import { EmptyState, IssueLikeDataTableView } from '../../issue-like-table';
@@ -36,7 +41,20 @@ const searchCountStyles = xcss({
36
41
  flex: 1,
37
42
  fontWeight: 600
38
43
  });
39
- export const ConfluenceSearchConfigModal = props => {
44
+
45
+ // TODO: common functionality of all modals refactor in EDM-9573
46
+ export const getColumnAction = (oldVisibleColumnKeys, newVisibleColumnKeys) => {
47
+ const newColumnSize = newVisibleColumnKeys.length;
48
+ const oldColumnSize = oldVisibleColumnKeys.length;
49
+ if (newColumnSize > oldColumnSize) {
50
+ return DatasourceAction.COLUMN_ADDED;
51
+ } else if (newColumnSize < oldColumnSize) {
52
+ return DatasourceAction.COLUMN_REMOVED;
53
+ } else {
54
+ return DatasourceAction.COLUMN_REORDERED;
55
+ }
56
+ };
57
+ export const PlainConfluenceSearchConfigModal = props => {
40
58
  const {
41
59
  current: modalRenderInstanceId
42
60
  } = useRef(uuidv4());
@@ -55,6 +73,11 @@ export const ConfluenceSearchConfigModal = props => {
55
73
  const [searchString, setSearchString] = useState(initialParameters === null || initialParameters === void 0 ? void 0 : initialParameters.searchString);
56
74
  const [visibleColumnKeys, setVisibleColumnKeys] = useState(initialVisibleColumnKeys);
57
75
 
76
+ // analytics related parameters
77
+ const searchCount = useRef(0);
78
+ const userInteractionActions = useRef(new Set());
79
+ const visibleColumnCount = useRef((visibleColumnKeys === null || visibleColumnKeys === void 0 ? void 0 : visibleColumnKeys.length) || 0);
80
+
58
81
  // TODO: further refactoring in EDM-9573
59
82
  // https://stash.atlassian.com/projects/ATLASSIAN/repos/atlassian-frontend-monorepo/pull-requests/82725/overview?commentId=6829210
60
83
  const parameters = useMemo(() => ({
@@ -72,8 +95,9 @@ export const ConfluenceSearchConfigModal = props => {
72
95
  columns,
73
96
  defaultVisibleColumnKeys,
74
97
  loadDatasourceDetails,
98
+ totalCount,
75
99
  extensionKey = null,
76
- totalCount
100
+ destinationObjectTypes
77
101
  } = useDatasourceTableState({
78
102
  datasourceId,
79
103
  parameters: isParametersSet ? parameters : undefined,
@@ -117,6 +141,11 @@ export const ConfluenceSearchConfigModal = props => {
117
141
  };
118
142
  void fetchSiteDisplayNames();
119
143
  }, []);
144
+ useEffect(() => {
145
+ const newVisibleColumnKeys = !initialVisibleColumnKeys || (initialVisibleColumnKeys || []).length === 0 ? defaultVisibleColumnKeys : initialVisibleColumnKeys;
146
+ visibleColumnCount.current = newVisibleColumnKeys.length;
147
+ setVisibleColumnKeys(newVisibleColumnKeys);
148
+ }, [initialVisibleColumnKeys, defaultVisibleColumnKeys]);
120
149
  const siteSelectorLabel = availableSites && availableSites.length > 1 ? confluenceSearchModalMessages.insertIssuesTitleManySites : confluenceSearchModalMessages.insertIssuesTitle;
121
150
  const [columnCustomSizes, setColumnCustomSizes] = useState(initialColumnCustomSizes);
122
151
  const onColumnResize = useCallback((key, width) => {
@@ -136,6 +165,14 @@ export const ConfluenceSearchConfigModal = props => {
136
165
  setWrappedColumnKeys(Array.from(set));
137
166
  }, [wrappedColumnKeys]);
138
167
 
168
+ // TODO: common functionality of all modals refactor in EDM-9573
169
+ const handleVisibleColumnKeysChange = useCallback((newVisibleColumnKeys = []) => {
170
+ const columnAction = getColumnAction(visibleColumnKeys || [], newVisibleColumnKeys);
171
+ userInteractionActions.current.add(columnAction);
172
+ visibleColumnCount.current = newVisibleColumnKeys.length;
173
+ setVisibleColumnKeys(newVisibleColumnKeys);
174
+ }, [visibleColumnKeys]);
175
+
139
176
  // TODO: further refactoring in EDM-9573
140
177
  // https://stash.atlassian.com/projects/ATLASSIAN/repos/atlassian-frontend-monorepo/pull-requests/82725/overview?commentId=6798258
141
178
  const confluenceSearchTable = useMemo(() => jsx(ContentContainer, {
@@ -149,18 +186,24 @@ export const ConfluenceSearchConfigModal = props => {
149
186
  visibleColumnKeys: visibleColumnKeys || defaultVisibleColumnKeys,
150
187
  onNextPage: onNextPage,
151
188
  onLoadDatasourceDetails: loadDatasourceDetails,
152
- onVisibleColumnKeysChange: setVisibleColumnKeys,
189
+ onVisibleColumnKeysChange: handleVisibleColumnKeysChange,
153
190
  parentContainerRenderInstanceId: modalRenderInstanceId,
154
191
  extensionKey: extensionKey,
155
192
  columnCustomSizes: columnCustomSizes,
156
193
  onColumnResize: onColumnResize,
157
194
  wrappedColumnKeys: wrappedColumnKeys,
158
195
  onWrappedColumnChange: getBooleanFF('platform.linking-platform.datasource-word_wrap') ? onWrappedColumnChange : undefined
159
- })), [status, columns, responseItems, hasNextPage, visibleColumnKeys, defaultVisibleColumnKeys, onNextPage, loadDatasourceDetails, setVisibleColumnKeys, modalRenderInstanceId, extensionKey, columnCustomSizes, onColumnResize, wrappedColumnKeys, onWrappedColumnChange]);
196
+ })), [status, columns, responseItems, hasNextPage, visibleColumnKeys, defaultVisibleColumnKeys, onNextPage, loadDatasourceDetails, handleVisibleColumnKeysChange, modalRenderInstanceId, extensionKey, columnCustomSizes, onColumnResize, wrappedColumnKeys, onWrappedColumnChange]);
160
197
  const resolvedWithNoResults = status === 'resolved' && !responseItems.length;
161
198
  const hasConfluenceSearchParams = selectedConfluenceSite && searchString;
162
199
  const selectedConfluenceSiteUrl = selectedConfluenceSite === null || selectedConfluenceSite === void 0 ? void 0 : selectedConfluenceSite.url;
163
200
  const confluenceSearchUrl = selectedConfluenceSiteUrl && searchString !== undefined && `${selectedConfluenceSiteUrl}/wiki/search/?text=${encodeURI(searchString)}`;
201
+ const analyticsPayload = useMemo(() => ({
202
+ extensionKey,
203
+ destinationObjectTypes,
204
+ searchCount: searchCount.current,
205
+ actions: Array.from(userInteractionActions.current)
206
+ }), [destinationObjectTypes, extensionKey]);
164
207
  const renderModalContent = useCallback(() => {
165
208
  if (status === 'rejected') {
166
209
  return jsx(ModalLoadingError, null);
@@ -186,10 +229,26 @@ export const ConfluenceSearchConfigModal = props => {
186
229
  return confluenceSearchTable;
187
230
  }, [columns.length, selectedConfluenceSiteUrl, confluenceSearchTable, resolvedWithNoResults, status, urlBeingEdited, hasConfluenceSearchParams]);
188
231
  const shouldShowResultsCount = !!totalCount && totalCount !== 1;
189
- const onInsertPressed = useCallback(() => {
232
+ const onInsertPressed = useCallback((e, analyticsEvent) => {
233
+ var _insertButtonClickedE;
190
234
  if (!isParametersSet || !cloudId) {
191
235
  return;
192
236
  }
237
+ const insertButtonClickedEvent = analyticsEvent.update({
238
+ actionSubjectId: 'insert',
239
+ attributes: {
240
+ ...analyticsPayload,
241
+ totalItemCount: totalCount || 0,
242
+ displayedColumnCount: visibleColumnCount.current,
243
+ display: DatasourceDisplay.DATASOURCE_TABLE,
244
+ searchCount: searchCount.current,
245
+ searchMethod: DatasourceSearchMethod.DATASOURCE_SEARCH_QUERY,
246
+ actions: Array.from(userInteractionActions.current)
247
+ },
248
+ eventType: 'ui'
249
+ });
250
+ const consumerEvent = (_insertButtonClickedE = insertButtonClickedEvent.clone()) !== null && _insertButtonClickedE !== void 0 ? _insertButtonClickedE : undefined;
251
+ insertButtonClickedEvent.fire(EVENT_CHANNEL);
193
252
  onInsert(buildDatasourceAdf({
194
253
  id: datasourceId,
195
254
  parameters: {
@@ -214,15 +273,25 @@ export const ConfluenceSearchConfigModal = props => {
214
273
  })
215
274
  }
216
275
  }]
217
- }));
218
- }, [cloudId, isParametersSet, onInsert, datasourceId, parameters, visibleColumnKeys, columnCustomSizes, wrappedColumnKeys]);
276
+ }), consumerEvent);
277
+ }, [isParametersSet, cloudId, analyticsPayload, totalCount, onInsert, datasourceId, parameters, visibleColumnKeys, columnCustomSizes, wrappedColumnKeys]);
219
278
  const onSearch = useCallback(newSearchString => {
279
+ searchCount.current++;
280
+ userInteractionActions.current.add(DatasourceAction.QUERY_UPDATED);
220
281
  setSearchString(newSearchString);
221
282
  reset({
222
283
  shouldForceRequest: true
223
284
  });
224
285
  }, [reset]);
225
286
  const isInsertDisabled = !isParametersSet || status === 'rejected' || status === 'unauthorized' || status === 'loading';
287
+ const getCancelButtonAnalyticsPayload = useCallback(() => {
288
+ return {
289
+ extensionKey,
290
+ destinationObjectTypes,
291
+ searchCount: searchCount.current,
292
+ actions: Array.from(userInteractionActions.current)
293
+ };
294
+ }, [destinationObjectTypes, extensionKey]);
226
295
  return jsx(IntlMessagesProvider, {
227
296
  defaultMessages: i18nEN,
228
297
  loaderFn: fetchMessagesForLocale
@@ -264,13 +333,28 @@ export const ConfluenceSearchConfigModal = props => {
264
333
  values: {
265
334
  totalCount
266
335
  }
267
- })))), jsx(Button, {
268
- appearance: "default",
269
- onClick: onCancel
270
- }, jsx(FormattedMessage, confluenceSearchModalMessages.cancelButtonText)), !hasNoConfluenceSites && jsx(Button, {
336
+ })))), jsx(CancelButton, {
337
+ onCancel: onCancel,
338
+ getAnalyticsPayload: getCancelButtonAnalyticsPayload,
339
+ testId: "confluence-search-modal--cancel-button"
340
+ }), !hasNoConfluenceSites && jsx(Button, {
271
341
  appearance: "primary",
272
342
  onClick: onInsertPressed,
273
343
  isDisabled: isInsertDisabled,
274
344
  testId: "confluence-search-datasource-modal--insert-button"
275
345
  }, jsx(FormattedMessage, confluenceSearchModalMessages.insertResultsButtonText)))));
276
- };
346
+ };
347
+ const analyticsContextAttributes = {
348
+ dataProvider: 'confluence-search'
349
+ };
350
+ const analyticsContextData = {
351
+ ...componentMetadata.configModal,
352
+ source: 'datasourceConfigModal'
353
+ };
354
+ const contextData = {
355
+ ...analyticsContextData,
356
+ attributes: {
357
+ ...analyticsContextAttributes
358
+ }
359
+ };
360
+ export const ConfluenceSearchConfigModal = withAnalyticsContext(contextData)(PlainConfluenceSearchConfigModal);
@@ -30,6 +30,7 @@ import { NoInstancesView } from '../../common/error-state/no-instances';
30
30
  import { NoResults } from '../../common/error-state/no-results';
31
31
  import { InitialStateView } from '../../common/initial-state-view';
32
32
  import { initialStateViewMessages } from '../../common/initial-state-view/messages';
33
+ import { CancelButton } from '../../common/modal/cancel-button';
33
34
  import { ContentContainer } from '../../common/modal/content-container';
34
35
  import { SiteSelector } from '../../common/modal/site-selector';
35
36
  import { EmptyState, IssueLikeDataTableView } from '../../issue-like-table';
@@ -161,12 +162,10 @@ export const PlainJiraIssuesConfigModal = props => {
161
162
  return (availableSites === null || availableSites === void 0 ? void 0 : availableSites.find(jiraSite => jiraSite.url === currentlyLoggedInSiteUrl)) || (availableSites === null || availableSites === void 0 ? void 0 : availableSites[0]);
162
163
  }
163
164
  }, [availableSites, cloudId]);
164
- const analyticsPayload = useMemo(() => {
165
- return {
166
- extensionKey: extensionKey,
167
- destinationObjectTypes: destinationObjectTypes
168
- };
169
- }, [destinationObjectTypes, extensionKey]);
165
+ const analyticsPayload = useMemo(() => ({
166
+ extensionKey,
167
+ destinationObjectTypes
168
+ }), [destinationObjectTypes, extensionKey]);
170
169
  const resolvedWithNoResults = status === 'resolved' && !responseItems.length;
171
170
  const jqlUrl = selectedJiraSite && jql && `${selectedJiraSite.url}/issues/?jql=${encodeURI(jql)}`;
172
171
  const isInsertDisabled = !isParametersSet || status === 'rejected' || status === 'unauthorized' || status === 'loading';
@@ -277,18 +276,6 @@ export const PlainJiraIssuesConfigModal = props => {
277
276
  shouldForceRequest: true
278
277
  });
279
278
  }, [jql, reset]);
280
- const onCancelClick = useCallback((e, analyticEvent) => {
281
- analyticEvent.update({
282
- eventType: 'ui',
283
- actionSubjectId: 'cancel',
284
- attributes: {
285
- ...analyticsPayload,
286
- searchCount: searchCount.current,
287
- actions: Array.from(userInteractionActions.current)
288
- }
289
- }).fire(EVENT_CHANNEL);
290
- onCancel();
291
- }, [analyticsPayload, onCancel]);
292
279
  const onSiteSelection = useCallback(site => {
293
280
  userInteractionActions.current.add(DatasourceAction.INSTANCE_UPDATED);
294
281
  setJql('');
@@ -493,6 +480,13 @@ export const PlainJiraIssuesConfigModal = props => {
493
480
  return issueLikeDataTableView;
494
481
  }, [columns.length, currentSearchMethod, issueLikeDataTableView, jql, jqlUrl, resolvedWithNoResults, selectedJiraSite === null || selectedJiraSite === void 0 ? void 0 : selectedJiraSite.url, status, urlBeingEdited]);
495
482
  const siteSelectorLabel = availableSites && availableSites.length > 1 ? modalMessages.insertIssuesTitleManySites : modalMessages.insertIssuesTitle;
483
+ const getCancelButtonAnalyticsPayload = useCallback(() => {
484
+ return {
485
+ ...analyticsPayload,
486
+ searchCount: searchCount.current,
487
+ actions: Array.from(userInteractionActions.current)
488
+ };
489
+ }, [analyticsPayload]);
496
490
  return jsx(IntlMessagesProvider, {
497
491
  defaultMessages: i18nEN,
498
492
  loaderFn: fetchMessagesForLocale
@@ -539,10 +533,11 @@ export const PlainJiraIssuesConfigModal = props => {
539
533
  values: {
540
534
  totalCount
541
535
  }
542
- })))), jsx(Button, {
543
- appearance: "default",
544
- onClick: onCancelClick
545
- }, jsx(FormattedMessage, modalMessages.cancelButtonText)), !hasNoJiraSites && jsx(Button, {
536
+ })))), jsx(CancelButton, {
537
+ onCancel: onCancel,
538
+ getAnalyticsPayload: getCancelButtonAnalyticsPayload,
539
+ testId: "jira-datasource-modal--cancel-button"
540
+ }), !hasNoJiraSites && jsx(Button, {
546
541
  appearance: "primary",
547
542
  onClick: onInsertPressed,
548
543
  isDisabled: isInsertDisabled,
@@ -1,10 +1,5 @@
1
1
  import { defineMessages } from 'react-intl-next';
2
2
  export const modalMessages = defineMessages({
3
- cancelButtonText: {
4
- id: 'linkDataSource.jira-issues.configmodal.cancelButtonText',
5
- description: 'Button text to close the modal with no changes being made',
6
- defaultMessage: 'Cancel'
7
- },
8
3
  insertIssuesButtonText: {
9
4
  id: 'linkDataSource.jira-issues.configmodal.insertIssuesButtonText',
10
5
  description: 'Button text to insert the displayed content',
@@ -26,6 +26,7 @@ import i18nEN from '../../../i18n/en';
26
26
  import { PermissionError } from '../../../services/cmdbService.utils';
27
27
  import { AccessRequired } from '../../../ui/common/error-state/access-required';
28
28
  import { ModalLoadingError } from '../../common/error-state/modal-loading-error';
29
+ import { CancelButton } from '../../common/modal/cancel-button';
29
30
  import { AssetsSearchContainer } from '../search-container';
30
31
  import { AssetsSearchContainerLoading } from '../search-container/loading-state';
31
32
  import { modalMessages } from './messages';
@@ -263,17 +264,6 @@ var PlainAssetsConfigModal = function PlainAssetsConfigModal(props) {
263
264
  }), consumerEvent);
264
265
  }
265
266
  }, [aql, schemaId, workspaceId, analyticsPayload, totalCount, retrieveUrlForSmartCardRender, responseItems.length, onInsert, datasourceId, visibleColumnKeys]);
266
- var onCancelClick = useCallback(function (e, analyticEvent) {
267
- analyticEvent.update({
268
- eventType: 'ui',
269
- actionSubjectId: 'cancel',
270
- attributes: _objectSpread(_objectSpread({}, analyticsPayload), {}, {
271
- searchCount: searchCount.current,
272
- actions: Array.from(userInteractionActions.current)
273
- })
274
- }).fire(EVENT_CHANNEL);
275
- onCancel();
276
- }, [analyticsPayload, onCancel]);
277
267
  var handleOnSearch = useCallback(function (searchAql, searchSchemaId) {
278
268
  if (schemaId !== searchSchemaId || aql !== searchAql || status === 'rejected') {
279
269
  searchCount.current++;
@@ -327,6 +317,12 @@ var PlainAssetsConfigModal = function PlainAssetsConfigModal(props) {
327
317
  });
328
318
  }
329
319
  }, [errorState, workspaceId, assetsClientLoading, initialParameters === null || initialParameters === void 0 ? void 0 : initialParameters.aql, existingObjectSchema, objectSchemas, handleOnSearch, status]);
320
+ var getCancelButtonAnalyticsPayload = useCallback(function () {
321
+ return _objectSpread(_objectSpread({}, analyticsPayload), {}, {
322
+ searchCount: searchCount.current,
323
+ actions: Array.from(userInteractionActions.current)
324
+ });
325
+ }, [analyticsPayload]);
330
326
  return jsx(IntlMessagesProvider, {
331
327
  defaultMessages: i18nEN,
332
328
  loaderFn: fetchMessagesForLocale
@@ -353,11 +349,11 @@ var PlainAssetsConfigModal = function PlainAssetsConfigModal(props) {
353
349
  columns: columns,
354
350
  defaultVisibleColumnKeys: defaultVisibleColumnKeys,
355
351
  modalRenderInstanceId: modalRenderInstanceId
356
- })), jsx(ModalFooter, null, jsx(Button, {
357
- appearance: "default",
358
- onClick: onCancelClick,
352
+ })), jsx(ModalFooter, null, jsx(CancelButton, {
353
+ onCancel: onCancel,
354
+ getAnalyticsPayload: getCancelButtonAnalyticsPayload,
359
355
  testId: 'asset-datasource-modal--cancel-button'
360
- }, jsx(FormattedMessage, modalMessages.cancelButtonText)), jsx(Button, {
356
+ }), jsx(Button, {
361
357
  appearance: "primary",
362
358
  onClick: onInsertPressed,
363
359
  isDisabled: isDisabled,
@@ -1,10 +1,5 @@
1
1
  import { defineMessages } from 'react-intl-next';
2
2
  export var modalMessages = defineMessages({
3
- cancelButtonText: {
4
- id: 'linkDataSource.assets.configmodal.cancelButtonText',
5
- description: 'Button text to close the modal with no changes being made',
6
- defaultMessage: 'Cancel'
7
- },
8
3
  updateObjectsButtonText: {
9
4
  id: 'linkDataSource.assets.configmodal.updateObjectsButtonText',
10
5
  description: 'Button text to update the displayed content',
@@ -0,0 +1,23 @@
1
+ /** @jsx jsx */
2
+ import { useCallback } from 'react';
3
+ import { jsx } from '@emotion/react';
4
+ import { FormattedMessage } from 'react-intl-next';
5
+ import Button from '@atlaskit/button/standard-button';
6
+ import { useDatasourceAnalyticsEvents } from '../../../../analytics';
7
+ import { cancelButtonMessages } from './messages';
8
+ export var CancelButton = function CancelButton(_ref) {
9
+ var getAnalyticsPayload = _ref.getAnalyticsPayload,
10
+ onCancel = _ref.onCancel,
11
+ testId = _ref.testId;
12
+ var _useDatasourceAnalyti = useDatasourceAnalyticsEvents(),
13
+ fireEvent = _useDatasourceAnalyti.fireEvent;
14
+ var onCancelClick = useCallback(function () {
15
+ fireEvent('ui.button.clicked.cancel', getAnalyticsPayload());
16
+ onCancel();
17
+ }, [getAnalyticsPayload, fireEvent, onCancel]);
18
+ return jsx(Button, {
19
+ appearance: "default",
20
+ onClick: onCancelClick,
21
+ testId: testId
22
+ }, jsx(FormattedMessage, cancelButtonMessages.cancelButtonText));
23
+ };
@@ -0,0 +1,8 @@
1
+ import { defineMessages } from 'react-intl-next';
2
+ export var cancelButtonMessages = defineMessages({
3
+ cancelButtonText: {
4
+ id: 'linkDataSource.configmodal.cancelButtonText',
5
+ description: 'Button text to close the modal with no changes being made',
6
+ defaultMessage: 'Cancel'
7
+ }
8
+ });
@@ -11,6 +11,7 @@ import { Fragment, useCallback, useEffect, useMemo, useRef, useState } from 'rea
11
11
  import { jsx } from '@emotion/react';
12
12
  import { FormattedMessage, FormattedNumber } from 'react-intl-next';
13
13
  import { v4 as uuidv4 } from 'uuid';
14
+ import { withAnalyticsContext } from '@atlaskit/analytics-next';
14
15
  import Button from '@atlaskit/button/standard-button';
15
16
  import { IntlMessagesProvider } from '@atlaskit/intl-messages-provider';
16
17
  import Modal, { ModalBody, ModalFooter, ModalHeader, ModalTitle } from '@atlaskit/modal-dialog';
@@ -18,6 +19,9 @@ import { getBooleanFF } from '@atlaskit/platform-feature-flags';
18
19
  import { Box, xcss } from '@atlaskit/primitives';
19
20
  import LinkUrl from '@atlaskit/smart-card/link-url';
20
21
  import { N800 } from '@atlaskit/theme/colors';
22
+ import { EVENT_CHANNEL } from '../../../analytics';
23
+ import { componentMetadata } from '../../../analytics/constants';
24
+ import { DatasourceAction, DatasourceDisplay, DatasourceSearchMethod } from '../../../analytics/types';
21
25
  import { buildDatasourceAdf } from '../../../common/utils/adf';
22
26
  import { fetchMessagesForLocale } from '../../../common/utils/locale/fetch-messages-for-locale';
23
27
  import { useDatasourceTableState } from '../../../hooks/useDatasourceTableState';
@@ -28,6 +32,7 @@ import { ModalLoadingError } from '../../common/error-state/modal-loading-error'
28
32
  import { NoInstancesView } from '../../common/error-state/no-instances';
29
33
  import { NoResults } from '../../common/error-state/no-results';
30
34
  import { InitialStateView } from '../../common/initial-state-view';
35
+ import { CancelButton } from '../../common/modal/cancel-button';
31
36
  import { ContentContainer } from '../../common/modal/content-container';
32
37
  import { SiteSelector } from '../../common/modal/site-selector';
33
38
  import { EmptyState, IssueLikeDataTableView } from '../../issue-like-table';
@@ -43,7 +48,20 @@ var searchCountStyles = xcss({
43
48
  flex: 1,
44
49
  fontWeight: 600
45
50
  });
46
- export var ConfluenceSearchConfigModal = function ConfluenceSearchConfigModal(props) {
51
+
52
+ // TODO: common functionality of all modals refactor in EDM-9573
53
+ export var getColumnAction = function getColumnAction(oldVisibleColumnKeys, newVisibleColumnKeys) {
54
+ var newColumnSize = newVisibleColumnKeys.length;
55
+ var oldColumnSize = oldVisibleColumnKeys.length;
56
+ if (newColumnSize > oldColumnSize) {
57
+ return DatasourceAction.COLUMN_ADDED;
58
+ } else if (newColumnSize < oldColumnSize) {
59
+ return DatasourceAction.COLUMN_REMOVED;
60
+ } else {
61
+ return DatasourceAction.COLUMN_REORDERED;
62
+ }
63
+ };
64
+ export var PlainConfluenceSearchConfigModal = function PlainConfluenceSearchConfigModal(props) {
47
65
  var _useRef = useRef(uuidv4()),
48
66
  modalRenderInstanceId = _useRef.current;
49
67
  var datasourceId = props.datasourceId,
@@ -71,6 +89,11 @@ export var ConfluenceSearchConfigModal = function ConfluenceSearchConfigModal(pr
71
89
  visibleColumnKeys = _useState8[0],
72
90
  setVisibleColumnKeys = _useState8[1];
73
91
 
92
+ // analytics related parameters
93
+ var searchCount = useRef(0);
94
+ var userInteractionActions = useRef(new Set());
95
+ var visibleColumnCount = useRef((visibleColumnKeys === null || visibleColumnKeys === void 0 ? void 0 : visibleColumnKeys.length) || 0);
96
+
74
97
  // TODO: further refactoring in EDM-9573
75
98
  // https://stash.atlassian.com/projects/ATLASSIAN/repos/atlassian-frontend-monorepo/pull-requests/82725/overview?commentId=6829210
76
99
  var parameters = useMemo(function () {
@@ -97,9 +120,10 @@ export var ConfluenceSearchConfigModal = function ConfluenceSearchConfigModal(pr
97
120
  columns = _useDatasourceTableSt.columns,
98
121
  defaultVisibleColumnKeys = _useDatasourceTableSt.defaultVisibleColumnKeys,
99
122
  loadDatasourceDetails = _useDatasourceTableSt.loadDatasourceDetails,
123
+ totalCount = _useDatasourceTableSt.totalCount,
100
124
  _useDatasourceTableSt2 = _useDatasourceTableSt.extensionKey,
101
125
  extensionKey = _useDatasourceTableSt2 === void 0 ? null : _useDatasourceTableSt2,
102
- totalCount = _useDatasourceTableSt.totalCount;
126
+ destinationObjectTypes = _useDatasourceTableSt.destinationObjectTypes;
103
127
  var hasNoConfluenceSites = availableSites && availableSites.length === 0;
104
128
  var selectedConfluenceSite = useMemo(function () {
105
129
  if (cloudId) {
@@ -161,6 +185,11 @@ export var ConfluenceSearchConfigModal = function ConfluenceSearchConfigModal(pr
161
185
  }();
162
186
  void fetchSiteDisplayNames();
163
187
  }, []);
188
+ useEffect(function () {
189
+ var newVisibleColumnKeys = !initialVisibleColumnKeys || (initialVisibleColumnKeys || []).length === 0 ? defaultVisibleColumnKeys : initialVisibleColumnKeys;
190
+ visibleColumnCount.current = newVisibleColumnKeys.length;
191
+ setVisibleColumnKeys(newVisibleColumnKeys);
192
+ }, [initialVisibleColumnKeys, defaultVisibleColumnKeys]);
164
193
  var siteSelectorLabel = availableSites && availableSites.length > 1 ? confluenceSearchModalMessages.insertIssuesTitleManySites : confluenceSearchModalMessages.insertIssuesTitle;
165
194
  var _useState9 = useState(initialColumnCustomSizes),
166
195
  _useState10 = _slicedToArray(_useState9, 2),
@@ -183,6 +212,15 @@ export var ConfluenceSearchConfigModal = function ConfluenceSearchConfigModal(pr
183
212
  setWrappedColumnKeys(Array.from(set));
184
213
  }, [wrappedColumnKeys]);
185
214
 
215
+ // TODO: common functionality of all modals refactor in EDM-9573
216
+ var handleVisibleColumnKeysChange = useCallback(function () {
217
+ var newVisibleColumnKeys = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
218
+ var columnAction = getColumnAction(visibleColumnKeys || [], newVisibleColumnKeys);
219
+ userInteractionActions.current.add(columnAction);
220
+ visibleColumnCount.current = newVisibleColumnKeys.length;
221
+ setVisibleColumnKeys(newVisibleColumnKeys);
222
+ }, [visibleColumnKeys]);
223
+
186
224
  // TODO: further refactoring in EDM-9573
187
225
  // https://stash.atlassian.com/projects/ATLASSIAN/repos/atlassian-frontend-monorepo/pull-requests/82725/overview?commentId=6798258
188
226
  var confluenceSearchTable = useMemo(function () {
@@ -197,7 +235,7 @@ export var ConfluenceSearchConfigModal = function ConfluenceSearchConfigModal(pr
197
235
  visibleColumnKeys: visibleColumnKeys || defaultVisibleColumnKeys,
198
236
  onNextPage: onNextPage,
199
237
  onLoadDatasourceDetails: loadDatasourceDetails,
200
- onVisibleColumnKeysChange: setVisibleColumnKeys,
238
+ onVisibleColumnKeysChange: handleVisibleColumnKeysChange,
201
239
  parentContainerRenderInstanceId: modalRenderInstanceId,
202
240
  extensionKey: extensionKey,
203
241
  columnCustomSizes: columnCustomSizes,
@@ -205,11 +243,19 @@ export var ConfluenceSearchConfigModal = function ConfluenceSearchConfigModal(pr
205
243
  wrappedColumnKeys: wrappedColumnKeys,
206
244
  onWrappedColumnChange: getBooleanFF('platform.linking-platform.datasource-word_wrap') ? onWrappedColumnChange : undefined
207
245
  }));
208
- }, [status, columns, responseItems, hasNextPage, visibleColumnKeys, defaultVisibleColumnKeys, onNextPage, loadDatasourceDetails, setVisibleColumnKeys, modalRenderInstanceId, extensionKey, columnCustomSizes, onColumnResize, wrappedColumnKeys, onWrappedColumnChange]);
246
+ }, [status, columns, responseItems, hasNextPage, visibleColumnKeys, defaultVisibleColumnKeys, onNextPage, loadDatasourceDetails, handleVisibleColumnKeysChange, modalRenderInstanceId, extensionKey, columnCustomSizes, onColumnResize, wrappedColumnKeys, onWrappedColumnChange]);
209
247
  var resolvedWithNoResults = status === 'resolved' && !responseItems.length;
210
248
  var hasConfluenceSearchParams = selectedConfluenceSite && searchString;
211
249
  var selectedConfluenceSiteUrl = selectedConfluenceSite === null || selectedConfluenceSite === void 0 ? void 0 : selectedConfluenceSite.url;
212
250
  var confluenceSearchUrl = selectedConfluenceSiteUrl && searchString !== undefined && "".concat(selectedConfluenceSiteUrl, "/wiki/search/?text=").concat(encodeURI(searchString));
251
+ var analyticsPayload = useMemo(function () {
252
+ return {
253
+ extensionKey: extensionKey,
254
+ destinationObjectTypes: destinationObjectTypes,
255
+ searchCount: searchCount.current,
256
+ actions: Array.from(userInteractionActions.current)
257
+ };
258
+ }, [destinationObjectTypes, extensionKey]);
213
259
  var renderModalContent = useCallback(function () {
214
260
  if (status === 'rejected') {
215
261
  return jsx(ModalLoadingError, null);
@@ -235,10 +281,25 @@ export var ConfluenceSearchConfigModal = function ConfluenceSearchConfigModal(pr
235
281
  return confluenceSearchTable;
236
282
  }, [columns.length, selectedConfluenceSiteUrl, confluenceSearchTable, resolvedWithNoResults, status, urlBeingEdited, hasConfluenceSearchParams]);
237
283
  var shouldShowResultsCount = !!totalCount && totalCount !== 1;
238
- var onInsertPressed = useCallback(function () {
284
+ var onInsertPressed = useCallback(function (e, analyticsEvent) {
285
+ var _insertButtonClickedE;
239
286
  if (!isParametersSet || !cloudId) {
240
287
  return;
241
288
  }
289
+ var insertButtonClickedEvent = analyticsEvent.update({
290
+ actionSubjectId: 'insert',
291
+ attributes: _objectSpread(_objectSpread({}, analyticsPayload), {}, {
292
+ totalItemCount: totalCount || 0,
293
+ displayedColumnCount: visibleColumnCount.current,
294
+ display: DatasourceDisplay.DATASOURCE_TABLE,
295
+ searchCount: searchCount.current,
296
+ searchMethod: DatasourceSearchMethod.DATASOURCE_SEARCH_QUERY,
297
+ actions: Array.from(userInteractionActions.current)
298
+ }),
299
+ eventType: 'ui'
300
+ });
301
+ var consumerEvent = (_insertButtonClickedE = insertButtonClickedEvent.clone()) !== null && _insertButtonClickedE !== void 0 ? _insertButtonClickedE : undefined;
302
+ insertButtonClickedEvent.fire(EVENT_CHANNEL);
242
303
  onInsert(buildDatasourceAdf({
243
304
  id: datasourceId,
244
305
  parameters: _objectSpread(_objectSpread({}, parameters), {}, {
@@ -260,15 +321,25 @@ export var ConfluenceSearchConfigModal = function ConfluenceSearchConfigModal(pr
260
321
  })
261
322
  }
262
323
  }]
263
- }));
264
- }, [cloudId, isParametersSet, onInsert, datasourceId, parameters, visibleColumnKeys, columnCustomSizes, wrappedColumnKeys]);
324
+ }), consumerEvent);
325
+ }, [isParametersSet, cloudId, analyticsPayload, totalCount, onInsert, datasourceId, parameters, visibleColumnKeys, columnCustomSizes, wrappedColumnKeys]);
265
326
  var onSearch = useCallback(function (newSearchString) {
327
+ searchCount.current++;
328
+ userInteractionActions.current.add(DatasourceAction.QUERY_UPDATED);
266
329
  setSearchString(newSearchString);
267
330
  reset({
268
331
  shouldForceRequest: true
269
332
  });
270
333
  }, [reset]);
271
334
  var isInsertDisabled = !isParametersSet || status === 'rejected' || status === 'unauthorized' || status === 'loading';
335
+ var getCancelButtonAnalyticsPayload = useCallback(function () {
336
+ return {
337
+ extensionKey: extensionKey,
338
+ destinationObjectTypes: destinationObjectTypes,
339
+ searchCount: searchCount.current,
340
+ actions: Array.from(userInteractionActions.current)
341
+ };
342
+ }, [destinationObjectTypes, extensionKey]);
272
343
  return jsx(IntlMessagesProvider, {
273
344
  defaultMessages: i18nEN,
274
345
  loaderFn: fetchMessagesForLocale
@@ -310,13 +381,24 @@ export var ConfluenceSearchConfigModal = function ConfluenceSearchConfigModal(pr
310
381
  values: {
311
382
  totalCount: totalCount
312
383
  }
313
- })))), jsx(Button, {
314
- appearance: "default",
315
- onClick: onCancel
316
- }, jsx(FormattedMessage, confluenceSearchModalMessages.cancelButtonText)), !hasNoConfluenceSites && jsx(Button, {
384
+ })))), jsx(CancelButton, {
385
+ onCancel: onCancel,
386
+ getAnalyticsPayload: getCancelButtonAnalyticsPayload,
387
+ testId: "confluence-search-modal--cancel-button"
388
+ }), !hasNoConfluenceSites && jsx(Button, {
317
389
  appearance: "primary",
318
390
  onClick: onInsertPressed,
319
391
  isDisabled: isInsertDisabled,
320
392
  testId: "confluence-search-datasource-modal--insert-button"
321
393
  }, jsx(FormattedMessage, confluenceSearchModalMessages.insertResultsButtonText)))));
322
- };
394
+ };
395
+ var analyticsContextAttributes = {
396
+ dataProvider: 'confluence-search'
397
+ };
398
+ var analyticsContextData = _objectSpread(_objectSpread({}, componentMetadata.configModal), {}, {
399
+ source: 'datasourceConfigModal'
400
+ });
401
+ var contextData = _objectSpread(_objectSpread({}, analyticsContextData), {}, {
402
+ attributes: _objectSpread({}, analyticsContextAttributes)
403
+ });
404
+ export var ConfluenceSearchConfigModal = withAnalyticsContext(contextData)(PlainConfluenceSearchConfigModal);