@atlaskit/smart-card 43.26.3 → 43.26.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +19 -0
- package/analytics.spec.yaml +9 -0
- package/dist/cjs/extractors/flexible/actions/extract-rovo-chat-action.js +17 -1
- package/dist/cjs/extractors/flexible/actions/index.js +8 -1
- package/dist/cjs/messages.js +15 -10
- package/dist/cjs/state/hooks/use-invoke-client-action/index.js +4 -3
- package/dist/cjs/utils/analytics/analytics.js +1 -1
- package/dist/cjs/view/FlexibleCard/components/actions/copy-link-action/index.js +2 -1
- package/dist/cjs/view/FlexibleCard/components/actions/preview-action/index.js +3 -2
- package/dist/cjs/view/FlexibleCard/components/actions/rovo-chat-action/html-to-adf.js +180 -0
- package/dist/cjs/view/FlexibleCard/components/actions/rovo-chat-action/index.js +56 -19
- package/dist/cjs/view/FlexibleCard/components/actions/view-related-links-action/related-links-action-icon/index.js +2 -1
- package/dist/cjs/view/HoverCard/components/views/resolved/index.js +5 -1
- package/dist/cjs/view/LinkUrl/index.js +1 -1
- package/dist/es2019/extractors/flexible/actions/extract-rovo-chat-action.js +19 -2
- package/dist/es2019/extractors/flexible/actions/index.js +8 -1
- package/dist/es2019/messages.js +15 -10
- package/dist/es2019/state/hooks/use-invoke-client-action/index.js +3 -1
- package/dist/es2019/utils/analytics/analytics.js +1 -1
- package/dist/es2019/view/FlexibleCard/components/actions/copy-link-action/index.js +2 -1
- package/dist/es2019/view/FlexibleCard/components/actions/preview-action/index.js +3 -2
- package/dist/es2019/view/FlexibleCard/components/actions/rovo-chat-action/html-to-adf.js +161 -0
- package/dist/es2019/view/FlexibleCard/components/actions/rovo-chat-action/index.js +34 -37
- package/dist/es2019/view/FlexibleCard/components/actions/view-related-links-action/related-links-action-icon/index.js +2 -1
- package/dist/es2019/view/HoverCard/components/views/resolved/index.js +5 -1
- package/dist/es2019/view/LinkUrl/index.js +1 -1
- package/dist/esm/extractors/flexible/actions/extract-rovo-chat-action.js +18 -2
- package/dist/esm/extractors/flexible/actions/index.js +8 -1
- package/dist/esm/messages.js +15 -10
- package/dist/esm/state/hooks/use-invoke-client-action/index.js +4 -3
- package/dist/esm/utils/analytics/analytics.js +1 -1
- package/dist/esm/view/FlexibleCard/components/actions/copy-link-action/index.js +2 -1
- package/dist/esm/view/FlexibleCard/components/actions/preview-action/index.js +3 -2
- package/dist/esm/view/FlexibleCard/components/actions/rovo-chat-action/html-to-adf.js +172 -0
- package/dist/esm/view/FlexibleCard/components/actions/rovo-chat-action/index.js +56 -19
- package/dist/esm/view/FlexibleCard/components/actions/view-related-links-action/related-links-action-icon/index.js +2 -1
- package/dist/esm/view/HoverCard/components/views/resolved/index.js +5 -1
- package/dist/esm/view/LinkUrl/index.js +1 -1
- package/dist/types/common/analytics/generated/analytics.types.d.ts +12 -1
- package/dist/types/extractors/flexible/actions/extract-rovo-chat-action.d.ts +10 -1
- package/dist/types/messages.d.ts +1 -1
- package/dist/types/state/flexible-ui-context/types.d.ts +1 -0
- package/dist/types/state/hooks/use-invoke-client-action/types.d.ts +6 -2
- package/dist/types/view/FlexibleCard/components/actions/rovo-chat-action/html-to-adf.d.ts +8 -0
- package/dist/types-ts4.5/common/analytics/generated/analytics.types.d.ts +12 -1
- package/dist/types-ts4.5/extractors/flexible/actions/extract-rovo-chat-action.d.ts +10 -1
- package/dist/types-ts4.5/messages.d.ts +1 -1
- package/dist/types-ts4.5/state/flexible-ui-context/types.d.ts +1 -0
- package/dist/types-ts4.5/state/hooks/use-invoke-client-action/types.d.ts +6 -2
- package/dist/types-ts4.5/view/FlexibleCard/components/actions/rovo-chat-action/html-to-adf.d.ts +8 -0
- package/package.json +9 -5
|
@@ -1,9 +1,17 @@
|
|
|
1
1
|
import { extractSmartLinkUrl } from '@atlaskit/link-extractors';
|
|
2
|
-
import {
|
|
2
|
+
import { InternalActionName } from '../../../constants';
|
|
3
|
+
import { getDefinitionId, getExtensionKey, getResourceType } from '../../../state/helpers';
|
|
3
4
|
import { canShowAction } from '../../../utils/actions/can-show-action';
|
|
4
5
|
import { getIsRovoChatEnabled } from '../../../utils/rovo';
|
|
5
6
|
import { CardAction } from '../../../view/Card/types';
|
|
6
|
-
const extractRovoChatAction = (
|
|
7
|
+
const extractRovoChatAction = ({
|
|
8
|
+
actionOptions,
|
|
9
|
+
appearance,
|
|
10
|
+
id,
|
|
11
|
+
product,
|
|
12
|
+
response,
|
|
13
|
+
rovoConfig
|
|
14
|
+
}) => {
|
|
7
15
|
var _actionOptions$rovoCh;
|
|
8
16
|
if (!canShowAction(CardAction.RovoChatAction, actionOptions)) {
|
|
9
17
|
return;
|
|
@@ -19,6 +27,15 @@ const extractRovoChatAction = (response, rovoConfig, actionOptions, product) =>
|
|
|
19
27
|
const isOptIn = (actionOptions === null || actionOptions === void 0 ? void 0 : (_actionOptions$rovoCh = actionOptions.rovoChatAction) === null || _actionOptions$rovoCh === void 0 ? void 0 : _actionOptions$rovoCh.optIn) === true;
|
|
20
28
|
const url = extractSmartLinkUrl(response);
|
|
21
29
|
return isSupportedFeature && isOptIn ? {
|
|
30
|
+
invokeAction: {
|
|
31
|
+
actionSubjectId: 'rovoChatPrompt',
|
|
32
|
+
actionType: InternalActionName.RovoChatAction,
|
|
33
|
+
definitionId: getDefinitionId(response),
|
|
34
|
+
display: appearance,
|
|
35
|
+
extensionKey: getExtensionKey(response),
|
|
36
|
+
id,
|
|
37
|
+
resourceType: getResourceType(response)
|
|
38
|
+
},
|
|
22
39
|
product,
|
|
23
40
|
url
|
|
24
41
|
} : undefined;
|
|
@@ -49,7 +49,14 @@ export const extractFlexibleCardActions = ({
|
|
|
49
49
|
[ActionName.AutomationAction]: extractAutomationAction(response),
|
|
50
50
|
[InternalActionName.AISummaryAction]: extractAISummaryAction(response, url, actionOptions, aiSummaryConfig),
|
|
51
51
|
...(fg('platform_sl_3p_auth_rovo_action_kill_switch') ? {
|
|
52
|
-
[InternalActionName.RovoChatAction]: extractRovoChatAction(
|
|
52
|
+
[InternalActionName.RovoChatAction]: extractRovoChatAction({
|
|
53
|
+
actionOptions,
|
|
54
|
+
appearance,
|
|
55
|
+
id,
|
|
56
|
+
product,
|
|
57
|
+
response,
|
|
58
|
+
rovoConfig
|
|
59
|
+
})
|
|
53
60
|
} : undefined),
|
|
54
61
|
[InternalActionName.ViewRelatedLinksAction]: extractViewRelatedLinksAction(response)
|
|
55
62
|
};
|
package/dist/es2019/messages.js
CHANGED
|
@@ -860,11 +860,6 @@ export const messages = defineMessages({
|
|
|
860
860
|
defaultMessage: 'Confluence page',
|
|
861
861
|
description: 'The Confluence page the user see Smart Link in, to be used as the {context} for Rovo prompt message'
|
|
862
862
|
},
|
|
863
|
-
rovo_prompt_context_confluence_page_plural: {
|
|
864
|
-
id: 'fabric.linking.rovo_prompt_context_confluence_page_plural.non-final',
|
|
865
|
-
defaultMessage: 'Confluence pages',
|
|
866
|
-
description: 'The Confluence page the user see Smart Link in, to be used as the {context} for Rovo prompt message'
|
|
867
|
-
},
|
|
868
863
|
rovo_prompt_context_confluence_page_short: {
|
|
869
864
|
id: 'fabric.linking.rovo_prompt_context_confluence_page_short.non-final',
|
|
870
865
|
defaultMessage: 'page',
|
|
@@ -875,11 +870,6 @@ export const messages = defineMessages({
|
|
|
875
870
|
defaultMessage: 'Jira work item',
|
|
876
871
|
description: 'The Jira work item the user see Smart Link in, to be used as the {context} for Rovo prompt message'
|
|
877
872
|
},
|
|
878
|
-
rovo_prompt_context_jira_work_item_plural: {
|
|
879
|
-
id: 'fabric.linking.rovo_prompt_context_jira_work_item_plural.non-final',
|
|
880
|
-
defaultMessage: 'Jira work items',
|
|
881
|
-
description: 'The Jira work item the user see Smart Link in, to be used as the {context} for Rovo prompt message'
|
|
882
|
-
},
|
|
883
873
|
rovo_prompt_context_jira_work_item_short: {
|
|
884
874
|
id: 'fabric.linking.rovo_prompt_context_jira_work_item_short.non-final',
|
|
885
875
|
defaultMessage: 'work item',
|
|
@@ -890,14 +880,29 @@ export const messages = defineMessages({
|
|
|
890
880
|
defaultMessage: 'Recommend other sources',
|
|
891
881
|
description: 'The name of the action to send prompt message to Rovo Chat in relation to current Smart Link'
|
|
892
882
|
},
|
|
883
|
+
rovo_prompt_message_recommend_other_sources: {
|
|
884
|
+
id: 'fabric.linking.rovo_prompt_message_recommend_other_sources.non-final',
|
|
885
|
+
defaultMessage: '<p>From this <a>{url}</a> and the {context} I’m viewing now as context:</p><ul><li><p>Search across all sources I can access for items that discuss <b>similar concepts, themes, or problems</b>, or that <b>reference similar or closely related sources</b> (including links to the same or related pages, issues, or docs).</p></li><li><p>Return the results as a list or table with columns: <code>Item</code>, <code>Type</code>, <code>Short summary</code>, and <code>Why it’s similar</code>.</p></li><li><p>For each result, give a one‑sentence <b>Short summary</b> of what the item is about.</p></li><li><p>In <b>Why it’s similar</b>, briefly explain (in a phrase or short sentence) what makes it related to this Smart Link and/or the item I’m viewing (for example: same project, similar decision, shared requirements, overlapping stakeholders, similar metrics, or referencing related docs).</p></li><li><p>Order the list from <b>most to least relevant</b> based on Rovo’s assessment of semantic similarity to both the Smart Link target and the current item. Prioritize items that I do not own or have not contributed to.</p></li><li><p>If there are more than 5 results, show the <b>5 most relevant</b> and state how many additional items you found.</p></li></ul>',
|
|
886
|
+
description: 'The prompt message to send to Rovo Chat. {context} refers to the content the user triggered from, e.g. Confluence page or Jira work item. {url} refers to Smart Link that the user triggers this action from. (Please make sure all html tags remain the same.)'
|
|
887
|
+
},
|
|
893
888
|
rovo_prompt_button_show_other_mentions: {
|
|
894
889
|
id: 'fabric.linking.rovo_prompt_button_show_other_mentions.non-final',
|
|
895
890
|
defaultMessage: 'Show other mentions',
|
|
896
891
|
description: 'The name of the action to send prompt message to Rovo Chat in relation to current Smart Link'
|
|
897
892
|
},
|
|
893
|
+
rovo_prompt_message_show_other_mentions: {
|
|
894
|
+
id: 'fabric.linking.rovo_prompt_message_show_other_mentions.non-final',
|
|
895
|
+
defaultMessage: '<p>From <a>{url}</a> and the {context} I’m viewing now:</p><ul><li><p>Search across all Confluence pages and Jira work items I can access for other items that contain this exact Smart Link (same underlying URL/resource).</p></li><li><p>List all matching items in a table with columns: <code>Item</code>, <code>Type</code>, <code>Short summary</code>, <code>How this item uses the link</code>, and <code>Relevance to current item</code>.</p></li><li><p>For <code>Short summary</code>, give a one‑sentence description of what the {context} is about.</p></li><li><p>For <code>How this item uses the link</code>, briefly explain the role this link plays there (e.g., decision doc, background context, implementation details, status update).</p></li><li><p>For <code>Relevance to current item</code>, compare each item to the {context} I’m viewing now and label it <code>High</code>, <code>Medium</code>, or <code>Low</code> relevance, with a short reason (a phrase or single clause).</p></li><li><p>If there are more than 15 matches, show the 15 most relevant and tell me how many additional matches exist.</p></li></ul>',
|
|
896
|
+
description: 'The prompt message to send to Rovo Chat. {context} refers to the content the user triggered from, e.g. Confluence page or Jira work item. {url} refers to Smart Link that the user triggers this action from. (Please make sure all html tags remain the same.)'
|
|
897
|
+
},
|
|
898
898
|
rovo_prompt_button_suggest_improvement: {
|
|
899
899
|
id: 'fabric.linking.rovo_prompt_button_suggest_improvement.non-final',
|
|
900
900
|
defaultMessage: 'Suggest {context} improvement',
|
|
901
901
|
description: 'The name of the action to send prompt message to Rovo Chat in relation to current Smart Link'
|
|
902
|
+
},
|
|
903
|
+
rovo_prompt_message_suggest_improvement: {
|
|
904
|
+
id: 'fabric.linking.rovo_prompt_message_suggest_improvement.non-final',
|
|
905
|
+
defaultMessage: '<p>Using the {context} I’m viewing now, plus all files and links referenced in it (including <a>{url}</a>):</p><ul><li><p>Identify unclear reasoning, missing context, or contradictions between the item and its linked files.</p></li><li><p>Call out any places where assumptions are not backed up by data or prior docs.</p></li><li><p>Stay concise: summarize your findings in <b>no more than three short paragraphs of content listed as bullets</b> of no more than a couple of sentences long focused only on the two points above.</p></li><li><p>After presenting that summary, <b>ask me explicitly</b> if I want you to go deeper. Only if I say yes, then:</p><ul><li><p>Suggest concrete rewrites (bullets or short paragraphs) to make the argument clearer, more concise, and better aligned with the supporting files.</p></li><li><p>Propose 3–5 follow‑up edits or additions that would make this item and its linked docs “share‑ready” for stakeholders.</p></li></ul></li></ul>',
|
|
906
|
+
description: 'The prompt message to send to Rovo Chat. {context} refers to the content the user triggered from, e.g. Confluence page or Jira work item. {url} refers to Smart Link that the user triggers this action from. (Please make sure all html tags remain the same.)'
|
|
902
907
|
}
|
|
903
908
|
});
|
|
@@ -25,6 +25,7 @@ const useInvokeClientAction = ({
|
|
|
25
25
|
extensionKey,
|
|
26
26
|
display,
|
|
27
27
|
id,
|
|
28
|
+
prompt,
|
|
28
29
|
resourceType = null
|
|
29
30
|
}) => {
|
|
30
31
|
// eslint-disable-next-line @atlaskit/platform/prefer-crypto-random-uuid -- Use crypto.randomUUID instead
|
|
@@ -50,7 +51,8 @@ const useInvokeClientAction = ({
|
|
|
50
51
|
definitionId,
|
|
51
52
|
display: display !== null && display !== void 0 ? display : null,
|
|
52
53
|
id: id !== null && id !== void 0 ? id : experienceId,
|
|
53
|
-
resourceType
|
|
54
|
+
resourceType,
|
|
55
|
+
prompt
|
|
54
56
|
});
|
|
55
57
|
}
|
|
56
58
|
// Invoke action
|
|
@@ -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: "
|
|
5
|
+
packageVersion: "0.0.0-development"
|
|
6
6
|
};
|
|
7
7
|
export let TrackQuickActionType = /*#__PURE__*/function (TrackQuickActionType) {
|
|
8
8
|
TrackQuickActionType["StatusUpdate"] = "StatusUpdate";
|
|
@@ -2,6 +2,7 @@ import _extends from "@babel/runtime/helpers/extends";
|
|
|
2
2
|
import React, { useCallback, useState } from 'react';
|
|
3
3
|
import { FormattedMessage } from 'react-intl-next';
|
|
4
4
|
import LinkIcon from '@atlaskit/icon/core/link';
|
|
5
|
+
import { fg } from '@atlaskit/platform-feature-flags';
|
|
5
6
|
import { ActionName } from '../../../../../constants';
|
|
6
7
|
import { messages } from '../../../../../messages';
|
|
7
8
|
import { useFlexibleUiContext } from '../../../../../state/flexible-ui-context';
|
|
@@ -33,7 +34,7 @@ const CopyLinkAction = ({
|
|
|
33
34
|
content: /*#__PURE__*/React.createElement(FormattedMessage, messages.copy_url_to_clipboard),
|
|
34
35
|
icon: /*#__PURE__*/React.createElement(LinkIcon, {
|
|
35
36
|
color: "currentColor",
|
|
36
|
-
label:
|
|
37
|
+
label: fg('navx-3698-flexible-card-a11y-fix') ? '' : 'copy url',
|
|
37
38
|
spacing: "spacious"
|
|
38
39
|
}),
|
|
39
40
|
onClick: onClick,
|
|
@@ -3,6 +3,7 @@ import React, { useCallback } from 'react';
|
|
|
3
3
|
import { FormattedMessage } from 'react-intl-next';
|
|
4
4
|
import MediaServicesActualSizeIcon from '@atlaskit/icon/core/grow-diagonal';
|
|
5
5
|
import PanelRightIcon from '@atlaskit/icon/core/panel-right';
|
|
6
|
+
import { fg } from '@atlaskit/platform-feature-flags';
|
|
6
7
|
import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals';
|
|
7
8
|
import { ActionName } from '../../../../../constants';
|
|
8
9
|
import { messages } from '../../../../../messages';
|
|
@@ -32,13 +33,13 @@ const PreviewAction = ({
|
|
|
32
33
|
return /*#__PURE__*/React.createElement(PanelRightIcon, {
|
|
33
34
|
color: "currentColor",
|
|
34
35
|
spacing: "spacious",
|
|
35
|
-
label:
|
|
36
|
+
label: fg('navx-3698-flexible-card-a11y-fix') ? '' : 'Open preview panel'
|
|
36
37
|
});
|
|
37
38
|
}
|
|
38
39
|
return /*#__PURE__*/React.createElement(MediaServicesActualSizeIcon, {
|
|
39
40
|
color: "currentColor",
|
|
40
41
|
spacing: "spacious",
|
|
41
|
-
label:
|
|
42
|
+
label: fg('navx-3698-flexible-card-a11y-fix') ? '' : 'Open preview'
|
|
42
43
|
});
|
|
43
44
|
}, [hasPreviewPanel]);
|
|
44
45
|
const actionLabel = useCallback(() => {
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This is a simplified version of html to adf conversion,
|
|
3
|
+
* used specifically for SL RovoChatAction prompt message,
|
|
4
|
+
* and does not support all ADF offered via @atlaskit/adf-utils
|
|
5
|
+
*
|
|
6
|
+
* Support: p, ul, li, text, b, strong, code, inlineCard (replace a hyperlink)
|
|
7
|
+
*/
|
|
8
|
+
import { code, doc, inlineCard, p, b, ul, li, text } from '@atlaskit/adf-utils/builders';
|
|
9
|
+
const INLINE_TAG_NAMES = ['b', 'strong', 'code', 'a', 'inlineCard'];
|
|
10
|
+
const BLOCK_TAG_NAMES = ['p', 'ul', 'ol', 'li'];
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Group Captures Example
|
|
14
|
+
* ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
15
|
+
* match[1] Self-closing tag name br from <br/> or <img src="x"/>
|
|
16
|
+
* match[2] Opening tag name div from <div> or <div class="x">
|
|
17
|
+
* match[3] Closing tag name div from </div>
|
|
18
|
+
* match[4] Text content Hello world
|
|
19
|
+
*/
|
|
20
|
+
const htmlRegex = /<\s*(\w+)[^>]*?\s*\/\s*>|<\s*(\w+)[^>]*>|<\s*\/\s*(\w+)\s*>|([^<]+)/g;
|
|
21
|
+
const decodeHtmlEntities = (text = '') => {
|
|
22
|
+
return text.replace(/ /g, ' ').replace(/</g, '<').replace(/>/g, '>').replace(/&/g, '&').replace(/"/g, '"').replace(/'/g, "'");
|
|
23
|
+
};
|
|
24
|
+
const tokenizeHtml = html => {
|
|
25
|
+
const tokens = [];
|
|
26
|
+
let match;
|
|
27
|
+
while ((match = htmlRegex.exec(html)) !== null) {
|
|
28
|
+
const selfClosingTag = match[1];
|
|
29
|
+
const openingTag = match[2];
|
|
30
|
+
const closingTag = match[3];
|
|
31
|
+
const textContent = match[4];
|
|
32
|
+
if (selfClosingTag) {
|
|
33
|
+
tokens.push({
|
|
34
|
+
type: 'selfClosing',
|
|
35
|
+
tagName: selfClosingTag.toLowerCase()
|
|
36
|
+
});
|
|
37
|
+
} else if (openingTag) {
|
|
38
|
+
tokens.push({
|
|
39
|
+
type: 'open',
|
|
40
|
+
tagName: openingTag.toLowerCase()
|
|
41
|
+
});
|
|
42
|
+
} else if (closingTag) {
|
|
43
|
+
tokens.push({
|
|
44
|
+
type: 'close',
|
|
45
|
+
tagName: closingTag.toLowerCase()
|
|
46
|
+
});
|
|
47
|
+
} else if (textContent) {
|
|
48
|
+
if (textContent !== null && textContent !== void 0 && textContent.trim()) {
|
|
49
|
+
tokens.push({
|
|
50
|
+
type: 'text',
|
|
51
|
+
content: decodeHtmlEntities(textContent)
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return tokens;
|
|
57
|
+
};
|
|
58
|
+
const buildListItem = (content = []) => {
|
|
59
|
+
// Check if content has only text/inline elements
|
|
60
|
+
const hasOnlyInlineContent = content.every(node => node.type === 'text' || node.type === 'hardBreak' || !node.type);
|
|
61
|
+
if (hasOnlyInlineContent) {
|
|
62
|
+
// Wrap text content in a paragraph
|
|
63
|
+
return li([p(...content)]);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Content has block elements (like nested lists), use as-is
|
|
67
|
+
return li(content);
|
|
68
|
+
};
|
|
69
|
+
const blockToAdf = (tagName, content = []) => {
|
|
70
|
+
switch (tagName) {
|
|
71
|
+
case 'p':
|
|
72
|
+
return p(...content);
|
|
73
|
+
case 'ul':
|
|
74
|
+
return ul(...content);
|
|
75
|
+
case 'li':
|
|
76
|
+
return buildListItem(content);
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
const inlineToAdf = (tagName, content) => {
|
|
80
|
+
switch (tagName) {
|
|
81
|
+
case 'b':
|
|
82
|
+
case 'strong':
|
|
83
|
+
return b(content);
|
|
84
|
+
case 'code':
|
|
85
|
+
return code(content);
|
|
86
|
+
case 'a':
|
|
87
|
+
case 'inlineCard':
|
|
88
|
+
return inlineCard({
|
|
89
|
+
url: content
|
|
90
|
+
});
|
|
91
|
+
default:
|
|
92
|
+
return text(content);
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
const parseTokensToAdf = tokens => {
|
|
96
|
+
const stack = [{
|
|
97
|
+
type: 'root',
|
|
98
|
+
content: []
|
|
99
|
+
}];
|
|
100
|
+
let currentMarks = [];
|
|
101
|
+
for (let i = 0; i < tokens.length; i++) {
|
|
102
|
+
const token = tokens[i];
|
|
103
|
+
const current = stack[stack.length - 1];
|
|
104
|
+
switch (token.type) {
|
|
105
|
+
case 'text':
|
|
106
|
+
if (token.content) {
|
|
107
|
+
var _currentMarks, _currentMarks$;
|
|
108
|
+
const inlineAdfNode = inlineToAdf((_currentMarks = currentMarks) === null || _currentMarks === void 0 ? void 0 : (_currentMarks$ = _currentMarks[0]) === null || _currentMarks$ === void 0 ? void 0 : _currentMarks$.type, token.content);
|
|
109
|
+
current.content.push(inlineAdfNode);
|
|
110
|
+
}
|
|
111
|
+
break;
|
|
112
|
+
case 'open':
|
|
113
|
+
if (INLINE_TAG_NAMES.includes(token.tagName)) {
|
|
114
|
+
currentMarks.push({
|
|
115
|
+
type: token.tagName
|
|
116
|
+
});
|
|
117
|
+
} else if (BLOCK_TAG_NAMES.includes(token.tagName)) {
|
|
118
|
+
stack.push({
|
|
119
|
+
type: token.tagName,
|
|
120
|
+
content: []
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
break;
|
|
124
|
+
case 'close':
|
|
125
|
+
// Inline formatting
|
|
126
|
+
if (token.tagName && INLINE_TAG_NAMES.includes(token.tagName)) {
|
|
127
|
+
currentMarks = currentMarks.filter(m => m.type !== token.tagName);
|
|
128
|
+
}
|
|
129
|
+
// Block elements
|
|
130
|
+
else if (stack.length > 1) {
|
|
131
|
+
const closed = stack.pop();
|
|
132
|
+
const parent = stack[stack.length - 1];
|
|
133
|
+
const adfNode = blockToAdf(closed === null || closed === void 0 ? void 0 : closed.type, closed === null || closed === void 0 ? void 0 : closed.content);
|
|
134
|
+
if (adfNode) {
|
|
135
|
+
parent.content.push(adfNode);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
break;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// Return root content
|
|
143
|
+
return stack[0].content;
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Convert HTML string to ADF format
|
|
148
|
+
*
|
|
149
|
+
* This is a simplified version specific for RovoChatAction prompt message
|
|
150
|
+
* and does not support all ADF offered via @atlaskit/adf-utils
|
|
151
|
+
*/
|
|
152
|
+
const htmlToAdf = html => {
|
|
153
|
+
try {
|
|
154
|
+
const tokens = tokenizeHtml(html);
|
|
155
|
+
const adfContent = parseTokensToAdf(tokens);
|
|
156
|
+
return doc(...adfContent);
|
|
157
|
+
} catch {
|
|
158
|
+
return html;
|
|
159
|
+
}
|
|
160
|
+
};
|
|
161
|
+
export default htmlToAdf;
|
|
@@ -4,11 +4,13 @@ import { useIntl } from 'react-intl-next';
|
|
|
4
4
|
import { InternalActionName } from '../../../../../constants';
|
|
5
5
|
import { messages } from '../../../../../messages';
|
|
6
6
|
import { useFlexibleUiContext } from '../../../../../state/flexible-ui-context';
|
|
7
|
+
import useInvokeClientAction from '../../../../../state/hooks/use-invoke-client-action';
|
|
7
8
|
import useRovoChat from '../../../../../state/hooks/use-rovo-chat';
|
|
8
9
|
import AiChapterIcon from '../../../assets/ai-chapter-icon';
|
|
9
10
|
import AIEditIcon from '../../../assets/ai-edit-icon';
|
|
10
11
|
import AISearchIcon from '../../../assets/ai-search-icon';
|
|
11
12
|
import Action from '../action';
|
|
13
|
+
import htmlToAdf from './html-to-adf';
|
|
12
14
|
export let RovoChatPromptKey = /*#__PURE__*/function (RovoChatPromptKey) {
|
|
13
15
|
RovoChatPromptKey["RECOMMEND_OTHER_SOURCES"] = "recommend-other-sources";
|
|
14
16
|
RovoChatPromptKey["SHOW_OTHER_MENTIONS"] = "show-other-mentions";
|
|
@@ -21,7 +23,6 @@ const getContext = (intl, product) => {
|
|
|
21
23
|
case 'CONFLUENCE':
|
|
22
24
|
return {
|
|
23
25
|
contextLong: intl.formatMessage(messages.rovo_prompt_context_confluence_page),
|
|
24
|
-
contextLongPlural: intl.formatMessage(messages.rovo_prompt_context_confluence_page_plural),
|
|
25
26
|
contextShort: intl.formatMessage(messages.rovo_prompt_context_confluence_page_short)
|
|
26
27
|
};
|
|
27
28
|
case 'JSW':
|
|
@@ -30,25 +31,28 @@ const getContext = (intl, product) => {
|
|
|
30
31
|
case 'JPD':
|
|
31
32
|
return {
|
|
32
33
|
contextLong: intl.formatMessage(messages.rovo_prompt_context_jira_work_item),
|
|
33
|
-
contextLongPlural: intl.formatMessage(messages.rovo_prompt_context_jira_work_item_plural),
|
|
34
34
|
contextShort: intl.formatMessage(messages.rovo_prompt_context_jira_work_item_short)
|
|
35
35
|
};
|
|
36
36
|
}
|
|
37
37
|
};
|
|
38
|
-
const getPromptAction = (promptKey, intl, url, product) => {
|
|
38
|
+
const getPromptAction = (promptKey, intl, url = '', product) => {
|
|
39
39
|
var _getContext;
|
|
40
40
|
const {
|
|
41
41
|
contextLong,
|
|
42
|
-
contextLongPlural,
|
|
43
42
|
contextShort
|
|
44
43
|
} = (_getContext = getContext(intl, product)) !== null && _getContext !== void 0 ? _getContext : {
|
|
45
44
|
contextLong: intl.formatMessage(messages.rovo_prompt_context_generic),
|
|
46
|
-
contextLongPlural: intl.formatMessage(messages.rovo_prompt_context_generic_plural),
|
|
47
45
|
contextShort: intl.formatMessage(messages.rovo_prompt_context_generic)
|
|
48
46
|
};
|
|
49
47
|
switch (promptKey) {
|
|
50
48
|
case RovoChatPromptKey.RECOMMEND_OTHER_SOURCES:
|
|
51
49
|
const label_recommend = intl.formatMessage(messages.rovo_prompt_button_recommend_other_sources);
|
|
50
|
+
const html_recommend = intl.formatMessage(messages.rovo_prompt_message_recommend_other_sources, {
|
|
51
|
+
context: contextLong,
|
|
52
|
+
url
|
|
53
|
+
}, {
|
|
54
|
+
ignoreTag: true
|
|
55
|
+
});
|
|
52
56
|
return {
|
|
53
57
|
icon: /*#__PURE__*/React.createElement(AIEditIcon, null),
|
|
54
58
|
content: label_recommend,
|
|
@@ -56,18 +60,17 @@ const getPromptAction = (promptKey, intl, url, product) => {
|
|
|
56
60
|
data: {
|
|
57
61
|
name: label_recommend,
|
|
58
62
|
dialogues: [],
|
|
59
|
-
|
|
60
|
-
prompt: `From this ${url} and the ${contextLong} I’m viewing now as context:
|
|
61
|
-
- Search across all sources I can access for items that discuss similar concepts, themes, or problems, or that reference similar or closely related sources (including links to the same or related pages, issues, or docs).
|
|
62
|
-
- Return the results as a list or table with columns: Item, Type, Short summary, and Why it’s similar.
|
|
63
|
-
- For each result, give a one‑sentence Short summary of what the item is about.
|
|
64
|
-
- In Why it’s similar, briefly explain (in a phrase or short sentence) what makes it related to this Smart Link and/or the item I’m viewing (for example: same project, similar decision, shared requirements, overlapping stakeholders, similar metrics, or referencing related docs).
|
|
65
|
-
- Order the list from most to least relevant based on Rovo’s assessment of semantic similarity to both the Smart Link target and the current item. Prioritize items that I do not own or have not contributed to.
|
|
66
|
-
- If there are more than 5 results, show the 5 most relevant and state how many additional items you found.`
|
|
63
|
+
prompt: htmlToAdf(html_recommend)
|
|
67
64
|
}
|
|
68
65
|
};
|
|
69
66
|
case RovoChatPromptKey.SHOW_OTHER_MENTIONS:
|
|
70
67
|
const label_other_mentions = intl.formatMessage(messages.rovo_prompt_button_show_other_mentions);
|
|
68
|
+
const html_other_mentions = intl.formatMessage(messages.rovo_prompt_message_show_other_mentions, {
|
|
69
|
+
context: contextLong,
|
|
70
|
+
url
|
|
71
|
+
}, {
|
|
72
|
+
ignoreTag: true
|
|
73
|
+
});
|
|
71
74
|
return {
|
|
72
75
|
icon: /*#__PURE__*/React.createElement(AiChapterIcon, null),
|
|
73
76
|
content: label_other_mentions,
|
|
@@ -75,20 +78,19 @@ const getPromptAction = (promptKey, intl, url, product) => {
|
|
|
75
78
|
data: {
|
|
76
79
|
name: label_other_mentions,
|
|
77
80
|
dialogues: [],
|
|
78
|
-
|
|
79
|
-
prompt: `From this ${url} and the ${contextLong} I’m viewing now:
|
|
80
|
-
- Search across all ${contextLongPlural} I can access for other items that contain this exact Smart Link (same underlying URL/resource).
|
|
81
|
-
- List all matching items in a table with columns: Item, Type, Short summary, How this item uses the link, and Relevance to current item.
|
|
82
|
-
- For Short summary, give a one‑sentence description of what the page/issue is about.
|
|
83
|
-
- For How this item uses the link, briefly explain the role this link plays there (e.g., decision doc, background context, implementation details, status update).
|
|
84
|
-
- For Relevance to current item, compare each item to the page/issue I’m viewing now and label it High, Medium, or Low relevance, with a short reason (a phrase or single clause).
|
|
85
|
-
- If there are more than 15 matches, show the 15 most relevant and tell me how many additional matches exist.`
|
|
81
|
+
prompt: htmlToAdf(html_other_mentions)
|
|
86
82
|
}
|
|
87
83
|
};
|
|
88
84
|
case RovoChatPromptKey.SUGGEST_IMPROVEMENT:
|
|
89
85
|
const label_improvement = intl.formatMessage(messages.rovo_prompt_button_suggest_improvement, {
|
|
90
86
|
context: contextShort
|
|
91
87
|
});
|
|
88
|
+
const html_improvement = intl.formatMessage(messages.rovo_prompt_message_suggest_improvement, {
|
|
89
|
+
context: contextLong,
|
|
90
|
+
url
|
|
91
|
+
}, {
|
|
92
|
+
ignoreTag: true
|
|
93
|
+
});
|
|
92
94
|
return {
|
|
93
95
|
icon: /*#__PURE__*/React.createElement(AISearchIcon, null),
|
|
94
96
|
content: label_improvement,
|
|
@@ -96,14 +98,7 @@ const getPromptAction = (promptKey, intl, url, product) => {
|
|
|
96
98
|
data: {
|
|
97
99
|
name: label_improvement,
|
|
98
100
|
dialogues: [],
|
|
99
|
-
|
|
100
|
-
prompt: `Using the ${contextLong} I’m viewing now, plus all files and links referenced in it (including this ${url}):
|
|
101
|
-
- Identify unclear reasoning, missing context, or contradictions between the item and its linked files.
|
|
102
|
-
- Call out any places where assumptions are not backed up by data or prior docs.
|
|
103
|
-
- Stay concise: summarize your findings in no more than three short paragraphs of content listed as bullets of no more than a couple of sentences long focused only on the two points above.
|
|
104
|
-
- After presenting that summary, ask me explicitly if I want you to go deeper. Only if I say yes, then:
|
|
105
|
-
- Suggest concrete rewrites (bullets or short paragraphs) to make the argument clearer, more concise, and better aligned with the supporting files.
|
|
106
|
-
- Propose 3–5 follow‑up edits or additions that would make this item and its linked docs “share‑ready” for stakeholders.`
|
|
101
|
+
prompt: htmlToAdf(html_improvement)
|
|
107
102
|
}
|
|
108
103
|
};
|
|
109
104
|
}
|
|
@@ -122,15 +117,17 @@ const RovoChatAction = ({
|
|
|
122
117
|
} = useRovoChat();
|
|
123
118
|
const context = useFlexibleUiContext();
|
|
124
119
|
const data = context === null || context === void 0 ? void 0 : (_context$actions = context.actions) === null || _context$actions === void 0 ? void 0 : _context$actions[InternalActionName.RovoChatAction];
|
|
125
|
-
const
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
120
|
+
const invoke = useInvokeClientAction({});
|
|
121
|
+
const onClick = useCallback((promptData, promptKey) => {
|
|
122
|
+
if (promptData && data !== null && data !== void 0 && data.invokeAction) {
|
|
123
|
+
invoke({
|
|
124
|
+
...(data === null || data === void 0 ? void 0 : data.invokeAction),
|
|
125
|
+
actionFn: async () => sendPromptMessage(promptData),
|
|
126
|
+
prompt: promptKey
|
|
127
|
+
});
|
|
131
128
|
onClickCallback === null || onClickCallback === void 0 ? void 0 : onClickCallback();
|
|
132
129
|
}
|
|
133
|
-
}, [onClickCallback, sendPromptMessage]);
|
|
130
|
+
}, [data === null || data === void 0 ? void 0 : data.invokeAction, invoke, onClickCallback, sendPromptMessage]);
|
|
134
131
|
const promptActions = useMemo(() => {
|
|
135
132
|
return prompts.map((promptKey, idx) => {
|
|
136
133
|
const {
|
|
@@ -143,7 +140,7 @@ const RovoChatAction = ({
|
|
|
143
140
|
content: content,
|
|
144
141
|
icon: icon,
|
|
145
142
|
key: promptKey,
|
|
146
|
-
onClick: () => onClick(promptData),
|
|
143
|
+
onClick: () => onClick(promptData, promptKey),
|
|
147
144
|
testId: `${testId}-${idx + 1}`,
|
|
148
145
|
tooltipMessage: tooltipMessage
|
|
149
146
|
}, props)) : null;
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import ClockIcon from '@atlaskit/icon/core/clock';
|
|
3
|
+
import { fg } from '@atlaskit/platform-feature-flags';
|
|
3
4
|
const RelatedLinksActionIcon = () => /*#__PURE__*/React.createElement(ClockIcon, {
|
|
4
5
|
color: "currentColor",
|
|
5
6
|
spacing: "spacious",
|
|
6
|
-
label:
|
|
7
|
+
label: fg('navx-3698-flexible-card-a11y-fix') ? '' : 'View related links...'
|
|
7
8
|
});
|
|
8
9
|
export default RelatedLinksActionIcon;
|
|
@@ -40,7 +40,11 @@ const HoverCardResolvedView = ({
|
|
|
40
40
|
useRovoConfig() : undefined;
|
|
41
41
|
const isRovoSummaryEnabled = fg('platform_sl_3p_auth_rovo_action_kill_switch') ?
|
|
42
42
|
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
43
|
-
useMemo(() => (cardState === null || cardState === void 0 ? void 0 : cardState.details) && extractRovoChatAction(
|
|
43
|
+
useMemo(() => (cardState === null || cardState === void 0 ? void 0 : cardState.details) && extractRovoChatAction({
|
|
44
|
+
response: cardState.details,
|
|
45
|
+
rovoConfig,
|
|
46
|
+
actionOptions
|
|
47
|
+
}) !== undefined, [actionOptions, cardState === null || cardState === void 0 ? void 0 : cardState.details, rovoConfig]) : false;
|
|
44
48
|
useEffect(() => {
|
|
45
49
|
// Since this hover view is only rendered on resolved status,
|
|
46
50
|
// there is no need to check for statuses.
|
|
@@ -12,7 +12,7 @@ import LinkWarningModal from './LinkWarningModal';
|
|
|
12
12
|
import { useLinkWarningModal } from './LinkWarningModal/hooks/use-link-warning-modal';
|
|
13
13
|
const PACKAGE_DATA = {
|
|
14
14
|
packageName: "@atlaskit/smart-card",
|
|
15
|
-
packageVersion: "
|
|
15
|
+
packageVersion: "0.0.0-development",
|
|
16
16
|
componentName: 'linkUrl'
|
|
17
17
|
};
|
|
18
18
|
const Anchor = withLinkClickedEvent('a');
|
|
@@ -1,10 +1,17 @@
|
|
|
1
1
|
import { extractSmartLinkUrl } from '@atlaskit/link-extractors';
|
|
2
|
-
import {
|
|
2
|
+
import { InternalActionName } from '../../../constants';
|
|
3
|
+
import { getDefinitionId, getExtensionKey, getResourceType } from '../../../state/helpers';
|
|
3
4
|
import { canShowAction } from '../../../utils/actions/can-show-action';
|
|
4
5
|
import { getIsRovoChatEnabled } from '../../../utils/rovo';
|
|
5
6
|
import { CardAction } from '../../../view/Card/types';
|
|
6
|
-
var extractRovoChatAction = function extractRovoChatAction(
|
|
7
|
+
var extractRovoChatAction = function extractRovoChatAction(_ref) {
|
|
7
8
|
var _actionOptions$rovoCh;
|
|
9
|
+
var actionOptions = _ref.actionOptions,
|
|
10
|
+
appearance = _ref.appearance,
|
|
11
|
+
id = _ref.id,
|
|
12
|
+
product = _ref.product,
|
|
13
|
+
response = _ref.response,
|
|
14
|
+
rovoConfig = _ref.rovoConfig;
|
|
8
15
|
if (!canShowAction(CardAction.RovoChatAction, actionOptions)) {
|
|
9
16
|
return;
|
|
10
17
|
}
|
|
@@ -19,6 +26,15 @@ var extractRovoChatAction = function extractRovoChatAction(response, rovoConfig,
|
|
|
19
26
|
var isOptIn = (actionOptions === null || actionOptions === void 0 || (_actionOptions$rovoCh = actionOptions.rovoChatAction) === null || _actionOptions$rovoCh === void 0 ? void 0 : _actionOptions$rovoCh.optIn) === true;
|
|
20
27
|
var url = extractSmartLinkUrl(response);
|
|
21
28
|
return isSupportedFeature && isOptIn ? {
|
|
29
|
+
invokeAction: {
|
|
30
|
+
actionSubjectId: 'rovoChatPrompt',
|
|
31
|
+
actionType: InternalActionName.RovoChatAction,
|
|
32
|
+
definitionId: getDefinitionId(response),
|
|
33
|
+
display: appearance,
|
|
34
|
+
extensionKey: getExtensionKey(response),
|
|
35
|
+
id: id,
|
|
36
|
+
resourceType: getResourceType(response)
|
|
37
|
+
},
|
|
22
38
|
product: product,
|
|
23
39
|
url: url
|
|
24
40
|
} : undefined;
|
|
@@ -43,7 +43,14 @@ export var extractFlexibleCardActions = function extractFlexibleCardActions(_ref
|
|
|
43
43
|
response: response,
|
|
44
44
|
isPreviewPanelAvailable: isPreviewPanelAvailable,
|
|
45
45
|
openPreviewPanel: openPreviewPanel
|
|
46
|
-
})), ActionName.AutomationAction, extractAutomationAction(response)), InternalActionName.AISummaryAction, extractAISummaryAction(response, url, actionOptions, aiSummaryConfig)), fg('platform_sl_3p_auth_rovo_action_kill_switch') ? _defineProperty({}, InternalActionName.RovoChatAction, extractRovoChatAction(
|
|
46
|
+
})), ActionName.AutomationAction, extractAutomationAction(response)), InternalActionName.AISummaryAction, extractAISummaryAction(response, url, actionOptions, aiSummaryConfig)), fg('platform_sl_3p_auth_rovo_action_kill_switch') ? _defineProperty({}, InternalActionName.RovoChatAction, extractRovoChatAction({
|
|
47
|
+
actionOptions: actionOptions,
|
|
48
|
+
appearance: appearance,
|
|
49
|
+
id: id,
|
|
50
|
+
product: product,
|
|
51
|
+
response: response,
|
|
52
|
+
rovoConfig: rovoConfig
|
|
53
|
+
})) : undefined), {}, _defineProperty({}, InternalActionName.ViewRelatedLinksAction, extractViewRelatedLinksAction(response)));
|
|
47
54
|
return Object.values(action).some(function (value) {
|
|
48
55
|
return Boolean(value);
|
|
49
56
|
}) ? action : undefined;
|