@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.
|
@@ -96692,6 +96692,7 @@ var analyticsAccessTimeHeatmap$3 = {
|
|
|
96692
96692
|
tooltipActiveUsers: "{count} active users"
|
|
96693
96693
|
};
|
|
96694
96694
|
var analyticsAnalyticsAuditLogStats$3 = {
|
|
96695
|
+
anonymous: "Anonymous",
|
|
96695
96696
|
scopeAgent: "Agent",
|
|
96696
96697
|
scopeAriaLabel: "Audit log scope",
|
|
96697
96698
|
scopePlatform: "Platform",
|
|
@@ -96820,6 +96821,7 @@ var analyticsAgentScopeLink$3 = {
|
|
|
96820
96821
|
scopeToAgent: "View analytics for {name}"
|
|
96821
96822
|
};
|
|
96822
96823
|
var analyticsAnalyticsMemoryStats$3 = {
|
|
96824
|
+
anonymous: "Anonymous",
|
|
96823
96825
|
noPermission: "You do not have permission to view user memories.",
|
|
96824
96826
|
scopeLabel: "Memory scope",
|
|
96825
96827
|
scopeMentor: "This Agent",
|
|
@@ -97034,6 +97036,7 @@ var analyticsAnalyticsTopicsStats$3 = {
|
|
|
97034
97036
|
topicsRankedFooter: "{shown} of {total} topics · ranked by message volume"
|
|
97035
97037
|
};
|
|
97036
97038
|
var analyticsAnalyticsTranscriptsStats$3 = {
|
|
97039
|
+
anonymous: "Anonymous",
|
|
97037
97040
|
justNow: "Just now",
|
|
97038
97041
|
minutesAgo: "{count} min ago",
|
|
97039
97042
|
hoursAgo: "{count} hour{count, plural, one {} other {s}} ago",
|
|
@@ -103973,6 +103976,7 @@ var analyticsAccessTimeHeatmap$2 = {
|
|
|
103973
103976
|
tooltipActiveUsers: "{count} utilisateurs actifs"
|
|
103974
103977
|
};
|
|
103975
103978
|
var analyticsAnalyticsAuditLogStats$2 = {
|
|
103979
|
+
anonymous: "Anonyme",
|
|
103976
103980
|
scopeAgent: "Agent",
|
|
103977
103981
|
scopeAriaLabel: "Portée du journal d'audit",
|
|
103978
103982
|
scopePlatform: "Plateforme",
|
|
@@ -104101,6 +104105,7 @@ var analyticsAgentScopeLink$2 = {
|
|
|
104101
104105
|
scopeToAgent: "Voir les analyses de {name}"
|
|
104102
104106
|
};
|
|
104103
104107
|
var analyticsAnalyticsMemoryStats$2 = {
|
|
104108
|
+
anonymous: "Anonyme",
|
|
104104
104109
|
noPermission: "Vous n'avez pas l'autorisation de consulter les mémoires des utilisateurs.",
|
|
104105
104110
|
scopeLabel: "Portée de la mémoire",
|
|
104106
104111
|
scopeMentor: "Cet agent",
|
|
@@ -104315,6 +104320,7 @@ var analyticsAnalyticsTopicsStats$2 = {
|
|
|
104315
104320
|
topicsRankedFooter: "{shown} sur {total} sujets · classés par volume de messages"
|
|
104316
104321
|
};
|
|
104317
104322
|
var analyticsAnalyticsTranscriptsStats$2 = {
|
|
104323
|
+
anonymous: "Anonyme",
|
|
104318
104324
|
justNow: "À l'instant",
|
|
104319
104325
|
minutesAgo: "Il y a {count} min",
|
|
104320
104326
|
hoursAgo: "Il y a {count} heure{count, plural, one {} other {s}}",
|
|
@@ -111254,6 +111260,7 @@ var analyticsAccessTimeHeatmap$1 = {
|
|
|
111254
111260
|
tooltipActiveUsers: "{count} usuarios activos"
|
|
111255
111261
|
};
|
|
111256
111262
|
var analyticsAnalyticsAuditLogStats$1 = {
|
|
111263
|
+
anonymous: "Anónimo",
|
|
111257
111264
|
scopeAgent: "Agente",
|
|
111258
111265
|
scopeAriaLabel: "Alcance del registro de auditoría",
|
|
111259
111266
|
scopePlatform: "Plataforma",
|
|
@@ -111382,6 +111389,7 @@ var analyticsAgentScopeLink$1 = {
|
|
|
111382
111389
|
scopeToAgent: "Ver analíticas de {name}"
|
|
111383
111390
|
};
|
|
111384
111391
|
var analyticsAnalyticsMemoryStats$1 = {
|
|
111392
|
+
anonymous: "Anónimo",
|
|
111385
111393
|
noPermission: "No tienes permiso para ver los recuerdos de los usuarios.",
|
|
111386
111394
|
scopeLabel: "Alcance de la memoria",
|
|
111387
111395
|
scopeMentor: "Este agente",
|
|
@@ -111596,6 +111604,7 @@ var analyticsAnalyticsTopicsStats$1 = {
|
|
|
111596
111604
|
topicsRankedFooter: "{shown} de {total} temas · ordenados por volumen de mensajes"
|
|
111597
111605
|
};
|
|
111598
111606
|
var analyticsAnalyticsTranscriptsStats$1 = {
|
|
111607
|
+
anonymous: "Anónimo",
|
|
111599
111608
|
justNow: "Ahora mismo",
|
|
111600
111609
|
minutesAgo: "Hace {count} min",
|
|
111601
111610
|
hoursAgo: "Hace {count} hora{count, plural, one {} other {s}}",
|
|
@@ -118535,6 +118544,7 @@ var analyticsAccessTimeHeatmap = {
|
|
|
118535
118544
|
tooltipActiveUsers: "{count} 位活跃用户"
|
|
118536
118545
|
};
|
|
118537
118546
|
var analyticsAnalyticsAuditLogStats = {
|
|
118547
|
+
anonymous: "匿名",
|
|
118538
118548
|
scopeAgent: "智能体",
|
|
118539
118549
|
scopeAriaLabel: "审计日志范围",
|
|
118540
118550
|
scopePlatform: "平台",
|
|
@@ -118663,6 +118673,7 @@ var analyticsAgentScopeLink = {
|
|
|
118663
118673
|
scopeToAgent: "查看 {name} 的分析"
|
|
118664
118674
|
};
|
|
118665
118675
|
var analyticsAnalyticsMemoryStats = {
|
|
118676
|
+
anonymous: "匿名",
|
|
118666
118677
|
noPermission: "您没有查看用户记忆的权限。",
|
|
118667
118678
|
scopeLabel: "记忆范围",
|
|
118668
118679
|
scopeMentor: "当前智能体",
|
|
@@ -118877,6 +118888,7 @@ var analyticsAnalyticsTopicsStats = {
|
|
|
118877
118888
|
topicsRankedFooter: "共 {total} 个主题,显示 {shown} 个 · 按消息量排序"
|
|
118878
118889
|
};
|
|
118879
118890
|
var analyticsAnalyticsTranscriptsStats = {
|
|
118891
|
+
anonymous: "匿名",
|
|
118880
118892
|
justNow: "刚刚",
|
|
118881
118893
|
minutesAgo: "{count} 分钟前",
|
|
118882
118894
|
hoursAgo: "{count} 小时前",
|
|
@@ -221826,7 +221838,7 @@ function RetrievedDocumentsButton({ sessionId = '', documents, className, label,
|
|
|
221826
221838
|
// Safe inside clickable transcript rows: the row must not react.
|
|
221827
221839
|
event.stopPropagation();
|
|
221828
221840
|
setIsOpen(true);
|
|
221829
|
-
}, "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 }) })] }) })] }));
|
|
221841
|
+
}, "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 }) })] }) })] }));
|
|
221830
221842
|
}
|
|
221831
221843
|
|
|
221832
221844
|
var COLLAPSIBLE_NAME = "Collapsible";
|
|
@@ -222288,6 +222300,11 @@ function useLlmDisplayName({ llmName, llmConfig, org, userId, mentorId, }) {
|
|
|
222288
222300
|
* white circle (the catalogue's artwork, or the bot icon when it has none)
|
|
222289
222301
|
* beside the model's display name. Read-only; used on admin transcripts to
|
|
222290
222302
|
* name the model a turn ran on.
|
|
222303
|
+
*
|
|
222304
|
+
* It sets no font size, weight or colour of its own and sizes the logo in
|
|
222305
|
+
* `em`, so it reads as one more fact in whatever row holds it — a `text-xs
|
|
222306
|
+
* text-gray-500` transcript card or the details panel — rather than as a
|
|
222307
|
+
* larger, bolder pill beside them. Pass `className` for the nav bar's look.
|
|
222291
222308
|
*/
|
|
222292
222309
|
function LlmModelBadge({ model, provider, tenantKey, mentorId, className, }) {
|
|
222293
222310
|
var _a, _b;
|
|
@@ -222308,9 +222325,9 @@ function LlmModelBadge({ model, provider, tenantKey, mentorId, className, }) {
|
|
|
222308
222325
|
const label = displayName || providerDetails.displayName;
|
|
222309
222326
|
if (!label)
|
|
222310
222327
|
return null;
|
|
222311
|
-
return (jsxs("span", { className: cn('inline-flex max-w-full items-center gap-
|
|
222328
|
+
return (jsxs("span", { className: cn('inline-flex max-w-full items-center gap-[0.5em] align-middle', className), title: providerDetails.displayName && providerDetails.displayName !== label
|
|
222312
222329
|
? `${label} · ${providerDetails.displayName}`
|
|
222313
|
-
: label, "data-testid": "llm-model-badge", children: [jsx("span", { className: "flex h-
|
|
222330
|
+
: 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 })] }));
|
|
222314
222331
|
}
|
|
222315
222332
|
|
|
222316
222333
|
/** SPAs whose users have coursework, so the profile leads with a Gradebook tab. */
|
|
@@ -222356,17 +222373,18 @@ function UserProfileDialog({ tenantKey, username, isOpen, onClose, customization
|
|
|
222356
222373
|
function UserProfileLink({ tenantKey, username, display, className, testId, customization, currentSPA, }) {
|
|
222357
222374
|
const t = useT();
|
|
222358
222375
|
const [isOpen, setIsOpen] = React__default.useState(false);
|
|
222376
|
+
// The text truncates inside an `inline-flex` box: an `inline-block` with
|
|
222377
|
+
// hidden overflow puts its baseline on its bottom edge, so the value would
|
|
222378
|
+
// ride above the "User:" label beside it.
|
|
222359
222379
|
if (!username) {
|
|
222360
|
-
|
|
222361
|
-
// an inline box takes its width from its own text.
|
|
222362
|
-
return (jsx("span", { className: cn('inline-block max-w-full truncate', className), "data-testid": testId, children: display }));
|
|
222380
|
+
return (jsx("span", { className: cn('inline-flex max-w-full', className), "data-testid": testId, children: jsx("span", { className: "min-w-0 truncate", children: display }) }));
|
|
222363
222381
|
}
|
|
222364
222382
|
return (jsxs(Fragment$1, { children: [jsx("button", { type: "button", onClick: (event) => {
|
|
222365
222383
|
event.stopPropagation();
|
|
222366
222384
|
setIsOpen(true);
|
|
222367
222385
|
},
|
|
222368
222386
|
// Rows that open on Enter/Space would otherwise swallow the key press.
|
|
222369
|
-
onKeyDown: (event) => event.stopPropagation(), className: cn('max-w-full cursor-pointer
|
|
222387
|
+
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 })] }));
|
|
222370
222388
|
}
|
|
222371
222389
|
|
|
222372
222390
|
const AdvancedPagination = ({ currentPage, totalPages, onPageChange, totalCount, itemsPerPage, itemLabel = 'items', variant = 'default', className, }) => {
|
|
@@ -259773,6 +259791,154 @@ AnalyticsScopeContext.Provider;
|
|
|
259773
259791
|
|
|
259774
259792
|
Array.from({ length: 24 }, (_, i) => i);
|
|
259775
259793
|
|
|
259794
|
+
/**
|
|
259795
|
+
* One place that decides how a user is shown.
|
|
259796
|
+
*
|
|
259797
|
+
* Backend payloads name their user in a dozen ways — `email` / `lti_email` /
|
|
259798
|
+
* `user_email`, `username` / `student` / `lti_username`, `name` /
|
|
259799
|
+
* `full_name` / `user_full_name`, or a nested `user` object — and most of
|
|
259800
|
+
* them can be empty, `null`, or a placeholder like "None". Every surface used
|
|
259801
|
+
* to pick through those on its own. `resolveUserIdentity()` takes whatever
|
|
259802
|
+
* the payload is and returns what to show, what to open a profile on, and
|
|
259803
|
+
* the avatar initial, so the rule lives here and can be tweaked once.
|
|
259804
|
+
*
|
|
259805
|
+
* Default rule: a real full name first (see {@link hasDistinctName}), else
|
|
259806
|
+
* email → username → the anonymous label.
|
|
259807
|
+
*/
|
|
259808
|
+
const DEFAULT_USER_IDENTITY_ORDER = ['email', 'name', 'username'];
|
|
259809
|
+
/** Order used when the payload carries a real name (see {@link hasDistinctName}). */
|
|
259810
|
+
const NAME_FIRST_ORDER = ['name', 'email', 'username'];
|
|
259811
|
+
/**
|
|
259812
|
+
* Lower-case letters and digits of any script, accents and punctuation dropped,
|
|
259813
|
+
* so "Conrad Mugabe" / "conrad.mugabe" and "José" / "jose" compare equal.
|
|
259814
|
+
*/
|
|
259815
|
+
const identityKey = (value) => (value !== null && value !== void 0 ? value : '')
|
|
259816
|
+
.normalize('NFKD')
|
|
259817
|
+
.replace(/[^\p{L}\p{N}]/gu, '')
|
|
259818
|
+
.toLowerCase();
|
|
259819
|
+
/**
|
|
259820
|
+
* Whether `name` is a real name rather than a restatement of the username.
|
|
259821
|
+
*
|
|
259822
|
+
* Many payloads fill the name field with the username ("conradmugabe" →
|
|
259823
|
+
* "Conrad Mugabe", "fayyaz_4_ibleducation_com"), which tells an admin nothing
|
|
259824
|
+
* the email does not. A name that matches none of the usernames on the record
|
|
259825
|
+
* is the most recognisable thing on it — including for LTI learners, whose
|
|
259826
|
+
* minted `<opaque-id>@edx-lti-1p3.com` address and username identify nobody.
|
|
259827
|
+
*/
|
|
259828
|
+
function hasDistinctName(name, ...usernames) {
|
|
259829
|
+
const key = identityKey(name);
|
|
259830
|
+
if (!key)
|
|
259831
|
+
return false;
|
|
259832
|
+
return usernames.every((username) => key !== identityKey(username));
|
|
259833
|
+
}
|
|
259834
|
+
const DEFAULT_ANONYMOUS_LABEL = 'Anonymous';
|
|
259835
|
+
/** Values backends emit instead of "nothing". Compared case-insensitively. */
|
|
259836
|
+
const PLACEHOLDERS = new Set([
|
|
259837
|
+
'',
|
|
259838
|
+
'none',
|
|
259839
|
+
'null',
|
|
259840
|
+
'undefined',
|
|
259841
|
+
'n/a',
|
|
259842
|
+
'na',
|
|
259843
|
+
'-',
|
|
259844
|
+
'anonymous',
|
|
259845
|
+
'anonymoususer',
|
|
259846
|
+
]);
|
|
259847
|
+
/**
|
|
259848
|
+
* `local@domain.tld` with no whitespace, checked with a single pass rather than
|
|
259849
|
+
* a backtracking pattern (CodeQL flags `[^@]+@[^@]+\.[^@]+` as polynomial on
|
|
259850
|
+
* adversarial input).
|
|
259851
|
+
*/
|
|
259852
|
+
const isEmailLike = (value) => {
|
|
259853
|
+
const text = value.trim();
|
|
259854
|
+
if (!text || /\s/.test(text))
|
|
259855
|
+
return false;
|
|
259856
|
+
const at = text.indexOf('@');
|
|
259857
|
+
if (at <= 0 || at !== text.lastIndexOf('@') || at === text.length - 1)
|
|
259858
|
+
return false;
|
|
259859
|
+
const domain = text.slice(at + 1);
|
|
259860
|
+
const dot = domain.indexOf('.');
|
|
259861
|
+
// A dot somewhere inside the domain, with something after the last one.
|
|
259862
|
+
return dot > 0 && !domain.endsWith('.');
|
|
259863
|
+
};
|
|
259864
|
+
/** Trimmed string, or undefined for blanks, non-strings and placeholders. */
|
|
259865
|
+
const clean = (value) => {
|
|
259866
|
+
if (typeof value !== 'string')
|
|
259867
|
+
return undefined;
|
|
259868
|
+
const trimmed = value.trim();
|
|
259869
|
+
return PLACEHOLDERS.has(trimmed.toLowerCase()) ? undefined : trimmed;
|
|
259870
|
+
};
|
|
259871
|
+
const firstOf = (...candidates) => {
|
|
259872
|
+
for (const candidate of candidates) {
|
|
259873
|
+
const value = clean(candidate);
|
|
259874
|
+
if (value)
|
|
259875
|
+
return value;
|
|
259876
|
+
}
|
|
259877
|
+
return undefined;
|
|
259878
|
+
};
|
|
259879
|
+
const nested = (source) => source.user && typeof source.user === 'object' ? source.user : undefined;
|
|
259880
|
+
/**
|
|
259881
|
+
* Resolve how a user should be displayed from any payload that names one.
|
|
259882
|
+
*
|
|
259883
|
+
* - `email`: `lti_email`, `email`, `user_email`, the nested `user`'s email —
|
|
259884
|
+
* or a username field that turns out to hold an email address.
|
|
259885
|
+
* - `username`: `lti_username`, `username`, `student`, `user_username`, the
|
|
259886
|
+
* nested `user`'s username, or a bare string `user` value (a numeric id is
|
|
259887
|
+
* ignored).
|
|
259888
|
+
* - `name`: `user_full_name`, `full_name`, `name`, `first_name last_name`, or
|
|
259889
|
+
* the nested `user`'s name.
|
|
259890
|
+
* - `profileUsername`: the first *platform* username (never an LTI claim).
|
|
259891
|
+
*
|
|
259892
|
+
* A string source is treated as an email when it looks like one, else as a
|
|
259893
|
+
* username. Placeholder strings ("None", "-", "anonymous"…) count as absent.
|
|
259894
|
+
*
|
|
259895
|
+
* The default order flips to name → email → username when the record carries a
|
|
259896
|
+
* real name (see {@link hasDistinctName}): "Joseph Oti" is more use to an admin
|
|
259897
|
+
* than his address, while a name that merely repeats the username is not, so
|
|
259898
|
+
* those records keep showing the email. An explicit `order` is always obeyed.
|
|
259899
|
+
*/
|
|
259900
|
+
function resolveUserIdentity(source, options = {}) {
|
|
259901
|
+
var _a, _b;
|
|
259902
|
+
const anonymousLabel = options.anonymousLabel || DEFAULT_ANONYMOUS_LABEL;
|
|
259903
|
+
const order = ((_a = options.order) === null || _a === void 0 ? void 0 : _a.length) ? options.order : DEFAULT_USER_IDENTITY_ORDER;
|
|
259904
|
+
const record = source && typeof source === 'object' ? source : { user: source !== null && source !== void 0 ? source : null };
|
|
259905
|
+
const inner = nested(record);
|
|
259906
|
+
// A bare `user` value is a username — unless it is a numeric id, which
|
|
259907
|
+
// names nobody: transcript rows carry `user: 1` beside `username: null`,
|
|
259908
|
+
// and showing "1" for that person is worse than "Anonymous".
|
|
259909
|
+
const bareString = typeof record.user === 'string' ? clean(record.user) : undefined;
|
|
259910
|
+
const bareUser = bareString && !/^\d+$/.test(bareString) ? bareString : undefined;
|
|
259911
|
+
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);
|
|
259912
|
+
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);
|
|
259913
|
+
let username = firstOf(record.lti_username, inner === null || inner === void 0 ? void 0 : inner.lti_username, platformUsername);
|
|
259914
|
+
const composed = [clean(record.first_name), clean(record.last_name)].filter(Boolean).join(' ');
|
|
259915
|
+
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);
|
|
259916
|
+
// A bare string that looks like an email is an email, and so is a
|
|
259917
|
+
// "username" field that actually carries one.
|
|
259918
|
+
if (!email && bareUser && isEmailLike(bareUser))
|
|
259919
|
+
email = bareUser;
|
|
259920
|
+
if (!email && username && isEmailLike(username)) {
|
|
259921
|
+
email = username;
|
|
259922
|
+
username = undefined;
|
|
259923
|
+
}
|
|
259924
|
+
const facts = { email, username, name };
|
|
259925
|
+
// Every username on the record counts: the platform one a profile opens on
|
|
259926
|
+
// and the LTI claim that would be displayed.
|
|
259927
|
+
const labelOrder = !((_b = options.order) === null || _b === void 0 ? void 0 : _b.length) && hasDistinctName(name, platformUsername, username)
|
|
259928
|
+
? NAME_FIRST_ORDER
|
|
259929
|
+
: order;
|
|
259930
|
+
const label = labelOrder.map((field) => facts[field]).find(Boolean);
|
|
259931
|
+
return {
|
|
259932
|
+
label: label !== null && label !== void 0 ? label : anonymousLabel,
|
|
259933
|
+
email,
|
|
259934
|
+
username,
|
|
259935
|
+
name,
|
|
259936
|
+
profileUsername: platformUsername,
|
|
259937
|
+
initial: (label !== null && label !== void 0 ? label : anonymousLabel).charAt(0).toUpperCase() || 'A',
|
|
259938
|
+
isAnonymous: !label,
|
|
259939
|
+
};
|
|
259940
|
+
}
|
|
259941
|
+
|
|
259776
259942
|
const asArray = (value) => (Array.isArray(value) ? value : []);
|
|
259777
259943
|
const hasEntries = (value) => !!value && typeof value === 'object' && !Array.isArray(value) && Object.keys(value).length > 0;
|
|
259778
259944
|
/** Rollup counts as the conversation-list endpoint reports them: numbers, numeric strings or `null`. */
|
|
@@ -260084,7 +260250,7 @@ function SectionHeading({ icon, children }) {
|
|
|
260084
260250
|
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] }));
|
|
260085
260251
|
}
|
|
260086
260252
|
const MODEL_KEYS = new Set(['llm_model', 'llm_provider']);
|
|
260087
|
-
function MetadataSection({ metadata, renderModel, }) {
|
|
260253
|
+
function MetadataSection({ metadata, renderModel, tenantKey, mentorId, }) {
|
|
260088
260254
|
var _a, _b;
|
|
260089
260255
|
const t = useT();
|
|
260090
260256
|
const labelFor = useFieldLabels();
|
|
@@ -260092,7 +260258,9 @@ function MetadataSection({ metadata, renderModel, }) {
|
|
|
260092
260258
|
const model = ((_a = metadata.llm_model) !== null && _a !== void 0 ? _a : '').trim() || undefined;
|
|
260093
260259
|
const provider = ((_b = metadata.llm_provider) !== null && _b !== void 0 ? _b : '').trim() || undefined;
|
|
260094
260260
|
const hasModel = !!(model || provider);
|
|
260095
|
-
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:
|
|
260261
|
+
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
|
|
260262
|
+
? renderModel({ model, provider })
|
|
260263
|
+
: defaultRenderModel({ model, provider, tenantKey, mentorId }) })), jsx(DetailRows, { entries: rest, labelFor: labelFor })] }));
|
|
260096
260264
|
}
|
|
260097
260265
|
function RequestContextSection({ requestContext }) {
|
|
260098
260266
|
const t = useT();
|
|
@@ -260107,7 +260275,7 @@ function RequestContextSection({ requestContext }) {
|
|
|
260107
260275
|
*/
|
|
260108
260276
|
const defaultRenderDocuments = (documents) => (jsx(RetrievedDocumentsButton, { documents: toRetrievedDocuments(documents) }));
|
|
260109
260277
|
const defaultRenderToolCalls = (toolCalls) => (jsx(ToolCallIndicator, { toolCalls: toToolCallInfos(toolCalls), showResults: true }));
|
|
260110
|
-
const defaultRenderModel = ({ model, provider }) =>
|
|
260278
|
+
const defaultRenderModel = ({ model, provider, tenantKey, mentorId, }) => jsx(LlmModelBadge, { model: model, provider: provider, tenantKey: tenantKey, mentorId: mentorId });
|
|
260111
260279
|
const defaultRenderFiles = (files) => (jsx(TranscriptFileCards, { files: files }));
|
|
260112
260280
|
/**
|
|
260113
260281
|
* Collapsible "Sources / Tools / Metadata" panel for one AI turn of an admin
|
|
@@ -260117,7 +260285,7 @@ const defaultRenderFiles = (files) => (jsx(TranscriptFileCards, { files: files }
|
|
|
260117
260285
|
* renders nothing at all when every field is null or empty, so it is safe to
|
|
260118
260286
|
* drop under every AI bubble.
|
|
260119
260287
|
*/
|
|
260120
|
-
function TranscriptTurnDetails({ turn, className, defaultOpen = false, renderDocuments, renderToolCalls, renderModel, renderFiles, }) {
|
|
260288
|
+
function TranscriptTurnDetails({ turn, className, defaultOpen = false, renderDocuments, renderToolCalls, renderModel, renderFiles, tenantKey, mentorId, }) {
|
|
260121
260289
|
const t = useT();
|
|
260122
260290
|
const labelFor = useFieldLabels();
|
|
260123
260291
|
const [open, setOpen] = React__default.useState(defaultOpen);
|
|
@@ -260131,7 +260299,7 @@ function TranscriptTurnDetails({ turn, className, defaultOpen = false, renderDoc
|
|
|
260131
260299
|
const requestContext = hasEntries(turn === null || turn === void 0 ? void 0 : turn.request_context) ? turn === null || turn === void 0 ? void 0 : turn.request_context : null;
|
|
260132
260300
|
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
|
|
260133
260301
|
? t('analyticsTranscriptTurnDetails.hideDetails')
|
|
260134
|
-
: 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 })] })] }) }));
|
|
260302
|
+
: 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 })] })] }) }));
|
|
260135
260303
|
}
|
|
260136
260304
|
/**
|
|
260137
260305
|
* "Documents · N" / "Tools · N" chips for a conversation row, from the
|
|
@@ -260147,118 +260315,6 @@ function TranscriptRollupBadges({ documentsCount, toolCallsCount, className, })
|
|
|
260147
260315
|
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 })] }))] }));
|
|
260148
260316
|
}
|
|
260149
260317
|
|
|
260150
|
-
/**
|
|
260151
|
-
* One place that decides how a user is shown.
|
|
260152
|
-
*
|
|
260153
|
-
* Backend payloads name their user in a dozen ways — `email` / `lti_email` /
|
|
260154
|
-
* `user_email`, `username` / `student` / `lti_username`, `name` /
|
|
260155
|
-
* `full_name` / `user_full_name`, or a nested `user` object — and most of
|
|
260156
|
-
* them can be empty, `null`, or a placeholder like "None". Every surface used
|
|
260157
|
-
* to pick through those on its own. `resolveUserIdentity()` takes whatever
|
|
260158
|
-
* the payload is and returns what to show, what to open a profile on, and
|
|
260159
|
-
* the avatar initial, so the rule lives here and can be tweaked once.
|
|
260160
|
-
*
|
|
260161
|
-
* Default rule: email → full name → username → the anonymous label.
|
|
260162
|
-
*/
|
|
260163
|
-
const DEFAULT_USER_IDENTITY_ORDER = ['email', 'name', 'username'];
|
|
260164
|
-
const DEFAULT_ANONYMOUS_LABEL = 'Anonymous';
|
|
260165
|
-
/** Values backends emit instead of "nothing". Compared case-insensitively. */
|
|
260166
|
-
const PLACEHOLDERS = new Set([
|
|
260167
|
-
'',
|
|
260168
|
-
'none',
|
|
260169
|
-
'null',
|
|
260170
|
-
'undefined',
|
|
260171
|
-
'n/a',
|
|
260172
|
-
'na',
|
|
260173
|
-
'-',
|
|
260174
|
-
'anonymous',
|
|
260175
|
-
'anonymoususer',
|
|
260176
|
-
]);
|
|
260177
|
-
/**
|
|
260178
|
-
* `local@domain.tld` with no whitespace, checked with a single pass rather than
|
|
260179
|
-
* a backtracking pattern (CodeQL flags `[^@]+@[^@]+\.[^@]+` as polynomial on
|
|
260180
|
-
* adversarial input).
|
|
260181
|
-
*/
|
|
260182
|
-
const isEmailLike = (value) => {
|
|
260183
|
-
const text = value.trim();
|
|
260184
|
-
if (!text || /\s/.test(text))
|
|
260185
|
-
return false;
|
|
260186
|
-
const at = text.indexOf('@');
|
|
260187
|
-
if (at <= 0 || at !== text.lastIndexOf('@') || at === text.length - 1)
|
|
260188
|
-
return false;
|
|
260189
|
-
const domain = text.slice(at + 1);
|
|
260190
|
-
const dot = domain.indexOf('.');
|
|
260191
|
-
// A dot somewhere inside the domain, with something after the last one.
|
|
260192
|
-
return dot > 0 && !domain.endsWith('.');
|
|
260193
|
-
};
|
|
260194
|
-
/** Trimmed string, or undefined for blanks, non-strings and placeholders. */
|
|
260195
|
-
const clean = (value) => {
|
|
260196
|
-
if (typeof value !== 'string')
|
|
260197
|
-
return undefined;
|
|
260198
|
-
const trimmed = value.trim();
|
|
260199
|
-
return PLACEHOLDERS.has(trimmed.toLowerCase()) ? undefined : trimmed;
|
|
260200
|
-
};
|
|
260201
|
-
const firstOf = (...candidates) => {
|
|
260202
|
-
for (const candidate of candidates) {
|
|
260203
|
-
const value = clean(candidate);
|
|
260204
|
-
if (value)
|
|
260205
|
-
return value;
|
|
260206
|
-
}
|
|
260207
|
-
return undefined;
|
|
260208
|
-
};
|
|
260209
|
-
const nested = (source) => source.user && typeof source.user === 'object' ? source.user : undefined;
|
|
260210
|
-
/**
|
|
260211
|
-
* Resolve how a user should be displayed from any payload that names one.
|
|
260212
|
-
*
|
|
260213
|
-
* - `email`: `lti_email`, `email`, `user_email`, the nested `user`'s email —
|
|
260214
|
-
* or a username field that turns out to hold an email address.
|
|
260215
|
-
* - `username`: `lti_username`, `username`, `student`, `user_username`, the
|
|
260216
|
-
* nested `user`'s username, or a bare string/number `user` value.
|
|
260217
|
-
* - `name`: `user_full_name`, `full_name`, `name`, `first_name last_name`, or
|
|
260218
|
-
* the nested `user`'s name.
|
|
260219
|
-
* - `profileUsername`: the first *platform* username (never an LTI claim).
|
|
260220
|
-
*
|
|
260221
|
-
* A string source is treated as an email when it looks like one, else as a
|
|
260222
|
-
* username. Placeholder strings ("None", "-", "anonymous"…) count as absent.
|
|
260223
|
-
*/
|
|
260224
|
-
function resolveUserIdentity(source, options = {}) {
|
|
260225
|
-
var _a;
|
|
260226
|
-
const anonymousLabel = options.anonymousLabel || DEFAULT_ANONYMOUS_LABEL;
|
|
260227
|
-
const order = ((_a = options.order) === null || _a === void 0 ? void 0 : _a.length) ? options.order : DEFAULT_USER_IDENTITY_ORDER;
|
|
260228
|
-
const record = source && typeof source === 'object' ? source : { user: source !== null && source !== void 0 ? source : null };
|
|
260229
|
-
const inner = nested(record);
|
|
260230
|
-
// A bare `user` value is an id or username; numeric ids are still shown.
|
|
260231
|
-
const bareUser = typeof record.user === 'number' && Number.isFinite(record.user)
|
|
260232
|
-
? String(record.user)
|
|
260233
|
-
: typeof record.user === 'string'
|
|
260234
|
-
? clean(record.user)
|
|
260235
|
-
: undefined;
|
|
260236
|
-
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);
|
|
260237
|
-
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);
|
|
260238
|
-
let username = firstOf(record.lti_username, inner === null || inner === void 0 ? void 0 : inner.lti_username, platformUsername);
|
|
260239
|
-
const composed = [clean(record.first_name), clean(record.last_name)].filter(Boolean).join(' ');
|
|
260240
|
-
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);
|
|
260241
|
-
// A bare string that looks like an email is an email, and so is a
|
|
260242
|
-
// "username" field that actually carries one.
|
|
260243
|
-
if (!email && bareUser && isEmailLike(bareUser))
|
|
260244
|
-
email = bareUser;
|
|
260245
|
-
if (!email && username && isEmailLike(username)) {
|
|
260246
|
-
email = username;
|
|
260247
|
-
username = undefined;
|
|
260248
|
-
}
|
|
260249
|
-
const facts = { email, username, name };
|
|
260250
|
-
const label = order.map((field) => facts[field]).find(Boolean);
|
|
260251
|
-
return {
|
|
260252
|
-
label: label !== null && label !== void 0 ? label : anonymousLabel,
|
|
260253
|
-
email,
|
|
260254
|
-
username,
|
|
260255
|
-
name,
|
|
260256
|
-
profileUsername: platformUsername,
|
|
260257
|
-
initial: (label !== null && label !== void 0 ? label : anonymousLabel).charAt(0).toUpperCase() || 'A',
|
|
260258
|
-
isAnonymous: !label,
|
|
260259
|
-
};
|
|
260260
|
-
}
|
|
260261
|
-
|
|
260262
260318
|
const AnalyticsSettingsContext = createContext({});
|
|
260263
260319
|
AnalyticsSettingsContext.Provider;
|
|
260264
260320
|
|
|
@@ -279113,7 +279169,7 @@ function AgentHistoryTab({ renderMessageContent, PaginationComponent, onExport,
|
|
|
279113
279169
|
// Use mentor summaries data for rating and tags
|
|
279114
279170
|
const averageRating = (mentorSummaries === null || mentorSummaries === void 0 ? void 0 : mentorSummaries.rating) || 0;
|
|
279115
279171
|
const topicTags = (mentorSummaries === null || mentorSummaries === void 0 ? void 0 : mentorSummaries.tags) || [];
|
|
279116
|
-
// Who the previewed conversation belongs to (
|
|
279172
|
+
// Who the previewed conversation belongs to (the shared identity rule).
|
|
279117
279173
|
const identityOptions = { anonymousLabel: labels.conversation.anonymous };
|
|
279118
279174
|
const selectedOwner = resolveUserIdentity(selectedConversation, identityOptions);
|
|
279119
279175
|
const previewOwner = resolveUserIdentity(previewConversationContent, identityOptions);
|
|
@@ -279175,11 +279231,11 @@ function AgentHistoryTab({ renderMessageContent, PaginationComponent, onExport,
|
|
|
279175
279231
|
jsx(RetrievedDocumentsButton, { documents: documents, label: labels.conversation.documentsChip(rollup.documentsCount), className: "h-6 gap-1 rounded-md border-transparent bg-blue-50 px-2 text-xs font-normal text-blue-700 hover:bg-blue-100 [&_svg]:h-3 [&_svg]:w-3" })), jsx(TranscriptRollupBadges, { documentsCount: 0, toolCallsCount: rollup.toolCallsCount })] }))] }), jsx("div", { className: "flex items-center gap-2 text-sm text-gray-600", children: jsx(ChevronRight, { className: "h-4 w-4" }) })] }, conversation.id));
|
|
279176
279232
|
}) }), totalPages > 1 && PaginationComponent && (jsx("div", { className: "my-2", children: jsx(PaginationComponent, { currentPage: currentPage, totalPages: totalPages, onPageChange: handlePageChange, disabled: isChatHistoryFetching || isChatHistoryLoading, disableNumberedButtons: isMobile }) }))] }), jsx("div", { className: "scrollbar-hide hidden max-h-[500px] flex-col overflow-y-auto rounded-lg border bg-white p-6 shadow-sm md:flex", tabIndex: 0, role: "region", "aria-label": t('tabsHistoryTab.conversationPreviewLabel'), children: selectedConversation && previewConversationContent ? (jsxs(Fragment$1, { children: [jsxs("div", { className: "mb-4", children: [jsx("h3", { className: "mb-1 text-base font-semibold text-gray-700", children: ((_m = selectedConversation.messages[0]) === null || _m === void 0 ? void 0 : _m.human) || labels.conversation.title }), jsx("span", { className: "text-sm text-gray-500", children: format$1(new Date(selectedConversation.inserted_at), "MMM dd, yyyy 'at' h:mm a") }), jsx(RetrievedDocumentsButton, { sessionId: selectedConversation.id, documents: conversationDocuments(selectedConversation.messages).length > 0
|
|
279177
279233
|
? conversationDocuments(selectedConversation.messages)
|
|
279178
|
-
: undefined, className: "mt-2" })] }), jsxs("div", { className: "space-y-6", children: [selectedConversation.messages.map((message, index) => (jsxs("div", { className: "space-y-4", children: [jsxs("div", { className: "flex items-start gap-3", children: [jsx("div", { className: "flex h-8 w-8 flex-shrink-0 items-center justify-center rounded-full bg-blue-100", children: jsx("span", { className: "text-sm font-medium text-blue-600", children: selectedOwner.initial }) }), jsxs("div", { className: "flex-1", children: [jsx("div", { className: "font-medium text-gray-700", children: jsx(UserProfileLink, { tenantKey: tenantKey, username: selectedOwner.profileUsername, display: selectedOwner.label, currentSPA: currentSPA }) }), jsx("p", { className: "mt-1 text-sm whitespace-pre-line text-gray-500", children: message.human }), jsx(TranscriptFileCards, { files: attachmentCards(message.human_files) })] })] }), jsxs("div", { className: "flex items-start gap-3 border-t border-gray-200 pt-4", children: [jsx("div", { className: "flex h-8 w-8 flex-shrink-0 items-center justify-center rounded-full bg-gray-100", children: jsx("span", { className: "text-sm font-medium text-gray-600", children: t('tabsHistoryTab.aiAvatarLabel') }) }), jsxs("div", { className: "flex-1", children: [jsx("div", { className: "font-medium text-gray-700", children: labels.conversation.aiAgent }), jsx("div", { className: "mt-1 text-sm text-gray-500", children: renderAiContent(message.ai) }), jsx(TranscriptFileCards, { files: attachmentCards(message.ai_files) }), jsx(TranscriptTurnDetails, { turn: message })] })] })] }, index))), (selectedConversation === null || selectedConversation === void 0 ? void 0 : selectedConversation.memory_tracked) && (jsxs("div", { className: "border-t border-gray-200 pt-4", children: [jsxs(Button$1, { variant: "outline", onClick: () => setShowConversationMemory(!showConversationMemory), className: "flex w-full items-center justify-center gap-2 border-gray-200 text-gray-700 hover:bg-gray-50", children: [jsx(Brain, { className: "h-4 w-4" }), showConversationMemory ? labels.memory.hide : labels.memory.show] }), showConversationMemory && (jsx("div", { className: "mt-4 space-y-6", children: isConversationMemoryLoading ? (jsx("div", { className: "flex items-center justify-center py-4", children: jsx(Spinner, {}) })) : ((_o = conversationMemory === null || conversationMemory === void 0 ? void 0 : conversationMemory.entries) === null || _o === void 0 ? void 0 : _o.length) ? (jsx(Fragment$1, { children: conversationMemory.entries.map((entry, index) => (jsxs("div", { children: [jsx("h4", { className: "mb-3 font-semibold text-gray-900", children: entry.key }), jsx("ul", { className: "space-y-2", children: jsx("li", { className: "flex items-start gap-2 text-sm text-gray-600", children: entry.value }) })] }, index))) })) : (jsx("div", { className: "text-sm text-gray-500", children: labels.memory.notAvailable })) }))] }))] })] })) : (jsx("div", { className: "flex h-full items-center justify-center text-gray-500", children: labels.conversation.selectPrompt })) })] }))] }) }), jsx(Dialog, { open: isConversationPreviewModalOpen, onOpenChange: setIsConversationPreviewModalOpen, children: jsxs(DialogContent, { className: "scrollbar-hide mx-auto max-h-[80vh] max-w-[90vw] overflow-x-hidden overflow-y-auto", children: [jsx(DialogHeader, { children: jsx(DialogTitle, { className: "text-lg font-semibold text-gray-900", children: previewConversationContent
|
|
279234
|
+
: undefined, className: "mt-2" })] }), jsxs("div", { className: "space-y-6", children: [selectedConversation.messages.map((message, index) => (jsxs("div", { className: "space-y-4", children: [jsxs("div", { className: "flex items-start gap-3", children: [jsx("div", { className: "flex h-8 w-8 flex-shrink-0 items-center justify-center rounded-full bg-blue-100", children: jsx("span", { className: "text-sm font-medium text-blue-600", children: selectedOwner.initial }) }), jsxs("div", { className: "flex-1", children: [jsx("div", { className: "font-medium text-gray-700", children: jsx(UserProfileLink, { tenantKey: tenantKey, username: selectedOwner.profileUsername, display: selectedOwner.label, currentSPA: currentSPA }) }), jsx("p", { className: "mt-1 text-sm whitespace-pre-line text-gray-500", children: message.human }), jsx(TranscriptFileCards, { files: attachmentCards(message.human_files) })] })] }), jsxs("div", { className: "flex items-start gap-3 border-t border-gray-200 pt-4", children: [jsx("div", { className: "flex h-8 w-8 flex-shrink-0 items-center justify-center rounded-full bg-gray-100", children: jsx("span", { className: "text-sm font-medium text-gray-600", children: t('tabsHistoryTab.aiAvatarLabel') }) }), jsxs("div", { className: "flex-1", children: [jsx("div", { className: "font-medium text-gray-700", children: labels.conversation.aiAgent }), jsx("div", { className: "mt-1 text-sm text-gray-500", children: renderAiContent(message.ai) }), jsx(TranscriptFileCards, { files: attachmentCards(message.ai_files) }), jsx(TranscriptTurnDetails, { turn: message, tenantKey: tenantKey, mentorId: mentorId })] })] })] }, index))), (selectedConversation === null || selectedConversation === void 0 ? void 0 : selectedConversation.memory_tracked) && (jsxs("div", { className: "border-t border-gray-200 pt-4", children: [jsxs(Button$1, { variant: "outline", onClick: () => setShowConversationMemory(!showConversationMemory), className: "flex w-full items-center justify-center gap-2 border-gray-200 text-gray-700 hover:bg-gray-50", children: [jsx(Brain, { className: "h-4 w-4" }), showConversationMemory ? labels.memory.hide : labels.memory.show] }), showConversationMemory && (jsx("div", { className: "mt-4 space-y-6", children: isConversationMemoryLoading ? (jsx("div", { className: "flex items-center justify-center py-4", children: jsx(Spinner, {}) })) : ((_o = conversationMemory === null || conversationMemory === void 0 ? void 0 : conversationMemory.entries) === null || _o === void 0 ? void 0 : _o.length) ? (jsx(Fragment$1, { children: conversationMemory.entries.map((entry, index) => (jsxs("div", { children: [jsx("h4", { className: "mb-3 font-semibold text-gray-900", children: entry.key }), jsx("ul", { className: "space-y-2", children: jsx("li", { className: "flex items-start gap-2 text-sm text-gray-600", children: entry.value }) })] }, index))) })) : (jsx("div", { className: "text-sm text-gray-500", children: labels.memory.notAvailable })) }))] }))] })] })) : (jsx("div", { className: "flex h-full items-center justify-center text-gray-500", children: labels.conversation.selectPrompt })) })] }))] }) }), jsx(Dialog, { open: isConversationPreviewModalOpen, onOpenChange: setIsConversationPreviewModalOpen, children: jsxs(DialogContent, { className: "scrollbar-hide mx-auto max-h-[80vh] max-w-[90vw] overflow-x-hidden overflow-y-auto", children: [jsx(DialogHeader, { children: jsx(DialogTitle, { className: "text-lg font-semibold text-gray-900", children: previewConversationContent
|
|
279179
279235
|
? ((_p = previewConversationContent.messages[0]) === null || _p === void 0 ? void 0 : _p.human) || labels.conversation.title
|
|
279180
279236
|
: labels.conversation.title }) }), jsx("div", { className: "mx-auto max-w-full overflow-x-hidden", children: previewConversationContent && (jsxs("div", { className: "scrollbar-hide space-y-4 overflow-y-auto", children: [jsx("div", { className: "text-sm text-gray-500", children: format$1(new Date(previewConversationContent.inserted_at), "MMM dd, yyyy 'at' h:mm a") }), jsx(RetrievedDocumentsButton, { sessionId: previewConversationContent.id, documents: conversationDocuments(previewConversationContent.messages).length > 0
|
|
279181
279237
|
? conversationDocuments(previewConversationContent.messages)
|
|
279182
|
-
: undefined }), previewConversationContent.messages.map((message, index) => (jsxs("div", { className: "space-y-4", children: [jsxs("div", { className: "flex items-start gap-3", children: [jsx("div", { className: "flex h-8 w-8 flex-shrink-0 items-center justify-center rounded-full bg-blue-100", children: jsx("span", { className: "text-sm font-medium text-blue-600", children: previewOwner.initial }) }), jsxs("div", { className: "overflow-x-hidden", children: [jsx("div", { className: "truncate font-medium text-gray-900", children: jsx(UserProfileLink, { tenantKey: tenantKey, username: previewOwner.profileUsername, display: previewOwner.label, currentSPA: currentSPA }) }), jsx("p", { className: "mt-1 text-sm whitespace-pre-line text-gray-900", children: message.human }), jsx(TranscriptFileCards, { files: attachmentCards(message.human_files) })] })] }), jsxs("div", { className: "flex items-start gap-3 border-t border-gray-200 pt-4", children: [jsx("div", { className: "flex h-8 w-8 flex-shrink-0 items-center justify-center rounded-full bg-gray-100", children: jsx("span", { className: "text-sm font-medium text-gray-600", children: t('tabsHistoryTab.aiAvatarLabel') }) }), jsxs("div", { className: "overflow-x-hidden", children: [jsx("div", { className: "font-medium text-gray-900", children: labels.conversation.aiAgent }), jsx("div", { className: "mt-1 text-sm text-gray-900", children: renderAiContent(message.ai) }), jsx(TranscriptFileCards, { files: attachmentCards(message.ai_files) }), jsx(TranscriptTurnDetails, { turn: message })] })] })] }, index)))] })) })] }) })] }));
|
|
279238
|
+
: undefined }), previewConversationContent.messages.map((message, index) => (jsxs("div", { className: "space-y-4", children: [jsxs("div", { className: "flex items-start gap-3", children: [jsx("div", { className: "flex h-8 w-8 flex-shrink-0 items-center justify-center rounded-full bg-blue-100", children: jsx("span", { className: "text-sm font-medium text-blue-600", children: previewOwner.initial }) }), jsxs("div", { className: "overflow-x-hidden", children: [jsx("div", { className: "truncate font-medium text-gray-900", children: jsx(UserProfileLink, { tenantKey: tenantKey, username: previewOwner.profileUsername, display: previewOwner.label, currentSPA: currentSPA }) }), jsx("p", { className: "mt-1 text-sm whitespace-pre-line text-gray-900", children: message.human }), jsx(TranscriptFileCards, { files: attachmentCards(message.human_files) })] })] }), jsxs("div", { className: "flex items-start gap-3 border-t border-gray-200 pt-4", children: [jsx("div", { className: "flex h-8 w-8 flex-shrink-0 items-center justify-center rounded-full bg-gray-100", children: jsx("span", { className: "text-sm font-medium text-gray-600", children: t('tabsHistoryTab.aiAvatarLabel') }) }), jsxs("div", { className: "overflow-x-hidden", children: [jsx("div", { className: "font-medium text-gray-900", children: labels.conversation.aiAgent }), jsx("div", { className: "mt-1 text-sm text-gray-900", children: renderAiContent(message.ai) }), jsx(TranscriptFileCards, { files: attachmentCards(message.ai_files) }), jsx(TranscriptTurnDetails, { turn: message, tenantKey: tenantKey, mentorId: mentorId })] })] })] }, index)))] })) })] }) })] }));
|
|
279183
279239
|
}
|
|
279184
279240
|
|
|
279185
279241
|
const ANONYMOUS_USERNAME = 'anonymous';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@iblai/iblai-js",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.19.0",
|
|
4
4
|
"description": "Unified JavaScript SDK for IBL.ai — re-exports data-layer, web-containers, and web-utils under a single package",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"engines": {
|
|
@@ -76,10 +76,10 @@
|
|
|
76
76
|
"axios": "1.13.6",
|
|
77
77
|
"dotenv": "16.6.1",
|
|
78
78
|
"winston": "3.19.0",
|
|
79
|
-
"@iblai/
|
|
80
|
-
"@iblai/
|
|
81
|
-
"@iblai/
|
|
82
|
-
"@iblai/web-utils": "2.
|
|
79
|
+
"@iblai/mcp": "1.17.0",
|
|
80
|
+
"@iblai/web-containers": "1.26.0",
|
|
81
|
+
"@iblai/data-layer": "1.19.1",
|
|
82
|
+
"@iblai/web-utils": "2.5.0"
|
|
83
83
|
},
|
|
84
84
|
"peerDependencies": {
|
|
85
85
|
"@iblai/iblai-api": "4.166.0-ai",
|