feat: push locally built image to docker registry
ui: fixes here and there
This commit is contained in:
parent
e33fec0e1a
commit
f88e3c5b29
@ -38,10 +38,10 @@ public function rollbackImage($commit)
|
||||
]);
|
||||
}
|
||||
|
||||
public function loadImages()
|
||||
public function loadImages($showToast = false)
|
||||
{
|
||||
try {
|
||||
$image = $this->application->uuid;
|
||||
$image = $this->application->docker_registry_image_name ?? $this->application->uuid;
|
||||
if ($this->application->destination->server->isFunctional()) {
|
||||
$output = instant_remote_process([
|
||||
"docker inspect --format='{{.Config.Image}}' {$this->application->uuid}",
|
||||
@ -66,6 +66,7 @@ public function loadImages()
|
||||
];
|
||||
})->toArray();
|
||||
}
|
||||
$showToast && $this->emit('success', 'Images loaded.');
|
||||
return [];
|
||||
} catch (\Throwable $e) {
|
||||
return handleError($e, $this);
|
||||
|
@ -24,6 +24,7 @@
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Str;
|
||||
use RuntimeException;
|
||||
use Spatie\Url\Url;
|
||||
use Symfony\Component\Yaml\Yaml;
|
||||
use Throwable;
|
||||
@ -197,6 +198,12 @@ public function handle(): void
|
||||
try {
|
||||
if ($this->restart_only && $this->application->build_pack !== 'dockerimage') {
|
||||
$this->just_restart();
|
||||
if ($this->server->isProxyShouldRun()) {
|
||||
dispatch(new ContainerStatusJob($this->server));
|
||||
}
|
||||
$this->next(ApplicationDeploymentStatus::FINISHED->value);
|
||||
$this->application->isConfigurationChanged(true);
|
||||
return;
|
||||
} else if ($this->application->dockerfile) {
|
||||
$this->deploy_simple_dockerfile();
|
||||
} else if ($this->application->build_pack === 'dockerimage') {
|
||||
@ -215,6 +222,9 @@ public function handle(): void
|
||||
if ($this->server->isProxyShouldRun()) {
|
||||
dispatch(new ContainerStatusJob($this->server));
|
||||
}
|
||||
if ($this->application->docker_registry_image_name) {
|
||||
$this->push_to_docker_registry();
|
||||
}
|
||||
$this->next(ApplicationDeploymentStatus::FINISHED->value);
|
||||
$this->application->isConfigurationChanged(true);
|
||||
} catch (Exception $e) {
|
||||
@ -255,7 +265,38 @@ public function handle(): void
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private function push_to_docker_registry()
|
||||
{
|
||||
try {
|
||||
instant_remote_process(["docker images --format '{{json .}}' {$this->production_image_name}"], $this->server);
|
||||
$this->execute_remote_command(
|
||||
[
|
||||
"echo '\n----------------------------------------'",
|
||||
],
|
||||
["echo -n 'Pushing image to docker registry ({$this->production_image_name}).'"],
|
||||
[
|
||||
executeInDocker($this->deployment_uuid, "docker push {$this->production_image_name}"), 'ignore_errors' => true, 'hidden' => true
|
||||
],
|
||||
);
|
||||
if ($this->application->docker_registry_image_tag) {
|
||||
// Tag image with latest
|
||||
$this->execute_remote_command(
|
||||
['echo -n "Tagging and pushing image with latest tag."'],
|
||||
[
|
||||
executeInDocker($this->deployment_uuid, "docker tag {$this->production_image_name} {$this->application->docker_registry_image_name}:{$this->application->docker_registry_image_tag}"), 'ignore_errors' => true, 'hidden' => true
|
||||
],
|
||||
[
|
||||
executeInDocker($this->deployment_uuid, "docker push {$this->application->docker_registry_image_name}:{$this->application->docker_registry_image_tag}"), 'ignore_errors' => true, 'hidden' => true
|
||||
],
|
||||
);
|
||||
}
|
||||
$this->execute_remote_command([
|
||||
"echo -n 'Image pushed to docker registry.'"
|
||||
]);
|
||||
} catch (Exception $e) {
|
||||
ray($e);
|
||||
}
|
||||
}
|
||||
// private function deploy_docker_compose()
|
||||
// {
|
||||
// $dockercompose_base64 = base64_encode($this->application->dockercompose);
|
||||
@ -303,12 +344,14 @@ private function generate_image_names()
|
||||
$this->build_image_name = Str::lower("{$this->application->uuid}:pr-{$this->pull_request_id}-build");
|
||||
$this->production_image_name = Str::lower("{$this->application->uuid}:pr-{$this->pull_request_id}");
|
||||
} else {
|
||||
$tag = Str::of("{$this->commit}-{$this->application->id}-{$this->pull_request_id}");
|
||||
if (strlen($tag) > 128) {
|
||||
$tag = $tag->substr(0, 128);
|
||||
$this->dockerImageTag = str($this->commit)->substr(0, 128);
|
||||
if ($this->application->docker_registry_image_name) {
|
||||
$this->build_image_name = Str::lower("{$this->application->docker_registry_image_name}:{$this->dockerImageTag}-build");
|
||||
$this->production_image_name = Str::lower("{$this->application->docker_registry_image_name}:{$this->dockerImageTag}");
|
||||
} else {
|
||||
$this->build_image_name = Str::lower("{$this->application->uuid}:{$this->dockerImageTag}-build");
|
||||
$this->production_image_name = Str::lower("{$this->application->uuid}:{$this->dockerImageTag}");
|
||||
}
|
||||
$this->build_image_name = Str::lower("{$this->application->uuid}:{$tag}-build");
|
||||
$this->production_image_name = Str::lower("{$this->application->uuid}:{$tag}");
|
||||
}
|
||||
}
|
||||
private function just_restart()
|
||||
@ -322,17 +365,29 @@ private function just_restart()
|
||||
$this->check_git_if_build_needed();
|
||||
$this->set_base_dir();
|
||||
$this->generate_image_names();
|
||||
$this->execute_remote_command([
|
||||
"docker images -q {$this->production_image_name} 2>/dev/null", "hidden" => true, "save" => "local_image_found"
|
||||
]);
|
||||
$this->check_image_locally_or_remotely();
|
||||
if (str($this->saved_outputs->get('local_image_found'))->isNotEmpty()) {
|
||||
$this->generate_compose_file();
|
||||
$this->rolling_update();
|
||||
return;
|
||||
}
|
||||
throw new RuntimeException('Cannot find image anywhere. Please redeploy the application.');
|
||||
}
|
||||
private function check_image_locally_or_remotely()
|
||||
{
|
||||
$this->execute_remote_command([
|
||||
"echo 'Cannot find image {$this->production_image_name} locally. Please redeploy the application.'",
|
||||
"docker images -q {$this->production_image_name} 2>/dev/null", "hidden" => true, "save" => "local_image_found"
|
||||
]);
|
||||
if (str($this->saved_outputs->get('local_image_found'))->isEmpty() && $this->application->docker_registry_image_name) {
|
||||
$this->execute_remote_command([
|
||||
"echo 'Cannot find image locally. Pulling from docker registry.'", 'type' => 'err'
|
||||
], [
|
||||
"docker pull {$this->production_image_name} 2>/dev/null", "ignore_errors" => true, "hidden" => true
|
||||
]);
|
||||
$this->execute_remote_command([
|
||||
"docker images -q {$this->production_image_name} 2>/dev/null", "hidden" => true, "save" => "local_image_found"
|
||||
]);
|
||||
}
|
||||
}
|
||||
private function save_environment_variables()
|
||||
{
|
||||
@ -419,12 +474,10 @@ private function deploy_nixpacks_buildpack()
|
||||
$this->set_base_dir();
|
||||
$this->generate_image_names();
|
||||
if (!$this->force_rebuild) {
|
||||
$this->execute_remote_command([
|
||||
"docker images -q {$this->production_image_name} 2>/dev/null", "hidden" => true, "save" => "local_image_found"
|
||||
]);
|
||||
if (Str::of($this->saved_outputs->get('local_image_found'))->isNotEmpty() && !$this->application->isConfigurationChanged()) {
|
||||
$this->check_image_locally_or_remotely();
|
||||
if (str($this->saved_outputs->get('local_image_found'))->isNotEmpty() && !$this->application->isConfigurationChanged()) {
|
||||
$this->execute_remote_command([
|
||||
"echo 'No configuration changed & Docker Image found locally with the same Git Commit SHA {$this->application->uuid}:{$this->commit}. Build step skipped.'",
|
||||
"echo 'No configuration changed & image found ({$this->production_image_name}) with the same Git Commit SHA. Build step skipped.'",
|
||||
]);
|
||||
$this->generate_compose_file();
|
||||
$this->rolling_update();
|
||||
@ -467,12 +520,18 @@ private function rolling_update()
|
||||
{
|
||||
if (count($this->application->ports_mappings_array) > 0) {
|
||||
$this->execute_remote_command(
|
||||
[
|
||||
"echo '\n----------------------------------------'",
|
||||
],
|
||||
["echo -n 'Application has ports mapped to the host system, rolling update is not supported.'"],
|
||||
);
|
||||
$this->stop_running_container(force: true);
|
||||
$this->start_by_compose_file();
|
||||
} else {
|
||||
$this->execute_remote_command(
|
||||
[
|
||||
"echo '\n----------------------------------------'",
|
||||
],
|
||||
["echo -n 'Rolling update started.'"],
|
||||
);
|
||||
$this->start_by_compose_file();
|
||||
@ -488,10 +547,10 @@ private function health_check()
|
||||
}
|
||||
// ray('New container name: ', $this->container_name);
|
||||
if ($this->container_name) {
|
||||
$counter = 0;
|
||||
$counter = 1;
|
||||
$this->execute_remote_command(
|
||||
[
|
||||
"echo 'Waiting for healthcheck to pass on the new version of your application.'"
|
||||
"echo 'Waiting for healthcheck to pass on the new container.'"
|
||||
]
|
||||
);
|
||||
if ($this->full_healthcheck_url) {
|
||||
@ -503,9 +562,6 @@ private function health_check()
|
||||
}
|
||||
while ($counter < $this->application->health_check_retries) {
|
||||
$this->execute_remote_command(
|
||||
[
|
||||
"echo 'Attempt {$counter} of {$this->application->health_check_retries}'"
|
||||
],
|
||||
[
|
||||
"docker inspect --format='{{json .State.Health.Status}}' {$this->container_name}",
|
||||
"hidden" => true,
|
||||
@ -515,17 +571,17 @@ private function health_check()
|
||||
);
|
||||
$this->execute_remote_command(
|
||||
[
|
||||
"echo 'New version healthcheck status: {$this->saved_outputs->get('health_check')}'"
|
||||
"echo 'Attempt {$counter} of {$this->application->health_check_retries} | Healthcheck status: {$this->saved_outputs->get('health_check')}'"
|
||||
],
|
||||
);
|
||||
if (Str::of($this->saved_outputs->get('health_check'))->contains('healthy')) {
|
||||
$this->newVersionIsHealthy = true;
|
||||
$this->application->update(['status' => 'running']);
|
||||
$this->execute_remote_command(
|
||||
[
|
||||
"echo 'Rolling update completed.'"
|
||||
"echo 'New container is healthy.'"
|
||||
],
|
||||
);
|
||||
$this->application->update(['status' => 'running']);
|
||||
break;
|
||||
}
|
||||
$counter++;
|
||||
@ -588,6 +644,7 @@ private function set_base_dir()
|
||||
[
|
||||
"echo -n 'Setting base directory to {$this->workdir}.'"
|
||||
],
|
||||
["echo '\n----------------------------------------'"]
|
||||
);
|
||||
}
|
||||
private function check_git_if_build_needed()
|
||||
@ -630,6 +687,9 @@ private function clone_repository()
|
||||
{
|
||||
$importCommands = $this->generate_git_import_commands();
|
||||
$this->execute_remote_command(
|
||||
[
|
||||
"echo '\n----------------------------------------'",
|
||||
],
|
||||
[
|
||||
"echo -n 'Importing {$this->customRepository}:{$this->application->git_branch} (commit sha {$this->application->git_commit_sha}) to {$this->basedir}. '"
|
||||
],
|
||||
@ -677,7 +737,7 @@ private function generate_git_import_commands()
|
||||
$this->fullRepoUrl = $this->customRepository;
|
||||
$private_key = data_get($this->application, 'private_key.private_key');
|
||||
if (is_null($private_key)) {
|
||||
throw new Exception('Private key not found. Please add a private key to the application and try again.');
|
||||
throw new RuntimeException('Private key not found. Please add a private key to the application and try again.');
|
||||
}
|
||||
$private_key = base64_encode($private_key);
|
||||
$git_clone_command_base = "GIT_SSH_COMMAND=\"ssh -o ConnectTimeout=30 -p {$this->customPort} -o Port={$this->customPort} -o LogLevel=ERROR -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -i /root/.ssh/id_rsa\" {$git_clone_command} {$this->customRepository} {$this->basedir}";
|
||||
@ -736,16 +796,10 @@ private function cleanup_git()
|
||||
|
||||
private function generate_nixpacks_confs()
|
||||
{
|
||||
|
||||
$this->execute_remote_command(
|
||||
[
|
||||
"echo -n 'Generating nixpacks configuration.'",
|
||||
]
|
||||
);
|
||||
$nixpacks_command = $this->nixpacks_build_cmd();
|
||||
$this->execute_remote_command(
|
||||
[
|
||||
"echo -n Running: $nixpacks_command",
|
||||
"echo -n 'Generating nixpacks configuration with: $nixpacks_command'",
|
||||
],
|
||||
[executeInDocker($this->deployment_uuid, $nixpacks_command)],
|
||||
[executeInDocker($this->deployment_uuid, "cp {$this->workdir}/.nixpacks/Dockerfile {$this->workdir}/Dockerfile")],
|
||||
@ -884,7 +938,6 @@ private function generate_compose_file()
|
||||
];
|
||||
if (data_get($this->application, 'settings.gpu_count')) {
|
||||
$count = data_get($this->application, 'settings.gpu_count');
|
||||
ray($count);
|
||||
if ($count === 'all') {
|
||||
$docker_compose['services'][$this->container_name]['deploy']['resources']['reservations']['devices'][0]['count'] = $count;
|
||||
} else {
|
||||
@ -912,7 +965,6 @@ private function generate_compose_file()
|
||||
// 'dockerfile' => $this->workdir . $this->dockerfile_location,
|
||||
// ];
|
||||
// }
|
||||
ray($docker_compose);
|
||||
$this->docker_compose = Yaml::dump($docker_compose, 10);
|
||||
$this->docker_compose_base64 = base64_encode($this->docker_compose);
|
||||
$this->execute_remote_command([executeInDocker($this->deployment_uuid, "echo '{$this->docker_compose_base64}' | base64 -d > {$this->workdir}/docker-compose.yml"), "hidden" => true]);
|
||||
@ -1021,9 +1073,12 @@ private function build_image()
|
||||
"echo -n 'Static deployment. Copying static assets to the image.'",
|
||||
]);
|
||||
} else {
|
||||
$this->execute_remote_command([
|
||||
"echo -n 'Building docker image for your application. To check the current progress, click on Show Debug Logs.'",
|
||||
]);
|
||||
$this->execute_remote_command(
|
||||
[
|
||||
"echo -n 'Building docker image started.'",
|
||||
],
|
||||
["echo -n 'To check the current progress, click on Show Debug Logs.'"]
|
||||
);
|
||||
}
|
||||
|
||||
if ($this->application->settings->is_static || $this->application->build_pack === 'static') {
|
||||
@ -1105,12 +1160,14 @@ private function build_image()
|
||||
]);
|
||||
}
|
||||
}
|
||||
$this->execute_remote_command([
|
||||
"echo -n 'Building docker image completed.'",
|
||||
]);
|
||||
}
|
||||
|
||||
private function stop_running_container(bool $force = false)
|
||||
{
|
||||
$this->execute_remote_command(["echo -n 'Removing old version of your application.'"]);
|
||||
|
||||
$this->execute_remote_command(["echo -n 'Removing old container.'"]);
|
||||
if ($this->newVersionIsHealthy || $force) {
|
||||
$containers = getCurrentApplicationContainerStatus($this->server, $this->application->id, $this->pull_request_id);
|
||||
if ($this->pull_request_id !== 0) {
|
||||
@ -1128,9 +1185,14 @@ private function stop_running_container(bool $force = false)
|
||||
[executeInDocker($this->deployment_uuid, "docker rm -f $containerName >/dev/null 2>&1"), "hidden" => true, "ignore_errors" => true],
|
||||
);
|
||||
});
|
||||
$this->execute_remote_command(
|
||||
[
|
||||
"echo 'Rolling update completed.'"
|
||||
],
|
||||
);
|
||||
} else {
|
||||
$this->execute_remote_command(
|
||||
["echo -n 'New version is not healthy, rolling back to the old version.'"],
|
||||
["echo -n 'New container is not healthy, rolling back to the old container.'"],
|
||||
[executeInDocker($this->deployment_uuid, "docker rm -f $this->container_name >/dev/null 2>&1"), "hidden" => true, "ignore_errors" => true],
|
||||
);
|
||||
}
|
||||
@ -1142,12 +1204,10 @@ private function start_by_compose_file()
|
||||
$this->execute_remote_command(
|
||||
["echo -n 'Pulling latest images from the registry.'"],
|
||||
[executeInDocker($this->deployment_uuid, "docker compose --project-directory {$this->workdir} pull"), "hidden" => true],
|
||||
["echo -n 'Starting application (could take a while).'"],
|
||||
[executeInDocker($this->deployment_uuid, "docker compose --project-directory {$this->workdir} up --build -d"), "hidden" => true],
|
||||
);
|
||||
} else {
|
||||
$this->execute_remote_command(
|
||||
["echo -n 'Starting application (could take a while).'"],
|
||||
[executeInDocker($this->deployment_uuid, "docker compose --project-directory {$this->workdir} up --build -d"), "hidden" => true],
|
||||
);
|
||||
}
|
||||
@ -1206,9 +1266,9 @@ private function next(string $status)
|
||||
public function failed(Throwable $exception): void
|
||||
{
|
||||
$this->execute_remote_command(
|
||||
["echo 'Oops something is not okay, are you okay? 😢'"],
|
||||
["echo '{$exception->getMessage()}'"],
|
||||
["echo -n 'Deployment failed. Removing the new version of your application.'"],
|
||||
["echo 'Oops something is not okay, are you okay? 😢'", 'type' => 'err'],
|
||||
["echo '{$exception->getMessage()}'", 'type' => 'err'],
|
||||
["echo -n 'Deployment failed. Removing the new version of your application.'", 'type' => 'err'],
|
||||
[executeInDocker($this->deployment_uuid, "docker rm -f $this->container_name >/dev/null 2>&1"), "hidden" => true, "ignore_errors" => true]
|
||||
);
|
||||
|
||||
|
@ -32,16 +32,20 @@ public function execute_remote_command(...$commands)
|
||||
throw new \RuntimeException('Command is not set');
|
||||
}
|
||||
$hidden = data_get($single_command, 'hidden', false);
|
||||
$customType = data_get($single_command, 'type');
|
||||
$ignore_errors = data_get($single_command, 'ignore_errors', false);
|
||||
$this->save = data_get($single_command, 'save');
|
||||
|
||||
$remote_command = generateSshCommand($this->server, $command);
|
||||
$process = Process::timeout(3600)->idleTimeout(3600)->start($remote_command, function (string $type, string $output) use ($command, $hidden) {
|
||||
$process = Process::timeout(3600)->idleTimeout(3600)->start($remote_command, function (string $type, string $output) use ($command, $hidden, $customType) {
|
||||
$output = Str::of($output)->trim();
|
||||
if ($output->startsWith('╔')) {
|
||||
$output = "\n" . $output;
|
||||
}
|
||||
$new_log_entry = [
|
||||
'command' => $command,
|
||||
'output' => $output,
|
||||
'type' => $type === 'err' ? 'stderr' : 'stdout',
|
||||
'command' => remove_iip($command),
|
||||
'output' => remove_iip($output),
|
||||
'type' => $customType ?? $type === 'err' ? 'stderr' : 'stdout',
|
||||
'timestamp' => Carbon::now('UTC'),
|
||||
'hidden' => $hidden,
|
||||
'batch' => static::$batch_counter,
|
||||
|
@ -1,5 +1,6 @@
|
||||
<?php
|
||||
|
||||
const REDACTED = '<REDACTED>';
|
||||
const DATABASE_TYPES = ['postgresql', 'redis', 'mongodb', 'mysql', 'mariadb'];
|
||||
const VALID_CRON_STRINGS = [
|
||||
'every_minute' => '* * * * *',
|
||||
|
@ -170,10 +170,13 @@ function decode_remote_command_output(?ApplicationDeploymentQueue $application_d
|
||||
$i['timestamp'] = Carbon::parse($i['timestamp'])->format('Y-M-d H:i:s.u');
|
||||
return $i;
|
||||
});
|
||||
|
||||
return $formatted;
|
||||
}
|
||||
|
||||
function remove_iip($text)
|
||||
{
|
||||
$text = preg_replace('/x-access-token:.*?(?=@)/', "x-access-token:" . REDACTED, $text);
|
||||
return preg_replace('/\x1b\[[0-9;]*m/', '', $text);
|
||||
}
|
||||
function refresh_server_connection(?PrivateKey $private_key = null)
|
||||
{
|
||||
if (is_null($private_key)) {
|
||||
|
@ -48,9 +48,8 @@ class="fixed top-4 right-16" x-on:click="toggleScroll"><svg class="icon" viewBox
|
||||
@foreach (decode_remote_command_output($application_deployment_queue) as $line)
|
||||
<div @class([
|
||||
'font-mono whitespace-pre-line',
|
||||
'text-white' => $line['type'] == 'stdout',
|
||||
'text-error' => $line['type'] == 'stderr',
|
||||
'text-warning' => $line['hidden'],
|
||||
'text-error' => $line['type'] == 'stderr',
|
||||
])>[{{ $line['timestamp'] }}] @if ($line['hidden'])
|
||||
<br>COMMAND: <br>{{ $line['command'] }} <br><br>OUTPUT:
|
||||
@endif{{ $line['output'] }}@if ($line['hidden'])
|
||||
|
@ -40,12 +40,33 @@
|
||||
</div>
|
||||
@if ($application->could_set_build_commands())
|
||||
<div class="w-64">
|
||||
<x-forms.checkbox instantSave id="application.settings.is_static" label="Is it a static site?"
|
||||
<x-forms.checkbox instantSave id="application.settings.is_static"
|
||||
label="Is it a static site?"
|
||||
helper="If your application is a static site or the final build assets should be served as a static site, enable this." />
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
@endif
|
||||
<h3>Docker Registry</h3>
|
||||
@if ($application->build_pack !== 'dockerimage')
|
||||
<div>Push the built image to a docker registry. More info <a class="underline"
|
||||
href="https://coolify.io/docs/" target="_blank">here</a>.</div>
|
||||
@endif
|
||||
<div class="flex flex-col gap-2 xl:flex-row">
|
||||
@if ($application->build_pack === 'dockerimage')
|
||||
<x-forms.input id="application.docker_registry_image_name" label="Docker Image" />
|
||||
<x-forms.input id="application.docker_registry_image_tag" label="Docker Image Tag" />
|
||||
@else
|
||||
<x-forms.input id="application.docker_registry_image_name"
|
||||
helper="Empty means it won't push the image to a docker registry."
|
||||
placeholder="Empty means it won't push the image to a docker registry." label="Docker Image" />
|
||||
<x-forms.input id="application.docker_registry_image_tag"
|
||||
placeholder="Empty means only push commit sha tag."
|
||||
helper="If set, it will tag the built image with this tag too. <br><br>Example: If you set it to 'latest', it will push the image with the commit sha tag + with the latest tag."
|
||||
label="Docker Image Tag" />
|
||||
@endif
|
||||
|
||||
</div>
|
||||
|
||||
@if ($application->build_pack !== 'dockerimage')
|
||||
<h3>Build</h3>
|
||||
@ -64,8 +85,6 @@
|
||||
</div>
|
||||
@endif
|
||||
@endif
|
||||
|
||||
|
||||
<div class="flex flex-col gap-2 xl:flex-row">
|
||||
<x-forms.input placeholder="/" id="application.base_directory" label="Base Directory"
|
||||
helper="Directory to use as root. Useful for monorepos." />
|
||||
@ -88,11 +107,6 @@
|
||||
@endif
|
||||
@endif
|
||||
</div>
|
||||
@else
|
||||
<div class="flex flex-col gap-2 xl:flex-row">
|
||||
<x-forms.input id="application.docker_registry_image_name" label="Docker Image" />
|
||||
<x-forms.input id="application.docker_registry_image_tag" label="Docker Image Tag" />
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@if ($application->dockerfile)
|
||||
|
@ -1,12 +1,12 @@
|
||||
<div x-init="$wire.loadImages">
|
||||
<div class="flex items-center gap-2">
|
||||
<h2>Rollback</h2>
|
||||
<x-forms.button wire:click='loadImages'>Reload Available Images</x-forms.button>
|
||||
<x-forms.button wire:click='loadImages(true)'>Reload Available Images</x-forms.button>
|
||||
</div>
|
||||
<div class="pb-4 ">You can easily rollback to a previously built image quickly.</div>
|
||||
<div class="pb-4 ">You can easily rollback to a previously built <span class="text-warning">(local)</span> images quickly.</div>
|
||||
<div wire:target='loadImages'>
|
||||
<div class="flex flex-wrap">
|
||||
@foreach ($images as $image)
|
||||
@forelse ($images as $image)
|
||||
<div class="w-2/4 p-2">
|
||||
<div class="rounded shadow-lg bg-coolgray-200">
|
||||
<div class="p-2">
|
||||
@ -25,14 +25,16 @@
|
||||
Rollback
|
||||
</x-forms.button>
|
||||
@else
|
||||
<x-forms.button wire:click="rollbackImage('{{ data_get($image, 'tag') }}')">
|
||||
<x-forms.button class="bg-coolgray-100" wire:click="rollbackImage('{{ data_get($image, 'tag') }}')">
|
||||
Rollback
|
||||
</x-forms.button>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endforeach
|
||||
@empty
|
||||
<div>No images found locally.</div>
|
||||
@endforelse
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -36,7 +36,7 @@
|
||||
@endif
|
||||
@if ($application->build_pack !== 'static')
|
||||
<a :class="activeTab === 'health' && 'text-white'"
|
||||
@click.prevent="activeTab = 'health'; window.location.hash = 'health'" href="#">Health Checks
|
||||
@click.prevent="activeTab = 'health'; window.location.hash = 'health'" href="#">Healthchecks
|
||||
</a>
|
||||
@endif
|
||||
<a :class="activeTab === 'rollback' && 'text-white'"
|
||||
|
Loading…
Reference in New Issue
Block a user