@atlaskit/smart-card 40.17.1 → 40.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/dist/cjs/state/hooks/use-ai-summary/ai-summary-service/index.js +5 -7
  3. package/dist/cjs/utils/analytics/analytics.js +1 -1
  4. package/dist/cjs/view/FlexibleCard/components/container/layered-link/index.js +3 -0
  5. package/dist/cjs/view/LinkUrl/HyperlinkResolver/error-boundary.js +17 -0
  6. package/dist/cjs/view/LinkUrl/HyperlinkResolver/hooks/useScheduledRegister.js +82 -0
  7. package/dist/cjs/view/LinkUrl/HyperlinkResolver/index.js +34 -0
  8. package/dist/cjs/view/LinkUrl/HyperlinkResolver/resolve-hyperlink.js +69 -0
  9. package/dist/cjs/view/LinkUrl/index.js +10 -3
  10. package/dist/es2019/state/hooks/use-ai-summary/ai-summary-service/index.js +5 -7
  11. package/dist/es2019/utils/analytics/analytics.js +1 -1
  12. package/dist/es2019/view/FlexibleCard/components/container/layered-link/index.js +3 -0
  13. package/dist/es2019/view/LinkUrl/HyperlinkResolver/error-boundary.js +8 -0
  14. package/dist/es2019/view/LinkUrl/HyperlinkResolver/hooks/useScheduledRegister.js +77 -0
  15. package/dist/es2019/view/LinkUrl/HyperlinkResolver/index.js +26 -0
  16. package/dist/es2019/view/LinkUrl/HyperlinkResolver/resolve-hyperlink.js +58 -0
  17. package/dist/es2019/view/LinkUrl/index.js +8 -2
  18. package/dist/esm/state/hooks/use-ai-summary/ai-summary-service/index.js +5 -7
  19. package/dist/esm/utils/analytics/analytics.js +1 -1
  20. package/dist/esm/view/FlexibleCard/components/container/layered-link/index.js +3 -0
  21. package/dist/esm/view/LinkUrl/HyperlinkResolver/error-boundary.js +10 -0
  22. package/dist/esm/view/LinkUrl/HyperlinkResolver/hooks/useScheduledRegister.js +76 -0
  23. package/dist/esm/view/LinkUrl/HyperlinkResolver/index.js +25 -0
  24. package/dist/esm/view/LinkUrl/HyperlinkResolver/resolve-hyperlink.js +60 -0
  25. package/dist/esm/view/LinkUrl/index.js +10 -3
  26. package/dist/types/common/analytics/generated/analytics.types.d.ts +19 -0
  27. package/dist/types/view/LinkUrl/HyperlinkResolver/error-boundary.d.ts +4 -0
  28. package/dist/types/view/LinkUrl/HyperlinkResolver/hooks/useScheduledRegister.d.ts +5 -0
  29. package/dist/types/view/LinkUrl/HyperlinkResolver/index.d.ts +7 -0
  30. package/dist/types/view/LinkUrl/HyperlinkResolver/resolve-hyperlink.d.ts +3 -0
  31. package/dist/types/view/LinkUrl/types.d.ts +4 -0
  32. package/dist/types-ts4.5/common/analytics/generated/analytics.types.d.ts +19 -0
  33. package/dist/types-ts4.5/view/LinkUrl/HyperlinkResolver/error-boundary.d.ts +4 -0
  34. package/dist/types-ts4.5/view/LinkUrl/HyperlinkResolver/hooks/useScheduledRegister.d.ts +5 -0
  35. package/dist/types-ts4.5/view/LinkUrl/HyperlinkResolver/index.d.ts +7 -0
  36. package/dist/types-ts4.5/view/LinkUrl/HyperlinkResolver/resolve-hyperlink.d.ts +3 -0
  37. package/dist/types-ts4.5/view/LinkUrl/types.d.ts +4 -0
  38. package/package.json +6 -6
package/CHANGELOG.md CHANGED
@@ -1,5 +1,26 @@
1
1
  # @atlaskit/smart-card
2
2
 
3
+ ## 40.18.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [`7992070df7ee6`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/7992070df7ee6) -
8
+ Add functionality to enable resolving sharepoint hyperlinks on the renderer
9
+
10
+ ### Patch Changes
11
+
12
+ - Updated dependencies
13
+
14
+ ## 40.17.2
15
+
16
+ ### Patch Changes
17
+
18
+ - [`e6dbebe004a7f`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/e6dbebe004a7f) -
19
+ NAVX-1706 Adding aria-hidden attribute to LayeredLink component to be accessible to users
20
+ - [`6298cfc5a5088`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/6298cfc5a5088) -
21
+ NAVX-1387 cleaning up platform-linking-ai-summary-migration-to-convo-ai
22
+ - Updated dependencies
23
+
3
24
  ## 40.17.1
4
25
 
5
26
  ### Patch Changes
@@ -12,7 +12,6 @@ var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/creat
12
12
  var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
13
13
  var _uuid = _interopRequireDefault(require("uuid"));
14
14
  var _linkingCommon = require("@atlaskit/linking-common");
15
- var _platformFeatureFlags = require("@atlaskit/platform-feature-flags");
16
15
  var _readStream = require("./readStream");
17
16
  var _types = require("./types");
18
17
  var _utils = require("./utils");
@@ -35,12 +34,11 @@ var AISummaryService = exports.AISummaryService = /*#__PURE__*/function () {
35
34
  });
36
35
  (0, _defineProperty2.default)(this, "subscribedStateSetters", new Set());
37
36
  (0, _defineProperty2.default)(this, "getRequestUrl", function (envKey, baseUrlOverride) {
38
- var path = (0, _platformFeatureFlags.fg)('platform-linking-ai-summary-migration-to-convo-ai') ? CONVO_AI_ENDPOINT : 'assist/chat/v1/invoke_agent/stream';
39
37
  if (baseUrlOverride || envKey) {
40
38
  var baseUrl = baseUrlOverride || (0, _linkingCommon.getBaseUrl)(envKey);
41
- return (0, _utils.addPath)(baseUrl, path);
39
+ return (0, _utils.addPath)(baseUrl, CONVO_AI_ENDPOINT);
42
40
  }
43
- return (0, _utils.addPath)('/gateway/api/', path);
41
+ return (0, _utils.addPath)('/gateway/api/', CONVO_AI_ENDPOINT);
44
42
  });
45
43
  (0, _defineProperty2.default)(this, "fetchStream", /*#__PURE__*/(0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee() {
46
44
  var payload, options, response;
@@ -57,11 +55,11 @@ var AISummaryService = exports.AISummaryService = /*#__PURE__*/function () {
57
55
  locale: _this.locale
58
56
  }
59
57
  }, {
60
- ai_feature_input: (0, _platformFeatureFlags.fg)('platform-linking-ai-summary-migration-to-convo-ai') ? {
58
+ ai_feature_input: {
61
59
  content_url: _this.url,
62
60
  content_ari: _this.ari,
63
61
  locale: _this.locale
64
- } : undefined
62
+ }
65
63
  });
66
64
  options = {
67
65
  method: 'POST',
@@ -164,7 +162,7 @@ var AISummaryService = exports.AISummaryService = /*#__PURE__*/function () {
164
162
 
165
163
  //if AI Mate service returns cached summary we get the summary text in one piece as the last message
166
164
  if (chunk.type === 'FINAL_RESPONSE') {
167
- bufferContent = (0, _platformFeatureFlags.fg)('platform-linking-ai-summary-migration-to-convo-ai') ? chunk.message.content : chunk.message.message.content;
165
+ bufferContent = chunk.message.content;
168
166
  }
169
167
  if (!(chunk.type === 'ERROR')) {
170
168
  _context2.next = 22;
@@ -11,7 +11,7 @@ var ANALYTICS_CHANNEL = exports.ANALYTICS_CHANNEL = 'media';
11
11
  var context = exports.context = {
12
12
  componentName: 'smart-cards',
13
13
  packageName: "@atlaskit/smart-card",
14
- packageVersion: "40.17.0"
14
+ packageVersion: "40.17.2"
15
15
  };
16
16
  var TrackQuickActionType = exports.TrackQuickActionType = /*#__PURE__*/function (TrackQuickActionType) {
17
17
  TrackQuickActionType["StatusUpdate"] = "StatusUpdate";
@@ -9,6 +9,7 @@ exports.default = void 0;
9
9
  require("./index.compiled.css");
10
10
  var React = _interopRequireWildcard(require("react"));
11
11
  var _runtime = require("@compiled/react/runtime");
12
+ var _platformFeatureFlags = require("@atlaskit/platform-feature-flags");
12
13
  var _useLinkClicked = require("../../../../../state/analytics/useLinkClicked");
13
14
  function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function _interopRequireWildcard(e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != _typeof(e) && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (var _t in e) "default" !== _t && {}.hasOwnProperty.call(e, _t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, _t)) && (i.get || i.set) ? o(f, _t, i) : f[_t] = e[_t]); return f; })(e, t); }
14
15
  var styles = null;
@@ -34,6 +35,8 @@ var LayeredLink = function LayeredLink(_ref) {
34
35
  onMouseDown: onMouseDown,
35
36
  target: target,
36
37
  tabIndex: -1 // Hide tab index and let the title link be the link.
38
+ ,
39
+ "aria-hidden": (0, _platformFeatureFlags.fg)('navx-1706-smart-link-layered-link-a11y-update') // This is to avoid screen readers reading out the link twice.
37
40
  }, text);
38
41
  };
39
42
  var _default = exports.default = LayeredLink;
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
+ Object.defineProperty(exports, "__esModule", {
5
+ value: true
6
+ });
7
+ exports.default = void 0;
8
+ var _react = _interopRequireDefault(require("react"));
9
+ var _reactErrorBoundary = require("react-error-boundary");
10
+ var withErrorBoundary = function withErrorBoundary(Component) {
11
+ return function (props) {
12
+ return /*#__PURE__*/_react.default.createElement(_reactErrorBoundary.ErrorBoundary, {
13
+ fallback: null
14
+ }, /*#__PURE__*/_react.default.createElement(Component, props));
15
+ };
16
+ };
17
+ var _default = exports.default = withErrorBoundary;
@@ -0,0 +1,82 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.useScheduledRegister = void 0;
7
+ var _react = require("react");
8
+ /**
9
+ * This is a scheduled batched register mechanism for resolving blue hyperlinks while the page is idle.
10
+ * i.e. SharePoint tenants with the same hostname will be grouped together before the register is made.
11
+ */
12
+
13
+ var batchQueue = new Map();
14
+ var batchTimeouts = new Map();
15
+ var BATCH_DELAY = 250;
16
+ var executeBatch = function executeBatch(hostname) {
17
+ var items = batchQueue.get(hostname) || [];
18
+ if (items.length === 0) {
19
+ return;
20
+ }
21
+ batchQueue.delete(hostname);
22
+ batchTimeouts.delete(hostname);
23
+ items.forEach(function (_ref) {
24
+ var register = _ref.register,
25
+ resolve = _ref.resolve,
26
+ reject = _ref.reject;
27
+ register().then(resolve).catch(reject);
28
+ });
29
+ };
30
+ var addToBatch = function addToBatch(hostname, item) {
31
+ if (!batchQueue.has(hostname)) {
32
+ batchQueue.set(hostname, []);
33
+ }
34
+ batchQueue.get(hostname).push(item);
35
+ if (batchTimeouts.has(hostname)) {
36
+ clearTimeout(batchTimeouts.get(hostname));
37
+ }
38
+ batchTimeouts.set(hostname, setTimeout(function () {
39
+ executeBatch(hostname);
40
+ }, BATCH_DELAY));
41
+ };
42
+ var useScheduledRegister = exports.useScheduledRegister = function useScheduledRegister(href, register) {
43
+ var isScheduled = (0, _react.useRef)(false);
44
+ var scheduledRegister = (0, _react.useCallback)(function () {
45
+ if (!href || !register || isScheduled.current) {
46
+ return Promise.resolve();
47
+ }
48
+ isScheduled.current = true;
49
+ return new Promise(function (_resolve, _reject) {
50
+ var scheduleRegister = function scheduleRegister() {
51
+ try {
52
+ var hostname = new URL(href).hostname;
53
+ addToBatch(hostname, {
54
+ href: href,
55
+ register: register,
56
+ resolve: function resolve(value) {
57
+ isScheduled.current = false;
58
+ _resolve(value);
59
+ },
60
+ reject: function reject(error) {
61
+ isScheduled.current = false;
62
+ _reject(error);
63
+ }
64
+ });
65
+ } catch (error) {
66
+ isScheduled.current = false;
67
+ register().then(_resolve).catch(_reject);
68
+ }
69
+ };
70
+ if (typeof window !== 'undefined') {
71
+ if ('requestIdleCallback' in window) {
72
+ window.requestIdleCallback(scheduleRegister);
73
+ } else {
74
+ setTimeout(scheduleRegister, 0);
75
+ }
76
+ } else {
77
+ scheduleRegister();
78
+ }
79
+ });
80
+ }, [href, register]);
81
+ return scheduledRegister;
82
+ };
@@ -0,0 +1,34 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
+ var _typeof = require("@babel/runtime/helpers/typeof");
5
+ Object.defineProperty(exports, "__esModule", {
6
+ value: true
7
+ });
8
+ exports.isSharePointDomain = exports.default = void 0;
9
+ var _react = _interopRequireWildcard(require("react"));
10
+ var _featureGateJsClient = _interopRequireDefault(require("@atlaskit/feature-gate-js-client"));
11
+ var _state = require("../../../state");
12
+ var _errorBoundary = _interopRequireDefault(require("./error-boundary"));
13
+ var _resolveHyperlink = require("./resolve-hyperlink");
14
+ function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function _interopRequireWildcard(e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != _typeof(e) && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (var _t in e) "default" !== _t && {}.hasOwnProperty.call(e, _t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, _t)) && (i.get || i.set) ? o(f, _t, i) : f[_t] = e[_t]); return f; })(e, t); }
15
+ var isSharePointDomain = exports.isSharePointDomain = function isSharePointDomain(href) {
16
+ try {
17
+ var hostname = new URL(href).hostname.toLowerCase();
18
+ return hostname.includes('sharepoint.com') || hostname.includes('onedrive.com') || hostname.includes('.live.com');
19
+ } catch (_unused) {
20
+ return false;
21
+ }
22
+ };
23
+ var HyperlinkResolver = function HyperlinkResolver(_ref) {
24
+ var href = _ref.href;
25
+ var hasSmartCardProvider = !!(0, _react.useContext)(_state.SmartCardContext);
26
+ var isHyperlinkResolveExperimentEnabled = _featureGateJsClient.default.getExperimentValue('platform_editor_resolve_hyperlinks_confluence', 'isEnabled', false) || _featureGateJsClient.default.getExperimentValue('platform_editor_resolve_hyperlinks_jira', 'isEnabled', false);
27
+ if (!isSharePointDomain(href) || !hasSmartCardProvider || !isHyperlinkResolveExperimentEnabled) {
28
+ return null;
29
+ }
30
+ return /*#__PURE__*/_react.default.createElement(_resolveHyperlink.ResolveHyperlink, {
31
+ href: href
32
+ });
33
+ };
34
+ var _default = exports.default = (0, _errorBoundary.default)(HyperlinkResolver);
@@ -0,0 +1,69 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
+ var _typeof = require("@babel/runtime/helpers/typeof");
5
+ Object.defineProperty(exports, "__esModule", {
6
+ value: true
7
+ });
8
+ exports.ResolveHyperlink = void 0;
9
+ var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
10
+ var _react = require("react");
11
+ var _uuid = _interopRequireDefault(require("uuid"));
12
+ var _useAnalyticsEvents2 = require("../../../common/analytics/generated/use-analytics-events");
13
+ var _actions = require("../../../state/actions");
14
+ var _helpers = require("../../../state/helpers");
15
+ var _store = require("../../../state/store");
16
+ var measure = _interopRequireWildcard(require("../../../utils/performance"));
17
+ var _useScheduledRegister = require("./hooks/useScheduledRegister");
18
+ function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function _interopRequireWildcard(e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != _typeof(e) && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (var _t in e) "default" !== _t && {}.hasOwnProperty.call(e, _t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, _t)) && (i.get || i.set) ? o(f, _t, i) : f[_t] = e[_t]); return f; })(e, t); }
19
+ var ResolveHyperlink = exports.ResolveHyperlink = function ResolveHyperlink(_ref) {
20
+ var href = _ref.href;
21
+ var _useState = (0, _react.useState)(function () {
22
+ return (0, _uuid.default)();
23
+ }),
24
+ _useState2 = (0, _slicedToArray2.default)(_useState, 1),
25
+ id = _useState2[0];
26
+ var state = (0, _store.useSmartCardState)(href);
27
+ var definitionId = (0, _helpers.getDefinitionId)(state.details);
28
+ var extensionKey = (0, _helpers.getExtensionKey)(state.details);
29
+ var resourceType = (0, _helpers.getResourceType)(state.details);
30
+ var _useSmartCardActions = (0, _actions.useSmartCardActions)(id, href),
31
+ register = _useSmartCardActions.register;
32
+ var scheduledRegister = (0, _useScheduledRegister.useScheduledRegister)(href, register);
33
+ var _useAnalyticsEvents = (0, _useAnalyticsEvents2.useAnalyticsEvents)(),
34
+ fireEvent = _useAnalyticsEvents.fireEvent;
35
+ (0, _react.useEffect)(function () {
36
+ scheduledRegister().catch(function (error) {
37
+ throw error;
38
+ });
39
+ }, [scheduledRegister]);
40
+ (0, _react.useEffect)(function () {
41
+ measure.mark(id, state.status);
42
+ if (state.status !== 'pending' && state.status !== 'resolving') {
43
+ var _state$error, _state$error2;
44
+ measure.create(id, state.status);
45
+ if (state.status === 'resolved') {
46
+ var _measure$getMeasure$d, _measure$getMeasure;
47
+ fireEvent('operational.hyperlink.resolved', {
48
+ definitionId: definitionId !== null && definitionId !== void 0 ? definitionId : null,
49
+ extensionKey: extensionKey !== null && extensionKey !== void 0 ? extensionKey : null,
50
+ resourceType: resourceType !== null && resourceType !== void 0 ? resourceType : null,
51
+ duration: (_measure$getMeasure$d = (_measure$getMeasure = measure.getMeasure(id, state.status)) === null || _measure$getMeasure === void 0 ? void 0 : _measure$getMeasure.duration) !== null && _measure$getMeasure$d !== void 0 ? _measure$getMeasure$d : null
52
+ });
53
+ } else if (((_state$error = state.error) === null || _state$error === void 0 ? void 0 : _state$error.type) !== 'ResolveUnsupportedError' && ((_state$error2 = state.error) === null || _state$error2 === void 0 ? void 0 : _state$error2.type) !== 'UnsupportedError') {
54
+ fireEvent('operational.hyperlink.unresolved', {
55
+ definitionId: definitionId !== null && definitionId !== void 0 ? definitionId : null,
56
+ extensionKey: extensionKey !== null && extensionKey !== void 0 ? extensionKey : null,
57
+ resourceType: resourceType !== null && resourceType !== void 0 ? resourceType : null,
58
+ reason: state.status,
59
+ error: state.error === undefined ? null : {
60
+ name: state.error.name,
61
+ kind: state.error.kind,
62
+ type: state.error.type
63
+ }
64
+ });
65
+ }
66
+ }
67
+ }, [id, state.status, state.error, definitionId, extensionKey, resourceType, fireEvent]);
68
+ return null;
69
+ };
@@ -10,16 +10,18 @@ var _objectWithoutProperties2 = _interopRequireDefault(require("@babel/runtime/h
10
10
  var _react = _interopRequireDefault(require("react"));
11
11
  var _reactMagneticDi = require("react-magnetic-di");
12
12
  var _analyticsNext = require("@atlaskit/analytics-next");
13
+ var _featureGateJsClient = _interopRequireDefault(require("@atlaskit/feature-gate-js-client"));
13
14
  var _link = _interopRequireDefault(require("@atlaskit/link"));
14
15
  var _click = require("../../utils/analytics/click");
15
16
  var _LinkAnalyticsContext = require("../../utils/analytics/LinkAnalyticsContext");
17
+ var _HyperlinkResolver = _interopRequireDefault(require("./HyperlinkResolver"));
16
18
  var _LinkWarningModal = _interopRequireDefault(require("./LinkWarningModal"));
17
19
  var _useLinkWarningModal2 = require("./LinkWarningModal/hooks/use-link-warning-modal");
18
- var _excluded = ["href", "children", "checkSafety", "onClick", "testId", "isLinkComponent"],
20
+ var _excluded = ["href", "children", "checkSafety", "onClick", "testId", "isLinkComponent", "enableResolve"],
19
21
  _excluded2 = ["isLinkSafe", "showSafetyWarningModal"];
20
22
  var PACKAGE_DATA = {
21
23
  packageName: "@atlaskit/smart-card",
22
- packageVersion: "40.17.0",
24
+ packageVersion: "40.17.2",
23
25
  componentName: 'linkUrl'
24
26
  };
25
27
  var Anchor = (0, _click.withLinkClickedEvent)('a');
@@ -34,12 +36,15 @@ var LinkUrl = function LinkUrl(_ref) {
34
36
  testId = _ref$testId === void 0 ? 'link-with-safety' : _ref$testId,
35
37
  _ref$isLinkComponent = _ref.isLinkComponent,
36
38
  isLinkComponent = _ref$isLinkComponent === void 0 ? false : _ref$isLinkComponent,
39
+ _ref$enableResolve = _ref.enableResolve,
40
+ enableResolve = _ref$enableResolve === void 0 ? false : _ref$enableResolve,
37
41
  props = (0, _objectWithoutProperties2.default)(_ref, _excluded);
38
42
  var _useLinkWarningModal = (0, _useLinkWarningModal2.useLinkWarningModal)(),
39
43
  isLinkSafe = _useLinkWarningModal.isLinkSafe,
40
44
  showSafetyWarningModal = _useLinkWarningModal.showSafetyWarningModal,
41
45
  linkWarningModalProps = (0, _objectWithoutProperties2.default)(_useLinkWarningModal, _excluded2);
42
46
  var Link = isLinkComponent ? LinkComponent : Anchor;
47
+ var resolveHyperlinkFG = _featureGateJsClient.default.checkGate('platform_editor_resolve_hyperlinks_killswitch');
43
48
  return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement(_LinkAnalyticsContext.LinkAnalyticsContext, {
44
49
  url: href,
45
50
  display: "url"
@@ -62,6 +67,8 @@ var LinkUrl = function LinkUrl(_ref) {
62
67
  showSafetyWarningModal(e, href);
63
68
  }
64
69
  }
65
- }, props), children)), checkSafety && /*#__PURE__*/_react.default.createElement(_LinkWarningModal.default, linkWarningModalProps));
70
+ }, props), children)), checkSafety && /*#__PURE__*/_react.default.createElement(_LinkWarningModal.default, linkWarningModalProps), enableResolve && href && resolveHyperlinkFG && /*#__PURE__*/_react.default.createElement(_HyperlinkResolver.default, {
71
+ href: href
72
+ }));
66
73
  };
67
74
  var _default = exports.default = (0, _analyticsNext.withAnalyticsContext)(PACKAGE_DATA)(LinkUrl);
@@ -1,7 +1,6 @@
1
1
  import _defineProperty from "@babel/runtime/helpers/defineProperty";
2
2
  import uuid from 'uuid';
3
3
  import { getBaseUrl } from '@atlaskit/linking-common';
4
- import { fg } from '@atlaskit/platform-feature-flags';
5
4
  import { readStream } from './readStream';
6
5
  import { ChunkProcessingError } from './types';
7
6
  import { addPath, getXProductHeaderValue } from './utils';
@@ -15,12 +14,11 @@ export class AISummaryService {
15
14
  });
16
15
  _defineProperty(this, "subscribedStateSetters", new Set());
17
16
  _defineProperty(this, "getRequestUrl", (envKey, baseUrlOverride) => {
18
- const path = fg('platform-linking-ai-summary-migration-to-convo-ai') ? CONVO_AI_ENDPOINT : 'assist/chat/v1/invoke_agent/stream';
19
17
  if (baseUrlOverride || envKey) {
20
18
  const baseUrl = baseUrlOverride || getBaseUrl(envKey);
21
- return addPath(baseUrl, path);
19
+ return addPath(baseUrl, CONVO_AI_ENDPOINT);
22
20
  }
23
- return addPath('/gateway/api/', path);
21
+ return addPath('/gateway/api/', CONVO_AI_ENDPOINT);
24
22
  });
25
23
  _defineProperty(this, "fetchStream", async () => {
26
24
  const payload = {
@@ -33,11 +31,11 @@ export class AISummaryService {
33
31
  locale: this.locale
34
32
  },
35
33
  ...{
36
- ai_feature_input: fg('platform-linking-ai-summary-migration-to-convo-ai') ? {
34
+ ai_feature_input: {
37
35
  content_url: this.url,
38
36
  content_ari: this.ari,
39
37
  locale: this.locale
40
- } : undefined
38
+ }
41
39
  }
42
40
  };
43
41
  const options = {
@@ -95,7 +93,7 @@ export class AISummaryService {
95
93
 
96
94
  //if AI Mate service returns cached summary we get the summary text in one piece as the last message
97
95
  if (chunk.type === 'FINAL_RESPONSE') {
98
- bufferContent = fg('platform-linking-ai-summary-migration-to-convo-ai') ? chunk.message.content : chunk.message.message.content;
96
+ bufferContent = chunk.message.content;
99
97
  }
100
98
  if (chunk.type === 'ERROR') {
101
99
  var _chunk$message;
@@ -2,7 +2,7 @@ export const ANALYTICS_CHANNEL = 'media';
2
2
  export const context = {
3
3
  componentName: 'smart-cards',
4
4
  packageName: "@atlaskit/smart-card",
5
- packageVersion: "40.17.0"
5
+ packageVersion: "40.17.2"
6
6
  };
7
7
  export let TrackQuickActionType = /*#__PURE__*/function (TrackQuickActionType) {
8
8
  TrackQuickActionType["StatusUpdate"] = "StatusUpdate";
@@ -2,6 +2,7 @@
2
2
  import "./index.compiled.css";
3
3
  import * as React from 'react';
4
4
  import { ax, ix } from "@compiled/react/runtime";
5
+ import { fg } from '@atlaskit/platform-feature-flags';
5
6
  import { useMouseDownEvent } from '../../../../../state/analytics/useLinkClicked';
6
7
  const styles = null;
7
8
 
@@ -27,6 +28,8 @@ const LayeredLink = ({
27
28
  onMouseDown: onMouseDown,
28
29
  target: target,
29
30
  tabIndex: -1 // Hide tab index and let the title link be the link.
31
+ ,
32
+ "aria-hidden": fg('navx-1706-smart-link-layered-link-a11y-update') // This is to avoid screen readers reading out the link twice.
30
33
  }, text);
31
34
  };
32
35
  export default LayeredLink;
@@ -0,0 +1,8 @@
1
+ import React from 'react';
2
+ import { ErrorBoundary } from 'react-error-boundary';
3
+ const withErrorBoundary = Component => props => {
4
+ return /*#__PURE__*/React.createElement(ErrorBoundary, {
5
+ fallback: null
6
+ }, /*#__PURE__*/React.createElement(Component, props));
7
+ };
8
+ export default withErrorBoundary;
@@ -0,0 +1,77 @@
1
+ /**
2
+ * This is a scheduled batched register mechanism for resolving blue hyperlinks while the page is idle.
3
+ * i.e. SharePoint tenants with the same hostname will be grouped together before the register is made.
4
+ */
5
+
6
+ import { useCallback, useRef } from 'react';
7
+ const batchQueue = new Map();
8
+ const batchTimeouts = new Map();
9
+ const BATCH_DELAY = 250;
10
+ const executeBatch = hostname => {
11
+ const items = batchQueue.get(hostname) || [];
12
+ if (items.length === 0) {
13
+ return;
14
+ }
15
+ batchQueue.delete(hostname);
16
+ batchTimeouts.delete(hostname);
17
+ items.forEach(({
18
+ register,
19
+ resolve,
20
+ reject
21
+ }) => {
22
+ register().then(resolve).catch(reject);
23
+ });
24
+ };
25
+ const addToBatch = (hostname, item) => {
26
+ if (!batchQueue.has(hostname)) {
27
+ batchQueue.set(hostname, []);
28
+ }
29
+ batchQueue.get(hostname).push(item);
30
+ if (batchTimeouts.has(hostname)) {
31
+ clearTimeout(batchTimeouts.get(hostname));
32
+ }
33
+ batchTimeouts.set(hostname, setTimeout(() => {
34
+ executeBatch(hostname);
35
+ }, BATCH_DELAY));
36
+ };
37
+ export const useScheduledRegister = (href, register) => {
38
+ const isScheduled = useRef(false);
39
+ const scheduledRegister = useCallback(() => {
40
+ if (!href || !register || isScheduled.current) {
41
+ return Promise.resolve();
42
+ }
43
+ isScheduled.current = true;
44
+ return new Promise((resolve, reject) => {
45
+ const scheduleRegister = () => {
46
+ try {
47
+ const hostname = new URL(href).hostname;
48
+ addToBatch(hostname, {
49
+ href,
50
+ register,
51
+ resolve: value => {
52
+ isScheduled.current = false;
53
+ resolve(value);
54
+ },
55
+ reject: error => {
56
+ isScheduled.current = false;
57
+ reject(error);
58
+ }
59
+ });
60
+ } catch (error) {
61
+ isScheduled.current = false;
62
+ register().then(resolve).catch(reject);
63
+ }
64
+ };
65
+ if (typeof window !== 'undefined') {
66
+ if ('requestIdleCallback' in window) {
67
+ window.requestIdleCallback(scheduleRegister);
68
+ } else {
69
+ setTimeout(scheduleRegister, 0);
70
+ }
71
+ } else {
72
+ scheduleRegister();
73
+ }
74
+ });
75
+ }, [href, register]);
76
+ return scheduledRegister;
77
+ };
@@ -0,0 +1,26 @@
1
+ import React, { useContext } from 'react';
2
+ import FeatureGates from '@atlaskit/feature-gate-js-client';
3
+ import { SmartCardContext } from '../../../state';
4
+ import withErrorBoundary from './error-boundary';
5
+ import { ResolveHyperlink } from './resolve-hyperlink';
6
+ export const isSharePointDomain = href => {
7
+ try {
8
+ const hostname = new URL(href).hostname.toLowerCase();
9
+ return hostname.includes('sharepoint.com') || hostname.includes('onedrive.com') || hostname.includes('.live.com');
10
+ } catch {
11
+ return false;
12
+ }
13
+ };
14
+ const HyperlinkResolver = ({
15
+ href
16
+ }) => {
17
+ const hasSmartCardProvider = !!useContext(SmartCardContext);
18
+ const isHyperlinkResolveExperimentEnabled = FeatureGates.getExperimentValue('platform_editor_resolve_hyperlinks_confluence', 'isEnabled', false) || FeatureGates.getExperimentValue('platform_editor_resolve_hyperlinks_jira', 'isEnabled', false);
19
+ if (!isSharePointDomain(href) || !hasSmartCardProvider || !isHyperlinkResolveExperimentEnabled) {
20
+ return null;
21
+ }
22
+ return /*#__PURE__*/React.createElement(ResolveHyperlink, {
23
+ href: href
24
+ });
25
+ };
26
+ export default withErrorBoundary(HyperlinkResolver);
@@ -0,0 +1,58 @@
1
+ import { useEffect, useState } from "react";
2
+ import uuid from 'uuid';
3
+ import { useAnalyticsEvents } from '../../../common/analytics/generated/use-analytics-events';
4
+ import { useSmartCardActions } from '../../../state/actions';
5
+ import { getDefinitionId, getExtensionKey, getResourceType } from '../../../state/helpers';
6
+ import { useSmartCardState } from '../../../state/store';
7
+ import * as measure from '../../../utils/performance';
8
+ import { useScheduledRegister } from "./hooks/useScheduledRegister";
9
+ export const ResolveHyperlink = ({
10
+ href
11
+ }) => {
12
+ const [id] = useState(() => uuid());
13
+ const state = useSmartCardState(href);
14
+ const definitionId = getDefinitionId(state.details);
15
+ const extensionKey = getExtensionKey(state.details);
16
+ const resourceType = getResourceType(state.details);
17
+ const {
18
+ register
19
+ } = useSmartCardActions(id, href);
20
+ const scheduledRegister = useScheduledRegister(href, register);
21
+ const {
22
+ fireEvent
23
+ } = useAnalyticsEvents();
24
+ useEffect(() => {
25
+ scheduledRegister().catch(error => {
26
+ throw error;
27
+ });
28
+ }, [scheduledRegister]);
29
+ useEffect(() => {
30
+ measure.mark(id, state.status);
31
+ if (state.status !== 'pending' && state.status !== 'resolving') {
32
+ var _state$error, _state$error2;
33
+ measure.create(id, state.status);
34
+ if (state.status === 'resolved') {
35
+ var _measure$getMeasure$d, _measure$getMeasure;
36
+ fireEvent('operational.hyperlink.resolved', {
37
+ definitionId: definitionId !== null && definitionId !== void 0 ? definitionId : null,
38
+ extensionKey: extensionKey !== null && extensionKey !== void 0 ? extensionKey : null,
39
+ resourceType: resourceType !== null && resourceType !== void 0 ? resourceType : null,
40
+ duration: (_measure$getMeasure$d = (_measure$getMeasure = measure.getMeasure(id, state.status)) === null || _measure$getMeasure === void 0 ? void 0 : _measure$getMeasure.duration) !== null && _measure$getMeasure$d !== void 0 ? _measure$getMeasure$d : null
41
+ });
42
+ } else if (((_state$error = state.error) === null || _state$error === void 0 ? void 0 : _state$error.type) !== 'ResolveUnsupportedError' && ((_state$error2 = state.error) === null || _state$error2 === void 0 ? void 0 : _state$error2.type) !== 'UnsupportedError') {
43
+ fireEvent('operational.hyperlink.unresolved', {
44
+ definitionId: definitionId !== null && definitionId !== void 0 ? definitionId : null,
45
+ extensionKey: extensionKey !== null && extensionKey !== void 0 ? extensionKey : null,
46
+ resourceType: resourceType !== null && resourceType !== void 0 ? resourceType : null,
47
+ reason: state.status,
48
+ error: state.error === undefined ? null : {
49
+ name: state.error.name,
50
+ kind: state.error.kind,
51
+ type: state.error.type
52
+ }
53
+ });
54
+ }
55
+ }
56
+ }, [id, state.status, state.error, definitionId, extensionKey, resourceType, fireEvent]);
57
+ return null;
58
+ };
@@ -2,14 +2,16 @@ import _extends from "@babel/runtime/helpers/extends";
2
2
  import React from 'react';
3
3
  import { di } from 'react-magnetic-di';
4
4
  import { withAnalyticsContext } from '@atlaskit/analytics-next';
5
+ import FeatureGates from '@atlaskit/feature-gate-js-client';
5
6
  import AKLink from '@atlaskit/link';
6
7
  import { withLinkClickedEvent } from '../../utils/analytics/click';
7
8
  import { LinkAnalyticsContext } from '../../utils/analytics/LinkAnalyticsContext';
9
+ import HyperlinkResolver from './HyperlinkResolver';
8
10
  import LinkWarningModal from './LinkWarningModal';
9
11
  import { useLinkWarningModal } from './LinkWarningModal/hooks/use-link-warning-modal';
10
12
  const PACKAGE_DATA = {
11
13
  packageName: "@atlaskit/smart-card",
12
- packageVersion: "40.17.0",
14
+ packageVersion: "40.17.2",
13
15
  componentName: 'linkUrl'
14
16
  };
15
17
  const Anchor = withLinkClickedEvent('a');
@@ -21,6 +23,7 @@ const LinkUrl = ({
21
23
  onClick,
22
24
  testId = 'link-with-safety',
23
25
  isLinkComponent = false,
26
+ enableResolve = false,
24
27
  ...props
25
28
  }) => {
26
29
  const {
@@ -29,6 +32,7 @@ const LinkUrl = ({
29
32
  ...linkWarningModalProps
30
33
  } = useLinkWarningModal();
31
34
  const Link = isLinkComponent ? LinkComponent : Anchor;
35
+ const resolveHyperlinkFG = FeatureGates.checkGate('platform_editor_resolve_hyperlinks_killswitch');
32
36
  return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(LinkAnalyticsContext, {
33
37
  url: href,
34
38
  display: "url"
@@ -51,6 +55,8 @@ const LinkUrl = ({
51
55
  showSafetyWarningModal(e, href);
52
56
  }
53
57
  }
54
- }, props), children)), checkSafety && /*#__PURE__*/React.createElement(LinkWarningModal, linkWarningModalProps));
58
+ }, props), children)), checkSafety && /*#__PURE__*/React.createElement(LinkWarningModal, linkWarningModalProps), enableResolve && href && resolveHyperlinkFG && /*#__PURE__*/React.createElement(HyperlinkResolver, {
59
+ href: href
60
+ }));
55
61
  };
56
62
  export default withAnalyticsContext(PACKAGE_DATA)(LinkUrl);
@@ -12,7 +12,6 @@ function _asyncIterator(r) { var n, t, o, e = 2; for ("undefined" != typeof Symb
12
12
  function AsyncFromSyncIterator(r) { function AsyncFromSyncIteratorContinuation(r) { if (Object(r) !== r) return Promise.reject(new TypeError(r + " is not an object.")); var n = r.done; return Promise.resolve(r.value).then(function (r) { return { value: r, done: n }; }); } return AsyncFromSyncIterator = function AsyncFromSyncIterator(r) { this.s = r, this.n = r.next; }, AsyncFromSyncIterator.prototype = { s: null, n: null, next: function next() { return AsyncFromSyncIteratorContinuation(this.n.apply(this.s, arguments)); }, return: function _return(r) { var n = this.s.return; return void 0 === n ? Promise.resolve({ value: r, done: !0 }) : AsyncFromSyncIteratorContinuation(n.apply(this.s, arguments)); }, throw: function _throw(r) { var n = this.s.return; return void 0 === n ? Promise.reject(r) : AsyncFromSyncIteratorContinuation(n.apply(this.s, arguments)); } }, new AsyncFromSyncIterator(r); }
13
13
  import uuid from 'uuid';
14
14
  import { getBaseUrl } from '@atlaskit/linking-common';
15
- import { fg } from '@atlaskit/platform-feature-flags';
16
15
  import { readStream } from './readStream';
17
16
  import { ChunkProcessingError } from './types';
18
17
  import { addPath, getXProductHeaderValue } from './utils';
@@ -28,12 +27,11 @@ export var AISummaryService = /*#__PURE__*/function () {
28
27
  });
29
28
  _defineProperty(this, "subscribedStateSetters", new Set());
30
29
  _defineProperty(this, "getRequestUrl", function (envKey, baseUrlOverride) {
31
- var path = fg('platform-linking-ai-summary-migration-to-convo-ai') ? CONVO_AI_ENDPOINT : 'assist/chat/v1/invoke_agent/stream';
32
30
  if (baseUrlOverride || envKey) {
33
31
  var baseUrl = baseUrlOverride || getBaseUrl(envKey);
34
- return addPath(baseUrl, path);
32
+ return addPath(baseUrl, CONVO_AI_ENDPOINT);
35
33
  }
36
- return addPath('/gateway/api/', path);
34
+ return addPath('/gateway/api/', CONVO_AI_ENDPOINT);
37
35
  });
38
36
  _defineProperty(this, "fetchStream", /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee() {
39
37
  var payload, options, response;
@@ -50,11 +48,11 @@ export var AISummaryService = /*#__PURE__*/function () {
50
48
  locale: _this.locale
51
49
  }
52
50
  }, {
53
- ai_feature_input: fg('platform-linking-ai-summary-migration-to-convo-ai') ? {
51
+ ai_feature_input: {
54
52
  content_url: _this.url,
55
53
  content_ari: _this.ari,
56
54
  locale: _this.locale
57
- } : undefined
55
+ }
58
56
  });
59
57
  options = {
60
58
  method: 'POST',
@@ -157,7 +155,7 @@ export var AISummaryService = /*#__PURE__*/function () {
157
155
 
158
156
  //if AI Mate service returns cached summary we get the summary text in one piece as the last message
159
157
  if (chunk.type === 'FINAL_RESPONSE') {
160
- bufferContent = fg('platform-linking-ai-summary-migration-to-convo-ai') ? chunk.message.content : chunk.message.message.content;
158
+ bufferContent = chunk.message.content;
161
159
  }
162
160
  if (!(chunk.type === 'ERROR')) {
163
161
  _context2.next = 22;
@@ -4,7 +4,7 @@ export var ANALYTICS_CHANNEL = 'media';
4
4
  export var context = {
5
5
  componentName: 'smart-cards',
6
6
  packageName: "@atlaskit/smart-card",
7
- packageVersion: "40.17.0"
7
+ packageVersion: "40.17.2"
8
8
  };
9
9
  export var TrackQuickActionType = /*#__PURE__*/function (TrackQuickActionType) {
10
10
  TrackQuickActionType["StatusUpdate"] = "StatusUpdate";
@@ -2,6 +2,7 @@
2
2
  import "./index.compiled.css";
3
3
  import * as React from 'react';
4
4
  import { ax, ix } from "@compiled/react/runtime";
5
+ import { fg } from '@atlaskit/platform-feature-flags';
5
6
  import { useMouseDownEvent } from '../../../../../state/analytics/useLinkClicked';
6
7
  var styles = null;
7
8
 
@@ -26,6 +27,8 @@ var LayeredLink = function LayeredLink(_ref) {
26
27
  onMouseDown: onMouseDown,
27
28
  target: target,
28
29
  tabIndex: -1 // Hide tab index and let the title link be the link.
30
+ ,
31
+ "aria-hidden": fg('navx-1706-smart-link-layered-link-a11y-update') // This is to avoid screen readers reading out the link twice.
29
32
  }, text);
30
33
  };
31
34
  export default LayeredLink;
@@ -0,0 +1,10 @@
1
+ import React from 'react';
2
+ import { ErrorBoundary } from 'react-error-boundary';
3
+ var withErrorBoundary = function withErrorBoundary(Component) {
4
+ return function (props) {
5
+ return /*#__PURE__*/React.createElement(ErrorBoundary, {
6
+ fallback: null
7
+ }, /*#__PURE__*/React.createElement(Component, props));
8
+ };
9
+ };
10
+ export default withErrorBoundary;
@@ -0,0 +1,76 @@
1
+ /**
2
+ * This is a scheduled batched register mechanism for resolving blue hyperlinks while the page is idle.
3
+ * i.e. SharePoint tenants with the same hostname will be grouped together before the register is made.
4
+ */
5
+
6
+ import { useCallback, useRef } from 'react';
7
+ var batchQueue = new Map();
8
+ var batchTimeouts = new Map();
9
+ var BATCH_DELAY = 250;
10
+ var executeBatch = function executeBatch(hostname) {
11
+ var items = batchQueue.get(hostname) || [];
12
+ if (items.length === 0) {
13
+ return;
14
+ }
15
+ batchQueue.delete(hostname);
16
+ batchTimeouts.delete(hostname);
17
+ items.forEach(function (_ref) {
18
+ var register = _ref.register,
19
+ resolve = _ref.resolve,
20
+ reject = _ref.reject;
21
+ register().then(resolve).catch(reject);
22
+ });
23
+ };
24
+ var addToBatch = function addToBatch(hostname, item) {
25
+ if (!batchQueue.has(hostname)) {
26
+ batchQueue.set(hostname, []);
27
+ }
28
+ batchQueue.get(hostname).push(item);
29
+ if (batchTimeouts.has(hostname)) {
30
+ clearTimeout(batchTimeouts.get(hostname));
31
+ }
32
+ batchTimeouts.set(hostname, setTimeout(function () {
33
+ executeBatch(hostname);
34
+ }, BATCH_DELAY));
35
+ };
36
+ export var useScheduledRegister = function useScheduledRegister(href, register) {
37
+ var isScheduled = useRef(false);
38
+ var scheduledRegister = useCallback(function () {
39
+ if (!href || !register || isScheduled.current) {
40
+ return Promise.resolve();
41
+ }
42
+ isScheduled.current = true;
43
+ return new Promise(function (_resolve, _reject) {
44
+ var scheduleRegister = function scheduleRegister() {
45
+ try {
46
+ var hostname = new URL(href).hostname;
47
+ addToBatch(hostname, {
48
+ href: href,
49
+ register: register,
50
+ resolve: function resolve(value) {
51
+ isScheduled.current = false;
52
+ _resolve(value);
53
+ },
54
+ reject: function reject(error) {
55
+ isScheduled.current = false;
56
+ _reject(error);
57
+ }
58
+ });
59
+ } catch (error) {
60
+ isScheduled.current = false;
61
+ register().then(_resolve).catch(_reject);
62
+ }
63
+ };
64
+ if (typeof window !== 'undefined') {
65
+ if ('requestIdleCallback' in window) {
66
+ window.requestIdleCallback(scheduleRegister);
67
+ } else {
68
+ setTimeout(scheduleRegister, 0);
69
+ }
70
+ } else {
71
+ scheduleRegister();
72
+ }
73
+ });
74
+ }, [href, register]);
75
+ return scheduledRegister;
76
+ };
@@ -0,0 +1,25 @@
1
+ import React, { useContext } from 'react';
2
+ import FeatureGates from '@atlaskit/feature-gate-js-client';
3
+ import { SmartCardContext } from '../../../state';
4
+ import withErrorBoundary from './error-boundary';
5
+ import { ResolveHyperlink } from './resolve-hyperlink';
6
+ export var isSharePointDomain = function isSharePointDomain(href) {
7
+ try {
8
+ var hostname = new URL(href).hostname.toLowerCase();
9
+ return hostname.includes('sharepoint.com') || hostname.includes('onedrive.com') || hostname.includes('.live.com');
10
+ } catch (_unused) {
11
+ return false;
12
+ }
13
+ };
14
+ var HyperlinkResolver = function HyperlinkResolver(_ref) {
15
+ var href = _ref.href;
16
+ var hasSmartCardProvider = !!useContext(SmartCardContext);
17
+ var isHyperlinkResolveExperimentEnabled = FeatureGates.getExperimentValue('platform_editor_resolve_hyperlinks_confluence', 'isEnabled', false) || FeatureGates.getExperimentValue('platform_editor_resolve_hyperlinks_jira', 'isEnabled', false);
18
+ if (!isSharePointDomain(href) || !hasSmartCardProvider || !isHyperlinkResolveExperimentEnabled) {
19
+ return null;
20
+ }
21
+ return /*#__PURE__*/React.createElement(ResolveHyperlink, {
22
+ href: href
23
+ });
24
+ };
25
+ export default withErrorBoundary(HyperlinkResolver);
@@ -0,0 +1,60 @@
1
+ import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
2
+ import { useEffect, useState } from "react";
3
+ import uuid from 'uuid';
4
+ import { useAnalyticsEvents } from '../../../common/analytics/generated/use-analytics-events';
5
+ import { useSmartCardActions } from '../../../state/actions';
6
+ import { getDefinitionId, getExtensionKey, getResourceType } from '../../../state/helpers';
7
+ import { useSmartCardState } from '../../../state/store';
8
+ import * as measure from '../../../utils/performance';
9
+ import { useScheduledRegister } from "./hooks/useScheduledRegister";
10
+ export var ResolveHyperlink = function ResolveHyperlink(_ref) {
11
+ var href = _ref.href;
12
+ var _useState = useState(function () {
13
+ return uuid();
14
+ }),
15
+ _useState2 = _slicedToArray(_useState, 1),
16
+ id = _useState2[0];
17
+ var state = useSmartCardState(href);
18
+ var definitionId = getDefinitionId(state.details);
19
+ var extensionKey = getExtensionKey(state.details);
20
+ var resourceType = getResourceType(state.details);
21
+ var _useSmartCardActions = useSmartCardActions(id, href),
22
+ register = _useSmartCardActions.register;
23
+ var scheduledRegister = useScheduledRegister(href, register);
24
+ var _useAnalyticsEvents = useAnalyticsEvents(),
25
+ fireEvent = _useAnalyticsEvents.fireEvent;
26
+ useEffect(function () {
27
+ scheduledRegister().catch(function (error) {
28
+ throw error;
29
+ });
30
+ }, [scheduledRegister]);
31
+ useEffect(function () {
32
+ measure.mark(id, state.status);
33
+ if (state.status !== 'pending' && state.status !== 'resolving') {
34
+ var _state$error, _state$error2;
35
+ measure.create(id, state.status);
36
+ if (state.status === 'resolved') {
37
+ var _measure$getMeasure$d, _measure$getMeasure;
38
+ fireEvent('operational.hyperlink.resolved', {
39
+ definitionId: definitionId !== null && definitionId !== void 0 ? definitionId : null,
40
+ extensionKey: extensionKey !== null && extensionKey !== void 0 ? extensionKey : null,
41
+ resourceType: resourceType !== null && resourceType !== void 0 ? resourceType : null,
42
+ duration: (_measure$getMeasure$d = (_measure$getMeasure = measure.getMeasure(id, state.status)) === null || _measure$getMeasure === void 0 ? void 0 : _measure$getMeasure.duration) !== null && _measure$getMeasure$d !== void 0 ? _measure$getMeasure$d : null
43
+ });
44
+ } else if (((_state$error = state.error) === null || _state$error === void 0 ? void 0 : _state$error.type) !== 'ResolveUnsupportedError' && ((_state$error2 = state.error) === null || _state$error2 === void 0 ? void 0 : _state$error2.type) !== 'UnsupportedError') {
45
+ fireEvent('operational.hyperlink.unresolved', {
46
+ definitionId: definitionId !== null && definitionId !== void 0 ? definitionId : null,
47
+ extensionKey: extensionKey !== null && extensionKey !== void 0 ? extensionKey : null,
48
+ resourceType: resourceType !== null && resourceType !== void 0 ? resourceType : null,
49
+ reason: state.status,
50
+ error: state.error === undefined ? null : {
51
+ name: state.error.name,
52
+ kind: state.error.kind,
53
+ type: state.error.type
54
+ }
55
+ });
56
+ }
57
+ }
58
+ }, [id, state.status, state.error, definitionId, extensionKey, resourceType, fireEvent]);
59
+ return null;
60
+ };
@@ -1,18 +1,20 @@
1
1
  import _extends from "@babel/runtime/helpers/extends";
2
2
  import _objectWithoutProperties from "@babel/runtime/helpers/objectWithoutProperties";
3
- var _excluded = ["href", "children", "checkSafety", "onClick", "testId", "isLinkComponent"],
3
+ var _excluded = ["href", "children", "checkSafety", "onClick", "testId", "isLinkComponent", "enableResolve"],
4
4
  _excluded2 = ["isLinkSafe", "showSafetyWarningModal"];
5
5
  import React from 'react';
6
6
  import { di } from 'react-magnetic-di';
7
7
  import { withAnalyticsContext } from '@atlaskit/analytics-next';
8
+ import FeatureGates from '@atlaskit/feature-gate-js-client';
8
9
  import AKLink from '@atlaskit/link';
9
10
  import { withLinkClickedEvent } from '../../utils/analytics/click';
10
11
  import { LinkAnalyticsContext } from '../../utils/analytics/LinkAnalyticsContext';
12
+ import HyperlinkResolver from './HyperlinkResolver';
11
13
  import LinkWarningModal from './LinkWarningModal';
12
14
  import { useLinkWarningModal } from './LinkWarningModal/hooks/use-link-warning-modal';
13
15
  var PACKAGE_DATA = {
14
16
  packageName: "@atlaskit/smart-card",
15
- packageVersion: "40.17.0",
17
+ packageVersion: "40.17.2",
16
18
  componentName: 'linkUrl'
17
19
  };
18
20
  var Anchor = withLinkClickedEvent('a');
@@ -27,12 +29,15 @@ var LinkUrl = function LinkUrl(_ref) {
27
29
  testId = _ref$testId === void 0 ? 'link-with-safety' : _ref$testId,
28
30
  _ref$isLinkComponent = _ref.isLinkComponent,
29
31
  isLinkComponent = _ref$isLinkComponent === void 0 ? false : _ref$isLinkComponent,
32
+ _ref$enableResolve = _ref.enableResolve,
33
+ enableResolve = _ref$enableResolve === void 0 ? false : _ref$enableResolve,
30
34
  props = _objectWithoutProperties(_ref, _excluded);
31
35
  var _useLinkWarningModal = useLinkWarningModal(),
32
36
  isLinkSafe = _useLinkWarningModal.isLinkSafe,
33
37
  showSafetyWarningModal = _useLinkWarningModal.showSafetyWarningModal,
34
38
  linkWarningModalProps = _objectWithoutProperties(_useLinkWarningModal, _excluded2);
35
39
  var Link = isLinkComponent ? LinkComponent : Anchor;
40
+ var resolveHyperlinkFG = FeatureGates.checkGate('platform_editor_resolve_hyperlinks_killswitch');
36
41
  return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(LinkAnalyticsContext, {
37
42
  url: href,
38
43
  display: "url"
@@ -55,6 +60,8 @@ var LinkUrl = function LinkUrl(_ref) {
55
60
  showSafetyWarningModal(e, href);
56
61
  }
57
62
  }
58
- }, props), children)), checkSafety && /*#__PURE__*/React.createElement(LinkWarningModal, linkWarningModalProps));
63
+ }, props), children)), checkSafety && /*#__PURE__*/React.createElement(LinkWarningModal, linkWarningModalProps), enableResolve && href && resolveHyperlinkFG && /*#__PURE__*/React.createElement(HyperlinkResolver, {
64
+ href: href
65
+ }));
59
66
  };
60
67
  export default withAnalyticsContext(PACKAGE_DATA)(LinkUrl);
@@ -181,6 +181,19 @@ export type SmartLinkClickedTitleGoToLinkAttributesType = {
181
181
  definitionId: string | null;
182
182
  isModifierKeyPressed: boolean | null;
183
183
  };
184
+ export type HyperlinkResolvedAttributesType = {
185
+ definitionId: string | null;
186
+ extensionKey: string | null;
187
+ resourceType: string | null;
188
+ duration: number | null;
189
+ };
190
+ export type HyperlinkUnresolvedAttributesType = {
191
+ definitionId: string | null;
192
+ extensionKey: string | null;
193
+ resourceType: string | null;
194
+ error: Record<string, unknown> | null;
195
+ reason: string;
196
+ };
184
197
  export type HoverCardViewedAttributesType = {
185
198
  previewDisplay: 'card' | 'embed';
186
199
  previewInvokeMethod: 'keyboard' | 'mouse_hover' | 'mouse_click' | null;
@@ -339,6 +352,12 @@ export type AnalyticsEventAttributes = {
339
352
  /**
340
353
  * Fires an event when a Smart Link action is failed to resolved. */
341
354
  'operational.smartLinkAction.unresolved': SmartLinkActionUnresolvedAttributesType;
355
+ /**
356
+ * Fires an event when a Hyperlink is successfully resolved. */
357
+ 'operational.hyperlink.resolved': HyperlinkResolvedAttributesType;
358
+ /**
359
+ * Fires an event when a Hyperlink is failed to resolve. */
360
+ 'operational.hyperlink.unresolved': HyperlinkUnresolvedAttributesType;
342
361
  /**
343
362
  * fires an event that represents when a user clicks on a Smart Link. */
344
363
  'ui.smartLink.clicked': SmartLinkClickedAttributesType;
@@ -0,0 +1,4 @@
1
+ import React, { type ComponentType } from 'react';
2
+ import type { HyperlinkResolverProps } from './index';
3
+ declare const withErrorBoundary: (Component: ComponentType<HyperlinkResolverProps>) => (props: HyperlinkResolverProps) => React.JSX.Element;
4
+ export default withErrorBoundary;
@@ -0,0 +1,5 @@
1
+ /**
2
+ * This is a scheduled batched register mechanism for resolving blue hyperlinks while the page is idle.
3
+ * i.e. SharePoint tenants with the same hostname will be grouped together before the register is made.
4
+ */
5
+ export declare const useScheduledRegister: (href: string, register: (() => Promise<any>) | null) => () => Promise<void>;
@@ -0,0 +1,7 @@
1
+ import React from 'react';
2
+ export interface HyperlinkResolverProps {
3
+ href: string;
4
+ }
5
+ export declare const isSharePointDomain: (href: string) => boolean;
6
+ declare const _default: (props: HyperlinkResolverProps) => React.JSX.Element;
7
+ export default _default;
@@ -0,0 +1,3 @@
1
+ export declare const ResolveHyperlink: ({ href }: {
2
+ href: string;
3
+ }) => null;
@@ -3,6 +3,10 @@ export interface LinkUrlProps extends React.AnchorHTMLAttributes<HTMLAnchorEleme
3
3
  * Determines if we want to perform a link safety check. True by default.
4
4
  */
5
5
  checkSafety?: boolean;
6
+ /**
7
+ * Determines if we want to resolve the URL in the background for Rovo indexing. This has no impact on the UI/UX. False by default.
8
+ */
9
+ enableResolve?: boolean;
6
10
  isLinkComponent?: boolean;
7
11
  testId?: string;
8
12
  }
@@ -181,6 +181,19 @@ export type SmartLinkClickedTitleGoToLinkAttributesType = {
181
181
  definitionId: string | null;
182
182
  isModifierKeyPressed: boolean | null;
183
183
  };
184
+ export type HyperlinkResolvedAttributesType = {
185
+ definitionId: string | null;
186
+ extensionKey: string | null;
187
+ resourceType: string | null;
188
+ duration: number | null;
189
+ };
190
+ export type HyperlinkUnresolvedAttributesType = {
191
+ definitionId: string | null;
192
+ extensionKey: string | null;
193
+ resourceType: string | null;
194
+ error: Record<string, unknown> | null;
195
+ reason: string;
196
+ };
184
197
  export type HoverCardViewedAttributesType = {
185
198
  previewDisplay: 'card' | 'embed';
186
199
  previewInvokeMethod: 'keyboard' | 'mouse_hover' | 'mouse_click' | null;
@@ -339,6 +352,12 @@ export type AnalyticsEventAttributes = {
339
352
  /**
340
353
  * Fires an event when a Smart Link action is failed to resolved. */
341
354
  'operational.smartLinkAction.unresolved': SmartLinkActionUnresolvedAttributesType;
355
+ /**
356
+ * Fires an event when a Hyperlink is successfully resolved. */
357
+ 'operational.hyperlink.resolved': HyperlinkResolvedAttributesType;
358
+ /**
359
+ * Fires an event when a Hyperlink is failed to resolve. */
360
+ 'operational.hyperlink.unresolved': HyperlinkUnresolvedAttributesType;
342
361
  /**
343
362
  * fires an event that represents when a user clicks on a Smart Link. */
344
363
  'ui.smartLink.clicked': SmartLinkClickedAttributesType;
@@ -0,0 +1,4 @@
1
+ import React, { type ComponentType } from 'react';
2
+ import type { HyperlinkResolverProps } from './index';
3
+ declare const withErrorBoundary: (Component: ComponentType<HyperlinkResolverProps>) => (props: HyperlinkResolverProps) => React.JSX.Element;
4
+ export default withErrorBoundary;
@@ -0,0 +1,5 @@
1
+ /**
2
+ * This is a scheduled batched register mechanism for resolving blue hyperlinks while the page is idle.
3
+ * i.e. SharePoint tenants with the same hostname will be grouped together before the register is made.
4
+ */
5
+ export declare const useScheduledRegister: (href: string, register: (() => Promise<any>) | null) => () => Promise<void>;
@@ -0,0 +1,7 @@
1
+ import React from 'react';
2
+ export interface HyperlinkResolverProps {
3
+ href: string;
4
+ }
5
+ export declare const isSharePointDomain: (href: string) => boolean;
6
+ declare const _default: (props: HyperlinkResolverProps) => React.JSX.Element;
7
+ export default _default;
@@ -0,0 +1,3 @@
1
+ export declare const ResolveHyperlink: ({ href }: {
2
+ href: string;
3
+ }) => null;
@@ -3,6 +3,10 @@ export interface LinkUrlProps extends React.AnchorHTMLAttributes<HTMLAnchorEleme
3
3
  * Determines if we want to perform a link safety check. True by default.
4
4
  */
5
5
  checkSafety?: boolean;
6
+ /**
7
+ * Determines if we want to resolve the URL in the background for Rovo indexing. This has no impact on the UI/UX. False by default.
8
+ */
9
+ enableResolve?: boolean;
6
10
  isLinkComponent?: boolean;
7
11
  testId?: string;
8
12
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlaskit/smart-card",
3
- "version": "40.17.1",
3
+ "version": "40.18.0",
4
4
  "description": "Smart card component",
5
5
  "publishConfig": {
6
6
  "registry": "https://registry.npmjs.org/"
@@ -62,13 +62,13 @@
62
62
  "@atlaskit/platform-feature-flags": "^1.1.0",
63
63
  "@atlaskit/popup": "^4.3.0",
64
64
  "@atlaskit/primitives": "^14.12.0",
65
- "@atlaskit/section-message": "^8.6.0",
65
+ "@atlaskit/section-message": "^8.7.0",
66
66
  "@atlaskit/select": "^21.2.0",
67
67
  "@atlaskit/spinner": "^19.0.0",
68
68
  "@atlaskit/textarea": "^8.0.0",
69
69
  "@atlaskit/textfield": "^8.0.0",
70
70
  "@atlaskit/theme": "^20.0.0",
71
- "@atlaskit/tmp-editor-statsig": "^12.1.0",
71
+ "@atlaskit/tmp-editor-statsig": "^12.3.0",
72
72
  "@atlaskit/tokens": "^6.1.0",
73
73
  "@atlaskit/tooltip": "^20.4.0",
74
74
  "@atlaskit/ufo": "^0.4.0",
@@ -184,9 +184,6 @@
184
184
  "confluence-issue-terminology-refresh": {
185
185
  "type": "boolean"
186
186
  },
187
- "platform-linking-ai-summary-migration-to-convo-ai": {
188
- "type": "boolean"
189
- },
190
187
  "dst-a11y__replace-anchor-with-link__linking-platfo": {
191
188
  "type": "boolean"
192
189
  },
@@ -231,6 +228,9 @@
231
228
  },
232
229
  "navx-1483-a11y-close-button-in-modal-updates": {
233
230
  "type": "boolean"
231
+ },
232
+ "navx-1706-smart-link-layered-link-a11y-update": {
233
+ "type": "boolean"
234
234
  }
235
235
  },
236
236
  "compassUnitTestMetricSourceId": "ari:cloud:compass:a436116f-02ce-4520-8fbb-7301462a1674:metric-source/c5751cc6-3513-4070-9deb-af31e86aed34/f74ef1bc-7240-4aac-9dc8-9dc43b502089"