@promptbook/cli 0.114.0-14 → 0.114.0-18
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/apps/agents-server/next.config.ts +6 -0
- package/apps/agents-server/src/app/admin/_components/AdminFilterFields.tsx +84 -0
- package/apps/agents-server/src/app/admin/_components/AdminMetricCard.tsx +36 -0
- package/apps/agents-server/src/app/admin/_components/AdminTaskManagerTabs.tsx +97 -0
- package/apps/agents-server/src/app/admin/planned-messages/PlannedMessageManagerClient.tsx +103 -0
- package/apps/agents-server/src/app/admin/planned-messages/PlannedMessageManagerEditDialog.tsx +232 -0
- package/apps/agents-server/src/app/admin/planned-messages/PlannedMessageManagerFiltersCard.tsx +195 -0
- package/apps/agents-server/src/app/admin/planned-messages/PlannedMessageManagerRow.tsx +189 -0
- package/apps/agents-server/src/app/admin/planned-messages/PlannedMessageManagerSummaryMetrics.tsx +60 -0
- package/apps/agents-server/src/app/admin/planned-messages/PlannedMessageManagerTableCard.tsx +147 -0
- package/apps/agents-server/src/app/admin/planned-messages/page.tsx +17 -0
- package/apps/agents-server/src/app/admin/planned-messages/plannedMessageEditForm.ts +186 -0
- package/apps/agents-server/src/app/admin/planned-messages/plannedMessageManagerDialogs.ts +46 -0
- package/apps/agents-server/src/app/admin/planned-messages/plannedMessageManagerPresentation.tsx +188 -0
- package/apps/agents-server/src/app/admin/planned-messages/resolvePlannedMessageSortValue.ts +115 -0
- package/apps/agents-server/src/app/admin/planned-messages/usePlannedMessageManagerData.ts +116 -0
- package/apps/agents-server/src/app/admin/planned-messages/usePlannedMessageManagerState.ts +289 -0
- package/apps/agents-server/src/app/admin/task-manager/TaskManagerClient.tsx +7 -2
- package/apps/agents-server/src/app/admin/task-manager/TaskManagerFiltersCard.tsx +7 -73
- package/apps/agents-server/src/app/admin/task-manager/TaskManagerSummaryMetrics.tsx +5 -30
- package/apps/agents-server/src/app/admin/task-manager/[taskId]/TaskManagerTaskDetailClient.tsx +1 -1
- package/apps/agents-server/src/app/agents/[agentName]/api/book/reference-diagnostics/route.ts +30 -7
- package/apps/agents-server/src/app/agents/[agentName]/api/book/route.ts +1 -0
- package/apps/agents-server/src/app/agents/[agentName]/api/book/test.http +3 -3
- package/apps/agents-server/src/app/agents/[agentName]/book/BookEditorMissingReferences.tsx +106 -12
- package/apps/agents-server/src/app/agents/[agentName]/book/BookEditorWrapper.tsx +3 -0
- package/apps/agents-server/src/app/agents/[agentName]/book/useBookEditorDiagnostics.ts +12 -0
- package/apps/agents-server/src/app/agents/[agentName]/book/useBookEditorWrapper.tsx +2 -0
- package/apps/agents-server/src/app/agents/[agentName]/chat/AgentGoalChatPlannedMessages.tsx +46 -3
- package/apps/agents-server/src/app/api/admin/default-agents/reinstate/route.ts +5 -1
- package/apps/agents-server/src/app/api/admin/planned-messages/[timeoutId]/route.ts +80 -0
- package/apps/agents-server/src/app/api/admin/planned-messages/route.ts +19 -0
- package/apps/agents-server/src/app/api/internal/agent-goal-chat-planned-messages/route.ts +30 -2
- package/apps/agents-server/src/components/DefaultAgents/ReinstateBundledAgentsButton.tsx +7 -0
- package/apps/agents-server/src/components/DefaultAgents/coreAgentsAdminRoute.ts +6 -0
- package/apps/agents-server/src/components/Header/buildHeaderSystemMenuItems.ts +7 -0
- package/apps/agents-server/src/components/Homepage/DefaultAgentsStatusNotice.tsx +1 -7
- package/apps/agents-server/src/database/migrations/2026-08-1800-user-chat-timeout-schedule.sql +11 -0
- package/apps/agents-server/src/instrumentation-node.ts +18 -0
- package/apps/agents-server/src/languages/ServerTranslationKeys.ts +4 -0
- package/apps/agents-server/src/languages/translations/czech.yaml +4 -0
- package/apps/agents-server/src/languages/translations/english.yaml +4 -0
- package/apps/agents-server/src/tools/agentGoalChatTimeoutToolFunctions.ts +62 -15
- package/apps/agents-server/src/tools/agentGoalChatTimeoutTools.ts +63 -9
- package/apps/agents-server/src/utils/adminEntityLookups/loadAgentNamesByPermanentId.ts +45 -0
- package/apps/agents-server/src/utils/adminEntityLookups/loadUsernamesByUserId.ts +36 -0
- package/apps/agents-server/src/utils/adminEntityLookups.ts +2 -0
- package/apps/agents-server/src/utils/agentGoalChat/agentGoalChatPlannedMessageActions.ts +299 -52
- package/apps/agents-server/src/utils/agentGoalChat/createAgentGoalChatNoteContent.ts +45 -17
- package/apps/agents-server/src/utils/agentGoalChat.ts +1 -0
- package/apps/agents-server/src/utils/agentProjects/agentProjectIdentity.ts +46 -0
- package/apps/agents-server/src/utils/agentProjects/agentProjectRuntimeAutostartScheduler.ts +162 -0
- package/apps/agents-server/src/utils/agentProjects/agentProjectRuntimeDesiredState.ts +252 -0
- package/apps/agents-server/src/utils/agentProjects/agentProjectRuntimeDisplay.ts +6 -3
- package/apps/agents-server/src/utils/agentProjects/agentProjectRuntimeDomains.ts +2 -44
- package/apps/agents-server/src/utils/agentProjects/agentProjectRuntimePaths.ts +25 -0
- package/apps/agents-server/src/utils/agentProjects/agentProjectRuntimePm2.ts +4 -3
- package/apps/agents-server/src/utils/agentProjects/agentProjectRuntimeRegistry.ts +77 -24
- package/apps/agents-server/src/utils/agentProjects/agentProjectStateMutationQueue.ts +58 -0
- package/apps/agents-server/src/utils/agentProjects/listAllLocalAgentProjectIdentities.ts +48 -0
- package/apps/agents-server/src/utils/agentProjects/resolveAgentProjectRuntimeEnvironmentFlag.ts +23 -0
- package/apps/agents-server/src/utils/agentProjects/resolveAgentProjectRuntimeStatus.ts +73 -0
- package/apps/agents-server/src/utils/agentProjects/startDefaultAgentProjectRuntimes.ts +110 -0
- package/apps/agents-server/src/utils/agentReferenceResolver/MissingCoreAgentRecovery.ts +19 -0
- package/apps/agents-server/src/utils/agentReferenceResolver/bookScopedAgentReferences.ts +7 -0
- package/apps/agents-server/src/utils/agentReferenceResolver/createAgentInheritanceDiagnostics.ts +457 -0
- package/apps/agents-server/src/utils/agentReferenceResolver/createUnresolvedAgentReferenceDiagnostics.ts +27 -0
- package/apps/agents-server/src/utils/agentReferenceResolver/resolveCoreAgentAwareMissingReferences.ts +156 -0
- package/apps/agents-server/src/utils/chatMessageChips/createAnsweredMessageChipToolCalls.ts +15 -3
- package/apps/agents-server/src/utils/chatMessageChips/createPlannedMessageChipToolCalls.ts +8 -3
- package/apps/agents-server/src/utils/chatMessageChips/createTouchedExternalSourceChipToolCalls.ts +39 -0
- package/apps/agents-server/src/utils/chatMessageChips/createTouchedProjectChipResult.ts +45 -0
- package/apps/agents-server/src/utils/chatMessageChips/createTouchedProjectChipToolCalls.ts +58 -24
- package/apps/agents-server/src/utils/cronExpression/CronExpression.ts +63 -0
- package/apps/agents-server/src/utils/cronExpression/normalizeCronExpression.ts +34 -0
- package/apps/agents-server/src/utils/cronExpression/normalizeCronExpressionWhitespace.ts +11 -0
- package/apps/agents-server/src/utils/cronExpression/parseCronExpression.ts +41 -0
- package/apps/agents-server/src/utils/cronExpression/parseCronExpressionField.ts +140 -0
- package/apps/agents-server/src/utils/cronExpression/resolveNextCronRun.ts +100 -0
- package/apps/agents-server/src/utils/cronExpression/throwInvalidCronExpressionField.ts +20 -0
- package/apps/agents-server/src/utils/cronExpression.ts +10 -0
- package/apps/agents-server/src/utils/explicitFromCommitment.ts +130 -0
- package/apps/agents-server/src/utils/getAdminChatTasksResponse/getAdminChatTasks/loadAdminChatTaskFallbackData.ts +3 -77
- package/apps/agents-server/src/utils/localChatRunner/applyLocalAgentPlannedMessageCommands.ts +53 -4
- package/apps/agents-server/src/utils/localChatRunner/prepareLocalAgentPlannedMessagesSidecar.ts +15 -7
- package/apps/agents-server/src/utils/localChatRunner/processLocalUserChatJob.ts +8 -0
- package/apps/agents-server/src/utils/manGoOnboarding/manGoOnboardingAgentBooks.ts +5 -11
- package/apps/agents-server/src/utils/manGoOnboarding/manGoOnboardingAgentRuntime.ts +2 -2
- package/apps/agents-server/src/utils/managementApi/managementApiSchemas.ts +2 -2
- package/apps/agents-server/src/utils/plannedMessageManager/cancelManagedPlannedMessage.ts +35 -0
- package/apps/agents-server/src/utils/plannedMessageManager/collectPlannedMessageAgentOptions.ts +56 -0
- package/apps/agents-server/src/utils/plannedMessageManager/createPlannedMessageManagerCounters.ts +104 -0
- package/apps/agents-server/src/utils/plannedMessageManager/filterPlannedMessages.ts +191 -0
- package/apps/agents-server/src/utils/plannedMessageManager/getPlannedMessageManagerResponse.ts +55 -0
- package/apps/agents-server/src/utils/plannedMessageManager/isPlannedMessageStillPlanned.ts +18 -0
- package/apps/agents-server/src/utils/plannedMessageManager/loadPlannedMessageManagerRecord.ts +32 -0
- package/apps/agents-server/src/utils/plannedMessageManager/mapPlannedMessageManagerRecord.ts +73 -0
- package/apps/agents-server/src/utils/plannedMessageManager/parsePlannedMessageManagerUpdateRequest.ts +76 -0
- package/apps/agents-server/src/utils/plannedMessageManager/resolvePlannedMessageEndReason.ts +59 -0
- package/apps/agents-server/src/utils/plannedMessageManager/resolvePlannedMessageLifecycle.ts +99 -0
- package/apps/agents-server/src/utils/plannedMessageManager/resolvePlannedMessageRecurrenceKind.ts +40 -0
- package/apps/agents-server/src/utils/plannedMessageManager/updateManagedPlannedMessage.ts +121 -0
- package/apps/agents-server/src/utils/plannedMessagesAdmin.ts +200 -0
- package/apps/agents-server/src/utils/resolveInheritedAgentSource.ts +114 -95
- package/apps/agents-server/src/utils/userChatClient.ts +4 -0
- package/apps/agents-server/src/utils/userChatTimeout/UserChatTimeoutRecord.ts +37 -1
- package/apps/agents-server/src/utils/userChatTimeout/agentScopedTimeoutBulkActions.ts +11 -17
- package/apps/agents-server/src/utils/userChatTimeout/createTimeoutWakeUpMessage.ts +37 -13
- package/apps/agents-server/src/utils/userChatTimeout/plannedMessageSchedule/PlannedMessageSchedule.ts +52 -0
- package/apps/agents-server/src/utils/userChatTimeout/plannedMessageSchedule/hasPlannedMessageRecurrence.ts +13 -0
- package/apps/agents-server/src/utils/userChatTimeout/plannedMessageSchedule/isPlannedMessageScheduleFinished.ts +30 -0
- package/apps/agents-server/src/utils/userChatTimeout/plannedMessageSchedule/normalizePlannedMessageScheduleValues.ts +62 -0
- package/apps/agents-server/src/utils/userChatTimeout/plannedMessageSchedule/parsePlannedMessageSchedule.ts +202 -0
- package/apps/agents-server/src/utils/userChatTimeout/plannedMessageSchedule/resolvePlannedMessageDueAt.ts +121 -0
- package/apps/agents-server/src/utils/userChatTimeout/plannedMessageSchedule.ts +12 -0
- package/apps/agents-server/src/utils/userChatTimeout/setAgentScopedUserChatTimeoutPausedState.ts +66 -0
- package/apps/agents-server/src/utils/userChatTimeout/userChatTimeoutStore/createUserChatTimeout.ts +76 -5
- package/apps/agents-server/src/utils/userChatTimeout/userChatTimeoutStore/listAllUserChatTimeouts.ts +37 -0
- package/apps/agents-server/src/utils/userChatTimeout/userChatTimeoutStore/mapUserChatTimeoutRow.ts +9 -0
- package/apps/agents-server/src/utils/userChatTimeout/userChatTimeoutStore/repeatFiredUserChatTimeout.ts +19 -9
- package/apps/agents-server/src/utils/userChatTimeout/userChatTimeoutStore/updateAgentScopedUserChatTimeout.ts +39 -6
- package/apps/agents-server/src/utils/userChatTimeout/userChatTimeoutStore.ts +1 -0
- package/apps/agents-server/src/utils/userChatTimeout/userChatTimeoutWorker.ts +110 -11
- package/apps/agents-server/src/utils/userChatTimeout.ts +16 -0
- package/apps/agents-server/src/utils/vpsSelfUpdate/vpsSelfUpdateCron.ts +23 -316
- package/apps/agents-server/tests/e2e/support/AgentManagementApi.ts +3 -3
- package/esm/index.es.js +814 -58
- package/esm/index.es.js.map +1 -1
- package/esm/scripts/run-agent-messages/git/commitAgentProjectChanges.d.ts +15 -0
- package/esm/scripts/run-agent-messages/git/commitAnsweredMessageProjectChanges.d.ts +24 -0
- package/esm/scripts/run-agent-messages/git/ensureAgentProjectGitRepository.d.ts +20 -0
- package/esm/scripts/run-agent-messages/git/readAgentProjectCommitChange.d.ts +11 -0
- package/esm/scripts/run-agent-messages/git/runAgentProjectGitCommand.d.ts +29 -0
- package/esm/scripts/run-agent-messages/messages/buildAgentGoalChatPromptSection.d.ts +3 -3
- package/esm/scripts/run-agent-messages/messages/listAgentProjectDirectoryNames.d.ts +7 -0
- package/esm/scripts/run-agent-messages/messages/resolveAnsweredMessageTouches.d.ts +29 -0
- package/esm/src/book-3.0/AgentMessageRunReport.d.ts +18 -0
- package/esm/src/book-3.0/AgentPlannedMessagesSidecar.d.ts +38 -5
- package/esm/src/book-3.0/describeAgentPlannedMessageSchedule.d.ts +31 -0
- package/esm/src/book-components/BookEditor/createDeprecatedCommitmentDiagnostics.browser.d.ts +1 -9
- package/esm/src/book-components/BookEditor/createDuplicateFromCommitmentDiagnostics.d.ts +28 -0
- package/esm/src/book-components/BookEditor/createDuplicateFromCommitmentDiagnostics.test.d.ts +1 -0
- package/esm/src/book-components/Chat/Chat/renderAgentProjectDiff.d.ts +13 -0
- package/esm/src/book-components/Chat/Chat/renderAgentProjectToolCallDetails.d.ts +16 -0
- package/esm/src/book-components/Chat/utils/agentProjectToolCall.d.ts +39 -0
- package/esm/src/book-components/Chat/utils/agentProjectToolCall.test.d.ts +1 -0
- package/esm/src/book-components/Chat/utils/externalSourceToolCall.d.ts +38 -0
- package/esm/src/book-components/Chat/utils/timeoutToolCallPresentation.d.ts +6 -0
- package/esm/src/collection/agent-collection/constructors/agent-collection-in-supabase/AgentCollectionInSupabase.d.ts +15 -0
- package/esm/src/utils/agent-message-runtime/AgentMessageProjectChange.d.ts +76 -0
- package/esm/src/utils/agent-message-runtime/AgentMessageTouchedExternalSource.d.ts +45 -0
- package/esm/src/utils/agent-message-runtime/parseAgentMessageRuntimeLogEvents.d.ts +3 -0
- package/esm/src/utils/agent-message-runtime/resolveAgentMessageTouchedExternalSources.d.ts +18 -0
- package/esm/src/utils/agent-message-runtime/resolveAgentMessageTouchedExternalSources.test.d.ts +1 -0
- package/esm/src/utils/random/$generateBookBoilerplate.test.d.ts +1 -0
- package/esm/src/version.d.ts +1 -1
- package/package.json +1 -1
- package/src/book-2.0/agent-source/string_book.ts +1 -1
- package/src/book-2.0/book-language-documentation/czechBookLanguageManualDictionary.ts +6 -1
- package/src/book-2.0/book-language-documentation/englishBookLanguageManualDictionary.ts +6 -1
- package/src/book-3.0/AgentMessageRunReport.ts +59 -0
- package/src/book-3.0/AgentPlannedMessagesSidecar.ts +64 -9
- package/src/book-3.0/describeAgentPlannedMessageSchedule.ts +94 -0
- package/src/book-components/BookEditor/BookEditorMonaco.tsx +2 -0
- package/src/book-components/BookEditor/createDeprecatedCommitmentDiagnostics.browser.ts +3 -11
- package/src/book-components/BookEditor/createDuplicateFromCommitmentDiagnostics.ts +71 -0
- package/src/book-components/Chat/Chat/Chat.module.css +165 -18
- package/src/book-components/Chat/Chat/ChatMessageMap.tsx +0 -1
- package/src/book-components/Chat/Chat/renderAgentProjectDiff.tsx +85 -0
- package/src/book-components/Chat/Chat/renderAgentProjectToolCallDetails.tsx +206 -0
- package/src/book-components/Chat/Chat/renderToolCallDetails.tsx +8 -0
- package/src/book-components/Chat/MarkdownContent/MarkdownContent.tsx +2 -3
- package/src/book-components/Chat/utils/agentProjectToolCall.ts +82 -5
- package/src/book-components/Chat/utils/externalSourceToolCall.ts +65 -0
- package/src/book-components/Chat/utils/getToolCallChipletInfo.ts +36 -0
- package/src/book-components/Chat/utils/renderMarkdown.ts +3 -10
- package/src/book-components/Chat/utils/timeoutToolCallPresentation.ts +12 -1
- package/src/cli/cli-commands/common/harness/$applyHarnessInstallationStatus.ts +3 -1
- package/src/cli/cli-commands/common/harness/$checkHarnessInstallation.ts +3 -1
- package/src/cli/cli-commands/common/harnessUpdateCliOptions.ts +1 -4
- package/src/collection/agent-collection/constructors/agent-collection-in-supabase/AgentCollectionInSupabase.ts +47 -3
- package/src/commands/FORMAT/formatCommandParser.ts +4 -2
- package/src/commitments/FROM/FROM.ts +13 -0
- package/src/other/templates/getTemplatesPipelineCollection.ts +793 -813
- package/src/utils/agent-message-runtime/AgentMessageProjectChange.ts +183 -0
- package/src/utils/agent-message-runtime/AgentMessageTouchedExternalSource.ts +80 -0
- package/src/utils/agent-message-runtime/parseAgentMessageRuntimeLogEvents.ts +3 -0
- package/src/utils/agent-message-runtime/resolveAgentMessageRuntimeActivity.ts +2 -4
- package/src/utils/agent-message-runtime/resolveAgentMessageTouchedExternalSources.ts +341 -0
- package/src/utils/random/$generateBookBoilerplate.ts +1 -1
- package/src/version.ts +2 -2
- package/src/versions.txt +4 -0
- package/umd/index.umd.js +813 -57
- package/umd/index.umd.js.map +1 -1
- package/umd/scripts/run-agent-messages/git/commitAgentProjectChanges.d.ts +15 -0
- package/umd/scripts/run-agent-messages/git/commitAnsweredMessageProjectChanges.d.ts +24 -0
- package/umd/scripts/run-agent-messages/git/ensureAgentProjectGitRepository.d.ts +20 -0
- package/umd/scripts/run-agent-messages/git/readAgentProjectCommitChange.d.ts +11 -0
- package/umd/scripts/run-agent-messages/git/runAgentProjectGitCommand.d.ts +29 -0
- package/umd/scripts/run-agent-messages/messages/buildAgentGoalChatPromptSection.d.ts +3 -3
- package/umd/scripts/run-agent-messages/messages/listAgentProjectDirectoryNames.d.ts +7 -0
- package/umd/scripts/run-agent-messages/messages/resolveAnsweredMessageTouches.d.ts +29 -0
- package/umd/src/book-3.0/AgentMessageRunReport.d.ts +18 -0
- package/umd/src/book-3.0/AgentPlannedMessagesSidecar.d.ts +38 -5
- package/umd/src/book-3.0/describeAgentPlannedMessageSchedule.d.ts +31 -0
- package/umd/src/book-components/BookEditor/createDeprecatedCommitmentDiagnostics.browser.d.ts +1 -9
- package/umd/src/book-components/BookEditor/createDuplicateFromCommitmentDiagnostics.d.ts +28 -0
- package/umd/src/book-components/BookEditor/createDuplicateFromCommitmentDiagnostics.test.d.ts +1 -0
- package/umd/src/book-components/Chat/Chat/renderAgentProjectDiff.d.ts +13 -0
- package/umd/src/book-components/Chat/Chat/renderAgentProjectToolCallDetails.d.ts +16 -0
- package/umd/src/book-components/Chat/utils/agentProjectToolCall.d.ts +39 -0
- package/umd/src/book-components/Chat/utils/agentProjectToolCall.test.d.ts +1 -0
- package/umd/src/book-components/Chat/utils/externalSourceToolCall.d.ts +38 -0
- package/umd/src/book-components/Chat/utils/timeoutToolCallPresentation.d.ts +6 -0
- package/umd/src/collection/agent-collection/constructors/agent-collection-in-supabase/AgentCollectionInSupabase.d.ts +15 -0
- package/umd/src/utils/agent-message-runtime/AgentMessageProjectChange.d.ts +76 -0
- package/umd/src/utils/agent-message-runtime/AgentMessageTouchedExternalSource.d.ts +45 -0
- package/umd/src/utils/agent-message-runtime/parseAgentMessageRuntimeLogEvents.d.ts +3 -0
- package/umd/src/utils/agent-message-runtime/resolveAgentMessageTouchedExternalSources.d.ts +18 -0
- package/umd/src/utils/agent-message-runtime/resolveAgentMessageTouchedExternalSources.test.d.ts +1 -0
- package/umd/src/utils/random/$generateBookBoilerplate.test.d.ts +1 -0
- package/umd/src/version.d.ts +1 -1
- package/apps/agents-server/src/app/admin/task-manager/TaskManagerScopeTabs.tsx +0 -74
- package/esm/scripts/run-agent-messages/messages/resolveTouchedAgentProjects.d.ts +0 -15
- package/umd/scripts/run-agent-messages/messages/resolveTouchedAgentProjects.d.ts +0 -15
|
@@ -137,6 +137,12 @@ const nextConfig: NextConfig = {
|
|
|
137
137
|
tls: false,
|
|
138
138
|
dns: false,
|
|
139
139
|
child_process: false,
|
|
140
|
+
// Note: The startup hooks of `instrumentation.ts` only run in the Node.js runtime, but the
|
|
141
|
+
// whole graph behind them is still compiled into the edge bundle as dead code. Agent
|
|
142
|
+
// project runtimes hash and identify processes and serve built projects over plain
|
|
143
|
+
// HTTP, so both modules have to be stubbed there just like the other Node.js-only ones.
|
|
144
|
+
crypto: false,
|
|
145
|
+
http: false,
|
|
140
146
|
// jsdom and related dependencies that require Node.js APIs
|
|
141
147
|
canvas: false,
|
|
142
148
|
// Standalone VPS SQLite backend is Node-only; edge middleware never runs it
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* One option of a shared admin filter select.
|
|
5
|
+
*
|
|
6
|
+
* @private shared admin UI type
|
|
7
|
+
*/
|
|
8
|
+
export type AdminFilterSelectOption = {
|
|
9
|
+
readonly label: string;
|
|
10
|
+
readonly value: string;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Props for the shared admin filter field wrapper.
|
|
15
|
+
*
|
|
16
|
+
* @private shared admin UI type
|
|
17
|
+
*/
|
|
18
|
+
type AdminFilterFieldProps = {
|
|
19
|
+
readonly children: ReactNode;
|
|
20
|
+
readonly htmlFor: string;
|
|
21
|
+
readonly label: string;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Props for the shared admin filter select.
|
|
26
|
+
*
|
|
27
|
+
* @private shared admin UI type
|
|
28
|
+
*/
|
|
29
|
+
type AdminFilterSelectFieldProps = {
|
|
30
|
+
readonly disabled?: boolean;
|
|
31
|
+
readonly id: string;
|
|
32
|
+
readonly label: string;
|
|
33
|
+
readonly onChange: (value: string) => void;
|
|
34
|
+
readonly options: ReadonlyArray<AdminFilterSelectOption>;
|
|
35
|
+
readonly value: string;
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Shared label-and-control wrapper for compact admin filter controls.
|
|
40
|
+
*
|
|
41
|
+
* @private shared admin UI component
|
|
42
|
+
*/
|
|
43
|
+
export function AdminFilterField({ children, htmlFor, label }: AdminFilterFieldProps) {
|
|
44
|
+
return (
|
|
45
|
+
<div className="flex flex-col gap-1">
|
|
46
|
+
<label htmlFor={htmlFor} className="text-sm font-medium text-gray-700">
|
|
47
|
+
{label}
|
|
48
|
+
</label>
|
|
49
|
+
{children}
|
|
50
|
+
</div>
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Shared select control used in admin filter panels.
|
|
56
|
+
*
|
|
57
|
+
* @private shared admin UI component
|
|
58
|
+
*/
|
|
59
|
+
export function AdminFilterSelectField({
|
|
60
|
+
disabled,
|
|
61
|
+
id,
|
|
62
|
+
label,
|
|
63
|
+
onChange,
|
|
64
|
+
options,
|
|
65
|
+
value,
|
|
66
|
+
}: AdminFilterSelectFieldProps) {
|
|
67
|
+
return (
|
|
68
|
+
<AdminFilterField label={label} htmlFor={id}>
|
|
69
|
+
<select
|
|
70
|
+
id={id}
|
|
71
|
+
value={value}
|
|
72
|
+
disabled={disabled}
|
|
73
|
+
onChange={(event) => onChange(event.target.value)}
|
|
74
|
+
className="rounded-md border border-gray-300 px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-500 disabled:cursor-not-allowed disabled:bg-gray-100 disabled:text-gray-400"
|
|
75
|
+
>
|
|
76
|
+
{options.map((option) => (
|
|
77
|
+
<option key={option.value} value={option.value}>
|
|
78
|
+
{option.label}
|
|
79
|
+
</option>
|
|
80
|
+
))}
|
|
81
|
+
</select>
|
|
82
|
+
</AdminFilterField>
|
|
83
|
+
);
|
|
84
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Props for one admin summary metric card.
|
|
3
|
+
*
|
|
4
|
+
* @private shared admin UI type
|
|
5
|
+
*/
|
|
6
|
+
type AdminMetricCardProps = {
|
|
7
|
+
/**
|
|
8
|
+
* Small heading naming the measured thing.
|
|
9
|
+
*/
|
|
10
|
+
readonly label: string;
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Measured value, already formatted.
|
|
14
|
+
*/
|
|
15
|
+
readonly value: string;
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Short sentence saying what the value means.
|
|
19
|
+
*/
|
|
20
|
+
readonly caption: string;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Small metric card used in the summary header of admin dashboards.
|
|
25
|
+
*
|
|
26
|
+
* @private shared admin UI component
|
|
27
|
+
*/
|
|
28
|
+
export function AdminMetricCard({ caption, label, value }: AdminMetricCardProps) {
|
|
29
|
+
return (
|
|
30
|
+
<div className="rounded-2xl border border-gray-200 bg-white p-5 shadow-sm">
|
|
31
|
+
<div className="text-xs font-semibold uppercase tracking-wide text-gray-400">{label}</div>
|
|
32
|
+
<div className="mt-2 text-3xl font-light text-gray-900">{value}</div>
|
|
33
|
+
<div className="mt-1 text-sm text-gray-500">{caption}</div>
|
|
34
|
+
</div>
|
|
35
|
+
);
|
|
36
|
+
}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { AdminRouteTabs, type AdminRouteTabItem } from './AdminRouteTabs';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Sections of the admin background-work tab group.
|
|
7
|
+
*
|
|
8
|
+
* @private shared admin UI type
|
|
9
|
+
*/
|
|
10
|
+
export type AdminTaskManagerTabId = 'server' | 'vps' | 'planned-messages';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Task-manager scope: one server, or the whole VPS.
|
|
14
|
+
*
|
|
15
|
+
* @private shared admin UI type
|
|
16
|
+
*/
|
|
17
|
+
export type TaskManagerScope = Exclude<AdminTaskManagerTabId, 'planned-messages'>;
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Route of the per-server task manager.
|
|
21
|
+
*
|
|
22
|
+
* @private shared admin UI constant
|
|
23
|
+
*/
|
|
24
|
+
export const SERVER_TASK_MANAGER_PATH = '/admin/task-manager';
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Route of the VPS-wide (superadmin) task manager.
|
|
28
|
+
*
|
|
29
|
+
* @private shared admin UI constant
|
|
30
|
+
*/
|
|
31
|
+
export const VPS_TASK_MANAGER_PATH = '/superadmin/task-manager';
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Route of the planned-message manager.
|
|
35
|
+
*
|
|
36
|
+
* @private shared admin UI constant
|
|
37
|
+
*/
|
|
38
|
+
export const PLANNED_MESSAGE_MANAGER_PATH = '/admin/planned-messages';
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Route-backed sections of the admin background-work tab group.
|
|
42
|
+
*
|
|
43
|
+
* The task managers show what background work is running right now; the planned-message manager shows
|
|
44
|
+
* the plans that keep creating some of that work. They belong to one tab group because an
|
|
45
|
+
* administrator answering "why does this agent keep waking up?" needs to move between the two.
|
|
46
|
+
*
|
|
47
|
+
* @private constant of AdminTaskManagerTabs
|
|
48
|
+
*/
|
|
49
|
+
const ADMIN_TASK_MANAGER_TAB_ITEMS: ReadonlyArray<AdminRouteTabItem<AdminTaskManagerTabId>> = [
|
|
50
|
+
{
|
|
51
|
+
id: 'server',
|
|
52
|
+
href: SERVER_TASK_MANAGER_PATH,
|
|
53
|
+
label: 'This server',
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
id: 'vps',
|
|
57
|
+
href: VPS_TASK_MANAGER_PATH,
|
|
58
|
+
label: 'All servers (VPS)',
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
id: 'planned-messages',
|
|
62
|
+
href: PLANNED_MESSAGE_MANAGER_PATH,
|
|
63
|
+
label: 'Planned messages',
|
|
64
|
+
},
|
|
65
|
+
];
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Props for the admin background-work tabs.
|
|
69
|
+
*
|
|
70
|
+
* @private shared admin UI type
|
|
71
|
+
*/
|
|
72
|
+
type AdminTaskManagerTabsProps = {
|
|
73
|
+
/**
|
|
74
|
+
* Section the current page belongs to.
|
|
75
|
+
*/
|
|
76
|
+
readonly activeTabId: AdminTaskManagerTabId;
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Whether the VPS-wide tab is available to the current user (superadmin only).
|
|
80
|
+
*/
|
|
81
|
+
readonly isSuperAdmin: boolean;
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Renders the tabs interlinking the task managers and the planned-message manager.
|
|
86
|
+
*
|
|
87
|
+
* The VPS-wide tab is superadmin-only, so an ordinary admin moves between the two per-server sections.
|
|
88
|
+
*
|
|
89
|
+
* @private shared admin UI component
|
|
90
|
+
*/
|
|
91
|
+
export function AdminTaskManagerTabs({ activeTabId, isSuperAdmin }: AdminTaskManagerTabsProps) {
|
|
92
|
+
const visibleTabItems = ADMIN_TASK_MANAGER_TAB_ITEMS.filter(
|
|
93
|
+
(tabItem) => tabItem.id !== 'vps' || isSuperAdmin,
|
|
94
|
+
);
|
|
95
|
+
|
|
96
|
+
return <AdminRouteTabs activeTabId={activeTabId} items={visibleTabItems} />;
|
|
97
|
+
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { Card } from '../../../components/Homepage/Card';
|
|
4
|
+
import { useServerLanguage } from '../../../components/ServerLanguage/ServerLanguageProvider';
|
|
5
|
+
import { AdminTaskManagerTabs, PLANNED_MESSAGE_MANAGER_PATH } from '../_components/AdminTaskManagerTabs';
|
|
6
|
+
import { PlannedMessageManagerEditDialog } from './PlannedMessageManagerEditDialog';
|
|
7
|
+
import { PlannedMessageManagerFiltersCard } from './PlannedMessageManagerFiltersCard';
|
|
8
|
+
import { formatPlannedMessageDateTime } from './plannedMessageManagerPresentation';
|
|
9
|
+
import { PlannedMessageManagerSummaryMetrics } from './PlannedMessageManagerSummaryMetrics';
|
|
10
|
+
import { PlannedMessageManagerTableCard } from './PlannedMessageManagerTableCard';
|
|
11
|
+
import { usePlannedMessageManagerState } from './usePlannedMessageManagerState';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Props for the admin planned-message manager client.
|
|
15
|
+
*
|
|
16
|
+
* @private route component of AdminPlannedMessagesPage
|
|
17
|
+
*/
|
|
18
|
+
type PlannedMessageManagerClientProps = {
|
|
19
|
+
/**
|
|
20
|
+
* Whether the current user may also reach the VPS-wide task manager.
|
|
21
|
+
*/
|
|
22
|
+
readonly isSuperAdmin: boolean;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Admin manager of every planned message (durable chat timeout) on this server.
|
|
27
|
+
*
|
|
28
|
+
* @private route component of AdminPlannedMessagesPage
|
|
29
|
+
*/
|
|
30
|
+
export function PlannedMessageManagerClient({ isSuperAdmin }: PlannedMessageManagerClientProps) {
|
|
31
|
+
const { language } = useServerLanguage();
|
|
32
|
+
const state = usePlannedMessageManagerState();
|
|
33
|
+
const lastRefreshedLabel = state.data.generatedAt
|
|
34
|
+
? `Last refreshed ${formatPlannedMessageDateTime(state.data.generatedAt, language)}`
|
|
35
|
+
: 'Waiting for first refresh…';
|
|
36
|
+
|
|
37
|
+
return (
|
|
38
|
+
<div className="container mx-auto space-y-6 px-4 py-8">
|
|
39
|
+
<div className="mt-20">
|
|
40
|
+
<AdminTaskManagerTabs activeTabId="planned-messages" isSuperAdmin={isSuperAdmin} />
|
|
41
|
+
</div>
|
|
42
|
+
|
|
43
|
+
<div className="flex flex-col gap-4 md:flex-row md:items-end md:justify-between">
|
|
44
|
+
<div>
|
|
45
|
+
<h1 className="text-3xl font-light text-gray-900">Planned messages</h1>
|
|
46
|
+
<p className="mt-1 max-w-3xl text-sm text-gray-500">
|
|
47
|
+
Admin-only view of every timeout an agent planned for itself or for one of its chats — the
|
|
48
|
+
wake-ups still ahead, the ones starting later, the ones firing right now, and the ones that were
|
|
49
|
+
cancelled or whose plan is over. Each of them can be re-planned, held back, or cancelled here.
|
|
50
|
+
</p>
|
|
51
|
+
</div>
|
|
52
|
+
<div className="flex flex-wrap items-center gap-2 text-xs text-gray-500">
|
|
53
|
+
<span className="rounded-full border border-gray-200 bg-white px-3 py-1.5">
|
|
54
|
+
Route: <span className="font-mono text-gray-700">{PLANNED_MESSAGE_MANAGER_PATH}</span>
|
|
55
|
+
</span>
|
|
56
|
+
<button
|
|
57
|
+
type="button"
|
|
58
|
+
onClick={state.data.refreshNow}
|
|
59
|
+
disabled={state.data.isRefreshing}
|
|
60
|
+
className="rounded-full border border-blue-200 bg-blue-50 px-3 py-1.5 font-semibold text-blue-700 disabled:cursor-not-allowed disabled:opacity-60"
|
|
61
|
+
>
|
|
62
|
+
{state.data.isRefreshing ? 'Refreshing…' : 'Refresh now'}
|
|
63
|
+
</button>
|
|
64
|
+
</div>
|
|
65
|
+
</div>
|
|
66
|
+
|
|
67
|
+
<PlannedMessageManagerSummaryMetrics
|
|
68
|
+
counters={state.counters}
|
|
69
|
+
isLoading={state.data.isLoading}
|
|
70
|
+
language={language}
|
|
71
|
+
/>
|
|
72
|
+
|
|
73
|
+
<PlannedMessageManagerFiltersCard state={state} lastRefreshedLabel={lastRefreshedLabel} />
|
|
74
|
+
|
|
75
|
+
{state.data.error !== null && (
|
|
76
|
+
<Card className="border-red-200 bg-red-50 hover:border-red-200 hover:shadow-md">
|
|
77
|
+
<p className="text-sm text-red-700">{state.data.error}</p>
|
|
78
|
+
</Card>
|
|
79
|
+
)}
|
|
80
|
+
|
|
81
|
+
{state.data.hasMore && (
|
|
82
|
+
<Card className="border-amber-200 bg-amber-50 hover:border-amber-200 hover:shadow-md">
|
|
83
|
+
<p className="text-sm text-amber-800">
|
|
84
|
+
This server has more planned messages than one listing shows. The most recently changed ones are
|
|
85
|
+
listed — narrow the filters to find an older one.
|
|
86
|
+
</p>
|
|
87
|
+
</Card>
|
|
88
|
+
)}
|
|
89
|
+
|
|
90
|
+
<PlannedMessageManagerTableCard language={language} state={state} />
|
|
91
|
+
|
|
92
|
+
{state.editedPlannedMessage !== null && (
|
|
93
|
+
<PlannedMessageManagerEditDialog
|
|
94
|
+
key={state.editedPlannedMessage.timeoutId}
|
|
95
|
+
plannedMessage={state.editedPlannedMessage}
|
|
96
|
+
isSaving={state.busyAction === 'edit'}
|
|
97
|
+
onClose={state.closePlannedMessageEditor}
|
|
98
|
+
onSubmit={state.submitPlannedMessageEdit}
|
|
99
|
+
/>
|
|
100
|
+
)}
|
|
101
|
+
</div>
|
|
102
|
+
);
|
|
103
|
+
}
|
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { Dialog } from '@/src/components/Portal/Dialog';
|
|
4
|
+
import type { PlannedMessageRecurrenceKind } from '@/src/utils/plannedMessageManager/resolvePlannedMessageRecurrenceKind';
|
|
5
|
+
import type { PlannedMessageManagerRecord } from '@/src/utils/plannedMessagesAdmin';
|
|
6
|
+
import { X } from 'lucide-react';
|
|
7
|
+
import { useState } from 'react';
|
|
8
|
+
import {
|
|
9
|
+
createPlannedMessageEditForm,
|
|
10
|
+
type PlannedMessageEditForm,
|
|
11
|
+
type PlannedMessageIntervalUnit,
|
|
12
|
+
} from './plannedMessageEditForm';
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Frequency choices offered by the editor, with what each of them needs.
|
|
16
|
+
*
|
|
17
|
+
* @private function of PlannedMessageManagerEditDialog
|
|
18
|
+
*/
|
|
19
|
+
const PLANNED_MESSAGE_RECURRENCE_CHOICES: ReadonlyArray<{
|
|
20
|
+
readonly id: PlannedMessageRecurrenceKind;
|
|
21
|
+
readonly label: string;
|
|
22
|
+
readonly description: string;
|
|
23
|
+
}> = [
|
|
24
|
+
{ id: 'INTERVAL', label: 'Every', description: 'Repeats at a fixed interval' },
|
|
25
|
+
{ id: 'CRON', label: 'On a cron', description: 'Repeats on a five-field cron expression' },
|
|
26
|
+
{ id: 'ONCE', label: 'Once', description: 'Wakes the agent a single time, at the starting date' },
|
|
27
|
+
];
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Interval units offered by the editor.
|
|
31
|
+
*
|
|
32
|
+
* @private function of PlannedMessageManagerEditDialog
|
|
33
|
+
*/
|
|
34
|
+
const PLANNED_MESSAGE_INTERVAL_UNITS: ReadonlyArray<PlannedMessageIntervalUnit> = ['minutes', 'hours', 'days'];
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Shared classes of the editor text inputs.
|
|
38
|
+
*
|
|
39
|
+
* @private function of PlannedMessageManagerEditDialog
|
|
40
|
+
*/
|
|
41
|
+
const PLANNED_MESSAGE_EDITOR_INPUT_CLASS_NAME =
|
|
42
|
+
'w-full rounded-md border border-gray-300 px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-500';
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Props for the planned-message editor.
|
|
46
|
+
*
|
|
47
|
+
* @private function of PlannedMessageManagerClient
|
|
48
|
+
*/
|
|
49
|
+
type PlannedMessageManagerEditDialogProps = {
|
|
50
|
+
readonly plannedMessage: PlannedMessageManagerRecord;
|
|
51
|
+
readonly isSaving: boolean;
|
|
52
|
+
readonly onClose: () => void;
|
|
53
|
+
readonly onSubmit: (form: PlannedMessageEditForm) => Promise<boolean>;
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Dialog changing the whole plan of one planned message.
|
|
58
|
+
*
|
|
59
|
+
* The form always describes the complete plan, so emptying a bound really removes it. What the plan is
|
|
60
|
+
* allowed to be is decided by the server, which holds an administrator to the very same rules an agent
|
|
61
|
+
* planning for itself is held to.
|
|
62
|
+
*
|
|
63
|
+
* @private function of PlannedMessageManagerClient
|
|
64
|
+
*/
|
|
65
|
+
export function PlannedMessageManagerEditDialog({
|
|
66
|
+
plannedMessage,
|
|
67
|
+
isSaving,
|
|
68
|
+
onClose,
|
|
69
|
+
onSubmit,
|
|
70
|
+
}: PlannedMessageManagerEditDialogProps) {
|
|
71
|
+
const [form, setForm] = useState<PlannedMessageEditForm>(() => createPlannedMessageEditForm(plannedMessage));
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Applies one field change to the edited plan.
|
|
75
|
+
*/
|
|
76
|
+
function updateForm(change: Partial<PlannedMessageEditForm>): void {
|
|
77
|
+
setForm((currentForm) => ({ ...currentForm, ...change }));
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
return (
|
|
81
|
+
<Dialog onClose={onClose} className="w-[min(44rem,92vw)] p-6" ariaLabel="Edit planned message">
|
|
82
|
+
<div className="flex items-start justify-between gap-4">
|
|
83
|
+
<div>
|
|
84
|
+
<h2 className="text-lg font-medium text-gray-900">Edit planned message</h2>
|
|
85
|
+
<p className="mt-1 text-sm text-gray-500">
|
|
86
|
+
Of {plannedMessage.agentName || plannedMessage.agentPermanentId}
|
|
87
|
+
</p>
|
|
88
|
+
</div>
|
|
89
|
+
<button
|
|
90
|
+
type="button"
|
|
91
|
+
onClick={onClose}
|
|
92
|
+
className="rounded-md p-1 text-gray-400 hover:bg-gray-100 hover:text-gray-600"
|
|
93
|
+
title="Close"
|
|
94
|
+
aria-label="Close"
|
|
95
|
+
>
|
|
96
|
+
<X className="h-4 w-4" />
|
|
97
|
+
</button>
|
|
98
|
+
</div>
|
|
99
|
+
|
|
100
|
+
<form
|
|
101
|
+
className="mt-4 flex flex-col gap-4"
|
|
102
|
+
onSubmit={(event) => {
|
|
103
|
+
event.preventDefault();
|
|
104
|
+
void onSubmit(form);
|
|
105
|
+
}}
|
|
106
|
+
>
|
|
107
|
+
<label className="flex flex-col gap-1">
|
|
108
|
+
<span className="text-sm font-medium text-gray-700">Message</span>
|
|
109
|
+
<textarea
|
|
110
|
+
value={form.message}
|
|
111
|
+
rows={3}
|
|
112
|
+
onChange={(event) => updateForm({ message: event.target.value })}
|
|
113
|
+
className={PLANNED_MESSAGE_EDITOR_INPUT_CLASS_NAME}
|
|
114
|
+
placeholder="What the agent is woken up to do"
|
|
115
|
+
/>
|
|
116
|
+
</label>
|
|
117
|
+
|
|
118
|
+
<fieldset className="flex flex-col gap-2">
|
|
119
|
+
<legend className="text-sm font-medium text-gray-700">Frequency</legend>
|
|
120
|
+
{PLANNED_MESSAGE_RECURRENCE_CHOICES.map((choice) => (
|
|
121
|
+
<label key={choice.id} className="flex flex-wrap items-center gap-2 text-sm text-gray-700">
|
|
122
|
+
<input
|
|
123
|
+
type="radio"
|
|
124
|
+
name="planned-message-recurrence-kind"
|
|
125
|
+
checked={form.recurrenceKind === choice.id}
|
|
126
|
+
onChange={() => updateForm({ recurrenceKind: choice.id })}
|
|
127
|
+
/>
|
|
128
|
+
<span className="font-medium">{choice.label}</span>
|
|
129
|
+
|
|
130
|
+
{choice.id === 'INTERVAL' && (
|
|
131
|
+
<>
|
|
132
|
+
<input
|
|
133
|
+
type="number"
|
|
134
|
+
min={1}
|
|
135
|
+
value={form.intervalValue}
|
|
136
|
+
onChange={(event) => updateForm({ intervalValue: event.target.value })}
|
|
137
|
+
disabled={form.recurrenceKind !== 'INTERVAL'}
|
|
138
|
+
className="w-24 rounded-md border border-gray-300 px-2 py-1 text-sm disabled:bg-gray-100"
|
|
139
|
+
/>
|
|
140
|
+
<select
|
|
141
|
+
value={form.intervalUnit}
|
|
142
|
+
onChange={(event) =>
|
|
143
|
+
updateForm({
|
|
144
|
+
intervalUnit: event.target.value as PlannedMessageIntervalUnit,
|
|
145
|
+
})
|
|
146
|
+
}
|
|
147
|
+
disabled={form.recurrenceKind !== 'INTERVAL'}
|
|
148
|
+
className="rounded-md border border-gray-300 px-2 py-1 text-sm disabled:bg-gray-100"
|
|
149
|
+
>
|
|
150
|
+
{PLANNED_MESSAGE_INTERVAL_UNITS.map((unit) => (
|
|
151
|
+
<option key={unit} value={unit}>
|
|
152
|
+
{unit}
|
|
153
|
+
</option>
|
|
154
|
+
))}
|
|
155
|
+
</select>
|
|
156
|
+
</>
|
|
157
|
+
)}
|
|
158
|
+
|
|
159
|
+
{choice.id === 'CRON' && (
|
|
160
|
+
<input
|
|
161
|
+
type="text"
|
|
162
|
+
value={form.cronExpression}
|
|
163
|
+
onChange={(event) => updateForm({ cronExpression: event.target.value })}
|
|
164
|
+
disabled={form.recurrenceKind !== 'CRON'}
|
|
165
|
+
placeholder="0 9 * * 1-5"
|
|
166
|
+
className="w-44 rounded-md border border-gray-300 px-2 py-1 font-mono text-sm disabled:bg-gray-100"
|
|
167
|
+
/>
|
|
168
|
+
)}
|
|
169
|
+
|
|
170
|
+
<span className="text-xs text-gray-500">{choice.description}</span>
|
|
171
|
+
</label>
|
|
172
|
+
))}
|
|
173
|
+
</fieldset>
|
|
174
|
+
|
|
175
|
+
<div className="grid gap-4 sm:grid-cols-3">
|
|
176
|
+
<label className="flex flex-col gap-1">
|
|
177
|
+
<span className="text-sm font-medium text-gray-700">Starts at</span>
|
|
178
|
+
<input
|
|
179
|
+
type="datetime-local"
|
|
180
|
+
value={form.startsAtLocal}
|
|
181
|
+
onChange={(event) => updateForm({ startsAtLocal: event.target.value })}
|
|
182
|
+
className={PLANNED_MESSAGE_EDITOR_INPUT_CLASS_NAME}
|
|
183
|
+
/>
|
|
184
|
+
<span className="text-xs text-gray-500">Empty means it may wake the agent right away.</span>
|
|
185
|
+
</label>
|
|
186
|
+
|
|
187
|
+
<label className="flex flex-col gap-1">
|
|
188
|
+
<span className="text-sm font-medium text-gray-700">Ends at</span>
|
|
189
|
+
<input
|
|
190
|
+
type="datetime-local"
|
|
191
|
+
value={form.endsAtLocal}
|
|
192
|
+
onChange={(event) => updateForm({ endsAtLocal: event.target.value })}
|
|
193
|
+
className={PLANNED_MESSAGE_EDITOR_INPUT_CLASS_NAME}
|
|
194
|
+
/>
|
|
195
|
+
<span className="text-xs text-gray-500">Empty means it has no ending date.</span>
|
|
196
|
+
</label>
|
|
197
|
+
|
|
198
|
+
<label className="flex flex-col gap-1">
|
|
199
|
+
<span className="text-sm font-medium text-gray-700">Total runs</span>
|
|
200
|
+
<input
|
|
201
|
+
type="number"
|
|
202
|
+
min={1}
|
|
203
|
+
value={form.maxRunCount}
|
|
204
|
+
onChange={(event) => updateForm({ maxRunCount: event.target.value })}
|
|
205
|
+
className={PLANNED_MESSAGE_EDITOR_INPUT_CLASS_NAME}
|
|
206
|
+
/>
|
|
207
|
+
<span className="text-xs text-gray-500">
|
|
208
|
+
Empty means it repeats until cancelled. Already done: {plannedMessage.runCount}.
|
|
209
|
+
</span>
|
|
210
|
+
</label>
|
|
211
|
+
</div>
|
|
212
|
+
|
|
213
|
+
<div className="mt-2 flex items-center justify-end gap-2">
|
|
214
|
+
<button
|
|
215
|
+
type="button"
|
|
216
|
+
onClick={onClose}
|
|
217
|
+
className="rounded-md border border-gray-300 px-3 py-1.5 text-sm font-medium text-gray-700 hover:bg-gray-50"
|
|
218
|
+
>
|
|
219
|
+
Close
|
|
220
|
+
</button>
|
|
221
|
+
<button
|
|
222
|
+
type="submit"
|
|
223
|
+
disabled={isSaving}
|
|
224
|
+
className="rounded-md border border-blue-200 bg-blue-50 px-3 py-1.5 text-sm font-semibold text-blue-700 hover:bg-blue-100 disabled:cursor-not-allowed disabled:opacity-60"
|
|
225
|
+
>
|
|
226
|
+
{isSaving ? 'Saving…' : 'Save plan'}
|
|
227
|
+
</button>
|
|
228
|
+
</div>
|
|
229
|
+
</form>
|
|
230
|
+
</Dialog>
|
|
231
|
+
);
|
|
232
|
+
}
|