@atlaskit/smart-card 26.49.0 → 26.49.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 (80) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/dist/cjs/state/hooks/use-ai-summary/ai-summary-service/index.js +39 -27
  3. package/dist/cjs/state/hooks/use-ai-summary/index.js +16 -38
  4. package/dist/cjs/utils/analytics/analytics.js +1 -1
  5. package/dist/cjs/view/FlexibleCard/components/blocks/ai-summary-block/resolved/index.js +37 -29
  6. package/dist/cjs/view/FlexibleCard/components/blocks/block/index.js +1 -4
  7. package/dist/cjs/view/FlexibleCard/components/blocks/element-group/index.js +8 -9
  8. package/dist/cjs/view/HoverCard/components/ContentContainer.js +39 -13
  9. package/dist/cjs/view/HoverCard/components/HoverCardContent.js +1 -10
  10. package/dist/cjs/view/HoverCard/components/views/resolved/index.js +63 -16
  11. package/dist/cjs/view/LinkUrl/index.js +1 -1
  12. package/dist/cjs/view/common/ai-prism/index.js +0 -1
  13. package/dist/cjs/view/common/ai-summary/index.js +9 -3
  14. package/dist/es2019/state/hooks/use-ai-summary/ai-summary-service/index.js +14 -5
  15. package/dist/es2019/state/hooks/use-ai-summary/index.js +17 -35
  16. package/dist/es2019/utils/analytics/analytics.js +1 -1
  17. package/dist/es2019/view/FlexibleCard/components/blocks/ai-summary-block/resolved/index.js +33 -26
  18. package/dist/es2019/view/FlexibleCard/components/blocks/block/index.js +1 -1
  19. package/dist/es2019/view/FlexibleCard/components/blocks/element-group/index.js +0 -1
  20. package/dist/es2019/view/HoverCard/components/ContentContainer.js +35 -10
  21. package/dist/es2019/view/HoverCard/components/HoverCardContent.js +2 -7
  22. package/dist/es2019/view/HoverCard/components/views/resolved/index.js +56 -7
  23. package/dist/es2019/view/LinkUrl/index.js +1 -1
  24. package/dist/es2019/view/common/ai-prism/index.js +0 -1
  25. package/dist/es2019/view/common/ai-summary/index.js +7 -3
  26. package/dist/esm/state/hooks/use-ai-summary/ai-summary-service/index.js +39 -27
  27. package/dist/esm/state/hooks/use-ai-summary/index.js +17 -39
  28. package/dist/esm/utils/analytics/analytics.js +1 -1
  29. package/dist/esm/view/FlexibleCard/components/blocks/ai-summary-block/resolved/index.js +38 -30
  30. package/dist/esm/view/FlexibleCard/components/blocks/block/index.js +1 -1
  31. package/dist/esm/view/FlexibleCard/components/blocks/element-group/index.js +0 -1
  32. package/dist/esm/view/HoverCard/components/ContentContainer.js +39 -13
  33. package/dist/esm/view/HoverCard/components/HoverCardContent.js +2 -11
  34. package/dist/esm/view/HoverCard/components/views/resolved/index.js +66 -18
  35. package/dist/esm/view/LinkUrl/index.js +1 -1
  36. package/dist/esm/view/common/ai-prism/index.js +0 -1
  37. package/dist/esm/view/common/ai-summary/index.js +9 -3
  38. package/dist/types/state/hooks/use-ai-summary/ai-summary-service/types.d.ts +3 -1
  39. package/dist/types/state/hooks/use-ai-summary/index.d.ts +0 -1
  40. package/dist/types/view/BlockCard/views/flexible/unresolved-view/index.d.ts +2 -2
  41. package/dist/types/view/BlockCard/views/flexible/unresolved-view/types.d.ts +3 -2
  42. package/dist/types/view/FlexibleCard/components/blocks/ai-summary-block/ai-event-error-viewed/index.d.ts +1 -2
  43. package/dist/types/view/FlexibleCard/components/blocks/ai-summary-block/ai-state-indicator/types.d.ts +2 -2
  44. package/dist/types/view/FlexibleCard/components/blocks/ai-summary-block/types.d.ts +2 -3
  45. package/dist/types/view/FlexibleCard/components/blocks/block/index.d.ts +2 -3
  46. package/dist/types/view/FlexibleCard/components/blocks/element-group/index.d.ts +2 -3
  47. package/dist/types/view/FlexibleCard/components/blocks/element-group/types.d.ts +3 -2
  48. package/dist/types/view/FlexibleCard/components/blocks/types.d.ts +3 -3
  49. package/dist/types/view/FlexibleCard/components/container/hover-card-control/index.d.ts +2 -2
  50. package/dist/types/view/FlexibleCard/components/container/hover-card-control/types.d.ts +3 -2
  51. package/dist/types/view/FlexibleCard/components/container/index.d.ts +2 -4
  52. package/dist/types/view/FlexibleCard/components/container/types.d.ts +3 -2
  53. package/dist/types/view/HoverCard/components/ContentContainer.d.ts +3 -2
  54. package/dist/types/view/HoverCard/components/views/resolved/types.d.ts +0 -2
  55. package/dist/types/view/HoverCard/types.d.ts +1 -1
  56. package/dist/types/view/common/ai-prism/index.d.ts +3 -2
  57. package/dist/types/view/common/ai-prism/types.d.ts +3 -2
  58. package/dist/types/view/common/ai-summary/index.d.ts +4 -0
  59. package/dist/types-ts4.5/state/hooks/use-ai-summary/ai-summary-service/types.d.ts +3 -1
  60. package/dist/types-ts4.5/state/hooks/use-ai-summary/index.d.ts +0 -1
  61. package/dist/types-ts4.5/view/BlockCard/views/flexible/unresolved-view/index.d.ts +2 -2
  62. package/dist/types-ts4.5/view/BlockCard/views/flexible/unresolved-view/types.d.ts +3 -2
  63. package/dist/types-ts4.5/view/FlexibleCard/components/blocks/ai-summary-block/ai-event-error-viewed/index.d.ts +1 -2
  64. package/dist/types-ts4.5/view/FlexibleCard/components/blocks/ai-summary-block/ai-state-indicator/types.d.ts +2 -2
  65. package/dist/types-ts4.5/view/FlexibleCard/components/blocks/ai-summary-block/types.d.ts +2 -3
  66. package/dist/types-ts4.5/view/FlexibleCard/components/blocks/block/index.d.ts +2 -3
  67. package/dist/types-ts4.5/view/FlexibleCard/components/blocks/element-group/index.d.ts +2 -3
  68. package/dist/types-ts4.5/view/FlexibleCard/components/blocks/element-group/types.d.ts +3 -2
  69. package/dist/types-ts4.5/view/FlexibleCard/components/blocks/types.d.ts +3 -3
  70. package/dist/types-ts4.5/view/FlexibleCard/components/container/hover-card-control/index.d.ts +2 -2
  71. package/dist/types-ts4.5/view/FlexibleCard/components/container/hover-card-control/types.d.ts +3 -2
  72. package/dist/types-ts4.5/view/FlexibleCard/components/container/index.d.ts +2 -4
  73. package/dist/types-ts4.5/view/FlexibleCard/components/container/types.d.ts +3 -2
  74. package/dist/types-ts4.5/view/HoverCard/components/ContentContainer.d.ts +3 -2
  75. package/dist/types-ts4.5/view/HoverCard/components/views/resolved/types.d.ts +0 -2
  76. package/dist/types-ts4.5/view/HoverCard/types.d.ts +1 -1
  77. package/dist/types-ts4.5/view/common/ai-prism/index.d.ts +3 -2
  78. package/dist/types-ts4.5/view/common/ai-prism/types.d.ts +3 -2
  79. package/dist/types-ts4.5/view/common/ai-summary/index.d.ts +4 -0
  80. package/package.json +5 -5
@@ -20,6 +20,7 @@ var _messages = require("../../../../../messages");
20
20
  var _reactIntlNext = require("react-intl-next");
21
21
  var _platformFeatureFlags = require("@atlaskit/platform-feature-flags");
22
22
  var _helpers = require("../../../../../state/helpers");
23
+ var _useAiSummary = require("../../../../../state/hooks/use-ai-summary");
23
24
  function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(e) { return e ? t : r; })(e); }
24
25
  function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != _typeof(e) && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
25
26
  var toFooterActions = exports.toFooterActions = function toFooterActions(cardActions, onActionClick) {
@@ -56,19 +57,41 @@ var toFooterActions = exports.toFooterActions = function toFooterActions(cardAct
56
57
  });
57
58
  return [followAction].concat((0, _toConsumableArray2.default)(actions));
58
59
  };
59
- var HoverCardResolvedView = function HoverCardResolvedView(_ref) {
60
+
61
+ //This component encapsulates useAISummary hook under the AI Summary FF 'platform.linking-platform.smart-card.hover-card-ai-summaries'
62
+ var ConnectedAIBlock = function ConnectedAIBlock(_ref) {
63
+ var bottomPrimary = _ref.bottomPrimary,
64
+ url = _ref.url,
65
+ imagePreview = _ref.imagePreview;
66
+ var aiSummary = (0, _useAiSummary.useAISummary)({
67
+ url: url
68
+ });
69
+ var aiStatus = aiSummary.state.status;
70
+ var showData = aiStatus === 'ready' || aiStatus === 'error';
71
+ return showData ? /*#__PURE__*/_react.default.createElement(_blocks.CustomBlock, {
72
+ direction: _constants.SmartLinkDirection.Vertical
73
+ }, !imagePreview && /*#__PURE__*/_react.default.createElement(_blocks.SnippetBlock, {
74
+ status: _constants.SmartLinkStatus.Resolved
75
+ }), /*#__PURE__*/_react.default.createElement(_blocks.MetadataBlock, {
76
+ primary: bottomPrimary,
77
+ size: _constants.SmartLinkSize.Large,
78
+ overrideCss: _styled.metadataBlockCss,
79
+ maxLines: 1,
80
+ status: _constants.SmartLinkStatus.Resolved
81
+ })) : null;
82
+ };
83
+ var HoverCardResolvedView = function HoverCardResolvedView(_ref2) {
60
84
  var _cardState$details;
61
- var flexibleCardProps = _ref.flexibleCardProps,
62
- titleBlockProps = _ref.titleBlockProps,
63
- analytics = _ref.analytics,
64
- cardState = _ref.cardState,
65
- _ref$cardActions = _ref.cardActions,
66
- cardActions = _ref$cardActions === void 0 ? [] : _ref$cardActions,
67
- isAISummaryEnabled = _ref.isAISummaryEnabled,
68
- onActionClick = _ref.onActionClick,
69
- onAIActionChange = _ref.onAIActionChange,
70
- extensionKey = _ref.extensionKey,
71
- url = _ref.url;
85
+ var flexibleCardProps = _ref2.flexibleCardProps,
86
+ titleBlockProps = _ref2.titleBlockProps,
87
+ analytics = _ref2.analytics,
88
+ cardState = _ref2.cardState,
89
+ _ref2$cardActions = _ref2.cardActions,
90
+ cardActions = _ref2$cardActions === void 0 ? [] : _ref2$cardActions,
91
+ isAISummaryEnabled = _ref2.isAISummaryEnabled,
92
+ onActionClick = _ref2.onActionClick,
93
+ extensionKey = _ref2.extensionKey,
94
+ url = _ref2.url;
72
95
  var canBeDatasource = (0, _helpers.getCanBeDatasource)(cardState.details);
73
96
  (0, _react.useEffect)(function () {
74
97
  // Since this hover view is only rendered on resolved status,
@@ -100,6 +123,15 @@ var HoverCardResolvedView = function HoverCardResolvedView(_ref) {
100
123
  var _snippetBlockRef$curr, _snippetBlockRef$curr2;
101
124
  snippetHeight.current = (_snippetBlockRef$curr = (_snippetBlockRef$curr2 = snippetBlockRef.current) === null || _snippetBlockRef$curr2 === void 0 ? void 0 : _snippetBlockRef$curr2.getBoundingClientRect().height) !== null && _snippetBlockRef$curr !== void 0 ? _snippetBlockRef$curr : 0;
102
125
  }, []);
126
+
127
+ // We want to maintain the height of the HoverCard while summarizing and pass this height to the AISummaryBlock.
128
+ // This approach will prevent any abrupt changes in the height of the HoverCard.
129
+ var connectedAIBlockHeight = _react.default.useRef(0);
130
+ var connectedAIBlockRef = (0, _react.useRef)(null);
131
+ var onConnectedAIBlockRender = (0, _react.useCallback)(function () {
132
+ var _connectedAIBlockRef$, _connectedAIBlockRef$2;
133
+ connectedAIBlockHeight.current = (_connectedAIBlockRef$ = (_connectedAIBlockRef$2 = connectedAIBlockRef.current) === null || _connectedAIBlockRef$2 === void 0 ? void 0 : _connectedAIBlockRef$2.getBoundingClientRect().height) !== null && _connectedAIBlockRef$ !== void 0 ? _connectedAIBlockRef$ : 0;
134
+ }, []);
103
135
  var imagePreview = (0, _ImagePreview.default)({
104
136
  data: data,
105
137
  fallbackElementHeight: snippetHeight.current
@@ -112,16 +144,31 @@ var HoverCardResolvedView = function HoverCardResolvedView(_ref) {
112
144
  overrideCss: _styled.metadataBlockCss,
113
145
  maxLines: 1,
114
146
  size: _constants.SmartLinkSize.Medium
115
- }), !imagePreview && /*#__PURE__*/_react.default.createElement(_blocks.SnippetBlock, null), /*#__PURE__*/_react.default.createElement(_blocks.SnippetBlock, {
147
+ }), isAISummaryEnabled &&
148
+ /*#__PURE__*/
149
+ // All custom elements should be contained within a CustomBlock.
150
+ // Flex Container components check whether the direct child is a flex blocks. It removes anything that isn't
151
+ _react.default.createElement(_blocks.CustomBlock, {
152
+ direction: _constants.SmartLinkDirection.Vertical,
153
+ onRender: onConnectedAIBlockRender,
154
+ blockRef: connectedAIBlockRef
155
+ }, /*#__PURE__*/_react.default.createElement(ConnectedAIBlock, {
156
+ imagePreview: !!imagePreview,
157
+ url: url,
158
+ bottomPrimary: bottomPrimary
159
+ })), !isAISummaryEnabled && !imagePreview && /*#__PURE__*/_react.default.createElement(_blocks.SnippetBlock, {
160
+ status: _constants.SmartLinkStatus.Resolved
161
+ }), /*#__PURE__*/_react.default.createElement(_blocks.SnippetBlock, {
116
162
  testId: 'hidden-snippet',
117
163
  onRender: onSnippetRender,
118
164
  blockRef: snippetBlockRef,
119
165
  overrideCss: _styled.hiddenSnippetStyles
120
- }), /*#__PURE__*/_react.default.createElement(_blocks.MetadataBlock, {
166
+ }), !isAISummaryEnabled && /*#__PURE__*/_react.default.createElement(_blocks.MetadataBlock, {
121
167
  primary: bottomPrimary,
122
168
  size: _constants.SmartLinkSize.Large,
123
169
  overrideCss: _styled.metadataBlockCss,
124
- maxLines: 1
170
+ maxLines: 1,
171
+ status: _constants.SmartLinkStatus.Resolved
125
172
  }), (0, _platformFeatureFlags.getBooleanFF)('platform.linking-platform.smart-card.enable-hover-card-related-urls') && /*#__PURE__*/_react.default.createElement(_blocks.RelatedUrlsBlock, {
126
173
  url: url,
127
174
  size: _constants.SmartLinkSize.Small
@@ -130,7 +177,7 @@ var HoverCardResolvedView = function HoverCardResolvedView(_ref) {
130
177
  name: _constants.ElementName.Provider
131
178
  }],
132
179
  actions: footerActions,
133
- onAIActionChange: onAIActionChange
180
+ aiSummaryMinHeight: connectedAIBlockHeight.current
134
181
  }) : /*#__PURE__*/_react.default.createElement(_blocks.FooterBlock, {
135
182
  actions: footerActions,
136
183
  size: _constants.SmartLinkSize.Large,
@@ -17,7 +17,7 @@ var _excluded = ["href", "children", "checkSafety", "onClick", "testId"],
17
17
  _excluded2 = ["isLinkSafe", "showSafetyWarningModal"];
18
18
  var PACKAGE_DATA = {
19
19
  packageName: "@atlaskit/smart-card",
20
- packageVersion: "26.49.0",
20
+ packageVersion: "26.49.2",
21
21
  componentName: 'linkUrl'
22
22
  };
23
23
  var Link = (0, _click.withLinkClickedEvent)('a');
@@ -6,7 +6,6 @@ Object.defineProperty(exports, "__esModule", {
6
6
  });
7
7
  exports.default = void 0;
8
8
  var _react = require("@emotion/react");
9
- var _react2 = _interopRequireDefault(require("react"));
10
9
  var _tokens = require("@atlaskit/tokens");
11
10
  var _constants = require("./constants");
12
11
  var _aiGlowingBorder = _interopRequireDefault(require("./ai-glowing-border"));
@@ -31,14 +31,17 @@ var AISummaryCSS = (0, _react2.css)({
31
31
  */
32
32
 
33
33
  var AISummary = function AISummary(_ref) {
34
- var content = _ref.content,
34
+ var _ref$content = _ref.content,
35
+ content = _ref$content === void 0 ? '' : _ref$content,
35
36
  _ref$showIcon = _ref.showIcon,
36
37
  showIcon = _ref$showIcon === void 0 ? false : _ref$showIcon,
37
38
  iconComponent = _ref.iconComponent,
38
39
  overrideCss = _ref.overrideCss,
39
40
  _ref$testId = _ref.testId,
40
- testId = _ref$testId === void 0 ? 'ai-summary' : _ref$testId;
41
- if (!content) {
41
+ testId = _ref$testId === void 0 ? 'ai-summary' : _ref$testId,
42
+ _ref$minHeight = _ref.minHeight,
43
+ minHeight = _ref$minHeight === void 0 ? 0 : _ref$minHeight;
44
+ if (!content && minHeight === 0) {
42
45
  return null;
43
46
  }
44
47
  return (0, _react2.jsx)(_markdownToJsx.default, {
@@ -50,6 +53,9 @@ var AISummary = function AISummary(_ref) {
50
53
  overrides: {
51
54
  Icon: iconComponent !== null && iconComponent !== void 0 ? iconComponent : AITooltipIcon
52
55
  }
56
+ },
57
+ style: {
58
+ minHeight: minHeight
53
59
  }
54
60
  });
55
61
  };
@@ -23,7 +23,11 @@ export class AISummaryService {
23
23
  const path = 'chat/v1/invoke_agent/stream';
24
24
  const requestUrl = addPath(this.config.baseUrl, path);
25
25
  const response = await fetch(requestUrl, options);
26
- return readStream(response);
26
+ if (!response.ok || response.status >= 400) {
27
+ throw new Error(`Status: ${response.status}\n URL: ${this.url}\n StatusText ${response.statusText}`);
28
+ } else {
29
+ return readStream(response);
30
+ }
27
31
  });
28
32
  const defaultConfig = {
29
33
  baseUrl: '/gateway/api/assist',
@@ -42,10 +46,10 @@ export class AISummaryService {
42
46
  };
43
47
  this.url = props.url;
44
48
  }
45
- async summariseUrl(summaryStyle = 'short') {
49
+ async summariseUrl(summaryStyle = 'medium') {
46
50
  this.state = {
47
- ...this.state,
48
- status: 'loading'
51
+ status: 'loading',
52
+ content: ''
49
53
  };
50
54
  for (const subscriber of this.subscribedStateSetters) {
51
55
  subscriber(this.state);
@@ -63,12 +67,17 @@ export class AISummaryService {
63
67
  });
64
68
  }
65
69
  }
70
+
71
+ //if AI Mate service returns cached summary we get the summary text in one piece as the last message
72
+ if (chunk.type === 'FINAL_RESPONSE') {
73
+ bufferContent = chunk.message.message.content;
74
+ }
66
75
  }
67
76
  this.state = {
68
77
  status: 'done',
69
78
  content: bufferContent
70
79
  };
71
- } catch {
80
+ } catch (err) {
72
81
  this.state = {
73
82
  status: 'error',
74
83
  content: ''
@@ -1,4 +1,4 @@
1
- import { useState, useEffect, useMemo } from 'react';
1
+ import { useState, useEffect } from 'react';
2
2
  import { AISummariesStore } from './ai-summary-service/store';
3
3
  import { AISummaryService } from './ai-summary-service';
4
4
  export const useAISummary = props => {
@@ -6,50 +6,32 @@ export const useAISummary = props => {
6
6
  const {
7
7
  url,
8
8
  baseUrl,
9
- product,
10
- headers
9
+ headers,
10
+ product
11
11
  } = props;
12
12
  const [state, setState] = useState(((_AISummariesStore$get = AISummariesStore.get(url)) === null || _AISummariesStore$get === void 0 ? void 0 : _AISummariesStore$get.state) || {
13
13
  status: 'ready',
14
14
  content: ''
15
15
  });
16
-
17
- // Can be used to know the summary status upon mounting a component (HoverCard UI state for example).
18
- // For other scenarios, opt for dynamic status updates via state.status.
19
- const isSummarisedOnMount = useMemo(() => {
20
- var _AISummariesStore$get2;
21
- return ((_AISummariesStore$get2 = AISummariesStore.get(url)) === null || _AISummariesStore$get2 === void 0 ? void 0 : _AISummariesStore$get2.state.status) === 'done';
22
- }, [url]);
23
16
  useEffect(() => {
24
- // Create or subscribe to an AI service only if a summary has not been previously generated.
25
- // Otherwise, use the data from the current state synchronized with a cache (AISummariesStore).
26
- if (!isSummarisedOnMount) {
27
- const aISummaryService = AISummariesStore.get(url);
28
- const isAISummaryServiceInitiated = !!aISummaryService;
29
- if (isAISummaryServiceInitiated) {
30
- //if we want to subscribe to updates from an existing AI service that has not yet provided a summary or is currently in progress.
31
- const unsubscribe = aISummaryService.subscribe(setState);
32
- return () => unsubscribe();
33
- } else {
34
- var _AISummariesStore$get3;
35
- //if we want to create a new AI service and wish to subscribe for updates
36
- AISummariesStore.set(url, new AISummaryService({
37
- url,
38
- baseUrl,
39
- product,
40
- headers
41
- }));
42
- const unsubscribe = (_AISummariesStore$get3 = AISummariesStore.get(url)) === null || _AISummariesStore$get3 === void 0 ? void 0 : _AISummariesStore$get3.subscribe(setState);
43
- return () => unsubscribe && unsubscribe();
44
- }
17
+ var _AISummariesStore$get2;
18
+ if (!AISummariesStore.get(url)) {
19
+ AISummariesStore.set(url, new AISummaryService({
20
+ url,
21
+ baseUrl,
22
+ headers,
23
+ product
24
+ }));
45
25
  }
46
- }, [isSummarisedOnMount, url, baseUrl, product, headers]);
26
+
27
+ //returns function that calls unsubscribe method
28
+ return (_AISummariesStore$get2 = AISummariesStore.get(url)) === null || _AISummariesStore$get2 === void 0 ? void 0 : _AISummariesStore$get2.subscribe(setState);
29
+ }, [url, baseUrl, headers, product]);
47
30
  const summariseUrl = () => {
48
- var _AISummariesStore$get4;
49
- return (_AISummariesStore$get4 = AISummariesStore.get(url)) === null || _AISummariesStore$get4 === void 0 ? void 0 : _AISummariesStore$get4.summariseUrl();
31
+ var _AISummariesStore$get3;
32
+ return (_AISummariesStore$get3 = AISummariesStore.get(url)) === null || _AISummariesStore$get3 === void 0 ? void 0 : _AISummariesStore$get3.summariseUrl();
50
33
  };
51
34
  return {
52
- isSummarisedOnMount,
53
35
  summariseUrl,
54
36
  state
55
37
  };
@@ -4,7 +4,7 @@ export const ANALYTICS_CHANNEL = 'media';
4
4
  export const context = {
5
5
  componentName: 'smart-cards',
6
6
  packageName: "@atlaskit/smart-card",
7
- packageVersion: "26.49.0"
7
+ packageVersion: "26.49.2"
8
8
  };
9
9
  export let TrackQuickActionType = /*#__PURE__*/function (TrackQuickActionType) {
10
10
  TrackQuickActionType["StatusUpdate"] = "StatusUpdate";
@@ -1,5 +1,5 @@
1
1
  import _extends from "@babel/runtime/helpers/extends";
2
- import React, { useCallback, useMemo, useState } from 'react';
2
+ import React, { useCallback, useMemo, useRef, useState, useEffect } from 'react';
3
3
  import { FormattedMessage } from 'react-intl-next';
4
4
  import { Box, Inline } from '@atlaskit/primitives';
5
5
  import { ActionName, SmartLinkDirection, SmartLinkSize, SmartLinkWidth } from '../../../../../../constants';
@@ -21,40 +21,46 @@ const AISummaryBlockResolvedView = props => {
21
21
  actions = [],
22
22
  metadata,
23
23
  onActionMenuOpenChange,
24
- onAIActionChange,
25
24
  size = SmartLinkSize.Medium,
26
- testId
25
+ testId,
26
+ aiSummaryMinHeight
27
27
  } = props;
28
- const [aiState, setAIState] = useState('ready');
28
+ const metadataElements = renderElementItems(metadata);
29
29
  const {
30
30
  fireEvent
31
31
  } = useAnalyticsEvents();
32
- const metadataElements = renderElementItems(metadata);
33
32
  const context = useFlexibleUiContext();
34
33
  const url = (context === null || context === void 0 ? void 0 : context.url) || '';
35
- const aiSummary = useAISummary({
36
- url
37
- });
38
34
  const {
35
+ summariseUrl,
39
36
  state: {
40
37
  content,
41
38
  status
42
- },
43
- isSummarisedOnMount
44
- } = aiSummary;
45
- const onAIActionClick = useCallback(() => {
46
- fireEvent('ui.button.clicked.aiSummary', {});
47
- setAIState('loading');
48
- if (onAIActionChange) {
49
- onAIActionChange('loading');
50
39
  }
51
- }, [onAIActionChange, fireEvent]);
40
+ } = useAISummary({
41
+ url
42
+ });
43
+ const showAISummary = status !== 'ready' && status !== 'error';
44
+ const isSummarisedOnMountRef = useRef(status === 'done');
45
+ let isErroredOnMountRef = useRef(status === 'error');
46
+ const [showAISummaryErrorMessage, setShowAISummaryErrorMessage] = useState(false);
47
+ useEffect(() => {
48
+ if (isErroredOnMountRef.current && status === 'loading') {
49
+ isErroredOnMountRef.current = false;
50
+ setShowAISummaryErrorMessage(true);
51
+ } else {
52
+ setShowAISummaryErrorMessage(!isErroredOnMountRef.current && status === 'error');
53
+ }
54
+ }, [status]);
52
55
  const combinedActions = useMemo(() => {
53
- if (aiState === 'ready') {
56
+ if (status === 'ready' || status === 'error') {
54
57
  const aiAction = {
55
58
  content: /*#__PURE__*/React.createElement(FormattedMessage, messages.ai_summarize),
56
59
  name: ActionName.CustomAction,
57
- onClick: onAIActionClick,
60
+ onClick: () => {
61
+ fireEvent('ui.button.clicked.aiSummary', {});
62
+ summariseUrl();
63
+ },
58
64
  testId: `${testId}-ai-summary-action`,
59
65
  icon: /*#__PURE__*/React.createElement(AIIcon, {
60
66
  label: "AIIcon"
@@ -63,7 +69,7 @@ const AISummaryBlockResolvedView = props => {
63
69
  return [aiAction, ...actions];
64
70
  }
65
71
  return actions;
66
- }, [actions, aiState, onAIActionClick, testId]);
72
+ }, [actions, status, testId, summariseUrl, fireEvent]);
67
73
  const onDropdownOpenChange = useCallback(isOpen => {
68
74
  if (onActionMenuOpenChange) {
69
75
  onActionMenuOpenChange({
@@ -75,17 +81,18 @@ const AISummaryBlockResolvedView = props => {
75
81
  direction: SmartLinkDirection.Vertical,
76
82
  testId: `${testId}-resolved-view`
77
83
  }), status === 'done' && /*#__PURE__*/React.createElement(AIEventSummaryViewed, {
78
- fromCache: isSummarisedOnMount
79
- }), /*#__PURE__*/React.createElement(AISummary, {
84
+ fromCache: isSummarisedOnMountRef.current
85
+ }), showAISummary && /*#__PURE__*/React.createElement(AISummary, {
86
+ minHeight: aiSummaryMinHeight,
80
87
  content: content,
81
- showIcon: isSummarisedOnMount
88
+ showIcon: isSummarisedOnMountRef.current
82
89
  }), /*#__PURE__*/React.createElement(Inline, {
83
90
  alignBlock: "center",
84
91
  alignInline: "end",
85
92
  grow: "fill",
86
93
  spread: "space-between"
87
- }, /*#__PURE__*/React.createElement(Box, null, !isSummarisedOnMount && (aiState === 'loading' || aiState === 'done') ? /*#__PURE__*/React.createElement(AIStateIndicator, {
88
- state: aiState,
94
+ }, /*#__PURE__*/React.createElement(Box, null, !isSummarisedOnMountRef.current && (status === 'loading' || status === 'done') ? /*#__PURE__*/React.createElement(AIStateIndicator, {
95
+ state: status,
89
96
  testId: `${testId}-state-indicator`
90
97
  }) : /*#__PURE__*/React.createElement(ElementGroup, {
91
98
  width: SmartLinkWidth.FitToContent,
@@ -95,7 +102,7 @@ const AISummaryBlockResolvedView = props => {
95
102
  items: combinedActions,
96
103
  appearance: "default",
97
104
  size: size
98
- }))), status === 'error' && /*#__PURE__*/React.createElement(Inline, {
105
+ }))), showAISummaryErrorMessage && /*#__PURE__*/React.createElement(Inline, {
99
106
  grow: "fill"
100
107
  }, /*#__PURE__*/React.createElement(AIEventErrorViewed, null), /*#__PURE__*/React.createElement(AIStateIndicator, {
101
108
  state: status,
@@ -1,5 +1,5 @@
1
1
  /** @jsx jsx */
2
- import React, { useEffect } from 'react';
2
+ import { useEffect } from 'react';
3
3
  import { css, jsx } from '@emotion/react';
4
4
  import { ElementName, SmartLinkDirection, SmartLinkSize } from '../../../../../constants';
5
5
  import { getBaseStyles, getGapSize, highlightRemoveStyles, renderChildren } from '../utils';
@@ -1,5 +1,4 @@
1
1
  /** @jsx jsx */
2
- import React from 'react';
3
2
  import { css, jsx } from '@emotion/react';
4
3
  import { SmartLinkAlignment, SmartLinkDirection, SmartLinkPosition, SmartLinkSize, SmartLinkWidth } from '../../../../../constants';
5
4
  import { getBaseStyles, getGapSize, renderChildren } from '../utils';
@@ -1,28 +1,53 @@
1
1
  import _extends from "@babel/runtime/helpers/extends";
2
2
  /** @jsx jsx */
3
3
  import { jsx } from '@emotion/react';
4
- import React from 'react';
4
+ import { useState, useEffect } from 'react';
5
5
  import { getBooleanFF } from '@atlaskit/platform-feature-flags';
6
6
  import { HoverCardContainer, popupContainerStyles } from '../styled';
7
7
  import AIPrism from '../../common/ai-prism';
8
8
  import { hoverCardClassName } from './HoverCardContent';
9
+ import { useAISummary } from '../../../state/hooks/use-ai-summary';
10
+ const ConnectedAIPrismContainer = ({
11
+ children,
12
+ isAIEnabled = false,
13
+ testId,
14
+ url,
15
+ ...props
16
+ }) => {
17
+ const {
18
+ state: {
19
+ status
20
+ }
21
+ } = useAISummary({
22
+ url
23
+ });
24
+ const [showPrism, setShowPrism] = useState(status === 'loading');
25
+ useEffect(() => {
26
+ setShowPrism(status === 'loading');
27
+ }, [status]);
28
+ const container = jsx("div", _extends({
29
+ className: hoverCardClassName,
30
+ css: [HoverCardContainer, isAIEnabled && showPrism ? undefined : popupContainerStyles],
31
+ "data-testid": testId
32
+ }, props), children);
33
+ return isAIEnabled ? jsx(AIPrism, {
34
+ isVisible: showPrism,
35
+ testId: `${testId}-prism`
36
+ }, container) : container;
37
+ };
9
38
  const ContentContainer = ({
10
39
  children,
11
40
  isAIEnabled = false,
12
- showPrism = false,
13
41
  testId,
42
+ url,
14
43
  ...props
15
44
  }) => {
16
45
  if (getBooleanFF('platform.linking-platform.smart-card.hover-card-ai-summaries')) {
17
- const container = jsx("div", _extends({
18
- className: hoverCardClassName,
19
- css: [HoverCardContainer, isAIEnabled && showPrism ? undefined : popupContainerStyles],
20
- "data-testid": testId
46
+ return jsx(ConnectedAIPrismContainer, _extends({
47
+ isAIEnabled: isAIEnabled,
48
+ url: url,
49
+ testId: testId
21
50
  }, props), children);
22
- return isAIEnabled ? jsx(AIPrism, {
23
- isVisible: showPrism,
24
- testId: `${testId}-prism`
25
- }, container) : container;
26
51
  }
27
52
  return jsx("div", _extends({
28
53
  className: hoverCardClassName,
@@ -2,7 +2,7 @@
2
2
  import { jsx } from '@emotion/react';
3
3
  import { useAnalyticsEvents } from '@atlaskit/analytics-next';
4
4
  import CopyIcon from '@atlaskit/icon/glyph/copy';
5
- import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
5
+ import React, { useCallback, useEffect, useMemo, useRef } from 'react';
6
6
  import { useSmartLinkContext } from '@atlaskit/link-provider';
7
7
  import { ActionName, CardDisplay, SmartLinkPosition, SmartLinkSize } from '../../../constants';
8
8
  import { extractMetadata } from '../../../extractors/hover/extractMetadata';
@@ -61,7 +61,6 @@ const HoverCardContent = ({
61
61
  const services = getServices(linkState.details);
62
62
  const statusRef = useRef(linkStatus);
63
63
  const analyticsRef = useRef(analytics);
64
- const [showPrism, setShowPrism] = useState(false);
65
64
  useEffect(() => {
66
65
  /**
67
66
  * Must access current analytics object value via ref because its not stable
@@ -131,9 +130,6 @@ const HoverCardContent = ({
131
130
  analytics
132
131
  };
133
132
  const onClickStopPropagation = useCallback(e => e.stopPropagation(), []);
134
- const onAIActionChange = useCallback(state => {
135
- setShowPrism(state === 'loading');
136
- }, []);
137
133
  const getCardView = cardState => {
138
134
  if (cardState.metadataStatus === 'pending') {
139
135
  return jsx(HoverCardLoadingView, {
@@ -166,7 +162,6 @@ const HoverCardContent = ({
166
162
  flexibleCardProps: flexibleCardProps,
167
163
  isAISummaryEnabled: isAISummaryEnabled,
168
164
  onActionClick: onActionClick,
169
- onAIActionChange: onAIActionChange,
170
165
  titleBlockProps: titleBlockProps
171
166
  });
172
167
  }
@@ -178,7 +173,7 @@ const HoverCardContent = ({
178
173
  onMouseLeave: onMouseLeave,
179
174
  onClick: onClickStopPropagation,
180
175
  isAIEnabled: isAISummaryEnabled,
181
- showPrism: showPrism
176
+ url: url
182
177
  }, cardView) : null;
183
178
  };
184
179
  export default HoverCardContent;
@@ -1,7 +1,7 @@
1
1
  import _extends from "@babel/runtime/helpers/extends";
2
2
  import React, { useCallback, useEffect, useMemo, useRef } from 'react';
3
- import { ActionName, CardDisplay, ElementName, SmartLinkPosition, SmartLinkSize } from '../../../../../constants';
4
- import { FooterBlock, MetadataBlock, RelatedUrlsBlock, SnippetBlock, TitleBlock, AISummaryBlock } from '../../../../FlexibleCard/components/blocks';
3
+ import { ActionName, CardDisplay, ElementName, SmartLinkPosition, SmartLinkSize, SmartLinkDirection } from '../../../../../constants';
4
+ import { FooterBlock, MetadataBlock, RelatedUrlsBlock, SnippetBlock, TitleBlock, AISummaryBlock, CustomBlock } from '../../../../FlexibleCard/components/blocks';
5
5
  import { footerBlockCss, hiddenSnippetStyles, metadataBlockCss } from './styled';
6
6
  import FlexibleCard from '../../../../FlexibleCard';
7
7
  import { getSimulatedBetterMetadata } from '../../../utils';
@@ -11,6 +11,8 @@ import { messages } from '../../../../../messages';
11
11
  import { FormattedMessage } from 'react-intl-next';
12
12
  import { getBooleanFF } from '@atlaskit/platform-feature-flags';
13
13
  import { getCanBeDatasource } from '../../../../../state/helpers';
14
+ import { useAISummary } from '../../../../../state/hooks/use-ai-summary';
15
+ import { SmartLinkStatus } from '../../../../../constants';
14
16
  export const toFooterActions = (cardActions, onActionClick) => {
15
17
  const followAction = {
16
18
  hideIcon: true,
@@ -45,6 +47,30 @@ export const toFooterActions = (cardActions, onActionClick) => {
45
47
  });
46
48
  return [followAction, ...actions];
47
49
  };
50
+
51
+ //This component encapsulates useAISummary hook under the AI Summary FF 'platform.linking-platform.smart-card.hover-card-ai-summaries'
52
+ const ConnectedAIBlock = ({
53
+ bottomPrimary,
54
+ url,
55
+ imagePreview
56
+ }) => {
57
+ const aiSummary = useAISummary({
58
+ url
59
+ });
60
+ const aiStatus = aiSummary.state.status;
61
+ const showData = aiStatus === 'ready' || aiStatus === 'error';
62
+ return showData ? /*#__PURE__*/React.createElement(CustomBlock, {
63
+ direction: SmartLinkDirection.Vertical
64
+ }, !imagePreview && /*#__PURE__*/React.createElement(SnippetBlock, {
65
+ status: SmartLinkStatus.Resolved
66
+ }), /*#__PURE__*/React.createElement(MetadataBlock, {
67
+ primary: bottomPrimary,
68
+ size: SmartLinkSize.Large,
69
+ overrideCss: metadataBlockCss,
70
+ maxLines: 1,
71
+ status: SmartLinkStatus.Resolved
72
+ })) : null;
73
+ };
48
74
  const HoverCardResolvedView = ({
49
75
  flexibleCardProps,
50
76
  titleBlockProps,
@@ -53,7 +79,6 @@ const HoverCardResolvedView = ({
53
79
  cardActions = [],
54
80
  isAISummaryEnabled,
55
81
  onActionClick,
56
- onAIActionChange,
57
82
  extensionKey,
58
83
  url
59
84
  }) => {
@@ -88,6 +113,15 @@ const HoverCardResolvedView = ({
88
113
  var _snippetBlockRef$curr, _snippetBlockRef$curr2;
89
114
  snippetHeight.current = (_snippetBlockRef$curr = (_snippetBlockRef$curr2 = snippetBlockRef.current) === null || _snippetBlockRef$curr2 === void 0 ? void 0 : _snippetBlockRef$curr2.getBoundingClientRect().height) !== null && _snippetBlockRef$curr !== void 0 ? _snippetBlockRef$curr : 0;
90
115
  }, []);
116
+
117
+ // We want to maintain the height of the HoverCard while summarizing and pass this height to the AISummaryBlock.
118
+ // This approach will prevent any abrupt changes in the height of the HoverCard.
119
+ const connectedAIBlockHeight = React.useRef(0);
120
+ const connectedAIBlockRef = useRef(null);
121
+ const onConnectedAIBlockRender = useCallback(() => {
122
+ var _connectedAIBlockRef$, _connectedAIBlockRef$2;
123
+ connectedAIBlockHeight.current = (_connectedAIBlockRef$ = (_connectedAIBlockRef$2 = connectedAIBlockRef.current) === null || _connectedAIBlockRef$2 === void 0 ? void 0 : _connectedAIBlockRef$2.getBoundingClientRect().height) !== null && _connectedAIBlockRef$ !== void 0 ? _connectedAIBlockRef$ : 0;
124
+ }, []);
91
125
  const imagePreview = ImagePreview({
92
126
  data: data,
93
127
  fallbackElementHeight: snippetHeight.current
@@ -100,16 +134,31 @@ const HoverCardResolvedView = ({
100
134
  overrideCss: metadataBlockCss,
101
135
  maxLines: 1,
102
136
  size: SmartLinkSize.Medium
103
- }), !imagePreview && /*#__PURE__*/React.createElement(SnippetBlock, null), /*#__PURE__*/React.createElement(SnippetBlock, {
137
+ }), isAISummaryEnabled &&
138
+ /*#__PURE__*/
139
+ // All custom elements should be contained within a CustomBlock.
140
+ // Flex Container components check whether the direct child is a flex blocks. It removes anything that isn't
141
+ React.createElement(CustomBlock, {
142
+ direction: SmartLinkDirection.Vertical,
143
+ onRender: onConnectedAIBlockRender,
144
+ blockRef: connectedAIBlockRef
145
+ }, /*#__PURE__*/React.createElement(ConnectedAIBlock, {
146
+ imagePreview: !!imagePreview,
147
+ url: url,
148
+ bottomPrimary: bottomPrimary
149
+ })), !isAISummaryEnabled && !imagePreview && /*#__PURE__*/React.createElement(SnippetBlock, {
150
+ status: SmartLinkStatus.Resolved
151
+ }), /*#__PURE__*/React.createElement(SnippetBlock, {
104
152
  testId: 'hidden-snippet',
105
153
  onRender: onSnippetRender,
106
154
  blockRef: snippetBlockRef,
107
155
  overrideCss: hiddenSnippetStyles
108
- }), /*#__PURE__*/React.createElement(MetadataBlock, {
156
+ }), !isAISummaryEnabled && /*#__PURE__*/React.createElement(MetadataBlock, {
109
157
  primary: bottomPrimary,
110
158
  size: SmartLinkSize.Large,
111
159
  overrideCss: metadataBlockCss,
112
- maxLines: 1
160
+ maxLines: 1,
161
+ status: SmartLinkStatus.Resolved
113
162
  }), getBooleanFF('platform.linking-platform.smart-card.enable-hover-card-related-urls') && /*#__PURE__*/React.createElement(RelatedUrlsBlock, {
114
163
  url: url,
115
164
  size: SmartLinkSize.Small
@@ -118,7 +167,7 @@ const HoverCardResolvedView = ({
118
167
  name: ElementName.Provider
119
168
  }],
120
169
  actions: footerActions,
121
- onAIActionChange: onAIActionChange
170
+ aiSummaryMinHeight: connectedAIBlockHeight.current
122
171
  }) : /*#__PURE__*/React.createElement(FooterBlock, {
123
172
  actions: footerActions,
124
173
  size: SmartLinkSize.Large,