diff --git a/.github/ISSUE_TEMPLATE/BUG_REPORT.yml b/.github/ISSUE_TEMPLATE/BUG_REPORT.yml index 8a52ffebc..6e81f993d 100644 --- a/.github/ISSUE_TEMPLATE/BUG_REPORT.yml +++ b/.github/ISSUE_TEMPLATE/BUG_REPORT.yml @@ -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 diff --git a/.github/workflows/coolify-helper-next.yml b/.github/workflows/coolify-helper-next.yml index fe14ba759..d9921b363 100644 --- a/.github/workflows/coolify-helper-next.yml +++ b/.github/workflows/coolify-helper-next.yml @@ -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 }} diff --git a/.github/workflows/coolify-helper.yml b/.github/workflows/coolify-helper.yml index d174bfaf9..7e8132ec6 100644 --- a/.github/workflows/coolify-helper.yml +++ b/.github/workflows/coolify-helper.yml @@ -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 }} diff --git a/.github/workflows/coolify-testing-host.yml b/.github/workflows/coolify-testing-host.yml index a40dfd285..5fdc32991 100644 --- a/.github/workflows/coolify-testing-host.yml +++ b/.github/workflows/coolify-testing-host.yml @@ -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 }} diff --git a/.github/workflows/docker-image.yml b/.github/workflows/docker-image.yml index 36def4911..0edaa4f1c 100644 --- a/.github/workflows/docker-image.yml +++ b/.github/workflows/docker-image.yml @@ -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: diff --git a/.tinkerwell/snippets/DeleteUser.php b/.tinkerwell/snippets/DeleteUser.php deleted file mode 100644 index bd562557b..000000000 --- a/.tinkerwell/snippets/DeleteUser.php +++ /dev/null @@ -1,22 +0,0 @@ -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(); -} diff --git a/.tinkerwell/snippets/SendEmail.php b/.tinkerwell/snippets/SendEmail.php deleted file mode 100644 index 07edfe8cd..000000000 --- a/.tinkerwell/snippets/SendEmail.php +++ /dev/null @@ -1,28 +0,0 @@ -to($user->email) - ->subject("Testing") - ->text( - <<id - -EOF - ); - }); -} diff --git a/CONTRIBUTION.md b/CONTRIBUTION.md index c6a5b3273..c139793ec 100644 --- a/CONTRIBUTION.md +++ b/CONTRIBUTION.md @@ -30,5 +30,5 @@ ### 4) Start development 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). diff --git a/README.md b/README.md index 6e6d80c59..db38eb142 100644 --- a/README.md +++ b/README.md @@ -28,15 +28,16 @@ # Donations Thank you so much! -Special thanks to our biggest sponsors, [CCCareers](https://cccareers.org/) and [Appwrite](https://appwrite.io)! +Special thanks to our biggest sponsor, [CCCareers](https://cccareers.org/)! cccareers logo -appwrite logo ## Github Sponsors ($40+) +American Cloud CryptoJobsList typebot BC Direct +UXWizz Corentin Clichy Corentin Clichy Niklas Lausch diff --git a/app/Actions/Database/StartDatabaseProxy.php b/app/Actions/Database/StartDatabaseProxy.php index 500798d30..2a86ab913 100644 --- a/app/Actions/Database/StartDatabaseProxy.php +++ b/app/Actions/Database/StartDatabaseProxy.php @@ -25,7 +25,8 @@ public function handle(StandaloneRedis|StandalonePostgresql|StandaloneMongodb|St $proxyContainerName = "{$database->uuid}-proxy"; if ($database->getMorphClass() === 'App\Models\ServiceDatabase') { $databaseType = $database->databaseType(); - $network = data_get($database, 'service.destination.network'); + // $connectPredefined = data_get($database, 'service.connect_to_docker_network'); + $network = $database->service->uuid; $server = data_get($database, 'service.destination.server'); $proxyContainerName = "{$database->service->uuid}-proxy"; switch ($databaseType) { @@ -124,6 +125,7 @@ public function handle(StandaloneRedis|StandalonePostgresql|StandaloneMongodb|St $dockercompose_base64 = base64_encode(Yaml::dump($docker_compose, 4, 2)); $nginxconf_base64 = base64_encode($nginxconf); $dockerfile_base64 = base64_encode($dockerfile); + instant_remote_process(["docker rm -f $proxyContainerName"], $server, false); instant_remote_process([ "mkdir -p $configuration_dir", "echo '{$dockerfile_base64}' | base64 -d > $configuration_dir/Dockerfile", diff --git a/app/Actions/Database/StopDatabaseProxy.php b/app/Actions/Database/StopDatabaseProxy.php index fc18985f1..6582da34e 100644 --- a/app/Actions/Database/StopDatabaseProxy.php +++ b/app/Actions/Database/StopDatabaseProxy.php @@ -17,10 +17,12 @@ class StopDatabaseProxy public function handle(StandaloneRedis|StandalonePostgresql|StandaloneMongodb|StandaloneMysql|StandaloneMariadb|ServiceDatabase $database) { $server = data_get($database, 'destination.server'); + $uuid = $database->uuid; if ($database->getMorphClass() === 'App\Models\ServiceDatabase') { + $uuid = $database->service->uuid; $server = data_get($database, 'service.server'); } - instant_remote_process(["docker rm -f {$database->uuid}-proxy"], $server); + instant_remote_process(["docker rm -f {$uuid}-proxy"], $server); $database->is_public = false; $database->save(); } diff --git a/app/Actions/Proxy/CheckProxy.php b/app/Actions/Proxy/CheckProxy.php index 5a1ae56cf..32a4897a6 100644 --- a/app/Actions/Proxy/CheckProxy.php +++ b/app/Actions/Proxy/CheckProxy.php @@ -35,6 +35,9 @@ public function handle(Server $server, $fromUI = false) $server->save(); return false; } + if ($server->settings->is_cloudflare_tunnel) { + return false; + } $ip = $server->ip; if ($server->id === 0) { $ip = 'host.docker.internal'; diff --git a/app/Actions/Server/ConfigureCloudflared.php b/app/Actions/Server/ConfigureCloudflared.php new file mode 100644 index 000000000..6b08b3de6 --- /dev/null +++ b/app/Actions/Server/ConfigureCloudflared.php @@ -0,0 +1,44 @@ + [ + "coolify-cloudflared" => [ + "container_name" => "coolify-cloudflared", + "image" => "cloudflare/cloudflared:latest", + "restart" => RESTART_MODE, + "network_mode" => "host", + "command" => "tunnel run", + "environment" => [ + "TUNNEL_TOKEN={$cloudflare_token}", + ], + ], + ], + ]; + $config = Yaml::dump($config, 12, 2); + $docker_compose_yml_base64 = base64_encode($config); + $commands = collect([ + "mkdir -p /tmp/cloudflared && cd /tmp/cloudflared", + "echo '$docker_compose_yml_base64' | base64 -d > docker-compose.yml", + "docker compose pull", + "docker compose down -v --remove-orphans > /dev/null 2>&1", + "docker compose up -d --remove-orphans", + ]); + instant_remote_process($commands, $server); + } catch (\Throwable $e) { + ray($e); + throw $e; + } + } +} diff --git a/app/Actions/Server/InstallDocker.php b/app/Actions/Server/InstallDocker.php index 553a1c09d..1db766a88 100644 --- a/app/Actions/Server/InstallDocker.php +++ b/app/Actions/Server/InstallDocker.php @@ -13,7 +13,7 @@ public function handle(Server $server) { $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: documentation.'); + throw new \Exception('Server OS type is not supported for automated installation. Please install Docker manually before continuing: documentation.'); } ray('Installing Docker on server: ' . $server->name . ' (' . $server->ip . ')' . ' with OS type: ' . $supported_os_type); $dockerVersion = '24.0'; diff --git a/app/Actions/Server/UpdateCoolify.php b/app/Actions/Server/UpdateCoolify.php index 09efb848e..6c01f75c9 100644 --- a/app/Actions/Server/UpdateCoolify.php +++ b/app/Actions/Server/UpdateCoolify.php @@ -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 @@ private function update() { 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; } } diff --git a/app/Console/Commands/CleanupDatabase.php b/app/Console/Commands/CleanupDatabase.php index 495b365ee..9e3a58a7e 100644 --- a/app/Console/Commands/CleanupDatabase.php +++ b/app/Console/Commands/CleanupDatabase.php @@ -20,7 +20,7 @@ public function handle() $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')) { diff --git a/app/Console/Commands/Horizon.php b/app/Console/Commands/Horizon.php new file mode 100644 index 000000000..8dd64a246 --- /dev/null +++ b/app/Console/Commands/Horizon.php @@ -0,0 +1,21 @@ +info('Horizon is enabled. Starting.'); + $this->call('horizon'); + exit(0); + } else { + exit(0); + } + } +} diff --git a/app/Console/Commands/Init.php b/app/Console/Commands/Init.php index 66a4f1aff..acdff5b35 100644 --- a/app/Console/Commands/Init.php +++ b/app/Console/Commands/Init.php @@ -34,11 +34,13 @@ public function handle() $this->cleanup_stucked_helper_containers(); $this->call('cleanup:queue'); $this->call('cleanup:stucked-resources'); - try { - $server = Server::find(0)->first(); - $server->setupDynamicProxyConfiguration(); - } catch (\Throwable $e) { - echo "Could not setup dynamic configuration: {$e->getMessage()}\n"; + if (!isCloud()) { + try { + $server = Server::find(0)->first(); + $server->setupDynamicProxyConfiguration(); + } catch (\Throwable $e) { + echo "Could not setup dynamic configuration: {$e->getMessage()}\n"; + } } $settings = InstanceSettings::get(); diff --git a/app/Console/Commands/Scheduler.php b/app/Console/Commands/Scheduler.php new file mode 100644 index 000000000..eab623802 --- /dev/null +++ b/app/Console/Commands/Scheduler.php @@ -0,0 +1,21 @@ +info('Scheduler is enabled. Starting.'); + $this->call('schedule:work'); + exit(0); + } else { + exit(0); + } + } +} diff --git a/app/Console/Kernel.php b/app/Console/Kernel.php index d43da9cbe..dbb8e6ead 100644 --- a/app/Console/Kernel.php +++ b/app/Console/Kernel.php @@ -48,9 +48,7 @@ protected function schedule(Schedule $schedule): void $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 @@ private function check_resources($schedule) $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) { diff --git a/app/Http/Controllers/Api/Deploy.php b/app/Http/Controllers/Api/Deploy.php index 89a994afe..5469ba1c6 100644 --- a/app/Http/Controllers/Api/Deploy.php +++ b/app/Http/Controllers/Api/Deploy.php @@ -44,7 +44,7 @@ public function deploy(Request $request) $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 @@ public function deploy(Request $request) } 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 @@ private function by_uuids(string $uuid, int $teamId, bool $force = false) $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 @@ private function by_uuids(string $uuid, int $teamId, bool $force = false) $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 @@ public function by_tags(string $tags, int $team_id, bool $force = false) $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 @@ public function by_tags(string $tags, int $team_id, bool $force = false) 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 { diff --git a/app/Http/Controllers/Api/Team.php b/app/Http/Controllers/Api/Team.php index 453c2590f..d5b1f6209 100644 --- a/app/Http/Controllers/Api/Team.php +++ b/app/Http/Controllers/Api/Team.php @@ -26,7 +26,7 @@ public function team_by_id(Request $request) $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 @@ public function members_by_id(Request $request) $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); } diff --git a/app/Http/Controllers/OauthController.php b/app/Http/Controllers/OauthController.php new file mode 100644 index 000000000..7d917e5a6 --- /dev/null +++ b/app/Http/Controllers/OauthController.php @@ -0,0 +1,35 @@ +redirect(); + } + + public function callback(string $provider) + { + try { + $oauthUser = get_socialite_provider($provider)->user(); + $user = User::whereEmail($oauthUser->email)->first(); + if (!$user) { + $user = User::create([ + 'name' => $oauthUser->name, + 'email' => $oauthUser->email, + ]); + } + Auth::login($user); + return redirect('/'); + } catch (\Exception $e) { + ray($e->getMessage()); + return redirect()->route('login')->withErrors([__('auth.failed.callback')]); + } + } +} diff --git a/app/Jobs/ApplicationDeploymentJob.php b/app/Jobs/ApplicationDeploymentJob.php index a27800ee3..0c6b6eecb 100644 --- a/app/Jobs/ApplicationDeploymentJob.php +++ b/app/Jobs/ApplicationDeploymentJob.php @@ -298,6 +298,8 @@ public function handle(): void "ignore_errors" => true, ] ); + + // $this->execute_remote_command( // [ // "docker image prune -f >/dev/null 2>&1", @@ -305,6 +307,8 @@ public function handle(): void // "ignore_errors" => true, // ] // ); + + ApplicationStatusChanged::dispatch(data_get($this->application, 'environment.project.team.id')); } } @@ -417,7 +421,6 @@ private function deploy_docker_compose_buildpack() "docker network connect {$networkId} coolify-proxy || true", "hidden" => true, "ignore_errors" => true ]); } - $this->write_deployment_configurations(); // Start compose file if ($this->application->settings->is_raw_compose_deployment_enabled) { @@ -425,7 +428,9 @@ private function deploy_docker_compose_buildpack() $this->execute_remote_command( [executeInDocker($this->deployment_uuid, "cd {$this->workdir} && {$this->docker_compose_custom_start_command}"), "hidden" => true], ); + $this->write_deployment_configurations(); } else { + $this->write_deployment_configurations(); $server_workdir = $this->application->workdir(); ray("SOURCE_COMMIT={$this->commit} docker compose --project-directory {$server_workdir} -f {$server_workdir}{$this->docker_compose_location} up -d"); $this->execute_remote_command( @@ -437,14 +442,15 @@ private function deploy_docker_compose_buildpack() $this->execute_remote_command( [executeInDocker($this->deployment_uuid, "cd {$this->basedir} && {$this->docker_compose_custom_start_command}"), "hidden" => true], ); + $this->write_deployment_configurations(); } else { $this->execute_remote_command( [executeInDocker($this->deployment_uuid, "SOURCE_COMMIT={$this->commit} docker compose --project-directory {$this->workdir} -f {$this->workdir}{$this->docker_compose_location} up -d"), "hidden" => true], ); + $this->write_deployment_configurations(); } } - $this->application_deployment_queue->addLogEntry("New container started."); } private function deploy_dockerfile_buildpack() @@ -731,7 +737,7 @@ private function framework_based_notification() $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() @@ -822,6 +828,10 @@ private function health_check() } private function deploy_pull_request() { + if ($this->application->build_pack === 'dockercompose') { + $this->deploy_docker_compose_buildpack(); + return; + } if ($this->use_build_server) { $this->server = $this->build_server; } @@ -888,6 +898,9 @@ private function deploy_to_additional_destinations() 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."); diff --git a/app/Jobs/ContainerStatusJob.php b/app/Jobs/ContainerStatusJob.php index 68035a258..333d46027 100644 --- a/app/Jobs/ContainerStatusJob.php +++ b/app/Jobs/ContainerStatusJob.php @@ -8,6 +8,7 @@ use App\Actions\Shared\ComplexStatusCheck; use App\Models\ApplicationPreview; use App\Models\Server; +use App\Models\ServiceDatabase; use App\Notifications\Container\ContainerRestarted; use App\Notifications\Container\ContainerStopped; use Illuminate\Bus\Queueable; @@ -149,31 +150,58 @@ public function handle() } } else { $uuid = data_get($labels, 'com.docker.compose.service'); + $type = data_get($labels, 'coolify.type'); + if ($uuid) { - $database = $databases->where('uuid', $uuid)->first(); - if ($database) { - $isPublic = data_get($database, 'is_public'); - $foundDatabases[] = $database->id; - $statusFromDb = $database->status; - if ($statusFromDb !== $containerStatus) { - $database->update(['status' => $containerStatus]); - } - if ($isPublic) { - $foundTcpProxy = $containers->filter(function ($value, $key) use ($uuid) { - if ($this->server->isSwarm()) { - return data_get($value, 'Spec.Name') === "coolify-proxy_$uuid"; - } else { - return data_get($value, 'Name') === "/$uuid-proxy"; + if ($type === 'service') { + $database_id = data_get($labels, 'coolify.service.subId'); + if ($database_id) { + $service_db = ServiceDatabase::where('id', $database_id)->first(); + if ($service_db) { + $uuid = $service_db->service->uuid; + $isPublic = data_get($service_db, 'is_public'); + if ($isPublic) { + $foundTcpProxy = $containers->filter(function ($value, $key) use ($uuid) { + if ($this->server->isSwarm()) { + return data_get($value, 'Spec.Name') === "coolify-proxy_$uuid"; + } else { + return data_get($value, 'Name') === "/$uuid-proxy"; + } + })->first(); + if (!$foundTcpProxy) { + StartDatabaseProxy::run($service_db); + // $this->server->team?->notify(new ContainerRestarted("TCP Proxy for {$service_db->service->name}", $this->server)); + } } - })->first(); - if (!$foundTcpProxy) { - StartDatabaseProxy::run($database); - $this->server->team?->notify(new ContainerRestarted("TCP Proxy for {$database->name}", $this->server)); } } } else { - // Notify user that this container should not be there. + $database = $databases->where('uuid', $uuid)->first(); + if ($database) { + $isPublic = data_get($database, 'is_public'); + $foundDatabases[] = $database->id; + $statusFromDb = $database->status; + if ($statusFromDb !== $containerStatus) { + $database->update(['status' => $containerStatus]); + } + if ($isPublic) { + $foundTcpProxy = $containers->filter(function ($value, $key) use ($uuid) { + if ($this->server->isSwarm()) { + return data_get($value, 'Spec.Name') === "coolify-proxy_$uuid"; + } else { + return data_get($value, 'Name') === "/$uuid-proxy"; + } + })->first(); + if (!$foundTcpProxy) { + StartDatabaseProxy::run($database); + $this->server->team?->notify(new ContainerRestarted("TCP Proxy for {$database->name}", $this->server)); + } + } + } else { + // Notify user that this container should not be there. + } } + } if (data_get($container, 'Name') === '/coolify-db') { $foundDatabases[] = 0; diff --git a/app/Jobs/DatabaseBackupJob.php b/app/Jobs/DatabaseBackupJob.php index aa4b2fa7f..befeffed0 100644 --- a/app/Jobs/DatabaseBackupJob.php +++ b/app/Jobs/DatabaseBackupJob.php @@ -95,7 +95,7 @@ public function handle(): void $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 @@ public function handle(): void } 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 @@ public function handle(): void } 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 @@ public function handle(): void } 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 @@ public function handle(): void $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 @@ public function handle(): void '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 @@ public function handle(): void '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 @@ public function handle(): void '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([ diff --git a/app/Jobs/InstanceAutoUpdateJob.php b/app/Jobs/InstanceAutoUpdateJob.php index 99e0a34f3..fa5c29421 100644 --- a/app/Jobs/InstanceAutoUpdateJob.php +++ b/app/Jobs/InstanceAutoUpdateJob.php @@ -23,6 +23,6 @@ public function __construct(private bool $force = false) public function handle(): void { - UpdateCoolify::run($this->force); + UpdateCoolify::run(force: $this->force, async: false); } } diff --git a/app/Livewire/ActivityMonitor.php b/app/Livewire/ActivityMonitor.php index ad2a599a1..421992cb5 100644 --- a/app/Livewire/ActivityMonitor.php +++ b/app/Livewire/ActivityMonitor.php @@ -13,6 +13,7 @@ class ActivityMonitor extends Component public $activityId; public $eventToDispatch = 'activityFinished'; public $isPollingActive = false; + public bool $showWaiting = false; protected $activity; protected $listeners = ['activityMonitor' => 'newMonitorActivity']; diff --git a/app/Livewire/Boarding/Index.php b/app/Livewire/Boarding/Index.php index c77aa54ec..2681b69e0 100644 --- a/app/Livewire/Boarding/Index.php +++ b/app/Livewire/Boarding/Index.php @@ -2,22 +2,24 @@ namespace App\Livewire\Boarding; -use App\Actions\Server\InstallDocker; use App\Enums\ProxyTypes; use App\Models\PrivateKey; use App\Models\Project; use App\Models\Server; use App\Models\Team; use Illuminate\Support\Collection; +use Livewire\Attributes\Url; use Livewire\Component; class Index extends Component { protected $listeners = ['serverInstalled' => 'validateServer']; + public string $currentState = 'welcome'; public ?string $selectedServerType = null; public ?Collection $privateKeys = null; + public ?int $selectedExistingPrivateKey = null; public ?string $privateKeyType = null; public ?string $privateKey = null; @@ -27,6 +29,7 @@ class Index extends Component public ?PrivateKey $createdPrivateKey = null; public ?Collection $servers = null; + public ?int $selectedExistingServer = null; public ?string $remoteServerName = null; public ?string $remoteServerDescription = null; @@ -38,7 +41,8 @@ class Index extends Component public ?Server $createdServer = null; public Collection $projects; - public ?int $selectedExistingProject = null; + + public ?int $selectedProject = null; public ?Project $createdProject = null; public bool $dockerInstallationStarted = false; @@ -62,6 +66,26 @@ public function mount() $this->remoteServerDescription = 'Created by Coolify'; $this->remoteServerHost = 'coolify-testing-host'; } + // if ($this->currentState === 'create-project') { + // $this->getProjects(); + // } + // if ($this->currentState === 'create-resource') { + // $this->selectExistingServer(); + // $this->selectExistingProject(); + // } + // if ($this->currentState === 'private-key') { + // $this->setServerType('remote'); + // } + // if ($this->currentState === 'create-server') { + // $this->selectExistingPrivateKey(); + // } + // if ($this->currentState === 'validate-server') { + // $this->selectExistingServer(); + // } + // if ($this->currentState === 'select-existing-server') { + // $this->selectExistingServer(); + // } + } public function explanation() { @@ -89,6 +113,7 @@ public function setServerType(string $type) $this->selectedServerType = $type; if ($this->selectedServerType === 'localhost') { $this->createdServer = Server::find(0); + $this->selectedExistingServer = 0; if (!$this->createdServer) { return $this->dispatch('error', 'Localhost server is not found. Something went wrong during installation. Please try to reinstall or contact support.'); } @@ -137,6 +162,10 @@ public function getProxyType() } public function selectExistingPrivateKey() { + if (is_null($this->selectedExistingPrivateKey)) { + $this->restartBoarding(); + return; + } $this->createdPrivateKey = PrivateKey::find($this->selectedExistingPrivateKey); $this->privateKey = $this->createdPrivateKey->private_key; $this->currentState = 'create-server'; @@ -196,6 +225,7 @@ public function saveServer() $this->createdServer->settings->is_cloudflare_tunnel = $this->isCloudflareTunnel; $this->createdServer->settings->save(); $this->createdServer->addInitialNetwork(); + $this->selectedExistingServer = $this->createdServer->id; $this->currentState = 'validate-server'; } public function installServer() @@ -249,13 +279,13 @@ public function getProjects() { $this->projects = Project::ownedByCurrentTeam(['name'])->get(); if ($this->projects->count() > 0) { - $this->selectedExistingProject = $this->projects->first()->id; + $this->selectedProject = $this->projects->first()->id; } $this->currentState = 'create-project'; } public function selectExistingProject() { - $this->createdProject = Project::find($this->selectedExistingProject); + $this->createdProject = Project::find($this->selectedProject); $this->currentState = 'create-resource'; } public function createNewProject() diff --git a/app/Livewire/Dashboard.php b/app/Livewire/Dashboard.php index 632f14d65..8a5d491e4 100644 --- a/app/Livewire/Dashboard.php +++ b/app/Livewire/Dashboard.php @@ -3,6 +3,7 @@ namespace App\Livewire; use App\Models\ApplicationDeploymentQueue; +use App\Models\PrivateKey; use App\Models\Project; use App\Models\Server; use Illuminate\Support\Collection; @@ -13,9 +14,11 @@ class Dashboard extends Component { public $projects = []; public Collection $servers; + public Collection $private_keys; public $deployments_per_server; public function mount() { + $this->private_keys = PrivateKey::ownedByCurrentTeam()->get(); $this->servers = Server::ownedByCurrentTeam()->get(); $this->projects = Project::ownedByCurrentTeam()->get(); $this->get_deployments(); diff --git a/app/Livewire/Destination/New/Docker.php b/app/Livewire/Destination/New/Docker.php index 66d0df82e..d87f4bc0a 100644 --- a/app/Livewire/Destination/New/Docker.php +++ b/app/Livewire/Destination/New/Docker.php @@ -5,7 +5,7 @@ use App\Models\Server; use App\Models\StandaloneDocker as ModelsStandaloneDocker; use App\Models\SwarmDocker; -use Illuminate\Database\Eloquent\Collection; +use Illuminate\Support\Collection; use Livewire\Component; use Visus\Cuid2\Cuid2; @@ -14,7 +14,7 @@ class Docker extends Component public string $name; public string $network; - public Collection $servers; + public ?Collection $servers = null; public Server $server; public ?int $server_id = null; public bool $is_swarm = false; @@ -34,6 +34,9 @@ class Docker extends Component public function mount() { + if (is_null($this->servers)) { + $this->servers = Server::isReachable()->get(); + } if (request()->query('server_id')) { $this->server_id = request()->query('server_id'); } else { @@ -46,7 +49,9 @@ public function mount() } else { $this->network = new Cuid2(7); } - $this->name = str("{$this->servers->first()->name}-{$this->network}")->kebab(); + if ($this->servers->count() > 0) { + $this->name = str("{$this->servers->first()->name}-{$this->network}")->kebab(); + } } public function generate_name() diff --git a/app/Livewire/Destination/Show.php b/app/Livewire/Destination/Show.php index b9cbcc147..4bdbf88b0 100644 --- a/app/Livewire/Destination/Show.php +++ b/app/Livewire/Destination/Show.php @@ -3,6 +3,8 @@ namespace App\Livewire\Destination; use App\Models\Server; +use App\Models\StandaloneDocker; +use App\Models\SwarmDocker; use Illuminate\Support\Collection; use Livewire\Component; @@ -11,6 +13,40 @@ class Show extends Component public Server $server; public Collection|array $networks = []; + private function createNetworkAndAttachToProxy() + { + $connectProxyToDockerNetworks = connectProxyToNetworks($this->server); + instant_remote_process($connectProxyToDockerNetworks, $this->server, false); + } + public function add($name) + { + if ($this->server->isSwarm()) { + $found = $this->server->swarmDockers()->where('network', $name)->first(); + if ($found) { + $this->dispatch('error', 'Network already added to this server.'); + return; + } else { + SwarmDocker::create([ + 'name' => $this->server->name . "-" . $name, + 'network' => $this->name, + 'server_id' => $this->server->id, + ]); + } + } else { + $found = $this->server->standaloneDockers()->where('network', $name)->first(); + if ($found) { + $this->dispatch('error', 'Network already added to this server.'); + return; + } else { + StandaloneDocker::create([ + 'name' => $this->server->name . "-" . $name, + 'network' => $name, + 'server_id' => $this->server->id, + ]); + } + $this->createNetworkAndAttachToProxy(); + } + } public function scan() { if ($this->server->isSwarm()) { @@ -26,6 +62,8 @@ public function scan() }); if ($this->networks->count() === 0) { $this->dispatch('success', 'No new networks found.'); + return; } + $this->dispatch('success', 'Scan done.'); } } diff --git a/app/Livewire/LayoutPopups.php b/app/Livewire/LayoutPopups.php index b6f06f808..136c94ca2 100644 --- a/app/Livewire/LayoutPopups.php +++ b/app/Livewire/LayoutPopups.php @@ -17,14 +17,6 @@ public function testEvent() { $this->dispatch('success', 'Realtime events configured!'); } - public function disableSponsorship() - { - auth()->user()->update(['is_notification_sponsorship_enabled' => false]); - } - public function disableNotifications() - { - auth()->user()->update(['is_notification_notifications_enabled' => false]); - } public function render() { return view('livewire.layout-popups'); diff --git a/app/Livewire/Notifications/DiscordSettings.php b/app/Livewire/Notifications/Discord.php similarity index 91% rename from app/Livewire/Notifications/DiscordSettings.php rename to app/Livewire/Notifications/Discord.php index f5f0d5591..8aad8ccf0 100644 --- a/app/Livewire/Notifications/DiscordSettings.php +++ b/app/Livewire/Notifications/Discord.php @@ -6,7 +6,7 @@ use App\Notifications\Test; use Livewire\Component; -class DiscordSettings extends Component +class Discord extends Component { public Team $team; protected $rules = [ @@ -55,4 +55,8 @@ public function sendTestNotification() $this->team?->notify(new Test()); $this->dispatch('success', 'Test notification sent.'); } + public function render() + { + return view('livewire.notifications.discord'); + } } diff --git a/app/Livewire/Notifications/EmailSettings.php b/app/Livewire/Notifications/Email.php similarity index 89% rename from app/Livewire/Notifications/EmailSettings.php rename to app/Livewire/Notifications/Email.php index b6152907d..343cbda3e 100644 --- a/app/Livewire/Notifications/EmailSettings.php +++ b/app/Livewire/Notifications/Email.php @@ -2,13 +2,12 @@ namespace App\Livewire\Notifications; +use Livewire\Component; use App\Models\InstanceSettings; use App\Models\Team; use App\Notifications\Test; -use Livewire\Component; -use Log; -class EmailSettings extends Component +class Email extends Component { public Team $team; public string $emails; @@ -119,16 +118,18 @@ public function submit() { try { $this->resetErrorBag(); - $this->validate([ - 'team.smtp_from_address' => 'required|email', - 'team.smtp_from_name' => 'required', - 'team.smtp_host' => 'required', - 'team.smtp_port' => 'required|numeric', - 'team.smtp_encryption' => 'nullable', - 'team.smtp_username' => 'nullable', - 'team.smtp_password' => 'nullable', - 'team.smtp_timeout' => 'nullable', - ]); + if (!$this->team->use_instance_email_settings) { + $this->validate([ + 'team.smtp_from_address' => 'required|email', + 'team.smtp_from_name' => 'required', + 'team.smtp_host' => 'required', + 'team.smtp_port' => 'required|numeric', + 'team.smtp_encryption' => 'nullable', + 'team.smtp_username' => 'nullable', + 'team.smtp_password' => 'nullable', + 'team.smtp_timeout' => 'nullable', + ]); + } $this->team->save(); refreshSession(); $this->dispatch('success', 'Settings saved.'); @@ -189,4 +190,8 @@ public function copyFromInstanceSettings() } $this->dispatch('error', 'Instance SMTP/Resend settings are not enabled.'); } + public function render() + { + return view('livewire.notifications.email'); + } } diff --git a/app/Livewire/Notifications/TelegramSettings.php b/app/Livewire/Notifications/Telegram.php similarity index 93% rename from app/Livewire/Notifications/TelegramSettings.php rename to app/Livewire/Notifications/Telegram.php index 0f581a515..35b868527 100644 --- a/app/Livewire/Notifications/TelegramSettings.php +++ b/app/Livewire/Notifications/Telegram.php @@ -6,8 +6,9 @@ use App\Notifications\Test; use Livewire\Component; -class TelegramSettings extends Component +class Telegram extends Component { + public Team $team; protected $rules = [ 'team.telegram_enabled' => 'nullable|boolean', @@ -61,4 +62,8 @@ public function sendTestNotification() $this->team?->notify(new Test()); $this->dispatch('success', 'Test notification sent.'); } + public function render() + { + return view('livewire.notifications.telegram'); + } } diff --git a/app/Livewire/Profile/Index.php b/app/Livewire/Profile/Index.php index abfc0b972..631d4f956 100644 --- a/app/Livewire/Profile/Index.php +++ b/app/Livewire/Profile/Index.php @@ -11,11 +11,8 @@ class Index extends Component public int $userId; public string $email; - #[Validate('required')] public string $current_password; - #[Validate('required|min:8')] public string $new_password; - #[Validate('required|min:8|same:new_password')] public string $new_password_confirmation; #[Validate('required')] @@ -29,7 +26,9 @@ public function mount() public function submit() { try { - $this->validate(); + $this->validate([ + 'name' => 'required', + ]); auth()->user()->update([ 'name' => $this->name, ]); @@ -42,7 +41,11 @@ public function submit() public function resetPassword() { try { - $this->validate(); + $this->validate([ + 'current_password' => 'required', + 'new_password' => 'required|min:8', + 'new_password_confirmation' => 'required|min:8|same:new_password', + ]); if (!Hash::check($this->current_password, auth()->user()->password)) { $this->dispatch('error', 'Current password is incorrect.'); return; diff --git a/app/Livewire/Project/Application/Deployment/Index.php b/app/Livewire/Project/Application/Deployment/Index.php index 520848a54..d8e033b24 100644 --- a/app/Livewire/Project/Application/Deployment/Index.php +++ b/app/Livewire/Project/Application/Deployment/Index.php @@ -9,7 +9,7 @@ class Index extends Component { public Application $application; - public array|Collection $deployments = []; + public ?Collection $deployments; public int $deployments_count = 0; public string $current_url; public int $skip = 0; @@ -48,9 +48,9 @@ private function show_pull_request_only() } private function show_more() { - if (count($this->deployments) !== 0) { + if ($this->deployments->count() !== 0) { $this->show_next = true; - if (count($this->deployments) < $this->default_take) { + if ($this->deployments->count() < $this->default_take) { $this->show_next = false; } return; @@ -63,7 +63,6 @@ public function reload_deployments() } public function previous_page(?int $take = null) { - if ($take) { $this->skip = $this->skip - $take; } diff --git a/app/Livewire/Project/Application/General.php b/app/Livewire/Project/Application/General.php index e530a0698..9485cdd03 100644 --- a/app/Livewire/Project/Application/General.php +++ b/app/Livewire/Project/Application/General.php @@ -251,7 +251,7 @@ public function submit($showToaster = true) 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.

Check this documentation for further help."); + $showToaster && $this->dispatch('error', "Validating DNS ($domain) failed.", "Make sure you have added the DNS records correctly.

Check this documentation for further help."); } } } diff --git a/app/Livewire/Project/Application/Heading.php b/app/Livewire/Project/Application/Heading.php index 3047f9f23..089eb5e9f 100644 --- a/app/Livewire/Project/Application/Heading.php +++ b/app/Livewire/Project/Application/Heading.php @@ -56,11 +56,11 @@ public function deploy(bool $force_rebuild = false) 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.
More information here: documentation'); + $this->dispatch('error', 'Failed to deploy.', 'To use a build server, you must first set a Docker image.
More information here: documentation'); 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.
More information here: documentation'); + $this->dispatch('error', 'Failed to deploy.', 'Before deploying to multiple servers, you must first set a Docker image in the General tab.
More information here: documentation'); return; } $this->setDeploymentUuid(); @@ -99,7 +99,7 @@ public function stop() 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.
More information here: documentation'); + $this->dispatch('error', 'Failed to deploy', 'Before deploying to multiple servers, you must first set a Docker image in the General tab.
More information here: documentation'); return; } $this->setDeploymentUuid(); diff --git a/app/Livewire/Project/Database/BackupEdit.php b/app/Livewire/Project/Database/BackupEdit.php index 86aec0f6a..f5f476257 100644 --- a/app/Livewire/Project/Database/BackupEdit.php +++ b/app/Livewire/Project/Database/BackupEdit.php @@ -42,19 +42,21 @@ public function mount() public function delete() { - // TODO: Delete backup from server and add a confirmation modal - $this->backup->delete(); - if ($this->backup->database->getMorphClass() === 'App\Models\ServiceDatabase') { - $previousUrl = url()->previous(); - $url = Url::fromString($previousUrl); - $url = $url->withoutQueryParameter('selectedBackupId'); - $url = $url->withFragment('backups'); - $url = $url->getPath() . "#{$url->getFragment()}"; - return redirect($url); - } else { - return redirect()->route('project.database.backup.index', $this->parameters); + try { + $this->backup->delete(); + if ($this->backup->database->getMorphClass() === 'App\Models\ServiceDatabase') { + $previousUrl = url()->previous(); + $url = Url::fromString($previousUrl); + $url = $url->withoutQueryParameter('selectedBackupId'); + $url = $url->withFragment('backups'); + $url = $url->getPath() . "#{$url->getFragment()}"; + return redirect($url); + } else { + return redirect()->route('project.database.backup.index', $this->parameters); + } + } catch (\Throwable $e) { + return handleError($e, $this); } - } public function instantSave() @@ -63,7 +65,7 @@ public function instantSave() $this->custom_validate(); $this->backup->save(); $this->backup->refresh(); - $this->dispatch('success', 'Backup updated successfully'); + $this->dispatch('success', 'Backup updated successfully.'); } catch (\Throwable $e) { $this->dispatch('error', $e->getMessage()); } diff --git a/app/Livewire/Project/Edit.php b/app/Livewire/Project/Edit.php index a80b1af76..17cb6902b 100644 --- a/app/Livewire/Project/Edit.php +++ b/app/Livewire/Project/Edit.php @@ -46,10 +46,11 @@ public function mount() public function submit() { - $this->validate(); try { + $this->validate(); $this->project->save(); $this->dispatch('saved'); + $this->dispatch('success', 'Project updated.'); } catch (\Throwable $e) { return handleError($e, $this); } diff --git a/app/Livewire/Project/Index.php b/app/Livewire/Project/Index.php index 1e6f79855..0537ad192 100644 --- a/app/Livewire/Project/Index.php +++ b/app/Livewire/Project/Index.php @@ -2,6 +2,7 @@ namespace App\Livewire\Project; +use App\Models\PrivateKey; use App\Models\Project; use App\Models\Server; use Livewire\Component; @@ -10,7 +11,9 @@ class Index extends Component { public $projects; public $servers; + public $private_keys; public function mount() { + $this->private_keys = PrivateKey::ownedByCurrentTeam()->get(); $this->projects = Project::ownedByCurrentTeam()->get(); $this->servers = Server::ownedByCurrentTeam()->count(); } diff --git a/app/Livewire/Project/New/Select.php b/app/Livewire/Project/New/Select.php index 8178590a3..b1842547e 100644 --- a/app/Livewire/Project/New/Select.php +++ b/app/Livewire/Project/New/Select.php @@ -49,7 +49,6 @@ public function mount() } public function render() { - $this->loadServices(); return view('livewire.project.new.select'); } @@ -74,6 +73,7 @@ public function updatedSelectedEnvironment() public function loadServices(bool $force = false) { try { + $this->loadingServices = true; if (count($this->allServices) > 0 && !$force) { if (!$this->search) { $this->services = $this->allServices; @@ -90,8 +90,7 @@ public function loadServices(bool $force = false) $this->allServices = getServiceTemplates(); $this->services = $this->allServices->filter(function ($service, $key) { return str_contains(strtolower($key), strtolower($this->search)); - });; - $this->dispatch('success', 'Successfully loaded services.'); + }); } } catch (\Throwable $e) { return handleError($e, $this); diff --git a/app/Livewire/Project/Service/Configuration.php b/app/Livewire/Project/Service/Configuration.php index eb72c803c..cdedb3f8e 100644 --- a/app/Livewire/Project/Service/Configuration.php +++ b/app/Livewire/Project/Service/Configuration.php @@ -36,6 +36,30 @@ public function mount() $this->applications = $this->service->applications->sort(); $this->databases = $this->service->databases->sort(); } + public function restartApplication($id) + { + try { + $application = $this->service->applications->find($id); + if ($application) { + $application->restart(); + $this->dispatch('success', 'Application restarted successfully.'); + } + } catch (\Exception $e) { + return handleError($e, $this); + } + } + public function restartDatabase($id) + { + try { + $database = $this->service->databases->find($id); + if ($database) { + $database->restart(); + $this->dispatch('success', 'Database restarted successfully.'); + } + } catch (\Exception $e) { + return handleError($e, $this); + } + } public function check_status() { try { diff --git a/app/Livewire/Project/Service/Database.php b/app/Livewire/Project/Service/Database.php index 8dec97852..d7c1c9f5c 100644 --- a/app/Livewire/Project/Service/Database.php +++ b/app/Livewire/Project/Service/Database.php @@ -34,7 +34,11 @@ public function mount() } $this->refreshFileStorages(); } - public function instantSaveAdvanced() + public function instantSaveExclude() + { + $this->submit(); + } + public function instantSaveLogDrain() { if (!$this->database->service->destination->server->isLogDrainEnabled()) { $this->database->is_log_drain_enabled = false; diff --git a/app/Livewire/Modal/EditCompose.php b/app/Livewire/Project/Service/EditCompose.php similarity index 69% rename from app/Livewire/Modal/EditCompose.php rename to app/Livewire/Project/Service/EditCompose.php index f2804e5ac..cc385315e 100644 --- a/app/Livewire/Modal/EditCompose.php +++ b/app/Livewire/Project/Service/EditCompose.php @@ -1,11 +1,11 @@ service = Service::find($this->serviceId); } - public function render() - { - return view('livewire.modal.edit-compose'); - } - public function submit() { + + public function saveEditedCompose() { $this->dispatch('warning', "Saving new docker compose..."); $this->dispatch('saveCompose', $this->service->docker_compose_raw); - $this->closeModal(); + } + public function render() + { + return view('livewire.project.service.edit-compose'); } } diff --git a/app/Livewire/Project/Service/Modal.php b/app/Livewire/Project/Service/Modal.php deleted file mode 100644 index 653425835..000000000 --- a/app/Livewire/Project/Service/Modal.php +++ /dev/null @@ -1,13 +0,0 @@ -user()->id; return [ + "echo-private:user.{$userId},ServiceStatusChanged" => 'serviceStarted', "serviceStatusChanged" ]; } + public function serviceStarted() { + $this->dispatch('success', 'Service status changed.'); + } public function serviceStatusChanged() { $this->dispatch('refresh')->self(); } - public function check_status() { + public function check_status() + { $this->dispatch('check_status'); $this->dispatch('success', 'Service status updated.'); } @@ -44,7 +51,7 @@ public function checkDeployments() $this->isDeploymentProgress = false; } } - public function deploy() + public function start() { $this->checkDeployments(); if ($this->isDeploymentProgress) { @@ -73,9 +80,9 @@ public function restart() return; } PullImage::run($this->service); - $this->dispatch('image-pulled'); StopService::run($this->service); $this->service->parse(); + $this->dispatch('imagePulled'); $activity = StartService::run($this->service); $this->dispatch('activityMonitor', $activity->id); } diff --git a/app/Livewire/Project/Service/ServiceApplicationView.php b/app/Livewire/Project/Service/ServiceApplicationView.php index 29bd796fd..0b3a4cef6 100644 --- a/app/Livewire/Project/Service/ServiceApplicationView.php +++ b/app/Livewire/Project/Service/ServiceApplicationView.php @@ -59,7 +59,7 @@ public function submit() $this->validate(); $this->application->save(); updateCompose($this->application); - $this->dispatch('success', 'Application saved.'); + $this->dispatch('success', 'Service saved.'); } catch (\Throwable $e) { return handleError($e, $this); } finally { diff --git a/app/Livewire/Project/Service/StackForm.php b/app/Livewire/Project/Service/StackForm.php index 650dde792..1bfb70c5e 100644 --- a/app/Livewire/Project/Service/StackForm.php +++ b/app/Livewire/Project/Service/StackForm.php @@ -2,11 +2,12 @@ namespace App\Livewire\Project\Service; +use App\Models\Service; use Livewire\Component; class StackForm extends Component { - public $service; + public Service $service; public $fields = []; protected $listeners = ["saveCompose"]; public $rules = [ diff --git a/app/Livewire/Project/Shared/Destination.php b/app/Livewire/Project/Shared/Destination.php index 787b9da20..fa19e8c42 100644 --- a/app/Livewire/Project/Shared/Destination.php +++ b/app/Livewire/Project/Shared/Destination.php @@ -56,7 +56,7 @@ public function stop(int $server_id) public function redeploy(int $network_id, int $server_id) { if ($this->resource->additional_servers->count() > 0 && str($this->resource->docker_registry_image_name)->isEmpty()) { - $this->dispatch('error', 'Failed to deploy.', 'Before deploying to multiple servers, you must first set a Docker image in the General tab.
More information here: documentation'); + $this->dispatch('error', 'Failed to deploy.', 'Before deploying to multiple servers, you must first set a Docker image in the General tab.
More information here: documentation'); return; } $deployment_uuid = new Cuid2(7); diff --git a/app/Livewire/Project/Shared/EnvironmentVariable/All.php b/app/Livewire/Project/Shared/EnvironmentVariable/All.php index 53dd0ffe3..c1a39afee 100644 --- a/app/Livewire/Project/Shared/EnvironmentVariable/All.php +++ b/app/Livewire/Project/Shared/EnvironmentVariable/All.php @@ -98,6 +98,7 @@ public function saveVariables($isPreview) } } $environment->is_build_time = false; + $environment->is_multiline = false; $environment->is_preview = $isPreview ? true : false; switch ($this->resource->type()) { case 'application': diff --git a/app/Livewire/Project/Shared/ScheduledTask/Add.php b/app/Livewire/Project/Shared/ScheduledTask/Add.php index 3cc5428b8..3a7a3fa23 100644 --- a/app/Livewire/Project/Shared/ScheduledTask/Add.php +++ b/app/Livewire/Project/Shared/ScheduledTask/Add.php @@ -33,19 +33,23 @@ public function mount() public function submit() { - $this->validate(); - $isValid = validate_cron_expression($this->frequency); - if (!$isValid) { - $this->dispatch('error', 'Invalid Cron / Human expression.'); - return; + try { + $this->validate(); + $isValid = validate_cron_expression($this->frequency); + if (!$isValid) { + $this->dispatch('error', 'Invalid Cron / Human expression.'); + return; + } + $this->dispatch('saveScheduledTask', [ + 'name' => $this->name, + 'command' => $this->command, + 'frequency' => $this->frequency, + 'container' => $this->container, + ]); + $this->clear(); + } catch (\Exception $e) { + return handleError($e, $this); } - $this->dispatch('saveScheduledTask', [ - 'name' => $this->name, - 'command' => $this->command, - 'frequency' => $this->frequency, - 'container' => $this->container, - ]); - $this->clear(); } public function clear() diff --git a/app/Livewire/Project/Shared/Tags.php b/app/Livewire/Project/Shared/Tags.php index 0977f18f8..92a08f117 100644 --- a/app/Livewire/Project/Shared/Tags.php +++ b/app/Livewire/Project/Shared/Tags.php @@ -28,7 +28,7 @@ public function addTag(string $id, string $name) { try { if ($this->resource->tags()->where('id', $id)->exists()) { - $this->dispatch('error', 'Duplicate tags.', "Tag $name already added."); + $this->dispatch('error', 'Duplicate tags.', "Tag $name already added."); return; } $this->resource->tags()->syncWithoutDetaching($id); @@ -66,7 +66,7 @@ public function submit() $tags = str($this->new_tag)->trim()->explode(' '); foreach ($tags as $tag) { if ($this->resource->tags()->where('name', $tag)->exists()) { - $this->dispatch('error', 'Duplicate tags.', "Tag $tag already added."); + $this->dispatch('error', 'Duplicate tags.', "Tag $tag already added."); continue; } $found = Tag::where(['name' => $tag, 'team_id' => currentTeam()->id])->first(); diff --git a/app/Livewire/RealtimeConnection.php b/app/Livewire/RealtimeConnection.php deleted file mode 100644 index 89b680277..000000000 --- a/app/Livewire/RealtimeConnection.php +++ /dev/null @@ -1,25 +0,0 @@ -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; - } -} diff --git a/app/Livewire/Security/PrivateKey/Create.php b/app/Livewire/Security/PrivateKey/Create.php index 62d763601..cd1c06568 100644 --- a/app/Livewire/Security/PrivateKey/Create.php +++ b/app/Livewire/Security/PrivateKey/Create.php @@ -67,7 +67,7 @@ public function createPrivateKey() 'team_id' => currentTeam()->id ]); if ($this->from === 'server') { - return redirect()->route('server.create'); + return redirect()->route('dashboard'); } return redirect()->route('security.private-key.show', ['private_key_uuid' => $private_key->uuid]); } catch (\Throwable $e) { diff --git a/app/Livewire/Security/PrivateKey/Show.php b/app/Livewire/Security/PrivateKey/Show.php index a4fbaef52..0540b2e29 100644 --- a/app/Livewire/Security/PrivateKey/Show.php +++ b/app/Livewire/Security/PrivateKey/Show.php @@ -50,6 +50,7 @@ public function changePrivateKey() $this->private_key->private_key = formatPrivateKey($this->private_key->private_key); $this->private_key->save(); refresh_server_connection($this->private_key); + $this->dispatch('success', 'Private key updated.'); } catch (\Throwable $e) { return handleError($e, $this); } diff --git a/app/Livewire/Server/ConfigureCloudflareTunnels.php b/app/Livewire/Server/ConfigureCloudflareTunnels.php new file mode 100644 index 000000000..03a48c3e1 --- /dev/null +++ b/app/Livewire/Server/ConfigureCloudflareTunnels.php @@ -0,0 +1,45 @@ +where('id', $this->server_id)->firstOrFail(); + $server->settings->is_cloudflare_tunnel = true; + $server->settings->save(); + $this->dispatch('success', 'Cloudflare Tunnels configured successfully.'); + $this->dispatch('serverInstalled'); + } catch (\Throwable $e) { + return handleError($e, $this); + } + } + public function submit() + { + try { + $server = Server::ownedByCurrentTeam()->where('id', $this->server_id)->firstOrFail(); + ConfigureCloudflared::run($server, $this->cloudflare_token); + $server->settings->is_cloudflare_tunnel = true; + $server->ip = $this->ssh_domain; + $server->save(); + $server->settings->save(); + $this->dispatch('success', 'Cloudflare Tunnels configured successfully.'); + $this->dispatch('serverInstalled'); + } catch(\Throwable $e) { + return handleError($e, $this); + } + } + public function render() + { + return view('livewire.server.configure-cloudflare-tunnels'); + } +} diff --git a/app/Livewire/Server/Form.php b/app/Livewire/Server/Form.php index 098a7c1ff..ff9aaf701 100644 --- a/app/Livewire/Server/Form.php +++ b/app/Livewire/Server/Form.php @@ -82,7 +82,7 @@ public function checkLocalhostConnection() $this->server->settings->is_usable = true; $this->server->settings->save(); } else { - $this->dispatch('error', 'Server is not reachable.', 'Please validate your configuration and connection.

Check this documentation for further help.'); + $this->dispatch('error', 'Server is not reachable.', 'Please validate your configuration and connection.

Check this documentation for further help.'); return; } } diff --git a/app/Livewire/Server/New/ByIp.php b/app/Livewire/Server/New/ByIp.php index df3fae20f..1ce3df273 100644 --- a/app/Livewire/Server/New/ByIp.php +++ b/app/Livewire/Server/New/ByIp.php @@ -53,7 +53,7 @@ class ByIp extends Component public function mount() { $this->name = generate_random_name(); - $this->private_key_id = $this->private_keys->first()->id; + $this->private_key_id = $this->private_keys->first()?->id; $this->swarm_managers = Server::isUsable()->get()->where('settings.is_swarm_manager', true); if ($this->swarm_managers->count() > 0) { $this->selected_swarm_cluster = $this->swarm_managers->first()->id; diff --git a/app/Livewire/Server/Proxy/Deploy.php b/app/Livewire/Server/Proxy/Deploy.php index 72d0b3884..8a029e6a1 100644 --- a/app/Livewire/Server/Proxy/Deploy.php +++ b/app/Livewire/Server/Proxy/Deploy.php @@ -49,7 +49,8 @@ public function proxyStatusUpdated() { $this->server->refresh(); } - public function restart() { + public function restart() + { try { $this->stop(); $this->dispatch('checkProxy'); diff --git a/app/Livewire/Server/ShowPrivateKey.php b/app/Livewire/Server/ShowPrivateKey.php index 43b55fbb6..d44d2cb5f 100644 --- a/app/Livewire/Server/ShowPrivateKey.php +++ b/app/Livewire/Server/ShowPrivateKey.php @@ -39,7 +39,7 @@ public function checkConnection() if ($uptime) { $this->dispatch('success', 'Server is reachable.'); } else { - $this->dispatch('error', 'Server is not reachable.
Please validate your configuration and connection.

Check this documentation for further help.'); + $this->dispatch('error', 'Server is not reachable.
Please validate your configuration and connection.

Check this documentation for further help.'); return; } } catch (\Throwable $e) { diff --git a/app/Livewire/Server/ValidateAndInstall.php b/app/Livewire/Server/ValidateAndInstall.php index ff623e972..6d4173956 100644 --- a/app/Livewire/Server/ValidateAndInstall.php +++ b/app/Livewire/Server/ValidateAndInstall.php @@ -75,7 +75,7 @@ public function validateConnection() { $this->uptime = $this->server->validateConnection(); if (!$this->uptime) { - $this->error = 'Server is not reachable. Please validate your configuration and connection.

Check this documentation for further help.'; + $this->error = 'Server is not reachable. Please validate your configuration and connection.

Check this documentation for further help.'; return; } $this->dispatch('validateOS'); diff --git a/app/Livewire/Settings/Auth.php b/app/Livewire/Settings/Auth.php new file mode 100644 index 000000000..100f99a73 --- /dev/null +++ b/app/Livewire/Settings/Auth.php @@ -0,0 +1,43 @@ +reduce(function($carry, $setting) { + $carry["oauth_settings_map.$setting->provider.enabled"] = 'required'; + $carry["oauth_settings_map.$setting->provider.client_id"] = 'nullable'; + $carry["oauth_settings_map.$setting->provider.client_secret"] = 'nullable'; + $carry["oauth_settings_map.$setting->provider.redirect_uri"] = 'nullable'; + $carry["oauth_settings_map.$setting->provider.tenant"] = 'nullable'; + return $carry; + }, []); + } + + public function mount() { + $this->oauth_settings_map = OauthSetting::all()->sortBy('provider')->reduce(function($carry, $setting) { + $carry[$setting->provider] = $setting; + return $carry; + }, []); + } + + private function updateOauthSettings() { + foreach (array_values($this->oauth_settings_map) as &$setting) { + $setting->save(); + } + } + + public function instantSave() { + $this->updateOauthSettings(); + } + + public function submit() { + $this->updateOauthSettings(); + $this->dispatch('success', 'Instance settings updated successfully!'); + } +} diff --git a/app/Livewire/Settings/Email.php b/app/Livewire/Settings/Email.php index 3563e2e64..77b82df43 100644 --- a/app/Livewire/Settings/Email.php +++ b/app/Livewire/Settings/Email.php @@ -58,6 +58,8 @@ public function submitResend() { 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 @@ public function submit() 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', diff --git a/app/Livewire/Settings/License.php b/app/Livewire/Settings/License.php index 64ad0a6f7..e2ae5fcf7 100644 --- a/app/Livewire/Settings/License.php +++ b/app/Livewire/Settings/License.php @@ -30,7 +30,7 @@ public function mount () { } public function render() { - return view('livewire.settings.license')->layout('layouts.subscription'); + return view('livewire.settings.license'); } public function submit() { diff --git a/app/Livewire/Subscription/Index.php b/app/Livewire/Subscription/Index.php index 4f36750c7..c87f7d0b6 100644 --- a/app/Livewire/Subscription/Index.php +++ b/app/Livewire/Subscription/Index.php @@ -31,6 +31,6 @@ public function stripeCustomerPortal() } public function render() { - return view('livewire.subscription.index')->layout('layouts.subscription'); + return view('livewire.subscription.index'); } } diff --git a/app/Livewire/SwitchTeam.php b/app/Livewire/SwitchTeam.php index 845619820..49b73cdc6 100644 --- a/app/Livewire/SwitchTeam.php +++ b/app/Livewire/SwitchTeam.php @@ -8,7 +8,9 @@ class SwitchTeam extends Component { public string $selectedTeamId = 'default'; - + public function mount() { + $this->selectedTeamId = auth()->user()->currentTeam()->id; + } public function updatedSelectedTeamId() { $this->switch_to($this->selectedTeamId); diff --git a/app/Livewire/Tags/Index.php b/app/Livewire/Tags/Index.php index eba25a750..75ed06f7b 100644 --- a/app/Livewire/Tags/Index.php +++ b/app/Livewire/Tags/Index.php @@ -2,14 +2,73 @@ namespace App\Livewire\Tags; +use App\Http\Controllers\Api\Deploy; +use App\Models\ApplicationDeploymentQueue; use App\Models\Tag; +use Illuminate\Support\Collection; +use Livewire\Attributes\Url; use Livewire\Component; class Index extends Component { - public $tags = []; - public function mount() { - $this->tags = Tag::where('team_id', currentTeam()->id)->get()->unique('name')->sortBy('name'); + #[Url()] + public ?string $tag = null; + + public Collection $tags; + public Collection $applications; + public Collection $services; + public $webhook = null; + public $deployments_per_tag_per_server = []; + + public function updatedTag() + { + $tag = $this->tags->where('name', $this->tag)->first(); + $this->webhook = generatTagDeployWebhook($tag->name); + $this->applications = $tag->applications()->get(); + $this->services = $tag->services()->get(); + $this->get_deployments(); + } + public function get_deployments() + { + try { + $resource_ids = $this->applications->pluck('id'); + $this->deployments_per_tag_per_server = ApplicationDeploymentQueue::whereIn("status", ["in_progress", "queued"])->whereIn('application_id', $resource_ids)->get([ + "id", + "application_id", + "application_name", + "deployment_url", + "pull_request_id", + "server_name", + "server_id", + "status" + ])->sortBy('id')->groupBy('server_name')->toArray(); + } catch (\Exception $e) { + return handleError($e, $this); + } + } + public function redeploy_all() + { + try { + $message = collect([]); + $this->applications->each(function ($resource) use ($message) { + $deploy = new Deploy(); + $message->push($deploy->deploy_resource($resource)); + }); + $this->services->each(function ($resource) use ($message) { + $deploy = new Deploy(); + $message->push($deploy->deploy_resource($resource)); + }); + $this->dispatch('success', 'Mass deployment started.'); + } catch (\Exception $e) { + return handleError($e, $this); + } + } + public function mount() + { + $this->tags = Tag::ownedByCurrentTeam()->get()->unique('name')->sortBy('name'); + if ($this->tag) { + $this->updatedTag(); + } } public function render() { diff --git a/app/Livewire/Team/Notification/Index.php b/app/Livewire/Team/Notification/Index.php deleted file mode 100644 index 86754d619..000000000 --- a/app/Livewire/Team/Notification/Index.php +++ /dev/null @@ -1,13 +0,0 @@ -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); } diff --git a/app/Models/OauthSetting.php b/app/Models/OauthSetting.php new file mode 100644 index 000000000..4ab21aeec --- /dev/null +++ b/app/Models/OauthSetting.php @@ -0,0 +1,21 @@ + empty($value) ? null : Crypt::decryptString($value), + set: fn (string | null $value) => empty($value) ? null : Crypt::encryptString($value), + ); + } +} diff --git a/app/Models/ServiceApplication.php b/app/Models/ServiceApplication.php index 37f7d9c9c..820ef6fee 100644 --- a/app/Models/ServiceApplication.php +++ b/app/Models/ServiceApplication.php @@ -19,6 +19,11 @@ protected static function booted() $service->fileStorages()->delete(); }); } + public function restart() + { + $container_id = $this->name . '-' . $this->service->uuid; + instant_remote_process(["docker restart {$container_id}"], $this->service->server); + } public function isLogDrainEnabled() { return data_get($this, 'is_log_drain_enabled', false); diff --git a/app/Models/ServiceDatabase.php b/app/Models/ServiceDatabase.php index 9375fe807..76c174d08 100644 --- a/app/Models/ServiceDatabase.php +++ b/app/Models/ServiceDatabase.php @@ -17,6 +17,11 @@ protected static function booted() $service->fileStorages()->delete(); }); } + public function restart() + { + $container_id = $this->name . '-' . $this->service->uuid; + remote_process(["docker restart {$container_id}"], $this->service->server); + } public function isLogDrainEnabled() { return data_get($this, 'is_log_drain_enabled', false); @@ -52,8 +57,7 @@ public function getServiceDatabaseUrl() if ($this->service->server->isLocalhost() || isDev()) { $realIp = base_ip(); } - $url = "{$realIp}:{$port}"; - return $url; + return "{$realIp}:{$port}"; } public function service() { diff --git a/app/Models/Team.php b/app/Models/Team.php index 7cb1601de..a3dd4e473 100644 --- a/app/Models/Team.php +++ b/app/Models/Team.php @@ -177,9 +177,6 @@ public function isAnyNotificationEnabled() if (isCloud()) { return true; } - if (!data_get(auth()->user(), 'is_notification_notifications_enabled')) { - return true; - } if ($this->smtp_enabled || $this->resend_enabled || $this->discord_enabled || $this->telegram_enabled || $this->use_instance_email_settings) { return true; } diff --git a/app/Notifications/Server/HighDiskUsage.php b/app/Notifications/Server/HighDiskUsage.php index d8794600d..33e49387e 100644 --- a/app/Notifications/Server/HighDiskUsage.php +++ b/app/Notifications/Server/HighDiskUsage.php @@ -53,13 +53,13 @@ public function toMail(): MailMessage 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." ]; } } diff --git a/app/Providers/EventServiceProvider.php b/app/Providers/EventServiceProvider.php index 0e9be72d1..a6ded1dc7 100644 --- a/app/Providers/EventServiceProvider.php +++ b/app/Providers/EventServiceProvider.php @@ -19,7 +19,10 @@ class EventServiceProvider extends ServiceProvider MaintenanceModeDisabled::class => [ MaintenanceModeDisabledNotification::class, ], - ProxyStarted::class => [ + \SocialiteProviders\Manager\SocialiteWasCalled::class => [ + \SocialiteProviders\Azure\AzureExtendSocialite::class.'@handle', + ], + ProxyStarted::class => [ ProxyStartedNotification::class, ], ]; diff --git a/app/Providers/FortifyServiceProvider.php b/app/Providers/FortifyServiceProvider.php index 77de80885..6bb284eef 100644 --- a/app/Providers/FortifyServiceProvider.php +++ b/app/Providers/FortifyServiceProvider.php @@ -7,6 +7,7 @@ use App\Actions\Fortify\UpdateUserPassword; use App\Actions\Fortify\UpdateUserProfileInformation; use App\Models\InstanceSettings; +use App\Models\OauthSetting; use App\Models\User; use Illuminate\Cache\RateLimiting\Limit; use Illuminate\Http\Request; @@ -56,13 +57,15 @@ public function boot(): void Fortify::loginView(function () { $settings = InstanceSettings::get(); + $enabled_oauth_providers = OauthSetting::where('enabled', true)->get(); $users = User::count(); if ($users == 0) { // If there are no users, redirect to registration return redirect()->route('register'); } return view('auth.login', [ - 'is_registration_enabled' => $settings->is_registration_enabled + 'is_registration_enabled' => $settings->is_registration_enabled, + 'enabled_oauth_providers' => $enabled_oauth_providers, ]); }); diff --git a/app/View/Components/Forms/Button.php b/app/View/Components/Forms/Button.php index c9f4ebdc0..06681910e 100644 --- a/app/View/Components/Forms/Button.php +++ b/app/View/Components/Forms/Button.php @@ -13,10 +13,9 @@ class Button extends Component */ public function __construct( public bool $disabled = false, - public bool $isModal = false, public bool $noStyle = false, public ?string $modalId = null, - public string $defaultClass = "btn btn-primary btn-sm font-normal text-white normal-case no-animation rounded border-none" + public string $defaultClass = "button" ) { if ($this->noStyle) { $this->defaultClass = ""; diff --git a/app/View/Components/Forms/Checkbox.php b/app/View/Components/Forms/Checkbox.php index 0bbbc1e04..95fe2d4f4 100644 --- a/app/View/Components/Forms/Checkbox.php +++ b/app/View/Components/Forms/Checkbox.php @@ -12,14 +12,14 @@ class Checkbox extends Component * Create a new component instance. */ public function __construct( - public string|null $id = null, - public string|null $name = null, - public string|null $value = null, - public string|null $label = null, - public string|null $helper = null, - public string|bool $instantSave = false, + public ?string $id = null, + public ?string $name = null, + public ?string $value = null, + public ?string $label = null, + public ?string $helper = null, + public string|bool $instantSave = false, public bool $disabled = false, - public string $defaultClass = "toggle toggle-xs toggle-warning rounded disabled:bg-coolgray-200 disabled:opacity-50 placeholder:text-neutral-700", + public string $defaultClass = "dark:border-neutral-700 text-coolgray-400 focus:ring-warning dark:bg-coolgray-100 rounded cursor-pointer dark:disabled:bg-base dark:disabled:cursor-not-allowed", ) { // } diff --git a/app/View/Components/Forms/Input.php b/app/View/Components/Forms/Input.php index a55f9b9d2..45f8e9678 100644 --- a/app/View/Components/Forms/Input.php +++ b/app/View/Components/Forms/Input.php @@ -21,7 +21,7 @@ public function __construct( public ?string $helper = null, public bool $allowToPeak = true, public bool $isMultiline = false, - public string $defaultClass = "input input-sm bg-coolgray-100 rounded text-white w-full disabled:bg-coolgray-200/50 disabled:border-none placeholder:text-coolgray-500 read-only:text-neutral-500 read-only:bg-coolgray-200/50" + public string $defaultClass = "input", ) { } @@ -29,7 +29,9 @@ public function render(): View|Closure|string { if (is_null($this->id)) $this->id = new Cuid2(7); if (is_null($this->name)) $this->name = $this->id; - + if ($this->type === 'password') { + $this->defaultClass = $this->defaultClass . " pr-[2.8rem]"; + } // $this->label = Str::title($this->label); return view('components.forms.input'); } diff --git a/app/View/Components/Forms/Select.php b/app/View/Components/Forms/Select.php index e1f2fc759..40279bea6 100644 --- a/app/View/Components/Forms/Select.php +++ b/app/View/Components/Forms/Select.php @@ -14,12 +14,12 @@ class Select extends Component * Create a new component instance. */ public function __construct( - public string|null $id = null, - public string|null $name = null, - public string|null $label = null, - public string|null $helper = null, - public bool $required = false, - public string $defaultClass = "select select-sm w-full rounded text-sm bg-coolgray-100 font-normal disabled:bg-coolgray-200/50 disabled:border-none" + public ?string $id = null, + public ?string $name = null, + public ?string $label = null, + public ?string $helper = null, + public bool $required = false, + public string $defaultClass = "select" ) { // } diff --git a/app/View/Components/Forms/Textarea.php b/app/View/Components/Forms/Textarea.php index 8c50af533..95e0ef5d2 100644 --- a/app/View/Components/Forms/Textarea.php +++ b/app/View/Components/Forms/Textarea.php @@ -25,8 +25,8 @@ public function __construct( public ?string $helper = null, public bool $realtimeValidation = false, public bool $allowToPeak = true, - public string $defaultClass = "textarea leading-normal bg-coolgray-100 rounded text-white w-full scrollbar disabled:bg-coolgray-200/50 disabled:border-none placeholder:text-coolgray-500 read-only:text-neutral-500 read-only:bg-coolgray-200/50", - public string $defaultClassInput = "input input-sm bg-coolgray-100 rounded text-white w-full disabled:bg-coolgray-200/50 disabled:border-none placeholder:text-coolgray-500 read-only:text-neutral-500 read-only:bg-coolgray-200/50" + public string $defaultClass = "input scrollbar", + public string $defaultClassInput = "input" ) { // } diff --git a/bootstrap/helpers/api.php b/bootstrap/helpers/api.php index 4fcdbac4f..46c0caa0a 100644 --- a/bootstrap/helpers/api.php +++ b/bootstrap/helpers/api.php @@ -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); } diff --git a/bootstrap/helpers/constants.php b/bootstrap/helpers/constants.php index 134cc6aad..84997d134 100644 --- a/bootstrap/helpers/constants.php +++ b/bootstrap/helpers/constants.php @@ -27,7 +27,8 @@ 'couchdb', 'neo4j', 'influxdb', - 'clickhouse/clickhouse-server' + 'clickhouse/clickhouse-server', + 'supabase/postgres' ]; const SPECIFIC_SERVICES = [ 'quay.io/minio/minio', diff --git a/bootstrap/helpers/services.php b/bootstrap/helpers/services.php index dd05c67eb..7cb8595db 100644 --- a/bootstrap/helpers/services.php +++ b/bootstrap/helpers/services.php @@ -94,7 +94,7 @@ function updateCompose(ServiceApplication|ServiceDatabase $resource) $resource->service->docker_compose_raw = $dockerComposeRaw; $resource->service->save(); - if (!str($resource->fqdn)->contains(',')) { + if ($resource->fqdn && !str($resource->fqdn)->contains(',')) { // Update FQDN $variableName = "SERVICE_FQDN_" . Str::of($resource->name)->upper(); $generatedEnv = EnvironmentVariable::where('service_id', $resource->service_id)->where('key', $variableName)->first(); diff --git a/bootstrap/helpers/shared.php b/bootstrap/helpers/shared.php index c9f98e48a..023a65107 100644 --- a/bootstrap/helpers/shared.php +++ b/bootstrap/helpers/shared.php @@ -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."; } @@ -280,6 +280,10 @@ function base_url(bool $withPort = true): string return url('/'); } +function isSubscribed() +{ + return auth()->user()->currentTeam()->subscription()->exists() || auth()->user()->isInstanceAdmin(); +} function isDev(): bool { return config('app.env') === 'local'; @@ -429,7 +433,7 @@ function sslip(Server $server) function getServiceTemplates() { - if (isDev()) { + if (!isDev()) { $services = File::get(base_path('templates/service-templates.json')); $services = collect(json_decode($services))->sortKeys(); } else { @@ -444,13 +448,6 @@ function getServiceTemplates() $services = collect([]); } } - // $version = config('version'); - // $services = $services->map(function ($service) use ($version) { - // if (version_compare($version, data_get($service, 'minVersion', '0.0.0'), '<')) { - // $service->disabled = true; - // } - // return $service; - // }); return $services; } @@ -947,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([ @@ -963,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([ @@ -1001,61 +996,63 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal 'service_id' => $resource->id, ])->first(); ['command' => $command, 'forService' => $forService, 'generatedValue' => $generatedValue, 'port' => $port] = parseEnvVariable($value); - if ($command?->value() === 'FQDN' || $command?->value() === 'URL') { - if (Str::lower($forService) === $serviceName) { - $fqdn = generateFqdn($resource->server, $containerName); - } else { - $fqdn = generateFqdn($resource->server, Str::lower($forService) . '-' . $resource->uuid); - } - if ($port) { - $fqdn = "$fqdn:$port"; - } - if ($foundEnv) { - $fqdn = data_get($foundEnv, 'value'); - } else { - if ($command->value() === 'URL') { - $fqdn = Str::of($fqdn)->after('://')->value(); + if (!is_null($command)) { + if ($command?->value() === 'FQDN' || $command?->value() === 'URL') { + if (Str::lower($forService) === $serviceName) { + $fqdn = generateFqdn($resource->server, $containerName); + } else { + $fqdn = generateFqdn($resource->server, Str::lower($forService) . '-' . $resource->uuid); } - EnvironmentVariable::create([ - 'key' => $key, - 'value' => $fqdn, - 'is_build_time' => false, - 'service_id' => $resource->id, - 'is_preview' => false, - ]); - } - if (!$isDatabase) { - if ($command->value() === 'FQDN' && is_null($savedService->fqdn) && !$foundEnv) { - $savedService->fqdn = $fqdn; - $savedService->save(); + if ($port) { + $fqdn = "$fqdn:$port"; } - // Caddy needs exact port in some cases. - if ($predefinedPort && !$key->endsWith("_{$predefinedPort}") && $command?->value() === 'FQDN' && $resource->server->proxyType() === 'CADDY') { - $env = EnvironmentVariable::where([ + if ($foundEnv) { + $fqdn = data_get($foundEnv, 'value'); + } else { + if ($command->value() === 'URL') { + $fqdn = Str::of($fqdn)->after('://')->value(); + } + EnvironmentVariable::create([ 'key' => $key, + 'value' => $fqdn, + 'is_build_time' => false, 'service_id' => $resource->id, - ])->first(); - if ($env) { - $env_url = Url::fromString($env->value); - $env_port = $env_url->getPort(); - if ($env_port !== $predefinedPort) { - $env_url = $env_url->withPort($predefinedPort); - $savedService->fqdn = $env_url->__toString(); - $savedService->save(); + 'is_preview' => false, + ]); + } + if (!$isDatabase) { + if ($command->value() === 'FQDN' && is_null($savedService->fqdn) && !$foundEnv) { + $savedService->fqdn = $fqdn; + $savedService->save(); + } + // Caddy needs exact port in some cases. + if ($predefinedPort && !$key->endsWith("_{$predefinedPort}") && $command?->value() === 'FQDN' && $resource->server->proxyType() === 'CADDY') { + $env = EnvironmentVariable::where([ + 'key' => $key, + 'service_id' => $resource->id, + ])->first(); + if ($env) { + $env_url = Url::fromString($env->value); + $env_port = $env_url->getPort(); + if ($env_port !== $predefinedPort) { + $env_url = $env_url->withPort($predefinedPort); + $savedService->fqdn = $env_url->__toString(); + $savedService->save(); + } } } } - } - } else { - $generatedValue = generateEnvValue($command, $resource); - if (!$foundEnv) { - EnvironmentVariable::create([ - 'key' => $key, - 'value' => $generatedValue, - 'is_build_time' => false, - 'service_id' => $resource->id, - 'is_preview' => false, - ]); + } else { + $generatedValue = generateEnvValue($command, $resource); + if (!$foundEnv) { + EnvironmentVariable::create([ + 'key' => $key, + 'value' => $generatedValue, + 'is_build_time' => false, + 'service_id' => $resource->id, + 'is_preview' => false, + ]); + } } } } else { @@ -1240,84 +1237,94 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal } $baseName = generateApplicationContainerName($resource, $pull_request_id); $containerName = "$serviceName-$baseName"; - if ($pull_request_id !== 0) { - if (count($serviceVolumes) > 0) { - $serviceVolumes = $serviceVolumes->map(function ($volume) use ($resource, $pull_request_id, $topLevelVolumes) { - if (is_string($volume)) { - $volume = str($volume); - if ($volume->contains(':') && !$volume->startsWith('/')) { - $name = $volume->before(':'); - $mount = $volume->after(':'); - $newName = $resource->uuid . "-{$name}-pr-$pull_request_id"; - $volume = str("$newName:$mount"); - $topLevelVolumes->put($newName, [ - 'name' => $newName, - ]); - } - } else if (is_array($volume)) { - $source = data_get($volume, 'source'); - if ($source) { - $newSource = $resource->uuid . "-{$source}-pr-$pull_request_id"; - data_set($volume, 'source', $newSource); - if (!str($source)->startsWith('/')) { - $topLevelVolumes->put($newSource, [ - 'name' => $newSource, - ]); + if (count($serviceVolumes) > 0) { + $serviceVolumes = $serviceVolumes->map(function ($volume) use ($resource, $topLevelVolumes, $pull_request_id) { + if (is_string($volume)) { + $volume = str($volume); + if ($volume->contains(':') && !$volume->startsWith('/')) { + $name = $volume->before(':'); + $mount = $volume->after(':'); + if ($name->startsWith('.') || $name->startsWith('~')) { + $dir = base_configuration_dir() . '/applications/' . $resource->uuid; + if ($name->startsWith('.')) { + $name = $name->replaceFirst('.', $dir); } - } - } - return $volume->value(); - }); - data_set($service, 'volumes', $serviceVolumes->toArray()); - } - } else { - if (count($serviceVolumes) > 0) { - $serviceVolumes = $serviceVolumes->map(function ($volume) use ($resource, $topLevelVolumes) { - if (is_string($volume)) { - $volume = str($volume); - if ($volume->contains(':') && !$volume->startsWith('/')) { - $name = $volume->before(':'); - $mount = $volume->after(':'); - if ($name->startsWith('.') || $name->startsWith('~')) { - $dir = base_configuration_dir() . '/applications/' . $resource->uuid; - if ($name->startsWith('.')) { - $name = $name->replaceFirst('.', $dir); - } - if ($name->startsWith('~')) { - $name = $name->replaceFirst('~', $dir); - } + if ($name->startsWith('~')) { + $name = $name->replaceFirst('~', $dir); + } + if ($pull_request_id !== 0) { + $name = $name . "-pr-$pull_request_id"; + } + $volume = str("$name:$mount"); + } else { + if ($pull_request_id !== 0) { + $name = $name . "-pr-$pull_request_id"; $volume = str("$name:$mount"); + $topLevelVolumes->put($name, [ + 'name' => $name, + ]); } else { $topLevelVolumes->put($name->value(), [ 'name' => $name->value(), ]); } } - } else if (is_array($volume)) { - $source = data_get($volume, 'source'); - if ($source) { - if ((str($source)->startsWith('.') || str($source)->startsWith('~')) && !str($source)->startsWith('/')) { - $dir = base_configuration_dir() . '/applications/' . $resource->uuid; - if (str($source, '.')) { - $source = str('.', $dir, $source); - } - if (str($source, '~')) { - $source = str('~', $dir, $source); - } - data_set($volume, 'source', $source); + } else { + if ($volume->startsWith('/')) { + $name = $volume->before(':'); + $mount = $volume->after(':'); + if ($pull_request_id !== 0) { + $name = $name . "-pr-$pull_request_id"; + } + $volume = str("$name:$mount"); + } + } + } else if (is_array($volume)) { + $source = data_get($volume, 'source'); + $target = data_get($volume, 'target'); + $read_only = data_get($volume, 'read_only'); + if ($source && $target) { + if ((str($source)->startsWith('.') || str($source)->startsWith('~'))) { + $dir = base_configuration_dir() . '/applications/' . $resource->uuid; + if (str($source, '.')) { + $source = str($source)->replaceFirst('.', $dir); + } + if (str($source, '~')) { + $source = str($source)->replaceFirst('~', $dir); + } + if ($pull_request_id !== 0) { + $source = $source . "-pr-$pull_request_id"; + } + if ($read_only) { + data_set($volume, 'source', $source . ':' . $target . ':ro'); } else { - data_set($volume, 'source', $source); + data_set($volume, 'source', $source . ':' . $target); + } + } else { + if ($pull_request_id !== 0) { + $source = $source . "-pr-$pull_request_id"; + } + if ($read_only) { + data_set($volume, 'source', $source . ':' . $target . ':ro'); + } else { + data_set($volume, 'source', $source . ':' . $target); + } + if (!str($source)->startsWith('/')) { $topLevelVolumes->put($source, [ 'name' => $source, ]); } } } - return $volume->value(); - }); - data_set($service, 'volumes', $serviceVolumes->toArray()); - } + } + if (is_array($volume)) { + return data_get($volume, 'source'); + } + return $volume->value(); + }); + data_set($service, 'volumes', $serviceVolumes->toArray()); } + // Decide if the service is a database $isDatabase = isDatabaseImage(data_get_str($service, 'image')); data_set($service, 'is_database', $isDatabase); @@ -1450,46 +1457,48 @@ 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); - if ($command?->value() === 'FQDN' || $command?->value() === 'URL') { - if (Str::lower($forService) === $serviceName) { - $fqdn = generateFqdn($server, $containerName); - } else { - $fqdn = generateFqdn($server, Str::lower($forService) . '-' . $resource->uuid); - } - if ($port) { - $fqdn = "$fqdn:$port"; - } - if ($foundEnv) { - $fqdn = data_get($foundEnv, 'value'); - } else { - if ($command->value() === 'URL') { - $fqdn = Str::of($fqdn)->after('://')->value(); + ray($command, $generatedValue); + if (!is_null($command)) { + if ($command?->value() === 'FQDN' || $command?->value() === 'URL') { + if (Str::lower($forService) === $serviceName) { + $fqdn = generateFqdn($server, $containerName); + } else { + $fqdn = generateFqdn($server, Str::lower($forService) . '-' . $resource->uuid); + } + if ($port) { + $fqdn = "$fqdn:$port"; + } + if ($foundEnv) { + $fqdn = data_get($foundEnv, 'value'); + } else { + if ($command?->value() === 'URL') { + $fqdn = Str::of($fqdn)->after('://')->value(); + } + EnvironmentVariable::create([ + 'key' => $key, + 'value' => $fqdn, + 'is_build_time' => false, + 'application_id' => $resource->id, + 'is_preview' => false, + ]); + } + } else { + $generatedValue = generateEnvValue($command); + if (!$foundEnv) { + EnvironmentVariable::create([ + 'key' => $key, + 'value' => $generatedValue, + 'is_build_time' => false, + 'application_id' => $resource->id, + 'is_preview' => false, + ]); } - EnvironmentVariable::create([ - 'key' => $key, - 'value' => $fqdn, - 'is_build_time' => false, - 'application_id' => $resource->id, - 'is_preview' => false, - ]); - } - } else { - $generatedValue = generateEnvValue($command); - if (!$foundEnv) { - EnvironmentVariable::create([ - 'key' => $key, - 'value' => $generatedValue, - 'is_build_time' => false, - 'application_id' => $resource->id, - 'is_preview' => false, - ]); } } } else { @@ -1602,6 +1611,12 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal return $service; }); + if ($pull_request_id !== 0) { + $services->each(function ($service, $serviceName) use ($pull_request_id, $services) { + $services[$serviceName . "-pr-$pull_request_id"] = $service; + data_forget($services, $serviceName); + }); + } $finalServices = [ 'version' => $dockerComposeVersion, 'services' => $services->toArray(), @@ -1635,29 +1650,30 @@ function parseEnvVariable(Str|string $value) $forService = null; $generatedValue = null; $port = null; - - if ($count === 2) { - if ($value->startsWith('SERVICE_FQDN') || $value->startsWith('SERVICE_URL')) { - // SERVICE_FQDN_UMAMI - $command = $value->after('SERVICE_')->beforeLast('_'); - $forService = $value->afterLast('_'); - } else { - // SERVICE_BASE64_UMAMI - $command = $value->after('SERVICE_')->beforeLast('_'); - } - } - if ($count === 3) { - if ($value->startsWith('SERVICE_FQDN') || $value->startsWith('SERVICE_URL')) { - // SERVICE_FQDN_UMAMI_1000 - $command = $value->after('SERVICE_')->before('_'); - $forService = $value->after('SERVICE_')->after('_')->before('_'); - $port = $value->afterLast('_'); - if (filter_var($port, FILTER_VALIDATE_INT) === false) { - $port = null; + if ($value->startsWith('SERVICE')) { + if ($count === 2) { + if ($value->startsWith('SERVICE_FQDN') || $value->startsWith('SERVICE_URL')) { + // SERVICE_FQDN_UMAMI + $command = $value->after('SERVICE_')->beforeLast('_'); + $forService = $value->afterLast('_'); + } else { + // SERVICE_BASE64_UMAMI + $command = $value->after('SERVICE_')->beforeLast('_'); + } + } + if ($count === 3) { + if ($value->startsWith('SERVICE_FQDN') || $value->startsWith('SERVICE_URL')) { + // SERVICE_FQDN_UMAMI_1000 + $command = $value->after('SERVICE_')->before('_'); + $forService = $value->after('SERVICE_')->after('_')->before('_'); + $port = $value->afterLast('_'); + if (filter_var($port, FILTER_VALIDATE_INT) === false) { + $port = null; + } + } else { + // SERVICE_BASE64_64_UMAMI + $command = $value->after('SERVICE_')->beforeLast('_'); } - } else { - // SERVICE_BASE64_64_UMAMI - $command = $value->after('SERVICE_')->beforeLast('_'); } } return [ diff --git a/bootstrap/helpers/socialite.php b/bootstrap/helpers/socialite.php new file mode 100644 index 000000000..0798717e8 --- /dev/null +++ b/bootstrap/helpers/socialite.php @@ -0,0 +1,37 @@ +client_id, + $oauth_setting->client_secret, + $oauth_setting->redirect_uri, + ['tenant' => $oauth_setting->tenant], + ); + return Socialite::driver('azure')->setConfig($azure_config); + } + + $config = [ + 'client_id' => $oauth_setting->client_id, + 'client_secret' => $oauth_setting->client_secret, + 'redirect' => $oauth_setting->redirect_uri, + ]; + + $provider_class_map = [ + 'bitbucket' => \Laravel\Socialite\Two\BitbucketProvider::class, + 'github' => \Laravel\Socialite\Two\GithubProvider::class, + 'gitlab' => \Laravel\Socialite\Two\GitlabProvider::class, + 'google' => \Laravel\Socialite\Two\GoogleProvider::class, + ]; + + return Socialite::buildProvider( + $provider_class_map[$provider], + $config + ); +} diff --git a/composer.json b/composer.json index f762ed579..b57263534 100644 --- a/composer.json +++ b/composer.json @@ -17,6 +17,7 @@ "laravel/horizon": "^5.15", "laravel/prompts": "^0.1.6", "laravel/sanctum": "^v3.2.1", + "laravel/socialite": "^5.12", "laravel/tinker": "^v2.8.1", "laravel/ui": "^4.2", "lcobucci/jwt": "^5.0.0", @@ -31,6 +32,7 @@ "pusher/pusher-php-server": "^7.2", "resend/resend-laravel": "^0.5.0", "sentry/sentry-laravel": "^3.4", + "socialiteproviders/microsoft-azure": "^5.1", "spatie/laravel-activitylog": "^4.7.3", "spatie/laravel-data": "^3.4.3", "spatie/laravel-ray": "^1.32.4", @@ -39,7 +41,6 @@ "stripe/stripe-php": "^12.0", "symfony/yaml": "^6.2", "visus/cuid2": "^2.0.0", - "wire-elements/modal": "^2.0", "yosymfony/toml": "^1.0" }, "require-dev": { diff --git a/composer.lock b/composer.lock index 74b27137f..91613ec5f 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "19b19082b605e09867e6ae65fb8135f6", + "content-hash": "e095b8a9eb22df2943cbc3e9649ff9e8", "packages": [ { "name": "amphp/amp", @@ -317,21 +317,22 @@ }, { "name": "amphp/parallel", - "version": "v2.2.6", + "version": "v2.2.9", "source": { "type": "git", "url": "https://github.com/amphp/parallel.git", - "reference": "5aeaad20297507cc754859236720501b54306eba" + "reference": "73d293f1fc4df1bebc3c4fce1432e82dd7032238" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/amphp/parallel/zipball/5aeaad20297507cc754859236720501b54306eba", - "reference": "5aeaad20297507cc754859236720501b54306eba", + "url": "https://api.github.com/repos/amphp/parallel/zipball/73d293f1fc4df1bebc3c4fce1432e82dd7032238", + "reference": "73d293f1fc4df1bebc3c4fce1432e82dd7032238", "shasum": "" }, "require": { "amphp/amp": "^3", "amphp/byte-stream": "^2", + "amphp/cache": "^2", "amphp/parser": "^1", "amphp/pipeline": "^1", "amphp/process": "^2", @@ -388,7 +389,7 @@ ], "support": { "issues": "https://github.com/amphp/parallel/issues", - "source": "https://github.com/amphp/parallel/tree/v2.2.6" + "source": "https://github.com/amphp/parallel/tree/v2.2.9" }, "funding": [ { @@ -396,20 +397,20 @@ "type": "github" } ], - "time": "2024-01-07T18:12:13+00:00" + "time": "2024-03-24T18:27:44+00:00" }, { "name": "amphp/parser", - "version": "v1.1.0", + "version": "v1.1.1", "source": { "type": "git", "url": "https://github.com/amphp/parser.git", - "reference": "ff1de4144726c5dad5fab97f66692ebe8de3e151" + "reference": "3cf1f8b32a0171d4b1bed93d25617637a77cded7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/amphp/parser/zipball/ff1de4144726c5dad5fab97f66692ebe8de3e151", - "reference": "ff1de4144726c5dad5fab97f66692ebe8de3e151", + "url": "https://api.github.com/repos/amphp/parser/zipball/3cf1f8b32a0171d4b1bed93d25617637a77cded7", + "reference": "3cf1f8b32a0171d4b1bed93d25617637a77cded7", "shasum": "" }, "require": { @@ -450,7 +451,7 @@ ], "support": { "issues": "https://github.com/amphp/parser/issues", - "source": "https://github.com/amphp/parser/tree/v1.1.0" + "source": "https://github.com/amphp/parser/tree/v1.1.1" }, "funding": [ { @@ -458,20 +459,20 @@ "type": "github" } ], - "time": "2022-12-30T18:08:47+00:00" + "time": "2024-03-21T19:16:53+00:00" }, { "name": "amphp/pipeline", - "version": "v1.1.0", + "version": "v1.2.0", "source": { "type": "git", "url": "https://github.com/amphp/pipeline.git", - "reference": "8a0ecc281bb0932d6b4a786453aff18c55756e63" + "reference": "f1c2ce35d27ae86ead018adb803eccca7421dd9b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/amphp/pipeline/zipball/8a0ecc281bb0932d6b4a786453aff18c55756e63", - "reference": "8a0ecc281bb0932d6b4a786453aff18c55756e63", + "url": "https://api.github.com/repos/amphp/pipeline/zipball/f1c2ce35d27ae86ead018adb803eccca7421dd9b", + "reference": "f1c2ce35d27ae86ead018adb803eccca7421dd9b", "shasum": "" }, "require": { @@ -517,7 +518,7 @@ ], "support": { "issues": "https://github.com/amphp/pipeline/issues", - "source": "https://github.com/amphp/pipeline/tree/v1.1.0" + "source": "https://github.com/amphp/pipeline/tree/v1.2.0" }, "funding": [ { @@ -525,7 +526,7 @@ "type": "github" } ], - "time": "2023-12-23T04:34:28+00:00" + "time": "2024-03-10T14:48:16+00:00" }, { "name": "amphp/process", @@ -655,16 +656,16 @@ }, { "name": "amphp/socket", - "version": "v2.2.4", + "version": "v2.3.0", "source": { "type": "git", "url": "https://github.com/amphp/socket.git", - "reference": "4223324c627cc26d44800630411e64856d3344bc" + "reference": "acc0a2f65ab498025ba5641f7cce499c4b1ed4b5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/amphp/socket/zipball/4223324c627cc26d44800630411e64856d3344bc", - "reference": "4223324c627cc26d44800630411e64856d3344bc", + "url": "https://api.github.com/repos/amphp/socket/zipball/acc0a2f65ab498025ba5641f7cce499c4b1ed4b5", + "reference": "acc0a2f65ab498025ba5641f7cce499c4b1ed4b5", "shasum": "" }, "require": { @@ -727,7 +728,7 @@ ], "support": { "issues": "https://github.com/amphp/socket/issues", - "source": "https://github.com/amphp/socket/tree/v2.2.4" + "source": "https://github.com/amphp/socket/tree/v2.3.0" }, "funding": [ { @@ -735,20 +736,20 @@ "type": "github" } ], - "time": "2024-02-28T15:56:06+00:00" + "time": "2024-03-19T20:01:53+00:00" }, { "name": "amphp/sync", - "version": "v2.1.0", + "version": "v2.2.0", "source": { "type": "git", "url": "https://github.com/amphp/sync.git", - "reference": "50ddc7392cc8034b3e4798cef3cc90d3f4c0441c" + "reference": "375ef5b54a0d12c38e12728dde05a55e30f2fbec" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/amphp/sync/zipball/50ddc7392cc8034b3e4798cef3cc90d3f4c0441c", - "reference": "50ddc7392cc8034b3e4798cef3cc90d3f4c0441c", + "url": "https://api.github.com/repos/amphp/sync/zipball/375ef5b54a0d12c38e12728dde05a55e30f2fbec", + "reference": "375ef5b54a0d12c38e12728dde05a55e30f2fbec", "shasum": "" }, "require": { @@ -762,7 +763,7 @@ "amphp/php-cs-fixer-config": "^2", "amphp/phpunit-util": "^3", "phpunit/phpunit": "^9", - "psalm/phar": "^5.4" + "psalm/phar": "5.23" }, "type": "library", "autoload": { @@ -802,7 +803,7 @@ ], "support": { "issues": "https://github.com/amphp/sync/issues", - "source": "https://github.com/amphp/sync/tree/v2.1.0" + "source": "https://github.com/amphp/sync/tree/v2.2.0" }, "funding": [ { @@ -810,7 +811,7 @@ "type": "github" } ], - "time": "2023-08-19T13:53:40+00:00" + "time": "2024-03-12T01:00:01+00:00" }, { "name": "amphp/windows-registry", @@ -920,16 +921,16 @@ }, { "name": "aws/aws-sdk-php", - "version": "3.300.10", + "version": "3.301.6", "source": { "type": "git", "url": "https://github.com/aws/aws-sdk-php.git", - "reference": "b24bf7882fed0ef029996dcdcba6c273b69db8fe" + "reference": "18c0ebd71d3071304f1ea02aa9af75f95863177a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/b24bf7882fed0ef029996dcdcba6c273b69db8fe", - "reference": "b24bf7882fed0ef029996dcdcba6c273b69db8fe", + "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/18c0ebd71d3071304f1ea02aa9af75f95863177a", + "reference": "18c0ebd71d3071304f1ea02aa9af75f95863177a", "shasum": "" }, "require": { @@ -1009,9 +1010,9 @@ "support": { "forum": "https://forums.aws.amazon.com/forum.jspa?forumID=80", "issues": "https://github.com/aws/aws-sdk-php/issues", - "source": "https://github.com/aws/aws-sdk-php/tree/3.300.10" + "source": "https://github.com/aws/aws-sdk-php/tree/3.301.6" }, - "time": "2024-03-04T19:06:07+00:00" + "time": "2024-03-22T18:05:21+00:00" }, { "name": "bacon/bacon-qr-code", @@ -2724,16 +2725,16 @@ }, { "name": "jean85/pretty-package-versions", - "version": "2.0.5", + "version": "2.0.6", "source": { "type": "git", "url": "https://github.com/Jean85/pretty-package-versions.git", - "reference": "ae547e455a3d8babd07b96966b17d7fd21d9c6af" + "reference": "f9fdd29ad8e6d024f52678b570e5593759b550b4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Jean85/pretty-package-versions/zipball/ae547e455a3d8babd07b96966b17d7fd21d9c6af", - "reference": "ae547e455a3d8babd07b96966b17d7fd21d9c6af", + "url": "https://api.github.com/repos/Jean85/pretty-package-versions/zipball/f9fdd29ad8e6d024f52678b570e5593759b550b4", + "reference": "f9fdd29ad8e6d024f52678b570e5593759b550b4", "shasum": "" }, "require": { @@ -2741,9 +2742,9 @@ "php": "^7.1|^8.0" }, "require-dev": { - "friendsofphp/php-cs-fixer": "^2.17", + "friendsofphp/php-cs-fixer": "^3.2", "jean85/composer-provided-replaced-stub-package": "^1.0", - "phpstan/phpstan": "^0.12.66", + "phpstan/phpstan": "^1.4", "phpunit/phpunit": "^7.5|^8.5|^9.4", "vimeo/psalm": "^4.3" }, @@ -2777,9 +2778,9 @@ ], "support": { "issues": "https://github.com/Jean85/pretty-package-versions/issues", - "source": "https://github.com/Jean85/pretty-package-versions/tree/2.0.5" + "source": "https://github.com/Jean85/pretty-package-versions/tree/2.0.6" }, - "time": "2021-10-08T21:21:46+00:00" + "time": "2024-03-08T09:58:59+00:00" }, { "name": "kelunik/certificate", @@ -2841,16 +2842,16 @@ }, { "name": "laravel/fortify", - "version": "v1.20.1", + "version": "v1.21.0", "source": { "type": "git", "url": "https://github.com/laravel/fortify.git", - "reference": "ab1a76991a32be21448156419ddc7eb4731b0a8b" + "reference": "b34e672e1d341f6e520f81712f73e56f6cb80767" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/fortify/zipball/ab1a76991a32be21448156419ddc7eb4731b0a8b", - "reference": "ab1a76991a32be21448156419ddc7eb4731b0a8b", + "url": "https://api.github.com/repos/laravel/fortify/zipball/b34e672e1d341f6e520f81712f73e56f6cb80767", + "reference": "b34e672e1d341f6e520f81712f73e56f6cb80767", "shasum": "" }, "require": { @@ -2901,20 +2902,20 @@ "issues": "https://github.com/laravel/fortify/issues", "source": "https://github.com/laravel/fortify" }, - "time": "2024-02-08T14:36:46+00:00" + "time": "2024-03-08T19:55:45+00:00" }, { "name": "laravel/framework", - "version": "v10.46.0", + "version": "v10.48.4", "source": { "type": "git", "url": "https://github.com/laravel/framework.git", - "reference": "5e95946a8283a8d5c015035793f9c61c297e937f" + "reference": "7e0701bf59cb76a51f7c1f7bea51c0c0c29c0b72" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/framework/zipball/5e95946a8283a8d5c015035793f9c61c297e937f", - "reference": "5e95946a8283a8d5c015035793f9c61c297e937f", + "url": "https://api.github.com/repos/laravel/framework/zipball/7e0701bf59cb76a51f7c1f7bea51c0c0c29c0b72", + "reference": "7e0701bf59cb76a51f7c1f7bea51c0c0c29c0b72", "shasum": "" }, "require": { @@ -2962,6 +2963,7 @@ "conflict": { "carbonphp/carbon-doctrine-types": ">=3.0", "doctrine/dbal": ">=4.0", + "mockery/mockery": "1.6.8", "phpunit/phpunit": ">=11.0.0", "tightenco/collect": "<5.5.33" }, @@ -3018,7 +3020,7 @@ "league/flysystem-sftp-v3": "^3.0", "mockery/mockery": "^1.5.1", "nyholm/psr7": "^1.2", - "orchestra/testbench-core": "^8.18", + "orchestra/testbench-core": "^8.23.4", "pda/pheanstalk": "^4.0", "phpstan/phpstan": "^1.4.7", "phpunit/phpunit": "^10.0.7", @@ -3107,7 +3109,7 @@ "issues": "https://github.com/laravel/framework/issues", "source": "https://github.com/laravel/framework" }, - "time": "2024-02-27T16:46:54+00:00" + "time": "2024-03-21T13:36:36+00:00" }, { "name": "laravel/horizon", @@ -3370,6 +3372,76 @@ }, "time": "2023-11-08T14:08:06+00:00" }, + { + "name": "laravel/socialite", + "version": "v5.12.1", + "source": { + "type": "git", + "url": "https://github.com/laravel/socialite.git", + "reference": "7dae1b072573809f32ab6dcf4aebb57c8b3e8acf" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laravel/socialite/zipball/7dae1b072573809f32ab6dcf4aebb57c8b3e8acf", + "reference": "7dae1b072573809f32ab6dcf4aebb57c8b3e8acf", + "shasum": "" + }, + "require": { + "ext-json": "*", + "guzzlehttp/guzzle": "^6.0|^7.0", + "illuminate/contracts": "^6.0|^7.0|^8.0|^9.0|^10.0|^11.0", + "illuminate/http": "^6.0|^7.0|^8.0|^9.0|^10.0|^11.0", + "illuminate/support": "^6.0|^7.0|^8.0|^9.0|^10.0|^11.0", + "league/oauth1-client": "^1.10.1", + "php": "^7.2|^8.0" + }, + "require-dev": { + "mockery/mockery": "^1.0", + "orchestra/testbench": "^4.0|^5.0|^6.0|^7.0|^8.0|^9.0", + "phpstan/phpstan": "^1.10", + "phpunit/phpunit": "^8.0|^9.3|^10.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.x-dev" + }, + "laravel": { + "providers": [ + "Laravel\\Socialite\\SocialiteServiceProvider" + ], + "aliases": { + "Socialite": "Laravel\\Socialite\\Facades\\Socialite" + } + } + }, + "autoload": { + "psr-4": { + "Laravel\\Socialite\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Taylor Otwell", + "email": "taylor@laravel.com" + } + ], + "description": "Laravel wrapper around OAuth 1 & OAuth 2 libraries.", + "homepage": "https://laravel.com", + "keywords": [ + "laravel", + "oauth" + ], + "support": { + "issues": "https://github.com/laravel/socialite/issues", + "source": "https://github.com/laravel/socialite" + }, + "time": "2024-02-16T08:58:20+00:00" + }, { "name": "laravel/tinker", "version": "v2.9.0", @@ -3438,16 +3510,16 @@ }, { "name": "laravel/ui", - "version": "v4.4.0", + "version": "v4.5.0", "source": { "type": "git", "url": "https://github.com/laravel/ui.git", - "reference": "7335d7049b2cde345c029e9d2de839b80af62bc0" + "reference": "da3811f409297d13feccd5858ce748e7474b3d11" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/ui/zipball/7335d7049b2cde345c029e9d2de839b80af62bc0", - "reference": "7335d7049b2cde345c029e9d2de839b80af62bc0", + "url": "https://api.github.com/repos/laravel/ui/zipball/da3811f409297d13feccd5858ce748e7474b3d11", + "reference": "da3811f409297d13feccd5858ce748e7474b3d11", "shasum": "" }, "require": { @@ -3458,8 +3530,8 @@ "php": "^8.0" }, "require-dev": { - "orchestra/testbench": "^7.0|^8.0|^9.0", - "phpunit/phpunit": "^9.3|^10.4" + "orchestra/testbench": "^7.35|^8.15|^9.0", + "phpunit/phpunit": "^9.3|^10.4|^11.0" }, "type": "library", "extra": { @@ -3494,9 +3566,9 @@ "ui" ], "support": { - "source": "https://github.com/laravel/ui/tree/v4.4.0" + "source": "https://github.com/laravel/ui/tree/v4.5.0" }, - "time": "2024-01-12T15:56:45+00:00" + "time": "2024-03-04T13:58:27+00:00" }, { "name": "lcobucci/jwt", @@ -3761,16 +3833,16 @@ }, { "name": "league/flysystem", - "version": "3.24.0", + "version": "3.25.1", "source": { "type": "git", "url": "https://github.com/thephpleague/flysystem.git", - "reference": "b25a361508c407563b34fac6f64a8a17a8819675" + "reference": "abbd664eb4381102c559d358420989f835208f18" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/b25a361508c407563b34fac6f64a8a17a8819675", - "reference": "b25a361508c407563b34fac6f64a8a17a8819675", + "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/abbd664eb4381102c559d358420989f835208f18", + "reference": "abbd664eb4381102c559d358420989f835208f18", "shasum": "" }, "require": { @@ -3798,7 +3870,7 @@ "friendsofphp/php-cs-fixer": "^3.5", "google/cloud-storage": "^1.23", "microsoft/azure-storage-blob": "^1.1", - "phpseclib/phpseclib": "^3.0.34", + "phpseclib/phpseclib": "^3.0.36", "phpstan/phpstan": "^1.10", "phpunit/phpunit": "^9.5.11|^10.0", "sabre/dav": "^4.6.0" @@ -3835,7 +3907,7 @@ ], "support": { "issues": "https://github.com/thephpleague/flysystem/issues", - "source": "https://github.com/thephpleague/flysystem/tree/3.24.0" + "source": "https://github.com/thephpleague/flysystem/tree/3.25.1" }, "funding": [ { @@ -3847,20 +3919,20 @@ "type": "github" } ], - "time": "2024-02-04T12:10:17+00:00" + "time": "2024-03-16T12:53:19+00:00" }, { "name": "league/flysystem-aws-s3-v3", - "version": "3.24.0", + "version": "3.25.1", "source": { "type": "git", "url": "https://github.com/thephpleague/flysystem-aws-s3-v3.git", - "reference": "809474e37b7fb1d1f8bcc0f8a98bc1cae99aa513" + "reference": "6a5be0e6d6a93574e80805c9cc108a4b63c824d8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/flysystem-aws-s3-v3/zipball/809474e37b7fb1d1f8bcc0f8a98bc1cae99aa513", - "reference": "809474e37b7fb1d1f8bcc0f8a98bc1cae99aa513", + "url": "https://api.github.com/repos/thephpleague/flysystem-aws-s3-v3/zipball/6a5be0e6d6a93574e80805c9cc108a4b63c824d8", + "reference": "6a5be0e6d6a93574e80805c9cc108a4b63c824d8", "shasum": "" }, "require": { @@ -3900,7 +3972,7 @@ "storage" ], "support": { - "source": "https://github.com/thephpleague/flysystem-aws-s3-v3/tree/3.24.0" + "source": "https://github.com/thephpleague/flysystem-aws-s3-v3/tree/3.25.1" }, "funding": [ { @@ -3912,20 +3984,20 @@ "type": "github" } ], - "time": "2024-01-26T18:43:21+00:00" + "time": "2024-03-15T19:58:44+00:00" }, { "name": "league/flysystem-local", - "version": "3.23.1", + "version": "3.25.1", "source": { "type": "git", "url": "https://github.com/thephpleague/flysystem-local.git", - "reference": "b884d2bf9b53bb4804a56d2df4902bb51e253f00" + "reference": "61a6a90d6e999e4ddd9ce5adb356de0939060b92" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/flysystem-local/zipball/b884d2bf9b53bb4804a56d2df4902bb51e253f00", - "reference": "b884d2bf9b53bb4804a56d2df4902bb51e253f00", + "url": "https://api.github.com/repos/thephpleague/flysystem-local/zipball/61a6a90d6e999e4ddd9ce5adb356de0939060b92", + "reference": "61a6a90d6e999e4ddd9ce5adb356de0939060b92", "shasum": "" }, "require": { @@ -3959,8 +4031,7 @@ "local" ], "support": { - "issues": "https://github.com/thephpleague/flysystem-local/issues", - "source": "https://github.com/thephpleague/flysystem-local/tree/3.23.1" + "source": "https://github.com/thephpleague/flysystem-local/tree/3.25.1" }, "funding": [ { @@ -3972,20 +4043,20 @@ "type": "github" } ], - "time": "2024-01-26T18:25:23+00:00" + "time": "2024-03-15T19:58:44+00:00" }, { "name": "league/flysystem-sftp-v3", - "version": "3.23.1", + "version": "3.25.1", "source": { "type": "git", "url": "https://github.com/thephpleague/flysystem-sftp-v3.git", - "reference": "09d001860d6642e2bed75f9d2f9e9fa931a3a6be" + "reference": "5cf169f33e4351832373f9d1b663c137589aa260" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/flysystem-sftp-v3/zipball/09d001860d6642e2bed75f9d2f9e9fa931a3a6be", - "reference": "09d001860d6642e2bed75f9d2f9e9fa931a3a6be", + "url": "https://api.github.com/repos/thephpleague/flysystem-sftp-v3/zipball/5cf169f33e4351832373f9d1b663c137589aa260", + "reference": "5cf169f33e4351832373f9d1b663c137589aa260", "shasum": "" }, "require": { @@ -4019,8 +4090,7 @@ "sftp" ], "support": { - "issues": "https://github.com/thephpleague/flysystem-sftp-v3/issues", - "source": "https://github.com/thephpleague/flysystem-sftp-v3/tree/3.23.1" + "source": "https://github.com/thephpleague/flysystem-sftp-v3/tree/3.25.1" }, "funding": [ { @@ -4032,7 +4102,7 @@ "type": "github" } ], - "time": "2024-01-26T18:25:23+00:00" + "time": "2024-03-16T11:44:18+00:00" }, { "name": "league/mime-type-detection", @@ -4091,17 +4161,93 @@ "time": "2024-01-28T23:22:08+00:00" }, { - "name": "league/uri", - "version": "7.4.0", + "name": "league/oauth1-client", + "version": "v1.10.1", "source": { "type": "git", - "url": "https://github.com/thephpleague/uri.git", - "reference": "bf414ba956d902f5d98bf9385fcf63954f09dce5" + "url": "https://github.com/thephpleague/oauth1-client.git", + "reference": "d6365b901b5c287dd41f143033315e2f777e1167" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/uri/zipball/bf414ba956d902f5d98bf9385fcf63954f09dce5", - "reference": "bf414ba956d902f5d98bf9385fcf63954f09dce5", + "url": "https://api.github.com/repos/thephpleague/oauth1-client/zipball/d6365b901b5c287dd41f143033315e2f777e1167", + "reference": "d6365b901b5c287dd41f143033315e2f777e1167", + "shasum": "" + }, + "require": { + "ext-json": "*", + "ext-openssl": "*", + "guzzlehttp/guzzle": "^6.0|^7.0", + "guzzlehttp/psr7": "^1.7|^2.0", + "php": ">=7.1||>=8.0" + }, + "require-dev": { + "ext-simplexml": "*", + "friendsofphp/php-cs-fixer": "^2.17", + "mockery/mockery": "^1.3.3", + "phpstan/phpstan": "^0.12.42", + "phpunit/phpunit": "^7.5||9.5" + }, + "suggest": { + "ext-simplexml": "For decoding XML-based responses." + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev", + "dev-develop": "2.0-dev" + } + }, + "autoload": { + "psr-4": { + "League\\OAuth1\\Client\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ben Corlett", + "email": "bencorlett@me.com", + "homepage": "http://www.webcomm.com.au", + "role": "Developer" + } + ], + "description": "OAuth 1.0 Client Library", + "keywords": [ + "Authentication", + "SSO", + "authorization", + "bitbucket", + "identity", + "idp", + "oauth", + "oauth1", + "single sign on", + "trello", + "tumblr", + "twitter" + ], + "support": { + "issues": "https://github.com/thephpleague/oauth1-client/issues", + "source": "https://github.com/thephpleague/oauth1-client/tree/v1.10.1" + }, + "time": "2022-04-15T14:02:14+00:00" + }, + { + "name": "league/uri", + "version": "7.4.1", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/uri.git", + "reference": "bedb6e55eff0c933668addaa7efa1e1f2c417cc4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/uri/zipball/bedb6e55eff0c933668addaa7efa1e1f2c417cc4", + "reference": "bedb6e55eff0c933668addaa7efa1e1f2c417cc4", "shasum": "" }, "require": { @@ -4170,7 +4316,7 @@ "docs": "https://uri.thephpleague.com", "forum": "https://thephpleague.slack.com", "issues": "https://github.com/thephpleague/uri-src/issues", - "source": "https://github.com/thephpleague/uri/tree/7.4.0" + "source": "https://github.com/thephpleague/uri/tree/7.4.1" }, "funding": [ { @@ -4178,20 +4324,20 @@ "type": "github" } ], - "time": "2023-12-01T06:24:25+00:00" + "time": "2024-03-23T07:42:40+00:00" }, { "name": "league/uri-interfaces", - "version": "7.4.0", + "version": "7.4.1", "source": { "type": "git", "url": "https://github.com/thephpleague/uri-interfaces.git", - "reference": "bd8c487ec236930f7bbc42b8d374fa882fbba0f3" + "reference": "8d43ef5c841032c87e2de015972c06f3865ef718" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/uri-interfaces/zipball/bd8c487ec236930f7bbc42b8d374fa882fbba0f3", - "reference": "bd8c487ec236930f7bbc42b8d374fa882fbba0f3", + "url": "https://api.github.com/repos/thephpleague/uri-interfaces/zipball/8d43ef5c841032c87e2de015972c06f3865ef718", + "reference": "8d43ef5c841032c87e2de015972c06f3865ef718", "shasum": "" }, "require": { @@ -4254,7 +4400,7 @@ "docs": "https://uri.thephpleague.com", "forum": "https://thephpleague.slack.com", "issues": "https://github.com/thephpleague/uri-src/issues", - "source": "https://github.com/thephpleague/uri-interfaces/tree/7.4.0" + "source": "https://github.com/thephpleague/uri-interfaces/tree/7.4.1" }, "funding": [ { @@ -4262,20 +4408,20 @@ "type": "github" } ], - "time": "2023-11-24T15:40:42+00:00" + "time": "2024-03-23T07:42:40+00:00" }, { "name": "livewire/livewire", - "version": "v3.4.6", + "version": "v3.4.9", "source": { "type": "git", "url": "https://github.com/livewire/livewire.git", - "reference": "7e7d638183b34fb61621455891869f5abfd55a82" + "reference": "c65b3f0798ab2c9338213ede3588c3cdf4e6fcc0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/livewire/livewire/zipball/7e7d638183b34fb61621455891869f5abfd55a82", - "reference": "7e7d638183b34fb61621455891869f5abfd55a82", + "url": "https://api.github.com/repos/livewire/livewire/zipball/c65b3f0798ab2c9338213ede3588c3cdf4e6fcc0", + "reference": "c65b3f0798ab2c9338213ede3588c3cdf4e6fcc0", "shasum": "" }, "require": { @@ -4329,7 +4475,7 @@ "description": "A front-end framework for Laravel.", "support": { "issues": "https://github.com/livewire/livewire/issues", - "source": "https://github.com/livewire/livewire/tree/v3.4.6" + "source": "https://github.com/livewire/livewire/tree/v3.4.9" }, "funding": [ { @@ -4337,31 +4483,31 @@ "type": "github" } ], - "time": "2024-02-20T14:04:25+00:00" + "time": "2024-03-14T14:03:32+00:00" }, { "name": "lorisleiva/laravel-actions", - "version": "v2.7.3", + "version": "v2.8.0", "source": { "type": "git", "url": "https://github.com/lorisleiva/laravel-actions.git", - "reference": "5d2e2a670ad758496021943a8d6dea4014e213d6" + "reference": "d5c2ca544f40d85f877b38eb6d23e9c967ecb69f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/lorisleiva/laravel-actions/zipball/5d2e2a670ad758496021943a8d6dea4014e213d6", - "reference": "5d2e2a670ad758496021943a8d6dea4014e213d6", + "url": "https://api.github.com/repos/lorisleiva/laravel-actions/zipball/d5c2ca544f40d85f877b38eb6d23e9c967ecb69f", + "reference": "d5c2ca544f40d85f877b38eb6d23e9c967ecb69f", "shasum": "" }, "require": { - "illuminate/contracts": "9.0 - 9.34 || ^9.36 || ^10.0", - "lorisleiva/lody": "^0.4", - "php": "^8.0" + "illuminate/contracts": "^10.0|^11.0", + "lorisleiva/lody": "^0.5", + "php": "^8.1" }, "require-dev": { - "orchestra/testbench": "^8.5", - "pestphp/pest": "^1.23", - "phpunit/phpunit": "^9.6" + "orchestra/testbench": "^9.0", + "pestphp/pest": "^1.23|^2.34", + "phpunit/phpunit": "^9.6|^10.0" }, "type": "library", "extra": { @@ -4404,7 +4550,7 @@ ], "support": { "issues": "https://github.com/lorisleiva/laravel-actions/issues", - "source": "https://github.com/lorisleiva/laravel-actions/tree/v2.7.3" + "source": "https://github.com/lorisleiva/laravel-actions/tree/v2.8.0" }, "funding": [ { @@ -4412,30 +4558,30 @@ "type": "github" } ], - "time": "2024-01-09T16:57:43+00:00" + "time": "2024-03-13T12:47:32+00:00" }, { "name": "lorisleiva/lody", - "version": "v0.4.0", + "version": "v0.5.0", "source": { "type": "git", "url": "https://github.com/lorisleiva/lody.git", - "reference": "1a43e8e423f3b2b64119542bc44a2071208fae16" + "reference": "c2f51b070e99f3a240d66cf68ef1f232036917fe" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/lorisleiva/lody/zipball/1a43e8e423f3b2b64119542bc44a2071208fae16", - "reference": "1a43e8e423f3b2b64119542bc44a2071208fae16", + "url": "https://api.github.com/repos/lorisleiva/lody/zipball/c2f51b070e99f3a240d66cf68ef1f232036917fe", + "reference": "c2f51b070e99f3a240d66cf68ef1f232036917fe", "shasum": "" }, "require": { - "illuminate/contracts": "^8.0|^9.0|^10.0", + "illuminate/contracts": "^9.0|^10.0|^11.0", "php": "^8.0" }, "require-dev": { - "orchestra/testbench": "^8.0", - "pestphp/pest": "^1.20.0", - "phpunit/phpunit": "^9.5.10" + "orchestra/testbench": "^9.0", + "pestphp/pest": "^1.20|^2.34", + "phpunit/phpunit": "^9.5.10|^10.5" }, "type": "library", "extra": { @@ -4476,7 +4622,7 @@ ], "support": { "issues": "https://github.com/lorisleiva/lody/issues", - "source": "https://github.com/lorisleiva/lody/tree/v0.4.0" + "source": "https://github.com/lorisleiva/lody/tree/v0.5.0" }, "funding": [ { @@ -4484,7 +4630,7 @@ "type": "github" } ], - "time": "2023-02-05T15:03:45+00:00" + "time": "2024-03-13T12:08:59+00:00" }, { "name": "monolog/monolog", @@ -4910,16 +5056,16 @@ }, { "name": "nikic/php-parser", - "version": "v5.0.1", + "version": "v5.0.2", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "2218c2252c874a4624ab2f613d86ac32d227bc69" + "reference": "139676794dc1e9231bf7bcd123cfc0c99182cb13" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/2218c2252c874a4624ab2f613d86ac32d227bc69", - "reference": "2218c2252c874a4624ab2f613d86ac32d227bc69", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/139676794dc1e9231bf7bcd123cfc0c99182cb13", + "reference": "139676794dc1e9231bf7bcd123cfc0c99182cb13", "shasum": "" }, "require": { @@ -4962,9 +5108,9 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v5.0.1" + "source": "https://github.com/nikic/PHP-Parser/tree/v5.0.2" }, - "time": "2024-02-21T19:24:10+00:00" + "time": "2024-03-05T20:51:40+00:00" }, { "name": "nubs/random-name-generator", @@ -5592,16 +5738,16 @@ }, { "name": "php-http/message", - "version": "1.16.0", + "version": "1.16.1", "source": { "type": "git", "url": "https://github.com/php-http/message.git", - "reference": "47a14338bf4ebd67d317bf1144253d7db4ab55fd" + "reference": "5997f3289332c699fa2545c427826272498a2088" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-http/message/zipball/47a14338bf4ebd67d317bf1144253d7db4ab55fd", - "reference": "47a14338bf4ebd67d317bf1144253d7db4ab55fd", + "url": "https://api.github.com/repos/php-http/message/zipball/5997f3289332c699fa2545c427826272498a2088", + "reference": "5997f3289332c699fa2545c427826272498a2088", "shasum": "" }, "require": { @@ -5655,9 +5801,9 @@ ], "support": { "issues": "https://github.com/php-http/message/issues", - "source": "https://github.com/php-http/message/tree/1.16.0" + "source": "https://github.com/php-http/message/tree/1.16.1" }, - "time": "2023-05-17T06:43:38+00:00" + "time": "2024-03-07T13:22:09+00:00" }, { "name": "php-http/message-factory", @@ -5716,16 +5862,16 @@ }, { "name": "php-http/promise", - "version": "1.3.0", + "version": "1.3.1", "source": { "type": "git", "url": "https://github.com/php-http/promise.git", - "reference": "2916a606d3b390f4e9e8e2b8dd68581508be0f07" + "reference": "fc85b1fba37c169a69a07ef0d5a8075770cc1f83" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-http/promise/zipball/2916a606d3b390f4e9e8e2b8dd68581508be0f07", - "reference": "2916a606d3b390f4e9e8e2b8dd68581508be0f07", + "url": "https://api.github.com/repos/php-http/promise/zipball/fc85b1fba37c169a69a07ef0d5a8075770cc1f83", + "reference": "fc85b1fba37c169a69a07ef0d5a8075770cc1f83", "shasum": "" }, "require": { @@ -5762,9 +5908,9 @@ ], "support": { "issues": "https://github.com/php-http/promise/issues", - "source": "https://github.com/php-http/promise/tree/1.3.0" + "source": "https://github.com/php-http/promise/tree/1.3.1" }, - "time": "2024-01-04T18:49:48+00:00" + "time": "2024-03-15T13:55:21+00:00" }, { "name": "phpdocumentor/reflection-common", @@ -6064,16 +6210,16 @@ }, { "name": "phpstan/phpdoc-parser", - "version": "1.26.0", + "version": "1.27.0", "source": { "type": "git", "url": "https://github.com/phpstan/phpdoc-parser.git", - "reference": "231e3186624c03d7e7c890ec662b81e6b0405227" + "reference": "86e4d5a4b036f8f0be1464522f4c6b584c452757" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/231e3186624c03d7e7c890ec662b81e6b0405227", - "reference": "231e3186624c03d7e7c890ec662b81e6b0405227", + "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/86e4d5a4b036f8f0be1464522f4c6b584c452757", + "reference": "86e4d5a4b036f8f0be1464522f4c6b584c452757", "shasum": "" }, "require": { @@ -6105,22 +6251,22 @@ "description": "PHPDoc parser with support for nullable, intersection and generic types", "support": { "issues": "https://github.com/phpstan/phpdoc-parser/issues", - "source": "https://github.com/phpstan/phpdoc-parser/tree/1.26.0" + "source": "https://github.com/phpstan/phpdoc-parser/tree/1.27.0" }, - "time": "2024-02-23T16:05:55+00:00" + "time": "2024-03-21T13:14:53+00:00" }, { "name": "phpstan/phpstan", - "version": "1.10.59", + "version": "1.10.65", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan.git", - "reference": "e607609388d3a6d418a50a49f7940e8086798281" + "reference": "3c657d057a0b7ecae19cb12db446bbc99d8839c6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/e607609388d3a6d418a50a49f7940e8086798281", - "reference": "e607609388d3a6d418a50a49f7940e8086798281", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/3c657d057a0b7ecae19cb12db446bbc99d8839c6", + "reference": "3c657d057a0b7ecae19cb12db446bbc99d8839c6", "shasum": "" }, "require": { @@ -6169,7 +6315,7 @@ "type": "tidelift" } ], - "time": "2024-02-20T13:59:13+00:00" + "time": "2024-03-23T10:30:26+00:00" }, { "name": "pimple/pimple", @@ -6783,16 +6929,16 @@ }, { "name": "psy/psysh", - "version": "v0.12.0", + "version": "v0.12.2", "source": { "type": "git", "url": "https://github.com/bobthecow/psysh.git", - "reference": "750bf031a48fd07c673dbe3f11f72362ea306d0d" + "reference": "9185c66c2165bbf4d71de78a69dccf4974f9538d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/bobthecow/psysh/zipball/750bf031a48fd07c673dbe3f11f72362ea306d0d", - "reference": "750bf031a48fd07c673dbe3f11f72362ea306d0d", + "url": "https://api.github.com/repos/bobthecow/psysh/zipball/9185c66c2165bbf4d71de78a69dccf4974f9538d", + "reference": "9185c66c2165bbf4d71de78a69dccf4974f9538d", "shasum": "" }, "require": { @@ -6856,9 +7002,9 @@ ], "support": { "issues": "https://github.com/bobthecow/psysh/issues", - "source": "https://github.com/bobthecow/psysh/tree/v0.12.0" + "source": "https://github.com/bobthecow/psysh/tree/v0.12.2" }, - "time": "2023-12-20T15:28:09+00:00" + "time": "2024-03-17T01:53:00+00:00" }, { "name": "purplepixie/phpdns", @@ -7196,16 +7342,16 @@ }, { "name": "rector/rector", - "version": "1.0.2", + "version": "1.0.3", "source": { "type": "git", "url": "https://github.com/rectorphp/rector.git", - "reference": "7596fa6da06c6a20c012efe6bb3d9188a9113b11" + "reference": "c59507a9090b465d65e1aceed91e5b81986e375b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/rectorphp/rector/zipball/7596fa6da06c6a20c012efe6bb3d9188a9113b11", - "reference": "7596fa6da06c6a20c012efe6bb3d9188a9113b11", + "url": "https://api.github.com/repos/rectorphp/rector/zipball/c59507a9090b465d65e1aceed91e5b81986e375b", + "reference": "c59507a9090b465d65e1aceed91e5b81986e375b", "shasum": "" }, "require": { @@ -7240,7 +7386,7 @@ ], "support": { "issues": "https://github.com/rectorphp/rector/issues", - "source": "https://github.com/rectorphp/rector/tree/1.0.2" + "source": "https://github.com/rectorphp/rector/tree/1.0.3" }, "funding": [ { @@ -7248,7 +7394,7 @@ "type": "github" } ], - "time": "2024-03-03T12:32:31+00:00" + "time": "2024-03-14T15:04:18+00:00" }, { "name": "resend/resend-laravel", @@ -7696,6 +7842,131 @@ ], "time": "2023-10-12T14:38:46+00:00" }, + { + "name": "socialiteproviders/manager", + "version": "v4.5.1", + "source": { + "type": "git", + "url": "https://github.com/SocialiteProviders/Manager.git", + "reference": "a67f194f0f4c4c7616c549afc697b78df9658d44" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/SocialiteProviders/Manager/zipball/a67f194f0f4c4c7616c549afc697b78df9658d44", + "reference": "a67f194f0f4c4c7616c549afc697b78df9658d44", + "shasum": "" + }, + "require": { + "illuminate/support": "^8.0 || ^9.0 || ^10.0 || ^11.0", + "laravel/socialite": "^5.2", + "php": "^8.0" + }, + "require-dev": { + "mockery/mockery": "^1.2", + "phpunit/phpunit": "^9.0" + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "SocialiteProviders\\Manager\\ServiceProvider" + ] + } + }, + "autoload": { + "psr-4": { + "SocialiteProviders\\Manager\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Andy Wendt", + "email": "andy@awendt.com" + }, + { + "name": "Anton Komarev", + "email": "a.komarev@cybercog.su" + }, + { + "name": "Miguel Piedrafita", + "email": "soy@miguelpiedrafita.com" + }, + { + "name": "atymic", + "email": "atymicq@gmail.com", + "homepage": "https://atymic.dev" + } + ], + "description": "Easily add new or override built-in providers in Laravel Socialite.", + "homepage": "https://socialiteproviders.com", + "keywords": [ + "laravel", + "manager", + "oauth", + "providers", + "socialite" + ], + "support": { + "issues": "https://github.com/socialiteproviders/manager/issues", + "source": "https://github.com/socialiteproviders/manager" + }, + "time": "2024-02-17T08:58:03+00:00" + }, + { + "name": "socialiteproviders/microsoft-azure", + "version": "5.2.0", + "source": { + "type": "git", + "url": "https://github.com/SocialiteProviders/Microsoft-Azure.git", + "reference": "453d62c9d7e3b3b76e94c913fb46e68a33347b16" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/SocialiteProviders/Microsoft-Azure/zipball/453d62c9d7e3b3b76e94c913fb46e68a33347b16", + "reference": "453d62c9d7e3b3b76e94c913fb46e68a33347b16", + "shasum": "" + }, + "require": { + "ext-json": "*", + "php": "^8.0", + "socialiteproviders/manager": "^4.4" + }, + "type": "library", + "autoload": { + "psr-4": { + "SocialiteProviders\\Azure\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Chris Hemmings", + "email": "chris@hemmin.gs" + } + ], + "description": "Microsoft Azure OAuth2 Provider for Laravel Socialite", + "keywords": [ + "azure", + "laravel", + "microsoft", + "oauth", + "provider", + "socialite" + ], + "support": { + "docs": "https://socialiteproviders.com/microsoft-azure", + "issues": "https://github.com/socialiteproviders/providers/issues", + "source": "https://github.com/socialiteproviders/providers" + }, + "time": "2024-03-15T03:02:10+00:00" + }, { "name": "spatie/backtrace", "version": "1.5.3", @@ -7760,29 +8031,29 @@ }, { "name": "spatie/laravel-activitylog", - "version": "4.7.3", + "version": "4.8.0", "source": { "type": "git", "url": "https://github.com/spatie/laravel-activitylog.git", - "reference": "ec65a478a909b8df1b4f0c3c45de2592ca7639e5" + "reference": "eb6f37dd40af950ce10cf5280f0acfa3e08c3bff" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/spatie/laravel-activitylog/zipball/ec65a478a909b8df1b4f0c3c45de2592ca7639e5", - "reference": "ec65a478a909b8df1b4f0c3c45de2592ca7639e5", + "url": "https://api.github.com/repos/spatie/laravel-activitylog/zipball/eb6f37dd40af950ce10cf5280f0acfa3e08c3bff", + "reference": "eb6f37dd40af950ce10cf5280f0acfa3e08c3bff", "shasum": "" }, "require": { - "illuminate/config": "^8.0 || ^9.0 || ^10.0", - "illuminate/database": "^8.69 || ^9.27 || ^10.0", - "illuminate/support": "^8.0 || ^9.0 || ^10.0", - "php": "^8.0", + "illuminate/config": "^8.0 || ^9.0 || ^10.0 || ^11.0", + "illuminate/database": "^8.69 || ^9.27 || ^10.0 || ^11.0", + "illuminate/support": "^8.0 || ^9.0 || ^10.0 || ^11.0", + "php": "^8.1", "spatie/laravel-package-tools": "^1.6.3" }, "require-dev": { "ext-json": "*", - "orchestra/testbench": "^6.23 || ^7.0 || ^8.0", - "pestphp/pest": "^1.20" + "orchestra/testbench": "^6.23 || ^7.0 || ^8.0 || ^9.0", + "pestphp/pest": "^1.20 || ^2.0" }, "type": "library", "extra": { @@ -7835,7 +8106,7 @@ ], "support": { "issues": "https://github.com/spatie/laravel-activitylog/issues", - "source": "https://github.com/spatie/laravel-activitylog/tree/4.7.3" + "source": "https://github.com/spatie/laravel-activitylog/tree/4.8.0" }, "funding": [ { @@ -7847,7 +8118,7 @@ "type": "github" } ], - "time": "2023-01-25T17:04:51+00:00" + "time": "2024-03-08T22:28:17+00:00" }, { "name": "spatie/laravel-data", @@ -7936,16 +8207,16 @@ }, { "name": "spatie/laravel-package-tools", - "version": "1.16.2", + "version": "1.16.4", "source": { "type": "git", "url": "https://github.com/spatie/laravel-package-tools.git", - "reference": "e62eeb1fe8a8a0b2e83227a6c279c8c59f7d3a15" + "reference": "ddf678e78d7f8b17e5cdd99c0c3413a4a6592e53" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/spatie/laravel-package-tools/zipball/e62eeb1fe8a8a0b2e83227a6c279c8c59f7d3a15", - "reference": "e62eeb1fe8a8a0b2e83227a6c279c8c59f7d3a15", + "url": "https://api.github.com/repos/spatie/laravel-package-tools/zipball/ddf678e78d7f8b17e5cdd99c0c3413a4a6592e53", + "reference": "ddf678e78d7f8b17e5cdd99c0c3413a4a6592e53", "shasum": "" }, "require": { @@ -7984,7 +8255,7 @@ ], "support": { "issues": "https://github.com/spatie/laravel-package-tools/issues", - "source": "https://github.com/spatie/laravel-package-tools/tree/1.16.2" + "source": "https://github.com/spatie/laravel-package-tools/tree/1.16.4" }, "funding": [ { @@ -7992,7 +8263,7 @@ "type": "github" } ], - "time": "2024-01-11T08:43:00+00:00" + "time": "2024-03-20T07:29:11+00:00" }, { "name": "spatie/laravel-ray", @@ -8209,16 +8480,16 @@ }, { "name": "spatie/php-structure-discoverer", - "version": "2.1.0", + "version": "2.1.1", "source": { "type": "git", "url": "https://github.com/spatie/php-structure-discoverer.git", - "reference": "f5b3c935dda89d6c382b27e3caf348fa80bcfa88" + "reference": "24f5221641560ec0f7dce23dd814e7d555b0098b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/spatie/php-structure-discoverer/zipball/f5b3c935dda89d6c382b27e3caf348fa80bcfa88", - "reference": "f5b3c935dda89d6c382b27e3caf348fa80bcfa88", + "url": "https://api.github.com/repos/spatie/php-structure-discoverer/zipball/24f5221641560ec0f7dce23dd814e7d555b0098b", + "reference": "24f5221641560ec0f7dce23dd814e7d555b0098b", "shasum": "" }, "require": { @@ -8277,7 +8548,7 @@ ], "support": { "issues": "https://github.com/spatie/php-structure-discoverer/issues", - "source": "https://github.com/spatie/php-structure-discoverer/tree/2.1.0" + "source": "https://github.com/spatie/php-structure-discoverer/tree/2.1.1" }, "funding": [ { @@ -8285,7 +8556,7 @@ "type": "github" } ], - "time": "2024-02-16T12:42:24+00:00" + "time": "2024-03-13T16:08:30+00:00" }, { "name": "spatie/ray", @@ -8369,22 +8640,22 @@ }, { "name": "spatie/url", - "version": "2.3.0", + "version": "2.4.0", "source": { "type": "git", "url": "https://github.com/spatie/url.git", - "reference": "ae324f5f77290827d66486fc88aa2c9373bc2170" + "reference": "93a51db743cdec22b081c64593e193887c9cd395" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/spatie/url/zipball/ae324f5f77290827d66486fc88aa2c9373bc2170", - "reference": "ae324f5f77290827d66486fc88aa2c9373bc2170", + "url": "https://api.github.com/repos/spatie/url/zipball/93a51db743cdec22b081c64593e193887c9cd395", + "reference": "93a51db743cdec22b081c64593e193887c9cd395", "shasum": "" }, "require": { "php": "^8.0", "psr/http-message": "^1.0 || ^2.0", - "spatie/macroable": "^2.0" + "spatie/macroable": "^1.0 || ^2.0" }, "require-dev": { "pestphp/pest": "^1.21" @@ -8415,7 +8686,7 @@ ], "support": { "issues": "https://github.com/spatie/url/issues", - "source": "https://github.com/spatie/url/tree/2.3.0" + "source": "https://github.com/spatie/url/tree/2.4.0" }, "funding": [ { @@ -8427,7 +8698,7 @@ "type": "github" } ], - "time": "2024-01-05T10:09:13+00:00" + "time": "2024-03-08T11:35:19+00:00" }, { "name": "stripe/stripe-php", @@ -11588,64 +11859,6 @@ }, "time": "2022-06-03T18:03:27+00:00" }, - { - "name": "wire-elements/modal", - "version": "2.0.9", - "source": { - "type": "git", - "url": "https://github.com/wire-elements/modal.git", - "reference": "899b05e313403669aa8a359db71a066246184355" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/wire-elements/modal/zipball/899b05e313403669aa8a359db71a066246184355", - "reference": "899b05e313403669aa8a359db71a066246184355", - "shasum": "" - }, - "require": { - "livewire/livewire": "^3.2.3", - "php": "^8.1", - "spatie/laravel-package-tools": "^1.9" - }, - "require-dev": { - "orchestra/testbench": "^8.5", - "phpunit/phpunit": "^9.5" - }, - "type": "library", - "extra": { - "laravel": { - "providers": [ - "LivewireUI\\Modal\\LivewireModalServiceProvider" - ] - } - }, - "autoload": { - "psr-4": { - "LivewireUI\\Modal\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Philo Hermans", - "email": "me@philohermans.com" - } - ], - "description": "Laravel Livewire modal component", - "keywords": [ - "laravel", - "livewire", - "modal" - ], - "support": { - "issues": "https://github.com/wire-elements/modal/issues", - "source": "https://github.com/wire-elements/modal/tree/2.0.9" - }, - "time": "2023-12-08T09:31:14+00:00" - }, { "name": "yosymfony/parser-utils", "version": "v2.0.0", @@ -11833,16 +12046,16 @@ }, { "name": "zbateson/mb-wrapper", - "version": "1.2.0", + "version": "1.2.1", "source": { "type": "git", "url": "https://github.com/zbateson/mb-wrapper.git", - "reference": "faf35dddfacfc5d4d5f9210143eafd7a7fe74334" + "reference": "09a8b77eb94af3823a9a6623dcc94f8d988da67f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/zbateson/mb-wrapper/zipball/faf35dddfacfc5d4d5f9210143eafd7a7fe74334", - "reference": "faf35dddfacfc5d4d5f9210143eafd7a7fe74334", + "url": "https://api.github.com/repos/zbateson/mb-wrapper/zipball/09a8b77eb94af3823a9a6623dcc94f8d988da67f", + "reference": "09a8b77eb94af3823a9a6623dcc94f8d988da67f", "shasum": "" }, "require": { @@ -11853,7 +12066,7 @@ "require-dev": { "friendsofphp/php-cs-fixer": "*", "phpstan/phpstan": "*", - "phpunit/phpunit": "<=9.0" + "phpunit/phpunit": "<10.0" }, "suggest": { "ext-iconv": "For best support/performance", @@ -11890,7 +12103,7 @@ ], "support": { "issues": "https://github.com/zbateson/mb-wrapper/issues", - "source": "https://github.com/zbateson/mb-wrapper/tree/1.2.0" + "source": "https://github.com/zbateson/mb-wrapper/tree/1.2.1" }, "funding": [ { @@ -11898,7 +12111,7 @@ "type": "github" } ], - "time": "2023-01-11T23:05:44+00:00" + "time": "2024-03-18T04:31:04+00:00" }, { "name": "zbateson/stream-decorators", @@ -12449,16 +12662,16 @@ }, { "name": "mockery/mockery", - "version": "1.6.7", + "version": "1.6.11", "source": { "type": "git", "url": "https://github.com/mockery/mockery.git", - "reference": "0cc058854b3195ba21dc6b1f7b1f60f4ef3a9c06" + "reference": "81a161d0b135df89951abd52296adf97deb0723d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/mockery/mockery/zipball/0cc058854b3195ba21dc6b1f7b1f60f4ef3a9c06", - "reference": "0cc058854b3195ba21dc6b1f7b1f60f4ef3a9c06", + "url": "https://api.github.com/repos/mockery/mockery/zipball/81a161d0b135df89951abd52296adf97deb0723d", + "reference": "81a161d0b135df89951abd52296adf97deb0723d", "shasum": "" }, "require": { @@ -12470,8 +12683,8 @@ "phpunit/phpunit": "<8.0" }, "require-dev": { - "phpunit/phpunit": "^8.5 || ^9.6.10", - "symplify/easy-coding-standard": "^12.0.8" + "phpunit/phpunit": "^8.5 || ^9.6.17", + "symplify/easy-coding-standard": "^12.1.14" }, "type": "library", "autoload": { @@ -12528,7 +12741,7 @@ "security": "https://github.com/mockery/mockery/security/advisories", "source": "https://github.com/mockery/mockery" }, - "time": "2023-12-10T02:24:34+00:00" + "time": "2024-03-21T18:34:15+00:00" }, { "name": "myclabs/deep-copy", @@ -12687,35 +12900,35 @@ }, { "name": "pestphp/pest", - "version": "v2.34.1", + "version": "v2.34.5", "source": { "type": "git", "url": "https://github.com/pestphp/pest.git", - "reference": "78d9fd31d0bf50f9eb9daf855d69217e681b5e3e" + "reference": "863a0cc83744c677ffdb28a6a2b841dd049e57ce" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/pestphp/pest/zipball/78d9fd31d0bf50f9eb9daf855d69217e681b5e3e", - "reference": "78d9fd31d0bf50f9eb9daf855d69217e681b5e3e", + "url": "https://api.github.com/repos/pestphp/pest/zipball/863a0cc83744c677ffdb28a6a2b841dd049e57ce", + "reference": "863a0cc83744c677ffdb28a6a2b841dd049e57ce", "shasum": "" }, "require": { "brianium/paratest": "^7.3.1", - "nunomaduro/collision": "^7.10.0|^8.1.0", - "nunomaduro/termwind": "^1.15.1|^2.0.0", + "nunomaduro/collision": "^7.10.0|^8.1.1", + "nunomaduro/termwind": "^1.15.1|^2.0.1", "pestphp/pest-plugin": "^2.1.1", "pestphp/pest-plugin-arch": "^2.7.0", "php": "^8.1.0", - "phpunit/phpunit": "^10.5.11" + "phpunit/phpunit": "^10.5.15" }, "conflict": { - "phpunit/phpunit": ">10.5.11", + "phpunit/phpunit": ">10.5.15", "sebastian/exporter": "<5.1.0", "webmozart/assert": "<1.11.0" }, "require-dev": { "pestphp/pest-dev-tools": "^2.16.0", - "pestphp/pest-plugin-type-coverage": "^2.8.0", + "pestphp/pest-plugin-type-coverage": "^2.8.1", "symfony/process": "^6.4.0|^7.0.4" }, "bin": [ @@ -12779,7 +12992,7 @@ ], "support": { "issues": "https://github.com/pestphp/pest/issues", - "source": "https://github.com/pestphp/pest/tree/v2.34.1" + "source": "https://github.com/pestphp/pest/tree/v2.34.5" }, "funding": [ { @@ -12791,7 +13004,7 @@ "type": "github" } ], - "time": "2024-02-28T15:15:55+00:00" + "time": "2024-03-22T08:44:19+00:00" }, { "name": "pestphp/pest-plugin", @@ -13177,16 +13390,16 @@ }, { "name": "phpunit/php-code-coverage", - "version": "10.1.12", + "version": "10.1.14", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "842f72662d6b9edda84c4b6f13885fd9cd53dc63" + "reference": "e3f51450ebffe8e0efdf7346ae966a656f7d5e5b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/842f72662d6b9edda84c4b6f13885fd9cd53dc63", - "reference": "842f72662d6b9edda84c4b6f13885fd9cd53dc63", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/e3f51450ebffe8e0efdf7346ae966a656f7d5e5b", + "reference": "e3f51450ebffe8e0efdf7346ae966a656f7d5e5b", "shasum": "" }, "require": { @@ -13243,7 +13456,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy", - "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/10.1.12" + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/10.1.14" }, "funding": [ { @@ -13251,7 +13464,7 @@ "type": "github" } ], - "time": "2024-03-02T07:22:05+00:00" + "time": "2024-03-12T15:33:41+00:00" }, { "name": "phpunit/php-file-iterator", @@ -13498,16 +13711,16 @@ }, { "name": "phpunit/phpunit", - "version": "10.5.11", + "version": "10.5.15", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "0d968f6323deb3dbfeba5bfd4929b9415eb7a9a4" + "reference": "86376e05e8745ed81d88232ff92fee868247b07b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/0d968f6323deb3dbfeba5bfd4929b9415eb7a9a4", - "reference": "0d968f6323deb3dbfeba5bfd4929b9415eb7a9a4", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/86376e05e8745ed81d88232ff92fee868247b07b", + "reference": "86376e05e8745ed81d88232ff92fee868247b07b", "shasum": "" }, "require": { @@ -13579,7 +13792,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", "security": "https://github.com/sebastianbergmann/phpunit/security/policy", - "source": "https://github.com/sebastianbergmann/phpunit/tree/10.5.11" + "source": "https://github.com/sebastianbergmann/phpunit/tree/10.5.15" }, "funding": [ { @@ -13595,7 +13808,7 @@ "type": "tidelift" } ], - "time": "2024-02-25T14:05:00+00:00" + "time": "2024-03-22T04:17:47+00:00" }, { "name": "sebastian/cli-parser", @@ -13969,16 +14182,16 @@ }, { "name": "sebastian/environment", - "version": "6.0.1", + "version": "6.1.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/environment.git", - "reference": "43c751b41d74f96cbbd4e07b7aec9675651e2951" + "reference": "8074dbcd93529b357029f5cc5058fd3e43666984" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/43c751b41d74f96cbbd4e07b7aec9675651e2951", - "reference": "43c751b41d74f96cbbd4e07b7aec9675651e2951", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/8074dbcd93529b357029f5cc5058fd3e43666984", + "reference": "8074dbcd93529b357029f5cc5058fd3e43666984", "shasum": "" }, "require": { @@ -13993,7 +14206,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "6.0-dev" + "dev-main": "6.1-dev" } }, "autoload": { @@ -14021,7 +14234,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/environment/issues", "security": "https://github.com/sebastianbergmann/environment/security/policy", - "source": "https://github.com/sebastianbergmann/environment/tree/6.0.1" + "source": "https://github.com/sebastianbergmann/environment/tree/6.1.0" }, "funding": [ { @@ -14029,7 +14242,7 @@ "type": "github" } ], - "time": "2023-04-11T05:39:26+00:00" + "time": "2024-03-23T08:47:14+00:00" }, { "name": "sebastian/exporter", diff --git a/config/app.php b/config/app.php index 5851640be..b95224fdc 100644 --- a/config/app.php +++ b/config/app.php @@ -187,6 +187,7 @@ /* * Package Service Providers... */ + \SocialiteProviders\Manager\ServiceProvider::class, /* * Application Service Providers... diff --git a/config/constants.php b/config/constants.php index 7bab10a56..54c451310 100644 --- a/config/constants.php +++ b/config/constants.php @@ -19,7 +19,9 @@ ], ], 'services' => [ - 'official' => 'https://cdn.coollabs.io/coolify/service-templates.json', + // Temporary disabled until cache is implemented + // 'official' => 'https://cdn.coollabs.io/coolify/service-templates.json', + 'official' => 'https://raw.githubusercontent.com/coollabsio/coolify/main/templates/service-templates.json', ], 'limits' => [ 'trial_period' => 0, diff --git a/config/coolify.php b/config/coolify.php index 69ec23146..a6d6d8581 100644 --- a/config/coolify.php +++ b/config/coolify.php @@ -12,4 +12,6 @@ 'is_windows_docker_desktop' => env('IS_WINDOWS_DOCKER_DESKTOP', false), 'base_config_path' => env('BASE_CONFIG_PATH', '/data/coolify'), 'helper_image' => env('HELPER_IMAGE', 'ghcr.io/coollabsio/coolify-helper:latest'), + 'is_horizon_enabled' => env('HORIZON_ENABLED', true), + 'is_scheduler_enabled' => env('SCHEDULER_ENABLED', true), ]; diff --git a/config/sentry.php b/config/sentry.php index b4c1aa5f4..89345d082 100644 --- a/config/sentry.php +++ b/config/sentry.php @@ -3,11 +3,11 @@ return [ // @see https://docs.sentry.io/product/sentry-basics/dsn-explainer/ - 'dsn' => 'https://f0b0e6be13926d4ac68d68d51d38db8f@o1082494.ingest.us.sentry.io/4505347448045568', + 'dsn' => 'https://89552af6db48f4ca6a871ec0fc42964d@o1082494.ingest.us.sentry.io/4505347448045568', // 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.241', + 'release' => '4.0.0-beta.248', // When left empty or `null` the Laravel environment will be used 'environment' => config('app.env'), diff --git a/config/services.php b/config/services.php index 0ace530e8..db81eef9a 100644 --- a/config/services.php +++ b/config/services.php @@ -31,4 +31,11 @@ 'region' => env('AWS_DEFAULT_REGION', 'us-east-1'), ], + 'azure' => [ + 'client_id' => env('AZURE_CLIENT_ID'), + 'client_secret' => env('AZURE_CLIENT_SECRET'), + 'redirect' => env('AZURE_REDIRECT_URI'), + 'tenant' => env('AZURE_TENANT_ID'), + 'proxy' => env('AZURE_PROXY'), + ], ]; diff --git a/config/version.php b/config/version.php index f00cd2d57..642ee812d 100644 --- a/config/version.php +++ b/config/version.php @@ -1,3 +1,3 @@ false, - - /* - |-------------------------------------------------------------------------- - | Include JS - |-------------------------------------------------------------------------- - | - | Livewire UI will inject the required Javascript in your blade template. - | If you want to bundle the required Javascript you can set this to false - | and add `require('vendor/wire-elements/modal/resources/js/modal');` - | to your script bundler like webpack. - | - */ - 'include_js' => false, - - /* - |-------------------------------------------------------------------------- - | Modal Component Defaults - |-------------------------------------------------------------------------- - | - | Configure the default properties for a modal component. - | - | Supported modal_max_width - | 'sm', 'md', 'lg', 'xl', '2xl', '3xl', '4xl', '5xl', '6xl', '7xl' - */ - 'component_defaults' => [ - 'modal_max_width' => '7xl', - - 'close_modal_on_click_away' => true, - - 'close_modal_on_escape' => true, - - 'close_modal_on_escape_is_forceful' => true, - - 'dispatch_close_event' => false, - - 'destroy_on_close' => false, - ], -]; diff --git a/database/migrations/2024_03_08_180457_nullable_password.php b/database/migrations/2024_03_08_180457_nullable_password.php new file mode 100644 index 000000000..3bd91b0be --- /dev/null +++ b/database/migrations/2024_03_08_180457_nullable_password.php @@ -0,0 +1,28 @@ +string('password')->nullable()->change(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('users', function (Blueprint $table) { + $table->string('password')->nullable(false)->change(); + }); + } +}; diff --git a/database/migrations/2024_03_11_150013_create_oauth_settings.php b/database/migrations/2024_03_11_150013_create_oauth_settings.php new file mode 100644 index 000000000..c2178426d --- /dev/null +++ b/database/migrations/2024_03_11_150013_create_oauth_settings.php @@ -0,0 +1,33 @@ +id(); + $table->string('provider')->unique(); + $table->boolean('enabled')->default(false); + $table->string('client_id')->nullable(); + $table->text('client_secret')->nullable(); + $table->string('redirect_uri')->nullable(); + $table->string('tenant')->nullable(); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('oauth_settings'); + } +}; diff --git a/database/migrations/2024_03_22_080914_remove_popup_notifications.php b/database/migrations/2024_03_22_080914_remove_popup_notifications.php new file mode 100644 index 000000000..ccb270093 --- /dev/null +++ b/database/migrations/2024_03_22_080914_remove_popup_notifications.php @@ -0,0 +1,30 @@ +dropColumn('is_notification_sponsorship_enabled'); + $table->dropColumn('is_notification_notifications_enabled'); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('users', function (Blueprint $table) { + $table->boolean('is_notification_sponsorship_enabled')->default(true); + $table->boolean('is_notification_notifications_enabled')->default(true); + }); + } +}; diff --git a/database/migrations/2024_03_26_122110_remove_realtime_notifications.php b/database/migrations/2024_03_26_122110_remove_realtime_notifications.php new file mode 100644 index 000000000..6d5d0e041 --- /dev/null +++ b/database/migrations/2024_03_26_122110_remove_realtime_notifications.php @@ -0,0 +1,28 @@ +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); + }); + } +}; diff --git a/database/seeders/DatabaseSeeder.php b/database/seeders/DatabaseSeeder.php index 2a2767d78..b3fac350f 100644 --- a/database/seeders/DatabaseSeeder.php +++ b/database/seeders/DatabaseSeeder.php @@ -32,6 +32,7 @@ public function run(): void StandalonePostgresqlSeeder::class, ScheduledDatabaseBackupSeeder::class, ScheduledDatabaseBackupExecutionSeeder::class, + OauthSettingSeeder::class, ]); } } diff --git a/database/seeders/OauthSettingSeeder.php b/database/seeders/OauthSettingSeeder.php new file mode 100644 index 000000000..4d33468c7 --- /dev/null +++ b/database/seeders/OauthSettingSeeder.php @@ -0,0 +1,37 @@ + 0, + 'provider' => 'azure', + ]); + OauthSetting::firstOrCreate([ + 'id' => 1, + 'provider' => 'bitbucket', + ]); + OauthSetting::firstOrCreate([ + 'id' => 2, + 'provider' => 'github', + ]); + OauthSetting::firstOrCreate([ + 'id' => 3, + 'provider' => 'gitlab', + ]); + OauthSetting::firstOrCreate([ + 'id' => 4, + 'provider' => 'google', + ]); + } +} diff --git a/database/seeders/ProductionSeeder.php b/database/seeders/ProductionSeeder.php index 4c66bdabf..206e92f76 100644 --- a/database/seeders/ProductionSeeder.php +++ b/database/seeders/ProductionSeeder.php @@ -198,5 +198,8 @@ public function run(): void } catch (\Throwable $e) { echo "Error: {$e->getMessage()}\n"; } + + $oauth_settings_seeder = new OauthSettingSeeder(); + $oauth_settings_seeder->run(); } } diff --git a/docker/coolify-helper/Dockerfile b/docker/coolify-helper/Dockerfile index 4cf996904..5798c92bd 100644 --- a/docker/coolify-helper/Dockerfile +++ b/docker/coolify-helper/Dockerfile @@ -2,15 +2,15 @@ FROM alpine:3.17 ARG TARGETPLATFORM # https://download.docker.com/linux/static/stable/ -ARG DOCKER_VERSION=24.0.5 +ARG DOCKER_VERSION=24.0.9 # https://github.com/docker/compose/releases -ARG DOCKER_COMPOSE_VERSION=2.21.0 +ARG DOCKER_COMPOSE_VERSION=2.25.0 # https://github.com/docker/buildx/releases -ARG DOCKER_BUILDX_VERSION=0.11.2 +ARG DOCKER_BUILDX_VERSION=0.13.1 # https://github.com/buildpacks/pack/releases -ARG PACK_VERSION=0.32.1 +ARG PACK_VERSION=0.33.2 # https://github.com/railwayapp/nixpacks/releases -ARG NIXPACKS_VERSION=1.20.0 +ARG NIXPACKS_VERSION=1.21.2 USER root WORKDIR /artifacts @@ -34,7 +34,7 @@ RUN if [[ ${TARGETPLATFORM} == 'linux/arm64' ]]; then \ chmod +x ~/.docker/cli-plugins/docker-compose /usr/bin/docker /usr/local/bin/pack /root/.docker/cli-plugins/docker-buildx \ ;fi -COPY --from=minio/mc /usr/bin/mc /usr/bin/mc +COPY --from=minio/mc:RELEASE.2024-03-13T23-51-57Z /usr/bin/mc /usr/bin/mc RUN chmod +x /usr/bin/mc ENTRYPOINT ["/sbin/tini", "--"] diff --git a/docker/dev-ssu/Dockerfile b/docker/dev-ssu/Dockerfile index cf79afe4d..0c7ce2b2a 100644 --- a/docker/dev-ssu/Dockerfile +++ b/docker/dev-ssu/Dockerfile @@ -1,8 +1,8 @@ -FROM serversideup/php:8.2-fpm-nginx +FROM serversideup/php:8.2-fpm-nginx-v2.2.1 ARG TARGETPLATFORM # https://github.com/cloudflare/cloudflared/releases -ARG CLOUDFLARED_VERSION=2023.10.0 +ARG CLOUDFLARED_VERSION=2024.2.1 ARG POSTGRES_VERSION=15 RUN apt-get update @@ -40,4 +40,4 @@ RUN /bin/bash -c "if [[ ${TARGETPLATFORM} == 'linux/arm64' ]]; then \ RUN { \ echo 'upload_max_filesize=256M'; \ echo 'post_max_size=256M'; \ - } > /etc/php/current_version/cli/conf.d/upload-limits.ini \ No newline at end of file + } > /etc/php/current_version/cli/conf.d/upload-limits.ini diff --git a/docker/dev-ssu/etc/s6-overlay/s6-rc.d/horizon/run b/docker/dev-ssu/etc/s6-overlay/s6-rc.d/horizon/run index cec4f1dda..87471097e 100644 --- a/docker/dev-ssu/etc/s6-overlay/s6-rc.d/horizon/run +++ b/docker/dev-ssu/etc/s6-overlay/s6-rc.d/horizon/run @@ -1,5 +1,5 @@ #!/command/execlineb -P foreground { s6-sleep 5 - su - webuser -c "php /var/www/html/artisan horizon" + su - webuser -c "php /var/www/html/artisan start:horizon" } diff --git a/docker/dev-ssu/etc/s6-overlay/s6-rc.d/scheduler-worker/run b/docker/dev-ssu/etc/s6-overlay/s6-rc.d/scheduler-worker/run index 0f205c897..87ca0cae1 100644 --- a/docker/dev-ssu/etc/s6-overlay/s6-rc.d/scheduler-worker/run +++ b/docker/dev-ssu/etc/s6-overlay/s6-rc.d/scheduler-worker/run @@ -1,5 +1,5 @@ #!/command/execlineb -P foreground { s6-sleep 5 - su - webuser -c "php /var/www/html/artisan schedule:work" + su - webuser -c "php /var/www/html/artisan start:scheduler" } diff --git a/docker/prod-ssu/Dockerfile b/docker/prod-ssu/Dockerfile index d5ba465b7..dcc1c334d 100644 --- a/docker/prod-ssu/Dockerfile +++ b/docker/prod-ssu/Dockerfile @@ -1,21 +1,21 @@ -FROM serversideup/php:8.2-fpm-nginx as base +FROM serversideup/php:8.2-fpm-nginx-v2.2.1 as base WORKDIR /var/www/html COPY composer.json composer.lock ./ RUN composer install --no-dev --no-interaction --no-plugins --no-scripts --prefer-dist -FROM node:19 as static-assets +FROM node:20 as static-assets WORKDIR /app COPY . . COPY --from=base --chown=9999:9999 /var/www/html . RUN npm install RUN npm run build -FROM serversideup/php:8.2-fpm-nginx +FROM serversideup/php:8.2-fpm-nginx-v2.2.1 ARG TARGETPLATFORM # https://github.com/cloudflare/cloudflared/releases -ARG CLOUDFLARED_VERSION=2023.10.0 +ARG CLOUDFLARED_VERSION=2024.2.1 ARG POSTGRES_VERSION=15 WORKDIR /var/www/html @@ -66,4 +66,4 @@ RUN /bin/bash -c "if [[ ${TARGETPLATFORM} == 'linux/arm64' ]]; then \ RUN { \ echo 'upload_max_filesize=256M'; \ echo 'post_max_size=256M'; \ - } > /etc/php/current_version/cli/conf.d/upload-limits.ini \ No newline at end of file + } > /etc/php/current_version/cli/conf.d/upload-limits.ini diff --git a/lang/en.json b/lang/en.json index 1f4fbdb74..461a96e9a 100644 --- a/lang/en.json +++ b/lang/en.json @@ -1,15 +1,21 @@ { "auth.login": "Login", + "auth.login.azure": "Login with Microsoft", + "auth.login.bitbucket": "Login with Bitbucket", + "auth.login.github": "Login with GitHub", + "auth.login.gitlab": "Login with Gitlab", + "auth.login.google": "Login with Google", "auth.already_registered": "Already registered?", "auth.confirm_password": "Confirm password", "auth.forgot_password": "Forgot password", "auth.forgot_password_send_email": "Send password reset email", - "auth.register_now": "Register a new account", + "auth.register_now": "Register", "auth.logout": "Logout", "auth.register": "Register", "auth.registration_disabled": "Registration is disabled. Please contact the administrator.", "auth.reset_password": "Reset password", "auth.failed": "These credentials do not match our records.", + "auth.failed.callback": "Failed to process callback from login provider.", "auth.failed.password": "The provided password is incorrect.", "auth.failed.email": "We can't find a user with that e-mail address.", "auth.throttle": "Too many login attempts. Please try again in :seconds seconds.", diff --git a/package-lock.json b/package-lock.json index b2124e9df..5d53421ab 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5,19 +5,19 @@ "packages": { "": { "dependencies": { + "@tailwindcss/forms": "0.5.7", "@tailwindcss/typography": "0.5.10", - "alpinejs": "3.13.5", - "daisyui": "4.7.2", + "alpinejs": "3.13.7", "ioredis": "5.3.2", "tailwindcss-scrollbar": "0.1.0" }, "devDependencies": { "@vitejs/plugin-vue": "4.5.1", - "autoprefixer": "10.4.18", - "axios": "1.6.7", + "autoprefixer": "10.4.19", + "axios": "1.6.8", "laravel-echo": "1.16.0", "laravel-vite-plugin": "0.8.1", - "postcss": "8.4.35", + "postcss": "8.4.38", "pusher-js": "8.4.0-rc2", "tailwindcss": "3.4.1", "vite": "4.5.2", @@ -484,6 +484,17 @@ "node": ">= 8" } }, + "node_modules/@tailwindcss/forms": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/@tailwindcss/forms/-/forms-0.5.7.tgz", + "integrity": "sha512-QE7X69iQI+ZXwldE+rzasvbJiyV/ju1FGHH0Qn2W3FKbuYtqp8LKcy6iSw79fVUT5/Vvf+0XgLCeYVG+UV6hOw==", + "dependencies": { + "mini-svg-data-uri": "^1.2.3" + }, + "peerDependencies": { + "tailwindcss": ">=3.0.0 || >= 3.0.0-alpha.1" + } + }, "node_modules/@tailwindcss/typography": { "version": "0.5.10", "resolved": "https://registry.npmjs.org/@tailwindcss/typography/-/typography-0.5.10.tgz", @@ -672,9 +683,9 @@ "integrity": "sha512-oJ4F3TnvpXaQwZJNF3ZK+kLPHKarDmJjJ6jyzVNDKH9md1dptjC7lWR//jrGuLdek/U6iltWxqAnYOu8gCiOvA==" }, "node_modules/alpinejs": { - "version": "3.13.5", - "resolved": "https://registry.npmjs.org/alpinejs/-/alpinejs-3.13.5.tgz", - "integrity": "sha512-1d2XeNGN+Zn7j4mUAKXtAgdc4/rLeadyTMWeJGXF5DzwawPBxwTiBhFFm6w/Ei8eJxUZeyNWWSD9zknfdz1kEw==", + "version": "3.13.7", + "resolved": "https://registry.npmjs.org/alpinejs/-/alpinejs-3.13.7.tgz", + "integrity": "sha512-rcTyjTANbsePq1hb7eSekt3qjI94HLGeO6JaRjCssCVbIIc+qBrc7pO5S/+2JB6oojIibjM6FA+xRI3zhGPZIg==", "dependencies": { "@vue/reactivity": "~3.1.1" } @@ -708,9 +719,9 @@ "dev": true }, "node_modules/autoprefixer": { - "version": "10.4.18", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.18.tgz", - "integrity": "sha512-1DKbDfsr6KUElM6wg+0zRNkB/Q7WcKYAaK+pzXn+Xqmszm/5Xa9coeNdtP88Vi+dPzZnMjhge8GIV49ZQkDa+g==", + "version": "10.4.19", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.19.tgz", + "integrity": "sha512-BaENR2+zBZ8xXhM4pUaKUxlVdxZ0EZhjvbopwnXmxRUfqDmwSpC2lAi/QXvx7NRdPCo1WKEcEF6mV64si1z4Ew==", "dev": true, "funding": [ { @@ -728,7 +739,7 @@ ], "dependencies": { "browserslist": "^4.23.0", - "caniuse-lite": "^1.0.30001591", + "caniuse-lite": "^1.0.30001599", "fraction.js": "^4.3.7", "normalize-range": "^0.1.2", "picocolors": "^1.0.0", @@ -745,12 +756,12 @@ } }, "node_modules/axios": { - "version": "1.6.7", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.7.tgz", - "integrity": "sha512-/hDJGff6/c7u0hDkvkGxR/oy6CbCs8ziCsC7SqmhjfozqiJGc8Z11wrv9z9lYfY4K8l+H9TpjcMDX0xOZmx+RA==", + "version": "1.6.8", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.8.tgz", + "integrity": "sha512-v/ZHtJDU39mDpyBoFVkETcd/uNdxrWRrg3bKpOKzXFA6Bvqopts6ALSMU3y6ijYxbw2B+wPrIv46egTzJXCLGQ==", "dev": true, "dependencies": { - "follow-redirects": "^1.15.4", + "follow-redirects": "^1.15.6", "form-data": "^4.0.0", "proxy-from-env": "^1.1.0" } @@ -829,9 +840,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001594", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001594.tgz", - "integrity": "sha512-VblSX6nYqyJVs8DKFMldE2IVCJjZ225LW00ydtUWwh5hk9IfkTOffO6r8gJNsH0qqqeAF8KrbMYA2VEwTlGW5g==", + "version": "1.0.30001600", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001600.tgz", + "integrity": "sha512-+2S9/2JFhYmYaDpZvo0lKkfvuKIglrx68MwOBqMGHhQsNkLjB5xtc/TGoEPs+MxjSyN/72qer2g97nzR641mOQ==", "dev": true, "funding": [ { @@ -918,15 +929,6 @@ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" }, - "node_modules/css-selector-tokenizer": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/css-selector-tokenizer/-/css-selector-tokenizer-0.8.0.tgz", - "integrity": "sha512-Jd6Ig3/pe62/qe5SBPTN8h8LeUg/pT4lLgtavPf7updwwHpvFzxvOQBHYj2LZDMjUnBzgvIUSjRcf6oT5HzHFg==", - "dependencies": { - "cssesc": "^3.0.0", - "fastparse": "^1.1.2" - } - }, "node_modules/cssesc": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", @@ -944,32 +946,6 @@ "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", "dev": true }, - "node_modules/culori": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/culori/-/culori-3.2.0.tgz", - "integrity": "sha512-HIEbTSP7vs1mPq/2P9In6QyFE0Tkpevh0k9a+FkjhD+cwsYm9WRSbn4uMdW9O0yXlNYC3ppxL3gWWPOcvEl57w==", - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - } - }, - "node_modules/daisyui": { - "version": "4.7.2", - "resolved": "https://registry.npmjs.org/daisyui/-/daisyui-4.7.2.tgz", - "integrity": "sha512-9UCss12Zmyk/22u+JbkVrHHxOzFOyY17HuqP5LeswI4hclbj6qbjJTovdj2zRy8cCH6/n6Wh0lTLjriGnyGh0g==", - "dependencies": { - "css-selector-tokenizer": "^0.8", - "culori": "^3", - "picocolors": "^1", - "postcss-js": "^4" - }, - "engines": { - "node": ">=16.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/daisyui" - } - }, "node_modules/debug": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", @@ -1109,11 +1085,6 @@ "node": ">= 6" } }, - "node_modules/fastparse": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/fastparse/-/fastparse-1.1.2.tgz", - "integrity": "sha512-483XLLxTVIwWK3QTrMGRqUfUpoOs/0hbQrl2oz4J0pAcm3A3bu84wxTFqGqkJzewCLdME38xJLJAxBABfQT8sQ==" - }, "node_modules/fastq": { "version": "1.15.0", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", @@ -1134,9 +1105,9 @@ } }, "node_modules/follow-redirects": { - "version": "1.15.5", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.5.tgz", - "integrity": "sha512-vSFWUON1B+yAw1VN4xMfxgn5fTUiaOzAJCKBwIIgT/+7CuGy9+r+5gITvP62j3RmaD5Ph65UaERdOSRGUzZtgw==", + "version": "1.15.6", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", + "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", "dev": true, "funding": [ { @@ -1462,6 +1433,14 @@ "node": ">= 0.6" } }, + "node_modules/mini-svg-data-uri": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/mini-svg-data-uri/-/mini-svg-data-uri-1.4.4.tgz", + "integrity": "sha512-r9deDe9p5FJUPZAk3A59wGH7Ii9YrjjWw0jmw/liSbHl2CHiyXj6FcDXDu2K3TjVAXqiJdaw3xxwlZZr9E6nHg==", + "bin": { + "mini-svg-data-uri": "cli.js" + } + }, "node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -1598,9 +1577,9 @@ } }, "node_modules/postcss": { - "version": "8.4.35", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.35.tgz", - "integrity": "sha512-u5U8qYpBCpN13BsiEB0CbR1Hhh4Gc0zLFuedrHJKMctHCHAGrMdG0PRM/KErzAL3CU6/eckEtmHNB3x6e3c0vA==", + "version": "8.4.38", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.38.tgz", + "integrity": "sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==", "funding": [ { "type": "opencollective", @@ -1618,7 +1597,7 @@ "dependencies": { "nanoid": "^3.3.7", "picocolors": "^1.0.0", - "source-map-js": "^1.0.2" + "source-map-js": "^1.2.0" }, "engines": { "node": "^10 || ^12 || >=14" @@ -1876,9 +1855,9 @@ } }, "node_modules/source-map-js": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", - "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz", + "integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==", "engines": { "node": ">=0.10.0" } diff --git a/package.json b/package.json index 8568525e6..efedd03f0 100644 --- a/package.json +++ b/package.json @@ -7,20 +7,20 @@ }, "devDependencies": { "@vitejs/plugin-vue": "4.5.1", - "autoprefixer": "10.4.18", - "axios": "1.6.7", + "autoprefixer": "10.4.19", + "axios": "1.6.8", "laravel-echo": "1.16.0", "laravel-vite-plugin": "0.8.1", - "postcss": "8.4.35", + "postcss": "8.4.38", "pusher-js": "8.4.0-rc2", "tailwindcss": "3.4.1", "vite": "4.5.2", "vue": "3.4.21" }, "dependencies": { + "@tailwindcss/forms": "0.5.7", "@tailwindcss/typography": "0.5.10", - "alpinejs": "3.13.5", - "daisyui": "4.7.2", + "alpinejs": "3.13.7", "ioredis": "5.3.2", "tailwindcss-scrollbar": "0.1.0" } diff --git a/public/svgs/github.svg b/public/svgs/github.svg index 6c77b4144..270db203b 100644 --- a/public/svgs/github.svg +++ b/public/svgs/github.svg @@ -1 +1 @@ - + diff --git a/public/svgs/unknown.svg b/public/svgs/unknown.svg deleted file mode 100644 index d7752c454..000000000 --- a/public/svgs/unknown.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/resources/css/app.css b/resources/css/app.css index 1080a84f4..b7965ebbc 100644 --- a/resources/css/app.css +++ b/resources/css/app.css @@ -2,24 +2,176 @@ @tailwind components; @tailwind utilities; -html { - @apply text-neutral-400; +html, +body { + @apply h-full bg-neutral-50 text-neutral-800 dark:bg-base dark:text-neutral-400; } body { @apply text-sm antialiased scrollbar; } -button[isError] { - @apply bg-red-600 hover:bg-red-700; +.input, +.select { + @apply text-black dark:bg-coolgray-100 dark:text-white ring-neutral-300 dark:ring-coolgray-300; } -button[isHighlighted] { - @apply bg-coollabs hover:bg-coollabs-100; +/* Readonly */ +.input { + @apply dark:read-only:text-neutral-500 dark:read-only:ring-0 dark:read-only:bg-coolgray-100/40 placeholder:text-neutral-300 dark:placeholder:text-neutral-700 read-only:text-neutral-500 read-only:bg-neutral-200; } +/* Focus */ +.input, +.select { + @apply focus:ring-2 dark:focus:ring-coolgray-300 focus:ring-neutral-400; +} + +.input, +.select { + @apply block w-full py-1.5 rounded border-0 text-sm ring-1 ring-inset; +} + +.input[type='password'] { + @apply pr-10; +} + +option { + @apply dark:text-white dark:bg-coolgray-100; +} + +.button { + @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) { + @apply text-white bg-red-600 hover:bg-red-700; +} + +button[isHighlighted]:not(:disabled) { + @apply text-white bg-coollabs hover:bg-coollabs-100; +} + + +h1 { + @apply text-2xl font-bold dark:text-white; +} + +h2 { + @apply text-xl font-bold dark:text-white; +} + +h3 { + @apply text-lg font-bold dark:text-white; +} + +h4 { + @apply text-base font-bold dark:text-white; +} + +a { + @apply hover:text-black dark:hover:text-white; +} + +label { + @apply dark:text-neutral-400; +} + +table { + @apply min-w-full divide-y dark:divide-coolgray-200 divide-neutral-300; +} + +thead { + @apply uppercase; +} + +tbody { + @apply divide-y dark:divide-coolgray-200 divide-neutral-300; +} + +tr { + @apply text-neutral-400; +} + +tr th { + @apply px-3 py-3.5 text-left text-black dark:text-white; +} + +tr th:first-child { + @apply py-3.5 pl-4 pr-3 sm:pl-6; +} + +tr td { + @apply px-3 py-4 whitespace-nowrap; +} + +tr td:first-child { + @apply pl-4 pr-3 font-bold sm:pl-6; +} + +.alert-success { + @apply flex items-center gap-2 text-success; +} + +.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-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 { + @apply inline-block w-3 h-3 text-xs font-bold leading-none border rounded-full border-neutral-200 dark:border-black; +} + +.badge-success { + @apply bg-success; +} + +.badge-warning { + @apply bg-warning; +} + +.badge-error { + @apply bg-error; +} + +/* [type='checkbox']:checked { + background-image: url("data:image/svg+xml,%3csvg viewBox='0 0 16 16' fill='black' xmlns='http://www.w3.org/2000/svg'%3e%3cpath d='M12.207 4.793a1 1 0 010 1.414l-5 5a1 1 0 01-1.414 0l-2-2a1 1 0 011.414-1.414L6.5 9.086l4.293-4.293a1 1 0 011.414 0z'/%3e%3c/svg%3e"); +} */ + +.menu { + @apply flex items-center gap-1; +} + +.menu-item { + @apply flex items-center w-full gap-3 py-1 pl-2 dark:hover:bg-coolgray-100 dark:hover:text-white hover:bg-neutral-300; +} + +.menu-item-active { + @apply text-black rounded-none dark:bg-coolgray-200 dark:text-warning bg-neutral-200; +} + +.heading-item-active { + @apply text-black rounded-none dark:bg-coolgray-200 dark:text-warning; +} + +.icon { + @apply w-6 h-6 dark:hover:text-white; +} + + .scrollbar { - @apply scrollbar-thumb-coollabs-100 scrollbar-track-coolgray-200 scrollbar-w-2; + @apply scrollbar-thumb-coollabs-100 dark:scrollbar-track-coolgray-200 scrollbar-track-neutral-200 scrollbar-w-2; } .main { @@ -27,64 +179,46 @@ .main { } .custom-modal { - @apply flex flex-col gap-2 px-8 py-4 border bg-base-100 border-coolgray-200; -} - -.label-text, -label { - @apply text-neutral-400; + @apply z-50 flex flex-col gap-2 px-8 py-4 border dark:bg-coolgray-100 dark:border-coolgray-200; } .navbar-main { - @apply flex items-end gap-6 py-2 border-b-2 border-solid border-coolgray-200; + @apply flex items-center h-10 gap-6 pb-2 border-b-2 border-solid dark:border-coolgray-200; } .loading { - @apply w-4 text-warning; -} - -h1 { - @apply text-3xl font-bold text-white; -} - -h2 { - @apply text-2xl font-bold text-white; -} - -h3 { - @apply text-xl font-bold text-white; -} - -h4 { - @apply text-base font-bold text-white; -} - -a { - @apply text-neutral-400 hover:text-white link link-hover hover:bg-transparent; + @apply w-4 dark:text-warning text-coollabs; } .kbd-custom { - @apply px-2 text-xs border border-dashed rounded border-neutral-700 text-warning; -} - -.icon { - @apply w-6 h-6; -} - -.icon:hover { - @apply text-white; + @apply px-2 text-xs border border-dashed rounded border-neutral-700 dark:text-warning; } .box { - @apply flex p-2 transition-colors cursor-pointer min-h-[4rem] bg-coolgray-100 hover:bg-coollabs-100 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 text-black dark:text-white hover:text-black 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; } -.box-without-bg { - @apply flex p-2 transition-colors hover:text-white hover:no-underline min-h-[4rem]; +.on-box { + @apply rounded hover:bg-neutral-300 dark:hover:bg-coolgray-500/20; +} + + +.box-title { + @apply font-bold text-black dark:text-white group-hover:dark:text-white; +} + +.box-description { + @apply text-xs font-bold text-neutral-500 group-hover:dark:text-white group-hover:text-black; } .description { - @apply text-xs font-bold text-neutral-500 group-hover:text-white; + @apply text-xs font-bold text-neutral-500 group-hover:dark:text-white group-hover:text-black; } .lds-heart { @@ -122,56 +256,33 @@ .bg-coollabs-gradient { } .text-helper { - @apply inline-block font-bold text-warning; + @apply inline-block font-bold text-coollabs dark:text-warning; } -table { - @apply min-w-full divide-y divide-coolgray-200; +.info-helper { + @apply cursor-pointer text-coollabs dark:text-warning; } -thead { - @apply uppercase; -} - -tbody { - @apply divide-y divide-coolgray-200; -} - -tr { - @apply text-neutral-400; -} - -tr th { - @apply px-3 py-3.5 text-left text-white; -} - -tr th:first-child { - @apply py-3.5 pl-4 pr-3 sm:pl-6; -} - -tr td { - @apply px-3 py-4 whitespace-nowrap; -} - -tr td:first-child { - @apply pl-4 pr-3 font-bold sm:pl-6; +.info-helper-popup { + @apply absolute z-40 hidden text-xs rounded text-neutral-700 group-hover:block dark:border-coolgray-500 border-neutral-900 dark:bg-coolgray-400 bg-neutral-200 dark:text-neutral-300; } .buyme { @apply block px-3 py-2 mt-10 text-sm font-semibold leading-6 text-center text-white rounded-md shadow-sm bg-coolgray-200 hover:bg-coolgray-300 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-coolgray-200 hover:no-underline; } +.title { + @apply hidden pb-0 lg:block lg:pb-8; +} + .subtitle { - @apply pt-2 pb-10; + @apply pt-2 pb-9; } .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; } -input.input-sm { - @apply pr-10; -} -option{ - @apply text-white; +.toast { + z-index: 1; } diff --git a/resources/js/app.js b/resources/js/app.js index a49c95e97..47313863b 100644 --- a/resources/js/app.js +++ b/resources/js/app.js @@ -1,6 +1,5 @@ import { createApp } from "vue"; import MagicBar from "./components/MagicBar.vue"; -import "../../vendor/wire-elements/modal/resources/js/modal"; const app = createApp({}); app.component("magic-bar", MagicBar); diff --git a/resources/js/components/MagicBar.vue b/resources/js/components/MagicBar.vue index 386a267b1..611ec0891 100644 --- a/resources/js/components/MagicBar.vue +++ b/resources/js/components/MagicBar.vue @@ -9,6 +9,7 @@ + / @@ -38,7 +39,7 @@ class="mt-4 mb-2 text-xs font-semibold text-neutral-500">{{ possibleSequences[sequenceState.sequence[sequenceState.currentActionIndex]].newTitle }} -
    +
    • @@ -53,12 +54,12 @@ {{ sequenceState.sequence[sequenceState.currentActionIndex] }} name will be: - {{ search }} + {{ search }} {{ sequenceState.sequence[sequenceState.currentActionIndex] }} name will be: - randomly generated (type to + randomly generated (type to change) @@ -66,7 +67,7 @@
  • -
      +
      • {{ possibleSequences[sequenceState.sequence[sequenceState.currentActionIndex]].title }} -
          +
          • + + class="absolute top-0 right-0 -mt-2 -mr-2 font-bold dark:text-warning">+
            {{ action.name }} diff --git a/resources/views/auth/confirm-password.blade.php b/resources/views/auth/confirm-password.blade.php index 491d25cac..8d491a218 100644 --- a/resources/views/auth/confirm-password.blade.php +++ b/resources/views/auth/confirm-password.blade.php @@ -2,8 +2,8 @@
            -
            Coolify
            - +
            Coolify
            + {{-- --}}
            diff --git a/resources/views/auth/forgot-password.blade.php b/resources/views/auth/forgot-password.blade.php index d52a5b4e3..54d57a302 100644 --- a/resources/views/auth/forgot-password.blade.php +++ b/resources/views/auth/forgot-password.blade.php @@ -1,18 +1,15 @@ -
            -
            -
            - -
            Coolify
            -
            - +
            +
            + + Coolify +
            + {{ __('auth.forgot_password') }}
            - -
            -

            {{ __('auth.forgot_password') }}

            -
            -
            - @if (is_transactional_emails_active()) +
            +
            + @if (is_transactional_emails_active()) @csrf @@ -20,7 +17,7 @@ @else
            Transactional emails are not active on this instance.
            -
            See how to set it in our See how to set it in our docs, or how to manually reset password.
            @@ -37,7 +34,9 @@ {{ session('status') }}
            @endif +
            -
            + + diff --git a/resources/views/auth/login.blade.php b/resources/views/auth/login.blade.php index ed288f9ee..82ea5062b 100644 --- a/resources/views/auth/login.blade.php +++ b/resources/views/auth/login.blade.php @@ -1,67 +1,77 @@ -
            -
            -
            -
            Coolify
            -
            -
            -

            {{ __('auth.login') }}

            - @if ($is_registration_enabled) - @if (config('coolify.waitlist')) - - Join the waitlist - - @else - - {{ __('auth.register_now') }} - - @endif - @endif -
            -
            -
            - @csrf - @env('local') +
            +
            + + Coolify + +
            +
            + + @csrf + @env('local') + {{ __('auth.forgot_password') }}? @else - + {{ __('auth.forgot_password') }}? - @endenv - {{ __('auth.login') }} - @if (!$is_registration_enabled) -
            {{ __('auth.registration_disabled') }}
            - @endif - @if ($errors->any()) -
            - @foreach ($errors->all() as $error) -

            {{ $error }}

            - @endforeach -
            - @endif - @if (session('status')) -
            - {{ session('status') }} -
            - @endif - @if (session('error')) -
            - {{ session('error') }} -
            - @endif - + @endenv + {{ __('auth.login') }} + @if ($is_registration_enabled) + + {{ __('auth.register_now') }} + + @endif + @if ($enabled_oauth_providers->isNotEmpty()) +
            + +
            + or +
            +
            + @endif + @foreach ($enabled_oauth_providers as $provider_setting) + + {{ __("auth.login.$provider_setting->provider") }} + + @endforeach + @if (!$is_registration_enabled) +
            {{ __('auth.registration_disabled') }}
            + @endif + @if ($errors->any()) +
            + @foreach ($errors->all() as $error) +

            {{ $error }}

            + @endforeach +
            + @endif + @if (session('status')) +
            + {{ session('status') }} +
            + @endif + @if (session('error')) +
            + {{ session('error') }} +
            + @endif + +
            -
            + diff --git a/resources/views/auth/register.blade.php b/resources/views/auth/register.blade.php index ce632f31b..f57d8c6fc 100644 --- a/resources/views/auth/register.blade.php +++ b/resources/views/auth/register.blade.php @@ -1,48 +1,53 @@ -
            -
            -
            -
            Coolify
            - +
            +
            + + Coolify + +
            +
            +

            + Create an account +

            +
            + @csrf + @env('local') + + +
            + + +
            + @else + + +
            + + +
            + @endenv + Register + + {{ __('auth.already_registered') }} + + + @if ($errors->any()) +
            + @foreach ($errors->all() as $error) +

            {{ $error }}

            + @endforeach +
            + @endif + +
            -
            -

            {{ __('auth.register') }}

            - - {{ __('auth.already_registered') }} - -
            -
            - @csrf - @env('local') - - -
            - - -
            - @else - - -
            - - -
            - @endenv - {{ __('auth.register') }} - - @if ($errors->any()) -
            - @foreach ($errors->all() as $error) -

            {{ $error }}

            - @endforeach -
            - @endif
            -
            + diff --git a/resources/views/auth/reset-password.blade.php b/resources/views/auth/reset-password.blade.php index 6b248cfee..d227a7498 100644 --- a/resources/views/auth/reset-password.blade.php +++ b/resources/views/auth/reset-password.blade.php @@ -3,7 +3,7 @@
            diff --git a/resources/views/auth/two-factor-challenge.blade.php b/resources/views/auth/two-factor-challenge.blade.php index 90d975f22..33094920c 100644 --- a/resources/views/auth/two-factor-challenge.blade.php +++ b/resources/views/auth/two-factor-challenge.blade.php @@ -2,32 +2,26 @@
            -
            Coolify
            - +
            Coolify
            + {{-- --}}
            -
            +
            @csrf - - +
            + + {{--
            Use + Recovery Code +
            --}} +
            +
            + + {{--
            Use + One-Time Code +
            --}} +
            {{ __('auth.login') }}
            @if ($errors->any()) diff --git a/resources/views/auth/verify-email.blade.php b/resources/views/auth/verify-email.blade.php index 7db8da43b..cfdd68291 100644 --- a/resources/views/auth/verify-email.blade.php +++ b/resources/views/auth/verify-email.blade.php @@ -1,6 +1,6 @@ - -
            -
            + +
            +

            Verification Email Sent


            To activate your account, please open the email and follow the @@ -8,5 +8,5 @@
            -
            - + + diff --git a/resources/views/components/applications/advanced.blade.php b/resources/views/components/applications/advanced.blade.php index 622708103..46ea54e99 100644 --- a/resources/views/components/applications/advanced.blade.php +++ b/resources/views/components/applications/advanced.blade.php @@ -1,50 +1,36 @@ -
            -
            - - -
            + @else + + @endif + diff --git a/resources/views/components/applications/links.blade.php b/resources/views/components/applications/links.blade.php index 7f3bed2da..a14d0e3ae 100644 --- a/resources/views/components/applications/links.blade.php +++ b/resources/views/components/applications/links.blade.php @@ -1,54 +1,100 @@ -
            + + + Links + @if ( (data_get($application, 'fqdn') || collect(json_decode($this->application->docker_compose_domains))->count() > 0 || data_get($application, 'previews', collect([]))->count() > 0 || data_get($application, 'ports_mappings_array')) && data_get($application, 'settings.is_raw_compose_deployment_enabled') !== true) - - - + @endforeach + @endif + @else +
            No links available
            @endif -
            + diff --git a/resources/views/components/banner.blade.php b/resources/views/components/banner.blade.php index d75a6d75e..a28e5445d 100644 --- a/resources/views/components/banner.blade.php +++ b/resources/views/components/banner.blade.php @@ -6,7 +6,7 @@ x-transition:enter-start="-translate-y-10" x-transition:enter-end="translate-y-0" x-transition:leave="transition ease-in duration-100" x-transition:leave-start="translate-y-0" x-transition:leave-end="-translate-y-10" x-init="setTimeout(() => { bannerVisible = true }, bannerVisibleAfter);" - class="relative z-50 w-full py-2 mx-auto duration-100 ease-out shadow-sm bg-coolgray-100 sm:py-0 sm:h-14" x-cloak> + class="relative z-[999] w-full py-2 mx-auto duration-100 ease-out shadow-sm bg-coolgray-100 sm:py-0 sm:h-14" x-cloak>
            {{ $slot }} @if ($closable) diff --git a/resources/views/components/boarding-step.blade.php b/resources/views/components/boarding-step.blade.php index a8d47da37..d963e55f0 100644 --- a/resources/views/components/boarding-step.blade.php +++ b/resources/views/components/boarding-step.blade.php @@ -1,22 +1,22 @@
            -
            -

            {{ $title }}

            -
            +
            +

            {{ $title }}

            +
            @isset($question) -

            +

            {{ $question }}

            @endisset
            @if ($actions) -
            +
            {{ $actions }}
            @endif
            @isset($explanation)
            -

            Explanation

            +

            Explanation

            {{ $explanation }}
            diff --git a/resources/views/components/confirm-modal.blade.php b/resources/views/components/confirm-modal.blade.php index 461ac2637..a0cd8d01e 100644 --- a/resources/views/components/confirm-modal.blade.php +++ b/resources/views/components/confirm-modal.blade.php @@ -20,7 +20,7 @@
            -
            +
            Confirm Cancel diff --git a/resources/views/components/databases/navbar.blade.php b/resources/views/components/databases/navbar.blade.php deleted file mode 100644 index 962c3d22e..000000000 --- a/resources/views/components/databases/navbar.blade.php +++ /dev/null @@ -1,46 +0,0 @@ - diff --git a/resources/views/components/dropdown.blade.php b/resources/views/components/dropdown.blade.php new file mode 100644 index 000000000..0eb8086a1 --- /dev/null +++ b/resources/views/components/dropdown.blade.php @@ -0,0 +1,23 @@ +
            + + +
            +
            + {{ $slot }} +
            +
            +
            diff --git a/resources/views/components/external-link.blade.php b/resources/views/components/external-link.blade.php index 0ee609a91..ddf03427f 100644 --- a/resources/views/components/external-link.blade.php +++ b/resources/views/components/external-link.blade.php @@ -1 +1,7 @@ - + diff --git a/resources/views/components/forms/button.blade.php b/resources/views/components/forms/button.blade.php index f3bec86e9..3eafc26c6 100644 --- a/resources/views/components/forms/button.blade.php +++ b/resources/views/components/forms/button.blade.php @@ -6,15 +6,10 @@ @isset($confirmAction) x-on:{{ explode('(', $confirmAction)[0] }}.window="$wire.{{ explode('(', $confirmAction)[0] }}" @endisset - @if ($isModal) onclick="{{ $modalId }}.showModal()" @endif> + > {{ $slot }} - @if ($attributes->get('type') === 'submit') - - @else - @if ($attributes->whereStartsWith('wire:click')->first()) - - @endif + @if ($attributes->whereStartsWith('wire:click')->first()) + @endif diff --git a/resources/views/components/forms/checkbox.blade.php b/resources/views/components/forms/checkbox.blade.php index 12ed8edb3..f3e3d5c9e 100644 --- a/resources/views/components/forms/checkbox.blade.php +++ b/resources/views/components/forms/checkbox.blade.php @@ -1,6 +1,6 @@ -
            +
          • - - - - + @endif +
            + @if (isInstanceAdmin() && !isCloud()) +
          • + @persist('upgrade') + + @endpersist +
          • + @endif +
          • + + + + + Onboarding + +
          • +
          • + + + + + + + + Sponsor us + +
          • + @endif +
          • + + + + + + +
          • +
          • +
            + @csrf + +
            +
          • +
          + + {{--
        • +
          Your teams
          + - -@endauth +
        • + + W + Workcation + +
        • +
        +
      • +
      • + + + Your profile + + +
      • --}} +
      + diff --git a/resources/views/components/notification/navbar.blade.php b/resources/views/components/notification/navbar.blade.php new file mode 100644 index 000000000..24b4fecfd --- /dev/null +++ b/resources/views/components/notification/navbar.blade.php @@ -0,0 +1,18 @@ +
      +

      Notifications

      +
      Get notified about your infrastructure.
      + +
      diff --git a/resources/views/components/notifications/navbar.blade.php b/resources/views/components/notifications/navbar.blade.php deleted file mode 100644 index 65b374249..000000000 --- a/resources/views/components/notifications/navbar.blade.php +++ /dev/null @@ -1,25 +0,0 @@ -
      -
      -

      Team Notifications

      -
      - - -
      diff --git a/resources/views/components/popup.blade.php b/resources/views/components/popup.blade.php new file mode 100644 index 000000000..8061c29bd --- /dev/null +++ b/resources/views/components/popup.blade.php @@ -0,0 +1,36 @@ +@props(['title' => 'Default title', 'description' => 'Default Description', 'buttonText' => 'Default Button Text']) +
      +
      +
      + @if (isset($icon)) + {{ $icon }} + @endif + +
      +

      + {{ $title }} +

      +

      {{ $description }}

      +
      +
      +
      + +
      +
      +
      diff --git a/resources/views/components/pricing-plans.blade.php b/resources/views/components/pricing-plans.blade.php index e6ea81342..ca71bf93e 100644 --- a/resources/views/components/pricing-plans.blade.php +++ b/resources/views/components/pricing-plans.blade.php @@ -5,7 +5,7 @@
      + 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"> Payment frequency
      @if (config('constants.limits.trial_period') > 0)
      {{ config('constants.limits.trial_period') }} + class="font-bold dark:text-warning">{{ config('constants.limits.trial_period') }} days trial included on all plans, without credit card details.
      @endif
      -
      Save 10% annually with the yearly plans. +
      Save 10% annually with the yearly plans.
      @@ -36,29 +36,29 @@ class="font-bold text-warning">{{ config('constants.limits.trial_period') }}
      {{--

      Unlimited Trial - Get Started

      -

      Start self-hosting without limits with +

      Start self-hosting without limits with our OSS version. Same features as the paid version, but you have to manage by yourself.

      --}}
      For the detailed list of features, please visit our landing page: coolify.io
      + class="font-bold underline dark:text-white" href="https://coolify.io">coolify.io
      -

      Basic

      +

      Basic

      - $5 + $5 /month + VAT - $4 + $4 /month + VAT

      @@ -73,21 +73,21 @@ class="grid max-w-sm grid-cols-1 -mt-16 divide-y divide-coolgray-500 isolate gap {{ $basic }} @endisset @endif -

      Begin hosting your own services in the +

      Begin hosting your own services in the cloud.

      • - - Connect 2 servers + Connect 2 servers
      • -
      • -

        Pro

        +

        Pro

        - $30 + $30 /month + VAT - $27 + $27 /month + VAT

        @@ -141,21 +141,21 @@ class="grid max-w-sm grid-cols-1 -mt-16 divide-y divide-coolgray-500 isolate gap {{ $pro }} @endisset @endif -

        Expand your business or set up your own hosting +

        Expand your business or set up your own hosting environment.

        • - - Connect 10 servers + Connect 10 servers
        • -
        • -

          Ultimate

          +

          Ultimate

          - Custom + Custom {{-- pay-as-you-go --}} - Custom + Custom {{-- /month + VAT --}}

          @@ -209,21 +209,21 @@ class="grid max-w-sm grid-cols-1 -mt-16 divide-y divide-coolgray-500 isolate gap {{ $ultimate }} @endisset @endif -

          Easily manage complex infrastructures in a +

          Easily manage complex infrastructures in a single location.

          • - - Connect 10+ servers + Connect 10+ servers
          • -
          • Need official support for your self-hosted instance? - Contact Us @@ -267,11 +267,11 @@ class="grid max-w-sm grid-cols-1 -mt-16 divide-y divide-coolgray-500 isolate gap
      --}}
      - {{--
      Included in all plans
      + {{--
      Included in all plans
      -
      +
      -
      Bring Your Own Servers
      +
      Bring Your Own Servers
      Bring your own server from any cloud providers, or even your own server at home! All you need is SSH @@ -288,7 +288,7 @@ class="grid max-w-sm grid-cols-1 -mt-16 divide-y divide-coolgray-500 isolate gap
      -
      +
      Server Automations
      +
      Server Automations
      Once you connected your server, Coolify will start managing it and do a lot of administrative tasks for you. You can also write your own scripts to - automate your server*. + automate your server*.
      -
      +
      No Vendor Lock-in
      +
      No Vendor Lock-in
      You own your own data. All configurations saved on your own servers, so if @@ -334,7 +334,7 @@ class="grid max-w-sm grid-cols-1 -mt-16 divide-y divide-coolgray-500 isolate gap
      -
      +
      @@ -346,7 +346,7 @@ class="grid max-w-sm grid-cols-1 -mt-16 divide-y divide-coolgray-500 isolate gap
      -
      Monitoring
      +
      Monitoring
      Coolify will automatically monitor your configured servers and deployed @@ -356,7 +356,7 @@ class="grid max-w-sm grid-cols-1 -mt-16 divide-y divide-coolgray-500 isolate gap
      -
      +
      Automatic Backups
      +
      Automatic Backups
      We automatically backup your databases to any S3 compatible solution. If @@ -375,7 +375,7 @@ class="grid max-w-sm grid-cols-1 -mt-16 divide-y divide-coolgray-500 isolate gap
      -
      +
      @@ -384,17 +384,17 @@ class="grid max-w-sm grid-cols-1 -mt-16 divide-y divide-coolgray-500 isolate gap
      -
      Powerful API
      +
      Powerful API
      Programmatically deploy, query, and manage your servers & resources. Integrate to your CI/CD pipelines, or build your own custom integrations. * + class="dark:text-warning">*
      -
      +
      *
      -
      Push to Deploy
      +
      Push to Deploy
      Git integration is default today. We support hosted (github.com, - gitlab.com*) or self-hosted* + gitlab.com*) or self-hosted* (Github Enterprise, Gitlab) Git repositories.
      -
      +
      * d="M10 13a2 2 0 1 0 4 0a2 2 0 0 0-4 0m-2 8v-1a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v1M15 5a2 2 0 1 0 4 0a2 2 0 0 0-4 0m2 5h2a2 2 0 0 1 2 2v1M5 5a2 2 0 1 0 4 0a2 2 0 0 0-4 0m-2 8v-1a2 2 0 0 1 2-2h2" />
      -
      Pull Request Deployments
      +
      Pull Request Deployments
      Automagically deploy new commits and pull requests separately to quickly @@ -434,7 +434,7 @@ class="text-warning">*
      - * Some features are work in progress and will be available soon. + * Some features are work in progress and will be available soon.
      --}}
      @isset($other) diff --git a/resources/views/components/resource-view.blade.php b/resources/views/components/resource-view.blade.php index e4872dd21..d6cc12026 100644 --- a/resources/views/components/resource-view.blade.php +++ b/resources/views/components/resource-view.blade.php @@ -1,18 +1,18 @@
      !$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>
      {{ $logo }}
      -
      +
      {{ $title }}
      - @if($upgrade) -
      {{ $upgrade }}
      + @if ($upgrade) +
      {{ $upgrade }}
      @else - diff --git a/resources/views/components/resources/breadcrumbs.blade.php b/resources/views/components/resources/breadcrumbs.blade.php index 6e2b234a3..5b0956c93 100644 --- a/resources/views/components/resources/breadcrumbs.blade.php +++ b/resources/views/components/resources/breadcrumbs.blade.php @@ -7,19 +7,19 @@
    • -
    • -

      Security

      - +
      Security related settings.
      diff --git a/resources/views/components/server/navbar.blade.php b/resources/views/components/server/navbar.blade.php index 08a8019a8..5afee652c 100644 --- a/resources/views/components/server/navbar.blade.php +++ b/resources/views/components/server/navbar.blade.php @@ -10,40 +10,40 @@ @endif
    • -
      {{ data_get($server, 'name') }}
      +
      {{ data_get($server, 'name') }}.
      diff --git a/resources/views/components/server/sidebar.blade.php b/resources/views/components/server/sidebar.blade.php index ef2b4b8e7..2b06ba7e6 100644 --- a/resources/views/components/server/sidebar.blade.php +++ b/resources/views/components/server/sidebar.blade.php @@ -1,17 +1,17 @@
      - @if ($server->proxyType() !== 'NONE') {{-- @if ($server->proxyType() === 'TRAEFIK_V2') --}} - {{-- @endif --}} - diff --git a/resources/views/components/services/links.blade.php b/resources/views/components/services/links.blade.php index 2bbd9c65b..84394f792 100644 --- a/resources/views/components/services/links.blade.php +++ b/resources/views/components/services/links.blade.php @@ -1,31 +1,18 @@ @if ($links->count() > 0) -
      - - - -
      + + + Links + + @foreach ($links as $link) + + + + + + + {{ $link }} + + @endforeach + @endif diff --git a/resources/views/components/services/navbar.blade.php b/resources/views/components/services/navbar.blade.php deleted file mode 100644 index 3f5dc15f5..000000000 --- a/resources/views/components/services/navbar.blade.php +++ /dev/null @@ -1,94 +0,0 @@ - - -@script - -@endscript diff --git a/resources/views/components/settings/navbar.blade.php b/resources/views/components/settings/navbar.blade.php index 93625efd9..fc431d220 100644 --- a/resources/views/components/settings/navbar.blade.php +++ b/resources/views/components/settings/navbar.blade.php @@ -2,12 +2,12 @@

      Settings

      Instance wide settings for Coolify.