@gooddata/sdk-ui-gen-ai 11.57.0-alpha.1 → 11.57.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.
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-9-10
10
+ Date generated: 2026-9-13
11
11
 
12
- Revision ID: 134c47a0c4df31513dbb70f1253bfcf3a9a37ca9
12
+ Revision ID: 6137e079cb078a0bcfbae6cca294b0e3b8efb320
13
13
 
14
14
  ================================================================================
15
15
  ================================================================================
@@ -43212,7 +43212,7 @@ MIT
43212
43212
 
43213
43213
  Authors: richiebendall@gmail.com
43214
43214
  Package Manager: NPM
43215
- Project URL: https://www.npmjs.com/package/char-regex
43215
+ Project URL: https://github.com/Richienb/char-regex#readme
43216
43216
  Package Download URL: https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz
43217
43217
  Dependency Path: remark-emoji > node-emoji > char-regex
43218
43218
  File Path(s): common/config/subspaces/sdk/pnpm-lock.yaml
@@ -48198,7 +48198,7 @@ MIT
48198
48198
 
48199
48199
  Authors: tituswormer@gmail.com
48200
48200
  Package Manager: NPM
48201
- Project URL: https://www.npmjs.com/package/micromark-extension-gfm-table
48201
+ Project URL: https://github.com/micromark/micromark-extension-gfm-table#readme
48202
48202
  Package Download URL: https://registry.npmjs.org/micromark-extension-gfm-table/-/micromark-extension-gfm-table-2.1.1.tgz
48203
48203
  Dependency Path: remark-gfm > micromark-extension-gfm > micromark-extension-gfm-table
48204
48204
  File Path(s): common/config/subspaces/sdk/pnpm-lock.yaml
@@ -64353,4 +64353,4 @@ File Path(s): common/config/subspaces/sdk/pnpm-lock.yaml
64353
64353
  --------------------------------------------------------------------------------
64354
64354
  --------------------------------------------------------------------------------
64355
64355
 
64356
- Report Generated by FOSSA on 2026-9-10
64356
+ Report Generated by FOSSA on 2026-9-13
@@ -1 +1 @@
1
- {"version":3,"file":"CustomHyperlink.d.ts","sourceRoot":"","sources":["../../../../src/components/messages/contents/CustomHyperlink.tsx"],"names":[],"mappings":"AAMA,OAAO,EAAE,KAAK,sBAAsB,EAAE,MAAM,2BAA2B,CAAC;AAKxE,MAAM,MAAM,uBAAuB,GAAG;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,KAAK,oBAAoB,GAAG,uBAAuB,GAAG;IAClD,QAAQ,CAAC,EAAE,sBAAsB,CAAC;CACrC,CAAC;AAEF;;;GAGG;AACH,wBAAgB,wBAAwB,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,oBAAoB,oDA4FtF;AAyBD,wBAAgB,eAAe,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,uBAAuB,2CAItE"}
1
+ {"version":3,"file":"CustomHyperlink.d.ts","sourceRoot":"","sources":["../../../../src/components/messages/contents/CustomHyperlink.tsx"],"names":[],"mappings":"AAMA,OAAO,EAAE,KAAK,sBAAsB,EAAE,MAAM,2BAA2B,CAAC;AAMxE,MAAM,MAAM,uBAAuB,GAAG;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,KAAK,oBAAoB,GAAG,uBAAuB,GAAG;IAClD,QAAQ,CAAC,EAAE,sBAAsB,CAAC;CACrC,CAAC;AAEF;;;GAGG;AACH,wBAAgB,wBAAwB,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,oBAAoB,oDAmGtF;AAyBD,wBAAgB,eAAe,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,uBAAuB,2CAItE"}
@@ -4,6 +4,7 @@ import { useMemo } from "react";
4
4
  import { useSelector } from "react-redux";
5
5
  import { settingsSelector } from "../../../store/chatWindow/chatWindowSelectors.js";
6
6
  import { useConfig } from "../../ConfigContext.js";
7
+ import { removeMarkdown } from "../../utils/markdownUtils.js";
7
8
  /**
8
9
  * Similar to SDK Hyperlink, but can handle customer schemas
9
10
  * used for links management
@@ -14,11 +15,19 @@ export function CustomHyperlinkComponent({ href, text, settings }) {
14
15
  const enableShellApplication_dashboards = Boolean(settings?.enableShellApplication_dashboards);
15
16
  const canManageMetrics = canManage || canAnalyze;
16
17
  const canManageVisualisations = canManage || canAnalyze;
18
+ const plainText = removeMarkdown(text);
17
19
  const parsedRef = useMemo(() => {
18
20
  if (!href) {
19
21
  return null;
20
22
  }
21
- const url = new URL(href);
23
+ let url;
24
+ try {
25
+ const decodedHref = decodeURIComponent(href);
26
+ url = new URL(decodedHref);
27
+ }
28
+ catch {
29
+ return null;
30
+ }
22
31
  if (url.protocol !== "gooddata:") {
23
32
  return null;
24
33
  }
@@ -40,7 +49,7 @@ export function CustomHyperlinkComponent({ href, text, settings }) {
40
49
  };
41
50
  }, [href, enableShellApplication_analyticalDesigner, enableShellApplication_dashboards]);
42
51
  if (!parsedRef) {
43
- return text;
52
+ return plainText;
44
53
  }
45
54
  const handleLinkClick = (e) => {
46
55
  if (!linkHandler) {
@@ -59,17 +68,17 @@ export function CustomHyperlinkComponent({ href, text, settings }) {
59
68
  // If the link is for a metric and the user cannot manage metrics,
60
69
  // we do not render the link
61
70
  if (parsedRef.type === "metric" && !canManageMetrics) {
62
- return text;
71
+ return plainText;
63
72
  }
64
73
  // If the link is for a visualization and the user cannot manage visualizations,
65
74
  // we do not render the link
66
75
  if (parsedRef.type === "visualization" && !canManageVisualisations) {
67
- return text;
76
+ return plainText;
68
77
  }
69
78
  if (allowNativeLinks) {
70
- return (_jsx("a", { className: "gd-hyperlink", href: parsedRef.itemUrl, onClick: handleLinkClick, children: _jsx("span", { className: "gd-hyperlink-text", children: text }) }));
79
+ return (_jsx("a", { className: "gd-hyperlink", href: parsedRef.itemUrl, onClick: handleLinkClick, children: _jsx("span", { className: "gd-hyperlink-text", children: plainText }) }));
71
80
  }
72
- return (_jsx("span", { className: "gd-hyperlink", onClick: handleLinkClick, children: _jsx("span", { className: "gd-hyperlink-text", children: text }) }));
81
+ return (_jsx("span", { className: "gd-hyperlink", onClick: handleLinkClick, children: _jsx("span", { className: "gd-hyperlink-text", children: plainText }) }));
73
82
  }
74
83
  const getItemUrl = (workspaceId, id, objectType, enableShellApplication_analyticalDesigner, enableShellApplication_dashboards) => {
75
84
  switch (objectType) {
@@ -1 +1 @@
1
- {"version":3,"file":"ConversationVisualisation.d.ts","sourceRoot":"","sources":["../../../../src/components/messages/conversationContents/ConversationVisualisation.tsx"],"names":[],"mappings":"AAOA,OAAO,EAAE,KAAK,qCAAqC,EAAE,MAAM,2BAA2B,CAAC;AACvF,OAAO,EAEH,KAAK,aAAa,EAElB,KAAK,gBAAgB,EAGrB,KAAK,WAAW,EAKnB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAEH,KAAK,gBAAgB,EACrB,KAAK,WAAW,EAInB,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EACH,KAAK,kCAAkC,EAE1C,MAAM,4BAA4B,CAAC;AAiBpC,OAAO,EAAE,KAAK,0BAA0B,EAAE,MAAM,mBAAmB,CAAC;AAyBpE,MAAM,MAAM,8BAA8B,GAAG;IACzC,OAAO,EAAE,0BAA0B,CAAC;IACpC,aAAa,EAAE,WAAW,CAAC,qCAAqC,CAAC,eAAe,CAAC,CAAC,CAAC;IACnF,YAAY,CAAC,EAAE,aAAa,CAAC;IAC7B,UAAU,CAAC,EAAE,WAAW,CAAC;IACzB,UAAU,CAAC,EAAE,gBAAgB,CAAC;IAC9B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,oBAAoB,CAAC,EAAE,CAAC,KAAK,EAAE,gBAAgB,KAAK,IAAI,CAAC;IACzD,YAAY,CAAC,EAAE,CACX,IAAI,EAAE;QACF,aAAa,EAAE,kCAAkC,EAAE,CAAC;QACpD,KAAK,EAAE,WAAW,CAAC;KACtB,GAAG,IAAI,KACP,IAAI,CAAC;IACV,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,yBAAyB,CAAC,EAAE,OAAO,CAAC;IACpC,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,4BAA4B,CAAC,EAAE,OAAO,CAAC;CAC1C,CAAC;AAEF,wBAAgB,yBAAyB,CAAC,EACtC,OAAO,EACP,YAAY,EACZ,UAAU,EACV,aAAa,EACb,UAAU,EACV,WAAW,EACX,OAAO,EACP,oBAAoB,EACpB,YAAY,EACZ,cAAqB,EACrB,oBAA4B,EAC5B,yBAAiC,EACjC,mBAA0B,EAC1B,4BAAoC,GACvC,EAAE,8BAA8B,2CA+PhC"}
1
+ {"version":3,"file":"ConversationVisualisation.d.ts","sourceRoot":"","sources":["../../../../src/components/messages/conversationContents/ConversationVisualisation.tsx"],"names":[],"mappings":"AAOA,OAAO,EAAE,KAAK,qCAAqC,EAAE,MAAM,2BAA2B,CAAC;AACvF,OAAO,EAEH,KAAK,aAAa,EAElB,KAAK,gBAAgB,EAGrB,KAAK,WAAW,EAKnB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAEH,KAAK,gBAAgB,EACrB,KAAK,WAAW,EAInB,MAAM,kBAAkB,CAAC;AAW1B,OAAO,EACH,KAAK,kCAAkC,EAE1C,MAAM,4BAA4B,CAAC;AAiBpC,OAAO,EAAE,KAAK,0BAA0B,EAAE,MAAM,mBAAmB,CAAC;AAyBpE,MAAM,MAAM,8BAA8B,GAAG;IACzC,OAAO,EAAE,0BAA0B,CAAC;IACpC,aAAa,EAAE,WAAW,CAAC,qCAAqC,CAAC,eAAe,CAAC,CAAC,CAAC;IACnF,YAAY,CAAC,EAAE,aAAa,CAAC;IAC7B,UAAU,CAAC,EAAE,WAAW,CAAC;IACzB,UAAU,CAAC,EAAE,gBAAgB,CAAC;IAC9B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,oBAAoB,CAAC,EAAE,CAAC,KAAK,EAAE,gBAAgB,KAAK,IAAI,CAAC;IACzD,YAAY,CAAC,EAAE,CACX,IAAI,EAAE;QACF,aAAa,EAAE,kCAAkC,EAAE,CAAC;QACpD,KAAK,EAAE,WAAW,CAAC;KACtB,GAAG,IAAI,KACP,IAAI,CAAC;IACV,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,yBAAyB,CAAC,EAAE,OAAO,CAAC;IACpC,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,4BAA4B,CAAC,EAAE,OAAO,CAAC;CAC1C,CAAC;AAEF,wBAAgB,yBAAyB,CAAC,EACtC,OAAO,EACP,YAAY,EACZ,UAAU,EACV,aAAa,EACb,UAAU,EACV,WAAW,EACX,OAAO,EACP,oBAAoB,EACpB,YAAY,EACZ,cAAqB,EACrB,oBAA4B,EAC5B,yBAAiC,EACjC,mBAA0B,EAC1B,4BAAoC,GACvC,EAAE,8BAA8B,2CAiRhC"}
@@ -4,7 +4,7 @@ import { useCallback, useMemo } from "react";
4
4
  import { useIntl } from "react-intl";
5
5
  import { useDispatch } from "react-redux";
6
6
  import { isAttribute, isMeasure, } from "@gooddata/sdk-model";
7
- import { BarChart, ColumnChart, Headline, LineChart, PieChart, ScatterPlot } from "@gooddata/sdk-ui-charts";
7
+ import { BarChart, ColumnChart, Headline, LineChart, PieChart, ScatterPlot, WaterfallChart, } from "@gooddata/sdk-ui-charts";
8
8
  import { getKdaKeyDriverCombinations, } from "@gooddata/sdk-ui-dashboard";
9
9
  import { PivotTable } from "@gooddata/sdk-ui-pivot";
10
10
  import { PivotTableNext, useAgGridToken } from "@gooddata/sdk-ui-pivot/next";
@@ -162,6 +162,13 @@ export function ConversationVisualisation({ message, colorPalette, separators, v
162
162
  execConfig,
163
163
  separators,
164
164
  });
165
+ case "local:waterfall":
166
+ return renderWaterfallChart(intl.locale, visualization, bucketsData, filters, sorts, colorPalette, handleSdkError, handleSuccess, handlerDrill, {
167
+ drillableItems,
168
+ enableAccessibleChartTooltip,
169
+ execConfig,
170
+ separators,
171
+ });
165
172
  case "local:headline":
166
173
  return renderHeadline(intl.locale, kpiTheme, bucketsData, filters, colorPalette, handleSdkError, handleSuccess, handlerDrill, {
167
174
  drillableItems,
@@ -248,6 +255,18 @@ const renderScatterPlot = (locale, visualization, buckets, filters, sortBy, colo
248
255
  ...(clusteringConfig && clustering ? { clustering } : {}),
249
256
  }, drillableItems: props.drillableItems, onDrill: onDrill, onError: onError, onExportReady: onSuccess, execConfig: props.execConfig }));
250
257
  };
258
+ const renderWaterfallChart = (locale, visualization, buckets, filters, sortBy, colorPalette, onError, onSuccess, onDrill, props) => {
259
+ const { metrics, view } = buckets;
260
+ const total = visualization.insight.properties["controls"]?.["total"];
261
+ return (_jsx(WaterfallChart, { locale: locale, height: VIS_HEIGHT, measures: metrics, viewBy: view[0], filters: filters, sortBy: sortBy, config: {
262
+ ...visualizationTooltipOptions,
263
+ ...legendTooltipOptions,
264
+ colorPalette,
265
+ separators: props.separators,
266
+ enableAccessibleTooltip: props.enableAccessibleChartTooltip,
267
+ ...(total ? { total } : {}),
268
+ }, drillableItems: props.drillableItems, onDrill: onDrill, onError: onError, onExportReady: onSuccess, execConfig: props.execConfig }));
269
+ };
251
270
  const renderTable = (locale, buckets, filters, sortBy, onError, onSuccess, onDrill, props) => {
252
271
  const TableComponent = props.enableNewPivotTable ? PivotTableNext : PivotTable;
253
272
  const { metrics, attribute, trend, view, stack, segment, columns } = buckets;
@@ -1 +1 @@
1
- {"version":3,"file":"markdownUtils.d.ts","sourceRoot":"","sources":["../../../src/components/utils/markdownUtils.ts"],"names":[],"mappings":"AAIA,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEnD;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAanD;AAED,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,iBAa1C"}
1
+ {"version":3,"file":"markdownUtils.d.ts","sourceRoot":"","sources":["../../../src/components/utils/markdownUtils.ts"],"names":[],"mappings":"AAKA,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEnD;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAcnD;AAED,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,iBAa1C"}
@@ -1,5 +1,6 @@
1
1
  // (C) 2025-2026 GoodData Corporation
2
2
  const MARKDOWN_ESCAPE_PATTERN = /(\{[^{}]*\})|[\\`*_{}[\]()#+\-.!]/g;
3
+ const MARKDOWN_UNESCAPE_PATTERN = /\\([\\`*_{}[\]()#+\-.!])/g;
3
4
  export function escapeMarkdown(text) {
4
5
  return text.replace(MARKDOWN_ESCAPE_PATTERN, (match, inBraces) => inBraces || `\\${match}`);
5
6
  }
@@ -8,14 +9,15 @@ export function escapeMarkdown(text) {
8
9
  */
9
10
  export function removeMarkdown(text) {
10
11
  return text
11
- .replace(/(\*\*|__)(.*?)\1/g, "$2") // bold
12
- .replace(/(\*|_)(.*?)\1/g, "$2") // italic
12
+ .replace(/(?<!\\)(\*\*|__)(.*?)(?<!\\)\1/g, "$2") // bold
13
+ .replace(/(?<!\\)(\*|_)(.*?)(?<!\\)\1/g, "$2") // italic
13
14
  .replace(/\[([^\]]+)\]\(([^)]+)\)/g, "$1") // links
14
15
  .replace(/`([^`]+)`/g, "$1") // code
15
16
  .replace(/#{1,6}\s+(.*)/gm, "$1") // headers
16
17
  .replace(/>\s+(.*)/gm, "$1") // blockquotes
17
18
  .replace(/^\s*[-*+]\s+(.*)/gm, "$1") // unordered lists
18
19
  .replace(/^\s*\d+\.\s+(.*)/gm, "$1") // ordered lists
20
+ .replace(MARKDOWN_UNESCAPE_PATTERN, "$1") // unescape markdown escaped characters
19
21
  .replace(/(\r\n|\n|\r)/gm, " ") // replace newlines with space
20
22
  .replace(/ {2,}/g, " ") // remove double spaces
21
23
  .trim();
package/esm/context.js CHANGED
@@ -1,5 +1,5 @@
1
1
  // (C) 2026 GoodData Corporation
2
- /* oxlint-disable no-barrel-files/no-barrel-files */
2
+ // oxlint-disable no-barrel-files/no-barrel-files
3
3
  import { mergeContexts } from "./context/build.js";
4
4
  import { buildDashboardContext, buildFiltersContext, buildWidgetContext, buildWidgetsContext, } from "./context/dashboard.js";
5
5
  import { buildReferenceContext, buildReferencedContext } from "./context/referencedObjects.js";
package/esm/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  // (C) 2024-2026 GoodData Corporation
2
- /* oxlint-disable no-barrel-files/no-barrel-files */
2
+ // oxlint-disable no-barrel-files/no-barrel-files
3
3
  /**
4
4
  * This package provides React components for GoodData's GenAI features.
5
5
  * @packageDocumentation
package/esm/internal.js CHANGED
@@ -1,5 +1,5 @@
1
1
  // (C) 2024-2026 GoodData Corporation
2
- /* oxlint-disable no-barrel-files/no-barrel-files */
2
+ // oxlint-disable no-barrel-files/no-barrel-files
3
3
  import { makeTextContents, makeUserMessage } from "./model.js";
4
4
  import { clearThreadAction, newMessageAction, setSelectedAgentAction, } from "./store/messages/messagesSlice.js";
5
5
  export { ChatSkeleton } from "./components/ChatSkeleton.js";
@@ -27,8 +27,8 @@ export const zh_HK = {
27
27
  "gd.gen-ai.visualization.error.data_too_large": "<b>資料過大。</b> 請套用篩選器以減少資料。",
28
28
  "gd.gen-ai.visualization.unavailable": "無法顯示可視化。",
29
29
  "gd.gen-ai.permission-error": "權限不足",
30
- "gd.gen-ai.permission-error.description": "你無權訪問聊天機械人。 請與您的管理員聯繫以請求訪問權限。",
31
- "gd.gen-ai.input-placeholder": "喺呢度提問…",
30
+ "gd.gen-ai.permission-error.description": "您無權訪問聊天機械人。 請與您的管理員聯繫以請求訪問權限。",
31
+ "gd.gen-ai.input-placeholder": "在此提問…",
32
32
  "gd.gen-ai.input-label.mac": "提出您的問題。 使用control+space或cmd+I獲取建議。",
33
33
  "gd.gen-ai.input-label.win": "提出您的問題。 使用control+space或control+I獲取建議。",
34
34
  "gd.gen-ai.context.add_context": "新增上下文",
@@ -69,18 +69,18 @@ export const zh_HK = {
69
69
  "gd.gen-ai.reasoning.thinking.description": "為複雜分析問題提供較慢但更詳盡的解答。",
70
70
  "gd.gen-ai.feedback.like": "將此消息標記為有用",
71
71
  "gd.gen-ai.feedback.dislike": "將此消息標記為無用",
72
- "gd.gen-ai.feedback.popup.title": "我哋收到你哋嘅意見",
73
- "gd.gen-ai.feedback.popup.reasons-label": "你話我哋知乜嘢出咗問題",
74
- "gd.gen-ai.feedback.popup.description-label": "唔該你講下發生咗乜嘢事",
72
+ "gd.gen-ai.feedback.popup.title": "我們已收到您的意見",
73
+ "gd.gen-ai.feedback.popup.reasons-label": "告訴我們出了什麼問題",
74
+ "gd.gen-ai.feedback.popup.description-label": "請描述發生了什麼事",
75
75
  "gd.gen-ai.feedback.popup.cancel": "取消",
76
76
  "gd.gen-ai.feedback.popup.send": "發送",
77
77
  "gd.gen-ai.feedback.popup.close": "關閉反饋對話框",
78
- "gd.gen-ai.feedback.reason.forgot-context": "唔記得之前嘅上下文",
78
+ "gd.gen-ai.feedback.reason.forgot-context": "忘記了先前的上下文",
79
79
  "gd.gen-ai.feedback.reason.ignored-instructions": "無視或拒絕指示",
80
80
  "gd.gen-ai.feedback.reason.factually-incorrect": "事實錯誤",
81
81
  "gd.gen-ai.feedback.reason.answer-too-long": "答案需時過長",
82
82
  "gd.gen-ai.feedback.reason.other": "其他",
83
- "gd.gen-ai.disclaimer": "AI助手可能會犯錯誤。 在依賴呢啲答案之前檢查。",
83
+ "gd.gen-ai.disclaimer": "AI助手可能會犯錯。 在依賴這些答案之前請先檢查。",
84
84
  "gd.gen-ai.dialog.label": "AI助手對話",
85
85
  "gd.gen-ai.header.reset-tooltip": "重置",
86
86
  "gd.gen-ai.header.conversations-tooltip": "最近對話",
@@ -88,14 +88,14 @@ export const zh_HK = {
88
88
  "gd.gen-ai.header.contract-tooltip": "收縮",
89
89
  "gd.gen-ai.header.expand-tooltip": "擴大",
90
90
  "gd.gen-ai.header.close-tooltip": "關閉助手",
91
- "gd.gen-ai.welcome.line-1": "嘿,你好",
92
- "gd.gen-ai.welcome.line-2": "我該點樣幫助你法?",
91
+ "gd.gen-ai.welcome.line-1": "嘿,您好",
92
+ "gd.gen-ai.welcome.line-2": "我該怎樣幫助您?",
93
93
  "gd.gen-ai.welcome.option-1.title": "搜索儀表板或可視化",
94
- "gd.gen-ai.welcome.option-1.answer": "當然,你希望睇到点样嘅儀錶板或可視化效果?",
94
+ "gd.gen-ai.welcome.option-1.answer": "當然,您想看到什麼樣的儀表板或可視化?",
95
95
  "gd.gen-ai.welcome.option-2.title": "創建新的可視化",
96
96
  "gd.gen-ai.welcome.option-2.answer": "當然,您想創建点样的可視化效果?",
97
97
  "gd.gen-ai.welcome.option-3.title": "答業務問題",
98
- "gd.gen-ai.welcome.option-3.answer": "當然,您想答乜嘢商業問題?",
98
+ "gd.gen-ai.welcome.option-3.answer": "當然,您想回答什麼商業問題?",
99
99
  "gd.gen-ai.semantic-search.title": "搜尋",
100
100
  "gd.gen-ai.alert-proposal.title": "通知",
101
101
  "gd.gen-ai.alert-proposal.summary.title": "名字",
@@ -179,12 +179,12 @@ export const zh_HK = {
179
179
  "gd.gen-ai.save-dialog.label": "名字",
180
180
  "gd.gen-ai.save-dialog.title": "為可視化效果命名",
181
181
  "gd.gen-ai.save-dialog.description": "為新的可視化效果指定一個新的描述性名稱,方便日後容易找到。",
182
- "gd.gen-ai.save-dialog.description.explore": "要打開此可視化,需要保存它先。 你可以喺下面為其命名。",
182
+ "gd.gen-ai.save-dialog.description.explore": "若要開啟此可視化,必須先儲存。 您可以在下方為其命名。",
183
183
  "gd.gen-ai.autocomplete.type": "類型",
184
184
  "gd.gen-ai.autocomplete.dataset": "數據",
185
185
  "gd.gen-ai.autocomplete.id": "ID",
186
186
  "gd.gen-ai.autocomplete.attribute": "屬性",
187
- "gd.gen-ai.autocomplete.metric": "計量",
187
+ "gd.gen-ai.autocomplete.metric": "指標",
188
188
  "gd.gen-ai.autocomplete.fact": "事實",
189
189
  "gd.gen-ai.autocomplete.date": "數據",
190
190
  "gd.gen-ai.autocomplete.insight": "可視化",
@@ -198,7 +198,7 @@ export const zh_HK = {
198
198
  "gd.gen-ai.visualisation.menu.button.save_as_visualisation": "保存可視化效果",
199
199
  "gd.gen-ai.visualisation.menu.button.save_as_new_visualisation": "另存為新...",
200
200
  "gd.gen-ai.visualisation.menu.button.open_in_analyze": "在Analyze中打開",
201
- "gd.gen-ai.visualisation.menu.button.open_in_analyze.description": "這會要求你先儲存視覺化,然後才能打開它。",
201
+ "gd.gen-ai.visualisation.menu.button.open_in_analyze.description": "這會要求您先儲存視覺化,然後才能打開它。",
202
202
  "gd.gen-ai.visualisation.menu.button.copy_visualisation_link": "複製可視化效果link",
203
203
  "gd.gen-ai.messages.label": "聊天消息",
204
204
  "gd.gen-ai.message.label.user": "用戶:",
@@ -208,8 +208,8 @@ export const zh_HK = {
208
208
  "gd.gen-ai.message.reasoning.tool-result": "<b>正在從工具收集資料</b>",
209
209
  "gd.gen-ai.message.reasoned.tool-result": "<b>已從工具收集資料</b>",
210
210
  "gd.gen-ai.skip-messages-history": "跳到AI助手輸入",
211
- "gd.gen-ai.skip-navigation": "跳过導航",
212
- "gd.gen-ai.changeAnalysis.default_message": "呢度係 <metric>{title}</metric> <b>{range}</b> 之間嘅關鍵驅動因素分析。",
211
+ "gd.gen-ai.skip-navigation": "跳過導航",
212
+ "gd.gen-ai.changeAnalysis.default_message": "以下是 <metric>{title}</metric> <b>{range}</b> 之間的關鍵驅動因素分析。",
213
213
  "gd.gen-ai.kda.default_message": "以下是 **{title}** 在 **{range}** 期間的關鍵驅動因素分析。",
214
214
  "gd.gen-ai.changeAnalysis.splitter": "和",
215
215
  "gd.gen-ai.changeAnalysis.explain_the_change": "開分析",
@@ -254,7 +254,7 @@ export const zh_HK = {
254
254
  "gd.gen-ai.interactionIntelligence.detail.searched": "已搜尋",
255
255
  "gd.gen-ai.interactionIntelligence.detail.found": "找到",
256
256
  "gd.gen-ai.interactionIntelligence.detail.used": "已使用",
257
- "gd.gen-ai.interactionIntelligence.detail.metrics": "計量",
257
+ "gd.gen-ai.interactionIntelligence.detail.metrics": "指標",
258
258
  "gd.gen-ai.interactionIntelligence.detail.groupedBy": "分組依據",
259
259
  "gd.gen-ai.interactionIntelligence.detail.filteredBy": "篩選依據",
260
260
  "gd.gen-ai.interactionIntelligence.detail.visualization": "可視化",
@@ -275,7 +275,7 @@ export const zh_HK = {
275
275
  "gd.gen-ai.interactionIntelligence.detail.output.searchResults": "搜尋結果",
276
276
  "gd.gen-ai.interactionIntelligence.detail.output.alertProposal": "警示建議",
277
277
  "drill.kda.from": "從",
278
- "drill.kda.in": "",
278
+ "drill.kda.in": "",
279
279
  "drill.kda.drop": "下降 {where} {title}",
280
280
  "drill.kda.increase": "增加 {where} {title}",
281
281
  "drill.kda.no_change": "無變化 {where} {title}",
@@ -4,4 +4,6 @@ export declare function setIsOpened(isOpened: boolean): void;
4
4
  export declare function saveMessages(workspaceId: string, messages: Message[]): void;
5
5
  export declare function loadMessages(workspaceId: string): Message[] | undefined;
6
6
  export declare function clearCachedMessages(workspaceId: string): void;
7
+ export declare function getLastActiveAt(workspaceId: string): number | undefined;
8
+ export declare function setLastActiveAt(workspaceId: string, timestamp: number): void;
7
9
  //# sourceMappingURL=localStorage.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"localStorage.d.ts","sourceRoot":"","sources":["../../src/store/localStorage.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAK3C,wBAAgB,WAAW,wBAU1B;AAED,wBAAgB,WAAW,CAAC,QAAQ,EAAE,OAAO,QAY5C;AAMD,wBAAgB,YAAY,CAAC,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,IAAI,CAS3E;AAED,wBAAgB,YAAY,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,EAAE,GAAG,SAAS,CAavE;AAED,wBAAgB,mBAAmB,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAS7D"}
1
+ {"version":3,"file":"localStorage.d.ts","sourceRoot":"","sources":["../../src/store/localStorage.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAM3C,wBAAgB,WAAW,wBAU1B;AAED,wBAAgB,WAAW,CAAC,QAAQ,EAAE,OAAO,QAY5C;AAMD,wBAAgB,YAAY,CAAC,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,IAAI,CAS3E;AAED,wBAAgB,YAAY,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,EAAE,GAAG,SAAS,CAavE;AAED,wBAAgB,mBAAmB,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAS7D;AAMD,wBAAgB,eAAe,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAWvE;AAED,wBAAgB,eAAe,CAAC,WAAW,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI,CAM5E"}
@@ -1,6 +1,7 @@
1
1
  // (C) 2026 GoodData Corporation
2
2
  const OPENED_KEY = "gd-gen-ai-is-opened";
3
3
  const MESSAGES_KEY_PREFIX = "gd-gen-ai-messages";
4
+ const LAST_ACTIVE_KEY_PREFIX = "gd-gen-ai-last-active";
4
5
  export function getIsOpened() {
5
6
  if (typeof localStorage !== "undefined") {
6
7
  try {
@@ -68,3 +69,27 @@ export function clearCachedMessages(workspaceId) {
68
69
  // Fail silently
69
70
  }
70
71
  }
72
+ function getLastActiveKey(workspaceId) {
73
+ return `${LAST_ACTIVE_KEY_PREFIX}-${workspaceId}`;
74
+ }
75
+ export function getLastActiveAt(workspaceId) {
76
+ try {
77
+ const raw = globalThis.localStorage?.getItem(getLastActiveKey(workspaceId));
78
+ if (!raw) {
79
+ return undefined;
80
+ }
81
+ const parsed = Number(raw);
82
+ return Number.isFinite(parsed) ? parsed : undefined;
83
+ }
84
+ catch {
85
+ return undefined;
86
+ }
87
+ }
88
+ export function setLastActiveAt(workspaceId, timestamp) {
89
+ try {
90
+ globalThis.localStorage?.setItem(getLastActiveKey(workspaceId), String(timestamp));
91
+ }
92
+ catch {
93
+ // Fail silently
94
+ }
95
+ }
@@ -0,0 +1,20 @@
1
+ /**
2
+ * How long the assistant may sit unused before the next open counts as a new session.
3
+ * @internal
4
+ */
5
+ export declare const CONVERSATION_SESSION_TIMEOUT_MS: number;
6
+ /**
7
+ * Whether the next open should start a fresh conversation instead of resuming the last one.
8
+ * A missing timestamp keeps the previous resume behaviour.
9
+ * @internal
10
+ */
11
+ export declare function isConversationSessionStale(workspaceId: string, now?: number): boolean;
12
+ /**
13
+ * @internal
14
+ */
15
+ export declare function touchConversationSession(workspaceId: string, now?: number): void;
16
+ /** Refresh the session timer on assistant interaction (not on open). @internal */
17
+ export declare function onConversationActivity(): Generator<import("redux-saga/effects").GetContextEffect, void, string>;
18
+ /** Read staleness and refresh the timer on open. Only one open path calls this per opening. @internal */
19
+ export declare function consumeStaleConversationSession(): Generator<any, boolean, any>;
20
+ //# sourceMappingURL=conversationSession.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"conversationSession.d.ts","sourceRoot":"","sources":["../../../src/store/sideEffects/conversationSession.ts"],"names":[],"mappings":"AASA;;;GAGG;AACH,eAAO,MAAM,+BAA+B,QAAqB,CAAC;AAElE;;;;GAIG;AACH,wBAAgB,0BAA0B,CAAC,WAAW,EAAE,MAAM,EAAE,GAAG,GAAE,MAAmB,GAAG,OAAO,CAIjG;AAED;;GAEG;AACH,wBAAgB,wBAAwB,CAAC,WAAW,EAAE,MAAM,EAAE,GAAG,GAAE,MAAmB,GAAG,IAAI,CAE5F;AAED,kFAAkF;AAClF,wBAAiB,sBAAsB,2EAItC;AAED,yGAAyG;AACzG,wBAAiB,+BAA+B,IAAI,SAAS,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,CAAC,CAW/E"}
@@ -0,0 +1,40 @@
1
+ // (C) 2026 GoodData Corporation
2
+ import { getContext, select } from "redux-saga/effects";
3
+ import { settingsSelector } from "../chatWindow/chatWindowSelectors.js";
4
+ import { getLastActiveAt, setLastActiveAt } from "../localStorage.js";
5
+ /**
6
+ * How long the assistant may sit unused before the next open counts as a new session.
7
+ * @internal
8
+ */
9
+ export const CONVERSATION_SESSION_TIMEOUT_MS = 8 * 60 * 60 * 1000;
10
+ /**
11
+ * Whether the next open should start a fresh conversation instead of resuming the last one.
12
+ * A missing timestamp keeps the previous resume behaviour.
13
+ * @internal
14
+ */
15
+ export function isConversationSessionStale(workspaceId, now = Date.now()) {
16
+ const lastActiveAt = getLastActiveAt(workspaceId);
17
+ return lastActiveAt !== undefined && now - lastActiveAt > CONVERSATION_SESSION_TIMEOUT_MS;
18
+ }
19
+ /**
20
+ * @internal
21
+ */
22
+ export function touchConversationSession(workspaceId, now = Date.now()) {
23
+ setLastActiveAt(workspaceId, now);
24
+ }
25
+ /** Refresh the session timer on assistant interaction (not on open). @internal */
26
+ export function* onConversationActivity() {
27
+ const workspace = yield getContext("workspace");
28
+ touchConversationSession(workspace);
29
+ }
30
+ /** Read staleness and refresh the timer on open. Only one open path calls this per opening. @internal */
31
+ export function* consumeStaleConversationSession() {
32
+ const settings = yield select(settingsSelector);
33
+ if (!settings?.enableAiAgenticConversations || !settings?.enableAiAgenticMultiConversations) {
34
+ return false;
35
+ }
36
+ const workspace = yield getContext("workspace");
37
+ const stale = isConversationSessionStale(workspace);
38
+ touchConversationSession(workspace);
39
+ return stale;
40
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/store/sideEffects/index.ts"],"names":[],"mappings":"AAiDA;;;GAGG;AACH,wBAAiB,QAAQ,4HA4BxB"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/store/sideEffects/index.ts"],"names":[],"mappings":"AAoDA;;;GAGG;AACH,wBAAiB,QAAQ,4HAgCxB"}
@@ -1,7 +1,8 @@
1
1
  // (C) 2024-2026 GoodData Corporation
2
2
  import { call, fork, takeEvery, takeLatest, takeLeading } from "redux-saga/effects";
3
3
  import { initContextObjectsAction, loadContextObjectsNextPageAction, setContextObjectsSearchAction, setOpenAction, } from "../chatWindow/chatWindowSlice.js";
4
- import { clearThreadAction, deleteConversationAction, evaluateMessageUpdateAction, loadThreadAction, newMessageAction, pinConversationAction, renameConversationAction, saveVisualisationRenderStatusAction, saveVisualizationAction, saveVisualizationSuccessAction, setUserFeedback, setVerboseAction, } from "../messages/messagesSlice.js";
4
+ import { clearThreadAction, deleteConversationAction, evaluateMessageCompleteAction, evaluateMessageUpdateAction, loadThreadAction, newMessageAction, pinConversationAction, renameConversationAction, saveVisualisationRenderStatusAction, saveVisualizationAction, saveVisualizationSuccessAction, setCurrentConversationAction, setUserFeedback, setVerboseAction, } from "../messages/messagesSlice.js";
5
+ import { onConversationActivity } from "./conversationSession.js";
5
6
  import { loadAgents } from "./loadAgents.js";
6
7
  import { loadCatalogItems } from "./loadCatalogItems.js";
7
8
  import { loadColorPalette } from "./loadColorPalette.js";
@@ -48,6 +49,7 @@ export function* rootSaga() {
48
49
  yield takeLatest(setContextObjectsSearchAction.type, reloadContextObjects);
49
50
  //others
50
51
  yield takeEvery(setVerboseAction.type, onVerboseStore);
52
+ yield takeEvery([newMessageAction.type, evaluateMessageCompleteAction.type, setCurrentConversationAction.type], onConversationActivity);
51
53
  yield fork(onEvent);
52
54
  yield call(loadColorPalette);
53
55
  yield call(loadSettings);
@@ -22,6 +22,9 @@ import { type IChatConversationLocal, type IChatConversationLocalItem } from "..
22
22
  export declare function onChatOpenSync({ payload: { isOpen } }: PayloadAction<{
23
23
  isOpen: boolean;
24
24
  }>): Generator<import("redux-saga/effects").CallEffect<any> | import("redux-saga/effects").PutEffect<{
25
+ payload: undefined;
26
+ type: "messages/startNewConversationAction";
27
+ }> | import("redux-saga/effects").PutEffect<{
25
28
  payload: {
26
29
  messages?: import("../../model.js").Message[];
27
30
  items?: IChatConversationLocalItem[];
@@ -1 +1 @@
1
- {"version":3,"file":"onChatOpenSync.d.ts","sourceRoot":"","sources":["../../../src/store/sideEffects/onChatOpenSync.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAUtD,OAAO,EACH,KAAK,sBAAsB,EAC3B,KAAK,0BAA0B,EAElC,MAAM,gBAAgB,CAAC;AAiBxB;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAiB,cAAc,CAAC,EAAE,OAAO,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,aAAa,CAAC;IAAE,MAAM,EAAE,OAAO,CAAA;CAAE,CAAC;;;;;;;;;;;6DAyG1F"}
1
+ {"version":3,"file":"onChatOpenSync.d.ts","sourceRoot":"","sources":["../../../src/store/sideEffects/onChatOpenSync.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAUtD,OAAO,EACH,KAAK,sBAAsB,EAC3B,KAAK,0BAA0B,EAElC,MAAM,gBAAgB,CAAC;AAmBxB;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAiB,cAAc,CAAC,EAAE,OAAO,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,aAAa,CAAC;IAAE,MAAM,EAAE,OAAO,CAAA;CAAE,CAAC;;;;;;;;;;;;;;6DAkH1F"}
@@ -2,8 +2,9 @@
2
2
  import { call, getContext, put, select } from "redux-saga/effects";
3
3
  import { makeConversationItem, } from "../../model.js";
4
4
  import { settingsSelector } from "../chatWindow/chatWindowSelectors.js";
5
- import { asyncProcessSelector, conversationMessagesSelector, conversationSelector, conversationsLoadedSelector, } from "../messages/messagesSelectors.js";
6
- import { loadConversationsSuccessAction, setCurrentConversationAction, setMessagesAction, } from "../messages/messagesSlice.js";
5
+ import { asyncProcessSelector, conversationMessagesSelector, conversationSelector, loadedSelector, } from "../messages/messagesSelectors.js";
6
+ import { loadConversationsSuccessAction, setCurrentConversationAction, setMessagesAction, startNewConversationAction, } from "../messages/messagesSlice.js";
7
+ import { consumeStaleConversationSession } from "./conversationSession.js";
7
8
  import { convertToLocalContent } from "./converters/toLocalContent.js";
8
9
  import { notifyDefinitionReceived } from "./onDefinitionReceivedTrigger.js";
9
10
  /**
@@ -35,9 +36,9 @@ export function* onChatOpenSync({ payload: { isOpen } }) {
35
36
  if (!settings?.enableAiAgenticConversations) {
36
37
  return;
37
38
  }
38
- // The very first open is handled by the regular thread loading; only re-sync afterwards.
39
- const conversationsLoaded = yield select(conversationsLoadedSelector);
40
- if (!conversationsLoaded) {
39
+ // Initial load is owned by onThreadLoad; skip until it finishes to avoid a double stale check.
40
+ const loaded = yield select(loadedSelector);
41
+ if (!loaded) {
41
42
  return;
42
43
  }
43
44
  // Do not interrupt a genuine in-flight exchange. We deliberately only bail on "evaluating"
@@ -57,6 +58,14 @@ export function* onChatOpenSync({ payload: { isOpen } }) {
57
58
  if (current && !current.id) {
58
59
  return;
59
60
  }
61
+ // Reopening after a long idle period starts a fresh conversation rather than re-syncing the
62
+ // previous one. Before the fetches: there is nothing to sync into a conversation
63
+ // we are about to leave behind.
64
+ const staleSession = yield call(consumeStaleConversationSession);
65
+ if (staleSession) {
66
+ yield put(startNewConversationAction());
67
+ return;
68
+ }
60
69
  try {
61
70
  const latest = yield call(fetchLatestConversation, current);
62
71
  // Empty (or transient) backend result - most likely a flaky list fetch. Keep the current UI
@@ -1 +1 @@
1
- {"version":3,"file":"onThreadLoad.d.ts","sourceRoot":"","sources":["../../../src/store/sideEffects/onThreadLoad.ts"],"names":[],"mappings":"AAIA,OAAO,EACH,KAAK,kBAAkB,EAMvB,KAAK,kBAAkB,EACvB,KAAK,sBAAsB,EAC9B,MAAM,2BAA2B,CAAC;AAEnC,OAAO,EAGH,KAAK,sBAAsB,EAE3B,KAAK,OAAO,EAIf,MAAM,gBAAgB,CAAC;AAwBxB;;;GAGG;AACH,wBAAiB,YAAY;;;;;;;;;;;;;;;;;;;;;;;;mKAoC5B;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,eAAe,EAAE,OAAO,EAAE,EAAE,cAAc,EAAE,OAAO,EAAE,GAAG,OAAO,EAAE,CA+B/F"}
1
+ {"version":3,"file":"onThreadLoad.d.ts","sourceRoot":"","sources":["../../../src/store/sideEffects/onThreadLoad.ts"],"names":[],"mappings":"AAIA,OAAO,EACH,KAAK,kBAAkB,EAMvB,KAAK,kBAAkB,EACvB,KAAK,sBAAsB,EAC9B,MAAM,2BAA2B,CAAC;AAEnC,OAAO,EAGH,KAAK,sBAAsB,EAE3B,KAAK,OAAO,EAIf,MAAM,gBAAgB,CAAC;AAyBxB;;;GAGG;AACH,wBAAiB,YAAY;;;;;;;;;;;;;;;;;;;;;;;;mKAoC5B;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,eAAe,EAAE,OAAO,EAAE,EAAE,cAAc,EAAE,OAAO,EAAE,GAAG,OAAO,EAAE,CA+B/F"}
@@ -6,6 +6,7 @@ import { loadMessages } from "../localStorage.js";
6
6
  import { conversationMessagesByIdSelector, conversationSelector, conversationsLoadedSelector, conversationsSelector, } from "../messages/messagesSelectors.js";
7
7
  import { cancelAsyncAction, clearConversationLoadingAction, loadConversationSuccessAction, loadConversationsSuccessAction, loadThreadErrorAction, loadThreadSuccessAction, restoreCachedMessagesAction, } from "../messages/messagesSlice.js";
8
8
  import { createEmptyConversation } from "../utils.js";
9
+ import { consumeStaleConversationSession } from "./conversationSession.js";
9
10
  import { interactionsToMessages } from "./converters/interactionsToMessages.js";
10
11
  import { convertToLocalContent } from "./converters/toLocalContent.js";
11
12
  import { notifyDefinitionReceived } from "./onDefinitionReceivedTrigger.js";
@@ -186,6 +187,16 @@ function* fetchCurrentConversation() {
186
187
  }));
187
188
  return;
188
189
  }
190
+ // Opening after a long idle period starts a fresh conversation instead of resuming the last
191
+ // one. Applies to an explicit pick too - selecting one refreshes the timer.
192
+ const staleSession = yield call(consumeStaleConversationSession);
193
+ if (staleSession) {
194
+ yield put(loadConversationSuccessAction({
195
+ currentConversation: createEmptyConversation(),
196
+ conversationItems: [],
197
+ }));
198
+ return;
199
+ }
189
200
  const api = backend.workspace(workspace).genAI().getChatConversations({ isPreview });
190
201
  //Sort by createion date, because normally there are pinned on top
191
202
  const sortedConv = conversations
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gooddata/sdk-ui-gen-ai",
3
- "version": "11.57.0-alpha.1",
3
+ "version": "11.57.0-alpha.2",
4
4
  "description": "GoodData GenAI SDK",
5
5
  "license": "MIT",
6
6
  "author": "GoodData Corporation",
@@ -57,18 +57,18 @@
57
57
  "reselect": "5.1.1",
58
58
  "tslib": "2.8.1",
59
59
  "uuid": "11.1.1",
60
- "@gooddata/api-client-tiger": "11.57.0-alpha.1",
61
- "@gooddata/sdk-backend-spi": "11.57.0-alpha.1",
62
- "@gooddata/sdk-model": "11.57.0-alpha.1",
63
- "@gooddata/sdk-ui-charts": "11.57.0-alpha.1",
64
- "@gooddata/sdk-ui": "11.57.0-alpha.1",
65
- "@gooddata/sdk-ui-dashboard": "11.57.0-alpha.1",
66
- "@gooddata/sdk-ui-filters": "11.57.0-alpha.1",
67
- "@gooddata/sdk-ui-kit": "11.57.0-alpha.1",
68
- "@gooddata/sdk-ui-pivot": "11.57.0-alpha.1",
69
- "@gooddata/sdk-ui-semantic-search": "11.57.0-alpha.1",
70
- "@gooddata/sdk-ui-theme-provider": "11.57.0-alpha.1",
71
- "@gooddata/util": "11.57.0-alpha.1"
60
+ "@gooddata/sdk-backend-spi": "11.57.0-alpha.2",
61
+ "@gooddata/api-client-tiger": "11.57.0-alpha.2",
62
+ "@gooddata/sdk-ui": "11.57.0-alpha.2",
63
+ "@gooddata/sdk-ui-charts": "11.57.0-alpha.2",
64
+ "@gooddata/sdk-model": "11.57.0-alpha.2",
65
+ "@gooddata/sdk-ui-dashboard": "11.57.0-alpha.2",
66
+ "@gooddata/sdk-ui-filters": "11.57.0-alpha.2",
67
+ "@gooddata/sdk-ui-kit": "11.57.0-alpha.2",
68
+ "@gooddata/sdk-ui-semantic-search": "11.57.0-alpha.2",
69
+ "@gooddata/sdk-ui-pivot": "11.57.0-alpha.2",
70
+ "@gooddata/sdk-ui-theme-provider": "11.57.0-alpha.2",
71
+ "@gooddata/util": "11.57.0-alpha.2"
72
72
  },
73
73
  "devDependencies": {
74
74
  "@microsoft/api-documenter": "7.30.10",
@@ -96,23 +96,24 @@
96
96
  "happy-dom": "20.12.0",
97
97
  "npm-run-all": "4.1.5",
98
98
  "oxfmt": "0.66.0",
99
- "oxlint": "1.57.0",
99
+ "oxlint": "1.66.0",
100
+ "oxlint-plugin-eslint": "1.82.0",
100
101
  "oxlint-tsgolint": "0.18.1",
101
102
  "raf": "3.4.1",
102
103
  "react": "19.1.1",
103
104
  "react-dom": "19.1.1",
104
- "sass": "1.100.0",
105
+ "sass": "1.104.0",
105
106
  "stylelint": "16.26.1",
106
107
  "svgo": "2.8.3",
107
108
  "typescript": "7.0.2",
108
109
  "vitest": "4.1.8",
109
110
  "vitest-dom": "0.1.1",
110
- "@gooddata/eslint-config": "11.57.0-alpha.1",
111
- "@gooddata/i18n-toolkit": "11.57.0-alpha.1",
112
- "@gooddata/oxlint-config": "11.57.0-alpha.1",
113
- "@gooddata/reference-workspace": "11.57.0-alpha.1",
114
- "@gooddata/sdk-backend-mockingbird": "11.57.0-alpha.1",
115
- "@gooddata/stylelint-config": "11.57.0-alpha.1"
111
+ "@gooddata/eslint-config": "11.57.0-alpha.2",
112
+ "@gooddata/i18n-toolkit": "11.57.0-alpha.2",
113
+ "@gooddata/oxlint-config": "11.57.0-alpha.2",
114
+ "@gooddata/reference-workspace": "11.57.0-alpha.2",
115
+ "@gooddata/sdk-backend-mockingbird": "11.57.0-alpha.2",
116
+ "@gooddata/stylelint-config": "11.57.0-alpha.2"
116
117
  },
117
118
  "peerDependencies": {
118
119
  "react": "^18.0.0 || ^19.0.0",
@@ -80,7 +80,7 @@
80
80
  margin: 30px 10px 0 10px;
81
81
  padding: 4px 4px;
82
82
  border: 2px dashed var(--gd-palette-primary-base, #14b2e2);
83
- background-color: var(--gd-palette-primary-dimmed, rgb(231.5, 247.3, 252.1));
83
+ background-color: var(--gd-palette-primary-dimmed, rgb(90.7843137255%, 96.9803921569%, 98.862745098%));
84
84
  border-radius: 5px;
85
85
  min-height: 30px;
86
86
  }
@@ -158,7 +158,7 @@
158
158
  color: var(--gd-palette-complementary-9, #000);
159
159
  }
160
160
  .gd-gen-ai-chat__window__conversations__list__item.openedMenu .gd-ui-kit-menu__item.gd-ui-kit-menu__item--isSelected {
161
- background-color: var(--gd-palette-primary-dimmed, rgb(231.5, 247.3, 252.1));
161
+ background-color: var(--gd-palette-primary-dimmed, rgb(90.7843137255%, 96.9803921569%, 98.862745098%));
162
162
  color: var(--gd-palette-primary-base, #14b2e2);
163
163
  }
164
164
  .gd-gen-ai-chat__window__conversations__list__item.generatingTitle .gd-ui-kit-menu__item-title, .gd-gen-ai-chat__window__conversations__list__item.inProgress .gd-ui-kit-menu__item-title {
@@ -192,7 +192,7 @@
192
192
  }
193
193
  .gd-gen-ai-chat__window__conversations__delete-button:hover, .gd-gen-ai-chat__window__conversations__delete-button:focus-visible {
194
194
  color: var(--gd-palette-error-base, #e54d42);
195
- background-color: var(--gd-palette-error-dimmed, rgb(252.4, 237.2, 236.1));
195
+ background-color: var(--gd-palette-error-dimmed, rgb(98.9803921569%, 93.0196078431%, 92.5882352941%));
196
196
  }
197
197
  .gd-gen-ai-chat__window__conversations .gd-ui-kit-menu__items-container {
198
198
  overflow-y: auto;
@@ -1251,7 +1251,7 @@ button.gd-list-item {
1251
1251
  }
1252
1252
 
1253
1253
  .gd-list-item:hover.is-selected {
1254
- background-color: var(--gd-palette-primary-dimmed, rgb(231.5, 247.3, 252.1));
1254
+ background-color: var(--gd-palette-primary-dimmed, rgb(90.7843137255%, 96.9803921569%, 98.862745098%));
1255
1255
  }
1256
1256
 
1257
1257
  .gd-list-item:focus-visible {
@@ -1261,7 +1261,7 @@ button.gd-list-item {
1261
1261
 
1262
1262
  .gd-list-item.gd-menu-item-remove:hover {
1263
1263
  color: var(--gd-palette-error-base, #e54d42);
1264
- background: var(--gd-palette-error-dimmed, rgb(252.4, 237.2, 236.1));
1264
+ background: var(--gd-palette-error-dimmed, rgb(98.9803921569%, 93.0196078431%, 92.5882352941%));
1265
1265
  }
1266
1266
 
1267
1267
  .gd-mobile-dropdown-content .gd-list-item {
@@ -1272,7 +1272,7 @@ button.gd-list-item {
1272
1272
 
1273
1273
  .gd-list-item.variant-delete:hover {
1274
1274
  color: var(--gd-palette-error-base, #e54d42);
1275
- background: var(--gd-palette-error-dimmed, rgb(252.4, 237.2, 236.1));
1275
+ background: var(--gd-palette-error-dimmed, rgb(98.9803921569%, 93.0196078431%, 92.5882352941%));
1276
1276
  }
1277
1277
 
1278
1278
  .gd-list-item.is-disabled {
@@ -9726,7 +9726,7 @@ button.gd-list-item {
9726
9726
  --ag-cell-horizontal-border: none;
9727
9727
  --ag-header-background-color: var(--gd-table-backgroundColor, var(--gd-palette-complementary-0, #fff));
9728
9728
  --ag-header-foreground-color: var(--gd-table-headerLabelColor, var(--gd-palette-complementary-7-from-theme, var(--gd-palette-complementary-8, #464e56)));
9729
- --ag-header-cell-hover-background-color: var(--gd-table-headerHoverBackgroundColor, var(--gd-palette-complementary-1-from-theme, var(--gd-palette-primary-dimmed, rgb(231.5, 247.3, 252.1))));
9729
+ --ag-header-cell-hover-background-color: var(--gd-table-headerHoverBackgroundColor, var(--gd-palette-complementary-1-from-theme, var(--gd-palette-primary-dimmed, rgb(90.7843137255%, 96.9803921569%, 98.862745098%))));
9730
9730
  --ag-subheader-background-color: #e2e9eb;
9731
9731
  --ag-balham-active-color: #0091ea;
9732
9732
  --ag-range-selection-border-color: #0091ea;
@@ -9921,7 +9921,7 @@ button.gd-list-item {
9921
9921
 
9922
9922
  .gd-table-component .gd-table .gd-column-group-header:hover .gd-pivot-table-header-label--clickable,
9923
9923
  .gd-table-component .gd-table .gd-column-group-header:hover .gd-pivot-table-header-menu ~ .gd-pivot-table-header-label {
9924
- background-color: var(--gd-table-headerHoverBackgroundColor, var(--gd-palette-complementary-1-from-theme, var(--gd-palette-primary-dimmed, rgb(231.5, 247.3, 252.1))));
9924
+ background-color: var(--gd-table-headerHoverBackgroundColor, var(--gd-palette-complementary-1-from-theme, var(--gd-palette-primary-dimmed, rgb(90.7843137255%, 96.9803921569%, 98.862745098%))));
9925
9925
  }
9926
9926
 
9927
9927
  .gd-table-component .gd-table .gd-column-group-header:hover .ag-header-cell-resize {
@@ -10152,14 +10152,14 @@ button.gd-list-item {
10152
10152
  align-items: center;
10153
10153
  overflow: hidden;
10154
10154
  border-top: 2px solid transparent;
10155
- background-color: var(--gd-table-headerHoverBackgroundColor, var(--gd-palette-complementary-1-from-theme, var(--gd-palette-primary-dimmed, rgb(231.5, 247.3, 252.1))));
10155
+ background-color: var(--gd-table-headerHoverBackgroundColor, var(--gd-palette-complementary-1-from-theme, var(--gd-palette-primary-dimmed, rgb(90.7843137255%, 96.9803921569%, 98.862745098%))));
10156
10156
  opacity: 0;
10157
10157
  cursor: pointer;
10158
10158
  transition: width 200ms, opacity 100ms;
10159
10159
  }
10160
10160
 
10161
10161
  .gd-pivot-table-header-menu:hover {
10162
- background-color: var(--gd-palette-primary-base-dimmed-darken03, rgb(217.8806818182, 242.8375, 250.4193181818));
10162
+ background-color: var(--gd-palette-primary-base-dimmed-darken03, rgb(85.4434046346%, 95.2303921569%, 98.2036541889%));
10163
10163
  }
10164
10164
 
10165
10165
  .gd-pivot-table-header-menu .menu-icon {
@@ -10265,7 +10265,7 @@ button.gd-list-item {
10265
10265
  }
10266
10266
 
10267
10267
  .gd-menuPosition-wrapper:hover .gd-list-item.gd-menu-item.is-submenu.is-selected {
10268
- background-color: var(--gd-palette-primary-dimmed, rgb(231.5, 247.3, 252.1));
10268
+ background-color: var(--gd-palette-primary-dimmed, rgb(90.7843137255%, 96.9803921569%, 98.862745098%));
10269
10269
  }
10270
10270
 
10271
10271
  .gd-pivot-table-next {
@@ -12708,7 +12708,7 @@ body.gd-kda-dialog-opened .highcharts-tooltip-container {
12708
12708
  flex: unset;
12709
12709
  padding: 4px 10px;
12710
12710
  border-radius: 3px;
12711
- background: var(--gd-palette-error-dimmed, rgb(252.4, 237.2, 236.1));
12711
+ background: var(--gd-palette-error-dimmed, rgb(98.9803921569%, 93.0196078431%, 92.5882352941%));
12712
12712
  color: var(--gd-palette-error-base, #e54d42);
12713
12713
  }
12714
12714
 
@@ -13189,7 +13189,7 @@ body.gd-kda-dialog-opened .highcharts-tooltip-container {
13189
13189
  border-radius: 3px;
13190
13190
  flex: unset;
13191
13191
  padding: 4px 10px;
13192
- background: var(--gd-palette-error-dimmed, rgb(252.4, 237.2, 236.1));
13192
+ background: var(--gd-palette-error-dimmed, rgb(98.9803921569%, 93.0196078431%, 92.5882352941%));
13193
13193
  color: var(--gd-palette-error-base, #e54d42);
13194
13194
  }
13195
13195
  .gd-gen-ai-chat__messages__conversation-group--error p {
@@ -13952,7 +13952,7 @@ body.gd-kda-dialog-opened .highcharts-tooltip-container {
13952
13952
  gap: 7px;
13953
13953
  }
13954
13954
  .gd-gen-ai-chat__conversation__item__content--error .gd-gen-ai-chat__error-details {
13955
- border-top: 1px solid rgb(247.2, 201.6, 198.3);
13955
+ border-top: 1px solid rgb(96.9411764706%, 79.0588235294%, 77.7647058824%);
13956
13956
  margin: 0 -10px;
13957
13957
  padding: 5px 12px 0 12px;
13958
13958
  }
@@ -14297,7 +14297,7 @@ body.gd-kda-dialog-opened .highcharts-tooltip-container {
14297
14297
  margin: 30px 10px 0 10px;
14298
14298
  padding: 4px 4px;
14299
14299
  border: 2px dashed var(--gd-palette-primary-base, #14b2e2);
14300
- background-color: var(--gd-palette-primary-dimmed, rgb(231.5, 247.3, 252.1));
14300
+ background-color: var(--gd-palette-primary-dimmed, rgb(90.7843137255%, 96.9803921569%, 98.862745098%));
14301
14301
  border-radius: 5px;
14302
14302
  min-height: 30px;
14303
14303
  }
@@ -14375,7 +14375,7 @@ body.gd-kda-dialog-opened .highcharts-tooltip-container {
14375
14375
  color: var(--gd-palette-complementary-9, #000);
14376
14376
  }
14377
14377
  .gd-gen-ai-chat__window__conversations__list__item.openedMenu .gd-ui-kit-menu__item.gd-ui-kit-menu__item--isSelected {
14378
- background-color: var(--gd-palette-primary-dimmed, rgb(231.5, 247.3, 252.1));
14378
+ background-color: var(--gd-palette-primary-dimmed, rgb(90.7843137255%, 96.9803921569%, 98.862745098%));
14379
14379
  color: var(--gd-palette-primary-base, #14b2e2);
14380
14380
  }
14381
14381
  .gd-gen-ai-chat__window__conversations__list__item.generatingTitle .gd-ui-kit-menu__item-title, .gd-gen-ai-chat__window__conversations__list__item.inProgress .gd-ui-kit-menu__item-title {
@@ -14409,7 +14409,7 @@ body.gd-kda-dialog-opened .highcharts-tooltip-container {
14409
14409
  }
14410
14410
  .gd-gen-ai-chat__window__conversations__delete-button:hover, .gd-gen-ai-chat__window__conversations__delete-button:focus-visible {
14411
14411
  color: var(--gd-palette-error-base, #e54d42);
14412
- background-color: var(--gd-palette-error-dimmed, rgb(252.4, 237.2, 236.1));
14412
+ background-color: var(--gd-palette-error-dimmed, rgb(98.9803921569%, 93.0196078431%, 92.5882352941%));
14413
14413
  }
14414
14414
  .gd-gen-ai-chat__window__conversations .gd-ui-kit-menu__items-container {
14415
14415
  overflow-y: auto;
@@ -432,7 +432,7 @@
432
432
  flex: unset;
433
433
  padding: 4px 10px;
434
434
  border-radius: 3px;
435
- background: var(--gd-palette-error-dimmed, rgb(252.4, 237.2, 236.1));
435
+ background: var(--gd-palette-error-dimmed, rgb(98.9803921569%, 93.0196078431%, 92.5882352941%));
436
436
  color: var(--gd-palette-error-base, #e54d42);
437
437
  }
438
438
 
@@ -913,7 +913,7 @@
913
913
  border-radius: 3px;
914
914
  flex: unset;
915
915
  padding: 4px 10px;
916
- background: var(--gd-palette-error-dimmed, rgb(252.4, 237.2, 236.1));
916
+ background: var(--gd-palette-error-dimmed, rgb(98.9803921569%, 93.0196078431%, 92.5882352941%));
917
917
  color: var(--gd-palette-error-base, #e54d42);
918
918
  }
919
919
  .gd-gen-ai-chat__messages__conversation-group--error p {
@@ -1676,7 +1676,7 @@
1676
1676
  gap: 7px;
1677
1677
  }
1678
1678
  .gd-gen-ai-chat__conversation__item__content--error .gd-gen-ai-chat__error-details {
1679
- border-top: 1px solid rgb(247.2, 201.6, 198.3);
1679
+ border-top: 1px solid rgb(96.9411764706%, 79.0588235294%, 77.7647058824%);
1680
1680
  margin: 0 -10px;
1681
1681
  padding: 5px 12px 0 12px;
1682
1682
  }