mirror of
https://github.com/ershisan99/coolify.git
synced 2026-01-03 20:52:06 +00:00
Compare commits
15 Commits
v4.0.0-bet
...
v4.0.0-bet
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0f99ee787c | ||
|
|
95777e978e | ||
|
|
fb0b9dbfed | ||
|
|
9617000daa | ||
|
|
1818404172 | ||
|
|
d9a966fd98 | ||
|
|
763ce5fc14 | ||
|
|
df021760a7 | ||
|
|
fb2598f2e4 | ||
|
|
7af07b2718 | ||
|
|
23a94c9378 | ||
|
|
ed34fc9645 | ||
|
|
cafd9e0ab2 | ||
|
|
e882477e21 | ||
|
|
db0e3cfcc4 |
@@ -21,26 +21,33 @@ class StartDatabaseProxy
|
|||||||
$type = $database->getMorphClass();
|
$type = $database->getMorphClass();
|
||||||
$network = data_get($database, 'destination.network');
|
$network = data_get($database, 'destination.network');
|
||||||
$server = data_get($database, 'destination.server');
|
$server = data_get($database, 'destination.server');
|
||||||
|
$containerName = data_get($database, 'uuid');
|
||||||
|
$proxyContainerName = "{$database->uuid}-proxy";
|
||||||
if ($database->getMorphClass() === 'App\Models\ServiceDatabase') {
|
if ($database->getMorphClass() === 'App\Models\ServiceDatabase') {
|
||||||
$databaseType = $database->databaseType();
|
$databaseType = $database->databaseType();
|
||||||
$network = data_get($database, 'service.destination.network');
|
$network = data_get($database, 'service.destination.network');
|
||||||
$server = data_get($database, 'service.destination.server');
|
$server = data_get($database, 'service.destination.server');
|
||||||
ray($databaseType, $network);
|
$proxyContainerName = "{$database->service->uuid}-proxy";
|
||||||
switch ($databaseType) {
|
switch ($databaseType) {
|
||||||
case 'standalone-mariadb':
|
case 'standalone-mariadb':
|
||||||
$type = 'App\Models\StandaloneMariadb';
|
$type = 'App\Models\StandaloneMariadb';
|
||||||
|
$containerName = "mariadb-{$database->service->uuid}";
|
||||||
break;
|
break;
|
||||||
case 'standalone-mongodb':
|
case 'standalone-mongodb':
|
||||||
$type = 'App\Models\StandaloneMongodb';
|
$type = 'App\Models\StandaloneMongodb';
|
||||||
|
$containerName = "mongodb-{$database->service->uuid}";
|
||||||
break;
|
break;
|
||||||
case 'standalone-mysql':
|
case 'standalone-mysql':
|
||||||
$type = 'App\Models\StandaloneMysql';
|
$type = 'App\Models\StandaloneMysql';
|
||||||
|
$containerName = "mysql-{$database->service->uuid}";
|
||||||
break;
|
break;
|
||||||
case 'standalone-postgresql':
|
case 'standalone-postgresql':
|
||||||
$type = 'App\Models\StandalonePostgresql';
|
$type = 'App\Models\StandalonePostgresql';
|
||||||
|
$containerName = "postgresql-{$database->service->uuid}";
|
||||||
break;
|
break;
|
||||||
case 'standalone-redis':
|
case 'standalone-redis':
|
||||||
$type = 'App\Models\StandaloneRedis';
|
$type = 'App\Models\StandaloneRedis';
|
||||||
|
$containerName = "redis-{$database->service->uuid}";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -55,7 +62,6 @@ class StartDatabaseProxy
|
|||||||
} else if ($type === 'App\Models\StandaloneMariadb') {
|
} else if ($type === 'App\Models\StandaloneMariadb') {
|
||||||
$internalPort = 3306;
|
$internalPort = 3306;
|
||||||
}
|
}
|
||||||
$containerName = "{$database->uuid}-proxy";
|
|
||||||
$configuration_dir = database_proxy_dir($database->uuid);
|
$configuration_dir = database_proxy_dir($database->uuid);
|
||||||
$nginxconf = <<<EOF
|
$nginxconf = <<<EOF
|
||||||
user nginx;
|
user nginx;
|
||||||
@@ -69,7 +75,7 @@ class StartDatabaseProxy
|
|||||||
stream {
|
stream {
|
||||||
server {
|
server {
|
||||||
listen $database->public_port;
|
listen $database->public_port;
|
||||||
proxy_pass $database->uuid:$internalPort;
|
proxy_pass $containerName:$internalPort;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
EOF;
|
EOF;
|
||||||
@@ -81,13 +87,13 @@ class StartDatabaseProxy
|
|||||||
$docker_compose = [
|
$docker_compose = [
|
||||||
'version' => '3.8',
|
'version' => '3.8',
|
||||||
'services' => [
|
'services' => [
|
||||||
$containerName => [
|
$proxyContainerName => [
|
||||||
'build' => [
|
'build' => [
|
||||||
'context' => $configuration_dir,
|
'context' => $configuration_dir,
|
||||||
'dockerfile' => 'Dockerfile',
|
'dockerfile' => 'Dockerfile',
|
||||||
],
|
],
|
||||||
'image' => "nginx:stable-alpine",
|
'image' => "nginx:stable-alpine",
|
||||||
'container_name' => $containerName,
|
'container_name' => $proxyContainerName,
|
||||||
'restart' => RESTART_MODE,
|
'restart' => RESTART_MODE,
|
||||||
'ports' => [
|
'ports' => [
|
||||||
"$database->public_port:$database->public_port",
|
"$database->public_port:$database->public_port",
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ class StartMariadb
|
|||||||
'memswap_limit' => $this->database->limits_memory_swap,
|
'memswap_limit' => $this->database->limits_memory_swap,
|
||||||
'mem_swappiness' => $this->database->limits_memory_swappiness,
|
'mem_swappiness' => $this->database->limits_memory_swappiness,
|
||||||
'mem_reservation' => $this->database->limits_memory_reservation,
|
'mem_reservation' => $this->database->limits_memory_reservation,
|
||||||
'cpus' => $this->database->limits_cpus,
|
'cpus' => (int) $this->database->limits_cpus,
|
||||||
'cpuset' => $this->database->limits_cpuset,
|
'cpuset' => $this->database->limits_cpuset,
|
||||||
'cpu_shares' => $this->database->limits_cpu_shares,
|
'cpu_shares' => $this->database->limits_cpu_shares,
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ class StartMongodb
|
|||||||
'memswap_limit' => $this->database->limits_memory_swap,
|
'memswap_limit' => $this->database->limits_memory_swap,
|
||||||
'mem_swappiness' => $this->database->limits_memory_swappiness,
|
'mem_swappiness' => $this->database->limits_memory_swappiness,
|
||||||
'mem_reservation' => $this->database->limits_memory_reservation,
|
'mem_reservation' => $this->database->limits_memory_reservation,
|
||||||
'cpus' => $this->database->limits_cpus,
|
'cpus' => (int) $this->database->limits_cpus,
|
||||||
'cpuset' => $this->database->limits_cpuset,
|
'cpuset' => $this->database->limits_cpuset,
|
||||||
'cpu_shares' => $this->database->limits_cpu_shares,
|
'cpu_shares' => $this->database->limits_cpu_shares,
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ class StartMysql
|
|||||||
'memswap_limit' => $this->database->limits_memory_swap,
|
'memswap_limit' => $this->database->limits_memory_swap,
|
||||||
'mem_swappiness' => $this->database->limits_memory_swappiness,
|
'mem_swappiness' => $this->database->limits_memory_swappiness,
|
||||||
'mem_reservation' => $this->database->limits_memory_reservation,
|
'mem_reservation' => $this->database->limits_memory_reservation,
|
||||||
'cpus' => $this->database->limits_cpus,
|
'cpus' => (int) $this->database->limits_cpus,
|
||||||
'cpuset' => $this->database->limits_cpuset,
|
'cpuset' => $this->database->limits_cpuset,
|
||||||
'cpu_shares' => $this->database->limits_cpu_shares,
|
'cpu_shares' => $this->database->limits_cpu_shares,
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ class StartPostgresql
|
|||||||
'memswap_limit' => $this->database->limits_memory_swap,
|
'memswap_limit' => $this->database->limits_memory_swap,
|
||||||
'mem_swappiness' => $this->database->limits_memory_swappiness,
|
'mem_swappiness' => $this->database->limits_memory_swappiness,
|
||||||
'mem_reservation' => $this->database->limits_memory_reservation,
|
'mem_reservation' => $this->database->limits_memory_reservation,
|
||||||
'cpus' => $this->database->limits_cpus,
|
'cpus' => (int) $this->database->limits_cpus,
|
||||||
'cpuset' => $this->database->limits_cpuset,
|
'cpuset' => $this->database->limits_cpuset,
|
||||||
'cpu_shares' => $this->database->limits_cpu_shares,
|
'cpu_shares' => $this->database->limits_cpu_shares,
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ class StartRedis
|
|||||||
'memswap_limit' => $this->database->limits_memory_swap,
|
'memswap_limit' => $this->database->limits_memory_swap,
|
||||||
'mem_swappiness' => $this->database->limits_memory_swappiness,
|
'mem_swappiness' => $this->database->limits_memory_swappiness,
|
||||||
'mem_reservation' => $this->database->limits_memory_reservation,
|
'mem_reservation' => $this->database->limits_memory_reservation,
|
||||||
'cpus' => $this->database->limits_cpus,
|
'cpus' => (int) $this->database->limits_cpus,
|
||||||
'cpuset' => $this->database->limits_cpuset,
|
'cpuset' => $this->database->limits_cpuset,
|
||||||
'cpu_shares' => $this->database->limits_cpu_shares,
|
'cpu_shares' => $this->database->limits_cpu_shares,
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -192,6 +192,8 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
|
|||||||
$this->deploy_dockerimage_buildpack();
|
$this->deploy_dockerimage_buildpack();
|
||||||
} else if ($this->application->build_pack === 'dockerfile') {
|
} else if ($this->application->build_pack === 'dockerfile') {
|
||||||
$this->deploy_dockerfile_buildpack();
|
$this->deploy_dockerfile_buildpack();
|
||||||
|
} else if ($this->application->build_pack === 'static') {
|
||||||
|
$this->deploy_static_buildpack();
|
||||||
} else {
|
} else {
|
||||||
if ($this->pull_request_id !== 0) {
|
if ($this->pull_request_id !== 0) {
|
||||||
$this->deploy_pull_request();
|
$this->deploy_pull_request();
|
||||||
@@ -227,6 +229,14 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
|
|||||||
[
|
[
|
||||||
"docker rm -f {$this->deployment_uuid} >/dev/null 2>&1",
|
"docker rm -f {$this->deployment_uuid} >/dev/null 2>&1",
|
||||||
"hidden" => true,
|
"hidden" => true,
|
||||||
|
"ignore_errors" => true,
|
||||||
|
]
|
||||||
|
);
|
||||||
|
$this->execute_remote_command(
|
||||||
|
[
|
||||||
|
"docker image prune -f >/dev/null 2>&1",
|
||||||
|
"hidden" => true,
|
||||||
|
"ignore_errors" => true,
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -421,6 +431,23 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
|
|||||||
$this->build_image();
|
$this->build_image();
|
||||||
$this->rolling_update();
|
$this->rolling_update();
|
||||||
}
|
}
|
||||||
|
private function deploy_static_buildpack()
|
||||||
|
{
|
||||||
|
$this->execute_remote_command(
|
||||||
|
[
|
||||||
|
"echo 'Starting deployment of {$this->customRepository}:{$this->application->git_branch}.'"
|
||||||
|
],
|
||||||
|
);
|
||||||
|
$this->prepare_builder_image();
|
||||||
|
$this->check_git_if_build_needed();
|
||||||
|
$this->set_base_dir();
|
||||||
|
$this->generate_image_names();
|
||||||
|
$this->clone_repository();
|
||||||
|
$this->cleanup_git();
|
||||||
|
$this->build_image();
|
||||||
|
$this->generate_compose_file();
|
||||||
|
$this->rolling_update();
|
||||||
|
}
|
||||||
|
|
||||||
private function rolling_update()
|
private function rolling_update()
|
||||||
{
|
{
|
||||||
@@ -529,7 +556,7 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
|
|||||||
"hidden" => true,
|
"hidden" => true,
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
"command" => executeInDocker($this->deployment_uuid, "mkdir -p {$this->workdir}")
|
"command" => executeInDocker($this->deployment_uuid, "mkdir -p {$this->basedir}")
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -787,7 +814,7 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
|
|||||||
'memswap_limit' => $this->application->limits_memory_swap,
|
'memswap_limit' => $this->application->limits_memory_swap,
|
||||||
'mem_swappiness' => $this->application->limits_memory_swappiness,
|
'mem_swappiness' => $this->application->limits_memory_swappiness,
|
||||||
'mem_reservation' => $this->application->limits_memory_reservation,
|
'mem_reservation' => $this->application->limits_memory_reservation,
|
||||||
'cpus' => $this->application->limits_cpus,
|
'cpus' => (int) $this->application->limits_cpus,
|
||||||
'cpuset' => $this->application->limits_cpuset,
|
'cpuset' => $this->application->limits_cpuset,
|
||||||
'cpu_shares' => $this->application->limits_cpu_shares,
|
'cpu_shares' => $this->application->limits_cpu_shares,
|
||||||
]
|
]
|
||||||
@@ -910,22 +937,26 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
|
|||||||
|
|
||||||
private function build_image()
|
private function build_image()
|
||||||
{
|
{
|
||||||
$this->execute_remote_command([
|
if ($this->application->build_pack === 'static') {
|
||||||
"echo -n 'Building docker image for your application. To check the current progress, click on Show Debug Logs.'",
|
|
||||||
]);
|
|
||||||
|
|
||||||
if ($this->application->settings->is_static) {
|
|
||||||
$this->execute_remote_command([
|
$this->execute_remote_command([
|
||||||
executeInDocker($this->deployment_uuid, "docker build $this->buildTarget $this->addHosts --network host -f {$this->workdir}/{$this->dockerfile_location} {$this->build_args} --progress plain -t $this->build_image_name {$this->workdir}"), "hidden" => true
|
"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.'",
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
$dockerfile = base64_encode("FROM {$this->application->static_image}
|
if ($this->application->settings->is_static || $this->application->build_pack === 'static') {
|
||||||
|
if ($this->application->build_pack === 'static') {
|
||||||
|
$dockerfile = base64_encode("FROM {$this->application->static_image}
|
||||||
WORKDIR /usr/share/nginx/html/
|
WORKDIR /usr/share/nginx/html/
|
||||||
LABEL coolify.deploymentId={$this->deployment_uuid}
|
LABEL coolify.deploymentId={$this->deployment_uuid}
|
||||||
COPY --from=$this->build_image_name /app/{$this->application->publish_directory} .
|
COPY . .
|
||||||
|
RUN rm -f /usr/share/nginx/html/nginx.conf
|
||||||
|
RUN rm -f /usr/share/nginx/html/Dockerfile
|
||||||
COPY ./nginx.conf /etc/nginx/conf.d/default.conf");
|
COPY ./nginx.conf /etc/nginx/conf.d/default.conf");
|
||||||
|
$nginx_config = base64_encode("server {
|
||||||
$nginx_config = base64_encode("server {
|
|
||||||
listen 80;
|
listen 80;
|
||||||
listen [::]:80;
|
listen [::]:80;
|
||||||
server_name localhost;
|
server_name localhost;
|
||||||
@@ -941,15 +972,43 @@ COPY ./nginx.conf /etc/nginx/conf.d/default.conf");
|
|||||||
root /usr/share/nginx/html;
|
root /usr/share/nginx/html;
|
||||||
}
|
}
|
||||||
}");
|
}");
|
||||||
|
} else {
|
||||||
|
$this->execute_remote_command([
|
||||||
|
executeInDocker($this->deployment_uuid, "docker build $this->buildTarget $this->addHosts --network host -f {$this->workdir}/{$this->dockerfile_location} {$this->build_args} --progress plain -t $this->build_image_name {$this->workdir}"), "hidden" => true
|
||||||
|
]);
|
||||||
|
|
||||||
|
$dockerfile = base64_encode("FROM {$this->application->static_image}
|
||||||
|
WORKDIR /usr/share/nginx/html/
|
||||||
|
LABEL coolify.deploymentId={$this->deployment_uuid}
|
||||||
|
COPY --from=$this->build_image_name /app/{$this->application->publish_directory} .
|
||||||
|
COPY ./nginx.conf /etc/nginx/conf.d/default.conf");
|
||||||
|
|
||||||
|
$nginx_config = base64_encode("server {
|
||||||
|
listen 80;
|
||||||
|
listen [::]:80;
|
||||||
|
server_name localhost;
|
||||||
|
|
||||||
|
location / {
|
||||||
|
root /usr/share/nginx/html;
|
||||||
|
index index.html;
|
||||||
|
try_files \$uri \$uri.html \$uri/index.html \$uri/ /index.html =404;
|
||||||
|
}
|
||||||
|
|
||||||
|
error_page 500 502 503 504 /50x.html;
|
||||||
|
location = /50x.html {
|
||||||
|
root /usr/share/nginx/html;
|
||||||
|
}
|
||||||
|
}");
|
||||||
|
}
|
||||||
$this->execute_remote_command(
|
$this->execute_remote_command(
|
||||||
[
|
[
|
||||||
executeInDocker($this->deployment_uuid, "echo '{$dockerfile}' | base64 -d > {$this->workdir}/Dockerfile-prod")
|
executeInDocker($this->deployment_uuid, "echo '{$dockerfile}' | base64 -d > {$this->workdir}/Dockerfile")
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
executeInDocker($this->deployment_uuid, "echo '{$nginx_config}' | base64 -d > {$this->workdir}/nginx.conf")
|
executeInDocker($this->deployment_uuid, "echo '{$nginx_config}' | base64 -d > {$this->workdir}/nginx.conf")
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
executeInDocker($this->deployment_uuid, "docker build $this->addHosts --network host -f {$this->workdir}/Dockerfile-prod {$this->build_args} --progress plain -t $this->production_image_name {$this->workdir}"), "hidden" => true
|
executeInDocker($this->deployment_uuid, "docker build $this->addHosts --network host -f {$this->workdir}/Dockerfile {$this->build_args} --progress plain -t $this->production_image_name {$this->workdir}"), "hidden" => true
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
namespace App\Jobs;
|
namespace App\Jobs;
|
||||||
|
|
||||||
use App\Models\Server;
|
use App\Models\Server;
|
||||||
|
use Exception;
|
||||||
use Illuminate\Bus\Queueable;
|
use Illuminate\Bus\Queueable;
|
||||||
use Illuminate\Contracts\Queue\ShouldBeEncrypted;
|
use Illuminate\Contracts\Queue\ShouldBeEncrypted;
|
||||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
@@ -10,12 +11,13 @@ use Illuminate\Foundation\Bus\Dispatchable;
|
|||||||
use Illuminate\Queue\InteractsWithQueue;
|
use Illuminate\Queue\InteractsWithQueue;
|
||||||
use Illuminate\Queue\Middleware\WithoutOverlapping;
|
use Illuminate\Queue\Middleware\WithoutOverlapping;
|
||||||
use Illuminate\Queue\SerializesModels;
|
use Illuminate\Queue\SerializesModels;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
|
||||||
class DockerCleanupJob implements ShouldQueue, ShouldBeEncrypted
|
class DockerCleanupJob implements ShouldQueue, ShouldBeEncrypted
|
||||||
{
|
{
|
||||||
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||||
|
|
||||||
public $timeout = 1000;
|
public $timeout = 300;
|
||||||
public ?string $dockerRootFilesystem = null;
|
public ?string $dockerRootFilesystem = null;
|
||||||
public ?int $usageBefore = null;
|
public ?int $usageBefore = null;
|
||||||
|
|
||||||
@@ -33,14 +35,15 @@ class DockerCleanupJob implements ShouldQueue, ShouldBeEncrypted
|
|||||||
}
|
}
|
||||||
public function handle(): void
|
public function handle(): void
|
||||||
{
|
{
|
||||||
$queuedCount = 0;
|
$isInprogress = false;
|
||||||
$this->server->applications()->each(function ($application) use ($queuedCount) {
|
$this->server->applications()->each(function ($application) use (&$isInprogress) {
|
||||||
$count = data_get($application->deployments(), 'count', 0);
|
if ($application->isDeploymentInprogress()) {
|
||||||
$queuedCount += $count;
|
$isInprogress = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
if ($queuedCount > 0) {
|
if ($isInprogress) {
|
||||||
ray('DockerCleanupJob: ApplicationDeploymentQueue is not empty, skipping')->color('orange');
|
throw new Exception('DockerCleanupJob: ApplicationDeploymentQueue is not empty, skipping...');
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
if (!$this->server->isFunctional()) {
|
if (!$this->server->isFunctional()) {
|
||||||
@@ -49,23 +52,25 @@ class DockerCleanupJob implements ShouldQueue, ShouldBeEncrypted
|
|||||||
$this->dockerRootFilesystem = "/";
|
$this->dockerRootFilesystem = "/";
|
||||||
$this->usageBefore = $this->getFilesystemUsage();
|
$this->usageBefore = $this->getFilesystemUsage();
|
||||||
if ($this->usageBefore >= $this->server->settings->cleanup_after_percentage) {
|
if ($this->usageBefore >= $this->server->settings->cleanup_after_percentage) {
|
||||||
ray('Cleaning up ' . $this->server->name)->color('orange');
|
ray('Cleaning up ' . $this->server->name);
|
||||||
instant_remote_process(['docker image prune -af'], $this->server);
|
instant_remote_process(['docker image prune -af'], $this->server);
|
||||||
instant_remote_process(['docker container prune -f --filter "label=coolify.managed=true"'], $this->server);
|
instant_remote_process(['docker container prune -f --filter "label=coolify.managed=true"'], $this->server);
|
||||||
instant_remote_process(['docker builder prune -af'], $this->server);
|
instant_remote_process(['docker builder prune -af'], $this->server);
|
||||||
$usageAfter = $this->getFilesystemUsage();
|
$usageAfter = $this->getFilesystemUsage();
|
||||||
if ($usageAfter < $this->usageBefore) {
|
if ($usageAfter < $this->usageBefore) {
|
||||||
ray('Saved ' . ($this->usageBefore - $usageAfter) . '% disk space on ' . $this->server->name)->color('orange');
|
ray('Saved ' . ($this->usageBefore - $usageAfter) . '% disk space on ' . $this->server->name);
|
||||||
send_internal_notification('DockerCleanupJob done: Saved ' . ($this->usageBefore - $usageAfter) . '% disk space on ' . $this->server->name);
|
send_internal_notification('DockerCleanupJob done: Saved ' . ($this->usageBefore - $usageAfter) . '% disk space on ' . $this->server->name);
|
||||||
|
Log::info('DockerCleanupJob done: Saved ' . ($this->usageBefore - $usageAfter) . '% disk space on ' . $this->server->name);
|
||||||
} else {
|
} else {
|
||||||
ray('DockerCleanupJob failed to save disk space on ' . $this->server->name)->color('orange');
|
Log::info('DockerCleanupJob failed to save disk space on ' . $this->server->name);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ray('No need to clean up ' . $this->server->name)->color('orange');
|
ray('No need to clean up ' . $this->server->name);
|
||||||
|
Log::info('No need to clean up ' . $this->server->name);
|
||||||
}
|
}
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
send_internal_notification('DockerCleanupJob failed with: ' . $e->getMessage());
|
send_internal_notification('DockerCleanupJob failed with: ' . $e->getMessage());
|
||||||
ray($e->getMessage())->color('orange');
|
ray($e->getMessage());
|
||||||
throw $e;
|
throw $e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -213,6 +213,14 @@ class Application extends BaseModel
|
|||||||
return $this->morphTo();
|
return $this->morphTo();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function isDeploymentInprogress() {
|
||||||
|
$deployments = ApplicationDeploymentQueue::where('application_id', $this->id)->where('status', 'in_progress')->count();
|
||||||
|
if ($deployments > 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
public function deployments(int $skip = 0, int $take = 10)
|
public function deployments(int $skip = 0, int $take = 10)
|
||||||
{
|
{
|
||||||
$deployments = ApplicationDeploymentQueue::where('application_id', $this->id)->orderBy('created_at', 'desc');
|
$deployments = ApplicationDeploymentQueue::where('application_id', $this->id)->orderBy('created_at', 'desc');
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ class Input extends Component
|
|||||||
public bool $readonly = false,
|
public bool $readonly = false,
|
||||||
public string|null $helper = null,
|
public string|null $helper = null,
|
||||||
public bool $allowToPeak = true,
|
public bool $allowToPeak = true,
|
||||||
public string $defaultClass = "input input-sm bg-coolgray-200 rounded text-white w-full disabled:bg-coolgray-200/50 disabled:border-none placeholder:text-coolgray-500 read-only:text-neutral-500 read-only:bg-coolgray-200/50"
|
public string $defaultClass = "input input-sm bg-coolgray-100 rounded text-white w-full disabled:bg-coolgray-200/50 disabled:border-none placeholder:text-coolgray-500 read-only:text-neutral-500 read-only:bg-coolgray-200/50"
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ class Select extends Component
|
|||||||
public string|null $label = null,
|
public string|null $label = null,
|
||||||
public string|null $helper = null,
|
public string|null $helper = null,
|
||||||
public bool $required = false,
|
public bool $required = false,
|
||||||
public string $defaultClass = "select select-sm w-full rounded text-white text-sm bg-coolgray-200 font-normal disabled:bg-coolgray-200/50 disabled:border-none"
|
public string $defaultClass = "select select-sm w-full rounded text-white text-sm bg-coolgray-100 font-normal disabled:bg-coolgray-200/50 disabled:border-none"
|
||||||
) {
|
) {
|
||||||
//
|
//
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ class Textarea extends Component
|
|||||||
public bool $readonly = false,
|
public bool $readonly = false,
|
||||||
public string|null $helper = null,
|
public string|null $helper = null,
|
||||||
public bool $realtimeValidation = false,
|
public bool $realtimeValidation = false,
|
||||||
public string $defaultClass = "textarea leading-normal bg-coolgray-200 rounded text-white scrollbar disabled:bg-coolgray-200/50 disabled:border-none placeholder:text-coolgray-500 read-only:text-neutral-500 read-only:bg-coolgray-200/50"
|
public string $defaultClass = "textarea leading-normal bg-coolgray-100 rounded text-white scrollbar disabled:bg-coolgray-200/50 disabled:border-none placeholder:text-coolgray-500 read-only:text-neutral-500 read-only:bg-coolgray-200/50"
|
||||||
) {
|
) {
|
||||||
//
|
//
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ return [
|
|||||||
|
|
||||||
// The release version of your application
|
// The release version of your application
|
||||||
// Example with dynamic git hash: trim(exec('git --git-dir ' . base_path('.git') . ' log --pretty="%h" -n1 HEAD'))
|
// Example with dynamic git hash: trim(exec('git --git-dir ' . base_path('.git') . ' log --pretty="%h" -n1 HEAD'))
|
||||||
'release' => '4.0.0-beta.119',
|
'release' => '4.0.0-beta.121',
|
||||||
// When left empty or `null` the Laravel environment will be used
|
// When left empty or `null` the Laravel environment will be used
|
||||||
'environment' => config('app.env'),
|
'environment' => config('app.env'),
|
||||||
|
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ return [
|
|||||||
'stripe_price_id_pro_yearly' => env('STRIPE_PRICE_ID_PRO_YEARLY', null),
|
'stripe_price_id_pro_yearly' => env('STRIPE_PRICE_ID_PRO_YEARLY', null),
|
||||||
'stripe_price_id_ultimate_monthly' => env('STRIPE_PRICE_ID_ULTIMATE_MONTHLY', null),
|
'stripe_price_id_ultimate_monthly' => env('STRIPE_PRICE_ID_ULTIMATE_MONTHLY', null),
|
||||||
'stripe_price_id_ultimate_yearly' => env('STRIPE_PRICE_ID_ULTIMATE_YEARLY', null),
|
'stripe_price_id_ultimate_yearly' => env('STRIPE_PRICE_ID_ULTIMATE_YEARLY', null),
|
||||||
|
'stripe_excluded_plans' => env('STRIPE_EXCLUDED_PLANS', null),
|
||||||
|
|
||||||
|
|
||||||
// Paddle
|
// Paddle
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
return '4.0.0-beta.119';
|
return '4.0.0-beta.121';
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ a {
|
|||||||
@apply text-white;
|
@apply text-white;
|
||||||
}
|
}
|
||||||
.box {
|
.box {
|
||||||
@apply flex p-2 transition-colors cursor-pointer min-h-16 bg-coolgray-200 hover:bg-coollabs-100 hover:text-white hover:no-underline min-w-[24rem];
|
@apply flex p-2 transition-colors cursor-pointer min-h-16 bg-coolgray-100 hover:bg-coollabs-100 hover:text-white hover:no-underline min-w-[24rem];
|
||||||
}
|
}
|
||||||
.box-without-bg {
|
.box-without-bg {
|
||||||
@apply flex p-2 transition-colors min-h-16 hover:text-white hover:no-underline min-w-[24rem];
|
@apply flex p-2 transition-colors min-h-16 hover:text-white hover:no-underline min-w-[24rem];
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<Transition name="fade">
|
<Transition name="fade">
|
||||||
<div>
|
<div>
|
||||||
<div class="flex items-center p-1 px-2 overflow-hidden transition-all transform rounded cursor-pointer bg-coolgray-200"
|
<div class="flex items-center p-1 px-2 overflow-hidden transition-all transform rounded cursor-pointer bg-coolgray-100"
|
||||||
@click="showCommandPalette = true">
|
@click="showCommandPalette = true">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" class="w-6 h-6 icon" viewBox="0 0 24 24" stroke-width="2"
|
<svg xmlns="http://www.w3.org/2000/svg" class="w-6 h-6 icon" viewBox="0 0 24 24" stroke-width="2"
|
||||||
stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
|
stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
@auth
|
@auth
|
||||||
<nav class="fixed h-full overflow-hidden overflow-y-auto pt-14 scrollbar">
|
<nav class="fixed h-full overflow-hidden overflow-y-auto pt-14 scrollbar">
|
||||||
<a href="/" class="fixed top-0 z-50 mx-3 mt-3 cursor-pointer bg-coolgray-100"><img class="transition rounded w-11 h-11" src="{{ asset('coolify-transparent.png') }}"></a>
|
<a href="/" class="fixed top-0 z-50 mx-3 mt-3 bg-transparent cursor-pointer"><img
|
||||||
|
class="transition rounded w-11 h-11" src="{{ asset('coolify-transparent.png') }}"></a>
|
||||||
<ul class="flex flex-col h-full gap-4 menu flex-nowrap">
|
<ul class="flex flex-col h-full gap-4 menu flex-nowrap">
|
||||||
<li title="Dashboard">
|
<li title="Dashboard">
|
||||||
<a class="hover:bg-transparent" @if (!request()->is('/')) href="/" @endif>
|
<a class="hover:bg-transparent" @if (!request()->is('/')) href="/" @endif>
|
||||||
@@ -11,6 +12,18 @@
|
|||||||
</svg>
|
</svg>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
<li title="Help us!">
|
||||||
|
<a class="hover:bg-transparent"href="https://coolify.io/sponsorships" target="_blank">
|
||||||
|
<svg class="icon hover:text-pink-500" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<g fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"
|
||||||
|
stroke-width="2">
|
||||||
|
<path d="M19.5 12.572L12 20l-7.5-7.428A5 5 0 1 1 12 6.006a5 5 0 1 1 7.5 6.572" />
|
||||||
|
<path
|
||||||
|
d="M12 6L8.707 9.293a1 1 0 0 0 0 1.414l.543.543c.69.69 1.81.69 2.5 0l1-1a3.182 3.182 0 0 1 4.5 0l2.25 2.25m-7 3l2 2M15 13l2 2" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
<li title="Send us feedback or get help!" class="fixed top-0 right-0 p-2 px-4 pt-4 mt-auto text-xs">
|
<li title="Send us feedback or get help!" class="fixed top-0 right-0 p-2 px-4 pt-4 mt-auto text-xs">
|
||||||
<div class="justify-center" wire:click="help" onclick="help.showModal()">
|
<div class="justify-center" wire:click="help" onclick="help.showModal()">
|
||||||
<svg class="w-5 h-5" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
<svg class="w-5 h-5" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
@auth
|
@auth
|
||||||
<nav class="fixed h-full overflow-hidden overflow-y-auto pt-28 scrollbar">
|
<nav class="fixed h-full overflow-hidden overflow-y-auto pt-28 scrollbar">
|
||||||
<a href="/" class="fixed top-0 z-50 mx-3 mt-3 cursor-pointer bg-coolgray-100"><img class="transition rounded w-11 h-11" src="{{ asset('coolify-transparent.png') }}"></a>
|
<a href="/" class="fixed top-0 z-50 mx-3 mt-3 bg-transparent cursor-pointer"><img
|
||||||
|
class="transition rounded w-11 h-11" src="{{ asset('coolify-transparent.png') }}"></a>
|
||||||
<ul class="flex flex-col h-full gap-4 menu flex-nowrap">
|
<ul class="flex flex-col h-full gap-4 menu flex-nowrap">
|
||||||
<li title="Dashboard">
|
<li title="Dashboard">
|
||||||
<a class="hover:bg-transparent" @if (!request()->is('/')) href="/" @endif>
|
<a class="hover:bg-transparent" @if (!request()->is('/')) href="/" @endif>
|
||||||
@@ -87,6 +88,18 @@
|
|||||||
@if (isInstanceAdmin() && !isCloud())
|
@if (isInstanceAdmin() && !isCloud())
|
||||||
<livewire:upgrade />
|
<livewire:upgrade />
|
||||||
@endif
|
@endif
|
||||||
|
<li title="Help us!">
|
||||||
|
<a class="hover:bg-transparent"href="https://coolify.io/sponsorships" target="_blank">
|
||||||
|
<svg class="icon hover:text-pink-500" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<g fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"
|
||||||
|
stroke-width="2">
|
||||||
|
<path d="M19.5 12.572L12 20l-7.5-7.428A5 5 0 1 1 12 6.006a5 5 0 1 1 7.5 6.572" />
|
||||||
|
<path
|
||||||
|
d="M12 6L8.707 9.293a1 1 0 0 0 0 1.414l.543.543c.69.69 1.81.69 2.5 0l1-1a3.182 3.182 0 0 1 4.5 0l2.25 2.25m-7 3l2 2M15 13l2 2" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
<li title="Profile">
|
<li title="Profile">
|
||||||
<a class="hover:bg-transparent" @if (!request()->is('profile')) href="/profile" @endif>
|
<a class="hover:bg-transparent" @if (!request()->is('profile')) href="/profile" @endif>
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" class="icon" viewBox="0 0 24 24" stroke-width="1.5"
|
<svg xmlns="http://www.w3.org/2000/svg" class="icon" viewBox="0 0 24 24" stroke-width="1.5"
|
||||||
|
|||||||
@@ -25,7 +25,6 @@
|
|||||||
@endif
|
@endif
|
||||||
</head>
|
</head>
|
||||||
@section('body')
|
@section('body')
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
@livewireScripts
|
@livewireScripts
|
||||||
<dialog id="help" class="modal">
|
<dialog id="help" class="modal">
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
@endif
|
@endif
|
||||||
<div id="screen" :class="fullscreen ? 'fullscreen' : ''">
|
<div id="screen" :class="fullscreen ? 'fullscreen' : ''">
|
||||||
<div @if ($isKeepAliveOn) wire:poll.2000ms="polling" @endif
|
<div @if ($isKeepAliveOn) wire:poll.2000ms="polling" @endif
|
||||||
class="relative flex flex-col-reverse w-full p-2 px-4 mt-4 overflow-y-auto scrollbar border-coolgray-400"
|
class="relative flex flex-col-reverse w-full p-2 px-4 mt-4 overflow-y-auto text-white bg-coolgray-100 scrollbar border-coolgray-300"
|
||||||
:class="fullscreen ? '' : 'max-h-[40rem] border border-dotted rounded'">
|
:class="fullscreen ? '' : 'max-h-[40rem] border border-dotted rounded'">
|
||||||
<button title="Minimize" x-show="fullscreen" class="fixed top-4 right-4" x-on:click="makeFullscreen"><svg
|
<button title="Minimize" x-show="fullscreen" class="fixed top-4 right-4" x-on:click="makeFullscreen"><svg
|
||||||
class="icon" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
class="icon" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||||
@@ -48,7 +48,7 @@
|
|||||||
@foreach (decode_remote_command_output($application_deployment_queue) as $line)
|
@foreach (decode_remote_command_output($application_deployment_queue) as $line)
|
||||||
<div @class([
|
<div @class([
|
||||||
'font-mono whitespace-pre-line',
|
'font-mono whitespace-pre-line',
|
||||||
'text-neutral-400' => $line['type'] == 'stdout',
|
'text-white' => $line['type'] == 'stdout',
|
||||||
'text-error' => $line['type'] == 'stderr',
|
'text-error' => $line['type'] == 'stderr',
|
||||||
'text-warning' => $line['hidden'],
|
'text-warning' => $line['hidden'],
|
||||||
])>[{{ $line['timestamp'] }}] @if ($line['hidden'])
|
])>[{{ $line['timestamp'] }}] @if ($line['hidden'])
|
||||||
|
|||||||
@@ -12,14 +12,14 @@
|
|||||||
</form>
|
</form>
|
||||||
@forelse ($deployments as $deployment)
|
@forelse ($deployments as $deployment)
|
||||||
<a @class([
|
<a @class([
|
||||||
'bg-coolgray-200 p-2 border-l border-dashed transition-colors hover:no-underline',
|
'bg-coolgray-100 p-2 border-l border-dashed transition-colors hover:no-underline',
|
||||||
'hover:bg-coolgray-200' =>
|
'hover:bg-coolgray-200' =>
|
||||||
data_get($deployment, 'status') === 'queued' ||
|
data_get($deployment, 'status') === 'queued',
|
||||||
data_get($deployment, 'status') === 'cancelled by system',
|
|
||||||
'border-warning hover:bg-warning hover:text-black' =>
|
'border-warning hover:bg-warning hover:text-black' =>
|
||||||
data_get($deployment, 'status') === 'in_progress',
|
data_get($deployment, 'status') === 'in_progress' ||
|
||||||
|
data_get($deployment, 'status') === 'cancelled-by-user',
|
||||||
'border-error hover:bg-error' =>
|
'border-error hover:bg-error' =>
|
||||||
data_get($deployment, 'status') === 'error',
|
data_get($deployment, 'status') === 'failed',
|
||||||
'border-success hover:bg-success' =>
|
'border-success hover:bg-success' =>
|
||||||
data_get($deployment, 'status') === 'finished',
|
data_get($deployment, 'status') === 'finished',
|
||||||
]) href="{{ $current_url . '/' . data_get($deployment, 'deployment_uuid') }}"
|
]) href="{{ $current_url . '/' . data_get($deployment, 'deployment_uuid') }}"
|
||||||
|
|||||||
@@ -27,10 +27,11 @@
|
|||||||
<div class="flex gap-2">
|
<div class="flex gap-2">
|
||||||
<x-forms.select wire:model="application.build_pack" label="Build Pack" required>
|
<x-forms.select wire:model="application.build_pack" label="Build Pack" required>
|
||||||
<option value="nixpacks">Nixpacks</option>
|
<option value="nixpacks">Nixpacks</option>
|
||||||
|
<option value="static">Static</option>
|
||||||
<option value="dockerfile">Dockerfile</option>
|
<option value="dockerfile">Dockerfile</option>
|
||||||
<option value="dockerimage">Docker Image</option>
|
<option value="dockerimage">Docker Image</option>
|
||||||
</x-forms.select>
|
</x-forms.select>
|
||||||
@if ($application->settings->is_static)
|
@if ($application->settings->is_static || $application->build_pack === 'static')
|
||||||
<x-forms.select id="application.static_image" label="Static Image" required>
|
<x-forms.select id="application.static_image" label="Static Image" required>
|
||||||
<option value="nginx:alpine">nginx:alpine</option>
|
<option value="nginx:alpine">nginx:alpine</option>
|
||||||
<option disabled value="apache:alpine">apache:alpine</option>
|
<option disabled value="apache:alpine">apache:alpine</option>
|
||||||
@@ -51,7 +52,7 @@
|
|||||||
@if ($application->could_set_build_commands())
|
@if ($application->could_set_build_commands())
|
||||||
@if ($application->build_pack === 'nixpacks')
|
@if ($application->build_pack === 'nixpacks')
|
||||||
<div>Nixpacks will detect the required configuration automatically.
|
<div>Nixpacks will detect the required configuration automatically.
|
||||||
<a class="underline" href="https://coolify.io/docs/frameworks">Framework Specific Docs</a>
|
<a class="underline" href="https://coolify.io/docs/frameworks/">Framework Specific Docs</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex flex-col gap-2 xl:flex-row">
|
<div class="flex flex-col gap-2 xl:flex-row">
|
||||||
<x-forms.input placeholder="If you modify this, you probably need to have a nixpacks.toml"
|
<x-forms.input placeholder="If you modify this, you probably need to have a nixpacks.toml"
|
||||||
@@ -97,7 +98,7 @@
|
|||||||
@endif
|
@endif
|
||||||
<h3>Network</h3>
|
<h3>Network</h3>
|
||||||
<div class="flex flex-col gap-2 xl:flex-row">
|
<div class="flex flex-col gap-2 xl:flex-row">
|
||||||
@if ($application->settings->is_static)
|
@if ($application->settings->is_static || $application->build_pack === 'static')
|
||||||
<x-forms.input id="application.ports_exposes" label="Ports Exposes" readonly />
|
<x-forms.input id="application.ports_exposes" label="Ports Exposes" readonly />
|
||||||
@else
|
@else
|
||||||
<x-forms.input placeholder="3000,3001" id="application.ports_exposes" label="Ports Exposes" required
|
<x-forms.input placeholder="3000,3001" id="application.ports_exposes" label="Ports Exposes" required
|
||||||
|
|||||||
@@ -2,7 +2,9 @@
|
|||||||
@if (
|
@if (
|
||||||
$resource->getMorphClass() == 'App\Models\Application' ||
|
$resource->getMorphClass() == 'App\Models\Application' ||
|
||||||
$resource->getMorphClass() == 'App\Models\StandalonePostgresql' ||
|
$resource->getMorphClass() == 'App\Models\StandalonePostgresql' ||
|
||||||
$resource->getMorphClass() == 'App\Models\StandaloneRedis')
|
$resource->getMorphClass() == 'App\Models\StandaloneRedis' ||
|
||||||
|
$resource->getMorphClass() == 'App\Models\StandaloneMariadb' ||
|
||||||
|
$resource->getMorphClass() == 'App\Models\StandaloneMongodb')
|
||||||
<div class="flex items-center gap-2">
|
<div class="flex items-center gap-2">
|
||||||
<h2>Storages</h2>
|
<h2>Storages</h2>
|
||||||
<x-helper
|
<x-helper
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
<x-forms.button type="submit">Refresh</x-forms.button>
|
<x-forms.button type="submit">Refresh</x-forms.button>
|
||||||
</form>
|
</form>
|
||||||
<div id="screen" x-data="{ fullscreen: false, alwaysScroll: false, intervalId: null }" :class="fullscreen ? 'fullscreen' : 'container w-full pt-4 mx-auto'">
|
<div id="screen" x-data="{ fullscreen: false, alwaysScroll: false, intervalId: null }" :class="fullscreen ? 'fullscreen' : 'container w-full pt-4 mx-auto'">
|
||||||
<div class="relative flex flex-col-reverse w-full p-4 pt-6 overflow-y-auto text-white scrollbar border-coolgray-300"
|
<div class="relative flex flex-col-reverse w-full p-4 pt-6 overflow-y-auto text-white bg-coolgray-100 scrollbar border-coolgray-300"
|
||||||
:class="fullscreen ? '' : 'max-h-[40rem] border border-solid rounded'">
|
:class="fullscreen ? '' : 'max-h-[40rem] border border-solid rounded'">
|
||||||
<button title="Minimize" x-show="fullscreen" class="fixed top-4 right-4" x-on:click="makeFullscreen"><svg
|
<button title="Minimize" x-show="fullscreen" class="fixed top-4 right-4" x-on:click="makeFullscreen"><svg
|
||||||
class="icon" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
class="icon" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
|||||||
@@ -5,10 +5,12 @@
|
|||||||
<div class="flex flex-col gap-4 min-w-fit">
|
<div class="flex flex-col gap-4 min-w-fit">
|
||||||
<a :class="activeTab === 'general' && 'text-white'"
|
<a :class="activeTab === 'general' && 'text-white'"
|
||||||
@click.prevent="activeTab = 'general'; window.location.hash = 'general'" href="#">General</a>
|
@click.prevent="activeTab = 'general'; window.location.hash = 'general'" href="#">General</a>
|
||||||
<a :class="activeTab === 'environment-variables' && 'text-white'"
|
@if ($application->build_pack !== 'static')
|
||||||
@click.prevent="activeTab = 'environment-variables'; window.location.hash = 'environment-variables'"
|
<a :class="activeTab === 'environment-variables' && 'text-white'"
|
||||||
href="#">Environment
|
@click.prevent="activeTab = 'environment-variables'; window.location.hash = 'environment-variables'"
|
||||||
Variables</a>
|
href="#">Environment
|
||||||
|
Variables</a>
|
||||||
|
@endif
|
||||||
@if ($application->git_based())
|
@if ($application->git_based())
|
||||||
<a :class="activeTab === 'source' && 'text-white'"
|
<a :class="activeTab === 'source' && 'text-white'"
|
||||||
@click.prevent="activeTab = 'source'; window.location.hash = 'source'" href="#">Source</a>
|
@click.prevent="activeTab = 'source'; window.location.hash = 'source'" href="#">Source</a>
|
||||||
@@ -16,21 +18,25 @@
|
|||||||
<a :class="activeTab === 'server' && 'text-white'"
|
<a :class="activeTab === 'server' && 'text-white'"
|
||||||
@click.prevent="activeTab = 'server'; window.location.hash = 'server'" href="#">Server
|
@click.prevent="activeTab = 'server'; window.location.hash = 'server'" href="#">Server
|
||||||
</a>
|
</a>
|
||||||
<a :class="activeTab === 'storages' && 'text-white'"
|
@if ($application->build_pack !== 'static')
|
||||||
@click.prevent="activeTab = 'storages'; window.location.hash = 'storages'" href="#">Storages
|
<a :class="activeTab === 'storages' && 'text-white'"
|
||||||
</a>
|
@click.prevent="activeTab = 'storages'; window.location.hash = 'storages'" href="#">Storages
|
||||||
|
</a>
|
||||||
|
@endif
|
||||||
<a :class="activeTab === 'webhooks' && 'text-white'"
|
<a :class="activeTab === 'webhooks' && 'text-white'"
|
||||||
@click.prevent="activeTab = 'webhooks'; window.location.hash = 'webhooks'" href="#">Webhooks
|
@click.prevent="activeTab = 'webhooks'; window.location.hash = 'webhooks'" href="#">Webhooks
|
||||||
</a>
|
</a>
|
||||||
@if ($application->git_based())
|
@if ($application->git_based() && $application->build_pack !== 'static')
|
||||||
<a :class="activeTab === 'previews' && 'text-white'"
|
<a :class="activeTab === 'previews' && 'text-white'"
|
||||||
@click.prevent="activeTab = 'previews'; window.location.hash = 'previews'" href="#">Preview
|
@click.prevent="activeTab = 'previews'; window.location.hash = 'previews'" href="#">Preview
|
||||||
Deployments
|
Deployments
|
||||||
</a>
|
</a>
|
||||||
@endif
|
@endif
|
||||||
<a :class="activeTab === 'health' && 'text-white'"
|
@if ($application->build_pack !== 'static')
|
||||||
@click.prevent="activeTab = 'health'; window.location.hash = 'health'" href="#">Health Checks
|
<a :class="activeTab === 'health' && 'text-white'"
|
||||||
</a>
|
@click.prevent="activeTab = 'health'; window.location.hash = 'health'" href="#">Health Checks
|
||||||
|
</a>
|
||||||
|
@endif
|
||||||
<a :class="activeTab === 'rollback' && 'text-white'"
|
<a :class="activeTab === 'rollback' && 'text-white'"
|
||||||
@click.prevent="activeTab = 'rollback'; window.location.hash = 'rollback'" href="#">Rollback
|
@click.prevent="activeTab = 'rollback'; window.location.hash = 'rollback'" href="#">Rollback
|
||||||
</a>
|
</a>
|
||||||
|
|||||||
@@ -237,7 +237,7 @@ Route::post('/payments/stripe/events', function () {
|
|||||||
try {
|
try {
|
||||||
$webhookSecret = config('subscription.stripe_webhook_secret');
|
$webhookSecret = config('subscription.stripe_webhook_secret');
|
||||||
$signature = request()->header('Stripe-Signature');
|
$signature = request()->header('Stripe-Signature');
|
||||||
|
$excludedPlans = config('subscription.stripe_excluded_plans');
|
||||||
$event = \Stripe\Webhook::constructEvent(
|
$event = \Stripe\Webhook::constructEvent(
|
||||||
request()->getContent(),
|
request()->getContent(),
|
||||||
$signature,
|
$signature,
|
||||||
@@ -253,6 +253,10 @@ Route::post('/payments/stripe/events', function () {
|
|||||||
switch ($type) {
|
switch ($type) {
|
||||||
case 'checkout.session.completed':
|
case 'checkout.session.completed':
|
||||||
$clientReferenceId = data_get($data, 'client_reference_id');
|
$clientReferenceId = data_get($data, 'client_reference_id');
|
||||||
|
if (is_null($clientReferenceId)) {
|
||||||
|
send_internal_notification('Checkout session completed without client reference id.');
|
||||||
|
break;
|
||||||
|
}
|
||||||
$userId = Str::before($clientReferenceId, ':');
|
$userId = Str::before($clientReferenceId, ':');
|
||||||
$teamId = Str::after($clientReferenceId, ':');
|
$teamId = Str::after($clientReferenceId, ':');
|
||||||
$subscriptionId = data_get($data, 'subscription');
|
$subscriptionId = data_get($data, 'subscription');
|
||||||
@@ -282,12 +286,17 @@ Route::post('/payments/stripe/events', function () {
|
|||||||
break;
|
break;
|
||||||
case 'invoice.paid':
|
case 'invoice.paid':
|
||||||
$customerId = data_get($data, 'customer');
|
$customerId = data_get($data, 'customer');
|
||||||
|
$planId = data_get($data, 'lines.data.0.plan.id');
|
||||||
|
if (Str::contains($excludedPlans, $planId)) {
|
||||||
|
send_internal_notification('Subscription excluded.');
|
||||||
|
break;
|
||||||
|
}
|
||||||
$subscription = Subscription::where('stripe_customer_id', $customerId)->first();
|
$subscription = Subscription::where('stripe_customer_id', $customerId)->first();
|
||||||
if (!$subscription) {
|
if (!$subscription) {
|
||||||
Sleep::for(5)->seconds();
|
Sleep::for(5)->seconds();
|
||||||
$subscription = Subscription::where('stripe_customer_id', $customerId)->firstOrFail();
|
$subscription = Subscription::where('stripe_customer_id', $customerId)->firstOrFail();
|
||||||
}
|
}
|
||||||
$planId = data_get($data, 'lines.data.0.plan.id');
|
|
||||||
$subscription->update([
|
$subscription->update([
|
||||||
'stripe_plan_id' => $planId,
|
'stripe_plan_id' => $planId,
|
||||||
'stripe_invoice_paid' => true,
|
'stripe_invoice_paid' => true,
|
||||||
@@ -303,11 +312,15 @@ Route::post('/payments/stripe/events', function () {
|
|||||||
break;
|
break;
|
||||||
case 'customer.subscription.updated':
|
case 'customer.subscription.updated':
|
||||||
$customerId = data_get($data, 'customer');
|
$customerId = data_get($data, 'customer');
|
||||||
$subscription = Subscription::where('stripe_customer_id', $customerId)->firstOrFail();
|
|
||||||
$trialEndedAlready = data_get($subscription, 'stripe_trial_already_ended');
|
|
||||||
$status = data_get($data, 'status');
|
$status = data_get($data, 'status');
|
||||||
$subscriptionId = data_get($data, 'items.data.0.subscription');
|
$subscriptionId = data_get($data, 'items.data.0.subscription');
|
||||||
$planId = data_get($data, 'items.data.0.plan.id');
|
$planId = data_get($data, 'items.data.0.plan.id');
|
||||||
|
if (Str::contains($excludedPlans, $planId)) {
|
||||||
|
send_internal_notification('Subscription excluded.');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
$subscription = Subscription::where('stripe_customer_id', $customerId)->firstOrFail();
|
||||||
|
$trialEndedAlready = data_get($subscription, 'stripe_trial_already_ended');
|
||||||
$cancelAtPeriodEnd = data_get($data, 'cancel_at_period_end');
|
$cancelAtPeriodEnd = data_get($data, 'cancel_at_period_end');
|
||||||
$alreadyCancelAtPeriodEnd = data_get($subscription, 'stripe_cancel_at_period_end');
|
$alreadyCancelAtPeriodEnd = data_get($subscription, 'stripe_cancel_at_period_end');
|
||||||
$feedback = data_get($data, 'cancellation_details.feedback');
|
$feedback = data_get($data, 'cancellation_details.feedback');
|
||||||
|
|||||||
@@ -39,12 +39,12 @@ module.exports = {
|
|||||||
themes: [
|
themes: [
|
||||||
{
|
{
|
||||||
coollabs: {
|
coollabs: {
|
||||||
primary: "#323232",
|
primary: "#202020",
|
||||||
"primary-focus": "#242424",
|
"primary-focus": "#242424",
|
||||||
secondary: "#6B16ED",
|
secondary: "#6B16ED",
|
||||||
accent: "#4338ca",
|
accent: "#4338ca",
|
||||||
neutral: "#1B1D1D",
|
neutral: "#1B1D1D",
|
||||||
"base-100": "#181818",
|
"base-100": "#101010",
|
||||||
info: "#2563EB",
|
info: "#2563EB",
|
||||||
success: "#16A34A",
|
success: "#16A34A",
|
||||||
warning: "#FCD34D",
|
warning: "#FCD34D",
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
"version": "3.12.36"
|
"version": "3.12.36"
|
||||||
},
|
},
|
||||||
"v4": {
|
"v4": {
|
||||||
"version": "4.0.0-beta.119"
|
"version": "4.0.0-beta.121"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user