@iblai/iblai-js 2.10.3 → 2.11.1

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.
@@ -2132,7 +2132,7 @@ var analyticsAnalyticsOverview$3 = {
2132
2132
  topicsChartDescription: "The most discussed topics, ranked by how many messages each one generated.",
2133
2133
  activeUsersChartDescription: "Unique active users per day, showing how engagement changes over time.",
2134
2134
  llmSpend: "LLM spend",
2135
- llmSpendDescription: "Raw cost of every traced LLM call in the selected period, from the trace store. Billing totals live on the Cost & LLM tab.",
2135
+ llmSpendDescription: "Raw cost of every traced LLM call in the selected period, from the trace store. Billing totals live on the Cost tab.",
2136
2136
  allTopics: "All topics",
2137
2137
  topicsRankedFooter: "{shown} of {total} topics · ranked by message volume"
2138
2138
  };
@@ -8089,7 +8089,7 @@ var analyticsChartCard$3 = {
8089
8089
  adjustRangeHint: "This card only — the page range stays where it is."
8090
8090
  };
8091
8091
  var analyticsCostTabs$3 = {
8092
- ariaLabel: "Cost & LLM sections",
8092
+ ariaLabel: "Cost sections",
8093
8093
  spend: "Spend",
8094
8094
  usage: "Usage & latency",
8095
8095
  traces: "Traces"
@@ -9280,7 +9280,7 @@ var analyticsAnalyticsOverview$2 = {
9280
9280
  topicsChartDescription: "Les sujets les plus abordés, classés selon le nombre de messages générés.",
9281
9281
  activeUsersChartDescription: "Utilisateurs actifs uniques par jour, pour suivre l’évolution de l’engagement.",
9282
9282
  llmSpend: "Dépenses LLM",
9283
- llmSpendDescription: "Coût brut de chaque appel LLM tracé sur la période sélectionnée, issu du magasin de traces. Les totaux de facturation sont dans l'onglet Coûts et LLM.",
9283
+ llmSpendDescription: "Coût brut de chaque appel LLM tracé sur la période sélectionnée, issu du magasin de traces. Les totaux de facturation sont dans l'onglet Coûts.",
9284
9284
  allTopics: "Tous les sujets",
9285
9285
  topicsRankedFooter: "{shown} sur {total} sujets · classés par volume de messages"
9286
9286
  };
@@ -15237,7 +15237,7 @@ var analyticsChartCard$2 = {
15237
15237
  adjustRangeHint: "Cette carte uniquement — la plage de la page reste inchangée."
15238
15238
  };
15239
15239
  var analyticsCostTabs$2 = {
15240
- ariaLabel: "Sections Coûts et LLM",
15240
+ ariaLabel: "Sections Coûts",
15241
15241
  spend: "Dépenses",
15242
15242
  usage: "Utilisation et latence",
15243
15243
  traces: "Traces"
@@ -16428,7 +16428,7 @@ var analyticsAnalyticsOverview$1 = {
16428
16428
  topicsChartDescription: "Los temas más tratados, ordenados por la cantidad de mensajes que generó cada uno.",
16429
16429
  activeUsersChartDescription: "Usuarios activos únicos por día, para ver cómo cambia la participación con el tiempo.",
16430
16430
  llmSpend: "Gasto LLM",
16431
- llmSpendDescription: "Costo bruto de cada llamada LLM trazada en el período seleccionado, del almacén de trazas. Los totales de facturación están en la pestaña Costos y LLM.",
16431
+ llmSpendDescription: "Costo bruto de cada llamada LLM trazada en el período seleccionado, del almacén de trazas. Los totales de facturación están en la pestaña Costos.",
16432
16432
  allTopics: "Todos los temas",
16433
16433
  topicsRankedFooter: "{shown} de {total} temas · ordenados por volumen de mensajes"
16434
16434
  };
@@ -22385,7 +22385,7 @@ var analyticsChartCard$1 = {
22385
22385
  adjustRangeHint: "Solo esta tarjeta — el rango de la página no cambia."
22386
22386
  };
22387
22387
  var analyticsCostTabs$1 = {
22388
- ariaLabel: "Secciones de Costos y LLM",
22388
+ ariaLabel: "Secciones de Costos",
22389
22389
  spend: "Gasto",
22390
22390
  usage: "Uso y latencia",
22391
22391
  traces: "Trazas"
@@ -23576,7 +23576,7 @@ var analyticsAnalyticsOverview = {
23576
23576
  topicsChartDescription: "讨论最多的主题,按各自产生的消息数排序。",
23577
23577
  activeUsersChartDescription: "每日独立活跃用户数,展示参与度随时间的变化。",
23578
23578
  llmSpend: "LLM 支出",
23579
- llmSpendDescription: "所选时段内每次被追踪的 LLM 调用的原始成本,来自追踪存储。计费总额在成本与 LLM 页。",
23579
+ llmSpendDescription: "所选时段内每次被追踪的 LLM 调用的原始成本,来自追踪存储。计费总额在成本页。",
23580
23580
  allTopics: "所有主题",
23581
23581
  topicsRankedFooter: "共 {total} 个主题,显示 {shown} 个 · 按消息量排序"
23582
23582
  };
@@ -29533,7 +29533,7 @@ var analyticsChartCard = {
29533
29533
  adjustRangeHint: "仅此卡片 — 页面范围保持不变。"
29534
29534
  };
29535
29535
  var analyticsCostTabs = {
29536
- ariaLabel: "成本与 LLM 分区",
29536
+ ariaLabel: "成本分区",
29537
29537
  spend: "支出",
29538
29538
  usage: "用量与延迟",
29539
29539
  traces: "追踪"
@@ -190957,15 +190957,17 @@ const PAGE_SIZE$7 = 20;
190957
190957
  const SEARCH_DEBOUNCE_MS$3 = 300;
190958
190958
  /**
190959
190959
  * The public application URL on the auth SPA for one form of a platform
190960
- * (`<auth-url>/applications/<platform-key>/<form-id>?redirect-to=<origin>`), or
190961
- * null when the auth SPA URL cannot be resolved. `authSpaUrl` (prop) wins;
190960
+ * (`<auth-url>/applications/<platform-key>/<form-id>?redirect-to=<origin>&app=<spa>`),
190961
+ * or null when the auth SPA URL cannot be resolved. `authSpaUrl` (prop) wins;
190962
190962
  * otherwise the runtime-injected env (`window.__ENV__.NEXT_PUBLIC_AUTH_URL`) is
190963
190963
  * used. With no `formId` the link resolves the platform's default form (404
190964
190964
  * when none). The `redirect-to` param carries the origin the applicant is sent
190965
190965
  * back to after submitting — by default the origin the link is copied from — and
190966
- * is omitted when no origin can be read (no DOM).
190966
+ * is omitted when no origin can be read (no DOM). The `app` param carries the
190967
+ * SPA the link was copied from, so the login flow the applicant is sent through
190968
+ * (unauthenticated visitors) is branded for that SPA; omitted when unknown.
190967
190969
  */
190968
- function buildApplicationLink(platformKey, formId, authSpaUrl, redirectTo) {
190970
+ function buildApplicationLink(platformKey, formId, authSpaUrl, redirectTo, currentSpa) {
190969
190971
  var _a, _b;
190970
190972
  const base = (_b = authSpaUrl !== null && authSpaUrl !== void 0 ? authSpaUrl : (typeof window !== 'undefined'
190971
190973
  ? (_a = window.__ENV__) === null || _a === void 0 ? void 0 : _a.NEXT_PUBLIC_AUTH_URL
@@ -190975,7 +190977,13 @@ function buildApplicationLink(platformKey, formId, authSpaUrl, redirectTo) {
190975
190977
  const root = `${trimTrailingSlashes(base)}/applications/${encodeURIComponent(platformKey)}`;
190976
190978
  const path = formId != null ? `${root}/${encodeURIComponent(String(formId))}` : root;
190977
190979
  const target = (typeof window !== 'undefined' ? window.location.origin : undefined);
190978
- return target ? `${path}?redirect-to=${encodeURIComponent(target)}` : path;
190980
+ const query = new URLSearchParams();
190981
+ if (target)
190982
+ query.set('redirect-to', target);
190983
+ if (currentSpa)
190984
+ query.set('app', currentSpa);
190985
+ const search = query.toString();
190986
+ return search ? `${path}?${search}` : path;
190979
190987
  }
190980
190988
  /**
190981
190989
  * Applications management. Entry view lists the platform's application forms
@@ -190983,7 +190991,7 @@ function buildApplicationLink(platformKey, formId, authSpaUrl, redirectTo) {
190983
190991
  * per-form (or all-form) submission pipelines, the submission workspace with
190984
190992
  * per-student decisions, the form/question editor, and the ban list.
190985
190993
  */
190986
- function ApplicationsTab({ platformKey, authSpaUrl, }) {
190994
+ function ApplicationsTab({ platformKey, authSpaUrl, currentSpa, }) {
190987
190995
  const [view, setView] = useState({ name: 'forms' });
190988
190996
  if (view.name === 'editor') {
190989
190997
  return (jsx(QuestionsEditor, { platformKey: platformKey, initialFormId: view.formId, startNew: view.startNew, onBack: () => setView({ name: 'forms' }) }));
@@ -190997,10 +191005,10 @@ function ApplicationsTab({ platformKey, authSpaUrl, }) {
190997
191005
  if (view.name === 'submissions') {
190998
191006
  return (jsx(SubmissionsPipeline, { platformKey: platformKey, form: view.form, onBack: () => setView({ name: 'forms' }), onOpen: (submissionId) => setView({ name: 'detail', submissionId, form: view.form }) }));
190999
191007
  }
191000
- return (jsx(FormsList, { platformKey: platformKey, authSpaUrl: authSpaUrl, onViewSubmissions: (form) => setView({ name: 'submissions', form }), onEditForm: (formId) => setView({ name: 'editor', formId, startNew: false }), onNewForm: () => setView({ name: 'editor', formId: null, startNew: true }), onViewBlocks: () => setView({ name: 'blocks' }) }));
191008
+ return (jsx(FormsList, { platformKey: platformKey, authSpaUrl: authSpaUrl, currentSpa: currentSpa, onViewSubmissions: (form) => setView({ name: 'submissions', form }), onEditForm: (formId) => setView({ name: 'editor', formId, startNew: false }), onNewForm: () => setView({ name: 'editor', formId: null, startNew: true }), onViewBlocks: () => setView({ name: 'blocks' }) }));
191001
191009
  }
191002
191010
  /** The entry view: every application form of the platform, with actions. */
191003
- function FormsList({ platformKey, authSpaUrl, onViewSubmissions, onEditForm, onNewForm, onViewBlocks, }) {
191011
+ function FormsList({ platformKey, authSpaUrl, currentSpa, onViewSubmissions, onEditForm, onNewForm, onViewBlocks, }) {
191004
191012
  const t = useT();
191005
191013
  /** The form id whose link was just copied (transient "Copied" feedback). */
191006
191014
  const [copiedFormId, setCopiedFormId] = useState(null);
@@ -191014,7 +191022,7 @@ function FormsList({ platformKey, authSpaUrl, onViewSubmissions, onEditForm, onN
191014
191022
  const counts = statsCounts(stats);
191015
191023
  const total = Object.values(counts).reduce((sum, n) => sum + n, 0);
191016
191024
  const handleCopyLink = async (form) => {
191017
- const link = buildApplicationLink(platformKey, form.id, authSpaUrl);
191025
+ const link = buildApplicationLink(platformKey, form.id, authSpaUrl, undefined, currentSpa);
191018
191026
  if (!link)
191019
191027
  return;
191020
191028
  try {
@@ -191034,7 +191042,7 @@ function FormsList({ platformKey, authSpaUrl, onViewSubmissions, onEditForm, onN
191034
191042
  ? 'bg-blue-50 text-blue-700 border-blue-200 dark:bg-blue-900/30 dark:text-blue-300 dark:border-blue-900'
191035
191043
  : 'bg-gray-100 text-gray-600 border-gray-200 dark:bg-gray-700 dark:text-gray-300 dark:border-gray-600', children: t(form.enabled
191036
191044
  ? 'profileApplicationsTab.formEnabled'
191037
- : 'profileApplicationsTab.formDisabled') }) }), jsx("td", { className: "whitespace-nowrap px-6 py-4 text-right", children: jsxs("div", { className: "flex items-center justify-end gap-1", children: [buildApplicationLink(platformKey, form.id, authSpaUrl) && (jsxs(Tooltip$1, { children: [jsx(TooltipTrigger, { asChild: true, children: jsxs(Button$1, { variant: "ghost", className: copiedFormId === form.id
191045
+ : 'profileApplicationsTab.formDisabled') }) }), jsx("td", { className: "whitespace-nowrap px-6 py-4 text-right", children: jsxs("div", { className: "flex items-center justify-end gap-1", children: [buildApplicationLink(platformKey, form.id, authSpaUrl, undefined, currentSpa) && (jsxs(Tooltip$1, { children: [jsx(TooltipTrigger, { asChild: true, children: jsxs(Button$1, { variant: "ghost", className: copiedFormId === form.id
191038
191046
  ? 'h-8 w-8 p-0 text-blue-600 dark:text-blue-400'
191039
191047
  : 'h-8 w-8 p-0 text-gray-500 hover:text-gray-900 dark:text-gray-400 dark:hover:text-gray-100', onClick: () => handleCopyLink(form), "aria-label": t('profileApplicationsTab.copyFormLink', {
191040
191048
  form: ((_b = form.schema) === null || _b === void 0 ? void 0 : _b.title) ||
@@ -191587,7 +191595,7 @@ const Admin = ({ tenant, onInviteClick, hasUserTabPermission = false, hasGroupsT
191587
191595
  */
191588
191596
  const isWatcher = isPureWatcher(storeRbacPermissions, currentTenant);
191589
191597
  const showUsersTab = isWatcher || hasUserTabPermission;
191590
- return (jsx("div", { className: "border border-gray-200 rounded-lg p-6", children: jsxs(Tabs, { defaultValue: "users", "aria-label": t('profileAdmin.rbacManagementTabsAriaLabel'), children: [jsxs(TabsList, { "aria-label": t('profileAdmin.managementTabsAriaLabel'), className: "max-w-full overflow-x-auto justify-start px-1", children: [showUsersTab && jsx(TabsTrigger, { value: "users", children: t('profileAdmin.usersTab') }), !isWatcher && hasGroupsTabPermission && (jsx(TabsTrigger, { value: "groups", children: t('profileAdmin.groupsTab') })), !isWatcher && hasRolesTabPermission && (jsx(TabsTrigger, { value: "roles", children: t('profileAdmin.rolesTab') })), !isWatcher && hasPoliciesTabPermission && (jsx(TabsTrigger, { value: "policies", children: t('profileAdmin.policiesTab') })), !isWatcher && hasTeamsTabPermission && (jsx(TabsTrigger, { value: "teams", children: t('profileAdmin.teamsTab') })), !isWatcher && hasAlertsTabPermission && (jsx(TabsTrigger, { value: "alerts", children: t('profileAdmin.alertsTab') })), !isWatcher && (jsx(TabsTrigger, { value: "applications", children: t('profileAdmin.applicationsTab') })), !isWatcher && (jsx(TabsTrigger, { value: "onboarding", children: t('profileAdmin.onboardingTab') }))] }), showUsersTab && (jsxs(TabsContent, { className: "mt-4", value: "users", children: [jsx(TabDescription, { icon: jsx(Users, { className: "w-5 h-5" }), title: t('profileAdmin.usersTab'), children: t('profileAdmin.usersDescription') }), jsx(UsersTab, { tenant: tenant, onInviteClick: onInviteClick, currentSpa: currentSpa, showGradebookTab: showGradebookTab })] })), !isWatcher && hasGroupsTabPermission && (jsxs(TabsContent, { className: "mt-4", value: "groups", children: [jsx(TabDescription, { icon: jsx(UsersRound, { className: "w-5 h-5" }), title: t('profileAdmin.groupsTab'), children: t('profileAdmin.groupsDescription') }), jsx(GroupsTab, { tenant: tenant })] })), !isWatcher && hasRolesTabPermission && (jsxs(TabsContent, { className: "mt-4", value: "roles", children: [jsx(TabDescription, { icon: jsx(UserCog, { className: "w-5 h-5" }), title: t('profileAdmin.rolesTab'), children: t('profileAdmin.rolesDescription') }), jsx(RolesTab, { tenant: tenant })] })), !isWatcher && hasPoliciesTabPermission && (jsxs(TabsContent, { className: "mt-4", value: "policies", children: [jsx(TabDescription, { icon: jsx(ScrollText, { className: "w-5 h-5" }), title: t('profileAdmin.policiesTab'), children: t('profileAdmin.policiesDescription') }), jsx(PoliciesTab, { tenant: tenant })] })), !isWatcher && hasTeamsTabPermission && (jsxs(TabsContent, { className: "mt-4", value: "teams", children: [jsx(TabDescription, { icon: jsx(Shield, { className: "w-5 h-5" }), title: t('profileAdmin.teamsTab'), children: t('profileAdmin.teamsDescription') }), jsx(GroupsTab, { tenant: tenant, isTeam: true, onInviteClick: onInviteClick, hasInviteUserPermission: hasInviteUserPermission, hasCreateTeamPermission: hasCreateTeamPermission, onLoadGroupPermissions: onLoadGroupPermissions, rbacPermissions: rbacPermissions, enableRbac: enableRbac })] })), !isWatcher && hasAlertsTabPermission && (jsxs(TabsContent, { className: "mt-4", value: "alerts", children: [jsx(TabDescription, { icon: jsx(BellRing, { className: "w-5 h-5" }), title: t('profileAdmin.alertsTab'), children: t('profileAdmin.alertsDescription') }), jsx(AlertsTab$1, { tenant: tenant })] })), !isWatcher && (jsxs(TabsContent, { className: "mt-4", value: "applications", children: [jsx(TabDescription, { icon: jsx(ClipboardList, { className: "w-5 h-5" }), title: t('profileAdmin.applicationsTab'), children: t('profileAdmin.applicationsTabDescription') }), jsx(ApplicationsTab, { platformKey: tenant, authSpaUrl: authSpaUrl })] })), !isWatcher && (jsxs(TabsContent, { className: "mt-4", value: "onboarding", children: [jsx(TabDescription, { icon: jsx(UserPlus, { className: "w-5 h-5" }), title: t('profileAdmin.onboardingTab'), children: t('profileAdmin.onboardingTabDescription') }), jsx(OnboardingTab, { platformKey: tenant, onboardingBasePath: onboardingBasePath })] }))] }) }));
191598
+ return (jsx("div", { className: "border border-gray-200 rounded-lg p-6", children: jsxs(Tabs, { defaultValue: "users", "aria-label": t('profileAdmin.rbacManagementTabsAriaLabel'), children: [jsxs(TabsList, { "aria-label": t('profileAdmin.managementTabsAriaLabel'), className: "max-w-full overflow-x-auto justify-start px-1", children: [showUsersTab && jsx(TabsTrigger, { value: "users", children: t('profileAdmin.usersTab') }), !isWatcher && hasGroupsTabPermission && (jsx(TabsTrigger, { value: "groups", children: t('profileAdmin.groupsTab') })), !isWatcher && hasRolesTabPermission && (jsx(TabsTrigger, { value: "roles", children: t('profileAdmin.rolesTab') })), !isWatcher && hasPoliciesTabPermission && (jsx(TabsTrigger, { value: "policies", children: t('profileAdmin.policiesTab') })), !isWatcher && hasTeamsTabPermission && (jsx(TabsTrigger, { value: "teams", children: t('profileAdmin.teamsTab') })), !isWatcher && hasAlertsTabPermission && (jsx(TabsTrigger, { value: "alerts", children: t('profileAdmin.alertsTab') })), !isWatcher && (jsx(TabsTrigger, { value: "applications", children: t('profileAdmin.applicationsTab') })), !isWatcher && (jsx(TabsTrigger, { value: "onboarding", children: t('profileAdmin.onboardingTab') }))] }), showUsersTab && (jsxs(TabsContent, { className: "mt-4", value: "users", children: [jsx(TabDescription, { icon: jsx(Users, { className: "w-5 h-5" }), title: t('profileAdmin.usersTab'), children: t('profileAdmin.usersDescription') }), jsx(UsersTab, { tenant: tenant, onInviteClick: onInviteClick, currentSpa: currentSpa, showGradebookTab: showGradebookTab })] })), !isWatcher && hasGroupsTabPermission && (jsxs(TabsContent, { className: "mt-4", value: "groups", children: [jsx(TabDescription, { icon: jsx(UsersRound, { className: "w-5 h-5" }), title: t('profileAdmin.groupsTab'), children: t('profileAdmin.groupsDescription') }), jsx(GroupsTab, { tenant: tenant })] })), !isWatcher && hasRolesTabPermission && (jsxs(TabsContent, { className: "mt-4", value: "roles", children: [jsx(TabDescription, { icon: jsx(UserCog, { className: "w-5 h-5" }), title: t('profileAdmin.rolesTab'), children: t('profileAdmin.rolesDescription') }), jsx(RolesTab, { tenant: tenant })] })), !isWatcher && hasPoliciesTabPermission && (jsxs(TabsContent, { className: "mt-4", value: "policies", children: [jsx(TabDescription, { icon: jsx(ScrollText, { className: "w-5 h-5" }), title: t('profileAdmin.policiesTab'), children: t('profileAdmin.policiesDescription') }), jsx(PoliciesTab, { tenant: tenant })] })), !isWatcher && hasTeamsTabPermission && (jsxs(TabsContent, { className: "mt-4", value: "teams", children: [jsx(TabDescription, { icon: jsx(Shield, { className: "w-5 h-5" }), title: t('profileAdmin.teamsTab'), children: t('profileAdmin.teamsDescription') }), jsx(GroupsTab, { tenant: tenant, isTeam: true, onInviteClick: onInviteClick, hasInviteUserPermission: hasInviteUserPermission, hasCreateTeamPermission: hasCreateTeamPermission, onLoadGroupPermissions: onLoadGroupPermissions, rbacPermissions: rbacPermissions, enableRbac: enableRbac })] })), !isWatcher && hasAlertsTabPermission && (jsxs(TabsContent, { className: "mt-4", value: "alerts", children: [jsx(TabDescription, { icon: jsx(BellRing, { className: "w-5 h-5" }), title: t('profileAdmin.alertsTab'), children: t('profileAdmin.alertsDescription') }), jsx(AlertsTab$1, { tenant: tenant })] })), !isWatcher && (jsxs(TabsContent, { className: "mt-4", value: "applications", children: [jsx(TabDescription, { icon: jsx(ClipboardList, { className: "w-5 h-5" }), title: t('profileAdmin.applicationsTab'), children: t('profileAdmin.applicationsTabDescription') }), jsx(ApplicationsTab, { platformKey: tenant, authSpaUrl: authSpaUrl, currentSpa: currentSpa })] })), !isWatcher && (jsxs(TabsContent, { className: "mt-4", value: "onboarding", children: [jsx(TabDescription, { icon: jsx(UserPlus, { className: "w-5 h-5" }), title: t('profileAdmin.onboardingTab'), children: t('profileAdmin.onboardingTabDescription') }), jsx(OnboardingTab, { platformKey: tenant, onboardingBasePath: onboardingBasePath })] }))] }) }));
191591
191599
  };
191592
191600
 
191593
191601
  function DeleteApiModal({ isOpen, onClose, apiKey, tenantKey }) {
@@ -229541,7 +229549,7 @@ const useOverview = ({ tenantKey, mentorId, usergroupIds, }) => {
229541
229549
  ...((usergroupIds === null || usergroupIds === void 0 ? void 0 : usergroupIds.length) ? { usergroup_ids: usergroupIds } : {}),
229542
229550
  });
229543
229551
  // LLM spend joins the KPI row so cost is visible before anyone opens the
229544
- // Cost & LLM tab. It follows the page range; unavailable renders as an
229552
+ // Cost tab. It follows the page range; unavailable renders as an
229545
229553
  // em-dash, never $0.00.
229546
229554
  const globalFilters = (_o = useAnalyticsGlobalFilters()) === null || _o === void 0 ? void 0 : _o.filters;
229547
229555
  const { data: llmSpendData, isLoading: isLoadingLlmSpend, error: llmSpendError, } = useGetLlmUsageMetricsQuery({
@@ -229951,7 +229959,7 @@ const defaultTabs = [
229951
229959
  },
229952
229960
  {
229953
229961
  // The unified cost surface: ClickHouse billing + Langfuse LLM usage.
229954
- label: 'Cost & LLM',
229962
+ label: 'Cost',
229955
229963
  value: 'financial',
229956
229964
  },
229957
229965
  {
@@ -230499,7 +230507,7 @@ const byProvider = (models) => {
230499
230507
  .sort((a, b) => b.total_cost - a.total_cost);
230500
230508
  };
230501
230509
  /**
230502
- * Spend view-model for the Cost & LLM tab, backed by the ClickHouse
230510
+ * Spend view-model for the Cost tab, backed by the ClickHouse
230503
230511
  * `/api/ai-analytics/` cost endpoints (KPIs, per-model, per-user) and the
230504
230512
  * Langfuse `llm-usage` metrics resource (the daily spend series). The
230505
230513
  * deprecated `/api/analytics/financial/` family is gone; the return shape is
@@ -230708,7 +230716,7 @@ const formatCompactNumber = (value) => {
230708
230716
  const formatLatencySeconds = (value) => `${value.toFixed(2)}s`;
230709
230717
  const UNAVAILABLE = '—';
230710
230718
  /**
230711
- * The Langfuse side of the Cost & LLM tab: tokens, calls, latency percentiles
230719
+ * The Langfuse side of the Cost tab: tokens, calls, latency percentiles
230712
230720
  * and spend breakdowns per service and model. Ranked per-user/per-session
230713
230721
  * totals live on the Spend sub-tab (ClickHouse) — Langfuse cannot group by
230714
230722
  * those dimensions.
@@ -230780,7 +230788,7 @@ function useDebouncedValue(value, delay) {
230780
230788
  }
230781
230789
  /**
230782
230790
  * Tenant user picker for the analytics filter rows — memory, transcripts and
230783
- * the Cost & LLM traces list.
230791
+ * the Cost traces list.
230784
230792
  * Both endpoints behind it do the searching, so the dropdown only pages in the
230785
230793
  * first {@link USERS_PAGE_SIZE} matches for whatever is typed rather than
230786
230794
  * filtering client-side.
@@ -231097,7 +231105,7 @@ function SpendTab({ tenantKey, mentorId: currentMentorId, userId, onOpenUserTrac
231097
231105
  }) }), jsxs("div", { className: "flex items-center space-x-2", children: [jsxs(Button$1, { variant: "outline", size: "sm", className: "h-8 p-2 !w-auto !inline-flex bg-transparent", onClick: handleFirstPage, disabled: costPerUserPage === 1, children: [jsx("span", { className: "sr-only", children: t('analyticsAnalyticsFinancialStats.goToFirstPage') }), jsx(ChevronsLeft, { className: "h-4 w-4" })] }), jsxs(Button$1, { variant: "outline", size: "sm", className: "h-8 p-2 !w-auto !inline-flex bg-transparent", onClick: handlePreviousPage, disabled: costPerUserPage === 1, children: [jsx("span", { className: "sr-only", children: t('analyticsAnalyticsFinancialStats.goToPreviousPage') }), jsx(ChevronLeft, { className: "h-4 w-4" })] }), generatePageNumbers().map((page, index) => (jsx(React__default.Fragment, { children: page === '...' ? (jsx("span", { className: "px-2 text-gray-500", children: "..." })) : (jsx(Button$1, { variant: costPerUserPage === page ? 'default' : 'outline', size: "sm", className: `h-8 p-3 !w-auto !inline-flex ${costPerUserPage === page ? 'bg-blue-50 text-blue-600' : 'bg-transparent'}`, onClick: () => setCostPerUserPage(page), children: page })) }, index))), jsxs(Button$1, { variant: "outline", size: "sm", className: "h-8 p-2 !w-auto !inline-flex bg-transparent", onClick: handleNextPage, disabled: costPerUserPage === detailedCostPerUserData.total_pages, children: [jsx("span", { className: "sr-only", children: t('analyticsAnalyticsFinancialStats.goToNextPage') }), jsx(ChevronRight, { className: "h-4 w-4" })] }), jsxs(Button$1, { variant: "outline", size: "sm", className: "h-8 p-2 !w-auto !inline-flex bg-transparent", onClick: handleLastPage, disabled: costPerUserPage === detailedCostPerUserData.total_pages, children: [jsx("span", { className: "sr-only", children: t('analyticsAnalyticsFinancialStats.goToLastPage') }), jsx(ChevronsRight, { className: "h-4 w-4" })] })] })] }))] }) }) })] }));
231098
231106
  }
231099
231107
  /**
231100
- * The Cost & LLM tab: one surface over two backends, split where the backends
231108
+ * The Cost tab: one surface over two backends, split where the backends
231101
231109
  * actually split. Spend is ClickHouse (billing truth: marked-up USD, ranked
231102
231110
  * per-user history); Usage & latency and Traces are the Langfuse proxy
231103
231111
  * (tokens, latency percentiles, per-call drill-down). Every card names its
@@ -96915,7 +96915,7 @@ var analyticsAnalyticsOverview$3 = {
96915
96915
  topicsChartDescription: "The most discussed topics, ranked by how many messages each one generated.",
96916
96916
  activeUsersChartDescription: "Unique active users per day, showing how engagement changes over time.",
96917
96917
  llmSpend: "LLM spend",
96918
- llmSpendDescription: "Raw cost of every traced LLM call in the selected period, from the trace store. Billing totals live on the Cost & LLM tab.",
96918
+ llmSpendDescription: "Raw cost of every traced LLM call in the selected period, from the trace store. Billing totals live on the Cost tab.",
96919
96919
  allTopics: "All topics",
96920
96920
  topicsRankedFooter: "{shown} of {total} topics · ranked by message volume"
96921
96921
  };
@@ -102872,7 +102872,7 @@ var analyticsChartCard$3 = {
102872
102872
  adjustRangeHint: "This card only — the page range stays where it is."
102873
102873
  };
102874
102874
  var analyticsCostTabs$3 = {
102875
- ariaLabel: "Cost & LLM sections",
102875
+ ariaLabel: "Cost sections",
102876
102876
  spend: "Spend",
102877
102877
  usage: "Usage & latency",
102878
102878
  traces: "Traces"
@@ -104063,7 +104063,7 @@ var analyticsAnalyticsOverview$2 = {
104063
104063
  topicsChartDescription: "Les sujets les plus abordés, classés selon le nombre de messages générés.",
104064
104064
  activeUsersChartDescription: "Utilisateurs actifs uniques par jour, pour suivre l’évolution de l’engagement.",
104065
104065
  llmSpend: "Dépenses LLM",
104066
- llmSpendDescription: "Coût brut de chaque appel LLM tracé sur la période sélectionnée, issu du magasin de traces. Les totaux de facturation sont dans l'onglet Coûts et LLM.",
104066
+ llmSpendDescription: "Coût brut de chaque appel LLM tracé sur la période sélectionnée, issu du magasin de traces. Les totaux de facturation sont dans l'onglet Coûts.",
104067
104067
  allTopics: "Tous les sujets",
104068
104068
  topicsRankedFooter: "{shown} sur {total} sujets · classés par volume de messages"
104069
104069
  };
@@ -110020,7 +110020,7 @@ var analyticsChartCard$2 = {
110020
110020
  adjustRangeHint: "Cette carte uniquement — la plage de la page reste inchangée."
110021
110021
  };
110022
110022
  var analyticsCostTabs$2 = {
110023
- ariaLabel: "Sections Coûts et LLM",
110023
+ ariaLabel: "Sections Coûts",
110024
110024
  spend: "Dépenses",
110025
110025
  usage: "Utilisation et latence",
110026
110026
  traces: "Traces"
@@ -111211,7 +111211,7 @@ var analyticsAnalyticsOverview$1 = {
111211
111211
  topicsChartDescription: "Los temas más tratados, ordenados por la cantidad de mensajes que generó cada uno.",
111212
111212
  activeUsersChartDescription: "Usuarios activos únicos por día, para ver cómo cambia la participación con el tiempo.",
111213
111213
  llmSpend: "Gasto LLM",
111214
- llmSpendDescription: "Costo bruto de cada llamada LLM trazada en el período seleccionado, del almacén de trazas. Los totales de facturación están en la pestaña Costos y LLM.",
111214
+ llmSpendDescription: "Costo bruto de cada llamada LLM trazada en el período seleccionado, del almacén de trazas. Los totales de facturación están en la pestaña Costos.",
111215
111215
  allTopics: "Todos los temas",
111216
111216
  topicsRankedFooter: "{shown} de {total} temas · ordenados por volumen de mensajes"
111217
111217
  };
@@ -117168,7 +117168,7 @@ var analyticsChartCard$1 = {
117168
117168
  adjustRangeHint: "Solo esta tarjeta — el rango de la página no cambia."
117169
117169
  };
117170
117170
  var analyticsCostTabs$1 = {
117171
- ariaLabel: "Secciones de Costos y LLM",
117171
+ ariaLabel: "Secciones de Costos",
117172
117172
  spend: "Gasto",
117173
117173
  usage: "Uso y latencia",
117174
117174
  traces: "Trazas"
@@ -118359,7 +118359,7 @@ var analyticsAnalyticsOverview = {
118359
118359
  topicsChartDescription: "讨论最多的主题,按各自产生的消息数排序。",
118360
118360
  activeUsersChartDescription: "每日独立活跃用户数,展示参与度随时间的变化。",
118361
118361
  llmSpend: "LLM 支出",
118362
- llmSpendDescription: "所选时段内每次被追踪的 LLM 调用的原始成本,来自追踪存储。计费总额在成本与 LLM 页。",
118362
+ llmSpendDescription: "所选时段内每次被追踪的 LLM 调用的原始成本,来自追踪存储。计费总额在成本页。",
118363
118363
  allTopics: "所有主题",
118364
118364
  topicsRankedFooter: "共 {total} 个主题,显示 {shown} 个 · 按消息量排序"
118365
118365
  };
@@ -124316,7 +124316,7 @@ var analyticsChartCard = {
124316
124316
  adjustRangeHint: "仅此卡片 — 页面范围保持不变。"
124317
124317
  };
124318
124318
  var analyticsCostTabs = {
124319
- ariaLabel: "成本与 LLM 分区",
124319
+ ariaLabel: "成本分区",
124320
124320
  spend: "支出",
124321
124321
  usage: "用量与延迟",
124322
124322
  traces: "追踪"
@@ -223577,15 +223577,17 @@ const PAGE_SIZE$b = 20;
223577
223577
  const SEARCH_DEBOUNCE_MS$1 = 300;
223578
223578
  /**
223579
223579
  * The public application URL on the auth SPA for one form of a platform
223580
- * (`<auth-url>/applications/<platform-key>/<form-id>?redirect-to=<origin>`), or
223581
- * null when the auth SPA URL cannot be resolved. `authSpaUrl` (prop) wins;
223580
+ * (`<auth-url>/applications/<platform-key>/<form-id>?redirect-to=<origin>&app=<spa>`),
223581
+ * or null when the auth SPA URL cannot be resolved. `authSpaUrl` (prop) wins;
223582
223582
  * otherwise the runtime-injected env (`window.__ENV__.NEXT_PUBLIC_AUTH_URL`) is
223583
223583
  * used. With no `formId` the link resolves the platform's default form (404
223584
223584
  * when none). The `redirect-to` param carries the origin the applicant is sent
223585
223585
  * back to after submitting — by default the origin the link is copied from — and
223586
- * is omitted when no origin can be read (no DOM).
223586
+ * is omitted when no origin can be read (no DOM). The `app` param carries the
223587
+ * SPA the link was copied from, so the login flow the applicant is sent through
223588
+ * (unauthenticated visitors) is branded for that SPA; omitted when unknown.
223587
223589
  */
223588
- function buildApplicationLink(platformKey, formId, authSpaUrl, redirectTo) {
223590
+ function buildApplicationLink(platformKey, formId, authSpaUrl, redirectTo, currentSpa) {
223589
223591
  var _a, _b;
223590
223592
  const base = (_b = authSpaUrl !== null && authSpaUrl !== void 0 ? authSpaUrl : (typeof window !== 'undefined'
223591
223593
  ? (_a = window.__ENV__) === null || _a === void 0 ? void 0 : _a.NEXT_PUBLIC_AUTH_URL
@@ -223595,7 +223597,13 @@ function buildApplicationLink(platformKey, formId, authSpaUrl, redirectTo) {
223595
223597
  const root = `${trimTrailingSlashes(base)}/applications/${encodeURIComponent(platformKey)}`;
223596
223598
  const path = formId != null ? `${root}/${encodeURIComponent(String(formId))}` : root;
223597
223599
  const target = (typeof window !== 'undefined' ? window.location.origin : undefined);
223598
- return target ? `${path}?redirect-to=${encodeURIComponent(target)}` : path;
223600
+ const query = new URLSearchParams();
223601
+ if (target)
223602
+ query.set('redirect-to', target);
223603
+ if (currentSpa)
223604
+ query.set('app', currentSpa);
223605
+ const search = query.toString();
223606
+ return search ? `${path}?${search}` : path;
223599
223607
  }
223600
223608
  /**
223601
223609
  * Applications management. Entry view lists the platform's application forms
@@ -223603,7 +223611,7 @@ function buildApplicationLink(platformKey, formId, authSpaUrl, redirectTo) {
223603
223611
  * per-form (or all-form) submission pipelines, the submission workspace with
223604
223612
  * per-student decisions, the form/question editor, and the ban list.
223605
223613
  */
223606
- function ApplicationsTab({ platformKey, authSpaUrl, }) {
223614
+ function ApplicationsTab({ platformKey, authSpaUrl, currentSpa, }) {
223607
223615
  const [view, setView] = useState({ name: 'forms' });
223608
223616
  if (view.name === 'editor') {
223609
223617
  return (jsx(QuestionsEditor, { platformKey: platformKey, initialFormId: view.formId, startNew: view.startNew, onBack: () => setView({ name: 'forms' }) }));
@@ -223617,10 +223625,10 @@ function ApplicationsTab({ platformKey, authSpaUrl, }) {
223617
223625
  if (view.name === 'submissions') {
223618
223626
  return (jsx(SubmissionsPipeline, { platformKey: platformKey, form: view.form, onBack: () => setView({ name: 'forms' }), onOpen: (submissionId) => setView({ name: 'detail', submissionId, form: view.form }) }));
223619
223627
  }
223620
- return (jsx(FormsList, { platformKey: platformKey, authSpaUrl: authSpaUrl, onViewSubmissions: (form) => setView({ name: 'submissions', form }), onEditForm: (formId) => setView({ name: 'editor', formId, startNew: false }), onNewForm: () => setView({ name: 'editor', formId: null, startNew: true }), onViewBlocks: () => setView({ name: 'blocks' }) }));
223628
+ return (jsx(FormsList, { platformKey: platformKey, authSpaUrl: authSpaUrl, currentSpa: currentSpa, onViewSubmissions: (form) => setView({ name: 'submissions', form }), onEditForm: (formId) => setView({ name: 'editor', formId, startNew: false }), onNewForm: () => setView({ name: 'editor', formId: null, startNew: true }), onViewBlocks: () => setView({ name: 'blocks' }) }));
223621
223629
  }
223622
223630
  /** The entry view: every application form of the platform, with actions. */
223623
- function FormsList({ platformKey, authSpaUrl, onViewSubmissions, onEditForm, onNewForm, onViewBlocks, }) {
223631
+ function FormsList({ platformKey, authSpaUrl, currentSpa, onViewSubmissions, onEditForm, onNewForm, onViewBlocks, }) {
223624
223632
  const t = useT();
223625
223633
  /** The form id whose link was just copied (transient "Copied" feedback). */
223626
223634
  const [copiedFormId, setCopiedFormId] = useState(null);
@@ -223634,7 +223642,7 @@ function FormsList({ platformKey, authSpaUrl, onViewSubmissions, onEditForm, onN
223634
223642
  const counts = statsCounts(stats);
223635
223643
  const total = Object.values(counts).reduce((sum, n) => sum + n, 0);
223636
223644
  const handleCopyLink = async (form) => {
223637
- const link = buildApplicationLink(platformKey, form.id, authSpaUrl);
223645
+ const link = buildApplicationLink(platformKey, form.id, authSpaUrl, undefined, currentSpa);
223638
223646
  if (!link)
223639
223647
  return;
223640
223648
  try {
@@ -223654,7 +223662,7 @@ function FormsList({ platformKey, authSpaUrl, onViewSubmissions, onEditForm, onN
223654
223662
  ? 'bg-blue-50 text-blue-700 border-blue-200 dark:bg-blue-900/30 dark:text-blue-300 dark:border-blue-900'
223655
223663
  : 'bg-gray-100 text-gray-600 border-gray-200 dark:bg-gray-700 dark:text-gray-300 dark:border-gray-600', children: t(form.enabled
223656
223664
  ? 'profileApplicationsTab.formEnabled'
223657
- : 'profileApplicationsTab.formDisabled') }) }), jsx("td", { className: "whitespace-nowrap px-6 py-4 text-right", children: jsxs("div", { className: "flex items-center justify-end gap-1", children: [buildApplicationLink(platformKey, form.id, authSpaUrl) && (jsxs(Tooltip$1, { children: [jsx(TooltipTrigger, { asChild: true, children: jsxs(Button$1, { variant: "ghost", className: copiedFormId === form.id
223665
+ : 'profileApplicationsTab.formDisabled') }) }), jsx("td", { className: "whitespace-nowrap px-6 py-4 text-right", children: jsxs("div", { className: "flex items-center justify-end gap-1", children: [buildApplicationLink(platformKey, form.id, authSpaUrl, undefined, currentSpa) && (jsxs(Tooltip$1, { children: [jsx(TooltipTrigger, { asChild: true, children: jsxs(Button$1, { variant: "ghost", className: copiedFormId === form.id
223658
223666
  ? 'h-8 w-8 p-0 text-blue-600 dark:text-blue-400'
223659
223667
  : 'h-8 w-8 p-0 text-gray-500 hover:text-gray-900 dark:text-gray-400 dark:hover:text-gray-100', onClick: () => handleCopyLink(form), "aria-label": t('profileApplicationsTab.copyFormLink', {
223660
223668
  form: ((_b = form.schema) === null || _b === void 0 ? void 0 : _b.title) ||
@@ -224123,7 +224131,7 @@ const Admin = ({ tenant, onInviteClick, hasUserTabPermission = false, hasGroupsT
224123
224131
  */
224124
224132
  const isWatcher = isPureWatcher(storeRbacPermissions, currentTenant);
224125
224133
  const showUsersTab = isWatcher || hasUserTabPermission;
224126
- return (jsx("div", { className: "border border-gray-200 rounded-lg p-6", children: jsxs(Tabs, { defaultValue: "users", "aria-label": t('profileAdmin.rbacManagementTabsAriaLabel'), children: [jsxs(TabsList, { "aria-label": t('profileAdmin.managementTabsAriaLabel'), className: "max-w-full overflow-x-auto justify-start px-1", children: [showUsersTab && jsx(TabsTrigger, { value: "users", children: t('profileAdmin.usersTab') }), !isWatcher && hasGroupsTabPermission && (jsx(TabsTrigger, { value: "groups", children: t('profileAdmin.groupsTab') })), !isWatcher && hasRolesTabPermission && (jsx(TabsTrigger, { value: "roles", children: t('profileAdmin.rolesTab') })), !isWatcher && hasPoliciesTabPermission && (jsx(TabsTrigger, { value: "policies", children: t('profileAdmin.policiesTab') })), !isWatcher && hasTeamsTabPermission && (jsx(TabsTrigger, { value: "teams", children: t('profileAdmin.teamsTab') })), !isWatcher && hasAlertsTabPermission && (jsx(TabsTrigger, { value: "alerts", children: t('profileAdmin.alertsTab') })), !isWatcher && (jsx(TabsTrigger, { value: "applications", children: t('profileAdmin.applicationsTab') })), !isWatcher && (jsx(TabsTrigger, { value: "onboarding", children: t('profileAdmin.onboardingTab') }))] }), showUsersTab && (jsxs(TabsContent, { className: "mt-4", value: "users", children: [jsx(TabDescription, { icon: jsx(Users, { className: "w-5 h-5" }), title: t('profileAdmin.usersTab'), children: t('profileAdmin.usersDescription') }), jsx(UsersTab, { tenant: tenant, onInviteClick: onInviteClick, currentSpa: currentSpa, showGradebookTab: showGradebookTab })] })), !isWatcher && hasGroupsTabPermission && (jsxs(TabsContent, { className: "mt-4", value: "groups", children: [jsx(TabDescription, { icon: jsx(UsersRound, { className: "w-5 h-5" }), title: t('profileAdmin.groupsTab'), children: t('profileAdmin.groupsDescription') }), jsx(GroupsTab, { tenant: tenant })] })), !isWatcher && hasRolesTabPermission && (jsxs(TabsContent, { className: "mt-4", value: "roles", children: [jsx(TabDescription, { icon: jsx(UserCog, { className: "w-5 h-5" }), title: t('profileAdmin.rolesTab'), children: t('profileAdmin.rolesDescription') }), jsx(RolesTab, { tenant: tenant })] })), !isWatcher && hasPoliciesTabPermission && (jsxs(TabsContent, { className: "mt-4", value: "policies", children: [jsx(TabDescription, { icon: jsx(ScrollText, { className: "w-5 h-5" }), title: t('profileAdmin.policiesTab'), children: t('profileAdmin.policiesDescription') }), jsx(PoliciesTab, { tenant: tenant })] })), !isWatcher && hasTeamsTabPermission && (jsxs(TabsContent, { className: "mt-4", value: "teams", children: [jsx(TabDescription, { icon: jsx(Shield, { className: "w-5 h-5" }), title: t('profileAdmin.teamsTab'), children: t('profileAdmin.teamsDescription') }), jsx(GroupsTab, { tenant: tenant, isTeam: true, onInviteClick: onInviteClick, hasInviteUserPermission: hasInviteUserPermission, hasCreateTeamPermission: hasCreateTeamPermission, onLoadGroupPermissions: onLoadGroupPermissions, rbacPermissions: rbacPermissions, enableRbac: enableRbac })] })), !isWatcher && hasAlertsTabPermission && (jsxs(TabsContent, { className: "mt-4", value: "alerts", children: [jsx(TabDescription, { icon: jsx(BellRing, { className: "w-5 h-5" }), title: t('profileAdmin.alertsTab'), children: t('profileAdmin.alertsDescription') }), jsx(AlertsTab, { tenant: tenant })] })), !isWatcher && (jsxs(TabsContent, { className: "mt-4", value: "applications", children: [jsx(TabDescription, { icon: jsx(ClipboardList, { className: "w-5 h-5" }), title: t('profileAdmin.applicationsTab'), children: t('profileAdmin.applicationsTabDescription') }), jsx(ApplicationsTab, { platformKey: tenant, authSpaUrl: authSpaUrl })] })), !isWatcher && (jsxs(TabsContent, { className: "mt-4", value: "onboarding", children: [jsx(TabDescription, { icon: jsx(UserPlus, { className: "w-5 h-5" }), title: t('profileAdmin.onboardingTab'), children: t('profileAdmin.onboardingTabDescription') }), jsx(OnboardingTab, { platformKey: tenant, onboardingBasePath: onboardingBasePath })] }))] }) }));
224134
+ return (jsx("div", { className: "border border-gray-200 rounded-lg p-6", children: jsxs(Tabs, { defaultValue: "users", "aria-label": t('profileAdmin.rbacManagementTabsAriaLabel'), children: [jsxs(TabsList, { "aria-label": t('profileAdmin.managementTabsAriaLabel'), className: "max-w-full overflow-x-auto justify-start px-1", children: [showUsersTab && jsx(TabsTrigger, { value: "users", children: t('profileAdmin.usersTab') }), !isWatcher && hasGroupsTabPermission && (jsx(TabsTrigger, { value: "groups", children: t('profileAdmin.groupsTab') })), !isWatcher && hasRolesTabPermission && (jsx(TabsTrigger, { value: "roles", children: t('profileAdmin.rolesTab') })), !isWatcher && hasPoliciesTabPermission && (jsx(TabsTrigger, { value: "policies", children: t('profileAdmin.policiesTab') })), !isWatcher && hasTeamsTabPermission && (jsx(TabsTrigger, { value: "teams", children: t('profileAdmin.teamsTab') })), !isWatcher && hasAlertsTabPermission && (jsx(TabsTrigger, { value: "alerts", children: t('profileAdmin.alertsTab') })), !isWatcher && (jsx(TabsTrigger, { value: "applications", children: t('profileAdmin.applicationsTab') })), !isWatcher && (jsx(TabsTrigger, { value: "onboarding", children: t('profileAdmin.onboardingTab') }))] }), showUsersTab && (jsxs(TabsContent, { className: "mt-4", value: "users", children: [jsx(TabDescription, { icon: jsx(Users, { className: "w-5 h-5" }), title: t('profileAdmin.usersTab'), children: t('profileAdmin.usersDescription') }), jsx(UsersTab, { tenant: tenant, onInviteClick: onInviteClick, currentSpa: currentSpa, showGradebookTab: showGradebookTab })] })), !isWatcher && hasGroupsTabPermission && (jsxs(TabsContent, { className: "mt-4", value: "groups", children: [jsx(TabDescription, { icon: jsx(UsersRound, { className: "w-5 h-5" }), title: t('profileAdmin.groupsTab'), children: t('profileAdmin.groupsDescription') }), jsx(GroupsTab, { tenant: tenant })] })), !isWatcher && hasRolesTabPermission && (jsxs(TabsContent, { className: "mt-4", value: "roles", children: [jsx(TabDescription, { icon: jsx(UserCog, { className: "w-5 h-5" }), title: t('profileAdmin.rolesTab'), children: t('profileAdmin.rolesDescription') }), jsx(RolesTab, { tenant: tenant })] })), !isWatcher && hasPoliciesTabPermission && (jsxs(TabsContent, { className: "mt-4", value: "policies", children: [jsx(TabDescription, { icon: jsx(ScrollText, { className: "w-5 h-5" }), title: t('profileAdmin.policiesTab'), children: t('profileAdmin.policiesDescription') }), jsx(PoliciesTab, { tenant: tenant })] })), !isWatcher && hasTeamsTabPermission && (jsxs(TabsContent, { className: "mt-4", value: "teams", children: [jsx(TabDescription, { icon: jsx(Shield, { className: "w-5 h-5" }), title: t('profileAdmin.teamsTab'), children: t('profileAdmin.teamsDescription') }), jsx(GroupsTab, { tenant: tenant, isTeam: true, onInviteClick: onInviteClick, hasInviteUserPermission: hasInviteUserPermission, hasCreateTeamPermission: hasCreateTeamPermission, onLoadGroupPermissions: onLoadGroupPermissions, rbacPermissions: rbacPermissions, enableRbac: enableRbac })] })), !isWatcher && hasAlertsTabPermission && (jsxs(TabsContent, { className: "mt-4", value: "alerts", children: [jsx(TabDescription, { icon: jsx(BellRing, { className: "w-5 h-5" }), title: t('profileAdmin.alertsTab'), children: t('profileAdmin.alertsDescription') }), jsx(AlertsTab, { tenant: tenant })] })), !isWatcher && (jsxs(TabsContent, { className: "mt-4", value: "applications", children: [jsx(TabDescription, { icon: jsx(ClipboardList, { className: "w-5 h-5" }), title: t('profileAdmin.applicationsTab'), children: t('profileAdmin.applicationsTabDescription') }), jsx(ApplicationsTab, { platformKey: tenant, authSpaUrl: authSpaUrl, currentSpa: currentSpa })] })), !isWatcher && (jsxs(TabsContent, { className: "mt-4", value: "onboarding", children: [jsx(TabDescription, { icon: jsx(UserPlus, { className: "w-5 h-5" }), title: t('profileAdmin.onboardingTab'), children: t('profileAdmin.onboardingTabDescription') }), jsx(OnboardingTab, { platformKey: tenant, onboardingBasePath: onboardingBasePath })] }))] }) }));
224127
224135
  };
224128
224136
 
224129
224137
  function DeleteApiModal$1({ isOpen, onClose, apiKey, tenantKey }) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@iblai/iblai-js",
3
- "version": "2.10.3",
3
+ "version": "2.11.1",
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,9 +76,9 @@
76
76
  "axios": "1.13.6",
77
77
  "dotenv": "16.6.1",
78
78
  "winston": "3.19.0",
79
- "@iblai/mcp": "1.12.12",
79
+ "@iblai/mcp": "1.12.13",
80
80
  "@iblai/data-layer": "1.13.3",
81
- "@iblai/web-containers": "1.19.15",
81
+ "@iblai/web-containers": "1.20.1",
82
82
  "@iblai/web-utils": "2.4.6"
83
83
  },
84
84
  "peerDependencies": {