@@ -4,7 +4,6 @@ import { createComponent, LocationService, NestedRouteLink, Shade } from '@furys
44import type { ColumnFilterConfig } from '@furystack/shades-common-components'
55import {
66 Button ,
7- ButtonGroup ,
87 CollectionService ,
98 DataGrid ,
109 Icon ,
@@ -32,6 +31,12 @@ import { navigate } from '../../utils/navigate.js'
3231import { ConfirmDialog } from '../../components/confirm-dialog.js'
3332import { ServiceForm } from '../../components/entity-forms/service-form.js'
3433import { ServiceStatusIndicator } from '../../components/service-status-indicator.js'
34+ import {
35+ BuildStatusChip ,
36+ CloneStatusChip ,
37+ InstallStatusChip ,
38+ RunStatusChip ,
39+ } from '../../components/status-chips.js'
3540import { ServicesApiClient } from '../../services/api-clients/services-api-client.js'
3641
3742const eventLabels : Record < string , string > = {
@@ -270,50 +275,6 @@ export const ServiceDetail = Shade<ServiceDetailProps>({
270275 actions = {
271276 < div style = { { display : 'flex' , alignItems : 'center' , gap : '8px' , flexWrap : 'wrap' } } >
272277 < ServiceStatusIndicator service = { service } />
273- < ButtonGroup variant = "outlined" >
274- { service . runStatus !== 'running' ? (
275- < Button
276- size = "small"
277- color = "success"
278- loading = { actionInProgress === 'start' }
279- disabled = { ! ! actionInProgress }
280- onclick = { ( ) => void runAction ( 'start' , '/services/:id/start' ) }
281- startIcon = { < Icon icon = { icons . play } size = "small" /> }
282- >
283- Start
284- </ Button >
285- ) : (
286- < Button
287- size = "small"
288- loading = { actionInProgress === 'stop' }
289- disabled = { ! ! actionInProgress }
290- onclick = { ( ) => void runAction ( 'stop' , '/services/:id/stop' ) }
291- startIcon = { < Icon icon = { icons . stopCircle } size = "small" /> }
292- >
293- Stop
294- </ Button >
295- ) }
296- < Button
297- size = "small"
298- loading = { actionInProgress === 'restart' }
299- disabled = { ! ! actionInProgress }
300- onclick = { ( ) => void runAction ( 'restart' , '/services/:id/restart' ) }
301- startIcon = { < Icon icon = { icons . refresh } size = "small" /> }
302- >
303- Restart
304- </ Button >
305- { service . repositoryId ? (
306- < Button
307- size = "small"
308- loading = { actionInProgress === 'update' }
309- disabled = { ! ! actionInProgress }
310- onclick = { ( ) => void runAction ( 'update' , '/services/:id/update' ) }
311- startIcon = { < Icon icon = { icons . download } size = "small" /> }
312- >
313- Update
314- </ Button >
315- ) : null }
316- </ ButtonGroup >
317278 < NestedRouteLink href = { `/services/${ service . id } /logs` } >
318279 < Button variant = "outlined" size = "small" startIcon = { < Icon icon = { icons . file } size = "small" /> } >
319280 Logs
@@ -340,7 +301,15 @@ export const ServiceDetail = Shade<ServiceDetailProps>({
340301 }
341302 />
342303 < Paper >
343- < div style = { { display : 'grid' , gridTemplateColumns : '200px 1fr' , gap : '8px 16px' , fontSize : '14px' } } >
304+ < div
305+ style = { {
306+ display : 'grid' ,
307+ gridTemplateColumns : '200px 1fr auto' ,
308+ gap : '8px 16px' ,
309+ fontSize : '14px' ,
310+ alignItems : 'center' ,
311+ } }
312+ >
344313 { linkedRepo ? (
345314 < div style = { { display : 'contents' } } >
346315 < strong > Repository</ strong >
@@ -349,46 +318,43 @@ export const ServiceDetail = Shade<ServiceDetailProps>({
349318 { linkedRepo . displayName }
350319 </ NestedRouteLink >
351320 </ span >
321+ < span >
322+ { linkedRepo . url ? (
323+ < a href = { linkedRepo . url } target = "_blank" rel = "noopener noreferrer" style = { { color : 'inherit' } } >
324+ < Button variant = "outlined" size = "small" startIcon = { < Icon icon = { icons . externalLink } size = "small" /> } >
325+ Open
326+ </ Button >
327+ </ a >
328+ ) : null }
329+ </ span >
352330 </ div >
353331 ) : null }
354332 < strong > Working Directory</ strong >
355333 < span style = { { fontFamily : 'monospace' } } > { fullCwd ?? '(loading…)' } </ span >
356- < strong > Run Command</ strong >
357- < span style = { { fontFamily : 'monospace' } } > { service . runCommand } </ span >
358- { service . installCommand ? (
359- < div style = { { display : 'contents' } } >
360- < strong > Install Command</ strong >
361- < span style = { { fontFamily : 'monospace' } } > { service . installCommand } </ span >
362- </ div >
363- ) : null }
364- { service . buildCommand ? (
334+ < span />
335+ { service . repositoryId ? (
365336 < div style = { { display : 'contents' } } >
366- < strong > Build Command</ strong >
367- < span style = { { fontFamily : 'monospace' } } > { service . buildCommand } </ span >
337+ < strong > Clone</ strong >
338+ < CloneStatusChip status = { service . cloneStatus } />
339+ < Button
340+ variant = "outlined"
341+ size = "small"
342+ loading = { actionInProgress === 'pull' }
343+ disabled = { ! ! actionInProgress }
344+ onclick = { ( ) => void runAction ( 'pull' , '/services/:id/pull' ) }
345+ startIcon = { < Icon icon = { icons . download } size = "small" /> }
346+ >
347+ { service . cloneStatus === 'not-cloned' ? 'Clone' : 'Pull' }
348+ </ Button >
368349 </ div >
369350 ) : null }
370- { service . repositoryId ? (
351+ { service . installCommand ? (
371352 < div style = { { display : 'contents' } } >
372- < strong > Clone Status </ strong >
353+ < strong > Install </ strong >
373354 < div style = { { display : 'flex' , alignItems : 'center' , gap : '8px' } } >
374- < span > { service . cloneStatus } </ span >
375- < Button
376- variant = "outlined"
377- size = "small"
378- loading = { actionInProgress === 'pull' }
379- disabled = { ! ! actionInProgress }
380- onclick = { ( ) => void runAction ( 'pull' , '/services/:id/pull' ) }
381- startIcon = { < Icon icon = { icons . download } size = "small" /> }
382- >
383- { service . cloneStatus === 'not-cloned' ? 'Clone' : 'Pull' }
384- </ Button >
355+ < span style = { { fontFamily : 'monospace' } } > { service . installCommand } </ span >
356+ < InstallStatusChip status = { service . installStatus } />
385357 </ div >
386- </ div >
387- ) : null }
388- < strong > Install Status</ strong >
389- < div style = { { display : 'flex' , alignItems : 'center' , gap : '8px' } } >
390- < span > { service . installStatus } </ span >
391- { service . installCommand ? (
392358 < Button
393359 variant = "outlined"
394360 size = "small"
@@ -399,12 +365,15 @@ export const ServiceDetail = Shade<ServiceDetailProps>({
399365 >
400366 Install
401367 </ Button >
402- ) : null }
403- </ div >
404- < strong > Build Status</ strong >
405- < div style = { { display : 'flex' , alignItems : 'center' , gap : '8px' } } >
406- < span > { service . buildStatus } </ span >
407- { service . buildCommand ? (
368+ </ div >
369+ ) : null }
370+ { service . buildCommand ? (
371+ < div style = { { display : 'contents' } } >
372+ < strong > Build</ strong >
373+ < div style = { { display : 'flex' , alignItems : 'center' , gap : '8px' } } >
374+ < span style = { { fontFamily : 'monospace' } } > { service . buildCommand } </ span >
375+ < BuildStatusChip status = { service . buildStatus } />
376+ </ div >
408377 < Button
409378 variant = "outlined"
410379 size = "small"
@@ -415,10 +384,37 @@ export const ServiceDetail = Shade<ServiceDetailProps>({
415384 >
416385 Build
417386 </ Button >
418- ) : null }
387+ </ div >
388+ ) : null }
389+ < strong > Run</ strong >
390+ < div style = { { display : 'flex' , alignItems : 'center' , gap : '8px' } } >
391+ < span style = { { fontFamily : 'monospace' } } > { service . runCommand } </ span >
392+ < RunStatusChip status = { service . runStatus } />
419393 </ div >
420- < strong > Run Status</ strong >
421- < span > { service . runStatus } </ span >
394+ { service . runStatus !== 'running' ? (
395+ < Button
396+ variant = "outlined"
397+ size = "small"
398+ color = "success"
399+ loading = { actionInProgress === 'start' }
400+ disabled = { ! ! actionInProgress }
401+ onclick = { ( ) => void runAction ( 'start' , '/services/:id/start' ) }
402+ startIcon = { < Icon icon = { icons . play } size = "small" /> }
403+ >
404+ Start
405+ </ Button >
406+ ) : (
407+ < Button
408+ variant = "outlined"
409+ size = "small"
410+ loading = { actionInProgress === 'stop' }
411+ disabled = { ! ! actionInProgress }
412+ onclick = { ( ) => void runAction ( 'stop' , '/services/:id/stop' ) }
413+ startIcon = { < Icon icon = { icons . stopCircle } size = "small" /> }
414+ >
415+ Stop
416+ </ Button >
417+ ) }
422418 </ div >
423419 </ Paper >
424420 < ServiceHistory serviceId = { service . id } />
0 commit comments