@iblai/iblai-js 2.17.0 → 2.18.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/web-containers/source/index.esm.js +2818 -698
- package/dist/web-containers/source/next/index.esm.js +2685 -617
- package/package.json +5 -5
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { jsx, jsxs, Fragment as Fragment$1 } from 'react/jsx-runtime';
|
|
2
2
|
import * as React from 'react';
|
|
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';
|
|
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, Fragment as Fragment$2, useId as useId$2, useDebugValue, lazy, Suspense } from 'react';
|
|
4
4
|
import * as dataLayer from '@iblai/data-layer';
|
|
5
|
-
import { useGetUserMetadataQuery, useGetUserMetadataEdxQuery, useGetUserProfileSummaryQuery, 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, useGetAiSearchMentorsQuery, useStarMentorMutation, useUnstarMentorMutation, useGetUserChatHistoryReportsQuery, USER_CHAT_HISTORY_REPORT_ACTIVE_STATES, useCreateUserChatHistoryReportMutation, useLazyGetDownloadReportFromURLQuery, useGetUserChatHistoryReportStatusQuery, userChatHistoryApiSlice, USER_CHAT_HISTORY_QUERY_KEYS, useGetUserChatHistoryQuery, useGetUserChatHistoryFilterQuery, useGetMentorsQuery, useGetUserChatHistorySessionQuery, 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, 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, useGetLlmUsageMetricsQuery, 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, useListPaywallsQuery, useListPricesQuery, useCreatePriceMutation, useUpdatePriceMutation, useDeletePriceMutation, useGetPaywallConfigQuery, useEnablePaywallMutation, useUpdatePaywallMutation, useGetMentorMemoriesListQuery, useGetMemoryCategoriesAdminQuery, useCreateMentorMemoryMutation, 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, 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, useCreateMemoryCategoryMutation, useUpdateMemoryCategoryMutation, useDeleteMemoryCategoryMutation, useDeletePromptMutation, useDeleteTrainingDocumentMutation, useGetTrainingDocumentRetrainScheduleQuery, useCreateTrainingDocumentRetrainScheduleMutation, useUpdateArtifactMutation, useLazyGetArtifactVersionQuery, useLazyListArtifactVersionsQuery, useSetCurrentVersionMutation, useListArtifactVersionsQuery, useLazyGetArtifactQuery, useLazyListArtifactsQuery, useEditSessionMutation } from '@iblai/data-layer';
|
|
6
|
-
import { removeAuthItem, setAuthItem, isTauriEmbeddedLLMHost, selectRbacPermissions, useCurrentTenant, canViewOtherUsersChatHistory, getInitials, useTenantMetadata,
|
|
5
|
+
import { useGetUserMetadataQuery, useGetUserMetadataEdxQuery, useGetUserProfileSummaryQuery, 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, useGetAiSearchMentorsQuery, useStarMentorMutation, useUnstarMentorMutation, useGetUserChatHistoryReportsQuery, USER_CHAT_HISTORY_REPORT_ACTIVE_STATES, useCreateUserChatHistoryReportMutation, useLazyGetDownloadReportFromURLQuery, useGetUserChatHistoryReportStatusQuery, userChatHistoryApiSlice, USER_CHAT_HISTORY_QUERY_KEYS, useGetUserChatHistoryQuery, useGetUserChatHistoryFilterQuery, useGetMentorsQuery, useGetUserChatHistorySessionQuery, useUserLlmUsageSummary, useUserLlmSpendOverTime, useUserLlmCostByModel, useUserLlmCostByService, useUserLlmRecentActivity, USER_LLM_RECENT_ACTIVITY_PAGE_SIZE, useUserLlmTraceObservations, useInviteUserMutation, usePlatformInvitationsQuery, useCreateCatalogInvitationCourseBulkMutation, useGetCatalogInvitationsCourseQuery, useLazyPlatformUsersQuery, useLazyPlatformUserGroupsQuery, useGetPersonnalizedSearchQuery, useCreateCatalogInvitationProgramBulkMutation, useGetCatalogInvitationsProgramQuery, useGetVectorDocumentsQuery, useGetLlmsQuery, 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, useUpdateTenantMetadataMutation, useLazyGetTenantMetadataQuery, useDeleteApiKeyMutation, useGetApiKeyQuery, useGetApiKeyFieldPermissionsQuery, useUpdateApiKeyMutation, useGetApiKeysQuery, unwrapApiTokenList, useCreateApiKeyMutation, useCreateLLMCredentialMutation, useGetCredentialsSchemaQuery, useGetMaskedLLMCredentialsQuery, useDeleteIntegrationCredentialMutation, useDeleteCredentialMutation, useCreateIntegrationCredentialMutation, useGetIntegrationCredentialsSchemaQuery, useGetMaskedIntegrationCredentialsQuery, useGetAccountBillingInfoQuery, useUpdateAutoRechargeInfoMutation, useTriggerAutoRechargeMutation, useGetAgentSpendCapQuery, useGetTenantSpendCapQuery, useListAgentUserSpendCapsQuery, useUpsertAgentSpendCapMutation, useDeleteAgentSpendCapMutation, useUpsertTenantSpendCapMutation, useDeleteTenantSpendCapMutation, useUpsertUserSpendCapMutation, useDeleteUserSpendCapMutation, useGetLlmUsageMetricsQuery, 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, useListPaywallsQuery, useListPricesQuery, useCreatePriceMutation, useUpdatePriceMutation, useDeletePriceMutation, useGetPaywallConfigQuery, useEnablePaywallMutation, useUpdatePaywallMutation, useGetMentorMemoriesListQuery, useGetMemoryCategoriesAdminQuery, useCreateMentorMemoryMutation, 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, 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, useCreateMemoryCategoryMutation, useUpdateMemoryCategoryMutation, useDeleteMemoryCategoryMutation, useDeletePromptMutation, useDeleteTrainingDocumentMutation, useGetTrainingDocumentRetrainScheduleQuery, useCreateTrainingDocumentRetrainScheduleMutation, useUpdateArtifactMutation, useLazyGetArtifactVersionQuery, useLazyListArtifactVersionsQuery, useSetCurrentVersionMutation, useListArtifactVersionsQuery, useLazyGetArtifactQuery, useLazyListArtifactsQuery, useEditSessionMutation } from '@iblai/data-layer';
|
|
6
|
+
import { removeAuthItem, setAuthItem, isTauriEmbeddedLLMHost, selectRbacPermissions, useCurrentTenant, canViewOtherUsersChatHistory, isPureWatcher, getInitials, useTenantMetadata, useUsername, selectStreaming, isLoggedIn, TOOL_NAME_MAP, WRITE_TODOS_TOOL, WithPermissions, canWriteField, useStripeUpgrade, openExternalUrl, CHAT_AREA_SIZE, isAlphaNumeric32, checkRbacPermission, selectNumberOfActiveChatMessages, 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, use401TokenRefresh, 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';
|
|
9
9
|
import { useSearchParams, useParams, useRouter, usePathname } from 'next/navigation';
|
|
@@ -44326,7 +44326,7 @@ var isArray$h = function isArray(arr) {
|
|
|
44326
44326
|
return toStr.call(arr) === '[object Array]';
|
|
44327
44327
|
};
|
|
44328
44328
|
|
|
44329
|
-
var isPlainObject$
|
|
44329
|
+
var isPlainObject$5 = function isPlainObject(obj) {
|
|
44330
44330
|
if (!obj || toStr.call(obj) !== '[object Object]') {
|
|
44331
44331
|
return false;
|
|
44332
44332
|
}
|
|
@@ -44405,12 +44405,12 @@ var extend$3 = function extend() {
|
|
|
44405
44405
|
// Prevent never-ending loop
|
|
44406
44406
|
if (target !== copy) {
|
|
44407
44407
|
// Recurse if we're merging plain objects or arrays
|
|
44408
|
-
if (deep && copy && (isPlainObject$
|
|
44408
|
+
if (deep && copy && (isPlainObject$5(copy) || (copyIsArray = isArray$h(copy)))) {
|
|
44409
44409
|
if (copyIsArray) {
|
|
44410
44410
|
copyIsArray = false;
|
|
44411
44411
|
clone = src && isArray$h(src) ? src : [];
|
|
44412
44412
|
} else {
|
|
44413
|
-
clone = src && isPlainObject$
|
|
44413
|
+
clone = src && isPlainObject$5(src) ? src : {};
|
|
44414
44414
|
}
|
|
44415
44415
|
|
|
44416
44416
|
// Never move original objects, clone them
|
|
@@ -44431,7 +44431,7 @@ var extend$3 = function extend() {
|
|
|
44431
44431
|
|
|
44432
44432
|
var extend$2 = /*@__PURE__*/getDefaultExportFromCjs(extend$3);
|
|
44433
44433
|
|
|
44434
|
-
function isPlainObject$
|
|
44434
|
+
function isPlainObject$4(value) {
|
|
44435
44435
|
if (typeof value !== 'object' || value === null) {
|
|
44436
44436
|
return false;
|
|
44437
44437
|
}
|
|
@@ -45502,7 +45502,7 @@ class Processor extends CallableInstance {
|
|
|
45502
45502
|
else if (parameters.length > 0) {
|
|
45503
45503
|
let [primary, ...rest] = parameters;
|
|
45504
45504
|
const currentPrimary = attachers[entryIndex][1];
|
|
45505
|
-
if (isPlainObject$
|
|
45505
|
+
if (isPlainObject$4(currentPrimary) && isPlainObject$4(primary)) {
|
|
45506
45506
|
primary = extend$2(true, currentPrimary, primary);
|
|
45507
45507
|
}
|
|
45508
45508
|
|
|
@@ -45594,7 +45594,7 @@ function assertUnfrozen(name, frozen) {
|
|
|
45594
45594
|
function assertNode(node) {
|
|
45595
45595
|
// `isPlainObj` unfortunately uses `any` instead of `unknown`.
|
|
45596
45596
|
// type-coverage:ignore-next-line
|
|
45597
|
-
if (!isPlainObject$
|
|
45597
|
+
if (!isPlainObject$4(node) || typeof node.type !== 'string') {
|
|
45598
45598
|
throw new TypeError('Expected node, got `' + node + '`')
|
|
45599
45599
|
// Fine.
|
|
45600
45600
|
}
|
|
@@ -97047,7 +97047,7 @@ var analyticsAnalyticsTranscriptsStats$3 = {
|
|
|
97047
97047
|
labelUsername: "Username:",
|
|
97048
97048
|
labelAgent: "Agent:",
|
|
97049
97049
|
labelModel: "Model:",
|
|
97050
|
-
labelModelCard: "
|
|
97050
|
+
labelModelCard: "Model:",
|
|
97051
97051
|
labelUser: "User:",
|
|
97052
97052
|
roleUser: "User",
|
|
97053
97053
|
roleAgent: "Agent",
|
|
@@ -97089,6 +97089,37 @@ var analyticsAnalyticsTranscriptsStats$3 = {
|
|
|
97089
97089
|
avgCostPerConversationDescription: "What a typical conversation costs in model usage.",
|
|
97090
97090
|
avgRatingDescription: "Average rating users gave their conversations, on a scale of 1 to 5."
|
|
97091
97091
|
};
|
|
97092
|
+
var analyticsTranscriptTurnDetails$3 = {
|
|
97093
|
+
showDetails: "Show Details",
|
|
97094
|
+
hideDetails: "Hide Details",
|
|
97095
|
+
metadata: "Metadata",
|
|
97096
|
+
requestContext: "Request Context",
|
|
97097
|
+
model: "Model",
|
|
97098
|
+
provider: "Provider",
|
|
97099
|
+
temperature: "Temperature",
|
|
97100
|
+
client: "Client",
|
|
97101
|
+
sourcesBadge: "Documents · {count}",
|
|
97102
|
+
toolsBadge: "Tools · {count}",
|
|
97103
|
+
yes: "Yes",
|
|
97104
|
+
no: "No",
|
|
97105
|
+
redacted: "Redacted",
|
|
97106
|
+
fieldSession: "Session",
|
|
97107
|
+
fieldCallerVerified: "Caller Verified",
|
|
97108
|
+
fieldFiles: "Files",
|
|
97109
|
+
fieldFile: "File",
|
|
97110
|
+
fieldSystemPrompt: "System Prompt",
|
|
97111
|
+
fieldFlow: "Flow",
|
|
97112
|
+
fieldToken: "Token",
|
|
97113
|
+
fieldTenant: "Tenant",
|
|
97114
|
+
fieldPathway: "Pathway",
|
|
97115
|
+
fieldUsername: "Username",
|
|
97116
|
+
fieldName: "Name",
|
|
97117
|
+
fieldCanvas: "Canvas",
|
|
97118
|
+
fieldProactivePrompt: "Proactive Prompt",
|
|
97119
|
+
fieldGrader: "Grader",
|
|
97120
|
+
fieldDatasets: "Datasets",
|
|
97121
|
+
fieldDateTime: "Date & Time"
|
|
97122
|
+
};
|
|
97092
97123
|
var analyticsAnalyticsUsersStats$3 = {
|
|
97093
97124
|
usersLoggedInNow: "Users logged in right now",
|
|
97094
97125
|
usersLoggedInPast30Days: "Users logged in past 30 days",
|
|
@@ -98579,7 +98610,8 @@ var historyTabLabels$3 = {
|
|
|
98579
98610
|
noResponse: "No response available",
|
|
98580
98611
|
selectPrompt: "Select a conversation to view details.",
|
|
98581
98612
|
aiAgent: "AI Agent",
|
|
98582
|
-
noConversations: "No conversations found"
|
|
98613
|
+
noConversations: "No conversations found",
|
|
98614
|
+
documentsChip: "Documents · {count}"
|
|
98583
98615
|
},
|
|
98584
98616
|
summary: {
|
|
98585
98617
|
notAvailable: "Summary not available"
|
|
@@ -99704,7 +99736,13 @@ var profileAccount$3 = {
|
|
|
99704
99736
|
tabBenchmarks: "Benchmarks",
|
|
99705
99737
|
descBenchmarks: "Build benchmark suites of test inputs to evaluate agents.",
|
|
99706
99738
|
tabMemory: "Memory",
|
|
99707
|
-
descMemory: "Manage user global memories and agent memories."
|
|
99739
|
+
descMemory: "Manage user global memories and agent memories.",
|
|
99740
|
+
groupWorkspace: "Workspace",
|
|
99741
|
+
groupAiData: "AI & data",
|
|
99742
|
+
groupSystem: "System",
|
|
99743
|
+
ariaSettingsNav: "Organization settings",
|
|
99744
|
+
ariaSettingsNavMobile: "Organization settings (mobile)",
|
|
99745
|
+
groupFinance: "Finance"
|
|
99708
99746
|
};
|
|
99709
99747
|
var profileAddCreditsModal$3 = {
|
|
99710
99748
|
title: "Add Credits",
|
|
@@ -99900,7 +99938,6 @@ var profileIndex$3 = {
|
|
|
99900
99938
|
langSpanish: "Spanish",
|
|
99901
99939
|
langFrench: "French",
|
|
99902
99940
|
checkboxDisplayMentorAI: "Display Agent Sidebar",
|
|
99903
|
-
checkboxDisplayLeaderboard: "Display Leaderboard",
|
|
99904
99941
|
labelFacebook: "Facebook",
|
|
99905
99942
|
placeholderFacebook: "Facebook",
|
|
99906
99943
|
labelLinkedIn: "LinkedIn",
|
|
@@ -99921,7 +99958,16 @@ var profileIndex$3 = {
|
|
|
99921
99958
|
descChatHistoryPreview: "Conversations with AI agents.",
|
|
99922
99959
|
ariaAddEducation: "Add education",
|
|
99923
99960
|
ariaAddExperience: "Add experience",
|
|
99924
|
-
ariaAddResume: "Add resume"
|
|
99961
|
+
ariaAddResume: "Add resume",
|
|
99962
|
+
tabLlmUsage: "Usage",
|
|
99963
|
+
descLlmUsage: "See how much AI you have used: spend, tokens and requests across your conversations.",
|
|
99964
|
+
groupProfile: "Profile",
|
|
99965
|
+
groupAiData: "AI & data",
|
|
99966
|
+
groupAccount: "Account",
|
|
99967
|
+
groupRecords: "Records",
|
|
99968
|
+
descLlmUsagePreview: "Spend, tokens and requests across conversations.",
|
|
99969
|
+
sectionFeatures: "Features",
|
|
99970
|
+
tooltipDisplayMentorAI: "Keeps the AI agent panel beside whatever you are working on, so you can ask questions without leaving the page."
|
|
99925
99971
|
};
|
|
99926
99972
|
var profileInviteUserContent$3 = {
|
|
99927
99973
|
inviteUsersTitle: "Invite Users",
|
|
@@ -102946,6 +102992,81 @@ var analyticsTraces$3 = {
|
|
|
102946
102992
|
mentorScopeTitle: "Agent scope narrows the trace list only.",
|
|
102947
102993
|
mentorScopeBody: "Row-level observations cannot be filtered to a single agent upstream — open a trace to see its own calls."
|
|
102948
102994
|
};
|
|
102995
|
+
var profileLlmUsage$3 = {
|
|
102996
|
+
rangeLabel: "Date range",
|
|
102997
|
+
rangeToday: "Today",
|
|
102998
|
+
range7d: "7 days",
|
|
102999
|
+
range30d: "30 days",
|
|
103000
|
+
range90d: "90 days",
|
|
103001
|
+
rangeAllTime: "All time",
|
|
103002
|
+
periodToday: "Today",
|
|
103003
|
+
period7d: "Last 7 days",
|
|
103004
|
+
period30d: "Last 30 days",
|
|
103005
|
+
period90d: "Last 90 days",
|
|
103006
|
+
periodAllTime: "All time",
|
|
103007
|
+
scopeSelf: "Only your own activity is shown",
|
|
103008
|
+
refresh: "Refresh usage",
|
|
103009
|
+
kpiSpend: "Spend",
|
|
103010
|
+
kpiTokens: "Tokens",
|
|
103011
|
+
kpiRequests: "Requests",
|
|
103012
|
+
kpiAvgCost: "Avg cost per request",
|
|
103013
|
+
kpiTokensSub: "{value} per request",
|
|
103014
|
+
kpiRequestsSub: "AI calls",
|
|
103015
|
+
kpiAvgCostSub: "Spend divided by requests",
|
|
103016
|
+
chartTitle: "Spend over time",
|
|
103017
|
+
chartSubtitleDay: "Daily spend in US dollars",
|
|
103018
|
+
chartSubtitleWeek: "Weekly spend in US dollars",
|
|
103019
|
+
chartSubtitleMonth: "Monthly spend in US dollars",
|
|
103020
|
+
chartAria: "Spend over time. Use the left and right arrow keys to read each bar.",
|
|
103021
|
+
chartNoData: "No spend in this period.",
|
|
103022
|
+
chartTableCaption: "Spend per period",
|
|
103023
|
+
colPeriod: "Period",
|
|
103024
|
+
colCost: "Cost",
|
|
103025
|
+
byModelTitle: "By model",
|
|
103026
|
+
byModelSubtitle: "Share of your spend per model",
|
|
103027
|
+
byServiceTitle: "By service",
|
|
103028
|
+
byServiceSubtitle: "Where your spend comes from",
|
|
103029
|
+
otherRow: "Other",
|
|
103030
|
+
unknownModel: "Unknown model",
|
|
103031
|
+
unknownService: "Other service",
|
|
103032
|
+
breakdownEmpty: "Nothing to break down in this period.",
|
|
103033
|
+
sectionError: "This section couldn't be loaded.",
|
|
103034
|
+
activityTitle: "Recent activity",
|
|
103035
|
+
activitySubtitle: "Your latest AI requests, newest first. Open one to see each step.",
|
|
103036
|
+
activityEmpty: "No requests in this period.",
|
|
103037
|
+
colWhen: "When",
|
|
103038
|
+
colService: "Service",
|
|
103039
|
+
colSession: "Session",
|
|
103040
|
+
colLatency: "Latency",
|
|
103041
|
+
colDetails: "Details",
|
|
103042
|
+
showSteps: "Show steps for {when}",
|
|
103043
|
+
hideSteps: "Hide steps for {when}",
|
|
103044
|
+
stepsLoading: "Loading steps…",
|
|
103045
|
+
stepsEmpty: "No steps were recorded for this request.",
|
|
103046
|
+
stepsError: "The steps for this request couldn't be loaded.",
|
|
103047
|
+
colStep: "Step",
|
|
103048
|
+
colModel: "Model",
|
|
103049
|
+
colInput: "Input",
|
|
103050
|
+
colOutput: "Output",
|
|
103051
|
+
colTotal: "Total",
|
|
103052
|
+
paginationSummary: "Showing {from}–{to} of {total}",
|
|
103053
|
+
previous: "Previous",
|
|
103054
|
+
next: "Next",
|
|
103055
|
+
emptyTitle: "No AI usage in this period",
|
|
103056
|
+
emptyBody: "Chats, memory and other AI requests show up here once they happen. Try a longer range.",
|
|
103057
|
+
emptyAction90: "Show last 90 days",
|
|
103058
|
+
emptyActionAll: "Show all time",
|
|
103059
|
+
errorForbiddenTitle: "Usage isn't available",
|
|
103060
|
+
errorForbiddenBody: "We couldn't load usage for this account.",
|
|
103061
|
+
errorUnavailableTitle: "Usage is temporarily unavailable",
|
|
103062
|
+
errorUnavailableBody: "Please try again in a few minutes.",
|
|
103063
|
+
errorUnauthorizedTitle: "Your session has expired",
|
|
103064
|
+
errorUnauthorizedBody: "Sign in again to see your usage.",
|
|
103065
|
+
errorUnknownTitle: "Something went wrong",
|
|
103066
|
+
errorUnknownBody: "We couldn't load your usage.",
|
|
103067
|
+
tryAgain: "Try again",
|
|
103068
|
+
scopeUser: "Usage for {username}"
|
|
103069
|
+
};
|
|
102949
103070
|
var en = {
|
|
102950
103071
|
accessTabAddAccess: accessTabAddAccess$3,
|
|
102951
103072
|
accessTabLabels: accessTabLabels$3,
|
|
@@ -102982,6 +103103,7 @@ var en = {
|
|
|
102982
103103
|
analyticsAnalyticsReports: analyticsAnalyticsReports$3,
|
|
102983
103104
|
analyticsAnalyticsTopicsStats: analyticsAnalyticsTopicsStats$3,
|
|
102984
103105
|
analyticsAnalyticsTranscriptsStats: analyticsAnalyticsTranscriptsStats$3,
|
|
103106
|
+
analyticsTranscriptTurnDetails: analyticsTranscriptTurnDetails$3,
|
|
102985
103107
|
analyticsAnalyticsUsersStats: analyticsAnalyticsUsersStats$3,
|
|
102986
103108
|
analyticsGroupsFilterDropdown: analyticsGroupsFilterDropdown$3,
|
|
102987
103109
|
analyticsStatCard: analyticsStatCard$3,
|
|
@@ -103229,7 +103351,8 @@ var en = {
|
|
|
103229
103351
|
analyticsChartCard: analyticsChartCard$3,
|
|
103230
103352
|
analyticsCostTabs: analyticsCostTabs$3,
|
|
103231
103353
|
analyticsLlmUsage: analyticsLlmUsage$3,
|
|
103232
|
-
analyticsTraces: analyticsTraces$3
|
|
103354
|
+
analyticsTraces: analyticsTraces$3,
|
|
103355
|
+
profileLlmUsage: profileLlmUsage$3
|
|
103233
103356
|
};
|
|
103234
103357
|
|
|
103235
103358
|
var accessTabAddAccess$2 = {
|
|
@@ -104205,7 +104328,7 @@ var analyticsAnalyticsTranscriptsStats$2 = {
|
|
|
104205
104328
|
labelUsername: "Nom d'utilisateur :",
|
|
104206
104329
|
labelAgent: "Agent :",
|
|
104207
104330
|
labelModel: "Modèle :",
|
|
104208
|
-
labelModelCard: "
|
|
104331
|
+
labelModelCard: "Modèle :",
|
|
104209
104332
|
labelUser: "Utilisateur :",
|
|
104210
104333
|
roleUser: "Utilisateur",
|
|
104211
104334
|
roleAgent: "Agent",
|
|
@@ -104247,6 +104370,37 @@ var analyticsAnalyticsTranscriptsStats$2 = {
|
|
|
104247
104370
|
avgCostPerConversationDescription: "Coût d’utilisation des modèles pour une conversation type.",
|
|
104248
104371
|
avgRatingDescription: "Note moyenne attribuée par les utilisateurs à leurs conversations, sur une échelle de 1 à 5."
|
|
104249
104372
|
};
|
|
104373
|
+
var analyticsTranscriptTurnDetails$2 = {
|
|
104374
|
+
showDetails: "Afficher les détails",
|
|
104375
|
+
hideDetails: "Masquer les détails",
|
|
104376
|
+
metadata: "Métadonnées",
|
|
104377
|
+
requestContext: "Contexte de la requête",
|
|
104378
|
+
model: "Modèle",
|
|
104379
|
+
provider: "Fournisseur",
|
|
104380
|
+
temperature: "Température",
|
|
104381
|
+
client: "Client",
|
|
104382
|
+
sourcesBadge: "Documents · {count}",
|
|
104383
|
+
toolsBadge: "Outils · {count}",
|
|
104384
|
+
yes: "Oui",
|
|
104385
|
+
no: "Non",
|
|
104386
|
+
redacted: "Masqué",
|
|
104387
|
+
fieldSession: "Session",
|
|
104388
|
+
fieldCallerVerified: "Appelant vérifié",
|
|
104389
|
+
fieldFiles: "Fichiers",
|
|
104390
|
+
fieldFile: "Fichier",
|
|
104391
|
+
fieldSystemPrompt: "Prompt système",
|
|
104392
|
+
fieldFlow: "Flux",
|
|
104393
|
+
fieldToken: "Jeton",
|
|
104394
|
+
fieldTenant: "Locataire",
|
|
104395
|
+
fieldPathway: "Parcours",
|
|
104396
|
+
fieldUsername: "Nom d’utilisateur",
|
|
104397
|
+
fieldName: "Nom",
|
|
104398
|
+
fieldCanvas: "Canvas",
|
|
104399
|
+
fieldProactivePrompt: "Prompt proactif",
|
|
104400
|
+
fieldGrader: "Correcteur",
|
|
104401
|
+
fieldDatasets: "Jeux de données",
|
|
104402
|
+
fieldDateTime: "Date et heure"
|
|
104403
|
+
};
|
|
104250
104404
|
var analyticsAnalyticsUsersStats$2 = {
|
|
104251
104405
|
usersLoggedInNow: "Utilisateurs connectés en ce moment",
|
|
104252
104406
|
usersLoggedInPast30Days: "Utilisateurs connectés ces 30 derniers jours",
|
|
@@ -105903,7 +106057,8 @@ var historyTabLabels$2 = {
|
|
|
105903
106057
|
noResponse: "Aucune réponse disponible",
|
|
105904
106058
|
selectPrompt: "Sélectionnez une conversation pour afficher les détails.",
|
|
105905
106059
|
aiAgent: "AI Agent",
|
|
105906
|
-
noConversations: "Aucune conversation trouvée"
|
|
106060
|
+
noConversations: "Aucune conversation trouvée",
|
|
106061
|
+
documentsChip: "Documents · {count}"
|
|
105907
106062
|
},
|
|
105908
106063
|
summary: {
|
|
105909
106064
|
notAvailable: "Résumé non disponible"
|
|
@@ -107028,7 +107183,13 @@ var profileAccount$2 = {
|
|
|
107028
107183
|
tabBenchmarks: "Benchmarks",
|
|
107029
107184
|
descBenchmarks: "Créez des suites de benchmarks d'entrées de test pour évaluer les agents.",
|
|
107030
107185
|
tabMemory: "Mémoire",
|
|
107031
|
-
descMemory: "Gérez les mémoires globales des utilisateurs et les mémoires des agents."
|
|
107186
|
+
descMemory: "Gérez les mémoires globales des utilisateurs et les mémoires des agents.",
|
|
107187
|
+
groupWorkspace: "Espace de travail",
|
|
107188
|
+
groupAiData: "IA et données",
|
|
107189
|
+
groupSystem: "Système",
|
|
107190
|
+
ariaSettingsNav: "Paramètres de l'organisation",
|
|
107191
|
+
ariaSettingsNavMobile: "Paramètres de l'organisation (mobile)",
|
|
107192
|
+
groupFinance: "Finance"
|
|
107032
107193
|
};
|
|
107033
107194
|
var profileAddCreditsModal$2 = {
|
|
107034
107195
|
title: "Ajouter des crédits",
|
|
@@ -107224,7 +107385,6 @@ var profileIndex$2 = {
|
|
|
107224
107385
|
langSpanish: "Espagnol",
|
|
107225
107386
|
langFrench: "Français",
|
|
107226
107387
|
checkboxDisplayMentorAI: "Afficher la barre latérale de l'agent",
|
|
107227
|
-
checkboxDisplayLeaderboard: "Afficher le classement",
|
|
107228
107388
|
labelFacebook: "Facebook",
|
|
107229
107389
|
placeholderFacebook: "Facebook",
|
|
107230
107390
|
labelLinkedIn: "LinkedIn",
|
|
@@ -107245,7 +107405,16 @@ var profileIndex$2 = {
|
|
|
107245
107405
|
descChatHistoryPreview: "Conversations avec les agents IA.",
|
|
107246
107406
|
ariaAddEducation: "Ajouter une formation",
|
|
107247
107407
|
ariaAddExperience: "Ajouter une expérience",
|
|
107248
|
-
ariaAddResume: "Ajouter un CV"
|
|
107408
|
+
ariaAddResume: "Ajouter un CV",
|
|
107409
|
+
tabLlmUsage: "Utilisation",
|
|
107410
|
+
descLlmUsage: "Voyez combien d'IA vous avez utilisé : dépenses, jetons et requêtes dans vos conversations.",
|
|
107411
|
+
groupProfile: "Profil",
|
|
107412
|
+
groupAiData: "IA et données",
|
|
107413
|
+
groupAccount: "Compte",
|
|
107414
|
+
groupRecords: "Dossiers",
|
|
107415
|
+
descLlmUsagePreview: "Dépenses, jetons et requêtes dans les conversations.",
|
|
107416
|
+
sectionFeatures: "Fonctionnalités",
|
|
107417
|
+
tooltipDisplayMentorAI: "Garde le panneau de l'agent IA à côté de ce que vous faites, pour poser des questions sans quitter la page."
|
|
107249
107418
|
};
|
|
107250
107419
|
var profileInviteUserContent$2 = {
|
|
107251
107420
|
inviteUsersTitle: "Inviter des utilisateurs",
|
|
@@ -110104,6 +110273,81 @@ var analyticsTraces$2 = {
|
|
|
110104
110273
|
mentorScopeTitle: "La portée par agent ne restreint que la liste des traces.",
|
|
110105
110274
|
mentorScopeBody: "Les observations au niveau ligne ne peuvent pas être filtrées sur un seul agent — ouvrez une trace pour voir ses propres appels."
|
|
110106
110275
|
};
|
|
110276
|
+
var profileLlmUsage$2 = {
|
|
110277
|
+
rangeLabel: "Période",
|
|
110278
|
+
rangeToday: "Aujourd'hui",
|
|
110279
|
+
range7d: "7 jours",
|
|
110280
|
+
range30d: "30 jours",
|
|
110281
|
+
range90d: "90 jours",
|
|
110282
|
+
rangeAllTime: "Tout",
|
|
110283
|
+
periodToday: "Aujourd'hui",
|
|
110284
|
+
period7d: "7 derniers jours",
|
|
110285
|
+
period30d: "30 derniers jours",
|
|
110286
|
+
period90d: "90 derniers jours",
|
|
110287
|
+
periodAllTime: "Depuis le début",
|
|
110288
|
+
scopeSelf: "Seule votre propre activité est affichée",
|
|
110289
|
+
refresh: "Actualiser l'utilisation",
|
|
110290
|
+
kpiSpend: "Dépenses",
|
|
110291
|
+
kpiTokens: "Jetons",
|
|
110292
|
+
kpiRequests: "Requêtes",
|
|
110293
|
+
kpiAvgCost: "Coût moyen par requête",
|
|
110294
|
+
kpiTokensSub: "{value} par requête",
|
|
110295
|
+
kpiRequestsSub: "Appels à l'IA",
|
|
110296
|
+
kpiAvgCostSub: "Dépenses divisées par les requêtes",
|
|
110297
|
+
chartTitle: "Dépenses dans le temps",
|
|
110298
|
+
chartSubtitleDay: "Dépenses quotidiennes en dollars américains",
|
|
110299
|
+
chartSubtitleWeek: "Dépenses hebdomadaires en dollars américains",
|
|
110300
|
+
chartSubtitleMonth: "Dépenses mensuelles en dollars américains",
|
|
110301
|
+
chartAria: "Dépenses dans le temps. Utilisez les flèches gauche et droite pour lire chaque barre.",
|
|
110302
|
+
chartNoData: "Aucune dépense sur cette période.",
|
|
110303
|
+
chartTableCaption: "Dépenses par période",
|
|
110304
|
+
colPeriod: "Période",
|
|
110305
|
+
colCost: "Coût",
|
|
110306
|
+
byModelTitle: "Par modèle",
|
|
110307
|
+
byModelSubtitle: "Part de vos dépenses par modèle",
|
|
110308
|
+
byServiceTitle: "Par service",
|
|
110309
|
+
byServiceSubtitle: "D'où viennent vos dépenses",
|
|
110310
|
+
otherRow: "Autres",
|
|
110311
|
+
unknownModel: "Modèle inconnu",
|
|
110312
|
+
unknownService: "Autre service",
|
|
110313
|
+
breakdownEmpty: "Rien à détailler sur cette période.",
|
|
110314
|
+
sectionError: "Cette section n'a pas pu être chargée.",
|
|
110315
|
+
activityTitle: "Activité récente",
|
|
110316
|
+
activitySubtitle: "Vos dernières requêtes d'IA, les plus récentes d'abord. Ouvrez-en une pour voir chaque étape.",
|
|
110317
|
+
activityEmpty: "Aucune requête sur cette période.",
|
|
110318
|
+
colWhen: "Quand",
|
|
110319
|
+
colService: "Service",
|
|
110320
|
+
colSession: "Session",
|
|
110321
|
+
colLatency: "Latence",
|
|
110322
|
+
colDetails: "Détails",
|
|
110323
|
+
showSteps: "Afficher les étapes du {when}",
|
|
110324
|
+
hideSteps: "Masquer les étapes du {when}",
|
|
110325
|
+
stepsLoading: "Chargement des étapes…",
|
|
110326
|
+
stepsEmpty: "Aucune étape n'a été enregistrée pour cette requête.",
|
|
110327
|
+
stepsError: "Les étapes de cette requête n'ont pas pu être chargées.",
|
|
110328
|
+
colStep: "Étape",
|
|
110329
|
+
colModel: "Modèle",
|
|
110330
|
+
colInput: "Entrée",
|
|
110331
|
+
colOutput: "Sortie",
|
|
110332
|
+
colTotal: "Total",
|
|
110333
|
+
paginationSummary: "{from}–{to} sur {total}",
|
|
110334
|
+
previous: "Précédent",
|
|
110335
|
+
next: "Suivant",
|
|
110336
|
+
emptyTitle: "Aucune utilisation de l'IA sur cette période",
|
|
110337
|
+
emptyBody: "Les discussions, la mémoire et les autres requêtes d'IA apparaissent ici dès qu'elles ont lieu. Essayez une période plus longue.",
|
|
110338
|
+
emptyAction90: "Afficher les 90 derniers jours",
|
|
110339
|
+
emptyActionAll: "Tout afficher",
|
|
110340
|
+
errorForbiddenTitle: "L'utilisation n'est pas disponible",
|
|
110341
|
+
errorForbiddenBody: "Nous n'avons pas pu charger l'utilisation de ce compte.",
|
|
110342
|
+
errorUnavailableTitle: "L'utilisation est temporairement indisponible",
|
|
110343
|
+
errorUnavailableBody: "Veuillez réessayer dans quelques minutes.",
|
|
110344
|
+
errorUnauthorizedTitle: "Votre session a expiré",
|
|
110345
|
+
errorUnauthorizedBody: "Reconnectez-vous pour voir votre utilisation.",
|
|
110346
|
+
errorUnknownTitle: "Un problème est survenu",
|
|
110347
|
+
errorUnknownBody: "Nous n'avons pas pu charger votre utilisation.",
|
|
110348
|
+
tryAgain: "Réessayer",
|
|
110349
|
+
scopeUser: "Utilisation de {username}"
|
|
110350
|
+
};
|
|
110107
110351
|
var fr = {
|
|
110108
110352
|
accessTabAddAccess: accessTabAddAccess$2,
|
|
110109
110353
|
accessTabLabels: accessTabLabels$2,
|
|
@@ -110140,6 +110384,7 @@ var fr = {
|
|
|
110140
110384
|
analyticsAnalyticsReports: analyticsAnalyticsReports$2,
|
|
110141
110385
|
analyticsAnalyticsTopicsStats: analyticsAnalyticsTopicsStats$2,
|
|
110142
110386
|
analyticsAnalyticsTranscriptsStats: analyticsAnalyticsTranscriptsStats$2,
|
|
110387
|
+
analyticsTranscriptTurnDetails: analyticsTranscriptTurnDetails$2,
|
|
110143
110388
|
analyticsAnalyticsUsersStats: analyticsAnalyticsUsersStats$2,
|
|
110144
110389
|
analyticsGroupsFilterDropdown: analyticsGroupsFilterDropdown$2,
|
|
110145
110390
|
analyticsStatCard: analyticsStatCard$2,
|
|
@@ -110387,7 +110632,8 @@ var fr = {
|
|
|
110387
110632
|
analyticsChartCard: analyticsChartCard$2,
|
|
110388
110633
|
analyticsCostTabs: analyticsCostTabs$2,
|
|
110389
110634
|
analyticsLlmUsage: analyticsLlmUsage$2,
|
|
110390
|
-
analyticsTraces: analyticsTraces$2
|
|
110635
|
+
analyticsTraces: analyticsTraces$2,
|
|
110636
|
+
profileLlmUsage: profileLlmUsage$2
|
|
110391
110637
|
};
|
|
110392
110638
|
|
|
110393
110639
|
var accessTabAddAccess$1 = {
|
|
@@ -111363,7 +111609,7 @@ var analyticsAnalyticsTranscriptsStats$1 = {
|
|
|
111363
111609
|
labelUsername: "Nombre de usuario:",
|
|
111364
111610
|
labelAgent: "Agente:",
|
|
111365
111611
|
labelModel: "Modelo:",
|
|
111366
|
-
labelModelCard: "
|
|
111612
|
+
labelModelCard: "Modelo:",
|
|
111367
111613
|
labelUser: "Usuario:",
|
|
111368
111614
|
roleUser: "Usuario",
|
|
111369
111615
|
roleAgent: "Agente",
|
|
@@ -111405,6 +111651,37 @@ var analyticsAnalyticsTranscriptsStats$1 = {
|
|
|
111405
111651
|
avgCostPerConversationDescription: "Lo que cuesta una conversación típica en uso de modelos.",
|
|
111406
111652
|
avgRatingDescription: "Valoración media que los usuarios dieron a sus conversaciones, en una escala de 1 a 5."
|
|
111407
111653
|
};
|
|
111654
|
+
var analyticsTranscriptTurnDetails$1 = {
|
|
111655
|
+
showDetails: "Mostrar detalles",
|
|
111656
|
+
hideDetails: "Ocultar detalles",
|
|
111657
|
+
metadata: "Metadatos",
|
|
111658
|
+
requestContext: "Contexto de la solicitud",
|
|
111659
|
+
model: "Modelo",
|
|
111660
|
+
provider: "Proveedor",
|
|
111661
|
+
temperature: "Temperatura",
|
|
111662
|
+
client: "Cliente",
|
|
111663
|
+
sourcesBadge: "Documentos · {count}",
|
|
111664
|
+
toolsBadge: "Herramientas · {count}",
|
|
111665
|
+
yes: "Sí",
|
|
111666
|
+
no: "No",
|
|
111667
|
+
redacted: "Oculto",
|
|
111668
|
+
fieldSession: "Sesión",
|
|
111669
|
+
fieldCallerVerified: "Llamante verificado",
|
|
111670
|
+
fieldFiles: "Archivos",
|
|
111671
|
+
fieldFile: "Archivo",
|
|
111672
|
+
fieldSystemPrompt: "Prompt del sistema",
|
|
111673
|
+
fieldFlow: "Flujo",
|
|
111674
|
+
fieldToken: "Token",
|
|
111675
|
+
fieldTenant: "Inquilino",
|
|
111676
|
+
fieldPathway: "Ruta",
|
|
111677
|
+
fieldUsername: "Nombre de usuario",
|
|
111678
|
+
fieldName: "Nombre",
|
|
111679
|
+
fieldCanvas: "Canvas",
|
|
111680
|
+
fieldProactivePrompt: "Prompt proactivo",
|
|
111681
|
+
fieldGrader: "Calificador",
|
|
111682
|
+
fieldDatasets: "Conjuntos de datos",
|
|
111683
|
+
fieldDateTime: "Fecha y hora"
|
|
111684
|
+
};
|
|
111408
111685
|
var analyticsAnalyticsUsersStats$1 = {
|
|
111409
111686
|
usersLoggedInNow: "Usuarios conectados ahora mismo",
|
|
111410
111687
|
usersLoggedInPast30Days: "Usuarios conectados en los últimos 30 días",
|
|
@@ -113061,7 +113338,8 @@ var historyTabLabels$1 = {
|
|
|
113061
113338
|
noResponse: "No hay respuesta disponible",
|
|
113062
113339
|
selectPrompt: "Selecciona una conversación para ver los detalles.",
|
|
113063
113340
|
aiAgent: "AI Agent",
|
|
113064
|
-
noConversations: "No se encontraron conversaciones"
|
|
113341
|
+
noConversations: "No se encontraron conversaciones",
|
|
113342
|
+
documentsChip: "Documentos · {count}"
|
|
113065
113343
|
},
|
|
113066
113344
|
summary: {
|
|
113067
113345
|
notAvailable: "Resumen no disponible"
|
|
@@ -114186,7 +114464,13 @@ var profileAccount$1 = {
|
|
|
114186
114464
|
tabBenchmarks: "Benchmarks",
|
|
114187
114465
|
descBenchmarks: "Cree suites de benchmarks con entradas de prueba para evaluar agentes.",
|
|
114188
114466
|
tabMemory: "Memoria",
|
|
114189
|
-
descMemory: "Gestiona las memorias globales de los usuarios y las memorias de los agentes."
|
|
114467
|
+
descMemory: "Gestiona las memorias globales de los usuarios y las memorias de los agentes.",
|
|
114468
|
+
groupWorkspace: "Espacio de trabajo",
|
|
114469
|
+
groupAiData: "IA y datos",
|
|
114470
|
+
groupSystem: "Sistema",
|
|
114471
|
+
ariaSettingsNav: "Configuración de la organización",
|
|
114472
|
+
ariaSettingsNavMobile: "Configuración de la organización (móvil)",
|
|
114473
|
+
groupFinance: "Finanzas"
|
|
114190
114474
|
};
|
|
114191
114475
|
var profileAddCreditsModal$1 = {
|
|
114192
114476
|
title: "Agregar créditos",
|
|
@@ -114382,7 +114666,6 @@ var profileIndex$1 = {
|
|
|
114382
114666
|
langSpanish: "Español",
|
|
114383
114667
|
langFrench: "Francés",
|
|
114384
114668
|
checkboxDisplayMentorAI: "Mostrar barra lateral del agente",
|
|
114385
|
-
checkboxDisplayLeaderboard: "Mostrar tabla de clasificación",
|
|
114386
114669
|
labelFacebook: "Facebook",
|
|
114387
114670
|
placeholderFacebook: "Facebook",
|
|
114388
114671
|
labelLinkedIn: "LinkedIn",
|
|
@@ -114403,7 +114686,16 @@ var profileIndex$1 = {
|
|
|
114403
114686
|
descChatHistoryPreview: "Conversaciones con agentes de IA.",
|
|
114404
114687
|
ariaAddEducation: "Añadir educación",
|
|
114405
114688
|
ariaAddExperience: "Añadir experiencia",
|
|
114406
|
-
ariaAddResume: "Añadir currículum"
|
|
114689
|
+
ariaAddResume: "Añadir currículum",
|
|
114690
|
+
tabLlmUsage: "Uso",
|
|
114691
|
+
descLlmUsage: "Consulta cuánta IA has usado: gasto, tokens y solicitudes en tus conversaciones.",
|
|
114692
|
+
groupProfile: "Perfil",
|
|
114693
|
+
groupAiData: "IA y datos",
|
|
114694
|
+
groupAccount: "Cuenta",
|
|
114695
|
+
groupRecords: "Registros",
|
|
114696
|
+
descLlmUsagePreview: "Gasto, tokens y solicitudes en las conversaciones.",
|
|
114697
|
+
sectionFeatures: "Funciones",
|
|
114698
|
+
tooltipDisplayMentorAI: "Mantiene el panel del agente de IA junto a lo que estés haciendo, para que puedas preguntar sin salir de la página."
|
|
114407
114699
|
};
|
|
114408
114700
|
var profileInviteUserContent$1 = {
|
|
114409
114701
|
inviteUsersTitle: "Invitar usuarios",
|
|
@@ -117262,6 +117554,81 @@ var analyticsTraces$1 = {
|
|
|
117262
117554
|
mentorScopeTitle: "El alcance por agente solo acota la lista de trazas.",
|
|
117263
117555
|
mentorScopeBody: "Las observaciones a nivel de fila no pueden filtrarse por un solo agente — abre una traza para ver sus propias llamadas."
|
|
117264
117556
|
};
|
|
117557
|
+
var profileLlmUsage$1 = {
|
|
117558
|
+
rangeLabel: "Rango de fechas",
|
|
117559
|
+
rangeToday: "Hoy",
|
|
117560
|
+
range7d: "7 días",
|
|
117561
|
+
range30d: "30 días",
|
|
117562
|
+
range90d: "90 días",
|
|
117563
|
+
rangeAllTime: "Todo",
|
|
117564
|
+
periodToday: "Hoy",
|
|
117565
|
+
period7d: "Últimos 7 días",
|
|
117566
|
+
period30d: "Últimos 30 días",
|
|
117567
|
+
period90d: "Últimos 90 días",
|
|
117568
|
+
periodAllTime: "Todo el tiempo",
|
|
117569
|
+
scopeSelf: "Solo se muestra tu propia actividad",
|
|
117570
|
+
refresh: "Actualizar uso",
|
|
117571
|
+
kpiSpend: "Gasto",
|
|
117572
|
+
kpiTokens: "Tokens",
|
|
117573
|
+
kpiRequests: "Solicitudes",
|
|
117574
|
+
kpiAvgCost: "Costo promedio por solicitud",
|
|
117575
|
+
kpiTokensSub: "{value} por solicitud",
|
|
117576
|
+
kpiRequestsSub: "Llamadas a la IA",
|
|
117577
|
+
kpiAvgCostSub: "Gasto dividido entre solicitudes",
|
|
117578
|
+
chartTitle: "Gasto a lo largo del tiempo",
|
|
117579
|
+
chartSubtitleDay: "Gasto diario en dólares estadounidenses",
|
|
117580
|
+
chartSubtitleWeek: "Gasto semanal en dólares estadounidenses",
|
|
117581
|
+
chartSubtitleMonth: "Gasto mensual en dólares estadounidenses",
|
|
117582
|
+
chartAria: "Gasto a lo largo del tiempo. Usa las flechas izquierda y derecha para leer cada barra.",
|
|
117583
|
+
chartNoData: "No hay gasto en este período.",
|
|
117584
|
+
chartTableCaption: "Gasto por período",
|
|
117585
|
+
colPeriod: "Período",
|
|
117586
|
+
colCost: "Costo",
|
|
117587
|
+
byModelTitle: "Por modelo",
|
|
117588
|
+
byModelSubtitle: "Parte de tu gasto por modelo",
|
|
117589
|
+
byServiceTitle: "Por servicio",
|
|
117590
|
+
byServiceSubtitle: "De dónde proviene tu gasto",
|
|
117591
|
+
otherRow: "Otros",
|
|
117592
|
+
unknownModel: "Modelo desconocido",
|
|
117593
|
+
unknownService: "Otro servicio",
|
|
117594
|
+
breakdownEmpty: "No hay nada que desglosar en este período.",
|
|
117595
|
+
sectionError: "No se pudo cargar esta sección.",
|
|
117596
|
+
activityTitle: "Actividad reciente",
|
|
117597
|
+
activitySubtitle: "Tus solicitudes de IA más recientes, primero las más nuevas. Abre una para ver cada paso.",
|
|
117598
|
+
activityEmpty: "No hay solicitudes en este período.",
|
|
117599
|
+
colWhen: "Cuándo",
|
|
117600
|
+
colService: "Servicio",
|
|
117601
|
+
colSession: "Sesión",
|
|
117602
|
+
colLatency: "Latencia",
|
|
117603
|
+
colDetails: "Detalles",
|
|
117604
|
+
showSteps: "Mostrar pasos de {when}",
|
|
117605
|
+
hideSteps: "Ocultar pasos de {when}",
|
|
117606
|
+
stepsLoading: "Cargando pasos…",
|
|
117607
|
+
stepsEmpty: "No se registraron pasos para esta solicitud.",
|
|
117608
|
+
stepsError: "No se pudieron cargar los pasos de esta solicitud.",
|
|
117609
|
+
colStep: "Paso",
|
|
117610
|
+
colModel: "Modelo",
|
|
117611
|
+
colInput: "Entrada",
|
|
117612
|
+
colOutput: "Salida",
|
|
117613
|
+
colTotal: "Total",
|
|
117614
|
+
paginationSummary: "Mostrando {from}–{to} de {total}",
|
|
117615
|
+
previous: "Anterior",
|
|
117616
|
+
next: "Siguiente",
|
|
117617
|
+
emptyTitle: "Sin uso de IA en este período",
|
|
117618
|
+
emptyBody: "Los chats, la memoria y otras solicitudes de IA aparecen aquí cuando ocurren. Prueba un rango más amplio.",
|
|
117619
|
+
emptyAction90: "Mostrar los últimos 90 días",
|
|
117620
|
+
emptyActionAll: "Mostrar todo",
|
|
117621
|
+
errorForbiddenTitle: "El uso no está disponible",
|
|
117622
|
+
errorForbiddenBody: "No pudimos cargar el uso de esta cuenta.",
|
|
117623
|
+
errorUnavailableTitle: "El uso no está disponible temporalmente",
|
|
117624
|
+
errorUnavailableBody: "Inténtalo de nuevo en unos minutos.",
|
|
117625
|
+
errorUnauthorizedTitle: "Tu sesión ha expirado",
|
|
117626
|
+
errorUnauthorizedBody: "Vuelve a iniciar sesión para ver tu uso.",
|
|
117627
|
+
errorUnknownTitle: "Algo salió mal",
|
|
117628
|
+
errorUnknownBody: "No pudimos cargar tu uso.",
|
|
117629
|
+
tryAgain: "Intentar de nuevo",
|
|
117630
|
+
scopeUser: "Uso de {username}"
|
|
117631
|
+
};
|
|
117265
117632
|
var es = {
|
|
117266
117633
|
accessTabAddAccess: accessTabAddAccess$1,
|
|
117267
117634
|
accessTabLabels: accessTabLabels$1,
|
|
@@ -117298,6 +117665,7 @@ var es = {
|
|
|
117298
117665
|
analyticsAnalyticsReports: analyticsAnalyticsReports$1,
|
|
117299
117666
|
analyticsAnalyticsTopicsStats: analyticsAnalyticsTopicsStats$1,
|
|
117300
117667
|
analyticsAnalyticsTranscriptsStats: analyticsAnalyticsTranscriptsStats$1,
|
|
117668
|
+
analyticsTranscriptTurnDetails: analyticsTranscriptTurnDetails$1,
|
|
117301
117669
|
analyticsAnalyticsUsersStats: analyticsAnalyticsUsersStats$1,
|
|
117302
117670
|
analyticsGroupsFilterDropdown: analyticsGroupsFilterDropdown$1,
|
|
117303
117671
|
analyticsStatCard: analyticsStatCard$1,
|
|
@@ -117545,7 +117913,8 @@ var es = {
|
|
|
117545
117913
|
analyticsChartCard: analyticsChartCard$1,
|
|
117546
117914
|
analyticsCostTabs: analyticsCostTabs$1,
|
|
117547
117915
|
analyticsLlmUsage: analyticsLlmUsage$1,
|
|
117548
|
-
analyticsTraces: analyticsTraces$1
|
|
117916
|
+
analyticsTraces: analyticsTraces$1,
|
|
117917
|
+
profileLlmUsage: profileLlmUsage$1
|
|
117549
117918
|
};
|
|
117550
117919
|
|
|
117551
117920
|
var accessTabAddAccess = {
|
|
@@ -118563,6 +118932,37 @@ var analyticsAnalyticsTranscriptsStats = {
|
|
|
118563
118932
|
avgCostPerConversationDescription: "一次典型对话所产生的模型使用成本。",
|
|
118564
118933
|
avgRatingDescription: "用户对其对话给出的平均评分,满分 5 分。"
|
|
118565
118934
|
};
|
|
118935
|
+
var analyticsTranscriptTurnDetails = {
|
|
118936
|
+
showDetails: "显示详情",
|
|
118937
|
+
hideDetails: "隐藏详情",
|
|
118938
|
+
metadata: "元数据",
|
|
118939
|
+
requestContext: "请求上下文",
|
|
118940
|
+
model: "模型",
|
|
118941
|
+
provider: "提供商",
|
|
118942
|
+
temperature: "温度",
|
|
118943
|
+
client: "客户端",
|
|
118944
|
+
sourcesBadge: "文档 · {count}",
|
|
118945
|
+
toolsBadge: "工具 · {count}",
|
|
118946
|
+
yes: "是",
|
|
118947
|
+
no: "否",
|
|
118948
|
+
redacted: "已隐藏",
|
|
118949
|
+
fieldSession: "会话",
|
|
118950
|
+
fieldCallerVerified: "调用者已验证",
|
|
118951
|
+
fieldFiles: "文件",
|
|
118952
|
+
fieldFile: "文件",
|
|
118953
|
+
fieldSystemPrompt: "系统提示",
|
|
118954
|
+
fieldFlow: "流程",
|
|
118955
|
+
fieldToken: "令牌",
|
|
118956
|
+
fieldTenant: "租户",
|
|
118957
|
+
fieldPathway: "路径",
|
|
118958
|
+
fieldUsername: "用户名",
|
|
118959
|
+
fieldName: "名称",
|
|
118960
|
+
fieldCanvas: "画布",
|
|
118961
|
+
fieldProactivePrompt: "主动提示",
|
|
118962
|
+
fieldGrader: "评分器",
|
|
118963
|
+
fieldDatasets: "数据集",
|
|
118964
|
+
fieldDateTime: "日期和时间"
|
|
118965
|
+
};
|
|
118566
118966
|
var analyticsAnalyticsUsersStats = {
|
|
118567
118967
|
usersLoggedInNow: "当前在线用户",
|
|
118568
118968
|
usersLoggedInPast30Days: "过去 30 天登录用户",
|
|
@@ -120219,7 +120619,8 @@ var historyTabLabels = {
|
|
|
120219
120619
|
noResponse: "暂无回复",
|
|
120220
120620
|
selectPrompt: "选择一条对话以查看详情。",
|
|
120221
120621
|
aiAgent: "AI Agent",
|
|
120222
|
-
noConversations: "未找到对话"
|
|
120622
|
+
noConversations: "未找到对话",
|
|
120623
|
+
documentsChip: "文档 · {count}"
|
|
120223
120624
|
},
|
|
120224
120625
|
summary: {
|
|
120225
120626
|
notAvailable: "摘要不可用"
|
|
@@ -121344,7 +121745,13 @@ var profileAccount = {
|
|
|
121344
121745
|
tabBenchmarks: "基准测试",
|
|
121345
121746
|
descBenchmarks: "构建包含测试输入的基准测试套件,以评估智能体。",
|
|
121346
121747
|
tabMemory: "记忆",
|
|
121347
|
-
descMemory: "管理用户的全局记忆和智能体记忆。"
|
|
121748
|
+
descMemory: "管理用户的全局记忆和智能体记忆。",
|
|
121749
|
+
groupWorkspace: "工作区",
|
|
121750
|
+
groupAiData: "AI 与数据",
|
|
121751
|
+
groupSystem: "系统",
|
|
121752
|
+
ariaSettingsNav: "组织设置",
|
|
121753
|
+
ariaSettingsNavMobile: "组织设置(移动端)",
|
|
121754
|
+
groupFinance: "财务"
|
|
121348
121755
|
};
|
|
121349
121756
|
var profileAddCreditsModal = {
|
|
121350
121757
|
title: "添加积分",
|
|
@@ -121540,7 +121947,6 @@ var profileIndex = {
|
|
|
121540
121947
|
langSpanish: "西班牙语",
|
|
121541
121948
|
langFrench: "法语",
|
|
121542
121949
|
checkboxDisplayMentorAI: "显示助手侧边栏",
|
|
121543
|
-
checkboxDisplayLeaderboard: "显示排行榜",
|
|
121544
121950
|
labelFacebook: "Facebook",
|
|
121545
121951
|
placeholderFacebook: "Facebook",
|
|
121546
121952
|
labelLinkedIn: "LinkedIn",
|
|
@@ -121561,7 +121967,16 @@ var profileIndex = {
|
|
|
121561
121967
|
descChatHistoryPreview: "与 AI 代理的对话。",
|
|
121562
121968
|
ariaAddEducation: "添加教育经历",
|
|
121563
121969
|
ariaAddExperience: "添加工作经历",
|
|
121564
|
-
ariaAddResume: "添加简历"
|
|
121970
|
+
ariaAddResume: "添加简历",
|
|
121971
|
+
tabLlmUsage: "用量",
|
|
121972
|
+
descLlmUsage: "查看你使用了多少 AI:各对话中的花费、令牌数和请求数。",
|
|
121973
|
+
groupProfile: "个人资料",
|
|
121974
|
+
groupAiData: "AI 与数据",
|
|
121975
|
+
groupAccount: "账户",
|
|
121976
|
+
groupRecords: "记录",
|
|
121977
|
+
descLlmUsagePreview: "各对话中的花费、令牌数和请求数。",
|
|
121978
|
+
sectionFeatures: "功能",
|
|
121979
|
+
tooltipDisplayMentorAI: "让 AI 助手面板始终显示在当前页面旁边,无需离开页面即可提问。"
|
|
121565
121980
|
};
|
|
121566
121981
|
var profileInviteUserContent = {
|
|
121567
121982
|
inviteUsersTitle: "邀请用户",
|
|
@@ -124420,6 +124835,81 @@ var analyticsTraces = {
|
|
|
124420
124835
|
mentorScopeTitle: "代理范围仅缩小追踪列表。",
|
|
124421
124836
|
mentorScopeBody: "行级观测记录无法按单个代理筛选 — 打开一条追踪查看它自己的调用。"
|
|
124422
124837
|
};
|
|
124838
|
+
var profileLlmUsage = {
|
|
124839
|
+
rangeLabel: "日期范围",
|
|
124840
|
+
rangeToday: "今天",
|
|
124841
|
+
range7d: "7 天",
|
|
124842
|
+
range30d: "30 天",
|
|
124843
|
+
range90d: "90 天",
|
|
124844
|
+
rangeAllTime: "全部",
|
|
124845
|
+
periodToday: "今天",
|
|
124846
|
+
period7d: "最近 7 天",
|
|
124847
|
+
period30d: "最近 30 天",
|
|
124848
|
+
period90d: "最近 90 天",
|
|
124849
|
+
periodAllTime: "全部时间",
|
|
124850
|
+
scopeSelf: "仅显示你自己的活动",
|
|
124851
|
+
refresh: "刷新用量",
|
|
124852
|
+
kpiSpend: "花费",
|
|
124853
|
+
kpiTokens: "令牌",
|
|
124854
|
+
kpiRequests: "请求",
|
|
124855
|
+
kpiAvgCost: "每次请求平均花费",
|
|
124856
|
+
kpiTokensSub: "每次请求 {value}",
|
|
124857
|
+
kpiRequestsSub: "AI 调用",
|
|
124858
|
+
kpiAvgCostSub: "花费除以请求数",
|
|
124859
|
+
chartTitle: "花费趋势",
|
|
124860
|
+
chartSubtitleDay: "每日花费(美元)",
|
|
124861
|
+
chartSubtitleWeek: "每周花费(美元)",
|
|
124862
|
+
chartSubtitleMonth: "每月花费(美元)",
|
|
124863
|
+
chartAria: "花费趋势。使用左右方向键逐个读取柱形。",
|
|
124864
|
+
chartNoData: "此期间没有花费。",
|
|
124865
|
+
chartTableCaption: "各期间花费",
|
|
124866
|
+
colPeriod: "期间",
|
|
124867
|
+
colCost: "花费",
|
|
124868
|
+
byModelTitle: "按模型",
|
|
124869
|
+
byModelSubtitle: "各模型占你花费的比例",
|
|
124870
|
+
byServiceTitle: "按服务",
|
|
124871
|
+
byServiceSubtitle: "你的花费来自哪里",
|
|
124872
|
+
otherRow: "其他",
|
|
124873
|
+
unknownModel: "未知模型",
|
|
124874
|
+
unknownService: "其他服务",
|
|
124875
|
+
breakdownEmpty: "此期间没有可细分的数据。",
|
|
124876
|
+
sectionError: "无法加载此部分。",
|
|
124877
|
+
activityTitle: "最近活动",
|
|
124878
|
+
activitySubtitle: "你最近的 AI 请求,最新的在前。展开可查看每个步骤。",
|
|
124879
|
+
activityEmpty: "此期间没有请求。",
|
|
124880
|
+
colWhen: "时间",
|
|
124881
|
+
colService: "服务",
|
|
124882
|
+
colSession: "会话",
|
|
124883
|
+
colLatency: "延迟",
|
|
124884
|
+
colDetails: "详情",
|
|
124885
|
+
showSteps: "显示 {when} 的步骤",
|
|
124886
|
+
hideSteps: "隐藏 {when} 的步骤",
|
|
124887
|
+
stepsLoading: "正在加载步骤…",
|
|
124888
|
+
stepsEmpty: "此请求没有记录任何步骤。",
|
|
124889
|
+
stepsError: "无法加载此请求的步骤。",
|
|
124890
|
+
colStep: "步骤",
|
|
124891
|
+
colModel: "模型",
|
|
124892
|
+
colInput: "输入",
|
|
124893
|
+
colOutput: "输出",
|
|
124894
|
+
colTotal: "合计",
|
|
124895
|
+
paginationSummary: "第 {from}–{to} 条,共 {total} 条",
|
|
124896
|
+
previous: "上一页",
|
|
124897
|
+
next: "下一页",
|
|
124898
|
+
emptyTitle: "此期间没有 AI 用量",
|
|
124899
|
+
emptyBody: "发生聊天、记忆和其他 AI 请求后,相关记录会显示在这里。请尝试更长的时间范围。",
|
|
124900
|
+
emptyAction90: "显示最近 90 天",
|
|
124901
|
+
emptyActionAll: "显示全部",
|
|
124902
|
+
errorForbiddenTitle: "无法查看用量",
|
|
124903
|
+
errorForbiddenBody: "无法加载此账户的用量。",
|
|
124904
|
+
errorUnavailableTitle: "用量暂时不可用",
|
|
124905
|
+
errorUnavailableBody: "请几分钟后再试。",
|
|
124906
|
+
errorUnauthorizedTitle: "你的会话已过期",
|
|
124907
|
+
errorUnauthorizedBody: "请重新登录以查看你的用量。",
|
|
124908
|
+
errorUnknownTitle: "出现问题",
|
|
124909
|
+
errorUnknownBody: "无法加载你的用量。",
|
|
124910
|
+
tryAgain: "重试",
|
|
124911
|
+
scopeUser: "{username} 的用量"
|
|
124912
|
+
};
|
|
124423
124913
|
var zh = {
|
|
124424
124914
|
accessTabAddAccess: accessTabAddAccess,
|
|
124425
124915
|
accessTabLabels: accessTabLabels,
|
|
@@ -124456,6 +124946,7 @@ var zh = {
|
|
|
124456
124946
|
analyticsAnalyticsReports: analyticsAnalyticsReports,
|
|
124457
124947
|
analyticsAnalyticsTopicsStats: analyticsAnalyticsTopicsStats,
|
|
124458
124948
|
analyticsAnalyticsTranscriptsStats: analyticsAnalyticsTranscriptsStats,
|
|
124949
|
+
analyticsTranscriptTurnDetails: analyticsTranscriptTurnDetails,
|
|
124459
124950
|
analyticsAnalyticsUsersStats: analyticsAnalyticsUsersStats,
|
|
124460
124951
|
analyticsGroupsFilterDropdown: analyticsGroupsFilterDropdown,
|
|
124461
124952
|
analyticsStatCard: analyticsStatCard,
|
|
@@ -124703,7 +125194,8 @@ var zh = {
|
|
|
124703
125194
|
analyticsChartCard: analyticsChartCard,
|
|
124704
125195
|
analyticsCostTabs: analyticsCostTabs,
|
|
124705
125196
|
analyticsLlmUsage: analyticsLlmUsage,
|
|
124706
|
-
analyticsTraces: analyticsTraces
|
|
125197
|
+
analyticsTraces: analyticsTraces,
|
|
125198
|
+
profileLlmUsage: profileLlmUsage
|
|
124707
125199
|
};
|
|
124708
125200
|
|
|
124709
125201
|
/**
|
|
@@ -131707,8 +132199,8 @@ function EducationDialog({ open, onOpenChange, org, username, education, onCompl
|
|
|
131707
132199
|
}, org: org, username: username })] }));
|
|
131708
132200
|
}
|
|
131709
132201
|
|
|
131710
|
-
const Card = React.forwardRef(({ className, ...props }, ref) => (jsx("div", { ref: ref, className: cn("rounded-lg border bg-card text-card-foreground shadow-sm", className), ...props })));
|
|
131711
|
-
Card.displayName = "Card";
|
|
132202
|
+
const Card$1 = React.forwardRef(({ className, ...props }, ref) => (jsx("div", { ref: ref, className: cn("rounded-lg border bg-card text-card-foreground shadow-sm", className), ...props })));
|
|
132203
|
+
Card$1.displayName = "Card";
|
|
131712
132204
|
const CardHeader = React.forwardRef(({ className, ...props }, ref) => (jsx("div", { ref: ref, className: cn("flex flex-col space-y-1.5 p-6", className), ...props })));
|
|
131713
132205
|
CardHeader.displayName = "CardHeader";
|
|
131714
132206
|
const CardTitle = React.forwardRef(({ className, ...props }, ref) => (jsx("div", { ref: ref, className: cn("text-2xl font-semibold leading-none tracking-tight", className), ...props })));
|
|
@@ -131721,7 +132213,7 @@ const CardFooter = React.forwardRef(({ className, ...props }, ref) => (jsx("div"
|
|
|
131721
132213
|
CardFooter.displayName = "CardFooter";
|
|
131722
132214
|
|
|
131723
132215
|
function ProfileEmptyState({ icon: Icon, message }) {
|
|
131724
|
-
return (jsx(Card, { className: "shadow-sm border border-dashed", style: { borderColor: 'oklch(.922 0 0)' }, children: jsxs(CardContent, { className: "p-8 text-center", children: [jsx(Icon, { className: "h-10 w-10 mx-auto text-gray-300 mb-3", "aria-hidden": "true" }), jsx("p", { className: "text-sm text-gray-400", children: message })] }) }));
|
|
132216
|
+
return (jsx(Card$1, { className: "shadow-sm border border-dashed", style: { borderColor: 'oklch(.922 0 0)' }, children: jsxs(CardContent, { className: "p-8 text-center", children: [jsx(Icon, { className: "h-10 w-10 mx-auto text-gray-300 mb-3", "aria-hidden": "true" }), jsx("p", { className: "text-sm text-gray-400", children: message })] }) }));
|
|
131725
132217
|
}
|
|
131726
132218
|
|
|
131727
132219
|
const formatEducationDuration = (education, present) => {
|
|
@@ -154144,15 +154636,15 @@ function SubscriptionDetail({ subscription: initialSubscription, platformKey, on
|
|
|
154144
154636
|
if (isLoadingDetail) {
|
|
154145
154637
|
return (jsxs("div", { className: "space-y-4", children: [jsxs("div", { className: "flex items-center gap-3", children: [jsxs(Button$1, { variant: "ghost", size: "sm", onClick: onBack, className: "cursor-pointer", children: [jsx(ChevronLeft, { className: "h-4 w-4 mr-1" }), t('purchasesPurchasesTab.back')] }), jsx(Skeleton, { className: "h-6 w-48" })] }), jsx(Skeleton, { className: "h-64 w-full" })] }));
|
|
154146
154638
|
}
|
|
154147
|
-
return (jsxs("div", { className: "space-y-4", children: [jsxs("div", { className: "flex items-center gap-3", children: [jsxs(Button$1, { variant: "ghost", size: "sm", onClick: onBack, className: "cursor-pointer", children: [jsx(ChevronLeft, { className: "h-4 w-4 mr-1" }), t('purchasesPurchasesTab.back')] }), jsxs("div", { children: [jsx("h4", { className: "text-base font-semibold text-gray-900 dark:text-gray-100", children: subscription.item_name || subscription.item_id }), jsx("span", { className: "text-xs text-gray-400 capitalize", children: subscription.item_type })] })] }), jsx(Card, { className: "shadow-sm border", style: { borderColor: 'oklch(.922 0 0)' }, children: jsxs(CardContent, { className: "p-6 space-y-5", children: [jsxs("div", { className: "flex items-center justify-between", children: [jsx("span", { className: "text-sm font-medium text-gray-700 dark:text-gray-300", children: t('purchasesPurchasesTab.labelStatus') }), jsx(Badge, { className: statusBadgeStyle(subscription.status), children: subscription.status })] }), jsxs("div", { className: "flex items-center justify-between border-t pt-3", children: [jsx("span", { className: "text-sm font-medium text-gray-700 dark:text-gray-300", children: t('purchasesPurchasesTab.labelPlan') }), jsxs("div", { className: "text-right", children: [jsx("span", { className: "text-sm font-semibold text-gray-900 dark:text-gray-100", children: (_b = subscription.price) === null || _b === void 0 ? void 0 : _b.name }), jsxs("span", { className: "text-sm text-gray-500 ml-2", children: [formatCurrency((_c = subscription.price) === null || _c === void 0 ? void 0 : _c.amount, (_d = subscription.price) === null || _d === void 0 ? void 0 : _d.currency), formatInterval((_e = subscription.price) === null || _e === void 0 ? void 0 : _e.interval)] })] })] }), jsxs("div", { className: "flex items-center justify-between border-t pt-3", children: [jsx("span", { className: "text-sm font-medium text-gray-700 dark:text-gray-300", children: t('purchasesPurchasesTab.labelType') }), jsx(Badge, { variant: "secondary", className: "capitalize", children: subscription.item_type })] }), subscription.current_period_end && (jsxs("div", { className: "flex items-center justify-between border-t pt-3", children: [jsx("span", { className: "text-sm font-medium text-gray-700 dark:text-gray-300", children: subscription.cancel_at_period_end
|
|
154639
|
+
return (jsxs("div", { className: "space-y-4", children: [jsxs("div", { className: "flex items-center gap-3", children: [jsxs(Button$1, { variant: "ghost", size: "sm", onClick: onBack, className: "cursor-pointer", children: [jsx(ChevronLeft, { className: "h-4 w-4 mr-1" }), t('purchasesPurchasesTab.back')] }), jsxs("div", { children: [jsx("h4", { className: "text-base font-semibold text-gray-900 dark:text-gray-100", children: subscription.item_name || subscription.item_id }), jsx("span", { className: "text-xs text-gray-400 capitalize", children: subscription.item_type })] })] }), jsx(Card$1, { className: "shadow-sm border", style: { borderColor: 'oklch(.922 0 0)' }, children: jsxs(CardContent, { className: "p-6 space-y-5", children: [jsxs("div", { className: "flex items-center justify-between", children: [jsx("span", { className: "text-sm font-medium text-gray-700 dark:text-gray-300", children: t('purchasesPurchasesTab.labelStatus') }), jsx(Badge, { className: statusBadgeStyle(subscription.status), children: subscription.status })] }), jsxs("div", { className: "flex items-center justify-between border-t pt-3", children: [jsx("span", { className: "text-sm font-medium text-gray-700 dark:text-gray-300", children: t('purchasesPurchasesTab.labelPlan') }), jsxs("div", { className: "text-right", children: [jsx("span", { className: "text-sm font-semibold text-gray-900 dark:text-gray-100", children: (_b = subscription.price) === null || _b === void 0 ? void 0 : _b.name }), jsxs("span", { className: "text-sm text-gray-500 ml-2", children: [formatCurrency((_c = subscription.price) === null || _c === void 0 ? void 0 : _c.amount, (_d = subscription.price) === null || _d === void 0 ? void 0 : _d.currency), formatInterval((_e = subscription.price) === null || _e === void 0 ? void 0 : _e.interval)] })] })] }), jsxs("div", { className: "flex items-center justify-between border-t pt-3", children: [jsx("span", { className: "text-sm font-medium text-gray-700 dark:text-gray-300", children: t('purchasesPurchasesTab.labelType') }), jsx(Badge, { variant: "secondary", className: "capitalize", children: subscription.item_type })] }), subscription.current_period_end && (jsxs("div", { className: "flex items-center justify-between border-t pt-3", children: [jsx("span", { className: "text-sm font-medium text-gray-700 dark:text-gray-300", children: subscription.cancel_at_period_end
|
|
154148
154640
|
? t('purchasesPurchasesTab.labelAccessUntil')
|
|
154149
|
-
: t('purchasesPurchasesTab.labelRenewsOn') }), jsxs("span", { className: "text-sm text-gray-600 dark:text-gray-400 flex items-center gap-1.5", children: [jsx(Calendar$1, { className: "h-3.5 w-3.5" }), new Date(subscription.current_period_end).toLocaleDateString()] })] })), subscription.created_at && (jsxs("div", { className: "flex items-center justify-between border-t pt-3", children: [jsx("span", { className: "text-sm font-medium text-gray-700 dark:text-gray-300", children: t('purchasesPurchasesTab.labelSubscribedSince') }), jsxs("span", { className: "text-sm text-gray-600 dark:text-gray-400 flex items-center gap-1.5", children: [jsx(Clock, { className: "h-3.5 w-3.5" }), new Date(subscription.created_at).toLocaleDateString()] })] })), subscription.is_grandfathered && (jsxs("div", { className: "flex items-center justify-between border-t pt-3", children: [jsx("span", { className: "text-sm font-medium text-gray-700 dark:text-gray-300", children: t('purchasesPurchasesTab.labelLegacyAccess') }), jsxs(Badge, { className: "bg-amber-100 text-amber-700 border-amber-200 text-xs", children: [jsx(Shield, { className: "h-3 w-3 mr-1" }), t('purchasesPurchasesTab.badgeGrandfathered')] })] })), subscription.cancel_at_period_end && (jsxs("div", { className: "flex items-center gap-2 border-t pt-3 text-yellow-600", children: [jsx(TriangleAlert, { className: "h-4 w-4 flex-shrink-0" }), jsx("span", { className: "text-sm", children: t('purchasesPurchasesTab.warningWillNotRenew') })] }))] }) }), canCancel && !cancelResult && (jsx(Card, { className: "shadow-sm border border-blue-100", style: { borderColor: 'oklch(.922 0 0)' }, children: jsxs(CardContent, { className: "p-5 space-y-3", children: [jsx("h4", { className: "text-sm font-medium text-gray-700 dark:text-gray-300", children: t('purchasesPurchasesTab.cancelSectionHeading') }), jsx("p", { className: "text-xs text-gray-500", children: t('purchasesPurchasesTab.cancelSectionDescription') }), jsxs("div", { className: "flex gap-2 items-end", children: [jsxs("div", { className: "flex-1", children: [jsxs("label", { className: "text-xs text-gray-500 mb-1 block", children: [t('purchasesPurchasesTab.cancelConfirmLabelPrefix'), ' ', jsx("span", { className: "font-mono font-bold", children: "cancel" }), ' ', t('purchasesPurchasesTab.cancelConfirmLabelSuffix')] }), jsx(Input, { value: confirmText, onChange: (e) => setConfirmText(e.target.value), placeholder: t('purchasesPurchasesTab.cancelConfirmPlaceholder') })] }), jsxs(Button$1, { onClick: handleCancel, disabled: confirmText !== 'cancel' || isCanceling, className: "bg-gradient-to-r from-[#2563EB] to-[#93C5FD] hover:opacity-90 text-white cursor-pointer", children: [isCanceling ? (jsx(LoaderCircle, { className: "h-4 w-4 mr-2 animate-spin" })) : (jsx(CircleX, { className: "h-4 w-4 mr-2" })), t('purchasesPurchasesTab.cancelButton')] })] })] }) })), (cancelResult === null || cancelResult === void 0 ? void 0 : cancelResult.canceled) && (jsx(Card, { className: "shadow-sm border border-green-200", style: { borderColor: 'oklch(.922 0 0)' }, children: jsxs(CardContent, { className: "p-5 text-center", children: [jsx(CircleX, { className: "h-8 w-8 text-gray-400 mx-auto mb-2" }), jsx("h4", { className: "text-sm font-semibold text-gray-900 dark:text-gray-100 mb-1", children: t('purchasesPurchasesTab.canceledHeading') }), jsx("p", { className: "text-xs text-gray-500", children: t('purchasesPurchasesTab.canceledDescription') }), jsx(Button$1, { variant: "outline", size: "icon", onClick: onBack, "aria-label": t('purchasesPurchasesTab.backToPurchases'), className: "mt-3 h-8 w-8 cursor-pointer rounded-full border-0 bg-gray-100 text-gray-700 hover:bg-gray-200 hover:text-gray-900 dark:bg-gray-800 dark:text-gray-200 dark:hover:bg-gray-700 dark:hover:text-white", children: jsx(ArrowLeft, { className: "h-4 w-4" }) })] }) })), (cancelResult === null || cancelResult === void 0 ? void 0 : cancelResult.portalUrl) && (jsx(Card, { className: "shadow-sm border border-blue-200", style: { borderColor: 'oklch(.922 0 0)' }, children: jsxs(CardContent, { className: "p-5 text-center", children: [jsx(ExternalLink, { className: "h-8 w-8 text-blue-400 mx-auto mb-2" }), jsx("h4", { className: "text-sm font-semibold text-gray-900 dark:text-gray-100 mb-1", children: t('purchasesPurchasesTab.stripePortalHeading') }), jsx("p", { className: "text-xs text-gray-500 mb-3", children: t('purchasesPurchasesTab.stripePortalDescription') }), jsxs(Button$1, { onClick: () => window.open(cancelResult.portalUrl, '_blank'), className: "bg-gradient-to-r from-[#2563EB] to-[#93C5FD] hover:opacity-90 text-white cursor-pointer", children: [jsx(ExternalLink, { className: "h-4 w-4 mr-2" }), t('purchasesPurchasesTab.openStripePortal')] })] }) }))] }));
|
|
154641
|
+
: t('purchasesPurchasesTab.labelRenewsOn') }), jsxs("span", { className: "text-sm text-gray-600 dark:text-gray-400 flex items-center gap-1.5", children: [jsx(Calendar$1, { className: "h-3.5 w-3.5" }), new Date(subscription.current_period_end).toLocaleDateString()] })] })), subscription.created_at && (jsxs("div", { className: "flex items-center justify-between border-t pt-3", children: [jsx("span", { className: "text-sm font-medium text-gray-700 dark:text-gray-300", children: t('purchasesPurchasesTab.labelSubscribedSince') }), jsxs("span", { className: "text-sm text-gray-600 dark:text-gray-400 flex items-center gap-1.5", children: [jsx(Clock, { className: "h-3.5 w-3.5" }), new Date(subscription.created_at).toLocaleDateString()] })] })), subscription.is_grandfathered && (jsxs("div", { className: "flex items-center justify-between border-t pt-3", children: [jsx("span", { className: "text-sm font-medium text-gray-700 dark:text-gray-300", children: t('purchasesPurchasesTab.labelLegacyAccess') }), jsxs(Badge, { className: "bg-amber-100 text-amber-700 border-amber-200 text-xs", children: [jsx(Shield, { className: "h-3 w-3 mr-1" }), t('purchasesPurchasesTab.badgeGrandfathered')] })] })), subscription.cancel_at_period_end && (jsxs("div", { className: "flex items-center gap-2 border-t pt-3 text-yellow-600", children: [jsx(TriangleAlert, { className: "h-4 w-4 flex-shrink-0" }), jsx("span", { className: "text-sm", children: t('purchasesPurchasesTab.warningWillNotRenew') })] }))] }) }), canCancel && !cancelResult && (jsx(Card$1, { className: "shadow-sm border border-blue-100", style: { borderColor: 'oklch(.922 0 0)' }, children: jsxs(CardContent, { className: "p-5 space-y-3", children: [jsx("h4", { className: "text-sm font-medium text-gray-700 dark:text-gray-300", children: t('purchasesPurchasesTab.cancelSectionHeading') }), jsx("p", { className: "text-xs text-gray-500", children: t('purchasesPurchasesTab.cancelSectionDescription') }), jsxs("div", { className: "flex gap-2 items-end", children: [jsxs("div", { className: "flex-1", children: [jsxs("label", { className: "text-xs text-gray-500 mb-1 block", children: [t('purchasesPurchasesTab.cancelConfirmLabelPrefix'), ' ', jsx("span", { className: "font-mono font-bold", children: "cancel" }), ' ', t('purchasesPurchasesTab.cancelConfirmLabelSuffix')] }), jsx(Input, { value: confirmText, onChange: (e) => setConfirmText(e.target.value), placeholder: t('purchasesPurchasesTab.cancelConfirmPlaceholder') })] }), jsxs(Button$1, { onClick: handleCancel, disabled: confirmText !== 'cancel' || isCanceling, className: "bg-gradient-to-r from-[#2563EB] to-[#93C5FD] hover:opacity-90 text-white cursor-pointer", children: [isCanceling ? (jsx(LoaderCircle, { className: "h-4 w-4 mr-2 animate-spin" })) : (jsx(CircleX, { className: "h-4 w-4 mr-2" })), t('purchasesPurchasesTab.cancelButton')] })] })] }) })), (cancelResult === null || cancelResult === void 0 ? void 0 : cancelResult.canceled) && (jsx(Card$1, { className: "shadow-sm border border-green-200", style: { borderColor: 'oklch(.922 0 0)' }, children: jsxs(CardContent, { className: "p-5 text-center", children: [jsx(CircleX, { className: "h-8 w-8 text-gray-400 mx-auto mb-2" }), jsx("h4", { className: "text-sm font-semibold text-gray-900 dark:text-gray-100 mb-1", children: t('purchasesPurchasesTab.canceledHeading') }), jsx("p", { className: "text-xs text-gray-500", children: t('purchasesPurchasesTab.canceledDescription') }), jsx(Button$1, { variant: "outline", size: "icon", onClick: onBack, "aria-label": t('purchasesPurchasesTab.backToPurchases'), className: "mt-3 h-8 w-8 cursor-pointer rounded-full border-0 bg-gray-100 text-gray-700 hover:bg-gray-200 hover:text-gray-900 dark:bg-gray-800 dark:text-gray-200 dark:hover:bg-gray-700 dark:hover:text-white", children: jsx(ArrowLeft, { className: "h-4 w-4" }) })] }) })), (cancelResult === null || cancelResult === void 0 ? void 0 : cancelResult.portalUrl) && (jsx(Card$1, { className: "shadow-sm border border-blue-200", style: { borderColor: 'oklch(.922 0 0)' }, children: jsxs(CardContent, { className: "p-5 text-center", children: [jsx(ExternalLink, { className: "h-8 w-8 text-blue-400 mx-auto mb-2" }), jsx("h4", { className: "text-sm font-semibold text-gray-900 dark:text-gray-100 mb-1", children: t('purchasesPurchasesTab.stripePortalHeading') }), jsx("p", { className: "text-xs text-gray-500 mb-3", children: t('purchasesPurchasesTab.stripePortalDescription') }), jsxs(Button$1, { onClick: () => window.open(cancelResult.portalUrl, '_blank'), className: "bg-gradient-to-r from-[#2563EB] to-[#93C5FD] hover:opacity-90 text-white cursor-pointer", children: [jsx(ExternalLink, { className: "h-4 w-4 mr-2" }), t('purchasesPurchasesTab.openStripePortal')] })] }) }))] }));
|
|
154150
154642
|
}
|
|
154151
154643
|
// ── Subscription Card (List Item) ──
|
|
154152
154644
|
function SubscriptionCard({ sub, onClick }) {
|
|
154153
154645
|
var _a, _b, _c, _d, _e, _f, _g;
|
|
154154
154646
|
const t = useT();
|
|
154155
|
-
return (jsx(Card, { className: "shadow-sm border hover:border-blue-200 transition-colors cursor-pointer", style: { borderColor: 'oklch(.922 0 0)' }, onClick: onClick, children: jsx(CardContent, { className: "p-4", children: jsxs("div", { className: "flex items-start justify-between", children: [jsxs("div", { className: "flex-1 min-w-0", children: [jsxs("div", { className: "flex items-center gap-2 mb-1", children: [jsx("h4", { className: "text-sm font-semibold text-gray-900 dark:text-gray-100 truncate", children: sub.item_name || sub.item_id }), jsx(Badge, { variant: "secondary", className: "text-xs capitalize flex-shrink-0", children: sub.item_type })] }), jsxs("div", { className: "flex items-center gap-2 text-sm text-gray-600", children: [jsx(CreditCard, { className: "h-3.5 w-3.5 text-gray-400" }), jsxs("span", { children: [(_a = sub.price) === null || _a === void 0 ? void 0 : _a.name, " \u2014", ' ', jsxs("span", { className: "font-semibold", children: [formatCurrency((_b = sub.price) === null || _b === void 0 ? void 0 : _b.amount, (_c = sub.price) === null || _c === void 0 ? void 0 : _c.currency), ((_d = sub.price) === null || _d === void 0 ? void 0 : _d.interval) === 'month'
|
|
154647
|
+
return (jsx(Card$1, { className: "shadow-sm border hover:border-blue-200 transition-colors cursor-pointer", style: { borderColor: 'oklch(.922 0 0)' }, onClick: onClick, children: jsx(CardContent, { className: "p-4", children: jsxs("div", { className: "flex items-start justify-between", children: [jsxs("div", { className: "flex-1 min-w-0", children: [jsxs("div", { className: "flex items-center gap-2 mb-1", children: [jsx("h4", { className: "text-sm font-semibold text-gray-900 dark:text-gray-100 truncate", children: sub.item_name || sub.item_id }), jsx(Badge, { variant: "secondary", className: "text-xs capitalize flex-shrink-0", children: sub.item_type })] }), jsxs("div", { className: "flex items-center gap-2 text-sm text-gray-600", children: [jsx(CreditCard, { className: "h-3.5 w-3.5 text-gray-400" }), jsxs("span", { children: [(_a = sub.price) === null || _a === void 0 ? void 0 : _a.name, " \u2014", ' ', jsxs("span", { className: "font-semibold", children: [formatCurrency((_b = sub.price) === null || _b === void 0 ? void 0 : _b.amount, (_c = sub.price) === null || _c === void 0 ? void 0 : _c.currency), ((_d = sub.price) === null || _d === void 0 ? void 0 : _d.interval) === 'month'
|
|
154156
154648
|
? t('purchasesPurchasesTab.intervalMonth')
|
|
154157
154649
|
: ((_e = sub.price) === null || _e === void 0 ? void 0 : _e.interval) === 'year'
|
|
154158
154650
|
? t('purchasesPurchasesTab.intervalYear')
|
|
@@ -154189,7 +154681,7 @@ function PurchasesTab({ org, username }) {
|
|
|
154189
154681
|
refetch();
|
|
154190
154682
|
} }));
|
|
154191
154683
|
}
|
|
154192
|
-
return (jsxs("div", { className: "space-y-4", children: [jsxs("div", { className: "relative", 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('purchasesPurchasesTab.searchPlaceholder'), className: "pl-9" }), isFetching && !isLoading && (jsx(LoaderCircle, { className: "absolute right-3 top-1/2 -translate-y-1/2 h-4 w-4 animate-spin text-gray-400" }))] }), jsxs("div", { className: "flex flex-col sm:flex-row gap-2", children: [jsxs(Select$1, { value: statusFilter, onValueChange: setStatusFilter, children: [jsx(SelectTrigger, { className: "w-full sm:w-[160px]", children: jsx(SelectValue, { placeholder: t('purchasesPurchasesTab.filterStatusPlaceholder') }) }), jsxs(SelectContent, { children: [jsx(SelectItem, { value: "all", children: t('purchasesPurchasesTab.filterAllStatuses') }), jsx(SelectItem, { value: "active", children: t('purchasesPurchasesTab.filterActive') }), jsx(SelectItem, { value: "trialing", children: t('purchasesPurchasesTab.filterTrialing') }), jsx(SelectItem, { value: "canceled", children: t('purchasesPurchasesTab.filterCanceled') }), jsx(SelectItem, { value: "past_due", children: t('purchasesPurchasesTab.filterPastDue') })] })] }), jsxs(Select$1, { value: typeFilter, onValueChange: setTypeFilter, children: [jsx(SelectTrigger, { className: "w-full sm:w-[160px]", children: jsx(SelectValue, { placeholder: t('purchasesPurchasesTab.filterTypePlaceholder') }) }), jsxs(SelectContent, { children: [jsx(SelectItem, { value: "all", children: t('purchasesPurchasesTab.filterAllTypes') }), jsx(SelectItem, { value: "mentor", children: t('purchasesPurchasesTab.filterAgent') }), jsx(SelectItem, { value: "course", children: t('purchasesPurchasesTab.filterCourse') }), jsx(SelectItem, { value: "program", children: t('purchasesPurchasesTab.filterProgram') }), jsx(SelectItem, { value: "pathway", children: t('purchasesPurchasesTab.filterPathway') })] })] }), data && (jsx("span", { className: "text-xs text-gray-400 self-center ml-auto", children: t('purchasesPurchasesTab.purchaseCount', { count: data.count }) }))] }), isLoading ? (jsx("div", { className: "space-y-2", children: [1, 2, 3].map((i) => (jsx(Skeleton, { className: "h-24 w-full" }, i))) })) : (data === null || data === void 0 ? void 0 : data.results) && data.results.length > 0 ? (jsxs(Fragment$1, { children: [jsx("div", { className: "space-y-2", children: data.results.map((sub) => (jsx(SubscriptionCard, { sub: sub, onClick: () => setSelectedSubscription(sub) }, sub.unique_id))) }), (data.previous_page !== null || data.next_page !== null) && (jsxs("div", { className: "flex items-center justify-between pt-2", children: [jsx("span", { className: "text-xs text-gray-400", children: t('purchasesPurchasesTab.paginationTotal', { count: data.count }) }), jsxs("div", { className: "flex items-center gap-2", children: [jsx(Button$1, { variant: "outline", size: "sm", disabled: data.previous_page === null, onClick: () => data.previous_page !== null && setPage(data.previous_page), className: "h-7 text-xs cursor-pointer", children: t('purchasesPurchasesTab.previousPage') }), jsx("span", { className: "text-xs text-gray-500", children: t('purchasesPurchasesTab.pageIndicator', { page }) }), jsx(Button$1, { variant: "outline", size: "sm", disabled: data.next_page === null, onClick: () => data.next_page !== null && setPage(data.next_page), className: "h-7 text-xs cursor-pointer", children: t('purchasesPurchasesTab.nextPage') })] })] }))] })) : (jsx(Card, { className: "shadow-sm border border-dashed", style: { borderColor: 'oklch(.922 0 0)' }, children: jsxs(CardContent, { className: "p-8 text-center", children: [jsx(ShoppingBag, { className: "h-10 w-10 mx-auto text-gray-300 mb-3" }), jsx("p", { className: "text-sm text-gray-400", children: debouncedSearch.trim()
|
|
154684
|
+
return (jsxs("div", { className: "space-y-4", children: [jsxs("div", { className: "relative", 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('purchasesPurchasesTab.searchPlaceholder'), className: "pl-9" }), isFetching && !isLoading && (jsx(LoaderCircle, { className: "absolute right-3 top-1/2 -translate-y-1/2 h-4 w-4 animate-spin text-gray-400" }))] }), jsxs("div", { className: "flex flex-col sm:flex-row gap-2", children: [jsxs(Select$1, { value: statusFilter, onValueChange: setStatusFilter, children: [jsx(SelectTrigger, { className: "w-full sm:w-[160px]", children: jsx(SelectValue, { placeholder: t('purchasesPurchasesTab.filterStatusPlaceholder') }) }), jsxs(SelectContent, { children: [jsx(SelectItem, { value: "all", children: t('purchasesPurchasesTab.filterAllStatuses') }), jsx(SelectItem, { value: "active", children: t('purchasesPurchasesTab.filterActive') }), jsx(SelectItem, { value: "trialing", children: t('purchasesPurchasesTab.filterTrialing') }), jsx(SelectItem, { value: "canceled", children: t('purchasesPurchasesTab.filterCanceled') }), jsx(SelectItem, { value: "past_due", children: t('purchasesPurchasesTab.filterPastDue') })] })] }), jsxs(Select$1, { value: typeFilter, onValueChange: setTypeFilter, children: [jsx(SelectTrigger, { className: "w-full sm:w-[160px]", children: jsx(SelectValue, { placeholder: t('purchasesPurchasesTab.filterTypePlaceholder') }) }), jsxs(SelectContent, { children: [jsx(SelectItem, { value: "all", children: t('purchasesPurchasesTab.filterAllTypes') }), jsx(SelectItem, { value: "mentor", children: t('purchasesPurchasesTab.filterAgent') }), jsx(SelectItem, { value: "course", children: t('purchasesPurchasesTab.filterCourse') }), jsx(SelectItem, { value: "program", children: t('purchasesPurchasesTab.filterProgram') }), jsx(SelectItem, { value: "pathway", children: t('purchasesPurchasesTab.filterPathway') })] })] }), data && (jsx("span", { className: "text-xs text-gray-400 self-center ml-auto", children: t('purchasesPurchasesTab.purchaseCount', { count: data.count }) }))] }), isLoading ? (jsx("div", { className: "space-y-2", children: [1, 2, 3].map((i) => (jsx(Skeleton, { className: "h-24 w-full" }, i))) })) : (data === null || data === void 0 ? void 0 : data.results) && data.results.length > 0 ? (jsxs(Fragment$1, { children: [jsx("div", { className: "space-y-2", children: data.results.map((sub) => (jsx(SubscriptionCard, { sub: sub, onClick: () => setSelectedSubscription(sub) }, sub.unique_id))) }), (data.previous_page !== null || data.next_page !== null) && (jsxs("div", { className: "flex items-center justify-between pt-2", children: [jsx("span", { className: "text-xs text-gray-400", children: t('purchasesPurchasesTab.paginationTotal', { count: data.count }) }), jsxs("div", { className: "flex items-center gap-2", children: [jsx(Button$1, { variant: "outline", size: "sm", disabled: data.previous_page === null, onClick: () => data.previous_page !== null && setPage(data.previous_page), className: "h-7 text-xs cursor-pointer", children: t('purchasesPurchasesTab.previousPage') }), jsx("span", { className: "text-xs text-gray-500", children: t('purchasesPurchasesTab.pageIndicator', { page }) }), jsx(Button$1, { variant: "outline", size: "sm", disabled: data.next_page === null, onClick: () => data.next_page !== null && setPage(data.next_page), className: "h-7 text-xs cursor-pointer", children: t('purchasesPurchasesTab.nextPage') })] })] }))] })) : (jsx(Card$1, { className: "shadow-sm border border-dashed", style: { borderColor: 'oklch(.922 0 0)' }, children: jsxs(CardContent, { className: "p-8 text-center", children: [jsx(ShoppingBag, { className: "h-10 w-10 mx-auto text-gray-300 mb-3" }), jsx("p", { className: "text-sm text-gray-400", children: debouncedSearch.trim()
|
|
154193
154685
|
? t('purchasesPurchasesTab.emptySearchResult')
|
|
154194
154686
|
: t('purchasesPurchasesTab.emptyNoPurchases') })] }) }))] }));
|
|
154195
154687
|
}
|
|
@@ -165098,7 +165590,7 @@ function formatLocale(locale) {
|
|
|
165098
165590
|
"q": formatQuarter,
|
|
165099
165591
|
"Q": formatUnixTimestamp,
|
|
165100
165592
|
"s": formatUnixTimestampSeconds,
|
|
165101
|
-
"S": formatSeconds,
|
|
165593
|
+
"S": formatSeconds$1,
|
|
165102
165594
|
"u": formatWeekdayNumberMonday,
|
|
165103
165595
|
"U": formatWeekNumberSunday,
|
|
165104
165596
|
"V": formatWeekNumberISO,
|
|
@@ -165564,7 +166056,7 @@ function formatMinutes(d, p) {
|
|
|
165564
166056
|
return pad$1(d.getMinutes(), p, 2);
|
|
165565
166057
|
}
|
|
165566
166058
|
|
|
165567
|
-
function formatSeconds(d, p) {
|
|
166059
|
+
function formatSeconds$1(d, p) {
|
|
165568
166060
|
return pad$1(d.getSeconds(), p, 2);
|
|
165569
166061
|
}
|
|
165570
166062
|
|
|
@@ -173316,7 +173808,7 @@ var objectCtorString = funcToString.call(Object);
|
|
|
173316
173808
|
* _.isPlainObject(Object.create(null));
|
|
173317
173809
|
* // => true
|
|
173318
173810
|
*/
|
|
173319
|
-
function isPlainObject$
|
|
173811
|
+
function isPlainObject$3(value) {
|
|
173320
173812
|
if (!isObjectLike$1(value) || baseGetTag$1(value) != objectTag) {
|
|
173321
173813
|
return false;
|
|
173322
173814
|
}
|
|
@@ -173329,9 +173821,9 @@ function isPlainObject$2(value) {
|
|
|
173329
173821
|
funcToString.call(Ctor) == objectCtorString;
|
|
173330
173822
|
}
|
|
173331
173823
|
|
|
173332
|
-
var isPlainObject_1 = isPlainObject$
|
|
173824
|
+
var isPlainObject_1 = isPlainObject$3;
|
|
173333
173825
|
|
|
173334
|
-
var isPlainObject$
|
|
173826
|
+
var isPlainObject$2 = /*@__PURE__*/getDefaultExportFromCjs(isPlainObject_1);
|
|
173335
173827
|
|
|
173336
173828
|
var baseGetTag = _baseGetTag,
|
|
173337
173829
|
isObjectLike = isObjectLike_1;
|
|
@@ -173548,7 +174040,7 @@ function Shape(_ref2) {
|
|
|
173548
174040
|
shape = /*#__PURE__*/cloneElement(option, _objectSpread$e(_objectSpread$e({}, props), getPropsFromShapeOption(option)));
|
|
173549
174041
|
} else if (isFunction$3(option)) {
|
|
173550
174042
|
shape = option(props);
|
|
173551
|
-
} else if (isPlainObject$
|
|
174043
|
+
} else if (isPlainObject$2(option) && !isBoolean(option)) {
|
|
173552
174044
|
var nextProps = propTransformer(option, props);
|
|
173553
174045
|
shape = /*#__PURE__*/React__default.createElement(ShapeSelector, {
|
|
173554
174046
|
shapeType: shapeType,
|
|
@@ -178833,7 +179325,7 @@ function useGradebookData(type, org, username, page, search) {
|
|
|
178833
179325
|
page,
|
|
178834
179326
|
page_size: PAGE_SIZE$e,
|
|
178835
179327
|
platform_key: org,
|
|
178836
|
-
...(trimmed ? {
|
|
179328
|
+
...(trimmed ? { course_name: trimmed } : {}),
|
|
178837
179329
|
},
|
|
178838
179330
|
}, { skip: type !== 'courses', refetchOnMountOrArgChange: true });
|
|
178839
179331
|
const programsQ = useGetUserEnrolledProgramsQuery([{ username, platformKey: org }], { skip: type !== 'programs' });
|
|
@@ -178984,7 +179476,7 @@ function GradebookCard({ row, icon: Icon, onClick, }) {
|
|
|
178984
179476
|
var _a;
|
|
178985
179477
|
const t = useT();
|
|
178986
179478
|
const clickable = !!onClick;
|
|
178987
|
-
return (jsx(Card, { className: cn('shadow-sm border transition-colors', clickable && 'hover:border-blue-200 cursor-pointer'), style: { borderColor: 'oklch(.922 0 0)' }, onClick: onClick, role: clickable ? 'button' : undefined, tabIndex: clickable ? 0 : undefined, onKeyDown: clickable
|
|
179479
|
+
return (jsx(Card$1, { className: cn('shadow-sm border transition-colors', clickable && 'hover:border-blue-200 cursor-pointer'), style: { borderColor: 'oklch(.922 0 0)' }, onClick: onClick, role: clickable ? 'button' : undefined, tabIndex: clickable ? 0 : undefined, onKeyDown: clickable
|
|
178988
179480
|
? (e) => {
|
|
178989
179481
|
if (e.key === 'Enter' || e.key === ' ') {
|
|
178990
179482
|
e.preventDefault();
|
|
@@ -218053,6 +218545,100 @@ function Markdown({ children, className }) {
|
|
|
218053
218545
|
return (jsx("div", { className: className, children: jsx(Markdown$1, { components: components, children: children }) }));
|
|
218054
218546
|
}
|
|
218055
218547
|
|
|
218548
|
+
function FileCard({ fileName, fileType }) {
|
|
218549
|
+
const getFileIcon = (fileName, fileType) => {
|
|
218550
|
+
const type = fileType.toLowerCase();
|
|
218551
|
+
const name = fileName.toLowerCase();
|
|
218552
|
+
const extension = name.split('.').pop() || '';
|
|
218553
|
+
// Check by MIME type first
|
|
218554
|
+
if (type.includes('pdf')) {
|
|
218555
|
+
return jsx(File$1, { className: "h-5 w-5 text-blue-500" });
|
|
218556
|
+
}
|
|
218557
|
+
else if (type.includes('image')) {
|
|
218558
|
+
return jsx(FileImage, { className: "h-5 w-5 text-blue-500" });
|
|
218559
|
+
}
|
|
218560
|
+
else if (type.includes('audio')) {
|
|
218561
|
+
return jsx(FileAudio, { className: "h-5 w-5 text-blue-500" });
|
|
218562
|
+
}
|
|
218563
|
+
else if (type.includes('video')) {
|
|
218564
|
+
return jsx(FilePlay, { className: "h-5 w-5 text-blue-500" });
|
|
218565
|
+
}
|
|
218566
|
+
else if (type.includes('spreadsheet') || type.includes('excel') || type.includes('csv')) {
|
|
218567
|
+
return jsx(FileSpreadsheet, { className: "h-5 w-5 text-blue-500" });
|
|
218568
|
+
}
|
|
218569
|
+
else if (type.includes('zip') || type.includes('compressed') || type.includes('archive')) {
|
|
218570
|
+
return jsx(FileArchive, { className: "h-5 w-5 text-blue-500" });
|
|
218571
|
+
}
|
|
218572
|
+
else if (type.includes('javascript') ||
|
|
218573
|
+
type.includes('typescript') ||
|
|
218574
|
+
type.includes('html') ||
|
|
218575
|
+
type.includes('css') ||
|
|
218576
|
+
type.includes('json')) {
|
|
218577
|
+
return jsx(FileCode, { className: "h-5 w-5 text-blue-500" });
|
|
218578
|
+
}
|
|
218579
|
+
// If MIME type doesn't match, check by extension
|
|
218580
|
+
if (['doc', 'docx', 'txt', 'rtf'].includes(extension)) {
|
|
218581
|
+
return jsx(FileText, { className: "h-5 w-5 text-blue-500" });
|
|
218582
|
+
}
|
|
218583
|
+
else if (['jpg', 'jpeg', 'png', 'gif', 'svg', 'webp'].includes(extension)) {
|
|
218584
|
+
return jsx(FileImage, { className: "h-5 w-5 text-blue-500" });
|
|
218585
|
+
}
|
|
218586
|
+
else if (['pdf'].includes(extension)) {
|
|
218587
|
+
return jsx(File$1, { className: "h-5 w-5 text-blue-500" });
|
|
218588
|
+
}
|
|
218589
|
+
else if (['mp3', 'wav', 'ogg', 'flac'].includes(extension)) {
|
|
218590
|
+
return jsx(FileAudio, { className: "h-5 w-5 text-blue-500" });
|
|
218591
|
+
}
|
|
218592
|
+
else if (['mp4', 'webm', 'avi', 'mov'].includes(extension)) {
|
|
218593
|
+
return jsx(FilePlay, { className: "h-5 w-5 text-blue-500" });
|
|
218594
|
+
}
|
|
218595
|
+
else if (['xls', 'xlsx', 'csv'].includes(extension)) {
|
|
218596
|
+
return jsx(FileSpreadsheet, { className: "h-5 w-5 text-blue-500" });
|
|
218597
|
+
}
|
|
218598
|
+
else if (['zip', 'rar', '7z', 'tar', 'gz'].includes(extension)) {
|
|
218599
|
+
return jsx(FileArchive, { className: "h-5 w-5 text-blue-500" });
|
|
218600
|
+
}
|
|
218601
|
+
else if (['js', 'ts', 'jsx', 'tsx', 'html', 'css', 'json', 'py', 'java', 'c', 'cpp'].includes(extension)) {
|
|
218602
|
+
return jsx(FileCode, { className: "h-5 w-5 text-blue-500" });
|
|
218603
|
+
}
|
|
218604
|
+
// Default icon
|
|
218605
|
+
return jsx(File$1, { className: "h-5 w-5 text-blue-500" });
|
|
218606
|
+
};
|
|
218607
|
+
return (jsxs("div", { className: "mb-2 flex max-w-xs items-center rounded-lg border border-gray-200 bg-white p-3", children: [jsx("div", { className: "mr-3 shrink-0 rounded-lg bg-blue-100 p-2 text-blue-600", children: getFileIcon(fileName, fileType) }), jsxs("div", { className: "min-w-0 flex-1", children: [jsx("h3", { className: "truncate text-sm font-medium text-gray-900", children: fileName }), jsx("p", { className: "truncate text-xs text-gray-500", children: fileType })] })] }));
|
|
218608
|
+
}
|
|
218609
|
+
|
|
218610
|
+
function ImageMessage({ url, fileName, setPreviewImage }) {
|
|
218611
|
+
const [hasError, setHasError] = useState(false);
|
|
218612
|
+
if (hasError || !url) {
|
|
218613
|
+
return jsx(FileCard, { fileName: fileName, fileType: "image/*" });
|
|
218614
|
+
}
|
|
218615
|
+
return (jsx("div", { className: "h-full max-h-64 w-full max-w-96 overflow-hidden rounded-lg", children: jsx("div", { className: "relative", children: jsx("img", { src: url, alt: fileName, className: "h-auto w-full cursor-pointer object-contain p-2", onClick: () => setPreviewImage(url), onError: () => setHasError(true) }) }) }));
|
|
218616
|
+
}
|
|
218617
|
+
|
|
218618
|
+
const openInNewTab = (url) => {
|
|
218619
|
+
window.open(url, '_blank', 'noopener,noreferrer');
|
|
218620
|
+
};
|
|
218621
|
+
/**
|
|
218622
|
+
* Files on an admin transcript, in the chat's own attachment idiom: images
|
|
218623
|
+
* preview like a sent image, everything else is the chat's file card. A card
|
|
218624
|
+
* with a URL opens the file in a new tab (presigned links expire, so nothing
|
|
218625
|
+
* is cached here).
|
|
218626
|
+
*/
|
|
218627
|
+
function TranscriptFileCards({ files, className, }) {
|
|
218628
|
+
const shown = files.filter((file) => file === null || file === void 0 ? void 0 : file.name);
|
|
218629
|
+
if (shown.length === 0)
|
|
218630
|
+
return null;
|
|
218631
|
+
return (jsx("div", { className: className !== null && className !== void 0 ? className : 'mt-2 flex flex-wrap items-start gap-2', "data-testid": "transcript-file-cards", children: shown.map((file, index) => {
|
|
218632
|
+
var _a;
|
|
218633
|
+
const contentType = (_a = file.contentType) !== null && _a !== void 0 ? _a : '';
|
|
218634
|
+
if (file.url && contentType.startsWith('image/')) {
|
|
218635
|
+
return (jsx(ImageMessage, { url: file.url, fileName: file.name, setPreviewImage: openInNewTab }, `${file.name}-${index}`));
|
|
218636
|
+
}
|
|
218637
|
+
const card = jsx(FileCard, { fileName: file.name, fileType: contentType || 'file' });
|
|
218638
|
+
return file.url ? (jsx("a", { href: file.url, target: "_blank", rel: "noopener noreferrer", className: "block hover:opacity-90", "aria-label": `Open ${file.name}`, onClick: (event) => event.stopPropagation(), children: card }, `${file.name}-${index}`)) : (jsx("div", { children: card }, `${file.name}-${index}`));
|
|
218639
|
+
}) }));
|
|
218640
|
+
}
|
|
218641
|
+
|
|
218056
218642
|
/**
|
|
218057
218643
|
* Whether the dropdown is open, closing on a pointer press outside `ref` or on
|
|
218058
218644
|
* Escape.
|
|
@@ -218696,8 +219282,12 @@ function ConversationMessages({ messages, username, agent, fallbackEmail, }) {
|
|
|
218696
219282
|
? (userMetadata === null || userMetadata === void 0 ? void 0 : userMetadata.email) || fallbackEmail || username
|
|
218697
219283
|
: t('chatHistoryChatHistoryTab.you');
|
|
218698
219284
|
return (jsx("div", { className: "space-y-6", children: messages.map((message, index) => {
|
|
218699
|
-
var _a, _b;
|
|
218700
|
-
return (jsxs("div", { className: "space-y-4", children: [jsxs("div", { className: "flex items-start gap-3", children: [jsx(UserMessageAvatar, { username: username }), jsxs("div", { className: "min-w-0 flex-1 overflow-x-hidden", children: [jsx("div", { className: "font-medium break-all text-gray-700", children: humanLabel }), jsx(Markdown, { className: "mt-1 text-sm text-gray-500", children: (_a = message.human) !== null && _a !== void 0 ? _a : '' })
|
|
219285
|
+
var _a, _b, _c;
|
|
219286
|
+
return (jsxs("div", { className: "space-y-4", children: [jsxs("div", { className: "flex items-start gap-3", children: [jsx(UserMessageAvatar, { username: username }), jsxs("div", { className: "min-w-0 flex-1 overflow-x-hidden", children: [jsx("div", { className: "font-medium break-all text-gray-700", children: humanLabel }), jsx(Markdown, { className: "mt-1 text-sm text-gray-500", children: (_a = message.human) !== null && _a !== void 0 ? _a : '' }), jsx(TranscriptFileCards, { files: ((_b = message.human_files) !== null && _b !== void 0 ? _b : []).map((file) => ({
|
|
219287
|
+
name: file.name,
|
|
219288
|
+
contentType: file.content_type,
|
|
219289
|
+
url: file.url,
|
|
219290
|
+
})) })] })] }), jsxs("div", { className: "flex items-start gap-3 border-t border-gray-200 pt-4", children: [jsx(AgentMessageAvatar, { agent: agent, fallback: t('chatHistoryChatHistoryTab.aiAvatarLabel') }), jsxs("div", { className: "min-w-0 flex-1 overflow-x-hidden", children: [jsx("div", { className: "font-medium text-gray-700", children: agent.name }), jsx(Markdown, { className: "mt-1 text-sm text-gray-500", children: (_c = message.ai) !== null && _c !== void 0 ? _c : '' })] })] })] }, index));
|
|
218701
219291
|
}) }));
|
|
218702
219292
|
}
|
|
218703
219293
|
/**
|
|
@@ -218802,6 +219392,607 @@ function ChatHistoryTab({ org, username }) {
|
|
|
218802
219392
|
: t('chatHistoryChatHistoryTab.conversation') }) }), jsx("div", { className: "mx-auto max-w-full overflow-x-hidden", children: selectedSession && (jsx(ConversationPreview, { org: org, username: username, session: selectedSession, agent: resolveAgent(selectedSession) })) })] }) })] }), jsx(TabsContent, { value: "exports", className: "mt-0 min-h-0 flex-1 overflow-y-auto data-[state=inactive]:hidden", children: jsx(ReportHistory, { org: org, username: username, onDownload: downloadFromUrl }) })] }));
|
|
218803
219393
|
}
|
|
218804
219394
|
|
|
219395
|
+
/**
|
|
219396
|
+
* The info icon that sits on every analytics card and, on hover or keyboard
|
|
219397
|
+
* focus, explains what the card measures. The description doubles as the
|
|
219398
|
+
* accessible name so screen readers get it without needing the hover.
|
|
219399
|
+
*
|
|
219400
|
+
* Uses the tooltip primitives directly rather than the shared `TooltipContent`
|
|
219401
|
+
* because analytics wants a light popover, while `TooltipContent` is the dark
|
|
219402
|
+
* `bg-primary` style the rest of the app relies on.
|
|
219403
|
+
*/
|
|
219404
|
+
function CardInfoIcon({ title, description, className }) {
|
|
219405
|
+
return (jsxs(Tooltip$1, { children: [jsx(TooltipTrigger, { asChild: true, children: jsx("button", { type: "button", "aria-label": description, className: cn('shrink-0 cursor-help rounded p-1 text-[#898989] transition-colors hover:bg-gray-100 hover:text-[#38A1E5] focus-visible:ring-2 focus-visible:ring-[#38A1E5] focus-visible:outline-none', className), children: jsx(Info$3, { className: "h-4 w-4", "aria-hidden": "true" }) }) }), jsx(Portal$2, { children: jsxs(Content2$3, { "data-slot": "tooltip-content", side: "top", align: "center", sideOffset: 6, collisionPadding: 12, className: "animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 z-50 max-w-[260px] rounded-lg border border-[oklch(0.922_0_0)] bg-white p-3 shadow-lg", children: [title && (jsx("div", { "data-slot": "tooltip-title", className: "mb-1 text-sm font-semibold text-[#484848]", children: title })), jsx("p", { "data-slot": "tooltip-description", className: "text-sm leading-relaxed text-[#646464]", children: description })] }) })] }));
|
|
219406
|
+
}
|
|
219407
|
+
|
|
219408
|
+
/**
|
|
219409
|
+
* Chart color system for the analytics surface.
|
|
219410
|
+
*
|
|
219411
|
+
* Single-series charts keep the app's established `#38A1E5`. Multi-series
|
|
219412
|
+
* charts (spend stacked by service, spend by model) use a categorical palette
|
|
219413
|
+
* validated for color-vision-deficiency separation on a white surface
|
|
219414
|
+
* (worst adjacent-pair CVD ΔE 9.1, worst normal-vision ΔE 19.6 — OKLab ×100):
|
|
219415
|
+
* hues are assigned in this fixed order, per entity, never cycled or reshuffled
|
|
219416
|
+
* when a filter changes the series count.
|
|
219417
|
+
*
|
|
219418
|
+
* Three of the light-surface slots sit below 3:1 contrast against white, so
|
|
219419
|
+
* every chart that uses them must carry visible direct labels or a table view
|
|
219420
|
+
* (all of ours do — ranked rows and legends carry the values as text).
|
|
219421
|
+
*/
|
|
219422
|
+
const CHART_SERIES_COLORS = [
|
|
219423
|
+
'#2a78d6', // blue
|
|
219424
|
+
'#eb6834', // orange
|
|
219425
|
+
'#1baf7a', // aqua
|
|
219426
|
+
'#eda100', // yellow
|
|
219427
|
+
'#e87ba4', // magenta
|
|
219428
|
+
'#008300', // green
|
|
219429
|
+
];
|
|
219430
|
+
/**
|
|
219431
|
+
* Color follows the entity: a service keeps its hue whether or not the other
|
|
219432
|
+
* services are on screen. Services beyond this list fold into slots in first-
|
|
219433
|
+
* seen order via {@link colorForSeries} rather than inventing new hues.
|
|
219434
|
+
*/
|
|
219435
|
+
const SERVICE_COLOR_ORDER = [
|
|
219436
|
+
'chat',
|
|
219437
|
+
'embeddings',
|
|
219438
|
+
'memory',
|
|
219439
|
+
'grading',
|
|
219440
|
+
'moderation',
|
|
219441
|
+
'call',
|
|
219442
|
+
];
|
|
219443
|
+
/**
|
|
219444
|
+
* Stable color for a named series. Known services get their fixed slot; an
|
|
219445
|
+
* unknown name hashes into the palette deterministically so the same name is
|
|
219446
|
+
* the same color on every render and every chart.
|
|
219447
|
+
*/
|
|
219448
|
+
function colorForSeries(name) {
|
|
219449
|
+
const fixed = SERVICE_COLOR_ORDER.indexOf(name);
|
|
219450
|
+
if (fixed >= 0)
|
|
219451
|
+
return CHART_SERIES_COLORS[fixed % CHART_SERIES_COLORS.length];
|
|
219452
|
+
let hash = 0;
|
|
219453
|
+
for (let i = 0; i < name.length; i++) {
|
|
219454
|
+
hash = (hash * 31 + name.charCodeAt(i)) >>> 0;
|
|
219455
|
+
}
|
|
219456
|
+
return CHART_SERIES_COLORS[hash % CHART_SERIES_COLORS.length];
|
|
219457
|
+
}
|
|
219458
|
+
|
|
219459
|
+
const LLM_USAGE_RANGES = ['today', '7d', '30d', '90d', 'all_time'];
|
|
219460
|
+
const DEFAULT_LLM_USAGE_RANGE = '30d';
|
|
219461
|
+
/** Buckets that keep the time axis readable for the chosen span. */
|
|
219462
|
+
function granularityForRange(range) {
|
|
219463
|
+
if (range === '90d')
|
|
219464
|
+
return 'week';
|
|
219465
|
+
if (range === 'all_time')
|
|
219466
|
+
return 'month';
|
|
219467
|
+
return 'day';
|
|
219468
|
+
}
|
|
219469
|
+
/** The next wider range, offered from the empty state. */
|
|
219470
|
+
function widerRange(range) {
|
|
219471
|
+
if (range === 'all_time')
|
|
219472
|
+
return null;
|
|
219473
|
+
if (range === '90d')
|
|
219474
|
+
return 'all_time';
|
|
219475
|
+
return '90d';
|
|
219476
|
+
}
|
|
219477
|
+
const DAY_MS = 86400000;
|
|
219478
|
+
const DAYS_IN_RANGE = { today: 1, '7d': 7, '30d': 30 };
|
|
219479
|
+
/**
|
|
219480
|
+
* Spend buckets for the chart. Daily ranges get every day of the window, with
|
|
219481
|
+
* zero where the backend sent no bucket (it omits empty days), so the axis is
|
|
219482
|
+
* continuous. Weekly and monthly ranges use the buckets as returned.
|
|
219483
|
+
*/
|
|
219484
|
+
function buildSpendSeries(points, range, now = new Date()) {
|
|
219485
|
+
var _a;
|
|
219486
|
+
const days = DAYS_IN_RANGE[range];
|
|
219487
|
+
if (!days || granularityForRange(range) !== 'day')
|
|
219488
|
+
return points;
|
|
219489
|
+
const byDate = new Map(points.map((point) => [point.date, point.totalCost]));
|
|
219490
|
+
const series = [];
|
|
219491
|
+
for (let offset = days - 1; offset >= 0; offset--) {
|
|
219492
|
+
const date = new Date(now.getTime() - offset * DAY_MS).toISOString().slice(0, 10);
|
|
219493
|
+
series.push({ date, totalCost: (_a = byDate.get(date)) !== null && _a !== void 0 ? _a : 0 });
|
|
219494
|
+
}
|
|
219495
|
+
return series;
|
|
219496
|
+
}
|
|
219497
|
+
/** Axis ceiling and ticks on a 1-2-5 step, so labels land on clean numbers. */
|
|
219498
|
+
function niceScale(max, tickCount = 4) {
|
|
219499
|
+
if (!Number.isFinite(max) || max <= 0)
|
|
219500
|
+
return { max: 1, ticks: [0, 0.25, 0.5, 0.75, 1] };
|
|
219501
|
+
const rough = max / tickCount;
|
|
219502
|
+
const magnitude = 10 ** Math.floor(Math.log10(rough));
|
|
219503
|
+
const residual = rough / magnitude;
|
|
219504
|
+
const step = (residual <= 1 ? 1 : residual <= 2 ? 2 : residual <= 5 ? 5 : 10) * magnitude;
|
|
219505
|
+
const top = Math.ceil(max / step - 1e-9) * step;
|
|
219506
|
+
const ticks = [];
|
|
219507
|
+
for (let value = 0; value <= top + step / 2; value += step) {
|
|
219508
|
+
ticks.push(Number(value.toPrecision(12)));
|
|
219509
|
+
}
|
|
219510
|
+
return { max: ticks[ticks.length - 1], ticks };
|
|
219511
|
+
}
|
|
219512
|
+
const usd = (fractionDigits) => new Intl.NumberFormat('en-US', {
|
|
219513
|
+
style: 'currency',
|
|
219514
|
+
currency: 'USD',
|
|
219515
|
+
minimumFractionDigits: fractionDigits,
|
|
219516
|
+
maximumFractionDigits: fractionDigits,
|
|
219517
|
+
});
|
|
219518
|
+
/**
|
|
219519
|
+
* Dollars with enough precision to be meaningful: small values keep four
|
|
219520
|
+
* decimals. `precise` keeps four decimals for anything under a dollar — for
|
|
219521
|
+
* per-request figures (a trace, a step, the average), where $0.0147 and
|
|
219522
|
+
* $0.0102 must not both read as $0.01.
|
|
219523
|
+
*/
|
|
219524
|
+
function formatCost(value, { precise = false } = {}) {
|
|
219525
|
+
if (value === null || value === undefined || !Number.isFinite(value))
|
|
219526
|
+
return '—';
|
|
219527
|
+
if (value === 0)
|
|
219528
|
+
return usd(2).format(0);
|
|
219529
|
+
const abs = Math.abs(value);
|
|
219530
|
+
if (abs < 0.0001)
|
|
219531
|
+
return `<${usd(4).format(0.0001)}`;
|
|
219532
|
+
if (abs < (precise ? 1 : 0.01))
|
|
219533
|
+
return usd(4).format(value);
|
|
219534
|
+
return usd(2).format(value);
|
|
219535
|
+
}
|
|
219536
|
+
/** Axis labels: whole dollars on big steps, cents (or finer) on small ones; zero is `$0`. */
|
|
219537
|
+
function formatAxisCost(value, step) {
|
|
219538
|
+
if (value === 0)
|
|
219539
|
+
return usd(0).format(0);
|
|
219540
|
+
const decimals = step >= 1 ? 0 : Math.min(4, Math.max(2, Math.ceil(-Math.log10(step))));
|
|
219541
|
+
return usd(decimals).format(value);
|
|
219542
|
+
}
|
|
219543
|
+
function formatCompact(value) {
|
|
219544
|
+
if (value === null || value === undefined || !Number.isFinite(value))
|
|
219545
|
+
return '—';
|
|
219546
|
+
return new Intl.NumberFormat('en-US', { notation: 'compact', maximumFractionDigits: 1 }).format(value);
|
|
219547
|
+
}
|
|
219548
|
+
function formatInteger(value) {
|
|
219549
|
+
if (value === null || value === undefined || !Number.isFinite(value))
|
|
219550
|
+
return '—';
|
|
219551
|
+
return Math.round(value).toLocaleString('en-US');
|
|
219552
|
+
}
|
|
219553
|
+
/** Trace and observation latency arrive in seconds. */
|
|
219554
|
+
function formatSeconds(value) {
|
|
219555
|
+
if (value === null || value === undefined || !Number.isFinite(value))
|
|
219556
|
+
return '—';
|
|
219557
|
+
return `${value < 10 ? value.toFixed(2) : value.toFixed(1)}s`;
|
|
219558
|
+
}
|
|
219559
|
+
/** `YYYY-MM-DD` bucket keys are UTC calendar dates. */
|
|
219560
|
+
function formatBucket(date, granularity) {
|
|
219561
|
+
const parsed = new Date(`${date.slice(0, 10)}T00:00:00Z`);
|
|
219562
|
+
if (Number.isNaN(parsed.getTime()))
|
|
219563
|
+
return date;
|
|
219564
|
+
return parsed.toLocaleDateString('en-US', granularity === 'month'
|
|
219565
|
+
? { month: 'short', year: 'numeric', timeZone: 'UTC' }
|
|
219566
|
+
: { month: 'short', day: 'numeric', timeZone: 'UTC' });
|
|
219567
|
+
}
|
|
219568
|
+
function formatWhen(iso) {
|
|
219569
|
+
if (!iso)
|
|
219570
|
+
return '—';
|
|
219571
|
+
const date = new Date(iso);
|
|
219572
|
+
if (Number.isNaN(date.getTime()))
|
|
219573
|
+
return '—';
|
|
219574
|
+
return date.toLocaleString('en-US', {
|
|
219575
|
+
month: 'short',
|
|
219576
|
+
day: 'numeric',
|
|
219577
|
+
hour: '2-digit',
|
|
219578
|
+
minute: '2-digit',
|
|
219579
|
+
});
|
|
219580
|
+
}
|
|
219581
|
+
/** `0feb37e6-d125-…-7c9ee0a252e7` → `0feb…52e7`; the full id stays in a title. */
|
|
219582
|
+
function shortId(id) {
|
|
219583
|
+
if (!id)
|
|
219584
|
+
return '—';
|
|
219585
|
+
return id.length > 12 ? `${id.slice(0, 4)}…${id.slice(-4)}` : id;
|
|
219586
|
+
}
|
|
219587
|
+
/**
|
|
219588
|
+
* Keeps the biggest rows and folds the rest into one "Other" row, so a long
|
|
219589
|
+
* tail never floods the card.
|
|
219590
|
+
*/
|
|
219591
|
+
function foldTail(rows, keep, otherLabel) {
|
|
219592
|
+
if (rows.length <= keep + 1)
|
|
219593
|
+
return rows;
|
|
219594
|
+
const head = rows.slice(0, keep);
|
|
219595
|
+
const tail = rows.slice(keep);
|
|
219596
|
+
return [
|
|
219597
|
+
...head,
|
|
219598
|
+
{
|
|
219599
|
+
key: '__other__',
|
|
219600
|
+
label: otherLabel,
|
|
219601
|
+
totalCost: tail.reduce((sum, row) => sum + row.totalCost, 0),
|
|
219602
|
+
count: tail.reduce((sum, row) => sum + row.count, 0),
|
|
219603
|
+
isOther: true,
|
|
219604
|
+
},
|
|
219605
|
+
];
|
|
219606
|
+
}
|
|
219607
|
+
/** Share of a total as a whole percent, keeping tiny non-zero shares visible. */
|
|
219608
|
+
function sharePercent(value, total) {
|
|
219609
|
+
if (!total || value <= 0)
|
|
219610
|
+
return 0;
|
|
219611
|
+
const pct = (value / total) * 100;
|
|
219612
|
+
return pct < 1 ? Math.round(pct * 10) / 10 : Math.round(pct);
|
|
219613
|
+
}
|
|
219614
|
+
|
|
219615
|
+
/** Single series, so the palette's lead hue; it clears 3:1 on white. */
|
|
219616
|
+
const BAR_COLOR = CHART_SERIES_COLORS[0];
|
|
219617
|
+
const PLOT_HEIGHT = 176;
|
|
219618
|
+
const MAX_X_LABELS = 5;
|
|
219619
|
+
/**
|
|
219620
|
+
* Spend per bucket as columns: ≤24px wide, 4px rounded tops, square at the
|
|
219621
|
+
* baseline, a hairline grid on clean ticks. Hover or arrow keys read one
|
|
219622
|
+
* column into the readout above the plot; the same numbers are in a
|
|
219623
|
+
* visually-hidden table for screen readers.
|
|
219624
|
+
*/
|
|
219625
|
+
function SpendChart({ points, granularity, }) {
|
|
219626
|
+
const t = useT();
|
|
219627
|
+
const [active, setActive] = useState(null);
|
|
219628
|
+
const { max, ticks } = useMemo(() => niceScale(Math.max(0, ...points.map((point) => point.totalCost))), [points]);
|
|
219629
|
+
const step = ticks.length > 1 ? ticks[1] - ticks[0] : max;
|
|
219630
|
+
const labelIndexes = useMemo(() => {
|
|
219631
|
+
if (points.length <= MAX_X_LABELS)
|
|
219632
|
+
return new Set(points.map((_, index) => index));
|
|
219633
|
+
const every = (points.length - 1) / (MAX_X_LABELS - 1);
|
|
219634
|
+
return new Set(Array.from({ length: MAX_X_LABELS }, (_, i) => Math.round(i * every)));
|
|
219635
|
+
}, [points]);
|
|
219636
|
+
const onKeyDown = (event) => {
|
|
219637
|
+
if (!points.length)
|
|
219638
|
+
return;
|
|
219639
|
+
const last = points.length - 1;
|
|
219640
|
+
const current = active !== null && active !== void 0 ? active : last;
|
|
219641
|
+
let next = null;
|
|
219642
|
+
if (event.key === 'ArrowRight')
|
|
219643
|
+
next = Math.min(last, active === null ? last : current + 1);
|
|
219644
|
+
if (event.key === 'ArrowLeft')
|
|
219645
|
+
next = Math.max(0, active === null ? last : current - 1);
|
|
219646
|
+
if (event.key === 'Home')
|
|
219647
|
+
next = 0;
|
|
219648
|
+
if (event.key === 'End')
|
|
219649
|
+
next = last;
|
|
219650
|
+
if (next === null)
|
|
219651
|
+
return;
|
|
219652
|
+
event.preventDefault();
|
|
219653
|
+
setActive(next);
|
|
219654
|
+
};
|
|
219655
|
+
const activePoint = active !== null ? points[active] : null;
|
|
219656
|
+
return (jsxs("div", { className: "flex flex-col gap-2", children: [jsx("p", { className: "h-5 text-sm text-gray-600 dark:text-gray-300", "aria-live": "polite", children: activePoint && (jsxs(Fragment$1, { children: [jsx("span", { className: "font-semibold tabular-nums text-gray-900 dark:text-gray-100", children: formatCost(activePoint.totalCost) }), ' ', jsxs("span", { className: "text-gray-500 dark:text-gray-400", children: ["\u00B7 ", formatBucket(activePoint.date, granularity)] })] })) }), jsxs("div", { className: "flex gap-2", children: [jsx("div", { className: "relative w-12 flex-shrink-0 text-right text-[11px] tabular-nums text-gray-500 dark:text-gray-400", style: { height: PLOT_HEIGHT }, "aria-hidden": "true", children: ticks.map((tick) => (jsx("span", { className: "absolute right-0 -translate-y-1/2 leading-none", style: { top: `${(1 - tick / max) * 100}%` }, children: formatAxisCost(tick, step) }, tick))) }), jsxs("div", { className: "min-w-0 flex-1", children: [jsxs("div", { role: "group", tabIndex: 0, "aria-label": t('profileLlmUsage.chartAria'), onKeyDown: onKeyDown, onBlur: () => setActive(null), onMouseLeave: () => setActive(null), className: "relative rounded-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-blue-500", style: { height: PLOT_HEIGHT }, children: [ticks.map((tick) => (jsx("div", { className: tick === 0
|
|
219657
|
+
? 'absolute inset-x-0 border-t border-gray-300 dark:border-gray-600'
|
|
219658
|
+
: 'absolute inset-x-0 border-t border-gray-100 dark:border-gray-800', style: { top: `${(1 - tick / max) * 100}%` }, "aria-hidden": "true" }, tick))), jsx("div", { className: "absolute inset-0 flex items-end gap-[2px]", "aria-hidden": "true", children: points.map((point, index) => {
|
|
219659
|
+
const height = max > 0 ? (point.totalCost / max) * 100 : 0;
|
|
219660
|
+
const isActive = index === active;
|
|
219661
|
+
return (jsx("div", {
|
|
219662
|
+
// The whole column slot is the hover target, not just the bar.
|
|
219663
|
+
className: "flex h-full min-w-0 flex-1 items-end justify-center", onMouseEnter: () => setActive(index), children: jsx("div", { className: "w-full max-w-[24px] rounded-t-[4px] transition-opacity", style: {
|
|
219664
|
+
height: point.totalCost > 0 ? `max(${height}%, 2px)` : 0,
|
|
219665
|
+
background: BAR_COLOR,
|
|
219666
|
+
opacity: active === null || isActive ? 1 : 0.45,
|
|
219667
|
+
} }) }, point.date));
|
|
219668
|
+
}) })] }), jsx("div", { className: "relative mt-2 h-4 text-[11px] text-gray-500 dark:text-gray-400", "aria-hidden": "true", children: points.map((point, index) => labelIndexes.has(index) ? (jsx("span", { className: "absolute whitespace-nowrap", style: index === 0
|
|
219669
|
+
? { left: 0 }
|
|
219670
|
+
: index === points.length - 1
|
|
219671
|
+
? { right: 0 }
|
|
219672
|
+
: {
|
|
219673
|
+
left: `${((index + 0.5) / points.length) * 100}%`,
|
|
219674
|
+
transform: 'translateX(-50%)',
|
|
219675
|
+
}, children: formatBucket(point.date, granularity) }, point.date)) : null) })] })] }), jsxs("table", { className: "sr-only", children: [jsx("caption", { children: t('profileLlmUsage.chartTableCaption') }), jsx("thead", { children: jsxs("tr", { children: [jsx("th", { scope: "col", children: t('profileLlmUsage.colPeriod') }), jsx("th", { scope: "col", children: t('profileLlmUsage.colCost') })] }) }), jsx("tbody", { children: points.map((point) => (jsxs("tr", { children: [jsx("td", { children: formatBucket(point.date, granularity) }), jsx("td", { children: formatCost(point.totalCost) })] }, point.date))) })] })] }));
|
|
219676
|
+
}
|
|
219677
|
+
|
|
219678
|
+
const RANGE_LABEL_KEYS = {
|
|
219679
|
+
today: 'rangeToday',
|
|
219680
|
+
'7d': 'range7d',
|
|
219681
|
+
'30d': 'range30d',
|
|
219682
|
+
'90d': 'range90d',
|
|
219683
|
+
all_time: 'rangeAllTime',
|
|
219684
|
+
};
|
|
219685
|
+
const PERIOD_LABEL_KEYS = {
|
|
219686
|
+
today: 'periodToday',
|
|
219687
|
+
'7d': 'period7d',
|
|
219688
|
+
'30d': 'period30d',
|
|
219689
|
+
'90d': 'period90d',
|
|
219690
|
+
all_time: 'periodAllTime',
|
|
219691
|
+
};
|
|
219692
|
+
const CHART_SUBTITLE_KEYS = {
|
|
219693
|
+
day: 'chartSubtitleDay',
|
|
219694
|
+
week: 'chartSubtitleWeek',
|
|
219695
|
+
month: 'chartSubtitleMonth',
|
|
219696
|
+
};
|
|
219697
|
+
const BREAKDOWN_ROWS = 5;
|
|
219698
|
+
const MODEL_BAR_COLOR = CHART_SERIES_COLORS[0];
|
|
219699
|
+
const CARD = 'rounded-xl border border-gray-200 bg-white dark:border-gray-800 dark:bg-gray-950';
|
|
219700
|
+
function Card({ title, subtitle, aside, children, className, bodyClassName, }) {
|
|
219701
|
+
return (jsxs("section", { className: cn(CARD, className), "aria-label": title, children: [jsxs("div", { className: "flex items-start justify-between gap-4 px-5 pt-5", children: [jsxs("div", { className: "min-w-0", children: [jsx("h4", { className: "text-[15px] font-semibold text-gray-900 dark:text-gray-100", children: title }), subtitle && (jsx("p", { className: "mt-0.5 text-[13px] text-gray-500 dark:text-gray-400", children: subtitle }))] }), aside] }), jsx("div", { className: cn('px-5 pb-5 pt-4', bodyClassName), children: children })] }));
|
|
219702
|
+
}
|
|
219703
|
+
function RangeControl({ value, onChange, }) {
|
|
219704
|
+
const t = useT();
|
|
219705
|
+
const groupRef = useRef(null);
|
|
219706
|
+
const onKeyDown = (event, index) => {
|
|
219707
|
+
var _a, _b;
|
|
219708
|
+
const last = LLM_USAGE_RANGES.length - 1;
|
|
219709
|
+
let next = null;
|
|
219710
|
+
if (event.key === 'ArrowRight' || event.key === 'ArrowDown')
|
|
219711
|
+
next = index === last ? 0 : index + 1;
|
|
219712
|
+
if (event.key === 'ArrowLeft' || event.key === 'ArrowUp')
|
|
219713
|
+
next = index === 0 ? last : index - 1;
|
|
219714
|
+
if (next === null)
|
|
219715
|
+
return;
|
|
219716
|
+
event.preventDefault();
|
|
219717
|
+
onChange(LLM_USAGE_RANGES[next]);
|
|
219718
|
+
(_b = (_a = groupRef.current) === null || _a === void 0 ? void 0 : _a.querySelectorAll('[role="radio"]')[next]) === null || _b === void 0 ? void 0 : _b.focus();
|
|
219719
|
+
};
|
|
219720
|
+
return (jsx("div", { ref: groupRef, role: "radiogroup", "aria-label": t('profileLlmUsage.rangeLabel'), className: "inline-flex max-w-full gap-0.5 overflow-x-auto rounded-lg bg-gray-100 p-[3px] dark:bg-gray-800", children: LLM_USAGE_RANGES.map((range, index) => {
|
|
219721
|
+
const checked = range === value;
|
|
219722
|
+
return (jsx("button", { type: "button", role: "radio", "aria-checked": checked, tabIndex: checked ? 0 : -1, onClick: () => onChange(range), onKeyDown: (event) => onKeyDown(event, index), className: cn('h-8 whitespace-nowrap rounded-md px-3 text-[13px] transition-colors', 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-blue-500', checked
|
|
219723
|
+
? 'bg-white font-semibold text-gray-900 shadow-sm ring-1 ring-gray-200 dark:bg-gray-950 dark:text-gray-100 dark:ring-gray-700'
|
|
219724
|
+
: 'font-medium text-gray-600 hover:text-gray-900 dark:text-gray-300'), children: t(`profileLlmUsage.${RANGE_LABEL_KEYS[range]}`) }, range));
|
|
219725
|
+
}) }));
|
|
219726
|
+
}
|
|
219727
|
+
function StatTile({ label, value, sub, loading, }) {
|
|
219728
|
+
return (jsxs("div", { className: cn(CARD, 'flex flex-col gap-2 p-4'), children: [jsx("p", { className: "text-[13px] font-medium text-gray-500 dark:text-gray-400", children: label }), loading ? (jsxs(Fragment$1, { children: [jsx(Skeleton, { className: "h-7 w-24" }), jsx(Skeleton, { className: "h-4 w-20" })] })) : (jsxs(Fragment$1, { children: [jsx("p", { className: "text-[26px] font-semibold leading-tight tracking-tight text-gray-900 dark:text-gray-100", children: value }), jsx("p", { className: "min-h-[1rem] text-xs text-gray-500 tabular-nums dark:text-gray-400", children: sub })] }))] }));
|
|
219729
|
+
}
|
|
219730
|
+
function StateMessage({ icon, tone = 'neutral', title, body, action, }) {
|
|
219731
|
+
return (jsxs("div", { className: cn(CARD, 'flex flex-col items-center gap-3 px-6 py-14 text-center'), role: tone === 'error' ? 'alert' : undefined, children: [jsx("div", { className: cn('flex h-12 w-12 items-center justify-center rounded-xl', tone === 'error'
|
|
219732
|
+
? 'bg-red-50 text-red-700 dark:bg-red-950 dark:text-red-300'
|
|
219733
|
+
: 'bg-gray-100 text-gray-500 dark:bg-gray-800 dark:text-gray-400'), "aria-hidden": "true", children: icon }), jsx("h4", { className: "text-base font-semibold text-gray-900 dark:text-gray-100", children: title }), jsx("p", { className: "max-w-sm text-sm leading-relaxed text-gray-500 dark:text-gray-400", children: body }), action] }));
|
|
219734
|
+
}
|
|
219735
|
+
function RankedBars({ rows, total, colorFor, }) {
|
|
219736
|
+
return (jsx("ul", { className: "flex flex-col gap-3", children: rows.map((row) => {
|
|
219737
|
+
const share = sharePercent(row.totalCost, total);
|
|
219738
|
+
return (jsxs("li", { className: "flex flex-col gap-1.5", children: [jsxs("div", { className: "flex items-baseline justify-between gap-3 text-[13px]", children: [jsxs("span", { className: "flex min-w-0 items-center gap-2 font-medium text-gray-900 dark:text-gray-100", children: [jsx("span", { className: "h-2 w-2 flex-shrink-0 rounded-[2px]", style: { background: colorFor(row) }, "aria-hidden": "true" }), jsx("span", { className: "truncate", title: row.label, children: row.label })] }), jsxs("span", { className: "whitespace-nowrap tabular-nums text-gray-700 dark:text-gray-300", children: [formatCost(row.totalCost), jsxs("span", { className: "text-gray-500 dark:text-gray-400", children: [" \u00B7 ", share, "%"] })] })] }), jsx("div", { className: "h-1.5 overflow-hidden rounded-full bg-gray-100 dark:bg-gray-800", "aria-hidden": "true", children: jsx("div", { className: "h-full rounded-full", style: { width: `${Math.min(100, share)}%`, background: colorFor(row) } }) })] }, row.key));
|
|
219739
|
+
}) }));
|
|
219740
|
+
}
|
|
219741
|
+
function BreakdownSkeleton() {
|
|
219742
|
+
return (jsx("div", { className: "flex flex-col gap-4", children: [0, 1, 2, 3].map((i) => (jsxs("div", { className: "flex flex-col gap-2", children: [jsx(Skeleton, { className: "h-4 w-3/4" }), jsx(Skeleton, { className: "h-1.5 w-full" })] }, i))) }));
|
|
219743
|
+
}
|
|
219744
|
+
function SectionError() {
|
|
219745
|
+
const t = useT();
|
|
219746
|
+
return (jsxs("p", { className: "flex items-center gap-2 text-sm text-gray-500 dark:text-gray-400", children: [jsx(CircleAlert, { className: "h-4 w-4 text-red-600", "aria-hidden": "true" }), t('profileLlmUsage.sectionError')] }));
|
|
219747
|
+
}
|
|
219748
|
+
const observationTokens = (o) => {
|
|
219749
|
+
var _a, _b, _c, _d, _e, _f;
|
|
219750
|
+
return ({
|
|
219751
|
+
input: (_b = (_a = o.usage) === null || _a === void 0 ? void 0 : _a.input) !== null && _b !== void 0 ? _b : o.promptTokens,
|
|
219752
|
+
output: (_d = (_c = o.usage) === null || _c === void 0 ? void 0 : _c.output) !== null && _d !== void 0 ? _d : o.completionTokens,
|
|
219753
|
+
total: (_f = (_e = o.usage) === null || _e === void 0 ? void 0 : _e.total) !== null && _f !== void 0 ? _f : o.totalTokens,
|
|
219754
|
+
});
|
|
219755
|
+
};
|
|
219756
|
+
const observationCost = (o) => { var _a, _b, _c; return (_b = (_a = o.calculatedTotalCost) !== null && _a !== void 0 ? _a : o.totalCost) !== null && _b !== void 0 ? _b : (_c = o.costDetails) === null || _c === void 0 ? void 0 : _c.total; };
|
|
219757
|
+
function TraceSteps({ steps, isLoading, error, }) {
|
|
219758
|
+
const t = useT();
|
|
219759
|
+
if (isLoading) {
|
|
219760
|
+
return (jsx("p", { className: "px-4 py-3 text-sm text-gray-500 dark:text-gray-400", children: t('profileLlmUsage.stepsLoading') }));
|
|
219761
|
+
}
|
|
219762
|
+
if (error) {
|
|
219763
|
+
return (jsx("p", { className: "px-4 py-3 text-sm text-gray-500 dark:text-gray-400", children: t('profileLlmUsage.stepsError') }));
|
|
219764
|
+
}
|
|
219765
|
+
if (!steps.length) {
|
|
219766
|
+
return (jsx("p", { className: "px-4 py-3 text-sm text-gray-500 dark:text-gray-400", children: t('profileLlmUsage.stepsEmpty') }));
|
|
219767
|
+
}
|
|
219768
|
+
const cell = 'px-3 py-2 text-right tabular-nums';
|
|
219769
|
+
return (jsx("div", { className: "overflow-x-auto", children: jsxs("table", { className: "w-full text-[12.5px]", children: [jsx("thead", { children: jsxs("tr", { className: "text-left text-gray-500 dark:text-gray-400", children: [jsx("th", { scope: "col", className: "px-4 py-2 font-medium", children: t('profileLlmUsage.colStep') }), jsx("th", { scope: "col", className: "px-3 py-2 font-medium", children: t('profileLlmUsage.colModel') }), jsx("th", { scope: "col", className: cn(cell, 'font-medium'), children: t('profileLlmUsage.colInput') }), jsx("th", { scope: "col", className: cn(cell, 'font-medium'), children: t('profileLlmUsage.colOutput') }), jsx("th", { scope: "col", className: cn(cell, 'font-medium'), children: t('profileLlmUsage.colTotal') }), jsx("th", { scope: "col", className: cn(cell, 'font-medium'), children: t('profileLlmUsage.colLatency') }), jsx("th", { scope: "col", className: "px-4 py-2 text-right font-medium", children: t('profileLlmUsage.colCost') })] }) }), jsx("tbody", { children: steps.map((step) => {
|
|
219770
|
+
const tokens = observationTokens(step);
|
|
219771
|
+
return (jsxs("tr", { className: "border-t border-gray-100 text-gray-700 dark:border-gray-800 dark:text-gray-300", children: [jsx("td", { className: "px-4 py-2 font-medium text-gray-900 dark:text-gray-100", children: step.name || step.type || '—' }), jsx("td", { className: "px-3 py-2", children: step.providedModelName || step.model || '—' }), jsx("td", { className: cell, children: formatInteger(tokens.input) }), jsx("td", { className: cell, children: formatInteger(tokens.output) }), jsx("td", { className: cell, children: formatInteger(tokens.total) }), jsx("td", { className: cell, children: formatSeconds(step.latency) }), jsx("td", { className: "px-4 py-2 text-right font-semibold tabular-nums text-gray-900 dark:text-gray-100", children: formatCost(observationCost(step), { precise: true }) })] }, step.id));
|
|
219772
|
+
}) })] }) }));
|
|
219773
|
+
}
|
|
219774
|
+
/**
|
|
219775
|
+
* The profile "Usage" tab: AI spend, tokens and requests for the profile on
|
|
219776
|
+
* screen. Every request names that user, so an admin viewing someone else
|
|
219777
|
+
* sees their rows rather than the whole platform's.
|
|
219778
|
+
*/
|
|
219779
|
+
function LlmUsageTab({ org, username, isOwnProfile = true }) {
|
|
219780
|
+
var _a;
|
|
219781
|
+
const t = useT();
|
|
219782
|
+
const [range, setRange] = useState(DEFAULT_LLM_USAGE_RANGE);
|
|
219783
|
+
const [page, setPage] = useState(1);
|
|
219784
|
+
const [openTraceId, setOpenTraceId] = useState(null);
|
|
219785
|
+
const granularity = granularityForRange(range);
|
|
219786
|
+
const scope = { platformKey: org, username, date_filter: range };
|
|
219787
|
+
const summary = useUserLlmUsageSummary(scope);
|
|
219788
|
+
const spend = useUserLlmSpendOverTime({ ...scope, granularity });
|
|
219789
|
+
const byModel = useUserLlmCostByModel({ ...scope, limit: 20 });
|
|
219790
|
+
const byService = useUserLlmCostByService(scope);
|
|
219791
|
+
const activity = useUserLlmRecentActivity({
|
|
219792
|
+
...scope,
|
|
219793
|
+
page,
|
|
219794
|
+
limit: USER_LLM_RECENT_ACTIVITY_PAGE_SIZE,
|
|
219795
|
+
});
|
|
219796
|
+
const steps = useUserLlmTraceObservations({ ...scope, traceId: openTraceId });
|
|
219797
|
+
const changeRange = (next) => {
|
|
219798
|
+
setRange(next);
|
|
219799
|
+
setPage(1);
|
|
219800
|
+
setOpenTraceId(null);
|
|
219801
|
+
};
|
|
219802
|
+
const refreshAll = () => {
|
|
219803
|
+
summary.refetch();
|
|
219804
|
+
spend.refetch();
|
|
219805
|
+
byModel.refetch();
|
|
219806
|
+
byService.refetch();
|
|
219807
|
+
activity.refetch();
|
|
219808
|
+
if (openTraceId)
|
|
219809
|
+
steps.refetch();
|
|
219810
|
+
};
|
|
219811
|
+
const series = useMemo(() => buildSpendSeries(spend.points, range), [spend.points, range]);
|
|
219812
|
+
const modelRows = useMemo(() => foldTail(byModel.models.map((row, index) => ({
|
|
219813
|
+
key: row.model || `unknown-${index}`,
|
|
219814
|
+
label: row.model || t('profileLlmUsage.unknownModel'),
|
|
219815
|
+
totalCost: row.totalCost,
|
|
219816
|
+
count: row.count,
|
|
219817
|
+
})), BREAKDOWN_ROWS, t('profileLlmUsage.otherRow')), [byModel.models, t]);
|
|
219818
|
+
const serviceRows = useMemo(() => foldTail(byService.services.map((row, index) => ({
|
|
219819
|
+
key: row.service || `unknown-${index}`,
|
|
219820
|
+
label: row.service || t('profileLlmUsage.unknownService'),
|
|
219821
|
+
totalCost: row.totalCost,
|
|
219822
|
+
count: row.count,
|
|
219823
|
+
})), BREAKDOWN_ROWS, t('profileLlmUsage.otherRow')), [byService.services, t]);
|
|
219824
|
+
const modelTotal = modelRows.reduce((sum, row) => sum + row.totalCost, 0);
|
|
219825
|
+
const serviceTotal = serviceRows.reduce((sum, row) => sum + row.totalCost, 0);
|
|
219826
|
+
const totals = summary.summary;
|
|
219827
|
+
const periodLabel = t(`profileLlmUsage.${PERIOD_LABEL_KEYS[range]}`);
|
|
219828
|
+
const next = widerRange(range);
|
|
219829
|
+
const errorCopy = (error) => {
|
|
219830
|
+
if (error.kind === 'unavailable') {
|
|
219831
|
+
return {
|
|
219832
|
+
title: t('profileLlmUsage.errorUnavailableTitle'),
|
|
219833
|
+
body: t('profileLlmUsage.errorUnavailableBody'),
|
|
219834
|
+
};
|
|
219835
|
+
}
|
|
219836
|
+
if (error.kind === 'unauthorized') {
|
|
219837
|
+
return {
|
|
219838
|
+
title: t('profileLlmUsage.errorUnauthorizedTitle'),
|
|
219839
|
+
body: t('profileLlmUsage.errorUnauthorizedBody'),
|
|
219840
|
+
};
|
|
219841
|
+
}
|
|
219842
|
+
if (error.kind === 'forbidden' || error.kind === 'not_found') {
|
|
219843
|
+
return {
|
|
219844
|
+
title: t('profileLlmUsage.errorForbiddenTitle'),
|
|
219845
|
+
body: t('profileLlmUsage.errorForbiddenBody'),
|
|
219846
|
+
};
|
|
219847
|
+
}
|
|
219848
|
+
return {
|
|
219849
|
+
title: t('profileLlmUsage.errorUnknownTitle'),
|
|
219850
|
+
body: t('profileLlmUsage.errorUnknownBody'),
|
|
219851
|
+
};
|
|
219852
|
+
};
|
|
219853
|
+
const meta = activity.meta;
|
|
219854
|
+
const pageSize = (meta === null || meta === void 0 ? void 0 : meta.limit) || USER_LLM_RECENT_ACTIVITY_PAGE_SIZE;
|
|
219855
|
+
const from = meta && meta.totalItems > 0 ? (meta.page - 1) * pageSize + 1 : 0;
|
|
219856
|
+
const to = meta ? Math.min(meta.page * pageSize, meta.totalItems) : 0;
|
|
219857
|
+
const totalPages = (_a = meta === null || meta === void 0 ? void 0 : meta.totalPages) !== null && _a !== void 0 ? _a : 1;
|
|
219858
|
+
let body;
|
|
219859
|
+
if (summary.error) {
|
|
219860
|
+
const copy = errorCopy(summary.error);
|
|
219861
|
+
body = (jsx(StateMessage, { tone: "error", icon: jsx(CircleAlert, { className: "h-6 w-6" }), title: copy.title, body: copy.body, action: summary.error.kind !== 'unauthorized' && (jsx(Button$1, { onClick: refreshAll, className: "mt-1 bg-blue-600 text-white hover:bg-blue-700", children: t('profileLlmUsage.tryAgain') })) }));
|
|
219862
|
+
}
|
|
219863
|
+
else if (summary.isEmpty) {
|
|
219864
|
+
body = (jsx(StateMessage, { icon: jsx(Inbox, { className: "h-6 w-6" }), title: t('profileLlmUsage.emptyTitle'), body: t('profileLlmUsage.emptyBody'), action: next && (jsx(Button$1, { variant: "outline", onClick: () => changeRange(next), className: "mt-1", children: next === 'all_time'
|
|
219865
|
+
? t('profileLlmUsage.emptyActionAll')
|
|
219866
|
+
: t('profileLlmUsage.emptyAction90') })) }));
|
|
219867
|
+
}
|
|
219868
|
+
else {
|
|
219869
|
+
const loadingTotals = summary.isLoading || summary.isIdle;
|
|
219870
|
+
body = (jsxs(Fragment$1, { children: [jsxs("div", { className: "grid grid-cols-2 gap-3 xl:grid-cols-4", children: [jsx(StatTile, { label: t('profileLlmUsage.kpiSpend'), value: formatCost(totals === null || totals === void 0 ? void 0 : totals.totalCost), sub: periodLabel, loading: loadingTotals }), jsx(StatTile, { label: t('profileLlmUsage.kpiTokens'), value: formatCompact(totals === null || totals === void 0 ? void 0 : totals.totalTokens), sub: totals && totals.count > 0
|
|
219871
|
+
? t('profileLlmUsage.kpiTokensSub', {
|
|
219872
|
+
value: formatCompact(totals.totalTokens / totals.count),
|
|
219873
|
+
})
|
|
219874
|
+
: undefined, loading: loadingTotals }), jsx(StatTile, { label: t('profileLlmUsage.kpiRequests'), value: formatInteger(totals === null || totals === void 0 ? void 0 : totals.count), sub: t('profileLlmUsage.kpiRequestsSub'), loading: loadingTotals }), jsx(StatTile, { label: t('profileLlmUsage.kpiAvgCost'), value: totals && totals.count > 0
|
|
219875
|
+
? formatCost(totals.totalCost / totals.count, { precise: true })
|
|
219876
|
+
: '—', sub: t('profileLlmUsage.kpiAvgCostSub'), loading: loadingTotals })] }), jsx(Card, { title: t('profileLlmUsage.chartTitle'), subtitle: t(`profileLlmUsage.${CHART_SUBTITLE_KEYS[granularity]}`), aside: totals && (jsx("span", { className: "text-[15px] font-semibold tabular-nums text-gray-900 dark:text-gray-100", children: formatCost(totals.totalCost) })), bodyClassName: "pt-2", children: spend.isLoading || spend.isIdle ? (jsx(Skeleton, { className: "h-[220px] w-full" })) : spend.error ? (jsx(SectionError, {})) : series.length === 0 ? (jsx("p", { className: "py-10 text-center text-sm text-gray-500 dark:text-gray-400", children: t('profileLlmUsage.chartNoData') })) : (jsx(SpendChart, { points: series, granularity: granularity })) }), jsxs("div", { className: "grid grid-cols-1 gap-3 md:grid-cols-2", children: [jsx(Card, { title: t('profileLlmUsage.byModelTitle'), subtitle: t('profileLlmUsage.byModelSubtitle'), children: byModel.isLoading || byModel.isIdle ? (jsx(BreakdownSkeleton, {})) : byModel.error ? (jsx(SectionError, {})) : modelRows.length === 0 ? (jsx("p", { className: "text-sm text-gray-500 dark:text-gray-400", children: t('profileLlmUsage.breakdownEmpty') })) : (jsx(RankedBars, { rows: modelRows, total: modelTotal, colorFor: () => MODEL_BAR_COLOR })) }), jsx(Card, { title: t('profileLlmUsage.byServiceTitle'), subtitle: t('profileLlmUsage.byServiceSubtitle'), children: byService.isLoading || byService.isIdle ? (jsx(BreakdownSkeleton, {})) : byService.error ? (jsx(SectionError, {})) : serviceRows.length === 0 ? (jsx("p", { className: "text-sm text-gray-500 dark:text-gray-400", children: t('profileLlmUsage.breakdownEmpty') })) : (jsx(RankedBars, { rows: serviceRows, total: serviceTotal,
|
|
219877
|
+
// Colour follows the service, so "chat" is the same hue everywhere.
|
|
219878
|
+
colorFor: (row) => (row.isOther ? '#9ca3af' : colorForSeries(row.key)) })) })] }), jsxs("section", { className: cn(CARD, 'overflow-hidden'), "aria-labelledby": "llm-activity-heading", children: [jsxs("div", { className: "border-b border-gray-200 px-5 py-4 dark:border-gray-800", children: [jsx("h4", { id: "llm-activity-heading", className: "text-[15px] font-semibold text-gray-900 dark:text-gray-100", children: t('profileLlmUsage.activityTitle') }), jsx("p", { className: "mt-0.5 text-[13px] text-gray-500 dark:text-gray-400", children: t('profileLlmUsage.activitySubtitle') })] }), activity.isLoading || activity.isIdle ? (jsx("div", { className: "flex flex-col gap-3 p-5", children: [0, 1, 2, 3].map((i) => (jsx(Skeleton, { className: "h-8 w-full" }, i))) })) : activity.error ? (jsx("div", { className: "p-5", children: jsx(SectionError, {}) })) : activity.isEmpty || activity.rows.length === 0 ? (jsx("p", { className: "p-5 text-sm text-gray-500 dark:text-gray-400", children: t('profileLlmUsage.activityEmpty') })) : (jsxs(Fragment$1, { children: [jsx("div", { className: "overflow-x-auto", children: jsxs("table", { className: "w-full text-[13px]", children: [jsx("thead", { children: jsxs("tr", { className: "bg-gray-50 text-left text-gray-500 dark:bg-gray-900 dark:text-gray-400", children: [jsx("th", { scope: "col", className: "px-5 py-2.5 font-medium", children: t('profileLlmUsage.colWhen') }), jsx("th", { scope: "col", className: "px-3 py-2.5 font-medium", children: t('profileLlmUsage.colService') }), jsx("th", { scope: "col", className: "hidden px-3 py-2.5 font-medium md:table-cell", children: t('profileLlmUsage.colSession') }), jsx("th", { scope: "col", className: "px-3 py-2.5 text-right font-medium", children: t('profileLlmUsage.colLatency') }), jsx("th", { scope: "col", className: "px-3 py-2.5 text-right font-medium", children: t('profileLlmUsage.colCost') }), jsx("th", { scope: "col", className: "w-12 py-2.5 pl-2 pr-5", children: jsx("span", { className: "sr-only", children: t('profileLlmUsage.colDetails') }) })] }) }), jsx("tbody", { children: activity.rows.map((trace) => {
|
|
219879
|
+
const open = trace.id === openTraceId;
|
|
219880
|
+
const when = formatWhen(trace.timestamp);
|
|
219881
|
+
const service = trace.name || t('profileLlmUsage.unknownService');
|
|
219882
|
+
const stepsId = `llm-trace-${trace.id}-steps`;
|
|
219883
|
+
return (jsxs(Fragment$2, { children: [jsxs("tr", { className: cn('border-t border-gray-200 dark:border-gray-800', open && 'bg-gray-50 dark:bg-gray-900'), children: [jsx("td", { className: "whitespace-nowrap px-5 py-3 text-gray-900 dark:text-gray-100", children: when }), jsx("td", { className: "px-3 py-3", children: jsxs("span", { className: "inline-flex items-center gap-2 text-gray-700 dark:text-gray-300", children: [jsx("span", { className: "h-2 w-2 flex-shrink-0 rounded-[2px]", style: { background: colorForSeries(trace.name || '') }, "aria-hidden": "true" }), jsx("span", { className: "max-w-[16rem] truncate", title: service, children: service })] }) }), jsx("td", { className: "hidden px-3 py-3 font-mono text-xs text-gray-500 dark:text-gray-400 md:table-cell", title: trace.sessionId, children: shortId(trace.sessionId) }), jsx("td", { className: "px-3 py-3 text-right tabular-nums text-gray-700 dark:text-gray-300", children: formatSeconds(trace.latency) }), jsx("td", { className: "px-3 py-3 text-right font-semibold tabular-nums text-gray-900 dark:text-gray-100", children: formatCost(trace.totalCost, { precise: true }) }), jsx("td", { className: "py-2 pl-2 pr-5", children: jsx("button", { type: "button", "aria-expanded": open, "aria-controls": open ? stepsId : undefined, "aria-label": open
|
|
219884
|
+
? t('profileLlmUsage.hideSteps', { when })
|
|
219885
|
+
: t('profileLlmUsage.showSteps', { when }), onClick: () => setOpenTraceId(open ? null : trace.id), className: cn('flex h-8 w-8 items-center justify-center rounded-md transition-colors', 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-blue-500', open
|
|
219886
|
+
? 'bg-gray-200 text-gray-900 dark:bg-gray-700 dark:text-gray-100'
|
|
219887
|
+
: 'text-gray-500 hover:bg-gray-100 hover:text-gray-900 dark:hover:bg-gray-800'), children: open ? (jsx(ChevronDown, { className: "h-4 w-4", "aria-hidden": "true" })) : (jsx(ChevronRight, { className: "h-4 w-4", "aria-hidden": "true" })) }) })] }), open && (jsx("tr", { className: "bg-gray-50 dark:bg-gray-900", children: jsx("td", { colSpan: 6, className: "px-5 pb-4", children: jsx("div", { id: stepsId, className: "overflow-hidden rounded-lg border border-gray-200 bg-white dark:border-gray-800 dark:bg-gray-950", children: jsx(TraceSteps, { steps: steps.rows, isLoading: steps.isLoading, error: steps.error }) }) }) }))] }, trace.id));
|
|
219888
|
+
}) })] }) }), meta && (jsxs("div", { className: "flex flex-wrap items-center justify-between gap-3 border-t border-gray-200 px-5 py-3 dark:border-gray-800", children: [jsx("p", { className: "text-[13px] tabular-nums text-gray-500 dark:text-gray-400", children: t('profileLlmUsage.paginationSummary', {
|
|
219889
|
+
from: formatInteger(from),
|
|
219890
|
+
to: formatInteger(to),
|
|
219891
|
+
total: formatInteger(meta.totalItems),
|
|
219892
|
+
}) }), jsxs("div", { className: "flex gap-2", children: [jsxs(Button$1, { variant: "outline", size: "sm", className: "h-8 gap-1", disabled: page <= 1 || activity.isFetching, onClick: () => {
|
|
219893
|
+
setOpenTraceId(null);
|
|
219894
|
+
setPage((current) => Math.max(1, current - 1));
|
|
219895
|
+
}, children: [jsx(ChevronLeft, { className: "h-4 w-4", "aria-hidden": "true" }), t('profileLlmUsage.previous')] }), jsxs(Button$1, { variant: "outline", size: "sm", className: "h-8 gap-1", disabled: page >= totalPages || activity.isFetching, onClick: () => {
|
|
219896
|
+
setOpenTraceId(null);
|
|
219897
|
+
setPage((current) => current + 1);
|
|
219898
|
+
}, children: [t('profileLlmUsage.next'), jsx(ChevronRight, { className: "h-4 w-4", "aria-hidden": "true" })] })] })] }))] }))] })] }));
|
|
219899
|
+
}
|
|
219900
|
+
const isRefreshing = summary.isFetching ||
|
|
219901
|
+
spend.isFetching ||
|
|
219902
|
+
byModel.isFetching ||
|
|
219903
|
+
byService.isFetching ||
|
|
219904
|
+
activity.isFetching;
|
|
219905
|
+
return (jsxs("div", { className: "flex flex-col gap-5", "data-testid": "llm-usage-tab", children: [jsxs("div", { className: "flex flex-wrap items-center justify-between gap-3", children: [jsx(RangeControl, { value: range, onChange: changeRange }), jsxs("div", { className: "flex items-center gap-3", children: [jsxs("span", { className: "inline-flex items-center gap-1.5 text-[13px] text-gray-500 dark:text-gray-400", children: [jsx(Lock, { className: "h-3.5 w-3.5", "aria-hidden": "true" }), isOwnProfile
|
|
219906
|
+
? t('profileLlmUsage.scopeSelf')
|
|
219907
|
+
: t('profileLlmUsage.scopeUser', { username })] }), jsx(Button$1, { variant: "outline", size: "icon", className: "h-9 w-9", onClick: refreshAll, disabled: isRefreshing, "aria-label": t('profileLlmUsage.refresh'), title: t('profileLlmUsage.refresh'), children: jsx(RefreshCw, { className: cn('h-4 w-4', isRefreshing && 'animate-spin'), "aria-hidden": "true" }) })] })] }), body] }));
|
|
219908
|
+
}
|
|
219909
|
+
|
|
219910
|
+
const tabId = (id, mobile) => (mobile ? `${id}-tab-mobile` : `${id}-tab`);
|
|
219911
|
+
/** Arrow/Home/End handling for the tab variant, with automatic activation. */
|
|
219912
|
+
function useTabKeyboard(items, onSelect, mobile) {
|
|
219913
|
+
const containerRef = useRef(null);
|
|
219914
|
+
const onKeyDown = (event, index) => {
|
|
219915
|
+
var _a, _b;
|
|
219916
|
+
const last = items.length - 1;
|
|
219917
|
+
let next = null;
|
|
219918
|
+
if (event.key === 'ArrowDown' || event.key === 'ArrowRight')
|
|
219919
|
+
next = index === last ? 0 : index + 1;
|
|
219920
|
+
if (event.key === 'ArrowUp' || event.key === 'ArrowLeft')
|
|
219921
|
+
next = index === 0 ? last : index - 1;
|
|
219922
|
+
if (event.key === 'Home')
|
|
219923
|
+
next = 0;
|
|
219924
|
+
if (event.key === 'End')
|
|
219925
|
+
next = last;
|
|
219926
|
+
if (next === null)
|
|
219927
|
+
return;
|
|
219928
|
+
event.preventDefault();
|
|
219929
|
+
const target = items[next];
|
|
219930
|
+
onSelect(target.id);
|
|
219931
|
+
(_b = (_a = containerRef.current) === null || _a === void 0 ? void 0 : _a.querySelector(`[id="${tabId(target.id, mobile)}"]`)) === null || _b === void 0 ? void 0 : _b.focus();
|
|
219932
|
+
};
|
|
219933
|
+
return { containerRef, onKeyDown };
|
|
219934
|
+
}
|
|
219935
|
+
/** Grouped vertical navigation for the desktop sidebar. */
|
|
219936
|
+
function SettingsSidebarNav({ groups, activeId, onSelect, variant, ariaLabel, }) {
|
|
219937
|
+
const visibleGroups = groups.filter((group) => group.items.length > 0);
|
|
219938
|
+
const flat = visibleGroups.flatMap((group) => group.items);
|
|
219939
|
+
const isTabs = variant === 'tabs';
|
|
219940
|
+
const { containerRef, onKeyDown } = useTabKeyboard(flat, onSelect, false);
|
|
219941
|
+
const renderItem = (item) => {
|
|
219942
|
+
const active = item.id === activeId;
|
|
219943
|
+
const Icon = item.icon;
|
|
219944
|
+
return (jsxs("button", { type: "button", onClick: () => onSelect(item.id), ...(isTabs
|
|
219945
|
+
? {
|
|
219946
|
+
role: 'tab',
|
|
219947
|
+
id: tabId(item.id, false),
|
|
219948
|
+
'aria-selected': active,
|
|
219949
|
+
'aria-controls': `${item.id}-tabpanel`,
|
|
219950
|
+
tabIndex: active ? 0 : -1,
|
|
219951
|
+
onKeyDown: (event) => onKeyDown(event, flat.indexOf(item)),
|
|
219952
|
+
}
|
|
219953
|
+
: { 'aria-current': active ? 'page' : undefined }), className: cn('group flex h-9 w-full items-center gap-2.5 rounded-lg px-2.5 text-left text-sm transition-colors', 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-blue-500 focus-visible:ring-offset-1', active
|
|
219954
|
+
? 'bg-white font-semibold text-gray-900 shadow-sm ring-1 ring-gray-200 dark:bg-gray-800 dark:text-gray-100 dark:ring-gray-700'
|
|
219955
|
+
: 'font-medium text-gray-700 hover:bg-gray-100 hover:text-gray-900 dark:text-gray-300 dark:hover:bg-gray-800 dark:hover:text-gray-100'), children: [jsx(Icon, { className: cn('h-4 w-4 flex-shrink-0', active
|
|
219956
|
+
? 'text-blue-600 dark:text-blue-400'
|
|
219957
|
+
: 'text-gray-500 group-hover:text-gray-700 dark:text-gray-400'), "aria-hidden": true }), jsx("span", { className: "truncate", children: item.label })] }, item.id));
|
|
219958
|
+
};
|
|
219959
|
+
return (jsx("nav", { className: "min-h-0 flex-1 overflow-y-auto px-3 py-4", "aria-label": ariaLabel, children: jsx("div", { ref: containerRef, className: "flex flex-col gap-4", ...(isTabs ? { role: 'tablist', 'aria-orientation': 'vertical' } : {}), children: visibleGroups.map((group) => (jsxs("div", { className: "flex flex-col gap-0.5", ...(isTabs
|
|
219960
|
+
? {}
|
|
219961
|
+
: { role: 'group', 'aria-labelledby': `settings-nav-group-${group.id}` }), children: [jsx("div", { id: `settings-nav-group-${group.id}`, className: "px-2.5 pb-1 text-[11px] font-semibold uppercase tracking-wider text-gray-500 dark:text-gray-400", "aria-hidden": isTabs ? true : undefined, children: group.label }), group.items.map(renderItem)] }, group.id))) }) }));
|
|
219962
|
+
}
|
|
219963
|
+
/** Horizontally scrolling pills for small screens. */
|
|
219964
|
+
function SettingsMobileNav({ groups, activeId, onSelect, variant, ariaLabel, }) {
|
|
219965
|
+
const flat = groups.flatMap((group) => group.items);
|
|
219966
|
+
const isTabs = variant === 'tabs';
|
|
219967
|
+
const { containerRef, onKeyDown } = useTabKeyboard(flat, onSelect, true);
|
|
219968
|
+
return (jsx("nav", { className: "border-b border-gray-200 dark:border-gray-800 lg:hidden", "aria-label": ariaLabel, children: jsx("div", { ref: containerRef, className: "flex gap-2 overflow-x-auto px-4 py-2.5 [scrollbar-width:none] sm:px-6", ...(isTabs ? { role: 'tablist', 'aria-orientation': 'horizontal' } : {}), children: flat.map((item, index) => {
|
|
219969
|
+
const active = item.id === activeId;
|
|
219970
|
+
const Icon = item.icon;
|
|
219971
|
+
return (jsxs("button", { type: "button", onClick: () => onSelect(item.id), ...(isTabs
|
|
219972
|
+
? {
|
|
219973
|
+
role: 'tab',
|
|
219974
|
+
id: tabId(item.id, true),
|
|
219975
|
+
'aria-selected': active,
|
|
219976
|
+
'aria-controls': `${item.id}-tabpanel`,
|
|
219977
|
+
tabIndex: active ? 0 : -1,
|
|
219978
|
+
onKeyDown: (event) => onKeyDown(event, index),
|
|
219979
|
+
}
|
|
219980
|
+
: { 'aria-current': active ? 'page' : undefined }), className: cn('flex h-9 flex-shrink-0 items-center gap-1.5 whitespace-nowrap rounded-full px-3.5 text-sm transition-colors', 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-blue-500 focus-visible:ring-offset-1', active
|
|
219981
|
+
? 'bg-blue-600 font-semibold text-white dark:bg-blue-500 dark:text-white'
|
|
219982
|
+
: 'border border-gray-200 bg-white font-medium text-gray-700 hover:bg-gray-50 dark:border-gray-700 dark:bg-gray-900 dark:text-gray-300'), children: [jsx(Icon, { className: "h-3.5 w-3.5", "aria-hidden": true }), jsx("span", { children: item.label })] }, item.id));
|
|
219983
|
+
}) }) }));
|
|
219984
|
+
}
|
|
219985
|
+
/** Small uppercase chip under the identity card (role, platform key). */
|
|
219986
|
+
function SettingsChip({ children, tone = 'neutral', icon: Icon, }) {
|
|
219987
|
+
return (jsxs("span", { className: cn('inline-flex items-center gap-1 rounded-md px-2 py-0.5 text-xs font-semibold', tone === 'accent'
|
|
219988
|
+
? 'bg-blue-50 text-blue-700 dark:bg-blue-950 dark:text-blue-300'
|
|
219989
|
+
: 'bg-gray-100 text-gray-600 tracking-wide dark:bg-gray-800 dark:text-gray-300'), children: [Icon && jsx(Icon, { className: "h-3 w-3", "aria-hidden": true }), children] }));
|
|
219990
|
+
}
|
|
219991
|
+
function SettingsShell({ sidebarHeader, sidebarNav, mobileHeader, mobileNav, title, description, panelProps, footer, overlays, children, }) {
|
|
219992
|
+
const { className: panelClassName, ...restPanelProps } = panelProps !== null && panelProps !== void 0 ? panelProps : {};
|
|
219993
|
+
return (jsxs("div", { className: "flex h-full min-h-0 flex-col bg-white dark:bg-gray-950 lg:flex-row", children: [jsx("div", { className: "border-b border-gray-200 py-3 pl-4 pr-14 dark:border-gray-800 sm:pl-6 lg:hidden", children: mobileHeader }), mobileNav, jsxs("aside", { className: "hidden h-full w-[280px] flex-shrink-0 flex-col overflow-hidden border-r border-gray-200 bg-gray-50 dark:border-gray-800 dark:bg-gray-900 lg:flex", children: [jsx("div", { className: "flex-shrink-0 border-b border-gray-200 px-5 pb-4 pt-6 dark:border-gray-800", children: sidebarHeader }), sidebarNav] }), jsxs("div", { className: "flex min-h-0 min-w-0 flex-1 flex-col overflow-hidden", children: [jsxs("div", { className: "hidden flex-shrink-0 border-b border-gray-200 py-5 pl-8 pr-16 dark:border-gray-800 lg:block", children: [jsx("h3", { className: "text-xl font-semibold tracking-tight text-gray-900 dark:text-gray-100", children: title }), description && (jsx("p", { className: "mt-1 text-sm text-gray-500 dark:text-gray-400", children: description }))] }), jsxs("div", { className: cn('min-h-0 flex-1 overflow-y-auto overflow-x-hidden px-4 py-5 sm:px-6 lg:px-8 lg:py-6', panelClassName), ...restPanelProps, children: [jsxs("div", { className: "mb-5 lg:hidden", children: [jsx("h3", { className: "text-lg font-semibold text-gray-900 dark:text-gray-100", children: title }), description && (jsx("p", { className: "mt-1 text-sm text-gray-500 dark:text-gray-400", children: description }))] }), children] }), footer && (jsx("div", { className: "flex-shrink-0 border-t border-gray-200 bg-white px-4 py-3 dark:border-gray-800 dark:bg-gray-950 sm:px-6 lg:px-8 lg:py-4", children: footer }))] }), overlays] }));
|
|
219994
|
+
}
|
|
219995
|
+
|
|
218805
219996
|
const COWORK_ENABLED_KEY = 'ibl_cowork_enabled';
|
|
218806
219997
|
/**
|
|
218807
219998
|
* Whether Cowork is enabled, read from localStorage. This is a user preference
|
|
@@ -218822,10 +220013,7 @@ function setCoworkEnabled(enabled) {
|
|
|
218822
220013
|
localStorage.setItem(COWORK_ENABLED_KEY, String(enabled));
|
|
218823
220014
|
}
|
|
218824
220015
|
|
|
218825
|
-
const
|
|
218826
|
-
return jsx(Icon, { ...props });
|
|
218827
|
-
};
|
|
218828
|
-
const TAB_DESC_KEYS = {
|
|
220016
|
+
const TAB_DESC_KEYS$1 = {
|
|
218829
220017
|
basic: 'descBasic',
|
|
218830
220018
|
social: 'descSocial',
|
|
218831
220019
|
education: 'descEducation',
|
|
@@ -218835,6 +220023,7 @@ const TAB_DESC_KEYS = {
|
|
|
218835
220023
|
memory: 'descMemory',
|
|
218836
220024
|
privacy: 'descPrivacy',
|
|
218837
220025
|
chatHistory: 'descChatHistory',
|
|
220026
|
+
llmUsage: 'descLlmUsage',
|
|
218838
220027
|
security: 'descSecurity',
|
|
218839
220028
|
advanced: 'descAdvanced',
|
|
218840
220029
|
};
|
|
@@ -218849,9 +220038,13 @@ const TAB_DESC_PREVIEW_KEYS = {
|
|
|
218849
220038
|
memory: 'descMemoryPreview',
|
|
218850
220039
|
privacy: 'descPrivacyPreview',
|
|
218851
220040
|
chatHistory: 'descChatHistoryPreview',
|
|
220041
|
+
llmUsage: 'descLlmUsagePreview',
|
|
218852
220042
|
};
|
|
218853
|
-
|
|
218854
|
-
|
|
220043
|
+
const LABEL_CLASS = 'text-sm font-medium text-gray-700 dark:text-gray-300';
|
|
220044
|
+
const FIELD_CLASS = 'h-10 w-full bg-white border-gray-300 text-sm text-gray-900 focus:ring-blue-500 focus:border-blue-500 dark:bg-gray-900 dark:border-gray-700 dark:text-gray-100';
|
|
220045
|
+
const PRIMARY_BUTTON_CLASS = 'bg-blue-600 text-white hover:bg-blue-700 focus-visible:ring-blue-500 disabled:bg-blue-600/60';
|
|
220046
|
+
function Profile({ tenant, username, tenants, onClose, customization = {}, isAdmin = false, targetTab = 'basic', onAccountDeleted, enableMemoryTab = false, showLlmUsageTab = true, localLLMProps, currentSPA = '', }) {
|
|
220047
|
+
var _a, _b, _c, _d, _e, _f;
|
|
218855
220048
|
const t = useT();
|
|
218856
220049
|
const { data: memsearchStatus, isError: isMemsearchStatusError } = useGetMemsearchStatusQuery({ org: tenant, userId: username }, { skip: !enableMemoryTab });
|
|
218857
220050
|
// Show memory tab if enabled for this platform AND memsearch is enabled (or status API is unavailable)
|
|
@@ -218870,34 +220063,46 @@ function Profile({ tenant, username, tenants, onClose, customization = {}, isAdm
|
|
|
218870
220063
|
const rbacPermissions = useSelector(selectRbacPermissions);
|
|
218871
220064
|
const { currentTenant: viewerTenant } = useCurrentTenant();
|
|
218872
220065
|
const isChatHistoryVisible = !isReadOnly || canViewOtherUsersChatHistory(rbacPermissions, viewerTenant);
|
|
218873
|
-
|
|
218874
|
-
|
|
218875
|
-
|
|
220066
|
+
// Usage is always read for the profile on screen, so it works while
|
|
220067
|
+
// previewing someone else too — the backend decides whether this viewer may
|
|
220068
|
+
// see their rows, and answers 403 when they may not. A pure watcher (the
|
|
220069
|
+
// `/watchedgroups/#list` permission without tenant admin) is kept out of
|
|
220070
|
+
// cost reporting entirely, the same way the analytics tabs exclude them.
|
|
220071
|
+
const isLlmUsageVisible = showLlmUsageTab && !isPureWatcher(rbacPermissions, viewerTenant);
|
|
220072
|
+
// Add Advanced tab only when in Tauri app (Local Models is provided and available)
|
|
220073
|
+
const isAdvancedAvailable = (localLLMProps === null || localLLMProps === void 0 ? void 0 : localLLMProps.isAvailable) === true;
|
|
220074
|
+
const TABS = [
|
|
220075
|
+
{ id: 'basic', label: t('profileIndex.tabBasic'), icon: User, group: 'profile' },
|
|
220076
|
+
{ id: 'social', label: t('profileIndex.tabSocial'), icon: Globe, group: 'profile' },
|
|
218876
220077
|
...(isGradebookEnabled
|
|
218877
220078
|
? [
|
|
218878
220079
|
{
|
|
218879
220080
|
id: 'gradebook',
|
|
218880
220081
|
label: t('profileIndex.tabGradebook'),
|
|
218881
|
-
|
|
220082
|
+
icon: GraduationCap,
|
|
220083
|
+
group: 'records',
|
|
218882
220084
|
},
|
|
218883
220085
|
]
|
|
218884
220086
|
: []),
|
|
218885
220087
|
{
|
|
218886
220088
|
id: 'education',
|
|
218887
220089
|
label: t('profileIndex.tabEducation'),
|
|
218888
|
-
|
|
220090
|
+
icon: BookOpen,
|
|
220091
|
+
group: 'records',
|
|
218889
220092
|
},
|
|
218890
220093
|
{
|
|
218891
220094
|
id: 'experience',
|
|
218892
220095
|
label: t('profileIndex.tabExperience'),
|
|
218893
|
-
|
|
220096
|
+
icon: Briefcase,
|
|
220097
|
+
group: 'records',
|
|
218894
220098
|
},
|
|
218895
220099
|
...(isPurchasesEnabled
|
|
218896
220100
|
? [
|
|
218897
220101
|
{
|
|
218898
220102
|
id: 'purchases',
|
|
218899
220103
|
label: t('profileIndex.tabPurchases'),
|
|
218900
|
-
|
|
220104
|
+
icon: ShoppingBag,
|
|
220105
|
+
group: 'records',
|
|
218901
220106
|
},
|
|
218902
220107
|
]
|
|
218903
220108
|
: []),
|
|
@@ -218906,20 +220111,23 @@ function Profile({ tenant, username, tenants, onClose, customization = {}, isAdm
|
|
|
218906
220111
|
{
|
|
218907
220112
|
id: 'memory',
|
|
218908
220113
|
label: t('profileIndex.tabMemory'),
|
|
218909
|
-
|
|
220114
|
+
icon: Archive,
|
|
220115
|
+
group: 'aiData',
|
|
218910
220116
|
},
|
|
218911
220117
|
]
|
|
218912
220118
|
: []),
|
|
218913
220119
|
// id stays as 'privacy' so callers passing `targetTab='privacy'` and
|
|
218914
220120
|
// any test selectors targeting #panel-privacy keep working. The
|
|
218915
220121
|
// user-visible `label` is "Privacy"; the chat-privacy feature itself
|
|
218916
|
-
// is still called "Private Mode" within the tab's content.
|
|
220122
|
+
// is still called "Private Mode" within the tab's content. It sits with
|
|
220123
|
+
// the account controls, just above Security.
|
|
218917
220124
|
...(isChatPrivacyEnabled
|
|
218918
220125
|
? [
|
|
218919
220126
|
{
|
|
218920
220127
|
id: 'privacy',
|
|
218921
220128
|
label: t('profileIndex.tabPrivacy'),
|
|
218922
|
-
|
|
220129
|
+
icon: Lock,
|
|
220130
|
+
group: 'account',
|
|
218923
220131
|
},
|
|
218924
220132
|
]
|
|
218925
220133
|
: []),
|
|
@@ -218928,7 +220136,18 @@ function Profile({ tenant, username, tenants, onClose, customization = {}, isAdm
|
|
|
218928
220136
|
{
|
|
218929
220137
|
id: 'chatHistory',
|
|
218930
220138
|
label: t('profileIndex.tabChatHistory'),
|
|
218931
|
-
|
|
220139
|
+
icon: History,
|
|
220140
|
+
group: 'aiData',
|
|
220141
|
+
},
|
|
220142
|
+
]
|
|
220143
|
+
: []),
|
|
220144
|
+
...(isLlmUsageVisible
|
|
220145
|
+
? [
|
|
220146
|
+
{
|
|
220147
|
+
id: 'llmUsage',
|
|
220148
|
+
label: t('profileIndex.tabLlmUsage'),
|
|
220149
|
+
icon: Gauge,
|
|
220150
|
+
group: 'aiData',
|
|
218932
220151
|
},
|
|
218933
220152
|
]
|
|
218934
220153
|
: []),
|
|
@@ -218937,24 +220156,33 @@ function Profile({ tenant, username, tenants, onClose, customization = {}, isAdm
|
|
|
218937
220156
|
{
|
|
218938
220157
|
id: 'security',
|
|
218939
220158
|
label: t('profileIndex.tabSecurity'),
|
|
218940
|
-
|
|
220159
|
+
icon: Shield,
|
|
220160
|
+
group: 'account',
|
|
220161
|
+
},
|
|
220162
|
+
]
|
|
220163
|
+
: []),
|
|
220164
|
+
...(isAdvancedAvailable
|
|
220165
|
+
? [
|
|
220166
|
+
{
|
|
220167
|
+
id: 'advanced',
|
|
220168
|
+
label: t('profileIndex.tabAdvanced'),
|
|
220169
|
+
icon: Settings$1,
|
|
220170
|
+
group: 'account',
|
|
218941
220171
|
},
|
|
218942
220172
|
]
|
|
218943
220173
|
: []),
|
|
218944
220174
|
];
|
|
218945
|
-
|
|
218946
|
-
|
|
218947
|
-
|
|
218948
|
-
|
|
218949
|
-
|
|
218950
|
-
|
|
218951
|
-
|
|
218952
|
-
|
|
218953
|
-
|
|
218954
|
-
|
|
218955
|
-
|
|
218956
|
-
: baseTabs;
|
|
218957
|
-
const RoleIcon = renderLucideIcon(User);
|
|
220175
|
+
const GROUP_LABELS = {
|
|
220176
|
+
profile: t('profileIndex.groupProfile'),
|
|
220177
|
+
records: t('profileIndex.groupRecords'),
|
|
220178
|
+
aiData: t('profileIndex.groupAiData'),
|
|
220179
|
+
account: t('profileIndex.groupAccount'),
|
|
220180
|
+
};
|
|
220181
|
+
const navGroups = Object.keys(GROUP_LABELS).map((group) => ({
|
|
220182
|
+
id: group,
|
|
220183
|
+
label: GROUP_LABELS[group],
|
|
220184
|
+
items: TABS.filter((tab) => tab.group === group),
|
|
220185
|
+
}));
|
|
218958
220186
|
const [activeTab, setActiveTab] = useState(targetTab);
|
|
218959
220187
|
const [isHovering, setIsHovering] = useState(false);
|
|
218960
220188
|
const fileInputRef = useRef(null);
|
|
@@ -218976,8 +220204,7 @@ function Profile({ tenant, username, tenants, onClose, customization = {}, isAdm
|
|
|
218976
220204
|
};
|
|
218977
220205
|
// The picture itself, with no editing affordance around it. The wrapper
|
|
218978
220206
|
// below decides whether it is clickable.
|
|
218979
|
-
const profileAvatar = (jsxs(Avatar, { className: "h-
|
|
218980
|
-
!((_d = userMetadataEdx === null || userMetadataEdx === void 0 ? void 0 : userMetadataEdx.profile_image) === null || _d === void 0 ? void 0 : _d.image_url_full)
|
|
220207
|
+
const profileAvatar = (jsxs(Avatar, { className: "h-14 w-14", children: [((_b = userMetadataEdx === null || userMetadataEdx === void 0 ? void 0 : userMetadataEdx.profile_image) === null || _b === void 0 ? void 0 : _b.has_image) ? (jsx(AvatarImage, { src: (_c = userMetadataEdx === null || userMetadataEdx === void 0 ? void 0 : userMetadataEdx.profile_image) === null || _c === void 0 ? void 0 : _c.image_url_full, alt: t('profileIndex.altProfilePicture'), className: "rounded-full object-cover w-full h-full group-hover:opacity-80 transition-opacity" })) : customization.useGravatarPicFallback ? (jsx(Gravatar, { className: "w-full h-full rounded-full object-cover group-hover:opacity-80 transition-opacity", email: userMetadata === null || userMetadata === void 0 ? void 0 : userMetadata.email, size: 56, alt: t('profileIndex.altProfilePictureGravatar') })) : (jsx(Fragment$1, {})), jsx(AvatarFallback, { className: cn('bg-blue-800 text-white text-lg font-semibold rounded-full', customization.useGravatarPicFallback && !((_d = userMetadataEdx === null || userMetadataEdx === void 0 ? void 0 : userMetadataEdx.profile_image) === null || _d === void 0 ? void 0 : _d.image_url_full)
|
|
218981
220208
|
? 'hidden'
|
|
218982
220209
|
: ''), children: getInitials((userMetadata === null || userMetadata === void 0 ? void 0 : userMetadata.name) || (userMetadata === null || userMetadata === void 0 ? void 0 : userMetadata.username) || (userMetadata === null || userMetadata === void 0 ? void 0 : userMetadata.email) || '') })] }));
|
|
218983
220210
|
const handleFileUpload = (event) => {
|
|
@@ -219022,115 +220249,122 @@ function Profile({ tenant, username, tenants, onClose, customization = {}, isAdm
|
|
|
219022
220249
|
// Rendered inline on the sub-tabs row (education/experience/resume), pushed to
|
|
219023
220250
|
// the far right. `headerAdd` already encodes which sub-tab is active, so this
|
|
219024
220251
|
// only appears on the sub-tabs that support adding/uploading.
|
|
219025
|
-
const headerAddButton = headerAdd && (
|
|
220252
|
+
const headerAddButton = headerAdd && (jsxs(Button$1, { size: "sm", onClick: headerAdd.onClick, className: cn('h-9 flex-shrink-0 gap-1.5 px-3', PRIMARY_BUTTON_CLASS), "aria-label": headerAdd.ariaLabel, children: [headerAdd.upload ? (jsx(Upload, { className: "h-4 w-4", "aria-hidden": "true" })) : (jsx(Plus, { className: "h-4 w-4", "aria-hidden": "true" })), jsx("span", { className: "hidden sm:inline", children: headerAdd.ariaLabel })] }));
|
|
219026
220253
|
const tabDescription = (id) => {
|
|
219027
|
-
const key = (isReadOnly && TAB_DESC_PREVIEW_KEYS[id]) || TAB_DESC_KEYS[id];
|
|
220254
|
+
const key = (isReadOnly && TAB_DESC_PREVIEW_KEYS[id]) || TAB_DESC_KEYS$1[id];
|
|
219028
220255
|
return key ? t(`profileIndex.${key}`) : '';
|
|
219029
220256
|
};
|
|
219030
|
-
|
|
219031
|
-
|
|
219032
|
-
|
|
219033
|
-
|
|
219034
|
-
|
|
219035
|
-
|
|
219036
|
-
|
|
219037
|
-
|
|
219038
|
-
|
|
219039
|
-
|
|
219040
|
-
|
|
219041
|
-
|
|
219042
|
-
|
|
219043
|
-
|
|
219044
|
-
|
|
219045
|
-
|
|
219046
|
-
|
|
219047
|
-
|
|
219048
|
-
|
|
219049
|
-
|
|
219050
|
-
|
|
219051
|
-
|
|
219052
|
-
|
|
219053
|
-
|
|
219054
|
-
|
|
219055
|
-
|
|
219056
|
-
|
|
219057
|
-
|
|
219058
|
-
|
|
219059
|
-
|
|
219060
|
-
|
|
219061
|
-
|
|
219062
|
-
|
|
219063
|
-
|
|
219064
|
-
|
|
219065
|
-
|
|
219066
|
-
|
|
219067
|
-
|
|
219068
|
-
|
|
219069
|
-
|
|
219070
|
-
|
|
219071
|
-
|
|
219072
|
-
|
|
219073
|
-
|
|
219074
|
-
|
|
219075
|
-
|
|
219076
|
-
|
|
219077
|
-
|
|
219078
|
-
|
|
219079
|
-
|
|
219080
|
-
|
|
219081
|
-
|
|
219082
|
-
|
|
219083
|
-
|
|
219084
|
-
|
|
219085
|
-
|
|
219086
|
-
|
|
219087
|
-
|
|
219088
|
-
|
|
219089
|
-
|
|
219090
|
-
|
|
219091
|
-
|
|
219092
|
-
|
|
219093
|
-
|
|
219094
|
-
|
|
219095
|
-
|
|
219096
|
-
|
|
219097
|
-
|
|
219098
|
-
|
|
219099
|
-
|
|
219100
|
-
|
|
219101
|
-
|
|
219102
|
-
|
|
219103
|
-
|
|
219104
|
-
|
|
219105
|
-
|
|
219106
|
-
|
|
219107
|
-
|
|
219108
|
-
|
|
219109
|
-
|
|
219110
|
-
|
|
219111
|
-
|
|
219112
|
-
|
|
219113
|
-
|
|
219114
|
-
|
|
219115
|
-
|
|
219116
|
-
|
|
219117
|
-
|
|
219118
|
-
|
|
219119
|
-
|
|
219120
|
-
|
|
219121
|
-
|
|
219122
|
-
|
|
219123
|
-
|
|
219124
|
-
|
|
219125
|
-
|
|
219126
|
-
|
|
219127
|
-
|
|
219128
|
-
|
|
219129
|
-
|
|
219130
|
-
|
|
219131
|
-
|
|
219132
|
-
|
|
219133
|
-
|
|
220257
|
+
const email = (userMetadata === null || userMetadata === void 0 ? void 0 : userMetadata.email) || '';
|
|
220258
|
+
const displayName = (userMetadata === null || userMetadata === void 0 ? void 0 : userMetadata.name) || (userMetadata === null || userMetadata === void 0 ? void 0 : userMetadata.username) || email;
|
|
220259
|
+
const roleChip = (jsx(SettingsChip, { tone: "accent", icon: User, children: isAdmin ? t('profileIndex.roleAdmin') : t('profileIndex.roleUser') }));
|
|
220260
|
+
const platformChip = customization.showPlatformName ? (jsx(SettingsChip, { children: tenant.toUpperCase() })) : null;
|
|
220261
|
+
const avatarBlock = isUserMetadataEdxLoading || isUploadingProfileImage ? (jsx(Skeleton, { className: "h-14 w-14 flex-shrink-0 rounded-full", "aria-label": t('profileIndex.ariaLoadingProfileImage') })) : isReadOnly ? (
|
|
220262
|
+
// Someone else's profile: show the picture, offer no way to replace it.
|
|
220263
|
+
jsx("div", { className: "relative h-14 w-14 flex-shrink-0 rounded-full", children: profileAvatar })) : (jsxs("button", { type: "button", className: "group relative h-14 w-14 flex-shrink-0 cursor-pointer rounded-full focus:outline-none focus-visible:ring-2 focus-visible:ring-blue-500 focus-visible:ring-offset-2", onMouseEnter: () => setIsHovering(true), onMouseLeave: () => setIsHovering(false), onClick: handleAvatarClick, "aria-label": t('profileIndex.ariaUploadProfilePicture'), children: [profileAvatar, isHovering && (jsx("div", { className: "absolute inset-0 flex items-center justify-center rounded-full bg-blue-900/80", "aria-hidden": "true", children: jsx("span", { className: "px-1 text-center text-[11px] font-semibold text-white", children: t('profileIndex.uploadOverlay') }) })), jsx("span", { className: "absolute -bottom-0.5 -right-0.5 flex h-6 w-6 items-center justify-center rounded-full border border-gray-200 bg-white text-gray-700 shadow-sm dark:border-gray-700 dark:bg-gray-800 dark:text-gray-200", "aria-hidden": "true", children: jsx(Camera, { className: "h-3 w-3" }) }), jsx("input", { ref: fileInputRef, type: "file", accept: "image/*", onChange: handleFileUpload, className: "hidden", "aria-label": t('profileIndex.ariaChooseProfilePicture'), tabIndex: -1 })] }));
|
|
220264
|
+
const sidebarHeader = (jsxs("div", { className: "flex flex-col gap-3", children: [jsxs("div", { className: "flex items-center gap-3", children: [avatarBlock, jsxs("div", { className: "min-w-0 space-y-1", children: [jsx("h2", { className: "truncate text-[15px] font-semibold text-gray-900 dark:text-gray-100", title: displayName, children: displayName }), jsxs("div", { className: "flex flex-wrap gap-1.5", children: [roleChip, platformChip] })] })] }), email && email !== displayName && (jsx("p", { className: "break-all text-[13px] leading-snug text-gray-500 dark:text-gray-400", title: email, children: email }))] }));
|
|
220265
|
+
// Name only: the email already sits in the sidebar card, which small
|
|
220266
|
+
// screens hide, and the dialog title covers the rest.
|
|
220267
|
+
const mobileHeader = (jsx("p", { className: "truncate text-[15px] font-semibold text-gray-900 dark:text-gray-100", children: (userMetadata === null || userMetadata === void 0 ? void 0 : userMetadata.name) || (userMetadata === null || userMetadata === void 0 ? void 0 : userMetadata.username) || t('profileIndex.profileHeading') }));
|
|
220268
|
+
const isBusyBasic = basicForm.state.isSubmitting || isUserMetadataLoading || isReadOnly;
|
|
220269
|
+
const footer = !isReadOnly && ['basic', 'social'].includes(activeTab) ? (jsxs("div", { className: "flex justify-end gap-3", children: [jsx(Button$1, { onClick: onClose, variant: "outline", className: "h-10 px-4", children: t('profileIndex.buttonCancel') }), jsx(Button$1, { onClick: () => {
|
|
220270
|
+
if (activeTab === 'basic') {
|
|
220271
|
+
basicForm.handleSubmit();
|
|
220272
|
+
}
|
|
220273
|
+
else if (activeTab === 'social') {
|
|
220274
|
+
socialForm.handleSubmit();
|
|
220275
|
+
}
|
|
220276
|
+
}, className: cn('h-10 px-5', PRIMARY_BUTTON_CLASS), disabled: (activeTab === 'basic' && (basicForm.state.isSubmitting || isUserMetadataLoading)) ||
|
|
220277
|
+
(activeTab === 'social' && socialForm.state.isSubmitting), children: (activeTab === 'basic' && basicForm.state.isSubmitting) ||
|
|
220278
|
+
(activeTab === 'social' && socialForm.state.isSubmitting)
|
|
220279
|
+
? t('profileIndex.buttonSaving')
|
|
220280
|
+
: t('profileIndex.buttonSaveChanges') })] })) : null;
|
|
220281
|
+
const socialField = ({ id, name, label, placeholder, prefix, badge, validator, }) => (jsxs("div", { className: "space-y-1.5", children: [jsx("label", { htmlFor: id, className: LABEL_CLASS, children: label }), socialForm.Field({
|
|
220282
|
+
name,
|
|
220283
|
+
validators: {
|
|
220284
|
+
onChange: validator,
|
|
220285
|
+
},
|
|
220286
|
+
children: (field) => {
|
|
220287
|
+
var _a;
|
|
220288
|
+
return (jsxs(Fragment$1, { children: [jsxs("div", { className: "relative mb-0", children: [jsx("div", { className: "pointer-events-none absolute inset-y-0 left-2 flex items-center", "aria-hidden": "true", children: jsx("div", { className: cn('flex h-7 w-7 items-center justify-center rounded-md text-white', badge.className), children: jsx("span", { className: cn('font-bold', badge.textClassName), children: badge.text }) }) }), jsx(Input, { id: id, className: cn(FIELD_CLASS, 'pl-12'), placeholder: placeholder, value: field.state.value, onChange: (e) => handleSocialLinkChange(e.target.value, field.handleChange, prefix), disabled: socialForm.state.isSubmitting || isReadOnly })] }), jsx("p", { className: "text-sm text-red-600 dark:text-red-400", role: ((_a = field.state.meta.errors) === null || _a === void 0 ? void 0 : _a.length) ? 'alert' : undefined, "aria-live": "polite", children: field.state.meta.errors })] }));
|
|
220289
|
+
},
|
|
220290
|
+
})] }));
|
|
220291
|
+
return (jsxs(SettingsShell, { sidebarHeader: sidebarHeader, sidebarNav: jsx(SettingsSidebarNav, { groups: navGroups, activeId: activeTab, onSelect: setActiveTab, variant: "tabs", ariaLabel: t('profileIndex.ariaProfileTabs') }), mobileHeader: mobileHeader, mobileNav: jsx(SettingsMobileNav, { groups: navGroups, activeId: activeTab, onSelect: setActiveTab, variant: "tabs", ariaLabel: t('profileIndex.ariaProfileTabsMobile') }),
|
|
220292
|
+
// Render the tab's label rather than the id — every label is already
|
|
220293
|
+
// cased correctly.
|
|
220294
|
+
title: (_f = (_e = TABS.find((tab) => tab.id === activeTab)) === null || _e === void 0 ? void 0 : _e.label) !== null && _f !== void 0 ? _f : activeTab, description: tabDescription(activeTab), panelProps: {
|
|
220295
|
+
role: 'tabpanel',
|
|
220296
|
+
id: `${activeTab}-tabpanel`,
|
|
220297
|
+
'aria-labelledby': `${activeTab}-tab`,
|
|
220298
|
+
tabIndex: 0,
|
|
220299
|
+
}, footer: footer, overlays: jsxs(Fragment$1, { children: [jsx(EducationDialog, { open: isEducationDialogOpen, onOpenChange: setIsEducationDialogOpen, education: undefined, org: tenant, username: username, onComplete: () => {
|
|
220300
|
+
// The education tab will handle refetching
|
|
220301
|
+
} }), jsx(ExperienceDialog, { open: isExperienceDialogOpen, onOpenChange: setIsExperienceDialogOpen, experience: undefined, org: tenant, username: username, onComplete: () => {
|
|
220302
|
+
// The experience tab will handle refetching
|
|
220303
|
+
} }), jsx(ToastProvider, {})] }), children: [activeTab === 'basic' && (jsxs("form", { onSubmit: (formEvent) => {
|
|
220304
|
+
formEvent.preventDefault();
|
|
220305
|
+
formEvent.stopPropagation();
|
|
220306
|
+
if (isReadOnly)
|
|
220307
|
+
return;
|
|
220308
|
+
basicForm.handleSubmit();
|
|
220309
|
+
}, className: "max-w-3xl space-y-8", children: [jsxs("div", { className: "grid grid-cols-1 gap-x-5 gap-y-5 md:grid-cols-2", children: [jsxs("div", { className: "space-y-1.5", children: [jsx("label", { htmlFor: "fullName", className: LABEL_CLASS, children: t('profileIndex.labelFullName') }), basicForm.Field({
|
|
220310
|
+
name: 'fullName',
|
|
220311
|
+
validators: {
|
|
220312
|
+
onChange: basicValidators.fullName,
|
|
220313
|
+
onSubmit: basicValidators.fullName,
|
|
220314
|
+
},
|
|
220315
|
+
children: (field) => {
|
|
220316
|
+
var _a;
|
|
220317
|
+
return (jsxs(Fragment$1, { children: [jsx(Input, { id: "fullName", className: FIELD_CLASS, value: field.state.value, onChange: (e) => field.handleChange(e.target.value), disabled: isBusyBasic }), ((_a = field.state.meta.errors) === null || _a === void 0 ? void 0 : _a.length) > 0 && (jsx("p", { className: "mt-1 text-sm text-red-600 dark:text-red-400", role: "alert", children: field.state.meta.errors }))] }));
|
|
220318
|
+
},
|
|
220319
|
+
})] }), jsxs("div", { className: "space-y-1.5", children: [jsx("label", { htmlFor: "email", className: LABEL_CLASS, children: t('profileIndex.labelEmail') }), basicForm.Field({
|
|
220320
|
+
name: 'email',
|
|
220321
|
+
children: (field) => (jsx(Input, { id: "email", type: "email", className: FIELD_CLASS, value: field.state.value, onChange: (e) => field.handleChange(e.target.value), disabled: isBusyBasic })),
|
|
220322
|
+
})] }), customization.showUsernameField && (jsxs("div", { className: "space-y-1.5", children: [jsx("label", { htmlFor: "username", className: LABEL_CLASS, children: t('profileIndex.labelUsername') }), basicForm.Field({
|
|
220323
|
+
name: 'username',
|
|
220324
|
+
children: (field) => (jsx(Input, { id: "username", className: FIELD_CLASS, value: field.state.value, onChange: (e) => field.handleChange(e.target.value), disabled: isBusyBasic })),
|
|
220325
|
+
})] })), jsxs("div", { className: "space-y-1.5", children: [jsx("label", { htmlFor: "title", className: LABEL_CLASS, children: t('profileIndex.labelTitle') }), basicForm.Field({
|
|
220326
|
+
name: 'title',
|
|
220327
|
+
children: (field) => (jsx(Input, { id: "title", className: FIELD_CLASS, value: field.state.value, onChange: (e) => field.handleChange(e.target.value), disabled: isBusyBasic })),
|
|
220328
|
+
})] }), jsxs("div", { className: "space-y-1.5", children: [jsx("label", { htmlFor: "language", className: LABEL_CLASS, children: t('profileIndex.labelLanguage') }), basicForm.Field({
|
|
220329
|
+
name: 'language',
|
|
220330
|
+
children: (field) => (jsxs(Select$1, { defaultValue: field.state.value, onValueChange: (value) => field.handleChange(value), disabled: isBusyBasic, children: [jsx(SelectTrigger, { id: "language", className: FIELD_CLASS, "aria-label": t('profileIndex.selectLanguagePlaceholder'), children: jsx(SelectValue, { placeholder: t('profileIndex.selectLanguagePlaceholder') }) }), jsxs(SelectContent, { children: [jsx(SelectItem, { value: "en", children: t('profileIndex.langEnglish') }), jsx(SelectItem, { value: "es", children: t('profileIndex.langSpanish') }), jsx(SelectItem, { value: "fr", children: t('profileIndex.langFrench') })] })] })),
|
|
220331
|
+
})] }), jsxs("div", { className: "space-y-1.5 md:col-span-2", children: [jsx("label", { htmlFor: "about", className: LABEL_CLASS, children: t('profileIndex.labelAbout') }), basicForm.Field({
|
|
220332
|
+
name: 'about',
|
|
220333
|
+
children: (field) => (jsx(Textarea, { id: "about", placeholder: t('profileIndex.placeholderAbout'), className: cn(FIELD_CLASS, 'h-auto resize-none py-2.5 leading-relaxed'), rows: 4, value: field.state.value, onChange: (e) => field.handleChange(e.target.value), disabled: isBusyBasic })),
|
|
220334
|
+
})] })] }), customization.showMentorAIDisplayCheckbox && (jsxs("section", { className: "space-y-2.5", "aria-labelledby": "profile-features-heading", children: [jsx("h4", { id: "profile-features-heading", className: "text-sm font-semibold text-gray-900 dark:text-gray-100", children: t('profileIndex.sectionFeatures') }), jsx("div", { className: "divide-y divide-gray-200 rounded-xl border border-gray-200 dark:divide-gray-800 dark:border-gray-800", children: jsxs("div", { className: "flex items-center justify-between gap-4 px-4 py-3.5", children: [jsxs("div", { className: "flex min-w-0 items-center gap-1", children: [jsx("label", { htmlFor: "display-mentor", className: "text-sm font-medium text-gray-700 peer-disabled:cursor-not-allowed peer-disabled:opacity-70 dark:text-gray-300", children: t('profileIndex.checkboxDisplayMentorAI') }), jsx(CardInfoIcon, { description: t('profileIndex.tooltipDisplayMentorAI') })] }), basicForm.Field({
|
|
220335
|
+
name: 'displayMentor',
|
|
220336
|
+
children: (field) => (jsx(Switch, { className: "data-[state=checked]:bg-blue-600", onCheckedChange: (checked) => field.handleChange(checked), checked: field.state.value, disabled: isBusyBasic, id: "display-mentor" })),
|
|
220337
|
+
})] }) })] }))] })), activeTab === 'social' && (jsxs("form", { className: "max-w-2xl space-y-5", onSubmit: (formEvent) => {
|
|
220338
|
+
formEvent.preventDefault();
|
|
220339
|
+
formEvent.stopPropagation();
|
|
220340
|
+
if (isReadOnly)
|
|
220341
|
+
return;
|
|
220342
|
+
socialForm.handleSubmit();
|
|
220343
|
+
}, children: [socialField({
|
|
220344
|
+
id: 'facebook',
|
|
220345
|
+
name: 'facebook',
|
|
220346
|
+
label: t('profileIndex.labelFacebook'),
|
|
220347
|
+
placeholder: t('profileIndex.placeholderFacebook'),
|
|
220348
|
+
prefix: FACEBOOK_URL_PREFIX,
|
|
220349
|
+
badge: { className: 'bg-[#1877F2]', text: 'f', textClassName: 'text-sm' },
|
|
220350
|
+
validator: socialValidators.facebook,
|
|
220351
|
+
}), socialField({
|
|
220352
|
+
id: 'linkedin',
|
|
220353
|
+
name: 'linkedIn',
|
|
220354
|
+
label: t('profileIndex.labelLinkedIn'),
|
|
220355
|
+
placeholder: t('profileIndex.placeholderLinkedIn'),
|
|
220356
|
+
prefix: LINKEDIN_URL_PREFIX,
|
|
220357
|
+
badge: { className: 'bg-[#0A66C2]', text: 'in', textClassName: 'text-xs' },
|
|
220358
|
+
validator: socialValidators.linkedIn,
|
|
220359
|
+
}), socialField({
|
|
220360
|
+
id: 'x',
|
|
220361
|
+
name: 'x',
|
|
220362
|
+
label: t('profileIndex.labelX'),
|
|
220363
|
+
placeholder: t('profileIndex.placeholderX'),
|
|
220364
|
+
prefix: X_URL_PREFIX,
|
|
220365
|
+
badge: { className: 'bg-black', text: 'X', textClassName: 'text-sm' },
|
|
220366
|
+
validator: socialValidators.x,
|
|
220367
|
+
})] })), activeTab === 'education' && (jsxs(Tabs, { value: educationSubTab, onValueChange: setEducationSubTab, className: "space-y-4", children: [jsxs("div", { className: "flex items-center justify-between gap-3", children: [jsxs(TabsList, { children: [jsx(TabsTrigger, { value: "education", children: t('profileIndex.tabEducation') }), jsx(TabsTrigger, { value: "credentials", children: t('gradebookGradebookTab.typeCredentials') }), jsx(TabsTrigger, { value: "skills", children: t('gradebookGradebookTab.typeSkills') })] }), headerAddButton] }), jsx(TabsContent, { value: "education", children: jsx(EducationTab, { org: tenant, username: username }) }), jsx(TabsContent, { value: "credentials", children: jsx(CredentialsList, { org: tenant, username: username }) }), jsx(TabsContent, { value: "skills", children: jsx(SkillsList, { org: tenant, username: username }) })] })), activeTab === 'gradebook' && jsx(GradebookTab, { org: tenant, username: username }), activeTab === 'experience' && (jsxs(Tabs, { value: experienceSubTab, onValueChange: setExperienceSubTab, className: "space-y-4", children: [jsxs("div", { className: "flex items-center justify-between gap-3", children: [jsxs(TabsList, { children: [jsx(TabsTrigger, { value: "experience", children: t('profileIndex.tabExperience') }), jsx(TabsTrigger, { value: "resume", children: t('profileIndex.tabResume') })] }), headerAddButton] }), jsx(TabsContent, { value: "experience", children: jsx(ExperienceTab, { org: tenant, username: username }) }), jsx(TabsContent, { value: "resume", children: jsx(ResumeTab, { org: tenant, username: username }) })] })), activeTab === 'purchases' && jsx(PurchasesTab, { org: tenant, username: username }), activeTab === 'memory' && jsx(MemoryTab, { org: tenant, username: username }), activeTab === 'privacy' && jsx(ChatPrivacyTab, { org: tenant, username: username }), isChatHistoryVisible && activeTab === 'chatHistory' && (jsx(ChatHistoryTab, { org: tenant, username: username })), isLlmUsageVisible && activeTab === 'llmUsage' && (jsx(LlmUsageTab, { org: tenant, username: username, isOwnProfile: !isReadOnly })), !isReadOnly && activeTab === 'security' && (jsx(Security, { app: currentSPA || '', email: (userMetadata === null || userMetadata === void 0 ? void 0 : userMetadata.email) || '', platformKey: tenant, onAccountDeleted: onAccountDeleted })), activeTab === 'advanced' && localLLMProps && (jsx("div", { className: "space-y-6", children: jsx(LocalModelsContent, { isAvailable: localLLMProps.isAvailable, state: localLLMProps.state, ollamaStatus: localLLMProps.ollamaStatus, systemMemory: localLLMProps.systemMemory, isUsingFoundry: localLLMProps.isUsingFoundry, foundryModels: localLLMProps.foundryModels, selectedFoundryModel: localLLMProps.selectedFoundryModel, foundryStatus: localLLMProps.foundryStatus, onStartDownload: localLLMProps.onStartDownload, onCancelDownload: localLLMProps.onCancelDownload, onInstallOllama: localLLMProps.onInstallOllama, onStopManager: localLLMProps.onStopManager, onInstallFoundry: localLLMProps.onInstallFoundry, onCheckStatus: localLLMProps.onCheckStatus, onResetState: localLLMProps.onResetState, onSelectFoundryModel: localLLMProps.onSelectFoundryModel }) }))] }));
|
|
219134
220368
|
}
|
|
219135
220369
|
|
|
219136
220370
|
function CSVEditor({ csvData, onSave, onCancel }) {
|
|
@@ -220517,6 +221751,624 @@ function InvitedUsersDialog({ tenant, onClose }) {
|
|
|
220517
221751
|
}, children: jsx(DialogPortal, { forceMount: true, children: jsxs(DialogContent, { "aria-label": t('profileInvitedUsers.dialogAriaLabel'), className: "max-w-sm rounded-2xl px-6 py-8 pointer-events-auto", "aria-describedby": "invited-users-dialog", children: [jsx(DialogHeader, { className: "relative flex-row justify-between", children: jsx(DialogTitle, { className: "text-blue-600 text-xl font-semibold", children: t('profileInvitedUsers.title') }) }), jsxs("div", { className: "mt-4 space-y-1", children: [jsx("p", { className: "text-gray-500 text-sm", children: t('profileInvitedUsers.pendingDescription') }), jsx("form", { children: jsx(Input, { value: query, onChange: (event) => setQuery(event.target.value), placeholder: t('profileInvitedUsers.searchPlaceholder'), className: "mt-2" }) })] }), jsxs("div", { children: [jsx("h2", { className: "text-md text-gray-600 font-semibold mb-4", children: t('profileInvitedUsers.emailHeading') }), invitedUsers === null || invitedUsers === void 0 ? void 0 : invitedUsers.results.map((user) => (jsx("div", { className: "border-b-gray-50 pb-2 mb-4 text-sm text-gray-600 dark:text-gray-400", children: user.email }, user.id))), (invitedUsers === null || invitedUsers === void 0 ? void 0 : invitedUsers.results.length) === 0 && (jsx("p", { className: "text-gray", children: t('profileInvitedUsers.noRecords') }))] })] }) }) }));
|
|
220518
221752
|
}
|
|
220519
221753
|
|
|
221754
|
+
function DocumentSidebar({ isModal = false, sessionId = '', documents, }) {
|
|
221755
|
+
const t = useT();
|
|
221756
|
+
const [isCollapsed, setIsCollapsed] = React.useState(false);
|
|
221757
|
+
const params = useParams();
|
|
221758
|
+
const username = useUsername();
|
|
221759
|
+
const isStreaming = useSelector(selectStreaming);
|
|
221760
|
+
const hasOwnDocuments = documents !== undefined;
|
|
221761
|
+
const { data: sessionDocuments, refetch, status, } = useGetVectorDocumentsQuery({
|
|
221762
|
+
org: params.tenantKey,
|
|
221763
|
+
sessionId: sessionId,
|
|
221764
|
+
// @ts-ignore
|
|
221765
|
+
userId: username,
|
|
221766
|
+
}, {
|
|
221767
|
+
skip: hasOwnDocuments || !params.tenantKey || !sessionId || !username || !isLoggedIn(),
|
|
221768
|
+
});
|
|
221769
|
+
const vectorDocuments = hasOwnDocuments
|
|
221770
|
+
? (documents !== null && documents !== void 0 ? documents : undefined)
|
|
221771
|
+
: sessionDocuments;
|
|
221772
|
+
React.useEffect(() => {
|
|
221773
|
+
if (!hasOwnDocuments && !isStreaming && isLoggedIn() && status !== 'uninitialized') {
|
|
221774
|
+
refetch();
|
|
221775
|
+
}
|
|
221776
|
+
}, [hasOwnDocuments, isStreaming, refetch]);
|
|
221777
|
+
const toggleCollapse = () => {
|
|
221778
|
+
setIsCollapsed(!isCollapsed);
|
|
221779
|
+
};
|
|
221780
|
+
return (jsx(Fragment$1, { children: (vectorDocuments === null || vectorDocuments === void 0 ? void 0 : vectorDocuments.length) && vectorDocuments.length > 0 ? (jsx("aside", { className: cn('transition-all duration-300 ease-in-out', isModal
|
|
221781
|
+
? 'h-full max-h-full w-full overflow-auto'
|
|
221782
|
+
: 'hidden rounded-tl-lg rounded-bl-lg md:hidden lg:block', !isModal && (isCollapsed ? 'w-[40px]' : 'w-[380px]')), style: {
|
|
221783
|
+
backgroundColor: isCollapsed && !isModal ? 'white' : '#F3F6FB',
|
|
221784
|
+
// In the dialog the parent bounds the height; the rail caps itself.
|
|
221785
|
+
maxHeight: isModal ? undefined : 'calc(100vh - 80px)',
|
|
221786
|
+
}, children: jsxs("div", { className: "flex h-full min-h-0 flex-col", children: [!isModal && (jsxs("div", { className: cn('flex cursor-pointer items-center gap-2 border-b border-gray-200 p-4 transition-colors duration-200', isCollapsed && 'h-[80px] justify-center rounded-tl-[5px] rounded-bl-[5px] p-2', 'hover:bg-blue-100'), onClick: toggleCollapse, style: { backgroundColor: '#F3F6FB' }, children: [jsx(FileText, { className: "h-5 w-5 shrink-0 text-blue-600" }), !isCollapsed && (jsxs(Fragment$1, { children: [jsx("h2", { className: "text-base font-medium text-[#646464]", children: t('documentSidebar.retrievedDocuments') }), jsx(ChevronRight, { className: cn('ml-auto h-4 w-4 text-gray-400 transition-transform', isCollapsed ? 'rotate-180' : '') })] }))] })), (!isCollapsed || isModal) && (jsx(Fragment$1, { children: jsx("div", { className: "min-h-0 flex-1 overflow-auto", style: { backgroundColor: '#F3F6FB' }, children: jsx("div", { className: "mt-0 space-y-1 p-2", children: vectorDocuments.map((doc, index) => {
|
|
221787
|
+
var _a, _b;
|
|
221788
|
+
return (jsxs(React.Fragment, { children: [jsx("div", { className: "rounded-lg p-2 hover:bg-gray-50", children: jsxs("div", { className: "flex items-start gap-2", children: [jsx(Radio$1, { className: "mt-1 h-4 w-4 text-gray-400" }), jsxs("div", { className: "min-w-0 flex-1 space-y-1", children: [jsxs("div", { className: "flex items-center justify-between", children: [jsx(Link$2, { href: (_a = doc.source) !== null && _a !== void 0 ? _a : '', target: "_blank", className: "min-w-0", children: jsx("span", { className: "text-sm font-semibold break-words text-[#646464] hover:text-blue-600", children: doc.title }) }), jsx("div", { className: "flex items-center gap-2 self-center", children: jsx("span", { className: "text-xs text-gray-500", children: (_b = doc === null || doc === void 0 ? void 0 : doc.score) === null || _b === void 0 ? void 0 : _b.toFixed(2) }) })] }), jsx("p", { className: "line-clamp-6 pt-[10px] text-[14px] text-gray-600", children: doc.snippet })] })] }) }), index < vectorDocuments.length - 1 && (jsx("div", { className: "my-2 border-t border-gray-200" }))] }, index));
|
|
221789
|
+
}) }) }) }))] }) })) : null }));
|
|
221790
|
+
}
|
|
221791
|
+
|
|
221792
|
+
/**
|
|
221793
|
+
* The chat's "Retrieved Documents" control: an outline button opening the
|
|
221794
|
+
* documents dialog (`DocumentSidebar` in modal mode). Fed by the session's
|
|
221795
|
+
* vector results by default, or by `documents` the host already has — the
|
|
221796
|
+
* admin transcript surfaces pass a turn's or a conversation's documents, so
|
|
221797
|
+
* one component shows retrieved documents everywhere.
|
|
221798
|
+
*/
|
|
221799
|
+
function RetrievedDocumentsButton({ sessionId = '', documents, className, label, }) {
|
|
221800
|
+
const t = useT();
|
|
221801
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
221802
|
+
const params = useParams();
|
|
221803
|
+
const username = useUsername();
|
|
221804
|
+
const isStreaming = useSelector(selectStreaming);
|
|
221805
|
+
const hasOwnDocuments = documents !== undefined;
|
|
221806
|
+
const { data: sessionDocuments, refetch, status, } = useGetVectorDocumentsQuery({
|
|
221807
|
+
org: params.tenantKey,
|
|
221808
|
+
sessionId: sessionId,
|
|
221809
|
+
// @ts-ignore
|
|
221810
|
+
userId: username,
|
|
221811
|
+
}, {
|
|
221812
|
+
skip: hasOwnDocuments || !params.tenantKey || !sessionId || !username || !isLoggedIn(),
|
|
221813
|
+
});
|
|
221814
|
+
const vectorDocuments = hasOwnDocuments
|
|
221815
|
+
? (documents !== null && documents !== void 0 ? documents : undefined)
|
|
221816
|
+
: sessionDocuments;
|
|
221817
|
+
useEffect(() => {
|
|
221818
|
+
if (!hasOwnDocuments && !isStreaming && isLoggedIn() && status !== 'uninitialized') {
|
|
221819
|
+
refetch();
|
|
221820
|
+
}
|
|
221821
|
+
}, [hasOwnDocuments, isStreaming, refetch]);
|
|
221822
|
+
if (!(vectorDocuments === null || vectorDocuments === void 0 ? void 0 : vectorDocuments.length)) {
|
|
221823
|
+
return null;
|
|
221824
|
+
}
|
|
221825
|
+
return (jsxs(Fragment$1, { children: [jsxs(Button$1, { variant: "outline", size: "sm", className: cn('flex items-center gap-2 border-gray-200 bg-white text-gray-700 hover:bg-gray-50', className), onClick: (event) => {
|
|
221826
|
+
// Safe inside clickable transcript rows: the row must not react.
|
|
221827
|
+
event.stopPropagation();
|
|
221828
|
+
setIsOpen(true);
|
|
221829
|
+
}, "data-testid": "retrieved-documents-button", children: [jsx(FileText, { className: "h-4 w-4 text-blue-600" }), jsx("span", { children: label !== null && label !== void 0 ? label : t('retrievedDocumentsButton.title') })] }), jsx(Dialog, { open: isOpen, onOpenChange: setIsOpen, children: jsxs(DialogContent, { className: "flex max-h-[80vh] flex-col gap-0 p-0 sm:max-w-[425px] md:max-w-[600px]", children: [jsx(DialogHeader, { className: "border-b px-4 py-2", children: jsxs(DialogTitle, { className: "flex items-center gap-2 text-base font-medium text-[#646464]", children: [jsx(FileText, { className: "h-5 w-5 text-blue-600" }), t('retrievedDocumentsButton.title')] }) }), jsx("div", { className: "min-h-0 flex-1 overflow-y-auto", "data-testid": "retrieved-documents-scroll", children: jsx(DocumentSidebar, { isModal: true, sessionId: sessionId, documents: documents }) })] }) })] }));
|
|
221830
|
+
}
|
|
221831
|
+
|
|
221832
|
+
var COLLAPSIBLE_NAME = "Collapsible";
|
|
221833
|
+
var [createCollapsibleContext] = createContextScope$1(COLLAPSIBLE_NAME);
|
|
221834
|
+
var [CollapsibleProvider, useCollapsibleContext] = createCollapsibleContext(COLLAPSIBLE_NAME);
|
|
221835
|
+
var Collapsible$1 = React.forwardRef(
|
|
221836
|
+
(props, forwardedRef) => {
|
|
221837
|
+
const {
|
|
221838
|
+
__scopeCollapsible,
|
|
221839
|
+
open: openProp,
|
|
221840
|
+
defaultOpen,
|
|
221841
|
+
disabled,
|
|
221842
|
+
onOpenChange,
|
|
221843
|
+
...collapsibleProps
|
|
221844
|
+
} = props;
|
|
221845
|
+
const [open, setOpen] = useControllableState$1({
|
|
221846
|
+
prop: openProp,
|
|
221847
|
+
defaultProp: defaultOpen ?? false,
|
|
221848
|
+
onChange: onOpenChange,
|
|
221849
|
+
caller: COLLAPSIBLE_NAME
|
|
221850
|
+
});
|
|
221851
|
+
return /* @__PURE__ */ jsx(
|
|
221852
|
+
CollapsibleProvider,
|
|
221853
|
+
{
|
|
221854
|
+
scope: __scopeCollapsible,
|
|
221855
|
+
disabled,
|
|
221856
|
+
contentId: useId$1(),
|
|
221857
|
+
open,
|
|
221858
|
+
onOpenToggle: React.useCallback(() => setOpen((prevOpen) => !prevOpen), [setOpen]),
|
|
221859
|
+
children: /* @__PURE__ */ jsx(
|
|
221860
|
+
Primitive$2.div,
|
|
221861
|
+
{
|
|
221862
|
+
"data-state": getState$1(open),
|
|
221863
|
+
"data-disabled": disabled ? "" : void 0,
|
|
221864
|
+
...collapsibleProps,
|
|
221865
|
+
ref: forwardedRef
|
|
221866
|
+
}
|
|
221867
|
+
)
|
|
221868
|
+
}
|
|
221869
|
+
);
|
|
221870
|
+
}
|
|
221871
|
+
);
|
|
221872
|
+
Collapsible$1.displayName = COLLAPSIBLE_NAME;
|
|
221873
|
+
var TRIGGER_NAME$2 = "CollapsibleTrigger";
|
|
221874
|
+
var CollapsibleTrigger$1 = React.forwardRef(
|
|
221875
|
+
(props, forwardedRef) => {
|
|
221876
|
+
const { __scopeCollapsible, ...triggerProps } = props;
|
|
221877
|
+
const context = useCollapsibleContext(TRIGGER_NAME$2, __scopeCollapsible);
|
|
221878
|
+
return /* @__PURE__ */ jsx(
|
|
221879
|
+
Primitive$2.button,
|
|
221880
|
+
{
|
|
221881
|
+
type: "button",
|
|
221882
|
+
"aria-controls": context.contentId,
|
|
221883
|
+
"aria-expanded": context.open || false,
|
|
221884
|
+
"data-state": getState$1(context.open),
|
|
221885
|
+
"data-disabled": context.disabled ? "" : void 0,
|
|
221886
|
+
disabled: context.disabled,
|
|
221887
|
+
...triggerProps,
|
|
221888
|
+
ref: forwardedRef,
|
|
221889
|
+
onClick: composeEventHandlers$1(props.onClick, context.onOpenToggle)
|
|
221890
|
+
}
|
|
221891
|
+
);
|
|
221892
|
+
}
|
|
221893
|
+
);
|
|
221894
|
+
CollapsibleTrigger$1.displayName = TRIGGER_NAME$2;
|
|
221895
|
+
var CONTENT_NAME$3 = "CollapsibleContent";
|
|
221896
|
+
var CollapsibleContent$1 = React.forwardRef(
|
|
221897
|
+
(props, forwardedRef) => {
|
|
221898
|
+
const { forceMount, ...contentProps } = props;
|
|
221899
|
+
const context = useCollapsibleContext(CONTENT_NAME$3, props.__scopeCollapsible);
|
|
221900
|
+
return /* @__PURE__ */ jsx(Presence$2, { present: forceMount || context.open, children: ({ present }) => /* @__PURE__ */ jsx(CollapsibleContentImpl, { ...contentProps, ref: forwardedRef, present }) });
|
|
221901
|
+
}
|
|
221902
|
+
);
|
|
221903
|
+
CollapsibleContent$1.displayName = CONTENT_NAME$3;
|
|
221904
|
+
var CollapsibleContentImpl = React.forwardRef((props, forwardedRef) => {
|
|
221905
|
+
const { __scopeCollapsible, present, children, ...contentProps } = props;
|
|
221906
|
+
const context = useCollapsibleContext(CONTENT_NAME$3, __scopeCollapsible);
|
|
221907
|
+
const [isPresent, setIsPresent] = React.useState(present);
|
|
221908
|
+
const ref = React.useRef(null);
|
|
221909
|
+
const composedRefs = useComposedRefs$1(forwardedRef, ref);
|
|
221910
|
+
const heightRef = React.useRef(0);
|
|
221911
|
+
const height = heightRef.current;
|
|
221912
|
+
const widthRef = React.useRef(0);
|
|
221913
|
+
const width = widthRef.current;
|
|
221914
|
+
const isOpen = context.open || isPresent;
|
|
221915
|
+
const isMountAnimationPreventedRef = React.useRef(isOpen);
|
|
221916
|
+
const originalStylesRef = React.useRef(void 0);
|
|
221917
|
+
React.useEffect(() => {
|
|
221918
|
+
const rAF = requestAnimationFrame(() => isMountAnimationPreventedRef.current = false);
|
|
221919
|
+
return () => cancelAnimationFrame(rAF);
|
|
221920
|
+
}, []);
|
|
221921
|
+
useLayoutEffect2$1(() => {
|
|
221922
|
+
const node = ref.current;
|
|
221923
|
+
if (node) {
|
|
221924
|
+
originalStylesRef.current = originalStylesRef.current || {
|
|
221925
|
+
transitionDuration: node.style.transitionDuration,
|
|
221926
|
+
animationName: node.style.animationName
|
|
221927
|
+
};
|
|
221928
|
+
node.style.transitionDuration = "0s";
|
|
221929
|
+
node.style.animationName = "none";
|
|
221930
|
+
const rect = node.getBoundingClientRect();
|
|
221931
|
+
heightRef.current = rect.height;
|
|
221932
|
+
widthRef.current = rect.width;
|
|
221933
|
+
if (!isMountAnimationPreventedRef.current) {
|
|
221934
|
+
node.style.transitionDuration = originalStylesRef.current.transitionDuration;
|
|
221935
|
+
node.style.animationName = originalStylesRef.current.animationName;
|
|
221936
|
+
}
|
|
221937
|
+
setIsPresent(present);
|
|
221938
|
+
}
|
|
221939
|
+
}, [context.open, present]);
|
|
221940
|
+
return /* @__PURE__ */ jsx(
|
|
221941
|
+
Primitive$2.div,
|
|
221942
|
+
{
|
|
221943
|
+
"data-state": getState$1(context.open),
|
|
221944
|
+
"data-disabled": context.disabled ? "" : void 0,
|
|
221945
|
+
id: context.contentId,
|
|
221946
|
+
hidden: !isOpen,
|
|
221947
|
+
...contentProps,
|
|
221948
|
+
ref: composedRefs,
|
|
221949
|
+
style: {
|
|
221950
|
+
[`--radix-collapsible-content-height`]: height ? `${height}px` : void 0,
|
|
221951
|
+
[`--radix-collapsible-content-width`]: width ? `${width}px` : void 0,
|
|
221952
|
+
...props.style
|
|
221953
|
+
},
|
|
221954
|
+
children: isOpen && children
|
|
221955
|
+
}
|
|
221956
|
+
);
|
|
221957
|
+
});
|
|
221958
|
+
function getState$1(open) {
|
|
221959
|
+
return open ? "open" : "closed";
|
|
221960
|
+
}
|
|
221961
|
+
var Root$5 = Collapsible$1;
|
|
221962
|
+
|
|
221963
|
+
const Collapsible = Root$5;
|
|
221964
|
+
const CollapsibleTrigger = CollapsibleTrigger$1;
|
|
221965
|
+
const CollapsibleContent = CollapsibleContent$1;
|
|
221966
|
+
|
|
221967
|
+
function getFriendlyToolName(toolName) {
|
|
221968
|
+
if (TOOL_NAME_MAP === null || TOOL_NAME_MAP === void 0 ? void 0 : TOOL_NAME_MAP[toolName])
|
|
221969
|
+
return TOOL_NAME_MAP[toolName];
|
|
221970
|
+
const words = toolName.replace(/_/g, ' ').trim();
|
|
221971
|
+
return words.charAt(0).toUpperCase() + words.slice(1);
|
|
221972
|
+
}
|
|
221973
|
+
// Extract a short human-readable query from tool input or log
|
|
221974
|
+
function getQueryLabel(toolCall) {
|
|
221975
|
+
var _a, _b, _c, _d, _e;
|
|
221976
|
+
// Prefer structured input
|
|
221977
|
+
if (toolCall.input && typeof toolCall.input === 'object') {
|
|
221978
|
+
const val = (_c = (_b = (_a = toolCall.input.query) !== null && _a !== void 0 ? _a : toolCall.input.q) !== null && _b !== void 0 ? _b : toolCall.input.input) !== null && _c !== void 0 ? _c : toolCall.input.text;
|
|
221979
|
+
if (val && typeof val === 'string')
|
|
221980
|
+
return val;
|
|
221981
|
+
// Fallback: first string value in input
|
|
221982
|
+
const firstStr = Object.values(toolCall.input).find((v) => typeof v === 'string');
|
|
221983
|
+
if (firstStr)
|
|
221984
|
+
return firstStr;
|
|
221985
|
+
}
|
|
221986
|
+
// Fallback: parse the "… with `{...}`" snippet of the log string. Located
|
|
221987
|
+
// with index scans rather than a lazy regex, which backtracks
|
|
221988
|
+
// polynomially on adversarial logs (CodeQL js/polynomial-redos).
|
|
221989
|
+
if (toolCall.log) {
|
|
221990
|
+
const snippet = extractLogPayload(toolCall.log);
|
|
221991
|
+
if (snippet) {
|
|
221992
|
+
try {
|
|
221993
|
+
const parsed = JSON.parse(snippet.replace(/'/g, '"'));
|
|
221994
|
+
const val = (_e = (_d = parsed.query) !== null && _d !== void 0 ? _d : parsed.q) !== null && _e !== void 0 ? _e : parsed.input;
|
|
221995
|
+
if (val)
|
|
221996
|
+
return val;
|
|
221997
|
+
}
|
|
221998
|
+
catch (_f) {
|
|
221999
|
+
// Not every log snippet is JSON (apostrophes inside the payload break
|
|
222000
|
+
// the quote swap above). That is expected input, not an error — and
|
|
222001
|
+
// this runs inside a memo comparator on every streaming tick, so
|
|
222002
|
+
// logging here flooded the console on phones.
|
|
222003
|
+
}
|
|
222004
|
+
}
|
|
222005
|
+
}
|
|
222006
|
+
return null;
|
|
222007
|
+
}
|
|
222008
|
+
/** The `{...}` inside the first "with `{...}`" of a tool log, or null. */
|
|
222009
|
+
function extractLogPayload(log) {
|
|
222010
|
+
let from = 0;
|
|
222011
|
+
while (from < log.length) {
|
|
222012
|
+
const open = log.indexOf('`{', from);
|
|
222013
|
+
if (open === -1)
|
|
222014
|
+
return null;
|
|
222015
|
+
// Must follow the word "with" plus at least one whitespace character.
|
|
222016
|
+
let i = open - 1;
|
|
222017
|
+
let sawSpace = false;
|
|
222018
|
+
while (i >= 0 && /\s/.test(log[i])) {
|
|
222019
|
+
sawSpace = true;
|
|
222020
|
+
i -= 1;
|
|
222021
|
+
}
|
|
222022
|
+
if (sawSpace && log.slice(Math.max(0, i - 3), i + 1) === 'with') {
|
|
222023
|
+
const close = log.indexOf('}`', open + 1);
|
|
222024
|
+
if (close === -1)
|
|
222025
|
+
return null;
|
|
222026
|
+
return log.slice(open + 1, close + 1);
|
|
222027
|
+
}
|
|
222028
|
+
from = open + 1;
|
|
222029
|
+
}
|
|
222030
|
+
return null;
|
|
222031
|
+
}
|
|
222032
|
+
function formatResult(result) {
|
|
222033
|
+
return result.replace(/\n{3,}/g, '\n\n').trim();
|
|
222034
|
+
}
|
|
222035
|
+
|
|
222036
|
+
const TOOL_ICONS = {
|
|
222037
|
+
web_search_call: Globe,
|
|
222038
|
+
vector_search: Search,
|
|
222039
|
+
code_executor: Code$1,
|
|
222040
|
+
file_reader: FileText,
|
|
222041
|
+
wikipedia: BookOpen,
|
|
222042
|
+
};
|
|
222043
|
+
function getToolIcon(toolName) {
|
|
222044
|
+
return (toolName && TOOL_ICONS[toolName]) || Wrench;
|
|
222045
|
+
}
|
|
222046
|
+
/**
|
|
222047
|
+
* Collapsible record of the tools a turn used — the "Used N tools" line of
|
|
222048
|
+
* the chat bubble.
|
|
222049
|
+
*
|
|
222050
|
+
* The header always reads as the completed record ("Used N tools") and the
|
|
222051
|
+
* individual rows never animate. Only while this row is the live phase does the
|
|
222052
|
+
* header sprout dots — at which point the working line has stood down, so there
|
|
222053
|
+
* is still exactly one animated "agent is working" signal on screen.
|
|
222054
|
+
*/
|
|
222055
|
+
function ToolCallIndicator({ toolCalls, isActive = false, showResults = false, }) {
|
|
222056
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
222057
|
+
// `write_todos` has a dedicated renderer (`AgentTodoList`), so it must never
|
|
222058
|
+
// appear as a generic tool card nor be counted in "Used N tools".
|
|
222059
|
+
const visibleToolCalls = (toolCalls !== null && toolCalls !== void 0 ? toolCalls : []).filter((tc) => (tc === null || tc === void 0 ? void 0 : tc.name) !== WRITE_TODOS_TOOL);
|
|
222060
|
+
if (visibleToolCalls.length === 0) {
|
|
222061
|
+
return null;
|
|
222062
|
+
}
|
|
222063
|
+
const uniqueToolCount = new Set(visibleToolCalls.map((tc) => tc.name)).size;
|
|
222064
|
+
const headerLabel = `Used ${uniqueToolCount} tool${uniqueToolCount === 1 ? '' : 's'}`;
|
|
222065
|
+
return (jsxs(Collapsible, { open: isOpen, onOpenChange: setIsOpen, className: "mb-2", children: [jsxs(CollapsibleTrigger, { className: "flex cursor-pointer items-center gap-1 pt-1 text-xs text-gray-600 transition-colors hover:text-gray-800", children: [jsx(ChevronRight, { className: cn('h-3 w-3 transition-transform duration-200', isOpen && 'rotate-90') }), jsx(Wrench, { className: "h-3 w-3" }), jsx("span", { children: headerLabel }), isActive && (jsxs("span", { className: "inline-flex gap-0.5", "aria-hidden": "true", children: [jsx("span", { className: "inline-block h-1 w-1 animate-bounce rounded-full bg-gray-600 [animation-delay:0ms] motion-reduce:animate-none" }), jsx("span", { className: "inline-block h-1 w-1 animate-bounce rounded-full bg-gray-600 [animation-delay:150ms] motion-reduce:animate-none" }), jsx("span", { className: "inline-block h-1 w-1 animate-bounce rounded-full bg-gray-600 [animation-delay:300ms] motion-reduce:animate-none" })] }))] }), jsx(CollapsibleContent, { className: "pb-2 pl-4", children: jsx("div", { className: "space-y-2.5 border-l-2 border-gray-300 pt-2.5 pl-3 text-xs leading-relaxed text-gray-600", children: visibleToolCalls.map((toolCall, index) => {
|
|
222066
|
+
var _a;
|
|
222067
|
+
const query = getQueryLabel(toolCall);
|
|
222068
|
+
const Icon = getToolIcon(toolCall === null || toolCall === void 0 ? void 0 : toolCall.name);
|
|
222069
|
+
const result = showResults && (toolCall === null || toolCall === void 0 ? void 0 : toolCall.result) ? formatResult(toolCall.result) : null;
|
|
222070
|
+
return (jsxs("div", { children: [jsxs("div", { className: "flex items-center gap-1.5 text-gray-700", children: [jsx(Icon, { className: "h-3 w-3 shrink-0 text-gray-500" }), jsx("span", { className: "font-medium", children: getFriendlyToolName((_a = toolCall === null || toolCall === void 0 ? void 0 : toolCall.name) !== null && _a !== void 0 ? _a : '') })] }), query && (jsx("div", { className: "mt-0.5 ml-[18px] text-gray-600", children: jsx(Markdown, { className: "prose prose-xs max-w-none [&_*]:text-xs [&_*]:text-gray-600 [&_p]:m-0", children: query }) })), result && (jsx("div", { className: "mt-1 ml-[18px] max-h-48 overflow-y-auto rounded-md border border-gray-200 bg-white px-2 py-1.5 leading-relaxed whitespace-pre-wrap text-gray-600", "data-testid": "tool-call-result", children: result }))] }, (toolCall === null || toolCall === void 0 ? void 0 : toolCall.id) || index));
|
|
222071
|
+
}) }) })] }));
|
|
222072
|
+
}
|
|
222073
|
+
|
|
222074
|
+
// Model wire keys whose raw form is not presentable, keyed lowercased and
|
|
222075
|
+
// alphanumerics-only.
|
|
222076
|
+
const IBL_AI_DISPLAY_NAME = 'ibl.ai';
|
|
222077
|
+
const MODEL_DISPLAY_NAME_BY_KEY = {
|
|
222078
|
+
iblai: IBL_AI_DISPLAY_NAME,
|
|
222079
|
+
};
|
|
222080
|
+
/**
|
|
222081
|
+
* The label to show for a model when only its wire key is known.
|
|
222082
|
+
*
|
|
222083
|
+
* The LLM picker gets a `display_name` per model straight from the API, but
|
|
222084
|
+
* mentor settings and transcripts persist only `llm_name` — a wire key — so
|
|
222085
|
+
* surfaces that read from those have no label to fall back on and would
|
|
222086
|
+
* render `iblai`. Most keys are already presentable (`gpt-4.1`), so this maps
|
|
222087
|
+
* only the ones that are not and passes everything else through untouched.
|
|
222088
|
+
*/
|
|
222089
|
+
function getLLMModelDisplayName(llmName) {
|
|
222090
|
+
var _a;
|
|
222091
|
+
const raw = llmName !== null && llmName !== void 0 ? llmName : '';
|
|
222092
|
+
const normalized = raw.toLowerCase().replace(/[^a-z0-9]/g, '');
|
|
222093
|
+
// ibl.ai keys are the brand followed by an optional variant — `iblai`,
|
|
222094
|
+
// `iblai-pro`, `iblai-fast`, `IBL AI Pro`. Rebuild the label the model
|
|
222095
|
+
// picker gets from the API (`ibl.ai Pro`) rather than collapsing every
|
|
222096
|
+
// variant onto a bare `ibl.ai`, which would disagree with the picker.
|
|
222097
|
+
const brand = /^(iblai|ibl)(.*)$/.exec(normalized);
|
|
222098
|
+
const leadsWithBrand = brand &&
|
|
222099
|
+
(brand[1] === 'iblai' ||
|
|
222100
|
+
raw
|
|
222101
|
+
.toLowerCase()
|
|
222102
|
+
.split(/[^a-z0-9]+/)
|
|
222103
|
+
.filter(Boolean)[0] === 'ibl');
|
|
222104
|
+
if (leadsWithBrand) {
|
|
222105
|
+
const variant = brand[2];
|
|
222106
|
+
if (!variant)
|
|
222107
|
+
return IBL_AI_DISPLAY_NAME;
|
|
222108
|
+
// `ai` is part of the brand when the key spells it out (`ibl-ai-pro`).
|
|
222109
|
+
const suffix = variant.startsWith('ai') && brand[1] === 'ibl' ? variant.slice(2) : variant;
|
|
222110
|
+
if (!suffix)
|
|
222111
|
+
return IBL_AI_DISPLAY_NAME;
|
|
222112
|
+
return `${IBL_AI_DISPLAY_NAME} ${suffix.charAt(0).toUpperCase()}${suffix.slice(1)}`;
|
|
222113
|
+
}
|
|
222114
|
+
return (_a = MODEL_DISPLAY_NAME_BY_KEY[normalized]) !== null && _a !== void 0 ? _a : raw;
|
|
222115
|
+
}
|
|
222116
|
+
|
|
222117
|
+
/** Loose key for matching a model across spellings: lower-case, alphanumerics only. */
|
|
222118
|
+
const modelKey = (value) => (value !== null && value !== void 0 ? value : '').toLowerCase().replace(/[^a-z0-9]/g, '');
|
|
222119
|
+
/**
|
|
222120
|
+
* Model families → the provider keys the catalogue may list them under, for
|
|
222121
|
+
* a model the catalogue does not name (a dated or "-latest" wire key, or a
|
|
222122
|
+
* model the tenant enabled elsewhere). First key present in the catalogue
|
|
222123
|
+
* wins; hosted variants (Azure, Bedrock, Groq) come after the vendor.
|
|
222124
|
+
*/
|
|
222125
|
+
const MODEL_FAMILY_PROVIDERS = [
|
|
222126
|
+
[/^(gpt|o[1-9]|chatgpt|davinci|text-embedding)/, ['openai', 'azure_openai', 'azure']],
|
|
222127
|
+
[/^claude/, ['anthropic', 'bedrock']],
|
|
222128
|
+
[/^(gemini|gemma|palm)/, ['google', 'vertex', 'vertexai', 'gemini']],
|
|
222129
|
+
[/^(llama|meta)/, ['llama', 'meta', 'bedrock', 'groq']],
|
|
222130
|
+
[/^(mistral|mixtral|codestral)/, ['mistral']],
|
|
222131
|
+
[/^deepseek/, ['deepseek']],
|
|
222132
|
+
[/^grok/, ['xai', 'grok']],
|
|
222133
|
+
[/^(command|aya)/, ['cohere']],
|
|
222134
|
+
[/^qwen/, ['qwen', 'alibaba']],
|
|
222135
|
+
[/^(nova|titan)/, ['bedrock', 'amazon']],
|
|
222136
|
+
];
|
|
222137
|
+
/** Provider keys a model of this family is listed under, in order of preference. */
|
|
222138
|
+
function inferProviderKeysFromModel(model) {
|
|
222139
|
+
const key = modelKey(model);
|
|
222140
|
+
if (!key)
|
|
222141
|
+
return [];
|
|
222142
|
+
for (const [pattern, providers] of MODEL_FAMILY_PROVIDERS) {
|
|
222143
|
+
if (pattern.test(key))
|
|
222144
|
+
return providers;
|
|
222145
|
+
}
|
|
222146
|
+
return [];
|
|
222147
|
+
}
|
|
222148
|
+
/**
|
|
222149
|
+
* A resolver from a provider key (the `llm_provider` mentor settings persist,
|
|
222150
|
+
* e.g. `openai`) to the name and logo the backend publishes for it. A second,
|
|
222151
|
+
* optional model key finds the provider whose `chat_models` list it, for
|
|
222152
|
+
* payloads that name only the model (analytics transcript rows).
|
|
222153
|
+
*
|
|
222154
|
+
* Provider naming is backend-owned: the mentor-llms catalogue carries each
|
|
222155
|
+
* provider's `logo` (and `display_name` where the API supplies one), so this
|
|
222156
|
+
* reads the same RTK Query cache entry the LLM tab and model picker fill —
|
|
222157
|
+
* matched on `name`. A key the catalogue does not list (the catalogue is
|
|
222158
|
+
* still loading, or an on-device provider that has no backend row) resolves
|
|
222159
|
+
* to the raw key and no logo, so callers degrade to plain text.
|
|
222160
|
+
*
|
|
222161
|
+
* Returns a function rather than a value so list renderers (a mentors table,
|
|
222162
|
+
* a facet dropdown) can resolve many keys from one subscription.
|
|
222163
|
+
*/
|
|
222164
|
+
function useLlmProviderCatalogue({ org, userId, mentorId }) {
|
|
222165
|
+
const skip = !org || !userId || !mentorId;
|
|
222166
|
+
const { data: providers } = useGetLlmsQuery({
|
|
222167
|
+
org: org !== null && org !== void 0 ? org : '',
|
|
222168
|
+
// @ts-expect-error - userId is not in the generated query args but the endpoint scopes by it
|
|
222169
|
+
userId: userId !== null && userId !== void 0 ? userId : '',
|
|
222170
|
+
mentorId: mentorId !== null && mentorId !== void 0 ? mentorId : '',
|
|
222171
|
+
}, { skip });
|
|
222172
|
+
// Indexed once per catalogue load so list renderers resolve each key in
|
|
222173
|
+
// O(1). First row wins on a duplicate name, as `Array.find` would.
|
|
222174
|
+
const rowsByName = useMemo(() => {
|
|
222175
|
+
const byName = new Map();
|
|
222176
|
+
if (!Array.isArray(providers))
|
|
222177
|
+
return byName;
|
|
222178
|
+
for (const row of providers) {
|
|
222179
|
+
if ((row === null || row === void 0 ? void 0 : row.name) && !byName.has(row.name))
|
|
222180
|
+
byName.set(row.name, row);
|
|
222181
|
+
}
|
|
222182
|
+
return byName;
|
|
222183
|
+
}, [providers]);
|
|
222184
|
+
// Model key → the provider row listing it. Keyed loosely (see `modelKey`):
|
|
222185
|
+
// transcripts persist the model as it was displayed ("GPT-5.2") while the
|
|
222186
|
+
// catalogue lists the wire key ("gpt-5.2"), so both spellings, and the
|
|
222187
|
+
// display name, must find the row.
|
|
222188
|
+
const rowsByModel = useMemo(() => {
|
|
222189
|
+
var _a;
|
|
222190
|
+
const byModel = new Map();
|
|
222191
|
+
for (const row of rowsByName.values()) {
|
|
222192
|
+
for (const model of (_a = row.chat_models) !== null && _a !== void 0 ? _a : []) {
|
|
222193
|
+
for (const candidate of [model === null || model === void 0 ? void 0 : model.llm_name, model === null || model === void 0 ? void 0 : model.display_name]) {
|
|
222194
|
+
const key = modelKey(candidate);
|
|
222195
|
+
if (key && !byModel.has(key))
|
|
222196
|
+
byModel.set(key, row);
|
|
222197
|
+
}
|
|
222198
|
+
}
|
|
222199
|
+
}
|
|
222200
|
+
return byModel;
|
|
222201
|
+
}, [rowsByName]);
|
|
222202
|
+
// Provider rows keyed loosely by name and display name ("OpenAI" → openai).
|
|
222203
|
+
const rowsByLooseName = useMemo(() => {
|
|
222204
|
+
const byLoose = new Map();
|
|
222205
|
+
for (const row of rowsByName.values()) {
|
|
222206
|
+
for (const candidate of [row.name, row.display_name]) {
|
|
222207
|
+
const key = modelKey(candidate);
|
|
222208
|
+
if (key && !byLoose.has(key))
|
|
222209
|
+
byLoose.set(key, row);
|
|
222210
|
+
}
|
|
222211
|
+
}
|
|
222212
|
+
return byLoose;
|
|
222213
|
+
}, [rowsByName]);
|
|
222214
|
+
const rowForModel = useCallback((llmName) => {
|
|
222215
|
+
var _a;
|
|
222216
|
+
const wanted = modelKey(llmName);
|
|
222217
|
+
if (!wanted)
|
|
222218
|
+
return undefined;
|
|
222219
|
+
const exact = rowsByModel.get(wanted);
|
|
222220
|
+
if (exact)
|
|
222221
|
+
return exact;
|
|
222222
|
+
// A dated or "-latest" wire key ("gpt-5.2-2026-03-01") still names
|
|
222223
|
+
// the family the catalogue lists ("gpt-5.2"), and vice versa.
|
|
222224
|
+
for (const [listed, row] of rowsByModel) {
|
|
222225
|
+
if (listed.startsWith(wanted) || wanted.startsWith(listed))
|
|
222226
|
+
return row;
|
|
222227
|
+
}
|
|
222228
|
+
for (const provider of inferProviderKeysFromModel(llmName)) {
|
|
222229
|
+
const row = (_a = rowsByName.get(provider)) !== null && _a !== void 0 ? _a : rowsByLooseName.get(modelKey(provider));
|
|
222230
|
+
if (row)
|
|
222231
|
+
return row;
|
|
222232
|
+
}
|
|
222233
|
+
return undefined;
|
|
222234
|
+
}, [rowsByModel, rowsByName, rowsByLooseName]);
|
|
222235
|
+
return useCallback((llmProvider, llmName) => {
|
|
222236
|
+
var _a, _b, _c, _d, _e;
|
|
222237
|
+
const key = llmProvider !== null && llmProvider !== void 0 ? llmProvider : '';
|
|
222238
|
+
const row = (_c = (_b = (_a = rowsByName.get(key)) !== null && _a !== void 0 ? _a : rowsByName.get(key.toLowerCase())) !== null && _b !== void 0 ? _b : rowsByLooseName.get(modelKey(key))) !== null && _c !== void 0 ? _c : rowForModel(llmName);
|
|
222239
|
+
return {
|
|
222240
|
+
logo: (row === null || row === void 0 ? void 0 : row.logo) || null,
|
|
222241
|
+
displayName: ((_d = row === null || row === void 0 ? void 0 : row.display_name) === null || _d === void 0 ? void 0 : _d.trim()) || ((_e = row === null || row === void 0 ? void 0 : row.name) === null || _e === void 0 ? void 0 : _e.trim()) || key,
|
|
222242
|
+
};
|
|
222243
|
+
}, [rowsByName, rowsByLooseName, rowForModel]);
|
|
222244
|
+
}
|
|
222245
|
+
const clean$1 = (value) => (value === null || value === void 0 ? void 0 : value.trim()) || undefined;
|
|
222246
|
+
/**
|
|
222247
|
+
* The label to show for a model.
|
|
222248
|
+
*
|
|
222249
|
+
* Settings persist only `llm_name` — a wire key like `iblai-pro` or
|
|
222250
|
+
* `claude-haiku-4-5-20251001` — while the model picker reads the catalogue,
|
|
222251
|
+
* which carries a `display_name` ("ibl.ai Pro", "Claude Haiku 4.5"). Resolve
|
|
222252
|
+
* the label in three steps:
|
|
222253
|
+
*
|
|
222254
|
+
* 1. `llm_config.display_name` from settings, when the caller has it.
|
|
222255
|
+
* 2. The mentor-llms catalogue, matched on `llm_name`. Only queried when step
|
|
222256
|
+
* 1 came back empty.
|
|
222257
|
+
* 3. `getLLMModelDisplayName`, which tidies the handful of keys whose raw
|
|
222258
|
+
* form is unpresentable — used while the catalogue is loading or failed.
|
|
222259
|
+
*/
|
|
222260
|
+
function useLlmDisplayName({ llmName, llmConfig, org, userId, mentorId, }) {
|
|
222261
|
+
var _a;
|
|
222262
|
+
const fromConfig = clean$1(llmConfig === null || llmConfig === void 0 ? void 0 : llmConfig.display_name);
|
|
222263
|
+
const skip = Boolean(fromConfig) || !llmName || !org || !userId || !mentorId;
|
|
222264
|
+
const { data: providers } = useGetLlmsQuery({
|
|
222265
|
+
org: org !== null && org !== void 0 ? org : '',
|
|
222266
|
+
// @ts-expect-error - userId is not in the generated query args but the endpoint scopes by it
|
|
222267
|
+
userId: userId !== null && userId !== void 0 ? userId : '',
|
|
222268
|
+
mentorId: mentorId !== null && mentorId !== void 0 ? mentorId : '',
|
|
222269
|
+
}, { skip });
|
|
222270
|
+
const fromCatalogue = useMemo(() => {
|
|
222271
|
+
var _a;
|
|
222272
|
+
if (skip || !llmName || !Array.isArray(providers))
|
|
222273
|
+
return undefined;
|
|
222274
|
+
const wanted = modelKey(llmName);
|
|
222275
|
+
for (const provider of providers) {
|
|
222276
|
+
const match = (_a = provider === null || provider === void 0 ? void 0 : provider.chat_models) === null || _a === void 0 ? void 0 : _a.find((model) => modelKey(model === null || model === void 0 ? void 0 : model.llm_name) === wanted || modelKey(model === null || model === void 0 ? void 0 : model.display_name) === wanted);
|
|
222277
|
+
const label = clean$1(match === null || match === void 0 ? void 0 : match.display_name);
|
|
222278
|
+
if (label)
|
|
222279
|
+
return label;
|
|
222280
|
+
}
|
|
222281
|
+
return undefined;
|
|
222282
|
+
}, [skip, providers, llmName]);
|
|
222283
|
+
return (_a = fromConfig !== null && fromConfig !== void 0 ? fromConfig : fromCatalogue) !== null && _a !== void 0 ? _a : getLLMModelDisplayName(llmName);
|
|
222284
|
+
}
|
|
222285
|
+
|
|
222286
|
+
/**
|
|
222287
|
+
* A model the way the nav bar shows the mentor's: the provider logo in a
|
|
222288
|
+
* white circle (the catalogue's artwork, or the bot icon when it has none)
|
|
222289
|
+
* beside the model's display name. Read-only; used on admin transcripts to
|
|
222290
|
+
* name the model a turn ran on.
|
|
222291
|
+
*/
|
|
222292
|
+
function LlmModelBadge({ model, provider, tenantKey, mentorId, className, }) {
|
|
222293
|
+
var _a, _b;
|
|
222294
|
+
const params = useParams();
|
|
222295
|
+
const username = useUsername();
|
|
222296
|
+
const org = (_a = tenantKey !== null && tenantKey !== void 0 ? tenantKey : params === null || params === void 0 ? void 0 : params.tenantKey) !== null && _a !== void 0 ? _a : null;
|
|
222297
|
+
const mentor = (_b = mentorId !== null && mentorId !== void 0 ? mentorId : params === null || params === void 0 ? void 0 : params.mentorId) !== null && _b !== void 0 ? _b : null;
|
|
222298
|
+
const resolveLlmProvider = useLlmProviderCatalogue({ org, userId: username, mentorId: mentor });
|
|
222299
|
+
// With no provider key (transcript rows carry only the model), the
|
|
222300
|
+
// catalogue row that lists this model supplies the logo and name.
|
|
222301
|
+
const providerDetails = resolveLlmProvider(provider, model);
|
|
222302
|
+
const displayName = useLlmDisplayName({
|
|
222303
|
+
llmName: model,
|
|
222304
|
+
org,
|
|
222305
|
+
userId: username,
|
|
222306
|
+
mentorId: mentor,
|
|
222307
|
+
});
|
|
222308
|
+
const label = displayName || providerDetails.displayName;
|
|
222309
|
+
if (!label)
|
|
222310
|
+
return null;
|
|
222311
|
+
return (jsxs("span", { className: cn('inline-flex max-w-full items-center gap-2 text-sm font-medium text-[#646464]', className), title: providerDetails.displayName && providerDetails.displayName !== label
|
|
222312
|
+
? `${label} · ${providerDetails.displayName}`
|
|
222313
|
+
: label, "data-testid": "llm-model-badge", children: [jsx("span", { className: "flex h-6 w-6 flex-shrink-0 items-center justify-center rounded-full bg-white", children: providerDetails.logo ? (jsx("img", { src: providerDetails.logo, alt: `${label} model logo`, className: "h-5 w-5 object-contain", height: 32, width: 32, loading: "lazy" })) : (jsx(Bot, { className: "h-4 w-4", "aria-hidden": "true" })) }), jsx("span", { className: "max-w-[220px] truncate", children: label })] }));
|
|
222314
|
+
}
|
|
222315
|
+
|
|
222316
|
+
/** SPAs whose users have coursework, so the profile leads with a Gradebook tab. */
|
|
222317
|
+
const GRADEBOOK_SPAS = ['lms', 'skills'];
|
|
222318
|
+
/**
|
|
222319
|
+
* The customization `Profile` is opened with: whatever the host passed, with
|
|
222320
|
+
* the Gradebook tab defaulted from the SPA it runs in. An explicit
|
|
222321
|
+
* `showGradebookTab` always wins, so a host can force it either way.
|
|
222322
|
+
*/
|
|
222323
|
+
function profileCustomization(customization, currentSPA) {
|
|
222324
|
+
var _a;
|
|
222325
|
+
return {
|
|
222326
|
+
...customization,
|
|
222327
|
+
showGradebookTab: (_a = customization === null || customization === void 0 ? void 0 : customization.showGradebookTab) !== null && _a !== void 0 ? _a : GRADEBOOK_SPAS.includes((currentSPA !== null && currentSPA !== void 0 ? currentSPA : '').trim().toLowerCase()),
|
|
222328
|
+
};
|
|
222329
|
+
}
|
|
222330
|
+
/**
|
|
222331
|
+
* The shared `Profile` viewer in a dialog — the same modal the tenant
|
|
222332
|
+
* Management tab opens when a user row is clicked. Controlled variant for
|
|
222333
|
+
* hosts that trigger it from a whole table row.
|
|
222334
|
+
*
|
|
222335
|
+
* Radix portals the dialog into `document.body`, but a React portal still
|
|
222336
|
+
* bubbles its events through the React tree — so without the guard below, a
|
|
222337
|
+
* click *inside* the open profile would reach the row this dialog is rendered
|
|
222338
|
+
* from and fire its `onClick` (e.g. opening the enrollment progress modal
|
|
222339
|
+
* behind the profile). The wrapper is `display: contents`, so it adds nothing
|
|
222340
|
+
* to the host's layout.
|
|
222341
|
+
*/
|
|
222342
|
+
function UserProfileDialog({ tenantKey, username, isOpen, onClose, customization, currentSPA, }) {
|
|
222343
|
+
const t = useT();
|
|
222344
|
+
if (!isOpen)
|
|
222345
|
+
return null;
|
|
222346
|
+
return (jsx("span", { className: "contents", onClick: (event) => event.stopPropagation(), onMouseDown: (event) => event.stopPropagation(), onKeyDown: (event) => event.stopPropagation(), children: jsx(Dialog, { open: true, onOpenChange: onClose, children: jsxs(DialogContent, { autoFocus: false, className: "profile-component-dialog max-w-7xl w-[85vw] gap-0 overflow-hidden bg-white p-0", style: { height: '85vh', display: 'flex', flexDirection: 'column' }, "data-testid": "user-profile-link-dialog", children: [jsx(DialogTitle, { className: "sr-only", children: t('tabsUserstab.profileDialogTitle') }), jsx(DialogDescription, { className: "sr-only", children: t('tabsUserstab.profileDialogDescription') }), jsx(Profile, { tenant: tenantKey, tenants: [], username: username, onClose: onClose, customization: profileCustomization(customization, currentSPA), currentSPA: currentSPA })] }) }) }));
|
|
222347
|
+
}
|
|
222348
|
+
/**
|
|
222349
|
+
* Clickable user identity that opens the shared `Profile` viewer in a dialog
|
|
222350
|
+
* — the same modal the tenant Management tab opens when a user row is
|
|
222351
|
+
* clicked. `Profile` drops into preview (read-only) mode on its own for anyone
|
|
222352
|
+
* but the signed-in user. Used by the spend-cap tables and every analytics
|
|
222353
|
+
* surface that names a user; safe inside clickable rows and cards, since
|
|
222354
|
+
* neither its clicks nor its key presses reach the host's handlers.
|
|
222355
|
+
*/
|
|
222356
|
+
function UserProfileLink({ tenantKey, username, display, className, testId, customization, currentSPA, }) {
|
|
222357
|
+
const t = useT();
|
|
222358
|
+
const [isOpen, setIsOpen] = React__default.useState(false);
|
|
222359
|
+
if (!username) {
|
|
222360
|
+
// `inline-block`, or `truncate`'s `overflow: hidden` has nothing to clip:
|
|
222361
|
+
// an inline box takes its width from its own text.
|
|
222362
|
+
return (jsx("span", { className: cn('inline-block max-w-full truncate', className), "data-testid": testId, children: display }));
|
|
222363
|
+
}
|
|
222364
|
+
return (jsxs(Fragment$1, { children: [jsx("button", { type: "button", onClick: (event) => {
|
|
222365
|
+
event.stopPropagation();
|
|
222366
|
+
setIsOpen(true);
|
|
222367
|
+
},
|
|
222368
|
+
// Rows that open on Enter/Space would otherwise swallow the key press.
|
|
222369
|
+
onKeyDown: (event) => event.stopPropagation(), className: cn('max-w-full cursor-pointer truncate text-left hover:text-blue-600 hover:underline focus:text-blue-600 focus:outline-none', className), "aria-label": t('tabsUserstab.viewProfileAriaLabel', { name: display }), "data-testid": testId, children: display }), jsx(UserProfileDialog, { tenantKey: tenantKey, username: username, isOpen: isOpen, onClose: () => setIsOpen(false), customization: customization, currentSPA: currentSPA })] }));
|
|
222370
|
+
}
|
|
222371
|
+
|
|
220520
222372
|
const AdvancedPagination = ({ currentPage, totalPages, onPageChange, totalCount, itemsPerPage, itemLabel = 'items', variant = 'default', className, }) => {
|
|
220521
222373
|
const t = useT();
|
|
220522
222374
|
if (totalPages <= 1) {
|
|
@@ -222427,141 +224279,6 @@ function trimTrailingSlashes(value) {
|
|
|
222427
224279
|
return end === value.length ? value : value.slice(0, end);
|
|
222428
224280
|
}
|
|
222429
224281
|
|
|
222430
|
-
var COLLAPSIBLE_NAME = "Collapsible";
|
|
222431
|
-
var [createCollapsibleContext] = createContextScope$1(COLLAPSIBLE_NAME);
|
|
222432
|
-
var [CollapsibleProvider, useCollapsibleContext] = createCollapsibleContext(COLLAPSIBLE_NAME);
|
|
222433
|
-
var Collapsible$1 = React.forwardRef(
|
|
222434
|
-
(props, forwardedRef) => {
|
|
222435
|
-
const {
|
|
222436
|
-
__scopeCollapsible,
|
|
222437
|
-
open: openProp,
|
|
222438
|
-
defaultOpen,
|
|
222439
|
-
disabled,
|
|
222440
|
-
onOpenChange,
|
|
222441
|
-
...collapsibleProps
|
|
222442
|
-
} = props;
|
|
222443
|
-
const [open, setOpen] = useControllableState$1({
|
|
222444
|
-
prop: openProp,
|
|
222445
|
-
defaultProp: defaultOpen ?? false,
|
|
222446
|
-
onChange: onOpenChange,
|
|
222447
|
-
caller: COLLAPSIBLE_NAME
|
|
222448
|
-
});
|
|
222449
|
-
return /* @__PURE__ */ jsx(
|
|
222450
|
-
CollapsibleProvider,
|
|
222451
|
-
{
|
|
222452
|
-
scope: __scopeCollapsible,
|
|
222453
|
-
disabled,
|
|
222454
|
-
contentId: useId$1(),
|
|
222455
|
-
open,
|
|
222456
|
-
onOpenToggle: React.useCallback(() => setOpen((prevOpen) => !prevOpen), [setOpen]),
|
|
222457
|
-
children: /* @__PURE__ */ jsx(
|
|
222458
|
-
Primitive$2.div,
|
|
222459
|
-
{
|
|
222460
|
-
"data-state": getState$1(open),
|
|
222461
|
-
"data-disabled": disabled ? "" : void 0,
|
|
222462
|
-
...collapsibleProps,
|
|
222463
|
-
ref: forwardedRef
|
|
222464
|
-
}
|
|
222465
|
-
)
|
|
222466
|
-
}
|
|
222467
|
-
);
|
|
222468
|
-
}
|
|
222469
|
-
);
|
|
222470
|
-
Collapsible$1.displayName = COLLAPSIBLE_NAME;
|
|
222471
|
-
var TRIGGER_NAME$2 = "CollapsibleTrigger";
|
|
222472
|
-
var CollapsibleTrigger$1 = React.forwardRef(
|
|
222473
|
-
(props, forwardedRef) => {
|
|
222474
|
-
const { __scopeCollapsible, ...triggerProps } = props;
|
|
222475
|
-
const context = useCollapsibleContext(TRIGGER_NAME$2, __scopeCollapsible);
|
|
222476
|
-
return /* @__PURE__ */ jsx(
|
|
222477
|
-
Primitive$2.button,
|
|
222478
|
-
{
|
|
222479
|
-
type: "button",
|
|
222480
|
-
"aria-controls": context.contentId,
|
|
222481
|
-
"aria-expanded": context.open || false,
|
|
222482
|
-
"data-state": getState$1(context.open),
|
|
222483
|
-
"data-disabled": context.disabled ? "" : void 0,
|
|
222484
|
-
disabled: context.disabled,
|
|
222485
|
-
...triggerProps,
|
|
222486
|
-
ref: forwardedRef,
|
|
222487
|
-
onClick: composeEventHandlers$1(props.onClick, context.onOpenToggle)
|
|
222488
|
-
}
|
|
222489
|
-
);
|
|
222490
|
-
}
|
|
222491
|
-
);
|
|
222492
|
-
CollapsibleTrigger$1.displayName = TRIGGER_NAME$2;
|
|
222493
|
-
var CONTENT_NAME$3 = "CollapsibleContent";
|
|
222494
|
-
var CollapsibleContent$1 = React.forwardRef(
|
|
222495
|
-
(props, forwardedRef) => {
|
|
222496
|
-
const { forceMount, ...contentProps } = props;
|
|
222497
|
-
const context = useCollapsibleContext(CONTENT_NAME$3, props.__scopeCollapsible);
|
|
222498
|
-
return /* @__PURE__ */ jsx(Presence$2, { present: forceMount || context.open, children: ({ present }) => /* @__PURE__ */ jsx(CollapsibleContentImpl, { ...contentProps, ref: forwardedRef, present }) });
|
|
222499
|
-
}
|
|
222500
|
-
);
|
|
222501
|
-
CollapsibleContent$1.displayName = CONTENT_NAME$3;
|
|
222502
|
-
var CollapsibleContentImpl = React.forwardRef((props, forwardedRef) => {
|
|
222503
|
-
const { __scopeCollapsible, present, children, ...contentProps } = props;
|
|
222504
|
-
const context = useCollapsibleContext(CONTENT_NAME$3, __scopeCollapsible);
|
|
222505
|
-
const [isPresent, setIsPresent] = React.useState(present);
|
|
222506
|
-
const ref = React.useRef(null);
|
|
222507
|
-
const composedRefs = useComposedRefs$1(forwardedRef, ref);
|
|
222508
|
-
const heightRef = React.useRef(0);
|
|
222509
|
-
const height = heightRef.current;
|
|
222510
|
-
const widthRef = React.useRef(0);
|
|
222511
|
-
const width = widthRef.current;
|
|
222512
|
-
const isOpen = context.open || isPresent;
|
|
222513
|
-
const isMountAnimationPreventedRef = React.useRef(isOpen);
|
|
222514
|
-
const originalStylesRef = React.useRef(void 0);
|
|
222515
|
-
React.useEffect(() => {
|
|
222516
|
-
const rAF = requestAnimationFrame(() => isMountAnimationPreventedRef.current = false);
|
|
222517
|
-
return () => cancelAnimationFrame(rAF);
|
|
222518
|
-
}, []);
|
|
222519
|
-
useLayoutEffect2$1(() => {
|
|
222520
|
-
const node = ref.current;
|
|
222521
|
-
if (node) {
|
|
222522
|
-
originalStylesRef.current = originalStylesRef.current || {
|
|
222523
|
-
transitionDuration: node.style.transitionDuration,
|
|
222524
|
-
animationName: node.style.animationName
|
|
222525
|
-
};
|
|
222526
|
-
node.style.transitionDuration = "0s";
|
|
222527
|
-
node.style.animationName = "none";
|
|
222528
|
-
const rect = node.getBoundingClientRect();
|
|
222529
|
-
heightRef.current = rect.height;
|
|
222530
|
-
widthRef.current = rect.width;
|
|
222531
|
-
if (!isMountAnimationPreventedRef.current) {
|
|
222532
|
-
node.style.transitionDuration = originalStylesRef.current.transitionDuration;
|
|
222533
|
-
node.style.animationName = originalStylesRef.current.animationName;
|
|
222534
|
-
}
|
|
222535
|
-
setIsPresent(present);
|
|
222536
|
-
}
|
|
222537
|
-
}, [context.open, present]);
|
|
222538
|
-
return /* @__PURE__ */ jsx(
|
|
222539
|
-
Primitive$2.div,
|
|
222540
|
-
{
|
|
222541
|
-
"data-state": getState$1(context.open),
|
|
222542
|
-
"data-disabled": context.disabled ? "" : void 0,
|
|
222543
|
-
id: context.contentId,
|
|
222544
|
-
hidden: !isOpen,
|
|
222545
|
-
...contentProps,
|
|
222546
|
-
ref: composedRefs,
|
|
222547
|
-
style: {
|
|
222548
|
-
[`--radix-collapsible-content-height`]: height ? `${height}px` : void 0,
|
|
222549
|
-
[`--radix-collapsible-content-width`]: width ? `${width}px` : void 0,
|
|
222550
|
-
...props.style
|
|
222551
|
-
},
|
|
222552
|
-
children: isOpen && children
|
|
222553
|
-
}
|
|
222554
|
-
);
|
|
222555
|
-
});
|
|
222556
|
-
function getState$1(open) {
|
|
222557
|
-
return open ? "open" : "closed";
|
|
222558
|
-
}
|
|
222559
|
-
var Root$5 = Collapsible$1;
|
|
222560
|
-
|
|
222561
|
-
const Collapsible = Root$5;
|
|
222562
|
-
const CollapsibleTrigger = CollapsibleTrigger$1;
|
|
222563
|
-
const CollapsibleContent = CollapsibleContent$1;
|
|
222564
|
-
|
|
222565
224282
|
// Pure logic behind the application form (questions) editor. No React here so
|
|
222566
224283
|
// it stays unit testable. The backend validates schemas on save and remains
|
|
222567
224284
|
// authoritative; these helpers only shape the editor's local state.
|
|
@@ -226185,19 +227902,6 @@ function AddCreditsModal({ isOpen, onClose, tenant }) {
|
|
|
226185
227902
|
return (jsx(Dialog, { open: isOpen, onOpenChange: handleClose, children: jsxs(DialogContent, { className: "max-w-md", children: [jsxs(DialogHeader, { children: [jsx(DialogTitle, { children: t('profileAddCreditsModal.title') }), jsx(DialogDescription, { children: t('profileAddCreditsModal.description') })] }), jsxs("form", { onSubmit: handleSubmit, className: "space-y-6", children: [jsxs("div", { className: "space-y-2", children: [jsx(Label$1, { htmlFor: "credit-amount", className: "text-sm font-medium", children: t('profileAddCreditsModal.amountLabel') }), jsxs("div", { className: "relative", children: [jsx(DollarSign, { className: "absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-slate-400" }), jsx(Input, { id: "credit-amount", type: "number", min: "0.01", step: "0.01", placeholder: "50.00", value: amount, onChange: (e) => setAmount(e.target.value), className: "pl-9" })] }), jsx("p", { className: "text-xs text-slate-500 dark:text-slate-400", children: t('profileAddCreditsModal.amountHint') })] }), jsxs("div", { className: "flex items-start gap-2 p-3 bg-blue-50 dark:bg-blue-900/20 rounded-lg border border-blue-100 dark:border-blue-800", children: [jsx(CircleAlert, { className: "h-4 w-4 text-blue-500 mt-0.5 flex-shrink-0" }), jsx("p", { className: "text-xs text-blue-700 dark:text-blue-300", children: t('profileAddCreditsModal.paymentMethodNotice') })] }), jsxs(DialogFooter, { className: "gap-2 sm:gap-0", children: [jsx(Button$1, { type: "button", variant: "outline", onClick: handleClose, children: t('profileAddCreditsModal.cancel') }), jsx(Button$1, { type: "submit", disabled: isLoading, className: "bg-gradient-to-r from-[#2563EB] to-[#93C5FD] hover:opacity-90 text-white", children: isLoading ? (jsxs(Fragment$1, { children: [jsx(LoaderCircle, { className: "mr-2 h-4 w-4 animate-spin" }), t('profileAddCreditsModal.processing')] })) : (t('profileAddCreditsModal.addCredits')) })] })] })] }) }));
|
|
226186
227903
|
}
|
|
226187
227904
|
|
|
226188
|
-
/**
|
|
226189
|
-
* The info icon that sits on every analytics card and, on hover or keyboard
|
|
226190
|
-
* focus, explains what the card measures. The description doubles as the
|
|
226191
|
-
* accessible name so screen readers get it without needing the hover.
|
|
226192
|
-
*
|
|
226193
|
-
* Uses the tooltip primitives directly rather than the shared `TooltipContent`
|
|
226194
|
-
* because analytics wants a light popover, while `TooltipContent` is the dark
|
|
226195
|
-
* `bg-primary` style the rest of the app relies on.
|
|
226196
|
-
*/
|
|
226197
|
-
function CardInfoIcon({ title, description, className }) {
|
|
226198
|
-
return (jsxs(Tooltip$1, { children: [jsx(TooltipTrigger, { asChild: true, children: jsx("button", { type: "button", "aria-label": description, className: cn('shrink-0 cursor-help rounded p-1 text-[#898989] transition-colors hover:bg-gray-100 hover:text-[#38A1E5] focus-visible:ring-2 focus-visible:ring-[#38A1E5] focus-visible:outline-none', className), children: jsx(Info$3, { className: "h-4 w-4", "aria-hidden": "true" }) }) }), jsx(Portal$2, { children: jsxs(Content2$3, { "data-slot": "tooltip-content", side: "top", align: "center", sideOffset: 6, collisionPadding: 12, className: "animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 z-50 max-w-[260px] rounded-lg border border-[oklch(0.922_0_0)] bg-white p-3 shadow-lg", children: [title && (jsx("div", { "data-slot": "tooltip-title", className: "mb-1 text-sm font-semibold text-[#484848]", children: title })), jsx("p", { "data-slot": "tooltip-description", className: "text-sm leading-relaxed text-[#646464]", children: description })] }) })] }));
|
|
226199
|
-
}
|
|
226200
|
-
|
|
226201
227905
|
/**
|
|
226202
227906
|
* Shared utilities for tab label systems.
|
|
226203
227907
|
*
|
|
@@ -226780,62 +228484,6 @@ function SpendLimitsSection({ tenantKey, labels: labelsOverride }) {
|
|
|
226780
228484
|
return (jsxs(Fragment$1, { children: [jsxs("div", { "data-testid": "spend-limits-workspace-section", className: "rounded-lg border border-[#e5e5e5] bg-white shadow-[0_1px_2px_0_rgba(0,0,0,0.05)] dark:bg-zinc-900 dark:border-zinc-800", children: [jsx("div", { className: "flex flex-col gap-2 p-4 sm:flex-row sm:items-start sm:justify-between", children: jsxs("div", { className: "space-y-0.5", children: [jsx("h3", { className: "text-[16px] font-medium leading-6 text-[#101828] dark:text-gray-100", children: labels.tenantSections.workspace.title }), jsx("p", { className: "text-[13px] font-normal leading-5 text-[#4a5565] dark:text-gray-400", children: labels.tenantSections.workspace.description })] }) }), jsx("div", { className: "border-t border-[#e5e7eb] dark:border-zinc-800 px-4 py-3", children: isTenantCapLoading ? (jsx("div", { className: "flex items-center justify-center py-8", "data-testid": "tenant-cap-loading", children: jsx(Spinner, {}) })) : isTenantForbidden ? (jsxs("div", { className: "flex flex-col items-center gap-2 rounded-lg border border-gray-200 bg-gray-50 px-4 py-10 text-center", "data-testid": "spend-limits-denied", children: [jsx(ShieldAlert, { className: "h-6 w-6 text-gray-400" }), jsx("p", { className: "text-sm font-medium text-gray-900", children: labels.denied.title }), jsx("p", { className: "max-w-sm text-xs text-gray-600", children: labels.denied.description })] })) : (jsxs("div", { className: "space-y-4", children: [!tenantCap && (monthlySpend != null || totalSpend != null) && (jsxs("div", { className: "space-y-1", "data-testid": "workspace-actual-spend-stats", children: [jsxs("div", { className: "grid grid-cols-1 gap-4 sm:grid-cols-2", children: [monthlySpend != null && (jsxs("div", { className: "space-y-0.5", children: [jsx("p", { className: "text-[11px] font-medium uppercase tracking-wide text-[#6a7282] dark:text-gray-400", children: labels.tenantSections.noCapStats.spentThisMonth }), jsx("p", { className: "text-[18px] font-semibold leading-6 text-[#101828] dark:text-gray-100", "data-testid": "workspace-actual-spend-month", children: formatUsd$1(String(monthlySpend)) })] })), totalSpend != null && (jsxs("div", { className: "space-y-0.5", children: [jsx("p", { className: "text-[11px] font-medium uppercase tracking-wide text-[#6a7282] dark:text-gray-400", children: labels.tenantSections.noCapStats.spentAllTime }), jsx("p", { className: "text-[18px] font-semibold leading-6 text-[#101828] dark:text-gray-100", "data-testid": "workspace-actual-spend-total", children: formatUsd$1(String(totalSpend)) })] }))] }), jsx("p", { className: "text-[12px] font-normal leading-4 text-[#6a7282] dark:text-gray-500", children: labels.tenantSections.noCapStats.hint })] })), jsx(SpendCapForm, { labels: labels, cap: tenantCap, isSaving: isSavingTenantCap, isDeleting: isDeletingTenantCap, onSave: saveTenantCap, onDelete: () => setIsDeleteOpen(true), testId: "tenant-cap" })] })) })] }), jsx(Dialog, { open: isDeleteOpen, onOpenChange: () => setIsDeleteOpen(false), children: jsxs(DialogContent, { "aria-describedby": "tenant-cap-delete-description", "data-testid": "tenant-cap-delete-modal", children: [jsx(DialogHeader, { children: jsx(DialogTitle, { className: "ibl-dialog-title", children: labels.deleteModal.title }) }), jsx("div", { className: "my-5", id: "tenant-cap-delete-description", children: jsx("p", { className: "text-sm text-[#646464]", children: labels.deleteModal.description }) }), jsxs(DialogFooter, { className: "gap-3", children: [jsx(Button$1, { variant: "outline", onClick: () => setIsDeleteOpen(false), children: labels.deleteModal.cancel }), jsx(Button$1, { className: "bg-gradient-to-r from-[#2563EB] to-[#93C5FD] text-white hover:opacity-90", onClick: handleConfirmDelete, disabled: isDeletingTenantCap, "data-testid": "tenant-cap-delete-confirm", children: isDeletingTenantCap ? labels.form.removing : labels.deleteModal.confirm })] })] }) })] }));
|
|
226781
228485
|
}
|
|
226782
228486
|
|
|
226783
|
-
/** SPAs whose users have coursework, so the profile leads with a Gradebook tab. */
|
|
226784
|
-
const GRADEBOOK_SPAS = ['lms', 'skills'];
|
|
226785
|
-
/**
|
|
226786
|
-
* The customization `Profile` is opened with: whatever the host passed, with
|
|
226787
|
-
* the Gradebook tab defaulted from the SPA it runs in. An explicit
|
|
226788
|
-
* `showGradebookTab` always wins, so a host can force it either way.
|
|
226789
|
-
*/
|
|
226790
|
-
function profileCustomization(customization, currentSPA) {
|
|
226791
|
-
var _a;
|
|
226792
|
-
return {
|
|
226793
|
-
...customization,
|
|
226794
|
-
showGradebookTab: (_a = customization === null || customization === void 0 ? void 0 : customization.showGradebookTab) !== null && _a !== void 0 ? _a : GRADEBOOK_SPAS.includes((currentSPA !== null && currentSPA !== void 0 ? currentSPA : '').trim().toLowerCase()),
|
|
226795
|
-
};
|
|
226796
|
-
}
|
|
226797
|
-
/**
|
|
226798
|
-
* The shared `Profile` viewer in a dialog — the same modal the tenant
|
|
226799
|
-
* Management tab opens when a user row is clicked. Controlled variant for
|
|
226800
|
-
* hosts that trigger it from a whole table row.
|
|
226801
|
-
*
|
|
226802
|
-
* Radix portals the dialog into `document.body`, but a React portal still
|
|
226803
|
-
* bubbles its events through the React tree — so without the guard below, a
|
|
226804
|
-
* click *inside* the open profile would reach the row this dialog is rendered
|
|
226805
|
-
* from and fire its `onClick` (e.g. opening the enrollment progress modal
|
|
226806
|
-
* behind the profile). The wrapper is `display: contents`, so it adds nothing
|
|
226807
|
-
* to the host's layout.
|
|
226808
|
-
*/
|
|
226809
|
-
function UserProfileDialog({ tenantKey, username, isOpen, onClose, customization, currentSPA, }) {
|
|
226810
|
-
const t = useT();
|
|
226811
|
-
if (!isOpen)
|
|
226812
|
-
return null;
|
|
226813
|
-
return (jsx("span", { className: "contents", onClick: (event) => event.stopPropagation(), onMouseDown: (event) => event.stopPropagation(), onKeyDown: (event) => event.stopPropagation(), children: jsx(Dialog, { open: true, onOpenChange: onClose, children: jsxs(DialogContent, { autoFocus: false, className: "profile-component-dialog max-w-7xl w-[85vw] gap-0 overflow-hidden bg-white p-0", style: { height: '85vh', display: 'flex', flexDirection: 'column' }, "data-testid": "user-profile-link-dialog", children: [jsx(DialogTitle, { className: "sr-only", children: t('tabsUserstab.profileDialogTitle') }), jsx(DialogDescription, { className: "sr-only", children: t('tabsUserstab.profileDialogDescription') }), jsx(Profile, { tenant: tenantKey, tenants: [], username: username, onClose: onClose, customization: profileCustomization(customization, currentSPA), currentSPA: currentSPA })] }) }) }));
|
|
226814
|
-
}
|
|
226815
|
-
/**
|
|
226816
|
-
* Clickable user identity that opens the shared `Profile` viewer in a dialog
|
|
226817
|
-
* — the same modal the tenant Management tab opens when a user row is
|
|
226818
|
-
* clicked. `Profile` drops into preview (read-only) mode on its own for anyone
|
|
226819
|
-
* but the signed-in user. Used by the spend-cap tables and every analytics
|
|
226820
|
-
* surface that names a user; safe inside clickable rows and cards, since
|
|
226821
|
-
* neither its clicks nor its key presses reach the host's handlers.
|
|
226822
|
-
*/
|
|
226823
|
-
function UserProfileLink({ tenantKey, username, display, className, testId, customization, currentSPA, }) {
|
|
226824
|
-
const t = useT();
|
|
226825
|
-
const [isOpen, setIsOpen] = React__default.useState(false);
|
|
226826
|
-
if (!username) {
|
|
226827
|
-
// `inline-block`, or `truncate`'s `overflow: hidden` has nothing to clip:
|
|
226828
|
-
// an inline box takes its width from its own text.
|
|
226829
|
-
return (jsx("span", { className: cn('inline-block max-w-full truncate', className), "data-testid": testId, children: display }));
|
|
226830
|
-
}
|
|
226831
|
-
return (jsxs(Fragment$1, { children: [jsx("button", { type: "button", onClick: (event) => {
|
|
226832
|
-
event.stopPropagation();
|
|
226833
|
-
setIsOpen(true);
|
|
226834
|
-
},
|
|
226835
|
-
// Rows that open on Enter/Space would otherwise swallow the key press.
|
|
226836
|
-
onKeyDown: (event) => event.stopPropagation(), className: cn('max-w-full cursor-pointer truncate text-left hover:text-blue-600 hover:underline focus:text-blue-600 focus:outline-none', className), "aria-label": t('tabsUserstab.viewProfileAriaLabel', { name: display }), "data-testid": testId, children: display }), jsx(UserProfileDialog, { tenantKey: tenantKey, username: username, isOpen: isOpen, onClose: () => setIsOpen(false), customization: customization, currentSPA: currentSPA })] }));
|
|
226837
|
-
}
|
|
226838
|
-
|
|
226839
228487
|
/**
|
|
226840
228488
|
* Add/edit dialog for one per-user spend limit, mirroring the grader
|
|
226841
228489
|
* criterion modal: create mode starts with a searchable platform-user picker
|
|
@@ -229474,11 +231122,11 @@ function StripeConnect({ platformKey }) {
|
|
|
229474
231122
|
}
|
|
229475
231123
|
};
|
|
229476
231124
|
if (isLoading) {
|
|
229477
|
-
return (jsx(Card, { className: "shadow-sm border", style: { borderColor: 'oklch(.922 0 0)' }, children: jsx(CardContent, { className: "p-6", children: jsxs("div", { className: "flex items-center gap-4", children: [jsx(Skeleton, { className: "h-12 w-12 rounded-full" }), jsxs("div", { className: "flex-1 space-y-2", children: [jsx(Skeleton, { className: "h-5 w-48" }), jsx(Skeleton, { className: "h-4 w-72" })] }), jsx(Skeleton, { className: "h-9 w-32" })] }) }) }));
|
|
231125
|
+
return (jsx(Card$1, { className: "shadow-sm border", style: { borderColor: 'oklch(.922 0 0)' }, children: jsx(CardContent, { className: "p-6", children: jsxs("div", { className: "flex items-center gap-4", children: [jsx(Skeleton, { className: "h-12 w-12 rounded-full" }), jsxs("div", { className: "flex-1 space-y-2", children: [jsx(Skeleton, { className: "h-5 w-48" }), jsx(Skeleton, { className: "h-4 w-72" })] }), jsx(Skeleton, { className: "h-9 w-32" })] }) }) }));
|
|
229478
231126
|
}
|
|
229479
231127
|
const isReady = status === null || status === void 0 ? void 0 : status.is_ready_for_payments;
|
|
229480
231128
|
const hasAccount = status === null || status === void 0 ? void 0 : status.has_account;
|
|
229481
|
-
return (jsx(Card, { className: "shadow-sm border", style: { borderColor: 'oklch(.922 0 0)' }, children: jsx(CardContent, { className: "p-6", children: jsxs("div", { className: "flex flex-col sm:flex-row items-start sm:items-center gap-4", children: [jsxs("div", { className: "flex-1 min-w-0", children: [jsxs("div", { className: "flex items-center gap-2 mb-1", children: [jsx("h4", { className: "text-base font-semibold text-gray-900 dark:text-gray-100", children: t('monetizationStripeConnect.stripeConfiguration') }), isReady ? (jsx(Badge, { className: "bg-blue-100 text-blue-700 border-blue-200", children: t('monetizationStripeConnect.badgeConfigured') })) : hasAccount ? (jsx(Badge, { className: "bg-yellow-100 text-yellow-700 border-yellow-200", children: t('monetizationStripeConnect.badgeIncomplete') })) : (jsx(Badge, { variant: "secondary", children: t('monetizationStripeConnect.badgeNotConfigured') }))] }), isReady ? (jsxs("p", { className: "text-sm text-gray-500", children: [t('monetizationStripeConnect.stripeConnectedReady'), (status === null || status === void 0 ? void 0 : status.charges_enabled) && ' ' + t('monetizationStripeConnect.chargesEnabled'), (status === null || status === void 0 ? void 0 : status.payouts_enabled) && ' ' + t('monetizationStripeConnect.payoutsEnabled')] })) : hasAccount ? (jsx("p", { className: "text-sm text-gray-500", children: t('monetizationStripeConnect.onboardingIncomplete') })) : (jsx("p", { className: "text-sm text-gray-500", children: t('monetizationStripeConnect.connectStripePrompt') }))] }), jsx("div", { className: "flex gap-2 flex-shrink-0", children: isError ? null : isReady ? (jsxs(Button$1, { onClick: handleOpenDashboard, disabled: isRedirecting, variant: "outline", className: "cursor-pointer", children: [isRedirecting ? (jsx(LoaderCircle, { className: "h-4 w-4 mr-2 animate-spin" })) : (jsx(ExternalLink, { className: "h-4 w-4 mr-2" })), t('monetizationStripeConnect.stripeDashboardButton')] })) : (jsxs(Button$1, { onClick: handleStartOnboarding, disabled: isStartingOnboarding || isRedirecting, className: "bg-gradient-to-r from-[#2563EB] to-[#93C5FD] hover:opacity-90 text-white cursor-pointer", children: [isStartingOnboarding || isRedirecting ? (jsx(LoaderCircle, { className: "h-4 w-4 mr-2 animate-spin" })) : (jsx(Link$1, { className: "h-4 w-4 mr-2" })), isStartingOnboarding || isRedirecting
|
|
231129
|
+
return (jsx(Card$1, { className: "shadow-sm border", style: { borderColor: 'oklch(.922 0 0)' }, children: jsx(CardContent, { className: "p-6", children: jsxs("div", { className: "flex flex-col sm:flex-row items-start sm:items-center gap-4", children: [jsxs("div", { className: "flex-1 min-w-0", children: [jsxs("div", { className: "flex items-center gap-2 mb-1", children: [jsx("h4", { className: "text-base font-semibold text-gray-900 dark:text-gray-100", children: t('monetizationStripeConnect.stripeConfiguration') }), isReady ? (jsx(Badge, { className: "bg-blue-100 text-blue-700 border-blue-200", children: t('monetizationStripeConnect.badgeConfigured') })) : hasAccount ? (jsx(Badge, { className: "bg-yellow-100 text-yellow-700 border-yellow-200", children: t('monetizationStripeConnect.badgeIncomplete') })) : (jsx(Badge, { variant: "secondary", children: t('monetizationStripeConnect.badgeNotConfigured') }))] }), isReady ? (jsxs("p", { className: "text-sm text-gray-500", children: [t('monetizationStripeConnect.stripeConnectedReady'), (status === null || status === void 0 ? void 0 : status.charges_enabled) && ' ' + t('monetizationStripeConnect.chargesEnabled'), (status === null || status === void 0 ? void 0 : status.payouts_enabled) && ' ' + t('monetizationStripeConnect.payoutsEnabled')] })) : hasAccount ? (jsx("p", { className: "text-sm text-gray-500", children: t('monetizationStripeConnect.onboardingIncomplete') })) : (jsx("p", { className: "text-sm text-gray-500", children: t('monetizationStripeConnect.connectStripePrompt') }))] }), jsx("div", { className: "flex gap-2 flex-shrink-0", children: isError ? null : isReady ? (jsxs(Button$1, { onClick: handleOpenDashboard, disabled: isRedirecting, variant: "outline", className: "cursor-pointer", children: [isRedirecting ? (jsx(LoaderCircle, { className: "h-4 w-4 mr-2 animate-spin" })) : (jsx(ExternalLink, { className: "h-4 w-4 mr-2" })), t('monetizationStripeConnect.stripeDashboardButton')] })) : (jsxs(Button$1, { onClick: handleStartOnboarding, disabled: isStartingOnboarding || isRedirecting, className: "bg-gradient-to-r from-[#2563EB] to-[#93C5FD] hover:opacity-90 text-white cursor-pointer", children: [isStartingOnboarding || isRedirecting ? (jsx(LoaderCircle, { className: "h-4 w-4 mr-2 animate-spin" })) : (jsx(Link$1, { className: "h-4 w-4 mr-2" })), isStartingOnboarding || isRedirecting
|
|
229482
231130
|
? t('monetizationStripeConnect.redirecting')
|
|
229483
231131
|
: hasAccount
|
|
229484
231132
|
? t('monetizationStripeConnect.completeSetup')
|
|
@@ -229631,12 +231279,12 @@ function PaywalledItemsList({ platformKey, onSelectItem, onAddCustomItem, }) {
|
|
|
229631
231279
|
page_size: PAGE_SIZE$a,
|
|
229632
231280
|
...(statusFilter !== 'all' && { is_enabled: statusFilter === 'active' }),
|
|
229633
231281
|
}, { refetchOnMountOrArgChange: true });
|
|
229634
|
-
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) => {
|
|
231282
|
+
return (jsxs("div", { className: "space-y-4", children: [jsx(Card$1, { 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) => {
|
|
229635
231283
|
setStatusFilter(v);
|
|
229636
231284
|
setPage(1);
|
|
229637
231285
|
}, children: [jsx(SelectTrigger, { className: "w-[130px] h-8 text-xs", children: jsx(SelectValue, {}) }), jsxs(SelectContent, { children: [jsx(SelectItem, { value: "all", children: t('monetizationPaywalledItemsList.filterAll') }), jsx(SelectItem, { value: "active", children: t('monetizationPaywalledItemsList.filterActive') }), jsx(SelectItem, { value: "disabled", children: t('monetizationPaywalledItemsList.filterDisabled') })] })] })] }), isLoading ? (jsx("div", { className: "space-y-2", children: [1, 2, 3].map((i) => (jsx(Skeleton, { className: "h-16 w-full" }, i))) })) : (paywalls === null || paywalls === void 0 ? void 0 : paywalls.results) && paywalls.results.length > 0 ? (jsxs(Fragment$1, { children: [paywalls.results.map((pw) => {
|
|
229638
231286
|
var _a;
|
|
229639
|
-
return (jsx(Card, { className: "shadow-sm border hover:border-blue-200 transition-colors cursor-pointer", style: { borderColor: 'oklch(.922 0 0)' }, onClick: () => onSelectItem(pw.item_type, pw.item_id, pw.item_name), children: jsxs(CardContent, { className: "p-4 flex items-center justify-between", children: [jsx("div", { className: "flex items-center gap-3", children: jsxs("div", { children: [jsx("span", { className: "text-sm font-medium text-gray-900 dark:text-gray-100", children: pw.item_name || pw.item_id }), jsxs("div", { className: "flex items-center gap-2 mt-0.5", children: [jsx(Badge, { variant: "secondary", className: "text-xs capitalize", children: displayItemType(pw.item_type) }), ((_a = pw.prices) === null || _a === void 0 ? void 0 : _a.length) > 0 &&
|
|
231287
|
+
return (jsx(Card$1, { className: "shadow-sm border hover:border-blue-200 transition-colors cursor-pointer", style: { borderColor: 'oklch(.922 0 0)' }, onClick: () => onSelectItem(pw.item_type, pw.item_id, pw.item_name), children: jsxs(CardContent, { className: "p-4 flex items-center justify-between", children: [jsx("div", { className: "flex items-center gap-3", children: jsxs("div", { children: [jsx("span", { className: "text-sm font-medium text-gray-900 dark:text-gray-100", children: pw.item_name || pw.item_id }), jsxs("div", { className: "flex items-center gap-2 mt-0.5", children: [jsx(Badge, { variant: "secondary", className: "text-xs capitalize", children: displayItemType(pw.item_type) }), ((_a = pw.prices) === null || _a === void 0 ? void 0 : _a.length) > 0 &&
|
|
229640
231288
|
(() => {
|
|
229641
231289
|
const activeCount = pw.prices.filter((p) => p.is_active).length;
|
|
229642
231290
|
return activeCount > 0 ? (jsx("span", { className: "text-xs text-gray-400", children: activeCount !== 1
|
|
@@ -229692,7 +231340,7 @@ function PriceForm({ form, onChange, onSave, onCancel, isSaving, isEdit, }) {
|
|
|
229692
231340
|
const handleRemoveFeature = (index) => {
|
|
229693
231341
|
onChange({ ...form, features: form.features.filter((_, i) => i !== index) });
|
|
229694
231342
|
};
|
|
229695
|
-
return (jsx(Card, { className: "shadow-sm border border-blue-200 bg-blue-50/30", style: { borderColor: 'oklch(.922 0 0)' }, children: jsxs(CardContent, { className: "p-4 space-y-3", children: [jsxs("div", { className: "grid grid-cols-1 sm:grid-cols-2 gap-3", children: [jsxs("div", { children: [jsx(Label$1, { className: "text-xs text-gray-500", children: t('monetizationPriceManagement.nameLabel') }), jsx(Input, { value: form.name, onChange: (e) => onChange({ ...form, name: e.target.value }), placeholder: t('monetizationPriceManagement.namePlaceholder'), className: "mt-1" })] }), jsxs("div", { children: [jsx(Label$1, { className: "text-xs text-gray-500", children: t('monetizationPriceManagement.amountLabel') }), jsx(Input, { type: "number", min: 0, step: "0.01", value: form.amount, onChange: (e) => onChange({ ...form, amount: e.target.value }), placeholder: t('monetizationPriceManagement.amountPlaceholder'), className: "mt-1" })] }), jsxs("div", { children: [jsx(Label$1, { className: "text-xs text-gray-500", children: t('monetizationPriceManagement.intervalLabel') }), jsxs(Select$1, { value: form.interval, onValueChange: (v) => onChange({ ...form, interval: v }), children: [jsx(SelectTrigger, { className: "mt-1", children: jsx(SelectValue, {}) }), jsxs(SelectContent, { children: [jsx(SelectItem, { value: "month", children: t('monetizationPriceManagement.intervalMonthly') }), jsx(SelectItem, { value: "year", children: t('monetizationPriceManagement.intervalYearly') }), jsx(SelectItem, { value: "one_time", children: t('monetizationPriceManagement.intervalOneTime') })] })] })] }), jsxs("div", { children: [jsx(Label$1, { className: "text-xs text-gray-500", children: t('monetizationPriceManagement.currencyLabel') }), jsx(Input, { value: form.currency, disabled: true, className: "mt-1 bg-gray-50 text-gray-500 cursor-not-allowed" })] })] }), jsxs("div", { children: [jsx(Label$1, { className: "text-xs text-gray-500", children: t('monetizationPriceManagement.descriptionLabel') }), jsx(Input, { value: form.description, onChange: (e) => onChange({ ...form, description: e.target.value }), placeholder: t('monetizationPriceManagement.descriptionPlaceholder'), className: "mt-1" })] }), jsxs("div", { children: [jsx(Label$1, { className: "text-xs text-gray-500", children: t('monetizationPriceManagement.featuresLabel') }), form.features.length > 0 && (jsx("div", { className: "flex flex-wrap gap-1.5 mt-1.5 mb-1.5", children: form.features.map((feature, i) => (jsxs(Badge, { variant: "secondary", className: "text-xs font-normal pl-2 pr-1 py-0.5 flex items-center gap-1", children: [feature, jsx("button", { type: "button", onClick: () => handleRemoveFeature(i), className: "hover:bg-gray-300 rounded-full p-0.5 transition-colors cursor-pointer", children: jsx(X$2, { className: "h-2.5 w-2.5" }) })] }, i))) })), jsxs("div", { className: "flex gap-1.5 mt-1", children: [jsx(Input, { value: featureInput, onChange: (e) => setFeatureInput(e.target.value), onKeyDown: (e) => {
|
|
231343
|
+
return (jsx(Card$1, { className: "shadow-sm border border-blue-200 bg-blue-50/30", style: { borderColor: 'oklch(.922 0 0)' }, children: jsxs(CardContent, { className: "p-4 space-y-3", children: [jsxs("div", { className: "grid grid-cols-1 sm:grid-cols-2 gap-3", children: [jsxs("div", { children: [jsx(Label$1, { className: "text-xs text-gray-500", children: t('monetizationPriceManagement.nameLabel') }), jsx(Input, { value: form.name, onChange: (e) => onChange({ ...form, name: e.target.value }), placeholder: t('monetizationPriceManagement.namePlaceholder'), className: "mt-1" })] }), jsxs("div", { children: [jsx(Label$1, { className: "text-xs text-gray-500", children: t('monetizationPriceManagement.amountLabel') }), jsx(Input, { type: "number", min: 0, step: "0.01", value: form.amount, onChange: (e) => onChange({ ...form, amount: e.target.value }), placeholder: t('monetizationPriceManagement.amountPlaceholder'), className: "mt-1" })] }), jsxs("div", { children: [jsx(Label$1, { className: "text-xs text-gray-500", children: t('monetizationPriceManagement.intervalLabel') }), jsxs(Select$1, { value: form.interval, onValueChange: (v) => onChange({ ...form, interval: v }), children: [jsx(SelectTrigger, { className: "mt-1", children: jsx(SelectValue, {}) }), jsxs(SelectContent, { children: [jsx(SelectItem, { value: "month", children: t('monetizationPriceManagement.intervalMonthly') }), jsx(SelectItem, { value: "year", children: t('monetizationPriceManagement.intervalYearly') }), jsx(SelectItem, { value: "one_time", children: t('monetizationPriceManagement.intervalOneTime') })] })] })] }), jsxs("div", { children: [jsx(Label$1, { className: "text-xs text-gray-500", children: t('monetizationPriceManagement.currencyLabel') }), jsx(Input, { value: form.currency, disabled: true, className: "mt-1 bg-gray-50 text-gray-500 cursor-not-allowed" })] })] }), jsxs("div", { children: [jsx(Label$1, { className: "text-xs text-gray-500", children: t('monetizationPriceManagement.descriptionLabel') }), jsx(Input, { value: form.description, onChange: (e) => onChange({ ...form, description: e.target.value }), placeholder: t('monetizationPriceManagement.descriptionPlaceholder'), className: "mt-1" })] }), jsxs("div", { children: [jsx(Label$1, { className: "text-xs text-gray-500", children: t('monetizationPriceManagement.featuresLabel') }), form.features.length > 0 && (jsx("div", { className: "flex flex-wrap gap-1.5 mt-1.5 mb-1.5", children: form.features.map((feature, i) => (jsxs(Badge, { variant: "secondary", className: "text-xs font-normal pl-2 pr-1 py-0.5 flex items-center gap-1", children: [feature, jsx("button", { type: "button", onClick: () => handleRemoveFeature(i), className: "hover:bg-gray-300 rounded-full p-0.5 transition-colors cursor-pointer", children: jsx(X$2, { className: "h-2.5 w-2.5" }) })] }, i))) })), jsxs("div", { className: "flex gap-1.5 mt-1", children: [jsx(Input, { value: featureInput, onChange: (e) => setFeatureInput(e.target.value), onKeyDown: (e) => {
|
|
229696
231344
|
if (e.key === 'Enter') {
|
|
229697
231345
|
e.preventDefault();
|
|
229698
231346
|
handleAddFeature();
|
|
@@ -229809,7 +231457,7 @@ function PriceManagement({ platformKey, itemType, itemId }) {
|
|
|
229809
231457
|
return editingPriceId === price.id ? (jsx(PriceForm, { form: formData, onChange: setFormData, onSave: handleUpdate, onCancel: () => {
|
|
229810
231458
|
setEditingPriceId(null);
|
|
229811
231459
|
setFormData(EMPTY_FORM$1);
|
|
229812
|
-
}, isSaving: isUpdating, isEdit: true }, price.id)) : (jsx(Card, { className: "shadow-sm border", style: { borderColor: 'oklch(.922 0 0)' }, children: jsx(CardContent, { className: "p-4", children: jsxs("div", { className: "flex items-center justify-between", children: [jsxs("div", { className: "flex items-center gap-3", children: [jsx(Tag, { className: "h-4 w-4 text-gray-400" }), jsxs("div", { children: [jsxs("div", { className: "flex items-center gap-2", children: [jsx("span", { className: "text-sm font-medium text-gray-900 dark:text-gray-100", children: price.name }), jsxs("span", { className: "text-sm font-semibold text-blue-600", children: ["$", price.amount, " ", formatInterval(price.interval)] }), !price.is_active && (jsx(Badge, { variant: "secondary", className: "text-xs", children: t('monetizationPriceManagement.inactiveBadge') }))] }), price.description && (jsx("p", { className: "text-xs text-gray-400 mt-0.5", children: price.description })), ((_a = price.features) === null || _a === void 0 ? void 0 : _a.length) > 0 && (jsx("div", { className: "flex flex-wrap gap-1 mt-1", children: price.features.map((f, i) => (jsx(Badge, { variant: "outline", className: "text-xs font-normal", children: f }, i))) }))] })] }), jsxs("div", { className: "flex gap-1 flex-shrink-0", children: [jsx(Button$1, { onClick: () => handleStartEdit(price), variant: "ghost", size: "sm", className: "h-8 w-8 p-0 cursor-pointer", children: jsx(Pencil, { className: "h-3 w-3" }) }), jsx(Button$1, { onClick: () => handleDelete(price.id), variant: "ghost", size: "sm", disabled: deletingId === price.id, className: "h-8 w-8 p-0 text-red-500 hover:text-red-700 cursor-pointer", children: deletingId === price.id ? (jsx(LoaderCircle, { className: "h-3 w-3 animate-spin" })) : (jsx(Trash2, { className: "h-3 w-3" })) })] })] }) }) }, price.id));
|
|
231460
|
+
}, isSaving: isUpdating, isEdit: true }, price.id)) : (jsx(Card$1, { className: "shadow-sm border", style: { borderColor: 'oklch(.922 0 0)' }, children: jsx(CardContent, { className: "p-4", children: jsxs("div", { className: "flex items-center justify-between", children: [jsxs("div", { className: "flex items-center gap-3", children: [jsx(Tag, { className: "h-4 w-4 text-gray-400" }), jsxs("div", { children: [jsxs("div", { className: "flex items-center gap-2", children: [jsx("span", { className: "text-sm font-medium text-gray-900 dark:text-gray-100", children: price.name }), jsxs("span", { className: "text-sm font-semibold text-blue-600", children: ["$", price.amount, " ", formatInterval(price.interval)] }), !price.is_active && (jsx(Badge, { variant: "secondary", className: "text-xs", children: t('monetizationPriceManagement.inactiveBadge') }))] }), price.description && (jsx("p", { className: "text-xs text-gray-400 mt-0.5", children: price.description })), ((_a = price.features) === null || _a === void 0 ? void 0 : _a.length) > 0 && (jsx("div", { className: "flex flex-wrap gap-1 mt-1", children: price.features.map((f, i) => (jsx(Badge, { variant: "outline", className: "text-xs font-normal", children: f }, i))) }))] })] }), jsxs("div", { className: "flex gap-1 flex-shrink-0", children: [jsx(Button$1, { onClick: () => handleStartEdit(price), variant: "ghost", size: "sm", className: "h-8 w-8 p-0 cursor-pointer", children: jsx(Pencil, { className: "h-3 w-3" }) }), jsx(Button$1, { onClick: () => handleDelete(price.id), variant: "ghost", size: "sm", disabled: deletingId === price.id, className: "h-8 w-8 p-0 text-red-500 hover:text-red-700 cursor-pointer", children: deletingId === price.id ? (jsx(LoaderCircle, { className: "h-3 w-3 animate-spin" })) : (jsx(Trash2, { className: "h-3 w-3" })) })] })] }) }) }, price.id));
|
|
229813
231461
|
}) })) : (jsx("p", { className: "text-xs text-gray-400 text-center py-4", children: t('monetizationPriceManagement.emptyState') }))] }));
|
|
229814
231462
|
}
|
|
229815
231463
|
|
|
@@ -229979,13 +231627,13 @@ function PaywallDetail({ platformKey, authURL, itemType, itemId, itemName, isCus
|
|
|
229979
231627
|
const currentIndex = wizardSteps.findIndex((s) => s.key === currentStep);
|
|
229980
231628
|
if (targetIndex < currentIndex)
|
|
229981
231629
|
setCurrentStep(step);
|
|
229982
|
-
} }), currentStep === 'custom-item' && isCustom && (jsx(Card, { className: "shadow-sm border", style: { borderColor: 'oklch(.922 0 0)' }, children: jsxs(CardContent, { className: "p-6 space-y-4", children: [jsx("h4", { className: "text-sm font-semibold text-gray-700 dark:text-gray-300", children: t('monetizationPaywallDetail.stepItemDetails') }), jsxs("div", { className: "space-y-3", children: [jsxs("div", { children: [jsx(Label$1, { className: "text-sm font-medium", children: t('monetizationPaywallDetail.labelItemType') }), jsx(Input, { value: customItemType, onChange: (e) => setCustomItemType(e.target.value), placeholder: t('monetizationPaywallDetail.placeholderItemType'), className: "mt-1", disabled: itemCreated }), customItemType && (jsx("p", { className: "text-xs text-gray-400 mt-1", children: t('monetizationPaywallDetail.slugPreview', { slug: slugify(customItemType) }) }))] }), jsxs("div", { children: [jsx(Label$1, { className: "text-sm font-medium", children: t('monetizationPaywallDetail.labelItemName') }), jsx(Input, { value: customItemName, onChange: (e) => setCustomItemName(e.target.value), placeholder: t('monetizationPaywallDetail.placeholderItemName'), className: "mt-1", disabled: itemCreated }), customItemName && (jsx("p", { className: "text-xs text-gray-400 mt-1", children: t('monetizationPaywallDetail.idPreview', { id: slugify(customItemName) }) }))] }), jsxs("div", { children: [jsx(Label$1, { className: "text-sm font-medium", children: t('monetizationPaywallDetail.labelDescription') }), jsx(Textarea, { value: customDescription, onChange: (e) => setCustomDescription(e.target.value), placeholder: t('monetizationPaywallDetail.placeholderDescription'), className: "mt-1", rows: 3 })] }), jsxs("div", { children: [jsx(Label$1, { className: "text-sm font-medium", children: t('monetizationPaywallDetail.labelProductUrl') }), jsx(Input, { type: "url", value: customProductUrl, onChange: (e) => setCustomProductUrl(e.target.value), placeholder: t('monetizationPaywallDetail.placeholderProductUrl'), className: "mt-1", disabled: itemCreated }), jsx("p", { className: "text-xs text-gray-400 mt-1", children: t('monetizationPaywallDetail.hintProductUrl') })] })] }), jsx("div", { className: "pt-3 border-t flex justify-end", children: jsxs(Button$1, { onClick: handleCreateCustomItem, disabled: isSaving || !customItemType.trim() || !customItemName.trim(), className: "bg-gradient-to-r from-[#2563EB] to-[#93C5FD] hover:opacity-90 text-white cursor-pointer", children: [isCreating ? (jsx(LoaderCircle, { className: "h-4 w-4 mr-2 animate-spin" })) : (jsx(ChevronRight, { className: "h-4 w-4 mr-2" })), t('monetizationPaywallDetail.createAndContinue')] }) })] }) })), currentStep === 'paywall' && (jsx(Card, { className: "shadow-sm border", style: { borderColor: 'oklch(.922 0 0)' }, children: jsxs(CardContent, { className: "p-6 space-y-5", children: [jsxs("div", { className: "flex items-center justify-between", children: [jsxs("div", { children: [jsx(Label$1, { className: "text-sm font-medium", children: t('monetizationPaywallDetail.labelPaywallEnabled') }), jsx("p", { className: "text-xs text-gray-400 mt-0.5", children: t('monetizationPaywallDetail.hintPaywallEnabled') })] }), jsx(Switch, { checked: isEnabled, onCheckedChange: setIsEnabled, className: "cursor-pointer data-[state=checked]:bg-blue-500" })] }), jsxs("div", { className: !isEnabled ? 'opacity-50 pointer-events-none' : '', children: [jsxs("div", { className: "flex items-center justify-between py-3 border-t", children: [jsxs("div", { children: [jsx(Label$1, { className: "text-sm font-medium", children: t('monetizationPaywallDetail.labelAllowFreeTier') }), jsx("p", { className: "text-xs text-gray-400 mt-0.5", children: t('monetizationPaywallDetail.hintAllowFreeTier') })] }), jsx(Switch, { checked: allowFreeTier, onCheckedChange: setAllowFreeTier, className: "cursor-pointer data-[state=checked]:bg-blue-500" })] }), jsxs("div", { className: "flex items-center justify-between py-3 border-t", children: [jsxs("div", { children: [jsx(Label$1, { className: "text-sm font-medium", children: t('monetizationPaywallDetail.labelTrialPeriod') }), jsx("p", { className: "text-xs text-gray-400 mt-0.5", children: t('monetizationPaywallDetail.hintTrialPeriod') })] }), jsx(Input, { type: "number", min: 0, value: trialDays, onChange: (e) => setTrialDays(parseInt(e.target.value) || 0), className: "w-24 text-right" })] }), jsxs("div", { className: "flex items-center justify-between py-3 border-t", children: [jsxs("div", { children: [jsx(Label$1, { className: "text-sm font-medium", children: t('monetizationPaywallDetail.labelExistingUsers') }), jsx("p", { className: "text-xs text-gray-400 mt-0.5", children: t('monetizationPaywallDetail.hintExistingUsers') })] }), jsxs(Select$1, { value: grandfathering, onValueChange: (v) => setGrandfathering(v), children: [jsx(SelectTrigger, { className: "w-[180px]", children: jsx(SelectValue, {}) }), jsxs(SelectContent, { children: [jsx(SelectItem, { value: "free_forever", children: t('monetizationPaywallDetail.grandfatheringFreeForever') }), jsx(SelectItem, { value: "require_subscription", children: t('monetizationPaywallDetail.grandfatheringRequireSubscription') })] })] })] })] }), jsx("div", { className: "pt-3 border-t flex justify-end", children: jsxs(Button$1, { onClick: handleSaveConfig, disabled: isSaving, className: "bg-gradient-to-r from-[#2563EB] to-[#93C5FD] hover:opacity-90 text-white cursor-pointer", children: [isSaving ? (jsx(LoaderCircle, { className: "h-4 w-4 mr-2 animate-spin" })) : (jsx(Check, { className: "h-4 w-4 mr-2" })), t('monetizationPaywallDetail.saveConfiguration')] }) })] }) })), currentStep === 'pricing' && (jsx(PriceManagement, { platformKey: platformKey, itemType: resolvedItemType, itemId: resolvedItemId }))] }));
|
|
231630
|
+
} }), currentStep === 'custom-item' && isCustom && (jsx(Card$1, { className: "shadow-sm border", style: { borderColor: 'oklch(.922 0 0)' }, children: jsxs(CardContent, { className: "p-6 space-y-4", children: [jsx("h4", { className: "text-sm font-semibold text-gray-700 dark:text-gray-300", children: t('monetizationPaywallDetail.stepItemDetails') }), jsxs("div", { className: "space-y-3", children: [jsxs("div", { children: [jsx(Label$1, { className: "text-sm font-medium", children: t('monetizationPaywallDetail.labelItemType') }), jsx(Input, { value: customItemType, onChange: (e) => setCustomItemType(e.target.value), placeholder: t('monetizationPaywallDetail.placeholderItemType'), className: "mt-1", disabled: itemCreated }), customItemType && (jsx("p", { className: "text-xs text-gray-400 mt-1", children: t('monetizationPaywallDetail.slugPreview', { slug: slugify(customItemType) }) }))] }), jsxs("div", { children: [jsx(Label$1, { className: "text-sm font-medium", children: t('monetizationPaywallDetail.labelItemName') }), jsx(Input, { value: customItemName, onChange: (e) => setCustomItemName(e.target.value), placeholder: t('monetizationPaywallDetail.placeholderItemName'), className: "mt-1", disabled: itemCreated }), customItemName && (jsx("p", { className: "text-xs text-gray-400 mt-1", children: t('monetizationPaywallDetail.idPreview', { id: slugify(customItemName) }) }))] }), jsxs("div", { children: [jsx(Label$1, { className: "text-sm font-medium", children: t('monetizationPaywallDetail.labelDescription') }), jsx(Textarea, { value: customDescription, onChange: (e) => setCustomDescription(e.target.value), placeholder: t('monetizationPaywallDetail.placeholderDescription'), className: "mt-1", rows: 3 })] }), jsxs("div", { children: [jsx(Label$1, { className: "text-sm font-medium", children: t('monetizationPaywallDetail.labelProductUrl') }), jsx(Input, { type: "url", value: customProductUrl, onChange: (e) => setCustomProductUrl(e.target.value), placeholder: t('monetizationPaywallDetail.placeholderProductUrl'), className: "mt-1", disabled: itemCreated }), jsx("p", { className: "text-xs text-gray-400 mt-1", children: t('monetizationPaywallDetail.hintProductUrl') })] })] }), jsx("div", { className: "pt-3 border-t flex justify-end", children: jsxs(Button$1, { onClick: handleCreateCustomItem, disabled: isSaving || !customItemType.trim() || !customItemName.trim(), className: "bg-gradient-to-r from-[#2563EB] to-[#93C5FD] hover:opacity-90 text-white cursor-pointer", children: [isCreating ? (jsx(LoaderCircle, { className: "h-4 w-4 mr-2 animate-spin" })) : (jsx(ChevronRight, { className: "h-4 w-4 mr-2" })), t('monetizationPaywallDetail.createAndContinue')] }) })] }) })), currentStep === 'paywall' && (jsx(Card$1, { className: "shadow-sm border", style: { borderColor: 'oklch(.922 0 0)' }, children: jsxs(CardContent, { className: "p-6 space-y-5", children: [jsxs("div", { className: "flex items-center justify-between", children: [jsxs("div", { children: [jsx(Label$1, { className: "text-sm font-medium", children: t('monetizationPaywallDetail.labelPaywallEnabled') }), jsx("p", { className: "text-xs text-gray-400 mt-0.5", children: t('monetizationPaywallDetail.hintPaywallEnabled') })] }), jsx(Switch, { checked: isEnabled, onCheckedChange: setIsEnabled, className: "cursor-pointer data-[state=checked]:bg-blue-500" })] }), jsxs("div", { className: !isEnabled ? 'opacity-50 pointer-events-none' : '', children: [jsxs("div", { className: "flex items-center justify-between py-3 border-t", children: [jsxs("div", { children: [jsx(Label$1, { className: "text-sm font-medium", children: t('monetizationPaywallDetail.labelAllowFreeTier') }), jsx("p", { className: "text-xs text-gray-400 mt-0.5", children: t('monetizationPaywallDetail.hintAllowFreeTier') })] }), jsx(Switch, { checked: allowFreeTier, onCheckedChange: setAllowFreeTier, className: "cursor-pointer data-[state=checked]:bg-blue-500" })] }), jsxs("div", { className: "flex items-center justify-between py-3 border-t", children: [jsxs("div", { children: [jsx(Label$1, { className: "text-sm font-medium", children: t('monetizationPaywallDetail.labelTrialPeriod') }), jsx("p", { className: "text-xs text-gray-400 mt-0.5", children: t('monetizationPaywallDetail.hintTrialPeriod') })] }), jsx(Input, { type: "number", min: 0, value: trialDays, onChange: (e) => setTrialDays(parseInt(e.target.value) || 0), className: "w-24 text-right" })] }), jsxs("div", { className: "flex items-center justify-between py-3 border-t", children: [jsxs("div", { children: [jsx(Label$1, { className: "text-sm font-medium", children: t('monetizationPaywallDetail.labelExistingUsers') }), jsx("p", { className: "text-xs text-gray-400 mt-0.5", children: t('monetizationPaywallDetail.hintExistingUsers') })] }), jsxs(Select$1, { value: grandfathering, onValueChange: (v) => setGrandfathering(v), children: [jsx(SelectTrigger, { className: "w-[180px]", children: jsx(SelectValue, {}) }), jsxs(SelectContent, { children: [jsx(SelectItem, { value: "free_forever", children: t('monetizationPaywallDetail.grandfatheringFreeForever') }), jsx(SelectItem, { value: "require_subscription", children: t('monetizationPaywallDetail.grandfatheringRequireSubscription') })] })] })] })] }), jsx("div", { className: "pt-3 border-t flex justify-end", children: jsxs(Button$1, { onClick: handleSaveConfig, disabled: isSaving, className: "bg-gradient-to-r from-[#2563EB] to-[#93C5FD] hover:opacity-90 text-white cursor-pointer", children: [isSaving ? (jsx(LoaderCircle, { className: "h-4 w-4 mr-2 animate-spin" })) : (jsx(Check, { className: "h-4 w-4 mr-2" })), t('monetizationPaywallDetail.saveConfiguration')] }) })] }) })), currentStep === 'pricing' && (jsx(PriceManagement, { platformKey: platformKey, itemType: resolvedItemType, itemId: resolvedItemId }))] }));
|
|
229983
231631
|
}
|
|
229984
231632
|
|
|
229985
231633
|
function PaywallConfig({ platformKey, authURL, disabled }) {
|
|
229986
231634
|
const [selectedItem, setSelectedItem] = useState(null);
|
|
229987
231635
|
if (disabled) {
|
|
229988
|
-
return (jsx(Card, { className: "shadow-sm border border-dashed", style: { borderColor: 'oklch(.922 0 0)' }, children: jsxs(CardContent, { className: "p-8 text-center", children: [jsx(Shield, { className: "h-10 w-10 mx-auto text-gray-300 mb-3" }), jsx("p", { className: "text-sm text-gray-400", children: "Connect Stripe first to configure paywalls." })] }) }));
|
|
231636
|
+
return (jsx(Card$1, { className: "shadow-sm border border-dashed", style: { borderColor: 'oklch(.922 0 0)' }, children: jsxs(CardContent, { className: "p-8 text-center", children: [jsx(Shield, { className: "h-10 w-10 mx-auto text-gray-300 mb-3" }), jsx("p", { className: "text-sm text-gray-400", children: "Connect Stripe first to configure paywalls." })] }) }));
|
|
229989
231637
|
}
|
|
229990
231638
|
if (selectedItem) {
|
|
229991
231639
|
return (jsx(PaywallDetail, { platformKey: platformKey, authURL: authURL, itemType: selectedItem.type, itemId: selectedItem.id, itemName: selectedItem.name, isCustom: selectedItem.isCustom, onBack: () => setSelectedItem(null) }));
|
|
@@ -247096,7 +248744,7 @@ function inputRulesPlugin(props) {
|
|
|
247096
248744
|
function getType(value) {
|
|
247097
248745
|
return Object.prototype.toString.call(value).slice(8, -1);
|
|
247098
248746
|
}
|
|
247099
|
-
function isPlainObject(value) {
|
|
248747
|
+
function isPlainObject$1(value) {
|
|
247100
248748
|
if (getType(value) !== "Object") {
|
|
247101
248749
|
return false;
|
|
247102
248750
|
}
|
|
@@ -247106,9 +248754,9 @@ function isPlainObject(value) {
|
|
|
247106
248754
|
// src/utilities/mergeDeep.ts
|
|
247107
248755
|
function mergeDeep(target, source) {
|
|
247108
248756
|
const output = { ...target };
|
|
247109
|
-
if (isPlainObject(target) && isPlainObject(source)) {
|
|
248757
|
+
if (isPlainObject$1(target) && isPlainObject$1(source)) {
|
|
247110
248758
|
Object.keys(source).forEach((key) => {
|
|
247111
|
-
if (isPlainObject(source[key]) && isPlainObject(target[key])) {
|
|
248759
|
+
if (isPlainObject$1(source[key]) && isPlainObject$1(target[key])) {
|
|
247112
248760
|
output[key] = mergeDeep(target[key], source[key]);
|
|
247113
248761
|
} else {
|
|
247114
248762
|
output[key] = source[key];
|
|
@@ -258125,6 +259773,492 @@ AnalyticsScopeContext.Provider;
|
|
|
258125
259773
|
|
|
258126
259774
|
Array.from({ length: 24 }, (_, i) => i);
|
|
258127
259775
|
|
|
259776
|
+
const asArray = (value) => (Array.isArray(value) ? value : []);
|
|
259777
|
+
const hasEntries = (value) => !!value && typeof value === 'object' && !Array.isArray(value) && Object.keys(value).length > 0;
|
|
259778
|
+
/** Rollup counts as the conversation-list endpoint reports them: numbers, numeric strings or `null`. */
|
|
259779
|
+
const toRollupCount = (value) => {
|
|
259780
|
+
const count = typeof value === 'string' ? Number(value) : (value !== null && value !== void 0 ? value : 0);
|
|
259781
|
+
return Number.isFinite(count) && count > 0 ? Math.floor(count) : 0;
|
|
259782
|
+
};
|
|
259783
|
+
/**
|
|
259784
|
+
* Sum the retrieved documents and tool calls over a conversation's turns, for
|
|
259785
|
+
* surfaces (the admin chat-history list) that carry the turns inline but have
|
|
259786
|
+
* no server-side rollup fields.
|
|
259787
|
+
*/
|
|
259788
|
+
function summarizeTranscriptTurns(turns) {
|
|
259789
|
+
return asArray(turns).reduce((rollup, turn) => ({
|
|
259790
|
+
documentsCount: rollup.documentsCount + asArray(turn === null || turn === void 0 ? void 0 : turn.documents).length,
|
|
259791
|
+
toolCallsCount: rollup.toolCallsCount + asArray(turn === null || turn === void 0 ? void 0 : turn.tool_calls).length,
|
|
259792
|
+
}), { documentsCount: 0, toolCallsCount: 0 });
|
|
259793
|
+
}
|
|
259794
|
+
/** A transcript's retrieved documents in the shape the chat's documents dialog lists. */
|
|
259795
|
+
function toRetrievedDocuments(documents) {
|
|
259796
|
+
return documents.map((doc) => {
|
|
259797
|
+
var _a, _b, _c, _d;
|
|
259798
|
+
return ({
|
|
259799
|
+
title: (_b = (_a = doc.title) !== null && _a !== void 0 ? _a : doc.source) !== null && _b !== void 0 ? _b : null,
|
|
259800
|
+
snippet: (_c = doc.snippet) !== null && _c !== void 0 ? _c : null,
|
|
259801
|
+
source: (_d = doc.source) !== null && _d !== void 0 ? _d : null,
|
|
259802
|
+
score: typeof doc.score === 'number' ? doc.score : null,
|
|
259803
|
+
});
|
|
259804
|
+
});
|
|
259805
|
+
}
|
|
259806
|
+
/**
|
|
259807
|
+
* Every document a conversation retrieved, across its turns, exactly as the
|
|
259808
|
+
* backend reports them — a source retrieved again on a later turn appears
|
|
259809
|
+
* again, so the count matches the backend's per-conversation totals. Comes
|
|
259810
|
+
* from the admin history payload itself, so it needs no per-user session
|
|
259811
|
+
* lookup.
|
|
259812
|
+
*/
|
|
259813
|
+
function conversationDocuments(turns) {
|
|
259814
|
+
return toRetrievedDocuments(asArray(turns).flatMap((turn) => asArray(turn === null || turn === void 0 ? void 0 : turn.documents)));
|
|
259815
|
+
}
|
|
259816
|
+
const asText = (value) => {
|
|
259817
|
+
if (value === null || value === undefined)
|
|
259818
|
+
return '';
|
|
259819
|
+
if (typeof value === 'string')
|
|
259820
|
+
return value;
|
|
259821
|
+
if (typeof value === 'number' || typeof value === 'boolean')
|
|
259822
|
+
return String(value);
|
|
259823
|
+
try {
|
|
259824
|
+
return JSON.stringify(value, null, 2);
|
|
259825
|
+
}
|
|
259826
|
+
catch (_a) {
|
|
259827
|
+
return String(value);
|
|
259828
|
+
}
|
|
259829
|
+
};
|
|
259830
|
+
/** A transcript's tool calls in the shape the chat's "Used N tools" record renders. */
|
|
259831
|
+
function toToolCallInfos(toolCalls) {
|
|
259832
|
+
return toolCalls.map((call, index) => {
|
|
259833
|
+
var _a;
|
|
259834
|
+
return ({
|
|
259835
|
+
id: `transcript-tool-${index}`,
|
|
259836
|
+
name: (_a = call.name) !== null && _a !== void 0 ? _a : '',
|
|
259837
|
+
input: call.input && typeof call.input === 'object' && !Array.isArray(call.input)
|
|
259838
|
+
? call.input
|
|
259839
|
+
: typeof call.input === 'string'
|
|
259840
|
+
? { input: call.input }
|
|
259841
|
+
: undefined,
|
|
259842
|
+
log: '',
|
|
259843
|
+
result: asText(call.output),
|
|
259844
|
+
});
|
|
259845
|
+
});
|
|
259846
|
+
}
|
|
259847
|
+
/** Whether a turn carries anything worth a details panel. */
|
|
259848
|
+
function hasTranscriptTurnDetails(turn) {
|
|
259849
|
+
if (!turn)
|
|
259850
|
+
return false;
|
|
259851
|
+
return (asArray(turn.documents).length > 0 ||
|
|
259852
|
+
asArray(turn.tool_calls).length > 0 ||
|
|
259853
|
+
hasEntries(turn.metadata) ||
|
|
259854
|
+
hasEntries(turn.request_context));
|
|
259855
|
+
}
|
|
259856
|
+
const isPlainObject = (value) => !!value && typeof value === 'object' && !Array.isArray(value);
|
|
259857
|
+
/** Nothing worth a row: null, blank strings, empty arrays and empty objects. */
|
|
259858
|
+
const isPresent = (value) => {
|
|
259859
|
+
if (value === null || value === undefined)
|
|
259860
|
+
return false;
|
|
259861
|
+
if (typeof value === 'string')
|
|
259862
|
+
return value.trim() !== '';
|
|
259863
|
+
if (Array.isArray(value))
|
|
259864
|
+
return value.length > 0;
|
|
259865
|
+
if (isPlainObject(value))
|
|
259866
|
+
return Object.keys(value).length > 0;
|
|
259867
|
+
return true;
|
|
259868
|
+
};
|
|
259869
|
+
const FIELD_ABBREVIATIONS = new Set([
|
|
259870
|
+
'ai',
|
|
259871
|
+
'api',
|
|
259872
|
+
'css',
|
|
259873
|
+
'csv',
|
|
259874
|
+
'html',
|
|
259875
|
+
'http',
|
|
259876
|
+
'https',
|
|
259877
|
+
'id',
|
|
259878
|
+
'ids',
|
|
259879
|
+
'ip',
|
|
259880
|
+
'json',
|
|
259881
|
+
'llm',
|
|
259882
|
+
'lti',
|
|
259883
|
+
'mcp',
|
|
259884
|
+
'mime',
|
|
259885
|
+
'pdf',
|
|
259886
|
+
'rag',
|
|
259887
|
+
'sso',
|
|
259888
|
+
'stt',
|
|
259889
|
+
'tts',
|
|
259890
|
+
'ui',
|
|
259891
|
+
'uri',
|
|
259892
|
+
'url',
|
|
259893
|
+
'urls',
|
|
259894
|
+
'uuid',
|
|
259895
|
+
]);
|
|
259896
|
+
/**
|
|
259897
|
+
* "file_references" → "File References", "llmModel" → "LLM Model". Backend
|
|
259898
|
+
* keys are never shown raw: every unknown key goes through this, and the
|
|
259899
|
+
* common ones get a translated label on top (see `useFieldLabels`).
|
|
259900
|
+
*/
|
|
259901
|
+
function humanizeFieldName(key) {
|
|
259902
|
+
const words = key
|
|
259903
|
+
.replace(/([a-z0-9])([A-Z])/g, '$1 $2')
|
|
259904
|
+
.replace(/([A-Z]+)([A-Z][a-z])/g, '$1 $2')
|
|
259905
|
+
.toLowerCase()
|
|
259906
|
+
.split(/[^a-z0-9]+/)
|
|
259907
|
+
.filter(Boolean);
|
|
259908
|
+
if (words.length === 0)
|
|
259909
|
+
return key;
|
|
259910
|
+
return words
|
|
259911
|
+
.map((word) => FIELD_ABBREVIATIONS.has(word)
|
|
259912
|
+
? word.toUpperCase()
|
|
259913
|
+
: word.charAt(0).toUpperCase() + word.slice(1))
|
|
259914
|
+
.join(' ');
|
|
259915
|
+
}
|
|
259916
|
+
/** Translated labels for the keys the backend is known to send. */
|
|
259917
|
+
function useFieldLabels() {
|
|
259918
|
+
const t = useT();
|
|
259919
|
+
const known = {
|
|
259920
|
+
llm_model: t('analyticsTranscriptTurnDetails.model'),
|
|
259921
|
+
llm_provider: t('analyticsTranscriptTurnDetails.provider'),
|
|
259922
|
+
llm_temperature: t('analyticsTranscriptTurnDetails.temperature'),
|
|
259923
|
+
model: t('analyticsTranscriptTurnDetails.model'),
|
|
259924
|
+
provider: t('analyticsTranscriptTurnDetails.provider'),
|
|
259925
|
+
temperature: t('analyticsTranscriptTurnDetails.temperature'),
|
|
259926
|
+
client: t('analyticsTranscriptTurnDetails.client'),
|
|
259927
|
+
session_id: t('analyticsTranscriptTurnDetails.fieldSession'),
|
|
259928
|
+
// The product's own names: artifacts are "Canvas" in the chat, proactivity
|
|
259929
|
+
// is the "Proactive Prompt", grading is the "Grader" tab, document filters
|
|
259930
|
+
// are "Datasets".
|
|
259931
|
+
enable_artifacts: t('analyticsTranscriptTurnDetails.fieldCanvas'),
|
|
259932
|
+
artifact: t('analyticsTranscriptTurnDetails.fieldCanvas'),
|
|
259933
|
+
artifacts: t('analyticsTranscriptTurnDetails.fieldCanvas'),
|
|
259934
|
+
is_proactive: t('analyticsTranscriptTurnDetails.fieldProactivePrompt'),
|
|
259935
|
+
grading_context: t('analyticsTranscriptTurnDetails.fieldGrader'),
|
|
259936
|
+
document_filter: t('analyticsTranscriptTurnDetails.fieldDatasets'),
|
|
259937
|
+
current_datetime: t('analyticsTranscriptTurnDetails.fieldDateTime'),
|
|
259938
|
+
caller_verified: t('analyticsTranscriptTurnDetails.fieldCallerVerified'),
|
|
259939
|
+
file_references: t('analyticsTranscriptTurnDetails.fieldFiles'),
|
|
259940
|
+
file_id: t('analyticsTranscriptTurnDetails.fieldFile'),
|
|
259941
|
+
system_prompt: t('analyticsTranscriptTurnDetails.fieldSystemPrompt'),
|
|
259942
|
+
flow: t('analyticsTranscriptTurnDetails.fieldFlow'),
|
|
259943
|
+
token: t('analyticsTranscriptTurnDetails.fieldToken'),
|
|
259944
|
+
tenant: t('analyticsTranscriptTurnDetails.fieldTenant'),
|
|
259945
|
+
pathway: t('analyticsTranscriptTurnDetails.fieldPathway'),
|
|
259946
|
+
username: t('analyticsTranscriptTurnDetails.fieldUsername'),
|
|
259947
|
+
name: t('analyticsTranscriptTurnDetails.fieldName'),
|
|
259948
|
+
};
|
|
259949
|
+
return (key) => { var _a; return (_a = known[key]) !== null && _a !== void 0 ? _a : humanizeFieldName(key); };
|
|
259950
|
+
}
|
|
259951
|
+
const fileName = (value) => {
|
|
259952
|
+
var _a, _b, _c, _d;
|
|
259953
|
+
const name = (_b = (_a = value.file_name) !== null && _a !== void 0 ? _a : value.filename) !== null && _b !== void 0 ? _b : value.name;
|
|
259954
|
+
if (typeof name === 'string' && name.trim())
|
|
259955
|
+
return name.trim();
|
|
259956
|
+
const key = (_d = (_c = value.file_key) !== null && _c !== void 0 ? _c : value.key) !== null && _d !== void 0 ? _d : value.path;
|
|
259957
|
+
if (typeof key === 'string' && key.trim())
|
|
259958
|
+
return key.trim().split('/').pop() || key.trim();
|
|
259959
|
+
return undefined;
|
|
259960
|
+
};
|
|
259961
|
+
/** Backend payloads name files in a few shapes; anything with a name plus a file-ish fact counts. */
|
|
259962
|
+
function isFileReference(value) {
|
|
259963
|
+
if (!isPlainObject(value) || !fileName(value))
|
|
259964
|
+
return false;
|
|
259965
|
+
return ['file_id', 'file_key', 'file_size', 'content_type', 'mime_type', 'url', 'size'].some((key) => key in value && value[key] !== null && value[key] !== undefined);
|
|
259966
|
+
}
|
|
259967
|
+
const attachmentUrl = (name, attachments) => { var _a; return (_a = attachments === null || attachments === void 0 ? void 0 : attachments.find((file) => (file === null || file === void 0 ? void 0 : file.name) === name && !!file.url)) === null || _a === void 0 ? void 0 : _a.url; };
|
|
259968
|
+
/** Normalise a file reference; the turn's attachments lend their presigned `url` to a same-named file. */
|
|
259969
|
+
function toFileReference(value, attachments) {
|
|
259970
|
+
var _a, _b, _c, _d, _e, _f;
|
|
259971
|
+
const name = (_a = fileName(value)) !== null && _a !== void 0 ? _a : '';
|
|
259972
|
+
const contentType = (_c = (_b = value.content_type) !== null && _b !== void 0 ? _b : value.mime_type) !== null && _c !== void 0 ? _c : value.type;
|
|
259973
|
+
const size = (_d = value.file_size) !== null && _d !== void 0 ? _d : value.size;
|
|
259974
|
+
const own = (_f = (_e = value.url) !== null && _e !== void 0 ? _e : value.download_url) !== null && _f !== void 0 ? _f : value.href;
|
|
259975
|
+
const numericSize = typeof size === 'number'
|
|
259976
|
+
? size
|
|
259977
|
+
: typeof size === 'string' && size.trim() && Number.isFinite(Number(size))
|
|
259978
|
+
? Number(size)
|
|
259979
|
+
: undefined;
|
|
259980
|
+
return {
|
|
259981
|
+
name,
|
|
259982
|
+
contentType: typeof contentType === 'string' ? contentType : undefined,
|
|
259983
|
+
size: numericSize,
|
|
259984
|
+
url: typeof own === 'string' && own ? own : attachmentUrl(name, attachments),
|
|
259985
|
+
};
|
|
259986
|
+
}
|
|
259987
|
+
const REDACTED_PATTERN = /^\[?(redacted|hidden|masked|removed)\]?$|^\*{3,}$/i;
|
|
259988
|
+
const UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
259989
|
+
/** Past this depth nested objects flatten to "key: value" text rather than nesting further. */
|
|
259990
|
+
const MAX_NESTING = 4;
|
|
259991
|
+
const formatPrimitive = (value) => {
|
|
259992
|
+
if (value === null || value === undefined)
|
|
259993
|
+
return '';
|
|
259994
|
+
if (typeof value === 'string')
|
|
259995
|
+
return value;
|
|
259996
|
+
if (typeof value === 'number')
|
|
259997
|
+
return Number.isInteger(value) ? String(value) : String(value);
|
|
259998
|
+
return String(value);
|
|
259999
|
+
};
|
|
260000
|
+
/** Deeply nested leftovers as readable "Key: value" text — never JSON. */
|
|
260001
|
+
function compactText(value, labelFor) {
|
|
260002
|
+
if (Array.isArray(value)) {
|
|
260003
|
+
return value
|
|
260004
|
+
.filter(isPresent)
|
|
260005
|
+
.map((item) => compactText(item, labelFor))
|
|
260006
|
+
.join('; ');
|
|
260007
|
+
}
|
|
260008
|
+
if (isPlainObject(value)) {
|
|
260009
|
+
return Object.entries(value)
|
|
260010
|
+
.filter(([, v]) => isPresent(v))
|
|
260011
|
+
.map(([k, v]) => `${labelFor(k)}: ${compactText(v, labelFor)}`)
|
|
260012
|
+
.join(', ');
|
|
260013
|
+
}
|
|
260014
|
+
return formatPrimitive(value);
|
|
260015
|
+
}
|
|
260016
|
+
function BooleanValue({ value }) {
|
|
260017
|
+
const t = useT();
|
|
260018
|
+
return (jsx("span", { className: cn('inline-flex items-center rounded-full px-2 py-0.5 text-xs font-medium', value ? 'bg-green-50 text-green-700' : 'bg-gray-100 text-gray-600'), children: value ? t('analyticsTranscriptTurnDetails.yes') : t('analyticsTranscriptTurnDetails.no') }));
|
|
260019
|
+
}
|
|
260020
|
+
function StringValue({ value }) {
|
|
260021
|
+
const t = useT();
|
|
260022
|
+
const text = value.trim();
|
|
260023
|
+
if (REDACTED_PATTERN.test(text)) {
|
|
260024
|
+
return (jsx("span", { className: "text-gray-400 italic", children: t('analyticsTranscriptTurnDetails.redacted') }));
|
|
260025
|
+
}
|
|
260026
|
+
if (UUID_PATTERN.test(text)) {
|
|
260027
|
+
return jsx("span", { className: "font-mono text-xs break-all text-gray-700", children: text });
|
|
260028
|
+
}
|
|
260029
|
+
return (jsx("span", { className: "block max-h-48 overflow-y-auto break-words whitespace-pre-line", children: text }));
|
|
260030
|
+
}
|
|
260031
|
+
const DetailCtx = React__default.createContext({ labelFor: humanizeFieldName });
|
|
260032
|
+
function DetailValue({ value, depth, labelFor, }) {
|
|
260033
|
+
var _a, _b;
|
|
260034
|
+
const ctx = React__default.useContext(DetailCtx);
|
|
260035
|
+
if (typeof value === 'boolean')
|
|
260036
|
+
return jsx(BooleanValue, { value: value });
|
|
260037
|
+
if (typeof value === 'number')
|
|
260038
|
+
return jsx("span", { className: "tabular-nums", children: formatPrimitive(value) });
|
|
260039
|
+
if (typeof value === 'string')
|
|
260040
|
+
return jsx(StringValue, { value: value });
|
|
260041
|
+
if (depth >= MAX_NESTING) {
|
|
260042
|
+
return jsx("span", { className: "break-words", children: compactText(value, labelFor) });
|
|
260043
|
+
}
|
|
260044
|
+
if (isFileReference(value)) {
|
|
260045
|
+
const files = [toFileReference(value, ctx.attachments)];
|
|
260046
|
+
return jsx(Fragment$1, { children: ((_a = ctx.renderFiles) !== null && _a !== void 0 ? _a : defaultRenderFiles)(files) });
|
|
260047
|
+
}
|
|
260048
|
+
if (Array.isArray(value)) {
|
|
260049
|
+
const items = value.filter(isPresent);
|
|
260050
|
+
if (items.length === 0)
|
|
260051
|
+
return null;
|
|
260052
|
+
if (items.every(isFileReference)) {
|
|
260053
|
+
const files = items.map((item) => toFileReference(item, ctx.attachments));
|
|
260054
|
+
return jsx(Fragment$1, { children: ((_b = ctx.renderFiles) !== null && _b !== void 0 ? _b : defaultRenderFiles)(files) });
|
|
260055
|
+
}
|
|
260056
|
+
const allPrimitive = items.every((item) => !isPlainObject(item) && !Array.isArray(item));
|
|
260057
|
+
if (allPrimitive) {
|
|
260058
|
+
return (jsx("span", { className: "flex flex-wrap gap-1", children: items.map((item, index) => (jsx(Badge, { variant: "secondary", className: "max-w-full font-normal break-all whitespace-normal", children: typeof item === 'boolean' ? jsx(BooleanValue, { value: item }) : formatPrimitive(item) }, index))) }));
|
|
260059
|
+
}
|
|
260060
|
+
return (jsx("ol", { className: "space-y-2", children: items.map((item, index) => (jsxs("li", { className: "flex gap-2", children: [jsxs("span", { className: "mt-1 text-xs font-medium text-gray-400 tabular-nums", children: [index + 1, "."] }), jsx("div", { className: "min-w-0 flex-1 rounded-md border border-gray-200 px-3 py-1", children: isPlainObject(item) ? (jsx(DetailRows, { entries: item, depth: depth + 1, labelFor: labelFor })) : (jsx(DetailValue, { value: item, depth: depth + 1, labelFor: labelFor })) })] }, index))) }));
|
|
260061
|
+
}
|
|
260062
|
+
if (isPlainObject(value)) {
|
|
260063
|
+
return (jsx("div", { className: "border-l-2 border-gray-200 pl-3", children: jsx(DetailRows, { entries: value, depth: depth + 1, labelFor: labelFor }) }));
|
|
260064
|
+
}
|
|
260065
|
+
return jsx("span", { children: formatPrimitive(value) });
|
|
260066
|
+
}
|
|
260067
|
+
/**
|
|
260068
|
+
* Label/value rows for a metadata-style object. Keys are humanized (never
|
|
260069
|
+
* shown raw), blanks are skipped, booleans read Yes/No, lists become chips or
|
|
260070
|
+
* numbered cards, files become the chat's file cards and nested objects
|
|
260071
|
+
* indent — the same read-only detail style as the audit-log sheet, so nothing
|
|
260072
|
+
* here ever looks like a JSON dump.
|
|
260073
|
+
*/
|
|
260074
|
+
function DetailRows({ entries, depth = 0, labelFor, }) {
|
|
260075
|
+
const rows = Object.entries(entries).filter(([, value]) => isPresent(value));
|
|
260076
|
+
if (rows.length === 0)
|
|
260077
|
+
return null;
|
|
260078
|
+
const top = depth === 0;
|
|
260079
|
+
return (jsx("dl", { className: cn(top ? 'divide-y divide-gray-100' : 'space-y-1'), children: rows.map(([key, value]) => (jsxs("div", { className: cn('grid gap-x-3', top
|
|
260080
|
+
? 'grid-cols-[minmax(0,7rem)_minmax(0,1fr)] py-2'
|
|
260081
|
+
: 'grid-cols-[minmax(0,6rem)_minmax(0,1fr)] py-0.5'), children: [jsx("dt", { className: cn('break-words text-gray-500', top ? 'text-xs font-medium tracking-wide uppercase' : 'text-xs font-medium'), children: labelFor(key) }), jsx("dd", { className: "min-w-0 text-sm text-gray-800", children: jsx(DetailValue, { value: value, depth: depth, labelFor: labelFor }) })] }, key))) }));
|
|
260082
|
+
}
|
|
260083
|
+
function SectionHeading({ icon, children }) {
|
|
260084
|
+
return (jsxs("h4", { className: "mb-2 flex items-center gap-1.5 text-xs font-semibold tracking-wide text-gray-700 uppercase", children: [icon, children] }));
|
|
260085
|
+
}
|
|
260086
|
+
const MODEL_KEYS = new Set(['llm_model', 'llm_provider']);
|
|
260087
|
+
function MetadataSection({ metadata, renderModel, }) {
|
|
260088
|
+
var _a, _b;
|
|
260089
|
+
const t = useT();
|
|
260090
|
+
const labelFor = useFieldLabels();
|
|
260091
|
+
const rest = Object.fromEntries(Object.entries(metadata).filter(([key]) => !MODEL_KEYS.has(key)));
|
|
260092
|
+
const model = ((_a = metadata.llm_model) !== null && _a !== void 0 ? _a : '').trim() || undefined;
|
|
260093
|
+
const provider = ((_b = metadata.llm_provider) !== null && _b !== void 0 ? _b : '').trim() || undefined;
|
|
260094
|
+
const hasModel = !!(model || provider);
|
|
260095
|
+
return (jsxs("section", { "data-testid": "transcript-turn-metadata", children: [jsx(SectionHeading, { icon: jsx(Info$3, { className: "h-3.5 w-3.5", "aria-hidden": "true" }), children: t('analyticsTranscriptTurnDetails.metadata') }), hasModel && (jsx("div", { "data-testid": "transcript-turn-model", className: "mb-2", children: (renderModel !== null && renderModel !== void 0 ? renderModel : defaultRenderModel)({ model, provider }) })), jsx(DetailRows, { entries: rest, labelFor: labelFor })] }));
|
|
260096
|
+
}
|
|
260097
|
+
function RequestContextSection({ requestContext }) {
|
|
260098
|
+
const t = useT();
|
|
260099
|
+
const labelFor = useFieldLabels();
|
|
260100
|
+
return (jsxs("section", { "data-testid": "transcript-turn-request-context", children: [jsx(SectionHeading, { icon: jsx(Info$3, { className: "h-3.5 w-3.5", "aria-hidden": "true" }), children: t('analyticsTranscriptTurnDetails.requestContext') }), jsx(DetailRows, { entries: requestContext, labelFor: labelFor })] }));
|
|
260101
|
+
}
|
|
260102
|
+
/**
|
|
260103
|
+
* The panel's defaults are the chat's own components, so admins see exactly
|
|
260104
|
+
* what the conversation shows: the "Retrieved Documents" dialog button, the
|
|
260105
|
+
* "Used N tools" record (with results), the nav-bar model badge and the
|
|
260106
|
+
* attachment file cards.
|
|
260107
|
+
*/
|
|
260108
|
+
const defaultRenderDocuments = (documents) => (jsx(RetrievedDocumentsButton, { documents: toRetrievedDocuments(documents) }));
|
|
260109
|
+
const defaultRenderToolCalls = (toolCalls) => (jsx(ToolCallIndicator, { toolCalls: toToolCallInfos(toolCalls), showResults: true }));
|
|
260110
|
+
const defaultRenderModel = ({ model, provider }) => (jsx(LlmModelBadge, { model: model, provider: provider }));
|
|
260111
|
+
const defaultRenderFiles = (files) => (jsx(TranscriptFileCards, { files: files }));
|
|
260112
|
+
/**
|
|
260113
|
+
* Collapsible "Sources / Tools / Metadata" panel for one AI turn of an admin
|
|
260114
|
+
* transcript (Perplexity/Claude-style citations). Driven by the extended
|
|
260115
|
+
* per-turn context the backend attaches on admin surfaces — the analytics
|
|
260116
|
+
* `messages/details/` endpoint and the admin `chat-history/` list — and
|
|
260117
|
+
* renders nothing at all when every field is null or empty, so it is safe to
|
|
260118
|
+
* drop under every AI bubble.
|
|
260119
|
+
*/
|
|
260120
|
+
function TranscriptTurnDetails({ turn, className, defaultOpen = false, renderDocuments, renderToolCalls, renderModel, renderFiles, }) {
|
|
260121
|
+
const t = useT();
|
|
260122
|
+
const labelFor = useFieldLabels();
|
|
260123
|
+
const [open, setOpen] = React__default.useState(defaultOpen);
|
|
260124
|
+
const attachments = React__default.useMemo(() => [...asArray(turn === null || turn === void 0 ? void 0 : turn.human_files), ...asArray(turn === null || turn === void 0 ? void 0 : turn.ai_files)], [turn === null || turn === void 0 ? void 0 : turn.human_files, turn === null || turn === void 0 ? void 0 : turn.ai_files]);
|
|
260125
|
+
const detailContext = React__default.useMemo(() => ({ labelFor, attachments, renderFiles }), [labelFor, attachments, renderFiles]);
|
|
260126
|
+
if (!hasTranscriptTurnDetails(turn))
|
|
260127
|
+
return null;
|
|
260128
|
+
const documents = asArray(turn === null || turn === void 0 ? void 0 : turn.documents);
|
|
260129
|
+
const toolCalls = asArray(turn === null || turn === void 0 ? void 0 : turn.tool_calls);
|
|
260130
|
+
const metadata = hasEntries(turn === null || turn === void 0 ? void 0 : turn.metadata) ? turn === null || turn === void 0 ? void 0 : turn.metadata : null;
|
|
260131
|
+
const requestContext = hasEntries(turn === null || turn === void 0 ? void 0 : turn.request_context) ? turn === null || turn === void 0 ? void 0 : turn.request_context : null;
|
|
260132
|
+
return (jsx(DetailCtx.Provider, { value: detailContext, children: jsxs(Collapsible, { open: open, onOpenChange: setOpen, className: cn('mt-2', className), "data-testid": "transcript-turn-details", children: [jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [jsx(CollapsibleTrigger, { asChild: true, children: jsxs(Button$1, { type: "button", variant: "outline", size: "sm", className: "flex items-center gap-2 border-gray-200 bg-white text-gray-700 hover:bg-gray-50", "aria-expanded": open, children: [jsx(ChevronDown, { className: cn('h-4 w-4 transition-transform', open && 'rotate-180'), "aria-hidden": "true" }), open
|
|
260133
|
+
? t('analyticsTranscriptTurnDetails.hideDetails')
|
|
260134
|
+
: t('analyticsTranscriptTurnDetails.showDetails')] }) }), documents.length > 0 && (jsx("div", { "data-testid": "transcript-turn-sources", className: "contents", children: (renderDocuments !== null && renderDocuments !== void 0 ? renderDocuments : defaultRenderDocuments)(documents) })), jsx(TranscriptRollupBadges, { documentsCount: 0, toolCallsCount: toolCalls.length })] }), jsxs(CollapsibleContent, { className: "mt-2 space-y-5 rounded-lg border border-gray-200 bg-white p-3", children: [toolCalls.length > 0 && (jsx("div", { "data-testid": "transcript-turn-tools", children: (renderToolCalls !== null && renderToolCalls !== void 0 ? renderToolCalls : defaultRenderToolCalls)(toolCalls) })), metadata && jsx(MetadataSection, { metadata: metadata, renderModel: renderModel }), requestContext && jsx(RequestContextSection, { requestContext: requestContext })] })] }) }));
|
|
260135
|
+
}
|
|
260136
|
+
/**
|
|
260137
|
+
* "Documents · N" / "Tools · N" chips for a conversation row, from the
|
|
260138
|
+
* conversation-list rollup fields (or a client-side `summarizeTranscriptTurns`).
|
|
260139
|
+
* A chip is hidden when its count is zero; nothing renders when both are.
|
|
260140
|
+
*/
|
|
260141
|
+
function TranscriptRollupBadges({ documentsCount, toolCallsCount, className, }) {
|
|
260142
|
+
const t = useT();
|
|
260143
|
+
const documents = toRollupCount(documentsCount);
|
|
260144
|
+
const tools = toRollupCount(toolCallsCount);
|
|
260145
|
+
if (documents === 0 && tools === 0)
|
|
260146
|
+
return null;
|
|
260147
|
+
return (jsxs("span", { className: cn('inline-flex flex-wrap items-center gap-1.5', className), "data-testid": "transcript-rollup-badges", children: [documents > 0 && (jsxs(Badge, { variant: "outline", className: "gap-1 border-transparent bg-blue-50 font-normal text-blue-700", "data-testid": "transcript-sources-badge", children: [jsx(FileText, { className: "h-3 w-3", "aria-hidden": "true" }), t('analyticsTranscriptTurnDetails.sourcesBadge', { count: documents })] })), tools > 0 && (jsxs(Badge, { variant: "outline", className: "gap-1 border-transparent bg-amber-50 font-normal text-amber-800", "data-testid": "transcript-tools-badge", children: [jsx(Wrench, { className: "h-3 w-3", "aria-hidden": "true" }), t('analyticsTranscriptTurnDetails.toolsBadge', { count: tools })] }))] }));
|
|
260148
|
+
}
|
|
260149
|
+
|
|
260150
|
+
/**
|
|
260151
|
+
* One place that decides how a user is shown.
|
|
260152
|
+
*
|
|
260153
|
+
* Backend payloads name their user in a dozen ways — `email` / `lti_email` /
|
|
260154
|
+
* `user_email`, `username` / `student` / `lti_username`, `name` /
|
|
260155
|
+
* `full_name` / `user_full_name`, or a nested `user` object — and most of
|
|
260156
|
+
* them can be empty, `null`, or a placeholder like "None". Every surface used
|
|
260157
|
+
* to pick through those on its own. `resolveUserIdentity()` takes whatever
|
|
260158
|
+
* the payload is and returns what to show, what to open a profile on, and
|
|
260159
|
+
* the avatar initial, so the rule lives here and can be tweaked once.
|
|
260160
|
+
*
|
|
260161
|
+
* Default rule: email → full name → username → the anonymous label.
|
|
260162
|
+
*/
|
|
260163
|
+
const DEFAULT_USER_IDENTITY_ORDER = ['email', 'name', 'username'];
|
|
260164
|
+
const DEFAULT_ANONYMOUS_LABEL = 'Anonymous';
|
|
260165
|
+
/** Values backends emit instead of "nothing". Compared case-insensitively. */
|
|
260166
|
+
const PLACEHOLDERS = new Set([
|
|
260167
|
+
'',
|
|
260168
|
+
'none',
|
|
260169
|
+
'null',
|
|
260170
|
+
'undefined',
|
|
260171
|
+
'n/a',
|
|
260172
|
+
'na',
|
|
260173
|
+
'-',
|
|
260174
|
+
'anonymous',
|
|
260175
|
+
'anonymoususer',
|
|
260176
|
+
]);
|
|
260177
|
+
/**
|
|
260178
|
+
* `local@domain.tld` with no whitespace, checked with a single pass rather than
|
|
260179
|
+
* a backtracking pattern (CodeQL flags `[^@]+@[^@]+\.[^@]+` as polynomial on
|
|
260180
|
+
* adversarial input).
|
|
260181
|
+
*/
|
|
260182
|
+
const isEmailLike = (value) => {
|
|
260183
|
+
const text = value.trim();
|
|
260184
|
+
if (!text || /\s/.test(text))
|
|
260185
|
+
return false;
|
|
260186
|
+
const at = text.indexOf('@');
|
|
260187
|
+
if (at <= 0 || at !== text.lastIndexOf('@') || at === text.length - 1)
|
|
260188
|
+
return false;
|
|
260189
|
+
const domain = text.slice(at + 1);
|
|
260190
|
+
const dot = domain.indexOf('.');
|
|
260191
|
+
// A dot somewhere inside the domain, with something after the last one.
|
|
260192
|
+
return dot > 0 && !domain.endsWith('.');
|
|
260193
|
+
};
|
|
260194
|
+
/** Trimmed string, or undefined for blanks, non-strings and placeholders. */
|
|
260195
|
+
const clean = (value) => {
|
|
260196
|
+
if (typeof value !== 'string')
|
|
260197
|
+
return undefined;
|
|
260198
|
+
const trimmed = value.trim();
|
|
260199
|
+
return PLACEHOLDERS.has(trimmed.toLowerCase()) ? undefined : trimmed;
|
|
260200
|
+
};
|
|
260201
|
+
const firstOf = (...candidates) => {
|
|
260202
|
+
for (const candidate of candidates) {
|
|
260203
|
+
const value = clean(candidate);
|
|
260204
|
+
if (value)
|
|
260205
|
+
return value;
|
|
260206
|
+
}
|
|
260207
|
+
return undefined;
|
|
260208
|
+
};
|
|
260209
|
+
const nested = (source) => source.user && typeof source.user === 'object' ? source.user : undefined;
|
|
260210
|
+
/**
|
|
260211
|
+
* Resolve how a user should be displayed from any payload that names one.
|
|
260212
|
+
*
|
|
260213
|
+
* - `email`: `lti_email`, `email`, `user_email`, the nested `user`'s email —
|
|
260214
|
+
* or a username field that turns out to hold an email address.
|
|
260215
|
+
* - `username`: `lti_username`, `username`, `student`, `user_username`, the
|
|
260216
|
+
* nested `user`'s username, or a bare string/number `user` value.
|
|
260217
|
+
* - `name`: `user_full_name`, `full_name`, `name`, `first_name last_name`, or
|
|
260218
|
+
* the nested `user`'s name.
|
|
260219
|
+
* - `profileUsername`: the first *platform* username (never an LTI claim).
|
|
260220
|
+
*
|
|
260221
|
+
* A string source is treated as an email when it looks like one, else as a
|
|
260222
|
+
* username. Placeholder strings ("None", "-", "anonymous"…) count as absent.
|
|
260223
|
+
*/
|
|
260224
|
+
function resolveUserIdentity(source, options = {}) {
|
|
260225
|
+
var _a;
|
|
260226
|
+
const anonymousLabel = options.anonymousLabel || DEFAULT_ANONYMOUS_LABEL;
|
|
260227
|
+
const order = ((_a = options.order) === null || _a === void 0 ? void 0 : _a.length) ? options.order : DEFAULT_USER_IDENTITY_ORDER;
|
|
260228
|
+
const record = source && typeof source === 'object' ? source : { user: source !== null && source !== void 0 ? source : null };
|
|
260229
|
+
const inner = nested(record);
|
|
260230
|
+
// A bare `user` value is an id or username; numeric ids are still shown.
|
|
260231
|
+
const bareUser = typeof record.user === 'number' && Number.isFinite(record.user)
|
|
260232
|
+
? String(record.user)
|
|
260233
|
+
: typeof record.user === 'string'
|
|
260234
|
+
? clean(record.user)
|
|
260235
|
+
: undefined;
|
|
260236
|
+
let email = firstOf(record.lti_email, record.email, record.user_email, inner === null || inner === void 0 ? void 0 : inner.lti_email, inner === null || inner === void 0 ? void 0 : inner.email, inner === null || inner === void 0 ? void 0 : inner.user_email);
|
|
260237
|
+
const platformUsername = firstOf(record.username, record.student, record.user_username, inner === null || inner === void 0 ? void 0 : inner.username, inner === null || inner === void 0 ? void 0 : inner.student, inner === null || inner === void 0 ? void 0 : inner.user_username, bareUser && !isEmailLike(bareUser) ? bareUser : undefined);
|
|
260238
|
+
let username = firstOf(record.lti_username, inner === null || inner === void 0 ? void 0 : inner.lti_username, platformUsername);
|
|
260239
|
+
const composed = [clean(record.first_name), clean(record.last_name)].filter(Boolean).join(' ');
|
|
260240
|
+
const name = firstOf(record.user_full_name, record.full_name, record.name, composed, inner === null || inner === void 0 ? void 0 : inner.user_full_name, inner === null || inner === void 0 ? void 0 : inner.full_name, inner === null || inner === void 0 ? void 0 : inner.name);
|
|
260241
|
+
// A bare string that looks like an email is an email, and so is a
|
|
260242
|
+
// "username" field that actually carries one.
|
|
260243
|
+
if (!email && bareUser && isEmailLike(bareUser))
|
|
260244
|
+
email = bareUser;
|
|
260245
|
+
if (!email && username && isEmailLike(username)) {
|
|
260246
|
+
email = username;
|
|
260247
|
+
username = undefined;
|
|
260248
|
+
}
|
|
260249
|
+
const facts = { email, username, name };
|
|
260250
|
+
const label = order.map((field) => facts[field]).find(Boolean);
|
|
260251
|
+
return {
|
|
260252
|
+
label: label !== null && label !== void 0 ? label : anonymousLabel,
|
|
260253
|
+
email,
|
|
260254
|
+
username,
|
|
260255
|
+
name,
|
|
260256
|
+
profileUsername: platformUsername,
|
|
260257
|
+
initial: (label !== null && label !== void 0 ? label : anonymousLabel).charAt(0).toUpperCase() || 'A',
|
|
260258
|
+
isAnonymous: !label,
|
|
260259
|
+
};
|
|
260260
|
+
}
|
|
260261
|
+
|
|
258128
260262
|
const AnalyticsSettingsContext = createContext({});
|
|
258129
260263
|
AnalyticsSettingsContext.Provider;
|
|
258130
260264
|
|
|
@@ -260865,64 +262999,6 @@ const AutoResizeTextarea = ({ allowEmptySubmit = false, value, onChange, onSubmi
|
|
|
260865
262999
|
disabled, placeholder: placeholder, style: combinedStyle, className: `flex max-h-32 min-h-[36px] w-full resize-none rounded-2xl border-0 border-gray-200 bg-transparent px-4 py-2 pt-2 pb-1 text-base ring-offset-white placeholder:text-gray-400 focus:outline-none focus-visible:outline-none disabled:cursor-not-allowed disabled:opacity-50 dark:border-gray-800 dark:bg-gray-950 dark:ring-offset-gray-950 dark:placeholder:text-gray-400 ${className}`, ...props }));
|
|
260866
263000
|
};
|
|
260867
263001
|
|
|
260868
|
-
function DocumentSidebar({ isModal = false, sessionId }) {
|
|
260869
|
-
const t = useT();
|
|
260870
|
-
const [isCollapsed, setIsCollapsed] = React.useState(false);
|
|
260871
|
-
const params = useParams();
|
|
260872
|
-
const username = useUsername();
|
|
260873
|
-
const isStreaming = useSelector(selectStreaming);
|
|
260874
|
-
const { data: vectorDocuments, refetch, status, } = useGetVectorDocumentsQuery({
|
|
260875
|
-
org: params.tenantKey,
|
|
260876
|
-
sessionId: sessionId,
|
|
260877
|
-
// @ts-ignore
|
|
260878
|
-
userId: username,
|
|
260879
|
-
}, {
|
|
260880
|
-
skip: !params.tenantKey || !sessionId || !username || !isLoggedIn(),
|
|
260881
|
-
});
|
|
260882
|
-
React.useEffect(() => {
|
|
260883
|
-
if (!isStreaming && isLoggedIn() && status !== 'uninitialized') {
|
|
260884
|
-
refetch();
|
|
260885
|
-
}
|
|
260886
|
-
}, [isStreaming, refetch]);
|
|
260887
|
-
const toggleCollapse = () => {
|
|
260888
|
-
setIsCollapsed(!isCollapsed);
|
|
260889
|
-
};
|
|
260890
|
-
return (jsx(Fragment$1, { children: (vectorDocuments === null || vectorDocuments === void 0 ? void 0 : vectorDocuments.length) && vectorDocuments.length > 0 ? (jsx("aside", { className: cn('transition-all duration-300 ease-in-out', isModal
|
|
260891
|
-
? 'max-h-full w-full overflow-auto'
|
|
260892
|
-
: 'hidden rounded-tl-lg rounded-bl-lg md:hidden lg:block', !isModal && (isCollapsed ? 'w-[40px]' : 'w-[380px]')), style: {
|
|
260893
|
-
backgroundColor: isCollapsed && !isModal ? 'white' : '#F3F6FB',
|
|
260894
|
-
maxHeight: 'calc(100vh - 80px)',
|
|
260895
|
-
}, children: jsxs("div", { className: "flex h-full flex-col", children: [!isModal && (jsxs("div", { className: cn('flex cursor-pointer items-center gap-2 border-b border-gray-200 p-4 transition-colors duration-200', isCollapsed && 'h-[80px] justify-center rounded-tl-[5px] rounded-bl-[5px] p-2', 'hover:bg-blue-100'), onClick: toggleCollapse, style: { backgroundColor: '#F3F6FB' }, children: [jsx(FileText, { className: "h-5 w-5 shrink-0 text-blue-600" }), !isCollapsed && (jsxs(Fragment$1, { children: [jsx("h2", { className: "text-base font-medium text-[#646464]", children: t('documentSidebar.retrievedDocuments') }), jsx(ChevronRight, { className: cn('ml-auto h-4 w-4 text-gray-400 transition-transform', isCollapsed ? 'rotate-180' : '') })] }))] })), (!isCollapsed || isModal) && (jsx(Fragment$1, { children: jsx("div", { className: "flex-1 overflow-auto", style: { backgroundColor: '#F3F6FB' }, children: jsx("div", { className: "mt-0 space-y-1 p-2", children: vectorDocuments.map((doc, index) => {
|
|
260896
|
-
var _a, _b;
|
|
260897
|
-
return (jsxs(React.Fragment, { children: [jsx("div", { className: "rounded-lg p-2 hover:bg-gray-50", children: jsxs("div", { className: "flex items-start gap-2", children: [jsx(Radio$1, { className: "mt-1 h-4 w-4 text-gray-400" }), jsxs("div", { className: "min-w-0 flex-1 space-y-1", children: [jsxs("div", { className: "flex items-center justify-between", children: [jsx(Link$2, { href: (_a = doc.source) !== null && _a !== void 0 ? _a : '', target: "_blank", className: "min-w-0", children: jsx("span", { className: "text-sm font-semibold break-words text-[#646464] hover:text-blue-600", children: doc.title }) }), jsx("div", { className: "flex items-center gap-2 self-center", children: jsx("span", { className: "text-xs text-gray-500", children: (_b = doc === null || doc === void 0 ? void 0 : doc.score) === null || _b === void 0 ? void 0 : _b.toFixed(2) }) })] }), jsx("p", { className: "line-clamp-6 pt-[10px] text-[14px] text-gray-600", children: doc.snippet })] })] }) }), index < vectorDocuments.length - 1 && (jsx("div", { className: "my-2 border-t border-gray-200" }))] }, index));
|
|
260898
|
-
}) }) }) }))] }) })) : null }));
|
|
260899
|
-
}
|
|
260900
|
-
|
|
260901
|
-
function RetrievedDocumentsButton({ sessionId }) {
|
|
260902
|
-
const t = useT();
|
|
260903
|
-
const [isOpen, setIsOpen] = useState(false);
|
|
260904
|
-
const params = useParams();
|
|
260905
|
-
const username = useUsername();
|
|
260906
|
-
const isStreaming = useSelector(selectStreaming);
|
|
260907
|
-
const { data: vectorDocuments, refetch, status, } = useGetVectorDocumentsQuery({
|
|
260908
|
-
org: params.tenantKey,
|
|
260909
|
-
sessionId: sessionId,
|
|
260910
|
-
// @ts-ignore
|
|
260911
|
-
userId: username,
|
|
260912
|
-
}, {
|
|
260913
|
-
skip: !params.tenantKey || !sessionId || !username || !isLoggedIn(),
|
|
260914
|
-
});
|
|
260915
|
-
useEffect(() => {
|
|
260916
|
-
if (!isStreaming && isLoggedIn() && status !== 'uninitialized') {
|
|
260917
|
-
refetch();
|
|
260918
|
-
}
|
|
260919
|
-
}, [isStreaming, refetch]);
|
|
260920
|
-
if (!(vectorDocuments === null || vectorDocuments === void 0 ? void 0 : vectorDocuments.length)) {
|
|
260921
|
-
return null;
|
|
260922
|
-
}
|
|
260923
|
-
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 }) })] }) })] }));
|
|
260924
|
-
}
|
|
260925
|
-
|
|
260926
263002
|
const PAGE_SIZE$5 = 10;
|
|
260927
263003
|
const MemoryMenu = ({ onClose, mentorId, tenantKey, username }) => {
|
|
260928
263004
|
const t = useT();
|
|
@@ -263583,7 +265659,7 @@ function useWebsiteCrawlerResource(resource) {
|
|
|
263583
265659
|
function WebsiteCrawlModal({ resource }) {
|
|
263584
265660
|
const t = useT();
|
|
263585
265661
|
const { form, handleCheckUrlIsValid, crawlerMatchPatterns, setCrawlerMatchPatterns } = useWebsiteCrawlerResource(resource);
|
|
263586
|
-
return (jsxs(Card, { className: "mx-auto w-full max-w-2xl", role: "dialog", "aria-labelledby": "crawler-title", "aria-describedby": "crawler-description", children: [jsxs(CardHeader, { children: [jsx(CardTitle, { id: "crawler-title", className: "text-md font-semibold text-gray-600", children: t('resourceModalWebsiteCrawlModal.title') }), jsx("p", { id: "crawler-description", className: "text-muted-foreground text-sm", children: t('resourceModalWebsiteCrawlModal.description') })] }), jsx(CardContent, { children: jsx("form", { className: "space-y-4", onSubmit: (e) => {
|
|
265662
|
+
return (jsxs(Card$1, { className: "mx-auto w-full max-w-2xl", role: "dialog", "aria-labelledby": "crawler-title", "aria-describedby": "crawler-description", children: [jsxs(CardHeader, { children: [jsx(CardTitle, { id: "crawler-title", className: "text-md font-semibold text-gray-600", children: t('resourceModalWebsiteCrawlModal.title') }), jsx("p", { id: "crawler-description", className: "text-muted-foreground text-sm", children: t('resourceModalWebsiteCrawlModal.description') })] }), jsx(CardContent, { children: jsx("form", { className: "space-y-4", onSubmit: (e) => {
|
|
263587
265663
|
e.preventDefault();
|
|
263588
265664
|
e.stopPropagation();
|
|
263589
265665
|
form.handleSubmit();
|
|
@@ -264943,8 +267019,21 @@ function BenchmarksTab({ tenantKey, username, }) {
|
|
|
264943
267019
|
}), 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 }))] }));
|
|
264944
267020
|
}
|
|
264945
267021
|
|
|
267022
|
+
const TAB_DESC_KEYS = {
|
|
267023
|
+
management: 'descManagement',
|
|
267024
|
+
organization: 'descOrganization',
|
|
267025
|
+
integrations: 'descIntegrations',
|
|
267026
|
+
billing: 'descBilling',
|
|
267027
|
+
monetization: 'descMonetization',
|
|
267028
|
+
datasets: 'descBenchmarks',
|
|
267029
|
+
memory: 'descMemory',
|
|
267030
|
+
advanced: 'descAdvanced',
|
|
267031
|
+
basic: 'descBasic',
|
|
267032
|
+
social: 'descSocial',
|
|
267033
|
+
security: 'descSecurity',
|
|
267034
|
+
};
|
|
264946
267035
|
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, onboardingBasePath = '', }) {
|
|
264947
|
-
var _a, _b, _c
|
|
267036
|
+
var _a, _b, _c;
|
|
264948
267037
|
const t = useT();
|
|
264949
267038
|
const currentTenant = tenants.find((ten) => ten.key === tenant);
|
|
264950
267039
|
const hasMonetizationPermission = checkRbacPermission(rbacPermissions, `/platforms/${tenant}/#can_sell_items`, enableRbac);
|
|
@@ -264957,17 +267046,46 @@ function Account({ tenant, tenants = [], username, onInviteClick, email, mainPla
|
|
|
264957
267046
|
*/
|
|
264958
267047
|
const canSeeBilling = !!(currentTenant === null || currentTenant === void 0 ? void 0 : currentTenant.show_paywall) && (isAdmin || hasMonetizationPermission);
|
|
264959
267048
|
const TABS = [
|
|
264960
|
-
{
|
|
264961
|
-
|
|
264962
|
-
|
|
267049
|
+
{
|
|
267050
|
+
id: 'organization',
|
|
267051
|
+
label: t('profileAccount.tabOrganization'),
|
|
267052
|
+
icon: Briefcase,
|
|
267053
|
+
group: 'workspace',
|
|
267054
|
+
},
|
|
267055
|
+
{
|
|
267056
|
+
id: 'management',
|
|
267057
|
+
label: t('profileAccount.tabManagement'),
|
|
267058
|
+
icon: Users,
|
|
267059
|
+
group: 'workspace',
|
|
267060
|
+
},
|
|
267061
|
+
{
|
|
267062
|
+
id: 'integrations',
|
|
267063
|
+
label: t('profileAccount.tabIntegrations'),
|
|
267064
|
+
icon: KeyRound,
|
|
267065
|
+
group: 'workspace',
|
|
267066
|
+
},
|
|
264963
267067
|
...(canMonetize
|
|
264964
|
-
? [
|
|
267068
|
+
? [
|
|
267069
|
+
{
|
|
267070
|
+
id: 'monetization',
|
|
267071
|
+
label: t('profileAccount.tabMonetization'),
|
|
267072
|
+
icon: Coins,
|
|
267073
|
+
group: 'finance',
|
|
267074
|
+
},
|
|
267075
|
+
]
|
|
264965
267076
|
: []),
|
|
264966
267077
|
...(showBenchmarks
|
|
264967
|
-
? [
|
|
267078
|
+
? [
|
|
267079
|
+
{
|
|
267080
|
+
id: 'datasets',
|
|
267081
|
+
label: t('profileAccount.tabBenchmarks'),
|
|
267082
|
+
icon: ListChecks,
|
|
267083
|
+
group: 'aiData',
|
|
267084
|
+
},
|
|
267085
|
+
]
|
|
264968
267086
|
: []),
|
|
264969
|
-
{ id: 'memory', label: t('profileAccount.tabMemory'), icon: Brain },
|
|
264970
|
-
{ id: 'advanced', label: t('profileAccount.tabAdvanced'), icon: Settings$1 },
|
|
267087
|
+
{ id: 'memory', label: t('profileAccount.tabMemory'), icon: Brain, group: 'aiData' },
|
|
267088
|
+
{ id: 'advanced', label: t('profileAccount.tabAdvanced'), icon: Settings$1, group: 'system' },
|
|
264971
267089
|
];
|
|
264972
267090
|
const [organizationLogo, setOrganizationLogo] = useState(`${LOGO_ENDPOINTS.light_logo(tenant)}?v=${Date.now()}`);
|
|
264973
267091
|
const hasUserTabPermission = checkRbacPermission(rbacPermissions, `/platforms/${tenant}/#can_manage_users`, enableRbac);
|
|
@@ -265012,56 +267130,61 @@ function Account({ tenant, tenants = [], username, onInviteClick, email, mainPla
|
|
|
265012
267130
|
firstInput.focus();
|
|
265013
267131
|
}
|
|
265014
267132
|
}, []);
|
|
265015
|
-
|
|
265016
|
-
|
|
265017
|
-
|
|
265018
|
-
|
|
265019
|
-
|
|
265020
|
-
|
|
265021
|
-
|
|
265022
|
-
|
|
265023
|
-
|
|
265024
|
-
|
|
265025
|
-
|
|
265026
|
-
|
|
265027
|
-
|
|
265028
|
-
|
|
265029
|
-
|
|
265030
|
-
|
|
265031
|
-
|
|
265032
|
-
|
|
265033
|
-
|
|
265034
|
-
|
|
265035
|
-
|
|
265036
|
-
|
|
265037
|
-
|
|
265038
|
-
|
|
265039
|
-
|
|
265040
|
-
|
|
265041
|
-
|
|
265042
|
-
|
|
265043
|
-
|
|
265044
|
-
|
|
265045
|
-
|
|
265046
|
-
|
|
265047
|
-
|
|
265048
|
-
|
|
265049
|
-
|
|
265050
|
-
|
|
265051
|
-
|
|
265052
|
-
|
|
265053
|
-
|
|
265054
|
-
|
|
265055
|
-
|
|
265056
|
-
|
|
265057
|
-
|
|
265058
|
-
|
|
265059
|
-
|
|
265060
|
-
|
|
265061
|
-
|
|
267133
|
+
/**
|
|
267134
|
+
* Billing and Monetization are mirrored into the host's URL through
|
|
267135
|
+
* `onTabChange`; leaving them for any other tab clears the param.
|
|
267136
|
+
*/
|
|
267137
|
+
const selectTab = (id) => {
|
|
267138
|
+
setActiveTab(id);
|
|
267139
|
+
if (id === 'billing') {
|
|
267140
|
+
onTabChange === null || onTabChange === void 0 ? void 0 : onTabChange('billing');
|
|
267141
|
+
return;
|
|
267142
|
+
}
|
|
267143
|
+
if ((activeTab === 'billing' || activeTab === 'monetization') &&
|
|
267144
|
+
id !== 'billing' &&
|
|
267145
|
+
id !== 'monetization') {
|
|
267146
|
+
onTabChange === null || onTabChange === void 0 ? void 0 : onTabChange('');
|
|
267147
|
+
}
|
|
267148
|
+
if (id === 'monetization') {
|
|
267149
|
+
onTabChange === null || onTabChange === void 0 ? void 0 : onTabChange('monetization');
|
|
267150
|
+
}
|
|
267151
|
+
};
|
|
267152
|
+
const billingTab = {
|
|
267153
|
+
id: 'billing',
|
|
267154
|
+
label: t('profileAccount.tabBilling'),
|
|
267155
|
+
icon: CreditCard,
|
|
267156
|
+
group: 'finance',
|
|
267157
|
+
};
|
|
267158
|
+
const navTabs = [...TABS, billingTab].filter((tab) => visibleTabIds.includes(tab.id));
|
|
267159
|
+
const GROUP_LABELS = {
|
|
267160
|
+
workspace: t('profileAccount.groupWorkspace'),
|
|
267161
|
+
finance: t('profileAccount.groupFinance'),
|
|
267162
|
+
aiData: t('profileAccount.groupAiData'),
|
|
267163
|
+
system: t('profileAccount.groupSystem'),
|
|
267164
|
+
};
|
|
267165
|
+
const navGroups = Object.keys(GROUP_LABELS).map((group) => ({
|
|
267166
|
+
id: group,
|
|
267167
|
+
label: GROUP_LABELS[group],
|
|
267168
|
+
items: navTabs.filter((tab) => tab.group === group),
|
|
267169
|
+
}));
|
|
267170
|
+
// Render the tab's `label` rather than the id so renames like
|
|
267171
|
+
// "datasets" → "Benchmarks" land in the header too. Billing lives outside
|
|
267172
|
+
// TABS (paywall-gated), so it needs its own translated label — the raw id
|
|
267173
|
+
// would render lowercase.
|
|
267174
|
+
const title = (_c = (_b = TABS.find((tab) => tab.id === activeTab)) === null || _b === void 0 ? void 0 : _b.label) !== null && _c !== void 0 ? _c : (activeTab === 'billing' ? t('profileAccount.tabBilling') : activeTab);
|
|
267175
|
+
const description = TAB_DESC_KEYS[activeTab]
|
|
267176
|
+
? t(`profileAccount.${TAB_DESC_KEYS[activeTab]}`)
|
|
267177
|
+
: undefined;
|
|
267178
|
+
const platformName = (currentTenant === null || currentTenant === void 0 ? void 0 : currentTenant.platform_name) || (currentTenant === null || currentTenant === void 0 ? void 0 : currentTenant.name) || tenant;
|
|
267179
|
+
const roleChip = (jsx(SettingsChip, { tone: "accent", icon: User, children: isAdmin ? t('profileAccount.roleAdmin') : t('profileAccount.roleUser') }));
|
|
267180
|
+
const sidebarHeader = (jsxs("div", { className: "flex flex-col gap-3.5", children: [jsxs("div", { className: "flex items-center gap-3", children: [organizationLogo ? (jsx("div", { className: "flex h-14 w-14 flex-shrink-0 items-center justify-center overflow-hidden rounded-xl border border-gray-200 bg-white p-1 dark:border-gray-700", children: jsx(Image$4, { src: organizationLogo, alt: t('profileAccount.organizationLogoAlt'), width: 56, height: 56, className: "h-full w-full object-contain", onError: () => {
|
|
267181
|
+
setOrganizationLogo('');
|
|
267182
|
+
} }) })) : (jsx("div", { className: "flex h-14 w-14 flex-shrink-0 items-center justify-center rounded-xl border border-blue-100 bg-blue-50 text-blue-600 dark:border-blue-900 dark:bg-blue-950 dark:text-blue-300", "aria-hidden": "true", children: jsx(BriefcaseBusiness, { className: "h-6 w-6" }) })), jsxs("div", { className: "min-w-0", children: [jsx("h2", { className: "truncate text-[15px] font-semibold text-gray-900 dark:text-gray-100", title: platformName, children: platformName }), platformName !== tenant && (jsx("p", { className: "truncate font-mono text-xs text-gray-500 dark:text-gray-400", children: tenant }))] })] }), jsxs("div", { className: "flex flex-wrap gap-1.5", children: [roleChip, showPlatformName && jsx(SettingsChip, { children: tenant.toUpperCase() })] })] }));
|
|
267183
|
+
const mobileHeader = (jsx("div", { className: "flex min-w-0 items-center justify-between gap-3", children: jsx("p", { className: "truncate text-[15px] font-semibold text-gray-900 dark:text-gray-100", children: platformName || t('profileAccount.profileTitle') }) }));
|
|
267184
|
+
return (jsx(SettingsShell, { sidebarHeader: sidebarHeader, sidebarNav: jsx(SettingsSidebarNav, { groups: navGroups, activeId: activeTab, onSelect: selectTab, variant: "buttons", ariaLabel: t('profileAccount.ariaSettingsNav') }), mobileHeader: mobileHeader, mobileNav: jsx(SettingsMobileNav, { groups: navGroups, activeId: activeTab, onSelect: selectTab, variant: "buttons", ariaLabel: t('profileAccount.ariaSettingsNavMobile') }), title: title, description: description, overlays: jsx(ToastProvider, {}), children: jsxs("div", { className: "space-y-6", children: [activeTab === 'management' && hasManagementPermissions && (jsx(Admin, { onboardingBasePath: onboardingBasePath, 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' && canSeeBilling && (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 }))] }) }));
|
|
265062
267185
|
}
|
|
265063
267186
|
|
|
265064
|
-
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, onboardingBasePath = '', }) {
|
|
267187
|
+
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, showLlmUsageTab = true, showBenchmarks = false, localLLMProps, enableSupportPhone, onboardingBasePath = '', }) {
|
|
265065
267188
|
const t = useT();
|
|
265066
267189
|
console.log('[UserProfileModal] localLLMProps received:', {
|
|
265067
267190
|
isAvailable: localLLMProps === null || localLLMProps === void 0 ? void 0 : localLLMProps.isAvailable,
|
|
@@ -265111,7 +267234,7 @@ function UserProfileModal({ isOpen, onClose, params, email, mainPlatformKey, sho
|
|
|
265111
267234
|
if (!isInviteUserDialogOpen) {
|
|
265112
267235
|
onClose();
|
|
265113
267236
|
}
|
|
265114
|
-
}, children: jsxs(DialogContent, { autoFocus: false, forceMount: true, 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('modalsUserProfileModal.dialogTitle') }), jsx(DialogDescription, { className: "sr-only", children: t('modalsUserProfileModal.dialogDescription') }), [
|
|
267237
|
+
}, children: jsxs(DialogContent, { autoFocus: false, forceMount: true, className: "max-w-7xl w-[85vw] p-0 gap-0 overflow-hidden bg-white sm:rounded-2xl profile-component-dialog", style: { height: '85vh', display: 'flex', flexDirection: 'column' }, children: [jsx(DialogTitle, { className: "sr-only", children: t('modalsUserProfileModal.dialogTitle') }), jsx(DialogDescription, { className: "sr-only", children: t('modalsUserProfileModal.dialogDescription') }), [
|
|
265115
267238
|
'basic',
|
|
265116
267239
|
'social',
|
|
265117
267240
|
'security',
|
|
@@ -265120,6 +267243,7 @@ function UserProfileModal({ isOpen, onClose, params, email, mainPlatformKey, sho
|
|
|
265120
267243
|
'resume',
|
|
265121
267244
|
'memory',
|
|
265122
267245
|
'chatHistory',
|
|
267246
|
+
'llmUsage',
|
|
265123
267247
|
'advanced',
|
|
265124
267248
|
].includes(targetTab) && (jsx(Profile, { currentSPA: currentSPA, tenant: params.tenantKey, tenants: tenants, username: getUserName$1(), customization: {
|
|
265125
267249
|
showMentorAIDisplayCheckbox: showMentorAIDisplayCheckbox,
|
|
@@ -265128,7 +267252,7 @@ function UserProfileModal({ isOpen, onClose, params, email, mainPlatformKey, sho
|
|
|
265128
267252
|
showPlatformName: showPlatformName,
|
|
265129
267253
|
useGravatarPicFallback: useGravatarPicFallback,
|
|
265130
267254
|
showGradebookTab: showGradebookTab,
|
|
265131
|
-
}, isAdmin: params.isAdmin, targetTab: targetTab, onClose: onClose, onAccountDeleted: onAccountDeleted, enableMemoryTab: enableMemoryTab, localLLMProps: localLLMProps })), [
|
|
267255
|
+
}, isAdmin: params.isAdmin, targetTab: targetTab, onClose: onClose, onAccountDeleted: onAccountDeleted, enableMemoryTab: enableMemoryTab, showLlmUsageTab: showLlmUsageTab, localLLMProps: localLLMProps })), [
|
|
265132
267256
|
'organization',
|
|
265133
267257
|
'management',
|
|
265134
267258
|
'integrations',
|
|
@@ -267722,7 +269846,7 @@ function ConversationStarters$1({ onTemplateSelect, guidedPrompts = [], disabled
|
|
|
267722
269846
|
}
|
|
267723
269847
|
return (jsxs("div", { className: cn('w-full max-w-6xl mx-auto px-4', className), children: [jsx("h2", { className: "text-xl font-semibold text-gray-900 mb-6", children: t('welcomeChatConversationStarters.conversationStarters') }), jsx("div", { className: "grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-5 gap-4", children: guidedPrompts.map((guidedPrompt, index) => {
|
|
267724
269848
|
var _a;
|
|
267725
|
-
return (jsx(Card, { className: cn('shadow-xs transition-all duration-200 bg-[#F5F8FF] border border-[#D0E0FF] h-full', disabled
|
|
269849
|
+
return (jsx(Card$1, { className: cn('shadow-xs transition-all duration-200 bg-[#F5F8FF] border border-[#D0E0FF] h-full', disabled
|
|
267726
269850
|
? 'opacity-50 cursor-not-allowed'
|
|
267727
269851
|
: 'cursor-pointer hover:shadow-sm focus:shadow-md focus:outline-none focus:ring-2 focus:ring-gray-300 focus:ring-offset-2'), onClick: () => !disabled && onTemplateSelect(guidedPrompt.prompt), onKeyDown: (e) => {
|
|
267728
269852
|
if (disabled)
|
|
@@ -276866,6 +278990,7 @@ const AGENT_HISTORY_TAB_LABELS = {
|
|
|
276866
278990
|
selectPrompt: 'Select a conversation to view details.',
|
|
276867
278991
|
aiAgent: 'AI Agent',
|
|
276868
278992
|
noConversations: 'No conversations found',
|
|
278993
|
+
documentsChip: (count) => `Documents · ${count}`,
|
|
276869
278994
|
},
|
|
276870
278995
|
summary: {
|
|
276871
278996
|
notAvailable: 'Summary not available',
|
|
@@ -276904,6 +279029,7 @@ function buildHistoryTabLabels(t) {
|
|
|
276904
279029
|
selectPrompt: t('historyTabLabels.conversation.selectPrompt'),
|
|
276905
279030
|
aiAgent: t('historyTabLabels.conversation.aiAgent'),
|
|
276906
279031
|
noConversations: t('historyTabLabels.conversation.noConversations'),
|
|
279032
|
+
documentsChip: (count) => t('historyTabLabels.conversation.documentsChip', { count }),
|
|
276907
279033
|
},
|
|
276908
279034
|
summary: {
|
|
276909
279035
|
notAvailable: t('historyTabLabels.summary.notAvailable'),
|
|
@@ -276923,6 +279049,8 @@ function resolveHistoryTabLabels(override, t) {
|
|
|
276923
279049
|
}
|
|
276924
279050
|
|
|
276925
279051
|
const ANONYMOUS_USERNAME$1 = 'anonymous';
|
|
279052
|
+
/** A turn's attachments in the shape the chat's file cards take. */
|
|
279053
|
+
const attachmentCards = (files) => (files !== null && files !== void 0 ? files : []).map((file) => ({ name: file.name, contentType: file.content_type, url: file.url }));
|
|
276926
279054
|
function textTruncate$1(str, length, ending) {
|
|
276927
279055
|
if (length == null) {
|
|
276928
279056
|
length = 50;
|
|
@@ -276935,7 +279063,7 @@ function textTruncate$1(str, length, ending) {
|
|
|
276935
279063
|
}
|
|
276936
279064
|
return str;
|
|
276937
279065
|
}
|
|
276938
|
-
function AgentHistoryTab({ renderMessageContent, PaginationComponent, onExport, isExporting = false, labels: labelsOverride, }) {
|
|
279066
|
+
function AgentHistoryTab({ renderMessageContent, PaginationComponent, onExport, isExporting = false, labels: labelsOverride, currentSPA, }) {
|
|
276939
279067
|
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p;
|
|
276940
279068
|
const t = useT();
|
|
276941
279069
|
const { tenantKey, mentorId, username } = useAgentSettings();
|
|
@@ -276985,6 +279113,10 @@ function AgentHistoryTab({ renderMessageContent, PaginationComponent, onExport,
|
|
|
276985
279113
|
// Use mentor summaries data for rating and tags
|
|
276986
279114
|
const averageRating = (mentorSummaries === null || mentorSummaries === void 0 ? void 0 : mentorSummaries.rating) || 0;
|
|
276987
279115
|
const topicTags = (mentorSummaries === null || mentorSummaries === void 0 ? void 0 : mentorSummaries.tags) || [];
|
|
279116
|
+
// Who the previewed conversation belongs to (email → full name → username → Anonymous).
|
|
279117
|
+
const identityOptions = { anonymousLabel: labels.conversation.anonymous };
|
|
279118
|
+
const selectedOwner = resolveUserIdentity(selectedConversation, identityOptions);
|
|
279119
|
+
const previewOwner = resolveUserIdentity(previewConversationContent, identityOptions);
|
|
276988
279120
|
const renderAiContent = (content) => {
|
|
276989
279121
|
if (renderMessageContent) {
|
|
276990
279122
|
return renderMessageContent(content);
|
|
@@ -277016,7 +279148,10 @@ function AgentHistoryTab({ renderMessageContent, PaginationComponent, onExport,
|
|
|
277016
279148
|
const conversation = _conversation;
|
|
277017
279149
|
const messages = conversation.messages;
|
|
277018
279150
|
const firstMessage = messages[0];
|
|
277019
|
-
|
|
279151
|
+
// Email → full name → username → Anonymous, decided in one place.
|
|
279152
|
+
const owner = resolveUserIdentity(conversation, {
|
|
279153
|
+
anonymousLabel: labels.conversation.anonymous,
|
|
279154
|
+
});
|
|
277020
279155
|
const timeAgo = formatDistanceToNow(new Date(conversation.inserted_at), {
|
|
277021
279156
|
addSuffix: true,
|
|
277022
279157
|
});
|
|
@@ -277026,22 +279161,25 @@ function AgentHistoryTab({ renderMessageContent, PaginationComponent, onExport,
|
|
|
277026
279161
|
const preview = (firstMessage === null || firstMessage === void 0 ? void 0 : firstMessage.ai)
|
|
277027
279162
|
? textTruncate$1(firstMessage.ai, 60)
|
|
277028
279163
|
: labels.conversation.noResponse;
|
|
279164
|
+
// The admin list carries the turns inline (no server-side
|
|
279165
|
+
// rollups), so badge rows from the turns themselves.
|
|
279166
|
+
// The chip counts what the dialog lists: every document the
|
|
279167
|
+
// turns carry, as the backend reports them.
|
|
279168
|
+
const documents = conversationDocuments(messages);
|
|
279169
|
+
const rollup = summarizeTranscriptTurns(messages);
|
|
277029
279170
|
return (jsxs("div", { className: cn('flex cursor-pointer items-center justify-between border-b p-4 last:border-b-0', (selectedConversation === null || selectedConversation === void 0 ? void 0 : selectedConversation.id) === conversation.id
|
|
277030
279171
|
? 'bg-gray-100'
|
|
277031
|
-
: 'hover:bg-gray-50'), onClick: () => handleConversationClick(conversation), children: [jsxs("div", { className: "w-full", children: [jsxs("div", { className: "mb-2 flex items-center justify-between", children: [jsx("span", { className: "text-sm text-gray-600", children: timeAgo }), jsx(
|
|
277032
|
-
|
|
277033
|
-
|
|
277034
|
-
|
|
277035
|
-
|
|
277036
|
-
|
|
277037
|
-
|
|
279172
|
+
: 'hover:bg-gray-50'), onClick: () => handleConversationClick(conversation), children: [jsxs("div", { className: "w-full", children: [jsxs("div", { className: "mb-2 flex items-center justify-between", children: [jsx("span", { className: "text-sm text-gray-600", children: timeAgo }), jsx(UserProfileLink, { tenantKey: tenantKey, username: owner.profileUsername, display: owner.label, currentSPA: currentSPA, className: "max-w-[100px] text-sm text-gray-900 sm:max-w-[200px]" })] }), jsx("div", { className: "font-medium text-gray-900", children: title }), jsx("p", { className: "line-clamp-1 text-sm text-gray-600", children: preview }), (rollup.documentsCount > 0 || rollup.toolCallsCount > 0) && (jsxs("div", { className: "mt-2 flex flex-wrap items-center gap-1.5", children: [rollup.documentsCount > 0 && (
|
|
279173
|
+
// The chat's documents dialog, as a chip: one
|
|
279174
|
+
// click shows what the conversation retrieved.
|
|
279175
|
+
jsx(RetrievedDocumentsButton, { documents: documents, label: labels.conversation.documentsChip(rollup.documentsCount), className: "h-6 gap-1 rounded-md border-transparent bg-blue-50 px-2 text-xs font-normal text-blue-700 hover:bg-blue-100 [&_svg]:h-3 [&_svg]:w-3" })), jsx(TranscriptRollupBadges, { documentsCount: 0, toolCallsCount: rollup.toolCallsCount })] }))] }), jsx("div", { className: "flex items-center gap-2 text-sm text-gray-600", children: jsx(ChevronRight, { className: "h-4 w-4" }) })] }, conversation.id));
|
|
279176
|
+
}) }), totalPages > 1 && PaginationComponent && (jsx("div", { className: "my-2", children: jsx(PaginationComponent, { currentPage: currentPage, totalPages: totalPages, onPageChange: handlePageChange, disabled: isChatHistoryFetching || isChatHistoryLoading, disableNumberedButtons: isMobile }) }))] }), jsx("div", { className: "scrollbar-hide hidden max-h-[500px] flex-col overflow-y-auto rounded-lg border bg-white p-6 shadow-sm md:flex", tabIndex: 0, role: "region", "aria-label": t('tabsHistoryTab.conversationPreviewLabel'), children: selectedConversation && previewConversationContent ? (jsxs(Fragment$1, { children: [jsxs("div", { className: "mb-4", children: [jsx("h3", { className: "mb-1 text-base font-semibold text-gray-700", children: ((_m = selectedConversation.messages[0]) === null || _m === void 0 ? void 0 : _m.human) || labels.conversation.title }), jsx("span", { className: "text-sm text-gray-500", children: format$1(new Date(selectedConversation.inserted_at), "MMM dd, yyyy 'at' h:mm a") }), jsx(RetrievedDocumentsButton, { sessionId: selectedConversation.id, documents: conversationDocuments(selectedConversation.messages).length > 0
|
|
279177
|
+
? conversationDocuments(selectedConversation.messages)
|
|
279178
|
+
: undefined, className: "mt-2" })] }), jsxs("div", { className: "space-y-6", children: [selectedConversation.messages.map((message, index) => (jsxs("div", { className: "space-y-4", children: [jsxs("div", { className: "flex items-start gap-3", children: [jsx("div", { className: "flex h-8 w-8 flex-shrink-0 items-center justify-center rounded-full bg-blue-100", children: jsx("span", { className: "text-sm font-medium text-blue-600", children: selectedOwner.initial }) }), jsxs("div", { className: "flex-1", children: [jsx("div", { className: "font-medium text-gray-700", children: jsx(UserProfileLink, { tenantKey: tenantKey, username: selectedOwner.profileUsername, display: selectedOwner.label, currentSPA: currentSPA }) }), jsx("p", { className: "mt-1 text-sm whitespace-pre-line text-gray-500", children: message.human }), jsx(TranscriptFileCards, { files: attachmentCards(message.human_files) })] })] }), jsxs("div", { className: "flex items-start gap-3 border-t border-gray-200 pt-4", children: [jsx("div", { className: "flex h-8 w-8 flex-shrink-0 items-center justify-center rounded-full bg-gray-100", children: jsx("span", { className: "text-sm font-medium text-gray-600", children: t('tabsHistoryTab.aiAvatarLabel') }) }), jsxs("div", { className: "flex-1", children: [jsx("div", { className: "font-medium text-gray-700", children: labels.conversation.aiAgent }), jsx("div", { className: "mt-1 text-sm text-gray-500", children: renderAiContent(message.ai) }), jsx(TranscriptFileCards, { files: attachmentCards(message.ai_files) }), jsx(TranscriptTurnDetails, { turn: message })] })] })] }, index))), (selectedConversation === null || selectedConversation === void 0 ? void 0 : selectedConversation.memory_tracked) && (jsxs("div", { className: "border-t border-gray-200 pt-4", children: [jsxs(Button$1, { variant: "outline", onClick: () => setShowConversationMemory(!showConversationMemory), className: "flex w-full items-center justify-center gap-2 border-gray-200 text-gray-700 hover:bg-gray-50", children: [jsx(Brain, { className: "h-4 w-4" }), showConversationMemory ? labels.memory.hide : labels.memory.show] }), showConversationMemory && (jsx("div", { className: "mt-4 space-y-6", children: isConversationMemoryLoading ? (jsx("div", { className: "flex items-center justify-center py-4", children: jsx(Spinner, {}) })) : ((_o = conversationMemory === null || conversationMemory === void 0 ? void 0 : conversationMemory.entries) === null || _o === void 0 ? void 0 : _o.length) ? (jsx(Fragment$1, { children: conversationMemory.entries.map((entry, index) => (jsxs("div", { children: [jsx("h4", { className: "mb-3 font-semibold text-gray-900", children: entry.key }), jsx("ul", { className: "space-y-2", children: jsx("li", { className: "flex items-start gap-2 text-sm text-gray-600", children: entry.value }) })] }, index))) })) : (jsx("div", { className: "text-sm text-gray-500", children: labels.memory.notAvailable })) }))] }))] })] })) : (jsx("div", { className: "flex h-full items-center justify-center text-gray-500", children: labels.conversation.selectPrompt })) })] }))] }) }), jsx(Dialog, { open: isConversationPreviewModalOpen, onOpenChange: setIsConversationPreviewModalOpen, children: jsxs(DialogContent, { className: "scrollbar-hide mx-auto max-h-[80vh] max-w-[90vw] overflow-x-hidden overflow-y-auto", children: [jsx(DialogHeader, { children: jsx(DialogTitle, { className: "text-lg font-semibold text-gray-900", children: previewConversationContent
|
|
277038
279179
|
? ((_p = previewConversationContent.messages[0]) === null || _p === void 0 ? void 0 : _p.human) || labels.conversation.title
|
|
277039
|
-
: labels.conversation.title }) }), jsx("div", { className: "mx-auto max-w-full overflow-x-hidden", children: previewConversationContent && (jsxs("div", { className: "scrollbar-hide space-y-4 overflow-y-auto", children: [jsx("div", { className: "text-sm text-gray-500", children: format$1(new Date(previewConversationContent.inserted_at), "MMM dd, yyyy 'at' h:mm a") }), previewConversationContent.
|
|
277040
|
-
|
|
277041
|
-
|
|
277042
|
-
previewConversationContent.email ||
|
|
277043
|
-
labels.conversation.anonymous }), jsx("p", { className: "mt-1 text-sm whitespace-pre-line text-gray-900", children: message.human })] })] }), jsxs("div", { className: "flex items-start gap-3 border-t border-gray-200 pt-4", children: [jsx("div", { className: "flex h-8 w-8 flex-shrink-0 items-center justify-center rounded-full bg-gray-100", children: jsx("span", { className: "text-sm font-medium text-gray-600", children: t('tabsHistoryTab.aiAvatarLabel') }) }), jsxs("div", { className: "overflow-x-hidden", children: [jsx("div", { className: "font-medium text-gray-900", children: labels.conversation.aiAgent }), jsx("div", { className: "mt-1 text-sm text-gray-900", children: renderAiContent(message.ai) })] })] })] }, index));
|
|
277044
|
-
})] })) })] }) })] }));
|
|
279180
|
+
: labels.conversation.title }) }), jsx("div", { className: "mx-auto max-w-full overflow-x-hidden", children: previewConversationContent && (jsxs("div", { className: "scrollbar-hide space-y-4 overflow-y-auto", children: [jsx("div", { className: "text-sm text-gray-500", children: format$1(new Date(previewConversationContent.inserted_at), "MMM dd, yyyy 'at' h:mm a") }), jsx(RetrievedDocumentsButton, { sessionId: previewConversationContent.id, documents: conversationDocuments(previewConversationContent.messages).length > 0
|
|
279181
|
+
? conversationDocuments(previewConversationContent.messages)
|
|
279182
|
+
: undefined }), previewConversationContent.messages.map((message, index) => (jsxs("div", { className: "space-y-4", children: [jsxs("div", { className: "flex items-start gap-3", children: [jsx("div", { className: "flex h-8 w-8 flex-shrink-0 items-center justify-center rounded-full bg-blue-100", children: jsx("span", { className: "text-sm font-medium text-blue-600", children: previewOwner.initial }) }), jsxs("div", { className: "overflow-x-hidden", children: [jsx("div", { className: "truncate font-medium text-gray-900", children: jsx(UserProfileLink, { tenantKey: tenantKey, username: previewOwner.profileUsername, display: previewOwner.label, currentSPA: currentSPA }) }), jsx("p", { className: "mt-1 text-sm whitespace-pre-line text-gray-900", children: message.human }), jsx(TranscriptFileCards, { files: attachmentCards(message.human_files) })] })] }), jsxs("div", { className: "flex items-start gap-3 border-t border-gray-200 pt-4", children: [jsx("div", { className: "flex h-8 w-8 flex-shrink-0 items-center justify-center rounded-full bg-gray-100", children: jsx("span", { className: "text-sm font-medium text-gray-600", children: t('tabsHistoryTab.aiAvatarLabel') }) }), jsxs("div", { className: "overflow-x-hidden", children: [jsx("div", { className: "font-medium text-gray-900", children: labels.conversation.aiAgent }), jsx("div", { className: "mt-1 text-sm text-gray-900", children: renderAiContent(message.ai) }), jsx(TranscriptFileCards, { files: attachmentCards(message.ai_files) }), jsx(TranscriptTurnDetails, { turn: message })] })] })] }, index)))] })) })] }) })] }));
|
|
277045
279183
|
}
|
|
277046
279184
|
|
|
277047
279185
|
const ANONYMOUS_USERNAME = 'anonymous';
|
|
@@ -280027,7 +282165,7 @@ function AgentEmbedTab({ labels: labelsProp, urls, CopyCodeBlock, visibilityOpti
|
|
|
280027
282165
|
? jsValidation.warnings.length > 0
|
|
280028
282166
|
? 'bg-blue-50 text-blue-700'
|
|
280029
282167
|
: 'bg-green-50 text-green-700'
|
|
280030
|
-
: 'bg-red-50 text-red-700'), children: jsValidation.isValid ? (jsValidation.warnings.length > 0 ? (jsxs(Fragment$1, { children: [jsx(TriangleAlert, { className: "h-3.5 w-3.5" }), t('tabsEmbedTab.warnings')] })) : (jsxs(Fragment$1, { children: [jsx(Check, { className: "h-3.5 w-3.5" }), t('tabsEmbedTab.valid')] }))) : (jsxs(Fragment$1, { children: [jsx(CircleAlert, { className: "h-3.5 w-3.5" }), t('tabsEmbedTab.invalid')] })) })) })] }), !jsValidation.isValid && (jsxs("div", { id: "js-errors", className: "rounded-lg border border-red-100 bg-red-50 p-3", role: "alert", children: [jsx("p", { className: "mb-1 text-sm font-medium text-red-800", children: t('tabsEmbedTab.jsValidationErrors') }), jsx("ul", { className: "list-inside list-disc space-y-0.5 text-sm text-red-700", children: jsValidation.errors.map((error, index) => (jsx("li", { children: error }, index))) })] })), jsValidation.isValid && jsValidation.warnings.length > 0 && (jsxs("div", { id: "js-warnings", className: "rounded-lg border border-blue-100 bg-blue-50 p-3", role: "status", children: [jsx("p", { className: "mb-1 text-sm font-medium text-blue-800", children: t('tabsEmbedTab.warningsHeading') }), jsx("ul", { className: "list-inside list-disc space-y-0.5 text-sm text-blue-700", children: jsValidation.warnings.map((warning, index) => (jsx("li", { children: warning }, index))) })] })), jsxs("div", { className: "flex items-center justify-between pt-2", children: [jsx("p", { className: "text-xs text-gray-500", children: t('tabsEmbedTab.jsChangesHint') }), jsxs("div", { className: "flex items-center gap-2", children: [hasJsChanges && (jsx(Button$1, { type: "button", variant: "outline", size: "sm", onClick: handleDiscardJs, disabled: isAdvancedDisabled, "aria-label": labels.actions.discard, children: labels.actions.discard })), jsx(Button$1, { type: "button", size: "sm", onClick: handleSaveJs, disabled: !canSaveJs, className: "bg-gradient-to-r from-[#2563EB] to-[#93C5FD] text-white hover:opacity-90", "aria-label": `${labels.actions.save} ${labels.advancedJs.title.toLowerCase()}`, children: isSavingAdvanced ? labels.actions.saving : labels.actions.save })] })] })] })) }))] }), jsx(form.Subscribe, { selector: (formState) => [formState.values.icon_selection], children: ([iconSelection]) => (jsxs(Fragment$1, { children: [jsx(form.Field, { name: "icon_selection", children: (field) => (jsxs("div", { className: "space-y-2", children: [jsx("h3", { className: "text-sm font-medium text-[#646464]", children: labels.fields.iconSelection }), jsxs(Select$1, { defaultValue: field.state.value, onValueChange: (value) => field.handleChange(value), disabled: form.state.isSubmitting, children: [jsx(SelectTrigger, { className: "text-[#646464]", "aria-label": t('tabsEmbedTab.selectEmbedModeAriaLabel'), children: jsx(SelectValue, { placeholder: t('tabsEmbedTab.selectModePlaceholder'), className: "text-[#646464]" }) }), jsxs(SelectContent, { children: [jsx(SelectItem, { value: "default", className: "text-[#646464]", children: t('tabsEmbedTab.iconSelectionDefault') }), jsx(SelectItem, { value: "custom", className: "text-[#646464]", children: t('tabsEmbedTab.iconSelectionCustom') })] })] })] })) }), iconSelection === 'custom' && (jsxs("div", { className: "flex w-full flex-col items-center gap-4", children: [jsx(Button$1, { type: "button", variant: "outline", className: "w-full bg-gray-50 text-gray-700 hover:bg-gray-100", onClick: () => setFocusEditCustomFloatingBubble(true), children: labels.iconEditor.title }), jsxs(Card, { children: [jsx(CardHeader, { className: "mb-0 pt-4 pb-0", children: jsx(CardTitle, { className: "text-sm font-medium text-[#646464]", children: t('tabsEmbedTab.livePreview') }) }), jsx(CardContent, { className: "mt-0", children: jsx(InteractiveBubbleConfigDisplay, { customFloatingBubbleConfig: customFloatingBubbleConfig, handleFloatingBubbleImageError: handleFloatingBubbleImageError }) })] })] }))] })) }), jsx("hr", { className: "my-4 border-t border-gray-200" }), jsx(form.Field, { name: "mode", children: (field) => (jsxs("div", { className: "space-y-2", children: [jsx("h3", { className: "text-sm font-medium text-[#646464]", children: labels.fields.modeSelection }), jsxs(Select$1, { defaultValue: field.state.value, onValueChange: (value) => field.handleChange(value), disabled: form.state.isSubmitting, children: [jsx(SelectTrigger, { className: "text-[#646464]", "aria-label": t('tabsEmbedTab.selectEmbedModeAriaLabel'), children: jsx(SelectValue, { placeholder: t('tabsEmbedTab.selectModePlaceholder'), className: "text-[#646464]" }) }), jsxs(SelectContent, { children: [jsx(SelectItem, { value: "default", className: "text-[#646464]", children: t('tabsEmbedTab.modeDefault') }), jsx(SelectItem, { value: "advanced", className: "text-[#646464]", children: t('tabsEmbedTab.modeAdvanced') })] })] })] })) }), jsx(form.Field, { name: "starter_prompts", children: (field) => (jsxs("div", { className: "space-y-2", children: [jsxs("div", { className: "flex items-center gap-2", children: [jsx("h3", { className: "text-sm font-medium text-[#646464]", children: labels.fields.starterPrompts.label }), jsx(TooltipProvider, { children: jsxs(Tooltip$1, { children: [jsx(TooltipTrigger, { "aria-label": t('tabsEmbedTab.moreInfoStarterPrompts'), children: jsx(Info$3, { className: "h-4 w-4 text-gray-400" }) }), jsx(TooltipContent, { className: "ibl-tooltip-content", children: jsx("p", { children: labels.fields.starterPrompts.tooltip }) })] }) })] }), jsxs(Select$1, { value: field.state.value, onValueChange: (value) => field.handleChange(value), disabled: form.state.isSubmitting, children: [jsx(SelectTrigger, { className: "text-[#646464]", "aria-label": t('tabsEmbedTab.selectStarterPromptsAriaLabel'), children: jsx(SelectValue, { placeholder: t('tabsEmbedTab.selectStarterPromptsPlaceholder'), className: "text-[#646464]" }) }), jsxs(SelectContent, { children: [jsx(SelectItem, { value: "guided_prompt", className: "text-[#646464]", children: t('tabsEmbedTab.guidedPrompts') }), jsx(SelectItem, { value: "suggested_prompt", className: "text-[#646464]", children: t('tabsEmbedTab.suggestedPrompts') })] })] })] })) }), jsx(WithFormPermissions, { name: "mentor_visibility",
|
|
282168
|
+
: 'bg-red-50 text-red-700'), children: jsValidation.isValid ? (jsValidation.warnings.length > 0 ? (jsxs(Fragment$1, { children: [jsx(TriangleAlert, { className: "h-3.5 w-3.5" }), t('tabsEmbedTab.warnings')] })) : (jsxs(Fragment$1, { children: [jsx(Check, { className: "h-3.5 w-3.5" }), t('tabsEmbedTab.valid')] }))) : (jsxs(Fragment$1, { children: [jsx(CircleAlert, { className: "h-3.5 w-3.5" }), t('tabsEmbedTab.invalid')] })) })) })] }), !jsValidation.isValid && (jsxs("div", { id: "js-errors", className: "rounded-lg border border-red-100 bg-red-50 p-3", role: "alert", children: [jsx("p", { className: "mb-1 text-sm font-medium text-red-800", children: t('tabsEmbedTab.jsValidationErrors') }), jsx("ul", { className: "list-inside list-disc space-y-0.5 text-sm text-red-700", children: jsValidation.errors.map((error, index) => (jsx("li", { children: error }, index))) })] })), jsValidation.isValid && jsValidation.warnings.length > 0 && (jsxs("div", { id: "js-warnings", className: "rounded-lg border border-blue-100 bg-blue-50 p-3", role: "status", children: [jsx("p", { className: "mb-1 text-sm font-medium text-blue-800", children: t('tabsEmbedTab.warningsHeading') }), jsx("ul", { className: "list-inside list-disc space-y-0.5 text-sm text-blue-700", children: jsValidation.warnings.map((warning, index) => (jsx("li", { children: warning }, index))) })] })), jsxs("div", { className: "flex items-center justify-between pt-2", children: [jsx("p", { className: "text-xs text-gray-500", children: t('tabsEmbedTab.jsChangesHint') }), jsxs("div", { className: "flex items-center gap-2", children: [hasJsChanges && (jsx(Button$1, { type: "button", variant: "outline", size: "sm", onClick: handleDiscardJs, disabled: isAdvancedDisabled, "aria-label": labels.actions.discard, children: labels.actions.discard })), jsx(Button$1, { type: "button", size: "sm", onClick: handleSaveJs, disabled: !canSaveJs, className: "bg-gradient-to-r from-[#2563EB] to-[#93C5FD] text-white hover:opacity-90", "aria-label": `${labels.actions.save} ${labels.advancedJs.title.toLowerCase()}`, children: isSavingAdvanced ? labels.actions.saving : labels.actions.save })] })] })] })) }))] }), jsx(form.Subscribe, { selector: (formState) => [formState.values.icon_selection], children: ([iconSelection]) => (jsxs(Fragment$1, { children: [jsx(form.Field, { name: "icon_selection", children: (field) => (jsxs("div", { className: "space-y-2", children: [jsx("h3", { className: "text-sm font-medium text-[#646464]", children: labels.fields.iconSelection }), jsxs(Select$1, { defaultValue: field.state.value, onValueChange: (value) => field.handleChange(value), disabled: form.state.isSubmitting, children: [jsx(SelectTrigger, { className: "text-[#646464]", "aria-label": t('tabsEmbedTab.selectEmbedModeAriaLabel'), children: jsx(SelectValue, { placeholder: t('tabsEmbedTab.selectModePlaceholder'), className: "text-[#646464]" }) }), jsxs(SelectContent, { children: [jsx(SelectItem, { value: "default", className: "text-[#646464]", children: t('tabsEmbedTab.iconSelectionDefault') }), jsx(SelectItem, { value: "custom", className: "text-[#646464]", children: t('tabsEmbedTab.iconSelectionCustom') })] })] })] })) }), iconSelection === 'custom' && (jsxs("div", { className: "flex w-full flex-col items-center gap-4", children: [jsx(Button$1, { type: "button", variant: "outline", className: "w-full bg-gray-50 text-gray-700 hover:bg-gray-100", onClick: () => setFocusEditCustomFloatingBubble(true), children: labels.iconEditor.title }), jsxs(Card$1, { children: [jsx(CardHeader, { className: "mb-0 pt-4 pb-0", children: jsx(CardTitle, { className: "text-sm font-medium text-[#646464]", children: t('tabsEmbedTab.livePreview') }) }), jsx(CardContent, { className: "mt-0", children: jsx(InteractiveBubbleConfigDisplay, { customFloatingBubbleConfig: customFloatingBubbleConfig, handleFloatingBubbleImageError: handleFloatingBubbleImageError }) })] })] }))] })) }), jsx("hr", { className: "my-4 border-t border-gray-200" }), jsx(form.Field, { name: "mode", children: (field) => (jsxs("div", { className: "space-y-2", children: [jsx("h3", { className: "text-sm font-medium text-[#646464]", children: labels.fields.modeSelection }), jsxs(Select$1, { defaultValue: field.state.value, onValueChange: (value) => field.handleChange(value), disabled: form.state.isSubmitting, children: [jsx(SelectTrigger, { className: "text-[#646464]", "aria-label": t('tabsEmbedTab.selectEmbedModeAriaLabel'), children: jsx(SelectValue, { placeholder: t('tabsEmbedTab.selectModePlaceholder'), className: "text-[#646464]" }) }), jsxs(SelectContent, { children: [jsx(SelectItem, { value: "default", className: "text-[#646464]", children: t('tabsEmbedTab.modeDefault') }), jsx(SelectItem, { value: "advanced", className: "text-[#646464]", children: t('tabsEmbedTab.modeAdvanced') })] })] })] })) }), jsx(form.Field, { name: "starter_prompts", children: (field) => (jsxs("div", { className: "space-y-2", children: [jsxs("div", { className: "flex items-center gap-2", children: [jsx("h3", { className: "text-sm font-medium text-[#646464]", children: labels.fields.starterPrompts.label }), jsx(TooltipProvider, { children: jsxs(Tooltip$1, { children: [jsx(TooltipTrigger, { "aria-label": t('tabsEmbedTab.moreInfoStarterPrompts'), children: jsx(Info$3, { className: "h-4 w-4 text-gray-400" }) }), jsx(TooltipContent, { className: "ibl-tooltip-content", children: jsx("p", { children: labels.fields.starterPrompts.tooltip }) })] }) })] }), jsxs(Select$1, { value: field.state.value, onValueChange: (value) => field.handleChange(value), disabled: form.state.isSubmitting, children: [jsx(SelectTrigger, { className: "text-[#646464]", "aria-label": t('tabsEmbedTab.selectStarterPromptsAriaLabel'), children: jsx(SelectValue, { placeholder: t('tabsEmbedTab.selectStarterPromptsPlaceholder'), className: "text-[#646464]" }) }), jsxs(SelectContent, { children: [jsx(SelectItem, { value: "guided_prompt", className: "text-[#646464]", children: t('tabsEmbedTab.guidedPrompts') }), jsx(SelectItem, { value: "suggested_prompt", className: "text-[#646464]", children: t('tabsEmbedTab.suggestedPrompts') })] })] })] })) }), jsx(WithFormPermissions, { name: "mentor_visibility",
|
|
280031
282169
|
// @ts-ignore
|
|
280032
282170
|
permissions: (_b = mentorSettings === null || mentorSettings === void 0 ? void 0 : mentorSettings.permissions) === null || _b === void 0 ? void 0 : _b.field, children: ({ disabled }) => (jsx(form.Field, { name: "mentor_visibility", children: (field) => (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.fields.whoCanView.label }), jsx(TooltipProvider, { children: jsxs(Tooltip$1, { children: [jsx(TooltipTrigger, { "aria-label": t('tabsEmbedTab.moreInfoVisibility'), children: jsx(Info$3, { className: "h-4 w-4 text-gray-400" }) }), jsx(TooltipContent, { className: "ibl-tooltip-content", children: jsx("p", { children: labels.fields.whoCanView.tooltip }) })] }) })] }), jsxs(Select$1, { value: typeof field.state.value === 'string' ? field.state.value : '', onValueChange: (value) => field.handleChange(value), disabled: form.state.isSubmitting || disabled, children: [jsx(SelectTrigger, { className: "text-[#646464]", "aria-label": t('tabsEmbedTab.selectWhoCanViewAriaLabel'), children: jsx(SelectValue, { placeholder: t('tabsEmbedTab.selectWhoCanViewPlaceholder'), className: "text-[#646464]" }) }), jsx(SelectContent, { children: visibilityOptions.map((visibility) => (jsx(SelectItem, { value: visibility.value, className: "text-[#646464]", children: visibility.label }, visibility.value))) })] })] })) })) }), jsx(WithFormPermissions, { name: "allow_anonymous",
|
|
280033
282171
|
// @ts-ignore
|
|
@@ -280058,7 +282196,7 @@ function AgentEmbedTab({ labels: labelsProp, urls, CopyCodeBlock, visibilityOpti
|
|
|
280058
282196
|
minHeight: '580px',
|
|
280059
282197
|
width: '100%',
|
|
280060
282198
|
minWidth: '280px',
|
|
280061
|
-
}, frameBorder: "0" })) }) })] }), focusEditCustomFloatingBubble && (jsx(Dialog, { open: focusEditCustomFloatingBubble, onOpenChange: (open) => setFocusEditCustomFloatingBubble(open), children: jsxs(DialogContent, { className: "max-h-[80vh] max-w-[600px] overflow-y-auto", children: [jsxs(DialogHeader, { className: "mb-1", children: [jsx(DialogTitle, { className: "ibl-dialog-title", children: labels.iconEditor.title }), jsx("p", { className: "text-xs text-gray-600", children: labels.iconEditor.description })] }), jsxs(Tabs, { defaultValue: "appearance", className: "w-full", children: [jsxs(TabsList, { className: "mb-4 grid h-10 w-full grid-cols-3", children: [jsxs(TabsTrigger, { value: "appearance", className: "flex items-center gap-2", children: [jsx(Palette, { className: "h-4 w-4" }), t('tabsEmbedTab.appearanceTab')] }), jsxs(TabsTrigger, { value: "position", className: "flex items-center gap-2", children: [jsx(Settings$1, { className: "h-4 w-4" }), t('tabsEmbedTab.positionTab')] }), jsxs(TabsTrigger, { value: "content", className: "flex items-center gap-2", children: [jsx(MessageCircle, { className: "h-4 w-4" }), t('tabsEmbedTab.contentTab')] })] }), jsx(TabsContent, { value: "appearance", className: "space-y-6", children: jsxs(Card, { children: [jsx(CardHeader, { className: "mb-0 px-4 py-3", children: jsx(CardTitle, { className: "text-sm font-medium text-gray-600", children: t('tabsEmbedTab.visualStyling') }) }), jsx(CardContent, { className: "space-y-6 pt-2", children: jsxs("div", { className: "grid grid-cols-1 gap-6 md:grid-cols-2", children: [jsxs("div", { className: "space-y-2", children: [jsx(Label$1, { htmlFor: "backgroundColor", className: "text-sm text-gray-600", children: t('tabsEmbedTab.backgroundColor') }), jsxs("div", { className: "mt-2 flex gap-2", children: [jsx(Input, { id: "backgroundColor", type: "color", value: customFloatingBubbleConfig.backgroundColor, onChange: (e) => updateConfig('backgroundColor', e.target.value), className: "h-10 w-16 rounded border p-1" }), jsx(Input, { value: customFloatingBubbleConfig.backgroundColor, onChange: (e) => updateConfig('backgroundColor', e.target.value), placeholder: "#3b82f6", className: "flex-1" })] })] }), jsxs("div", { className: "space-y-2", children: [jsx(Label$1, { htmlFor: "textColor", className: "text-sm text-gray-600", children: t('tabsEmbedTab.titleTextColor') }), jsxs("div", { className: "mt-2 flex gap-2", children: [jsx(Input, { id: "textColor", type: "color", value: customFloatingBubbleConfig.textColor, onChange: (e) => updateConfig('textColor', e.target.value), className: "h-10 w-16 rounded border p-1" }), jsx(Input, { value: customFloatingBubbleConfig.textColor, onChange: (e) => updateConfig('textColor', e.target.value), placeholder: "#ffffff", className: "flex-1" })] })] }), jsxs("div", { className: "space-y-2", children: [jsx(Label$1, { htmlFor: "subtitleTextColor", className: "text-sm text-gray-600", children: t('tabsEmbedTab.subtitleTextColor') }), jsxs("div", { className: "mt-2 flex gap-2", children: [jsx(Input, { id: "subtitleTextColor", type: "color", value: customFloatingBubbleConfig.subtitleTextColor, onChange: (e) => updateConfig('subtitleTextColor', e.target.value), className: "h-10 w-16 rounded border p-1" }), jsx(Input, { value: customFloatingBubbleConfig.subtitleTextColor, onChange: (e) => updateConfig('subtitleTextColor', e.target.value), placeholder: "#e5e7eb", className: "flex-1" })] })] }), jsxs("div", { className: "space-y-2", children: [jsx(Label$1, { htmlFor: "borderRadius", className: "text-sm text-gray-600", children: t('tabsEmbedTab.borderRadius') }), jsx("div", { className: "mt-2 flex gap-2", children: jsx(Input, { value: customFloatingBubbleConfig.borderRadius, onChange: (e) => updateConfig('borderRadius', e.target.value), placeholder: "16", type: "range", min: 0, max: 100, step: 1, className: "flex-1", id: "borderRadius" }) })] }), jsxs("div", { className: "space-y-2", children: [jsx(Label$1, { htmlFor: "imageSize", className: "text-sm text-gray-600", children: t('tabsEmbedTab.imageSize') }), jsx("div", { className: "mt-2 flex gap-2", children: jsx(Input, { value: customFloatingBubbleConfig.imageSize, onChange: (e) => updateConfig('imageSize', e.target.value), placeholder: "16", type: "range", min: 0, max: 100, step: 1, className: "flex-1" }) })] }), jsxs("div", { className: "space-y-2", children: [jsx(Label$1, { htmlFor: "fontSize", className: "text-sm text-gray-600", children: t('tabsEmbedTab.titleFontSize') }), jsxs("div", { className: "mt-2 flex gap-2", children: [jsx(Input, { id: "fontSize", value: customFloatingBubbleConfig.fontSize, onChange: (e) => updateConfig('fontSize', e.target.value), placeholder: "16", type: "range", min: 10, max: 24, step: 1, className: "flex-1" }), jsxs("span", { className: "flex min-w-[30px] items-center text-xs text-gray-500", children: [customFloatingBubbleConfig.fontSize, "px"] })] })] }), jsxs("div", { className: "space-y-2", children: [jsx(Label$1, { htmlFor: "subtitleFontSize", className: "text-sm text-gray-600", children: t('tabsEmbedTab.subtitleFontSize') }), jsxs("div", { className: "mt-2 flex gap-2", children: [jsx(Input, { id: "subtitleFontSize", value: customFloatingBubbleConfig.subtitleFontSize, onChange: (e) => updateConfig('subtitleFontSize', e.target.value), placeholder: "12", type: "range", min: 8, max: 20, step: 1, className: "flex-1" }), jsxs("span", { className: "flex min-w-[30px] items-center text-xs text-gray-500", children: [customFloatingBubbleConfig.subtitleFontSize, "px"] })] })] }), jsxs("div", { className: "space-y-2", children: [jsx(Label$1, { htmlFor: "shadow", className: "text-sm text-gray-600", children: t('tabsEmbedTab.useShadow') }), jsx("div", { className: "mt-2", children: jsxs(Select$1, { value: customFloatingBubbleConfig.shadow ? '1' : '0', onValueChange: (value) => updateConfig('shadow', value === '1'), children: [jsx(SelectTrigger, { children: jsx(SelectValue, {}) }), jsxs(SelectContent, { children: [jsx(SelectItem, { value: '1', children: t('tabsEmbedTab.yes') }), jsx(SelectItem, { value: '0', children: t('tabsEmbedTab.no') })] })] }) })] }), jsxs("div", { className: "space-y-2", children: [jsx(Label$1, { htmlFor: "padding", className: "text-sm text-gray-600", children: t('tabsEmbedTab.padding') }), jsx("div", { className: "mt-2 flex gap-2", children: jsx(Input, { value: customFloatingBubbleConfig.padding, onChange: (e) => updateConfig('padding', e.target.value), placeholder: "1", type: "range", min: 0, max: 50, step: 1, className: "flex-1" }) })] }), jsxs("div", { className: "space-y-2", children: [jsx(Label$1, { htmlFor: "strokeWidth", className: "text-sm text-gray-600", children: t('tabsEmbedTab.strokeThickness') }), jsx("div", { className: "mt-2 flex gap-2", children: jsx(Input, { value: customFloatingBubbleConfig.strokeWidth, onChange: (e) => updateConfig('strokeWidth', e.target.value), placeholder: "1", type: "range", min: 0, max: 10, step: 1, className: "flex-1" }) })] }), jsxs("div", { className: "space-y-2", children: [jsx(Label$1, { htmlFor: "strokeColor", className: "text-sm text-gray-600", children: t('tabsEmbedTab.strokeColor') }), jsxs("div", { className: "mt-2 flex gap-2", children: [jsx(Input, { id: "strokeColor", type: "color", value: customFloatingBubbleConfig.strokeColor, onChange: (e) => updateConfig('strokeColor', e.target.value), className: "h-10 w-16 rounded border p-1" }), jsx(Input, { value: customFloatingBubbleConfig.strokeColor, onChange: (e) => updateConfig('strokeColor', e.target.value), placeholder: "#3b82f6", className: "flex-1" })] })] })] }) })] }) }), jsx(TabsContent, { value: "position", className: "space-y-6", children: jsxs(Card, { children: [jsx(CardHeader, { className: "mb-0 px-4 py-3", children: jsx(CardTitle, { className: "text-sm font-medium text-gray-600", children: t('tabsEmbedTab.positionLayout') }) }), jsx(CardContent, { className: "space-y-6 pt-0", children: jsxs("div", { className: "space-y-2", children: [jsx(Label$1, { htmlFor: "position", className: "text-sm text-gray-600", children: t('tabsEmbedTab.screenPosition') }), jsx("div", { className: "mt-2", children: jsxs(Select$1, { value: customFloatingBubbleConfig.position, onValueChange: (value) => updateConfig('position', value), children: [jsx(SelectTrigger, { children: jsx(SelectValue, {}) }), jsxs(SelectContent, { children: [jsx(SelectItem, { value: "bottom-right", children: t('tabsEmbedTab.bottomRight') }), jsx(SelectItem, { value: "bottom-left", children: t('tabsEmbedTab.bottomLeft') }), jsx(SelectItem, { value: "top-right", children: t('tabsEmbedTab.topRight') }), jsx(SelectItem, { value: "top-left", children: t('tabsEmbedTab.topLeft') })] })] }) })] }) })] }) }), jsx(TabsContent, { value: "content", className: "space-y-6", children: jsxs(Card, { children: [jsx(CardHeader, { className: "mb-0 px-4 py-3", children: jsx(CardTitle, { className: "text-sm font-medium text-gray-600", children: t('tabsEmbedTab.textContent') }) }), jsxs(CardContent, { className: "space-y-4 pt-0", children: [jsxs("div", { className: "space-y-2", children: [jsx(Label$1, { htmlFor: "title", className: "text-sm text-gray-600", children: t('tabsEmbedTab.titleLabel') }), jsx(Input, { id: "title", value: customFloatingBubbleConfig.title, onChange: (e) => updateConfig('title', e.target.value), placeholder: "AI-powered assistant", className: "mt-2" })] }), jsxs("div", { className: "space-y-2", children: [jsx(Label$1, { htmlFor: "subtitle", className: "text-sm text-gray-600", children: t('tabsEmbedTab.subtitleText') }), jsx(Input, { id: "subtitle", value: customFloatingBubbleConfig.subtitle, onChange: (e) => updateConfig('subtitle', e.target.value), placeholder: "Created with AI", className: "mt-2" })] }), jsxs("div", { className: "space-y-2", children: [jsx(Label$1, { htmlFor: "iconImage", className: "text-sm text-gray-600", children: t('tabsEmbedTab.iconImage') }), jsxs("div", { className: "mt-2 space-y-1", children: [jsx(Input, { id: "iconImage", type: "file", accept: "image/*", onChange: (e) => {
|
|
282199
|
+
}, frameBorder: "0" })) }) })] }), focusEditCustomFloatingBubble && (jsx(Dialog, { open: focusEditCustomFloatingBubble, onOpenChange: (open) => setFocusEditCustomFloatingBubble(open), children: jsxs(DialogContent, { className: "max-h-[80vh] max-w-[600px] overflow-y-auto", children: [jsxs(DialogHeader, { className: "mb-1", children: [jsx(DialogTitle, { className: "ibl-dialog-title", children: labels.iconEditor.title }), jsx("p", { className: "text-xs text-gray-600", children: labels.iconEditor.description })] }), jsxs(Tabs, { defaultValue: "appearance", className: "w-full", children: [jsxs(TabsList, { className: "mb-4 grid h-10 w-full grid-cols-3", children: [jsxs(TabsTrigger, { value: "appearance", className: "flex items-center gap-2", children: [jsx(Palette, { className: "h-4 w-4" }), t('tabsEmbedTab.appearanceTab')] }), jsxs(TabsTrigger, { value: "position", className: "flex items-center gap-2", children: [jsx(Settings$1, { className: "h-4 w-4" }), t('tabsEmbedTab.positionTab')] }), jsxs(TabsTrigger, { value: "content", className: "flex items-center gap-2", children: [jsx(MessageCircle, { className: "h-4 w-4" }), t('tabsEmbedTab.contentTab')] })] }), jsx(TabsContent, { value: "appearance", className: "space-y-6", children: jsxs(Card$1, { children: [jsx(CardHeader, { className: "mb-0 px-4 py-3", children: jsx(CardTitle, { className: "text-sm font-medium text-gray-600", children: t('tabsEmbedTab.visualStyling') }) }), jsx(CardContent, { className: "space-y-6 pt-2", children: jsxs("div", { className: "grid grid-cols-1 gap-6 md:grid-cols-2", children: [jsxs("div", { className: "space-y-2", children: [jsx(Label$1, { htmlFor: "backgroundColor", className: "text-sm text-gray-600", children: t('tabsEmbedTab.backgroundColor') }), jsxs("div", { className: "mt-2 flex gap-2", children: [jsx(Input, { id: "backgroundColor", type: "color", value: customFloatingBubbleConfig.backgroundColor, onChange: (e) => updateConfig('backgroundColor', e.target.value), className: "h-10 w-16 rounded border p-1" }), jsx(Input, { value: customFloatingBubbleConfig.backgroundColor, onChange: (e) => updateConfig('backgroundColor', e.target.value), placeholder: "#3b82f6", className: "flex-1" })] })] }), jsxs("div", { className: "space-y-2", children: [jsx(Label$1, { htmlFor: "textColor", className: "text-sm text-gray-600", children: t('tabsEmbedTab.titleTextColor') }), jsxs("div", { className: "mt-2 flex gap-2", children: [jsx(Input, { id: "textColor", type: "color", value: customFloatingBubbleConfig.textColor, onChange: (e) => updateConfig('textColor', e.target.value), className: "h-10 w-16 rounded border p-1" }), jsx(Input, { value: customFloatingBubbleConfig.textColor, onChange: (e) => updateConfig('textColor', e.target.value), placeholder: "#ffffff", className: "flex-1" })] })] }), jsxs("div", { className: "space-y-2", children: [jsx(Label$1, { htmlFor: "subtitleTextColor", className: "text-sm text-gray-600", children: t('tabsEmbedTab.subtitleTextColor') }), jsxs("div", { className: "mt-2 flex gap-2", children: [jsx(Input, { id: "subtitleTextColor", type: "color", value: customFloatingBubbleConfig.subtitleTextColor, onChange: (e) => updateConfig('subtitleTextColor', e.target.value), className: "h-10 w-16 rounded border p-1" }), jsx(Input, { value: customFloatingBubbleConfig.subtitleTextColor, onChange: (e) => updateConfig('subtitleTextColor', e.target.value), placeholder: "#e5e7eb", className: "flex-1" })] })] }), jsxs("div", { className: "space-y-2", children: [jsx(Label$1, { htmlFor: "borderRadius", className: "text-sm text-gray-600", children: t('tabsEmbedTab.borderRadius') }), jsx("div", { className: "mt-2 flex gap-2", children: jsx(Input, { value: customFloatingBubbleConfig.borderRadius, onChange: (e) => updateConfig('borderRadius', e.target.value), placeholder: "16", type: "range", min: 0, max: 100, step: 1, className: "flex-1", id: "borderRadius" }) })] }), jsxs("div", { className: "space-y-2", children: [jsx(Label$1, { htmlFor: "imageSize", className: "text-sm text-gray-600", children: t('tabsEmbedTab.imageSize') }), jsx("div", { className: "mt-2 flex gap-2", children: jsx(Input, { value: customFloatingBubbleConfig.imageSize, onChange: (e) => updateConfig('imageSize', e.target.value), placeholder: "16", type: "range", min: 0, max: 100, step: 1, className: "flex-1" }) })] }), jsxs("div", { className: "space-y-2", children: [jsx(Label$1, { htmlFor: "fontSize", className: "text-sm text-gray-600", children: t('tabsEmbedTab.titleFontSize') }), jsxs("div", { className: "mt-2 flex gap-2", children: [jsx(Input, { id: "fontSize", value: customFloatingBubbleConfig.fontSize, onChange: (e) => updateConfig('fontSize', e.target.value), placeholder: "16", type: "range", min: 10, max: 24, step: 1, className: "flex-1" }), jsxs("span", { className: "flex min-w-[30px] items-center text-xs text-gray-500", children: [customFloatingBubbleConfig.fontSize, "px"] })] })] }), jsxs("div", { className: "space-y-2", children: [jsx(Label$1, { htmlFor: "subtitleFontSize", className: "text-sm text-gray-600", children: t('tabsEmbedTab.subtitleFontSize') }), jsxs("div", { className: "mt-2 flex gap-2", children: [jsx(Input, { id: "subtitleFontSize", value: customFloatingBubbleConfig.subtitleFontSize, onChange: (e) => updateConfig('subtitleFontSize', e.target.value), placeholder: "12", type: "range", min: 8, max: 20, step: 1, className: "flex-1" }), jsxs("span", { className: "flex min-w-[30px] items-center text-xs text-gray-500", children: [customFloatingBubbleConfig.subtitleFontSize, "px"] })] })] }), jsxs("div", { className: "space-y-2", children: [jsx(Label$1, { htmlFor: "shadow", className: "text-sm text-gray-600", children: t('tabsEmbedTab.useShadow') }), jsx("div", { className: "mt-2", children: jsxs(Select$1, { value: customFloatingBubbleConfig.shadow ? '1' : '0', onValueChange: (value) => updateConfig('shadow', value === '1'), children: [jsx(SelectTrigger, { children: jsx(SelectValue, {}) }), jsxs(SelectContent, { children: [jsx(SelectItem, { value: '1', children: t('tabsEmbedTab.yes') }), jsx(SelectItem, { value: '0', children: t('tabsEmbedTab.no') })] })] }) })] }), jsxs("div", { className: "space-y-2", children: [jsx(Label$1, { htmlFor: "padding", className: "text-sm text-gray-600", children: t('tabsEmbedTab.padding') }), jsx("div", { className: "mt-2 flex gap-2", children: jsx(Input, { value: customFloatingBubbleConfig.padding, onChange: (e) => updateConfig('padding', e.target.value), placeholder: "1", type: "range", min: 0, max: 50, step: 1, className: "flex-1" }) })] }), jsxs("div", { className: "space-y-2", children: [jsx(Label$1, { htmlFor: "strokeWidth", className: "text-sm text-gray-600", children: t('tabsEmbedTab.strokeThickness') }), jsx("div", { className: "mt-2 flex gap-2", children: jsx(Input, { value: customFloatingBubbleConfig.strokeWidth, onChange: (e) => updateConfig('strokeWidth', e.target.value), placeholder: "1", type: "range", min: 0, max: 10, step: 1, className: "flex-1" }) })] }), jsxs("div", { className: "space-y-2", children: [jsx(Label$1, { htmlFor: "strokeColor", className: "text-sm text-gray-600", children: t('tabsEmbedTab.strokeColor') }), jsxs("div", { className: "mt-2 flex gap-2", children: [jsx(Input, { id: "strokeColor", type: "color", value: customFloatingBubbleConfig.strokeColor, onChange: (e) => updateConfig('strokeColor', e.target.value), className: "h-10 w-16 rounded border p-1" }), jsx(Input, { value: customFloatingBubbleConfig.strokeColor, onChange: (e) => updateConfig('strokeColor', e.target.value), placeholder: "#3b82f6", className: "flex-1" })] })] })] }) })] }) }), jsx(TabsContent, { value: "position", className: "space-y-6", children: jsxs(Card$1, { children: [jsx(CardHeader, { className: "mb-0 px-4 py-3", children: jsx(CardTitle, { className: "text-sm font-medium text-gray-600", children: t('tabsEmbedTab.positionLayout') }) }), jsx(CardContent, { className: "space-y-6 pt-0", children: jsxs("div", { className: "space-y-2", children: [jsx(Label$1, { htmlFor: "position", className: "text-sm text-gray-600", children: t('tabsEmbedTab.screenPosition') }), jsx("div", { className: "mt-2", children: jsxs(Select$1, { value: customFloatingBubbleConfig.position, onValueChange: (value) => updateConfig('position', value), children: [jsx(SelectTrigger, { children: jsx(SelectValue, {}) }), jsxs(SelectContent, { children: [jsx(SelectItem, { value: "bottom-right", children: t('tabsEmbedTab.bottomRight') }), jsx(SelectItem, { value: "bottom-left", children: t('tabsEmbedTab.bottomLeft') }), jsx(SelectItem, { value: "top-right", children: t('tabsEmbedTab.topRight') }), jsx(SelectItem, { value: "top-left", children: t('tabsEmbedTab.topLeft') })] })] }) })] }) })] }) }), jsx(TabsContent, { value: "content", className: "space-y-6", children: jsxs(Card$1, { children: [jsx(CardHeader, { className: "mb-0 px-4 py-3", children: jsx(CardTitle, { className: "text-sm font-medium text-gray-600", children: t('tabsEmbedTab.textContent') }) }), jsxs(CardContent, { className: "space-y-4 pt-0", children: [jsxs("div", { className: "space-y-2", children: [jsx(Label$1, { htmlFor: "title", className: "text-sm text-gray-600", children: t('tabsEmbedTab.titleLabel') }), jsx(Input, { id: "title", value: customFloatingBubbleConfig.title, onChange: (e) => updateConfig('title', e.target.value), placeholder: "AI-powered assistant", className: "mt-2" })] }), jsxs("div", { className: "space-y-2", children: [jsx(Label$1, { htmlFor: "subtitle", className: "text-sm text-gray-600", children: t('tabsEmbedTab.subtitleText') }), jsx(Input, { id: "subtitle", value: customFloatingBubbleConfig.subtitle, onChange: (e) => updateConfig('subtitle', e.target.value), placeholder: "Created with AI", className: "mt-2" })] }), jsxs("div", { className: "space-y-2", children: [jsx(Label$1, { htmlFor: "iconImage", className: "text-sm text-gray-600", children: t('tabsEmbedTab.iconImage') }), jsxs("div", { className: "mt-2 space-y-1", children: [jsx(Input, { id: "iconImage", type: "file", accept: "image/*", onChange: (e) => {
|
|
280062
282200
|
var _a;
|
|
280063
282201
|
const file = (_a = e.target.files) === null || _a === void 0 ? void 0 : _a[0];
|
|
280064
282202
|
if (file) {
|
|
@@ -280073,7 +282211,7 @@ function AgentEmbedTab({ labels: labelsProp, urls, CopyCodeBlock, visibilityOpti
|
|
|
280073
282211
|
}
|
|
280074
282212
|
}, className: "h-[45px] file:mr-4 file:rounded-full file:border-0 file:bg-blue-50 file:px-4 file:py-2 file:text-sm file:font-semibold file:text-blue-700 hover:file:bg-blue-100" }), customFloatingBubbleConfig.image && (jsxs("div", { className: "my-3 flex items-center gap-3", children: [jsx("img", { src: customFloatingBubbleConfig.image || '/placeholder.svg', alt: t('tabsEmbedTab.chatIconPreviewAlt'), className: "h-12 w-12 rounded-lg border bg-gray-100 object-cover p-1" }), jsx(Button$1, { type: "button", variant: "outline", size: "sm", onClick: () => updateMultipleConfig({
|
|
280075
282213
|
image: null,
|
|
280076
|
-
}), children: t('tabsEmbedTab.removeImage') })] })), jsx("p", { className: "text-xs text-gray-500", children: t('tabsEmbedTab.iconUploadHint') })] })] })] })] }) })] }), jsxs(Card, { children: [jsx(CardHeader, { className: "mb-0 pt-4 pb-0", children: jsx(CardTitle, { className: "text-sm font-medium text-gray-600", children: t('tabsEmbedTab.livePreview') }) }), jsx(CardContent, { children: jsx(InteractiveBubbleConfigDisplay, { customFloatingBubbleConfig: customFloatingBubbleConfig, handleFloatingBubbleImageError: handleFloatingBubbleImageError }) })] })] }) }))] }) }), jsx("div", { className: "flex flex-shrink-0 justify-end border-t border-gray-200 bg-white px-3 py-4", children: jsx(Button$1, { onClick: () => form.handleSubmit(), className: "bg-gradient-to-r from-[#2563EB] to-[#93C5FD] text-sm text-white hover:text-white hover:opacity-90", disabled: form.state.isSubmitting, children: form.state.isSubmitting ? labels.actions.creatingEmbed : labels.actions.createEmbed }) })] }), embedCode && (jsx(Dialog, { open: !!embedCode, onOpenChange: (open) => {
|
|
282214
|
+
}), children: t('tabsEmbedTab.removeImage') })] })), jsx("p", { className: "text-xs text-gray-500", children: t('tabsEmbedTab.iconUploadHint') })] })] })] })] }) })] }), jsxs(Card$1, { children: [jsx(CardHeader, { className: "mb-0 pt-4 pb-0", children: jsx(CardTitle, { className: "text-sm font-medium text-gray-600", children: t('tabsEmbedTab.livePreview') }) }), jsx(CardContent, { children: jsx(InteractiveBubbleConfigDisplay, { customFloatingBubbleConfig: customFloatingBubbleConfig, handleFloatingBubbleImageError: handleFloatingBubbleImageError }) })] })] }) }))] }) }), jsx("div", { className: "flex flex-shrink-0 justify-end border-t border-gray-200 bg-white px-3 py-4", children: jsx(Button$1, { onClick: () => form.handleSubmit(), className: "bg-gradient-to-r from-[#2563EB] to-[#93C5FD] text-sm text-white hover:text-white hover:opacity-90", disabled: form.state.isSubmitting, children: form.state.isSubmitting ? labels.actions.creatingEmbed : labels.actions.createEmbed }) })] }), embedCode && (jsx(Dialog, { open: !!embedCode, onOpenChange: (open) => {
|
|
280077
282215
|
if (!open) {
|
|
280078
282216
|
setEmbedCode('');
|
|
280079
282217
|
}
|
|
@@ -282549,7 +284687,7 @@ function AgentCard({ agent, onClick, variant = 'default', isStarred = false, isT
|
|
|
282549
284687
|
onClick(agent);
|
|
282550
284688
|
}
|
|
282551
284689
|
};
|
|
282552
|
-
return (jsx(Card, { className: "cursor-pointer rounded-lg border border-[#D0E0FF] bg-[#F5F8FF] transition-shadow hover:shadow-md md:h-full", onClick: handleCardClick, tabIndex: 0, onKeyDown: handleCardKeyDown, "aria-label": `${exploreAriaPrefix} ${agent.name}. ${agent.description || ''}`, children: jsx(CardContent, { className: "p-6 md:h-full", children: jsxs("div", { className: "flex items-start gap-4 md:h-full", children: [jsxs(Avatar, { className: "h-12 w-12 shrink-0 rounded-full", children: [jsx(AvatarImage, { src: agent.profile_image, alt: agent.name, className: "object-cover" }), jsx(AvatarFallback, { children: agent.name.substring(0, 2).toUpperCase() })] }), jsxs("div", { className: "min-w-0 flex-1", children: [jsxs("div", { className: "mb-2 flex items-center justify-between", children: [jsx("h3", { className: "text-sm font-medium text-gray-900", children: agent.name }), variant === 'with-star' && onToggleStar && (jsx(StarButton, { isStarred: isStarred, isToggling: isTogglingStar, disabled: disableStar, onClick: (e) => {
|
|
284690
|
+
return (jsx(Card$1, { className: "cursor-pointer rounded-lg border border-[#D0E0FF] bg-[#F5F8FF] transition-shadow hover:shadow-md md:h-full", onClick: handleCardClick, tabIndex: 0, onKeyDown: handleCardKeyDown, "aria-label": `${exploreAriaPrefix} ${agent.name}. ${agent.description || ''}`, children: jsx(CardContent, { className: "p-6 md:h-full", children: jsxs("div", { className: "flex items-start gap-4 md:h-full", children: [jsxs(Avatar, { className: "h-12 w-12 shrink-0 rounded-full", children: [jsx(AvatarImage, { src: agent.profile_image, alt: agent.name, className: "object-cover" }), jsx(AvatarFallback, { children: agent.name.substring(0, 2).toUpperCase() })] }), jsxs("div", { className: "min-w-0 flex-1", children: [jsxs("div", { className: "mb-2 flex items-center justify-between", children: [jsx("h3", { className: "text-sm font-medium text-gray-900", children: agent.name }), variant === 'with-star' && onToggleStar && (jsx(StarButton, { isStarred: isStarred, isToggling: isTogglingStar, disabled: disableStar, onClick: (e) => {
|
|
282553
284691
|
e.stopPropagation();
|
|
282554
284692
|
onToggleStar(agent, e);
|
|
282555
284693
|
} }))] }), jsx("p", { className: "mb-3 line-clamp-2 text-sm leading-relaxed text-gray-600", children: agent.description }), agent.updated_at && (jsxs("p", { className: "text-xs text-gray-500", children: [updatedOnLabel, " ", formatDate(agent.updated_at)] }))] })] }) }) }));
|
|
@@ -282584,7 +284722,7 @@ function StarredAgentsSection() {
|
|
|
282584
284722
|
onUnauthenticatedAction === null || onUnauthenticatedAction === void 0 ? void 0 : onUnauthenticatedAction();
|
|
282585
284723
|
}, [username, onUnauthenticatedAction]);
|
|
282586
284724
|
const sectionLabels = labels.sections.starred;
|
|
282587
|
-
return (jsxs("div", { children: [jsx("h2", { className: "mb-4 text-lg font-medium text-gray-900", role: "heading", "aria-level": 2, children: sectionLabels.title }), agents.length > 0 ? (jsxs(Fragment$1, { children: [jsx("div", { className: "grid grid-cols-1 gap-6 md:grid-cols-2", "data-testid": "favorites-card-list", role: "list", "aria-label": sectionLabels.ariaLabel, children: agents.map((agent) => (jsx("div", { role: "listitem", children: jsx(AgentCard, { agent: agent, onClick: onAgentClick, variant: "with-star", isStarred: agent.starred, isTogglingStar: togglingAgentId === String(agent.id), onToggleStar: toggleFavorite, disableStar: !username, updatedOnLabel: labels.card.updatedOn, exploreAriaPrefix: labels.card.exploreAriaPrefix }) }, agent.id))) }), hasMore && (jsx("div", { className: "mt-6 flex justify-center", children: jsx(Button$1, { variant: "outline", onClick: () => setLimit((prev) => prev + FAVORITE_AGENTS_LIMIT), disabled: isFetching, "aria-label": sectionLabels.loadMoreAriaLabel, role: "button", children: isFetching ? (jsxs("div", { className: "flex items-center gap-2", children: [jsx(Spinner, { className: "h-4 w-4", "aria-hidden": "true" }), jsx("span", { children: labels.loadingMore })] })) : (labels.seeMore) }) }))] })) : (jsx("div", { className: "grid grid-cols-1 gap-6 md:grid-cols-2 lg:grid-cols-3", children: jsx(Card, { "data-testid": "favorites-card", className: "cursor-pointer rounded-lg border border-[#D0E0FF] bg-[#F5F8FF] transition-shadow duration-200 hover:shadow-md md:col-span-2 lg:col-span-3", onClick: handleFavoriteCardClick, role: "button", tabIndex: 0, onKeyDown: (e) => {
|
|
284725
|
+
return (jsxs("div", { children: [jsx("h2", { className: "mb-4 text-lg font-medium text-gray-900", role: "heading", "aria-level": 2, children: sectionLabels.title }), agents.length > 0 ? (jsxs(Fragment$1, { children: [jsx("div", { className: "grid grid-cols-1 gap-6 md:grid-cols-2", "data-testid": "favorites-card-list", role: "list", "aria-label": sectionLabels.ariaLabel, children: agents.map((agent) => (jsx("div", { role: "listitem", children: jsx(AgentCard, { agent: agent, onClick: onAgentClick, variant: "with-star", isStarred: agent.starred, isTogglingStar: togglingAgentId === String(agent.id), onToggleStar: toggleFavorite, disableStar: !username, updatedOnLabel: labels.card.updatedOn, exploreAriaPrefix: labels.card.exploreAriaPrefix }) }, agent.id))) }), hasMore && (jsx("div", { className: "mt-6 flex justify-center", children: jsx(Button$1, { variant: "outline", onClick: () => setLimit((prev) => prev + FAVORITE_AGENTS_LIMIT), disabled: isFetching, "aria-label": sectionLabels.loadMoreAriaLabel, role: "button", children: isFetching ? (jsxs("div", { className: "flex items-center gap-2", children: [jsx(Spinner, { className: "h-4 w-4", "aria-hidden": "true" }), jsx("span", { children: labels.loadingMore })] })) : (labels.seeMore) }) }))] })) : (jsx("div", { className: "grid grid-cols-1 gap-6 md:grid-cols-2 lg:grid-cols-3", children: jsx(Card$1, { "data-testid": "favorites-card", className: "cursor-pointer rounded-lg border border-[#D0E0FF] bg-[#F5F8FF] transition-shadow duration-200 hover:shadow-md md:col-span-2 lg:col-span-3", onClick: handleFavoriteCardClick, role: "button", tabIndex: 0, onKeyDown: (e) => {
|
|
282588
284726
|
if (e.key === 'Enter' || e.key === ' ') {
|
|
282589
284727
|
e.preventDefault();
|
|
282590
284728
|
handleFavoriteCardClick();
|
|
@@ -282619,7 +284757,7 @@ function FeaturedAgentsSection() {
|
|
|
282619
284757
|
if (agents.length === 0 && !isFetching) {
|
|
282620
284758
|
return null;
|
|
282621
284759
|
}
|
|
282622
|
-
return (jsxs("div", { children: [jsx("h2", { className: "mb-4 text-lg font-medium text-gray-900", role: "heading", "aria-level": 2, children: sectionLabels.title }), agents.length > 0 ? (jsxs(Fragment$1, { children: [jsx("div", { className: "grid grid-cols-1 gap-6 md:grid-cols-2", children: agents.map((agent) => (jsx(AgentCard, { agent: agent, onClick: onAgentClick, variant: "with-star", isStarred: agent.starred, isTogglingStar: togglingAgentId === String(agent.id), onToggleStar: toggleFavorite, disableStar: !username, updatedOnLabel: labels.card.updatedOn, exploreAriaPrefix: labels.card.exploreAriaPrefix }, agent.id))) }), hasMore && (jsx("div", { className: "mt-6 flex justify-center", children: jsx(Button$1, { variant: "outline", onClick: () => setLimit((prev) => prev + FEATURED_AGENTS_LIMIT), disabled: isFetching, "aria-label": sectionLabels.loadMoreAriaLabel, children: isFetching ? (jsxs("div", { className: "flex items-center gap-2", children: [jsx(Spinner, { className: "h-4 w-4", "aria-hidden": "true" }), jsx("span", { children: labels.loadingMore })] })) : (labels.seeMore) }) }))] })) : (jsx("div", { className: "grid grid-cols-1 gap-6 md:grid-cols-2 lg:grid-cols-3", children: jsx(Card, { className: "rounded-lg border border-[#D0E0FF] bg-[#F5F8FF] md:col-span-2 lg:col-span-3", children: jsx(CardContent, { className: "p-6", children: jsxs("div", { className: "flex items-start gap-4", children: [jsx("div", { className: "flex h-12 w-12 flex-shrink-0 items-center justify-center rounded-lg bg-[#D0E0FF]", children: jsx(Award, { className: "h-6 w-6 text-[#38A1E5]" }) }), jsxs("div", { className: "min-w-0 flex-1", children: [jsx("h3", { className: "mb-2 text-sm font-medium text-gray-900", children: sectionLabels.emptyTitle }), jsx("p", { className: "mb-3 text-sm leading-relaxed text-gray-600", children: sectionLabels.emptyDescription }), jsx("p", { className: "text-xs text-gray-500", children: sectionLabels.emptySubtext })] })] }) }) }) }))] }));
|
|
284760
|
+
return (jsxs("div", { children: [jsx("h2", { className: "mb-4 text-lg font-medium text-gray-900", role: "heading", "aria-level": 2, children: sectionLabels.title }), agents.length > 0 ? (jsxs(Fragment$1, { children: [jsx("div", { className: "grid grid-cols-1 gap-6 md:grid-cols-2", children: agents.map((agent) => (jsx(AgentCard, { agent: agent, onClick: onAgentClick, variant: "with-star", isStarred: agent.starred, isTogglingStar: togglingAgentId === String(agent.id), onToggleStar: toggleFavorite, disableStar: !username, updatedOnLabel: labels.card.updatedOn, exploreAriaPrefix: labels.card.exploreAriaPrefix }, agent.id))) }), hasMore && (jsx("div", { className: "mt-6 flex justify-center", children: jsx(Button$1, { variant: "outline", onClick: () => setLimit((prev) => prev + FEATURED_AGENTS_LIMIT), disabled: isFetching, "aria-label": sectionLabels.loadMoreAriaLabel, children: isFetching ? (jsxs("div", { className: "flex items-center gap-2", children: [jsx(Spinner, { className: "h-4 w-4", "aria-hidden": "true" }), jsx("span", { children: labels.loadingMore })] })) : (labels.seeMore) }) }))] })) : (jsx("div", { className: "grid grid-cols-1 gap-6 md:grid-cols-2 lg:grid-cols-3", children: jsx(Card$1, { className: "rounded-lg border border-[#D0E0FF] bg-[#F5F8FF] md:col-span-2 lg:col-span-3", children: jsx(CardContent, { className: "p-6", children: jsxs("div", { className: "flex items-start gap-4", children: [jsx("div", { className: "flex h-12 w-12 flex-shrink-0 items-center justify-center rounded-lg bg-[#D0E0FF]", children: jsx(Award, { className: "h-6 w-6 text-[#38A1E5]" }) }), jsxs("div", { className: "min-w-0 flex-1", children: [jsx("h3", { className: "mb-2 text-sm font-medium text-gray-900", children: sectionLabels.emptyTitle }), jsx("p", { className: "mb-3 text-sm leading-relaxed text-gray-600", children: sectionLabels.emptyDescription }), jsx("p", { className: "text-xs text-gray-500", children: sectionLabels.emptySubtext })] })] }) }) }) }))] }));
|
|
282623
284761
|
}
|
|
282624
284762
|
|
|
282625
284763
|
function CustomAgentsSection() {
|
|
@@ -282651,7 +284789,7 @@ function CustomAgentsSection() {
|
|
|
282651
284789
|
onCreateAgent === null || onCreateAgent === void 0 ? void 0 : onCreateAgent();
|
|
282652
284790
|
}, [username, onUnauthenticatedAction, onCreateAgent]);
|
|
282653
284791
|
const sectionLabels = labels.sections.custom;
|
|
282654
|
-
const createCard = onCreateAgent ? (jsx(WithPermissions, { rbacResource: createAgentRbacResource, rbacPermissions: rbacPermissions !== null && rbacPermissions !== void 0 ? rbacPermissions : {}, children: ({ hasPermission }) => hasPermission || !enableRBAC ? (jsx(Card, { className: "cursor-pointer border border-[#D0E0FF] bg-[#F5F8FF] transition-shadow duration-200 hover:shadow-md", onClick: handleCreate, role: "button", tabIndex: 0, onKeyDown: (e) => {
|
|
284792
|
+
const createCard = onCreateAgent ? (jsx(WithPermissions, { rbacResource: createAgentRbacResource, rbacPermissions: rbacPermissions !== null && rbacPermissions !== void 0 ? rbacPermissions : {}, children: ({ hasPermission }) => hasPermission || !enableRBAC ? (jsx(Card$1, { className: "cursor-pointer border border-[#D0E0FF] bg-[#F5F8FF] transition-shadow duration-200 hover:shadow-md", onClick: handleCreate, role: "button", tabIndex: 0, onKeyDown: (e) => {
|
|
282655
284793
|
if (e.key === 'Enter' || e.key === ' ') {
|
|
282656
284794
|
e.preventDefault();
|
|
282657
284795
|
handleCreate();
|
|
@@ -283839,76 +285977,6 @@ const AIMessageBubble = forwardRef(function AIMessageBubble({ content, profileIm
|
|
|
283839
285977
|
}, className: "-ml-1 text-gray-500 hover:text-gray-700", children: [jsx("span", { className: "sr-only", children: t('chatAiMessageBubble.retryScreenReaderLabel') }), jsx(RefreshCcw, { className: "h-4 w-4" })] }) }), jsx(TooltipContent, { className: "ibl-tooltip-content", children: t('chatAiMessageBubble.retryTooltip') })] }))] })] })] }) }) }));
|
|
283840
285978
|
});
|
|
283841
285979
|
|
|
283842
|
-
function FileCard({ fileName, fileType }) {
|
|
283843
|
-
const getFileIcon = (fileName, fileType) => {
|
|
283844
|
-
const type = fileType.toLowerCase();
|
|
283845
|
-
const name = fileName.toLowerCase();
|
|
283846
|
-
const extension = name.split('.').pop() || '';
|
|
283847
|
-
// Check by MIME type first
|
|
283848
|
-
if (type.includes('pdf')) {
|
|
283849
|
-
return jsx(File$1, { className: "h-5 w-5 text-blue-500" });
|
|
283850
|
-
}
|
|
283851
|
-
else if (type.includes('image')) {
|
|
283852
|
-
return jsx(FileImage, { className: "h-5 w-5 text-blue-500" });
|
|
283853
|
-
}
|
|
283854
|
-
else if (type.includes('audio')) {
|
|
283855
|
-
return jsx(FileAudio, { className: "h-5 w-5 text-blue-500" });
|
|
283856
|
-
}
|
|
283857
|
-
else if (type.includes('video')) {
|
|
283858
|
-
return jsx(FilePlay, { className: "h-5 w-5 text-blue-500" });
|
|
283859
|
-
}
|
|
283860
|
-
else if (type.includes('spreadsheet') || type.includes('excel') || type.includes('csv')) {
|
|
283861
|
-
return jsx(FileSpreadsheet, { className: "h-5 w-5 text-blue-500" });
|
|
283862
|
-
}
|
|
283863
|
-
else if (type.includes('zip') || type.includes('compressed') || type.includes('archive')) {
|
|
283864
|
-
return jsx(FileArchive, { className: "h-5 w-5 text-blue-500" });
|
|
283865
|
-
}
|
|
283866
|
-
else if (type.includes('javascript') ||
|
|
283867
|
-
type.includes('typescript') ||
|
|
283868
|
-
type.includes('html') ||
|
|
283869
|
-
type.includes('css') ||
|
|
283870
|
-
type.includes('json')) {
|
|
283871
|
-
return jsx(FileCode, { className: "h-5 w-5 text-blue-500" });
|
|
283872
|
-
}
|
|
283873
|
-
// If MIME type doesn't match, check by extension
|
|
283874
|
-
if (['doc', 'docx', 'txt', 'rtf'].includes(extension)) {
|
|
283875
|
-
return jsx(FileText, { className: "h-5 w-5 text-blue-500" });
|
|
283876
|
-
}
|
|
283877
|
-
else if (['jpg', 'jpeg', 'png', 'gif', 'svg', 'webp'].includes(extension)) {
|
|
283878
|
-
return jsx(FileImage, { className: "h-5 w-5 text-blue-500" });
|
|
283879
|
-
}
|
|
283880
|
-
else if (['pdf'].includes(extension)) {
|
|
283881
|
-
return jsx(File$1, { className: "h-5 w-5 text-blue-500" });
|
|
283882
|
-
}
|
|
283883
|
-
else if (['mp3', 'wav', 'ogg', 'flac'].includes(extension)) {
|
|
283884
|
-
return jsx(FileAudio, { className: "h-5 w-5 text-blue-500" });
|
|
283885
|
-
}
|
|
283886
|
-
else if (['mp4', 'webm', 'avi', 'mov'].includes(extension)) {
|
|
283887
|
-
return jsx(FilePlay, { className: "h-5 w-5 text-blue-500" });
|
|
283888
|
-
}
|
|
283889
|
-
else if (['xls', 'xlsx', 'csv'].includes(extension)) {
|
|
283890
|
-
return jsx(FileSpreadsheet, { className: "h-5 w-5 text-blue-500" });
|
|
283891
|
-
}
|
|
283892
|
-
else if (['zip', 'rar', '7z', 'tar', 'gz'].includes(extension)) {
|
|
283893
|
-
return jsx(FileArchive, { className: "h-5 w-5 text-blue-500" });
|
|
283894
|
-
}
|
|
283895
|
-
else if (['js', 'ts', 'jsx', 'tsx', 'html', 'css', 'json', 'py', 'java', 'c', 'cpp'].includes(extension)) {
|
|
283896
|
-
return jsx(FileCode, { className: "h-5 w-5 text-blue-500" });
|
|
283897
|
-
}
|
|
283898
|
-
// Default icon
|
|
283899
|
-
return jsx(File$1, { className: "h-5 w-5 text-blue-500" });
|
|
283900
|
-
};
|
|
283901
|
-
return (jsxs("div", { className: "mb-2 flex max-w-xs items-center rounded-lg border border-gray-200 bg-white p-3", children: [jsx("div", { className: "mr-3 shrink-0 rounded-lg bg-blue-100 p-2 text-blue-600", children: getFileIcon(fileName, fileType) }), jsxs("div", { className: "min-w-0 flex-1", children: [jsx("h3", { className: "truncate text-sm font-medium text-gray-900", children: fileName }), jsx("p", { className: "truncate text-xs text-gray-500", children: fileType })] })] }));
|
|
283902
|
-
}
|
|
283903
|
-
|
|
283904
|
-
function ImageMessage({ url, fileName, setPreviewImage }) {
|
|
283905
|
-
const [hasError, setHasError] = useState(false);
|
|
283906
|
-
if (hasError || !url) {
|
|
283907
|
-
return jsx(FileCard, { fileName: fileName, fileType: "image/*" });
|
|
283908
|
-
}
|
|
283909
|
-
return (jsx("div", { className: "h-full max-h-64 w-full max-w-96 overflow-hidden rounded-lg", children: jsx("div", { className: "relative", children: jsx("img", { src: url, alt: fileName, className: "h-auto w-full cursor-pointer object-contain p-2", onClick: () => setPreviewImage(url), onError: () => setHasError(true) }) }) }));
|
|
283910
|
-
}
|
|
283911
|
-
|
|
283912
285980
|
function UserMessageBubble({ message, isHighlighted, profileImage, mentorName, messages, onHighlightMessage, onPreviewImage, }) {
|
|
283913
285981
|
return (jsxs("div", { className: `message-container mb-4 flex flex-col items-end transition-all duration-300 ${isHighlighted ? 'rounded-2xl bg-blue-100' : ''}`, children: [message.fileAttachments && message.fileAttachments.length > 0 && (jsx("div", { className: "mb-2 flex flex-col items-end gap-2", children: message.fileAttachments.map((attachment, idx) => {
|
|
283914
285982
|
if (attachment.fileType.startsWith('image/')) {
|
|
@@ -285942,7 +288010,7 @@ function ExploreMentors({ tenantKey, onBrowseAll, onSelectMentor }) {
|
|
|
285942
288010
|
name: mentor.name,
|
|
285943
288011
|
// @ts-expect-error - description property may not exist on Mentor type
|
|
285944
288012
|
description: mentor.description || t('welcomeChatExploreMentors.noDescription'),
|
|
285945
|
-
}), children: jsx(Card, { className: "h-full cursor-pointer border border-[#D0E0FF] bg-[#F5F8FF] shadow-xs transition-all duration-200 focus-within:shadow-md hover:shadow-sm", children: jsx(CardContent, { className: "h-full p-4", children: jsxs("div", { className: "flex h-full items-start gap-3", children: [jsxs(Avatar, { className: "h-12 w-12 flex-shrink-0", children: [jsx(AvatarImage
|
|
288013
|
+
}), children: jsx(Card$1, { className: "h-full cursor-pointer border border-[#D0E0FF] bg-[#F5F8FF] shadow-xs transition-all duration-200 focus-within:shadow-md hover:shadow-sm", children: jsx(CardContent, { className: "h-full p-4", children: jsxs("div", { className: "flex h-full items-start gap-3", children: [jsxs(Avatar, { className: "h-12 w-12 flex-shrink-0", children: [jsx(AvatarImage
|
|
285946
288014
|
// @ts-expect-error - profile_image property may not exist on Mentor type
|
|
285947
288015
|
, {
|
|
285948
288016
|
// @ts-expect-error - profile_image property may not exist on Mentor type
|
|
@@ -285990,7 +288058,7 @@ function ConversationStarters({ onTemplateSelect, enabledGuidedPrompts, sessionI
|
|
|
285990
288058
|
}
|
|
285991
288059
|
return (jsxs("div", { className: "mx-auto w-full max-w-6xl px-4", children: [jsx("h2", { className: "mb-6 text-xl font-semibold text-gray-900", children: t('welcomeChatConversationStarters.heading') }), jsx("div", { className: "grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-5", children: (_b = guidedPrompts === null || guidedPrompts === void 0 ? void 0 : guidedPrompts.results) === null || _b === void 0 ? void 0 : _b.map((guidedPrompt, index) => {
|
|
285992
288060
|
var _a;
|
|
285993
|
-
return (jsx(Card, { className: cn('h-full border border-[#D0E0FF] bg-[#F5F8FF] shadow-xs transition-all duration-200', isChatDisabledByRbac
|
|
288061
|
+
return (jsx(Card$1, { className: cn('h-full border border-[#D0E0FF] bg-[#F5F8FF] shadow-xs transition-all duration-200', isChatDisabledByRbac
|
|
285994
288062
|
? 'cursor-not-allowed opacity-50'
|
|
285995
288063
|
: 'cursor-pointer hover:shadow-sm focus:shadow-md focus:ring-2 focus:ring-gray-300 focus:ring-offset-2 focus:outline-none'), onClick: () => !isChatDisabledByRbac && onTemplateSelect(guidedPrompt.prompt), onKeyDown: (e) => {
|
|
285996
288064
|
if (isChatDisabledByRbac)
|
|
@@ -287447,7 +289515,7 @@ function TaskMetricsCards({ tasksData, labels }) {
|
|
|
287447
289515
|
const totalTasks = tasksData.length;
|
|
287448
289516
|
const completedTasks = tasksData.filter((t) => t.status === 'Completed').length;
|
|
287449
289517
|
const failedTasks = tasksData.filter((t) => t.status === 'Failed').length;
|
|
287450
|
-
return (jsxs("div", { className: "grid grid-cols-1 sm:grid-cols-3 gap-4", children: [jsx(Card, { className: "w-full bg-white border border-blue-200", children: jsxs(CardContent, { className: "p-4 flex flex-row items-center justify-between", children: [jsxs("div", { className: "flex flex-col", children: [jsx("h3", { className: "text-sm font-medium text-gray-700 mb-2", children: labels.metrics.total }), jsx("p", { className: "text-2xl font-semibold text-gray-900", children: totalTasks })] }), jsx(ClipboardList, { className: "h-6 w-6 text-blue-500 flex-shrink-0" })] }) }), jsx(Card, { className: "w-full bg-white border border-blue-200", children: jsxs(CardContent, { className: "p-4 flex flex-row items-center justify-between", children: [jsxs("div", { className: "flex flex-col", children: [jsx("h3", { className: "text-sm font-medium text-gray-700 mb-2", children: labels.metrics.completed }), jsx("p", { className: "text-2xl font-semibold text-gray-900", children: completedTasks })] }), jsx(CircleCheckBig, { className: "h-6 w-6 text-blue-500 flex-shrink-0" })] }) }), jsx(Card, { className: "w-full bg-white border border-blue-200", children: jsxs(CardContent, { className: "p-4 flex flex-row items-center justify-between", children: [jsxs("div", { className: "flex flex-col", children: [jsx("h3", { className: "text-sm font-medium text-gray-700 mb-2", children: labels.metrics.failed }), jsx("p", { className: "text-2xl font-semibold text-gray-900", children: failedTasks })] }), jsx(CircleX, { className: "h-6 w-6 text-red-500 flex-shrink-0" })] }) })] }));
|
|
289518
|
+
return (jsxs("div", { className: "grid grid-cols-1 sm:grid-cols-3 gap-4", children: [jsx(Card$1, { className: "w-full bg-white border border-blue-200", children: jsxs(CardContent, { className: "p-4 flex flex-row items-center justify-between", children: [jsxs("div", { className: "flex flex-col", children: [jsx("h3", { className: "text-sm font-medium text-gray-700 mb-2", children: labels.metrics.total }), jsx("p", { className: "text-2xl font-semibold text-gray-900", children: totalTasks })] }), jsx(ClipboardList, { className: "h-6 w-6 text-blue-500 flex-shrink-0" })] }) }), jsx(Card$1, { className: "w-full bg-white border border-blue-200", children: jsxs(CardContent, { className: "p-4 flex flex-row items-center justify-between", children: [jsxs("div", { className: "flex flex-col", children: [jsx("h3", { className: "text-sm font-medium text-gray-700 mb-2", children: labels.metrics.completed }), jsx("p", { className: "text-2xl font-semibold text-gray-900", children: completedTasks })] }), jsx(CircleCheckBig, { className: "h-6 w-6 text-blue-500 flex-shrink-0" })] }) }), jsx(Card$1, { className: "w-full bg-white border border-blue-200", children: jsxs(CardContent, { className: "p-4 flex flex-row items-center justify-between", children: [jsxs("div", { className: "flex flex-col", children: [jsx("h3", { className: "text-sm font-medium text-gray-700 mb-2", children: labels.metrics.failed }), jsx("p", { className: "text-2xl font-semibold text-gray-900", children: failedTasks })] }), jsx(CircleX, { className: "h-6 w-6 text-red-500 flex-shrink-0" })] }) })] }));
|
|
287451
289519
|
}
|
|
287452
289520
|
|
|
287453
289521
|
const STATUS_BADGE = {
|
|
@@ -288529,7 +290597,7 @@ function PromptCard({ prompt, onEdit, onSelect, title, tenantKey, userIsStudent
|
|
|
288529
290597
|
onSelect(prompt.prompt);
|
|
288530
290598
|
}
|
|
288531
290599
|
};
|
|
288532
|
-
return (jsxs(Fragment$1, { children: [jsx(Card, { className: "overflow-hidden border-0 bg-[#F8F8F8] transition-shadow hover:shadow-md", children: jsxs(CardContent, { className: "h-full p-4", children: [jsxs("div", { className: "mb-5 flex flex-1 items-start gap-2", children: [jsx(MessageSquare, { className: "mt-1 h-4 w-4 flex-shrink-0 text-gray-400" }), jsxs("div", { className: "flex-1", children: [jsx("h3", { className: "text-sm font-medium text-gray-600", children: title }), jsx(Markdown, { className: "mt-1 line-clamp-4 text-sm text-gray-500", children: parsePrompt(prompt.prompt) })] })] }), jsxs("div", { className: "flex flex-wrap justify-start gap-2", children: [!userIsStudent && (jsxs(Button$1, { variant: "outline", size: "sm", className: "flex h-7 items-center border-gray-200 px-3 text-xs font-normal text-gray-600", onClick: handleEdit, disabled: isDeleting, children: [jsx(SquarePen, { className: "mr-1.5 h-3 w-3" }), t('promptGalleryModalPromptCard.edit')] })), jsxs(Button$1, { variant: "outline", size: "sm", className: "flex h-7 items-center border-gray-200 px-3 text-xs font-normal text-gray-600", onClick: () => executeWithTrialCheck(handleRun), disabled: isDeleting, children: [jsx(Play, { className: "mr-1.5 h-3 w-3" }), t('promptGalleryModalPromptCard.run')] }), jsx(Button$1, { variant: "outline", size: "sm", className: "flex h-7 items-center border-gray-200 px-3 text-xs font-normal text-gray-600", onClick: () => copy(prompt.prompt), disabled: isDeleting, children: status === 'success' ? (jsxs(Fragment$1, { children: [jsx(Check, { className: "mr-1.5 h-3 w-3" }), " ", t('promptGalleryModalPromptCard.copied')] })) : (jsxs(Fragment$1, { children: [jsx(Copy, { className: "mr-1.5 h-3 w-3" }), " ", t('promptGalleryModalPromptCard.copy')] })) }), !userIsStudent && (jsxs(Button$1, { variant: "outline", size: "sm", className: "flex h-7 items-center border-gray-200 px-3 text-xs font-normal text-gray-600 hover:text-gray-600", onClick: () => executeWithTrialCheck(handleDelete), disabled: isDeleting, children: [jsx(DeleteIcon, { className: cn('mr-1.5 h-3 w-3', isDeleting && 'animate-spin') }), t('promptGalleryModalPromptCard.delete')] }))] })] }) }), isModalOpen && FreeTrialDialog && (jsx(FreeTrialDialog, { onClose: closeModal, isOpen: isModalOpen }))] }));
|
|
290600
|
+
return (jsxs(Fragment$1, { children: [jsx(Card$1, { className: "overflow-hidden border-0 bg-[#F8F8F8] transition-shadow hover:shadow-md", children: jsxs(CardContent, { className: "h-full p-4", children: [jsxs("div", { className: "mb-5 flex flex-1 items-start gap-2", children: [jsx(MessageSquare, { className: "mt-1 h-4 w-4 flex-shrink-0 text-gray-400" }), jsxs("div", { className: "flex-1", children: [jsx("h3", { className: "text-sm font-medium text-gray-600", children: title }), jsx(Markdown, { className: "mt-1 line-clamp-4 text-sm text-gray-500", children: parsePrompt(prompt.prompt) })] })] }), jsxs("div", { className: "flex flex-wrap justify-start gap-2", children: [!userIsStudent && (jsxs(Button$1, { variant: "outline", size: "sm", className: "flex h-7 items-center border-gray-200 px-3 text-xs font-normal text-gray-600", onClick: handleEdit, disabled: isDeleting, children: [jsx(SquarePen, { className: "mr-1.5 h-3 w-3" }), t('promptGalleryModalPromptCard.edit')] })), jsxs(Button$1, { variant: "outline", size: "sm", className: "flex h-7 items-center border-gray-200 px-3 text-xs font-normal text-gray-600", onClick: () => executeWithTrialCheck(handleRun), disabled: isDeleting, children: [jsx(Play, { className: "mr-1.5 h-3 w-3" }), t('promptGalleryModalPromptCard.run')] }), jsx(Button$1, { variant: "outline", size: "sm", className: "flex h-7 items-center border-gray-200 px-3 text-xs font-normal text-gray-600", onClick: () => copy(prompt.prompt), disabled: isDeleting, children: status === 'success' ? (jsxs(Fragment$1, { children: [jsx(Check, { className: "mr-1.5 h-3 w-3" }), " ", t('promptGalleryModalPromptCard.copied')] })) : (jsxs(Fragment$1, { children: [jsx(Copy, { className: "mr-1.5 h-3 w-3" }), " ", t('promptGalleryModalPromptCard.copy')] })) }), !userIsStudent && (jsxs(Button$1, { variant: "outline", size: "sm", className: "flex h-7 items-center border-gray-200 px-3 text-xs font-normal text-gray-600 hover:text-gray-600", onClick: () => executeWithTrialCheck(handleDelete), disabled: isDeleting, children: [jsx(DeleteIcon, { className: cn('mr-1.5 h-3 w-3', isDeleting && 'animate-spin') }), t('promptGalleryModalPromptCard.delete')] }))] })] }) }), isModalOpen && FreeTrialDialog && (jsx(FreeTrialDialog, { onClose: closeModal, isOpen: isModalOpen }))] }));
|
|
288533
290601
|
}
|
|
288534
290602
|
|
|
288535
290603
|
function EmptyPrompts() {
|