mirror of
https://github.com/ershisan99/coolify.git
synced 2026-01-04 20:52:05 +00:00
Compare commits
97 Commits
v4.0.0-bet
...
v4.0.0-bet
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b983b23e7e | ||
|
|
0b81e77a94 | ||
|
|
b8cf314bfe | ||
|
|
4a3338e59c | ||
|
|
5b8538c0f4 | ||
|
|
88d6320d08 | ||
|
|
651c9c2c9b | ||
|
|
8dd45cd388 | ||
|
|
126ac354d5 | ||
|
|
024769c402 | ||
|
|
5acf141669 | ||
|
|
92e3e8ab7b | ||
|
|
187a29c666 | ||
|
|
4c24631795 | ||
|
|
7d6bd10cca | ||
|
|
f8c86769a7 | ||
|
|
e0b0dda382 | ||
|
|
b8708f086e | ||
|
|
3539e4dce9 | ||
|
|
5fdadcf557 | ||
|
|
acb3f01f79 | ||
|
|
83becdb19d | ||
|
|
e3e8fe7895 | ||
|
|
6ddff8fae1 | ||
|
|
f5cb2dbdcf | ||
|
|
fe19769d82 | ||
|
|
45e404b15b | ||
|
|
5bdaa68368 | ||
|
|
d903a377bf | ||
|
|
8e7745f4c1 | ||
|
|
a9ea6330d9 | ||
|
|
bfb0260550 | ||
|
|
bba1cb3832 | ||
|
|
29ad2144b7 | ||
|
|
38d367e709 | ||
|
|
0e81ff970f | ||
|
|
00feef40a3 | ||
|
|
dfba593072 | ||
|
|
c770c8d988 | ||
|
|
0f071031a9 | ||
|
|
99efa857f4 | ||
|
|
80035395ff | ||
|
|
d3490e1c95 | ||
|
|
dab13c92eb | ||
|
|
1f18542960 | ||
|
|
8f21ea9367 | ||
|
|
73e64d9052 | ||
|
|
6cdd87da41 | ||
|
|
2a5d49f9b3 | ||
|
|
cc7ba9eb9f | ||
|
|
c4cc42c8d5 | ||
|
|
2d0838b112 | ||
|
|
07b94a8e48 | ||
|
|
4b08abc144 | ||
|
|
93e4fc2f32 | ||
|
|
6dd86eec30 | ||
|
|
a7ab5d55d3 | ||
|
|
689547463c | ||
|
|
8a0046c571 | ||
|
|
fb3991321a | ||
|
|
ca6543a919 | ||
|
|
364a6aa3a2 | ||
|
|
82b0667277 | ||
|
|
74c126c731 | ||
|
|
d87a0fe74f | ||
|
|
9a858f628d | ||
|
|
fed01fa9d2 | ||
|
|
e1468da36a | ||
|
|
ddfc1440cd | ||
|
|
5fc46384e6 | ||
|
|
48d9df1e43 | ||
|
|
6b62d91f82 | ||
|
|
e6ca8cd167 | ||
|
|
059748ad3b | ||
|
|
a334f998a2 | ||
|
|
53a5ccef31 | ||
|
|
9eea73cefb | ||
|
|
b210e1f243 | ||
|
|
ef3202101c | ||
|
|
22d5159d16 | ||
|
|
1cbd30bd9e | ||
|
|
ad54358de7 | ||
|
|
3689b58b92 | ||
|
|
5a4180a750 | ||
|
|
047922b13a | ||
|
|
798d747164 | ||
|
|
29676ffb22 | ||
|
|
8a50b063d4 | ||
|
|
3d2444ab2e | ||
|
|
7c395edab4 | ||
|
|
7e7f322e21 | ||
|
|
9350fb4b97 | ||
|
|
59c3cc6ce1 | ||
|
|
d7001937ac | ||
|
|
3fe58ec66b | ||
|
|
ed12f73483 | ||
|
|
f357f40fc7 |
21
README.md
21
README.md
@@ -10,6 +10,17 @@ No vendor lock-in, which means that all the configuration for your applications/
|
|||||||
|
|
||||||
For more information, take a look at our landing page [here](https://coolify.io).
|
For more information, take a look at our landing page [here](https://coolify.io).
|
||||||
|
|
||||||
|
# Installation
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -fsSL https://cdn.coollabs.io/coolify/install.sh | bash
|
||||||
|
```
|
||||||
|
You can find the installation script source [here](./scripts/install.sh).
|
||||||
|
|
||||||
|
# Support
|
||||||
|
|
||||||
|
Contact us [here](https://coolify.io/docs/contact).
|
||||||
|
|
||||||
# Donations
|
# Donations
|
||||||
To stay completely free, open-source, no feature behind paywall and evolve the project, we need your help. If you like Coolify, please consider donating to help us fund the future development of the project.
|
To stay completely free, open-source, no feature behind paywall and evolve the project, we need your help. If you like Coolify, please consider donating to help us fund the future development of the project.
|
||||||
|
|
||||||
@@ -66,16 +77,6 @@ By subscribing to the cloud version, you get the Coolify server for the same pri
|
|||||||
- Better support
|
- Better support
|
||||||
- Less maintenance for you
|
- Less maintenance for you
|
||||||
|
|
||||||
# Installation
|
|
||||||
|
|
||||||
```bash
|
|
||||||
curl -fsSL https://cdn.coollabs.io/coolify/install.sh | bash
|
|
||||||
```
|
|
||||||
You can find the installation script source [here](./scripts/install.sh).
|
|
||||||
|
|
||||||
# Support
|
|
||||||
|
|
||||||
Contact us [here](https://coolify.io/docs/contact).
|
|
||||||
|
|
||||||
# Recognitions
|
# Recognitions
|
||||||
|
|
||||||
|
|||||||
@@ -106,7 +106,6 @@ class StartMariadb
|
|||||||
$this->commands[] = "echo 'Pulling {$database->image} image.'";
|
$this->commands[] = "echo 'Pulling {$database->image} image.'";
|
||||||
$this->commands[] = "docker compose -f $this->configuration_dir/docker-compose.yml pull";
|
$this->commands[] = "docker compose -f $this->configuration_dir/docker-compose.yml pull";
|
||||||
$this->commands[] = "docker compose -f $this->configuration_dir/docker-compose.yml up -d";
|
$this->commands[] = "docker compose -f $this->configuration_dir/docker-compose.yml up -d";
|
||||||
$database_name = addslashes($database->name);
|
|
||||||
$this->commands[] = "echo 'Database started.'";
|
$this->commands[] = "echo 'Database started.'";
|
||||||
return remote_process($this->commands, $database->destination->server, callEventOnFinish: 'DatabaseStatusChanged');
|
return remote_process($this->commands, $database->destination->server, callEventOnFinish: 'DatabaseStatusChanged');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -122,7 +122,6 @@ class StartMongodb
|
|||||||
$this->commands[] = "echo 'Pulling {$database->image} image.'";
|
$this->commands[] = "echo 'Pulling {$database->image} image.'";
|
||||||
$this->commands[] = "docker compose -f $this->configuration_dir/docker-compose.yml pull";
|
$this->commands[] = "docker compose -f $this->configuration_dir/docker-compose.yml pull";
|
||||||
$this->commands[] = "docker compose -f $this->configuration_dir/docker-compose.yml up -d";
|
$this->commands[] = "docker compose -f $this->configuration_dir/docker-compose.yml up -d";
|
||||||
$database_name = addslashes($database->name);
|
|
||||||
$this->commands[] = "echo 'Database started.'";
|
$this->commands[] = "echo 'Database started.'";
|
||||||
return remote_process($this->commands, $database->destination->server, callEventOnFinish: 'DatabaseStatusChanged');
|
return remote_process($this->commands, $database->destination->server, callEventOnFinish: 'DatabaseStatusChanged');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -106,7 +106,6 @@ class StartMysql
|
|||||||
$this->commands[] = "echo 'Pulling {$database->image} image.'";
|
$this->commands[] = "echo 'Pulling {$database->image} image.'";
|
||||||
$this->commands[] = "docker compose -f $this->configuration_dir/docker-compose.yml pull";
|
$this->commands[] = "docker compose -f $this->configuration_dir/docker-compose.yml pull";
|
||||||
$this->commands[] = "docker compose -f $this->configuration_dir/docker-compose.yml up -d";
|
$this->commands[] = "docker compose -f $this->configuration_dir/docker-compose.yml up -d";
|
||||||
$database_name = addslashes($database->name);
|
|
||||||
$this->commands[] = "echo 'Database started.'";
|
$this->commands[] = "echo 'Database started.'";
|
||||||
return remote_process($this->commands, $database->destination->server,callEventOnFinish: 'DatabaseStatusChanged');
|
return remote_process($this->commands, $database->destination->server,callEventOnFinish: 'DatabaseStatusChanged');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -128,7 +128,6 @@ class StartPostgresql
|
|||||||
$this->commands[] = "echo 'Pulling {$database->image} image.'";
|
$this->commands[] = "echo 'Pulling {$database->image} image.'";
|
||||||
$this->commands[] = "docker compose -f $this->configuration_dir/docker-compose.yml pull";
|
$this->commands[] = "docker compose -f $this->configuration_dir/docker-compose.yml pull";
|
||||||
$this->commands[] = "docker compose -f $this->configuration_dir/docker-compose.yml up -d";
|
$this->commands[] = "docker compose -f $this->configuration_dir/docker-compose.yml up -d";
|
||||||
$database_name = addslashes($database->name);
|
|
||||||
$this->commands[] = "echo 'Database started.'";
|
$this->commands[] = "echo 'Database started.'";
|
||||||
return remote_process($this->commands, $database->destination->server, callEventOnFinish: 'DatabaseStatusChanged');
|
return remote_process($this->commands, $database->destination->server, callEventOnFinish: 'DatabaseStatusChanged');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -117,7 +117,6 @@ class StartRedis
|
|||||||
$this->commands[] = "echo 'Pulling {$database->image} image.'";
|
$this->commands[] = "echo 'Pulling {$database->image} image.'";
|
||||||
$this->commands[] = "docker compose -f $this->configuration_dir/docker-compose.yml pull";
|
$this->commands[] = "docker compose -f $this->configuration_dir/docker-compose.yml pull";
|
||||||
$this->commands[] = "docker compose -f $this->configuration_dir/docker-compose.yml up -d";
|
$this->commands[] = "docker compose -f $this->configuration_dir/docker-compose.yml up -d";
|
||||||
$database_name = addslashes($database->name);
|
|
||||||
$this->commands[] = "echo 'Database started.'";
|
$this->commands[] = "echo 'Database started.'";
|
||||||
return remote_process($this->commands, $database->destination->server, callEventOnFinish: 'DatabaseStatusChanged');
|
return remote_process($this->commands, $database->destination->server, callEventOnFinish: 'DatabaseStatusChanged');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -128,9 +128,9 @@ class InstallLogDrain
|
|||||||
if ($type !== 'custom') {
|
if ($type !== 'custom') {
|
||||||
$parsers = base64_encode("
|
$parsers = base64_encode("
|
||||||
[PARSER]
|
[PARSER]
|
||||||
Name empty_line_skipper
|
Name empty_line_skipper
|
||||||
Format regex
|
Format regex
|
||||||
Regex /^(?!\s*$).+/
|
Regex /^(?!\s*$).+/
|
||||||
");
|
");
|
||||||
}
|
}
|
||||||
$compose = base64_encode("
|
$compose = base64_encode("
|
||||||
@@ -198,7 +198,7 @@ Files:
|
|||||||
}
|
}
|
||||||
$restart_command = [
|
$restart_command = [
|
||||||
"echo 'Stopping old Fluent Bit'",
|
"echo 'Stopping old Fluent Bit'",
|
||||||
"cd $config_path && docker rm -f coolify-log-drain || true",
|
"cd $config_path && docker compose down --remove-orphans || true",
|
||||||
"echo 'Starting Fluent Bit'",
|
"echo 'Starting Fluent Bit'",
|
||||||
"cd $config_path && docker compose up -d --remove-orphans",
|
"cd $config_path && docker compose up -d --remove-orphans",
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -25,7 +25,6 @@ class UpdateCoolify
|
|||||||
CleanupDocker::run($this->server, false);
|
CleanupDocker::run($this->server, false);
|
||||||
$this->latestVersion = get_latest_version_of_coolify();
|
$this->latestVersion = get_latest_version_of_coolify();
|
||||||
$this->currentVersion = config('version');
|
$this->currentVersion = config('version');
|
||||||
ray('latest version:' . $this->latestVersion . " current version: " . $this->currentVersion . ' force: ' . $force);
|
|
||||||
if ($settings->next_channel) {
|
if ($settings->next_channel) {
|
||||||
ray('next channel enabled');
|
ray('next channel enabled');
|
||||||
$this->latestVersion = 'next';
|
$this->latestVersion = 'next';
|
||||||
@@ -44,7 +43,7 @@ class UpdateCoolify
|
|||||||
}
|
}
|
||||||
$this->update();
|
$this->update();
|
||||||
}
|
}
|
||||||
send_internal_notification('InstanceAutoUpdateJob done to version: ' . $this->latestVersion . ' from version: ' . $this->currentVersion);
|
send_internal_notification("Instance updated from {$this->currentVersion} -> {$this->latestVersion}");
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
ray('InstanceAutoUpdateJob failed');
|
ray('InstanceAutoUpdateJob failed');
|
||||||
ray($e->getMessage());
|
ray($e->getMessage());
|
||||||
|
|||||||
@@ -45,6 +45,9 @@ class DeleteService
|
|||||||
foreach ($service->databases()->get() as $database) {
|
foreach ($service->databases()->get() as $database) {
|
||||||
$database->forceDelete();
|
$database->forceDelete();
|
||||||
}
|
}
|
||||||
|
foreach ($service->scheduled_tasks as $task) {
|
||||||
|
$task->delete();
|
||||||
|
}
|
||||||
$service->tags()->detach();
|
$service->tags()->detach();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,10 +13,6 @@ class StartService
|
|||||||
{
|
{
|
||||||
ray('Starting service: ' . $service->name);
|
ray('Starting service: ' . $service->name);
|
||||||
$service->saveComposeConfigs();
|
$service->saveComposeConfigs();
|
||||||
|
|
||||||
$service_name = addslashes($service->name);
|
|
||||||
$server_name = addslashes($service->server->name);
|
|
||||||
|
|
||||||
$commands[] = "cd " . $service->workdir();
|
$commands[] = "cd " . $service->workdir();
|
||||||
$commands[] = "echo 'Saved configuration files to {$service->workdir()}.'";
|
$commands[] = "echo 'Saved configuration files to {$service->workdir()}.'";
|
||||||
$commands[] = "echo 'Creating Docker network.'";
|
$commands[] = "echo 'Creating Docker network.'";
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
namespace App\Console\Commands;
|
namespace App\Console\Commands;
|
||||||
|
|
||||||
use App\Models\Application;
|
use App\Models\Application;
|
||||||
|
use App\Models\ScheduledTask;
|
||||||
use App\Models\Service;
|
use App\Models\Service;
|
||||||
use App\Models\ServiceApplication;
|
use App\Models\ServiceApplication;
|
||||||
use App\Models\ServiceDatabase;
|
use App\Models\ServiceDatabase;
|
||||||
@@ -108,6 +109,17 @@ class CleanupStuckedResources extends Command
|
|||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
echo "Error in cleaning stuck serviceapp: {$e->getMessage()}\n";
|
echo "Error in cleaning stuck serviceapp: {$e->getMessage()}\n";
|
||||||
}
|
}
|
||||||
|
try {
|
||||||
|
$scheduled_tasks = ScheduledTask::all();
|
||||||
|
foreach ($scheduled_tasks as $scheduled_task) {
|
||||||
|
if (!$scheduled_task->service && !$scheduled_task->application) {
|
||||||
|
echo "Deleting stuck scheduledtask: {$scheduled_task->name}\n";
|
||||||
|
$scheduled_task->delete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
echo "Error in cleaning stuck scheduledtasks: {$e->getMessage()}\n";
|
||||||
|
}
|
||||||
|
|
||||||
// Cleanup any resources that are not attached to any environment or destination or server
|
// Cleanup any resources that are not attached to any environment or destination or server
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -125,6 +125,9 @@ class Init extends Command
|
|||||||
// Cleanup any failed deployments
|
// Cleanup any failed deployments
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
if (isCloud()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
$queued_inprogress_deployments = ApplicationDeploymentQueue::whereIn('status', [ApplicationDeploymentStatus::IN_PROGRESS->value, ApplicationDeploymentStatus::QUEUED->value])->get();
|
$queued_inprogress_deployments = ApplicationDeploymentQueue::whereIn('status', [ApplicationDeploymentStatus::IN_PROGRESS->value, ApplicationDeploymentStatus::QUEUED->value])->get();
|
||||||
foreach ($queued_inprogress_deployments as $deployment) {
|
foreach ($queued_inprogress_deployments as $deployment) {
|
||||||
ray($deployment->id, $deployment->status);
|
ray($deployment->id, $deployment->status);
|
||||||
|
|||||||
@@ -120,8 +120,8 @@ class Kernel extends ConsoleKernel
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
foreach ($scheduled_tasks as $scheduled_task) {
|
foreach ($scheduled_tasks as $scheduled_task) {
|
||||||
$service = $scheduled_task->service()->get();
|
$service = $scheduled_task->service;
|
||||||
$application = $scheduled_task->application()->get();
|
$application = $scheduled_task->application;
|
||||||
|
|
||||||
if (!$application && !$service) {
|
if (!$application && !$service) {
|
||||||
ray('application/service attached to scheduled task does not exist');
|
ray('application/service attached to scheduled task does not exist');
|
||||||
|
|||||||
@@ -18,8 +18,7 @@ class Deploy extends Controller
|
|||||||
{
|
{
|
||||||
public function deploy(Request $request)
|
public function deploy(Request $request)
|
||||||
{
|
{
|
||||||
$token = auth()->user()->currentAccessToken();
|
$teamId = get_team_id_from_token();
|
||||||
$teamId = data_get($token, 'team_id');
|
|
||||||
$uuids = $request->query->get('uuid');
|
$uuids = $request->query->get('uuid');
|
||||||
$tags = $request->query->get('tag');
|
$tags = $request->query->get('tag');
|
||||||
$force = $request->query->get('force') ?? false;
|
$force = $request->query->get('force') ?? false;
|
||||||
|
|||||||
39
app/Http/Controllers/Api/Project.php
Normal file
39
app/Http/Controllers/Api/Project.php
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers\Api;
|
||||||
|
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Models\Project as ModelsProject;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
|
class Project extends Controller
|
||||||
|
{
|
||||||
|
public function projects(Request $request)
|
||||||
|
{
|
||||||
|
$teamId = get_team_id_from_token();
|
||||||
|
if (is_null($teamId)) {
|
||||||
|
return response()->json(['error' => 'Invalid token.', 'docs' => 'https://coolify.io/docs/api/authentication'], 400);
|
||||||
|
}
|
||||||
|
$projects = ModelsProject::whereTeamId($teamId)->select('id', 'name', 'uuid')->get();
|
||||||
|
return response()->json($projects);
|
||||||
|
}
|
||||||
|
public function project_by_uuid(Request $request)
|
||||||
|
{
|
||||||
|
$teamId = get_team_id_from_token();
|
||||||
|
if (is_null($teamId)) {
|
||||||
|
return response()->json(['error' => 'Invalid token.', 'docs' => 'https://coolify.io/docs/api/authentication'], 400);
|
||||||
|
}
|
||||||
|
$project = ModelsProject::whereTeamId($teamId)->whereUuid(request()->uuid)->first()->load(['environments']);
|
||||||
|
return response()->json($project);
|
||||||
|
}
|
||||||
|
public function environment_details(Request $request)
|
||||||
|
{
|
||||||
|
$teamId = get_team_id_from_token();
|
||||||
|
if (is_null($teamId)) {
|
||||||
|
return response()->json(['error' => 'Invalid token.', 'docs' => 'https://coolify.io/docs/api/authentication'], 400);
|
||||||
|
}
|
||||||
|
$project = ModelsProject::whereTeamId($teamId)->whereUuid(request()->uuid)->first();
|
||||||
|
$environment = $project->environments()->whereName(request()->environment_name)->first()->load(['applications', 'postgresqls', 'redis', 'mongodbs', 'mysqls', 'mariadbs', 'services']);
|
||||||
|
return response()->json($environment);
|
||||||
|
}
|
||||||
|
}
|
||||||
54
app/Http/Controllers/Api/Server.php
Normal file
54
app/Http/Controllers/Api/Server.php
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers\Api;
|
||||||
|
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Models\Server as ModelsServer;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
|
class Server extends Controller
|
||||||
|
{
|
||||||
|
public function servers(Request $request)
|
||||||
|
{
|
||||||
|
$teamId = get_team_id_from_token();
|
||||||
|
if (is_null($teamId)) {
|
||||||
|
return response()->json(['error' => 'Invalid token.', 'docs' => 'https://coolify.io/docs/api/authentication'], 400);
|
||||||
|
}
|
||||||
|
$servers = ModelsServer::whereTeamId($teamId)->select('id', 'name', 'uuid', 'ip', 'user', 'port')->get()->load(['settings'])->map(function ($server) {
|
||||||
|
$server['is_reachable'] = $server->settings->is_reachable;
|
||||||
|
$server['is_usable'] = $server->settings->is_usable;
|
||||||
|
return $server;
|
||||||
|
});
|
||||||
|
ray($servers);
|
||||||
|
return response()->json($servers);
|
||||||
|
}
|
||||||
|
public function server_by_uuid(Request $request)
|
||||||
|
{
|
||||||
|
$teamId = get_team_id_from_token();
|
||||||
|
if (is_null($teamId)) {
|
||||||
|
return response()->json(['error' => 'Invalid token.', 'docs' => 'https://coolify.io/docs/api/authentication'], 400);
|
||||||
|
}
|
||||||
|
$server = ModelsServer::whereTeamId($teamId)->whereUuid(request()->uuid)->first();
|
||||||
|
if (is_null($server)) {
|
||||||
|
return response()->json(['error' => 'Server not found.'], 404);
|
||||||
|
}
|
||||||
|
$server->load(['settings']);
|
||||||
|
$server['resources'] = $server->definedResources()->map(function ($resource) {
|
||||||
|
$payload = [
|
||||||
|
'id' => $resource->id,
|
||||||
|
'uuid' => $resource->uuid,
|
||||||
|
'name' => $resource->name,
|
||||||
|
'type' => $resource->type(),
|
||||||
|
'created_at' => $resource->created_at,
|
||||||
|
'updated_at' => $resource->updated_at,
|
||||||
|
];
|
||||||
|
if ($resource->type() === 'service') {
|
||||||
|
$payload['status'] = $resource->status();
|
||||||
|
} else {
|
||||||
|
$payload['status'] = $resource->status;
|
||||||
|
}
|
||||||
|
return $payload;
|
||||||
|
});
|
||||||
|
return response()->json($server);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -133,6 +133,8 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
|
|||||||
$this->is_debug_enabled = $this->application->settings->is_debug_enabled;
|
$this->is_debug_enabled = $this->application->settings->is_debug_enabled;
|
||||||
|
|
||||||
$this->container_name = generateApplicationContainerName($this->application, $this->pull_request_id);
|
$this->container_name = generateApplicationContainerName($this->application, $this->pull_request_id);
|
||||||
|
ray('New container name: ', $this->container_name);
|
||||||
|
|
||||||
savePrivateKeyToFs($this->server);
|
savePrivateKeyToFs($this->server);
|
||||||
$this->saved_outputs = collect();
|
$this->saved_outputs = collect();
|
||||||
|
|
||||||
@@ -618,6 +620,9 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
$this->dockerImageTag = str($this->commit)->substr(0, 128);
|
$this->dockerImageTag = str($this->commit)->substr(0, 128);
|
||||||
|
if ($this->application->docker_registry_image_tag) {
|
||||||
|
$this->dockerImageTag = $this->application->docker_registry_image_tag;
|
||||||
|
}
|
||||||
if ($this->application->docker_registry_image_name) {
|
if ($this->application->docker_registry_image_name) {
|
||||||
$this->build_image_name = Str::lower("{$this->application->docker_registry_image_name}:{$this->dockerImageTag}-build");
|
$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}");
|
$this->production_image_name = Str::lower("{$this->application->docker_registry_image_name}:{$this->dockerImageTag}");
|
||||||
@@ -708,9 +713,14 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
|
|||||||
$this->write_deployment_configurations();
|
$this->write_deployment_configurations();
|
||||||
$this->server = $this->original_server;
|
$this->server = $this->original_server;
|
||||||
}
|
}
|
||||||
if (count($this->application->ports_mappings_array) > 0) {
|
if (count($this->application->ports_mappings_array) > 0 || (bool) $this->application->settings->is_consistent_container_name_enabled) {
|
||||||
$this->application_deployment_queue->addLogEntry("----------------------------------------");
|
$this->application_deployment_queue->addLogEntry("----------------------------------------");
|
||||||
$this->application_deployment_queue->addLogEntry("Application has ports mapped to the host system, rolling update is not supported.");
|
if (count($this->application->ports_mappings_array) > 0) {
|
||||||
|
$this->application_deployment_queue->addLogEntry("Application has ports mapped to the host system, rolling update is not supported.");
|
||||||
|
}
|
||||||
|
if ((bool) $this->application->settings->is_consistent_container_name_enabled) {
|
||||||
|
$this->application_deployment_queue->addLogEntry("Consistent container name feature enabled, rolling update is not supported.");
|
||||||
|
}
|
||||||
$this->stop_running_container(force: true);
|
$this->stop_running_container(force: true);
|
||||||
$this->start_by_compose_file();
|
$this->start_by_compose_file();
|
||||||
} else {
|
} else {
|
||||||
@@ -1012,11 +1022,15 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
|
|||||||
$this->env_nixpacks_args = collect([]);
|
$this->env_nixpacks_args = collect([]);
|
||||||
if ($this->pull_request_id === 0) {
|
if ($this->pull_request_id === 0) {
|
||||||
foreach ($this->application->nixpacks_environment_variables as $env) {
|
foreach ($this->application->nixpacks_environment_variables as $env) {
|
||||||
$this->env_nixpacks_args->push("--env {$env->key}={$env->real_value}");
|
if (!is_null($env->real_value)) {
|
||||||
|
$this->env_nixpacks_args->push("--env {$env->key}={$env->real_value}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
foreach ($this->application->nixpacks_environment_variables_preview as $env) {
|
foreach ($this->application->nixpacks_environment_variables_preview as $env) {
|
||||||
$this->env_nixpacks_args->push("--env {$env->key}={$env->real_value}");
|
if (!is_null($env->real_value)) {
|
||||||
|
$this->env_nixpacks_args->push("--env {$env->key}={$env->real_value}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1027,11 +1041,15 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
|
|||||||
$this->env_args = collect([]);
|
$this->env_args = collect([]);
|
||||||
if ($this->pull_request_id === 0) {
|
if ($this->pull_request_id === 0) {
|
||||||
foreach ($this->application->build_environment_variables as $env) {
|
foreach ($this->application->build_environment_variables as $env) {
|
||||||
$this->env_args->put($env->key, $env->real_value);
|
if (!is_null($env->real_value)) {
|
||||||
|
$this->env_args->put($env->key, $env->real_value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
foreach ($this->application->build_environment_variables_preview as $env) {
|
foreach ($this->application->build_environment_variables_preview as $env) {
|
||||||
$this->env_args->put($env->key, $env->real_value);
|
if (!is_null($env->real_value)) {
|
||||||
|
$this->env_args->put($env->key, $env->real_value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$this->env_args->put('SOURCE_COMMIT', $this->commit);
|
$this->env_args->put('SOURCE_COMMIT', $this->commit);
|
||||||
@@ -1196,13 +1214,18 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
|
|||||||
// ];
|
// ];
|
||||||
// }
|
// }
|
||||||
|
|
||||||
$docker_compose['services'][$this->application->uuid] = $docker_compose['services'][$this->container_name];
|
if ((bool)$this->application->settings->is_consistent_container_name_enabled) {
|
||||||
|
$custom_compose = convert_docker_run_to_compose($this->application->custom_docker_run_options);
|
||||||
data_forget($docker_compose, 'services.' . $this->container_name);
|
if (count($custom_compose) > 0) {
|
||||||
|
$docker_compose['services'][$this->container_name] = array_merge_recursive($docker_compose['services'][$this->container_name], $custom_compose);
|
||||||
$custom_compose = convert_docker_run_to_compose($this->application->custom_docker_run_options);
|
}
|
||||||
if (count($custom_compose) > 0) {
|
} else {
|
||||||
$docker_compose['services'][$this->application->uuid] = array_merge_recursive($docker_compose['services'][$this->application->uuid], $custom_compose);
|
$docker_compose['services'][$this->application->uuid] = $docker_compose['services'][$this->container_name];
|
||||||
|
data_forget($docker_compose, 'services.' . $this->container_name);
|
||||||
|
$custom_compose = convert_docker_run_to_compose($this->application->custom_docker_run_options);
|
||||||
|
if (count($custom_compose) > 0) {
|
||||||
|
$docker_compose['services'][$this->application->uuid] = array_merge_recursive($docker_compose['services'][$this->application->uuid], $custom_compose);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->docker_compose = Yaml::dump($docker_compose, 10);
|
$this->docker_compose = Yaml::dump($docker_compose, 10);
|
||||||
@@ -1487,6 +1510,11 @@ COPY ./nginx.conf /etc/nginx/conf.d/default.conf");
|
|||||||
[executeInDocker($this->deployment_uuid, "docker rm -f $containerName >/dev/null 2>&1"), "hidden" => true, "ignore_errors" => true],
|
[executeInDocker($this->deployment_uuid, "docker rm -f $containerName >/dev/null 2>&1"), "hidden" => true, "ignore_errors" => true],
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
if ($this->application->settings->is_consistent_container_name_enabled) {
|
||||||
|
$this->execute_remote_command(
|
||||||
|
[executeInDocker($this->deployment_uuid, "docker rm -f $this->container_name >/dev/null 2>&1"), "hidden" => true, "ignore_errors" => true],
|
||||||
|
);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
$this->application_deployment_queue->addLogEntry("New container is not healthy, rolling back to the old container.");
|
$this->application_deployment_queue->addLogEntry("New container is not healthy, rolling back to the old container.");
|
||||||
$this->application_deployment_queue->update([
|
$this->application_deployment_queue->update([
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ class ServerStatusJob implements ShouldQueue, ShouldBeEncrypted
|
|||||||
{
|
{
|
||||||
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||||
|
|
||||||
public ?int $disk_usage = null;
|
public int|string|null $disk_usage = null;
|
||||||
public $tries = 4;
|
public $tries = 4;
|
||||||
public function backoff(): int
|
public function backoff(): int
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -11,6 +11,9 @@ class Index extends Component
|
|||||||
public $users = [];
|
public $users = [];
|
||||||
public function mount()
|
public function mount()
|
||||||
{
|
{
|
||||||
|
if (!isCloud()) {
|
||||||
|
return redirect()->route('dashboard');
|
||||||
|
}
|
||||||
if (auth()->user()->id !== 0 && session('adminToken') === null) {
|
if (auth()->user()->id !== 0 && session('adminToken') === null) {
|
||||||
return redirect()->route('dashboard');
|
return redirect()->route('dashboard');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
namespace App\Livewire\Boarding;
|
namespace App\Livewire\Boarding;
|
||||||
|
|
||||||
use App\Actions\Server\InstallDocker;
|
use App\Actions\Server\InstallDocker;
|
||||||
|
use App\Enums\ProxyTypes;
|
||||||
use App\Models\PrivateKey;
|
use App\Models\PrivateKey;
|
||||||
use App\Models\Project;
|
use App\Models\Project;
|
||||||
use App\Models\Server;
|
use App\Models\Server;
|
||||||
@@ -121,15 +122,16 @@ uZx9iFkCELtxrh31QJ68AAAAEXNhaWxANzZmZjY2ZDJlMmRkAQIDBA==
|
|||||||
}
|
}
|
||||||
$this->selectedExistingPrivateKey = $this->createdServer->privateKey->id;
|
$this->selectedExistingPrivateKey = $this->createdServer->privateKey->id;
|
||||||
$this->serverPublicKey = $this->createdServer->privateKey->publicKey();
|
$this->serverPublicKey = $this->createdServer->privateKey->publicKey();
|
||||||
$this->validateServer();
|
$this->installServer();
|
||||||
}
|
}
|
||||||
public function getProxyType()
|
public function getProxyType()
|
||||||
{
|
{
|
||||||
$proxyTypeSet = $this->createdServer->proxy->type;
|
$this->selectProxy(ProxyTypes::TRAEFIK_V2->value);
|
||||||
if (!$proxyTypeSet) {
|
// $proxyTypeSet = $this->createdServer->proxy->type;
|
||||||
$this->currentState = 'select-proxy';
|
// if (!$proxyTypeSet) {
|
||||||
return;
|
// $this->currentState = 'select-proxy';
|
||||||
}
|
// return;
|
||||||
|
// }
|
||||||
$this->getProjects();
|
$this->getProjects();
|
||||||
}
|
}
|
||||||
public function selectExistingPrivateKey()
|
public function selectExistingPrivateKey()
|
||||||
@@ -193,7 +195,7 @@ uZx9iFkCELtxrh31QJ68AAAAEXNhaWxANzZmZjY2ZDJlMmRkAQIDBA==
|
|||||||
$this->createdServer->settings->is_cloudflare_tunnel = $this->isCloudflareTunnel;
|
$this->createdServer->settings->is_cloudflare_tunnel = $this->isCloudflareTunnel;
|
||||||
$this->createdServer->settings->save();
|
$this->createdServer->settings->save();
|
||||||
$this->createdServer->addInitialNetwork();
|
$this->createdServer->addInitialNetwork();
|
||||||
$this->validateServer();
|
$this->currentState = 'validate-server';
|
||||||
}
|
}
|
||||||
public function installServer()
|
public function installServer()
|
||||||
{
|
{
|
||||||
@@ -204,7 +206,8 @@ uZx9iFkCELtxrh31QJ68AAAAEXNhaWxANzZmZjY2ZDJlMmRkAQIDBA==
|
|||||||
try {
|
try {
|
||||||
config()->set('coolify.mux_enabled', false);
|
config()->set('coolify.mux_enabled', false);
|
||||||
|
|
||||||
instant_remote_process(['uptime'], $this->createdServer, true);
|
// EC2 does not have `uptime` command, lol
|
||||||
|
instant_remote_process(['ls /'], $this->createdServer, true);
|
||||||
|
|
||||||
$this->createdServer->settings()->update([
|
$this->createdServer->settings()->update([
|
||||||
'is_reachable' => true,
|
'is_reachable' => true,
|
||||||
@@ -219,7 +222,7 @@ uZx9iFkCELtxrh31QJ68AAAAEXNhaWxANzZmZjY2ZDJlMmRkAQIDBA==
|
|||||||
$dockerVersion = instant_remote_process(["docker version|head -2|grep -i version| awk '{print $2}'"], $this->createdServer, true);
|
$dockerVersion = instant_remote_process(["docker version|head -2|grep -i version| awk '{print $2}'"], $this->createdServer, true);
|
||||||
$dockerVersion = checkMinimumDockerEngineVersion($dockerVersion);
|
$dockerVersion = checkMinimumDockerEngineVersion($dockerVersion);
|
||||||
if (is_null($dockerVersion)) {
|
if (is_null($dockerVersion)) {
|
||||||
$this->currentState = 'install-docker';
|
$this->currentState = 'validate-server';
|
||||||
throw new \Exception('Docker not found or old version is installed.');
|
throw new \Exception('Docker not found or old version is installed.');
|
||||||
}
|
}
|
||||||
$this->createdServer->settings()->update([
|
$this->createdServer->settings()->update([
|
||||||
@@ -227,27 +230,10 @@ uZx9iFkCELtxrh31QJ68AAAAEXNhaWxANzZmZjY2ZDJlMmRkAQIDBA==
|
|||||||
]);
|
]);
|
||||||
$this->getProxyType();
|
$this->getProxyType();
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
// $this->dockerInstallationStarted = false;
|
|
||||||
return handleError(error: $e, livewire: $this);
|
return handleError(error: $e, livewire: $this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public function installDocker()
|
public function selectProxy(?string $proxyType = null)
|
||||||
{
|
|
||||||
try {
|
|
||||||
$this->dockerInstallationStarted = true;
|
|
||||||
$activity = InstallDocker::run($this->createdServer);
|
|
||||||
$this->dispatch('installDocker');
|
|
||||||
$this->dispatch('activityMonitor', $activity->id);
|
|
||||||
} catch (\Throwable $e) {
|
|
||||||
$this->dockerInstallationStarted = false;
|
|
||||||
return handleError(error: $e, livewire: $this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public function dockerInstalledOrSkipped()
|
|
||||||
{
|
|
||||||
$this->validateServer();
|
|
||||||
}
|
|
||||||
public function selectProxy(string|null $proxyType = null)
|
|
||||||
{
|
{
|
||||||
if (!$proxyType) {
|
if (!$proxyType) {
|
||||||
return $this->getProjects();
|
return $this->getProjects();
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ class Dashboard extends Component
|
|||||||
}
|
}
|
||||||
public function cleanup_queue()
|
public function cleanup_queue()
|
||||||
{
|
{
|
||||||
|
$this->dispatch('success', 'Cleanup started.');
|
||||||
Artisan::queue('app:init', [
|
Artisan::queue('app:init', [
|
||||||
'--cleanup-deployments' => 'true'
|
'--cleanup-deployments' => 'true'
|
||||||
]);
|
]);
|
||||||
|
|||||||
@@ -8,20 +8,25 @@ use Livewire\Component;
|
|||||||
class Advanced extends Component
|
class Advanced extends Component
|
||||||
{
|
{
|
||||||
public Application $application;
|
public Application $application;
|
||||||
|
public bool $is_force_https_enabled;
|
||||||
protected $rules = [
|
protected $rules = [
|
||||||
'application.settings.is_git_submodules_enabled' => 'boolean|required',
|
'application.settings.is_git_submodules_enabled' => 'boolean|required',
|
||||||
'application.settings.is_git_lfs_enabled' => 'boolean|required',
|
'application.settings.is_git_lfs_enabled' => 'boolean|required',
|
||||||
'application.settings.is_preview_deployments_enabled' => 'boolean|required',
|
'application.settings.is_preview_deployments_enabled' => 'boolean|required',
|
||||||
'application.settings.is_auto_deploy_enabled' => 'boolean|required',
|
'application.settings.is_auto_deploy_enabled' => 'boolean|required',
|
||||||
'application.settings.is_force_https_enabled' => 'boolean|required',
|
'is_force_https_enabled' => 'boolean|required',
|
||||||
'application.settings.is_log_drain_enabled' => 'boolean|required',
|
'application.settings.is_log_drain_enabled' => 'boolean|required',
|
||||||
'application.settings.is_gpu_enabled' => 'boolean|required',
|
'application.settings.is_gpu_enabled' => 'boolean|required',
|
||||||
'application.settings.is_build_server_enabled' => 'boolean|required',
|
'application.settings.is_build_server_enabled' => 'boolean|required',
|
||||||
|
'application.settings.is_consistent_container_name_enabled' => 'boolean|required',
|
||||||
'application.settings.gpu_driver' => 'string|required',
|
'application.settings.gpu_driver' => 'string|required',
|
||||||
'application.settings.gpu_count' => 'string|required',
|
'application.settings.gpu_count' => 'string|required',
|
||||||
'application.settings.gpu_device_ids' => 'string|required',
|
'application.settings.gpu_device_ids' => 'string|required',
|
||||||
'application.settings.gpu_options' => 'string|required',
|
'application.settings.gpu_options' => 'string|required',
|
||||||
];
|
];
|
||||||
|
public function mount() {
|
||||||
|
$this->is_force_https_enabled = $this->application->settings->is_force_https_enabled;
|
||||||
|
}
|
||||||
public function instantSave()
|
public function instantSave()
|
||||||
{
|
{
|
||||||
if ($this->application->isLogDrainEnabled()) {
|
if ($this->application->isLogDrainEnabled()) {
|
||||||
@@ -31,7 +36,8 @@ class Advanced extends Component
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ($this->application->settings->is_force_https_enabled) {
|
if ($this->application->settings->is_force_https_enabled !== $this->is_force_https_enabled) {
|
||||||
|
$this->application->settings->is_force_https_enabled = $this->is_force_https_enabled;
|
||||||
$this->dispatch('resetDefaultLabels', false);
|
$this->dispatch('resetDefaultLabels', false);
|
||||||
}
|
}
|
||||||
$this->application->settings->save();
|
$this->application->settings->save();
|
||||||
|
|||||||
@@ -126,7 +126,6 @@ class General extends Component
|
|||||||
$this->application->save();
|
$this->application->save();
|
||||||
}
|
}
|
||||||
$this->initialDockerComposeLocation = $this->application->docker_compose_location;
|
$this->initialDockerComposeLocation = $this->application->docker_compose_location;
|
||||||
$this->checkLabelUpdates();
|
|
||||||
}
|
}
|
||||||
public function instantSave()
|
public function instantSave()
|
||||||
{
|
{
|
||||||
@@ -164,6 +163,7 @@ class General extends Component
|
|||||||
}
|
}
|
||||||
return $domain;
|
return $domain;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function updatedApplicationBuildPack()
|
public function updatedApplicationBuildPack()
|
||||||
{
|
{
|
||||||
if ($this->application->build_pack !== 'nixpacks') {
|
if ($this->application->build_pack !== 'nixpacks') {
|
||||||
@@ -184,15 +184,6 @@ class General extends Component
|
|||||||
$this->submit();
|
$this->submit();
|
||||||
$this->dispatch('build_pack_updated');
|
$this->dispatch('build_pack_updated');
|
||||||
}
|
}
|
||||||
public function checkLabelUpdates()
|
|
||||||
{
|
|
||||||
if (md5($this->application->custom_labels) !== md5(implode("|", generateLabelsApplication($this->application)))) {
|
|
||||||
$this->labelsChanged = true;
|
|
||||||
} else {
|
|
||||||
$this->labelsChanged = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getWildcardDomain()
|
public function getWildcardDomain()
|
||||||
{
|
{
|
||||||
$server = data_get($this->application, 'destination.server');
|
$server = data_get($this->application, 'destination.server');
|
||||||
@@ -212,6 +203,13 @@ class General extends Component
|
|||||||
|
|
||||||
public function updatedApplicationFqdn()
|
public function updatedApplicationFqdn()
|
||||||
{
|
{
|
||||||
|
$this->application->fqdn = str($this->application->fqdn)->replaceEnd(',', '')->trim();
|
||||||
|
$this->application->fqdn = str($this->application->fqdn)->replaceStart(',', '')->trim();
|
||||||
|
$this->application->fqdn = str($this->application->fqdn)->trim()->explode(',')->map(function ($domain) {
|
||||||
|
return str($domain)->trim()->lower();
|
||||||
|
});
|
||||||
|
$this->application->fqdn = $this->application->fqdn->unique()->implode(',');
|
||||||
|
$this->application->save();
|
||||||
$this->resetDefaultLabels(false);
|
$this->resetDefaultLabels(false);
|
||||||
// $this->dispatch('success', 'Labels reset to default!');
|
// $this->dispatch('success', 'Labels reset to default!');
|
||||||
}
|
}
|
||||||
@@ -238,22 +236,17 @@ class General extends Component
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
if (data_get($this->application, 'fqdn')) {
|
if (data_get($this->application, 'fqdn')) {
|
||||||
$this->application->fqdn = str($this->application->fqdn)->replaceEnd(',', '')->trim();
|
$domains = str($this->application->fqdn)->trim()->explode(',');
|
||||||
$domains = str($this->application->fqdn)->trim()->explode(',')->map(function ($domain) {
|
|
||||||
return str($domain)->trim()->lower();
|
|
||||||
});
|
|
||||||
$domains = $domains->unique();
|
|
||||||
if ($this->application->additional_servers->count() === 0) {
|
if ($this->application->additional_servers->count() === 0) {
|
||||||
foreach ($domains as $domain) {
|
foreach ($domains as $domain) {
|
||||||
if (!validate_dns_entry($domain, $this->application->destination->server)) {
|
if (!validate_dns_entry($domain, $this->application->destination->server)) {
|
||||||
$showToaster && $this->dispatch('error', "Validating DNS ($domain) failed.","Make sure you have added the DNS records correctly.<br><br>Check this <a target='_blank' class='text-white underline' href='https://coolify.io/docs/dns-settings'>documentation</a> for further help.");
|
$showToaster && $this->dispatch('error', "Validating DNS ($domain) failed.", "Make sure you have added the DNS records correctly.<br><br>Check this <a target='_blank' class='text-white underline' href='https://coolify.io/docs/dns-settings'>documentation</a> for further help.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
check_fqdn_usage($this->application);
|
check_fqdn_usage($this->application);
|
||||||
$this->application->fqdn = $domains->implode(',');
|
$this->application->fqdn = $domains->implode(',');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data_get($this->application, 'custom_docker_run_options')) {
|
if (data_get($this->application, 'custom_docker_run_options')) {
|
||||||
$this->application->custom_docker_run_options = str($this->application->custom_docker_run_options)->trim();
|
$this->application->custom_docker_run_options = str($this->application->custom_docker_run_options)->trim();
|
||||||
}
|
}
|
||||||
@@ -279,7 +272,6 @@ class General extends Component
|
|||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
return handleError($e, $this);
|
return handleError($e, $this);
|
||||||
} finally {
|
} finally {
|
||||||
$this->checkLabelUpdates();
|
|
||||||
$this->isConfigurationChanged = $this->application->isConfigurationChanged();
|
$this->isConfigurationChanged = $this->application->isConfigurationChanged();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,15 +56,15 @@ class Heading extends Component
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if ($this->application->destination->server->isSwarm() && str($this->application->docker_registry_image_name)->isEmpty()) {
|
if ($this->application->destination->server->isSwarm() && str($this->application->docker_registry_image_name)->isEmpty()) {
|
||||||
$this->dispatch('error', 'Failed to deploy', 'To deploy to a Swarm cluster you must set a Docker image name first.');
|
$this->dispatch('error', 'Failed to deploy.', 'To deploy to a Swarm cluster you must set a Docker image name first.');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (data_get($this->application, 'settings.is_build_server_enabled') && str($this->application->docker_registry_image_name)->isEmpty()) {
|
if (data_get($this->application, 'settings.is_build_server_enabled') && str($this->application->docker_registry_image_name)->isEmpty()) {
|
||||||
$this->dispatch('error', 'Failed to deploy', 'To use a build server, you must first set a Docker image.<br>More information here: <a target="_blank" class="underline" href="https://coolify.io/docs/server/build-server">documentation</a>');
|
$this->dispatch('error', 'Failed to deploy.', 'To use a build server, you must first set a Docker image.<br>More information here: <a target="_blank" class="underline" href="https://coolify.io/docs/server/build-server">documentation</a>');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if ($this->application->additional_servers->count() > 0 && str($this->application->docker_registry_image_name)->isEmpty()) {
|
if ($this->application->additional_servers->count() > 0 && str($this->application->docker_registry_image_name)->isEmpty()) {
|
||||||
$this->dispatch('error', 'Failed to deploy', 'To deploy to more than one server, you must first set a Docker image.<br>More information here: <a target="_blank" class="underline" href="https://coolify.io/docs/server/build-server">documentation</a>');
|
$this->dispatch('error', 'Failed to deploy.', 'Before deploying to multiple servers, you must first set a Docker image in the General tab.<br>More information here: <a target="_blank" class="underline" href="https://coolify.io/docs/server/multiple-servers">documentation</a>');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
$this->setDeploymentUuid();
|
$this->setDeploymentUuid();
|
||||||
@@ -103,7 +103,7 @@ class Heading extends Component
|
|||||||
public function restart()
|
public function restart()
|
||||||
{
|
{
|
||||||
if ($this->application->additional_servers->count() > 0 && str($this->application->docker_registry_image_name)->isEmpty()) {
|
if ($this->application->additional_servers->count() > 0 && str($this->application->docker_registry_image_name)->isEmpty()) {
|
||||||
$this->dispatch('error', 'Failed to deploy', 'To deploy to more than one server, you must first set a Docker image.<br>More information here: <a target="_blank" class="underline" href="https://coolify.io/docs/server/build-server">documentation</a>');
|
$this->dispatch('error', 'Failed to deploy', 'Before deploying to multiple servers, you must first set a Docker image in the General tab.<br>More information here: <a target="_blank" class="underline" href="https://coolify.io/docs/server/multiple-servers">documentation</a>');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
$this->setDeploymentUuid();
|
$this->setDeploymentUuid();
|
||||||
|
|||||||
@@ -104,7 +104,7 @@ class Index extends Component
|
|||||||
'environment_name' => data_get($service, 'environment.name'),
|
'environment_name' => data_get($service, 'environment.name'),
|
||||||
'service_uuid' => data_get($service, 'uuid')
|
'service_uuid' => data_get($service, 'uuid')
|
||||||
]);
|
]);
|
||||||
$service->status = serviceStatus($service);
|
$service->status = $service->status();
|
||||||
}
|
}
|
||||||
return $service;
|
return $service;
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ class FileStorage extends Component
|
|||||||
$this->fileStorage->content = null;
|
$this->fileStorage->content = null;
|
||||||
}
|
}
|
||||||
$this->fileStorage->save();
|
$this->fileStorage->save();
|
||||||
$this->fileStorage->saveStorageOnServer($this->service);
|
$this->fileStorage->saveStorageOnServer();
|
||||||
$this->dispatch('success', 'File updated successfully.');
|
$this->dispatch('success', 'File updated successfully.');
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
$this->fileStorage->setRawAttributes($original);
|
$this->fileStorage->setRawAttributes($original);
|
||||||
|
|||||||
@@ -27,12 +27,12 @@ class Index extends Component
|
|||||||
$this->parameters = get_route_parameters();
|
$this->parameters = get_route_parameters();
|
||||||
$this->query = request()->query();
|
$this->query = request()->query();
|
||||||
$this->service = Service::whereUuid($this->parameters['service_uuid'])->firstOrFail();
|
$this->service = Service::whereUuid($this->parameters['service_uuid'])->firstOrFail();
|
||||||
$service = $this->service->applications()->whereName($this->parameters['service_name'])->first();
|
$service = $this->service->applications()->whereUuid($this->parameters['stack_service_uuid'])->first();
|
||||||
if ($service) {
|
if ($service) {
|
||||||
$this->serviceApplication = $service;
|
$this->serviceApplication = $service;
|
||||||
$this->serviceApplication->getFilesFromServer();
|
$this->serviceApplication->getFilesFromServer();
|
||||||
} else {
|
} else {
|
||||||
$this->serviceDatabase = $this->service->databases()->whereName($this->parameters['service_name'])->first();
|
$this->serviceDatabase = $this->service->databases()->whereUuid($this->parameters['stack_service_uuid'])->first();
|
||||||
$this->serviceDatabase->getFilesFromServer();
|
$this->serviceDatabase->getFilesFromServer();
|
||||||
}
|
}
|
||||||
$this->s3s = currentTeam()->s3s;
|
$this->s3s = currentTeam()->s3s;
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ class ServiceApplicationView extends Component
|
|||||||
'application.exclude_from_status' => 'required|boolean',
|
'application.exclude_from_status' => 'required|boolean',
|
||||||
'application.required_fqdn' => 'required|boolean',
|
'application.required_fqdn' => 'required|boolean',
|
||||||
'application.is_log_drain_enabled' => 'nullable|boolean',
|
'application.is_log_drain_enabled' => 'nullable|boolean',
|
||||||
|
'application.is_gzip_enabled' => 'nullable|boolean',
|
||||||
];
|
];
|
||||||
public function render()
|
public function render()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -45,8 +45,10 @@ class StackForm extends Component
|
|||||||
$this->service->docker_compose_raw = $raw;
|
$this->service->docker_compose_raw = $raw;
|
||||||
$this->submit();
|
$this->submit();
|
||||||
}
|
}
|
||||||
public function instantSave() {
|
public function instantSave()
|
||||||
|
{
|
||||||
$this->service->save();
|
$this->service->save();
|
||||||
|
$this->dispatch('success', 'Service settings saved successfully.');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function submit()
|
public function submit()
|
||||||
|
|||||||
@@ -37,10 +37,16 @@ class Destination extends Component
|
|||||||
$this->networks = $this->networks->reject(function ($network) use ($all_networks) {
|
$this->networks = $this->networks->reject(function ($network) use ($all_networks) {
|
||||||
return $all_networks->pluck('id')->contains($network->id);
|
return $all_networks->pluck('id')->contains($network->id);
|
||||||
});
|
});
|
||||||
|
$this->networks = $this->networks->reject(function ($network) {
|
||||||
|
return $this->resource->destination->server->id == $network->server->id;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
public function redeploy(int $network_id, int $server_id)
|
public function redeploy(int $network_id, int $server_id)
|
||||||
{
|
{
|
||||||
|
if ($this->resource->additional_servers->count() > 0 && str($this->resource->docker_registry_image_name)->isEmpty()) {
|
||||||
|
$this->dispatch('error', 'Failed to deploy.', 'Before deploying to multiple servers, you must first set a Docker image in the General tab.<br>More information here: <a target="_blank" class="underline" href="https://coolify.io/docs/server/multiple-servers">documentation</a>');
|
||||||
|
return;
|
||||||
|
}
|
||||||
$deployment_uuid = new Cuid2(7);
|
$deployment_uuid = new Cuid2(7);
|
||||||
$server = Server::find($server_id);
|
$server = Server::find($server_id);
|
||||||
$destination = StandaloneDocker::find($network_id);
|
$destination = StandaloneDocker::find($network_id);
|
||||||
@@ -67,7 +73,7 @@ class Destination extends Component
|
|||||||
}
|
}
|
||||||
public function removeServer(int $network_id, int $server_id)
|
public function removeServer(int $network_id, int $server_id)
|
||||||
{
|
{
|
||||||
if ($this->resource->destination->server->id == $server_id) {
|
if ($this->resource->destination->server->id == $server_id && $this->resource->destination->id == $network_id) {
|
||||||
$this->dispatch('error', 'You cannot remove this destination server.', 'You are trying to remove the main server.');
|
$this->dispatch('error', 'You cannot remove this destination server.', 'You are trying to remove the main server.');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,8 +13,9 @@ class Form extends Component
|
|||||||
public ?string $wildcard_domain = null;
|
public ?string $wildcard_domain = null;
|
||||||
public int $cleanup_after_percentage;
|
public int $cleanup_after_percentage;
|
||||||
public bool $dockerInstallationStarted = false;
|
public bool $dockerInstallationStarted = false;
|
||||||
|
public bool $revalidate = false;
|
||||||
|
|
||||||
protected $listeners = ['serverInstalled'];
|
protected $listeners = ['serverInstalled', 'revalidate' => '$refresh'];
|
||||||
|
|
||||||
protected $rules = [
|
protected $rules = [
|
||||||
'server.name' => 'required',
|
'server.name' => 'required',
|
||||||
@@ -68,6 +69,10 @@ class Form extends Component
|
|||||||
return handleError($e, $this);
|
return handleError($e, $this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
public function revalidate()
|
||||||
|
{
|
||||||
|
$this->revalidate = true;
|
||||||
|
}
|
||||||
public function checkLocalhostConnection()
|
public function checkLocalhostConnection()
|
||||||
{
|
{
|
||||||
$uptime = $this->server->validateConnection();
|
$uptime = $this->server->validateConnection();
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ class Status extends Component
|
|||||||
public Server $server;
|
public Server $server;
|
||||||
public bool $polling = false;
|
public bool $polling = false;
|
||||||
public int $numberOfPolls = 0;
|
public int $numberOfPolls = 0;
|
||||||
protected $listeners = ['proxyStatusUpdated', 'startProxyPolling'];
|
protected $listeners = ['proxyStatusUpdated' => '$refresh', 'startProxyPolling'];
|
||||||
|
|
||||||
public function startProxyPolling()
|
public function startProxyPolling()
|
||||||
{
|
{
|
||||||
|
|||||||
64
app/Livewire/Server/Resources.php
Normal file
64
app/Livewire/Server/Resources.php
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Livewire\Server;
|
||||||
|
|
||||||
|
use App\Models\Server;
|
||||||
|
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
|
||||||
|
use Illuminate\Support\Collection;
|
||||||
|
use Livewire\Component;
|
||||||
|
|
||||||
|
class Resources extends Component
|
||||||
|
{
|
||||||
|
use AuthorizesRequests;
|
||||||
|
public ?Server $server = null;
|
||||||
|
public $parameters = [];
|
||||||
|
public Collection $unmanagedContainers;
|
||||||
|
public function getListeners()
|
||||||
|
{
|
||||||
|
$teamId = auth()->user()->currentTeam()->id;
|
||||||
|
return [
|
||||||
|
"echo-private:team.{$teamId},ApplicationStatusChanged" => 'refreshStatus',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function startUnmanaged($id) {
|
||||||
|
$this->server->startUnmanaged($id);
|
||||||
|
$this->dispatch('success', 'Container started.');
|
||||||
|
$this->loadUnmanagedContainers();
|
||||||
|
}
|
||||||
|
public function restartUnmanaged($id) {
|
||||||
|
$this->server->restartUnmanaged($id);
|
||||||
|
$this->dispatch('success', 'Container restarted.');
|
||||||
|
$this->loadUnmanagedContainers();
|
||||||
|
}
|
||||||
|
public function stopUnmanaged($id) {
|
||||||
|
$this->server->stopUnmanaged($id);
|
||||||
|
$this->dispatch('success', 'Container stopped.');
|
||||||
|
$this->loadUnmanagedContainers();
|
||||||
|
}
|
||||||
|
public function refreshStatus() {
|
||||||
|
$this->server->refresh();
|
||||||
|
$this->loadUnmanagedContainers();
|
||||||
|
$this->dispatch('success', 'Resource statuses refreshed.');
|
||||||
|
}
|
||||||
|
public function loadUnmanagedContainers() {
|
||||||
|
$this->unmanagedContainers = $this->server->loadUnmanagedContainers();
|
||||||
|
}
|
||||||
|
public function mount() {
|
||||||
|
$this->unmanagedContainers = collect();
|
||||||
|
$this->parameters = get_route_parameters();
|
||||||
|
try {
|
||||||
|
$this->server = Server::ownedByCurrentTeam()->whereUuid(request()->server_uuid)->first();
|
||||||
|
if (is_null($this->server)) {
|
||||||
|
return redirect()->route('server.index');
|
||||||
|
}
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
return handleError($e, $this);
|
||||||
|
}
|
||||||
|
$this->loadUnmanagedContainers();
|
||||||
|
}
|
||||||
|
public function render()
|
||||||
|
{
|
||||||
|
return view('livewire.server.resources');
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
namespace App\Livewire\Server;
|
namespace App\Livewire\Server;
|
||||||
|
|
||||||
|
use App\Actions\Proxy\StartProxy;
|
||||||
use App\Models\Server;
|
use App\Models\Server;
|
||||||
use Livewire\Component;
|
use Livewire\Component;
|
||||||
|
|
||||||
@@ -14,8 +15,11 @@ class ValidateAndInstall extends Component
|
|||||||
public $uptime = null;
|
public $uptime = null;
|
||||||
public $supported_os_type = null;
|
public $supported_os_type = null;
|
||||||
public $docker_installed = null;
|
public $docker_installed = null;
|
||||||
|
public $docker_compose_installed = null;
|
||||||
public $docker_version = null;
|
public $docker_version = null;
|
||||||
|
public $proxy_started = false;
|
||||||
public $error = null;
|
public $error = null;
|
||||||
|
public bool $ask = false;
|
||||||
|
|
||||||
protected $listeners = ['validateServer' => 'init', 'validateDockerEngine', 'validateServerNow' => 'validateServer'];
|
protected $listeners = ['validateServer' => 'init', 'validateDockerEngine', 'validateServerNow' => 'validateServer'];
|
||||||
|
|
||||||
@@ -26,11 +30,18 @@ class ValidateAndInstall extends Component
|
|||||||
$this->supported_os_type = null;
|
$this->supported_os_type = null;
|
||||||
$this->docker_installed = null;
|
$this->docker_installed = null;
|
||||||
$this->docker_version = null;
|
$this->docker_version = null;
|
||||||
|
$this->docker_compose_installed = null;
|
||||||
|
$this->proxy_started = null;
|
||||||
$this->error = null;
|
$this->error = null;
|
||||||
$this->number_of_tries = 0;
|
$this->number_of_tries = 0;
|
||||||
$this->dispatch('validateServerNow');
|
if (!$this->ask) {
|
||||||
|
$this->dispatch('validateServerNow');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public function startValidatingAfterAsking() {
|
||||||
|
$this->ask = false;
|
||||||
|
$this->init();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function validateServer()
|
public function validateServer()
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
@@ -43,6 +54,11 @@ class ValidateAndInstall extends Component
|
|||||||
if ($swarmInstalled) {
|
if ($swarmInstalled) {
|
||||||
$this->dispatch('success', 'Docker Swarm is initiated.');
|
$this->dispatch('success', 'Docker Swarm is initiated.');
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
$proxy = StartProxy::run($this->server);
|
||||||
|
if ($proxy) {
|
||||||
|
$this->proxy_started = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
return handleError($e, $this);
|
return handleError($e, $this);
|
||||||
@@ -67,9 +83,9 @@ class ValidateAndInstall extends Component
|
|||||||
public function validateDockerEngine()
|
public function validateDockerEngine()
|
||||||
{
|
{
|
||||||
$this->docker_installed = $this->server->validateDockerEngine();
|
$this->docker_installed = $this->server->validateDockerEngine();
|
||||||
if (!$this->docker_installed) {
|
$this->docker_compose_installed = $this->server->validateDockerCompose();
|
||||||
|
if (!$this->docker_installed || !$this->docker_compose_installed) {
|
||||||
if ($this->install) {
|
if ($this->install) {
|
||||||
ray($this->number_of_tries, $this->max_tries);
|
|
||||||
if ($this->number_of_tries == $this->max_tries) {
|
if ($this->number_of_tries == $this->max_tries) {
|
||||||
$this->error = 'Docker Engine could not be installed. Please install Docker manually before continuing: <a target="_blank" class="underline" href="https://docs.docker.com/engine/install/#server">documentation</a>.';
|
$this->error = 'Docker Engine could not be installed. Please install Docker manually before continuing: <a target="_blank" class="underline" href="https://docs.docker.com/engine/install/#server">documentation</a>.';
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ use App\Enums\ApplicationDeploymentStatus;
|
|||||||
use Illuminate\Database\Eloquent\Casts\Attribute;
|
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||||
|
use Illuminate\Support\Collection;
|
||||||
use Spatie\Activitylog\Models\Activity;
|
use Spatie\Activitylog\Models\Activity;
|
||||||
use Illuminate\Support\Str;
|
use Illuminate\Support\Str;
|
||||||
use RuntimeException;
|
use RuntimeException;
|
||||||
@@ -48,6 +49,9 @@ class Application extends BaseModel
|
|||||||
$application->persistentStorages()->delete();
|
$application->persistentStorages()->delete();
|
||||||
$application->environment_variables()->delete();
|
$application->environment_variables()->delete();
|
||||||
$application->environment_variables_preview()->delete();
|
$application->environment_variables_preview()->delete();
|
||||||
|
foreach ($application->scheduled_tasks as $task) {
|
||||||
|
$task->delete();
|
||||||
|
}
|
||||||
$application->tags()->detach();
|
$application->tags()->detach();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -200,9 +204,6 @@ class Application extends BaseModel
|
|||||||
set: fn ($value) => $value === "" ? null : $value,
|
set: fn ($value) => $value === "" ? null : $value,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Normal Deployments
|
|
||||||
|
|
||||||
public function portsMappingsArray(): Attribute
|
public function portsMappingsArray(): Attribute
|
||||||
{
|
{
|
||||||
return Attribute::make(
|
return Attribute::make(
|
||||||
@@ -212,9 +213,13 @@ class Application extends BaseModel
|
|||||||
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
public function isExited()
|
||||||
|
{
|
||||||
|
return (bool) str($this->status)->startsWith('exited');
|
||||||
|
}
|
||||||
public function realStatus()
|
public function realStatus()
|
||||||
{
|
{
|
||||||
return $this->getRawOriginal('status');
|
return $this->getRawOriginal('status');
|
||||||
}
|
}
|
||||||
public function status(): Attribute
|
public function status(): Attribute
|
||||||
{
|
{
|
||||||
@@ -470,7 +475,7 @@ class Application extends BaseModel
|
|||||||
{
|
{
|
||||||
return data_get($this, 'settings.is_log_drain_enabled', false);
|
return data_get($this, 'settings.is_log_drain_enabled', false);
|
||||||
}
|
}
|
||||||
public function isConfigurationChanged($save = false)
|
public function isConfigurationChanged(bool $save = false)
|
||||||
{
|
{
|
||||||
$newConfigHash = $this->fqdn . $this->git_repository . $this->git_branch . $this->git_commit_sha . $this->build_pack . $this->static_image . $this->install_command . $this->build_command . $this->start_command . $this->port_exposes . $this->port_mappings . $this->base_directory . $this->publish_directory . $this->dockerfile . $this->dockerfile_location . $this->custom_labels;
|
$newConfigHash = $this->fqdn . $this->git_repository . $this->git_branch . $this->git_commit_sha . $this->build_pack . $this->static_image . $this->install_command . $this->build_command . $this->start_command . $this->port_exposes . $this->port_mappings . $this->base_directory . $this->publish_directory . $this->dockerfile . $this->dockerfile_location . $this->custom_labels;
|
||||||
if ($this->pull_request_id === 0 || $this->pull_request_id === null) {
|
if ($this->pull_request_id === 0 || $this->pull_request_id === null) {
|
||||||
@@ -518,17 +523,21 @@ class Application extends BaseModel
|
|||||||
{
|
{
|
||||||
return "/artifacts/{$uuid}";
|
return "/artifacts/{$uuid}";
|
||||||
}
|
}
|
||||||
function setGitImportSettings(string $deployment_uuid, string $git_clone_command)
|
function setGitImportSettings(string $deployment_uuid, string $git_clone_command, bool $public = false)
|
||||||
{
|
{
|
||||||
$baseDir = $this->generateBaseDir($deployment_uuid);
|
$baseDir = $this->generateBaseDir($deployment_uuid);
|
||||||
|
|
||||||
if ($this->git_commit_sha !== 'HEAD') {
|
if ($this->git_commit_sha !== 'HEAD') {
|
||||||
$git_clone_command = "{$git_clone_command} && cd {$baseDir} && git -c advice.detachedHead=false checkout {$this->git_commit_sha} >/dev/null 2>&1";
|
$git_clone_command = "{$git_clone_command} && cd {$baseDir} && GIT_SSH_COMMAND=\"ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null\" git -c advice.detachedHead=false checkout {$this->git_commit_sha} >/dev/null 2>&1";
|
||||||
}
|
}
|
||||||
if ($this->settings->is_git_submodules_enabled) {
|
if ($this->settings->is_git_submodules_enabled) {
|
||||||
$git_clone_command = "{$git_clone_command} && cd {$baseDir} && git submodule update --init --recursive";
|
if ($public) {
|
||||||
|
$git_clone_command = "{$git_clone_command} && cd {$baseDir} && sed -i \"s#git@\(.*\):#https://\\1/#g\" {$baseDir}/.gitmodules || true";
|
||||||
|
}
|
||||||
|
$git_clone_command = "{$git_clone_command} && cd {$baseDir} && GIT_SSH_COMMAND=\"ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null\" git submodule update --init --recursive";
|
||||||
}
|
}
|
||||||
if ($this->settings->is_git_lfs_enabled) {
|
if ($this->settings->is_git_lfs_enabled) {
|
||||||
$git_clone_command = "{$git_clone_command} && cd {$baseDir} && git lfs pull";
|
$git_clone_command = "{$git_clone_command} && cd {$baseDir} && GIT_SSH_COMMAND=\"ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null\" git lfs pull";
|
||||||
}
|
}
|
||||||
return $git_clone_command;
|
return $git_clone_command;
|
||||||
}
|
}
|
||||||
@@ -556,7 +565,7 @@ class Application extends BaseModel
|
|||||||
$fullRepoUrl = "{$this->source->html_url}/{$customRepository}";
|
$fullRepoUrl = "{$this->source->html_url}/{$customRepository}";
|
||||||
$git_clone_command = "{$git_clone_command} {$this->source->html_url}/{$customRepository} {$baseDir}";
|
$git_clone_command = "{$git_clone_command} {$this->source->html_url}/{$customRepository} {$baseDir}";
|
||||||
if (!$only_checkout) {
|
if (!$only_checkout) {
|
||||||
$git_clone_command = $this->setGitImportSettings($deployment_uuid, $git_clone_command);
|
$git_clone_command = $this->setGitImportSettings($deployment_uuid, $git_clone_command, public: true);
|
||||||
}
|
}
|
||||||
if ($exec_in_docker) {
|
if ($exec_in_docker) {
|
||||||
$commands->push(executeInDocker($deployment_uuid, $git_clone_command));
|
$commands->push(executeInDocker($deployment_uuid, $git_clone_command));
|
||||||
@@ -655,7 +664,7 @@ class Application extends BaseModel
|
|||||||
if ($this->deploymentType() === 'other') {
|
if ($this->deploymentType() === 'other') {
|
||||||
$fullRepoUrl = $customRepository;
|
$fullRepoUrl = $customRepository;
|
||||||
$git_clone_command = "{$git_clone_command} {$customRepository} {$baseDir}";
|
$git_clone_command = "{$git_clone_command} {$customRepository} {$baseDir}";
|
||||||
$git_clone_command = $this->setGitImportSettings($deployment_uuid, $git_clone_command);
|
$git_clone_command = $this->setGitImportSettings($deployment_uuid, $git_clone_command, public: true);
|
||||||
|
|
||||||
if ($pull_request_id !== 0) {
|
if ($pull_request_id !== 0) {
|
||||||
if ($git_type === 'gitlab') {
|
if ($git_type === 'gitlab') {
|
||||||
|
|||||||
@@ -26,7 +26,6 @@ class Environment extends Model
|
|||||||
{
|
{
|
||||||
return $this->hasMany(Application::class);
|
return $this->hasMany(Application::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function postgresqls()
|
public function postgresqls()
|
||||||
{
|
{
|
||||||
return $this->hasMany(StandalonePostgresql::class);
|
return $this->hasMany(StandalonePostgresql::class);
|
||||||
|
|||||||
@@ -10,20 +10,37 @@ class LocalFileVolume extends BaseModel
|
|||||||
use HasFactory;
|
use HasFactory;
|
||||||
protected $guarded = [];
|
protected $guarded = [];
|
||||||
|
|
||||||
|
protected static function booted()
|
||||||
|
{
|
||||||
|
static::created(function (LocalFileVolume $fileVolume) {
|
||||||
|
$fileVolume->load(['service']);
|
||||||
|
$fileVolume->saveStorageOnServer();
|
||||||
|
});
|
||||||
|
}
|
||||||
public function service()
|
public function service()
|
||||||
{
|
{
|
||||||
return $this->morphTo('resource');
|
return $this->morphTo('resource');
|
||||||
}
|
}
|
||||||
public function saveStorageOnServer(ServiceApplication|ServiceDatabase $service)
|
public function saveStorageOnServer()
|
||||||
{
|
{
|
||||||
$workdir = $service->service->workdir();
|
$workdir = $this->resource->service->workdir();
|
||||||
$server = $service->service->server;
|
$server = $this->resource->service->server;
|
||||||
$commands = collect([
|
$commands = collect([
|
||||||
"mkdir -p $workdir > /dev/null 2>&1 || true",
|
"mkdir -p $workdir > /dev/null 2>&1 || true",
|
||||||
"cd $workdir"
|
"cd $workdir"
|
||||||
]);
|
]);
|
||||||
|
$is_directory = $this->is_directory;
|
||||||
|
if ($is_directory) {
|
||||||
|
$commands->push("mkdir -p $this->fs_path > /dev/null 2>&1 || true");
|
||||||
|
}
|
||||||
|
if (str($this->fs_path)->startsWith('.') || str($this->fs_path)->startsWith('/') || str($this->fs_path)->startsWith('~')) {
|
||||||
|
$parent_dir = str($this->fs_path)->beforeLast('/');
|
||||||
|
if ($parent_dir != '') {
|
||||||
|
$commands->push("mkdir -p $parent_dir > /dev/null 2>&1 || true");
|
||||||
|
}
|
||||||
|
}
|
||||||
$fileVolume = $this;
|
$fileVolume = $this;
|
||||||
$path = Str::of(data_get($fileVolume, 'fs_path'));
|
$path = str(data_get($fileVolume, 'fs_path'));
|
||||||
$content = data_get($fileVolume, 'content');
|
$content = data_get($fileVolume, 'content');
|
||||||
if ($path->startsWith('.')) {
|
if ($path->startsWith('.')) {
|
||||||
$path = $path->after('.');
|
$path = $path->after('.');
|
||||||
@@ -32,17 +49,18 @@ class LocalFileVolume extends BaseModel
|
|||||||
$isFile = instant_remote_process(["test -f $path && echo OK || echo NOK"], $server);
|
$isFile = instant_remote_process(["test -f $path && echo OK || echo NOK"], $server);
|
||||||
$isDir = instant_remote_process(["test -d $path && echo OK || echo NOK"], $server);
|
$isDir = instant_remote_process(["test -d $path && echo OK || echo NOK"], $server);
|
||||||
if ($isFile == 'OK' && $fileVolume->is_directory) {
|
if ($isFile == 'OK' && $fileVolume->is_directory) {
|
||||||
throw new \Exception("File $path is a file on the server, but you are trying to mark it as a directory. Please delete the file on the server or mark it as directory.");
|
throw new \Exception("The following file is a file on the server, but you are trying to mark it as a directory. Please delete the file on the server or mark it as directory.");
|
||||||
} else if ($isDir == 'OK' && !$fileVolume->is_directory) {
|
} else if ($isDir == 'OK' && !$fileVolume->is_directory) {
|
||||||
throw new \Exception("File $path is a directory on the server, but you are trying to mark it as a file. Please delete the directory on the server or mark it as directory.");
|
throw new \Exception("The following file is a directory on the server, but you are trying to mark it as a file. <br><br>Please delete the directory on the server or mark it as directory.");
|
||||||
}
|
}
|
||||||
if (!$fileVolume->is_directory && $isDir == 'NOK') {
|
if (!$fileVolume->is_directory && $isDir == 'NOK') {
|
||||||
$content = base64_encode($content);
|
if ($content) {
|
||||||
$commands->push("echo '$content' | base64 -d > $path");
|
$content = base64_encode($content);
|
||||||
} else if ($isDir == 'NOK' && $fileVolume->is_directory) {
|
$commands->push("echo '$content' | base64 -d > $path");
|
||||||
|
}
|
||||||
|
} else if ($isDir == 'NOK' && $fileVolume->is_directory) {
|
||||||
$commands->push("mkdir -p $path > /dev/null 2>&1 || true");
|
$commands->push("mkdir -p $path > /dev/null 2>&1 || true");
|
||||||
}
|
}
|
||||||
ray($commands->toArray());
|
|
||||||
return instant_remote_process($commands, $server);
|
return instant_remote_process($commands, $server);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,10 @@ use Illuminate\Database\Eloquent\Model;
|
|||||||
|
|
||||||
class ProjectSetting extends Model
|
class ProjectSetting extends Model
|
||||||
{
|
{
|
||||||
protected $fillable = [
|
protected $guarded = [];
|
||||||
'project_id'
|
|
||||||
];
|
public function project()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Project::class);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -225,6 +225,32 @@ class Server extends BaseModel
|
|||||||
$services = $this->services();
|
$services = $this->services();
|
||||||
return $applications->concat($databases)->concat($services->get());
|
return $applications->concat($databases)->concat($services->get());
|
||||||
}
|
}
|
||||||
|
public function stopUnmanaged($id)
|
||||||
|
{
|
||||||
|
return instant_remote_process(["docker stop -t 0 $id"], $this);
|
||||||
|
}
|
||||||
|
public function restartUnmanaged($id)
|
||||||
|
{
|
||||||
|
return instant_remote_process(["docker restart $id"], $this);
|
||||||
|
}
|
||||||
|
public function startUnmanaged($id)
|
||||||
|
{
|
||||||
|
return instant_remote_process(["docker start $id"], $this);
|
||||||
|
}
|
||||||
|
public function loadUnmanagedContainers()
|
||||||
|
{
|
||||||
|
$containers = instant_remote_process(["docker ps -a --format '{{json .}}' "], $this);
|
||||||
|
$containers = format_docker_command_output_to_json($containers);
|
||||||
|
$containers = $containers->map(function ($container) {
|
||||||
|
$labels = data_get($container, 'Labels');
|
||||||
|
if (!str($labels)->contains("coolify.managed")) {
|
||||||
|
return $container;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
$containers = $containers->filter();
|
||||||
|
return collect($containers);
|
||||||
|
}
|
||||||
public function hasDefinedResources()
|
public function hasDefinedResources()
|
||||||
{
|
{
|
||||||
$applications = $this->applications()->count() > 0;
|
$applications = $this->applications()->count() > 0;
|
||||||
@@ -245,6 +271,8 @@ class Server extends BaseModel
|
|||||||
$mysqls = data_get($standaloneDocker, 'mysqls', collect([]));
|
$mysqls = data_get($standaloneDocker, 'mysqls', collect([]));
|
||||||
$mariadbs = data_get($standaloneDocker, 'mariadbs', collect([]));
|
$mariadbs = data_get($standaloneDocker, 'mariadbs', collect([]));
|
||||||
return $postgresqls->concat($redis)->concat($mongodbs)->concat($mysqls)->concat($mariadbs);
|
return $postgresqls->concat($redis)->concat($mongodbs)->concat($mysqls)->concat($mariadbs);
|
||||||
|
})->filter(function ($item) {
|
||||||
|
return data_get($item, 'name') !== 'coolify-db';
|
||||||
})->flatten();
|
})->flatten();
|
||||||
}
|
}
|
||||||
public function applications()
|
public function applications()
|
||||||
@@ -400,7 +428,9 @@ class Server extends BaseModel
|
|||||||
if ($server->skipServer()) {
|
if ($server->skipServer()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
$uptime = instant_remote_process(['uptime'], $server, false);
|
// EC2 does not have `uptime` command, lol
|
||||||
|
|
||||||
|
$uptime = instant_remote_process(['ls /'], $server, false);
|
||||||
if (!$uptime) {
|
if (!$uptime) {
|
||||||
$server->settings()->update([
|
$server->settings()->update([
|
||||||
'is_reachable' => false,
|
'is_reachable' => false,
|
||||||
@@ -443,6 +473,21 @@ class Server extends BaseModel
|
|||||||
$this->validateCoolifyNetwork(isSwarm: false, isBuildServer: $this->settings->is_build_server);
|
$this->validateCoolifyNetwork(isSwarm: false, isBuildServer: $this->settings->is_build_server);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
public function validateDockerCompose($throwError = false)
|
||||||
|
{
|
||||||
|
$dockerCompose = instant_remote_process(["docker compose version"], $this, false);
|
||||||
|
if (is_null($dockerCompose)) {
|
||||||
|
$this->settings->is_usable = false;
|
||||||
|
$this->settings->save();
|
||||||
|
if ($throwError) {
|
||||||
|
throw new \Exception('Server is not usable. Docker Compose is not installed.');
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$this->settings->is_usable = true;
|
||||||
|
$this->settings->save();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
public function validateDockerSwarm()
|
public function validateDockerSwarm()
|
||||||
{
|
{
|
||||||
$swarmStatus = instant_remote_process(["docker info|grep -i swarm"], $this, false);
|
$swarmStatus = instant_remote_process(["docker info|grep -i swarm"], $this, false);
|
||||||
|
|||||||
@@ -28,6 +28,48 @@ class Service extends BaseModel
|
|||||||
{
|
{
|
||||||
return $this->morphToMany(Tag::class, 'taggable');
|
return $this->morphToMany(Tag::class, 'taggable');
|
||||||
}
|
}
|
||||||
|
public function status() {
|
||||||
|
$foundRunning = false;
|
||||||
|
$isDegraded = false;
|
||||||
|
$foundRestaring = false;
|
||||||
|
$applications = $this->applications;
|
||||||
|
$databases = $this->databases;
|
||||||
|
foreach ($applications as $application) {
|
||||||
|
if ($application->exclude_from_status) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (Str::of($application->status)->startsWith('running')) {
|
||||||
|
$foundRunning = true;
|
||||||
|
} else if (Str::of($application->status)->startsWith('restarting')) {
|
||||||
|
$foundRestaring = true;
|
||||||
|
} else {
|
||||||
|
$isDegraded = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
foreach ($databases as $database) {
|
||||||
|
if ($database->exclude_from_status) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (Str::of($database->status)->startsWith('running')) {
|
||||||
|
$foundRunning = true;
|
||||||
|
} else if (Str::of($database->status)->startsWith('restarting')) {
|
||||||
|
$foundRestaring = true;
|
||||||
|
} else {
|
||||||
|
$isDegraded = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($foundRestaring) {
|
||||||
|
return 'degraded';
|
||||||
|
}
|
||||||
|
if ($foundRunning && !$isDegraded) {
|
||||||
|
return 'running';
|
||||||
|
} else if ($foundRunning && $isDegraded) {
|
||||||
|
return 'degraded';
|
||||||
|
} else if (!$foundRunning && !$isDegraded) {
|
||||||
|
return 'exited';
|
||||||
|
}
|
||||||
|
return 'exited';
|
||||||
|
}
|
||||||
public function extraFields()
|
public function extraFields()
|
||||||
{
|
{
|
||||||
$fields = collect([]);
|
$fields = collect([]);
|
||||||
|
|||||||
@@ -23,6 +23,10 @@ class ServiceApplication extends BaseModel
|
|||||||
{
|
{
|
||||||
return data_get($this, 'is_log_drain_enabled', false);
|
return data_get($this, 'is_log_drain_enabled', false);
|
||||||
}
|
}
|
||||||
|
public function isGzipEnabled()
|
||||||
|
{
|
||||||
|
return data_get($this, 'is_gzip_enabled', true);
|
||||||
|
}
|
||||||
public function type()
|
public function type()
|
||||||
{
|
{
|
||||||
return 'service';
|
return 'service';
|
||||||
|
|||||||
@@ -21,6 +21,10 @@ class ServiceDatabase extends BaseModel
|
|||||||
{
|
{
|
||||||
return data_get($this, 'is_log_drain_enabled', false);
|
return data_get($this, 'is_log_drain_enabled', false);
|
||||||
}
|
}
|
||||||
|
public function isGzipEnabled()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
public function type()
|
public function type()
|
||||||
{
|
{
|
||||||
return 'service';
|
return 'service';
|
||||||
|
|||||||
@@ -82,6 +82,9 @@ class StandaloneMariadb extends BaseModel
|
|||||||
{
|
{
|
||||||
return $this->morphToMany(Tag::class, 'taggable');
|
return $this->morphToMany(Tag::class, 'taggable');
|
||||||
}
|
}
|
||||||
|
public function project() {
|
||||||
|
return data_get($this, 'environment.project');
|
||||||
|
}
|
||||||
public function team()
|
public function team()
|
||||||
{
|
{
|
||||||
return data_get($this, 'environment.project.team');
|
return data_get($this, 'environment.project.team');
|
||||||
|
|||||||
@@ -85,6 +85,9 @@ class StandaloneMongodb extends BaseModel
|
|||||||
{
|
{
|
||||||
return $this->morphToMany(Tag::class, 'taggable');
|
return $this->morphToMany(Tag::class, 'taggable');
|
||||||
}
|
}
|
||||||
|
public function project() {
|
||||||
|
return data_get($this, 'environment.project');
|
||||||
|
}
|
||||||
public function team()
|
public function team()
|
||||||
{
|
{
|
||||||
return data_get($this, 'environment.project.team');
|
return data_get($this, 'environment.project.team');
|
||||||
|
|||||||
@@ -82,6 +82,9 @@ class StandaloneMysql extends BaseModel
|
|||||||
{
|
{
|
||||||
return $this->morphToMany(Tag::class, 'taggable');
|
return $this->morphToMany(Tag::class, 'taggable');
|
||||||
}
|
}
|
||||||
|
public function project() {
|
||||||
|
return data_get($this, 'environment.project');
|
||||||
|
}
|
||||||
public function team()
|
public function team()
|
||||||
{
|
{
|
||||||
return data_get($this, 'environment.project.team');
|
return data_get($this, 'environment.project.team');
|
||||||
|
|||||||
@@ -82,6 +82,10 @@ class StandalonePostgresql extends BaseModel
|
|||||||
{
|
{
|
||||||
return $this->morphToMany(Tag::class, 'taggable');
|
return $this->morphToMany(Tag::class, 'taggable');
|
||||||
}
|
}
|
||||||
|
public function project()
|
||||||
|
{
|
||||||
|
return data_get($this, 'environment.project');
|
||||||
|
}
|
||||||
public function link()
|
public function link()
|
||||||
{
|
{
|
||||||
if (data_get($this, 'environment.project.uuid')) {
|
if (data_get($this, 'environment.project.uuid')) {
|
||||||
|
|||||||
@@ -77,6 +77,10 @@ class StandaloneRedis extends BaseModel
|
|||||||
{
|
{
|
||||||
return $this->morphToMany(Tag::class, 'taggable');
|
return $this->morphToMany(Tag::class, 'taggable');
|
||||||
}
|
}
|
||||||
|
public function project()
|
||||||
|
{
|
||||||
|
return data_get($this, 'environment.project');
|
||||||
|
}
|
||||||
public function team()
|
public function team()
|
||||||
{
|
{
|
||||||
return data_get($this, 'environment.project.team');
|
return data_get($this, 'environment.project.team');
|
||||||
|
|||||||
@@ -15,8 +15,9 @@ class Services extends Component
|
|||||||
public function __construct(
|
public function __construct(
|
||||||
public Service $service,
|
public Service $service,
|
||||||
public string $complexStatus = 'exited',
|
public string $complexStatus = 'exited',
|
||||||
|
public bool $showRefreshButton = true
|
||||||
) {
|
) {
|
||||||
$this->complexStatus = serviceStatus($service);
|
$this->complexStatus = $service->status();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
7
bootstrap/helpers/api.php
Normal file
7
bootstrap/helpers/api.php
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
function get_team_id_from_token()
|
||||||
|
{
|
||||||
|
$token = auth()->user()->currentAccessToken();
|
||||||
|
return data_get($token, 'team_id');
|
||||||
|
}
|
||||||
@@ -13,6 +13,11 @@ const VALID_CRON_STRINGS = [
|
|||||||
const RESTART_MODE = 'unless-stopped';
|
const RESTART_MODE = 'unless-stopped';
|
||||||
|
|
||||||
const DATABASE_DOCKER_IMAGES = [
|
const DATABASE_DOCKER_IMAGES = [
|
||||||
|
'bitnami/mariadb',
|
||||||
|
'bitnami/mongodb',
|
||||||
|
'bitnami/mysql',
|
||||||
|
'bitnami/postgresql',
|
||||||
|
'bitnami/redis',
|
||||||
'mysql',
|
'mysql',
|
||||||
'mariadb',
|
'mariadb',
|
||||||
'postgres',
|
'postgres',
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ use App\Models\ServiceApplication;
|
|||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
use Illuminate\Support\Str;
|
use Illuminate\Support\Str;
|
||||||
use Spatie\Url\Url;
|
use Spatie\Url\Url;
|
||||||
use Visus\Cuid2\Cuid2;
|
|
||||||
|
|
||||||
function getCurrentApplicationContainerStatus(Server $server, int $id, ?int $pullRequestId = null): Collection
|
function getCurrentApplicationContainerStatus(Server $server, int $id, ?int $pullRequestId = null): Collection
|
||||||
{
|
{
|
||||||
@@ -123,10 +122,14 @@ function getContainerStatus(Server $server, string $container_id, bool $all_data
|
|||||||
|
|
||||||
function generateApplicationContainerName(Application $application, $pull_request_id = 0)
|
function generateApplicationContainerName(Application $application, $pull_request_id = 0)
|
||||||
{
|
{
|
||||||
|
$consistent_container_name = $application->settings->is_consistent_container_name_enabled;
|
||||||
$now = now()->format('Hisu');
|
$now = now()->format('Hisu');
|
||||||
if ($pull_request_id !== 0 && $pull_request_id !== null) {
|
if ($pull_request_id !== 0 && $pull_request_id !== null) {
|
||||||
return $application->uuid . '-pr-' . $pull_request_id;
|
return $application->uuid . '-pr-' . $pull_request_id;
|
||||||
} else {
|
} else {
|
||||||
|
if ($consistent_container_name) {
|
||||||
|
return $application->uuid;
|
||||||
|
}
|
||||||
return $application->uuid . '-' . $now;
|
return $application->uuid . '-' . $now;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -209,15 +212,48 @@ function generateServiceSpecificFqdns(ServiceApplication|Application $resource,
|
|||||||
}
|
}
|
||||||
return $payload;
|
return $payload;
|
||||||
}
|
}
|
||||||
function fqdnLabelsForTraefik(string $uuid, Collection $domains, bool $is_force_https_enabled = false, $onlyPort = null)
|
function fqdnLabelsForTraefik(string $uuid, Collection $domains, bool $is_force_https_enabled = false, $onlyPort = null, ?Collection $serviceLabels = null, ?bool $is_gzip_enabled = true)
|
||||||
{
|
{
|
||||||
$labels = collect([]);
|
$labels = collect([]);
|
||||||
$labels->push('traefik.enable=true');
|
$labels->push('traefik.enable=true');
|
||||||
$labels->push("traefik.http.middlewares.gzip.compress=true");
|
$labels->push("traefik.http.middlewares.gzip.compress=true");
|
||||||
$labels->push("traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https");
|
$labels->push("traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https");
|
||||||
|
|
||||||
|
$basic_auth = false;
|
||||||
|
$basic_auth_middleware = null;
|
||||||
|
$redirect = false;
|
||||||
|
$redirect_middleware = null;
|
||||||
|
if ($serviceLabels) {
|
||||||
|
$basic_auth = $serviceLabels->contains(function ($value) {
|
||||||
|
return str_contains($value, 'basicauth');
|
||||||
|
});
|
||||||
|
if ($basic_auth) {
|
||||||
|
$basic_auth_middleware = $serviceLabels
|
||||||
|
->map(function ($item) {
|
||||||
|
if (preg_match('/traefik\.http\.middlewares\.(.*?)\.basicauth\.users/', $item, $matches)) {
|
||||||
|
return $matches[1];
|
||||||
|
}
|
||||||
|
})
|
||||||
|
->filter()
|
||||||
|
->first();
|
||||||
|
}
|
||||||
|
$redirect = $serviceLabels->contains(function ($value) {
|
||||||
|
return str_contains($value, 'redirectregex');
|
||||||
|
});
|
||||||
|
if ($redirect) {
|
||||||
|
$redirect_middleware = $serviceLabels
|
||||||
|
->map(function ($item) {
|
||||||
|
if (preg_match('/traefik\.http\.middlewares\.(.*?)\.redirectregex\.regex/', $item, $matches)) {
|
||||||
|
return $matches[1];
|
||||||
|
}
|
||||||
|
})
|
||||||
|
->filter()
|
||||||
|
->first();
|
||||||
|
}
|
||||||
|
}
|
||||||
foreach ($domains as $loop => $domain) {
|
foreach ($domains as $loop => $domain) {
|
||||||
try {
|
try {
|
||||||
$uuid = new Cuid2(7);
|
// $uuid = new Cuid2(7);
|
||||||
$url = Url::fromString($domain);
|
$url = Url::fromString($domain);
|
||||||
$host = $url->getHost();
|
$host = $url->getHost();
|
||||||
$path = $url->getPath();
|
$path = $url->getPath();
|
||||||
@@ -239,11 +275,36 @@ function fqdnLabelsForTraefik(string $uuid, Collection $domains, bool $is_force_
|
|||||||
}
|
}
|
||||||
if ($path !== '/') {
|
if ($path !== '/') {
|
||||||
$labels->push("traefik.http.middlewares.{$https_label}-stripprefix.stripprefix.prefixes={$path}");
|
$labels->push("traefik.http.middlewares.{$https_label}-stripprefix.stripprefix.prefixes={$path}");
|
||||||
$labels->push("traefik.http.routers.{$https_label}.middlewares={$https_label}-stripprefix,gzip");
|
$middlewares = collect(["{$https_label}-stripprefix"]);
|
||||||
|
if ($is_gzip_enabled) {
|
||||||
|
$middlewares->push('gzip');
|
||||||
|
}
|
||||||
|
if ($basic_auth && $basic_auth_middleware) {
|
||||||
|
$middlewares->push($basic_auth_middleware);
|
||||||
|
}
|
||||||
|
if ($redirect && $redirect_middleware) {
|
||||||
|
$middlewares->push($redirect_middleware);
|
||||||
|
}
|
||||||
|
if ($middlewares->isNotEmpty()) {
|
||||||
|
$middlewares = $middlewares->join(',');
|
||||||
|
$labels->push("traefik.http.routers.{$https_label}.middlewares={$middlewares}");
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
$labels->push("traefik.http.routers.{$https_label}.middlewares=gzip");
|
$middlewares = collect([]);
|
||||||
|
if ($is_gzip_enabled) {
|
||||||
|
$middlewares->push('gzip');
|
||||||
|
}
|
||||||
|
if ($basic_auth && $basic_auth_middleware) {
|
||||||
|
$middlewares->push($basic_auth_middleware);
|
||||||
|
}
|
||||||
|
if ($redirect && $redirect_middleware) {
|
||||||
|
$middlewares->push($redirect_middleware);
|
||||||
|
}
|
||||||
|
if ($middlewares->isNotEmpty()) {
|
||||||
|
$middlewares = $middlewares->join(',');
|
||||||
|
$labels->push("traefik.http.routers.{$https_label}.middlewares={$middlewares}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$labels->push("traefik.http.routers.{$https_label}.tls=true");
|
$labels->push("traefik.http.routers.{$https_label}.tls=true");
|
||||||
$labels->push("traefik.http.routers.{$https_label}.tls.certresolver=letsencrypt");
|
$labels->push("traefik.http.routers.{$https_label}.tls.certresolver=letsencrypt");
|
||||||
|
|
||||||
@@ -267,16 +328,41 @@ function fqdnLabelsForTraefik(string $uuid, Collection $domains, bool $is_force_
|
|||||||
}
|
}
|
||||||
if ($path !== '/') {
|
if ($path !== '/') {
|
||||||
$labels->push("traefik.http.middlewares.{$http_label}-stripprefix.stripprefix.prefixes={$path}");
|
$labels->push("traefik.http.middlewares.{$http_label}-stripprefix.stripprefix.prefixes={$path}");
|
||||||
$labels->push("traefik.http.routers.{$http_label}.middlewares={$http_label}-stripprefix,gzip");
|
$middlewares = collect(["{$http_label}-stripprefix"]);
|
||||||
|
if ($is_gzip_enabled) {
|
||||||
|
$middlewares->push('gzip');
|
||||||
|
}
|
||||||
|
if ($basic_auth && $basic_auth_middleware) {
|
||||||
|
$middlewares->push($basic_auth_middleware);
|
||||||
|
}
|
||||||
|
if ($redirect && $redirect_middleware) {
|
||||||
|
$middlewares->push($redirect_middleware);
|
||||||
|
}
|
||||||
|
if ($middlewares->isNotEmpty()) {
|
||||||
|
$middlewares = $middlewares->join(',');
|
||||||
|
$labels->push("traefik.http.routers.{$http_label}.middlewares={$middlewares}");
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
$labels->push("traefik.http.routers.{$http_label}.middlewares=gzip");
|
$middlewares = collect([]);
|
||||||
|
if ($is_gzip_enabled) {
|
||||||
|
$middlewares->push('gzip');
|
||||||
|
}
|
||||||
|
if ($basic_auth && $basic_auth_middleware) {
|
||||||
|
$middlewares->push($basic_auth_middleware);
|
||||||
|
}
|
||||||
|
if ($redirect && $redirect_middleware) {
|
||||||
|
$middlewares->push($redirect_middleware);
|
||||||
|
}
|
||||||
|
if ($middlewares->isNotEmpty()) {
|
||||||
|
$middlewares = $middlewares->join(',');
|
||||||
|
$labels->push("traefik.http.routers.{$http_label}.middlewares={$middlewares}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return $labels->sort();
|
return $labels->sort();
|
||||||
}
|
}
|
||||||
function generateLabelsApplication(Application $application, ?ApplicationPreview $preview = null): array
|
function generateLabelsApplication(Application $application, ?ApplicationPreview $preview = null): array
|
||||||
@@ -340,25 +426,20 @@ function convert_docker_run_to_compose(?string $custom_docker_run_options = null
|
|||||||
'--cap-drop' => 'cap_drop',
|
'--cap-drop' => 'cap_drop',
|
||||||
'--security-opt' => 'security_opt',
|
'--security-opt' => 'security_opt',
|
||||||
'--sysctl' => 'sysctls',
|
'--sysctl' => 'sysctls',
|
||||||
'--device' => 'devices',
|
|
||||||
'--ulimit' => 'ulimits',
|
'--ulimit' => 'ulimits',
|
||||||
|
'--device' => 'devices',
|
||||||
'--init' => 'init',
|
'--init' => 'init',
|
||||||
'--ulimit' => 'ulimits',
|
'--ulimit' => 'ulimits',
|
||||||
'--privileged' => 'privileged',
|
'--privileged' => 'privileged',
|
||||||
]);
|
]);
|
||||||
foreach ($matches as $match) {
|
foreach ($matches as $match) {
|
||||||
$option = $match[1];
|
$option = $match[1];
|
||||||
$value = isset($match[2]) && $match[2] !== '' ? $match[2] : true;
|
if (isset($match[2]) && $match[2] !== '') {
|
||||||
if ($list_options->contains($option)) {
|
$value = $match[2];
|
||||||
$value = explode(',', $value);
|
$options[$option][] = $value;
|
||||||
}
|
$options[$option] = array_unique($options[$option]);
|
||||||
if (array_key_exists($option, $options)) {
|
|
||||||
if (is_array($options[$option])) {
|
|
||||||
$options[$option][] = $value;
|
|
||||||
} else {
|
|
||||||
$options[$option] = [$options[$option], $value];
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
|
$value = true;
|
||||||
$options[$option] = $value;
|
$options[$option] = $value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -370,7 +451,7 @@ function convert_docker_run_to_compose(?string $custom_docker_run_options = null
|
|||||||
}
|
}
|
||||||
if ($option === '--ulimit') {
|
if ($option === '--ulimit') {
|
||||||
$ulimits = collect([]);
|
$ulimits = collect([]);
|
||||||
collect($value)->map(function ($ulimit) use ($ulimits){
|
collect($value)->map(function ($ulimit) use ($ulimits) {
|
||||||
$ulimit = explode('=', $ulimit);
|
$ulimit = explode('=', $ulimit);
|
||||||
$type = $ulimit[0];
|
$type = $ulimit[0];
|
||||||
$limits = explode(':', $ulimit[1]);
|
$limits = explode(':', $ulimit[1]);
|
||||||
@@ -381,7 +462,6 @@ function convert_docker_run_to_compose(?string $custom_docker_run_options = null
|
|||||||
'soft' => $soft_limit,
|
'soft' => $soft_limit,
|
||||||
'hard' => $hard_limit
|
'hard' => $hard_limit
|
||||||
]);
|
]);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
$soft_limit = $ulimit[1];
|
$soft_limit = $ulimit[1];
|
||||||
$ulimits->put($type, [
|
$ulimits->put($type, [
|
||||||
|
|||||||
@@ -103,6 +103,7 @@ function generate_default_proxy_configuration(Server $server)
|
|||||||
"traefik.http.routers.traefik.entrypoints=http",
|
"traefik.http.routers.traefik.entrypoints=http",
|
||||||
"traefik.http.routers.traefik.service=api@internal",
|
"traefik.http.routers.traefik.service=api@internal",
|
||||||
"traefik.http.services.traefik.loadbalancer.server.port=8080",
|
"traefik.http.services.traefik.loadbalancer.server.port=8080",
|
||||||
|
"coolify.managed=true",
|
||||||
];
|
];
|
||||||
$config = [
|
$config = [
|
||||||
"version" => "3.8",
|
"version" => "3.8",
|
||||||
|
|||||||
@@ -228,56 +228,6 @@ function refresh_server_connection(?PrivateKey $private_key = null)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// function validateServer(Server $server, bool $throwError = false)
|
|
||||||
// {
|
|
||||||
// try {
|
|
||||||
// $uptime = instant_remote_process(['uptime'], $server, $throwError);
|
|
||||||
// if (!$uptime) {
|
|
||||||
// $server->settings->is_reachable = false;
|
|
||||||
// $server->team->notify(new Unreachable($server));
|
|
||||||
// $server->unreachable_notification_sent = true;
|
|
||||||
// $server->save();
|
|
||||||
// return [
|
|
||||||
// "uptime" => null,
|
|
||||||
// "dockerVersion" => null,
|
|
||||||
// ];
|
|
||||||
// }
|
|
||||||
// $server->settings->is_reachable = true;
|
|
||||||
// instant_remote_process(["docker ps"], $server, $throwError);
|
|
||||||
// $dockerVersion = instant_remote_process(["docker version|head -2|grep -i version| awk '{print $2}'"], $server, $throwError);
|
|
||||||
// if (!$dockerVersion) {
|
|
||||||
// $dockerVersion = null;
|
|
||||||
// return [
|
|
||||||
// "uptime" => $uptime,
|
|
||||||
// "dockerVersion" => null,
|
|
||||||
// ];
|
|
||||||
// }
|
|
||||||
// $dockerVersion = checkMinimumDockerEngineVersion($dockerVersion);
|
|
||||||
// if (is_null($dockerVersion)) {
|
|
||||||
// $server->settings->is_usable = false;
|
|
||||||
// } else {
|
|
||||||
// $server->settings->is_usable = true;
|
|
||||||
// if (data_get($server, 'unreachable_notification_sent') === true) {
|
|
||||||
// $server->team->notify(new Revived($server));
|
|
||||||
// $server->unreachable_notification_sent = false;
|
|
||||||
// $server->save();
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// return [
|
|
||||||
// "uptime" => $uptime,
|
|
||||||
// "dockerVersion" => $dockerVersion,
|
|
||||||
// ];
|
|
||||||
// } catch (\Throwable $e) {
|
|
||||||
// $server->settings->is_reachable = false;
|
|
||||||
// $server->settings->is_usable = false;
|
|
||||||
// throw $e;
|
|
||||||
// } finally {
|
|
||||||
// if (data_get($server, 'settings')) {
|
|
||||||
// $server->settings->save();
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
function checkRequiredCommands(Server $server)
|
function checkRequiredCommands(Server $server)
|
||||||
{
|
{
|
||||||
$commands = collect(["jq", "jc"]);
|
$commands = collect(["jq", "jc"]);
|
||||||
|
|||||||
@@ -21,49 +21,6 @@ function replaceVariables($variable)
|
|||||||
return $variable->replaceFirst('$', '')->replaceFirst('{', '')->replaceLast('}', '');
|
return $variable->replaceFirst('$', '')->replaceFirst('{', '')->replaceLast('}', '');
|
||||||
}
|
}
|
||||||
|
|
||||||
function serviceStatus(Service $service)
|
|
||||||
{
|
|
||||||
$foundRunning = false;
|
|
||||||
$isDegraded = false;
|
|
||||||
$foundRestaring = false;
|
|
||||||
$applications = $service->applications;
|
|
||||||
$databases = $service->databases;
|
|
||||||
foreach ($applications as $application) {
|
|
||||||
if ($application->exclude_from_status) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (Str::of($application->status)->startsWith('running')) {
|
|
||||||
$foundRunning = true;
|
|
||||||
} else if (Str::of($application->status)->startsWith('restarting')) {
|
|
||||||
$foundRestaring = true;
|
|
||||||
} else {
|
|
||||||
$isDegraded = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
foreach ($databases as $database) {
|
|
||||||
if ($database->exclude_from_status) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (Str::of($database->status)->startsWith('running')) {
|
|
||||||
$foundRunning = true;
|
|
||||||
} else if (Str::of($database->status)->startsWith('restarting')) {
|
|
||||||
$foundRestaring = true;
|
|
||||||
} else {
|
|
||||||
$isDegraded = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ($foundRestaring) {
|
|
||||||
return 'degraded';
|
|
||||||
}
|
|
||||||
if ($foundRunning && !$isDegraded) {
|
|
||||||
return 'running';
|
|
||||||
} else if ($foundRunning && $isDegraded) {
|
|
||||||
return 'degraded';
|
|
||||||
} else if (!$foundRunning && !$isDegraded) {
|
|
||||||
return 'exited';
|
|
||||||
}
|
|
||||||
return 'exited';
|
|
||||||
}
|
|
||||||
function getFilesystemVolumesFromServer(ServiceApplication|ServiceDatabase $oneService, bool $isInit = false)
|
function getFilesystemVolumesFromServer(ServiceApplication|ServiceDatabase $oneService, bool $isInit = false)
|
||||||
{
|
{
|
||||||
// TODO: make this async
|
// TODO: make this async
|
||||||
|
|||||||
@@ -125,6 +125,9 @@ function handleError(?Throwable $error = null, ?Livewire\Component $livewire = n
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (isset($livewire)) {
|
if (isset($livewire)) {
|
||||||
|
if (str($message)->length() > 20) {
|
||||||
|
return $livewire->dispatch('error', 'Error occured', $message);
|
||||||
|
}
|
||||||
return $livewire->dispatch('error', $message);
|
return $livewire->dispatch('error', $message);
|
||||||
}
|
}
|
||||||
throw new Exception($message);
|
throw new Exception($message);
|
||||||
@@ -527,28 +530,32 @@ function getTopLevelNetworks(Service|Application $resource)
|
|||||||
$definedNetwork = collect([$resource->uuid]);
|
$definedNetwork = collect([$resource->uuid]);
|
||||||
$services = collect($services)->map(function ($service, $_) use ($topLevelNetworks, $definedNetwork) {
|
$services = collect($services)->map(function ($service, $_) use ($topLevelNetworks, $definedNetwork) {
|
||||||
$serviceNetworks = collect(data_get($service, 'networks', []));
|
$serviceNetworks = collect(data_get($service, 'networks', []));
|
||||||
|
$hasHostNetworkMode = data_get($service, 'network_mode') === 'host' ? true : false;
|
||||||
|
|
||||||
// Collect/create/update networks
|
// Only add 'networks' key if 'network_mode' is not 'host'
|
||||||
if ($serviceNetworks->count() > 0) {
|
if (!$hasHostNetworkMode) {
|
||||||
foreach ($serviceNetworks as $networkName => $networkDetails) {
|
// Collect/create/update networks
|
||||||
$networkExists = $topLevelNetworks->contains(function ($value, $key) use ($networkName) {
|
if ($serviceNetworks->count() > 0) {
|
||||||
return $value == $networkName || $key == $networkName;
|
foreach ($serviceNetworks as $networkName => $networkDetails) {
|
||||||
});
|
$networkExists = $topLevelNetworks->contains(function ($value, $key) use ($networkName) {
|
||||||
if (!$networkExists) {
|
return $value == $networkName || $key == $networkName;
|
||||||
$topLevelNetworks->put($networkDetails, null);
|
});
|
||||||
|
if (!$networkExists) {
|
||||||
|
$topLevelNetworks->put($networkDetails, null);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
$definedNetworkExists = $topLevelNetworks->contains(function ($value, $_) use ($definedNetwork) {
|
$definedNetworkExists = $topLevelNetworks->contains(function ($value, $_) use ($definedNetwork) {
|
||||||
return $value == $definedNetwork;
|
return $value == $definedNetwork;
|
||||||
});
|
});
|
||||||
if (!$definedNetworkExists) {
|
if (!$definedNetworkExists) {
|
||||||
foreach ($definedNetwork as $network) {
|
foreach ($definedNetwork as $network) {
|
||||||
$topLevelNetworks->put($network, [
|
$topLevelNetworks->put($network, [
|
||||||
'name' => $network,
|
'name' => $network,
|
||||||
'external' => true
|
'external' => true
|
||||||
]);
|
]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -628,6 +635,7 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal
|
|||||||
$serviceNetworks = collect(data_get($service, 'networks', []));
|
$serviceNetworks = collect(data_get($service, 'networks', []));
|
||||||
$serviceVariables = collect(data_get($service, 'environment', []));
|
$serviceVariables = collect(data_get($service, 'environment', []));
|
||||||
$serviceLabels = collect(data_get($service, 'labels', []));
|
$serviceLabels = collect(data_get($service, 'labels', []));
|
||||||
|
$hasHostNetworkMode = data_get($service, 'network_mode') === 'host' ? true : false;
|
||||||
if ($serviceLabels->count() > 0) {
|
if ($serviceLabels->count() > 0) {
|
||||||
$removedLabels = collect([]);
|
$removedLabels = collect([]);
|
||||||
$serviceLabels = $serviceLabels->filter(function ($serviceLabel, $serviceLabelName) use ($removedLabels) {
|
$serviceLabels = $serviceLabels->filter(function ($serviceLabel, $serviceLabelName) use ($removedLabels) {
|
||||||
@@ -698,7 +706,6 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal
|
|||||||
$savedService->image = $image;
|
$savedService->image = $image;
|
||||||
$savedService->save();
|
$savedService->save();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Collect/create/update networks
|
// Collect/create/update networks
|
||||||
if ($serviceNetworks->count() > 0) {
|
if ($serviceNetworks->count() > 0) {
|
||||||
foreach ($serviceNetworks as $networkName => $networkDetails) {
|
foreach ($serviceNetworks as $networkName => $networkDetails) {
|
||||||
@@ -729,37 +736,39 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal
|
|||||||
$savedService->ports = $collectedPorts->implode(',');
|
$savedService->ports = $collectedPorts->implode(',');
|
||||||
$savedService->save();
|
$savedService->save();
|
||||||
|
|
||||||
// Add Coolify specific networks
|
if (!$hasHostNetworkMode) {
|
||||||
$definedNetworkExists = $topLevelNetworks->contains(function ($value, $_) use ($definedNetwork) {
|
// Add Coolify specific networks
|
||||||
return $value == $definedNetwork;
|
$definedNetworkExists = $topLevelNetworks->contains(function ($value, $_) use ($definedNetwork) {
|
||||||
});
|
return $value == $definedNetwork;
|
||||||
if (!$definedNetworkExists) {
|
});
|
||||||
foreach ($definedNetwork as $network) {
|
if (!$definedNetworkExists) {
|
||||||
$topLevelNetworks->put($network, [
|
foreach ($definedNetwork as $network) {
|
||||||
'name' => $network,
|
$topLevelNetworks->put($network, [
|
||||||
'external' => true
|
'name' => $network,
|
||||||
]);
|
'external' => true
|
||||||
|
]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
$networks = collect();
|
||||||
$networks = collect();
|
foreach ($serviceNetworks as $key => $serviceNetwork) {
|
||||||
foreach ($serviceNetworks as $key => $serviceNetwork) {
|
if (gettype($serviceNetwork) === 'string') {
|
||||||
if (gettype($serviceNetwork) === 'string') {
|
// networks:
|
||||||
// networks:
|
// - appwrite
|
||||||
// - appwrite
|
$networks->put($serviceNetwork, null);
|
||||||
$networks->put($serviceNetwork, null);
|
} else if (gettype($serviceNetwork) === 'array') {
|
||||||
} else if (gettype($serviceNetwork) === 'array') {
|
// networks:
|
||||||
// networks:
|
// default:
|
||||||
// default:
|
// ipv4_address: 192.168.203.254
|
||||||
// ipv4_address: 192.168.203.254
|
// $networks->put($serviceNetwork, null);
|
||||||
// $networks->put($serviceNetwork, null);
|
ray($key);
|
||||||
ray($key);
|
$networks->put($key, $serviceNetwork);
|
||||||
$networks->put($key, $serviceNetwork);
|
}
|
||||||
}
|
}
|
||||||
|
foreach ($definedNetwork as $key => $network) {
|
||||||
|
$networks->put($network, null);
|
||||||
|
}
|
||||||
|
data_set($service, 'networks', $networks->toArray());
|
||||||
}
|
}
|
||||||
foreach ($definedNetwork as $key => $network) {
|
|
||||||
$networks->put($network, null);
|
|
||||||
}
|
|
||||||
data_set($service, 'networks', $networks->toArray());
|
|
||||||
|
|
||||||
// Collect/create/update volumes
|
// Collect/create/update volumes
|
||||||
if ($serviceVolumes->count() > 0) {
|
if ($serviceVolumes->count() > 0) {
|
||||||
@@ -782,14 +791,14 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal
|
|||||||
$source = data_get_str($volume, 'source');
|
$source = data_get_str($volume, 'source');
|
||||||
$target = data_get_str($volume, 'target');
|
$target = data_get_str($volume, 'target');
|
||||||
$content = data_get($volume, 'content');
|
$content = data_get($volume, 'content');
|
||||||
$isDirectory = (bool) data_get($volume, 'isDirectory', false);
|
$isDirectory = (bool) data_get($volume, 'isDirectory', false) || (bool) data_get($volume, 'is_directory', false);
|
||||||
$foundConfig = $savedService->fileStorages()->whereMountPath($target)->first();
|
$foundConfig = $savedService->fileStorages()->whereMountPath($target)->first();
|
||||||
if ($foundConfig) {
|
if ($foundConfig) {
|
||||||
$contentNotNull = data_get($foundConfig, 'content');
|
$contentNotNull = data_get($foundConfig, 'content');
|
||||||
if ($contentNotNull) {
|
if ($contentNotNull) {
|
||||||
$content = $contentNotNull;
|
$content = $contentNotNull;
|
||||||
}
|
}
|
||||||
$isDirectory = (bool) data_get($foundConfig, 'is_directory');
|
$isDirectory = (bool) data_get($volume, 'isDirectory', false) || (bool) data_get($volume, 'is_directory', false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ($type->value() === 'bind') {
|
if ($type->value() === 'bind') {
|
||||||
@@ -1030,7 +1039,7 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal
|
|||||||
$serviceLabels = $serviceLabels->merge($defaultLabels);
|
$serviceLabels = $serviceLabels->merge($defaultLabels);
|
||||||
if (!$isDatabase && $fqdns->count() > 0) {
|
if (!$isDatabase && $fqdns->count() > 0) {
|
||||||
if ($fqdns) {
|
if ($fqdns) {
|
||||||
$serviceLabels = $serviceLabels->merge(fqdnLabelsForTraefik($resource->uuid, $fqdns, true));
|
$serviceLabels = $serviceLabels->merge(fqdnLabelsForTraefik($resource->uuid, $fqdns, true, serviceLabels: $serviceLabels, is_gzip_enabled: $savedService->isGzipEnabled()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ($resource->server->isLogDrainEnabled() && $savedService->isLogDrainEnabled()) {
|
if ($resource->server->isLogDrainEnabled() && $savedService->isLogDrainEnabled()) {
|
||||||
@@ -1054,6 +1063,8 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal
|
|||||||
data_set($service, 'container_name', $containerName);
|
data_set($service, 'container_name', $containerName);
|
||||||
data_forget($service, 'volumes.*.content');
|
data_forget($service, 'volumes.*.content');
|
||||||
data_forget($service, 'volumes.*.isDirectory');
|
data_forget($service, 'volumes.*.isDirectory');
|
||||||
|
data_forget($service, 'volumes.*.is_directory');
|
||||||
|
|
||||||
// Remove unnecessary variables from service.environment
|
// Remove unnecessary variables from service.environment
|
||||||
// $withoutServiceEnvs = collect([]);
|
// $withoutServiceEnvs = collect([]);
|
||||||
// collect(data_get($service, 'environment'))->each(function ($value, $key) use ($withoutServiceEnvs) {
|
// collect(data_get($service, 'environment'))->each(function ($value, $key) use ($withoutServiceEnvs) {
|
||||||
@@ -1469,7 +1480,7 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal
|
|||||||
return $preview_fqdn;
|
return $preview_fqdn;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
$serviceLabels = $serviceLabels->merge(fqdnLabelsForTraefik($uuid, $fqdns));
|
$serviceLabels = $serviceLabels->merge(fqdnLabelsForTraefik($uuid, $fqdns,serviceLabels: $serviceLabels));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
803
composer.lock
generated
803
composer.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -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.212',
|
'release' => '4.0.0-beta.221',
|
||||||
// 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'),
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
return '4.0.0-beta.212';
|
return '4.0.0-beta.221';
|
||||||
|
|||||||
@@ -0,0 +1,28 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::table('application_settings', function (Blueprint $table) {
|
||||||
|
$table->boolean('is_consistent_container_name_enabled')->default(false);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::table('application_settings', function (Blueprint $table) {
|
||||||
|
$table->dropColumn('is_consistent_container_name_enabled');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::table('service_applications', function (Blueprint $table) {
|
||||||
|
$table->boolean('is_gzip_enabled')->default(true);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::table('service_applications', function (Blueprint $table) {
|
||||||
|
$table->dropColumn('is_gzip_enabled');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
version: '3.8'
|
version: '3.8'
|
||||||
services:
|
services:
|
||||||
coolify:
|
coolify:
|
||||||
image: "ghcr.io/coollabsio/coolify:${LATEST_IMAGE:latest}"
|
image: "ghcr.io/coollabsio/coolify:${LATEST_IMAGE:-latest}"
|
||||||
volumes:
|
volumes:
|
||||||
- type: bind
|
- type: bind
|
||||||
source: /data/coolify/source/.env
|
source: /data/coolify/source/.env
|
||||||
|
|||||||
176
package-lock.json
generated
176
package-lock.json
generated
@@ -7,7 +7,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@tailwindcss/typography": "0.5.10",
|
"@tailwindcss/typography": "0.5.10",
|
||||||
"alpinejs": "3.13.5",
|
"alpinejs": "3.13.5",
|
||||||
"daisyui": "4.4.19",
|
"daisyui": "4.7.2",
|
||||||
"ioredis": "5.3.2",
|
"ioredis": "5.3.2",
|
||||||
"tailwindcss-scrollbar": "0.1.0"
|
"tailwindcss-scrollbar": "0.1.0"
|
||||||
},
|
},
|
||||||
@@ -17,11 +17,11 @@
|
|||||||
"axios": "1.6.7",
|
"axios": "1.6.7",
|
||||||
"laravel-echo": "1.15.3",
|
"laravel-echo": "1.15.3",
|
||||||
"laravel-vite-plugin": "0.8.1",
|
"laravel-vite-plugin": "0.8.1",
|
||||||
"postcss": "8.4.33",
|
"postcss": "8.4.35",
|
||||||
"pusher-js": "8.4.0-rc2",
|
"pusher-js": "8.4.0-rc2",
|
||||||
"tailwindcss": "3.4.1",
|
"tailwindcss": "3.4.1",
|
||||||
"vite": "4.5.2",
|
"vite": "4.5.2",
|
||||||
"vue": "3.4.15"
|
"vue": "3.4.19"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@alloc/quick-lru": {
|
"node_modules/@alloc/quick-lru": {
|
||||||
@@ -524,77 +524,77 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@vue/compiler-core": {
|
"node_modules/@vue/compiler-core": {
|
||||||
"version": "3.4.15",
|
"version": "3.4.19",
|
||||||
"resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.4.15.tgz",
|
"resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.4.19.tgz",
|
||||||
"integrity": "sha512-XcJQVOaxTKCnth1vCxEChteGuwG6wqnUHxAm1DO3gCz0+uXKaJNx8/digSz4dLALCy8n2lKq24jSUs8segoqIw==",
|
"integrity": "sha512-gj81785z0JNzRcU0Mq98E56e4ltO1yf8k5PQ+tV/7YHnbZkrM0fyFyuttnN8ngJZjbpofWE/m4qjKBiLl8Ju4w==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/parser": "^7.23.6",
|
"@babel/parser": "^7.23.9",
|
||||||
"@vue/shared": "3.4.15",
|
"@vue/shared": "3.4.19",
|
||||||
"entities": "^4.5.0",
|
"entities": "^4.5.0",
|
||||||
"estree-walker": "^2.0.2",
|
"estree-walker": "^2.0.2",
|
||||||
"source-map-js": "^1.0.2"
|
"source-map-js": "^1.0.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@vue/compiler-core/node_modules/@vue/shared": {
|
"node_modules/@vue/compiler-core/node_modules/@vue/shared": {
|
||||||
"version": "3.4.15",
|
"version": "3.4.19",
|
||||||
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.4.15.tgz",
|
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.4.19.tgz",
|
||||||
"integrity": "sha512-KzfPTxVaWfB+eGcGdbSf4CWdaXcGDqckoeXUh7SB3fZdEtzPCK2Vq9B/lRRL3yutax/LWITz+SwvgyOxz5V75g==",
|
"integrity": "sha512-/KliRRHMF6LoiThEy+4c1Z4KB/gbPrGjWwJR+crg2otgrf/egKzRaCPvJ51S5oetgsgXLfc4Rm5ZgrKHZrtMSw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/@vue/compiler-dom": {
|
"node_modules/@vue/compiler-dom": {
|
||||||
"version": "3.4.15",
|
"version": "3.4.19",
|
||||||
"resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.4.15.tgz",
|
"resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.4.19.tgz",
|
||||||
"integrity": "sha512-wox0aasVV74zoXyblarOM3AZQz/Z+OunYcIHe1OsGclCHt8RsRm04DObjefaI82u6XDzv+qGWZ24tIsRAIi5MQ==",
|
"integrity": "sha512-vm6+cogWrshjqEHTzIDCp72DKtea8Ry/QVpQRYoyTIg9k7QZDX6D8+HGURjtmatfgM8xgCFtJJaOlCaRYRK3QA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@vue/compiler-core": "3.4.15",
|
"@vue/compiler-core": "3.4.19",
|
||||||
"@vue/shared": "3.4.15"
|
"@vue/shared": "3.4.19"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@vue/compiler-dom/node_modules/@vue/shared": {
|
"node_modules/@vue/compiler-dom/node_modules/@vue/shared": {
|
||||||
"version": "3.4.15",
|
"version": "3.4.19",
|
||||||
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.4.15.tgz",
|
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.4.19.tgz",
|
||||||
"integrity": "sha512-KzfPTxVaWfB+eGcGdbSf4CWdaXcGDqckoeXUh7SB3fZdEtzPCK2Vq9B/lRRL3yutax/LWITz+SwvgyOxz5V75g==",
|
"integrity": "sha512-/KliRRHMF6LoiThEy+4c1Z4KB/gbPrGjWwJR+crg2otgrf/egKzRaCPvJ51S5oetgsgXLfc4Rm5ZgrKHZrtMSw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/@vue/compiler-sfc": {
|
"node_modules/@vue/compiler-sfc": {
|
||||||
"version": "3.4.15",
|
"version": "3.4.19",
|
||||||
"resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.4.15.tgz",
|
"resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.4.19.tgz",
|
||||||
"integrity": "sha512-LCn5M6QpkpFsh3GQvs2mJUOAlBQcCco8D60Bcqmf3O3w5a+KWS5GvYbrrJBkgvL1BDnTp+e8q0lXCLgHhKguBA==",
|
"integrity": "sha512-LQ3U4SN0DlvV0xhr1lUsgLCYlwQfUfetyPxkKYu7dkfvx7g3ojrGAkw0AERLOKYXuAGnqFsEuytkdcComei3Yg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/parser": "^7.23.6",
|
"@babel/parser": "^7.23.9",
|
||||||
"@vue/compiler-core": "3.4.15",
|
"@vue/compiler-core": "3.4.19",
|
||||||
"@vue/compiler-dom": "3.4.15",
|
"@vue/compiler-dom": "3.4.19",
|
||||||
"@vue/compiler-ssr": "3.4.15",
|
"@vue/compiler-ssr": "3.4.19",
|
||||||
"@vue/shared": "3.4.15",
|
"@vue/shared": "3.4.19",
|
||||||
"estree-walker": "^2.0.2",
|
"estree-walker": "^2.0.2",
|
||||||
"magic-string": "^0.30.5",
|
"magic-string": "^0.30.6",
|
||||||
"postcss": "^8.4.33",
|
"postcss": "^8.4.33",
|
||||||
"source-map-js": "^1.0.2"
|
"source-map-js": "^1.0.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@vue/compiler-sfc/node_modules/@vue/shared": {
|
"node_modules/@vue/compiler-sfc/node_modules/@vue/shared": {
|
||||||
"version": "3.4.15",
|
"version": "3.4.19",
|
||||||
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.4.15.tgz",
|
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.4.19.tgz",
|
||||||
"integrity": "sha512-KzfPTxVaWfB+eGcGdbSf4CWdaXcGDqckoeXUh7SB3fZdEtzPCK2Vq9B/lRRL3yutax/LWITz+SwvgyOxz5V75g==",
|
"integrity": "sha512-/KliRRHMF6LoiThEy+4c1Z4KB/gbPrGjWwJR+crg2otgrf/egKzRaCPvJ51S5oetgsgXLfc4Rm5ZgrKHZrtMSw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/@vue/compiler-ssr": {
|
"node_modules/@vue/compiler-ssr": {
|
||||||
"version": "3.4.15",
|
"version": "3.4.19",
|
||||||
"resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.4.15.tgz",
|
"resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.4.19.tgz",
|
||||||
"integrity": "sha512-1jdeQyiGznr8gjFDadVmOJqZiLNSsMa5ZgqavkPZ8O2wjHv0tVuAEsw5hTdUoUW4232vpBbL/wJhzVW/JwY1Uw==",
|
"integrity": "sha512-P0PLKC4+u4OMJ8sinba/5Z/iDT84uMRRlrWzadgLA69opCpI1gG4N55qDSC+dedwq2fJtzmGald05LWR5TFfLw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@vue/compiler-dom": "3.4.15",
|
"@vue/compiler-dom": "3.4.19",
|
||||||
"@vue/shared": "3.4.15"
|
"@vue/shared": "3.4.19"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@vue/compiler-ssr/node_modules/@vue/shared": {
|
"node_modules/@vue/compiler-ssr/node_modules/@vue/shared": {
|
||||||
"version": "3.4.15",
|
"version": "3.4.19",
|
||||||
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.4.15.tgz",
|
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.4.19.tgz",
|
||||||
"integrity": "sha512-KzfPTxVaWfB+eGcGdbSf4CWdaXcGDqckoeXUh7SB3fZdEtzPCK2Vq9B/lRRL3yutax/LWITz+SwvgyOxz5V75g==",
|
"integrity": "sha512-/KliRRHMF6LoiThEy+4c1Z4KB/gbPrGjWwJR+crg2otgrf/egKzRaCPvJ51S5oetgsgXLfc4Rm5ZgrKHZrtMSw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/@vue/reactivity": {
|
"node_modules/@vue/reactivity": {
|
||||||
@@ -606,64 +606,64 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@vue/runtime-core": {
|
"node_modules/@vue/runtime-core": {
|
||||||
"version": "3.4.15",
|
"version": "3.4.19",
|
||||||
"resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.4.15.tgz",
|
"resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.4.19.tgz",
|
||||||
"integrity": "sha512-6E3by5m6v1AkW0McCeAyhHTw+3y17YCOKG0U0HDKDscV4Hs0kgNT5G+GCHak16jKgcCDHpI9xe5NKb8sdLCLdw==",
|
"integrity": "sha512-/Z3tFwOrerJB/oyutmJGoYbuoadphDcJAd5jOuJE86THNZji9pYjZroQ2NFsZkTxOq0GJbb+s2kxTYToDiyZzw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@vue/reactivity": "3.4.15",
|
"@vue/reactivity": "3.4.19",
|
||||||
"@vue/shared": "3.4.15"
|
"@vue/shared": "3.4.19"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@vue/runtime-core/node_modules/@vue/reactivity": {
|
"node_modules/@vue/runtime-core/node_modules/@vue/reactivity": {
|
||||||
"version": "3.4.15",
|
"version": "3.4.19",
|
||||||
"resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.4.15.tgz",
|
"resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.4.19.tgz",
|
||||||
"integrity": "sha512-55yJh2bsff20K5O84MxSvXKPHHt17I2EomHznvFiJCAZpJTNW8IuLj1xZWMLELRhBK3kkFV/1ErZGHJfah7i7w==",
|
"integrity": "sha512-+VcwrQvLZgEclGZRHx4O2XhyEEcKaBi50WbxdVItEezUf4fqRh838Ix6amWTdX0CNb/b6t3Gkz3eOebfcSt+UA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@vue/shared": "3.4.15"
|
"@vue/shared": "3.4.19"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@vue/runtime-core/node_modules/@vue/shared": {
|
"node_modules/@vue/runtime-core/node_modules/@vue/shared": {
|
||||||
"version": "3.4.15",
|
"version": "3.4.19",
|
||||||
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.4.15.tgz",
|
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.4.19.tgz",
|
||||||
"integrity": "sha512-KzfPTxVaWfB+eGcGdbSf4CWdaXcGDqckoeXUh7SB3fZdEtzPCK2Vq9B/lRRL3yutax/LWITz+SwvgyOxz5V75g==",
|
"integrity": "sha512-/KliRRHMF6LoiThEy+4c1Z4KB/gbPrGjWwJR+crg2otgrf/egKzRaCPvJ51S5oetgsgXLfc4Rm5ZgrKHZrtMSw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/@vue/runtime-dom": {
|
"node_modules/@vue/runtime-dom": {
|
||||||
"version": "3.4.15",
|
"version": "3.4.19",
|
||||||
"resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.4.15.tgz",
|
"resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.4.19.tgz",
|
||||||
"integrity": "sha512-EVW8D6vfFVq3V/yDKNPBFkZKGMFSvZrUQmx196o/v2tHKdwWdiZjYUBS+0Ez3+ohRyF8Njwy/6FH5gYJ75liUw==",
|
"integrity": "sha512-IyZzIDqfNCF0OyZOauL+F4yzjMPN2rPd8nhqPP2N1lBn3kYqJpPHHru+83Rkvo2lHz5mW+rEeIMEF9qY3PB94g==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@vue/runtime-core": "3.4.15",
|
"@vue/runtime-core": "3.4.19",
|
||||||
"@vue/shared": "3.4.15",
|
"@vue/shared": "3.4.19",
|
||||||
"csstype": "^3.1.3"
|
"csstype": "^3.1.3"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@vue/runtime-dom/node_modules/@vue/shared": {
|
"node_modules/@vue/runtime-dom/node_modules/@vue/shared": {
|
||||||
"version": "3.4.15",
|
"version": "3.4.19",
|
||||||
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.4.15.tgz",
|
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.4.19.tgz",
|
||||||
"integrity": "sha512-KzfPTxVaWfB+eGcGdbSf4CWdaXcGDqckoeXUh7SB3fZdEtzPCK2Vq9B/lRRL3yutax/LWITz+SwvgyOxz5V75g==",
|
"integrity": "sha512-/KliRRHMF6LoiThEy+4c1Z4KB/gbPrGjWwJR+crg2otgrf/egKzRaCPvJ51S5oetgsgXLfc4Rm5ZgrKHZrtMSw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/@vue/server-renderer": {
|
"node_modules/@vue/server-renderer": {
|
||||||
"version": "3.4.15",
|
"version": "3.4.19",
|
||||||
"resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.4.15.tgz",
|
"resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.4.19.tgz",
|
||||||
"integrity": "sha512-3HYzaidu9cHjrT+qGUuDhFYvF/j643bHC6uUN9BgM11DVy+pM6ATsG6uPBLnkwOgs7BpJABReLmpL3ZPAsUaqw==",
|
"integrity": "sha512-eAj2p0c429RZyyhtMRnttjcSToch+kTWxFPHlzGMkR28ZbF1PDlTcmGmlDxccBuqNd9iOQ7xPRPAGgPVj+YpQw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@vue/compiler-ssr": "3.4.15",
|
"@vue/compiler-ssr": "3.4.19",
|
||||||
"@vue/shared": "3.4.15"
|
"@vue/shared": "3.4.19"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"vue": "3.4.15"
|
"vue": "3.4.19"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@vue/server-renderer/node_modules/@vue/shared": {
|
"node_modules/@vue/server-renderer/node_modules/@vue/shared": {
|
||||||
"version": "3.4.15",
|
"version": "3.4.19",
|
||||||
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.4.15.tgz",
|
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.4.19.tgz",
|
||||||
"integrity": "sha512-KzfPTxVaWfB+eGcGdbSf4CWdaXcGDqckoeXUh7SB3fZdEtzPCK2Vq9B/lRRL3yutax/LWITz+SwvgyOxz5V75g==",
|
"integrity": "sha512-/KliRRHMF6LoiThEy+4c1Z4KB/gbPrGjWwJR+crg2otgrf/egKzRaCPvJ51S5oetgsgXLfc4Rm5ZgrKHZrtMSw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/@vue/shared": {
|
"node_modules/@vue/shared": {
|
||||||
@@ -953,9 +953,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/daisyui": {
|
"node_modules/daisyui": {
|
||||||
"version": "4.4.19",
|
"version": "4.7.2",
|
||||||
"resolved": "https://registry.npmjs.org/daisyui/-/daisyui-4.4.19.tgz",
|
"resolved": "https://registry.npmjs.org/daisyui/-/daisyui-4.7.2.tgz",
|
||||||
"integrity": "sha512-IjOLWwnndD4N7Ut5CDxbUsaVtbqXPeVHM92IcgxGFxpuOd3CCKW/PAXZH6JoBTHFRaN57vB9XqEhdWm5yC+bPA==",
|
"integrity": "sha512-9UCss12Zmyk/22u+JbkVrHHxOzFOyY17HuqP5LeswI4hclbj6qbjJTovdj2zRy8cCH6/n6Wh0lTLjriGnyGh0g==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"css-selector-tokenizer": "^0.8",
|
"css-selector-tokenizer": "^0.8",
|
||||||
"culori": "^3",
|
"culori": "^3",
|
||||||
@@ -1410,9 +1410,9 @@
|
|||||||
"integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ=="
|
"integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ=="
|
||||||
},
|
},
|
||||||
"node_modules/magic-string": {
|
"node_modules/magic-string": {
|
||||||
"version": "0.30.5",
|
"version": "0.30.7",
|
||||||
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.5.tgz",
|
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.7.tgz",
|
||||||
"integrity": "sha512-7xlpfBaQaP/T6Vh8MO/EqXSW5En6INHEvEXQiuff7Gku0PWjU3uf6w/j9o7O+SpB5fOAkrI5HeoNgwjEO0pFsA==",
|
"integrity": "sha512-8vBuFF/I/+OSLRmdf2wwFCJCz+nSn0m6DPvGH1fS/KiQoSaR+sETbov0eIk9KhEKy8CYqIkIAnbohxT/4H0kuA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@jridgewell/sourcemap-codec": "^1.4.15"
|
"@jridgewell/sourcemap-codec": "^1.4.15"
|
||||||
@@ -1598,9 +1598,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/postcss": {
|
"node_modules/postcss": {
|
||||||
"version": "8.4.33",
|
"version": "8.4.35",
|
||||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.33.tgz",
|
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.35.tgz",
|
||||||
"integrity": "sha512-Kkpbhhdjw2qQs2O2DGX+8m5OVqEcbB9HRBvuYM9pgrjEFUg30A9LmXNlTAUj4S9kgtGyrMbTzVjH7E+s5Re2yg==",
|
"integrity": "sha512-u5U8qYpBCpN13BsiEB0CbR1Hhh4Gc0zLFuedrHJKMctHCHAGrMdG0PRM/KErzAL3CU6/eckEtmHNB3x6e3c0vA==",
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
"type": "opencollective",
|
"type": "opencollective",
|
||||||
@@ -2106,16 +2106,16 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/vue": {
|
"node_modules/vue": {
|
||||||
"version": "3.4.15",
|
"version": "3.4.19",
|
||||||
"resolved": "https://registry.npmjs.org/vue/-/vue-3.4.15.tgz",
|
"resolved": "https://registry.npmjs.org/vue/-/vue-3.4.19.tgz",
|
||||||
"integrity": "sha512-jC0GH4KkWLWJOEQjOpkqU1bQsBwf4R1rsFtw5GQJbjHVKWDzO6P0nWWBTmjp1xSemAioDFj1jdaK1qa3DnMQoQ==",
|
"integrity": "sha512-W/7Fc9KUkajFU8dBeDluM4sRGc/aa4YJnOYck8dkjgZoXtVsn3OeTGni66FV1l3+nvPA7VBFYtPioaGKUmEADw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@vue/compiler-dom": "3.4.15",
|
"@vue/compiler-dom": "3.4.19",
|
||||||
"@vue/compiler-sfc": "3.4.15",
|
"@vue/compiler-sfc": "3.4.19",
|
||||||
"@vue/runtime-dom": "3.4.15",
|
"@vue/runtime-dom": "3.4.19",
|
||||||
"@vue/server-renderer": "3.4.15",
|
"@vue/server-renderer": "3.4.19",
|
||||||
"@vue/shared": "3.4.15"
|
"@vue/shared": "3.4.19"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"typescript": "*"
|
"typescript": "*"
|
||||||
@@ -2127,9 +2127,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/vue/node_modules/@vue/shared": {
|
"node_modules/vue/node_modules/@vue/shared": {
|
||||||
"version": "3.4.15",
|
"version": "3.4.19",
|
||||||
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.4.15.tgz",
|
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.4.19.tgz",
|
||||||
"integrity": "sha512-KzfPTxVaWfB+eGcGdbSf4CWdaXcGDqckoeXUh7SB3fZdEtzPCK2Vq9B/lRRL3yutax/LWITz+SwvgyOxz5V75g==",
|
"integrity": "sha512-/KliRRHMF6LoiThEy+4c1Z4KB/gbPrGjWwJR+crg2otgrf/egKzRaCPvJ51S5oetgsgXLfc4Rm5ZgrKHZrtMSw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/wrappy": {
|
"node_modules/wrappy": {
|
||||||
|
|||||||
@@ -11,16 +11,16 @@
|
|||||||
"axios": "1.6.7",
|
"axios": "1.6.7",
|
||||||
"laravel-echo": "1.15.3",
|
"laravel-echo": "1.15.3",
|
||||||
"laravel-vite-plugin": "0.8.1",
|
"laravel-vite-plugin": "0.8.1",
|
||||||
"postcss": "8.4.33",
|
"postcss": "8.4.35",
|
||||||
"pusher-js": "8.4.0-rc2",
|
"pusher-js": "8.4.0-rc2",
|
||||||
"tailwindcss": "3.4.1",
|
"tailwindcss": "3.4.1",
|
||||||
"vite": "4.5.2",
|
"vite": "4.5.2",
|
||||||
"vue": "3.4.15"
|
"vue": "3.4.19"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@tailwindcss/typography": "0.5.10",
|
"@tailwindcss/typography": "0.5.10",
|
||||||
"alpinejs": "3.13.5",
|
"alpinejs": "3.13.5",
|
||||||
"daisyui": "4.4.19",
|
"daisyui": "4.7.2",
|
||||||
"ioredis": "5.3.2",
|
"ioredis": "5.3.2",
|
||||||
"tailwindcss-scrollbar": "0.1.0"
|
"tailwindcss-scrollbar": "0.1.0"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,8 +28,8 @@
|
|||||||
<a class="text-xs text-white rounded-none hover:no-underline hover:bg-coollabs hover:text-white"
|
<a class="text-xs text-white rounded-none hover:no-underline hover:bg-coollabs hover:text-white"
|
||||||
target="_blank" href="{{ getFqdnWithoutPort($domain) }}">
|
target="_blank" href="{{ getFqdnWithoutPort($domain) }}">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" class="w-6 h-6" viewBox="0 0 24 24"
|
<svg xmlns="http://www.w3.org/2000/svg" class="w-6 h-6" viewBox="0 0 24 24"
|
||||||
stroke-width="1.5" stroke="currentColor" fill="none" stroke-linecap="round"
|
stroke-width="1.5" stroke="currentColor" fill="none"
|
||||||
stroke-linejoin="round">
|
stroke-linecap="round" stroke-linejoin="round">
|
||||||
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
||||||
<path d="M9 15l6 -6" />
|
<path d="M9 15l6 -6" />
|
||||||
<path d="M11 6l.463 -.536a5 5 0 0 1 7.071 7.072l-.534 .464" />
|
<path d="M11 6l.463 -.536a5 5 0 0 1 7.071 7.072l-.534 .464" />
|
||||||
@@ -84,7 +84,7 @@
|
|||||||
@endif
|
@endif
|
||||||
@if (data_get($application, 'ports_mappings_array'))
|
@if (data_get($application, 'ports_mappings_array'))
|
||||||
@foreach ($application->ports_mappings_array as $port)
|
@foreach ($application->ports_mappings_array as $port)
|
||||||
@if (isDev())
|
@if ($application->destination->server->id === 0)
|
||||||
<li>
|
<li>
|
||||||
<a class="text-xs text-white rounded-none hover:no-underline hover:bg-coollabs hover:text-white"
|
<a class="text-xs text-white rounded-none hover:no-underline hover:bg-coollabs hover:text-white"
|
||||||
target="_blank" href="http://localhost:{{ explode(':', $port)[0] }}">
|
target="_blank" href="http://localhost:{{ explode(':', $port)[0] }}">
|
||||||
@@ -114,9 +114,29 @@
|
|||||||
<path
|
<path
|
||||||
d="M13 18l-.397 .534a5.068 5.068 0 0 1 -7.127 0a4.972 4.972 0 0 1 0 -7.071l.524 -.463" />
|
d="M13 18l-.397 .534a5.068 5.068 0 0 1 -7.127 0a4.972 4.972 0 0 1 0 -7.071l.524 -.463" />
|
||||||
</svg>
|
</svg>
|
||||||
Port {{ $port }}
|
{{ $application->destination->server->ip }}:{{ explode(':', $port)[0] }}
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
@if (count($application->additional_servers) > 0)
|
||||||
|
@foreach ($application->additional_servers as $server)
|
||||||
|
<li>
|
||||||
|
<a class="text-xs text-white rounded-none hover:no-underline hover:bg-coollabs hover:text-white"
|
||||||
|
target="_blank"
|
||||||
|
href="http://{{ $server->ip }}:{{ explode(':', $port)[0] }}">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" class="w-6 h-6" viewBox="0 0 24 24"
|
||||||
|
stroke-width="1.5" stroke="currentColor" fill="none"
|
||||||
|
stroke-linecap="round" stroke-linejoin="round">
|
||||||
|
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
||||||
|
<path d="M9 15l6 -6" />
|
||||||
|
<path d="M11 6l.463 -.536a5 5 0 0 1 7.071 7.072l-.534 .464" />
|
||||||
|
<path
|
||||||
|
d="M13 18l-.397 .534a5.068 5.068 0 0 1 -7.127 0a4.972 4.972 0 0 1 0 -7.071l.524 -.463" />
|
||||||
|
</svg>
|
||||||
|
{{ $server->ip }}:{{ explode(':', $port)[0] }}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
@endforeach
|
||||||
|
@endif
|
||||||
@endif
|
@endif
|
||||||
@endforeach
|
@endforeach
|
||||||
@endif
|
@endif
|
||||||
|
|||||||
@@ -22,7 +22,7 @@
|
|||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
@endif
|
@endif
|
||||||
<input value="{{ $value }}" {{ $attributes->merge(['class' => $defaultClass . ' pl-10']) }}
|
<input value="{{ $value }}" {{ $attributes->merge(['class' => $defaultClass]) }}
|
||||||
@required($required) @if ($id !== 'null') wire:model={{ $id }} @endif
|
@required($required) @if ($id !== 'null') wire:model={{ $id }} @endif
|
||||||
wire:dirty.class.remove='text-white' wire:dirty.class="input-warning" wire:loading.attr="disabled"
|
wire:dirty.class.remove='text-white' wire:dirty.class="input-warning" wire:loading.attr="disabled"
|
||||||
type="{{ $type }}" @readonly($readonly) @disabled($disabled) id="{{ $id }}"
|
type="{{ $type }}" @readonly($readonly) @disabled($disabled) id="{{ $id }}"
|
||||||
|
|||||||
@@ -40,109 +40,133 @@
|
|||||||
</svg>
|
</svg>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
<div class="inline-block text-left " x-data="{ open: false }">
|
||||||
<details x-data="{ open: false }" class="dropdown dropdown-right" x-bind:open="open">
|
<div>
|
||||||
<summary class="bg-transparent border-none btn hover:bg-transparent no-animation"
|
<button x-on:click.prevent="open = !open" x-on:click.away="open = false" type="button"
|
||||||
x-on:click.prevent="open = !open" x-on:click.away="open = false"> <svg class="icon"
|
class="py-4 mx-4" id="menu-button" aria-expanded="true" aria-haspopup="true">
|
||||||
viewBox="0 0 256 256" xmlns="http://www.w3.org/2000/svg">
|
<svg class="icon" viewBox="0 0 256 256" xmlns="http://www.w3.org/2000/svg">
|
||||||
<path fill="currentColor"
|
<path fill="currentColor"
|
||||||
d="M224 128a8 8 0 0 1-8 8h-80v80a8 8 0 0 1-16 0v-80H40a8 8 0 0 1 0-16h80V40a8 8 0 0 1 16 0v80h80a8 8 0 0 1 8 8" />
|
d="M224 128a8 8 0 0 1-8 8h-80v80a8 8 0 0 1-16 0v-80H40a8 8 0 0 1 0-16h80V40a8 8 0 0 1 16 0v80h80a8 8 0 0 1 8 8" />
|
||||||
</svg></summary>
|
</svg>
|
||||||
<ul tabindex="0" class="w-64 p-2 border border-coolgray-200 dropdown-content menu bg-coolgray-100 ">
|
</button>
|
||||||
<li title="Tags" class="border-transparent hover:bg-coolgray-200 ">
|
</div>
|
||||||
<a class=" hover:bg-transparent hover:no-underline" href="{{ route('tags.index') }}">
|
<div x-show="open" x-cloak
|
||||||
<svg class="icon" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
class="absolute left-0 z-10 w-56 mx-4 mt-2 origin-top-right rounded shadow-lg bg-coolgray-100 ring-1 ring-black ring-opacity-5 focus:outline-none"
|
||||||
<g fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"
|
role="menu" aria-orientation="vertical" aria-labelledby="menu-button" tabindex="-1">
|
||||||
stroke-width="2">
|
<div class="py-1" role="none">
|
||||||
<path
|
<li title="Tags" class="border-transparent hover:bg-coolgray-200 ">
|
||||||
d="M3 8v4.172a2 2 0 0 0 .586 1.414l5.71 5.71a2.41 2.41 0 0 0 3.408 0l3.592-3.592a2.41 2.41 0 0 0 0-3.408l-5.71-5.71A2 2 0 0 0 9.172 6H5a2 2 0 0 0-2 2" />
|
<a class=" hover:bg-transparent hover:no-underline" href="{{ route('tags.index') }}">
|
||||||
<path d="m18 19l1.592-1.592a4.82 4.82 0 0 0 0-6.816L15 6m-8 4h-.01" />
|
<svg class="{{ request()->is('tags*') ? 'text-warning icon' : 'icon' }}"viewBox="0 0 24 24"
|
||||||
</g>
|
xmlns="http://www.w3.org/2000/svg">
|
||||||
</svg>
|
<g fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"
|
||||||
Tags
|
stroke-width="2">
|
||||||
</a>
|
<path
|
||||||
</li>
|
d="M3 8v4.172a2 2 0 0 0 .586 1.414l5.71 5.71a2.41 2.41 0 0 0 3.408 0l3.592-3.592a2.41 2.41 0 0 0 0-3.408l-5.71-5.71A2 2 0 0 0 9.172 6H5a2 2 0 0 0-2 2" />
|
||||||
<li title="Command Center" class="hover:bg-coolgray-200">
|
<path d="m18 19l1.592-1.592a4.82 4.82 0 0 0 0-6.816L15 6m-8 4h-.01" />
|
||||||
<a class="hover:bg-transparent hover:no-underline" href="{{ route('command-center') }}">
|
</g>
|
||||||
<svg xmlns="http://www.w3.org/2000/svg"
|
</svg>
|
||||||
class="{{ request()->is('command-center') ? ' icon' : 'icon' }}" viewBox="0 0 24 24"
|
Tags
|
||||||
stroke-width="1.5" stroke="currentColor" fill="none" stroke-linecap="round"
|
</a>
|
||||||
stroke-linejoin="round">
|
</li>
|
||||||
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
<li title="Command Center" class="hover:bg-coolgray-200">
|
||||||
<path d="M5 7l5 5l-5 5" />
|
<a class="hover:bg-transparent hover:no-underline" href="{{ route('command-center') }}">
|
||||||
<path d="M12 19l7 0" />
|
|
||||||
</svg>
|
|
||||||
Command Center
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li title="Source" class="hover:bg-coolgray-200">
|
|
||||||
<a class="hover:bg-transparent hover:no-underline" href="{{ route('source.all') }}">
|
|
||||||
<svg class="icon" viewBox="0 0 15 15" xmlns="http://www.w3.org/2000/svg">
|
|
||||||
<path fill="currentColor"
|
|
||||||
d="m6.793 1.207l.353.354l-.353-.354ZM1.207 6.793l-.353-.354l.353.354Zm0 1.414l.354-.353l-.354.353Zm5.586 5.586l-.354.353l.354-.353Zm1.414 0l-.353-.354l.353.354Zm5.586-5.586l.353.354l-.353-.354Zm0-1.414l-.354.353l.354-.353ZM8.207 1.207l.354-.353l-.354.353ZM6.44.854L.854 6.439l.707.707l5.585-5.585L6.44.854ZM.854 8.56l5.585 5.585l.707-.707l-5.585-5.585l-.707.707Zm7.707 5.585l5.585-5.585l-.707-.707l-5.585 5.585l.707.707Zm5.585-7.707L8.561.854l-.707.707l5.585 5.585l.707-.707Zm0 2.122a1.5 1.5 0 0 0 0-2.122l-.707.707a.5.5 0 0 1 0 .708l.707.707ZM6.44 14.146a1.5 1.5 0 0 0 2.122 0l-.707-.707a.5.5 0 0 1-.708 0l-.707.707ZM.854 6.44a1.5 1.5 0 0 0 0 2.122l.707-.707a.5.5 0 0 1 0-.708L.854 6.44Zm6.292-4.878a.5.5 0 0 1 .708 0L8.56.854a1.5 1.5 0 0 0-2.122 0l.707.707Zm-2 1.293l1 1l.708-.708l-1-1l-.708.708ZM7.5 5a.5.5 0 0 1-.5-.5H6A1.5 1.5 0 0 0 7.5 6V5Zm.5-.5a.5.5 0 0 1-.5.5v1A1.5 1.5 0 0 0 9 4.5H8ZM7.5 4a.5.5 0 0 1 .5.5h1A1.5 1.5 0 0 0 7.5 3v1Zm0-1A1.5 1.5 0 0 0 6 4.5h1a.5.5 0 0 1 .5-.5V3Zm.646 2.854l1.5 1.5l.707-.708l-1.5-1.5l-.707.708ZM10.5 8a.5.5 0 0 1-.5-.5H9A1.5 1.5 0 0 0 10.5 9V8Zm.5-.5a.5.5 0 0 1-.5.5v1A1.5 1.5 0 0 0 12 7.5h-1Zm-.5-.5a.5.5 0 0 1 .5.5h1A1.5 1.5 0 0 0 10.5 6v1Zm0-1A1.5 1.5 0 0 0 9 7.5h1a.5.5 0 0 1 .5-.5V6ZM7 5.5v4h1v-4H7Zm.5 5.5a.5.5 0 0 1-.5-.5H6A1.5 1.5 0 0 0 7.5 12v-1Zm.5-.5a.5.5 0 0 1-.5.5v1A1.5 1.5 0 0 0 9 10.5H8Zm-.5-.5a.5.5 0 0 1 .5.5h1A1.5 1.5 0 0 0 7.5 9v1Zm0-1A1.5 1.5 0 0 0 6 10.5h1a.5.5 0 0 1 .5-.5V9Z" />
|
|
||||||
</svg>
|
|
||||||
Sources
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li title="Security" class="hover:bg-coolgray-200">
|
|
||||||
<a class="hover:bg-transparent hover:no-underline" href="{{ route('security.private-key.index') }}">
|
|
||||||
<svg class="icon" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
|
||||||
<path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"
|
|
||||||
stroke-width="2"
|
|
||||||
d="m16.555 3.843l3.602 3.602a2.877 2.877 0 0 1 0 4.069l-2.643 2.643a2.877 2.877 0 0 1-4.069 0l-.301-.301l-6.558 6.558a2 2 0 0 1-1.239.578L5.172 21H4a1 1 0 0 1-.993-.883L3 20v-1.172a2 2 0 0 1 .467-1.284l.119-.13L4 17h2v-2h2v-2l2.144-2.144l-.301-.301a2.877 2.877 0 0 1 0-4.069l2.643-2.643a2.877 2.877 0 0 1 4.069 0zM15 9h.01" />
|
|
||||||
</svg>
|
|
||||||
Security
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li title="Profile" class="hover:bg-coolgray-200">
|
|
||||||
<a class="hover:bg-transparent hover:no-underline" href="{{ route('profile') }}">
|
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" class="icon" viewBox="0 0 24 24"
|
|
||||||
stroke-width="1.5" stroke="currentColor" fill="none" stroke-linecap="round"
|
|
||||||
stroke-linejoin="round">
|
|
||||||
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
|
||||||
<path d="M12 12m-9 0a9 9 0 1 0 18 0a9 9 0 1 0 -18 0" />
|
|
||||||
<path d="M12 10m-3 0a3 3 0 1 0 6 0a3 3 0 1 0 -6 0" />
|
|
||||||
<path d="M6.168 18.849a4 4 0 0 1 3.832 -2.849h4a4 4 0 0 1 3.834 2.855" />
|
|
||||||
</svg>
|
|
||||||
Profile
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li title="Teams" class="hover:bg-coolgray-200">
|
|
||||||
<a class="hover:bg-transparent hover:no-underline" href="{{ route('team.index') }}">
|
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" class="icon" viewBox="0 0 24 24"
|
|
||||||
stroke-width="1.5" stroke="currentColor" fill="none" stroke-linecap="round"
|
|
||||||
stroke-linejoin="round">
|
|
||||||
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
|
||||||
<path d="M10 13a2 2 0 1 0 4 0a2 2 0 0 0 -4 0" />
|
|
||||||
<path d="M8 21v-1a2 2 0 0 1 2 -2h4a2 2 0 0 1 2 2v1" />
|
|
||||||
<path d="M15 5a2 2 0 1 0 4 0a2 2 0 0 0 -4 0" />
|
|
||||||
<path d="M17 10h2a2 2 0 0 1 2 2v1" />
|
|
||||||
<path d="M5 5a2 2 0 1 0 4 0a2 2 0 0 0 -4 0" />
|
|
||||||
<path d="M3 13v-1a2 2 0 0 1 2 -2h2" />
|
|
||||||
</svg>
|
|
||||||
Teams
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
@if (isInstanceAdmin())
|
|
||||||
<li title="Settings" class="hover:bg-coolgray-200">
|
|
||||||
<a class="hover:bg-transparent hover:no-underline" href="/settings">
|
|
||||||
<svg xmlns="http://www.w3.org/2000/svg"
|
<svg xmlns="http://www.w3.org/2000/svg"
|
||||||
class="{{ request()->is('settings*') ? 'text-warning icon' : 'icon' }}"
|
class="{{ request()->is('command-center*') ? 'text-warning icon' : 'icon' }}"
|
||||||
viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" fill="none"
|
viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" fill="none"
|
||||||
stroke-linecap="round" stroke-linejoin="round">
|
stroke-linecap="round" stroke-linejoin="round">
|
||||||
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
||||||
<path
|
<path d="M5 7l5 5l-5 5" />
|
||||||
d="M10.325 4.317c.426 -1.756 2.924 -1.756 3.35 0a1.724 1.724 0 0 0 2.573 1.066c1.543 -.94 3.31 .826 2.37 2.37a1.724 1.724 0 0 0 1.065 2.572c1.756 .426 1.756 2.924 0 3.35a1.724 1.724 0 0 0 -1.066 2.573c.94 1.543 -.826 3.31 -2.37 2.37a1.724 1.724 0 0 0 -2.572 1.065c-.426 1.756 -2.924 1.756 -3.35 0a1.724 1.724 0 0 0 -2.573 -1.066c-1.543 .94 -3.31 -.826 -2.37 -2.37a1.724 1.724 0 0 0 -1.065 -2.572c-1.756 -.426 -1.756 -2.924 0 -3.35a1.724 1.724 0 0 0 1.066 -2.573c-.94 -1.543 .826 -3.31 2.37 -2.37c1 .608 2.296 .07 2.572 -1.065z" />
|
<path d="M12 19l7 0" />
|
||||||
<path d="M9 12a3 3 0 1 0 6 0a3 3 0 0 0 -6 0" />
|
|
||||||
</svg>
|
</svg>
|
||||||
Settings
|
Command Center
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li title="Source" class="hover:bg-coolgray-200">
|
||||||
|
<a class="hover:bg-transparent hover:no-underline" href="{{ route('source.all') }}">
|
||||||
|
<svg class="{{ request()->is('source*') ? 'text-warning icon' : 'icon' }}"
|
||||||
|
viewBox="0 0 15 15" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path fill="currentColor"
|
||||||
|
d="m6.793 1.207l.353.354l-.353-.354ZM1.207 6.793l-.353-.354l.353.354Zm0 1.414l.354-.353l-.354.353Zm5.586 5.586l-.354.353l.354-.353Zm1.414 0l-.353-.354l.353.354Zm5.586-5.586l.353.354l-.353-.354Zm0-1.414l-.354.353l.354-.353ZM8.207 1.207l.354-.353l-.354.353ZM6.44.854L.854 6.439l.707.707l5.585-5.585L6.44.854ZM.854 8.56l5.585 5.585l.707-.707l-5.585-5.585l-.707.707Zm7.707 5.585l5.585-5.585l-.707-.707l-5.585 5.585l.707.707Zm5.585-7.707L8.561.854l-.707.707l5.585 5.585l.707-.707Zm0 2.122a1.5 1.5 0 0 0 0-2.122l-.707.707a.5.5 0 0 1 0 .708l.707.707ZM6.44 14.146a1.5 1.5 0 0 0 2.122 0l-.707-.707a.5.5 0 0 1-.708 0l-.707.707ZM.854 6.44a1.5 1.5 0 0 0 0 2.122l.707-.707a.5.5 0 0 1 0-.708L.854 6.44Zm6.292-4.878a.5.5 0 0 1 .708 0L8.56.854a1.5 1.5 0 0 0-2.122 0l.707.707Zm-2 1.293l1 1l.708-.708l-1-1l-.708.708ZM7.5 5a.5.5 0 0 1-.5-.5H6A1.5 1.5 0 0 0 7.5 6V5Zm.5-.5a.5.5 0 0 1-.5.5v1A1.5 1.5 0 0 0 9 4.5H8ZM7.5 4a.5.5 0 0 1 .5.5h1A1.5 1.5 0 0 0 7.5 3v1Zm0-1A1.5 1.5 0 0 0 6 4.5h1a.5.5 0 0 1 .5-.5V3Zm.646 2.854l1.5 1.5l.707-.708l-1.5-1.5l-.707.708ZM10.5 8a.5.5 0 0 1-.5-.5H9A1.5 1.5 0 0 0 10.5 9V8Zm.5-.5a.5.5 0 0 1-.5.5v1A1.5 1.5 0 0 0 12 7.5h-1Zm-.5-.5a.5.5 0 0 1 .5.5h1A1.5 1.5 0 0 0 10.5 6v1Zm0-1A1.5 1.5 0 0 0 9 7.5h1a.5.5 0 0 1 .5-.5V6ZM7 5.5v4h1v-4H7Zm.5 5.5a.5.5 0 0 1-.5-.5H6A1.5 1.5 0 0 0 7.5 12v-1Zm.5-.5a.5.5 0 0 1-.5.5v1A1.5 1.5 0 0 0 9 10.5H8Zm-.5-.5a.5.5 0 0 1 .5.5h1A1.5 1.5 0 0 0 7.5 9v1Zm0-1A1.5 1.5 0 0 0 6 10.5h1a.5.5 0 0 1 .5-.5V9Z" />
|
||||||
|
</svg>
|
||||||
|
Sources
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li title="Security" class="hover:bg-coolgray-200">
|
||||||
|
<a class="hover:bg-transparent hover:no-underline"
|
||||||
|
href="{{ route('security.private-key.index') }}">
|
||||||
|
<svg class="{{ request()->is('security*') ? 'text-warning icon' : 'icon' }}"
|
||||||
|
viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path fill="none" stroke="currentColor" stroke-linecap="round"
|
||||||
|
stroke-linejoin="round" stroke-width="2"
|
||||||
|
d="m16.555 3.843l3.602 3.602a2.877 2.877 0 0 1 0 4.069l-2.643 2.643a2.877 2.877 0 0 1-4.069 0l-.301-.301l-6.558 6.558a2 2 0 0 1-1.239.578L5.172 21H4a1 1 0 0 1-.993-.883L3 20v-1.172a2 2 0 0 1 .467-1.284l.119-.13L4 17h2v-2h2v-2l2.144-2.144l-.301-.301a2.877 2.877 0 0 1 0-4.069l2.643-2.643a2.877 2.877 0 0 1 4.069 0zM15 9h.01" />
|
||||||
|
</svg>
|
||||||
|
Security
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li title="Profile" class="hover:bg-coolgray-200">
|
||||||
|
<a class="hover:bg-transparent hover:no-underline" href="{{ route('profile') }}">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg"
|
||||||
|
class="{{ request()->is('profile*') ? 'text-warning icon' : 'icon' }}"
|
||||||
|
viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" fill="none"
|
||||||
|
stroke-linecap="round" stroke-linejoin="round">
|
||||||
|
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
||||||
|
<path d="M12 12m-9 0a9 9 0 1 0 18 0a9 9 0 1 0 -18 0" />
|
||||||
|
<path d="M12 10m-3 0a3 3 0 1 0 6 0a3 3 0 1 0 -6 0" />
|
||||||
|
<path d="M6.168 18.849a4 4 0 0 1 3.832 -2.849h4a4 4 0 0 1 3.834 2.855" />
|
||||||
|
</svg>
|
||||||
|
Profile
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li title="Teams" class="hover:bg-coolgray-200">
|
||||||
|
<a class="hover:bg-transparent hover:no-underline" href="{{ route('team.index') }}">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"
|
||||||
|
class="{{ request()->is('team*') ? 'text-warning icon' : 'icon' }}"
|
||||||
|
stroke-width="1.5" stroke="currentColor" fill="none" stroke-linecap="round"
|
||||||
|
stroke-linejoin="round">
|
||||||
|
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
||||||
|
<path d="M10 13a2 2 0 1 0 4 0a2 2 0 0 0 -4 0" />
|
||||||
|
<path d="M8 21v-1a2 2 0 0 1 2 -2h4a2 2 0 0 1 2 2v1" />
|
||||||
|
<path d="M15 5a2 2 0 1 0 4 0a2 2 0 0 0 -4 0" />
|
||||||
|
<path d="M17 10h2a2 2 0 0 1 2 2v1" />
|
||||||
|
<path d="M5 5a2 2 0 1 0 4 0a2 2 0 0 0 -4 0" />
|
||||||
|
<path d="M3 13v-1a2 2 0 0 1 2 -2h2" />
|
||||||
|
</svg>
|
||||||
|
Teams @if (isCloud())
|
||||||
|
/ Subscription
|
||||||
|
@endif
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
@endif
|
|
||||||
|
|
||||||
</ul>
|
@if (isInstanceAdmin())
|
||||||
</details>
|
<li title="Settings" class="hover:bg-coolgray-200">
|
||||||
@if (isCloud())
|
<a class="hover:bg-transparent hover:no-underline" href="/settings">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg"
|
||||||
|
class="{{ request()->is('settings*') ? 'text-warning icon' : 'icon' }}"
|
||||||
|
viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" fill="none"
|
||||||
|
stroke-linecap="round" stroke-linejoin="round">
|
||||||
|
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
||||||
|
<path
|
||||||
|
d="M10.325 4.317c.426 -1.756 2.924 -1.756 3.35 0a1.724 1.724 0 0 0 2.573 1.066c1.543 -.94 3.31 .826 2.37 2.37a1.724 1.724 0 0 0 1.065 2.572c1.756 .426 1.756 2.924 0 3.35a1.724 1.724 0 0 0 -1.066 2.573c.94 1.543 -.826 3.31 -2.37 2.37a1.724 1.724 0 0 0 -2.572 1.065c-.426 1.756 -2.924 1.756 -3.35 0a1.724 1.724 0 0 0 -2.573 -1.066c-1.543 .94 -3.31 -.826 -2.37 -2.37a1.724 1.724 0 0 0 -1.065 -2.572c-1.756 -.426 -1.756 -2.924 0 -3.35a1.724 1.724 0 0 0 1.066 -2.573c-.94 -1.543 .826 -3.31 2.37 -2.37c1 .608 2.296 .07 2.572 -1.065z" />
|
||||||
|
<path d="M9 12a3 3 0 1 0 6 0a3 3 0 0 0 -6 0" />
|
||||||
|
</svg>
|
||||||
|
Settings
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
@endif
|
||||||
|
<li title="Boarding" class="hover:bg-coolgray-200">
|
||||||
|
<a class="hover:bg-transparent hover:no-underline" href="{{ route('boarding') }}">
|
||||||
|
<svg class="{{ request()->is('boarding*') ? 'text-warning icon' : 'icon' }}"
|
||||||
|
viewBox="0 0 256 256" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path fill="currentColor"
|
||||||
|
d="M224 128a8 8 0 0 1-8 8h-88a8 8 0 0 1 0-16h88a8 8 0 0 1 8 8m-96-56h88a8 8 0 0 0 0-16h-88a8 8 0 0 0 0 16m88 112h-88a8 8 0 0 0 0 16h88a8 8 0 0 0 0-16M82.34 42.34L56 68.69L45.66 58.34a8 8 0 0 0-11.32 11.32l16 16a8 8 0 0 0 11.32 0l32-32a8 8 0 0 0-11.32-11.32m0 64L56 132.69l-10.34-10.35a8 8 0 0 0-11.32 11.32l16 16a8 8 0 0 0 11.32 0l32-32a8 8 0 0 0-11.32-11.32m0 64L56 196.69l-10.34-10.35a8 8 0 0 0-11.32 11.32l16 16a8 8 0 0 0 11.32 0l32-32a8 8 0 0 0-11.32-11.32" />
|
||||||
|
</svg>
|
||||||
|
Boarding
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@if (isCloud() && isInstanceAdmin())
|
||||||
<li title="Admin">
|
<li title="Admin">
|
||||||
<a class="hover:bg-transparent" href="/admin">
|
<a class="hover:bg-transparent" href="/admin">
|
||||||
<svg class="text-pink-600 icon" viewBox="0 0 256 256" xmlns="http://www.w3.org/2000/svg">
|
<svg class="text-pink-600 icon" viewBox="0 0 256 256" xmlns="http://www.w3.org/2000/svg">
|
||||||
@@ -180,11 +204,12 @@
|
|||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
<form action="/logout" method="POST" class="hover:bg-transparent">
|
<form action="/logout" method="POST" class="hover:bg-transparent">
|
||||||
<li title="Logout" class="mb-6 hover:transparent">
|
<li title="Logout" class="mb-6 hover:transparent">
|
||||||
@csrf
|
@csrf
|
||||||
<button type="submit" class="rounded-none hover:text-white hover:bg-transparent">
|
<button type="submit" class="rounded-none hover:text-white hover:bg-transparent">
|
||||||
<svg class="icon" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
<svg class="icon" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||||
<path fill="currentColor" d="M12 22C6.477 22 2 17.523 2 12S6.477 2 12 2a9.985 9.985 0 0 1 8 4h-2.71a8 8 0 1 0 .001 12h2.71A9.985 9.985 0 0 1 12 22m7-6v-3h-8v-2h8V8l5 4z"/>
|
<path fill="currentColor"
|
||||||
|
d="M12 22C6.477 22 2 17.523 2 12S6.477 2 12 2a9.985 9.985 0 0 1 8 4h-2.71a8 8 0 1 0 .001 12h2.71A9.985 9.985 0 0 1 12 22m7-6v-3h-8v-2h8V8l5 4z" />
|
||||||
</svg>
|
</svg>
|
||||||
</button>
|
</button>
|
||||||
</li>
|
</li>
|
||||||
|
|||||||
@@ -18,6 +18,12 @@
|
|||||||
]) }}">
|
]) }}">
|
||||||
<button>General</button>
|
<button>General</button>
|
||||||
</a>
|
</a>
|
||||||
|
<a class="{{ request()->routeIs('server.resources') ? 'text-white' : '' }}"
|
||||||
|
href="{{ route('server.resources', [
|
||||||
|
'server_uuid' => data_get($parameters, 'server_uuid'),
|
||||||
|
]) }}">
|
||||||
|
<button>Resources</button>
|
||||||
|
</a>
|
||||||
<a class="{{ request()->routeIs('server.private-key') ? 'text-white' : '' }}"
|
<a class="{{ request()->routeIs('server.private-key') ? 'text-white' : '' }}"
|
||||||
href="{{ route('server.private-key', [
|
href="{{ route('server.private-key', [
|
||||||
'server_uuid' => data_get($parameters, 'server_uuid'),
|
'server_uuid' => data_get($parameters, 'server_uuid'),
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
</a>
|
</a>
|
||||||
<x-services.links />
|
<x-services.links />
|
||||||
<div class="flex-1"></div>
|
<div class="flex-1"></div>
|
||||||
@if (serviceStatus($service) === 'degraded')
|
@if ($service->status() === 'degraded')
|
||||||
<button wire:click='deploy' onclick="startService.showModal()"
|
<button wire:click='deploy' onclick="startService.showModal()"
|
||||||
class="flex items-center gap-2 cursor-pointer hover:text-white text-neutral-400">
|
class="flex items-center gap-2 cursor-pointer hover:text-white text-neutral-400">
|
||||||
<svg class="w-5 h-5 text-warning" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
<svg class="w-5 h-5 text-warning" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||||
@@ -26,7 +26,7 @@
|
|||||||
Stop
|
Stop
|
||||||
</button>
|
</button>
|
||||||
@endif
|
@endif
|
||||||
@if (serviceStatus($service) === 'running')
|
@if ($service->status() === 'running')
|
||||||
<button wire:click='restart' class="flex items-center gap-2 cursor-pointer hover:text-white text-neutral-400">
|
<button wire:click='restart' class="flex items-center gap-2 cursor-pointer hover:text-white text-neutral-400">
|
||||||
<svg class="w-5 h-5 text-warning" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
<svg class="w-5 h-5 text-warning" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||||
<g fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"
|
<g fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"
|
||||||
@@ -47,7 +47,7 @@
|
|||||||
Stop
|
Stop
|
||||||
</button>
|
</button>
|
||||||
@endif
|
@endif
|
||||||
@if (serviceStatus($service) === 'exited')
|
@if ($service->status() === 'exited')
|
||||||
<button wire:click='stop(true)'
|
<button wire:click='stop(true)'
|
||||||
class="flex items-center gap-2 cursor-pointer hover:text-white text-neutral-400">
|
class="flex items-center gap-2 cursor-pointer hover:text-white text-neutral-400">
|
||||||
<svg class="w-5 h-5 " viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg">
|
<svg class="w-5 h-5 " viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
@props(['closeWithX' => 'false', 'fullScreen' => 'false'])
|
@props(['closeWithX' => false, 'fullScreen' => false])
|
||||||
<div x-data="{
|
<div x-data="{
|
||||||
slideOverOpen: false
|
slideOverOpen: false
|
||||||
}" class="relative w-auto h-auto">
|
}" class="relative w-auto h-auto">
|
||||||
@@ -19,7 +19,7 @@
|
|||||||
x-transition:leave-start="translate-x-0" x-transition:leave-end="translate-x-full"
|
x-transition:leave-start="translate-x-0" x-transition:leave-end="translate-x-full"
|
||||||
@class([
|
@class([
|
||||||
'max-w-md w-screen' => !$fullScreen,
|
'max-w-md w-screen' => !$fullScreen,
|
||||||
'max-w-7xl w-screen' => $fullScreen,
|
'max-w-4xl w-screen' => $fullScreen,
|
||||||
])>
|
])>
|
||||||
<div
|
<div
|
||||||
class="flex flex-col h-full py-6 overflow-hidden border-l shadow-lg bg-base-100 border-neutral-800">
|
class="flex flex-col h-full py-6 overflow-hidden border-l shadow-lg bg-base-100 border-neutral-800">
|
||||||
|
|||||||
@@ -1,11 +1,15 @@
|
|||||||
|
@props(['status', 'showRefreshButton' => true])
|
||||||
@if (str($status)->startsWith('running'))
|
@if (str($status)->startsWith('running'))
|
||||||
<x-status.running :status="$status" />
|
<x-status.running :status="$status" />
|
||||||
@elseif(str($status)->startsWith('restarting') || str($status)->startsWith('starting') || str($status)->startsWith('degraded'))
|
@elseif(str($status)->startsWith('restarting') ||
|
||||||
|
str($status)->startsWith('starting') ||
|
||||||
|
str($status)->startsWith('degraded'))
|
||||||
<x-status.restarting :status="$status" />
|
<x-status.restarting :status="$status" />
|
||||||
@else
|
@else
|
||||||
<x-status.stopped :status="$status" />
|
<x-status.stopped :status="$status"/>
|
||||||
@endif
|
@endif
|
||||||
@if (!str($status)->contains('exited'))
|
|
||||||
|
@if (!str($status)->contains('exited') && $showRefreshButton)
|
||||||
<button title="Refresh Status" wire:click='check_status(true)' class="mx-1 hover:fill-white fill-warning">
|
<button title="Refresh Status" wire:click='check_status(true)' class="mx-1 hover:fill-white fill-warning">
|
||||||
<svg class="w-4 h-4" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
<svg class="w-4 h-4" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||||
<path
|
<path
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
<div class="pl-2 pr-1 text-xs font-bold tracking-widerr text-warning">
|
<div class="pl-2 pr-1 text-xs font-bold tracking-widerr text-warning">
|
||||||
{{ str($status)->before(':')->headline() }}
|
{{ str($status)->before(':')->headline() }}
|
||||||
</div>
|
</div>
|
||||||
@if (!str($status)->startsWith('Proxy'))
|
@if (!str($status)->startsWith('Proxy') && !str($status)->contains('('))
|
||||||
<div class="text-xs text-warning">({{ str($status)->after(':') }})</div>
|
<div class="text-xs text-warning">({{ str($status)->after(':') }})</div>
|
||||||
@endif
|
@endif
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
<div class="pl-2 pr-1 text-xs font-bold tracking-wider text-success">
|
<div class="pl-2 pr-1 text-xs font-bold tracking-wider text-success">
|
||||||
{{ str($status)->before(':')->headline() }}
|
{{ str($status)->before(':')->headline() }}
|
||||||
</div>
|
</div>
|
||||||
@if (!str($status)->startsWith('Proxy'))
|
@if (!str($status)->startsWith('Proxy') && !str($status)->contains('('))
|
||||||
<div class="text-xs text-success">({{ str($status)->after(':') }})</div>
|
<div class="text-xs text-success">({{ str($status)->after(':') }})</div>
|
||||||
@endif
|
@endif
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
@else
|
@else
|
||||||
<x-status.stopped :status="$complexStatus" />
|
<x-status.stopped :status="$complexStatus" />
|
||||||
@endif
|
@endif
|
||||||
@if (!str($complexStatus)->contains('exited'))
|
@if (!str($complexStatus)->contains('exited') && $showRefreshButton)
|
||||||
<button title="Refresh Status" wire:click='check_status(true)' class="mx-1 hover:fill-white fill-warning">
|
<button title="Refresh Status" wire:click='check_status(true)' class="mx-1 hover:fill-white fill-warning">
|
||||||
<svg class="w-4 h-4" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
<svg class="w-4 h-4" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||||
<path
|
<path
|
||||||
|
|||||||
@@ -121,18 +121,24 @@
|
|||||||
There are already servers available for your Team. Do you want to use one of them?
|
There are already servers available for your Team. Do you want to use one of them?
|
||||||
</x-slot:question>
|
</x-slot:question>
|
||||||
<x-slot:actions>
|
<x-slot:actions>
|
||||||
<x-forms.button class="justify-center w-64 box" wire:click="createNewServer">No (create one for me)
|
<div class="flex flex-col gap-4">
|
||||||
</x-forms.button>
|
<div>
|
||||||
<div>
|
<x-forms.button class="justify-center w-64 box" wire:click="createNewServer">No (create one
|
||||||
<form wire:submit='selectExistingServer' class="flex flex-col w-full gap-4 lg:w-96">
|
for
|
||||||
<x-forms.select label="Existing servers" class="w-96" id='selectedExistingServer'>
|
me)
|
||||||
@foreach ($servers as $server)
|
</x-forms.button>
|
||||||
<option wire:key="{{ $loop->index }}" value="{{ $server->id }}">
|
</div>
|
||||||
{{ $server->name }}</option>
|
<div>
|
||||||
@endforeach
|
<form wire:submit='selectExistingServer' class="flex flex-col w-full gap-4 lg:w-96">
|
||||||
</x-forms.select>
|
<x-forms.select label="Existing servers" class="w-96" id='selectedExistingServer'>
|
||||||
<x-forms.button type="submit">Use this Server</x-forms.button>
|
@foreach ($servers as $server)
|
||||||
</form>
|
<option wire:key="{{ $loop->index }}" value="{{ $server->id }}">
|
||||||
|
{{ $server->name }}</option>
|
||||||
|
@endforeach
|
||||||
|
</x-forms.select>
|
||||||
|
<x-forms.button type="submit">Use this Server</x-forms.button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@if (!$serverReachable)
|
@if (!$serverReachable)
|
||||||
This server is not reachable with the following public key.
|
This server is not reachable with the following public key.
|
||||||
@@ -216,7 +222,7 @@
|
|||||||
helper="If you are using Cloudflare Tunnels, enable this. It will proxy all ssh requests to your server through Cloudflare.<br><span class='text-warning'>Coolify does not install/setup Cloudflare (cloudflared) on your server.</span>"
|
helper="If you are using Cloudflare Tunnels, enable this. It will proxy all ssh requests to your server through Cloudflare.<br><span class='text-warning'>Coolify does not install/setup Cloudflare (cloudflared) on your server.</span>"
|
||||||
id="isCloudflareTunnel" label="Cloudflare Tunnel" />
|
id="isCloudflareTunnel" label="Cloudflare Tunnel" />
|
||||||
</div>
|
</div>
|
||||||
<x-forms.button type="submit">Check Connection</x-forms.button>
|
<x-forms.button type="submit">Continue</x-forms.button>
|
||||||
</form>
|
</form>
|
||||||
</x-slot:actions>
|
</x-slot:actions>
|
||||||
<x-slot:explanation>
|
<x-slot:explanation>
|
||||||
@@ -227,14 +233,15 @@
|
|||||||
@endif
|
@endif
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
@if ($currentState === 'install-docker')
|
@if ($currentState === 'validate-server')
|
||||||
<x-boarding-step title="Install Docker">
|
<x-boarding-step title="Validate & Configure Server">
|
||||||
<x-slot:question>
|
<x-slot:question>
|
||||||
Could not find Docker Engine on your server. Do you want me to install it for you?
|
I need to validate your server (connection, Docker Engine, etc) and configure if something is
|
||||||
|
missing for me. Are you okay with this?
|
||||||
</x-slot:question>
|
</x-slot:question>
|
||||||
<x-slot:actions>
|
<x-slot:actions>
|
||||||
<x-slide-over closeWithX fullScreen>
|
<x-slide-over closeWithX fullScreen>
|
||||||
<x-slot:title>Configuring Server</x-slot:title>
|
<x-slot:title>Validate & configure</x-slot:title>
|
||||||
<x-slot:content>
|
<x-slot:content>
|
||||||
<livewire:server.validate-and-install :server="$this->createdServer" />
|
<livewire:server.validate-and-install :server="$this->createdServer" />
|
||||||
</x-slot:content>
|
</x-slot:content>
|
||||||
@@ -254,7 +261,7 @@
|
|||||||
</x-boarding-step>
|
</x-boarding-step>
|
||||||
@endif
|
@endif
|
||||||
</div>
|
</div>
|
||||||
<div>
|
{{-- <div>
|
||||||
@if ($currentState === 'select-proxy')
|
@if ($currentState === 'select-proxy')
|
||||||
<x-boarding-step title="Select a Proxy">
|
<x-boarding-step title="Select a Proxy">
|
||||||
<x-slot:question>
|
<x-slot:question>
|
||||||
@@ -281,7 +288,7 @@
|
|||||||
</x-slot:explanation>
|
</x-slot:explanation>
|
||||||
</x-boarding-step>
|
</x-boarding-step>
|
||||||
@endif
|
@endif
|
||||||
</div>
|
</div> --}}
|
||||||
<div>
|
<div>
|
||||||
@if ($currentState === 'create-project')
|
@if ($currentState === 'create-project')
|
||||||
<x-boarding-step title="Project">
|
<x-boarding-step title="Project">
|
||||||
|
|||||||
@@ -15,7 +15,11 @@
|
|||||||
@endif
|
@endif
|
||||||
<x-forms.checkbox
|
<x-forms.checkbox
|
||||||
helper="Your application will be available only on https if your domain starts with https://..."
|
helper="Your application will be available only on https if your domain starts with https://..."
|
||||||
instantSave id="application.settings.is_force_https_enabled" label="Force Https" />
|
instantSave id="is_force_https_enabled" label="Force Https" />
|
||||||
|
<x-forms.checkbox
|
||||||
|
helper="The deployed container will have the same name ({{ $application->uuid }}). <span class='font-bold text-warning'>You will lose the rolling update feature!</span>"
|
||||||
|
instantSave id="application.settings.is_consistent_container_name_enabled"
|
||||||
|
label="Consistent Container Names" />
|
||||||
<h4>Logs</h4>
|
<h4>Logs</h4>
|
||||||
@if (!$application->settings->is_raw_compose_deployment_enabled)
|
@if (!$application->settings->is_raw_compose_deployment_enabled)
|
||||||
<x-forms.checkbox helper="Drain logs to your configured log drain endpoint in your Server settings."
|
<x-forms.checkbox helper="Drain logs to your configured log drain endpoint in your Server settings."
|
||||||
|
|||||||
@@ -5,9 +5,12 @@
|
|||||||
<x-forms.button type="submit">
|
<x-forms.button type="submit">
|
||||||
Save
|
Save
|
||||||
</x-forms.button>
|
</x-forms.button>
|
||||||
@if ($isConfigurationChanged && !is_null($application->config_hash))
|
@if ($isConfigurationChanged && !is_null($application->config_hash) && !$application->isExited())
|
||||||
<div class="font-bold text-warning">Configuration not applied to the running application. You need to
|
<div title="Configuration not applied to the running application. You need to redeploy.">
|
||||||
redeploy.</div>
|
<svg class="w-6 h-6 text-warning" viewBox="0 0 256 256" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path fill="currentColor" d="M240.26 186.1L152.81 34.23a28.74 28.74 0 0 0-49.62 0L15.74 186.1a27.45 27.45 0 0 0 0 27.71A28.31 28.31 0 0 0 40.55 228h174.9a28.31 28.31 0 0 0 24.79-14.19a27.45 27.45 0 0 0 .02-27.71m-20.8 15.7a4.46 4.46 0 0 1-4 2.2H40.55a4.46 4.46 0 0 1-4-2.2a3.56 3.56 0 0 1 0-3.73L124 46.2a4.77 4.77 0 0 1 8 0l87.44 151.87a3.56 3.56 0 0 1 .02 3.73M116 136v-32a12 12 0 0 1 24 0v32a12 12 0 0 1-24 0m28 40a16 16 0 1 1-16-16a16 16 0 0 1 16 16"/>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
@endif
|
@endif
|
||||||
</div>
|
</div>
|
||||||
<div>General configuration for your application.</div>
|
<div>General configuration for your application.</div>
|
||||||
|
|||||||
@@ -1,5 +1,9 @@
|
|||||||
<div>
|
<div>
|
||||||
<livewire:project.application.preview.form :application="$application" />
|
<livewire:project.application.preview.form :application="$application" />
|
||||||
|
@if (count($application->additional_servers) > 0)
|
||||||
|
<div class="pb-4">Previews will be deployed on <span
|
||||||
|
class="text-warning">{{ $application->destination->server->name }}</span>.</div>
|
||||||
|
@endif
|
||||||
<div>
|
<div>
|
||||||
@if ($application->is_github_based())
|
@if ($application->is_github_based())
|
||||||
<div class="flex items-center gap-2">
|
<div class="flex items-center gap-2">
|
||||||
@@ -51,7 +55,7 @@
|
|||||||
</div>
|
</div>
|
||||||
@if ($application->previews->count() > 0)
|
@if ($application->previews->count() > 0)
|
||||||
<div class="pb-4">Previews</div>
|
<div class="pb-4">Previews</div>
|
||||||
<div class="flex gap-6 ">
|
<div class="flex flex-wrap gap-6">
|
||||||
@foreach ($application->previews as $preview)
|
@foreach ($application->previews as $preview)
|
||||||
<div class="flex flex-col p-4 bg-coolgray-200">
|
<div class="flex flex-col p-4 bg-coolgray-200">
|
||||||
<div class="flex gap-2">PR #{{ data_get($preview, 'pull_request_id') }} |
|
<div class="flex gap-2">PR #{{ data_get($preview, 'pull_request_id') }} |
|
||||||
|
|||||||
@@ -213,9 +213,9 @@
|
|||||||
@endif --}}
|
@endif --}}
|
||||||
<div class="flex flex-col justify-center gap-4 text-left xl:flex-row xl:flex-wrap">
|
<div class="flex flex-col justify-center gap-4 text-left xl:flex-row xl:flex-wrap">
|
||||||
@forelse($servers as $server)
|
@forelse($servers as $server)
|
||||||
<div class="box group" wire:click="setServer({{ $server }})">
|
<div class="w-64 box group" wire:click="setServer({{ $server }})">
|
||||||
<div class="flex flex-col mx-6">
|
<div class="flex flex-col mx-6">
|
||||||
<div class="group-hover:text-white">
|
<div class="font-bold group-hover:text-white">
|
||||||
{{ $server->name }}
|
{{ $server->name }}
|
||||||
</div>
|
</div>
|
||||||
<div class="text-xs group-hover:text-white">
|
<div class="text-xs group-hover:text-white">
|
||||||
@@ -263,13 +263,13 @@
|
|||||||
Standalone Docker <span class="text-xs">({{ $standaloneDocker->name }})</span>
|
Standalone Docker <span class="text-xs">({{ $standaloneDocker->name }})</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="text-xs group-hover:text-white">
|
<div class="text-xs group-hover:text-white">
|
||||||
network: {{ $standaloneDocker->network }}</div>
|
Network: {{ $standaloneDocker->network }}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@endforeach
|
@endforeach
|
||||||
@endif
|
@endif
|
||||||
<a href="{{ route('destination.new', ['server_id' => $server_id]) }}"
|
<a href="{{ route('destination.new', ['server_id' => $server_id]) }}"
|
||||||
class="items-center justify-center pb-10 text-center box-without-bg group bg-coollabs hover:bg-coollabs-100">
|
class="items-center justify-center text-center box-without-bg group bg-coollabs hover:bg-coollabs-100">
|
||||||
<div class="flex flex-col mx-6 ">
|
<div class="flex flex-col mx-6 ">
|
||||||
<div class="font-bold text-white">
|
<div class="font-bold text-white">
|
||||||
+ Add New
|
+ Add New
|
||||||
|
|||||||
@@ -48,25 +48,27 @@
|
|||||||
<x-forms.input placeholder="Search for name, fqdn..." class="w-full" x-model="search" />
|
<x-forms.input placeholder="Search for name, fqdn..." class="w-full" x-model="search" />
|
||||||
<div class="grid grid-cols-1 gap-4 pt-4 lg:grid-cols-2 xl:grid-cols-3">
|
<div class="grid grid-cols-1 gap-4 pt-4 lg:grid-cols-2 xl:grid-cols-3">
|
||||||
<template x-for="item in filteredApplications" :key="item.id">
|
<template x-for="item in filteredApplications" :key="item.id">
|
||||||
<span class="relative">
|
<span>
|
||||||
<a class="h-24 box group" :href="item.hrefLink">
|
<a class="h-24 box group" :href="item.hrefLink">
|
||||||
<div class="flex flex-col mx-6">
|
<div class="flex flex-col mx-6">
|
||||||
<div class="pb-2 font-bold text-white" x-text="item.name"></div>
|
<div class="flex gap-2">
|
||||||
|
<div class="pb-2 font-bold text-white" x-text="item.name"></div>
|
||||||
|
<template x-if="item.status.startsWith('running')">
|
||||||
|
<div title="running" class="mt-1 bg-success badge badge-xs"></div>
|
||||||
|
</template>
|
||||||
|
<template x-if="item.status.startsWith('exited')">
|
||||||
|
<div title="exited" class="mt-1 bg-error badge badge-xs"></div>
|
||||||
|
</template>
|
||||||
|
<template x-if="item.status.startsWith('restarting')">
|
||||||
|
<div title="restarting" class="mt-1 bg-warningbadge badge-xs"></div>
|
||||||
|
</template>
|
||||||
|
<template x-if="item.status.startsWith('degraded')">
|
||||||
|
<div title="degraded" class="mt-1 bg-warning badge badge-xs"></div>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
<div class="description" x-text="item.description"></div>
|
<div class="description" x-text="item.description"></div>
|
||||||
<div class="description" x-text="item.fqdn"></div>
|
<div class="description" x-text="item.fqdn"></div>
|
||||||
</div>
|
</div>
|
||||||
<template x-if="item.status.startsWith('running')">
|
|
||||||
<div class="absolute bg-success -top-1 -left-1 badge badge-xs"></div>
|
|
||||||
</template>
|
|
||||||
<template x-if="item.status.startsWith('exited')">
|
|
||||||
<div class="absolute bg-error -top-1 -left-1 badge badge-xs"></div>
|
|
||||||
</template>
|
|
||||||
<template x-if="item.status.startsWith('restarting')" >
|
|
||||||
<div class="absolute bg-warning -top-1 -left-1 badge badge-xs"></div>
|
|
||||||
</template>
|
|
||||||
<template x-if="item.status.startsWith('degraded')">
|
|
||||||
<div class="absolute bg-warning -top-1 -left-1 badge badge-xs"></div>
|
|
||||||
</template>
|
|
||||||
</a>
|
</a>
|
||||||
<div class="flex gap-1 pt-1 group-hover:text-white group min-h-6">
|
<div class="flex gap-1 pt-1 group-hover:text-white group min-h-6">
|
||||||
<template x-for="tag in item.tags">
|
<template x-for="tag in item.tags">
|
||||||
@@ -79,21 +81,26 @@
|
|||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
<template x-for="item in filteredPostgresqls" :key="item.id">
|
<template x-for="item in filteredPostgresqls" :key="item.id">
|
||||||
<span class="relative">
|
<span>
|
||||||
<a class="h-24 box group" :href="item.hrefLink">
|
<a class="h-24 box group" :href="item.hrefLink">
|
||||||
<div class="flex flex-col mx-6">
|
<div class="flex flex-col mx-6">
|
||||||
<div class="font-bold text-white" x-text="item.name"></div>
|
<div class="flex gap-2">
|
||||||
|
<div class="pb-2 font-bold text-white" x-text="item.name"></div>
|
||||||
|
<template x-if="item.status.startsWith('running')">
|
||||||
|
<div title="running" class="mt-1 bg-success badge badge-xs"></div>
|
||||||
|
</template>
|
||||||
|
<template x-if="item.status.startsWith('exited')">
|
||||||
|
<div title="exited" class="mt-1 bg-error badge badge-xs"></div>
|
||||||
|
</template>
|
||||||
|
<template x-if="item.status.startsWith('restarting')">
|
||||||
|
<div title="restarting" class="mt-1 bg-warningbadge badge-xs"></div>
|
||||||
|
</template>
|
||||||
|
<template x-if="item.status.startsWith('degraded')">
|
||||||
|
<div title="degraded" class="mt-1 bg-warning badge badge-xs"></div>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
<div class="description" x-text="item.description"></div>
|
<div class="description" x-text="item.description"></div>
|
||||||
</div>
|
</div>
|
||||||
<template x-if="item.status.startsWith('running')">
|
|
||||||
<div class="absolute bg-success -top-1 -left-1 badge badge-xs"></div>
|
|
||||||
</template>
|
|
||||||
<template x-if="item.status.startsWith('exited')">
|
|
||||||
<div class="absolute bg-error -top-1 -left-1 badge badge-xs"></div>
|
|
||||||
</template>
|
|
||||||
<template x-if="item.status.startsWith('restarting')">
|
|
||||||
<div class="absolute bg-warning -top-1 -left-1 badge badge-xs"></div>
|
|
||||||
</template>
|
|
||||||
</a>
|
</a>
|
||||||
<div class="flex gap-1 pt-1 group-hover:text-white group min-h-6">
|
<div class="flex gap-1 pt-1 group-hover:text-white group min-h-6">
|
||||||
<template x-for="tag in item.tags">
|
<template x-for="tag in item.tags">
|
||||||
@@ -106,22 +113,26 @@
|
|||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
<template x-for="item in filteredRedis" :key="item.id">
|
<template x-for="item in filteredRedis" :key="item.id">
|
||||||
<span class="relative">
|
<span>
|
||||||
<a class="h-24 box group" :href="item.hrefLink">
|
<a class="h-24 box group" :href="item.hrefLink">
|
||||||
<div class="flex flex-col mx-6">
|
<div class="flex flex-col mx-6">
|
||||||
<div class="font-bold text-white" x-text="item.name"></div>
|
<div class="flex gap-2">
|
||||||
|
<div class="pb-2 font-bold text-white" x-text="item.name"></div>
|
||||||
|
<template x-if="item.status.startsWith('running')">
|
||||||
|
<div title="running" class="mt-1 bg-success badge badge-xs"></div>
|
||||||
|
</template>
|
||||||
|
<template x-if="item.status.startsWith('exited')">
|
||||||
|
<div title="exited" class="mt-1 bg-error badge badge-xs"></div>
|
||||||
|
</template>
|
||||||
|
<template x-if="item.status.startsWith('restarting')">
|
||||||
|
<div title="restarting" class="mt-1 bg-warningbadge badge-xs"></div>
|
||||||
|
</template>
|
||||||
|
<template x-if="item.status.startsWith('degraded')">
|
||||||
|
<div title="degraded" class="mt-1 bg-warning badge badge-xs"></div>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
<div class="description" x-text="item.description"></div>
|
<div class="description" x-text="item.description"></div>
|
||||||
</div>
|
</div>
|
||||||
<template x-if="item.status.startsWith('running')">
|
|
||||||
<div class="absolute bg-success -top-1 -left-1 badge badge-xs"></div>
|
|
||||||
</template>
|
|
||||||
<template x-if="item.status.startsWith('exited')">
|
|
||||||
<div class="absolute bg-error -top-1 -left-1 badge badge-xs"></div>
|
|
||||||
</template>
|
|
||||||
<template x-if="item.status.startsWith('restarting')">
|
|
||||||
<div class="absolute bg-warning -top-1 -left-1 badge badge-xs"></div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
</a>
|
</a>
|
||||||
<div class="flex gap-1 pt-1 group-hover:text-white group min-h-6">
|
<div class="flex gap-1 pt-1 group-hover:text-white group min-h-6">
|
||||||
<template x-for="tag in item.tags">
|
<template x-for="tag in item.tags">
|
||||||
@@ -134,21 +145,26 @@
|
|||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
<template x-for="item in filteredMongodbs" :key="item.id">
|
<template x-for="item in filteredMongodbs" :key="item.id">
|
||||||
<span class="relative">
|
<span>
|
||||||
<a class="h-24 box group" :href="item.hrefLink">
|
<a class="h-24 box group" :href="item.hrefLink">
|
||||||
<div class="flex flex-col mx-6">
|
<div class="flex flex-col mx-6">
|
||||||
<div class="font-bold text-white" x-text="item.name"></div>
|
<div class="flex gap-2">
|
||||||
|
<div class="pb-2 font-bold text-white" x-text="item.name"></div>
|
||||||
|
<template x-if="item.status.startsWith('running')">
|
||||||
|
<div title="running" class="mt-1 bg-success badge badge-xs"></div>
|
||||||
|
</template>
|
||||||
|
<template x-if="item.status.startsWith('exited')">
|
||||||
|
<div title="exited" class="mt-1 bg-error badge badge-xs"></div>
|
||||||
|
</template>
|
||||||
|
<template x-if="item.status.startsWith('restarting')">
|
||||||
|
<div title="restarting" class="mt-1 bg-warningbadge badge-xs"></div>
|
||||||
|
</template>
|
||||||
|
<template x-if="item.status.startsWith('degraded')">
|
||||||
|
<div title="degraded" class="mt-1 bg-warning badge badge-xs"></div>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
<div class="description" x-text="item.description"></div>
|
<div class="description" x-text="item.description"></div>
|
||||||
</div>
|
</div>
|
||||||
<template x-if="item.status.startsWith('running')">
|
|
||||||
<div class="absolute bg-success -top-1 -left-1 badge badge-xs"></div>
|
|
||||||
</template>
|
|
||||||
<template x-if="item.status.startsWith('exited')">
|
|
||||||
<div class="absolute bg-error -top-1 -left-1 badge badge-xs"></div>
|
|
||||||
</template>
|
|
||||||
<template x-if="item.status.startsWith('restarting')">
|
|
||||||
<div class="absolute bg-warning -top-1 -left-1 badge badge-xs"></div>
|
|
||||||
</template>
|
|
||||||
</a>
|
</a>
|
||||||
<div class="flex gap-1 pt-1 group-hover:text-white group min-h-6">
|
<div class="flex gap-1 pt-1 group-hover:text-white group min-h-6">
|
||||||
<template x-for="tag in item.tags">
|
<template x-for="tag in item.tags">
|
||||||
@@ -161,21 +177,26 @@
|
|||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
<template x-for="item in filteredMysqls" :key="item.id">
|
<template x-for="item in filteredMysqls" :key="item.id">
|
||||||
<span class="relative">
|
<span>
|
||||||
<a class="h-24 box group" :href="item.hrefLink">
|
<a class="h-24 box group" :href="item.hrefLink">
|
||||||
<div class="flex flex-col mx-6">
|
<div class="flex flex-col mx-6">
|
||||||
<div class="font-bold text-white" x-text="item.name"></div>
|
<div class="flex gap-2">
|
||||||
|
<div class="pb-2 font-bold text-white" x-text="item.name"></div>
|
||||||
|
<template x-if="item.status.startsWith('running')">
|
||||||
|
<div title="running" class="mt-1 bg-success badge badge-xs"></div>
|
||||||
|
</template>
|
||||||
|
<template x-if="item.status.startsWith('exited')">
|
||||||
|
<div title="exited" class="mt-1 bg-error badge badge-xs"></div>
|
||||||
|
</template>
|
||||||
|
<template x-if="item.status.startsWith('restarting')">
|
||||||
|
<div title="restarting" class="mt-1 bg-warningbadge badge-xs"></div>
|
||||||
|
</template>
|
||||||
|
<template x-if="item.status.startsWith('degraded')">
|
||||||
|
<div title="degraded" class="mt-1 bg-warning badge badge-xs"></div>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
<div class="description" x-text="item.description"></div>
|
<div class="description" x-text="item.description"></div>
|
||||||
</div>
|
</div>
|
||||||
<template x-if="item.status.startsWith('running')">
|
|
||||||
<div class="absolute bg-success -top-1 -left-1 badge badge-xs"></div>
|
|
||||||
</template>
|
|
||||||
<template x-if="item.status.startsWith('exited')">
|
|
||||||
<div class="absolute bg-error -top-1 -left-1 badge badge-xs"></div>
|
|
||||||
</template>
|
|
||||||
<template x-if="item.status.startsWith('restarting')">
|
|
||||||
<div class="absolute bg-warning -top-1 -left-1 badge badge-xs"></div>
|
|
||||||
</template>
|
|
||||||
</a>
|
</a>
|
||||||
<div class="flex gap-1 pt-1 group-hover:text-white group min-h-6">
|
<div class="flex gap-1 pt-1 group-hover:text-white group min-h-6">
|
||||||
<template x-for="tag in item.tags">
|
<template x-for="tag in item.tags">
|
||||||
@@ -188,21 +209,26 @@
|
|||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
<template x-for="item in filteredMariadbs" :key="item.id">
|
<template x-for="item in filteredMariadbs" :key="item.id">
|
||||||
<span class="relative">
|
<span>
|
||||||
<a class="h-24 box group" :href="item.hrefLink">
|
<a class="h-24 box group" :href="item.hrefLink">
|
||||||
<div class="flex flex-col mx-6">
|
<div class="flex flex-col mx-6">
|
||||||
<div class="font-bold text-white" x-text="item.name"></div>
|
<div class="flex gap-2">
|
||||||
|
<div class="pb-2 font-bold text-white" x-text="item.name"></div>
|
||||||
|
<template x-if="item.status.startsWith('running')">
|
||||||
|
<div title="running" class="mt-1 bg-success badge badge-xs"></div>
|
||||||
|
</template>
|
||||||
|
<template x-if="item.status.startsWith('exited')">
|
||||||
|
<div title="exited" class="mt-1 bg-error badge badge-xs"></div>
|
||||||
|
</template>
|
||||||
|
<template x-if="item.status.startsWith('restarting')">
|
||||||
|
<div title="restarting" class="mt-1 bg-warningbadge badge-xs"></div>
|
||||||
|
</template>
|
||||||
|
<template x-if="item.status.startsWith('degraded')">
|
||||||
|
<div title="degraded" class="mt-1 bg-warning badge badge-xs"></div>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
<div class="description" x-text="item.description"></div>
|
<div class="description" x-text="item.description"></div>
|
||||||
</div>
|
</div>
|
||||||
<template x-if="item.status.startsWith('running')">
|
|
||||||
<div class="absolute bg-success -top-1 -left-1 badge badge-xs"></div>
|
|
||||||
</template>
|
|
||||||
<template x-if="item.status.startsWith('exited')">
|
|
||||||
<div class="absolute bg-error -top-1 -left-1 badge badge-xs"></div>
|
|
||||||
</template>
|
|
||||||
<template x-if="item.status.startsWith('restarting')">
|
|
||||||
<div class="absolute bg-warning -top-1 -left-1 badge badge-xs"></div>
|
|
||||||
</template>
|
|
||||||
</a>
|
</a>
|
||||||
<div class="flex gap-1 pt-1 group-hover:text-white group min-h-6">
|
<div class="flex gap-1 pt-1 group-hover:text-white group min-h-6">
|
||||||
<template x-for="tag in item.tags">
|
<template x-for="tag in item.tags">
|
||||||
@@ -215,21 +241,26 @@
|
|||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
<template x-for="item in filteredServices" :key="item.id">
|
<template x-for="item in filteredServices" :key="item.id">
|
||||||
<span class="relative">
|
<span>
|
||||||
<a class="h-24 box group" :href="item.hrefLink">
|
<a class="h-24 box group" :href="item.hrefLink">
|
||||||
<div class="flex flex-col mx-6">
|
<div class="flex flex-col mx-6">
|
||||||
<div class="font-bold text-white" x-text="item.name"></div>
|
<div class="flex gap-2">
|
||||||
|
<div class="pb-2 font-bold text-white" x-text="item.name"></div>
|
||||||
|
<template x-if="item.status.startsWith('running')">
|
||||||
|
<div title="running" class="mt-1 bg-success badge badge-xs"></div>
|
||||||
|
</template>
|
||||||
|
<template x-if="item.status.startsWith('exited')">
|
||||||
|
<div title="exited" class="mt-1 bg-error badge badge-xs"></div>
|
||||||
|
</template>
|
||||||
|
<template x-if="item.status.startsWith('restarting')">
|
||||||
|
<div title="restarting" class="mt-1 bg-warningbadge badge-xs"></div>
|
||||||
|
</template>
|
||||||
|
<template x-if="item.status.startsWith('degraded')">
|
||||||
|
<div title="degraded" class="mt-1 bg-warning badge badge-xs"></div>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
<div class="description" x-text="item.description"></div>
|
<div class="description" x-text="item.description"></div>
|
||||||
</div>
|
</div>
|
||||||
<template x-if="item.status.startsWith('running')">
|
|
||||||
<div class="absolute bg-success -top-1 -left-1 badge badge-xs"></div>
|
|
||||||
</template>
|
|
||||||
<template x-if="item.status.startsWith('exited')">
|
|
||||||
<div class="absolute bg-error -top-1 -left-1 badge badge-xs"></div>
|
|
||||||
</template>
|
|
||||||
<template x-if="item.status.startsWith('degraded')">
|
|
||||||
<div class="absolute bg-warning -top-1 -left-1 badge badge-xs"></div>
|
|
||||||
</template>
|
|
||||||
</a>
|
</a>
|
||||||
<div class="flex gap-1 pt-1 group-hover:text-white group min-h-6">
|
<div class="flex gap-1 pt-1 group-hover:text-white group min-h-6">
|
||||||
<template x-for="tag in item.tags">
|
<template x-for="tag in item.tags">
|
||||||
|
|||||||
@@ -76,7 +76,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="flex items-center px-4">
|
<div class="flex items-center px-4">
|
||||||
<a class="flex flex-col flex-1 group-hover:text-white hover:no-underline"
|
<a class="flex flex-col flex-1 group-hover:text-white hover:no-underline"
|
||||||
href="{{ route('project.service.index', [...$parameters, 'service_name' => $application->name]) }}">
|
href="{{ route('project.service.index', [...$parameters, 'stack_service_uuid' => $application->uuid]) }}">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" class="icon hover:text-warning"
|
<svg xmlns="http://www.w3.org/2000/svg" class="icon hover:text-warning"
|
||||||
viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" fill="none"
|
viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" fill="none"
|
||||||
stroke-linecap="round" stroke-linejoin="round">
|
stroke-linecap="round" stroke-linejoin="round">
|
||||||
@@ -122,7 +122,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="flex items-center px-4">
|
<div class="flex items-center px-4">
|
||||||
<a class="flex flex-col flex-1 group-hover:text-white hover:no-underline"
|
<a class="flex flex-col flex-1 group-hover:text-white hover:no-underline"
|
||||||
href="{{ route('project.service.index', [...$parameters, 'service_name' => $database->name]) }}">
|
href="{{ route('project.service.index', [...$parameters, 'stack_service_uuid' => $database->uuid]) }}">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" class="icon hover:text-warning"
|
<svg xmlns="http://www.w3.org/2000/svg" class="icon hover:text-warning"
|
||||||
viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" fill="none"
|
viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" fill="none"
|
||||||
stroke-linecap="round" stroke-linejoin="round">
|
stroke-linecap="round" stroke-linejoin="round">
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<div class="flex h-full pt-6">
|
<div class="flex h-full pt-6">
|
||||||
<div class="flex flex-col gap-4 min-w-fit">
|
<div class="flex flex-col gap-4 min-w-fit">
|
||||||
<a class="{{ request()->routeIs('project.service.configuration') ? 'text-white' : '' }}"
|
<a class="{{ request()->routeIs('project.service.configuration') ? 'text-white' : '' }}"
|
||||||
href="{{ route('project.service.configuration', [...$parameters, 'service_name' => null]) }}">
|
href="{{ route('project.service.configuration', [...$parameters, 'stack_service_uuid' => null]) }}">
|
||||||
<button><- Back</button>
|
<button><- Back</button>
|
||||||
</a>
|
</a>
|
||||||
<a :class="activeTab === 'general' && 'text-white'"
|
<a :class="activeTab === 'general' && 'text-white'"
|
||||||
|
|||||||
@@ -32,7 +32,9 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<h3 class="pt-2">Advanced</h3>
|
<h3 class="pt-2">Advanced</h3>
|
||||||
<div class="w-64">
|
<div class="w-96">
|
||||||
|
<x-forms.checkbox instantSave id="application.is_gzip_enabled" label="Enable gzip compression"
|
||||||
|
helper="You can disable gzip compression if you want. Some services are compressing data by default. In this case, you do not need this." />
|
||||||
<x-forms.checkbox instantSave label="Exclude from service status"
|
<x-forms.checkbox instantSave label="Exclude from service status"
|
||||||
helper="If you do not need to monitor this resource, enable. Useful if this service is optional."
|
helper="If you do not need to monitor this resource, enable. Useful if this service is optional."
|
||||||
id="application.exclude_from_status"></x-forms.checkbox>
|
id="application.exclude_from_status"></x-forms.checkbox>
|
||||||
|
|||||||
@@ -15,7 +15,8 @@
|
|||||||
<x-forms.input id="service.description" label="Description" />
|
<x-forms.input id="service.description" label="Description" />
|
||||||
</div>
|
</div>
|
||||||
<div class="w-96">
|
<div class="w-96">
|
||||||
<x-forms.checkbox instantSave id="service.connect_to_docker_network" label="Connect To Predefined Network" helper="By default, you do not reach the Coolify defined networks.<br>Starting a docker compose based resource will have an internal network. <br>If you connect to a Coolify defined network, you maybe need to use different internal DNS names to connect to a resource.<br><br>For more information, check <a class='text-white underline' href='https://coolify.io/docs/docker/compose#connect-to-predefined-networks'>this</a>." />
|
<x-forms.checkbox instantSave id="service.connect_to_docker_network" label="Connect To Predefined Network"
|
||||||
|
helper="By default, you do not reach the Coolify defined networks.<br>Starting a docker compose based resource will have an internal network. <br>If you connect to a Coolify defined network, you maybe need to use different internal DNS names to connect to a resource.<br><br>For more information, check <a class='text-white underline' href='https://coolify.io/docs/docker/compose#connect-to-predefined-networks'>this</a>." />
|
||||||
</div>
|
</div>
|
||||||
@if ($fields)
|
@if ($fields)
|
||||||
<div>
|
<div>
|
||||||
|
|||||||
@@ -55,21 +55,25 @@
|
|||||||
@endforeach
|
@endforeach
|
||||||
@endif
|
@endif
|
||||||
</div>
|
</div>
|
||||||
{{-- @if ($resource->getMorphClass() === 'App\Models\Application')
|
@if ($resource->getMorphClass() === 'App\Models\Application')
|
||||||
@if (count($networks) > 0)
|
@if (count($networks) > 0)
|
||||||
<h4>Choose another server</h4>
|
<h4>Choose another server</h4>
|
||||||
<div class="pb-4 description">(experimental) </div>
|
<div class="pb-4 description">(experimental) </div>
|
||||||
<div class="grid grid-cols-1 gap-4 ">
|
<div class="grid grid-cols-1 gap-4">
|
||||||
@foreach ($networks as $network)
|
@foreach ($networks as $network)
|
||||||
<div wire:click="addServer('{{ $network->id }}','{{ data_get($network, 'server.id') }}')"
|
<div wire:click="addServer('{{ $network->id }}','{{ data_get($network, 'server.id') }}')"
|
||||||
class="box w-96">
|
class="relative flex flex-col text-white cursor-default box w-96">
|
||||||
{{ data_get($network, 'server.name') }}
|
<div>
|
||||||
{{ $network->name }}
|
Server: {{ data_get($network, 'server.name') }}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
Network: {{ data_get($network, 'name') }}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@endforeach
|
@endforeach
|
||||||
</div>
|
</div>
|
||||||
@else
|
@else
|
||||||
<div class="text-neutral-500">No additional servers available to attach.</div>
|
<div class="text-neutral-500">No additional servers available to attach.</div>
|
||||||
@endif
|
@endif
|
||||||
@endif --}}
|
@endif
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -28,7 +28,7 @@
|
|||||||
</form>
|
</form>
|
||||||
|
|
||||||
<div class="pt-4">
|
<div class="pt-4">
|
||||||
<h3 class="py-4">Recent executions</h3>
|
<h3 class="py-4">Recent executions <span class="text-xs text-neutral-500">(click to check output)</span></h3>
|
||||||
<livewire:project.shared.scheduled-task.executions key="{{ $task->id }}" selectedKey="" :executions="$task->executions->take(-20)" />
|
<livewire:project.shared.scheduled-task.executions key="{{ $task->id }}" selectedKey="" :executions="$task->executions->take(-20)" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -15,44 +15,5 @@
|
|||||||
This server will be deleted. It is not reversible. <br>Please think again.
|
This server will be deleted. It is not reversible. <br>Please think again.
|
||||||
</x-new-modal>
|
</x-new-modal>
|
||||||
@endif
|
@endif
|
||||||
<div class="flex flex-col">
|
|
||||||
@forelse ($server->definedResources() as $resource)
|
|
||||||
@if ($loop->first)
|
|
||||||
<h3 class="pt-4">Resources</h3>
|
|
||||||
@endif
|
|
||||||
@if ($resource->link())
|
|
||||||
<a class="flex gap-2 p-1 hover:bg-coolgray-100 hover:no-underline" href="{{ $resource->link() }}">
|
|
||||||
<div class="w-64">{{ str($resource->type())->headline() }}</div>
|
|
||||||
<div>{{ $resource->name }}</div>
|
|
||||||
</a>
|
|
||||||
@else
|
|
||||||
<div class="flex gap-2 p-1 hover:bg-coolgray-100 hover:no-underline">
|
|
||||||
<div class="w-64">{{ str($resource->type())->headline() }}</div>
|
|
||||||
<div>{{ $resource->name }}</div>
|
|
||||||
</div>
|
|
||||||
@endif
|
|
||||||
@empty
|
|
||||||
@endforelse
|
|
||||||
</div>
|
|
||||||
@else
|
|
||||||
<div class="flex flex-col">
|
|
||||||
@forelse ($server->definedResources() as $resource)
|
|
||||||
@if ($loop->first)
|
|
||||||
<h3 class="pt-4">Resources</h3>
|
|
||||||
@endif
|
|
||||||
@if ($resource->link())
|
|
||||||
<a class="flex gap-2 p-1 hover:bg-coolgray-100 hover:no-underline" href="{{ $resource->link() }}">
|
|
||||||
<div class="w-64">{{ str($resource->type())->headline() }}</div>
|
|
||||||
<div>{{ $resource->name }}</div>
|
|
||||||
</a>
|
|
||||||
@else
|
|
||||||
<div class="flex gap-2 p-1 hover:bg-coolgray-100 hover:no-underline">
|
|
||||||
<div class="w-64">{{ str($resource->type())->headline() }}</div>
|
|
||||||
<div>{{ $resource->name }}</div>
|
|
||||||
</div>
|
|
||||||
@endif
|
|
||||||
@empty
|
|
||||||
@endforelse
|
|
||||||
</div>
|
|
||||||
@endif
|
@endif
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -10,16 +10,25 @@
|
|||||||
</x-new-modal>
|
</x-new-modal>
|
||||||
@else
|
@else
|
||||||
<x-forms.button type="submit">Save</x-forms.button>
|
<x-forms.button type="submit">Save</x-forms.button>
|
||||||
|
<x-slide-over closeWithX fullScreen>
|
||||||
|
<x-slot:title>Validate & configure</x-slot:title>
|
||||||
|
<x-slot:content>
|
||||||
|
<livewire:server.validate-and-install :server="$server" ask />
|
||||||
|
</x-slot:content>
|
||||||
|
<x-forms.button @click="slideOverOpen=true" wire:click.prevent='validateServer' isHighlighted>
|
||||||
|
Revalidate server
|
||||||
|
</x-forms.button>
|
||||||
|
</x-slide-over>
|
||||||
@endif
|
@endif
|
||||||
</div>
|
</div>
|
||||||
@if (!$server->isFunctional())
|
@if ($server->isFunctional())
|
||||||
You can't use this server until it is validated.
|
|
||||||
@else
|
|
||||||
Server is reachable and validated.
|
Server is reachable and validated.
|
||||||
|
@else
|
||||||
|
You can't use this server until it is validated.
|
||||||
@endif
|
@endif
|
||||||
@if ((!$server->settings->is_reachable || !$server->settings->is_usable) && $server->id !== 0)
|
@if ((!$server->settings->is_reachable || !$server->settings->is_usable) && $server->id !== 0)
|
||||||
<x-slide-over closeWithX fullScreen>
|
<x-slide-over closeWithX fullScreen>
|
||||||
<x-slot:title>Configuring Server</x-slot:title>
|
<x-slot:title>Validate & configure</x-slot:title>
|
||||||
<x-slot:content>
|
<x-slot:content>
|
||||||
<livewire:server.validate-and-install :server="$server" />
|
<livewire:server.validate-and-install :server="$server" />
|
||||||
</x-slot:content>
|
</x-slot:content>
|
||||||
|
|||||||
@@ -12,12 +12,21 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="flex flex-col gap-4">
|
<div class="flex flex-col gap-4">
|
||||||
<div class="flex flex-col w-full gap-2 xl:flex-row">
|
<div class="flex flex-col w-full gap-2 xl:flex-row">
|
||||||
<x-forms.input type="password" required id="server.settings.logdrain_newrelic_license_key"
|
@if ($server->isLogDrainEnabled())
|
||||||
label="License Key" />
|
<x-forms.input disabled type="password" required
|
||||||
<x-forms.input required id="server.settings.logdrain_newrelic_base_uri"
|
id="server.settings.logdrain_newrelic_license_key" label="License Key" />
|
||||||
placeholder="https://log-api.eu.newrelic.com/log/v1"
|
<x-forms.input disabled required id="server.settings.logdrain_newrelic_base_uri"
|
||||||
helper="For EU use: https://log-api.eu.newrelic.com/log/v1<br>For US use: https://log-api.newrelic.com/log/v1"
|
placeholder="https://log-api.eu.newrelic.com/log/v1"
|
||||||
label="Endpoint" />
|
helper="For EU use: https://log-api.eu.newrelic.com/log/v1<br>For US use: https://log-api.newrelic.com/log/v1"
|
||||||
|
label="Endpoint" />
|
||||||
|
@else
|
||||||
|
<x-forms.input type="password" required id="server.settings.logdrain_newrelic_license_key"
|
||||||
|
label="License Key" />
|
||||||
|
<x-forms.input required id="server.settings.logdrain_newrelic_base_uri"
|
||||||
|
placeholder="https://log-api.eu.newrelic.com/log/v1"
|
||||||
|
helper="For EU use: https://log-api.eu.newrelic.com/log/v1<br>For US use: https://log-api.newrelic.com/log/v1"
|
||||||
|
label="Endpoint" />
|
||||||
|
@endif
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex justify-end gap-4 pt-6">
|
<div class="flex justify-end gap-4 pt-6">
|
||||||
@@ -35,9 +44,17 @@
|
|||||||
<form wire:submit='submit("axiom")' class="flex flex-col">
|
<form wire:submit='submit("axiom")' class="flex flex-col">
|
||||||
<div class="flex flex-col gap-4">
|
<div class="flex flex-col gap-4">
|
||||||
<div class="flex flex-col w-full gap-2 xl:flex-row">
|
<div class="flex flex-col w-full gap-2 xl:flex-row">
|
||||||
<x-forms.input type="password" required id="server.settings.logdrain_axiom_api_key"
|
@if ($server->isLogDrainEnabled())
|
||||||
label="API Key" />
|
<x-forms.input disabled type="password" required id="server.settings.logdrain_axiom_api_key"
|
||||||
<x-forms.input required id="server.settings.logdrain_axiom_dataset_name" label="Dataset Name" />
|
label="API Key" />
|
||||||
|
<x-forms.input disabled required id="server.settings.logdrain_axiom_dataset_name"
|
||||||
|
label="Dataset Name" />
|
||||||
|
@else
|
||||||
|
<x-forms.input type="password" required id="server.settings.logdrain_axiom_api_key"
|
||||||
|
label="API Key" />
|
||||||
|
<x-forms.input required id="server.settings.logdrain_axiom_dataset_name"
|
||||||
|
label="Dataset Name" />
|
||||||
|
@endif
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex justify-end gap-4 pt-6">
|
<div class="flex justify-end gap-4 pt-6">
|
||||||
@@ -71,10 +88,18 @@
|
|||||||
</div>
|
</div>
|
||||||
<form wire:submit='submit("custom")' class="flex flex-col">
|
<form wire:submit='submit("custom")' class="flex flex-col">
|
||||||
<div class="flex flex-col gap-4">
|
<div class="flex flex-col gap-4">
|
||||||
<x-forms.textarea rows="6" required id="server.settings.logdrain_custom_config"
|
@if ($server->isLogDrainEnabled())
|
||||||
label="Custom FluentBit Configuration" />
|
<x-forms.textarea disabled rows="6" required id="server.settings.logdrain_custom_config"
|
||||||
<x-forms.textarea id="server.settings.logdrain_custom_config_parser"
|
label="Custom FluentBit Configuration" />
|
||||||
label="Custom Parser Configuration" />
|
<x-forms.textarea disabled id="server.settings.logdrain_custom_config_parser"
|
||||||
|
label="Custom Parser Configuration" />
|
||||||
|
@else
|
||||||
|
<x-forms.textarea rows="6" required id="server.settings.logdrain_custom_config"
|
||||||
|
label="Custom FluentBit Configuration" />
|
||||||
|
<x-forms.textarea id="server.settings.logdrain_custom_config_parser"
|
||||||
|
label="Custom Parser Configuration" />
|
||||||
|
@endif
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div class="flex justify-end gap-4 pt-6">
|
<div class="flex justify-end gap-4 pt-6">
|
||||||
<x-forms.button type="submit">
|
<x-forms.button type="submit">
|
||||||
|
|||||||
@@ -51,7 +51,7 @@
|
|||||||
</x-forms.button>
|
</x-forms.button>
|
||||||
</div>
|
</div>
|
||||||
@else
|
@else
|
||||||
<button onclick="checkProxy()"
|
<button x-on:click="$wire.dispatch('checkProxy')"
|
||||||
class="flex items-center gap-2 cursor-pointer hover:text-white text-neutral-400">
|
class="flex items-center gap-2 cursor-pointer hover:text-white text-neutral-400">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" class="w-5 h-5 text-warning" viewBox="0 0 24 24"
|
<svg xmlns="http://www.w3.org/2000/svg" class="w-5 h-5 text-warning" viewBox="0 0 24 24"
|
||||||
stroke-width="1.5" stroke="currentColor" fill="none" stroke-linecap="round"
|
stroke-width="1.5" stroke="currentColor" fill="none" stroke-linecap="round"
|
||||||
@@ -64,9 +64,6 @@
|
|||||||
@endif
|
@endif
|
||||||
@endif
|
@endif
|
||||||
<script>
|
<script>
|
||||||
function checkProxy() {
|
|
||||||
window.Livewire.dispatch('checkProxy')
|
|
||||||
}
|
|
||||||
Livewire.on('proxyChecked', () => {
|
Livewire.on('proxyChecked', () => {
|
||||||
startProxy.showModal();
|
startProxy.showModal();
|
||||||
window.Livewire.dispatch('startProxy');
|
window.Livewire.dispatch('startProxy');
|
||||||
|
|||||||
143
resources/views/livewire/server/resources.blade.php
Normal file
143
resources/views/livewire/server/resources.blade.php
Normal file
@@ -0,0 +1,143 @@
|
|||||||
|
<div>
|
||||||
|
<x-server.navbar :server="$server" :parameters="$parameters" />
|
||||||
|
|
||||||
|
<div x-data="{ activeTab: window.location.hash ? window.location.hash.substring(1) : 'managed' }" class="flex h-full">
|
||||||
|
<div class="flex flex-col gap-4 xl:w-32">
|
||||||
|
<a :class="activeTab === 'managed' && 'text-white'"
|
||||||
|
@click.prevent="activeTab = 'managed'; window.location.hash = 'managed'" href="#">Managed</a>
|
||||||
|
<a :class="activeTab === 'unmanaged' && 'text-white'"
|
||||||
|
@click.prevent="activeTab = 'unmanaged'; window.location.hash = 'unmanaged'" href="#">Unmanaged</a>
|
||||||
|
</div>
|
||||||
|
<div class="w-full pl-8">
|
||||||
|
<div x-cloak x-show="activeTab === 'managed'" class="h-full">
|
||||||
|
<div class="flex flex-col">
|
||||||
|
<div class="flex gap-2">
|
||||||
|
<h2>Resources</h2>
|
||||||
|
<x-forms.button wire:click="refreshStatus">Refresh</x-forms.button>
|
||||||
|
</div>
|
||||||
|
<div class="pb-4 title">Here you can find all resources that are managed by Coolify.</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col">
|
||||||
|
<div class="flex flex-col">
|
||||||
|
<div class="overflow-x-auto">
|
||||||
|
<div class="inline-block min-w-full">
|
||||||
|
<div class="overflow-hidden">
|
||||||
|
<table class="min-w-full divide-y divide-coolgray-400">
|
||||||
|
<thead>
|
||||||
|
<tr class="text-neutral-500">
|
||||||
|
<th class="px-5 py-3 text-xs font-medium text-left uppercase">Project
|
||||||
|
</th>
|
||||||
|
<th class="px-5 py-3 text-xs font-medium text-left uppercase">
|
||||||
|
Environment</th>
|
||||||
|
<th class="px-5 py-3 text-xs font-medium text-left uppercase">Name</th>
|
||||||
|
<th class="px-5 py-3 text-xs font-medium text-left uppercase">Type</th>
|
||||||
|
<th class="px-5 py-3 text-xs font-medium text-left uppercase">Status
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody class="divide-y divide-coolgray-400">
|
||||||
|
@forelse ($server->definedResources()->sortBy('name',SORT_NATURAL) as $resource)
|
||||||
|
<tr class="text-white bg-coolblack hover:bg-coolgray-100">
|
||||||
|
<td class="px-5 py-4 text-sm whitespace-nowrap">
|
||||||
|
{{ data_get($resource->project(), 'name') }}
|
||||||
|
</td>
|
||||||
|
<td class="px-5 py-4 text-sm whitespace-nowrap">
|
||||||
|
{{ data_get($resource, 'environment.name') }}
|
||||||
|
</td>
|
||||||
|
<td class="px-5 py-4 text-sm whitespace-nowrap"><a class=""
|
||||||
|
href="{{ $resource->link() }}">{{ $resource->name }} </a>
|
||||||
|
</td>
|
||||||
|
<td class="px-5 py-4 text-sm whitespace-nowrap">
|
||||||
|
{{ str($resource->type())->headline() }}</td>
|
||||||
|
<td class="px-5 py-4 text-sm font-medium whitespace-nowrap">
|
||||||
|
@if ($resource->type() === 'service')
|
||||||
|
<x-status.services :service="$resource" :showRefreshButton="false" />
|
||||||
|
@else
|
||||||
|
<x-status.index :status="$resource->status" :showRefreshButton="false" />
|
||||||
|
@endif
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
@empty
|
||||||
|
@endforelse
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div x-cloak x-show="activeTab === 'unmanaged'" class="h-full">
|
||||||
|
<div class="flex flex-col">
|
||||||
|
<div class="flex gap-2">
|
||||||
|
<h2>Resources</h2>
|
||||||
|
<x-forms.button wire:click="refreshStatus">Refresh</x-forms.button>
|
||||||
|
</div>
|
||||||
|
<div class="pb-4 title">Here you can find all other containers running on the server.</div>
|
||||||
|
</div>
|
||||||
|
@if ($unmanagedContainers->count() > 0)
|
||||||
|
<div class="flex flex-col">
|
||||||
|
<div class="flex flex-col">
|
||||||
|
<div class="overflow-x-auto">
|
||||||
|
<div class="inline-block min-w-full">
|
||||||
|
<div class="overflow-hidden">
|
||||||
|
<table class="min-w-full divide-y divide-coolgray-400">
|
||||||
|
<thead>
|
||||||
|
<tr class="text-neutral-500">
|
||||||
|
<th class="px-5 py-3 text-xs font-medium text-left uppercase">Name
|
||||||
|
</th>
|
||||||
|
<th class="px-5 py-3 text-xs font-medium text-left uppercase">Image
|
||||||
|
</th>
|
||||||
|
<th class="px-5 py-3 text-xs font-medium text-left uppercase">Status
|
||||||
|
</th>
|
||||||
|
<th class="px-5 py-3 text-xs font-medium text-left uppercase">Action
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody class="divide-y divide-coolgray-400">
|
||||||
|
@forelse ($unmanagedContainers->sortBy('name',SORT_NATURAL) as $resource)
|
||||||
|
<tr class="text-white bg-coolblack hover:bg-coolgray-100">
|
||||||
|
<td class="px-5 py-4 text-sm whitespace-nowrap">
|
||||||
|
{{ data_get($resource, 'Names') }}
|
||||||
|
</td>
|
||||||
|
<td class="px-5 py-4 text-sm whitespace-nowrap">
|
||||||
|
{{ data_get($resource, 'Image') }}
|
||||||
|
</td>
|
||||||
|
<td class="px-5 py-4 text-sm whitespace-nowrap">
|
||||||
|
{{ data_get($resource, 'State') }}
|
||||||
|
</td>
|
||||||
|
<td class="px-5 py-4 text-sm whitespace-nowrap">
|
||||||
|
@if (data_get($resource, 'State') === 'running')
|
||||||
|
<x-forms.button
|
||||||
|
wire:click="restartUnmanaged('{{ data_get($resource, 'ID') }}')"
|
||||||
|
wire:key="{{ data_get($resource, 'ID') }}">Restart</x-forms.button>
|
||||||
|
<x-forms.button isError
|
||||||
|
wire:click="stopUnmanaged('{{ data_get($resource, 'ID') }}')"
|
||||||
|
wire:key="{{ data_get($resource, 'ID') }}">Stop</x-forms.button>
|
||||||
|
@elseif (data_get($resource, 'State') === 'exited')
|
||||||
|
<x-forms.button
|
||||||
|
wire:click="startUnmanaged('{{ data_get($resource, 'ID') }}')"
|
||||||
|
wire:key="{{ data_get($resource, 'ID') }}">Start</x-forms.button>
|
||||||
|
@elseif (data_get($resource, 'State') === 'restarting')
|
||||||
|
<x-forms.button
|
||||||
|
wire:click="stopUnmanaged('{{ data_get($resource, 'ID') }}')"
|
||||||
|
wire:key="{{ data_get($resource, 'ID') }}">Stop</x-forms.button>
|
||||||
|
@endif
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
@empty
|
||||||
|
@endforelse
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
@@ -1,29 +1,12 @@
|
|||||||
<div class="flex flex-col gap-2">
|
<div class="flex flex-col gap-2">
|
||||||
@if ($uptime)
|
@if ($ask)
|
||||||
<div class="flex w-64 gap-2">Server is reachable: <svg class="w-5 h-5 text-success" viewBox="0 0 256 256"
|
This will revalidate the server, install / update Docker Engine, Docker Compose and all related
|
||||||
xmlns="http://www.w3.org/2000/svg">
|
configuration. It will also restart Docker Engine, so your running containers will be unreachable
|
||||||
<g fill="currentColor">
|
for the time being.
|
||||||
<path
|
<x-forms.button isHighlighted wire:click='startValidatingAfterAsking '>Continue</x-forms.button>
|
||||||
d="m237.66 85.26l-128.4 128.4a8 8 0 0 1-11.32 0l-71.6-72a8 8 0 0 1 0-11.31l24-24a8 8 0 0 1 11.32 0l36.68 35.32a8 8 0 0 0 11.32 0l92.68-91.32a8 8 0 0 1 11.32 0l24 23.6a8 8 0 0 1 0 11.31"
|
|
||||||
opacity=".2" />
|
|
||||||
<path
|
|
||||||
d="m243.28 68.24l-24-23.56a16 16 0 0 0-22.58 0L104 136l-.11-.11l-36.64-35.27a16 16 0 0 0-22.57.06l-24 24a16 16 0 0 0 0 22.61l71.62 72a16 16 0 0 0 22.63 0l128.4-128.38a16 16 0 0 0-.05-22.67M103.62 208L32 136l24-24l.11.11l36.64 35.27a16 16 0 0 0 22.52 0L208.06 56L232 79.6Z" />
|
|
||||||
</g>
|
|
||||||
</svg></div>
|
|
||||||
@else
|
@else
|
||||||
@if ($error)
|
@if ($uptime)
|
||||||
<div class="flex w-64 gap-2">Server is reachable: <svg class="w-5 h-5 text-error" viewBox="0 0 256 256"
|
<div class="flex w-64 gap-2">Server is reachable: <svg class="w-5 h-5 text-success" viewBox="0 0 256 256"
|
||||||
xmlns="http://www.w3.org/2000/svg">
|
|
||||||
<path fill="currentColor"
|
|
||||||
d="M208.49 191.51a12 12 0 0 1-17 17L128 145l-63.51 63.49a12 12 0 0 1-17-17L111 128L47.51 64.49a12 12 0 0 1 17-17L128 111l63.51-63.52a12 12 0 0 1 17 17L145 128Z" />
|
|
||||||
</svg></div>
|
|
||||||
@else
|
|
||||||
<div class="w-64"><x-loading text="Server is reachable: " /></div>
|
|
||||||
@endif
|
|
||||||
@endif
|
|
||||||
@if ($uptime)
|
|
||||||
@if ($supported_os_type)
|
|
||||||
<div class="flex w-64 gap-2">Supported OS type: <svg class="w-5 h-5 text-success" viewBox="0 0 256 256"
|
|
||||||
xmlns="http://www.w3.org/2000/svg">
|
xmlns="http://www.w3.org/2000/svg">
|
||||||
<g fill="currentColor">
|
<g fill="currentColor">
|
||||||
<path
|
<path
|
||||||
@@ -41,14 +24,105 @@
|
|||||||
d="M208.49 191.51a12 12 0 0 1-17 17L128 145l-63.51 63.49a12 12 0 0 1-17-17L111 128L47.51 64.49a12 12 0 0 1 17-17L128 111l63.51-63.52a12 12 0 0 1 17 17L145 128Z" />
|
d="M208.49 191.51a12 12 0 0 1-17 17L128 145l-63.51 63.49a12 12 0 0 1-17-17L111 128L47.51 64.49a12 12 0 0 1 17-17L128 111l63.51-63.52a12 12 0 0 1 17 17L145 128Z" />
|
||||||
</svg></div>
|
</svg></div>
|
||||||
@else
|
@else
|
||||||
<div class="w-64"><x-loading text="Server is reachable:" /></div>
|
<div class="w-64"><x-loading text="Server is reachable: " /></div>
|
||||||
@endif
|
@endif
|
||||||
@endif
|
@endif
|
||||||
@endif
|
@if ($uptime)
|
||||||
@if ($uptime && $supported_os_type)
|
@if ($supported_os_type)
|
||||||
@if ($docker_installed)
|
<div class="flex w-64 gap-2">Supported OS type: <svg class="w-5 h-5 text-success" viewBox="0 0 256 256"
|
||||||
<div class="flex w-64 gap-2">Docker is installed: <svg class="w-5 h-5 text-success" viewBox="0 0 256 256"
|
xmlns="http://www.w3.org/2000/svg">
|
||||||
xmlns="http://www.w3.org/2000/svg">
|
<g fill="currentColor">
|
||||||
|
<path
|
||||||
|
d="m237.66 85.26l-128.4 128.4a8 8 0 0 1-11.32 0l-71.6-72a8 8 0 0 1 0-11.31l24-24a8 8 0 0 1 11.32 0l36.68 35.32a8 8 0 0 0 11.32 0l92.68-91.32a8 8 0 0 1 11.32 0l24 23.6a8 8 0 0 1 0 11.31"
|
||||||
|
opacity=".2" />
|
||||||
|
<path
|
||||||
|
d="m243.28 68.24l-24-23.56a16 16 0 0 0-22.58 0L104 136l-.11-.11l-36.64-35.27a16 16 0 0 0-22.57.06l-24 24a16 16 0 0 0 0 22.61l71.62 72a16 16 0 0 0 22.63 0l128.4-128.38a16 16 0 0 0-.05-22.67M103.62 208L32 136l24-24l.11.11l36.64 35.27a16 16 0 0 0 22.52 0L208.06 56L232 79.6Z" />
|
||||||
|
</g>
|
||||||
|
</svg></div>
|
||||||
|
@else
|
||||||
|
@if ($error)
|
||||||
|
<div class="flex w-64 gap-2">Server is reachable: <svg class="w-5 h-5 text-error"
|
||||||
|
viewBox="0 0 256 256" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path fill="currentColor"
|
||||||
|
d="M208.49 191.51a12 12 0 0 1-17 17L128 145l-63.51 63.49a12 12 0 0 1-17-17L111 128L47.51 64.49a12 12 0 0 1 17-17L128 111l63.51-63.52a12 12 0 0 1 17 17L145 128Z" />
|
||||||
|
</svg></div>
|
||||||
|
@else
|
||||||
|
<div class="w-64"><x-loading text="Server is reachable:" /></div>
|
||||||
|
@endif
|
||||||
|
@endif
|
||||||
|
@endif
|
||||||
|
@if ($uptime && $supported_os_type)
|
||||||
|
@if ($docker_installed)
|
||||||
|
<div class="flex w-64 gap-2">Docker is installed: <svg class="w-5 h-5 text-success"
|
||||||
|
viewBox="0 0 256 256" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<g fill="currentColor">
|
||||||
|
<path
|
||||||
|
d="m237.66 85.26l-128.4 128.4a8 8 0 0 1-11.32 0l-71.6-72a8 8 0 0 1 0-11.31l24-24a8 8 0 0 1 11.32 0l36.68 35.32a8 8 0 0 0 11.32 0l92.68-91.32a8 8 0 0 1 11.32 0l24 23.6a8 8 0 0 1 0 11.31"
|
||||||
|
opacity=".2" />
|
||||||
|
<path
|
||||||
|
d="m243.28 68.24l-24-23.56a16 16 0 0 0-22.58 0L104 136l-.11-.11l-36.64-35.27a16 16 0 0 0-22.57.06l-24 24a16 16 0 0 0 0 22.61l71.62 72a16 16 0 0 0 22.63 0l128.4-128.38a16 16 0 0 0-.05-22.67M103.62 208L32 136l24-24l.11.11l36.64 35.27a16 16 0 0 0 22.52 0L208.06 56L232 79.6Z" />
|
||||||
|
</g>
|
||||||
|
</svg></div>
|
||||||
|
@else
|
||||||
|
@if ($error)
|
||||||
|
<div class="flex w-64 gap-2">Docker is installed: <svg class="w-5 h-5 text-error"
|
||||||
|
viewBox="0 0 256 256" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path fill="currentColor"
|
||||||
|
d="M208.49 191.51a12 12 0 0 1-17 17L128 145l-63.51 63.49a12 12 0 0 1-17-17L111 128L47.51 64.49a12 12 0 0 1 17-17L128 111l63.51-63.52a12 12 0 0 1 17 17L145 128Z" />
|
||||||
|
</svg></div>
|
||||||
|
@else
|
||||||
|
<div class="w-64"><x-loading text="Docker is installed:" /></div>
|
||||||
|
@endif
|
||||||
|
@endif
|
||||||
|
@if ($docker_compose_installed)
|
||||||
|
<div class="flex w-64 gap-2">Docker Compose is installed: <svg class="w-5 h-5 text-success"
|
||||||
|
viewBox="0 0 256 256" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<g fill="currentColor">
|
||||||
|
<path
|
||||||
|
d="m237.66 85.26l-128.4 128.4a8 8 0 0 1-11.32 0l-71.6-72a8 8 0 0 1 0-11.31l24-24a8 8 0 0 1 11.32 0l36.68 35.32a8 8 0 0 0 11.32 0l92.68-91.32a8 8 0 0 1 11.32 0l24 23.6a8 8 0 0 1 0 11.31"
|
||||||
|
opacity=".2" />
|
||||||
|
<path
|
||||||
|
d="m243.28 68.24l-24-23.56a16 16 0 0 0-22.58 0L104 136l-.11-.11l-36.64-35.27a16 16 0 0 0-22.57.06l-24 24a16 16 0 0 0 0 22.61l71.62 72a16 16 0 0 0 22.63 0l128.4-128.38a16 16 0 0 0-.05-22.67M103.62 208L32 136l24-24l.11.11l36.64 35.27a16 16 0 0 0 22.52 0L208.06 56L232 79.6Z" />
|
||||||
|
</g>
|
||||||
|
</svg></div>
|
||||||
|
@if ($proxy_started)
|
||||||
|
<div class="flex w-64 gap-2">Proxy Started: <svg class="w-5 h-5 text-success" viewBox="0 0 256 256"
|
||||||
|
xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<g fill="currentColor">
|
||||||
|
<path
|
||||||
|
d="m237.66 85.26l-128.4 128.4a8 8 0 0 1-11.32 0l-71.6-72a8 8 0 0 1 0-11.31l24-24a8 8 0 0 1 11.32 0l36.68 35.32a8 8 0 0 0 11.32 0l92.68-91.32a8 8 0 0 1 11.32 0l24 23.6a8 8 0 0 1 0 11.31"
|
||||||
|
opacity=".2" />
|
||||||
|
<path
|
||||||
|
d="m243.28 68.24l-24-23.56a16 16 0 0 0-22.58 0L104 136l-.11-.11l-36.64-35.27a16 16 0 0 0-22.57.06l-24 24a16 16 0 0 0 0 22.61l71.62 72a16 16 0 0 0 22.63 0l128.4-128.38a16 16 0 0 0-.05-22.67M103.62 208L32 136l24-24l.11.11l36.64 35.27a16 16 0 0 0 22.52 0L208.06 56L232 79.6Z" />
|
||||||
|
</g>
|
||||||
|
</svg></div>
|
||||||
|
@else
|
||||||
|
@if ($error)
|
||||||
|
<div class="flex w-64 gap-2">Proxy Started: <svg class="w-5 h-5 text-error"
|
||||||
|
viewBox="0 0 256 256" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path fill="currentColor"
|
||||||
|
d="M208.49 191.51a12 12 0 0 1-17 17L128 145l-63.51 63.49a12 12 0 0 1-17-17L111 128L47.51 64.49a12 12 0 0 1 17-17L128 111l63.51-63.52a12 12 0 0 1 17 17L145 128Z" />
|
||||||
|
</svg></div>
|
||||||
|
@else
|
||||||
|
<div class="w-64"><x-loading text="Proxy Started:" /></div>
|
||||||
|
@endif
|
||||||
|
@endif
|
||||||
|
@else
|
||||||
|
@if ($error)
|
||||||
|
<div class="flex w-64 gap-2">Docker Compose is installed: <svg class="w-5 h-5 text-error"
|
||||||
|
viewBox="0 0 256 256" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path fill="currentColor"
|
||||||
|
d="M208.49 191.51a12 12 0 0 1-17 17L128 145l-63.51 63.49a12 12 0 0 1-17-17L111 128L47.51 64.49a12 12 0 0 1 17-17L128 111l63.51-63.52a12 12 0 0 1 17 17L145 128Z" />
|
||||||
|
</svg></div>
|
||||||
|
@else
|
||||||
|
<div class="w-64"><x-loading text="Docker Compose is installed:" /></div>
|
||||||
|
@endif
|
||||||
|
@endif
|
||||||
|
|
||||||
|
@endif
|
||||||
|
@isset($docker_version)
|
||||||
|
<div class="flex w-64 gap-2">Minimum Docker version installed: <svg class="w-5 h-5 text-success"
|
||||||
|
viewBox="0 0 256 256" xmlns="http://www.w3.org/2000/svg">
|
||||||
<g fill="currentColor">
|
<g fill="currentColor">
|
||||||
<path
|
<path
|
||||||
d="m237.66 85.26l-128.4 128.4a8 8 0 0 1-11.32 0l-71.6-72a8 8 0 0 1 0-11.31l24-24a8 8 0 0 1 11.32 0l36.68 35.32a8 8 0 0 0 11.32 0l92.68-91.32a8 8 0 0 1 11.32 0l24 23.6a8 8 0 0 1 0 11.31"
|
d="m237.66 85.26l-128.4 128.4a8 8 0 0 1-11.32 0l-71.6-72a8 8 0 0 1 0-11.31l24-24a8 8 0 0 1 11.32 0l36.68 35.32a8 8 0 0 0 11.32 0l92.68-91.32a8 8 0 0 1 11.32 0l24 23.6a8 8 0 0 1 0 11.31"
|
||||||
@@ -57,32 +131,11 @@
|
|||||||
d="m243.28 68.24l-24-23.56a16 16 0 0 0-22.58 0L104 136l-.11-.11l-36.64-35.27a16 16 0 0 0-22.57.06l-24 24a16 16 0 0 0 0 22.61l71.62 72a16 16 0 0 0 22.63 0l128.4-128.38a16 16 0 0 0-.05-22.67M103.62 208L32 136l24-24l.11.11l36.64 35.27a16 16 0 0 0 22.52 0L208.06 56L232 79.6Z" />
|
d="m243.28 68.24l-24-23.56a16 16 0 0 0-22.58 0L104 136l-.11-.11l-36.64-35.27a16 16 0 0 0-22.57.06l-24 24a16 16 0 0 0 0 22.61l71.62 72a16 16 0 0 0 22.63 0l128.4-128.38a16 16 0 0 0-.05-22.67M103.62 208L32 136l24-24l.11.11l36.64 35.27a16 16 0 0 0 22.52 0L208.06 56L232 79.6Z" />
|
||||||
</g>
|
</g>
|
||||||
</svg></div>
|
</svg></div>
|
||||||
@else
|
@endisset
|
||||||
@if ($error)
|
|
||||||
<div class="flex w-64 gap-2">Docker is installed: <svg class="w-5 h-5 text-error" viewBox="0 0 256 256"
|
<livewire:new-activity-monitor header="Logs" />
|
||||||
xmlns="http://www.w3.org/2000/svg">
|
@isset($error)
|
||||||
<path fill="currentColor"
|
<pre class="font-bold whitespace-pre-line text-error">{!! $error !!}</pre>
|
||||||
d="M208.49 191.51a12 12 0 0 1-17 17L128 145l-63.51 63.49a12 12 0 0 1-17-17L111 128L47.51 64.49a12 12 0 0 1 17-17L128 111l63.51-63.52a12 12 0 0 1 17 17L145 128Z" />
|
@endisset
|
||||||
</svg></div>
|
|
||||||
@else
|
|
||||||
<div class="w-64"><x-loading text="Docker is installed:" /></div>
|
|
||||||
@endif
|
|
||||||
@endif
|
|
||||||
@endif
|
@endif
|
||||||
@isset($docker_version)
|
|
||||||
<div class="flex w-64 gap-2">Minimum Docker version installed: <svg class="w-5 h-5 text-success"
|
|
||||||
viewBox="0 0 256 256" xmlns="http://www.w3.org/2000/svg">
|
|
||||||
<g fill="currentColor">
|
|
||||||
<path
|
|
||||||
d="m237.66 85.26l-128.4 128.4a8 8 0 0 1-11.32 0l-71.6-72a8 8 0 0 1 0-11.31l24-24a8 8 0 0 1 11.32 0l36.68 35.32a8 8 0 0 0 11.32 0l92.68-91.32a8 8 0 0 1 11.32 0l24 23.6a8 8 0 0 1 0 11.31"
|
|
||||||
opacity=".2" />
|
|
||||||
<path
|
|
||||||
d="m243.28 68.24l-24-23.56a16 16 0 0 0-22.58 0L104 136l-.11-.11l-36.64-35.27a16 16 0 0 0-22.57.06l-24 24a16 16 0 0 0 0 22.61l71.62 72a16 16 0 0 0 22.63 0l128.4-128.38a16 16 0 0 0-.05-22.67M103.62 208L32 136l24-24l.11.11l36.64 35.27a16 16 0 0 0 22.52 0L208.06 56L232 79.6Z" />
|
|
||||||
</g>
|
|
||||||
</svg></div>
|
|
||||||
@endisset
|
|
||||||
<livewire:new-activity-monitor header="Logs" />
|
|
||||||
@isset($error)
|
|
||||||
<pre class="font-bold whitespace-pre-line text-error">{!! $error !!}</pre>
|
|
||||||
@endisset
|
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,36 +1,11 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
use App\Actions\Database\StartMariadb;
|
|
||||||
use App\Actions\Database\StartMongodb;
|
|
||||||
use App\Actions\Database\StartMysql;
|
|
||||||
use App\Actions\Database\StartPostgresql;
|
|
||||||
use App\Actions\Database\StartRedis;
|
|
||||||
use App\Actions\Service\StartService;
|
|
||||||
use App\Http\Controllers\Api\Deploy;
|
use App\Http\Controllers\Api\Deploy;
|
||||||
use App\Models\ApplicationDeploymentQueue;
|
use App\Http\Controllers\Api\Project;
|
||||||
use App\Models\Tag;
|
use App\Http\Controllers\Api\Server;
|
||||||
use App\Models\User;
|
|
||||||
use App\Providers\RouteServiceProvider;
|
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Support\Facades\Http;
|
use Illuminate\Support\Facades\Http;
|
||||||
use Illuminate\Support\Facades\Route;
|
use Illuminate\Support\Facades\Route;
|
||||||
use Visus\Cuid2\Cuid2;
|
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| API Routes
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| Here is where you can register API routes for your application. These
|
|
||||||
| routes are loaded by the RouteServiceProvider and all of them will
|
|
||||||
| be assigned to the "api" middleware group. Make something great!
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
|
|
||||||
$middlewares = ['auth:sanctum'];
|
|
||||||
if (isDev()) {
|
|
||||||
$middlewares = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
Route::get('/health', function () {
|
Route::get('/health', function () {
|
||||||
return 'OK';
|
return 'OK';
|
||||||
@@ -45,44 +20,41 @@ Route::post('/feedback', function (Request $request) {
|
|||||||
}
|
}
|
||||||
return response()->json(['message' => 'Feedback sent.'], 200);
|
return response()->json(['message' => 'Feedback sent.'], 200);
|
||||||
});
|
});
|
||||||
// Route::group([
|
|
||||||
// 'middleware' => $middlewares,
|
|
||||||
// 'prefix' => 'v1'
|
|
||||||
// ], function () {
|
|
||||||
// Route::get('/deployments', function () {
|
|
||||||
// return ApplicationDeploymentQueue::whereIn("status", ["in_progress", "queued"])->get([
|
|
||||||
// "id",
|
|
||||||
// "server_id",
|
|
||||||
// "status"
|
|
||||||
// ])->groupBy("server_id")->map(function ($item) {
|
|
||||||
// return $item;
|
|
||||||
// })->toArray();
|
|
||||||
// });
|
|
||||||
// });
|
|
||||||
Route::group([
|
Route::group([
|
||||||
'middleware' => ['auth:sanctum'],
|
'middleware' => ['auth:sanctum'],
|
||||||
'prefix' => 'v1'
|
'prefix' => 'v1'
|
||||||
], function () {
|
], function () {
|
||||||
|
Route::get('/version', function () {
|
||||||
|
return response(config('version'));
|
||||||
|
});
|
||||||
Route::get('/deploy', [Deploy::class, 'deploy']);
|
Route::get('/deploy', [Deploy::class, 'deploy']);
|
||||||
|
Route::get('/servers', [Server::class, 'servers']);
|
||||||
|
Route::get('/server/{uuid}', [Server::class, 'server_by_uuid']);
|
||||||
|
Route::get('/projects', [Project::class, 'projects']);
|
||||||
|
Route::get('/project/{uuid}', [Project::class, 'project_by_uuid']);
|
||||||
|
Route::get('/project/{uuid}/{environment_name}', [Project::class, 'environment_details']);
|
||||||
});
|
});
|
||||||
|
|
||||||
Route::middleware(['throttle:5'])->group(function () {
|
Route::get('/{any}', function () {
|
||||||
Route::get('/unsubscribe/{token}', function () {
|
return response()->json(['error' => 'Not found.'], 404);
|
||||||
try {
|
})->where('any', '.*');
|
||||||
$token = request()->token;
|
|
||||||
$email = decrypt($token);
|
// Route::middleware(['throttle:5'])->group(function () {
|
||||||
if (!User::whereEmail($email)->exists()) {
|
// Route::get('/unsubscribe/{token}', function () {
|
||||||
return redirect(RouteServiceProvider::HOME);
|
// try {
|
||||||
}
|
// $token = request()->token;
|
||||||
if (User::whereEmail($email)->first()->marketing_emails === false) {
|
// $email = decrypt($token);
|
||||||
return 'You have already unsubscribed from marketing emails.';
|
// if (!User::whereEmail($email)->exists()) {
|
||||||
}
|
// return redirect(RouteServiceProvider::HOME);
|
||||||
User::whereEmail($email)->update(['marketing_emails' => false]);
|
// }
|
||||||
return 'You have been unsubscribed from marketing emails.';
|
// if (User::whereEmail($email)->first()->marketing_emails === false) {
|
||||||
} catch (\Throwable $e) {
|
// return 'You have already unsubscribed from marketing emails.';
|
||||||
return 'Something went wrong. Please try again or contact support.';
|
// }
|
||||||
}
|
// User::whereEmail($email)->update(['marketing_emails' => false]);
|
||||||
})->name('unsubscribe.marketing.emails');
|
// return 'You have been unsubscribed from marketing emails.';
|
||||||
});
|
// } catch (\Throwable $e) {
|
||||||
|
// return 'Something went wrong. Please try again or contact support.';
|
||||||
|
// }
|
||||||
|
// })->name('unsubscribe.marketing.emails');
|
||||||
|
// });
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
use App\Http\Controllers\Api\Server as ApiServer;
|
||||||
use App\Models\GitlabApp;
|
use App\Models\GitlabApp;
|
||||||
use App\Models\PrivateKey;
|
use App\Models\PrivateKey;
|
||||||
use App\Models\Server;
|
use App\Models\Server;
|
||||||
@@ -61,12 +62,13 @@ use App\Livewire\Security\PrivateKey\Show as SecurityPrivateKeyShow;
|
|||||||
use App\Livewire\Server\Index as ServerIndex;
|
use App\Livewire\Server\Index as ServerIndex;
|
||||||
use App\Livewire\Server\Create as ServerCreate;
|
use App\Livewire\Server\Create as ServerCreate;
|
||||||
use App\Livewire\Server\Show as ServerShow;
|
use App\Livewire\Server\Show as ServerShow;
|
||||||
|
use App\Livewire\Server\Resources as ResourcesShow;
|
||||||
|
|
||||||
use App\Livewire\Server\Destination\Show as DestinationShow;
|
use App\Livewire\Server\Destination\Show as DestinationShow;
|
||||||
use App\Livewire\Server\LogDrains;
|
use App\Livewire\Server\LogDrains;
|
||||||
use App\Livewire\Server\PrivateKey\Show as PrivateKeyShow;
|
use App\Livewire\Server\PrivateKey\Show as PrivateKeyShow;
|
||||||
use App\Livewire\Server\Proxy\Show as ProxyShow;
|
use App\Livewire\Server\Proxy\Show as ProxyShow;
|
||||||
use App\Livewire\Server\Proxy\Logs as ProxyLogs;
|
use App\Livewire\Server\Proxy\Logs as ProxyLogs;
|
||||||
|
|
||||||
use App\Livewire\Source\Github\Change as GitHubChange;
|
use App\Livewire\Source\Github\Change as GitHubChange;
|
||||||
use App\Livewire\Subscription\Index as SubscriptionIndex;
|
use App\Livewire\Subscription\Index as SubscriptionIndex;
|
||||||
|
|
||||||
@@ -79,9 +81,7 @@ use App\Livewire\Waitlist\Index as WaitlistIndex;
|
|||||||
if (isDev()) {
|
if (isDev()) {
|
||||||
Route::get('/dev/compose', Compose::class)->name('dev.compose');
|
Route::get('/dev/compose', Compose::class)->name('dev.compose');
|
||||||
}
|
}
|
||||||
if (isCloud()) {
|
Route::get('/admin', AdminIndex::class)->name('admin.index');
|
||||||
Route::get('/admin', AdminIndex::class)->name('admin.index');
|
|
||||||
}
|
|
||||||
|
|
||||||
Route::post('/forgot-password', [Controller::class, 'forgot_password'])->name('password.forgot');
|
Route::post('/forgot-password', [Controller::class, 'forgot_password'])->name('password.forgot');
|
||||||
Route::get('/api/v1/test/realtime', [Controller::class, 'realtime_test'])->middleware('auth');
|
Route::get('/api/v1/test/realtime', [Controller::class, 'realtime_test'])->middleware('auth');
|
||||||
@@ -165,7 +165,7 @@ Route::middleware(['auth', 'verified'])->group(function () {
|
|||||||
});
|
});
|
||||||
Route::prefix('project/{project_uuid}/{environment_name}/service/{service_uuid}')->group(function () {
|
Route::prefix('project/{project_uuid}/{environment_name}/service/{service_uuid}')->group(function () {
|
||||||
Route::get('/', ServiceConfiguration::class)->name('project.service.configuration');
|
Route::get('/', ServiceConfiguration::class)->name('project.service.configuration');
|
||||||
Route::get('/{service_name}', ServiceIndex::class)->name('project.service.index');
|
Route::get('/{stack_service_uuid}', ServiceIndex::class)->name('project.service.index');
|
||||||
Route::get('/command', ExecuteContainerCommand::class)->name('project.service.command');
|
Route::get('/command', ExecuteContainerCommand::class)->name('project.service.command');
|
||||||
Route::get('/tasks/{task_uuid}', ScheduledTaskShow::class)->name('project.service.scheduled-tasks');
|
Route::get('/tasks/{task_uuid}', ScheduledTaskShow::class)->name('project.service.scheduled-tasks');
|
||||||
});
|
});
|
||||||
@@ -175,6 +175,7 @@ Route::middleware(['auth', 'verified'])->group(function () {
|
|||||||
|
|
||||||
Route::prefix('server/{server_uuid}')->group(function () {
|
Route::prefix('server/{server_uuid}')->group(function () {
|
||||||
Route::get('/', ServerShow::class)->name('server.show');
|
Route::get('/', ServerShow::class)->name('server.show');
|
||||||
|
Route::get('/resources', ResourcesShow::class)->name('server.resources');
|
||||||
Route::get('/proxy', ProxyShow::class)->name('server.proxy');
|
Route::get('/proxy', ProxyShow::class)->name('server.proxy');
|
||||||
Route::get('/proxy/logs', ProxyLogs::class)->name('server.proxy.logs');
|
Route::get('/proxy/logs', ProxyLogs::class)->name('server.proxy.logs');
|
||||||
Route::get('/private-key', PrivateKeyShow::class)->name('server.private-key');
|
Route::get('/private-key', PrivateKeyShow::class)->name('server.private-key');
|
||||||
|
|||||||
@@ -861,7 +861,11 @@ Route::post('/payments/stripe/events', function () {
|
|||||||
$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)->first();
|
||||||
|
}
|
||||||
|
if (!$subscription) {
|
||||||
|
send_internal_notification('No subscription found for: ' . $customerId);
|
||||||
|
return response("No subscription found", 400);
|
||||||
}
|
}
|
||||||
$trialEndedAlready = data_get($subscription, 'stripe_trial_already_ended');
|
$trialEndedAlready = data_get($subscription, 'stripe_trial_already_ended');
|
||||||
$cancelAtPeriodEnd = data_get($data, 'cancel_at_period_end');
|
$cancelAtPeriodEnd = data_get($data, 'cancel_at_period_end');
|
||||||
|
|||||||
@@ -11,7 +11,13 @@ DOCKER_VERSION="24.0"
|
|||||||
|
|
||||||
CDN="https://cdn.coollabs.io/coolify"
|
CDN="https://cdn.coollabs.io/coolify"
|
||||||
OS_TYPE=$(grep -w "ID" /etc/os-release | cut -d "=" -f 2 | tr -d '"')
|
OS_TYPE=$(grep -w "ID" /etc/os-release | cut -d "=" -f 2 | tr -d '"')
|
||||||
OS_VERSION=$(grep -w "VERSION_ID" /etc/os-release | cut -d "=" -f 2 | tr -d '"')
|
|
||||||
|
if [ "$OS_TYPE" = "arch" ]; then
|
||||||
|
OS_VERSION="rolling"
|
||||||
|
else
|
||||||
|
OS_VERSION=$(grep -w "VERSION_ID" /etc/os-release | cut -d "=" -f 2 | tr -d '"')
|
||||||
|
fi
|
||||||
|
|
||||||
LATEST_VERSION=$(curl --silent $CDN/versions.json | grep -i version | sed -n '2p' | xargs | awk '{print $2}' | tr -d ',')
|
LATEST_VERSION=$(curl --silent $CDN/versions.json | grep -i version | sed -n '2p' | xargs | awk '{print $2}' | tr -d ',')
|
||||||
DATE=$(date +"%Y%m%d-%H%M%S")
|
DATE=$(date +"%Y%m%d-%H%M%S")
|
||||||
|
|
||||||
@@ -21,11 +27,11 @@ if [ $EUID != 0 ]; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
case "$OS_TYPE" in
|
case "$OS_TYPE" in
|
||||||
ubuntu | debian | raspbian | centos | fedora | rhel | ol | rocky | sles | opensuse-leap | opensuse-tumbleweed) ;;
|
arch | ubuntu | debian | raspbian | centos | fedora | rhel | ol | rocky | sles | opensuse-leap | opensuse-tumbleweed) ;;
|
||||||
*)
|
*)
|
||||||
echo "This script only supports Debian, Redhat or Sles based operating systems for now."
|
echo "This script only supports Debian, Redhat, Arch Linux, or SLES based operating systems for now."
|
||||||
exit
|
exit
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
# Overwrite LATEST_VERSION if user pass a version number
|
# Overwrite LATEST_VERSION if user pass a version number
|
||||||
@@ -48,33 +54,47 @@ echo -e "-------------"
|
|||||||
echo "Installing required packages..."
|
echo "Installing required packages..."
|
||||||
|
|
||||||
case "$OS_TYPE" in
|
case "$OS_TYPE" in
|
||||||
ubuntu | debian | raspbian)
|
arch)
|
||||||
apt update -y >/dev/null 2>&1
|
pacman -Sy >/dev/null 2>&1 || true
|
||||||
apt install -y curl wget git jq >/dev/null 2>&1
|
if ! pacman -Q curl wget git jq >/dev/null 2>&1; then
|
||||||
;;
|
pacman -S --noconfirm curl wget git jq >/dev/null 2>&1 || true
|
||||||
centos | fedora | rhel | ol | rocky)
|
fi
|
||||||
dnf install -y curl wget git jq >/dev/null 2>&1
|
;;
|
||||||
;;
|
ubuntu | debian | raspbian)
|
||||||
sles | opensuse-leap | opensuse-tumbleweed)
|
apt update -y >/dev/null 2>&1
|
||||||
zypper refresh >/dev/null 2>&1
|
apt install -y curl wget git jq >/dev/null 2>&1
|
||||||
zypper install -y curl wget git jq >/dev/null 2>&1
|
;;
|
||||||
;;
|
centos | fedora | rhel | ol | rocky)
|
||||||
*)
|
dnf install -y curl wget git jq >/dev/null 2>&1
|
||||||
echo "This script only supports Debian, Redhat or Sles based operating systems for now."
|
;;
|
||||||
exit
|
sles | opensuse-leap | opensuse-tumbleweed)
|
||||||
;;
|
zypper refresh >/dev/null 2>&1
|
||||||
|
zypper install -y curl wget git jq >/dev/null 2>&1
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "This script only supports Debian, Redhat, Arch Linux, or SLES based operating systems for now."
|
||||||
|
exit
|
||||||
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
# Detect OpenSSH server
|
# Detect OpenSSH server
|
||||||
SSH_DETECTED=false
|
SSH_DETECTED=false
|
||||||
if [ -x "$(command -v systemctl)" ]; then
|
if [ -x "$(command -v systemctl)" ]; then
|
||||||
if systemctl status sshd >/dev/null 2>&1; then
|
if systemctl status sshd >/dev/null 2>&1; then
|
||||||
echo "OpenSSH server is installed and running."
|
echo "OpenSSH server is installed."
|
||||||
|
SSH_DETECTED=true
|
||||||
|
fi
|
||||||
|
if systemctl status ssh >/dev/null 2>&1; then
|
||||||
|
echo "OpenSSH server is installed."
|
||||||
SSH_DETECTED=true
|
SSH_DETECTED=true
|
||||||
fi
|
fi
|
||||||
elif [ -x "$(command -v service)" ]; then
|
elif [ -x "$(command -v service)" ]; then
|
||||||
if service sshd status >/dev/null 2>&1; then
|
if service sshd status >/dev/null 2>&1; then
|
||||||
echo "OpenSSH server is installed and running."
|
echo "OpenSSH server is installed."
|
||||||
|
SSH_DETECTED=true
|
||||||
|
fi
|
||||||
|
if service ssh status >/dev/null 2>&1; then
|
||||||
|
echo "OpenSSH server is installed."
|
||||||
SSH_DETECTED=true
|
SSH_DETECTED=true
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
@@ -105,22 +125,35 @@ fi
|
|||||||
|
|
||||||
if ! [ -x "$(command -v docker)" ]; then
|
if ! [ -x "$(command -v docker)" ]; then
|
||||||
echo "Docker is not installed. Installing Docker."
|
echo "Docker is not installed. Installing Docker."
|
||||||
curl https://releases.rancher.com/install-docker/${DOCKER_VERSION}.sh | sh
|
if [ "$OS_TYPE" = "arch" ]; then
|
||||||
if [ -x "$(command -v docker)" ]; then
|
pacman -Sy docker docker-compose --noconfirm
|
||||||
echo "Docker installed successfully."
|
systemctl enable docker.service
|
||||||
else
|
|
||||||
echo "Docker installation failed with Rancher script. Trying with official script."
|
|
||||||
curl https://get.docker.com | sh -s -- --version ${DOCKER_VERSION}
|
|
||||||
if [ -x "$(command -v docker)" ]; then
|
if [ -x "$(command -v docker)" ]; then
|
||||||
echo "Docker installed successfully."
|
echo "Docker installed successfully."
|
||||||
else
|
else
|
||||||
echo "Docker installation failed with official script."
|
echo "Failed to install Docker with pacman. Try to install it manually."
|
||||||
echo "Maybe your OS is not supported."
|
echo "Please visit https://wiki.archlinux.org/title/docker for more information."
|
||||||
echo "Please visit https://docs.docker.com/engine/install/ and install Docker manually to continue."
|
exit
|
||||||
exit 1
|
fi
|
||||||
|
else
|
||||||
|
curl https://releases.rancher.com/install-docker/${DOCKER_VERSION}.sh | sh
|
||||||
|
if [ -x "$(command -v docker)" ]; then
|
||||||
|
echo "Docker installed successfully."
|
||||||
|
else
|
||||||
|
echo "Docker installation failed with Rancher script. Trying with official script."
|
||||||
|
curl https://get.docker.com | sh -s -- --version ${DOCKER_VERSION}
|
||||||
|
if [ -x "$(command -v docker)" ]; then
|
||||||
|
echo "Docker installed successfully."
|
||||||
|
else
|
||||||
|
echo "Docker installation failed with official script."
|
||||||
|
echo "Maybe your OS is not supported?"
|
||||||
|
echo "Please visit https://docs.docker.com/engine/install/ and install Docker manually to continue."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo -e "-------------"
|
echo -e "-------------"
|
||||||
echo -e "Check Docker Configuration..."
|
echo -e "Check Docker Configuration..."
|
||||||
mkdir -p /etc/docker
|
mkdir -p /etc/docker
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
services:
|
services:
|
||||||
directus:
|
directus:
|
||||||
image: directus/directus:10.7
|
image: directus/directus:10
|
||||||
volumes:
|
volumes:
|
||||||
- directus-uploads:/directus/uploads
|
- directus-uploads:/directus/uploads
|
||||||
- directus-extensions:/directus/extensions
|
- directus-extensions:/directus/extensions
|
||||||
|
|||||||
48
templates/compose/docker-registry.yaml
Normal file
48
templates/compose/docker-registry.yaml
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
# documentation: https://docs.docker.com/registry/
|
||||||
|
# slogan: The Docker Registry is a stateless, highly scalable server side application that stores and lets you distribute Docker images.
|
||||||
|
# tags: registry,images,docker
|
||||||
|
|
||||||
|
services:
|
||||||
|
registry:
|
||||||
|
image: registry:2
|
||||||
|
environment:
|
||||||
|
- SERVICE_FQDN_REGISTRY
|
||||||
|
- REGISTRY_AUTH=htpasswd
|
||||||
|
- REGISTRY_AUTH_HTPASSWD_REALM=Registry
|
||||||
|
- REGISTRY_AUTH_HTPASSWD_PATH=/auth/registry.password
|
||||||
|
- REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY=/data
|
||||||
|
volumes:
|
||||||
|
- type: bind
|
||||||
|
source: ./auth/registry.password
|
||||||
|
target: /auth/registry.password
|
||||||
|
isDirectory: false
|
||||||
|
content: >-
|
||||||
|
testuser:$2y$05$/o2JvmI2bhExXIt6Oqxa7ekYB7v3scj1wFEf6tBslJvJOMoPQL.Gy
|
||||||
|
- type: bind
|
||||||
|
source: ./config/config.yml
|
||||||
|
target: /etc/docker/registry/config.yml
|
||||||
|
isDirectory: false
|
||||||
|
content: >-
|
||||||
|
version: 0.1
|
||||||
|
|
||||||
|
log:
|
||||||
|
fields:
|
||||||
|
service: registry
|
||||||
|
storage:
|
||||||
|
cache:
|
||||||
|
blobdescriptor: inmemory
|
||||||
|
filesystem:
|
||||||
|
rootdirectory: /var/lib/registry
|
||||||
|
http:
|
||||||
|
addr: :5000
|
||||||
|
headers:
|
||||||
|
X-Content-Type-Options: [nosniff]
|
||||||
|
health:
|
||||||
|
storagedriver:
|
||||||
|
enabled: true
|
||||||
|
interval: 10s
|
||||||
|
threshold: 3
|
||||||
|
- type: bind
|
||||||
|
source: ./data
|
||||||
|
target: /data
|
||||||
|
isDirectory: true
|
||||||
@@ -4,15 +4,20 @@
|
|||||||
|
|
||||||
services:
|
services:
|
||||||
filebrowser:
|
filebrowser:
|
||||||
image: filebrowser/filebrowser:s6
|
image: filebrowser/filebrowser:latest
|
||||||
environment:
|
environment:
|
||||||
- SERVICE_FQDN_FILEBROWSER
|
- SERVICE_FQDN_FILEBROWSER
|
||||||
- PUID=1000
|
|
||||||
- PGID=1000
|
|
||||||
volumes:
|
volumes:
|
||||||
- filebrowser-srv:/srv
|
- type: bind
|
||||||
- filebrowser-database:/database/filebrowser.db
|
source: ./srv
|
||||||
- filebrowser-config:/config/settings.json
|
target: /srv
|
||||||
|
isDirectory: true
|
||||||
|
- ./database.db:/database.db
|
||||||
|
- type: bind
|
||||||
|
source: ./filebrowser.json
|
||||||
|
target: /.filebrowser.json
|
||||||
|
read_only: true
|
||||||
|
content: "{}"
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: ["CMD", "curl", "-f", "http://localhost:80"]
|
test: ["CMD", "curl", "-f", "http://localhost:80"]
|
||||||
interval: 2s
|
interval: 2s
|
||||||
|
|||||||
35
templates/compose/metabase.yaml
Normal file
35
templates/compose/metabase.yaml
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
# documentation: https://www.metabase.com/docs/latest/installation-and-operation/running-metabase-on-docker
|
||||||
|
# slogan: Fast analytics with the friendly UX and integrated tooling to let your company explore data on their own.
|
||||||
|
# tags: analytics,bi,business,intelligence
|
||||||
|
|
||||||
|
services:
|
||||||
|
metabase:
|
||||||
|
image: metabase/metabase:latest
|
||||||
|
volumes:
|
||||||
|
- /dev/urandom:/dev/random:ro
|
||||||
|
environment:
|
||||||
|
- SERVICE_FQDN_METABASE
|
||||||
|
- MB_DB_TYPE=postgres
|
||||||
|
- MB_DB_HOST=postgresql
|
||||||
|
- MB_DB_PORT=5432
|
||||||
|
- MB_DB_DBNAME=${POSTGRESQL_DATABASE:-metabase}
|
||||||
|
- MB_DB_USER=$SERVICE_USER_POSTGRESQL
|
||||||
|
- MB_DB_PASS=$SERVICE_PASSWORD_POSTGRESQL
|
||||||
|
healthcheck:
|
||||||
|
test: curl --fail -I http://localhost:3000/api/health || exit 1
|
||||||
|
interval: 5s
|
||||||
|
timeout: 20s
|
||||||
|
retries: 10
|
||||||
|
postgresql:
|
||||||
|
image: postgres:16-alpine
|
||||||
|
volumes:
|
||||||
|
- metabase-postgresql-data:/var/lib/postgresql/data
|
||||||
|
environment:
|
||||||
|
- POSTGRES_USER=${SERVICE_USER_POSTGRESQL}
|
||||||
|
- POSTGRES_PASSWORD=${SERVICE_PASSWORD_POSTGRESQL}
|
||||||
|
- POSTGRES_DB=${POSTGRESQL_DATABASE:-metabase}
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}"]
|
||||||
|
interval: 5s
|
||||||
|
timeout: 20s
|
||||||
|
retries: 10
|
||||||
20
templates/compose/syncthing.yaml
Normal file
20
templates/compose/syncthing.yaml
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
# documentation: https://syncthing.net/
|
||||||
|
# slogan: Syncthing is a continuous file synchronization program. It synchronizes files between two or more computers in real time, safely protected from prying eyes. Your data is your data alone and you deserve to choose where it is stored, whether it is shared with some third party, and how it’s transmitted over the internet.
|
||||||
|
# tags: filestorage, data, synchronization
|
||||||
|
|
||||||
|
services:
|
||||||
|
syncthing:
|
||||||
|
image: 'lscr.io/linuxserver/syncthing:latest'
|
||||||
|
environment:
|
||||||
|
- SERVICE_FQDN_SYNCTHING
|
||||||
|
- PUID=1000
|
||||||
|
- PGID=1000
|
||||||
|
- TZ=Etc/UTC
|
||||||
|
volumes:
|
||||||
|
- 'syncthing-config:/config'
|
||||||
|
- 'syncthing-data1:/data1'
|
||||||
|
- 'syncthing-data2:/data2'
|
||||||
|
ports:
|
||||||
|
- '22000:22000/tcp'
|
||||||
|
- '22000:22000/udp'
|
||||||
|
- '21027:21027/udp'
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user