@@ -21,17 +21,22 @@ export interface ProjectSyncView {
2121 canSync : boolean ;
2222}
2323
24- export function formatLastSynced ( timestamp ?: string ) : string {
24+ function formatTimestamp ( timestamp ?: string ) : string | undefined {
2525 if ( ! timestamp ) {
26- return 'Never synced' ;
26+ return undefined ;
2727 }
2828
2929 const parsed = new Date ( timestamp ) ;
3030 if ( Number . isNaN ( parsed . getTime ( ) ) ) {
31- return 'Never synced' ;
31+ return undefined ;
3232 }
3333
34- return `Last synced ${ parsed . toLocaleString ( ) } ` ;
34+ return parsed . toLocaleString ( ) ;
35+ }
36+
37+ export function formatLastSynced ( timestamp ?: string ) : string {
38+ const formatted = formatTimestamp ( timestamp ) ;
39+ return formatted ? `Last synced ${ formatted } ` : 'Never synced' ;
3540}
3641
3742export function formatRemoteRunCount ( count ?: number ) : string {
@@ -41,6 +46,22 @@ export function formatRemoteRunCount(count?: number): string {
4146 return `${ count } remote run${ count === 1 ? '' : 's' } ` ;
4247}
4348
49+ export function buildRemoteStatusItems (
50+ status : RemoteStatusResponse | undefined ,
51+ projectName ?: string ,
52+ ) : string [ ] {
53+ if ( status ?. configured !== true ) {
54+ return [ ] ;
55+ }
56+
57+ return [
58+ projectName ? `Project: ${ projectName } ` : undefined ,
59+ formatRemoteRunCount ( status . run_count ) ,
60+ formatLastSynced ( status . last_synced_at ) ,
61+ status . repo ? `Repo: ${ status . repo } ` : undefined ,
62+ ] . filter ( ( item ) : item is string => item !== undefined ) ;
63+ }
64+
4465export function getProjectSyncView (
4566 status : RemoteStatusResponse | undefined ,
4667 syncInFlight = false ,
@@ -140,14 +161,63 @@ export function getProjectSyncView(
140161 } ;
141162}
142163
164+ function formatSyncOutcomeRuns ( count ?: number ) : string {
165+ if ( typeof count !== 'number' || ! Number . isFinite ( count ) ) {
166+ return 'remote results' ;
167+ }
168+ return formatRemoteRunCount ( count ) ;
169+ }
170+
171+ function buildSyncOutcomeSentence ( status : RemoteStatusResponse ) : string {
172+ const parts = [ `Synced ${ formatSyncOutcomeRuns ( status . run_count ) } ` ] ;
173+ if ( status . repo ) {
174+ parts . push ( `from ${ status . repo } ` ) ;
175+ }
176+
177+ const syncedAt = formatTimestamp ( status . last_synced_at ) ;
178+ if ( syncedAt ) {
179+ parts . push ( `at ${ syncedAt } ` ) ;
180+ }
181+
182+ return `${ parts . join ( ' ' ) } .` ;
183+ }
184+
185+ function buildCachedRemoteAvailability (
186+ status : RemoteStatusResponse | undefined ,
187+ ) : string | undefined {
188+ if ( status ?. available !== true ) {
189+ return undefined ;
190+ }
191+
192+ const runCount = status . run_count ;
193+ if ( typeof runCount === 'number' && Number . isFinite ( runCount ) && runCount > 0 ) {
194+ return `Cached ${ formatRemoteRunCount ( runCount ) } ${
195+ runCount === 1 ? 'remains' : 'remain'
196+ } available.`;
197+ }
198+
199+ return 'The remote results cache remains available.' ;
200+ }
201+
202+ export function buildRemoteErrorAction ( status : RemoteStatusResponse | undefined ) : string {
203+ return [
204+ buildCachedRemoteAvailability ( status ) ,
205+ 'Resolve the results repo issue, then sync remote results again.' ,
206+ ]
207+ . filter ( ( part ) : part is string => part !== undefined )
208+ . join ( ' ' ) ;
209+ }
210+
143211export function buildProjectSyncFeedback ( status : RemoteStatusResponse ) : {
144212 kind : 'success' | 'warning' ;
145213 message : string ;
146214} {
147215 if ( status . blocked || status . sync_status === 'conflicted' || status . sync_status === 'diverged' ) {
216+ const repo = status . repo ? ` for ${ status . repo } ` : '' ;
217+ const reason = status . block_reason ?? 'Sync stopped before changing the results repo.' ;
148218 return {
149219 kind : 'warning' ,
150- message : status . block_reason ?? ' Sync stopped before changing the results repo.' ,
220+ message : ` Sync stopped${ repo } : ${ reason } . ${ buildRemoteErrorAction ( status ) } ` ,
151221 } ;
152222 }
153223
@@ -161,7 +231,21 @@ export function buildProjectSyncFeedback(status: RemoteStatusResponse): {
161231 kind : 'success' ,
162232 message :
163233 actions . length > 0
164- ? `Sync complete: ${ actions . join ( ', ' ) } .`
165- : 'Sync complete; project results are up to date.' ,
234+ ? `${ buildSyncOutcomeSentence ( status ) } Sync completed: ${ actions . join ( ', ' ) } .`
235+ : `${ buildSyncOutcomeSentence ( status ) } Project results were already up to date.` ,
236+ } ;
237+ }
238+
239+ export function buildProjectSyncErrorFeedback (
240+ error : unknown ,
241+ status : RemoteStatusResponse | undefined ,
242+ ) : {
243+ kind : 'error' ;
244+ message : string ;
245+ } {
246+ const message = error instanceof Error ? error . message : String ( error ) ;
247+ return {
248+ kind : 'error' ,
249+ message : `Sync failed: ${ message } . ${ buildRemoteErrorAction ( status ) } ` ,
166250 } ;
167251}
0 commit comments