@iblai/iblai-js 2.3.5 → 2.3.7

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.
@@ -1,9 +1,9 @@
1
1
  import * as React from 'react';
2
2
  import React__default, { useRef, useEffect, useState, useCallback, useLayoutEffect, forwardRef, createElement as createElement$1, createContext, useContext, useMemo, useReducer, useImperativeHandle, isValidElement, Children, PureComponent, cloneElement, Component, useId as useId$2, useDebugValue, lazy, Suspense } from 'react';
3
3
  import { useDispatch, useSelector } from 'react-redux';
4
- import { selectSessionId, selectActiveChatMessages, useCachedSessionId, chatActions, LOCAL_STORAGE_KEYS, TimeTracker, getInitials, useTenantMetadata, WithPermissions, canWriteField, useStripeUpgrade, openExternalUrl, CHAT_AREA_SIZE, isAlphaNumeric32, checkRbacPermission, getTimeAgo, REQUIRED_ACTIONS_FOR_GROUPS, formatRelativeTime as formatRelativeTime$2, ANONYMOUS_USERNAME, combineCSVData, redirectToAuthSpaJoinTenant, redirectToAuthSpa, getAuthSpaJoinUrl, useOS, selectNumberOfActiveChatMessages, useUsername, selectStreaming, isLoggedIn, TOOLS, hasRemoteAiConfig, isSafariBrowser, useShowAttachment, useShowVoiceCall, useShowVoiceRecorder, useMentorSettings, selectShowingSharedChat, selectRbacPermissions, useShowFreeTrialDialog, useEmbedMode, chatInputSliceSelectors, useResponsive, useAccessingPublicRoute, useVisitingTenant, useModelFileUploadCapabilities, useChatFileUpload, useVoiceChat, selectAttachedFiles, MENTOR_CHAT_DOCUMENTS_EXTENSIONS, chatInputSliceActions, removeFile, WithFormPermissions, MENTOR_VISIBILITY } from '@iblai/web-utils';
4
+ import { selectSessionId, selectActiveChatMessages, useCachedSessionId, chatActions, LOCAL_STORAGE_KEYS, TimeTracker, getInitials, useTenantMetadata, useCurrentTenant, selectRbacPermissions, isPureWatcher, WithPermissions, canWriteField, useStripeUpgrade, openExternalUrl, CHAT_AREA_SIZE, isAlphaNumeric32, checkRbacPermission, getTimeAgo, REQUIRED_ACTIONS_FOR_GROUPS, getVisibleAnalyticsTabs, formatRelativeTime as formatRelativeTime$2, ANONYMOUS_USERNAME, combineCSVData, WATCHER_HIDDEN_REPORTS, redirectToAuthSpaJoinTenant, redirectToAuthSpa, getAuthSpaJoinUrl, useOS, selectNumberOfActiveChatMessages, useUsername, selectStreaming, isLoggedIn, TOOLS, hasRemoteAiConfig, isSafariBrowser, useShowAttachment, useShowVoiceCall, useShowVoiceRecorder, useMentorSettings, selectShowingSharedChat, useShowFreeTrialDialog, useEmbedMode, chatInputSliceSelectors, useResponsive, useAccessingPublicRoute, useVisitingTenant, useModelFileUploadCapabilities, useChatFileUpload, useVoiceChat, selectAttachedFiles, MENTOR_CHAT_DOCUMENTS_EXTENSIONS, chatInputSliceActions, removeFile, WithFormPermissions, MENTOR_VISIBILITY } from '@iblai/web-utils';
5
5
  import * as dataLayer from '@iblai/data-layer';
6
- import { useCreateSessionIdMutation, useTimeTrackingMutation, useGetUserMetadataQuery, useGetUserMetadataEdxQuery, useUpdateUserMetadataMutation, useUpdateUserMetadataEdxMutation, useUploadProfileImageMutation, useResetPasswordMutation, useSelfRetireMutation, useCreateUserInstitutionMutation, useGetUserInstitutionsQuery, useCreateUserEducationMutation, useUpdateUserEducationMutation, useDeleteUserEducationMutation, useGetUserEducationQuery, useCreateUserCompanyMutation, useGetUserCompaniesQuery, useCreateUserExperienceMutation, useUpdateUserExperienceMutation, useDeleteUserExperienceMutation, useGetUserExperienceQuery, useGetUserResumeQuery, useCreateUserResumeMutation, useGetMySubscriptionsQuery, useGetItemSubscriptionQuery, useCancelSubscriptionMutation, useGetLearnerDetailsQuery, useGetUserEnrolledCoursesQuery, useGetUserEnrolledProgramsQuery, useGetUserCatalogPathwaysQuery, useGetUsersAsAssertionsQuery, useGetUserEarnedSkillsQuery, useGetUserReportedSkillsQuery, useGetUserDesiredSkillsQuery, useCreateGlobalMemoryMutation, useGetMemsearchStatusQuery, useGetUserMemorySettingsQuery, useUpdateUserMemorySettingsMutation, useGetGlobalMemoriesQuery, useDeleteGlobalMemoryMutation, useInviteUserMutation, usePlatformInvitationsQuery, useCreateCatalogInvitationCourseBulkMutation, useGetCatalogInvitationsCourseQuery, useLazyPlatformUsersQuery, useLazyPlatformUserGroupsQuery, useGetPersonnalizedSearchQuery, useCreateCatalogInvitationProgramBulkMutation, useGetCatalogInvitationsProgramQuery, useUpdateUserRoleMutation, useUpdateUserStatusMutation, useUpdatePlatformUserRoleWithPoliciesMutation, usePlatformUsersQuery, isPoliciesResponse, platformApiSlice, featureTags, useLazyGetRbacTeamsAccessListQuery, useCreateRbacTeamsAccessMutation, useGetRbacGroupsQuery, usePlatformUserGroupsQuery, useCreateRbacGroupMutation, useUpdateRbacGroupMutation, useDeleteRbacGroupMutation, useCreatePlatformUserGroupMutation, useUpdatePlatformUserGroupMutation, useDeletePlatformUserGroupMutation, useGetRbacGroupDetailsQuery, useGetPlatformUserGroupDetailsQuery, useGetRbacPermissionsMutation, useGetRbacRolesQuery, useCreateRbacRoleMutation, useUpdateRbacRoleMutation, useDeleteRbacRoleMutation, useGetRbacRoleDetailsQuery, useGetRbacActionsDefinitionQuery, useGetRbacResourceDiscoveryQuery, useGetRbacResourceListQuery, useGetRbacPoliciesQuery, useCreateRbacPolicyMutation, useUpdateRbacPolicyMutation, useDeleteRbacPolicyMutation, useGetRbacPolicyDetailsQuery, useGetWatchedGroupsQuery, useCreateWatchedGroupMutation, useUpdateWatchedGroupMutation, useDeleteWatchedGroupMutation, useAddWatchedUserMutation, useRemoveWatchedUserMutation, useAddWatcherMutation, useUpdateWatcherMutation, useDeleteWatcherMutation, useGetWatchedUsersQuery, useGetWatchersQuery, WATCHER_NOTIFICATION_EVENTS, WATCHER_NOTIFICATION_EVENT_LABELS, useGetApplicationFormsQuery, useGetApplicationFormDetailQuery, useCreateApplicationFormMutation, useUpdateApplicationFormMutation, useGetApplicationAdminDetailQuery, useInviteApplicationCandidateMutation, useLazyGetApplicationAttachmentFileQuery, useCreateApplicationWaiverMutation, useDeleteApplicationWaiverMutation, useSubmitApplicationOverrideMutation, useUpdateApplicationPlacementMutation, useDeleteApplicationCourseAssignmentMutation, useCreateApplicationNoteMutation, useUpdateApplicationNoteMutation, useDeleteApplicationNoteMutation, useTransitionApplicationMutation, useLinkApplicationCandidateMutation, useCreateApplicationPlacementsMutation, useGetCustomMentorsQuery, useCreateApplicationCourseAssignmentsMutation, useGetApplicationBlocksQuery, useDeleteApplicationBlockMutation, useGetApplicationsPipelineStatsQuery, useGetApplicationsPipelineQuery, useDeleteApiKeyMutation, useGetApiKeyQuery, useGetApiKeyFieldPermissionsQuery, useUpdateApiKeyMutation, useGetApiKeysQuery, unwrapApiTokenList, useCreateApiKeyMutation, useCreateLLMCredentialMutation, useGetCredentialsSchemaQuery, useGetMaskedLLMCredentialsQuery, useGetLlmsQuery, useDeleteIntegrationCredentialMutation, useDeleteCredentialMutation, useCreateIntegrationCredentialMutation, useGetIntegrationCredentialsSchemaQuery, useGetMaskedIntegrationCredentialsQuery, useGetAccountBillingInfoQuery, useUpdateAutoRechargeInfoMutation, useTriggerAutoRechargeMutation, useCreateStripeCustomerPortalMutation, useSetPlatformConfigurationsMutation, useGetPlatformConfigurationsQuery, useUpdatePlatformMembershipMutation, useGetPlatformMembershipQuery, useGetCustomDomainsQuery, useCreateCustomDomainMutation, useDeleteCustomDomainMutation, useGetStudentMentorCreationStatusQuery, useSetStudentMentorCreationStatusMutation, coreApiSlice, recommendationPromptTypeEnum, useGetRecommendedPromptsListQuery, useCreateRecommendedPromptMutation, useUpdateRecommendedPromptMutation, useDeleteRecommendedPromptMutation, useLazyGetPublicPlatformImageAssetFileUrlQuery, useUpdateTenantMetadataMutation, useCreatePlatformImageAssetMutation, useGetProviderConfigQuery, useCreateProviderConfigMutation, useDeleteProviderConfigMutation, useGetExternalMappingQuery, useGetCredentialsListQuery, useCreateExternalMappingMutation, useDeleteExternalMappingMutation, useGetMemsearchConfigQuery, useUpdateMemsearchConfigMutation, useGetStripeConnectStatusQuery, useStartStripeConnectOnboardingMutation, useLazyGetStripeConnectDashboardQuery, useGetAiSearchMentorsQuery, useListPaywallsQuery, useListPricesQuery, useCreatePriceMutation, useUpdatePriceMutation, useDeletePriceMutation, useGetPaywallConfigQuery, useEnablePaywallMutation, useUpdatePaywallMutation, useGetNotificationsCountQuery, useLazyGetNotificationsQuery, useMarkAllAsReadMutation, useCreateNotificationPreviewMutation, useSendNotificationMutation, useGetMentorsQuery, useUpdateTemplateMutation, useGetTemplateDetailsQuery, useGetTemplatesQuery, useLazyGetTemplateDetailsQuery, useToggleTemplateMutation, useGetTopicsStatsQuery, useGetUsersStatsQuery, useGetSessionStatsQuery, useGetTopicsDetailsStatsQuery, useGetAccessTimeHeatmapQuery, useGetUserDetailsStatsQuery, useGetTranscriptsConversationHeadlineQuery, useGetAverageRatingQuery, useGetFinancialStatsQuery, useGetDetailedFinancialStatsQuery, useGetTranscriptsMessagesDetailsQuery, useGetTranscriptsMessagesQuery, useGetReportDetailQuery, useLazyGetDownloadReportFromURLQuery, useGetMentorPublicSettingsQuery, useGetReportsQuery, useCreateReportMutation, useGetContentAnalyticsQuery, useGetContentAnalyticsDetailsQuery, useGetRevenueQuery, useListSubscribersQuery, useGetAuditLogsQuery, useLazyGetCourseMetaDataQuery, useLazyGetCourseCompletionOutlinesQuery, useLazyGetCourseEligibilityQuery, useLazyGetUserEnrolledCoursesQuery, useLazyGetUserAssignedCoursesQuery, useLazyGetUserCredentialsQuery, useLazyGetOverTimeActivityQuery, useLazyGetCatalogSearchQuery, useCreateOrUpdateUserReportedSkillMutation, useCreateOrUpdateUserDesiredSkillMutation, useLazyGetPathwayListQuery, useLazyGetUserAssignedPathwaysQuery, useLazyGetUserEnrolledPathwaysQuery, useLazyGetPathwayCompletionQuery, useLazyGetProgramListQuery, useLazyGetProgramCompletionQuery, useLazyGetUserEnrolledProgramsQuery, useLazyGetAssignedProgramsQuery, useLazyGetUserSkillsPointsQuery, useLazyGetUserReportedSkillsQuery, useLazyGetUserDesiredSkillsQuery, useLazyGetUserCatalogPathwaysQuery, useLazyGetPerLearnerInfoQuery, useLazyGetEdxSSOTokenQuery, useCreateCourseEnrollmentMutation, useCreateStripeCheckoutSessionMutation, useLazyGetCourseProgressQuery, useLazyGetCourseCompletionQuery, useLazyGetPersonnalizedSearchQuery, useUpdateExamAttemptMutation, useStartExamMutation, useLazyGetExamInfoQuery, useGetClawMentorConfigQuery, useGetClawInstancesQuery, useGetAgentConfigQuery, useUpdateClawMentorConfigMutation, useCreateClawMentorConfigMutation, useDeleteClawMentorConfigMutation, usePushClawConfigMutation, useCreateClawInstanceMutation, useDeleteClawInstanceMutation, useUpdateAgentConfigMutation, useHealthCheckClawInstanceMutation, useTestConnectivityClawInstanceMutation, useUpdateClawInstanceMutation, useGetAgentSkillResourcesQuery, useCreateAgentSkillResourceMutation, useUpdateAgentSkillResourceMutation, useUploadAgentSkillResourceAssetMutation, useDeleteAgentSkillResourceMutation, useGetAgentSkillsQuery, useGetMentorSkillAssignmentsQuery, useCreateMentorSkillAssignmentMutation, useUpdateMentorSkillAssignmentMutation, useDeleteMentorSkillAssignmentMutation, useCreateAgentSkillMutation, useUpdateAgentSkillMutation, useDeleteAgentSkillMutation, resolveEffectiveAgentSkills, filterSlashSkills, useCreateCheckoutMutation, useGetUserProjectsQuery, useUpdateUserProjectMutation, useGetTrainingDocumentsQuery, useGetVectorDocumentsQuery, useGetMentorMemoriesListQuery, useGetMemoryCategoriesAdminQuery, useDeleteMentorMemoryMutation, useUpdateMentorMemoryMutation, useCreateMentorMemoryMutation, useLazyGetConnectedServiceAuthUrlQuery, useCreateUserProjectMutation, useDeleteUserProjectMutation, useGetUserProjectDetailsQuery, useEditTrainingDocumentMutation, useAddTrainingDocumentMutation, useLazyGetCredentialsQuery, useGetMentorSettingsQuery, useEditMentorMutation, useGetMentorCategoriesQuery, useCreateMentorMutation, useUpdateUserPlatformMetadataMutation, useGetApplicationStatusQuery, useListOwnApplicationsQuery, useGetApplicationFormQuery, useWithdrawApplicationMutation, useRenewApplicationMutation, useCreateApplicationDraftMutation, useSubmitApplicationMutation, useUpdateApplicationMutation, useUploadApplicationAttachmentMutation, useDeleteApplicationAttachmentMutation, useGetPromptCategoriesQuery, useCreatePromptMutation, useDeletePromptMutation, useGetPromptsSearchQuery, useUpdatePromptMutation, useDeleteTrainingDocumentMutation, useGetTrainingDocumentRetrainScheduleQuery, useCreateTrainingDocumentRetrainScheduleMutation } from '@iblai/data-layer';
6
+ import { useCreateSessionIdMutation, useTimeTrackingMutation, useGetUserMetadataQuery, useGetUserMetadataEdxQuery, useUpdateUserMetadataMutation, useUpdateUserMetadataEdxMutation, useUploadProfileImageMutation, useResetPasswordMutation, useSelfRetireMutation, useCreateUserInstitutionMutation, useGetUserInstitutionsQuery, useCreateUserEducationMutation, useUpdateUserEducationMutation, useDeleteUserEducationMutation, useGetUserEducationQuery, useCreateUserCompanyMutation, useGetUserCompaniesQuery, useCreateUserExperienceMutation, useUpdateUserExperienceMutation, useDeleteUserExperienceMutation, useGetUserExperienceQuery, useGetUserResumeQuery, useCreateUserResumeMutation, useGetMySubscriptionsQuery, useGetItemSubscriptionQuery, useCancelSubscriptionMutation, useGetLearnerDetailsQuery, useGetUserEnrolledCoursesQuery, useGetUserEnrolledProgramsQuery, useGetUserCatalogPathwaysQuery, useGetUsersAsAssertionsQuery, useGetUserEarnedSkillsQuery, useGetUserReportedSkillsQuery, useGetUserDesiredSkillsQuery, useCreateGlobalMemoryMutation, useGetMemsearchStatusQuery, useGetUserMemorySettingsQuery, useUpdateUserMemorySettingsMutation, useGetGlobalMemoriesQuery, useGetAllMentorMemoriesQuery, useDeleteGlobalMemoryMutation, useInviteUserMutation, usePlatformInvitationsQuery, useCreateCatalogInvitationCourseBulkMutation, useGetCatalogInvitationsCourseQuery, useLazyPlatformUsersQuery, useLazyPlatformUserGroupsQuery, useGetPersonnalizedSearchQuery, useCreateCatalogInvitationProgramBulkMutation, useGetCatalogInvitationsProgramQuery, useUpdateUserRoleMutation, useUpdateUserStatusMutation, useUpdatePlatformUserRoleWithPoliciesMutation, usePlatformUsersQuery, useGetAccessibleUsersQuery, isPoliciesResponse, platformApiSlice, featureTags, useLazyGetRbacTeamsAccessListQuery, useCreateRbacTeamsAccessMutation, useGetRbacGroupsQuery, usePlatformUserGroupsQuery, useCreateRbacGroupMutation, useUpdateRbacGroupMutation, useDeleteRbacGroupMutation, useCreatePlatformUserGroupMutation, useUpdatePlatformUserGroupMutation, useDeletePlatformUserGroupMutation, useGetRbacGroupDetailsQuery, useGetPlatformUserGroupDetailsQuery, useGetRbacPermissionsMutation, useGetRbacRolesQuery, useCreateRbacRoleMutation, useUpdateRbacRoleMutation, useDeleteRbacRoleMutation, useGetRbacRoleDetailsQuery, useGetRbacActionsDefinitionQuery, useGetRbacResourceDiscoveryQuery, useGetRbacResourceListQuery, useGetRbacPoliciesQuery, useCreateRbacPolicyMutation, useUpdateRbacPolicyMutation, useDeleteRbacPolicyMutation, useGetRbacPolicyDetailsQuery, useGetWatchedGroupsQuery, useCreateWatchedGroupMutation, useUpdateWatchedGroupMutation, useDeleteWatchedGroupMutation, useAddWatchedUserMutation, useRemoveWatchedUserMutation, useAddWatcherMutation, useUpdateWatcherMutation, useDeleteWatcherMutation, useGetWatchedUsersQuery, useGetWatchersQuery, WATCHER_NOTIFICATION_EVENTS, WATCHER_NOTIFICATION_EVENT_LABELS, useGetApplicationFormsQuery, useGetApplicationFormDetailQuery, useCreateApplicationFormMutation, useUpdateApplicationFormMutation, useGetApplicationAdminDetailQuery, useInviteApplicationCandidateMutation, useLazyGetApplicationAttachmentFileQuery, useCreateApplicationWaiverMutation, useDeleteApplicationWaiverMutation, useSubmitApplicationOverrideMutation, useUpdateApplicationPlacementMutation, useDeleteApplicationCourseAssignmentMutation, useCreateApplicationNoteMutation, useUpdateApplicationNoteMutation, useDeleteApplicationNoteMutation, useTransitionApplicationMutation, useLinkApplicationCandidateMutation, useCreateApplicationPlacementsMutation, useGetCustomMentorsQuery, useCreateApplicationCourseAssignmentsMutation, useGetApplicationBlocksQuery, useDeleteApplicationBlockMutation, useGetApplicationsPipelineStatsQuery, useGetApplicationsPipelineQuery, useDeleteApiKeyMutation, useGetApiKeyQuery, useGetApiKeyFieldPermissionsQuery, useUpdateApiKeyMutation, useGetApiKeysQuery, unwrapApiTokenList, useCreateApiKeyMutation, useCreateLLMCredentialMutation, useGetCredentialsSchemaQuery, useGetMaskedLLMCredentialsQuery, useGetLlmsQuery, useDeleteIntegrationCredentialMutation, useDeleteCredentialMutation, useCreateIntegrationCredentialMutation, useGetIntegrationCredentialsSchemaQuery, useGetMaskedIntegrationCredentialsQuery, useGetAccountBillingInfoQuery, useUpdateAutoRechargeInfoMutation, useTriggerAutoRechargeMutation, useCreateStripeCustomerPortalMutation, useSetPlatformConfigurationsMutation, useGetPlatformConfigurationsQuery, useUpdatePlatformMembershipMutation, useGetPlatformMembershipQuery, useGetCustomDomainsQuery, useCreateCustomDomainMutation, useDeleteCustomDomainMutation, useGetStudentMentorCreationStatusQuery, useSetStudentMentorCreationStatusMutation, coreApiSlice, recommendationPromptTypeEnum, useGetRecommendedPromptsListQuery, useCreateRecommendedPromptMutation, useUpdateRecommendedPromptMutation, useDeleteRecommendedPromptMutation, useLazyGetPublicPlatformImageAssetFileUrlQuery, useUpdateTenantMetadataMutation, useCreatePlatformImageAssetMutation, useGetProviderConfigQuery, useCreateProviderConfigMutation, useDeleteProviderConfigMutation, useGetExternalMappingQuery, useGetCredentialsListQuery, useCreateExternalMappingMutation, useDeleteExternalMappingMutation, useGetMemsearchConfigQuery, useUpdateMemsearchConfigMutation, useGetStripeConnectStatusQuery, useStartStripeConnectOnboardingMutation, useLazyGetStripeConnectDashboardQuery, useGetAiSearchMentorsQuery, useListPaywallsQuery, useListPricesQuery, useCreatePriceMutation, useUpdatePriceMutation, useDeletePriceMutation, useGetPaywallConfigQuery, useEnablePaywallMutation, useUpdatePaywallMutation, useGetNotificationsCountQuery, useLazyGetNotificationsQuery, useMarkAllAsReadMutation, useCreateNotificationPreviewMutation, useSendNotificationMutation, useGetMentorsQuery, useUpdateTemplateMutation, useGetTemplateDetailsQuery, useGetTemplatesQuery, useLazyGetTemplateDetailsQuery, useToggleTemplateMutation, useGetTopicsStatsQuery, useGetUsersStatsQuery, useGetSessionStatsQuery, useGetTopicsDetailsStatsQuery, useGetAccessTimeHeatmapQuery, useGetUserDetailsStatsQuery, useGetTranscriptsConversationHeadlineQuery, useGetAverageRatingQuery, useGetFinancialStatsQuery, useGetDetailedFinancialStatsQuery, useGetTranscriptsMessagesDetailsQuery, useGetTranscriptsMessagesQuery, useGetReportDetailQuery, useLazyGetDownloadReportFromURLQuery, useGetMentorPublicSettingsQuery, useGetReportsQuery, useCreateReportMutation, useGetContentAnalyticsQuery, useGetContentAnalyticsDetailsQuery, useGetRevenueQuery, useListSubscribersQuery, useGetAuditLogsQuery, useGetMentorMemoriesListQuery, useGetMentorMemoriesQuery, useGetMemoryCategoriesAdminQuery, useLazyGetCourseMetaDataQuery, useLazyGetCourseCompletionOutlinesQuery, useLazyGetCourseEligibilityQuery, useLazyGetUserEnrolledCoursesQuery, useLazyGetUserAssignedCoursesQuery, useLazyGetUserCredentialsQuery, useLazyGetOverTimeActivityQuery, useLazyGetCatalogSearchQuery, useCreateOrUpdateUserReportedSkillMutation, useCreateOrUpdateUserDesiredSkillMutation, useLazyGetPathwayListQuery, useLazyGetUserAssignedPathwaysQuery, useLazyGetUserEnrolledPathwaysQuery, useLazyGetPathwayCompletionQuery, useLazyGetProgramListQuery, useLazyGetProgramCompletionQuery, useLazyGetUserEnrolledProgramsQuery, useLazyGetAssignedProgramsQuery, useLazyGetUserSkillsPointsQuery, useLazyGetUserReportedSkillsQuery, useLazyGetUserDesiredSkillsQuery, useLazyGetUserCatalogPathwaysQuery, useLazyGetPerLearnerInfoQuery, useLazyGetEdxSSOTokenQuery, useCreateCourseEnrollmentMutation, useCreateStripeCheckoutSessionMutation, useLazyGetCourseProgressQuery, useLazyGetCourseCompletionQuery, useLazyGetPersonnalizedSearchQuery, useUpdateExamAttemptMutation, useStartExamMutation, useLazyGetExamInfoQuery, useGetClawMentorConfigQuery, useGetClawInstancesQuery, useGetAgentConfigQuery, useUpdateClawMentorConfigMutation, useCreateClawMentorConfigMutation, useDeleteClawMentorConfigMutation, usePushClawConfigMutation, useCreateClawInstanceMutation, useDeleteClawInstanceMutation, useUpdateAgentConfigMutation, useHealthCheckClawInstanceMutation, useTestConnectivityClawInstanceMutation, useUpdateClawInstanceMutation, useGetAgentSkillResourcesQuery, useCreateAgentSkillResourceMutation, useUpdateAgentSkillResourceMutation, useUploadAgentSkillResourceAssetMutation, useDeleteAgentSkillResourceMutation, useGetAgentSkillsQuery, useGetMentorSkillAssignmentsQuery, useCreateMentorSkillAssignmentMutation, useUpdateMentorSkillAssignmentMutation, useDeleteMentorSkillAssignmentMutation, useCreateAgentSkillMutation, useUpdateAgentSkillMutation, useDeleteAgentSkillMutation, resolveEffectiveAgentSkills, filterSlashSkills, useCreateCheckoutMutation, useGetUserProjectsQuery, useUpdateUserProjectMutation, useGetTrainingDocumentsQuery, useGetVectorDocumentsQuery, useDeleteMentorMemoryMutation, useUpdateMentorMemoryMutation, useCreateMentorMemoryMutation, useLazyGetConnectedServiceAuthUrlQuery, useCreateUserProjectMutation, useDeleteUserProjectMutation, useGetUserProjectDetailsQuery, useEditTrainingDocumentMutation, useAddTrainingDocumentMutation, useLazyGetCredentialsQuery, useGetMentorSettingsQuery, useEditMentorMutation, useGetMentorCategoriesQuery, useCreateMentorMutation, useUpdateUserPlatformMetadataMutation, useGetApplicationStatusQuery, useListOwnApplicationsQuery, useGetApplicationFormQuery, useWithdrawApplicationMutation, useRenewApplicationMutation, useCreateApplicationDraftMutation, useSubmitApplicationMutation, useUpdateApplicationMutation, useUploadApplicationAttachmentMutation, useDeleteApplicationAttachmentMutation, useGetPromptCategoriesQuery, useCreatePromptMutation, useDeletePromptMutation, useGetPromptsSearchQuery, useUpdatePromptMutation, useDeleteTrainingDocumentMutation, useGetTrainingDocumentRetrainScheduleQuery, useCreateTrainingDocumentRetrainScheduleMutation } from '@iblai/data-layer';
7
7
  import { toast } from 'sonner';
8
8
  import { jsx, Fragment as Fragment$1, jsxs } from 'react/jsx-runtime';
9
9
  import * as ReactDOM from 'react-dom';
@@ -54884,7 +54884,7 @@ const createLucideIcon = (iconName, iconNode) => {
54884
54884
  */
54885
54885
 
54886
54886
 
54887
- const __iconNode$2l = [
54887
+ const __iconNode$2m = [
54888
54888
  [
54889
54889
  "path",
54890
54890
  {
@@ -54893,7 +54893,7 @@ const __iconNode$2l = [
54893
54893
  }
54894
54894
  ]
54895
54895
  ];
54896
- const Activity = createLucideIcon("activity", __iconNode$2l);
54896
+ const Activity = createLucideIcon("activity", __iconNode$2m);
54897
54897
 
54898
54898
  /**
54899
54899
  * @license lucide-react v0.528.0 - ISC
@@ -54903,12 +54903,12 @@ const Activity = createLucideIcon("activity", __iconNode$2l);
54903
54903
  */
54904
54904
 
54905
54905
 
54906
- const __iconNode$2k = [
54906
+ const __iconNode$2l = [
54907
54907
  ["path", { d: "M17 12H7", key: "16if0g" }],
54908
54908
  ["path", { d: "M19 18H5", key: "18s9l3" }],
54909
54909
  ["path", { d: "M21 6H3", key: "1jwq7v" }]
54910
54910
  ];
54911
- const AlignCenter = createLucideIcon("align-center", __iconNode$2k);
54911
+ const AlignCenter = createLucideIcon("align-center", __iconNode$2l);
54912
54912
 
54913
54913
  /**
54914
54914
  * @license lucide-react v0.528.0 - ISC
@@ -54918,12 +54918,12 @@ const AlignCenter = createLucideIcon("align-center", __iconNode$2k);
54918
54918
  */
54919
54919
 
54920
54920
 
54921
- const __iconNode$2j = [
54921
+ const __iconNode$2k = [
54922
54922
  ["path", { d: "M15 12H3", key: "6jk70r" }],
54923
54923
  ["path", { d: "M17 18H3", key: "1amg6g" }],
54924
54924
  ["path", { d: "M21 6H3", key: "1jwq7v" }]
54925
54925
  ];
54926
- const AlignLeft = createLucideIcon("align-left", __iconNode$2j);
54926
+ const AlignLeft = createLucideIcon("align-left", __iconNode$2k);
54927
54927
 
54928
54928
  /**
54929
54929
  * @license lucide-react v0.528.0 - ISC
@@ -54933,12 +54933,12 @@ const AlignLeft = createLucideIcon("align-left", __iconNode$2j);
54933
54933
  */
54934
54934
 
54935
54935
 
54936
- const __iconNode$2i = [
54936
+ const __iconNode$2j = [
54937
54937
  ["path", { d: "M21 12H9", key: "dn1m92" }],
54938
54938
  ["path", { d: "M21 18H7", key: "1ygte8" }],
54939
54939
  ["path", { d: "M21 6H3", key: "1jwq7v" }]
54940
54940
  ];
54941
- const AlignRight = createLucideIcon("align-right", __iconNode$2i);
54941
+ const AlignRight = createLucideIcon("align-right", __iconNode$2j);
54942
54942
 
54943
54943
  /**
54944
54944
  * @license lucide-react v0.528.0 - ISC
@@ -54948,12 +54948,12 @@ const AlignRight = createLucideIcon("align-right", __iconNode$2i);
54948
54948
  */
54949
54949
 
54950
54950
 
54951
- const __iconNode$2h = [
54951
+ const __iconNode$2i = [
54952
54952
  ["rect", { width: "20", height: "5", x: "2", y: "3", rx: "1", key: "1wp1u1" }],
54953
54953
  ["path", { d: "M4 8v11a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8", key: "1s80jp" }],
54954
54954
  ["path", { d: "M10 12h4", key: "a56b0p" }]
54955
54955
  ];
54956
- const Archive = createLucideIcon("archive", __iconNode$2h);
54956
+ const Archive = createLucideIcon("archive", __iconNode$2i);
54957
54957
 
54958
54958
  /**
54959
54959
  * @license lucide-react v0.528.0 - ISC
@@ -54963,11 +54963,11 @@ const Archive = createLucideIcon("archive", __iconNode$2h);
54963
54963
  */
54964
54964
 
54965
54965
 
54966
- const __iconNode$2g = [
54966
+ const __iconNode$2h = [
54967
54967
  ["path", { d: "M12 5v14", key: "s699le" }],
54968
54968
  ["path", { d: "m19 12-7 7-7-7", key: "1idqje" }]
54969
54969
  ];
54970
- const ArrowDown = createLucideIcon("arrow-down", __iconNode$2g);
54970
+ const ArrowDown = createLucideIcon("arrow-down", __iconNode$2h);
54971
54971
 
54972
54972
  /**
54973
54973
  * @license lucide-react v0.528.0 - ISC
@@ -54977,11 +54977,11 @@ const ArrowDown = createLucideIcon("arrow-down", __iconNode$2g);
54977
54977
  */
54978
54978
 
54979
54979
 
54980
- const __iconNode$2f = [
54980
+ const __iconNode$2g = [
54981
54981
  ["path", { d: "m12 19-7-7 7-7", key: "1l729n" }],
54982
54982
  ["path", { d: "M19 12H5", key: "x3x0zl" }]
54983
54983
  ];
54984
- const ArrowLeft = createLucideIcon("arrow-left", __iconNode$2f);
54984
+ const ArrowLeft = createLucideIcon("arrow-left", __iconNode$2g);
54985
54985
 
54986
54986
  /**
54987
54987
  * @license lucide-react v0.528.0 - ISC
@@ -54991,11 +54991,11 @@ const ArrowLeft = createLucideIcon("arrow-left", __iconNode$2f);
54991
54991
  */
54992
54992
 
54993
54993
 
54994
- const __iconNode$2e = [
54994
+ const __iconNode$2f = [
54995
54995
  ["path", { d: "M5 12h14", key: "1ays0h" }],
54996
54996
  ["path", { d: "m12 5 7 7-7 7", key: "xquz4c" }]
54997
54997
  ];
54998
- const ArrowRight = createLucideIcon("arrow-right", __iconNode$2e);
54998
+ const ArrowRight = createLucideIcon("arrow-right", __iconNode$2f);
54999
54999
 
55000
55000
  /**
55001
55001
  * @license lucide-react v0.528.0 - ISC
@@ -55005,11 +55005,11 @@ const ArrowRight = createLucideIcon("arrow-right", __iconNode$2e);
55005
55005
  */
55006
55006
 
55007
55007
 
55008
- const __iconNode$2d = [
55008
+ const __iconNode$2e = [
55009
55009
  ["path", { d: "m5 12 7-7 7 7", key: "hav0vg" }],
55010
55010
  ["path", { d: "M12 19V5", key: "x0mq9r" }]
55011
55011
  ];
55012
- const ArrowUp = createLucideIcon("arrow-up", __iconNode$2d);
55012
+ const ArrowUp = createLucideIcon("arrow-up", __iconNode$2e);
55013
55013
 
55014
55014
  /**
55015
55015
  * @license lucide-react v0.528.0 - ISC
@@ -55019,7 +55019,7 @@ const ArrowUp = createLucideIcon("arrow-up", __iconNode$2d);
55019
55019
  */
55020
55020
 
55021
55021
 
55022
- const __iconNode$2c = [
55022
+ const __iconNode$2d = [
55023
55023
  [
55024
55024
  "path",
55025
55025
  {
@@ -55029,7 +55029,7 @@ const __iconNode$2c = [
55029
55029
  ],
55030
55030
  ["circle", { cx: "12", cy: "8", r: "6", key: "1vp47v" }]
55031
55031
  ];
55032
- const Award = createLucideIcon("award", __iconNode$2c);
55032
+ const Award = createLucideIcon("award", __iconNode$2d);
55033
55033
 
55034
55034
  /**
55035
55035
  * @license lucide-react v0.528.0 - ISC
@@ -55039,11 +55039,11 @@ const Award = createLucideIcon("award", __iconNode$2c);
55039
55039
  */
55040
55040
 
55041
55041
 
55042
- const __iconNode$2b = [
55042
+ const __iconNode$2c = [
55043
55043
  ["path", { d: "M4.929 4.929 19.07 19.071", key: "196cmz" }],
55044
55044
  ["circle", { cx: "12", cy: "12", r: "10", key: "1mglay" }]
55045
55045
  ];
55046
- const Ban = createLucideIcon("ban", __iconNode$2b);
55046
+ const Ban = createLucideIcon("ban", __iconNode$2c);
55047
55047
 
55048
55048
  /**
55049
55049
  * @license lucide-react v0.528.0 - ISC
@@ -55053,12 +55053,12 @@ const Ban = createLucideIcon("ban", __iconNode$2b);
55053
55053
  */
55054
55054
 
55055
55055
 
55056
- const __iconNode$2a = [
55056
+ const __iconNode$2b = [
55057
55057
  ["rect", { width: "20", height: "12", x: "2", y: "6", rx: "2", key: "9lu3g6" }],
55058
55058
  ["circle", { cx: "12", cy: "12", r: "2", key: "1c9p78" }],
55059
55059
  ["path", { d: "M6 12h.01M18 12h.01", key: "113zkx" }]
55060
55060
  ];
55061
- const Banknote = createLucideIcon("banknote", __iconNode$2a);
55061
+ const Banknote = createLucideIcon("banknote", __iconNode$2b);
55062
55062
 
55063
55063
  /**
55064
55064
  * @license lucide-react v0.528.0 - ISC
@@ -55068,7 +55068,7 @@ const Banknote = createLucideIcon("banknote", __iconNode$2a);
55068
55068
  */
55069
55069
 
55070
55070
 
55071
- const __iconNode$29 = [
55071
+ const __iconNode$2a = [
55072
55072
  ["path", { d: "M10.268 21a2 2 0 0 0 3.464 0", key: "vwvbt9" }],
55073
55073
  ["path", { d: "M22 8c0-2.3-.8-4.3-2-6", key: "5bb3ad" }],
55074
55074
  [
@@ -55080,7 +55080,7 @@ const __iconNode$29 = [
55080
55080
  ],
55081
55081
  ["path", { d: "M4 2C2.8 3.7 2 5.7 2 8", key: "tap9e0" }]
55082
55082
  ];
55083
- const BellRing = createLucideIcon("bell-ring", __iconNode$29);
55083
+ const BellRing = createLucideIcon("bell-ring", __iconNode$2a);
55084
55084
 
55085
55085
  /**
55086
55086
  * @license lucide-react v0.528.0 - ISC
@@ -55090,7 +55090,7 @@ const BellRing = createLucideIcon("bell-ring", __iconNode$29);
55090
55090
  */
55091
55091
 
55092
55092
 
55093
- const __iconNode$28 = [
55093
+ const __iconNode$29 = [
55094
55094
  ["path", { d: "M10.268 21a2 2 0 0 0 3.464 0", key: "vwvbt9" }],
55095
55095
  [
55096
55096
  "path",
@@ -55100,7 +55100,7 @@ const __iconNode$28 = [
55100
55100
  }
55101
55101
  ]
55102
55102
  ];
55103
- const Bell = createLucideIcon("bell", __iconNode$28);
55103
+ const Bell = createLucideIcon("bell", __iconNode$29);
55104
55104
 
55105
55105
  /**
55106
55106
  * @license lucide-react v0.528.0 - ISC
@@ -55110,13 +55110,13 @@ const Bell = createLucideIcon("bell", __iconNode$28);
55110
55110
  */
55111
55111
 
55112
55112
 
55113
- const __iconNode$27 = [
55113
+ const __iconNode$28 = [
55114
55114
  [
55115
55115
  "path",
55116
55116
  { d: "M6 12h9a4 4 0 0 1 0 8H7a1 1 0 0 1-1-1V5a1 1 0 0 1 1-1h7a4 4 0 0 1 0 8", key: "mg9rjx" }
55117
55117
  ]
55118
55118
  ];
55119
- const Bold$1 = createLucideIcon("bold", __iconNode$27);
55119
+ const Bold$1 = createLucideIcon("bold", __iconNode$28);
55120
55120
 
55121
55121
  /**
55122
55122
  * @license lucide-react v0.528.0 - ISC
@@ -55126,7 +55126,7 @@ const Bold$1 = createLucideIcon("bold", __iconNode$27);
55126
55126
  */
55127
55127
 
55128
55128
 
55129
- const __iconNode$26 = [
55129
+ const __iconNode$27 = [
55130
55130
  ["path", { d: "M12 7v14", key: "1akyts" }],
55131
55131
  [
55132
55132
  "path",
@@ -55136,7 +55136,7 @@ const __iconNode$26 = [
55136
55136
  }
55137
55137
  ]
55138
55138
  ];
55139
- const BookOpen = createLucideIcon("book-open", __iconNode$26);
55139
+ const BookOpen = createLucideIcon("book-open", __iconNode$27);
55140
55140
 
55141
55141
  /**
55142
55142
  * @license lucide-react v0.528.0 - ISC
@@ -55146,7 +55146,7 @@ const BookOpen = createLucideIcon("book-open", __iconNode$26);
55146
55146
  */
55147
55147
 
55148
55148
 
55149
- const __iconNode$25 = [
55149
+ const __iconNode$26 = [
55150
55150
  ["path", { d: "M12 8V4H8", key: "hb8ula" }],
55151
55151
  ["rect", { width: "16", height: "12", x: "4", y: "8", rx: "2", key: "enze0r" }],
55152
55152
  ["path", { d: "M2 14h2", key: "vft8re" }],
@@ -55154,7 +55154,27 @@ const __iconNode$25 = [
55154
55154
  ["path", { d: "M15 13v2", key: "1xurst" }],
55155
55155
  ["path", { d: "M9 13v2", key: "rq6x2g" }]
55156
55156
  ];
55157
- const Bot = createLucideIcon("bot", __iconNode$25);
55157
+ const Bot = createLucideIcon("bot", __iconNode$26);
55158
+
55159
+ /**
55160
+ * @license lucide-react v0.528.0 - ISC
55161
+ *
55162
+ * This source code is licensed under the ISC license.
55163
+ * See the LICENSE file in the root directory of this source tree.
55164
+ */
55165
+
55166
+
55167
+ const __iconNode$25 = [
55168
+ ["path", { d: "M12 18V5", key: "adv99a" }],
55169
+ ["path", { d: "M15 13a4.17 4.17 0 0 1-3-4 4.17 4.17 0 0 1-3 4", key: "1e3is1" }],
55170
+ ["path", { d: "M17.598 6.5A3 3 0 1 0 12 5a3 3 0 1 0-5.598 1.5", key: "1gqd8o" }],
55171
+ ["path", { d: "M17.997 5.125a4 4 0 0 1 2.526 5.77", key: "iwvgf7" }],
55172
+ ["path", { d: "M18 18a4 4 0 0 0 2-7.464", key: "efp6ie" }],
55173
+ ["path", { d: "M19.967 17.483A4 4 0 1 1 12 18a4 4 0 1 1-7.967-.517", key: "1gq6am" }],
55174
+ ["path", { d: "M6 18a4 4 0 0 1-2-7.464", key: "k1g0md" }],
55175
+ ["path", { d: "M6.003 5.125a4 4 0 0 0-2.526 5.77", key: "q97ue3" }]
55176
+ ];
55177
+ const Brain = createLucideIcon("brain", __iconNode$25);
55158
55178
 
55159
55179
  /**
55160
55180
  * @license lucide-react v0.528.0 - ISC
@@ -60619,6 +60639,37 @@ var analyticsAnalyticsFinancialStats$3 = {
60619
60639
  goToLastPage: "Go to last page",
60620
60640
  paginationShowing: "Showing {from} to {to} of {total} results"
60621
60641
  };
60642
+ var analyticsAnalyticsMemoryStats$3 = {
60643
+ noPermission: "You do not have permission to view user memories.",
60644
+ scopeLabel: "Memory scope",
60645
+ scopeMentor: "This Agent",
60646
+ scopeAllMentors: "All Agents",
60647
+ scopeGlobal: "Global",
60648
+ searchAgents: "Search Agents…",
60649
+ searchAgentsTitle: "Search Agents",
60650
+ clearAgentSearch: "Clear Agent Search",
60651
+ contentPlaceholder: "Search memory content",
60652
+ pickDateRange: "Pick a Date Range",
60653
+ allCategories: "All Categories",
60654
+ byCategory: "Memories by Category",
60655
+ categoryCount: "{count} ({percent}%)",
60656
+ loadError: "An error occurred while loading memories.",
60657
+ noMemories: "No memories have been captured yet.",
60658
+ detailTitle: "Memory Detail",
60659
+ detailUser: "User",
60660
+ detailAgent: "Agent",
60661
+ detailCategory: "Category",
60662
+ detailSource: "Source",
60663
+ detailCaptured: "Captured",
60664
+ detailSession: "Session",
60665
+ sourceAuto: "Auto-captured",
60666
+ sourceManual: "Added manually",
60667
+ colUser: "USER",
60668
+ colMemory: "MEMORY",
60669
+ colAgent: "AGENT",
60670
+ colCategory: "CATEGORY",
60671
+ colCaptured: "CAPTURED"
60672
+ };
60622
60673
  var analyticsAnalyticsMonetizationStats$3 = {
60623
60674
  totalRevenue: "Total Revenue",
60624
60675
  totalSales: "Total Sales",
@@ -60864,6 +60915,13 @@ var analyticsStatCard$3 = {
60864
60915
  ariaLabel: "{title} mini card",
60865
60916
  ariaLabelValue: "{title} mini card value"
60866
60917
  };
60918
+ var analyticsUserFilterSelect$3 = {
60919
+ filterByUser: "Filter by user",
60920
+ you: "You",
60921
+ searchPlaceholder: "Search users…",
60922
+ noUsersFound: "No users found.",
60923
+ loadingUsers: "Loading users…"
60924
+ };
60867
60925
  var apiTabApiKeyModal$3 = {
60868
60926
  title: "API Key",
60869
60927
  dialogDescription: "Copy and paste the API key.",
@@ -62567,12 +62625,14 @@ var memoryMemoryTab$3 = {
62567
62625
  useMemoryLabelDesc: "When enabled, the AI will use what it knows about you to personalize responses.",
62568
62626
  useMemoryAriaLabel: "Use memory in responses {state}",
62569
62627
  sectionMyMemories: "My Memories",
62628
+ sectionMyMemoriesPreview: "Memories",
62570
62629
  addMemoryButton: "Add Memory",
62571
62630
  autoGeneratedMemoryAriaLabel: "Auto-generated memory",
62572
62631
  manuallyAddedMemoryAriaLabel: "Manually added memory",
62573
62632
  autoBadge: "auto",
62574
62633
  deleteMemoryAriaLabel: "Delete memory: {excerpt}",
62575
62634
  noMemoriesYet: "No memories yet. The AI will start remembering information from your conversations, or you can add memories manually.",
62635
+ noMemoriesYetPreview: "No memories yet. The AI has not recorded any information from this user's conversations.",
62576
62636
  stateEnabled: "enabled",
62577
62637
  stateDisabled: "disabled"
62578
62638
  };
@@ -64778,6 +64838,10 @@ var analyticsTabLabels$3 = {
64778
64838
  label: "Transcripts",
64779
64839
  description: "Read full conversation transcripts message by message."
64780
64840
  },
64841
+ memory: {
64842
+ label: "Memory",
64843
+ description: "What this agent remembers about each user it talks to."
64844
+ },
64781
64845
  financial: {
64782
64846
  label: "Costs",
64783
64847
  description: "Track token usage and what this agent is costing you."
@@ -65770,11 +65834,12 @@ var graderTabLabels$3 = {
65770
65834
  offHint: "Turn it on to write grading instructions and build your rubric. Anything you set up here is kept safe if you later turn it off."
65771
65835
  },
65772
65836
  subTabs: {
65773
- setup: "Grading setup",
65774
- rubric: "Rubric"
65837
+ setup: "Grading Setup",
65838
+ rubric: "Rubric",
65839
+ results: "Results"
65775
65840
  },
65776
65841
  denied: {
65777
- title: "No access to grading settings",
65842
+ title: "No Access to Grading Settings",
65778
65843
  description: "You don't have permission to view this agent's grading setup. Ask an administrator for access."
65779
65844
  },
65780
65845
  warnings: {
@@ -65782,12 +65847,12 @@ var graderTabLabels$3 = {
65782
65847
  noCriteria: "Grading is on but the rubric is empty — the agent will fail when asked to grade. Add at least one criterion in the Rubric tab."
65783
65848
  },
65784
65849
  config: {
65785
- sectionTitle: "Grading setup",
65850
+ sectionTitle: "Grading Setup",
65786
65851
  gradingMode: {
65787
- label: "What gets graded",
65852
+ label: "What Gets Graded",
65788
65853
  options: {
65789
- submission: "A submission",
65790
- conversation: "The conversation"
65854
+ submission: "A Submission",
65855
+ conversation: "The Conversation"
65791
65856
  },
65792
65857
  help: {
65793
65858
  submission: "The agent grades a piece of work the person hands in, like an essay or answer.",
@@ -65795,16 +65860,16 @@ var graderTabLabels$3 = {
65795
65860
  }
65796
65861
  },
65797
65862
  feedbackMode: {
65798
- label: "Feedback shared with the person",
65863
+ label: "Feedback Shared with the Person",
65799
65864
  options: {
65800
- overall: "Overall feedback only",
65801
- perCriteria: "Feedback per criterion",
65802
- both: "Overall + per criterion"
65865
+ overall: "Overall Feedback Only",
65866
+ perCriteria: "Feedback per Criterion",
65867
+ both: "Overall + per Criterion"
65803
65868
  },
65804
65869
  help: "The overall score is always calculated — this only controls how much detail is shared back."
65805
65870
  },
65806
65871
  instructions: {
65807
- label: "Grading instructions",
65872
+ label: "Grading Instructions",
65808
65873
  placeholder: "Describe what's being graded and anything the grader should know beyond the rubric. E.g. 'You are grading a 500-word persuasive essay on climate policy written by a high-school student. Be encouraging but honest.'",
65809
65874
  help: "Required. This is the context the agent uses every time it grades."
65810
65875
  },
@@ -65816,7 +65881,7 @@ var graderTabLabels$3 = {
65816
65881
  description: "Each row is one thing the agent looks for and how many points it is worth. The overall score is points earned out of the total.",
65817
65882
  needsConfigHint: "Save your grading setup first, then add rubric criteria here.",
65818
65883
  emptyState: "No criteria yet. Add your first one — for example \"Clarity\", 10 points.",
65819
- addButton: "Add criterion",
65884
+ addButton: "Add Criterion",
65820
65885
  columns: {
65821
65886
  name: "Name",
65822
65887
  criteria: "Criteria",
@@ -65825,12 +65890,12 @@ var graderTabLabels$3 = {
65825
65890
  actionsAria: "Actions for {name}",
65826
65891
  edit: "Edit",
65827
65892
  "delete": "Delete",
65828
- totalPoints: "Total possible points: {total}",
65893
+ totalPoints: "Total Possible Points: {total}",
65829
65894
  scoreHint: "Overall score = points earned ÷ {total}.",
65830
65895
  lastCriterionHint: "A rubric needs at least one criterion — add another before removing this one.",
65831
65896
  modal: {
65832
- addTitle: "Add criterion",
65833
- editTitle: "Edit criterion",
65897
+ addTitle: "Add Criterion",
65898
+ editTitle: "Edit Criterion",
65834
65899
  name: {
65835
65900
  label: "Name",
65836
65901
  placeholder: "e.g. Clarity",
@@ -65851,7 +65916,7 @@ var graderTabLabels$3 = {
65851
65916
  cancel: "Cancel"
65852
65917
  },
65853
65918
  deleteModal: {
65854
- title: "Delete criterion",
65919
+ title: "Delete Criterion",
65855
65920
  confirmationPrefix: "Are you sure you want to remove",
65856
65921
  confirmationSuffix: " from the rubric?",
65857
65922
  cancel: "Cancel",
@@ -65869,6 +65934,59 @@ var graderTabLabels$3 = {
65869
65934
  criterionUpdated: "Criterion updated",
65870
65935
  criterionDeleted: "Criterion deleted",
65871
65936
  criterionError: "Couldn't update the rubric"
65937
+ },
65938
+ results: {
65939
+ sectionTitle: "Grade Results",
65940
+ description: "Every grade this agent has issued. Override a score to correct it — the change is pushed back to the LMS the grade came from.",
65941
+ filters: {
65942
+ searchUser: "Search for User",
65943
+ searchUsersPlaceholder: "Search users...",
65944
+ noUsersFound: "No users found.",
65945
+ allUsers: "All Users",
65946
+ statusLabel: "Score Status",
65947
+ allStatuses: "All Statuses",
65948
+ dateRangeLabel: "Pick a Date Range"
65949
+ },
65950
+ statusValues: {
65951
+ pending: "Pending",
65952
+ published: "Published",
65953
+ failed: "Failed"
65954
+ },
65955
+ columns: {
65956
+ learner: "Learner",
65957
+ score: "Score",
65958
+ status: "Status",
65959
+ override: "Override",
65960
+ gradedAt: "Graded"
65961
+ },
65962
+ emptyState: "No grades yet. They will appear here once the agent starts grading.",
65963
+ emptyFiltered: "No grades match the current filters.",
65964
+ overriddenBadge: "Overridden",
65965
+ overrideModal: {
65966
+ title: "Override Grade",
65967
+ learnerLabel: "Learner",
65968
+ aiScoreLabel: "AI Score",
65969
+ currentOverrideLabel: "Current Override",
65970
+ noOverride: "None",
65971
+ pointsLabel: "Override Points",
65972
+ pointsHelp: "Between 0 and {total}. The score pushed to the LMS becomes points ÷ {total}.",
65973
+ pointsRange: "Points must be between 0 and {total}",
65974
+ feedbackLabel: "Override Feedback",
65975
+ feedbackPlaceholder: "Explain the change for the learner (optional).",
65976
+ clearHelp: "Clearing the override restores the AI score and pushes it back to the LMS.",
65977
+ save: "Save",
65978
+ saving: "Saving…",
65979
+ clear: "Clear",
65980
+ clearing: "Clearing…",
65981
+ cancel: "Cancel"
65982
+ },
65983
+ toasts: {
65984
+ overrideSaved: "Override saved and pushed to the LMS",
65985
+ overrideCleared: "Override cleared — the AI score was restored",
65986
+ overrideError: "Couldn't save the override"
65987
+ },
65988
+ overrideButton: "Override",
65989
+ overrideButtonAria: "Override grade for {email}"
65872
65990
  }
65873
65991
  };
65874
65992
  var en = {
@@ -65897,6 +66015,7 @@ var en = {
65897
66015
  analyticsAnalyticsCourseDetail: analyticsAnalyticsCourseDetail$3,
65898
66016
  analyticsAnalyticsCourses: analyticsAnalyticsCourses$3,
65899
66017
  analyticsAnalyticsFinancialStats: analyticsAnalyticsFinancialStats$3,
66018
+ analyticsAnalyticsMemoryStats: analyticsAnalyticsMemoryStats$3,
65900
66019
  analyticsAnalyticsMonetizationStats: analyticsAnalyticsMonetizationStats$3,
65901
66020
  analyticsAnalyticsOverview: analyticsAnalyticsOverview$3,
65902
66021
  analyticsAnalyticsProgramDetail: analyticsAnalyticsProgramDetail$3,
@@ -65907,6 +66026,7 @@ var en = {
65907
66026
  analyticsAnalyticsUsersStats: analyticsAnalyticsUsersStats$3,
65908
66027
  analyticsGroupsFilterDropdown: analyticsGroupsFilterDropdown$3,
65909
66028
  analyticsStatCard: analyticsStatCard$3,
66029
+ analyticsUserFilterSelect: analyticsUserFilterSelect$3,
65910
66030
  apiTabApiKeyModal: apiTabApiKeyModal$3,
65911
66031
  apiTabCreateApiModal2: apiTabCreateApiModal2$3,
65912
66032
  apiTabDeleteApiModal2: apiTabDeleteApiModal2$3,
@@ -66839,6 +66959,37 @@ var analyticsAnalyticsFinancialStats$2 = {
66839
66959
  goToLastPage: "Aller à la dernière page",
66840
66960
  paginationShowing: "Affichage de {from} à {to} sur {total} résultats"
66841
66961
  };
66962
+ var analyticsAnalyticsMemoryStats$2 = {
66963
+ noPermission: "Vous n'avez pas l'autorisation de consulter les mémoires des utilisateurs.",
66964
+ scopeLabel: "Portée de la mémoire",
66965
+ scopeMentor: "Cet agent",
66966
+ scopeAllMentors: "Tous les agents",
66967
+ scopeGlobal: "Global",
66968
+ searchAgents: "Rechercher des agents…",
66969
+ searchAgentsTitle: "Rechercher des agents",
66970
+ clearAgentSearch: "Effacer la recherche d'agent",
66971
+ contentPlaceholder: "Rechercher dans le contenu des mémoires",
66972
+ pickDateRange: "Choisir une plage de dates",
66973
+ allCategories: "Toutes les catégories",
66974
+ byCategory: "Mémoires par catégorie",
66975
+ categoryCount: "{count} ({percent}%)",
66976
+ loadError: "Une erreur s'est produite lors du chargement des mémoires.",
66977
+ noMemories: "Aucune mémoire n'a encore été capturée.",
66978
+ detailTitle: "Détail de la mémoire",
66979
+ detailUser: "Utilisateur",
66980
+ detailAgent: "Agent",
66981
+ detailCategory: "Catégorie",
66982
+ detailSource: "Source",
66983
+ detailCaptured: "Capturée",
66984
+ detailSession: "Session",
66985
+ sourceAuto: "Capturée automatiquement",
66986
+ sourceManual: "Ajoutée manuellement",
66987
+ colUser: "UTILISATEUR",
66988
+ colMemory: "MÉMOIRE",
66989
+ colAgent: "AGENT",
66990
+ colCategory: "CATÉGORIE",
66991
+ colCaptured: "CAPTURÉE"
66992
+ };
66842
66993
  var analyticsAnalyticsMonetizationStats$2 = {
66843
66994
  totalRevenue: "Revenu total",
66844
66995
  totalSales: "Ventes totales",
@@ -67084,6 +67235,13 @@ var analyticsStatCard$2 = {
67084
67235
  ariaLabel: "mini carte {title}",
67085
67236
  ariaLabelValue: "valeur de la mini carte {title}"
67086
67237
  };
67238
+ var analyticsUserFilterSelect$2 = {
67239
+ filterByUser: "Filtrer par utilisateur",
67240
+ you: "Vous",
67241
+ searchPlaceholder: "Rechercher des utilisateurs…",
67242
+ noUsersFound: "Aucun utilisateur trouvé.",
67243
+ loadingUsers: "Chargement des utilisateurs…"
67244
+ };
67087
67245
  var apiTabApiKeyModal$2 = {
67088
67246
  title: "Clé API",
67089
67247
  dialogDescription: "Copiez et collez la clé API.",
@@ -67411,7 +67569,8 @@ var graderTabLabels$2 = {
67411
67569
  },
67412
67570
  subTabs: {
67413
67571
  setup: "Configuration de la notation",
67414
- rubric: "Grille d'évaluation"
67572
+ rubric: "Grille d'évaluation",
67573
+ results: "Résultats"
67415
67574
  },
67416
67575
  denied: {
67417
67576
  title: "Pas d'accès aux paramètres de notation",
@@ -67499,6 +67658,59 @@ var graderTabLabels$2 = {
67499
67658
  deleting: "Suppression…"
67500
67659
  }
67501
67660
  },
67661
+ results: {
67662
+ sectionTitle: "Résultats de notation",
67663
+ description: "Toutes les notes émises par cet agent. Remplacez une note pour la corriger — la modification est renvoyée au LMS d'où provient la note.",
67664
+ filters: {
67665
+ searchUser: "Rechercher un utilisateur",
67666
+ searchUsersPlaceholder: "Rechercher des utilisateurs...",
67667
+ noUsersFound: "Aucun utilisateur trouvé.",
67668
+ allUsers: "Tous les utilisateurs",
67669
+ statusLabel: "Statut de la note",
67670
+ allStatuses: "Tous les statuts",
67671
+ dateRangeLabel: "Choisir une plage de dates"
67672
+ },
67673
+ statusValues: {
67674
+ pending: "En attente",
67675
+ published: "Publié",
67676
+ failed: "Échoué"
67677
+ },
67678
+ columns: {
67679
+ learner: "Apprenant",
67680
+ score: "Note",
67681
+ status: "Statut",
67682
+ override: "Remplacement",
67683
+ gradedAt: "Noté"
67684
+ },
67685
+ emptyState: "Aucune note pour l'instant. Elles apparaîtront ici dès que l'agent commencera à noter.",
67686
+ emptyFiltered: "Aucune note ne correspond aux filtres actuels.",
67687
+ overriddenBadge: "Remplacée",
67688
+ overrideModal: {
67689
+ title: "Remplacer la note",
67690
+ learnerLabel: "Apprenant",
67691
+ aiScoreLabel: "Note de l'IA",
67692
+ currentOverrideLabel: "Remplacement actuel",
67693
+ noOverride: "Aucun",
67694
+ pointsLabel: "Points de remplacement",
67695
+ pointsHelp: "Entre 0 et {total}. La note envoyée au LMS devient points ÷ {total}.",
67696
+ pointsRange: "Les points doivent être compris entre 0 et {total}",
67697
+ feedbackLabel: "Retour sur le remplacement",
67698
+ feedbackPlaceholder: "Expliquez le changement à l'apprenant (facultatif).",
67699
+ clearHelp: "Supprimer le remplacement restaure la note de l'IA et la renvoie au LMS.",
67700
+ save: "Enregistrer",
67701
+ saving: "Enregistrement…",
67702
+ clear: "Supprimer",
67703
+ clearing: "Suppression…",
67704
+ cancel: "Annuler"
67705
+ },
67706
+ toasts: {
67707
+ overrideSaved: "Remplacement enregistré et envoyé au LMS",
67708
+ overrideCleared: "Remplacement supprimé — la note de l'IA a été restaurée",
67709
+ overrideError: "Impossible d'enregistrer le remplacement"
67710
+ },
67711
+ overrideButton: "Remplacer",
67712
+ overrideButtonAria: "Remplacer la note de {email}"
67713
+ },
67502
67714
  toasts: {
67503
67715
  toggleOn: "Notation activée",
67504
67716
  toggleOff: "Notation désactivée — votre grille est conservée pour la prochaine fois",
@@ -68899,12 +69111,14 @@ var memoryMemoryTab$2 = {
68899
69111
  useMemoryLabelDesc: "Lorsque cette option est activée, l'IA utilisera ce qu'elle sait de vous pour personnaliser ses réponses.",
68900
69112
  useMemoryAriaLabel: "Utilisation de la mémoire dans les réponses {state}",
68901
69113
  sectionMyMemories: "Mes souvenirs",
69114
+ sectionMyMemoriesPreview: "Souvenirs",
68902
69115
  addMemoryButton: "Ajouter un souvenir",
68903
69116
  autoGeneratedMemoryAriaLabel: "Souvenir généré automatiquement",
68904
69117
  manuallyAddedMemoryAriaLabel: "Souvenir ajouté manuellement",
68905
69118
  autoBadge: "auto",
68906
69119
  deleteMemoryAriaLabel: "Supprimer le souvenir : {excerpt}",
68907
69120
  noMemoriesYet: "Aucun souvenir pour l'instant. L'IA commencera à mémoriser des informations de vos conversations, ou vous pouvez ajouter des souvenirs manuellement.",
69121
+ noMemoriesYetPreview: "Aucun souvenir pour l'instant. L'IA n'a enregistré aucune information des conversations de cet utilisateur.",
68908
69122
  stateEnabled: "activée",
68909
69123
  stateDisabled: "désactivée"
68910
69124
  };
@@ -71110,6 +71324,10 @@ var analyticsTabLabels$2 = {
71110
71324
  label: "Transcriptions",
71111
71325
  description: "Lisez les transcriptions complètes des conversations, message par message."
71112
71326
  },
71327
+ memory: {
71328
+ label: "Mémoire",
71329
+ description: "Ce que cet agent retient de chaque utilisateur avec qui il échange."
71330
+ },
71113
71331
  financial: {
71114
71332
  label: "Coûts",
71115
71333
  description: "Suivez l'utilisation des jetons et ce que cet agent vous coûte."
@@ -72117,6 +72335,7 @@ var fr = {
72117
72335
  analyticsAnalyticsCourseDetail: analyticsAnalyticsCourseDetail$2,
72118
72336
  analyticsAnalyticsCourses: analyticsAnalyticsCourses$2,
72119
72337
  analyticsAnalyticsFinancialStats: analyticsAnalyticsFinancialStats$2,
72338
+ analyticsAnalyticsMemoryStats: analyticsAnalyticsMemoryStats$2,
72120
72339
  analyticsAnalyticsMonetizationStats: analyticsAnalyticsMonetizationStats$2,
72121
72340
  analyticsAnalyticsOverview: analyticsAnalyticsOverview$2,
72122
72341
  analyticsAnalyticsProgramDetail: analyticsAnalyticsProgramDetail$2,
@@ -72127,6 +72346,7 @@ var fr = {
72127
72346
  analyticsAnalyticsUsersStats: analyticsAnalyticsUsersStats$2,
72128
72347
  analyticsGroupsFilterDropdown: analyticsGroupsFilterDropdown$2,
72129
72348
  analyticsStatCard: analyticsStatCard$2,
72349
+ analyticsUserFilterSelect: analyticsUserFilterSelect$2,
72130
72350
  apiTabApiKeyModal: apiTabApiKeyModal$2,
72131
72351
  apiTabCreateApiModal2: apiTabCreateApiModal2$2,
72132
72352
  apiTabDeleteApiModal2: apiTabDeleteApiModal2$2,
@@ -73059,6 +73279,37 @@ var analyticsAnalyticsFinancialStats$1 = {
73059
73279
  goToLastPage: "Ir a la última página",
73060
73280
  paginationShowing: "Mostrando {from} a {to} de {total} resultados"
73061
73281
  };
73282
+ var analyticsAnalyticsMemoryStats$1 = {
73283
+ noPermission: "No tienes permiso para ver los recuerdos de los usuarios.",
73284
+ scopeLabel: "Alcance de la memoria",
73285
+ scopeMentor: "Este agente",
73286
+ scopeAllMentors: "Todos los agentes",
73287
+ scopeGlobal: "Global",
73288
+ searchAgents: "Buscar agentes…",
73289
+ searchAgentsTitle: "Buscar agentes",
73290
+ clearAgentSearch: "Borrar la búsqueda de agentes",
73291
+ contentPlaceholder: "Buscar en el contenido de los recuerdos",
73292
+ pickDateRange: "Elige un rango de fechas",
73293
+ allCategories: "Todas las categorías",
73294
+ byCategory: "Recuerdos por categoría",
73295
+ categoryCount: "{count} ({percent}%)",
73296
+ loadError: "Se produjo un error al cargar los recuerdos.",
73297
+ noMemories: "Todavía no se ha capturado ningún recuerdo.",
73298
+ detailTitle: "Detalle del recuerdo",
73299
+ detailUser: "Usuario",
73300
+ detailAgent: "Agente",
73301
+ detailCategory: "Categoría",
73302
+ detailSource: "Origen",
73303
+ detailCaptured: "Capturado",
73304
+ detailSession: "Sesión",
73305
+ sourceAuto: "Capturado automáticamente",
73306
+ sourceManual: "Añadido manualmente",
73307
+ colUser: "USUARIO",
73308
+ colMemory: "RECUERDO",
73309
+ colAgent: "AGENTE",
73310
+ colCategory: "CATEGORÍA",
73311
+ colCaptured: "CAPTURADO"
73312
+ };
73062
73313
  var analyticsAnalyticsMonetizationStats$1 = {
73063
73314
  totalRevenue: "Ingresos totales",
73064
73315
  totalSales: "Ventas totales",
@@ -73304,6 +73555,13 @@ var analyticsStatCard$1 = {
73304
73555
  ariaLabel: "mini tarjeta {title}",
73305
73556
  ariaLabelValue: "valor de la mini tarjeta {title}"
73306
73557
  };
73558
+ var analyticsUserFilterSelect$1 = {
73559
+ filterByUser: "Filtrar por usuario",
73560
+ you: "Tú",
73561
+ searchPlaceholder: "Buscar usuarios…",
73562
+ noUsersFound: "No se encontraron usuarios.",
73563
+ loadingUsers: "Cargando usuarios…"
73564
+ };
73307
73565
  var apiTabApiKeyModal$1 = {
73308
73566
  title: "Clave API",
73309
73567
  dialogDescription: "Copie y pegue la clave API.",
@@ -73631,7 +73889,8 @@ var graderTabLabels$1 = {
73631
73889
  },
73632
73890
  subTabs: {
73633
73891
  setup: "Configuración de calificación",
73634
- rubric: "Rúbrica"
73892
+ rubric: "Rúbrica",
73893
+ results: "Resultados"
73635
73894
  },
73636
73895
  denied: {
73637
73896
  title: "Sin acceso a la configuración de calificación",
@@ -73719,6 +73978,59 @@ var graderTabLabels$1 = {
73719
73978
  deleting: "Eliminando…"
73720
73979
  }
73721
73980
  },
73981
+ results: {
73982
+ sectionTitle: "Resultados de calificación",
73983
+ description: "Todas las calificaciones que este agente ha emitido. Anula una puntuación para corregirla — el cambio se envía de vuelta al LMS del que proviene la calificación.",
73984
+ filters: {
73985
+ searchUser: "Buscar usuario",
73986
+ searchUsersPlaceholder: "Buscar usuarios...",
73987
+ noUsersFound: "No se encontraron usuarios.",
73988
+ allUsers: "Todos los usuarios",
73989
+ statusLabel: "Estado de la puntuación",
73990
+ allStatuses: "Todos los estados",
73991
+ dateRangeLabel: "Selecciona un rango de fechas"
73992
+ },
73993
+ statusValues: {
73994
+ pending: "Pendiente",
73995
+ published: "Publicado",
73996
+ failed: "Fallido"
73997
+ },
73998
+ columns: {
73999
+ learner: "Estudiante",
74000
+ score: "Puntuación",
74001
+ status: "Estado",
74002
+ override: "Anulación",
74003
+ gradedAt: "Calificado"
74004
+ },
74005
+ emptyState: "Aún no hay calificaciones. Aparecerán aquí cuando el agente comience a calificar.",
74006
+ emptyFiltered: "Ninguna calificación coincide con los filtros actuales.",
74007
+ overriddenBadge: "Anulada",
74008
+ overrideModal: {
74009
+ title: "Anular calificación",
74010
+ learnerLabel: "Estudiante",
74011
+ aiScoreLabel: "Puntuación de la IA",
74012
+ currentOverrideLabel: "Anulación actual",
74013
+ noOverride: "Ninguna",
74014
+ pointsLabel: "Puntos de anulación",
74015
+ pointsHelp: "Entre 0 y {total}. La puntuación enviada al LMS es puntos ÷ {total}.",
74016
+ pointsRange: "Los puntos deben estar entre 0 y {total}",
74017
+ feedbackLabel: "Retroalimentación de la anulación",
74018
+ feedbackPlaceholder: "Explica el cambio al estudiante (opcional).",
74019
+ clearHelp: "Quitar la anulación restaura la puntuación de la IA y la envía de vuelta al LMS.",
74020
+ save: "Guardar",
74021
+ saving: "Guardando…",
74022
+ clear: "Quitar",
74023
+ clearing: "Quitando…",
74024
+ cancel: "Cancelar"
74025
+ },
74026
+ toasts: {
74027
+ overrideSaved: "Anulación guardada y enviada al LMS",
74028
+ overrideCleared: "Anulación quitada — se restauró la puntuación de la IA",
74029
+ overrideError: "No se pudo guardar la anulación"
74030
+ },
74031
+ overrideButton: "Anular",
74032
+ overrideButtonAria: "Anular la calificación de {email}"
74033
+ },
73722
74034
  toasts: {
73723
74035
  toggleOn: "Calificación activada",
73724
74036
  toggleOff: "Calificación desactivada — tu rúbrica se conserva para la próxima vez",
@@ -75119,12 +75431,14 @@ var memoryMemoryTab$1 = {
75119
75431
  useMemoryLabelDesc: "Cuando está habilitado, la IA usará lo que sabe sobre usted para personalizar las respuestas.",
75120
75432
  useMemoryAriaLabel: "Uso de memoria en las respuestas {state}",
75121
75433
  sectionMyMemories: "Mis memorias",
75434
+ sectionMyMemoriesPreview: "Memorias",
75122
75435
  addMemoryButton: "Añadir memoria",
75123
75436
  autoGeneratedMemoryAriaLabel: "Memoria generada automáticamente",
75124
75437
  manuallyAddedMemoryAriaLabel: "Memoria añadida manualmente",
75125
75438
  autoBadge: "auto",
75126
75439
  deleteMemoryAriaLabel: "Eliminar memoria: {excerpt}",
75127
75440
  noMemoriesYet: "Aún no hay memorias. La IA comenzará a recordar información de sus conversaciones, o puede añadir memorias manualmente.",
75441
+ noMemoriesYetPreview: "Aún no hay memorias. La IA no ha registrado información de las conversaciones de este usuario.",
75128
75442
  stateEnabled: "habilitada",
75129
75443
  stateDisabled: "deshabilitada"
75130
75444
  };
@@ -77330,6 +77644,10 @@ var analyticsTabLabels$1 = {
77330
77644
  label: "Transcripciones",
77331
77645
  description: "Lee las transcripciones completas de las conversaciones, mensaje a mensaje."
77332
77646
  },
77647
+ memory: {
77648
+ label: "Memoria",
77649
+ description: "Lo que este agente recuerda de cada usuario con el que habla."
77650
+ },
77333
77651
  financial: {
77334
77652
  label: "Costos",
77335
77653
  description: "Controla el uso de tokens y lo que te cuesta este agente."
@@ -78337,6 +78655,7 @@ var es = {
78337
78655
  analyticsAnalyticsCourseDetail: analyticsAnalyticsCourseDetail$1,
78338
78656
  analyticsAnalyticsCourses: analyticsAnalyticsCourses$1,
78339
78657
  analyticsAnalyticsFinancialStats: analyticsAnalyticsFinancialStats$1,
78658
+ analyticsAnalyticsMemoryStats: analyticsAnalyticsMemoryStats$1,
78340
78659
  analyticsAnalyticsMonetizationStats: analyticsAnalyticsMonetizationStats$1,
78341
78660
  analyticsAnalyticsOverview: analyticsAnalyticsOverview$1,
78342
78661
  analyticsAnalyticsProgramDetail: analyticsAnalyticsProgramDetail$1,
@@ -78347,6 +78666,7 @@ var es = {
78347
78666
  analyticsAnalyticsUsersStats: analyticsAnalyticsUsersStats$1,
78348
78667
  analyticsGroupsFilterDropdown: analyticsGroupsFilterDropdown$1,
78349
78668
  analyticsStatCard: analyticsStatCard$1,
78669
+ analyticsUserFilterSelect: analyticsUserFilterSelect$1,
78350
78670
  apiTabApiKeyModal: apiTabApiKeyModal$1,
78351
78671
  apiTabCreateApiModal2: apiTabCreateApiModal2$1,
78352
78672
  apiTabDeleteApiModal2: apiTabDeleteApiModal2$1,
@@ -79279,6 +79599,37 @@ var analyticsAnalyticsFinancialStats = {
79279
79599
  goToLastPage: "转到最后一页",
79280
79600
  paginationShowing: "显示第 {from} 至 {to} 条,共 {total} 条结果"
79281
79601
  };
79602
+ var analyticsAnalyticsMemoryStats = {
79603
+ noPermission: "您没有查看用户记忆的权限。",
79604
+ scopeLabel: "记忆范围",
79605
+ scopeMentor: "当前智能体",
79606
+ scopeAllMentors: "所有智能体",
79607
+ scopeGlobal: "全局",
79608
+ searchAgents: "搜索智能体…",
79609
+ searchAgentsTitle: "搜索智能体",
79610
+ clearAgentSearch: "清除智能体搜索",
79611
+ contentPlaceholder: "搜索记忆内容",
79612
+ pickDateRange: "选择日期范围",
79613
+ allCategories: "所有类别",
79614
+ byCategory: "按类别统计记忆",
79615
+ categoryCount: "{count} ({percent}%)",
79616
+ loadError: "加载记忆时发生错误。",
79617
+ noMemories: "尚未捕获任何记忆。",
79618
+ detailTitle: "记忆详情",
79619
+ detailUser: "用户",
79620
+ detailAgent: "智能体",
79621
+ detailCategory: "类别",
79622
+ detailSource: "来源",
79623
+ detailCaptured: "捕获时间",
79624
+ detailSession: "会话",
79625
+ sourceAuto: "自动捕获",
79626
+ sourceManual: "手动添加",
79627
+ colUser: "用户",
79628
+ colMemory: "记忆",
79629
+ colAgent: "智能体",
79630
+ colCategory: "类别",
79631
+ colCaptured: "捕获时间"
79632
+ };
79282
79633
  var analyticsAnalyticsMonetizationStats = {
79283
79634
  totalRevenue: "总收入",
79284
79635
  totalSales: "总销售额",
@@ -79524,6 +79875,13 @@ var analyticsStatCard = {
79524
79875
  ariaLabel: "{title} 迷你卡片",
79525
79876
  ariaLabelValue: "{title} 迷你卡片值"
79526
79877
  };
79878
+ var analyticsUserFilterSelect = {
79879
+ filterByUser: "按用户筛选",
79880
+ you: "我",
79881
+ searchPlaceholder: "搜索用户…",
79882
+ noUsersFound: "未找到用户。",
79883
+ loadingUsers: "正在加载用户…"
79884
+ };
79527
79885
  var apiTabApiKeyModal = {
79528
79886
  title: "API 密钥",
79529
79887
  dialogDescription: "复制并粘贴 API 密钥。",
@@ -79851,7 +80209,8 @@ var graderTabLabels = {
79851
80209
  },
79852
80210
  subTabs: {
79853
80211
  setup: "评分设置",
79854
- rubric: "评分标准"
80212
+ rubric: "评分标准",
80213
+ results: "结果"
79855
80214
  },
79856
80215
  denied: {
79857
80216
  title: "无权访问评分设置",
@@ -79939,6 +80298,59 @@ var graderTabLabels = {
79939
80298
  deleting: "删除中…"
79940
80299
  }
79941
80300
  },
80301
+ results: {
80302
+ sectionTitle: "评分结果",
80303
+ description: "此智能体发出的所有评分。覆盖分数即可更正 — 更改会推送回评分来源的 LMS。",
80304
+ filters: {
80305
+ searchUser: "搜索用户",
80306
+ searchUsersPlaceholder: "搜索用户...",
80307
+ noUsersFound: "未找到用户。",
80308
+ allUsers: "所有用户",
80309
+ statusLabel: "分数状态",
80310
+ allStatuses: "全部状态",
80311
+ dateRangeLabel: "选择日期范围"
80312
+ },
80313
+ statusValues: {
80314
+ pending: "待处理",
80315
+ published: "已发布",
80316
+ failed: "失败"
80317
+ },
80318
+ columns: {
80319
+ learner: "学员",
80320
+ score: "分数",
80321
+ status: "状态",
80322
+ override: "覆盖",
80323
+ gradedAt: "评分时间"
80324
+ },
80325
+ emptyState: "还没有评分。智能体开始评分后将显示在这里。",
80326
+ emptyFiltered: "没有符合当前筛选条件的评分。",
80327
+ overriddenBadge: "已覆盖",
80328
+ overrideModal: {
80329
+ title: "覆盖评分",
80330
+ learnerLabel: "学员",
80331
+ aiScoreLabel: "AI 分数",
80332
+ currentOverrideLabel: "当前覆盖",
80333
+ noOverride: "无",
80334
+ pointsLabel: "覆盖分数",
80335
+ pointsHelp: "介于 0 和 {total} 之间。推送到 LMS 的分数为 分数 ÷ {total}。",
80336
+ pointsRange: "分数必须介于 0 和 {total} 之间",
80337
+ feedbackLabel: "覆盖反馈",
80338
+ feedbackPlaceholder: "向学员说明此更改(可选)。",
80339
+ clearHelp: "清除覆盖会恢复 AI 分数并推送回 LMS。",
80340
+ save: "保存",
80341
+ saving: "保存中…",
80342
+ clear: "清除",
80343
+ clearing: "清除中…",
80344
+ cancel: "取消"
80345
+ },
80346
+ toasts: {
80347
+ overrideSaved: "覆盖已保存并推送到 LMS",
80348
+ overrideCleared: "覆盖已清除 — AI 分数已恢复",
80349
+ overrideError: "无法保存覆盖"
80350
+ },
80351
+ overrideButton: "覆盖",
80352
+ overrideButtonAria: "覆盖 {email} 的评分"
80353
+ },
79942
80354
  toasts: {
79943
80355
  toggleOn: "评分已开启",
79944
80356
  toggleOff: "评分已关闭 — 您的评分标准已保留,下次可继续使用",
@@ -81339,12 +81751,14 @@ var memoryMemoryTab = {
81339
81751
  useMemoryLabelDesc: "启用后,AI 将利用它对您的了解来个性化回复。",
81340
81752
  useMemoryAriaLabel: "在回复中使用记忆{state}",
81341
81753
  sectionMyMemories: "我的记忆",
81754
+ sectionMyMemoriesPreview: "记忆",
81342
81755
  addMemoryButton: "添加记忆",
81343
81756
  autoGeneratedMemoryAriaLabel: "自动生成的记忆",
81344
81757
  manuallyAddedMemoryAriaLabel: "手动添加的记忆",
81345
81758
  autoBadge: "自动",
81346
81759
  deleteMemoryAriaLabel: "删除记忆:{excerpt}",
81347
81760
  noMemoriesYet: "暂无记忆。AI 将开始记住您对话中的信息,或者您也可以手动添加记忆。",
81761
+ noMemoriesYetPreview: "暂无记忆。AI 尚未记录该用户对话中的任何信息。",
81348
81762
  stateEnabled: "已启用",
81349
81763
  stateDisabled: "已禁用"
81350
81764
  };
@@ -83550,6 +83964,10 @@ var analyticsTabLabels = {
83550
83964
  label: "对话记录",
83551
83965
  description: "逐条阅读完整的对话记录。"
83552
83966
  },
83967
+ memory: {
83968
+ label: "记忆",
83969
+ description: "该智能体记住的与其对话的每位用户的相关信息。"
83970
+ },
83553
83971
  financial: {
83554
83972
  label: "费用",
83555
83973
  description: "跟踪令牌用量以及该智能体的花费。"
@@ -84557,6 +84975,7 @@ var zh = {
84557
84975
  analyticsAnalyticsCourseDetail: analyticsAnalyticsCourseDetail,
84558
84976
  analyticsAnalyticsCourses: analyticsAnalyticsCourses,
84559
84977
  analyticsAnalyticsFinancialStats: analyticsAnalyticsFinancialStats,
84978
+ analyticsAnalyticsMemoryStats: analyticsAnalyticsMemoryStats,
84560
84979
  analyticsAnalyticsMonetizationStats: analyticsAnalyticsMonetizationStats,
84561
84980
  analyticsAnalyticsOverview: analyticsAnalyticsOverview,
84562
84981
  analyticsAnalyticsProgramDetail: analyticsAnalyticsProgramDetail,
@@ -84567,6 +84986,7 @@ var zh = {
84567
84986
  analyticsAnalyticsUsersStats: analyticsAnalyticsUsersStats,
84568
84987
  analyticsGroupsFilterDropdown: analyticsGroupsFilterDropdown,
84569
84988
  analyticsStatCard: analyticsStatCard,
84989
+ analyticsUserFilterSelect: analyticsUserFilterSelect,
84570
84990
  apiTabApiKeyModal: apiTabApiKeyModal,
84571
84991
  apiTabCreateApiModal2: apiTabCreateApiModal2,
84572
84992
  apiTabDeleteApiModal2: apiTabDeleteApiModal2,
@@ -87544,11 +87964,10 @@ const getUserName$1 = () => {
87544
87964
  };
87545
87965
 
87546
87966
  /**
87547
- * True when the logged-in user is viewing someone else's profile (preview
87548
- * mode), so editing affordances can be hidden. Reads the current username from
87549
- * localStorage after mount to stay SSR-safe.
87967
+ * The signed-in user's username, or an empty string before it is known. Read
87968
+ * from localStorage after mount to stay SSR-safe.
87550
87969
  */
87551
- function useIsProfilePreview(username) {
87970
+ function useCurrentUsername() {
87552
87971
  const [currentUsername, setCurrentUsername] = useState('');
87553
87972
  useEffect(() => {
87554
87973
  try {
@@ -87558,6 +87977,14 @@ function useIsProfilePreview(username) {
87558
87977
  setCurrentUsername('');
87559
87978
  }
87560
87979
  }, []);
87980
+ return currentUsername;
87981
+ }
87982
+ /**
87983
+ * True when the logged-in user is viewing someone else's profile (preview
87984
+ * mode), so editing affordances can be hidden.
87985
+ */
87986
+ function useIsProfilePreview(username) {
87987
+ const currentUsername = useCurrentUsername();
87561
87988
  return !!currentUsername && currentUsername !== username;
87562
87989
  }
87563
87990
 
@@ -141243,7 +141670,7 @@ const EmptyStats = ({ title = 'No data available' }) => {
141243
141670
 
141244
141671
  const COMPLETED_COLOR = '#ED8936';
141245
141672
  const REMAINING_COLOR = '#E5E7EB';
141246
- const formatDate$1 = (value) => {
141673
+ const formatDate$2 = (value) => {
141247
141674
  if (!value)
141248
141675
  return '—';
141249
141676
  const date = new Date(value);
@@ -141347,13 +141774,13 @@ function EnrolledUserProgressModal({ open, onOpenChange, username, userName, ema
141347
141774
  const passingPct = getPassingPct((_h = (_g = item === null || item === void 0 ? void 0 : item.edx_progress) === null || _g === void 0 ? void 0 : _g.grading_policy) === null || _h === void 0 ? void 0 : _h.grade_range);
141348
141775
  return (jsx(Dialog, { open: open, onOpenChange: onOpenChange, children: jsxs(DialogContent, { className: "max-w-2xl max-h-[85vh] overflow-y-auto", "aria-label": "Enrolled user progress", children: [jsxs(DialogHeader, { children: [jsx(DialogTitle, { children: userName || username || 'Learner progress' }), jsxs(DialogDescription, { children: [email ? `${email} · ` : '', resolvedName || (isProgram ? 'Program progress' : 'Course progress')] })] }), loading ? (jsx("div", { className: "flex items-center justify-center py-12", children: jsx("div", { className: "text-sm text-gray-500", children: "Loading..." }) })) : !item ? (jsx(EmptyStats, { title: "No progress data available" })) : (jsxs("div", { className: "space-y-6", children: [jsxs("div", { className: "relative mx-auto", style: { width: 220, height: 220 }, children: [jsx(ResponsiveContainer, { width: "100%", height: "100%", children: jsx(PieChart, { children: jsxs(Pie, { data: pieData, dataKey: "value", cx: "50%", cy: "50%", innerRadius: 75, outerRadius: 100, startAngle: 90, endAngle: -270, stroke: "none", isAnimationActive: false, children: [jsx(Cell, { fill: COMPLETED_COLOR }), jsx(Cell, { fill: REMAINING_COLOR })] }) }) }), jsxs("div", { className: "absolute inset-0 flex flex-col items-center justify-center pointer-events-none", children: [jsxs("span", { className: "text-3xl font-bold text-gray-700", children: [percentage, "%"] }), jsx("span", { className: "text-sm text-gray-500", children: "completed" })] })] }), jsxs("div", { className: "divide-y divide-[oklch(0.922_0_0)]", children: [jsx(DetailRow, { label: "Status", children: jsx("span", { className: `inline-flex items-center rounded-full px-2.5 py-0.5 text-xs font-medium ${((_j = item.completion) === null || _j === void 0 ? void 0 : _j.passed)
141349
141776
  ? 'bg-green-50 text-green-700'
141350
- : 'bg-gray-100 text-gray-600'}`, children: ((_k = item.completion) === null || _k === void 0 ? void 0 : _k.passed) ? 'Passed' : 'Not passed' }) }), jsx(DetailRow, { label: "Passed on", children: formatDate$1((_l = item.completion) === null || _l === void 0 ? void 0 : _l.passed_date) }), jsx(DetailRow, { label: "Time spent", children: item.time_spent || '—' }), jsx(DetailRow, { label: "Enrollment date", children: formatDate$1((_o = (_m = item.enrollment) === null || _m === void 0 ? void 0 : _m.started) !== null && _o !== void 0 ? _o : (_p = item.enrollment) === null || _p === void 0 ? void 0 : _p.created) })] }), ((_s = (_r = (_q = item.edx_progress) === null || _q === void 0 ? void 0 : _q.grading_policy) === null || _r === void 0 ? void 0 : _r.assignment_policies) === null || _s === void 0 ? void 0 : _s.length) ? (jsxs("div", { className: "space-y-4", children: [jsxs("div", { className: "rounded-lg border p-4", style: { borderColor: 'oklch(.922 0 0)' }, children: [jsx("h4", { className: "text-sm font-semibold text-gray-900", children: "Grades" }), jsx("p", { className: "text-xs text-gray-500", children: "This represents the weighted grade against the grade needed to pass this course." }), jsx(GradeBar, { currentPct: currentGradePct, passingPct: passingPct })] }), jsxs("div", { className: "flex items-start gap-2 rounded-md border border-amber-200 bg-amber-50 px-4 py-3", children: [jsx(TriangleAlert, { className: "mt-0.5 h-4 w-4 shrink-0 text-amber-600" }), jsxs("span", { className: "text-sm font-medium text-gray-800", children: ["A weighted grade of ", passingPct, "% is required to pass in this course"] })] }), jsxs("div", { className: "rounded-lg border p-4 space-y-3", style: { borderColor: 'oklch(.922 0 0)' }, children: [jsx("h4", { className: "text-sm font-semibold text-gray-900", children: "Grade summary" }), jsx("div", { className: "overflow-x-auto", children: jsxs("table", { className: "w-full border-collapse text-sm", children: [jsx("thead", { children: jsxs("tr", { className: "bg-amber-50 text-[11px] uppercase tracking-wide text-gray-600", children: [jsx("th", { className: "px-3 py-2 text-left font-medium", children: "Assignment type" }), jsx("th", { className: "px-3 py-2 text-right font-medium", children: "Weight" }), jsx("th", { className: "px-3 py-2 text-right font-medium", children: "Grade" }), jsx("th", { className: "px-3 py-2 text-right font-medium", children: "Weighted grade" })] }) }), jsxs("tbody", { children: [gradeSummary === null || gradeSummary === void 0 ? void 0 : gradeSummary.rows.map((row, index) => (jsxs("tr", { className: index % 2 === 0 ? '' : 'bg-gray-50', children: [jsxs("td", { className: "px-3 py-2 text-gray-800", children: [row.type, row.footnote ? (jsx("sup", { className: "ml-0.5 text-amber-500", children: row.footnote })) : null] }), jsxs("td", { className: "px-3 py-2 text-right text-gray-700", children: [row.weightPct, "%"] }), jsxs("td", { className: "px-3 py-2 text-right text-gray-700", children: [row.gradePct, "%"] }), jsxs("td", { className: "px-3 py-2 text-right font-semibold text-amber-600", children: [row.weightedGradePct, "%"] })] }, row.type))), jsxs("tr", { className: "border-l-2 border-amber-400 bg-amber-50", children: [jsx("td", { className: "px-3 py-2 font-medium text-gray-800", colSpan: 3, children: "Current weighted grade summary" }), jsxs("td", { className: "px-3 py-2 text-right font-bold text-amber-600", children: [currentGradePct, "%"] })] })] })] }) }), gradeSummary && gradeSummary.footnotes.length > 0 ? (jsx("div", { className: "space-y-1", children: gradeSummary.footnotes.map((note, index) => (jsxs("p", { className: "text-xs text-gray-500", children: [jsx("sup", { className: "text-amber-500", children: index + 1 }), " ", note] }, note))) })) : null] })] })) : null] }))] }) }));
141777
+ : 'bg-gray-100 text-gray-600'}`, children: ((_k = item.completion) === null || _k === void 0 ? void 0 : _k.passed) ? 'Passed' : 'Not passed' }) }), jsx(DetailRow, { label: "Passed on", children: formatDate$2((_l = item.completion) === null || _l === void 0 ? void 0 : _l.passed_date) }), jsx(DetailRow, { label: "Time spent", children: item.time_spent || '—' }), jsx(DetailRow, { label: "Enrollment date", children: formatDate$2((_o = (_m = item.enrollment) === null || _m === void 0 ? void 0 : _m.started) !== null && _o !== void 0 ? _o : (_p = item.enrollment) === null || _p === void 0 ? void 0 : _p.created) })] }), ((_s = (_r = (_q = item.edx_progress) === null || _q === void 0 ? void 0 : _q.grading_policy) === null || _r === void 0 ? void 0 : _r.assignment_policies) === null || _s === void 0 ? void 0 : _s.length) ? (jsxs("div", { className: "space-y-4", children: [jsxs("div", { className: "rounded-lg border p-4", style: { borderColor: 'oklch(.922 0 0)' }, children: [jsx("h4", { className: "text-sm font-semibold text-gray-900", children: "Grades" }), jsx("p", { className: "text-xs text-gray-500", children: "This represents the weighted grade against the grade needed to pass this course." }), jsx(GradeBar, { currentPct: currentGradePct, passingPct: passingPct })] }), jsxs("div", { className: "flex items-start gap-2 rounded-md border border-amber-200 bg-amber-50 px-4 py-3", children: [jsx(TriangleAlert, { className: "mt-0.5 h-4 w-4 shrink-0 text-amber-600" }), jsxs("span", { className: "text-sm font-medium text-gray-800", children: ["A weighted grade of ", passingPct, "% is required to pass in this course"] })] }), jsxs("div", { className: "rounded-lg border p-4 space-y-3", style: { borderColor: 'oklch(.922 0 0)' }, children: [jsx("h4", { className: "text-sm font-semibold text-gray-900", children: "Grade summary" }), jsx("div", { className: "overflow-x-auto", children: jsxs("table", { className: "w-full border-collapse text-sm", children: [jsx("thead", { children: jsxs("tr", { className: "bg-amber-50 text-[11px] uppercase tracking-wide text-gray-600", children: [jsx("th", { className: "px-3 py-2 text-left font-medium", children: "Assignment type" }), jsx("th", { className: "px-3 py-2 text-right font-medium", children: "Weight" }), jsx("th", { className: "px-3 py-2 text-right font-medium", children: "Grade" }), jsx("th", { className: "px-3 py-2 text-right font-medium", children: "Weighted grade" })] }) }), jsxs("tbody", { children: [gradeSummary === null || gradeSummary === void 0 ? void 0 : gradeSummary.rows.map((row, index) => (jsxs("tr", { className: index % 2 === 0 ? '' : 'bg-gray-50', children: [jsxs("td", { className: "px-3 py-2 text-gray-800", children: [row.type, row.footnote ? (jsx("sup", { className: "ml-0.5 text-amber-500", children: row.footnote })) : null] }), jsxs("td", { className: "px-3 py-2 text-right text-gray-700", children: [row.weightPct, "%"] }), jsxs("td", { className: "px-3 py-2 text-right text-gray-700", children: [row.gradePct, "%"] }), jsxs("td", { className: "px-3 py-2 text-right font-semibold text-amber-600", children: [row.weightedGradePct, "%"] })] }, row.type))), jsxs("tr", { className: "border-l-2 border-amber-400 bg-amber-50", children: [jsx("td", { className: "px-3 py-2 font-medium text-gray-800", colSpan: 3, children: "Current weighted grade summary" }), jsxs("td", { className: "px-3 py-2 text-right font-bold text-amber-600", children: [currentGradePct, "%"] })] })] })] }) }), gradeSummary && gradeSummary.footnotes.length > 0 ? (jsx("div", { className: "space-y-1", children: gradeSummary.footnotes.map((note, index) => (jsxs("p", { className: "text-xs text-gray-500", children: [jsx("sup", { className: "text-amber-500", children: index + 1 }), " ", note] }, note))) })) : null] })] })) : null] }))] }) }));
141351
141778
  }
141352
141779
  function DetailRow({ label, children }) {
141353
141780
  return (jsxs("div", { className: "flex items-center justify-between gap-4 py-2", children: [jsx("span", { className: "text-sm text-gray-500", children: label }), jsx("span", { className: "text-sm font-medium text-gray-900 text-right", children: children })] }));
141354
141781
  }
141355
141782
 
141356
- const PAGE_SIZE$5 = 8;
141783
+ const PAGE_SIZE$6 = 8;
141357
141784
  const CONTENT_TYPES = [
141358
141785
  { value: 'courses', labelKey: 'gradebookGradebookTab.typeCourses', icon: GraduationCap },
141359
141786
  { value: 'programs', labelKey: 'gradebookGradebookTab.typePrograms', icon: Layers },
@@ -141370,7 +141797,7 @@ function useDebounce$1(value, delay) {
141370
141797
  }, [value, delay]);
141371
141798
  return debouncedValue;
141372
141799
  }
141373
- const formatDate = (value) => {
141800
+ const formatDate$1 = (value) => {
141374
141801
  if (!value)
141375
141802
  return '—';
141376
141803
  const date = new Date(value);
@@ -141384,29 +141811,29 @@ function useGradebookData(type, org, username, page, search) {
141384
141811
  username,
141385
141812
  query: {
141386
141813
  page,
141387
- page_size: PAGE_SIZE$5,
141814
+ page_size: PAGE_SIZE$6,
141388
141815
  platform_key: org,
141389
141816
  ...(trimmed ? { search: trimmed } : {}),
141390
141817
  },
141391
141818
  }, { skip: type !== 'courses', refetchOnMountOrArgChange: true });
141392
141819
  const programsQ = useGetUserEnrolledProgramsQuery([{ username, platformKey: org }], { skip: type !== 'programs' });
141393
141820
  const pathwaysQ = useGetUserCatalogPathwaysQuery({ username, platform_key: org }, { skip: type !== 'pathways' });
141394
- const credentialsQ = useGetUsersAsAssertionsQuery({ platformKey: org, userId: username, page, pageSize: PAGE_SIZE$5 }, { skip: type !== 'credentials', refetchOnMountOrArgChange: true });
141821
+ const credentialsQ = useGetUsersAsAssertionsQuery({ platformKey: org, userId: username, page, pageSize: PAGE_SIZE$6 }, { skip: type !== 'credentials', refetchOnMountOrArgChange: true });
141395
141822
  const earnedQ = useGetUserEarnedSkillsQuery([{ org, userId: username }], { skip: type !== 'skills' });
141396
141823
  const reportedQ = useGetUserReportedSkillsQuery([{ username }], { skip: type !== 'skills' });
141397
141824
  const desiredQ = useGetUserDesiredSkillsQuery([{ username }], { skip: type !== 'skills' });
141398
141825
  const statusLabel = (active) => active ? t('gradebookGradebookTab.statusActive') : t('gradebookGradebookTab.statusInactive');
141399
- const enrolledSubtitle = (created) => `${t('gradebookGradebookTab.enrolledOn')}: ${formatDate(created)}`;
141826
+ const enrolledSubtitle = (created) => `${t('gradebookGradebookTab.enrolledOn')}: ${formatDate$1(created)}`;
141400
141827
  const paginateClient = (rows) => {
141401
141828
  const filtered = trimmed
141402
141829
  ? rows.filter((row) => row.name.toLowerCase().includes(trimmed.toLowerCase()))
141403
141830
  : rows;
141404
- const start = (page - 1) * PAGE_SIZE$5;
141831
+ const start = (page - 1) * PAGE_SIZE$6;
141405
141832
  return {
141406
- rows: filtered.slice(start, start + PAGE_SIZE$5),
141833
+ rows: filtered.slice(start, start + PAGE_SIZE$6),
141407
141834
  total: filtered.length,
141408
141835
  hasPrev: page > 1,
141409
- hasNext: start + PAGE_SIZE$5 < filtered.length,
141836
+ hasNext: start + PAGE_SIZE$6 < filtered.length,
141410
141837
  };
141411
141838
  };
141412
141839
  switch (type) {
@@ -141463,7 +141890,7 @@ function useGradebookData(type, org, username, page, search) {
141463
141890
  rows,
141464
141891
  total,
141465
141892
  hasPrev: page > 1,
141466
- hasNext: page * PAGE_SIZE$5 < total,
141893
+ hasNext: page * PAGE_SIZE$6 < total,
141467
141894
  isLoading: credentialsQ.isLoading,
141468
141895
  isFetching: credentialsQ.isFetching,
141469
141896
  isError: credentialsQ.isError,
@@ -141702,29 +142129,58 @@ const IblPagination = ({ currentPage, totalPages, onPageChange, disabled = false
141702
142129
 
141703
142130
  const MEMORIES_PAGE_SIZE = 25;
141704
142131
  function MemoryTab({ org, username }) {
141705
- var _a, _b, _c;
142132
+ var _a, _b;
141706
142133
  const t = useT();
141707
142134
  const [isAddDialogOpen, setIsAddDialogOpen] = useState(false);
141708
142135
  const [deletingId, setDeletingId] = useState(null);
141709
142136
  const [currentPage, setCurrentPage] = useState(1);
142137
+ // Viewing someone else's profile, which lists both of that user's memory
142138
+ // collections — global and per-agent — instead of just your own global feed.
142139
+ const isPreview = useIsProfilePreview(username);
142140
+ const currentUsername = useCurrentUsername();
141710
142141
  // Platform memsearch status (available to students and admins)
141711
142142
  const { data: memsearchStatus, isLoading: isLoadingConfig, isError: isConfigError, } = useGetMemsearchStatusQuery({
141712
142143
  org,
141713
142144
  userId: username,
141714
- });
142145
+ }, { skip: isPreview });
141715
142146
  // User memory settings
141716
142147
  const { data: settings, isLoading: isLoadingSettings } = useGetUserMemorySettingsQuery({
141717
142148
  org,
141718
142149
  userId: username,
141719
- });
142150
+ }, { skip: isPreview });
141720
142151
  const [updateSettings, { isLoading: isUpdatingSettings }] = useUpdateUserMemorySettingsMutation();
141721
- // Global memories
141722
- const { data: memoriesData, isLoading: isLoadingMemories } = useGetGlobalMemoriesQuery({
142152
+ const memoriesParams = { page: currentPage, page_size: MEMORIES_PAGE_SIZE };
142153
+ // Global memories. On your own profile this is the plain call — your username
142154
+ // in the path. Previewing someone else addresses it the way the analytics
142155
+ // memory tab does: the caller in the `{user_id}` path segment, and the user
142156
+ // being looked at in the `user_id` param.
142157
+ const { data: globalMemoriesData, isLoading: isLoadingGlobalMemories } = useGetGlobalMemoriesQuery(isPreview
142158
+ ? { org, userId: currentUsername, params: { ...memoriesParams, user_id: username } }
142159
+ : { org, userId: username, params: memoriesParams }, { skip: isPreview && !currentUsername });
142160
+ // Agent memories across every mentor, addressed the same way. Only fetched in
142161
+ // preview, where the tab shows both of the profile owner's collections.
142162
+ const { data: mentorMemoriesData, isLoading: isLoadingMentorMemories } = useGetAllMentorMemoriesQuery({
141723
142163
  org,
141724
- userId: username,
141725
- params: { page: currentPage, page_size: MEMORIES_PAGE_SIZE },
141726
- });
141727
- const totalPages = (memoriesData === null || memoriesData === void 0 ? void 0 : memoriesData.count) ? Math.ceil(memoriesData.count / MEMORIES_PAGE_SIZE) : 0;
142164
+ userId: currentUsername,
142165
+ params: { ...memoriesParams, user_id: username },
142166
+ }, { skip: !isPreview || !currentUsername });
142167
+ const memories = useMemo(() => {
142168
+ var _a, _b;
142169
+ const globalMemories = (_a = globalMemoriesData === null || globalMemoriesData === void 0 ? void 0 : globalMemoriesData.results) !== null && _a !== void 0 ? _a : [];
142170
+ if (!isPreview)
142171
+ return globalMemories;
142172
+ // Both collections are newest-first on their own; interleave them so the
142173
+ // combined list still reads chronologically.
142174
+ return [...((_b = mentorMemoriesData === null || mentorMemoriesData === void 0 ? void 0 : mentorMemoriesData.results) !== null && _b !== void 0 ? _b : []), ...globalMemories].sort((a, b) => new Date(b.created_at).getTime() - new Date(a.created_at).getTime());
142175
+ }, [isPreview, globalMemoriesData, mentorMemoriesData]);
142176
+ const isLoadingMemories = isLoadingGlobalMemories || (isPreview && isLoadingMentorMemories);
142177
+ // The two collections page independently at the same size, so a page shows
142178
+ // that page of each and the pager spans whichever collection is longer.
142179
+ const totalPages = useMemo(() => {
142180
+ const pageCount = (count) => (count ? Math.ceil(count / MEMORIES_PAGE_SIZE) : 0);
142181
+ const globalPages = pageCount(globalMemoriesData === null || globalMemoriesData === void 0 ? void 0 : globalMemoriesData.count);
142182
+ return isPreview ? Math.max(globalPages, pageCount(mentorMemoriesData === null || mentorMemoriesData === void 0 ? void 0 : mentorMemoriesData.count)) : globalPages;
142183
+ }, [isPreview, globalMemoriesData, mentorMemoriesData]);
141728
142184
  const [deleteMemory] = useDeleteGlobalMemoryMutation();
141729
142185
  const handleToggleSetting = async (key, checked) => {
141730
142186
  try {
@@ -141763,7 +142219,7 @@ function MemoryTab({ org, username }) {
141763
142219
  if (!isConfigError && memsearchStatus && !memsearchStatus.enable_memsearch) {
141764
142220
  return (jsx("div", { className: "max-w-2xl", children: jsx("div", { className: "rounded-lg border px-6 py-8 text-center", style: { borderColor: 'oklch(.922 0 0)' }, children: jsx("p", { className: "text-sm text-gray-500", children: t('memoryMemoryTab.memoryFeatureDisabled') }) }) }));
141765
142221
  }
141766
- return (jsxs("div", { className: "space-y-8", children: [jsxs("div", { className: "space-y-4", children: [jsx("h4", { className: "text-sm font-semibold text-gray-700 dark:text-gray-300 tracking-wide", children: t('memoryMemoryTab.sectionMemoryPersonalization') }), jsxs("div", { className: "flex items-center justify-between rounded-lg border px-6 py-5", style: { borderColor: 'oklch(.922 0 0)' }, children: [jsxs("div", { className: "flex-1 mr-4", children: [jsx("span", { className: "text-sm font-medium text-gray-900 dark:text-gray-100", children: t('memoryMemoryTab.autoCaptureLabelTitle') }), jsx("p", { className: "text-xs text-gray-500 dark:text-gray-400 mt-1", children: t('memoryMemoryTab.autoCaptureLabelDesc') })] }), jsx(Switch, { checked: (_a = settings === null || settings === void 0 ? void 0 : settings.auto_capture_enabled) !== null && _a !== void 0 ? _a : false, onCheckedChange: (checked) => handleToggleSetting('auto_capture_enabled', checked), disabled: isUpdatingSettings, "aria-label": t('memoryMemoryTab.autoCaptureAriaLabel', {
142222
+ return (jsxs("div", { className: "space-y-8", children: [!isPreview && (jsxs("div", { className: "space-y-4", children: [!isPreview && (jsx("h4", { className: "text-sm font-semibold text-gray-700 dark:text-gray-300 tracking-wide", children: t('memoryMemoryTab.sectionMemoryPersonalization') })), jsxs("div", { className: "flex items-center justify-between rounded-lg border px-6 py-5", style: { borderColor: 'oklch(.922 0 0)' }, children: [jsxs("div", { className: "flex-1 mr-4", children: [jsx("span", { className: "text-sm font-medium text-gray-900 dark:text-gray-100", children: t('memoryMemoryTab.autoCaptureLabelTitle') }), jsx("p", { className: "text-xs text-gray-500 dark:text-gray-400 mt-1", children: t('memoryMemoryTab.autoCaptureLabelDesc') })] }), jsx(Switch, { checked: (_a = settings === null || settings === void 0 ? void 0 : settings.auto_capture_enabled) !== null && _a !== void 0 ? _a : false, onCheckedChange: (checked) => handleToggleSetting('auto_capture_enabled', checked), disabled: isUpdatingSettings, "aria-label": t('memoryMemoryTab.autoCaptureAriaLabel', {
141767
142223
  state: (settings === null || settings === void 0 ? void 0 : settings.auto_capture_enabled)
141768
142224
  ? t('memoryMemoryTab.stateEnabled')
141769
142225
  : t('memoryMemoryTab.stateDisabled'),
@@ -141771,9 +142227,13 @@ function MemoryTab({ org, username }) {
141771
142227
  state: (settings === null || settings === void 0 ? void 0 : settings.use_memory_in_responses)
141772
142228
  ? t('memoryMemoryTab.stateEnabled')
141773
142229
  : t('memoryMemoryTab.stateDisabled'),
141774
- }), className: "cursor-pointer data-[state=checked]:bg-blue-500 flex-shrink-0" })] })] }), jsxs("div", { className: "space-y-4", children: [jsxs("div", { className: "flex items-center justify-between", children: [jsx("h4", { className: "text-sm font-semibold text-gray-700 dark:text-gray-300 tracking-wide", children: t('memoryMemoryTab.sectionMyMemories') }), jsxs(Button$1, { variant: "outline", size: "sm", onClick: () => setIsAddDialogOpen(true), className: "text-xs", children: [jsx(Plus, { className: "h-3 w-3 mr-1" }), t('memoryMemoryTab.addMemoryButton')] })] }), isLoadingMemories ? (jsx("div", { className: "space-y-3", children: [1, 2, 3].map((i) => (jsx(Skeleton, { className: "h-16 w-full rounded-lg" }, i))) })) : ((_c = memoriesData === null || memoriesData === void 0 ? void 0 : memoriesData.results) === null || _c === void 0 ? void 0 : _c.length) ? (jsx("div", { className: "space-y-3", children: memoriesData.results.map((memory) => (jsxs("div", { className: "group flex items-start gap-3 rounded-lg border px-4 py-3", style: { borderColor: 'oklch(.922 0 0)' }, children: [jsx("div", { className: "flex-shrink-0 mt-0.5", children: memory.is_auto_generated ? (jsx(Bot, { className: "h-4 w-4 text-blue-500", "aria-label": t('memoryMemoryTab.autoGeneratedMemoryAriaLabel') })) : (jsx(User, { className: "h-4 w-4 text-gray-400", "aria-label": t('memoryMemoryTab.manuallyAddedMemoryAriaLabel') })) }), jsxs("div", { className: "flex-1 min-w-0", children: [jsx("p", { className: "text-sm text-gray-800 dark:text-gray-200", children: memory.content }), jsxs("p", { className: "text-xs text-gray-400 mt-1", children: [new Date(memory.created_at).toLocaleDateString(), memory.is_auto_generated && (jsx("span", { className: "ml-2 inline-flex items-center rounded-full bg-blue-50 px-1.5 py-0.5 text-[10px] font-medium text-blue-600", children: t('memoryMemoryTab.autoBadge') }))] })] }), jsx("button", { type: "button", onClick: () => handleDeleteMemory(memory.id), disabled: deletingId === memory.id, className: "flex-shrink-0 opacity-0 group-hover:opacity-100 transition-opacity p-1 rounded hover:bg-gray-100 text-gray-400 hover:text-gray-600 focus:opacity-100 focus:outline-none focus:ring-2 focus:ring-gray-300", "aria-label": t('memoryMemoryTab.deleteMemoryAriaLabel', {
142230
+ }), className: "cursor-pointer data-[state=checked]:bg-blue-500 flex-shrink-0" })] })] })), jsxs("div", { className: "space-y-4", children: [jsxs("div", { className: "flex items-center justify-between", children: [jsx("h4", { className: "text-sm font-semibold text-gray-700 dark:text-gray-300 tracking-wide", children: isPreview
142231
+ ? t('memoryMemoryTab.sectionMyMemoriesPreview')
142232
+ : t('memoryMemoryTab.sectionMyMemories') }), !isPreview && (jsxs(Button$1, { variant: "outline", size: "sm", onClick: () => setIsAddDialogOpen(true), className: "text-xs", children: [jsx(Plus, { className: "h-3 w-3 mr-1" }), t('memoryMemoryTab.addMemoryButton')] }))] }), isLoadingMemories ? (jsx("div", { className: "space-y-3", children: [1, 2, 3].map((i) => (jsx(Skeleton, { className: "h-16 w-full rounded-lg" }, i))) })) : memories.length ? (jsx("div", { className: "space-y-3", children: memories.map((memory) => (jsxs("div", { className: "group flex items-start gap-3 rounded-lg border px-4 py-3", style: { borderColor: 'oklch(.922 0 0)' }, children: [jsx("div", { className: "flex-shrink-0 mt-0.5", children: memory.is_auto_generated ? (jsx(Bot, { className: "h-4 w-4 text-blue-500", "aria-label": t('memoryMemoryTab.autoGeneratedMemoryAriaLabel') })) : (jsx(User, { className: "h-4 w-4 text-gray-400", "aria-label": t('memoryMemoryTab.manuallyAddedMemoryAriaLabel') })) }), jsxs("div", { className: "flex-1 min-w-0", children: [jsx("p", { className: "text-sm text-gray-800 dark:text-gray-200", children: memory.content }), jsxs("p", { className: "text-xs text-gray-400 mt-1", children: [new Date(memory.created_at).toLocaleDateString(), memory.is_auto_generated && (jsx("span", { className: "ml-2 inline-flex items-center rounded-full bg-blue-50 px-1.5 py-0.5 text-[10px] font-medium text-blue-600", children: t('memoryMemoryTab.autoBadge') }))] })] }), !isPreview && (jsx("button", { type: "button", onClick: () => handleDeleteMemory(memory.id), disabled: deletingId === memory.id, className: "flex-shrink-0 opacity-0 group-hover:opacity-100 transition-opacity p-1 rounded hover:bg-gray-100 text-gray-400 hover:text-gray-600 focus:opacity-100 focus:outline-none focus:ring-2 focus:ring-gray-300", "aria-label": t('memoryMemoryTab.deleteMemoryAriaLabel', {
141775
142233
  excerpt: memory.content.substring(0, 30),
141776
- }), children: deletingId === memory.id ? (jsx("div", { className: "w-4 h-4 border-2 border-gray-500 border-t-transparent rounded-full animate-spin" })) : (jsx(Trash2, { className: "h-4 w-4" })) })] }, memory.id))) })) : (jsx("div", { className: "rounded-lg border px-6 py-8 text-center", style: { borderColor: 'oklch(.922 0 0)' }, children: jsx("p", { className: "text-sm text-gray-500", children: t('memoryMemoryTab.noMemoriesYet') }) })), totalPages > 1 && (jsx(IblPagination, { currentPage: currentPage, totalPages: totalPages, onPageChange: setCurrentPage, disabled: isLoadingMemories }))] }), jsx(AddMemoryDialog, { open: isAddDialogOpen, onOpenChange: setIsAddDialogOpen, org: org, username: username })] }));
142234
+ }), children: deletingId === memory.id ? (jsx("div", { className: "w-4 h-4 border-2 border-gray-500 border-t-transparent rounded-full animate-spin" })) : (jsx(Trash2, { className: "h-4 w-4" })) }))] }, `${'mentor_id' in memory ? memory.mentor_id : 'global'}-${memory.id}`))) })) : (jsx("div", { className: "rounded-lg border px-6 py-8 text-center", style: { borderColor: 'oklch(.922 0 0)' }, children: jsx("p", { className: "text-sm text-gray-500", children: isPreview
142235
+ ? t('memoryMemoryTab.noMemoriesYetPreview')
142236
+ : t('memoryMemoryTab.noMemoriesYet') }) })), totalPages > 1 && (jsx(IblPagination, { currentPage: currentPage, totalPages: totalPages, onPageChange: setCurrentPage, disabled: isLoadingMemories }))] }), jsx(AddMemoryDialog, { open: isAddDialogOpen, onOpenChange: setIsAddDialogOpen, org: org, username: username })] }));
141777
142237
  }
141778
142238
 
141779
142239
  // One entry per chat-privacy mode. `description` is read inline on each
@@ -143872,7 +144332,9 @@ const PopoverContent = React.forwardRef(({ className, align = 'center', sideOffs
143872
144332
  });
143873
144333
  PopoverContent.displayName = Content2$3.displayName;
143874
144334
 
144335
+ const PAGE_SIZE$5 = 10;
143875
144336
  function UsersTab({ tenant, onInviteClick, currentSpa, showGradebookTab = false, }) {
144337
+ var _a, _b;
143876
144338
  const t = useT();
143877
144339
  const dispatch = useDispatch();
143878
144340
  const [page, setPage] = useState(1);
@@ -143884,14 +144346,35 @@ function UsersTab({ tenant, onInviteClick, currentSpa, showGradebookTab = false,
143884
144346
  const [updatingUserIds, setUpdatingUserIds] = useState(new Set());
143885
144347
  const [openPolicyPopover, setOpenPolicyPopover] = useState(null);
143886
144348
  const [selectedUser, setSelectedUser] = useState(null);
143887
- const { data: users, refetch: refetchPlatformUsers, isLoading, } = usePlatformUsersQuery({
144349
+ const { currentTenant } = useCurrentTenant();
144350
+ const rbacPermissions = useSelector(selectRbacPermissions);
144351
+ // A pure watcher administers nothing: the platform users endpoint 403s for
144352
+ // them, so they get the RBAC-scoped list of users they may read instead —
144353
+ // name and email only, with no invite, role, policy or status controls.
144354
+ const isWatcher = isPureWatcher(rbacPermissions, currentTenant);
144355
+ const { data: users, refetch: refetchPlatformUsers, isLoading: isLoadingPlatformUsers, } = usePlatformUsersQuery({
143888
144356
  page,
143889
- page_size: 10,
144357
+ page_size: PAGE_SIZE$5,
143890
144358
  platform_key: tenant,
143891
144359
  platform_org: tenant,
143892
144360
  query: debouncedSearchQuery,
143893
144361
  return_policies: 'true',
143894
- });
144362
+ }, { skip: isWatcher });
144363
+ // The accessible endpoint scopes itself to the caller's platform from their
144364
+ // token, so it takes no tenant param. It also filters per field instead of
144365
+ // with one search param, hence the "@" routing the term to `email` and
144366
+ // anything else to `username`.
144367
+ const { data: accessibleUsers, isLoading: isLoadingAccessibleUsers } = useGetAccessibleUsersQuery({
144368
+ // TODO to use required_action: 'Ibl.Core/Users/read',
144369
+ required_action: 'Ibl.Mentor/Memory/list',
144370
+ page,
144371
+ page_size: PAGE_SIZE$5,
144372
+ sort: 'name',
144373
+ ...(debouncedSearchQuery.includes('@')
144374
+ ? { email: debouncedSearchQuery }
144375
+ : { username: debouncedSearchQuery }),
144376
+ }, { skip: !isWatcher });
144377
+ const isLoading = isWatcher ? isLoadingAccessibleUsers : isLoadingPlatformUsers;
143895
144378
  useEffect(() => {
143896
144379
  const handler = setTimeout(() => {
143897
144380
  if (searchQuery.length > 2) {
@@ -143908,7 +144391,10 @@ function UsersTab({ tenant, onInviteClick, currentSpa, showGradebookTab = false,
143908
144391
  }, [searchQuery]);
143909
144392
  const handlePageChange = async (newPage) => {
143910
144393
  setPage(newPage);
143911
- await refetchPlatformUsers();
144394
+ // The watcher list is served by the other (skipped) query — changing `page`
144395
+ // is enough to refetch it.
144396
+ if (!isWatcher)
144397
+ await refetchPlatformUsers();
143912
144398
  };
143913
144399
  const handleUserRoleChange = async (user) => {
143914
144400
  const userId = user === null || user === void 0 ? void 0 : user.user_id;
@@ -144026,8 +144512,6 @@ function UsersTab({ tenant, onInviteClick, currentSpa, showGradebookTab = false,
144026
144512
  });
144027
144513
  }
144028
144514
  };
144029
- // Calculate total pages
144030
- const totalPages = users ? Math.ceil(users.count / 10) : 0; // Assuming 10 users per page
144031
144515
  // Extract allowed policies and user data
144032
144516
  const isResultsWithPolicies = (users === null || users === void 0 ? void 0 : users.results) ? isPoliciesResponse(users.results) : false;
144033
144517
  const allowedPolicies = isResultsWithPolicies
@@ -144036,31 +144520,55 @@ function UsersTab({ tenant, onInviteClick, currentSpa, showGradebookTab = false,
144036
144520
  const userData = isResultsWithPolicies
144037
144521
  ? (users === null || users === void 0 ? void 0 : users.results).data
144038
144522
  : [];
144039
- return (jsxs("div", { className: "mt-4", children: [jsxs("div", { className: "flex justify-between items-center gap-1", children: [jsxs("div", { className: "relative mb-6 max-w-sm", children: [jsx(Search, { className: "absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-gray-400" }), jsx(Input, { type: "text", value: searchQuery, onChange: (event) => setQuerySearch(event.target.value), placeholder: t('tabsUserstab.searchPlaceholder'), className: "pl-10 pr-10 focus:ring-blue-500 focus:border-blue-500 h-[35px]", "aria-label": t('tabsUserstab.searchAriaLabel') }), searchQuery.length > 0 && (searchQuery !== debouncedSearchQuery || isLoading) && (jsx(LoaderCircle, { "data-testid": "search-spinner", className: "absolute right-3 top-1/2 -translate-y-1/2 h-4 w-4 text-gray-400 animate-spin", "aria-hidden": "true" }))] }), jsx("div", { className: "mb-6", children: jsx(Button$1, { className: "bg-gradient-to-r from-[#2563EB] to-[#93C5FD] hover:opacity-90 text-white h-[35px]", onClick: onInviteClick, children: t('tabsUserstab.inviteButton') }) })] }), isLoading ? (jsx("div", { className: "flex justify-center items-center h-64", children: jsx(Spinner, {}) })) : (jsxs(Fragment$1, { children: [jsx("div", { className: "bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-lg overflow-x-auto", children: jsxs("table", { className: "w-full text-sm", children: [jsx("thead", { className: "bg-gray-50 dark:bg-gray-700 border-b border-gray-200 dark:border-gray-600", children: jsxs("tr", { children: [jsx("th", { className: "px-6 py-3 text-left font-medium text-gray-500 dark:text-gray-400 w-[16%]", children: t('tabsUserstab.columnName') }), jsx("th", { className: "px-6 py-3 text-left font-medium text-gray-500 dark:text-gray-400 w-[25%]", children: t('tabsUserstab.columnEmail') }), jsx("th", { className: "px-6 py-3 text-left font-medium text-gray-500 dark:text-gray-400 w-[16%]", children: t('tabsUserstab.columnRole') }), jsx("th", { className: "px-6 py-3 text-left font-medium text-gray-500 dark:text-gray-400 w-[25%]", children: t('tabsUserstab.columnPolicies') }), jsx("th", { className: "px-6 py-3 text-left font-medium text-gray-500 dark:text-gray-400 w-[18%]", children: t('tabsUserstab.columnStatus') })] }) }), jsxs("tbody", { className: "divide-y divide-gray-200 dark:divide-gray-600", children: [userData.map((user, index) => (jsxs("tr", { onClick: () => setSelectedUser(user), className: "cursor-pointer hover:bg-gray-50 dark:hover:bg-gray-700/50 transition-colors", children: [jsx("td", { "aria-label": 'user-management-name-column', className: "px-6 py-4 text-gray-900 dark:text-gray-100 text-sm whitespace-nowrap overflow-hidden text-ellipsis max-w-0", children: jsx("button", { type: "button", onClick: (e) => {
144040
- e.stopPropagation();
144041
- setSelectedUser(user);
144042
- }, className: "block max-w-full truncate text-left hover:text-blue-600 hover:underline focus:outline-none focus:text-blue-600", "aria-label": t('tabsUserstab.viewProfileAriaLabel', { name: user.name }), children: user.name }) }), jsx("td", { "aria-label": 'user-management-email-column', className: "px-6 py-4 text-gray-600 dark:text-gray-300 text-sm max-w-0", children: jsx("div", { className: "truncate", children: user.email }) }), jsx("td", { className: "px-6 py-4", onClick: (e) => e.stopPropagation(), children: jsxs(Select$1, { value: user.is_admin ? 'admin' : 'student', onValueChange: () => handleUserRoleChange(user), children: [jsx(SelectTrigger, { className: "w-full text-sm", children: jsx(SelectValue, {}) }), jsxs(SelectContent, { className: "text-sm", children: [jsx(SelectItem, { value: "admin", children: t('tabsUserstab.roleAdmin') }), jsx(SelectItem, { value: "student", children: t('tabsUserstab.roleUser') })] })] }) }), jsx("td", { className: "px-6 py-4", onClick: (e) => e.stopPropagation(), children: jsxs(Popover, { modal: true, open: openPolicyPopover === user.user_id, onOpenChange: (open) => setOpenPolicyPopover(open ? user.user_id : null), children: [jsx(PopoverTrigger, { asChild: true, children: jsxs(Button$1, { variant: "outline", role: "combobox", "aria-expanded": openPolicyPopover === user.user_id, "aria-label": t('tabsUserstab.selectPoliciesAriaLabel', {
144523
+ const rows = isWatcher
144524
+ ? ((_a = accessibleUsers === null || accessibleUsers === void 0 ? void 0 : accessibleUsers.results) !== null && _a !== void 0 ? _a : []).map((user) => ({
144525
+ key: user.id,
144526
+ name: user.name,
144527
+ email: user.email,
144528
+ username: user.username,
144529
+ isAdmin: false,
144530
+ }))
144531
+ : userData.map((user) => ({
144532
+ key: user.user_id,
144533
+ name: user.name,
144534
+ email: user.email,
144535
+ username: user.username,
144536
+ isAdmin: user.is_admin,
144537
+ managed: user,
144538
+ }));
144539
+ const totalCount = (_b = (isWatcher ? accessibleUsers === null || accessibleUsers === void 0 ? void 0 : accessibleUsers.count : users === null || users === void 0 ? void 0 : users.count)) !== null && _b !== void 0 ? _b : 0;
144540
+ const totalPages = Math.ceil(totalCount / PAGE_SIZE$5);
144541
+ return (jsxs("div", { className: "mt-4", children: [jsxs("div", { className: "flex justify-between items-center gap-1", children: [jsxs("div", { className: "relative mb-6 max-w-sm", children: [jsx(Search, { className: "absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-gray-400" }), jsx(Input, { type: "text", value: searchQuery, onChange: (event) => setQuerySearch(event.target.value), placeholder: t('tabsUserstab.searchPlaceholder'), className: "pl-10 pr-10 focus:ring-blue-500 focus:border-blue-500 h-[35px]", "aria-label": t('tabsUserstab.searchAriaLabel') }), searchQuery.length > 0 && (searchQuery !== debouncedSearchQuery || isLoading) && (jsx(LoaderCircle, { "data-testid": "search-spinner", className: "absolute right-3 top-1/2 -translate-y-1/2 h-4 w-4 text-gray-400 animate-spin", "aria-hidden": "true" }))] }), !isWatcher && (jsx("div", { className: "mb-6", children: jsx(Button$1, { className: "bg-gradient-to-r from-[#2563EB] to-[#93C5FD] hover:opacity-90 text-white h-[35px]", onClick: onInviteClick, children: t('tabsUserstab.inviteButton') }) }))] }), isLoading ? (jsx("div", { className: "flex justify-center items-center h-64", children: jsx(Spinner, {}) })) : (jsxs(Fragment$1, { children: [jsx("div", { className: "bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-lg overflow-x-auto", children: jsxs("table", { className: "w-full text-sm", children: [jsx("thead", { className: "bg-gray-50 dark:bg-gray-700 border-b border-gray-200 dark:border-gray-600", children: jsxs("tr", { children: [jsx("th", { className: `px-6 py-3 text-left font-medium text-gray-500 dark:text-gray-400 ${isWatcher ? 'w-[40%]' : 'w-[16%]'}`, children: t('tabsUserstab.columnName') }), jsx("th", { className: `px-6 py-3 text-left font-medium text-gray-500 dark:text-gray-400 ${isWatcher ? 'w-[60%]' : 'w-[25%]'}`, children: t('tabsUserstab.columnEmail') }), !isWatcher && (jsxs(Fragment$1, { children: [jsx("th", { className: "px-6 py-3 text-left font-medium text-gray-500 dark:text-gray-400 w-[16%]", children: t('tabsUserstab.columnRole') }), jsx("th", { className: "px-6 py-3 text-left font-medium text-gray-500 dark:text-gray-400 w-[25%]", children: t('tabsUserstab.columnPolicies') }), jsx("th", { className: "px-6 py-3 text-left font-medium text-gray-500 dark:text-gray-400 w-[18%]", children: t('tabsUserstab.columnStatus') })] }))] }) }), jsxs("tbody", { className: "divide-y divide-gray-200 dark:divide-gray-600", children: [rows.map((row) => {
144542
+ // Only set on the admin path — see {@link UserRow}.
144543
+ const user = row.managed;
144544
+ return (jsxs("tr", { onClick: () => setSelectedUser(row), className: "cursor-pointer hover:bg-gray-50 dark:hover:bg-gray-700/50 transition-colors", children: [jsx("td", { "aria-label": 'user-management-name-column', className: "px-6 py-4 text-gray-900 dark:text-gray-100 text-sm whitespace-nowrap overflow-hidden text-ellipsis max-w-0", children: jsx("button", { type: "button", onClick: (e) => {
144545
+ e.stopPropagation();
144546
+ setSelectedUser(row);
144547
+ }, className: "block max-w-full truncate text-left hover:text-blue-600 hover:underline focus:outline-none focus:text-blue-600", "aria-label": t('tabsUserstab.viewProfileAriaLabel', { name: row.name }), children: row.name }) }), jsx("td", { "aria-label": 'user-management-email-column', className: "px-6 py-4 text-gray-600 dark:text-gray-300 text-sm max-w-0", children: jsx("div", { className: "truncate", children: row.email }) }), user && (jsxs(Fragment$1, { children: [jsx("td", { className: "px-6 py-4", onClick: (e) => e.stopPropagation(), children: jsxs(Select$1, { value: user.is_admin ? 'admin' : 'student', onValueChange: () => handleUserRoleChange(user), children: [jsx(SelectTrigger, { className: "w-full text-sm", children: jsx(SelectValue, {}) }), jsxs(SelectContent, { className: "text-sm", children: [jsx(SelectItem, { value: "admin", children: t('tabsUserstab.roleAdmin') }), jsx(SelectItem, { value: "student", children: t('tabsUserstab.roleUser') })] })] }) }), jsx("td", { className: "px-6 py-4", onClick: (e) => e.stopPropagation(), children: jsxs(Popover, { modal: true, open: openPolicyPopover === user.user_id, onOpenChange: (open) => setOpenPolicyPopover(open ? user.user_id : null), children: [jsx(PopoverTrigger, { asChild: true, children: jsxs(Button$1, { variant: "outline", role: "combobox", "aria-expanded": openPolicyPopover === user.user_id, "aria-label": t('tabsUserstab.selectPoliciesAriaLabel', {
144548
+ name: user.name,
144549
+ }), className: "w-full justify-between text-sm h-9 font-normal", disabled: updatingUserIds.has(user === null || user === void 0 ? void 0 : user.user_id), children: [jsx("span", { className: "truncate", children: user.is_admin
144550
+ ? t('tabsUserstab.allPoliciesSelected', {
144551
+ count: allowedPolicies.length,
144552
+ })
144553
+ : user.policies && user.policies.length > 0
144554
+ ? t('tabsUserstab.nPoliciesSelected', {
144555
+ count: user.policies.length,
144556
+ })
144557
+ : t('tabsUserstab.noPolicies') }), openPolicyPopover === user.user_id ? (jsx(ChevronUp, { className: "ml-2 h-4 w-4 shrink-0 opacity-50" })) : (jsx(ChevronDown, { className: "ml-2 h-4 w-4 shrink-0 opacity-50" }))] }) }), jsx(PopoverContent, { className: "w-64 p-3", align: "start", children: jsxs("div", { className: "space-y-2", children: [jsx("div", { className: "text-sm font-medium mb-2", children: t('tabsUserstab.selectPoliciesHeading') }), allowedPolicies.map((policy) => {
144558
+ var _a;
144559
+ return (jsxs("div", { className: "flex items-center space-x-2", children: [jsx(Checkbox, { id: `${user.user_id}-${policy}`, checked: user.is_admin || ((_a = user.policies) === null || _a === void 0 ? void 0 : _a.includes(policy)), onCheckedChange: (checked) => handlePolicyChange(user, policy, checked), disabled: user.is_admin || updatingUserIds.has(user === null || user === void 0 ? void 0 : user.user_id), "aria-label": t('tabsUserstab.togglePolicyAriaLabel', {
144560
+ policy,
144561
+ name: user.name,
144562
+ }) }), jsx("label", { htmlFor: `${user.user_id}-${policy}`, className: `text-sm font-normal ${user.is_admin ? 'cursor-default' : 'cursor-pointer'}`, children: policy })] }, policy));
144563
+ })] }) })] }) }), jsx("td", { className: "px-6 py-4", onClick: (e) => e.stopPropagation(), children: jsx(Switch, { checked: user.active, onCheckedChange: (checked) => handleUserStatusChange(user, checked), disabled: updatingUserIds.has(user === null || user === void 0 ? void 0 : user.user_id), "aria-label": t('tabsUserstab.toggleStatusAriaLabel', {
144043
144564
  name: user.name,
144044
- }), className: "w-full justify-between text-sm h-9 font-normal", disabled: updatingUserIds.has(user === null || user === void 0 ? void 0 : user.user_id), children: [jsx("span", { className: "truncate", children: user.is_admin
144045
- ? t('tabsUserstab.allPoliciesSelected', {
144046
- count: allowedPolicies.length,
144047
- })
144048
- : user.policies && user.policies.length > 0
144049
- ? t('tabsUserstab.nPoliciesSelected', {
144050
- count: user.policies.length,
144051
- })
144052
- : t('tabsUserstab.noPolicies') }), openPolicyPopover === user.user_id ? (jsx(ChevronUp, { className: "ml-2 h-4 w-4 shrink-0 opacity-50" })) : (jsx(ChevronDown, { className: "ml-2 h-4 w-4 shrink-0 opacity-50" }))] }) }), jsx(PopoverContent, { className: "w-64 p-3", align: "start", children: jsxs("div", { className: "space-y-2", children: [jsx("div", { className: "text-sm font-medium mb-2", children: t('tabsUserstab.selectPoliciesHeading') }), allowedPolicies.map((policy) => {
144053
- var _a;
144054
- return (jsxs("div", { className: "flex items-center space-x-2", children: [jsx(Checkbox, { id: `${user.user_id}-${policy}`, checked: user.is_admin || ((_a = user.policies) === null || _a === void 0 ? void 0 : _a.includes(policy)), onCheckedChange: (checked) => handlePolicyChange(user, policy, checked), disabled: user.is_admin || updatingUserIds.has(user === null || user === void 0 ? void 0 : user.user_id), "aria-label": t('tabsUserstab.togglePolicyAriaLabel', {
144055
- policy,
144056
- name: user.name,
144057
- }) }), jsx("label", { htmlFor: `${user.user_id}-${policy}`, className: `text-sm font-normal ${user.is_admin ? 'cursor-default' : 'cursor-pointer'}`, children: policy })] }, policy));
144058
- })] }) })] }) }), jsx("td", { className: "px-6 py-4", onClick: (e) => e.stopPropagation(), children: jsx(Switch, { checked: user.active, onCheckedChange: (checked) => handleUserStatusChange(user, checked), disabled: updatingUserIds.has(user === null || user === void 0 ? void 0 : user.user_id), "aria-label": t('tabsUserstab.toggleStatusAriaLabel', { name: user.name }), className: "cursor-pointer data-[state=checked]:bg-blue-500 disabled:cursor-not-allowed disabled:opacity-50" }) })] }, index))), (!userData || userData.length === 0) && (jsx("tr", { children: jsx("td", { colSpan: 5, className: "px-6 py-8 text-center text-gray-500 dark:text-gray-400", children: t('tabsUserstab.noUsersFound') }) }))] })] }) }), jsx(AdvancedPagination, { variant: "footer", className: "-mx-6 -mb-6 mt-4 rounded-b-lg", totalPages: totalPages, currentPage: page, onPageChange: (_page) => handlePageChange(_page), totalCount: users === null || users === void 0 ? void 0 : users.count, itemsPerPage: 10, itemLabel: "users" })] })), selectedUser && (jsx(Dialog, { open: !!selectedUser, onOpenChange: (open) => {
144565
+ }), className: "cursor-pointer data-[state=checked]:bg-blue-500 disabled:cursor-not-allowed disabled:opacity-50" }) })] }))] }, row.key));
144566
+ }), rows.length === 0 && (jsx("tr", { children: jsx("td", { colSpan: isWatcher ? 2 : 5, className: "px-6 py-8 text-center text-gray-500 dark:text-gray-400", children: t('tabsUserstab.noUsersFound') }) }))] })] }) }), jsx(AdvancedPagination, { variant: "footer", className: "-mx-6 -mb-6 mt-4 rounded-b-lg", totalPages: totalPages, currentPage: page, onPageChange: (_page) => handlePageChange(_page), totalCount: totalCount, itemsPerPage: PAGE_SIZE$5, itemLabel: "users" })] })), selectedUser && (jsx(Dialog, { open: !!selectedUser, onOpenChange: (open) => {
144059
144567
  if (!open)
144060
144568
  setSelectedUser(null);
144061
- }, children: jsxs(DialogContent, { autoFocus: false, className: "max-w-7xl w-[85vw] p-0 gap-0 overflow-hidden bg-white profile-component-dialog", style: { height: '85vh', display: 'flex', flexDirection: 'column' }, children: [jsx(DialogTitle, { className: "sr-only", children: t('tabsUserstab.profileDialogTitle') }), jsx(DialogDescription, { className: "sr-only", children: t('tabsUserstab.profileDialogDescription') }), jsx(Profile, { tenant: tenant, tenants: [], username: selectedUser.username, isAdmin: selectedUser.is_admin, currentSPA: currentSpa, onClose: () => setSelectedUser(null), customization: {
144569
+ }, children: jsxs(DialogContent, { autoFocus: false, className: "max-w-7xl w-[85vw] p-0 gap-0 overflow-hidden bg-white profile-component-dialog", style: { height: '85vh', display: 'flex', flexDirection: 'column' }, children: [jsx(DialogTitle, { className: "sr-only", children: t('tabsUserstab.profileDialogTitle') }), jsx(DialogDescription, { className: "sr-only", children: t('tabsUserstab.profileDialogDescription') }), jsx(Profile, { tenant: tenant, tenants: [], username: selectedUser.username, isAdmin: selectedUser.isAdmin, currentSPA: currentSpa, onClose: () => setSelectedUser(null), customization: {
144062
144570
  showGradebookTab: showGradebookTab,
144063
- } })] }) }))] }));
144571
+ }, enableMemoryTab: true })] }) }))] }));
144064
144572
  }
144065
144573
 
144066
144574
  // Permission options for teams access
@@ -146968,7 +147476,7 @@ function BlocksView({ platformKey, onBack, }) {
146968
147476
 
146969
147477
  const FILTER_ORDER = ['all', ...APPLICATION_STATUSES];
146970
147478
  const PAGE_SIZE$3 = 20;
146971
- const SEARCH_DEBOUNCE_MS = 300;
147479
+ const SEARCH_DEBOUNCE_MS$1 = 300;
146972
147480
  /**
146973
147481
  * The public application URL on the auth SPA for one form of a platform
146974
147482
  * (`<auth-url>/applications/<platform-key>/<form-id>?app=<spa>`), or null when
@@ -147077,7 +147585,7 @@ function SubmissionsPipeline({ platformKey, form, onBack, onOpen, }) {
147077
147585
  const timer = setTimeout(() => {
147078
147586
  setDebouncedSearch(search.trim());
147079
147587
  setDebouncedCandidateFilter(candidateFilter.trim());
147080
- }, SEARCH_DEBOUNCE_MS);
147588
+ }, SEARCH_DEBOUNCE_MS$1);
147081
147589
  return () => clearTimeout(timer);
147082
147590
  }, [search, candidateFilter]);
147083
147591
  // New filters restart paging.
@@ -151814,7 +152322,7 @@ function SearchableMultiSelect({ items, selectedItems, onSelectionChange, search
151814
152322
  }) }))] }));
151815
152323
  }
151816
152324
 
151817
- function useDebouncedValue$3(value, delay) {
152325
+ function useDebouncedValue$4(value, delay) {
151818
152326
  const [debouncedValue, setDebouncedValue] = React__default.useState(value);
151819
152327
  React__default.useEffect(() => {
151820
152328
  const timer = window.setTimeout(() => setDebouncedValue(value), delay);
@@ -151859,8 +152367,8 @@ function TokenPolicyFields({ tenantKey, mode, onModeChange, policies, onPolicies
151859
152367
  const t = useT();
151860
152368
  const [policySearch, setPolicySearch] = React__default.useState('');
151861
152369
  const [groupSearch, setGroupSearch] = React__default.useState('');
151862
- const debouncedPolicySearch = useDebouncedValue$3(policySearch, RBAC_SEARCH_DEBOUNCE_MS);
151863
- const debouncedGroupSearch = useDebouncedValue$3(groupSearch, RBAC_SEARCH_DEBOUNCE_MS);
152370
+ const debouncedPolicySearch = useDebouncedValue$4(policySearch, RBAC_SEARCH_DEBOUNCE_MS);
152371
+ const debouncedGroupSearch = useDebouncedValue$4(groupSearch, RBAC_SEARCH_DEBOUNCE_MS);
151864
152372
  const canWriteMode = canWriteField(fieldPermissions, 'mode');
151865
152373
  const canWritePolicies = canWriteField(fieldPermissions, 'policies_to_add') ||
151866
152374
  canWriteField(fieldPermissions, 'policies_to_remove');
@@ -152139,6 +152647,64 @@ function CreateApiModal({ isOpen, onClose, tenantKey, username }) {
152139
152647
  : t('apiTabLabels.createModal.submit') })) }) })] })] }) }), apiKey && jsx(ApiKeyModal, { isOpen: true, onClose: () => setApiKey(null), apiKey: apiKey })] }));
152140
152648
  }
152141
152649
 
152650
+ /**
152651
+ * Returns the canonical logo path and display name for an LLM provider.
152652
+ * `logo` is a static-root path (e.g. `/llm-amazon-provider.png`); the package
152653
+ * ships the canonical assets under `@iblai/web-containers/public/` — copy them
152654
+ * into your app's static-root (`public/` for Next.js) so the paths resolve.
152655
+ */
152656
+ function getLLMProviderDetails(llmProvider, llmName) {
152657
+ switch (llmProvider) {
152658
+ case 'groq':
152659
+ return { logo: '/llm-groq-provider.png', name: 'Groq' };
152660
+ case 'azure_openai':
152661
+ return { logo: '/llm-microsoft-provider.png', name: 'Microsoft' };
152662
+ case 'openai':
152663
+ if (llmName)
152664
+ return { logo: '/llm-openai-provider.jpg', name: 'OpenAI' };
152665
+ return { logo: '/llm-openai-provider-2.svg', name: 'OpenAI' };
152666
+ case 'mistral':
152667
+ return { logo: '/llm-mistral-provider.jpeg', name: 'Mistral' };
152668
+ case 'google':
152669
+ if (llmName)
152670
+ return { logo: '/llm-gemini-provider.png', name: 'Google' };
152671
+ return { logo: '/llm-google-provider.svg', name: 'Google' };
152672
+ case 'llama':
152673
+ return { logo: '/llm-llama-provider.jpeg', name: 'Meta' };
152674
+ case 'perplexity':
152675
+ return { logo: '/llm-perplexity-provider.webp', name: 'Perplexity' };
152676
+ case 'deepseek':
152677
+ return { logo: '/llm-deepseek-provider.png', name: 'DeepSeek' };
152678
+ case 'xai':
152679
+ return { logo: '/llm-xai-provider.jpg', name: 'xAI' };
152680
+ case 'IBLChatAnthropic':
152681
+ case 'anthropic':
152682
+ return { logo: '/llm-claude-provider.png', name: 'Anthropic' };
152683
+ case 'IBLChatNvidia':
152684
+ case 'nvidia':
152685
+ return { logo: '/llm-nvidia-provider.webp', name: 'NVIDIA' };
152686
+ case 'bedrock':
152687
+ case 'amazon-bedrock':
152688
+ case 'amazon_bedrock':
152689
+ case 'IBLChatBedrock':
152690
+ return { logo: '/llm-amazon-provider.png', name: 'Amazon' };
152691
+ // ibl.ai's own hosted provider. The backend key is `iblai` (NameEnum.IBLAI);
152692
+ // the other cases cover the `IBLChat<Vendor>` house spelling and the
152693
+ // dotted/dashed/underscored brand forms seen in labels and older payloads.
152694
+ case 'iblai':
152695
+ case 'IBLAI':
152696
+ case 'ibl.ai':
152697
+ case 'ibl_ai':
152698
+ case 'ibl-ai':
152699
+ case 'ibl':
152700
+ case 'IBLChatIBL':
152701
+ case 'IBLChatIBLAI':
152702
+ return { logo: '/llm-iblai-provider.png', name: 'ibl.ai' };
152703
+ default:
152704
+ return { logo: '/llm-generic-provider.png', name: llmProvider };
152705
+ }
152706
+ }
152707
+
152142
152708
  // Dynamic schema based on selected provider
152143
152709
  const createDynamicSchema$1 = (schemaFields) => {
152144
152710
  const schemaObj = {
@@ -152367,10 +152933,14 @@ function CreateLLMModal({ isOpen, onClose, tenantKey, onSuccess }) {
152367
152933
  }
152368
152934
  }, children: [jsx(SelectTrigger, { children: jsx(SelectValue, { placeholder: t('llmsTabCreateLlmModal.selectProviderPlaceholder') }) }), jsx(SelectContent, { children: availableProviders.map((provider) => {
152369
152935
  var _a, _b;
152370
- const providerLogo = (_a = provider === null || provider === void 0 ? void 0 : provider.service_info) === null || _a === void 0 ? void 0 : _a.logo;
152936
+ // Prefer the logo the API ships; fall back to the
152937
+ // bundled provider artwork so known providers (ibl.ai
152938
+ // included) never degrade to a generic key emoji.
152939
+ const providerLogo = ((_a = provider === null || provider === void 0 ? void 0 : provider.service_info) === null || _a === void 0 ? void 0 : _a.logo) ||
152940
+ getLLMProviderDetails(provider.name).logo;
152371
152941
  const providerName = ((_b = provider === null || provider === void 0 ? void 0 : provider.service_info) === null || _b === void 0 ? void 0 : _b.display_name) ||
152372
152942
  provider.name;
152373
- return (jsx(SelectItem, { value: provider.name, children: jsxs("div", { className: "flex items-center gap-2", children: [providerLogo ? (jsx("img", { src: providerLogo, alt: provider.name, className: "w-4 h-4 rounded-sm object-contain" })) : (jsx("span", { children: "\uD83D\uDD11" })), providerName || provider.name] }) }, provider.name));
152943
+ return (jsx(SelectItem, { value: provider.name, children: jsxs("div", { className: "flex items-center gap-2", children: [jsx("img", { src: providerLogo, alt: provider.name, className: "w-4 h-4 rounded-sm object-contain" }), providerName || provider.name] }) }, provider.name));
152374
152944
  }) })] }), shouldShowError && (jsx("p", { className: "text-red-500 text-xs", children: (_b = field.state.meta.errors[0]) === null || _b === void 0 ? void 0 : _b.message }))] }));
152375
152945
  } })), isCredentialsSchemaLoading && (jsxs("div", { className: "flex items-center justify-center py-4", children: [jsx(LoaderCircle, { className: "h-4 w-4 animate-spin mr-2" }), jsx("span", { className: "text-sm text-gray-600", children: t('llmsTabCreateLlmModal.loadingProviderConfigurations') })] })), showProviderForm && !isCredentialsSchemaLoading && !isAzureOpenAI && (jsx(Fragment$1, { children: schemaFields.map((fieldName) => (jsx(form.Field, { name: fieldName, children: (field) => {
152376
152946
  var _a, _b;
@@ -152459,17 +153029,22 @@ function IntegrationLLMsTab({ tenantKey }) {
152459
153029
  return (jsxs("div", { className: "space-y-4", children: [jsx(InfoBanner, { icon: jsx(Bot, { className: "w-5 h-5" }), children: t('llmsTabIntegrationLlmsTab.infoBannerText') }), jsx("div", { className: "bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-lg overflow-x-auto", children: jsxs("table", { className: "w-full text-sm min-w-[600px]", children: [jsx("thead", { className: "bg-gray-50 dark:bg-gray-700 border-b border-gray-200 dark:border-gray-600", children: jsxs("tr", { children: [jsx("th", { className: "px-6 py-3 text-left font-medium text-gray-500 dark:text-gray-400", children: t('llmsTabIntegrationLlmsTab.colName') }), jsx("th", { className: "px-6 py-3 text-left font-medium text-gray-500 dark:text-gray-400", children: t('llmsTabIntegrationLlmsTab.colKey') }), jsx("th", { className: "px-6 py-3 text-left font-medium text-gray-500 dark:text-gray-400 w-[50px]" })] }) }), jsx("tbody", { className: "divide-y divide-gray-200 dark:divide-gray-600", children: isMaskedCredentialsLoading ? (jsx("tr", { children: jsx("td", { colSpan: 3, className: "px-6 py-8 text-center text-sm text-gray-500", children: t('llmsTabIntegrationLlmsTab.loading') }) })) : maskedCredentials.length === 0 ? (jsx("tr", { children: jsx("td", { colSpan: 3, className: "px-6 py-8 text-center text-sm text-gray-500", children: t('llmsTabIntegrationLlmsTab.noLlmKeysFound') }) })) : (maskedCredentials.map((cred, idx) => {
152460
153030
  var _a, _b, _c;
152461
153031
  const provider = ((_a = cred.service_info) === null || _a === void 0 ? void 0 : _a.display_name) || cred.name;
152462
- // Use logo from service_info only
153032
+ // Prefer the logo the API ships; fall back to the bundled
153033
+ // provider artwork so known providers (ibl.ai included) never
153034
+ // degrade to a generic key emoji.
152463
153035
  let logoUrl;
152464
153036
  let logoAlt;
152465
153037
  if ((_b = cred.service_info) === null || _b === void 0 ? void 0 : _b.logo) {
152466
153038
  logoUrl = cred.service_info.logo;
152467
153039
  logoAlt = cred.service_info.display_name || cred.service_info.name;
152468
153040
  }
153041
+ else {
153042
+ logoUrl = getLLMProviderDetails(cred.name).logo;
153043
+ }
152469
153044
  const isAzure = isAzureOpenAI(cred);
152470
153045
  const azureModels = isAzure ? getAzureModels(cred) : [];
152471
153046
  const isExpanded = expandedRows.has(cred.name);
152472
- return (jsxs(React__default.Fragment, { children: [jsxs("tr", { children: [jsx("td", { className: "px-6 py-4", children: jsxs("div", { className: "flex items-center gap-2", children: [logoUrl ? (jsx("img", { src: logoUrl, alt: logoAlt || provider || cred.name, className: "w-6 h-6 rounded-sm object-contain" })) : (jsx("span", { className: "text-lg", children: '🔑' })), jsx("span", { className: "font-normal text-gray-900 dark:text-gray-100", children: provider || cred.name }), isAzure && azureModels.length > 0 && (jsx("button", { type: "button", onClick: () => toggleRowExpansion(cred.name), className: "p-0.5 hover:bg-gray-100 rounded", children: isExpanded ? (jsx(ChevronUp, { className: "h-4 w-4 text-gray-500" })) : (jsx(ChevronDown, { className: "h-4 w-4 text-gray-500" })) }))] }) }), jsx("td", { className: "px-6 py-4 font-mono text-sm text-gray-900 dark:text-gray-100", children: isAzure ? (jsx("span", { className: "text-xs text-gray-500", children: t('llmsTabIntegrationLlmsTab.azureModelCount', {
153047
+ return (jsxs(React__default.Fragment, { children: [jsxs("tr", { children: [jsx("td", { className: "px-6 py-4", children: jsxs("div", { className: "flex items-center gap-2", children: [jsx("img", { src: logoUrl, alt: logoAlt || provider || cred.name, className: "w-6 h-6 rounded-sm object-contain" }), jsx("span", { className: "font-normal text-gray-900 dark:text-gray-100", children: provider || cred.name }), isAzure && azureModels.length > 0 && (jsx("button", { type: "button", onClick: () => toggleRowExpansion(cred.name), className: "p-0.5 hover:bg-gray-100 rounded", children: isExpanded ? (jsx(ChevronUp, { className: "h-4 w-4 text-gray-500" })) : (jsx(ChevronDown, { className: "h-4 w-4 text-gray-500" })) }))] }) }), jsx("td", { className: "px-6 py-4 font-mono text-sm text-gray-900 dark:text-gray-100", children: isAzure ? (jsx("span", { className: "text-xs text-gray-500", children: t('llmsTabIntegrationLlmsTab.azureModelCount', {
152473
153048
  count: azureModels.length,
152474
153049
  }) })) : (String((_c = cred === null || cred === void 0 ? void 0 : cred.value) === null || _c === void 0 ? void 0 : _c.key).slice(0, 15) || '') }), jsx("td", { className: "px-6 py-4", children: jsx(Button$1, { variant: "ghost", size: "sm", className: "cursor-pointer mr-2", disabled: isDeletingIntegration || isDeletingCredential, onClick: () => handleDeleteCredential(cred.name, cred.platform, false), children: jsx(Trash, { className: "h-4 w-4" }) }) })] }), isAzure &&
152475
153050
  isExpanded &&
@@ -184641,7 +185216,7 @@ function PolicyConfigDialog({ open, onOpenChange, config, onSave, }) {
184641
185216
  return (jsx(Dialog, { open: open, onOpenChange: handleOpenChange, children: jsxs(DialogContent, { className: "sm:max-w-md", "aria-describedby": "policy-config-description", children: [jsxs(DialogHeader, { children: [jsx(DialogTitle, { children: t('componentsPolicyConfigDialog.title') }), jsx(DialogDescription, { id: "policy-config-description", children: t('componentsPolicyConfigDialog.description') })] }), jsxs("div", { className: "space-y-4", children: [jsxs("div", { children: [jsx(Label$2, { htmlFor: "policy-config-role-name", className: "text-sm font-medium text-gray-700", children: t('componentsPolicyConfigDialog.roleName') }), jsx(Input, { id: "policy-config-role-name", value: (_a = draft === null || draft === void 0 ? void 0 : draft.role_name) !== null && _a !== void 0 ? _a : '', disabled: true, className: "bg-gray-50" })] }), jsxs("div", { className: "flex items-center space-x-2", children: [jsx(Checkbox, { id: "policy-config-enabled", checked: (_b = draft === null || draft === void 0 ? void 0 : draft.enabled) !== null && _b !== void 0 ? _b : true, onCheckedChange: (checked) => updateDraft({ enabled: checked === true }) }), jsx(Label$2, { htmlFor: "policy-config-enabled", className: "text-sm font-medium text-gray-700 cursor-pointer", children: t('componentsPolicyConfigDialog.enabled') })] }), jsxs("div", { className: "flex items-center space-x-2", children: [jsx(Checkbox, { id: "policy-config-notify-assignment", checked: (_c = draft === null || draft === void 0 ? void 0 : draft.notify_on_assignment) !== null && _c !== void 0 ? _c : true, onCheckedChange: (checked) => updateDraft({ notify_on_assignment: checked === true }) }), jsx(Label$2, { htmlFor: "policy-config-notify-assignment", className: "text-sm font-medium text-gray-700 cursor-pointer", children: t('componentsPolicyConfigDialog.notifyOnAssignment') })] }), jsxs("div", { className: "flex items-center space-x-2", children: [jsx(Checkbox, { id: "policy-config-notify-removal", checked: (_d = draft === null || draft === void 0 ? void 0 : draft.notify_on_removal) !== null && _d !== void 0 ? _d : true, onCheckedChange: (checked) => updateDraft({ notify_on_removal: checked === true }) }), jsx(Label$2, { htmlFor: "policy-config-notify-removal", className: "text-sm font-medium text-gray-700 cursor-pointer", children: t('componentsPolicyConfigDialog.notifyOnRemoval') })] }), jsxs("div", { className: "space-y-2", children: [jsx(Label$2, { htmlFor: "policy-config-subject", className: "text-sm font-medium text-gray-700", children: t('componentsPolicyConfigDialog.subject') }), jsx(Textarea, { id: "policy-config-subject", value: (_e = draft === null || draft === void 0 ? void 0 : draft.subject) !== null && _e !== void 0 ? _e : '', onChange: (event) => updateDraft({ subject: event.target.value }), placeholder: t('componentsPolicyConfigDialog.subjectPlaceholder'), rows: 3 }), jsx("p", { className: "text-xs text-gray-500", children: t('componentsPolicyConfigDialog.subjectHint') })] })] }), jsxs(DialogFooter, { className: "pt-2", children: [jsx(Button$1, { variant: "outline", onClick: () => onOpenChange(false), children: t('componentsPolicyConfigDialog.cancel') }), jsx(Button$1, { className: "bg-gradient-to-r from-[#2563EB] to-[#93C5FD] hover:opacity-90 text-white", onClick: handleSave, disabled: !config, children: t('componentsPolicyConfigDialog.saveConfiguration') })] })] }) }));
184642
185217
  }
184643
185218
 
184644
- function useDebouncedValue$2(value, delay) {
185219
+ function useDebouncedValue$3(value, delay) {
184645
185220
  const [debouncedValue, setDebouncedValue] = useState(value);
184646
185221
  useEffect(() => {
184647
185222
  const timer = window.setTimeout(() => setDebouncedValue(value), delay);
@@ -184670,7 +185245,7 @@ function ProactiveSettingsSection({ platformKey, username, isSaving, userLocalTi
184670
185245
  const [isPromptDialogOpen, setIsPromptDialogOpen] = useState(false);
184671
185246
  const customIntervalErrorId = 'proactive-custom-interval-error';
184672
185247
  const executionTimeErrorId = 'proactive-execution-time-error';
184673
- const debouncedMentorSearch = useDebouncedValue$2(mentorSearch, 300);
185248
+ const debouncedMentorSearch = useDebouncedValue$3(mentorSearch, 300);
184674
185249
  const showUseLocalTimezone = periodicTimezone !== userLocalTimezone;
184675
185250
  const shouldFetchMentors = Boolean(platformKey) && Boolean(username);
184676
185251
  const { data: mentorsResponse, isLoading: isMentorsLoading } = useGetMentorsQuery({
@@ -184767,7 +185342,7 @@ function ProactiveSettingsSection({ platformKey, username, isSaving, userLocalTi
184767
185342
  }) })] })] }), jsxs("div", { className: "space-y-2", children: [jsx(Label$2, { htmlFor: "periodic-execution-time", className: "text-sm font-medium text-gray-700", children: t('componentsProactiveSettingsSection.executionTimeLabel') }), jsx(Input, { id: "periodic-execution-time", type: "time", value: periodicExecutionTime, onChange: (event) => onExecutionTimeChange(event.target.value), disabled: isSaving, "aria-invalid": isExecutionTimeMissing, "aria-describedby": isExecutionTimeMissing ? executionTimeErrorId : undefined }), renderTimezoneNotice(t('componentsProactiveSettingsSection.chooseWhenNotice'))] })] })), periodicFrequency !== 'CUSTOM' && (jsxs("div", { className: "space-y-2", children: [jsx(Label$2, { htmlFor: "periodic-execution-time", className: "text-sm font-medium text-gray-700", children: t('componentsProactiveSettingsSection.executionTimeLabel') }), jsx(Input, { id: "periodic-execution-time", type: "time", value: periodicExecutionTime, onChange: (event) => onExecutionTimeChange(event.target.value), disabled: isSaving }), renderTimezoneNotice(t('componentsProactiveSettingsSection.optionalChooseWhenNotice'))] })), isProactiveInvalid && (jsxs("div", { className: "space-y-1", "aria-live": "polite", children: [isCustomIntervalMissing && (jsx("p", { id: customIntervalErrorId, className: "text-sm text-red-600", role: "alert", children: t('componentsProactiveSettingsSection.customIntervalError') })), isExecutionTimeMissing && (jsx("p", { id: executionTimeErrorId, className: "text-sm text-red-600", role: "alert", children: t('componentsProactiveSettingsSection.executionTimeError') }))] })), jsxs("div", { className: "space-y-2", children: [jsx(Label$2, { className: "text-sm font-medium text-gray-700", htmlFor: "periodic-mentors", children: t('componentsProactiveSettingsSection.periodicAgentsLabel') }), jsx(SearchableMultiSelect, { items: mentorOptions, selectedItems: selectedMentors, onSelectionChange: handleMentorSelectionChange, searchQuery: mentorSearch, onSearchChange: setMentorSearch, isLoading: isMentorsLoading, placeholder: t('componentsProactiveSettingsSection.searchAgentsPlaceholder'), getItemValue: (mentor) => mentor.unique_id, getItemLabel: (mentor) => mentor.name ? `${mentor.name} (${mentor.unique_id})` : mentor.unique_id, onSelectedItemAction: handleEditMentorPrompt, selectedItemActionIcon: jsx(SquarePen, { className: "h-3 w-3", "aria-hidden": "true" }), selectedItemActionAriaLabel: t('componentsProactiveSettingsSection.editAgentPromptAriaLabel'), inputId: "periodic-mentors", ariaDescribedBy: "periodic-mentors-help", className: "max-w-full" }), jsx("p", { id: "periodic-mentors-help", className: "text-xs text-gray-500", children: t('componentsProactiveSettingsSection.periodicAgentsHelp') })] })] }), jsx(MentorPromptDialog, { open: isPromptDialogOpen, onOpenChange: setIsPromptDialogOpen, mentor: activePromptMentor, initialPrompt: activePromptMentor ? ((_b = mentorPrompts[activePromptMentor.id]) !== null && _b !== void 0 ? _b : '') : '', onSave: handlePromptSave })] }));
184768
185343
  }
184769
185344
 
184770
- function useDebouncedValue$1(value, delay) {
185345
+ function useDebouncedValue$2(value, delay) {
184771
185346
  const [debouncedValue, setDebouncedValue] = useState(value);
184772
185347
  useEffect(() => {
184773
185348
  const timer = window.setTimeout(() => setDebouncedValue(value), delay);
@@ -184799,7 +185374,7 @@ function PolicyAssignmentSection({ platformKey, isSaving, notifyOnAssignment, on
184799
185374
  const [isPolicyConfigDialogOpen, setIsPolicyConfigDialogOpen] = useState(false);
184800
185375
  // Track the last initialized data to detect when new data arrives
184801
185376
  const lastInitializedRef = useRef('');
184802
- const debouncedPolicySearch = useDebouncedValue$1(policySearch, 300);
185377
+ const debouncedPolicySearch = useDebouncedValue$2(policySearch, 300);
184803
185378
  const shouldFetchPolicies = Boolean(platformKey);
184804
185379
  const { data: policiesResponse, isLoading: isPoliciesLoading } = useGetRbacPoliciesQuery({ platformKey }, { skip: !shouldFetchPolicies });
184805
185380
  const policyOptions = useMemo(() => {
@@ -184894,7 +185469,7 @@ function PolicyAssignmentSection({ platformKey, isSaving, notifyOnAssignment, on
184894
185469
  return (jsxs(Fragment$1, { children: [jsxs("div", { className: "space-y-4 border-t border-gray-200 pt-4", children: [jsxs("div", { className: "space-y-1", children: [jsx("h3", { className: "text-sm font-semibold text-gray-900", children: t('componentsPolicyAssignmentSection.sectionTitle') }), jsx("p", { className: "text-xs text-gray-500", children: t('componentsPolicyAssignmentSection.sectionDescription') })] }), jsxs("div", { className: "grid gap-4 md:grid-cols-2", children: [jsxs("div", { className: "flex items-center space-x-2", children: [jsx(Checkbox, { id: "policy-notify-assignment", checked: notifyOnAssignment, onCheckedChange: (checked) => onNotifyOnAssignmentChange(checked === true), disabled: isSaving }), jsx(Label$2, { htmlFor: "policy-notify-assignment", className: "text-sm font-medium text-gray-700 cursor-pointer", children: t('componentsPolicyAssignmentSection.notifyOnAssignment') })] }), jsxs("div", { className: "flex items-center space-x-2", children: [jsx(Checkbox, { id: "policy-notify-removal", checked: notifyOnRemoval, onCheckedChange: (checked) => onNotifyOnRemovalChange(checked === true), disabled: isSaving }), jsx(Label$2, { htmlFor: "policy-notify-removal", className: "text-sm font-medium text-gray-700 cursor-pointer", children: t('componentsPolicyAssignmentSection.notifyOnRemoval') })] })] }), jsxs("div", { className: "space-y-2", children: [jsx(Label$2, { className: "text-sm font-medium text-gray-700", htmlFor: "enabled-policies", children: t('componentsPolicyAssignmentSection.enabledPoliciesLabel') }), jsx(SearchableMultiSelect, { items: policyOptions, selectedItems: selectedPolicies, onSelectionChange: handlePolicySelectionChange, searchQuery: policySearch, onSearchChange: setPolicySearch, isLoading: isPoliciesLoading, placeholder: t('componentsPolicyAssignmentSection.searchPlaceholder'), getItemValue: (policy) => String(policy.id), getItemLabel: (policy) => { var _a; return (((_a = policy.role) === null || _a === void 0 ? void 0 : _a.name) ? `${policy.name}` : policy.name); }, onSelectedItemAction: handleEditPolicyConfig, selectedItemActionIcon: jsx(SquarePen, { className: "h-3 w-3", "aria-hidden": "true" }), selectedItemActionAriaLabel: t('componentsPolicyAssignmentSection.editPolicyAriaLabel'), inputId: "enabled-policies", ariaDescribedBy: "enabled-policies-help", className: "max-w-full" }), jsx("p", { id: "enabled-policies-help", className: "text-xs text-gray-500", children: t('componentsPolicyAssignmentSection.enabledPoliciesHelp') })] })] }), jsx(PolicyConfigDialog, { open: isPolicyConfigDialogOpen, onOpenChange: setIsPolicyConfigDialogOpen, config: activePolicyConfig, onSave: handlePolicyConfigSave })] }));
184895
185470
  }
184896
185471
 
184897
- function useDebouncedValue(value, delay) {
185472
+ function useDebouncedValue$1(value, delay) {
184898
185473
  const [debouncedValue, setDebouncedValue] = useState(value);
184899
185474
  useEffect(() => {
184900
185475
  const timer = window.setTimeout(() => setDebouncedValue(value), delay);
@@ -184963,9 +185538,9 @@ function HumanSupportSection({ platformKey, isSaving, recipientMode, onRecipient
184963
185538
  // Track the last initialized data to detect when new data arrives
184964
185539
  const lastInitializedRef = useRef('');
184965
185540
  // Debounced search values
184966
- const debouncedUserSearch = useDebouncedValue(userSearch, 300);
184967
- const debouncedGroupSearch = useDebouncedValue(groupSearch, 300);
184968
- const debouncedPolicySearch = useDebouncedValue(policySearch, 300);
185541
+ const debouncedUserSearch = useDebouncedValue$1(userSearch, 300);
185542
+ const debouncedGroupSearch = useDebouncedValue$1(groupSearch, 300);
185543
+ const debouncedPolicySearch = useDebouncedValue$1(policySearch, 300);
184969
185544
  const shouldFetch = Boolean(platformKey);
184970
185545
  // Fetch users
184971
185546
  const { data: usersResponse, isLoading: isUsersLoading } = usePlatformUsersQuery({
@@ -186655,6 +187230,10 @@ const defaultTabs = [
186655
187230
  label: 'Transcripts',
186656
187231
  value: 'transcripts',
186657
187232
  },
187233
+ {
187234
+ label: 'Memory',
187235
+ value: 'memory',
187236
+ },
186658
187237
  {
186659
187238
  label: 'Costs',
186660
187239
  value: 'financial',
@@ -186670,6 +187249,16 @@ const defaultTabs = [
186670
187249
  ];
186671
187250
  const className = 'inline-flex items-center justify-center whitespace-nowrap rounded-[5px] px-2 sm:px-2.5 pt-1 pb-0.5 sm:text-sm text-gray-500 ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:text-blue-600 data-[state=active]:font-semibold text-sm font-medium data-[state=active]:bg-[#f5f7fb] data-[state=active]:shadow-none cursor-pointer';
186672
187251
  function AnalyticsLayout({ children, currentPath, basePath, onTabChange, tabs = defaultTabs, activeTabClassName = '', beforeDataReports, excludeTabs = [], }) {
187252
+ const { currentTenant } = useCurrentTenant();
187253
+ const rbacPermissions = useSelector(selectRbacPermissions);
187254
+ // Only a pure watcher narrows the tab strip — everyone else keeps whatever
187255
+ // the caller passed, custom tabs included.
187256
+ const isRestricted = isPureWatcher(rbacPermissions, currentTenant);
187257
+ const allowedTabs = useMemo(() => getVisibleAnalyticsTabs(rbacPermissions, currentTenant), [rbacPermissions, currentTenant]);
187258
+ const canAccessTab = useCallback(
187259
+ // Callers may pass custom tab values, so compare as plain strings: anything
187260
+ // outside the watcher allow-list stays hidden from a restricted user.
187261
+ (tabValue) => !isRestricted || allowedTabs.includes(tabValue), [isRestricted, allowedTabs]);
186673
187262
  useEffect(() => {
186674
187263
  const mainContentContainer = document.getElementById('main-content-container');
186675
187264
  if (mainContentContainer) {
@@ -186689,6 +187278,8 @@ function AnalyticsLayout({ children, currentPath, basePath, onTabChange, tabs =
186689
187278
  return 'topics';
186690
187279
  if (path === `${basePath}/transcripts`)
186691
187280
  return 'transcripts';
187281
+ if (path === `${basePath}/memory`)
187282
+ return 'memory';
186692
187283
  if (path === `${basePath}/financial`)
186693
187284
  return 'financial';
186694
187285
  if (path === `${basePath}/audit`)
@@ -186703,15 +187294,38 @@ function AnalyticsLayout({ children, currentPath, basePath, onTabChange, tabs =
186703
187294
  return 'programs';
186704
187295
  return '';
186705
187296
  };
187297
+ const activeTab = getTabValue(currentPath);
187298
+ const isActiveTabAllowed = canAccessTab(activeTab);
187299
+ // Kept in refs so the guard below only re-runs when the tab or the allowed
187300
+ // set changes — callers pass these inline, so their identity churns.
187301
+ const latestPropsRef = useRef({ onTabChange, excludeTabs });
187302
+ useEffect(() => {
187303
+ latestPropsRef.current = { onTabChange, excludeTabs };
187304
+ });
187305
+ // A watcher who deep-links into a restricted tab (e.g. /analytics/users, or
187306
+ // the Overview landing page) gets sent to the first tab they may open. It has
187307
+ // to skip `excludeTabs`: a host that drops a tab has no route behind it, so
187308
+ // redirecting there would 404 (mentorai excludes courses/programs).
187309
+ useEffect(() => {
187310
+ if (isActiveTabAllowed)
187311
+ return;
187312
+ const { onTabChange: notify, excludeTabs: excluded } = latestPropsRef.current;
187313
+ const fallbackTab = allowedTabs.find((tab) => !excluded.includes(tab));
187314
+ if (fallbackTab === undefined)
187315
+ return;
187316
+ notify(fallbackTab);
187317
+ }, [isActiveTabAllowed, allowedTabs]);
186706
187318
  const handleTabClick = (tabValue) => {
187319
+ if (!canAccessTab(tabValue))
187320
+ return;
186707
187321
  onTabChange(tabValue);
186708
187322
  };
186709
- return (jsxs("div", { className: "flex flex-col flex-1 min-h-0 h-full overflow-hidden overscroll-none bg-[#f5f7fb]", children: [jsx("div", { className: "p-6 pb-0", children: jsx("div", { className: "flex items-center justify-between mb-6", children: jsxs("div", { className: "flex items-center justify-between w-full overflow-x-auto", children: [jsx(Tabs, { className: "mb-6 bg-[#f5f7fb]", value: getTabValue(currentPath), children: jsx(TabsList, { className: "bg-[#f5f7fb]", children: tabs
186710
- .filter((tab) => !excludeTabs.includes(tab.value))
187323
+ return (jsxs("div", { className: "flex flex-col flex-1 min-h-0 h-full overflow-hidden overscroll-none bg-[#f5f7fb]", children: [jsx("div", { className: "p-6 pb-0", children: jsx("div", { className: "flex items-center justify-between mb-6", children: jsxs("div", { className: "flex items-center justify-between w-full overflow-x-auto", children: [jsx(Tabs, { className: "mb-6 bg-[#f5f7fb]", value: activeTab, children: jsx(TabsList, { className: "bg-[#f5f7fb]", children: tabs
187324
+ .filter((tab) => !excludeTabs.includes(tab.value) && canAccessTab(tab.value))
186711
187325
  .map((tab) => {
186712
- const isActive = getTabValue(currentPath) === tab.value;
187326
+ const isActive = activeTab === tab.value;
186713
187327
  return (jsx(TabsTrigger, { value: tab.value, className: cn(className, isActive && activeTabClassName), onClick: () => handleTabClick(tab.value), children: tab.label }, tab.value));
186714
- }) }) }), jsxs("div", { className: "flex items-center gap-4", children: [beforeDataReports, jsx(Tabs, { className: "mb-6 bg-[#f5f7fb]", value: getTabValue(currentPath), children: jsx(TabsList, { className: "bg-[#f5f7fb]", children: jsx(TabsTrigger, { value: "reports", className: cn(className, getTabValue(currentPath) === 'reports' && activeTabClassName), onClick: () => handleTabClick('reports'), children: "Data Reports" }) }) })] })] }) }) }), jsx("div", { className: "flex-1 overflow-auto overscroll-contain scrollbar-none px-6 pb-6 pt-0", children: children })] }));
187328
+ }) }) }), jsxs("div", { className: "flex items-center gap-4", children: [beforeDataReports, canAccessTab('reports') && (jsx(Tabs, { className: "mb-6 bg-[#f5f7fb]", value: activeTab, children: jsx(TabsList, { className: "bg-[#f5f7fb]", children: jsx(TabsTrigger, { value: "reports", className: cn(className, activeTab === 'reports' && activeTabClassName), onClick: () => handleTabClick('reports'), children: "Data Reports" }) }) }))] })] }) }) }), jsx("div", { className: "flex-1 overflow-auto overscroll-contain scrollbar-none px-6 pb-6 pt-0", children: isActiveTabAllowed ? children : null })] }));
186715
187329
  }
186716
187330
 
186717
187331
  const accessTimeData = [
@@ -222565,6 +223179,8 @@ const toTitleCase = (value) => {
222565
223179
  };
222566
223180
  function AnalyticsReports({ tenantKey, selectedMentorId, disabledReports = [], usergroupIds, selectedMentorDbId, }) {
222567
223181
  const t = useT();
223182
+ const { currentTenant } = useCurrentTenant();
223183
+ const rbacPermissions = useSelector(selectRbacPermissions);
222568
223184
  const { metadata } = useTenantMetadata({ org: tenantKey });
222569
223185
  //we using metadata to get the combined recommendation reports
222570
223186
  //"combined_recommendation_reports": "Recommendation History Report,Course Grade Report,User Group Member List Report",
@@ -222925,14 +223541,18 @@ function AnalyticsReports({ tenantKey, selectedMentorId, disabledReports = [], u
222925
223541
  timeZone: 'UTC',
222926
223542
  });
222927
223543
  }, []);
222928
- // Filter out disabled reports and sort alphabetically by display name
223544
+ // Reports the tenant disabled, plus the ones a pure watcher may not see.
223545
+ const hiddenReports = useMemo(() => isPureWatcher(rbacPermissions, currentTenant)
223546
+ ? [...disabledReports, ...WATCHER_HIDDEN_REPORTS]
223547
+ : disabledReports, [disabledReports, rbacPermissions, currentTenant]);
223548
+ // Filter out hidden reports and sort alphabetically by display name
222929
223549
  const filteredReports = useMemo(() => {
222930
- const filtered = disabledReports.length
223550
+ const filtered = hiddenReports.length
222931
223551
  ? reports.filter((report) => {
222932
223552
  const displayName = (report.display_name ||
222933
223553
  toTitleCase(report.report_name) ||
222934
223554
  '').toLowerCase();
222935
- return !disabledReports.some((disabledReport) => displayName.includes(disabledReport.toLowerCase()));
223555
+ return !hiddenReports.some((hiddenReport) => displayName.includes(hiddenReport.toLowerCase()));
222936
223556
  })
222937
223557
  : [...reports];
222938
223558
  return filtered.sort((a, b) => {
@@ -222940,7 +223560,7 @@ function AnalyticsReports({ tenantKey, selectedMentorId, disabledReports = [], u
222940
223560
  const nameB = (b.display_name || toTitleCase(b.report_name) || '').toLowerCase();
222941
223561
  return nameA.localeCompare(nameB);
222942
223562
  });
222943
- }, [reports, disabledReports]);
223563
+ }, [reports, hiddenReports]);
222944
223564
  const content = useMemo(() => {
222945
223565
  if (isLoading) {
222946
223566
  return (jsx("div", { className: "grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-8 items-stretch", children: Array.from({ length: 12 }).map((_, key) => (jsx(Card, { className: "bg-white border-gray-200 h-full flex flex-col", children: jsx(CardContent, { className: "p-6 flex-1 flex flex-col", children: jsxs("div", { className: "flex-1", children: [jsxs("div", { className: "flex justify-between items-start mb-2", children: [jsx(Skeleton, { className: "h-5 w-32 flex-1 mr-2" }), jsx(Skeleton, { className: "h-8 w-8 flex-shrink-0" })] }), jsx(Skeleton, { className: "h-4 w-full" })] }) }) }, key))) }));
@@ -223317,7 +223937,7 @@ const formatSecondsToHours$1 = (seconds) => {
223317
223937
  return Math.round((seconds / 3600) * 10) / 10;
223318
223938
  };
223319
223939
  function AnalyticsCourses({ tenantKey, mentorId, selectedMentorId, basePath = '', }) {
223320
- var _a, _b, _c, _d, _e;
223940
+ var _a, _b, _c, _d;
223321
223941
  const t = useT();
223322
223942
  const router = useRouter();
223323
223943
  const currentMentorId = selectedMentorId || mentorId;
@@ -223325,11 +223945,12 @@ function AnalyticsCourses({ tenantKey, mentorId, selectedMentorId, basePath = ''
223325
223945
  const handleCourseClick = (courseId) => {
223326
223946
  router.push(`${basePath}/courses/${courseId}`);
223327
223947
  };
223328
- return (jsxs("div", { className: "space-y-8", children: [jsxs("div", { className: "grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4 mb-6", children: [jsx(StatCard, { loading: isLoading, title: t('analyticsAnalyticsCourses.activeCourses'), value: courseStats.active_courses, percentage: courseStats.active_courses_percentage }), jsx(StatCard, { loading: isLoading, title: t('analyticsAnalyticsCourses.totalCourses'), value: courseStats.total_courses, percentage: courseStats.total_courses_percentage }), jsx(StatCard, { loading: isLoading, title: t('analyticsAnalyticsCourses.enrollments'), value: courseStats.enrollments, percentage: courseStats.enrollments_percentage }), jsx(StatCard, { loading: isLoading, title: t('analyticsAnalyticsCourses.totalLearners'), value: courseStats.total_learners })] }), jsx("div", { className: "grid grid-cols-1 gap-6", children: jsx(ChartCardWrapper, { title: t('analyticsAnalyticsCourses.courseOvertime'), label: t('analyticsAnalyticsCourses.timeSpent'), filters: enrollmentStatsDateFilter, setOutsideFilters: setEnrollmentStatsDateFilter, children: isLoading ? (jsx(ChartLoading, {})) : ((_a = enrollmentStats === null || enrollmentStats === void 0 ? void 0 : enrollmentStats.points) === null || _a === void 0 ? void 0 : _a.length) && ((_b = enrollmentStats === null || enrollmentStats === void 0 ? void 0 : enrollmentStats.points) === null || _b === void 0 ? void 0 : _b.length) > 0 ? (jsxs(LineChart, { data: ((_c = enrollmentStats === null || enrollmentStats === void 0 ? void 0 : enrollmentStats.points) === null || _c === void 0 ? void 0 : _c.map((point) => ({
223948
+ const hasEnrollmentStatsPoints = Number((_a = enrollmentStats === null || enrollmentStats === void 0 ? void 0 : enrollmentStats.points) === null || _a === void 0 ? void 0 : _a.length) > 0;
223949
+ return (jsxs("div", { className: "space-y-8", children: [jsxs("div", { className: "grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4 mb-6", children: [jsx(StatCard, { loading: isLoading, title: t('analyticsAnalyticsCourses.activeCourses'), value: courseStats.active_courses, percentage: courseStats.active_courses_percentage }), jsx(StatCard, { loading: isLoading, title: t('analyticsAnalyticsCourses.totalCourses'), value: courseStats.total_courses, percentage: courseStats.total_courses_percentage }), jsx(StatCard, { loading: isLoading, title: t('analyticsAnalyticsCourses.enrollments'), value: courseStats.enrollments, percentage: courseStats.enrollments_percentage }), jsx(StatCard, { loading: isLoading, title: t('analyticsAnalyticsCourses.totalLearners'), value: courseStats.total_learners })] }), (isLoading || hasEnrollmentStatsPoints) && (jsx("div", { className: "grid grid-cols-1 gap-6", children: jsx(ChartCardWrapper, { title: t('analyticsAnalyticsCourses.courseOvertime'), label: t('analyticsAnalyticsCourses.timeSpent'), filters: enrollmentStatsDateFilter, setOutsideFilters: setEnrollmentStatsDateFilter, children: isLoading ? (jsx(ChartLoading, {})) : (jsxs(LineChart, { data: ((_b = enrollmentStats === null || enrollmentStats === void 0 ? void 0 : enrollmentStats.points) === null || _b === void 0 ? void 0 : _b.map((point) => ({
223329
223950
  date: formatDateToShortFormat$1(point.date, enrollmentStatsDateFilter.activeFilter === 'today'),
223330
223951
  value: formatSecondsToHours$1(point.value),
223331
223952
  rawSeconds: point.value,
223332
- }))) || [], margin: { top: 5, right: 5, left: 0, bottom: 5 }, children: [jsx(CartesianGrid, { strokeDasharray: "3 3", stroke: "#f0f0f0", vertical: false }), jsx(XAxis, { dataKey: "date", tick: { fontSize: 8, textAnchor: 'end' }, angle: -45, interval: Math.floor(Number((_d = enrollmentStats === null || enrollmentStats === void 0 ? void 0 : enrollmentStats.points) === null || _d === void 0 ? void 0 : _d.length) / 31) || 0 }), jsx(YAxis, { tick: { fontSize: 10 }, width: 40, allowDecimals: false, tickFormatter: (value) => `${value}h` }), jsx(Tooltip, { content: ({ active, payload, label }) => {
223953
+ }))) || [], margin: { top: 5, right: 5, left: 0, bottom: 5 }, children: [jsx(CartesianGrid, { strokeDasharray: "3 3", stroke: "#f0f0f0", vertical: false }), jsx(XAxis, { dataKey: "date", tick: { fontSize: 8, textAnchor: 'end' }, angle: -45, interval: Math.floor(Number((_c = enrollmentStats === null || enrollmentStats === void 0 ? void 0 : enrollmentStats.points) === null || _c === void 0 ? void 0 : _c.length) / 31) || 0 }), jsx(YAxis, { tick: { fontSize: 10 }, width: 40, allowDecimals: false, tickFormatter: (value) => `${value}h` }), jsx(Tooltip, { content: ({ active, payload, label }) => {
223333
223954
  var _a;
223334
223955
  if (!active || !(payload === null || payload === void 0 ? void 0 : payload.length))
223335
223956
  return null;
@@ -223340,7 +223961,7 @@ function AnalyticsCourses({ tenantKey, mentorId, selectedMentorId, basePath = ''
223340
223961
  stroke: '#38A1E5',
223341
223962
  strokeWidth: 2,
223342
223963
  fill: 'white',
223343
- } })] })) : (jsx(EmptyStats, {})) }) }), jsx("div", { className: "grid grid-cols-1 gap-6", children: jsx(Card, { className: "w-full bg-white shadow-xs", style: { borderColor: 'oklch(.922 0 0)' }, children: jsxs(CardContent, { className: "p-4", "aria-label": t('analyticsAnalyticsCourses.coursesTableAriaLabel'), children: [jsx("h3", { className: "text-base font-medium text-gray-700 mb-4", children: t('analyticsAnalyticsCourses.coursesHeading') }), jsxs("div", { className: "space-y-4", children: [jsxs("div", { className: "relative flex-1 w-full", children: [jsx(Search, { className: "absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-gray-400" }), jsx(Input, { id: "search-course", type: "text", placeholder: t('analyticsAnalyticsCourses.searchPlaceholder'), value: coursesListSearch, onChange: handleSearchInputChange, className: "pl-9 border-gray-300 focus:bg-transparent focus:color-transparent h-11", "aria-label": t('analyticsAnalyticsCourses.searchAriaLabel') })] }), isLoading ? (jsx("div", { className: "flex items-center justify-center py-8", children: jsx("div", { className: "text-sm text-gray-500", children: t('analyticsAnalyticsCourses.loading') }) })) : ((_e = coursesList === null || coursesList === void 0 ? void 0 : coursesList.courses) === null || _e === void 0 ? void 0 : _e.length) && coursesList.courses.length > 0 ? (jsxs(Fragment$1, { children: [jsx("div", { className: "rounded-md overflow-x-auto", style: { borderColor: 'oklch(.922 0 0)', borderWidth: '1px' }, children: jsxs(Table, { children: [jsx(TableHeader, { children: jsxs(TableRow, { className: "h-[48px]", style: { borderColor: 'oklch(.922 0 0)' }, children: [jsx(TableHead, { className: "text-left", children: t('analyticsAnalyticsCourses.colCourseName') }), jsx(TableHead, { className: "text-left", children: t('analyticsAnalyticsCourses.colCourseId') }), jsx(TableHead, { className: "text-right", children: t('analyticsAnalyticsCourses.colEnrollments') })] }) }), jsx(TableBody, { children: coursesList.courses.map((course, index) => (jsxs(TableRow, { className: `cursor-pointer hover:bg-muted/50 h-[48px] ${index % 2 === 0 ? 'bg-gray-50' : ''}`, onClick: () => handleCourseClick(course.id), role: "button", tabIndex: 0, onKeyDown: (e) => {
223964
+ } })] })) }) })), jsx("div", { className: "grid grid-cols-1 gap-6", children: jsx(Card, { className: "w-full bg-white shadow-xs", style: { borderColor: 'oklch(.922 0 0)' }, children: jsxs(CardContent, { className: "p-4", "aria-label": t('analyticsAnalyticsCourses.coursesTableAriaLabel'), children: [jsx("h3", { className: "text-base font-medium text-gray-700 mb-4", children: t('analyticsAnalyticsCourses.coursesHeading') }), jsxs("div", { className: "space-y-4", children: [jsxs("div", { className: "relative flex-1 w-full", children: [jsx(Search, { className: "absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-gray-400" }), jsx(Input, { id: "search-course", type: "text", placeholder: t('analyticsAnalyticsCourses.searchPlaceholder'), value: coursesListSearch, onChange: handleSearchInputChange, className: "pl-9 border-gray-300 focus:bg-transparent focus:color-transparent h-11", "aria-label": t('analyticsAnalyticsCourses.searchAriaLabel') })] }), isLoading ? (jsx("div", { className: "flex items-center justify-center py-8", children: jsx("div", { className: "text-sm text-gray-500", children: t('analyticsAnalyticsCourses.loading') }) })) : ((_d = coursesList === null || coursesList === void 0 ? void 0 : coursesList.courses) === null || _d === void 0 ? void 0 : _d.length) && coursesList.courses.length > 0 ? (jsxs(Fragment$1, { children: [jsx("div", { className: "rounded-md overflow-x-auto", style: { borderColor: 'oklch(.922 0 0)', borderWidth: '1px' }, children: jsxs(Table, { children: [jsx(TableHeader, { children: jsxs(TableRow, { className: "h-[48px]", style: { borderColor: 'oklch(.922 0 0)' }, children: [jsx(TableHead, { className: "text-left", children: t('analyticsAnalyticsCourses.colCourseName') }), jsx(TableHead, { className: "text-left", children: t('analyticsAnalyticsCourses.colCourseId') }), jsx(TableHead, { className: "text-right", children: t('analyticsAnalyticsCourses.colEnrollments') })] }) }), jsx(TableBody, { children: coursesList.courses.map((course, index) => (jsxs(TableRow, { className: `cursor-pointer hover:bg-muted/50 h-[48px] ${index % 2 === 0 ? 'bg-gray-50' : ''}`, onClick: () => handleCourseClick(course.id), role: "button", tabIndex: 0, onKeyDown: (e) => {
223344
223965
  if (e.key === 'Enter' || e.key === ' ') {
223345
223966
  e.preventDefault();
223346
223967
  handleCourseClick(course.id);
@@ -223366,15 +223987,6 @@ function AnalyticsCourses({ tenantKey, mentorId, selectedMentorId, basePath = ''
223366
223987
  }), jsxs(Button$1, { variant: "outline", size: "sm", className: "h-8 w-8 p-2 !w-auto !inline-flex bg-transparent", onClick: () => setCoursesListPage(coursesPagination.current_page + 1), disabled: coursesPagination.current_page === coursesPagination.total_pages, "aria-label": t('analyticsAnalyticsCourses.goToNextPage'), children: [jsx("span", { className: "sr-only", children: t('analyticsAnalyticsCourses.goToNextPage') }), jsx(ChevronRight, { className: "h-4 w-4" })] }), jsxs(Button$1, { variant: "outline", size: "sm", className: "h-8 w-8 p-2 !w-auto !inline-flex bg-transparent", onClick: () => setCoursesListPage(coursesPagination.total_pages), disabled: coursesPagination.current_page === coursesPagination.total_pages, "aria-label": t('analyticsAnalyticsCourses.goToLastPage'), children: [jsx("span", { className: "sr-only", children: t('analyticsAnalyticsCourses.goToLastPage') }), jsx(ChevronsRight, { className: "h-4 w-4" })] })] }))] })) : (jsx(EmptyStats, { title: t('analyticsAnalyticsCourses.noCoursesAvailable') }))] })] }) }) })] }));
223367
223988
  }
223368
223989
 
223369
- // Utility function to format time spent (in minutes) to readable format
223370
- const formatTimeSpent = (minutes) => {
223371
- if (minutes < 60) {
223372
- return `${minutes}m`;
223373
- }
223374
- const hours = Math.floor(minutes / 60);
223375
- const mins = minutes % 60;
223376
- return mins > 0 ? `${hours}h ${mins}m` : `${hours}h`;
223377
- };
223378
223990
  function AnalyticsCourseDetail({ tenantKey, mentorId, selectedMentorId, courseId, courseName, showCourseTitle = true, onBack, }) {
223379
223991
  var _a, _b;
223380
223992
  const t = useT();
@@ -223387,7 +223999,7 @@ function AnalyticsCourseDetail({ tenantKey, mentorId, selectedMentorId, courseId
223387
223999
  const [selectedEnrollment, setSelectedEnrollment] = useState(null);
223388
224000
  const resolvedCourseName = courseName || (courseInfo === null || courseInfo === void 0 ? void 0 : courseInfo.name);
223389
224001
  const showTitle = showCourseTitle && !!resolvedCourseName;
223390
- return (jsxs("div", { className: "space-y-8", children: [(onBack || showTitle) && (jsxs("div", { className: "mb-4 flex flex-col gap-2 sm:flex-row sm:items-center sm:gap-4", children: [jsx("div", { className: "flex flex-1 justify-start", children: onBack && (jsxs(Button$1, { variant: "ghost", onClick: onBack, "aria-label": t('analyticsAnalyticsCourseDetail.goBackAriaLabel'), children: [jsx(ArrowLeft, { className: "mr-2 h-4 w-4" }), t('analyticsAnalyticsCourseDetail.backToCourses')] })) }), showTitle && (jsx("h2", { className: "flex-1 text-left text-2xl font-medium text-gray-700 sm:text-center", children: resolvedCourseName })), jsx("div", { className: "hidden flex-1 sm:block" })] })), jsxs("div", { className: "grid grid-cols-1 sm:grid-cols-3 gap-4 mb-6", children: [jsx(StatCard, { loading: isLoading, title: t('analyticsAnalyticsCourseDetail.activeEnrollments'), value: courseDetailStats.active_enrollments, percentage: courseDetailStats.active_enrollments_percentage }), jsx(StatCard, { loading: isLoading, title: t('analyticsAnalyticsCourseDetail.completedEnrollments'), value: courseDetailStats.completed_enrollments, percentage: courseDetailStats.completed_enrollments_percentage }), jsx(StatCard, { loading: isLoading, title: t('analyticsAnalyticsCourseDetail.timeSpent'), value: formatTimeSpent(courseDetailStats.time_spent), percentage: courseDetailStats.time_spent_percentage })] }), jsx("div", { className: "grid grid-cols-1 gap-6", children: jsx(Card, { className: "w-full bg-white shadow-xs", style: { borderColor: 'oklch(.922 0 0)' }, children: jsxs(CardContent, { className: "p-4", "aria-label": t('analyticsAnalyticsCourseDetail.courseEnrollmentsTableAriaLabel'), children: [jsx("h3", { className: "text-base font-medium text-gray-700 mb-4", children: t('analyticsAnalyticsCourseDetail.enrolledUsers') }), jsxs("div", { className: "space-y-4", children: [jsxs("div", { className: "relative flex-1 w-full", children: [jsx(Search, { className: "absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-gray-400" }), jsx(Input, { id: "search-enrolled-user", type: "text", placeholder: t('analyticsAnalyticsCourseDetail.searchPlaceholder'), value: courseEnrollmentsSearch, onChange: handleCourseEnrollmentsSearchInputChange, className: "pl-9 border-gray-300 focus:bg-transparent focus:color-transparent h-11", "aria-label": t('analyticsAnalyticsCourseDetail.searchAriaLabel') })] }), isLoading ? (jsx("div", { className: "flex items-center justify-center py-8", children: jsx("div", { className: "text-sm text-gray-500", children: t('analyticsAnalyticsCourseDetail.loadingLabel') }) })) : ((_a = courseEnrollments === null || courseEnrollments === void 0 ? void 0 : courseEnrollments.enrollments) === null || _a === void 0 ? void 0 : _a.length) &&
224002
+ return (jsxs("div", { className: "space-y-8", children: [(onBack || showTitle) && (jsxs("div", { className: "mb-4 flex flex-col gap-2 sm:flex-row sm:items-center sm:gap-4", children: [jsx("div", { className: "flex flex-1 justify-start", children: onBack && (jsxs(Button$1, { variant: "ghost", onClick: onBack, "aria-label": t('analyticsAnalyticsCourseDetail.goBackAriaLabel'), children: [jsx(ArrowLeft, { className: "mr-2 h-4 w-4" }), t('analyticsAnalyticsCourseDetail.backToCourses')] })) }), showTitle && (jsx("h2", { className: "flex-1 text-left text-2xl font-medium text-gray-700 sm:text-center", children: resolvedCourseName })), jsx("div", { className: "hidden flex-1 sm:block" })] })), jsxs("div", { className: "grid grid-cols-1 sm:grid-cols-2 gap-4 mb-6", children: [jsx(StatCard, { loading: isLoading, title: t('analyticsAnalyticsCourseDetail.activeEnrollments'), value: courseDetailStats.active_enrollments, percentage: courseDetailStats.active_enrollments_percentage }), jsx(StatCard, { loading: isLoading, title: t('analyticsAnalyticsCourseDetail.completedEnrollments'), value: courseDetailStats.completed_enrollments, percentage: courseDetailStats.completed_enrollments_percentage })] }), jsx("div", { className: "grid grid-cols-1 gap-6", children: jsx(Card, { className: "w-full bg-white shadow-xs", style: { borderColor: 'oklch(.922 0 0)' }, children: jsxs(CardContent, { className: "p-4", "aria-label": t('analyticsAnalyticsCourseDetail.courseEnrollmentsTableAriaLabel'), children: [jsx("h3", { className: "text-base font-medium text-gray-700 mb-4", children: t('analyticsAnalyticsCourseDetail.enrolledUsers') }), jsxs("div", { className: "space-y-4", children: [jsxs("div", { className: "relative flex-1 w-full", children: [jsx(Search, { className: "absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-gray-400" }), jsx(Input, { id: "search-enrolled-user", type: "text", placeholder: t('analyticsAnalyticsCourseDetail.searchPlaceholder'), value: courseEnrollmentsSearch, onChange: handleCourseEnrollmentsSearchInputChange, className: "pl-9 border-gray-300 focus:bg-transparent focus:color-transparent h-11", "aria-label": t('analyticsAnalyticsCourseDetail.searchAriaLabel') })] }), isLoading ? (jsx("div", { className: "flex items-center justify-center py-8", children: jsx("div", { className: "text-sm text-gray-500", children: t('analyticsAnalyticsCourseDetail.loadingLabel') }) })) : ((_a = courseEnrollments === null || courseEnrollments === void 0 ? void 0 : courseEnrollments.enrollments) === null || _a === void 0 ? void 0 : _a.length) &&
223391
224003
  courseEnrollments.enrollments.length > 0 ? (jsxs(Fragment$1, { children: [jsx("div", { className: "rounded-md overflow-x-auto", style: { borderColor: 'oklch(.922 0 0)', borderWidth: '1px' }, children: jsxs(Table, { children: [jsx(TableHeader, { children: jsxs(TableRow, { className: "h-[48px]", style: { borderColor: 'oklch(.922 0 0)' }, children: [jsx(TableHead, { className: "text-left", children: t('analyticsAnalyticsCourseDetail.columnName') }), jsx(TableHead, { className: "text-left", children: t('analyticsAnalyticsCourseDetail.columnEmail') }), jsx(TableHead, { className: "text-right", children: t('analyticsAnalyticsCourseDetail.columnEnrollmentDate') }), jsx(TableHead, { className: "text-right", children: t('analyticsAnalyticsCourseDetail.columnLastActiveOn') })] }) }), jsx(TableBody, { children: courseEnrollments.enrollments.map((enrollment, index) => (jsxs(TableRow, { className: `cursor-pointer hover:bg-muted/50 h-[48px] ${index % 2 === 0 ? 'bg-gray-50' : ''}`, onClick: () => setSelectedEnrollment(enrollment), role: "button", tabIndex: 0, onKeyDown: (e) => {
223392
224004
  if (e.key === 'Enter' || e.key === ' ') {
223393
224005
  e.preventDefault();
@@ -223682,7 +224294,7 @@ const formatSecondsToHours = (seconds) => {
223682
224294
  return Math.round((seconds / 3600) * 10) / 10;
223683
224295
  };
223684
224296
  function AnalyticsPrograms({ tenantKey, mentorId, selectedMentorId, basePath = '', }) {
223685
- var _a, _b, _c, _d, _e;
224297
+ var _a, _b, _c, _d;
223686
224298
  const t = useT();
223687
224299
  const router = useRouter();
223688
224300
  const currentMentorId = selectedMentorId || mentorId;
@@ -223690,11 +224302,12 @@ function AnalyticsPrograms({ tenantKey, mentorId, selectedMentorId, basePath = '
223690
224302
  const handleProgramClick = (programId) => {
223691
224303
  router.push(`${basePath}/programs/${programId}`);
223692
224304
  };
223693
- return (jsxs("div", { className: "space-y-8", children: [jsxs("div", { className: "grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4 mb-6", children: [jsx(StatCard, { loading: isLoading, title: t('analyticsAnalyticsPrograms.activePrograms'), value: programStats.active_programs, percentage: programStats.active_programs_percentage }), jsx(StatCard, { loading: isLoading, title: t('analyticsAnalyticsPrograms.totalPrograms'), value: programStats.total_programs, percentage: programStats.total_programs_percentage }), jsx(StatCard, { loading: isLoading, title: t('analyticsAnalyticsPrograms.enrollments'), value: programStats.enrollments, percentage: programStats.enrollments_percentage }), jsx(StatCard, { loading: isLoading, title: t('analyticsAnalyticsPrograms.totalLearners'), value: programStats.total_learners })] }), jsx("div", { className: "grid grid-cols-1 gap-6", children: jsx(ChartCardWrapper, { title: t('analyticsAnalyticsPrograms.programOvertime'), label: t('analyticsAnalyticsPrograms.timeSpent'), filters: enrollmentStatsDateFilter, setOutsideFilters: setEnrollmentStatsDateFilter, children: isLoading ? (jsx(ChartLoading, {})) : ((_a = enrollmentStats === null || enrollmentStats === void 0 ? void 0 : enrollmentStats.points) === null || _a === void 0 ? void 0 : _a.length) && ((_b = enrollmentStats === null || enrollmentStats === void 0 ? void 0 : enrollmentStats.points) === null || _b === void 0 ? void 0 : _b.length) > 0 ? (jsxs(LineChart, { data: ((_c = enrollmentStats === null || enrollmentStats === void 0 ? void 0 : enrollmentStats.points) === null || _c === void 0 ? void 0 : _c.map((point) => ({
224305
+ const hasEnrollmentStatsPoints = Number((_a = enrollmentStats === null || enrollmentStats === void 0 ? void 0 : enrollmentStats.points) === null || _a === void 0 ? void 0 : _a.length) > 0;
224306
+ return (jsxs("div", { className: "space-y-8", children: [jsxs("div", { className: "grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4 mb-6", children: [jsx(StatCard, { loading: isLoading, title: t('analyticsAnalyticsPrograms.activePrograms'), value: programStats.active_programs, percentage: programStats.active_programs_percentage }), jsx(StatCard, { loading: isLoading, title: t('analyticsAnalyticsPrograms.totalPrograms'), value: programStats.total_programs, percentage: programStats.total_programs_percentage }), jsx(StatCard, { loading: isLoading, title: t('analyticsAnalyticsPrograms.enrollments'), value: programStats.enrollments, percentage: programStats.enrollments_percentage }), jsx(StatCard, { loading: isLoading, title: t('analyticsAnalyticsPrograms.totalLearners'), value: programStats.total_learners })] }), (isLoading || hasEnrollmentStatsPoints) && (jsx("div", { className: "grid grid-cols-1 gap-6", children: jsx(ChartCardWrapper, { title: t('analyticsAnalyticsPrograms.programOvertime'), label: t('analyticsAnalyticsPrograms.timeSpent'), filters: enrollmentStatsDateFilter, setOutsideFilters: setEnrollmentStatsDateFilter, children: isLoading ? (jsx(ChartLoading, {})) : (jsxs(LineChart, { data: ((_b = enrollmentStats === null || enrollmentStats === void 0 ? void 0 : enrollmentStats.points) === null || _b === void 0 ? void 0 : _b.map((point) => ({
223694
224307
  date: formatDateToShortFormat(point.date, enrollmentStatsDateFilter.activeFilter === 'today'),
223695
224308
  value: formatSecondsToHours(point.value),
223696
224309
  rawSeconds: point.value,
223697
- }))) || [], margin: { top: 5, right: 5, left: 0, bottom: 5 }, children: [jsx(CartesianGrid, { strokeDasharray: "3 3", stroke: "#f0f0f0", vertical: false }), jsx(XAxis, { dataKey: "date", tick: { fontSize: 8, textAnchor: 'end' }, angle: -45, interval: Math.floor(Number((_d = enrollmentStats === null || enrollmentStats === void 0 ? void 0 : enrollmentStats.points) === null || _d === void 0 ? void 0 : _d.length) / 31) || 0 }), jsx(YAxis, { tick: { fontSize: 10 }, width: 40, allowDecimals: false, tickFormatter: (value) => `${value}h` }), jsx(Tooltip, { content: ({ active, payload, label }) => {
224310
+ }))) || [], margin: { top: 5, right: 5, left: 0, bottom: 5 }, children: [jsx(CartesianGrid, { strokeDasharray: "3 3", stroke: "#f0f0f0", vertical: false }), jsx(XAxis, { dataKey: "date", tick: { fontSize: 8, textAnchor: 'end' }, angle: -45, interval: Math.floor(Number((_c = enrollmentStats === null || enrollmentStats === void 0 ? void 0 : enrollmentStats.points) === null || _c === void 0 ? void 0 : _c.length) / 31) || 0 }), jsx(YAxis, { tick: { fontSize: 10 }, width: 40, allowDecimals: false, tickFormatter: (value) => `${value}h` }), jsx(Tooltip, { content: ({ active, payload, label }) => {
223698
224311
  var _a;
223699
224312
  if (!active || !(payload === null || payload === void 0 ? void 0 : payload.length))
223700
224313
  return null;
@@ -223705,7 +224318,7 @@ function AnalyticsPrograms({ tenantKey, mentorId, selectedMentorId, basePath = '
223705
224318
  stroke: '#38A1E5',
223706
224319
  strokeWidth: 2,
223707
224320
  fill: 'white',
223708
- } })] })) : (jsx(EmptyStats, {})) }) }), jsx("div", { className: "grid grid-cols-1 gap-6", children: jsx(Card, { className: "w-full bg-white shadow-xs", style: { borderColor: 'oklch(.922 0 0)' }, children: jsxs(CardContent, { className: "p-4", "aria-label": t('analyticsAnalyticsPrograms.programsTableAriaLabel'), children: [jsx("h3", { className: "text-base font-medium text-gray-700 mb-4", children: t('analyticsAnalyticsPrograms.programs') }), jsxs("div", { className: "space-y-4", children: [jsxs("div", { className: "relative flex-1 w-full", children: [jsx(Search, { className: "absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-gray-400" }), jsx(Input, { id: "search-program", type: "text", placeholder: t('analyticsAnalyticsPrograms.searchPlaceholder'), value: programsListSearch, onChange: handleSearchInputChange, className: "pl-9 border-gray-300 focus:bg-transparent focus:color-transparent h-11", "aria-label": t('analyticsAnalyticsPrograms.searchAriaLabel') })] }), isLoading ? (jsx("div", { className: "flex items-center justify-center py-8", children: jsx("div", { className: "text-sm text-gray-500", children: t('analyticsAnalyticsPrograms.loading') }) })) : ((_e = programsList === null || programsList === void 0 ? void 0 : programsList.programs) === null || _e === void 0 ? void 0 : _e.length) && programsList.programs.length > 0 ? (jsxs(Fragment$1, { children: [jsx("div", { className: "rounded-md overflow-x-auto", style: { borderColor: 'oklch(.922 0 0)', borderWidth: '1px' }, children: jsxs(Table, { children: [jsx(TableHeader, { children: jsxs(TableRow, { className: "h-[48px]", style: { borderColor: 'oklch(.922 0 0)' }, children: [jsx(TableHead, { className: "text-left", children: t('analyticsAnalyticsPrograms.programName') }), jsx(TableHead, { className: "text-left", children: t('analyticsAnalyticsPrograms.programId') }), jsx(TableHead, { className: "text-right", children: t('analyticsAnalyticsPrograms.enrollments') })] }) }), jsx(TableBody, { children: programsList.programs.map((program, index) => (jsxs(TableRow, { className: `cursor-pointer hover:bg-muted/50 h-[48px] ${index % 2 === 0 ? 'bg-gray-50' : ''}`, onClick: () => handleProgramClick(program.id), role: "button", tabIndex: 0, onKeyDown: (e) => {
224321
+ } })] })) }) })), jsx("div", { className: "grid grid-cols-1 gap-6", children: jsx(Card, { className: "w-full bg-white shadow-xs", style: { borderColor: 'oklch(.922 0 0)' }, children: jsxs(CardContent, { className: "p-4", "aria-label": t('analyticsAnalyticsPrograms.programsTableAriaLabel'), children: [jsx("h3", { className: "text-base font-medium text-gray-700 mb-4", children: t('analyticsAnalyticsPrograms.programs') }), jsxs("div", { className: "space-y-4", children: [jsxs("div", { className: "relative flex-1 w-full", children: [jsx(Search, { className: "absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-gray-400" }), jsx(Input, { id: "search-program", type: "text", placeholder: t('analyticsAnalyticsPrograms.searchPlaceholder'), value: programsListSearch, onChange: handleSearchInputChange, className: "pl-9 border-gray-300 focus:bg-transparent focus:color-transparent h-11", "aria-label": t('analyticsAnalyticsPrograms.searchAriaLabel') })] }), isLoading ? (jsx("div", { className: "flex items-center justify-center py-8", children: jsx("div", { className: "text-sm text-gray-500", children: t('analyticsAnalyticsPrograms.loading') }) })) : ((_d = programsList === null || programsList === void 0 ? void 0 : programsList.programs) === null || _d === void 0 ? void 0 : _d.length) && programsList.programs.length > 0 ? (jsxs(Fragment$1, { children: [jsx("div", { className: "rounded-md overflow-x-auto", style: { borderColor: 'oklch(.922 0 0)', borderWidth: '1px' }, children: jsxs(Table, { children: [jsx(TableHeader, { children: jsxs(TableRow, { className: "h-[48px]", style: { borderColor: 'oklch(.922 0 0)' }, children: [jsx(TableHead, { className: "text-left", children: t('analyticsAnalyticsPrograms.programName') }), jsx(TableHead, { className: "text-left", children: t('analyticsAnalyticsPrograms.programId') }), jsx(TableHead, { className: "text-right", children: t('analyticsAnalyticsPrograms.enrollments') })] }) }), jsx(TableBody, { children: programsList.programs.map((program, index) => (jsxs(TableRow, { className: `cursor-pointer hover:bg-muted/50 h-[48px] ${index % 2 === 0 ? 'bg-gray-50' : ''}`, onClick: () => handleProgramClick(program.id), role: "button", tabIndex: 0, onKeyDown: (e) => {
223709
224322
  if (e.key === 'Enter' || e.key === ' ') {
223710
224323
  e.preventDefault();
223711
224324
  handleProgramClick(program.id);
@@ -224246,6 +224859,542 @@ function AnalyticsAuditLogStats({ tenantKey, mentorId, userId, selectedMentorId,
224246
224859
  }, children: [jsx(SelectTrigger, { className: "w-full font-normal bg-white h-9", children: jsx(SelectValue, { placeholder: t('analyticsAnalyticsAuditLogStats.allActions') }) }), jsx(SelectContent, { children: ACTION_FILTER_OPTIONS.map((opt) => (jsx(SelectItem, { value: opt.value, children: opt.label }, opt.value))) })] }) })] }) }), jsx("div", { className: "overflow-hidden rounded-md border border-[oklch(0.922_0_0)] bg-white", children: jsx("div", { className: "overflow-x-auto", children: jsx("div", { className: "inline-block min-w-full align-middle", children: isLoading ? (jsx("div", { className: "flex items-center justify-center w-full py-10", children: jsx("div", { className: "h-6 w-6 animate-spin rounded-full border-2 border-blue-600 border-t-transparent" }) })) : error && !is403 ? (jsx("div", { className: "py-8 text-center text-[#646464]", children: t('analyticsAnalyticsAuditLogStats.loadError') })) : !((_a = data === null || data === void 0 ? void 0 : data.results) === null || _a === void 0 ? void 0 : _a.length) ? (jsx("div", { className: "h-[120px]", children: jsx(EmptyStats, { title: t('analyticsAnalyticsAuditLogStats.noEntries') }) })) : (jsxs(Table, { className: "min-w-full", children: [jsx(TableHeader, { children: jsxs(TableRow, { className: "bg-muted/50 border-b border-[oklch(0.922_0_0)]", children: [jsx(TableHead, { className: "p-3 text-left text-sm whitespace-nowrap text-[#646464]", children: t('analyticsAnalyticsAuditLogStats.colUser') }), jsx(TableHead, { className: "p-3 text-left text-sm whitespace-nowrap text-[#646464]", children: t('analyticsAnalyticsAuditLogStats.colAction') }), jsx(TableHead, { className: "p-3 text-left text-sm whitespace-nowrap text-[#646464]", children: t('analyticsAnalyticsAuditLogStats.colTime') })] }) }), jsx(TableBody, { children: data.results.map((entry) => (jsxs(TableRow, { className: "border-b border-[oklch(0.922_0_0)] last:border-0", children: [jsx(TableCell, { className: "p-3 font-medium whitespace-nowrap text-[#646464]", children: entry.actor_email }), jsx(TableCell, { className: "min-w-[250px] p-3 text-[#646464]", children: summarizeChanges(entry) }), jsx(TableCell, { className: "p-3 whitespace-nowrap text-[#646464]", children: formatDistanceToNow(new Date(entry.timestamp), { addSuffix: true }) })] }, entry.id))) })] })) }) }) }), jsx(IblPagination, { currentPage: page, totalPages: totalPages, onPageChange: setPage, disabled: isLoading })] }));
224247
224860
  }
224248
224861
 
224862
+ /**
224863
+ * Core agent search hook — thin wrapper around `useGetAiSearchMentorsQuery`.
224864
+ *
224865
+ * This is the low-level building block. For a higher-level hook that manages
224866
+ * search state, debounce, and pagination controls, use
224867
+ * `useAgentSearchWithPagination`.
224868
+ */
224869
+ function useAgentSearch({ tenantKey, query, limit = 6, offset, starred, featured, category, subjects, llm, types, includeMainPublicMentors, orderDirection, skip = false, }) {
224870
+ var _a, _b, _c;
224871
+ const { data, isLoading, isFetching, refetch } = useGetAiSearchMentorsQuery({
224872
+ platform_key: tenantKey,
224873
+ query: query || undefined,
224874
+ limit,
224875
+ ...(offset !== undefined && { offset }),
224876
+ ...(starred !== undefined && { starred }),
224877
+ ...(featured !== undefined && { featured }),
224878
+ ...(category && { category }),
224879
+ ...(subjects && { subjects }),
224880
+ ...(llm && { llm }),
224881
+ ...(types && { types }),
224882
+ ...(includeMainPublicMentors !== undefined && {
224883
+ include_main_public_mentors: includeMainPublicMentors,
224884
+ }),
224885
+ ...(orderDirection && { order_direction: orderDirection }),
224886
+ }, { skip: skip || !tenantKey });
224887
+ return {
224888
+ agents: ((_a = data === null || data === void 0 ? void 0 : data.results) !== null && _a !== void 0 ? _a : []),
224889
+ facets: data === null || data === void 0 ? void 0 : data.facets,
224890
+ hasMore: !!(data === null || data === void 0 ? void 0 : data.next),
224891
+ totalCount: (_b = data === null || data === void 0 ? void 0 : data.count) !== null && _b !== void 0 ? _b : 0,
224892
+ totalPages: (_c = data === null || data === void 0 ? void 0 : data.total_pages) !== null && _c !== void 0 ? _c : 0,
224893
+ isLoading,
224894
+ isFetching,
224895
+ refetch,
224896
+ };
224897
+ }
224898
+
224899
+ function c(e,u,c){var i=this,a=useRef(null),o=useRef(0),f=useRef(null),l=useRef([]),v=useRef(),m=useRef(),d=useRef(e),g=useRef(true);d.current=e;var p="undefined"!=typeof window,w=!u&&0!==u&&p;if("function"!=typeof e)throw new TypeError("Expected a function");u=+u||0;var s=!!(c=c||{}).leading,x=!("trailing"in c)||!!c.trailing,h="maxWait"in c,y="debounceOnServer"in c&&!!c.debounceOnServer,F=h?Math.max(+c.maxWait||0,u):null;useEffect(function(){return g.current=true,function(){g.current=false;}},[]);var A=useMemo(function(){var r=function(r){var n=l.current,t=v.current;return l.current=v.current=null,o.current=r,m.current=d.current.apply(t,n)},n=function(r,n){w&&cancelAnimationFrame(f.current),f.current=w?requestAnimationFrame(r):setTimeout(r,n);},t=function(r){if(!g.current)return false;var n=r-a.current;return !a.current||n>=u||n<0||h&&r-o.current>=F},e=function(n){return f.current=null,x&&l.current?r(n):(l.current=v.current=null,m.current)},c=function r(){var c=Date.now();if(t(c))return e(c);if(g.current){var i=u-(c-a.current),f=h?Math.min(i,F-(c-o.current)):i;n(r,f);}},A=function(){if(p||y){var e=Date.now(),d=t(e);if(l.current=[].slice.call(arguments),v.current=i,a.current=e,d){if(!f.current&&g.current)return o.current=a.current,n(c,u),s?r(a.current):m.current;if(h)return n(c,u),r(a.current)}return f.current||n(c,u),m.current}};return A.cancel=function(){f.current&&(w?cancelAnimationFrame(f.current):clearTimeout(f.current)),o.current=0,l.current=a.current=v.current=f.current=null;},A.isPending=function(){return !!f.current},A.flush=function(){return f.current?e(Date.now()):m.current},A},[s,h,u,F,x,w,p,y]);return A}function i(r,n){return r===n}function a(n,t,a){var o=i,f=useRef(n),l=useState({})[1],v=c(useCallback(function(r){f.current=r,l({});},[l]),t,a),m=useRef(n);return o(m.current,n)||(v(n),m.current=n),[f.current,v]}
224900
+
224901
+ /**
224902
+ * Higher-level agent search hook that manages search state, debounce, and
224903
+ * pagination controls on top of `useAgentSearch`.
224904
+ *
224905
+ * Use this for simple list/table views (MyMentorsModal, SettingsModal).
224906
+ * For the full explore page with sections, use `useAgentSearch` directly.
224907
+ */
224908
+ function useAgentSearchWithPagination({ itemsPerPage = 6, paginationMode = 'paginated', debounceMs = 500, ...queryConfig }) {
224909
+ const [searchQuery, setSearchQuery] = React__default.useState('');
224910
+ const [debouncedQuery] = a(searchQuery, debounceMs);
224911
+ const [currentPage, setCurrentPage] = React__default.useState(1);
224912
+ const [infiniteLimit, setInfiniteLimit] = React__default.useState(itemsPerPage);
224913
+ // Reset pagination when search changes
224914
+ React__default.useEffect(() => {
224915
+ setCurrentPage(1);
224916
+ setInfiniteLimit(itemsPerPage);
224917
+ }, [debouncedQuery, itemsPerPage]);
224918
+ const isPaginated = paginationMode === 'paginated';
224919
+ const result = useAgentSearch({
224920
+ ...queryConfig,
224921
+ query: debouncedQuery,
224922
+ limit: isPaginated ? itemsPerPage : infiniteLimit,
224923
+ offset: isPaginated ? (currentPage - 1) * itemsPerPage : undefined,
224924
+ });
224925
+ const totalPages = Math.ceil(result.totalCount / itemsPerPage);
224926
+ const handlePageChange = React__default.useCallback((page) => {
224927
+ setCurrentPage(page);
224928
+ }, []);
224929
+ const loadMore = React__default.useCallback(() => {
224930
+ setInfiniteLimit((prev) => prev + itemsPerPage);
224931
+ }, [itemsPerPage]);
224932
+ return {
224933
+ ...result,
224934
+ searchQuery,
224935
+ setSearchQuery,
224936
+ debouncedQuery,
224937
+ currentPage,
224938
+ totalPages,
224939
+ handlePageChange,
224940
+ loadMore,
224941
+ };
224942
+ }
224943
+
224944
+ function MentorSelectionGrid({ selectedMentorIds, onMentorSelect, searchQuery, onSearchChange, tenantKey, itemsPerPage = 8, showSearch = true, minHeight = '400px', }) {
224945
+ const t = useT();
224946
+ const { agents: mentors, isLoading: isMentorsLoading, isFetching: isMentorsFetching, currentPage, totalPages, setSearchQuery: setMentorSearch, handlePageChange, } = useAgentSearchWithPagination({ tenantKey, itemsPerPage });
224947
+ // Update search query with debounce effect handled by the hook
224948
+ React__default.useEffect(() => {
224949
+ setMentorSearch(searchQuery);
224950
+ }, [searchQuery]);
224951
+ const isMentorSelected = (mentorId) => {
224952
+ return selectedMentorIds.includes(mentorId);
224953
+ };
224954
+ return (jsxs("div", { className: "space-y-4", children: [showSearch && (jsxs("div", { className: "relative", children: [isMentorsFetching ? (jsx(Spinner, { className: "absolute top-1/2 left-3 h-4 w-4 -translate-y-1/2 transform text-gray-400" })) : (jsx(Search, { className: "absolute top-1/2 left-3 h-4 w-4 -translate-y-1/2 transform text-gray-400" })), jsx(Input, { placeholder: t('mentorsMentorSelectionGrid.searchAgentsPlaceholder'), value: searchQuery, onChange: (e) => onSearchChange(e.target.value), className: "h-10 border-gray-200 pl-10 focus:border-blue-500 focus:ring-0" })] })), jsxs("div", { className: "space-y-4", children: [jsx("div", { className: "grid max-h-96 auto-rows-min grid-cols-1 items-start gap-3 overflow-y-auto rounded-lg border border-gray-200 p-4 md:max-h-none md:grid-cols-2", style: { minHeight }, children: isMentorsLoading ? (jsx("div", { className: "col-span-full py-8 text-center text-gray-500", children: t('mentorsMentorSelectionGrid.loadingAgents') })) : mentors.length === 0 ? (jsx("div", { className: "col-span-full py-8 text-center text-gray-500", children: t('mentorsMentorSelectionGrid.noAgentsFound') })) : (mentors.map((mentor) => {
224955
+ const isSelected = isMentorSelected(mentor.unique_id || '');
224956
+ const isAlreadyAdded = selectedMentorIds.includes(mentor.unique_id || '');
224957
+ return (jsxs("button", { onClick: () => onMentorSelect(mentor), className: `flex cursor-pointer items-center gap-3 rounded-lg border-2 p-3 transition-all ${isSelected
224958
+ ? 'border-blue-500 bg-blue-50'
224959
+ : isAlreadyAdded
224960
+ ? 'bg-blue-25 border-blue-300'
224961
+ : 'border-gray-200 hover:border-gray-300 hover:bg-gray-50'}`, children: [jsxs(Avatar, { className: "h-12 w-12 flex-shrink-0", children: [jsx(AvatarImage, { src: mentor.profile_image || '/placeholder.svg', alt: mentor.name }), jsx(AvatarFallback, { children: mentor.name.substring(0, 2) })] }), jsxs("div", { className: "flex min-w-0 flex-1 flex-col justify-start text-left", children: [jsx("h4", { className: "truncate text-sm font-medium text-gray-900", children: mentor.name }), jsx("p", { className: "line-clamp-2 text-xs text-gray-600", children: mentor.description })] }), isSelected && (jsx("div", { className: "flex-shrink-0", children: jsx("div", { className: "flex h-6 w-6 items-center justify-center rounded-full bg-blue-600", children: jsx(Check, { className: "h-4 w-4 text-white" }) }) })), isAlreadyAdded && !isSelected && (jsx("div", { className: "flex-shrink-0", children: jsx("div", { className: "flex h-6 w-6 items-center justify-center rounded-full bg-blue-400", children: jsx(Check, { className: "h-4 w-4 text-white" }) }) }))] }, mentor.unique_id));
224962
+ })) }), jsx(IblPagination, { currentPage: currentPage, totalPages: totalPages, onPageChange: handlePageChange, disabled: isMentorsFetching || isMentorsLoading })] })] }));
224963
+ }
224964
+
224965
+ const USERS_PAGE_SIZE = 50;
224966
+ const SEARCH_DEBOUNCE_MS = 300;
224967
+ /** cmdk needs a non-empty value; the handler treats this one as "clear". */
224968
+ const SELF_VALUE = '__self__';
224969
+ /**
224970
+ * RBAC action a watcher must hold on a user for their memories to be listable —
224971
+ * the same one the memory endpoints check, so the dropdown can't offer a user
224972
+ * whose memories would then come back 403.
224973
+ */
224974
+ const MEMORY_LIST_ACTION = 'Ibl.Mentor/Memory/list';
224975
+ function useDebouncedValue(value, delay) {
224976
+ const [debounced, setDebounced] = useState(value);
224977
+ useEffect(() => {
224978
+ const timer = setTimeout(() => setDebounced(value), delay);
224979
+ return () => clearTimeout(timer);
224980
+ }, [value, delay]);
224981
+ return debounced;
224982
+ }
224983
+ /**
224984
+ * Tenant user picker for the analytics memory filters. Both endpoints behind it
224985
+ * do the searching, so the dropdown only pages in the first
224986
+ * {@link USERS_PAGE_SIZE} matches for whatever is typed rather than filtering
224987
+ * client-side.
224988
+ *
224989
+ * Which endpoint serves the list depends on the caller:
224990
+ * - Admins get `GET /api/core/platform/users/` — every user on the tenant.
224991
+ * - Pure watchers get `GET /api/core/users/accessible/`, which the platform
224992
+ * endpoint would 403 for. It returns only the users they hold
224993
+ * {@link MEMORY_LIST_ACTION} on, i.e. the members of the groups they watch.
224994
+ */
224995
+ function UserFilterSelect({ tenantKey, currentUsername, value, onChange, }) {
224996
+ const t = useT();
224997
+ const [open, setOpen] = useState(false);
224998
+ const [search, setSearch] = useState('');
224999
+ const debouncedSearch = useDebouncedValue(search, SEARCH_DEBOUNCE_MS);
225000
+ const { currentTenant } = useCurrentTenant();
225001
+ const rbacPermissions = useSelector(selectRbacPermissions);
225002
+ const isWatcher = isPureWatcher(rbacPermissions, currentTenant);
225003
+ // Only fetched once the dropdown is open — the trigger shows the selected
225004
+ // username, which is the filter value itself, so nothing needs looking up
225005
+ // first.
225006
+ const { data, isFetching: isFetchingPlatformUsers } = usePlatformUsersQuery({
225007
+ platform_key: tenantKey,
225008
+ platform_org: tenantKey,
225009
+ page: 1,
225010
+ page_size: USERS_PAGE_SIZE,
225011
+ query: debouncedSearch,
225012
+ return_policies: 'false',
225013
+ }, { skip: !open || !tenantKey || isWatcher });
225014
+ // The accessible endpoint scopes itself to the caller's platform from their
225015
+ // token, so it takes no tenant param. It also filters per field instead of
225016
+ // with one search param, hence the "@" routing the term to `email` and
225017
+ // anything else to `username`.
225018
+ const { data: accessibleUsers, isFetching: isFetchingAccessibleUsers } = useGetAccessibleUsersQuery({
225019
+ required_action: MEMORY_LIST_ACTION,
225020
+ page: 1,
225021
+ page_size: USERS_PAGE_SIZE,
225022
+ sort: 'name',
225023
+ ...(debouncedSearch.includes('@')
225024
+ ? { email: debouncedSearch }
225025
+ : { username: debouncedSearch }),
225026
+ }, { skip: !open || !isWatcher });
225027
+ const isFetching = isWatcher ? isFetchingAccessibleUsers : isFetchingPlatformUsers;
225028
+ const users = useMemo(() => {
225029
+ var _a, _b;
225030
+ let list;
225031
+ if (isWatcher) {
225032
+ list = ((_a = accessibleUsers === null || accessibleUsers === void 0 ? void 0 : accessibleUsers.results) !== null && _a !== void 0 ? _a : []).map((user) => ({
225033
+ key: String(user.id),
225034
+ username: user.username,
225035
+ name: user.name,
225036
+ email: user.email,
225037
+ }));
225038
+ }
225039
+ else {
225040
+ // `results` is a bare array unless policies were requested, in which case
225041
+ // the users sit under `results.data`.
225042
+ const results = data === null || data === void 0 ? void 0 : data.results;
225043
+ const platformUsers = Array.isArray(results)
225044
+ ? results
225045
+ : ((_b = results === null || results === void 0 ? void 0 : results.data) !== null && _b !== void 0 ? _b : []);
225046
+ list = platformUsers.map((user) => {
225047
+ var _a;
225048
+ return ({
225049
+ key: String((_a = user.user_id) !== null && _a !== void 0 ? _a : user.username),
225050
+ username: user.username,
225051
+ name: user.name,
225052
+ email: user.email,
225053
+ });
225054
+ });
225055
+ }
225056
+ return list.filter(
225057
+ // Usernames are the filter values, so a user without one is unselectable,
225058
+ // and the caller already has their own entry at the top of the list.
225059
+ (user) => !!user.username && user.username !== currentUsername);
225060
+ }, [isWatcher, accessibleUsers, data, currentUsername]);
225061
+ const handleSelect = (username) => {
225062
+ onChange(username);
225063
+ setOpen(false);
225064
+ };
225065
+ return (jsxs(Popover, { open: open, onOpenChange: setOpen, children: [jsx(PopoverTrigger, { asChild: true, children: jsxs(Button$1, { variant: "outline", role: "combobox", "aria-expanded": open, "aria-label": t('analyticsUserFilterSelect.filterByUser'), className: "h-9 w-full justify-between bg-white font-normal", children: [jsx("span", { className: "truncate", children: value || t('analyticsUserFilterSelect.you') }), jsx(ChevronsUpDown, { className: "ml-2 h-4 w-4 shrink-0 opacity-50" })] }) }), jsx(PopoverContent, { "data-iblai-dialog-interaction-layer": true, className: "z-[60] w-[280px] p-0", align: "start", children: jsxs(Command, { shouldFilter: false, children: [jsx(CommandInput, { value: search, onValueChange: setSearch, placeholder: t('analyticsUserFilterSelect.searchPlaceholder') }), jsxs(CommandList, { children: [jsxs(CommandGroup, { children: [jsxs(CommandItem, { value: SELF_VALUE, onSelect: () => handleSelect(''), children: [jsx(Check, { className: cn('mr-2 h-4 w-4', value ? 'opacity-0' : 'opacity-100') }), t('analyticsUserFilterSelect.you')] }), users.map((user) => (jsxs(CommandItem, {
225066
+ // cmdk keys items by value; the search itself is server-side.
225067
+ value: user.username, onSelect: () => handleSelect(user.username), children: [jsx(Check, { className: cn('mr-2 h-4 w-4', value === user.username ? 'opacity-100' : 'opacity-0') }), jsxs("div", { className: "flex min-w-0 flex-col", children: [jsx("span", { className: "truncate font-medium", children: user.name || user.username }), jsx("span", { className: "truncate text-xs text-gray-500", children: user.email || user.username })] })] }, user.key)))] }), isFetching && (jsx("div", { className: "px-3 py-4 text-center text-sm text-gray-500", children: t('analyticsUserFilterSelect.loadingUsers') })), !isFetching && users.length === 0 && (jsx("div", { className: "px-3 py-4 text-center text-sm text-gray-500", children: t('analyticsUserFilterSelect.noUsersFound') }))] })] }) })] }));
225068
+ }
225069
+
225070
+ /**
225071
+ * The global and cross-mentor endpoints both cap `page_size` at 25 server-side,
225072
+ * so we ask for a size every scope can honor rather than paginating
225073
+ * inconsistently between them.
225074
+ */
225075
+ const MEMORY_PAGE_SIZE = 20;
225076
+ /** Sentinel for "don't filter by category" — categories are keyed by slug. */
225077
+ const ALL_CATEGORIES = 'all';
225078
+ const formatDate = (date) => date ? date.toISOString().split('T')[0] : undefined;
225079
+ function isForbiddenError(error) {
225080
+ return !!error && 'status' in error && error.status === 403;
225081
+ }
225082
+ function toRowFromMentorMemory(memory) {
225083
+ var _a, _b, _c, _d, _e, _f;
225084
+ return {
225085
+ id: memory.id,
225086
+ content: memory.content,
225087
+ categoryName: (_b = (_a = memory.category) === null || _a === void 0 ? void 0 : _a.name) !== null && _b !== void 0 ? _b : null,
225088
+ categorySlug: (_d = (_c = memory.category) === null || _c === void 0 ? void 0 : _c.slug) !== null && _d !== void 0 ? _d : null,
225089
+ learner: memory.email || memory.username,
225090
+ email: memory.email || null,
225091
+ mentorId: (_e = memory.mentor_id) !== null && _e !== void 0 ? _e : null,
225092
+ mentorName: 'mentor_name' in memory ? ((_f = memory.mentor_name) !== null && _f !== void 0 ? _f : null) : null,
225093
+ isAutoGenerated: memory.is_auto_generated,
225094
+ sourceSessionId: memory.source_session_id,
225095
+ createdAt: memory.created_at,
225096
+ };
225097
+ }
225098
+ function toRowFromGlobalMemory(memory) {
225099
+ return {
225100
+ id: memory.id,
225101
+ content: memory.content,
225102
+ categoryName: null,
225103
+ categorySlug: null,
225104
+ learner: memory.username,
225105
+ email: null,
225106
+ mentorId: null,
225107
+ mentorName: null,
225108
+ isAutoGenerated: memory.is_auto_generated,
225109
+ sourceSessionId: memory.source_session_id,
225110
+ createdAt: memory.created_at,
225111
+ };
225112
+ }
225113
+ /**
225114
+ * Backs the analytics Memory tab. Owns scope selection (including an agent
225115
+ * picked through the dropdown's search), the shared filter state, and
225116
+ * pagination, and normalizes the three differently-shaped memory endpoints
225117
+ * into a single row type.
225118
+ *
225119
+ * All three list queries are always mounted (RTK Query hooks can't be called
225120
+ * conditionally); `skip` keeps only the active scope's request in flight.
225121
+ */
225122
+ const useMemory = ({ tenantKey, userId, mentorId, myMemory = false, }) => {
225123
+ const [searchedMentor, setSearchedMentor] = useState(null);
225124
+ // An agent picked from the scope dropdown's search stands in for the route
225125
+ // agent, so admins can inspect any agent's memories without leaving the tab.
225126
+ const activeMentorId = (searchedMentor === null || searchedMentor === void 0 ? void 0 : searchedMentor.id) || mentorId;
225127
+ const hasMentor = !!activeMentorId;
225128
+ // Global (agent-independent) memories lead: they are the ones that hold for
225129
+ // the user everywhere, so the tab opens on them and the dropdown lists them
225130
+ // first.
225131
+ const availableScopes = useMemo(() => (hasMentor ? ['global', 'mentor', 'all-mentors'] : ['global', 'all-mentors']), [hasMentor]);
225132
+ const [scope, setScope] = useState('global');
225133
+ const [page, setPage] = useState(1);
225134
+ const [learnerFilter, setLearnerFilter] = useState('');
225135
+ const [categoryFilter, setCategoryFilter] = useState(ALL_CATEGORIES);
225136
+ const [contentFilter, setContentFilter] = useState('');
225137
+ const [dateRange, setDateRange] = useState(undefined);
225138
+ const selectSearchedMentor = useCallback((mentor) => {
225139
+ setSearchedMentor(mentor);
225140
+ // Categories belong to a single agent, so a slug carried over from the
225141
+ // previous one would filter the new agent's memories down to nothing.
225142
+ setCategoryFilter(ALL_CATEGORIES);
225143
+ if (mentor)
225144
+ setScope('mentor');
225145
+ }, []);
225146
+ // Picking an agent in the analytics switcher is the more explicit choice, so
225147
+ // it drops whatever the tab's own search had pinned.
225148
+ useEffect(() => {
225149
+ setSearchedMentor(null);
225150
+ setCategoryFilter(ALL_CATEGORIES);
225151
+ }, [mentorId]);
225152
+ // The agent scope disappears when the analytics page has no agent selected;
225153
+ // fall back rather than leaving the tab stuck on an unqueryable scope.
225154
+ useEffect(() => {
225155
+ if (!hasMentor && scope === 'mentor') {
225156
+ setScope('all-mentors');
225157
+ }
225158
+ }, [hasMentor, scope]);
225159
+ // Only the agent-scoped endpoint takes a `category`, and the category list is
225160
+ // that agent's. Drop the selection anywhere else so a filter the UI no longer
225161
+ // shows can't silently narrow the results.
225162
+ useEffect(() => {
225163
+ if (scope !== 'mentor')
225164
+ setCategoryFilter(ALL_CATEGORIES);
225165
+ }, [scope]);
225166
+ // Any filter or scope change invalidates the current page index — the new
225167
+ // result set may well be shorter than the page we're sitting on.
225168
+ useEffect(() => {
225169
+ setPage(1);
225170
+ }, [scope, learnerFilter, categoryFilter, contentFilter, dateRange]);
225171
+ const startDate = formatDate(dateRange === null || dateRange === void 0 ? void 0 : dateRange.from);
225172
+ const endDate = formatDate(dateRange === null || dateRange === void 0 ? void 0 : dateRange.to);
225173
+ const isMentorScope = scope === 'mentor' && hasMentor;
225174
+ const isAllMentorsScope = scope === 'all-mentors';
225175
+ const isGlobalScope = scope === 'global';
225176
+ const hasIdentity = !!tenantKey && !!userId;
225177
+ const mentorListParams = useMemo(() => ({
225178
+ page,
225179
+ page_size: MEMORY_PAGE_SIZE,
225180
+ ...(categoryFilter !== ALL_CATEGORIES ? { category: categoryFilter } : {}),
225181
+ ...(learnerFilter ? { user_id: learnerFilter } : {}),
225182
+ ...(startDate ? { start_date: startDate } : {}),
225183
+ ...(endDate ? { end_date: endDate } : {}),
225184
+ ...(myMemory ? { my_memory: true } : {}),
225185
+ }), [page, categoryFilter, learnerFilter, startDate, endDate, myMemory]);
225186
+ const { data: mentorList, isLoading: isLoadingMentorList, isFetching: isFetchingMentorList, error: mentorListError, } = useGetMentorMemoriesListQuery({ org: tenantKey, userId, mentorId: activeMentorId !== null && activeMentorId !== void 0 ? activeMentorId : '', params: mentorListParams }, { skip: !hasIdentity || !isMentorScope });
225187
+ // Unpaginated, grouped-by-category companion to the list above. It honors the
225188
+ // same filters, so it's the only place we can source aggregates that describe
225189
+ // the whole filtered set instead of just the visible page.
225190
+ const mentorSnapshotParams = useMemo(() => ({
225191
+ ...(learnerFilter ? { user_id: learnerFilter } : {}),
225192
+ ...(startDate ? { start_date: startDate } : {}),
225193
+ ...(endDate ? { end_date: endDate } : {}),
225194
+ ...(myMemory ? { my_memory: true } : {}),
225195
+ }), [learnerFilter, startDate, endDate, myMemory]);
225196
+ const { data: mentorGrouped, isLoading: isLoadingMentorGrouped } = useGetMentorMemoriesQuery({ org: tenantKey, userId, mentorId: activeMentorId !== null && activeMentorId !== void 0 ? activeMentorId : '', params: mentorSnapshotParams }, { skip: !hasIdentity || !isMentorScope });
225197
+ // Deliberately unfiltered by mentor — the point of this scope is to span
225198
+ // every agent. Per-agent numbers come from the `mentor` scope instead.
225199
+ const allMentorsParams = useMemo(() => ({
225200
+ page,
225201
+ page_size: MEMORY_PAGE_SIZE,
225202
+ ...(learnerFilter ? { user_id: learnerFilter } : {}),
225203
+ ...(startDate ? { start_date: startDate } : {}),
225204
+ ...(endDate ? { end_date: endDate } : {}),
225205
+ }), [page, learnerFilter, startDate, endDate]);
225206
+ const { data: allMentors, isLoading: isLoadingAllMentors, isFetching: isFetchingAllMentors, error: allMentorsError, } = useGetAllMentorMemoriesQuery({ org: tenantKey, userId, params: allMentorsParams }, { skip: !hasIdentity || !isAllMentorsScope });
225207
+ const globalParams = useMemo(() => ({
225208
+ page,
225209
+ page_size: MEMORY_PAGE_SIZE,
225210
+ ...(learnerFilter ? { user_id: learnerFilter } : {}),
225211
+ ...(contentFilter ? { content: contentFilter } : {}),
225212
+ ...(startDate ? { start_date: startDate } : {}),
225213
+ ...(endDate ? { end_date: endDate } : {}),
225214
+ }), [page, learnerFilter, contentFilter, startDate, endDate]);
225215
+ const { data: globalMemories, isLoading: isLoadingGlobal, isFetching: isFetchingGlobal, error: globalError, } = useGetGlobalMemoriesQuery({ org: tenantKey, userId, params: globalParams }, { skip: !hasIdentity || !isGlobalScope });
225216
+ const { data: adminCategories } = useGetMemoryCategoriesAdminQuery({ org: tenantKey, mentorId: activeMentorId !== null && activeMentorId !== void 0 ? activeMentorId : '' }, { skip: !tenantKey || !hasMentor });
225217
+ const rows = useMemo(() => {
225218
+ var _a, _b, _c;
225219
+ if (isMentorScope)
225220
+ return ((_a = mentorList === null || mentorList === void 0 ? void 0 : mentorList.results) !== null && _a !== void 0 ? _a : []).map(toRowFromMentorMemory);
225221
+ if (isAllMentorsScope)
225222
+ return ((_b = allMentors === null || allMentors === void 0 ? void 0 : allMentors.results) !== null && _b !== void 0 ? _b : []).map(toRowFromMentorMemory);
225223
+ return ((_c = globalMemories === null || globalMemories === void 0 ? void 0 : globalMemories.results) !== null && _c !== void 0 ? _c : []).map(toRowFromGlobalMemory);
225224
+ }, [isMentorScope, isAllMentorsScope, mentorList, allMentors, globalMemories]);
225225
+ const totalCount = useMemo(() => {
225226
+ var _a, _b, _c;
225227
+ if (isMentorScope)
225228
+ return (_a = mentorList === null || mentorList === void 0 ? void 0 : mentorList.count) !== null && _a !== void 0 ? _a : 0;
225229
+ if (isAllMentorsScope)
225230
+ return (_b = allMentors === null || allMentors === void 0 ? void 0 : allMentors.count) !== null && _b !== void 0 ? _b : 0;
225231
+ return (_c = globalMemories === null || globalMemories === void 0 ? void 0 : globalMemories.count) !== null && _c !== void 0 ? _c : 0;
225232
+ }, [isMentorScope, isAllMentorsScope, mentorList, allMentors, globalMemories]);
225233
+ // Only the agent scope has an unpaginated source to aggregate over. The
225234
+ // category filter is applied client-side here because the grouped endpoint
225235
+ // returns every category regardless.
225236
+ const aggregates = useMemo(() => {
225237
+ if (!isMentorScope || !mentorGrouped)
225238
+ return null;
225239
+ const groups = categoryFilter === ALL_CATEGORIES
225240
+ ? mentorGrouped
225241
+ : mentorGrouped.filter((group) => group.category.slug === categoryFilter);
225242
+ const learners = new Set();
225243
+ let autoCaptured = 0;
225244
+ let totalMemories = 0;
225245
+ const categories = groups.map((group) => {
225246
+ group.memories.forEach((memory) => {
225247
+ learners.add(memory.email || memory.username);
225248
+ if (memory.is_auto_generated)
225249
+ autoCaptured += 1;
225250
+ });
225251
+ totalMemories += group.memories.length;
225252
+ return {
225253
+ slug: group.category.slug,
225254
+ name: group.category.name,
225255
+ count: group.memories.length,
225256
+ };
225257
+ });
225258
+ return {
225259
+ totalMemories,
225260
+ autoCaptured,
225261
+ learners: learners.size,
225262
+ categories: categories.sort((a, b) => b.count - a.count),
225263
+ };
225264
+ }, [isMentorScope, mentorGrouped, categoryFilter]);
225265
+ const error = isMentorScope ? mentorListError : isAllMentorsScope ? allMentorsError : globalError;
225266
+ const isLoading = isMentorScope
225267
+ ? isLoadingMentorList || isLoadingMentorGrouped
225268
+ : isAllMentorsScope
225269
+ ? isLoadingAllMentors
225270
+ : isLoadingGlobal;
225271
+ const isFetching = isMentorScope
225272
+ ? isFetchingMentorList
225273
+ : isAllMentorsScope
225274
+ ? isFetchingAllMentors
225275
+ : isFetchingGlobal;
225276
+ return {
225277
+ scope,
225278
+ setScope,
225279
+ availableScopes,
225280
+ searchedMentor,
225281
+ selectSearchedMentor,
225282
+ rows,
225283
+ aggregates,
225284
+ totalCount,
225285
+ categories: adminCategories !== null && adminCategories !== void 0 ? adminCategories : [],
225286
+ isLoading,
225287
+ isFetching,
225288
+ error,
225289
+ isForbidden: isForbiddenError(error),
225290
+ page,
225291
+ setPage,
225292
+ totalPages: Math.ceil(totalCount / MEMORY_PAGE_SIZE),
225293
+ pageSize: MEMORY_PAGE_SIZE,
225294
+ learnerFilter,
225295
+ setLearnerFilter,
225296
+ categoryFilter,
225297
+ setCategoryFilter,
225298
+ contentFilter,
225299
+ setContentFilter,
225300
+ dateRange,
225301
+ setDateRange,
225302
+ };
225303
+ };
225304
+
225305
+ const CELL = 'p-3 text-[#646464]';
225306
+ const HEAD = 'p-3 text-left text-sm whitespace-nowrap text-[#646464]';
225307
+ /**
225308
+ * Action items that share the scope dropdown. Radix rejects empty values and
225309
+ * matches the trigger label by value, so these are sentinels the change handler
225310
+ * intercepts rather than selectable scopes.
225311
+ */
225312
+ const SEARCH_AGENTS_ACTION = '__search-agents__';
225313
+ const CLEAR_AGENT_ACTION = '__clear-agent__';
225314
+ function MemoryDetailDialog({ memory, onClose, scope, }) {
225315
+ const t = useT();
225316
+ return (jsx(Dialog, { open: !!memory, onOpenChange: (open) => !open && onClose(), children: jsxs(DialogContent, { className: "max-w-lg", children: [jsx(DialogHeader, { children: jsx(DialogTitle, { children: t('analyticsAnalyticsMemoryStats.detailTitle') }) }), memory && (jsxs("div", { className: "space-y-4", children: [jsx("p", { className: "text-sm whitespace-pre-wrap text-gray-700", children: memory.content }), jsxs("dl", { className: "grid grid-cols-2 gap-3 border-t border-gray-100 pt-3 text-xs", children: [jsxs("div", { children: [jsx("dt", { className: "text-gray-500", children: t('analyticsAnalyticsMemoryStats.detailUser') }), jsx("dd", { className: "mt-0.5 font-medium break-all text-gray-800", children: memory.learner })] }), memory.categoryName && (jsxs("div", { children: [jsx("dt", { className: "text-gray-500", children: t('analyticsAnalyticsMemoryStats.detailCategory') }), jsx("dd", { className: "mt-0.5 font-medium text-gray-800", children: memory.categoryName })] })), scope === 'all-mentors' && (jsxs("div", { children: [jsx("dt", { className: "text-gray-500", children: t('analyticsAnalyticsMemoryStats.detailAgent') }), jsx("dd", { className: "mt-0.5 font-medium break-all text-gray-800", children: memory.mentorName || memory.mentorId || '—' })] })), jsxs("div", { children: [jsx("dt", { className: "text-gray-500", children: t('analyticsAnalyticsMemoryStats.detailSource') }), jsx("dd", { className: "mt-0.5 font-medium text-gray-800", children: memory.isAutoGenerated
225317
+ ? t('analyticsAnalyticsMemoryStats.sourceAuto')
225318
+ : t('analyticsAnalyticsMemoryStats.sourceManual') })] }), jsxs("div", { children: [jsx("dt", { className: "text-gray-500", children: t('analyticsAnalyticsMemoryStats.detailCaptured') }), jsx("dd", { className: "mt-0.5 font-medium text-gray-800", children: format$1(new Date(memory.createdAt), "MMM dd, yyyy 'at' h:mm a") })] }), memory.sourceSessionId && (jsxs("div", { className: "col-span-2", children: [jsx("dt", { className: "text-gray-500", children: t('analyticsAnalyticsMemoryStats.detailSession') }), jsx("dd", { className: "mt-0.5 font-mono text-[11px] break-all text-gray-800", children: memory.sourceSessionId })] }))] })] }))] }) }));
225319
+ }
225320
+ function AgentSearchDialog({ tenantKey, open, onClose, selectedMentorId, onSelect, }) {
225321
+ const t = useT();
225322
+ const [query, setQuery] = useState('');
225323
+ return (jsx(Dialog, { open: open, onOpenChange: (next) => !next && onClose(), children: jsxs(DialogContent, { className: "max-w-2xl", children: [jsx(DialogHeader, { children: jsx(DialogTitle, { children: t('analyticsAnalyticsMemoryStats.searchAgentsTitle') }) }), jsx(MentorSelectionGrid, { tenantKey: tenantKey, searchQuery: query, onSearchChange: setQuery, selectedMentorIds: selectedMentorId ? [selectedMentorId] : [], itemsPerPage: 6, minHeight: "240px", onMentorSelect: (mentor) => {
225324
+ if (!(mentor === null || mentor === void 0 ? void 0 : mentor.unique_id))
225325
+ return;
225326
+ onSelect({ id: mentor.unique_id, name: mentor.name });
225327
+ onClose();
225328
+ } })] }) }));
225329
+ }
225330
+ /**
225331
+ * Analytics "Memory" tab. Surfaces the memories memsearch captures while users
225332
+ * chat with agents, across three scopes: the selected agent, every agent in the
225333
+ * tenant, and global (agent-independent) memories. The scope dropdown also
225334
+ * offers an agent search, so any agent's memories can be pulled up without
225335
+ * leaving the tab.
225336
+ *
225337
+ * Hosts are expected to gate this behind `GET .../memsearch-status/`; the
225338
+ * component itself only handles the per-request permission failure (403).
225339
+ */
225340
+ function AnalyticsMemoryStats({ tenantKey, mentorId, userId, selectedMentorId, myMemory = false, }) {
225341
+ const t = useT();
225342
+ const [selectedMemory, setSelectedMemory] = useState(null);
225343
+ const [agentSearchOpen, setAgentSearchOpen] = useState(false);
225344
+ // The content search is committed on Enter/blur rather than per-keystroke so
225345
+ // we don't fire a request (and reset pagination) on every character typed.
225346
+ const [contentInput, setContentInput] = useState('');
225347
+ const { scope, setScope, availableScopes, searchedMentor, selectSearchedMentor, rows, aggregates, categories, isLoading, error, isForbidden, page, setPage, totalPages, learnerFilter, setLearnerFilter, categoryFilter, setCategoryFilter, setContentFilter, dateRange, setDateRange, } = useMemory({
225348
+ tenantKey,
225349
+ userId,
225350
+ mentorId: selectedMentorId || mentorId,
225351
+ myMemory,
225352
+ });
225353
+ const scopeLabels = {
225354
+ // A searched agent takes over the agent scope, so name it in the trigger.
225355
+ mentor: (searchedMentor === null || searchedMentor === void 0 ? void 0 : searchedMentor.name) || t('analyticsAnalyticsMemoryStats.scopeMentor'),
225356
+ 'all-mentors': t('analyticsAnalyticsMemoryStats.scopeAllMentors'),
225357
+ global: t('analyticsAnalyticsMemoryStats.scopeGlobal'),
225358
+ };
225359
+ const showCategoryColumn = scope !== 'global';
225360
+ const showAgentColumn = scope === 'all-mentors';
225361
+ // Only the agent-scoped endpoint filters by category, and the categories
225362
+ // themselves are that agent's — see `useMemory`.
225363
+ const showCategoryFilter = scope === 'mentor' && categories.length > 0;
225364
+ if (isForbidden) {
225365
+ return (jsx(Card, { className: "rounded-lg border border-gray-100 bg-white shadow-sm", children: jsx(CardContent, { className: "p-8 text-center", children: jsx("p", { className: "text-gray-500", children: t('analyticsAnalyticsMemoryStats.noPermission') }) }) }));
225366
+ }
225367
+ return (jsxs("div", { className: "space-y-6", children: [jsx("div", { className: "rounded-lg border border-[oklch(0.922_0_0)] bg-white p-4", children: jsxs("div", { className: "flex flex-col gap-3 lg:flex-row", children: [jsx("div", { className: "min-w-[160px]", children: jsxs(Select$1, { value: scope, onValueChange: (value) => {
225368
+ // The trailing items are actions, not scopes — the Select stays
225369
+ // on whatever scope is currently active.
225370
+ if (value === SEARCH_AGENTS_ACTION) {
225371
+ setAgentSearchOpen(true);
225372
+ return;
225373
+ }
225374
+ if (value === CLEAR_AGENT_ACTION) {
225375
+ selectSearchedMentor(null);
225376
+ return;
225377
+ }
225378
+ setScope(value);
225379
+ }, children: [jsx(SelectTrigger, { className: "h-9 w-full bg-white font-normal", "aria-label": t('analyticsAnalyticsMemoryStats.scopeLabel'), children: jsx(SelectValue, {}) }), jsxs(SelectContent, { children: [availableScopes.map((value) => (jsx(SelectItem, { value: value, children: scopeLabels[value] }, value))), jsx(SelectSeparator, {}), jsx(SelectItem, { value: SEARCH_AGENTS_ACTION, children: jsxs("span", { className: "flex items-center gap-2", children: [jsx(Search, { className: "h-3.5 w-3.5" }), t('analyticsAnalyticsMemoryStats.searchAgents')] }) }), searchedMentor && (jsx(SelectItem, { value: CLEAR_AGENT_ACTION, children: jsxs("span", { className: "flex items-center gap-2", children: [jsx(X$1, { className: "h-3.5 w-3.5" }), t('analyticsAnalyticsMemoryStats.clearAgentSearch')] }) }))] })] }) }), jsx("div", { className: "min-w-[200px] flex-1", children: jsx(UserFilterSelect, { tenantKey: tenantKey, currentUsername: userId, value: learnerFilter, onChange: setLearnerFilter }) }), scope === 'global' && (jsx("form", { className: "min-w-[180px] flex-1", onSubmit: (event) => {
225380
+ event.preventDefault();
225381
+ setContentFilter(contentInput.trim());
225382
+ }, children: jsx(Input, { value: contentInput, onChange: (event) => setContentInput(event.target.value), onBlur: () => setContentFilter(contentInput.trim()), placeholder: t('analyticsAnalyticsMemoryStats.contentPlaceholder'), "aria-label": t('analyticsAnalyticsMemoryStats.contentPlaceholder'), className: "h-9 bg-white" }) })), jsxs(Popover, { modal: true, children: [jsx(PopoverTrigger, { asChild: true, children: jsxs(Button$1, { variant: "outline", className: "flex h-9 w-full items-center gap-2 bg-white font-normal whitespace-nowrap lg:w-auto", children: [jsx(Calendar$1, { className: "h-4 w-4" }), (dateRange === null || dateRange === void 0 ? void 0 : dateRange.from) && (dateRange === null || dateRange === void 0 ? void 0 : dateRange.to)
225383
+ ? `${format$1(dateRange.from, 'MMM dd')} - ${format$1(dateRange.to, 'MMM dd')}`
225384
+ : t('analyticsAnalyticsMemoryStats.pickDateRange')] }) }), jsx(PopoverContent, { "data-iblai-dialog-interaction-layer": true, className: "z-[60] w-auto p-0", align: "start", children: jsx(Calendar, { mode: "range", selected: dateRange, onSelect: (range) => setDateRange(range ? { from: range.from, to: range.to } : undefined), numberOfMonths: 2 }) })] }), showCategoryFilter && (jsx("div", { className: "min-w-[160px]", children: jsxs(Select$1, { value: categoryFilter, onValueChange: setCategoryFilter, children: [jsx(SelectTrigger, { className: "h-9 w-full bg-white font-normal", "aria-label": t('analyticsAnalyticsMemoryStats.allCategories'), children: jsx(SelectValue, {}) }), jsxs(SelectContent, { children: [jsx(SelectItem, { value: ALL_CATEGORIES, children: t('analyticsAnalyticsMemoryStats.allCategories') }), categories.map((category) => (jsx(SelectItem, { value: category.slug, children: category.name }, category.slug)))] })] }) }))] }) }), aggregates && aggregates.categories.length > 0 && (jsxs("div", { className: "rounded-lg border border-[oklch(0.922_0_0)] bg-white p-4", children: [jsxs("h3", { className: "mb-4 flex items-center gap-2 text-sm font-medium text-[#484848]", children: [jsx(Brain, { className: "h-4 w-4 text-blue-600" }), t('analyticsAnalyticsMemoryStats.byCategory')] }), jsx("ul", { className: "space-y-3", children: aggregates.categories.map((category) => {
225385
+ const percent = aggregates.totalMemories
225386
+ ? Math.round((category.count / aggregates.totalMemories) * 100)
225387
+ : 0;
225388
+ return (jsxs("li", { children: [jsxs("div", { className: "mb-1 flex items-center justify-between text-sm text-[#646464]", children: [jsx("span", { children: category.name }), jsx("span", { className: "tabular-nums", children: t('analyticsAnalyticsMemoryStats.categoryCount', {
225389
+ count: category.count,
225390
+ percent,
225391
+ }) })] }), jsx("div", { className: "h-2 w-full overflow-hidden rounded-full bg-gray-100", children: jsx("div", { className: "h-full rounded-full bg-blue-600", style: { width: `${percent}%` } }) })] }, category.slug));
225392
+ }) })] })), jsx("div", { className: "overflow-hidden rounded-md border border-[oklch(0.922_0_0)] bg-white", children: jsx("div", { className: "overflow-x-auto", children: jsx("div", { className: "inline-block min-w-full align-middle", children: isLoading ? (jsx("div", { className: "flex w-full items-center justify-center py-10", children: jsx("div", { className: "h-6 w-6 animate-spin rounded-full border-2 border-blue-600 border-t-transparent" }) })) : error ? (jsx("div", { className: "py-8 text-center text-[#646464]", children: t('analyticsAnalyticsMemoryStats.loadError') })) : rows.length === 0 ? (jsx("div", { className: "h-[120px]", children: jsx(EmptyStats, { title: t('analyticsAnalyticsMemoryStats.noMemories') }) })) : (jsxs(Table, { className: "min-w-full", children: [jsx(TableHeader, { children: jsxs(TableRow, { className: "bg-muted/50 border-b border-[oklch(0.922_0_0)]", children: [jsx(TableHead, { className: HEAD, children: t('analyticsAnalyticsMemoryStats.colUser') }), jsx(TableHead, { className: HEAD, children: t('analyticsAnalyticsMemoryStats.colMemory') }), showAgentColumn && (jsx(TableHead, { className: HEAD, children: t('analyticsAnalyticsMemoryStats.colAgent') })), showCategoryColumn && (jsx(TableHead, { className: HEAD, children: t('analyticsAnalyticsMemoryStats.colCategory') })), jsx(TableHead, { className: HEAD, children: t('analyticsAnalyticsMemoryStats.colCaptured') })] }) }), jsx(TableBody, { children: rows.map((row) => {
225393
+ var _a;
225394
+ return (jsxs(TableRow, { onClick: () => setSelectedMemory(row), className: "cursor-pointer border-b border-[oklch(0.922_0_0)] last:border-0 hover:bg-gray-50", children: [jsx(TableCell, { className: cn(CELL, 'font-medium whitespace-nowrap'), children: row.learner }), jsx(TableCell, { className: cn(CELL, 'min-w-[280px]'), children: jsx("span", { className: "line-clamp-2", children: row.content }) }), showAgentColumn && (jsx(TableCell, { className: cn(CELL, 'whitespace-nowrap'), children: row.mentorName || row.mentorId || '—' })), showCategoryColumn && (jsx(TableCell, { className: cn(CELL, 'whitespace-nowrap'), children: row.categoryName ? (jsx("span", { className: "rounded-md bg-blue-100 px-2 py-1 text-xs text-blue-700", children: row.categoryName })) : ('—') })), jsx(TableCell, { className: cn(CELL, 'whitespace-nowrap'), children: formatDistanceToNow(new Date(row.createdAt), { addSuffix: true }) })] }, `${(_a = row.mentorId) !== null && _a !== void 0 ? _a : 'global'}-${row.id}`));
225395
+ }) })] })) }) }) }), jsx(IblPagination, { currentPage: page, totalPages: totalPages, onPageChange: setPage, disabled: isLoading }), jsx(MemoryDetailDialog, { memory: selectedMemory, scope: scope, onClose: () => setSelectedMemory(null) }), agentSearchOpen && (jsx(AgentSearchDialog, { open: true, tenantKey: tenantKey, selectedMentorId: searchedMentor === null || searchedMentor === void 0 ? void 0 : searchedMentor.id, onSelect: selectSearchedMentor, onClose: () => setAgentSearchOpen(false) }))] }));
225396
+ }
225397
+
224249
225398
  const SkeletonMultiplier = ({ Skeleton, multiplier }) => {
224250
225399
  return (jsx(Fragment$1, { children: Array.from({ length: multiplier }).map((_, index) => (jsx(Skeleton, {}, index))) }));
224251
225400
  };
@@ -227267,52 +228416,6 @@ function SignupButton({ authUrl, tenantKey, redirectTo, label = 'Sign Up', onCli
227267
228416
  }
227268
228417
  SignupButton.displayName = 'SignupButton';
227269
228418
 
227270
- /**
227271
- * Returns the canonical logo path and display name for an LLM provider.
227272
- * `logo` is a static-root path (e.g. `/llm-amazon-provider.png`); the package
227273
- * ships the canonical assets under `@iblai/web-containers/public/` — copy them
227274
- * into your app's static-root (`public/` for Next.js) so the paths resolve.
227275
- */
227276
- function getLLMProviderDetails(llmProvider, llmName) {
227277
- switch (llmProvider) {
227278
- case 'groq':
227279
- return { logo: '/llm-groq-provider.png', name: 'Groq' };
227280
- case 'azure_openai':
227281
- return { logo: '/llm-microsoft-provider.png', name: 'Microsoft' };
227282
- case 'openai':
227283
- if (llmName)
227284
- return { logo: '/llm-openai-provider.jpg', name: 'OpenAI' };
227285
- return { logo: '/llm-openai-provider-2.svg', name: 'OpenAI' };
227286
- case 'mistral':
227287
- return { logo: '/llm-mistral-provider.jpeg', name: 'Mistral' };
227288
- case 'google':
227289
- if (llmName)
227290
- return { logo: '/llm-gemini-provider.png', name: 'Google' };
227291
- return { logo: '/llm-google-provider.svg', name: 'Google' };
227292
- case 'llama':
227293
- return { logo: '/llm-llama-provider.jpeg', name: 'Meta' };
227294
- case 'perplexity':
227295
- return { logo: '/llm-perplexity-provider.webp', name: 'Perplexity' };
227296
- case 'deepseek':
227297
- return { logo: '/llm-deepseek-provider.png', name: 'DeepSeek' };
227298
- case 'xai':
227299
- return { logo: '/llm-xai-provider.jpg', name: 'xAI' };
227300
- case 'IBLChatAnthropic':
227301
- case 'anthropic':
227302
- return { logo: '/llm-claude-provider.png', name: 'Anthropic' };
227303
- case 'IBLChatNvidia':
227304
- case 'nvidia':
227305
- return { logo: '/llm-nvidia-provider.webp', name: 'NVIDIA' };
227306
- case 'bedrock':
227307
- case 'amazon-bedrock':
227308
- case 'amazon_bedrock':
227309
- case 'IBLChatBedrock':
227310
- return { logo: '/llm-amazon-provider.png', name: 'Amazon' };
227311
- default:
227312
- return { logo: '/llm-generic-provider.png', name: llmProvider };
227313
- }
227314
- }
227315
-
227316
228419
  function OverlayModal({ open, onClose, title, description, className, children, }) {
227317
228420
  const t = useT();
227318
228421
  const [mounted, setMounted] = useState(false);
@@ -229123,8 +230226,6 @@ function CreditBalance({ tenant, username, mainPlatformKey, currentUserEmail, re
229123
230226
  : t('creditBalance.manageBilling')] })) }))] }), jsx(AutoRechargeModal, { tenant: tenant, isOpen: isAutoRechargeModalOpen, onClose: () => setIsAutoRechargeModalOpen(false) }), jsx(AddCreditsModal, { tenant: tenant, isOpen: isAddCreditsModalOpen, onClose: () => setIsAddCreditsModalOpen(false) }), jsx(AppleRestrictionModal, { isOpen: isAppleRestrictionModalOpen, onClose: () => setIsAppleRestrictionModalOpen(false) })] }));
229124
230227
  }
229125
230228
 
229126
- function c(e,u,c){var i=this,a=useRef(null),o=useRef(0),f=useRef(null),l=useRef([]),v=useRef(),m=useRef(),d=useRef(e),g=useRef(true);d.current=e;var p="undefined"!=typeof window,w=!u&&0!==u&&p;if("function"!=typeof e)throw new TypeError("Expected a function");u=+u||0;var s=!!(c=c||{}).leading,x=!("trailing"in c)||!!c.trailing,h="maxWait"in c,y="debounceOnServer"in c&&!!c.debounceOnServer,F=h?Math.max(+c.maxWait||0,u):null;useEffect(function(){return g.current=true,function(){g.current=false;}},[]);var A=useMemo(function(){var r=function(r){var n=l.current,t=v.current;return l.current=v.current=null,o.current=r,m.current=d.current.apply(t,n)},n=function(r,n){w&&cancelAnimationFrame(f.current),f.current=w?requestAnimationFrame(r):setTimeout(r,n);},t=function(r){if(!g.current)return false;var n=r-a.current;return !a.current||n>=u||n<0||h&&r-o.current>=F},e=function(n){return f.current=null,x&&l.current?r(n):(l.current=v.current=null,m.current)},c=function r(){var c=Date.now();if(t(c))return e(c);if(g.current){var i=u-(c-a.current),f=h?Math.min(i,F-(c-o.current)):i;n(r,f);}},A=function(){if(p||y){var e=Date.now(),d=t(e);if(l.current=[].slice.call(arguments),v.current=i,a.current=e,d){if(!f.current&&g.current)return o.current=a.current,n(c,u),s?r(a.current):m.current;if(h)return n(c,u),r(a.current)}return f.current||n(c,u),m.current}};return A.cancel=function(){f.current&&(w?cancelAnimationFrame(f.current):clearTimeout(f.current)),o.current=0,l.current=a.current=v.current=f.current=null;},A.isPending=function(){return !!f.current},A.flush=function(){return f.current?e(Date.now()):m.current},A},[s,h,u,F,x,w,p,y]);return A}function i(r,n){return r===n}function a(n,t,a){var o=i,f=useRef(n),l=useState({})[1],v=c(useCallback(function(r){f.current=r,l({});},[l]),t,a),m=useRef(n);return o(m.current,n)||(v(n),m.current=n),[f.current,v]}
229127
-
229128
230229
  const DEFAULT_ITEMS_PER_PAGE = 10;
229129
230230
  const DEFAULT_DEBOUNCE_MS = 500;
229130
230231
  /** Manages the projects list: debounced search, pagination, and the paged query. */
@@ -231024,107 +232125,6 @@ var minimumMentorAlert = /*#__PURE__*/Object.freeze({
231024
232125
  MinimumMentorAlert: MinimumMentorAlert
231025
232126
  });
231026
232127
 
231027
- /**
231028
- * Core agent search hook — thin wrapper around `useGetAiSearchMentorsQuery`.
231029
- *
231030
- * This is the low-level building block. For a higher-level hook that manages
231031
- * search state, debounce, and pagination controls, use
231032
- * `useAgentSearchWithPagination`.
231033
- */
231034
- function useAgentSearch({ tenantKey, query, limit = 6, offset, starred, featured, category, subjects, llm, types, includeMainPublicMentors, orderDirection, skip = false, }) {
231035
- var _a, _b, _c;
231036
- const { data, isLoading, isFetching, refetch } = useGetAiSearchMentorsQuery({
231037
- platform_key: tenantKey,
231038
- query: query || undefined,
231039
- limit,
231040
- ...(offset !== undefined && { offset }),
231041
- ...(starred !== undefined && { starred }),
231042
- ...(featured !== undefined && { featured }),
231043
- ...(category && { category }),
231044
- ...(subjects && { subjects }),
231045
- ...(llm && { llm }),
231046
- ...(types && { types }),
231047
- ...(includeMainPublicMentors !== undefined && {
231048
- include_main_public_mentors: includeMainPublicMentors,
231049
- }),
231050
- ...(orderDirection && { order_direction: orderDirection }),
231051
- }, { skip: skip || !tenantKey });
231052
- return {
231053
- agents: ((_a = data === null || data === void 0 ? void 0 : data.results) !== null && _a !== void 0 ? _a : []),
231054
- facets: data === null || data === void 0 ? void 0 : data.facets,
231055
- hasMore: !!(data === null || data === void 0 ? void 0 : data.next),
231056
- totalCount: (_b = data === null || data === void 0 ? void 0 : data.count) !== null && _b !== void 0 ? _b : 0,
231057
- totalPages: (_c = data === null || data === void 0 ? void 0 : data.total_pages) !== null && _c !== void 0 ? _c : 0,
231058
- isLoading,
231059
- isFetching,
231060
- refetch,
231061
- };
231062
- }
231063
-
231064
- /**
231065
- * Higher-level agent search hook that manages search state, debounce, and
231066
- * pagination controls on top of `useAgentSearch`.
231067
- *
231068
- * Use this for simple list/table views (MyMentorsModal, SettingsModal).
231069
- * For the full explore page with sections, use `useAgentSearch` directly.
231070
- */
231071
- function useAgentSearchWithPagination({ itemsPerPage = 6, paginationMode = 'paginated', debounceMs = 500, ...queryConfig }) {
231072
- const [searchQuery, setSearchQuery] = React__default.useState('');
231073
- const [debouncedQuery] = a(searchQuery, debounceMs);
231074
- const [currentPage, setCurrentPage] = React__default.useState(1);
231075
- const [infiniteLimit, setInfiniteLimit] = React__default.useState(itemsPerPage);
231076
- // Reset pagination when search changes
231077
- React__default.useEffect(() => {
231078
- setCurrentPage(1);
231079
- setInfiniteLimit(itemsPerPage);
231080
- }, [debouncedQuery, itemsPerPage]);
231081
- const isPaginated = paginationMode === 'paginated';
231082
- const result = useAgentSearch({
231083
- ...queryConfig,
231084
- query: debouncedQuery,
231085
- limit: isPaginated ? itemsPerPage : infiniteLimit,
231086
- offset: isPaginated ? (currentPage - 1) * itemsPerPage : undefined,
231087
- });
231088
- const totalPages = Math.ceil(result.totalCount / itemsPerPage);
231089
- const handlePageChange = React__default.useCallback((page) => {
231090
- setCurrentPage(page);
231091
- }, []);
231092
- const loadMore = React__default.useCallback(() => {
231093
- setInfiniteLimit((prev) => prev + itemsPerPage);
231094
- }, [itemsPerPage]);
231095
- return {
231096
- ...result,
231097
- searchQuery,
231098
- setSearchQuery,
231099
- debouncedQuery,
231100
- currentPage,
231101
- totalPages,
231102
- handlePageChange,
231103
- loadMore,
231104
- };
231105
- }
231106
-
231107
- function MentorSelectionGrid({ selectedMentorIds, onMentorSelect, searchQuery, onSearchChange, tenantKey, itemsPerPage = 8, showSearch = true, minHeight = '400px', }) {
231108
- const t = useT();
231109
- const { agents: mentors, isLoading: isMentorsLoading, isFetching: isMentorsFetching, currentPage, totalPages, setSearchQuery: setMentorSearch, handlePageChange, } = useAgentSearchWithPagination({ tenantKey, itemsPerPage });
231110
- // Update search query with debounce effect handled by the hook
231111
- React__default.useEffect(() => {
231112
- setMentorSearch(searchQuery);
231113
- }, [searchQuery]);
231114
- const isMentorSelected = (mentorId) => {
231115
- return selectedMentorIds.includes(mentorId);
231116
- };
231117
- return (jsxs("div", { className: "space-y-4", children: [showSearch && (jsxs("div", { className: "relative", children: [isMentorsFetching ? (jsx(Spinner, { className: "absolute top-1/2 left-3 h-4 w-4 -translate-y-1/2 transform text-gray-400" })) : (jsx(Search, { className: "absolute top-1/2 left-3 h-4 w-4 -translate-y-1/2 transform text-gray-400" })), jsx(Input, { placeholder: t('mentorsMentorSelectionGrid.searchAgentsPlaceholder'), value: searchQuery, onChange: (e) => onSearchChange(e.target.value), className: "h-10 border-gray-200 pl-10 focus:border-blue-500 focus:ring-0" })] })), jsxs("div", { className: "space-y-4", children: [jsx("div", { className: "grid max-h-96 auto-rows-min grid-cols-1 items-start gap-3 overflow-y-auto rounded-lg border border-gray-200 p-4 md:max-h-none md:grid-cols-2", style: { minHeight }, children: isMentorsLoading ? (jsx("div", { className: "col-span-full py-8 text-center text-gray-500", children: t('mentorsMentorSelectionGrid.loadingAgents') })) : mentors.length === 0 ? (jsx("div", { className: "col-span-full py-8 text-center text-gray-500", children: t('mentorsMentorSelectionGrid.noAgentsFound') })) : (mentors.map((mentor) => {
231118
- const isSelected = isMentorSelected(mentor.unique_id || '');
231119
- const isAlreadyAdded = selectedMentorIds.includes(mentor.unique_id || '');
231120
- return (jsxs("button", { onClick: () => onMentorSelect(mentor), className: `flex cursor-pointer items-center gap-3 rounded-lg border-2 p-3 transition-all ${isSelected
231121
- ? 'border-blue-500 bg-blue-50'
231122
- : isAlreadyAdded
231123
- ? 'bg-blue-25 border-blue-300'
231124
- : 'border-gray-200 hover:border-gray-300 hover:bg-gray-50'}`, children: [jsxs(Avatar, { className: "h-12 w-12 flex-shrink-0", children: [jsx(AvatarImage, { src: mentor.profile_image || '/placeholder.svg', alt: mentor.name }), jsx(AvatarFallback, { children: mentor.name.substring(0, 2) })] }), jsxs("div", { className: "flex min-w-0 flex-1 flex-col justify-start text-left", children: [jsx("h4", { className: "truncate text-sm font-medium text-gray-900", children: mentor.name }), jsx("p", { className: "line-clamp-2 text-xs text-gray-600", children: mentor.description })] }), isSelected && (jsx("div", { className: "flex-shrink-0", children: jsx("div", { className: "flex h-6 w-6 items-center justify-center rounded-full bg-blue-600", children: jsx(Check, { className: "h-4 w-4 text-white" }) }) })), isAlreadyAdded && !isSelected && (jsx("div", { className: "flex-shrink-0", children: jsx("div", { className: "flex h-6 w-6 items-center justify-center rounded-full bg-blue-400", children: jsx(Check, { className: "h-4 w-4 text-white" }) }) }))] }, mentor.unique_id));
231125
- })) }), jsx(IblPagination, { currentPage: currentPage, totalPages: totalPages, onPageChange: handlePageChange, disabled: isMentorsFetching || isMentorsLoading })] })] }));
231126
- }
231127
-
231128
232128
  function CreateProjectModal({ isOpen, onClose, tenantKey, username, navigateToMentorInProject, }) {
231129
232129
  const t = useT();
231130
232130
  const dispatch = useDispatch();
@@ -235121,5 +236121,5 @@ var trainOrDeleteModal = /*#__PURE__*/Object.freeze({
235121
236121
  TrainOrDeleteModal: TrainOrDeleteModal
235122
236122
  });
235123
236123
 
235124
- export { ACCESS_COURSE_LABEL, AccessTimeHeatmap, AccessiblePaginate, AddMentorToProjectModal, AddSkillDialog, Admin, AdvancedTab, AgentConfigPrompts, AgentSkills, AlertsTab, AnalyticsAuditLogStats, AnalyticsCourseDetail, AnalyticsCourses, AnalyticsFinancialStats, AnalyticsLayout, AnalyticsMonetizationStats, AnalyticsOverview, AnalyticsProgramDetail, AnalyticsPrograms, AnalyticsReportDownload, AnalyticsReports, AnalyticsSettingsProvider, AnalyticsTopicsStats, AnalyticsTranscriptsStats, AnalyticsUsersStats, AppleRestrictionModal, ApplyWizard, BUY_NOW_LABEL, BillingTab, CATALOGS, CREATE_AGENT_LABELS, CUA_DRIVER_REPO_URL, CUA_DRIVER_TAURI_COMMANDS, CUA_DRIVER_TAURI_EVENTS, CategorizedDropdownMenu, ChartCardWrapper, ChartFiltersProvider, ChartLoading, ChatContext, ChatPrivacyToggle, ChatProvider, CompanyDialog, ConnectorManagementDialog, CopyButtonIcon, CourseAccessGuard, CourseCardSkeleton, CourseContentLoading, CourseOutline, CourseOutlineContext, CourseOutlineDrawer, CreateAgentForm, CreateAgentModal, CreateProjectModal, CreateWorkflowModal, CredentialBox, CredentialMiniBoxSkeleton, CredentialsList, CreditBalance, CustomDateRangePicker, CustomTooltip, DEFAULT_COWORK_REQUIRED_SIZE_GB, DEFAULT_LOCALE, DefaultEmptyBox, DeleteProjectModal, DeleteWorkflowModal, DiscoverContentCard, DiscoverFacetsFilter, DiscoverFilterDrawer, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, ENROLL_NOW_COURSE_STARTING_SOON_LABEL, ENROLL_NOW_LABEL, EditAlertDialog, EducationBox, EducationDialog, EducationTab, EdxIframeContext, EmptyStats, ExperienceBox, ExperienceDialog, ExperienceTab, FacetFilterContext, Footer, GradebookTab, GroupsFilterDropdown, INVITATION_ONLY_LABEL, InstitutionDialog, IntegrationsTab, InviteUserContent, InviteUserDialog, InvitedUsersDialog, LOCAL_MODELS, Loader, LocalLLMTab, LocalModelsContent, LoginButton, MACOS_PERMISSIONS_COMMANDS, Markdown, MinimumMentorAlert, MonetizationTab, NotificationDisplay, NotificationDropdown, ONBOARDING_SECTORS, OnboardingShell, OnboardingWizard, PaywallModal, PlacementExam, PlacementExamsDropdown, PlatformNavbar, PlatformNavbarSearch, Profile, ProfileTimeChart, ProgressDots, ProjectActionButtons, ProjectFilesModal, ProjectInstructionsModal, ProjectLandingPage, ProjectMentorsList, ProjectsPage, REQUEST_ACCESS_COURSE_STARTING_SOON_LABEL, REQUEST_ACCESS_LABEL, RenameProjectModal, ResumeBox, ResumeTab, RichTextEditor, SUPPORTED_LOCALES, SandboxConfig, SearchableMultiSelect, SendNotificationDialog, SignupButton, SkeletonActivityStatBox, SkeletonAddSkillsLoading, SkeletonCreatePathwaySearchList, SkeletonDiscoverFilterBox, SkeletonEducationBox, SkeletonMultiplier, SkeletonPathwayBox, SkeletonProfileInfoCard, SkeletonSkillBox, SkillBox, SkillDetailModal, SkillLeaderboardChart, SkillsBox, SkillsList, SlashSkillPicker, Spinner, StatCard, StepHeader, TAURI_COMMANDS, TAURI_EVENTS, TenantSwitcher, TimeFilter, TimeTrackingProvider, TimedExam, ToolDialogs, TopBanner, UpgradePackageModal, UserAvatar, Version, WebContainersI18nProvider, WorkflowSidebar, addBookmarksTab, availablePlacementExams, findLastResumeBlock, findSequentialParent, flattenVerticalBlocks, getCatalog, getFirstAvailableUnit, getLocalLLMModel, getLocalLLMToolSupport, getNextUnitIframe, getOrg, getParentBlockById, getParentsInfosFromSublessonId, getPreviousUnitIframe, getRandomCourseImage, getSectorById, getTenant, getUnitToIframe, getUserId, getUserName, inBrowserPrint, inIframe, initialCuaDriverInstallState, initialModelDownloadState, isCoworkEnabled, isLocalLLMEnabled, isPlatformNavbarCreditBalanceVisible, isSlashCommandToken, isTauriApp, isValidLocale, components as markdownComponents, modelSupportsCowork, onboardingPrimaryButtonClass, onboardingSecondaryButtonClass, resolveCreateAgentLabels, sanitizeCss, setCoworkEnabled, setLocalLLMEnabled, setLocalLLMModel, setLocalLLMToolSupport, smallestCoworkModel, useAnalyticsSettings, useAuditLog, useCatalogSearch, useChartFilters, useChatPrivacy, useChatState, useCourseDetail, useCourseMetadata, useCourses, useCuaDriver, useDiscover, useEdxIframe, useFinancial, useIframeMessageHandler, useLocalStorage, useModelDownload, useMonetization, useOverview, useProfileActivityStats, useProfileCredentials, useProfilePathways, useProfilePrograms, useProfileSkills, useProfileTimeSpent, usePrograms, useReports, useSlashSkillPicker, useT, useTauri, useTimeTracking, useTopics, useTranscripts, useUserCourses, useUserMetadata, useUsers, useWebContainersI18n, useWebContainersLocale };
236124
+ export { ACCESS_COURSE_LABEL, ALL_CATEGORIES, AccessTimeHeatmap, AccessiblePaginate, AddMentorToProjectModal, AddSkillDialog, Admin, AdvancedTab, AgentConfigPrompts, AgentSkills, AlertsTab, AnalyticsAuditLogStats, AnalyticsCourseDetail, AnalyticsCourses, AnalyticsFinancialStats, AnalyticsLayout, AnalyticsMemoryStats, AnalyticsMonetizationStats, AnalyticsOverview, AnalyticsProgramDetail, AnalyticsPrograms, AnalyticsReportDownload, AnalyticsReports, AnalyticsSettingsProvider, AnalyticsTopicsStats, AnalyticsTranscriptsStats, AnalyticsUsersStats, AppleRestrictionModal, ApplyWizard, BUY_NOW_LABEL, BillingTab, CATALOGS, CREATE_AGENT_LABELS, CUA_DRIVER_REPO_URL, CUA_DRIVER_TAURI_COMMANDS, CUA_DRIVER_TAURI_EVENTS, CategorizedDropdownMenu, ChartCardWrapper, ChartFiltersProvider, ChartLoading, ChatContext, ChatPrivacyToggle, ChatProvider, CompanyDialog, ConnectorManagementDialog, CopyButtonIcon, CourseAccessGuard, CourseCardSkeleton, CourseContentLoading, CourseOutline, CourseOutlineContext, CourseOutlineDrawer, CreateAgentForm, CreateAgentModal, CreateProjectModal, CreateWorkflowModal, CredentialBox, CredentialMiniBoxSkeleton, CredentialsList, CreditBalance, CustomDateRangePicker, CustomTooltip, DEFAULT_COWORK_REQUIRED_SIZE_GB, DEFAULT_LOCALE, DefaultEmptyBox, DeleteProjectModal, DeleteWorkflowModal, DiscoverContentCard, DiscoverFacetsFilter, DiscoverFilterDrawer, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, ENROLL_NOW_COURSE_STARTING_SOON_LABEL, ENROLL_NOW_LABEL, EditAlertDialog, EducationBox, EducationDialog, EducationTab, EdxIframeContext, EmptyStats, ExperienceBox, ExperienceDialog, ExperienceTab, FacetFilterContext, Footer, GradebookTab, GroupsFilterDropdown, INVITATION_ONLY_LABEL, InstitutionDialog, IntegrationsTab, InviteUserContent, InviteUserDialog, InvitedUsersDialog, LOCAL_MODELS, Loader, LocalLLMTab, LocalModelsContent, LoginButton, MACOS_PERMISSIONS_COMMANDS, MEMORY_PAGE_SIZE, Markdown, MinimumMentorAlert, MonetizationTab, NotificationDisplay, NotificationDropdown, ONBOARDING_SECTORS, OnboardingShell, OnboardingWizard, PaywallModal, PlacementExam, PlacementExamsDropdown, PlatformNavbar, PlatformNavbarSearch, Profile, ProfileTimeChart, ProgressDots, ProjectActionButtons, ProjectFilesModal, ProjectInstructionsModal, ProjectLandingPage, ProjectMentorsList, ProjectsPage, REQUEST_ACCESS_COURSE_STARTING_SOON_LABEL, REQUEST_ACCESS_LABEL, RenameProjectModal, ResumeBox, ResumeTab, RichTextEditor, SUPPORTED_LOCALES, SandboxConfig, SearchableMultiSelect, SendNotificationDialog, SignupButton, SkeletonActivityStatBox, SkeletonAddSkillsLoading, SkeletonCreatePathwaySearchList, SkeletonDiscoverFilterBox, SkeletonEducationBox, SkeletonMultiplier, SkeletonPathwayBox, SkeletonProfileInfoCard, SkeletonSkillBox, SkillBox, SkillDetailModal, SkillLeaderboardChart, SkillsBox, SkillsList, SlashSkillPicker, Spinner, StatCard, StepHeader, TAURI_COMMANDS, TAURI_EVENTS, TenantSwitcher, TimeFilter, TimeTrackingProvider, TimedExam, ToolDialogs, TopBanner, UpgradePackageModal, UserAvatar, Version, WebContainersI18nProvider, WorkflowSidebar, addBookmarksTab, availablePlacementExams, findLastResumeBlock, findSequentialParent, flattenVerticalBlocks, getCatalog, getFirstAvailableUnit, getLocalLLMModel, getLocalLLMToolSupport, getNextUnitIframe, getOrg, getParentBlockById, getParentsInfosFromSublessonId, getPreviousUnitIframe, getRandomCourseImage, getSectorById, getTenant, getUnitToIframe, getUserId, getUserName, inBrowserPrint, inIframe, initialCuaDriverInstallState, initialModelDownloadState, isCoworkEnabled, isLocalLLMEnabled, isPlatformNavbarCreditBalanceVisible, isSlashCommandToken, isTauriApp, isValidLocale, components as markdownComponents, modelSupportsCowork, onboardingPrimaryButtonClass, onboardingSecondaryButtonClass, resolveCreateAgentLabels, sanitizeCss, setCoworkEnabled, setLocalLLMEnabled, setLocalLLMModel, setLocalLLMToolSupport, smallestCoworkModel, useAnalyticsSettings, useAuditLog, useCatalogSearch, useChartFilters, useChatPrivacy, useChatState, useCourseDetail, useCourseMetadata, useCourses, useCuaDriver, useDiscover, useEdxIframe, useFinancial, useIframeMessageHandler, useLocalStorage, useMemory, useModelDownload, useMonetization, useOverview, useProfileActivityStats, useProfileCredentials, useProfilePathways, useProfilePrograms, useProfileSkills, useProfileTimeSpent, usePrograms, useReports, useSlashSkillPicker, useT, useTauri, useTimeTracking, useTopics, useTranscripts, useUserCourses, useUserMetadata, useUsers, useWebContainersI18n, useWebContainersLocale };
235125
236125
  //# sourceMappingURL=index.esm.js.map