@iblai/iblai-js 2.5.0 → 2.5.5

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.
Files changed (33) hide show
  1. package/dist/data-layer/playwright/index.d.ts +4 -2
  2. package/dist/data-layer/playwright/lti-tab-helpers.d.ts +36 -1
  3. package/dist/data-layer/playwright/memory-admin-helpers.d.ts +153 -0
  4. package/dist/data-layer/playwright/memory-test-helpers.d.ts +8 -7
  5. package/dist/data-layer/playwright/voice-tab-helpers.d.ts +32 -0
  6. package/dist/playwright/index.cjs +550 -26
  7. package/dist/playwright/index.cjs.map +1 -1
  8. package/dist/playwright/index.d.ts +231 -10
  9. package/dist/playwright/index.esm.js +521 -27
  10. package/dist/playwright/index.esm.js.map +1 -1
  11. package/dist/playwright/playwright/index.d.ts +4 -2
  12. package/dist/playwright/playwright/lti-tab-helpers.d.ts +36 -1
  13. package/dist/playwright/playwright/memory-admin-helpers.d.ts +153 -0
  14. package/dist/playwright/playwright/memory-test-helpers.d.ts +8 -7
  15. package/dist/playwright/playwright/voice-tab-helpers.d.ts +32 -0
  16. package/dist/security/playwright/index.d.ts +4 -2
  17. package/dist/security/playwright/lti-tab-helpers.d.ts +36 -1
  18. package/dist/security/playwright/memory-admin-helpers.d.ts +153 -0
  19. package/dist/security/playwright/memory-test-helpers.d.ts +8 -7
  20. package/dist/security/playwright/voice-tab-helpers.d.ts +32 -0
  21. package/dist/web-containers/playwright/index.d.ts +4 -2
  22. package/dist/web-containers/playwright/lti-tab-helpers.d.ts +36 -1
  23. package/dist/web-containers/playwright/memory-admin-helpers.d.ts +153 -0
  24. package/dist/web-containers/playwright/memory-test-helpers.d.ts +8 -7
  25. package/dist/web-containers/playwright/voice-tab-helpers.d.ts +32 -0
  26. package/dist/web-containers/source/index.esm.js +12524 -11248
  27. package/dist/web-containers/source/next/index.esm.js +1740 -444
  28. package/dist/web-utils/playwright/index.d.ts +4 -2
  29. package/dist/web-utils/playwright/lti-tab-helpers.d.ts +36 -1
  30. package/dist/web-utils/playwright/memory-admin-helpers.d.ts +153 -0
  31. package/dist/web-utils/playwright/memory-test-helpers.d.ts +8 -7
  32. package/dist/web-utils/playwright/voice-tab-helpers.d.ts +32 -0
  33. package/package.json +4 -4
@@ -2,7 +2,7 @@ import { jsx, jsxs, Fragment as Fragment$1 } from 'react/jsx-runtime';
2
2
  import * as React from 'react';
3
3
  import React__default, { useState, useEffect, forwardRef, createElement as createElement$3, useLayoutEffect, createContext, useContext, useMemo, useReducer, useRef, useImperativeHandle, useCallback, isValidElement, Children, PureComponent, cloneElement, Component as Component$1, useId as useId$2, useDebugValue, lazy, Suspense } from 'react';
4
4
  import * as dataLayer from '@iblai/data-layer';
5
- import { 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, useGetAgentSpendCapQuery, useGetTenantSpendCapQuery, useListAgentUserSpendCapsQuery, useUpsertAgentSpendCapMutation, useDeleteAgentSpendCapMutation, useUpsertTenantSpendCapMutation, useDeleteTenantSpendCapMutation, useUpsertUserSpendCapMutation, useDeleteUserSpendCapMutation, useGetFinancialStatsQuery, useGetMentorsQuery, useListAgentSpendCapsQuery, useGetCreditTransactionsQuery, 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, useStarMentorMutation, useUnstarMentorMutation, useLazyGetCourseMetaDataQuery, useLazyGetCourseCompletionOutlinesQuery, useLazyGetCourseEligibilityQuery, useLazyGetEdxSSOTokenQuery, useCreateCourseEnrollmentMutation, useCreateStripeCheckoutSessionMutation, useLazyGetCourseProgressQuery, useLazyGetCourseCompletionQuery, useUpdateExamAttemptMutation, useStartExamMutation, useLazyGetExamInfoQuery, useGetAgentSkillResourcesQuery, useCreateAgentSkillResourceMutation, useUpdateAgentSkillResourceMutation, useUploadAgentSkillResourceAssetMutation, useDeleteAgentSkillResourceMutation, useGetMentorSkillAssignmentsQuery, useGetAgentSkillsQuery, useCreateMentorSkillAssignmentMutation, useUpdateMentorSkillAssignmentMutation, useDeleteMentorSkillAssignmentMutation, useCreateAgentSkillMutation, useUpdateAgentSkillMutation, useDeleteAgentSkillMutation, filterSlashSkills, useGetMentorSkillAssignmentsInfiniteQuery, MENTOR_SKILL_ASSIGNMENTS_PAGE_SIZE, useUpdateUserProjectMutation, useGetTrainingDocumentsQuery, useGetVectorDocumentsQuery, useGetMentorMemoriesListQuery, useGetMemoryCategoriesAdminQuery, useDeleteMentorMemoryMutation, useUpdateMentorMemoryMutation, useCreateMentorMemoryMutation, useLazyGetConnectedServiceAuthUrlQuery, useCreateUserProjectMutation, useDeleteUserProjectMutation, useGetUserProjectDetailsQuery, useEditTrainingDocumentMutation, useAddTrainingDocumentMutation, useLazyGetCredentialsQuery, useGetMentorSettingsQuery, useEditMentorMutation, useUploadLightLogoMutation, useUploadDarkLogoMutation, useUpdatePlatformInfoMutation, LOGO_ENDPOINTS, useCreateEvalDatasetMutation, useAddEvalDatasetItemsMutation, useUploadEvalDatasetCsvMutation, useDeleteEvalDatasetItemMutation, useListEvalDatasetItemsQuery, evalTotalPages, useListEvalDatasetsQuery, useGetUserProjectsQuery, useCreateSessionIdMutation, useGetMentorCategoriesQuery, useGetTenantChatPrivacyConfigQuery as useGetTenantChatPrivacyConfigQuery$1, useGetCallConfigurationsQuery, useCreateCallConfigurationMutation, useUpdateCallConfigurationMutation, chatPrivacyApiSlice, useDeleteMentorMutation, useForkMentorMutation, useGetToolsQuery, useLazyGetMCPServersQuery, useOauthFindMutation, useLazyStartOAuthFlowQuery, useCreateMCPServerMutation, usePartialUpdateMCPServerMutation, useCreateMCPServerConnectionMutation, usePatchMCPServerConnectionMutation, useGetConnectedServicesQuery, useGetMCPServersQuery, useGetMCPServerConnectionsQuery, useUpdateMCPServerMutation, useDeleteMCPServerMutation, useEditMentorJsonMutation, useDisconnectServiceMutation, useGetPromptCategoriesQuery, PRIVACY_ACTIONS, PRIVACY_ENTITY_TYPES, useGetVoicesQuery, useGetVoiceQuery, isBaseAgentMentor, useGetGradeResultQuery, useOverrideGradeResultMutation, useGetChatHistoryFilterQuery, useListGradeResultsQuery, useGetMentorGraderConfigurationQuery, useListGraderCriteriaQuery, useCreateMentorGraderConfigurationMutation, useUpdateMentorGraderConfigurationMutation, useCreateGraderCriterionMutation, useUpdateGraderCriterionMutation, useDeleteGraderCriterionMutation, useGetSpendCapStatusQuery, useGetMentorPublicSettingsQuery, useGetChatHistoryQuery, useGetMentorSummariesQuery, useGetConversationMemoriesQuery, useGetSupportTicketsQuery, useGetSupportTicketMessagesQuery, useCreateSupportTicketMessageMutation, usePatchSupportTicketMutation, useCloseSupportTicketMutation, useCreateLtiMentorMutation, useUpdateLtiMentorMutation, useGetLtiMentorsQuery, useCreateLtiKeyMutation, useUpdateLtiKeyMutation, useDeleteLtiKeyMutation, useGetLtiKeysQuery, useCreateLtiToolMutation, useUpdateLtiToolMutation, useGetLtiToolsQuery, useGetPlatformInfoQuery, useCreatePromptMutation, useGetPromptsSearchQuery, useUpdatePromptMutation, useCreateRedirectTokenMutation, useGetShareableLinkQuery, useCreateShareableLinkMutation, useUpdateShareableLinkMutation, useCreateDisclaimerMutation, useUpdateDisclaimerMutation, useGetDisclaimersQuery, useUpdateRbacMentorAccessMutation, useGetRbacMentorAccessListQuery, useStartEvalRunMutation, useEvaluateEvalRunMutation, useGetEvalRunQuery, useDeleteEvalScoreMutation, useListEvalRunJudgesQuery, useCreateEvalScoreMutation, useDeleteEvalRunMutation, useExportEvalRunMutation, useListEvalRunsQuery, useLazyGetEvalRunQuery, evaluationsApiSlice, EVALUATIONS_TAGS, useGetPersonnalizedMentorsQuery, useCreateCallCredentialsMutation, useGetGuidedPromptsQuery, useUpdateChatSessionSharedMutation, useUpdateMessageFeedbackMutation, useLazyGetPromptsSearchQuery, useLazyGetGuidedPromptsQuery, useGetPublicMentorsQuery, useGetPeriodicAgentsQuery, useGetPeriodicAgentLogsListQuery, useCreatePeriodicAgentMutation, useDeletePeriodicAgentMutation, useDeletePromptMutation, useDeleteTrainingDocumentMutation, useGetTrainingDocumentRetrainScheduleQuery, useCreateTrainingDocumentRetrainScheduleMutation, useCreateMemoryCategoryMutation, useUpdateMemoryCategoryMutation, useDeleteMemoryCategoryMutation, useUpdateArtifactMutation, useLazyGetArtifactVersionQuery, useLazyListArtifactVersionsQuery, useSetCurrentVersionMutation, useListArtifactVersionsQuery, useLazyGetArtifactQuery, useLazyListArtifactsQuery, useEditSessionMutation } from '@iblai/data-layer';
5
+ import { 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, useUpdateGlobalMemoryMutation, useUpdateMentorMemoryMutation, useGetMemsearchStatusQuery, useGetUserMemorySettingsQuery, useUpdateUserMemorySettingsMutation, useGetGlobalMemoriesQuery, useGetAllMentorMemoriesQuery, useDeleteGlobalMemoryMutation, useDeleteMentorMemoryMutation, 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, useGetTenantMetadataQuery, useGetMentorsQuery, useUpdateTenantMetadataMutation, useLazyGetTenantMetadataQuery, useDeleteApiKeyMutation, useGetApiKeyQuery, useGetApiKeyFieldPermissionsQuery, useUpdateApiKeyMutation, useGetApiKeysQuery, unwrapApiTokenList, useCreateApiKeyMutation, useCreateLLMCredentialMutation, useGetCredentialsSchemaQuery, useGetMaskedLLMCredentialsQuery, useGetLlmsQuery, useDeleteIntegrationCredentialMutation, useDeleteCredentialMutation, useCreateIntegrationCredentialMutation, useGetIntegrationCredentialsSchemaQuery, useGetMaskedIntegrationCredentialsQuery, useGetAccountBillingInfoQuery, useUpdateAutoRechargeInfoMutation, useTriggerAutoRechargeMutation, useGetAgentSpendCapQuery, useGetTenantSpendCapQuery, useListAgentUserSpendCapsQuery, useUpsertAgentSpendCapMutation, useDeleteAgentSpendCapMutation, useUpsertTenantSpendCapMutation, useDeleteTenantSpendCapMutation, useUpsertUserSpendCapMutation, useDeleteUserSpendCapMutation, useGetFinancialStatsQuery, useListAgentSpendCapsQuery, useGetCreditTransactionsQuery, useCreateStripeCustomerPortalMutation, useSetPlatformConfigurationsMutation, useGetPlatformConfigurationsQuery, useUpdatePlatformMembershipMutation, useGetPlatformMembershipQuery, useGetCustomDomainsQuery, useCreateCustomDomainMutation, useDeleteCustomDomainMutation, useGetStudentMentorCreationStatusQuery, useSetStudentMentorCreationStatusMutation, coreApiSlice, recommendationPromptTypeEnum, useGetRecommendedPromptsListQuery, useCreateRecommendedPromptMutation, useUpdateRecommendedPromptMutation, useDeleteRecommendedPromptMutation, useLazyGetPublicPlatformImageAssetFileUrlQuery, useCreatePlatformImageAssetMutation, useGetProviderConfigQuery, useCreateProviderConfigMutation, useDeleteProviderConfigMutation, useGetExternalMappingQuery, useGetCredentialsListQuery, useCreateExternalMappingMutation, useDeleteExternalMappingMutation, useGetMemsearchConfigQuery, useUpdateMemsearchConfigMutation, useGetStripeConnectStatusQuery, useStartStripeConnectOnboardingMutation, useLazyGetStripeConnectDashboardQuery, useGetAiSearchMentorsQuery, useListPaywallsQuery, useListPricesQuery, useCreatePriceMutation, useUpdatePriceMutation, useDeletePriceMutation, useGetPaywallConfigQuery, useEnablePaywallMutation, useUpdatePaywallMutation, useStarMentorMutation, useUnstarMentorMutation, useLazyGetCourseMetaDataQuery, useLazyGetCourseCompletionOutlinesQuery, useLazyGetCourseEligibilityQuery, useLazyGetEdxSSOTokenQuery, useCreateCourseEnrollmentMutation, useCreateStripeCheckoutSessionMutation, useLazyGetCourseProgressQuery, useLazyGetCourseCompletionQuery, useUpdateExamAttemptMutation, useStartExamMutation, useLazyGetExamInfoQuery, useGetAgentSkillResourcesQuery, useCreateAgentSkillResourceMutation, useUpdateAgentSkillResourceMutation, useUploadAgentSkillResourceAssetMutation, useDeleteAgentSkillResourceMutation, useGetMentorSkillAssignmentsQuery, useGetAgentSkillsQuery, useCreateMentorSkillAssignmentMutation, useUpdateMentorSkillAssignmentMutation, useDeleteMentorSkillAssignmentMutation, useCreateAgentSkillMutation, useUpdateAgentSkillMutation, useDeleteAgentSkillMutation, filterSlashSkills, useGetMentorSkillAssignmentsInfiniteQuery, MENTOR_SKILL_ASSIGNMENTS_PAGE_SIZE, useUpdateUserProjectMutation, useGetTrainingDocumentsQuery, useGetVectorDocumentsQuery, useGetMentorMemoriesListQuery, useGetMemoryCategoriesAdminQuery, useCreateMentorMemoryMutation, useLazyGetConnectedServiceAuthUrlQuery, useCreateUserProjectMutation, useDeleteUserProjectMutation, useGetUserProjectDetailsQuery, useEditTrainingDocumentMutation, useAddTrainingDocumentMutation, useLazyGetCredentialsQuery, useGetMentorSettingsQuery, useEditMentorMutation, useUploadLightLogoMutation, useUploadDarkLogoMutation, useUpdatePlatformInfoMutation, LOGO_ENDPOINTS, useCreateEvalDatasetMutation, useAddEvalDatasetItemsMutation, useUploadEvalDatasetCsvMutation, useDeleteEvalDatasetItemMutation, useListEvalDatasetItemsQuery, evalTotalPages, useListEvalDatasetsQuery, useGetUserProjectsQuery, useCreateSessionIdMutation, useGetMentorCategoriesQuery, useGetTenantChatPrivacyConfigQuery as useGetTenantChatPrivacyConfigQuery$1, useGetCallConfigurationsQuery, useCreateCallConfigurationMutation, useUpdateCallConfigurationMutation, chatPrivacyApiSlice, useDeleteMentorMutation, useForkMentorMutation, useGetToolsQuery, useLazyGetMCPServersQuery, useOauthFindMutation, useLazyStartOAuthFlowQuery, useCreateMCPServerMutation, usePartialUpdateMCPServerMutation, useCreateMCPServerConnectionMutation, usePatchMCPServerConnectionMutation, useGetConnectedServicesQuery, useGetMCPServersQuery, useGetMCPServerConnectionsQuery, useUpdateMCPServerMutation, useDeleteMCPServerMutation, useEditMentorJsonMutation, useDisconnectServiceMutation, useGetPromptCategoriesQuery, PRIVACY_ACTIONS, PRIVACY_ENTITY_TYPES, useGetVoicesQuery, useGetVoiceQuery, isBaseAgentMentor, useGetGradeResultQuery, useOverrideGradeResultMutation, useGetChatHistoryFilterQuery, useListGradeResultsQuery, useGetMentorGraderConfigurationQuery, useListGraderCriteriaQuery, useCreateMentorGraderConfigurationMutation, useUpdateMentorGraderConfigurationMutation, useCreateGraderCriterionMutation, useUpdateGraderCriterionMutation, useDeleteGraderCriterionMutation, useGetSpendCapStatusQuery, useGetMentorPublicSettingsQuery, useGetChatHistoryQuery, useGetMentorSummariesQuery, useGetConversationMemoriesQuery, useGetSupportTicketsQuery, useGetSupportTicketMessagesQuery, useCreateSupportTicketMessageMutation, usePatchSupportTicketMutation, useCloseSupportTicketMutation, useCreateLtiMentorMutation, useUpdateLtiMentorMutation, useGetLtiMentorsQuery, useDeleteLtiMentorMutation, useCreateLtiKeyMutation, useUpdateLtiKeyMutation, useDeleteLtiKeyMutation, useGetLtiKeysQuery, useCreateLtiToolMutation, useUpdateLtiToolMutation, useGetLtiToolsQuery, useGetPlatformInfoQuery, useCreatePromptMutation, useGetPromptsSearchQuery, useUpdatePromptMutation, useCreateRedirectTokenMutation, useGetShareableLinkQuery, useCreateShareableLinkMutation, useUpdateShareableLinkMutation, useCreateDisclaimerMutation, useUpdateDisclaimerMutation, useGetDisclaimersQuery, useUpdateRbacMentorAccessMutation, useGetRbacMentorAccessListQuery, useStartEvalRunMutation, useEvaluateEvalRunMutation, useGetEvalRunQuery, useDeleteEvalScoreMutation, useListEvalRunJudgesQuery, useCreateEvalScoreMutation, useDeleteEvalRunMutation, useExportEvalRunMutation, useListEvalRunsQuery, useLazyGetEvalRunQuery, evaluationsApiSlice, EVALUATIONS_TAGS, useGetPersonnalizedMentorsQuery, useCreateCallCredentialsMutation, useGetGuidedPromptsQuery, useUpdateChatSessionSharedMutation, useUpdateMessageFeedbackMutation, useLazyGetPromptsSearchQuery, useLazyGetGuidedPromptsQuery, useGetPublicMentorsQuery, useGetPeriodicAgentsQuery, useGetPeriodicAgentLogsListQuery, useCreatePeriodicAgentMutation, useDeletePeriodicAgentMutation, useDeletePromptMutation, useDeleteTrainingDocumentMutation, useGetTrainingDocumentRetrainScheduleQuery, useCreateTrainingDocumentRetrainScheduleMutation, useCreateMemoryCategoryMutation, useUpdateMemoryCategoryMutation, useDeleteMemoryCategoryMutation, useUpdateArtifactMutation, useLazyGetArtifactVersionQuery, useLazyListArtifactVersionsQuery, useSetCurrentVersionMutation, useListArtifactVersionsQuery, useLazyGetArtifactQuery, useLazyListArtifactsQuery, useEditSessionMutation } from '@iblai/data-layer';
6
6
  import { getInitials, useTenantMetadata, useCurrentTenant, selectRbacPermissions, isPureWatcher, WithPermissions, canWriteField, useStripeUpgrade, openExternalUrl, CHAT_AREA_SIZE, isAlphaNumeric32, checkRbacPermission, 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, removeFile, chatInputSliceActions, chatActions, WithFormPermissions, useTenantContext, TimeTracker, advancedTabsProperties, defaultSessionIds, pickWritableFields, ANONYMOUS_USERNAME as ANONYMOUS_USERNAME$3, redirectToAuthSpaJoinTenant, selectActiveTab, useAxdToken, useWelcomeMessage, markdownToPlainText, useCachedSessionId, use402ErrorCheck, selectTokenEnabled, selectToken, useServiceWorker, useUserAgreement, useAdvancedChat, sendMessageToParentWebsite, useMentorTools, useFileDragDrop, eventBus, RemoteEvents, selectEnableChatActionsPopup, advancedTabs, isInIframe, getAuthSpaJoinUrl, addMessage, clearFiles, MENTOR_VISIBILITY } from '@iblai/web-utils';
7
7
  import { useDispatch, useSelector } from 'react-redux';
8
8
  import { toast } from 'sonner';
@@ -99699,7 +99699,63 @@ var memoryMemoryTab$3 = {
99699
99699
  noMemoriesYet: "No memories yet. The AI will start remembering information from your conversations, or you can add memories manually.",
99700
99700
  noMemoriesYetPreview: "No memories yet. The AI has not recorded any information from this user's conversations.",
99701
99701
  stateEnabled: "enabled",
99702
- stateDisabled: "disabled"
99702
+ stateDisabled: "disabled",
99703
+ actionsMenuAriaLabel: "Memory actions: {excerpt}",
99704
+ editAction: "Edit",
99705
+ deleteAction: "Delete"
99706
+ };
99707
+ var memoryAdminTab$3 = {
99708
+ tabsAriaLabel: "Memory management sections",
99709
+ tabGlobalMemories: "Global",
99710
+ tabAgentMemories: "Agent",
99711
+ featureDisabled: "The memory feature is not enabled for this platform.",
99712
+ searchUsersPlaceholder: "Search Users",
99713
+ searchUsersAriaLabel: "Search Users",
99714
+ nameColumn: "Name",
99715
+ usernameColumn: "Username",
99716
+ emailColumn: "Email",
99717
+ agentColumn: "Agent",
99718
+ descriptionColumn: "Description",
99719
+ actionsColumn: "Actions",
99720
+ loading: "Loading...",
99721
+ noUsersFound: "No users found",
99722
+ noAgentsFound: "No agents found",
99723
+ forbidden: "You do not have permission to view this content.",
99724
+ viewMemoriesAriaLabel: "View memories for {name}",
99725
+ filter: {
99726
+ placeholder: "Search Agents…",
99727
+ typeToSearch: "Type at least 2 characters to search",
99728
+ searching: "Searching agents…",
99729
+ noResults: "No agents found",
99730
+ clear: "Clear Agent Filter"
99731
+ }
99732
+ };
99733
+ var memoryAdminUserMemoriesModal$3 = {
99734
+ title: "Global Memories",
99735
+ description: "View and manage this user's global memories.",
99736
+ addMemoryButton: "Add Memory",
99737
+ noMemories: "No memories saved for this user yet.",
99738
+ forbidden: "You do not have permission to view this user's memories.",
99739
+ failedToLoad: "Failed to load memories.",
99740
+ memoryDeleted: "Memory deleted",
99741
+ failedToDeleteMemory: "Failed to delete memory"
99742
+ };
99743
+ var memoryEditMemoryDialog$3 = {
99744
+ dialogTitle: "Edit Memory",
99745
+ dialogDescription: "Update the content of this memory",
99746
+ contentLabel: "Memory Content",
99747
+ validationMinLength: "Memory content must be at least 10 characters",
99748
+ inlineMinLength: "Must be at least 10 characters",
99749
+ toastUpdated: "Memory updated",
99750
+ toastDuplicate: "This memory already exists",
99751
+ toastForbidden: "You do not have permission to update this memory",
99752
+ toastFailed: "Failed to update memory",
99753
+ cancelButton: "Cancel",
99754
+ savingButton: "Saving...",
99755
+ saveButton: "Save Memory"
99756
+ };
99757
+ var memoryAdminAgentMemoriesModal$3 = {
99758
+ description: "View and manage memories saved for this agent."
99703
99759
  };
99704
99760
  var memoryTabAddMemoryModal$3 = {
99705
99761
  addMemory: "Add Memory",
@@ -100287,7 +100343,9 @@ var profileAccount$3 = {
100287
100343
  descSocial: "Connect and manage your social media accounts.",
100288
100344
  descSecurity: "Update your security settings and password.",
100289
100345
  tabBenchmarks: "Benchmarks",
100290
- descBenchmarks: "Build benchmark suites of test inputs to evaluate agents."
100346
+ descBenchmarks: "Build benchmark suites of test inputs to evaluate agents.",
100347
+ tabMemory: "Memory",
100348
+ descMemory: "Manage user global memories and agent memories."
100291
100349
  };
100292
100350
  var profileAddCreditsModal$3 = {
100293
100351
  title: "Add Credits",
@@ -100321,7 +100379,9 @@ var profileAdmin$3 = {
100321
100379
  teamsDescription: "A team is a curated set of users that you can share with others — e.g., grant another user permission to view the team's analytics or send notifications to them.",
100322
100380
  alertsDescription: "An alert pairs a team of watched users with one or more watchers who get notified when monitored events occur for a watched user. Each watcher subscribes to its own subset of events.",
100323
100381
  applicationsTab: "Applications",
100324
- applicationsTabDescription: "Review applications to your organization and edit the questions applicants answer when they apply."
100382
+ applicationsTabDescription: "Review applications to your organization and edit the questions applicants answer when they apply.",
100383
+ onboardingTab: "Onboarding",
100384
+ onboardingTabDescription: "Choose the agent every new member of this platform meets when they arrive, and how it introduces itself."
100325
100385
  };
100326
100386
  var profileAutoRechargeModal$3 = {
100327
100387
  title: "Manage Usage",
@@ -101867,8 +101927,8 @@ var tabsTeamsaccesspanel$3 = {
101867
101927
  errorDefault: "An error occurred while updating team access"
101868
101928
  };
101869
101929
  var tabsUserstab$3 = {
101870
- searchPlaceholder: "Search users",
101871
- searchAriaLabel: "Search users",
101930
+ searchPlaceholder: "Search Users",
101931
+ searchAriaLabel: "Search Users",
101872
101932
  inviteButton: "Invite",
101873
101933
  columnName: "Name",
101874
101934
  columnEmail: "Email",
@@ -102135,7 +102195,28 @@ var voiceTabLabels$3 = {
102135
102195
  stop: "Stop {voiceName} voice"
102136
102196
  },
102137
102197
  saveButton: "Save voice",
102138
- savingButton: "Saving…"
102198
+ savingButton: "Saving…",
102199
+ instructions: {
102200
+ label: "Voice Instructions",
102201
+ tooltip: "Describe how the agent should sound when it speaks — tone, pace, emotion, accent, energy. This changes the delivery, not what it says. Example: \"Speak slowly in a warm, encouraging tone, like a patient tutor.\"",
102202
+ placeholder: "e.g. Speak slowly in a warm, encouraging tone, like a patient tutor.",
102203
+ helpText: "Works with OpenAI voices (sent as speech instructions) and Google voices (sent as a synthesis prompt); other voices ignore it. Leave blank for the provider's default delivery — instructions switch OpenAI to a pricier, instruction-capable speech model.",
102204
+ presetsLabel: "Examples",
102205
+ presets: {
102206
+ warm: {
102207
+ label: "Warm and encouraging",
102208
+ text: "Speak slowly in a warm, encouraging tone, like a patient tutor."
102209
+ },
102210
+ calm: {
102211
+ label: "Calm and measured",
102212
+ text: "Speak in a calm, measured voice with a steady, unhurried pace."
102213
+ },
102214
+ energetic: {
102215
+ label: "Energetic and upbeat",
102216
+ text: "Speak with upbeat energy and enthusiasm, keeping a lively pace."
102217
+ }
102218
+ }
102219
+ }
102139
102220
  },
102140
102221
  callConfig: {
102141
102222
  title: "Voice call",
@@ -102385,6 +102466,18 @@ var ltiTabLabels$3 = {
102385
102466
  createButton: "Create LTI Link",
102386
102467
  empty: "No LTI link yet for this agent.",
102387
102468
  targetUriColumn: "TARGET LINK URI",
102469
+ statusColumn: "STATUS",
102470
+ status: {
102471
+ pending: "Pending",
102472
+ building: "Building",
102473
+ ready: "Ready",
102474
+ failed: "Failed"
102475
+ },
102476
+ failedHint: "Something went wrong while creating this link. Retry deletes it and creates it again.",
102477
+ refresh: "Refresh",
102478
+ retry: "Retry",
102479
+ retrying: "Retrying…",
102480
+ retryAria: "Retry {name}",
102388
102481
  editAria: "Edit {name}",
102389
102482
  copyTargetUri: "Copy target link URI",
102390
102483
  modal: {
@@ -102492,6 +102585,7 @@ var ltiTabLabels$3 = {
102492
102585
  },
102493
102586
  toasts: {
102494
102587
  linkCreated: "LTI link created successfully",
102588
+ linkCreationStarted: "LTI link creation started — this can take a few minutes",
102495
102589
  linkUpdated: "LTI link updated successfully",
102496
102590
  linkDeleted: "LTI link deleted successfully",
102497
102591
  linkError: "Something went wrong with the LTI link",
@@ -103298,6 +103392,41 @@ var analyticsUsePlatformAuditLabels$3 = {
103298
103392
  actionDelete: "Delete",
103299
103393
  actionAccess: "Access"
103300
103394
  };
103395
+ var onboardingUserOnboarding$3 = {
103396
+ defaultTitle: "Tell us about yourself",
103397
+ "continue": "Continue",
103398
+ submit: "Submit",
103399
+ back: "Back",
103400
+ saving: "Saving...",
103401
+ selectAnOption: "Select an option",
103402
+ couldNotSaveAnswers: "Could not save your answers. Please try again.",
103403
+ agentStepTitle: "Meet your assistant",
103404
+ agentStepSubtitle: "Ask your assistant anything to get started.",
103405
+ agentUnavailable: "Your assistant cannot be loaded right now. You can finish onboarding and come back to it later.",
103406
+ noOnboardingTitle: "Nothing to set up yet",
103407
+ noOnboardingBody: "Your organization has not set up an onboarding experience. Nothing is required from you — head on in.",
103408
+ continueToApp: "Continue"
103409
+ };
103410
+ var profileOnboardingTab$3 = {
103411
+ editorTitle: "User onboarding agent",
103412
+ editorDescription: "The agent every new member of this platform meets when they arrive.",
103413
+ loadError: "Could not load the onboarding settings.",
103414
+ save: "Save changes",
103415
+ saving: "Saving...",
103416
+ savedToast: "Onboarding agent saved",
103417
+ saveFailedToast: "Could not save the onboarding agent",
103418
+ unsavedChanges: "Unsaved changes",
103419
+ agentLabel: "Agent",
103420
+ searchAgents: "Search agents",
103421
+ loadingAgents: "Loading agents...",
103422
+ noAgents: "No agents found.",
103423
+ clearAgent: "Clear the selected agent",
103424
+ agentTitleLabel: "Heading",
103425
+ agentTitlePlaceholder: "Meet your assistant",
103426
+ agentDescriptionLabel: "Sub-heading",
103427
+ agentDescriptionPlaceholder: "Ask your assistant anything to get started.",
103428
+ noAgentHint: "With no agent set, members skip onboarding entirely."
103429
+ };
103301
103430
  var en = {
103302
103431
  accessTabAddAccess: accessTabAddAccess$3,
103303
103432
  accessTabLabels: accessTabLabels$3,
@@ -103425,6 +103554,10 @@ var en = {
103425
103554
  mcpTabConnectorManagementContent: mcpTabConnectorManagementContent$3,
103426
103555
  memoryAddMemoryDialog: memoryAddMemoryDialog$3,
103427
103556
  memoryMemoryTab: memoryMemoryTab$3,
103557
+ memoryAdminTab: memoryAdminTab$3,
103558
+ memoryAdminUserMemoriesModal: memoryAdminUserMemoriesModal$3,
103559
+ memoryEditMemoryDialog: memoryEditMemoryDialog$3,
103560
+ memoryAdminAgentMemoriesModal: memoryAdminAgentMemoriesModal$3,
103428
103561
  memoryTabAddMemoryModal: memoryTabAddMemoryModal$3,
103429
103562
  memoryTabDeleteMemoryModal: memoryTabDeleteMemoryModal$3,
103430
103563
  memoryTabEditMemoryModal: memoryTabEditMemoryModal$3,
@@ -103567,7 +103700,9 @@ var en = {
103567
103700
  analyticsAnalyticsPlatformAuditLog: analyticsAnalyticsPlatformAuditLog$3,
103568
103701
  analyticsPlatformAuditLogDetailSheet: analyticsPlatformAuditLogDetailSheet$3,
103569
103702
  analyticsAuditLogJsonView: analyticsAuditLogJsonView$3,
103570
- analyticsUsePlatformAuditLabels: analyticsUsePlatformAuditLabels$3
103703
+ analyticsUsePlatformAuditLabels: analyticsUsePlatformAuditLabels$3,
103704
+ onboardingUserOnboarding: onboardingUserOnboarding$3,
103705
+ profileOnboardingTab: profileOnboardingTab$3
103571
103706
  };
103572
103707
 
103573
103708
  var accessTabAddAccess$2 = {
@@ -106608,7 +106743,63 @@ var memoryMemoryTab$2 = {
106608
106743
  noMemoriesYet: "Aucun souvenir pour l'instant. L'IA commencera à mémoriser des informations de vos conversations, ou vous pouvez ajouter des souvenirs manuellement.",
106609
106744
  noMemoriesYetPreview: "Aucun souvenir pour l'instant. L'IA n'a enregistré aucune information des conversations de cet utilisateur.",
106610
106745
  stateEnabled: "activée",
106611
- stateDisabled: "désactivée"
106746
+ stateDisabled: "désactivée",
106747
+ actionsMenuAriaLabel: "Actions de la mémoire : {excerpt}",
106748
+ editAction: "Modifier",
106749
+ deleteAction: "Supprimer"
106750
+ };
106751
+ var memoryAdminTab$2 = {
106752
+ tabsAriaLabel: "Sections de gestion des mémoires",
106753
+ tabGlobalMemories: "Global",
106754
+ tabAgentMemories: "Agent",
106755
+ featureDisabled: "La fonctionnalité de mémoire n'est pas activée pour cette plateforme.",
106756
+ searchUsersPlaceholder: "Rechercher des utilisateurs",
106757
+ searchUsersAriaLabel: "Rechercher des utilisateurs",
106758
+ nameColumn: "Nom",
106759
+ usernameColumn: "Nom d'utilisateur",
106760
+ emailColumn: "E-mail",
106761
+ agentColumn: "Agent",
106762
+ descriptionColumn: "Description",
106763
+ actionsColumn: "Actions",
106764
+ loading: "Chargement...",
106765
+ noUsersFound: "Aucun utilisateur trouvé",
106766
+ noAgentsFound: "Aucun agent trouvé",
106767
+ forbidden: "Vous n'avez pas l'autorisation de voir ce contenu.",
106768
+ viewMemoriesAriaLabel: "Voir les mémoires de {name}",
106769
+ filter: {
106770
+ placeholder: "Rechercher des agents…",
106771
+ typeToSearch: "Saisissez au moins 2 caractères pour rechercher",
106772
+ searching: "Recherche d'agents…",
106773
+ noResults: "Aucun agent trouvé",
106774
+ clear: "Effacer le filtre d'agent"
106775
+ }
106776
+ };
106777
+ var memoryAdminUserMemoriesModal$2 = {
106778
+ title: "Mémoires globales",
106779
+ description: "Voir et gérer les mémoires globales de cet utilisateur.",
106780
+ addMemoryButton: "Ajouter une mémoire",
106781
+ noMemories: "Aucune mémoire enregistrée pour cet utilisateur pour l'instant.",
106782
+ forbidden: "Vous n'avez pas l'autorisation de voir les mémoires de cet utilisateur.",
106783
+ failedToLoad: "Échec du chargement des mémoires.",
106784
+ memoryDeleted: "Mémoire supprimée",
106785
+ failedToDeleteMemory: "Échec de la suppression de la mémoire"
106786
+ };
106787
+ var memoryEditMemoryDialog$2 = {
106788
+ dialogTitle: "Modifier la mémoire",
106789
+ dialogDescription: "Mettez à jour le contenu de cette mémoire",
106790
+ contentLabel: "Contenu de la mémoire",
106791
+ validationMinLength: "Le contenu de la mémoire doit comporter au moins 10 caractères",
106792
+ inlineMinLength: "Doit comporter au moins 10 caractères",
106793
+ toastUpdated: "Mémoire mise à jour",
106794
+ toastDuplicate: "Cette mémoire existe déjà",
106795
+ toastForbidden: "Vous n'avez pas l'autorisation de mettre à jour cette mémoire",
106796
+ toastFailed: "Échec de la mise à jour de la mémoire",
106797
+ cancelButton: "Annuler",
106798
+ savingButton: "Enregistrement...",
106799
+ saveButton: "Enregistrer la mémoire"
106800
+ };
106801
+ var memoryAdminAgentMemoriesModal$2 = {
106802
+ description: "Voir et gérer les mémoires enregistrées pour cet agent."
106612
106803
  };
106613
106804
  var memoryTabAddMemoryModal$2 = {
106614
106805
  addMemory: "Ajouter un souvenir",
@@ -107196,7 +107387,9 @@ var profileAccount$2 = {
107196
107387
  descSocial: "Connecter et gérer vos comptes de réseaux sociaux.",
107197
107388
  descSecurity: "Mettre à jour vos paramètres de sécurité et votre mot de passe.",
107198
107389
  tabBenchmarks: "Benchmarks",
107199
- descBenchmarks: "Créez des suites de benchmarks d'entrées de test pour évaluer les agents."
107390
+ descBenchmarks: "Créez des suites de benchmarks d'entrées de test pour évaluer les agents.",
107391
+ tabMemory: "Mémoire",
107392
+ descMemory: "Gérez les mémoires globales des utilisateurs et les mémoires des agents."
107200
107393
  };
107201
107394
  var profileAddCreditsModal$2 = {
107202
107395
  title: "Ajouter des crédits",
@@ -107230,7 +107423,9 @@ var profileAdmin$2 = {
107230
107423
  teamsDescription: "Une équipe est un ensemble organisé d'utilisateurs que vous pouvez partager avec d'autres — par exemple, accorder à un autre utilisateur la permission de consulter les analyses de l'équipe ou de lui envoyer des notifications.",
107231
107424
  alertsDescription: "Une alerte associe une équipe d'utilisateurs surveillés à un ou plusieurs observateurs qui sont notifiés lorsque des événements surveillés se produisent pour un utilisateur observé. Chaque observateur s'abonne à son propre sous-ensemble d'événements.",
107232
107425
  applicationsTab: "Candidatures",
107233
- applicationsTabDescription: "Consultez les candidatures à votre organisation et modifiez les questions auxquelles les candidats répondent lorsqu'ils postulent."
107426
+ applicationsTabDescription: "Consultez les candidatures à votre organisation et modifiez les questions auxquelles les candidats répondent lorsqu'ils postulent.",
107427
+ onboardingTab: "Intégration",
107428
+ onboardingTabDescription: "Choisissez l'agent que rencontre chaque nouveau membre de cette plateforme à son arrivée, ainsi que sa présentation."
107234
107429
  };
107235
107430
  var profileAutoRechargeModal$2 = {
107236
107431
  title: "Gérer l'utilisation",
@@ -109044,7 +109239,28 @@ var voiceTabLabels$2 = {
109044
109239
  stop: "Arrêter la voix {voiceName}"
109045
109240
  },
109046
109241
  saveButton: "Enregistrer la voix",
109047
- savingButton: "Enregistrement…"
109242
+ savingButton: "Enregistrement…",
109243
+ instructions: {
109244
+ label: "Instructions vocales",
109245
+ tooltip: "Décrivez comment l'agent doit sonner lorsqu'il parle : ton, rythme, émotion, accent, énergie. Cela modifie la manière de le dire, pas le contenu. Exemple : « Parle lentement, d'un ton chaleureux et encourageant, comme un tuteur patient. »",
109246
+ placeholder: "p. ex. Parle lentement, d'un ton chaleureux et encourageant, comme un tuteur patient.",
109247
+ helpText: "Fonctionne avec les voix OpenAI (envoyé comme instructions de parole) et Google (comme prompt de synthèse) ; les autres voix l'ignorent. Laissez vide pour la diction par défaut du fournisseur — avec des instructions, OpenAI utilise un modèle vocal plus coûteux compatible avec les instructions.",
109248
+ presetsLabel: "Exemples",
109249
+ presets: {
109250
+ warm: {
109251
+ label: "Chaleureux et encourageant",
109252
+ text: "Parle lentement, d'un ton chaleureux et encourageant, comme un tuteur patient."
109253
+ },
109254
+ calm: {
109255
+ label: "Calme et posé",
109256
+ text: "Parle d'une voix calme et posée, à un rythme régulier et sans hâte."
109257
+ },
109258
+ energetic: {
109259
+ label: "Énergique et enjoué",
109260
+ text: "Parle avec énergie et enthousiasme, en gardant un rythme entraînant."
109261
+ }
109262
+ }
109263
+ }
109048
109264
  },
109049
109265
  callConfig: {
109050
109266
  title: "Appel vocal",
@@ -109294,6 +109510,18 @@ var ltiTabLabels$2 = {
109294
109510
  createButton: "Créer un lien LTI",
109295
109511
  empty: "Aucun lien LTI pour cet agent pour le moment.",
109296
109512
  targetUriColumn: "URI DU LIEN CIBLE",
109513
+ statusColumn: "STATUT",
109514
+ status: {
109515
+ pending: "En attente",
109516
+ building: "Création",
109517
+ ready: "Prêt",
109518
+ failed: "Échec"
109519
+ },
109520
+ failedHint: "Une erreur s'est produite lors de la création de ce lien. Réessayer le supprime et le recrée.",
109521
+ refresh: "Actualiser",
109522
+ retry: "Réessayer",
109523
+ retrying: "Nouvelle tentative…",
109524
+ retryAria: "Réessayer {name}",
109297
109525
  editAria: "Modifier {name}",
109298
109526
  copyTargetUri: "Copier l'URI du lien cible",
109299
109527
  modal: {
@@ -109401,6 +109629,7 @@ var ltiTabLabels$2 = {
109401
109629
  },
109402
109630
  toasts: {
109403
109631
  linkCreated: "Lien LTI créé avec succès",
109632
+ linkCreationStarted: "Création du lien LTI lancée — cela peut prendre quelques minutes",
109404
109633
  linkUpdated: "Lien LTI mis à jour avec succès",
109405
109634
  linkDeleted: "Lien LTI supprimé avec succès",
109406
109635
  linkError: "Un problème est survenu avec le lien LTI",
@@ -110041,6 +110270,41 @@ var analyticsUsePlatformAuditLabels$2 = {
110041
110270
  actionDelete: "Supprimer",
110042
110271
  actionAccess: "Accéder"
110043
110272
  };
110273
+ var onboardingUserOnboarding$2 = {
110274
+ defaultTitle: "Parlez-nous de vous",
110275
+ "continue": "Continuer",
110276
+ submit: "Envoyer",
110277
+ back: "Retour",
110278
+ saving: "Enregistrement...",
110279
+ selectAnOption: "Sélectionnez une option",
110280
+ couldNotSaveAnswers: "Impossible d'enregistrer vos réponses. Veuillez réessayer.",
110281
+ agentStepTitle: "Rencontrez votre assistant",
110282
+ agentStepSubtitle: "Posez toutes vos questions à votre assistant pour commencer.",
110283
+ agentUnavailable: "Votre assistant ne peut pas être chargé pour le moment. Vous pouvez terminer l'intégration et y revenir plus tard.",
110284
+ noOnboardingTitle: "Rien à configurer pour l'instant",
110285
+ noOnboardingBody: "Votre organisation n'a pas encore configuré de parcours d'intégration. Rien ne vous est demandé — vous pouvez continuer.",
110286
+ continueToApp: "Continuer"
110287
+ };
110288
+ var profileOnboardingTab$2 = {
110289
+ editorTitle: "Agent d'intégration des utilisateurs",
110290
+ editorDescription: "L'agent que rencontre chaque nouveau membre de cette plateforme à son arrivée.",
110291
+ loadError: "Impossible de charger les paramètres d'intégration.",
110292
+ save: "Enregistrer les modifications",
110293
+ saving: "Enregistrement...",
110294
+ savedToast: "Agent d'intégration enregistré",
110295
+ saveFailedToast: "Impossible d'enregistrer l'agent d'intégration",
110296
+ unsavedChanges: "Modifications non enregistrées",
110297
+ agentLabel: "Agent",
110298
+ searchAgents: "Rechercher des agents",
110299
+ loadingAgents: "Chargement des agents...",
110300
+ noAgents: "Aucun agent trouvé.",
110301
+ clearAgent: "Effacer l'agent sélectionné",
110302
+ agentTitleLabel: "Titre",
110303
+ agentTitlePlaceholder: "Rencontrez votre assistant",
110304
+ agentDescriptionLabel: "Sous-titre",
110305
+ agentDescriptionPlaceholder: "Posez toutes vos questions à votre assistant pour commencer.",
110306
+ noAgentHint: "Sans agent défini, les membres ignorent complètement l'intégration."
110307
+ };
110044
110308
  var fr = {
110045
110309
  accessTabAddAccess: accessTabAddAccess$2,
110046
110310
  accessTabLabels: accessTabLabels$2,
@@ -110169,6 +110433,10 @@ var fr = {
110169
110433
  mcpTabConnectorManagementContent: mcpTabConnectorManagementContent$2,
110170
110434
  memoryAddMemoryDialog: memoryAddMemoryDialog$2,
110171
110435
  memoryMemoryTab: memoryMemoryTab$2,
110436
+ memoryAdminTab: memoryAdminTab$2,
110437
+ memoryAdminUserMemoriesModal: memoryAdminUserMemoriesModal$2,
110438
+ memoryEditMemoryDialog: memoryEditMemoryDialog$2,
110439
+ memoryAdminAgentMemoriesModal: memoryAdminAgentMemoriesModal$2,
110172
110440
  memoryTabAddMemoryModal: memoryTabAddMemoryModal$2,
110173
110441
  memoryTabDeleteMemoryModal: memoryTabDeleteMemoryModal$2,
110174
110442
  memoryTabEditMemoryModal: memoryTabEditMemoryModal$2,
@@ -110310,7 +110578,9 @@ var fr = {
110310
110578
  analyticsAnalyticsPlatformAuditLog: analyticsAnalyticsPlatformAuditLog$2,
110311
110579
  analyticsPlatformAuditLogDetailSheet: analyticsPlatformAuditLogDetailSheet$2,
110312
110580
  analyticsAuditLogJsonView: analyticsAuditLogJsonView$2,
110313
- analyticsUsePlatformAuditLabels: analyticsUsePlatformAuditLabels$2
110581
+ analyticsUsePlatformAuditLabels: analyticsUsePlatformAuditLabels$2,
110582
+ onboardingUserOnboarding: onboardingUserOnboarding$2,
110583
+ profileOnboardingTab: profileOnboardingTab$2
110314
110584
  };
110315
110585
 
110316
110586
  var accessTabAddAccess$1 = {
@@ -113351,7 +113621,63 @@ var memoryMemoryTab$1 = {
113351
113621
  noMemoriesYet: "Aún no hay memorias. La IA comenzará a recordar información de sus conversaciones, o puede añadir memorias manualmente.",
113352
113622
  noMemoriesYetPreview: "Aún no hay memorias. La IA no ha registrado información de las conversaciones de este usuario.",
113353
113623
  stateEnabled: "habilitada",
113354
- stateDisabled: "deshabilitada"
113624
+ stateDisabled: "deshabilitada",
113625
+ actionsMenuAriaLabel: "Acciones de memoria: {excerpt}",
113626
+ editAction: "Editar",
113627
+ deleteAction: "Eliminar"
113628
+ };
113629
+ var memoryAdminTab$1 = {
113630
+ tabsAriaLabel: "Secciones de gestión de memorias",
113631
+ tabGlobalMemories: "Global",
113632
+ tabAgentMemories: "Agente",
113633
+ featureDisabled: "La función de memoria no está habilitada para esta plataforma.",
113634
+ searchUsersPlaceholder: "Buscar usuarios",
113635
+ searchUsersAriaLabel: "Buscar usuarios",
113636
+ nameColumn: "Nombre",
113637
+ usernameColumn: "Nombre de usuario",
113638
+ emailColumn: "Correo electrónico",
113639
+ agentColumn: "Agente",
113640
+ descriptionColumn: "Descripción",
113641
+ actionsColumn: "Acciones",
113642
+ loading: "Cargando...",
113643
+ noUsersFound: "No se encontraron usuarios",
113644
+ noAgentsFound: "No se encontraron agentes",
113645
+ forbidden: "No tienes permiso para ver este contenido.",
113646
+ viewMemoriesAriaLabel: "Ver memorias de {name}",
113647
+ filter: {
113648
+ placeholder: "Buscar agentes…",
113649
+ typeToSearch: "Escribe al menos 2 caracteres para buscar",
113650
+ searching: "Buscando agentes…",
113651
+ noResults: "No se encontraron agentes",
113652
+ clear: "Quitar el filtro de agente"
113653
+ }
113654
+ };
113655
+ var memoryAdminUserMemoriesModal$1 = {
113656
+ title: "Memorias globales",
113657
+ description: "Ver y gestionar las memorias globales de este usuario.",
113658
+ addMemoryButton: "Agregar memoria",
113659
+ noMemories: "Este usuario aún no tiene memorias guardadas.",
113660
+ forbidden: "No tienes permiso para ver las memorias de este usuario.",
113661
+ failedToLoad: "Error al cargar las memorias.",
113662
+ memoryDeleted: "Memoria eliminada",
113663
+ failedToDeleteMemory: "Error al eliminar la memoria"
113664
+ };
113665
+ var memoryEditMemoryDialog$1 = {
113666
+ dialogTitle: "Editar memoria",
113667
+ dialogDescription: "Actualiza el contenido de esta memoria",
113668
+ contentLabel: "Contenido de la memoria",
113669
+ validationMinLength: "El contenido de la memoria debe tener al menos 10 caracteres",
113670
+ inlineMinLength: "Debe tener al menos 10 caracteres",
113671
+ toastUpdated: "Memoria actualizada",
113672
+ toastDuplicate: "Esta memoria ya existe",
113673
+ toastForbidden: "No tienes permiso para actualizar esta memoria",
113674
+ toastFailed: "Error al actualizar la memoria",
113675
+ cancelButton: "Cancelar",
113676
+ savingButton: "Guardando...",
113677
+ saveButton: "Guardar memoria"
113678
+ };
113679
+ var memoryAdminAgentMemoriesModal$1 = {
113680
+ description: "Ver y gestionar las memorias guardadas para este agente."
113355
113681
  };
113356
113682
  var memoryTabAddMemoryModal$1 = {
113357
113683
  addMemory: "Agregar memoria",
@@ -113939,7 +114265,9 @@ var profileAccount$1 = {
113939
114265
  descSocial: "Conectar y gestionar sus cuentas de redes sociales.",
113940
114266
  descSecurity: "Actualizar su configuración de seguridad y contraseña.",
113941
114267
  tabBenchmarks: "Benchmarks",
113942
- descBenchmarks: "Cree suites de benchmarks con entradas de prueba para evaluar agentes."
114268
+ descBenchmarks: "Cree suites de benchmarks con entradas de prueba para evaluar agentes.",
114269
+ tabMemory: "Memoria",
114270
+ descMemory: "Gestiona las memorias globales de los usuarios y las memorias de los agentes."
113943
114271
  };
113944
114272
  var profileAddCreditsModal$1 = {
113945
114273
  title: "Agregar créditos",
@@ -113973,7 +114301,9 @@ var profileAdmin$1 = {
113973
114301
  teamsDescription: "Un equipo es un conjunto organizado de usuarios que puedes compartir con otros — por ejemplo, otorgar a otro usuario permiso para ver las analíticas del equipo o enviarles notificaciones.",
113974
114302
  alertsDescription: "Una alerta empareja un equipo de usuarios vigilados con uno o más observadores que reciben notificaciones cuando ocurren eventos monitoreados para un usuario vigilado. Cada observador se suscribe a su propio subconjunto de eventos.",
113975
114303
  applicationsTab: "Solicitudes",
113976
- applicationsTabDescription: "Revise las solicitudes a su organización y edite las preguntas que responden los solicitantes cuando postulan."
114304
+ applicationsTabDescription: "Revise las solicitudes a su organización y edite las preguntas que responden los solicitantes cuando postulan.",
114305
+ onboardingTab: "Incorporación",
114306
+ onboardingTabDescription: "Elija el agente que conoce cada nuevo miembro de esta plataforma al llegar y cómo se presenta."
113977
114307
  };
113978
114308
  var profileAutoRechargeModal$1 = {
113979
114309
  title: "Gestionar uso",
@@ -115787,7 +116117,28 @@ var voiceTabLabels$1 = {
115787
116117
  stop: "Detener la voz {voiceName}"
115788
116118
  },
115789
116119
  saveButton: "Guardar voz",
115790
- savingButton: "Guardando…"
116120
+ savingButton: "Guardando…",
116121
+ instructions: {
116122
+ label: "Instrucciones de voz",
116123
+ tooltip: "Describe cómo debe sonar el agente al hablar: tono, ritmo, emoción, acento, energía. Cambia la forma de decirlo, no lo que dice. Ejemplo: \"Habla despacio, con un tono cálido y alentador, como un tutor paciente.\"",
116124
+ placeholder: "p. ej., Habla despacio, con un tono cálido y alentador, como un tutor paciente.",
116125
+ helpText: "Funciona con las voces de OpenAI (se envía como instrucciones de habla) y de Google (como prompt de síntesis); las demás voces lo ignoran. Déjalo en blanco para usar la entrega predeterminada del proveedor: con instrucciones, OpenAI usa un modelo de voz más caro compatible con instrucciones.",
116126
+ presetsLabel: "Ejemplos",
116127
+ presets: {
116128
+ warm: {
116129
+ label: "Cálido y alentador",
116130
+ text: "Habla despacio, con un tono cálido y alentador, como un tutor paciente."
116131
+ },
116132
+ calm: {
116133
+ label: "Tranquilo y pausado",
116134
+ text: "Habla con voz tranquila y pausada, a un ritmo constante y sin prisa."
116135
+ },
116136
+ energetic: {
116137
+ label: "Enérgico y animado",
116138
+ text: "Habla con energía y entusiasmo, manteniendo un ritmo animado."
116139
+ }
116140
+ }
116141
+ }
115791
116142
  },
115792
116143
  callConfig: {
115793
116144
  title: "Llamada de voz",
@@ -116037,6 +116388,18 @@ var ltiTabLabels$1 = {
116037
116388
  createButton: "Crear enlace LTI",
116038
116389
  empty: "Aún no hay ningún enlace LTI para este agente.",
116039
116390
  targetUriColumn: "URI DE ENLACE DESTINO",
116391
+ statusColumn: "ESTADO",
116392
+ status: {
116393
+ pending: "Pendiente",
116394
+ building: "Creando",
116395
+ ready: "Listo",
116396
+ failed: "Fallido"
116397
+ },
116398
+ failedHint: "Algo salió mal al crear este enlace. Reintentar lo elimina y lo crea de nuevo.",
116399
+ refresh: "Actualizar",
116400
+ retry: "Reintentar",
116401
+ retrying: "Reintentando…",
116402
+ retryAria: "Reintentar {name}",
116040
116403
  editAria: "Editar {name}",
116041
116404
  copyTargetUri: "Copiar URI de enlace destino",
116042
116405
  modal: {
@@ -116144,6 +116507,7 @@ var ltiTabLabels$1 = {
116144
116507
  },
116145
116508
  toasts: {
116146
116509
  linkCreated: "Enlace LTI creado correctamente",
116510
+ linkCreationStarted: "Creación del enlace LTI iniciada — puede tardar unos minutos",
116147
116511
  linkUpdated: "Enlace LTI actualizado correctamente",
116148
116512
  linkDeleted: "Enlace LTI eliminado correctamente",
116149
116513
  linkError: "Algo salió mal con el enlace LTI",
@@ -116784,6 +117148,41 @@ var analyticsUsePlatformAuditLabels$1 = {
116784
117148
  actionDelete: "Eliminar",
116785
117149
  actionAccess: "Acceder"
116786
117150
  };
117151
+ var onboardingUserOnboarding$1 = {
117152
+ defaultTitle: "Cuéntenos sobre usted",
117153
+ "continue": "Continuar",
117154
+ submit: "Enviar",
117155
+ back: "Atrás",
117156
+ saving: "Guardando...",
117157
+ selectAnOption: "Seleccione una opción",
117158
+ couldNotSaveAnswers: "No se pudieron guardar sus respuestas. Inténtelo de nuevo.",
117159
+ agentStepTitle: "Conozca a su asistente",
117160
+ agentStepSubtitle: "Pregúntele lo que quiera a su asistente para empezar.",
117161
+ agentUnavailable: "Su asistente no se puede cargar en este momento. Puede terminar la incorporación y volver más tarde.",
117162
+ noOnboardingTitle: "Todavía no hay nada que configurar",
117163
+ noOnboardingBody: "Su organización aún no ha configurado una experiencia de incorporación. No se le pide nada — puede continuar.",
117164
+ continueToApp: "Continuar"
117165
+ };
117166
+ var profileOnboardingTab$1 = {
117167
+ editorTitle: "Agente de incorporación de usuarios",
117168
+ editorDescription: "El agente que conoce cada nuevo miembro de esta plataforma al llegar.",
117169
+ loadError: "No se pudo cargar la configuración de incorporación.",
117170
+ save: "Guardar cambios",
117171
+ saving: "Guardando...",
117172
+ savedToast: "Agente de incorporación guardado",
117173
+ saveFailedToast: "No se pudo guardar el agente de incorporación",
117174
+ unsavedChanges: "Cambios sin guardar",
117175
+ agentLabel: "Agente",
117176
+ searchAgents: "Buscar agentes",
117177
+ loadingAgents: "Cargando agentes...",
117178
+ noAgents: "No se encontraron agentes.",
117179
+ clearAgent: "Quitar el agente seleccionado",
117180
+ agentTitleLabel: "Encabezado",
117181
+ agentTitlePlaceholder: "Conozca a su asistente",
117182
+ agentDescriptionLabel: "Subtítulo",
117183
+ agentDescriptionPlaceholder: "Pregúntele lo que quiera a su asistente para empezar.",
117184
+ noAgentHint: "Sin un agente definido, los miembros omiten por completo la incorporación."
117185
+ };
116787
117186
  var es = {
116788
117187
  accessTabAddAccess: accessTabAddAccess$1,
116789
117188
  accessTabLabels: accessTabLabels$1,
@@ -116912,6 +117311,10 @@ var es = {
116912
117311
  mcpTabConnectorManagementContent: mcpTabConnectorManagementContent$1,
116913
117312
  memoryAddMemoryDialog: memoryAddMemoryDialog$1,
116914
117313
  memoryMemoryTab: memoryMemoryTab$1,
117314
+ memoryAdminTab: memoryAdminTab$1,
117315
+ memoryAdminUserMemoriesModal: memoryAdminUserMemoriesModal$1,
117316
+ memoryEditMemoryDialog: memoryEditMemoryDialog$1,
117317
+ memoryAdminAgentMemoriesModal: memoryAdminAgentMemoriesModal$1,
116915
117318
  memoryTabAddMemoryModal: memoryTabAddMemoryModal$1,
116916
117319
  memoryTabDeleteMemoryModal: memoryTabDeleteMemoryModal$1,
116917
117320
  memoryTabEditMemoryModal: memoryTabEditMemoryModal$1,
@@ -117053,7 +117456,9 @@ var es = {
117053
117456
  analyticsAnalyticsPlatformAuditLog: analyticsAnalyticsPlatformAuditLog$1,
117054
117457
  analyticsPlatformAuditLogDetailSheet: analyticsPlatformAuditLogDetailSheet$1,
117055
117458
  analyticsAuditLogJsonView: analyticsAuditLogJsonView$1,
117056
- analyticsUsePlatformAuditLabels: analyticsUsePlatformAuditLabels$1
117459
+ analyticsUsePlatformAuditLabels: analyticsUsePlatformAuditLabels$1,
117460
+ onboardingUserOnboarding: onboardingUserOnboarding$1,
117461
+ profileOnboardingTab: profileOnboardingTab$1
117057
117462
  };
117058
117463
 
117059
117464
  var accessTabAddAccess = {
@@ -120094,7 +120499,63 @@ var memoryMemoryTab = {
120094
120499
  noMemoriesYet: "暂无记忆。AI 将开始记住您对话中的信息,或者您也可以手动添加记忆。",
120095
120500
  noMemoriesYetPreview: "暂无记忆。AI 尚未记录该用户对话中的任何信息。",
120096
120501
  stateEnabled: "已启用",
120097
- stateDisabled: "已禁用"
120502
+ stateDisabled: "已禁用",
120503
+ actionsMenuAriaLabel: "记忆操作:{excerpt}",
120504
+ editAction: "编辑",
120505
+ deleteAction: "删除"
120506
+ };
120507
+ var memoryAdminTab = {
120508
+ tabsAriaLabel: "记忆管理部分",
120509
+ tabGlobalMemories: "全局",
120510
+ tabAgentMemories: "智能体",
120511
+ featureDisabled: "此平台未启用记忆功能。",
120512
+ searchUsersPlaceholder: "搜索用户",
120513
+ searchUsersAriaLabel: "搜索用户",
120514
+ nameColumn: "姓名",
120515
+ usernameColumn: "用户名",
120516
+ emailColumn: "邮箱",
120517
+ agentColumn: "智能体",
120518
+ descriptionColumn: "描述",
120519
+ actionsColumn: "操作",
120520
+ loading: "加载中...",
120521
+ noUsersFound: "未找到用户",
120522
+ noAgentsFound: "未找到智能体",
120523
+ forbidden: "您没有权限查看此内容。",
120524
+ viewMemoriesAriaLabel: "查看 {name} 的记忆",
120525
+ filter: {
120526
+ placeholder: "搜索智能体…",
120527
+ typeToSearch: "请输入至少 2 个字符进行搜索",
120528
+ searching: "正在搜索智能体…",
120529
+ noResults: "未找到智能体",
120530
+ clear: "清除智能体筛选"
120531
+ }
120532
+ };
120533
+ var memoryAdminUserMemoriesModal = {
120534
+ title: "全局记忆",
120535
+ description: "查看和管理此用户的全局记忆。",
120536
+ addMemoryButton: "添加记忆",
120537
+ noMemories: "此用户尚未保存任何记忆。",
120538
+ forbidden: "您没有权限查看此用户的记忆。",
120539
+ failedToLoad: "加载记忆失败。",
120540
+ memoryDeleted: "记忆已删除",
120541
+ failedToDeleteMemory: "删除记忆失败"
120542
+ };
120543
+ var memoryEditMemoryDialog = {
120544
+ dialogTitle: "编辑记忆",
120545
+ dialogDescription: "更新此记忆的内容",
120546
+ contentLabel: "记忆内容",
120547
+ validationMinLength: "记忆内容至少需要 10 个字符",
120548
+ inlineMinLength: "至少需要 10 个字符",
120549
+ toastUpdated: "记忆已更新",
120550
+ toastDuplicate: "此记忆已存在",
120551
+ toastForbidden: "您没有权限更新此记忆",
120552
+ toastFailed: "更新记忆失败",
120553
+ cancelButton: "取消",
120554
+ savingButton: "保存中...",
120555
+ saveButton: "保存记忆"
120556
+ };
120557
+ var memoryAdminAgentMemoriesModal = {
120558
+ description: "查看和管理为此智能体保存的记忆。"
120098
120559
  };
120099
120560
  var memoryTabAddMemoryModal = {
120100
120561
  addMemory: "添加记忆",
@@ -120682,7 +121143,9 @@ var profileAccount = {
120682
121143
  descSocial: "连接和管理您的社交媒体账户。",
120683
121144
  descSecurity: "更新您的安全设置和密码。",
120684
121145
  tabBenchmarks: "基准测试",
120685
- descBenchmarks: "构建包含测试输入的基准测试套件,以评估智能体。"
121146
+ descBenchmarks: "构建包含测试输入的基准测试套件,以评估智能体。",
121147
+ tabMemory: "记忆",
121148
+ descMemory: "管理用户的全局记忆和智能体记忆。"
120686
121149
  };
120687
121150
  var profileAddCreditsModal = {
120688
121151
  title: "添加积分",
@@ -120716,7 +121179,9 @@ var profileAdmin = {
120716
121179
  teamsDescription: "团队是一组精心筛选的用户,可与他人共享 — 例如,授予另一个用户查看团队分析数据或向其发送通知的权限。",
120717
121180
  alertsDescription: "警报将一组被监控用户与一个或多个观察者配对,当被监控用户发生受监控事件时,观察者会收到通知。每位观察者可订阅自己感兴趣的事件子集。",
120718
121181
  applicationsTab: "申请",
120719
- applicationsTabDescription: "查看向贵组织提交的申请,并编辑申请人申请时回答的问题。"
121182
+ applicationsTabDescription: "查看向贵组织提交的申请,并编辑申请人申请时回答的问题。",
121183
+ onboardingTab: "引导",
121184
+ onboardingTabDescription: "选择本平台每位新成员进入时见到的智能体,以及它的介绍文案。"
120720
121185
  };
120721
121186
  var profileAutoRechargeModal = {
120722
121187
  title: "管理用量",
@@ -122530,7 +122995,28 @@ var voiceTabLabels = {
122530
122995
  stop: "停止 {voiceName} 声音"
122531
122996
  },
122532
122997
  saveButton: "保存声音",
122533
- savingButton: "保存中…"
122998
+ savingButton: "保存中…",
122999
+ instructions: {
123000
+ label: "语音指令",
123001
+ tooltip: "描述智能体说话时应有的声音效果:语气、语速、情感、口音、活力。它只改变表达方式,不改变说话内容。示例:\"语速放慢,用温暖、鼓励的语气,像一位耐心的导师。\"",
123002
+ placeholder: "例如:语速放慢,用温暖、鼓励的语气,像一位耐心的导师。",
123003
+ helpText: "适用于 OpenAI 声音(作为语音指令发送)和 Google 声音(作为合成提示发送);其他声音会忽略它。留空则使用提供商的默认表达方式——填写指令后,OpenAI 会切换到价格更高、支持指令的语音模型。",
123004
+ presetsLabel: "示例",
123005
+ presets: {
123006
+ warm: {
123007
+ label: "温暖鼓励",
123008
+ text: "语速放慢,用温暖、鼓励的语气,像一位耐心的导师。"
123009
+ },
123010
+ calm: {
123011
+ label: "平静从容",
123012
+ text: "用平静、从容的声音说话,保持稳定、不急不缓的节奏。"
123013
+ },
123014
+ energetic: {
123015
+ label: "活力四射",
123016
+ text: "用饱满的活力和热情说话,保持轻快的节奏。"
123017
+ }
123018
+ }
123019
+ }
122534
123020
  },
122535
123021
  callConfig: {
122536
123022
  title: "语音通话",
@@ -122780,6 +123266,18 @@ var ltiTabLabels = {
122780
123266
  createButton: "创建 LTI 链接",
122781
123267
  empty: "此智能体尚无 LTI 链接。",
122782
123268
  targetUriColumn: "目标链接 URI",
123269
+ statusColumn: "状态",
123270
+ status: {
123271
+ pending: "等待中",
123272
+ building: "创建中",
123273
+ ready: "就绪",
123274
+ failed: "失败"
123275
+ },
123276
+ failedHint: "创建此链接时出错。重试将删除该链接并重新创建。",
123277
+ refresh: "刷新",
123278
+ retry: "重试",
123279
+ retrying: "正在重试…",
123280
+ retryAria: "重试 {name}",
122783
123281
  editAria: "编辑 {name}",
122784
123282
  copyTargetUri: "复制目标链接 URI",
122785
123283
  modal: {
@@ -122887,6 +123385,7 @@ var ltiTabLabels = {
122887
123385
  },
122888
123386
  toasts: {
122889
123387
  linkCreated: "LTI 链接创建成功",
123388
+ linkCreationStarted: "LTI 链接创建已开始 — 可能需要几分钟",
122890
123389
  linkUpdated: "LTI 链接更新成功",
122891
123390
  linkDeleted: "LTI 链接删除成功",
122892
123391
  linkError: "LTI 链接出现问题",
@@ -123527,6 +124026,41 @@ var analyticsUsePlatformAuditLabels = {
123527
124026
  actionDelete: "删除",
123528
124027
  actionAccess: "访问"
123529
124028
  };
124029
+ var onboardingUserOnboarding = {
124030
+ defaultTitle: "介绍一下您自己",
124031
+ "continue": "继续",
124032
+ submit: "提交",
124033
+ back: "返回",
124034
+ saving: "保存中…",
124035
+ selectAnOption: "请选择一项",
124036
+ couldNotSaveAnswers: "无法保存您的答案,请重试。",
124037
+ agentStepTitle: "认识您的助手",
124038
+ agentStepSubtitle: "有任何问题都可以问您的助手。",
124039
+ agentUnavailable: "目前无法加载您的助手。您可以先完成引导,稍后再回来查看。",
124040
+ noOnboardingTitle: "暂时没有需要设置的内容",
124041
+ noOnboardingBody: "您的组织尚未配置引导流程。您无需进行任何操作,可以直接进入。",
124042
+ continueToApp: "继续"
124043
+ };
124044
+ var profileOnboardingTab = {
124045
+ editorTitle: "用户引导智能体",
124046
+ editorDescription: "本平台每位新成员进入时见到的智能体。",
124047
+ loadError: "无法加载引导设置。",
124048
+ save: "保存更改",
124049
+ saving: "保存中…",
124050
+ savedToast: "引导智能体已保存",
124051
+ saveFailedToast: "无法保存引导智能体",
124052
+ unsavedChanges: "有未保存的更改",
124053
+ agentLabel: "智能体",
124054
+ searchAgents: "搜索智能体",
124055
+ loadingAgents: "正在加载智能体…",
124056
+ noAgents: "未找到智能体。",
124057
+ clearAgent: "清除所选智能体",
124058
+ agentTitleLabel: "标题",
124059
+ agentTitlePlaceholder: "认识您的助手",
124060
+ agentDescriptionLabel: "副标题",
124061
+ agentDescriptionPlaceholder: "有任何问题都可以问您的助手。",
124062
+ noAgentHint: "未设置智能体时,成员将完全跳过引导流程。"
124063
+ };
123530
124064
  var zh = {
123531
124065
  accessTabAddAccess: accessTabAddAccess,
123532
124066
  accessTabLabels: accessTabLabels,
@@ -123655,6 +124189,10 @@ var zh = {
123655
124189
  mcpTabConnectorManagementContent: mcpTabConnectorManagementContent,
123656
124190
  memoryAddMemoryDialog: memoryAddMemoryDialog,
123657
124191
  memoryMemoryTab: memoryMemoryTab,
124192
+ memoryAdminTab: memoryAdminTab,
124193
+ memoryAdminUserMemoriesModal: memoryAdminUserMemoriesModal,
124194
+ memoryEditMemoryDialog: memoryEditMemoryDialog,
124195
+ memoryAdminAgentMemoriesModal: memoryAdminAgentMemoriesModal,
123658
124196
  memoryTabAddMemoryModal: memoryTabAddMemoryModal,
123659
124197
  memoryTabDeleteMemoryModal: memoryTabDeleteMemoryModal,
123660
124198
  memoryTabEditMemoryModal: memoryTabEditMemoryModal,
@@ -123796,7 +124334,9 @@ var zh = {
123796
124334
  analyticsAnalyticsPlatformAuditLog: analyticsAnalyticsPlatformAuditLog,
123797
124335
  analyticsPlatformAuditLogDetailSheet: analyticsPlatformAuditLogDetailSheet,
123798
124336
  analyticsAuditLogJsonView: analyticsAuditLogJsonView,
123799
- analyticsUsePlatformAuditLabels: analyticsUsePlatformAuditLabels
124337
+ analyticsUsePlatformAuditLabels: analyticsUsePlatformAuditLabels,
124338
+ onboardingUserOnboarding: onboardingUserOnboarding,
124339
+ profileOnboardingTab: profileOnboardingTab
123800
124340
  };
123801
124341
 
123802
124342
  /**
@@ -177681,7 +178221,7 @@ const buildGradeSummary = (edx) => {
177681
178221
  function GradeBar({ currentPct, passingPct }) {
177682
178222
  const clampedCurrent = Math.min(Math.max(currentPct, 0), 100);
177683
178223
  const clampedPassing = Math.min(Math.max(passingPct, 0), 100);
177684
- return (jsxs("div", { className: "pt-7 pb-4", children: [jsxs("div", { className: "relative", children: [jsx("div", { className: "absolute -top-7 -translate-x-1/2", style: { left: `${clampedCurrent}%` }, children: jsxs("span", { className: "whitespace-nowrap rounded border border-amber-300 bg-amber-50 px-1.5 py-0.5 text-xs font-semibold text-gray-700", children: [currentPct, "%"] }) }), jsxs("div", { className: "relative h-2 rounded-full bg-gray-200", children: [jsx("div", { className: "absolute left-0 top-0 h-2 rounded-full bg-amber-500", style: { width: `${clampedCurrent}%` } }), jsx("div", { className: "absolute top-1/2 h-3.5 w-3.5 -translate-x-1/2 -translate-y-1/2 rounded-full border-2 border-white bg-amber-500", style: { left: `${clampedPassing}%` } })] }), jsx("div", { className: "absolute top-3 -translate-x-1/2", style: { left: `${clampedPassing}%` }, children: jsxs("span", { className: "whitespace-nowrap rounded bg-amber-500 px-1.5 py-0.5 text-xs font-semibold text-white", children: [passingPct, "%"] }) })] }), jsxs("div", { className: "mt-10 flex justify-between text-xs text-gray-500", children: [jsx("span", { children: "Current grade" }), jsx("span", { children: "Passing grade" })] })] }));
178224
+ return (jsxs("div", { className: "pt-7 pb-4", children: [jsxs("div", { className: "relative", children: [jsx("div", { className: "absolute -top-7 -translate-x-1/2", style: { left: `calc(${clampedCurrent}% + 15px)` }, children: jsxs("span", { className: "whitespace-nowrap rounded border border-amber-300 bg-amber-50 px-1.5 py-0.5 text-xs font-semibold text-gray-700", children: [currentPct, "%"] }) }), jsxs("div", { className: "relative h-2 rounded-full bg-gray-200", children: [jsx("div", { className: "absolute left-0 top-0 h-2 rounded-full bg-amber-500", style: { width: `${clampedCurrent}%` } }), jsx("div", { className: "absolute top-1/2 h-3.5 w-3.5 -translate-x-1/2 -translate-y-1/2 rounded-full border-2 border-white bg-amber-500", style: { left: `${clampedPassing}%` } })] }), jsx("div", { className: "absolute top-3 -translate-x-1/2", style: { left: `${clampedPassing}%` }, children: jsxs("span", { className: "whitespace-nowrap rounded bg-amber-500 px-1.5 py-0.5 text-xs font-semibold text-white", children: [passingPct, "%"] }) })] }), jsxs("div", { className: "mt-10 flex justify-between text-xs text-gray-500", children: [jsx("span", { children: "Current grade" }), jsx("span", { children: "Passing grade" })] })] }));
177685
178225
  }
177686
178226
  function EnrolledUserProgressModal({ open, onOpenChange, username, userName, email, contentId, contentName, tenantKey, metric = 'course', }) {
177687
178227
  var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s;
@@ -177722,7 +178262,7 @@ function DetailRow({ label, children }) {
177722
178262
  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 })] }));
177723
178263
  }
177724
178264
 
177725
- const PAGE_SIZE$b = 8;
178265
+ const PAGE_SIZE$e = 8;
177726
178266
  const CONTENT_TYPES = [
177727
178267
  { value: 'courses', labelKey: 'gradebookGradebookTab.typeCourses', icon: GraduationCap },
177728
178268
  { value: 'programs', labelKey: 'gradebookGradebookTab.typePrograms', icon: Layers },
@@ -177753,14 +178293,14 @@ function useGradebookData(type, org, username, page, search) {
177753
178293
  username,
177754
178294
  query: {
177755
178295
  page,
177756
- page_size: PAGE_SIZE$b,
178296
+ page_size: PAGE_SIZE$e,
177757
178297
  platform_key: org,
177758
178298
  ...(trimmed ? { search: trimmed } : {}),
177759
178299
  },
177760
178300
  }, { skip: type !== 'courses', refetchOnMountOrArgChange: true });
177761
178301
  const programsQ = useGetUserEnrolledProgramsQuery([{ username, platformKey: org }], { skip: type !== 'programs' });
177762
178302
  const pathwaysQ = useGetUserCatalogPathwaysQuery({ username, platform_key: org }, { skip: type !== 'pathways' });
177763
- const credentialsQ = useGetUsersAsAssertionsQuery({ platformKey: org, userId: username, page, pageSize: PAGE_SIZE$b }, { skip: type !== 'credentials', refetchOnMountOrArgChange: true });
178303
+ const credentialsQ = useGetUsersAsAssertionsQuery({ platformKey: org, userId: username, page, pageSize: PAGE_SIZE$e }, { skip: type !== 'credentials', refetchOnMountOrArgChange: true });
177764
178304
  const earnedQ = useGetUserEarnedSkillsQuery([{ org, userId: username }], { skip: type !== 'skills' });
177765
178305
  const reportedQ = useGetUserReportedSkillsQuery([{ username }], { skip: type !== 'skills' });
177766
178306
  const desiredQ = useGetUserDesiredSkillsQuery([{ username }], { skip: type !== 'skills' });
@@ -177770,12 +178310,12 @@ function useGradebookData(type, org, username, page, search) {
177770
178310
  const filtered = trimmed
177771
178311
  ? rows.filter((row) => row.name.toLowerCase().includes(trimmed.toLowerCase()))
177772
178312
  : rows;
177773
- const start = (page - 1) * PAGE_SIZE$b;
178313
+ const start = (page - 1) * PAGE_SIZE$e;
177774
178314
  return {
177775
- rows: filtered.slice(start, start + PAGE_SIZE$b),
178315
+ rows: filtered.slice(start, start + PAGE_SIZE$e),
177776
178316
  total: filtered.length,
177777
178317
  hasPrev: page > 1,
177778
- hasNext: start + PAGE_SIZE$b < filtered.length,
178318
+ hasNext: start + PAGE_SIZE$e < filtered.length,
177779
178319
  };
177780
178320
  };
177781
178321
  switch (type) {
@@ -177832,7 +178372,7 @@ function useGradebookData(type, org, username, page, search) {
177832
178372
  rows,
177833
178373
  total,
177834
178374
  hasPrev: page > 1,
177835
- hasNext: page * PAGE_SIZE$b < total,
178375
+ hasNext: page * PAGE_SIZE$e < total,
177836
178376
  isLoading: credentialsQ.isLoading,
177837
178377
  isFetching: credentialsQ.isFetching,
177838
178378
  isError: credentialsQ.isError,
@@ -177989,6 +178529,75 @@ function AddMemoryDialog({ open, onOpenChange, org, username }) {
177989
178529
  : t('memoryAddMemoryDialog.saveButton') })] })] }) }) }));
177990
178530
  }
177991
178531
 
178532
+ /**
178533
+ * Counterpart to {@link AddMemoryDialog} for updating a memory's content. The
178534
+ * backend refreshes embeddings on update and answers 409 when the new content
178535
+ * duplicates another memory.
178536
+ */
178537
+ function EditMemoryDialog({ open, onOpenChange, org, username, memory, mentorId, }) {
178538
+ const t = useT();
178539
+ const [content, setContent] = useState(memory.content);
178540
+ const [updateGlobalMemory, { isLoading: isSavingGlobal }] = useUpdateGlobalMemoryMutation();
178541
+ const [updateMentorMemory, { isLoading: isSavingMentor }] = useUpdateMentorMemoryMutation();
178542
+ const isLoading = isSavingGlobal || isSavingMentor;
178543
+ const handleSubmit = async (e) => {
178544
+ e.preventDefault();
178545
+ e.stopPropagation();
178546
+ if (content.trim().length < 10) {
178547
+ toast.error(t('memoryEditMemoryDialog.validationMinLength'));
178548
+ return;
178549
+ }
178550
+ try {
178551
+ if (mentorId) {
178552
+ await updateMentorMemory({
178553
+ org,
178554
+ userId: username,
178555
+ mentorId,
178556
+ memoryId: memory.id,
178557
+ data: { content: content.trim() },
178558
+ }).unwrap();
178559
+ }
178560
+ else {
178561
+ await updateGlobalMemory({
178562
+ org,
178563
+ userId: username,
178564
+ memoryId: memory.id,
178565
+ content: content.trim(),
178566
+ }).unwrap();
178567
+ }
178568
+ toast.success(t('memoryEditMemoryDialog.toastUpdated'));
178569
+ onOpenChange(false);
178570
+ }
178571
+ catch (error) {
178572
+ const status = error === null || error === void 0 ? void 0 : error.status;
178573
+ if (status === 409) {
178574
+ toast.error(t('memoryEditMemoryDialog.toastDuplicate'));
178575
+ }
178576
+ else if (status === 403) {
178577
+ toast.error(t('memoryEditMemoryDialog.toastForbidden'));
178578
+ }
178579
+ else {
178580
+ toast.error(t('memoryEditMemoryDialog.toastFailed'));
178581
+ }
178582
+ }
178583
+ };
178584
+ return (jsx(Dialog, { open: open, onOpenChange: onOpenChange, children: jsx(DialogContent, { className: "p-0 overflow-hidden max-w-lg", children: jsxs("form", { onSubmit: handleSubmit, children: [jsx("div", { className: "flex items-center justify-between px-6 py-4 border-b", children: jsx(DialogTitle, { className: "text-lg font-semibold text-gray-900", children: t('memoryEditMemoryDialog.dialogTitle') }) }), jsx(DialogDescription, { className: "sr-only", children: t('memoryEditMemoryDialog.dialogDescription') }), jsx("div", { className: "p-6 space-y-4", children: jsxs("div", { className: "space-y-2", children: [jsx(Label$1, { htmlFor: "edit-memory-content", children: t('memoryEditMemoryDialog.contentLabel') }), jsx(Textarea, { id: "edit-memory-content", value: content, onChange: (e) => setContent(e.target.value), rows: 4, className: "w-full bg-gray-50 border-gray-200 focus:ring-blue-500 focus:border-blue-500 text-sm resize-none", disabled: isLoading }), content.length > 0 && content.trim().length < 10 && (jsx("p", { className: "text-sm text-red-500", children: t('memoryEditMemoryDialog.inlineMinLength') }))] }) }), jsxs("div", { className: "flex justify-end gap-3 border-t px-6 py-4", children: [jsx(Button$1, { type: "button", variant: "outline", onClick: () => onOpenChange(false), disabled: isLoading, children: t('memoryEditMemoryDialog.cancelButton') }), jsx(Button$1, { className: "bg-gradient-to-r from-[#2563EB] to-[#93C5FD] hover:opacity-90 text-white", type: "submit", disabled: isLoading || content.trim().length < 10, children: isLoading
178585
+ ? t('memoryEditMemoryDialog.savingButton')
178586
+ : t('memoryEditMemoryDialog.saveButton') })] })] }) }) }));
178587
+ }
178588
+
178589
+ function DeleteMemoryModal$1({ open, onOpenChange, onConfirm, onCancel, isDeleting, }) {
178590
+ const t = useT();
178591
+ return (jsx(Dialog, { open: open, onOpenChange: onOpenChange, children: jsxs(DialogContent, { className: "mx-4 max-w-md sm:mx-auto", children: [jsx(DialogHeader, { children: jsx(DialogTitle, { children: t('memoryTabDeleteMemoryModal.title') }) }), jsx("p", { className: "text-muted-foreground text-sm", children: t('memoryTabDeleteMemoryModal.confirmMessage') }), jsxs("div", { className: "mt-4 flex justify-end gap-2", children: [jsx(Button$1, { variant: "outline", onClick: onCancel, children: t('memoryTabDeleteMemoryModal.cancel') }), jsx(Button$1, { className: "ibl-button-primary", onClick: onConfirm, disabled: isDeleting, children: isDeleting
178592
+ ? t('memoryTabDeleteMemoryModal.deleting')
178593
+ : t('memoryTabDeleteMemoryModal.delete') })] })] }) }));
178594
+ }
178595
+
178596
+ var deleteMemoryModal = /*#__PURE__*/Object.freeze({
178597
+ __proto__: null,
178598
+ DeleteMemoryModal: DeleteMemoryModal$1
178599
+ });
178600
+
177992
178601
  const Pagination = ({ className, ...props }) => {
177993
178602
  const t = useT();
177994
178603
  return (jsx("nav", { role: "navigation", "aria-label": t('uiPagination.paginationNavLabel'), className: cn('mx-auto flex w-full justify-center', className), ...props }));
@@ -178069,11 +178678,42 @@ const IblPagination = ({ currentPage, totalPages, onPageChange, disabled = false
178069
178678
  }, "aria-disabled": currentPage === totalPages || disabled, className: cn('cursor-pointer', (currentPage === totalPages || disabled) && 'pointer-events-none opacity-50') }) })] }) }));
178070
178679
  };
178071
178680
 
178681
+ /**
178682
+ * The one memory list UI — rows with source icon, content, date and auto
178683
+ * badge, a three-dots Edit/Delete menu, delete confirmation, and pagination.
178684
+ * Shared by the profile Memory tab and the tenant-settings memory popup so
178685
+ * the two stay identical.
178686
+ */
178687
+ function MemoriesList({ memories, isLoading, emptyText, deletingId, onEdit, onDelete, totalPages, currentPage, onPageChange, }) {
178688
+ const t = useT();
178689
+ const [pendingDelete, setPendingDelete] = useState(null);
178690
+ const confirmDelete = async () => {
178691
+ if (!pendingDelete)
178692
+ return;
178693
+ try {
178694
+ await onDelete(pendingDelete);
178695
+ }
178696
+ catch (_a) {
178697
+ // Hosts surface their own failure toasts; the modal just closes.
178698
+ }
178699
+ finally {
178700
+ setPendingDelete(null);
178701
+ }
178702
+ };
178703
+ if (isLoading) {
178704
+ return (jsx("div", { className: "space-y-3", children: [1, 2, 3].map((i) => (jsx(Skeleton, { className: "h-16 w-full rounded-lg" }, i))) }));
178705
+ }
178706
+ return (jsxs(Fragment$1, { children: [memories.length ? (jsx("div", { className: "space-y-3", "data-testid": "memories-list", children: memories.map((memory) => (jsxs("div", { "data-testid": "memory-row", 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') }))] })] }), deletingId === memory.id ? (jsx("div", { className: "mt-1 h-4 w-4 flex-shrink-0 animate-spin rounded-full border-2 border-gray-500 border-t-transparent" })) : (jsxs(DropdownMenu, { children: [jsx(DropdownMenuTrigger, { asChild: true, children: jsx(Button$1, { variant: "ghost", size: "sm", className: "h-6 w-6 flex-shrink-0 p-0 text-gray-600 hover:text-gray-900", "aria-label": t('memoryMemoryTab.actionsMenuAriaLabel', {
178707
+ excerpt: memory.content.substring(0, 30),
178708
+ }), children: jsx(Ellipsis, { className: "h-4 w-4" }) }) }), jsxs(DropdownMenuContent, { align: "end", children: [jsxs(DropdownMenuItem, { onClick: () => onEdit(memory), children: [jsx(Pencil, { className: "mr-2 h-4 w-4" }), t('memoryMemoryTab.editAction')] }), jsxs(DropdownMenuItem, { className: "text-red-600 focus:text-red-700", onClick: () => setPendingDelete(memory), children: [jsx(Trash2, { className: "mr-2 h-4 w-4" }), t('memoryMemoryTab.deleteAction')] })] })] }))] }, `${'mentor_id' in memory ? memory.mentor_id : 'global'}-${memory.id}`))) })) : (jsx("div", { "data-testid": "memories-list-empty", 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: emptyText }) })), totalPages > 1 && (jsx(IblPagination, { currentPage: currentPage, totalPages: totalPages, onPageChange: onPageChange, disabled: isLoading })), jsx(DeleteMemoryModal$1, { open: !!pendingDelete, onOpenChange: (open) => !open && setPendingDelete(null), onConfirm: confirmDelete, onCancel: () => setPendingDelete(null), isDeleting: !!pendingDelete && deletingId === pendingDelete.id })] }));
178709
+ }
178710
+
178072
178711
  const MEMORIES_PAGE_SIZE = 25;
178073
178712
  function MemoryTab({ org, username }) {
178074
178713
  var _a, _b;
178075
178714
  const t = useT();
178076
178715
  const [isAddDialogOpen, setIsAddDialogOpen] = useState(false);
178716
+ const [editingMemory, setEditingMemory] = useState(null);
178077
178717
  const [deletingId, setDeletingId] = useState(null);
178078
178718
  const [currentPage, setCurrentPage] = useState(1);
178079
178719
  // Viewing someone else's profile, which lists both of that user's memory
@@ -178085,11 +178725,13 @@ function MemoryTab({ org, username }) {
178085
178725
  org,
178086
178726
  userId: username,
178087
178727
  }, { skip: isPreview });
178088
- // User memory settings
178728
+ // User memory settings. In preview the path addresses the previewed user —
178729
+ // the backend resolves that for admin/RBAC callers, and the section simply
178730
+ // stays hidden when the settings come back forbidden.
178089
178731
  const { data: settings, isLoading: isLoadingSettings } = useGetUserMemorySettingsQuery({
178090
178732
  org,
178091
178733
  userId: username,
178092
- }, { skip: isPreview });
178734
+ });
178093
178735
  const [updateSettings, { isLoading: isUpdatingSettings }] = useUpdateUserMemorySettingsMutation();
178094
178736
  const memoriesParams = { page: currentPage, page_size: MEMORIES_PAGE_SIZE };
178095
178737
  // Global memories. On your own profile this is the plain call — your username
@@ -178124,6 +178766,7 @@ function MemoryTab({ org, username }) {
178124
178766
  return isPreview ? Math.max(globalPages, pageCount(mentorMemoriesData === null || mentorMemoriesData === void 0 ? void 0 : mentorMemoriesData.count)) : globalPages;
178125
178767
  }, [isPreview, globalMemoriesData, mentorMemoriesData]);
178126
178768
  const [deleteMemory] = useDeleteGlobalMemoryMutation();
178769
+ const [deleteMentorMemory] = useDeleteMentorMemoryMutation();
178127
178770
  const handleToggleSetting = async (key, checked) => {
178128
178771
  try {
178129
178772
  await updateSettings({
@@ -178137,14 +178780,26 @@ function MemoryTab({ org, username }) {
178137
178780
  toast.error(t('memoryMemoryTab.failedToUpdateMemorySetting'));
178138
178781
  }
178139
178782
  };
178140
- const handleDeleteMemory = async (memoryId) => {
178141
- setDeletingId(memoryId);
178783
+ const handleDeleteMemory = async (memory) => {
178784
+ setDeletingId(memory.id);
178142
178785
  try {
178143
- await deleteMemory({
178144
- org,
178145
- userId: username,
178146
- memoryId,
178147
- }).unwrap();
178786
+ if ('mentor_id' in memory) {
178787
+ // Agent memories are deleted the way the agent memory manager does it:
178788
+ // the caller in the path, authorization resolved server-side.
178789
+ await deleteMentorMemory({
178790
+ org,
178791
+ userId: currentUsername,
178792
+ mentorId: memory.mentor_id,
178793
+ memoryId: memory.id,
178794
+ }).unwrap();
178795
+ }
178796
+ else {
178797
+ await deleteMemory({
178798
+ org,
178799
+ userId: username,
178800
+ memoryId: memory.id,
178801
+ }).unwrap();
178802
+ }
178148
178803
  toast.success(t('memoryMemoryTab.memoryDeleted'));
178149
178804
  }
178150
178805
  catch (_a) {
@@ -178161,7 +178816,7 @@ function MemoryTab({ org, username }) {
178161
178816
  if (!isConfigError && memsearchStatus && !memsearchStatus.enable_memsearch) {
178162
178817
  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') }) }) }));
178163
178818
  }
178164
- 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', {
178819
+ return (jsxs("div", { className: "space-y-8", children: [(!isPreview || settings) && (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', {
178165
178820
  state: (settings === null || settings === void 0 ? void 0 : settings.auto_capture_enabled)
178166
178821
  ? t('memoryMemoryTab.stateEnabled')
178167
178822
  : t('memoryMemoryTab.stateDisabled'),
@@ -178171,11 +178826,16 @@ function MemoryTab({ org, username }) {
178171
178826
  : t('memoryMemoryTab.stateDisabled'),
178172
178827
  }), 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
178173
178828
  ? t('memoryMemoryTab.sectionMyMemoriesPreview')
178174
- : 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', {
178175
- excerpt: memory.content.substring(0, 30),
178176
- }), 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
178177
- ? t('memoryMemoryTab.noMemoriesYetPreview')
178178
- : 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 })] }));
178829
+ : 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')] })] }), jsx(MemoriesList, { memories: memories, isLoading: isLoadingMemories, emptyText: isPreview
178830
+ ? t('memoryMemoryTab.noMemoriesYetPreview')
178831
+ : t('memoryMemoryTab.noMemoriesYet'), deletingId: deletingId, onEdit: (memory) => setEditingMemory({
178832
+ id: memory.id,
178833
+ content: memory.content,
178834
+ ...('mentor_id' in memory ? { mentorId: memory.mentor_id } : {}),
178835
+ }), onDelete: handleDeleteMemory, totalPages: totalPages, currentPage: currentPage, onPageChange: setCurrentPage })] }), jsx(AddMemoryDialog, { open: isAddDialogOpen, onOpenChange: setIsAddDialogOpen, org: org, username: username }), editingMemory && (jsx(EditMemoryDialog, { open: !!editingMemory, onOpenChange: (open) => !open && setEditingMemory(null), org: org,
178836
+ // Agent memories are written with the caller in the path (the way
178837
+ // the agent memory manager does); global memories with their owner.
178838
+ username: editingMemory.mentorId ? currentUsername : username, memory: editingMemory, mentorId: editingMemory.mentorId }))] }));
178179
178839
  }
178180
178840
 
178181
178841
  var _a$1;
@@ -180316,7 +180976,7 @@ const PopoverContent = React.forwardRef(({ className, align = 'center', sideOffs
180316
180976
  });
180317
180977
  PopoverContent.displayName = Content2$2.displayName;
180318
180978
 
180319
- const PAGE_SIZE$a = 10;
180979
+ const PAGE_SIZE$d = 10;
180320
180980
  function UsersTab({ tenant, onInviteClick, currentSpa, showGradebookTab = false, }) {
180321
180981
  var _a, _b;
180322
180982
  const t = useT();
@@ -180338,7 +180998,7 @@ function UsersTab({ tenant, onInviteClick, currentSpa, showGradebookTab = false,
180338
180998
  const isWatcher = isPureWatcher(rbacPermissions, currentTenant);
180339
180999
  const { data: users, refetch: refetchPlatformUsers, isLoading: isLoadingPlatformUsers, } = usePlatformUsersQuery({
180340
181000
  page,
180341
- page_size: PAGE_SIZE$a,
181001
+ page_size: PAGE_SIZE$d,
180342
181002
  platform_key: tenant,
180343
181003
  platform_org: tenant,
180344
181004
  query: debouncedSearchQuery,
@@ -180352,7 +181012,7 @@ function UsersTab({ tenant, onInviteClick, currentSpa, showGradebookTab = false,
180352
181012
  // TODO to use required_action: 'Ibl.Core/Users/read',
180353
181013
  required_action: 'Ibl.Mentor/Memory/list',
180354
181014
  page,
180355
- page_size: PAGE_SIZE$a,
181015
+ page_size: PAGE_SIZE$d,
180356
181016
  sort: 'name',
180357
181017
  ...(debouncedSearchQuery.includes('@')
180358
181018
  ? { email: debouncedSearchQuery }
@@ -180521,14 +181181,16 @@ function UsersTab({ tenant, onInviteClick, currentSpa, showGradebookTab = false,
180521
181181
  managed: user,
180522
181182
  }));
180523
181183
  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;
180524
- const totalPages = Math.ceil(totalCount / PAGE_SIZE$a);
180525
- 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) => {
181184
+ const totalPages = Math.ceil(totalCount / PAGE_SIZE$d);
181185
+ 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-full' : 'w-[41%]'}`, 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) => {
180526
181186
  // Only set on the admin path — see {@link UserRow}.
180527
181187
  const user = row.managed;
180528
- 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) => {
181188
+ 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-email-column', className: "px-6 py-4 text-gray-900 dark:text-gray-100 text-sm max-w-0", children: jsx("button", { type: "button", onClick: (e) => {
180529
181189
  e.stopPropagation();
180530
181190
  setSelectedUser(row);
180531
- }, 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', {
181191
+ }, 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', {
181192
+ name: row.name || row.email,
181193
+ }), 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', {
180532
181194
  name: user.name,
180533
181195
  }), 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
180534
181196
  ? t('tabsUserstab.allPoliciesSelected', {
@@ -180547,7 +181209,7 @@ function UsersTab({ tenant, onInviteClick, currentSpa, showGradebookTab = false,
180547
181209
  })] }) })] }) }), 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', {
180548
181210
  name: user.name,
180549
181211
  }), className: "cursor-pointer data-[state=checked]:bg-blue-500 disabled:cursor-not-allowed disabled:opacity-50" }) })] }))] }, row.key));
180550
- }), 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$a, itemLabel: "users" })] })), selectedUser && (jsx(Dialog, { open: !!selectedUser, onOpenChange: (open) => {
181212
+ }), 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$d, itemLabel: "users" })] })), selectedUser && (jsx(Dialog, { open: !!selectedUser, onOpenChange: (open) => {
180551
181213
  if (!open)
180552
181214
  setSelectedUser(null);
180553
181215
  }, 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: {
@@ -181767,7 +182429,7 @@ function PoliciesTab({ tenant }) {
181767
182429
  : t('tabsPoliciestab.createPolicy')] }) }) }), editing && (policyDetails === null || policyDetails === void 0 ? void 0 : policyDetails.is_internal) && (jsx(TooltipContent, { children: jsx("p", { children: t('tabsPoliciestab.cannotEditInternal') }) }))] }) })] })] }) }), jsx(ResourcePickerModal, { open: isResourcePickerOpen, onOpenChange: setIsResourcePickerOpen, tenant: tenant, onSelect: addPickedResource })] }));
181768
182430
  }
181769
182431
 
181770
- const PAGE_SIZE$9 = 10;
182432
+ const PAGE_SIZE$c = 10;
181771
182433
  function normalizeEvents(events) {
181772
182434
  if (!events)
181773
182435
  return [];
@@ -181816,8 +182478,8 @@ function AlertsTab({ tenant }) {
181816
182478
  const { data: watchedGroupsData, isLoading, isError, refetch, } = useGetWatchedGroupsQuery({
181817
182479
  params: {
181818
182480
  platform_key: tenant,
181819
- limit: PAGE_SIZE$9,
181820
- offset: (page - 1) * PAGE_SIZE$9,
182481
+ limit: PAGE_SIZE$c,
182482
+ offset: (page - 1) * PAGE_SIZE$c,
181821
182483
  },
181822
182484
  });
181823
182485
  const groups = useMemo(() => {
@@ -181830,7 +182492,7 @@ function AlertsTab({ tenant }) {
181830
182492
  return results;
181831
182493
  }, [watchedGroupsData, debouncedSearchQuery]);
181832
182494
  const totalPages = watchedGroupsData
181833
- ? Math.max(1, Math.ceil(watchedGroupsData.count / PAGE_SIZE$9))
182495
+ ? Math.max(1, Math.ceil(watchedGroupsData.count / PAGE_SIZE$c))
181834
182496
  : 0;
181835
182497
  const handlePageChange = async (newPage) => {
181836
182498
  setPage(newPage);
@@ -182139,7 +182801,7 @@ function AlertsTab({ tenant }) {
182139
182801
  setDeletingGroupId(null);
182140
182802
  }
182141
182803
  }
182142
- return (jsxs("div", { className: "mt-4", children: [jsxs("div", { className: "flex mb-6 gap-2 flex-row items-center justify-between", children: [jsxs("div", { className: "relative max-w-sm w-full sm:w-auto", children: [jsx(Search, { className: "absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-gray-400" }), jsx(Input, { value: searchQuery, onChange: (e) => setSearchQuery(e.target.value), placeholder: t('tabsAlertstab.searchAlertsPlaceholder'), "aria-label": t('tabsAlertstab.searchAlertsAriaLabel'), className: "pl-10 pr-10 focus:ring-blue-500 focus:border-blue-500 h-[35px]" }), 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: "flex gap-2", children: jsx(Button$1, { onClick: openNew, "aria-label": t('tabsAlertstab.newAlertAriaLabel'), className: "bg-gradient-to-r from-[#2563EB] to-[#93C5FD] hover:opacity-90 text-white h-[35px]", children: t('tabsAlertstab.newAlert') }) })] }), isLoading && (jsx("div", { className: "flex justify-center items-center h-64", children: jsx("div", { className: "py-8 text-center text-sm text-gray-500 dark:text-gray-400", children: t('tabsAlertstab.loading') }) })), isError && (jsx("div", { className: "py-8 text-center text-sm text-red-500", children: t('tabsAlertstab.failedToLoadAlerts') })), !isLoading && !isError && (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", children: t('tabsAlertstab.columnName') }), jsx("th", { className: "px-6 py-3 text-right font-medium text-gray-500 dark:text-gray-400 w-[120px]" })] }) }), jsxs("tbody", { className: "divide-y divide-gray-200 dark:divide-gray-600", children: [groups.map((g) => (jsxs("tr", { children: [jsx("td", { className: "px-6 py-4 text-gray-900 dark:text-gray-100 text-sm", children: g.name }), jsx("td", { className: "px-6 py-4", children: jsxs("div", { className: "flex gap-2 justify-end", children: [jsx(Button$1, { variant: "ghost", size: "sm", onClick: () => openEdit(g), disabled: deletingGroupId === g.id, "aria-label": t('tabsAlertstab.editAlertAriaLabel', { name: g.name }), children: jsx(Pencil, { className: "h-4 w-4", "aria-hidden": "true" }) }), jsx(Button$1, { variant: "ghost", size: "sm", onClick: () => onDelete(g), className: "text-red-600 hover:text-red-700", disabled: deletingGroupId === g.id, "aria-label": t('tabsAlertstab.deleteAlertAriaLabel', { name: g.name }), children: deletingGroupId === g.id ? (jsx(LoaderCircle, { className: "h-4 w-4 animate-spin", "aria-hidden": "true" })) : (jsx(Trash2, { className: "h-4 w-4", "aria-hidden": "true" })) })] }) })] }, g.id))), groups.length === 0 && (jsx("tr", { children: jsx("td", { colSpan: 2, className: "px-6 py-8 text-center text-gray-500 dark:text-gray-400", children: t('tabsAlertstab.noAlertsFound') }) }))] })] }) })), !isLoading && !isError && (jsx(AdvancedPagination, { variant: "footer", className: "-mx-6 -mb-6 mt-4 rounded-b-lg", totalPages: totalPages, currentPage: page, onPageChange: (newPage) => handlePageChange(newPage), totalCount: watchedGroupsData === null || watchedGroupsData === void 0 ? void 0 : watchedGroupsData.count, itemsPerPage: PAGE_SIZE$9, itemLabel: "alerts" })), jsx(Dialog, { open: isOpen, onOpenChange: setIsOpen, children: jsxs(DialogContent, { "aria-describedby": undefined, className: "max-w-2xl max-h-[90vh] overflow-y-auto", children: [jsx(DialogHeader, { children: jsx(DialogTitle, { children: editingGroup ? t('tabsAlertstab.editAlert') : t('tabsAlertstab.newAlert') }) }), jsxs("div", { className: "space-y-5", children: [jsxs("div", { className: "grid gap-1.5", children: [jsx(Label$1, { htmlFor: "wg-name", children: t('tabsAlertstab.nameLabel') }), jsx(Input, { id: "wg-name", value: name, onChange: (e) => setName(e.target.value), placeholder: t('tabsAlertstab.enterAlertNamePlaceholder'), required: true })] }), jsxs("div", { className: "grid gap-1.5", children: [jsx(Label$1, { children: t('tabsAlertstab.watchedUsersLabel') }), jsx("p", { className: "text-xs text-gray-500 dark:text-gray-400", children: t('tabsAlertstab.watchedUsersDescription') }), watchedUsers.length > 0 ? (jsx("div", { className: "space-y-2 max-h-48 overflow-y-auto border border-gray-200 dark:border-gray-700 rounded-md p-2", children: watchedUsers.map((user) => (jsxs("div", { className: "flex items-center justify-between bg-gray-50 dark:bg-gray-800 p-2 rounded-md", children: [jsxs("div", { className: "flex flex-col", children: [jsx("span", { className: "text-sm font-medium text-gray-900 dark:text-gray-100", children: user.name || user.username }), user.email && (jsx("span", { className: "text-xs text-gray-500 dark:text-gray-400", children: user.email }))] }), jsx(Button$1, { type: "button", variant: "ghost", size: "sm", onClick: () => removeWatchedUserDraft(user.id), className: "h-8 w-8 p-0 text-red-600 hover:text-red-700 hover:bg-red-50 dark:hover:bg-red-900/20", "aria-label": t('tabsAlertstab.removeWatchedUserAriaLabel', {
182804
+ return (jsxs("div", { className: "mt-4", children: [jsxs("div", { className: "flex mb-6 gap-2 flex-row items-center justify-between", children: [jsxs("div", { className: "relative max-w-sm w-full sm:w-auto", children: [jsx(Search, { className: "absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-gray-400" }), jsx(Input, { value: searchQuery, onChange: (e) => setSearchQuery(e.target.value), placeholder: t('tabsAlertstab.searchAlertsPlaceholder'), "aria-label": t('tabsAlertstab.searchAlertsAriaLabel'), className: "pl-10 pr-10 focus:ring-blue-500 focus:border-blue-500 h-[35px]" }), 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: "flex gap-2", children: jsx(Button$1, { onClick: openNew, "aria-label": t('tabsAlertstab.newAlertAriaLabel'), className: "bg-gradient-to-r from-[#2563EB] to-[#93C5FD] hover:opacity-90 text-white h-[35px]", children: t('tabsAlertstab.newAlert') }) })] }), isLoading && (jsx("div", { className: "flex justify-center items-center h-64", children: jsx("div", { className: "py-8 text-center text-sm text-gray-500 dark:text-gray-400", children: t('tabsAlertstab.loading') }) })), isError && (jsx("div", { className: "py-8 text-center text-sm text-red-500", children: t('tabsAlertstab.failedToLoadAlerts') })), !isLoading && !isError && (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", children: t('tabsAlertstab.columnName') }), jsx("th", { className: "px-6 py-3 text-right font-medium text-gray-500 dark:text-gray-400 w-[120px]" })] }) }), jsxs("tbody", { className: "divide-y divide-gray-200 dark:divide-gray-600", children: [groups.map((g) => (jsxs("tr", { children: [jsx("td", { className: "px-6 py-4 text-gray-900 dark:text-gray-100 text-sm", children: g.name }), jsx("td", { className: "px-6 py-4", children: jsxs("div", { className: "flex gap-2 justify-end", children: [jsx(Button$1, { variant: "ghost", size: "sm", onClick: () => openEdit(g), disabled: deletingGroupId === g.id, "aria-label": t('tabsAlertstab.editAlertAriaLabel', { name: g.name }), children: jsx(Pencil, { className: "h-4 w-4", "aria-hidden": "true" }) }), jsx(Button$1, { variant: "ghost", size: "sm", onClick: () => onDelete(g), className: "text-red-600 hover:text-red-700", disabled: deletingGroupId === g.id, "aria-label": t('tabsAlertstab.deleteAlertAriaLabel', { name: g.name }), children: deletingGroupId === g.id ? (jsx(LoaderCircle, { className: "h-4 w-4 animate-spin", "aria-hidden": "true" })) : (jsx(Trash2, { className: "h-4 w-4", "aria-hidden": "true" })) })] }) })] }, g.id))), groups.length === 0 && (jsx("tr", { children: jsx("td", { colSpan: 2, className: "px-6 py-8 text-center text-gray-500 dark:text-gray-400", children: t('tabsAlertstab.noAlertsFound') }) }))] })] }) })), !isLoading && !isError && (jsx(AdvancedPagination, { variant: "footer", className: "-mx-6 -mb-6 mt-4 rounded-b-lg", totalPages: totalPages, currentPage: page, onPageChange: (newPage) => handlePageChange(newPage), totalCount: watchedGroupsData === null || watchedGroupsData === void 0 ? void 0 : watchedGroupsData.count, itemsPerPage: PAGE_SIZE$c, itemLabel: "alerts" })), jsx(Dialog, { open: isOpen, onOpenChange: setIsOpen, children: jsxs(DialogContent, { "aria-describedby": undefined, className: "max-w-2xl max-h-[90vh] overflow-y-auto", children: [jsx(DialogHeader, { children: jsx(DialogTitle, { children: editingGroup ? t('tabsAlertstab.editAlert') : t('tabsAlertstab.newAlert') }) }), jsxs("div", { className: "space-y-5", children: [jsxs("div", { className: "grid gap-1.5", children: [jsx(Label$1, { htmlFor: "wg-name", children: t('tabsAlertstab.nameLabel') }), jsx(Input, { id: "wg-name", value: name, onChange: (e) => setName(e.target.value), placeholder: t('tabsAlertstab.enterAlertNamePlaceholder'), required: true })] }), jsxs("div", { className: "grid gap-1.5", children: [jsx(Label$1, { children: t('tabsAlertstab.watchedUsersLabel') }), jsx("p", { className: "text-xs text-gray-500 dark:text-gray-400", children: t('tabsAlertstab.watchedUsersDescription') }), watchedUsers.length > 0 ? (jsx("div", { className: "space-y-2 max-h-48 overflow-y-auto border border-gray-200 dark:border-gray-700 rounded-md p-2", children: watchedUsers.map((user) => (jsxs("div", { className: "flex items-center justify-between bg-gray-50 dark:bg-gray-800 p-2 rounded-md", children: [jsxs("div", { className: "flex flex-col", children: [jsx("span", { className: "text-sm font-medium text-gray-900 dark:text-gray-100", children: user.name || user.username }), user.email && (jsx("span", { className: "text-xs text-gray-500 dark:text-gray-400", children: user.email }))] }), jsx(Button$1, { type: "button", variant: "ghost", size: "sm", onClick: () => removeWatchedUserDraft(user.id), className: "h-8 w-8 p-0 text-red-600 hover:text-red-700 hover:bg-red-50 dark:hover:bg-red-900/20", "aria-label": t('tabsAlertstab.removeWatchedUserAriaLabel', {
182143
182805
  username: user.username,
182144
182806
  }), children: jsx(X$2, { className: "h-4 w-4" }) })] }, user.id))) })) : (jsx("div", { className: "text-sm text-gray-500 dark:text-gray-400 p-4 text-center border border-dashed border-gray-300 dark:border-gray-600 rounded-md", children: t('tabsAlertstab.noWatchedUsersAdded') })), jsxs("div", { className: "relative", children: [jsx(Input, { value: watchedUserSearch, onChange: (e) => {
182145
182807
  setWatchedUserSearch(e.target.value);
@@ -183462,8 +184124,8 @@ function BlocksView({ platformKey, onBack, }) {
183462
184124
  }
183463
184125
 
183464
184126
  const FILTER_ORDER = ['all', ...APPLICATION_STATUSES];
183465
- const PAGE_SIZE$8 = 20;
183466
- const SEARCH_DEBOUNCE_MS = 300;
184127
+ const PAGE_SIZE$b = 20;
184128
+ const SEARCH_DEBOUNCE_MS$1 = 300;
183467
184129
  /**
183468
184130
  * The public application URL on the auth SPA for one form of a platform
183469
184131
  * (`<auth-url>/applications/<platform-key>/<form-id>?redirect-to=<origin>`), or
@@ -183574,7 +184236,7 @@ function SubmissionsPipeline({ platformKey, form, onBack, onOpen, }) {
183574
184236
  const timer = setTimeout(() => {
183575
184237
  setDebouncedSearch(search.trim());
183576
184238
  setDebouncedCandidateFilter(candidateFilter.trim());
183577
- }, SEARCH_DEBOUNCE_MS);
184239
+ }, SEARCH_DEBOUNCE_MS$1);
183578
184240
  return () => clearTimeout(timer);
183579
184241
  }, [search, candidateFilter]);
183580
184242
  // New filters restart paging.
@@ -183597,7 +184259,7 @@ function SubmissionsPipeline({ platformKey, form, onBack, onOpen, }) {
183597
184259
  ...(sort !== '-created' ? { sort } : {}),
183598
184260
  ...candidateParams,
183599
184261
  page,
183600
- page_size: PAGE_SIZE$8,
184262
+ page_size: PAGE_SIZE$b,
183601
184263
  }, {
183602
184264
  refetchOnMountOrArgChange: true,
183603
184265
  });
@@ -183606,7 +184268,7 @@ function SubmissionsPipeline({ platformKey, form, onBack, onOpen, }) {
183606
184268
  : [];
183607
184269
  const rows = form ? allRows.filter((row) => row.form_id === form.id) : allRows;
183608
184270
  const count = typeof (pipeline === null || pipeline === void 0 ? void 0 : pipeline.count) === 'number' ? pipeline.count : allRows.length;
183609
- const totalPages = Math.max(1, Math.ceil(count / PAGE_SIZE$8));
184271
+ const totalPages = Math.max(1, Math.ceil(count / PAGE_SIZE$b));
183610
184272
  const counts = statsCounts(stats);
183611
184273
  const countFor = (key) => {
183612
184274
  if (!stats)
@@ -183644,7 +184306,263 @@ function SubmissionsPipeline({ platformKey, form, onBack, onOpen, }) {
183644
184306
  }) }) }), jsx("td", { className: "whitespace-nowrap px-6 py-4 text-sm text-gray-600 dark:text-gray-300", children: formatDate(row) }), jsx("td", { className: "px-6 py-4", children: jsx(Badge, { variant: "outline", className: approvalTone(row.status), children: STATUS_LABEL_KEYS[row.status]
183645
184307
  ? t(STATUS_LABEL_KEYS[row.status])
183646
184308
  : row.status }) })] }, row.id));
183647
- })) })] }) }), jsx(AdvancedPagination, { variant: "footer", className: "-mx-6 -mb-6 mt-4 rounded-b-lg", totalPages: totalPages, currentPage: page, onPageChange: (newPage) => setPage(newPage), totalCount: count, itemsPerPage: PAGE_SIZE$8, itemLabel: "applications" })] }))] }));
184309
+ })) })] }) }), jsx(AdvancedPagination, { variant: "footer", className: "-mx-6 -mb-6 mt-4 rounded-b-lg", totalPages: totalPages, currentPage: page, onPageChange: (newPage) => setPage(newPage), totalCount: count, itemsPerPage: PAGE_SIZE$b, itemLabel: "applications" })] }))] }));
184310
+ }
184311
+
184312
+ /**
184313
+ * Single-select searchable picker: a deb-ounce-agnostic input + absolute
184314
+ * results dropdown (the add-access pattern), collapsing to a removable chip
184315
+ * once something is picked. The caller owns the search term and the fetched
184316
+ * options so any query hook can back it.
184317
+ */
184318
+ function SearchSelect({ labels, selected, onSelect, onClear, searchTerm, onSearchTermChange, options, isLoading, minChars = 2, labelClassName = 'text-xs font-medium text-gray-700', testId, }) {
184319
+ const [isOpen, setIsOpen] = React__default.useState(false);
184320
+ const blurTimeout = React__default.useRef(null);
184321
+ React__default.useEffect(() => () => {
184322
+ if (blurTimeout.current)
184323
+ clearTimeout(blurTimeout.current);
184324
+ }, []);
184325
+ if (selected) {
184326
+ return (jsxs("div", { className: "space-y-1.5", children: [labels.label && jsx(Label$1, { className: labelClassName, children: labels.label }), jsxs("div", { className: "flex items-center justify-between gap-2 rounded-md border border-gray-200 bg-gray-50 px-3 py-2", "data-testid": `${testId}-selected`, children: [jsxs("div", { className: "min-w-0", children: [jsx("p", { className: "truncate text-sm font-medium text-gray-900", children: selected.label }), selected.sublabel && (jsx("p", { className: "truncate text-xs text-gray-600", children: selected.sublabel }))] }), jsxs(Button$1, { type: "button", size: "icon", variant: "ghost", className: "h-6 w-6 flex-shrink-0 text-gray-500 hover:text-red-600", onClick: onClear, "data-testid": `${testId}-clear`, children: [jsx(X$2, { className: "h-3.5 w-3.5", "aria-hidden": "true" }), jsx("span", { className: "sr-only", children: labels.clear })] })] })] }));
184327
+ }
184328
+ return (jsxs("div", { className: "space-y-1.5", children: [labels.label && (jsx(Label$1, { className: labelClassName, htmlFor: `${testId}-input`, children: labels.label })), jsxs("div", { className: "relative", children: [jsx(Input, { id: `${testId}-input`, className: "focus-visible:border-blue-500 focus-visible:ring-1 focus-visible:ring-blue-500", "aria-label": labels.label || labels.placeholder, value: searchTerm, onChange: (e) => onSearchTermChange(e.target.value), onFocus: () => {
184329
+ if (blurTimeout.current)
184330
+ clearTimeout(blurTimeout.current);
184331
+ setIsOpen(true);
184332
+ }, onBlur: () => {
184333
+ blurTimeout.current = setTimeout(() => setIsOpen(false), 100);
184334
+ }, placeholder: labels.placeholder, autoComplete: "off", "aria-autocomplete": "list", "aria-expanded": isOpen, "data-testid": `${testId}-input` }), isOpen && (jsx("div", { className: "absolute top-full right-0 left-0 z-50 mt-1 max-h-64 overflow-y-auto rounded-md border border-gray-200 bg-white shadow-lg", "data-testid": `${testId}-results`, children: searchTerm.trim().length < minChars ? (jsx("div", { className: "px-3 py-2 text-sm text-gray-600", children: labels.typeToSearch })) : isLoading ? (jsxs("div", { className: "flex items-center gap-2 px-3 py-2 text-sm text-gray-600", children: [jsx(LoaderCircle, { className: "h-3.5 w-3.5 animate-spin", "aria-hidden": "true" }), labels.searching] })) : options.length > 0 ? (options.map((option) => (jsxs("button", { type: "button", className: "flex w-full flex-col items-start gap-0.5 px-3 py-2 text-left hover:bg-gray-50", onMouseDown: (event) => event.preventDefault(), onClick: () => {
184335
+ onSelect(option);
184336
+ setIsOpen(false);
184337
+ }, "data-testid": `${testId}-option-${option.value}`, children: [jsx("span", { className: "text-sm font-medium text-gray-900", children: option.label }), option.sublabel && (jsx("span", { className: "text-xs text-gray-600", children: option.sublabel }))] }, option.value)))) : (jsx("div", { className: "px-3 py-2 text-sm text-gray-600", "data-testid": `${testId}-no-results`, children: labels.noResults })) }))] })] }));
184338
+ }
184339
+
184340
+ // The user-onboarding form contract: the schema an admin authors in the admin
184341
+ // panel, where both it and the learners' answers live (tenant metadata), and
184342
+ // the pure readers/writers both sides share. No React here so it stays unit
184343
+ // testable.
184344
+ //
184345
+ // Storage (tenant metadata, `PUT /api/core/orgs/<org>/metadata/`):
184346
+ // `user_onboarding_form` -> one {@link UserOnboardingForm}
184347
+ // `user_onboarding_submission` -> { [username]: {@link UserOnboardingSubmission} }
184348
+ //
184349
+ // The metadata endpoint replaces the whole metadata object, so every writer
184350
+ // here takes the current metadata and returns a merged copy.
184351
+ /** Tenant-metadata key holding the admin-authored onboarding form. */
184352
+ const USER_ONBOARDING_FORM_SLUG = 'user_onboarding_form';
184353
+ /** Bump when the persisted form/submission shape changes. */
184354
+ const USER_ONBOARDING_FORM_VERSION = 1;
184355
+ /** Metadata values reach us as objects or, on older writes, JSON strings. */
184356
+ function parseMetadataValue(raw) {
184357
+ if (typeof raw !== 'string')
184358
+ return raw;
184359
+ try {
184360
+ return JSON.parse(raw);
184361
+ }
184362
+ catch (_a) {
184363
+ return undefined;
184364
+ }
184365
+ }
184366
+ function isRecord(value) {
184367
+ return !!value && typeof value === 'object' && !Array.isArray(value);
184368
+ }
184369
+ /** A blank form for a platform that has never configured onboarding. */
184370
+ function emptyUserOnboardingForm(title = '') {
184371
+ return {
184372
+ version: USER_ONBOARDING_FORM_VERSION,
184373
+ enabled: false,
184374
+ title,
184375
+ sections: [],
184376
+ agent: null,
184377
+ };
184378
+ }
184379
+ /** Defensive read of a stored agent selection; null when unusable. */
184380
+ function coerceOnboardingAgent(raw) {
184381
+ var _a, _b;
184382
+ const value = parseMetadataValue(raw);
184383
+ if (!isRecord(value))
184384
+ return null;
184385
+ const id = (_b = (_a = value.mentor_unique_id) !== null && _a !== void 0 ? _a : value.unique_id) !== null && _b !== void 0 ? _b : value.mentor;
184386
+ if (typeof id !== 'string' || !id.trim())
184387
+ return null;
184388
+ return {
184389
+ mentor_unique_id: id,
184390
+ name: typeof value.name === 'string' ? value.name : undefined,
184391
+ title: typeof value.title === 'string' ? value.title : undefined,
184392
+ description: typeof value.description === 'string' ? value.description : undefined,
184393
+ };
184394
+ }
184395
+ /**
184396
+ * Defensive read of the stored form. Anything unrecognizable (missing key,
184397
+ * wrong type, unparseable string) reads as an empty, disabled form so both the
184398
+ * editor and the wizard always have something to work with.
184399
+ */
184400
+ function coerceUserOnboardingForm(raw) {
184401
+ const value = parseMetadataValue(raw);
184402
+ if (!isRecord(value))
184403
+ return emptyUserOnboardingForm();
184404
+ const sections = Array.isArray(value.sections)
184405
+ ? value.sections.filter((section) => isRecord(section) && Array.isArray(section.fields))
184406
+ : [];
184407
+ return {
184408
+ version: typeof value.version === 'number' ? value.version : USER_ONBOARDING_FORM_VERSION,
184409
+ enabled: value.enabled === true,
184410
+ title: typeof value.title === 'string' ? value.title : '',
184411
+ description: typeof value.description === 'string' ? value.description : undefined,
184412
+ sections,
184413
+ agent: coerceOnboardingAgent(value.agent),
184414
+ updated_at: typeof value.updated_at === 'string' ? value.updated_at : undefined,
184415
+ };
184416
+ }
184417
+ /** Read the onboarding form out of a tenant's metadata. */
184418
+ function readUserOnboardingForm(metadata) {
184419
+ return coerceUserOnboardingForm(metadata === null || metadata === void 0 ? void 0 : metadata[USER_ONBOARDING_FORM_SLUG]);
184420
+ }
184421
+ /**
184422
+ * Merge the form into the tenant metadata for a `PUT` (the endpoint replaces
184423
+ * the whole object, so untouched keys must ride along).
184424
+ */
184425
+ function buildUserOnboardingFormMetadata(metadata, form, updatedAt) {
184426
+ var _a;
184427
+ return {
184428
+ ...(metadata !== null && metadata !== void 0 ? metadata : {}),
184429
+ [USER_ONBOARDING_FORM_SLUG]: {
184430
+ ...form,
184431
+ version: USER_ONBOARDING_FORM_VERSION,
184432
+ agent: (_a = form.agent) !== null && _a !== void 0 ? _a : null,
184433
+ updated_at: updatedAt,
184434
+ },
184435
+ };
184436
+ }
184437
+
184438
+ /**
184439
+ * Onboarding management: which agent every new member of the platform
184440
+ * meets, and how it is introduced (heading + sub-heading).
184441
+ *
184442
+ * The whole thing is one tenant-metadata key (`user_onboarding_form`), so
184443
+ * saving merges the choice in and PUTs the metadata back. The member-facing
184444
+ * side is `OnboardingWizard` with `isAdminOnboarding={false}`, which shows the
184445
+ * agent — and nothing at all when no agent is set, handing the user straight
184446
+ * back to the app.
184447
+ */
184448
+ function OnboardingTab({ platformKey, username, }) {
184449
+ var _a, _b, _c;
184450
+ const t = useT();
184451
+ const { data, isLoading, error } = useGetTenantMetadataQuery([{ org: platformKey }], {
184452
+ skip: !platformKey,
184453
+ refetchOnMountOrArgChange: true,
184454
+ });
184455
+ const metadata = data === null || data === void 0 ? void 0 : data.metadata;
184456
+ const resolvedUsername = React.useMemo(() => {
184457
+ var _a;
184458
+ if (username)
184459
+ return username;
184460
+ try {
184461
+ return (_a = getUserName$1()) !== null && _a !== void 0 ? _a : '';
184462
+ }
184463
+ catch (_b) {
184464
+ return '';
184465
+ }
184466
+ }, [username]);
184467
+ const [agent, setAgent] = React.useState(null);
184468
+ const [dirty, setDirty] = React.useState(false);
184469
+ // Seed from the saved metadata, and re-seed when a refetch brings a newer
184470
+ // saved version.
184471
+ const saved = readUserOnboardingForm(metadata);
184472
+ const savedAt = saved.updated_at;
184473
+ React.useEffect(() => {
184474
+ var _a;
184475
+ if (!metadata)
184476
+ return;
184477
+ setAgent((_a = readUserOnboardingForm(metadata).agent) !== null && _a !== void 0 ? _a : null);
184478
+ setDirty(false);
184479
+ // eslint-disable-next-line react-hooks/exhaustive-deps
184480
+ }, [!!metadata, savedAt]);
184481
+ const update = (next) => {
184482
+ setAgent(next);
184483
+ setDirty(true);
184484
+ };
184485
+ // Agent search — the endpoint filters server-side, so only the term is local.
184486
+ const [searchTerm, setSearchTerm] = React.useState('');
184487
+ const [debouncedTerm, setDebouncedTerm] = React.useState('');
184488
+ React.useEffect(() => {
184489
+ const timer = setTimeout(() => setDebouncedTerm(searchTerm.trim()), 300);
184490
+ return () => clearTimeout(timer);
184491
+ }, [searchTerm]);
184492
+ const { data: mentorsData, isFetching: isSearching } = useGetMentorsQuery({
184493
+ org: platformKey,
184494
+ username: resolvedUsername,
184495
+ limit: 20,
184496
+ ...(debouncedTerm ? { query: debouncedTerm } : {}),
184497
+ }, { skip: !platformKey || !resolvedUsername });
184498
+ const options = ((_a = mentorsData === null || mentorsData === void 0 ? void 0 : mentorsData.results) !== null && _a !== void 0 ? _a : [])
184499
+ .filter((mentor) => !!mentor.unique_id)
184500
+ .map((mentor) => ({
184501
+ value: mentor.unique_id,
184502
+ label: mentor.name || mentor.unique_id,
184503
+ sublabel: mentor.description || undefined,
184504
+ }));
184505
+ const [updateTenantMetadata, { isLoading: saving }] = useUpdateTenantMetadataMutation();
184506
+ const [fetchTenantMetadata] = useLazyGetTenantMetadataQuery();
184507
+ /**
184508
+ * Save onto the tenant metadata. The endpoint replaces the whole metadata
184509
+ * object, so the newest copy is re-read immediately before merging rather
184510
+ * than trusting the one loaded on mount.
184511
+ */
184512
+ const handleSave = async () => {
184513
+ var _a;
184514
+ try {
184515
+ let latest = metadata;
184516
+ try {
184517
+ const fresh = (await fetchTenantMetadata([{ org: platformKey }]).unwrap());
184518
+ latest = (_a = fresh === null || fresh === void 0 ? void 0 : fresh.metadata) !== null && _a !== void 0 ? _a : latest;
184519
+ }
184520
+ catch (_b) {
184521
+ // Fall back to the copy loaded on mount.
184522
+ }
184523
+ await updateTenantMetadata([
184524
+ {
184525
+ org: platformKey,
184526
+ // @ts-expect-error requestBody is not part of the useUpdateTenantMetadataMutation Query Definition
184527
+ requestBody: {
184528
+ metadata: buildUserOnboardingFormMetadata(latest, {
184529
+ ...emptyUserOnboardingForm(),
184530
+ // An agent IS the onboarding here: picking one turns the flow
184531
+ // on, clearing it turns the flow off.
184532
+ enabled: !!agent,
184533
+ agent,
184534
+ }, new Date().toISOString()),
184535
+ },
184536
+ },
184537
+ ]).unwrap();
184538
+ setDirty(false);
184539
+ toast.success(t('profileOnboardingTab.savedToast'));
184540
+ }
184541
+ catch (_c) {
184542
+ toast.error(t('profileOnboardingTab.saveFailedToast'));
184543
+ }
184544
+ };
184545
+ if (isLoading) {
184546
+ return (jsxs("div", { className: "space-y-4 pt-4", children: [jsx(Skeleton, { className: "h-8 w-56" }), jsx(Skeleton, { className: "h-40 w-full" })] }));
184547
+ }
184548
+ if (error) {
184549
+ return jsx("p", { className: "pt-4 text-sm text-red-600", children: t('profileOnboardingTab.loadError') });
184550
+ }
184551
+ return (jsxs("div", { className: "space-y-5 pt-4", children: [jsxs("div", { className: "space-y-4 rounded-xl border border-gray-200 bg-white p-5 shadow-sm dark:border-gray-700 dark:bg-gray-900", children: [jsx(SearchSelect, { testId: "onboarding-agent", labels: {
184552
+ label: t('profileOnboardingTab.agentLabel'),
184553
+ placeholder: t('profileOnboardingTab.searchAgents'),
184554
+ typeToSearch: t('profileOnboardingTab.searchAgents'),
184555
+ searching: t('profileOnboardingTab.loadingAgents'),
184556
+ noResults: t('profileOnboardingTab.noAgents'),
184557
+ clear: t('profileOnboardingTab.clearAgent'),
184558
+ },
184559
+ // Focusing shows the platform's agents straight away; typing filters.
184560
+ minChars: 0,
184561
+ // The picker's own compact label would sit a size below the Heading
184562
+ // and Sub-heading fields beside it; match them instead.
184563
+ labelClassName: "text-sm font-medium", selected: agent
184564
+ ? { value: agent.mentor_unique_id, label: agent.name || agent.mentor_unique_id }
184565
+ : null, onSelect: (option) => update({ ...(agent !== null && agent !== void 0 ? agent : {}), mentor_unique_id: option.value, name: option.label }), onClear: () => update(null), searchTerm: searchTerm, onSearchTermChange: setSearchTerm, options: options, isLoading: isSearching }), agent && (jsxs("div", { className: "grid gap-3 sm:grid-cols-2", children: [jsxs("div", { className: "space-y-1.5", children: [jsx(Label$1, { htmlFor: "onboarding-agent-title", children: t('profileOnboardingTab.agentTitleLabel') }), jsx(Input, { id: "onboarding-agent-title", value: (_b = agent.title) !== null && _b !== void 0 ? _b : '', placeholder: t('profileOnboardingTab.agentTitlePlaceholder'), onChange: (event) => update({ ...agent, title: event.target.value }) })] }), jsxs("div", { className: "space-y-1.5", children: [jsx(Label$1, { htmlFor: "onboarding-agent-description", children: t('profileOnboardingTab.agentDescriptionLabel') }), jsx(Input, { id: "onboarding-agent-description", value: (_c = agent.description) !== null && _c !== void 0 ? _c : '', placeholder: t('profileOnboardingTab.agentDescriptionPlaceholder'), onChange: (event) => update({ ...agent, description: event.target.value }) })] })] })), !agent && jsx("p", { className: "text-xs text-gray-400", children: t('profileOnboardingTab.noAgentHint') })] }), jsxs("div", { className: "flex flex-wrap items-center justify-end gap-3", children: [dirty && (jsx("span", { className: "text-xs text-amber-600", children: t('profileOnboardingTab.unsavedChanges') })), jsx(Button$1, { onClick: handleSave, disabled: saving, className: "bg-gradient-to-r from-blue-600 to-blue-400 text-white hover:opacity-90", children: saving ? t('profileOnboardingTab.saving') : t('profileOnboardingTab.save') })] })] }));
183648
184566
  }
183649
184567
 
183650
184568
  const TabDescription = ({ icon, title, children }) => {
@@ -183654,7 +184572,7 @@ const TabDescription = ({ icon, title, children }) => {
183654
184572
  };
183655
184573
  const Admin = ({ tenant, onInviteClick, hasUserTabPermission = false, hasGroupsTabPermission = false, hasRolesTabPermission = false, hasPoliciesTabPermission = false, hasTeamsTabPermission = false, hasAlertsTabPermission = false, hasInviteUserPermission = false, hasCreateTeamPermission = false, onLoadGroupPermissions, rbacPermissions = {}, enableRbac = false, showGradebookTab = false, currentSpa, authSpaUrl, }) => {
183656
184574
  const t = useT();
183657
- return (jsx("div", { className: "border border-gray-200 rounded-lg p-6", children: jsxs(Tabs, { defaultValue: "users", "aria-label": t('profileAdmin.rbacManagementTabsAriaLabel'), children: [jsxs(TabsList, { "aria-label": t('profileAdmin.managementTabsAriaLabel'), className: "max-w-full overflow-x-auto justify-start px-1", children: [hasUserTabPermission && (jsx(TabsTrigger, { value: "users", children: t('profileAdmin.usersTab') })), hasGroupsTabPermission && (jsx(TabsTrigger, { value: "groups", children: t('profileAdmin.groupsTab') })), hasRolesTabPermission && (jsx(TabsTrigger, { value: "roles", children: t('profileAdmin.rolesTab') })), hasPoliciesTabPermission && (jsx(TabsTrigger, { value: "policies", children: t('profileAdmin.policiesTab') })), hasTeamsTabPermission && (jsx(TabsTrigger, { value: "teams", children: t('profileAdmin.teamsTab') })), hasAlertsTabPermission && (jsx(TabsTrigger, { value: "alerts", children: t('profileAdmin.alertsTab') })), jsx(TabsTrigger, { value: "applications", children: t('profileAdmin.applicationsTab') })] }), hasUserTabPermission && (jsxs(TabsContent, { className: "mt-4", value: "users", children: [jsx(TabDescription, { icon: jsx(Users, { className: "w-5 h-5" }), title: t('profileAdmin.usersTab'), children: t('profileAdmin.usersDescription') }), jsx(UsersTab, { tenant: tenant, onInviteClick: onInviteClick, currentSpa: currentSpa, showGradebookTab: showGradebookTab })] })), hasGroupsTabPermission && (jsxs(TabsContent, { className: "mt-4", value: "groups", children: [jsx(TabDescription, { icon: jsx(UsersRound, { className: "w-5 h-5" }), title: t('profileAdmin.groupsTab'), children: t('profileAdmin.groupsDescription') }), jsx(GroupsTab, { tenant: tenant })] })), hasRolesTabPermission && (jsxs(TabsContent, { className: "mt-4", value: "roles", children: [jsx(TabDescription, { icon: jsx(UserCog, { className: "w-5 h-5" }), title: t('profileAdmin.rolesTab'), children: t('profileAdmin.rolesDescription') }), jsx(RolesTab, { tenant: tenant })] })), hasPoliciesTabPermission && (jsxs(TabsContent, { className: "mt-4", value: "policies", children: [jsx(TabDescription, { icon: jsx(ScrollText, { className: "w-5 h-5" }), title: t('profileAdmin.policiesTab'), children: t('profileAdmin.policiesDescription') }), jsx(PoliciesTab, { tenant: tenant })] })), hasTeamsTabPermission && (jsxs(TabsContent, { className: "mt-4", value: "teams", children: [jsx(TabDescription, { icon: jsx(Shield, { className: "w-5 h-5" }), title: t('profileAdmin.teamsTab'), children: t('profileAdmin.teamsDescription') }), jsx(GroupsTab, { tenant: tenant, isTeam: true, onInviteClick: onInviteClick, hasInviteUserPermission: hasInviteUserPermission, hasCreateTeamPermission: hasCreateTeamPermission, onLoadGroupPermissions: onLoadGroupPermissions, rbacPermissions: rbacPermissions, enableRbac: enableRbac })] })), hasAlertsTabPermission && (jsxs(TabsContent, { className: "mt-4", value: "alerts", children: [jsx(TabDescription, { icon: jsx(BellRing, { className: "w-5 h-5" }), title: t('profileAdmin.alertsTab'), children: t('profileAdmin.alertsDescription') }), jsx(AlertsTab, { tenant: tenant })] })), jsxs(TabsContent, { className: "mt-4", value: "applications", children: [jsx(TabDescription, { icon: jsx(ClipboardList, { className: "w-5 h-5" }), title: t('profileAdmin.applicationsTab'), children: t('profileAdmin.applicationsTabDescription') }), jsx(ApplicationsTab, { platformKey: tenant, authSpaUrl: authSpaUrl })] })] }) }));
184575
+ return (jsx("div", { className: "border border-gray-200 rounded-lg p-6", children: jsxs(Tabs, { defaultValue: "users", "aria-label": t('profileAdmin.rbacManagementTabsAriaLabel'), children: [jsxs(TabsList, { "aria-label": t('profileAdmin.managementTabsAriaLabel'), className: "max-w-full overflow-x-auto justify-start px-1", children: [hasUserTabPermission && (jsx(TabsTrigger, { value: "users", children: t('profileAdmin.usersTab') })), hasGroupsTabPermission && (jsx(TabsTrigger, { value: "groups", children: t('profileAdmin.groupsTab') })), hasRolesTabPermission && (jsx(TabsTrigger, { value: "roles", children: t('profileAdmin.rolesTab') })), hasPoliciesTabPermission && (jsx(TabsTrigger, { value: "policies", children: t('profileAdmin.policiesTab') })), hasTeamsTabPermission && (jsx(TabsTrigger, { value: "teams", children: t('profileAdmin.teamsTab') })), hasAlertsTabPermission && (jsx(TabsTrigger, { value: "alerts", children: t('profileAdmin.alertsTab') })), jsx(TabsTrigger, { value: "applications", children: t('profileAdmin.applicationsTab') }), jsx(TabsTrigger, { value: "onboarding", children: t('profileAdmin.onboardingTab') })] }), hasUserTabPermission && (jsxs(TabsContent, { className: "mt-4", value: "users", children: [jsx(TabDescription, { icon: jsx(Users, { className: "w-5 h-5" }), title: t('profileAdmin.usersTab'), children: t('profileAdmin.usersDescription') }), jsx(UsersTab, { tenant: tenant, onInviteClick: onInviteClick, currentSpa: currentSpa, showGradebookTab: showGradebookTab })] })), hasGroupsTabPermission && (jsxs(TabsContent, { className: "mt-4", value: "groups", children: [jsx(TabDescription, { icon: jsx(UsersRound, { className: "w-5 h-5" }), title: t('profileAdmin.groupsTab'), children: t('profileAdmin.groupsDescription') }), jsx(GroupsTab, { tenant: tenant })] })), hasRolesTabPermission && (jsxs(TabsContent, { className: "mt-4", value: "roles", children: [jsx(TabDescription, { icon: jsx(UserCog, { className: "w-5 h-5" }), title: t('profileAdmin.rolesTab'), children: t('profileAdmin.rolesDescription') }), jsx(RolesTab, { tenant: tenant })] })), hasPoliciesTabPermission && (jsxs(TabsContent, { className: "mt-4", value: "policies", children: [jsx(TabDescription, { icon: jsx(ScrollText, { className: "w-5 h-5" }), title: t('profileAdmin.policiesTab'), children: t('profileAdmin.policiesDescription') }), jsx(PoliciesTab, { tenant: tenant })] })), hasTeamsTabPermission && (jsxs(TabsContent, { className: "mt-4", value: "teams", children: [jsx(TabDescription, { icon: jsx(Shield, { className: "w-5 h-5" }), title: t('profileAdmin.teamsTab'), children: t('profileAdmin.teamsDescription') }), jsx(GroupsTab, { tenant: tenant, isTeam: true, onInviteClick: onInviteClick, hasInviteUserPermission: hasInviteUserPermission, hasCreateTeamPermission: hasCreateTeamPermission, onLoadGroupPermissions: onLoadGroupPermissions, rbacPermissions: rbacPermissions, enableRbac: enableRbac })] })), hasAlertsTabPermission && (jsxs(TabsContent, { className: "mt-4", value: "alerts", children: [jsx(TabDescription, { icon: jsx(BellRing, { className: "w-5 h-5" }), title: t('profileAdmin.alertsTab'), children: t('profileAdmin.alertsDescription') }), jsx(AlertsTab, { tenant: tenant })] })), jsxs(TabsContent, { className: "mt-4", value: "applications", children: [jsx(TabDescription, { icon: jsx(ClipboardList, { className: "w-5 h-5" }), title: t('profileAdmin.applicationsTab'), children: t('profileAdmin.applicationsTabDescription') }), jsx(ApplicationsTab, { platformKey: tenant, authSpaUrl: authSpaUrl })] }), jsxs(TabsContent, { className: "mt-4", value: "onboarding", children: [jsx(TabDescription, { icon: jsx(UserPlus, { className: "w-5 h-5" }), title: t('profileAdmin.onboardingTab'), children: t('profileAdmin.onboardingTabDescription') }), jsx(OnboardingTab, { platformKey: tenant })] })] }) }));
183658
184576
  };
183659
184577
 
183660
184578
  function DeleteApiModal$1({ isOpen, onClose, apiKey, tenantKey }) {
@@ -190002,34 +190920,6 @@ TableCell$1.displayName = "TableCell";
190002
190920
  const TableCaption = React.forwardRef(({ className, ...props }, ref) => (jsx("caption", { ref: ref, className: cn("mt-4 text-sm text-muted-foreground", className), ...props })));
190003
190921
  TableCaption.displayName = "TableCaption";
190004
190922
 
190005
- /**
190006
- * Single-select searchable picker: a deb-ounce-agnostic input + absolute
190007
- * results dropdown (the add-access pattern), collapsing to a removable chip
190008
- * once something is picked. The caller owns the search term and the fetched
190009
- * options so any query hook can back it.
190010
- */
190011
- function SearchSelect({ labels, selected, onSelect, onClear, searchTerm, onSearchTermChange, options, isLoading, minChars = 2, testId, }) {
190012
- const [isOpen, setIsOpen] = React__default.useState(false);
190013
- const blurTimeout = React__default.useRef(null);
190014
- React__default.useEffect(() => () => {
190015
- if (blurTimeout.current)
190016
- clearTimeout(blurTimeout.current);
190017
- }, []);
190018
- if (selected) {
190019
- return (jsxs("div", { className: "space-y-1.5", children: [jsx(Label$1, { className: "text-xs font-medium text-gray-700", children: labels.label }), jsxs("div", { className: "flex items-center justify-between gap-2 rounded-md border border-gray-200 bg-gray-50 px-3 py-2", "data-testid": `${testId}-selected`, children: [jsxs("div", { className: "min-w-0", children: [jsx("p", { className: "truncate text-sm font-medium text-gray-900", children: selected.label }), selected.sublabel && (jsx("p", { className: "truncate text-xs text-gray-600", children: selected.sublabel }))] }), jsxs(Button$1, { type: "button", size: "icon", variant: "ghost", className: "h-6 w-6 flex-shrink-0 text-gray-500 hover:text-red-600", onClick: onClear, "data-testid": `${testId}-clear`, children: [jsx(X$2, { className: "h-3.5 w-3.5", "aria-hidden": "true" }), jsx("span", { className: "sr-only", children: labels.clear })] })] })] }));
190020
- }
190021
- return (jsxs("div", { className: "space-y-1.5", children: [jsx(Label$1, { className: "text-xs font-medium text-gray-700", htmlFor: `${testId}-input`, children: labels.label }), jsxs("div", { className: "relative", children: [jsx(Input, { id: `${testId}-input`, className: "focus-visible:border-blue-500 focus-visible:ring-1 focus-visible:ring-blue-500", value: searchTerm, onChange: (e) => onSearchTermChange(e.target.value), onFocus: () => {
190022
- if (blurTimeout.current)
190023
- clearTimeout(blurTimeout.current);
190024
- setIsOpen(true);
190025
- }, onBlur: () => {
190026
- blurTimeout.current = setTimeout(() => setIsOpen(false), 100);
190027
- }, placeholder: labels.placeholder, autoComplete: "off", "aria-autocomplete": "list", "aria-expanded": isOpen, "data-testid": `${testId}-input` }), isOpen && (jsx("div", { className: "absolute top-full right-0 left-0 z-50 mt-1 max-h-64 overflow-y-auto rounded-md border border-gray-200 bg-white shadow-lg", "data-testid": `${testId}-results`, children: searchTerm.trim().length < minChars ? (jsx("div", { className: "px-3 py-2 text-sm text-gray-600", children: labels.typeToSearch })) : isLoading ? (jsxs("div", { className: "flex items-center gap-2 px-3 py-2 text-sm text-gray-600", children: [jsx(LoaderCircle, { className: "h-3.5 w-3.5 animate-spin", "aria-hidden": "true" }), labels.searching] })) : options.length > 0 ? (options.map((option) => (jsxs("button", { type: "button", className: "flex w-full flex-col items-start gap-0.5 px-3 py-2 text-left hover:bg-gray-50", onMouseDown: (event) => event.preventDefault(), onClick: () => {
190028
- onSelect(option);
190029
- setIsOpen(false);
190030
- }, "data-testid": `${testId}-option-${option.value}`, children: [jsx("span", { className: "text-sm font-medium text-gray-900", children: option.label }), option.sublabel && (jsx("span", { className: "text-xs text-gray-600", children: option.sublabel }))] }, option.value)))) : (jsx("div", { className: "px-3 py-2 text-sm text-gray-600", "data-testid": `${testId}-no-results`, children: labels.noResults })) }))] })] }));
190031
- }
190032
-
190033
190923
  /**
190034
190924
  * The shared `Profile` viewer in a dialog — the same modal the tenant
190035
190925
  * Management tab opens when a user row is clicked. Controlled variant for
@@ -192836,7 +193726,7 @@ function ItemSearchDropdown({ platformKey, onSelect, }) {
192836
193726
  }, children: [jsx("div", { className: "flex-1 min-w-0", children: jsx("span", { className: "text-sm font-medium text-gray-900 dark:text-gray-100 block truncate", children: item.name }) }), jsx(Badge, { variant: "secondary", className: "text-xs shrink-0 capitalize", children: displayItemType(item.itemType) })] }, `${item.itemType}-${item.id}`)))) : isFetching ? (jsx("div", { className: "px-3 py-4 text-center text-sm text-gray-400", children: t('monetizationItemSearchDropdown.searching') })) : (jsx("div", { className: "px-3 py-4 text-center text-sm text-gray-400", children: t('monetizationItemSearchDropdown.noItemsFound') })) }))] }));
192837
193727
  }
192838
193728
 
192839
- const PAGE_SIZE$7 = 8;
193729
+ const PAGE_SIZE$a = 8;
192840
193730
  function PaywalledItemsList({ platformKey, onSelectItem, onAddCustomItem, }) {
192841
193731
  const t = useT();
192842
193732
  const [page, setPage] = useState(1);
@@ -192844,7 +193734,7 @@ function PaywalledItemsList({ platformKey, onSelectItem, onAddCustomItem, }) {
192844
193734
  const { data: paywalls, isLoading } = useListPaywallsQuery({
192845
193735
  platform_key: platformKey,
192846
193736
  page,
192847
- page_size: PAGE_SIZE$7,
193737
+ page_size: PAGE_SIZE$a,
192848
193738
  ...(statusFilter !== 'all' && { is_enabled: statusFilter === 'active' }),
192849
193739
  }, { refetchOnMountOrArgChange: true });
192850
193740
  return (jsxs("div", { className: "space-y-4", children: [jsx(Card, { className: "shadow-sm border", style: { borderColor: 'oklch(.922 0 0)' }, children: jsxs(CardContent, { className: "p-4", children: [jsx("h4", { className: "text-sm font-medium text-gray-700 dark:text-gray-300 mb-3", children: t('monetizationPaywalledItemsList.configureItemForSale') }), jsxs("div", { className: "flex items-center gap-2", children: [jsx(ItemSearchDropdown, { platformKey: platformKey, onSelect: (itemType, uniqueId, name) => onSelectItem(itemType, uniqueId, name) }), jsx(Button$1, { variant: "outline", size: "icon", onClick: onAddCustomItem, className: "shrink-0 cursor-pointer", title: t('monetizationPaywalledItemsList.addCustomItemTitle'), children: jsx(Plus, { className: "h-4 w-4" }) })] })] }) }), jsxs("div", { className: "space-y-2", children: [jsxs("div", { className: "flex items-center justify-between", children: [jsx("h4", { className: "text-sm font-medium text-gray-500", children: t('monetizationPaywalledItemsList.configuredItems') }), jsxs(Select$1, { value: statusFilter, onValueChange: (v) => {
@@ -192867,7 +193757,7 @@ function PaywalledItemsList({ platformKey, onSelectItem, onAddCustomItem, }) {
192867
193757
  : 'bg-gray-100 text-gray-500 border-gray-200 hover:bg-gray-100', children: pw.is_enabled
192868
193758
  ? t('monetizationPaywalledItemsList.statusActive')
192869
193759
  : t('monetizationPaywalledItemsList.statusDisabled') })] }) }, `${pw.item_type}-${pw.item_id}`));
192870
- }), jsx(AdvancedPagination, { variant: "footer", className: "mt-2 rounded-lg border", currentPage: page, totalPages: Math.ceil(paywalls.count / PAGE_SIZE$7), onPageChange: setPage, totalCount: paywalls.count, itemsPerPage: PAGE_SIZE$7, itemLabel: "items" })] })) : (jsx("p", { className: "text-sm text-gray-400 text-center py-6", children: statusFilter !== 'all'
193760
+ }), jsx(AdvancedPagination, { variant: "footer", className: "mt-2 rounded-lg border", currentPage: page, totalPages: Math.ceil(paywalls.count / PAGE_SIZE$a), onPageChange: setPage, totalCount: paywalls.count, itemsPerPage: PAGE_SIZE$a, itemLabel: "items" })] })) : (jsx("p", { className: "text-sm text-gray-400 text-center py-6", children: statusFilter !== 'all'
192871
193761
  ? t('monetizationPaywalledItemsList.noFilteredItemsFound', { status: statusFilter })
192872
193762
  : t('monetizationPaywalledItemsList.noItemsConfigured') }))] })] }));
192873
193763
  }
@@ -220700,6 +221590,12 @@ AlertDialogAction.displayName = Action.displayName;
220700
221590
  const AlertDialogCancel = React.forwardRef(({ className, ...props }, ref) => (jsx(Cancel, { ref: ref, className: cn(buttonVariants({ variant: 'outline' }), 'mt-2 sm:mt-0', className), ...props })));
220701
221591
  AlertDialogCancel.displayName = Cancel.displayName;
220702
221592
 
221593
+ // Notification bodies are arbitrary (often email) HTML: long unbroken URLs and
221594
+ // fixed-width tables would otherwise bleed out of the panel. Break long words,
221595
+ // cap every descendant at the container width, and let anything that still
221596
+ // cannot shrink scroll inside the body instead of stretching the layout.
221597
+ cn('prose prose-sm max-w-none text-gray-700', 'overflow-x-auto break-words [overflow-wrap:anywhere]', '[&_*]:max-w-full', '[&_a]:break-all', '[&_img]:h-auto', '[&_pre]:overflow-x-auto [&_pre]:whitespace-pre-wrap', '[&_code]:whitespace-pre-wrap');
221598
+
220703
221599
  const THEMES = { light: '', dark: '.dark' };
220704
221600
  const ChartContext = React.createContext(null);
220705
221601
  function useChart() {
@@ -258028,7 +258924,7 @@ function RetrievedDocumentsButton({ sessionId }) {
258028
258924
  return (jsxs(Fragment$1, { children: [jsxs(Button$1, { variant: "outline", size: "sm", className: "flex items-center gap-2 border-gray-200 bg-white text-gray-700 hover:bg-gray-50", onClick: () => setIsOpen(true), children: [jsx(FileText, { className: "h-4 w-4 text-blue-600" }), jsx("span", { children: t('retrievedDocumentsButton.title') })] }), jsx(Dialog, { open: isOpen, onOpenChange: setIsOpen, children: jsxs(DialogContent, { className: "flex max-h-[80vh] flex-col gap-0 p-0 sm:max-w-[425px] md:max-w-[600px]", children: [jsx(DialogHeader, { className: "border-b px-4 py-2", children: jsxs(DialogTitle, { className: "flex items-center gap-2 text-base font-medium text-[#646464]", children: [jsx(FileText, { className: "h-5 w-5 text-blue-600" }), t('retrievedDocumentsButton.title')] }) }), jsx("div", { className: "flex-1 overflow-hidden", children: jsx(DocumentSidebar, { isModal: true, sessionId: sessionId }) })] }) })] }));
258029
258925
  }
258030
258926
 
258031
- const PAGE_SIZE$6 = 10;
258927
+ const PAGE_SIZE$9 = 10;
258032
258928
  const MemoryMenu = ({ onClose, mentorId, tenantKey, username }) => {
258033
258929
  const t = useT();
258034
258930
  const [page, setPage] = useState(1);
@@ -258046,7 +258942,7 @@ const MemoryMenu = ({ onClose, mentorId, tenantKey, username }) => {
258046
258942
  mentorId,
258047
258943
  params: {
258048
258944
  page,
258049
- page_size: PAGE_SIZE$6,
258945
+ page_size: PAGE_SIZE$9,
258050
258946
  my_memory: true,
258051
258947
  },
258052
258948
  }, {
@@ -261929,7 +262825,7 @@ function DeleteItemConfirm({ isOpen, onClose, tenantKey, username, datasetName,
261929
262825
  : t('benchmarksDeleteItemConfirm.delete') })] })] }) }));
261930
262826
  }
261931
262827
 
261932
- const PAGE_SIZE$5 = 10;
262828
+ const PAGE_SIZE$8 = 10;
261933
262829
  function BenchmarkItemsModal({ isOpen, onClose, tenantKey, username, datasetName }) {
261934
262830
  var _a;
261935
262831
  const t = useT();
@@ -261941,17 +262837,17 @@ function BenchmarkItemsModal({ isOpen, onClose, tenantKey, username, datasetName
261941
262837
  userId: username,
261942
262838
  datasetName,
261943
262839
  page,
261944
- limit: PAGE_SIZE$5,
262840
+ limit: PAGE_SIZE$8,
261945
262841
  });
261946
262842
  const items = (_a = data === null || data === void 0 ? void 0 : data.results) !== null && _a !== void 0 ? _a : [];
261947
- const totalPages = evalTotalPages(data === null || data === void 0 ? void 0 : data.count, PAGE_SIZE$5);
262843
+ const totalPages = evalTotalPages(data === null || data === void 0 ? void 0 : data.count, PAGE_SIZE$8);
261948
262844
  return (jsx(Dialog, { open: isOpen, onOpenChange: (open) => !open && onClose(), children: jsxs(DialogContent, { "aria-label": "benchmark-items", className: "w-full max-w-4xl max-h-[90vh] overflow-y-auto", children: [jsxs(DialogHeader, { children: [jsx(DialogTitle, { children: datasetName }), jsx(DialogDescription, { children: t('benchmarksBenchmarkItemsModal.description') })] }), jsx("div", { className: "flex justify-end mb-4", children: jsxs(Button$1, { onClick: () => setShowAdd(true), className: "bg-gradient-to-r from-[#2563EB] to-[#93C5FD] hover:opacity-90 text-white h-[35px]", children: [jsx(Plus, { className: "h-4 w-4 mr-1" }), t('benchmarksBenchmarkItemsModal.addItems')] }) }), isLoading ? (jsx("div", { className: "flex justify-center items-center h-40", 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-4 py-3 text-left font-medium text-gray-500 dark:text-gray-400 w-[45%]", children: t('benchmarksBenchmarkItemsModal.questionColumn') }), jsx("th", { className: "px-4 py-3 text-left font-medium text-gray-500 dark:text-gray-400 w-[45%]", children: t('benchmarksBenchmarkItemsModal.answerColumn') }), jsx("th", { className: "px-4 py-3 text-right font-medium text-gray-500 dark:text-gray-400 w-[10%]", children: t('benchmarksBenchmarkItemsModal.actionsColumn') })] }) }), jsxs("tbody", { className: "divide-y divide-gray-200 dark:divide-gray-600", children: [items.map((item) => {
261949
262845
  var _a;
261950
262846
  return (jsxs("tr", { className: "align-top", children: [jsx("td", { className: "px-4 py-3 text-gray-900 dark:text-gray-100", children: jsx("div", { className: "line-clamp-3 break-words", children: typeof item.input === 'string' ? item.input : JSON.stringify(item.input) }) }), jsx("td", { className: "px-4 py-3 text-gray-600 dark:text-gray-300", children: jsx("div", { className: "line-clamp-3 break-words", children: (_a = item.expected_output) !== null && _a !== void 0 ? _a : jsx("span", { className: "text-gray-400", children: "\u2014" }) }) }), jsx("td", { className: "px-4 py-3 text-right", children: jsx(Button$1, { variant: "ghost", size: "sm", "aria-label": t('benchmarksBenchmarkItemsModal.deleteItemAriaLabel'), onClick: () => setDeleteItemId(item.id), children: jsx(Trash2, { className: "h-4 w-4 text-red-500" }) }) })] }, item.id));
261951
262847
  }), items.length === 0 && (jsx("tr", { children: jsx("td", { colSpan: 3, className: "px-4 py-8 text-center text-gray-500 dark:text-gray-400", children: t('benchmarksBenchmarkItemsModal.empty') }) }))] })] }) }), totalPages > 1 && (jsx("div", { className: "mt-6", children: jsx(AdvancedPagination, { totalPages: totalPages, currentPage: page, onPageChange: setPage }) }))] })), jsx(AddItemsModal, { isOpen: showAdd, onClose: () => setShowAdd(false), tenantKey: tenantKey, username: username, datasetName: datasetName }), deleteItemId && (jsx(DeleteItemConfirm, { isOpen: !!deleteItemId, onClose: () => setDeleteItemId(null), tenantKey: tenantKey, username: username, datasetName: datasetName, itemId: deleteItemId }))] }) }));
261952
262848
  }
261953
262849
 
261954
- const PAGE_SIZE$4 = 10;
262850
+ const PAGE_SIZE$7 = 10;
261955
262851
  function BenchmarksTab({ tenantKey, username, }) {
261956
262852
  var _a;
261957
262853
  const t = useT();
@@ -261963,13 +262859,13 @@ function BenchmarksTab({ tenantKey, username, }) {
261963
262859
  org: tenantKey,
261964
262860
  userId: username,
261965
262861
  page,
261966
- limit: PAGE_SIZE$4,
262862
+ limit: PAGE_SIZE$7,
261967
262863
  });
261968
262864
  const benchmarks = (_a = data === null || data === void 0 ? void 0 : data.results) !== null && _a !== void 0 ? _a : [];
261969
262865
  const filtered = searchQuery.trim()
261970
262866
  ? benchmarks.filter((benchmark) => benchmark.name.toLowerCase().includes(searchQuery.toLowerCase()))
261971
262867
  : benchmarks;
261972
- const totalPages = evalTotalPages(data === null || data === void 0 ? void 0 : data.count, PAGE_SIZE$4);
262868
+ const totalPages = evalTotalPages(data === null || data === void 0 ? void 0 : data.count, PAGE_SIZE$7);
261973
262869
  return (jsxs("div", { className: "mt-4", children: [jsxs("div", { className: "flex justify-between items-center gap-1 flex-wrap", children: [jsxs("div", { className: "relative mb-6 max-w-sm w-full sm:w-auto", 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) => setSearchQuery(event.target.value), placeholder: t('benchmarksIndex.searchPlaceholder'), className: "pl-10 pr-10 focus:ring-blue-500 focus:border-blue-500 h-[35px]", "aria-label": t('benchmarksIndex.searchAriaLabel') })] }), jsx("div", { className: "mb-6", children: jsxs(Button$1, { className: "bg-gradient-to-r from-[#2563EB] to-[#93C5FD] hover:opacity-90 text-white h-[35px]", onClick: () => setShowCreate(true), children: [jsx(Plus, { className: "h-4 w-4 mr-1" }), t('benchmarksIndex.newBenchmark')] }) })] }), 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-[28%]", children: t('benchmarksIndex.nameColumn') }), jsx("th", { className: "px-6 py-3 text-left font-medium text-gray-500 dark:text-gray-400 w-[36%]", children: t('benchmarksIndex.descriptionColumn') }), jsx("th", { className: "px-6 py-3 text-left font-medium text-gray-500 dark:text-gray-400 w-[20%]", children: t('benchmarksIndex.createdColumn') }), jsx("th", { className: "px-6 py-3 text-right font-medium text-gray-500 dark:text-gray-400 w-[16%]", children: t('benchmarksIndex.actionsColumn') })] }) }), jsxs("tbody", { className: "divide-y divide-gray-200 dark:divide-gray-600", children: [filtered.map((benchmark) => (jsxs("tr", { children: [jsx("td", { className: "px-6 py-4 text-gray-900 dark:text-gray-100 max-w-0", children: jsx("div", { className: "truncate font-medium", children: benchmark.name }) }), jsx("td", { className: "px-6 py-4 text-gray-600 dark:text-gray-300 max-w-0", children: jsx("div", { className: "truncate", children: benchmark.description || '—' }) }), jsx("td", { className: "px-6 py-4 text-gray-600 dark:text-gray-300 whitespace-nowrap", children: benchmark.created_at
261974
262870
  ? formatDistanceToNow(new Date(benchmark.created_at), {
261975
262871
  addSuffix: true,
@@ -261979,6 +262875,514 @@ function BenchmarksTab({ tenantKey, username, }) {
261979
262875
  }), onClick: () => setViewBenchmark(benchmark.name), children: jsx(Eye, { className: "h-4 w-4" }) }) }) })] }, benchmark.name))), filtered.length === 0 && (jsx("tr", { children: jsx("td", { colSpan: 4, className: "px-6 py-8 text-center text-gray-500 dark:text-gray-400", children: isFetching ? t('benchmarksIndex.loading') : t('benchmarksIndex.empty') }) }))] })] }) }), totalPages > 1 && (jsx("div", { className: "mt-6", children: jsx(AdvancedPagination, { totalPages: totalPages, currentPage: page, onPageChange: setPage }) }))] })), jsx(CreateBenchmarkModal, { isOpen: showCreate, onClose: () => setShowCreate(false), tenantKey: tenantKey, username: username }), viewBenchmark && (jsx(BenchmarkItemsModal, { isOpen: !!viewBenchmark, onClose: () => setViewBenchmark(null), tenantKey: tenantKey, username: username, datasetName: viewBenchmark }))] }));
261980
262876
  }
261981
262877
 
262878
+ /** Matches the server-side cap on the global memories listing. */
262879
+ const PAGE_SIZE$6 = 25;
262880
+ /**
262881
+ * Popup for managing one user's global memories. Reads them the way the
262882
+ * profile preview does — the caller in the path, the managed user identified
262883
+ * by their id (username) in `user_id` — while writes address the managed
262884
+ * user's path directly, which the backend resolves for admin/RBAC callers.
262885
+ * The list itself is the same {@link MemoriesList} the profile Memory tab
262886
+ * renders.
262887
+ */
262888
+ function UserMemoriesModal({ isOpen, onClose, tenantKey, adminUsername, user, }) {
262889
+ var _a, _b, _c;
262890
+ const t = useT();
262891
+ const [page, setPage] = useState(1);
262892
+ const [showAdd, setShowAdd] = useState(false);
262893
+ const [editingMemory, setEditingMemory] = useState(null);
262894
+ const [deletingId, setDeletingId] = useState(null);
262895
+ const { data: memoriesData, isLoading, error, } = useGetGlobalMemoriesQuery({
262896
+ org: tenantKey,
262897
+ userId: adminUsername,
262898
+ // `user_id` must be the managed user's id (username) — the backend does
262899
+ // not resolve emails here, so passing one returns an empty list.
262900
+ params: { page, page_size: PAGE_SIZE$6, user_id: user.username },
262901
+ });
262902
+ const memories = (_a = memoriesData === null || memoriesData === void 0 ? void 0 : memoriesData.results) !== null && _a !== void 0 ? _a : [];
262903
+ const totalPages = (memoriesData === null || memoriesData === void 0 ? void 0 : memoriesData.count) ? Math.ceil(memoriesData.count / PAGE_SIZE$6) : 0;
262904
+ const isForbidden = !!error && error.status === 403;
262905
+ // The managed user's capture/personalization toggles, addressed through
262906
+ // their path the way every admin write here is. Hidden unless they load.
262907
+ const { data: settings } = useGetUserMemorySettingsQuery({
262908
+ org: tenantKey,
262909
+ userId: user.username,
262910
+ });
262911
+ const [updateSettings, { isLoading: isUpdatingSettings }] = useUpdateUserMemorySettingsMutation();
262912
+ const handleToggleSetting = async (key, checked) => {
262913
+ try {
262914
+ await updateSettings({
262915
+ org: tenantKey,
262916
+ userId: user.username,
262917
+ settings: { [key]: checked },
262918
+ }).unwrap();
262919
+ toast.success(t('memoryMemoryTab.memorySettingUpdated'));
262920
+ }
262921
+ catch (_a) {
262922
+ toast.error(t('memoryMemoryTab.failedToUpdateMemorySetting'));
262923
+ }
262924
+ };
262925
+ const [deleteMemory] = useDeleteGlobalMemoryMutation();
262926
+ const handleDeleteMemory = async (memory) => {
262927
+ setDeletingId(memory.id);
262928
+ try {
262929
+ await deleteMemory({
262930
+ org: tenantKey,
262931
+ userId: user.username,
262932
+ memoryId: memory.id,
262933
+ }).unwrap();
262934
+ toast.success(t('memoryAdminUserMemoriesModal.memoryDeleted'));
262935
+ }
262936
+ catch (deleteError) {
262937
+ if ((deleteError === null || deleteError === void 0 ? void 0 : deleteError.status) === 403) {
262938
+ toast.error(t('memoryAdminTab.forbidden'));
262939
+ }
262940
+ else {
262941
+ toast.error(t('memoryAdminUserMemoriesModal.failedToDeleteMemory'));
262942
+ }
262943
+ }
262944
+ finally {
262945
+ setDeletingId(null);
262946
+ }
262947
+ };
262948
+ return (jsx(Dialog, { open: isOpen, onOpenChange: (open) => !open && onClose(), children: jsxs(DialogContent, { "data-testid": "user-memories-modal", "aria-label": "user-global-memories", className: "w-full max-w-3xl max-h-[90vh] overflow-y-auto", children: [jsxs(DialogHeader, { children: [jsxs(DialogTitle, { children: [t('memoryAdminUserMemoriesModal.title'), " \u2014 ", user.email || user.username] }), jsx(DialogDescription, { children: t('memoryAdminUserMemoriesModal.description') })] }), settings && (jsxs("div", { className: "space-y-4", children: [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: (_b = settings.auto_capture_enabled) !== null && _b !== void 0 ? _b : false, onCheckedChange: (checked) => handleToggleSetting('auto_capture_enabled', checked), disabled: isUpdatingSettings, "aria-label": t('memoryMemoryTab.autoCaptureAriaLabel', {
262949
+ state: settings.auto_capture_enabled
262950
+ ? t('memoryMemoryTab.stateEnabled')
262951
+ : t('memoryMemoryTab.stateDisabled'),
262952
+ }), className: "cursor-pointer data-[state=checked]:bg-blue-500 flex-shrink-0" })] }), 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.useMemoryLabelTitle') }), jsx("p", { className: "text-xs text-gray-500 dark:text-gray-400 mt-1", children: t('memoryMemoryTab.useMemoryLabelDesc') })] }), jsx(Switch, { checked: (_c = settings.use_memory_in_responses) !== null && _c !== void 0 ? _c : false, onCheckedChange: (checked) => handleToggleSetting('use_memory_in_responses', checked), disabled: isUpdatingSettings, "aria-label": t('memoryMemoryTab.useMemoryAriaLabel', {
262953
+ state: settings.use_memory_in_responses
262954
+ ? t('memoryMemoryTab.stateEnabled')
262955
+ : t('memoryMemoryTab.stateDisabled'),
262956
+ }), className: "cursor-pointer data-[state=checked]:bg-blue-500 flex-shrink-0" })] })] })), !isForbidden && (jsx("div", { className: "flex justify-end mb-4", children: jsxs(Button$1, { "data-testid": "user-memories-add", variant: "outline", size: "sm", onClick: () => setShowAdd(true), className: "text-xs", children: [jsx(Plus, { className: "h-3 w-3 mr-1" }), t('memoryAdminUserMemoriesModal.addMemoryButton')] }) })), isForbidden ? (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('memoryAdminUserMemoriesModal.forbidden') }) })) : error ? (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('memoryAdminUserMemoriesModal.failedToLoad') }) })) : (jsx(MemoriesList, { memories: memories, isLoading: isLoading, emptyText: t('memoryAdminUserMemoriesModal.noMemories'), deletingId: deletingId, onEdit: setEditingMemory, onDelete: handleDeleteMemory, totalPages: totalPages, currentPage: page, onPageChange: setPage })), jsx(AddMemoryDialog, { open: showAdd, onOpenChange: setShowAdd, org: tenantKey, username: user.username }), editingMemory && (jsx(EditMemoryDialog, { open: !!editingMemory, onOpenChange: (open) => !open && setEditingMemory(null), org: tenantKey, username: user.username, memory: editingMemory }))] }) }));
262957
+ }
262958
+
262959
+ const PAGE_SIZE$5 = 10;
262960
+ const SEARCH_DEBOUNCE_MS = 300;
262961
+ /**
262962
+ * Tenant users table with server-side search. Opening a row shows that user's
262963
+ * global memories in a popup where the admin can manage them.
262964
+ */
262965
+ function GlobalMemoriesSection({ tenantKey, username }) {
262966
+ var _a;
262967
+ const t = useT();
262968
+ const [page, setPage] = useState(1);
262969
+ const [searchQuery, setSearchQuery] = useState('');
262970
+ const [debouncedSearch, setDebouncedSearch] = useState(searchQuery);
262971
+ const [selectedUser, setSelectedUser] = useState(null);
262972
+ // Same debounce contract as the Management tab's user search: terms shorter
262973
+ // than three characters search as empty. Bailing out on an unchanged value
262974
+ // keeps the mount-time timer from resetting a page the user already turned.
262975
+ useEffect(() => {
262976
+ const handler = setTimeout(() => {
262977
+ setDebouncedSearch((previous) => {
262978
+ const next = searchQuery.length > 2 ? searchQuery : '';
262979
+ return previous === next ? previous : next;
262980
+ });
262981
+ }, SEARCH_DEBOUNCE_MS);
262982
+ return () => clearTimeout(handler);
262983
+ }, [searchQuery]);
262984
+ // A new search term invalidates the current page index.
262985
+ useEffect(() => {
262986
+ setPage(1);
262987
+ }, [debouncedSearch]);
262988
+ const { data, isLoading, isFetching, error } = usePlatformUsersQuery({
262989
+ platform_key: tenantKey,
262990
+ platform_org: tenantKey,
262991
+ page,
262992
+ page_size: PAGE_SIZE$5,
262993
+ query: debouncedSearch,
262994
+ return_policies: 'false',
262995
+ });
262996
+ const users = useMemo(() => {
262997
+ var _a;
262998
+ // `results` is a bare array unless policies were requested, in which case
262999
+ // the users sit under `results.data`.
263000
+ const results = data === null || data === void 0 ? void 0 : data.results;
263001
+ const platformUsers = Array.isArray(results)
263002
+ ? results
263003
+ : ((_a = results === null || results === void 0 ? void 0 : results.data) !== null && _a !== void 0 ? _a : []);
263004
+ // A user without a username cannot be addressed by the memory endpoints.
263005
+ return platformUsers
263006
+ .filter((user) => !!user.username)
263007
+ .map((user) => ({
263008
+ username: user.username,
263009
+ name: user.name,
263010
+ email: user.email,
263011
+ }));
263012
+ }, [data]);
263013
+ const totalPages = Math.ceil(((_a = data === null || data === void 0 ? void 0 : data.count) !== null && _a !== void 0 ? _a : 0) / PAGE_SIZE$5);
263014
+ const isForbidden = !!error && error.status === 403;
263015
+ return (jsxs("div", { "data-testid": "memory-admin-global-section", children: [jsxs("div", { className: "relative mb-6 max-w-sm w-full sm:w-auto", children: [jsx(Search, { className: "absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-gray-400" }), jsx(Input, { "data-testid": "memory-admin-users-search", type: "text", value: searchQuery, onChange: (event) => setSearchQuery(event.target.value), placeholder: t('memoryAdminTab.searchUsersPlaceholder'), className: "pl-10 pr-10 focus:ring-blue-500 focus:border-blue-500 h-[35px]", "aria-label": t('memoryAdminTab.searchUsersAriaLabel') }), searchQuery.length > 0 && (searchQuery !== debouncedSearch || isFetching) && (jsx(LoaderCircle, { "data-testid": "user-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" }))] }), isForbidden ? (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('memoryAdminTab.forbidden') }) })) : 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-[28%]", children: t('memoryAdminTab.nameColumn') }), jsx("th", { className: "px-6 py-3 text-left font-medium text-gray-500 dark:text-gray-400 w-[26%]", children: t('memoryAdminTab.usernameColumn') }), jsx("th", { className: "px-6 py-3 text-left font-medium text-gray-500 dark:text-gray-400 w-[30%]", children: t('memoryAdminTab.emailColumn') }), jsx("th", { className: "px-6 py-3 text-right font-medium text-gray-500 dark:text-gray-400 w-[16%]", children: t('memoryAdminTab.actionsColumn') })] }) }), jsxs("tbody", { className: "divide-y divide-gray-200 dark:divide-gray-600", children: [users.map((user) => (jsxs("tr", { "data-testid": `memory-admin-user-row-${user.username}`, children: [jsx("td", { className: "px-6 py-4 text-gray-900 dark:text-gray-100 max-w-0", children: jsx("div", { className: "truncate font-medium", children: user.name || '—' }) }), jsx("td", { className: "px-6 py-4 text-gray-600 dark:text-gray-300 max-w-0", children: jsx("div", { className: "truncate", children: user.username }) }), jsx("td", { className: "px-6 py-4 text-gray-600 dark:text-gray-300 max-w-0", children: jsx("div", { className: "truncate", children: user.email || '—' }) }), jsx("td", { className: "px-6 py-4", children: jsx("div", { className: "flex justify-end gap-2", children: jsx(Button$1, { "data-testid": `memory-admin-user-view-${user.username}`, variant: "ghost", size: "sm", "aria-label": t('memoryAdminTab.viewMemoriesAriaLabel', {
263016
+ name: user.email || user.username,
263017
+ }), onClick: () => setSelectedUser(user), children: jsx(Eye, { className: "h-4 w-4" }) }) }) })] }, user.username))), users.length === 0 && (jsx("tr", { children: jsx("td", { colSpan: 4, className: "px-6 py-8 text-center text-gray-500 dark:text-gray-400", children: isFetching ? t('memoryAdminTab.loading') : t('memoryAdminTab.noUsersFound') }) }))] })] }) }), totalPages > 1 && (jsx("div", { className: "mt-6", children: jsx(IblPagination, { totalPages: totalPages, currentPage: page, onPageChange: setPage, disabled: isFetching }) }))] })), selectedUser && (jsx(UserMemoriesModal, { isOpen: !!selectedUser, onClose: () => setSelectedUser(null), tenantKey: tenantKey, adminUsername: username, user: selectedUser }))] }));
263018
+ }
263019
+
263020
+ const EditMemoryModal$1 = dynamic(() => Promise.resolve().then(function () { return editMemoryModal; }).then((module) => ({
263021
+ default: module.EditMemoryModal,
263022
+ })), { ssr: false });
263023
+ const AddMemoryModal$1 = dynamic(() => Promise.resolve().then(function () { return addMemoryModal; }).then((module) => ({
263024
+ default: module.AddMemoryModal,
263025
+ })), { ssr: false });
263026
+ const DeleteMemoryModal = dynamic(() => Promise.resolve().then(function () { return deleteMemoryModal; }).then((module) => ({
263027
+ default: module.DeleteMemoryModal,
263028
+ })), { ssr: false });
263029
+ const BulkDeleteMemoryModal$1 = dynamic(() => Promise.resolve().then(function () { return bulkDeleteMemoryModal; }).then((module) => ({
263030
+ default: module.BulkDeleteMemoryModal,
263031
+ })), { ssr: false });
263032
+ const ManageCategoriesModal$1 = dynamic(() => Promise.resolve().then(function () { return manageCategoriesModal; }).then((module) => ({
263033
+ default: module.ManageCategoriesModal,
263034
+ })), { ssr: false });
263035
+ const PAGE_SIZE$4 = 20;
263036
+ const SNAPSHOT_PAGE_SIZE = 1000;
263037
+ function ManageMemories({ tenantKey, username, mentorId }) {
263038
+ var _a, _b, _c, _d, _e;
263039
+ const t = useT();
263040
+ const [selectedLearner, setSelectedLearner] = useState('');
263041
+ const [dateRange, setDateRange] = useState(undefined);
263042
+ const [selectedCategorySlug, setSelectedCategorySlug] = useState('all');
263043
+ const [page, setPage] = useState(1);
263044
+ // Reset to page 1 whenever any filter changes — otherwise we could land on a
263045
+ // page index that no longer exists in the new result set.
263046
+ useEffect(() => {
263047
+ setPage(1);
263048
+ }, [selectedLearner, dateRange, selectedCategorySlug]);
263049
+ const listParams = useMemo(() => {
263050
+ const params = { page, page_size: PAGE_SIZE$4 };
263051
+ if (selectedLearner)
263052
+ params.email = selectedLearner;
263053
+ if (selectedCategorySlug !== 'all')
263054
+ params.category = selectedCategorySlug;
263055
+ if (dateRange === null || dateRange === void 0 ? void 0 : dateRange.from)
263056
+ params.start_date = format$1(dateRange.from, 'yyyy-MM-dd');
263057
+ if (dateRange === null || dateRange === void 0 ? void 0 : dateRange.to)
263058
+ params.end_date = format$1(dateRange.to, 'yyyy-MM-dd');
263059
+ return params;
263060
+ }, [page, selectedLearner, selectedCategorySlug, dateRange]);
263061
+ const { data: listResponse, isLoading: isLoadingMemories } = useGetMentorMemoriesListQuery({
263062
+ org: tenantKey,
263063
+ userId: username !== null && username !== void 0 ? username : '',
263064
+ mentorId,
263065
+ params: listParams,
263066
+ }, {
263067
+ skip: !tenantKey || !username || !mentorId,
263068
+ });
263069
+ const totalPages = Math.max(1, Math.ceil(((_a = listResponse === null || listResponse === void 0 ? void 0 : listResponse.count) !== null && _a !== void 0 ? _a : 0) / PAGE_SIZE$4));
263070
+ const { data: adminCategories } = useGetMemoryCategoriesAdminQuery({
263071
+ org: tenantKey,
263072
+ mentorId,
263073
+ }, {
263074
+ skip: !tenantKey || !mentorId,
263075
+ });
263076
+ const [deleteMentorMemory, { isLoading: isDeleting }] = useDeleteMentorMemoryMutation();
263077
+ const [updateMentorMemory, { isLoading: isEditing }] = useUpdateMentorMemoryMutation();
263078
+ const [createMentorMemory, { isLoading: isSaving }] = useCreateMentorMemoryMutation();
263079
+ // Flat list of memories on the current page, mapped into the local `Memory`
263080
+ // shape used by the rest of this component.
263081
+ const memories = useMemo(() => {
263082
+ if (!(listResponse === null || listResponse === void 0 ? void 0 : listResponse.results))
263083
+ return [];
263084
+ return listResponse.results.map((memory) => ({
263085
+ id: memory.id,
263086
+ content: memory.content,
263087
+ category: {
263088
+ id: memory.category.id,
263089
+ name: memory.category.name,
263090
+ slug: memory.category.slug,
263091
+ },
263092
+ email: memory.email,
263093
+ createdAt: memory.created_at,
263094
+ }));
263095
+ }, [listResponse]);
263096
+ // Unfiltered snapshot used to derive the learner dropdown and to source the
263097
+ // bulk-delete operation, which needs the full set of memories — not just the
263098
+ // current page.
263099
+ const { data: snapshotResponse } = useGetMentorMemoriesListQuery({
263100
+ org: tenantKey,
263101
+ userId: username !== null && username !== void 0 ? username : '',
263102
+ mentorId,
263103
+ params: { page: 1, page_size: SNAPSHOT_PAGE_SIZE },
263104
+ }, {
263105
+ skip: !tenantKey || !username || !mentorId,
263106
+ });
263107
+ const learners = useMemo(() => {
263108
+ if (!(snapshotResponse === null || snapshotResponse === void 0 ? void 0 : snapshotResponse.results))
263109
+ return [];
263110
+ const emailSet = new Set();
263111
+ snapshotResponse.results.forEach((m) => {
263112
+ if (m.email)
263113
+ emailSet.add(m.email);
263114
+ });
263115
+ return Array.from(emailSet).map((email) => ({ email }));
263116
+ }, [snapshotResponse]);
263117
+ const categories = useMemo(() => {
263118
+ if (adminCategories && adminCategories.length > 0) {
263119
+ return [
263120
+ { id: 0, name: 'All', slug: 'all' },
263121
+ ...adminCategories.map((cat) => ({
263122
+ id: cat.id,
263123
+ name: cat.name,
263124
+ slug: cat.slug,
263125
+ })),
263126
+ ];
263127
+ }
263128
+ return [{ id: 0, name: 'All', slug: 'all' }];
263129
+ }, [adminCategories]);
263130
+ const [editingMemory, setEditingMemory] = useState(null);
263131
+ const [editContent, setEditContent] = useState('');
263132
+ const [editCategory, setEditCategory] = useState('');
263133
+ const [showDeleteConfirm, setShowDeleteConfirm] = useState(null);
263134
+ const [showAddMemory, setShowAddMemory] = useState(false);
263135
+ const [newMemoryContent, setNewMemoryContent] = useState('');
263136
+ const [newMemoryCategory, setNewMemoryCategory] = useState('');
263137
+ const [showMobileDropdown, setShowMobileDropdown] = useState(false);
263138
+ const [showBulkDeleteConfirm, setShowBulkDeleteConfirm] = useState(false);
263139
+ const [isBulkDeleting, setIsBulkDeleting] = useState(false);
263140
+ const [showManageCategories, setShowManageCategories] = useState(false);
263141
+ const selectedCategoryName = (_c = (_b = categories.find((c) => c.slug === selectedCategorySlug)) === null || _b === void 0 ? void 0 : _b.name) !== null && _c !== void 0 ? _c : t('memoryTabManageMemories.all');
263142
+ const VISIBLE_CATEGORY_LIMIT = 6;
263143
+ const visibleCategories = categories.slice(0, VISIBLE_CATEGORY_LIMIT);
263144
+ const overflowCategories = categories.slice(VISIBLE_CATEGORY_LIMIT);
263145
+ const overflowSelected = overflowCategories.find((c) => c.slug === selectedCategorySlug);
263146
+ // Category is filtered server-side via the `category` query param now, so
263147
+ // `memories` already contains only the relevant entries for the page.
263148
+ const filteredMemories = memories;
263149
+ const handleDeleteMemory = async (id) => {
263150
+ if (!tenantKey || !username)
263151
+ return;
263152
+ try {
263153
+ await deleteMentorMemory({
263154
+ org: tenantKey,
263155
+ userId: username,
263156
+ mentorId,
263157
+ memoryId: id,
263158
+ }).unwrap();
263159
+ setShowDeleteConfirm(null);
263160
+ toast.success(t('memoryTabManageMemories.memoryDeletedSuccessfully'));
263161
+ }
263162
+ catch (error) {
263163
+ console.error('Failed to delete memory:', error);
263164
+ toast.error(t('memoryTabManageMemories.failedToDeleteMemory'));
263165
+ }
263166
+ };
263167
+ const handleBulkDelete = async () => {
263168
+ var _a;
263169
+ if (!tenantKey || !username)
263170
+ return;
263171
+ setIsBulkDeleting(true);
263172
+ try {
263173
+ // Source bulk-delete from the unfiltered snapshot — `memories` only holds
263174
+ // the current page, while bulk delete must remove every entry in the
263175
+ // selected category.
263176
+ const memoriesToDelete = ((_a = snapshotResponse === null || snapshotResponse === void 0 ? void 0 : snapshotResponse.results) !== null && _a !== void 0 ? _a : []).filter((memory) => memory.category.slug === selectedCategorySlug);
263177
+ await Promise.all(memoriesToDelete.map((memory) => deleteMentorMemory({
263178
+ org: tenantKey,
263179
+ userId: username,
263180
+ mentorId,
263181
+ memoryId: memory.id,
263182
+ }).unwrap()));
263183
+ toast.success(t('memoryTabManageMemories.allCategoryMemoriesDeleted', { category: selectedCategoryName }));
263184
+ setShowBulkDeleteConfirm(false);
263185
+ }
263186
+ catch (error) {
263187
+ console.error('Failed to delete memories:', error);
263188
+ toast.error(t('memoryTabManageMemories.failedToDeleteMemories'));
263189
+ }
263190
+ finally {
263191
+ setIsBulkDeleting(false);
263192
+ }
263193
+ };
263194
+ const startEdit = (memory) => {
263195
+ setEditingMemory(memory);
263196
+ setEditContent(memory.content);
263197
+ setEditCategory(memory.category.name);
263198
+ };
263199
+ const saveEdit = async () => {
263200
+ if (!editingMemory || !tenantKey || !username)
263201
+ return;
263202
+ try {
263203
+ const selectedCat = categories.find((c) => c.name === editCategory);
263204
+ const categoryChanged = !!selectedCat && selectedCat.slug !== editingMemory.category.slug;
263205
+ await updateMentorMemory({
263206
+ org: tenantKey,
263207
+ userId: username,
263208
+ mentorId,
263209
+ memoryId: editingMemory.id,
263210
+ data: {
263211
+ content: editContent,
263212
+ ...(categoryChanged ? { category_slug: selectedCat.slug } : {}),
263213
+ },
263214
+ }).unwrap();
263215
+ toast.success(t('memoryTabManageMemories.memoryUpdatedSuccessfully'));
263216
+ // Follow the entry to its new category tab so the user doesn't lose
263217
+ // sight of it. Skip when viewing "All" — the entry is still visible.
263218
+ if (categoryChanged && selectedCategorySlug !== 'all') {
263219
+ setSelectedCategorySlug(selectedCat.slug);
263220
+ }
263221
+ setEditingMemory(null);
263222
+ setEditContent('');
263223
+ setEditCategory('');
263224
+ }
263225
+ catch (error) {
263226
+ console.error('Failed to update memory:', error);
263227
+ toast.error(t('memoryTabManageMemories.failedToUpdateMemory'));
263228
+ }
263229
+ };
263230
+ const cancelEdit = () => {
263231
+ setEditingMemory(null);
263232
+ setEditContent('');
263233
+ setEditCategory('');
263234
+ };
263235
+ const startAddMemory = () => {
263236
+ setShowAddMemory(true);
263237
+ setNewMemoryCategory(selectedCategoryName);
263238
+ };
263239
+ const saveNewMemory = async () => {
263240
+ var _a;
263241
+ if (!newMemoryContent.trim() || !tenantKey || !username)
263242
+ return;
263243
+ try {
263244
+ const selectedCat = categories.find((c) => c.name === newMemoryCategory);
263245
+ const categorySlug = (_a = selectedCat === null || selectedCat === void 0 ? void 0 : selectedCat.slug) !== null && _a !== void 0 ? _a : selectedCategorySlug;
263246
+ await createMentorMemory({
263247
+ org: tenantKey,
263248
+ userId: username,
263249
+ mentorId,
263250
+ data: {
263251
+ category_slug: categorySlug === 'all' ? 'general' : categorySlug,
263252
+ content: newMemoryContent.trim(),
263253
+ },
263254
+ }).unwrap();
263255
+ setShowAddMemory(false);
263256
+ setNewMemoryContent('');
263257
+ setNewMemoryCategory('');
263258
+ if (selectedCat) {
263259
+ setSelectedCategorySlug(selectedCat.slug);
263260
+ }
263261
+ toast.success(t('memoryTabManageMemories.memoryCreatedSuccessfully'));
263262
+ }
263263
+ catch (error) {
263264
+ console.error('Failed to create memory:', error);
263265
+ toast.error(t('memoryTabManageMemories.failedToCreateMemory'));
263266
+ }
263267
+ };
263268
+ const cancelAddMemory = () => {
263269
+ setShowAddMemory(false);
263270
+ setNewMemoryContent('');
263271
+ setNewMemoryCategory('');
263272
+ };
263273
+ const categoryNames = categories.map((c) => c.name);
263274
+ return (jsxs(Fragment$1, { children: [jsxs("div", { className: "space-y-6", children: [jsx("div", { className: "rounded-lg border p-4", children: jsxs("div", { className: "flex flex-col gap-3 lg:flex-row", children: [jsx("div", { className: "relative min-w-[200px] flex-1", children: jsxs(Popover, { children: [jsx(PopoverTrigger, { asChild: true, children: jsxs(Button$1, { variant: "outline", role: "combobox", "aria-label": t('memoryTabManageMemories.searchForUser'), className: "w-full justify-between bg-transparent font-normal", children: [selectedLearner
263275
+ ? ((_e = (_d = learners.find((learner) => learner.email === selectedLearner)) === null || _d === void 0 ? void 0 : _d.email) !== null && _e !== void 0 ? _e : selectedLearner)
263276
+ : t('memoryTabManageMemories.searchForUser'), jsx(ChevronsUpDown, { className: "ml-2 h-4 w-4 shrink-0 opacity-50" })] }) }), jsx(PopoverContent, { className: "w-full p-0", align: "start", children: jsxs(Command, { children: [jsx(CommandInput, { placeholder: t('memoryTabManageMemories.searchUsersPlaceholder') }), jsxs(CommandList, { children: [jsx(CommandEmpty, { children: t('memoryTabManageMemories.noUsersFound') }), jsxs(CommandGroup, { children: [jsxs(CommandItem, { value: "", onSelect: () => {
263277
+ setSelectedLearner('');
263278
+ }, children: [jsx(Check, { className: cn('mr-2 h-4 w-4', !selectedLearner ? 'opacity-100' : 'opacity-0') }), t('memoryTabManageMemories.allUsers')] }), learners.map((learner) => (jsxs(CommandItem, { value: learner.email, onSelect: () => {
263279
+ setSelectedLearner(learner.email);
263280
+ }, children: [jsx(Check, { className: cn('mr-2 h-4 w-4', selectedLearner === learner.email ? 'opacity-100' : 'opacity-0') }), jsx("div", { className: "flex flex-col", children: jsx("span", { className: "font-medium text-gray-700", children: learner.email }) })] }, learner.email)))] })] })] }) })] }) }), jsxs(Popover, { children: [jsx(PopoverTrigger, { asChild: true, children: jsxs(Button$1, { variant: "outline", className: "flex w-full items-center gap-2 bg-transparent 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)
263281
+ ? `${format$1(dateRange.from, 'MMM dd')} - ${format$1(dateRange.to, 'MMM dd')}`
263282
+ : t('memoryTabManageMemories.pickDateRange')] }) }), jsx(PopoverContent, { className: "w-auto p-0", align: "start", children: jsx(Calendar, { mode: "range", selected: dateRange, onSelect: setDateRange, numberOfMonths: 2, initialFocus: true }) })] })] }) }), jsx("div", { children: jsxs("div", { className: "flex items-center justify-between gap-4", children: [jsxs("div", { className: "scrollbar-none hidden flex-1 items-center space-x-8 overflow-x-auto sm:flex", children: [visibleCategories.map((category) => (jsxs("button", { onClick: () => setSelectedCategorySlug(category.slug), className: `relative px-1 py-2 text-sm font-medium whitespace-nowrap transition-colors ${selectedCategorySlug === category.slug
263283
+ ? 'text-[#38A1E5]'
263284
+ : 'text-gray-600 hover:text-gray-900'}`, children: [category.name, selectedCategorySlug === category.slug && (jsx("div", { className: "absolute bottom-0 left-1/2 h-0.5 -translate-x-1/2 transform bg-[#38A1E5] transition-all duration-200", style: { width: `${category.name.length * 0.55}em` } }))] }, category.slug))), overflowCategories.length > 0 && (jsxs(DropdownMenu, { children: [jsx(DropdownMenuTrigger, { asChild: true, children: jsxs("button", { className: cn('relative flex items-center gap-1 px-1 py-2 text-sm font-medium whitespace-nowrap transition-colors', overflowSelected ? 'text-[#38A1E5]' : 'text-gray-600 hover:text-gray-900'), "aria-label": t('memoryTabManageMemories.moreCategories'), children: [overflowSelected ? overflowSelected.name : t('memoryTabManageMemories.more'), jsx(ChevronDown, { className: "h-3.5 w-3.5" }), overflowSelected && (jsx("div", { className: "absolute bottom-0 left-0 h-0.5 bg-[#38A1E5] transition-all duration-200", style: {
263285
+ width: `${overflowSelected.name.length * 0.55}em`,
263286
+ } }))] }) }), jsx(DropdownMenuContent, { align: "end", children: overflowCategories.map((category) => (jsx(DropdownMenuItem, { onClick: () => setSelectedCategorySlug(category.slug), className: selectedCategorySlug === category.slug ? 'bg-gray-100' : '', children: category.name }, category.slug))) })] }))] }), jsx("div", { className: "w-full py-2 sm:hidden", children: jsxs(DropdownMenu, { open: showMobileDropdown, onOpenChange: setShowMobileDropdown, children: [jsx(DropdownMenuTrigger, { asChild: true, children: jsxs(Button$1, { variant: "outline", className: "w-full justify-between bg-transparent", children: [selectedCategoryName, jsx(ChevronDown, { className: "h-4 w-4" })] }) }), jsx(DropdownMenuContent, { className: "w-full", children: categories.map((category) => (jsx(DropdownMenuItem, { onClick: () => {
263287
+ setSelectedCategorySlug(category.slug);
263288
+ setShowMobileDropdown(false);
263289
+ }, className: selectedCategorySlug === category.slug ? 'bg-gray-100' : '', children: category.name }, category.slug))) })] }) }), jsxs(Button$1, { onClick: () => setShowManageCategories(true), size: "sm", variant: "outline", className: "shrink-0", "aria-label": t('memoryTabManageMemories.manageCategories'), children: [jsx(Tags, { className: "h-4 w-4 sm:mr-2" }), jsx("span", { className: "hidden sm:inline", children: t('memoryTabManageMemories.categories') })] }), jsxs(Button$1, { onClick: startAddMemory, size: "sm", className: "ibl-button-primary shrink-0", children: [jsx(Plus, { className: "mr-1 h-4 w-4 sm:mr-2" }), jsx("span", { className: "hidden sm:inline", children: t('memoryTabManageMemories.addMemory') }), jsx("span", { className: "sm:hidden", children: t('memoryTabManageMemories.add') })] })] }) }), jsx("div", { className: "space-y-3 px-1 sm:px-0", children: isLoadingMemories ? (jsx("div", { className: "py-8 text-center text-gray-600", children: jsx("p", { children: t('memoryTabManageMemories.loadingMemories') }) })) : (filteredMemories.map((memory) => {
263290
+ const timeAgo = memory.createdAt
263291
+ ? formatDistanceToNow(new Date(memory.createdAt), {
263292
+ addSuffix: true,
263293
+ })
263294
+ : '';
263295
+ const displayUser = memory.email || t('memoryTabManageMemories.unknown');
263296
+ return (jsxs("div", { className: "flex items-start gap-3 rounded-lg border border-gray-200 bg-white p-3", children: [jsxs("div", { className: "flex-1", children: [(timeAgo || displayUser) && (jsxs("div", { className: "mb-2 flex items-center justify-between", children: [timeAgo && jsx("span", { className: "text-sm text-gray-600", children: timeAgo }), displayUser && (jsx("span", { className: "max-w-[100px] truncate text-sm text-gray-900 sm:max-w-[200px]", children: displayUser }))] })), jsx("div", { className: "text-sm leading-relaxed text-gray-900", children: memory.content })] }), jsxs(DropdownMenu, { children: [jsx(DropdownMenuTrigger, { asChild: true, children: jsx(Button$1, { variant: "ghost", size: "sm", className: "h-6 w-6 flex-shrink-0 p-0 text-gray-600 hover:text-gray-900", children: jsx(Ellipsis, { className: "h-4 w-4" }) }) }), jsxs(DropdownMenuContent, { align: "end", children: [jsx(DropdownMenuItem, { onClick: () => startEdit(memory), children: t('memoryTabManageMemories.edit') }), jsx(DropdownMenuItem, { onClick: () => setShowDeleteConfirm(memory.id), children: t('memoryTabManageMemories.delete') })] })] })] }, memory.id));
263297
+ })) }), filteredMemories.length > 0 && selectedCategorySlug !== 'all' && (jsx("div", { className: "flex justify-end", children: jsx(Button$1, { variant: "outline", onClick: () => setShowBulkDeleteConfirm(true), children: t('memoryTabManageMemories.deleteAll') }) })), filteredMemories.length === 0 && !isLoadingMemories && (jsx("div", { className: "py-8 text-center text-gray-600", children: jsx("p", { children: t('memoryTabManageMemories.noSavedMemories') }) })), totalPages > 1 && (jsx("div", { className: "flex justify-center pt-2", children: jsx(IblPagination, { currentPage: page, totalPages: totalPages, onPageChange: setPage, disabled: isLoadingMemories }) }))] }), jsx(EditMemoryModal$1, { open: !!editingMemory, onOpenChange: (open) => !open && cancelEdit(), editContent: editContent, editCategory: editCategory, onContentChange: setEditContent, onCategoryChange: setEditCategory, onSave: saveEdit, onCancel: cancelEdit, categories: categoryNames, isSaving: isEditing }), jsx(AddMemoryModal$1, { open: showAddMemory, onOpenChange: (open) => !open && cancelAddMemory(), newMemoryContent: newMemoryContent, newMemoryCategory: newMemoryCategory, onContentChange: setNewMemoryContent, onCategoryChange: setNewMemoryCategory, onSave: saveNewMemory, onCancel: cancelAddMemory, categories: categoryNames, isSaving: isSaving }), jsx(DeleteMemoryModal, { open: !!showDeleteConfirm, onOpenChange: (open) => !open && setShowDeleteConfirm(null), onConfirm: () => showDeleteConfirm !== null && handleDeleteMemory(showDeleteConfirm), onCancel: () => setShowDeleteConfirm(null), isDeleting: isDeleting }), jsx(ManageCategoriesModal$1, { open: showManageCategories, onOpenChange: setShowManageCategories, tenantKey: tenantKey, mentorId: mentorId }), jsx(BulkDeleteMemoryModal$1, { open: showBulkDeleteConfirm, onOpenChange: setShowBulkDeleteConfirm, onConfirm: handleBulkDelete, onCancel: () => setShowBulkDeleteConfirm(false), isDeleting: isBulkDeleting, selectedCategory: selectedCategoryName })] }));
263298
+ }
263299
+
263300
+ /**
263301
+ * Popup hosting the same memory manager the agent settings modal renders —
263302
+ * learner/category/date filters and full CRUD included — for one agent.
263303
+ * Laid out like the Billing tab's agent-limits popup: a fixed divider header
263304
+ * and a body that scrolls vertically while the content fits the width.
263305
+ */
263306
+ function AgentMemoriesModal({ isOpen, onClose, tenantKey, username, agent, }) {
263307
+ const t = useT();
263308
+ return (jsx(Dialog, { open: isOpen, onOpenChange: (open) => !open && onClose(), children: jsxs(DialogContent, { "data-testid": "agent-memories-modal", "aria-label": "agent-memories", className: "flex max-h-[90vh] w-[calc(100vw-2rem)] flex-col gap-0 overflow-hidden p-0 sm:max-w-4xl", children: [jsxs(DialogHeader, { className: "flex-shrink-0 border-b border-gray-200 px-6 py-4 pr-12", children: [jsx(DialogTitle, { className: "ibl-dialog-title", children: agent.name }), jsx(DialogDescription, { children: t('memoryAdminAgentMemoriesModal.description') })] }), jsx("div", { className: "min-h-0 flex-1 overflow-y-auto p-3 lg:p-4", children: jsx("div", { className: "space-y-8", children: jsx(ManageMemories, { tenantKey: tenantKey, username: username, mentorId: agent.unique_id }) }) })] }) }));
263309
+ }
263310
+
263311
+ const PAGE_SIZE$3 = 10;
263312
+ /**
263313
+ * Agents table filtered by the same agent autocomplete the Billing tab's
263314
+ * Agent Limits section uses. Opening a row shows that agent's memories in a
263315
+ * popup hosting the same manager the agent settings modal uses.
263316
+ */
263317
+ function AgentMemoriesSection({ tenantKey, username }) {
263318
+ var _a;
263319
+ const t = useT();
263320
+ const [page, setPage] = useState(1);
263321
+ const [agentFilter, setAgentFilter] = useState(null);
263322
+ const [agentSearch, setAgentSearch] = useState('');
263323
+ const [debouncedAgentSearch] = a$3(agentSearch, 300);
263324
+ const [selectedAgent, setSelectedAgent] = useState(null);
263325
+ // A new filter invalidates the current page index.
263326
+ useEffect(() => {
263327
+ setPage(1);
263328
+ }, [agentFilter]);
263329
+ // Autocomplete options for the filter, fetched once two characters are in.
263330
+ const shouldSearchAgents = Boolean(tenantKey && debouncedAgentSearch.trim().length >= 2);
263331
+ const { data: searchResponse, isFetching: isSearchingAgents } = useGetMentorsQuery({ org: tenantKey, username, limit: 20, query: debouncedAgentSearch.trim() }, { skip: !shouldSearchAgents });
263332
+ const agentOptions = useMemo(() => {
263333
+ var _a;
263334
+ return ((_a = searchResponse === null || searchResponse === void 0 ? void 0 : searchResponse.results) !== null && _a !== void 0 ? _a : [])
263335
+ .filter((mentor) => Boolean(mentor.unique_id))
263336
+ .map((mentor) => ({
263337
+ value: mentor.unique_id,
263338
+ label: mentor.name || mentor.unique_id,
263339
+ }));
263340
+ }, [searchResponse]);
263341
+ const { data, isLoading, isFetching, error } = useGetMentorsQuery({
263342
+ org: tenantKey,
263343
+ username,
263344
+ limit: PAGE_SIZE$3,
263345
+ offset: (page - 1) * PAGE_SIZE$3,
263346
+ ...(agentFilter ? { uniqueId: agentFilter.value } : {}),
263347
+ });
263348
+ const agents = ((_a = data === null || data === void 0 ? void 0 : data.results) !== null && _a !== void 0 ? _a : []);
263349
+ const totalPages = (data === null || data === void 0 ? void 0 : data.count) ? Math.ceil(data.count / PAGE_SIZE$3) : 0;
263350
+ const isForbidden = !!error && error.status === 403;
263351
+ return (jsxs("div", { "data-testid": "memory-admin-agent-section", children: [jsx("div", { className: "mb-6 max-w-sm", children: jsx(SearchSelect, { labels: {
263352
+ // No field label — the users tab's search carries none either.
263353
+ label: '',
263354
+ placeholder: t('memoryAdminTab.filter.placeholder'),
263355
+ typeToSearch: t('memoryAdminTab.filter.typeToSearch'),
263356
+ searching: t('memoryAdminTab.filter.searching'),
263357
+ noResults: t('memoryAdminTab.filter.noResults'),
263358
+ clear: t('memoryAdminTab.filter.clear'),
263359
+ }, selected: agentFilter, onSelect: (option) => {
263360
+ setAgentFilter(option);
263361
+ setAgentSearch('');
263362
+ }, onClear: () => setAgentFilter(null), searchTerm: agentSearch, onSearchTermChange: setAgentSearch, options: agentOptions, isLoading: isSearchingAgents, testId: "agent-memories-filter" }) }), isForbidden ? (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('memoryAdminTab.forbidden') }) })) : 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-[32%]", children: t('memoryAdminTab.agentColumn') }), jsx("th", { className: "px-6 py-3 text-left font-medium text-gray-500 dark:text-gray-400 w-[52%]", children: t('memoryAdminTab.descriptionColumn') }), jsx("th", { className: "px-6 py-3 text-right font-medium text-gray-500 dark:text-gray-400 w-[16%]", children: t('memoryAdminTab.actionsColumn') })] }) }), jsxs("tbody", { className: "divide-y divide-gray-200 dark:divide-gray-600", children: [agents.map((agent) => (jsxs("tr", { "data-testid": `memory-admin-agent-row-${agent.unique_id}`, children: [jsx("td", { className: "px-6 py-4 text-gray-900 dark:text-gray-100 max-w-0", children: jsx("div", { className: "truncate font-medium", children: agent.name }) }), jsx("td", { className: "px-6 py-4 text-gray-600 dark:text-gray-300 max-w-0", children: jsx("div", { className: "truncate", children: agent.description || '—' }) }), jsx("td", { className: "px-6 py-4", children: jsx("div", { className: "flex justify-end gap-2", children: jsx(Button$1, { "data-testid": `memory-admin-agent-view-${agent.unique_id}`, variant: "ghost", size: "sm", "aria-label": t('memoryAdminTab.viewMemoriesAriaLabel', {
263363
+ name: agent.name,
263364
+ }), onClick: () => setSelectedAgent(agent), children: jsx(Eye, { className: "h-4 w-4" }) }) }) })] }, agent.unique_id))), agents.length === 0 && (jsx("tr", { children: jsx("td", { colSpan: 3, className: "px-6 py-8 text-center text-gray-500 dark:text-gray-400", children: isFetching ? t('memoryAdminTab.loading') : t('memoryAdminTab.noAgentsFound') }) }))] })] }) }), totalPages > 1 && (jsx("div", { className: "mt-6", children: jsx(IblPagination, { totalPages: totalPages, currentPage: page, onPageChange: setPage, disabled: isFetching }) }))] })), selectedAgent && (jsx(AgentMemoriesModal, { isOpen: !!selectedAgent, onClose: () => setSelectedAgent(null), tenantKey: tenantKey, username: username, agent: selectedAgent }))] }));
263365
+ }
263366
+
263367
+ /**
263368
+ * Tenant-settings Memory tab. Lets admins/RBAC-granted users manage other
263369
+ * users' global memories and per-agent memories from one place, mirroring the
263370
+ * Billing tab's sub-tab layout.
263371
+ */
263372
+ function MemoryAdminTab({ tenantKey, username }) {
263373
+ const t = useT();
263374
+ // Same platform gate the profile memory tab applies: when memsearch is off
263375
+ // for the tenant there is nothing to manage.
263376
+ const { data: memsearchStatus, isLoading, isError, } = useGetMemsearchStatusQuery({ org: tenantKey, userId: username });
263377
+ if (isLoading) {
263378
+ return (jsxs("div", { className: "space-y-6", children: [jsx(Skeleton, { className: "h-10 w-full max-w-sm rounded-lg" }), jsx(Skeleton, { className: "h-40 w-full rounded-lg" })] }));
263379
+ }
263380
+ if (!isError && memsearchStatus && !memsearchStatus.enable_memsearch) {
263381
+ 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('memoryAdminTab.featureDisabled') }) }) }));
263382
+ }
263383
+ return (jsxs(Tabs, { defaultValue: "global-memories", "aria-label": t('memoryAdminTab.tabsAriaLabel'), children: [jsxs(TabsList, { "aria-label": t('memoryAdminTab.tabsAriaLabel'), className: "max-w-full overflow-x-auto justify-start px-1", children: [jsx(TabsTrigger, { "data-testid": "memory-admin-sub-tab-global", value: "global-memories", children: t('memoryAdminTab.tabGlobalMemories') }), jsx(TabsTrigger, { "data-testid": "memory-admin-sub-tab-agent", value: "agent-memories", children: t('memoryAdminTab.tabAgentMemories') })] }), jsx(TabsContent, { className: "mt-4", value: "global-memories", children: jsx(GlobalMemoriesSection, { tenantKey: tenantKey, username: username }) }), jsx(TabsContent, { className: "mt-4", value: "agent-memories", children: jsx(AgentMemoriesSection, { tenantKey: tenantKey, username: username }) })] }));
263384
+ }
263385
+
261982
263386
  function Account({ tenant, tenants = [], username, onInviteClick, email, mainPlatformKey, userActiveApp = null, showPlatformName = false, isAdmin = false, targetTab = 'basic', currentPlan: _currentPlan = '', currentSPA = '', authURL, onTenantUpdate, currentPlatformBaseDomain = '', enableRbac = false, showBenchmarks = false, rbacPermissions = {}, onLoadGroupPermissions, onTabChange, defaultSupportPhone = '', enableSupportPhone, showGradebookTab = false, }) {
261983
263387
  var _a, _b, _c, _d;
261984
263388
  const t = useT();
@@ -261995,6 +263399,7 @@ function Account({ tenant, tenants = [], username, onInviteClick, email, mainPla
261995
263399
  ...(showBenchmarks
261996
263400
  ? [{ id: 'datasets', label: t('profileAccount.tabBenchmarks'), icon: ListChecks }]
261997
263401
  : []),
263402
+ { id: 'memory', label: t('profileAccount.tabMemory'), icon: Brain },
261998
263403
  { id: 'advanced', label: t('profileAccount.tabAdvanced'), icon: Settings$1 },
261999
263404
  ];
262000
263405
  const [activeTab, setActiveTab] = useState(targetTab);
@@ -262076,10 +263481,10 @@ function Account({ tenant, tenants = [], username, onInviteClick, email, mainPla
262076
263481
  onTabChange === null || onTabChange === void 0 ? void 0 : onTabChange('billing');
262077
263482
  }, className: `flex items-center gap-2 px-3 py-2 rounded-lg whitespace-nowrap text-sm transition-all ${activeTab === 'billing'
262078
263483
  ? 'bg-blue-50 text-blue-600 font-medium'
262079
- : 'text-gray-600 hover:bg-gray-50'}`, children: [jsx(CreditCard, { className: "h-4 w-4" }), jsx("span", { className: "hidden sm:inline", children: t('profileAccount.tabBilling') }), jsx("span", { className: "sm:hidden", children: t('profileAccount.tabBilling') })] }, 'billing'))] }) }) }), jsxs("div", { className: "flex-1 flex flex-col overflow-hidden", style: { height: '100%' }, children: [jsxs("div", { className: "hidden lg:block flex-shrink-0 p-6 border-b border-gray-200 bg-white dark:bg-gray-900", children: [jsx("h3", { className: "text-lg font-medium text-gray-900 dark:text-gray-100 mb-2", children: (_b = (_a = TABS.find((t) => t.id === activeTab)) === null || _a === void 0 ? void 0 : _a.label) !== null && _b !== void 0 ? _b : (activeTab === 'billing' ? t('profileAccount.tabBilling') : activeTab) }), jsxs("p", { className: "text-gray-600 dark:text-gray-400 text-sm", children: [activeTab === 'management' && t('profileAccount.descManagement'), activeTab === 'organization' && t('profileAccount.descOrganization'), activeTab === 'integrations' && t('profileAccount.descIntegrations'), activeTab === 'billing' && t('profileAccount.descBilling'), activeTab === 'monetization' && t('profileAccount.descMonetization'), activeTab === 'datasets' && t('profileAccount.descBenchmarks'), activeTab === 'advanced' && t('profileAccount.descAdvanced')] })] }), jsxs("div", { className: "flex-1 p-6 space-y-6", style: {
263484
+ : 'text-gray-600 hover:bg-gray-50'}`, children: [jsx(CreditCard, { className: "h-4 w-4" }), jsx("span", { className: "hidden sm:inline", children: t('profileAccount.tabBilling') }), jsx("span", { className: "sm:hidden", children: t('profileAccount.tabBilling') })] }, 'billing'))] }) }) }), jsxs("div", { className: "flex-1 flex flex-col overflow-hidden", style: { height: '100%' }, children: [jsxs("div", { className: "hidden lg:block flex-shrink-0 p-6 border-b border-gray-200 bg-white dark:bg-gray-900", children: [jsx("h3", { className: "text-lg font-medium text-gray-900 dark:text-gray-100 mb-2", children: (_b = (_a = TABS.find((t) => t.id === activeTab)) === null || _a === void 0 ? void 0 : _a.label) !== null && _b !== void 0 ? _b : (activeTab === 'billing' ? t('profileAccount.tabBilling') : activeTab) }), jsxs("p", { className: "text-gray-600 dark:text-gray-400 text-sm", children: [activeTab === 'management' && t('profileAccount.descManagement'), activeTab === 'organization' && t('profileAccount.descOrganization'), activeTab === 'integrations' && t('profileAccount.descIntegrations'), activeTab === 'billing' && t('profileAccount.descBilling'), activeTab === 'monetization' && t('profileAccount.descMonetization'), activeTab === 'datasets' && t('profileAccount.descBenchmarks'), activeTab === 'memory' && t('profileAccount.descMemory'), activeTab === 'advanced' && t('profileAccount.descAdvanced')] })] }), jsxs("div", { className: "flex-1 p-6 space-y-6", style: {
262080
263485
  overflowY: 'auto',
262081
263486
  overflowX: 'hidden',
262082
- }, children: [jsxs("div", { className: "lg:hidden mb-6", children: [jsx("h3", { className: "text-lg font-medium text-gray-900 dark:text-gray-100 mb-2", children: (_d = (_c = TABS.find((t) => t.id === activeTab)) === null || _c === void 0 ? void 0 : _c.label) !== null && _d !== void 0 ? _d : (activeTab === 'billing' ? t('profileAccount.tabBilling') : activeTab) }), jsxs("p", { className: "text-gray-600 dark:text-gray-400 text-sm", children: [activeTab === 'billing' && t('profileAccount.descBilling'), activeTab === 'basic' && t('profileAccount.descBasic'), activeTab === 'social' && t('profileAccount.descSocial'), activeTab === 'security' && t('profileAccount.descSecurity'), activeTab === 'management' && t('profileAccount.descManagement'), activeTab === 'organization' && t('profileAccount.descOrganization'), activeTab === 'monetization' && t('profileAccount.descMonetization'), activeTab === 'datasets' && t('profileAccount.descBenchmarks'), activeTab === 'advanced' && t('profileAccount.descAdvanced')] })] }), activeTab === 'management' && hasManagementPermissions && (jsx(Admin, { authSpaUrl: authURL, onInviteClick: onInviteClick, tenant: tenant, currentSpa: currentSPA, hasUserTabPermission: hasUserTabPermission, hasGroupsTabPermission: hasGroupsTabPermission, hasPoliciesTabPermission: hasPoliciesTabPermission, hasRolesTabPermission: hasRolesTabPermission, hasTeamsTabPermission: hasTeamsTabPermission, hasInviteUserPermission: hasInviteUserPermission, hasCreateTeamPermission: hasCreateTeamPermission, onLoadGroupPermissions: onLoadGroupPermissions, hasAlertsTabPermission: hasAlertsTabPermission, rbacPermissions: rbacPermissions, enableRbac: enableRbac, showGradebookTab: showGradebookTab })), activeTab === 'organization' && (jsx(OrganizationTab, { platformKey: tenant, tenant: tenants.find((ten) => ten.key === tenant), onTenantUpdate: onTenantUpdate, setOrganizationLogoFromOutside: setOrganizationLogo, defaultSupportPhone: defaultSupportPhone, enableSupportPhone: enableSupportPhone })), activeTab === 'integrations' && (jsx(IntegrationsTab, { tenantKey: tenant, username: username })), activeTab === 'billing' && (jsx(BillingTab, { tenant: tenant, userActiveApp: userActiveApp, username: username, currentUserEmail: email, mainPlatformKey: mainPlatformKey })), activeTab === 'monetization' && (jsx(MonetizationTab, { platformKey: tenant, authURL: authURL })), activeTab === 'datasets' && showBenchmarks && (jsx(BenchmarksTab, { tenantKey: tenant, username: username })), activeTab === 'advanced' && (jsx(AdvancedTab, { platformKey: tenant, currentSPA: currentSPA, username: username, authURL: authURL, currentPlatformBaseDomain: currentPlatformBaseDomain }))] })] }), jsx(ToastProvider, {})] }));
263487
+ }, children: [jsxs("div", { className: "lg:hidden mb-6", children: [jsx("h3", { className: "text-lg font-medium text-gray-900 dark:text-gray-100 mb-2", children: (_d = (_c = TABS.find((t) => t.id === activeTab)) === null || _c === void 0 ? void 0 : _c.label) !== null && _d !== void 0 ? _d : (activeTab === 'billing' ? t('profileAccount.tabBilling') : activeTab) }), jsxs("p", { className: "text-gray-600 dark:text-gray-400 text-sm", children: [activeTab === 'billing' && t('profileAccount.descBilling'), activeTab === 'basic' && t('profileAccount.descBasic'), activeTab === 'social' && t('profileAccount.descSocial'), activeTab === 'security' && t('profileAccount.descSecurity'), activeTab === 'management' && t('profileAccount.descManagement'), activeTab === 'organization' && t('profileAccount.descOrganization'), activeTab === 'monetization' && t('profileAccount.descMonetization'), activeTab === 'datasets' && t('profileAccount.descBenchmarks'), activeTab === 'memory' && t('profileAccount.descMemory'), activeTab === 'advanced' && t('profileAccount.descAdvanced')] })] }), activeTab === 'management' && hasManagementPermissions && (jsx(Admin, { authSpaUrl: authURL, onInviteClick: onInviteClick, tenant: tenant, currentSpa: currentSPA, hasUserTabPermission: hasUserTabPermission, hasGroupsTabPermission: hasGroupsTabPermission, hasPoliciesTabPermission: hasPoliciesTabPermission, hasRolesTabPermission: hasRolesTabPermission, hasTeamsTabPermission: hasTeamsTabPermission, hasInviteUserPermission: hasInviteUserPermission, hasCreateTeamPermission: hasCreateTeamPermission, onLoadGroupPermissions: onLoadGroupPermissions, hasAlertsTabPermission: hasAlertsTabPermission, rbacPermissions: rbacPermissions, enableRbac: enableRbac, showGradebookTab: showGradebookTab })), activeTab === 'organization' && (jsx(OrganizationTab, { platformKey: tenant, tenant: tenants.find((ten) => ten.key === tenant), onTenantUpdate: onTenantUpdate, setOrganizationLogoFromOutside: setOrganizationLogo, defaultSupportPhone: defaultSupportPhone, enableSupportPhone: enableSupportPhone })), activeTab === 'integrations' && (jsx(IntegrationsTab, { tenantKey: tenant, username: username })), activeTab === 'billing' && (jsx(BillingTab, { tenant: tenant, userActiveApp: userActiveApp, username: username, currentUserEmail: email, mainPlatformKey: mainPlatformKey })), activeTab === 'monetization' && (jsx(MonetizationTab, { platformKey: tenant, authURL: authURL })), activeTab === 'datasets' && showBenchmarks && (jsx(BenchmarksTab, { tenantKey: tenant, username: username })), activeTab === 'memory' && jsx(MemoryAdminTab, { tenantKey: tenant, username: username }), activeTab === 'advanced' && (jsx(AdvancedTab, { platformKey: tenant, currentSPA: currentSPA, username: username, authURL: authURL, currentPlatformBaseDomain: currentPlatformBaseDomain }))] })] }), jsx(ToastProvider, {})] }));
262083
263488
  }
262084
263489
 
262085
263490
  function UserProfileModal({ isOpen, onClose, params, email, mainPlatformKey, showMentorAIDisplayCheckbox = false, showLeaderboardDisplayCheckbox = false, showGradebookTab = false, showUsernameField = false, showPlatformName = false, useGravatarPicFallback = true, enableCatalogInvite = false, targetTab = 'basic', currentPlan = '', currentSPA = '', userActiveApp = null, authURL, tenants = [], onTenantUpdate, currentPlatformBaseDomain = '', rbacPermissions = {}, enableRbac = false, onLoadGroupPermissions, onTabChange, defaultSupportPhone = '', onBillingTabRequest, onAccountDeleted, enableMemoryTab = false, showBenchmarks = false, localLLMProps, enableSupportPhone, }) {
@@ -268177,286 +269582,6 @@ function AgentToolsTab({ labels: labelsOverride }) {
268177
269582
  }) })) }) })] }));
268178
269583
  }
268179
269584
 
268180
- const EditMemoryModal$1 = dynamic(() => Promise.resolve().then(function () { return editMemoryModal; }).then((module) => ({
268181
- default: module.EditMemoryModal,
268182
- })), { ssr: false });
268183
- const AddMemoryModal$1 = dynamic(() => Promise.resolve().then(function () { return addMemoryModal; }).then((module) => ({
268184
- default: module.AddMemoryModal,
268185
- })), { ssr: false });
268186
- const DeleteMemoryModal$1 = dynamic(() => Promise.resolve().then(function () { return deleteMemoryModal; }).then((module) => ({
268187
- default: module.DeleteMemoryModal,
268188
- })), { ssr: false });
268189
- const BulkDeleteMemoryModal$1 = dynamic(() => Promise.resolve().then(function () { return bulkDeleteMemoryModal; }).then((module) => ({
268190
- default: module.BulkDeleteMemoryModal,
268191
- })), { ssr: false });
268192
- const ManageCategoriesModal$1 = dynamic(() => Promise.resolve().then(function () { return manageCategoriesModal; }).then((module) => ({
268193
- default: module.ManageCategoriesModal,
268194
- })), { ssr: false });
268195
- const PAGE_SIZE$3 = 20;
268196
- const SNAPSHOT_PAGE_SIZE = 1000;
268197
- function ManageMemories({ tenantKey, username, mentorId }) {
268198
- var _a, _b, _c, _d, _e;
268199
- const t = useT();
268200
- const [selectedLearner, setSelectedLearner] = useState('');
268201
- const [dateRange, setDateRange] = useState(undefined);
268202
- const [selectedCategorySlug, setSelectedCategorySlug] = useState('all');
268203
- const [page, setPage] = useState(1);
268204
- // Reset to page 1 whenever any filter changes — otherwise we could land on a
268205
- // page index that no longer exists in the new result set.
268206
- useEffect(() => {
268207
- setPage(1);
268208
- }, [selectedLearner, dateRange, selectedCategorySlug]);
268209
- const listParams = useMemo(() => {
268210
- const params = { page, page_size: PAGE_SIZE$3 };
268211
- if (selectedLearner)
268212
- params.email = selectedLearner;
268213
- if (selectedCategorySlug !== 'all')
268214
- params.category = selectedCategorySlug;
268215
- if (dateRange === null || dateRange === void 0 ? void 0 : dateRange.from)
268216
- params.start_date = format$1(dateRange.from, 'yyyy-MM-dd');
268217
- if (dateRange === null || dateRange === void 0 ? void 0 : dateRange.to)
268218
- params.end_date = format$1(dateRange.to, 'yyyy-MM-dd');
268219
- return params;
268220
- }, [page, selectedLearner, selectedCategorySlug, dateRange]);
268221
- const { data: listResponse, isLoading: isLoadingMemories } = useGetMentorMemoriesListQuery({
268222
- org: tenantKey,
268223
- userId: username !== null && username !== void 0 ? username : '',
268224
- mentorId,
268225
- params: listParams,
268226
- }, {
268227
- skip: !tenantKey || !username || !mentorId,
268228
- });
268229
- const totalPages = Math.max(1, Math.ceil(((_a = listResponse === null || listResponse === void 0 ? void 0 : listResponse.count) !== null && _a !== void 0 ? _a : 0) / PAGE_SIZE$3));
268230
- const { data: adminCategories } = useGetMemoryCategoriesAdminQuery({
268231
- org: tenantKey,
268232
- mentorId,
268233
- }, {
268234
- skip: !tenantKey || !mentorId,
268235
- });
268236
- const [deleteMentorMemory, { isLoading: isDeleting }] = useDeleteMentorMemoryMutation();
268237
- const [updateMentorMemory, { isLoading: isEditing }] = useUpdateMentorMemoryMutation();
268238
- const [createMentorMemory, { isLoading: isSaving }] = useCreateMentorMemoryMutation();
268239
- // Flat list of memories on the current page, mapped into the local `Memory`
268240
- // shape used by the rest of this component.
268241
- const memories = useMemo(() => {
268242
- if (!(listResponse === null || listResponse === void 0 ? void 0 : listResponse.results))
268243
- return [];
268244
- return listResponse.results.map((memory) => ({
268245
- id: memory.id,
268246
- content: memory.content,
268247
- category: {
268248
- id: memory.category.id,
268249
- name: memory.category.name,
268250
- slug: memory.category.slug,
268251
- },
268252
- email: memory.email,
268253
- createdAt: memory.created_at,
268254
- }));
268255
- }, [listResponse]);
268256
- // Unfiltered snapshot used to derive the learner dropdown and to source the
268257
- // bulk-delete operation, which needs the full set of memories — not just the
268258
- // current page.
268259
- const { data: snapshotResponse } = useGetMentorMemoriesListQuery({
268260
- org: tenantKey,
268261
- userId: username !== null && username !== void 0 ? username : '',
268262
- mentorId,
268263
- params: { page: 1, page_size: SNAPSHOT_PAGE_SIZE },
268264
- }, {
268265
- skip: !tenantKey || !username || !mentorId,
268266
- });
268267
- const learners = useMemo(() => {
268268
- if (!(snapshotResponse === null || snapshotResponse === void 0 ? void 0 : snapshotResponse.results))
268269
- return [];
268270
- const emailSet = new Set();
268271
- snapshotResponse.results.forEach((m) => {
268272
- if (m.email)
268273
- emailSet.add(m.email);
268274
- });
268275
- return Array.from(emailSet).map((email) => ({ email }));
268276
- }, [snapshotResponse]);
268277
- const categories = useMemo(() => {
268278
- if (adminCategories && adminCategories.length > 0) {
268279
- return [
268280
- { id: 0, name: 'All', slug: 'all' },
268281
- ...adminCategories.map((cat) => ({
268282
- id: cat.id,
268283
- name: cat.name,
268284
- slug: cat.slug,
268285
- })),
268286
- ];
268287
- }
268288
- return [{ id: 0, name: 'All', slug: 'all' }];
268289
- }, [adminCategories]);
268290
- const [editingMemory, setEditingMemory] = useState(null);
268291
- const [editContent, setEditContent] = useState('');
268292
- const [editCategory, setEditCategory] = useState('');
268293
- const [showDeleteConfirm, setShowDeleteConfirm] = useState(null);
268294
- const [showAddMemory, setShowAddMemory] = useState(false);
268295
- const [newMemoryContent, setNewMemoryContent] = useState('');
268296
- const [newMemoryCategory, setNewMemoryCategory] = useState('');
268297
- const [showMobileDropdown, setShowMobileDropdown] = useState(false);
268298
- const [showBulkDeleteConfirm, setShowBulkDeleteConfirm] = useState(false);
268299
- const [isBulkDeleting, setIsBulkDeleting] = useState(false);
268300
- const [showManageCategories, setShowManageCategories] = useState(false);
268301
- const selectedCategoryName = (_c = (_b = categories.find((c) => c.slug === selectedCategorySlug)) === null || _b === void 0 ? void 0 : _b.name) !== null && _c !== void 0 ? _c : t('memoryTabManageMemories.all');
268302
- const VISIBLE_CATEGORY_LIMIT = 6;
268303
- const visibleCategories = categories.slice(0, VISIBLE_CATEGORY_LIMIT);
268304
- const overflowCategories = categories.slice(VISIBLE_CATEGORY_LIMIT);
268305
- const overflowSelected = overflowCategories.find((c) => c.slug === selectedCategorySlug);
268306
- // Category is filtered server-side via the `category` query param now, so
268307
- // `memories` already contains only the relevant entries for the page.
268308
- const filteredMemories = memories;
268309
- const handleDeleteMemory = async (id) => {
268310
- if (!tenantKey || !username)
268311
- return;
268312
- try {
268313
- await deleteMentorMemory({
268314
- org: tenantKey,
268315
- userId: username,
268316
- mentorId,
268317
- memoryId: id,
268318
- }).unwrap();
268319
- setShowDeleteConfirm(null);
268320
- toast.success(t('memoryTabManageMemories.memoryDeletedSuccessfully'));
268321
- }
268322
- catch (error) {
268323
- console.error('Failed to delete memory:', error);
268324
- toast.error(t('memoryTabManageMemories.failedToDeleteMemory'));
268325
- }
268326
- };
268327
- const handleBulkDelete = async () => {
268328
- var _a;
268329
- if (!tenantKey || !username)
268330
- return;
268331
- setIsBulkDeleting(true);
268332
- try {
268333
- // Source bulk-delete from the unfiltered snapshot — `memories` only holds
268334
- // the current page, while bulk delete must remove every entry in the
268335
- // selected category.
268336
- const memoriesToDelete = ((_a = snapshotResponse === null || snapshotResponse === void 0 ? void 0 : snapshotResponse.results) !== null && _a !== void 0 ? _a : []).filter((memory) => memory.category.slug === selectedCategorySlug);
268337
- await Promise.all(memoriesToDelete.map((memory) => deleteMentorMemory({
268338
- org: tenantKey,
268339
- userId: username,
268340
- mentorId,
268341
- memoryId: memory.id,
268342
- }).unwrap()));
268343
- toast.success(t('memoryTabManageMemories.allCategoryMemoriesDeleted', { category: selectedCategoryName }));
268344
- setShowBulkDeleteConfirm(false);
268345
- }
268346
- catch (error) {
268347
- console.error('Failed to delete memories:', error);
268348
- toast.error(t('memoryTabManageMemories.failedToDeleteMemories'));
268349
- }
268350
- finally {
268351
- setIsBulkDeleting(false);
268352
- }
268353
- };
268354
- const startEdit = (memory) => {
268355
- setEditingMemory(memory);
268356
- setEditContent(memory.content);
268357
- setEditCategory(memory.category.name);
268358
- };
268359
- const saveEdit = async () => {
268360
- if (!editingMemory || !tenantKey || !username)
268361
- return;
268362
- try {
268363
- const selectedCat = categories.find((c) => c.name === editCategory);
268364
- const categoryChanged = !!selectedCat && selectedCat.slug !== editingMemory.category.slug;
268365
- await updateMentorMemory({
268366
- org: tenantKey,
268367
- userId: username,
268368
- mentorId,
268369
- memoryId: editingMemory.id,
268370
- data: {
268371
- content: editContent,
268372
- ...(categoryChanged ? { category_slug: selectedCat.slug } : {}),
268373
- },
268374
- }).unwrap();
268375
- toast.success(t('memoryTabManageMemories.memoryUpdatedSuccessfully'));
268376
- // Follow the entry to its new category tab so the user doesn't lose
268377
- // sight of it. Skip when viewing "All" — the entry is still visible.
268378
- if (categoryChanged && selectedCategorySlug !== 'all') {
268379
- setSelectedCategorySlug(selectedCat.slug);
268380
- }
268381
- setEditingMemory(null);
268382
- setEditContent('');
268383
- setEditCategory('');
268384
- }
268385
- catch (error) {
268386
- console.error('Failed to update memory:', error);
268387
- toast.error(t('memoryTabManageMemories.failedToUpdateMemory'));
268388
- }
268389
- };
268390
- const cancelEdit = () => {
268391
- setEditingMemory(null);
268392
- setEditContent('');
268393
- setEditCategory('');
268394
- };
268395
- const startAddMemory = () => {
268396
- setShowAddMemory(true);
268397
- setNewMemoryCategory(selectedCategoryName);
268398
- };
268399
- const saveNewMemory = async () => {
268400
- var _a;
268401
- if (!newMemoryContent.trim() || !tenantKey || !username)
268402
- return;
268403
- try {
268404
- const selectedCat = categories.find((c) => c.name === newMemoryCategory);
268405
- const categorySlug = (_a = selectedCat === null || selectedCat === void 0 ? void 0 : selectedCat.slug) !== null && _a !== void 0 ? _a : selectedCategorySlug;
268406
- await createMentorMemory({
268407
- org: tenantKey,
268408
- userId: username,
268409
- mentorId,
268410
- data: {
268411
- category_slug: categorySlug === 'all' ? 'general' : categorySlug,
268412
- content: newMemoryContent.trim(),
268413
- },
268414
- }).unwrap();
268415
- setShowAddMemory(false);
268416
- setNewMemoryContent('');
268417
- setNewMemoryCategory('');
268418
- if (selectedCat) {
268419
- setSelectedCategorySlug(selectedCat.slug);
268420
- }
268421
- toast.success(t('memoryTabManageMemories.memoryCreatedSuccessfully'));
268422
- }
268423
- catch (error) {
268424
- console.error('Failed to create memory:', error);
268425
- toast.error(t('memoryTabManageMemories.failedToCreateMemory'));
268426
- }
268427
- };
268428
- const cancelAddMemory = () => {
268429
- setShowAddMemory(false);
268430
- setNewMemoryContent('');
268431
- setNewMemoryCategory('');
268432
- };
268433
- const categoryNames = categories.map((c) => c.name);
268434
- return (jsxs(Fragment$1, { children: [jsxs("div", { className: "space-y-6", children: [jsx("div", { className: "rounded-lg border p-4", children: jsxs("div", { className: "flex flex-col gap-3 lg:flex-row", children: [jsx("div", { className: "relative min-w-[200px] flex-1", children: jsxs(Popover, { children: [jsx(PopoverTrigger, { asChild: true, children: jsxs(Button$1, { variant: "outline", role: "combobox", "aria-label": t('memoryTabManageMemories.searchForUser'), className: "w-full justify-between bg-transparent font-normal", children: [selectedLearner
268435
- ? ((_e = (_d = learners.find((learner) => learner.email === selectedLearner)) === null || _d === void 0 ? void 0 : _d.email) !== null && _e !== void 0 ? _e : selectedLearner)
268436
- : t('memoryTabManageMemories.searchForUser'), jsx(ChevronsUpDown, { className: "ml-2 h-4 w-4 shrink-0 opacity-50" })] }) }), jsx(PopoverContent, { className: "w-full p-0", align: "start", children: jsxs(Command, { children: [jsx(CommandInput, { placeholder: t('memoryTabManageMemories.searchUsersPlaceholder') }), jsxs(CommandList, { children: [jsx(CommandEmpty, { children: t('memoryTabManageMemories.noUsersFound') }), jsxs(CommandGroup, { children: [jsxs(CommandItem, { value: "", onSelect: () => {
268437
- setSelectedLearner('');
268438
- }, children: [jsx(Check, { className: cn('mr-2 h-4 w-4', !selectedLearner ? 'opacity-100' : 'opacity-0') }), t('memoryTabManageMemories.allUsers')] }), learners.map((learner) => (jsxs(CommandItem, { value: learner.email, onSelect: () => {
268439
- setSelectedLearner(learner.email);
268440
- }, children: [jsx(Check, { className: cn('mr-2 h-4 w-4', selectedLearner === learner.email ? 'opacity-100' : 'opacity-0') }), jsx("div", { className: "flex flex-col", children: jsx("span", { className: "font-medium text-gray-700", children: learner.email }) })] }, learner.email)))] })] })] }) })] }) }), jsxs(Popover, { children: [jsx(PopoverTrigger, { asChild: true, children: jsxs(Button$1, { variant: "outline", className: "flex w-full items-center gap-2 bg-transparent 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)
268441
- ? `${format$1(dateRange.from, 'MMM dd')} - ${format$1(dateRange.to, 'MMM dd')}`
268442
- : t('memoryTabManageMemories.pickDateRange')] }) }), jsx(PopoverContent, { className: "w-auto p-0", align: "start", children: jsx(Calendar, { mode: "range", selected: dateRange, onSelect: setDateRange, numberOfMonths: 2, initialFocus: true }) })] })] }) }), jsx("div", { children: jsxs("div", { className: "flex items-center justify-between gap-4", children: [jsxs("div", { className: "scrollbar-none hidden flex-1 items-center space-x-8 overflow-x-auto sm:flex", children: [visibleCategories.map((category) => (jsxs("button", { onClick: () => setSelectedCategorySlug(category.slug), className: `relative px-1 py-2 text-sm font-medium whitespace-nowrap transition-colors ${selectedCategorySlug === category.slug
268443
- ? 'text-[#38A1E5]'
268444
- : 'text-gray-600 hover:text-gray-900'}`, children: [category.name, selectedCategorySlug === category.slug && (jsx("div", { className: "absolute bottom-0 left-1/2 h-0.5 -translate-x-1/2 transform bg-[#38A1E5] transition-all duration-200", style: { width: `${category.name.length * 0.55}em` } }))] }, category.slug))), overflowCategories.length > 0 && (jsxs(DropdownMenu, { children: [jsx(DropdownMenuTrigger, { asChild: true, children: jsxs("button", { className: cn('relative flex items-center gap-1 px-1 py-2 text-sm font-medium whitespace-nowrap transition-colors', overflowSelected ? 'text-[#38A1E5]' : 'text-gray-600 hover:text-gray-900'), "aria-label": t('memoryTabManageMemories.moreCategories'), children: [overflowSelected ? overflowSelected.name : t('memoryTabManageMemories.more'), jsx(ChevronDown, { className: "h-3.5 w-3.5" }), overflowSelected && (jsx("div", { className: "absolute bottom-0 left-0 h-0.5 bg-[#38A1E5] transition-all duration-200", style: {
268445
- width: `${overflowSelected.name.length * 0.55}em`,
268446
- } }))] }) }), jsx(DropdownMenuContent, { align: "end", children: overflowCategories.map((category) => (jsx(DropdownMenuItem, { onClick: () => setSelectedCategorySlug(category.slug), className: selectedCategorySlug === category.slug ? 'bg-gray-100' : '', children: category.name }, category.slug))) })] }))] }), jsx("div", { className: "w-full py-2 sm:hidden", children: jsxs(DropdownMenu, { open: showMobileDropdown, onOpenChange: setShowMobileDropdown, children: [jsx(DropdownMenuTrigger, { asChild: true, children: jsxs(Button$1, { variant: "outline", className: "w-full justify-between bg-transparent", children: [selectedCategoryName, jsx(ChevronDown, { className: "h-4 w-4" })] }) }), jsx(DropdownMenuContent, { className: "w-full", children: categories.map((category) => (jsx(DropdownMenuItem, { onClick: () => {
268447
- setSelectedCategorySlug(category.slug);
268448
- setShowMobileDropdown(false);
268449
- }, className: selectedCategorySlug === category.slug ? 'bg-gray-100' : '', children: category.name }, category.slug))) })] }) }), jsxs(Button$1, { onClick: () => setShowManageCategories(true), size: "sm", variant: "outline", className: "shrink-0", "aria-label": t('memoryTabManageMemories.manageCategories'), children: [jsx(Tags, { className: "h-4 w-4 sm:mr-2" }), jsx("span", { className: "hidden sm:inline", children: t('memoryTabManageMemories.categories') })] }), jsxs(Button$1, { onClick: startAddMemory, size: "sm", className: "ibl-button-primary shrink-0", children: [jsx(Plus, { className: "mr-1 h-4 w-4 sm:mr-2" }), jsx("span", { className: "hidden sm:inline", children: t('memoryTabManageMemories.addMemory') }), jsx("span", { className: "sm:hidden", children: t('memoryTabManageMemories.add') })] })] }) }), jsx("div", { className: "space-y-3 px-1 sm:px-0", children: isLoadingMemories ? (jsx("div", { className: "py-8 text-center text-gray-600", children: jsx("p", { children: t('memoryTabManageMemories.loadingMemories') }) })) : (filteredMemories.map((memory) => {
268450
- const timeAgo = memory.createdAt
268451
- ? formatDistanceToNow(new Date(memory.createdAt), {
268452
- addSuffix: true,
268453
- })
268454
- : '';
268455
- const displayUser = memory.email || t('memoryTabManageMemories.unknown');
268456
- return (jsxs("div", { className: "flex items-start gap-3 rounded-lg border border-gray-200 bg-white p-3", children: [jsxs("div", { className: "flex-1", children: [(timeAgo || displayUser) && (jsxs("div", { className: "mb-2 flex items-center justify-between", children: [timeAgo && jsx("span", { className: "text-sm text-gray-600", children: timeAgo }), displayUser && (jsx("span", { className: "max-w-[100px] truncate text-sm text-gray-900 sm:max-w-[200px]", children: displayUser }))] })), jsx("div", { className: "text-sm leading-relaxed text-gray-900", children: memory.content })] }), jsxs(DropdownMenu, { children: [jsx(DropdownMenuTrigger, { asChild: true, children: jsx(Button$1, { variant: "ghost", size: "sm", className: "h-6 w-6 flex-shrink-0 p-0 text-gray-600 hover:text-gray-900", children: jsx(Ellipsis, { className: "h-4 w-4" }) }) }), jsxs(DropdownMenuContent, { align: "end", children: [jsx(DropdownMenuItem, { onClick: () => startEdit(memory), children: t('memoryTabManageMemories.edit') }), jsx(DropdownMenuItem, { onClick: () => setShowDeleteConfirm(memory.id), children: t('memoryTabManageMemories.delete') })] })] })] }, memory.id));
268457
- })) }), filteredMemories.length > 0 && selectedCategorySlug !== 'all' && (jsx("div", { className: "flex justify-end", children: jsx(Button$1, { variant: "outline", onClick: () => setShowBulkDeleteConfirm(true), children: t('memoryTabManageMemories.deleteAll') }) })), filteredMemories.length === 0 && !isLoadingMemories && (jsx("div", { className: "py-8 text-center text-gray-600", children: jsx("p", { children: t('memoryTabManageMemories.noSavedMemories') }) })), totalPages > 1 && (jsx("div", { className: "flex justify-center pt-2", children: jsx(IblPagination, { currentPage: page, totalPages: totalPages, onPageChange: setPage, disabled: isLoadingMemories }) }))] }), jsx(EditMemoryModal$1, { open: !!editingMemory, onOpenChange: (open) => !open && cancelEdit(), editContent: editContent, editCategory: editCategory, onContentChange: setEditContent, onCategoryChange: setEditCategory, onSave: saveEdit, onCancel: cancelEdit, categories: categoryNames, isSaving: isEditing }), jsx(AddMemoryModal$1, { open: showAddMemory, onOpenChange: (open) => !open && cancelAddMemory(), newMemoryContent: newMemoryContent, newMemoryCategory: newMemoryCategory, onContentChange: setNewMemoryContent, onCategoryChange: setNewMemoryCategory, onSave: saveNewMemory, onCancel: cancelAddMemory, categories: categoryNames, isSaving: isSaving }), jsx(DeleteMemoryModal$1, { open: !!showDeleteConfirm, onOpenChange: (open) => !open && setShowDeleteConfirm(null), onConfirm: () => showDeleteConfirm !== null && handleDeleteMemory(showDeleteConfirm), onCancel: () => setShowDeleteConfirm(null), isDeleting: isDeleting }), jsx(ManageCategoriesModal$1, { open: showManageCategories, onOpenChange: setShowManageCategories, tenantKey: tenantKey, mentorId: mentorId }), jsx(BulkDeleteMemoryModal$1, { open: showBulkDeleteConfirm, onOpenChange: setShowBulkDeleteConfirm, onConfirm: handleBulkDelete, onCancel: () => setShowBulkDeleteConfirm(false), isDeleting: isBulkDeleting, selectedCategory: selectedCategoryName })] }));
268458
- }
268459
-
268460
269585
  const AGENT_MEMORY_TAB_LABELS = {
268461
269586
  header: {
268462
269587
  title: 'Memory',
@@ -270340,6 +271465,9 @@ function CopyButton({ text, disabled = false }) {
270340
271465
  const systemPromptSchema$1 = z$2.object({
270341
271466
  prompt: z$2.string().min(1, 'Prompt is required'),
270342
271467
  });
271468
+ const emptyAllowedPromptSchema = z$2.object({
271469
+ prompt: z$2.string(),
271470
+ });
270343
271471
  const nonSystemPromptSchema$1 = z$2.object({
270344
271472
  category: z$2.string().min(1, 'Category is required'),
270345
271473
  prompt: z$2.string().min(1, 'Prompt is required'),
@@ -270368,7 +271496,11 @@ function EditPromptModal$1({ isOpen, onClose, selectedPrompt, handleSave, isEdit
270368
271496
  promptVisibility: selectedPrompt.promptVisibility,
270369
271497
  },
270370
271498
  validators: {
270371
- onChange: selectedPrompt.isSystem ? systemPromptSchema$1 : nonSystemPromptSchema$1,
271499
+ onChange: selectedPrompt.isSystem
271500
+ ? selectedPrompt.allowEmpty
271501
+ ? emptyAllowedPromptSchema
271502
+ : systemPromptSchema$1
271503
+ : nonSystemPromptSchema$1,
270372
271504
  },
270373
271505
  onSubmit: ({ value }) => {
270374
271506
  handleSave(selectedPrompt, value);
@@ -270389,8 +271521,8 @@ function EditPromptModal$1({ isOpen, onClose, selectedPrompt, handleSave, isEdit
270389
271521
  }, children: [jsx(DialogHeader, { children: jsx(DialogTitle, { className: "text-start text-base font-semibold text-[#646464]", children: t('promptsTabEditPromptModal.editTitle', { label: selectedPrompt.label }) }) }), jsxs("div", { className: "mt-7 grid gap-4", children: [!selectedPrompt.isSystem && (jsx(form.Field, { name: "category", children: (field) => (jsxs("div", { className: "space-y-2", children: [jsx(Label$1, { className: "flex items-center text-sm font-medium text-[#646464]", children: t('promptsTabEditPromptModal.category') }), jsxs(Select$1, { disabled: isDisabled, value: field.state.value, onValueChange: field.handleChange, children: [jsx(SelectTrigger, { className: "py-6", "aria-label": t('promptsTabEditPromptModal.selectCategory'), children: jsx(SelectValue, { placeholder: t('promptsTabEditPromptModal.selectCategory') }) }), jsx(SelectContent, { children: promptCategories === null || promptCategories === void 0 ? void 0 : promptCategories.map((category) => (jsx(SelectItem, { value: category.name, children: category.name }, category.id))) })] })] })) })), !selectedPrompt.isSystem && (jsx(form.Field, { name: "promptVisibility", children: (field) => (jsxs("div", { className: "space-y-2", children: [jsx(Label$1, { className: "flex items-center text-sm font-medium text-[#646464]", children: t('promptsTabEditPromptModal.visibility') }), jsxs(Select$1, { disabled: isDisabled, value: field.state.value, onValueChange: (value) => field.handleChange(value), children: [jsx(SelectTrigger, { className: "py-6", "aria-label": t('promptsTabEditPromptModal.selectVisibility'), children: jsx(SelectValue, { placeholder: t('promptsTabEditPromptModal.selectVisibility') }) }), jsx(SelectContent, { children: (visibilityOptions !== null && visibilityOptions !== void 0 ? visibilityOptions : []).map((option) => (jsx(SelectItem, { value: option.value, children: option.label }, option.value))) })] })] })) })), jsx(form.Field, { name: "prompt", children: (field) => {
270390
271522
  const hasNoValue = field.state.value === '';
270391
271523
  const isDirty = field.state.meta.isDirty;
270392
- const hasNoValueAndIsDirty = hasNoValue && isDirty;
270393
- return (jsxs("div", { className: "space-y-2 overflow-hidden", children: [jsx(Label$1, { htmlFor: "prompt-textarea", className: "flex items-center text-sm font-medium text-[#646464]", children: selectedPrompt.label }), jsx(RichTextEditor, { value: field.state.value, onChange: field.handleChange, disabled: isDisabled }), hasNoValueAndIsDirty && (jsx("p", { className: "text-xs text-red-500", children: t('promptsTabEditPromptModal.promptRequired') }))] }));
271524
+ const hasNoValueAndIsDirty = hasNoValue && isDirty && !selectedPrompt.allowEmpty;
271525
+ return (jsxs("div", { className: "space-y-2 overflow-hidden", children: [!selectedPrompt.hideEditorLabel && (jsx(Label$1, { htmlFor: "prompt-textarea", className: "flex items-center text-sm font-medium text-[#646464]", children: selectedPrompt.label })), jsx(RichTextEditor, { value: field.state.value, onChange: field.handleChange, disabled: isDisabled }), hasNoValueAndIsDirty && (jsx("p", { className: "text-xs text-red-500", children: t('promptsTabEditPromptModal.promptRequired') }))] }));
270394
271526
  } })] }), jsx(DialogFooter, { children: jsx("div", { className: "flex justify-end gap-2 pt-4", children: jsx(form.Subscribe, { selector: (state) => ({ isFormValue: state.canSubmit }), children: ({ isFormValue }) => (jsx(Button$1, { type: "submit", className: "bg-gradient-to-r from-[#2563EB] to-[#93C5FD] text-white hover:opacity-90", disabled: isDisabled || !isFormValue, children: isEditing
270395
271527
  ? t('promptsTabEditPromptModal.saving')
270396
271528
  : t('promptsTabEditPromptModal.save') })) }) }) })] }) }) }));
@@ -270912,6 +272044,27 @@ const AGENT_VOICE_TAB_LABELS = {
270912
272044
  previewAria: (voiceName, action) => `${action === 'play' ? 'Preview' : 'Stop'} ${voiceName} voice`,
270913
272045
  saveButton: 'Save voice',
270914
272046
  savingButton: 'Saving…',
272047
+ instructions: {
272048
+ label: 'Voice Instructions',
272049
+ tooltip: 'Describe how the agent should sound when it speaks — tone, pace, emotion, accent, energy. This changes the delivery, not what it says. Example: "Speak slowly in a warm, encouraging tone, like a patient tutor."',
272050
+ placeholder: 'e.g. Speak slowly in a warm, encouraging tone, like a patient tutor.',
272051
+ helpText: "Works with OpenAI voices (sent as speech instructions) and Google voices (sent as a synthesis prompt); other voices ignore it. Leave blank for the provider's default delivery — instructions switch OpenAI to a pricier, instruction-capable speech model.",
272052
+ presetsLabel: 'Examples',
272053
+ presets: {
272054
+ warm: {
272055
+ label: 'Warm and encouraging',
272056
+ text: 'Speak slowly in a warm, encouraging tone, like a patient tutor.',
272057
+ },
272058
+ calm: {
272059
+ label: 'Calm and measured',
272060
+ text: 'Speak in a calm, measured voice with a steady, unhurried pace.',
272061
+ },
272062
+ energetic: {
272063
+ label: 'Energetic and upbeat',
272064
+ text: 'Speak with upbeat energy and enthusiasm, keeping a lively pace.',
272065
+ },
272066
+ },
272067
+ },
270915
272068
  },
270916
272069
  callConfig: {
270917
272070
  title: 'Voice call',
@@ -271012,6 +272165,27 @@ function buildVoiceTabLabels(t) {
271012
272165
  : t('voiceTabLabels.mentorVoice.previewAria.stop', { voiceName }),
271013
272166
  saveButton: t('voiceTabLabels.mentorVoice.saveButton'),
271014
272167
  savingButton: t('voiceTabLabels.mentorVoice.savingButton'),
272168
+ instructions: {
272169
+ label: t('voiceTabLabels.mentorVoice.instructions.label'),
272170
+ tooltip: t('voiceTabLabels.mentorVoice.instructions.tooltip'),
272171
+ placeholder: t('voiceTabLabels.mentorVoice.instructions.placeholder'),
272172
+ helpText: t('voiceTabLabels.mentorVoice.instructions.helpText'),
272173
+ presetsLabel: t('voiceTabLabels.mentorVoice.instructions.presetsLabel'),
272174
+ presets: {
272175
+ warm: {
272176
+ label: t('voiceTabLabels.mentorVoice.instructions.presets.warm.label'),
272177
+ text: t('voiceTabLabels.mentorVoice.instructions.presets.warm.text'),
272178
+ },
272179
+ calm: {
272180
+ label: t('voiceTabLabels.mentorVoice.instructions.presets.calm.label'),
272181
+ text: t('voiceTabLabels.mentorVoice.instructions.presets.calm.text'),
272182
+ },
272183
+ energetic: {
272184
+ label: t('voiceTabLabels.mentorVoice.instructions.presets.energetic.label'),
272185
+ text: t('voiceTabLabels.mentorVoice.instructions.presets.energetic.text'),
272186
+ },
272187
+ },
272188
+ },
271015
272189
  },
271016
272190
  callConfig: {
271017
272191
  title: t('voiceTabLabels.callConfig.title'),
@@ -271551,10 +272725,29 @@ function FieldWrap({ label, tooltip, children }) {
271551
272725
  return (jsxs("div", { className: "space-y-2", children: [jsxs("div", { className: "flex items-center gap-2", children: [jsx(Label$1, { className: "text-sm font-medium text-[#646464]", children: label }), tooltip && (jsx(TooltipProvider, { children: jsxs(Tooltip$1, { children: [jsx(TooltipTrigger, { type: "button", "aria-label": t('voiceTabCallConfigSection.moreInfoAbout', { label }), children: jsx(Info$3, { className: "h-4 w-4 text-gray-400" }) }), jsx(TooltipContent, { side: "top", align: "start", sideOffset: 6, collisionPadding: 16, className: "ibl-tooltip-content z-50 max-w-[300px]", children: jsx("p", { className: "text-xs leading-relaxed whitespace-normal", children: tooltip }) })] }) }))] }), children] }));
271552
272726
  }
271553
272727
 
272728
+ /**
272729
+ * Display-only card for a single prompt. Mirrors the visual pattern
272730
+ * used by `AgentPromptsTab` (System Prompt / Proactive Prompt cards):
272731
+ * a header, a 📝-prefixed body, and Edit + Copy action buttons at the
272732
+ * bottom. "Edit" is wired by the parent (typically opens the shared
272733
+ * `EditPromptModal`); the new value is written back via the parent's
272734
+ * `onEdit` handler.
272735
+ */
272736
+ function PromptCard$1({ label, placeholder, value, disabled, renderContent, onEdit, testId = 'screensharing-prompt-card', headerExtra, }) {
272737
+ const isEmpty = !value || value.trim() === '';
272738
+ return (jsxs("div", { className: "overflow-hidden rounded-lg bg-gray-50", "data-testid": testId, children: [jsx("div", { className: "flex items-center justify-between border-b border-gray-200 p-[1.12rem]", children: jsxs("div", { className: "flex items-center gap-2", children: [jsx("h3", { className: "text-sm font-medium text-gray-900", children: label }), headerExtra] }) }), jsxs("div", { className: "flex items-start gap-2 p-4", children: [jsx("div", { className: "mt-1 flex-shrink-0", "aria-hidden": "true", children: "\uD83D\uDCDD" }), jsx("div", { className: "flex h-[180px] flex-1 flex-col", children: jsx("div", { className: "mb-4 flex-grow overflow-y-auto", tabIndex: 0, role: "region", "aria-label": `${label} content`, children: isEmpty ? (jsx("p", { className: "text-sm text-gray-400 italic", children: placeholder })) : (renderContent(value)) }) })] }), jsxs("div", { className: "flex w-full gap-2 px-4 pb-4", children: [jsxs(Button$1, { variant: "outline", size: "sm", className: "h-8 flex-1 py-5", disabled: disabled, onClick: onEdit, "aria-label": `Edit ${label}`, children: [jsx(SquarePen, { className: "mr-2 h-4 w-4" }), "Edit"] }), jsx(CopyButton, { text: value, disabled: disabled })] })] }));
272739
+ }
272740
+
271554
272741
  const SUB_TAB_VALUES = {
271555
272742
  voice: 'voice',
271556
272743
  callConfig: 'call-config',
271557
272744
  };
272745
+ /**
272746
+ * Soft cap for the voice-instructions textarea. The backend column is an
272747
+ * unbounded TextField — this is purely a UI guardrail (TTS style prompts
272748
+ * gain nothing from being longer than this).
272749
+ */
272750
+ const VOICE_INSTRUCTIONS_MAX = 1000;
271558
272751
  /**
271559
272752
  * Pull a voice **name** out of the mentor settings response, which can
271560
272753
  * return a plain string, a numeric id, or a serialized object with a
@@ -271571,7 +272764,7 @@ function readVoiceName(value) {
271571
272764
  return null;
271572
272765
  }
271573
272766
  function AgentVoiceTab({ labels: labelsOverride, defaultSubTab = 'voice', renderPromptContent, tenantKey: tenantKeyProp, mentorId: mentorIdProp, username: usernameProp, enableRBAC: enableRBACProp, }) {
271574
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o;
272767
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p;
271575
272768
  const ctx = useAgentSettingsOptional();
271576
272769
  const tenantKey = (_a = tenantKeyProp !== null && tenantKeyProp !== void 0 ? tenantKeyProp : ctx === null || ctx === void 0 ? void 0 : ctx.tenantKey) !== null && _a !== void 0 ? _a : '';
271577
272770
  const mentorId = (_b = mentorIdProp !== null && mentorIdProp !== void 0 ? mentorIdProp : ctx === null || ctx === void 0 ? void 0 : ctx.mentorId) !== null && _b !== void 0 ? _b : '';
@@ -271605,15 +272798,19 @@ function AgentVoiceTab({ labels: labelsOverride, defaultSubTab = 'voice', render
271605
272798
  provider: 'google',
271606
272799
  name: savedGoogleName,
271607
272800
  });
272801
+ const savedInstructions = typeof (mentorSettings === null || mentorSettings === void 0 ? void 0 : mentorSettings.voice_instructions) === 'string' ? mentorSettings.voice_instructions : '';
271608
272802
  // Picked voices override the resolved server values once the user
271609
272803
  // makes a choice. Null means "use what came from the server".
271610
272804
  const [provider, setProvider] = React__default.useState(initialProvider);
271611
272805
  const [pickedOpenaiVoice, setPickedOpenaiVoice] = React__default.useState(null);
271612
272806
  const [pickedGoogleVoice, setPickedGoogleVoice] = React__default.useState(null);
272807
+ const [instructions, setInstructions] = React__default.useState(savedInstructions);
272808
+ const [selectedPrompt, setSelectedPrompt] = React__default.useState(null);
271613
272809
  React__default.useEffect(() => {
271614
272810
  setProvider(initialProvider);
271615
272811
  setPickedOpenaiVoice(null);
271616
272812
  setPickedGoogleVoice(null);
272813
+ setInstructions(savedInstructions);
271617
272814
  // eslint-disable-next-line react-hooks/exhaustive-deps
271618
272815
  }, [mentorId, rawMentorSettings]);
271619
272816
  const effectiveOpenaiVoice = (_h = pickedOpenaiVoice !== null && pickedOpenaiVoice !== void 0 ? pickedOpenaiVoice : resolvedOpenaiVoice) !== null && _h !== void 0 ? _h : null;
@@ -271651,7 +272848,14 @@ function AgentVoiceTab({ labels: labelsOverride, defaultSubTab = 'voice', render
271651
272848
  }
271652
272849
  };
271653
272850
  const isDisabled = isMentorSettingsLoading || isSavingMentor;
271654
- const isDirty = provider !== initialProvider || pickedOpenaiVoice != null || pickedGoogleVoice != null;
272851
+ const instructionsDirty = instructions !== savedInstructions;
272852
+ // Soft cap only — the modal editor doesn't enforce a max length, so we
272853
+ // block Save instead of truncating what the user wrote.
272854
+ const instructionsOverCap = instructions.length > VOICE_INSTRUCTIONS_MAX;
272855
+ const isDirty = provider !== initialProvider ||
272856
+ pickedOpenaiVoice != null ||
272857
+ pickedGoogleVoice != null ||
272858
+ instructionsDirty;
271655
272859
  /**
271656
272860
  * Provider chips. We reuse the OpenAI / Google logos already shipped in
271657
272861
  * the host's static-root (see `getLLMProviderDetails` for the canonical
@@ -271690,6 +272894,12 @@ function AgentVoiceTab({ labels: labelsOverride, defaultSubTab = 'voice', render
271690
272894
  if (provider === 'google' && pickedGoogleVoice) {
271691
272895
  formData.google_voice = pickedGoogleVoice.id;
271692
272896
  }
272897
+ // Same "absent = keep" contract: only send voice_instructions when
272898
+ // the user actually edited it. Clearing sends "" (never null) —
272899
+ // that's what resets the stored value server-side.
272900
+ if (instructionsDirty) {
272901
+ formData.voice_instructions = instructions;
272902
+ }
271693
272903
  await editMentor({
271694
272904
  mentor: mentorId,
271695
272905
  org: tenantKey,
@@ -271715,43 +272925,60 @@ function AgentVoiceTab({ labels: labelsOverride, defaultSubTab = 'voice', render
271715
272925
  else if (provider === 'google')
271716
272926
  setPickedGoogleVoice(voice);
271717
272927
  };
271718
- return (jsxs(Fragment$1, { children: [jsx("div", { className: "flex h-[73px] flex-shrink-0 items-center border-b border-gray-200 bg-white p-4 lg:block", children: jsxs("div", { children: [jsx("h3", { className: "mb-1 text-base font-medium text-gray-900", children: labels.header.title }), jsx("p", { className: "text-xs text-gray-600", children: labels.header.description })] }) }), jsx("div", { className: "flex-1 space-y-4 p-3 lg:p-4", style: { overflowY: 'auto', overflowX: 'hidden' }, "data-testid": "voice-tab-body", children: isMentorSettingsLoading ? (jsx("div", { className: "flex items-center justify-center py-12", "data-testid": "voice-tab-loading", children: jsx(Spinner, {}) })) : (jsx(CapabilityGate, { title: labels.capability.title, description: labels.capability.description, offHint: labels.capability.offHint, enabled: voiceCallEnabled, onToggle: handleToggleVoiceCall, disabled: isDisabled || isTogglingVoiceCall, ariaLabel: labels.capability.title, toggleTestId: "voice-capability-toggle", children: jsxs(Tabs, { defaultValue: SUB_TAB_VALUES[defaultSubTab], className: "w-full", children: [jsxs(TabsList, { "aria-label": labels.header.title, "data-testid": "voice-sub-tabs", children: [jsx(TabsTrigger, { value: SUB_TAB_VALUES.voice, "data-testid": "voice-sub-tab-voice", children: labels.subTabs.voice }), jsx(TabsTrigger, { value: SUB_TAB_VALUES.callConfig, "data-testid": "voice-sub-tab-call-config", children: labels.subTabs.callConfig })] }), jsxs(TabsContent, { value: SUB_TAB_VALUES.voice, className: "space-y-4", children: [jsx("p", { className: "text-xs text-gray-600", children: labels.mentorVoice.description }), jsx(WithFormPermissions, { name: "voice_provider",
271719
- // @ts-expect-error permissions.field is opaque
271720
- permissions: (_l = mentorSettings === null || mentorSettings === void 0 ? void 0 : mentorSettings.permissions) === null || _l === void 0 ? void 0 : _l.field, enableRBAC: enableRBAC, children: ({ disabled }) => (jsxs("div", { className: "space-y-2", children: [jsxs("div", { className: "flex items-center gap-2", children: [jsx(Label$1, { className: "text-sm font-medium text-[#646464]", children: labels.mentorVoice.providerLabel }), jsx(FieldTooltip, { text: labels.mentorVoice.providerTooltip })] }), jsx("div", { className: "grid grid-cols-1 gap-3 sm:grid-cols-3", role: "radiogroup", "aria-label": labels.mentorVoice.providerLabel, children: providerOptions.map((option) => {
271721
- const isSelected = provider === option.value;
271722
- const isDisabledOption = isDisabled || disabled;
271723
- return (jsxs("button", { type: "button", role: "radio", "aria-checked": isSelected, "aria-label": option.label, disabled: isDisabledOption, "data-testid": `voice-provider-${option.value}`, "data-voice-provider": option.value, onClick: () => setProvider(option.value), className: cn('flex flex-col items-start gap-2 rounded-lg border-2 p-3 text-left transition-all hover:shadow-sm', isSelected
271724
- ? 'border-blue-500 bg-blue-50/40'
271725
- : 'border-gray-200 bg-white hover:border-gray-300', isDisabledOption && 'cursor-not-allowed opacity-60'), children: [jsxs("div", { className: "flex items-center gap-2", children: [jsx("span", { className: "flex h-6 w-6 flex-shrink-0 items-center justify-center", children: option.logo.type === 'image' ? (jsx(Image$4, { src: option.logo.src, alt: option.logo.alt, width: 24, height: 24, className: "h-6 w-6 object-contain" })) : (jsx(option.logo.Icon, { className: "h-5 w-5 text-blue-600", "aria-hidden": "true" })) }), jsx("span", { className: "text-sm font-medium text-gray-900", children: option.label })] }), jsx("p", { className: "text-xs text-gray-500", children: option.description })] }, option.value));
271726
- }) })] })) }), (provider === 'openai' || provider === 'google') && (jsx(WithFormPermissions, { name: provider === 'openai' ? 'openai_voice' : 'google_voice',
271727
- // @ts-expect-error permissions.field is opaque
271728
- permissions: (_m = mentorSettings === null || mentorSettings === void 0 ? void 0 : mentorSettings.permissions) === null || _m === void 0 ? void 0 : _m.field, enableRBAC: enableRBAC, children: ({ disabled }) => (jsxs("div", { className: "space-y-2", children: [jsx(Label$1, { className: "text-sm font-medium text-[#646464]", children: t('tabsVoiceTab.voiceLabel') }), jsx(VoicePickerTrigger, { org: tenantKey, userId: username, provider: provider, selectedVoice: selectedVoice, onSelect: onSelectVoice, disabled: isDisabled || disabled, labels: labels.mentorVoice, modalTitle: t('tabsVoiceTab.selectVoiceModalTitle', {
271729
- voiceType: labels.mentorVoice.voicePickerLabel[provider],
271730
- }), modalDescription: t('tabsVoiceTab.selectVoiceModalDescription'), testId: "mentor-voice-trigger" })] })) })), jsx("div", { className: "flex items-center justify-end border-t border-gray-100 pt-3", children: jsx(Button$1, { type: "button", onClick: handleSaveVoice, disabled: isDisabled || !isDirty, "data-testid": "voice-save-button", className: "bg-gradient-to-r from-[#2563EB] to-[#93C5FD] text-white hover:opacity-90", children: isSavingMentor
271731
- ? labels.mentorVoice.savingButton
271732
- : labels.mentorVoice.saveButton }) })] }), jsxs(TabsContent, { value: SUB_TAB_VALUES.callConfig, className: "space-y-4", children: [jsx("p", { className: "text-xs text-gray-600", children: labels.callConfig.description }), mentorId && username && tenantKey && (jsx(CallConfigSection, { org: tenantKey, userId: username, mentorId: mentorId, isDisabled: isDisabled, labels: labels.callConfig, voicePickerLabels: labels.mentorVoice, initialConfig: (_o = mentorSettings === null || mentorSettings === void 0 ? void 0 : mentorSettings.call_configuration) !== null && _o !== void 0 ? _o : null, renderPromptContent: renderPromptContent, toastLabels: {
271733
- saved: labels.toasts.callConfigSaved,
271734
- error: labels.toasts.callConfigError,
271735
- } }))] })] }) })) })] }));
272928
+ // Mirrors `AgentScreenShareTab`: hosts can render prompt content as
272929
+ // Markdown via `renderPromptContent`; plain text otherwise.
272930
+ const renderInstructionsContent = (text) => {
272931
+ if (renderPromptContent)
272932
+ return renderPromptContent(text);
272933
+ return jsx("p", { className: "text-sm whitespace-pre-wrap text-gray-700", children: text });
272934
+ };
272935
+ return (jsxs(Fragment$1, { children: [jsx("div", { className: "flex h-[73px] flex-shrink-0 items-center border-b border-gray-200 bg-white p-4 lg:block", children: jsxs("div", { children: [jsx("h3", { className: "mb-1 text-base font-medium text-gray-900", children: labels.header.title }), jsx("p", { className: "text-xs text-gray-600", children: labels.header.description })] }) }), jsx("div", { className: "flex-1 space-y-4 p-3 lg:p-4", style: { overflowY: 'auto', overflowX: 'hidden' }, "data-testid": "voice-tab-body", children: isMentorSettingsLoading ? (jsx("div", { className: "flex items-center justify-center py-12", "data-testid": "voice-tab-loading", children: jsx(Spinner, {}) })) : (jsxs(CapabilityGate, { title: labels.capability.title, description: labels.capability.description, offHint: labels.capability.offHint, enabled: voiceCallEnabled, onToggle: handleToggleVoiceCall, disabled: isDisabled || isTogglingVoiceCall, ariaLabel: labels.capability.title, toggleTestId: "voice-capability-toggle", children: [jsxs(Tabs, { defaultValue: SUB_TAB_VALUES[defaultSubTab], className: "w-full", children: [jsxs(TabsList, { "aria-label": labels.header.title, "data-testid": "voice-sub-tabs", children: [jsx(TabsTrigger, { value: SUB_TAB_VALUES.voice, "data-testid": "voice-sub-tab-voice", children: labels.subTabs.voice }), jsx(TabsTrigger, { value: SUB_TAB_VALUES.callConfig, "data-testid": "voice-sub-tab-call-config", children: labels.subTabs.callConfig })] }), jsxs(TabsContent, { value: SUB_TAB_VALUES.voice, className: "space-y-4", children: [jsx("p", { className: "text-xs text-gray-600", children: labels.mentorVoice.description }), jsx(WithFormPermissions, { name: "voice_provider",
272936
+ // @ts-expect-error permissions.field is opaque
272937
+ permissions: (_l = mentorSettings === null || mentorSettings === void 0 ? void 0 : mentorSettings.permissions) === null || _l === void 0 ? void 0 : _l.field, enableRBAC: enableRBAC, children: ({ disabled }) => (jsxs("div", { className: "space-y-2", children: [jsxs("div", { className: "flex items-center gap-2", children: [jsx(Label$1, { className: "text-sm font-medium text-[#646464]", children: labels.mentorVoice.providerLabel }), jsx(FieldTooltip, { text: labels.mentorVoice.providerTooltip })] }), jsx("div", { className: "grid grid-cols-1 gap-3 sm:grid-cols-3", role: "radiogroup", "aria-label": labels.mentorVoice.providerLabel, children: providerOptions.map((option) => {
272938
+ const isSelected = provider === option.value;
272939
+ const isDisabledOption = isDisabled || disabled;
272940
+ return (jsxs("button", { type: "button", role: "radio", "aria-checked": isSelected, "aria-label": option.label, disabled: isDisabledOption, "data-testid": `voice-provider-${option.value}`, "data-voice-provider": option.value, onClick: () => setProvider(option.value), className: cn('flex flex-col items-start gap-2 rounded-lg border-2 p-3 text-left transition-all hover:shadow-sm', isSelected
272941
+ ? 'border-blue-500 bg-blue-50/40'
272942
+ : 'border-gray-200 bg-white hover:border-gray-300', isDisabledOption && 'cursor-not-allowed opacity-60'), children: [jsxs("div", { className: "flex items-center gap-2", children: [jsx("span", { className: "flex h-6 w-6 flex-shrink-0 items-center justify-center", children: option.logo.type === 'image' ? (jsx(Image$4, { src: option.logo.src, alt: option.logo.alt, width: 24, height: 24, className: "h-6 w-6 object-contain" })) : (jsx(option.logo.Icon, { className: "h-5 w-5 text-blue-600", "aria-hidden": "true" })) }), jsx("span", { className: "text-sm font-medium text-gray-900", children: option.label })] }), jsx("p", { className: "text-xs text-gray-500", children: option.description })] }, option.value));
272943
+ }) })] })) }), (provider === 'openai' || provider === 'google') && (jsx(WithFormPermissions, { name: provider === 'openai' ? 'openai_voice' : 'google_voice',
272944
+ // @ts-expect-error permissions.field is opaque
272945
+ permissions: (_m = mentorSettings === null || mentorSettings === void 0 ? void 0 : mentorSettings.permissions) === null || _m === void 0 ? void 0 : _m.field, enableRBAC: enableRBAC, children: ({ disabled }) => (jsxs("div", { className: "space-y-2", children: [jsx(Label$1, { className: "text-sm font-medium text-[#646464]", children: t('tabsVoiceTab.voiceLabel') }), jsx(VoicePickerTrigger, { org: tenantKey, userId: username, provider: provider, selectedVoice: selectedVoice, onSelect: onSelectVoice, disabled: isDisabled || disabled, labels: labels.mentorVoice, modalTitle: t('tabsVoiceTab.selectVoiceModalTitle', {
272946
+ voiceType: labels.mentorVoice.voicePickerLabel[provider],
272947
+ }), modalDescription: t('tabsVoiceTab.selectVoiceModalDescription'), testId: "mentor-voice-trigger" })] })) })), (provider === 'openai' || provider === 'google') && (jsx(WithFormPermissions, { name: "voice_instructions",
272948
+ // @ts-expect-error permissions.field is opaque
272949
+ permissions: (_o = mentorSettings === null || mentorSettings === void 0 ? void 0 : mentorSettings.permissions) === null || _o === void 0 ? void 0 : _o.field, enableRBAC: enableRBAC, children: ({ disabled }) => {
272950
+ const isFieldDisabled = isDisabled || disabled;
272951
+ const presetKeys = ['warm', 'calm', 'energetic'];
272952
+ return (jsxs("div", { className: "space-y-2", children: [jsx(PromptCard$1, { label: labels.mentorVoice.instructions.label, placeholder: labels.mentorVoice.instructions.placeholder, value: instructions, disabled: isFieldDisabled, renderContent: renderInstructionsContent, testId: "voice-instructions-card", headerExtra: jsx(FieldTooltip, { text: labels.mentorVoice.instructions.tooltip }), onEdit: () => setSelectedPrompt({
272953
+ label: labels.mentorVoice.instructions.label,
272954
+ isSystem: true,
272955
+ name: 'voice_instructions',
272956
+ prompt: instructions,
272957
+ allowEmpty: true,
272958
+ hideEditorLabel: true,
272959
+ }) }), jsxs("div", { className: "flex items-start justify-between gap-3", children: [jsx("p", { id: "voice-instructions-help", className: "text-xs text-gray-500", children: labels.mentorVoice.instructions.helpText }), jsxs("span", { id: "voice-instructions-counter", "aria-live": "polite", "data-testid": "voice-instructions-counter", className: cn('flex-shrink-0 text-xs text-gray-400', instructionsOverCap && 'text-red-500'), children: [instructions.length, "/", VOICE_INSTRUCTIONS_MAX] })] }), jsxs("div", { className: "flex flex-wrap items-center gap-2", role: "group", "aria-label": labels.mentorVoice.instructions.presetsLabel, children: [jsxs("span", { className: "text-xs text-gray-500", children: [labels.mentorVoice.instructions.presetsLabel, ":"] }), presetKeys.map((key) => (jsx("button", { type: "button", disabled: isFieldDisabled, "data-testid": `voice-instructions-preset-${key}`, onClick: () => setInstructions(labels.mentorVoice.instructions.presets[key].text), className: cn('inline-flex items-center rounded-full border border-gray-300 bg-white px-3 py-1 text-xs text-gray-700 transition-colors hover:bg-gray-50', isFieldDisabled && 'cursor-not-allowed opacity-50'), children: labels.mentorVoice.instructions.presets[key].label }, key)))] })] }));
272960
+ } })), jsx("div", { className: "flex items-center justify-end border-t border-gray-100 pt-3", children: jsx(Button$1, { type: "button", onClick: handleSaveVoice, disabled: isDisabled || !isDirty || instructionsOverCap, "data-testid": "voice-save-button", className: "bg-gradient-to-r from-[#2563EB] to-[#93C5FD] text-white hover:opacity-90", children: isSavingMentor
272961
+ ? labels.mentorVoice.savingButton
272962
+ : labels.mentorVoice.saveButton }) })] }), jsxs(TabsContent, { value: SUB_TAB_VALUES.callConfig, className: "space-y-4", children: [jsx("p", { className: "text-xs text-gray-600", children: labels.callConfig.description }), mentorId && username && tenantKey && (jsx(CallConfigSection, { org: tenantKey, userId: username, mentorId: mentorId, isDisabled: isDisabled, labels: labels.callConfig, voicePickerLabels: labels.mentorVoice, initialConfig: (_p = mentorSettings === null || mentorSettings === void 0 ? void 0 : mentorSettings.call_configuration) !== null && _p !== void 0 ? _p : null, renderPromptContent: renderPromptContent, toastLabels: {
272963
+ saved: labels.toasts.callConfigSaved,
272964
+ error: labels.toasts.callConfigError,
272965
+ } }))] })] }), selectedPrompt && (
272966
+ // `EditPromptModal` calls strict `useAgentSettings()`. The host
272967
+ // may not have wrapped this tab in `<AgentSettingsProvider>`
272968
+ // (older integrations pass identity via props), so re-provide
272969
+ // whatever we resolved — same pattern as `AgentScreenShareTab`.
272970
+ jsx(AgentSettingsProvider, { tenantKey: tenantKey, mentorId: mentorId, username: username, enableRBAC: enableRBAC, rbacPermissions: ctx === null || ctx === void 0 ? void 0 : ctx.rbacPermissions, executeGatedAction: ctx === null || ctx === void 0 ? void 0 : ctx.executeGatedAction, visibilityOptions: ctx === null || ctx === void 0 ? void 0 : ctx.visibilityOptions, children: jsx(EditPromptModal$1, { isOpen: true, onClose: () => setSelectedPrompt(null), selectedPrompt: selectedPrompt, isEditing: isSavingMentor, handleSave: (prompt, values) => {
272971
+ if (prompt.name === 'voice_instructions') {
272972
+ setInstructions(values.prompt);
272973
+ }
272974
+ setSelectedPrompt(null);
272975
+ } }) }))] })) })] }));
271736
272976
  }
271737
272977
  function FieldTooltip({ text }) {
271738
272978
  const t = useT();
271739
272979
  return (jsx(TooltipProvider, { delayDuration: 200, children: jsxs(Tooltip$1, { children: [jsx(TooltipTrigger, { type: "button", "aria-label": t('tabsVoiceTab.fieldTooltipMoreInfo'), children: jsx(Info$3, { className: "h-4 w-4 text-gray-400" }) }), jsx(TooltipContent, { side: "top", align: "start", sideOffset: 6, collisionPadding: 16, className: "ibl-tooltip-content z-50 max-w-[300px]", children: jsx("p", { className: "text-xs leading-relaxed whitespace-normal", children: text }) })] }) }));
271740
272980
  }
271741
272981
 
271742
- /**
271743
- * Display-only card for a single prompt. Mirrors the visual pattern
271744
- * used by `AgentPromptsTab` (System Prompt / Proactive Prompt cards):
271745
- * a header, a 📝-prefixed body, and Edit + Copy action buttons at the
271746
- * bottom. "Edit" is wired by the parent (typically opens the shared
271747
- * `EditPromptModal`); the new value is written back via the parent's
271748
- * `onEdit` handler.
271749
- */
271750
- function PromptCard$1({ label, placeholder, value, disabled, renderContent, onEdit, }) {
271751
- const isEmpty = !value || value.trim() === '';
271752
- return (jsxs("div", { className: "overflow-hidden rounded-lg bg-gray-50", "data-testid": "screensharing-prompt-card", children: [jsx("div", { className: "flex items-center justify-between border-b border-gray-200 p-[1.12rem]", children: jsx("div", { className: "flex items-center gap-2", children: jsx("h3", { className: "text-sm font-medium text-gray-900", children: label }) }) }), jsxs("div", { className: "flex items-start gap-2 p-4", children: [jsx("div", { className: "mt-1 flex-shrink-0", "aria-hidden": "true", children: "\uD83D\uDCDD" }), jsx("div", { className: "flex h-[180px] flex-1 flex-col", children: jsx("div", { className: "mb-4 flex-grow overflow-y-auto", tabIndex: 0, role: "region", "aria-label": `${label} content`, children: isEmpty ? (jsx("p", { className: "text-sm text-gray-400 italic", children: placeholder })) : (renderContent(value)) }) })] }), jsxs("div", { className: "flex w-full gap-2 px-4 pb-4", children: [jsxs(Button$1, { variant: "outline", size: "sm", className: "h-8 flex-1 py-5", disabled: disabled, onClick: onEdit, "aria-label": `Edit ${label}`, children: [jsx(SquarePen, { className: "mr-2 h-4 w-4" }), "Edit"] }), jsx(CopyButton, { text: value, disabled: disabled })] })] }));
271753
- }
271754
-
271755
272982
  const AGENT_SCREENSHARE_TAB_LABELS = {
271756
272983
  header: {
271757
272984
  // Title is deliberately just "Screen" — the description below carries the
@@ -273583,7 +274810,7 @@ function resolveHumanSupportTabLabels(override, t) {
273583
274810
  return deepMerge(base, override);
273584
274811
  }
273585
274812
 
273586
- const STATUS_BADGE_CLASSES = {
274813
+ const STATUS_BADGE_CLASSES$1 = {
273587
274814
  open: 'border-green-200 bg-green-100 text-green-800 hover:bg-green-100',
273588
274815
  in_progress: 'border-amber-200 bg-amber-100 text-amber-800 hover:bg-amber-100',
273589
274816
  closed: 'border-gray-200 bg-gray-100 text-gray-700 hover:bg-gray-100',
@@ -273827,7 +275054,7 @@ function AgentHumanSupportTab({ PaginationComponent = IblPagination, labels: lab
273827
275054
  };
273828
275055
  const renderStatusBadge = (status) => {
273829
275056
  const resolvedStatus = status !== null && status !== void 0 ? status : 'open';
273830
- return (jsx(Badge, { variant: "outline", className: cn('whitespace-nowrap', STATUS_BADGE_CLASSES[resolvedStatus]), children: statusLabels[resolvedStatus] }));
275057
+ return (jsx(Badge, { variant: "outline", className: cn('whitespace-nowrap', STATUS_BADGE_CLASSES$1[resolvedStatus]), children: statusLabels[resolvedStatus] }));
273831
275058
  };
273832
275059
  const renderMessage = (message, ticket) => {
273833
275060
  var _a;
@@ -273971,6 +275198,18 @@ const AGENT_LTI_TAB_LABELS = {
273971
275198
  createButton: 'Create LTI Link',
273972
275199
  empty: 'No LTI link yet for this agent.',
273973
275200
  targetUriColumn: 'TARGET LINK URI',
275201
+ statusColumn: 'STATUS',
275202
+ status: {
275203
+ pending: 'Pending',
275204
+ building: 'Building',
275205
+ ready: 'Ready',
275206
+ failed: 'Failed',
275207
+ },
275208
+ failedHint: 'Something went wrong while creating this link. Retry deletes it and creates it again.',
275209
+ refresh: 'Refresh',
275210
+ retry: 'Retry',
275211
+ retrying: 'Retrying…',
275212
+ retryAria: (name) => `Retry ${name}`,
273974
275213
  editAria: (name) => `Edit ${name}`,
273975
275214
  copyTargetUri: 'Copy target link URI',
273976
275215
  modal: {
@@ -274078,6 +275317,7 @@ const AGENT_LTI_TAB_LABELS = {
274078
275317
  },
274079
275318
  toasts: {
274080
275319
  linkCreated: 'LTI link created successfully',
275320
+ linkCreationStarted: 'LTI link creation started — this can take a few minutes',
274081
275321
  linkUpdated: 'LTI link updated successfully',
274082
275322
  linkDeleted: 'LTI link deleted successfully',
274083
275323
  linkError: 'Something went wrong with the LTI link',
@@ -274139,6 +275379,18 @@ function buildLtiTabLabels(t) {
274139
275379
  createButton: t('ltiTabLabels.links.createButton'),
274140
275380
  empty: t('ltiTabLabels.links.empty'),
274141
275381
  targetUriColumn: t('ltiTabLabels.links.targetUriColumn'),
275382
+ statusColumn: t('ltiTabLabels.links.statusColumn'),
275383
+ status: {
275384
+ pending: t('ltiTabLabels.links.status.pending'),
275385
+ building: t('ltiTabLabels.links.status.building'),
275386
+ ready: t('ltiTabLabels.links.status.ready'),
275387
+ failed: t('ltiTabLabels.links.status.failed'),
275388
+ },
275389
+ failedHint: t('ltiTabLabels.links.failedHint'),
275390
+ refresh: t('ltiTabLabels.links.refresh'),
275391
+ retry: t('ltiTabLabels.links.retry'),
275392
+ retrying: t('ltiTabLabels.links.retrying'),
275393
+ retryAria: (name) => t('ltiTabLabels.links.retryAria', { name }),
274142
275394
  editAria: (name) => t('ltiTabLabels.links.editAria', { name }),
274143
275395
  copyTargetUri: t('ltiTabLabels.links.copyTargetUri'),
274144
275396
  modal: {
@@ -274246,6 +275498,7 @@ function buildLtiTabLabels(t) {
274246
275498
  },
274247
275499
  toasts: {
274248
275500
  linkCreated: t('ltiTabLabels.toasts.linkCreated'),
275501
+ linkCreationStarted: t('ltiTabLabels.toasts.linkCreationStarted'),
274249
275502
  linkUpdated: t('ltiTabLabels.toasts.linkUpdated'),
274250
275503
  linkDeleted: t('ltiTabLabels.toasts.linkDeleted'),
274251
275504
  linkError: t('ltiTabLabels.toasts.linkError'),
@@ -274383,8 +275636,11 @@ function AgentLinkModal({ isOpen, onClose, platformKey, mentorId, mentorUniqueId
274383
275636
  toast.success(labels.toasts.linkUpdated);
274384
275637
  }
274385
275638
  else {
275639
+ // The data layer sends `async_create: true`, so the backend answers
275640
+ // 202 and builds the link in the background — the Links table polls
275641
+ // the detail endpoint and reports when it's ready (or failed).
274386
275642
  await createLtiMentor({ requestBody }).unwrap();
274387
- toast.success(labels.toasts.linkCreated);
275643
+ toast.success(labels.toasts.linkCreationStarted);
274388
275644
  // "Allow LTI" must be on for the link to work. Enable it automatically
274389
275645
  // on create so the user doesn't have to toggle it in Settings as a
274390
275646
  // separate step. Best-effort: a failure here doesn't fail the link.
@@ -274442,26 +275698,78 @@ function readTargetLinkUri(link) {
274442
275698
  const config = link.mentor_config;
274443
275699
  return (_a = config === null || config === void 0 ? void 0 : config.target_link_uri) !== null && _a !== void 0 ? _a : null;
274444
275700
  }
275701
+ function isInProgress(status) {
275702
+ return status === 'pending' || status === 'building';
275703
+ }
275704
+ const STATUS_BADGE_CLASSES = {
275705
+ pending: 'bg-amber-50 text-amber-700 border-amber-200',
275706
+ building: 'bg-amber-50 text-amber-700 border-amber-200',
275707
+ ready: 'bg-green-50 text-green-700 border-green-200',
275708
+ failed: 'bg-red-50 text-red-700 border-red-200',
275709
+ };
275710
+ function StatusBadge$2({ status, labels, }) {
275711
+ return (jsxs("span", { "data-testid": "lti-link-status", "data-status": status, title: status === 'failed' ? labels.links.failedHint : undefined, className: `inline-flex items-center gap-1.5 rounded-full border px-2 py-0.5 text-xs font-medium ${STATUS_BADGE_CLASSES[status]}`, children: [isInProgress(status) && jsx(LoaderCircle, { className: "h-3 w-3 animate-spin", "aria-hidden": "true" }), labels.links.status[status]] }));
275712
+ }
274445
275713
  function AgentLinksSection({ identity, labels, }) {
274446
275714
  const { platformKey, mentorId, mentorUniqueId, username, isLtiAccessible, isReady, isSettingsLoading } = identity;
274447
275715
  const [showCreate, setShowCreate] = React__default.useState(false);
274448
275716
  const [editingLink, setEditingLink] = React__default.useState(null);
274449
275717
  const [page, setPage] = React__default.useState(1);
274450
- const { data: allLinks, isLoading, isFetching, } = useGetLtiMentorsQuery({ platformKey, mentorId: mentorUniqueId, page, pageSize: LTI_PAGE_SIZE }, { skip: !isReady });
275718
+ const [retryingId, setRetryingId] = React__default.useState(null);
275719
+ const { data: allLinks, isLoading, isFetching, refetch, } = useGetLtiMentorsQuery({ platformKey, mentorId: mentorUniqueId, page, pageSize: LTI_PAGE_SIZE }, { skip: !isReady });
275720
+ const [createLtiMentor] = useCreateLtiMentorMutation();
275721
+ const [deleteLtiMentor] = useDeleteLtiMentorMutation();
274451
275722
  // The backend scopes the list to this agent via `mentor_id`; we still narrow
274452
- // client-side by the unique_id as a defensive safety net.
275723
+ // client-side by the unique_id as a defensive safety net. An in-flight async
275724
+ // build may not have its `mentor_config.mentor` populated yet, so only drop
275725
+ // rows that carry a mentor and it's a different one.
274453
275726
  const links = React__default.useMemo(() => mentorUniqueId
274454
- ? toArray(allLinks).filter((link) => { var _a; return ((_a = link.mentor_config) === null || _a === void 0 ? void 0 : _a.mentor) === mentorUniqueId; })
275727
+ ? toArray(allLinks).filter((link) => { var _a; return !((_a = link.mentor_config) === null || _a === void 0 ? void 0 : _a.mentor) || link.mentor_config.mentor === mentorUniqueId; })
274455
275728
  : [], [allLinks, mentorUniqueId]);
275729
+ // Async create: the celery build finishes out of band, so offer a manual
275730
+ // Refresh while any link is still pending/building.
275731
+ const hasLinkInProgress = links.some((link) => isInProgress(link.status));
275732
+ // Retry a failed build: delete the failed entity, then re-post the original
275733
+ // payload (name + mentor + platform_key) as a fresh async create.
275734
+ const handleRetry = async (link) => {
275735
+ var _a, _b;
275736
+ setRetryingId(link.id);
275737
+ try {
275738
+ await deleteLtiMentor({ id: String(link.id), platformKey }).unwrap();
275739
+ await createLtiMentor({
275740
+ requestBody: {
275741
+ name: link.name,
275742
+ mentor_config: { mentor: (_b = (_a = link.mentor_config) === null || _a === void 0 ? void 0 : _a.mentor) !== null && _b !== void 0 ? _b : mentorUniqueId },
275743
+ platform_key: platformKey,
275744
+ },
275745
+ }).unwrap();
275746
+ toast.success(labels.toasts.linkCreationStarted);
275747
+ }
275748
+ catch (error) {
275749
+ console.error(JSON.stringify({ tenant: platformKey, error }));
275750
+ toast.error(getApiErrorMessage(error, labels.toasts.linkError));
275751
+ }
275752
+ finally {
275753
+ setRetryingId(null);
275754
+ }
275755
+ };
274456
275756
  const totalPages = getTotalPages(allLinks);
274457
275757
  const busy = !isReady || isSettingsLoading || isLoading;
274458
275758
  const canCreate = !busy && links.length === 0 && Boolean(mentorUniqueId);
274459
- return (jsxs("div", { className: "space-y-4", "data-testid": "lti-links-section", children: [jsxs("div", { className: "flex flex-col items-start justify-between gap-3 sm:flex-row sm:items-center", children: [jsx("p", { className: "text-xs text-gray-600", children: labels.links.description }), canCreate && (jsxs(Button$1, { onClick: () => setShowCreate(true), size: "sm", "data-testid": "lti-link-create-button", className: "cursor-pointer whitespace-nowrap bg-gradient-to-r from-[#2563EB] to-[#93C5FD] text-white hover:opacity-90", children: [jsx(Plus, { className: "h-4 w-4" }), labels.links.createButton] }))] }), busy ? (jsx("div", { className: "flex w-full items-center justify-center py-10", children: jsx(Spinner, {}) })) : links.length === 0 ? (jsxs("div", { className: "flex flex-col items-center justify-center gap-3 rounded-md border border-dashed border-gray-200 py-12 text-center", "data-testid": "lti-links-empty", children: [jsx(Link2, { className: "h-8 w-8 text-gray-300", "aria-hidden": "true" }), jsx("p", { className: "text-sm text-[#646464]", children: labels.links.empty })] })) : (jsxs("div", { className: "overflow-hidden rounded-md border", children: [jsx("div", { className: "overflow-x-auto", children: jsxs(Table$1, { className: "min-w-full", children: [jsx(TableHeader$1, { children: jsxs(TableRow$1, { className: "bg-muted/50 border-b", children: [jsx(TableHead, { className: "p-3 text-left text-sm whitespace-nowrap text-[#646464]", children: labels.common.nameColumn }), jsx(TableHead, { className: "p-3 text-left text-sm whitespace-nowrap text-[#646464]", children: labels.links.targetUriColumn }), jsx(TableHead, { className: "p-3 text-right text-sm whitespace-nowrap text-[#646464]", children: labels.common.actionsColumn })] }) }), jsx(TableBody, { children: links.map((link) => {
275759
+ return (jsxs("div", { className: "space-y-4", "data-testid": "lti-links-section", children: [jsxs("div", { className: "flex flex-col items-start justify-between gap-3 sm:flex-row sm:items-center", children: [jsx("p", { className: "text-xs text-gray-600", children: labels.links.description }), hasLinkInProgress && (jsxs(Button$1, { type: "button", variant: "outline", size: "sm", "data-testid": "lti-links-refresh-button", disabled: isFetching, onClick: () => refetch(), className: "cursor-pointer whitespace-nowrap", children: [jsx(RefreshCw, { className: `h-4 w-4 ${isFetching ? 'animate-spin' : ''}` }), labels.links.refresh] })), canCreate && (jsxs(Button$1, { onClick: () => setShowCreate(true), size: "sm", "data-testid": "lti-link-create-button", className: "cursor-pointer whitespace-nowrap bg-gradient-to-r from-[#2563EB] to-[#93C5FD] text-white hover:opacity-90", children: [jsx(Plus, { className: "h-4 w-4" }), labels.links.createButton] }))] }), busy ? (jsx("div", { className: "flex w-full items-center justify-center py-10", children: jsx(Spinner, {}) })) : links.length === 0 ? (jsxs("div", { className: "flex flex-col items-center justify-center gap-3 rounded-md border border-dashed border-gray-200 py-12 text-center", "data-testid": "lti-links-empty", children: [jsx(Link2, { className: "h-8 w-8 text-gray-300", "aria-hidden": "true" }), jsx("p", { className: "text-sm text-[#646464]", children: labels.links.empty })] })) : (jsxs("div", { className: "overflow-hidden rounded-md border", children: [jsx("div", { className: "overflow-x-auto", children: jsxs(Table$1, { className: "min-w-full", children: [jsx(TableHeader$1, { children: jsxs(TableRow$1, { className: "bg-muted/50 border-b", children: [jsx(TableHead, { className: "p-3 text-left text-sm whitespace-nowrap text-[#646464]", children: labels.common.nameColumn }), jsx(TableHead, { className: "p-3 text-left text-sm whitespace-nowrap text-[#646464]", children: labels.links.targetUriColumn }), jsx(TableHead, { className: "p-3 text-left text-sm whitespace-nowrap text-[#646464]", children: labels.links.statusColumn }), jsx(TableHead, { className: "p-3 text-right text-sm whitespace-nowrap text-[#646464]", children: labels.common.actionsColumn })] }) }), jsx(TableBody, { children: links.map((link) => {
274460
275760
  const targetLinkUri = readTargetLinkUri(link);
274461
- return (jsxs(TableRow$1, { "data-testid": "lti-link-row", className: "cursor-pointer border-b last:border-0 hover:bg-muted/40", onClick: () => setEditingLink(link), children: [jsx(TableCell$1, { className: "p-3 text-sm font-medium text-gray-900", children: link.name }), jsx(TableCell$1, { className: "p-3 text-sm text-[#646464]", children: targetLinkUri ? (jsxs("div", { className: "flex items-center gap-2", onClick: (event) => event.stopPropagation(), children: [jsx("span", { className: "max-w-[260px] truncate font-mono text-xs", title: targetLinkUri, children: targetLinkUri }), jsx(CopyIconButton, { text: targetLinkUri, label: labels.links.copyTargetUri, copiedLabel: labels.common.copied })] })) : ('—') }), jsx(TableCell$1, { className: "p-3 text-right", children: jsx(Button$1, { type: "button", variant: "outline", size: "icon", "aria-label": labels.links.editAria(link.name), onClick: (event) => {
275761
+ const inProgress = isInProgress(link.status);
275762
+ const failed = link.status === 'failed';
275763
+ // A finished (or legacy pre-async) link is the only editable state.
275764
+ const editable = !inProgress && !failed;
275765
+ const isRetrying = retryingId === link.id;
275766
+ return (jsxs(TableRow$1, { "data-testid": "lti-link-row", className: `border-b last:border-0 hover:bg-muted/40 ${editable ? 'cursor-pointer' : ''}`, onClick: editable ? () => setEditingLink(link) : undefined, children: [jsx(TableCell$1, { className: "p-3 text-sm font-medium text-gray-900", children: link.name }), jsx(TableCell$1, { className: "p-3 text-sm text-[#646464]", children: targetLinkUri ? (jsxs("div", { className: "flex items-center gap-2", onClick: (event) => event.stopPropagation(), children: [jsx("span", { className: "max-w-[260px] truncate font-mono text-xs", title: targetLinkUri, children: targetLinkUri }), jsx(CopyIconButton, { text: targetLinkUri, label: labels.links.copyTargetUri, copiedLabel: labels.common.copied })] })) : ('—') }), jsx(TableCell$1, { className: "p-3 text-sm", children: link.status ? jsx(StatusBadge$2, { status: link.status, labels: labels }) : '—' }), jsx(TableCell$1, { className: "p-3 text-right", children: failed ? (jsxs(Button$1, { type: "button", variant: "outline", size: "sm", "data-testid": "lti-link-retry-button", "aria-label": labels.links.retryAria(link.name), disabled: isRetrying, onClick: (event) => {
275767
+ event.stopPropagation();
275768
+ handleRetry(link);
275769
+ }, children: [jsx(RotateCcw, { className: "h-4 w-4" }), isRetrying ? labels.links.retrying : labels.links.retry] })) : editable ? (jsx(Button$1, { type: "button", variant: "outline", size: "icon", "aria-label": labels.links.editAria(link.name), onClick: (event) => {
274462
275770
  event.stopPropagation();
274463
275771
  setEditingLink(link);
274464
- }, children: jsx(Pencil, { className: "h-4 w-4" }) }) })] }, link.id));
275772
+ }, children: jsx(Pencil, { className: "h-4 w-4" }) })) : null })] }, link.id));
274465
275773
  }) })] }) }), isFetching && (jsx("p", { className: "px-3 py-2 text-xs text-gray-400", children: labels.common.refreshing }))] })), jsx(IblPagination, { currentPage: page, totalPages: totalPages, onPageChange: setPage, disabled: busy }), showCreate && (jsx(AgentLinkModal, { isOpen: showCreate, onClose: () => setShowCreate(false), platformKey: platformKey, mentorId: mentorId, mentorUniqueId: mentorUniqueId, username: username, isLtiAccessible: isLtiAccessible, labels: labels })), editingLink && (jsx(AgentLinkModal, { isOpen: Boolean(editingLink), onClose: () => setEditingLink(null), platformKey: platformKey, mentorId: mentorId, mentorUniqueId: mentorUniqueId, username: username, isLtiAccessible: isLtiAccessible, link: editingLink, labels: labels }))] }));
274466
275774
  }
274467
275775
 
@@ -284921,18 +286229,6 @@ var addMemoryModal = /*#__PURE__*/Object.freeze({
284921
286229
  AddMemoryModal: AddMemoryModal
284922
286230
  });
284923
286231
 
284924
- function DeleteMemoryModal({ open, onOpenChange, onConfirm, onCancel, isDeleting, }) {
284925
- const t = useT();
284926
- return (jsx(Dialog, { open: open, onOpenChange: onOpenChange, children: jsxs(DialogContent, { className: "mx-4 max-w-md sm:mx-auto", children: [jsx(DialogHeader, { children: jsx(DialogTitle, { children: t('memoryTabDeleteMemoryModal.title') }) }), jsx("p", { className: "text-muted-foreground text-sm", children: t('memoryTabDeleteMemoryModal.confirmMessage') }), jsxs("div", { className: "mt-4 flex justify-end gap-2", children: [jsx(Button$1, { variant: "outline", onClick: onCancel, children: t('memoryTabDeleteMemoryModal.cancel') }), jsx(Button$1, { className: "ibl-button-primary", onClick: onConfirm, disabled: isDeleting, children: isDeleting
284927
- ? t('memoryTabDeleteMemoryModal.deleting')
284928
- : t('memoryTabDeleteMemoryModal.delete') })] })] }) }));
284929
- }
284930
-
284931
- var deleteMemoryModal = /*#__PURE__*/Object.freeze({
284932
- __proto__: null,
284933
- DeleteMemoryModal: DeleteMemoryModal
284934
- });
284935
-
284936
286232
  function BulkDeleteMemoryModal({ open, onOpenChange, onConfirm, onCancel, isDeleting, selectedCategory, }) {
284937
286233
  const isDeleteAll = selectedCategory === 'All';
284938
286234
  const getConfirmationText = () => {