Merge pull request #1903 from coollabsio/next

v4.0.0-beta.246
This commit is contained in:
Andras Bacsai 2024-03-27 14:55:41 +01:00 committed by GitHub
commit d921456036
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
53 changed files with 323 additions and 298 deletions

View File

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

View File

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

View File

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

View File

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

View File

@ -30,5 +30,5 @@ ### 4) Start development
Mails are caught by Mailpit: `localhost:8025` Mails are caught by Mailpit: `localhost:8025`
## New Service Contribution ## 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 @@ public function handle(Server $server)
{ {
$supported_os_type = $server->validateOS(); $supported_os_type = $server->validateOS();
if (!$supported_os_type) { 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); ray('Installing Docker on server: ' . $server->name . ' (' . $server->ip . ')' . ' with OS type: ' . $supported_os_type);
$dockerVersion = '24.0'; $dockerVersion = '24.0';

View File

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

View File

@ -44,7 +44,7 @@ public function deploy(Request $request)
$force = $request->query->get('force') ?? false; $force = $request->query->get('force') ?? false;
if ($uuids && $tags) { 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)) { if (is_null($teamId)) {
return invalid_token(); return invalid_token();
@ -54,7 +54,7 @@ public function deploy(Request $request)
} else if ($uuids) { } else if ($uuids) {
return $this->by_uuids($uuids, $teamId, $force); 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) private function by_uuids(string $uuid, int $teamId, bool $force = false)
{ {
@ -62,7 +62,7 @@ private function by_uuids(string $uuid, int $teamId, bool $force = false)
$uuids = collect(array_filter($uuids)); $uuids = collect(array_filter($uuids));
if (count($uuids) === 0) { 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(); $deployments = collect();
$payload = collect(); $payload = collect();
@ -81,7 +81,7 @@ private function by_uuids(string $uuid, int $teamId, bool $force = false)
$payload->put('deployments', $deployments->toArray()); $payload->put('deployments', $deployments->toArray());
return response()->json($payload->toArray(), 200); 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) public function by_tags(string $tags, int $team_id, bool $force = false)
{ {
@ -89,7 +89,7 @@ public function by_tags(string $tags, int $team_id, bool $force = false)
$tags = collect(array_filter($tags)); $tags = collect(array_filter($tags));
if (count($tags) === 0) { 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([]); $message = collect([]);
$deployments = collect(); $deployments = collect();
@ -127,7 +127,7 @@ public function by_tags(string $tags, int $team_id, bool $force = false)
return response()->json($payload->toArray(), 200); 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 public function deploy_resource($resource, bool $force = false): array
{ {

View File

@ -26,7 +26,7 @@ public function team_by_id(Request $request)
$teams = auth()->user()->teams; $teams = auth()->user()->teams;
$team = $teams->where('id', $id)->first(); $team = $teams->where('id', $id)->first();
if (is_null($team)) { 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); return response()->json($team);
} }
@ -40,7 +40,7 @@ public function members_by_id(Request $request)
$teams = auth()->user()->teams; $teams = auth()->user()->teams;
$team = $teams->where('id', $id)->first(); $team = $teams->where('id', $id)->first();
if (is_null($team)) { 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); return response()->json($team->members);
} }

View File

@ -737,7 +737,7 @@ private function framework_based_notification()
$nixpacks_php_root_dir = $this->application->environment_variables_preview->where('key', 'NIXPACKS_PHP_ROOT_DIR')->first(); $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) { 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() private function rolling_update()

View File

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

View File

@ -23,6 +23,6 @@ public function __construct(private bool $force = false)
public function handle(): void public function handle(): void
{ {
UpdateCoolify::run($this->force); UpdateCoolify::run(force: $this->force, async: false);
} }
} }

View File

@ -251,7 +251,7 @@ public function submit($showToaster = true)
if ($this->application->additional_servers->count() === 0) { if ($this->application->additional_servers->count() === 0) {
foreach ($domains as $domain) { foreach ($domains as $domain) {
if (!validate_dns_entry($domain, $this->application->destination->server)) { if (!validate_dns_entry($domain, $this->application->destination->server)) {
$showToaster && $this->dispatch('error', "Validating DNS ($domain) failed.", "Make sure you have added the DNS records correctly.<br><br>Check this <a target='_blank' class='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 @@ public function deploy(bool $force_rebuild = false)
return; return;
} }
if (data_get($this->application, 'settings.is_build_server_enabled') && str($this->application->docker_registry_image_name)->isEmpty()) { if (data_get($this->application, 'settings.is_build_server_enabled') && str($this->application->docker_registry_image_name)->isEmpty()) {
$this->dispatch('error', 'Failed to deploy.', 'To use a build server, you must first set a Docker image.<br>More information here: <a target="_blank" class="underline" href="https://coolify.io/docs/server/build-server">documentation</a>'); $this->dispatch('error', 'Failed to deploy.', 'To use a build server, you must first set a Docker image.<br>More information here: <a target="_blank" class="underline" href="https://coolify.io/docs/knowledge-base/server/build-server">documentation</a>');
return; return;
} }
if ($this->application->additional_servers->count() > 0 && str($this->application->docker_registry_image_name)->isEmpty()) { if ($this->application->additional_servers->count() > 0 && str($this->application->docker_registry_image_name)->isEmpty()) {
$this->dispatch('error', 'Failed to deploy.', '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; return;
} }
$this->setDeploymentUuid(); $this->setDeploymentUuid();
@ -99,7 +99,7 @@ public function stop()
public function restart() public function restart()
{ {
if ($this->application->additional_servers->count() > 0 && str($this->application->docker_registry_image_name)->isEmpty()) { if ($this->application->additional_servers->count() > 0 && str($this->application->docker_registry_image_name)->isEmpty()) {
$this->dispatch('error', 'Failed to deploy', '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; return;
} }
$this->setDeploymentUuid(); $this->setDeploymentUuid();

View File

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

View File

@ -56,7 +56,7 @@ public function stop(int $server_id)
public function redeploy(int $network_id, int $server_id) public function redeploy(int $network_id, int $server_id)
{ {
if ($this->resource->additional_servers->count() > 0 && str($this->resource->docker_registry_image_name)->isEmpty()) { 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; return;
} }
$deployment_uuid = new Cuid2(7); $deployment_uuid = new Cuid2(7);

View File

@ -82,7 +82,7 @@ public function checkLocalhostConnection()
$this->server->settings->is_usable = true; $this->server->settings->is_usable = true;
$this->server->settings->save(); $this->server->settings->save();
} else { } 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; return;
} }
} }

View File

@ -39,7 +39,7 @@ public function checkConnection()
if ($uptime) { if ($uptime) {
$this->dispatch('success', 'Server is reachable.'); $this->dispatch('success', 'Server is reachable.');
} else { } 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; return;
} }
} catch (\Throwable $e) { } catch (\Throwable $e) {

View File

@ -75,7 +75,7 @@ public function validateConnection()
{ {
$this->uptime = $this->server->validateConnection(); $this->uptime = $this->server->validateConnection();
if (!$this->uptime) { 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; return;
} }
$this->dispatch('validateOS'); $this->dispatch('validateOS');

View File

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

View File

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

View File

@ -53,13 +53,13 @@ public function toMail(): MailMessage
public function toDiscord(): string 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; return $message;
} }
public function toTelegram(): array public function toTelegram(): array
{ {
return [ 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() 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); ray($error);
if ($error instanceof TooManyRequestsException) { if ($error instanceof TooManyRequestsException) {
if (isset($livewire)) { 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."; 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 (!$isDatabase) {
if ($savedService->fqdn) { if ($savedService->fqdn) {
$fqdn = $savedService->fqdn . ',' . $fqdn; data_set($savedService, 'fqdn', $savedService->fqdn . ',' . $fqdn);
} else { } else {
$fqdn = $fqdn; data_set($savedService, 'fqdn', $fqdn);
} }
$savedService->fqdn = $fqdn;
$savedService->save(); $savedService->save();
} }
EnvironmentVariable::create([ EnvironmentVariable::create([
@ -960,7 +959,6 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal
]); ]);
} }
// Caddy needs exact port in some cases. // Caddy needs exact port in some cases.
if ($predefinedPort && !$key->endsWith("_{$predefinedPort}")) { if ($predefinedPort && !$key->endsWith("_{$predefinedPort}")) {
if ($resource->server->proxyType() === 'CADDY') { if ($resource->server->proxyType() === 'CADDY') {
$env = EnvironmentVariable::where([ $env = EnvironmentVariable::where([
@ -1459,13 +1457,13 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal
])->first(); ])->first();
$value = Str::of(replaceVariables($value)); $value = Str::of(replaceVariables($value));
$key = $value; $key = $value;
if ($value->startsWith('SERVICE_')) { if ($value->startsWith('SERVICE_')) {
$foundEnv = EnvironmentVariable::where([ $foundEnv = EnvironmentVariable::where([
'key' => $key, 'key' => $key,
'application_id' => $resource->id, 'application_id' => $resource->id,
])->first(); ])->first();
['command' => $command, 'forService' => $forService, 'generatedValue' => $generatedValue, 'port' => $port] = parseEnvVariable($value); ['command' => $command, 'forService' => $forService, 'generatedValue' => $generatedValue, 'port' => $port] = parseEnvVariable($value);
ray($command, $generatedValue);
if (!is_null($command)) { if (!is_null($command)) {
if ($command?->value() === 'FQDN' || $command?->value() === 'URL') { if ($command?->value() === 'FQDN' || $command?->value() === 'URL') {
if (Str::lower($forService) === $serviceName) { if (Str::lower($forService) === $serviceName) {

View File

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

View File

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

View File

@ -198,16 +198,16 @@ .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-100 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 { .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; @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 { .on-box {
@apply rounded hover:bg-neutral-300 dark:hover:bg-coolgray-500/20; @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 { .box-title {
@apply font-bold text-black dark:text-white group-hover:dark:text-white; @apply font-bold text-black dark:text-white group-hover:dark:text-white;
@ -280,7 +280,7 @@ .subtitle {
} }
.fullscreen { .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 { .toast {

View File

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

View File

@ -1,5 +1,14 @@
<nav class="flex flex-col flex-1 pl-2 bg-white border-r dark:border-coolgray-200 dark:bg-base" x-data="{ <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() { init() {
this.full = localStorage.getItem('pageWidth');
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', e => { window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', e => {
const userSettings = localStorage.getItem('theme'); const userSettings = localStorage.getItem('theme');
if (userSettings !== 'system') { if (userSettings !== 'system') {
@ -60,13 +69,16 @@
</div> </div>
</x-slot:title> </x-slot:title>
<div class="flex flex-col gap-1"> <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('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('light')" class="px-1 dropdown-item-no-padding">Light</button>
<button @click="setTheme('system')" class="px-1 dropdown-item-no-padding">System</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> </div>
</x-dropdown> </x-dropdown>
</div> </div>
</div> </div>
<div class="px-2 pt-2 pb-7"> <div class="px-2 pt-2 pb-7">
<livewire:switch-team /> <livewire:switch-team />

View File

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

View File

@ -1,7 +1,7 @@
<x-emails.layout> <x-emails.layout>
Your server ({{ $name }}) has high disk usage ({{ $disk_usage }}% used). Threshold is {{ $threshold }}%. 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.) (You can change the threshold in the Server Settings menu.)
</x-emails.layout> </x-emails.layout>

View File

@ -5,7 +5,12 @@
<livewire:layout-popups /> <livewire:layout-popups />
@endif @endif
@auth @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="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 bg-black/80"></div>
<div class="fixed inset-0 flex"> <div class="fixed inset-0 flex">
@ -50,7 +55,7 @@
</a> --}} </a> --}}
</div> </div>
<main class="lg:pl-48" > <main class="lg:pl-48">
<div class="p-4 sm:px-6 lg:px-8 lg:py-6"> <div class="p-4 sm:px-6 lg:px-8 lg:py-6">
{{ $slot }} {{ $slot }}
</div> </div>

View File

@ -82,10 +82,12 @@ function changePasswordFieldType(event) {
if (element.nodeName === 'INPUT' || element.nodeName === 'TEXTAREA') { if (element.nodeName === 'INPUT' || element.nodeName === 'TEXTAREA') {
if (element.type === 'password') { if (element.type === 'password') {
element.type = 'text'; element.type = 'text';
if (element.disabled) return;
element.classList.add('truncate'); element.classList.add('truncate');
this.type = 'text'; this.type = 'text';
} else { } else {
element.type = 'password'; element.type = 'password';
if (element.disabled) return;
element.classList.remove('truncate'); element.classList.remove('truncate');
this.type = 'password'; this.type = 'password';
} }

View File

@ -60,7 +60,7 @@
server. server.
<br /> <br />
Check this <a target="_blank" class="underline" 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.input readonly id="serverPublicKey"></x-forms.input>
<x-forms.button class="lg:w-64 box-boarding" wire:target="setServerType('localhost')" <x-forms.button class="lg:w-64 box-boarding" wire:target="setServerType('localhost')"
wire:click="setServerType('localhost')">Check again wire:click="setServerType('localhost')">Check again

View File

@ -18,7 +18,7 @@
if (checkNumber > 4) { if (checkNumber > 4) {
this.popups.realtime = true; this.popups.realtime = true;
console.error( 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/cloudflare/tunnels) or get help on Discord (https://coollabs.io/discord).)' '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); clearInterval(checkPusherInterval);
} }
@ -37,7 +37,7 @@
<span>Coolify could not connect to its real-time service.<br>This will cause unusual problems on the UI <span>Coolify could not connect to its real-time service.<br>This will cause unusual problems on the UI
if if
not fixed! <br><br>Please check the not fixed! <br><br>Please check the
related <a class="underline" href='https://coolify.io/docs/cloudflare/tunnels' related <a class="underline" href='https://coolify.io/docs/knowledge-base/cloudflare/tunnels'
target='_blank'>documentation</a> or get target='_blank'>documentation</a> or get
help on <a class="underline" href='https://coollabs.io/discord' target='_blank'>Discord</a>. </span> help on <a class="underline" href='https://coollabs.io/discord' target='_blank'>Discord</a>. </span>
</x-slot:description> </x-slot:description>

View File

@ -27,18 +27,17 @@ class="w-6 h-6" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
@endif @endif
@forelse ($deployments as $deployment) @forelse ($deployments as $deployment)
<a @class([ <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' => 'dark:hover:bg-coolgray-200' =>
data_get($deployment, 'status') === 'queued', data_get($deployment, 'status') === 'queued',
'border-warning hover:bg-warning hover:text-black' => 'border-warning hover:bg-warning hover:text-black' =>
data_get($deployment, 'status') === 'in_progress' || data_get($deployment, 'status') === 'in_progress' ||
data_get($deployment, 'status') === 'cancelled-by-user', 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', 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', data_get($deployment, 'status') === 'finished',
]) href="{{ $current_url . '/' . data_get($deployment, 'deployment_uuid') }}" ]) href="{{ $current_url . '/' . data_get($deployment, 'deployment_uuid') }}">
class="hover:no-underline">
<div class="flex flex-col justify-start"> <div class="flex flex-col justify-start">
<div class="flex gap-1"> <div class="flex gap-1">
{{ $deployment->created_at }} UTC {{ $deployment->created_at }} UTC

View File

@ -1,11 +1,45 @@
<div> <div>
<h1 class="py-0">Deployment</h1> <h1 class="py-0">Deployment</h1>
<livewire:project.application.heading :application="$application" /> <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" /> <livewire:project.application.deployment-navbar :application_deployment_queue="$application_deployment_queue" />
@if (data_get($application_deployment_queue, 'status') === 'in_progress') @if (data_get($application_deployment_queue, 'status') === 'in_progress')
<div class="flex items-center gap-1 pt-2 ">Deployment is <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> </div>
<x-loading class="loading-ring" /> <x-loading class="loading-ring" />
</div> </div>
@ -17,7 +51,7 @@ class="dark:text-warning">{{ Str::headline(data_get($application_deployment_queu
@endif @endif
<div id="screen" :class="fullscreen ? 'fullscreen' : ''"> <div id="screen" :class="fullscreen ? 'fullscreen' : ''">
<div @if ($isKeepAliveOn) wire:poll.2000ms="polling" @endif <div @if ($isKeepAliveOn) wire:poll.2000ms="polling" @endif
class="relative flex flex-col-reverse w-full p-2 px-4 mt-4 overflow-y-auto 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'"> :class="fullscreen ? '' : 'max-h-[40rem] border border-dotted rounded'">
<button title="Minimize" x-show="fullscreen" class="fixed top-4 right-4" <button title="Minimize" x-show="fullscreen" class="fixed top-4 right-4"
x-on:click="makeFullscreen"><svg class="icon" viewBox="0 0 24 24" x-on:click="makeFullscreen"><svg class="icon" viewBox="0 0 24 24"
@ -58,7 +92,11 @@ class="fixed top-4 right-16" x-on:click="toggleScroll"><svg class="icon" viewBox
<br>COMMAND: <br>{{ $line['command'] }} <br><br>OUTPUT: <br>COMMAND: <br>{{ $line['command'] }} <br><br>OUTPUT:
@endif @if (str($line['output'])->contains('http://') || str($line['output'])->contains('https://')) @endif @if (str($line['output'])->contains('http://') || str($line['output'])->contains('https://'))
@php @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'] !!} @endphp {!! $line['output'] !!}
@else @else
{{ $line['output'] }} {{ $line['output'] }}
@ -71,39 +109,5 @@ class="fixed top-4 right-16" x-on:click="toggleScroll"><svg class="icon" viewBox
</div> </div>
</div> </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>
</div> </div>

View File

@ -48,7 +48,7 @@
<div class="w-96"> <div class="w-96">
<x-forms.checkbox instantSave id="application.settings.is_raw_compose_deployment_enabled" <x-forms.checkbox instantSave id="application.settings.is_raw_compose_deployment_enabled"
label="Raw Compose Deployment" 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> </div>
@if (count($parsedServices) > 0 && !$application->settings->is_raw_compose_deployment_enabled) @if (count($parsedServices) > 0 && !$application->settings->is_raw_compose_deployment_enabled)
<h3>Domains</h3> <h3>Domains</h3>
@ -84,13 +84,13 @@
<h3>Docker Registry</h3> <h3>Docker Registry</h3>
@if ($application->build_pack !== 'dockerimage' && !$application->destination->server->isSwarm()) @if ($application->build_pack !== 'dockerimage' && !$application->destination->server->isSwarm())
<x-helper <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 @endif
</div> </div>
@if ($application->destination->server->isSwarm()) @if ($application->destination->server->isSwarm())
@if ($application->build_pack !== 'dockerimage') @if ($application->build_pack !== 'dockerimage')
<div>Docker Swarm requires the image to be available in a registry. More info <a <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> target="_blank">here</a>.</div>
@endif @endif
@endif @endif
@ -132,7 +132,7 @@ class="underline" href="https://coolify.io/docs/docker/registry"
@if ($application->build_pack !== 'dockercompose') @if ($application->build_pack !== 'dockercompose')
<div class="w-96"> <div class="w-96">
<x-forms.checkbox <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" instantSave id="application.settings.is_build_server_enabled"
label="Use a Build Server? (experimental)" /> label="Use a Build Server? (experimental)" />
</div> </div>
@ -148,7 +148,7 @@ class="underline" href="https://coolify.io/docs/docker/registry"
id="application.start_command" label="Start Command" /> id="application.start_command" label="Start Command" />
</div> </div>
<div>Nixpacks will detect the required configuration automatically. <div>Nixpacks will detect the required configuration automatically.
<a class="underline" href="https://coolify.io/docs/frameworks/">Framework Specific Docs</a> <a class="underline" href="https://coolify.io/docs/resources/introduction">Framework Specific Docs</a>
</div> </div>
@endif @endif
@endif @endif
@ -206,13 +206,13 @@ class="underline" href="https://coolify.io/docs/docker/registry"
know what are know what are
you doing.</div> you doing.</div>
<x-forms.input <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" 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" /> id="application.custom_docker_run_options" label="Custom Docker Options" />
@endif @endif
@else @else
<x-forms.input <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" 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" /> id="application.custom_docker_run_options" label="Custom Docker Options" />
@endif @endif

View File

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

View File

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

View File

@ -24,7 +24,7 @@
<div>You can use these variables anywhere with</div> <div>You can use these variables anywhere with</div>
<div class=" dark:text-warning text-coollabs">@{{ project.VARIABLENAME }} </div> <div class=" dark:text-warning text-coollabs">@{{ project.VARIABLENAME }} </div>
<x-helper <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>
<div class="flex flex-col gap-2"> <div class="flex flex-col gap-2">
@forelse ($project->environment_variables->sort()->sortBy('real_value') as $env) @forelse ($project->environment_variables->sort()->sortBy('real_value') as $env)

View File

@ -49,7 +49,7 @@
</x-modal-input> </x-modal-input>
</div> </div>
<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 <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/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>
<div class="flex flex-col gap-2"> <div class="flex flex-col gap-2">
@forelse ($environment->environment_variables->sort()->sortBy('real_value') as $env) @forelse ($environment->environment_variables->sort()->sortBy('real_value') as $env)

View File

@ -1,4 +1,4 @@
<div x-data x-init="$wire.loadServers"> <div x-data x-init="$wire.loadServers" x-init="$wire.loadServices">
<div class="flex flex-col gap-4 lg:flex-row "> <div class="flex flex-col gap-4 lg:flex-row ">
<h1>New Resource</h1> <h1>New Resource</h1>
<div class="w-full pb-4 lg:w-96 lg:pb-0"> <div class="w-full pb-4 lg:w-96 lg:pb-0">
@ -383,10 +383,10 @@ class="w-[4.5rem]
<div class="pb-4 text-xs">Trademarks Policy: The respective trademarks mentioned here are owned by the <div class="pb-4 text-xs">Trademarks Policy: The respective trademarks mentioned here are owned by the
respective respective
companies, and use of them does not imply any affiliation or endorsement.</div> companies, and use of them does not imply any affiliation or endorsement.</div>
<div class="grid justify-start grid-cols-1 gap-4 text-left xl:grid-cols-2">
@if ($loadingServices) @if ($loadingServices)
<span class="loading loading-xs loading-spinner"></span> <x-loading text="Loading services..." />
@else @else
<div class="grid justify-start grid-cols-1 gap-4 text-left xl:grid-cols-2">
@forelse ($services as $serviceName => $service) @forelse ($services as $serviceName => $service)
@if (data_get($service, 'minversion') && version_compare(config('version'), data_get($service, 'minversion'), '<')) @if (data_get($service, 'minversion') && version_compare(config('version'), data_get($service, 'minversion'), '<'))
<x-resource-view wire="setType('one-click-service-{{ $serviceName }}')"> <x-resource-view wire="setType('one-click-service-{{ $serviceName }}')">
@ -477,8 +477,7 @@ class="w-[4.5rem]
</div> </div>
@empty @empty
<div> <div>
<div>No validated & reachable servers found. <a class="underline dark:text-white" <div>No validated & reachable servers found. <a class="underline dark:text-white" href="/servers">
href="/servers">
Go to servers page Go to servers page
</a></div> </a></div>
</div> </div>
@ -526,5 +525,5 @@ class="w-[4.5rem]
<x-forms.button type="submit">Add Database</x-forms.button> <x-forms.button type="submit">Add Database</x-forms.button>
</form> </form>
@endif @endif
</div> </div>
</div> </div>

View File

@ -51,7 +51,7 @@
$application->status)->contains(['running']), $application->status)->contains(['running']),
'border-l border-dashed border-warning' => Str::of( 'border-l border-dashed border-warning' => Str::of(
$application->status)->contains(['starting']), $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-row w-full">
<div class="flex flex-col flex-1"> <div class="flex flex-col flex-1">
@ -95,7 +95,7 @@
$database->status)->contains(['running']), $database->status)->contains(['running']),
'border-l border-dashed border-warning' => Str::of( 'border-l border-dashed border-warning' => Str::of(
$database->status)->contains(['restarting']), $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-row w-full">
<div class="flex flex-col flex-1"> <div class="flex flex-col flex-1">

View File

@ -15,7 +15,7 @@
</div> </div>
<div class="w-96"> <div class="w-96">
<x-forms.checkbox instantSave id="service.connect_to_docker_network" label="Connect To Predefined Network" <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> </div>
@if ($fields) @if ($fields)
<div> <div>

View File

@ -1,5 +1,38 @@
<div> <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"> <div class="flex items-center gap-2">
@if ($resource?->type() === 'application') @if ($resource?->type() === 'application')
<h3>{{ $container }}</h3> <h3>{{ $container }}</h3>
@ -24,7 +57,7 @@
<x-forms.checkbox instantSave label="Include Timestamps" id="showTimeStamps"></x-forms.checkbox> <x-forms.checkbox instantSave label="Include Timestamps" id="showTimeStamps"></x-forms.checkbox>
</form> </form>
<div :class="fullscreen ? 'fullscreen' : 'relative w-full py-4 mx-auto'"> <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'"> :class="fullscreen ? '' : 'max-h-96 border border-solid rounded'">
<button title="Minimize" x-show="fullscreen" class="fixed top-4 right-4" <button title="Minimize" x-show="fullscreen" class="fixed top-4 right-4"
x-on:click="makeFullscreen"><svg class="icon" viewBox="0 0 24 24" x-on:click="makeFullscreen"><svg class="icon" viewBox="0 0 24 24"
@ -61,39 +94,5 @@ class="fixed top-4 right-16" x-on:click="toggleScroll"><svg class="icon" viewBox
@endif @endif
</div> </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>
</div> </div>

View File

@ -2,11 +2,11 @@
<div class="flex items-center gap-2"> <div class="flex items-center gap-2">
<h2>Webhooks</h2> <h2>Webhooks</h2>
<x-helper <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>
<div> <div>
<x-forms.input readonly <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> label="Deploy Webhook (auth required)" id="deploywebhook"></x-forms.input>
</div> </div>
@if ($resource->type() === 'application') @if ($resource->type() === 'application')

View File

@ -83,20 +83,20 @@ class="w-full mt-8 mb-4 font-bold box-without-bg bg-coollabs hover:bg-coollabs-1
@endif @endif
@if ($server->settings->is_swarm_worker) @if ($server->settings->is_swarm_worker)
<x-forms.checkbox disabled instantSave type="checkbox" id="server.settings.is_swarm_manager" <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?" /> label="Is it a Swarm Manager?" />
@else @else
<x-forms.checkbox instantSave type="checkbox" id="server.settings.is_swarm_manager" <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?" /> label="Is it a Swarm Manager?" />
@endif @endif
@if ($server->settings->is_swarm_manager) @if ($server->settings->is_swarm_manager)
<x-forms.checkbox disabled instantSave type="checkbox" id="server.settings.is_swarm_worker" <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?" /> label="Is it a Swarm Worker?" />
@else @else
<x-forms.checkbox instantSave type="checkbox" id="server.settings.is_swarm_worker" <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?" /> label="Is it a Swarm Worker?" />
@endif @endif
@endif @endif

View File

@ -29,24 +29,24 @@
<div class=""> <div class="">
<h3 class="pt-6">Swarm <span class="text-xs text-neutral-500">(experimental)</span></h3> <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' <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> target='_blank'>here</a>.</div>
@if ($is_swarm_worker || $is_build_server) @if ($is_swarm_worker || $is_build_server)
<x-forms.checkbox disabled instantSave type="checkbox" id="is_swarm_manager" <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?" /> label="Is it a Swarm Manager?" />
@else @else
<x-forms.checkbox type="checkbox" instantSave id="is_swarm_manager" <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?" /> label="Is it a Swarm Manager?" />
@endif @endif
@if ($is_swarm_manager|| $is_build_server) @if ($is_swarm_manager|| $is_build_server)
<x-forms.checkbox disabled instantSave type="checkbox" id="is_swarm_worker" <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?" /> label="Is it a Swarm Worker?" />
@else @else
<x-forms.checkbox type="checkbox" instantSave id="is_swarm_worker" <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?" /> label="Is it a Swarm Worker?" />
@endif @endif
@if ($is_swarm_worker && count($swarm_managers) > 0) @if ($is_swarm_worker && count($swarm_managers) > 0)

View File

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

View File

@ -2,11 +2,7 @@
<div class="flex items-center gap-2"> <div class="flex items-center gap-2">
<h2>Transactional Email</h2> <h2>Transactional Email</h2>
</div> </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> <div class="pb-4 ">Email settings for password resets, invitations, etc.</div>
@endif
<form wire:submit='submitFromFields' class="flex flex-col gap-2 pb-4"> <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_name" helper="Name used in emails." label="From Name" />
<x-forms.input required id="settings.smtp_from_address" helper="Email address used in emails." <x-forms.input required id="settings.smtp_from_address" helper="Email address used in emails."

View File

@ -8,7 +8,7 @@
</div> </div>
<div class="flex items-center gap-2 pb-4">You can use these variables anywhere with <span <div class="flex items-center gap-2 pb-4">You can use these variables anywhere with <span
class="dark:text-warning text-coollabs">@{{ team.VARIABLENAME }}</span> <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/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>
<div class="flex flex-col gap-2"> <div class="flex flex-col gap-2">

View File

@ -1,10 +1,7 @@
{ {
"coolify": { "coolify": {
"main": {
"version": "3.12.36"
},
"v4": { "v4": {
"version": "4.0.0-beta.245" "version": "4.0.0-beta.246"
} }
} }
} }