@promptbook/cli 0.113.0-5 → 0.113.0-8
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/src/app/admin/update/AdvancedOriginRepositoryPanel.tsx +76 -0
- package/apps/agents-server/src/app/admin/update/CurrentDeploymentCard.tsx +160 -0
- package/apps/agents-server/src/app/admin/update/PendingCommitsCard.tsx +86 -0
- package/apps/agents-server/src/app/admin/update/TargetEnvironmentCard.tsx +331 -0
- package/apps/agents-server/src/app/admin/update/UpdateClient.tsx +20 -873
- package/apps/agents-server/src/app/admin/update/UpdateJobCard.tsx +329 -0
- package/apps/agents-server/src/app/admin/update/UpdateOverview.ts +74 -0
- package/apps/agents-server/src/app/admin/update/buildDeploymentTimeBehindLabel.ts +29 -0
- package/apps/agents-server/src/app/admin/update/formatHumanReadableTimestamp.ts +18 -0
- package/apps/agents-server/src/app/admin/update/getUpdateJobFailureMessage.ts +13 -0
- package/apps/agents-server/src/app/admin/update/getUpdateJobSuccessMessage.ts +13 -0
- package/apps/agents-server/src/app/admin/update/useUpdateClientState.ts +441 -0
- package/apps/agents-server/src/app/agents/[agentName]/api/book/route.ts +13 -1
- package/apps/agents-server/src/app/agents/[agentName]/export-as-transpiled-code/AgentCodePageClient.tsx +14 -559
- package/apps/agents-server/src/app/agents/[agentName]/export-as-transpiled-code/AgentCodePageHeader.tsx +84 -0
- package/apps/agents-server/src/app/agents/[agentName]/export-as-transpiled-code/AgentCodePageSection.tsx +52 -0
- package/apps/agents-server/src/app/agents/[agentName]/export-as-transpiled-code/GeneratedCodePreview.tsx +138 -0
- package/apps/agents-server/src/app/agents/[agentName]/export-as-transpiled-code/GeneratedHarnessSection.tsx +98 -0
- package/apps/agents-server/src/app/agents/[agentName]/export-as-transpiled-code/SourceBookSection.tsx +66 -0
- package/apps/agents-server/src/app/agents/[agentName]/export-as-transpiled-code/TranspiledCodeErrorBanner.tsx +30 -0
- package/apps/agents-server/src/app/agents/[agentName]/export-as-transpiled-code/TranspiledCodeExportWarningBanner.tsx +62 -0
- package/apps/agents-server/src/app/agents/[agentName]/export-as-transpiled-code/Transpiler.ts +9 -0
- package/apps/agents-server/src/app/agents/[agentName]/export-as-transpiled-code/useAgentCodeExportState.ts +478 -0
- package/apps/agents-server/src/app/system/utilities/mocked-chats/cloneMockedChatPreset.ts +17 -0
- package/apps/agents-server/src/app/system/utilities/mocked-chats/confirmDeleteMockedChat.ts +16 -0
- package/apps/agents-server/src/app/system/utilities/mocked-chats/createDraftWithUpdatedMessage.ts +81 -0
- package/apps/agents-server/src/app/system/utilities/mocked-chats/createDraftWithUpdatedParticipant.ts +146 -0
- package/apps/agents-server/src/app/system/utilities/mocked-chats/createDraftWithUpdatedSettings.ts +19 -0
- package/apps/agents-server/src/app/system/utilities/mocked-chats/createDuplicatedDraft.ts +66 -0
- package/apps/agents-server/src/app/system/utilities/mocked-chats/findMockedChatById.ts +51 -0
- package/apps/agents-server/src/app/system/utilities/mocked-chats/persistMockedChats.ts +51 -0
- package/apps/agents-server/src/app/system/utilities/mocked-chats/useMockedChatsEditorState.ts +16 -426
- package/apps/agents-server/src/components/Homepage/buildFreeGraphBoxLayout.ts +446 -0
- package/apps/agents-server/src/components/Homepage/buildGraphLayoutNodes.ts +415 -157
- package/apps/agents-server/src/components/Homepage/useAgentsGraphCanvasState.ts +2 -1
- package/apps/agents-server/src/database/sqlite/$provideLocalSqliteSupabase.ts +3 -1541
- package/apps/agents-server/src/database/sqlite/localSqliteSupabase/LocalSqliteQueryBuilder.ts +623 -0
- package/apps/agents-server/src/database/sqlite/localSqliteSupabase/LocalSqliteSupabaseClient.ts +64 -0
- package/apps/agents-server/src/database/sqlite/localSqliteSupabase/ensureTable.ts +93 -0
- package/apps/agents-server/src/database/sqlite/localSqliteSupabase/localSqliteFilters.ts +202 -0
- package/apps/agents-server/src/database/sqlite/localSqliteSupabase/localSqliteMutationPayload.ts +131 -0
- package/apps/agents-server/src/database/sqlite/localSqliteSupabase/localSqliteRowOperations.ts +102 -0
- package/apps/agents-server/src/database/sqlite/localSqliteSupabase/localSqliteSql.ts +59 -0
- package/apps/agents-server/src/database/sqlite/localSqliteSupabase/localSqliteTableSchema.ts +329 -0
- package/apps/agents-server/src/database/sqlite/localSqliteSupabase/localSqliteTypes.ts +84 -0
- package/apps/agents-server/src/database/sqlite/localSqliteSupabase/localSqliteValueCodec.ts +63 -0
- package/apps/agents-server/src/database/sqlite/localSqliteSupabase/normalizeSqliteError.ts +22 -0
- package/apps/agents-server/src/search/createDefaultServerSearchProviders/loadLocalOrganizationSearchDataset.ts +12 -1
- package/apps/agents-server/src/tools/send_email.ts +1 -2
- package/apps/agents-server/src/utils/agentOrganization/loadAgentOrganizationState.ts +13 -1
- package/apps/agents-server/src/utils/backup/createServerBackupZipStream.ts +7 -1382
- package/apps/agents-server/src/utils/backup/serverBackup/appendAgentBackupEntriesToZip.ts +27 -0
- package/apps/agents-server/src/utils/backup/serverBackup/appendConversationBackupEntriesToZip.ts +140 -0
- package/apps/agents-server/src/utils/backup/serverBackup/appendFileBackupEntriesToZip.ts +147 -0
- package/apps/agents-server/src/utils/backup/serverBackup/appendMessageBackupEntriesToZip.ts +65 -0
- package/apps/agents-server/src/utils/backup/serverBackup/appendMetadataBackupEntriesToZip.ts +39 -0
- package/apps/agents-server/src/utils/backup/serverBackup/appendSectionEntriesToZip.ts +92 -0
- package/apps/agents-server/src/utils/backup/serverBackup/appendUserBackupEntriesToZip.ts +80 -0
- package/apps/agents-server/src/utils/backup/serverBackup/createRedactedWalletBackupRecord.ts +34 -0
- package/apps/agents-server/src/utils/backup/serverBackup/createServerBackupManifest.ts +82 -0
- package/apps/agents-server/src/utils/backup/serverBackup/downloadBackupBinaryContent.ts +39 -0
- package/apps/agents-server/src/utils/backup/serverBackup/resolveFeedbackThreadMessages.ts +53 -0
- package/apps/agents-server/src/utils/backup/serverBackup/serverBackupAttachments.ts +151 -0
- package/apps/agents-server/src/utils/backup/serverBackup/serverBackupContext.ts +167 -0
- package/apps/agents-server/src/utils/backup/serverBackup/serverBackupFilenames.ts +161 -0
- package/apps/agents-server/src/utils/backup/serverBackup/serverBackupPreviews.ts +97 -0
- package/apps/agents-server/src/utils/backup/serverBackup/serverBackupRowUtilities.ts +158 -0
- package/apps/agents-server/src/utils/backup/serverBackup/serverBackupTypes.ts +59 -0
- package/apps/agents-server/src/utils/createLocalAgentSourceImporter.ts +159 -0
- package/apps/agents-server/src/utils/createMissingImportedAgentFallback.ts +60 -0
- package/apps/agents-server/src/utils/customDomainRouting.ts +157 -12
- package/apps/agents-server/src/utils/externalChatRunner/processExternalUserChatJob.ts +1 -1
- package/apps/agents-server/src/utils/importAgentWithFallback.ts +1 -58
- package/apps/agents-server/src/utils/localAgentRouteReferences.ts +167 -0
- package/apps/agents-server/src/utils/localChatRunner/processLocalUserChatJob.ts +1 -1
- package/apps/agents-server/src/utils/managementApi/managementApiAgents.ts +17 -3
- package/apps/agents-server/src/utils/messages/sendMessage.ts +5 -3
- package/apps/agents-server/src/utils/resolveAgentStateFromSource.ts +7 -1
- package/apps/agents-server/src/utils/resolveInheritedAgentSource.ts +54 -5
- package/apps/agents-server/src/utils/resolveServerAgentContext.ts +12 -1
- package/apps/agents-server/src/utils/resolveStoredAgentState.ts +2 -1
- package/apps/agents-server/src/utils/speech-to-text/SpeechToTextFailoverRecognition/SpeechToTextFailoverRecognitionProviderRuntime.ts +0 -1
- package/apps/agents-server/src/utils/speech-to-text/SpeechToTextFailoverRecognition.ts +34 -2
- package/apps/agents-server/src/utils/userChat/userChatMessageLifecycle.ts +39 -9
- package/apps/agents-server/tests/e2e/support/ChatHistoryNavigationSupport.ts +5 -0
- package/esm/index.es.js +96 -57
- package/esm/index.es.js.map +1 -1
- package/esm/scripts/find-refactor-candidates/find-refactor-candidates.d.ts +7 -0
- package/esm/scripts/find-refactor-candidates/selectMostImportantRefactorCandidates.d.ts +12 -0
- package/esm/src/book-components/Chat/Chat/insertDictationChunk.d.ts +1 -1
- package/esm/src/book-components/Chat/Chat/insertDictationChunk.test.d.ts +1 -0
- package/esm/src/book-components/Chat/Chat/learnDictationDictionary.test.d.ts +1 -0
- package/esm/src/book-components/Chat/Chat/refineFinalDictationChunk.test.d.ts +1 -0
- package/esm/src/cli/cli-commands/common/createPositiveIntegerOptionParser.d.ts +10 -0
- package/esm/src/version.d.ts +1 -1
- package/package.json +1 -1
- package/src/avatars/avatarAnimationScheduler.ts +2 -1
- package/src/avatars/visuals/octopus3d3AvatarVisual.ts +6 -2
- package/src/avatars/visuals/octopus3d4AvatarVisual.ts +14 -18
- package/src/book-components/Chat/Chat/insertDictationChunk.ts +3 -3
- package/src/book-components/Chat/Chat/learnDictationDictionary.ts +1 -1
- package/src/book-components/Chat/Chat/useChatInputAreaDictation.ts +133 -26
- package/src/cli/cli-commands/agents-server/buildAgentsServer.ts +3 -1
- package/src/cli/cli-commands/coder/boilerplateTemplates.ts +14 -21
- package/src/cli/cli-commands/coder/find-refactor-candidates.ts +9 -2
- package/src/cli/cli-commands/coder/initializeCoderProjectConfiguration.ts +1 -4
- package/src/cli/cli-commands/coder/run.ts +3 -27
- package/src/cli/cli-commands/common/createPositiveIntegerOptionParser.ts +31 -0
- package/src/commitments/TEAM/TEAM.ts +5 -5
- package/src/other/templates/getTemplatesPipelineCollection.ts +727 -781
- package/src/utils/ascii-art/convertImageDataToAsciiArt.ts +1 -4
- package/src/version.ts +2 -2
- package/src/versions.txt +1 -0
- package/umd/index.umd.js +96 -57
- package/umd/index.umd.js.map +1 -1
- package/umd/scripts/find-refactor-candidates/find-refactor-candidates.d.ts +7 -0
- package/umd/scripts/find-refactor-candidates/selectMostImportantRefactorCandidates.d.ts +12 -0
- package/umd/src/book-components/Chat/Chat/insertDictationChunk.d.ts +1 -1
- package/umd/src/book-components/Chat/Chat/insertDictationChunk.test.d.ts +1 -0
- package/umd/src/book-components/Chat/Chat/learnDictationDictionary.test.d.ts +1 -0
- package/umd/src/book-components/Chat/Chat/refineFinalDictationChunk.test.d.ts +1 -0
- package/umd/src/cli/cli-commands/common/createPositiveIntegerOptionParser.d.ts +10 -0
- package/umd/src/version.d.ts +1 -1
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { ChevronDown, ChevronUp, Settings2 } from 'lucide-react';
|
|
4
|
+
import type { UpdateOverview } from './UpdateOverview';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Props for the advanced upstream repository settings panel.
|
|
8
|
+
*
|
|
9
|
+
* @private type of `<AdvancedOriginRepositoryPanel/>`
|
|
10
|
+
*/
|
|
11
|
+
type AdvancedOriginRepositoryPanelProps = {
|
|
12
|
+
readonly originRepositoryUrlOverride: string;
|
|
13
|
+
readonly onChange: (nextValue: string) => void;
|
|
14
|
+
readonly overview: UpdateOverview | null;
|
|
15
|
+
readonly isExpanded: boolean;
|
|
16
|
+
readonly onToggleExpanded: () => void;
|
|
17
|
+
readonly isDisabled: boolean;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Collapsible advanced panel for overriding the upstream repository URL.
|
|
22
|
+
*
|
|
23
|
+
* @private internal component of `<UpdateClient/>`
|
|
24
|
+
*/
|
|
25
|
+
export function AdvancedOriginRepositoryPanel({
|
|
26
|
+
originRepositoryUrlOverride,
|
|
27
|
+
onChange,
|
|
28
|
+
overview,
|
|
29
|
+
isExpanded,
|
|
30
|
+
onToggleExpanded,
|
|
31
|
+
isDisabled,
|
|
32
|
+
}: AdvancedOriginRepositoryPanelProps) {
|
|
33
|
+
return (
|
|
34
|
+
<div className="rounded-xl border border-slate-200 bg-white">
|
|
35
|
+
<button
|
|
36
|
+
type="button"
|
|
37
|
+
onClick={onToggleExpanded}
|
|
38
|
+
className="flex w-full items-center justify-between gap-3 px-4 py-3 text-sm font-semibold text-slate-700"
|
|
39
|
+
>
|
|
40
|
+
<span className="inline-flex items-center gap-2">
|
|
41
|
+
<Settings2 className="h-4 w-4" />
|
|
42
|
+
Advanced
|
|
43
|
+
</span>
|
|
44
|
+
{isExpanded ? <ChevronUp className="h-4 w-4" /> : <ChevronDown className="h-4 w-4" />}
|
|
45
|
+
</button>
|
|
46
|
+
{isExpanded && (
|
|
47
|
+
<div className="space-y-3 border-t border-slate-100 px-4 py-3 text-sm text-slate-600">
|
|
48
|
+
<label className="block">
|
|
49
|
+
<span className="text-xs font-semibold uppercase tracking-wide text-slate-500">
|
|
50
|
+
Upstream repository URL
|
|
51
|
+
</span>
|
|
52
|
+
<input
|
|
53
|
+
type="url"
|
|
54
|
+
value={originRepositoryUrlOverride}
|
|
55
|
+
onChange={(event) => onChange(event.target.value)}
|
|
56
|
+
disabled={isDisabled}
|
|
57
|
+
placeholder={overview?.defaultOriginRepositoryUrl || ''}
|
|
58
|
+
className="mt-1 w-full rounded-md border border-slate-300 bg-white px-3 py-2 font-mono text-sm focus:border-blue-500 focus:outline-none focus:ring-1 focus:ring-blue-500 disabled:cursor-not-allowed disabled:opacity-60"
|
|
59
|
+
/>
|
|
60
|
+
</label>
|
|
61
|
+
<p className="text-xs text-slate-500">
|
|
62
|
+
Defaults to <span className="font-mono">{overview?.defaultOriginRepositoryUrl}</span>. Only
|
|
63
|
+
change this if you self-host a fork of the original Promptbook repository — the new value is
|
|
64
|
+
persisted in the standalone VPS <code>.env</code>.
|
|
65
|
+
</p>
|
|
66
|
+
{overview && !overview.isOriginRepositoryDefault && (
|
|
67
|
+
<div className="rounded-md border border-amber-200 bg-amber-50 px-3 py-2 text-xs text-amber-800">
|
|
68
|
+
<strong>Custom origin active:</strong> updates currently pull from{' '}
|
|
69
|
+
<span className="font-mono">{overview.originRepositoryUrl}</span>.
|
|
70
|
+
</div>
|
|
71
|
+
)}
|
|
72
|
+
</div>
|
|
73
|
+
)}
|
|
74
|
+
</div>
|
|
75
|
+
);
|
|
76
|
+
}
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { CheckCircle2, Server, TriangleAlert } from 'lucide-react';
|
|
4
|
+
import { useMemo } from 'react';
|
|
5
|
+
import type { ServerLanguageCode } from '../../../languages/ServerLanguageRegistry';
|
|
6
|
+
import { buildDeploymentTimeBehindLabel } from './buildDeploymentTimeBehindLabel';
|
|
7
|
+
import { formatHumanReadableTimestamp } from './formatHumanReadableTimestamp';
|
|
8
|
+
import type { UpdateOverview } from './UpdateOverview';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Props for the current deployment summary card.
|
|
12
|
+
*
|
|
13
|
+
* @private type of `<CurrentDeploymentCard/>`
|
|
14
|
+
*/
|
|
15
|
+
type CurrentDeploymentCardProps = {
|
|
16
|
+
readonly overview: UpdateOverview | null;
|
|
17
|
+
readonly language: ServerLanguageCode;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Props for rendering one commit summary.
|
|
22
|
+
*
|
|
23
|
+
* @private type of `<CurrentDeploymentCard/>`
|
|
24
|
+
*/
|
|
25
|
+
type CommitSummaryCardProps = {
|
|
26
|
+
readonly label: string;
|
|
27
|
+
readonly commitSha: string | null;
|
|
28
|
+
readonly shortCommitSha: string | null;
|
|
29
|
+
readonly subject: string | null;
|
|
30
|
+
readonly authoredAt: string | null;
|
|
31
|
+
readonly language: ServerLanguageCode;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Current-deployment metrics card, including the new commits-behind and time-behind info.
|
|
36
|
+
*
|
|
37
|
+
* @private internal component of `<UpdateClient/>`
|
|
38
|
+
*/
|
|
39
|
+
export function CurrentDeploymentCard({ overview, language }: CurrentDeploymentCardProps) {
|
|
40
|
+
const driftLabel = useMemo(() => buildDeploymentDriftLabel(overview, language), [overview, language]);
|
|
41
|
+
|
|
42
|
+
return (
|
|
43
|
+
<div className="space-y-4">
|
|
44
|
+
<div className="flex items-start gap-3">
|
|
45
|
+
<Server className="mt-0.5 h-5 w-5 text-blue-600" />
|
|
46
|
+
<div>
|
|
47
|
+
<h2 className="text-lg font-semibold text-slate-900">Current deployment</h2>
|
|
48
|
+
<p className="mt-1 text-sm text-slate-500">
|
|
49
|
+
The server currently tracks the{' '}
|
|
50
|
+
<span className="font-medium">{overview?.currentEnvironment.label || 'Production'}</span>{' '}
|
|
51
|
+
environment on branch{' '}
|
|
52
|
+
<span className="font-mono">{overview?.currentEnvironment.branch || 'production'}</span>.
|
|
53
|
+
</p>
|
|
54
|
+
</div>
|
|
55
|
+
</div>
|
|
56
|
+
|
|
57
|
+
<dl className="grid gap-4 text-sm text-slate-600 sm:grid-cols-2">
|
|
58
|
+
<div className="rounded-xl border border-slate-200 bg-slate-50 px-4 py-3">
|
|
59
|
+
<dt className="text-xs font-semibold uppercase tracking-wide text-slate-500">Branch</dt>
|
|
60
|
+
<dd className="mt-1 font-mono text-slate-900">
|
|
61
|
+
{overview?.currentEnvironment.branch || 'production'}
|
|
62
|
+
</dd>
|
|
63
|
+
</div>
|
|
64
|
+
<CommitSummaryCard
|
|
65
|
+
label="Deployed commit"
|
|
66
|
+
commitSha={overview?.currentCommitSha ?? null}
|
|
67
|
+
shortCommitSha={overview?.currentCommitShortSha ?? null}
|
|
68
|
+
subject={overview?.currentCommitMessage ?? null}
|
|
69
|
+
authoredAt={overview?.currentCommitDate ?? null}
|
|
70
|
+
language={language}
|
|
71
|
+
/>
|
|
72
|
+
<CommitSummaryCard
|
|
73
|
+
label="Latest remote commit"
|
|
74
|
+
commitSha={overview?.latestRemoteCommitSha ?? null}
|
|
75
|
+
shortCommitSha={overview?.latestRemoteCommitShortSha ?? null}
|
|
76
|
+
subject={overview?.latestRemoteCommitMessage ?? null}
|
|
77
|
+
authoredAt={overview?.latestRemoteCommitDate ?? null}
|
|
78
|
+
language={language}
|
|
79
|
+
/>
|
|
80
|
+
<div className="rounded-xl border border-slate-200 bg-slate-50 px-4 py-3">
|
|
81
|
+
<dt className="text-xs font-semibold uppercase tracking-wide text-slate-500">
|
|
82
|
+
Update availability
|
|
83
|
+
</dt>
|
|
84
|
+
<dd className="mt-1 flex items-center gap-2 text-slate-900">
|
|
85
|
+
{overview?.isUpdateAvailable ? (
|
|
86
|
+
<>
|
|
87
|
+
<TriangleAlert className="h-4 w-4 text-amber-500" />
|
|
88
|
+
{driftLabel}
|
|
89
|
+
</>
|
|
90
|
+
) : (
|
|
91
|
+
<>
|
|
92
|
+
<CheckCircle2 className="h-4 w-4 text-emerald-600" />
|
|
93
|
+
Up to date
|
|
94
|
+
</>
|
|
95
|
+
)}
|
|
96
|
+
</dd>
|
|
97
|
+
</div>
|
|
98
|
+
</dl>
|
|
99
|
+
|
|
100
|
+
{overview?.repositoryDirectory && (
|
|
101
|
+
<div className="text-xs text-slate-500">
|
|
102
|
+
Managed repository:
|
|
103
|
+
<span className="ml-2 font-mono text-slate-700">{overview.repositoryDirectory}</span>
|
|
104
|
+
</div>
|
|
105
|
+
)}
|
|
106
|
+
</div>
|
|
107
|
+
);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Renders one commit as subject, hash and authored date.
|
|
112
|
+
*
|
|
113
|
+
* @private internal component of `<CurrentDeploymentCard/>`
|
|
114
|
+
*/
|
|
115
|
+
function CommitSummaryCard({
|
|
116
|
+
label,
|
|
117
|
+
commitSha,
|
|
118
|
+
shortCommitSha,
|
|
119
|
+
subject,
|
|
120
|
+
authoredAt,
|
|
121
|
+
language,
|
|
122
|
+
}: CommitSummaryCardProps) {
|
|
123
|
+
const commitHashLabel = commitSha || shortCommitSha || 'Unknown hash';
|
|
124
|
+
|
|
125
|
+
return (
|
|
126
|
+
<div className="rounded-xl border border-slate-200 bg-slate-50 px-4 py-3">
|
|
127
|
+
<dt className="text-xs font-semibold uppercase tracking-wide text-slate-500">{label}</dt>
|
|
128
|
+
<dd className="mt-1 text-slate-900">{subject || 'Unknown commit subject'}</dd>
|
|
129
|
+
<div className="mt-2 break-all font-mono text-xs text-slate-600">{commitHashLabel}</div>
|
|
130
|
+
<div className="mt-1 text-xs text-slate-500">{formatHumanReadableTimestamp(authoredAt, language)}</div>
|
|
131
|
+
</div>
|
|
132
|
+
);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Builds the "behind by …" label combining commits-behind and time-behind info.
|
|
137
|
+
*
|
|
138
|
+
* @param overview - Current overview snapshot.
|
|
139
|
+
* @param language - Active UI language for moment localization.
|
|
140
|
+
* @returns Human-readable label or fallback text.
|
|
141
|
+
*
|
|
142
|
+
* @private function of `<CurrentDeploymentCard/>`
|
|
143
|
+
*/
|
|
144
|
+
function buildDeploymentDriftLabel(overview: UpdateOverview | null, language: ServerLanguageCode): string {
|
|
145
|
+
if (!overview) {
|
|
146
|
+
return 'New commit available';
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
const commitsBehindLabel =
|
|
150
|
+
overview.commitsBehindCount !== null && overview.commitsBehindCount > 0
|
|
151
|
+
? `${overview.commitsBehindCount} commit${overview.commitsBehindCount === 1 ? '' : 's'} behind`
|
|
152
|
+
: 'New commit available';
|
|
153
|
+
|
|
154
|
+
const timeBehindLabel = buildDeploymentTimeBehindLabel(overview, language);
|
|
155
|
+
if (!timeBehindLabel) {
|
|
156
|
+
return commitsBehindLabel;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
return `${commitsBehindLabel} · ${timeBehindLabel}`;
|
|
160
|
+
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { GitCommit } from 'lucide-react';
|
|
4
|
+
import type { ServerLanguageCode } from '../../../languages/ServerLanguageRegistry';
|
|
5
|
+
import { Card } from '../../../components/Homepage/Card';
|
|
6
|
+
import { buildDeploymentTimeBehindLabel } from './buildDeploymentTimeBehindLabel';
|
|
7
|
+
import { formatHumanReadableTimestamp } from './formatHumanReadableTimestamp';
|
|
8
|
+
import type { UpdateOverview } from './UpdateOverview';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Props for the pending commits card.
|
|
12
|
+
*
|
|
13
|
+
* @private type of `<PendingCommitsCard/>`
|
|
14
|
+
*/
|
|
15
|
+
type PendingCommitsCardProps = {
|
|
16
|
+
readonly overview: UpdateOverview | null;
|
|
17
|
+
readonly language: ServerLanguageCode;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Lists the commits between the deployed checkout and the latest remote commit so the super admin can review what
|
|
22
|
+
* exactly is about to be installed before triggering the self-update.
|
|
23
|
+
*
|
|
24
|
+
* @private internal component of `<UpdateClient/>`
|
|
25
|
+
*/
|
|
26
|
+
export function PendingCommitsCard({ overview, language }: PendingCommitsCardProps) {
|
|
27
|
+
if (!overview || overview.pendingCommits.length === 0) {
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const commitsBehindLabel = getPendingCommitsCountLabel(overview);
|
|
32
|
+
const timeBehindLabel = buildDeploymentTimeBehindLabel(overview, language);
|
|
33
|
+
|
|
34
|
+
return (
|
|
35
|
+
<Card className="hover:border-gray-200 hover:shadow-md">
|
|
36
|
+
<div className="space-y-4">
|
|
37
|
+
<div className="flex flex-col gap-2 sm:flex-row sm:items-start sm:justify-between">
|
|
38
|
+
<div className="flex items-start gap-3">
|
|
39
|
+
<GitCommit className="mt-0.5 h-5 w-5 text-amber-500" />
|
|
40
|
+
<div>
|
|
41
|
+
<h2 className="text-lg font-semibold text-slate-900">Pending commits</h2>
|
|
42
|
+
<p className="mt-1 text-sm text-slate-500">
|
|
43
|
+
Commits between the currently deployed checkout and the latest commit on{' '}
|
|
44
|
+
<span className="font-mono">{overview.currentEnvironment.branch}</span>.
|
|
45
|
+
</p>
|
|
46
|
+
</div>
|
|
47
|
+
</div>
|
|
48
|
+
<div className="text-xs font-semibold uppercase tracking-wide text-slate-500 sm:text-right">
|
|
49
|
+
<div>{commitsBehindLabel}</div>
|
|
50
|
+
{timeBehindLabel && <div className="mt-1 normal-case text-slate-400">{timeBehindLabel}</div>}
|
|
51
|
+
</div>
|
|
52
|
+
</div>
|
|
53
|
+
|
|
54
|
+
<ul className="divide-y divide-slate-100 rounded-xl border border-slate-200 bg-white">
|
|
55
|
+
{overview.pendingCommits.map((pendingCommit) => (
|
|
56
|
+
<li key={pendingCommit.commitSha} className="px-4 py-3">
|
|
57
|
+
<div className="text-sm text-slate-900">{pendingCommit.subject}</div>
|
|
58
|
+
<div className="mt-1 break-all font-mono text-xs text-slate-500">
|
|
59
|
+
{pendingCommit.commitSha || pendingCommit.shortCommitSha}
|
|
60
|
+
</div>
|
|
61
|
+
<div className="mt-1 text-xs text-slate-500">
|
|
62
|
+
{formatHumanReadableTimestamp(pendingCommit.authoredAt, language)}
|
|
63
|
+
</div>
|
|
64
|
+
</li>
|
|
65
|
+
))}
|
|
66
|
+
</ul>
|
|
67
|
+
</div>
|
|
68
|
+
</Card>
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Builds the pending-commit count label shown in the card header.
|
|
74
|
+
*
|
|
75
|
+
* @param overview - Current overview snapshot.
|
|
76
|
+
* @returns Human-readable count label.
|
|
77
|
+
*
|
|
78
|
+
* @private function of `<PendingCommitsCard/>`
|
|
79
|
+
*/
|
|
80
|
+
function getPendingCommitsCountLabel(overview: UpdateOverview): string {
|
|
81
|
+
if (overview.commitsBehindCount !== null && overview.commitsBehindCount > 0) {
|
|
82
|
+
return `${overview.commitsBehindCount} commit${overview.commitsBehindCount === 1 ? '' : 's'} behind`;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
return `${overview.pendingCommits.length} commit${overview.pendingCommits.length === 1 ? '' : 's'} pending`;
|
|
86
|
+
}
|
|
@@ -0,0 +1,331 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { Download, Loader2, Rocket, TriangleAlert } from 'lucide-react';
|
|
4
|
+
import type { ServerLanguageCode } from '../../../languages/ServerLanguageRegistry';
|
|
5
|
+
import { AdvancedOriginRepositoryPanel } from './AdvancedOriginRepositoryPanel';
|
|
6
|
+
import { CustomCommitPicker } from './CustomCommitPicker';
|
|
7
|
+
import type { UpdateEnvironmentOption } from './UpdateOverview';
|
|
8
|
+
import type { UpdateClientState } from './useUpdateClientState';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Props for the target environment card.
|
|
12
|
+
*
|
|
13
|
+
* @private type of `<TargetEnvironmentCard/>`
|
|
14
|
+
*/
|
|
15
|
+
type TargetEnvironmentCardProps = {
|
|
16
|
+
readonly state: UpdateClientState;
|
|
17
|
+
readonly language: ServerLanguageCode;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Props for the environment option list.
|
|
22
|
+
*
|
|
23
|
+
* @private type of `<TargetEnvironmentCard/>`
|
|
24
|
+
*/
|
|
25
|
+
type EnvironmentOptionListProps = {
|
|
26
|
+
readonly environments: ReadonlyArray<UpdateEnvironmentOption>;
|
|
27
|
+
readonly currentEnvironmentId: string | null;
|
|
28
|
+
readonly selectedEnvironmentId: string | null;
|
|
29
|
+
readonly isDisabled: boolean;
|
|
30
|
+
readonly onSelectEnvironment: (environmentId: string) => void;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Props for one environment option button.
|
|
35
|
+
*
|
|
36
|
+
* @private type of `<TargetEnvironmentCard/>`
|
|
37
|
+
*/
|
|
38
|
+
type EnvironmentOptionButtonProps = {
|
|
39
|
+
readonly environment: UpdateEnvironmentOption;
|
|
40
|
+
readonly isSelected: boolean;
|
|
41
|
+
readonly isCurrent: boolean;
|
|
42
|
+
readonly isDisabled: boolean;
|
|
43
|
+
readonly onSelectEnvironment: (environmentId: string) => void;
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Props for the custom ref selection panel.
|
|
48
|
+
*
|
|
49
|
+
* @private type of `<TargetEnvironmentCard/>`
|
|
50
|
+
*/
|
|
51
|
+
type CustomRefPanelProps = {
|
|
52
|
+
readonly state: UpdateClientState;
|
|
53
|
+
readonly language: ServerLanguageCode;
|
|
54
|
+
readonly isControlsDisabled: boolean;
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Props for the primary update start button.
|
|
59
|
+
*
|
|
60
|
+
* @private type of `<TargetEnvironmentCard/>`
|
|
61
|
+
*/
|
|
62
|
+
type UpdateStartButtonProps = {
|
|
63
|
+
readonly state: UpdateClientState;
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Visual mode used by the primary update start button icon.
|
|
68
|
+
*
|
|
69
|
+
* @private type of `<TargetEnvironmentCard/>`
|
|
70
|
+
*/
|
|
71
|
+
type UpdateStartButtonMode = 'loading' | 'rocket' | 'download';
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Target environment picker and update trigger controls.
|
|
75
|
+
*
|
|
76
|
+
* @private internal component of `<UpdateClient/>`
|
|
77
|
+
*/
|
|
78
|
+
export function TargetEnvironmentCard({ state, language }: TargetEnvironmentCardProps) {
|
|
79
|
+
const isControlsDisabled = state.isUpdateRunning || state.isStartingUpdate;
|
|
80
|
+
|
|
81
|
+
return (
|
|
82
|
+
<div className="space-y-4">
|
|
83
|
+
<div>
|
|
84
|
+
<h2 className="text-lg font-semibold text-slate-900">Target environment</h2>
|
|
85
|
+
<p className="mt-1 text-sm text-slate-500">
|
|
86
|
+
Selecting another environment automatically updates the server to the latest commit on that branch.
|
|
87
|
+
</p>
|
|
88
|
+
</div>
|
|
89
|
+
|
|
90
|
+
<EnvironmentOptionList
|
|
91
|
+
environments={state.overview?.environments ?? []}
|
|
92
|
+
currentEnvironmentId={state.overview?.currentEnvironment.id ?? null}
|
|
93
|
+
selectedEnvironmentId={state.selectedEnvironment?.id ?? null}
|
|
94
|
+
isDisabled={isControlsDisabled}
|
|
95
|
+
onSelectEnvironment={state.selectEnvironment}
|
|
96
|
+
/>
|
|
97
|
+
|
|
98
|
+
<CustomRefPanel state={state} language={language} isControlsDisabled={isControlsDisabled} />
|
|
99
|
+
|
|
100
|
+
<AdvancedOriginRepositoryPanel
|
|
101
|
+
originRepositoryUrlOverride={state.originRepositoryUrlOverride}
|
|
102
|
+
onChange={state.changeOriginRepositoryUrlOverride}
|
|
103
|
+
overview={state.overview}
|
|
104
|
+
isExpanded={state.isAdvancedExpanded}
|
|
105
|
+
onToggleExpanded={state.toggleAdvanced}
|
|
106
|
+
isDisabled={isControlsDisabled}
|
|
107
|
+
/>
|
|
108
|
+
|
|
109
|
+
<UpdateStartButton state={state} />
|
|
110
|
+
</div>
|
|
111
|
+
);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Renders all update environment choices.
|
|
116
|
+
*
|
|
117
|
+
* @private internal component of `<TargetEnvironmentCard/>`
|
|
118
|
+
*/
|
|
119
|
+
function EnvironmentOptionList({
|
|
120
|
+
environments,
|
|
121
|
+
currentEnvironmentId,
|
|
122
|
+
selectedEnvironmentId,
|
|
123
|
+
isDisabled,
|
|
124
|
+
onSelectEnvironment,
|
|
125
|
+
}: EnvironmentOptionListProps) {
|
|
126
|
+
return (
|
|
127
|
+
<div className="grid gap-3">
|
|
128
|
+
{environments.map((environment) => (
|
|
129
|
+
<EnvironmentOptionButton
|
|
130
|
+
key={environment.id}
|
|
131
|
+
environment={environment}
|
|
132
|
+
isSelected={environment.id === selectedEnvironmentId}
|
|
133
|
+
isCurrent={environment.id === currentEnvironmentId}
|
|
134
|
+
isDisabled={isDisabled}
|
|
135
|
+
onSelectEnvironment={onSelectEnvironment}
|
|
136
|
+
/>
|
|
137
|
+
))}
|
|
138
|
+
</div>
|
|
139
|
+
);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Renders one selectable update environment.
|
|
144
|
+
*
|
|
145
|
+
* @private internal component of `<TargetEnvironmentCard/>`
|
|
146
|
+
*/
|
|
147
|
+
function EnvironmentOptionButton({
|
|
148
|
+
environment,
|
|
149
|
+
isSelected,
|
|
150
|
+
isCurrent,
|
|
151
|
+
isDisabled,
|
|
152
|
+
onSelectEnvironment,
|
|
153
|
+
}: EnvironmentOptionButtonProps) {
|
|
154
|
+
return (
|
|
155
|
+
<button
|
|
156
|
+
type="button"
|
|
157
|
+
onClick={() => onSelectEnvironment(environment.id)}
|
|
158
|
+
disabled={isDisabled}
|
|
159
|
+
className={`rounded-2xl border px-4 py-4 text-left transition ${
|
|
160
|
+
isSelected
|
|
161
|
+
? 'border-blue-300 bg-blue-50 text-blue-900 shadow-sm'
|
|
162
|
+
: 'border-slate-200 bg-white text-slate-700 hover:border-slate-300 hover:shadow-sm'
|
|
163
|
+
} disabled:cursor-not-allowed disabled:opacity-60`}
|
|
164
|
+
>
|
|
165
|
+
<div className="flex items-center justify-between gap-3">
|
|
166
|
+
<div className="text-sm font-semibold">{environment.label}</div>
|
|
167
|
+
{isCurrent && (
|
|
168
|
+
<span className="rounded-full border border-emerald-200 bg-emerald-50 px-2 py-0.5 text-[11px] font-semibold uppercase tracking-wide text-emerald-700">
|
|
169
|
+
Current
|
|
170
|
+
</span>
|
|
171
|
+
)}
|
|
172
|
+
</div>
|
|
173
|
+
{environment.branch && <div className="mt-1 font-mono text-xs">{environment.branch}</div>}
|
|
174
|
+
<div className="mt-2 text-sm opacity-80">{environment.description}</div>
|
|
175
|
+
</button>
|
|
176
|
+
);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Shows the custom commit/tag/branch picker for the custom target environment.
|
|
181
|
+
*
|
|
182
|
+
* @private internal component of `<TargetEnvironmentCard/>`
|
|
183
|
+
*/
|
|
184
|
+
function CustomRefPanel({ state, language, isControlsDisabled }: CustomRefPanelProps) {
|
|
185
|
+
if (!state.isCustomEnvironmentSelected) {
|
|
186
|
+
return null;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
if (!state.overview?.isAvailable) {
|
|
190
|
+
return null;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
return (
|
|
194
|
+
<div className="space-y-3 rounded-xl border border-blue-200 bg-blue-50/40 p-4">
|
|
195
|
+
<CustomCommitPicker
|
|
196
|
+
language={language}
|
|
197
|
+
selectedRef={state.customRef}
|
|
198
|
+
onSelectRef={state.selectCustomRef}
|
|
199
|
+
isDisabled={isControlsDisabled}
|
|
200
|
+
/>
|
|
201
|
+
|
|
202
|
+
{state.customRef.trim() && !state.isCustomRefRelease && (
|
|
203
|
+
<div className="flex items-start gap-2 rounded-md border border-amber-200 bg-amber-50 px-3 py-2 text-xs text-amber-800">
|
|
204
|
+
<TriangleAlert className="mt-0.5 h-4 w-4 shrink-0" />
|
|
205
|
+
<div>
|
|
206
|
+
<strong>Heads up:</strong> the selected ref is not a release tag, so it may be unstable and was
|
|
207
|
+
not validated by the regular release pipeline.
|
|
208
|
+
</div>
|
|
209
|
+
</div>
|
|
210
|
+
)}
|
|
211
|
+
</div>
|
|
212
|
+
);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Primary button for starting an update using the selected target.
|
|
217
|
+
*
|
|
218
|
+
* @private internal component of `<TargetEnvironmentCard/>`
|
|
219
|
+
*/
|
|
220
|
+
function UpdateStartButton({ state }: UpdateStartButtonProps) {
|
|
221
|
+
const buttonMode = getUpdateStartButtonMode(state);
|
|
222
|
+
|
|
223
|
+
return (
|
|
224
|
+
<button
|
|
225
|
+
type="button"
|
|
226
|
+
onClick={() => void state.startUpdate()}
|
|
227
|
+
disabled={isUpdateStartDisabled(state)}
|
|
228
|
+
className="inline-flex w-full items-center justify-center gap-2 rounded-md bg-blue-600 px-4 py-3 text-sm font-semibold text-white hover:bg-blue-700 disabled:cursor-not-allowed disabled:opacity-60"
|
|
229
|
+
>
|
|
230
|
+
<UpdateStartButtonIcon buttonMode={buttonMode} />
|
|
231
|
+
{getUpdateStartButtonLabel(state)}
|
|
232
|
+
</button>
|
|
233
|
+
);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* Renders the icon for the update start button.
|
|
238
|
+
*
|
|
239
|
+
* @private internal component of `<TargetEnvironmentCard/>`
|
|
240
|
+
*/
|
|
241
|
+
function UpdateStartButtonIcon({ buttonMode }: { readonly buttonMode: UpdateStartButtonMode }) {
|
|
242
|
+
if (buttonMode === 'loading') {
|
|
243
|
+
return <Loader2 className="h-4 w-4 animate-spin" />;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
if (buttonMode === 'rocket') {
|
|
247
|
+
return <Rocket className="h-4 w-4" />;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
return <Download className="h-4 w-4" />;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* Resolves whether the primary update button should be disabled.
|
|
255
|
+
*
|
|
256
|
+
* @param state - Current update client state.
|
|
257
|
+
* @returns `true` when the update cannot be started from the current selection.
|
|
258
|
+
*
|
|
259
|
+
* @private function of `<TargetEnvironmentCard/>`
|
|
260
|
+
*/
|
|
261
|
+
function isUpdateStartDisabled(state: UpdateClientState): boolean {
|
|
262
|
+
if (!state.overview?.isAvailable) {
|
|
263
|
+
return true;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
if (!state.selectedEnvironment) {
|
|
267
|
+
return true;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
if (state.isUpdateRunning || state.isStartingUpdate) {
|
|
271
|
+
return true;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
if (state.isCustomRefMissing) {
|
|
275
|
+
return true;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
if (state.isCustomEnvironmentSelected) {
|
|
279
|
+
return false;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
if (state.isEnvironmentSwitchRequired) {
|
|
283
|
+
return false;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
if (state.overview.isUpdateAvailable) {
|
|
287
|
+
return false;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
return !state.isOriginRepositoryUrlOverrideChanged;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
/**
|
|
294
|
+
* Resolves which icon should be shown by the update start button.
|
|
295
|
+
*
|
|
296
|
+
* @param state - Current update client state.
|
|
297
|
+
* @returns Button icon mode.
|
|
298
|
+
*
|
|
299
|
+
* @private function of `<TargetEnvironmentCard/>`
|
|
300
|
+
*/
|
|
301
|
+
function getUpdateStartButtonMode(state: UpdateClientState): UpdateStartButtonMode {
|
|
302
|
+
if (state.isStartingUpdate || state.isUpdateRunning) {
|
|
303
|
+
return 'loading';
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
if (state.isCustomEnvironmentSelected || state.isEnvironmentSwitchRequired) {
|
|
307
|
+
return 'rocket';
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
return 'download';
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
/**
|
|
314
|
+
* Builds the primary update button label from the current target selection.
|
|
315
|
+
*
|
|
316
|
+
* @param state - Current update client state.
|
|
317
|
+
* @returns Human-readable button label.
|
|
318
|
+
*
|
|
319
|
+
* @private function of `<TargetEnvironmentCard/>`
|
|
320
|
+
*/
|
|
321
|
+
function getUpdateStartButtonLabel(state: UpdateClientState): string {
|
|
322
|
+
if (state.isCustomEnvironmentSelected) {
|
|
323
|
+
return `Update to ${state.customRef.trim() || 'custom ref'}`;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
if (state.isEnvironmentSwitchRequired) {
|
|
327
|
+
return `Switch to ${state.selectedEnvironment?.label || 'selected environment'} and update`;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
return 'Update to latest commit';
|
|
331
|
+
}
|