Compare commits

...

38 Commits

Author SHA1 Message Date
Andras Bacsai
d921456036 Merge pull request #1903 from coollabsio/next
v4.0.0-beta.246
2024-03-27 14:55:41 +01:00
Andras Bacsai
6cc93250b8 fix: uis 2024-03-27 14:51:58 +01:00
Andras Bacsai
39082541ff fix: duplicated generated fqdns are now working 2024-03-27 14:51:43 +01:00
Andras Bacsai
8cff40fdd4 fix: disabled inputs are not trucated 2024-03-27 14:51:20 +01:00
Andras Bacsai
a777db1234 fix: async service loads 2024-03-27 14:50:56 +01:00
Andras Bacsai
3fca169096 feat: change page width 2024-03-27 12:45:53 +01:00
Andras Bacsai
58b451f616 Update GitHub Actions versions 2024-03-27 11:59:01 +01:00
Andras Bacsai
f9b82f711f Update platform tags in development-build.yml 2024-03-27 11:48:04 +01:00
Andras Bacsai
d92b5db320 Refactor forgot password page layout 2024-03-27 11:41:14 +01:00
Andras Bacsai
a164e4bf3a Update Docker build configurations for arm64-v8 architecture 2024-03-27 11:38:21 +01:00
Andras Bacsai
be3cbd9e21 Refactor email settings message in email.blade.php 2024-03-27 11:37:09 +01:00
Andras Bacsai
43fed96af1 fix: autoupdater 2024-03-27 11:35:57 +01:00
Andras Bacsai
3d3d31ef29 fix: name/from address required for resend 2024-03-27 11:28:12 +01:00
Andras Bacsai
d51e70bcaa temporary disable containerrestarted for tcp proxies 2024-03-27 11:13:40 +01:00
Andras Bacsai
32f4c6c982 Update documentation links 2024-03-27 11:07:29 +01:00
Andras Bacsai
8f47761200 ui: fix log outputs 2024-03-27 10:54:17 +01:00
Andras Bacsai
342ebecef2 Remove unnecessary version entry for "coolify" main branch 2024-03-26 14:19:25 +01:00
Andras Bacsai
220a8fe2cc Update container and version configurations 2024-03-26 14:18:33 +01:00
Andras Bacsai
480cb00098 Merge pull request #1893 from coollabsio/next
v4.0.0-beta.245
2024-03-26 13:58:02 +01:00
Andras Bacsai
07ed550dc2 fix: PR deployments should not be distributed to 2 servers 2024-03-26 13:56:30 +01:00
Andras Bacsai
6045870398 fix: scheduled backup for other service databases (supabase) 2024-03-26 13:50:44 +01:00
Andras Bacsai
2bf102cdf1 fix: multline env in dev mode 2024-03-26 13:36:06 +01:00
Andras Bacsai
889a5b2bce ui: fix 2024-03-26 13:35:55 +01:00
Andras Bacsai
df964a094b Remove commented out code for delayed jobs in Kernel.php 2024-03-26 13:27:06 +01:00
Andras Bacsai
e395d4ecee Update version description in bug report template 2024-03-26 13:26:00 +01:00
Andras Bacsai
d077e0c83c fix: realtime connection check 2024-03-26 13:25:10 +01:00
Andras Bacsai
d931241edc fix: update resources view 2024-03-26 12:51:42 +01:00
Andras Bacsai
64a9a72457 fix: ui for tags 2024-03-26 11:52:45 +01:00
Andras Bacsai
a8417aca16 cloud: run cleanup every day 2024-03-26 11:17:48 +01:00
Andras Bacsai
b7b2ecad59 Merge pull request #1888 from coollabsio/next
v4.0.0-beta.244
2024-03-26 10:52:24 +01:00
Andras Bacsai
dcaa2f4168 Refactor error pages 2024-03-26 10:44:52 +01:00
Andras Bacsai
7c7f54d224 Refactor modal input component transitions 2024-03-26 10:29:19 +01:00
Andras Bacsai
b942f8c726 ui ui ui 2024-03-26 10:24:53 +01:00
Andras Bacsai
f661f23ee5 Update background color and text color in app.css 2024-03-25 19:16:39 +01:00
Andras Bacsai
5a631df2a2 uiuiuiui 2024-03-25 19:07:59 +01:00
Andras Bacsai
fc9bb7dac6 Delete user and send email snippets 2024-03-25 16:52:34 +01:00
Andras Bacsai
0a82dc2e8e Remove unused Livewire components 2024-03-25 16:45:34 +01:00
Andras Bacsai
c5eff85c28 Update version numbers and fix UI styling 2024-03-25 16:42:41 +01:00
103 changed files with 895 additions and 818 deletions

View File

@@ -21,6 +21,6 @@ body:
- type: input
attributes:
label: Version
description: Coolify's version (see bottom left corner).
description: Coolify's version (see top of your screen).
validations:
required: true

View File

@@ -18,15 +18,15 @@ jobs:
contents: read
packages: write
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Login to ghcr.io
uses: docker/login-action@v2
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build image and push to registry
uses: docker/build-push-action@v3
uses: docker/build-push-action@v5
with:
no-cache: true
context: .
@@ -40,15 +40,15 @@ jobs:
contents: read
packages: write
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Login to ghcr.io
uses: docker/login-action@v2
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build image and push to registry
uses: docker/build-push-action@v3
uses: docker/build-push-action@v5
with:
no-cache: true
context: .
@@ -64,13 +64,13 @@ jobs:
needs: [ amd64, aarch64 ]
steps:
- name: Checkout
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Set up QEMU
uses: docker/setup-qemu-action@v2
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
uses: docker/setup-buildx-action@v3
- name: Login to ghcr.io
uses: docker/login-action@v2
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}

View File

@@ -18,15 +18,15 @@ jobs:
contents: read
packages: write
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Login to ghcr.io
uses: docker/login-action@v2
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build image and push to registry
uses: docker/build-push-action@v3
uses: docker/build-push-action@v5
with:
no-cache: true
context: .
@@ -40,15 +40,15 @@ jobs:
contents: read
packages: write
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Login to ghcr.io
uses: docker/login-action@v2
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build image and push to registry
uses: docker/build-push-action@v3
uses: docker/build-push-action@v5
with:
no-cache: true
context: .
@@ -64,13 +64,13 @@ jobs:
needs: [ amd64, aarch64 ]
steps:
- name: Checkout
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Set up QEMU
uses: docker/setup-qemu-action@v2
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
uses: docker/setup-buildx-action@v3
- name: Login to ghcr.io
uses: docker/login-action@v2
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}

View File

@@ -18,15 +18,15 @@ jobs:
contents: read
packages: write
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Login to ghcr.io
uses: docker/login-action@v2
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build image and push to registry
uses: docker/build-push-action@v3
uses: docker/build-push-action@v5
with:
no-cache: true
context: .
@@ -40,15 +40,15 @@ jobs:
contents: read
packages: write
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Login to ghcr.io
uses: docker/login-action@v2
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build image and push to registry
uses: docker/build-push-action@v3
uses: docker/build-push-action@v5
with:
no-cache: true
context: .
@@ -64,13 +64,13 @@ jobs:
needs: [ amd64, aarch64 ]
steps:
- name: Checkout
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Set up QEMU
uses: docker/setup-qemu-action@v2
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
uses: docker/setup-buildx-action@v3
- name: Login to ghcr.io
uses: docker/login-action@v2
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}

View File

@@ -14,7 +14,7 @@ jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Cache Docker layers
uses: actions/cache@v2
with:

View File

@@ -1,22 +0,0 @@
<?php
use App\Models\User;
$email = 'test@example.com';
$user = User::whereEmail($email)->first();
$teams = $user->teams;
foreach ($teams as $team) {
$servers = $team->servers;
if ($servers->count() > 0) {
foreach ($servers as $server) {
dump($server);
$server->delete();
}
}
dump($team);
$team->delete();
}
if ($user) {
dump($user);
$user->delete();
}

View File

@@ -1,28 +0,0 @@
<?php
/**
* @label Send Email
* @description Send email to all users
*/
use App\Models\User;
use Illuminate\Support\Facades\Mail;
set_transanctional_email_settings();
$users = User::whereEmail('test@example.com');
foreach ($users as $user) {
Mail::send([], [], function ($message) use ($user) {
$message
->to($user->email)
->subject("Testing")
->text(
<<<EOF
Hello,
Welcome to Coolify Cloud.
Here is your user id: $user->id
EOF
);
});
}

View File

@@ -30,5 +30,5 @@ Your horizon (Laravel scheduler): `localhost:8000/horizon` - Only reachable if y
Mails are caught by Mailpit: `localhost:8025`
## New Service Contribution
Check out the docs [here](https://coolify.io/docs/how-to-add-a-service).
Check out the docs [here](https://coolify.io/docs/resources/services/add-service).

View File

@@ -13,7 +13,7 @@ class InstallDocker
{
$supported_os_type = $server->validateOS();
if (!$supported_os_type) {
throw new \Exception('Server OS type is not supported for automated installation. Please install Docker manually before continuing: <a target="_blank" class="underline" href="https://coolify.io/docs/servers#install-docker-engine-manually">documentation</a>.');
throw new \Exception('Server OS type is not supported for automated installation. Please install Docker manually before continuing: <a target="_blank" class="underline" href="https://coolify.io/docs/installation#manually">documentation</a>.');
}
ray('Installing Docker on server: ' . $server->name . ' (' . $server->ip . ')' . ' with OS type: ' . $supported_os_type);
$dockerVersion = '24.0';

View File

@@ -12,10 +12,12 @@ class UpdateCoolify
public ?Server $server = null;
public ?string $latestVersion = null;
public ?string $currentVersion = null;
public bool $async = false;
public function handle(bool $force)
public function handle(bool $force = false, bool $async = false)
{
try {
$this->async = $async;
$settings = InstanceSettings::get();
ray('Running InstanceAutoUpdateJob');
$this->server = Server::find(0);
@@ -56,17 +58,31 @@ class UpdateCoolify
{
if (isDev()) {
ray("Running update on local docker container. Updating to $this->latestVersion");
remote_process([
"sleep 10"
], $this->server);
if ($this->async) {
ray('Running async update');
remote_process([
"sleep 10"
], $this->server);
} else {
instant_remote_process([
"sleep 10"
], $this->server);
}
ray('Update done');
return;
} else {
ray('Running update on production server');
remote_process([
"curl -fsSL https://cdn.coollabs.io/coolify/upgrade.sh -o /data/coolify/source/upgrade.sh",
"bash /data/coolify/source/upgrade.sh $this->latestVersion"
], $this->server);
if ($this->async) {
remote_process([
"curl -fsSL https://cdn.coollabs.io/coolify/upgrade.sh -o /data/coolify/source/upgrade.sh",
"bash /data/coolify/source/upgrade.sh $this->latestVersion"
], $this->server);
} else {
instant_remote_process([
"curl -fsSL https://cdn.coollabs.io/coolify/upgrade.sh -o /data/coolify/source/upgrade.sh",
"bash /data/coolify/source/upgrade.sh $this->latestVersion"
], $this->server);
}
return;
}
}

View File

@@ -20,7 +20,7 @@ class CleanupDatabase extends Command
$keep_days = 60;
echo "Keep days: $keep_days\n";
// Cleanup failed jobs table
$failed_jobs = DB::table('failed_jobs')->where('failed_at', '<', now()->subDays(7));
$failed_jobs = DB::table('failed_jobs')->where('failed_at', '<', now()->subDays(1));
$count = $failed_jobs->count();
echo "Delete $count entries from failed_jobs.\n";
if ($this->option('yes')) {

View File

@@ -48,9 +48,7 @@ class Kernel extends ConsoleKernel
$this->pull_helper_image($schedule);
$this->check_scheduled_tasks($schedule);
if (!isCloud()) {
$schedule->command('cleanup:database --yes')->daily();
}
$schedule->command('cleanup:database --yes')->daily();
}
}
private function pull_helper_image($schedule)
@@ -72,43 +70,14 @@ class Kernel extends ConsoleKernel
$containerServers = $servers->where('settings.is_swarm_worker', false)->where('settings.is_build_server', false);
}
foreach ($containerServers as $server) {
$schedule->job(new ContainerStatusJob($server))->everyMinute()->onOneServer();
$schedule->job(new ContainerStatusJob($server))->everyTwoMinutes()->onOneServer();
if ($server->isLogDrainEnabled()) {
$schedule->job(new CheckLogDrainContainerJob($server))->everyMinute()->onOneServer();
$schedule->job(new CheckLogDrainContainerJob($server))->everyTwoMinutes()->onOneServer();
}
}
foreach ($servers as $server) {
$schedule->job(new ServerStatusJob($server))->everyMinute()->onOneServer();
$schedule->job(new ServerStatusJob($server))->everyTwoMinutes()->onOneServer();
}
// Delayed Jobs
// foreach ($containerServers as $server) {
// $schedule
// ->call(function () use ($server) {
// $randomSeconds = rand(1, 40);
// $job = new ContainerStatusJob($server);
// $job->delay($randomSeconds);
// ray('dispatching container status job in ' . $randomSeconds . ' seconds');
// dispatch($job);
// })->name('container-status-' . $server->id)->everyMinute()->onOneServer();
// if ($server->isLogDrainEnabled()) {
// $schedule
// ->call(function () use ($server) {
// $randomSeconds = rand(1, 40);
// $job = new CheckLogDrainContainerJob($server);
// $job->delay($randomSeconds);
// dispatch($job);
// })->name('log-drain-container-check-' . $server->id)->everyMinute()->onOneServer();
// }
// }
// foreach ($servers as $server) {
// $schedule
// ->call(function () use ($server) {
// $randomSeconds = rand(1, 40);
// $job = new ServerStatusJob($server);
// $job->delay($randomSeconds);
// dispatch($job);
// })->name('server-status-job-' . $server->id)->everyMinute()->onOneServer();
// }
}
private function instance_auto_update($schedule)
{

View File

@@ -44,7 +44,7 @@ class Deploy extends Controller
$force = $request->query->get('force') ?? false;
if ($uuids && $tags) {
return response()->json(['error' => 'You can only use uuid or tag, not both.', 'docs' => 'https://coolify.io/docs/api/deploy-webhook'], 400);
return response()->json(['error' => 'You can only use uuid or tag, not both.', 'docs' => 'https://coolify.io/docs/api-reference/deploy-webhook'], 400);
}
if (is_null($teamId)) {
return invalid_token();
@@ -54,7 +54,7 @@ class Deploy extends Controller
} else if ($uuids) {
return $this->by_uuids($uuids, $teamId, $force);
}
return response()->json(['error' => 'You must provide uuid or tag.', 'docs' => 'https://coolify.io/docs/api/deploy-webhook'], 400);
return response()->json(['error' => 'You must provide uuid or tag.', 'docs' => 'https://coolify.io/docs/api-reference/deploy-webhook'], 400);
}
private function by_uuids(string $uuid, int $teamId, bool $force = false)
{
@@ -62,7 +62,7 @@ class Deploy extends Controller
$uuids = collect(array_filter($uuids));
if (count($uuids) === 0) {
return response()->json(['error' => 'No UUIDs provided.', 'docs' => 'https://coolify.io/docs/api/deploy-webhook'], 400);
return response()->json(['error' => 'No UUIDs provided.', 'docs' => 'https://coolify.io/docs/api-reference/deploy-webhook'], 400);
}
$deployments = collect();
$payload = collect();
@@ -81,7 +81,7 @@ class Deploy extends Controller
$payload->put('deployments', $deployments->toArray());
return response()->json($payload->toArray(), 200);
}
return response()->json(['error' => "No resources found.", 'docs' => 'https://coolify.io/docs/api/deploy-webhook'], 404);
return response()->json(['error' => "No resources found.", 'docs' => 'https://coolify.io/docs/api-reference/deploy-webhook'], 404);
}
public function by_tags(string $tags, int $team_id, bool $force = false)
{
@@ -89,7 +89,7 @@ class Deploy extends Controller
$tags = collect(array_filter($tags));
if (count($tags) === 0) {
return response()->json(['error' => 'No TAGs provided.', 'docs' => 'https://coolify.io/docs/api/deploy-webhook'], 400);
return response()->json(['error' => 'No TAGs provided.', 'docs' => 'https://coolify.io/docs/api-reference/deploy-webhook'], 400);
}
$message = collect([]);
$deployments = collect();
@@ -127,7 +127,7 @@ class Deploy extends Controller
return response()->json($payload->toArray(), 200);
}
return response()->json(['error' => "No resources found with this tag.", 'docs' => 'https://coolify.io/docs/api/deploy-webhook'], 404);
return response()->json(['error' => "No resources found with this tag.", 'docs' => 'https://coolify.io/docs/api-reference/deploy-webhook'], 404);
}
public function deploy_resource($resource, bool $force = false): array
{

View File

@@ -26,7 +26,7 @@ class Team extends Controller
$teams = auth()->user()->teams;
$team = $teams->where('id', $id)->first();
if (is_null($team)) {
return response()->json(['error' => 'Team not found.', "docs" => "https://coolify.io/docs/api/team-by-id"], 404);
return response()->json(['error' => 'Team not found.', "docs" => "https://coolify.io/docs/api-reference/get-team-by-teamid"], 404);
}
return response()->json($team);
}
@@ -40,7 +40,7 @@ class Team extends Controller
$teams = auth()->user()->teams;
$team = $teams->where('id', $id)->first();
if (is_null($team)) {
return response()->json(['error' => 'Team not found.', "docs" => "https://coolify.io/docs/api/team-by-id-members"], 404);
return response()->json(['error' => 'Team not found.', "docs" => "https://coolify.io/docs/api-reference/get-team-by-teamid-members"], 404);
}
return response()->json($team->members);
}

View File

@@ -737,7 +737,7 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
$nixpacks_php_root_dir = $this->application->environment_variables_preview->where('key', 'NIXPACKS_PHP_ROOT_DIR')->first();
}
if ($nixpacks_php_fallback_path?->value === '/index.php' && $nixpacks_php_root_dir?->value === '/app/public' && $this->newVersionIsHealthy === false) {
$this->application_deployment_queue->addLogEntry("There was a change in how Laravel is deployed. Please update your environment variables to match the new deployment method. More details here: https://coolify.io/docs/frameworks/laravel#requirements", 'stderr');
$this->application_deployment_queue->addLogEntry("There was a change in how Laravel is deployed. Please update your environment variables to match the new deployment method. More details here: https://coolify.io/docs/resources/laravel", 'stderr');
}
}
private function rolling_update()
@@ -898,6 +898,9 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
if ($this->application->additional_networks->count() === 0) {
return;
}
if ($this->pull_request_id !== 0) {
return;
}
$destination_ids = $this->application->additional_networks->pluck('id');
if ($this->server->isSwarm()) {
$this->application_deployment_queue->addLogEntry("Additional destinations are not supported in swarm mode.");

View File

@@ -170,16 +170,13 @@ class ContainerStatusJob implements ShouldQueue, ShouldBeEncrypted
})->first();
if (!$foundTcpProxy) {
StartDatabaseProxy::run($service_db);
$this->server->team?->notify(new ContainerRestarted("TCP Proxy for {$service_db->service->name}", $this->server));
// $this->server->team?->notify(new ContainerRestarted("TCP Proxy for {$service_db->service->name}", $this->server));
}
}
}
}
} else {
$database = $databases->where('uuid', $uuid)->first();
if ($uuid == 'postgresql') {
ray($database);
}
if ($database) {
$isPublic = data_get($database, 'is_public');
$foundDatabases[] = $database->id;
@@ -187,7 +184,6 @@ class ContainerStatusJob implements ShouldQueue, ShouldBeEncrypted
if ($statusFromDb !== $containerStatus) {
$database->update(['status' => $containerStatus]);
}
ray($database);
if ($isPublic) {
$foundTcpProxy = $containers->filter(function ($value, $key) use ($uuid) {
if ($this->server->isSwarm()) {
@@ -197,7 +193,6 @@ class ContainerStatusJob implements ShouldQueue, ShouldBeEncrypted
}
})->first();
if (!$foundTcpProxy) {
ray('asdffff');
StartDatabaseProxy::run($database);
$this->server->team?->notify(new ContainerRestarted("TCP Proxy for {$database->name}", $this->server));
}

View File

@@ -95,7 +95,7 @@ class DatabaseBackupJob implements ShouldQueue, ShouldBeEncrypted
$databaseType = $this->database->databaseType();
$serviceUuid = $this->database->service->uuid;
$serviceName = str($this->database->service->name)->slug();
if ($databaseType === 'standalone-postgresql') {
if (str($databaseType)->contains('postgres')) {
$this->container_name = "{$this->database->name}-$serviceUuid";
$this->directory_name = $serviceName . '-' . $this->container_name;
$commands[] = "docker exec $this->container_name env | grep POSTGRES_";
@@ -120,7 +120,7 @@ class DatabaseBackupJob implements ShouldQueue, ShouldBeEncrypted
} else {
$databasesToBackup = $this->database->postgres_user;
}
} else if ($databaseType === 'standalone-mysql') {
} else if (str($databaseType)->contains('mysql')) {
$this->container_name = "{$this->database->name}-$serviceUuid";
$this->directory_name = $serviceName . '-' . $this->container_name;
$commands[] = "docker exec $this->container_name env | grep MYSQL_";
@@ -143,7 +143,7 @@ class DatabaseBackupJob implements ShouldQueue, ShouldBeEncrypted
} else {
throw new \Exception('MYSQL_DATABASE not found');
}
} else if ($databaseType === 'standalone-mariadb') {
} else if (str($databaseType)->contains('mariadb')) {
$this->container_name = "{$this->database->name}-$serviceUuid";
$this->directory_name = $serviceName . '-' . $this->container_name;
$commands[] = "docker exec $this->container_name env";
@@ -190,32 +190,32 @@ class DatabaseBackupJob implements ShouldQueue, ShouldBeEncrypted
}
if (is_null($databasesToBackup)) {
if ($databaseType === 'standalone-postgresql') {
if (str($databaseType)->contains('postgres')) {
$databasesToBackup = [$this->database->postgres_db];
} else if ($databaseType === 'standalone-mongodb') {
} else if (str($databaseType)->contains('mongodb')) {
$databasesToBackup = ['*'];
} else if ($databaseType === 'standalone-mysql') {
} else if (str($databaseType)->contains('mysql')) {
$databasesToBackup = [$this->database->mysql_database];
} else if ($databaseType === 'standalone-mariadb') {
} else if (str($databaseType)->contains('mariadb')) {
$databasesToBackup = [$this->database->mariadb_database];
} else {
return;
}
} else {
if ($databaseType === 'standalone-postgresql') {
if (str($databaseType)->contains('postgres')) {
// Format: db1,db2,db3
$databasesToBackup = explode(',', $databasesToBackup);
$databasesToBackup = array_map('trim', $databasesToBackup);
} else if ($databaseType === 'standalone-mongodb') {
} else if (str($databaseType)->contains('mongodb')) {
// Format: db1:collection1,collection2|db2:collection3,collection4
$databasesToBackup = explode('|', $databasesToBackup);
$databasesToBackup = array_map('trim', $databasesToBackup);
ray($databasesToBackup);
} else if ($databaseType === 'standalone-mysql') {
} else if (str($databaseType)->contains('mysql')) {
// Format: db1,db2,db3
$databasesToBackup = explode(',', $databasesToBackup);
$databasesToBackup = array_map('trim', $databasesToBackup);
} else if ($databaseType === 'standalone-mariadb') {
} else if (str($databaseType)->contains('mariadb')) {
// Format: db1,db2,db3
$databasesToBackup = explode(',', $databasesToBackup);
$databasesToBackup = array_map('trim', $databasesToBackup);
@@ -235,7 +235,7 @@ class DatabaseBackupJob implements ShouldQueue, ShouldBeEncrypted
$size = 0;
ray('Backing up ' . $database);
try {
if ($databaseType === 'standalone-postgresql') {
if (str($databaseType)->contains('postgres')) {
$this->backup_file = "/pg-dump-$database-" . Carbon::now()->timestamp . ".dmp";
$this->backup_location = $this->backup_dir . $this->backup_file;
$this->backup_log = ScheduledDatabaseBackupExecution::create([
@@ -244,7 +244,7 @@ class DatabaseBackupJob implements ShouldQueue, ShouldBeEncrypted
'scheduled_database_backup_id' => $this->backup->id,
]);
$this->backup_standalone_postgresql($database);
} else if ($databaseType === 'standalone-mongodb') {
} else if (str($databaseType)->contains('mongodb')) {
if ($database === '*') {
$database = 'all';
$databaseName = 'all';
@@ -263,7 +263,7 @@ class DatabaseBackupJob implements ShouldQueue, ShouldBeEncrypted
'scheduled_database_backup_id' => $this->backup->id,
]);
$this->backup_standalone_mongodb($database);
} else if ($databaseType === 'standalone-mysql') {
} else if (str($databaseType)->contains('mysql')) {
$this->backup_file = "/mysql-dump-$database-" . Carbon::now()->timestamp . ".dmp";
$this->backup_location = $this->backup_dir . $this->backup_file;
$this->backup_log = ScheduledDatabaseBackupExecution::create([
@@ -272,7 +272,7 @@ class DatabaseBackupJob implements ShouldQueue, ShouldBeEncrypted
'scheduled_database_backup_id' => $this->backup->id,
]);
$this->backup_standalone_mysql($database);
} else if ($databaseType === 'standalone-mariadb') {
} else if (str($databaseType)->contains('mariadb')) {
$this->backup_file = "/mariadb-dump-$database-" . Carbon::now()->timestamp . ".dmp";
$this->backup_location = $this->backup_dir . $this->backup_file;
$this->backup_log = ScheduledDatabaseBackupExecution::create([

View File

@@ -23,6 +23,6 @@ class InstanceAutoUpdateJob implements ShouldQueue, ShouldBeUnique, ShouldBeEncr
public function handle(): void
{
UpdateCoolify::run($this->force);
UpdateCoolify::run(force: $this->force, async: false);
}
}

View File

@@ -251,7 +251,7 @@ class General extends Component
if ($this->application->additional_servers->count() === 0) {
foreach ($domains as $domain) {
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='dark: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='underline dark:text-white' href='https://coolify.io/docs/knowledge-base/dns-configuration'>documentation</a> for further help.");
}
}
}

View File

@@ -56,11 +56,11 @@ class Heading extends Component
return;
}
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/knowledge-base/server/build-server">documentation</a>');
return;
}
if ($this->application->additional_servers->count() > 0 && str($this->application->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>');
$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/knowledge-base/server/multiple-servers">documentation</a>');
return;
}
$this->setDeploymentUuid();
@@ -99,7 +99,7 @@ class Heading extends Component
public function restart()
{
if ($this->application->additional_servers->count() > 0 && str($this->application->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>');
$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/knowledge-base/server/multiple-servers">documentation</a>');
return;
}
$this->setDeploymentUuid();

View File

@@ -49,7 +49,6 @@ class Select extends Component
}
public function render()
{
$this->loadServices();
return view('livewire.project.new.select');
}
@@ -74,6 +73,7 @@ class Select extends Component
public function loadServices(bool $force = false)
{
try {
$this->loadingServices = true;
if (count($this->allServices) > 0 && !$force) {
if (!$this->search) {
$this->services = $this->allServices;

View File

@@ -56,7 +56,7 @@ class Destination extends Component
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>');
$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/knowledge-base/server/multiple-servers">documentation</a>');
return;
}
$deployment_uuid = new Cuid2(7);

View File

@@ -98,6 +98,7 @@ class All extends Component
}
}
$environment->is_build_time = false;
$environment->is_multiline = false;
$environment->is_preview = $isPreview ? true : false;
switch ($this->resource->type()) {
case 'application':

View File

@@ -1,25 +0,0 @@
<?php
namespace App\Livewire;
use Livewire\Component;
class RealtimeConnection extends Component
{
public $checkConnection = false;
public $showNotification = false;
public $isNotificationEnabled = true;
public function render()
{
return view('livewire.realtime-connection');
}
public function disable()
{
auth()->user()->update(['is_notification_realtime_enabled' => false]);
$this->showNotification = false;
}
public function mount() {
$this->isNotificationEnabled = auth()->user()->is_notification_realtime_enabled;
$this->checkConnection = auth()->user()->id === 0;
}
}

View File

@@ -82,7 +82,7 @@ class Form extends Component
$this->server->settings->is_usable = true;
$this->server->settings->save();
} else {
$this->dispatch('error', 'Server is not reachable.', 'Please validate your configuration and connection.<br><br>Check this <a target="_blank" class="underline" href="https://coolify.io/docs/server/openssh">documentation</a> for further help.');
$this->dispatch('error', 'Server is not reachable.', 'Please validate your configuration and connection.<br><br>Check this <a target="_blank" class="underline" href="https://coolify.io/docs/knowledge-base/server/openssh">documentation</a> for further help.');
return;
}
}

View File

@@ -39,7 +39,7 @@ class ShowPrivateKey extends Component
if ($uptime) {
$this->dispatch('success', 'Server is reachable.');
} else {
$this->dispatch('error', 'Server is not reachable.<br>Please validate your configuration and connection.<br><br>Check this <a target="_blank" class="underline" href="https://coolify.io/docs/server/openssh#openssh">documentation</a> for further help.');
$this->dispatch('error', 'Server is not reachable.<br>Please validate your configuration and connection.<br><br>Check this <a target="_blank" class="underline" href="https://coolify.io/docs/knowledge-base/server/openssh">documentation</a> for further help.');
return;
}
} catch (\Throwable $e) {

View File

@@ -75,7 +75,7 @@ class ValidateAndInstall extends Component
{
$this->uptime = $this->server->validateConnection();
if (!$this->uptime) {
$this->error = 'Server is not reachable. Please validate your configuration and connection.<br><br>Check this <a target="_blank" class="underline" href="https://coolify.io/docs/server/openssh">documentation</a> for further help.';
$this->error = 'Server is not reachable. Please validate your configuration and connection.<br><br>Check this <a target="_blank" class="underline" href="https://coolify.io/docs/knowledge-base/server/openssh">documentation</a> for further help.';
return;
}
$this->dispatch('validateOS');

View File

@@ -58,6 +58,8 @@ class Email extends Component
try {
$this->resetErrorBag();
$this->validate([
'settings.smtp_from_address' => 'required|email',
'settings.smtp_from_name' => 'required',
'settings.resend_api_key' => 'required'
]);
$this->settings->save();
@@ -90,6 +92,8 @@ class Email extends Component
try {
$this->resetErrorBag();
$this->validate([
'settings.smtp_from_address' => 'required|email',
'settings.smtp_from_name' => 'required',
'settings.smtp_host' => 'required',
'settings.smtp_port' => 'required|numeric',
'settings.smtp_encryption' => 'nullable',

View File

@@ -37,8 +37,8 @@ class Upgrade extends Component
return;
}
$this->showProgress = true;
UpdateCoolify::run(true);
$this->dispatch('success', "Upgrading to {$this->latestVersion} version...");
UpdateCoolify::run(force: true, async: true);
$this->dispatch('success', "Updating Coolify to {$this->latestVersion} version...");
} catch (\Throwable $e) {
return handleError($e, $this);
}

View File

@@ -53,13 +53,13 @@ class HighDiskUsage extends Notification implements ShouldQueue
public function toDiscord(): string
{
$message = "Coolify: Server '{$this->server->name}' high disk usage detected!\nDisk usage: {$this->disk_usage}%. Threshold: {$this->cleanup_after_percentage}%.\nPlease cleanup your disk to prevent data-loss.\nHere are some tips: https://coolify.io/docs/automated-cleanup.";
$message = "Coolify: Server '{$this->server->name}' high disk usage detected!\nDisk usage: {$this->disk_usage}%. Threshold: {$this->cleanup_after_percentage}%.\nPlease cleanup your disk to prevent data-loss.\nHere are some tips: https://coolify.io/docs/knowledge-base/server/automated-cleanup.";
return $message;
}
public function toTelegram(): array
{
return [
"message" => "Coolify: Server '{$this->server->name}' high disk usage detected!\nDisk usage: {$this->disk_usage}%. Threshold: {$this->cleanup_after_percentage}%.\nPlease cleanup your disk to prevent data-loss.\nHere are some tips: https://coolify.io/docs/automated-cleanup."
"message" => "Coolify: Server '{$this->server->name}' high disk usage detected!\nDisk usage: {$this->disk_usage}%. Threshold: {$this->cleanup_after_percentage}%.\nPlease cleanup your disk to prevent data-loss.\nHere are some tips: https://coolify.io/docs/knowledge-base/server/automated-cleanup."
];
}
}

View File

@@ -7,5 +7,5 @@ function get_team_id_from_token()
}
function invalid_token()
{
return response()->json(['error' => 'Invalid token.', 'docs' => 'https://coolify.io/docs/api/authentication'], 400);
return response()->json(['error' => 'Invalid token.', 'docs' => 'https://coolify.io/docs/api-reference/authorization'], 400);
}

View File

@@ -110,7 +110,7 @@ function handleError(?Throwable $error = null, ?Livewire\Component $livewire = n
ray($error);
if ($error instanceof TooManyRequestsException) {
if (isset($livewire)) {
return $livewire->dispatch('error', 'Too many requests. Please try again in {$error->secondsUntilAvailable} seconds.');
return $livewire->dispatch('error', "Too many requests. Please try again in {$error->secondsUntilAvailable} seconds.");
}
return "Too many requests. Please try again in {$error->secondsUntilAvailable} seconds.";
}
@@ -944,11 +944,10 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal
if (!$isDatabase) {
if ($savedService->fqdn) {
$fqdn = $savedService->fqdn . ',' . $fqdn;
data_set($savedService, 'fqdn', $savedService->fqdn . ',' . $fqdn);
} else {
$fqdn = $fqdn;
data_set($savedService, 'fqdn', $fqdn);
}
$savedService->fqdn = $fqdn;
$savedService->save();
}
EnvironmentVariable::create([
@@ -960,7 +959,6 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal
]);
}
// Caddy needs exact port in some cases.
if ($predefinedPort && !$key->endsWith("_{$predefinedPort}")) {
if ($resource->server->proxyType() === 'CADDY') {
$env = EnvironmentVariable::where([
@@ -1459,13 +1457,13 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal
])->first();
$value = Str::of(replaceVariables($value));
$key = $value;
if ($value->startsWith('SERVICE_')) {
$foundEnv = EnvironmentVariable::where([
'key' => $key,
'application_id' => $resource->id,
])->first();
['command' => $command, 'forService' => $forService, 'generatedValue' => $generatedValue, 'port' => $port] = parseEnvVariable($value);
ray($command, $generatedValue);
if (!is_null($command)) {
if ($command?->value() === 'FQDN' || $command?->value() === 'URL') {
if (Str::lower($forService) === $serviceName) {

View File

@@ -7,7 +7,7 @@ return [
// The release version of your application
// Example with dynamic git hash: trim(exec('git --git-dir ' . base_path('.git') . ' log --pretty="%h" -n1 HEAD'))
'release' => '4.0.0-beta.243',
'release' => '4.0.0-beta.246',
// When left empty or `null` the Laravel environment will be used
'environment' => config('app.env'),

View File

@@ -1,3 +1,3 @@
<?php
return '4.0.0-beta.243';
return '4.0.0-beta.246';

View File

@@ -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('users', function (Blueprint $table) {
$table->dropColumn('is_notification_realtime_enabled');
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('users', function (Blueprint $table) {
$table->boolean('is_notification_realtime_enabled')->default(true);
});
}
};

View File

@@ -1,3 +0,0 @@
<svg width="45.34" height="64" viewBox="0 0 17 24" xmlns="http://www.w3.org/2000/svg">
<path fill="#FCD34D" d="M11.403 18.751v4.499c-.01.41-.34.74-.748.75H6.159a.768.768 0 0 1-.749-.748v-4.5c.01-.41.34-.739.749-.749h4.5c.41.01.74.34.75.749v.001zm5.923-11.247a6.306 6.306 0 0 1-.962 3.354l.015-.026a5.462 5.462 0 0 1-1.021 1.108l-.01.008c-.321.282-.672.55-1.042.794l-.036.022q-.413.253-1.144.665a3.71 3.71 0 0 0-1.275 1.204l-.009.014a2.535 2.535 0 0 0-.515 1.243l-.001.012a.978.978 0 0 1-.226.611l.001-.002a.652.652 0 0 1-.524.29h-4.5a.563.563 0 0 1-.479-.343l-.001-.004a1.394 1.394 0 0 1-.197-.702v-.845a4.356 4.356 0 0 1 1.219-2.935l-.001.001A7.945 7.945 0 0 1 9.251 9.96l.048-.02a4.627 4.627 0 0 0 1.574-1.049l.001-.001a2.094 2.094 0 0 0 .469-1.429v.005a1.695 1.695 0 0 0-.863-1.382l-.009-.004a3.436 3.436 0 0 0-2.018-.599h.003a3.53 3.53 0 0 0-2.039.552l.014-.009A12.825 12.825 0 0 0 4.45 8.149l-.025.035a.73.73 0 0 1-.581.3a.897.897 0 0 1-.472-.152l.003.002L.301 5.991a.732.732 0 0 1-.29-.464L.01 5.523a.747.747 0 0 1 .105-.527l-.002.003C1.77 2 4.912.003 8.522.003c.103 0 .205.002.307.005h-.015a8.362 8.362 0 0 1 3.074.602l-.057-.02a10.2 10.2 0 0 1 2.757 1.571l-.02-.016a7.838 7.838 0 0 1 1.966 2.349l.02.041c.483.857.768 1.881.769 2.971z"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.2 KiB

View File

@@ -4,7 +4,7 @@
html,
body {
@apply h-full bg-neutral-100 text-neutral-800 dark:bg-base dark:text-neutral-400;
@apply h-full bg-neutral-50 text-neutral-800 dark:bg-base dark:text-neutral-400;
}
body {
@@ -41,7 +41,7 @@ option {
}
.button {
@apply flex items-center justify-center gap-2 px-3 py-1 text-sm font-normal normal-case rounded cursor-pointer bg-neutral-200 hover:bg-neutral-300 dark:bg-coolgray-200 dark:text-white dark:hover:bg-coolgray-100 dark:hover:dark:text-white dark:disabled:bg-coolgray-100/40 dark:disabled:text-neutral-800 disabled:bg-neutral-100 disabled:text-neutral-200 disabled:cursor-not-allowed min-w-fit hover:dark:text-white focus:outline-1 ;
@apply flex items-center justify-center gap-2 px-3 py-1 text-sm text-white normal-case rounded cursor-pointer hover:bg-black/80 bg-coolgray-200 hover:bg-coolgray-500 hover:text-white disabled:bg-coolgray-100/10 disabled:cursor-not-allowed min-w-fit focus:outline-1 dark:disabled:text-neutral-600;
}
button[isError]:not(:disabled) {
@@ -94,7 +94,7 @@ tr {
}
tr th {
@apply px-3 py-3.5 text-left text-white;
@apply px-3 py-3.5 text-left text-black dark:text-white;
}
tr th:first-child {
@@ -116,9 +116,17 @@ tr td:first-child {
.alert-error {
@apply flex items-center gap-2 text-error;
}
.tag {
@apply px-2 py-1 cursor-pointer box-description dark:bg-coolgray-100 dark:hover:bg-coolgray-300 bg-neutral-100 hover:bg-neutral-200
}
.add-tag {
@apply flex items-center px-2 text-xs cursor-pointer dark:text-neutral-500/20 text-neutral-500 group-hover:text-neutral-700 group-hover:dark:text-white dark:hover:bg-coolgray-300 hover:bg-neutral-200;
}
.dropdown-item {
@apply relative flex cursor-pointer select-none dark:text-white hover:bg-neutral-300 dark:hover:bg-coollabs items-center pr-4 pl-2 py-1 text-xs justify-start outline-none transition-colors data-[disabled]:pointer-events-none data-[disabled]:opacity-50 gap-2 w-full;
@apply relative flex cursor-pointer select-none dark:text-white hover:bg-neutral-100 dark:hover:bg-coollabs items-center pr-4 pl-2 py-1 text-xs justify-start outline-none transition-colors data-[disabled]:pointer-events-none data-[disabled]:opacity-50 gap-2 w-full;
}
.dropdown-item-no-padding {
@apply relative flex cursor-pointer select-none dark:text-white hover:bg-neutral-100 dark:hover:bg-coollabs items-center py-1 text-xs justify-start outline-none transition-colors data-[disabled]:pointer-events-none data-[disabled]:opacity-50 gap-2 w-full;
}
.badge {
@@ -187,16 +195,19 @@ tr td:first-child {
}
.box {
@apply flex lg:flex-row flex-col p-2 transition-colors cursor-pointer min-h-[4rem] dark:bg-coolgray-100 bg-white border border-neutral-200 dark:border-black hover:bg-neutral-200 dark:hover:bg-coollabs-100 dark:hover:text-white hover:no-underline;
@apply flex lg:flex-row flex-col p-2 transition-colors cursor-pointer min-h-[4rem] dark:bg-coolgray-100 bg-white border border-neutral-200 dark:border-black hover:bg-neutral-100 dark:hover:bg-coollabs-100 dark:hover:text-white hover:no-underline;
}
.box-boarding {
@apply flex lg:flex-row flex-col p-2 transition-colors cursor-pointer min-h-[4rem] dark:bg-coolgray-100 dark:text-white bg-neutral-50 border border-neutral-200 dark:border-black hover:bg-neutral-100 dark:hover:bg-coollabs-100 dark:hover:text-white hover:text-black hover:no-underline text-black ;
}
.box-without-bg {
@apply flex p-2 transition-colors dark:hover:text-white hover:no-underline min-h-[4rem] border border-neutral-200 dark:border-black;
}
.on-box {
@apply rounded hover:bg-neutral-300 dark:hover:bg-coolgray-500/20;
}
.box-without-bg {
@apply flex p-2 transition-colors dark:hover:text-white hover:no-underline min-h-[4rem];
}
.box-title {
@apply font-bold text-black dark:text-white group-hover:dark:text-white;
@@ -269,7 +280,7 @@ tr td:first-child {
}
.fullscreen {
@apply fixed top-0 left-0 w-full h-full z-[9999] bg-coolgray-100 overflow-y-auto scrollbar pb-4;
@apply fixed top-0 left-0 w-full h-full z-[9999] dark:bg-coolgray-100 bg-white overflow-y-auto scrollbar pb-4;
}
.toast {

View File

@@ -1,18 +1,15 @@
<x-layout-simple>
<div class="flex items-center justify-center h-screen">
<div>
<div class="flex flex-col items-center pb-8">
<a href="{{ route('dashboard') }}">
<div class="text-5xl font-bold tracking-tight text-center dark:text-white">Coolify</div>
</a>
{{-- <x-version /> --}}
<section class="bg-gray-50 dark:bg-base">
<div class="flex flex-col items-center justify-center px-6 py-8 mx-auto md:h-screen lg:py-0">
<a class="flex items-center mb-1 text-5xl font-extrabold tracking-tight text-gray-900 dark:text-white">
Coolify
</a> <div class="flex items-center gap-2">
{{ __('auth.forgot_password') }}
</div>
<div class="flex items-center gap-2">
<h1>{{ __('auth.forgot_password') }}</h1>
</div>
<div>
@if (is_transactional_emails_active())
<div
class="w-full bg-white shadow md:mt-0 sm:max-w-md xl:p-0 dark:bg-base ">
<div class="p-6 space-y-4 md:space-y-6 sm:p-8">
@if (is_transactional_emails_active())
<form action="/forgot-password" method="POST" class="flex flex-col gap-2">
@csrf
<x-forms.input required type="email" name="email" label="{{ __('input.email') }}" autofocus />
@@ -37,7 +34,9 @@
{{ session('status') }}
</div>
@endif
</div>
</div>
</div>
</div>
</section>
</x-layout-simple>

View File

@@ -1,5 +1,5 @@
<div class="grid grid-cols-1 gap-4 md:grid-cols-3">
<div class="box-border col-span-2 lg:min-w-[24rem] min-h-[21rem]">
<div class="box-border col-span-2 lg:min-w-[24rem] lg:min-h-[21rem]">
<h1 class="text-2xl font-bold lg:text-5xl">{{ $title }}</h1>
<div class="py-6">
@isset($question)
@@ -16,7 +16,7 @@
</div>
@isset($explanation)
<div class="col-span-1">
<h1 class="pb-8 font-bold">Explanation</h1>
<h3 class="pb-8 font-bold">Explanation</h3>
<div class="space-y-4">
{{ $explanation }}
</div>

View File

@@ -2,11 +2,11 @@
dropdownOpen: false
}" class="relative" @click.outside="dropdownOpen = false">
<button @click="dropdownOpen=true"
class="inline-flex items-center justify-start pr-10 transition-colors focus:outline-none disabled:opacity-50 disabled:pointer-events-none">
class="inline-flex items-center justify-start pr-8 transition-colors focus:outline-none disabled:opacity-50 disabled:pointer-events-none">
<span class="flex flex-col items-start h-full leading-none">
{{ $title }}
</span>
<svg class="absolute right-0 w-5 h-5 mr-3" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"
<svg class="absolute right-0 w-4 h-4 mr-3" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"
stroke-width="1.5" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round"
d="M8.25 15L12 18.75 15.75 15m-7.5-6L12 5.25 15.75 9" />
@@ -16,7 +16,7 @@
<div x-show="dropdownOpen" @click.away="dropdownOpen=false" x-transition:enter="ease-out duration-200"
x-transition:enter-start="-translate-y-2" x-transition:enter-end="translate-y-0"
class="absolute top-0 z-50 mt-6 min-w-max" x-cloak>
<div class="p-1 mt-1 border dark:bg-coolgray-200 bg-neutral-200 dark:border-black border-neutral-300">
<div class="p-1 mt-1 bg-white border rounded shadow dark:bg-coolgray-200 dark:border-black border-neutral-300">
{{ $slot }}
</div>
</div>

View File

@@ -1,4 +1,4 @@
<svg class="inline-flex w-3 h-3 ml-1 text-black dark:text-white" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"
<svg class="inline-flex w-3 h-3 ml-1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"
focusable="false" viewBox="0 0 24 24">
<path d="M0 0h24v24H0V0z" fill="none">
</path>

Before

Width:  |  Height:  |  Size: 317 B

After

Width:  |  Height:  |  Size: 290 B

View File

@@ -10,6 +10,6 @@
{{ $slot }}
@if ($attributes->whereStartsWith('wire:click')->first())
<x-loading wire:target="{{ $attributes->whereStartsWith('wire:click')->first() }}" wire:loading.delay />
<x-loading-on-button wire:target="{{ $attributes->whereStartsWith('wire:click')->first() }}" wire:loading.delay />
@endif
</button>

View File

@@ -0,0 +1,13 @@
@props(['text' => null])
<div class="inline-flex items-center justify-center" {{ $attributes }}>
@if (isset($text))
<div>{{ $text }}</div>
@endif
<svg class="w-4 h-4 mx-1 ml-3 text-warning animate-spin" xmlns="http://www.w3.org/2000/svg" fill="none"
viewBox="0 0 24 24">
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
<path class="opacity-75" fill="currentColor"
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z">
</path>
</svg>
</div>

View File

@@ -23,28 +23,28 @@
<template x-teleport="body">
<div x-show="modalOpen" class="fixed top-0 left-0 lg:px-0 px-4 z-[99] flex items-center justify-center w-screen h-screen"
x-cloak>
<div x-show="modalOpen" x-transition:enter="ease-out duration-100" x-transition:enter-start="opacity-0"
<div x-show="modalOpen" x-transition:enter="ease-out duration-100" x-transition:enter-start="opacity-0"
x-transition:enter-end="opacity-100" x-transition:leave="ease-in duration-100"
x-transition:leave-start="opacity-100" x-transition:leave-end="opacity-0"
class="absolute inset-0 w-full h-full bg-black bg-opacity-20 backdrop-blur-sm"></div>
<div x-show="modalOpen" x-trap.inert.noscroll="modalOpen" x-transition:enter="ease-out duration-100"
<div x-show="modalOpen" x-trap.inert.noscroll="modalOpen" @click.outside="modalOpen=false" x-transition:enter="ease-out duration-100"
x-transition:enter-start="opacity-0 -translate-y-2 sm:scale-95"
x-transition:enter-end="opacity-100 translate-y-0 sm:scale-100"
x-transition:leave="ease-in duration-100"
x-transition:leave-start="opacity-100 translate-y-0 sm:scale-100"
x-transition:leave-end="opacity-0 -translate-y-2 sm:scale-95"
class="relative w-full py-6 border rounded min-w-full lg:min-w-[36rem] max-w-fit bg-neutral-100 border-neutral-400 dark:bg-base px-7 dark:border-coolgray-300">
class="relative w-full py-6 border rounded drop-shadow min-w-full lg:min-w-[36rem] max-w-fit bg-white border-neutral-200 dark:bg-base px-6 dark:border-coolgray-300">
<div class="flex items-center justify-between pb-3">
<h3 class="text-2xl font-bold">{{ $title }}</h3>
<button @click="modalOpen=false"
class="absolute top-0 right-0 flex items-center justify-center w-8 h-8 mt-5 mr-5 rounded-full dark:text-white hover:bg-coolgray-300">
class="absolute top-0 right-0 flex items-center justify-center w-8 h-8 mt-5 mr-5 rounded-full dark:text-white hover:bg-neutral-100 dark:hover:bg-coolgray-300">
<svg class="w-5 h-5" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"
stroke-width="1.5" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12" />
</svg>
</button>
</div>
<div class="relative flex items-center justify-center w-auto pb-4">
<div class="relative flex items-center justify-center w-auto">
{{ $slot }}
</div>
</div>

View File

@@ -1,10 +1,84 @@
<nav class="flex flex-col flex-1 pl-2 bg-white border-r dark:border-coolgray-200 dark:bg-base">
<div class="flex w-full pt-6 pb-4 pl-3">
<div class="flex flex-col">
<nav class="flex flex-col flex-1 pl-2 bg-white border-r dark:border-coolgray-200 dark:bg-base" x-data="{
switchWidth() {
if (this.full === 'full') {
localStorage.removeItem('pageWidth');
} else {
localStorage.setItem('pageWidth', 'full');
}
window.location.reload();
},
init() {
this.full = localStorage.getItem('pageWidth');
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', e => {
const userSettings = localStorage.getItem('theme');
if (userSettings !== 'system') {
return;
}
if (e.matches) {
document.documentElement.classList.add('dark');
} else {
document.documentElement.classList.remove('dark');
}
});
this.queryTheme();
},
setTheme(type) {
this.theme = type;
localStorage.setItem('theme', type);
this.queryTheme();
},
queryTheme() {
const darkModePreference = window.matchMedia('(prefers-color-scheme: dark)').matches;
const userSettings = localStorage.getItem('theme') || 'dark';
localStorage.setItem('theme', userSettings);
if (userSettings === 'dark') {
document.documentElement.classList.add('dark');
this.theme = 'dark';
} else if (userSettings === 'light') {
document.documentElement.classList.remove('dark');
this.theme = 'light';
} else if (darkModePreference) {
this.theme = 'system';
document.documentElement.classList.add('dark');
} else if (!darkModePreference) {
this.theme = 'system';
document.documentElement.classList.remove('dark');
}
}
}">
<div class="flex pt-6 pb-4 pl-3">
<div class="flex flex-col w-full">
<div class="text-2xl font-bold tracking-wide dark:text-white">Coolify</div>
<x-version />
</div>
{{-- <button onclick="changeTheme()">Dark/light</button> --}}
<div class="pt-1">
<x-dropdown>
<x-slot:title>
<div class="flex justify-end w-8" x-show="theme === 'dark' || theme === 'system'">
<svg class="w-5 h-5 rounded dark:fill-white" xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24">
<path
d="M5.64,17l-.71.71a1,1,0,0,0,0,1.41,1,1,0,0,0,1.41,0l.71-.71A1,1,0,0,0,5.64,17ZM5,12a1,1,0,0,0-1-1H3a1,1,0,0,0,0,2H4A1,1,0,0,0,5,12Zm7-7a1,1,0,0,0,1-1V3a1,1,0,0,0-2,0V4A1,1,0,0,0,12,5ZM5.64,7.05a1,1,0,0,0,.7.29,1,1,0,0,0,.71-.29,1,1,0,0,0,0-1.41l-.71-.71A1,1,0,0,0,4.93,6.34Zm12,.29a1,1,0,0,0,.7-.29l.71-.71a1,1,0,1,0-1.41-1.41L17,5.64a1,1,0,0,0,0,1.41A1,1,0,0,0,17.66,7.34ZM21,11H20a1,1,0,0,0,0,2h1a1,1,0,0,0,0-2Zm-9,8a1,1,0,0,0-1,1v1a1,1,0,0,0,2,0V20A1,1,0,0,0,12,19ZM18.36,17A1,1,0,0,0,17,18.36l.71.71a1,1,0,0,0,1.41,0,1,1,0,0,0,0-1.41ZM12,6.5A5.5,5.5,0,1,0,17.5,12,5.51,5.51,0,0,0,12,6.5Zm0,9A3.5,3.5,0,1,1,15.5,12,3.5,3.5,0,0,1,12,15.5Z" />
</svg>
</div>
<div class="flex justify-end w-8" x-show="theme === 'light'">
<svg class="w-5 h-5" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
<path
d="M21.64,13a1,1,0,0,0-1.05-.14,8.05,8.05,0,0,1-3.37.73A8.15,8.15,0,0,1,9.08,5.49a8.59,8.59,0,0,1,.25-2A1,1,0,0,0,8,2.36,10.14,10.14,0,1,0,22,14.05,1,1,0,0,0,21.64,13Zm-9.5,6.69A8.14,8.14,0,0,1,7.08,5.22v.27A10.15,10.15,0,0,0,17.22,15.63a9.79,9.79,0,0,0,2.1-.22A8.11,8.11,0,0,1,12.14,19.73Z" />
</svg>
</div>
</x-slot:title>
<div class="flex flex-col gap-1">
<div class="mb-1 font-bold border-b dark:border-coolgray-500 dark:text-white text-md">Color</div>
<button @click="setTheme('dark')" class="px-1 dropdown-item-no-padding">Dark</button>
<button @click="setTheme('light')" class="px-1 dropdown-item-no-padding">Light</button>
<button @click="setTheme('system')" class="px-1 dropdown-item-no-padding">System</button>
<div class="my-1 font-bold border-b dark:border-coolgray-500 dark:text-white text-md">Width</div>
<button @click="switchWidth()" class="px-1 dropdown-item-no-padding" x-show="full">Center</button>
<button @click="switchWidth()" class="px-1 dropdown-item-no-padding" x-show="!full">Full</button>
</div>
</x-dropdown>
</div>
</div>
<div class="px-2 pt-2 pb-7">
<livewire:switch-team />
@@ -111,8 +185,8 @@
class="{{ request()->is('tags*') ? 'menu-item-active menu-item' : 'menu-item' }}"
href="{{ route('tags.index') }}">
<svg class="icon" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<g fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"
stroke-width="2">
<g fill="none" stroke="currentColor" stroke-linecap="round"
stroke-linejoin="round" stroke-width="2">
<path
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" />
<path d="m18 19l1.592-1.592a4.82 4.82 0 0 0 0-6.816L15 6m-8 4h-.01" />

View File

@@ -6,7 +6,8 @@
x-transition:enter-start="translate-y-full" x-transition:enter-end="translate-y-0"
x-transition:leave="transition ease-in duration-300" x-transition:leave-start="translate-y-0"
x-transition:leave-end="translate-y-full" x-init="setTimeout(() => { bannerVisible = true }, bannerVisibleAfter);"
class="fixed bottom-0 right-0 w-full h-auto duration-300 ease-out sm:px-5 sm:pb-5 sm:w-[26rem] lg:w-full z-[999]" x-cloak>
class="fixed bottom-0 right-0 w-full h-auto duration-300 ease-out sm:px-5 sm:pb-5 sm:w-[26rem] lg:w-full z-[999]"
x-cloak>
<div
class="flex flex-col items-center justify-between w-full h-full max-w-4xl p-6 mx-auto bg-white border shadow-lg lg:border-t dark:border-coolgray-300 dark:bg-coolgray-100 lg:p-8 lg:flex-row sm:rounded">
<div
@@ -27,7 +28,7 @@
@if ($buttonText->attributes->whereStartsWith('@click')->first()) @click="bannerVisible=false;{{ $buttonText->attributes->get('@click') }}"
@else
@click="bannerVisible=false;" @endif
class="inline-flex items-center justify-center flex-shrink-0 w-1/2 px-4 py-2 text-sm font-medium tracking-wide transition-colors duration-200 bg-white rounded-md dark:bg-coolgray-200 lg:w-auto dark:text-neutral-200 dark:hover:bg-coolgray-300 focus:shadow-outline focus:outline-none">
class="inline-flex items-center justify-center flex-shrink-0 w-1/2 px-4 py-2 text-sm font-medium tracking-wide transition-colors duration-200 rounded-md bg-neutral-100 hover:bg-neutral-200 dark:bg-coolgray-200 lg:w-auto dark:text-neutral-200 dark:hover:bg-coolgray-300 focus:shadow-outline focus:outline-none">
{{ $buttonText }}
</button>
</div>

View File

@@ -8,13 +8,13 @@
class="grid grid-cols-2 p-1 text-xs font-semibold leading-5 text-center rounded dark:text-white gap-x-1 bg-white/5">
<legend class="sr-only">Payment frequency</legend>
<label class="cursor-pointer rounded px-2.5 py-1"
:class="selected === 'monthly' ? 'bg-coollabs-100 dark:text-white' : ''">
:class="selected === 'monthly' ? 'bg-coollabs-100 text-white' : ''">
<input type="radio" x-on:click="selected = 'monthly'" name="frequency" value="monthly"
class="sr-only">
<span>Monthly</span>
</label>
<label class="cursor-pointer rounded px-2.5 py-1"
:class="selected === 'yearly' ? 'bg-coollabs-100 dark:text-white' : ''">
:class="selected === 'yearly' ? 'bg-coollabs-100 text-white' : ''">
<input type="radio" x-on:click="selected = 'yearly'" name="frequency" value="annually"
class="sr-only">
<span>Annually</span>
@@ -27,7 +27,7 @@
days trial</span> included on all plans, without credit card details.</div>
@endif
<div x-show="selected === 'monthly'" class="flex justify-center h-10 mt-3 text-sm leading-6 ">
<div>Save <span class="font-bold dark:text-warning">10%</span> annually with the yearly plans.
<div>Save <span class="font-bold text-black dark:text-warning">10%</span> annually with the yearly plans.
</div>
</div>
<div x-show="selected === 'yearly'" class="flex justify-center h-10 mt-3 text-sm leading-6 ">

View File

@@ -1,7 +1,7 @@
<div @class([
'transition-all duration-150 box-without-bg dark:bg-coolgray-100 bg-white group border-l-2 border-transparent',
'hover:border-coollabs cursor-pointer' => !$upgrade,
'hover:border-red-500 cursor-not-allowed' => $upgrade,
'transition-all duration-150 box-without-bg dark:bg-coolgray-100 bg-white group',
'hover:border-l-coollabs cursor-pointer' => !$upgrade,
'hover:border-l-red-500 cursor-not-allowed' => $upgrade,
]) @if (!$upgrade) wire:click={{ $wire }} @endif>
<div class="flex items-center">
{{ $logo }}

View File

@@ -8,7 +8,7 @@
<x-status.stopped :status="$resource->status" />
@endif
@if (!str($resource->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 dark:hover:fill-white fill-coollabs dark:fill-warning">
<svg class="w-4 h-4" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<path
d="M12 2a10.016 10.016 0 0 0-7 2.877V3a1 1 0 1 0-2 0v4.5a1 1 0 0 0 1 1h4.5a1 1 0 0 0 0-2H6.218A7.98 7.98 0 0 1 20 12a1 1 0 0 0 2 0A10.012 10.012 0 0 0 12 2zm7.989 13.5h-4.5a1 1 0 0 0 0 2h2.293A7.98 7.98 0 0 1 4 12a1 1 0 0 0-2 0a9.986 9.986 0 0 0 16.989 7.133V21a1 1 0 0 0 2 0v-4.5a1 1 0 0 0-1-1z" />

View File

@@ -1,2 +1,2 @@
<a {{ $attributes->merge(['class' => 'text-xs cursor-pointer opacity-90 hover:opacity-100 dark:hover:text-white hover:text-black z-[60]']) }}
<a {{ $attributes->merge(['class' => 'text-xs cursor-pointer opacity-90 hover:opacity-100 dark:hover:text-white hover:text-black']) }}
href="https://github.com/coollabsio/coolify/releases/tag/v{{ config('version') }}">v{{ config('version') }}</a>

View File

@@ -8,29 +8,30 @@
@endif
</div>
<div class="subtitle">Network endpoints to deploy your resources.</div>
<div class="grid gap-2 lg:grid-cols-2">
<div class="grid gap-2 lg:grid-cols-1">
@forelse ($destinations as $destination)
@if ($destination->getMorphClass() === 'App\Models\StandaloneDocker')
<a class="flex gap-4 text-center hover:no-underline box group"
<div class="box group">
<a class="flex flex-col mx-6"
href="{{ route('destination.show', ['destination_uuid' => data_get($destination, 'uuid')]) }}">
<div class="group-hover:dark:text-white">
<div>{{ $destination->name }}</div>
</div>
<div class="box-title">{{ $destination->name }}</div>
<div class="box-description">server: {{ $destination->server->name }}</div>
</a>
</div>
@endif
@if ($destination->getMorphClass() === 'App\Models\SwarmDocker')
<a class="flex gap-4 text-center hover:no-underline box group"
<div class="box group">
<a class="flex flex-col mx-6"
href="{{ route('destination.show', ['destination_uuid' => data_get($destination, 'uuid')]) }}">
<div class="group-hover:dark:text-white">
<div>{{ $destination->name }}</div>
</div>
<div class="box-title">{{ $destination->name }}</div>
<div class="box-description">server: {{ $destination->server->name }}</div>
</a>
</div>
@endif
@empty
<div>
@if ($servers->count() === 0)
<div> No servers found. Please add one first.</div>
<div>No servers found. Please add one first.</div>
@else
<div>No destinations found.</div>
@endif

View File

@@ -1,7 +1,7 @@
<x-emails.layout>
Your server ({{ $name }}) has high disk usage ({{ $disk_usage }}% used). Threshold is {{ $threshold }}%.
Please cleanup your disk to prevent data-loss. Here are some [tips](https://coolify.io/docs/automated-cleanup).
Please cleanup your disk to prevent data-loss. Here are some [tips](https://coolify.io/docs/knowledge-base/server/automated-cleanup).
(You can change the threshold in the Server Settings menu.)
</x-emails.layout>

View File

@@ -1,20 +1,18 @@
@extends('layouts.base')
<div class="min-h-screen hero">
<div class="text-center hero-content">
<div class="">
<p class="font-mono text-6xl font-semibold dark:text-warning">401</p>
<h1 class="mt-4 font-bold tracking-tight dark:text-white">You shall not pass!</h1>
<p class="mt-6 text-base leading-7 text-neutral-300">You don't have permission to access this page.
</p>
<div class="flex items-center justify-center mt-10 gap-x-6">
<a href="/">
<x-forms.button>Go back home</x-forms.button>
</a>
<a target="_blank" class="text-xs" href="{{ config('coolify.contact') }}">Contact
support
<x-external-link />
</a>
</div>
<div class="flex flex-col items-center justify-center h-full">
<div>
<p class="font-mono font-semibold text-7xl dark:text-warning">401</p>
<h1 class="mt-4 font-bold tracking-tight dark:text-white">You shall not pass!</h1>
<p class="text-base leading-7 text-neutral-300">You don't have permission to access this page.
</p>
<div class="flex items-center mt-10 gap-x-6">
<a href="/">
<x-forms.button>Go back home</x-forms.button>
</a>
<a target="_blank" class="text-xs" href="{{ config('coolify.contact') }}">Contact
support
<x-external-link />
</a>
</div>
</div>
</div>

View File

@@ -1,5 +1,17 @@
@extends('errors::minimal')
@extends('layouts.base')
@section('title', __('Payment Required'))
@section('code', '402')
@section('message', __('Payment Required'))
<div class="flex flex-col items-center justify-center h-full">
<div>
<p class="font-mono font-semibold text-7xl dark:text-warning">402</p>
<h1 class="mt-4 font-bold tracking-tight dark:text-white">Payment required.</h1>
<div class="flex items-center mt-10 gap-x-6">
<a href="/">
<x-forms.button>Go back home</x-forms.button>
</a>
<a target="_blank" class="text-xs" href="{{ config('coolify.contact') }}">Contact
support
<x-external-link />
</a>
</div>
</div>
</div>

View File

@@ -1,20 +1,18 @@
@extends('layouts.base')
<div class="min-h-screen hero">
<div class="text-center hero-content">
<div class="">
<p class="font-mono text-6xl font-semibold dark:text-warning">403</p>
<h1 class="mt-4 font-bold tracking-tight dark:text-white">You shall not pass!</h1>
<p class="mt-6 text-base leading-7 text-neutral-300">You don't have permission to access this page.
</p>
<div class="flex items-center justify-center mt-10 gap-x-6">
<a href="/">
<x-forms.button>Go back home</x-forms.button>
</a>
<a target="_blank" class="text-xs" href="{{ config('coolify.contact') }}">Contact
support
<x-external-link />
</a>
</div>
<div class="flex flex-col items-center justify-center h-full">
<div>
<p class="font-mono font-semibold text-7xl dark:text-warning">403</p>
<h1 class="mt-4 font-bold tracking-tight dark:text-white">You shall not pass!</h1>
<p class="text-base leading-7 text-neutral-300">You don't have permission to access this page.
</p>
<div class="flex items-center mt-10 gap-x-6">
<a href="/">
<x-forms.button>Go back home</x-forms.button>
</a>
<a target="_blank" class="text-xs" href="{{ config('coolify.contact') }}">Contact
support
<x-external-link />
</a>
</div>
</div>
</div>

View File

@@ -1,21 +1,19 @@
@extends('layouts.base')
<div class="min-h-screen hero">
<div class="text-center hero-content">
<div class="">
<p class="font-mono text-6xl font-semibold dark:text-warning">404</p>
<h1 class="mt-4 font-bold tracking-tight dark:text-white">How did you got here?</h1>
<p class="mt-6 text-base leading-7 text-neutral-300">Sorry, we couldnt find the page youre looking
for.
</p>
<div class="flex items-center justify-center mt-10 gap-x-6">
<a href="/">
<x-forms.button>Go back home</x-forms.button>
</a>
<a target="_blank" class="text-xs" href="{{ config('coolify.contact') }}">Contact
support
<x-external-link />
</a>
</div>
<div class="flex flex-col items-center justify-center h-full">
<div>
<p class="font-mono font-semibold text-7xl dark:text-warning">404</p>
<h1 class="mt-4 font-bold tracking-tight dark:text-white">How did you got here?</h1>
<p class="text-base leading-7 text-neutral-300">Sorry, we couldnt find the page youre looking
for.
</p>
<div class="flex items-center mt-10 gap-x-6">
<a href="/">
<x-forms.button>Go back home</x-forms.button>
</a>
<a target="_blank" class="text-xs" href="{{ config('coolify.contact') }}">Contact
support
<x-external-link />
</a>
</div>
</div>
</div>

View File

@@ -1,20 +1,19 @@
@extends('layouts.base')
<div class="min-h-screen hero">
<div class="text-center hero-content">
<div class="">
<p class="font-mono text-6xl font-semibold dark:text-warning">419</p>
<h1 class="mt-4 font-bold tracking-tight dark:text-white">This page is definitely old, not like you!</h1>
<p class="mt-6 text-base leading-7 text-neutral-300">Sorry, we couldnt find the page youre looking
for.
</p>
<div class="flex items-center justify-center mt-10 gap-x-6">
<a href="/">
<x-forms.button>Go back home</x-forms.button>
</a>
<a href="{{ config('coolify.contact') }}" class="font-semibold dark:text-white ">Contact
support
<span aria-hidden="true">&rarr;</span></a>
</div>
<div class="flex flex-col items-center justify-center h-full">
<div>
<p class="font-mono font-semibold text-7xl dark:text-warning">419</p>
<h1 class="mt-4 font-bold tracking-tight dark:text-white">This page is definitely old, not like you!</h1>
<p class="text-base leading-7 text-neutral-300">Sorry, we couldnt find the page youre looking
for.
</p>
<div class="flex items-center mt-10 gap-x-6">
<a href="/">
<x-forms.button>Go back home</x-forms.button>
</a>
<a target="_blank" class="text-xs" href="{{ config('coolify.contact') }}">Contact
support
<x-external-link />
</a>
</div>
</div>
</div>

View File

@@ -1,20 +1,19 @@
@extends('layouts.base')
<div class="min-h-screen hero">
<div class="text-center hero-content">
<div class="">
<p class="font-mono text-6xl font-semibold dark:text-warning">429</p>
<h1 class="mt-4 font-bold tracking-tight dark:text-white">Woah, slow down there!</h1>
<p class="mt-6 text-base leading-7 text-neutral-300">You're making too many requests. Please wait a few
seconds before trying again.
</p>
<div class="flex items-center justify-center mt-10 gap-x-6">
<a href="/">
<x-forms.button>Go back home</x-forms.button>
</a>
<a href="{{ config('coolify.contact') }}" class="font-semibold dark:text-white ">Contact
support
<span aria-hidden="true">&rarr;</span></a>
</div>
<div class="flex flex-col items-center justify-center h-full">
<div>
<p class="font-mono font-semibold text-7xl dark:text-warning">429</p>
<h1 class="mt-4 font-bold tracking-tight dark:text-white">Woah, slow down there!</h1>
<p class="text-base leading-7 text-neutral-300">You're making too many requests. Please wait a few
seconds before trying again.
</p>
<div class="flex items-center mt-10 gap-x-6">
<a href="/">
<x-forms.button>Go back home</x-forms.button>
</a>
<a target="_blank" class="text-xs" href="{{ config('coolify.contact') }}">Contact
support
<x-external-link />
</a>
</div>
</div>
</div>

View File

@@ -1,23 +1,22 @@
@extends('layouts.base')
<div class="min-h-screen hero ">
<div class="text-center hero-content">
<div>
<p class="font-mono text-6xl font-semibold dark:text-warning">500</p>
<h1 class="mt-4 font-bold tracking-tight dark:text-white">Something is not okay, are you okay?</h1>
<p class="mt-6 text-base leading-7 text-neutral-300">There has been an error, we are working on it.
</p>
@if ($exception->getMessage() !== '')
<code class="mt-6 text-xs text-left text-red-500">Error: {{ $exception->getMessage() }}
</code>
@endif
<div class="flex items-center justify-center mt-10 gap-x-6">
<a href="/">
<x-forms.button>Go back home</x-forms.button>
</a>
<a href="{{ config('coolify.contact') }}" class="font-semibold dark:text-white">Contact
support
<span aria-hidden="true">&rarr;</span></a>
</div>
<div class="flex flex-col items-center justify-center h-full">
<div>
<p class="font-mono font-semibold text-red-500 text-7xl">500</p>
<h1 class="mt-4 font-bold tracking-tight dark:text-white">Something is not okay, are you okay?</h1>
<p class="text-base leading-7 text-neutral-300">There has been an error, we are working on it.
</p>
@if ($exception->getMessage() !== '')
<code class="mt-6 text-xs text-left text-red-500">Error: {{ $exception->getMessage() }}
</code>
@endif
<div class="flex items-center mt-10 gap-x-6">
<a href="/">
<x-forms.button>Go back home</x-forms.button>
</a>
<a target="_blank" class="text-xs" href="{{ config('coolify.contact') }}">Contact
support
<x-external-link />
</a>
</div>
</div>
</div>

View File

@@ -1,17 +1,16 @@
@extends('layouts.base')
<div class="min-h-screen hero ">
<div class="text-center hero-content">
<div>
<p class="font-mono text-6xl font-semibold dark:text-warning">503</p>
<h1 class="mt-4 font-bold tracking-tight dark:text-white">We are working on serious things.</h1>
<p class="mt-6 text-base leading-7 text-neutral-300">Service Unavailable. Be right back. Thanks for your
patience.
</p>
<div class="flex items-center justify-center mt-10 gap-x-6">
<a href="{{ config('coolify.contact') }}" class="font-semibold dark:text-white ">Contact
support
<span aria-hidden="true">&rarr;</span></a>
</div>
<div class="flex flex-col items-center justify-center h-full">
<div>
<p class="font-mono font-semibold text-7xl dark:text-warning">503</p>
<h1 class="mt-4 font-bold tracking-tight dark:text-white">We are working on serious things.</h1>
<p class="text-base leading-7 text-neutral-300">Service Unavailable. Be right back. Thanks for your
patience.
</p>
<div class="flex items-center mt-10 gap-x-6">
<a target="_blank" class="text-xs" href="{{ config('coolify.contact') }}">Contact
support
<x-external-link />
</a>
</div>
</div>
</div>

View File

@@ -5,10 +5,12 @@
<livewire:layout-popups />
@endif
@auth
<livewire:realtime-connection />
@endauth
@auth
<div x-data="{ open: false }" x-cloak class="mx-auto max-w-7xl">
<div x-data="{
open: false,
init() {
this.pageWidth = localStorage.getItem('pageWidth');
}
}" x-cloak class="mx-auto" :class="pageWidth === 'full' ? '' : 'max-w-7xl'">
<div class="relative z-50 lg:hidden" :class="open ? 'block' : 'hidden'" role="dialog" aria-modal="true">
<div class="fixed inset-0 bg-black/80"></div>
<div class="fixed inset-0 flex">
@@ -53,7 +55,7 @@
</a> --}}
</div>
<main class="lg:pl-48" >
<main class="lg:pl-48">
<div class="p-4 sm:px-6 lg:px-8 lg:py-6">
{{ $slot }}
</div>

View File

@@ -40,20 +40,15 @@
<body>
<x-toast />
<script data-navigate-once>
if (localStorage.theme === 'dark' || (!('theme' in localStorage) && window.matchMedia(
'(prefers-color-scheme: dark)').matches)) {
if (localStorage.theme === 'dark') {
document.documentElement.classList.add('dark')
} else {
} else if (localStorage.theme === 'light') {
document.documentElement.classList.remove('dark')
}
function changeTheme() {
if (localStorage.theme === 'dark') {
localStorage.theme = 'light'
document.documentElement.classList.remove('dark')
} else {
localStorage.theme = 'dark'
} else {
if (window.matchMedia('(prefers-color-scheme: dark)').matches) {
document.documentElement.classList.add('dark')
} else {
document.documentElement.classList.remove('dark')
}
}
@auth
@@ -87,10 +82,12 @@
if (element.nodeName === 'INPUT' || element.nodeName === 'TEXTAREA') {
if (element.type === 'password') {
element.type = 'text';
if (element.disabled) return;
element.classList.add('truncate');
this.type = 'text';
} else {
element.type = 'password';
if (element.disabled) return;
element.classList.remove('truncate');
this.type = 'password';
}

View File

@@ -1,6 +1,6 @@
@extends('layouts.base')
@section('body')
<main class="h-full bg-gray-50 dark:bg-base">
<main class="h-full">
{{ $slot }}
</main>
@parent

View File

@@ -10,7 +10,7 @@
</div>
@endif
<div
class="flex flex-col-reverse w-full px-4 py-2 overflow-y-auto dark:text-white border border-solid rounded bg-coolgray-100 scrollbar border-coolgray-300 max-h-96">
class="flex flex-col-reverse w-full px-4 py-2 overflow-y-auto bg-white border border-solid rounded dark:text-white dark:bg-coolgray-100 scrollbar border-neutral-300 dark:border-coolgray-300 max-h-96">
<pre class="font-mono whitespace-pre-wrap" @if ($isPollingActive) wire:poll.1000ms="polling" @endif>{{ RunRemoteProcess::decodeOutput($this->activity) }}</pre>
</div>
@else

View File

@@ -1,11 +1,11 @@
@php use App\Enums\ProxyTypes; @endphp
<section class="flex flex-col h-full lg:items-center lg:justify-center">
<div class="flex flex-col items-center justify-center px-6 py-8 mx-auto max-w-7xl lg:py-0">
<div class="flex flex-col items-center justify-center p-10 mx-2 mt-10 bg-white border rounded-lg shadow lg:p-20 dark:bg-transparent dark:border-none max-w-7xl ">
@if ($currentState === 'welcome')
<h1 class="text-3xl font-bold lg:text-5xl">Welcome to Coolify</h1>
<p class="py-6 text-base text-center lg:text-xl">Let me help you set up the basics.</p>
<div class="py-6 text-center lg:text-xl">Let me help you set up the basics.</div>
<div class="flex justify-center ">
<x-forms.button class="justify-center w-64 box" wire:click="$set('currentState','explanation')">Get
<x-forms.button class="justify-center w-64 box-boarding" wire:click="$set('currentState','explanation')">Get
Started
</x-forms.button>
</div>
@@ -33,7 +33,7 @@
Telegram, Email, etc.) when something goes wrong, or an action is needed from your side.</p>
</x-slot:explanation>
<x-slot:actions>
<x-forms.button class="justify-center lg:w-64 box" wire:click="explanation">Next
<x-forms.button class="justify-center lg:w-64 box-boarding" wire:click="explanation">Next
</x-forms.button>
</x-slot:actions>
</x-boarding-step>
@@ -44,11 +44,11 @@
or to a <x-highlighted text="Remote Server" />?
</x-slot:question>
<x-slot:actions>
<x-forms.button class="justify-center w-64 box" wire:target="setServerType('localhost')"
<x-forms.button class="justify-center w-64 box-boarding" wire:target="setServerType('localhost')"
wire:click="setServerType('localhost')">Localhost
</x-forms.button>
<x-forms.button class="justify-center w-64 box " wire:target="setServerType('remote')"
<x-forms.button class="justify-center w-64 box-boarding " wire:target="setServerType('remote')"
wire:click="setServerType('remote')">Remote Server
</x-forms.button>
@if (!$serverReachable)
@@ -60,9 +60,9 @@
server.
<br />
Check this <a target="_blank" class="underline"
href="https://coolify.io/docs/server/openssh">documentation</a> for further help.
href="https://coolify.io/docs/knowledge-base/server/openssh">documentation</a> for further help.
<x-forms.input readonly id="serverPublicKey"></x-forms.input>
<x-forms.button class="lg:w-64 box" wire:target="setServerType('localhost')"
<x-forms.button class="lg:w-64 box-boarding" wire:target="setServerType('localhost')"
wire:click="setServerType('localhost')">Check again
</x-forms.button>
@endif
@@ -85,10 +85,10 @@
Do you have your own SSH Private Key?
</x-slot:question>
<x-slot:actions>
<x-forms.button class="justify-center lg:w-64 box" wire:target="setPrivateKey('own')"
<x-forms.button class="justify-center lg:w-64 box-boarding" wire:target="setPrivateKey('own')"
wire:click="setPrivateKey('own')">Yes
</x-forms.button>
<x-forms.button class="justify-center lg:w-64 box" wire:target="setPrivateKey('create')"
<x-forms.button class="justify-center lg:w-64 box-boarding" wire:target="setPrivateKey('create')"
wire:click="setPrivateKey('create')">No (create one for me)
</x-forms.button>
@if (count($privateKeys) > 0)
@@ -120,7 +120,7 @@
<x-slot:actions>
<div class="flex flex-col gap-4">
<div>
<x-forms.button class="justify-center w-64 box" wire:click="createNewServer">No (create
<x-forms.button class="justify-center w-64 box-boarding" wire:click="createNewServer">No (create
one
for
me)
@@ -146,7 +146,7 @@
'root' or skip the boarding process and add a new private key manually to Coolify and to the
server.
<x-forms.input readonly id="serverPublicKey"></x-forms.input>
<x-forms.button class="w-64 box" wire:target="validateServer" wire:click="validateServer">Check
<x-forms.button class="w-64 box-boarding" wire:target="validateServer" wire:click="validateServer">Check
again
</x-forms.button>
@endif
@@ -236,7 +236,7 @@
<x-slot:content>
<livewire:server.validate-and-install :server="$this->createdServer" />
</x-slot:content>
<x-forms.button @click="slideOverOpen=true" class="w-full font-bold box lg:w-96"
<x-forms.button @click="slideOverOpen=true" class="w-full font-bold box-boarding lg:w-96"
wire:click.prevent='installServer' isHighlighted>
Let's do it!
</x-forms.button>
@@ -263,7 +263,7 @@
@endif
</x-slot:question>
<x-slot:actions>
<x-forms.button class="justify-center w-64 box" wire:click="createNewProject">Create new
<x-forms.button class="justify-center w-64 box-boarding" wire:click="createNewProject">Create new
project!</x-forms.button>
<div>
@if (count($projects) > 0)
@@ -292,7 +292,7 @@
Let's go to the new resource page, where you can create your first resource.
</x-slot:question>
<x-slot:actions>
<div class="items-center justify-center w-64 box" wire:click="showNewResource">Let's do
<div class="items-center justify-center w-64 box-boarding" wire:click="showNewResource">Let's do
it!</div>
</x-slot:actions>
<x-slot:explanation>

View File

@@ -21,21 +21,20 @@
@foreach ($projects as $project)
<div class="gap-2 border border-transparent cursor-pointer box group">
@if (data_get($project, 'environments')->count() === 1)
<a class="flex flex-col flex-1 mx-6 hover:no-underline"
<a class="flex flex-col justify-center flex-1 mx-6"
href="{{ route('project.resource.index', ['project_uuid' => data_get($project, 'uuid'), 'environment_name' => data_get($project, 'environments.0.name', 'production')]) }}">
<div class="box-title">{{ $project->name }}</div>
<div class="box-description">
{{ $project->description }}</div>
<div class="box-description"> {{ $project->description }}</div>
</a>
@else
<a class="flex flex-col flex-1 mx-6 hover:no-underline"
<a class="flex flex-col justify-center flex-1 mx-6"
href="{{ route('project.show', ['project_uuid' => data_get($project, 'uuid')]) }}">
<div class="box-title">{{ $project->name }}</div>
<div class="box-description">
{{ $project->description }}</div>
</a>
@endif
<div class="flex items-center justify-center gap-2 pt-4 pb-2 mr-4 lg:py-0 lg:justify-normal">
<div class="flex items-center justify-center gap-2 pt-4 pb-2 mr-4 text-xs lg:py-0 lg:justify-normal">
<a class="hover:underline"
href="{{ route('project.resource.create', ['project_uuid' => data_get($project, 'uuid'), 'environment_name' => data_get($project, 'environments.0.name', 'production')]) }}">
<span class="p-2 font-bold">+
@@ -71,7 +70,7 @@
'border-transparent' => $server->settings->is_reachable,
'border-red-500' => !$server->settings->is_reachable,
])>
<div class="flex flex-col mx-6">
<div class="flex flex-col justify-center mx-6">
<div class="box-title">
{{ $server->name }}
</div>
@@ -79,13 +78,13 @@
{{ $server->description }}</div>
<div class="flex gap-1 text-xs text-error">
@if (!$server->settings->is_reachable)
<span>Not reachable</span>
Not reachable
@endif
@if (!$server->settings->is_reachable && !$server->settings->is_usable)
&
@endif
@if (!$server->settings->is_usable)
<span>Not usable by Coolify</span>
Not usable by Coolify
@endif
</div>
</div>
@@ -137,7 +136,7 @@
'dark:border-coolgray-300' => data_get($deployment, 'status') === 'queued',
'border-yellow-500' => data_get($deployment, 'status') === 'in_progress',
])>
<div class="flex flex-col mx-6">
<div class="flex flex-col justify-center mx-6">
<div class="box-title">
{{ data_get($deployment, 'application_name') }}
</div>

View File

@@ -1,13 +1,52 @@
<div x-data="{
popups: {
sponsorship: true,
notification: true
notification: true,
realtime: false,
},
init() {
this.popups.sponsorship = localStorage.getItem('popupSponsorship') !== 'false';
this.popups.notification = localStorage.getItem('popupNotification') !== 'false';
this.popups.realtime = localStorage.getItem('popupRealtime');
let checkNumber = 1;
let checkPusherInterval = null;
if (!this.popups.realtime) {
checkPusherInterval = setInterval(() => {
if (window.Echo && window.Echo.connector.pusher.connection.state !== 'connected') {
checkNumber++;
if (checkNumber > 4) {
this.popups.realtime = true;
console.error(
'Coolify could not connect to its real-time service. This will cause unusual problems on the UI if not fixed! Please check the related documentation (https://coolify.io/docs/knowledge-base/cloudflare/tunnels) or get help on Discord (https://coollabs.io/discord).)'
);
clearInterval(checkPusherInterval);
}
}
}, 1000);
}
}
}">
@auth
<span x-show="popups.realtime === true">
<x-popup>
<x-slot:title>
<span class="font-bold text-left text-red-500">WARNING: </span>Realtime Error?!
</x-slot:title>
<x-slot:description>
<span>Coolify could not connect to its real-time service.<br>This will cause unusual problems on the UI
if
not fixed! <br><br>Please check the
related <a class="underline" href='https://coolify.io/docs/knowledge-base/cloudflare/tunnels'
target='_blank'>documentation</a> or get
help on <a class="underline" href='https://coollabs.io/discord' target='_blank'>Discord</a>. </span>
</x-slot:description>
<x-slot:button-text @click="disableRealtime()">
Acknowledge & Disable This Popup
</x-slot:button-text>
</x-popup>
</span>
@endauth
<span x-show="popups.sponsorship">
<x-popup>
<x-slot:title>
@@ -20,8 +59,9 @@
<x-slot:description>
<span>Please
consider donating on <a href="https://github.com/sponsors/coollabsio"
class="text-xs dark:text-white underline">GitHub</a> or <a href="https://opencollective.com/coollabsio"
class="text-xs dark:text-white underline">OpenCollective</a>.<br><br></span>
class="text-xs underline dark:text-white">GitHub</a> or <a
href="https://opencollective.com/coollabsio"
class="text-xs underline dark:text-white">OpenCollective</a>.<br><br></span>
<span>It enables us to keep creating features without paywalls, ensuring our work remains free and
open.</span>
</x-slot:description>
@@ -35,7 +75,8 @@
<div><span class="font-bold text-red-500">WARNING:</span> The number of active servers exceeds the limit
covered by your payment. If not resolved, some of your servers <span class="font-bold text-red-500">will
be deactivated</span>. Visit <a href="{{ route('subscription.show') }}"
class="dark:text-white underline">/subscription</a> to update your subscription or remove some servers.
class="underline dark:text-white">/subscription</a> to update your subscription or remove some
servers.
</div>
</x-banner>
@endif
@@ -57,7 +98,7 @@
highly recommended to enable at least
one
notification channel to receive important alerts.<br>Visit <a
href="{{ route('notifications.email') }}" class="dark:text-white underline">/notification</a> to
href="{{ route('notifications.email') }}" class="underline dark:text-white">/notification</a> to
enable notifications.</span>
</x-slot:description>
<x-slot:button-text @click="disableNotification()">
@@ -70,8 +111,13 @@
function disableSponsorship() {
localStorage.setItem('popupSponsorship', false);
}
function disableNotification() {
localStorage.setItem('popupNotification', false);
}
function disableRealtime() {
localStorage.setItem('popupRealtime', 'disabled');
}
</script>
</div>

View File

@@ -18,8 +18,10 @@
</div>
<div class="flex flex-col gap-2">
<x-forms.input id="current_password" label="Current Password" required type="password" />
<div class="flex gap-2">
<x-forms.input id="new_password" label="New Password" required type="password" />
<x-forms.input id="new_password_confirmation" label="New Password Again" required type="password" />
</div>
</div>
</form>
<h2 class="py-4">Two-factor Authentication</h2>

View File

@@ -27,18 +27,17 @@
@endif
@forelse ($deployments as $deployment)
<a @class([
'dark:bg-coolgray-100 p-2 border-l border-dashed transition-colors hover:no-underline',
'dark:bg-coolgray-100 p-2 border-l border-dashed transition-colors hover:no-underline box-without-bg bg-white',
'dark:hover:bg-coolgray-200' =>
data_get($deployment, 'status') === 'queued',
'border-warning hover:bg-warning hover:text-black' =>
data_get($deployment, 'status') === 'in_progress' ||
data_get($deployment, 'status') === 'cancelled-by-user',
'border-error hover:bg-error' =>
'border-error dark:hover:bg-error hover:bg-neutral-200' =>
data_get($deployment, 'status') === 'failed',
'border-success hover:bg-success' =>
'border-success dark:hover:bg-success hover:bg-neutral-200' =>
data_get($deployment, 'status') === 'finished',
]) href="{{ $current_url . '/' . data_get($deployment, 'deployment_uuid') }}"
class="hover:no-underline">
]) href="{{ $current_url . '/' . data_get($deployment, 'deployment_uuid') }}">
<div class="flex flex-col justify-start">
<div class="flex gap-1">
{{ $deployment->created_at }} UTC

View File

@@ -1,11 +1,45 @@
<div>
<h1 class="py-0">Deployment</h1>
<livewire:project.application.heading :application="$application" />
<div class="pt-4" x-data="{ fullscreen: false, alwaysScroll: false, intervalId: null }">
<div class="pt-4" x-data="{
fullscreen: false,
alwaysScroll: false,
intervalId: null,
makeFullscreen() {
this.fullscreen = !this.fullscreen;
if (this.fullscreen === false) {
this.alwaysScroll = false;
clearInterval(this.intervalId);
}
},
toggleScroll() {
this.alwaysScroll = !this.alwaysScroll;
if (this.alwaysScroll) {
this.intervalId = setInterval(() => {
const screen = document.getElementById('screen');
const logs = document.getElementById('logs');
if (screen.scrollTop !== logs.scrollHeight) {
screen.scrollTop = logs.scrollHeight;
}
}, 100);
} else {
clearInterval(this.intervalId);
this.intervalId = null;
}
},
goTop() {
this.alwaysScroll = false;
clearInterval(this.intervalId);
const screen = document.getElementById('screen');
screen.scrollTop = 0;
}
}">
<livewire:project.application.deployment-navbar :application_deployment_queue="$application_deployment_queue" />
@if (data_get($application_deployment_queue, 'status') === 'in_progress')
<div class="flex items-center gap-1 pt-2 ">Deployment is
<div class="dark:text-warning"> {{ Str::headline(data_get($this->application_deployment_queue, 'status')) }}.
<div class="dark:text-warning">
{{ Str::headline(data_get($this->application_deployment_queue, 'status')) }}.
</div>
<x-loading class="loading-ring" />
</div>
@@ -17,7 +51,7 @@
@endif
<div id="screen" :class="fullscreen ? 'fullscreen' : ''">
<div @if ($isKeepAliveOn) wire:poll.2000ms="polling" @endif
class="relative flex flex-col-reverse w-full p-2 px-4 mt-4 overflow-y-auto dark:text-white bg-coolgray-100 scrollbar border-coolgray-300"
class="relative flex flex-col-reverse w-full p-2 px-4 mt-4 overflow-y-auto bg-white dark:text-white dark:bg-coolgray-100 scrollbar dark:border-coolgray-300"
:class="fullscreen ? '' : 'max-h-[40rem] border border-dotted rounded'">
<button title="Minimize" x-show="fullscreen" class="fixed top-4 right-4"
x-on:click="makeFullscreen"><svg class="icon" viewBox="0 0 24 24"
@@ -58,7 +92,11 @@
<br>COMMAND: <br>{{ $line['command'] }} <br><br>OUTPUT:
@endif @if (str($line['output'])->contains('http://') || str($line['output'])->contains('https://'))
@php
$line['output'] = preg_replace('/(https?:\/\/[^\s]+)/', '<a href="$1" target="_blank" class="underline text-neutral-400">$1</a>', $line['output']);
$line['output'] = preg_replace(
'/(https?:\/\/[^\s]+)/',
'<a href="$1" target="_blank" class="underline text-neutral-400">$1</a>',
$line['output'],
);
@endphp {!! $line['output'] !!}
@else
{{ $line['output'] }}
@@ -71,39 +109,5 @@
</div>
</div>
</div>
<script>
function makeFullscreen() {
this.fullscreen = !this.fullscreen;
if (this.fullscreen === false) {
this.alwaysScroll = false;
clearInterval(this.intervalId);
}
}
function toggleScroll() {
this.alwaysScroll = !this.alwaysScroll;
if (this.alwaysScroll) {
this.intervalId = setInterval(() => {
const screen = document.getElementById('screen');
const logs = document.getElementById('logs');
if (screen.scrollTop !== logs.scrollHeight) {
screen.scrollTop = logs.scrollHeight;
}
}, 100);
} else {
clearInterval(this.intervalId);
this.intervalId = null;
}
}
function goTop() {
this.alwaysScroll = false;
clearInterval(this.intervalId);
const screen = document.getElementById('screen');
screen.scrollTop = 0;
}
</script>
</div>
</div>

View File

@@ -48,10 +48,10 @@
<div class="w-96">
<x-forms.checkbox instantSave id="application.settings.is_raw_compose_deployment_enabled"
label="Raw Compose Deployment"
helper="WARNING: Advanced use cases only. Your docker compose file will be deployed as-is. Nothing is modified by Coolify. You need to configure the proxy parts. More info in the <a href='https://coolify.io/docs/docker/compose#raw-docker-compose-deployment'>documentation.</a>" />
helper="WARNING: Advanced use cases only. Your docker compose file will be deployed as-is. Nothing is modified by Coolify. You need to configure the proxy parts. More info in the <a href='https://coolify.io/docs/knowledge-base/docker/compose#raw-docker-compose-deployment'>documentation.</a>" />
</div>
@if (count($parsedServices) > 0 && !$application->settings->is_raw_compose_deployment_enabled)
<h3>Domains</h3>
<h3>Domains</h3>
@foreach (data_get($parsedServices, 'services') as $serviceName => $service)
@if (!isDatabaseImage(data_get($service, 'image')))
<div class="flex items-end gap-2">
@@ -78,19 +78,19 @@
</x-forms.button>
</div>
@endif
@if ($application->build_pack !== 'dockercompose')
<div class="flex items-center gap-2 pt-8">
<h3>Docker Registry</h3>
@if ($application->build_pack !== 'dockerimage' && !$application->destination->server->isSwarm())
<x-helper
helper='Push the built image to a docker registry. More info <a class="underline"
href="https://coolify.io/docs/docker/registry" target="_blank">here</a>' />
helper="Push the built image to a docker registry. More info <a class='underline' href='https://coolify.io/docs/knowledge-base/docker/registry' target='_blank'>here</a>." />
@endif
</div>
@if ($application->destination->server->isSwarm())
@if ($application->build_pack !== 'dockerimage')
<div>Docker Swarm requires the image to be available in a registry. More info <a
class="underline" href="https://coolify.io/docs/docker/registry"
class="underline" href="https://coolify.io/docs/knowledge-base/docker/registry"
target="_blank">here</a>.</div>
@endif
@endif
@@ -132,7 +132,7 @@
@if ($application->build_pack !== 'dockercompose')
<div class="w-96">
<x-forms.checkbox
helper="Use a build server to build your application. You can configure your build server in the Server settings. This is experimental. For more info, check the <a href='https://coolify.io/docs/server/build-server' class='underline' target='_blank'>documentation</a>."
helper="Use a build server to build your application. You can configure your build server in the Server settings. This is experimental. For more info, check the <a href='https://coolify.io/docs/knowledge-base/server/build-server' class='underline' target='_blank'>documentation</a>."
instantSave id="application.settings.is_build_server_enabled"
label="Use a Build Server? (experimental)" />
</div>
@@ -148,7 +148,7 @@
id="application.start_command" label="Start Command" />
</div>
<div>Nixpacks will detect the required configuration automatically.
<a class="underline" href="https://coolify.io/docs/frameworks/">Framework Specific Docs</a>
<a class="underline" href="https://coolify.io/docs/resources/introduction">Framework Specific Docs</a>
</div>
@endif
@endif
@@ -206,13 +206,13 @@
know what are
you doing.</div>
<x-forms.input
helper="You can add custom docker run options that will be used when your container is started.<br>Note: Not all options are supported, as they could mess up Coolify's automation and could cause bad experience for users.<br><br>Check the <a class='underline dark:text-white' href='https://coolify.io/docs/custom-docker-options'>docs.</a>"
helper="You can add custom docker run options that will be used when your container is started.<br>Note: Not all options are supported, as they could mess up Coolify's automation and could cause bad experience for users.<br><br>Check the <a class='underline dark:text-white' href='https://coolify.io/docs/knowledge-base/docker/custom-commands'>docs.</a>"
placeholder="--cap-add SYS_ADMIN --device=/dev/fuse --security-opt apparmor:unconfined --ulimit nofile=1024:1024 --tmpfs /run:rw,noexec,nosuid,size=65536k"
id="application.custom_docker_run_options" label="Custom Docker Options" />
@endif
@else
<x-forms.input
helper="You can add custom docker run options that will be used when your container is started.<br>Note: Not all options are supported, as they could mess up Coolify's automation and could cause bad experience for users.<br><br>Check the <a class='underline dark:text-white' href='https://coolify.io/docs/custom-docker-options'>docs.</a>"
helper="You can add custom docker run options that will be used when your container is started.<br>Note: Not all options are supported, as they could mess up Coolify's automation and could cause bad experience for users.<br><br>Check the <a class='underline dark:text-white' href='https://coolify.io/docs/knowledge-base/docker/custom-commands'>docs.</a>"
placeholder="--cap-add SYS_ADMIN --device=/dev/fuse --security-opt apparmor:unconfined --ulimit nofile=1024:1024 --tmpfs /run:rw,noexec,nosuid,size=65536k"
id="application.custom_docker_run_options" label="Custom Docker Options" />
@endif

View File

@@ -57,7 +57,7 @@
<div class="pb-4">Previews</div>
<div class="flex flex-wrap gap-6">
@foreach ($application->previews as $preview)
<div class="flex flex-col p-4 bg-coolgray-200">
<div class="flex flex-col p-4 dark:bg-coolgray-200">
<div class="flex gap-2">PR #{{ data_get($preview, 'pull_request_id') }} |
@if (Str::of(data_get($preview, 'status'))->startsWith('running'))
<x-status.running :status="data_get($preview, 'status')" />
@@ -78,7 +78,7 @@
</a>
</div>
<div class="flex items-center gap-2 pt-6">
<x-forms.button class="bg-coolgray-500"
<x-forms.button class="dark:bg-coolgray-500"
wire:click="deploy({{ data_get($preview, 'pull_request_id') }})">
@if (data_get($preview, 'status') === 'exited')
Deploy
@@ -88,17 +88,17 @@
</x-forms.button>
<a
href="{{ route('project.application.deployment.index', [...$parameters, 'pull_request_id' => data_get($preview, 'pull_request_id')]) }}">
<x-forms.button class="bg-coolgray-500">
<x-forms.button class="dark:bg-coolgray-500">
Deployment Logs
</x-forms.button>
</a>
<a
href="{{ route('project.application.logs', [...$parameters, 'pull_request_id' => data_get($preview, 'pull_request_id')]) }}">
<x-forms.button class="bg-coolgray-500">
<x-forms.button class="dark:bg-coolgray-500">
Application Logs
</x-forms.button>
</a>
<x-forms.button isError class="bg-coolgray-500"
<x-forms.button isError class="dark:bg-coolgray-500"
wire:click="stop({{ data_get($preview, 'pull_request_id') }})">Delete
</x-forms.button>
</div>

View File

@@ -9,7 +9,7 @@
<div class="flex flex-wrap">
@forelse ($images as $image)
<div class="w-2/4 p-2">
<div class="rounded shadow-lg bg-coolgray-100">
<div class="bg-white border rounded dark:border-bg-black dark:bg-coolgray-100">
<div class="p-2">
<div class="">
@if (data_get($image, 'is_current'))

View File

@@ -15,8 +15,8 @@
<div class="pt-4 pb-2">Docker Networks</div>
<div class="grid grid-cols-1 gap-2 pb-4 lg:grid-cols-4">
@foreach ($server->destinations() as $destination)
<div class="cursor-pointer box-without-bg bg-coolgray-200 group"
:class="'{{ $selectedDestination === $destination->id }}' && 'bg-coollabs dark:text-white'"
<div class="cursor-pointer box-without-bg group"
:class="'{{ $selectedDestination === $destination->id }}' ? 'bg-coollabs text-white' : 'dark:bg-coolgray-100 bg-white'"
wire:click="selectServer('{{ $server->id }}', '{{ $destination->id }}')">
{{ $destination->name }}
</div>
@@ -30,7 +30,7 @@
<div>These will be cloned to the new project</div>
<div class="grid grid-cols-1 gap-2 pt-4 opacity-95 lg:grid-cols-2 xl:grid-cols-3">
@foreach ($environment->applications->sortBy('name') as $application)
<div class="cursor-default box-without-bg bg-coolgray-100 group">
<div class="bg-white cursor-default box-without-bg dark:bg-coolgray-100 group">
<div class="flex flex-col">
<div class="font-bold dark:text-white">{{ $application->name }}</div>
<div class="description">{{ $application->description }}</div>
@@ -38,7 +38,7 @@
</div>
@endforeach
@foreach ($environment->databases()->sortBy('name') as $database)
<div class="cursor-default box-without-bg bg-coolgray-100 group">
<div class="bg-white cursor-default box-without-bg dark:bg-coolgray-100 group">
<div class="flex flex-col">
<div class="font-bold dark:text-white">{{ $database->name }}</div>
<div class="description">{{ $database->description }}</div>
@@ -46,7 +46,7 @@
</div>
@endforeach
@foreach ($environment->services->sortBy('name') as $service)
<div class="cursor-default box-without-bg bg-coolgray-100 group">
<div class="bg-white cursor-default box-without-bg dark:bg-coolgray-100 group">
<div class="flex flex-col">
<div class="font-bold dark:text-white">{{ $service->name }}</div>
<div class="description">{{ $service->description }}</div>

View File

@@ -11,14 +11,16 @@
</a>
</div>
@else
<div @class([
'border-coollabs' =>
data_get($backup, 'id') === data_get($selectedBackup, 'id'),
'flex flex-col box border-l-2 border-transparent',
]) wire:click="setSelectedBackup('{{ data_get($backup, 'id') }}')">
<div>Frequency: {{ $backup->frequency }}</div>
<div>Last backup: {{ data_get($backup->latest_log, 'status', 'No backup yet') }}</div>
<div>Number of backups to keep (locally): {{ $backup->number_of_backups_locally }}</div>
<div class="box">
<div @class([
'border-coollabs' =>
data_get($backup, 'id') === data_get($selectedBackup, 'id'),
'flex flex-col border-l-2 border-transparent',
]) wire:click="setSelectedBackup('{{ data_get($backup, 'id') }}')">
<div>Frequency: {{ $backup->frequency }}</div>
<div>Last backup: {{ data_get($backup->latest_log, 'status', 'No backup yet') }}</div>
<div>Number of backups to keep (locally): {{ $backup->number_of_backups_locally }}</div>
</div>
</div>
@endif
@empty

View File

@@ -24,7 +24,7 @@
<div>You can use these variables anywhere with</div>
<div class=" dark:text-warning text-coollabs">@{{ project.VARIABLENAME }} </div>
<x-helper
helper="More info <a class='underline dark:text-white' href='https://coolify.io/docs/environment-variables#shared-variables' target='_blank'>here</a>."></x-helper>
helper="More info <a class='underline dark:text-white' href='https://coolify.io/docs/knowledge-base/environment-variables#shared-variables' target='_blank'>here</a>."></x-helper>
</div>
<div class="flex flex-col gap-2">
@forelse ($project->environment_variables->sort()->sortBy('real_value') as $env)

View File

@@ -48,8 +48,8 @@
<livewire:project.shared.environment-variable.add />
</x-modal-input>
</div>
<div class="flex items-center gap-2 pb-4">You can use these variables anywhere with <span class="dark:text-warning">@{{environment.VARIABLENAME}}</span><x-helper
helper="More info <a class='underline dark:text-white' href='https://coolify.io/docs/environment-variables#shared-variables' target='_blank'>here</a>."></x-helper>
<div class="flex items-center gap-2 pb-4">You can use these variables anywhere with <span class="dark:text-warning text-coollabs">@{{environment.VARIABLENAME}}</span><x-helper
helper="More info <a class='underline dark:text-white' href='https://coolify.io/docs/knowledge-base/environment-variables#shared-variables' target='_blank'>here</a>."></x-helper>
</div>
<div class="flex flex-col gap-2">
@forelse ($environment->environment_variables->sort()->sortBy('real_value') as $env)

View File

@@ -10,13 +10,13 @@
@forelse ($projects as $project)
<div class="box group" x-data
x-on:click="goto('{{ $project->uuid }}')">
<a class="flex flex-col flex-1 mx-6 hover:no-underline"
<a class="flex flex-col justify-center flex-1 mx-6"
href="{{ route('project.show', ['project_uuid' => data_get($project, 'uuid')]) }}">
<div class="box-title">{{ $project->name }}</div>
<div class="box-description ">
{{ $project->description }}</div>
</a>
<div class="flex items-center">
<div class="flex items-center text-xs">
<a class="mx-4 font-bold hover:underline"
href="{{ route('project.edit', ['project_uuid' => data_get($project, 'uuid')]) }}">
Settings

View File

@@ -6,16 +6,7 @@
<h2>Docker Compose</h2>
<x-forms.button type="submit">Save</x-forms.button>
</div>
<x-forms.textarea label="Docker Compose file"
helper="
You can use these variables in your Docker Compose file and Coolify will generate default values or replace them with the values you set on the UI forms.<br>
<br>
- SERVICE_FQDN_*: FQDN - could be changeable from the UI. (example: SERVICE_FQDN_GHOST)<br>
- SERVICE_URL_*: URL parsed from FQDN - could be changeable from the UI. (example: SERVICE_URL_GHOST)<br>
- SERVICE_BASE64_64_*: Generated 'base64' string with length of '64' (example: SERVICE_BASE64_64_GHOST, to generate 32 bit: SERVICE_BASE64_32_GHOST)<br>
- SERVICE_USER_*: Generated user (example: SERVICE_USER_MYSQL)<br>
- SERVICE_PASSWORD_*: Generated password (example: SERVICE_PASSWORD_MYSQL)<br>"
rows="20" id="dockerComposeRaw"
<x-forms.textarea label="Docker Compose file" rows="20" id="dockerComposeRaw"
placeholder='services:
ghost:
documentation: https://ghost.org/docs/config
@@ -44,6 +35,5 @@
- MYSQL_DATABASE=${MYSQL_DATABASE}
- MYSQL_ROOT_PASSWORD=${SERVICE_PASSWORD_MYSQL_ROOT}
'></x-forms.textarea>
{{-- <x-forms.textarea label="Environment File" rows="20" id="envFile"></x-forms.textarea> --}}
</form>
</div>

File diff suppressed because one or more lines are too long

View File

@@ -72,10 +72,10 @@
</a>
<div class="flex gap-1 pt-1 group-hover:dark:text-white group-hover:text-black group min-h-6">
<template x-for="tag in item.tags">
<div class="px-2 py-1 cursor-pointer box-description dark:bg-coolgray-100 dark:hover:bg-coolgray-300 bg-neutral-100 hover:bg-neutral-200"
<div class="tag"
@click.prevent="gotoTag(tag.name)" x-text="tag.name"></div>
</template>
<div class="flex items-center px-2 text-xs cursor-pointer dark:text-neutral-500/20 text-neutral-500 group-hover:text-neutral-700 group-hover:dark:text-white dark:hover:bg-coolgray-300 hover:bg-neutral-200"
<div class="add-tag"
@click.prevent="goto(item)">Add tag</div>
</div>
</span>
@@ -104,10 +104,10 @@
</a>
<div class="flex gap-1 pt-1 group-hover:dark:text-white group-hover:text-black group min-h-6">
<template x-for="tag in item.tags">
<div class="px-2 py-1 cursor-pointer description bg-coolgray-100 hover:bg-coolgray-300"
<div class="tag"
@click.prevent="gotoTag(tag.name)" x-text="tag.name"></div>
</template>
<div class="flex items-center px-2 text-xs cursor-pointer text-neutral-500/20 group-hover:dark:text-white hover:bg-coolgray-300"
<div class="add-tag"
@click.prevent="goto(item)">Add tag</div>
</div>
</span>
@@ -136,10 +136,10 @@
</a>
<div class="flex gap-1 pt-1 group-hover:dark:text-white group min-h-6">
<template x-for="tag in item.tags">
<div class="px-2 py-1 cursor-pointer description bg-coolgray-100 hover:bg-coolgray-300"
<div class="tag"
@click.prevent="gotoTag(tag.name)" x-text="tag.name"></div>
</template>
<div class="flex items-center px-2 text-xs cursor-pointer text-neutral-500/20 group-hover:dark:text-white hover:bg-coolgray-300"
<div class="add-tag"
@click.prevent="goto(item)">Add tag</div>
</div>
</span>
@@ -168,10 +168,10 @@
</a>
<div class="flex gap-1 pt-1 group-hover:dark:text-white group min-h-6">
<template x-for="tag in item.tags">
<div class="px-2 py-1 cursor-pointer description bg-coolgray-100 hover:bg-coolgray-300"
<div class="tag"
@click.prevent="gotoTag(tag.name)" x-text="tag.name"></div>
</template>
<div class="flex items-center px-2 text-xs cursor-pointer text-neutral-500/20 group-hover:dark:text-white hover:bg-coolgray-300"
<div class="add-tag"
@click.prevent="goto(item)">Add tag</div>
</div>
</span>
@@ -200,10 +200,10 @@
</a>
<div class="flex gap-1 pt-1 group-hover:dark:text-white group min-h-6">
<template x-for="tag in item.tags">
<div class="px-2 py-1 cursor-pointer description bg-coolgray-100 hover:bg-coolgray-300"
<div class="tag"
@click.prevent="gotoTag(tag.name)" x-text="tag.name"></div>
</template>
<div class="flex items-center px-2 text-xs cursor-pointer text-neutral-500/20 group-hover:dark:text-white hover:bg-coolgray-300"
<div class="add-tag"
@click.prevent="goto(item)">Add tag</div>
</div>
</span>
@@ -232,10 +232,10 @@
</a>
<div class="flex gap-1 pt-1 group-hover:dark:text-white group min-h-6">
<template x-for="tag in item.tags">
<div class="px-2 py-1 cursor-pointer description bg-coolgray-100 hover:bg-coolgray-300"
<div class="tag"
@click.prevent="gotoTag(tag.name)" x-text="tag.name"></div>
</template>
<div class="flex items-center px-2 text-xs cursor-pointer text-neutral-500/20 group-hover:dark:text-white hover:bg-coolgray-300"
<div class="add-tag"
@click.prevent="goto(item)">Add tag</div>
</div>
</span>
@@ -264,10 +264,10 @@
</a>
<div class="flex gap-1 pt-1 group-hover:dark:text-white group min-h-6">
<template x-for="tag in item.tags">
<div class="px-2 py-1 cursor-pointer description bg-coolgray-100 hover:bg-coolgray-300"
<div class="tag"
@click.prevent="gotoTag(tag.name)" x-text="tag.name"></div>
</template>
<div class="flex items-center px-2 text-xs cursor-pointer text-neutral-500/20 group-hover:dark:text-white hover:bg-coolgray-300"
<div class="add-tag"
@click.prevent="goto(item)">Add tag</div>
</div>
</span>

View File

@@ -51,7 +51,7 @@
$application->status)->contains(['running']),
'border-l border-dashed border-warning' => Str::of(
$application->status)->contains(['starting']),
'flex gap-2 box-without-bg bg-coolgray-100 hover:text-neutral-300 group',
'flex gap-2 box-without-bg dark:bg-coolgray-100 bg-white dark:hover:text-neutral-300 group',
])>
<div class="flex flex-row w-full">
<div class="flex flex-col flex-1">
@@ -75,7 +75,7 @@
<div class="text-xs">{{ $application->status }}</div>
</div>
<div class="flex items-center px-4">
<a class="mx-4 font-bold hover:underline"
<a class="mx-4 text-xs font-bold hover:underline"
href="{{ route('project.service.index', [...$parameters, 'stack_service_uuid' => $application->uuid]) }}">
Settings
</a>
@@ -95,7 +95,7 @@
$database->status)->contains(['running']),
'border-l border-dashed border-warning' => Str::of(
$database->status)->contains(['restarting']),
'flex gap-2 box-without-bg bg-coolgray-100 hover:text-neutral-300 group',
'flex gap-2 box-without-bg dark:bg-coolgray-100 bg-white dark:hover:text-neutral-300 group',
])>
<div class="flex flex-row w-full">
<div class="flex flex-col flex-1">
@@ -116,7 +116,7 @@
<div class="text-xs">{{ $database->status }}</div>
</div>
<div class="flex items-center px-4">
<a class="mx-4 font-bold hover:underline"
<a class="mx-4 text-xs font-bold hover:underline"
href="{{ route('project.service.index', [...$parameters, 'stack_service_uuid' => $database->uuid]) }}">
Settings
</a>

View File

@@ -17,10 +17,9 @@
@click.prevent="activeTab = 'scheduled-tasks'; window.location.hash = 'scheduled-tasks'"
href="#">Scheduled Tasks
</a>
@if (
$serviceDatabase?->databaseType() === 'standalone-mysql' ||
$serviceDatabase?->databaseType() === 'standalone-postgresql' ||
$serviceDatabase?->databaseType() === 'standalone-mariadb')
@if (str($serviceDatabase?->databaseType())->contains('mysql') ||
str($serviceDatabase?->databaseType())->contains('postgres') ||
str($serviceDatabase?->databaseType())->contains('mariadb'))
<a :class="activeTab === 'backups' && 'dark:text-white'"
@click.prevent="activeTab = 'backups'; window.location.hash = 'backups'" href="#">Backups</a>
@endif

View File

@@ -15,7 +15,7 @@
</div>
<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='underline dark:text-white' target='_blank' href='https://coolify.io/docs/docker/compose#connect-to-predefined-networks'>this</a>." />
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='underline dark:text-white' target='_blank' href='https://coolify.io/docs/knowledge-base/docker/compose#connect-to-predefined-networks'>this</a>." />
</div>
@if ($fields)
<div>

View File

@@ -3,7 +3,7 @@
<div class="">Server related configurations.</div>
<div class="grid grid-cols-1 gap-4 py-4">
<div class="flex gap-2">
<div class="relative flex flex-col bg-white cursor-default dark:text-white box-without-bg dark:bg-coolgray-100 w-96">
<div class="relative flex flex-col bg-white border cursor-default dark:text-white box-without-bg dark:bg-coolgray-100 w-96 dark:border-black">
<div class="text-xl font-bold">Primary Server</div>
@if (str($resource->realStatus())->startsWith('running'))
<div title="{{ $resource->realStatus() }}" class="absolute bg-success -top-1 -left-1 badge ">

View File

@@ -1,5 +1,6 @@
<div>
<form wire:submit='submit' class="flex flex-col items-center gap-4 p-4 border lg:items-start dark:border-coolgray-300">
<form wire:submit='submit'
class="flex flex-col items-center gap-4 p-4 bg-white border lg:items-start dark:bg-base dark:border-coolgray-300">
@if ($isLocked)
<div class="flex flex-1 w-full gap-2">
<x-forms.input disabled id="env.key" />
@@ -12,7 +13,7 @@
</svg>
<x-modal-confirmation isErrorButton buttonTitle="Delete">
You will delete environment variable <span
class="font-bold dark:text-warning">{{ $env->key }}</span>.
class="font-bold dark:text-warning text-coollabs">{{ $env->key }}</span>.
</x-modal-confirmation>
</div>
@else
@@ -39,9 +40,15 @@
</div>
@endif
<div class="flex flex-col w-full gap-2 lg:flex-row">
@if ($type !== 'service' && !$isSharedVariable)
<x-forms.checkbox instantSave id="env.is_multiline" label="Is Multiline?" />
@if ($type === 'service')
<x-forms.checkbox instantSave id="env.is_build_time" label="Build Variable?" />
@else
@if ($env->is_shared)
<x-forms.checkbox instantSave id="env.is_build_time" label="Build Variable?" />
@else
<x-forms.checkbox instantSave id="env.is_multiline" label="Is Multiline?" />
<x-forms.checkbox instantSave id="env.is_build_time" label="Build Variable?" />
@endif
@endif
<div class="flex-1"></div>
@if ($isDisabled)

View File

@@ -1,5 +1,38 @@
<div>
<div x-init="$wire.getLogs" id="screen" x-data="{ fullscreen: false, alwaysScroll: false, intervalId: null }">
<div x-init="$wire.getLogs" id="screen" x-data="{
fullscreen: false,
alwaysScroll: false,
intervalId: null,
makeFullscreen() {
this.fullscreen = !this.fullscreen;
if (this.fullscreen === false) {
this.alwaysScroll = false;
clearInterval(this.intervalId);
}
},
toggleScroll() {
this.alwaysScroll = !this.alwaysScroll;
if (this.alwaysScroll) {
this.intervalId = setInterval(() => {
const screen = document.getElementById('screen');
const logs = document.getElementById('logs');
if (screen.scrollTop !== logs.scrollHeight) {
screen.scrollTop = logs.scrollHeight;
}
}, 100);
} else {
clearInterval(this.intervalId);
this.intervalId = null;
}
},
goTop() {
this.alwaysScroll = false;
clearInterval(this.intervalId);
const screen = document.getElementById('screen');
screen.scrollTop = 0;
}
}">
<div class="flex items-center gap-2">
@if ($resource?->type() === 'application')
<h3>{{ $container }}</h3>
@@ -24,7 +57,7 @@
<x-forms.checkbox instantSave label="Include Timestamps" id="showTimeStamps"></x-forms.checkbox>
</form>
<div :class="fullscreen ? 'fullscreen' : 'relative w-full py-4 mx-auto'">
<div class="flex flex-col-reverse w-full px-4 py-2 overflow-y-auto dark:text-white bg-coolgray-100 scrollbar border-coolgray-300"
<div class="flex flex-col-reverse w-full px-4 py-2 overflow-y-auto bg-white dark:text-white dark:bg-coolgray-100 scrollbar dark:border-coolgray-300"
:class="fullscreen ? '' : 'max-h-96 border border-solid rounded'">
<button title="Minimize" x-show="fullscreen" class="fixed top-4 right-4"
x-on:click="makeFullscreen"><svg class="icon" viewBox="0 0 24 24"
@@ -61,39 +94,5 @@
@endif
</div>
</div>
<script>
function makeFullscreen() {
this.fullscreen = !this.fullscreen;
if (this.fullscreen === false) {
this.alwaysScroll = false;
clearInterval(this.intervalId);
}
}
function toggleScroll() {
this.alwaysScroll = !this.alwaysScroll;
if (this.alwaysScroll) {
this.intervalId = setInterval(() => {
const screen = document.getElementById('screen');
const logs = document.getElementById('logs');
if (screen.scrollTop !== logs.scrollHeight) {
screen.scrollTop = logs.scrollHeight;
}
}, 100);
} else {
clearInterval(this.intervalId);
this.intervalId = null;
}
}
function goTop() {
this.alwaysScroll = false;
clearInterval(this.intervalId);
const screen = document.getElementById('screen');
screen.scrollTop = 0;
}
</script>
</div>
</div>

View File

@@ -14,9 +14,9 @@
<x-modal-confirmation action="cloneTo({{ data_get($destination, 'id') }})">
<x:slot name="content">
<div class="box">
<div class="flex flex-col gap-2 ">
<div class="font-bold dark:text-white">{{ $server->name }}</div>
<div>{{ $destination->name }}</div>
<div class="flex flex-col">
<div class="box-title">{{ $server->name }}</div>
<div class="box-description">{{ $destination->name }}</div>
</div>
</div>
</x:slot>
@@ -35,16 +35,16 @@
class="font-bold dark:text-warning">{{ $resource->environment->project->name }} /
{{ $resource->environment->name }}</span> environment.
</div>
<div class="grid gap-4">
<div class="flex flex-wrap gap-2">
@forelse ($projects as $project)
<div class="flex flex-row flex-wrap gap-2">
<div class="flex flex-wrap gap-2">
@foreach ($project->environments as $environment)
<x-modal-confirmation action="moveTo({{ data_get($environment, 'id') }})">
<x:slot name="content">
<div class="box">
<div class="flex flex-col gap-2 ">
<div class="font-bold dark:text-white">{{ $project->name }}</div>
<div><span class="dark:text-warning">{{ $environment->name }}</span> environment
<div class="flex flex-col">
<div class="box-title">{{ $project->name }}</div>
<div class="box-description">environment: {{ $environment->name }}
</div>
</div>
</div>

View File

@@ -2,11 +2,11 @@
<div class="flex items-center gap-2">
<h2>Webhooks</h2>
<x-helper
helper="For more details goto our <a class='dark:text-white underline' href='https://coolify.io/docs/api/deploy-webhook' target='_blank'>docs</a>." />
helper="For more details goto our <a class='underline dark:text-white' href='https://coolify.io/docs/api-reference/deploy-webhook' target='_blank'>docs</a>." />
</div>
<div>
<x-forms.input readonly
helper="See details in our <a target='_blank' class='dark:text-white underline' href='https://coolify.io/docs/api/authentication'>documentation</a>."
helper="See details in our <a target='_blank' class='underline dark:text-white' href='https://coolify.io/docs/api-reference/deploy-webhook'>documentation</a>."
label="Deploy Webhook (auth required)" id="deploywebhook"></x-forms.input>
</div>
@if ($resource->type() === 'application')

View File

@@ -17,7 +17,7 @@
<div class="description">
{{ $environment->description }}</div>
</a>
<div class="flex items-center">
<div class="flex items-center text-xs">
<a class="mx-4 font-bold hover:underline"
href="{{ route('project.environment.edit', ['project_uuid' => data_get($project, 'uuid'), 'environment_name' => $environment->name]) }}">
Settings

View File

@@ -1,48 +0,0 @@
<div x-data="{ showNotification: @entangle('showNotification') }">
@if ($checkConnection)
@script
<script>
let checkPusherInterval = null;
let checkNumber = 0;
checkPusherInterval = setInterval(() => {
if (window.Echo) {
if (window.Echo.connector.pusher.connection.state !== 'connected') {
checkNumber++;
if (checkNumber > 4) {
@if ($isNotificationEnabled)
$wire.showNotification = true;
@endif
console.error(
'Coolify could not connect to the new realtime service introduced in beta.154. This will cause unusual problems on the UI if not fixed! Please check the related documentation (https://coolify.io/docs/cloudflare/tunnels) or get help on Discord (https://coollabs.io/discord).)'
);
clearInterval(checkPusherInterval);
}
} else {
console.log('Coolify Realtime Service is connected!');
clearInterval(checkPusherInterval);
}
} else {
@if ($isNotificationEnabled)
$wire.showNotification = true;
@endif
console.error(
'Coolify could not connect to the new realtime service introduced in beta.154. This will cause unusual problems on the UI if not fixed! Please check the related documentation (https://coolify.io/docs/cloudflare/tunnels) or get help on Discord (https://coollabs.io/discord).)'
);
clearInterval(checkPusherInterval);
}
}, 1000);
</script>
@endscript
<div class="toast z-[9999]" x-cloak x-show="showNotification">
<div class="flex flex-col dark:text-white border border-red-500 border-dashed rounded alert-error bg-coolgray-200">
<span><span class="font-bold text-left text-red-500">WARNING: </span>Coolify could not connect to the new
realtime service introduced in beta.154. <br>This will cause unusual problems on the UI if not
fixed!<br><br>Please check the
related <a href='https://coolify.io/docs/cloudflare/tunnels' target='_blank'>documentation</a> or get
help on <a href='https://coollabs.io/discord' target='_blank'>Discord</a>.</span>
<x-forms.button class="bg-coolgray-400" wire:click='disable'>Acknowledge the problem and disable this
popup</x-forms.button>
</div>
</div>
@endif
</div>

View File

@@ -83,20 +83,20 @@
@endif
@if ($server->settings->is_swarm_worker)
<x-forms.checkbox disabled instantSave type="checkbox" id="server.settings.is_swarm_manager"
helper="For more information, please read the documentation <a class='dark:text-white' href='https://coolify.io/docs/docker/swarm' target='_blank'>here</a>."
helper="For more information, please read the documentation <a class='dark:text-white' href='https://coolify.io/docs/knowledge-base/docker/swarm' target='_blank'>here</a>."
label="Is it a Swarm Manager?" />
@else
<x-forms.checkbox instantSave type="checkbox" id="server.settings.is_swarm_manager"
helper="For more information, please read the documentation <a class='dark:text-white' href='https://coolify.io/docs/docker/swarm' target='_blank'>here</a>."
helper="For more information, please read the documentation <a class='dark:text-white' href='https://coolify.io/docs/knowledge-base/docker/swarm' target='_blank'>here</a>."
label="Is it a Swarm Manager?" />
@endif
@if ($server->settings->is_swarm_manager)
<x-forms.checkbox disabled instantSave type="checkbox" id="server.settings.is_swarm_worker"
helper="For more information, please read the documentation <a class='dark:text-white' href='https://coolify.io/docs/docker/swarm' target='_blank'>here</a>."
helper="For more information, please read the documentation <a class='dark:text-white' href='https://coolify.io/docs/knowledge-base/docker/swarm' target='_blank'>here</a>."
label="Is it a Swarm Worker?" />
@else
<x-forms.checkbox instantSave type="checkbox" id="server.settings.is_swarm_worker"
helper="For more information, please read the documentation <a class='dark:text-white' href='https://coolify.io/docs/docker/swarm' target='_blank'>here</a>."
helper="For more information, please read the documentation <a class='dark:text-white' href='https://coolify.io/docs/knowledge-base/docker/swarm' target='_blank'>here</a>."
label="Is it a Swarm Worker?" />
@endif
@endif

View File

@@ -18,7 +18,7 @@
'border-red-500' =>
!$server->settings->is_reachable || $server->settings->force_disabled,
])>
<div class="flex flex-col mx-6">
<div class="flex flex-col justify-center mx-6">
<div class="font-bold dark:text-white">
{{ $server->name }}
</div>

View File

@@ -29,24 +29,24 @@
<div class="">
<h3 class="pt-6">Swarm <span class="text-xs text-neutral-500">(experimental)</span></h3>
<div class="pb-4">Read the docs <a class='dark:text-white'
href='https://coolify.io/docs/docker/swarm#deploy-with-persistent-storage'
href='https://coolify.io/docs/knowledge-base/docker/swarm'
target='_blank'>here</a>.</div>
@if ($is_swarm_worker || $is_build_server)
<x-forms.checkbox disabled instantSave type="checkbox" id="is_swarm_manager"
helper="For more information, please read the documentation <a class='dark:text-white' href='https://coolify.io/docs/docker/swarm' target='_blank'>here</a>."
helper="For more information, please read the documentation <a class='dark:text-white' href='https://coolify.io/docs/knowledge-base/docker/swarm' target='_blank'>here</a>."
label="Is it a Swarm Manager?" />
@else
<x-forms.checkbox type="checkbox" instantSave id="is_swarm_manager"
helper="For more information, please read the documentation <a class='dark:text-white' href='https://coolify.io/docs/docker/swarm' target='_blank'>here</a>."
helper="For more information, please read the documentation <a class='dark:text-white' href='https://coolify.io/docs/knowledge-base/docker/swarm' target='_blank'>here</a>."
label="Is it a Swarm Manager?" />
@endif
@if ($is_swarm_manager|| $is_build_server)
<x-forms.checkbox disabled instantSave type="checkbox" id="is_swarm_worker"
helper="For more information, please read the documentation <a class='dark:text-white' href='https://coolify.io/docs/docker/swarm' target='_blank'>here</a>."
helper="For more information, please read the documentation <a class='dark:text-white' href='https://coolify.io/docs/knowledge-base/docker/swarm' target='_blank'>here</a>."
label="Is it a Swarm Worker?" />
@else
<x-forms.checkbox type="checkbox" instantSave id="is_swarm_worker"
helper="For more information, please read the documentation <a class='dark:text-white' href='https://coolify.io/docs/docker/swarm' target='_blank'>here</a>."
helper="For more information, please read the documentation <a class='dark:text-white' href='https://coolify.io/docs/knowledge-base/docker/swarm' target='_blank'>here</a>."
label="Is it a Swarm Worker?" />
@endif
@if ($is_swarm_worker && count($swarm_managers) > 0)

View File

@@ -17,8 +17,8 @@
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>Before switching proxies, please read <a class="dark:text-white underline"
href="https://coolify.io/docs/server/switching-proxies">this</a>.</div>
</svg>Before switching proxies, please read <a class="underline dark:text-white"
href="https://coolify.io/docs/knowledge-base/server/proxies#switch-between-proxies">this</a>.</div>
@if ($server->proxyType() === 'TRAEFIK_V2')
<div class="pb-4">Traefik v2</div>
@elseif ($server->proxyType() === 'CADDY')

View File

@@ -2,11 +2,7 @@
<div class="flex items-center gap-2">
<h2>Transactional Email</h2>
</div>
@if (isCloud())
<div class="pb-4 ">Email settings for password resets, invitations, shared with Pro+ subscribers etc.</div>
@else
<div class="pb-4 ">Email settings for password resets, invitations, etc.</div>
@endif
<div class="pb-4 ">Email settings for password resets, invitations, etc.</div>
<form wire:submit='submitFromFields' class="flex flex-col gap-2 pb-4">
<x-forms.input required id="settings.smtp_from_name" helper="Name used in emails." label="From Name" />
<x-forms.input required id="settings.smtp_from_address" helper="Email address used in emails."

View File

@@ -7,8 +7,8 @@
</x-modal-input>
</div>
<div class="flex items-center gap-2 pb-4">You can use these variables anywhere with <span
class="dark:text-warning">@{{ team.VARIABLENAME }}</span> <x-helper
helper="More info <a class='underline dark:text-white' href='https://coolify.io/docs/environment-variables#shared-variables' target='_blank'>here</a>."></x-helper>
class="dark:text-warning text-coollabs">@{{ team.VARIABLENAME }}</span> <x-helper
helper="More info <a class='underline dark:text-white' href='https://coolify.io/docs/knowledge-base/environment-variables#shared-variables' target='_blank'>here</a>."></x-helper>
</div>
<div class="flex flex-col gap-2">

View File

@@ -1,6 +1,6 @@
<tr @class([
'dark:text-white bg-coolblack hover:bg-coolgray-100',
'bg-coolgray-100' => $member->id == auth()->user()->id,
'dark:text-white text-black dark:bg-coolblack dark:hover:bg-coolgray-100',
'dark:bg-coolgray-100 bg-neutral-200' => $member->id == auth()->user()->id,
])>
<td class="px-5 py-4 text-sm whitespace-nowrap">
{{ $member->name }}

View File

@@ -7,7 +7,7 @@
<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">
<table class="min-w-full divide-y dark:divide-coolgray-400 divide-neutral-400">
<thead>
<tr>
<th class="px-5 py-3 text-xs font-medium text-left uppercase">Name
@@ -17,7 +17,7 @@
<th class="px-5 py-3 text-xs font-medium text-left uppercase">Actions</th>
</tr>
</thead>
<tbody class="divide-y divide-coolgray-400">
<tbody class="divide-y dark:divide-coolgray-400 divide-neutral-200">
@foreach (currentTeam()->members as $member)
<livewire:team.member :member="$member" :wire:key="$member->id" />
@endforeach

View File

@@ -12,10 +12,10 @@
@forelse ($s3 as $storage)
<div x-data x-on:click="goto('{{ $storage->uuid }}')" @class(['gap-2 border cursor-pointer box group border-transparent'])>
<div class="flex flex-col mx-6">
<div class=" group-hover:dark:text-white">
<div class="box-title">
{{ $storage->name }}
</div>
<div class="text-xs group-hover:dark:text-white">
<div class="box-description">
{{ $storage->description }}</div>
</div>
</div>

Some files were not shown because too many files have changed in this diff Show More