@iblai/iblai-js 2.18.0 → 2.19.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2121,6 +2121,7 @@ var analyticsAccessTimeHeatmap$3 = {
2121
2121
  tooltipActiveUsers: "{count} active users"
2122
2122
  };
2123
2123
  var analyticsAnalyticsAuditLogStats$3 = {
2124
+ anonymous: "Anonymous",
2124
2125
  scopeAgent: "Agent",
2125
2126
  scopeAriaLabel: "Audit log scope",
2126
2127
  scopePlatform: "Platform",
@@ -2249,6 +2250,7 @@ var analyticsAgentScopeLink$3 = {
2249
2250
  scopeToAgent: "View analytics for {name}"
2250
2251
  };
2251
2252
  var analyticsAnalyticsMemoryStats$3 = {
2253
+ anonymous: "Anonymous",
2252
2254
  noPermission: "You do not have permission to view user memories.",
2253
2255
  scopeLabel: "Memory scope",
2254
2256
  scopeMentor: "This Agent",
@@ -2463,6 +2465,7 @@ var analyticsAnalyticsTopicsStats$3 = {
2463
2465
  topicsRankedFooter: "{shown} of {total} topics · ranked by message volume"
2464
2466
  };
2465
2467
  var analyticsAnalyticsTranscriptsStats$3 = {
2468
+ anonymous: "Anonymous",
2466
2469
  justNow: "Just now",
2467
2470
  minutesAgo: "{count} min ago",
2468
2471
  hoursAgo: "{count} hour{count, plural, one {} other {s}} ago",
@@ -9402,6 +9405,7 @@ var analyticsAccessTimeHeatmap$2 = {
9402
9405
  tooltipActiveUsers: "{count} utilisateurs actifs"
9403
9406
  };
9404
9407
  var analyticsAnalyticsAuditLogStats$2 = {
9408
+ anonymous: "Anonyme",
9405
9409
  scopeAgent: "Agent",
9406
9410
  scopeAriaLabel: "Portée du journal d'audit",
9407
9411
  scopePlatform: "Plateforme",
@@ -9530,6 +9534,7 @@ var analyticsAgentScopeLink$2 = {
9530
9534
  scopeToAgent: "Voir les analyses de {name}"
9531
9535
  };
9532
9536
  var analyticsAnalyticsMemoryStats$2 = {
9537
+ anonymous: "Anonyme",
9533
9538
  noPermission: "Vous n'avez pas l'autorisation de consulter les mémoires des utilisateurs.",
9534
9539
  scopeLabel: "Portée de la mémoire",
9535
9540
  scopeMentor: "Cet agent",
@@ -9744,6 +9749,7 @@ var analyticsAnalyticsTopicsStats$2 = {
9744
9749
  topicsRankedFooter: "{shown} sur {total} sujets · classés par volume de messages"
9745
9750
  };
9746
9751
  var analyticsAnalyticsTranscriptsStats$2 = {
9752
+ anonymous: "Anonyme",
9747
9753
  justNow: "À l'instant",
9748
9754
  minutesAgo: "Il y a {count} min",
9749
9755
  hoursAgo: "Il y a {count} heure{count, plural, one {} other {s}}",
@@ -16683,6 +16689,7 @@ var analyticsAccessTimeHeatmap$1 = {
16683
16689
  tooltipActiveUsers: "{count} usuarios activos"
16684
16690
  };
16685
16691
  var analyticsAnalyticsAuditLogStats$1 = {
16692
+ anonymous: "Anónimo",
16686
16693
  scopeAgent: "Agente",
16687
16694
  scopeAriaLabel: "Alcance del registro de auditoría",
16688
16695
  scopePlatform: "Plataforma",
@@ -16811,6 +16818,7 @@ var analyticsAgentScopeLink$1 = {
16811
16818
  scopeToAgent: "Ver analíticas de {name}"
16812
16819
  };
16813
16820
  var analyticsAnalyticsMemoryStats$1 = {
16821
+ anonymous: "Anónimo",
16814
16822
  noPermission: "No tienes permiso para ver los recuerdos de los usuarios.",
16815
16823
  scopeLabel: "Alcance de la memoria",
16816
16824
  scopeMentor: "Este agente",
@@ -17025,6 +17033,7 @@ var analyticsAnalyticsTopicsStats$1 = {
17025
17033
  topicsRankedFooter: "{shown} de {total} temas · ordenados por volumen de mensajes"
17026
17034
  };
17027
17035
  var analyticsAnalyticsTranscriptsStats$1 = {
17036
+ anonymous: "Anónimo",
17028
17037
  justNow: "Ahora mismo",
17029
17038
  minutesAgo: "Hace {count} min",
17030
17039
  hoursAgo: "Hace {count} hora{count, plural, one {} other {s}}",
@@ -23964,6 +23973,7 @@ var analyticsAccessTimeHeatmap = {
23964
23973
  tooltipActiveUsers: "{count} 位活跃用户"
23965
23974
  };
23966
23975
  var analyticsAnalyticsAuditLogStats = {
23976
+ anonymous: "匿名",
23967
23977
  scopeAgent: "智能体",
23968
23978
  scopeAriaLabel: "审计日志范围",
23969
23979
  scopePlatform: "平台",
@@ -24092,6 +24102,7 @@ var analyticsAgentScopeLink = {
24092
24102
  scopeToAgent: "查看 {name} 的分析"
24093
24103
  };
24094
24104
  var analyticsAnalyticsMemoryStats = {
24105
+ anonymous: "匿名",
24095
24106
  noPermission: "您没有查看用户记忆的权限。",
24096
24107
  scopeLabel: "记忆范围",
24097
24108
  scopeMentor: "当前智能体",
@@ -24306,6 +24317,7 @@ var analyticsAnalyticsTopicsStats = {
24306
24317
  topicsRankedFooter: "共 {total} 个主题,显示 {shown} 个 · 按消息量排序"
24307
24318
  };
24308
24319
  var analyticsAnalyticsTranscriptsStats = {
24320
+ anonymous: "匿名",
24309
24321
  justNow: "刚刚",
24310
24322
  minutesAgo: "{count} 分钟前",
24311
24323
  hoursAgo: "{count} 小时前",
@@ -189484,7 +189496,7 @@ function RetrievedDocumentsButton({ sessionId = '', documents, className, label,
189484
189496
  // Safe inside clickable transcript rows: the row must not react.
189485
189497
  event.stopPropagation();
189486
189498
  setIsOpen(true);
189487
- }, "data-testid": "retrieved-documents-button", children: [jsx(FileText, { className: "h-4 w-4 text-blue-600" }), jsx("span", { children: label !== null && label !== void 0 ? label : t('retrievedDocumentsButton.title') })] }), jsx(Dialog, { open: isOpen, onOpenChange: setIsOpen, children: jsxs(DialogContent, { className: "flex max-h-[80vh] flex-col gap-0 p-0 sm:max-w-[425px] md:max-w-[600px]", children: [jsx(DialogHeader, { className: "border-b px-4 py-2", children: jsxs(DialogTitle, { className: "flex items-center gap-2 text-base font-medium text-[#646464]", children: [jsx(FileText, { className: "h-5 w-5 text-blue-600" }), t('retrievedDocumentsButton.title')] }) }), jsx("div", { className: "min-h-0 flex-1 overflow-y-auto", "data-testid": "retrieved-documents-scroll", children: jsx(DocumentSidebar, { isModal: true, sessionId: sessionId, documents: documents }) })] }) })] }));
189499
+ }, "data-testid": "retrieved-documents-button", children: [jsx(FileText, { className: "h-4 w-4 text-blue-600" }), jsx("span", { children: label !== null && label !== void 0 ? label : t('retrievedDocumentsButton.title') })] }), jsx(Dialog, { open: isOpen, onOpenChange: setIsOpen, children: jsxs(DialogContent, { className: "flex max-h-[80vh] flex-col gap-0 p-0 sm:max-w-[425px] md:max-w-[600px]", children: [jsx(DialogHeader, { className: "border-b border-gray-200 px-4 py-2", children: jsxs(DialogTitle, { className: "flex items-center gap-2 text-base font-medium text-[#646464]", children: [jsx(FileText, { className: "h-5 w-5 text-blue-600" }), t('retrievedDocumentsButton.title')] }) }), jsx("div", { className: "min-h-0 flex-1 overflow-y-auto", "data-testid": "retrieved-documents-scroll", children: jsx(DocumentSidebar, { isModal: true, sessionId: sessionId, documents: documents }) })] }) })] }));
189488
189500
  }
189489
189501
 
189490
189502
  var COLLAPSIBLE_NAME = "Collapsible";
@@ -189734,6 +189746,11 @@ function ToolCallIndicator({ toolCalls, isActive = false, showResults = false, }
189734
189746
  * white circle (the catalogue's artwork, or the bot icon when it has none)
189735
189747
  * beside the model's display name. Read-only; used on admin transcripts to
189736
189748
  * name the model a turn ran on.
189749
+ *
189750
+ * It sets no font size, weight or colour of its own and sizes the logo in
189751
+ * `em`, so it reads as one more fact in whatever row holds it — a `text-xs
189752
+ * text-gray-500` transcript card or the details panel — rather than as a
189753
+ * larger, bolder pill beside them. Pass `className` for the nav bar's look.
189737
189754
  */
189738
189755
  function LlmModelBadge({ model, provider, tenantKey, mentorId, className, }) {
189739
189756
  var _a, _b;
@@ -189754,9 +189771,9 @@ function LlmModelBadge({ model, provider, tenantKey, mentorId, className, }) {
189754
189771
  const label = displayName || providerDetails.displayName;
189755
189772
  if (!label)
189756
189773
  return null;
189757
- return (jsxs("span", { className: cn('inline-flex max-w-full items-center gap-2 text-sm font-medium text-[#646464]', className), title: providerDetails.displayName && providerDetails.displayName !== label
189774
+ return (jsxs("span", { className: cn('inline-flex max-w-full items-center gap-[0.5em] align-middle', className), title: providerDetails.displayName && providerDetails.displayName !== label
189758
189775
  ? `${label} · ${providerDetails.displayName}`
189759
- : label, "data-testid": "llm-model-badge", children: [jsx("span", { className: "flex h-6 w-6 flex-shrink-0 items-center justify-center rounded-full bg-white", children: providerDetails.logo ? (jsx("img", { src: providerDetails.logo, alt: `${label} model logo`, className: "h-5 w-5 object-contain", height: 32, width: 32, loading: "lazy" })) : (jsx(Bot, { className: "h-4 w-4", "aria-hidden": "true" })) }), jsx("span", { className: "max-w-[220px] truncate", children: label })] }));
189776
+ : label, "data-testid": "llm-model-badge", children: [jsx("span", { className: "flex h-[1.5em] w-[1.5em] flex-shrink-0 items-center justify-center rounded-full bg-white", children: providerDetails.logo ? (jsx("img", { src: providerDetails.logo, alt: `${label} model logo`, className: "h-[1.25em] w-[1.25em] object-contain", height: 32, width: 32, loading: "lazy" })) : (jsx(Bot, { className: "h-[1em] w-[1em]", "aria-hidden": "true" })) }), jsx("span", { className: "max-w-[220px] truncate", children: label })] }));
189760
189777
  }
189761
189778
 
189762
189779
  /** SPAs whose users have coursework, so the profile leads with a Gradebook tab. */
@@ -189802,17 +189819,18 @@ function UserProfileDialog({ tenantKey, username, isOpen, onClose, customization
189802
189819
  function UserProfileLink({ tenantKey, username, display, className, testId, customization, currentSPA, }) {
189803
189820
  const t = useT();
189804
189821
  const [isOpen, setIsOpen] = React__default.useState(false);
189822
+ // The text truncates inside an `inline-flex` box: an `inline-block` with
189823
+ // hidden overflow puts its baseline on its bottom edge, so the value would
189824
+ // ride above the "User:" label beside it.
189805
189825
  if (!username) {
189806
- // `inline-block`, or `truncate`'s `overflow: hidden` has nothing to clip:
189807
- // an inline box takes its width from its own text.
189808
- return (jsx("span", { className: cn('inline-block max-w-full truncate', className), "data-testid": testId, children: display }));
189826
+ return (jsx("span", { className: cn('inline-flex max-w-full', className), "data-testid": testId, children: jsx("span", { className: "min-w-0 truncate", children: display }) }));
189809
189827
  }
189810
189828
  return (jsxs(Fragment$1, { children: [jsx("button", { type: "button", onClick: (event) => {
189811
189829
  event.stopPropagation();
189812
189830
  setIsOpen(true);
189813
189831
  },
189814
189832
  // Rows that open on Enter/Space would otherwise swallow the key press.
189815
- onKeyDown: (event) => event.stopPropagation(), className: cn('max-w-full cursor-pointer truncate text-left hover:text-blue-600 hover:underline focus:text-blue-600 focus:outline-none', className), "aria-label": t('tabsUserstab.viewProfileAriaLabel', { name: display }), "data-testid": testId, children: display }), jsx(UserProfileDialog, { tenantKey: tenantKey, username: username, isOpen: isOpen, onClose: () => setIsOpen(false), customization: customization, currentSPA: currentSPA })] }));
189833
+ onKeyDown: (event) => event.stopPropagation(), className: cn('inline-flex max-w-full cursor-pointer text-left hover:text-blue-600 hover:underline focus:text-blue-600 focus:outline-none', className), "aria-label": t('tabsUserstab.viewProfileAriaLabel', { name: display }), "data-testid": testId, children: jsx("span", { className: "min-w-0 truncate", children: display }) }), jsx(UserProfileDialog, { tenantKey: tenantKey, username: username, isOpen: isOpen, onClose: () => setIsOpen(false), customization: customization, currentSPA: currentSPA })] }));
189816
189834
  }
189817
189835
 
189818
189836
  const AdvancedPagination = ({ currentPage, totalPages, onPageChange, totalCount, itemsPerPage, itemLabel = 'items', variant = 'default', className, }) => {
@@ -232420,6 +232438,154 @@ const useFinancial = ({ tenantKey, mentorId, userId, }) => {
232420
232438
  };
232421
232439
  };
232422
232440
 
232441
+ /**
232442
+ * One place that decides how a user is shown.
232443
+ *
232444
+ * Backend payloads name their user in a dozen ways — `email` / `lti_email` /
232445
+ * `user_email`, `username` / `student` / `lti_username`, `name` /
232446
+ * `full_name` / `user_full_name`, or a nested `user` object — and most of
232447
+ * them can be empty, `null`, or a placeholder like "None". Every surface used
232448
+ * to pick through those on its own. `resolveUserIdentity()` takes whatever
232449
+ * the payload is and returns what to show, what to open a profile on, and
232450
+ * the avatar initial, so the rule lives here and can be tweaked once.
232451
+ *
232452
+ * Default rule: a real full name first (see {@link hasDistinctName}), else
232453
+ * email → username → the anonymous label.
232454
+ */
232455
+ const DEFAULT_USER_IDENTITY_ORDER = ['email', 'name', 'username'];
232456
+ /** Order used when the payload carries a real name (see {@link hasDistinctName}). */
232457
+ const NAME_FIRST_ORDER = ['name', 'email', 'username'];
232458
+ /**
232459
+ * Lower-case letters and digits of any script, accents and punctuation dropped,
232460
+ * so "Conrad Mugabe" / "conrad.mugabe" and "José" / "jose" compare equal.
232461
+ */
232462
+ const identityKey = (value) => (value !== null && value !== void 0 ? value : '')
232463
+ .normalize('NFKD')
232464
+ .replace(/[^\p{L}\p{N}]/gu, '')
232465
+ .toLowerCase();
232466
+ /**
232467
+ * Whether `name` is a real name rather than a restatement of the username.
232468
+ *
232469
+ * Many payloads fill the name field with the username ("conradmugabe" →
232470
+ * "Conrad Mugabe", "fayyaz_4_ibleducation_com"), which tells an admin nothing
232471
+ * the email does not. A name that matches none of the usernames on the record
232472
+ * is the most recognisable thing on it — including for LTI learners, whose
232473
+ * minted `<opaque-id>@edx-lti-1p3.com` address and username identify nobody.
232474
+ */
232475
+ function hasDistinctName(name, ...usernames) {
232476
+ const key = identityKey(name);
232477
+ if (!key)
232478
+ return false;
232479
+ return usernames.every((username) => key !== identityKey(username));
232480
+ }
232481
+ const DEFAULT_ANONYMOUS_LABEL = 'Anonymous';
232482
+ /** Values backends emit instead of "nothing". Compared case-insensitively. */
232483
+ const PLACEHOLDERS = new Set([
232484
+ '',
232485
+ 'none',
232486
+ 'null',
232487
+ 'undefined',
232488
+ 'n/a',
232489
+ 'na',
232490
+ '-',
232491
+ 'anonymous',
232492
+ 'anonymoususer',
232493
+ ]);
232494
+ /**
232495
+ * `local@domain.tld` with no whitespace, checked with a single pass rather than
232496
+ * a backtracking pattern (CodeQL flags `[^@]+@[^@]+\.[^@]+` as polynomial on
232497
+ * adversarial input).
232498
+ */
232499
+ const isEmailLike = (value) => {
232500
+ const text = value.trim();
232501
+ if (!text || /\s/.test(text))
232502
+ return false;
232503
+ const at = text.indexOf('@');
232504
+ if (at <= 0 || at !== text.lastIndexOf('@') || at === text.length - 1)
232505
+ return false;
232506
+ const domain = text.slice(at + 1);
232507
+ const dot = domain.indexOf('.');
232508
+ // A dot somewhere inside the domain, with something after the last one.
232509
+ return dot > 0 && !domain.endsWith('.');
232510
+ };
232511
+ /** Trimmed string, or undefined for blanks, non-strings and placeholders. */
232512
+ const clean = (value) => {
232513
+ if (typeof value !== 'string')
232514
+ return undefined;
232515
+ const trimmed = value.trim();
232516
+ return PLACEHOLDERS.has(trimmed.toLowerCase()) ? undefined : trimmed;
232517
+ };
232518
+ const firstOf = (...candidates) => {
232519
+ for (const candidate of candidates) {
232520
+ const value = clean(candidate);
232521
+ if (value)
232522
+ return value;
232523
+ }
232524
+ return undefined;
232525
+ };
232526
+ const nested = (source) => source.user && typeof source.user === 'object' ? source.user : undefined;
232527
+ /**
232528
+ * Resolve how a user should be displayed from any payload that names one.
232529
+ *
232530
+ * - `email`: `lti_email`, `email`, `user_email`, the nested `user`'s email —
232531
+ * or a username field that turns out to hold an email address.
232532
+ * - `username`: `lti_username`, `username`, `student`, `user_username`, the
232533
+ * nested `user`'s username, or a bare string `user` value (a numeric id is
232534
+ * ignored).
232535
+ * - `name`: `user_full_name`, `full_name`, `name`, `first_name last_name`, or
232536
+ * the nested `user`'s name.
232537
+ * - `profileUsername`: the first *platform* username (never an LTI claim).
232538
+ *
232539
+ * A string source is treated as an email when it looks like one, else as a
232540
+ * username. Placeholder strings ("None", "-", "anonymous"…) count as absent.
232541
+ *
232542
+ * The default order flips to name → email → username when the record carries a
232543
+ * real name (see {@link hasDistinctName}): "Joseph Oti" is more use to an admin
232544
+ * than his address, while a name that merely repeats the username is not, so
232545
+ * those records keep showing the email. An explicit `order` is always obeyed.
232546
+ */
232547
+ function resolveUserIdentity(source, options = {}) {
232548
+ var _a, _b;
232549
+ const anonymousLabel = options.anonymousLabel || DEFAULT_ANONYMOUS_LABEL;
232550
+ const order = ((_a = options.order) === null || _a === void 0 ? void 0 : _a.length) ? options.order : DEFAULT_USER_IDENTITY_ORDER;
232551
+ const record = source && typeof source === 'object' ? source : { user: source !== null && source !== void 0 ? source : null };
232552
+ const inner = nested(record);
232553
+ // A bare `user` value is a username — unless it is a numeric id, which
232554
+ // names nobody: transcript rows carry `user: 1` beside `username: null`,
232555
+ // and showing "1" for that person is worse than "Anonymous".
232556
+ const bareString = typeof record.user === 'string' ? clean(record.user) : undefined;
232557
+ const bareUser = bareString && !/^\d+$/.test(bareString) ? bareString : undefined;
232558
+ let email = firstOf(record.lti_email, record.email, record.user_email, inner === null || inner === void 0 ? void 0 : inner.lti_email, inner === null || inner === void 0 ? void 0 : inner.email, inner === null || inner === void 0 ? void 0 : inner.user_email);
232559
+ const platformUsername = firstOf(record.username, record.student, record.user_username, inner === null || inner === void 0 ? void 0 : inner.username, inner === null || inner === void 0 ? void 0 : inner.student, inner === null || inner === void 0 ? void 0 : inner.user_username, bareUser && !isEmailLike(bareUser) ? bareUser : undefined);
232560
+ let username = firstOf(record.lti_username, inner === null || inner === void 0 ? void 0 : inner.lti_username, platformUsername);
232561
+ const composed = [clean(record.first_name), clean(record.last_name)].filter(Boolean).join(' ');
232562
+ const name = firstOf(record.user_full_name, record.full_name, record.name, composed, inner === null || inner === void 0 ? void 0 : inner.user_full_name, inner === null || inner === void 0 ? void 0 : inner.full_name, inner === null || inner === void 0 ? void 0 : inner.name);
232563
+ // A bare string that looks like an email is an email, and so is a
232564
+ // "username" field that actually carries one.
232565
+ if (!email && bareUser && isEmailLike(bareUser))
232566
+ email = bareUser;
232567
+ if (!email && username && isEmailLike(username)) {
232568
+ email = username;
232569
+ username = undefined;
232570
+ }
232571
+ const facts = { email, username, name };
232572
+ // Every username on the record counts: the platform one a profile opens on
232573
+ // and the LTI claim that would be displayed.
232574
+ const labelOrder = !((_b = options.order) === null || _b === void 0 ? void 0 : _b.length) && hasDistinctName(name, platformUsername, username)
232575
+ ? NAME_FIRST_ORDER
232576
+ : order;
232577
+ const label = labelOrder.map((field) => facts[field]).find(Boolean);
232578
+ return {
232579
+ label: label !== null && label !== void 0 ? label : anonymousLabel,
232580
+ email,
232581
+ username,
232582
+ name,
232583
+ profileUsername: platformUsername,
232584
+ initial: (label !== null && label !== void 0 ? label : anonymousLabel).charAt(0).toUpperCase() || 'A',
232585
+ isAnonymous: !label,
232586
+ };
232587
+ }
232588
+
232423
232589
  const TONES = {
232424
232590
  amber: {
232425
232591
  container: 'border-amber-200 bg-amber-50 text-amber-800',
@@ -232777,6 +232943,10 @@ const costTick = (value) => {
232777
232943
  function SpendTab({ tenantKey, currentSPA, mentorId: currentMentorId, userId, onOpenUserTraces, }) {
232778
232944
  var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s;
232779
232945
  const t = useT();
232946
+ // The label a cost row shows for its user, by the shared identity rule.
232947
+ const identify = React__default.useCallback((row) => resolveUserIdentity(row, {
232948
+ anonymousLabel: t('analyticsAnalyticsFinancialStats.anonymous'),
232949
+ }), [t]);
232780
232950
  const { weeklyCostData, isLoadingWeeklyCostData, isErrorWeeklyCostData, monthlyCostData, isLoadingMonthlyCostData, isErrorMonthlyCostData, totalCostData, isLoadingTotalCostData, isErrorTotalCostData, detailedCostPerDayData, isLoadingDetailedCostPerDayData, detailedCostPerDayFilters, setDetailedCostPerDayFilters, detailedCostPerProviderData, isLoadingDetailedCostPerProviderData, detailedCostPerProviderFilters, setDetailedCostPerProviderFilters, detailedCostPerUserData, isLoadingDetailedCostPerUserData, detailedCostPerUserFilters, setDetailedCostPerUserFilters, costPerUserPage, setCostPerUserPage, costPerUserLimit, providerColors, detailedLLMCostData, isLoadingDetailedLLMCostData, detailedLLMCostFilters, setDetailedLLMCostFilters, } = useFinancial({ tenantKey, mentorId: currentMentorId, userId });
232781
232951
  // Pagination handlers
232782
232952
  const handleFirstPage = () => {
@@ -232871,7 +233041,7 @@ function SpendTab({ tenantKey, currentSPA, mentorId: currentMentorId, userId, on
232871
233041
  shown: (_p = (_o = detailedLLMCostData === null || detailedLLMCostData === void 0 ? void 0 : detailedLLMCostData.rows) === null || _o === void 0 ? void 0 : _o.length) !== null && _p !== void 0 ? _p : 0,
232872
233042
  }) })) : (jsx(EmptyStats, {})) })] }), jsx("div", { className: "grid grid-cols-1 gap-6", children: jsx(ChartCardWrapper, { title: t('analyticsAnalyticsFinancialStats.costPerUserTitle'), source: "clickhouse", label: t('analyticsAnalyticsFinancialStats.costPerUserLabel'), filters: detailedCostPerUserFilters, setOutsideFilters: setDetailedCostPerUserFilters, overflowAuto: true, height: "450px", description: t('analyticsAnalyticsFinancialStats.costPerUserDescription'), children: jsxs("div", { className: "space-y-4", children: [jsx("div", { className: "rounded-md", style: { borderColor: 'oklch(.922 0 0)', borderWidth: '1px' }, children: jsxs(Table, { children: [jsx(TableHeader, { children: jsxs(TableRow, { className: "h-[48px]", style: { borderColor: 'oklch(.922 0 0)' }, children: [jsx(TableHead, { className: "w-[250px]", children: t('analyticsAnalyticsFinancialStats.tableHeaderUserEmail') }), jsx(TableHead, { className: "w-[120px]", children: t('analyticsAnalyticsFinancialStats.tableHeaderTotalCost') }), hasSessions && (jsx(TableHead, { children: t('analyticsAnalyticsFinancialStats.tableHeaderSessions') })), hasLastActive && (jsx(TableHead, { className: "text-right", children: t('analyticsAnalyticsFinancialStats.tableHeaderLastActive') })), onOpenUserTraces && jsx(TableHead, { className: "w-[90px]" })] }) }), jsx(TableBody, { children: (_q = detailedCostPerUserData === null || detailedCostPerUserData === void 0 ? void 0 : detailedCostPerUserData.rows) === null || _q === void 0 ? void 0 : _q.map((user, index) => {
232873
233043
  var _a;
232874
- return (jsxs(TableRow, { className: cn(index % 2 === 0 ? 'bg-gray-50' : '', 'h-[48px]'), style: { borderColor: 'oklch(.922 0 0)' }, children: [jsx(TableCell, { className: "font-medium", children: jsx("div", { className: "flex items-center", children: (user === null || user === void 0 ? void 0 : user.email) || (user === null || user === void 0 ? void 0 : user.username) ? (jsx(UserProfileLink, { tenantKey: tenantKey, currentSPA: currentSPA, username: user.username, display: String(user.email || user.username) })) : (t('analyticsAnalyticsFinancialStats.anonymous')) }) }), jsxs(TableCell, { className: "font-medium", children: ["$", Number(user.total_cost || 0).toFixed(2)] }), hasSessions && jsx(TableCell, { children: (_a = user.sessions) !== null && _a !== void 0 ? _a : '\u2014' }), hasLastActive && (jsx(TableCell, { className: "text-right", children: user.last_active ? formatRelativeTime$2(user.last_active) : '-' })), onOpenUserTraces && (jsx(TableCell, { className: "text-right", children: (user === null || user === void 0 ? void 0 : user.username) || (user === null || user === void 0 ? void 0 : user.email) ? (jsx("button", { type: "button", className: "cursor-pointer text-sm font-semibold text-blue-600 hover:text-blue-700 hover:underline", onClick: () => onOpenUserTraces(String(user.username || user.email)), children: t('analyticsAnalyticsFinancialStats.viewTraces') })) : null }))] }, index));
233044
+ return (jsxs(TableRow, { className: cn(index % 2 === 0 ? 'bg-gray-50' : '', 'h-[48px]'), style: { borderColor: 'oklch(.922 0 0)' }, children: [jsx(TableCell, { className: "font-medium", children: jsx("div", { className: "flex items-center", children: jsx(UserProfileLink, { tenantKey: tenantKey, currentSPA: currentSPA, username: user.username, display: identify(user).label }) }) }), jsxs(TableCell, { className: "font-medium", children: ["$", Number(user.total_cost || 0).toFixed(2)] }), hasSessions && jsx(TableCell, { children: (_a = user.sessions) !== null && _a !== void 0 ? _a : '\u2014' }), hasLastActive && (jsx(TableCell, { className: "text-right", children: user.last_active ? formatRelativeTime$2(user.last_active) : '-' })), onOpenUserTraces && (jsx(TableCell, { className: "text-right", children: (user === null || user === void 0 ? void 0 : user.username) || (user === null || user === void 0 ? void 0 : user.user_email) || (user === null || user === void 0 ? void 0 : user.email) ? (jsx("button", { type: "button", className: "cursor-pointer text-sm font-semibold text-blue-600 hover:text-blue-700 hover:underline", onClick: () => onOpenUserTraces(String(user.username || user.user_email || user.email)), children: t('analyticsAnalyticsFinancialStats.viewTraces') })) : null }))] }, index));
232875
233045
  }) })] }) }), isLoadingDetailedCostPerUserData && (jsx("div", { className: "h-[60px]", children: jsx(ChartLoading, {}) })), !isLoadingDetailedCostPerUserData &&
232876
233046
  (!((_r = detailedCostPerUserData === null || detailedCostPerUserData === void 0 ? void 0 : detailedCostPerUserData.rows) === null || _r === void 0 ? void 0 : _r.length) ||
232877
233047
  ((_s = detailedCostPerUserData === null || detailedCostPerUserData === void 0 ? void 0 : detailedCostPerUserData.rows) === null || _s === void 0 ? void 0 : _s.length) === 0) && (jsx("div", { className: "h-[60px]", children: jsx(EmptyStats, {}) })), detailedCostPerUserData && detailedCostPerUserData.total_pages > 1 && (jsxs("div", { className: "flex items-center justify-between py-3", children: [jsx("div", { className: "text-sm text-gray-700", children: t('analyticsAnalyticsFinancialStats.paginationShowing', {
@@ -233002,19 +233172,22 @@ const useTranscripts = ({ tenantKey, mentorId, usergroupIds, }) => {
233002
233172
  * from the data instead of from a search box.
233003
233173
  *
233004
233174
  * It renders as plain text wherever re-scoping is impossible or pointless: on
233005
- * per-agent pages (no picker, so nothing would visibly change), and on rows
233006
- * whose agent the payload identifies by name alone. Safe inside clickable rows
233007
- * and cards — neither its clicks nor its key presses reach their handlers.
233175
+ * per-agent pages (no picker, so nothing would visibly change), on rows whose
233176
+ * agent the payload identifies by name alone, and on rows of the agent the
233177
+ * page is already scoped to (every row, once the picker names one agent — a
233178
+ * blue link there promised something and delivered nothing). Safe inside
233179
+ * clickable rows and cards — neither its clicks nor its key presses reach
233180
+ * their handlers.
233008
233181
  */
233009
233182
  function AgentScopeLink({ uniqueId, name, fallback = '-', onScoped, className, testId, }) {
233010
233183
  const t = useT();
233011
233184
  const setScopedMentor = useAnalyticsScopeSetter();
233012
233185
  const { scopedMentor } = useAnalyticsScope();
233013
233186
  const display = name || uniqueId || fallback;
233014
- if (!setScopedMentor || !uniqueId) {
233187
+ const isCurrent = !!uniqueId && (scopedMentor === null || scopedMentor === void 0 ? void 0 : scopedMentor.uniqueId) === uniqueId;
233188
+ if (!setScopedMentor || !uniqueId || isCurrent) {
233015
233189
  return (jsx("span", { className: className, "data-testid": testId, children: display }));
233016
233190
  }
233017
- const isCurrent = (scopedMentor === null || scopedMentor === void 0 ? void 0 : scopedMentor.uniqueId) === uniqueId;
233018
233191
  return (jsx("button", { type: "button", onClick: (event) => {
233019
233192
  event.stopPropagation();
233020
233193
  // No `dbId`: these payloads carry the `unique_id` only. AnalyticsLayout
@@ -233024,7 +233197,10 @@ function AgentScopeLink({ uniqueId, name, fallback = '-', onScoped, className, t
233024
233197
  onScoped === null || onScoped === void 0 ? void 0 : onScoped();
233025
233198
  },
233026
233199
  // Rows that open on Enter/Space would otherwise swallow the key press.
233027
- onKeyDown: (event) => event.stopPropagation(), className: cn('max-w-full cursor-pointer truncate text-left hover:text-blue-600 hover:underline focus:text-blue-600 focus:outline-none', isCurrent && 'font-medium text-blue-600', className), "aria-label": t('analyticsAgentScopeLink.scopeToAgent', { name: display }), "aria-current": isCurrent ? 'true' : undefined, "data-testid": testId, children: display }));
233200
+ onKeyDown: (event) => event.stopPropagation(),
233201
+ // Truncates inside an `inline-flex` box so the name keeps the baseline
233202
+ // of the "Agent:" label beside it (see UserProfileLink).
233203
+ className: cn('inline-flex max-w-full cursor-pointer text-left hover:text-blue-600 hover:underline focus:text-blue-600 focus:outline-none', className), "aria-label": t('analyticsAgentScopeLink.scopeToAgent', { name: display }), "data-testid": testId, children: jsx("span", { className: "min-w-0 truncate", children: display }) }));
233028
233204
  }
233029
233205
 
233030
233206
  /**
@@ -233362,7 +233538,7 @@ function SectionHeading({ icon, children }) {
233362
233538
  return (jsxs("h4", { className: "mb-2 flex items-center gap-1.5 text-xs font-semibold tracking-wide text-gray-700 uppercase", children: [icon, children] }));
233363
233539
  }
233364
233540
  const MODEL_KEYS = new Set(['llm_model', 'llm_provider']);
233365
- function MetadataSection({ metadata, renderModel, }) {
233541
+ function MetadataSection({ metadata, renderModel, tenantKey, mentorId, }) {
233366
233542
  var _a, _b;
233367
233543
  const t = useT();
233368
233544
  const labelFor = useFieldLabels();
@@ -233370,7 +233546,9 @@ function MetadataSection({ metadata, renderModel, }) {
233370
233546
  const model = ((_a = metadata.llm_model) !== null && _a !== void 0 ? _a : '').trim() || undefined;
233371
233547
  const provider = ((_b = metadata.llm_provider) !== null && _b !== void 0 ? _b : '').trim() || undefined;
233372
233548
  const hasModel = !!(model || provider);
233373
- return (jsxs("section", { "data-testid": "transcript-turn-metadata", children: [jsx(SectionHeading, { icon: jsx(Info$3, { className: "h-3.5 w-3.5", "aria-hidden": "true" }), children: t('analyticsTranscriptTurnDetails.metadata') }), hasModel && (jsx("div", { "data-testid": "transcript-turn-model", className: "mb-2", children: (renderModel !== null && renderModel !== void 0 ? renderModel : defaultRenderModel)({ model, provider }) })), jsx(DetailRows, { entries: rest, labelFor: labelFor })] }));
233549
+ return (jsxs("section", { "data-testid": "transcript-turn-metadata", children: [jsx(SectionHeading, { icon: jsx(Info$3, { className: "h-3.5 w-3.5", "aria-hidden": "true" }), children: t('analyticsTranscriptTurnDetails.metadata') }), hasModel && (jsx("div", { "data-testid": "transcript-turn-model", className: "mb-2", children: renderModel
233550
+ ? renderModel({ model, provider })
233551
+ : defaultRenderModel({ model, provider, tenantKey, mentorId }) })), jsx(DetailRows, { entries: rest, labelFor: labelFor })] }));
233374
233552
  }
233375
233553
  function RequestContextSection({ requestContext }) {
233376
233554
  const t = useT();
@@ -233385,7 +233563,7 @@ function RequestContextSection({ requestContext }) {
233385
233563
  */
233386
233564
  const defaultRenderDocuments = (documents) => (jsx(RetrievedDocumentsButton, { documents: toRetrievedDocuments(documents) }));
233387
233565
  const defaultRenderToolCalls = (toolCalls) => (jsx(ToolCallIndicator, { toolCalls: toToolCallInfos(toolCalls), showResults: true }));
233388
- const defaultRenderModel = ({ model, provider }) => (jsx(LlmModelBadge, { model: model, provider: provider }));
233566
+ const defaultRenderModel = ({ model, provider, tenantKey, mentorId, }) => jsx(LlmModelBadge, { model: model, provider: provider, tenantKey: tenantKey, mentorId: mentorId });
233389
233567
  const defaultRenderFiles = (files) => (jsx(TranscriptFileCards, { files: files }));
233390
233568
  /**
233391
233569
  * Collapsible "Sources / Tools / Metadata" panel for one AI turn of an admin
@@ -233395,7 +233573,7 @@ const defaultRenderFiles = (files) => (jsx(TranscriptFileCards, { files: files }
233395
233573
  * renders nothing at all when every field is null or empty, so it is safe to
233396
233574
  * drop under every AI bubble.
233397
233575
  */
233398
- function TranscriptTurnDetails({ turn, className, defaultOpen = false, renderDocuments, renderToolCalls, renderModel, renderFiles, }) {
233576
+ function TranscriptTurnDetails({ turn, className, defaultOpen = false, renderDocuments, renderToolCalls, renderModel, renderFiles, tenantKey, mentorId, }) {
233399
233577
  const t = useT();
233400
233578
  const labelFor = useFieldLabels();
233401
233579
  const [open, setOpen] = React__default.useState(defaultOpen);
@@ -233409,7 +233587,7 @@ function TranscriptTurnDetails({ turn, className, defaultOpen = false, renderDoc
233409
233587
  const requestContext = hasEntries(turn === null || turn === void 0 ? void 0 : turn.request_context) ? turn === null || turn === void 0 ? void 0 : turn.request_context : null;
233410
233588
  return (jsx(DetailCtx.Provider, { value: detailContext, children: jsxs(Collapsible, { open: open, onOpenChange: setOpen, className: cn('mt-2', className), "data-testid": "transcript-turn-details", children: [jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [jsx(CollapsibleTrigger, { asChild: true, children: jsxs(Button$1, { type: "button", variant: "outline", size: "sm", className: "flex items-center gap-2 border-gray-200 bg-white text-gray-700 hover:bg-gray-50", "aria-expanded": open, children: [jsx(ChevronDown, { className: cn('h-4 w-4 transition-transform', open && 'rotate-180'), "aria-hidden": "true" }), open
233411
233589
  ? t('analyticsTranscriptTurnDetails.hideDetails')
233412
- : t('analyticsTranscriptTurnDetails.showDetails')] }) }), documents.length > 0 && (jsx("div", { "data-testid": "transcript-turn-sources", className: "contents", children: (renderDocuments !== null && renderDocuments !== void 0 ? renderDocuments : defaultRenderDocuments)(documents) })), jsx(TranscriptRollupBadges, { documentsCount: 0, toolCallsCount: toolCalls.length })] }), jsxs(CollapsibleContent, { className: "mt-2 space-y-5 rounded-lg border border-gray-200 bg-white p-3", children: [toolCalls.length > 0 && (jsx("div", { "data-testid": "transcript-turn-tools", children: (renderToolCalls !== null && renderToolCalls !== void 0 ? renderToolCalls : defaultRenderToolCalls)(toolCalls) })), metadata && jsx(MetadataSection, { metadata: metadata, renderModel: renderModel }), requestContext && jsx(RequestContextSection, { requestContext: requestContext })] })] }) }));
233590
+ : t('analyticsTranscriptTurnDetails.showDetails')] }) }), documents.length > 0 && (jsx("div", { "data-testid": "transcript-turn-sources", className: "contents", children: (renderDocuments !== null && renderDocuments !== void 0 ? renderDocuments : defaultRenderDocuments)(documents) })), jsx(TranscriptRollupBadges, { documentsCount: 0, toolCallsCount: toolCalls.length })] }), jsxs(CollapsibleContent, { className: "mt-2 space-y-5 rounded-lg border border-gray-200 bg-white p-3", children: [toolCalls.length > 0 && (jsx("div", { "data-testid": "transcript-turn-tools", children: (renderToolCalls !== null && renderToolCalls !== void 0 ? renderToolCalls : defaultRenderToolCalls)(toolCalls) })), metadata && (jsx(MetadataSection, { metadata: metadata, renderModel: renderModel, tenantKey: tenantKey, mentorId: mentorId })), requestContext && jsx(RequestContextSection, { requestContext: requestContext })] })] }) }));
233413
233591
  }
233414
233592
  /**
233415
233593
  * "Documents · N" / "Tools · N" chips for a conversation row, from the
@@ -233425,118 +233603,6 @@ function TranscriptRollupBadges({ documentsCount, toolCallsCount, className, })
233425
233603
  return (jsxs("span", { className: cn('inline-flex flex-wrap items-center gap-1.5', className), "data-testid": "transcript-rollup-badges", children: [documents > 0 && (jsxs(Badge, { variant: "outline", className: "gap-1 border-transparent bg-blue-50 font-normal text-blue-700", "data-testid": "transcript-sources-badge", children: [jsx(FileText, { className: "h-3 w-3", "aria-hidden": "true" }), t('analyticsTranscriptTurnDetails.sourcesBadge', { count: documents })] })), tools > 0 && (jsxs(Badge, { variant: "outline", className: "gap-1 border-transparent bg-amber-50 font-normal text-amber-800", "data-testid": "transcript-tools-badge", children: [jsx(Wrench, { className: "h-3 w-3", "aria-hidden": "true" }), t('analyticsTranscriptTurnDetails.toolsBadge', { count: tools })] }))] }));
233426
233604
  }
233427
233605
 
233428
- /**
233429
- * One place that decides how a user is shown.
233430
- *
233431
- * Backend payloads name their user in a dozen ways — `email` / `lti_email` /
233432
- * `user_email`, `username` / `student` / `lti_username`, `name` /
233433
- * `full_name` / `user_full_name`, or a nested `user` object — and most of
233434
- * them can be empty, `null`, or a placeholder like "None". Every surface used
233435
- * to pick through those on its own. `resolveUserIdentity()` takes whatever
233436
- * the payload is and returns what to show, what to open a profile on, and
233437
- * the avatar initial, so the rule lives here and can be tweaked once.
233438
- *
233439
- * Default rule: email → full name → username → the anonymous label.
233440
- */
233441
- const DEFAULT_USER_IDENTITY_ORDER = ['email', 'name', 'username'];
233442
- const DEFAULT_ANONYMOUS_LABEL = 'Anonymous';
233443
- /** Values backends emit instead of "nothing". Compared case-insensitively. */
233444
- const PLACEHOLDERS = new Set([
233445
- '',
233446
- 'none',
233447
- 'null',
233448
- 'undefined',
233449
- 'n/a',
233450
- 'na',
233451
- '-',
233452
- 'anonymous',
233453
- 'anonymoususer',
233454
- ]);
233455
- /**
233456
- * `local@domain.tld` with no whitespace, checked with a single pass rather than
233457
- * a backtracking pattern (CodeQL flags `[^@]+@[^@]+\.[^@]+` as polynomial on
233458
- * adversarial input).
233459
- */
233460
- const isEmailLike = (value) => {
233461
- const text = value.trim();
233462
- if (!text || /\s/.test(text))
233463
- return false;
233464
- const at = text.indexOf('@');
233465
- if (at <= 0 || at !== text.lastIndexOf('@') || at === text.length - 1)
233466
- return false;
233467
- const domain = text.slice(at + 1);
233468
- const dot = domain.indexOf('.');
233469
- // A dot somewhere inside the domain, with something after the last one.
233470
- return dot > 0 && !domain.endsWith('.');
233471
- };
233472
- /** Trimmed string, or undefined for blanks, non-strings and placeholders. */
233473
- const clean = (value) => {
233474
- if (typeof value !== 'string')
233475
- return undefined;
233476
- const trimmed = value.trim();
233477
- return PLACEHOLDERS.has(trimmed.toLowerCase()) ? undefined : trimmed;
233478
- };
233479
- const firstOf = (...candidates) => {
233480
- for (const candidate of candidates) {
233481
- const value = clean(candidate);
233482
- if (value)
233483
- return value;
233484
- }
233485
- return undefined;
233486
- };
233487
- const nested = (source) => source.user && typeof source.user === 'object' ? source.user : undefined;
233488
- /**
233489
- * Resolve how a user should be displayed from any payload that names one.
233490
- *
233491
- * - `email`: `lti_email`, `email`, `user_email`, the nested `user`'s email —
233492
- * or a username field that turns out to hold an email address.
233493
- * - `username`: `lti_username`, `username`, `student`, `user_username`, the
233494
- * nested `user`'s username, or a bare string/number `user` value.
233495
- * - `name`: `user_full_name`, `full_name`, `name`, `first_name last_name`, or
233496
- * the nested `user`'s name.
233497
- * - `profileUsername`: the first *platform* username (never an LTI claim).
233498
- *
233499
- * A string source is treated as an email when it looks like one, else as a
233500
- * username. Placeholder strings ("None", "-", "anonymous"…) count as absent.
233501
- */
233502
- function resolveUserIdentity(source, options = {}) {
233503
- var _a;
233504
- const anonymousLabel = options.anonymousLabel || DEFAULT_ANONYMOUS_LABEL;
233505
- const order = ((_a = options.order) === null || _a === void 0 ? void 0 : _a.length) ? options.order : DEFAULT_USER_IDENTITY_ORDER;
233506
- const record = source && typeof source === 'object' ? source : { user: source !== null && source !== void 0 ? source : null };
233507
- const inner = nested(record);
233508
- // A bare `user` value is an id or username; numeric ids are still shown.
233509
- const bareUser = typeof record.user === 'number' && Number.isFinite(record.user)
233510
- ? String(record.user)
233511
- : typeof record.user === 'string'
233512
- ? clean(record.user)
233513
- : undefined;
233514
- let email = firstOf(record.lti_email, record.email, record.user_email, inner === null || inner === void 0 ? void 0 : inner.lti_email, inner === null || inner === void 0 ? void 0 : inner.email, inner === null || inner === void 0 ? void 0 : inner.user_email);
233515
- const platformUsername = firstOf(record.username, record.student, record.user_username, inner === null || inner === void 0 ? void 0 : inner.username, inner === null || inner === void 0 ? void 0 : inner.student, inner === null || inner === void 0 ? void 0 : inner.user_username, bareUser && !isEmailLike(bareUser) ? bareUser : undefined);
233516
- let username = firstOf(record.lti_username, inner === null || inner === void 0 ? void 0 : inner.lti_username, platformUsername);
233517
- const composed = [clean(record.first_name), clean(record.last_name)].filter(Boolean).join(' ');
233518
- const name = firstOf(record.user_full_name, record.full_name, record.name, composed, inner === null || inner === void 0 ? void 0 : inner.user_full_name, inner === null || inner === void 0 ? void 0 : inner.full_name, inner === null || inner === void 0 ? void 0 : inner.name);
233519
- // A bare string that looks like an email is an email, and so is a
233520
- // "username" field that actually carries one.
233521
- if (!email && bareUser && isEmailLike(bareUser))
233522
- email = bareUser;
233523
- if (!email && username && isEmailLike(username)) {
233524
- email = username;
233525
- username = undefined;
233526
- }
233527
- const facts = { email, username, name };
233528
- const label = order.map((field) => facts[field]).find(Boolean);
233529
- return {
233530
- label: label !== null && label !== void 0 ? label : anonymousLabel,
233531
- email,
233532
- username,
233533
- name,
233534
- profileUsername: platformUsername,
233535
- initial: (label !== null && label !== void 0 ? label : anonymousLabel).charAt(0).toUpperCase() || 'A',
233536
- isAnonymous: !label,
233537
- };
233538
- }
233539
-
233540
233606
  // Utility function to format relative time
233541
233607
  const formatRelativeTime = (dateString, t) => {
233542
233608
  const date = new Date(dateString);
@@ -233576,14 +233642,12 @@ const getMessageContent = (content) => {
233576
233642
  return '';
233577
233643
  };
233578
233644
  /**
233579
- * Label for whoever a transcript belongs to, via the shared identity rule.
233580
- * The analytics payload carries an email only on newer deployments, so it
233581
- * wins where present and the display name / username stand in behind it,
233582
- * in the order the caller asks for; "-" when the row names nobody.
233645
+ * The model as the nav bar shows it (logo + display name); hosts may override
233646
+ * via `turnDetails.renderModel`. The catalogue is read for the tenant and the
233647
+ * agent the conversation ran on — route params only carry those on the mentor
233648
+ * SPA, so analytics passes them explicitly.
233583
233649
  */
233584
- const identifyUser = (source, order) => resolveUserIdentity(source, { order, anonymousLabel: '-' }).label;
233585
- /** The model as the nav bar shows it (logo + display name); hosts may override via `turnDetails.renderModel`. */
233586
- const renderModelBadge = ({ model, provider }) => (jsx(LlmModelBadge, { model: model, provider: provider }));
233650
+ const renderModelBadge = ({ model, provider, tenantKey, mentorId, }) => jsx(LlmModelBadge, { model: model, provider: provider, tenantKey: tenantKey, mentorId: mentorId });
233587
233651
  /** Newer deployments name the provider on rows and summaries; older ones only the model. */
233588
233652
  const providerOf = (source) => {
233589
233653
  const value = source === null || source === void 0 ? void 0 : source.llm_provider;
@@ -233619,14 +233683,24 @@ function TranscriptDocumentsButton({ detail, className, }) {
233619
233683
  return (jsx(RetrievedDocumentsButton, { sessionId: sessionId, documents: documents.length > 0 ? documents : undefined, className: className }));
233620
233684
  }
233621
233685
  function AnalyticsTranscriptsStats({ tenantKey, currentSPA, mentorId, selectedMentorId, usergroupIds, turnDetails, }) {
233622
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p;
233686
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q;
233623
233687
  const t = useT();
233688
+ // Who a row belongs to, by the shared identity rule: the translated
233689
+ // "Anonymous" when the row names nobody (a bare "-" read as missing data).
233690
+ const identifyUser = React__default.useCallback((source, order) => resolveUserIdentity(source, {
233691
+ order,
233692
+ anonymousLabel: t('analyticsAnalyticsTranscriptsStats.anonymous'),
233693
+ }).label, [t]);
233624
233694
  const currentMentorId = useScopedMentorId(selectedMentorId, mentorId);
233625
233695
  const [isModalOpen, setIsModalOpen] = useState(false);
233626
233696
  const searchParams = useSearchParams();
233627
233697
  const router = useRouter();
233628
233698
  const pathname = usePathname();
233629
233699
  const { transcriptsMessagesData, isLoadingTranscriptsMessagesData, isFetchingTranscriptsMessagesData, filters, setFilters, handleClearFilters, currentPage, handlePageChange, selectedTranscript, setSelectedTranscript, transcriptsMessagesDetailsData, isLoadingTranscriptsMessagesDetailsData, isErrorTranscriptsMessagesDetailsData, transcriptsConversationHeadlineData, isLoadingTranscriptsConversationHeadlineData, } = useTranscripts({ tenantKey, mentorId: currentMentorId, usergroupIds });
233700
+ // The agent the open transcript ran on — the catalogue scope for its model
233701
+ // badge. Hosts that browse across agents (the LMS analytics route) pass no
233702
+ // mentorId, so the transcript's own agent is the only correct scope.
233703
+ const detailMentorId = ((_a = transcriptsMessagesDetailsData === null || transcriptsMessagesDetailsData === void 0 ? void 0 : transcriptsMessagesDetailsData.summary) === null || _a === void 0 ? void 0 : _a.mentor_unique_id) || currentMentorId;
233630
233704
  // Read session_id from URL on mount and select the transcript
233631
233705
  useEffect(() => {
233632
233706
  const sessionIdParam = searchParams === null || searchParams === void 0 ? void 0 : searchParams.get('session_id');
@@ -233739,15 +233813,17 @@ function AnalyticsTranscriptsStats({ tenantKey, currentSPA, mentorId, selectedMe
233739
233813
  ? ((_e = turnDetails === null || turnDetails === void 0 ? void 0 : turnDetails.renderModel) !== null && _e !== void 0 ? _e : renderModelBadge)({
233740
233814
  model: transcriptsMessagesDetailsData.summary.model,
233741
233815
  provider: (_f = providerOf(transcriptsMessagesDetailsData.summary)) !== null && _f !== void 0 ? _f : providerOfTurns(transcriptsMessagesDetailsData.messages),
233816
+ tenantKey,
233817
+ mentorId: detailMentorId,
233742
233818
  })
233743
233819
  : '-'] }), jsx(TranscriptDocumentsButton, { detail: transcriptsMessagesDetailsData, className: "mt-2" })] })] }), jsx("div", { className: "flex-1 overflow-y-auto space-y-4 min-h-0", children: ((_g = transcriptsMessagesDetailsData === null || transcriptsMessagesDetailsData === void 0 ? void 0 : transcriptsMessagesDetailsData.messages) === null || _g === void 0 ? void 0 : _g.length) > 0 ? ((_h = transcriptsMessagesDetailsData === null || transcriptsMessagesDetailsData === void 0 ? void 0 : transcriptsMessagesDetailsData.messages) === null || _h === void 0 ? void 0 : _h.map((message, index) => {
233744
233820
  var _a, _b;
233745
- return (jsxs(React__default.Fragment, { children: [((message === null || message === void 0 ? void 0 : message.human) || !!((_a = message === null || message === void 0 ? void 0 : message.human_files) === null || _a === void 0 ? void 0 : _a.length)) && (jsxs("div", { className: `p-3 rounded-lg bg-blue-100 ml-4`, children: [jsx("div", { className: "flex justify-between items-start mb-1", children: jsx("span", { className: "font-medium text-sm", children: t('analyticsAnalyticsTranscriptsStats.roleUser') }) }), message.human && (jsx("p", { className: "text-sm", children: getMessageContent(message.human) })), jsx(TranscriptFiles, { files: message.human_files })] }, `${index}-human`)), ((message === null || message === void 0 ? void 0 : message.ai) || !!((_b = message === null || message === void 0 ? void 0 : message.ai_files) === null || _b === void 0 ? void 0 : _b.length)) && (jsxs("div", { className: `p-3 rounded-lg bg-white mr-4`, children: [jsx("div", { className: "flex justify-between items-start mb-1", children: jsx("span", { className: "font-medium text-sm", children: t('analyticsAnalyticsTranscriptsStats.roleAgent') }) }), message.ai && jsx(Markdown, { children: getMessageContent(message.ai) }), jsx(TranscriptFiles, { files: message.ai_files }), jsx(TranscriptTurnDetails, { turn: message, ...turnDetails })] }, `${index}-ai`))] }, index));
233821
+ return (jsxs(React__default.Fragment, { children: [((message === null || message === void 0 ? void 0 : message.human) || !!((_a = message === null || message === void 0 ? void 0 : message.human_files) === null || _a === void 0 ? void 0 : _a.length)) && (jsxs("div", { className: `p-3 rounded-lg bg-blue-100 ml-4`, children: [jsx("div", { className: "flex justify-between items-start mb-1", children: jsx("span", { className: "font-medium text-sm", children: t('analyticsAnalyticsTranscriptsStats.roleUser') }) }), message.human && (jsx("p", { className: "text-sm", children: getMessageContent(message.human) })), jsx(TranscriptFiles, { files: message.human_files })] }, `${index}-human`)), ((message === null || message === void 0 ? void 0 : message.ai) || !!((_b = message === null || message === void 0 ? void 0 : message.ai_files) === null || _b === void 0 ? void 0 : _b.length)) && (jsxs("div", { className: `p-3 rounded-lg bg-white mr-4`, children: [jsx("div", { className: "flex justify-between items-start mb-1", children: jsx("span", { className: "font-medium text-sm", children: t('analyticsAnalyticsTranscriptsStats.roleAgent') }) }), message.ai && jsx(Markdown, { children: getMessageContent(message.ai) }), jsx(TranscriptFiles, { files: message.ai_files }), jsx(TranscriptTurnDetails, { turn: message, tenantKey: tenantKey, mentorId: detailMentorId, ...turnDetails })] }, `${index}-ai`))] }, index));
233746
233822
  })) : (jsx("div", { className: "text-center text-gray-500 py-8", children: jsx("p", { children: t('analyticsAnalyticsTranscriptsStats.noMessages') }) })) })] })) }));
233747
233823
  };
233748
- return (jsxs("div", { className: "space-y-8", children: [jsxs("div", { className: "grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4 mb-6", children: [jsx(StatCard, { title: t('analyticsAnalyticsTranscriptsStats.avgMessagesPerConversation'), value: ((_a = transcriptsConversationHeadlineData === null || transcriptsConversationHeadlineData === void 0 ? void 0 : transcriptsConversationHeadlineData.avg_messages_per_conversation) === null || _a === void 0 ? void 0 : _a.value) || 0, percentage: ((_b = transcriptsConversationHeadlineData === null || transcriptsConversationHeadlineData === void 0 ? void 0 : transcriptsConversationHeadlineData.avg_messages_per_conversation) === null || _b === void 0 ? void 0 : _b.percentage_change) ||
233749
- undefined, loading: isLoadingTranscriptsConversationHeadlineData, description: t('analyticsAnalyticsTranscriptsStats.avgMessagesPerConversationDescription') }), jsx(StatCard, { title: t('analyticsAnalyticsTranscriptsStats.avgCostPerConversation'), value: Number(((_c = transcriptsConversationHeadlineData === null || transcriptsConversationHeadlineData === void 0 ? void 0 : transcriptsConversationHeadlineData.avg_cost_per_conversation) === null || _c === void 0 ? void 0 : _c.value) || 0).toFixed(2), percentage: ((_d = transcriptsConversationHeadlineData === null || transcriptsConversationHeadlineData === void 0 ? void 0 : transcriptsConversationHeadlineData.avg_cost_per_conversation) === null || _d === void 0 ? void 0 : _d.percentage_change) ||
233750
- undefined, showDollarSign: true, loading: isLoadingTranscriptsConversationHeadlineData, description: t('analyticsAnalyticsTranscriptsStats.avgCostPerConversationDescription') }), jsx(StatCard, { title: t('analyticsAnalyticsTranscriptsStats.avgRating'), value: ((_e = transcriptsConversationHeadlineData === null || transcriptsConversationHeadlineData === void 0 ? void 0 : transcriptsConversationHeadlineData.avg_rating) === null || _e === void 0 ? void 0 : _e.value) || 0, percentage: ((_f = transcriptsConversationHeadlineData === null || transcriptsConversationHeadlineData === void 0 ? void 0 : transcriptsConversationHeadlineData.avg_rating) === null || _f === void 0 ? void 0 : _f.percentage_change) || undefined, loading: isLoadingTranscriptsConversationHeadlineData, description: t('analyticsAnalyticsTranscriptsStats.avgRatingDescription') })] }), jsxs("div", { className: "flex h-[calc(100vh-120px)]", children: [jsxs("div", { className: "w-full md:w-2/3 md:pr-6 overflow-y-auto md:border-r border-gray-200 [&::-webkit-scrollbar]:hidden [-ms-overflow-style:none] [scrollbar-width:none]", children: [jsx("div", { className: "mb-6", children: jsxs("div", { className: "flex gap-2 mb-4 items-center", children: [jsxs("div", { className: "relative", children: [jsx(Search, { className: "absolute left-3 top-1/2 transform -translate-y-1/2 text-gray-400 h-4 w-4" }), jsx(Input, { placeholder: t('analyticsAnalyticsTranscriptsStats.placeholderTopics'), value: filters.topicSearch, onChange: (e) => setFilters({ ...filters, topicSearch: e.target.value }), className: "pl-10 w-[200px]" })] }), jsx("div", { className: "w-[200px]", children: jsx(UserFilterSelect, { tenantKey: tenantKey, value: filters.userSearch, onChange: (username) => setFilters({ ...filters, userSearch: username }), showSelfOption: false, className: "bg-transparent" }) }), isFetchingTranscriptsMessagesData && (filters.userSearch || filters.topicSearch) ? (jsx("div", { className: "animate-spin rounded-full h-5 w-5 border-b-2 border-blue-500 ml-2", "aria-hidden": "true" })) : (jsx(Button$1, { variant: "outline", onClick: handleClearFilters, className: "whitespace-nowrap", children: t('analyticsAnalyticsTranscriptsStats.clearAll') }))] }) }), jsxs("div", { className: "bg-gray-50 p-4 rounded-lg mb-6", children: [jsxs("div", { className: "flex flex-wrap gap-x-8 gap-y-2 text-sm text-gray-600", children: [jsxs("div", { "aria-label": t('analyticsAnalyticsTranscriptsStats.ariaTotalConversations'), children: [transcriptsMessagesData === null || transcriptsMessagesData === void 0 ? void 0 : transcriptsMessagesData.summary.total_conversations, ' ', t('analyticsAnalyticsTranscriptsStats.conversations')] }), jsx("div", { children: "\u2022" }), jsxs("div", { children: [transcriptsMessagesData === null || transcriptsMessagesData === void 0 ? void 0 : transcriptsMessagesData.summary.user_queries, ' ', t('analyticsAnalyticsTranscriptsStats.userQueries')] }), jsx("div", { children: "\u2022" }), jsxs("div", { children: [transcriptsMessagesData === null || transcriptsMessagesData === void 0 ? void 0 : transcriptsMessagesData.summary.assistant_responses, ' ', t('analyticsAnalyticsTranscriptsStats.assistantResponses')] })] }), jsx("div", { className: "flex flex-wrap gap-x-8 gap-y-2 text-sm text-gray-600 mt-2", children: jsxs("div", { children: [transcriptsMessagesData === null || transcriptsMessagesData === void 0 ? void 0 : transcriptsMessagesData.summary.average_sentiment_score, ' ', t('analyticsAnalyticsTranscriptsStats.averageSentimentScore')] }) })] }), jsx("div", { className: "flex flex-col gap-4", children: isLoadingTranscriptsMessagesData ? (
233824
+ return (jsxs("div", { className: "space-y-8", children: [jsxs("div", { className: "grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4 mb-6", children: [jsx(StatCard, { title: t('analyticsAnalyticsTranscriptsStats.avgMessagesPerConversation'), value: ((_b = transcriptsConversationHeadlineData === null || transcriptsConversationHeadlineData === void 0 ? void 0 : transcriptsConversationHeadlineData.avg_messages_per_conversation) === null || _b === void 0 ? void 0 : _b.value) || 0, percentage: ((_c = transcriptsConversationHeadlineData === null || transcriptsConversationHeadlineData === void 0 ? void 0 : transcriptsConversationHeadlineData.avg_messages_per_conversation) === null || _c === void 0 ? void 0 : _c.percentage_change) ||
233825
+ undefined, loading: isLoadingTranscriptsConversationHeadlineData, description: t('analyticsAnalyticsTranscriptsStats.avgMessagesPerConversationDescription') }), jsx(StatCard, { title: t('analyticsAnalyticsTranscriptsStats.avgCostPerConversation'), value: Number(((_d = transcriptsConversationHeadlineData === null || transcriptsConversationHeadlineData === void 0 ? void 0 : transcriptsConversationHeadlineData.avg_cost_per_conversation) === null || _d === void 0 ? void 0 : _d.value) || 0).toFixed(2), percentage: ((_e = transcriptsConversationHeadlineData === null || transcriptsConversationHeadlineData === void 0 ? void 0 : transcriptsConversationHeadlineData.avg_cost_per_conversation) === null || _e === void 0 ? void 0 : _e.percentage_change) ||
233826
+ undefined, showDollarSign: true, loading: isLoadingTranscriptsConversationHeadlineData, description: t('analyticsAnalyticsTranscriptsStats.avgCostPerConversationDescription') }), jsx(StatCard, { title: t('analyticsAnalyticsTranscriptsStats.avgRating'), value: ((_f = transcriptsConversationHeadlineData === null || transcriptsConversationHeadlineData === void 0 ? void 0 : transcriptsConversationHeadlineData.avg_rating) === null || _f === void 0 ? void 0 : _f.value) || 0, percentage: ((_g = transcriptsConversationHeadlineData === null || transcriptsConversationHeadlineData === void 0 ? void 0 : transcriptsConversationHeadlineData.avg_rating) === null || _g === void 0 ? void 0 : _g.percentage_change) || undefined, loading: isLoadingTranscriptsConversationHeadlineData, description: t('analyticsAnalyticsTranscriptsStats.avgRatingDescription') })] }), jsxs("div", { className: "flex h-[calc(100vh-120px)]", children: [jsxs("div", { className: "w-full md:w-2/3 md:pr-6 overflow-y-auto md:border-r border-gray-200 [&::-webkit-scrollbar]:hidden [-ms-overflow-style:none] [scrollbar-width:none]", children: [jsx("div", { className: "mb-6", children: jsxs("div", { className: "flex gap-2 mb-4 items-center", children: [jsxs("div", { className: "relative", children: [jsx(Search, { className: "absolute left-3 top-1/2 transform -translate-y-1/2 text-gray-400 h-4 w-4" }), jsx(Input, { placeholder: t('analyticsAnalyticsTranscriptsStats.placeholderTopics'), value: filters.topicSearch, onChange: (e) => setFilters({ ...filters, topicSearch: e.target.value }), className: "pl-10 w-[200px]" })] }), jsx("div", { className: "w-[200px]", children: jsx(UserFilterSelect, { tenantKey: tenantKey, value: filters.userSearch, onChange: (username) => setFilters({ ...filters, userSearch: username }), showSelfOption: false, className: "bg-transparent" }) }), isFetchingTranscriptsMessagesData && (filters.userSearch || filters.topicSearch) ? (jsx("div", { className: "animate-spin rounded-full h-5 w-5 border-b-2 border-blue-500 ml-2", "aria-hidden": "true" })) : (jsx(Button$1, { variant: "outline", onClick: handleClearFilters, className: "whitespace-nowrap", children: t('analyticsAnalyticsTranscriptsStats.clearAll') }))] }) }), jsxs("div", { className: "bg-gray-50 p-4 rounded-lg mb-6", children: [jsxs("div", { className: "flex flex-wrap gap-x-8 gap-y-2 text-sm text-gray-600", children: [jsxs("div", { "aria-label": t('analyticsAnalyticsTranscriptsStats.ariaTotalConversations'), children: [transcriptsMessagesData === null || transcriptsMessagesData === void 0 ? void 0 : transcriptsMessagesData.summary.total_conversations, ' ', t('analyticsAnalyticsTranscriptsStats.conversations')] }), jsx("div", { children: "\u2022" }), jsxs("div", { children: [transcriptsMessagesData === null || transcriptsMessagesData === void 0 ? void 0 : transcriptsMessagesData.summary.user_queries, ' ', t('analyticsAnalyticsTranscriptsStats.userQueries')] }), jsx("div", { children: "\u2022" }), jsxs("div", { children: [transcriptsMessagesData === null || transcriptsMessagesData === void 0 ? void 0 : transcriptsMessagesData.summary.assistant_responses, ' ', t('analyticsAnalyticsTranscriptsStats.assistantResponses')] })] }), jsx("div", { className: "flex flex-wrap gap-x-8 gap-y-2 text-sm text-gray-600 mt-2", children: jsxs("div", { children: [transcriptsMessagesData === null || transcriptsMessagesData === void 0 ? void 0 : transcriptsMessagesData.summary.average_sentiment_score, ' ', t('analyticsAnalyticsTranscriptsStats.averageSentimentScore')] }) })] }), jsx("div", { className: "flex flex-col gap-4", children: isLoadingTranscriptsMessagesData ? (
233751
233827
  // Loading state
233752
233828
  jsx("div", { className: "space-y-4", children: Array.from({ length: 3 }).map((_, index) => (jsxs(Card$1, { className: "p-4 animate-pulse", children: [jsx("div", { className: "mb-3", children: jsx("div", { className: "h-4 bg-gray-200 rounded w-3/4" }) }), jsxs("div", { className: "flex flex-wrap gap-2 mb-3", children: [jsx("div", { className: "h-6 bg-gray-200 rounded w-16" }), jsx("div", { className: "h-6 bg-gray-200 rounded w-20" })] }), jsxs("div", { className: "flex flex-wrap gap-x-6 gap-y-2 mb-2", children: [jsx("div", { className: "h-4 bg-gray-200 rounded w-24" }), jsx("div", { className: "h-4 bg-gray-200 rounded w-20" })] }), jsxs("div", { className: "flex flex-wrap gap-x-6 gap-y-2", children: [jsx("div", { className: "h-4 bg-gray-200 rounded w-20" }), jsx("div", { className: "h-4 bg-gray-200 rounded w-24" })] })] }, index))) })) : (transcriptsMessagesData === null || transcriptsMessagesData === void 0 ? void 0 : transcriptsMessagesData.results) && transcriptsMessagesData.results.length > 0 ? (
233753
233829
  // Results
@@ -233764,10 +233840,12 @@ function AnalyticsTranscriptsStats({ tenantKey, currentSPA, mentorId, selectedMe
233764
233840
  ? t('analyticsAnalyticsTranscriptsStats.sentimentNegative')
233765
233841
  : transcript.sentiment === 'positive'
233766
233842
  ? t('analyticsAnalyticsTranscriptsStats.sentimentPositive')
233767
- : t('analyticsAnalyticsTranscriptsStats.sentimentNeutral'), ' ', t('analyticsAnalyticsTranscriptsStats.userSentiment')] })] }) }), jsxs("div", { className: "flex flex-wrap gap-x-6 gap-y-2 text-xs text-gray-500 mb-2", children: [jsxs("div", { children: [t('analyticsAnalyticsTranscriptsStats.labelUser'), ' ', jsx(UserProfileLink, { currentSPA: currentSPA, tenantKey: tenantKey, username: transcript === null || transcript === void 0 ? void 0 : transcript.username, display: identifyUser(transcript) })] }), jsxs("div", { children: [t('analyticsAnalyticsTranscriptsStats.labelAgent'), ' ', jsx(AgentScopeLink, { uniqueId: transcript === null || transcript === void 0 ? void 0 : transcript.mentor_unique_id, name: transcript === null || transcript === void 0 ? void 0 : transcript.mentor })] })] }), jsx("div", { className: "flex flex-wrap gap-x-6 gap-y-2 text-xs text-gray-500 mb-2", children: jsxs("div", { className: "inline-flex flex-wrap items-center gap-1.5", children: [t('analyticsAnalyticsTranscriptsStats.labelModelCard'), ' ', (transcript === null || transcript === void 0 ? void 0 : transcript.model)
233843
+ : t('analyticsAnalyticsTranscriptsStats.sentimentNeutral'), ' ', t('analyticsAnalyticsTranscriptsStats.userSentiment')] })] }) }), jsxs("div", { className: "flex flex-wrap items-baseline gap-x-6 gap-y-2 text-xs text-gray-500 mb-2", children: [jsxs("div", { children: [t('analyticsAnalyticsTranscriptsStats.labelUser'), ' ', jsx(UserProfileLink, { currentSPA: currentSPA, tenantKey: tenantKey, username: transcript === null || transcript === void 0 ? void 0 : transcript.username, display: identifyUser(transcript) })] }), jsxs("div", { children: [t('analyticsAnalyticsTranscriptsStats.labelAgent'), ' ', jsx(AgentScopeLink, { uniqueId: transcript === null || transcript === void 0 ? void 0 : transcript.mentor_unique_id, name: transcript === null || transcript === void 0 ? void 0 : transcript.mentor })] })] }), jsx("div", { className: "flex flex-wrap gap-x-6 gap-y-2 text-xs text-gray-500 mb-2", children: jsxs("div", { className: "inline-flex flex-wrap items-center gap-1.5", children: [t('analyticsAnalyticsTranscriptsStats.labelModelCard'), ' ', (transcript === null || transcript === void 0 ? void 0 : transcript.model)
233768
233844
  ? ((_c = turnDetails === null || turnDetails === void 0 ? void 0 : turnDetails.renderModel) !== null && _c !== void 0 ? _c : renderModelBadge)({
233769
233845
  model: transcript.model,
233770
233846
  provider: providerOf(transcript),
233847
+ tenantKey,
233848
+ mentorId: (transcript === null || transcript === void 0 ? void 0 : transcript.mentor_unique_id) || currentMentorId,
233771
233849
  })
233772
233850
  : '-'] }) }), jsxs("div", { className: "flex flex-wrap gap-x-6 gap-y-2 text-xs text-gray-500", children: [jsxs("div", { children: [transcript.message_count, " ", t('analyticsAnalyticsTranscriptsStats.messages')] }), jsx("div", { children: "\u2022" }), jsxs("div", { children: ["$", Number((transcript === null || transcript === void 0 ? void 0 : transcript.cost) || 0).toFixed(2), ' ', t('analyticsAnalyticsTranscriptsStats.estimatedCost')] }), (transcript === null || transcript === void 0 ? void 0 : transcript.created_at) && (jsxs(Fragment$1, { children: [jsx("div", { children: "\u2022" }), jsxs("div", { children: [t('analyticsAnalyticsTranscriptsStats.created'), ' ', formatRelativeTime(transcript.created_at, t)] })] }))] })] }, transcript.session));
233773
233851
  })) : (
@@ -233805,14 +233883,16 @@ function AnalyticsTranscriptsStats({ tenantKey, currentSPA, mentorId, selectedMe
233805
233883
  /* Error or no data state */
233806
233884
  jsx("div", { className: "flex items-center justify-center h-full text-gray-400", children: jsxs("div", { className: "text-center", children: [jsx(X$1, { className: "h-6 w-6 mx-auto mb-2 text-red-400" }), jsx("p", { children: t('analyticsAnalyticsTranscriptsStats.noTranscriptDetails') }), jsx("p", { className: "text-sm mt-1", children: t('analyticsAnalyticsTranscriptsStats.unableToLoadTranscript') })] }) })) : (
233807
233885
  /* Data loaded successfully */
233808
- jsxs("div", { className: "space-y-4", children: [jsx("div", { className: "mb-4", children: jsxs("div", { className: "text-sm text-gray-500 space-y-1", children: [jsxs("div", { children: [t('analyticsAnalyticsTranscriptsStats.labelUser'), ' ', jsx(UserProfileLink, { currentSPA: currentSPA, tenantKey: tenantKey, username: (_g = transcriptsMessagesDetailsData === null || transcriptsMessagesDetailsData === void 0 ? void 0 : transcriptsMessagesDetailsData.summary) === null || _g === void 0 ? void 0 : _g.username, display: identifyUser(transcriptsMessagesDetailsData === null || transcriptsMessagesDetailsData === void 0 ? void 0 : transcriptsMessagesDetailsData.summary) })] }), jsxs("div", { children: [t('analyticsAnalyticsTranscriptsStats.labelAgent'), ' ', jsx(AgentScopeLink, { uniqueId: (_h = transcriptsMessagesDetailsData === null || transcriptsMessagesDetailsData === void 0 ? void 0 : transcriptsMessagesDetailsData.summary) === null || _h === void 0 ? void 0 : _h.mentor_unique_id, name: (_j = transcriptsMessagesDetailsData === null || transcriptsMessagesDetailsData === void 0 ? void 0 : transcriptsMessagesDetailsData.summary) === null || _j === void 0 ? void 0 : _j.mentor })] }), jsxs("div", { className: "flex flex-wrap items-center gap-1.5", children: [t('analyticsAnalyticsTranscriptsStats.labelModel'), ' ', ((_k = transcriptsMessagesDetailsData === null || transcriptsMessagesDetailsData === void 0 ? void 0 : transcriptsMessagesDetailsData.summary) === null || _k === void 0 ? void 0 : _k.model)
233809
- ? ((_l = turnDetails === null || turnDetails === void 0 ? void 0 : turnDetails.renderModel) !== null && _l !== void 0 ? _l : renderModelBadge)({
233886
+ jsxs("div", { className: "space-y-4", children: [jsx("div", { className: "mb-4", children: jsxs("div", { className: "text-sm text-gray-500 space-y-1", children: [jsxs("div", { children: [t('analyticsAnalyticsTranscriptsStats.labelUser'), ' ', jsx(UserProfileLink, { currentSPA: currentSPA, tenantKey: tenantKey, username: (_h = transcriptsMessagesDetailsData === null || transcriptsMessagesDetailsData === void 0 ? void 0 : transcriptsMessagesDetailsData.summary) === null || _h === void 0 ? void 0 : _h.username, display: identifyUser(transcriptsMessagesDetailsData === null || transcriptsMessagesDetailsData === void 0 ? void 0 : transcriptsMessagesDetailsData.summary) })] }), jsxs("div", { children: [t('analyticsAnalyticsTranscriptsStats.labelAgent'), ' ', jsx(AgentScopeLink, { uniqueId: (_j = transcriptsMessagesDetailsData === null || transcriptsMessagesDetailsData === void 0 ? void 0 : transcriptsMessagesDetailsData.summary) === null || _j === void 0 ? void 0 : _j.mentor_unique_id, name: (_k = transcriptsMessagesDetailsData === null || transcriptsMessagesDetailsData === void 0 ? void 0 : transcriptsMessagesDetailsData.summary) === null || _k === void 0 ? void 0 : _k.mentor })] }), jsxs("div", { className: "flex flex-wrap items-center gap-1.5", children: [t('analyticsAnalyticsTranscriptsStats.labelModel'), ' ', ((_l = transcriptsMessagesDetailsData === null || transcriptsMessagesDetailsData === void 0 ? void 0 : transcriptsMessagesDetailsData.summary) === null || _l === void 0 ? void 0 : _l.model)
233887
+ ? ((_m = turnDetails === null || turnDetails === void 0 ? void 0 : turnDetails.renderModel) !== null && _m !== void 0 ? _m : renderModelBadge)({
233810
233888
  model: transcriptsMessagesDetailsData.summary.model,
233811
- provider: (_m = providerOf(transcriptsMessagesDetailsData.summary)) !== null && _m !== void 0 ? _m : providerOfTurns(transcriptsMessagesDetailsData.messages),
233889
+ provider: (_o = providerOf(transcriptsMessagesDetailsData.summary)) !== null && _o !== void 0 ? _o : providerOfTurns(transcriptsMessagesDetailsData.messages),
233890
+ tenantKey,
233891
+ mentorId: detailMentorId,
233812
233892
  })
233813
- : '-'] }), jsx(TranscriptDocumentsButton, { detail: transcriptsMessagesDetailsData, className: "mt-2" })] }) }), jsx("div", { className: "space-y-4 pb-4", children: ((_o = transcriptsMessagesDetailsData === null || transcriptsMessagesDetailsData === void 0 ? void 0 : transcriptsMessagesDetailsData.messages) === null || _o === void 0 ? void 0 : _o.length) > 0 ? ((_p = transcriptsMessagesDetailsData === null || transcriptsMessagesDetailsData === void 0 ? void 0 : transcriptsMessagesDetailsData.messages) === null || _p === void 0 ? void 0 : _p.map((message, index) => {
233893
+ : '-'] }), jsx(TranscriptDocumentsButton, { detail: transcriptsMessagesDetailsData, className: "mt-2" })] }) }), jsx("div", { className: "space-y-4 pb-4", children: ((_p = transcriptsMessagesDetailsData === null || transcriptsMessagesDetailsData === void 0 ? void 0 : transcriptsMessagesDetailsData.messages) === null || _p === void 0 ? void 0 : _p.length) > 0 ? ((_q = transcriptsMessagesDetailsData === null || transcriptsMessagesDetailsData === void 0 ? void 0 : transcriptsMessagesDetailsData.messages) === null || _q === void 0 ? void 0 : _q.map((message, index) => {
233814
233894
  var _a, _b;
233815
- return (jsxs(React__default.Fragment, { children: [((message === null || message === void 0 ? void 0 : message.human) || !!((_a = message === null || message === void 0 ? void 0 : message.human_files) === null || _a === void 0 ? void 0 : _a.length)) && (jsxs("div", { className: "p-3 rounded-lg bg-blue-100 ml-4", children: [jsx("div", { className: "flex justify-between items-start mb-1", children: jsx("span", { className: "font-medium text-sm", children: t('analyticsAnalyticsTranscriptsStats.roleUser') }) }), message.human && (jsx("p", { className: "text-sm", children: getMessageContent(message.human) })), jsx(TranscriptFiles, { files: message.human_files })] })), ((message === null || message === void 0 ? void 0 : message.ai) || !!((_b = message === null || message === void 0 ? void 0 : message.ai_files) === null || _b === void 0 ? void 0 : _b.length)) && (jsxs("div", { className: "p-3 rounded-lg bg-white mr-4 border", style: { borderColor: 'oklch(.922 0 0)' }, children: [jsx("div", { className: "flex justify-between items-start mb-1", children: jsx("span", { className: "font-medium text-sm", children: t('analyticsAnalyticsTranscriptsStats.roleAgent') }) }), message.ai && jsx(Markdown, { children: getMessageContent(message.ai) }), jsx(TranscriptFiles, { files: message.ai_files }), jsx(TranscriptTurnDetails, { turn: message, ...turnDetails })] }))] }, index));
233895
+ return (jsxs(React__default.Fragment, { children: [((message === null || message === void 0 ? void 0 : message.human) || !!((_a = message === null || message === void 0 ? void 0 : message.human_files) === null || _a === void 0 ? void 0 : _a.length)) && (jsxs("div", { className: "p-3 rounded-lg bg-blue-100 ml-4", children: [jsx("div", { className: "flex justify-between items-start mb-1", children: jsx("span", { className: "font-medium text-sm", children: t('analyticsAnalyticsTranscriptsStats.roleUser') }) }), message.human && (jsx("p", { className: "text-sm", children: getMessageContent(message.human) })), jsx(TranscriptFiles, { files: message.human_files })] })), ((message === null || message === void 0 ? void 0 : message.ai) || !!((_b = message === null || message === void 0 ? void 0 : message.ai_files) === null || _b === void 0 ? void 0 : _b.length)) && (jsxs("div", { className: "p-3 rounded-lg bg-white mr-4 border", style: { borderColor: 'oklch(.922 0 0)' }, children: [jsx("div", { className: "flex justify-between items-start mb-1", children: jsx("span", { className: "font-medium text-sm", children: t('analyticsAnalyticsTranscriptsStats.roleAgent') }) }), message.ai && jsx(Markdown, { children: getMessageContent(message.ai) }), jsx(TranscriptFiles, { files: message.ai_files }), jsx(TranscriptTurnDetails, { turn: message, tenantKey: tenantKey, mentorId: detailMentorId, ...turnDetails })] }))] }, index));
233816
233896
  })) : (jsx("div", { className: "text-center text-gray-500 py-8", children: jsx("p", { children: t('analyticsAnalyticsTranscriptsStats.noMessages') }) })) })] })) })] }) }))] }));
233817
233897
  }
233818
233898
 
@@ -236507,7 +236587,7 @@ function AgentAuditLogView({ tenantKey, mentorId, userId, selectedMentorId, curr
236507
236587
  }, numberOfMonths: 2 }) })] }), jsx("div", { className: "min-w-[160px]", children: jsxs(Select$1, { value: actionFilter !== undefined ? String(actionFilter) : 'all', onValueChange: (val) => {
236508
236588
  setActionFilter(val === 'all' ? undefined : Number(val));
236509
236589
  setPage(1);
236510
- }, children: [jsx(SelectTrigger, { className: "w-full font-normal bg-white h-9", children: jsx(SelectValue, { placeholder: t('analyticsAnalyticsAuditLogStats.allActions') }) }), jsx(SelectContent, { children: ACTION_FILTER_OPTIONS.map((opt) => (jsx(SelectItem, { value: opt.value, children: opt.label }, opt.value))) })] }) })] }) }), jsx("div", { className: "overflow-hidden rounded-md border border-[oklch(0.922_0_0)] bg-white", children: jsx("div", { className: "overflow-x-auto", children: jsx("div", { className: "inline-block min-w-full align-middle", children: isLoading ? (jsx("div", { className: "flex items-center justify-center w-full py-10", children: jsx("div", { className: "h-6 w-6 animate-spin rounded-full border-2 border-blue-600 border-t-transparent" }) })) : error && !is403 ? (jsx("div", { className: "py-8 text-center text-[#646464]", children: t('analyticsAnalyticsAuditLogStats.loadError') })) : !((_a = data === null || data === void 0 ? void 0 : data.results) === null || _a === void 0 ? void 0 : _a.length) ? (jsx("div", { className: "h-[120px]", children: jsx(EmptyStats, { title: t('analyticsAnalyticsAuditLogStats.noEntries') }) })) : (jsxs(Table, { className: "min-w-full", children: [jsx(TableHeader, { children: jsxs(TableRow, { className: "bg-muted/50 border-b border-[oklch(0.922_0_0)]", children: [jsx(TableHead, { className: "p-3 text-left text-sm whitespace-nowrap text-[#646464]", children: t('analyticsAnalyticsAuditLogStats.colUser') }), jsx(TableHead, { className: "p-3 text-left text-sm whitespace-nowrap text-[#646464]", children: t('analyticsAnalyticsAuditLogStats.colAction') }), jsx(TableHead, { className: "p-3 text-left text-sm whitespace-nowrap text-[#646464]", children: t('analyticsAnalyticsAuditLogStats.colTime') })] }) }), jsx(TableBody, { children: data.results.map((entry) => (jsxs(TableRow, { className: "border-b border-[oklch(0.922_0_0)] last:border-0", children: [jsx(TableCell, { className: "p-3 font-medium whitespace-nowrap text-[#646464]", children: jsx(UserProfileLink, { tenantKey: tenantKey, currentSPA: currentSPA, username: entry.actor_username, display: entry.actor_email || entry.actor_username }) }), jsx(TableCell, { className: "min-w-[250px] p-3 text-[#646464]", children: summarizeChanges(entry) }), jsx(TableCell, { className: "p-3 whitespace-nowrap text-[#646464]", children: formatDistanceToNow(new Date(entry.timestamp), { addSuffix: true }) })] }, entry.id))) })] })) }) }) }), jsx(IblPagination, { currentPage: page, totalPages: totalPages, onPageChange: setPage, disabled: isLoading })] }));
236590
+ }, children: [jsx(SelectTrigger, { className: "w-full font-normal bg-white h-9", children: jsx(SelectValue, { placeholder: t('analyticsAnalyticsAuditLogStats.allActions') }) }), jsx(SelectContent, { children: ACTION_FILTER_OPTIONS.map((opt) => (jsx(SelectItem, { value: opt.value, children: opt.label }, opt.value))) })] }) })] }) }), jsx("div", { className: "overflow-hidden rounded-md border border-[oklch(0.922_0_0)] bg-white", children: jsx("div", { className: "overflow-x-auto", children: jsx("div", { className: "inline-block min-w-full align-middle", children: isLoading ? (jsx("div", { className: "flex items-center justify-center w-full py-10", children: jsx("div", { className: "h-6 w-6 animate-spin rounded-full border-2 border-blue-600 border-t-transparent" }) })) : error && !is403 ? (jsx("div", { className: "py-8 text-center text-[#646464]", children: t('analyticsAnalyticsAuditLogStats.loadError') })) : !((_a = data === null || data === void 0 ? void 0 : data.results) === null || _a === void 0 ? void 0 : _a.length) ? (jsx("div", { className: "h-[120px]", children: jsx(EmptyStats, { title: t('analyticsAnalyticsAuditLogStats.noEntries') }) })) : (jsxs(Table, { className: "min-w-full", children: [jsx(TableHeader, { children: jsxs(TableRow, { className: "bg-muted/50 border-b border-[oklch(0.922_0_0)]", children: [jsx(TableHead, { className: "p-3 text-left text-sm whitespace-nowrap text-[#646464]", children: t('analyticsAnalyticsAuditLogStats.colUser') }), jsx(TableHead, { className: "p-3 text-left text-sm whitespace-nowrap text-[#646464]", children: t('analyticsAnalyticsAuditLogStats.colAction') }), jsx(TableHead, { className: "p-3 text-left text-sm whitespace-nowrap text-[#646464]", children: t('analyticsAnalyticsAuditLogStats.colTime') })] }) }), jsx(TableBody, { children: data.results.map((entry) => (jsxs(TableRow, { className: "border-b border-[oklch(0.922_0_0)] last:border-0", children: [jsx(TableCell, { className: "p-3 font-medium whitespace-nowrap text-[#646464]", children: jsx(UserProfileLink, { tenantKey: tenantKey, currentSPA: currentSPA, username: entry.actor_username, display: resolveUserIdentity({ email: entry.actor_email, username: entry.actor_username }, { anonymousLabel: t('analyticsAnalyticsAuditLogStats.anonymous') }).label }) }), jsx(TableCell, { className: "min-w-[250px] p-3 text-[#646464]", children: summarizeChanges(entry) }), jsx(TableCell, { className: "p-3 whitespace-nowrap text-[#646464]", children: formatDistanceToNow(new Date(entry.timestamp), { addSuffix: true }) })] }, entry.id))) })] })) }) }) }), jsx(IblPagination, { currentPage: page, totalPages: totalPages, onPageChange: setPage, disabled: isLoading })] }));
236511
236591
  }
236512
236592
  function AnalyticsAuditLogStats({ tenantKey, currentSPA, mentorId, userId, selectedMentorId, defaultScope = 'agent', timezone, canViewPlatformAudit, }) {
236513
236593
  const t = useT();
@@ -236547,14 +236627,14 @@ const formatDate = (date) => date ? date.toISOString().split('T')[0] : undefined
236547
236627
  function isForbiddenError(error) {
236548
236628
  return !!error && 'status' in error && error.status === 403;
236549
236629
  }
236550
- function toRowFromMentorMemory(memory) {
236630
+ function toRowFromMentorMemory(memory, anonymousLabel) {
236551
236631
  var _a, _b, _c, _d, _e, _f;
236552
236632
  return {
236553
236633
  id: memory.id,
236554
236634
  content: memory.content,
236555
236635
  categoryName: (_b = (_a = memory.category) === null || _a === void 0 ? void 0 : _a.name) !== null && _b !== void 0 ? _b : null,
236556
236636
  categorySlug: (_d = (_c = memory.category) === null || _c === void 0 ? void 0 : _c.slug) !== null && _d !== void 0 ? _d : null,
236557
- learner: memory.email || memory.username,
236637
+ learner: resolveUserIdentity(memory, { anonymousLabel }).label,
236558
236638
  username: memory.username,
236559
236639
  email: memory.email || null,
236560
236640
  mentorId: (_e = memory.mentor_id) !== null && _e !== void 0 ? _e : null,
@@ -236564,13 +236644,13 @@ function toRowFromMentorMemory(memory) {
236564
236644
  createdAt: memory.created_at,
236565
236645
  };
236566
236646
  }
236567
- function toRowFromGlobalMemory(memory) {
236647
+ function toRowFromGlobalMemory(memory, anonymousLabel) {
236568
236648
  return {
236569
236649
  id: memory.id,
236570
236650
  content: memory.content,
236571
236651
  categoryName: null,
236572
236652
  categorySlug: null,
236573
- learner: memory.username,
236653
+ learner: resolveUserIdentity(memory, { anonymousLabel }).label,
236574
236654
  username: memory.username,
236575
236655
  email: null,
236576
236656
  mentorId: null,
@@ -236674,14 +236754,18 @@ const useMemory = ({ tenantKey, userId, mentorId, myMemory = false, }) => {
236674
236754
  }), [page, learnerFilter, contentFilter, startDate, endDate]);
236675
236755
  const { data: globalMemories, isLoading: isLoadingGlobal, isFetching: isFetchingGlobal, error: globalError, } = useGetGlobalMemoriesQuery({ org: tenantKey, userId, params: globalParams }, { skip: !hasIdentity || !isGlobalScope });
236676
236756
  const { data: adminCategories } = useGetMemoryCategoriesAdminQuery({ org: tenantKey, mentorId: mentorId !== null && mentorId !== void 0 ? mentorId : '' }, { skip: !tenantKey || !hasMentor });
236757
+ const t = useT();
236758
+ // The learner label when a memory names nobody — the same translated word
236759
+ // the other analytics tabs use.
236760
+ const anonymousLabel = t('analyticsAnalyticsMemoryStats.anonymous');
236677
236761
  const rows = useMemo(() => {
236678
236762
  var _a, _b, _c;
236679
236763
  if (isMentorScope)
236680
- return ((_a = mentorList === null || mentorList === void 0 ? void 0 : mentorList.results) !== null && _a !== void 0 ? _a : []).map(toRowFromMentorMemory);
236764
+ return ((_a = mentorList === null || mentorList === void 0 ? void 0 : mentorList.results) !== null && _a !== void 0 ? _a : []).map((memory) => toRowFromMentorMemory(memory, anonymousLabel));
236681
236765
  if (isAllMentorsScope)
236682
- return ((_b = allMentors === null || allMentors === void 0 ? void 0 : allMentors.results) !== null && _b !== void 0 ? _b : []).map(toRowFromMentorMemory);
236683
- return ((_c = globalMemories === null || globalMemories === void 0 ? void 0 : globalMemories.results) !== null && _c !== void 0 ? _c : []).map(toRowFromGlobalMemory);
236684
- }, [isMentorScope, isAllMentorsScope, mentorList, allMentors, globalMemories]);
236766
+ return ((_b = allMentors === null || allMentors === void 0 ? void 0 : allMentors.results) !== null && _b !== void 0 ? _b : []).map((memory) => toRowFromMentorMemory(memory, anonymousLabel));
236767
+ return ((_c = globalMemories === null || globalMemories === void 0 ? void 0 : globalMemories.results) !== null && _c !== void 0 ? _c : []).map((memory) => toRowFromGlobalMemory(memory, anonymousLabel));
236768
+ }, [isMentorScope, isAllMentorsScope, mentorList, allMentors, globalMemories, anonymousLabel]);
236685
236769
  const totalCount = useMemo(() => {
236686
236770
  var _a, _b, _c;
236687
236771
  if (isMentorScope)
@@ -236704,7 +236788,7 @@ const useMemory = ({ tenantKey, userId, mentorId, myMemory = false, }) => {
236704
236788
  let totalMemories = 0;
236705
236789
  const categories = groups.map((group) => {
236706
236790
  group.memories.forEach((memory) => {
236707
- learners.add(memory.email || memory.username);
236791
+ learners.add(resolveUserIdentity(memory, { anonymousLabel }).label);
236708
236792
  if (memory.is_auto_generated)
236709
236793
  autoCaptured += 1;
236710
236794
  });
@@ -236721,7 +236805,7 @@ const useMemory = ({ tenantKey, userId, mentorId, myMemory = false, }) => {
236721
236805
  learners: learners.size,
236722
236806
  categories: categories.sort((a, b) => b.count - a.count),
236723
236807
  };
236724
- }, [isMentorScope, mentorGrouped, categoryFilter]);
236808
+ }, [isMentorScope, mentorGrouped, categoryFilter, anonymousLabel]);
236725
236809
  const error = isMentorScope ? mentorListError : isAllMentorsScope ? allMentorsError : globalError;
236726
236810
  const isLoading = isMentorScope
236727
236811
  ? isLoadingMentorList || isLoadingMentorGrouped
@@ -248212,5 +248296,5 @@ var trainOrDeleteModal = /*#__PURE__*/Object.freeze({
248212
248296
  TrainOrDeleteModal: TrainOrDeleteModal
248213
248297
  });
248214
248298
 
248215
- export { ACCESS_COURSE_LABEL, ALL_CATEGORIES, AccessTimeHeatmap, AccessiblePaginate, AddMentorToProjectModal, AddSkillDialog, Admin, AdvancedTab, AgentConfigPrompts, AgentScopeLink, AgentSkills, AlertsTab, AnalyticsAgentPicker, AnalyticsAreaChart, AnalyticsAuditLogStats, AnalyticsBarChart, AnalyticsControlBar, AnalyticsCourseDetail, AnalyticsCourses, AnalyticsFinancialStats, AnalyticsGlobalFiltersProvider, AnalyticsLayout, AnalyticsLlmUsageStats, AnalyticsMemoryStats, AnalyticsMonetizationStats, AnalyticsNotice, AnalyticsOverview, AnalyticsPlatformAuditLog, AnalyticsProgramDetail, AnalyticsPrograms, AnalyticsReportDownload, AnalyticsReports, AnalyticsScopeProvider, AnalyticsSettingsProvider, AnalyticsTopicsStats, AnalyticsTraces, AnalyticsTranscriptsStats, AnalyticsUsersStats, AppleRestrictionModal, ApplyWizard, AuditLogChangesView, AuditLogJsonView, BUY_NOW_LABEL, BillingTab, CATALOGS, CHART_ORDINAL_RAMP, CHART_SERIES_COLORS, CHART_SINGLE_SERIES_COLOR, CREATE_AGENT_LABELS, CUA_DRIVER_REPO_URL, CUA_DRIVER_TAURI_COMMANDS, CUA_DRIVER_TAURI_EVENTS, CardInfoIcon, CategorizedDropdownMenu, ChartCardWrapper, ChartFiltersProvider, ChartLoading, ChartTooltipCard, ChatContext, ChatPrivacyToggle, ChatProvider, CompanyDialog, ConnectorManagementDialog, CopyButtonIcon, CourseAccessGuard, CourseCardSkeleton, CourseContentLoading, CourseOutline, CourseOutlineContext, CourseOutlineDrawer, CreateAgentForm, CreateAgentModal, CreateProjectModal, CreateWorkflowModal, CredentialBox, CredentialMiniBoxSkeleton, CredentialsList, CreditBalance, CustomDateRangePicker, CustomTooltip, DEFAULT_COWORK_REQUIRED_SIZE_GB, DEFAULT_LOCALE, DEFAULT_USER_IDENTITY_ORDER, DefaultEmptyBox, DeleteProjectModal, DeleteWorkflowModal, DiscoverContentCard, DiscoverFacetsFilter, DiscoverFilterDrawer, DocumentSidebar, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, ENROLL_NOW_COURSE_STARTING_SOON_LABEL, ENROLL_NOW_LABEL, EditAlertDialog, EducationBox, EducationDialog, EducationTab, EdxIframeContext, EmptyStats, ExperienceBox, ExperienceDialog, ExperienceTab, FacetFilterContext, Footer, GradebookTab, GroupsFilterDropdown, INVITATION_ONLY_LABEL, InstitutionDialog, IntegrationsTab, InviteUserContent, InviteUserDialog, InvitedUsersDialog, LOCAL_LLM_CHANGED_EVENT, LOCAL_MODELS, LlmModelBadge, Loader, LocalLLMTab, LocalModelsContent, LoginButton, MACOS_PERMISSIONS_COMMANDS, MEMORY_PAGE_SIZE, Markdown, MemoryAdminTab, MinimumMentorAlert, MonetizationTab, NotificationDisplay, NotificationDropdown, ONBOARDING_FIELD_TYPES, ONBOARDING_SECTORS, OnboardingField, OnboardingShell, OnboardingWizard, PLATFORM_AUDIT_DEEP_PAGING_THRESHOLD, PLATFORM_AUDIT_PAGE_SIZE, PaywallModal, PlacementExam, PlacementExamsDropdown, PlatformAuditLogDetailSheet, PlatformNavbar, PlatformNavbarSearch, Profile, ProfileTimeChart, ProgressDots, ProjectActionButtons, ProjectFilesModal, ProjectInstructionsModal, ProjectLandingPage, ProjectMentorsList, ProjectsPage, REQUEST_ACCESS_COURSE_STARTING_SOON_LABEL, REQUEST_ACCESS_LABEL, RankedBars, RenameProjectModal, ResumeBox, ResumeTab, RetrievedDocumentsButton, RichTextEditor, SERVICE_COLOR_ORDER, SUPPORTED_LOCALES, SandboxConfig, SearchableMultiSelect, SendNotificationDialog, SignupButton, SkeletonActivityStatBox, SkeletonAddSkillsLoading, SkeletonCreatePathwaySearchList, SkeletonDiscoverFilterBox, SkeletonEducationBox, SkeletonMultiplier, SkeletonPathwayBox, SkeletonProfileInfoCard, SkeletonSkillBox, SkillBox, SkillDetailModal, SkillLeaderboardChart, SkillsBox, SkillsList, SlashSkillPicker, SourceChip, Spinner, StatCard, StepHeader, SummerNoteTextEditor, TAURI_COMMANDS, TAURI_EVENTS, TRACES_PAGE_SIZE, TenantSwitcher, TimeFilter, TimeTrackingProvider, TimedExam, ToolCallIndicator, ToolDialogs, TopBanner, TranscriptFileCards, TranscriptRollupBadges, TranscriptTurnDetails, TrendSparkline, USER_ONBOARDING_FORM_SLUG, USER_ONBOARDING_FORM_VERSION, USER_ONBOARDING_SUBMISSION_SLUG, UpgradePackageModal, UserAvatar, UserOnboardingWizard, UserProfileDialog, UserProfileLink, Version, WebContainersI18nProvider, WorkflowSidebar, addBookmarksTab, areChartFiltersEqual, availablePlacementExams, buildOnboardingAgentPath, buildUserOnboardingFormMetadata, buildUserOnboardingSubmissionMetadata, coerceOnboardingAgent, coerceOnboardingAgents, coerceUserOnboardingForm, colorForRank, colorForSeries, conversationDocuments, emptyUserOnboardingForm, findLastResumeBlock, findOnboardingAgent, findSequentialParent, flattenVerticalBlocks, formatAuditTimestamp, formatCompactNumber, formatFileSize, formatLatencySeconds, formatResult, formatTimeZoneLabel, getCatalog, getFirstAvailableUnit, getFriendlyToolName, getLLMModelDisplayName, getLocalLLMModel, getLocalLLMToolSupport, getNextUnitIframe, getOrg, getParentBlockById, getParentsInfosFromSublessonId, getPreviousUnitIframe, getQueryLabel, getRandomCourseImage, getSectorById, getTenant, getUnitToIframe, getUserId, getUserName, granularityForFilter, hasOnboardingContent, humanizeAuditToken, humanizeFieldName, inBrowserPrint, inIframe, inferProviderKeysFromModel, initialCuaDriverInstallState, initialModelDownloadState, isCoworkEnabled, isEmailLike, isFileReference, isLlmUsageForbidden, isLlmUsageUnavailable, isLocalLLMEnabled, isPlatformNavbarCreditBalanceVisible, isSlashCommandToken, isTauriApp, isValidLocale, isValidTimeZone, llmUsageDateArgs, components as markdownComponents, modelSupportsCowork, onboardingPrimaryButtonClass, onboardingSecondaryButtonClass, readUserOnboardingForm, readUserOnboardingSubmission, readUserOnboardingSubmissions, resolveAuditTimeZone, resolveCreateAgentLabels, resolveUserIdentity, sanitizeCss, setCoworkEnabled, setLocalLLMEnabled, setLocalLLMModel, setLocalLLMToolSupport, smallestCoworkModel, summarizeTranscriptTurns, toFileReference, toRetrievedDocuments, toToolCallInfos, useAnalyticsGlobalFilters, useAnalyticsScope, useAnalyticsSettings, useAuditLog, useCatalogSearch, useChartFilters, useChatPrivacy, useChatState, useCourseDetail, useCourseMetadata, useCourses, useCuaDriver, useDiscover, useEdxIframe, useFinancial, useIframeMessageHandler, useLlmDisplayName, useLlmProviderCatalogue, useLlmTraces, useLlmUsage, useLocalStorage, useMemory, useModelDownload, useMonetization, useOverview, usePlatformAuditLabels, usePlatformAuditLog, useProfileActivityStats, useProfileCredentials, useProfilePathways, useProfilePrograms, useProfileSkills, useProfileTimeSpent, usePrograms, useReports, useScopedMentorDbId, useScopedMentorId, useSelectedLocalModel, useSlashSkillPicker, useSlashSkills, useT, useTauri, useTimeTracking, useTopics, useTranscripts, useUserCourses, useUserMetadata, useUsers, useWebContainersI18n, useWebContainersLocale };
248299
+ export { ACCESS_COURSE_LABEL, ALL_CATEGORIES, AccessTimeHeatmap, AccessiblePaginate, AddMentorToProjectModal, AddSkillDialog, Admin, AdvancedTab, AgentConfigPrompts, AgentScopeLink, AgentSkills, AlertsTab, AnalyticsAgentPicker, AnalyticsAreaChart, AnalyticsAuditLogStats, AnalyticsBarChart, AnalyticsControlBar, AnalyticsCourseDetail, AnalyticsCourses, AnalyticsFinancialStats, AnalyticsGlobalFiltersProvider, AnalyticsLayout, AnalyticsLlmUsageStats, AnalyticsMemoryStats, AnalyticsMonetizationStats, AnalyticsNotice, AnalyticsOverview, AnalyticsPlatformAuditLog, AnalyticsProgramDetail, AnalyticsPrograms, AnalyticsReportDownload, AnalyticsReports, AnalyticsScopeProvider, AnalyticsSettingsProvider, AnalyticsTopicsStats, AnalyticsTraces, AnalyticsTranscriptsStats, AnalyticsUsersStats, AppleRestrictionModal, ApplyWizard, AuditLogChangesView, AuditLogJsonView, BUY_NOW_LABEL, BillingTab, CATALOGS, CHART_ORDINAL_RAMP, CHART_SERIES_COLORS, CHART_SINGLE_SERIES_COLOR, CREATE_AGENT_LABELS, CUA_DRIVER_REPO_URL, CUA_DRIVER_TAURI_COMMANDS, CUA_DRIVER_TAURI_EVENTS, CardInfoIcon, CategorizedDropdownMenu, ChartCardWrapper, ChartFiltersProvider, ChartLoading, ChartTooltipCard, ChatContext, ChatPrivacyToggle, ChatProvider, CompanyDialog, ConnectorManagementDialog, CopyButtonIcon, CourseAccessGuard, CourseCardSkeleton, CourseContentLoading, CourseOutline, CourseOutlineContext, CourseOutlineDrawer, CreateAgentForm, CreateAgentModal, CreateProjectModal, CreateWorkflowModal, CredentialBox, CredentialMiniBoxSkeleton, CredentialsList, CreditBalance, CustomDateRangePicker, CustomTooltip, DEFAULT_COWORK_REQUIRED_SIZE_GB, DEFAULT_LOCALE, DEFAULT_USER_IDENTITY_ORDER, DefaultEmptyBox, DeleteProjectModal, DeleteWorkflowModal, DiscoverContentCard, DiscoverFacetsFilter, DiscoverFilterDrawer, DocumentSidebar, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, ENROLL_NOW_COURSE_STARTING_SOON_LABEL, ENROLL_NOW_LABEL, EditAlertDialog, EducationBox, EducationDialog, EducationTab, EdxIframeContext, EmptyStats, ExperienceBox, ExperienceDialog, ExperienceTab, FacetFilterContext, Footer, GradebookTab, GroupsFilterDropdown, INVITATION_ONLY_LABEL, InstitutionDialog, IntegrationsTab, InviteUserContent, InviteUserDialog, InvitedUsersDialog, LOCAL_LLM_CHANGED_EVENT, LOCAL_MODELS, LlmModelBadge, Loader, LocalLLMTab, LocalModelsContent, LoginButton, MACOS_PERMISSIONS_COMMANDS, MEMORY_PAGE_SIZE, Markdown, MemoryAdminTab, MinimumMentorAlert, MonetizationTab, NotificationDisplay, NotificationDropdown, ONBOARDING_FIELD_TYPES, ONBOARDING_SECTORS, OnboardingField, OnboardingShell, OnboardingWizard, PLATFORM_AUDIT_DEEP_PAGING_THRESHOLD, PLATFORM_AUDIT_PAGE_SIZE, PaywallModal, PlacementExam, PlacementExamsDropdown, PlatformAuditLogDetailSheet, PlatformNavbar, PlatformNavbarSearch, Profile, ProfileTimeChart, ProgressDots, ProjectActionButtons, ProjectFilesModal, ProjectInstructionsModal, ProjectLandingPage, ProjectMentorsList, ProjectsPage, REQUEST_ACCESS_COURSE_STARTING_SOON_LABEL, REQUEST_ACCESS_LABEL, RankedBars, RenameProjectModal, ResumeBox, ResumeTab, RetrievedDocumentsButton, RichTextEditor, SERVICE_COLOR_ORDER, SUPPORTED_LOCALES, SandboxConfig, SearchableMultiSelect, SendNotificationDialog, SignupButton, SkeletonActivityStatBox, SkeletonAddSkillsLoading, SkeletonCreatePathwaySearchList, SkeletonDiscoverFilterBox, SkeletonEducationBox, SkeletonMultiplier, SkeletonPathwayBox, SkeletonProfileInfoCard, SkeletonSkillBox, SkillBox, SkillDetailModal, SkillLeaderboardChart, SkillsBox, SkillsList, SlashSkillPicker, SourceChip, Spinner, StatCard, StepHeader, SummerNoteTextEditor, TAURI_COMMANDS, TAURI_EVENTS, TRACES_PAGE_SIZE, TenantSwitcher, TimeFilter, TimeTrackingProvider, TimedExam, ToolCallIndicator, ToolDialogs, TopBanner, TranscriptFileCards, TranscriptRollupBadges, TranscriptTurnDetails, TrendSparkline, USER_ONBOARDING_FORM_SLUG, USER_ONBOARDING_FORM_VERSION, USER_ONBOARDING_SUBMISSION_SLUG, UpgradePackageModal, UserAvatar, UserOnboardingWizard, UserProfileDialog, UserProfileLink, Version, WebContainersI18nProvider, WorkflowSidebar, addBookmarksTab, areChartFiltersEqual, availablePlacementExams, buildOnboardingAgentPath, buildUserOnboardingFormMetadata, buildUserOnboardingSubmissionMetadata, coerceOnboardingAgent, coerceOnboardingAgents, coerceUserOnboardingForm, colorForRank, colorForSeries, conversationDocuments, emptyUserOnboardingForm, findLastResumeBlock, findOnboardingAgent, findSequentialParent, flattenVerticalBlocks, formatAuditTimestamp, formatCompactNumber, formatFileSize, formatLatencySeconds, formatResult, formatTimeZoneLabel, getCatalog, getFirstAvailableUnit, getFriendlyToolName, getLLMModelDisplayName, getLocalLLMModel, getLocalLLMToolSupport, getNextUnitIframe, getOrg, getParentBlockById, getParentsInfosFromSublessonId, getPreviousUnitIframe, getQueryLabel, getRandomCourseImage, getSectorById, getTenant, getUnitToIframe, getUserId, getUserName, granularityForFilter, hasDistinctName, hasOnboardingContent, humanizeAuditToken, humanizeFieldName, inBrowserPrint, inIframe, inferProviderKeysFromModel, initialCuaDriverInstallState, initialModelDownloadState, isCoworkEnabled, isEmailLike, isFileReference, isLlmUsageForbidden, isLlmUsageUnavailable, isLocalLLMEnabled, isPlatformNavbarCreditBalanceVisible, isSlashCommandToken, isTauriApp, isValidLocale, isValidTimeZone, llmUsageDateArgs, components as markdownComponents, modelSupportsCowork, onboardingPrimaryButtonClass, onboardingSecondaryButtonClass, readUserOnboardingForm, readUserOnboardingSubmission, readUserOnboardingSubmissions, resolveAuditTimeZone, resolveCreateAgentLabels, resolveUserIdentity, sanitizeCss, setCoworkEnabled, setLocalLLMEnabled, setLocalLLMModel, setLocalLLMToolSupport, smallestCoworkModel, summarizeTranscriptTurns, toFileReference, toRetrievedDocuments, toToolCallInfos, useAnalyticsGlobalFilters, useAnalyticsScope, useAnalyticsSettings, useAuditLog, useCatalogSearch, useChartFilters, useChatPrivacy, useChatState, useCourseDetail, useCourseMetadata, useCourses, useCuaDriver, useDiscover, useEdxIframe, useFinancial, useIframeMessageHandler, useLlmDisplayName, useLlmProviderCatalogue, useLlmTraces, useLlmUsage, useLocalStorage, useMemory, useModelDownload, useMonetization, useOverview, usePlatformAuditLabels, usePlatformAuditLog, useProfileActivityStats, useProfileCredentials, useProfilePathways, useProfilePrograms, useProfileSkills, useProfileTimeSpent, usePrograms, useReports, useScopedMentorDbId, useScopedMentorId, useSelectedLocalModel, useSlashSkillPicker, useSlashSkills, useT, useTauri, useTimeTracking, useTopics, useTranscripts, useUserCourses, useUserMetadata, useUsers, useWebContainersI18n, useWebContainersLocale };
248216
248300
  //# sourceMappingURL=index.esm.js.map