This commit is contained in:
Andras Bacsai 2023-06-05 12:07:55 +02:00
parent 0f28acac00
commit e5aad4d170
42 changed files with 518 additions and 238 deletions

View File

@ -21,7 +21,7 @@ class Deploy extends Component
protected $source;
protected $listeners = [
'applicationStatusChanged' => 'applicationStatusChanged',
'applicationStatusChanged',
];
public function mount()
@ -40,8 +40,12 @@ protected function set_deployment_uuid()
$this->deployment_uuid = new Cuid2(7);
$this->parameters['deployment_uuid'] = $this->deployment_uuid;
}
public function deploy(bool $force = false)
public function deploy(bool $force = false, bool|null $debug = null)
{
if ($debug && !$this->application->settings->is_debug_enabled) {
$this->application->settings->is_debug_enabled = true;
$this->application->settings->save();
}
$this->set_deployment_uuid();
queue_application_deployment(
@ -62,5 +66,6 @@ public function stop()
instant_remote_process(["docker rm -f {$this->application->uuid}"], $this->application->destination->server);
$this->application->status = get_container_status(server: $this->application->destination->server, container_id: $this->application->uuid);
$this->application->save();
$this->emit('applicationStatusChanged');
}
}

View File

@ -2,15 +2,12 @@
namespace App\Http\Livewire\Project\Application\EnvironmentVariable;
use App\Models\Application;
use App\Models\EnvironmentVariable;
use Illuminate\Database\QueryException;
use Illuminate\Support\Facades\Route;
use Livewire\Component;
class Add extends Component
{
public $parameters;
public bool $is_preview = false;
public string $key;
public string $value;
public bool $is_build_time = false;
@ -32,6 +29,7 @@ public function submit()
'key' => $this->key,
'value' => $this->value,
'is_build_time' => $this->is_build_time,
'is_preview' => $this->is_preview,
]);
}
public function clear()

View File

@ -21,6 +21,7 @@ public function submit($data)
'key' => $data['key'],
'value' => $data['value'],
'is_build_time' => $data['is_build_time'],
'is_preview' => $data['is_preview'],
'application_id' => $this->application->id,
]);
$this->application->refresh();

View File

@ -11,7 +11,7 @@ class Status extends Component
public function applicationStatusChanged()
{
$this->emit('applicationStatusChanged');
$this->application->refresh();
$this->emit('applicationStatusChanged');
}
}

View File

@ -14,16 +14,22 @@
class PublicGitRepository extends Component
{
public string $repository_url;
private object $repository_url_parsed;
public int $port = 3000;
public string $type;
public $parameters;
public $query;
public $github_apps;
public $gitlab_apps;
public $branches = [];
public string $selected_branch = 'main';
public bool $is_static = false;
public null|string $publish_directory = null;
public string|null $publish_directory = null;
private GithubApp|GitlabApp $git_source;
private string $git_host;
private string $git_repository;
private string $git_branch;
protected $rules = [
'repository_url' => 'required|url',
@ -34,7 +40,7 @@ class PublicGitRepository extends Component
public function mount()
{
if (config('app.env') === 'local') {
$this->repository_url = 'https://github.com/coollabsio/coolify-examples/tree/nodejs-fastify';
$this->repository_url = 'https://github.com/coollabsio/coolify-examples';
$this->port = 3000;
}
$this->parameters = get_parameters();
@ -52,18 +58,43 @@ public function instantSave()
}
$this->emit('saved', 'Application settings updated!');
}
public function load_branches()
{
$this->get_git_source();
try {
['data' => $data] = get_from_git_api($this->git_source, "/repos/{$this->git_repository}/branches");
$this->branches = collect($data)->pluck('name')->toArray();
} catch (\Throwable $th) {
return general_error_handler($th, $this);
}
}
private function get_git_source()
{
$this->repository_url_parsed = Url::fromString($this->repository_url);
$this->git_host = $this->repository_url_parsed->getHost();
$this->git_repository = $this->repository_url_parsed->getSegment(1) . '/' . $this->repository_url_parsed->getSegment(2);
$this->git_branch = $this->repository_url_parsed->getSegment(4) ?? 'main';
if ($this->git_host == 'github.com') {
$this->git_source = GithubApp::where('name', 'Public GitHub')->first();
} elseif ($this->git_host == 'gitlab.com') {
$this->git_source = GitlabApp::where('name', 'Public GitLab')->first();
} elseif ($this->git_host == 'bitbucket.org') {
// Not supported yet
}
}
public function submit()
{
try {
$this->validate();
$url = Url::fromString($this->repository_url);
$git_host = $url->getHost();
$git_repository = $url->getSegment(1) . '/' . $url->getSegment(2);
$git_branch = $url->getSegment(4) ?? 'main';
$destination_uuid = $this->query['destination'];
$project_uuid = $this->parameters['project_uuid'];
$environment_name = $this->parameters['environment_name'];
$this->get_git_source();
$this->git_branch = $this->selected_branch ?? $this->git_branch;
$destination = StandaloneDocker::where('uuid', $destination_uuid)->first();
if (!$destination) {
$destination = SwarmDocker::where('uuid', $destination_uuid)->first();
@ -73,29 +104,24 @@ public function submit()
}
$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();
$project = Project::where('uuid', $project_uuid)->first();
$environment = $project->load(['environments'])->environments->where('name', $environment_name)->first();
$application_init = [
'name' => generate_application_name($git_repository, $git_branch),
'git_repository' => $git_repository,
'git_branch' => $git_branch,
'name' => generate_application_name($this->git_repository, $this->git_branch),
'git_repository' => $this->git_repository,
'git_branch' => $this->git_branch,
'build_pack' => 'nixpacks',
'ports_exposes' => $this->port,
'publish_directory' => $this->publish_directory,
'environment_id' => $environment->id,
'destination_id' => $destination->id,
'destination_type' => $destination_class,
'source_id' => $this->git_source->id,
'source_type' => $this->git_source->getMorphClass()
];
if ($git_host == 'github.com') {
$application_init['source_id'] = GithubApp::where('name', 'Public GitHub')->first()->id;
$application_init['source_type'] = GithubApp::class;
} elseif ($git_host == 'gitlab.com') {
$application_init['source_id'] = GitlabApp::where('name', 'Public GitLab')->first()->id;
$application_init['source_type'] = GitlabApp::class;
} elseif ($git_host == 'bitbucket.org') {
}
$application = Application::create($application_init);
$application->settings->is_static = $this->is_static;
$application->settings->save();
@ -106,7 +132,7 @@ public function submit()
'application_uuid' => $application->uuid,
]);
} catch (\Exception $e) {
return general_error_handler($e);
return general_error_handler($e, $this);
}
}
}

View File

@ -63,7 +63,7 @@ public function __construct(
$this->application = Application::find($this->application_id);
if ($this->pull_request_id) {
if ($this->pull_request_id !== 0) {
$this->preview = ApplicationPreview::findPreviewByApplicationAndPullId($this->application->id, $this->pull_request_id);
}
@ -97,7 +97,7 @@ public function handle(): void
}
$this->workdir = "/artifacts/{$this->deployment_uuid}";
if ($this->pull_request_id) {
if ($this->pull_request_id !== 0) {
ray('Deploying pull/' . $this->pull_request_id . '/head for application: ' . $this->application->name);
$this->deploy_pull_request();
} else {
@ -177,7 +177,7 @@ private function build_image()
"echo -n 'Building image... '",
]);
if ($this->application->settings->is_static) {
if ($this->application->settings->is_static && isset($this->application->build_command)) {
$this->execute_now([
$this->execute_in_builder("docker build -f {$this->workdir}/Dockerfile {$this->build_args} --progress plain -t { $this->build_image_name {$this->workdir}"),
], isDebuggable: true);
@ -292,9 +292,17 @@ private function execute_in_builder(string $command)
private function generate_environment_variables($ports)
{
$environment_variables = collect();
foreach ($this->application->runtime_environment_variables as $env) {
$environment_variables->push("$env->key=$env->value");
ray('Generate Environment Variables');
if ($this->pull_request_id === 0) {
ray($this->application->runtime_environment_variables);
foreach ($this->application->runtime_environment_variables as $env) {
$environment_variables->push("$env->key=$env->value");
}
} else {
ray($this->application->runtime_environment_variables_preview);
foreach ($this->application->runtime_environment_variables_preview as $env) {
$environment_variables->push("$env->key=$env->value");
}
}
// Add PORT if not exists, use the first port as default
if ($environment_variables->filter(fn ($env) => Str::of($env)->contains('PORT'))->isEmpty()) {
@ -305,17 +313,31 @@ private function generate_environment_variables($ports)
private function generate_env_variables()
{
$this->env_args = collect([]);
foreach ($this->application->nixpacks_environment_variables as $env) {
$this->env_args->push("--env {$env->key}={$env->value}");
if ($this->pull_request_id === 0) {
foreach ($this->application->nixpacks_environment_variables as $env) {
$this->env_args->push("--env {$env->key}={$env->value}");
}
} else {
foreach ($this->application->nixpacks_environment_variables_preview as $env) {
$this->env_args->push("--env {$env->key}={$env->value}");
}
}
$this->env_args = $this->env_args->implode(' ');
}
private function generate_build_env_variables()
{
$this->build_args = collect(["--build-arg SOURCE_COMMIT={$this->git_commit}"]);
foreach ($this->application->build_environment_variables as $env) {
$this->build_args->push("--build-arg {$env->key}={$env->value}");
if ($this->pull_request_id === 0) {
foreach ($this->application->build_environment_variables as $env) {
$this->build_args->push("--build-arg {$env->key}={$env->value}");
}
} else {
foreach ($this->application->build_environment_variables_preview as $env) {
$this->build_args->push("--build-arg {$env->key}={$env->value}");
}
}
$this->build_args = $this->build_args->implode(' ');
}
private function add_build_env_variables_to_dockerfile()
@ -336,15 +358,11 @@ private function add_build_env_variables_to_dockerfile()
private function generate_docker_compose()
{
$ports = $this->application->settings->is_static ? [80] : $this->application->ports_exposes_array;
if ($this->pull_request_id) {
$persistent_storages = [];
$volume_names = [];
$environment_variables = [];
} else {
$persistent_storages = $this->generate_local_persistent_volumes();
$volume_names = $this->generate_local_persistent_volumes_only_volume_names();
$environment_variables = $this->generate_environment_variables($ports);
}
$persistent_storages = $this->generate_local_persistent_volumes();
$volume_names = $this->generate_local_persistent_volumes_only_volume_names();
$environment_variables = $this->generate_environment_variables($ports);
$docker_compose = [
'version' => '3.8',
'services' => [
@ -385,7 +403,7 @@ private function generate_docker_compose()
]
]
];
if (count($this->application->ports_mappings_array) > 0 && !$this->pull_request_id) {
if (count($this->application->ports_mappings_array) > 0 && $this->pull_request_id === 0) {
$docker_compose['services'][$this->container_name]['ports'] = $this->application->ports_mappings_array;
}
if (count($persistent_storages) > 0) {
@ -400,8 +418,12 @@ private function generate_local_persistent_volumes()
{
foreach ($this->application->persistentStorages as $persistentStorage) {
$volume_name = $persistentStorage->host_path ?? $persistentStorage->name;
if ($this->pull_request_id !== 0) {
$volume_name = $volume_name . '-pr-' . $this->pull_request_id;
}
$local_persistent_volumes[] = $volume_name . ':' . $persistentStorage->mount_path;
}
ray('local_persistent_volumes', $local_persistent_volumes);
return $local_persistent_volumes ?? [];
}
@ -411,8 +433,14 @@ private function generate_local_persistent_volumes_only_volume_names()
if ($persistentStorage->host_path) {
continue;
}
$local_persistent_volumes_names[$persistentStorage->name] = [
'name' => $persistentStorage->name,
$name = $persistentStorage->name;
if ($this->pull_request_id !== 0) {
$name = $name . '-pr-' . $this->pull_request_id;
}
$local_persistent_volumes_names[$name] = [
'name' => $name,
'external' => false,
];
}
@ -443,11 +471,11 @@ private function set_labels_for_applications()
$labels[] = 'coolify.applicationId=' . $this->application->id;
$labels[] = 'coolify.type=application';
$labels[] = 'coolify.name=' . $this->application->name;
if ($this->pull_request_id) {
if ($this->pull_request_id !== 0) {
$labels[] = 'coolify.pullRequestId=' . $this->pull_request_id;
}
if ($this->application->fqdn) {
if ($this->pull_request_id) {
if ($this->pull_request_id !== 0) {
$preview_fqdn = data_get($this->preview, 'fqdn');
$template = $this->application->preview_url_template;
$url = Url::fromString($this->application->fqdn);
@ -566,7 +594,7 @@ private function set_git_import_settings($git_clone_command)
private function importing_git_repository()
{
$git_clone_command = "git clone -q -b {$this->application->git_branch}";
if ($this->pull_request_id) {
if ($this->pull_request_id !== 0) {
$pr_branch_name = "pr-{$this->pull_request_id}-coolify";
}
@ -583,7 +611,7 @@ private function importing_git_repository()
$commands = [$this->execute_in_builder($git_clone_command)];
if ($this->pull_request_id) {
if ($this->pull_request_id !== 0) {
$commands[] = $this->execute_in_builder("cd {$this->workdir} && git fetch origin pull/{$this->pull_request_id}/head:$pr_branch_name >/dev/null 2>&1 && git checkout $pr_branch_name >/dev/null 2>&1");
}
return $commands;
@ -592,7 +620,7 @@ private function importing_git_repository()
$commands = [
$this->execute_in_builder("git clone -q -b {$this->application->git_branch} $source_html_url_scheme://x-access-token:$github_access_token@$source_html_url_host/{$this->application->git_repository}.git {$this->workdir}")
];
if ($this->pull_request_id) {
if ($this->pull_request_id !== 0) {
$commands[] = $this->execute_in_builder("cd {$this->workdir} && git fetch origin pull/{$this->pull_request_id}/head:$pr_branch_name && git checkout $pr_branch_name");
}
return $commands;

View File

@ -99,21 +99,39 @@ public function portsExposesArray(): Attribute
: explode(',', $this->ports_exposes)
);
}
// Normal Deployments
public function environment_variables(): HasMany
{
return $this->hasMany(EnvironmentVariable::class);
return $this->hasMany(EnvironmentVariable::class)->where('is_preview', false);
}
public function runtime_environment_variables(): HasMany
{
return $this->hasMany(EnvironmentVariable::class)->where('key', 'not like', 'NIXPACKS_%');
return $this->hasMany(EnvironmentVariable::class)->where('is_preview', false)->where('key', 'not like', 'NIXPACKS_%');
}
public function build_environment_variables(): HasMany
{
return $this->hasMany(EnvironmentVariable::class)->where('is_build_time', true)->where('key', 'not like', 'NIXPACKS_%');
return $this->hasMany(EnvironmentVariable::class)->where('is_preview', false)->where('is_build_time', true)->where('key', 'not like', 'NIXPACKS_%');
}
public function nixpacks_environment_variables(): HasMany
{
return $this->hasMany(EnvironmentVariable::class)->where('key', 'like', 'NIXPACKS_%');
return $this->hasMany(EnvironmentVariable::class)->where('is_preview', false)->where('key', 'like', 'NIXPACKS_%');
}
// Preview Deployments
public function environment_variables_preview(): HasMany
{
return $this->hasMany(EnvironmentVariable::class)->where('is_preview', true);
}
public function runtime_environment_variables_preview(): HasMany
{
return $this->hasMany(EnvironmentVariable::class)->where('is_preview', true)->where('key', 'not like', 'NIXPACKS_%');
}
public function build_environment_variables_preview(): HasMany
{
return $this->hasMany(EnvironmentVariable::class)->where('is_preview', true)->where('is_build_time', true)->where('key', 'not like', 'NIXPACKS_%');
}
public function nixpacks_environment_variables_preview(): HasMany
{
return $this->hasMany(EnvironmentVariable::class)->where('is_preview', true)->where('key', 'like', 'NIXPACKS_%');
}
public function private_key()
{

View File

@ -2,13 +2,28 @@
namespace App\Models;
use App\Models\EnvironmentVariable as ModelsEnvironmentVariable;
use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Str;
class EnvironmentVariable extends Model
{
protected $fillable = ['key', 'value', 'is_build_time', 'application_id'];
protected static function booted()
{
static::created(function ($environment_variable) {
if (!$environment_variable->is_preview) {
ModelsEnvironmentVariable::create([
'key' => $environment_variable->key,
'value' => $environment_variable->value,
'is_build_time' => $environment_variable->is_build_time,
'application_id' => $environment_variable->application_id,
'is_preview' => true,
]);
}
});
}
protected $fillable = ['key', 'value', 'is_build_time', 'application_id', 'is_preview'];
protected $casts = [
"key" => 'string',
'value' => 'encrypted',

View File

@ -17,14 +17,15 @@ public function up(): void
$table->string('key');
$table->string('value')->nullable();
$table->boolean('is_build_time')->default(false);
$table->boolean('is_preview')->default(false);
$table->foreignId('application_id')->nullable();
$table->foreignId('service_id')->nullable();
$table->foreignId('database_id')->nullable();
$table->unique(['key', 'application_id', 'is_build_time']);
$table->unique(['key', 'service_id', 'is_build_time']);
$table->unique(['key', 'database_id', 'is_build_time']);
$table->unique(['key', 'application_id', 'is_build_time', 'is_preview']);
$table->unique(['key', 'service_id', 'is_build_time', 'is_preview']);
$table->unique(['key', 'database_id', 'is_build_time', 'is_preview']);
$table->timestamps();
});
}

8
package-lock.json generated
View File

@ -7,7 +7,7 @@
"dependencies": {
"@tailwindcss/typography": "0.5.9",
"alpinejs": "3.12.2",
"daisyui": "3.0.0",
"daisyui": "3.0.3",
"tailwindcss-scrollbar": "0.1.0"
},
"devDependencies": {
@ -941,9 +941,9 @@
"dev": true
},
"node_modules/daisyui": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/daisyui/-/daisyui-3.0.0.tgz",
"integrity": "sha512-EuNK9JQd5yrPLDynAPQkG/29vjZXFWhBK4HXvM83d9oJU0EmF35UNLLs0cslBFfLK4b+bOuhgoYPJ4BjytOxNQ==",
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/daisyui/-/daisyui-3.0.3.tgz",
"integrity": "sha512-RSbXsEBj2LonvjOKEI0I64F5xFJrFrthPgxRNeAZKmACQ3NoIoP45lO6UXLW3bm8PVOUGpKf1Br2SWwc1NqnHQ==",
"dependencies": {
"colord": "^2.9",
"css-selector-tokenizer": "^0.8",

View File

@ -17,7 +17,7 @@
"dependencies": {
"@tailwindcss/typography": "0.5.9",
"alpinejs": "3.12.2",
"daisyui": "3.0.0",
"daisyui": "3.0.3",
"tailwindcss-scrollbar": "0.1.0"
}
}

View File

@ -14,14 +14,14 @@ body {
@apply scrollbar min-h-screen bg-coolgray-100 text-neutral-400 antialiased ;
}
main {
@apply px-32 xl:px-14 mx-auto max-w-screen-xl;
@apply px-32 xl:px-14 mx-auto max-w-screen-xl pt-10;
}
input[type="checkbox"] {
@apply toggle toggle-warning toggle-xs rounded;
}
input {
@apply input input-sm placeholder:text-neutral-700 text-white rounded-none;
@apply input input-sm h-7 outline-none placeholder:text-neutral-700 text-white rounded-none;
}
input[type="text"],[type="number"],[type="email"],[type="password"] {
@apply read-only:opacity-40;
@ -34,7 +34,7 @@ textarea {
@apply textarea placeholder:text-neutral-700 text-white rounded-none;
}
select {
@apply select select-sm disabled:opacity-40 font-normal placeholder:text-neutral-700 text-white rounded-none;
@apply select select-sm disabled:bg-coolgray-200 border-none disabled:opacity-50 font-normal placeholder:text-neutral-700 text-white rounded-none;
}
.breadcrumbs > ul > li::before {
@apply text-warning opacity-100;
@ -47,7 +47,7 @@ button[type="button"] {
@apply hover:bg-coolgray-400 btn h-7 btn-xs border-none bg-coolgray-200 no-animation normal-case text-white rounded;
}
button[type="submit"] {
@apply btn btn-xs no-animation h-7 normal-case text-white btn-primary rounded;
@apply hover:bg-coolgray-400 btn h-7 btn-xs border-none bg-coolgray-200 no-animation normal-case text-white rounded;
}
button[isWarning] {
@apply bg-error;

View File

@ -15,23 +15,32 @@
]) }}">
<button>Deployments</button>
</a>
<livewire:project.application.status :application="$application" />
<div class="flex-1"></div>
<div class="dropdown dropdown-bottom">
<label tabindex="0">
<x-forms.button>
Open
<x-chevron-down />
</x-forms.button>
<div class="dropdown dropdown-bottom dropdown-hover">
<label tabindex="0" class="flex items-center gap-2 text-sm cursor-pointer hover:text-white"> Links
<x-chevron-down />
</label>
<ul tabindex="0"
class="mt-1 text-xs text-white normal-case rounded min-w-max dropdown-content menu bg-coolgray-200">
class="text-xs text-white normal-case rounded min-w-max dropdown-content menu bg-coolgray-200">
<li>
<a target="_blank" class="text-xs text-white rounded-none hover:no-underline hover:bg-coollabs"
href="{{ $application->gitBranchLocation }}">
<x-git-icon git="{{ $application->source->getMorphClass() }}" />
Git Repository
</a>
</li>
@if (data_get($application, 'fqdn'))
<li>
<a class="text-xs text-white rounded-none hover:no-underline hover:bg-coollabs" target="_blank"
href="{{ $application->fqdn }}">
{{ $application->fqdn }}
<x-external-link />
<svg xmlns="http://www.w3.org/2000/svg" class="w-6 h-6" viewBox="0 0 24 24" stroke-width="1.5"
stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
<path d="M9 15l6 -6" />
<path d="M11 6l.463 -.536a5 5 0 0 1 7.071 7.072l-.534 .464" />
<path
d="M13 18l-.397 .534a5.068 5.068 0 0 1 -7.127 0a4.972 4.972 0 0 1 0 -7.071l.524 -.463" />
</svg>{{ $application->fqdn }}
</a>
</li>
@endif
@ -40,9 +49,16 @@ class="mt-1 text-xs text-white normal-case rounded min-w-max dropdown-content me
@if (config('app.env') === 'local')
<li>
<a class="text-xs text-white rounded-none hover:no-underline hover:bg-coollabs"
target="_blank" href="http://localhost:{{ explode(':', $port)[0] }}">Port
{{ explode(':', $port)[0] }}
<x-external-link />
target="_blank" href="http://localhost:{{ explode(':', $port)[0] }}">
<svg xmlns="http://www.w3.org/2000/svg" class="w-6 h-6" viewBox="0 0 24 24"
stroke-width="1.5" stroke="currentColor" fill="none" stroke-linecap="round"
stroke-linejoin="round">
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
<path d="M9 15l6 -6" />
<path d="M11 6l.463 -.536a5 5 0 0 1 7.071 7.072l-.534 .464" />
<path
d="M13 18l-.397 .534a5.068 5.068 0 0 1 -7.127 0a4.972 4.972 0 0 1 0 -7.071l.524 -.463" />
</svg>{{ $port }}
</a>
</li>
@else
@ -50,7 +66,6 @@ class="mt-1 text-xs text-white normal-case rounded min-w-max dropdown-content me
<a class="text-xs hover:no-underline hover:bg-coollabs" target="_blank"
href="http://{{ $application->destination->server->ip }}:{{ explode(':', $port)[0] }}">Port
{{ $port }}
<x-external-link />
</a>
</li>
@endif

View File

@ -5,15 +5,17 @@
])
<span {{ $attributes->merge(['class' => 'flex flex-col']) }}>
<label for={{ $id }}>
@if ($label)
{{ $label }}
@else
{{ $id }}
@endif
@if ($required)
<span class="text-warning">*</span>
@endif
<label class="label" for={{ $id }}>
<span class="label-text">
@if ($label)
{{ $label }}
@else
{{ $id }}
@endif
@if ($required)
<span class="text-warning">*</span>
@endif
</span>
</label>
<select {{ $attributes }} wire:model.defer={{ $id }}>
{{ $slot }}

View File

@ -0,0 +1,18 @@
@props([
'git' => null,
])
@if ($git === 'App\Models\GithubApp')
<svg xmlns="http://www.w3.org/2000/svg" class="w-6 h-6" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"
fill="none" stroke-linecap="round" stroke-linejoin="round">
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
<path
d="M9 19c-4.3 1.4 -4.3 -2.5 -6 -3m12 5v-3.5c0 -1 .1 -1.4 -.5 -2c2.8 -.3 5.5 -1.4 5.5 -6a4.6 4.6 0 0 0 -1.3 -3.2a4.2 4.2 0 0 0 -.1 -3.2s-1.1 -.3 -3.5 1.3a12.3 12.3 0 0 0 -6.2 0c-2.4 -1.6 -3.5 -1.3 -3.5 -1.3a4.2 4.2 0 0 0 -.1 3.2a4.6 4.6 0 0 0 -1.3 3.2c0 4.6 2.7 5.7 5.5 6c-.6 .6 -.6 1.2 -.5 2v3.5" />
</svg>
@elseif($git === 'App\Models\GitlabApp')
<svg xmlns="http://www.w3.org/2000/svg" class="w-6 h-6" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"
fill="none" stroke-linecap="round" stroke-linejoin="round">
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
<path d="M21 14l-9 7l-9 -7l3 -11l3 7h6l3 -7z" />
</svg>
@endif

View File

@ -1 +1 @@
<span class="loading loading-bars"></span>
<span {{ $attributes->class(['bg-warning loading', 'loading-spinner' => !$attributes->has('class')]) }}></span>

View File

@ -1,13 +1,16 @@
<div>
@if ($this->activity)
@if ($header)
<h2>Logs</h2>
<div class="flex gap-2">
<h2>Logs</h2>
@if ($isPollingActive)
<x-loading />
@endif
</div>
@endif
<div
class="scrollbar flex flex-col-reverse w-full overflow-y-auto border border-solid rounded border-coolgray-300 max-h-[32rem] p-4 text-xs text-white">
@if ($isPollingActive)
<span class="loading loading-bars"></span>
@endif
<pre class="font-mono whitespace-pre-wrap" @if ($isPollingActive) wire:poll.2000ms="polling" @endif>{{ \App\Actions\CoolifyTask\RunRemoteProcess::decodeOutput($this->activity) }}</pre>
{{-- @else
<pre class="whitespace-pre-wrap">Output will be here...</pre> --}}

View File

@ -1,7 +1,6 @@
<div class="flex items-center gap-2">
<h2>Notifications</h2>
<x-forms.button isHighlighted class="text-white normal-case btn btn-xs no-animation btn-primary"
wire:click="sendTestNotification">
<x-forms.button class="text-white normal-case btn btn-xs no-animation btn-primary" wire:click="sendTestNotification">
Send Test Notifications
</x-forms.button>
</div>

View File

@ -1,40 +1,114 @@
<div class="flex items-center gap-2">
@if ($application->status === 'running')
<div class="dropdown dropdown-bottom">
<x-forms.button isHighlighted tabindex="0" class="">
Actions
<x-chevron-down />
</x-forms.button>
<div class="dropdown dropdown-bottom dropdown-hover">
<label tabindex="0" class="flex items-center gap-2 cursor-pointer hover:text-white"> Actions
<x-chevron-down />
</label>
@if ($application->status === 'running')
<ul tabindex="0"
class="mt-1 text-xs text-white normal-case rounded min-w-max dropdown-content menu bg-coolgray-200">
class="text-xs text-white normal-case rounded min-w-max dropdown-content menu bg-coolgray-200">
<li>
<div class="rounded-none hover:bg-coollabs" wire:click='deploy'>Restart</div>
<div class="rounded-none hover:bg-coollabs" wire:click='deploy'><svg xmlns="http://www.w3.org/2000/svg"
class="w-6 h-6" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" fill="none"
stroke-linecap="round" stroke-linejoin="round">
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
<path d="M20 11a8.1 8.1 0 0 0 -15.5 -2m-.5 -4v4h4" />
<path d="M4 13a8.1 8.1 0 0 0 15.5 2m.5 4v-4h-4" />
<path d="M12 9l0 3" />
<path d="M12 15l.01 0" />
</svg>Restart</div>
</li>
<li>
<div class="rounded-none hover:bg-coollabs" wire:click='deploy(true)'>Force deploy without cache</div>
<div class="rounded-none hover:bg-coollabs" wire:click='deploy(true, true)'><svg
xmlns="http://www.w3.org/2000/svg" class="w-6 h-6" viewBox="0 0 24 24" stroke-width="1.5"
stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
<path d="M9 9v-1a3 3 0 0 1 6 0v1" />
<path d="M8 9h8a6 6 0 0 1 1 3v3a5 5 0 0 1 -10 0v-3a6 6 0 0 1 1 -3" />
<path d="M3 13l4 0" />
<path d="M17 13l4 0" />
<path d="M12 20l0 -6" />
<path d="M4 19l3.35 -2" />
<path d="M20 19l-3.35 -2" />
<path d="M4 7l3.75 2.4" />
<path d="M20 7l-3.75 2.4" />
</svg>Force deploy (with
debug)
</div>
</li>
<li>
<div class="rounded-none hover:bg-red-500" wire:click='stop'>Stop</div>
<div class="rounded-none hover:bg-coollabs" wire:click='deploy(true)'><svg
xmlns="http://www.w3.org/2000/svg" class="w-6 h-6" viewBox="0 0 24 24" stroke-width="1.5"
stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
<path
d="M12.983 8.978c3.955 -.182 7.017 -1.446 7.017 -2.978c0 -1.657 -3.582 -3 -8 -3c-1.661 0 -3.204 .19 -4.483 .515m-2.783 1.228c-.471 .382 -.734 .808 -.734 1.257c0 1.22 1.944 2.271 4.734 2.74" />
<path
d="M4 6v6c0 1.657 3.582 3 8 3c.986 0 1.93 -.067 2.802 -.19m3.187 -.82c1.251 -.53 2.011 -1.228 2.011 -1.99v-6" />
<path d="M4 12v6c0 1.657 3.582 3 8 3c3.217 0 5.991 -.712 7.261 -1.74m.739 -3.26v-4" />
<path d="M3 3l18 18" />
</svg>Force deploy (without
cache)
</div>
</li>
<li>
<div class="rounded-none hover:bg-red-500" wire:click='stop'><svg xmlns="http://www.w3.org/2000/svg"
class="w-6 h-6" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" fill="none"
stroke-linecap="round" stroke-linejoin="round">
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
<path d="M8 13v-7.5a1.5 1.5 0 0 1 3 0v6.5" />
<path d="M11 5.5v-2a1.5 1.5 0 1 1 3 0v8.5" />
<path d="M14 5.5a1.5 1.5 0 0 1 3 0v6.5" />
<path
d="M17 7.5a1.5 1.5 0 0 1 3 0v8.5a6 6 0 0 1 -6 6h-2h.208a6 6 0 0 1 -5.012 -2.7a69.74 69.74 0 0 1 -.196 -.3c-.312 -.479 -1.407 -2.388 -3.286 -5.728a1.5 1.5 0 0 1 .536 -2.022a1.867 1.867 0 0 1 2.28 .28l1.47 1.47" />
</svg>Stop</div>
</li>
</ul>
</div>
@else
<div class="dropdown dropdown-bottom">
<label tabindex="0">
<x-forms.button isHighlighted>
Actions
<x-chevron-down />
</x-forms.button>
</label>
@else
<ul tabindex="0"
class="mt-1 text-xs text-white normal-case rounded min-w-max dropdown-content menu bg-coolgray-200">
class="text-xs text-white normal-case rounded min-w-max dropdown-content menu bg-coolgray-200">
<li>
<div class="rounded-none hover:bg-coollabs" wire:click='deploy'>Deploy</div>
<div class="rounded-none hover:bg-coollabs" wire:click='deploy'><svg
xmlns="http://www.w3.org/2000/svg" class="w-6 h-6" viewBox="0 0 24 24" stroke-width="1.5"
stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
<path d="M7 4v16l13 -8z" />
</svg>Deploy</div>
</li>
<li>
<div class="rounded-none hover:bg-coollabs" wire:click='deploy(true)'>Deploy without cache</div>
<div class="rounded-none hover:bg-coollabs" wire:click='deploy(true, true)'><svg
xmlns="http://www.w3.org/2000/svg" class="w-6 h-6" viewBox="0 0 24 24" stroke-width="1.5"
stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
<path d="M9 9v-1a3 3 0 0 1 6 0v1" />
<path d="M8 9h8a6 6 0 0 1 1 3v3a5 5 0 0 1 -10 0v-3a6 6 0 0 1 1 -3" />
<path d="M3 13l4 0" />
<path d="M17 13l4 0" />
<path d="M12 20l0 -6" />
<path d="M4 19l3.35 -2" />
<path d="M20 19l-3.35 -2" />
<path d="M4 7l3.75 2.4" />
<path d="M20 7l-3.75 2.4" />
</svg>Force deploy (with
debug)
</div>
</li>
<li>
<div class="rounded-none hover:bg-coollabs" wire:click='deploy(true)'><svg
xmlns="http://www.w3.org/2000/svg" class="w-6 h-6" viewBox="0 0 24 24"
stroke-width="1.5" stroke="currentColor" fill="none" stroke-linecap="round"
stroke-linejoin="round">
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
<path
d="M12.983 8.978c3.955 -.182 7.017 -1.446 7.017 -2.978c0 -1.657 -3.582 -3 -8 -3c-1.661 0 -3.204 .19 -4.483 .515m-2.783 1.228c-.471 .382 -.734 .808 -.734 1.257c0 1.22 1.944 2.271 4.734 2.74" />
<path
d="M4 6v6c0 1.657 3.582 3 8 3c.986 0 1.93 -.067 2.802 -.19m3.187 -.82c1.251 -.53 2.011 -1.228 2.011 -1.99v-6" />
<path d="M4 12v6c0 1.657 3.582 3 8 3c3.217 0 5.991 -.712 7.261 -1.74m.739 -3.26v-4" />
<path d="M3 3l18 18" />
</svg>Force deploy (without
cache)
</div>
</li>
</ul>
</div>
@endif
@endif
</div>
</div>

View File

@ -2,14 +2,15 @@
<h2>Logs</h2>
<livewire:project.application.deployment-navbar :activity="$activity" :application="$application" :deployment_uuid="$deployment_uuid" />
@if (data_get($activity, 'properties.status') === 'in_progress')
<div class="pt-2 text-sm">Deployment is
<span class="text-warning">{{ Str::headline(data_get($activity, 'properties.status')) }}</span>. Logs will
be updated
automatically.
<div class="flex items-center gap-1 pt-2 text-sm">Deployment is
<div class="text-warning"> {{ Str::headline(data_get($activity, 'properties.status')) }}.</div>
<x-loading class="loading-ring" />
</div>
<div>Logs will be updated automatically.</div>
@else
<div class="pt-2 text-sm">Deployment is <span
class="text-warning">{{ Str::headline(data_get($activity, 'properties.status')) }}</span>.</div>
class="text-warning">{{ Str::headline(data_get($activity, 'properties.status')) }}</span>.
</div>
@endif
<div
class="scrollbar flex flex-col-reverse w-full overflow-y-auto border border-solid rounded border-coolgray-300 max-h-[32rem] p-4 mt-4 text-xs text-white">

View File

@ -2,14 +2,11 @@
@if ($skip == 0) wire:poll.5000ms='reload_deployments' @endif>
<h2 class="pt-4">Deployments <span class="text-xs">({{ $deployments_count }})</span></h2>
@if (count($deployments) === 0)
<x-forms.button isHighlighted wire:click="load_deployments({{ $default_take }})">Load Deployments
<x-forms.button wire:click="load_deployments({{ $default_take }})">Load Deployments
</x-forms.button>
@endif
<div wire:loading wire:target='load_deployments'>
<x-loading />
</div>
@if ($show_next)
<x-forms.button isHighlighted wire:click="load_deployments({{ $default_take }})">Show More
<x-forms.button wire:click="load_deployments({{ $default_take }})">Show More
</x-forms.button>
@endif
@foreach ($deployments as $deployment)

View File

@ -1,8 +1,8 @@
<div>
<h2>Destination</h2>
<div class="text-sm">The destination server / network where your application will be deployed to.</div>
<div class="py-4">
<div class="py-4 text-sm">
<p>Server: {{ data_get($destination, 'server.name') }}</p>
<p>Destination: {{ $destination->network }}</p>
<p>Destination Network: {{ $destination->network }}</p>
</div>
</div>

View File

@ -1,12 +1,10 @@
<form wire:submit.prevent='submit' class="flex flex-col max-w-fit">
<div class="flex gap-2">
<div class="flex items-end justify-center gap-2">
<x-forms.input placeholder="NODE_ENV" noDirty id="key" label="Name" required />
<x-forms.input placeholder="production" noDirty id="value" label="Value" required />
<x-forms.checkbox noDirty class="flex-col items-center" id="is_build_time" label="Build Variable?" />
</div>
<div class="pt-2">
<x-forms.checkbox noDirty class="flex-col text-center w-96" id="is_build_time" label="Build Variable?" />
<x-forms.button type="submit">
Add
Add New Variable
</x-forms.button>
</div>
</form>

View File

@ -1,17 +1,24 @@
<div class="flex flex-col gap-2">
<div>
<h2>Environment Variables</h2>
<div class="text-sm">Environment (secrets) configuration. You can set variables for your Preview Deployments as
well
here.</div>
<div class="text-sm">Environment (secrets) variables for normal deployments.</div>
</div>
@forelse ($application->environment_variables as $env)
@foreach ($application->environment_variables as $env)
<livewire:project.application.environment-variable.show wire:key="environment-{{ $env->id }}"
:env="$env" />
@empty
<p>There are no environment variables added for this application.</p>
@endforelse
<div class="pt-10">
@endforeach
<div class="pt-2 pb-8">
<livewire:project.application.environment-variable.add />
</div>
<div>
<h3>Preview Deployments</h3>
<div class="text-sm">Environment (secrets) variables for Preview Deployments.</div>
</div>
@foreach ($application->environment_variables_preview as $env)
<livewire:project.application.environment-variable.show wire:key="environment-{{ $env->id }}"
:env="$env" />
@endforeach
<div class="pt-2 pb-8">
<livewire:project.application.environment-variable.add is_preview="true" />
</div>
</div>

View File

@ -1,17 +1,17 @@
<div x-data="{ deleteEnvironment: false }">
<form wire:submit.prevent='submit' class="flex flex-col max-w-fit">
<div class="flex gap-2">
<div class="flex items-end gap-2">
<x-forms.input label="Name" id="env.key" />
<x-forms.input label="Value" id="env.value" />
<x-forms.checkbox disabled class="flex-col items-center" id="env.is_build_time" label="Build Variable?" />
</div>
<div class="pt-2">
<x-forms.button type="submit">
Update
</x-forms.button>
<x-forms.button x-on:click.prevent="deleteEnvironment = true">
Delete
</x-forms.button>
<x-forms.checkbox disabled class="flex-col text-center w-96" id="env.is_build_time" label="Build Variable?" />
<div class="flex gap-2">
<x-forms.button type="submit">
Update
</x-forms.button>
<x-forms.button x-on:click.prevent="deleteEnvironment = true">
Delete
</x-forms.button>
</div>
</div>
</form>
<x-naked-modal show="deleteEnvironment" message="Are you sure you want to delete {{ $env->key }}?" />

View File

@ -18,11 +18,11 @@
<div class="pb-6">
<div class="text-sm">Set Random Domain</div>
@if ($global_wildcard_domain)
<x-forms.button isHighlighted wire:click="generateGlobalRandomDomain">Global Wildcard
<x-forms.button wire:click="generateGlobalRandomDomain">Global Wildcard
</x-forms.button>
@endif
@if ($project_wildcard_domain)
<x-forms.button isHighlighted wire:click="generateProjectRandomDomain">Project Wildcard
<x-forms.button wire:click="generateProjectRandomDomain">Project Wildcard
</x-forms.button>
@endif
</div>

View File

@ -1,40 +1,69 @@
<div>
<livewire:project.application.preview.form :application="$application" />
<h3>Pull Requests on Git</h3>
<div>
<x-forms.button wire:click="load_prs">Load Pull Requests (open)
</x-forms.button>
<div class="flex items-center gap-2">
<h3>Pull Requests on Git</h3>
<x-forms.button wire:click="load_prs">Load Pull Requests (open)
</x-forms.button>
</div>
@isset($rate_limit_remaining)
<div class="pt-1 text-sm">Requests remaning till rate limited by Git: {{ $rate_limit_remaining }}</div>
@endisset
@if (count($pull_requests) > 0)
<div wire:loading.remove wire:target='load_prs' class="flex gap-4 py-8">
@foreach ($pull_requests as $pull_request)
<div class="flex flex-col gap-4 p-4 text-sm bg-coolgray-200 hover:bg-coolgray-300">
<div class="text-base font-bold text-white">PR #{{ data_get($pull_request, 'number') }} |
{{ data_get($pull_request, 'title') }}</div>
<div class="flex items-center justify-start gap-2">
<x-forms.button isHighlighted
wire:click="deploy('{{ data_get($pull_request, 'number') }}', '{{ data_get($pull_request, 'html_url') }}')">
Deploy
</x-forms.button>
<a target="_blank" class="text-xs" href="{{ data_get($pull_request, 'html_url') }}">Open PR
on
Git
<x-external-link />
</a>
</div>
</div>
@endforeach
<div wire:loading.remove wire:target='load_prs' class="flex gap-4 py-4">
<div class="overflow-x-auto table-md">
<table class="table">
<thead>
<tr class="text-warning border-coolgray-200">
<th>PR Number</th>
<th>PR Title</th>
<th>Git</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
@foreach ($pull_requests as $pull_request)
<tr class="border-coolgray-200">
<th>{{ data_get($pull_request, 'number') }}</th>
<td>{{ data_get($pull_request, 'title') }}</td>
<td>
<a target="_blank" class="text-xs"
href="{{ data_get($pull_request, 'html_url') }}">Open PR on
Git
<x-external-link />
</a>
</td>
<td class="flex items-center justify-center gap-2">
<x-forms.button
wire:click="deploy('{{ data_get($pull_request, 'number') }}', '{{ data_get($pull_request, 'html_url') }}')">
Deploy
</x-forms.button>
</td>
</tr>
@endforeach
</tbody>
</table>
</div>
</div>
@endif
</div>
@if ($application->previews->count() > 0)
<h3>Preview Deployments</h3>
<h4 class="pt-4">Preview Deployments</h4>
<div class="flex gap-6 text-sm">
@foreach ($application->previews as $preview)
<div class="flex flex-col p-4 bg-coolgray-200 " x-init="$wire.loadStatus('{{ data_get($preview, 'pull_request_id') }}')">
<div>PR #{{ data_get($preview, 'pull_request_id') }} | {{ data_get($preview, 'status') }}
<div class="flex gap-2">PR #{{ data_get($preview, 'pull_request_id') }} |
@if (data_get($preview, 'status') === 'running')
<div class="flex items-center gap-2">
<div class="badge badge-success badge-xs"></div>
<div class="text-xs font-medium tracking-wide">Running</div>
</div>
@else
<div class="flex items-center gap-2">
<div class="badge badge-error badge-xs"></div>
<div class="text-xs font-medium tracking-wide">Stopped</div>
</div>
@endif
@if (data_get($preview, 'status') !== 'exited')
| <a target="_blank" href="{{ data_get($preview, 'fqdn') }}">Open Preview
<x-external-link />
@ -46,7 +75,7 @@
</a>
</div>
<div class="flex items-center gap-2 pt-6">
<x-forms.button isHighlighted wire:click="deploy({{ data_get($preview, 'pull_request_id') }})">
<x-forms.button wire:click="deploy({{ data_get($preview, 'pull_request_id') }})">
@if (data_get($preview, 'status') === 'exited')
Deploy
@else
@ -58,7 +87,6 @@
Preview
</x-forms.button>
@endif
</div>
</div>
@endforeach

View File

@ -1,12 +1,9 @@
<div x-init="$wire.loadImages">
<div class="flex items-center gap-2">
<h2>Rollback</h2>
<x-forms.button isHighlighted wire:click='loadImages'>Reload Available Images</x-forms.button>
<x-forms.button wire:click='loadImages'>Reload Available Images</x-forms.button>
</div>
<div class="pb-4 text-sm">You can easily rollback to a previously built image quickly.</div>
<div wire:loading wire:target='loadImages'>
<x-loading />
</div>
<div wire:loading.remove wire:target='loadImages'>
<div class="flex flex-wrap">
@forelse ($images as $image)
@ -28,8 +25,7 @@
Rollback
</x-forms.button>
@else
<x-forms.button isHighlighted
wire:click="rollbackImage('{{ data_get($image, 'tag') }}')">
<x-forms.button wire:click="rollbackImage('{{ data_get($image, 'tag') }}')">
Rollback
</x-forms.button>
@endif

View File

@ -1,25 +1,32 @@
<div>
<form wire:submit.prevent='submit' class="flex flex-col">
<form wire:submit.prevent='submit' class="flex flex-col w-96">
<div class="flex items-center gap-2">
<h2>Source</h2>
<x-forms.button type="submit">Save</x-forms.button>
<a target="_blank" class="hover:no-underline" href="{{ $application->gitBranchLocation }}">
<x-forms.button>
<x-git-icon git="{{ $application->source->getMorphClass() }}" />Open Repository on Git
<x-external-link />
</x-forms.button>
</a>
</div>
<div class="text-sm">Code source of your application.</div>
<div class="py-4 ">
<a target="_blank" class="hover:no-underline" href="{{ $application->gitCommits }}">
<x-forms.button>Open Commits on Git
<x-external-link />
</x-forms.button>
</a>
<a target="_blank" class="hover:no-underline" href="{{ $application->gitBranchLocation }}">
<x-forms.button>Open Repository on Git
<x-forms.input placeholder="coollabsio/coolify-example" id="application.git_repository" label="Repository" />
<x-forms.input placeholder="main" id="application.git_branch" label="Branch" />
<div class="flex items-end gap-2 w-96">
<x-forms.input placeholder="HEAD" id="application.git_commit_sha" placeholder="HEAD" label="Commit SHA" />
<a target="_blank" class="flex hover:no-underline" href="{{ $application->gitCommits }}">
<x-forms.button><svg xmlns="http://www.w3.org/2000/svg" class="w-6 h-6" viewBox="0 0 24 24"
stroke-width="1.5" stroke="currentColor" fill="none" stroke-linecap="round"
stroke-linejoin="round">
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
<path d="M12 12m-3 0a3 3 0 1 0 6 0a3 3 0 1 0 -6 0" />
<path d="M12 3l0 6" />
<path d="M12 15l0 6" />
</svg>Open Commits on Git
<x-external-link />
</x-forms.button>
</a>
</div>
<x-forms.input placeholder="coollabsio/coolify-example" id="application.git_repository" label="Repository" />
<x-forms.input placeholder="main" id="application.git_branch" label=" Branch" />
<x-forms.input placeholder="HEAD" id="application.git_commit_sha" placeholder="HEAD" label="Commit SHA" />
</form>
</div>

View File

@ -1,13 +1,15 @@
<div wire:poll.5000ms='applicationStatusChanged'>
@if ($application->status === 'running')
<span class="text-xs text-pink-600" wire:loading.delay.longer>Loading current status...</span>
<x-loading wire:loading.delay.longer />
<div class="flex items-center gap-2 text-sm" wire:loading.remove.delay.longer>
<div class="text-xs font-medium tracking-wide text-white badge border-success">Running</div>
<div class="badge badge-success badge-xs"></div>
<div class="text-xs font-medium tracking-wide">Running</div>
</div>
@else
<span class="text-xs text-pink-600" wire:loading.delay.longer>Loading current status...</span>
<x-loading wire:loading.delay.longer />
<div class="flex items-center gap-2 text-sm" wire:loading.remove.delay.longer>
<div class="text-xs font-medium tracking-wide text-white badge border-error">Stopped</div>
<div class="badge badge-error badge-xs"></div>
<div class="text-xs font-medium tracking-wide">Stopped</div>
</div>
@endif
</div>

View File

@ -1,10 +1,10 @@
<form wire:submit.prevent='submit' class="flex flex-col px-2 pt-10 max-w-fit">
<form wire:submit.prevent='submit' class="flex flex-col w-full px-2">
<div class="flex items-end gap-2">
<x-forms.input placeholder="pv-name" noDirty id="name" label="Name" required />
<x-forms.input placeholder="/root" noDirty id="host_path" label="Source Path" />
<x-forms.input placeholder="/tmp/root" noDirty id="mount_path" label="Destination Path" required />
<x-forms.button type="submit">
Add
Add New Volume
</x-forms.button>
</div>
</form>

View File

@ -1,6 +1,11 @@
<div>
<h2>Storages</h2>
<div class="text-sm">Persistent storage to preserve data between deployments.</div>
<div>
<h2>Storages</h2>
<div class="text-sm">Persistent storage to preserve data between deployments.</div>
<div class="text-sm">Preview Deployments has a <span class='text-helper'>-pr-#PRNumber</span> in their
volume
name, example: <span class='text-helper'>-pr-1</span>.</div>
</div>
<div class="flex flex-col gap-2 py-4">
@forelse ($application->persistentStorages as $storage)
<livewire:project.application.storages.show wire:key="storage-{{ $storage->id }}" :storage="$storage" />

View File

@ -1,10 +1,28 @@
<div>
<h1>Enter a public repository URL</h1>
<form class="flex flex-col gap-2" wire:submit.prevent='submit'>
<x-forms.checkbox instantSave id="is_static" label="Is it a static site?" />
<div class="flex gap-2">
<x-forms.input id="repository_url" label="Repository URL"
helper="<span class='text-helper'>Example</span>https://github.com/coollabsio/coolify-examples => main branch will be selected<br>https://github.com/coollabsio/coolify-examples/tree/nodejs-fastify => nodejs-fastify branch will be selected" />
<div class="flex flex-col gap-2">
<div class="flex flex-col">
<div class="flex items-end gap-2">
<x-forms.input wire:keypress.enter='load_branches' id="repository_url" label="Repository URL"
helper="<span class='text-helper'>Example</span>https://github.com/coollabsio/coolify-examples => main branch will be selected<br>https://github.com/coollabsio/coolify-examples/tree/nodejs-fastify => nodejs-fastify branch will be selected" />
<x-forms.button wire:click.prevent="load_branches">
Check repository
</x-forms.button>
</div>
@if (count($branches) > 0)
<x-forms.select id="selected_branch" label="Branch">
<option value="default" disabled selected>Select a branch</option>
@foreach ($branches as $branch)
<option value="{{ $branch }}">{{ $branch }}</option>
@endforeach
</x-forms.select>
@else
<x-forms.select id="branch" label="Branch" disabled>
<option value="default" selected>Set a repository first</option>
</x-forms.select>
@endif
</div>
@if ($is_static)
<x-forms.input id="publish_directory" label="Publish Directory"
helper="If there is a build process involved (like Svelte, React, Next, etc..), please specify the output directory for the build assets." />
@ -12,9 +30,18 @@
<x-forms.input type="number" id="port" label="Port" :readonly="$is_static"
helper="The port your application listens on." />
@endif
</div>
<x-forms.button type="submit">
Submit
</x-forms.button>
<x-forms.checkbox instantSave id="is_static" label="Is it a static site?" />
@if (count($branches) > 0)
<x-forms.button type="submit">
Save
</x-forms.button>
@else
<x-forms.button disabled type="submit">
Save
</x-forms.button>
@endif
</form>
</div>

View File

@ -38,7 +38,7 @@
</div>
</div>
@if (!$server->settings->is_validated)
<x-forms.button class="mt-4" isHighlighted wire:click.prevent='validateServer'>
<x-forms.button class="mt-4" wire:click.prevent='validateServer'>
Validate Server
</x-forms.button>
@endif

View File

@ -2,7 +2,7 @@
@if ($server->settings->is_validated)
@if ($server->extra_attributes->proxy_status === 'running')
<div class="dropdown dropdown-bottom">
<x-forms.button isHighlighted tabindex="0">
<x-forms.button tabindex="0">
Actions
<x-chevron-down />
</x-forms.button>
@ -33,9 +33,9 @@ class="mt-1 text-xs text-white normal-case rounded min-w-max dropdown-content me
</ul>
</div>
@else
<x-forms.button isHighlighted wire:click='deploy'> <svg xmlns="http://www.w3.org/2000/svg" class="icon"
width="44" height="44" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"
fill="none" stroke-linecap="round" stroke-linejoin="round">
<x-forms.button wire:click='deploy'> <svg xmlns="http://www.w3.org/2000/svg" class="icon" width="44"
height="44" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" fill="none"
stroke-linecap="round" stroke-linejoin="round">
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
<path d="M7 4v16l13 -8z" />
</svg>Start</x-forms.button>

View File

@ -2,12 +2,12 @@
@if ($server->settings->is_validated)
<div wire:poll.5000ms="proxyStatus">
@if ($server->extra_attributes->proxy_status === 'running')
<span class="text-xs text-pink-600" wire:loading.delay.longer>Loading current status...</span>
<x-loading wire:loading.delay.longer />
<div class="flex items-center gap-2 text-sm" wire:loading.remove.delay.longer>
<div class="text-xs font-medium tracking-wide text-white badge border-success">Running</div>
</div>
@else
<span class="text-xs text-pink-600" wire:loading.delay.longer>Loading current status...</span>
<x-loading wire:loading.delay.longer />
<div class="flex items-center gap-2 text-sm" wire:loading.remove.delay.longer>
<div class="text-xs font-medium tracking-wide text-white badge border-error">Stopped</div>
</div>

View File

@ -33,7 +33,7 @@
<div class="pb-4">
<div class="text-sm">You need to register a GitHub App before using this source!</div>
<form>
<x-forms.button isHighlighted x-on:click.prevent="createGithubApp">Register a GitHub
<x-forms.button x-on:click.prevent="createGithubApp">Register a GitHub
Application
</x-forms.button>
</form>

View File

@ -1,5 +1,5 @@
<div>
<x-forms.select wire:model="selectedTeamId" class="w-64 select-xs">
<div class="w-64 -mt-9">
<x-forms.select wire:model="selectedTeamId" class="pr-0 select-xs ">
<option value="default" disabled selected>Switch team</option>
@foreach (auth()->user()->teams as $team)
<option value="{{ $team->id }}">{{ $team->name }}</option>

View File

@ -9,6 +9,9 @@
href="{{ route('project.resources', ['environment_name' => request()->route('environment_name'), 'project_uuid' => request()->route('project_uuid')]) }}">{{ request()->route('environment_name') }}</a>
</li>
<li>{{ data_get($application, 'name') }}</li>
<li>
<livewire:project.application.status :application="$application" />
</li>
</ul>
</div>
<x-applications.navbar :application="$application" />

View File

@ -9,6 +9,9 @@
href="{{ route('project.resources', ['environment_name' => request()->route('environment_name'), 'project_uuid' => request()->route('project_uuid')]) }}">{{ request()->route('environment_name') }}</a>
</li>
<li>{{ data_get($application, 'name') }}</li>
<li>
<livewire:project.application.status :application="$application" />
</li>
</ul>
</div>
<x-applications.navbar :application="$application" />

View File

@ -1,7 +1,7 @@
<x-layout>
<h1>Deployments</h1>
<div class="pb-10 text-sm breadcrumbs">
<ul>`
<ul>
<li><a
href="{{ route('project.show', ['project_uuid' => request()->route('project_uuid')]) }}">{{ $application->environment->project->name }}</a>
</li>
@ -9,6 +9,9 @@
href="{{ route('project.resources', ['environment_name' => request()->route('environment_name'), 'project_uuid' => request()->route('project_uuid')]) }}">{{ request()->route('environment_name') }}</a>
</li>
<li>{{ data_get($application, 'name') }}</li>
<li>
<livewire:project.application.status :application="$application" />
</li>
</ul>
</div>
<x-applications.navbar :application="$application" />

View File

@ -22,7 +22,7 @@
<h2>Invite a new member</h2>
<form class="flex items-center gap-2">
<x-forms.input type="email" name="email" placeholder="Email" />
<x-forms.button isHighlighted>Invite</x-forms.button>
<x-forms.button>Invite</x-forms.button>
</form>
</div>
</x-layout>