feat: services
This commit is contained in:
parent
58522b59b7
commit
0b11093d18
@ -14,9 +14,9 @@ class StartService
|
|||||||
$commands[] = "cd " . $service->workdir();
|
$commands[] = "cd " . $service->workdir();
|
||||||
$commands[] = "echo '####### Starting service {$service->name} on {$service->server->name}.'";
|
$commands[] = "echo '####### Starting service {$service->name} on {$service->server->name}.'";
|
||||||
$commands[] = "echo '####### Pulling images.'";
|
$commands[] = "echo '####### Pulling images.'";
|
||||||
$commands[] = "docker compose pull --quiet";
|
$commands[] = "docker compose pull";
|
||||||
$commands[] = "echo '####### Starting containers.'";
|
$commands[] = "echo '####### Starting containers.'";
|
||||||
$commands[] = "docker compose up -d >/dev/null 2>&1";
|
$commands[] = "docker compose up -d";
|
||||||
$commands[] = "docker network connect $service->uuid coolify-proxy 2>/dev/null || true";
|
$commands[] = "docker network connect $service->uuid coolify-proxy 2>/dev/null || true";
|
||||||
$activity = remote_process($commands, $service->server);
|
$activity = remote_process($commands, $service->server);
|
||||||
return $activity;
|
return $activity;
|
||||||
|
@ -4,6 +4,9 @@ namespace App\Http\Controllers;
|
|||||||
|
|
||||||
use App\Models\Project;
|
use App\Models\Project;
|
||||||
use App\Models\Server;
|
use App\Models\Server;
|
||||||
|
use App\Models\Service;
|
||||||
|
use Illuminate\Support\Facades\Cache;
|
||||||
|
use Illuminate\Support\Str;
|
||||||
|
|
||||||
class ProjectController extends Controller
|
class ProjectController extends Controller
|
||||||
{
|
{
|
||||||
@ -41,9 +44,10 @@ class ProjectController extends Controller
|
|||||||
|
|
||||||
public function new()
|
public function new()
|
||||||
{
|
{
|
||||||
$type = request()->query('type');
|
$services = Cache::get('services', []);
|
||||||
|
$type = Str::of(request()->query('type'));
|
||||||
$destination_uuid = request()->query('destination');
|
$destination_uuid = request()->query('destination');
|
||||||
$server = requesT()->query('server');
|
$server_id = request()->query('server');
|
||||||
|
|
||||||
$project = currentTeam()->load(['projects'])->projects->where('uuid', request()->route('project_uuid'))->first();
|
$project = currentTeam()->load(['projects'])->projects->where('uuid', request()->route('project_uuid'))->first();
|
||||||
if (!$project) {
|
if (!$project) {
|
||||||
@ -61,8 +65,28 @@ class ProjectController extends Controller
|
|||||||
'database_uuid' => $standalone_postgresql->uuid,
|
'database_uuid' => $standalone_postgresql->uuid,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
if ($type->startsWith('one-click-service-')) {
|
||||||
|
$oneClickServiceName = $type->after('one-click-service-')->value();
|
||||||
|
$oneClickService = data_get($services, $oneClickServiceName);
|
||||||
|
if ($oneClickService) {
|
||||||
|
$service = Service::create([
|
||||||
|
'name' => "$oneClickServiceName-" . Str::random(10),
|
||||||
|
'docker_compose_raw' => base64_decode($oneClickService),
|
||||||
|
'environment_id' => $environment->id,
|
||||||
|
'server_id' => (int) $server_id,
|
||||||
|
]);
|
||||||
|
|
||||||
|
$service->parse(isNew: true);
|
||||||
|
|
||||||
|
return redirect()->route('project.service', [
|
||||||
|
'service_uuid' => $service->uuid,
|
||||||
|
'environment_name' => $environment->name,
|
||||||
|
'project_uuid' => $project->uuid,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
return view('project.new', [
|
return view('project.new', [
|
||||||
'type' => $type
|
'type' => $type->value()
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,15 +10,16 @@ use Symfony\Component\Yaml\Yaml;
|
|||||||
|
|
||||||
class DockerCompose extends Component
|
class DockerCompose extends Component
|
||||||
{
|
{
|
||||||
public string $dockercompose = '';
|
public string $dockerComposeRaw = '';
|
||||||
public array $parameters;
|
public array $parameters;
|
||||||
public array $query;
|
public array $query;
|
||||||
public function mount()
|
public function mount()
|
||||||
{
|
{
|
||||||
|
|
||||||
$this->parameters = get_route_parameters();
|
$this->parameters = get_route_parameters();
|
||||||
$this->query = request()->query();
|
$this->query = request()->query();
|
||||||
if (isDev()) {
|
if (isDev()) {
|
||||||
$this->dockercompose = 'services:
|
$this->dockerComposeRaw = 'services:
|
||||||
plausible_events_db:
|
plausible_events_db:
|
||||||
image: clickhouse/clickhouse-server:23.3.7.5-alpine
|
image: clickhouse/clickhouse-server:23.3.7.5-alpine
|
||||||
restart: always
|
restart: always
|
||||||
@ -37,9 +38,9 @@ class DockerCompose extends Component
|
|||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
$this->validate([
|
$this->validate([
|
||||||
'dockercompose' => 'required'
|
'dockerComposeRaw' => 'required'
|
||||||
]);
|
]);
|
||||||
$this->dockercompose = Yaml::dump(Yaml::parse($this->dockercompose), 10, 2, Yaml::DUMP_MULTI_LINE_LITERAL_BLOCK);
|
$this->dockerComposeRaw = Yaml::dump(Yaml::parse($this->dockerComposeRaw), 10, 2, Yaml::DUMP_MULTI_LINE_LITERAL_BLOCK);
|
||||||
$server_id = $this->query['server_id'];
|
$server_id = $this->query['server_id'];
|
||||||
|
|
||||||
$project = Project::where('uuid', $this->parameters['project_uuid'])->first();
|
$project = Project::where('uuid', $this->parameters['project_uuid'])->first();
|
||||||
@ -47,7 +48,7 @@ class DockerCompose extends Component
|
|||||||
|
|
||||||
$service = Service::create([
|
$service = Service::create([
|
||||||
'name' => 'service' . Str::random(10),
|
'name' => 'service' . Str::random(10),
|
||||||
'docker_compose_raw' => $this->dockercompose,
|
'docker_compose_raw' => $this->dockerComposeRaw,
|
||||||
'environment_id' => $environment->id,
|
'environment_id' => $environment->id,
|
||||||
'server_id' => (int) $server_id,
|
'server_id' => (int) $server_id,
|
||||||
]);
|
]);
|
||||||
|
@ -3,12 +3,12 @@
|
|||||||
namespace App\Http\Livewire\Project\New;
|
namespace App\Http\Livewire\Project\New;
|
||||||
|
|
||||||
use App\Models\Server;
|
use App\Models\Server;
|
||||||
use App\Models\StandaloneDocker;
|
|
||||||
use App\Models\SwarmDocker;
|
|
||||||
use Countable;
|
use Countable;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
|
use Illuminate\Support\Facades\Cache;
|
||||||
|
use Illuminate\Support\Facades\Http;
|
||||||
use Livewire\Component;
|
use Livewire\Component;
|
||||||
use Route;
|
use Illuminate\Support\Str;
|
||||||
|
|
||||||
class Select extends Component
|
class Select extends Component
|
||||||
{
|
{
|
||||||
@ -21,6 +21,8 @@ class Select extends Component
|
|||||||
public Collection|array $standaloneDockers = [];
|
public Collection|array $standaloneDockers = [];
|
||||||
public Collection|array $swarmDockers = [];
|
public Collection|array $swarmDockers = [];
|
||||||
public array $parameters;
|
public array $parameters;
|
||||||
|
public Collection|array $services = [];
|
||||||
|
public bool $loadingServices = true;
|
||||||
|
|
||||||
public ?string $existingPostgresqlUrl = null;
|
public ?string $existingPostgresqlUrl = null;
|
||||||
|
|
||||||
@ -44,6 +46,35 @@ class Select extends Component
|
|||||||
// return handleError($e, $this);
|
// return handleError($e, $this);
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
|
public function loadThings()
|
||||||
|
{
|
||||||
|
$this->loadServices();
|
||||||
|
$this->loadServers();
|
||||||
|
}
|
||||||
|
public function loadServices(bool $forceReload = false)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
if ($forceReload) {
|
||||||
|
Cache::forget('services');
|
||||||
|
}
|
||||||
|
$cached = Cache::remember('services', 3600, function () {
|
||||||
|
$services = Http::get(config('constants.services.offical'));
|
||||||
|
if ($services->failed()) {
|
||||||
|
throw new \Exception($services->body());
|
||||||
|
}
|
||||||
|
|
||||||
|
$services = collect($services->json());
|
||||||
|
$this->emit('success', 'Successfully reloaded services from the internet.');
|
||||||
|
return $services;
|
||||||
|
});
|
||||||
|
$this->services = $cached;
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
ray($e);
|
||||||
|
return handleError($e, $this);
|
||||||
|
} finally {
|
||||||
|
$this->loadingServices = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
public function setType(string $type)
|
public function setType(string $type)
|
||||||
{
|
{
|
||||||
$this->type = $type;
|
$this->type = $type;
|
||||||
@ -87,7 +118,7 @@ class Select extends Component
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function load_servers()
|
public function loadServers()
|
||||||
{
|
{
|
||||||
$this->servers = Server::isUsable()->get();
|
$this->servers = Server::isUsable()->get();
|
||||||
}
|
}
|
||||||
|
@ -8,23 +8,39 @@ use Livewire\Component;
|
|||||||
class Application extends Component
|
class Application extends Component
|
||||||
{
|
{
|
||||||
public ServiceApplication $application;
|
public ServiceApplication $application;
|
||||||
|
public $parameters;
|
||||||
public $fileStorages = null;
|
public $fileStorages = null;
|
||||||
protected $listeners = ["refreshFileStorages"];
|
protected $listeners = ["refreshFileStorages"];
|
||||||
protected $rules = [
|
protected $rules = [
|
||||||
'application.human_name' => 'nullable',
|
'application.human_name' => 'nullable',
|
||||||
'application.description' => 'nullable',
|
'application.description' => 'nullable',
|
||||||
'application.fqdn' => 'nullable',
|
'application.fqdn' => 'nullable',
|
||||||
|
'application.ignore_from_status' => 'required|boolean',
|
||||||
];
|
];
|
||||||
public function render()
|
public function render()
|
||||||
{
|
{
|
||||||
return view('livewire.project.service.application');
|
return view('livewire.project.service.application');
|
||||||
}
|
}
|
||||||
|
public function instantSave() {
|
||||||
|
$this->submit();
|
||||||
|
}
|
||||||
public function refreshFileStorages()
|
public function refreshFileStorages()
|
||||||
{
|
{
|
||||||
$this->fileStorages = $this->application->fileStorages()->get();
|
$this->fileStorages = $this->application->fileStorages()->get();
|
||||||
}
|
}
|
||||||
|
public function delete()
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$this->application->delete();
|
||||||
|
$this->emit('success', 'Application deleted successfully.');
|
||||||
|
return redirect()->route('project.service', $this->parameters);
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
return handleError($e, $this);
|
||||||
|
}
|
||||||
|
}
|
||||||
public function mount()
|
public function mount()
|
||||||
{
|
{
|
||||||
|
$this->parameters = get_route_parameters();
|
||||||
$this->refreshFileStorages();
|
$this->refreshFileStorages();
|
||||||
}
|
}
|
||||||
public function submit()
|
public function submit()
|
||||||
|
@ -12,16 +12,22 @@ class Database extends Component
|
|||||||
protected $rules = [
|
protected $rules = [
|
||||||
'database.human_name' => 'nullable',
|
'database.human_name' => 'nullable',
|
||||||
'database.description' => 'nullable',
|
'database.description' => 'nullable',
|
||||||
|
'database.ignore_from_status' => 'required|boolean',
|
||||||
|
|
||||||
];
|
];
|
||||||
public function render()
|
public function render()
|
||||||
{
|
{
|
||||||
return view('livewire.project.service.database');
|
return view('livewire.project.service.database');
|
||||||
}
|
}
|
||||||
|
public function instantSave() {
|
||||||
|
$this->submit();
|
||||||
|
}
|
||||||
public function submit()
|
public function submit()
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
$this->validate();
|
$this->validate();
|
||||||
$this->database->save();
|
$this->database->save();
|
||||||
|
$this->emit('success', 'Database saved successfully.');
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
ray($e);
|
ray($e);
|
||||||
} finally {
|
} finally {
|
||||||
|
@ -3,14 +3,17 @@
|
|||||||
namespace App\Http\Livewire\Project\Service;
|
namespace App\Http\Livewire\Project\Service;
|
||||||
|
|
||||||
use App\Models\Service;
|
use App\Models\Service;
|
||||||
|
use App\Models\ServiceApplication;
|
||||||
use Livewire\Component;
|
use Livewire\Component;
|
||||||
|
|
||||||
class Index extends Component
|
class Index extends Component
|
||||||
{
|
{
|
||||||
public Service $service;
|
public Service $service;
|
||||||
|
public $applications;
|
||||||
|
public $databases;
|
||||||
public array $parameters;
|
public array $parameters;
|
||||||
public array $query;
|
public array $query;
|
||||||
|
|
||||||
protected $rules = [
|
protected $rules = [
|
||||||
'service.docker_compose_raw' => 'required',
|
'service.docker_compose_raw' => 'required',
|
||||||
'service.docker_compose' => 'required',
|
'service.docker_compose' => 'required',
|
||||||
@ -23,6 +26,9 @@ class Index extends Component
|
|||||||
$this->parameters = get_route_parameters();
|
$this->parameters = get_route_parameters();
|
||||||
$this->query = request()->query();
|
$this->query = request()->query();
|
||||||
$this->service = Service::whereUuid($this->parameters['service_uuid'])->firstOrFail();
|
$this->service = Service::whereUuid($this->parameters['service_uuid'])->firstOrFail();
|
||||||
|
$this->applications = $this->service->applications->sort();
|
||||||
|
$this->databases = $this->service->databases->sort();
|
||||||
|
|
||||||
}
|
}
|
||||||
public function render()
|
public function render()
|
||||||
{
|
{
|
||||||
@ -30,12 +36,16 @@ class Index extends Component
|
|||||||
}
|
}
|
||||||
public function save()
|
public function save()
|
||||||
{
|
{
|
||||||
$this->service->save();
|
try {
|
||||||
$this->service->parse();
|
$this->service->save();
|
||||||
$this->service->refresh();
|
$this->service->parse();
|
||||||
$this->emit('refreshEnvs');
|
$this->service->refresh();
|
||||||
$this->emit('success', 'Service saved successfully.');
|
$this->emit('refreshEnvs');
|
||||||
$this->service->saveComposeConfigs();
|
$this->emit('success', 'Service saved successfully.');
|
||||||
|
$this->service->saveComposeConfigs();
|
||||||
|
} catch(\Throwable $e) {
|
||||||
|
return handleError($e, $this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
public function submit()
|
public function submit()
|
||||||
{
|
{
|
||||||
|
@ -76,7 +76,6 @@ class ContainerStatusJob implements ShouldQueue, ShouldBeEncrypted
|
|||||||
$databases = $this->server->databases();
|
$databases = $this->server->databases();
|
||||||
$services = $this->server->services();
|
$services = $this->server->services();
|
||||||
$previews = $this->server->previews();
|
$previews = $this->server->previews();
|
||||||
|
|
||||||
$this->server->proxyType();
|
$this->server->proxyType();
|
||||||
/// Check if proxy is running
|
/// Check if proxy is running
|
||||||
$foundProxyContainer = $containers->filter(function ($value, $key) {
|
$foundProxyContainer = $containers->filter(function ($value, $key) {
|
||||||
@ -149,19 +148,20 @@ class ContainerStatusJob implements ShouldQueue, ShouldBeEncrypted
|
|||||||
}
|
}
|
||||||
$serviceLabelId = data_get($labels, 'coolify.serviceId');
|
$serviceLabelId = data_get($labels, 'coolify.serviceId');
|
||||||
if ($serviceLabelId) {
|
if ($serviceLabelId) {
|
||||||
$coolifyName = data_get($labels, 'coolify.name');
|
$subType = data_get($labels, 'coolify.service.subType');
|
||||||
$serviceName = Str::of($coolifyName)->before('-');
|
$subId = data_get($labels, 'coolify.service.subId');
|
||||||
$serviceUuid = Str::of($coolifyName)->after('-');
|
$service = $services->where('id', $serviceLabelId)->first();
|
||||||
$service = $services->where('uuid', $serviceUuid)->first();
|
if ($subType === 'application') {
|
||||||
|
$service = $service->applications()->where('id', $subId)->first();
|
||||||
|
} else {
|
||||||
|
$service = $service->databases()->where('id', $subId)->first();
|
||||||
|
}
|
||||||
if ($service) {
|
if ($service) {
|
||||||
$foundService = $service->byName($serviceName);
|
$foundServices[] = "$service->id-$service->name";
|
||||||
if ($foundService) {
|
$statusFromDb = $service->status;
|
||||||
$foundServices[] = "$foundService->id-$serviceName";
|
if ($statusFromDb !== $containerStatus) {
|
||||||
$statusFromDb = $foundService->status;
|
// ray('Updating status: ' . $containerStatus);
|
||||||
if ($statusFromDb !== $containerStatus) {
|
$service->update(['status' => $containerStatus]);
|
||||||
// ray('Updating status: ' . $containerStatus);
|
|
||||||
$foundService->update(['status' => $containerStatus]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -79,7 +79,8 @@ class Service extends BaseModel
|
|||||||
{
|
{
|
||||||
return $this->hasMany(EnvironmentVariable::class)->orderBy('key', 'asc');
|
return $this->hasMany(EnvironmentVariable::class)->orderBy('key', 'asc');
|
||||||
}
|
}
|
||||||
public function workdir() {
|
public function workdir()
|
||||||
|
{
|
||||||
return service_configuration_dir() . "/{$this->uuid}";
|
return service_configuration_dir() . "/{$this->uuid}";
|
||||||
}
|
}
|
||||||
public function saveComposeConfigs()
|
public function saveComposeConfigs()
|
||||||
@ -97,6 +98,16 @@ class Service extends BaseModel
|
|||||||
}
|
}
|
||||||
instant_remote_process($commands, $this->server);
|
instant_remote_process($commands, $this->server);
|
||||||
}
|
}
|
||||||
|
private function generateFqdn($serviceVariables, $serviceName)
|
||||||
|
{
|
||||||
|
if (Str::of($serviceVariables)->contains('SERVICE_FQDN') || Str::of($serviceVariables)->contains('SERVICE_URL')) {
|
||||||
|
$defaultUsableFqdn = "http://$serviceName-{$this->uuid}.{$this->server->ip}.sslip.io";
|
||||||
|
if (isDev()) {
|
||||||
|
$defaultUsableFqdn = "http://$serviceName-{$this->uuid}.127.0.0.1.sslip.io";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $defaultUsableFqdn ?? null;
|
||||||
|
}
|
||||||
public function parse(bool $isNew = false): Collection
|
public function parse(bool $isNew = false): Collection
|
||||||
{
|
{
|
||||||
ray('parsing');
|
ray('parsing');
|
||||||
@ -132,20 +143,27 @@ class Service extends BaseModel
|
|||||||
data_set($service, 'is_database', true);
|
data_set($service, 'is_database', true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ($isNew) {
|
if ($isDatabase) {
|
||||||
|
$savedService = ServiceDatabase::where([
|
||||||
|
'name' => $serviceName,
|
||||||
|
'service_id' => $this->id
|
||||||
|
])->first();
|
||||||
|
} else {
|
||||||
|
$savedService = ServiceApplication::where([
|
||||||
|
'name' => $serviceName,
|
||||||
|
'service_id' => $this->id
|
||||||
|
])->first();
|
||||||
|
}
|
||||||
|
if ($isNew || is_null($savedService)) {
|
||||||
if ($isDatabase) {
|
if ($isDatabase) {
|
||||||
$savedService = ServiceDatabase::create([
|
$savedService = ServiceDatabase::create([
|
||||||
'name' => $serviceName,
|
'name' => $serviceName,
|
||||||
'service_id' => $this->id
|
'service_id' => $this->id
|
||||||
]);
|
]);
|
||||||
} else {
|
} else {
|
||||||
$defaultUsableFqdn = "http://$serviceName-{$this->uuid}.{$this->server->ip}.sslip.io";
|
|
||||||
if (isDev()) {
|
|
||||||
$defaultUsableFqdn = "http://$serviceName-{$this->uuid}.127.0.0.1.sslip.io";
|
|
||||||
}
|
|
||||||
$savedService = ServiceApplication::create([
|
$savedService = ServiceApplication::create([
|
||||||
'name' => $serviceName,
|
'name' => $serviceName,
|
||||||
'fqdn' => $defaultUsableFqdn,
|
'fqdn' => $this->generateFqdn($serviceVariables, $serviceName),
|
||||||
'service_id' => $this->id
|
'service_id' => $this->id
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
@ -157,14 +175,9 @@ class Service extends BaseModel
|
|||||||
if (data_get($savedService, 'fqdn')) {
|
if (data_get($savedService, 'fqdn')) {
|
||||||
$defaultUsableFqdn = data_get($savedService, 'fqdn', null);
|
$defaultUsableFqdn = data_get($savedService, 'fqdn', null);
|
||||||
} else {
|
} else {
|
||||||
if (Str::of($serviceVariables)->contains('SERVICE_FQDN') || Str::of($serviceVariables)->contains('SERVICE_URL')) {
|
$defaultUsableFqdn = $this->generateFqdn($serviceVariables, $serviceName);
|
||||||
$defaultUsableFqdn = "http://$serviceName-{$this->uuid}.{$this->server->ip}.sslip.io";
|
|
||||||
if (isDev()) {
|
|
||||||
$defaultUsableFqdn = "http://$serviceName-{$this->uuid}.127.0.0.1.sslip.io";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
$savedService->fqdn = $defaultUsableFqdn ?? null;
|
$savedService->fqdn = $defaultUsableFqdn;
|
||||||
$savedService->save();
|
$savedService->save();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -475,7 +488,7 @@ class Service extends BaseModel
|
|||||||
// Add labels to the service
|
// Add labels to the service
|
||||||
$labels = collect(data_get($service, 'labels', []));
|
$labels = collect(data_get($service, 'labels', []));
|
||||||
$labels = collect([]);
|
$labels = collect([]);
|
||||||
$labels = $labels->merge(defaultLabels($this->id, $container_name, type: 'service'));
|
$labels = $labels->merge(defaultLabels($this->id, $container_name, type: 'service', subType: $isDatabase ? 'database' : 'application', subId: $savedService->id));
|
||||||
if (!$isDatabase) {
|
if (!$isDatabase) {
|
||||||
if ($fqdns) {
|
if ($fqdns) {
|
||||||
$labels = $labels->merge(fqdnLabelsForTraefik($fqdns, $container_name, true));
|
$labels = $labels->merge(fqdnLabelsForTraefik($fqdns, $container_name, true));
|
||||||
|
@ -130,7 +130,7 @@ function get_port_from_dockerfile($dockerfile): int
|
|||||||
return 80;
|
return 80;
|
||||||
}
|
}
|
||||||
|
|
||||||
function defaultLabels($id, $name, $pull_request_id = 0, string $type = 'application')
|
function defaultLabels($id, $name, $pull_request_id = 0, string $type = 'application', $subType = null, $subId = null)
|
||||||
{
|
{
|
||||||
$labels = collect([]);
|
$labels = collect([]);
|
||||||
$labels->push('coolify.managed=true');
|
$labels->push('coolify.managed=true');
|
||||||
@ -141,6 +141,10 @@ function defaultLabels($id, $name, $pull_request_id = 0, string $type = 'applica
|
|||||||
if ($pull_request_id !== 0) {
|
if ($pull_request_id !== 0) {
|
||||||
$labels->push('coolify.pullRequestId=' . $pull_request_id);
|
$labels->push('coolify.pullRequestId=' . $pull_request_id);
|
||||||
}
|
}
|
||||||
|
if ($type === 'service') {
|
||||||
|
$labels->push('coolify.service.subId=' . $subId);
|
||||||
|
$labels->push('coolify.service.subType=' . $subType);
|
||||||
|
}
|
||||||
return $labels;
|
return $labels;
|
||||||
}
|
}
|
||||||
function fqdnLabelsForTraefik(Collection $domains, $container_name, $is_force_https_enabled)
|
function fqdnLabelsForTraefik(Collection $domains, $container_name, $is_force_https_enabled)
|
||||||
|
@ -25,6 +25,9 @@ function serviceStatus(Service $service)
|
|||||||
$applications = $service->applications;
|
$applications = $service->applications;
|
||||||
$databases = $service->databases;
|
$databases = $service->databases;
|
||||||
foreach ($applications as $application) {
|
foreach ($applications as $application) {
|
||||||
|
if ($application->ignore_from_status) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if (Str::of($application->status)->startsWith('running')) {
|
if (Str::of($application->status)->startsWith('running')) {
|
||||||
$foundRunning = true;
|
$foundRunning = true;
|
||||||
} else {
|
} else {
|
||||||
@ -32,6 +35,9 @@ function serviceStatus(Service $service)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
foreach ($databases as $database) {
|
foreach ($databases as $database) {
|
||||||
|
if ($database->ignore_from_status) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if (Str::of($database->status)->startsWith('running')) {
|
if (Str::of($database->status)->startsWith('running')) {
|
||||||
$foundRunning = true;
|
$foundRunning = true;
|
||||||
} else {
|
} else {
|
||||||
|
@ -100,8 +100,7 @@ function handleError(?Throwable $error = null, ?Livewire\Component $livewire = n
|
|||||||
return "Too many requests. Please try again in {$error->secondsUntilAvailable} seconds.";
|
return "Too many requests. Please try again in {$error->secondsUntilAvailable} seconds.";
|
||||||
}
|
}
|
||||||
if (isset($livewire)) {
|
if (isset($livewire)) {
|
||||||
$livewire->emit('error', $message);
|
return $livewire->emit('error', $message);
|
||||||
throw new RuntimeException($message);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new RuntimeException($message);
|
throw new RuntimeException($message);
|
||||||
|
@ -14,6 +14,9 @@ return [
|
|||||||
'expiration' => 10,
|
'expiration' => 10,
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
|
'services' => [
|
||||||
|
'offical' => 'https://cdn.coollabs.io/coolify/service-templates.json',
|
||||||
|
],
|
||||||
'limits' => [
|
'limits' => [
|
||||||
'trial_period'=> 7,
|
'trial_period'=> 7,
|
||||||
'server' => [
|
'server' => [
|
||||||
|
@ -0,0 +1,28 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::table('service_applications', function (Blueprint $table) {
|
||||||
|
$table->boolean('ignore_from_status')->default(false);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::table('service_applications', function (Blueprint $table) {
|
||||||
|
$table->dropColumn('ignore_from_status');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
@ -0,0 +1,29 @@
|
|||||||
|
<?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('service_databases', function (Blueprint $table) {
|
||||||
|
$table->boolean('ignore_from_status')->default(false);
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::table('service_databases', function (Blueprint $table) {
|
||||||
|
$table->dropColumn('ignore_from_status');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
3
examples/service-templates.json
Normal file
3
examples/service-templates.json
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"plausible-analytics": "dmVyc2lvbjogIjMuMyIKc2VydmljZXM6CiAgcGxhdXNpYmxlOgogICAgaW1hZ2U6IHBsYXVzaWJsZS9hbmFseXRpY3M6djIuMAogICAgY29tbWFuZDogc2ggLWMgInNsZWVwIDEwICYmIC9lbnRyeXBvaW50LnNoIGRiIGNyZWF0ZWRiICYmIC9lbnRyeXBvaW50LnNoIGRiIG1pZ3JhdGUgJiYgL2VudHJ5cG9pbnQuc2ggcnVuIgogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gREFUQUJBU0VfVVJMPXBvc3RncmVzOi8vcG9zdGdyZXM6JFNFUlZJQ0VfUEFTU1dPUkRfUE9TVEdSRVNAcGxhdXNpYmxlX2RiL3BsYXVzaWJsZQogICAgICAtIEJBU0VfVVJMPSRTRVJWSUNFX0ZRRE5fUExBVVNJQkxFCiAgICAgIC0gU0VDUkVUX0tFWV9CQVNFPSRTRVJWSUNFX0JBU0U2NF82NF9QTEFVU0lCTEUKICAgIGRlcGVuZHNfb246CiAgICAgIC0gcGxhdXNpYmxlX2RiCiAgICAgIC0gcGxhdXNpYmxlX2V2ZW50c19kYgogICAgICAtIG1haWwKCiAgbWFpbDoKICAgIGltYWdlOiBieXRlbWFyay9zbXRwCgogIHBsYXVzaWJsZV9kYjoKICAgIGltYWdlOiBwb3N0Z3JlczoxNC1hbHBpbmUKICAgIHZvbHVtZXM6CiAgICAgIC0gZGItZGF0YTovdmFyL2xpYi9wb3N0Z3Jlc3FsL2RhdGEKICAgIGVudmlyb25tZW50OgogICAgICAtIFBPU1RHUkVTX0RCPXBsYXVzaWJsZQogICAgICAtIFBPU1RHUkVTX1BBU1NXT1JEPSRTRVJWSUNFX1BBU1NXT1JEX1BPU1RHUkVTCgogIHBsYXVzaWJsZV9ldmVudHNfZGI6CiAgICBpbWFnZTogY2xpY2tob3VzZS9jbGlja2hvdXNlLXNlcnZlcjoyMy4zLjcuNS1hbHBpbmUKICAgIHZvbHVtZXM6CiAgICAgIC0gdHlwZTogdm9sdW1lCiAgICAgICAgc291cmNlOiBldmVudC1kYXRhCiAgICAgICAgdGFyZ2V0OiAvdmFyL2xpYi9jbGlja2hvdXNlCiAgICAgIC0gdHlwZTogYmluZAogICAgICAgIHNvdXJjZTogLi9jbGlja2hvdXNlL2NsaWNraG91c2UtY29uZmlnLnhtbAogICAgICAgIHRhcmdldDogL2V0Yy9jbGlja2hvdXNlLXNlcnZlci9jb25maWcuZC9sb2dnaW5nLnhtbAogICAgICAgIHJlYWRfb25seTogdHJ1ZQogICAgICAgIGNvbnRlbnQ6ID4tCiAgICAgICAgICA8Y2xpY2tob3VzZT48cHJvZmlsZXM+PGRlZmF1bHQ+PGxvZ19xdWVyaWVzPjA8L2xvZ19xdWVyaWVzPjxsb2dfcXVlcnlfdGhyZWFkcz4wPC9sb2dfcXVlcnlfdGhyZWFkcz48L2RlZmF1bHQ+PC9wcm9maWxlcz48L2NsaWNraG91c2U+CiAgICAgIC0gdHlwZTogYmluZAogICAgICAgIHNvdXJjZTogLi9jbGlja2hvdXNlL2NsaWNraG91c2UtdXNlci1jb25maWcueG1sCiAgICAgICAgdGFyZ2V0OiAvZXRjL2NsaWNraG91c2Utc2VydmVyL3VzZXJzLmQvbG9nZ2luZy54bWwKICAgICAgICByZWFkX29ubHk6IHRydWUKICAgICAgICBjb250ZW50OiA+LQogICAgICAgICAgPGNsaWNraG91c2U+PGxvZ2dlcj48bGV2ZWw+d2FybmluZzwvbGV2ZWw+PGNvbnNvbGU+dHJ1ZTwvY29uc29sZT48L2xvZ2dlcj48cXVlcnlfdGhyZWFkX2xvZwogICAgICAgICAgcmVtb3ZlPSJyZW1vdmUiLz48cXVlcnlfbG9nIHJlbW92ZT0icmVtb3ZlIi8+PHRleHRfbG9nCiAgICAgICAgICByZW1vdmU9InJlbW92ZSIvPjx0cmFjZV9sb2cgcmVtb3ZlPSJyZW1vdmUiLz48bWV0cmljX2xvZwogICAgICAgICAgcmVtb3ZlPSJyZW1vdmUiLz48YXN5bmNocm9ub3VzX21ldHJpY19sb2cKICAgICAgICAgIHJlbW92ZT0icmVtb3ZlIi8+PHNlc3Npb25fbG9nIHJlbW92ZT0icmVtb3ZlIi8+PHBhcnRfbG9nCiAgICAgICAgICByZW1vdmU9InJlbW92ZSIvPjwvY2xpY2tob3VzZT4KICAgIHVsaW1pdHM6CiAgICAgIG5vZmlsZToKICAgICAgICBzb2Z0OiAyNjIxNDQKICAgICAgICBoYXJkOiAyNjIxNDQK"
|
||||||
|
}
|
@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<Transition name="fade">
|
<Transition name="fade">
|
||||||
<div>
|
<div >
|
||||||
<div class="flex items-center p-1 px-2 mt-1 overflow-hidden transition-all transform rounded cursor-pointer bg-coolgray-200"
|
<div class="flex items-center p-1 px-2 overflow-hidden transition-all transform rounded cursor-pointer bg-coolgray-200"
|
||||||
@click="showCommandPalette = true">
|
@click="showCommandPalette = true">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" class="w-6 h-6 icon" viewBox="0 0 24 24" stroke-width="2"
|
<svg xmlns="http://www.w3.org/2000/svg" class="w-6 h-6 icon" viewBox="0 0 24 24" stroke-width="2"
|
||||||
stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
|
stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
@auth
|
@auth
|
||||||
<nav class="fixed h-full overflow-hidden overflow-y-auto scrollbar">
|
<nav class="fixed h-full overflow-hidden overflow-y-auto pt-14 scrollbar">
|
||||||
|
<a href="/" class="fixed top-0 z-50 mx-3 mt-3 cursor-pointer bg-coolgray-100"><img class="transition rounded w-11 h-11" src="{{ asset('coolify-transparent.png') }}"></a>
|
||||||
<ul class="flex flex-col h-full gap-4 menu flex-nowrap">
|
<ul class="flex flex-col h-full gap-4 menu flex-nowrap">
|
||||||
<li title="Dashboard">
|
<li title="Dashboard">
|
||||||
<a class="hover:bg-transparent" @if (!request()->is('/')) href="/" @endif>
|
<a class="hover:bg-transparent" @if (!request()->is('/')) href="/" @endif>
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
@auth
|
@auth
|
||||||
<nav class="fixed h-full overflow-hidden overflow-y-auto pt-14 scrollbar">
|
<nav class="fixed h-full overflow-hidden overflow-y-auto pt-28 scrollbar">
|
||||||
|
<a href="/" class="fixed top-0 z-50 mx-3 mt-3 cursor-pointer bg-coolgray-100"><img class="transition rounded w-11 h-11" src="{{ asset('coolify-transparent.png') }}"></a>
|
||||||
<ul class="flex flex-col h-full gap-4 menu flex-nowrap">
|
<ul class="flex flex-col h-full gap-4 menu flex-nowrap">
|
||||||
<li title="Dashboard">
|
<li title="Dashboard">
|
||||||
<a class="hover:bg-transparent" @if (!request()->is('/')) href="/" @endif>
|
<a class="hover:bg-transparent" @if (!request()->is('/')) href="/" @endif>
|
||||||
@ -114,12 +115,13 @@
|
|||||||
</li>
|
</li>
|
||||||
@endif
|
@endif
|
||||||
@if (isSubscriptionActive() || isDev())
|
@if (isSubscriptionActive() || isDev())
|
||||||
<li title="Send feedback or get help" class="fixed top-0 right-0 p-2 px-4 pt-2 mt-auto">
|
<li title="Send feedback or get help" class="fixed top-0 right-0 p-2 px-4 pt-4 mt-auto">
|
||||||
<div class="justify-center text-xs text-warning" wire:click="help" onclick="help.showModal()">
|
<div class="justify-center text-xs text-warning" wire:click="help" onclick="help.showModal()">
|
||||||
<svg class="w-4 h-4" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
<svg class="w-4 h-4" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||||
<path fill="currentColor" d="M22 5.5H9c-1.1 0-2 .9-2 2v9a2 2 0 0 0 2 2h13c1.11 0 2-.89 2-2v-9a2 2 0 0 0-2-2m0 11H9V9.17l6.5 3.33L22 9.17v7.33m-6.5-5.69L9 7.5h13l-6.5 3.31M5 16.5c0 .17.03.33.05.5H1c-.552 0-1-.45-1-1s.448-1 1-1h4v1.5M3 7h2.05c-.02.17-.05.33-.05.5V9H3c-.55 0-1-.45-1-1s.45-1 1-1m-2 5c0-.55.45-1 1-1h3v2H2c-.55 0-1-.45-1-1Z"/>
|
<path fill="currentColor"
|
||||||
|
d="M22 5.5H9c-1.1 0-2 .9-2 2v9a2 2 0 0 0 2 2h13c1.11 0 2-.89 2-2v-9a2 2 0 0 0-2-2m0 11H9V9.17l6.5 3.33L22 9.17v7.33m-6.5-5.69L9 7.5h13l-6.5 3.31M5 16.5c0 .17.03.33.05.5H1c-.552 0-1-.45-1-1s.448-1 1-1h4v1.5M3 7h2.05c-.02.17-.05.33-.05.5V9H3c-.55 0-1-.45-1-1s.45-1 1-1m-2 5c0-.55.45-1 1-1h3v2H2c-.55 0-1-.45-1-1Z" />
|
||||||
</svg>
|
</svg>
|
||||||
Feedback
|
Feedback
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
@endif
|
@endif
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
@section('body')
|
@section('body')
|
||||||
@parent
|
@parent
|
||||||
<x-navbar />
|
<x-navbar />
|
||||||
<div class="fixed top-3 left-4 z-50" id="vue">
|
<div class="fixed z-50 top-[4.5rem] left-4" id="vue">
|
||||||
<magic-bar></magic-bar>
|
<magic-bar></magic-bar>
|
||||||
</div>
|
</div>
|
||||||
<main class="main max-w-screen-2xl">
|
<main class="main max-w-screen-2xl">
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
@section('body')
|
@section('body')
|
||||||
@parent
|
@parent
|
||||||
@if (isSubscriptionOnGracePeriod())
|
@if (isSubscriptionOnGracePeriod())
|
||||||
<div class="fixed top-3 left-4 z-50" id="vue">
|
<div class="fixed top-[4.5rem] left-4 z-50" id="vue">
|
||||||
<magic-bar></magic-bar>
|
<magic-bar></magic-bar>
|
||||||
</div>
|
</div>
|
||||||
<x-navbar />
|
<x-navbar />
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
- SERVICE_BASE64_64_*: Generated 'base64' string with length of '64' (example: SERVICE_BASE64_64_GHOST, to generate 32 bit: SERVICE_BASE64_32_GHOST)<br>
|
- SERVICE_BASE64_64_*: Generated 'base64' string with length of '64' (example: SERVICE_BASE64_64_GHOST, to generate 32 bit: SERVICE_BASE64_32_GHOST)<br>
|
||||||
- SERVICE_USER_*: Generated user (example: SERVICE_USER_MYSQL)<br>
|
- SERVICE_USER_*: Generated user (example: SERVICE_USER_MYSQL)<br>
|
||||||
- SERVICE_PASSWORD_*: Generated password (example: SERVICE_PASSWORD_MYSQL)<br>"
|
- SERVICE_PASSWORD_*: Generated password (example: SERVICE_PASSWORD_MYSQL)<br>"
|
||||||
rows="20" id="dockercompose"
|
rows="20" id="dockerComposeRaw"
|
||||||
placeholder='services:
|
placeholder='services:
|
||||||
ghost:
|
ghost:
|
||||||
documentation: https://ghost.org/docs/config
|
documentation: https://ghost.org/docs/config
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
<div x-data x-init="$wire.load_servers">
|
<div x-data x-init="$wire.loadThings">
|
||||||
<h1>New Resource</h1>
|
<h1>New Resource</h1>
|
||||||
<div class="pb-4 ">Deploy resources, like Applications, Databases, Services...</div>
|
<div class="pb-4 ">Deploy resources, like Applications, Databases, Services...</div>
|
||||||
<div class="flex flex-col gap-2 pt-10">
|
<div class="flex flex-col gap-2 pt-10">
|
||||||
@ -52,18 +52,16 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@if (isDev())
|
<div class="box group" wire:click="setType('docker-compose-empty')">
|
||||||
<div class="box group" wire:click="setType('dockercompose')">
|
<div class="flex flex-col mx-6">
|
||||||
<div class="flex flex-col mx-6">
|
<div class="group-hover:text-white">
|
||||||
<div class="group-hover:text-white">
|
Based on a Docker Compose
|
||||||
Based on a Docker Compose
|
</div>
|
||||||
</div>
|
<div class="text-xs group-hover:text-white">
|
||||||
<div class="text-xs group-hover:text-white">
|
You can deploy complex application easily with Docker Compose.
|
||||||
You can deploy complex application easily with Docker Compose.
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@endif
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<h2 class="py-4">Databases</h2>
|
<h2 class="py-4">Databases</h2>
|
||||||
<div class="grid justify-start grid-cols-1 gap-2 text-left xl:grid-cols-3">
|
<div class="grid justify-start grid-cols-1 gap-2 text-left xl:grid-cols-3">
|
||||||
@ -88,9 +86,28 @@
|
|||||||
</div>
|
</div>
|
||||||
</div> --}}
|
</div> --}}
|
||||||
</div>
|
</div>
|
||||||
<h2 class="py-4">Services</h2>
|
<div class="flex items-center gap-2">
|
||||||
|
<h2 class="py-4">Services</h2>
|
||||||
|
<x-forms.button wire:click='loadServices(true)'>Reload Services from Templates</x-forms.button>
|
||||||
|
</div>
|
||||||
<div class="grid justify-start grid-cols-1 gap-2 text-left xl:grid-cols-3">
|
<div class="grid justify-start grid-cols-1 gap-2 text-left xl:grid-cols-3">
|
||||||
Ghost, Plausible, Wordpress, etc... Coming very very soon...
|
@if ($loadingServices)
|
||||||
|
<span class="loading loading-xs loading-spinner"></span>
|
||||||
|
@else
|
||||||
|
@foreach ($services as $serviceName => $service)
|
||||||
|
<div class="box group" wire:click="setType('one-click-service-{{ $serviceName }}')">
|
||||||
|
<div class="flex flex-col mx-6">
|
||||||
|
<div class="group-hover:text-white">
|
||||||
|
{{ Str::headline($serviceName) }}
|
||||||
|
</div>
|
||||||
|
<div class="text-xs group-hover:text-white">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@endforeach
|
||||||
|
@endif
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
@endif
|
@endif
|
||||||
@if ($current_step === 'servers')
|
@if ($current_step === 'servers')
|
||||||
|
@ -7,13 +7,22 @@
|
|||||||
<h2>{{ Str::headline($application->name) }}</h2>
|
<h2>{{ Str::headline($application->name) }}</h2>
|
||||||
@endif
|
@endif
|
||||||
<x-forms.button type="submit">Save</x-forms.button>
|
<x-forms.button type="submit">Save</x-forms.button>
|
||||||
|
<x-forms.button isError wire:click='delete'>Delete</x-forms.button>
|
||||||
<a target="_blank" href="{{ $application->documentation() }}">Documentation <x-external-link /></a>
|
<a target="_blank" href="{{ $application->documentation() }}">Documentation <x-external-link /></a>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex gap-2">
|
<div class="flex flex-col gap-2">
|
||||||
<x-forms.input label="Name" id="application.human_name" placeholder="Human readable name"></x-forms.input>
|
<div class="flex gap-2">
|
||||||
<x-forms.input label="Description" id="application.description"></x-forms.input>
|
<x-forms.input label="Name" id="application.human_name"
|
||||||
<x-forms.input placeholder="https://app.coolify.io" label="Domains"
|
placeholder="Human readable name"></x-forms.input>
|
||||||
id="application.fqdn"></x-forms.input>
|
<x-forms.input label="Description" id="application.description"></x-forms.input>
|
||||||
|
</div>
|
||||||
|
<x-forms.input placeholder="https://app.coolify.io" label="Domains" id="application.fqdn"></x-forms.input>
|
||||||
|
</div>
|
||||||
|
<h3 class="pt-2">Advanced</h3>
|
||||||
|
<div class="w-64">
|
||||||
|
<x-forms.checkbox instantSave label="Ignore from service status"
|
||||||
|
helper="If you do not need to monitor this resource, enable. Useful if this service is optional."
|
||||||
|
id="application.ignore_from_status"></x-forms.checkbox>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
@if ($fileStorages->count() > 0)
|
@if ($fileStorages->count() > 0)
|
||||||
|
@ -13,6 +13,12 @@
|
|||||||
<x-forms.input label="Name" id="database.human_name" placeholder="Name"></x-forms.input>
|
<x-forms.input label="Name" id="database.human_name" placeholder="Name"></x-forms.input>
|
||||||
<x-forms.input label="Description" id="database.description"></x-forms.input>
|
<x-forms.input label="Description" id="database.description"></x-forms.input>
|
||||||
</div>
|
</div>
|
||||||
|
<h3 class="pt-2">Advanced</h3>
|
||||||
|
<div class="w-64">
|
||||||
|
<x-forms.checkbox instantSave label="Ignore from service status"
|
||||||
|
helper="If you do not need to monitor this resource, enable. Useful if this service is optional."
|
||||||
|
id="database.ignore_from_status"></x-forms.checkbox>
|
||||||
|
</div>
|
||||||
</form>
|
</form>
|
||||||
@if ($database->fileStorages()->get()->count() > 0)
|
@if ($database->fileStorages()->get()->count() > 0)
|
||||||
<h3 class="py-4">Mounted Files (binds)</h3>
|
<h3 class="py-4">Mounted Files (binds)</h3>
|
||||||
|
@ -29,9 +29,17 @@
|
|||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
<h2 class="pb-4"> Service Stack </h2>
|
<h2 class="pb-4"> Service Stack </h2>
|
||||||
<div class="grid grid-cols-1 gap-2">
|
<div class="grid grid-cols-1 gap-2 xl:grid-cols-3 ">
|
||||||
@foreach ($service->applications as $application)
|
@foreach ($applications as $application)
|
||||||
<a class="flex flex-col justify-center box"
|
<a @class([
|
||||||
|
'border-l border-dashed border-red-500' => Str::of(
|
||||||
|
$application->status)->contains(['exited']),
|
||||||
|
'border-l border-dashed border-success' => Str::of(
|
||||||
|
$application->status)->contains(['running']),
|
||||||
|
'border-l border-dashed border-warning' => Str::of(
|
||||||
|
$application->status)->contains(['restarting']),
|
||||||
|
'flex flex-col justify-center box',
|
||||||
|
])
|
||||||
href="{{ route('project.service.show', [...$parameters, 'service_name' => $application->name]) }}">
|
href="{{ route('project.service.show', [...$parameters, 'service_name' => $application->name]) }}">
|
||||||
@if ($application->human_name)
|
@if ($application->human_name)
|
||||||
{{ Str::headline($application->human_name) }}
|
{{ Str::headline($application->human_name) }}
|
||||||
@ -44,10 +52,19 @@
|
|||||||
@if ($application->fqdn)
|
@if ($application->fqdn)
|
||||||
<span class="text-xs">{{ $application->fqdn }}</span>
|
<span class="text-xs">{{ $application->fqdn }}</span>
|
||||||
@endif
|
@endif
|
||||||
|
<div class="text-xs">{{ $application->status }}</div>
|
||||||
</a>
|
</a>
|
||||||
@endforeach
|
@endforeach
|
||||||
@foreach ($service->databases as $database)
|
@foreach ($databases as $database)
|
||||||
<a class="flex flex-col justify-center box"
|
<a @class([
|
||||||
|
'border-l border-dashed border-red-500' => Str::of(
|
||||||
|
$application->status)->contains(['exited']),
|
||||||
|
'border-l border-dashed border-success' => Str::of(
|
||||||
|
$application->status)->contains(['running']),
|
||||||
|
'border-l border-dashed border-warning' => Str::of(
|
||||||
|
$application->status)->contains(['restarting']),
|
||||||
|
'flex flex-col justify-center box',
|
||||||
|
])
|
||||||
href="{{ route('project.service.show', [...$parameters, 'service_name' => $database->name]) }}">
|
href="{{ route('project.service.show', [...$parameters, 'service_name' => $database->name]) }}">
|
||||||
@if ($database->human_name)
|
@if ($database->human_name)
|
||||||
{{ Str::headline($database->human_name) }}
|
{{ Str::headline($database->human_name) }}
|
||||||
@ -57,6 +74,7 @@
|
|||||||
@if ($database->description)
|
@if ($database->description)
|
||||||
<span class="text-xs">{{ $database->description }}</span>
|
<span class="text-xs">{{ $database->description }}</span>
|
||||||
@endif
|
@endif
|
||||||
|
<div class="text-xs">{{ $application->status }}</div>
|
||||||
</a>
|
</a>
|
||||||
@endforeach
|
@endforeach
|
||||||
</div>
|
</div>
|
||||||
@ -90,7 +108,8 @@
|
|||||||
</x-forms.textarea>
|
</x-forms.textarea>
|
||||||
</div>
|
</div>
|
||||||
<div x-cloak x-show="raw === false">
|
<div x-cloak x-show="raw === false">
|
||||||
<x-forms.textarea label="Actual Docker Compose file that will be deployed" readonly rows="20" id="service.docker_compose">
|
<x-forms.textarea label="Actual Docker Compose file that will be deployed" readonly
|
||||||
|
rows="20" id="service.docker_compose">
|
||||||
</x-forms.textarea>
|
</x-forms.textarea>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
<livewire:project.new.github-private-repository-deploy-key :type="$type" />
|
<livewire:project.new.github-private-repository-deploy-key :type="$type" />
|
||||||
@elseif ($type === 'dockerfile')
|
@elseif ($type === 'dockerfile')
|
||||||
<livewire:project.new.simple-dockerfile :type="$type" />
|
<livewire:project.new.simple-dockerfile :type="$type" />
|
||||||
@elseif ($type === 'dockercompose')
|
@elseif ($type === 'docker-compose-empty')
|
||||||
<livewire:project.new.docker-compose :type="$type" />
|
<livewire:project.new.docker-compose :type="$type" />
|
||||||
@else
|
@else
|
||||||
<livewire:project.new.select />
|
<livewire:project.new.select />
|
||||||
|
Loading…
x
Reference in New Issue
Block a user