2026-08-16 18:54:50 +00:00
< nav wire : poll . 10000 ms = " checkStatus " class = " w-full max-w-none pb-4 md:pb-6 lg:pb-0 " >
2026-06-05 12:57:57 +00:00
@ php
2026-08-03 21:11:54 +00:00
$routeIs = fn ( string | array $routes ) : bool => \Illuminate\Support\Str :: is ( $routes , $activeRouteName );
2026-08-05 11:50:11 +00:00
// Settings covers all configuration sub-pages (General, Webhooks, Domains, …),
// not only project.application.configuration. Primary tabs that are NOT settings:
// backups, console, deployment logs, runtime logs.
$isSettingsRoute = $routeIs ( 'project.application.*' )
&& ! $routeIs ([
'project.application.backup.*' ,
'project.application.command' ,
'project.application.deployment.*' ,
'project.application.logs' ,
]);
2026-06-05 12:57:57 +00:00
$applicationMenuItems = [
[
2026-08-03 21:11:54 +00:00
'label' => 'Settings' ,
2026-06-05 12:57:57 +00:00
'route' => 'project.application.configuration' ,
2026-08-05 11:50:11 +00:00
'active' => $isSettingsRoute ,
2026-06-05 12:57:57 +00:00
],
];
$applicationMenuItems = array_values ( array_filter (
$applicationMenuItems ,
fn ( array $item ) : bool => $item [ 'visible' ] ? ? true ,
));
@ endphp
2026-08-03 21:11:54 +00:00
< div >
2026-08-05 15:56:59 +00:00
< div class = " mb-3 w-full xl:hidden " >
2026-08-06 19:29:26 +00:00
< div class = " flex min-w-0 flex-col items-start gap-2 " >
< h1 class = " min-w-0 max-w-full truncate text-[24px]! leading-7! font-semibold! tracking-tight! text-black dark:text-fg " >
2026-08-03 21:11:54 +00:00
{{ $application -> name }}
</ h1 >
2026-08-15 12:04:09 +00:00
< div class = " relative flex w-full min-w-0 items-center gap-2 " >
< x - status - summary : status = " $application->status " />
< x - applications . links : application = " $application " compact />
</ div >
2026-08-31 11:13:26 +00:00
< div class = " flex w-full flex-wrap gap-1 " >
< x - application . restart - limit - warning : application = " $application " />
</ div >
2026-08-03 21:11:54 +00:00
</ div >
</ div >
2026-08-05 15:56:59 +00:00
< div class = " w-full xl:hidden " >
2026-06-12 14:09:26 +00:00
@ if ( ! ( $application -> build_pack === 'dockercompose' && is_null ( $application -> docker_compose_raw )))
2026-08-18 08:18:52 +00:00
@ can ( 'deploy' , $application )
2026-08-03 21:11:54 +00:00
< div id = " application-mobile-actions " class = " relative mb-3 "
x - data = " { open: false } " @ click . outside = " open = false "
@ keydown . escape . window = " open = false " >
< button type = " button " class = " button w-full justify-between " @ click = " open = !open "
: aria - expanded = " open " aria - haspopup = " menu " >
< span class = " inline-flex items-center gap-2 " >
Actions
</ span >
< span class = " inline-flex transition-transform " : class = " open && 'rotate-180' " >
< x - reicon name = " chevron-down " class = " size-3 opacity-55 " />
</ span >
</ button >
< div x - cloak x - show = " open " x - transition . origin . top . left
class = " listbox-panel top-full! left-0! right-0! mt-1! w-full! min-w-0! " role = " menu " >
@ if ( ! str ( $application -> status ) -> startsWith ( 'exited' ))
@ if ( ! $application -> destination -> server -> isSwarm ())
@ can ( 'deploy' , $application )
< button type = " button " class = " listbox-option justify-start! gap-2.5! "
wire : click = " deploy " @ click = " open = false " role = " menuitem " >
2026-08-06 16:15:58 +00:00
< x - reicon name = " refresh " class = " size-3.5 opacity-70 " />
2026-08-13 10:17:16 +00:00
Deploy
2026-08-03 21:11:54 +00:00
</ button >
@ else
< button type = " button " class = " listbox-option justify-start! gap-2.5! " disabled
role = " menuitem " >
< x - reicon name = " refresh " class = " size-3.5 opacity-70 " />
2026-08-13 10:17:16 +00:00
Deploy
2026-08-03 21:11:54 +00:00
</ button >
@ endcan
@ endif
@ if ( $application -> build_pack !== 'dockercompose' )
@ if ( $application -> destination -> server -> isSwarm ())
@ can ( 'deploy' , $application )
< button type = " button " class = " listbox-option justify-start! gap-2.5! "
wire : click = " deploy " @ click = " open = false " role = " menuitem " >
2026-08-06 16:15:58 +00:00
< x - reicon name = " refresh " class = " size-3.5 opacity-70 " />
2026-08-03 21:11:54 +00:00
Update Service
</ button >
@ else
< button type = " button " class = " listbox-option justify-start! gap-2.5! " disabled
role = " menuitem " >
< x - reicon name = " refresh " class = " size-3.5 opacity-70 " />
Update Service
</ button >
@ endcan
@ else
@ can ( 'deploy' , $application )
< button type = " button " class = " listbox-option justify-start! gap-2.5! "
@ click = " open = false; document.getElementById('application-mobile-restart-trigger')?.click() "
role = " menuitem " >
2026-08-06 16:15:58 +00:00
< x - reicon name = " restart " class = " size-3.5 opacity-70 " />
2026-08-03 21:11:54 +00:00
Restart
</ button >
@ else
< button type = " button " class = " listbox-option justify-start! gap-2.5! " disabled
role = " menuitem " >
< x - reicon name = " restart " class = " size-3.5 opacity-70 " />
Restart
</ button >
@ endcan
@ endif
@ endif
2026-06-12 14:09:26 +00:00
@ else
2026-08-03 21:11:54 +00:00
@ can ( 'deploy' , $application )
< button type = " button " class = " listbox-option justify-start! gap-2.5! "
wire : click = " deploy " @ click = " open = false " role = " menuitem " >
2026-08-06 16:15:58 +00:00
< x - reicon name = " play-circle " class = " size-3.5 opacity-70 " />
2026-08-31 11:13:26 +00:00
{{ $application -> stoppedAfterRestartLimit () ? 'Retry deployment' : 'Deploy' }}
2026-08-03 21:11:54 +00:00
</ button >
@ else
< button type = " button " class = " listbox-option justify-start! gap-2.5! " disabled
role = " menuitem " >
< x - reicon name = " play-circle " class = " size-3.5 opacity-70 " />
2026-08-31 11:13:26 +00:00
{{ $application -> stoppedAfterRestartLimit () ? 'Retry deployment' : 'Deploy' }}
2026-08-03 21:11:54 +00:00
</ button >
@ endcan
@ endif
@ if ( ! $application -> destination -> server -> isSwarm ())
@ can ( 'deploy' , $application )
< button type = " button " class = " listbox-option justify-start! gap-2.5! "
wire : click = " { { $application->status === 'running' ? 'force_deploy_without_cache' : 'deploy(true)' }} "
@ click = " open = false " role = " menuitem " >
< x - reicon name = " refresh " class = " size-3.5 opacity-70 " />
2026-08-31 11:13:26 +00:00
{{ $application -> stoppedAfterRestartLimit () ? 'Retry deployment (without cache)' : 'Deploy (without cache)' }}
2026-08-03 21:11:54 +00:00
</ button >
@ else
< button type = " button " class = " listbox-option justify-start! gap-2.5! " disabled
role = " menuitem " >
< x - reicon name = " refresh " class = " size-3.5 opacity-70 " />
2026-08-31 11:13:26 +00:00
{{ $application -> stoppedAfterRestartLimit () ? 'Retry deployment (without cache)' : 'Deploy (without cache)' }}
2026-08-03 21:11:54 +00:00
</ button >
@ endcan
2026-06-12 14:09:26 +00:00
@ endif
2026-08-31 11:13:26 +00:00
@ if ( ! str ( $application -> status ) -> startsWith ( 'exited' ) || $application -> container_present !== false )
< button type = " button " class = " listbox-option justify-start! gap-2.5! "
@ click = " open = false; document.getElementById('application-mobile-stop-trigger')?.click() "
role = " menuitem " >
< x - reicon name = " stop-circle " class = " size-3.5 text-error " />
{{ str ( $application -> status ) -> startsWith ( 'exited' ) ? 'Remove container' : 'Stop' }}
</ button >
@ endif
2026-06-12 14:09:26 +00:00
</ div >
</ div >
2026-08-18 08:18:52 +00:00
@ endcan
2026-06-12 14:09:26 +00:00
@ endif
2026-08-03 21:11:54 +00:00
< div class = " hidden " aria - hidden = " true " >
2026-08-31 11:13:26 +00:00
< x - modal - confirmation
canGate = " deploy " : canResource = " $application "
title = " { { str( $application->status )->startsWith('exited') ? 'Confirm Container Removal?' : 'Confirm Application Stopping?' }} "
buttonTitle = " { { str( $application->status )->startsWith('exited') ? 'Remove container' : 'Stop' }} "
2026-08-03 21:11:54 +00:00
submitAction = " stop " : checkboxes = " $checkboxes " : actions = " [
2026-08-31 11:13:26 +00:00
str ( $application -> status ) -> startsWith ( 'exited' ) ? 'The exited application container will be removed.' : 'This application will be stopped.' ,
str ( $application -> status ) -> startsWith ( 'exited' ) ? 'Anonymous volumes may become eligible for Docker cleanup.' : 'All non-persistent data of this application will be deleted.' ,
2026-08-03 21:11:54 +00:00
] " :confirmWithText= " false " :confirmWithPassword= " false "
step1ButtonText = " Continue " step2ButtonText = " Confirm " >
< x - slot : trigger >
< button id = " application-mobile-stop-trigger " type = " button " > Stop </ button >
</ x - slot : trigger >
</ x - modal - confirmation >
< x - modal - confirmation title = " Confirm Application Restart? " buttonTitle = " Restart "
submitAction = " restart " : actions = " [
'This application will be restarted without rebuilding.' ,
] " :confirmWithText= " false " :confirmWithPassword= " false "
step2ButtonText = " Confirm " >
< x - slot : trigger >
< button id = " application-mobile-restart-trigger " type = " button " > Restart </ button >
</ x - slot : trigger >
</ x - modal - confirmation >
</ div >
2026-06-05 12:57:57 +00:00
</ div >
2026-08-05 18:17:21 +00:00
{{ -- Desktop actions live in the fixed top bar so they cannot overlap page content . -- }}
@ teleport ( '#resource-action-hud-slot' )
< div class = " hidden w-full items-center xl:flex xl:w-auto " >
2026-08-03 21:11:54 +00:00
< div
2026-08-05 18:17:21 +00:00
class = " resource-heading-navbar application-heading-actions flex w-full min-w-0 items-center justify-start gap-1 overflow-visible xl:w-auto xl:justify-end " >
2026-08-05 15:56:59 +00:00
< div class = " resource-heading-actions flex shrink-0 items-center gap-0.5 " >
2026-08-03 21:11:54 +00:00
@ if ( $application -> build_pack === 'dockercompose' && is_null ( $application -> docker_compose_raw ))
< span class = " px-2 text-[13px] text-neutral-500 dark:text-fg-dim " > Load a Compose file to deploy .</ span >
@ else
2026-08-05 15:56:59 +00:00
< div class = " resource-heading-menus shrink-0 " >
< x - applications . links : application = " $application " />
</ div >
2026-08-18 08:18:52 +00:00
@ can ( 'deploy' , $application )
2026-08-13 12:08:33 +00:00
< div id = " application-desktop-actions " class = " relative " x - data = " { open: false } "
x - effect = " $dispatch ('resource-actions-toggled', { open }) "
@ click . outside = " open = false " @ keydown . escape . window = " open = false " >
< button type = " button " class = " button button-highlighted " @ click = " open = !open " : aria - expanded = " open "
aria - haspopup = " menu " >
Actions
< x - reicon name = " chevron-down " class = " size-3 opacity-55 " />
</ button >
< div x - cloak x - show = " open " x - transition . origin . top . right
class = " listbox-panel top-full! right-0! left-auto! mt-1! w-60! min-w-0! " role = " menu " >
@ if ( str ( $application -> status ) -> startsWith ( 'exited' ))
< button type = " button " class = " listbox-option justify-start! gap-2.5! "
@ disabled ( ! auth () -> user () -> can ( 'deploy' , $application ))
wire : click = " deploy " @ click = " open = false " role = " menuitem " >
< x - reicon name = " play-circle " class = " size-3.5 opacity-70 " />
2026-08-31 11:13:26 +00:00
{{ $application -> stoppedAfterRestartLimit () ? 'Retry deployment' : 'Deploy' }}
2026-08-13 12:08:33 +00:00
</ button >
@ if ( ! $application -> destination -> server -> isSwarm ())
< button type = " button " class = " listbox-option justify-start! gap-2.5! "
@ disabled ( ! auth () -> user () -> can ( 'deploy' , $application ))
wire : click = " deploy(true) " @ click = " open = false " role = " menuitem " >
< x - reicon name = " refresh " class = " size-3.5 opacity-70 " />
2026-08-31 11:13:26 +00:00
{{ $application -> stoppedAfterRestartLimit () ? 'Retry deployment (without cache)' : 'Deploy (without cache)' }}
</ button >
@ endif
@ if ( $application -> container_present !== false )
< button type = " button " class = " listbox-option justify-start! gap-2.5! "
@ click = " open = false; document.getElementById('application-mobile-stop-trigger')?.click() "
role = " menuitem " >
< x - reicon name = " stop-circle " class = " size-3.5 text-error " />
Remove container
2026-08-13 12:08:33 +00:00
</ button >
@ endif
@ else
@ if ( ! $application -> destination -> server -> isSwarm ())
@ can ( 'deploy' , $application )
< button type = " button " class = " listbox-option justify-start! gap-2.5! "
wire : click = " deploy " @ click = " open = false " role = " menuitem " >
< x - reicon name = " refresh " class = " size-3.5 opacity-70 " />
Redeploy
</ button >
@ else
< button type = " button " class = " listbox-option justify-start! gap-2.5! " disabled >
< x - reicon name = " refresh " class = " size-3.5 opacity-70 " />
Redeploy
</ button >
@ endcan
< button type = " button " class = " listbox-option justify-start! gap-2.5! "
@ disabled ( ! auth () -> user () -> can ( 'deploy' , $application ))
wire : click = " { { str( $application->status )->startsWith('running') ? 'force_deploy_without_cache' : 'deploy(true)' }} "
@ click = " open = false " role = " menuitem " >
< x - reicon name = " refresh " class = " size-3.5 opacity-70 " />
{{ str ( $application -> status ) -> startsWith ( 'running' ) ? 'Redeploy (without cache)' : 'Deploy (without cache)' }}
</ button >
@ endif
@ if ( $application -> build_pack !== 'dockercompose' )
@ if ( $application -> destination -> server -> isSwarm ())
@ can ( 'deploy' , $application )
< button type = " button " class = " listbox-option justify-start! gap-2.5! "
wire : click = " deploy " @ click = " open = false " role = " menuitem " >
< x - reicon name = " refresh " class = " size-3.5 opacity-70 " />
Update Service
</ button >
@ else
< button type = " button " class = " listbox-option justify-start! gap-2.5! " disabled >
< x - reicon name = " refresh " class = " size-3.5 opacity-70 " />
Update Service
</ button >
@ endcan
@ else
@ can ( 'deploy' , $application )
< button type = " button " class = " listbox-option justify-start! gap-2.5! "
@ click = " open = false; document.getElementById('application-mobile-restart-trigger')?.click() "
role = " menuitem " >
< x - reicon name = " restart " class = " size-3.5 opacity-70 " />
Restart
</ button >
@ else
< button type = " button " class = " listbox-option justify-start! gap-2.5! " disabled >
< x - reicon name = " restart " class = " size-3.5 opacity-70 " />
Restart
</ button >
@ endcan
@ endif
@ endif
2026-08-05 15:56:59 +00:00
@ can ( 'deploy' , $application )
2026-08-13 12:08:33 +00:00
< button type = " button " class = " listbox-option justify-start! gap-2.5! "
@ click = " open = false; document.getElementById('application-mobile-stop-trigger')?.click() "
role = " menuitem " >
< x - reicon name = " stop-circle " class = " size-3.5 text-error " />
Stop
2026-08-05 15:56:59 +00:00
</ button >
@ else
2026-08-13 12:08:33 +00:00
< button type = " button " class = " listbox-option justify-start! gap-2.5! " disabled >
< x - reicon name = " stop-circle " class = " size-3.5 opacity-70 " />
Stop
2026-08-05 15:56:59 +00:00
</ button >
@ endcan
2026-08-11 09:28:46 +00:00
@ endif
2026-08-13 12:08:33 +00:00
</ div >
</ div >
2026-08-18 08:18:52 +00:00
@ endcan
2026-08-03 21:11:54 +00:00
@ endif
2024-04-16 11:14:09 +00:00
</ div >
2026-08-03 21:11:54 +00:00
</ div >
2024-04-16 11:14:09 +00:00
</ div >
2026-08-05 18:17:21 +00:00
@ endteleport
2024-01-16 14:19:14 +00:00
</ div >
2023-06-30 08:49:00 +00:00
</ nav >