@gooddata/sdk-ui-gen-ai 11.53.0-alpha.0 → 11.53.0-alpha.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/NOTICE +59 -9
  2. package/esm/components/ConfigContext.d.ts +1 -0
  3. package/esm/components/ConfigContext.d.ts.map +1 -1
  4. package/esm/components/GenAiChatContextChooser.d.ts.map +1 -1
  5. package/esm/components/GenAiChatContextChooser.js +9 -11
  6. package/esm/components/GenAiChatContextChooserBody.d.ts +17 -0
  7. package/esm/components/GenAiChatContextChooserBody.d.ts.map +1 -0
  8. package/esm/components/GenAiChatContextChooserBody.js +82 -0
  9. package/esm/components/hooks/useContextItems.d.ts +1 -4
  10. package/esm/components/hooks/useContextItems.d.ts.map +1 -1
  11. package/esm/components/hooks/useContextItems.js +1 -22
  12. package/esm/components/intelligence/data/categoryDetailRows.d.ts.map +1 -1
  13. package/esm/components/intelligence/data/categoryDetailRows.js +90 -7
  14. package/esm/components/intelligence/data/deriveInteractionIntelligenceFromSteps.d.ts +2 -0
  15. package/esm/components/intelligence/data/deriveInteractionIntelligenceFromSteps.d.ts.map +1 -1
  16. package/esm/components/intelligence/data/deriveInteractionIntelligenceFromSteps.js +12 -0
  17. package/esm/components/intelligence/data/mergeDetailRows.d.ts +3 -1
  18. package/esm/components/intelligence/data/mergeDetailRows.d.ts.map +1 -1
  19. package/esm/components/intelligence/data/mergeDetailRows.js +66 -2
  20. package/esm/components/intelligence/data/types.d.ts +6 -1
  21. package/esm/components/intelligence/data/types.d.ts.map +1 -1
  22. package/esm/components/intelligence/detail/DetailRowValue.js +1 -1
  23. package/esm/components/intelligence/panel/IntelligenceCategoryRow.d.ts +2 -2
  24. package/esm/components/intelligence/panel/IntelligenceCategoryRow.d.ts.map +1 -1
  25. package/esm/components/intelligence/panel/IntelligenceCategoryRow.js +3 -3
  26. package/esm/components/messages/AssistantItemFeedback.js +2 -2
  27. package/esm/components/messages/ConversationItemContents.d.ts.map +1 -1
  28. package/esm/components/messages/ConversationItemContents.js +1 -1
  29. package/esm/components/messages/conversationContents/ConversationDashboardContent.d.ts +2 -1
  30. package/esm/components/messages/conversationContents/ConversationDashboardContent.d.ts.map +1 -1
  31. package/esm/components/messages/conversationContents/ConversationDashboardContent.js +3 -2
  32. package/esm/context/dashboard.d.ts +2 -2
  33. package/esm/context/dashboard.d.ts.map +1 -1
  34. package/esm/context/dashboard.js +5 -2
  35. package/esm/localization/bundles/en-US.localization-bundle.d.ts +68 -0
  36. package/esm/localization/bundles/en-US.localization-bundle.d.ts.map +1 -1
  37. package/esm/localization/bundles/en-US.localization-bundle.js +68 -0
  38. package/esm/sdk-ui-gen-ai.d.ts +1 -0
  39. package/esm/store/messages/messagesSelectors.d.ts.map +1 -1
  40. package/esm/store/messages/messagesSelectors.js +5 -1
  41. package/esm/store/messages/messagesSlice.d.ts +5 -1
  42. package/esm/store/messages/messagesSlice.d.ts.map +1 -1
  43. package/esm/store/messages/messagesSlice.js +14 -2
  44. package/esm/store/sideEffects/onUserMessage.d.ts.map +1 -1
  45. package/esm/store/sideEffects/onUserMessage.js +14 -1
  46. package/esm/types.d.ts +5 -0
  47. package/esm/types.d.ts.map +1 -1
  48. package/package.json +20 -20
  49. package/styles/css/intelligence.css +2 -0
  50. package/styles/css/intelligence.css.map +1 -1
  51. package/styles/css/main.css +44 -0
  52. package/styles/css/main.css.map +1 -1
  53. package/styles/scss/intelligence.scss +2 -0
  54. package/styles/scss/main.scss +33 -0
package/NOTICE CHANGED
@@ -7,9 +7,9 @@
7
7
 
8
8
  The following 3rd-party software packages may be used by or distributed with gooddata-ui-sdk. Any information relevant to third-party vendors listed below are collected using common, reasonable means.
9
9
 
10
- Date generated: 2026-8-10
10
+ Date generated: 2026-8-13
11
11
 
12
- Revision ID: df24fd6388dc31e841cd593b9a048731ec44afec
12
+ Revision ID: 03b276147864f291b2ed2694a19ccbfa1d69ce6b
13
13
 
14
14
  ================================================================================
15
15
  ================================================================================
@@ -126,6 +126,7 @@ Revision ID: df24fd6388dc31e841cd593b9a048731ec44afec
126
126
  - @cacheable/utils (2.5.0) [MIT]
127
127
  - @codemirror/autocomplete (6.20.0) [MIT]
128
128
  - @codemirror/commands (6.10.1) [MIT]
129
+ - @codemirror/lang-json (6.0.2) [MIT]
129
130
  - @codemirror/lang-yaml (6.1.3) [MIT]
130
131
  - @codemirror/language (6.12.1) [MIT]
131
132
  - @codemirror/lint (6.9.2) [MIT]
@@ -219,6 +220,7 @@ Revision ID: df24fd6388dc31e841cd593b9a048731ec44afec
219
220
  - @leichtgewicht/ip-codec (2.0.5) [MIT]
220
221
  - @lezer/common (1.5.2) [MIT]
221
222
  - @lezer/highlight (1.2.3) [MIT]
223
+ - @lezer/json (1.0.3) [MIT]
222
224
  - @lezer/lr (1.4.10) [MIT]
223
225
  - @lezer/yaml (1.0.4) [MIT]
224
226
  - @mapbox/geojson-rewind (0.5.2) [ISC]
@@ -945,7 +947,7 @@ Revision ID: df24fd6388dc31e841cd593b9a048731ec44afec
945
947
  - source-map-js (1.2.1) [BSD-3-Clause]
946
948
  - source-map-support (0.5.21) [MIT]
947
949
  - space-separated-tokens (2.0.2) [MIT]
948
- - spark-md5 (3.0.2) [Multi-license: MIT OR WTFPL]
950
+ - spark-md5 (3.0.2) [Multi-license: WTFPL OR MIT]
949
951
  - spdy (4.0.2) [MIT]
950
952
  - spdy-transport (3.0.0) [MIT]
951
953
  - statuses (1.5.0) [MIT]
@@ -978,7 +980,7 @@ Revision ID: df24fd6388dc31e841cd593b9a048731ec44afec
978
980
  - tar (7.5.22) [ISC]
979
981
  - terser (5.49.0) [BSD-2-Clause]
980
982
  - terser-webpack-plugin (5.6.1) [MIT]
981
- - text-encoding (0.7.0) [Multi-license: Apache-2.0 OR Unlicense]
983
+ - text-encoding (0.7.0) [Multi-license: Unlicense OR Apache-2.0]
982
984
  - thingies (2.6.1) [MIT]
983
985
  - thunky (1.1.0) [MIT]
984
986
  - tinycolor2 (1.6.0) [MIT]
@@ -999,7 +1001,7 @@ Revision ID: df24fd6388dc31e841cd593b9a048731ec44afec
999
1001
  - tslib (2.8.1) [ISC]
1000
1002
  - tslib (1.14.1) [ISC]
1001
1003
  - tsyringe (4.10.0) [MIT]
1002
- - type-fest (0.21.3) [Multi-license: MIT OR CC0-1.0]
1004
+ - type-fest (0.21.3) [Multi-license: CC0-1.0 OR MIT]
1003
1005
  - type-is (1.6.18) [MIT]
1004
1006
  - typescript (5.9.3) [Apache-2.0, MIT, Unicode-DFS-2020, CC-BY-4.0, BSD-3-Clause, W3C-20150513]
1005
1007
  - undici-types (6.21.0) [MIT]
@@ -2288,6 +2290,18 @@ Package Depth: Direct
2288
2290
  MIT
2289
2291
 
2290
2292
 
2293
+ --------------------------------------------------------------------------------
2294
+ Package Title: @codemirror/lang-json (6.0.2)
2295
+
2296
+ Package Locator: npm+@codemirror/lang-json$6.0.2
2297
+
2298
+ Package Depth: Direct
2299
+ --------------------------------------------------------------------------------
2300
+
2301
+ * Declared Licenses *
2302
+ MIT
2303
+
2304
+
2291
2305
  --------------------------------------------------------------------------------
2292
2306
  Package Title: @codemirror/lang-yaml (6.1.3)
2293
2307
 
@@ -3416,6 +3430,18 @@ Package Depth: Direct
3416
3430
  MIT
3417
3431
 
3418
3432
 
3433
+ --------------------------------------------------------------------------------
3434
+ Package Title: @lezer/json (1.0.3)
3435
+
3436
+ Package Locator: npm+@lezer/json$1.0.3
3437
+
3438
+ Package Depth: Transitive
3439
+ --------------------------------------------------------------------------------
3440
+
3441
+ * Declared Licenses *
3442
+ MIT
3443
+
3444
+
3419
3445
  --------------------------------------------------------------------------------
3420
3446
  Package Title: @lezer/lr (1.4.10)
3421
3447
 
@@ -12217,7 +12243,7 @@ Package Depth: Direct
12217
12243
  --------------------------------------------------------------------------------
12218
12244
 
12219
12245
  * Declared Licenses *
12220
- Multi-license: MIT OR WTFPL
12246
+ Multi-license: WTFPL OR MIT
12221
12247
 
12222
12248
 
12223
12249
  --------------------------------------------------------------------------------
@@ -12613,7 +12639,7 @@ Package Depth: Transitive
12613
12639
  --------------------------------------------------------------------------------
12614
12640
 
12615
12641
  * Declared Licenses *
12616
- Multi-license: Apache-2.0 OR Unlicense
12642
+ Multi-license: Unlicense OR Apache-2.0
12617
12643
 
12618
12644
 
12619
12645
  --------------------------------------------------------------------------------
@@ -12869,7 +12895,7 @@ Package Depth: Transitive
12869
12895
  --------------------------------------------------------------------------------
12870
12896
 
12871
12897
  * Declared Licenses *
12872
- Multi-license: MIT OR CC0-1.0
12898
+ Multi-license: CC0-1.0 OR MIT
12873
12899
 
12874
12900
 
12875
12901
  --------------------------------------------------------------------------------
@@ -22283,6 +22309,30 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22283
22309
  THE SOFTWARE.
22284
22310
 
22285
22311
 
22312
+ * MIT *
22313
+
22314
+ MIT License
22315
+
22316
+ Copyright (C) 2020 by Marijn Haverbeke <marijn@haverbeke.berlin>, Arun Srinivasan <rulfzid@gmail.com>, and others
22317
+
22318
+ Permission is hereby granted, free of charge, to any person obtaining a copy
22319
+ of this software and associated documentation files (the "Software"), to deal
22320
+ in the Software without restriction, including without limitation the rights
22321
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
22322
+ copies of the Software, and to permit persons to whom the Software is
22323
+ furnished to do so, subject to the following conditions:
22324
+
22325
+ The above copyright notice and this permission notice shall be included in
22326
+ all copies or substantial portions of the Software.
22327
+
22328
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22329
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22330
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22331
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22332
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22333
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22334
+ THE SOFTWARE.
22335
+
22286
22336
  * MIT *
22287
22337
 
22288
22338
  MIT License
@@ -29357,4 +29407,4 @@ POSSIBILITY OF SUCH DAMAGE.
29357
29407
  --------------------------------------------------------------------------------
29358
29408
  --------------------------------------------------------------------------------
29359
29409
 
29360
- Report Generated by FOSSA on 2026-8-10
29410
+ Report Generated by FOSSA on 2026-8-13
@@ -20,6 +20,7 @@ export type LinkHandlerEvent = {
20
20
  preventDefault: () => void;
21
21
  section?: "ai";
22
22
  dashboard?: IDashboard;
23
+ insights?: IInsight[];
23
24
  dashboardStatus?: "saved" | "draft";
24
25
  visualization?: IInsight;
25
26
  visualizationStatus?: "saved" | "draft";
@@ -1 +1 @@
1
- {"version":3,"file":"ConfigContext.d.ts","sourceRoot":"","sources":["../../src/components/ConfigContext.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,iBAAiB,EAAsC,MAAM,OAAO,CAAC;AAEnF,OAAO,EAAE,KAAK,WAAW,EAAE,KAAK,eAAe,EAAE,KAAK,UAAU,EAAE,KAAK,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAE7G,MAAM,MAAM,aAAa,GAAG;IACxB,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,WAAW,CAAC,EAAE,CAAC,cAAc,EAAE,gBAAgB,KAAK,MAAM,GAAG,SAAS,CAAC;IACvE,YAAY,CAAC,EAAE,WAAW,EAAE,CAAC;CAChC,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,gBAAgB,GAAG;IAC3B,IAAI,EAAE,SAAS,GAAG,eAAe,CAAC;IAClC,EAAE,EAAE,MAAM,CAAC;IACX,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,cAAc,EAAE,MAAM,IAAI,CAAC;IAC3B,OAAO,CAAC,EAAE,IAAI,CAAC;IACf,SAAS,CAAC,EAAE,UAAU,CAAC;IACvB,eAAe,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC;IACpC,aAAa,CAAC,EAAE,QAAQ,CAAC;IACzB,mBAAmB,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC;CAC3C,CAAC;AAEF;;;GAGG;AACH,MAAM,MAAM,kBAAkB,GAAG,QAAQ,GAAG,YAAY,CAAC;AAIzD,wBAAgB,cAAc,CAAC,EAC3B,QAAQ,EACR,gBAAgB,EAChB,WAAW,EACX,YAAY,EACZ,SAAS,EACT,UAAU,EACV,cAAc,EACjB,EAAE,iBAAiB,CAAC,aAAa,CAAC,2CA6BlC;AAED,eAAO,MAAM,SAAS,qBAErB,CAAC"}
1
+ {"version":3,"file":"ConfigContext.d.ts","sourceRoot":"","sources":["../../src/components/ConfigContext.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,iBAAiB,EAAsC,MAAM,OAAO,CAAC;AAEnF,OAAO,EAAE,KAAK,WAAW,EAAE,KAAK,eAAe,EAAE,KAAK,UAAU,EAAE,KAAK,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAE7G,MAAM,MAAM,aAAa,GAAG;IACxB,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,WAAW,CAAC,EAAE,CAAC,cAAc,EAAE,gBAAgB,KAAK,MAAM,GAAG,SAAS,CAAC;IACvE,YAAY,CAAC,EAAE,WAAW,EAAE,CAAC;CAChC,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,gBAAgB,GAAG;IAC3B,IAAI,EAAE,SAAS,GAAG,eAAe,CAAC;IAClC,EAAE,EAAE,MAAM,CAAC;IACX,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,cAAc,EAAE,MAAM,IAAI,CAAC;IAC3B,OAAO,CAAC,EAAE,IAAI,CAAC;IACf,SAAS,CAAC,EAAE,UAAU,CAAC;IACvB,QAAQ,CAAC,EAAE,QAAQ,EAAE,CAAC;IACtB,eAAe,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC;IACpC,aAAa,CAAC,EAAE,QAAQ,CAAC;IACzB,mBAAmB,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC;CAC3C,CAAC;AAEF;;;GAGG;AACH,MAAM,MAAM,kBAAkB,GAAG,QAAQ,GAAG,YAAY,CAAC;AAIzD,wBAAgB,cAAc,CAAC,EAC3B,QAAQ,EACR,gBAAgB,EAChB,WAAW,EACX,YAAY,EACZ,SAAS,EACT,UAAU,EACV,cAAc,EACjB,EAAE,iBAAiB,CAAC,aAAa,CAAC,2CA6BlC;AAED,eAAO,MAAM,SAAS,qBAErB,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"GenAiChatContextChooser.d.ts","sourceRoot":"","sources":["../../src/components/GenAiChatContextChooser.tsx"],"names":[],"mappings":"AAUA,OAAO,EAAE,KAAK,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAIvD,KAAK,+BAA+B,GAAG;IACnC,YAAY,CAAC,EAAE,CAAC,OAAO,EAAE,mBAAmB,KAAK,IAAI,CAAC;CACzD,CAAC;AAQF,wBAAgB,uBAAuB,CAAC,EAAE,YAAY,EAAE,EAAE,+BAA+B,kDAuDxF"}
1
+ {"version":3,"file":"GenAiChatContextChooser.d.ts","sourceRoot":"","sources":["../../src/components/GenAiChatContextChooser.tsx"],"names":[],"mappings":"AAUA,OAAO,EAAE,KAAK,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAWvD,KAAK,+BAA+B,GAAG;IACnC,YAAY,CAAC,EAAE,CAAC,OAAO,EAAE,mBAAmB,KAAK,IAAI,CAAC;CACzD,CAAC;AAEF,wBAAgB,uBAAuB,CAAC,EAAE,YAAY,EAAE,EAAE,+BAA+B,kDAoDxF"}
@@ -2,9 +2,10 @@ import { jsx as _jsx } from "react/jsx-runtime";
2
2
  // (C) 2026 GoodData Corporation
3
3
  import { defineMessages, useIntl } from "react-intl";
4
4
  import { useDispatch, useSelector } from "react-redux";
5
- import { Dropdown, UiIconButton, UiMenu, UiSubmenuHeader } from "@gooddata/sdk-ui-kit";
5
+ import { Dropdown, UiIconButton, useIdPrefixed } from "@gooddata/sdk-ui-kit";
6
6
  import { ambientContextSelector, userContextSelector } from "../store/chatWindow/chatWindowSelectors.js";
7
7
  import { addContextReferenceAction } from "../store/chatWindow/chatWindowSlice.js";
8
+ import { GenAiChatContextChooserBody } from "./GenAiChatContextChooserBody.js";
8
9
  import { useContextItems } from "./hooks/useContextItems.js";
9
10
  const msgs = defineMessages({
10
11
  add: {
@@ -14,22 +15,19 @@ const msgs = defineMessages({
14
15
  export function GenAiChatContextChooser({ onAddContext }) {
15
16
  const intl = useIntl();
16
17
  const dispatch = useDispatch();
18
+ const titleId = useIdPrefixed("context-chooser-title");
17
19
  const ambient = useSelector((state) => ambientContextSelector(state));
18
20
  const active = useSelector((state) => userContextSelector(state));
19
- const items = useContextItems(ambient, active);
21
+ const inputItems = useContextItems(ambient, active);
22
+ const addContextLabel = intl.formatMessage(msgs.add);
20
23
  if (!ambient) {
21
24
  return null;
22
25
  }
23
26
  return (_jsx("div", { className: "gd-gen-ai-chat__input__context", children: _jsx(Dropdown, { alignPoints: [{ align: "tl bl", offset: { x: 0, y: 0 } }], closeOnEscape: true, fullscreenOnMobile: false, autofocusOnOpen: true, accessibilityConfig: {}, renderButton: ({ isOpen, toggleDropdown, accessibilityConfig }) => (_jsx(UiIconButton, { icon: "plus", variant: "tertiary", size: "small", dataTestId: "choose_context", isActive: isOpen, accessibilityConfig: {
24
27
  ...accessibilityConfig,
25
- ariaLabel: intl.formatMessage(msgs.add),
26
- }, onClick: toggleDropdown, isDisabled: !items.length })), renderBody: ({ closeDropdown, ariaAttributes }) => (_jsx(UiMenu, { dataTestId: "agent_dropdown_menu", items: items, size: "medium", minWidth: 245, maxWidth: 245, containerTopPadding: "none", containerBottomPadding: "none", MenuHeader: ContextMenuHeader, ariaAttributes: ariaAttributes, onSelect: (item) => {
27
- dispatch(addContextReferenceAction({ object: item.data }));
28
- onAddContext?.(item.data);
29
- closeDropdown();
28
+ ariaLabel: addContextLabel,
29
+ }, onClick: toggleDropdown, isDisabled: !inputItems.length })), renderBody: ({ closeDropdown, ariaAttributes }) => (_jsx(GenAiChatContextChooserBody, { inputItems: inputItems, title: addContextLabel, titleId: titleId, ariaAttributes: ariaAttributes, closeDropdown: closeDropdown, onSelect: (item) => {
30
+ dispatch(addContextReferenceAction({ object: item }));
31
+ onAddContext?.(item);
30
32
  } })) }) }));
31
33
  }
32
- function ContextMenuHeader() {
33
- const intl = useIntl();
34
- return _jsx(UiSubmenuHeader, { title: intl.formatMessage(msgs.add), height: "medium" });
35
- }
@@ -0,0 +1,17 @@
1
+ import { type IGenAIContextObject } from "../types.js";
2
+ type GenAiChatContextChooserBodyProps = {
3
+ inputItems: IGenAIContextObject[];
4
+ title: string;
5
+ titleId: string;
6
+ isLoading?: boolean;
7
+ ariaAttributes: {
8
+ id: string;
9
+ role?: string;
10
+ "aria-labelledby"?: string;
11
+ };
12
+ onSelect: (item: IGenAIContextObject) => void;
13
+ closeDropdown: () => void;
14
+ };
15
+ export declare function GenAiChatContextChooserBody({ inputItems, title, titleId, isLoading, ariaAttributes, onSelect, closeDropdown }: GenAiChatContextChooserBodyProps): import("react/jsx-runtime").JSX.Element;
16
+ export {};
17
+ //# sourceMappingURL=GenAiChatContextChooserBody.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GenAiChatContextChooserBody.d.ts","sourceRoot":"","sources":["../../src/components/GenAiChatContextChooserBody.tsx"],"names":[],"mappings":"AAsBA,OAAO,EAAE,KAAK,mBAAmB,EAAE,MAAM,aAAa,CAAC;AA6BvD,KAAK,gCAAgC,GAAG;IACpC,UAAU,EAAE,mBAAmB,EAAE,CAAC;IAClC,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,cAAc,EAAE;QACZ,EAAE,EAAE,MAAM,CAAC;QACX,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,iBAAiB,CAAC,EAAE,MAAM,CAAC;KAC9B,CAAC;IACF,QAAQ,EAAE,CAAC,IAAI,EAAE,mBAAmB,KAAK,IAAI,CAAC;IAC9C,aAAa,EAAE,MAAM,IAAI,CAAC;CAC7B,CAAC;AAEF,wBAAgB,2BAA2B,CAAC,EACxC,UAAU,EACV,KAAK,EACL,OAAO,EACP,SAAiB,EACjB,cAAc,EACd,QAAQ,EACR,aAAa,EAChB,EAAE,gCAAgC,2CA+HlC"}
@@ -0,0 +1,82 @@
1
+ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ // (C) 2026 GoodData Corporation
3
+ import { useCallback, useId, useMemo, useState } from "react";
4
+ import cx from "classnames";
5
+ import { defineMessages, useIntl } from "react-intl";
6
+ import { DEFAULT_ITEM_HEIGHT, DETAILED_ANNOUNCEMENT_THRESHOLD, Input, NoData, ScopedIdStore, ShortenedText, UiIcon, UiPagedVirtualList, UiSearchResultsAnnouncement, UiSubmenuHeader, isTypingKey, useScopedIdStoreValue, } from "@gooddata/sdk-ui-kit";
7
+ import { getIconByType } from "./utils/icons.js";
8
+ const SEARCH_FIELD_VISIBILITY_THRESHOLD = 7;
9
+ const MAX_VISIBLE_ITEMS = 7;
10
+ const LOADING_SKELETON_ITEMS_COUNT = 3;
11
+ const msgs = defineMessages({
12
+ close: {
13
+ id: "gd.gen-ai.context.close",
14
+ },
15
+ listAriaLabel: {
16
+ id: "gd.gen-ai.context.list.ariaLabel",
17
+ },
18
+ searchPlaceholder: {
19
+ id: "gd.gen-ai.context.search.placeholder",
20
+ },
21
+ searchAriaLabel: {
22
+ id: "gd.gen-ai.context.search.ariaLabel",
23
+ },
24
+ noMatchingData: {
25
+ id: "gd.gen-ai.context.noMatchingData",
26
+ },
27
+ noDataAvailable: {
28
+ id: "gd.gen-ai.context.noDataAvailable",
29
+ },
30
+ });
31
+ export function GenAiChatContextChooserBody({ inputItems, title, titleId, isLoading = false, ariaAttributes, onSelect, closeDropdown, }) {
32
+ const intl = useIntl();
33
+ const listboxId = useId();
34
+ const [searchString, setSearchString] = useState("");
35
+ const isSearchFieldVisible = inputItems.length > SEARCH_FIELD_VISIBILITY_THRESHOLD && !isLoading;
36
+ const searchStringToUse = isSearchFieldVisible ? searchString : "";
37
+ const normalizedSearch = searchStringToUse.trim().toLowerCase();
38
+ const filteredItems = useMemo(() => {
39
+ if (!normalizedSearch) {
40
+ return inputItems;
41
+ }
42
+ return inputItems.filter((item) => item.title.toLowerCase().includes(normalizedSearch));
43
+ }, [inputItems, normalizedSearch]);
44
+ const scopedIdStoreValue = useScopedIdStoreValue((item) => `${item.type}-${item.id}`);
45
+ const handleSelect = useCallback((item) => {
46
+ onSelect(item);
47
+ closeDropdown();
48
+ }, [closeDropdown, onSelect]);
49
+ const hasNoData = !isLoading && filteredItems.length === 0;
50
+ const hasNoMatchingData = hasNoData && normalizedSearch.length > 0;
51
+ const searchFilled = searchString.length > 0;
52
+ const onEscKeyPress = useCallback((event) => {
53
+ if (searchFilled) {
54
+ event.stopPropagation();
55
+ }
56
+ else {
57
+ closeDropdown();
58
+ }
59
+ }, [closeDropdown, searchFilled]);
60
+ const listMaxHeight = Math.min(Math.max(filteredItems.length, 1), MAX_VISIBLE_ITEMS) * DEFAULT_ITEM_HEIGHT;
61
+ return (_jsxs("div", { ...ariaAttributes, "aria-labelledby": titleId, className: "gd-gen-ai-chat__context-chooser", "data-testid": "context_chooser_menu", children: [
62
+ _jsx(UiSubmenuHeader, { title: title, titleId: titleId, height: "medium", onClose: closeDropdown, closeAriaLabel: intl.formatMessage(msgs.close) }), isSearchFieldVisible ? (_jsxs(_Fragment, { children: [
63
+ _jsx("div", { onKeyDown: (event) => {
64
+ if (isTypingKey(event)) {
65
+ event.stopPropagation();
66
+ }
67
+ }, children: _jsx(Input, { className: cx("gd-list-searchfield", "gd-flex-item"), value: searchStringToUse, onChange: (value) => setSearchString(String(value)), onEscKeyPress: onEscKeyPress, placeholder: intl.formatMessage(msgs.searchPlaceholder), autofocus: true, clearOnEsc: true, isSearch: true, isSmall: true, type: "search", accessibilityConfig: {
68
+ ariaLabel: intl.formatMessage(msgs.searchAriaLabel),
69
+ ariaControls: listboxId,
70
+ } }) }), _jsx(UiSearchResultsAnnouncement, { totalResults: normalizedSearch ? filteredItems.length : undefined, resultValues: filteredItems.length <= DETAILED_ANNOUNCEMENT_THRESHOLD
71
+ ? filteredItems.map((item) => item.title)
72
+ : undefined })
73
+ ] })) : null, hasNoData ? (_jsx(NoData, { hasNoMatchingData: hasNoMatchingData, notFoundLabel: intl.formatMessage(msgs.noMatchingData), noDataLabel: intl.formatMessage(msgs.noDataAvailable) })) : (_jsx(ScopedIdStore, { value: scopedIdStoreValue, children: _jsx(UiPagedVirtualList, { maxHeight: listMaxHeight, items: filteredItems, itemHeight: DEFAULT_ITEM_HEIGHT, itemsGap: 0, itemPadding: 0, skeletonItemsCount: isLoading ? LOADING_SKELETON_ITEMS_COUNT : 0, isLoading: isLoading, representAs: "listbox", closeDropdown: closeDropdown, onKeyDownConfirm: handleSelect, listboxProps: {
74
+ id: listboxId,
75
+ "aria-label": intl.formatMessage(msgs.listAriaLabel),
76
+ }, children: (item) => _jsx(ContextChooserItem, { item: item, onSelect: () => handleSelect(item) }) }) }))] }));
77
+ }
78
+ function ContextChooserItem({ item, onSelect }) {
79
+ const icon = getIconByType(item.type);
80
+ return (_jsxs("div", { className: "gd-list-item", title: item.title, onClick: onSelect, children: [icon.iconBefore ? _jsx(UiIcon, { size: 16, type: icon.iconBefore, color: icon.iconColor }) : null, _jsx(ShortenedText, { ellipsisPosition: "end", children: item.title })
81
+ ] }));
82
+ }
@@ -1,7 +1,4 @@
1
1
  import { type IGenAIUserContext } from "@gooddata/sdk-model";
2
- import { type IUiMenuItem } from "@gooddata/sdk-ui-kit";
3
2
  import { type IGenAIContextObject } from "../../types.js";
4
- export declare function useContextItems(ambient: IGenAIUserContext | undefined, active: IGenAIUserContext | undefined): IUiMenuItem<{
5
- interactive: IGenAIContextObject;
6
- }>[];
3
+ export declare function useContextItems(ambient: IGenAIUserContext | undefined, active: IGenAIUserContext | undefined): IGenAIContextObject[];
7
4
  //# sourceMappingURL=useContextItems.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"useContextItems.d.ts","sourceRoot":"","sources":["../../../src/components/hooks/useContextItems.tsx"],"names":[],"mappings":"AAMA,OAAO,EAAE,KAAK,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAC7D,OAAO,EAAE,KAAK,WAAW,EAAU,MAAM,sBAAsB,CAAC;AAMhE,OAAO,EAAE,KAAK,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAG1D,wBAAgB,eAAe,CAC3B,OAAO,EAAE,iBAAiB,GAAG,SAAS,EACtC,MAAM,EAAE,iBAAiB,GAAG,SAAS,GACtC,WAAW,CAAC;IAAE,WAAW,EAAE,mBAAmB,CAAA;CAAE,CAAC,EAAE,CAmCrD"}
1
+ {"version":3,"file":"useContextItems.d.ts","sourceRoot":"","sources":["../../../src/components/hooks/useContextItems.tsx"],"names":[],"mappings":"AAMA,OAAO,EAAE,KAAK,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAM7D,OAAO,EAAE,KAAK,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAE1D,wBAAgB,eAAe,CAC3B,OAAO,EAAE,iBAAiB,GAAG,SAAS,EACtC,MAAM,EAAE,iBAAiB,GAAG,SAAS,GACtC,mBAAmB,EAAE,CAgBvB"}
@@ -1,34 +1,13 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
2
1
  // (C) 2026 GoodData Corporation
3
2
  import { useMemo } from "react";
4
3
  import { useIntl } from "react-intl";
5
- import { UiIcon } from "@gooddata/sdk-ui-kit";
6
4
  import { collectAvailableReferences, collectContextReferences, } from "../../context/collectContextReferences.js";
7
- import { getIconByType } from "../utils/icons.js";
8
5
  export function useContextItems(ambient, active) {
9
6
  const intl = useIntl();
10
7
  const emptyReferenceLabel = intl.formatMessage({ id: "gd.gen-ai.context.untitled" });
11
8
  return useMemo(() => {
12
- const items = [];
13
9
  const currentReferences = collectAvailableReferences(ambient, emptyReferenceLabel);
14
10
  const selectedReferences = collectContextReferences(active, emptyReferenceLabel);
15
- currentReferences.forEach((reference) => {
16
- const isSelected = selectedReferences.some((selectedReference) => selectedReference.id === reference.id && selectedReference.type === reference.type);
17
- if (!isSelected) {
18
- const icon = getIconByType(reference.type);
19
- items.push({
20
- type: "interactive",
21
- id: reference.id,
22
- data: reference,
23
- stringTitle: reference.title,
24
- ...(icon.iconBefore
25
- ? {
26
- iconLeft: _jsx(UiIcon, { size: 16, type: icon.iconBefore, color: icon.iconColor }),
27
- }
28
- : {}),
29
- });
30
- }
31
- });
32
- return items;
11
+ return currentReferences.filter((reference) => !selectedReferences.some((selectedReference) => selectedReference.id === reference.id && selectedReference.type === reference.type));
33
12
  }, [active, ambient, emptyReferenceLabel]);
34
13
  }
@@ -1 +1 @@
1
- {"version":3,"file":"categoryDetailRows.d.ts","sourceRoot":"","sources":["../../../../src/components/intelligence/data/categoryDetailRows.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAIR,2BAA2B,EAG9B,MAAM,2BAA2B,CAAC;AAGnC,OAAO,KAAK,EACR,mCAAmC,EAEnC,yBAAyB,EAC5B,MAAM,YAAY,CAAC;AAsCpB;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,2BAA2B,GAAG,mCAAmC,EAAE,CAe3G;AA2CD,uEAAuE;AACvE,wBAAgB,aAAa,CAAC,MAAM,EAAE,2BAA2B,GAAG,yBAAyB,EAAE,CAe9F"}
1
+ {"version":3,"file":"categoryDetailRows.d.ts","sourceRoot":"","sources":["../../../../src/components/intelligence/data/categoryDetailRows.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAKR,2BAA2B,EAI9B,MAAM,2BAA2B,CAAC;AAGnC,OAAO,KAAK,EACR,mCAAmC,EAEnC,yBAAyB,EAC5B,MAAM,YAAY,CAAC;AAiDpB;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,2BAA2B,GAAG,mCAAmC,EAAE,CAmB3G;AAqED,uEAAuE;AACvE,wBAAgB,aAAa,CAAC,MAAM,EAAE,2BAA2B,GAAG,yBAAyB,EAAE,CAmB9F"}
@@ -27,6 +27,10 @@ const MESSAGES = defineMessages({
27
27
  searched: { id: "gd.gen-ai.interactionIntelligence.detail.searched" },
28
28
  found: { id: "gd.gen-ai.interactionIntelligence.detail.found" },
29
29
  used: { id: "gd.gen-ai.interactionIntelligence.detail.used" },
30
+ useAlways: { id: "gd.gen-ai.interactionIntelligence.detail.useAlways" },
31
+ useWhenRelevant: { id: "gd.gen-ai.interactionIntelligence.detail.useWhenRelevant" },
32
+ appliedInTotal: { id: "gd.gen-ai.interactionIntelligence.detail.appliedInTotal" },
33
+ memoriesCount: { id: "gd.gen-ai.interactionIntelligence.detail.memoriesCount" },
30
34
  skillsCount: { id: "gd.gen-ai.interactionIntelligence.detail.skillsCount" },
31
35
  foundGroup: { id: "gd.gen-ai.interactionIntelligence.detail.foundGroup" },
32
36
  matchScore: { id: "gd.gen-ai.interactionIntelligence.detail.matchScore" },
@@ -34,6 +38,13 @@ const MESSAGES = defineMessages({
34
38
  excerptUsed: { id: "gd.gen-ai.interactionIntelligence.excerpt.used" },
35
39
  excerptDocuments: { id: "gd.gen-ai.interactionIntelligence.excerpt.documents" },
36
40
  excerptActivated: { id: "gd.gen-ai.interactionIntelligence.excerpt.activated" },
41
+ excerptMemories: { id: "gd.gen-ai.interactionIntelligence.excerpt.memories" },
42
+ metrics: { id: "gd.gen-ai.interactionIntelligence.detail.metrics" },
43
+ groupedBy: { id: "gd.gen-ai.interactionIntelligence.detail.groupedBy" },
44
+ filteredBy: { id: "gd.gen-ai.interactionIntelligence.detail.filteredBy" },
45
+ visualization: { id: "gd.gen-ai.interactionIntelligence.detail.visualization" },
46
+ result: { id: "gd.gen-ai.interactionIntelligence.detail.result" },
47
+ resultSize: { id: "gd.gen-ai.interactionIntelligence.detail.resultSize" },
37
48
  });
38
49
  /**
39
50
  * The list row's right-hand excerpt for one occurrence of a category, built from the same
@@ -43,10 +54,14 @@ const MESSAGES = defineMessages({
43
54
  */
44
55
  export function excerptForDetail(detail) {
45
56
  switch (detail.category) {
57
+ case "applyMemory":
58
+ return applyMemoryExcerpt(detail);
46
59
  case "catalogSearch":
47
60
  return catalogSearchExcerpt(detail);
48
61
  case "knowledgeSearch":
49
62
  return knowledgeSearchExcerpt(detail);
63
+ case "metricQuery":
64
+ return metricQueryExcerpt(detail);
50
65
  case "skillRouting":
51
66
  return skillRoutingExcerpt(detail);
52
67
  case "composeAnswer":
@@ -60,6 +75,9 @@ export function excerptForDetail(detail) {
60
75
  function countFragment(id, count) {
61
76
  return count > 0 ? [{ id, values: { count } }] : [];
62
77
  }
78
+ function applyMemoryExcerpt(detail) {
79
+ return countFragment(MESSAGES.excerptMemories.id, detail.items.length);
80
+ }
63
81
  function catalogSearchExcerpt(detail) {
64
82
  const foundCount = detail.found.reduce((sum, group) => sum + group.titles.length, 0);
65
83
  return [
@@ -70,6 +88,20 @@ function catalogSearchExcerpt(detail) {
70
88
  function knowledgeSearchExcerpt(detail) {
71
89
  return countFragment(MESSAGES.excerptDocuments.id, detail.documents.length);
72
90
  }
91
+ /**
92
+ * The size of what a query returned, once both of its halves are known. Not keyed on `count`,
93
+ * which the caller would sum across occurrences — a size must not be summed.
94
+ */
95
+ function resultSize(detail) {
96
+ const { resultRows, resultColumns } = detail;
97
+ return resultRows === undefined || resultColumns === undefined
98
+ ? undefined
99
+ : { rows: resultRows, columns: resultColumns };
100
+ }
101
+ function metricQueryExcerpt(detail) {
102
+ const size = resultSize(detail);
103
+ return size ? [{ id: MESSAGES.resultSize.id, values: size }] : [];
104
+ }
73
105
  function skillRoutingExcerpt(detail) {
74
106
  return countFragment(MESSAGES.excerptActivated.id, detail.activated.length);
75
107
  }
@@ -87,10 +119,14 @@ function composeAnswerExcerpt(detail) {
87
119
  /** The category's detail rows, built from one action's detail body. */
88
120
  export function rowsForDetail(detail) {
89
121
  switch (detail.category) {
122
+ case "applyMemory":
123
+ return applyMemoryRows(detail);
90
124
  case "catalogSearch":
91
125
  return catalogSearchRows(detail);
92
126
  case "knowledgeSearch":
93
127
  return knowledgeSearchRows(detail);
128
+ case "metricQuery":
129
+ return metricQueryRows(detail);
94
130
  case "skillRouting":
95
131
  return skillRoutingRows(detail);
96
132
  case "composeAnswer":
@@ -106,10 +142,10 @@ export function rowsForDetail(detail) {
106
142
  * `text` drawn from a known/stable set (e.g. {@link ANSWER_OUTPUT_LABEL_MESSAGES}) — absent
107
143
  * otherwise, when the text is never translated.
108
144
  */
109
- function textRow(labelId, text, textId) {
145
+ function textRow(labelId, text, textId, textValues) {
110
146
  return text === undefined || text === ""
111
147
  ? []
112
- : [{ labelId, value: { kind: "text", text: String(text), textId } }];
148
+ : [{ labelId, value: { kind: "text", text: String(text), textId, textValues } }];
113
149
  }
114
150
  /**
115
151
  * A row listing `items`, truncated past {@link MAX_DETAIL_LIST_ITEMS}, or nothing when the list
@@ -148,11 +184,24 @@ function knowledgeSearchRows(detail) {
148
184
  ...textRow(MESSAGES.bestMatch.id, detail.bestMatch),
149
185
  ];
150
186
  }
187
+ /** A query's request and execution arrive separately, so each half builds only the rows it covers. */
188
+ function metricQueryRows(detail) {
189
+ const size = resultSize(detail);
190
+ return [
191
+ ...listRow(MESSAGES.metrics.id, labels(detail.metrics)),
192
+ ...listRow(MESSAGES.groupedBy.id, labels(detail.groupedBy)),
193
+ ...listRow(MESSAGES.filteredBy.id, labels(detail.filteredBy)),
194
+ ...textRow(MESSAGES.visualization.id, detail.visualization),
195
+ ...(size ? textRow(MESSAGES.result.id, size.rows, MESSAGES.resultSize.id, size) : []),
196
+ ];
197
+ }
151
198
  function skillRoutingRows(detail) {
152
- const availableCount = detail.available.length;
153
199
  return [
154
- ...listRow(MESSAGES.available.id, detail.available.map((skill) => ({ label: skill })), { id: MESSAGES.skillsCount.id, values: { count: availableCount } }),
155
- ...listRow(MESSAGES.activated.id, detail.activated.map((skill) => ({ label: skill }))),
200
+ ...listRow(MESSAGES.available.id, labels(detail.available), {
201
+ id: MESSAGES.skillsCount.id,
202
+ values: { count: detail.available.length },
203
+ }),
204
+ ...listRow(MESSAGES.activated.id, labels(detail.activated)),
156
205
  ];
157
206
  }
158
207
  function composeAnswerRows(detail) {
@@ -165,11 +214,41 @@ function composeAnswerRows(detail) {
165
214
  ...textRow(MESSAGES.suggestedActions.id, detail.suggestedActions),
166
215
  ];
167
216
  }
217
+ /** Counts every item it applied, but lists only the titled ones — an untitled item was still applied. */
218
+ function memoryStrategyRow(labelId, items) {
219
+ if (items.length === 0) {
220
+ return [];
221
+ }
222
+ const listed = items.filter((item) => item.title !== "");
223
+ return [
224
+ {
225
+ labelId,
226
+ value: {
227
+ kind: "list",
228
+ heading: MESSAGES.memoriesCount.id,
229
+ headingId: MESSAGES.memoriesCount.id,
230
+ headingValues: { count: items.length },
231
+ ...truncate(listed.map((item) => ({ label: item.title, meta: scoreMeta(item.score) }))),
232
+ },
233
+ },
234
+ ];
235
+ }
236
+ function applyMemoryRows(detail) {
237
+ const { items } = detail;
238
+ return [
239
+ ...memoryStrategyRow(MESSAGES.useAlways.id, items.filter((item) => item.strategy === "always")),
240
+ ...memoryStrategyRow(MESSAGES.useWhenRelevant.id, items.filter((item) => item.strategy === "auto")),
241
+ // A count with no list under it, so a text row rather than a headed empty list.
242
+ ...textRow(MESSAGES.appliedInTotal.id, items.length || undefined, MESSAGES.memoriesCount.id, {
243
+ count: items.length,
244
+ }),
245
+ ];
246
+ }
168
247
  function catalogSearchRows(detail) {
169
248
  const found = detail.found.filter((group) => group.titles.length > 0);
170
249
  return [
171
250
  ...listRow(MESSAGES.query.id, detail.query.map((keyword) => ({ label: keyword }))),
172
- ...listRow(MESSAGES.searched.id, detail.requestedTypes.map((type) => ({ label: type }))),
251
+ ...listRow(MESSAGES.searched.id, labels(detail.requestedTypes)),
173
252
  ...(found.length === 0
174
253
  ? []
175
254
  : [
@@ -186,7 +265,7 @@ function catalogSearchRows(detail) {
186
265
  count: group.titles.length,
187
266
  objectType: group.objectType,
188
267
  },
189
- ...truncate(group.titles.map((title) => ({ label: title }))),
268
+ ...truncate(labels(group.titles)),
190
269
  })),
191
270
  },
192
271
  },
@@ -194,6 +273,10 @@ function catalogSearchRows(detail) {
194
273
  ...listRow(MESSAGES.used.id, detail.used.map((match) => ({ label: match.title, meta: scoreMeta(match.score) }))),
195
274
  ];
196
275
  }
276
+ /** Plain strings as list items. */
277
+ function labels(values) {
278
+ return values.map((label) => ({ label }));
279
+ }
197
280
  /** Caps a list at {@link MAX_DETAIL_LIST_ITEMS}, reporting the remainder as `truncatedCount`. */
198
281
  function truncate(items) {
199
282
  if (items.length <= MAX_DETAIL_LIST_ITEMS) {
@@ -10,6 +10,8 @@ import type { IInteractionIntelligence, IInteractionIntelligenceTotals } from ".
10
10
  * though its step keeps its time regardless.
11
11
  *
12
12
  * A tile's `index` is its array position, not the backend's `stepIndex` — it is the highlight key.
13
+ * A category can also come from a detail that belongs to the response rather than a step, which
14
+ * yields a row with no `stepIndexes` and so nothing to highlight.
13
15
  * @internal
14
16
  */
15
17
  export declare function deriveInteractionIntelligenceFromSteps(responseId: string, trace: IChatConversationResponseTrace): IInteractionIntelligence;
@@ -1 +1 @@
1
- {"version":3,"file":"deriveInteractionIntelligenceFromSteps.d.ts","sourceRoot":"","sources":["../../../../src/components/intelligence/data/deriveInteractionIntelligenceFromSteps.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,8BAA8B,EAAE,MAAM,mBAAmB,CAAC;AAIxE,OAAO,KAAK,EAIR,wBAAwB,EACxB,8BAA8B,EAEjC,MAAM,YAAY,CAAC;AAqBpB;;;;;;;;;;;GAWG;AACH,wBAAgB,sCAAsC,CAClD,UAAU,EAAE,MAAM,EAClB,KAAK,EAAE,8BAA8B,GACtC,wBAAwB,CAqD1B;AAED;;;;;GAKG;AACH,wBAAgB,mCAAmC,CAC/C,KAAK,EAAE,8BAA8B,GACtC,8BAA8B,CAYhC"}
1
+ {"version":3,"file":"deriveInteractionIntelligenceFromSteps.d.ts","sourceRoot":"","sources":["../../../../src/components/intelligence/data/deriveInteractionIntelligenceFromSteps.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,8BAA8B,EAAE,MAAM,mBAAmB,CAAC;AAIxE,OAAO,KAAK,EAIR,wBAAwB,EACxB,8BAA8B,EAEjC,MAAM,YAAY,CAAC;AAqBpB;;;;;;;;;;;;;GAaG;AACH,wBAAgB,sCAAsC,CAClD,UAAU,EAAE,MAAM,EAClB,KAAK,EAAE,8BAA8B,GACtC,wBAAwB,CAgE1B;AAED;;;;;GAKG;AACH,wBAAgB,mCAAmC,CAC/C,KAAK,EAAE,8BAA8B,GACtC,8BAA8B,CAYhC"}
@@ -24,11 +24,23 @@ const CATEGORY_LABEL_MESSAGES = defineMessages({
24
24
  * though its step keeps its time regardless.
25
25
  *
26
26
  * A tile's `index` is its array position, not the backend's `stepIndex` — it is the highlight key.
27
+ * A category can also come from a detail that belongs to the response rather than a step, which
28
+ * yields a row with no `stepIndexes` and so nothing to highlight.
27
29
  * @internal
28
30
  */
29
31
  export function deriveInteractionIntelligenceFromSteps(responseId, trace) {
30
32
  const sorted = [...trace.steps].sort((a, b) => a.stepIndex - b.stepIndex);
31
33
  const byCategory = new Map();
34
+ // Seeded first, so a response-scoped category sorts above the steps' own — it happened before
35
+ // them. Its `stepIndexes` stay empty: there is no tile it ran in.
36
+ for (const { detail } of trace.responseDetails ?? []) {
37
+ if (!detail) {
38
+ continue;
39
+ }
40
+ const entry = byCategory.get(detail.category) ?? { stepIndexes: [], details: [] };
41
+ byCategory.set(detail.category, entry);
42
+ entry.details.push(detail);
43
+ }
32
44
  const steps = sorted.map((step, index) => {
33
45
  const actions = trace.detailsByStepId[step.stepId] ?? [];
34
46
  const categoriesInStep = [];
@@ -5,7 +5,9 @@ import type { IInteractionStepDetailRow } from "./types.js";
5
5
  * across occurrences merges by value kind:
6
6
  * - `list` rows concatenate `items` (and sum `truncatedCount`), keeping the first occurrence
7
7
  * that authors a `heading`/`bulleted`.
8
- * - `groups` rows concatenate the `groups` arrays across occurrences.
8
+ * - `groups` rows concatenate the `groups` arrays across occurrences, then merge groups that
9
+ * describe the same thing (same heading key, e.g. Catalogue search's `objectType`) the same way
10
+ * `list` rows merge — so two steps each finding metrics render one metric group, not two.
9
11
  * - `text` rows become a plain, unheaded `list` of each occurrence's text as one item — the same
10
12
  * "stacked plain list" look already used for single-occurrence match lists like "Used".
11
13
  * - Mismatched kinds across occurrences fall back to the first occurrence's row.
@@ -1 +1 @@
1
- {"version":3,"file":"mergeDetailRows.d.ts","sourceRoot":"","sources":["../../../../src/components/intelligence/data/mergeDetailRows.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAA8B,yBAAyB,EAAE,MAAM,YAAY,CAAC;AAExF;;;;;;;;;;;GAWG;AACH,wBAAgB,eAAe,CAAC,SAAS,EAAE,yBAAyB,EAAE,EAAE,GAAG,yBAAyB,EAAE,CAcrG"}
1
+ {"version":3,"file":"mergeDetailRows.d.ts","sourceRoot":"","sources":["../../../../src/components/intelligence/data/mergeDetailRows.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAA8B,yBAAyB,EAAE,MAAM,YAAY,CAAC;AAExF;;;;;;;;;;;;;GAaG;AACH,wBAAgB,eAAe,CAAC,SAAS,EAAE,yBAAyB,EAAE,EAAE,GAAG,yBAAyB,EAAE,CAcrG"}