@iblai/iblai-js 2.4.3 → 2.4.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/data-layer/playwright/agent-skills-helpers.d.ts +23 -10
- package/dist/data-layer/playwright/index.d.ts +3 -1
- package/dist/data-layer/playwright/spend-limits-helpers.d.ts +275 -0
- package/dist/playwright/index.cjs +770 -66
- package/dist/playwright/index.cjs.map +1 -1
- package/dist/playwright/index.d.ts +300 -12
- package/dist/playwright/index.esm.js +737 -67
- package/dist/playwright/index.esm.js.map +1 -1
- package/dist/playwright/playwright/agent-skills-helpers.d.ts +23 -10
- package/dist/playwright/playwright/index.d.ts +3 -1
- package/dist/playwright/playwright/spend-limits-helpers.d.ts +275 -0
- package/dist/security/playwright/agent-skills-helpers.d.ts +23 -10
- package/dist/security/playwright/index.d.ts +3 -1
- package/dist/security/playwright/spend-limits-helpers.d.ts +275 -0
- package/dist/web-containers/playwright/agent-skills-helpers.d.ts +23 -10
- package/dist/web-containers/playwright/index.d.ts +3 -1
- package/dist/web-containers/playwright/spend-limits-helpers.d.ts +275 -0
- package/dist/web-containers/source/index.esm.js +9278 -6500
- package/dist/web-containers/source/next/index.esm.js +2308 -245
- package/dist/web-utils/playwright/agent-skills-helpers.d.ts +23 -10
- package/dist/web-utils/playwright/index.d.ts +3 -1
- package/dist/web-utils/playwright/spend-limits-helpers.d.ts +275 -0
- package/package.json +5 -5
|
@@ -2,7 +2,7 @@ import { jsx, jsxs, Fragment as Fragment$1 } from 'react/jsx-runtime';
|
|
|
2
2
|
import * as React from 'react';
|
|
3
3
|
import React__default, { useState, useEffect, forwardRef, createElement as createElement$3, useLayoutEffect, createContext, useContext, useMemo, useReducer, useRef, useImperativeHandle, useCallback, isValidElement, Children, PureComponent, cloneElement, Component as Component$1, useId as useId$2, useDebugValue, lazy, Suspense } from 'react';
|
|
4
4
|
import * as dataLayer from '@iblai/data-layer';
|
|
5
|
-
import { useGetUserMetadataQuery, useGetUserMetadataEdxQuery, useUpdateUserMetadataMutation, useUpdateUserMetadataEdxMutation, useUploadProfileImageMutation, useResetPasswordMutation, useSelfRetireMutation, useCreateUserInstitutionMutation, useGetUserInstitutionsQuery, useCreateUserEducationMutation, useUpdateUserEducationMutation, useDeleteUserEducationMutation, useGetUserEducationQuery, useCreateUserCompanyMutation, useGetUserCompaniesQuery, useCreateUserExperienceMutation, useUpdateUserExperienceMutation, useDeleteUserExperienceMutation, useGetUserExperienceQuery, useGetUserResumeQuery, useCreateUserResumeMutation, useGetMySubscriptionsQuery, useGetItemSubscriptionQuery, useCancelSubscriptionMutation, useGetLearnerDetailsQuery, useGetUserEnrolledCoursesQuery, useGetUserEnrolledProgramsQuery, useGetUserCatalogPathwaysQuery, useGetUsersAsAssertionsQuery, useGetUserEarnedSkillsQuery, useGetUserReportedSkillsQuery, useGetUserDesiredSkillsQuery, useCreateGlobalMemoryMutation, useGetMemsearchStatusQuery, useGetUserMemorySettingsQuery, useUpdateUserMemorySettingsMutation, useGetGlobalMemoriesQuery, useGetAllMentorMemoriesQuery, useDeleteGlobalMemoryMutation, useInviteUserMutation, usePlatformInvitationsQuery, useCreateCatalogInvitationCourseBulkMutation, useGetCatalogInvitationsCourseQuery, useLazyPlatformUsersQuery, useLazyPlatformUserGroupsQuery, useGetPersonnalizedSearchQuery, useCreateCatalogInvitationProgramBulkMutation, useGetCatalogInvitationsProgramQuery, useUpdateUserRoleMutation, useUpdateUserStatusMutation, useUpdatePlatformUserRoleWithPoliciesMutation, usePlatformUsersQuery, useGetAccessibleUsersQuery, isPoliciesResponse, platformApiSlice, featureTags, useLazyGetRbacTeamsAccessListQuery, useCreateRbacTeamsAccessMutation, useGetRbacGroupsQuery, usePlatformUserGroupsQuery, useCreateRbacGroupMutation, useUpdateRbacGroupMutation, useDeleteRbacGroupMutation, useCreatePlatformUserGroupMutation, useUpdatePlatformUserGroupMutation, useDeletePlatformUserGroupMutation, useGetRbacGroupDetailsQuery, useGetPlatformUserGroupDetailsQuery, useGetRbacPermissionsMutation, useGetRbacRolesQuery, useCreateRbacRoleMutation, useUpdateRbacRoleMutation, useDeleteRbacRoleMutation, useGetRbacRoleDetailsQuery, useGetRbacActionsDefinitionQuery, useGetRbacResourceDiscoveryQuery, useGetRbacResourceListQuery, useGetRbacPoliciesQuery, useCreateRbacPolicyMutation, useUpdateRbacPolicyMutation, useDeleteRbacPolicyMutation, useGetRbacPolicyDetailsQuery, useGetWatchedGroupsQuery, useCreateWatchedGroupMutation, useUpdateWatchedGroupMutation, useDeleteWatchedGroupMutation, useAddWatchedUserMutation, useRemoveWatchedUserMutation, useAddWatcherMutation, useUpdateWatcherMutation, useDeleteWatcherMutation, useGetWatchedUsersQuery, useGetWatchersQuery, WATCHER_NOTIFICATION_EVENTS, WATCHER_NOTIFICATION_EVENT_LABELS, useGetApplicationFormsQuery, useGetApplicationFormDetailQuery, useCreateApplicationFormMutation, useUpdateApplicationFormMutation, useGetApplicationAdminDetailQuery, useInviteApplicationCandidateMutation, useLazyGetApplicationAttachmentFileQuery, useCreateApplicationWaiverMutation, useDeleteApplicationWaiverMutation, useSubmitApplicationOverrideMutation, useUpdateApplicationPlacementMutation, useDeleteApplicationCourseAssignmentMutation, useCreateApplicationNoteMutation, useUpdateApplicationNoteMutation, useDeleteApplicationNoteMutation, useTransitionApplicationMutation, useLinkApplicationCandidateMutation, useCreateApplicationPlacementsMutation, useGetCustomMentorsQuery, useCreateApplicationCourseAssignmentsMutation, useGetApplicationBlocksQuery, useDeleteApplicationBlockMutation, useGetApplicationsPipelineStatsQuery, useGetApplicationsPipelineQuery, useDeleteApiKeyMutation, useGetApiKeyQuery, useGetApiKeyFieldPermissionsQuery, useUpdateApiKeyMutation, useGetApiKeysQuery, unwrapApiTokenList, useCreateApiKeyMutation, useCreateLLMCredentialMutation, useGetCredentialsSchemaQuery, useGetMaskedLLMCredentialsQuery, useGetLlmsQuery, useDeleteIntegrationCredentialMutation, useDeleteCredentialMutation, useCreateIntegrationCredentialMutation, useGetIntegrationCredentialsSchemaQuery, useGetMaskedIntegrationCredentialsQuery, useGetAccountBillingInfoQuery, useUpdateAutoRechargeInfoMutation, useTriggerAutoRechargeMutation, useCreateStripeCustomerPortalMutation, useSetPlatformConfigurationsMutation, useGetPlatformConfigurationsQuery, useUpdatePlatformMembershipMutation, useGetPlatformMembershipQuery, useGetCustomDomainsQuery, useCreateCustomDomainMutation, useDeleteCustomDomainMutation, useGetStudentMentorCreationStatusQuery, useSetStudentMentorCreationStatusMutation, coreApiSlice, recommendationPromptTypeEnum, useGetRecommendedPromptsListQuery, useCreateRecommendedPromptMutation, useUpdateRecommendedPromptMutation, useDeleteRecommendedPromptMutation, useLazyGetPublicPlatformImageAssetFileUrlQuery, useUpdateTenantMetadataMutation, useCreatePlatformImageAssetMutation, useGetProviderConfigQuery, useCreateProviderConfigMutation, useDeleteProviderConfigMutation, useGetExternalMappingQuery, useGetCredentialsListQuery, useCreateExternalMappingMutation, useDeleteExternalMappingMutation, useGetMemsearchConfigQuery, useUpdateMemsearchConfigMutation, useGetStripeConnectStatusQuery, useStartStripeConnectOnboardingMutation, useLazyGetStripeConnectDashboardQuery, useGetAiSearchMentorsQuery, useListPaywallsQuery, useListPricesQuery, useCreatePriceMutation, useUpdatePriceMutation, useDeletePriceMutation, useGetPaywallConfigQuery, useEnablePaywallMutation, useUpdatePaywallMutation, useStarMentorMutation, useUnstarMentorMutation, useLazyGetCourseMetaDataQuery, useLazyGetCourseCompletionOutlinesQuery, useLazyGetCourseEligibilityQuery, useLazyGetEdxSSOTokenQuery, useCreateCourseEnrollmentMutation, useCreateStripeCheckoutSessionMutation, useLazyGetCourseProgressQuery, useLazyGetCourseCompletionQuery, useUpdateExamAttemptMutation, useStartExamMutation, useLazyGetExamInfoQuery, useGetAgentSkillResourcesQuery, useCreateAgentSkillResourceMutation, useUpdateAgentSkillResourceMutation, useUploadAgentSkillResourceAssetMutation, useDeleteAgentSkillResourceMutation, useGetAgentSkillsQuery, useGetMentorSkillAssignmentsQuery, useCreateMentorSkillAssignmentMutation, useUpdateMentorSkillAssignmentMutation, useDeleteMentorSkillAssignmentMutation, useCreateAgentSkillMutation, useUpdateAgentSkillMutation, useDeleteAgentSkillMutation, resolveEffectiveAgentSkills, filterSlashSkills, useGetMentorSkillAssignmentsInfiniteQuery, MENTOR_SKILL_ASSIGNMENTS_PAGE_SIZE, useUpdateUserProjectMutation, useGetTrainingDocumentsQuery, useGetVectorDocumentsQuery, useGetMentorMemoriesListQuery, useGetMemoryCategoriesAdminQuery, useDeleteMentorMemoryMutation, useUpdateMentorMemoryMutation, useCreateMentorMemoryMutation, useLazyGetConnectedServiceAuthUrlQuery, useCreateUserProjectMutation, useDeleteUserProjectMutation, useGetUserProjectDetailsQuery, useEditTrainingDocumentMutation, useAddTrainingDocumentMutation, useLazyGetCredentialsQuery, useGetMentorSettingsQuery, useEditMentorMutation, useUploadLightLogoMutation, useUploadDarkLogoMutation, useUpdatePlatformInfoMutation, LOGO_ENDPOINTS, useCreateEvalDatasetMutation, useAddEvalDatasetItemsMutation, useUploadEvalDatasetCsvMutation, useDeleteEvalDatasetItemMutation, useListEvalDatasetItemsQuery, evalTotalPages, useListEvalDatasetsQuery, useGetUserProjectsQuery, useCreateSessionIdMutation, useGetMentorCategoriesQuery, useGetTenantChatPrivacyConfigQuery as useGetTenantChatPrivacyConfigQuery$1, useGetCallConfigurationsQuery, useCreateCallConfigurationMutation, useUpdateCallConfigurationMutation, chatPrivacyApiSlice, useDeleteMentorMutation, useForkMentorMutation, useGetToolsQuery, useLazyGetMCPServersQuery, useOauthFindMutation, useLazyStartOAuthFlowQuery, useCreateMCPServerMutation, usePartialUpdateMCPServerMutation, useCreateMCPServerConnectionMutation, usePatchMCPServerConnectionMutation, useGetConnectedServicesQuery, useGetMCPServersQuery, useGetMCPServerConnectionsQuery, useUpdateMCPServerMutation, useDeleteMCPServerMutation, useEditMentorJsonMutation, useDisconnectServiceMutation, useGetPromptCategoriesQuery, PRIVACY_ACTIONS, PRIVACY_ENTITY_TYPES, useGetVoicesQuery, useGetVoiceQuery, isBaseAgentMentor, useGetGradeResultQuery, useOverrideGradeResultMutation, useGetChatHistoryFilterQuery, useListGradeResultsQuery, useGetMentorGraderConfigurationQuery, useListGraderCriteriaQuery, useCreateMentorGraderConfigurationMutation, useUpdateMentorGraderConfigurationMutation, useCreateGraderCriterionMutation, useUpdateGraderCriterionMutation, useDeleteGraderCriterionMutation, useGetMentorPublicSettingsQuery, useGetChatHistoryQuery, useGetMentorSummariesQuery, useGetConversationMemoriesQuery, useGetSupportTicketsQuery, useGetSupportTicketMessagesQuery, useCreateSupportTicketMessageMutation, usePatchSupportTicketMutation, useCloseSupportTicketMutation, useCreateLtiMentorMutation, useUpdateLtiMentorMutation, useGetLtiMentorsQuery, useCreateLtiKeyMutation, useUpdateLtiKeyMutation, useDeleteLtiKeyMutation, useGetLtiKeysQuery, useCreateLtiToolMutation, useUpdateLtiToolMutation, useGetLtiToolsQuery, useGetPlatformInfoQuery, useCreatePromptMutation, useGetPromptsSearchQuery, useUpdatePromptMutation, useCreateRedirectTokenMutation, useGetShareableLinkQuery, useCreateShareableLinkMutation, useUpdateShareableLinkMutation, useCreateDisclaimerMutation, useUpdateDisclaimerMutation, useGetDisclaimersQuery, useUpdateRbacMentorAccessMutation, useGetRbacMentorAccessListQuery, useStartEvalRunMutation, useEvaluateEvalRunMutation, useGetEvalRunQuery, useDeleteEvalScoreMutation, useListEvalRunJudgesQuery, useCreateEvalScoreMutation, useDeleteEvalRunMutation, useExportEvalRunMutation, useListEvalRunsQuery, useLazyGetEvalRunQuery, evaluationsApiSlice, EVALUATIONS_TAGS, useGetPersonnalizedMentorsQuery, useCreateCallCredentialsMutation, useGetGuidedPromptsQuery, useUpdateChatSessionSharedMutation, useUpdateMessageFeedbackMutation, useLazyGetPromptsSearchQuery, useLazyGetGuidedPromptsQuery, useGetPublicMentorsQuery, useGetPeriodicAgentsQuery, useGetPeriodicAgentLogsListQuery, useCreatePeriodicAgentMutation, useDeletePeriodicAgentMutation, useDeletePromptMutation, useDeleteTrainingDocumentMutation, useGetTrainingDocumentRetrainScheduleQuery, useCreateTrainingDocumentRetrainScheduleMutation, useCreateMemoryCategoryMutation, useUpdateMemoryCategoryMutation, useDeleteMemoryCategoryMutation, useUpdateArtifactMutation, useLazyGetArtifactVersionQuery, useLazyListArtifactVersionsQuery, useSetCurrentVersionMutation, useListArtifactVersionsQuery, useLazyGetArtifactQuery, useLazyListArtifactsQuery, useEditSessionMutation } from '@iblai/data-layer';
|
|
5
|
+
import { useGetUserMetadataQuery, useGetUserMetadataEdxQuery, useUpdateUserMetadataMutation, useUpdateUserMetadataEdxMutation, useUploadProfileImageMutation, useResetPasswordMutation, useSelfRetireMutation, useCreateUserInstitutionMutation, useGetUserInstitutionsQuery, useCreateUserEducationMutation, useUpdateUserEducationMutation, useDeleteUserEducationMutation, useGetUserEducationQuery, useCreateUserCompanyMutation, useGetUserCompaniesQuery, useCreateUserExperienceMutation, useUpdateUserExperienceMutation, useDeleteUserExperienceMutation, useGetUserExperienceQuery, useGetUserResumeQuery, useCreateUserResumeMutation, useGetMySubscriptionsQuery, useGetItemSubscriptionQuery, useCancelSubscriptionMutation, useGetLearnerDetailsQuery, useGetUserEnrolledCoursesQuery, useGetUserEnrolledProgramsQuery, useGetUserCatalogPathwaysQuery, useGetUsersAsAssertionsQuery, useGetUserEarnedSkillsQuery, useGetUserReportedSkillsQuery, useGetUserDesiredSkillsQuery, useCreateGlobalMemoryMutation, useGetMemsearchStatusQuery, useGetUserMemorySettingsQuery, useUpdateUserMemorySettingsMutation, useGetGlobalMemoriesQuery, useGetAllMentorMemoriesQuery, useDeleteGlobalMemoryMutation, useInviteUserMutation, usePlatformInvitationsQuery, useCreateCatalogInvitationCourseBulkMutation, useGetCatalogInvitationsCourseQuery, useLazyPlatformUsersQuery, useLazyPlatformUserGroupsQuery, useGetPersonnalizedSearchQuery, useCreateCatalogInvitationProgramBulkMutation, useGetCatalogInvitationsProgramQuery, useUpdateUserRoleMutation, useUpdateUserStatusMutation, useUpdatePlatformUserRoleWithPoliciesMutation, usePlatformUsersQuery, useGetAccessibleUsersQuery, isPoliciesResponse, platformApiSlice, featureTags, useLazyGetRbacTeamsAccessListQuery, useCreateRbacTeamsAccessMutation, useGetRbacGroupsQuery, usePlatformUserGroupsQuery, useCreateRbacGroupMutation, useUpdateRbacGroupMutation, useDeleteRbacGroupMutation, useCreatePlatformUserGroupMutation, useUpdatePlatformUserGroupMutation, useDeletePlatformUserGroupMutation, useGetRbacGroupDetailsQuery, useGetPlatformUserGroupDetailsQuery, useGetRbacPermissionsMutation, useGetRbacRolesQuery, useCreateRbacRoleMutation, useUpdateRbacRoleMutation, useDeleteRbacRoleMutation, useGetRbacRoleDetailsQuery, useGetRbacActionsDefinitionQuery, useGetRbacResourceDiscoveryQuery, useGetRbacResourceListQuery, useGetRbacPoliciesQuery, useCreateRbacPolicyMutation, useUpdateRbacPolicyMutation, useDeleteRbacPolicyMutation, useGetRbacPolicyDetailsQuery, useGetWatchedGroupsQuery, useCreateWatchedGroupMutation, useUpdateWatchedGroupMutation, useDeleteWatchedGroupMutation, useAddWatchedUserMutation, useRemoveWatchedUserMutation, useAddWatcherMutation, useUpdateWatcherMutation, useDeleteWatcherMutation, useGetWatchedUsersQuery, useGetWatchersQuery, WATCHER_NOTIFICATION_EVENTS, WATCHER_NOTIFICATION_EVENT_LABELS, useGetApplicationFormsQuery, useGetApplicationFormDetailQuery, useCreateApplicationFormMutation, useUpdateApplicationFormMutation, useGetApplicationAdminDetailQuery, useInviteApplicationCandidateMutation, useLazyGetApplicationAttachmentFileQuery, useCreateApplicationWaiverMutation, useDeleteApplicationWaiverMutation, useSubmitApplicationOverrideMutation, useUpdateApplicationPlacementMutation, useDeleteApplicationCourseAssignmentMutation, useCreateApplicationNoteMutation, useUpdateApplicationNoteMutation, useDeleteApplicationNoteMutation, useTransitionApplicationMutation, useLinkApplicationCandidateMutation, useCreateApplicationPlacementsMutation, useGetCustomMentorsQuery, useCreateApplicationCourseAssignmentsMutation, useGetApplicationBlocksQuery, useDeleteApplicationBlockMutation, useGetApplicationsPipelineStatsQuery, useGetApplicationsPipelineQuery, useDeleteApiKeyMutation, useGetApiKeyQuery, useGetApiKeyFieldPermissionsQuery, useUpdateApiKeyMutation, useGetApiKeysQuery, unwrapApiTokenList, useCreateApiKeyMutation, useCreateLLMCredentialMutation, useGetCredentialsSchemaQuery, useGetMaskedLLMCredentialsQuery, useGetLlmsQuery, useDeleteIntegrationCredentialMutation, useDeleteCredentialMutation, useCreateIntegrationCredentialMutation, useGetIntegrationCredentialsSchemaQuery, useGetMaskedIntegrationCredentialsQuery, useGetAccountBillingInfoQuery, useUpdateAutoRechargeInfoMutation, useTriggerAutoRechargeMutation, useGetAgentSpendCapQuery, useGetTenantSpendCapQuery, useListAgentUserSpendCapsQuery, useUpsertAgentSpendCapMutation, useDeleteAgentSpendCapMutation, useUpsertTenantSpendCapMutation, useDeleteTenantSpendCapMutation, useUpsertUserSpendCapMutation, useDeleteUserSpendCapMutation, useGetFinancialStatsQuery, useGetMentorsQuery, useListAgentSpendCapsQuery, useGetCreditTransactionsQuery, useCreateStripeCustomerPortalMutation, useSetPlatformConfigurationsMutation, useGetPlatformConfigurationsQuery, useUpdatePlatformMembershipMutation, useGetPlatformMembershipQuery, useGetCustomDomainsQuery, useCreateCustomDomainMutation, useDeleteCustomDomainMutation, useGetStudentMentorCreationStatusQuery, useSetStudentMentorCreationStatusMutation, coreApiSlice, recommendationPromptTypeEnum, useGetRecommendedPromptsListQuery, useCreateRecommendedPromptMutation, useUpdateRecommendedPromptMutation, useDeleteRecommendedPromptMutation, useLazyGetPublicPlatformImageAssetFileUrlQuery, useUpdateTenantMetadataMutation, useCreatePlatformImageAssetMutation, useGetProviderConfigQuery, useCreateProviderConfigMutation, useDeleteProviderConfigMutation, useGetExternalMappingQuery, useGetCredentialsListQuery, useCreateExternalMappingMutation, useDeleteExternalMappingMutation, useGetMemsearchConfigQuery, useUpdateMemsearchConfigMutation, useGetStripeConnectStatusQuery, useStartStripeConnectOnboardingMutation, useLazyGetStripeConnectDashboardQuery, useGetAiSearchMentorsQuery, useListPaywallsQuery, useListPricesQuery, useCreatePriceMutation, useUpdatePriceMutation, useDeletePriceMutation, useGetPaywallConfigQuery, useEnablePaywallMutation, useUpdatePaywallMutation, useStarMentorMutation, useUnstarMentorMutation, useLazyGetCourseMetaDataQuery, useLazyGetCourseCompletionOutlinesQuery, useLazyGetCourseEligibilityQuery, useLazyGetEdxSSOTokenQuery, useCreateCourseEnrollmentMutation, useCreateStripeCheckoutSessionMutation, useLazyGetCourseProgressQuery, useLazyGetCourseCompletionQuery, useUpdateExamAttemptMutation, useStartExamMutation, useLazyGetExamInfoQuery, useGetAgentSkillResourcesQuery, useCreateAgentSkillResourceMutation, useUpdateAgentSkillResourceMutation, useUploadAgentSkillResourceAssetMutation, useDeleteAgentSkillResourceMutation, useGetMentorSkillAssignmentsQuery, useGetAgentSkillsQuery, useCreateMentorSkillAssignmentMutation, useUpdateMentorSkillAssignmentMutation, useDeleteMentorSkillAssignmentMutation, useCreateAgentSkillMutation, useUpdateAgentSkillMutation, useDeleteAgentSkillMutation, filterSlashSkills, useGetMentorSkillAssignmentsInfiniteQuery, MENTOR_SKILL_ASSIGNMENTS_PAGE_SIZE, useUpdateUserProjectMutation, useGetTrainingDocumentsQuery, useGetVectorDocumentsQuery, useGetMentorMemoriesListQuery, useGetMemoryCategoriesAdminQuery, useDeleteMentorMemoryMutation, useUpdateMentorMemoryMutation, useCreateMentorMemoryMutation, useLazyGetConnectedServiceAuthUrlQuery, useCreateUserProjectMutation, useDeleteUserProjectMutation, useGetUserProjectDetailsQuery, useEditTrainingDocumentMutation, useAddTrainingDocumentMutation, useLazyGetCredentialsQuery, useGetMentorSettingsQuery, useEditMentorMutation, useUploadLightLogoMutation, useUploadDarkLogoMutation, useUpdatePlatformInfoMutation, LOGO_ENDPOINTS, useCreateEvalDatasetMutation, useAddEvalDatasetItemsMutation, useUploadEvalDatasetCsvMutation, useDeleteEvalDatasetItemMutation, useListEvalDatasetItemsQuery, evalTotalPages, useListEvalDatasetsQuery, useGetUserProjectsQuery, useCreateSessionIdMutation, useGetMentorCategoriesQuery, useGetTenantChatPrivacyConfigQuery as useGetTenantChatPrivacyConfigQuery$1, useGetCallConfigurationsQuery, useCreateCallConfigurationMutation, useUpdateCallConfigurationMutation, chatPrivacyApiSlice, useDeleteMentorMutation, useForkMentorMutation, useGetToolsQuery, useLazyGetMCPServersQuery, useOauthFindMutation, useLazyStartOAuthFlowQuery, useCreateMCPServerMutation, usePartialUpdateMCPServerMutation, useCreateMCPServerConnectionMutation, usePatchMCPServerConnectionMutation, useGetConnectedServicesQuery, useGetMCPServersQuery, useGetMCPServerConnectionsQuery, useUpdateMCPServerMutation, useDeleteMCPServerMutation, useEditMentorJsonMutation, useDisconnectServiceMutation, useGetPromptCategoriesQuery, PRIVACY_ACTIONS, PRIVACY_ENTITY_TYPES, useGetVoicesQuery, useGetVoiceQuery, isBaseAgentMentor, useGetGradeResultQuery, useOverrideGradeResultMutation, useGetChatHistoryFilterQuery, useListGradeResultsQuery, useGetMentorGraderConfigurationQuery, useListGraderCriteriaQuery, useCreateMentorGraderConfigurationMutation, useUpdateMentorGraderConfigurationMutation, useCreateGraderCriterionMutation, useUpdateGraderCriterionMutation, useDeleteGraderCriterionMutation, useGetSpendCapStatusQuery, useGetMentorPublicSettingsQuery, useGetChatHistoryQuery, useGetMentorSummariesQuery, useGetConversationMemoriesQuery, useGetSupportTicketsQuery, useGetSupportTicketMessagesQuery, useCreateSupportTicketMessageMutation, usePatchSupportTicketMutation, useCloseSupportTicketMutation, useCreateLtiMentorMutation, useUpdateLtiMentorMutation, useGetLtiMentorsQuery, useCreateLtiKeyMutation, useUpdateLtiKeyMutation, useDeleteLtiKeyMutation, useGetLtiKeysQuery, useCreateLtiToolMutation, useUpdateLtiToolMutation, useGetLtiToolsQuery, useGetPlatformInfoQuery, useCreatePromptMutation, useGetPromptsSearchQuery, useUpdatePromptMutation, useCreateRedirectTokenMutation, useGetShareableLinkQuery, useCreateShareableLinkMutation, useUpdateShareableLinkMutation, useCreateDisclaimerMutation, useUpdateDisclaimerMutation, useGetDisclaimersQuery, useUpdateRbacMentorAccessMutation, useGetRbacMentorAccessListQuery, useStartEvalRunMutation, useEvaluateEvalRunMutation, useGetEvalRunQuery, useDeleteEvalScoreMutation, useListEvalRunJudgesQuery, useCreateEvalScoreMutation, useDeleteEvalRunMutation, useExportEvalRunMutation, useListEvalRunsQuery, useLazyGetEvalRunQuery, evaluationsApiSlice, EVALUATIONS_TAGS, useGetPersonnalizedMentorsQuery, useCreateCallCredentialsMutation, useGetGuidedPromptsQuery, useUpdateChatSessionSharedMutation, useUpdateMessageFeedbackMutation, useLazyGetPromptsSearchQuery, useLazyGetGuidedPromptsQuery, useGetPublicMentorsQuery, useGetPeriodicAgentsQuery, useGetPeriodicAgentLogsListQuery, useCreatePeriodicAgentMutation, useDeletePeriodicAgentMutation, useDeletePromptMutation, useDeleteTrainingDocumentMutation, useGetTrainingDocumentRetrainScheduleQuery, useCreateTrainingDocumentRetrainScheduleMutation, useCreateMemoryCategoryMutation, useUpdateMemoryCategoryMutation, useDeleteMemoryCategoryMutation, useUpdateArtifactMutation, useLazyGetArtifactVersionQuery, useLazyListArtifactVersionsQuery, useSetCurrentVersionMutation, useListArtifactVersionsQuery, useLazyGetArtifactQuery, useLazyListArtifactsQuery, useEditSessionMutation } from '@iblai/data-layer';
|
|
6
6
|
import { getInitials, useTenantMetadata, useCurrentTenant, selectRbacPermissions, isPureWatcher, WithPermissions, canWriteField, useStripeUpgrade, openExternalUrl, CHAT_AREA_SIZE, isAlphaNumeric32, checkRbacPermission, selectNumberOfActiveChatMessages, useUsername, selectStreaming, isLoggedIn, TOOLS, hasRemoteAiConfig, isSafariBrowser, useShowAttachment, useShowVoiceCall, useShowVoiceRecorder, useMentorSettings, selectShowingSharedChat, useShowFreeTrialDialog, useEmbedMode, chatInputSliceSelectors, useResponsive, useAccessingPublicRoute, useVisitingTenant, useModelFileUploadCapabilities, useChatFileUpload, useVoiceChat, selectAttachedFiles, MENTOR_CHAT_DOCUMENTS_EXTENSIONS, removeFile, chatInputSliceActions, chatActions, WithFormPermissions, useTenantContext, TimeTracker, advancedTabsProperties, defaultSessionIds, pickWritableFields, ANONYMOUS_USERNAME as ANONYMOUS_USERNAME$3, redirectToAuthSpaJoinTenant, selectActiveTab, useAxdToken, useWelcomeMessage, markdownToPlainText, useCachedSessionId, use402ErrorCheck, selectTokenEnabled, selectToken, useServiceWorker, useUserAgreement, useAdvancedChat, sendMessageToParentWebsite, useMentorTools, useFileDragDrop, eventBus, RemoteEvents, selectEnableChatActionsPopup, advancedTabs, isInIframe, getAuthSpaJoinUrl, addMessage, clearFiles, MENTOR_VISIBILITY } from '@iblai/web-utils';
|
|
7
7
|
import { useDispatch, useSelector } from 'react-redux';
|
|
8
8
|
import { toast } from 'sonner';
|
|
@@ -98333,7 +98333,13 @@ var chatIndex$3 = {
|
|
|
98333
98333
|
confirmScreenShareTitle: "Confirm Screen Sharing",
|
|
98334
98334
|
confirmScreenShareDescription: "Would you like to start a screen sharing with your agent?",
|
|
98335
98335
|
cancel: "Cancel",
|
|
98336
|
-
confirm: "Confirm"
|
|
98336
|
+
confirm: "Confirm",
|
|
98337
|
+
spendCapLimitDay: "You've reached today's usage limit for this assistant.",
|
|
98338
|
+
spendCapLimitWeek: "You've reached this week's usage limit for this assistant.",
|
|
98339
|
+
spendCapLimitMonth: "You've reached this month's usage limit for this assistant.",
|
|
98340
|
+
spendCapLimitYear: "You've reached this year's usage limit for this assistant.",
|
|
98341
|
+
spendCapLimitGeneric: "You've reached the usage limit for this assistant.",
|
|
98342
|
+
spendCapContactAdmin: "Please try again after the limit resets, or contact your administrator."
|
|
98337
98343
|
};
|
|
98338
98344
|
var chatInputForm$3 = {
|
|
98339
98345
|
uploadingOneFile: "Uploading 1 file...",
|
|
@@ -98536,6 +98542,8 @@ var clawSandboxAgentSkills$3 = {
|
|
|
98536
98542
|
fieldCategoryPlaceholder: "e.g. web, code, data",
|
|
98537
98543
|
privateToAgent: "Only This Agent",
|
|
98538
98544
|
privateToAgentHint: "Private skills are available to this agent only and take precedence over platform skills with the same slug.",
|
|
98545
|
+
privateToOtherAgentHint: "This skill is private to another agent, so this setting cannot be changed here.",
|
|
98546
|
+
privateToOtherAgentTooltip: "This skill is private to another agent and cannot be added here.",
|
|
98539
98547
|
instructionHint: "The playbook the agent follows when the skill is used. Edits apply immediately, including in conversations already in progress.",
|
|
98540
98548
|
filesHint: "Optional resources the agent can use with this skill. References and scripts are text files; assets are uploaded files.",
|
|
98541
98549
|
filesAfterCreateHint: "You can attach resources to this skill after creating it (reopen it with Edit).",
|
|
@@ -98775,6 +98783,92 @@ var componentsProactiveSettingsSection$3 = {
|
|
|
98775
98783
|
editAgentPromptAriaLabel: "Edit agent prompt",
|
|
98776
98784
|
periodicAgentsHelp: "Optional. Select agents to include in the proactive outreach rotation."
|
|
98777
98785
|
};
|
|
98786
|
+
var componentsTemplateActionsSection$3 = {
|
|
98787
|
+
title: "Test & Reset",
|
|
98788
|
+
description: "Preview the template in your inbox, or discard this platform's customizations.",
|
|
98789
|
+
testEmailLabel: "Send a test email",
|
|
98790
|
+
testEmailHelper: "Sends one rendering of this template to the address you enter.",
|
|
98791
|
+
testEmailPlaceholder: "you@example.com",
|
|
98792
|
+
sendTest: "Send test email",
|
|
98793
|
+
sendingTest: "Sending...",
|
|
98794
|
+
testSuccessTitle: "Test email sent",
|
|
98795
|
+
testSuccessDescription: "Sent to {email}.",
|
|
98796
|
+
testErrorTitle: "Could not send test email",
|
|
98797
|
+
testErrorDescription: "Please check the address and try again.",
|
|
98798
|
+
resetLabel: "Reset to default",
|
|
98799
|
+
resetHelper: "Discards this platform's copy and restores the default template.",
|
|
98800
|
+
reset: "Reset to default",
|
|
98801
|
+
resetting: "Resetting...",
|
|
98802
|
+
resetConfirmTitle: "Reset this template?",
|
|
98803
|
+
resetConfirmDescription: "This platform's customizations will be discarded and the default template restored. This cannot be undone.",
|
|
98804
|
+
resetConfirmCancel: "Cancel",
|
|
98805
|
+
resetConfirmAction: "Reset template",
|
|
98806
|
+
resetSuccessTitle: "Template reset",
|
|
98807
|
+
resetSuccessDescription: "The platform default has been restored.",
|
|
98808
|
+
resetErrorTitle: "Could not reset template",
|
|
98809
|
+
resetErrorDescription: "Please try again."
|
|
98810
|
+
};
|
|
98811
|
+
var componentsTemplateVariablesHelper$3 = {
|
|
98812
|
+
title: "Variables you can use",
|
|
98813
|
+
copyHint: "Click a variable to copy it, then paste it into the subject or body.",
|
|
98814
|
+
insertHint: "Click a variable to insert it.",
|
|
98815
|
+
copiedToast: "Copied {token} to your clipboard.",
|
|
98816
|
+
copyUnavailableToast: "Copy {token} manually — clipboard access is unavailable.",
|
|
98817
|
+
copyAriaLabel: "Copy the {name} variable",
|
|
98818
|
+
insertAriaLabel: "Insert the {name} variable"
|
|
98819
|
+
};
|
|
98820
|
+
var componentsUserProgressSettingsSection$3 = {
|
|
98821
|
+
scheduleTitle: "Schedule & Reporting Period",
|
|
98822
|
+
scheduleDescription: "Choose how often the summary is sent and how far back it looks.",
|
|
98823
|
+
frequencyLabel: "Frequency",
|
|
98824
|
+
selectFrequencyAriaLabel: "Select frequency",
|
|
98825
|
+
selectFrequencyPlaceholder: "Select frequency",
|
|
98826
|
+
daily: "Daily",
|
|
98827
|
+
weekly: "Weekly",
|
|
98828
|
+
monthly: "Monthly",
|
|
98829
|
+
custom: "Custom",
|
|
98830
|
+
cadenceDaily: "Sends every day at the time below.",
|
|
98831
|
+
cadenceWeekly: "Sends every Monday at the time below.",
|
|
98832
|
+
cadenceMonthly: "Sends on the 1st of each month at the time below.",
|
|
98833
|
+
cadenceCustom: "Sends every {days} days at the time below.",
|
|
98834
|
+
cadenceCustomUnset: "Set a custom interval to choose how often the summary is sent.",
|
|
98835
|
+
executionTimeLabel: "Send Time",
|
|
98836
|
+
executionTimeRequired: "Specify the time the summary should be sent.",
|
|
98837
|
+
timezoneLabel: "Timezone",
|
|
98838
|
+
selectTimezoneAriaLabel: "Select timezone",
|
|
98839
|
+
selectTimezonePlaceholder: "Select timezone",
|
|
98840
|
+
useLocalTimezone: "Use local timezone ({timezone})",
|
|
98841
|
+
customIntervalLabel: "Custom Interval (days)",
|
|
98842
|
+
customIntervalRequired: "Set how many days should pass between sends.",
|
|
98843
|
+
dayRangeError: "Enter a whole number of days between 1 and 365.",
|
|
98844
|
+
lookbackLabel: "Reporting Window (days)",
|
|
98845
|
+
lookbackHelp: "How far back each summary looks. This is separate from how often the email is sent — a weekly email can still report on the last 30 days.",
|
|
98846
|
+
lookbackRequired: "Set the reporting window in days.",
|
|
98847
|
+
dataPointsLabel: "Included Data Points",
|
|
98848
|
+
dataPointsHelp: "The email only shows sections that are enabled and have data for that learner.",
|
|
98849
|
+
dataPointCoursesProgressed: "Courses progressed",
|
|
98850
|
+
dataPointCoursesCompleted: "Courses completed",
|
|
98851
|
+
dataPointCredentialsEarned: "Credentials earned",
|
|
98852
|
+
dataPointTimeSpent: "Time spent",
|
|
98853
|
+
dataPointActiveDays: "Active days",
|
|
98854
|
+
dataPointMentorsAccessed: "AI agent activity",
|
|
98855
|
+
noDataPointsWarning: "No data points selected — the summary will have no content to show."
|
|
98856
|
+
};
|
|
98857
|
+
var componentsWatcherEmailSection$3 = {
|
|
98858
|
+
title: "Watcher Email",
|
|
98859
|
+
description: "Sent to a learner's watchers, such as a parent or manager.",
|
|
98860
|
+
fallbackNotice: "Watchers currently receive the learner email. Customize it to send them a different message.",
|
|
98861
|
+
customize: "Customize watcher email",
|
|
98862
|
+
useLearnerEmail: "Use the learner email",
|
|
98863
|
+
subjectLabel: "Watcher Email Subject",
|
|
98864
|
+
subjectHelper: "Supports the same variables as the learner email, plus learner_name.",
|
|
98865
|
+
subjectFallbackHelper: "Leave empty and watchers receive the learner email subject.",
|
|
98866
|
+
subjectPlaceholder: "Enter the watcher email subject...",
|
|
98867
|
+
bodyLabel: "Watcher Email Body",
|
|
98868
|
+
bodyHelper: "Supports the same variables as the learner email, plus learner_name.",
|
|
98869
|
+
bodyFallbackHelper: "Leave empty and watchers receive the learner email body.",
|
|
98870
|
+
bodyPlaceholder: "Enter the watcher email body..."
|
|
98871
|
+
};
|
|
98778
98872
|
var courseContentAccessiblePaginate$3 = {
|
|
98779
98873
|
pagination: "Pagination"
|
|
98780
98874
|
};
|
|
@@ -99977,7 +100071,14 @@ var notificationsEditAlertDialog$3 = {
|
|
|
99977
100071
|
toastErrorDescription: "Failed to update template. Please try again.",
|
|
99978
100072
|
cancel: "Cancel",
|
|
99979
100073
|
saving: "Saving...",
|
|
99980
|
-
saveChanges: "Save Changes"
|
|
100074
|
+
saveChanges: "Save Changes",
|
|
100075
|
+
learnerEmailSubjectLabel: "Learner Email Subject",
|
|
100076
|
+
learnerEmailSubjectHelper: "Required. Supports template variables — see the list below the body.",
|
|
100077
|
+
learnerEmailBodyLabel: "Learner Email Body",
|
|
100078
|
+
learnerEmailBodyHelper: "Required. Greet with \"Hey,\" rather than a username — usernames are often auto-generated.",
|
|
100079
|
+
noChangesToast: "No changes to save.",
|
|
100080
|
+
toastValidationTitle: "Check the highlighted fields",
|
|
100081
|
+
toastValidationDescription: "Some values were rejected. Review the fields marked in red."
|
|
99981
100082
|
};
|
|
99982
100083
|
var notificationsNotificationDisplay$3 = {
|
|
99983
100084
|
notificationsAriaLabel: "Notifications",
|
|
@@ -100260,7 +100361,8 @@ var profileBilling$3 = {
|
|
|
100260
100361
|
addCredits: "Add Credits",
|
|
100261
100362
|
manageBilling: "Manage Billing",
|
|
100262
100363
|
availableLabel: "Available",
|
|
100263
|
-
|
|
100364
|
+
creditsUsdEquivalent: "≈ {amount}",
|
|
100365
|
+
creditsConversionHint: "{credits} credits = $1",
|
|
100264
100366
|
creditsUnit: "{amount} Credits",
|
|
100265
100367
|
consumedLabel: "Consumed",
|
|
100266
100368
|
usedThisPeriod: "Used this period",
|
|
@@ -100272,10 +100374,17 @@ var profileBilling$3 = {
|
|
|
100272
100374
|
disabled: "Disabled",
|
|
100273
100375
|
manageUsage: "Manage Usage",
|
|
100274
100376
|
thresholdLabel: "Threshold",
|
|
100377
|
+
thresholdHint: "When your available credits fall below this amount, a top-up starts automatically",
|
|
100275
100378
|
rechargeAmountLabel: "Recharge amount",
|
|
100379
|
+
rechargeAmountHint: "Charged to your payment method and added to your credits with each top-up",
|
|
100276
100380
|
spendingLimitLabel: "Spending limit",
|
|
100381
|
+
spendingLimitHint: "The most auto recharge can charge per billing period",
|
|
100277
100382
|
unlimited: "Unlimited",
|
|
100278
|
-
autoRechargeDisabledMessage: "Auto recharge is currently disabled. Enable it to keep your balance topped up without interruption."
|
|
100383
|
+
autoRechargeDisabledMessage: "Auto recharge is currently disabled. Enable it to keep your balance topped up without interruption.",
|
|
100384
|
+
billingTabsAriaLabel: "Billing sections",
|
|
100385
|
+
tabPlanAndCredits: "Plan & Credits",
|
|
100386
|
+
tabSpendLimits: "Spend Limits",
|
|
100387
|
+
tabAgentLimits: "Agent Limits"
|
|
100279
100388
|
};
|
|
100280
100389
|
var profileCatalogInviteModal$3 = {
|
|
100281
100390
|
title: "Catalog Invite",
|
|
@@ -101219,6 +101328,156 @@ var skillsProfileSkillsBox$3 = {
|
|
|
101219
101328
|
desired: "Desired",
|
|
101220
101329
|
noDesiredSkills: "You don't have any desired skills yet."
|
|
101221
101330
|
};
|
|
101331
|
+
var spendCapUsage$3 = {
|
|
101332
|
+
scopeTenant: "Workspace",
|
|
101333
|
+
scopeAgent: "This agent",
|
|
101334
|
+
scopeUserAgent: "Your usage on this agent",
|
|
101335
|
+
intervalDay: "today",
|
|
101336
|
+
intervalWeek: "this week",
|
|
101337
|
+
intervalMonth: "this month",
|
|
101338
|
+
intervalYear: "this year",
|
|
101339
|
+
percentUsed: "{percent}% used",
|
|
101340
|
+
blockedBanner: "The usage limit has been reached. New chats and training are paused until the period resets.",
|
|
101341
|
+
warningBanner: "Usage is nearing its limit."
|
|
101342
|
+
};
|
|
101343
|
+
var spendCapsTabLabels$3 = {
|
|
101344
|
+
header: {
|
|
101345
|
+
title: "Billing",
|
|
101346
|
+
description: "Set spend limits for this agent and its users, and see how much has been used."
|
|
101347
|
+
},
|
|
101348
|
+
capability: {
|
|
101349
|
+
title: "Spend Limit",
|
|
101350
|
+
description: "Put a ceiling on AI spend. While this limit is on, everything it covers counts toward the amount below — and when the limit is reached, you choose whether new requests are blocked or admins are simply alerted.",
|
|
101351
|
+
offHint: "Turn it on to start tracking and enforcing this limit. Your setup here is kept safe if you later turn it off."
|
|
101352
|
+
},
|
|
101353
|
+
subTabs: {
|
|
101354
|
+
agent: "This Agent",
|
|
101355
|
+
users: "Per User"
|
|
101356
|
+
},
|
|
101357
|
+
tenantSections: {
|
|
101358
|
+
workspace: {
|
|
101359
|
+
title: "Workspace Spend Limit",
|
|
101360
|
+
description: "One limit covering everything all agents and users spend in this workspace. Per-agent and per-user limits live in each agent’s settings under Billing."
|
|
101361
|
+
},
|
|
101362
|
+
noCapStats: {
|
|
101363
|
+
spentThisMonth: "Spent This Month",
|
|
101364
|
+
spentAllTime: "Spent All Time",
|
|
101365
|
+
hint: "Across all agents and users in this workspace"
|
|
101366
|
+
},
|
|
101367
|
+
agents: {
|
|
101368
|
+
title: "Agent Spend Limits",
|
|
101369
|
+
description: "Agents with a spend limit configured in this workspace. Open one to manage its limit and its per-user limits.",
|
|
101370
|
+
filter: {
|
|
101371
|
+
label: "Search Agents",
|
|
101372
|
+
placeholder: "Search Agents…",
|
|
101373
|
+
typeToSearch: "Type at least 2 characters to search",
|
|
101374
|
+
searching: "Searching agents…",
|
|
101375
|
+
noResults: "No agents found",
|
|
101376
|
+
clear: "Clear Agent Filter"
|
|
101377
|
+
},
|
|
101378
|
+
table: {
|
|
101379
|
+
agentColumn: "Agent",
|
|
101380
|
+
limitColumn: "Limit",
|
|
101381
|
+
spentColumn: "Spent",
|
|
101382
|
+
remainingColumn: "Remaining",
|
|
101383
|
+
statusColumn: "Status"
|
|
101384
|
+
},
|
|
101385
|
+
emptyState: "No agent spend limits yet. Search for an agent above to set one.",
|
|
101386
|
+
emptyFiltered: "No spend limit for this agent yet.",
|
|
101387
|
+
setLimitButton: "Set Spend Limit",
|
|
101388
|
+
manageAria: "Manage spend limits for {name}",
|
|
101389
|
+
statusToggleAria: "Toggle spend limit for {name}"
|
|
101390
|
+
}
|
|
101391
|
+
},
|
|
101392
|
+
form: {
|
|
101393
|
+
limitLabel: "Spend Limit (USD)",
|
|
101394
|
+
limitPlaceholder: "e.g. 250.00",
|
|
101395
|
+
limitError: "Enter an amount greater than 0",
|
|
101396
|
+
intervalLabel: "Resets Every",
|
|
101397
|
+
intervalOptions: {
|
|
101398
|
+
day: "Day",
|
|
101399
|
+
week: "Week",
|
|
101400
|
+
month: "Month",
|
|
101401
|
+
year: "Year"
|
|
101402
|
+
},
|
|
101403
|
+
enforcementLabel: "When the Limit Is Reached",
|
|
101404
|
+
enforcementOptions: {
|
|
101405
|
+
block: "Block Requests",
|
|
101406
|
+
alertOnly: "Alert Only"
|
|
101407
|
+
},
|
|
101408
|
+
enforcementHelp: {
|
|
101409
|
+
block: "New chat and training requests are refused until the period resets.",
|
|
101410
|
+
alertOnly: "Nothing is blocked — admins are notified when spend nears the limit."
|
|
101411
|
+
},
|
|
101412
|
+
thresholdsLabel: "Alert At (% of Limit)",
|
|
101413
|
+
thresholdsPlaceholder: "e.g. 80, 95",
|
|
101414
|
+
thresholdsHelp: "Comma-separated percentages at which admins get a near-limit alert.",
|
|
101415
|
+
thresholdsError: "Use comma-separated numbers between 1 and 100",
|
|
101416
|
+
noCapHint: "No spend limit configured yet — set an amount and save to create one.",
|
|
101417
|
+
save: "Save",
|
|
101418
|
+
saving: "Saving…",
|
|
101419
|
+
remove: "Delete Limit",
|
|
101420
|
+
removing: "Deleting…",
|
|
101421
|
+
cancel: "Cancel"
|
|
101422
|
+
},
|
|
101423
|
+
usage: {
|
|
101424
|
+
title: "Spend Limit Usage",
|
|
101425
|
+
periodTitles: {
|
|
101426
|
+
day: "Daily Usage",
|
|
101427
|
+
week: "Weekly Usage",
|
|
101428
|
+
month: "Monthly Usage",
|
|
101429
|
+
year: "Yearly Usage"
|
|
101430
|
+
},
|
|
101431
|
+
spent: "Spent: {amount}",
|
|
101432
|
+
remaining: "Remaining: {amount}",
|
|
101433
|
+
percentUsed: "{percent}% of limit used",
|
|
101434
|
+
exceededBadge: "Limit Reached",
|
|
101435
|
+
alertOnlyBadge: "Alert Only",
|
|
101436
|
+
disabledBadge: "Off"
|
|
101437
|
+
},
|
|
101438
|
+
users: {
|
|
101439
|
+
sectionTitle: "Per-User Limits",
|
|
101440
|
+
sectionDescription: "Limit what specific users can spend on this agent.",
|
|
101441
|
+
addButton: "Add User Limit",
|
|
101442
|
+
addTitle: "New User Limit",
|
|
101443
|
+
editTitle: "Edit User Limit",
|
|
101444
|
+
cancel: "Cancel",
|
|
101445
|
+
emptyState: "No per-user limits yet. Add one to limit a specific user on this agent.",
|
|
101446
|
+
edit: "Edit",
|
|
101447
|
+
"delete": "Delete",
|
|
101448
|
+
table: {
|
|
101449
|
+
userColumn: "User",
|
|
101450
|
+
limitColumn: "Limit",
|
|
101451
|
+
statusColumn: "Status"
|
|
101452
|
+
},
|
|
101453
|
+
actionsAria: "Actions for {username}",
|
|
101454
|
+
statusToggleAria: "Toggle spend limit for {username}",
|
|
101455
|
+
picker: {
|
|
101456
|
+
label: "User",
|
|
101457
|
+
placeholder: "Search Users…",
|
|
101458
|
+
typeToSearch: "Type at least 2 characters to search",
|
|
101459
|
+
searching: "Searching users…",
|
|
101460
|
+
noResults: "No users found",
|
|
101461
|
+
clear: "Change User"
|
|
101462
|
+
}
|
|
101463
|
+
},
|
|
101464
|
+
denied: {
|
|
101465
|
+
title: "No Access to Spend Limits",
|
|
101466
|
+
description: "You don't have permission to view spend limits here. Ask an administrator for access."
|
|
101467
|
+
},
|
|
101468
|
+
deleteModal: {
|
|
101469
|
+
title: "Delete Spend Limit",
|
|
101470
|
+
description: "Spending will no longer be limited or tracked against this limit.",
|
|
101471
|
+
cancel: "Cancel",
|
|
101472
|
+
confirm: "Delete"
|
|
101473
|
+
},
|
|
101474
|
+
toasts: {
|
|
101475
|
+
saved: "Spend limit saved",
|
|
101476
|
+
saveError: "Couldn't save the spend limit",
|
|
101477
|
+
deleted: "Spend limit deleted",
|
|
101478
|
+
deleteError: "Couldn't delete the spend limit"
|
|
101479
|
+
}
|
|
101480
|
+
};
|
|
101222
101481
|
var tabsAlertstab$3 = {
|
|
101223
101482
|
searchAlertsPlaceholder: "Search alerts",
|
|
101224
101483
|
searchAlertsAriaLabel: "Search alerts",
|
|
@@ -103127,6 +103386,10 @@ var en = {
|
|
|
103127
103386
|
componentsPolicyAssignmentSection: componentsPolicyAssignmentSection$3,
|
|
103128
103387
|
componentsPolicyConfigDialog: componentsPolicyConfigDialog$3,
|
|
103129
103388
|
componentsProactiveSettingsSection: componentsProactiveSettingsSection$3,
|
|
103389
|
+
componentsTemplateActionsSection: componentsTemplateActionsSection$3,
|
|
103390
|
+
componentsTemplateVariablesHelper: componentsTemplateVariablesHelper$3,
|
|
103391
|
+
componentsUserProgressSettingsSection: componentsUserProgressSettingsSection$3,
|
|
103392
|
+
componentsWatcherEmailSection: componentsWatcherEmailSection$3,
|
|
103130
103393
|
courseContentAccessiblePaginate: courseContentAccessiblePaginate$3,
|
|
103131
103394
|
courseContentCourseContentLayout: courseContentCourseContentLayout$3,
|
|
103132
103395
|
courseContentDiscoverFacetsFilter: courseContentDiscoverFacetsFilter$3,
|
|
@@ -103242,6 +103505,8 @@ var en = {
|
|
|
103242
103505
|
skillsProfileResumeBox: skillsProfileResumeBox$3,
|
|
103243
103506
|
skillsProfileSkillDetailModal: skillsProfileSkillDetailModal$3,
|
|
103244
103507
|
skillsProfileSkillsBox: skillsProfileSkillsBox$3,
|
|
103508
|
+
spendCapUsage: spendCapUsage$3,
|
|
103509
|
+
spendCapsTabLabels: spendCapsTabLabels$3,
|
|
103245
103510
|
tabsAlertstab: tabsAlertstab$3,
|
|
103246
103511
|
tabsDisclaimersTab: tabsDisclaimersTab$3,
|
|
103247
103512
|
tabsEmbedTab: tabsEmbedTab$3,
|
|
@@ -104972,7 +105237,13 @@ var chatIndex$2 = {
|
|
|
104972
105237
|
confirmScreenShareTitle: "Confirmer le partage d'écran",
|
|
104973
105238
|
confirmScreenShareDescription: "Souhaitez-vous démarrer un partage d'écran avec votre agent ?",
|
|
104974
105239
|
cancel: "Annuler",
|
|
104975
|
-
confirm: "Confirmer"
|
|
105240
|
+
confirm: "Confirmer",
|
|
105241
|
+
spendCapLimitDay: "Vous avez atteint la limite d'utilisation du jour pour cet assistant.",
|
|
105242
|
+
spendCapLimitWeek: "Vous avez atteint la limite d'utilisation de la semaine pour cet assistant.",
|
|
105243
|
+
spendCapLimitMonth: "Vous avez atteint la limite d'utilisation du mois pour cet assistant.",
|
|
105244
|
+
spendCapLimitYear: "Vous avez atteint la limite d'utilisation de l'année pour cet assistant.",
|
|
105245
|
+
spendCapLimitGeneric: "Vous avez atteint la limite d'utilisation de cet assistant.",
|
|
105246
|
+
spendCapContactAdmin: "Réessayez après la réinitialisation de la limite ou contactez votre administrateur."
|
|
104976
105247
|
};
|
|
104977
105248
|
var chatInputForm$2 = {
|
|
104978
105249
|
uploadingOneFile: "Téléversement de 1 fichier...",
|
|
@@ -105175,6 +105446,8 @@ var clawSandboxAgentSkills$2 = {
|
|
|
105175
105446
|
fieldCategoryPlaceholder: "p. ex. web, code, données",
|
|
105176
105447
|
privateToAgent: "Cet agent uniquement",
|
|
105177
105448
|
privateToAgentHint: "Les compétences privées ne sont disponibles que pour cet agent et priment sur les compétences de la plateforme portant le même slug.",
|
|
105449
|
+
privateToOtherAgentHint: "Cette compétence est privée d'un autre agent, ce réglage ne peut donc pas être modifié ici.",
|
|
105450
|
+
privateToOtherAgentTooltip: "Cette compétence est privée d'un autre agent et ne peut pas être ajoutée ici.",
|
|
105178
105451
|
instructionHint: "Le guide que l'agent suit lorsque la compétence est utilisée. Les modifications s'appliquent immédiatement, y compris dans les conversations en cours.",
|
|
105179
105452
|
filesHint: "Ressources facultatives que l'agent peut utiliser avec cette compétence. Les références et les scripts sont des fichiers texte ; les assets sont des fichiers téléversés.",
|
|
105180
105453
|
filesAfterCreateHint: "Vous pouvez joindre des ressources à cette compétence après sa création (rouvrez-la avec Modifier).",
|
|
@@ -105414,6 +105687,92 @@ var componentsProactiveSettingsSection$2 = {
|
|
|
105414
105687
|
editAgentPromptAriaLabel: "Modifier le prompt de l'agent",
|
|
105415
105688
|
periodicAgentsHelp: "Facultatif. Sélectionnez les agents à inclure dans la rotation de contact proactif."
|
|
105416
105689
|
};
|
|
105690
|
+
var componentsTemplateActionsSection$2 = {
|
|
105691
|
+
title: "Tester et réinitialiser",
|
|
105692
|
+
description: "Prévisualisez le modèle dans votre boîte de réception ou annulez les personnalisations de cette plateforme.",
|
|
105693
|
+
testEmailLabel: "Envoyer un e-mail de test",
|
|
105694
|
+
testEmailHelper: "Envoie un rendu de ce modèle à l'adresse que vous saisissez.",
|
|
105695
|
+
testEmailPlaceholder: "vous@exemple.com",
|
|
105696
|
+
sendTest: "Envoyer l'e-mail de test",
|
|
105697
|
+
sendingTest: "Envoi...",
|
|
105698
|
+
testSuccessTitle: "E-mail de test envoyé",
|
|
105699
|
+
testSuccessDescription: "Envoyé à {email}.",
|
|
105700
|
+
testErrorTitle: "Impossible d'envoyer l'e-mail de test",
|
|
105701
|
+
testErrorDescription: "Vérifiez l'adresse et réessayez.",
|
|
105702
|
+
resetLabel: "Réinitialiser par défaut",
|
|
105703
|
+
resetHelper: "Supprime la copie de cette plateforme et restaure le modèle par défaut.",
|
|
105704
|
+
reset: "Réinitialiser par défaut",
|
|
105705
|
+
resetting: "Réinitialisation...",
|
|
105706
|
+
resetConfirmTitle: "Réinitialiser ce modèle ?",
|
|
105707
|
+
resetConfirmDescription: "Les personnalisations de cette plateforme seront supprimées et le modèle par défaut restauré. Cette action est irréversible.",
|
|
105708
|
+
resetConfirmCancel: "Annuler",
|
|
105709
|
+
resetConfirmAction: "Réinitialiser le modèle",
|
|
105710
|
+
resetSuccessTitle: "Modèle réinitialisé",
|
|
105711
|
+
resetSuccessDescription: "Le modèle par défaut de la plateforme a été restauré.",
|
|
105712
|
+
resetErrorTitle: "Impossible de réinitialiser le modèle",
|
|
105713
|
+
resetErrorDescription: "Veuillez réessayer."
|
|
105714
|
+
};
|
|
105715
|
+
var componentsTemplateVariablesHelper$2 = {
|
|
105716
|
+
title: "Variables disponibles",
|
|
105717
|
+
copyHint: "Cliquez sur une variable pour la copier, puis collez-la dans l’objet ou le corps.",
|
|
105718
|
+
insertHint: "Cliquez sur une variable pour l’insérer.",
|
|
105719
|
+
copiedToast: "{token} copié dans le presse-papiers.",
|
|
105720
|
+
copyUnavailableToast: "Copiez {token} manuellement : le presse-papiers est indisponible.",
|
|
105721
|
+
copyAriaLabel: "Copier la variable {name}",
|
|
105722
|
+
insertAriaLabel: "Insérer la variable {name}"
|
|
105723
|
+
};
|
|
105724
|
+
var componentsUserProgressSettingsSection$2 = {
|
|
105725
|
+
scheduleTitle: "Planification et période de rapport",
|
|
105726
|
+
scheduleDescription: "Choisissez la fréquence d’envoi du résumé et la période qu’il couvre.",
|
|
105727
|
+
frequencyLabel: "Fréquence",
|
|
105728
|
+
selectFrequencyAriaLabel: "Sélectionner la fréquence",
|
|
105729
|
+
selectFrequencyPlaceholder: "Sélectionner la fréquence",
|
|
105730
|
+
daily: "Quotidienne",
|
|
105731
|
+
weekly: "Hebdomadaire",
|
|
105732
|
+
monthly: "Mensuelle",
|
|
105733
|
+
custom: "Personnalisée",
|
|
105734
|
+
cadenceDaily: "Envoyé chaque jour à l’heure indiquée ci-dessous.",
|
|
105735
|
+
cadenceWeekly: "Envoyé chaque lundi à l’heure indiquée ci-dessous.",
|
|
105736
|
+
cadenceMonthly: "Envoyé le 1er de chaque mois à l’heure indiquée ci-dessous.",
|
|
105737
|
+
cadenceCustom: "Envoyé tous les {days} jours à l’heure indiquée ci-dessous.",
|
|
105738
|
+
cadenceCustomUnset: "Définissez un intervalle personnalisé pour choisir la fréquence d’envoi du résumé.",
|
|
105739
|
+
executionTimeLabel: "Heure d’envoi",
|
|
105740
|
+
executionTimeRequired: "Indiquez l’heure à laquelle le résumé doit être envoyé.",
|
|
105741
|
+
timezoneLabel: "Fuseau horaire",
|
|
105742
|
+
selectTimezoneAriaLabel: "Sélectionner le fuseau horaire",
|
|
105743
|
+
selectTimezonePlaceholder: "Sélectionner le fuseau horaire",
|
|
105744
|
+
useLocalTimezone: "Utiliser le fuseau horaire local ({timezone})",
|
|
105745
|
+
customIntervalLabel: "Intervalle personnalisé (jours)",
|
|
105746
|
+
customIntervalRequired: "Indiquez le nombre de jours entre deux envois.",
|
|
105747
|
+
dayRangeError: "Saisissez un nombre entier de jours compris entre 1 et 365.",
|
|
105748
|
+
lookbackLabel: "Période de rapport (jours)",
|
|
105749
|
+
lookbackHelp: "La période couverte par chaque résumé. Elle est indépendante de la fréquence d’envoi : un e-mail hebdomadaire peut couvrir les 30 derniers jours.",
|
|
105750
|
+
lookbackRequired: "Indiquez la période de rapport en jours.",
|
|
105751
|
+
dataPointsLabel: "Données incluses",
|
|
105752
|
+
dataPointsHelp: "L’e-mail n’affiche que les sections activées et pour lesquelles l’apprenant a des données.",
|
|
105753
|
+
dataPointCoursesProgressed: "Cours en progression",
|
|
105754
|
+
dataPointCoursesCompleted: "Cours terminés",
|
|
105755
|
+
dataPointCredentialsEarned: "Certifications obtenues",
|
|
105756
|
+
dataPointTimeSpent: "Temps passé",
|
|
105757
|
+
dataPointActiveDays: "Jours actifs",
|
|
105758
|
+
dataPointMentorsAccessed: "Activité des agents IA",
|
|
105759
|
+
noDataPointsWarning: "Aucune donnée sélectionnée : le résumé n’aura aucun contenu à afficher."
|
|
105760
|
+
};
|
|
105761
|
+
var componentsWatcherEmailSection$2 = {
|
|
105762
|
+
title: "E-mail des observateurs",
|
|
105763
|
+
description: "Envoyé aux observateurs de l’apprenant, par exemple un parent ou un responsable.",
|
|
105764
|
+
fallbackNotice: "Les observateurs reçoivent actuellement l’e-mail de l’apprenant. Personnalisez-le pour leur envoyer un message différent.",
|
|
105765
|
+
customize: "Personnaliser l’e-mail des observateurs",
|
|
105766
|
+
useLearnerEmail: "Utiliser l’e-mail de l’apprenant",
|
|
105767
|
+
subjectLabel: "Objet de l’e-mail des observateurs",
|
|
105768
|
+
subjectHelper: "Prend en charge les mêmes variables que l’e-mail de l’apprenant, plus learner_name.",
|
|
105769
|
+
subjectFallbackHelper: "Laissez vide et les observateurs recevront l’objet de l’e-mail de l’apprenant.",
|
|
105770
|
+
subjectPlaceholder: "Saisissez l’objet de l’e-mail des observateurs...",
|
|
105771
|
+
bodyLabel: "Corps de l’e-mail des observateurs",
|
|
105772
|
+
bodyHelper: "Prend en charge les mêmes variables que l’e-mail de l’apprenant, plus learner_name.",
|
|
105773
|
+
bodyFallbackHelper: "Laissez vide et les observateurs recevront le corps de l’e-mail de l’apprenant.",
|
|
105774
|
+
bodyPlaceholder: "Saisissez le corps de l’e-mail des observateurs..."
|
|
105775
|
+
};
|
|
105417
105776
|
var courseContentAccessiblePaginate$2 = {
|
|
105418
105777
|
pagination: "Pagination"
|
|
105419
105778
|
};
|
|
@@ -106616,7 +106975,14 @@ var notificationsEditAlertDialog$2 = {
|
|
|
106616
106975
|
toastErrorDescription: "Échec de la mise à jour du modèle. Veuillez réessayer.",
|
|
106617
106976
|
cancel: "Annuler",
|
|
106618
106977
|
saving: "Enregistrement...",
|
|
106619
|
-
saveChanges: "Enregistrer les modifications"
|
|
106978
|
+
saveChanges: "Enregistrer les modifications",
|
|
106979
|
+
learnerEmailSubjectLabel: "Objet de l’e-mail de l’apprenant",
|
|
106980
|
+
learnerEmailSubjectHelper: "Obligatoire. Prend en charge les variables de modèle : voir la liste sous le corps.",
|
|
106981
|
+
learnerEmailBodyLabel: "Corps de l’e-mail de l’apprenant",
|
|
106982
|
+
learnerEmailBodyHelper: "Obligatoire. Utilisez « Bonjour, » plutôt que le nom d’utilisateur : ceux-ci sont souvent générés automatiquement.",
|
|
106983
|
+
noChangesToast: "Aucune modification à enregistrer.",
|
|
106984
|
+
toastValidationTitle: "Vérifiez les champs signalés",
|
|
106985
|
+
toastValidationDescription: "Certaines valeurs ont été rejetées. Vérifiez les champs marqués en rouge."
|
|
106620
106986
|
};
|
|
106621
106987
|
var notificationsNotificationDisplay$2 = {
|
|
106622
106988
|
notificationsAriaLabel: "Notifications",
|
|
@@ -106899,7 +107265,8 @@ var profileBilling$2 = {
|
|
|
106899
107265
|
addCredits: "Ajouter des crédits",
|
|
106900
107266
|
manageBilling: "Gérer la facturation",
|
|
106901
107267
|
availableLabel: "Disponibles",
|
|
106902
|
-
|
|
107268
|
+
creditsUsdEquivalent: "≈ {amount}",
|
|
107269
|
+
creditsConversionHint: "{credits} crédits = 1 $",
|
|
106903
107270
|
creditsUnit: "{amount} Crédits",
|
|
106904
107271
|
consumedLabel: "Consommés",
|
|
106905
107272
|
usedThisPeriod: "Utilisés cette période",
|
|
@@ -106911,10 +107278,17 @@ var profileBilling$2 = {
|
|
|
106911
107278
|
disabled: "Désactivé",
|
|
106912
107279
|
manageUsage: "Gérer l'utilisation",
|
|
106913
107280
|
thresholdLabel: "Seuil",
|
|
107281
|
+
thresholdHint: "Quand vos crédits disponibles passent sous ce montant, une recharge démarre automatiquement",
|
|
106914
107282
|
rechargeAmountLabel: "Montant de rechargement",
|
|
107283
|
+
rechargeAmountHint: "Débité de votre moyen de paiement et ajouté à vos crédits à chaque recharge",
|
|
106915
107284
|
spendingLimitLabel: "Limite de dépenses",
|
|
107285
|
+
spendingLimitHint: "Le maximum que la recharge automatique peut débiter par période de facturation",
|
|
106916
107286
|
unlimited: "Illimité",
|
|
106917
|
-
autoRechargeDisabledMessage: "Le rechargement automatique est actuellement désactivé. Activez-le pour maintenir votre solde sans interruption."
|
|
107287
|
+
autoRechargeDisabledMessage: "Le rechargement automatique est actuellement désactivé. Activez-le pour maintenir votre solde sans interruption.",
|
|
107288
|
+
billingTabsAriaLabel: "Sections de facturation",
|
|
107289
|
+
tabPlanAndCredits: "Forfait et crédits",
|
|
107290
|
+
tabSpendLimits: "Limites de dépenses",
|
|
107291
|
+
tabAgentLimits: "Limites par agent"
|
|
106918
107292
|
};
|
|
106919
107293
|
var profileCatalogInviteModal$2 = {
|
|
106920
107294
|
title: "Invitation au catalogue",
|
|
@@ -107858,6 +108232,156 @@ var skillsProfileSkillsBox$2 = {
|
|
|
107858
108232
|
desired: "Souhaitées",
|
|
107859
108233
|
noDesiredSkills: "Vous n'avez pas encore de compétences souhaitées."
|
|
107860
108234
|
};
|
|
108235
|
+
var spendCapUsage$2 = {
|
|
108236
|
+
scopeTenant: "Espace de travail",
|
|
108237
|
+
scopeAgent: "Cet agent",
|
|
108238
|
+
scopeUserAgent: "Votre utilisation sur cet agent",
|
|
108239
|
+
intervalDay: "aujourd'hui",
|
|
108240
|
+
intervalWeek: "cette semaine",
|
|
108241
|
+
intervalMonth: "ce mois-ci",
|
|
108242
|
+
intervalYear: "cette année",
|
|
108243
|
+
percentUsed: "{percent}% utilisé",
|
|
108244
|
+
blockedBanner: "La limite d'utilisation est atteinte. Les nouveaux chats et l'entraînement sont suspendus jusqu'à la réinitialisation de la période.",
|
|
108245
|
+
warningBanner: "L'utilisation approche de sa limite."
|
|
108246
|
+
};
|
|
108247
|
+
var spendCapsTabLabels$2 = {
|
|
108248
|
+
header: {
|
|
108249
|
+
title: "Facturation",
|
|
108250
|
+
description: "Définissez des limites de dépenses pour cet agent et ses utilisateurs, et consultez la consommation."
|
|
108251
|
+
},
|
|
108252
|
+
capability: {
|
|
108253
|
+
title: "Limite de dépenses",
|
|
108254
|
+
description: "Fixez un plafond aux dépenses d'IA. Tant que cette limite est activée, tout ce qu'elle couvre compte dans le montant ci-dessous — et lorsque la limite est atteinte, vous choisissez de bloquer les nouvelles requêtes ou de simplement alerter les administrateurs.",
|
|
108255
|
+
offHint: "Activez-la pour commencer à suivre et appliquer cette limite. Votre configuration est conservée si vous la désactivez plus tard."
|
|
108256
|
+
},
|
|
108257
|
+
subTabs: {
|
|
108258
|
+
agent: "Cet agent",
|
|
108259
|
+
users: "Par utilisateur"
|
|
108260
|
+
},
|
|
108261
|
+
tenantSections: {
|
|
108262
|
+
workspace: {
|
|
108263
|
+
title: "Limite de dépenses de l'espace de travail",
|
|
108264
|
+
description: "Une seule limite couvrant tout ce que dépensent les agents et utilisateurs de cet espace de travail. Les limites par agent et par utilisateur se gèrent dans les réglages de chaque agent, sous Facturation."
|
|
108265
|
+
},
|
|
108266
|
+
noCapStats: {
|
|
108267
|
+
spentThisMonth: "Dépensé ce mois-ci",
|
|
108268
|
+
spentAllTime: "Dépensé au total",
|
|
108269
|
+
hint: "Sur l'ensemble des agents et utilisateurs de cet espace de travail"
|
|
108270
|
+
},
|
|
108271
|
+
agents: {
|
|
108272
|
+
title: "Limites de dépenses par agent",
|
|
108273
|
+
description: "Agents avec une limite de dépenses configurée dans cet espace de travail. Ouvrez-en un pour gérer sa limite et ses limites par utilisateur.",
|
|
108274
|
+
filter: {
|
|
108275
|
+
label: "Rechercher des agents",
|
|
108276
|
+
placeholder: "Rechercher des agents…",
|
|
108277
|
+
typeToSearch: "Saisissez au moins 2 caractères pour rechercher",
|
|
108278
|
+
searching: "Recherche d'agents…",
|
|
108279
|
+
noResults: "Aucun agent trouvé",
|
|
108280
|
+
clear: "Effacer le filtre d'agent"
|
|
108281
|
+
},
|
|
108282
|
+
table: {
|
|
108283
|
+
agentColumn: "Agent",
|
|
108284
|
+
limitColumn: "Limite",
|
|
108285
|
+
spentColumn: "Dépensé",
|
|
108286
|
+
remainingColumn: "Restant",
|
|
108287
|
+
statusColumn: "Statut"
|
|
108288
|
+
},
|
|
108289
|
+
emptyState: "Aucune limite de dépenses par agent pour l'instant. Recherchez un agent ci-dessus pour en définir une.",
|
|
108290
|
+
emptyFiltered: "Cet agent n'a pas encore de limite de dépenses.",
|
|
108291
|
+
setLimitButton: "Définir une limite de dépenses",
|
|
108292
|
+
manageAria: "Gérer les limites de dépenses de {name}",
|
|
108293
|
+
statusToggleAria: "Activer ou désactiver la limite de dépenses de {name}"
|
|
108294
|
+
}
|
|
108295
|
+
},
|
|
108296
|
+
form: {
|
|
108297
|
+
limitLabel: "Limite de dépenses (USD)",
|
|
108298
|
+
limitPlaceholder: "p. ex. 250.00",
|
|
108299
|
+
limitError: "Saisissez un montant supérieur à 0",
|
|
108300
|
+
intervalLabel: "Réinitialisation chaque",
|
|
108301
|
+
intervalOptions: {
|
|
108302
|
+
day: "Jour",
|
|
108303
|
+
week: "Semaine",
|
|
108304
|
+
month: "Mois",
|
|
108305
|
+
year: "Année"
|
|
108306
|
+
},
|
|
108307
|
+
enforcementLabel: "Quand la limite est atteinte",
|
|
108308
|
+
enforcementOptions: {
|
|
108309
|
+
block: "Bloquer les requêtes",
|
|
108310
|
+
alertOnly: "Alerte uniquement"
|
|
108311
|
+
},
|
|
108312
|
+
enforcementHelp: {
|
|
108313
|
+
block: "Les nouvelles requêtes de chat et d'entraînement sont refusées jusqu'à la réinitialisation de la période.",
|
|
108314
|
+
alertOnly: "Rien n'est bloqué : les administrateurs sont notifiés lorsque les dépenses approchent de la limite."
|
|
108315
|
+
},
|
|
108316
|
+
thresholdsLabel: "Alerter à (% de la limite)",
|
|
108317
|
+
thresholdsPlaceholder: "p. ex. 80, 95",
|
|
108318
|
+
thresholdsHelp: "Pourcentages séparés par des virgules auxquels les administrateurs reçoivent une alerte d'approche de la limite.",
|
|
108319
|
+
thresholdsError: "Utilisez des nombres séparés par des virgules entre 1 et 100",
|
|
108320
|
+
noCapHint: "Aucune limite de dépenses configurée pour l'instant — définissez un montant et enregistrez pour en créer une.",
|
|
108321
|
+
save: "Enregistrer",
|
|
108322
|
+
saving: "Enregistrement…",
|
|
108323
|
+
remove: "Supprimer la limite",
|
|
108324
|
+
removing: "Suppression…",
|
|
108325
|
+
cancel: "Annuler"
|
|
108326
|
+
},
|
|
108327
|
+
usage: {
|
|
108328
|
+
title: "Utilisation de la limite de dépenses",
|
|
108329
|
+
periodTitles: {
|
|
108330
|
+
day: "Utilisation quotidienne",
|
|
108331
|
+
week: "Utilisation hebdomadaire",
|
|
108332
|
+
month: "Utilisation mensuelle",
|
|
108333
|
+
year: "Utilisation annuelle"
|
|
108334
|
+
},
|
|
108335
|
+
spent: "Dépensé : {amount}",
|
|
108336
|
+
remaining: "Restant : {amount}",
|
|
108337
|
+
percentUsed: "{percent}% de la limite utilisée",
|
|
108338
|
+
exceededBadge: "Limite atteinte",
|
|
108339
|
+
alertOnlyBadge: "Alerte uniquement",
|
|
108340
|
+
disabledBadge: "Désactivé"
|
|
108341
|
+
},
|
|
108342
|
+
users: {
|
|
108343
|
+
sectionTitle: "Limites par utilisateur",
|
|
108344
|
+
sectionDescription: "Limitez ce que certains utilisateurs peuvent dépenser sur cet agent.",
|
|
108345
|
+
addButton: "Ajouter une limite utilisateur",
|
|
108346
|
+
addTitle: "Nouvelle limite utilisateur",
|
|
108347
|
+
editTitle: "Modifier la limite utilisateur",
|
|
108348
|
+
cancel: "Annuler",
|
|
108349
|
+
emptyState: "Aucune limite par utilisateur pour l'instant. Ajoutez-en une pour limiter un utilisateur précis sur cet agent.",
|
|
108350
|
+
edit: "Modifier",
|
|
108351
|
+
"delete": "Supprimer",
|
|
108352
|
+
table: {
|
|
108353
|
+
userColumn: "Utilisateur",
|
|
108354
|
+
limitColumn: "Limite",
|
|
108355
|
+
statusColumn: "Statut"
|
|
108356
|
+
},
|
|
108357
|
+
actionsAria: "Actions pour {username}",
|
|
108358
|
+
statusToggleAria: "Activer ou désactiver la limite de dépenses de {username}",
|
|
108359
|
+
picker: {
|
|
108360
|
+
label: "Utilisateur",
|
|
108361
|
+
placeholder: "Rechercher des utilisateurs…",
|
|
108362
|
+
typeToSearch: "Saisissez au moins 2 caractères pour rechercher",
|
|
108363
|
+
searching: "Recherche d'utilisateurs…",
|
|
108364
|
+
noResults: "Aucun utilisateur trouvé",
|
|
108365
|
+
clear: "Changer d'utilisateur"
|
|
108366
|
+
}
|
|
108367
|
+
},
|
|
108368
|
+
denied: {
|
|
108369
|
+
title: "Pas d'accès aux limites de dépenses",
|
|
108370
|
+
description: "Vous n'avez pas la permission de voir les limites de dépenses ici. Demandez l'accès à un administrateur."
|
|
108371
|
+
},
|
|
108372
|
+
deleteModal: {
|
|
108373
|
+
title: "Supprimer la limite de dépenses",
|
|
108374
|
+
description: "Les dépenses ne seront plus limitées ni suivies par cette limite.",
|
|
108375
|
+
cancel: "Annuler",
|
|
108376
|
+
confirm: "Supprimer"
|
|
108377
|
+
},
|
|
108378
|
+
toasts: {
|
|
108379
|
+
saved: "Limite de dépenses enregistrée",
|
|
108380
|
+
saveError: "Impossible d'enregistrer la limite de dépenses",
|
|
108381
|
+
deleted: "Limite de dépenses supprimée",
|
|
108382
|
+
deleteError: "Impossible de supprimer la limite de dépenses"
|
|
108383
|
+
}
|
|
108384
|
+
};
|
|
107861
108385
|
var tabsAlertstab$2 = {
|
|
107862
108386
|
searchAlertsPlaceholder: "Rechercher des alertes",
|
|
107863
108387
|
searchAlertsAriaLabel: "Rechercher des alertes",
|
|
@@ -109601,6 +110125,10 @@ var fr = {
|
|
|
109601
110125
|
componentsPolicyAssignmentSection: componentsPolicyAssignmentSection$2,
|
|
109602
110126
|
componentsPolicyConfigDialog: componentsPolicyConfigDialog$2,
|
|
109603
110127
|
componentsProactiveSettingsSection: componentsProactiveSettingsSection$2,
|
|
110128
|
+
componentsTemplateActionsSection: componentsTemplateActionsSection$2,
|
|
110129
|
+
componentsTemplateVariablesHelper: componentsTemplateVariablesHelper$2,
|
|
110130
|
+
componentsUserProgressSettingsSection: componentsUserProgressSettingsSection$2,
|
|
110131
|
+
componentsWatcherEmailSection: componentsWatcherEmailSection$2,
|
|
109604
110132
|
courseContentAccessiblePaginate: courseContentAccessiblePaginate$2,
|
|
109605
110133
|
courseContentCourseContentLayout: courseContentCourseContentLayout$2,
|
|
109606
110134
|
courseContentDiscoverFacetsFilter: courseContentDiscoverFacetsFilter$2,
|
|
@@ -109716,6 +110244,8 @@ var fr = {
|
|
|
109716
110244
|
skillsProfileResumeBox: skillsProfileResumeBox$2,
|
|
109717
110245
|
skillsProfileSkillDetailModal: skillsProfileSkillDetailModal$2,
|
|
109718
110246
|
skillsProfileSkillsBox: skillsProfileSkillsBox$2,
|
|
110247
|
+
spendCapUsage: spendCapUsage$2,
|
|
110248
|
+
spendCapsTabLabels: spendCapsTabLabels$2,
|
|
109719
110249
|
tabsAlertstab: tabsAlertstab$2,
|
|
109720
110250
|
tabsDisclaimersTab: tabsDisclaimersTab$2,
|
|
109721
110251
|
tabsEmbedTab: tabsEmbedTab$2,
|
|
@@ -111445,7 +111975,13 @@ var chatIndex$1 = {
|
|
|
111445
111975
|
confirmScreenShareTitle: "Confirmar uso compartido de pantalla",
|
|
111446
111976
|
confirmScreenShareDescription: "¿Deseas iniciar un uso compartido de pantalla con tu agente?",
|
|
111447
111977
|
cancel: "Cancelar",
|
|
111448
|
-
confirm: "Confirmar"
|
|
111978
|
+
confirm: "Confirmar",
|
|
111979
|
+
spendCapLimitDay: "Has alcanzado el límite de uso de hoy para este asistente.",
|
|
111980
|
+
spendCapLimitWeek: "Has alcanzado el límite de uso de esta semana para este asistente.",
|
|
111981
|
+
spendCapLimitMonth: "Has alcanzado el límite de uso de este mes para este asistente.",
|
|
111982
|
+
spendCapLimitYear: "Has alcanzado el límite de uso de este año para este asistente.",
|
|
111983
|
+
spendCapLimitGeneric: "Has alcanzado el límite de uso de este asistente.",
|
|
111984
|
+
spendCapContactAdmin: "Vuelve a intentarlo cuando el límite se reinicie o contacta con tu administrador."
|
|
111449
111985
|
};
|
|
111450
111986
|
var chatInputForm$1 = {
|
|
111451
111987
|
uploadingOneFile: "Subiendo 1 archivo...",
|
|
@@ -111648,6 +112184,8 @@ var clawSandboxAgentSkills$1 = {
|
|
|
111648
112184
|
fieldCategoryPlaceholder: "p. ej. web, código, datos",
|
|
111649
112185
|
privateToAgent: "Solo este agente",
|
|
111650
112186
|
privateToAgentHint: "Las habilidades privadas solo están disponibles para este agente y tienen prioridad sobre las habilidades de la plataforma con el mismo slug.",
|
|
112187
|
+
privateToOtherAgentHint: "Esta habilidad es privada de otro agente, por lo que este ajuste no se puede cambiar aquí.",
|
|
112188
|
+
privateToOtherAgentTooltip: "Esta habilidad es privada de otro agente y no se puede añadir aquí.",
|
|
111651
112189
|
instructionHint: "La guía que sigue el agente cuando se usa la habilidad. Los cambios se aplican de inmediato, incluso en conversaciones en curso.",
|
|
111652
112190
|
filesHint: "Recursos opcionales que el agente puede usar con esta habilidad. Las referencias y los scripts son archivos de texto; los assets son archivos subidos.",
|
|
111653
112191
|
filesAfterCreateHint: "Puedes adjuntar recursos a esta habilidad después de crearla (vuelve a abrirla con Editar).",
|
|
@@ -111887,6 +112425,92 @@ var componentsProactiveSettingsSection$1 = {
|
|
|
111887
112425
|
editAgentPromptAriaLabel: "Editar prompt del agente",
|
|
111888
112426
|
periodicAgentsHelp: "Opcional. Seleccione los agentes a incluir en la rotación de contacto proactivo."
|
|
111889
112427
|
};
|
|
112428
|
+
var componentsTemplateActionsSection$1 = {
|
|
112429
|
+
title: "Probar y restablecer",
|
|
112430
|
+
description: "Previsualice la plantilla en su bandeja de entrada o descarte las personalizaciones de esta plataforma.",
|
|
112431
|
+
testEmailLabel: "Enviar un correo de prueba",
|
|
112432
|
+
testEmailHelper: "Envía una versión de esta plantilla a la dirección que indique.",
|
|
112433
|
+
testEmailPlaceholder: "usted@ejemplo.com",
|
|
112434
|
+
sendTest: "Enviar correo de prueba",
|
|
112435
|
+
sendingTest: "Enviando...",
|
|
112436
|
+
testSuccessTitle: "Correo de prueba enviado",
|
|
112437
|
+
testSuccessDescription: "Enviado a {email}.",
|
|
112438
|
+
testErrorTitle: "No se pudo enviar el correo de prueba",
|
|
112439
|
+
testErrorDescription: "Verifique la dirección e inténtelo de nuevo.",
|
|
112440
|
+
resetLabel: "Restablecer al valor predeterminado",
|
|
112441
|
+
resetHelper: "Descarta la copia de esta plataforma y restaura la plantilla predeterminada.",
|
|
112442
|
+
reset: "Restablecer al valor predeterminado",
|
|
112443
|
+
resetting: "Restableciendo...",
|
|
112444
|
+
resetConfirmTitle: "¿Restablecer esta plantilla?",
|
|
112445
|
+
resetConfirmDescription: "Las personalizaciones de esta plataforma se descartarán y se restaurará la plantilla predeterminada. Esta acción no se puede deshacer.",
|
|
112446
|
+
resetConfirmCancel: "Cancelar",
|
|
112447
|
+
resetConfirmAction: "Restablecer plantilla",
|
|
112448
|
+
resetSuccessTitle: "Plantilla restablecida",
|
|
112449
|
+
resetSuccessDescription: "Se restauró el valor predeterminado de la plataforma.",
|
|
112450
|
+
resetErrorTitle: "No se pudo restablecer la plantilla",
|
|
112451
|
+
resetErrorDescription: "Inténtelo de nuevo."
|
|
112452
|
+
};
|
|
112453
|
+
var componentsTemplateVariablesHelper$1 = {
|
|
112454
|
+
title: "Variables que puede usar",
|
|
112455
|
+
copyHint: "Haga clic en una variable para copiarla y péguela en el asunto o el cuerpo.",
|
|
112456
|
+
insertHint: "Haga clic en una variable para insertarla.",
|
|
112457
|
+
copiedToast: "Se copió {token} al portapapeles.",
|
|
112458
|
+
copyUnavailableToast: "Copie {token} manualmente: el portapapeles no está disponible.",
|
|
112459
|
+
copyAriaLabel: "Copiar la variable {name}",
|
|
112460
|
+
insertAriaLabel: "Insertar la variable {name}"
|
|
112461
|
+
};
|
|
112462
|
+
var componentsUserProgressSettingsSection$1 = {
|
|
112463
|
+
scheduleTitle: "Programación y período del informe",
|
|
112464
|
+
scheduleDescription: "Elija con qué frecuencia se envía el resumen y qué período abarca.",
|
|
112465
|
+
frequencyLabel: "Frecuencia",
|
|
112466
|
+
selectFrequencyAriaLabel: "Seleccionar frecuencia",
|
|
112467
|
+
selectFrequencyPlaceholder: "Seleccionar frecuencia",
|
|
112468
|
+
daily: "Diaria",
|
|
112469
|
+
weekly: "Semanal",
|
|
112470
|
+
monthly: "Mensual",
|
|
112471
|
+
custom: "Personalizada",
|
|
112472
|
+
cadenceDaily: "Se envía todos los días a la hora indicada abajo.",
|
|
112473
|
+
cadenceWeekly: "Se envía todos los lunes a la hora indicada abajo.",
|
|
112474
|
+
cadenceMonthly: "Se envía el día 1 de cada mes a la hora indicada abajo.",
|
|
112475
|
+
cadenceCustom: "Se envía cada {days} días a la hora indicada abajo.",
|
|
112476
|
+
cadenceCustomUnset: "Defina un intervalo personalizado para elegir con qué frecuencia se envía el resumen.",
|
|
112477
|
+
executionTimeLabel: "Hora de envío",
|
|
112478
|
+
executionTimeRequired: "Indique la hora a la que debe enviarse el resumen.",
|
|
112479
|
+
timezoneLabel: "Zona horaria",
|
|
112480
|
+
selectTimezoneAriaLabel: "Seleccionar zona horaria",
|
|
112481
|
+
selectTimezonePlaceholder: "Seleccionar zona horaria",
|
|
112482
|
+
useLocalTimezone: "Usar la zona horaria local ({timezone})",
|
|
112483
|
+
customIntervalLabel: "Intervalo personalizado (días)",
|
|
112484
|
+
customIntervalRequired: "Indique cuántos días deben pasar entre envíos.",
|
|
112485
|
+
dayRangeError: "Introduzca un número entero de días entre 1 y 365.",
|
|
112486
|
+
lookbackLabel: "Período del informe (días)",
|
|
112487
|
+
lookbackHelp: "Cuánto tiempo hacia atrás abarca cada resumen. Es independiente de la frecuencia de envío: un correo semanal puede informar sobre los últimos 30 días.",
|
|
112488
|
+
lookbackRequired: "Indique el período del informe en días.",
|
|
112489
|
+
dataPointsLabel: "Datos incluidos",
|
|
112490
|
+
dataPointsHelp: "El correo solo muestra las secciones que están activadas y tienen datos para ese estudiante.",
|
|
112491
|
+
dataPointCoursesProgressed: "Cursos en progreso",
|
|
112492
|
+
dataPointCoursesCompleted: "Cursos completados",
|
|
112493
|
+
dataPointCredentialsEarned: "Credenciales obtenidas",
|
|
112494
|
+
dataPointTimeSpent: "Tiempo dedicado",
|
|
112495
|
+
dataPointActiveDays: "Días activos",
|
|
112496
|
+
dataPointMentorsAccessed: "Actividad de agentes de IA",
|
|
112497
|
+
noDataPointsWarning: "No se seleccionó ningún dato: el resumen no tendrá contenido que mostrar."
|
|
112498
|
+
};
|
|
112499
|
+
var componentsWatcherEmailSection$1 = {
|
|
112500
|
+
title: "Correo para observadores",
|
|
112501
|
+
description: "Se envía a los observadores del estudiante, como un padre, una madre o un supervisor.",
|
|
112502
|
+
fallbackNotice: "Actualmente los observadores reciben el correo del estudiante. Personalícelo para enviarles un mensaje distinto.",
|
|
112503
|
+
customize: "Personalizar el correo para observadores",
|
|
112504
|
+
useLearnerEmail: "Usar el correo del estudiante",
|
|
112505
|
+
subjectLabel: "Asunto del correo para observadores",
|
|
112506
|
+
subjectHelper: "Admite las mismas variables que el correo del estudiante, más learner_name.",
|
|
112507
|
+
subjectFallbackHelper: "Si lo deja vacío, los observadores reciben el asunto del correo del estudiante.",
|
|
112508
|
+
subjectPlaceholder: "Escriba el asunto del correo para observadores...",
|
|
112509
|
+
bodyLabel: "Cuerpo del correo para observadores",
|
|
112510
|
+
bodyHelper: "Admite las mismas variables que el correo del estudiante, más learner_name.",
|
|
112511
|
+
bodyFallbackHelper: "Si lo deja vacío, los observadores reciben el cuerpo del correo del estudiante.",
|
|
112512
|
+
bodyPlaceholder: "Escriba el cuerpo del correo para observadores..."
|
|
112513
|
+
};
|
|
111890
112514
|
var courseContentAccessiblePaginate$1 = {
|
|
111891
112515
|
pagination: "Paginación"
|
|
111892
112516
|
};
|
|
@@ -113089,7 +113713,14 @@ var notificationsEditAlertDialog$1 = {
|
|
|
113089
113713
|
toastErrorDescription: "No se pudo actualizar la plantilla. Por favor, inténtelo de nuevo.",
|
|
113090
113714
|
cancel: "Cancelar",
|
|
113091
113715
|
saving: "Guardando...",
|
|
113092
|
-
saveChanges: "Guardar cambios"
|
|
113716
|
+
saveChanges: "Guardar cambios",
|
|
113717
|
+
learnerEmailSubjectLabel: "Asunto del correo del estudiante",
|
|
113718
|
+
learnerEmailSubjectHelper: "Obligatorio. Admite variables de plantilla: consulte la lista debajo del cuerpo.",
|
|
113719
|
+
learnerEmailBodyLabel: "Cuerpo del correo del estudiante",
|
|
113720
|
+
learnerEmailBodyHelper: "Obligatorio. Salude con «Hola,» en lugar de usar el nombre de usuario: suelen generarse automáticamente.",
|
|
113721
|
+
noChangesToast: "No hay cambios que guardar.",
|
|
113722
|
+
toastValidationTitle: "Revise los campos resaltados",
|
|
113723
|
+
toastValidationDescription: "Se rechazaron algunos valores. Revise los campos marcados en rojo."
|
|
113093
113724
|
};
|
|
113094
113725
|
var notificationsNotificationDisplay$1 = {
|
|
113095
113726
|
notificationsAriaLabel: "Notificaciones",
|
|
@@ -113372,7 +114003,8 @@ var profileBilling$1 = {
|
|
|
113372
114003
|
addCredits: "Agregar créditos",
|
|
113373
114004
|
manageBilling: "Gestionar facturación",
|
|
113374
114005
|
availableLabel: "Disponibles",
|
|
113375
|
-
|
|
114006
|
+
creditsUsdEquivalent: "≈ {amount}",
|
|
114007
|
+
creditsConversionHint: "{credits} créditos = $1",
|
|
113376
114008
|
creditsUnit: "{amount} Créditos",
|
|
113377
114009
|
consumedLabel: "Consumidos",
|
|
113378
114010
|
usedThisPeriod: "Usados este período",
|
|
@@ -113384,10 +114016,17 @@ var profileBilling$1 = {
|
|
|
113384
114016
|
disabled: "Deshabilitado",
|
|
113385
114017
|
manageUsage: "Gestionar uso",
|
|
113386
114018
|
thresholdLabel: "Umbral",
|
|
114019
|
+
thresholdHint: "Cuando tus créditos disponibles bajan de este importe, se inicia una recarga automática",
|
|
113387
114020
|
rechargeAmountLabel: "Monto de recarga",
|
|
114021
|
+
rechargeAmountHint: "Se cobra a tu método de pago y se añade a tus créditos en cada recarga",
|
|
113388
114022
|
spendingLimitLabel: "Límite de gasto",
|
|
114023
|
+
spendingLimitHint: "Lo máximo que la recarga automática puede cobrar por periodo de facturación",
|
|
113389
114024
|
unlimited: "Ilimitado",
|
|
113390
|
-
autoRechargeDisabledMessage: "La recarga automática está deshabilitada. Actívala para mantener tu saldo sin interrupciones."
|
|
114025
|
+
autoRechargeDisabledMessage: "La recarga automática está deshabilitada. Actívala para mantener tu saldo sin interrupciones.",
|
|
114026
|
+
billingTabsAriaLabel: "Secciones de facturación",
|
|
114027
|
+
tabPlanAndCredits: "Plan y créditos",
|
|
114028
|
+
tabSpendLimits: "Límites de gasto",
|
|
114029
|
+
tabAgentLimits: "Límites por agente"
|
|
113391
114030
|
};
|
|
113392
114031
|
var profileCatalogInviteModal$1 = {
|
|
113393
114032
|
title: "Invitación al catálogo",
|
|
@@ -114331,6 +114970,156 @@ var skillsProfileSkillsBox$1 = {
|
|
|
114331
114970
|
desired: "Deseadas",
|
|
114332
114971
|
noDesiredSkills: "Todavía no tienes habilidades deseadas."
|
|
114333
114972
|
};
|
|
114973
|
+
var spendCapUsage$1 = {
|
|
114974
|
+
scopeTenant: "Espacio de trabajo",
|
|
114975
|
+
scopeAgent: "Este agente",
|
|
114976
|
+
scopeUserAgent: "Tu uso en este agente",
|
|
114977
|
+
intervalDay: "hoy",
|
|
114978
|
+
intervalWeek: "esta semana",
|
|
114979
|
+
intervalMonth: "este mes",
|
|
114980
|
+
intervalYear: "este año",
|
|
114981
|
+
percentUsed: "{percent}% usado",
|
|
114982
|
+
blockedBanner: "Se ha alcanzado el límite de uso. Los nuevos chats y el entrenamiento quedan en pausa hasta que el periodo se reinicie.",
|
|
114983
|
+
warningBanner: "El uso se acerca a su límite."
|
|
114984
|
+
};
|
|
114985
|
+
var spendCapsTabLabels$1 = {
|
|
114986
|
+
header: {
|
|
114987
|
+
title: "Facturación",
|
|
114988
|
+
description: "Define límites de gasto para este agente y sus usuarios, y consulta cuánto se ha usado."
|
|
114989
|
+
},
|
|
114990
|
+
capability: {
|
|
114991
|
+
title: "Límite de gasto",
|
|
114992
|
+
description: "Pon un techo al gasto en IA. Mientras este límite esté activado, todo lo que cubre cuenta para el importe de abajo; y cuando se alcanza, tú decides si se bloquean las nuevas solicitudes o simplemente se avisa a los administradores.",
|
|
114993
|
+
offHint: "Actívalo para empezar a hacer seguimiento y aplicar este límite. Tu configuración se conserva si luego lo desactivas."
|
|
114994
|
+
},
|
|
114995
|
+
subTabs: {
|
|
114996
|
+
agent: "Este agente",
|
|
114997
|
+
users: "Por usuario"
|
|
114998
|
+
},
|
|
114999
|
+
tenantSections: {
|
|
115000
|
+
workspace: {
|
|
115001
|
+
title: "Límite de gasto del espacio de trabajo",
|
|
115002
|
+
description: "Un único límite que cubre todo lo que gastan los agentes y usuarios de este espacio de trabajo. Los límites por agente y por usuario se gestionan en la configuración de cada agente, en Facturación."
|
|
115003
|
+
},
|
|
115004
|
+
noCapStats: {
|
|
115005
|
+
spentThisMonth: "Gastado este mes",
|
|
115006
|
+
spentAllTime: "Gastado en total",
|
|
115007
|
+
hint: "En todos los agentes y usuarios de este espacio de trabajo"
|
|
115008
|
+
},
|
|
115009
|
+
agents: {
|
|
115010
|
+
title: "Límites de gasto por agente",
|
|
115011
|
+
description: "Agentes con un límite de gasto configurado en este espacio de trabajo. Abre uno para gestionar su límite y sus límites por usuario.",
|
|
115012
|
+
filter: {
|
|
115013
|
+
label: "Buscar agentes",
|
|
115014
|
+
placeholder: "Buscar agentes…",
|
|
115015
|
+
typeToSearch: "Escribe al menos 2 caracteres para buscar",
|
|
115016
|
+
searching: "Buscando agentes…",
|
|
115017
|
+
noResults: "No se encontraron agentes",
|
|
115018
|
+
clear: "Quitar el filtro de agente"
|
|
115019
|
+
},
|
|
115020
|
+
table: {
|
|
115021
|
+
agentColumn: "Agente",
|
|
115022
|
+
limitColumn: "Límite",
|
|
115023
|
+
spentColumn: "Gastado",
|
|
115024
|
+
remainingColumn: "Restante",
|
|
115025
|
+
statusColumn: "Estado"
|
|
115026
|
+
},
|
|
115027
|
+
emptyState: "Aún no hay límites de gasto por agente. Busca un agente arriba para configurar uno.",
|
|
115028
|
+
emptyFiltered: "Este agente aún no tiene límite de gasto.",
|
|
115029
|
+
setLimitButton: "Configurar límite de gasto",
|
|
115030
|
+
manageAria: "Gestionar los límites de gasto de {name}",
|
|
115031
|
+
statusToggleAria: "Activar o desactivar el límite de gasto de {name}"
|
|
115032
|
+
}
|
|
115033
|
+
},
|
|
115034
|
+
form: {
|
|
115035
|
+
limitLabel: "Límite de gasto (USD)",
|
|
115036
|
+
limitPlaceholder: "p. ej. 250.00",
|
|
115037
|
+
limitError: "Introduce un importe mayor que 0",
|
|
115038
|
+
intervalLabel: "Se reinicia cada",
|
|
115039
|
+
intervalOptions: {
|
|
115040
|
+
day: "Día",
|
|
115041
|
+
week: "Semana",
|
|
115042
|
+
month: "Mes",
|
|
115043
|
+
year: "Año"
|
|
115044
|
+
},
|
|
115045
|
+
enforcementLabel: "Al alcanzar el límite",
|
|
115046
|
+
enforcementOptions: {
|
|
115047
|
+
block: "Bloquear solicitudes",
|
|
115048
|
+
alertOnly: "Solo alertar"
|
|
115049
|
+
},
|
|
115050
|
+
enforcementHelp: {
|
|
115051
|
+
block: "Las nuevas solicitudes de chat y entrenamiento se rechazan hasta que el periodo se reinicie.",
|
|
115052
|
+
alertOnly: "No se bloquea nada: se notifica a los administradores cuando el gasto se acerca al límite."
|
|
115053
|
+
},
|
|
115054
|
+
thresholdsLabel: "Alertar al (% del límite)",
|
|
115055
|
+
thresholdsPlaceholder: "p. ej. 80, 95",
|
|
115056
|
+
thresholdsHelp: "Porcentajes separados por comas en los que los administradores reciben una alerta de proximidad al límite.",
|
|
115057
|
+
thresholdsError: "Usa números separados por comas entre 1 y 100",
|
|
115058
|
+
noCapHint: "Aún no hay límite de gasto configurado: define un importe y guarda para crearlo.",
|
|
115059
|
+
save: "Guardar",
|
|
115060
|
+
saving: "Guardando…",
|
|
115061
|
+
remove: "Eliminar límite",
|
|
115062
|
+
removing: "Eliminando…",
|
|
115063
|
+
cancel: "Cancelar"
|
|
115064
|
+
},
|
|
115065
|
+
usage: {
|
|
115066
|
+
title: "Uso del límite de gasto",
|
|
115067
|
+
periodTitles: {
|
|
115068
|
+
day: "Uso diario",
|
|
115069
|
+
week: "Uso semanal",
|
|
115070
|
+
month: "Uso mensual",
|
|
115071
|
+
year: "Uso anual"
|
|
115072
|
+
},
|
|
115073
|
+
spent: "Gastado: {amount}",
|
|
115074
|
+
remaining: "Restante: {amount}",
|
|
115075
|
+
percentUsed: "{percent}% del límite usado",
|
|
115076
|
+
exceededBadge: "Límite alcanzado",
|
|
115077
|
+
alertOnlyBadge: "Solo alerta",
|
|
115078
|
+
disabledBadge: "Desactivado"
|
|
115079
|
+
},
|
|
115080
|
+
users: {
|
|
115081
|
+
sectionTitle: "Límites por usuario",
|
|
115082
|
+
sectionDescription: "Limita cuánto pueden gastar usuarios concretos en este agente.",
|
|
115083
|
+
addButton: "Añadir límite de usuario",
|
|
115084
|
+
addTitle: "Nuevo límite de usuario",
|
|
115085
|
+
editTitle: "Editar límite de usuario",
|
|
115086
|
+
cancel: "Cancelar",
|
|
115087
|
+
emptyState: "Aún no hay límites por usuario. Añade uno para limitar a un usuario concreto en este agente.",
|
|
115088
|
+
edit: "Editar",
|
|
115089
|
+
"delete": "Eliminar",
|
|
115090
|
+
table: {
|
|
115091
|
+
userColumn: "Usuario",
|
|
115092
|
+
limitColumn: "Límite",
|
|
115093
|
+
statusColumn: "Estado"
|
|
115094
|
+
},
|
|
115095
|
+
actionsAria: "Acciones para {username}",
|
|
115096
|
+
statusToggleAria: "Activar o desactivar el límite de gasto de {username}",
|
|
115097
|
+
picker: {
|
|
115098
|
+
label: "Usuario",
|
|
115099
|
+
placeholder: "Buscar usuarios…",
|
|
115100
|
+
typeToSearch: "Escribe al menos 2 caracteres para buscar",
|
|
115101
|
+
searching: "Buscando usuarios…",
|
|
115102
|
+
noResults: "No se encontraron usuarios",
|
|
115103
|
+
clear: "Cambiar de usuario"
|
|
115104
|
+
}
|
|
115105
|
+
},
|
|
115106
|
+
denied: {
|
|
115107
|
+
title: "Sin acceso a los límites de gasto",
|
|
115108
|
+
description: "No tienes permiso para ver los límites de gasto aquí. Pide acceso a un administrador."
|
|
115109
|
+
},
|
|
115110
|
+
deleteModal: {
|
|
115111
|
+
title: "Eliminar límite de gasto",
|
|
115112
|
+
description: "El gasto dejará de estar limitado y de contabilizarse contra este límite.",
|
|
115113
|
+
cancel: "Cancelar",
|
|
115114
|
+
confirm: "Eliminar"
|
|
115115
|
+
},
|
|
115116
|
+
toasts: {
|
|
115117
|
+
saved: "Límite de gasto guardado",
|
|
115118
|
+
saveError: "No se pudo guardar el límite de gasto",
|
|
115119
|
+
deleted: "Límite de gasto eliminado",
|
|
115120
|
+
deleteError: "No se pudo eliminar el límite de gasto"
|
|
115121
|
+
}
|
|
115122
|
+
};
|
|
114334
115123
|
var tabsAlertstab$1 = {
|
|
114335
115124
|
searchAlertsPlaceholder: "Buscar alertas",
|
|
114336
115125
|
searchAlertsAriaLabel: "Buscar alertas",
|
|
@@ -116074,6 +116863,10 @@ var es = {
|
|
|
116074
116863
|
componentsPolicyAssignmentSection: componentsPolicyAssignmentSection$1,
|
|
116075
116864
|
componentsPolicyConfigDialog: componentsPolicyConfigDialog$1,
|
|
116076
116865
|
componentsProactiveSettingsSection: componentsProactiveSettingsSection$1,
|
|
116866
|
+
componentsTemplateActionsSection: componentsTemplateActionsSection$1,
|
|
116867
|
+
componentsTemplateVariablesHelper: componentsTemplateVariablesHelper$1,
|
|
116868
|
+
componentsUserProgressSettingsSection: componentsUserProgressSettingsSection$1,
|
|
116869
|
+
componentsWatcherEmailSection: componentsWatcherEmailSection$1,
|
|
116077
116870
|
courseContentAccessiblePaginate: courseContentAccessiblePaginate$1,
|
|
116078
116871
|
courseContentCourseContentLayout: courseContentCourseContentLayout$1,
|
|
116079
116872
|
courseContentDiscoverFacetsFilter: courseContentDiscoverFacetsFilter$1,
|
|
@@ -116189,6 +116982,8 @@ var es = {
|
|
|
116189
116982
|
skillsProfileResumeBox: skillsProfileResumeBox$1,
|
|
116190
116983
|
skillsProfileSkillDetailModal: skillsProfileSkillDetailModal$1,
|
|
116191
116984
|
skillsProfileSkillsBox: skillsProfileSkillsBox$1,
|
|
116985
|
+
spendCapUsage: spendCapUsage$1,
|
|
116986
|
+
spendCapsTabLabels: spendCapsTabLabels$1,
|
|
116192
116987
|
tabsAlertstab: tabsAlertstab$1,
|
|
116193
116988
|
tabsDisclaimersTab: tabsDisclaimersTab$1,
|
|
116194
116989
|
tabsEmbedTab: tabsEmbedTab$1,
|
|
@@ -117918,7 +118713,13 @@ var chatIndex = {
|
|
|
117918
118713
|
confirmScreenShareTitle: "确认屏幕共享",
|
|
117919
118714
|
confirmScreenShareDescription: "您要与您的助手开始屏幕共享吗?",
|
|
117920
118715
|
cancel: "取消",
|
|
117921
|
-
confirm: "确认"
|
|
118716
|
+
confirm: "确认",
|
|
118717
|
+
spendCapLimitDay: "您已达到此助手今天的使用限额。",
|
|
118718
|
+
spendCapLimitWeek: "您已达到此助手本周的使用限额。",
|
|
118719
|
+
spendCapLimitMonth: "您已达到此助手本月的使用限额。",
|
|
118720
|
+
spendCapLimitYear: "您已达到此助手今年的使用限额。",
|
|
118721
|
+
spendCapLimitGeneric: "您已达到此助手的使用限额。",
|
|
118722
|
+
spendCapContactAdmin: "请在限额重置后重试,或联系您的管理员。"
|
|
117922
118723
|
};
|
|
117923
118724
|
var chatInputForm = {
|
|
117924
118725
|
uploadingOneFile: "正在上传 1 个文件...",
|
|
@@ -118121,6 +118922,8 @@ var clawSandboxAgentSkills = {
|
|
|
118121
118922
|
fieldCategoryPlaceholder: "例如 web、代码、数据",
|
|
118122
118923
|
privateToAgent: "仅此智能体",
|
|
118123
118924
|
privateToAgentHint: "私有技能仅对此智能体可用,并优先于具有相同 slug 的平台技能。",
|
|
118925
|
+
privateToOtherAgentHint: "该技能为其他智能体私有,因此无法在此更改该设置。",
|
|
118926
|
+
privateToOtherAgentTooltip: "该技能为其他智能体私有,无法在此添加。",
|
|
118124
118927
|
instructionHint: "使用该技能时智能体遵循的操作指南。修改会立即生效,包括正在进行的对话。",
|
|
118125
118928
|
filesHint: "智能体在使用此技能时可参考的可选资源。参考资料和脚本是文本文件;资产是上传的文件。",
|
|
118126
118929
|
filesAfterCreateHint: "创建技能后即可附加资源(通过“编辑”重新打开)。",
|
|
@@ -118360,6 +119163,92 @@ var componentsProactiveSettingsSection = {
|
|
|
118360
119163
|
editAgentPromptAriaLabel: "编辑代理提示",
|
|
118361
119164
|
periodicAgentsHelp: "可选。选择要包含在主动外联轮换中的代理。"
|
|
118362
119165
|
};
|
|
119166
|
+
var componentsTemplateActionsSection = {
|
|
119167
|
+
title: "测试与重置",
|
|
119168
|
+
description: "在您的收件箱中预览模板,或放弃本平台的自定义内容。",
|
|
119169
|
+
testEmailLabel: "发送测试邮件",
|
|
119170
|
+
testEmailHelper: "将此模板的一次渲染结果发送至您输入的地址。",
|
|
119171
|
+
testEmailPlaceholder: "you@example.com",
|
|
119172
|
+
sendTest: "发送测试邮件",
|
|
119173
|
+
sendingTest: "发送中...",
|
|
119174
|
+
testSuccessTitle: "测试邮件已发送",
|
|
119175
|
+
testSuccessDescription: "已发送至 {email}。",
|
|
119176
|
+
testErrorTitle: "无法发送测试邮件",
|
|
119177
|
+
testErrorDescription: "请检查地址后重试。",
|
|
119178
|
+
resetLabel: "重置为默认值",
|
|
119179
|
+
resetHelper: "放弃本平台的副本并恢复默认模板。",
|
|
119180
|
+
reset: "重置为默认值",
|
|
119181
|
+
resetting: "重置中...",
|
|
119182
|
+
resetConfirmTitle: "要重置此模板吗?",
|
|
119183
|
+
resetConfirmDescription: "本平台的自定义内容将被放弃并恢复默认模板。此操作无法撤销。",
|
|
119184
|
+
resetConfirmCancel: "取消",
|
|
119185
|
+
resetConfirmAction: "重置模板",
|
|
119186
|
+
resetSuccessTitle: "模板已重置",
|
|
119187
|
+
resetSuccessDescription: "已恢复平台默认设置。",
|
|
119188
|
+
resetErrorTitle: "无法重置模板",
|
|
119189
|
+
resetErrorDescription: "请重试。"
|
|
119190
|
+
};
|
|
119191
|
+
var componentsTemplateVariablesHelper = {
|
|
119192
|
+
title: "可用变量",
|
|
119193
|
+
copyHint: "点击变量即可复制,然后粘贴到主题或正文中。",
|
|
119194
|
+
insertHint: "点击变量即可插入。",
|
|
119195
|
+
copiedToast: "已将 {token} 复制到剪贴板。",
|
|
119196
|
+
copyUnavailableToast: "请手动复制 {token}:剪贴板不可用。",
|
|
119197
|
+
copyAriaLabel: "复制变量 {name}",
|
|
119198
|
+
insertAriaLabel: "插入变量 {name}"
|
|
119199
|
+
};
|
|
119200
|
+
var componentsUserProgressSettingsSection = {
|
|
119201
|
+
scheduleTitle: "发送计划与统计周期",
|
|
119202
|
+
scheduleDescription: "选择摘要的发送频率及其涵盖的时间范围。",
|
|
119203
|
+
frequencyLabel: "频率",
|
|
119204
|
+
selectFrequencyAriaLabel: "选择频率",
|
|
119205
|
+
selectFrequencyPlaceholder: "选择频率",
|
|
119206
|
+
daily: "每天",
|
|
119207
|
+
weekly: "每周",
|
|
119208
|
+
monthly: "每月",
|
|
119209
|
+
custom: "自定义",
|
|
119210
|
+
cadenceDaily: "每天在下方设定的时间发送。",
|
|
119211
|
+
cadenceWeekly: "每周一在下方设定的时间发送。",
|
|
119212
|
+
cadenceMonthly: "每月 1 日在下方设定的时间发送。",
|
|
119213
|
+
cadenceCustom: "每 {days} 天在下方设定的时间发送。",
|
|
119214
|
+
cadenceCustomUnset: "设置自定义间隔以确定摘要的发送频率。",
|
|
119215
|
+
executionTimeLabel: "发送时间",
|
|
119216
|
+
executionTimeRequired: "请指定摘要的发送时间。",
|
|
119217
|
+
timezoneLabel: "时区",
|
|
119218
|
+
selectTimezoneAriaLabel: "选择时区",
|
|
119219
|
+
selectTimezonePlaceholder: "选择时区",
|
|
119220
|
+
useLocalTimezone: "使用本地时区({timezone})",
|
|
119221
|
+
customIntervalLabel: "自定义间隔(天)",
|
|
119222
|
+
customIntervalRequired: "请设置两次发送之间相隔的天数。",
|
|
119223
|
+
dayRangeError: "请输入 1 到 365 之间的整数天数。",
|
|
119224
|
+
lookbackLabel: "统计周期(天)",
|
|
119225
|
+
lookbackHelp: "每份摘要回溯统计的时间范围。它与发送频率相互独立——每周发送的邮件也可以统计最近 30 天的数据。",
|
|
119226
|
+
lookbackRequired: "请设置以天为单位的统计周期。",
|
|
119227
|
+
dataPointsLabel: "包含的数据项",
|
|
119228
|
+
dataPointsHelp: "邮件仅显示已启用且该学习者有相应数据的板块。",
|
|
119229
|
+
dataPointCoursesProgressed: "课程进展",
|
|
119230
|
+
dataPointCoursesCompleted: "已完成课程",
|
|
119231
|
+
dataPointCredentialsEarned: "已获得证书",
|
|
119232
|
+
dataPointTimeSpent: "学习时长",
|
|
119233
|
+
dataPointActiveDays: "活跃天数",
|
|
119234
|
+
dataPointMentorsAccessed: "AI 代理活动",
|
|
119235
|
+
noDataPointsWarning: "未选择任何数据项——摘要将没有内容可显示。"
|
|
119236
|
+
};
|
|
119237
|
+
var componentsWatcherEmailSection = {
|
|
119238
|
+
title: "关注者邮件",
|
|
119239
|
+
description: "发送给学习者的关注者,例如家长或主管。",
|
|
119240
|
+
fallbackNotice: "关注者目前收到的是学习者邮件。自定义后可向他们发送不同的内容。",
|
|
119241
|
+
customize: "自定义关注者邮件",
|
|
119242
|
+
useLearnerEmail: "使用学习者邮件",
|
|
119243
|
+
subjectLabel: "关注者邮件主题",
|
|
119244
|
+
subjectHelper: "支持与学习者邮件相同的变量,另加 learner_name。",
|
|
119245
|
+
subjectFallbackHelper: "留空则关注者收到学习者邮件的主题。",
|
|
119246
|
+
subjectPlaceholder: "请输入关注者邮件主题...",
|
|
119247
|
+
bodyLabel: "关注者邮件正文",
|
|
119248
|
+
bodyHelper: "支持与学习者邮件相同的变量,另加 learner_name。",
|
|
119249
|
+
bodyFallbackHelper: "留空则关注者收到学习者邮件的正文。",
|
|
119250
|
+
bodyPlaceholder: "请输入关注者邮件正文..."
|
|
119251
|
+
};
|
|
118363
119252
|
var courseContentAccessiblePaginate = {
|
|
118364
119253
|
pagination: "分页"
|
|
118365
119254
|
};
|
|
@@ -119562,7 +120451,14 @@ var notificationsEditAlertDialog = {
|
|
|
119562
120451
|
toastErrorDescription: "更新模板失败,请重试。",
|
|
119563
120452
|
cancel: "取消",
|
|
119564
120453
|
saving: "保存中...",
|
|
119565
|
-
saveChanges: "保存更改"
|
|
120454
|
+
saveChanges: "保存更改",
|
|
120455
|
+
learnerEmailSubjectLabel: "学习者邮件主题",
|
|
120456
|
+
learnerEmailSubjectHelper: "必填。支持模板变量——请参阅正文下方的列表。",
|
|
120457
|
+
learnerEmailBodyLabel: "学习者邮件正文",
|
|
120458
|
+
learnerEmailBodyHelper: "必填。请使用“您好,”问候,而不要使用用户名——用户名通常是自动生成的。",
|
|
120459
|
+
noChangesToast: "没有需要保存的更改。",
|
|
120460
|
+
toastValidationTitle: "请检查高亮显示的字段",
|
|
120461
|
+
toastValidationDescription: "部分值被拒绝。请检查标记为红色的字段。"
|
|
119566
120462
|
};
|
|
119567
120463
|
var notificationsNotificationDisplay = {
|
|
119568
120464
|
notificationsAriaLabel: "通知",
|
|
@@ -119845,7 +120741,8 @@ var profileBilling = {
|
|
|
119845
120741
|
addCredits: "添加积分",
|
|
119846
120742
|
manageBilling: "管理账单",
|
|
119847
120743
|
availableLabel: "可用",
|
|
119848
|
-
|
|
120744
|
+
creditsUsdEquivalent: "约合 {amount}",
|
|
120745
|
+
creditsConversionHint: "{credits} 积分 = $1",
|
|
119849
120746
|
creditsUnit: "{amount} 积分",
|
|
119850
120747
|
consumedLabel: "已消耗",
|
|
119851
120748
|
usedThisPeriod: "本期已使用",
|
|
@@ -119857,10 +120754,17 @@ var profileBilling = {
|
|
|
119857
120754
|
disabled: "已禁用",
|
|
119858
120755
|
manageUsage: "管理用量",
|
|
119859
120756
|
thresholdLabel: "阈值",
|
|
120757
|
+
thresholdHint: "当可用积分低于此金额时,将自动开始充值",
|
|
119860
120758
|
rechargeAmountLabel: "充值金额",
|
|
120759
|
+
rechargeAmountHint: "每次充值时从您的付款方式扣款,并添加到您的积分中",
|
|
119861
120760
|
spendingLimitLabel: "消费限额",
|
|
120761
|
+
spendingLimitHint: "每个账单周期内自动充值可扣款的上限",
|
|
119862
120762
|
unlimited: "无限制",
|
|
119863
|
-
autoRechargeDisabledMessage: "自动充值当前已禁用。启用后可在不中断服务的情况下保持余额充足。"
|
|
120763
|
+
autoRechargeDisabledMessage: "自动充值当前已禁用。启用后可在不中断服务的情况下保持余额充足。",
|
|
120764
|
+
billingTabsAriaLabel: "账单板块",
|
|
120765
|
+
tabPlanAndCredits: "套餐与积分",
|
|
120766
|
+
tabSpendLimits: "支出限额",
|
|
120767
|
+
tabAgentLimits: "智能体限额"
|
|
119864
120768
|
};
|
|
119865
120769
|
var profileCatalogInviteModal = {
|
|
119866
120770
|
title: "目录邀请",
|
|
@@ -120804,6 +121708,156 @@ var skillsProfileSkillsBox = {
|
|
|
120804
121708
|
desired: "期望",
|
|
120805
121709
|
noDesiredSkills: "您还没有任何期望的技能。"
|
|
120806
121710
|
};
|
|
121711
|
+
var spendCapUsage = {
|
|
121712
|
+
scopeTenant: "工作区",
|
|
121713
|
+
scopeAgent: "此智能体",
|
|
121714
|
+
scopeUserAgent: "您在此智能体上的用量",
|
|
121715
|
+
intervalDay: "今天",
|
|
121716
|
+
intervalWeek: "本周",
|
|
121717
|
+
intervalMonth: "本月",
|
|
121718
|
+
intervalYear: "今年",
|
|
121719
|
+
percentUsed: "已使用 {percent}%",
|
|
121720
|
+
blockedBanner: "已达到使用限额。在周期重置前,新的聊天和训练将暂停。",
|
|
121721
|
+
warningBanner: "用量即将达到限额。"
|
|
121722
|
+
};
|
|
121723
|
+
var spendCapsTabLabels = {
|
|
121724
|
+
header: {
|
|
121725
|
+
title: "账单",
|
|
121726
|
+
description: "为此智能体及其用户设置支出限额,并查看已用金额。"
|
|
121727
|
+
},
|
|
121728
|
+
capability: {
|
|
121729
|
+
title: "支出限额",
|
|
121730
|
+
description: "为 AI 支出设置上限。此限额开启期间,其覆盖的所有支出都会计入下方金额;达到限额后,由您决定是阻止新请求,还是仅提醒管理员。",
|
|
121731
|
+
offHint: "开启后即开始统计并执行此限额。之后关闭也会保留您在此的配置。"
|
|
121732
|
+
},
|
|
121733
|
+
subTabs: {
|
|
121734
|
+
agent: "此智能体",
|
|
121735
|
+
users: "按用户"
|
|
121736
|
+
},
|
|
121737
|
+
tenantSections: {
|
|
121738
|
+
workspace: {
|
|
121739
|
+
title: "工作区支出限额",
|
|
121740
|
+
description: "一个覆盖此工作区内所有智能体和用户全部支出的限额。按智能体和按用户的限额请在各智能体设置的“账单”中管理。"
|
|
121741
|
+
},
|
|
121742
|
+
noCapStats: {
|
|
121743
|
+
spentThisMonth: "本月已支出",
|
|
121744
|
+
spentAllTime: "累计已支出",
|
|
121745
|
+
hint: "涵盖此工作区内的所有智能体和用户"
|
|
121746
|
+
},
|
|
121747
|
+
agents: {
|
|
121748
|
+
title: "智能体支出限额",
|
|
121749
|
+
description: "此工作区中已配置支出限额的智能体。打开任意一个即可管理其限额及按用户限额。",
|
|
121750
|
+
filter: {
|
|
121751
|
+
label: "搜索智能体",
|
|
121752
|
+
placeholder: "搜索智能体…",
|
|
121753
|
+
typeToSearch: "请输入至少 2 个字符进行搜索",
|
|
121754
|
+
searching: "正在搜索智能体…",
|
|
121755
|
+
noResults: "未找到智能体",
|
|
121756
|
+
clear: "清除智能体筛选"
|
|
121757
|
+
},
|
|
121758
|
+
table: {
|
|
121759
|
+
agentColumn: "智能体",
|
|
121760
|
+
limitColumn: "限额",
|
|
121761
|
+
spentColumn: "已支出",
|
|
121762
|
+
remainingColumn: "剩余",
|
|
121763
|
+
statusColumn: "状态"
|
|
121764
|
+
},
|
|
121765
|
+
emptyState: "尚无智能体支出限额。请在上方搜索智能体进行设置。",
|
|
121766
|
+
emptyFiltered: "此智能体尚未设置支出限额。",
|
|
121767
|
+
setLimitButton: "设置支出限额",
|
|
121768
|
+
manageAria: "管理 {name} 的支出限额",
|
|
121769
|
+
statusToggleAria: "开启或关闭 {name} 的支出限额"
|
|
121770
|
+
}
|
|
121771
|
+
},
|
|
121772
|
+
form: {
|
|
121773
|
+
limitLabel: "支出限额(美元)",
|
|
121774
|
+
limitPlaceholder: "例如 250.00",
|
|
121775
|
+
limitError: "请输入大于 0 的金额",
|
|
121776
|
+
intervalLabel: "重置周期",
|
|
121777
|
+
intervalOptions: {
|
|
121778
|
+
day: "每天",
|
|
121779
|
+
week: "每周",
|
|
121780
|
+
month: "每月",
|
|
121781
|
+
year: "每年"
|
|
121782
|
+
},
|
|
121783
|
+
enforcementLabel: "达到限额时",
|
|
121784
|
+
enforcementOptions: {
|
|
121785
|
+
block: "阻止请求",
|
|
121786
|
+
alertOnly: "仅提醒"
|
|
121787
|
+
},
|
|
121788
|
+
enforcementHelp: {
|
|
121789
|
+
block: "在周期重置前,新的聊天和训练请求将被拒绝。",
|
|
121790
|
+
alertOnly: "不会阻止任何请求——当支出接近限额时通知管理员。"
|
|
121791
|
+
},
|
|
121792
|
+
thresholdsLabel: "提醒阈值(限额百分比)",
|
|
121793
|
+
thresholdsPlaceholder: "例如 80, 95",
|
|
121794
|
+
thresholdsHelp: "以逗号分隔的百分比,达到时管理员会收到接近限额的提醒。",
|
|
121795
|
+
thresholdsError: "请使用 1 到 100 之间、以逗号分隔的数字",
|
|
121796
|
+
noCapHint: "尚未配置支出限额——设置金额并保存即可创建。",
|
|
121797
|
+
save: "保存",
|
|
121798
|
+
saving: "保存中…",
|
|
121799
|
+
remove: "删除限额",
|
|
121800
|
+
removing: "删除中…",
|
|
121801
|
+
cancel: "取消"
|
|
121802
|
+
},
|
|
121803
|
+
usage: {
|
|
121804
|
+
title: "支出限额使用情况",
|
|
121805
|
+
periodTitles: {
|
|
121806
|
+
day: "每日用量",
|
|
121807
|
+
week: "每周用量",
|
|
121808
|
+
month: "每月用量",
|
|
121809
|
+
year: "每年用量"
|
|
121810
|
+
},
|
|
121811
|
+
spent: "已用:{amount}",
|
|
121812
|
+
remaining: "剩余:{amount}",
|
|
121813
|
+
percentUsed: "已使用限额的 {percent}%",
|
|
121814
|
+
exceededBadge: "已达限额",
|
|
121815
|
+
alertOnlyBadge: "仅提醒",
|
|
121816
|
+
disabledBadge: "已关闭"
|
|
121817
|
+
},
|
|
121818
|
+
users: {
|
|
121819
|
+
sectionTitle: "按用户限额",
|
|
121820
|
+
sectionDescription: "限制特定用户在此智能体上的支出。",
|
|
121821
|
+
addButton: "添加用户限额",
|
|
121822
|
+
addTitle: "新建用户限额",
|
|
121823
|
+
editTitle: "编辑用户限额",
|
|
121824
|
+
cancel: "取消",
|
|
121825
|
+
emptyState: "尚无按用户设置的限额。添加一个以限制此智能体上的特定用户。",
|
|
121826
|
+
edit: "编辑",
|
|
121827
|
+
"delete": "删除",
|
|
121828
|
+
table: {
|
|
121829
|
+
userColumn: "用户",
|
|
121830
|
+
limitColumn: "限额",
|
|
121831
|
+
statusColumn: "状态"
|
|
121832
|
+
},
|
|
121833
|
+
actionsAria: "{username} 的操作",
|
|
121834
|
+
statusToggleAria: "开启或关闭 {username} 的支出限额",
|
|
121835
|
+
picker: {
|
|
121836
|
+
label: "用户",
|
|
121837
|
+
placeholder: "搜索用户…",
|
|
121838
|
+
typeToSearch: "请输入至少 2 个字符进行搜索",
|
|
121839
|
+
searching: "正在搜索用户…",
|
|
121840
|
+
noResults: "未找到用户",
|
|
121841
|
+
clear: "更换用户"
|
|
121842
|
+
}
|
|
121843
|
+
},
|
|
121844
|
+
denied: {
|
|
121845
|
+
title: "无权访问支出限额",
|
|
121846
|
+
description: "您没有权限在此查看支出限额。请向管理员申请访问权限。"
|
|
121847
|
+
},
|
|
121848
|
+
deleteModal: {
|
|
121849
|
+
title: "删除支出限额",
|
|
121850
|
+
description: "支出将不再受此限额限制或统计。",
|
|
121851
|
+
cancel: "取消",
|
|
121852
|
+
confirm: "删除"
|
|
121853
|
+
},
|
|
121854
|
+
toasts: {
|
|
121855
|
+
saved: "支出限额已保存",
|
|
121856
|
+
saveError: "无法保存支出限额",
|
|
121857
|
+
deleted: "支出限额已删除",
|
|
121858
|
+
deleteError: "无法删除支出限额"
|
|
121859
|
+
}
|
|
121860
|
+
};
|
|
120807
121861
|
var tabsAlertstab = {
|
|
120808
121862
|
searchAlertsPlaceholder: "搜索提醒",
|
|
120809
121863
|
searchAlertsAriaLabel: "搜索提醒",
|
|
@@ -122547,6 +123601,10 @@ var zh = {
|
|
|
122547
123601
|
componentsPolicyAssignmentSection: componentsPolicyAssignmentSection,
|
|
122548
123602
|
componentsPolicyConfigDialog: componentsPolicyConfigDialog,
|
|
122549
123603
|
componentsProactiveSettingsSection: componentsProactiveSettingsSection,
|
|
123604
|
+
componentsTemplateActionsSection: componentsTemplateActionsSection,
|
|
123605
|
+
componentsTemplateVariablesHelper: componentsTemplateVariablesHelper,
|
|
123606
|
+
componentsUserProgressSettingsSection: componentsUserProgressSettingsSection,
|
|
123607
|
+
componentsWatcherEmailSection: componentsWatcherEmailSection,
|
|
122550
123608
|
courseContentAccessiblePaginate: courseContentAccessiblePaginate,
|
|
122551
123609
|
courseContentCourseContentLayout: courseContentCourseContentLayout,
|
|
122552
123610
|
courseContentDiscoverFacetsFilter: courseContentDiscoverFacetsFilter,
|
|
@@ -122662,6 +123720,8 @@ var zh = {
|
|
|
122662
123720
|
skillsProfileResumeBox: skillsProfileResumeBox,
|
|
122663
123721
|
skillsProfileSkillDetailModal: skillsProfileSkillDetailModal,
|
|
122664
123722
|
skillsProfileSkillsBox: skillsProfileSkillsBox,
|
|
123723
|
+
spendCapUsage: spendCapUsage,
|
|
123724
|
+
spendCapsTabLabels: spendCapsTabLabels,
|
|
122665
123725
|
tabsAlertstab: tabsAlertstab,
|
|
122666
123726
|
tabsDisclaimersTab: tabsDisclaimersTab,
|
|
122667
123727
|
tabsEmbedTab: tabsEmbedTab,
|
|
@@ -188323,6 +189383,1002 @@ function AddCreditsModal({ isOpen, onClose, tenant }) {
|
|
|
188323
189383
|
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')) })] })] })] }) }));
|
|
188324
189384
|
}
|
|
188325
189385
|
|
|
189386
|
+
/**
|
|
189387
|
+
* The info icon that sits on every analytics card and, on hover or keyboard
|
|
189388
|
+
* focus, explains what the card measures. The description doubles as the
|
|
189389
|
+
* accessible name so screen readers get it without needing the hover.
|
|
189390
|
+
*
|
|
189391
|
+
* Uses the tooltip primitives directly rather than the shared `TooltipContent`
|
|
189392
|
+
* because analytics wants a light popover, while `TooltipContent` is the dark
|
|
189393
|
+
* `bg-primary` style the rest of the app relies on.
|
|
189394
|
+
*/
|
|
189395
|
+
function CardInfoIcon({ title, description, className }) {
|
|
189396
|
+
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 })] }) })] }));
|
|
189397
|
+
}
|
|
189398
|
+
|
|
189399
|
+
/**
|
|
189400
|
+
* Shared utilities for tab label systems.
|
|
189401
|
+
*
|
|
189402
|
+
* Every tab exports a `resolve*Labels(override?)` function that deep-merges
|
|
189403
|
+
* a partial override into the default AGENT labels. This file provides the
|
|
189404
|
+
* DeepPartial type and deepMerge implementation they all share.
|
|
189405
|
+
*/
|
|
189406
|
+
function deepMerge(base, override) {
|
|
189407
|
+
const result = { ...base };
|
|
189408
|
+
const overrideBag = override;
|
|
189409
|
+
for (const key of Object.keys(overrideBag)) {
|
|
189410
|
+
const overrideValue = overrideBag[key];
|
|
189411
|
+
if (overrideValue === undefined)
|
|
189412
|
+
continue;
|
|
189413
|
+
const baseValue = base[key];
|
|
189414
|
+
if (baseValue &&
|
|
189415
|
+
typeof baseValue === 'object' &&
|
|
189416
|
+
!Array.isArray(baseValue) &&
|
|
189417
|
+
overrideValue &&
|
|
189418
|
+
typeof overrideValue === 'object' &&
|
|
189419
|
+
!Array.isArray(overrideValue)) {
|
|
189420
|
+
result[key] = deepMerge(baseValue, overrideValue);
|
|
189421
|
+
}
|
|
189422
|
+
else {
|
|
189423
|
+
result[key] = overrideValue;
|
|
189424
|
+
}
|
|
189425
|
+
}
|
|
189426
|
+
return result;
|
|
189427
|
+
}
|
|
189428
|
+
|
|
189429
|
+
const AGENT_SPEND_CAPS_TAB_LABELS = {
|
|
189430
|
+
header: {
|
|
189431
|
+
title: 'Billing',
|
|
189432
|
+
description: 'Set spend limits for this agent and its users, and see how much has been used.',
|
|
189433
|
+
},
|
|
189434
|
+
capability: {
|
|
189435
|
+
title: 'Spend Limit',
|
|
189436
|
+
description: 'Put a ceiling on AI spend. While this limit is on, everything it covers counts toward the amount below — and when the limit is reached, you choose whether new requests are blocked or admins are simply alerted.',
|
|
189437
|
+
offHint: 'Turn it on to start tracking and enforcing this limit. Your setup here is kept safe if you later turn it off.',
|
|
189438
|
+
},
|
|
189439
|
+
subTabs: {
|
|
189440
|
+
agent: 'This Agent',
|
|
189441
|
+
users: 'Per User',
|
|
189442
|
+
},
|
|
189443
|
+
tenantSections: {
|
|
189444
|
+
workspace: {
|
|
189445
|
+
title: 'Workspace Spend Limit',
|
|
189446
|
+
description: 'One limit covering everything all agents and users spend in this workspace. Per-agent and per-user limits live in each agent’s settings under Billing.',
|
|
189447
|
+
},
|
|
189448
|
+
noCapStats: {
|
|
189449
|
+
spentThisMonth: 'Spent This Month',
|
|
189450
|
+
spentAllTime: 'Spent All Time',
|
|
189451
|
+
hint: 'Across all agents and users in this workspace',
|
|
189452
|
+
},
|
|
189453
|
+
agents: {
|
|
189454
|
+
title: 'Agent Spend Limits',
|
|
189455
|
+
description: 'Agents with a spend limit configured in this workspace. Open one to manage its limit and its per-user limits.',
|
|
189456
|
+
filter: {
|
|
189457
|
+
label: 'Search Agents',
|
|
189458
|
+
placeholder: 'Search Agents…',
|
|
189459
|
+
typeToSearch: 'Type at least 2 characters to search',
|
|
189460
|
+
searching: 'Searching agents…',
|
|
189461
|
+
noResults: 'No agents found',
|
|
189462
|
+
clear: 'Clear Agent Filter',
|
|
189463
|
+
},
|
|
189464
|
+
table: {
|
|
189465
|
+
agentColumn: 'Agent',
|
|
189466
|
+
limitColumn: 'Limit',
|
|
189467
|
+
spentColumn: 'Spent',
|
|
189468
|
+
remainingColumn: 'Remaining',
|
|
189469
|
+
statusColumn: 'Status',
|
|
189470
|
+
},
|
|
189471
|
+
emptyState: 'No agent spend limits yet. Search for an agent above to set one.',
|
|
189472
|
+
emptyFiltered: 'No spend limit for this agent yet.',
|
|
189473
|
+
setLimitButton: 'Set Spend Limit',
|
|
189474
|
+
manageAria: (name) => `Manage spend limits for ${name}`,
|
|
189475
|
+
statusToggleAria: (name) => `Toggle spend limit for ${name}`,
|
|
189476
|
+
},
|
|
189477
|
+
},
|
|
189478
|
+
form: {
|
|
189479
|
+
limitLabel: 'Spend Limit (USD)',
|
|
189480
|
+
limitPlaceholder: 'e.g. 250.00',
|
|
189481
|
+
limitError: 'Enter an amount greater than 0',
|
|
189482
|
+
intervalLabel: 'Resets Every',
|
|
189483
|
+
intervalOptions: {
|
|
189484
|
+
day: 'Day',
|
|
189485
|
+
week: 'Week',
|
|
189486
|
+
month: 'Month',
|
|
189487
|
+
year: 'Year',
|
|
189488
|
+
},
|
|
189489
|
+
enforcementLabel: 'When the Limit Is Reached',
|
|
189490
|
+
enforcementOptions: {
|
|
189491
|
+
block: 'Block Requests',
|
|
189492
|
+
alertOnly: 'Alert Only',
|
|
189493
|
+
},
|
|
189494
|
+
enforcementHelp: {
|
|
189495
|
+
block: 'New chat and training requests are refused until the period resets.',
|
|
189496
|
+
alertOnly: 'Nothing is blocked — admins are notified when spend nears the limit.',
|
|
189497
|
+
},
|
|
189498
|
+
thresholdsLabel: 'Alert At (% of Limit)',
|
|
189499
|
+
thresholdsPlaceholder: 'e.g. 80, 95',
|
|
189500
|
+
thresholdsHelp: 'Comma-separated percentages at which admins get a near-limit alert.',
|
|
189501
|
+
thresholdsError: 'Use comma-separated numbers between 1 and 100',
|
|
189502
|
+
noCapHint: 'No spend limit configured yet — set an amount and save to create one.',
|
|
189503
|
+
save: 'Save',
|
|
189504
|
+
saving: 'Saving…',
|
|
189505
|
+
cancel: 'Cancel',
|
|
189506
|
+
remove: 'Delete Limit',
|
|
189507
|
+
removing: 'Deleting…',
|
|
189508
|
+
},
|
|
189509
|
+
usage: {
|
|
189510
|
+
title: 'Spend Limit Usage',
|
|
189511
|
+
periodTitles: {
|
|
189512
|
+
day: 'Daily Usage',
|
|
189513
|
+
week: 'Weekly Usage',
|
|
189514
|
+
month: 'Monthly Usage',
|
|
189515
|
+
year: 'Yearly Usage',
|
|
189516
|
+
},
|
|
189517
|
+
spent: 'Spent: {amount}',
|
|
189518
|
+
remaining: 'Remaining: {amount}',
|
|
189519
|
+
percentUsed: '{percent}% of limit used',
|
|
189520
|
+
exceededBadge: 'Limit Reached',
|
|
189521
|
+
alertOnlyBadge: 'Alert Only',
|
|
189522
|
+
disabledBadge: 'Off',
|
|
189523
|
+
},
|
|
189524
|
+
users: {
|
|
189525
|
+
sectionTitle: 'Per-User Limits',
|
|
189526
|
+
sectionDescription: 'Limit what specific users can spend on this agent.',
|
|
189527
|
+
addButton: 'Add User Limit',
|
|
189528
|
+
addTitle: 'New User Limit',
|
|
189529
|
+
editTitle: 'Edit User Limit',
|
|
189530
|
+
cancel: 'Cancel',
|
|
189531
|
+
emptyState: 'No per-user limits yet. Add one to limit a specific user on this agent.',
|
|
189532
|
+
edit: 'Edit',
|
|
189533
|
+
delete: 'Delete',
|
|
189534
|
+
table: {
|
|
189535
|
+
userColumn: 'User',
|
|
189536
|
+
limitColumn: 'Limit',
|
|
189537
|
+
statusColumn: 'Status',
|
|
189538
|
+
},
|
|
189539
|
+
actionsAria: (username) => `Actions for ${username}`,
|
|
189540
|
+
statusToggleAria: (username) => `Toggle spend limit for ${username}`,
|
|
189541
|
+
picker: {
|
|
189542
|
+
label: 'User',
|
|
189543
|
+
placeholder: 'Search Users…',
|
|
189544
|
+
typeToSearch: 'Type at least 2 characters to search',
|
|
189545
|
+
searching: 'Searching users…',
|
|
189546
|
+
noResults: 'No users found',
|
|
189547
|
+
clear: 'Change User',
|
|
189548
|
+
},
|
|
189549
|
+
},
|
|
189550
|
+
denied: {
|
|
189551
|
+
title: 'No Access to Spend Limits',
|
|
189552
|
+
description: "You don't have permission to view spend limits here. Ask an administrator for access.",
|
|
189553
|
+
},
|
|
189554
|
+
deleteModal: {
|
|
189555
|
+
title: 'Delete Spend Limit',
|
|
189556
|
+
description: 'Spending will no longer be limited or tracked against this limit.',
|
|
189557
|
+
cancel: 'Cancel',
|
|
189558
|
+
confirm: 'Delete',
|
|
189559
|
+
},
|
|
189560
|
+
toasts: {
|
|
189561
|
+
saved: 'Spend limit saved',
|
|
189562
|
+
saveError: "Couldn't save the spend limit",
|
|
189563
|
+
deleted: 'Spend limit deleted',
|
|
189564
|
+
deleteError: "Couldn't delete the spend limit",
|
|
189565
|
+
},
|
|
189566
|
+
};
|
|
189567
|
+
function buildSpendCapsTabLabels(t) {
|
|
189568
|
+
return {
|
|
189569
|
+
header: {
|
|
189570
|
+
title: t('spendCapsTabLabels.header.title'),
|
|
189571
|
+
description: t('spendCapsTabLabels.header.description'),
|
|
189572
|
+
},
|
|
189573
|
+
capability: {
|
|
189574
|
+
title: t('spendCapsTabLabels.capability.title'),
|
|
189575
|
+
description: t('spendCapsTabLabels.capability.description'),
|
|
189576
|
+
offHint: t('spendCapsTabLabels.capability.offHint'),
|
|
189577
|
+
},
|
|
189578
|
+
subTabs: {
|
|
189579
|
+
agent: t('spendCapsTabLabels.subTabs.agent'),
|
|
189580
|
+
users: t('spendCapsTabLabels.subTabs.users'),
|
|
189581
|
+
},
|
|
189582
|
+
tenantSections: {
|
|
189583
|
+
workspace: {
|
|
189584
|
+
title: t('spendCapsTabLabels.tenantSections.workspace.title'),
|
|
189585
|
+
description: t('spendCapsTabLabels.tenantSections.workspace.description'),
|
|
189586
|
+
},
|
|
189587
|
+
noCapStats: {
|
|
189588
|
+
spentThisMonth: t('spendCapsTabLabels.tenantSections.noCapStats.spentThisMonth'),
|
|
189589
|
+
spentAllTime: t('spendCapsTabLabels.tenantSections.noCapStats.spentAllTime'),
|
|
189590
|
+
hint: t('spendCapsTabLabels.tenantSections.noCapStats.hint'),
|
|
189591
|
+
},
|
|
189592
|
+
agents: {
|
|
189593
|
+
title: t('spendCapsTabLabels.tenantSections.agents.title'),
|
|
189594
|
+
description: t('spendCapsTabLabels.tenantSections.agents.description'),
|
|
189595
|
+
filter: {
|
|
189596
|
+
label: t('spendCapsTabLabels.tenantSections.agents.filter.label'),
|
|
189597
|
+
placeholder: t('spendCapsTabLabels.tenantSections.agents.filter.placeholder'),
|
|
189598
|
+
typeToSearch: t('spendCapsTabLabels.tenantSections.agents.filter.typeToSearch'),
|
|
189599
|
+
searching: t('spendCapsTabLabels.tenantSections.agents.filter.searching'),
|
|
189600
|
+
noResults: t('spendCapsTabLabels.tenantSections.agents.filter.noResults'),
|
|
189601
|
+
clear: t('spendCapsTabLabels.tenantSections.agents.filter.clear'),
|
|
189602
|
+
},
|
|
189603
|
+
table: {
|
|
189604
|
+
agentColumn: t('spendCapsTabLabels.tenantSections.agents.table.agentColumn'),
|
|
189605
|
+
limitColumn: t('spendCapsTabLabels.tenantSections.agents.table.limitColumn'),
|
|
189606
|
+
spentColumn: t('spendCapsTabLabels.tenantSections.agents.table.spentColumn'),
|
|
189607
|
+
remainingColumn: t('spendCapsTabLabels.tenantSections.agents.table.remainingColumn'),
|
|
189608
|
+
statusColumn: t('spendCapsTabLabels.tenantSections.agents.table.statusColumn'),
|
|
189609
|
+
},
|
|
189610
|
+
emptyState: t('spendCapsTabLabels.tenantSections.agents.emptyState'),
|
|
189611
|
+
emptyFiltered: t('spendCapsTabLabels.tenantSections.agents.emptyFiltered'),
|
|
189612
|
+
setLimitButton: t('spendCapsTabLabels.tenantSections.agents.setLimitButton'),
|
|
189613
|
+
manageAria: (name) => t('spendCapsTabLabels.tenantSections.agents.manageAria', { name }),
|
|
189614
|
+
statusToggleAria: (name) => t('spendCapsTabLabels.tenantSections.agents.statusToggleAria', { name }),
|
|
189615
|
+
},
|
|
189616
|
+
},
|
|
189617
|
+
form: {
|
|
189618
|
+
limitLabel: t('spendCapsTabLabels.form.limitLabel'),
|
|
189619
|
+
limitPlaceholder: t('spendCapsTabLabels.form.limitPlaceholder'),
|
|
189620
|
+
limitError: t('spendCapsTabLabels.form.limitError'),
|
|
189621
|
+
intervalLabel: t('spendCapsTabLabels.form.intervalLabel'),
|
|
189622
|
+
intervalOptions: {
|
|
189623
|
+
day: t('spendCapsTabLabels.form.intervalOptions.day'),
|
|
189624
|
+
week: t('spendCapsTabLabels.form.intervalOptions.week'),
|
|
189625
|
+
month: t('spendCapsTabLabels.form.intervalOptions.month'),
|
|
189626
|
+
year: t('spendCapsTabLabels.form.intervalOptions.year'),
|
|
189627
|
+
},
|
|
189628
|
+
enforcementLabel: t('spendCapsTabLabels.form.enforcementLabel'),
|
|
189629
|
+
enforcementOptions: {
|
|
189630
|
+
block: t('spendCapsTabLabels.form.enforcementOptions.block'),
|
|
189631
|
+
alertOnly: t('spendCapsTabLabels.form.enforcementOptions.alertOnly'),
|
|
189632
|
+
},
|
|
189633
|
+
enforcementHelp: {
|
|
189634
|
+
block: t('spendCapsTabLabels.form.enforcementHelp.block'),
|
|
189635
|
+
alertOnly: t('spendCapsTabLabels.form.enforcementHelp.alertOnly'),
|
|
189636
|
+
},
|
|
189637
|
+
thresholdsLabel: t('spendCapsTabLabels.form.thresholdsLabel'),
|
|
189638
|
+
thresholdsPlaceholder: t('spendCapsTabLabels.form.thresholdsPlaceholder'),
|
|
189639
|
+
thresholdsHelp: t('spendCapsTabLabels.form.thresholdsHelp'),
|
|
189640
|
+
thresholdsError: t('spendCapsTabLabels.form.thresholdsError'),
|
|
189641
|
+
noCapHint: t('spendCapsTabLabels.form.noCapHint'),
|
|
189642
|
+
save: t('spendCapsTabLabels.form.save'),
|
|
189643
|
+
saving: t('spendCapsTabLabels.form.saving'),
|
|
189644
|
+
cancel: t('spendCapsTabLabels.form.cancel'),
|
|
189645
|
+
remove: t('spendCapsTabLabels.form.remove'),
|
|
189646
|
+
removing: t('spendCapsTabLabels.form.removing'),
|
|
189647
|
+
},
|
|
189648
|
+
usage: {
|
|
189649
|
+
title: t('spendCapsTabLabels.usage.title'),
|
|
189650
|
+
periodTitles: {
|
|
189651
|
+
day: t('spendCapsTabLabels.usage.periodTitles.day'),
|
|
189652
|
+
week: t('spendCapsTabLabels.usage.periodTitles.week'),
|
|
189653
|
+
month: t('spendCapsTabLabels.usage.periodTitles.month'),
|
|
189654
|
+
year: t('spendCapsTabLabels.usage.periodTitles.year'),
|
|
189655
|
+
},
|
|
189656
|
+
spent: t('spendCapsTabLabels.usage.spent'),
|
|
189657
|
+
remaining: t('spendCapsTabLabels.usage.remaining'),
|
|
189658
|
+
percentUsed: t('spendCapsTabLabels.usage.percentUsed'),
|
|
189659
|
+
exceededBadge: t('spendCapsTabLabels.usage.exceededBadge'),
|
|
189660
|
+
alertOnlyBadge: t('spendCapsTabLabels.usage.alertOnlyBadge'),
|
|
189661
|
+
disabledBadge: t('spendCapsTabLabels.usage.disabledBadge'),
|
|
189662
|
+
},
|
|
189663
|
+
users: {
|
|
189664
|
+
sectionTitle: t('spendCapsTabLabels.users.sectionTitle'),
|
|
189665
|
+
sectionDescription: t('spendCapsTabLabels.users.sectionDescription'),
|
|
189666
|
+
addButton: t('spendCapsTabLabels.users.addButton'),
|
|
189667
|
+
addTitle: t('spendCapsTabLabels.users.addTitle'),
|
|
189668
|
+
editTitle: t('spendCapsTabLabels.users.editTitle'),
|
|
189669
|
+
cancel: t('spendCapsTabLabels.users.cancel'),
|
|
189670
|
+
emptyState: t('spendCapsTabLabels.users.emptyState'),
|
|
189671
|
+
edit: t('spendCapsTabLabels.users.edit'),
|
|
189672
|
+
delete: t('spendCapsTabLabels.users.delete'),
|
|
189673
|
+
table: {
|
|
189674
|
+
userColumn: t('spendCapsTabLabels.users.table.userColumn'),
|
|
189675
|
+
limitColumn: t('spendCapsTabLabels.users.table.limitColumn'),
|
|
189676
|
+
statusColumn: t('spendCapsTabLabels.users.table.statusColumn'),
|
|
189677
|
+
},
|
|
189678
|
+
actionsAria: (username) => t('spendCapsTabLabels.users.actionsAria', { username }),
|
|
189679
|
+
statusToggleAria: (username) => t('spendCapsTabLabels.users.statusToggleAria', { username }),
|
|
189680
|
+
picker: {
|
|
189681
|
+
label: t('spendCapsTabLabels.users.picker.label'),
|
|
189682
|
+
placeholder: t('spendCapsTabLabels.users.picker.placeholder'),
|
|
189683
|
+
typeToSearch: t('spendCapsTabLabels.users.picker.typeToSearch'),
|
|
189684
|
+
searching: t('spendCapsTabLabels.users.picker.searching'),
|
|
189685
|
+
noResults: t('spendCapsTabLabels.users.picker.noResults'),
|
|
189686
|
+
clear: t('spendCapsTabLabels.users.picker.clear'),
|
|
189687
|
+
},
|
|
189688
|
+
},
|
|
189689
|
+
denied: {
|
|
189690
|
+
title: t('spendCapsTabLabels.denied.title'),
|
|
189691
|
+
description: t('spendCapsTabLabels.denied.description'),
|
|
189692
|
+
},
|
|
189693
|
+
deleteModal: {
|
|
189694
|
+
title: t('spendCapsTabLabels.deleteModal.title'),
|
|
189695
|
+
description: t('spendCapsTabLabels.deleteModal.description'),
|
|
189696
|
+
cancel: t('spendCapsTabLabels.deleteModal.cancel'),
|
|
189697
|
+
confirm: t('spendCapsTabLabels.deleteModal.confirm'),
|
|
189698
|
+
},
|
|
189699
|
+
toasts: {
|
|
189700
|
+
saved: t('spendCapsTabLabels.toasts.saved'),
|
|
189701
|
+
saveError: t('spendCapsTabLabels.toasts.saveError'),
|
|
189702
|
+
deleted: t('spendCapsTabLabels.toasts.deleted'),
|
|
189703
|
+
deleteError: t('spendCapsTabLabels.toasts.deleteError'),
|
|
189704
|
+
},
|
|
189705
|
+
};
|
|
189706
|
+
}
|
|
189707
|
+
function resolveSpendCapsTabLabels(override, t) {
|
|
189708
|
+
const base = t ? buildSpendCapsTabLabels(t) : AGENT_SPEND_CAPS_TAB_LABELS;
|
|
189709
|
+
if (!override)
|
|
189710
|
+
return base;
|
|
189711
|
+
return deepMerge(base, override);
|
|
189712
|
+
}
|
|
189713
|
+
|
|
189714
|
+
const CustomSwitch = React.forwardRef(({ className, checked, onCheckedChange, ...props }, ref) => (jsx(Root$c, { checked: checked, onCheckedChange: onCheckedChange, className: cn('peer focus-visible:ring-ring focus-visible:ring-offset-background inline-flex h-6 w-11 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent transition-colors focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-none disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-blue-500 data-[state=unchecked]:bg-gray-200', className), ...props, ref: ref, children: jsx(Thumb, { className: cn('pointer-events-none block h-5 w-5 rounded-full bg-white shadow-lg ring-0 transition-transform data-[state=checked]:translate-x-5 data-[state=unchecked]:translate-x-0') }) })));
|
|
189715
|
+
CustomSwitch.displayName = Root$c.displayName;
|
|
189716
|
+
|
|
189717
|
+
/**
|
|
189718
|
+
* Reusable header used at the top of every capability-gated agent-settings
|
|
189719
|
+
* tab. It surfaces the capability's on/off toggle (previously buried in the
|
|
189720
|
+
* Settings → Capabilities list) right where the feature is configured, with a
|
|
189721
|
+
* naive-friendly explanation.
|
|
189722
|
+
*
|
|
189723
|
+
* The configuration UI below is always rendered so admins can preview what
|
|
189724
|
+
* they'll get, but it's grayed out and made inert (`pointer-events-none`,
|
|
189725
|
+
* `aria-hidden`) until the capability is switched on.
|
|
189726
|
+
*/
|
|
189727
|
+
function CapabilityGate({ title, description, enabled, onToggle, disabled = false, ariaLabel, offHint, toggleTestId, children, }) {
|
|
189728
|
+
return (jsxs("div", { className: "space-y-4", children: [jsxs("div", { className: "flex items-start justify-between gap-4 rounded-lg border border-gray-200 bg-gray-50/60 p-4", "data-testid": "capability-gate-header", children: [jsx("div", { className: "min-w-0", children: jsxs("p", { className: "text-xs leading-relaxed text-gray-600", children: [description, !enabled && offHint && (jsxs("span", { className: "font-medium text-gray-500", "data-testid": "capability-gate-off-hint", children: [' ', offHint] }))] }) }), jsx(CustomSwitch, { checked: enabled, onCheckedChange: onToggle, disabled: disabled, "aria-label": ariaLabel !== null && ariaLabel !== void 0 ? ariaLabel : title, "aria-checked": enabled, "data-testid": toggleTestId, className: "mt-0.5 flex-shrink-0" })] }), jsx("div", { className: cn('transition-opacity', !enabled && 'pointer-events-none select-none opacity-50'), "aria-hidden": !enabled, inert: !enabled, "data-testid": "capability-gate-content", "data-enabled": enabled, children: children })] }));
|
|
189729
|
+
}
|
|
189730
|
+
|
|
189731
|
+
/**
|
|
189732
|
+
* Pure helpers for the spend-caps tab. The backend stores alert thresholds as
|
|
189733
|
+
* fractions of the limit (0.8 = 80%) while the form edits them as a
|
|
189734
|
+
* comma-separated percentage list, and dollar fields travel as decimal strings.
|
|
189735
|
+
*/
|
|
189736
|
+
/** Format a backend decimal string as a dollar amount, e.g. "30.500000" → "$30.50". */
|
|
189737
|
+
function formatUsd$1(value) {
|
|
189738
|
+
const parsed = Number(value);
|
|
189739
|
+
if (value == null || value === '' || Number.isNaN(parsed))
|
|
189740
|
+
return '$0.00';
|
|
189741
|
+
return `$${parsed.toFixed(2)}`;
|
|
189742
|
+
}
|
|
189743
|
+
/** Fractions → editable percent list: [0.8, 0.95] → "80, 95". */
|
|
189744
|
+
function thresholdsToInput(thresholds) {
|
|
189745
|
+
if (!Array.isArray(thresholds))
|
|
189746
|
+
return '';
|
|
189747
|
+
return thresholds
|
|
189748
|
+
.filter((value) => typeof value === 'number' && !Number.isNaN(value))
|
|
189749
|
+
.map((value) => {
|
|
189750
|
+
const percent = value * 100;
|
|
189751
|
+
return Number.isInteger(percent) ? String(percent) : percent.toFixed(1);
|
|
189752
|
+
})
|
|
189753
|
+
.join(', ');
|
|
189754
|
+
}
|
|
189755
|
+
/**
|
|
189756
|
+
* Percent list → fractions: "80, 95" → [0.8, 0.95]. Empty input is valid and
|
|
189757
|
+
* means "keep the backend default". Returns null when any entry is not a
|
|
189758
|
+
* number in (0, 100].
|
|
189759
|
+
*/
|
|
189760
|
+
function parseThresholdsInput(input) {
|
|
189761
|
+
const trimmed = input.trim();
|
|
189762
|
+
if (trimmed === '')
|
|
189763
|
+
return [];
|
|
189764
|
+
const parts = trimmed.split(',').map((part) => part.trim());
|
|
189765
|
+
const fractions = [];
|
|
189766
|
+
for (const part of parts) {
|
|
189767
|
+
if (part === '')
|
|
189768
|
+
return null;
|
|
189769
|
+
const percent = Number(part);
|
|
189770
|
+
if (Number.isNaN(percent) || percent <= 0 || percent > 100)
|
|
189771
|
+
return null;
|
|
189772
|
+
fractions.push(percent / 100);
|
|
189773
|
+
}
|
|
189774
|
+
return fractions;
|
|
189775
|
+
}
|
|
189776
|
+
/** A valid limit is any number strictly greater than 0. */
|
|
189777
|
+
function isValidLimit(input) {
|
|
189778
|
+
const parsed = Number(input);
|
|
189779
|
+
return input.trim() !== '' && !Number.isNaN(parsed) && parsed > 0;
|
|
189780
|
+
}
|
|
189781
|
+
/** Percent of the limit already spent, clamped to [0, 100] for progress bars. */
|
|
189782
|
+
function percentUsed(currentSpend, maxCost) {
|
|
189783
|
+
const spent = Number(currentSpend);
|
|
189784
|
+
const limit = Number(maxCost);
|
|
189785
|
+
if (Number.isNaN(spent) || Number.isNaN(limit) || limit <= 0)
|
|
189786
|
+
return 0;
|
|
189787
|
+
return Math.min(100, Math.max(0, Math.round((spent / limit) * 100)));
|
|
189788
|
+
}
|
|
189789
|
+
|
|
189790
|
+
/**
|
|
189791
|
+
* Editor for one spend cap of any scope. Counter fields
|
|
189792
|
+
* (current spend / remaining / exceeded) are read-only on the backend and
|
|
189793
|
+
* only rendered, never submitted.
|
|
189794
|
+
*/
|
|
189795
|
+
function SpendCapForm({ labels, cap, isSaving, isDeleting, onSave, onDelete, onCancel, showUsage = true, testId, }) {
|
|
189796
|
+
const [limit, setLimit] = React__default.useState('');
|
|
189797
|
+
const [interval, setInterval] = React__default.useState('month');
|
|
189798
|
+
const [enforcement, setEnforcement] = React__default.useState('block');
|
|
189799
|
+
const [thresholds, setThresholds] = React__default.useState('80, 95');
|
|
189800
|
+
const [enabled, setEnabled] = React__default.useState(true);
|
|
189801
|
+
// Rehydrate the form whenever the server copy changes.
|
|
189802
|
+
React__default.useEffect(() => {
|
|
189803
|
+
var _a, _b, _c;
|
|
189804
|
+
setLimit(cap ? String(Number(cap.max_cost_usd)) : '');
|
|
189805
|
+
setInterval((_a = cap === null || cap === void 0 ? void 0 : cap.interval_type) !== null && _a !== void 0 ? _a : 'month');
|
|
189806
|
+
setEnforcement((_b = cap === null || cap === void 0 ? void 0 : cap.enforcement) !== null && _b !== void 0 ? _b : 'block');
|
|
189807
|
+
setThresholds(cap ? thresholdsToInput(cap.alert_thresholds) : '80, 95');
|
|
189808
|
+
setEnabled((_c = cap === null || cap === void 0 ? void 0 : cap.enabled) !== null && _c !== void 0 ? _c : true);
|
|
189809
|
+
}, [cap === null || cap === void 0 ? void 0 : cap.id, cap === null || cap === void 0 ? void 0 : cap.updated_at]); // eslint-disable-line react-hooks/exhaustive-deps
|
|
189810
|
+
const limitTouched = limit.trim() !== '';
|
|
189811
|
+
const limitValid = isValidLimit(limit);
|
|
189812
|
+
const parsedThresholds = parseThresholdsInput(thresholds);
|
|
189813
|
+
const thresholdsValid = parsedThresholds !== null;
|
|
189814
|
+
const canSave = limitValid && thresholdsValid && !isSaving && !isDeleting;
|
|
189815
|
+
const handleSave = () => {
|
|
189816
|
+
const formData = {
|
|
189817
|
+
interval_type: interval,
|
|
189818
|
+
max_cost_usd: Number(limit).toFixed(2),
|
|
189819
|
+
enforcement,
|
|
189820
|
+
enabled,
|
|
189821
|
+
};
|
|
189822
|
+
if (parsedThresholds && parsedThresholds.length > 0) {
|
|
189823
|
+
formData.alert_thresholds = parsedThresholds;
|
|
189824
|
+
}
|
|
189825
|
+
onSave(formData);
|
|
189826
|
+
};
|
|
189827
|
+
const usagePercent = cap ? percentUsed(cap.current_spend_usd, cap.max_cost_usd) : 0;
|
|
189828
|
+
const barColor = (cap === null || cap === void 0 ? void 0 : cap.is_exceeded)
|
|
189829
|
+
? 'bg-red-500'
|
|
189830
|
+
: usagePercent >= 80
|
|
189831
|
+
? 'bg-amber-500'
|
|
189832
|
+
: 'bg-blue-500';
|
|
189833
|
+
return (jsxs("div", { className: "space-y-4", "data-testid": `${testId}-form`, children: [!cap && (jsx("p", { className: "text-xs text-gray-500", "data-testid": `${testId}-no-cap-hint`, children: labels.form.noCapHint })), jsx(CapabilityGate, { title: labels.capability.title, description: labels.capability.description, offHint: labels.capability.offHint, enabled: enabled, onToggle: setEnabled, disabled: isSaving || isDeleting, ariaLabel: labels.capability.title, toggleTestId: `${testId}-enabled-switch`, children: jsxs("div", { className: "space-y-4", children: [cap && showUsage && (jsxs("div", { className: "space-y-2 rounded-lg border border-gray-200 bg-gray-50 p-3", "data-testid": `${testId}-usage`, children: [jsxs("div", { className: "flex items-center justify-between", children: [jsx("p", { className: "text-xs font-medium text-gray-700", children: labels.usage.periodTitles[cap.interval_type] }), jsxs("div", { className: "flex items-center gap-1.5", children: [!cap.enabled && (jsx("span", { className: "rounded-full bg-gray-200 px-2 py-0.5 text-[11px] font-medium text-gray-700", "data-testid": `${testId}-disabled-badge`, children: labels.usage.disabledBadge })), cap.enforcement === 'alert_only' && (jsx("span", { className: "rounded-full bg-amber-100 px-2 py-0.5 text-[11px] font-medium text-amber-800", "data-testid": `${testId}-alert-only-badge`, children: labels.usage.alertOnlyBadge })), cap.is_exceeded && (jsx("span", { className: "rounded-full bg-red-100 px-2 py-0.5 text-[11px] font-medium text-red-700", "data-testid": `${testId}-exceeded-badge`, children: labels.usage.exceededBadge }))] })] }), jsx("div", { className: "h-2 w-full overflow-hidden rounded-full bg-gray-200", role: "progressbar", "aria-valuenow": usagePercent, "aria-valuemin": 0, "aria-valuemax": 100, "aria-label": labels.usage.title, children: jsx("div", { className: `h-full rounded-full transition-all ${barColor}`, style: { width: `${usagePercent}%` } }) }), jsxs("div", { className: "flex items-center justify-between text-xs text-gray-600", children: [jsx("span", { "data-testid": `${testId}-spent`, children: labels.usage.spent.replace('{amount}', formatUsd$1(cap.current_spend_usd)) }), jsx("span", { "data-testid": `${testId}-percent`, children: labels.usage.percentUsed.replace('{percent}', String(usagePercent)) }), jsx("span", { "data-testid": `${testId}-remaining`, children: labels.usage.remaining.replace('{amount}', formatUsd$1(cap.remaining_usd)) })] })] })), jsxs("div", { className: "grid grid-cols-1 gap-4 md:grid-cols-2", children: [jsxs("div", { className: "space-y-1.5", children: [jsx(Label$1, { className: "text-xs font-medium text-gray-700", children: labels.form.limitLabel }), jsx(Input, { className: "focus-visible:border-blue-500 focus-visible:ring-1 focus-visible:ring-blue-500", value: limit, onChange: (e) => setLimit(e.target.value), placeholder: labels.form.limitPlaceholder, inputMode: "decimal", "data-testid": `${testId}-limit-input` }), limitTouched && !limitValid && (jsx("p", { className: "text-xs text-red-500", "data-testid": `${testId}-limit-error`, children: labels.form.limitError }))] }), jsxs("div", { className: "space-y-1.5", children: [jsx(Label$1, { className: "text-xs font-medium text-gray-700", children: labels.form.intervalLabel }), jsxs(Select$1, { value: interval, onValueChange: (value) => setInterval(value), children: [jsx(SelectTrigger, { className: "h-9", "data-testid": `${testId}-interval-select`, children: jsx(SelectValue, {}) }), jsxs(SelectContent, { children: [jsx(SelectItem, { value: "day", children: labels.form.intervalOptions.day }), jsx(SelectItem, { value: "week", children: labels.form.intervalOptions.week }), jsx(SelectItem, { value: "month", children: labels.form.intervalOptions.month }), jsx(SelectItem, { value: "year", children: labels.form.intervalOptions.year })] })] })] })] }), jsxs("div", { className: "grid grid-cols-1 gap-4 md:grid-cols-2", children: [jsxs("div", { className: "space-y-1.5", children: [jsx(Label$1, { className: "text-xs font-medium text-gray-700", children: labels.form.enforcementLabel }), jsxs(Select$1, { value: enforcement, onValueChange: (value) => setEnforcement(value), children: [jsx(SelectTrigger, { className: "h-9", "data-testid": `${testId}-enforcement-select`, children: jsx(SelectValue, {}) }), jsxs(SelectContent, { children: [jsx(SelectItem, { value: "block", children: labels.form.enforcementOptions.block }), jsx(SelectItem, { value: "alert_only", children: labels.form.enforcementOptions.alertOnly })] })] }), jsx("p", { className: "text-xs text-gray-500", children: enforcement === 'block'
|
|
189834
|
+
? labels.form.enforcementHelp.block
|
|
189835
|
+
: labels.form.enforcementHelp.alertOnly })] }), jsxs("div", { className: "space-y-1.5", children: [jsx(Label$1, { className: "text-xs font-medium text-gray-700", children: labels.form.thresholdsLabel }), jsx(Input, { className: "focus-visible:border-blue-500 focus-visible:ring-1 focus-visible:ring-blue-500", value: thresholds, onChange: (e) => setThresholds(e.target.value), placeholder: labels.form.thresholdsPlaceholder, "data-testid": `${testId}-thresholds-input` }), thresholdsValid ? (jsx("p", { className: "text-xs text-gray-500", children: labels.form.thresholdsHelp })) : (jsx("p", { className: "text-xs text-red-500", "data-testid": `${testId}-thresholds-error`, children: labels.form.thresholdsError }))] })] })] }) }), jsxs("div", { className: "flex items-center justify-end gap-2", children: [onCancel && (jsx("button", { type: "button", onClick: onCancel, disabled: isSaving || isDeleting, "data-testid": `${testId}-cancel-button`, className: "inline-flex items-center rounded-md border border-gray-200 px-4 py-2 text-sm font-medium text-gray-700 hover:bg-gray-50 disabled:cursor-not-allowed disabled:opacity-50", children: labels.form.cancel })), cap && onDelete && (jsx("button", { type: "button", onClick: onDelete, disabled: isSaving || isDeleting, "data-testid": `${testId}-delete-button`, className: "inline-flex items-center rounded-md border border-red-200 px-4 py-2 text-sm font-medium text-red-600 hover:bg-red-50 disabled:cursor-not-allowed disabled:opacity-50", children: isDeleting ? labels.form.removing : labels.form.remove })), jsx("button", { type: "button", onClick: handleSave, disabled: !canSave, "data-testid": `${testId}-save-button`, className: "inline-flex items-center gap-2 rounded-md bg-gradient-to-r from-[#2563EB] to-[#93C5FD] px-4 py-2 text-sm font-medium text-white hover:opacity-90 disabled:cursor-not-allowed disabled:opacity-50", children: isSaving ? labels.form.saving : labels.form.save })] })] }));
|
|
189836
|
+
}
|
|
189837
|
+
|
|
189838
|
+
function errorStatus$2(error) {
|
|
189839
|
+
return error === null || error === void 0 ? void 0 : error.status;
|
|
189840
|
+
}
|
|
189841
|
+
function errorDetail$2(error) {
|
|
189842
|
+
const data = error === null || error === void 0 ? void 0 : error.data;
|
|
189843
|
+
if (typeof (data === null || data === void 0 ? void 0 : data.detail) === 'string')
|
|
189844
|
+
return data.detail;
|
|
189845
|
+
if (typeof (data === null || data === void 0 ? void 0 : data.error) === 'string')
|
|
189846
|
+
return data.error;
|
|
189847
|
+
return '';
|
|
189848
|
+
}
|
|
189849
|
+
function useSpendCaps({ tenantKey, mentorId, labels }) {
|
|
189850
|
+
const identityReady = Boolean(tenantKey && mentorId);
|
|
189851
|
+
// 404 is the documented "no cap configured yet" state for the singleton
|
|
189852
|
+
// GETs, not an error — the row simply may not exist (mirrors the grader
|
|
189853
|
+
// tab's config query, which 404s until first saved).
|
|
189854
|
+
const { data: agentCapData, error: agentCapError, isLoading: isAgentCapLoading, refetch: refetchAgentCap, } = useGetAgentSpendCapQuery({ org: tenantKey, mentorId }, { skip: !identityReady });
|
|
189855
|
+
const { data: tenantCapData, error: tenantCapError, isLoading: isTenantCapLoading, refetch: refetchTenantCap, } = useGetTenantSpendCapQuery({ org: tenantKey }, { skip: !tenantKey });
|
|
189856
|
+
// Derive the caps from the error state, not just from `data`: after a
|
|
189857
|
+
// delete, the explicit refetch 404s while RTK Query keeps the entry's
|
|
189858
|
+
// last fulfilled data — without this, the form would keep showing the
|
|
189859
|
+
// just-deleted cap. Keyed on error PRESENCE rather than `status === 404`
|
|
189860
|
+
// because `iblFetchBaseQuery` THROWS its errors and RTK serializes a
|
|
189861
|
+
// thrown plain object down to a bare SerializedError with no `status`.
|
|
189862
|
+
// Any singleton-GET error means there is no trustworthy cap: the
|
|
189863
|
+
// expected 404 is "no cap configured", and the 403 denied state renders
|
|
189864
|
+
// its own panel instead of the form.
|
|
189865
|
+
const agentCap = agentCapError ? undefined : agentCapData;
|
|
189866
|
+
const tenantCap = tenantCapError ? undefined : tenantCapData;
|
|
189867
|
+
const { data: userCaps = [], error: userCapsError, isLoading: isUserCapsLoading, refetch: refetchUserCaps, } = useListAgentUserSpendCapsQuery({ org: tenantKey, mentorId }, { skip: !identityReady });
|
|
189868
|
+
const [upsertAgentCap, { isLoading: isSavingAgentCap }] = useUpsertAgentSpendCapMutation();
|
|
189869
|
+
const [deleteAgentCap, { isLoading: isDeletingAgentCap }] = useDeleteAgentSpendCapMutation();
|
|
189870
|
+
const [upsertTenantCap, { isLoading: isSavingTenantCap }] = useUpsertTenantSpendCapMutation();
|
|
189871
|
+
const [deleteTenantCap, { isLoading: isDeletingTenantCap }] = useDeleteTenantSpendCapMutation();
|
|
189872
|
+
const [upsertUserCap, { isLoading: isSavingUserCap }] = useUpsertUserSpendCapMutation();
|
|
189873
|
+
const [deleteUserCap, { isLoading: isDeletingUserCap }] = useDeleteUserSpendCapMutation();
|
|
189874
|
+
const isAgentForbidden = errorStatus$2(agentCapError) === 403;
|
|
189875
|
+
const isTenantForbidden = errorStatus$2(tenantCapError) === 403;
|
|
189876
|
+
const isUsersForbidden = errorStatus$2(userCapsError) === 403;
|
|
189877
|
+
// Refetch the mutated scope explicitly after every successful save/delete
|
|
189878
|
+
// (same as the grader tab's `refetchConfig()`): the singleton GETs 404
|
|
189879
|
+
// until first created, and a cache entry whose only fetch errored isn't
|
|
189880
|
+
// reachable through the mutation's tag invalidation — the explicit
|
|
189881
|
+
// refetch keeps the form in sync in place regardless.
|
|
189882
|
+
const runSave = async (mutate, refetchScope) => {
|
|
189883
|
+
try {
|
|
189884
|
+
await mutate();
|
|
189885
|
+
refetchScope();
|
|
189886
|
+
toast.success(labels.toasts.saved);
|
|
189887
|
+
return true;
|
|
189888
|
+
}
|
|
189889
|
+
catch (error) {
|
|
189890
|
+
console.error('[AgentSpendCapsTab] save spend cap error', error);
|
|
189891
|
+
toast.error(errorDetail$2(error) || labels.toasts.saveError);
|
|
189892
|
+
return false;
|
|
189893
|
+
}
|
|
189894
|
+
};
|
|
189895
|
+
const runDelete = async (mutate, refetchScope) => {
|
|
189896
|
+
try {
|
|
189897
|
+
await mutate();
|
|
189898
|
+
refetchScope();
|
|
189899
|
+
toast.success(labels.toasts.deleted);
|
|
189900
|
+
return true;
|
|
189901
|
+
}
|
|
189902
|
+
catch (error) {
|
|
189903
|
+
console.error('[AgentSpendCapsTab] delete spend cap error', error);
|
|
189904
|
+
toast.error(errorDetail$2(error) || labels.toasts.deleteError);
|
|
189905
|
+
return false;
|
|
189906
|
+
}
|
|
189907
|
+
};
|
|
189908
|
+
const saveAgentCap = (formData) => runSave(() => upsertAgentCap({ org: tenantKey, mentorId, formData }).unwrap(), refetchAgentCap);
|
|
189909
|
+
const removeAgentCap = () => runDelete(() => deleteAgentCap({ org: tenantKey, mentorId }).unwrap(), refetchAgentCap);
|
|
189910
|
+
const saveTenantCap = (formData) => runSave(() => upsertTenantCap({ org: tenantKey, formData }).unwrap(), refetchTenantCap);
|
|
189911
|
+
const removeTenantCap = () => runDelete(() => deleteTenantCap({ org: tenantKey }).unwrap(), refetchTenantCap);
|
|
189912
|
+
const saveUserCap = (username, formData) => runSave(() => upsertUserCap({ org: tenantKey, mentorId, username, formData }).unwrap(), refetchUserCaps);
|
|
189913
|
+
const removeUserCap = (username) => runDelete(() => deleteUserCap({ org: tenantKey, mentorId, username }).unwrap(), refetchUserCaps);
|
|
189914
|
+
return {
|
|
189915
|
+
agentCap,
|
|
189916
|
+
isAgentCapLoading,
|
|
189917
|
+
isAgentForbidden,
|
|
189918
|
+
saveAgentCap,
|
|
189919
|
+
removeAgentCap,
|
|
189920
|
+
isSavingAgentCap,
|
|
189921
|
+
isDeletingAgentCap,
|
|
189922
|
+
tenantCap,
|
|
189923
|
+
isTenantCapLoading,
|
|
189924
|
+
isTenantForbidden,
|
|
189925
|
+
saveTenantCap,
|
|
189926
|
+
removeTenantCap,
|
|
189927
|
+
isSavingTenantCap,
|
|
189928
|
+
isDeletingTenantCap,
|
|
189929
|
+
userCaps,
|
|
189930
|
+
isUserCapsLoading,
|
|
189931
|
+
isUsersForbidden,
|
|
189932
|
+
saveUserCap,
|
|
189933
|
+
removeUserCap,
|
|
189934
|
+
isSavingUserCap,
|
|
189935
|
+
isDeletingUserCap,
|
|
189936
|
+
};
|
|
189937
|
+
}
|
|
189938
|
+
|
|
189939
|
+
/**
|
|
189940
|
+
* Tenant-settings Billing section for the workspace-wide LLM spend limit.
|
|
189941
|
+
* Renders the same `SpendCapForm` (usage strip included) as the agent
|
|
189942
|
+
* settings Billing tab, so both scopes present the identical editor.
|
|
189943
|
+
* Per-agent and per-user limits are managed in each agent's own Billing tab
|
|
189944
|
+
* (`AgentSpendCapsTab`), since user limits are keyed per agent.
|
|
189945
|
+
* Rendered inside `BillingTab`.
|
|
189946
|
+
*/
|
|
189947
|
+
function SpendLimitsSection({ tenantKey, labels: labelsOverride }) {
|
|
189948
|
+
const t = useT();
|
|
189949
|
+
const labels = React__default.useMemo(() => resolveSpendCapsTabLabels(labelsOverride, t), [labelsOverride, t]);
|
|
189950
|
+
const [isDeleteOpen, setIsDeleteOpen] = React__default.useState(false);
|
|
189951
|
+
const { tenantCap, isTenantCapLoading, isTenantForbidden, saveTenantCap, removeTenantCap, isSavingTenantCap, isDeletingTenantCap, } = useSpendCaps({ tenantKey, mentorId: '', labels });
|
|
189952
|
+
const handleConfirmDelete = async () => {
|
|
189953
|
+
const deleted = await removeTenantCap();
|
|
189954
|
+
if (deleted)
|
|
189955
|
+
setIsDeleteOpen(false);
|
|
189956
|
+
};
|
|
189957
|
+
// With no cap configured there are no reconciled counters, so surface the
|
|
189958
|
+
// workspace's actual spend from the financial analytics endpoint instead —
|
|
189959
|
+
// an admin should see what is being spent before deciding on a limit.
|
|
189960
|
+
const skipActualSpend = !tenantKey || isTenantCapLoading || isTenantForbidden || Boolean(tenantCap);
|
|
189961
|
+
const { data: monthlySpend } = useGetFinancialStatsQuery({ metric: 'monthly_costs', date_filter: 'all_time', platform_key: tenantKey }, { skip: skipActualSpend });
|
|
189962
|
+
const { data: totalSpend } = useGetFinancialStatsQuery({ metric: 'total_costs', all_time: 'true', date_filter: 'all_time', platform_key: tenantKey }, { skip: skipActualSpend });
|
|
189963
|
+
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.value)) })] })), 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.value)) })] }))] }), 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 })] })] }) })] }));
|
|
189964
|
+
}
|
|
189965
|
+
|
|
189966
|
+
function c$3(e,u,c){var i=this,a=useRef(null),o=useRef(0),f=useRef(null),l=useRef([]),v=useRef(),m=useRef(),d=useRef(e),g=useRef(true);d.current=e;var p="undefined"!=typeof window,w=!u&&0!==u&&p;if("function"!=typeof e)throw new TypeError("Expected a function");u=+u||0;var s=!!(c=c||{}).leading,x=!("trailing"in c)||!!c.trailing,h="maxWait"in c,y="debounceOnServer"in c&&!!c.debounceOnServer,F=h?Math.max(+c.maxWait||0,u):null;useEffect(function(){return g.current=true,function(){g.current=false;}},[]);var A=useMemo(function(){var r=function(r){var n=l.current,t=v.current;return l.current=v.current=null,o.current=r,m.current=d.current.apply(t,n)},n=function(r,n){w&&cancelAnimationFrame(f.current),f.current=w?requestAnimationFrame(r):setTimeout(r,n);},t=function(r){if(!g.current)return false;var n=r-a.current;return !a.current||n>=u||n<0||h&&r-o.current>=F},e=function(n){return f.current=null,x&&l.current?r(n):(l.current=v.current=null,m.current)},c=function r(){var c=Date.now();if(t(c))return e(c);if(g.current){var i=u-(c-a.current),f=h?Math.min(i,F-(c-o.current)):i;n(r,f);}},A=function(){if(p||y){var e=Date.now(),d=t(e);if(l.current=[].slice.call(arguments),v.current=i,a.current=e,d){if(!f.current&&g.current)return o.current=a.current,n(c,u),s?r(a.current):m.current;if(h)return n(c,u),r(a.current)}return f.current||n(c,u),m.current}};return A.cancel=function(){f.current&&(w?cancelAnimationFrame(f.current):clearTimeout(f.current)),o.current=0,l.current=a.current=v.current=f.current=null;},A.isPending=function(){return !!f.current},A.flush=function(){return f.current?e(Date.now()):m.current},A},[s,h,u,F,x,w,p,y]);return A}function i$9(r,n){return r===n}function a$3(n,t,a){var o=i$9,f=useRef(n),l=useState({})[1],v=c$3(useCallback(function(r){f.current=r,l({});},[l]),t,a),m=useRef(n);return o(m.current,n)||(v(n),m.current=n),[f.current,v]}
|
|
189967
|
+
|
|
189968
|
+
const Table$1 = React.forwardRef(({ className, ...props }, ref) => (jsx("div", { className: "relative w-full overflow-auto", children: jsx("table", { ref: ref, className: cn("w-full caption-bottom text-sm", className), ...props }) })));
|
|
189969
|
+
Table$1.displayName = "Table";
|
|
189970
|
+
const TableHeader$1 = React.forwardRef(({ className, ...props }, ref) => (jsx("thead", { ref: ref, className: cn("[&_tr]:border-b", className), ...props })));
|
|
189971
|
+
TableHeader$1.displayName = "TableHeader";
|
|
189972
|
+
const TableBody = React.forwardRef(({ className, ...props }, ref) => (jsx("tbody", { ref: ref, className: cn("[&_tr:last-child]:border-0", className), ...props })));
|
|
189973
|
+
TableBody.displayName = "TableBody";
|
|
189974
|
+
const TableFooter = React.forwardRef(({ className, ...props }, ref) => (jsx("tfoot", { ref: ref, className: cn("border-t bg-muted/50 font-medium [&>tr]:last:border-b-0", className), ...props })));
|
|
189975
|
+
TableFooter.displayName = "TableFooter";
|
|
189976
|
+
const TableRow$1 = React.forwardRef(({ className, ...props }, ref) => (jsx("tr", { ref: ref, className: cn("border-b transition-colors hover:bg-muted/50 data-[state=selected]:bg-muted", className), ...props })));
|
|
189977
|
+
TableRow$1.displayName = "TableRow";
|
|
189978
|
+
const TableHead = React.forwardRef(({ className, ...props }, ref) => (jsx("th", { ref: ref, className: cn("h-10 px-2 text-left align-middle font-medium text-muted-foreground [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]", className), ...props })));
|
|
189979
|
+
TableHead.displayName = "TableHead";
|
|
189980
|
+
const TableCell$1 = React.forwardRef(({ className, ...props }, ref) => (jsx("td", { ref: ref, className: cn("p-2 align-middle [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]", className), ...props })));
|
|
189981
|
+
TableCell$1.displayName = "TableCell";
|
|
189982
|
+
const TableCaption = React.forwardRef(({ className, ...props }, ref) => (jsx("caption", { ref: ref, className: cn("mt-4 text-sm text-muted-foreground", className), ...props })));
|
|
189983
|
+
TableCaption.displayName = "TableCaption";
|
|
189984
|
+
|
|
189985
|
+
/**
|
|
189986
|
+
* Single-select searchable picker: a deb-ounce-agnostic input + absolute
|
|
189987
|
+
* results dropdown (the add-access pattern), collapsing to a removable chip
|
|
189988
|
+
* once something is picked. The caller owns the search term and the fetched
|
|
189989
|
+
* options so any query hook can back it.
|
|
189990
|
+
*/
|
|
189991
|
+
function SearchSelect({ labels, selected, onSelect, onClear, searchTerm, onSearchTermChange, options, isLoading, minChars = 2, testId, }) {
|
|
189992
|
+
const [isOpen, setIsOpen] = React__default.useState(false);
|
|
189993
|
+
const blurTimeout = React__default.useRef(null);
|
|
189994
|
+
React__default.useEffect(() => () => {
|
|
189995
|
+
if (blurTimeout.current)
|
|
189996
|
+
clearTimeout(blurTimeout.current);
|
|
189997
|
+
}, []);
|
|
189998
|
+
if (selected) {
|
|
189999
|
+
return (jsxs("div", { className: "space-y-1.5", children: [jsx(Label$1, { className: "text-xs font-medium text-gray-700", children: labels.label }), jsxs("div", { className: "flex items-center justify-between gap-2 rounded-md border border-gray-200 bg-gray-50 px-3 py-2", "data-testid": `${testId}-selected`, children: [jsxs("div", { className: "min-w-0", children: [jsx("p", { className: "truncate text-sm font-medium text-gray-900", children: selected.label }), selected.sublabel && (jsx("p", { className: "truncate text-xs text-gray-600", children: selected.sublabel }))] }), jsxs(Button$1, { type: "button", size: "icon", variant: "ghost", className: "h-6 w-6 flex-shrink-0 text-gray-500 hover:text-red-600", onClick: onClear, "data-testid": `${testId}-clear`, children: [jsx(X$2, { className: "h-3.5 w-3.5", "aria-hidden": "true" }), jsx("span", { className: "sr-only", children: labels.clear })] })] })] }));
|
|
190000
|
+
}
|
|
190001
|
+
return (jsxs("div", { className: "space-y-1.5", children: [jsx(Label$1, { className: "text-xs font-medium text-gray-700", htmlFor: `${testId}-input`, children: labels.label }), jsxs("div", { className: "relative", children: [jsx(Input, { id: `${testId}-input`, className: "focus-visible:border-blue-500 focus-visible:ring-1 focus-visible:ring-blue-500", value: searchTerm, onChange: (e) => onSearchTermChange(e.target.value), onFocus: () => {
|
|
190002
|
+
if (blurTimeout.current)
|
|
190003
|
+
clearTimeout(blurTimeout.current);
|
|
190004
|
+
setIsOpen(true);
|
|
190005
|
+
}, onBlur: () => {
|
|
190006
|
+
blurTimeout.current = setTimeout(() => setIsOpen(false), 100);
|
|
190007
|
+
}, placeholder: labels.placeholder, autoComplete: "off", "aria-autocomplete": "list", "aria-expanded": isOpen, "data-testid": `${testId}-input` }), isOpen && (jsx("div", { className: "absolute top-full right-0 left-0 z-50 mt-1 max-h-64 overflow-y-auto rounded-md border border-gray-200 bg-white shadow-lg", "data-testid": `${testId}-results`, children: searchTerm.trim().length < minChars ? (jsx("div", { className: "px-3 py-2 text-sm text-gray-600", children: labels.typeToSearch })) : isLoading ? (jsxs("div", { className: "flex items-center gap-2 px-3 py-2 text-sm text-gray-600", children: [jsx(LoaderCircle, { className: "h-3.5 w-3.5 animate-spin", "aria-hidden": "true" }), labels.searching] })) : options.length > 0 ? (options.map((option) => (jsxs("button", { type: "button", className: "flex w-full flex-col items-start gap-0.5 px-3 py-2 text-left hover:bg-gray-50", onMouseDown: (event) => event.preventDefault(), onClick: () => {
|
|
190008
|
+
onSelect(option);
|
|
190009
|
+
setIsOpen(false);
|
|
190010
|
+
}, "data-testid": `${testId}-option-${option.value}`, children: [jsx("span", { className: "text-sm font-medium text-gray-900", children: option.label }), option.sublabel && (jsx("span", { className: "text-xs text-gray-600", children: option.sublabel }))] }, option.value)))) : (jsx("div", { className: "px-3 py-2 text-sm text-gray-600", "data-testid": `${testId}-no-results`, children: labels.noResults })) }))] })] }));
|
|
190011
|
+
}
|
|
190012
|
+
|
|
190013
|
+
/**
|
|
190014
|
+
* The shared `Profile` viewer in a dialog — the same modal the tenant
|
|
190015
|
+
* Management tab opens when a user row is clicked. Controlled variant for
|
|
190016
|
+
* hosts that trigger it from a whole table row.
|
|
190017
|
+
*/
|
|
190018
|
+
function UserProfileDialog({ tenantKey, username, isOpen, onClose }) {
|
|
190019
|
+
const t = useT();
|
|
190020
|
+
if (!isOpen)
|
|
190021
|
+
return null;
|
|
190022
|
+
return (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 })] }) }));
|
|
190023
|
+
}
|
|
190024
|
+
/**
|
|
190025
|
+
* Clickable user identity that opens the shared `Profile` viewer in a dialog
|
|
190026
|
+
* — the same modal the tenant Management tab opens when a user row is
|
|
190027
|
+
* clicked. Used by the per-user limits table and the user-limit modal.
|
|
190028
|
+
*/
|
|
190029
|
+
function UserProfileLink({ tenantKey, username, display, className, testId, }) {
|
|
190030
|
+
const t = useT();
|
|
190031
|
+
const [isOpen, setIsOpen] = React__default.useState(false);
|
|
190032
|
+
return (jsxs(Fragment$1, { children: [jsx("button", { type: "button", onClick: (event) => {
|
|
190033
|
+
event.stopPropagation();
|
|
190034
|
+
setIsOpen(true);
|
|
190035
|
+
}, 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) })] }));
|
|
190036
|
+
}
|
|
190037
|
+
|
|
190038
|
+
/**
|
|
190039
|
+
* Add/edit dialog for one per-user spend limit, mirroring the grader
|
|
190040
|
+
* criterion modal: create mode starts with a searchable platform-user picker
|
|
190041
|
+
* (no free-text usernames), edit mode goes straight to the form for the
|
|
190042
|
+
* cap's user. The form's Cancel/Save footer acts as the dialog footer.
|
|
190043
|
+
*/
|
|
190044
|
+
function UserCapModal({ isOpen, onClose, cap, labels, tenantKey, isSaving, onSave }) {
|
|
190045
|
+
var _a, _b, _c, _d, _e;
|
|
190046
|
+
const isEditing = Boolean(cap);
|
|
190047
|
+
const [pickedUser, setPickedUser] = React__default.useState(null);
|
|
190048
|
+
const [userSearch, setUserSearch] = React__default.useState('');
|
|
190049
|
+
// Reset the picker each time the modal opens for a create.
|
|
190050
|
+
React__default.useEffect(() => {
|
|
190051
|
+
if (!isOpen)
|
|
190052
|
+
return;
|
|
190053
|
+
setPickedUser(null);
|
|
190054
|
+
setUserSearch('');
|
|
190055
|
+
}, [isOpen, cap]);
|
|
190056
|
+
const [debouncedUserSearch] = a$3(userSearch, 300);
|
|
190057
|
+
const shouldSearchUsers = Boolean(isOpen && !isEditing && tenantKey && debouncedUserSearch.trim().length >= 2);
|
|
190058
|
+
const { data: usersData, isFetching: isSearchingUsers } = usePlatformUsersQuery({
|
|
190059
|
+
page: 1,
|
|
190060
|
+
page_size: 20,
|
|
190061
|
+
platform_key: tenantKey,
|
|
190062
|
+
platform_org: tenantKey,
|
|
190063
|
+
query: debouncedUserSearch.trim(),
|
|
190064
|
+
return_policies: 'false',
|
|
190065
|
+
}, { skip: !shouldSearchUsers });
|
|
190066
|
+
// The platform users endpoint returns either `results` or `results.data`
|
|
190067
|
+
// depending on whether policies were requested.
|
|
190068
|
+
const rawResults = usersData === null || usersData === void 0 ? void 0 : usersData.results;
|
|
190069
|
+
const foundUsers = Array.isArray(rawResults)
|
|
190070
|
+
? rawResults
|
|
190071
|
+
: ((_a = rawResults === null || rawResults === void 0 ? void 0 : rawResults.data) !== null && _a !== void 0 ? _a : []);
|
|
190072
|
+
// Deliberately email-only in the UI (no name/username noise); the cap API
|
|
190073
|
+
// is still keyed by username, which rides along as the option value.
|
|
190074
|
+
const userOptions = foundUsers
|
|
190075
|
+
.filter((user) => Boolean(user.username) && Boolean(user.email))
|
|
190076
|
+
.map((user) => ({
|
|
190077
|
+
value: user.username,
|
|
190078
|
+
label: user.email,
|
|
190079
|
+
}));
|
|
190080
|
+
const username = isEditing ? ((_b = cap === null || cap === void 0 ? void 0 : cap.username) !== null && _b !== void 0 ? _b : '') : ((_c = pickedUser === null || pickedUser === void 0 ? void 0 : pickedUser.value) !== null && _c !== void 0 ? _c : '');
|
|
190081
|
+
const handleSave = async (formData) => {
|
|
190082
|
+
if (!username)
|
|
190083
|
+
return;
|
|
190084
|
+
const saved = await onSave(username, formData);
|
|
190085
|
+
if (saved)
|
|
190086
|
+
onClose();
|
|
190087
|
+
};
|
|
190088
|
+
return (jsx(Dialog, { open: isOpen, onOpenChange: onClose, children: jsxs(DialogContent, { "aria-describedby": "user-cap-modal-description", "data-testid": "user-cap-modal", className: "flex max-h-[85vh] flex-col sm:max-w-xl", children: [jsx(DialogHeader, { className: "flex-shrink-0", children: jsx(DialogTitle, { className: "ibl-dialog-title", children: isEditing ? labels.users.editTitle : labels.users.addTitle }) }), jsxs("div", { className: cn('min-h-0 flex-1 space-y-4 overflow-y-auto',
|
|
190089
|
+
// Reserve room for the search results dropdown while no user is
|
|
190090
|
+
// picked yet — otherwise the scroll container clips it.
|
|
190091
|
+
!isEditing && !pickedUser && 'min-h-[340px]'), id: "user-cap-modal-description", children: [isEditing ? (jsx("p", { className: "text-sm text-[#646464]", "data-testid": "user-cap-modal-username", children: jsx(UserProfileLink, { tenantKey: tenantKey, username: (_d = cap === null || cap === void 0 ? void 0 : cap.username) !== null && _d !== void 0 ? _d : '', display: (cap === null || cap === void 0 ? void 0 : cap.email) || ((_e = cap === null || cap === void 0 ? void 0 : cap.username) !== null && _e !== void 0 ? _e : ''), className: "inline", testId: "user-cap-modal-profile-link" }) })) : (jsx(SearchSelect, { labels: labels.users.picker, selected: pickedUser, onSelect: setPickedUser, onClear: () => setPickedUser(null), searchTerm: userSearch, onSearchTermChange: setUserSearch, options: userOptions, isLoading: isSearchingUsers, testId: "user-cap-modal-user-picker" })), Boolean(username) && (jsx(SpendCapForm, { labels: labels, cap: cap !== null && cap !== void 0 ? cap : undefined, isSaving: isSaving, isDeleting: false, onSave: handleSave, onCancel: onClose, testId: "user-cap-modal" }))] })] }) }));
|
|
190092
|
+
}
|
|
190093
|
+
|
|
190094
|
+
/**
|
|
190095
|
+
* Per-user limits for one agent: a list of the explicit (user, agent) caps.
|
|
190096
|
+
* Add and edit both go through the `UserCapModal` popup (add picks the user
|
|
190097
|
+
* via a platform-user search — no free-text usernames); delete confirms in a
|
|
190098
|
+
* dialog.
|
|
190099
|
+
*/
|
|
190100
|
+
function UserCapsSection({ labels, tenantKey, caps, isLoading, isSaving, isDeleting, onSave, onDelete, }) {
|
|
190101
|
+
var _a;
|
|
190102
|
+
const [isModalOpen, setIsModalOpen] = React__default.useState(false);
|
|
190103
|
+
const [editingCap, setEditingCap] = React__default.useState(null);
|
|
190104
|
+
// The cap queued for deletion — kept whole so the dialog can show the
|
|
190105
|
+
// user's email while the delete call is still keyed by username.
|
|
190106
|
+
const [pendingDelete, setPendingDelete] = React__default.useState(null);
|
|
190107
|
+
// Whole-row click opens the user's profile (Management-tab pattern).
|
|
190108
|
+
const [profileCap, setProfileCap] = React__default.useState(null);
|
|
190109
|
+
const openAdd = () => {
|
|
190110
|
+
setEditingCap(null);
|
|
190111
|
+
setIsModalOpen(true);
|
|
190112
|
+
};
|
|
190113
|
+
const openEdit = (cap) => {
|
|
190114
|
+
setEditingCap(cap);
|
|
190115
|
+
setIsModalOpen(true);
|
|
190116
|
+
};
|
|
190117
|
+
// Status toggle saves immediately (datasets-table pattern) — the PUT is an
|
|
190118
|
+
// upsert, so the cap's current fields ride along with the flipped flag.
|
|
190119
|
+
const toggleEnabled = (cap, checked) => {
|
|
190120
|
+
var _a;
|
|
190121
|
+
void onSave((_a = cap.username) !== null && _a !== void 0 ? _a : '', {
|
|
190122
|
+
interval_type: cap.interval_type,
|
|
190123
|
+
max_cost_usd: cap.max_cost_usd,
|
|
190124
|
+
enforcement: cap.enforcement,
|
|
190125
|
+
alert_thresholds: cap.alert_thresholds,
|
|
190126
|
+
enabled: checked,
|
|
190127
|
+
});
|
|
190128
|
+
};
|
|
190129
|
+
const handleConfirmDelete = async () => {
|
|
190130
|
+
var _a;
|
|
190131
|
+
if (!pendingDelete)
|
|
190132
|
+
return;
|
|
190133
|
+
const deleted = await onDelete((_a = pendingDelete.username) !== null && _a !== void 0 ? _a : '');
|
|
190134
|
+
if (deleted)
|
|
190135
|
+
setPendingDelete(null);
|
|
190136
|
+
};
|
|
190137
|
+
return (jsxs("div", { className: "space-y-3", "data-testid": "user-caps-section", children: [jsxs("div", { className: "flex items-start justify-between gap-4", children: [jsxs("div", { children: [jsx("h4", { className: "text-sm font-medium text-gray-900", children: labels.users.sectionTitle }), jsx("p", { className: "text-xs text-gray-600", children: labels.users.sectionDescription })] }), jsxs(Button$1, { className: "ibl-button-primary flex-shrink-0", onClick: openAdd, disabled: isSaving || isDeleting, "data-testid": "user-caps-add-button", children: [jsx(Plus, { className: "mr-1 h-4 w-4" }), labels.users.addButton] })] }), jsx("div", { className: "overflow-hidden rounded-md border", "data-testid": "user-caps-list", children: jsx("div", { className: "overflow-x-auto sm:mx-0", children: jsx("div", { className: "inline-block min-w-full align-middle", children: isLoading ? (jsx("div", { className: "flex w-full items-center justify-center py-10", "data-testid": "user-caps-loading", children: jsx(Spinner, {}) })) : (jsxs(Table$1, { className: "min-w-full", children: [jsx(TableHeader$1, { children: jsxs(TableRow$1, { className: "bg-muted/50 border-b", children: [jsx(TableHead, { className: "p-3 text-left text-sm whitespace-nowrap text-[#646464]", children: labels.users.table.userColumn }), jsx(TableHead, { className: "p-3 text-left text-sm whitespace-nowrap text-[#646464]", children: labels.users.table.limitColumn }), jsx(TableHead, { className: "p-3 text-left text-sm whitespace-nowrap text-[#646464]", children: labels.users.table.statusColumn }), jsx(TableHead, { className: "w-10 p-3" })] }) }), jsx(TableBody, { children: caps.length === 0 ? (jsx(TableRow$1, { children: jsx(TableCell$1, { colSpan: 4, className: "p-4 text-center text-[#646464]", "data-testid": "user-caps-empty", children: labels.users.emptyState }) })) : (caps.map((cap) => {
|
|
190138
|
+
var _a;
|
|
190139
|
+
const username = (_a = cap.username) !== null && _a !== void 0 ? _a : '';
|
|
190140
|
+
// Email-first everywhere the user is shown or announced;
|
|
190141
|
+
// testids and mutation keys stay on the backend's
|
|
190142
|
+
// username key.
|
|
190143
|
+
const displayName = cap.email || username;
|
|
190144
|
+
return (jsxs(TableRow$1, { onClick: () => setProfileCap(cap), className: "cursor-pointer border-b transition-colors last:border-0 hover:bg-gray-50", "data-testid": `user-cap-row-${username}`, children: [jsx(TableCell$1, { className: "max-w-[240px] p-3 font-medium whitespace-nowrap text-[#646464]", children: jsx(UserProfileLink, { tenantKey: tenantKey, username: username, display: displayName, testId: `user-cap-profile-link-${username}` }) }), jsxs(TableCell$1, { className: "p-3 whitespace-nowrap text-[#646464]", children: [formatUsd$1(cap.max_cost_usd), " /", ' ', labels.form.intervalOptions[cap.interval_type]] }), jsx(TableCell$1, { className: "p-3", onClick: (e) => e.stopPropagation(), children: jsxs("div", { className: "flex items-center gap-1.5", children: [jsx(CustomSwitch, { checked: cap.enabled, onCheckedChange: (checked) => toggleEnabled(cap, checked), disabled: isSaving || isDeleting, "aria-label": labels.users.statusToggleAria(displayName), "data-testid": `user-cap-status-switch-${username}` }), cap.is_exceeded && (jsx("span", { className: "rounded-full bg-red-100 px-2 py-0.5 text-[11px] font-medium text-red-700", children: labels.usage.exceededBadge })), cap.enforcement === 'alert_only' && (jsx("span", { className: "rounded-full bg-amber-100 px-2 py-0.5 text-[11px] font-medium text-amber-800", children: labels.usage.alertOnlyBadge }))] }) }), jsx(TableCell$1, { className: "p-3 text-right", onClick: (e) => e.stopPropagation(), children: jsxs(DropdownMenu, { children: [jsx(DropdownMenuTrigger, { asChild: true, children: jsx(Button$1, { type: "button", variant: "ghost", size: "icon", "aria-label": labels.users.actionsAria(displayName), "data-testid": `user-cap-actions-${username}`, children: jsx(Ellipsis, { className: "h-4 w-4" }) }) }), jsxs(DropdownMenuContent, { align: "end", children: [jsxs(DropdownMenuItem, { onClick: () => openEdit(cap), "data-testid": `user-cap-edit-${username}`, children: [jsx(Pencil, { className: "mr-2 h-4 w-4" }), labels.users.edit] }), jsxs(DropdownMenuItem, { className: "text-red-600 focus:text-red-700", onClick: () => setPendingDelete(cap), "data-testid": `user-cap-delete-${username}`, children: [jsx(Trash2, { className: "mr-2 h-4 w-4" }), labels.users.delete] })] })] }) })] }, cap.id));
|
|
190145
|
+
})) })] })) }) }) }), jsx(UserProfileDialog, { tenantKey: tenantKey, username: (_a = profileCap === null || profileCap === void 0 ? void 0 : profileCap.username) !== null && _a !== void 0 ? _a : '', isOpen: profileCap !== null, onClose: () => setProfileCap(null) }), jsx(UserCapModal, { isOpen: isModalOpen, onClose: () => setIsModalOpen(false), cap: editingCap, labels: labels, tenantKey: tenantKey, isSaving: isSaving, onSave: onSave }), jsx(Dialog, { open: pendingDelete !== null, onOpenChange: () => setPendingDelete(null), children: jsxs(DialogContent, { "aria-describedby": "user-cap-delete-description", "data-testid": "user-cap-delete-modal", children: [jsx(DialogHeader, { children: jsx(DialogTitle, { className: "ibl-dialog-title", children: labels.deleteModal.title }) }), jsx("div", { className: "my-5", id: "user-cap-delete-description", children: jsxs("p", { className: "text-sm text-[#646464]", children: [jsx("span", { className: "font-bold italic", children: pendingDelete ? pendingDelete.email || pendingDelete.username : '' }), ' ', "\u2014 ", labels.deleteModal.description] }) }), jsxs(DialogFooter, { className: "gap-3", children: [jsx(Button$1, { variant: "outline", onClick: () => setPendingDelete(null), children: labels.deleteModal.cancel }), jsx(Button$1, { className: "bg-gradient-to-r from-[#2563EB] to-[#93C5FD] text-white hover:opacity-90", onClick: handleConfirmDelete, disabled: isDeleting, "data-testid": "user-cap-delete-confirm", children: isDeleting ? labels.form.removing : labels.deleteModal.confirm })] })] }) })] }));
|
|
190146
|
+
}
|
|
190147
|
+
|
|
190148
|
+
const AgentSettingsContext = React__default.createContext(null);
|
|
190149
|
+
function AgentSettingsProvider({ children, ...value }) {
|
|
190150
|
+
const ctx = React__default.useMemo(() => value,
|
|
190151
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
190152
|
+
[
|
|
190153
|
+
value.tenantKey,
|
|
190154
|
+
value.mentorId,
|
|
190155
|
+
value.username,
|
|
190156
|
+
value.enableRBAC,
|
|
190157
|
+
value.rbacPermissions,
|
|
190158
|
+
value.executeGatedAction,
|
|
190159
|
+
value.visibilityOptions,
|
|
190160
|
+
]);
|
|
190161
|
+
return jsx(AgentSettingsContext.Provider, { value: ctx, children: children });
|
|
190162
|
+
}
|
|
190163
|
+
/**
|
|
190164
|
+
* Read the shared agent identity / config from the nearest
|
|
190165
|
+
* `<AgentSettingsProvider>` if one is present, returning `null` otherwise.
|
|
190166
|
+
*
|
|
190167
|
+
* Use this when a tab can also be driven by direct props (i.e. the
|
|
190168
|
+
* `<AgentSettingsProvider>` wrapper is optional). For tabs that strictly
|
|
190169
|
+
* require the provider, use `useAgentSettings`.
|
|
190170
|
+
*/
|
|
190171
|
+
function useAgentSettingsOptional() {
|
|
190172
|
+
return React__default.useContext(AgentSettingsContext);
|
|
190173
|
+
}
|
|
190174
|
+
/**
|
|
190175
|
+
* Read the shared agent identity / config from the nearest
|
|
190176
|
+
* `<AgentSettingsProvider>`. Throws if called outside a provider — this is
|
|
190177
|
+
* intentional: every tab MUST be wrapped.
|
|
190178
|
+
*/
|
|
190179
|
+
function useAgentSettings() {
|
|
190180
|
+
const ctx = React__default.useContext(AgentSettingsContext);
|
|
190181
|
+
if (!ctx) {
|
|
190182
|
+
throw new Error('useAgentSettings must be used within an <AgentSettingsProvider>. ' +
|
|
190183
|
+
'Wrap your tab components with <AgentSettingsProvider tenantKey=... mentorId=... username=... enableRBAC=...>.');
|
|
190184
|
+
}
|
|
190185
|
+
return ctx;
|
|
190186
|
+
}
|
|
190187
|
+
|
|
190188
|
+
const SPEND_CAPS_SUB_TABS = {
|
|
190189
|
+
agent: 'agent',
|
|
190190
|
+
users: 'users',
|
|
190191
|
+
};
|
|
190192
|
+
function DeniedState({ labels }) {
|
|
190193
|
+
return (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-caps-denied", children: [jsx(ShieldAlert, { className: "h-6 w-6 text-gray-400" }), jsx("p", { className: "text-sm font-medium text-gray-900", children: labels.title }), jsx("p", { className: "max-w-sm text-xs text-gray-600", children: labels.description })] }));
|
|
190194
|
+
}
|
|
190195
|
+
/**
|
|
190196
|
+
* "Billing" tab of the agent settings modal, with two sub-tabs matching the
|
|
190197
|
+
* agent-level backend scopes: the agent's own spend limit and per-user limits
|
|
190198
|
+
* on this agent (user picked through a platform-user search). The
|
|
190199
|
+
* workspace-wide limit is managed in the tenant settings Billing tab instead
|
|
190200
|
+
* (`SpendLimitsSection` inside `BillingTab`). Reads/writes the RBAC-gated
|
|
190201
|
+
* admin endpoints; a 403 renders a friendly denied state per scope.
|
|
190202
|
+
*/
|
|
190203
|
+
function AgentSpendCapsTab({ labels: labelsOverride, tenantKey: tenantKeyProp, mentorId: mentorIdProp, headerClassName, bodyClassName, }) {
|
|
190204
|
+
var _a, _b;
|
|
190205
|
+
const ctx = useAgentSettingsOptional();
|
|
190206
|
+
const tenantKey = (_a = tenantKeyProp !== null && tenantKeyProp !== void 0 ? tenantKeyProp : ctx === null || ctx === void 0 ? void 0 : ctx.tenantKey) !== null && _a !== void 0 ? _a : '';
|
|
190207
|
+
const mentorId = (_b = mentorIdProp !== null && mentorIdProp !== void 0 ? mentorIdProp : ctx === null || ctx === void 0 ? void 0 : ctx.mentorId) !== null && _b !== void 0 ? _b : '';
|
|
190208
|
+
const t = useT();
|
|
190209
|
+
const labels = React__default.useMemo(() => resolveSpendCapsTabLabels(labelsOverride, t), [labelsOverride, t]);
|
|
190210
|
+
const { agentCap, isAgentCapLoading, isAgentForbidden, saveAgentCap, removeAgentCap, isSavingAgentCap, isDeletingAgentCap, userCaps, isUserCapsLoading, isUsersForbidden, saveUserCap, removeUserCap, isSavingUserCap, isDeletingUserCap, } = useSpendCaps({ tenantKey, mentorId, labels });
|
|
190211
|
+
const [isDeleteOpen, setIsDeleteOpen] = React__default.useState(false);
|
|
190212
|
+
// Height lock: the two sub-tabs have different natural heights, which
|
|
190213
|
+
// would make a content-sized host (the tenant Agent Limits popup) jump on
|
|
190214
|
+
// every switch. Ratchet the tallest rendered height into a min-height so
|
|
190215
|
+
// switching never shrinks the tab — without padding it beyond its own
|
|
190216
|
+
// natural size.
|
|
190217
|
+
const [subTab, setSubTab] = React__default.useState(SPEND_CAPS_SUB_TABS.agent);
|
|
190218
|
+
const tabsRef = React__default.useRef(null);
|
|
190219
|
+
const [minTabsHeight, setMinTabsHeight] = React__default.useState(0);
|
|
190220
|
+
React__default.useLayoutEffect(() => {
|
|
190221
|
+
var _a, _b;
|
|
190222
|
+
const height = (_b = (_a = tabsRef.current) === null || _a === void 0 ? void 0 : _a.offsetHeight) !== null && _b !== void 0 ? _b : 0;
|
|
190223
|
+
setMinTabsHeight((current) => Math.max(current, height));
|
|
190224
|
+
}, [subTab]);
|
|
190225
|
+
const handleConfirmDelete = async () => {
|
|
190226
|
+
const deleted = await removeAgentCap();
|
|
190227
|
+
if (deleted)
|
|
190228
|
+
setIsDeleteOpen(false);
|
|
190229
|
+
};
|
|
190230
|
+
return (jsxs(Fragment$1, { children: [jsx("div", { className: cn('flex h-[73px] flex-shrink-0 items-center border-b border-gray-200 bg-white p-4 lg:block', headerClassName), children: jsxs("div", { children: [jsx("h3", { className: "mb-1 text-base font-medium text-gray-900", children: labels.header.title }), jsx("p", { className: "text-xs text-gray-600", children: labels.header.description })] }) }), jsx("div", { className: cn('flex-1 space-y-4 p-3 lg:p-4', bodyClassName), style: { overflowY: 'auto', overflowX: 'hidden' }, "data-testid": "spend-caps-tab-body", children: jsxs(Tabs, { value: subTab, onValueChange: setSubTab, className: "w-full", ref: tabsRef, style: minTabsHeight ? { minHeight: minTabsHeight } : undefined, children: [jsxs(TabsList, { "aria-label": labels.header.title, "data-testid": "spend-caps-sub-tabs", children: [jsx(TabsTrigger, { value: SPEND_CAPS_SUB_TABS.agent, "data-testid": "spend-caps-sub-tab-agent", children: labels.subTabs.agent }), jsx(TabsTrigger, { value: SPEND_CAPS_SUB_TABS.users, "data-testid": "spend-caps-sub-tab-users", children: labels.subTabs.users })] }), jsx(TabsContent, { value: SPEND_CAPS_SUB_TABS.agent, className: "space-y-4", children: isAgentCapLoading ? (jsx("div", { className: "flex items-center justify-center py-12", "data-testid": "agent-cap-loading", children: jsx(Spinner, {}) })) : isAgentForbidden ? (jsx(DeniedState, { labels: labels.denied })) : (jsx(SpendCapForm, { labels: labels, cap: agentCap, isSaving: isSavingAgentCap, isDeleting: isDeletingAgentCap, onSave: saveAgentCap, onDelete: () => setIsDeleteOpen(true), testId: "agent-cap" })) }), jsx(TabsContent, { value: SPEND_CAPS_SUB_TABS.users, className: "space-y-4", children: isUsersForbidden ? (jsx(DeniedState, { labels: labels.denied })) : (jsx(UserCapsSection, { labels: labels, tenantKey: tenantKey, caps: userCaps, isLoading: isUserCapsLoading, isSaving: isSavingUserCap, isDeleting: isDeletingUserCap, onSave: saveUserCap, onDelete: removeUserCap })) })] }) }), jsx(Dialog, { open: isDeleteOpen, onOpenChange: () => setIsDeleteOpen(false), children: jsxs(DialogContent, { "aria-describedby": "spend-cap-delete-description", "data-testid": "spend-cap-delete-modal", children: [jsx(DialogHeader, { children: jsx(DialogTitle, { className: "ibl-dialog-title", children: labels.deleteModal.title }) }), jsx("div", { className: "my-5", id: "spend-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: isDeletingAgentCap, "data-testid": "spend-cap-delete-confirm", children: isDeletingAgentCap ? labels.form.removing : labels.deleteModal.confirm })] })] }) })] }));
|
|
190231
|
+
}
|
|
190232
|
+
|
|
190233
|
+
function errorStatus$1(error) {
|
|
190234
|
+
return error === null || error === void 0 ? void 0 : error.status;
|
|
190235
|
+
}
|
|
190236
|
+
/**
|
|
190237
|
+
* Tenant-settings Billing "Agent Limits" tab: every configured agent spend
|
|
190238
|
+
* cap in the workspace from the tenant-wide list endpoint (no per-agent
|
|
190239
|
+
* fan-out), with an agent autocomplete filter, a direct status toggle per
|
|
190240
|
+
* row (datasets-table pattern) and a manage action that opens the agent's
|
|
190241
|
+
* full Billing editor (`AgentSpendCapsTab` — agent limit + per-user limits)
|
|
190242
|
+
* in a popup. Rendered inside `BillingTab`.
|
|
190243
|
+
*/
|
|
190244
|
+
function AgentLimitsSection({ tenantKey, username, labels: labelsOverride, }) {
|
|
190245
|
+
var _a;
|
|
190246
|
+
const t = useT();
|
|
190247
|
+
const labels = React__default.useMemo(() => resolveSpendCapsTabLabels(labelsOverride, t), [labelsOverride, t]);
|
|
190248
|
+
const [upsertAgentCap, { isLoading: isSavingCap }] = useUpsertAgentSpendCapMutation();
|
|
190249
|
+
// Agent autocomplete filter (also the entry point for setting a limit on
|
|
190250
|
+
// an agent that has none yet).
|
|
190251
|
+
const [agentFilter, setAgentFilter] = React__default.useState(null);
|
|
190252
|
+
const [agentSearch, setAgentSearch] = React__default.useState('');
|
|
190253
|
+
const [debouncedAgentSearch] = a$3(agentSearch, 300);
|
|
190254
|
+
const shouldSearchAgents = Boolean(tenantKey && debouncedAgentSearch.trim().length >= 2);
|
|
190255
|
+
const { data: mentorsResponse, isFetching: isSearchingAgents } = useGetMentorsQuery({ org: tenantKey, username, limit: 20, query: debouncedAgentSearch.trim() }, { skip: !shouldSearchAgents });
|
|
190256
|
+
const agentOptions = ((_a = mentorsResponse === null || mentorsResponse === void 0 ? void 0 : mentorsResponse.results) !== null && _a !== void 0 ? _a : [])
|
|
190257
|
+
.filter((mentor) => Boolean(mentor.unique_id))
|
|
190258
|
+
.map((mentor) => ({
|
|
190259
|
+
value: mentor.unique_id,
|
|
190260
|
+
label: mentor.name || mentor.unique_id,
|
|
190261
|
+
}));
|
|
190262
|
+
// The endpoint supports filtering by mentor server-side — pass it through
|
|
190263
|
+
// instead of fetching everything and filtering client-side.
|
|
190264
|
+
const { data: visibleCaps = [], error: capsError, isLoading, isFetching, } = useListAgentSpendCapsQuery({ org: tenantKey, ...(agentFilter ? { mentor: agentFilter.value } : {}) }, { skip: !tenantKey });
|
|
190265
|
+
const isForbidden = errorStatus$1(capsError) === 403;
|
|
190266
|
+
const [selectedAgent, setSelectedAgent] = React__default.useState(null);
|
|
190267
|
+
// Status toggle saves immediately (datasets-table pattern) — the PUT is an
|
|
190268
|
+
// upsert, so the cap's current fields ride along with the flipped flag.
|
|
190269
|
+
const toggleEnabled = async (cap, checked) => {
|
|
190270
|
+
var _a;
|
|
190271
|
+
try {
|
|
190272
|
+
await upsertAgentCap({
|
|
190273
|
+
org: tenantKey,
|
|
190274
|
+
mentorId: (_a = cap.mentor_unique_id) !== null && _a !== void 0 ? _a : '',
|
|
190275
|
+
formData: {
|
|
190276
|
+
interval_type: cap.interval_type,
|
|
190277
|
+
max_cost_usd: cap.max_cost_usd,
|
|
190278
|
+
enforcement: cap.enforcement,
|
|
190279
|
+
alert_thresholds: cap.alert_thresholds,
|
|
190280
|
+
enabled: checked,
|
|
190281
|
+
},
|
|
190282
|
+
}).unwrap();
|
|
190283
|
+
toast.success(labels.toasts.saved);
|
|
190284
|
+
}
|
|
190285
|
+
catch (error) {
|
|
190286
|
+
console.error('[AgentLimitsSection] toggle spend limit error', error);
|
|
190287
|
+
toast.error(labels.toasts.saveError);
|
|
190288
|
+
}
|
|
190289
|
+
};
|
|
190290
|
+
return (jsxs(Fragment$1, { children: [jsxs("div", { "data-testid": "spend-limits-agents-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.agents.title }), jsx("p", { className: "text-[13px] font-normal leading-5 text-[#4a5565] dark:text-gray-400", children: labels.tenantSections.agents.description })] }) }), jsx("div", { className: "space-y-3 border-t border-[#e5e7eb] dark:border-zinc-800 px-4 py-3", children: isForbidden ? (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": "agent-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(Fragment$1, { children: [jsx("div", { className: "max-w-sm", children: jsx(SearchSelect, { labels: labels.tenantSections.agents.filter, selected: agentFilter, onSelect: setAgentFilter, onClear: () => setAgentFilter(null), searchTerm: agentSearch, onSearchTermChange: setAgentSearch, options: agentOptions, isLoading: isSearchingAgents, testId: "agent-limits-filter" }) }), jsx("div", { className: "overflow-hidden rounded-md border", "data-testid": "agent-limits-list", children: jsx("div", { className: "overflow-x-auto sm:mx-0", children: jsx("div", { className: "inline-block min-w-full align-middle", children: isLoading || isFetching ? (jsx("div", { className: "flex w-full items-center justify-center py-10", "data-testid": "agent-limits-loading", children: jsx(Spinner, {}) })) : (jsxs(Table$1, { className: "min-w-full", children: [jsx(TableHeader$1, { children: jsxs(TableRow$1, { className: "bg-muted/50 border-b", children: [jsx(TableHead, { className: "p-3 text-left text-sm whitespace-nowrap text-[#646464]", children: labels.tenantSections.agents.table.agentColumn }), jsx(TableHead, { className: "p-3 text-left text-sm whitespace-nowrap text-[#646464]", children: labels.tenantSections.agents.table.limitColumn }), jsx(TableHead, { className: "p-3 text-left text-sm whitespace-nowrap text-[#646464]", children: labels.tenantSections.agents.table.spentColumn }), jsx(TableHead, { className: "p-3 text-left text-sm whitespace-nowrap text-[#646464]", children: labels.tenantSections.agents.table.remainingColumn }), jsx(TableHead, { className: "p-3 text-left text-sm whitespace-nowrap text-[#646464]", children: labels.tenantSections.agents.table.statusColumn }), jsx(TableHead, { className: "w-10 p-3" })] }) }), jsx(TableBody, { children: visibleCaps.length === 0 ? (jsx(TableRow$1, { children: jsx(TableCell$1, { colSpan: 6, className: "p-4 text-center text-[#646464]", "data-testid": "agent-limits-empty", children: jsxs("div", { className: "space-y-2", children: [jsx("p", { children: agentFilter
|
|
190291
|
+
? labels.tenantSections.agents.emptyFiltered
|
|
190292
|
+
: labels.tenantSections.agents.emptyState }), agentFilter && (jsx(Button$1, { className: "ibl-button-primary", onClick: () => setSelectedAgent({
|
|
190293
|
+
uniqueId: agentFilter.value,
|
|
190294
|
+
name: agentFilter.label,
|
|
190295
|
+
}), "data-testid": "agent-limits-set-limit-button", children: labels.tenantSections.agents.setLimitButton }))] }) }) })) : (visibleCaps.map((cap) => {
|
|
190296
|
+
var _a;
|
|
190297
|
+
const uniqueId = (_a = cap.mentor_unique_id) !== null && _a !== void 0 ? _a : '';
|
|
190298
|
+
const name = cap.mentor_name || uniqueId;
|
|
190299
|
+
return (jsxs(TableRow$1, { className: "border-b last:border-0", "data-testid": `agent-limits-row-${uniqueId}`, children: [jsx(TableCell$1, { className: "max-w-[240px] truncate p-3 font-medium whitespace-nowrap text-[#646464]", children: name }), jsxs(TableCell$1, { className: "p-3 whitespace-nowrap text-[#646464]", children: [formatUsd$1(cap.max_cost_usd), " /", ' ', labels.form.intervalOptions[cap.interval_type]] }), jsx(TableCell$1, { className: "p-3 whitespace-nowrap text-[#646464]", children: formatUsd$1(cap.current_spend_usd) }), jsx(TableCell$1, { className: "p-3 whitespace-nowrap text-[#646464]", children: formatUsd$1(cap.remaining_usd) }), jsx(TableCell$1, { className: "p-3", children: jsxs("div", { className: "flex items-center gap-1.5", children: [jsx(CustomSwitch, { checked: cap.enabled, onCheckedChange: (checked) => toggleEnabled(cap, checked), disabled: isSavingCap, "aria-label": labels.tenantSections.agents.statusToggleAria(name), "data-testid": `agent-limits-status-switch-${uniqueId}` }), cap.is_exceeded && (jsx("span", { className: "rounded-full bg-red-100 px-2 py-0.5 text-[11px] font-medium text-red-700", children: labels.usage.exceededBadge })), cap.enforcement === 'alert_only' && (jsx("span", { className: "rounded-full bg-amber-100 px-2 py-0.5 text-[11px] font-medium text-amber-800", children: labels.usage.alertOnlyBadge }))] }) }), jsx(TableCell$1, { className: "p-3 text-right", children: jsx(Button$1, { type: "button", variant: "ghost", size: "icon", "aria-label": labels.tenantSections.agents.manageAria(name), onClick: () => setSelectedAgent({ uniqueId, name }), "data-testid": `agent-limits-manage-${uniqueId}`, children: jsx(SlidersHorizontal, { className: "h-4 w-4" }) }) })] }, cap.id));
|
|
190300
|
+
})) })] })) }) }) })] })) })] }), jsx(Dialog, { open: selectedAgent !== null, onOpenChange: () => setSelectedAgent(null), children: jsxs(DialogContent, { "aria-describedby": undefined, "data-testid": "agent-limits-modal",
|
|
190301
|
+
// Content-driven height (capped at 90vh) — the tab itself locks its
|
|
190302
|
+
// sub-tabs to a shared height so switching doesn't shift the dialog.
|
|
190303
|
+
className: "flex max-h-[90vh] w-[calc(100vw-2rem)] flex-col gap-0 overflow-hidden p-0 sm:max-w-4xl", children: [jsx(DialogHeader, { className: "flex-shrink-0 border-b border-gray-200 px-6 py-4 pr-12", children: jsx(DialogTitle, { className: "ibl-dialog-title", children: selectedAgent === null || selectedAgent === void 0 ? void 0 : selectedAgent.name }) }), jsx("div", { className: "flex min-h-0 flex-1 flex-col overflow-hidden", children: selectedAgent && (jsx(AgentSpendCapsTab, { tenantKey: tenantKey, mentorId: selectedAgent.uniqueId, headerClassName: "px-6", bodyClassName: "px-6 pb-6 lg:px-8" })) })] }) })] }));
|
|
190304
|
+
}
|
|
190305
|
+
|
|
190306
|
+
/**
|
|
190307
|
+
* Credit-balance → USD conversion for the Plan & Credits tab. The rate is
|
|
190308
|
+
* never hardcoded — it differs per environment — so everything here derives
|
|
190309
|
+
* from whichever fields the `/api/billing/account/` response actually
|
|
190310
|
+
* carries, and returns null when it carries none (the UI then shows credits
|
|
190311
|
+
* only).
|
|
190312
|
+
*/
|
|
190313
|
+
function toFiniteNumber(value) {
|
|
190314
|
+
if (value === null || value === undefined || value === '')
|
|
190315
|
+
return null;
|
|
190316
|
+
const num = typeof value === 'string' ? parseFloat(value) : value;
|
|
190317
|
+
return Number.isFinite(num) ? num : null;
|
|
190318
|
+
}
|
|
190319
|
+
/**
|
|
190320
|
+
* The environment's credits-per-USD rate read off the transaction history:
|
|
190321
|
+
* an `add` transaction records both the credits granted and the dollars paid
|
|
190322
|
+
* for them (`/api/billing/transactions/`), so their ratio IS the rate. Uses
|
|
190323
|
+
* the newest non-failed top-up (rows come most-recent first). Null when no
|
|
190324
|
+
* usable top-up exists yet.
|
|
190325
|
+
*/
|
|
190326
|
+
function resolveCreditsPerUsdFromTransactions(transactions) {
|
|
190327
|
+
for (const tx of transactions !== null && transactions !== void 0 ? transactions : []) {
|
|
190328
|
+
if (tx.transaction_type !== 'add' || tx.status === 'failed')
|
|
190329
|
+
continue;
|
|
190330
|
+
const usd = toFiniteNumber(tx.payment_amount_usd);
|
|
190331
|
+
const credits = toFiniteNumber(tx.credits_amount);
|
|
190332
|
+
if (usd !== null && usd > 0 && credits !== null && credits > 0)
|
|
190333
|
+
return credits / usd;
|
|
190334
|
+
}
|
|
190335
|
+
return null;
|
|
190336
|
+
}
|
|
190337
|
+
/**
|
|
190338
|
+
* The environment's credits-per-USD rate, from whichever field the backend
|
|
190339
|
+
* provides: `credits_per_usd` directly, `usd_per_credit` inverted, or — when
|
|
190340
|
+
* only the two balance figures exist — their ratio. Null when none resolve.
|
|
190341
|
+
*/
|
|
190342
|
+
function resolveCreditsPerUsd(billing) {
|
|
190343
|
+
const direct = toFiniteNumber(billing === null || billing === void 0 ? void 0 : billing.credits_per_usd);
|
|
190344
|
+
if (direct !== null && direct > 0)
|
|
190345
|
+
return direct;
|
|
190346
|
+
const usdPerCredit = toFiniteNumber(billing === null || billing === void 0 ? void 0 : billing.usd_per_credit);
|
|
190347
|
+
if (usdPerCredit !== null && usdPerCredit > 0)
|
|
190348
|
+
return 1 / usdPerCredit;
|
|
190349
|
+
const credits = toFiniteNumber(billing === null || billing === void 0 ? void 0 : billing.available_credits);
|
|
190350
|
+
const usd = toFiniteNumber(billing === null || billing === void 0 ? void 0 : billing.available_credits_usd);
|
|
190351
|
+
if (credits !== null && usd !== null && credits > 0 && usd > 0)
|
|
190352
|
+
return credits / usd;
|
|
190353
|
+
return null;
|
|
190354
|
+
}
|
|
190355
|
+
/**
|
|
190356
|
+
* Dollar value of the available credit balance: the backend's explicit
|
|
190357
|
+
* `available_credits_usd` when present, otherwise the balance divided by the
|
|
190358
|
+
* resolved rate. Null when the response supports neither.
|
|
190359
|
+
*/
|
|
190360
|
+
function resolveAvailableCreditsUsd(billing) {
|
|
190361
|
+
const explicit = toFiniteNumber(billing === null || billing === void 0 ? void 0 : billing.available_credits_usd);
|
|
190362
|
+
if (explicit !== null)
|
|
190363
|
+
return explicit;
|
|
190364
|
+
const rate = resolveCreditsPerUsd(billing);
|
|
190365
|
+
const credits = toFiniteNumber(billing === null || billing === void 0 ? void 0 : billing.available_credits);
|
|
190366
|
+
if (rate !== null && credits !== null)
|
|
190367
|
+
return credits / rate;
|
|
190368
|
+
return null;
|
|
190369
|
+
}
|
|
190370
|
+
/**
|
|
190371
|
+
* Format a credits-per-USD rate for the "X credits = $1" hint: whole rates
|
|
190372
|
+
* stay whole ("1,000"), fractional ones keep two decimals.
|
|
190373
|
+
*/
|
|
190374
|
+
function formatCreditsPerUsd(rate) {
|
|
190375
|
+
const rounded = Math.round(rate);
|
|
190376
|
+
const isWhole = Math.abs(rate - rounded) < 0.005;
|
|
190377
|
+
return isWhole
|
|
190378
|
+
? rounded.toLocaleString('en-US')
|
|
190379
|
+
: rate.toLocaleString('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 2 });
|
|
190380
|
+
}
|
|
190381
|
+
|
|
188326
190382
|
function formatCredits(credits) {
|
|
188327
190383
|
if (credits === null || credits === undefined || Number.isNaN(credits))
|
|
188328
190384
|
return '0';
|
|
@@ -188357,17 +190413,17 @@ function formatUsd(value) {
|
|
|
188357
190413
|
return '—';
|
|
188358
190414
|
return `$${num.toFixed(2)}`;
|
|
188359
190415
|
}
|
|
188360
|
-
function Section({ title, description, action, children, testId }) {
|
|
188361
|
-
return (jsxs("div", { "data-testid": testId, className:
|
|
190416
|
+
function Section({ title, description, action, children, testId, className }) {
|
|
190417
|
+
return (jsxs("div", { "data-testid": testId, className: cn('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', className), children: [jsxs("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: title }), description && (jsx("p", { className: "text-[13px] font-normal leading-5 text-[#4a5565] dark:text-gray-400", children: description }))] }), action && jsx("div", { className: "shrink-0", children: action })] }), children && (jsx("div", { className: "border-t border-[#e5e7eb] dark:border-zinc-800 px-4 py-3", children: children }))] }));
|
|
188362
190418
|
}
|
|
188363
|
-
function Stat({ label, value, hint }) {
|
|
188364
|
-
return (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: label }), jsx("p", { className: "text-[18px] font-semibold leading-6 text-[#101828] dark:text-gray-100", children: value }), hint && (jsx("p", { className: "text-[12px] font-normal leading-4 text-[#6a7282] dark:text-gray-500", children: hint }))] }));
|
|
190419
|
+
function Stat({ label, value, hint, info }) {
|
|
190420
|
+
return (jsxs("div", { className: "space-y-0.5", children: [jsxs("div", { className: "flex items-center gap-0.5", children: [jsx("p", { className: "text-[11px] font-medium uppercase tracking-wide text-[#6a7282] dark:text-gray-400", children: label }), info && jsx(CardInfoIcon, { description: info, className: "-my-1" })] }), jsx("p", { className: "text-[18px] font-semibold leading-6 text-[#101828] dark:text-gray-100", children: value }), hint && (jsx("p", { className: "text-[12px] font-normal leading-4 text-[#6a7282] dark:text-gray-500", children: hint }))] }));
|
|
188365
190421
|
}
|
|
188366
190422
|
function SectionSkeleton({ withBody = false }) {
|
|
188367
190423
|
return (jsxs("div", { 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: [jsxs("div", { className: "flex flex-col gap-2 p-4 sm:flex-row sm:items-start sm:justify-between", children: [jsxs("div", { className: "space-y-2", children: [jsx(Skeleton, { className: "h-5 w-32" }), jsx(Skeleton, { className: "h-4 w-56" })] }), jsx(Skeleton, { className: "h-9 w-32" })] }), withBody && (jsx("div", { className: "border-t border-[#e5e7eb] dark:border-zinc-800 px-4 py-3", children: jsx("div", { className: "grid grid-cols-1 gap-4 sm:grid-cols-3", children: [0, 1, 2].map((i) => (jsxs("div", { className: "space-y-2", children: [jsx(Skeleton, { className: "h-3 w-20" }), jsx(Skeleton, { className: "h-6 w-24" })] }, i))) }) }))] }));
|
|
188368
190424
|
}
|
|
188369
190425
|
function BillingTab({ tenant, userActiveApp = null, username, mainPlatformKey, currentUserEmail, redirectUrl, }) {
|
|
188370
|
-
var _a;
|
|
190426
|
+
var _a, _b, _c;
|
|
188371
190427
|
const t = useT();
|
|
188372
190428
|
const [isAutoRechargeModalOpen, setIsAutoRechargeModalOpen] = useState(false);
|
|
188373
190429
|
const [isAddCreditsModalOpen, setIsAddCreditsModalOpen] = useState(false);
|
|
@@ -188379,6 +190435,10 @@ function BillingTab({ tenant, userActiveApp = null, username, mainPlatformKey, c
|
|
|
188379
190435
|
currentUserEmail,
|
|
188380
190436
|
});
|
|
188381
190437
|
const { data: billingInfo, isLoading: isBillingInfoLoading } = useGetAccountBillingInfoQuery({ platform_key: tenant }, { refetchOnMountOrArgChange: true });
|
|
190438
|
+
// Top-up rows carry both the credits granted and the dollars paid — the
|
|
190439
|
+
// pair that reveals this environment's credits-per-USD rate for the
|
|
190440
|
+
// dollar-equivalent balance display.
|
|
190441
|
+
const { data: addTransactions } = useGetCreditTransactionsQuery({ platform_key: tenant, transaction_type: 'add' }, { skip: !tenant });
|
|
188382
190442
|
const [createStripePortal] = useCreateStripeCustomerPortalMutation();
|
|
188383
190443
|
const handleBilling = async ({ extraRequestBody = {}, }) => {
|
|
188384
190444
|
return await createStripePortal({
|
|
@@ -188414,7 +190474,7 @@ function BillingTab({ tenant, userActiveApp = null, username, mainPlatformKey, c
|
|
|
188414
190474
|
}
|
|
188415
190475
|
};
|
|
188416
190476
|
if (isBillingInfoLoading) {
|
|
188417
|
-
return (jsx("div", { className: "container max-w-
|
|
190477
|
+
return (jsx("div", { className: "container mx-auto max-w-7xl !mt-0", children: jsxs("div", { className: "space-y-4", children: [jsx(SectionSkeleton, {}), jsx(SectionSkeleton, { withBody: true }), jsx(SectionSkeleton, { withBody: true })] }) }));
|
|
188418
190478
|
}
|
|
188419
190479
|
const billing = billingInfo;
|
|
188420
190480
|
const isFreePlan = formatPlanLabel(billing === null || billing === void 0 ? void 0 : billing.current_plan) === 'Free' ||
|
|
@@ -188427,6 +190487,27 @@ function BillingTab({ tenant, userActiveApp = null, username, mainPlatformKey, c
|
|
|
188427
190487
|
: 'Premium';
|
|
188428
190488
|
const availableCredits = (_a = Number(billing === null || billing === void 0 ? void 0 : billing.available_credits)) !== null && _a !== void 0 ? _a : 0;
|
|
188429
190489
|
const consumedCredits = (billing === null || billing === void 0 ? void 0 : billing.consumed_credits) != null ? parseInt(billing.consumed_credits, 10) : null;
|
|
190490
|
+
// Recharging is priced in dollars, so the balance shows its dollar value
|
|
190491
|
+
// too — but only when the API provides the data for it (the rate differs
|
|
190492
|
+
// per environment and is never hardcoded). Preference order: explicit
|
|
190493
|
+
// account fields, then the credits/dollars pair on the newest top-up
|
|
190494
|
+
// transaction.
|
|
190495
|
+
const creditsPerUsd = (_b = resolveCreditsPerUsd(billing)) !== null && _b !== void 0 ? _b : resolveCreditsPerUsdFromTransactions(addTransactions);
|
|
190496
|
+
const availableCreditsUsd = (_c = resolveAvailableCreditsUsd(billing)) !== null && _c !== void 0 ? _c : (creditsPerUsd != null && Number.isFinite(availableCredits)
|
|
190497
|
+
? availableCredits / creditsPerUsd
|
|
190498
|
+
: null);
|
|
190499
|
+
const availableCreditsHint = availableCreditsUsd != null
|
|
190500
|
+
? [
|
|
190501
|
+
t('profileBilling.creditsUsdEquivalent', { amount: formatUsd(availableCreditsUsd) }),
|
|
190502
|
+
creditsPerUsd != null
|
|
190503
|
+
? t('profileBilling.creditsConversionHint', {
|
|
190504
|
+
credits: formatCreditsPerUsd(creditsPerUsd),
|
|
190505
|
+
})
|
|
190506
|
+
: null,
|
|
190507
|
+
]
|
|
190508
|
+
.filter(Boolean)
|
|
190509
|
+
.join(' · ')
|
|
190510
|
+
: undefined;
|
|
188430
190511
|
const hasPaymentMethod = Boolean(billing === null || billing === void 0 ? void 0 : billing.has_payment_method);
|
|
188431
190512
|
const isAutoRechargeEnabled = Boolean(billing === null || billing === void 0 ? void 0 : billing.auto_recharge_enabled);
|
|
188432
190513
|
const spendingLimitRaw = billing === null || billing === void 0 ? void 0 : billing.auto_recharge_spending_limit_usd;
|
|
@@ -188450,21 +190531,21 @@ function BillingTab({ tenant, userActiveApp = null, username, mainPlatformKey, c
|
|
|
188450
190531
|
}
|
|
188451
190532
|
return t('profileBilling.manageSubscriptionAndBilling');
|
|
188452
190533
|
})();
|
|
188453
|
-
return (jsxs("div", { className: "container mx-auto max-w-
|
|
188454
|
-
|
|
188455
|
-
|
|
188456
|
-
|
|
188457
|
-
|
|
188458
|
-
|
|
188459
|
-
|
|
188460
|
-
|
|
188461
|
-
|
|
188462
|
-
|
|
188463
|
-
|
|
188464
|
-
|
|
188465
|
-
|
|
188466
|
-
|
|
188467
|
-
|
|
190534
|
+
return (jsxs("div", { className: "container mx-auto max-w-7xl !mt-0", children: [jsxs(Tabs, { defaultValue: "plan", "aria-label": t('profileBilling.billingTabsAriaLabel'), children: [jsxs(TabsList, { "aria-label": t('profileBilling.billingTabsAriaLabel'), className: "max-w-full overflow-x-auto justify-start px-1", children: [jsx(TabsTrigger, { value: "plan", children: t('profileBilling.tabPlanAndCredits') }), jsx(TabsTrigger, { value: "spend-limits", children: t('profileBilling.tabSpendLimits') }), jsx(TabsTrigger, { value: "agent-limits", children: t('profileBilling.tabAgentLimits') })] }), jsx(TabsContent, { className: "mt-4", value: "plan", children: jsxs("div", { className: "space-y-4", children: [jsxs("div", { className: "grid grid-cols-1 items-start gap-4 lg:grid-cols-3", children: [jsx(Section, { title: t('profileBilling.planSectionTitle'), testId: "billing-plan-section", description: planDescription, className: "lg:col-span-1 lg:h-full", action: isFreePlan || isTrialPlan ? (jsxs(Button$1, { onClick: () => handleUpgrade('premium'), disabled: isUpgrading, className: "h-9 px-4 text-[14px] font-medium text-white bg-gradient-to-r from-[rgb(56,161,229)] to-[rgb(114,132,255)] hover:opacity-90 disabled:opacity-70", children: [isUpgrading ? (jsx(LoaderCircle, { className: "h-4 w-4 animate-spin" })) : (jsx(Sparkles, { className: "h-4 w-4" })), isUpgrading ? t('profileBilling.redirecting') : t('profileBilling.upgrade')] })) : undefined, children: jsxs("div", { className: "flex items-center gap-2", children: [jsx("span", { "data-testid": "billing-plan-label", className: "text-[18px] font-semibold leading-7 text-[#101828] dark:text-gray-100", children: planLabel }), jsx("span", { className: "rounded-full px-2.5 py-0.5 text-[12px] font-medium", style: {
|
|
190535
|
+
backgroundColor: '#f5f8ff',
|
|
190536
|
+
color: '#155dfc',
|
|
190537
|
+
border: '1px solid #d0e0ff',
|
|
190538
|
+
}, children: t('profileBilling.currentBadge') })] }) }), jsx(Section, { title: t('profileBilling.creditsSectionTitle'), testId: "billing-credits-section", description: t('profileBilling.creditsDescription'), className: "lg:col-span-2 lg:h-full", action: isFreePlan || isTrialPlan ? undefined : hasPaymentMethod ? (jsx(Button$1, { variant: "outline", onClick: () => setIsAddCreditsModalOpen(true), className: "h-9 px-4 text-[14px] font-medium", children: t('profileBilling.addCredits') })) : (jsxs(Button$1, { onClick: handleSetupPaymentMethod, disabled: isRedirectingToPaymentSettings, className: "h-9 px-4 text-[14px] font-medium bg-gradient-to-r from-[#2563EB] to-[#93C5FD] hover:opacity-90 text-white", children: [isRedirectingToPaymentSettings ? (jsx(LoaderCircle, { className: "h-4 w-4 animate-spin" })) : (jsx(Wallet, { className: "h-4 w-4" })), isRedirectingToPaymentSettings
|
|
190539
|
+
? t('profileBilling.redirecting')
|
|
190540
|
+
: t('profileBilling.manageBilling')] })), children: jsxs("div", { className: "grid grid-cols-1 gap-4 sm:grid-cols-3", children: [jsx(Stat, { label: t('profileBilling.availableLabel'), value: t('profileBilling.creditsUnit', { amount: formatCredits(availableCredits) }), hint: availableCreditsHint }), consumedCredits != null && (jsx(Stat, { label: t('profileBilling.consumedLabel'), value: t('profileBilling.creditsUnit', { amount: formatCredits(consumedCredits) }), info: t('profileBilling.usedThisPeriod') })), (billing === null || billing === void 0 ? void 0 : billing.credits_reset_date) && (jsx(Stat, { label: t('profileBilling.resetsOnLabel'), value: formatRenewalDate(billing.credits_reset_date), info: t('profileBilling.nextResetDate') }))] }) })] }), !isFreePlan && !isTrialPlan && hasPaymentMethod && (jsx(Section, { title: t('profileBilling.autoRechargeSectionTitle'), testId: "billing-auto-recharge-section", description: t('profileBilling.autoRechargeDescription'), action: jsxs("div", { className: "flex items-center gap-3", children: [jsx("span", { "data-testid": "billing-auto-recharge-status", className: "rounded-full px-2.5 py-0.5 text-[12px] font-medium", style: {
|
|
190541
|
+
backgroundColor: isAutoRechargeEnabled ? '#f5f8ff' : '#f3f4f6',
|
|
190542
|
+
color: isAutoRechargeEnabled ? '#155dfc' : '#6a7282',
|
|
190543
|
+
border: `1px solid ${isAutoRechargeEnabled ? '#d0e0ff' : '#e5e7eb'}`,
|
|
190544
|
+
}, children: isAutoRechargeEnabled
|
|
190545
|
+
? t('profileBilling.enabled')
|
|
190546
|
+
: t('profileBilling.disabled') }), jsx(Button$1, { variant: "outline", onClick: () => setIsAutoRechargeModalOpen(true), className: "h-9 px-4 text-[14px] font-medium", children: t('profileBilling.manageUsage') })] }), children: isAutoRechargeEnabled ? (jsxs("div", { className: "grid grid-cols-1 gap-4 sm:grid-cols-3", children: [jsx(Stat, { label: t('profileBilling.thresholdLabel'), value: formatUsd(billing === null || billing === void 0 ? void 0 : billing.auto_recharge_threshold_usd), info: t('profileBilling.thresholdHint') }), jsx(Stat, { label: t('profileBilling.rechargeAmountLabel'), value: formatUsd(billing === null || billing === void 0 ? void 0 : billing.auto_recharge_amount_usd), info: t('profileBilling.rechargeAmountHint') }), jsx(Stat, { label: t('profileBilling.spendingLimitLabel'), value: isUnlimitedSpendingLimit
|
|
190547
|
+
? t('profileBilling.unlimited')
|
|
190548
|
+
: formatUsd(spendingLimitRaw), info: t('profileBilling.spendingLimitHint') })] })) : (jsx("p", { className: "text-[14px] font-normal leading-5 text-[#4a5565] dark:text-gray-400", children: t('profileBilling.autoRechargeDisabledMessage') })) }))] }) }), jsx(TabsContent, { className: "mt-4", value: "spend-limits", children: jsx(SpendLimitsSection, { tenantKey: tenant }) }), jsx(TabsContent, { className: "mt-4", value: "agent-limits", children: jsx(AgentLimitsSection, { tenantKey: tenant, username: username }) })] }), jsx(AutoRechargeModal, { tenant: tenant, isOpen: isAutoRechargeModalOpen, onClose: () => setIsAutoRechargeModalOpen(false) }), jsx(AddCreditsModal, { tenant: tenant, isOpen: isAddCreditsModalOpen, onClose: () => setIsAddCreditsModalOpen(false) })] }));
|
|
188468
190549
|
}
|
|
188469
190550
|
|
|
188470
190551
|
const SmtpContent = ({ platformKey }) => {
|
|
@@ -188719,23 +190800,6 @@ const PlatformMembershipContent = ({ platformKey, authURL, }) => {
|
|
|
188719
190800
|
return (jsxs("div", { className: "flex items-center justify-between rounded-lg border px-6 py-6", style: { borderColor: 'oklch(.922 0 0)' }, children: [jsxs("div", { className: "flex items-center gap-2", children: [jsx("span", { className: "text-sm font-medium text-[#646464]", children: t('advancedPlatformMembership.publicRegistrationLabel') }), jsx(TooltipProvider, { children: jsxs(Tooltip$1, { children: [jsx(TooltipTrigger, { "aria-label": t('advancedPlatformMembership.infoAriaLabel'), className: "hidden sm:block", children: jsx(Info$3, { className: "h-4 w-4 text-gray-400" }) }), jsx(TooltipContent, { className: "rounded-lg bg-gray-700 px-3 py-2 text-sm font-medium whitespace-nowrap text-white shadow-sm transition-opacity duration-300 z-50", children: jsx("p", { children: t('advancedPlatformMembership.infoTooltip') }) })] }) }), (membershipData === null || membershipData === void 0 ? void 0 : membershipData.allow_self_linking) && (jsx(TooltipProvider, { children: jsxs(Tooltip$1, { children: [jsx(TooltipTrigger, { onClick: handleCopyToClipboard, "aria-label": t('advancedPlatformMembership.copyAriaLabel'), className: "cursor-pointer hover:bg-gray-100 dark:hover:bg-gray-800 p-1 rounded transition-colors focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-1", children: jsx(Copy, { className: "h-4 w-4 text-gray-400 hover:text-blue-500" }) }), jsx(TooltipContent, { className: "rounded-lg bg-gray-700 px-3 py-2 text-sm font-medium whitespace-nowrap text-white shadow-sm transition-opacity duration-300 z-50", children: jsx("p", { children: t('advancedPlatformMembership.copyTooltip') }) })] }) }))] }), jsxs("div", { className: "flex items-center gap-2", children: [jsx(Switch, { checked: membershipData === null || membershipData === void 0 ? void 0 : membershipData.allow_self_linking, onCheckedChange: handleToggleMembership, disabled: isUpdating, "aria-label": `${t('advancedPlatformMembership.switchAriaLabel')} ${(membershipData === null || membershipData === void 0 ? void 0 : membershipData.allow_self_linking) ? t('advancedPlatformMembership.switchEnabled') : t('advancedPlatformMembership.switchDisabled')}`, className: "cursor-pointer data-[state=checked]:bg-blue-500" }), isUpdating && (jsx("div", { className: "w-4 h-4 border-2 border-blue-500 border-t-transparent rounded-full animate-spin" }))] })] }));
|
|
188720
190801
|
};
|
|
188721
190802
|
|
|
188722
|
-
const Table$1 = React.forwardRef(({ className, ...props }, ref) => (jsx("div", { className: "relative w-full overflow-auto", children: jsx("table", { ref: ref, className: cn("w-full caption-bottom text-sm", className), ...props }) })));
|
|
188723
|
-
Table$1.displayName = "Table";
|
|
188724
|
-
const TableHeader$1 = React.forwardRef(({ className, ...props }, ref) => (jsx("thead", { ref: ref, className: cn("[&_tr]:border-b", className), ...props })));
|
|
188725
|
-
TableHeader$1.displayName = "TableHeader";
|
|
188726
|
-
const TableBody = React.forwardRef(({ className, ...props }, ref) => (jsx("tbody", { ref: ref, className: cn("[&_tr:last-child]:border-0", className), ...props })));
|
|
188727
|
-
TableBody.displayName = "TableBody";
|
|
188728
|
-
const TableFooter = React.forwardRef(({ className, ...props }, ref) => (jsx("tfoot", { ref: ref, className: cn("border-t bg-muted/50 font-medium [&>tr]:last:border-b-0", className), ...props })));
|
|
188729
|
-
TableFooter.displayName = "TableFooter";
|
|
188730
|
-
const TableRow$1 = React.forwardRef(({ className, ...props }, ref) => (jsx("tr", { ref: ref, className: cn("border-b transition-colors hover:bg-muted/50 data-[state=selected]:bg-muted", className), ...props })));
|
|
188731
|
-
TableRow$1.displayName = "TableRow";
|
|
188732
|
-
const TableHead = React.forwardRef(({ className, ...props }, ref) => (jsx("th", { ref: ref, className: cn("h-10 px-2 text-left align-middle font-medium text-muted-foreground [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]", className), ...props })));
|
|
188733
|
-
TableHead.displayName = "TableHead";
|
|
188734
|
-
const TableCell$1 = React.forwardRef(({ className, ...props }, ref) => (jsx("td", { ref: ref, className: cn("p-2 align-middle [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]", className), ...props })));
|
|
188735
|
-
TableCell$1.displayName = "TableCell";
|
|
188736
|
-
const TableCaption = React.forwardRef(({ className, ...props }, ref) => (jsx("caption", { ref: ref, className: cn("mt-4 text-sm text-muted-foreground", className), ...props })));
|
|
188737
|
-
TableCaption.displayName = "TableCaption";
|
|
188738
|
-
|
|
188739
190803
|
const normalizeCustomDomains = (response) => {
|
|
188740
190804
|
if (!response) {
|
|
188741
190805
|
return [];
|
|
@@ -204671,15 +206735,15 @@ var mac$2 = typeof navigator != "undefined" && /Mac/.test(navigator.platform);
|
|
|
204671
206735
|
var ie$1 = typeof navigator != "undefined" && /MSIE \d|Trident\/(?:[7-9]|\d{2,})\..*rv:(\d+)/.exec(navigator.userAgent);
|
|
204672
206736
|
|
|
204673
206737
|
// Fill in the digit keys
|
|
204674
|
-
for (var i$
|
|
206738
|
+
for (var i$8 = 0; i$8 < 10; i$8++) base[48 + i$8] = base[96 + i$8] = String(i$8);
|
|
204675
206739
|
|
|
204676
206740
|
// The function keys
|
|
204677
|
-
for (var i$
|
|
206741
|
+
for (var i$8 = 1; i$8 <= 24; i$8++) base[i$8 + 111] = "F" + i$8;
|
|
204678
206742
|
|
|
204679
206743
|
// And the alphabetic keys
|
|
204680
|
-
for (var i$
|
|
204681
|
-
base[i$
|
|
204682
|
-
shift[i$
|
|
206744
|
+
for (var i$8 = 65; i$8 <= 90; i$8++) {
|
|
206745
|
+
base[i$8] = String.fromCharCode(i$8 + 32);
|
|
206746
|
+
shift[i$8] = String.fromCharCode(i$8);
|
|
204683
206747
|
}
|
|
204684
206748
|
|
|
204685
206749
|
// For each code that doesn't have a shift-equivalent, copy the base name
|
|
@@ -218729,8 +220793,6 @@ function useAgentSearch({ tenantKey, query, limit = 6, offset, starred, featured
|
|
|
218729
220793
|
};
|
|
218730
220794
|
}
|
|
218731
220795
|
|
|
218732
|
-
function c$3(e,u,c){var i=this,a=useRef(null),o=useRef(0),f=useRef(null),l=useRef([]),v=useRef(),m=useRef(),d=useRef(e),g=useRef(true);d.current=e;var p="undefined"!=typeof window,w=!u&&0!==u&&p;if("function"!=typeof e)throw new TypeError("Expected a function");u=+u||0;var s=!!(c=c||{}).leading,x=!("trailing"in c)||!!c.trailing,h="maxWait"in c,y="debounceOnServer"in c&&!!c.debounceOnServer,F=h?Math.max(+c.maxWait||0,u):null;useEffect(function(){return g.current=true,function(){g.current=false;}},[]);var A=useMemo(function(){var r=function(r){var n=l.current,t=v.current;return l.current=v.current=null,o.current=r,m.current=d.current.apply(t,n)},n=function(r,n){w&&cancelAnimationFrame(f.current),f.current=w?requestAnimationFrame(r):setTimeout(r,n);},t=function(r){if(!g.current)return false;var n=r-a.current;return !a.current||n>=u||n<0||h&&r-o.current>=F},e=function(n){return f.current=null,x&&l.current?r(n):(l.current=v.current=null,m.current)},c=function r(){var c=Date.now();if(t(c))return e(c);if(g.current){var i=u-(c-a.current),f=h?Math.min(i,F-(c-o.current)):i;n(r,f);}},A=function(){if(p||y){var e=Date.now(),d=t(e);if(l.current=[].slice.call(arguments),v.current=i,a.current=e,d){if(!f.current&&g.current)return o.current=a.current,n(c,u),s?r(a.current):m.current;if(h)return n(c,u),r(a.current)}return f.current||n(c,u),m.current}};return A.cancel=function(){f.current&&(w?cancelAnimationFrame(f.current):clearTimeout(f.current)),o.current=0,l.current=a.current=v.current=f.current=null;},A.isPending=function(){return !!f.current},A.flush=function(){return f.current?e(Date.now()):m.current},A},[s,h,u,F,x,w,p,y]);return A}function i$8(r,n){return r===n}function a$3(n,t,a){var o=i$8,f=useRef(n),l=useState({})[1],v=c$3(useCallback(function(r){f.current=r,l({});},[l]),t,a),m=useRef(n);return o(m.current,n)||(v(n),m.current=n),[f.current,v]}
|
|
218733
|
-
|
|
218734
220796
|
/**
|
|
218735
220797
|
* Higher-level agent search hook that manages search state, debounce, and
|
|
218736
220798
|
* pagination controls on top of `useAgentSearch`.
|
|
@@ -254673,37 +256735,46 @@ const EMPTY_SKILL_FORM = {
|
|
|
254673
256735
|
};
|
|
254674
256736
|
/** Page size for both skill lists. */
|
|
254675
256737
|
const SKILLS_PAGE_SIZE = 10;
|
|
254676
|
-
// Resolving the agent's own set (assignment metadata + its private skills)
|
|
254677
|
-
// needs a catalog lookup that the API cannot scope server-side yet (there is
|
|
254678
|
-
// no `mentor=` filter), so one bounded background fetch covers the join.
|
|
254679
|
-
const FULL_LIST_LIMIT = 1000;
|
|
254680
256738
|
function AgentSkills({ platformKey, mentorUniqueId }) {
|
|
254681
|
-
var _a, _b, _c, _d;
|
|
256739
|
+
var _a, _b, _c, _d, _e, _f;
|
|
254682
256740
|
const t = useT();
|
|
254683
256741
|
// Skills are managed independently of the sandbox connection — org-level
|
|
254684
256742
|
// skills and the mentor's assignments both resolve without a wired Claw
|
|
254685
256743
|
// instance, so we always fetch and let admins add/assign skills freely.
|
|
254686
|
-
|
|
256744
|
+
// The "Agent Skills" tab pages the assignment list server-side.
|
|
256745
|
+
const [agentPage, setAgentPage] = useState(1);
|
|
256746
|
+
const { data: assignmentsPage, isLoading: isLoadingAssignments } = useGetMentorSkillAssignmentsQuery({
|
|
254687
256747
|
org: platformKey,
|
|
254688
|
-
|
|
254689
|
-
|
|
256748
|
+
mentorUniqueId,
|
|
256749
|
+
limit: SKILLS_PAGE_SIZE,
|
|
256750
|
+
offset: (agentPage - 1) * SKILLS_PAGE_SIZE,
|
|
254690
256751
|
});
|
|
254691
|
-
const
|
|
256752
|
+
const agentAssignments = (_a = assignmentsPage === null || assignmentsPage === void 0 ? void 0 : assignmentsPage.results) !== null && _a !== void 0 ? _a : [];
|
|
256753
|
+
const agentTotalCount = (_b = assignmentsPage === null || assignmentsPage === void 0 ? void 0 : assignmentsPage.count) !== null && _b !== void 0 ? _b : 0;
|
|
256754
|
+
const agentTotalPages = Math.max(1, Math.ceil(agentTotalCount / SKILLS_PAGE_SIZE));
|
|
256755
|
+
useEffect(() => {
|
|
256756
|
+
if (agentPage > agentTotalPages)
|
|
256757
|
+
setAgentPage(agentTotalPages);
|
|
256758
|
+
}, [agentPage, agentTotalPages]);
|
|
256759
|
+
// Unpaged lookup of the same (per-agent, naturally small) assignment list —
|
|
256760
|
+
// powers the "Added" chips on the catalog tab, since the API has no
|
|
256761
|
+
// per-skill "is assigned" check to ask instead.
|
|
256762
|
+
const { data: assignmentCoverage } = useGetMentorSkillAssignmentsQuery({
|
|
254692
256763
|
org: platformKey,
|
|
254693
256764
|
mentorUniqueId,
|
|
254694
|
-
limit: FULL_LIST_LIMIT,
|
|
254695
|
-
offset: 0,
|
|
254696
256765
|
});
|
|
254697
|
-
|
|
256766
|
+
const assignedSkillIds = new Set(((_c = assignmentCoverage === null || assignmentCoverage === void 0 ? void 0 : assignmentCoverage.results) !== null && _c !== void 0 ? _c : []).map((a) => a.skill));
|
|
256767
|
+
// The "Available skills" tab pages the catalog server-side. Deliberately
|
|
256768
|
+
// unfiltered: disabled skills stay listed (switch off) so admins can
|
|
256769
|
+
// re-enable, edit or delete them.
|
|
254698
256770
|
const [catalogPage, setCatalogPage] = useState(1);
|
|
254699
256771
|
const { data: catalogSkillsPage, isLoading: isLoadingCatalog } = useGetAgentSkillsQuery({
|
|
254700
256772
|
org: platformKey,
|
|
254701
|
-
enabled: true,
|
|
254702
256773
|
limit: SKILLS_PAGE_SIZE,
|
|
254703
256774
|
offset: (catalogPage - 1) * SKILLS_PAGE_SIZE,
|
|
254704
256775
|
});
|
|
254705
|
-
const catalogSkills = (
|
|
254706
|
-
const catalogTotalCount = (
|
|
256776
|
+
const catalogSkills = (_d = catalogSkillsPage === null || catalogSkillsPage === void 0 ? void 0 : catalogSkillsPage.results) !== null && _d !== void 0 ? _d : [];
|
|
256777
|
+
const catalogTotalCount = (_e = catalogSkillsPage === null || catalogSkillsPage === void 0 ? void 0 : catalogSkillsPage.count) !== null && _e !== void 0 ? _e : 0;
|
|
254707
256778
|
const catalogTotalPages = Math.max(1, Math.ceil(catalogTotalCount / SKILLS_PAGE_SIZE));
|
|
254708
256779
|
useEffect(() => {
|
|
254709
256780
|
if (catalogPage > catalogTotalPages)
|
|
@@ -254721,25 +256792,11 @@ function AgentSkills({ platformKey, mentorUniqueId }) {
|
|
|
254721
256792
|
const [editingSkill, setEditingSkill] = useState(null);
|
|
254722
256793
|
const [deletingSkill, setDeletingSkill] = useState(null);
|
|
254723
256794
|
const [form, setForm] = useState(EMPTY_SKILL_FORM);
|
|
254724
|
-
const
|
|
254725
|
-
|
|
254726
|
-
|
|
254727
|
-
|
|
254728
|
-
const
|
|
254729
|
-
const effectiveSlugs = new Set(effectiveSkills.map((s) => s.slug));
|
|
254730
|
-
// The "Agent skills" tab pages the (small, per-agent) effective set locally.
|
|
254731
|
-
const [agentPage, setAgentPage] = useState(1);
|
|
254732
|
-
const agentTotalPages = Math.max(1, Math.ceil(effectiveSkills.length / SKILLS_PAGE_SIZE));
|
|
254733
|
-
useEffect(() => {
|
|
254734
|
-
if (agentPage > agentTotalPages)
|
|
254735
|
-
setAgentPage(agentTotalPages);
|
|
254736
|
-
}, [agentPage, agentTotalPages]);
|
|
254737
|
-
const pagedEffectiveSkills = effectiveSkills.slice((agentPage - 1) * SKILLS_PAGE_SIZE, agentPage * SKILLS_PAGE_SIZE);
|
|
254738
|
-
// Catalog rows already covered by the agent's set (attached, or shadowed by
|
|
254739
|
-
// a same-slug private skill) show an "Added" chip instead of an Add button
|
|
254740
|
-
// — hiding them would make server pages uneven. Another agent's private
|
|
254741
|
-
// skills are not attachable at all.
|
|
254742
|
-
const isCoveredByAgent = (skill) => effectiveUniqueIds.has(skill.unique_id) || effectiveSlugs.has(skill.slug);
|
|
256795
|
+
const isMutatingAgentSkill = isCreatingAssignment || isUpdatingAssignment || isDeletingAssignment;
|
|
256796
|
+
// Catalog rows already assigned to the agent show an "Added" chip instead
|
|
256797
|
+
// of an Add button — hiding them would make server pages uneven. Another
|
|
256798
|
+
// agent's private skills get a disabled Add with an explanatory tooltip.
|
|
256799
|
+
const isCoveredByAgent = (skill) => assignedSkillIds.has(skill.unique_id);
|
|
254743
256800
|
const isOtherAgentsPrivate = (skill) => !!skill.mentor && skill.mentor !== mentorUniqueId;
|
|
254744
256801
|
// Featured skills from the `main` platform are read-only for tenants — the
|
|
254745
256802
|
// API 404s writes against them, so hide the edit/delete affordances.
|
|
@@ -254749,29 +256806,20 @@ function AgentSkills({ platformKey, mentorUniqueId }) {
|
|
|
254749
256806
|
return skill.platform_key ? skill.platform_key === platformKey : !skill.is_featured;
|
|
254750
256807
|
};
|
|
254751
256808
|
const resetForm = () => setForm(EMPTY_SKILL_FORM);
|
|
254752
|
-
const
|
|
256809
|
+
const handleToggleAssignment = async (assignment, shouldEnable) => {
|
|
254753
256810
|
try {
|
|
254754
|
-
|
|
254755
|
-
|
|
254756
|
-
|
|
254757
|
-
|
|
254758
|
-
|
|
254759
|
-
|
|
254760
|
-
}
|
|
254761
|
-
else if (effective.assignmentId !== undefined) {
|
|
254762
|
-
await updateAssignment({
|
|
254763
|
-
org: platformKey,
|
|
254764
|
-
mentorUniqueId,
|
|
254765
|
-
assignmentPk: effective.assignmentId,
|
|
254766
|
-
enabled: shouldEnable,
|
|
254767
|
-
}).unwrap();
|
|
254768
|
-
}
|
|
256811
|
+
await updateAssignment({
|
|
256812
|
+
org: platformKey,
|
|
256813
|
+
mentorUniqueId,
|
|
256814
|
+
assignmentPk: assignment.id,
|
|
256815
|
+
enabled: shouldEnable,
|
|
256816
|
+
}).unwrap();
|
|
254769
256817
|
toast.success(t(shouldEnable
|
|
254770
256818
|
? 'clawSandboxAgentSkills.skillEnabled'
|
|
254771
|
-
: 'clawSandboxAgentSkills.skillDisabled', { name:
|
|
256819
|
+
: 'clawSandboxAgentSkills.skillDisabled', { name: assignment.skill_name }));
|
|
254772
256820
|
}
|
|
254773
256821
|
catch (_a) {
|
|
254774
|
-
toast.error(t('clawSandboxAgentSkills.failedToUpdateSkill', { name:
|
|
256822
|
+
toast.error(t('clawSandboxAgentSkills.failedToUpdateSkill', { name: assignment.skill_name }));
|
|
254775
256823
|
}
|
|
254776
256824
|
};
|
|
254777
256825
|
const handleAttach = async (skill) => {
|
|
@@ -254788,19 +256836,30 @@ function AgentSkills({ platformKey, mentorUniqueId }) {
|
|
|
254788
256836
|
toast.error(t('clawSandboxAgentSkills.failedToUpdateSkill', { name: skill.name }));
|
|
254789
256837
|
}
|
|
254790
256838
|
};
|
|
254791
|
-
|
|
254792
|
-
|
|
254793
|
-
|
|
256839
|
+
// Platform-level enable/disable of the skill itself (catalog rows) — the
|
|
256840
|
+
// agent-tab switches PATCH the assignment instead.
|
|
256841
|
+
const handleToggleSkill = async (skill, shouldEnable) => {
|
|
256842
|
+
try {
|
|
256843
|
+
await updateSkill({ org: platformKey, id: skill.id, enabled: shouldEnable }).unwrap();
|
|
256844
|
+
toast.success(t(shouldEnable
|
|
256845
|
+
? 'clawSandboxAgentSkills.skillEnabled'
|
|
256846
|
+
: 'clawSandboxAgentSkills.skillDisabled', { name: skill.name }));
|
|
256847
|
+
}
|
|
256848
|
+
catch (_a) {
|
|
256849
|
+
toast.error(t('clawSandboxAgentSkills.failedToUpdateSkill', { name: skill.name }));
|
|
256850
|
+
}
|
|
256851
|
+
};
|
|
256852
|
+
const handleDetach = async (assignment) => {
|
|
254794
256853
|
try {
|
|
254795
256854
|
await deleteAssignment({
|
|
254796
256855
|
org: platformKey,
|
|
254797
256856
|
mentorUniqueId,
|
|
254798
|
-
assignmentPk:
|
|
256857
|
+
assignmentPk: assignment.id,
|
|
254799
256858
|
}).unwrap();
|
|
254800
|
-
toast.success(t('clawSandboxAgentSkills.skillRemoved', { name:
|
|
256859
|
+
toast.success(t('clawSandboxAgentSkills.skillRemoved', { name: assignment.skill_name }));
|
|
254801
256860
|
}
|
|
254802
256861
|
catch (_a) {
|
|
254803
|
-
toast.error(t('clawSandboxAgentSkills.failedToUpdateSkill', { name:
|
|
256862
|
+
toast.error(t('clawSandboxAgentSkills.failedToUpdateSkill', { name: assignment.skill_name }));
|
|
254804
256863
|
}
|
|
254805
256864
|
};
|
|
254806
256865
|
const openNewSkillDialog = () => {
|
|
@@ -254831,7 +256890,7 @@ function AgentSkills({ platformKey, mentorUniqueId }) {
|
|
|
254831
256890
|
return;
|
|
254832
256891
|
}
|
|
254833
256892
|
try {
|
|
254834
|
-
await createSkill({
|
|
256893
|
+
const created = await createSkill({
|
|
254835
256894
|
org: platformKey,
|
|
254836
256895
|
name: form.name,
|
|
254837
256896
|
slug: form.slug,
|
|
@@ -254842,6 +256901,16 @@ function AgentSkills({ platformKey, mentorUniqueId }) {
|
|
|
254842
256901
|
instruction: form.instruction,
|
|
254843
256902
|
enabled: true,
|
|
254844
256903
|
}).unwrap();
|
|
256904
|
+
// A private skill only takes effect once assigned, and the Agent Skills
|
|
256905
|
+
// tab lists assignments — so attach it to this agent right away.
|
|
256906
|
+
if (form.privateToAgent && (created === null || created === void 0 ? void 0 : created.unique_id)) {
|
|
256907
|
+
await createAssignment({
|
|
256908
|
+
org: platformKey,
|
|
256909
|
+
mentorUniqueId,
|
|
256910
|
+
skill: created.unique_id,
|
|
256911
|
+
enabled: true,
|
|
256912
|
+
}).unwrap();
|
|
256913
|
+
}
|
|
254845
256914
|
toast.success(t('clawSandboxAgentSkills.skillCreated'));
|
|
254846
256915
|
closeAllDialogs();
|
|
254847
256916
|
}
|
|
@@ -254856,6 +256925,10 @@ function AgentSkills({ platformKey, mentorUniqueId }) {
|
|
|
254856
256925
|
toast.error(t('clawSandboxAgentSkills.nameAndSlugRequired'));
|
|
254857
256926
|
return;
|
|
254858
256927
|
}
|
|
256928
|
+
// A skill private to a different agent keeps its owner: the "Only This
|
|
256929
|
+
// Agent" toggle is locked in the form, and the PATCH omits `mentor` so a
|
|
256930
|
+
// save here can never silently un-private (or steal) it.
|
|
256931
|
+
const privateLocked = isOtherAgentsPrivate(editingSkill);
|
|
254859
256932
|
try {
|
|
254860
256933
|
await updateSkill({
|
|
254861
256934
|
org: platformKey,
|
|
@@ -254866,8 +256939,18 @@ function AgentSkills({ platformKey, mentorUniqueId }) {
|
|
|
254866
256939
|
version: form.version,
|
|
254867
256940
|
category: form.category,
|
|
254868
256941
|
instruction: form.instruction,
|
|
254869
|
-
mentor: form.privateToAgent ? mentorUniqueId : null,
|
|
256942
|
+
...(!privateLocked && { mentor: form.privateToAgent ? mentorUniqueId : null }),
|
|
254870
256943
|
}).unwrap();
|
|
256944
|
+
// Making a skill private to this agent implies it should be usable by
|
|
256945
|
+
// it — attach it if it isn't assigned yet.
|
|
256946
|
+
if (!privateLocked && form.privateToAgent && !assignedSkillIds.has(editingSkill.unique_id)) {
|
|
256947
|
+
await createAssignment({
|
|
256948
|
+
org: platformKey,
|
|
256949
|
+
mentorUniqueId,
|
|
256950
|
+
skill: editingSkill.unique_id,
|
|
256951
|
+
enabled: true,
|
|
256952
|
+
}).unwrap();
|
|
256953
|
+
}
|
|
254871
256954
|
toast.success(t('clawSandboxAgentSkills.skillUpdated'));
|
|
254872
256955
|
closeAllDialogs();
|
|
254873
256956
|
}
|
|
@@ -254887,46 +256970,40 @@ function AgentSkills({ platformKey, mentorUniqueId }) {
|
|
|
254887
256970
|
toast.error(t('clawSandboxAgentSkills.failedToDeleteSkill'));
|
|
254888
256971
|
}
|
|
254889
256972
|
};
|
|
254890
|
-
const renderBadges = (skill,
|
|
254891
|
-
|
|
254892
|
-
|
|
254893
|
-
|
|
254894
|
-
|
|
254895
|
-
|
|
254896
|
-
};
|
|
254897
|
-
const renderSkillMenu = (skill, effective) => {
|
|
254898
|
-
var _a, _b;
|
|
254899
|
-
const editable = isSkillEditable(skill);
|
|
254900
|
-
const showEdit = editable;
|
|
254901
|
-
const showDelete = editable;
|
|
254902
|
-
const detachable = (effective === null || effective === void 0 ? void 0 : effective.origin) === 'assignment';
|
|
254903
|
-
if (!showEdit && !showDelete && !detachable)
|
|
256973
|
+
const renderBadges = (skill) => (jsxs("span", { className: "flex flex-wrap items-center gap-1", children: [skill.category && (jsx("span", { className: "rounded-full bg-gray-100 px-2 py-0.5 text-[0.625rem] text-gray-500", children: skill.category })), skill.skill_type === 'native' && (jsx("span", { className: "rounded-full bg-purple-50 px-2 py-0.5 text-[0.625rem] text-purple-600", children: t('clawSandboxAgentSkills.nativeBadge') })), skill.is_featured && (jsx("span", { className: "rounded-full bg-amber-50 px-2 py-0.5 text-[0.625rem] text-amber-600", children: t('clawSandboxAgentSkills.featuredBadge') })), skill.mentor === mentorUniqueId && (jsx("span", { className: "rounded-full bg-blue-50 px-2 py-0.5 text-[0.625rem] text-blue-600", children: t('clawSandboxAgentSkills.privateBadge') }))] }));
|
|
256974
|
+
// Agent-tab rows are assignments: their only row action is detaching.
|
|
256975
|
+
const renderAssignmentMenu = (assignment) => (jsxs(DropdownMenu, { children: [jsx(DropdownMenuTrigger, { asChild: true, children: jsx(Button$1, { variant: "ghost", size: "sm", "aria-label": t('clawSandboxAgentSkills.skillActions', { name: assignment.skill_name }), children: jsx(Ellipsis, { className: "h-4 w-4" }) }) }), jsx(DropdownMenuContent, { align: "end", children: jsxs(DropdownMenuItem, { className: "cursor-pointer", onClick: () => handleDetach(assignment), children: [jsx(CircleMinus$1, { className: "mr-2 h-4 w-4" }), t('clawSandboxAgentSkills.removeFromAgent')] }) })] }));
|
|
256976
|
+
// Catalog rows carry the full skill object: edit/delete where allowed.
|
|
256977
|
+
const renderSkillMenu = (skill) => {
|
|
256978
|
+
if (!isSkillEditable(skill))
|
|
254904
256979
|
return null;
|
|
254905
|
-
|
|
254906
|
-
|
|
254907
|
-
}
|
|
254908
|
-
|
|
254909
|
-
|
|
254910
|
-
|
|
254911
|
-
|
|
254912
|
-
|
|
254913
|
-
|
|
254914
|
-
|
|
254915
|
-
: 'clawSandboxAgentSkills.skillDisabledLabel', { name: effective.name }) }), renderSkillMenu(effective.skill, effective)] })] }, effective.unique_id));
|
|
254916
|
-
}), jsx(IblPagination, { currentPage: agentPage, totalPages: agentTotalPages, onPageChange: setAgentPage, disabled: isMutatingAgentSkill })] })) }), jsx(TabsContent, { value: "available", className: "space-y-3", children: isLoadingCatalog ? (jsxs("div", { className: "flex items-center gap-2 p-4", role: "status", children: [jsx(LoaderCircle, { className: "h-4 w-4 animate-spin text-blue-500" }), jsx("span", { className: "text-sm text-gray-500", children: t('clawSandboxAgentSkills.loadingSkills') })] })) : catalogTotalCount === 0 ? (jsx("div", { className: "flex items-center justify-center rounded-lg border p-6", children: jsx("p", { className: "text-sm text-gray-500", children: t('clawSandboxAgentSkills.noSkillsAvailable') }) })) : (jsxs(Fragment$1, { children: [catalogSkills.map((skill) => (jsxs("div", { className: "flex items-center justify-between gap-4 rounded-lg border p-4", "data-testid": "available-skill-row", children: [jsxs("div", { className: "min-w-0 space-y-1", children: [jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [jsx("span", { className: "text-sm font-medium text-gray-700", children: skill.name }), jsxs("span", { className: "hidden text-xs text-gray-400 sm:inline", children: ["v", skill.version] }), renderBadges(skill)] }), skill.description && (jsx("p", { className: "line-clamp-2 text-xs text-gray-500", children: skill.description }))] }), jsxs("div", { className: "flex shrink-0 items-center gap-2", children: [isCoveredByAgent(skill) ? (jsx("span", { className: "rounded-full bg-green-50 px-2 py-0.5 text-xs text-green-700", children: t('clawSandboxAgentSkills.addedBadge') })) : (!isOtherAgentsPrivate(skill) && (jsxs(Button$1, { variant: "outline", size: "sm", className: "cursor-pointer", disabled: isMutatingAgentSkill, onClick: () => handleAttach(skill), "aria-label": t('clawSandboxAgentSkills.addToAgentLabel', {
|
|
256980
|
+
return (jsxs(DropdownMenu, { children: [jsx(DropdownMenuTrigger, { asChild: true, children: jsx(Button$1, { variant: "ghost", size: "sm", "aria-label": t('clawSandboxAgentSkills.skillActions', { name: skill.name }), children: jsx(Ellipsis, { className: "h-4 w-4" }) }) }), jsxs(DropdownMenuContent, { align: "end", children: [jsxs(DropdownMenuItem, { className: "cursor-pointer", onClick: () => openEditSkillDialog(skill), children: [jsx(Pen, { className: "mr-2 h-4 w-4" }), t('clawSandboxAgentSkills.edit')] }), jsxs(DropdownMenuItem, { variant: "destructive", className: "cursor-pointer", onClick: () => setDeletingSkill(skill), children: [jsx(Trash2, { className: "mr-2 h-4 w-4" }), t('clawSandboxAgentSkills.delete')] })] })] }));
|
|
256981
|
+
};
|
|
256982
|
+
return (jsxs("div", { className: "space-y-4", "data-testid": "agent-skills-content", children: [jsxs("div", { className: "flex items-start justify-between gap-4", children: [jsxs("p", { className: "flex items-start gap-2 text-xs text-gray-500", children: [jsx(Info$3, { className: "mt-0.5 h-4 w-4 shrink-0 text-gray-400" }), jsx("span", { children: t('clawSandboxAgentSkills.sessionNote') })] }), jsxs(Button$1, { onClick: openNewSkillDialog, size: "sm", className: "shrink-0 cursor-pointer bg-gradient-to-r from-[#2563EB] to-[#93C5FD] text-white hover:opacity-90", children: [jsx(Plus, { className: "h-4 w-4" }), t('clawSandboxAgentSkills.newSkill')] })] }), jsxs(Tabs, { defaultValue: "agent", className: "w-full", children: [jsxs(TabsList, { "aria-label": t('clawSandboxAgentSkills.tabsAriaLabel'), "data-testid": "agent-skills-tabs", children: [jsx(TabsTrigger, { value: "agent", "data-testid": "agent-skills-tab-agent", children: t('clawSandboxAgentSkills.tabAgentSkills') }), jsx(TabsTrigger, { value: "available", "data-testid": "agent-skills-tab-available", children: t('clawSandboxAgentSkills.tabAvailableSkills') })] }), jsx(TabsContent, { value: "agent", className: "space-y-3", children: isLoadingAssignments ? (jsxs("div", { className: "flex items-center gap-2 p-4", role: "status", children: [jsx(LoaderCircle, { className: "h-4 w-4 animate-spin text-blue-500" }), jsx("span", { className: "text-sm text-gray-500", children: t('clawSandboxAgentSkills.loadingSkills') })] })) : agentTotalCount === 0 ? (jsx("div", { className: "flex items-center justify-center rounded-lg border p-6", children: jsx("p", { className: "text-sm text-gray-500", children: t('clawSandboxAgentSkills.noEffectiveSkills') }) })) : (jsxs(Fragment$1, { children: [agentAssignments.map((assignment) => (jsxs("div", { className: "flex items-center justify-between gap-4 rounded-lg border p-4", "data-testid": "agent-skill-row", children: [jsx("div", { className: "min-w-0 space-y-1", children: jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [jsx("span", { className: "text-sm font-medium text-gray-700", children: assignment.skill_name }), assignment.skill_slug && (jsxs("span", { className: "hidden text-xs text-gray-400 sm:inline", children: ["/", assignment.skill_slug] }))] }) }), jsxs("div", { className: "flex shrink-0 items-center gap-2", children: [jsx(Switch, { checked: assignment.enabled, onCheckedChange: (checked) => handleToggleAssignment(assignment, checked), disabled: isMutatingAgentSkill, className: "cursor-pointer data-[state=checked]:bg-blue-500", "aria-label": t(assignment.enabled
|
|
256983
|
+
? 'clawSandboxAgentSkills.skillEnabledLabel'
|
|
256984
|
+
: 'clawSandboxAgentSkills.skillDisabledLabel', { name: assignment.skill_name }) }), renderAssignmentMenu(assignment)] })] }, assignment.id))), jsx(IblPagination, { currentPage: agentPage, totalPages: agentTotalPages, onPageChange: setAgentPage, disabled: isMutatingAgentSkill })] })) }), jsx(TabsContent, { value: "available", className: "space-y-3", children: isLoadingCatalog ? (jsxs("div", { className: "flex items-center gap-2 p-4", role: "status", children: [jsx(LoaderCircle, { className: "h-4 w-4 animate-spin text-blue-500" }), jsx("span", { className: "text-sm text-gray-500", children: t('clawSandboxAgentSkills.loadingSkills') })] })) : catalogTotalCount === 0 ? (jsx("div", { className: "flex items-center justify-center rounded-lg border p-6", children: jsx("p", { className: "text-sm text-gray-500", children: t('clawSandboxAgentSkills.noSkillsAvailable') }) })) : (jsxs(Fragment$1, { children: [catalogSkills.map((skill) => (jsxs("div", { className: "flex items-center justify-between gap-4 rounded-lg border p-4", "data-testid": "available-skill-row", children: [jsxs("div", { className: "min-w-0 space-y-1", children: [jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [jsx("span", { className: "text-sm font-medium text-gray-700", children: skill.name }), jsxs("span", { className: "hidden text-xs text-gray-400 sm:inline", children: ["v", skill.version] }), renderBadges(skill)] }), skill.description && (jsx("p", { className: "line-clamp-2 text-xs text-gray-500", children: skill.description }))] }), jsxs("div", { className: "flex shrink-0 items-center gap-2", children: [isCoveredByAgent(skill) ? (jsx("span", { className: "rounded-full bg-green-50 px-2 py-0.5 text-xs text-green-700", children: t('clawSandboxAgentSkills.addedBadge') })) : isOtherAgentsPrivate(skill) ? (
|
|
256985
|
+
// Another agent's private skill: Add stays visible but
|
|
256986
|
+
// disabled, with the reason on hover/focus.
|
|
256987
|
+
jsx(TooltipProvider, { children: jsxs(Tooltip$1, { children: [jsx(TooltipTrigger, { asChild: true, children: jsx("span", { tabIndex: 0, children: jsxs(Button$1, { variant: "outline", size: "sm", disabled: true, "aria-label": t('clawSandboxAgentSkills.addToAgentLabel', {
|
|
256988
|
+
name: skill.name,
|
|
256989
|
+
}), children: [jsx(Plus, { className: "h-4 w-4" }), t('clawSandboxAgentSkills.addToAgent')] }) }) }), jsx(TooltipContent, { className: "ibl-tooltip-content max-w-64", children: jsx("p", { children: t('clawSandboxAgentSkills.privateToOtherAgentTooltip') }) })] }) })) : (jsxs(Button$1, { variant: "outline", size: "sm", className: "cursor-pointer", disabled: isMutatingAgentSkill, onClick: () => handleAttach(skill), "aria-label": t('clawSandboxAgentSkills.addToAgentLabel', {
|
|
254917
256990
|
name: skill.name,
|
|
254918
|
-
}), children: [jsx(Plus, { className: "h-4 w-4" }), t('clawSandboxAgentSkills.addToAgent')] }))
|
|
256991
|
+
}), children: [jsx(Plus, { className: "h-4 w-4" }), t('clawSandboxAgentSkills.addToAgent')] })), isSkillEditable(skill) && (jsx(Switch, { checked: skill.enabled, onCheckedChange: (checked) => handleToggleSkill(skill, checked), disabled: isUpdatingSkill, className: "cursor-pointer data-[state=checked]:bg-blue-500", "aria-label": t(skill.enabled
|
|
256992
|
+
? 'clawSandboxAgentSkills.skillEnabledLabel'
|
|
256993
|
+
: 'clawSandboxAgentSkills.skillDisabledLabel', { name: skill.name }) })), renderSkillMenu(skill)] })] }, skill.id))), jsx(IblPagination, { currentPage: catalogPage, totalPages: catalogTotalPages, onPageChange: setCatalogPage, disabled: isMutatingAgentSkill })] })) })] }), jsx(OverlayModal, { open: showNewDialog, onClose: closeAllDialogs, title: t('clawSandboxAgentSkills.newSkillDialogTitle'), className: "max-w-2xl", children: jsxs("div", { className: "flex h-[min(75dvh,46rem)] flex-col", children: [jsxs("div", { className: "flex-1 space-y-4 overflow-y-auto pb-4 pr-1", children: [jsx(SkillForm, { form: form, onChange: setForm }), jsx("p", { className: "text-xs text-gray-500", children: t('clawSandboxAgentSkills.filesAfterCreateHint') })] }), jsxs("div", { className: "flex justify-end gap-2 border-t pt-4", children: [jsx(Button$1, { variant: "outline", onClick: closeAllDialogs, children: t('clawSandboxAgentSkills.cancel') }), jsx(Button$1, { onClick: handleCreateSkill, disabled: isCreatingSkill || !form.name || !form.slug, className: "bg-gradient-to-r from-[#2563EB] to-[#93C5FD] text-white hover:opacity-90", children: isCreatingSkill
|
|
254919
256994
|
? t('clawSandboxAgentSkills.creating')
|
|
254920
|
-
: t('clawSandboxAgentSkills.create') })] })] }) }), jsx(OverlayModal, { open: !!editingSkill, onClose: closeAllDialogs, title: t('clawSandboxAgentSkills.editSkillDialogTitle'), className: "max-w-2xl", children: jsxs(Tabs, { defaultValue: "details", className: "w-full", children: [jsxs(TabsList, { "aria-label": t('clawSandboxAgentSkills.editSkillDialogTitle'), "data-testid": "skill-dialog-tabs", children: [jsx(TabsTrigger, { value: "details", "data-testid": "skill-dialog-tab-details", children: t('clawSandboxAgentSkills.detailsTab') }), jsx(TabsTrigger, { value: "files", "data-testid": "skill-dialog-tab-files", children: t('clawSandboxAgentSkills.filesTab') })] }), jsx(TabsContent, { value: "details", children: jsxs("div", { className: "flex h-[min(75dvh,46rem)] flex-col", children: [jsx("div", { className: "flex-1 space-y-4 overflow-y-auto pb-4 pr-1", children: jsx(SkillForm, { form: form, onChange: setForm }) }), jsxs("div", { className: "flex justify-end gap-2 border-t pt-4", children: [jsx(Button$1, { variant: "outline", onClick: closeAllDialogs, children: t('clawSandboxAgentSkills.cancel') }), jsx(Button$1, { onClick: handleUpdateSkill, disabled: isUpdatingSkill || !form.name || !form.slug, className: "bg-gradient-to-r from-[#2563EB] to-[#93C5FD] text-white hover:opacity-90", children: isUpdatingSkill
|
|
256995
|
+
: t('clawSandboxAgentSkills.create') })] })] }) }), jsx(OverlayModal, { open: !!editingSkill, onClose: closeAllDialogs, title: t('clawSandboxAgentSkills.editSkillDialogTitle'), className: "max-w-2xl", children: jsxs(Tabs, { defaultValue: "details", className: "w-full", children: [jsxs(TabsList, { "aria-label": t('clawSandboxAgentSkills.editSkillDialogTitle'), "data-testid": "skill-dialog-tabs", children: [jsx(TabsTrigger, { value: "details", "data-testid": "skill-dialog-tab-details", children: t('clawSandboxAgentSkills.detailsTab') }), jsx(TabsTrigger, { value: "files", "data-testid": "skill-dialog-tab-files", children: t('clawSandboxAgentSkills.filesTab') })] }), jsx(TabsContent, { value: "details", children: jsxs("div", { className: "flex h-[min(75dvh,46rem)] flex-col", children: [jsx("div", { className: "flex-1 space-y-4 overflow-y-auto pb-4 pr-1", children: jsx(SkillForm, { form: form, onChange: setForm, privateLocked: !!editingSkill && isOtherAgentsPrivate(editingSkill) }) }), jsxs("div", { className: "flex justify-end gap-2 border-t pt-4", children: [jsx(Button$1, { variant: "outline", onClick: closeAllDialogs, children: t('clawSandboxAgentSkills.cancel') }), jsx(Button$1, { onClick: handleUpdateSkill, disabled: isUpdatingSkill || !form.name || !form.slug, className: "bg-gradient-to-r from-[#2563EB] to-[#93C5FD] text-white hover:opacity-90", children: isUpdatingSkill
|
|
254921
256996
|
? t('clawSandboxAgentSkills.saving')
|
|
254922
|
-
: t('clawSandboxAgentSkills.save') })] })] }) }), jsx(TabsContent, { value: "files", children: jsx("div", { className: "flex h-[min(75dvh,46rem)] flex-col", children: jsx("div", { className: "flex-1 space-y-4 overflow-y-auto pb-4 pr-1", children: editingSkill && (jsx(SkillResourcesSection, { platformKey: platformKey, skillId: editingSkill.id })) }) }) })] }) }), jsxs(OverlayModal, { open: !!deletingSkill, onClose: () => setDeletingSkill(null), title: t('clawSandboxAgentSkills.deleteSkillDialogTitle'), className: "max-w-md", children: [jsx("p", { className: "mt-2 text-sm text-gray-600", children: t('clawSandboxAgentSkills.deleteConfirmation', { name: (
|
|
256997
|
+
: t('clawSandboxAgentSkills.save') })] })] }) }), jsx(TabsContent, { value: "files", children: jsx("div", { className: "flex h-[min(75dvh,46rem)] flex-col", children: jsx("div", { className: "flex-1 space-y-4 overflow-y-auto pb-4 pr-1", children: editingSkill && (jsx(SkillResourcesSection, { platformKey: platformKey, skillId: editingSkill.id })) }) }) })] }) }), jsxs(OverlayModal, { open: !!deletingSkill, onClose: () => setDeletingSkill(null), title: t('clawSandboxAgentSkills.deleteSkillDialogTitle'), className: "max-w-md", children: [jsx("p", { className: "mt-2 text-sm text-gray-600", children: t('clawSandboxAgentSkills.deleteConfirmation', { name: (_f = deletingSkill === null || deletingSkill === void 0 ? void 0 : deletingSkill.name) !== null && _f !== void 0 ? _f : '' }) }), jsxs("div", { className: "flex justify-end gap-2 pt-2", children: [jsx(Button$1, { variant: "outline", onClick: () => setDeletingSkill(null), children: t('clawSandboxAgentSkills.cancel') }), jsx(Button$1, { onClick: handleDeleteSkill, disabled: isDeletingSkill, className: "bg-red-600 text-white hover:bg-red-700", children: isDeletingSkill
|
|
254923
256998
|
? t('clawSandboxAgentSkills.deleting')
|
|
254924
256999
|
: t('clawSandboxAgentSkills.delete') })] })] })] }));
|
|
254925
257000
|
}
|
|
254926
257001
|
// ── Shared Skill Form ────────────────────────────────────────────────────────
|
|
254927
|
-
function SkillForm({ form, onChange, }) {
|
|
257002
|
+
function SkillForm({ form, onChange, privateLocked = false, }) {
|
|
254928
257003
|
const t = useT();
|
|
254929
|
-
return (jsxs("div", { className: "mt-4 grid gap-4", children: [jsxs("div", { className: "flex items-center justify-between rounded-lg border p-4", children: [jsxs("div", { className: "space-y-1", children: [jsx(Label$1, { htmlFor: "skill-private", className: "text-sm font-medium text-[#646464]", children: t('clawSandboxAgentSkills.privateToAgent') }), jsx("p", { className: "text-xs text-gray-500", children: t(
|
|
257004
|
+
return (jsxs("div", { className: "mt-4 grid gap-4", children: [jsxs("div", { className: "flex items-center justify-between rounded-lg border p-4", children: [jsxs("div", { className: "space-y-1", children: [jsx(Label$1, { htmlFor: "skill-private", className: "text-sm font-medium text-[#646464]", children: t('clawSandboxAgentSkills.privateToAgent') }), jsx("p", { className: "text-xs text-gray-500", children: t(privateLocked
|
|
257005
|
+
? 'clawSandboxAgentSkills.privateToOtherAgentHint'
|
|
257006
|
+
: 'clawSandboxAgentSkills.privateToAgentHint') })] }), jsx(Switch, { id: "skill-private", checked: form.privateToAgent, onCheckedChange: (checked) => onChange({ ...form, privateToAgent: checked }), disabled: privateLocked, className: "cursor-pointer data-[state=checked]:bg-blue-500" })] }), jsxs("div", { className: "space-y-2", children: [jsx(Label$1, { htmlFor: "skill-name", className: "text-sm font-medium text-[#646464]", children: t('clawSandboxAgentSkills.fieldName') }), jsx(Input, { id: "skill-name", name: "skill-name", value: form.name, onChange: (e) => onChange({ ...form, name: e.target.value }), placeholder: t('clawSandboxAgentSkills.fieldNamePlaceholder'), className: "py-6" })] }), jsxs("div", { className: "space-y-2", children: [jsx(Label$1, { htmlFor: "skill-slug", className: "text-sm font-medium text-[#646464]", children: t('clawSandboxAgentSkills.fieldSlug') }), jsx(Input, { id: "skill-slug", name: "skill-slug", value: form.slug, onChange: (e) => onChange({ ...form, slug: e.target.value }), placeholder: t('clawSandboxAgentSkills.fieldSlugPlaceholder'), className: "py-6" })] }), jsxs("div", { className: "space-y-2", children: [jsx(Label$1, { htmlFor: "skill-version", className: "text-sm font-medium text-[#646464]", children: t('clawSandboxAgentSkills.fieldVersion') }), jsx(Input, { id: "skill-version", name: "skill-version", value: form.version, onChange: (e) => onChange({ ...form, version: e.target.value }), placeholder: t('clawSandboxAgentSkills.fieldVersionPlaceholder'), className: "py-6" })] }), jsxs("div", { className: "space-y-2", children: [jsx(Label$1, { htmlFor: "skill-category", className: "text-sm font-medium text-[#646464]", children: t('clawSandboxAgentSkills.fieldCategory') }), jsx(Input, { id: "skill-category", name: "skill-category", value: form.category, onChange: (e) => onChange({ ...form, category: e.target.value }), placeholder: t('clawSandboxAgentSkills.fieldCategoryPlaceholder'), className: "py-6" })] }), jsxs("div", { className: "space-y-2", children: [jsx(Label$1, { htmlFor: "skill-description", className: "text-sm font-medium text-[#646464]", children: t('clawSandboxAgentSkills.fieldDescription') }), jsx(Textarea, { id: "skill-description", name: "skill-description", value: form.description, onChange: (e) => onChange({ ...form, description: e.target.value }), placeholder: t('clawSandboxAgentSkills.fieldDescriptionPlaceholder'), rows: 3 })] }), jsxs("div", { className: "space-y-2 overflow-hidden", children: [jsx(Label$1, { htmlFor: "skill-instruction", className: "text-sm font-medium text-[#646464]", children: t('clawSandboxAgentSkills.fieldInstruction') }), jsx("p", { className: "text-xs text-gray-500", children: t('clawSandboxAgentSkills.instructionHint') }), jsx(RichTextEditor, { value: form.instruction, onChange: (value) => onChange({ ...form, instruction: value }) })] })] }));
|
|
254930
257007
|
}
|
|
254931
257008
|
|
|
254932
257009
|
/** Distance (px) from the list bottom at which the next page is requested. */
|
|
@@ -255197,46 +257274,6 @@ function ProjectMentorsList({ projectMentors, onMentorRemoved, onAddMentorClick,
|
|
|
255197
257274
|
}) }), showMinimumMentorAlert && (jsx(Suspense, { fallback: null, children: jsx(MinimumMentorAlert$1, { open: showMinimumMentorAlert, onOpenChange: setShowMinimumMentorAlert }) }))] }));
|
|
255198
257275
|
}
|
|
255199
257276
|
|
|
255200
|
-
const AgentSettingsContext = React__default.createContext(null);
|
|
255201
|
-
function AgentSettingsProvider({ children, ...value }) {
|
|
255202
|
-
const ctx = React__default.useMemo(() => value,
|
|
255203
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
255204
|
-
[
|
|
255205
|
-
value.tenantKey,
|
|
255206
|
-
value.mentorId,
|
|
255207
|
-
value.username,
|
|
255208
|
-
value.enableRBAC,
|
|
255209
|
-
value.rbacPermissions,
|
|
255210
|
-
value.executeGatedAction,
|
|
255211
|
-
value.visibilityOptions,
|
|
255212
|
-
]);
|
|
255213
|
-
return jsx(AgentSettingsContext.Provider, { value: ctx, children: children });
|
|
255214
|
-
}
|
|
255215
|
-
/**
|
|
255216
|
-
* Read the shared agent identity / config from the nearest
|
|
255217
|
-
* `<AgentSettingsProvider>` if one is present, returning `null` otherwise.
|
|
255218
|
-
*
|
|
255219
|
-
* Use this when a tab can also be driven by direct props (i.e. the
|
|
255220
|
-
* `<AgentSettingsProvider>` wrapper is optional). For tabs that strictly
|
|
255221
|
-
* require the provider, use `useAgentSettings`.
|
|
255222
|
-
*/
|
|
255223
|
-
function useAgentSettingsOptional() {
|
|
255224
|
-
return React__default.useContext(AgentSettingsContext);
|
|
255225
|
-
}
|
|
255226
|
-
/**
|
|
255227
|
-
* Read the shared agent identity / config from the nearest
|
|
255228
|
-
* `<AgentSettingsProvider>`. Throws if called outside a provider — this is
|
|
255229
|
-
* intentional: every tab MUST be wrapped.
|
|
255230
|
-
*/
|
|
255231
|
-
function useAgentSettings() {
|
|
255232
|
-
const ctx = React__default.useContext(AgentSettingsContext);
|
|
255233
|
-
if (!ctx) {
|
|
255234
|
-
throw new Error('useAgentSettings must be used within an <AgentSettingsProvider>. ' +
|
|
255235
|
-
'Wrap your tab components with <AgentSettingsProvider tenantKey=... mentorId=... username=... enableRBAC=...>.');
|
|
255236
|
-
}
|
|
255237
|
-
return ctx;
|
|
255238
|
-
}
|
|
255239
|
-
|
|
255240
257277
|
function useDatasetsWithPagination(itemsPerPage = 5, opts = {}) {
|
|
255241
257278
|
const { page: controlledPage, search: controlledSearch, onPageChange, onSearchChange } = opts;
|
|
255242
257279
|
// Controlled/uncontrolled is decided per axis, independently.
|
|
@@ -257775,9 +259812,6 @@ var addMentorToProjectModal = /*#__PURE__*/Object.freeze({
|
|
|
257775
259812
|
AddMentorToProjectModal: AddMentorToProjectModal
|
|
257776
259813
|
});
|
|
257777
259814
|
|
|
257778
|
-
const CustomSwitch = React.forwardRef(({ className, checked, onCheckedChange, ...props }, ref) => (jsx(Root$c, { checked: checked, onCheckedChange: onCheckedChange, className: cn('peer focus-visible:ring-ring focus-visible:ring-offset-background inline-flex h-6 w-11 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent transition-colors focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-none disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-blue-500 data-[state=unchecked]:bg-gray-200', className), ...props, ref: ref, children: jsx(Thumb, { className: cn('pointer-events-none block h-5 w-5 rounded-full bg-white shadow-lg ring-0 transition-transform data-[state=checked]:translate-x-5 data-[state=unchecked]:translate-x-0') }) })));
|
|
257779
|
-
CustomSwitch.displayName = Root$c.displayName;
|
|
257780
|
-
|
|
257781
259815
|
const DeleteDatasetModal$1 = dynamic(() => Promise.resolve().then(function () { return deleteDatasetModal; }).then((mod) => ({
|
|
257782
259816
|
default: mod.DeleteDatasetModal,
|
|
257783
259817
|
})));
|
|
@@ -257902,36 +259936,6 @@ function DatasetItemList({ datasets, onSelect, selectedDatasetId, labels }) {
|
|
|
257902
259936
|
return (jsx(TableBody, { children: (datasets === null || datasets === void 0 ? void 0 : datasets.length) > 0 ? (datasets === null || datasets === void 0 ? void 0 : datasets.map((dataset) => (jsx(DatasetItem, { dataset: dataset, onSelect: onSelect, isSelected: selectedDatasetId === dataset.id, labels: labels }, dataset.id)))) : (jsx(TableRow$1, { children: jsx(TableCell$1, { colSpan: 6, className: "p-4 text-center text-[#646464]", children: (_b = (_a = labels === null || labels === void 0 ? void 0 : labels.table) === null || _a === void 0 ? void 0 : _a.emptyState) !== null && _b !== void 0 ? _b : 'No items found' }) })) }));
|
|
257903
259937
|
}
|
|
257904
259938
|
|
|
257905
|
-
/**
|
|
257906
|
-
* Shared utilities for tab label systems.
|
|
257907
|
-
*
|
|
257908
|
-
* Every tab exports a `resolve*Labels(override?)` function that deep-merges
|
|
257909
|
-
* a partial override into the default AGENT labels. This file provides the
|
|
257910
|
-
* DeepPartial type and deepMerge implementation they all share.
|
|
257911
|
-
*/
|
|
257912
|
-
function deepMerge(base, override) {
|
|
257913
|
-
const result = { ...base };
|
|
257914
|
-
const overrideBag = override;
|
|
257915
|
-
for (const key of Object.keys(overrideBag)) {
|
|
257916
|
-
const overrideValue = overrideBag[key];
|
|
257917
|
-
if (overrideValue === undefined)
|
|
257918
|
-
continue;
|
|
257919
|
-
const baseValue = base[key];
|
|
257920
|
-
if (baseValue &&
|
|
257921
|
-
typeof baseValue === 'object' &&
|
|
257922
|
-
!Array.isArray(baseValue) &&
|
|
257923
|
-
overrideValue &&
|
|
257924
|
-
typeof overrideValue === 'object' &&
|
|
257925
|
-
!Array.isArray(overrideValue)) {
|
|
257926
|
-
result[key] = deepMerge(baseValue, overrideValue);
|
|
257927
|
-
}
|
|
257928
|
-
else {
|
|
257929
|
-
result[key] = overrideValue;
|
|
257930
|
-
}
|
|
257931
|
-
}
|
|
257932
|
-
return result;
|
|
257933
|
-
}
|
|
257934
|
-
|
|
257935
259939
|
const AGENT_DATASETS_TAB_LABELS = {
|
|
257936
259940
|
header: {
|
|
257937
259941
|
title: 'Datasets',
|
|
@@ -258224,10 +260228,21 @@ const resourceTypes = [
|
|
|
258224
260228
|
},
|
|
258225
260229
|
];
|
|
258226
260230
|
|
|
260231
|
+
/**
|
|
260232
|
+
* Spend-cap blocks (HTTP 429) carry the machine code in `error`/`error_code`
|
|
260233
|
+
* and a friendly, learner-safe sentence in `message`. Detection keys on
|
|
260234
|
+
* `error_code` — never on the HTTP status, which can also mean a provider
|
|
260235
|
+
* rate limit.
|
|
260236
|
+
*/
|
|
260237
|
+
const SPEND_CAP_EXCEEDED_ERROR_CODE = 'spend_cap_exceeded';
|
|
258227
260238
|
const extractErrorMessage$1 = (error, fallback) => {
|
|
258228
|
-
var _a, _b;
|
|
260239
|
+
var _a, _b, _c;
|
|
258229
260240
|
const apiError = error;
|
|
258230
|
-
|
|
260241
|
+
if (((_a = apiError === null || apiError === void 0 ? void 0 : apiError.data) === null || _a === void 0 ? void 0 : _a.error_code) === SPEND_CAP_EXCEEDED_ERROR_CODE) {
|
|
260242
|
+
// Surface the friendly message, never the raw `spend_cap_exceeded` code.
|
|
260243
|
+
return apiError.data.message || fallback;
|
|
260244
|
+
}
|
|
260245
|
+
return ((_b = apiError === null || apiError === void 0 ? void 0 : apiError.data) === null || _b === void 0 ? void 0 : _b.error) || ((_c = apiError === null || apiError === void 0 ? void 0 : apiError.error) === null || _c === void 0 ? void 0 : _c.error) || fallback;
|
|
258231
260246
|
};
|
|
258232
260247
|
|
|
258233
260248
|
function useGithubRepoDetails(url, tenantKey) {
|
|
@@ -260008,10 +262023,10 @@ function Account({ tenant, tenants = [], username, onInviteClick, email, mainPla
|
|
|
260008
262023
|
onTabChange === null || onTabChange === void 0 ? void 0 : onTabChange('billing');
|
|
260009
262024
|
}, className: `flex items-center gap-2 px-3 py-2 rounded-lg whitespace-nowrap text-sm transition-all ${activeTab === 'billing'
|
|
260010
262025
|
? 'bg-blue-50 text-blue-600 font-medium'
|
|
260011
|
-
: 'text-gray-600 hover:bg-gray-50'}`, children: [jsx(CreditCard, { className: "h-4 w-4" }), jsx("span", { className: "hidden sm:inline", children: t('profileAccount.tabBilling') }), jsx("span", { className: "sm:hidden", children: t('profileAccount.tabBilling') })] }, 'billing'))] }) }) }), jsxs("div", { className: "flex-1 flex flex-col overflow-hidden", style: { height: '100%' }, children: [jsxs("div", { className: "hidden lg:block flex-shrink-0 p-6 border-b border-gray-200 bg-white dark:bg-gray-900", children: [jsx("h3", { className: "text-lg font-medium text-gray-900 dark:text-gray-100 mb-2", children: (_b = (_a = TABS.find((t) => t.id === activeTab)) === null || _a === void 0 ? void 0 : _a.label) !== null && _b !== void 0 ? _b : activeTab }), jsxs("p", { className: "text-gray-600 dark:text-gray-400 text-sm", children: [activeTab === 'management' && t('profileAccount.descManagement'), activeTab === 'organization' && t('profileAccount.descOrganization'), activeTab === 'integrations' && t('profileAccount.descIntegrations'), activeTab === 'billing' && t('profileAccount.descBilling'), activeTab === 'monetization' && t('profileAccount.descMonetization'), activeTab === 'datasets' && t('profileAccount.descBenchmarks'), activeTab === 'advanced' && t('profileAccount.descAdvanced')] })] }), jsxs("div", { className: "flex-1 p-6 space-y-6", style: {
|
|
262026
|
+
: 'text-gray-600 hover:bg-gray-50'}`, children: [jsx(CreditCard, { className: "h-4 w-4" }), jsx("span", { className: "hidden sm:inline", children: t('profileAccount.tabBilling') }), jsx("span", { className: "sm:hidden", children: t('profileAccount.tabBilling') })] }, 'billing'))] }) }) }), jsxs("div", { className: "flex-1 flex flex-col overflow-hidden", style: { height: '100%' }, children: [jsxs("div", { className: "hidden lg:block flex-shrink-0 p-6 border-b border-gray-200 bg-white dark:bg-gray-900", children: [jsx("h3", { className: "text-lg font-medium text-gray-900 dark:text-gray-100 mb-2", children: (_b = (_a = TABS.find((t) => t.id === activeTab)) === null || _a === void 0 ? void 0 : _a.label) !== null && _b !== void 0 ? _b : (activeTab === 'billing' ? t('profileAccount.tabBilling') : activeTab) }), jsxs("p", { className: "text-gray-600 dark:text-gray-400 text-sm", children: [activeTab === 'management' && t('profileAccount.descManagement'), activeTab === 'organization' && t('profileAccount.descOrganization'), activeTab === 'integrations' && t('profileAccount.descIntegrations'), activeTab === 'billing' && t('profileAccount.descBilling'), activeTab === 'monetization' && t('profileAccount.descMonetization'), activeTab === 'datasets' && t('profileAccount.descBenchmarks'), activeTab === 'advanced' && t('profileAccount.descAdvanced')] })] }), jsxs("div", { className: "flex-1 p-6 space-y-6", style: {
|
|
260012
262027
|
overflowY: 'auto',
|
|
260013
262028
|
overflowX: 'hidden',
|
|
260014
|
-
}, children: [jsxs("div", { className: "lg:hidden mb-6", children: [jsx("h3", { className: "text-lg font-medium text-gray-900 dark:text-gray-100 mb-2", children: (_d = (_c = TABS.find((t) => t.id === activeTab)) === null || _c === void 0 ? void 0 : _c.label) !== null && _d !== void 0 ? _d : activeTab }), jsxs("p", { className: "text-gray-600 dark:text-gray-400 text-sm", children: [activeTab === 'basic' && t('profileAccount.descBasic'), activeTab === 'social' && t('profileAccount.descSocial'), activeTab === 'security' && t('profileAccount.descSecurity'), activeTab === 'management' && t('profileAccount.descManagement'), activeTab === 'organization' && t('profileAccount.descOrganization'), activeTab === 'monetization' && t('profileAccount.descMonetization'), activeTab === 'datasets' && t('profileAccount.descBenchmarks'), activeTab === 'advanced' && t('profileAccount.descAdvanced')] })] }), activeTab === 'management' && hasManagementPermissions && (jsx(Admin, { authSpaUrl: authURL, onInviteClick: onInviteClick, tenant: tenant, currentSpa: currentSPA, hasUserTabPermission: hasUserTabPermission, hasGroupsTabPermission: hasGroupsTabPermission, hasPoliciesTabPermission: hasPoliciesTabPermission, hasRolesTabPermission: hasRolesTabPermission, hasTeamsTabPermission: hasTeamsTabPermission, hasInviteUserPermission: hasInviteUserPermission, hasCreateTeamPermission: hasCreateTeamPermission, onLoadGroupPermissions: onLoadGroupPermissions, hasAlertsTabPermission: hasAlertsTabPermission, rbacPermissions: rbacPermissions, enableRbac: enableRbac, showGradebookTab: showGradebookTab })), activeTab === 'organization' && (jsx(OrganizationTab, { platformKey: tenant, tenant: tenants.find((ten) => ten.key === tenant), onTenantUpdate: onTenantUpdate, setOrganizationLogoFromOutside: setOrganizationLogo, defaultSupportPhone: defaultSupportPhone, enableSupportPhone: enableSupportPhone })), activeTab === 'integrations' && (jsx(IntegrationsTab, { tenantKey: tenant, username: username })), activeTab === 'billing' && (jsx(BillingTab, { tenant: tenant, userActiveApp: userActiveApp, username: username, currentUserEmail: email, mainPlatformKey: mainPlatformKey })), activeTab === 'monetization' && (jsx(MonetizationTab, { platformKey: tenant, authURL: authURL })), activeTab === 'datasets' && showBenchmarks && (jsx(BenchmarksTab, { tenantKey: tenant, username: username })), activeTab === 'advanced' && (jsx(AdvancedTab, { platformKey: tenant, currentSPA: currentSPA, username: username, authURL: authURL, currentPlatformBaseDomain: currentPlatformBaseDomain }))] })] }), jsx(ToastProvider, {})] }));
|
|
262029
|
+
}, children: [jsxs("div", { className: "lg:hidden mb-6", children: [jsx("h3", { className: "text-lg font-medium text-gray-900 dark:text-gray-100 mb-2", children: (_d = (_c = TABS.find((t) => t.id === activeTab)) === null || _c === void 0 ? void 0 : _c.label) !== null && _d !== void 0 ? _d : (activeTab === 'billing' ? t('profileAccount.tabBilling') : activeTab) }), jsxs("p", { className: "text-gray-600 dark:text-gray-400 text-sm", children: [activeTab === 'billing' && t('profileAccount.descBilling'), activeTab === 'basic' && t('profileAccount.descBasic'), activeTab === 'social' && t('profileAccount.descSocial'), activeTab === 'security' && t('profileAccount.descSecurity'), activeTab === 'management' && t('profileAccount.descManagement'), activeTab === 'organization' && t('profileAccount.descOrganization'), activeTab === 'monetization' && t('profileAccount.descMonetization'), activeTab === 'datasets' && t('profileAccount.descBenchmarks'), activeTab === 'advanced' && t('profileAccount.descAdvanced')] })] }), activeTab === 'management' && hasManagementPermissions && (jsx(Admin, { authSpaUrl: authURL, onInviteClick: onInviteClick, tenant: tenant, currentSpa: currentSPA, hasUserTabPermission: hasUserTabPermission, hasGroupsTabPermission: hasGroupsTabPermission, hasPoliciesTabPermission: hasPoliciesTabPermission, hasRolesTabPermission: hasRolesTabPermission, hasTeamsTabPermission: hasTeamsTabPermission, hasInviteUserPermission: hasInviteUserPermission, hasCreateTeamPermission: hasCreateTeamPermission, onLoadGroupPermissions: onLoadGroupPermissions, hasAlertsTabPermission: hasAlertsTabPermission, rbacPermissions: rbacPermissions, enableRbac: enableRbac, showGradebookTab: showGradebookTab })), activeTab === 'organization' && (jsx(OrganizationTab, { platformKey: tenant, tenant: tenants.find((ten) => ten.key === tenant), onTenantUpdate: onTenantUpdate, setOrganizationLogoFromOutside: setOrganizationLogo, defaultSupportPhone: defaultSupportPhone, enableSupportPhone: enableSupportPhone })), activeTab === 'integrations' && (jsx(IntegrationsTab, { tenantKey: tenant, username: username })), activeTab === 'billing' && (jsx(BillingTab, { tenant: tenant, userActiveApp: userActiveApp, username: username, currentUserEmail: email, mainPlatformKey: mainPlatformKey })), activeTab === 'monetization' && (jsx(MonetizationTab, { platformKey: tenant, authURL: authURL })), activeTab === 'datasets' && showBenchmarks && (jsx(BenchmarksTab, { tenantKey: tenant, username: username })), activeTab === 'advanced' && (jsx(AdvancedTab, { platformKey: tenant, currentSPA: currentSPA, username: username, authURL: authURL, currentPlatformBaseDomain: currentPlatformBaseDomain }))] })] }), jsx(ToastProvider, {})] }));
|
|
260015
262030
|
}
|
|
260016
262031
|
|
|
260017
262032
|
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, }) {
|
|
@@ -268569,20 +270584,6 @@ function AgentSafetyTab({ renderPromptContent, FlaggedPromptsModal, showFlaggedP
|
|
|
268569
270584
|
selectedPrompt: selectedPrompt, isEditing: isEditMentorLoading })), isFlaggedPromptsModalOpen && FlaggedPromptsModal && (jsx(FlaggedPromptsModal, { isOpen: isFlaggedPromptsModalOpen, onClose: () => setIsFlaggedPromptsModalOpen(false), mentorId: mentorId, tenantKey: tenantKey, username: username !== null && username !== void 0 ? username : '' }))] }) })] }));
|
|
268570
270585
|
}
|
|
268571
270586
|
|
|
268572
|
-
/**
|
|
268573
|
-
* Reusable header used at the top of every capability-gated agent-settings
|
|
268574
|
-
* tab. It surfaces the capability's on/off toggle (previously buried in the
|
|
268575
|
-
* Settings → Capabilities list) right where the feature is configured, with a
|
|
268576
|
-
* naive-friendly explanation.
|
|
268577
|
-
*
|
|
268578
|
-
* The configuration UI below is always rendered so admins can preview what
|
|
268579
|
-
* they'll get, but it's grayed out and made inert (`pointer-events-none`,
|
|
268580
|
-
* `aria-hidden`) until the capability is switched on.
|
|
268581
|
-
*/
|
|
268582
|
-
function CapabilityGate({ title, description, enabled, onToggle, disabled = false, ariaLabel, offHint, toggleTestId, children, }) {
|
|
268583
|
-
return (jsxs("div", { className: "space-y-4", children: [jsxs("div", { className: "flex items-start justify-between gap-4 rounded-lg border border-gray-200 bg-gray-50/60 p-4", "data-testid": "capability-gate-header", children: [jsx("div", { className: "min-w-0", children: jsxs("p", { className: "text-xs leading-relaxed text-gray-600", children: [description, !enabled && offHint && (jsxs("span", { className: "font-medium text-gray-500", "data-testid": "capability-gate-off-hint", children: [' ', offHint] }))] }) }), jsx(CustomSwitch, { checked: enabled, onCheckedChange: onToggle, disabled: disabled, "aria-label": ariaLabel !== null && ariaLabel !== void 0 ? ariaLabel : title, "aria-checked": enabled, "data-testid": toggleTestId, className: "mt-0.5 flex-shrink-0" })] }), jsx("div", { className: cn('transition-opacity', !enabled && 'pointer-events-none select-none opacity-50'), "aria-hidden": !enabled, inert: !enabled, "data-testid": "capability-gate-content", "data-enabled": enabled, children: children })] }));
|
|
268584
|
-
}
|
|
268585
|
-
|
|
268586
270587
|
const AGENT_PRIVACY_TAB_LABELS = {
|
|
268587
270588
|
header: {
|
|
268588
270589
|
title: 'Privacy',
|
|
@@ -270825,6 +272826,46 @@ function AgentGraderTab({ labels: labelsOverride, tenantKey: tenantKeyProp, ment
|
|
|
270825
272826
|
return (jsxs(Fragment$1, { children: [jsx("div", { className: "flex h-[73px] flex-shrink-0 items-center border-b border-gray-200 bg-white p-4 lg:block", children: jsxs("div", { children: [jsx("h3", { className: "mb-1 text-base font-medium text-gray-900", children: labels.header.title }), jsx("p", { className: "text-xs text-gray-600", children: labels.header.description })] }) }), jsx("div", { className: "flex-1 space-y-4 p-3 lg:p-4", style: { overflowY: 'auto', overflowX: 'hidden' }, "data-testid": "grader-tab-body", children: isLoading ? (jsx("div", { className: "flex items-center justify-center py-12", "data-testid": "grader-tab-loading", children: jsx(Spinner, {}) })) : isForbidden || nothingViewable ? (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": "grader-tab-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(CapabilityGate, { title: labels.capability.title, description: labels.capability.description, offHint: labels.capability.offHint, enabled: enabled, onToggle: toggleGrading, disabled: isToggling, ariaLabel: labels.capability.title, toggleTestId: "grader-capability-toggle", children: [warningMessage && (jsxs("div", { className: "mb-4 flex items-start gap-2 rounded-lg border border-amber-200 bg-amber-50 p-3", "data-testid": "grader-misconfigured-warning", children: [jsx(TriangleAlert, { className: "mt-0.5 h-4 w-4 flex-shrink-0 text-amber-600" }), jsx("p", { className: "text-xs leading-relaxed text-amber-800", children: warningMessage })] })), jsxs(Tabs, { defaultValue: defaultSubTab, className: "w-full", children: [jsxs(TabsList, { "aria-label": labels.header.title, "data-testid": "grader-sub-tabs", children: [canReadConfig && (jsx(TabsTrigger, { value: GRADER_SUB_TABS.setup, "data-testid": "grader-sub-tab-setup", children: labels.subTabs.setup })), canViewCriteria && (jsx(TabsTrigger, { value: GRADER_SUB_TABS.rubric, "data-testid": "grader-sub-tab-rubric", children: labels.subTabs.rubric })), canViewResults && (jsx(TabsTrigger, { value: GRADER_SUB_TABS.results, "data-testid": "grader-sub-tab-results", children: labels.subTabs.results }))] }), jsx(TabsContent, { value: GRADER_SUB_TABS.setup, className: "space-y-4", children: jsx(SetupSection, { labels: labels.config, config: config, isSaving: isSavingConfig, canSave: canSaveConfig, onSave: saveConfig }) }), jsx(TabsContent, { value: GRADER_SUB_TABS.rubric, className: "space-y-4", children: jsx(RubricSection, { labels: labels.criteria, criteria: criteria, hasConfig: hasConfig, isLoading: isCriteriaLoading, isMutating: isMutatingCriteria, totalPoints: totalPoints, canAdd: canAddCriterion, canEdit: canEditCriterion, canDelete: canDeleteCriterion, onAdd: addCriterion, onEdit: editCriterion, onDelete: removeCriterion }) }), jsx(TabsContent, { value: GRADER_SUB_TABS.results, className: "space-y-4", children: jsx(ResultsSection, { labels: labels.results, tenantKey: tenantKey, mentorId: mentorId, username: username, canOverride: canOverrideResults }) })] })] })) })] }));
|
|
270826
272827
|
}
|
|
270827
272828
|
|
|
272829
|
+
/**
|
|
272830
|
+
* Learner-safe spend-cap usage indicator. The status endpoint intentionally
|
|
272831
|
+
* returns only zones and fill percentages — never dollar amounts — so this
|
|
272832
|
+
* renders progress toward each cap, a warning banner near the limit, and a
|
|
272833
|
+
* blocked banner once a hard-block cap is exceeded. Admin dollar figures live
|
|
272834
|
+
* in the `AgentSpendCapsTab` settings tab instead.
|
|
272835
|
+
*/
|
|
272836
|
+
function SpendCapUsage({ tenantKey, userId, mentorId, showWhenOk = false, className, }) {
|
|
272837
|
+
const t = useT();
|
|
272838
|
+
const { data, isLoading, error } = useGetSpendCapStatusQuery({ org: tenantKey, userId, mentor: mentorId }, { skip: !tenantKey || !userId });
|
|
272839
|
+
if (isLoading || error || !data)
|
|
272840
|
+
return null;
|
|
272841
|
+
const summary = data;
|
|
272842
|
+
if (summary.caps.length === 0)
|
|
272843
|
+
return null;
|
|
272844
|
+
if (summary.status === 'ok' && !showWhenOk)
|
|
272845
|
+
return null;
|
|
272846
|
+
const scopeLabels = {
|
|
272847
|
+
tenant: t('spendCapUsage.scopeTenant'),
|
|
272848
|
+
agent: t('spendCapUsage.scopeAgent'),
|
|
272849
|
+
user_agent: t('spendCapUsage.scopeUserAgent'),
|
|
272850
|
+
};
|
|
272851
|
+
const intervalLabels = {
|
|
272852
|
+
day: t('spendCapUsage.intervalDay'),
|
|
272853
|
+
week: t('spendCapUsage.intervalWeek'),
|
|
272854
|
+
month: t('spendCapUsage.intervalMonth'),
|
|
272855
|
+
year: t('spendCapUsage.intervalYear'),
|
|
272856
|
+
};
|
|
272857
|
+
return (jsxs("div", { className: cn('space-y-3 rounded-lg border border-gray-200 bg-white p-3', className), "data-testid": "spend-cap-usage", children: [summary.blocked ? (jsxs("div", { className: "flex items-start gap-2 rounded-lg border border-red-200 bg-red-50 p-3", "data-testid": "spend-cap-usage-blocked", children: [jsx(OctagonX, { className: "mt-0.5 h-4 w-4 flex-shrink-0 text-red-600" }), jsx("p", { className: "text-xs leading-relaxed text-red-800", children: t('spendCapUsage.blockedBanner') })] })) : summary.status !== 'ok' ? (jsxs("div", { className: "flex items-start gap-2 rounded-lg border border-amber-200 bg-amber-50 p-3", "data-testid": "spend-cap-usage-warning", children: [jsx(TriangleAlert, { className: "mt-0.5 h-4 w-4 flex-shrink-0 text-amber-600" }), jsx("p", { className: "text-xs leading-relaxed text-amber-800", children: t('spendCapUsage.warningBanner') })] })) : null, jsx("ul", { className: "space-y-2", children: summary.caps.map((cap, index) => {
|
|
272858
|
+
var _a, _b;
|
|
272859
|
+
const percent = Math.min(100, Math.max(0, Math.round(cap.percent_used)));
|
|
272860
|
+
const barColor = cap.status === 'exceeded'
|
|
272861
|
+
? 'bg-red-500'
|
|
272862
|
+
: cap.status === 'warning'
|
|
272863
|
+
? 'bg-amber-500'
|
|
272864
|
+
: 'bg-blue-500';
|
|
272865
|
+
return (jsxs("li", { className: "space-y-1", "data-testid": `spend-cap-usage-item-${cap.scope}`, children: [jsxs("div", { className: "flex items-center justify-between text-xs text-gray-600", children: [jsxs("span", { children: [scopeLabels[cap.scope], " \u00B7 ", intervalLabels[cap.interval_type]] }), jsx("span", { "data-testid": `spend-cap-usage-percent-${cap.scope}`, children: t('spendCapUsage.percentUsed', { percent }) })] }), jsx("div", { className: "h-1.5 w-full overflow-hidden rounded-full bg-gray-200", role: "progressbar", "aria-valuenow": percent, "aria-valuemin": 0, "aria-valuemax": 100, "aria-label": `${scopeLabels[cap.scope]} · ${intervalLabels[cap.interval_type]}`, children: jsx("div", { className: cn('h-full rounded-full transition-all', barColor), style: { width: `${percent}%` } }) })] }, `${cap.scope}-${(_a = cap.mentor_unique_id) !== null && _a !== void 0 ? _a : ''}-${(_b = cap.username) !== null && _b !== void 0 ? _b : ''}-${index}`));
|
|
272866
|
+
}) })] }));
|
|
272867
|
+
}
|
|
272868
|
+
|
|
270828
272869
|
function ApiKeyModal({ isOpen, onClose, apiKey, labels }) {
|
|
270829
272870
|
const { copy, status } = useCopyToClipboard(800);
|
|
270830
272871
|
const Icon = status === 'success' ? Check : Copy;
|
|
@@ -280455,6 +282496,27 @@ function Chat({ mode = 'default', isPreviewMode = false, hasBorder = true, isInC
|
|
|
280455
282496
|
closeButton: true,
|
|
280456
282497
|
});
|
|
280457
282498
|
}, []);
|
|
282499
|
+
// Spend-cap block (429, error_code "spend_cap_exceeded") — deliberately
|
|
282500
|
+
// separate from the 402 credits flow. Learner-safe: names only the interval,
|
|
282501
|
+
// never dollar amounts.
|
|
282502
|
+
const handleSpendCapError = useCallback((data) => {
|
|
282503
|
+
var _a;
|
|
282504
|
+
const interval = (_a = data === null || data === void 0 ? void 0 : data.details) === null || _a === void 0 ? void 0 : _a.interval_type;
|
|
282505
|
+
const message = interval === 'day'
|
|
282506
|
+
? t('chatIndex.spendCapLimitDay')
|
|
282507
|
+
: interval === 'week'
|
|
282508
|
+
? t('chatIndex.spendCapLimitWeek')
|
|
282509
|
+
: interval === 'month'
|
|
282510
|
+
? t('chatIndex.spendCapLimitMonth')
|
|
282511
|
+
: interval === 'year'
|
|
282512
|
+
? t('chatIndex.spendCapLimitYear')
|
|
282513
|
+
: t('chatIndex.spendCapLimitGeneric');
|
|
282514
|
+
toast.error(message, {
|
|
282515
|
+
description: t('chatIndex.spendCapContactAdmin'),
|
|
282516
|
+
closeButton: true,
|
|
282517
|
+
duration: TOAST_DURATION,
|
|
282518
|
+
});
|
|
282519
|
+
}, [t, TOAST_DURATION]);
|
|
280458
282520
|
const { showDisclaimerModal, isAgreeing, userAgreement, hasUserAgreement, handleDisclaimerAgree, checkAgreementAndExecute, executePendingSubmit, } = useUserAgreement({ mentorId, tenantKey });
|
|
280459
282521
|
const { changeTab, activeTab, currentStreamingMessage, enabledGuidedPrompts, isStreaming, mentorName, messages, profileImage, sendMessage, setMessage, stopGenerating, uniqueMentorId, sessionId, startNewChat, enableSafetyDisclaimer, isPending, isLoadingChats, isConnected, refetchChats, } = useAdvancedChat({
|
|
280460
282522
|
mentorId,
|
|
@@ -280495,6 +282557,7 @@ function Chat({ mode = 'default', isPreviewMode = false, hasBorder = true, isInC
|
|
|
280495
282557
|
!(searchParams === null || searchParams === void 0 ? void 0 : searchParams.get('token'))),
|
|
280496
282558
|
mentorShareableToken: searchParams === null || searchParams === void 0 ? void 0 : searchParams.get('token'),
|
|
280497
282559
|
on402Error: handle402Error,
|
|
282560
|
+
onSpendCapError: handleSpendCapError,
|
|
280498
282561
|
cachedSessionId,
|
|
280499
282562
|
onStartNewChat: (sessionId) => {
|
|
280500
282563
|
dispatch(chatActions.updateSessionIds(sessionId));
|
|
@@ -332819,5 +334882,5 @@ var index_es = /*#__PURE__*/Object.freeze({
|
|
|
332819
334882
|
vectorsRatio: vectorsRatio
|
|
332820
334883
|
});
|
|
332821
334884
|
|
|
332822
|
-
export { AGENT_ACCESS_TAB_LABELS, AGENT_ANALYTICS_TAB_LABELS, AGENT_API_TAB_LABELS, AGENT_DATASETS_TAB_LABELS, AGENT_DISCLAIMERS_TAB_LABELS, AGENT_EMBED_TAB_LABELS, AGENT_EVALUATION_TAB_LABELS, AGENT_GRADER_TAB_LABELS, AGENT_HISTORY_TAB_LABELS, AGENT_HUMAN_SUPPORT_TAB_LABELS, AGENT_LLM_TAB_LABELS, AGENT_LTI_TAB_LABELS, AGENT_MEMORY_TAB_LABELS, AGENT_PICKER_LABELS, AGENT_PRIVACY_TAB_LABELS, AGENT_PROMPTS_TAB_LABELS, AGENT_SAFETY_TAB_LABELS, AGENT_SCREENSHARE_TAB_LABELS, AGENT_SEARCH_LABELS, AGENT_SETTINGS_TAB_LABELS, AGENT_SKILLS_TAB_LABELS, AGENT_TASKS_TAB_LABELS, AGENT_TOOLS_TAB_LABELS, AGENT_VOICE_TAB_LABELS, Account, AgentAccessTab, AgentAnalyticsTab, AgentApiTab, AgentCard, AgentDatasetsTab, AgentDisclaimersTab, AgentEmbedTab, AgentEmptyState, AgentEvaluationTab, AgentGraderTab, AgentHistoryTab, AgentHumanSupportTab, AgentLLMTab, AgentLtiTab, AgentMemoryTab, AgentPrivacyTab, AgentPromptsTab, AgentSafetyTab, AgentScreenShareTab, AgentSearch, AgentSearchFilters, AgentSearchInput, AgentSettingsProvider, AgentSettingsTab, AgentSkillsTab, AgentTasksTab, AgentToolsTab, AgentVoiceTab, AppSidebar, CATALOGS, Chat, ClientErrorPage, ConversationStarters$1 as ConversationStarters, CopyButton, CopyMentorModal, CourseBox, CourseContentLayout, CourseContentTabPage, CreatePathwayModal, CredentialDetailModal, CredentialMiniBox, DEFAULT_ANALYTICS_HUB_TABS, DEFAULT_LOCALE, DeleteMentorModal, EMPTY_PROGRAM_SETTINGS_FORM, EdxIframe, ErrorPage, GRADING_TOOL_NAME, GreetingMethod, McpTab, MediaBox, MentorSelectionGrid, NavBar, OrganizationTab, PLATFORM_SIDEBAR_FLYOUT_ITEM_COLOR, PLATFORM_SIDEBAR_FLYOUT_TITLE_COLOR, PLATFORM_SIDEBAR_NAV_ACTIVE_BG_OPEN, PLATFORM_SIDEBAR_NAV_MUTED, PathwayDetailModal, PlatformAccountSheet, PlatformSidebar, PlatformSidebarCollapsedLabelFlyout, PlatformSidebarCollapsedNavFlyout, PlatformSidebarFooter, PlatformSidebarNavDivider, PlatformSidebarNavSection, PlatformSidebarSubNavItem, ProfileInfoCards, ProfileTabs, ProgramDetailModal, ProjectsSidebarDropdown, SUPPORTED_LOCALES, SidebarInset, SidebarProvider, SidebarTrigger, SsoLogin, StarButton, UserProfileDropdown, UserProfileModal, WebContainersI18nProvider, formatDateString, getCatalog, getLLMProviderDetails, initializeLocalStorageWithObject, isValidLocale, resolveAgentPickerLabels, resolveAgentSearchLabels, resolveSettingsTabLabels, useAgentSearch, useAgentSearchWithPagination, useAgentSettings, useAgentStar, useGetChatDetails, usePlatformSidebarFooterActions, usePlatformSidebarNavCallback, useSidebar, useT, useTimeTracker, useWebContainersI18n, useWebContainersLocale };
|
|
334885
|
+
export { AGENT_ACCESS_TAB_LABELS, AGENT_ANALYTICS_TAB_LABELS, AGENT_API_TAB_LABELS, AGENT_DATASETS_TAB_LABELS, AGENT_DISCLAIMERS_TAB_LABELS, AGENT_EMBED_TAB_LABELS, AGENT_EVALUATION_TAB_LABELS, AGENT_GRADER_TAB_LABELS, AGENT_HISTORY_TAB_LABELS, AGENT_HUMAN_SUPPORT_TAB_LABELS, AGENT_LLM_TAB_LABELS, AGENT_LTI_TAB_LABELS, AGENT_MEMORY_TAB_LABELS, AGENT_PICKER_LABELS, AGENT_PRIVACY_TAB_LABELS, AGENT_PROMPTS_TAB_LABELS, AGENT_SAFETY_TAB_LABELS, AGENT_SCREENSHARE_TAB_LABELS, AGENT_SEARCH_LABELS, AGENT_SETTINGS_TAB_LABELS, AGENT_SKILLS_TAB_LABELS, AGENT_SPEND_CAPS_TAB_LABELS, AGENT_TASKS_TAB_LABELS, AGENT_TOOLS_TAB_LABELS, AGENT_VOICE_TAB_LABELS, Account, AgentAccessTab, AgentAnalyticsTab, AgentApiTab, AgentCard, AgentDatasetsTab, AgentDisclaimersTab, AgentEmbedTab, AgentEmptyState, AgentEvaluationTab, AgentGraderTab, AgentHistoryTab, AgentHumanSupportTab, AgentLLMTab, AgentLtiTab, AgentMemoryTab, AgentPrivacyTab, AgentPromptsTab, AgentSafetyTab, AgentScreenShareTab, AgentSearch, AgentSearchFilters, AgentSearchInput, AgentSettingsProvider, AgentSettingsTab, AgentSkillsTab, AgentSpendCapsTab, AgentTasksTab, AgentToolsTab, AgentVoiceTab, AppSidebar, CATALOGS, Chat, ClientErrorPage, ConversationStarters$1 as ConversationStarters, CopyButton, CopyMentorModal, CourseBox, CourseContentLayout, CourseContentTabPage, CreatePathwayModal, CredentialDetailModal, CredentialMiniBox, DEFAULT_ANALYTICS_HUB_TABS, DEFAULT_LOCALE, DeleteMentorModal, EMPTY_PROGRAM_SETTINGS_FORM, EdxIframe, ErrorPage, GRADING_TOOL_NAME, GreetingMethod, McpTab, MediaBox, MentorSelectionGrid, NavBar, OrganizationTab, PLATFORM_SIDEBAR_FLYOUT_ITEM_COLOR, PLATFORM_SIDEBAR_FLYOUT_TITLE_COLOR, PLATFORM_SIDEBAR_NAV_ACTIVE_BG_OPEN, PLATFORM_SIDEBAR_NAV_MUTED, PathwayDetailModal, PlatformAccountSheet, PlatformSidebar, PlatformSidebarCollapsedLabelFlyout, PlatformSidebarCollapsedNavFlyout, PlatformSidebarFooter, PlatformSidebarNavDivider, PlatformSidebarNavSection, PlatformSidebarSubNavItem, ProfileInfoCards, ProfileTabs, ProgramDetailModal, ProjectsSidebarDropdown, SPEND_CAPS_SUB_TABS, SUPPORTED_LOCALES, SidebarInset, SidebarProvider, SidebarTrigger, SpendCapUsage, SsoLogin, StarButton, UserProfileDropdown, UserProfileModal, WebContainersI18nProvider, formatDateString, getCatalog, getLLMProviderDetails, initializeLocalStorageWithObject, isValidLocale, resolveAgentPickerLabels, resolveAgentSearchLabels, resolveSettingsTabLabels, useAgentSearch, useAgentSearchWithPagination, useAgentSettings, useAgentStar, useGetChatDetails, usePlatformSidebarFooterActions, usePlatformSidebarNavCallback, useSidebar, useT, useTimeTracker, useWebContainersI18n, useWebContainersLocale };
|
|
332823
334886
|
//# sourceMappingURL=index.esm.js.map
|