feat: dockerfile build pack

This commit is contained in:
Andras Bacsai 2023-08-11 22:41:47 +02:00
parent 82a01b4483
commit 619d395331
21 changed files with 330 additions and 137 deletions

View File

@ -1,16 +0,0 @@
<?php
namespace App\Http\Livewire\Dev;
use App\Models\ScheduledDatabaseBackup;
use Livewire\Component;
class ScheduledBackups extends Component
{
public $scheduledDatabaseBackup;
public function mount()
{
$this->scheduledDatabaseBackup = ScheduledDatabaseBackup::all();
}
}

View File

@ -47,6 +47,7 @@ class General extends Component
'application.publish_directory' => 'nullable',
'application.ports_exposes' => 'required',
'application.ports_mappings' => 'nullable',
'application.dockerfile' => 'nullable',
];
protected $validationAttributes = [
'application.name' => 'name',
@ -64,6 +65,7 @@ class General extends Component
'application.publish_directory' => 'Publish directory',
'application.ports_exposes' => 'Ports exposes',
'application.ports_mappings' => 'Ports mappings',
'application.dockerfile' => 'Dockerfile',
];
public function instantSave()
@ -140,6 +142,10 @@ public function submit()
$domains = Str::of($this->application->fqdn)->trim()->explode(',')->map(function ($domain) {
return Str::of($domain)->trim()->lower();
});
$port = get_port_from_dockerfile($this->application->dockerfile);
if ($port) {
$this->application->ports_exposes = $port;
}
if ($this->application->base_directory && $this->application->base_directory !== '/') {
$this->application->base_directory = rtrim($this->application->base_directory, '/');
}

View File

@ -0,0 +1,68 @@
<?php
namespace App\Http\Livewire\Project\New;
use App\Models\Application;
use App\Models\GithubApp;
use App\Models\Project;
use App\Models\StandaloneDocker;
use App\Models\SwarmDocker;
use Livewire\Component;
use Visus\Cuid2\Cuid2;
class SimpleDockerfile extends Component
{
public string $dockerfile = '';
public array $parameters;
public array $query;
public function mount()
{
$this->parameters = get_route_parameters();
$this->query = request()->query();
if (is_dev()) {
$this->dockerfile = 'FROM nginx
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
';
}
}
public function submit()
{
$this->validate([
'dockerfile' => 'required'
]);
$destination_uuid = $this->query['destination'];
$destination = StandaloneDocker::where('uuid', $destination_uuid)->first();
if (!$destination) {
$destination = SwarmDocker::where('uuid', $destination_uuid)->first();
}
if (!$destination) {
throw new \Exception('Destination not found. What?!');
}
$destination_class = $destination->getMorphClass();
$project = Project::where('uuid', $this->parameters['project_uuid'])->first();
$environment = $project->load(['environments'])->environments->where('name', $this->parameters['environment_name'])->first();
$port = get_port_from_dockerfile($this->dockerfile);
$application = Application::create([
'name' => 'dockerfile-' . new Cuid2(7),
'repository_project_id' => 0,
'git_repository' => "coollabsio/coolify",
'git_branch' => 'main',
'build_pack' => 'dockerfile',
'dockerfile' => $this->dockerfile,
'ports_exposes' => $port,
'environment_id' => $environment->id,
'destination_id' => $destination->id,
'destination_type' => $destination_class,
'source_id' => 0,
'source_type' => GithubApp::class
]);
redirect()->route('project.application.configuration', [
'application_uuid' => $application->uuid,
'environment_name' => $environment->name,
'project_uuid' => $project->uuid,
]);
}
}

View File

@ -28,6 +28,10 @@ public function mount()
$this->parameters = get_route_parameters();
}
public function instantSave()
{
$this->submit();
}
public function submit()
{
$this->validate();

View File

@ -117,10 +117,14 @@ public function handle(): void
'status' => ApplicationDeploymentStatus::IN_PROGRESS->value,
]);
try {
if ($this->pull_request_id !== 0) {
$this->deploy_pull_request();
if ($this->application->dockerfile) {
$this->deploy_simple_dockerfile();
} else {
$this->deploy();
if ($this->pull_request_id !== 0) {
$this->deploy_pull_request();
} else {
$this->deploy();
}
}
if ($this->application->fqdn) dispatch(new ProxyStartJob($this->server));
$this->next(ApplicationDeploymentStatus::FINISHED->value);
@ -150,7 +154,74 @@ public function handle(): void
);
}
}
private function deploy_simple_dockerfile()
{
$dockerfile_base64 = base64_encode($this->application->dockerfile);
$this->execute_remote_command(
[
"echo 'Starting deployment of {$this->application->name}.'"
],
);
$this->prepare_builder_image();
$this->execute_remote_command(
[
$this->execute_in_builder("echo '$dockerfile_base64' | base64 -d > $this->workdir/Dockerfile")
],
);
$this->build_image_name = "{$this->application->git_repository}:build";
$this->production_image_name = "{$this->application->uuid}:latest";
ray('Build Image Name: ' . $this->build_image_name . ' & Production Image Name: ' . $this->production_image_name)->green();
$this->generate_compose_file();
$this->generate_build_env_variables();
$this->add_build_env_variables_to_dockerfile();
$this->build_image();
$this->stop_running_container();
$this->start_by_compose_file();
}
private function deploy()
{
$this->execute_remote_command(
[
"echo 'Starting deployment of {$this->application->git_repository}:{$this->application->git_branch}.'"
],
);
$this->prepare_builder_image();
$this->clone_repository();
$tag = Str::of("{$this->commit}-{$this->application->id}-{$this->pull_request_id}");
if (strlen($tag) > 128) {
$tag = $tag->substr(0, 128);
}
$this->build_image_name = "{$this->application->git_repository}:{$tag}-build";
$this->production_image_name = "{$this->application->uuid}:{$tag}";
ray('Build Image Name: ' . $this->build_image_name . ' & Production Image Name: ' . $this->production_image_name)->green();
if (!$this->force_rebuild) {
$this->execute_remote_command([
"docker images -q {$this->production_image_name} 2>/dev/null", "hidden" => true, "save" => "local_image_found"
]);
if (Str::of($this->saved_outputs->get('local_image_found'))->isNotEmpty()) {
$this->execute_remote_command([
"echo 'Docker Image found locally with the same Git Commit SHA {$this->application->uuid}:{$this->commit}. Build step skipped...'"
]);
$this->generate_compose_file();
$this->stop_running_container();
$this->start_by_compose_file();
return;
}
}
$this->cleanup_git();
if ($this->application->build_pack === 'nixpacks') {
$this->generate_nixpacks_confs();
}
$this->generate_compose_file();
$this->generate_build_env_variables();
$this->add_build_env_variables_to_dockerfile();
$this->build_image();
$this->stop_running_container();
$this->start_by_compose_file();
}
private function deploy_pull_request()
{
$this->build_image_name = "{$this->application->uuid}:pr-{$this->pull_request_id}-build";
@ -162,7 +233,9 @@ private function deploy_pull_request()
$this->prepare_builder_image();
$this->clone_repository();
$this->cleanup_git();
$this->generate_buildpack();
if ($this->application->build_pack === 'nixpacks') {
$this->generate_nixpacks_confs();
}
$this->generate_compose_file();
// Needs separate preview variables
// $this->generate_build_env_variables();
@ -277,7 +350,7 @@ private function cleanup_git()
);
}
private function generate_buildpack()
private function generate_nixpacks_confs()
{
$this->execute_remote_command(
[
@ -589,49 +662,7 @@ private function start_by_compose_file()
);
}
private function deploy()
{
$this->execute_remote_command(
[
"echo 'Starting deployment of {$this->application->git_repository}:{$this->application->git_branch}.'"
],
);
$this->prepare_builder_image();
$this->clone_repository();
$tag = Str::of("{$this->commit}-{$this->application->id}-{$this->pull_request_id}");
if (strlen($tag) > 128) {
$tag = $tag->substr(0, 128);
}
$this->build_image_name = "{$this->application->git_repository}:{$tag}-build";
$this->production_image_name = "{$this->application->uuid}:{$tag}";
ray('Build Image Name: ' . $this->build_image_name . ' & Production Image Name: ' . $this->production_image_name)->green();
if (!$this->force_rebuild) {
$this->execute_remote_command([
"docker images -q {$this->production_image_name} 2>/dev/null", "hidden" => true, "save" => "local_image_found"
]);
if (Str::of($this->saved_outputs->get('local_image_found'))->isNotEmpty()) {
$this->execute_remote_command([
"echo 'Docker Image found locally with the same Git Commit SHA {$this->application->uuid}:{$this->commit}. Build step skipped...'"
]);
$this->generate_compose_file();
$this->stop_running_container();
$this->start_by_compose_file();
return;
}
}
$this->cleanup_git();
$this->generate_buildpack();
$this->generate_compose_file();
$this->generate_build_env_variables();
$this->add_build_env_variables_to_dockerfile();
$this->build_image();
$this->stop_running_container();
$this->start_by_compose_file();
}
private function generate_build_env_variables()
{

View File

@ -215,4 +215,18 @@ public function deploymentType()
}
throw new \Exception('No deployment type found');
}
public function could_set_build_commands(): bool
{
if ($this->build_pack === 'nixpacks') {
return true;
}
return false;
}
public function git_based(): bool
{
if ($this->dockerfile || $this->build_pack === 'dockerfile') {
return false;
}
return true;
}
}

View File

@ -6,7 +6,7 @@
class GithubApp extends BaseModel
{
protected $fillable = ['name', 'uuid', 'organization', 'api_url', 'html_url', 'custom_user', 'custom_port', 'team_id', 'client_secret', 'webhook_secret'];
protected $guarded = [];
protected $appends = ['type'];
protected $casts = [
'is_public' => 'boolean',

View File

@ -64,3 +64,13 @@ function generate_container_name(string $uuid, int $pull_request_id = 0)
return $uuid;
}
}
function get_port_from_dockerfile($dockerfile): int
{
$port = preg_grep('/EXPOSE\s+(\d+)/', explode("\n", $dockerfile));
if (count($port) > 0 && preg_match('/EXPOSE\s+(\d+)/', $port[1], $matches)) {
$port = $matches[1];
} else {
$port = 80;
}
return $port;
}

View File

@ -0,0 +1,25 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::table('applications', function (Blueprint $table) {
$table->longText('dockerfile')->nullable();
});
}
public function down(): void
{
Schema::table('applications', function (Blueprint $table) {
$table->dropColumn('dockerfile');
});
}
};

View File

@ -23,11 +23,27 @@ public function run(): void
'git_branch' => 'nodejs-fastify',
'build_pack' => 'nixpacks',
'ports_exposes' => '3000',
'ports_mappings' => '3000:3000',
'ports_mappings' => '3005:3000',
'environment_id' => 1,
'destination_id' => 0,
'destination_type' => StandaloneDocker::class,
'source_id' => 1,
'source_id' => 0,
'source_type' => GithubApp::class
]);
Application::create([
'name' => 'coollabsio/coolify-examples:dockerfile',
'description' => 'Dockerfile Example',
'fqdn' => 'http://foos.com',
'repository_project_id' => 603035348,
'git_repository' => 'coollabsio/coolify-examples',
'git_branch' => 'dockerfile',
'build_pack' => 'dockerfile',
'ports_exposes' => '3000',
'ports_mappings' => '3080:80',
'environment_id' => 1,
'destination_id' => 0,
'destination_type' => StandaloneDocker::class,
'source_id' => 0,
'source_type' => GithubApp::class
]);
}

View File

@ -13,6 +13,7 @@ class GithubAppSeeder extends Seeder
public function run(): void
{
GithubApp::create([
'id' => 0,
'name' => 'Public GitHub',
'api_url' => 'https://api.github.com',
'html_url' => 'https://github.com',

View File

@ -23,7 +23,6 @@
</div>
</div>
@if (is_dev())
<livewire:dev.s3-test />
<livewire:dev.scheduled-backups />
{{-- <livewire:dev.s3-test /> --}}
@endif
</x-layout>

View File

@ -1,13 +0,0 @@
<div>
<h2>Scheduled Databse Backups</h2>
@foreach ($scheduledDatabaseBackup as $backup)
<div>
{{ $backup->id }}
{{ $backup->database->id }}
{{ $backup->frequency }}
{{ $backup->database->type() }}
{{ $backup->created_at }}
{{ $backup->updated_at }}
</div>
@endforeach
</div>

View File

@ -18,7 +18,7 @@ class="scrollbar flex flex-col-reverse w-full overflow-y-auto border border-dott
@if (decode_remote_command_output($application_deployment_queue)->count() > 0)
@foreach (decode_remote_command_output($application_deployment_queue) as $line)
<div @class([
'font-mono break-all whitespace-pre-wrap',
'font-mono break-all',
'text-neutral-400' => $line['type'] == 'stdout',
'text-error' => $line['type'] == 'stderr',
'text-warning' => $line['hidden'],

View File

@ -12,10 +12,10 @@
<x-forms.input id="application.name" label="Name" required />
<x-forms.input id="application.description" label="Description" />
</div>
<x-forms.input placeholder="https://coolify.io" id="application.fqdn" label="Domains"
helper="You can specify one domain with path or more with comma.<br><span class='text-helper'>Example</span>- http://app.coolify.io, https://cloud.coolify.io/dashboard<br>- http://app.coolify.io/api/v3" />
@if ($wildcard_domain)
<div class="flex flex-row gap-2">
<div class="flex items-end gap-2">
<x-forms.input placeholder="https://coolify.io" id="application.fqdn" label="Domains"
helper="You can specify one domain with path or more with comma.<br><span class='text-helper'>Example</span>- http://app.coolify.io, https://cloud.coolify.io/dashboard<br>- http://app.coolify.io/api/v3" />
@if ($wildcard_domain)
@if ($global_wildcard_domain)
<x-forms.button wire:click="generateGlobalRandomDomain">Set Global Wildcard
</x-forms.button>
@ -24,11 +24,11 @@
<x-forms.button wire:click="generateServerRandomDomain">Set Server Wildcard
</x-forms.button>
@endif
</div>
@endif
@endif
</div>
<x-forms.select id="application.build_pack" label="Build Pack" required>
<option value="nixpacks">Nixpacks</option>
<option disabled value="docker">Docker</option>
<option value="dockerfile">Dockerfile</option>
<option disabled value="compose">Compose</option>
</x-forms.select>
@if ($application->settings->is_static)
@ -37,22 +37,30 @@
<option disabled value="apache:alpine">apache:alpine</option>
</x-forms.select>
@endif
<h3>Build</h3>
<div class="flex flex-col gap-2 xl:flex-row">
<x-forms.input placeholder="pnpm install" id="application.install_command" label="Install Command" />
<x-forms.input placeholder="pnpm build" id="application.build_command" label="Build Command" />
<x-forms.input placeholder="pnpm start" id="application.start_command" label="Start Command" />
</div>
<div class="flex flex-col gap-2 xl:flex-row">
<x-forms.input placeholder="/" id="application.base_directory" label="Base Directory"
helper="Directory to use as root. Useful for monorepos. WIP" disabled />
@if ($application->settings->is_static)
<x-forms.input placeholder="/dist" id="application.publish_directory" label="Publish Directory"
required />
@else
<x-forms.input placeholder="/" id="application.publish_directory" label="Publish Directory" />
@endif
</div>
@if ($application->could_set_build_commands())
<h3>Build</h3>
<div class="flex flex-col gap-2 xl:flex-row">
<x-forms.input placeholder="pnpm install" id="application.install_command"
label="Install Command" />
<x-forms.input placeholder="pnpm build" id="application.build_command" label="Build Command" />
<x-forms.input placeholder="pnpm start" id="application.start_command" label="Start Command" />
</div>
<div class="flex flex-col gap-2 xl:flex-row">
<x-forms.input placeholder="/" id="application.base_directory" label="Base Directory"
helper="Directory to use as root. Useful for monorepos. WIP" disabled />
@if ($application->settings->is_static)
<x-forms.input placeholder="/dist" id="application.publish_directory" label="Publish Directory"
required />
@else
<x-forms.input placeholder="/" id="application.publish_directory" label="Publish Directory" />
@endif
</div>
@endif
@if ($application->dockerfile)
<x-forms.textarea label="Dockerfile" id="application.dockerfile" rows="6"> </x-forms.textarea>
@endif
<h3>Network</h3>
<div class="flex flex-col gap-2 xl:flex-row">
@if ($application->settings->is_static)
@ -67,20 +75,26 @@
</div>
<h3>Advanced</h3>
<div class="flex flex-col">
<x-forms.checkbox instantSave id="is_static" label="Is it a static site?"
helper="If your application is a static site or the final build assets should be served as a static site, enable this." />
@if ($application->could_set_build_commands())
<x-forms.checkbox instantSave id="is_static" label="Is it a static site?"
helper="If your application is a static site or the final build assets should be served as a static site, enable this." />
@endif
<x-forms.checkbox
helper="Your application will be available only on https if your domain starts with https://..."
instantSave id="is_force_https_enabled" label="Force Https" />
<x-forms.checkbox helper="Automatically deploy new commits based on Git webhooks." instantSave
id="is_auto_deploy_enabled" label="Auto Deploy" />
<x-forms.checkbox
helper="Allow to automatically deploy Preview Deployments for all opened PR's.<br><br>Closing a PR will delete Preview Deployments."
instantSave id="is_preview_deployments_enabled" label="Previews Deployments" />
<x-forms.checkbox instantSave id="is_git_submodules_enabled" label="Git Submodules"
helper="Allow Git Submodules during build process." />
<x-forms.checkbox instantSave id="is_git_lfs_enabled" label="Git LFS"
helper="Allow Git LFS during build process." />
@if ($application->git_based())
<x-forms.checkbox helper="Automatically deploy new commits based on Git webhooks." instantSave
id="is_auto_deploy_enabled" label="Auto Deploy" />
<x-forms.checkbox
helper="Allow to automatically deploy Preview Deployments for all opened PR's.<br><br>Closing a PR will delete Preview Deployments."
instantSave id="is_preview_deployments_enabled" label="Previews Deployments" />
<x-forms.checkbox instantSave id="is_git_submodules_enabled" label="Git Submodules"
helper="Allow Git Submodules during build process." />
<x-forms.checkbox instantSave id="is_git_lfs_enabled" label="Git LFS"
helper="Allow Git LFS during build process." />
@endif
{{-- <x-forms.checkbox disabled instantSave id="is_dual_cert" label="Dual Certs?" />
<x-forms.checkbox disabled instantSave id="is_custom_ssl" label="Is Custom SSL?" />
<x-forms.checkbox disabled instantSave id="is_http2" label="Is Http2?" /> --}}

View File

@ -1,6 +1,6 @@
<div>
<h1>Create a new Application</h1>
<div class="pt-2">Deploy any public or private Git repositories through a Deploy Key.</div>
<div class="pb-4">Deploy any public or private Git repositories through a Deploy Key.</div>
<div class="flex flex-col pt-10">
@if ($current_step === 'private_keys')
<ul class="pb-10 steps">

View File

@ -1,16 +1,16 @@
<div x-data x-init="$wire.load_servers">
<h1>New Resource</h1>
<div class="pb-4 ">Deploy resources, like Applications, Databases, Services...</div>
<div class="flex flex-col pt-10">
<div class="flex flex-col gap-2 pt-10">
@if ($current_step === 'type')
<ul class="pb-10 steps">
<li class="step step-secondary">Select Source Type</li>
<li class="step">Select a Server</li>
<li class="step">Select a Destination</li>
</ul>
<h3 class="pb-4">Applications</h3>
<div class="flex flex-col justify-center gap-2 text-left xl:flex-row">
<div class="gap-2 py-4 cursor-pointer group hover:bg-coollabs bg-coolgray-200"
<h2>Applications</h2>
<div class="grid justify-start grid-cols-1 gap-2 text-left xl:grid-cols-3">
<div class="gap-2 py-4 cursor-pointer group hover:bg-coollabs bg-coolgray-200 min-w-[24rem]"
wire:click="set_type('public')">
<div class="flex flex-col mx-6">
<div class="group-hover:text-white">
@ -21,7 +21,7 @@
</div>
</div>
</div>
<div class="gap-2 py-4 cursor-pointer group hover:bg-coollabs bg-coolgray-200"
<div class="gap-2 py-4 cursor-pointer group hover:bg-coollabs bg-coolgray-200 min-w-[24rem]"
wire:click="set_type('private-gh-app')">
<div class="flex flex-col mx-6">
<div class="group-hover:text-white">
@ -32,7 +32,7 @@
</div>
</div>
</div>
<div class="gap-2 py-4 cursor-pointer group hover:bg-coollabs bg-coolgray-200"
<div class="gap-2 py-4 cursor-pointer group hover:bg-coollabs bg-coolgray-200 min-w-[24rem]"
wire:click="set_type('private-deploy-key')">
<div class="flex flex-col mx-6">
<div class="group-hover:text-white">
@ -44,8 +44,21 @@
</div>
</div>
</div>
<h3 class="py-4">Databases</h3>
<div class="flex flex-col justify-center gap-2 text-left xl:flex-row">
<div class="grid justify-start grid-cols-1 gap-2 text-left xl:grid-cols-3">
<div class="gap-2 py-4 cursor-pointer group hover:bg-coollabs bg-coolgray-200 min-w-[24rem]"
wire:click="set_type('dockerfile')">
<div class="flex flex-col mx-6">
<div class="group-hover:text-white">
Based on a Dockerfile
</div>
<div class="text-xs group-hover:text-white">
You can deploy a simple Dockerfile, without Git.
</div>
</div>
</div>
</div>
<h2 class="py-4">Databases</h2>
<div class="flex flex-col justify-start gap-2 text-left xl:flex-row">
<div class="gap-2 py-4 cursor-pointer group hover:bg-coollabs bg-coolgray-200"
wire:click="set_type('postgresql')">
<div class="flex flex-col mx-6">

View File

@ -0,0 +1,15 @@
<div>
<h1>Create a new Application</h1>
<div class="pb-4">You can deploy a simple Dockerfile, without Git.</div>
<form wire:submit.prevent="submit">
<div class="flex gap-2 pb-1">
<h2>Dockerfile</h2>
<x-forms.button type="submit">Save</x-forms.button>
</div>
<x-forms.textarea rows="20" id="dockerfile"
placeholder='FROM nginx
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
'></x-forms.textarea>
</form>
</div>

View File

@ -8,9 +8,7 @@ class="font-bold text-warning">({{ $env->key }})</span>?</p>
<form wire:submit.prevent='submit' class="flex flex-col items-center gap-2 xl:flex-row">
<x-forms.input id="env.key" />
<x-forms.input type="password" id="env.value" />
@if (data_get($parameters, 'application_uuid'))
<x-forms.checkbox disabled id="env.is_build_time" label="Build Variable?" />
@endif
<x-forms.checkbox instantSave id="env.is_build_time" label="Build Variable?" />
<div class="flex gap-2">
<x-forms.button type="submit">
Update

View File

@ -9,8 +9,10 @@
@click.prevent="activeTab = 'environment-variables'; window.location.hash = 'environment-variables'"
href="#">Environment
Variables</a>
<a :class="activeTab === 'source' && 'text-white'"
@click.prevent="activeTab = 'source'; window.location.hash = 'source'" href="#">Source</a>
@if ($application->git_based())
<a :class="activeTab === 'source' && 'text-white'"
@click.prevent="activeTab = 'source'; window.location.hash = 'source'" href="#">Source</a>
@endif
<a :class="activeTab === 'destination' && 'text-white'"
@click.prevent="activeTab = 'destination'; window.location.hash = 'destination'"
href="#">Destination
@ -18,10 +20,12 @@
<a :class="activeTab === 'storages' && 'text-white'"
@click.prevent="activeTab = 'storages'; window.location.hash = 'storages'" href="#">Storages
</a>
<a :class="activeTab === 'previews' && 'text-white'"
@click.prevent="activeTab = 'previews'; window.location.hash = 'previews'" href="#">Previews
Deployments
</a>
@if ($application->git_based())
<a :class="activeTab === 'previews' && 'text-white'"
@click.prevent="activeTab = 'previews'; window.location.hash = 'previews'" href="#">Previews
Deployments
</a>
@endif
<a :class="activeTab === 'rollback' && 'text-white'"
@click.prevent="activeTab = 'rollback'; window.location.hash = 'rollback'" href="#">Rollback
</a>
@ -40,9 +44,11 @@
<div x-cloak x-show="activeTab === 'environment-variables'">
<livewire:project.shared.environment-variable.all :resource="$application" />
</div>
<div x-cloak x-show="activeTab === 'source'">
<livewire:project.application.source :application="$application" />
</div>
@if ($application->git_based())
<div x-cloak x-show="activeTab === 'source'">
<livewire:project.application.source :application="$application" />
</div>
@endif
<div x-cloak x-show="activeTab === 'destination'">
<livewire:project.shared.destination :destination="$application->destination" />
</div>

View File

@ -5,6 +5,8 @@
<livewire:project.new.github-private-repository :type="$type" />
@elseif ($type === 'private-deploy-key')
<livewire:project.new.github-private-repository-deploy-key :type="$type" />
@elseif ($type === 'dockerfile')
<livewire:project.new.simple-dockerfile :type="$type" />
@else
<livewire:project.new.select />
@endif