mirror of
https://github.com/coollabsio/coolify.git
synced 2026-03-11 08:55:47 +00:00
Merge branch 'next' into new-magic
This commit is contained in:
commit
cab04e39e9
81 changed files with 1091 additions and 1437 deletions
|
|
@ -99,8 +99,8 @@ class StartClickhouse
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add custom docker run options
|
// Add custom docker run options
|
||||||
$docker_run_options = convert_docker_run_to_compose($this->database->custom_docker_run_options);
|
$docker_run_options = convertDockerRunToCompose($this->database->custom_docker_run_options);
|
||||||
$docker_compose = generate_custom_docker_run_options_for_databases($docker_run_options, $docker_compose, $container_name, $this->database->destination->network);
|
$docker_compose = generateCustomDockerRunOptionsForDatabases($docker_run_options, $docker_compose, $container_name, $this->database->destination->network);
|
||||||
|
|
||||||
$docker_compose = Yaml::dump($docker_compose, 10);
|
$docker_compose = Yaml::dump($docker_compose, 10);
|
||||||
$docker_compose_base64 = base64_encode($docker_compose);
|
$docker_compose_base64 = base64_encode($docker_compose);
|
||||||
|
|
|
||||||
|
|
@ -49,7 +49,7 @@ class StartDatabase
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if ($database->is_public && $database->public_port) {
|
if ($database->is_public && $database->public_port) {
|
||||||
StartDatabaseProxy::dispatch($database);
|
StartDatabaseProxy::dispatch($database)->onQueue('high');
|
||||||
}
|
}
|
||||||
|
|
||||||
return $activity;
|
return $activity;
|
||||||
|
|
|
||||||
|
|
@ -96,8 +96,8 @@ class StartDragonfly
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add custom docker run options
|
// Add custom docker run options
|
||||||
$docker_run_options = convert_docker_run_to_compose($this->database->custom_docker_run_options);
|
$docker_run_options = convertDockerRunToCompose($this->database->custom_docker_run_options);
|
||||||
$docker_compose = generate_custom_docker_run_options_for_databases($docker_run_options, $docker_compose, $container_name, $this->database->destination->network);
|
$docker_compose = generateCustomDockerRunOptionsForDatabases($docker_run_options, $docker_compose, $container_name, $this->database->destination->network);
|
||||||
|
|
||||||
$docker_compose = Yaml::dump($docker_compose, 10);
|
$docker_compose = Yaml::dump($docker_compose, 10);
|
||||||
$docker_compose_base64 = base64_encode($docker_compose);
|
$docker_compose_base64 = base64_encode($docker_compose);
|
||||||
|
|
|
||||||
|
|
@ -107,8 +107,8 @@ class StartKeydb
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add custom docker run options
|
// Add custom docker run options
|
||||||
$docker_run_options = convert_docker_run_to_compose($this->database->custom_docker_run_options);
|
$docker_run_options = convertDockerRunToCompose($this->database->custom_docker_run_options);
|
||||||
$docker_compose = generate_custom_docker_run_options_for_databases($docker_run_options, $docker_compose, $container_name, $this->database->destination->network);
|
$docker_compose = generateCustomDockerRunOptionsForDatabases($docker_run_options, $docker_compose, $container_name, $this->database->destination->network);
|
||||||
$docker_compose = Yaml::dump($docker_compose, 10);
|
$docker_compose = Yaml::dump($docker_compose, 10);
|
||||||
$docker_compose_base64 = base64_encode($docker_compose);
|
$docker_compose_base64 = base64_encode($docker_compose);
|
||||||
$this->commands[] = "echo '{$docker_compose_base64}' | base64 -d | tee $this->configuration_dir/docker-compose.yml > /dev/null";
|
$this->commands[] = "echo '{$docker_compose_base64}' | base64 -d | tee $this->configuration_dir/docker-compose.yml > /dev/null";
|
||||||
|
|
|
||||||
|
|
@ -101,8 +101,8 @@ class StartMariadb
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add custom docker run options
|
// Add custom docker run options
|
||||||
$docker_run_options = convert_docker_run_to_compose($this->database->custom_docker_run_options);
|
$docker_run_options = convertDockerRunToCompose($this->database->custom_docker_run_options);
|
||||||
$docker_compose = generate_custom_docker_run_options_for_databases($docker_run_options, $docker_compose, $container_name, $this->database->destination->network);
|
$docker_compose = generateCustomDockerRunOptionsForDatabases($docker_run_options, $docker_compose, $container_name, $this->database->destination->network);
|
||||||
|
|
||||||
$docker_compose = Yaml::dump($docker_compose, 10);
|
$docker_compose = Yaml::dump($docker_compose, 10);
|
||||||
$docker_compose_base64 = base64_encode($docker_compose);
|
$docker_compose_base64 = base64_encode($docker_compose);
|
||||||
|
|
|
||||||
|
|
@ -117,8 +117,8 @@ class StartMongodb
|
||||||
];
|
];
|
||||||
|
|
||||||
// Add custom docker run options
|
// Add custom docker run options
|
||||||
$docker_run_options = convert_docker_run_to_compose($this->database->custom_docker_run_options);
|
$docker_run_options = convertDockerRunToCompose($this->database->custom_docker_run_options);
|
||||||
$docker_compose = generate_custom_docker_run_options_for_databases($docker_run_options, $docker_compose, $container_name, $this->database->destination->network);
|
$docker_compose = generateCustomDockerRunOptionsForDatabases($docker_run_options, $docker_compose, $container_name, $this->database->destination->network);
|
||||||
|
|
||||||
$docker_compose = Yaml::dump($docker_compose, 10);
|
$docker_compose = Yaml::dump($docker_compose, 10);
|
||||||
$docker_compose_base64 = base64_encode($docker_compose);
|
$docker_compose_base64 = base64_encode($docker_compose);
|
||||||
|
|
|
||||||
|
|
@ -101,8 +101,8 @@ class StartMysql
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add custom docker run options
|
// Add custom docker run options
|
||||||
$docker_run_options = convert_docker_run_to_compose($this->database->custom_docker_run_options);
|
$docker_run_options = convertDockerRunToCompose($this->database->custom_docker_run_options);
|
||||||
$docker_compose = generate_custom_docker_run_options_for_databases($docker_run_options, $docker_compose, $container_name, $this->database->destination->network);
|
$docker_compose = generateCustomDockerRunOptionsForDatabases($docker_run_options, $docker_compose, $container_name, $this->database->destination->network);
|
||||||
|
|
||||||
$docker_compose = Yaml::dump($docker_compose, 10);
|
$docker_compose = Yaml::dump($docker_compose, 10);
|
||||||
$docker_compose_base64 = base64_encode($docker_compose);
|
$docker_compose_base64 = base64_encode($docker_compose);
|
||||||
|
|
|
||||||
|
|
@ -122,8 +122,8 @@ class StartPostgresql
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
// Add custom docker run options
|
// Add custom docker run options
|
||||||
$docker_run_options = convert_docker_run_to_compose($this->database->custom_docker_run_options);
|
$docker_run_options = convertDockerRunToCompose($this->database->custom_docker_run_options);
|
||||||
$docker_compose = generate_custom_docker_run_options_for_databases($docker_run_options, $docker_compose, $container_name, $this->database->destination->network);
|
$docker_compose = generateCustomDockerRunOptionsForDatabases($docker_run_options, $docker_compose, $container_name, $this->database->destination->network);
|
||||||
|
|
||||||
$docker_compose = Yaml::dump($docker_compose, 10);
|
$docker_compose = Yaml::dump($docker_compose, 10);
|
||||||
$docker_compose_base64 = base64_encode($docker_compose);
|
$docker_compose_base64 = base64_encode($docker_compose);
|
||||||
|
|
|
||||||
|
|
@ -110,8 +110,8 @@ class StartRedis
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add custom docker run options
|
// Add custom docker run options
|
||||||
$docker_run_options = convert_docker_run_to_compose($this->database->custom_docker_run_options);
|
$docker_run_options = convertDockerRunToCompose($this->database->custom_docker_run_options);
|
||||||
$docker_compose = generate_custom_docker_run_options_for_databases($docker_run_options, $docker_compose, $container_name, $this->database->destination->network);
|
$docker_compose = generateCustomDockerRunOptionsForDatabases($docker_run_options, $docker_compose, $container_name, $this->database->destination->network);
|
||||||
|
|
||||||
$docker_compose = Yaml::dump($docker_compose, 10);
|
$docker_compose = Yaml::dump($docker_compose, 10);
|
||||||
$docker_compose_base64 = base64_encode($docker_compose);
|
$docker_compose_base64 = base64_encode($docker_compose);
|
||||||
|
|
|
||||||
|
|
@ -12,11 +12,11 @@ class InstallDocker
|
||||||
|
|
||||||
public function handle(Server $server)
|
public function handle(Server $server)
|
||||||
{
|
{
|
||||||
|
$dockerVersion = config('constants.docker_install_version');
|
||||||
$supported_os_type = $server->validateOS();
|
$supported_os_type = $server->validateOS();
|
||||||
if (! $supported_os_type) {
|
if (! $supported_os_type) {
|
||||||
throw new \Exception('Server OS type is not supported for automated installation. Please install Docker manually before continuing: <a target="_blank" class="underline" href="https://coolify.io/docs/installation#manually">documentation</a>.');
|
throw new \Exception('Server OS type is not supported for automated installation. Please install Docker manually before continuing: <a target="_blank" class="underline" href="https://coolify.io/docs/installation#manually">documentation</a>.');
|
||||||
}
|
}
|
||||||
$dockerVersion = '26.0';
|
|
||||||
$config = base64_encode('{
|
$config = base64_encode('{
|
||||||
"log-driver": "json-file",
|
"log-driver": "json-file",
|
||||||
"log-opts": {
|
"log-opts": {
|
||||||
|
|
|
||||||
|
|
@ -130,10 +130,10 @@ class ServerCheck
|
||||||
if ($foundLogDrainContainer) {
|
if ($foundLogDrainContainer) {
|
||||||
$status = data_get($foundLogDrainContainer, 'State.Status');
|
$status = data_get($foundLogDrainContainer, 'State.Status');
|
||||||
if ($status !== 'running') {
|
if ($status !== 'running') {
|
||||||
StartLogDrain::dispatch($this->server);
|
StartLogDrain::dispatch($this->server)->onQueue('high');
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
StartLogDrain::dispatch($this->server);
|
StartLogDrain::dispatch($this->server)->onQueue('high');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,7 @@ class Init extends Command
|
||||||
}
|
}
|
||||||
|
|
||||||
// Backward compatibility
|
// Backward compatibility
|
||||||
$this->disable_metrics();
|
// $this->disable_metrics();
|
||||||
$this->replace_slash_in_environment_name();
|
$this->replace_slash_in_environment_name();
|
||||||
$this->restore_coolify_db_backup();
|
$this->restore_coolify_db_backup();
|
||||||
$this->update_user_emails();
|
$this->update_user_emails();
|
||||||
|
|
@ -80,19 +80,19 @@ class Init extends Command
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private function disable_metrics()
|
// private function disable_metrics()
|
||||||
{
|
// {
|
||||||
if (version_compare('4.0.0-beta.312', config('version'), '<=')) {
|
// if (version_compare('4.0.0-beta.312', config('version'), '<=')) {
|
||||||
foreach ($this->servers as $server) {
|
// foreach ($this->servers as $server) {
|
||||||
if ($server->settings->is_metrics_enabled === true) {
|
// if ($server->settings->is_metrics_enabled === true) {
|
||||||
$server->settings->update(['is_metrics_enabled' => false]);
|
// $server->settings->update(['is_metrics_enabled' => false]);
|
||||||
}
|
// }
|
||||||
if ($server->isFunctional()) {
|
// if ($server->isFunctional()) {
|
||||||
StopSentinel::dispatch($server);
|
// StopSentinel::dispatch($server)->onQueue('high');
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
private function update_user_emails()
|
private function update_user_emails()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -96,7 +96,7 @@ class ServicesDelete extends Command
|
||||||
if (! $confirmed) {
|
if (! $confirmed) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
DeleteResourceJob::dispatch($toDelete);
|
DeleteResourceJob::dispatch($toDelete)->onQueue('high');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -122,7 +122,7 @@ class ServicesDelete extends Command
|
||||||
if (! $confirmed) {
|
if (! $confirmed) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
DeleteResourceJob::dispatch($toDelete);
|
DeleteResourceJob::dispatch($toDelete)->onQueue('high');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -148,7 +148,7 @@ class ServicesDelete extends Command
|
||||||
if (! $confirmed) {
|
if (! $confirmed) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
DeleteResourceJob::dispatch($toDelete);
|
DeleteResourceJob::dispatch($toDelete)->onQueue('high');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -179,14 +179,11 @@ class Kernel extends ConsoleKernel
|
||||||
|
|
||||||
private function checkScheduledTasks($schedule): void
|
private function checkScheduledTasks($schedule): void
|
||||||
{
|
{
|
||||||
$scheduled_tasks = ScheduledTask::all();
|
$scheduled_tasks = ScheduledTask::where('enabled', true)->get();
|
||||||
if ($scheduled_tasks->isEmpty()) {
|
if ($scheduled_tasks->isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
foreach ($scheduled_tasks as $scheduled_task) {
|
foreach ($scheduled_tasks as $scheduled_task) {
|
||||||
if ($scheduled_task->enabled === false) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
$service = $scheduled_task->service;
|
$service = $scheduled_task->service;
|
||||||
$application = $scheduled_task->application;
|
$application = $scheduled_task->application;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1203,7 +1203,7 @@ class ApplicationsController extends Controller
|
||||||
$service->name = "service-$service->uuid";
|
$service->name = "service-$service->uuid";
|
||||||
$service->parse(isNew: true);
|
$service->parse(isNew: true);
|
||||||
if ($instantDeploy) {
|
if ($instantDeploy) {
|
||||||
StartService::dispatch($service);
|
StartService::dispatch($service)->onQueue('high');
|
||||||
}
|
}
|
||||||
|
|
||||||
return response()->json(serializeApiResponse([
|
return response()->json(serializeApiResponse([
|
||||||
|
|
@ -1358,7 +1358,7 @@ class ApplicationsController extends Controller
|
||||||
deleteVolumes: $request->query->get('delete_volumes', true),
|
deleteVolumes: $request->query->get('delete_volumes', true),
|
||||||
dockerCleanup: $request->query->get('docker_cleanup', true),
|
dockerCleanup: $request->query->get('docker_cleanup', true),
|
||||||
deleteConnectedNetworks: $request->query->get('delete_connected_networks', true)
|
deleteConnectedNetworks: $request->query->get('delete_connected_networks', true)
|
||||||
);
|
)->onQueue('high');
|
||||||
|
|
||||||
return response()->json([
|
return response()->json([
|
||||||
'message' => 'Application deletion request queued.',
|
'message' => 'Application deletion request queued.',
|
||||||
|
|
@ -2482,7 +2482,7 @@ class ApplicationsController extends Controller
|
||||||
if (! $application) {
|
if (! $application) {
|
||||||
return response()->json(['message' => 'Application not found.'], 404);
|
return response()->json(['message' => 'Application not found.'], 404);
|
||||||
}
|
}
|
||||||
StopApplication::dispatch($application);
|
StopApplication::dispatch($application)->onQueue('high');
|
||||||
|
|
||||||
return response()->json(
|
return response()->json(
|
||||||
[
|
[
|
||||||
|
|
|
||||||
|
|
@ -497,9 +497,9 @@ class DatabasesController extends Controller
|
||||||
$database->update($request->all());
|
$database->update($request->all());
|
||||||
|
|
||||||
if ($whatToDoWithDatabaseProxy === 'start') {
|
if ($whatToDoWithDatabaseProxy === 'start') {
|
||||||
StartDatabaseProxy::dispatch($database);
|
StartDatabaseProxy::dispatch($database)->onQueue('high');
|
||||||
} elseif ($whatToDoWithDatabaseProxy === 'stop') {
|
} elseif ($whatToDoWithDatabaseProxy === 'stop') {
|
||||||
StopDatabaseProxy::dispatch($database);
|
StopDatabaseProxy::dispatch($database)->onQueue('high');
|
||||||
}
|
}
|
||||||
|
|
||||||
return response()->json([
|
return response()->json([
|
||||||
|
|
@ -1151,7 +1151,7 @@ class DatabasesController extends Controller
|
||||||
}
|
}
|
||||||
$database = create_standalone_postgresql($environment->id, $destination->uuid, $request->all());
|
$database = create_standalone_postgresql($environment->id, $destination->uuid, $request->all());
|
||||||
if ($instantDeploy) {
|
if ($instantDeploy) {
|
||||||
StartDatabase::dispatch($database);
|
StartDatabase::dispatch($database)->onQueue('high');
|
||||||
}
|
}
|
||||||
$database->refresh();
|
$database->refresh();
|
||||||
$payload = [
|
$payload = [
|
||||||
|
|
@ -1206,7 +1206,7 @@ class DatabasesController extends Controller
|
||||||
}
|
}
|
||||||
$database = create_standalone_mariadb($environment->id, $destination->uuid, $request->all());
|
$database = create_standalone_mariadb($environment->id, $destination->uuid, $request->all());
|
||||||
if ($instantDeploy) {
|
if ($instantDeploy) {
|
||||||
StartDatabase::dispatch($database);
|
StartDatabase::dispatch($database)->onQueue('high');
|
||||||
}
|
}
|
||||||
|
|
||||||
$database->refresh();
|
$database->refresh();
|
||||||
|
|
@ -1264,7 +1264,7 @@ class DatabasesController extends Controller
|
||||||
}
|
}
|
||||||
$database = create_standalone_mysql($environment->id, $destination->uuid, $request->all());
|
$database = create_standalone_mysql($environment->id, $destination->uuid, $request->all());
|
||||||
if ($instantDeploy) {
|
if ($instantDeploy) {
|
||||||
StartDatabase::dispatch($database);
|
StartDatabase::dispatch($database)->onQueue('high');
|
||||||
}
|
}
|
||||||
|
|
||||||
$database->refresh();
|
$database->refresh();
|
||||||
|
|
@ -1320,7 +1320,7 @@ class DatabasesController extends Controller
|
||||||
}
|
}
|
||||||
$database = create_standalone_redis($environment->id, $destination->uuid, $request->all());
|
$database = create_standalone_redis($environment->id, $destination->uuid, $request->all());
|
||||||
if ($instantDeploy) {
|
if ($instantDeploy) {
|
||||||
StartDatabase::dispatch($database);
|
StartDatabase::dispatch($database)->onQueue('high');
|
||||||
}
|
}
|
||||||
|
|
||||||
$database->refresh();
|
$database->refresh();
|
||||||
|
|
@ -1357,7 +1357,7 @@ class DatabasesController extends Controller
|
||||||
removeUnnecessaryFieldsFromRequest($request);
|
removeUnnecessaryFieldsFromRequest($request);
|
||||||
$database = create_standalone_dragonfly($environment->id, $destination->uuid, $request->all());
|
$database = create_standalone_dragonfly($environment->id, $destination->uuid, $request->all());
|
||||||
if ($instantDeploy) {
|
if ($instantDeploy) {
|
||||||
StartDatabase::dispatch($database);
|
StartDatabase::dispatch($database)->onQueue('high');
|
||||||
}
|
}
|
||||||
|
|
||||||
return response()->json(serializeApiResponse([
|
return response()->json(serializeApiResponse([
|
||||||
|
|
@ -1406,7 +1406,7 @@ class DatabasesController extends Controller
|
||||||
}
|
}
|
||||||
$database = create_standalone_keydb($environment->id, $destination->uuid, $request->all());
|
$database = create_standalone_keydb($environment->id, $destination->uuid, $request->all());
|
||||||
if ($instantDeploy) {
|
if ($instantDeploy) {
|
||||||
StartDatabase::dispatch($database);
|
StartDatabase::dispatch($database)->onQueue('high');
|
||||||
}
|
}
|
||||||
|
|
||||||
$database->refresh();
|
$database->refresh();
|
||||||
|
|
@ -1442,7 +1442,7 @@ class DatabasesController extends Controller
|
||||||
removeUnnecessaryFieldsFromRequest($request);
|
removeUnnecessaryFieldsFromRequest($request);
|
||||||
$database = create_standalone_clickhouse($environment->id, $destination->uuid, $request->all());
|
$database = create_standalone_clickhouse($environment->id, $destination->uuid, $request->all());
|
||||||
if ($instantDeploy) {
|
if ($instantDeploy) {
|
||||||
StartDatabase::dispatch($database);
|
StartDatabase::dispatch($database)->onQueue('high');
|
||||||
}
|
}
|
||||||
|
|
||||||
$database->refresh();
|
$database->refresh();
|
||||||
|
|
@ -1500,7 +1500,7 @@ class DatabasesController extends Controller
|
||||||
}
|
}
|
||||||
$database = create_standalone_mongodb($environment->id, $destination->uuid, $request->all());
|
$database = create_standalone_mongodb($environment->id, $destination->uuid, $request->all());
|
||||||
if ($instantDeploy) {
|
if ($instantDeploy) {
|
||||||
StartDatabase::dispatch($database);
|
StartDatabase::dispatch($database)->onQueue('high');
|
||||||
}
|
}
|
||||||
|
|
||||||
$database->refresh();
|
$database->refresh();
|
||||||
|
|
@ -1593,7 +1593,7 @@ class DatabasesController extends Controller
|
||||||
deleteVolumes: $request->query->get('delete_volumes', true),
|
deleteVolumes: $request->query->get('delete_volumes', true),
|
||||||
dockerCleanup: $request->query->get('docker_cleanup', true),
|
dockerCleanup: $request->query->get('docker_cleanup', true),
|
||||||
deleteConnectedNetworks: $request->query->get('delete_connected_networks', true)
|
deleteConnectedNetworks: $request->query->get('delete_connected_networks', true)
|
||||||
);
|
)->onQueue('high');
|
||||||
|
|
||||||
return response()->json([
|
return response()->json([
|
||||||
'message' => 'Database deletion request queued.',
|
'message' => 'Database deletion request queued.',
|
||||||
|
|
@ -1666,7 +1666,7 @@ class DatabasesController extends Controller
|
||||||
if (str($database->status)->contains('running')) {
|
if (str($database->status)->contains('running')) {
|
||||||
return response()->json(['message' => 'Database is already running.'], 400);
|
return response()->json(['message' => 'Database is already running.'], 400);
|
||||||
}
|
}
|
||||||
StartDatabase::dispatch($database);
|
StartDatabase::dispatch($database)->onQueue('high');
|
||||||
|
|
||||||
return response()->json(
|
return response()->json(
|
||||||
[
|
[
|
||||||
|
|
@ -1742,7 +1742,7 @@ class DatabasesController extends Controller
|
||||||
if (str($database->status)->contains('stopped') || str($database->status)->contains('exited')) {
|
if (str($database->status)->contains('stopped') || str($database->status)->contains('exited')) {
|
||||||
return response()->json(['message' => 'Database is already stopped.'], 400);
|
return response()->json(['message' => 'Database is already stopped.'], 400);
|
||||||
}
|
}
|
||||||
StopDatabase::dispatch($database);
|
StopDatabase::dispatch($database)->onQueue('high');
|
||||||
|
|
||||||
return response()->json(
|
return response()->json(
|
||||||
[
|
[
|
||||||
|
|
@ -1815,7 +1815,7 @@ class DatabasesController extends Controller
|
||||||
if (! $database) {
|
if (! $database) {
|
||||||
return response()->json(['message' => 'Database not found.'], 404);
|
return response()->json(['message' => 'Database not found.'], 404);
|
||||||
}
|
}
|
||||||
RestartDatabase::dispatch($database);
|
RestartDatabase::dispatch($database)->onQueue('high');
|
||||||
|
|
||||||
return response()->json(
|
return response()->json(
|
||||||
[
|
[
|
||||||
|
|
|
||||||
|
|
@ -307,7 +307,7 @@ class DeployController extends Controller
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
// Database resource
|
// Database resource
|
||||||
StartDatabase::dispatch($resource);
|
StartDatabase::dispatch($resource)->onQueue('high');
|
||||||
$resource->update([
|
$resource->update([
|
||||||
'started_at' => now(),
|
'started_at' => now(),
|
||||||
]);
|
]);
|
||||||
|
|
|
||||||
|
|
@ -538,7 +538,7 @@ class ServersController extends Controller
|
||||||
'is_build_server' => $request->is_build_server,
|
'is_build_server' => $request->is_build_server,
|
||||||
]);
|
]);
|
||||||
if ($request->instant_validate) {
|
if ($request->instant_validate) {
|
||||||
ValidateServer::dispatch($server);
|
ValidateServer::dispatch($server)->onQueue('high');
|
||||||
}
|
}
|
||||||
|
|
||||||
return response()->json([
|
return response()->json([
|
||||||
|
|
@ -651,7 +651,7 @@ class ServersController extends Controller
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
if ($request->instant_validate) {
|
if ($request->instant_validate) {
|
||||||
ValidateServer::dispatch($server);
|
ValidateServer::dispatch($server)->onQueue('high');
|
||||||
}
|
}
|
||||||
|
|
||||||
return response()->json(serializeApiResponse($server))->setStatusCode(201);
|
return response()->json(serializeApiResponse($server))->setStatusCode(201);
|
||||||
|
|
@ -787,7 +787,7 @@ class ServersController extends Controller
|
||||||
if (! $server) {
|
if (! $server) {
|
||||||
return response()->json(['message' => 'Server not found.'], 404);
|
return response()->json(['message' => 'Server not found.'], 404);
|
||||||
}
|
}
|
||||||
ValidateServer::dispatch($server);
|
ValidateServer::dispatch($server)->onQueue('high');
|
||||||
|
|
||||||
return response()->json(['message' => 'Validation started.']);
|
return response()->json(['message' => 'Validation started.']);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -342,7 +342,7 @@ class ServicesController extends Controller
|
||||||
}
|
}
|
||||||
$service->parse(isNew: true);
|
$service->parse(isNew: true);
|
||||||
if ($instantDeploy) {
|
if ($instantDeploy) {
|
||||||
StartService::dispatch($service);
|
StartService::dispatch($service)->onQueue('high');
|
||||||
}
|
}
|
||||||
$domains = $service->applications()->get()->pluck('fqdn')->sort();
|
$domains = $service->applications()->get()->pluck('fqdn')->sort();
|
||||||
$domains = $domains->map(function ($domain) {
|
$domains = $domains->map(function ($domain) {
|
||||||
|
|
@ -487,7 +487,7 @@ class ServicesController extends Controller
|
||||||
deleteVolumes: $request->query->get('delete_volumes', true),
|
deleteVolumes: $request->query->get('delete_volumes', true),
|
||||||
dockerCleanup: $request->query->get('docker_cleanup', true),
|
dockerCleanup: $request->query->get('docker_cleanup', true),
|
||||||
deleteConnectedNetworks: $request->query->get('delete_connected_networks', true)
|
deleteConnectedNetworks: $request->query->get('delete_connected_networks', true)
|
||||||
);
|
)->onQueue('high');
|
||||||
|
|
||||||
return response()->json([
|
return response()->json([
|
||||||
'message' => 'Service deletion request queued.',
|
'message' => 'Service deletion request queued.',
|
||||||
|
|
@ -1076,7 +1076,7 @@ class ServicesController extends Controller
|
||||||
if (str($service->status())->contains('running')) {
|
if (str($service->status())->contains('running')) {
|
||||||
return response()->json(['message' => 'Service is already running.'], 400);
|
return response()->json(['message' => 'Service is already running.'], 400);
|
||||||
}
|
}
|
||||||
StartService::dispatch($service);
|
StartService::dispatch($service)->onQueue('high');
|
||||||
|
|
||||||
return response()->json(
|
return response()->json(
|
||||||
[
|
[
|
||||||
|
|
@ -1154,7 +1154,7 @@ class ServicesController extends Controller
|
||||||
if (str($service->status())->contains('stopped') || str($service->status())->contains('exited')) {
|
if (str($service->status())->contains('stopped') || str($service->status())->contains('exited')) {
|
||||||
return response()->json(['message' => 'Service is already stopped.'], 400);
|
return response()->json(['message' => 'Service is already stopped.'], 400);
|
||||||
}
|
}
|
||||||
StopService::dispatch($service);
|
StopService::dispatch($service)->onQueue('high');
|
||||||
|
|
||||||
return response()->json(
|
return response()->json(
|
||||||
[
|
[
|
||||||
|
|
@ -1229,7 +1229,7 @@ class ServicesController extends Controller
|
||||||
if (! $service) {
|
if (! $service) {
|
||||||
return response()->json(['message' => 'Service not found.'], 404);
|
return response()->json(['message' => 'Service not found.'], 404);
|
||||||
}
|
}
|
||||||
RestartService::dispatch($service);
|
RestartService::dispatch($service)->onQueue('high');
|
||||||
|
|
||||||
return response()->json(
|
return response()->json(
|
||||||
[
|
[
|
||||||
|
|
|
||||||
|
|
@ -1836,7 +1836,7 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->pull_request_id === 0) {
|
if ($this->pull_request_id === 0) {
|
||||||
$custom_compose = convert_docker_run_to_compose($this->application->custom_docker_run_options);
|
$custom_compose = convertDockerRunToCompose($this->application->custom_docker_run_options);
|
||||||
if ((bool) $this->application->settings->is_consistent_container_name_enabled) {
|
if ((bool) $this->application->settings->is_consistent_container_name_enabled) {
|
||||||
if (! $this->application->settings->custom_internal_name) {
|
if (! $this->application->settings->custom_internal_name) {
|
||||||
$docker_compose['services'][$this->application->uuid] = $docker_compose['services'][$this->container_name];
|
$docker_compose['services'][$this->application->uuid] = $docker_compose['services'][$this->container_name];
|
||||||
|
|
|
||||||
|
|
@ -360,7 +360,7 @@ class PushServerUpdateJob implements ShouldBeEncrypted, ShouldQueue
|
||||||
private function checkLogDrainContainer()
|
private function checkLogDrainContainer()
|
||||||
{
|
{
|
||||||
if ($this->server->isLogDrainEnabled() && $this->foundLogDrainContainer === false) {
|
if ($this->server->isLogDrainEnabled() && $this->foundLogDrainContainer === false) {
|
||||||
StartLogDrain::dispatch($this->server);
|
StartLogDrain::dispatch($this->server)->onQueue('high');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ use Illuminate\Contracts\Queue\ShouldBeEncrypted;
|
||||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
use Illuminate\Foundation\Bus\Dispatchable;
|
use Illuminate\Foundation\Bus\Dispatchable;
|
||||||
use Illuminate\Queue\InteractsWithQueue;
|
use Illuminate\Queue\InteractsWithQueue;
|
||||||
|
use Illuminate\Queue\Middleware\WithoutOverlapping;
|
||||||
use Illuminate\Queue\SerializesModels;
|
use Illuminate\Queue\SerializesModels;
|
||||||
|
|
||||||
class ServerCheckJob implements ShouldBeEncrypted, ShouldQueue
|
class ServerCheckJob implements ShouldBeEncrypted, ShouldQueue
|
||||||
|
|
@ -25,6 +26,11 @@ class ServerCheckJob implements ShouldBeEncrypted, ShouldQueue
|
||||||
|
|
||||||
public $containers;
|
public $containers;
|
||||||
|
|
||||||
|
public function middleware(): array
|
||||||
|
{
|
||||||
|
return [(new WithoutOverlapping($this->server->id))->dontRelease()];
|
||||||
|
}
|
||||||
|
|
||||||
public function __construct(public Server $server) {}
|
public function __construct(public Server $server) {}
|
||||||
|
|
||||||
public function handle()
|
public function handle()
|
||||||
|
|
@ -88,10 +94,10 @@ class ServerCheckJob implements ShouldBeEncrypted, ShouldQueue
|
||||||
if ($foundLogDrainContainer) {
|
if ($foundLogDrainContainer) {
|
||||||
$status = data_get($foundLogDrainContainer, 'State.Status');
|
$status = data_get($foundLogDrainContainer, 'State.Status');
|
||||||
if ($status !== 'running') {
|
if ($status !== 'running') {
|
||||||
StartLogDrain::dispatch($this->server);
|
StartLogDrain::dispatch($this->server)->onQueue('high');
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
StartLogDrain::dispatch($this->server);
|
StartLogDrain::dispatch($this->server)->onQueue('high');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -30,8 +30,7 @@ class ServerLimitCheckJob implements ShouldBeEncrypted, ShouldQueue
|
||||||
try {
|
try {
|
||||||
$servers = $this->team->servers;
|
$servers = $this->team->servers;
|
||||||
$servers_count = $servers->count();
|
$servers_count = $servers->count();
|
||||||
$limit = data_get($this->team->limits, 'serverLimit', 2);
|
$number_of_servers_to_disable = $servers_count - $this->team->limits;
|
||||||
$number_of_servers_to_disable = $servers_count - $limit;
|
|
||||||
if ($number_of_servers_to_disable > 0) {
|
if ($number_of_servers_to_disable > 0) {
|
||||||
$servers = $servers->sortbyDesc('created_at');
|
$servers = $servers->sortbyDesc('created_at');
|
||||||
$servers_to_disable = $servers->take($number_of_servers_to_disable);
|
$servers_to_disable = $servers->take($number_of_servers_to_disable);
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ use App\Models\Server;
|
||||||
use App\Models\StandaloneDocker;
|
use App\Models\StandaloneDocker;
|
||||||
use App\Models\SwarmDocker;
|
use App\Models\SwarmDocker;
|
||||||
use Livewire\Attributes\Locked;
|
use Livewire\Attributes\Locked;
|
||||||
use Livewire\Attributes\Rule;
|
use Livewire\Attributes\Validate;
|
||||||
use Livewire\Component;
|
use Livewire\Component;
|
||||||
use Visus\Cuid2\Cuid2;
|
use Visus\Cuid2\Cuid2;
|
||||||
|
|
||||||
|
|
@ -18,16 +18,16 @@ class Docker extends Component
|
||||||
#[Locked]
|
#[Locked]
|
||||||
public Server $selectedServer;
|
public Server $selectedServer;
|
||||||
|
|
||||||
#[Rule(['required', 'string'])]
|
#[Validate(['required', 'string'])]
|
||||||
public string $name;
|
public string $name;
|
||||||
|
|
||||||
#[Rule(['required', 'string'])]
|
#[Validate(['required', 'string'])]
|
||||||
public string $network;
|
public string $network;
|
||||||
|
|
||||||
#[Rule(['required', 'string'])]
|
#[Validate(['required', 'string'])]
|
||||||
public string $serverId;
|
public string $serverId;
|
||||||
|
|
||||||
#[Rule(['required', 'boolean'])]
|
#[Validate(['required', 'boolean'])]
|
||||||
public bool $isSwarm = false;
|
public bool $isSwarm = false;
|
||||||
|
|
||||||
public function mount(?string $server_id = null)
|
public function mount(?string $server_id = null)
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ use App\Models\Server;
|
||||||
use App\Models\StandaloneDocker;
|
use App\Models\StandaloneDocker;
|
||||||
use App\Models\SwarmDocker;
|
use App\Models\SwarmDocker;
|
||||||
use Livewire\Attributes\Locked;
|
use Livewire\Attributes\Locked;
|
||||||
use Livewire\Attributes\Rule;
|
use Livewire\Attributes\Validate;
|
||||||
use Livewire\Component;
|
use Livewire\Component;
|
||||||
|
|
||||||
class Show extends Component
|
class Show extends Component
|
||||||
|
|
@ -14,13 +14,13 @@ class Show extends Component
|
||||||
#[Locked]
|
#[Locked]
|
||||||
public $destination;
|
public $destination;
|
||||||
|
|
||||||
#[Rule(['string', 'required'])]
|
#[Validate(['string', 'required'])]
|
||||||
public string $name;
|
public string $name;
|
||||||
|
|
||||||
#[Rule(['string', 'required'])]
|
#[Validate(['string', 'required'])]
|
||||||
public string $network;
|
public string $network;
|
||||||
|
|
||||||
#[Rule(['string', 'required'])]
|
#[Validate(['string', 'required'])]
|
||||||
public string $serverIp;
|
public string $serverIp;
|
||||||
|
|
||||||
public function mount(string $destination_uuid)
|
public function mount(string $destination_uuid)
|
||||||
|
|
|
||||||
|
|
@ -5,17 +5,17 @@ namespace App\Livewire;
|
||||||
use DanHarrin\LivewireRateLimiting\WithRateLimiting;
|
use DanHarrin\LivewireRateLimiting\WithRateLimiting;
|
||||||
use Illuminate\Notifications\Messages\MailMessage;
|
use Illuminate\Notifications\Messages\MailMessage;
|
||||||
use Illuminate\Support\Facades\Http;
|
use Illuminate\Support\Facades\Http;
|
||||||
use Livewire\Attributes\Rule;
|
use Livewire\Attributes\Validate;
|
||||||
use Livewire\Component;
|
use Livewire\Component;
|
||||||
|
|
||||||
class Help extends Component
|
class Help extends Component
|
||||||
{
|
{
|
||||||
use WithRateLimiting;
|
use WithRateLimiting;
|
||||||
|
|
||||||
#[Rule(['required', 'min:10', 'max:1000'])]
|
#[Validate(['required', 'min:10', 'max:1000'])]
|
||||||
public string $description;
|
public string $description;
|
||||||
|
|
||||||
#[Rule(['required', 'min:3'])]
|
#[Validate(['required', 'min:3'])]
|
||||||
public string $subject;
|
public string $subject;
|
||||||
|
|
||||||
public function submit()
|
public function submit()
|
||||||
|
|
|
||||||
|
|
@ -4,35 +4,35 @@ namespace App\Livewire\Notifications;
|
||||||
|
|
||||||
use App\Models\Team;
|
use App\Models\Team;
|
||||||
use App\Notifications\Test;
|
use App\Notifications\Test;
|
||||||
use Livewire\Attributes\Rule;
|
use Livewire\Attributes\Validate;
|
||||||
use Livewire\Component;
|
use Livewire\Component;
|
||||||
|
|
||||||
class Discord extends Component
|
class Discord extends Component
|
||||||
{
|
{
|
||||||
public Team $team;
|
public Team $team;
|
||||||
|
|
||||||
#[Rule(['boolean'])]
|
#[Validate(['boolean'])]
|
||||||
public bool $discordEnabled = false;
|
public bool $discordEnabled = false;
|
||||||
|
|
||||||
#[Rule(['url', 'nullable'])]
|
#[Validate(['url', 'nullable'])]
|
||||||
public ?string $discordWebhookUrl = null;
|
public ?string $discordWebhookUrl = null;
|
||||||
|
|
||||||
#[Rule(['boolean'])]
|
#[Validate(['boolean'])]
|
||||||
public bool $discordNotificationsTest = false;
|
public bool $discordNotificationsTest = false;
|
||||||
|
|
||||||
#[Rule(['boolean'])]
|
#[Validate(['boolean'])]
|
||||||
public bool $discordNotificationsDeployments = false;
|
public bool $discordNotificationsDeployments = false;
|
||||||
|
|
||||||
#[Rule(['boolean'])]
|
#[Validate(['boolean'])]
|
||||||
public bool $discordNotificationsStatusChanges = false;
|
public bool $discordNotificationsStatusChanges = false;
|
||||||
|
|
||||||
#[Rule(['boolean'])]
|
#[Validate(['boolean'])]
|
||||||
public bool $discordNotificationsDatabaseBackups = false;
|
public bool $discordNotificationsDatabaseBackups = false;
|
||||||
|
|
||||||
#[Rule(['boolean'])]
|
#[Validate(['boolean'])]
|
||||||
public bool $discordNotificationsScheduledTasks = false;
|
public bool $discordNotificationsScheduledTasks = false;
|
||||||
|
|
||||||
#[Rule(['boolean'])]
|
#[Validate(['boolean'])]
|
||||||
public bool $discordNotificationsServerDiskUsage = false;
|
public bool $discordNotificationsServerDiskUsage = false;
|
||||||
|
|
||||||
public function mount()
|
public function mount()
|
||||||
|
|
@ -41,7 +41,7 @@ class Discord extends Component
|
||||||
$this->team = auth()->user()->currentTeam();
|
$this->team = auth()->user()->currentTeam();
|
||||||
$this->syncData();
|
$this->syncData();
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
handleError($e, $this);
|
return handleError($e, $this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -57,11 +57,8 @@ class Discord extends Component
|
||||||
$this->team->discord_notifications_database_backups = $this->discordNotificationsDatabaseBackups;
|
$this->team->discord_notifications_database_backups = $this->discordNotificationsDatabaseBackups;
|
||||||
$this->team->discord_notifications_scheduled_tasks = $this->discordNotificationsScheduledTasks;
|
$this->team->discord_notifications_scheduled_tasks = $this->discordNotificationsScheduledTasks;
|
||||||
$this->team->discord_notifications_server_disk_usage = $this->discordNotificationsServerDiskUsage;
|
$this->team->discord_notifications_server_disk_usage = $this->discordNotificationsServerDiskUsage;
|
||||||
try {
|
$this->team->save();
|
||||||
$this->saveModel();
|
refreshSession();
|
||||||
} catch (\Throwable $e) {
|
|
||||||
return handleError($e, $this);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
$this->discordEnabled = $this->team->discord_enabled;
|
$this->discordEnabled = $this->team->discord_enabled;
|
||||||
$this->discordWebhookUrl = $this->team->discord_webhook_url;
|
$this->discordWebhookUrl = $this->team->discord_webhook_url;
|
||||||
|
|
@ -74,6 +71,22 @@ class Discord extends Component
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function instantSaveDiscordEnabled()
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$this->validate([
|
||||||
|
'discordWebhookUrl' => 'required',
|
||||||
|
], [
|
||||||
|
'discordWebhookUrl.required' => 'Discord Webhook URL is required.',
|
||||||
|
]);
|
||||||
|
$this->saveModel();
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
$this->discordEnabled = false;
|
||||||
|
|
||||||
|
return handleError($e, $this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public function instantSave()
|
public function instantSave()
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
|
|
@ -96,7 +109,7 @@ class Discord extends Component
|
||||||
|
|
||||||
public function saveModel()
|
public function saveModel()
|
||||||
{
|
{
|
||||||
$this->team->save();
|
$this->syncData(true);
|
||||||
refreshSession();
|
refreshSession();
|
||||||
$this->dispatch('success', 'Settings saved.');
|
$this->dispatch('success', 'Settings saved.');
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,75 +5,133 @@ namespace App\Livewire\Notifications;
|
||||||
use App\Models\Team;
|
use App\Models\Team;
|
||||||
use App\Notifications\Test;
|
use App\Notifications\Test;
|
||||||
use Illuminate\Support\Facades\RateLimiter;
|
use Illuminate\Support\Facades\RateLimiter;
|
||||||
|
use Livewire\Attributes\Locked;
|
||||||
|
use Livewire\Attributes\Validate;
|
||||||
use Livewire\Component;
|
use Livewire\Component;
|
||||||
|
|
||||||
class Email extends Component
|
class Email extends Component
|
||||||
{
|
{
|
||||||
public Team $team;
|
public Team $team;
|
||||||
|
|
||||||
|
#[Locked]
|
||||||
public string $emails;
|
public string $emails;
|
||||||
|
|
||||||
public bool $sharedEmailEnabled = false;
|
#[Validate(['boolean'])]
|
||||||
|
public bool $smtpEnabled = false;
|
||||||
|
|
||||||
protected $rules = [
|
#[Validate(['boolean'])]
|
||||||
'team.smtp_enabled' => 'nullable|boolean',
|
public bool $useInstanceEmailSettings = false;
|
||||||
'team.smtp_from_address' => 'required|email',
|
|
||||||
'team.smtp_from_name' => 'required',
|
|
||||||
'team.smtp_recipients' => 'nullable',
|
|
||||||
'team.smtp_host' => 'required',
|
|
||||||
'team.smtp_port' => 'required',
|
|
||||||
'team.smtp_encryption' => 'nullable',
|
|
||||||
'team.smtp_username' => 'nullable',
|
|
||||||
'team.smtp_password' => 'nullable',
|
|
||||||
'team.smtp_timeout' => 'nullable',
|
|
||||||
'team.smtp_notifications_test' => 'nullable|boolean',
|
|
||||||
'team.smtp_notifications_deployments' => 'nullable|boolean',
|
|
||||||
'team.smtp_notifications_status_changes' => 'nullable|boolean',
|
|
||||||
'team.smtp_notifications_database_backups' => 'nullable|boolean',
|
|
||||||
'team.smtp_notifications_scheduled_tasks' => 'nullable|boolean',
|
|
||||||
'team.smtp_notifications_server_disk_usage' => 'nullable|boolean',
|
|
||||||
'team.use_instance_email_settings' => 'boolean',
|
|
||||||
'team.resend_enabled' => 'nullable|boolean',
|
|
||||||
'team.resend_api_key' => 'nullable',
|
|
||||||
];
|
|
||||||
|
|
||||||
protected $validationAttributes = [
|
#[Validate(['nullable', 'email'])]
|
||||||
'team.smtp_from_address' => 'From Address',
|
public ?string $smtpFromAddress = null;
|
||||||
'team.smtp_from_name' => 'From Name',
|
|
||||||
'team.smtp_recipients' => 'Recipients',
|
#[Validate(['nullable', 'string'])]
|
||||||
'team.smtp_host' => 'Host',
|
public ?string $smtpFromName = null;
|
||||||
'team.smtp_port' => 'Port',
|
|
||||||
'team.smtp_encryption' => 'Encryption',
|
#[Validate(['nullable', 'string'])]
|
||||||
'team.smtp_username' => 'Username',
|
public ?string $smtpRecipients = null;
|
||||||
'team.smtp_password' => 'Password',
|
|
||||||
'team.smtp_timeout' => 'Timeout',
|
#[Validate(['nullable', 'string'])]
|
||||||
'team.resend_enabled' => 'Resend Enabled',
|
public ?string $smtpHost = null;
|
||||||
'team.resend_api_key' => 'Resend API Key',
|
|
||||||
];
|
#[Validate(['nullable', 'numeric'])]
|
||||||
|
public ?int $smtpPort = null;
|
||||||
|
|
||||||
|
#[Validate(['nullable', 'string'])]
|
||||||
|
public ?string $smtpEncryption = null;
|
||||||
|
|
||||||
|
#[Validate(['nullable', 'string'])]
|
||||||
|
public ?string $smtpUsername = null;
|
||||||
|
|
||||||
|
#[Validate(['nullable', 'string'])]
|
||||||
|
public ?string $smtpPassword = null;
|
||||||
|
|
||||||
|
#[Validate(['nullable', 'numeric'])]
|
||||||
|
public ?int $smtpTimeout = null;
|
||||||
|
|
||||||
|
#[Validate(['boolean'])]
|
||||||
|
public bool $smtpNotificationsTest;
|
||||||
|
|
||||||
|
#[Validate(['boolean'])]
|
||||||
|
public bool $smtpNotificationsDeployments;
|
||||||
|
|
||||||
|
#[Validate(['boolean'])]
|
||||||
|
public bool $smtpNotificationsStatusChanges;
|
||||||
|
|
||||||
|
#[Validate(['boolean'])]
|
||||||
|
public bool $smtpNotificationsDatabaseBackups;
|
||||||
|
|
||||||
|
#[Validate(['boolean'])]
|
||||||
|
public bool $smtpNotificationsScheduledTasks;
|
||||||
|
|
||||||
|
#[Validate(['boolean'])]
|
||||||
|
public bool $smtpNotificationsServerDiskUsage;
|
||||||
|
|
||||||
|
#[Validate(['boolean'])]
|
||||||
|
public bool $resendEnabled;
|
||||||
|
|
||||||
|
#[Validate(['nullable', 'string'])]
|
||||||
|
public ?string $resendApiKey = null;
|
||||||
|
|
||||||
public function mount()
|
public function mount()
|
||||||
{
|
|
||||||
$this->team = auth()->user()->currentTeam();
|
|
||||||
['sharedEmailEnabled' => $this->sharedEmailEnabled] = $this->team->limits;
|
|
||||||
$this->emails = auth()->user()->email;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function submitFromFields()
|
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
$this->resetErrorBag();
|
$this->team = auth()->user()->currentTeam();
|
||||||
$this->validate([
|
$this->emails = auth()->user()->email;
|
||||||
'team.smtp_from_address' => 'required|email',
|
$this->syncData();
|
||||||
'team.smtp_from_name' => 'required',
|
|
||||||
]);
|
|
||||||
$this->team->save();
|
|
||||||
refreshSession();
|
|
||||||
$this->dispatch('success', 'Settings saved.');
|
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
return handleError($e, $this);
|
return handleError($e, $this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function syncData(bool $toModel = false)
|
||||||
|
{
|
||||||
|
if ($toModel) {
|
||||||
|
$this->validate();
|
||||||
|
$this->team->smtp_enabled = $this->smtpEnabled;
|
||||||
|
$this->team->smtp_from_address = $this->smtpFromAddress;
|
||||||
|
$this->team->smtp_from_name = $this->smtpFromName;
|
||||||
|
$this->team->smtp_host = $this->smtpHost;
|
||||||
|
$this->team->smtp_port = $this->smtpPort;
|
||||||
|
$this->team->smtp_encryption = $this->smtpEncryption;
|
||||||
|
$this->team->smtp_username = $this->smtpUsername;
|
||||||
|
$this->team->smtp_password = $this->smtpPassword;
|
||||||
|
$this->team->smtp_timeout = $this->smtpTimeout;
|
||||||
|
$this->team->smtp_recipients = $this->smtpRecipients;
|
||||||
|
$this->team->smtp_notifications_test = $this->smtpNotificationsTest;
|
||||||
|
$this->team->smtp_notifications_deployments = $this->smtpNotificationsDeployments;
|
||||||
|
$this->team->smtp_notifications_status_changes = $this->smtpNotificationsStatusChanges;
|
||||||
|
$this->team->smtp_notifications_database_backups = $this->smtpNotificationsDatabaseBackups;
|
||||||
|
$this->team->smtp_notifications_scheduled_tasks = $this->smtpNotificationsScheduledTasks;
|
||||||
|
$this->team->smtp_notifications_server_disk_usage = $this->smtpNotificationsServerDiskUsage;
|
||||||
|
$this->team->use_instance_email_settings = $this->useInstanceEmailSettings;
|
||||||
|
$this->team->resend_enabled = $this->resendEnabled;
|
||||||
|
$this->team->resend_api_key = $this->resendApiKey;
|
||||||
|
$this->team->save();
|
||||||
|
refreshSession();
|
||||||
|
} else {
|
||||||
|
$this->smtpEnabled = $this->team->smtp_enabled;
|
||||||
|
$this->smtpFromAddress = $this->team->smtp_from_address;
|
||||||
|
$this->smtpFromName = $this->team->smtp_from_name;
|
||||||
|
$this->smtpHost = $this->team->smtp_host;
|
||||||
|
$this->smtpPort = $this->team->smtp_port;
|
||||||
|
$this->smtpEncryption = $this->team->smtp_encryption;
|
||||||
|
$this->smtpUsername = $this->team->smtp_username;
|
||||||
|
$this->smtpPassword = $this->team->smtp_password;
|
||||||
|
$this->smtpTimeout = $this->team->smtp_timeout;
|
||||||
|
$this->smtpRecipients = $this->team->smtp_recipients;
|
||||||
|
$this->smtpNotificationsTest = $this->team->smtp_notifications_test;
|
||||||
|
$this->smtpNotificationsDeployments = $this->team->smtp_notifications_deployments;
|
||||||
|
$this->smtpNotificationsStatusChanges = $this->team->smtp_notifications_status_changes;
|
||||||
|
$this->smtpNotificationsDatabaseBackups = $this->team->smtp_notifications_database_backups;
|
||||||
|
$this->smtpNotificationsScheduledTasks = $this->team->smtp_notifications_scheduled_tasks;
|
||||||
|
$this->smtpNotificationsServerDiskUsage = $this->team->smtp_notifications_server_disk_usage;
|
||||||
|
$this->useInstanceEmailSettings = $this->team->use_instance_email_settings;
|
||||||
|
$this->resendEnabled = $this->team->resend_enabled;
|
||||||
|
$this->resendApiKey = $this->team->resend_api_key;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public function sendTestNotification()
|
public function sendTestNotification()
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
|
|
@ -98,38 +156,44 @@ class Email extends Component
|
||||||
public function instantSaveInstance()
|
public function instantSaveInstance()
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
if (! $this->sharedEmailEnabled) {
|
$this->smtpEnabled = false;
|
||||||
throw new \Exception('Not allowed to change settings. Please upgrade your subscription.');
|
$this->resendEnabled = false;
|
||||||
}
|
$this->saveModel();
|
||||||
$this->team->smtp_enabled = false;
|
|
||||||
$this->team->resend_enabled = false;
|
|
||||||
$this->team->save();
|
|
||||||
refreshSession();
|
|
||||||
$this->dispatch('success', 'Settings saved.');
|
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
return handleError($e, $this);
|
return handleError($e, $this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function instantSaveSmtpEnabled()
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$this->validate([
|
||||||
|
'smtpHost' => 'required',
|
||||||
|
'smtpPort' => 'required|numeric',
|
||||||
|
], [
|
||||||
|
'smtpHost.required' => 'SMTP Host is required.',
|
||||||
|
'smtpPort.required' => 'SMTP Port is required.',
|
||||||
|
]);
|
||||||
|
$this->resendEnabled = false;
|
||||||
|
$this->saveModel();
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
$this->smtpEnabled = false;
|
||||||
|
|
||||||
|
return handleError($e, $this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public function instantSaveResend()
|
public function instantSaveResend()
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
$this->team->smtp_enabled = false;
|
$this->validate([
|
||||||
$this->submitResend();
|
], [
|
||||||
|
'resendApiKey.required' => 'Resend API Key is required.',
|
||||||
|
]);
|
||||||
|
$this->smtpEnabled = false;
|
||||||
|
$this->saveModel();
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
$this->team->smtp_enabled = false;
|
$this->resendEnabled = false;
|
||||||
|
|
||||||
return handleError($e, $this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function instantSave()
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
$this->team->resend_enabled = false;
|
|
||||||
$this->submit();
|
|
||||||
} catch (\Throwable $e) {
|
|
||||||
$this->team->smtp_enabled = false;
|
|
||||||
|
|
||||||
return handleError($e, $this);
|
return handleError($e, $this);
|
||||||
}
|
}
|
||||||
|
|
@ -137,7 +201,7 @@ class Email extends Component
|
||||||
|
|
||||||
public function saveModel()
|
public function saveModel()
|
||||||
{
|
{
|
||||||
$this->team->save();
|
$this->syncData(true);
|
||||||
refreshSession();
|
refreshSession();
|
||||||
$this->dispatch('success', 'Settings saved.');
|
$this->dispatch('success', 'Settings saved.');
|
||||||
}
|
}
|
||||||
|
|
@ -146,43 +210,8 @@ class Email extends Component
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
$this->resetErrorBag();
|
$this->resetErrorBag();
|
||||||
if (! $this->team->use_instance_email_settings) {
|
$this->saveModel();
|
||||||
$this->validate([
|
|
||||||
'team.smtp_from_address' => 'required|email',
|
|
||||||
'team.smtp_from_name' => 'required',
|
|
||||||
'team.smtp_host' => 'required',
|
|
||||||
'team.smtp_port' => 'required|numeric',
|
|
||||||
'team.smtp_encryption' => 'nullable',
|
|
||||||
'team.smtp_username' => 'nullable',
|
|
||||||
'team.smtp_password' => 'nullable',
|
|
||||||
'team.smtp_timeout' => 'nullable',
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
$this->team->save();
|
|
||||||
refreshSession();
|
|
||||||
$this->dispatch('success', 'Settings saved.');
|
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
$this->team->smtp_enabled = false;
|
|
||||||
|
|
||||||
return handleError($e, $this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function submitResend()
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
$this->resetErrorBag();
|
|
||||||
$this->validate([
|
|
||||||
'team.smtp_from_address' => 'required|email',
|
|
||||||
'team.smtp_from_name' => 'required',
|
|
||||||
'team.resend_api_key' => 'required',
|
|
||||||
]);
|
|
||||||
$this->team->save();
|
|
||||||
refreshSession();
|
|
||||||
$this->dispatch('success', 'Settings saved.');
|
|
||||||
} catch (\Throwable $e) {
|
|
||||||
$this->team->resend_enabled = false;
|
|
||||||
|
|
||||||
return handleError($e, $this);
|
return handleError($e, $this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -190,35 +219,28 @@ class Email extends Component
|
||||||
public function copyFromInstanceSettings()
|
public function copyFromInstanceSettings()
|
||||||
{
|
{
|
||||||
$settings = instanceSettings();
|
$settings = instanceSettings();
|
||||||
|
|
||||||
if ($settings->smtp_enabled) {
|
if ($settings->smtp_enabled) {
|
||||||
$team = currentTeam();
|
$this->smtpEnabled = true;
|
||||||
$team->update([
|
$this->smtpFromAddress = $settings->smtp_from_address;
|
||||||
'smtp_enabled' => $settings->smtp_enabled,
|
$this->smtpFromName = $settings->smtp_from_name;
|
||||||
'smtp_from_address' => $settings->smtp_from_address,
|
$this->smtpRecipients = $settings->smtp_recipients;
|
||||||
'smtp_from_name' => $settings->smtp_from_name,
|
$this->smtpHost = $settings->smtp_host;
|
||||||
'smtp_recipients' => $settings->smtp_recipients,
|
$this->smtpPort = $settings->smtp_port;
|
||||||
'smtp_host' => $settings->smtp_host,
|
$this->smtpEncryption = $settings->smtp_encryption;
|
||||||
'smtp_port' => $settings->smtp_port,
|
$this->smtpUsername = $settings->smtp_username;
|
||||||
'smtp_encryption' => $settings->smtp_encryption,
|
$this->smtpPassword = $settings->smtp_password;
|
||||||
'smtp_username' => $settings->smtp_username,
|
$this->smtpTimeout = $settings->smtp_timeout;
|
||||||
'smtp_password' => $settings->smtp_password,
|
$this->resendEnabled = false;
|
||||||
'smtp_timeout' => $settings->smtp_timeout,
|
$this->saveModel();
|
||||||
]);
|
|
||||||
refreshSession();
|
|
||||||
$this->team = $team;
|
|
||||||
$this->dispatch('success', 'Settings saved.');
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if ($settings->resend_enabled) {
|
if ($settings->resend_enabled) {
|
||||||
$team = currentTeam();
|
$this->resendEnabled = true;
|
||||||
$team->update([
|
$this->resendApiKey = $settings->resend_api_key;
|
||||||
'resend_enabled' => $settings->resend_enabled,
|
$this->smtpEnabled = false;
|
||||||
'resend_api_key' => $settings->resend_api_key,
|
$this->saveModel();
|
||||||
]);
|
|
||||||
refreshSession();
|
|
||||||
$this->team = $team;
|
|
||||||
$this->dispatch('success', 'Settings saved.');
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,67 +4,157 @@ namespace App\Livewire\Notifications;
|
||||||
|
|
||||||
use App\Models\Team;
|
use App\Models\Team;
|
||||||
use App\Notifications\Test;
|
use App\Notifications\Test;
|
||||||
|
use Livewire\Attributes\Validate;
|
||||||
use Livewire\Component;
|
use Livewire\Component;
|
||||||
|
|
||||||
class Telegram extends Component
|
class Telegram extends Component
|
||||||
{
|
{
|
||||||
public Team $team;
|
public Team $team;
|
||||||
|
|
||||||
protected $rules = [
|
#[Validate(['boolean'])]
|
||||||
'team.telegram_enabled' => 'nullable|boolean',
|
public bool $telegramEnabled = false;
|
||||||
'team.telegram_token' => 'required|string',
|
|
||||||
'team.telegram_chat_id' => 'required|string',
|
|
||||||
'team.telegram_notifications_test' => 'nullable|boolean',
|
|
||||||
'team.telegram_notifications_deployments' => 'nullable|boolean',
|
|
||||||
'team.telegram_notifications_status_changes' => 'nullable|boolean',
|
|
||||||
'team.telegram_notifications_database_backups' => 'nullable|boolean',
|
|
||||||
'team.telegram_notifications_scheduled_tasks' => 'nullable|boolean',
|
|
||||||
'team.telegram_notifications_test_message_thread_id' => 'nullable|string',
|
|
||||||
'team.telegram_notifications_deployments_message_thread_id' => 'nullable|string',
|
|
||||||
'team.telegram_notifications_status_changes_message_thread_id' => 'nullable|string',
|
|
||||||
'team.telegram_notifications_database_backups_message_thread_id' => 'nullable|string',
|
|
||||||
'team.telegram_notifications_scheduled_tasks_thread_id' => 'nullable|string',
|
|
||||||
'team.telegram_notifications_server_disk_usage' => 'nullable|boolean',
|
|
||||||
];
|
|
||||||
|
|
||||||
protected $validationAttributes = [
|
#[Validate(['nullable', 'string'])]
|
||||||
'team.telegram_token' => 'Token',
|
public ?string $telegramToken = null;
|
||||||
'team.telegram_chat_id' => 'Chat ID',
|
|
||||||
];
|
#[Validate(['nullable', 'string'])]
|
||||||
|
public ?string $telegramChatId = null;
|
||||||
|
|
||||||
|
#[Validate(['boolean'])]
|
||||||
|
public bool $telegramNotificationsTest = false;
|
||||||
|
|
||||||
|
#[Validate(['boolean'])]
|
||||||
|
public bool $telegramNotificationsDeployments = false;
|
||||||
|
|
||||||
|
#[Validate(['boolean'])]
|
||||||
|
public bool $telegramNotificationsStatusChanges = false;
|
||||||
|
|
||||||
|
#[Validate(['boolean'])]
|
||||||
|
public bool $telegramNotificationsDatabaseBackups = false;
|
||||||
|
|
||||||
|
#[Validate(['boolean'])]
|
||||||
|
public bool $telegramNotificationsScheduledTasks = false;
|
||||||
|
|
||||||
|
#[Validate(['nullable', 'string'])]
|
||||||
|
public ?string $telegramNotificationsTestMessageThreadId = null;
|
||||||
|
|
||||||
|
#[Validate(['nullable', 'string'])]
|
||||||
|
public ?string $telegramNotificationsDeploymentsMessageThreadId = null;
|
||||||
|
|
||||||
|
#[Validate(['nullable', 'string'])]
|
||||||
|
public ?string $telegramNotificationsStatusChangesMessageThreadId = null;
|
||||||
|
|
||||||
|
#[Validate(['nullable', 'string'])]
|
||||||
|
public ?string $telegramNotificationsDatabaseBackupsMessageThreadId = null;
|
||||||
|
|
||||||
|
#[Validate(['nullable', 'string'])]
|
||||||
|
public ?string $telegramNotificationsScheduledTasksThreadId = null;
|
||||||
|
|
||||||
|
#[Validate(['boolean'])]
|
||||||
|
public bool $telegramNotificationsServerDiskUsage = false;
|
||||||
|
|
||||||
public function mount()
|
public function mount()
|
||||||
{
|
{
|
||||||
$this->team = auth()->user()->currentTeam();
|
try {
|
||||||
|
$this->team = auth()->user()->currentTeam();
|
||||||
|
$this->syncData();
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
return handleError($e, $this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function syncData(bool $toModel = false)
|
||||||
|
{
|
||||||
|
if ($toModel) {
|
||||||
|
$this->validate();
|
||||||
|
$this->team->telegram_enabled = $this->telegramEnabled;
|
||||||
|
$this->team->telegram_token = $this->telegramToken;
|
||||||
|
$this->team->telegram_chat_id = $this->telegramChatId;
|
||||||
|
$this->team->telegram_notifications_test = $this->telegramNotificationsTest;
|
||||||
|
$this->team->telegram_notifications_deployments = $this->telegramNotificationsDeployments;
|
||||||
|
$this->team->telegram_notifications_status_changes = $this->telegramNotificationsStatusChanges;
|
||||||
|
$this->team->telegram_notifications_database_backups = $this->telegramNotificationsDatabaseBackups;
|
||||||
|
$this->team->telegram_notifications_scheduled_tasks = $this->telegramNotificationsScheduledTasks;
|
||||||
|
$this->team->telegram_notifications_test_message_thread_id = $this->telegramNotificationsTestMessageThreadId;
|
||||||
|
$this->team->telegram_notifications_deployments_message_thread_id = $this->telegramNotificationsDeploymentsMessageThreadId;
|
||||||
|
$this->team->telegram_notifications_status_changes_message_thread_id = $this->telegramNotificationsStatusChangesMessageThreadId;
|
||||||
|
$this->team->telegram_notifications_database_backups_message_thread_id = $this->telegramNotificationsDatabaseBackupsMessageThreadId;
|
||||||
|
$this->team->telegram_notifications_scheduled_tasks_thread_id = $this->telegramNotificationsScheduledTasksThreadId;
|
||||||
|
$this->team->telegram_notifications_server_disk_usage = $this->telegramNotificationsServerDiskUsage;
|
||||||
|
$this->team->save();
|
||||||
|
refreshSession();
|
||||||
|
} else {
|
||||||
|
$this->telegramEnabled = $this->team->telegram_enabled;
|
||||||
|
$this->telegramToken = $this->team->telegram_token;
|
||||||
|
$this->telegramChatId = $this->team->telegram_chat_id;
|
||||||
|
$this->telegramNotificationsTest = $this->team->telegram_notifications_test;
|
||||||
|
$this->telegramNotificationsDeployments = $this->team->telegram_notifications_deployments;
|
||||||
|
$this->telegramNotificationsStatusChanges = $this->team->telegram_notifications_status_changes;
|
||||||
|
$this->telegramNotificationsDatabaseBackups = $this->team->telegram_notifications_database_backups;
|
||||||
|
$this->telegramNotificationsScheduledTasks = $this->team->telegram_notifications_scheduled_tasks;
|
||||||
|
$this->telegramNotificationsTestMessageThreadId = $this->team->telegram_notifications_test_message_thread_id;
|
||||||
|
$this->telegramNotificationsDeploymentsMessageThreadId = $this->team->telegram_notifications_deployments_message_thread_id;
|
||||||
|
$this->telegramNotificationsStatusChangesMessageThreadId = $this->team->telegram_notifications_status_changes_message_thread_id;
|
||||||
|
$this->telegramNotificationsDatabaseBackupsMessageThreadId = $this->team->telegram_notifications_database_backups_message_thread_id;
|
||||||
|
$this->telegramNotificationsScheduledTasksThreadId = $this->team->telegram_notifications_scheduled_tasks_thread_id;
|
||||||
|
$this->telegramNotificationsServerDiskUsage = $this->team->telegram_notifications_server_disk_usage;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function instantSave()
|
public function instantSave()
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
$this->submit();
|
$this->syncData(true);
|
||||||
} catch (\Throwable) {
|
} catch (\Throwable $e) {
|
||||||
$this->team->telegram_enabled = false;
|
return handleError($e, $this);
|
||||||
$this->validate();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function submit()
|
public function submit()
|
||||||
{
|
{
|
||||||
$this->resetErrorBag();
|
try {
|
||||||
$this->validate();
|
$this->resetErrorBag();
|
||||||
$this->saveModel();
|
$this->syncData(true);
|
||||||
|
$this->saveModel();
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
return handleError($e, $this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function instantSaveTelegramEnabled()
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$this->validate([
|
||||||
|
'telegramToken' => 'required',
|
||||||
|
'telegramChatId' => 'required',
|
||||||
|
], [
|
||||||
|
'telegramToken.required' => 'Telegram Token is required.',
|
||||||
|
'telegramChatId.required' => 'Telegram Chat ID is required.',
|
||||||
|
]);
|
||||||
|
$this->saveModel();
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
$this->telegramEnabled = false;
|
||||||
|
|
||||||
|
return handleError($e, $this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function saveModel()
|
public function saveModel()
|
||||||
{
|
{
|
||||||
$this->team->save();
|
$this->syncData(true);
|
||||||
refreshSession();
|
refreshSession();
|
||||||
$this->dispatch('success', 'Settings saved.');
|
$this->dispatch('success', 'Settings saved.');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function sendTestNotification()
|
public function sendTestNotification()
|
||||||
{
|
{
|
||||||
$this->team?->notify(new Test);
|
try {
|
||||||
$this->dispatch('success', 'Test notification sent.');
|
$this->team->notify(new Test);
|
||||||
|
$this->dispatch('success', 'Test notification sent.');
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
return handleError($e, $this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function render()
|
public function render()
|
||||||
|
|
|
||||||
|
|
@ -3,15 +3,15 @@
|
||||||
namespace App\Livewire\Project;
|
namespace App\Livewire\Project;
|
||||||
|
|
||||||
use App\Models\Project;
|
use App\Models\Project;
|
||||||
use Livewire\Attributes\Rule;
|
use Livewire\Attributes\Validate;
|
||||||
use Livewire\Component;
|
use Livewire\Component;
|
||||||
|
|
||||||
class AddEmpty extends Component
|
class AddEmpty extends Component
|
||||||
{
|
{
|
||||||
#[Rule(['required', 'string', 'min:3'])]
|
#[Validate(['required', 'string', 'min:3'])]
|
||||||
public string $name;
|
public string $name;
|
||||||
|
|
||||||
#[Rule(['nullable', 'string'])]
|
#[Validate(['nullable', 'string'])]
|
||||||
public string $description = '';
|
public string $description = '';
|
||||||
|
|
||||||
public function submit()
|
public function submit()
|
||||||
|
|
|
||||||
|
|
@ -3,120 +3,200 @@
|
||||||
namespace App\Livewire\Project\Application;
|
namespace App\Livewire\Project\Application;
|
||||||
|
|
||||||
use App\Models\Application;
|
use App\Models\Application;
|
||||||
|
use Livewire\Attributes\Validate;
|
||||||
use Livewire\Component;
|
use Livewire\Component;
|
||||||
|
|
||||||
class Advanced extends Component
|
class Advanced extends Component
|
||||||
{
|
{
|
||||||
public Application $application;
|
public Application $application;
|
||||||
|
|
||||||
public bool $is_force_https_enabled;
|
#[Validate(['boolean'])]
|
||||||
|
public bool $isForceHttpsEnabled = false;
|
||||||
|
|
||||||
public bool $is_gzip_enabled;
|
#[Validate(['boolean'])]
|
||||||
|
public bool $isGitSubmodulesEnabled = false;
|
||||||
|
|
||||||
public bool $is_stripprefix_enabled;
|
#[Validate(['boolean'])]
|
||||||
|
public bool $isGitLfsEnabled = false;
|
||||||
|
|
||||||
protected $rules = [
|
#[Validate(['boolean'])]
|
||||||
'application.settings.is_git_submodules_enabled' => 'boolean|required',
|
public bool $isPreviewDeploymentsEnabled = false;
|
||||||
'application.settings.is_git_lfs_enabled' => 'boolean|required',
|
|
||||||
'application.settings.is_preview_deployments_enabled' => 'boolean|required',
|
#[Validate(['boolean'])]
|
||||||
'application.settings.is_auto_deploy_enabled' => 'boolean|required',
|
public bool $isAutoDeployEnabled = true;
|
||||||
'is_force_https_enabled' => 'boolean|required',
|
|
||||||
'application.settings.is_log_drain_enabled' => 'boolean|required',
|
#[Validate(['boolean'])]
|
||||||
'application.settings.is_gpu_enabled' => 'boolean|required',
|
public bool $isLogDrainEnabled = false;
|
||||||
'application.settings.is_build_server_enabled' => 'boolean|required',
|
|
||||||
'application.settings.is_consistent_container_name_enabled' => 'boolean|required',
|
#[Validate(['boolean'])]
|
||||||
'application.settings.custom_internal_name' => 'string|nullable',
|
public bool $isGpuEnabled = false;
|
||||||
'application.settings.is_gzip_enabled' => 'boolean|required',
|
|
||||||
'application.settings.is_stripprefix_enabled' => 'boolean|required',
|
#[Validate(['string'])]
|
||||||
'application.settings.gpu_driver' => 'string|required',
|
public string $gpuDriver = '';
|
||||||
'application.settings.gpu_count' => 'string|required',
|
|
||||||
'application.settings.gpu_device_ids' => 'string|required',
|
#[Validate(['string', 'nullable'])]
|
||||||
'application.settings.gpu_options' => 'string|required',
|
public ?string $gpuCount = null;
|
||||||
'application.settings.is_raw_compose_deployment_enabled' => 'boolean|required',
|
|
||||||
'application.settings.connect_to_docker_network' => 'boolean|required',
|
#[Validate(['string', 'nullable'])]
|
||||||
];
|
public ?string $gpuDeviceIds = null;
|
||||||
|
|
||||||
|
#[Validate(['string', 'nullable'])]
|
||||||
|
public ?string $gpuOptions = null;
|
||||||
|
|
||||||
|
#[Validate(['boolean'])]
|
||||||
|
public bool $isBuildServerEnabled = false;
|
||||||
|
|
||||||
|
#[Validate(['boolean'])]
|
||||||
|
public bool $isConsistentContainerNameEnabled = false;
|
||||||
|
|
||||||
|
#[Validate(['string', 'nullable'])]
|
||||||
|
public ?string $customInternalName = null;
|
||||||
|
|
||||||
|
#[Validate(['boolean'])]
|
||||||
|
public bool $isGzipEnabled = true;
|
||||||
|
|
||||||
|
#[Validate(['boolean'])]
|
||||||
|
public bool $isStripprefixEnabled = true;
|
||||||
|
|
||||||
|
#[Validate(['boolean'])]
|
||||||
|
public bool $isRawComposeDeploymentEnabled = false;
|
||||||
|
|
||||||
|
#[Validate(['boolean'])]
|
||||||
|
public bool $isConnectToDockerNetworkEnabled = false;
|
||||||
|
|
||||||
public function mount()
|
public function mount()
|
||||||
{
|
{
|
||||||
$this->is_force_https_enabled = $this->application->isForceHttpsEnabled();
|
try {
|
||||||
$this->is_gzip_enabled = $this->application->isGzipEnabled();
|
$this->syncData();
|
||||||
$this->is_stripprefix_enabled = $this->application->isStripprefixEnabled();
|
} catch (\Throwable $e) {
|
||||||
|
return handleError($e, $this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function syncData(bool $toModel = false)
|
||||||
|
{
|
||||||
|
if ($toModel) {
|
||||||
|
$this->validate();
|
||||||
|
$this->application->settings->is_force_https_enabled = $this->isForceHttpsEnabled;
|
||||||
|
$this->application->settings->is_git_submodules_enabled = $this->isGitSubmodulesEnabled;
|
||||||
|
$this->application->settings->is_git_lfs_enabled = $this->isGitLfsEnabled;
|
||||||
|
$this->application->settings->is_preview_deployments_enabled = $this->isPreviewDeploymentsEnabled;
|
||||||
|
$this->application->settings->is_auto_deploy_enabled = $this->isAutoDeployEnabled;
|
||||||
|
$this->application->settings->is_log_drain_enabled = $this->isLogDrainEnabled;
|
||||||
|
$this->application->settings->is_gpu_enabled = $this->isGpuEnabled;
|
||||||
|
$this->application->settings->gpu_driver = $this->gpuDriver;
|
||||||
|
$this->application->settings->gpu_count = $this->gpuCount;
|
||||||
|
$this->application->settings->gpu_device_ids = $this->gpuDeviceIds;
|
||||||
|
$this->application->settings->gpu_options = $this->gpuOptions;
|
||||||
|
$this->application->settings->is_build_server_enabled = $this->isBuildServerEnabled;
|
||||||
|
$this->application->settings->is_consistent_container_name_enabled = $this->isConsistentContainerNameEnabled;
|
||||||
|
$this->application->settings->custom_internal_name = $this->customInternalName;
|
||||||
|
$this->application->settings->is_gzip_enabled = $this->isGzipEnabled;
|
||||||
|
$this->application->settings->is_stripprefix_enabled = $this->isStripprefixEnabled;
|
||||||
|
$this->application->settings->is_raw_compose_deployment_enabled = $this->isRawComposeDeploymentEnabled;
|
||||||
|
$this->application->settings->connect_to_docker_network = $this->isConnectToDockerNetworkEnabled;
|
||||||
|
$this->application->settings->save();
|
||||||
|
} else {
|
||||||
|
$this->isForceHttpsEnabled = $this->application->isForceHttpsEnabled();
|
||||||
|
$this->isGzipEnabled = $this->application->isGzipEnabled();
|
||||||
|
$this->isStripprefixEnabled = $this->application->isStripprefixEnabled();
|
||||||
|
$this->isLogDrainEnabled = $this->application->isLogDrainEnabled();
|
||||||
|
|
||||||
|
$this->isGitSubmodulesEnabled = $this->application->settings->is_git_submodules_enabled;
|
||||||
|
$this->isGitLfsEnabled = $this->application->settings->is_git_lfs_enabled;
|
||||||
|
$this->isPreviewDeploymentsEnabled = $this->application->settings->is_preview_deployments_enabled;
|
||||||
|
$this->isAutoDeployEnabled = $this->application->settings->is_auto_deploy_enabled;
|
||||||
|
$this->isGpuEnabled = $this->application->settings->is_gpu_enabled;
|
||||||
|
$this->gpuDriver = $this->application->settings->gpu_driver;
|
||||||
|
$this->gpuCount = $this->application->settings->gpu_count;
|
||||||
|
$this->gpuDeviceIds = $this->application->settings->gpu_device_ids;
|
||||||
|
$this->gpuOptions = $this->application->settings->gpu_options;
|
||||||
|
$this->isBuildServerEnabled = $this->application->settings->is_build_server_enabled;
|
||||||
|
$this->isConsistentContainerNameEnabled = $this->application->settings->is_consistent_container_name_enabled;
|
||||||
|
$this->customInternalName = $this->application->settings->custom_internal_name;
|
||||||
|
$this->isRawComposeDeploymentEnabled = $this->application->settings->is_raw_compose_deployment_enabled;
|
||||||
|
$this->isConnectToDockerNetworkEnabled = $this->application->settings->connect_to_docker_network;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function instantSave()
|
public function instantSave()
|
||||||
{
|
{
|
||||||
if ($this->application->isLogDrainEnabled()) {
|
try {
|
||||||
if (! $this->application->destination->server->isLogDrainEnabled()) {
|
if ($this->isLogDrainEnabled) {
|
||||||
$this->application->settings->is_log_drain_enabled = false;
|
if (! $this->application->destination->server->isLogDrainEnabled()) {
|
||||||
$this->dispatch('error', 'Log drain is not enabled on this server.');
|
$this->isLogDrainEnabled = false;
|
||||||
|
$this->syncData(true);
|
||||||
|
$this->dispatch('error', 'Log drain is not enabled on this server.');
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
if ($this->application->isForceHttpsEnabled() !== $this->isForceHttpsEnabled ||
|
||||||
|
$this->application->isGzipEnabled() !== $this->isGzipEnabled ||
|
||||||
|
$this->application->isStripprefixEnabled() !== $this->isStripprefixEnabled
|
||||||
|
) {
|
||||||
|
$this->dispatch('resetDefaultLabels', false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->application->settings->is_raw_compose_deployment_enabled) {
|
||||||
|
$this->application->oldRawParser();
|
||||||
|
} else {
|
||||||
|
$this->application->parse();
|
||||||
|
}
|
||||||
|
$this->syncData(true);
|
||||||
|
$this->dispatch('success', 'Settings saved.');
|
||||||
|
$this->dispatch('configurationChanged');
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
return handleError($e, $this);
|
||||||
}
|
}
|
||||||
if ($this->application->settings->is_force_https_enabled !== $this->is_force_https_enabled) {
|
|
||||||
$this->application->settings->is_force_https_enabled = $this->is_force_https_enabled;
|
|
||||||
$this->dispatch('resetDefaultLabels', false);
|
|
||||||
}
|
|
||||||
if ($this->application->settings->is_gzip_enabled !== $this->is_gzip_enabled) {
|
|
||||||
$this->application->settings->is_gzip_enabled = $this->is_gzip_enabled;
|
|
||||||
$this->dispatch('resetDefaultLabels', false);
|
|
||||||
}
|
|
||||||
if ($this->application->settings->is_stripprefix_enabled !== $this->is_stripprefix_enabled) {
|
|
||||||
$this->application->settings->is_stripprefix_enabled = $this->is_stripprefix_enabled;
|
|
||||||
$this->dispatch('resetDefaultLabels', false);
|
|
||||||
}
|
|
||||||
if ($this->application->settings->is_raw_compose_deployment_enabled) {
|
|
||||||
$this->application->oldRawParser();
|
|
||||||
} else {
|
|
||||||
$this->application->parse();
|
|
||||||
}
|
|
||||||
$this->application->settings->save();
|
|
||||||
$this->dispatch('success', 'Settings saved.');
|
|
||||||
$this->dispatch('configurationChanged');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function submit()
|
public function submit()
|
||||||
{
|
{
|
||||||
if ($this->application->settings->gpu_count && $this->application->settings->gpu_device_ids) {
|
try {
|
||||||
$this->dispatch('error', 'You cannot set both GPU count and GPU device IDs.');
|
if ($this->gpuCount && $this->gpuDeviceIds) {
|
||||||
$this->application->settings->gpu_count = null;
|
$this->dispatch('error', 'You cannot set both GPU count and GPU device IDs.');
|
||||||
$this->application->settings->gpu_device_ids = null;
|
$this->gpuCount = null;
|
||||||
$this->application->settings->save();
|
$this->gpuDeviceIds = null;
|
||||||
|
$this->syncData(true);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
$this->syncData(true);
|
||||||
|
$this->dispatch('success', 'Settings saved.');
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
return handleError($e, $this);
|
||||||
}
|
}
|
||||||
$this->application->settings->save();
|
|
||||||
$this->dispatch('success', 'Settings saved.');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function saveCustomName()
|
public function saveCustomName()
|
||||||
{
|
{
|
||||||
if (str($this->application->settings->custom_internal_name)->isNotEmpty()) {
|
if (str($this->customInternalName)->isNotEmpty()) {
|
||||||
$this->application->settings->custom_internal_name = str($this->application->settings->custom_internal_name)->slug()->value();
|
$this->customInternalName = str($this->customInternalName)->slug()->value();
|
||||||
} else {
|
} else {
|
||||||
$this->application->settings->custom_internal_name = null;
|
$this->customInternalName = null;
|
||||||
}
|
}
|
||||||
if (is_null($this->application->settings->custom_internal_name)) {
|
if (is_null($this->customInternalName)) {
|
||||||
$this->application->settings->save();
|
$this->syncData(true);
|
||||||
$this->dispatch('success', 'Custom name saved.');
|
$this->dispatch('success', 'Custom name saved.');
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
$customInternalName = $this->application->settings->custom_internal_name;
|
$customInternalName = $this->customInternalName;
|
||||||
$server = $this->application->destination->server;
|
$server = $this->application->destination->server;
|
||||||
$allApplications = $server->applications();
|
$allApplications = $server->applications();
|
||||||
|
|
||||||
$foundSameInternalName = $allApplications->filter(function ($application) {
|
$foundSameInternalName = $allApplications->filter(function ($application) {
|
||||||
return $application->id !== $this->application->id && $application->settings->custom_internal_name === $this->application->settings->custom_internal_name;
|
return $application->id !== $this->application->id && $application->settings->custom_internal_name === $this->customInternalName;
|
||||||
});
|
});
|
||||||
if ($foundSameInternalName->isNotEmpty()) {
|
if ($foundSameInternalName->isNotEmpty()) {
|
||||||
$this->dispatch('error', 'This custom container name is already in use by another application on this server.');
|
$this->dispatch('error', 'This custom container name is already in use by another application on this server.');
|
||||||
$this->application->settings->custom_internal_name = $customInternalName;
|
$this->customInternalName = $customInternalName;
|
||||||
$this->application->settings->refresh();
|
$this->syncData(true);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
$this->application->settings->save();
|
$this->syncData(true);
|
||||||
$this->dispatch('success', 'Custom name saved.');
|
$this->dispatch('success', 'Custom name saved.');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@
|
||||||
namespace App\Livewire\Project\Application\Preview;
|
namespace App\Livewire\Project\Application\Preview;
|
||||||
|
|
||||||
use App\Models\Application;
|
use App\Models\Application;
|
||||||
use Livewire\Attributes\Rule;
|
|
||||||
use Livewire\Component;
|
use Livewire\Component;
|
||||||
use Spatie\Url\Url;
|
use Spatie\Url\Url;
|
||||||
|
|
||||||
|
|
@ -11,7 +10,7 @@ class Form extends Component
|
||||||
{
|
{
|
||||||
public Application $application;
|
public Application $application;
|
||||||
|
|
||||||
#[Rule('required')]
|
#[Validate('required')]
|
||||||
public string $previewUrlTemplate;
|
public string $previewUrlTemplate;
|
||||||
|
|
||||||
public function mount()
|
public function mount()
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ namespace App\Livewire\Project\Application;
|
||||||
use App\Models\Application;
|
use App\Models\Application;
|
||||||
use App\Models\PrivateKey;
|
use App\Models\PrivateKey;
|
||||||
use Livewire\Attributes\Locked;
|
use Livewire\Attributes\Locked;
|
||||||
use Livewire\Attributes\Rule;
|
use Livewire\Attributes\Validate;
|
||||||
use Livewire\Component;
|
use Livewire\Component;
|
||||||
|
|
||||||
class Source extends Component
|
class Source extends Component
|
||||||
|
|
@ -15,19 +15,19 @@ class Source extends Component
|
||||||
#[Locked]
|
#[Locked]
|
||||||
public $privateKeys;
|
public $privateKeys;
|
||||||
|
|
||||||
#[Rule(['nullable', 'string'])]
|
#[Validate(['nullable', 'string'])]
|
||||||
public ?string $privateKeyName = null;
|
public ?string $privateKeyName = null;
|
||||||
|
|
||||||
#[Rule(['nullable', 'integer'])]
|
#[Validate(['nullable', 'integer'])]
|
||||||
public ?int $privateKeyId = null;
|
public ?int $privateKeyId = null;
|
||||||
|
|
||||||
#[Rule(['required', 'string'])]
|
#[Validate(['required', 'string'])]
|
||||||
public string $gitRepository;
|
public string $gitRepository;
|
||||||
|
|
||||||
#[Rule(['required', 'string'])]
|
#[Validate(['required', 'string'])]
|
||||||
public string $gitBranch;
|
public string $gitBranch;
|
||||||
|
|
||||||
#[Rule(['nullable', 'string'])]
|
#[Validate(['nullable', 'string'])]
|
||||||
public ?string $gitCommitSha = null;
|
public ?string $gitCommitSha = null;
|
||||||
|
|
||||||
public function mount()
|
public function mount()
|
||||||
|
|
|
||||||
|
|
@ -3,20 +3,20 @@
|
||||||
namespace App\Livewire\Project\Application;
|
namespace App\Livewire\Project\Application;
|
||||||
|
|
||||||
use App\Models\Application;
|
use App\Models\Application;
|
||||||
use Livewire\Attributes\Rule;
|
use Livewire\Attributes\Validate;
|
||||||
use Livewire\Component;
|
use Livewire\Component;
|
||||||
|
|
||||||
class Swarm extends Component
|
class Swarm extends Component
|
||||||
{
|
{
|
||||||
public Application $application;
|
public Application $application;
|
||||||
|
|
||||||
#[Rule('required')]
|
#[Validate('required')]
|
||||||
public int $swarmReplicas;
|
public int $swarmReplicas;
|
||||||
|
|
||||||
#[Rule(['nullable'])]
|
#[Validate(['nullable'])]
|
||||||
public ?string $swarmPlacementConstraints = null;
|
public ?string $swarmPlacementConstraints = null;
|
||||||
|
|
||||||
#[Rule('required')]
|
#[Validate('required')]
|
||||||
public bool $isSwarmOnlyWorkerNodes;
|
public bool $isSwarmOnlyWorkerNodes;
|
||||||
|
|
||||||
public function mount()
|
public function mount()
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ use Exception;
|
||||||
use Illuminate\Support\Facades\Auth;
|
use Illuminate\Support\Facades\Auth;
|
||||||
use Illuminate\Support\Facades\Hash;
|
use Illuminate\Support\Facades\Hash;
|
||||||
use Livewire\Attributes\Locked;
|
use Livewire\Attributes\Locked;
|
||||||
use Livewire\Attributes\Rule;
|
use Livewire\Attributes\Validate;
|
||||||
use Livewire\Component;
|
use Livewire\Component;
|
||||||
use Spatie\Url\Url;
|
use Spatie\Url\Url;
|
||||||
|
|
||||||
|
|
@ -22,37 +22,37 @@ class BackupEdit extends Component
|
||||||
#[Locked]
|
#[Locked]
|
||||||
public $parameters;
|
public $parameters;
|
||||||
|
|
||||||
#[Rule(['required', 'boolean'])]
|
#[Validate(['required', 'boolean'])]
|
||||||
public bool $delete_associated_backups_locally = false;
|
public bool $delete_associated_backups_locally = false;
|
||||||
|
|
||||||
#[Rule(['required', 'boolean'])]
|
#[Validate(['required', 'boolean'])]
|
||||||
public bool $delete_associated_backups_s3 = false;
|
public bool $delete_associated_backups_s3 = false;
|
||||||
|
|
||||||
#[Rule(['required', 'boolean'])]
|
#[Validate(['required', 'boolean'])]
|
||||||
public bool $delete_associated_backups_sftp = false;
|
public bool $delete_associated_backups_sftp = false;
|
||||||
|
|
||||||
#[Rule(['nullable', 'string'])]
|
#[Validate(['nullable', 'string'])]
|
||||||
public ?string $status = null;
|
public ?string $status = null;
|
||||||
|
|
||||||
#[Rule(['required', 'boolean'])]
|
#[Validate(['required', 'boolean'])]
|
||||||
public bool $backupEnabled = false;
|
public bool $backupEnabled = false;
|
||||||
|
|
||||||
#[Rule(['required', 'string'])]
|
#[Validate(['required', 'string'])]
|
||||||
public string $frequency = '';
|
public string $frequency = '';
|
||||||
|
|
||||||
#[Rule(['required', 'integer', 'min:1'])]
|
#[Validate(['required', 'integer', 'min:1'])]
|
||||||
public int $numberOfBackupsLocally = 1;
|
public int $numberOfBackupsLocally = 1;
|
||||||
|
|
||||||
#[Rule(['required', 'boolean'])]
|
#[Validate(['required', 'boolean'])]
|
||||||
public bool $saveS3 = false;
|
public bool $saveS3 = false;
|
||||||
|
|
||||||
#[Rule(['required', 'integer'])]
|
#[Validate(['required', 'integer'])]
|
||||||
public int $s3StorageId = 1;
|
public int $s3StorageId = 1;
|
||||||
|
|
||||||
#[Rule(['nullable', 'string'])]
|
#[Validate(['nullable', 'string'])]
|
||||||
public ?string $databasesToBackup = null;
|
public ?string $databasesToBackup = null;
|
||||||
|
|
||||||
#[Rule(['required', 'boolean'])]
|
#[Validate(['required', 'boolean'])]
|
||||||
public bool $dumpAll = false;
|
public bool $dumpAll = false;
|
||||||
|
|
||||||
public function mount()
|
public function mount()
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ use App\Models\Server;
|
||||||
use App\Models\StandaloneClickhouse;
|
use App\Models\StandaloneClickhouse;
|
||||||
use Exception;
|
use Exception;
|
||||||
use Illuminate\Support\Facades\Auth;
|
use Illuminate\Support\Facades\Auth;
|
||||||
use Livewire\Attributes\Rule;
|
use Livewire\Attributes\Validate;
|
||||||
use Livewire\Component;
|
use Livewire\Component;
|
||||||
|
|
||||||
class General extends Component
|
class General extends Component
|
||||||
|
|
@ -17,40 +17,40 @@ class General extends Component
|
||||||
|
|
||||||
public StandaloneClickhouse $database;
|
public StandaloneClickhouse $database;
|
||||||
|
|
||||||
#[Rule(['required', 'string'])]
|
#[Validate(['required', 'string'])]
|
||||||
public string $name;
|
public string $name;
|
||||||
|
|
||||||
#[Rule(['nullable', 'string'])]
|
#[Validate(['nullable', 'string'])]
|
||||||
public ?string $description = null;
|
public ?string $description = null;
|
||||||
|
|
||||||
#[Rule(['required', 'string'])]
|
#[Validate(['required', 'string'])]
|
||||||
public string $clickhouseAdminUser;
|
public string $clickhouseAdminUser;
|
||||||
|
|
||||||
#[Rule(['required', 'string'])]
|
#[Validate(['required', 'string'])]
|
||||||
public string $clickhouseAdminPassword;
|
public string $clickhouseAdminPassword;
|
||||||
|
|
||||||
#[Rule(['required', 'string'])]
|
#[Validate(['required', 'string'])]
|
||||||
public string $image;
|
public string $image;
|
||||||
|
|
||||||
#[Rule(['nullable', 'string'])]
|
#[Validate(['nullable', 'string'])]
|
||||||
public ?string $portsMappings = null;
|
public ?string $portsMappings = null;
|
||||||
|
|
||||||
#[Rule(['nullable', 'boolean'])]
|
#[Validate(['nullable', 'boolean'])]
|
||||||
public ?bool $isPublic = null;
|
public ?bool $isPublic = null;
|
||||||
|
|
||||||
#[Rule(['nullable', 'integer'])]
|
#[Validate(['nullable', 'integer'])]
|
||||||
public ?int $publicPort = null;
|
public ?int $publicPort = null;
|
||||||
|
|
||||||
#[Rule(['nullable', 'string'])]
|
#[Validate(['nullable', 'string'])]
|
||||||
public ?string $customDockerRunOptions = null;
|
public ?string $customDockerRunOptions = null;
|
||||||
|
|
||||||
#[Rule(['nullable', 'string'])]
|
#[Validate(['nullable', 'string'])]
|
||||||
public ?string $dbUrl = null;
|
public ?string $dbUrl = null;
|
||||||
|
|
||||||
#[Rule(['nullable', 'string'])]
|
#[Validate(['nullable', 'string'])]
|
||||||
public ?string $dbUrlPublic = null;
|
public ?string $dbUrlPublic = null;
|
||||||
|
|
||||||
#[Rule(['nullable', 'boolean'])]
|
#[Validate(['nullable', 'boolean'])]
|
||||||
public bool $isLogDrainEnabled = false;
|
public bool $isLogDrainEnabled = false;
|
||||||
|
|
||||||
public function getListeners()
|
public function getListeners()
|
||||||
|
|
|
||||||
|
|
@ -5,15 +5,15 @@ namespace App\Livewire\Project\Database;
|
||||||
use App\Models\ScheduledDatabaseBackup;
|
use App\Models\ScheduledDatabaseBackup;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
use Livewire\Attributes\Locked;
|
use Livewire\Attributes\Locked;
|
||||||
use Livewire\Attributes\Rule;
|
use Livewire\Attributes\Validate;
|
||||||
use Livewire\Component;
|
use Livewire\Component;
|
||||||
|
|
||||||
class CreateScheduledBackup extends Component
|
class CreateScheduledBackup extends Component
|
||||||
{
|
{
|
||||||
#[Rule(['required', 'string'])]
|
#[Validate(['required', 'string'])]
|
||||||
public $frequency;
|
public $frequency;
|
||||||
|
|
||||||
#[Rule(['required', 'boolean'])]
|
#[Validate(['required', 'boolean'])]
|
||||||
public bool $saveToS3 = false;
|
public bool $saveToS3 = false;
|
||||||
|
|
||||||
#[Locked]
|
#[Locked]
|
||||||
|
|
@ -21,7 +21,7 @@ class CreateScheduledBackup extends Component
|
||||||
|
|
||||||
public bool $enabled = true;
|
public bool $enabled = true;
|
||||||
|
|
||||||
#[Rule(['required', 'integer'])]
|
#[Validate(['required', 'integer'])]
|
||||||
public int $s3StorageId;
|
public int $s3StorageId;
|
||||||
|
|
||||||
public Collection $definedS3s;
|
public Collection $definedS3s;
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ use App\Models\Server;
|
||||||
use App\Models\StandaloneDragonfly;
|
use App\Models\StandaloneDragonfly;
|
||||||
use Exception;
|
use Exception;
|
||||||
use Illuminate\Support\Facades\Auth;
|
use Illuminate\Support\Facades\Auth;
|
||||||
use Livewire\Attributes\Rule;
|
use Livewire\Attributes\Validate;
|
||||||
use Livewire\Component;
|
use Livewire\Component;
|
||||||
|
|
||||||
class General extends Component
|
class General extends Component
|
||||||
|
|
@ -17,37 +17,37 @@ class General extends Component
|
||||||
|
|
||||||
public StandaloneDragonfly $database;
|
public StandaloneDragonfly $database;
|
||||||
|
|
||||||
#[Rule(['required', 'string'])]
|
#[Validate(['required', 'string'])]
|
||||||
public string $name;
|
public string $name;
|
||||||
|
|
||||||
#[Rule(['nullable', 'string'])]
|
#[Validate(['nullable', 'string'])]
|
||||||
public ?string $description = null;
|
public ?string $description = null;
|
||||||
|
|
||||||
#[Rule(['required', 'string'])]
|
#[Validate(['required', 'string'])]
|
||||||
public string $dragonflyPassword;
|
public string $dragonflyPassword;
|
||||||
|
|
||||||
#[Rule(['required', 'string'])]
|
#[Validate(['required', 'string'])]
|
||||||
public string $image;
|
public string $image;
|
||||||
|
|
||||||
#[Rule(['nullable', 'string'])]
|
#[Validate(['nullable', 'string'])]
|
||||||
public ?string $portsMappings = null;
|
public ?string $portsMappings = null;
|
||||||
|
|
||||||
#[Rule(['nullable', 'boolean'])]
|
#[Validate(['nullable', 'boolean'])]
|
||||||
public ?bool $isPublic = null;
|
public ?bool $isPublic = null;
|
||||||
|
|
||||||
#[Rule(['nullable', 'integer'])]
|
#[Validate(['nullable', 'integer'])]
|
||||||
public ?int $publicPort = null;
|
public ?int $publicPort = null;
|
||||||
|
|
||||||
#[Rule(['nullable', 'string'])]
|
#[Validate(['nullable', 'string'])]
|
||||||
public ?string $customDockerRunOptions = null;
|
public ?string $customDockerRunOptions = null;
|
||||||
|
|
||||||
#[Rule(['nullable', 'string'])]
|
#[Validate(['nullable', 'string'])]
|
||||||
public ?string $dbUrl = null;
|
public ?string $dbUrl = null;
|
||||||
|
|
||||||
#[Rule(['nullable', 'string'])]
|
#[Validate(['nullable', 'string'])]
|
||||||
public ?string $dbUrlPublic = null;
|
public ?string $dbUrlPublic = null;
|
||||||
|
|
||||||
#[Rule(['nullable', 'boolean'])]
|
#[Validate(['nullable', 'boolean'])]
|
||||||
public bool $isLogDrainEnabled = false;
|
public bool $isLogDrainEnabled = false;
|
||||||
|
|
||||||
public function getListeners()
|
public function getListeners()
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ namespace App\Livewire\Project\Database;
|
||||||
|
|
||||||
use Exception;
|
use Exception;
|
||||||
use Livewire\Attributes\Locked;
|
use Livewire\Attributes\Locked;
|
||||||
use Livewire\Attributes\Rule;
|
use Livewire\Attributes\Validate;
|
||||||
use Livewire\Component;
|
use Livewire\Component;
|
||||||
|
|
||||||
class InitScript extends Component
|
class InitScript extends Component
|
||||||
|
|
@ -15,10 +15,10 @@ class InitScript extends Component
|
||||||
#[Locked]
|
#[Locked]
|
||||||
public int $index;
|
public int $index;
|
||||||
|
|
||||||
#[Rule(['nullable', 'string'])]
|
#[Validate(['nullable', 'string'])]
|
||||||
public ?string $filename = null;
|
public ?string $filename = null;
|
||||||
|
|
||||||
#[Rule(['nullable', 'string'])]
|
#[Validate(['nullable', 'string'])]
|
||||||
public ?string $content = null;
|
public ?string $content = null;
|
||||||
|
|
||||||
public function mount()
|
public function mount()
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ use App\Models\Server;
|
||||||
use App\Models\StandaloneKeydb;
|
use App\Models\StandaloneKeydb;
|
||||||
use Exception;
|
use Exception;
|
||||||
use Illuminate\Support\Facades\Auth;
|
use Illuminate\Support\Facades\Auth;
|
||||||
use Livewire\Attributes\Rule;
|
use Livewire\Attributes\Validate;
|
||||||
use Livewire\Component;
|
use Livewire\Component;
|
||||||
|
|
||||||
class General extends Component
|
class General extends Component
|
||||||
|
|
@ -17,40 +17,40 @@ class General extends Component
|
||||||
|
|
||||||
public StandaloneKeydb $database;
|
public StandaloneKeydb $database;
|
||||||
|
|
||||||
#[Rule(['required', 'string'])]
|
#[Validate(['required', 'string'])]
|
||||||
public string $name;
|
public string $name;
|
||||||
|
|
||||||
#[Rule(['nullable', 'string'])]
|
#[Validate(['nullable', 'string'])]
|
||||||
public ?string $description = null;
|
public ?string $description = null;
|
||||||
|
|
||||||
#[Rule(['nullable', 'string'])]
|
#[Validate(['nullable', 'string'])]
|
||||||
public ?string $keydbConf = null;
|
public ?string $keydbConf = null;
|
||||||
|
|
||||||
#[Rule(['required', 'string'])]
|
#[Validate(['required', 'string'])]
|
||||||
public string $keydbPassword;
|
public string $keydbPassword;
|
||||||
|
|
||||||
#[Rule(['required', 'string'])]
|
#[Validate(['required', 'string'])]
|
||||||
public string $image;
|
public string $image;
|
||||||
|
|
||||||
#[Rule(['nullable', 'string'])]
|
#[Validate(['nullable', 'string'])]
|
||||||
public ?string $portsMappings = null;
|
public ?string $portsMappings = null;
|
||||||
|
|
||||||
#[Rule(['nullable', 'boolean'])]
|
#[Validate(['nullable', 'boolean'])]
|
||||||
public ?bool $isPublic = null;
|
public ?bool $isPublic = null;
|
||||||
|
|
||||||
#[Rule(['nullable', 'integer'])]
|
#[Validate(['nullable', 'integer'])]
|
||||||
public ?int $publicPort = null;
|
public ?int $publicPort = null;
|
||||||
|
|
||||||
#[Rule(['nullable', 'string'])]
|
#[Validate(['nullable', 'string'])]
|
||||||
public ?string $customDockerRunOptions = null;
|
public ?string $customDockerRunOptions = null;
|
||||||
|
|
||||||
#[Rule(['nullable', 'string'])]
|
#[Validate(['nullable', 'string'])]
|
||||||
public ?string $dbUrl = null;
|
public ?string $dbUrl = null;
|
||||||
|
|
||||||
#[Rule(['nullable', 'string'])]
|
#[Validate(['nullable', 'string'])]
|
||||||
public ?string $dbUrlPublic = null;
|
public ?string $dbUrlPublic = null;
|
||||||
|
|
||||||
#[Rule(['nullable', 'boolean'])]
|
#[Validate(['nullable', 'boolean'])]
|
||||||
public bool $isLogDrainEnabled = false;
|
public bool $isLogDrainEnabled = false;
|
||||||
|
|
||||||
public function getListeners()
|
public function getListeners()
|
||||||
|
|
|
||||||
|
|
@ -3,17 +3,17 @@
|
||||||
namespace App\Livewire\Project;
|
namespace App\Livewire\Project;
|
||||||
|
|
||||||
use App\Models\Project;
|
use App\Models\Project;
|
||||||
use Livewire\Attributes\Rule;
|
use Livewire\Attributes\Validate;
|
||||||
use Livewire\Component;
|
use Livewire\Component;
|
||||||
|
|
||||||
class Edit extends Component
|
class Edit extends Component
|
||||||
{
|
{
|
||||||
public Project $project;
|
public Project $project;
|
||||||
|
|
||||||
#[Rule(['required', 'string', 'min:3', 'max:255'])]
|
#[Validate(['required', 'string', 'min:3', 'max:255'])]
|
||||||
public string $name;
|
public string $name;
|
||||||
|
|
||||||
#[Rule(['nullable', 'string', 'max:255'])]
|
#[Validate(['nullable', 'string', 'max:255'])]
|
||||||
public ?string $description = null;
|
public ?string $description = null;
|
||||||
|
|
||||||
public function mount(string $project_uuid)
|
public function mount(string $project_uuid)
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ namespace App\Livewire\Project;
|
||||||
use App\Models\Application;
|
use App\Models\Application;
|
||||||
use App\Models\Project;
|
use App\Models\Project;
|
||||||
use Livewire\Attributes\Locked;
|
use Livewire\Attributes\Locked;
|
||||||
use Livewire\Attributes\Rule;
|
use Livewire\Attributes\Validate;
|
||||||
use Livewire\Component;
|
use Livewire\Component;
|
||||||
|
|
||||||
class EnvironmentEdit extends Component
|
class EnvironmentEdit extends Component
|
||||||
|
|
@ -17,10 +17,10 @@ class EnvironmentEdit extends Component
|
||||||
#[Locked]
|
#[Locked]
|
||||||
public $environment;
|
public $environment;
|
||||||
|
|
||||||
#[Rule(['required', 'string', 'min:3', 'max:255'])]
|
#[Validate(['required', 'string', 'min:3', 'max:255'])]
|
||||||
public string $name;
|
public string $name;
|
||||||
|
|
||||||
#[Rule(['nullable', 'string', 'max:255'])]
|
#[Validate(['nullable', 'string', 'max:255'])]
|
||||||
public ?string $description = null;
|
public ?string $description = null;
|
||||||
|
|
||||||
public function mount(string $project_uuid, string $environment_name)
|
public function mount(string $project_uuid, string $environment_name)
|
||||||
|
|
|
||||||
|
|
@ -4,17 +4,17 @@ namespace App\Livewire\Project;
|
||||||
|
|
||||||
use App\Models\Environment;
|
use App\Models\Environment;
|
||||||
use App\Models\Project;
|
use App\Models\Project;
|
||||||
use Livewire\Attributes\Rule;
|
use Livewire\Attributes\Validate;
|
||||||
use Livewire\Component;
|
use Livewire\Component;
|
||||||
|
|
||||||
class Show extends Component
|
class Show extends Component
|
||||||
{
|
{
|
||||||
public Project $project;
|
public Project $project;
|
||||||
|
|
||||||
#[Rule(['required', 'string', 'min:3'])]
|
#[Validate(['required', 'string', 'min:3'])]
|
||||||
public string $name;
|
public string $name;
|
||||||
|
|
||||||
#[Rule(['nullable', 'string'])]
|
#[Validate(['nullable', 'string'])]
|
||||||
public ?string $description = null;
|
public ?string $description = null;
|
||||||
|
|
||||||
public function mount(string $project_uuid)
|
public function mount(string $project_uuid)
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ namespace App\Livewire\Server;
|
||||||
|
|
||||||
use App\Jobs\DockerCleanupJob;
|
use App\Jobs\DockerCleanupJob;
|
||||||
use App\Models\Server;
|
use App\Models\Server;
|
||||||
use Livewire\Attributes\Rule;
|
use Livewire\Attributes\Validate;
|
||||||
use Livewire\Component;
|
use Livewire\Component;
|
||||||
|
|
||||||
class Advanced extends Component
|
class Advanced extends Component
|
||||||
|
|
@ -13,28 +13,28 @@ class Advanced extends Component
|
||||||
|
|
||||||
public array $parameters = [];
|
public array $parameters = [];
|
||||||
|
|
||||||
#[Rule(['integer', 'min:1'])]
|
#[Validate(['integer', 'min:1'])]
|
||||||
public int $concurrentBuilds = 1;
|
public int $concurrentBuilds = 1;
|
||||||
|
|
||||||
#[Rule(['integer', 'min:1'])]
|
#[Validate(['integer', 'min:1'])]
|
||||||
public int $dynamicTimeout = 1;
|
public int $dynamicTimeout = 1;
|
||||||
|
|
||||||
#[Rule('boolean')]
|
#[Validate('boolean')]
|
||||||
public bool $forceDockerCleanup = false;
|
public bool $forceDockerCleanup = false;
|
||||||
|
|
||||||
#[Rule('string')]
|
#[Validate('string')]
|
||||||
public string $dockerCleanupFrequency = '*/10 * * * *';
|
public string $dockerCleanupFrequency = '*/10 * * * *';
|
||||||
|
|
||||||
#[Rule(['integer', 'min:1', 'max:99'])]
|
#[Validate(['integer', 'min:1', 'max:99'])]
|
||||||
public int $dockerCleanupThreshold = 10;
|
public int $dockerCleanupThreshold = 10;
|
||||||
|
|
||||||
#[Rule(['integer', 'min:1', 'max:99'])]
|
#[Validate(['integer', 'min:1', 'max:99'])]
|
||||||
public int $serverDiskUsageNotificationThreshold = 50;
|
public int $serverDiskUsageNotificationThreshold = 50;
|
||||||
|
|
||||||
#[Rule('boolean')]
|
#[Validate('boolean')]
|
||||||
public bool $deleteUnusedVolumes = false;
|
public bool $deleteUnusedVolumes = false;
|
||||||
|
|
||||||
#[Rule('boolean')]
|
#[Validate('boolean')]
|
||||||
public bool $deleteUnusedNetworks = false;
|
public bool $deleteUnusedNetworks = false;
|
||||||
|
|
||||||
public function mount(string $server_uuid)
|
public function mount(string $server_uuid)
|
||||||
|
|
|
||||||
|
|
@ -3,14 +3,14 @@
|
||||||
namespace App\Livewire\Server;
|
namespace App\Livewire\Server;
|
||||||
|
|
||||||
use App\Models\Server;
|
use App\Models\Server;
|
||||||
use Livewire\Attributes\Rule;
|
use Livewire\Attributes\Validate;
|
||||||
use Livewire\Component;
|
use Livewire\Component;
|
||||||
|
|
||||||
class CloudflareTunnels extends Component
|
class CloudflareTunnels extends Component
|
||||||
{
|
{
|
||||||
public Server $server;
|
public Server $server;
|
||||||
|
|
||||||
#[Rule(['required', 'boolean'])]
|
#[Validate(['required', 'boolean'])]
|
||||||
public bool $isCloudflareTunnelsEnabled;
|
public bool $isCloudflareTunnelsEnabled;
|
||||||
|
|
||||||
public function mount(string $server_uuid)
|
public function mount(string $server_uuid)
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,6 @@ class Destinations extends Component
|
||||||
try {
|
try {
|
||||||
$this->networks = collect();
|
$this->networks = collect();
|
||||||
$this->server = Server::ownedByCurrentTeam()->whereUuid($server_uuid)->firstOrFail();
|
$this->server = Server::ownedByCurrentTeam()->whereUuid($server_uuid)->firstOrFail();
|
||||||
loggy($this->server);
|
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
return handleError($e, $this);
|
return handleError($e, $this);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,281 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Livewire\Server;
|
|
||||||
|
|
||||||
use App\Actions\Server\StartSentinel;
|
|
||||||
use App\Actions\Server\StopSentinel;
|
|
||||||
use App\Models\Server;
|
|
||||||
use Livewire\Component;
|
|
||||||
|
|
||||||
class Form extends Component
|
|
||||||
{
|
|
||||||
public Server $server;
|
|
||||||
|
|
||||||
public bool $isValidConnection = false;
|
|
||||||
|
|
||||||
public bool $isValidDocker = false;
|
|
||||||
|
|
||||||
public ?string $wildcard_domain = null;
|
|
||||||
|
|
||||||
public bool $dockerInstallationStarted = false;
|
|
||||||
|
|
||||||
public bool $revalidate = false;
|
|
||||||
|
|
||||||
public $timezones;
|
|
||||||
|
|
||||||
public $delete_unused_volumes = false;
|
|
||||||
|
|
||||||
public $delete_unused_networks = false;
|
|
||||||
|
|
||||||
public function getListeners()
|
|
||||||
{
|
|
||||||
$teamId = auth()->user()->currentTeam()->id;
|
|
||||||
|
|
||||||
return [
|
|
||||||
"echo-private:team.{$teamId},CloudflareTunnelConfigured" => 'cloudflareTunnelConfigured',
|
|
||||||
'refreshServerShow' => 'serverInstalled',
|
|
||||||
'revalidate' => '$refresh',
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
protected $rules = [
|
|
||||||
'server.name' => 'required',
|
|
||||||
'server.description' => 'nullable',
|
|
||||||
'server.ip' => 'required',
|
|
||||||
'server.user' => 'required',
|
|
||||||
'server.port' => 'required',
|
|
||||||
'wildcard_domain' => 'nullable|url',
|
|
||||||
'server.settings.is_reachable' => 'required',
|
|
||||||
'server.settings.is_swarm_manager' => 'required|boolean',
|
|
||||||
'server.settings.is_swarm_worker' => 'required|boolean',
|
|
||||||
'server.settings.is_build_server' => 'required|boolean',
|
|
||||||
'server.settings.is_metrics_enabled' => 'required|boolean',
|
|
||||||
'server.settings.sentinel_token' => 'required',
|
|
||||||
'server.settings.sentinel_metrics_refresh_rate_seconds' => 'required|integer|min:1',
|
|
||||||
'server.settings.sentinel_metrics_history_days' => 'required|integer|min:1',
|
|
||||||
'server.settings.sentinel_push_interval_seconds' => 'required|integer|min:10',
|
|
||||||
'server.settings.sentinel_custom_url' => 'nullable|url',
|
|
||||||
'server.settings.is_sentinel_enabled' => 'required|boolean',
|
|
||||||
'server.settings.is_sentinel_debug_enabled' => 'required|boolean',
|
|
||||||
'server.settings.server_timezone' => 'required|string|timezone',
|
|
||||||
];
|
|
||||||
|
|
||||||
protected $validationAttributes = [
|
|
||||||
'server.name' => 'Name',
|
|
||||||
'server.description' => 'Description',
|
|
||||||
'server.ip' => 'IP address/Domain',
|
|
||||||
'server.user' => 'User',
|
|
||||||
'server.port' => 'Port',
|
|
||||||
'server.settings.is_reachable' => 'Is reachable',
|
|
||||||
'server.settings.is_swarm_manager' => 'Swarm Manager',
|
|
||||||
'server.settings.is_swarm_worker' => 'Swarm Worker',
|
|
||||||
'server.settings.is_build_server' => 'Build Server',
|
|
||||||
'server.settings.is_metrics_enabled' => 'Metrics',
|
|
||||||
'server.settings.sentinel_token' => 'Metrics Token',
|
|
||||||
'server.settings.sentinel_metrics_refresh_rate_seconds' => 'Metrics Interval',
|
|
||||||
'server.settings.sentinel_metrics_history_days' => 'Metrics History',
|
|
||||||
'server.settings.sentinel_push_interval_seconds' => 'Push Interval',
|
|
||||||
'server.settings.is_sentinel_enabled' => 'Server API',
|
|
||||||
'server.settings.is_sentinel_debug_enabled' => 'Debug',
|
|
||||||
'server.settings.sentinel_custom_url' => 'Coolify URL',
|
|
||||||
'server.settings.server_timezone' => 'Server Timezone',
|
|
||||||
];
|
|
||||||
|
|
||||||
public function mount(Server $server)
|
|
||||||
{
|
|
||||||
$this->server = $server;
|
|
||||||
$this->timezones = collect(timezone_identifiers_list())->sort()->values()->toArray();
|
|
||||||
$this->wildcard_domain = $this->server->settings->wildcard_domain;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function checkSyncStatus()
|
|
||||||
{
|
|
||||||
$this->server->refresh();
|
|
||||||
$this->server->settings->refresh();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function regenerateSentinelToken()
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
$this->server->settings->generateSentinelToken();
|
|
||||||
$this->server->settings->refresh();
|
|
||||||
// $this->restartSentinel(notification: false);
|
|
||||||
$this->dispatch('success', 'Token regenerated & Sentinel restarted.');
|
|
||||||
} catch (\Throwable $e) {
|
|
||||||
return handleError($e, $this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function updated($field)
|
|
||||||
{
|
|
||||||
if ($field === 'server.settings.docker_cleanup_frequency') {
|
|
||||||
$frequency = $this->server->settings->docker_cleanup_frequency;
|
|
||||||
if (! validate_cron_expression($frequency)) {
|
|
||||||
$this->dispatch('error', 'Invalid Cron / Human expression for Docker Cleanup Frequency. Resetting to default 10 minutes.');
|
|
||||||
$this->server->settings->docker_cleanup_frequency = '*/10 * * * *';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function cloudflareTunnelConfigured()
|
|
||||||
{
|
|
||||||
$this->serverInstalled();
|
|
||||||
$this->dispatch('success', 'Cloudflare Tunnels configured successfully.');
|
|
||||||
}
|
|
||||||
|
|
||||||
public function serverInstalled()
|
|
||||||
{
|
|
||||||
$this->server->refresh();
|
|
||||||
$this->server->settings->refresh();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function updatedServerSettingsIsBuildServer()
|
|
||||||
{
|
|
||||||
$this->dispatch('refreshServerShow');
|
|
||||||
$this->dispatch('serverRefresh');
|
|
||||||
$this->dispatch('proxyStatusUpdated');
|
|
||||||
}
|
|
||||||
|
|
||||||
public function updatedServerSettingsIsSentinelEnabled($value)
|
|
||||||
{
|
|
||||||
$this->validate([
|
|
||||||
'server.settings.sentinel_custom_url' => 'required|url',
|
|
||||||
]);
|
|
||||||
if ($value === false) {
|
|
||||||
StopSentinel::dispatch($this->server);
|
|
||||||
$this->server->settings->is_metrics_enabled = false;
|
|
||||||
$this->server->settings->save();
|
|
||||||
$this->server->sentinelHeartbeat(isReset: true);
|
|
||||||
} else {
|
|
||||||
try {
|
|
||||||
StartSentinel::run($this->server);
|
|
||||||
} catch (\Throwable $e) {
|
|
||||||
return handleError($e, $this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function updatedServerSettingsIsMetricsEnabled()
|
|
||||||
{
|
|
||||||
$this->restartSentinel();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function updatedServerSettingsIsSentinelDebugEnabled()
|
|
||||||
{
|
|
||||||
$this->restartSentinel();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function instantSave()
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
$this->validate();
|
|
||||||
refresh_server_connection($this->server->privateKey);
|
|
||||||
$this->validateServer(false);
|
|
||||||
|
|
||||||
$this->server->settings->save();
|
|
||||||
$this->server->save();
|
|
||||||
$this->dispatch('success', 'Server updated.');
|
|
||||||
$this->dispatch('refreshServerShow');
|
|
||||||
} catch (\Throwable $e) {
|
|
||||||
$this->server->settings->refresh();
|
|
||||||
|
|
||||||
return handleError($e, $this);
|
|
||||||
} finally {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function saveSentinel()
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
$this->validate();
|
|
||||||
$this->server->settings->save();
|
|
||||||
$this->dispatch('success', 'Sentinel updated.');
|
|
||||||
} catch (\Throwable $e) {
|
|
||||||
return handleError($e, $this);
|
|
||||||
} finally {
|
|
||||||
$this->checkSyncStatus();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function restartSentinel($notification = true)
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
$this->validate();
|
|
||||||
$this->validate([
|
|
||||||
'server.settings.sentinel_custom_url' => 'required|url',
|
|
||||||
]);
|
|
||||||
$this->server->settings->save();
|
|
||||||
$this->server->restartSentinel(async: false);
|
|
||||||
if ($notification) {
|
|
||||||
$this->dispatch('success', 'Sentinel restarted.');
|
|
||||||
}
|
|
||||||
} catch (\Throwable $e) {
|
|
||||||
return handleError($e, $this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function revalidate()
|
|
||||||
{
|
|
||||||
$this->revalidate = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function checkLocalhostConnection()
|
|
||||||
{
|
|
||||||
$this->submit();
|
|
||||||
['uptime' => $uptime, 'error' => $error] = $this->server->validateConnection();
|
|
||||||
if ($uptime) {
|
|
||||||
$this->dispatch('success', 'Server is reachable.');
|
|
||||||
$this->server->settings->is_reachable = true;
|
|
||||||
$this->server->settings->is_usable = true;
|
|
||||||
$this->server->settings->save();
|
|
||||||
$this->dispatch('proxyStatusUpdated');
|
|
||||||
} else {
|
|
||||||
$this->dispatch('error', 'Server is not reachable.', 'Please validate your configuration and connection.<br><br>Check this <a target="_blank" class="underline" href="https://coolify.io/docs/knowledge-base/server/openssh">documentation</a> for further help. <br><br>Error: '.$error);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function validateServer($install = true)
|
|
||||||
{
|
|
||||||
$this->server->update([
|
|
||||||
'validation_logs' => null,
|
|
||||||
]);
|
|
||||||
$this->dispatch('init', $install);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function submit()
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
if (isCloud() && ! isDev()) {
|
|
||||||
$this->validate();
|
|
||||||
$this->validate([
|
|
||||||
'server.ip' => 'required',
|
|
||||||
]);
|
|
||||||
} else {
|
|
||||||
$this->validate();
|
|
||||||
}
|
|
||||||
$uniqueIPs = Server::all()->reject(function (Server $server) {
|
|
||||||
return $server->id === $this->server->id;
|
|
||||||
})->pluck('ip')->toArray();
|
|
||||||
if (in_array($this->server->ip, $uniqueIPs)) {
|
|
||||||
$this->dispatch('error', 'IP address is already in use by another team.');
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
refresh_server_connection($this->server->privateKey);
|
|
||||||
$this->server->settings->wildcard_domain = $this->wildcard_domain;
|
|
||||||
$currentTimezone = $this->server->settings->getOriginal('server_timezone');
|
|
||||||
$newTimezone = $this->server->settings->server_timezone;
|
|
||||||
if ($currentTimezone !== $newTimezone || $currentTimezone === '') {
|
|
||||||
$this->server->settings->server_timezone = $newTimezone;
|
|
||||||
}
|
|
||||||
$this->server->settings->save();
|
|
||||||
$this->server->save();
|
|
||||||
|
|
||||||
$this->dispatch('success', 'Server updated.');
|
|
||||||
} catch (\Throwable $e) {
|
|
||||||
return handleError($e, $this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -5,38 +5,38 @@ namespace App\Livewire\Server;
|
||||||
use App\Actions\Server\StartLogDrain;
|
use App\Actions\Server\StartLogDrain;
|
||||||
use App\Actions\Server\StopLogDrain;
|
use App\Actions\Server\StopLogDrain;
|
||||||
use App\Models\Server;
|
use App\Models\Server;
|
||||||
use Livewire\Attributes\Rule;
|
use Livewire\Attributes\Validate;
|
||||||
use Livewire\Component;
|
use Livewire\Component;
|
||||||
|
|
||||||
class LogDrains extends Component
|
class LogDrains extends Component
|
||||||
{
|
{
|
||||||
public Server $server;
|
public Server $server;
|
||||||
|
|
||||||
#[Rule(['boolean'])]
|
#[Validate(['boolean'])]
|
||||||
public bool $isLogDrainNewRelicEnabled = false;
|
public bool $isLogDrainNewRelicEnabled = false;
|
||||||
|
|
||||||
#[Rule(['boolean'])]
|
#[Validate(['boolean'])]
|
||||||
public bool $isLogDrainCustomEnabled = false;
|
public bool $isLogDrainCustomEnabled = false;
|
||||||
|
|
||||||
#[Rule(['boolean'])]
|
#[Validate(['boolean'])]
|
||||||
public bool $isLogDrainAxiomEnabled = false;
|
public bool $isLogDrainAxiomEnabled = false;
|
||||||
|
|
||||||
#[Rule(['string', 'nullable'])]
|
#[Validate(['string', 'nullable'])]
|
||||||
public ?string $logDrainNewRelicLicenseKey = null;
|
public ?string $logDrainNewRelicLicenseKey = null;
|
||||||
|
|
||||||
#[Rule(['url', 'nullable'])]
|
#[Validate(['url', 'nullable'])]
|
||||||
public ?string $logDrainNewRelicBaseUri = null;
|
public ?string $logDrainNewRelicBaseUri = null;
|
||||||
|
|
||||||
#[Rule(['string', 'nullable'])]
|
#[Validate(['string', 'nullable'])]
|
||||||
public ?string $logDrainAxiomDatasetName = null;
|
public ?string $logDrainAxiomDatasetName = null;
|
||||||
|
|
||||||
#[Rule(['string', 'nullable'])]
|
#[Validate(['string', 'nullable'])]
|
||||||
public ?string $logDrainAxiomApiKey = null;
|
public ?string $logDrainAxiomApiKey = null;
|
||||||
|
|
||||||
#[Rule(['string', 'nullable'])]
|
#[Validate(['string', 'nullable'])]
|
||||||
public ?string $logDrainCustomConfig = null;
|
public ?string $logDrainCustomConfig = null;
|
||||||
|
|
||||||
#[Rule(['string', 'nullable'])]
|
#[Validate(['string', 'nullable'])]
|
||||||
public ?string $logDrainCustomConfigParser = null;
|
public ?string $logDrainCustomConfigParser = null;
|
||||||
|
|
||||||
public function mount(string $server_uuid)
|
public function mount(string $server_uuid)
|
||||||
|
|
|
||||||
|
|
@ -5,77 +5,77 @@ namespace App\Livewire\Server;
|
||||||
use App\Actions\Server\StartSentinel;
|
use App\Actions\Server\StartSentinel;
|
||||||
use App\Actions\Server\StopSentinel;
|
use App\Actions\Server\StopSentinel;
|
||||||
use App\Models\Server;
|
use App\Models\Server;
|
||||||
use Livewire\Attributes\Rule;
|
use Livewire\Attributes\Validate;
|
||||||
use Livewire\Component;
|
use Livewire\Component;
|
||||||
|
|
||||||
class Show extends Component
|
class Show extends Component
|
||||||
{
|
{
|
||||||
public Server $server;
|
public Server $server;
|
||||||
|
|
||||||
#[Rule(['required'])]
|
#[Validate(['required'])]
|
||||||
public string $name;
|
public string $name;
|
||||||
|
|
||||||
#[Rule(['nullable'])]
|
#[Validate(['nullable'])]
|
||||||
public ?string $description;
|
public ?string $description;
|
||||||
|
|
||||||
#[Rule(['required'])]
|
#[Validate(['required'])]
|
||||||
public string $ip;
|
public string $ip;
|
||||||
|
|
||||||
#[Rule(['required'])]
|
#[Validate(['required'])]
|
||||||
public string $user;
|
public string $user;
|
||||||
|
|
||||||
#[Rule(['required'])]
|
#[Validate(['required'])]
|
||||||
public string $port;
|
public string $port;
|
||||||
|
|
||||||
#[Rule(['nullable'])]
|
#[Validate(['nullable'])]
|
||||||
public ?string $validationLogs = null;
|
public ?string $validationLogs = null;
|
||||||
|
|
||||||
#[Rule(['nullable', 'url'])]
|
#[Validate(['nullable', 'url'])]
|
||||||
public ?string $wildcardDomain;
|
public ?string $wildcardDomain;
|
||||||
|
|
||||||
#[Rule(['required'])]
|
#[Validate(['required'])]
|
||||||
public bool $isReachable;
|
public bool $isReachable;
|
||||||
|
|
||||||
#[Rule(['required'])]
|
#[Validate(['required'])]
|
||||||
public bool $isUsable;
|
public bool $isUsable;
|
||||||
|
|
||||||
#[Rule(['required'])]
|
#[Validate(['required'])]
|
||||||
public bool $isSwarmManager;
|
public bool $isSwarmManager;
|
||||||
|
|
||||||
#[Rule(['required'])]
|
#[Validate(['required'])]
|
||||||
public bool $isSwarmWorker;
|
public bool $isSwarmWorker;
|
||||||
|
|
||||||
#[Rule(['required'])]
|
#[Validate(['required'])]
|
||||||
public bool $isBuildServer;
|
public bool $isBuildServer;
|
||||||
|
|
||||||
#[Rule(['required'])]
|
#[Validate(['required'])]
|
||||||
public bool $isMetricsEnabled;
|
public bool $isMetricsEnabled;
|
||||||
|
|
||||||
#[Rule(['required'])]
|
#[Validate(['required'])]
|
||||||
public string $sentinelToken;
|
public string $sentinelToken;
|
||||||
|
|
||||||
#[Rule(['nullable'])]
|
#[Validate(['nullable'])]
|
||||||
public ?string $sentinelUpdatedAt;
|
public ?string $sentinelUpdatedAt;
|
||||||
|
|
||||||
#[Rule(['required', 'integer', 'min:1'])]
|
#[Validate(['required', 'integer', 'min:1'])]
|
||||||
public int $sentinelMetricsRefreshRateSeconds;
|
public int $sentinelMetricsRefreshRateSeconds;
|
||||||
|
|
||||||
#[Rule(['required', 'integer', 'min:1'])]
|
#[Validate(['required', 'integer', 'min:1'])]
|
||||||
public int $sentinelMetricsHistoryDays;
|
public int $sentinelMetricsHistoryDays;
|
||||||
|
|
||||||
#[Rule(['required', 'integer', 'min:10'])]
|
#[Validate(['required', 'integer', 'min:10'])]
|
||||||
public int $sentinelPushIntervalSeconds;
|
public int $sentinelPushIntervalSeconds;
|
||||||
|
|
||||||
#[Rule(['nullable', 'url'])]
|
#[Validate(['nullable', 'url'])]
|
||||||
public ?string $sentinelCustomUrl;
|
public ?string $sentinelCustomUrl;
|
||||||
|
|
||||||
#[Rule(['required'])]
|
#[Validate(['required'])]
|
||||||
public bool $isSentinelEnabled;
|
public bool $isSentinelEnabled;
|
||||||
|
|
||||||
#[Rule(['required'])]
|
#[Validate(['required'])]
|
||||||
public bool $isSentinelDebugEnabled;
|
public bool $isSentinelDebugEnabled;
|
||||||
|
|
||||||
#[Rule(['required'])]
|
#[Validate(['required'])]
|
||||||
public string $serverTimezone;
|
public string $serverTimezone;
|
||||||
|
|
||||||
public array $timezones;
|
public array $timezones;
|
||||||
|
|
@ -85,8 +85,8 @@ class Show extends Component
|
||||||
$teamId = auth()->user()->currentTeam()->id;
|
$teamId = auth()->user()->currentTeam()->id;
|
||||||
|
|
||||||
return [
|
return [
|
||||||
"echo-private:team.{$teamId},CloudflareTunnelConfigured" => '$refresh',
|
"echo-private:team.{$teamId},CloudflareTunnelConfigured" => 'refresh',
|
||||||
'refreshServerShow' => '$refresh',
|
'refreshServerShow' => 'refresh',
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -151,6 +151,12 @@ class Show extends Component
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function refresh()
|
||||||
|
{
|
||||||
|
$this->syncData();
|
||||||
|
$this->dispatch('$refresh');
|
||||||
|
}
|
||||||
|
|
||||||
public function validateServer($install = true)
|
public function validateServer($install = true)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ use App\Models\Server;
|
||||||
use Illuminate\Support\Facades\Auth;
|
use Illuminate\Support\Facades\Auth;
|
||||||
use Illuminate\Support\Facades\Hash;
|
use Illuminate\Support\Facades\Hash;
|
||||||
use Livewire\Attributes\Locked;
|
use Livewire\Attributes\Locked;
|
||||||
use Livewire\Attributes\Rule;
|
use Livewire\Attributes\Validate;
|
||||||
use Livewire\Component;
|
use Livewire\Component;
|
||||||
|
|
||||||
class Index extends Component
|
class Index extends Component
|
||||||
|
|
@ -20,58 +20,58 @@ class Index extends Component
|
||||||
#[Locked]
|
#[Locked]
|
||||||
public $timezones;
|
public $timezones;
|
||||||
|
|
||||||
#[Rule('boolean')]
|
#[Validate('boolean')]
|
||||||
public bool $is_auto_update_enabled;
|
public bool $is_auto_update_enabled;
|
||||||
|
|
||||||
#[Rule('nullable|string|max:255')]
|
#[Validate('nullable|string|max:255')]
|
||||||
public ?string $fqdn = null;
|
public ?string $fqdn = null;
|
||||||
|
|
||||||
#[Rule('nullable|string|max:255')]
|
#[Validate('nullable|string|max:255')]
|
||||||
public ?string $resale_license = null;
|
public ?string $resale_license = null;
|
||||||
|
|
||||||
#[Rule('required|integer|min:1025|max:65535')]
|
#[Validate('required|integer|min:1025|max:65535')]
|
||||||
public int $public_port_min;
|
public int $public_port_min;
|
||||||
|
|
||||||
#[Rule('required|integer|min:1025|max:65535')]
|
#[Validate('required|integer|min:1025|max:65535')]
|
||||||
public int $public_port_max;
|
public int $public_port_max;
|
||||||
|
|
||||||
#[Rule('nullable|string')]
|
#[Validate('nullable|string')]
|
||||||
public ?string $custom_dns_servers = null;
|
public ?string $custom_dns_servers = null;
|
||||||
|
|
||||||
#[Rule('nullable|string|max:255')]
|
#[Validate('nullable|string|max:255')]
|
||||||
public ?string $instance_name = null;
|
public ?string $instance_name = null;
|
||||||
|
|
||||||
#[Rule('nullable|string')]
|
#[Validate('nullable|string')]
|
||||||
public ?string $allowed_ips = null;
|
public ?string $allowed_ips = null;
|
||||||
|
|
||||||
#[Rule('nullable|string')]
|
#[Validate('nullable|string')]
|
||||||
public ?string $public_ipv4 = null;
|
public ?string $public_ipv4 = null;
|
||||||
|
|
||||||
#[Rule('nullable|string')]
|
#[Validate('nullable|string')]
|
||||||
public ?string $public_ipv6 = null;
|
public ?string $public_ipv6 = null;
|
||||||
|
|
||||||
#[Rule('string')]
|
#[Validate('string')]
|
||||||
public string $auto_update_frequency;
|
public string $auto_update_frequency;
|
||||||
|
|
||||||
#[Rule('string')]
|
#[Validate('string')]
|
||||||
public string $update_check_frequency;
|
public string $update_check_frequency;
|
||||||
|
|
||||||
#[Rule('required|string|timezone')]
|
#[Validate('required|string|timezone')]
|
||||||
public string $instance_timezone;
|
public string $instance_timezone;
|
||||||
|
|
||||||
#[Rule('boolean')]
|
#[Validate('boolean')]
|
||||||
public bool $do_not_track;
|
public bool $do_not_track;
|
||||||
|
|
||||||
#[Rule('boolean')]
|
#[Validate('boolean')]
|
||||||
public bool $is_registration_enabled;
|
public bool $is_registration_enabled;
|
||||||
|
|
||||||
#[Rule('boolean')]
|
#[Validate('boolean')]
|
||||||
public bool $is_dns_validation_enabled;
|
public bool $is_dns_validation_enabled;
|
||||||
|
|
||||||
#[Rule('boolean')]
|
#[Validate('boolean')]
|
||||||
public bool $is_api_enabled;
|
public bool $is_api_enabled;
|
||||||
|
|
||||||
#[Rule('boolean')]
|
#[Validate('boolean')]
|
||||||
public bool $disable_two_step_confirmation;
|
public bool $disable_two_step_confirmation;
|
||||||
|
|
||||||
public function render()
|
public function render()
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ use App\Models\ScheduledDatabaseBackup;
|
||||||
use App\Models\Server;
|
use App\Models\Server;
|
||||||
use App\Models\StandalonePostgresql;
|
use App\Models\StandalonePostgresql;
|
||||||
use Livewire\Attributes\Locked;
|
use Livewire\Attributes\Locked;
|
||||||
use Livewire\Attributes\Rule;
|
use Livewire\Attributes\Validate;
|
||||||
use Livewire\Component;
|
use Livewire\Component;
|
||||||
|
|
||||||
class SettingsBackup extends Component
|
class SettingsBackup extends Component
|
||||||
|
|
@ -25,19 +25,19 @@ class SettingsBackup extends Component
|
||||||
#[Locked]
|
#[Locked]
|
||||||
public $executions = [];
|
public $executions = [];
|
||||||
|
|
||||||
#[Rule(['required'])]
|
#[Validate(['required'])]
|
||||||
public string $uuid;
|
public string $uuid;
|
||||||
|
|
||||||
#[Rule(['required'])]
|
#[Validate(['required'])]
|
||||||
public string $name;
|
public string $name;
|
||||||
|
|
||||||
#[Rule(['nullable'])]
|
#[Validate(['nullable'])]
|
||||||
public ?string $description = null;
|
public ?string $description = null;
|
||||||
|
|
||||||
#[Rule(['required'])]
|
#[Validate(['required'])]
|
||||||
public string $postgres_user;
|
public string $postgres_user;
|
||||||
|
|
||||||
#[Rule(['required'])]
|
#[Validate(['required'])]
|
||||||
public string $postgres_password;
|
public string $postgres_password;
|
||||||
|
|
||||||
public function mount()
|
public function mount()
|
||||||
|
|
|
||||||
|
|
@ -3,44 +3,44 @@
|
||||||
namespace App\Livewire;
|
namespace App\Livewire;
|
||||||
|
|
||||||
use App\Models\InstanceSettings;
|
use App\Models\InstanceSettings;
|
||||||
use Livewire\Attributes\Rule;
|
use Livewire\Attributes\Validate;
|
||||||
use Livewire\Component;
|
use Livewire\Component;
|
||||||
|
|
||||||
class SettingsEmail extends Component
|
class SettingsEmail extends Component
|
||||||
{
|
{
|
||||||
public InstanceSettings $settings;
|
public InstanceSettings $settings;
|
||||||
|
|
||||||
#[Rule(['boolean'])]
|
#[Validate(['boolean'])]
|
||||||
public bool $smtpEnabled = false;
|
public bool $smtpEnabled = false;
|
||||||
|
|
||||||
#[Rule(['nullable', 'string'])]
|
#[Validate(['nullable', 'string'])]
|
||||||
public ?string $smtpHost = null;
|
public ?string $smtpHost = null;
|
||||||
|
|
||||||
#[Rule(['nullable', 'numeric', 'min:1', 'max:65535'])]
|
#[Validate(['nullable', 'numeric', 'min:1', 'max:65535'])]
|
||||||
public ?int $smtpPort = null;
|
public ?int $smtpPort = null;
|
||||||
|
|
||||||
#[Rule(['nullable', 'string'])]
|
#[Validate(['nullable', 'string'])]
|
||||||
public ?string $smtpEncryption = null;
|
public ?string $smtpEncryption = null;
|
||||||
|
|
||||||
#[Rule(['nullable', 'string'])]
|
#[Validate(['nullable', 'string'])]
|
||||||
public ?string $smtpUsername = null;
|
public ?string $smtpUsername = null;
|
||||||
|
|
||||||
#[Rule(['nullable'])]
|
#[Validate(['nullable'])]
|
||||||
public ?string $smtpPassword = null;
|
public ?string $smtpPassword = null;
|
||||||
|
|
||||||
#[Rule(['nullable', 'numeric'])]
|
#[Validate(['nullable', 'numeric'])]
|
||||||
public ?int $smtpTimeout = null;
|
public ?int $smtpTimeout = null;
|
||||||
|
|
||||||
#[Rule(['nullable', 'email'])]
|
#[Validate(['nullable', 'email'])]
|
||||||
public ?string $smtpFromAddress = null;
|
public ?string $smtpFromAddress = null;
|
||||||
|
|
||||||
#[Rule(['nullable', 'string'])]
|
#[Validate(['nullable', 'string'])]
|
||||||
public ?string $smtpFromName = null;
|
public ?string $smtpFromName = null;
|
||||||
|
|
||||||
#[Rule(['boolean'])]
|
#[Validate(['boolean'])]
|
||||||
public bool $resendEnabled = false;
|
public bool $resendEnabled = false;
|
||||||
|
|
||||||
#[Rule(['nullable', 'string'])]
|
#[Validate(['nullable', 'string'])]
|
||||||
public ?string $resendApiKey = null;
|
public ?string $resendApiKey = null;
|
||||||
|
|
||||||
public function mount()
|
public function mount()
|
||||||
|
|
|
||||||
|
|
@ -1,82 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Livewire\Tags;
|
|
||||||
|
|
||||||
use App\Http\Controllers\Api\DeployController;
|
|
||||||
use App\Models\Tag;
|
|
||||||
use Illuminate\Support\Collection;
|
|
||||||
use Livewire\Attributes\Title;
|
|
||||||
use Livewire\Attributes\Url;
|
|
||||||
use Livewire\Component;
|
|
||||||
|
|
||||||
#[Title('Tags | Coolify')]
|
|
||||||
class Index extends Component
|
|
||||||
{
|
|
||||||
#[Url()]
|
|
||||||
public ?string $tag = null;
|
|
||||||
|
|
||||||
public Collection $tags;
|
|
||||||
|
|
||||||
public Collection $applications;
|
|
||||||
|
|
||||||
public Collection $services;
|
|
||||||
|
|
||||||
public $webhook = null;
|
|
||||||
|
|
||||||
public $deploymentsPerTagPerServer = [];
|
|
||||||
|
|
||||||
protected $listeners = ['deployments' => 'updateDeployments'];
|
|
||||||
|
|
||||||
public function render()
|
|
||||||
{
|
|
||||||
return view('livewire.tags.index');
|
|
||||||
}
|
|
||||||
|
|
||||||
public function mount()
|
|
||||||
{
|
|
||||||
$this->tags = Tag::ownedByCurrentTeam()->get()->unique('name')->sortBy('name');
|
|
||||||
if ($this->tag) {
|
|
||||||
$this->tagUpdated();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function updateDeployments($deployments)
|
|
||||||
{
|
|
||||||
$this->deploymentsPerTagPerServer = $deployments;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function tagUpdated()
|
|
||||||
{
|
|
||||||
if ($this->tag === '') {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
$sanitizedTag = htmlspecialchars($this->tag, ENT_QUOTES, 'UTF-8');
|
|
||||||
$tag = $this->tags->where('name', $sanitizedTag)->first();
|
|
||||||
if (! $tag) {
|
|
||||||
$this->dispatch('error', 'Tag ('.e($sanitizedTag).') not found.');
|
|
||||||
$this->tag = '';
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
$this->webhook = generateTagDeployWebhook($tag->name);
|
|
||||||
$this->applications = $tag->applications()->get();
|
|
||||||
$this->services = $tag->services()->get();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function redeployAll()
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
$this->applications->each(function ($resource) {
|
|
||||||
$deploy = new DeployController;
|
|
||||||
$deploy->deploy_resource($resource);
|
|
||||||
});
|
|
||||||
$this->services->each(function ($resource) {
|
|
||||||
$deploy = new DeployController;
|
|
||||||
$deploy->deploy_resource($resource);
|
|
||||||
});
|
|
||||||
$this->dispatch('success', 'Mass deployment started.');
|
|
||||||
} catch (\Exception $e) {
|
|
||||||
return handleError($e, $this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -5,43 +5,57 @@ namespace App\Livewire\Tags;
|
||||||
use App\Http\Controllers\Api\DeployController;
|
use App\Http\Controllers\Api\DeployController;
|
||||||
use App\Models\ApplicationDeploymentQueue;
|
use App\Models\ApplicationDeploymentQueue;
|
||||||
use App\Models\Tag;
|
use App\Models\Tag;
|
||||||
|
use Illuminate\Support\Collection;
|
||||||
|
use Livewire\Attributes\Locked;
|
||||||
use Livewire\Attributes\Title;
|
use Livewire\Attributes\Title;
|
||||||
use Livewire\Component;
|
use Livewire\Component;
|
||||||
|
|
||||||
#[Title('Tags | Coolify')]
|
#[Title('Tags | Coolify')]
|
||||||
class Show extends Component
|
class Show extends Component
|
||||||
{
|
{
|
||||||
public $tags;
|
#[Locked]
|
||||||
|
public ?string $tagName = null;
|
||||||
|
|
||||||
public Tag $tag;
|
#[Locked]
|
||||||
|
public ?Collection $tags = null;
|
||||||
|
|
||||||
public $applications;
|
#[Locked]
|
||||||
|
public ?Tag $tag = null;
|
||||||
|
|
||||||
public $services;
|
#[Locked]
|
||||||
|
public ?Collection $applications = null;
|
||||||
|
|
||||||
public $webhook = null;
|
#[Locked]
|
||||||
|
public ?Collection $services = null;
|
||||||
|
|
||||||
public $deployments_per_tag_per_server = [];
|
#[Locked]
|
||||||
|
public ?string $webhook = null;
|
||||||
|
|
||||||
|
#[Locked]
|
||||||
|
public ?array $deploymentsPerTagPerServer = null;
|
||||||
|
|
||||||
public function mount()
|
public function mount()
|
||||||
{
|
{
|
||||||
$this->tags = Tag::ownedByCurrentTeam()->get()->unique('name')->sortBy('name');
|
try {
|
||||||
$tag = $this->tags->where('name', request()->tag_name)->first();
|
$this->tags = Tag::ownedByCurrentTeam()->get()->unique('name')->sortBy('name');
|
||||||
if (! $tag) {
|
if (str($this->tagName)->isNotEmpty()) {
|
||||||
return redirect()->route('tags.index');
|
$tag = $this->tags->where('name', $this->tagName)->first();
|
||||||
|
$this->webhook = generateTagDeployWebhook($tag->name);
|
||||||
|
$this->applications = $tag->applications()->get();
|
||||||
|
$this->services = $tag->services()->get();
|
||||||
|
$this->tag = $tag;
|
||||||
|
$this->getDeployments();
|
||||||
|
}
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
return handleError($e, $this);
|
||||||
}
|
}
|
||||||
$this->webhook = generateTagDeployWebhook($tag->name);
|
|
||||||
$this->applications = $tag->applications()->get();
|
|
||||||
$this->services = $tag->services()->get();
|
|
||||||
$this->tag = $tag;
|
|
||||||
$this->get_deployments();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function get_deployments()
|
public function getDeployments()
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
$resource_ids = $this->applications->pluck('id');
|
$resource_ids = $this->applications->pluck('id');
|
||||||
$this->deployments_per_tag_per_server = ApplicationDeploymentQueue::whereIn('status', ['in_progress', 'queued'])->whereIn('application_id', $resource_ids)->get([
|
$this->deploymentsPerTagPerServer = ApplicationDeploymentQueue::whereIn('status', ['in_progress', 'queued'])->whereIn('application_id', $resource_ids)->get([
|
||||||
'id',
|
'id',
|
||||||
'application_id',
|
'application_id',
|
||||||
'application_name',
|
'application_name',
|
||||||
|
|
@ -56,7 +70,7 @@ class Show extends Component
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function redeploy_all()
|
public function redeployAll()
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
$message = collect([]);
|
$message = collect([]);
|
||||||
|
|
|
||||||
|
|
@ -3,28 +3,21 @@
|
||||||
namespace App\Livewire\Team;
|
namespace App\Livewire\Team;
|
||||||
|
|
||||||
use App\Models\Team;
|
use App\Models\Team;
|
||||||
|
use Livewire\Attributes\Validate;
|
||||||
use Livewire\Component;
|
use Livewire\Component;
|
||||||
|
|
||||||
class Create extends Component
|
class Create extends Component
|
||||||
{
|
{
|
||||||
|
#[Validate(['required', 'min:3', 'max:255'])]
|
||||||
public string $name = '';
|
public string $name = '';
|
||||||
|
|
||||||
|
#[Validate(['nullable', 'min:3', 'max:255'])]
|
||||||
public ?string $description = null;
|
public ?string $description = null;
|
||||||
|
|
||||||
protected $rules = [
|
|
||||||
'name' => 'required|min:3|max:255',
|
|
||||||
'description' => 'nullable|min:3|max:255',
|
|
||||||
];
|
|
||||||
|
|
||||||
protected $validationAttributes = [
|
|
||||||
'name' => 'name',
|
|
||||||
'description' => 'description',
|
|
||||||
];
|
|
||||||
|
|
||||||
public function submit()
|
public function submit()
|
||||||
{
|
{
|
||||||
$this->validate();
|
|
||||||
try {
|
try {
|
||||||
|
$this->validate();
|
||||||
$team = Team::create([
|
$team = Team::create([
|
||||||
'name' => $this->name,
|
'name' => $this->name,
|
||||||
'description' => $this->description,
|
'description' => $this->description,
|
||||||
|
|
|
||||||
|
|
@ -974,10 +974,10 @@ $schema://$host {
|
||||||
|
|
||||||
public function serverStatus(): bool
|
public function serverStatus(): bool
|
||||||
{
|
{
|
||||||
if ($this->isFunctional() === false) {
|
if ($this->status() === false) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if ($this->status() === false) {
|
if ($this->isFunctional() === false) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -986,9 +986,6 @@ $schema://$host {
|
||||||
|
|
||||||
public function status(): bool
|
public function status(): bool
|
||||||
{
|
{
|
||||||
if ($this->isFunctional() === false) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
['uptime' => $uptime] = $this->validateConnection(false);
|
['uptime' => $uptime] = $this->validateConnection(false);
|
||||||
if ($uptime === false) {
|
if ($uptime === false) {
|
||||||
foreach ($this->applications() as $application) {
|
foreach ($this->applications() as $application) {
|
||||||
|
|
@ -1232,7 +1229,7 @@ $schema://$host {
|
||||||
return str($this->ip)->contains(':');
|
return str($this->ip)->contains(':');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function restartSentinel(bool $async = true): void
|
public function restartSentinel(bool $async = true)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
if ($async) {
|
if ($async) {
|
||||||
|
|
@ -1241,7 +1238,7 @@ $schema://$host {
|
||||||
StartSentinel::run($this, true);
|
StartSentinel::run($this, true);
|
||||||
}
|
}
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
loggy('Error restarting Sentinel: '.$e->getMessage());
|
return handleError($e, $this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ namespace App\Models;
|
||||||
|
|
||||||
use Illuminate\Database\Eloquent\Casts\Attribute;
|
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
use OpenApi\Attributes as OA;
|
use OpenApi\Attributes as OA;
|
||||||
|
|
||||||
#[OA\Schema(
|
#[OA\Schema(
|
||||||
|
|
@ -69,7 +70,7 @@ class ServerSetting extends Model
|
||||||
$setting->generateSentinelUrl(save: false);
|
$setting->generateSentinelUrl(save: false);
|
||||||
}
|
}
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
loggy('Error creating server setting: '.$e->getMessage());
|
Log::error('Error creating server setting: '.$e->getMessage());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
static::updated(function ($settings) {
|
static::updated(function ($settings) {
|
||||||
|
|
|
||||||
|
|
@ -165,7 +165,7 @@ class Team extends Model implements SendsDiscord, SendsEmail
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return data_get($team, 'limits.serverLimit', 0);
|
return data_get($team, 'limits', 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function limits(): Attribute
|
public function limits(): Attribute
|
||||||
|
|
@ -187,9 +187,8 @@ class Team extends Model implements SendsDiscord, SendsEmail
|
||||||
} else {
|
} else {
|
||||||
$serverLimit = config('constants.limits.server')[strtolower($subscription)];
|
$serverLimit = config('constants.limits.server')[strtolower($subscription)];
|
||||||
}
|
}
|
||||||
$sharedEmailEnabled = config('constants.limits.email')[strtolower($subscription)];
|
|
||||||
|
|
||||||
return ['serverLimit' => $serverLimit, 'sharedEmailEnabled' => $sharedEmailEnabled];
|
return $serverLimit ?? 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,6 @@ class DiscordChannel
|
||||||
if (! $webhookUrl) {
|
if (! $webhookUrl) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
dispatch(new SendMessageToDiscordJob($message, $webhookUrl));
|
dispatch(new SendMessageToDiscordJob($message, $webhookUrl))->onQueue('high');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -41,6 +41,6 @@ class TelegramChannel
|
||||||
if (! $telegramToken || ! $chatId || ! $message) {
|
if (! $telegramToken || ! $chatId || ! $message) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
dispatch(new SendMessageToTelegramJob($message, $buttons, $telegramToken, $chatId, $topicId));
|
dispatch(new SendMessageToTelegramJob($message, $buttons, $telegramToken, $chatId, $topicId))->onQueue('high');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -91,7 +91,7 @@ function next_queuable(string $server_id, string $application_id): bool
|
||||||
$server = Server::find($server_id);
|
$server = Server::find($server_id);
|
||||||
$concurrent_builds = $server->settings->concurrent_builds;
|
$concurrent_builds = $server->settings->concurrent_builds;
|
||||||
|
|
||||||
ray("serverId:{$server->id}", "concurrentBuilds:{$concurrent_builds}", "deployments:{$deployments->count()}", "sameApplicationDeployments:{$same_application_deployments->count()}")->green();
|
// ray("serverId:{$server->id}", "concurrentBuilds:{$concurrent_builds}", "deployments:{$deployments->count()}", "sameApplicationDeployments:{$same_application_deployments->count()}")->green();
|
||||||
|
|
||||||
if ($deployments->count() > $concurrent_builds) {
|
if ($deployments->count() > $concurrent_builds) {
|
||||||
return false;
|
return false;
|
||||||
|
|
|
||||||
|
|
@ -654,7 +654,7 @@ function isDatabaseImage(?string $image = null)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
function convert_docker_run_to_compose(?string $custom_docker_run_options = null)
|
function convertDockerRunToCompose(?string $custom_docker_run_options = null)
|
||||||
{
|
{
|
||||||
$options = [];
|
$options = [];
|
||||||
$compose_options = collect([]);
|
$compose_options = collect([]);
|
||||||
|
|
@ -679,9 +679,17 @@ function convert_docker_run_to_compose(?string $custom_docker_run_options = null
|
||||||
'--privileged' => 'privileged',
|
'--privileged' => 'privileged',
|
||||||
'--ip' => 'ip',
|
'--ip' => 'ip',
|
||||||
'--shm-size' => 'shm_size',
|
'--shm-size' => 'shm_size',
|
||||||
|
'--gpus' => 'gpus',
|
||||||
]);
|
]);
|
||||||
foreach ($matches as $match) {
|
foreach ($matches as $match) {
|
||||||
$option = $match[1];
|
$option = $match[1];
|
||||||
|
if ($option === '--gpus') {
|
||||||
|
$regexForParsingDeviceIds = '/device=([0-9A-Za-z-,]+)/';
|
||||||
|
preg_match($regexForParsingDeviceIds, $custom_docker_run_options, $device_matches);
|
||||||
|
$value = $device_matches[1] ?? 'all';
|
||||||
|
$options[$option][] = $value;
|
||||||
|
$options[$option] = array_unique($options[$option]);
|
||||||
|
}
|
||||||
if (isset($match[2]) && $match[2] !== '') {
|
if (isset($match[2]) && $match[2] !== '') {
|
||||||
$value = $match[2];
|
$value = $match[2];
|
||||||
$options[$option][] = $value;
|
$options[$option][] = $value;
|
||||||
|
|
@ -694,7 +702,6 @@ function convert_docker_run_to_compose(?string $custom_docker_run_options = null
|
||||||
$options = collect($options);
|
$options = collect($options);
|
||||||
// Easily get mappings from https://github.com/composerize/composerize/blob/master/packages/composerize/src/mappings.js
|
// Easily get mappings from https://github.com/composerize/composerize/blob/master/packages/composerize/src/mappings.js
|
||||||
foreach ($options as $option => $value) {
|
foreach ($options as $option => $value) {
|
||||||
// ray($option,$value);
|
|
||||||
if (! data_get($mapping, $option)) {
|
if (! data_get($mapping, $option)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
@ -723,6 +730,28 @@ function convert_docker_run_to_compose(?string $custom_docker_run_options = null
|
||||||
if (! is_null($value) && is_array($value) && count($value) > 0) {
|
if (! is_null($value) && is_array($value) && count($value) > 0) {
|
||||||
$compose_options->put($mapping[$option], $value[0]);
|
$compose_options->put($mapping[$option], $value[0]);
|
||||||
}
|
}
|
||||||
|
} elseif ($option === '--gpus') {
|
||||||
|
$payload = [
|
||||||
|
'driver' => 'nvidia',
|
||||||
|
'capabilities' => ['gpu'],
|
||||||
|
];
|
||||||
|
if (! is_null($value) && is_array($value) && count($value) > 0) {
|
||||||
|
if (str($value[0]) != 'all') {
|
||||||
|
if (str($value[0])->contains(',')) {
|
||||||
|
$payload['device_ids'] = str($value[0])->explode(',')->toArray();
|
||||||
|
} else {
|
||||||
|
$payload['device_ids'] = [$value[0]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ray($payload);
|
||||||
|
$compose_options->put('deploy', [
|
||||||
|
'resources' => [
|
||||||
|
'reservations' => [
|
||||||
|
'devices' => [$payload],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
]);
|
||||||
} else {
|
} else {
|
||||||
if ($list_options->contains($option)) {
|
if ($list_options->contains($option)) {
|
||||||
if ($compose_options->has($mapping[$option])) {
|
if ($compose_options->has($mapping[$option])) {
|
||||||
|
|
@ -744,7 +773,7 @@ function convert_docker_run_to_compose(?string $custom_docker_run_options = null
|
||||||
return $compose_options->toArray();
|
return $compose_options->toArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
function generate_custom_docker_run_options_for_databases($docker_run_options, $docker_compose, $container_name, $network)
|
function generateCustomDockerRunOptionsForDatabases($docker_run_options, $docker_compose, $container_name, $network)
|
||||||
{
|
{
|
||||||
$ipv4 = data_get($docker_run_options, 'ip.0');
|
$ipv4 = data_get($docker_run_options, 'ip.0');
|
||||||
$ipv6 = data_get($docker_run_options, 'ip6.0');
|
$ipv6 = data_get($docker_run_options, 'ip6.0');
|
||||||
|
|
|
||||||
|
|
@ -106,7 +106,7 @@ function currentTeam()
|
||||||
|
|
||||||
function showBoarding(): bool
|
function showBoarding(): bool
|
||||||
{
|
{
|
||||||
if (Auth::user()->isMember()) {
|
if (Auth::user()?->isMember()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
return [
|
return [
|
||||||
|
'docker_install_version' => '26.0',
|
||||||
'docs' => [
|
'docs' => [
|
||||||
'base_url' => 'https://coolify.io/docs',
|
'base_url' => 'https://coolify.io/docs',
|
||||||
'contact' => 'https://coolify.io/docs/contact',
|
'contact' => 'https://coolify.io/docs/contact',
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ use App\Models\Server;
|
||||||
use Illuminate\Database\Migrations\Migration;
|
use Illuminate\Database\Migrations\Migration;
|
||||||
use Illuminate\Database\Schema\Blueprint;
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
use Illuminate\Support\Facades\DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
use Illuminate\Support\Facades\Schema;
|
use Illuminate\Support\Facades\Schema;
|
||||||
use Visus\Cuid2\Cuid2;
|
use Visus\Cuid2\Cuid2;
|
||||||
|
|
||||||
|
|
@ -52,7 +53,7 @@ return new class extends Migration
|
||||||
|
|
||||||
DB::table('server_settings')->update(['metrics_history_days' => 7]);
|
DB::table('server_settings')->update(['metrics_history_days' => 7]);
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
loggy($e);
|
Log::error('Error updating db: '.$e->getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ namespace Database\Seeders;
|
||||||
|
|
||||||
use App\Models\Server;
|
use App\Models\Server;
|
||||||
use Illuminate\Database\Seeder;
|
use Illuminate\Database\Seeder;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
|
||||||
class SentinelSeeder extends Seeder
|
class SentinelSeeder extends Seeder
|
||||||
{
|
{
|
||||||
|
|
@ -23,7 +24,7 @@ class SentinelSeeder extends Seeder
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
loggy("Error: {$e->getMessage()}\n");
|
Log::error('Error seeding sentinel: '.$e->getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -45,6 +45,8 @@ RUN composer dump-autoload
|
||||||
COPY --from=static-assets --chown=9999:9999 /app/public/build ./public/build
|
COPY --from=static-assets --chown=9999:9999 /app/public/build ./public/build
|
||||||
COPY --chmod=755 docker/prod/etc/s6-overlay/ /etc/s6-overlay/
|
COPY --chmod=755 docker/prod/etc/s6-overlay/ /etc/s6-overlay/
|
||||||
|
|
||||||
|
RUN php artisan route:clear
|
||||||
|
RUN php artisan view:clear
|
||||||
RUN php artisan route:cache
|
RUN php artisan route:cache
|
||||||
RUN php artisan view:cache
|
RUN php artisan view:cache
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ set -e # Exit immediately if a command exits with a non-zero status
|
||||||
## $1 could be empty, so we need to disable this check
|
## $1 could be empty, so we need to disable this check
|
||||||
#set -u # Treat unset variables as an error and exit
|
#set -u # Treat unset variables as an error and exit
|
||||||
set -o pipefail # Cause a pipeline to return the status of the last command that exited with a non-zero status
|
set -o pipefail # Cause a pipeline to return the status of the last command that exited with a non-zero status
|
||||||
CDN="https://cdn.coollabs.io/coolify-nightly"
|
CDN="https://cdn.coollabs.io/coolify"
|
||||||
DATE=$(date +"%Y%m%d-%H%M%S")
|
DATE=$(date +"%Y%m%d-%H%M%S")
|
||||||
|
|
||||||
VERSION="1.6"
|
VERSION="1.6"
|
||||||
|
|
@ -13,7 +13,7 @@ DOCKER_VERSION="26.0"
|
||||||
# TODO: Ask for a user
|
# TODO: Ask for a user
|
||||||
CURRENT_USER=$USER
|
CURRENT_USER=$USER
|
||||||
|
|
||||||
mkdir -p /data/coolify/{source,ssh,applications,databases,backups,services,proxy,webhooks-during-maintenance,metrics,logs}
|
mkdir -p /data/coolify/{source,ssh,applications,databases,backups,services,proxy,webhooks-during-maintenance,sentinel}
|
||||||
mkdir -p /data/coolify/ssh/{keys,mux}
|
mkdir -p /data/coolify/ssh/{keys,mux}
|
||||||
mkdir -p /data/coolify/proxy/dynamic
|
mkdir -p /data/coolify/proxy/dynamic
|
||||||
|
|
||||||
|
|
@ -164,7 +164,6 @@ sles | opensuse-leap | opensuse-tumbleweed)
|
||||||
esac
|
esac
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
echo -e "2. Check OpenSSH server configuration. "
|
echo -e "2. Check OpenSSH server configuration. "
|
||||||
|
|
||||||
# Detect OpenSSH server
|
# Detect OpenSSH server
|
||||||
|
|
@ -262,9 +261,14 @@ if ! [ -x "$(command -v docker)" ]; then
|
||||||
fi
|
fi
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
curl -s https://releases.rancher.com/install-docker/${DOCKER_VERSION}.sh | sh >/dev/null 2>&1
|
if [ "$OS_TYPE" = "ubuntu" ] && [ "$OS_VERSION" = "24.10" ]; then
|
||||||
|
echo "Docker automated installation is not supported on Ubuntu 24.10 (non-LTS release)."
|
||||||
|
echo "Please install Docker manually."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
curl -s https://releases.rancher.com/install-docker/${DOCKER_VERSION}.sh | sh 2>&1
|
||||||
if ! [ -x "$(command -v docker)" ]; then
|
if ! [ -x "$(command -v docker)" ]; then
|
||||||
curl -s https://get.docker.com | sh -s -- --version ${DOCKER_VERSION} >/dev/null 2>&1
|
curl -s https://get.docker.com | sh -s -- --version ${DOCKER_VERSION} 2>&1
|
||||||
if ! [ -x "$(command -v docker)" ]; then
|
if ! [ -x "$(command -v docker)" ]; then
|
||||||
echo " - Docker installation failed."
|
echo " - Docker installation failed."
|
||||||
echo " Maybe your OS is not supported?"
|
echo " Maybe your OS is not supported?"
|
||||||
|
|
@ -404,10 +408,10 @@ if [ ! -f ~/.ssh/authorized_keys ]; then
|
||||||
fi
|
fi
|
||||||
|
|
||||||
set +e
|
set +e
|
||||||
IF_COOLIFY_VOLUME_EXISTS=$(docker volume ls | grep coolify-db | wc -l)
|
IS_COOLIFY_VOLUME_EXISTS=$(docker volume ls | grep coolify-db | wc -l)
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
if [ "$IF_COOLIFY_VOLUME_EXISTS" -eq 0 ]; then
|
if [ "$IS_COOLIFY_VOLUME_EXISTS" -eq 0 ]; then
|
||||||
echo " - Generating SSH key."
|
echo " - Generating SSH key."
|
||||||
ssh-keygen -t ed25519 -a 100 -f /data/coolify/ssh/keys/id.$CURRENT_USER@host.docker.internal -q -N "" -C coolify
|
ssh-keygen -t ed25519 -a 100 -f /data/coolify/ssh/keys/id.$CURRENT_USER@host.docker.internal -q -N "" -C coolify
|
||||||
chown 9999 /data/coolify/ssh/keys/id.$CURRENT_USER@host.docker.internal
|
chown 9999 /data/coolify/ssh/keys/id.$CURRENT_USER@host.docker.internal
|
||||||
|
|
@ -424,7 +428,7 @@ echo -e " - It could take a while based on your server's performance, network sp
|
||||||
echo -e " - Please wait."
|
echo -e " - Please wait."
|
||||||
getAJoke
|
getAJoke
|
||||||
|
|
||||||
bash /data/coolify/source/upgrade.sh "${LATEST_VERSION:-latest}" "${LATEST_HELPER_VERSION:-latest}" >/dev/null 2>&1
|
bash /data/coolify/source/upgrade.sh "${LATEST_VERSION:-latest}" "${LATEST_HELPER_VERSION:-latest}"
|
||||||
echo " - Coolify installed successfully."
|
echo " - Coolify installed successfully."
|
||||||
rm -f $ENV_FILE-$DATE
|
rm -f $ENV_FILE-$DATE
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -215,7 +215,7 @@
|
||||||
<li>
|
<li>
|
||||||
<a title="Tags"
|
<a title="Tags"
|
||||||
class="{{ request()->is('tags*') ? 'menu-item-active menu-item' : 'menu-item' }}"
|
class="{{ request()->is('tags*') ? 'menu-item-active menu-item' : 'menu-item' }}"
|
||||||
href="{{ route('tags.index') }}">
|
href="{{ route('tags.show') }}">
|
||||||
<svg class="icon" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
<svg class="icon" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||||
<g fill="none" stroke="currentColor" stroke-linecap="round"
|
<g fill="none" stroke="currentColor" stroke-linecap="round"
|
||||||
stroke-linejoin="round" stroke-width="2">
|
stroke-linejoin="round" stroke-width="2">
|
||||||
|
|
|
||||||
|
|
@ -3,15 +3,15 @@
|
||||||
<div class="subtitle">Get notified about your infrastructure.</div>
|
<div class="subtitle">Get notified about your infrastructure.</div>
|
||||||
<div class="navbar-main">
|
<div class="navbar-main">
|
||||||
<nav class="flex items-center gap-6 min-h-10">
|
<nav class="flex items-center gap-6 min-h-10">
|
||||||
<a class="{{ request()->routeIs('notifications.email') ? 'dark:text-white' : '' }}"
|
<a wire:navigate class="{{ request()->routeIs('notifications.email') ? 'dark:text-white' : '' }}"
|
||||||
href="{{ route('notifications.email') }}">
|
href="{{ route('notifications.email') }}">
|
||||||
<button>Email</button>
|
<button>Email</button>
|
||||||
</a>
|
</a>
|
||||||
<a class="{{ request()->routeIs('notifications.telegram') ? 'dark:text-white' : '' }}"
|
<a wire:navigate class="{{ request()->routeIs('notifications.telegram') ? 'dark:text-white' : '' }}"
|
||||||
href="{{ route('notifications.telegram') }}">
|
href="{{ route('notifications.telegram') }}">
|
||||||
<button>Telegram</button>
|
<button>Telegram</button>
|
||||||
</a>
|
</a>
|
||||||
<a class="{{ request()->routeIs('notifications.discord') ? 'dark:text-white' : '' }}"
|
<a wire:navigate class="{{ request()->routeIs('notifications.discord') ? 'dark:text-white' : '' }}"
|
||||||
href="{{ route('notifications.discord') }}">
|
href="{{ route('notifications.discord') }}">
|
||||||
<button>Discord</button>
|
<button>Discord</button>
|
||||||
</a>
|
</a>
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@
|
||||||
@endif
|
@endif
|
||||||
</div>
|
</div>
|
||||||
<div class="w-32">
|
<div class="w-32">
|
||||||
<x-forms.checkbox instantSave id="discordEnabled" label="Enabled" />
|
<x-forms.checkbox instantSave="instantSaveDiscordEnabled" id="discordEnabled" label="Enabled" />
|
||||||
</div>
|
</div>
|
||||||
<x-forms.input type="password"
|
<x-forms.input type="password"
|
||||||
helper="Generate a webhook in Discord.<br>Example: https://discord.com/api/webhooks/...." required
|
helper="Generate a webhook in Discord.<br>Example: https://discord.com/api/webhooks/...." required
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@
|
||||||
<x-forms.button type="submit">
|
<x-forms.button type="submit">
|
||||||
Save
|
Save
|
||||||
</x-forms.button>
|
</x-forms.button>
|
||||||
@if (isInstanceAdmin() && !$team->use_instance_email_settings)
|
@if (isInstanceAdmin() && !$useInstanceEmailSettings)
|
||||||
<x-forms.button wire:click='copyFromInstanceSettings'>
|
<x-forms.button wire:click='copyFromInstanceSettings'>
|
||||||
Copy from Instance Settings
|
Copy from Instance Settings
|
||||||
</x-forms.button>
|
</x-forms.button>
|
||||||
|
|
@ -25,99 +25,90 @@
|
||||||
</x-modal-input>
|
</x-modal-input>
|
||||||
@endif
|
@endif
|
||||||
</div>
|
</div>
|
||||||
</form>
|
@if (!isCloud())
|
||||||
@if (isCloud())
|
<div class="w-96">
|
||||||
@if ($this->sharedEmailEnabled)
|
<x-forms.checkbox instantSave="instantSaveInstance" id="useInstanceEmailSettings"
|
||||||
<div class="w-64 py-4">
|
label="Use system wide (transactional) email settings" />
|
||||||
<x-forms.checkbox instantSave="instantSaveInstance" id="team.use_instance_email_settings"
|
|
||||||
label="Use Hosted Email Service" />
|
|
||||||
</div>
|
|
||||||
@else
|
|
||||||
<div class="w-96 pb-4">
|
|
||||||
<x-forms.checkbox disabled id="team.use_instance_email_settings"
|
|
||||||
label="Use Hosted Email Service (Pro+ subscription required)" />
|
|
||||||
</div>
|
</div>
|
||||||
@endif
|
@endif
|
||||||
@else
|
@if (!$useInstanceEmailSettings)
|
||||||
<div class="w-96">
|
<div class="flex gap-4">
|
||||||
<x-forms.checkbox instantSave="instantSaveInstance" id="team.use_instance_email_settings"
|
<x-forms.input required id="smtpFromName" helper="Name used in emails." label="From Name" />
|
||||||
label="Use system wide (transactional) email settings" />
|
<x-forms.input required id="smtpFromAddress" helper="Email address used in emails."
|
||||||
|
label="From Address" />
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
</form>
|
||||||
|
@if (isCloud())
|
||||||
|
<div class="w-64 py-4">
|
||||||
|
<x-forms.checkbox instantSave="instantSaveInstance" id="useInstanceEmailSettings"
|
||||||
|
label="Use Hosted Email Service" />
|
||||||
</div>
|
</div>
|
||||||
@endif
|
@endif
|
||||||
@if (!$team->use_instance_email_settings)
|
@if (!$useInstanceEmailSettings)
|
||||||
<form class="flex flex-col items-end gap-2 pt-4 pb-4 xl:flex-row" wire:submit='submitFromFields'>
|
|
||||||
<x-forms.input required id="team.smtp_from_name" helper="Name used in emails." label="From Name" />
|
|
||||||
<x-forms.input required id="team.smtp_from_address" helper="Email address used in emails."
|
|
||||||
label="From Address" />
|
|
||||||
<x-forms.button type="submit">
|
|
||||||
Save
|
|
||||||
</x-forms.button>
|
|
||||||
</form>
|
|
||||||
<div class="flex flex-col gap-4">
|
<div class="flex flex-col gap-4">
|
||||||
<div class="p-4 border dark:border-coolgray-300">
|
<form wire:submit='submit' class="p-4 border dark:border-coolgray-300 flex flex-col gap-2">
|
||||||
<h3>SMTP Server</h3>
|
<div class="flex items-center gap-2">
|
||||||
<div class="w-32">
|
<h3>SMTP Server</h3>
|
||||||
<x-forms.checkbox instantSave id="team.smtp_enabled" label="Enabled" />
|
<x-forms.button type="submit">
|
||||||
|
Save
|
||||||
|
</x-forms.button>
|
||||||
</div>
|
</div>
|
||||||
<form wire:submit='submit' class="flex flex-col">
|
<div class="w-32">
|
||||||
|
<x-forms.checkbox instantSave="instantSaveSmtpEnabled" id="smtpEnabled" label="Enabled" />
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col">
|
||||||
<div class="flex flex-col gap-4">
|
<div class="flex flex-col gap-4">
|
||||||
<div class="flex flex-col w-full gap-2 xl:flex-row">
|
<div class="flex flex-col w-full gap-2 xl:flex-row">
|
||||||
<x-forms.input required id="team.smtp_host" placeholder="smtp.mailgun.org" label="Host" />
|
<x-forms.input required id="smtpHost" placeholder="smtp.mailgun.org" label="Host" />
|
||||||
<x-forms.input required id="team.smtp_port" placeholder="587" label="Port" />
|
<x-forms.input required id="smtpPort" placeholder="587" label="Port" />
|
||||||
<x-forms.input id="team.smtp_encryption" helper="If SMTP uses SSL, set it to 'tls'."
|
<x-forms.input id="smtpEncryption" helper="If SMTP uses SSL, set it to 'tls'."
|
||||||
placeholder="tls" label="Encryption" />
|
placeholder="tls" label="Encryption" />
|
||||||
</div>
|
</div>
|
||||||
<div class="flex flex-col w-full gap-2 xl:flex-row">
|
<div class="flex flex-col w-full gap-2 xl:flex-row">
|
||||||
<x-forms.input id="team.smtp_username" label="SMTP Username" />
|
<x-forms.input id="smtpUsername" label="SMTP Username" />
|
||||||
<x-forms.input id="team.smtp_password" type="password" label="SMTP Password" />
|
<x-forms.input id="smtpPassword" type="password" label="SMTP Password" />
|
||||||
<x-forms.input id="team.smtp_timeout" helper="Timeout value for sending emails."
|
<x-forms.input id="smtpTimeout" helper="Timeout value for sending emails."
|
||||||
label="Timeout" />
|
label="Timeout" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex justify-end gap-4 pt-6">
|
|
||||||
<x-forms.button type="submit">
|
|
||||||
Save
|
|
||||||
</x-forms.button>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
<div class="p-4 border dark:border-coolgray-300">
|
|
||||||
<h3>Resend</h3>
|
|
||||||
<div class="w-32">
|
|
||||||
<x-forms.checkbox instantSave='instantSaveResend' id="team.resend_enabled" label="Enabled" />
|
|
||||||
</div>
|
</div>
|
||||||
<form wire:submit='submitResend' class="flex flex-col">
|
</form>
|
||||||
|
<form wire:submit='submit' class="p-4 border dark:border-coolgray-300 flex flex-col gap-2">
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<h3>Resend</h3>
|
||||||
|
<x-forms.button type="submit">
|
||||||
|
Save
|
||||||
|
</x-forms.button>
|
||||||
|
</div>
|
||||||
|
<div class="w-32">
|
||||||
|
<x-forms.checkbox instantSave='instantSaveResend' id="resendEnabled" label="Enabled" />
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col">
|
||||||
<div class="flex flex-col gap-4">
|
<div class="flex flex-col gap-4">
|
||||||
<div class="flex flex-col w-full gap-2 xl:flex-row">
|
<div class="flex flex-col w-full gap-2 xl:flex-row">
|
||||||
<x-forms.input required type="password" id="team.resend_api_key" placeholder="API key"
|
<x-forms.input required type="password" id="resendApiKey" placeholder="API key"
|
||||||
label="API Key" />
|
label="API Key" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex justify-end gap-4 pt-6">
|
</div>
|
||||||
<x-forms.button type="submit">
|
</form>
|
||||||
Save
|
|
||||||
</x-forms.button>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
@endif
|
@endif
|
||||||
@if (isEmailEnabled($team) || data_get($team, 'use_instance_email_settings'))
|
@if (isEmailEnabled($team) || $useInstanceEmailSettings)
|
||||||
<h2 class="mt-4">Subscribe to events</h2>
|
<h2 class="mt-4">Subscribe to events</h2>
|
||||||
<div class="w-64">
|
<div class="w-64">
|
||||||
@if (isDev())
|
@if (isDev())
|
||||||
<x-forms.checkbox instantSave="saveModel" id="team.smtp_notifications_test" label="Test" />
|
<x-forms.checkbox instantSave="saveModel" id="smtpNotificationsTest" label="Test" />
|
||||||
@endif
|
@endif
|
||||||
<x-forms.checkbox instantSave="saveModel" id="team.smtp_notifications_status_changes"
|
<x-forms.checkbox instantSave="saveModel" id="smtpNotificationsStatusChanges"
|
||||||
label="Container Status Changes" />
|
label="Container Status Changes" />
|
||||||
<x-forms.checkbox instantSave="saveModel" id="team.smtp_notifications_deployments"
|
<x-forms.checkbox instantSave="saveModel" id="smtpNotificationsDeployments"
|
||||||
label="Application Deployments" />
|
label="Application Deployments" />
|
||||||
<x-forms.checkbox instantSave="saveModel" id="team.smtp_notifications_database_backups"
|
<x-forms.checkbox instantSave="saveModel" id="smtpNotificationsDatabaseBackups" label="Backup Status" />
|
||||||
label="Backup Status" />
|
<x-forms.checkbox instantSave="saveModel" id="smtpNotificationsScheduledTasks"
|
||||||
<x-forms.checkbox instantSave="saveModel" id="team.smtp_notifications_scheduled_tasks"
|
|
||||||
label="Scheduled Tasks Status" />
|
label="Scheduled Tasks Status" />
|
||||||
<x-forms.checkbox instantSave="saveModel" id="team.smtp_notifications_server_disk_usage"
|
<x-forms.checkbox instantSave="saveModel" id="smtpNotificationsServerDiskUsage" label="Server Disk Usage" />
|
||||||
label="Server Disk Usage" />
|
|
||||||
</div>
|
</div>
|
||||||
@endif
|
@endif
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@
|
||||||
<x-forms.button type="submit">
|
<x-forms.button type="submit">
|
||||||
Save
|
Save
|
||||||
</x-forms.button>
|
</x-forms.button>
|
||||||
@if ($team->telegram_enabled)
|
@if ($telegramEnabled)
|
||||||
<x-forms.button class="normal-case dark:text-white btn btn-xs no-animation btn-primary"
|
<x-forms.button class="normal-case dark:text-white btn btn-xs no-animation btn-primary"
|
||||||
wire:click="sendTestNotification">
|
wire:click="sendTestNotification">
|
||||||
Send Test Notifications
|
Send Test Notifications
|
||||||
|
|
@ -17,64 +17,61 @@
|
||||||
@endif
|
@endif
|
||||||
</div>
|
</div>
|
||||||
<div class="w-32">
|
<div class="w-32">
|
||||||
<x-forms.checkbox instantSave id="team.telegram_enabled" label="Enabled" />
|
<x-forms.checkbox instantSave="instantSaveTelegramEnabled" id="telegramEnabled" label="Enabled" />
|
||||||
</div>
|
</div>
|
||||||
<div class="flex gap-2">
|
<div class="flex gap-2">
|
||||||
|
|
||||||
<x-forms.input type="password" autocomplete="new-password"
|
<x-forms.input type="password" autocomplete="new-password"
|
||||||
helper="Get it from the <a class='inline-block underline dark:text-white' href='https://t.me/botfather' target='_blank'>BotFather Bot</a> on Telegram."
|
helper="Get it from the <a class='inline-block underline dark:text-white' href='https://t.me/botfather' target='_blank'>BotFather Bot</a> on Telegram."
|
||||||
required id="team.telegram_token" label="Token" />
|
required id="telegramToken" label="Token" />
|
||||||
<x-forms.input helper="Recommended to add your bot to a group chat and add its Chat ID here." required
|
<x-forms.input helper="Recommended to add your bot to a group chat and add its Chat ID here." required
|
||||||
id="team.telegram_chat_id" label="Chat ID" />
|
id="telegramChatId" label="Chat ID" />
|
||||||
</div>
|
</div>
|
||||||
@if (data_get($team, 'telegram_enabled'))
|
@if ($telegramEnabled)
|
||||||
<h2 class="mt-4">Subscribe to events</h2>
|
<h2 class="mt-4">Subscribe to events</h2>
|
||||||
<div class="flex flex-col gap-4 w-96">
|
<div class="flex flex-col gap-4 w-96">
|
||||||
@if (isDev())
|
@if (isDev())
|
||||||
<div class="flex flex-col">
|
<div class="flex flex-col">
|
||||||
<h4>Test Notification</h4>
|
<h4>Test Notification</h4>
|
||||||
<x-forms.checkbox instantSave="saveModel" id="team.telegram_notifications_test"
|
<x-forms.checkbox instantSave="saveModel" id="telegramNotificationsTest" label="Enabled" />
|
||||||
label="Enabled" />
|
|
||||||
<x-forms.input
|
<x-forms.input
|
||||||
helper="If you are using Group chat with Topics, you can specify the topics ID. If empty, General topic will be used."
|
helper="If you are using Group chat with Topics, you can specify the topics ID. If empty, General topic will be used."
|
||||||
id="team.telegram_notifications_test_message_thread_id" label="Custom Topic ID" />
|
id="telegramNotificationsTestMessageThreadId" label="Custom Topic ID" />
|
||||||
</div>
|
</div>
|
||||||
@endif
|
@endif
|
||||||
<div class="flex flex-col">
|
<div class="flex flex-col">
|
||||||
<h4>Container Status Changes</h4>
|
<h4>Container Status Changes</h4>
|
||||||
<x-forms.checkbox instantSave="saveModel" id="team.telegram_notifications_status_changes"
|
<x-forms.checkbox instantSave="saveModel" id="telegramNotificationsStatusChanges" label="Enabled" />
|
||||||
label="Enabled" />
|
|
||||||
<x-forms.input
|
<x-forms.input
|
||||||
helper="If you are using Group chat with Topics, you can specify the topics ID. If empty, General topic will be used."
|
helper="If you are using Group chat with Topics, you can specify the topics ID. If empty, General topic will be used."
|
||||||
id="team.telegram_notifications_status_changes_message_thread_id" label="Custom Topic ID" />
|
id="telegramNotificationsStatusChangesMessageThreadId" label="Custom Topic ID" />
|
||||||
</div>
|
</div>
|
||||||
<div class="flex flex-col">
|
<div class="flex flex-col">
|
||||||
<h4>Application Deployments</h4>
|
<h4>Application Deployments</h4>
|
||||||
<x-forms.checkbox instantSave="saveModel" id="team.telegram_notifications_deployments"
|
<x-forms.checkbox instantSave="saveModel" id="telegramNotificationsDeployments" label="Enabled" />
|
||||||
label="Enabled" />
|
|
||||||
<x-forms.input
|
<x-forms.input
|
||||||
helper="If you are using Group chat with Topics, you can specify the topics ID. If empty, General topic will be used."
|
helper="If you are using Group chat with Topics, you can specify the topics ID. If empty, General topic will be used."
|
||||||
id="team.telegram_notifications_deployments_message_thread_id" label="Custom Topic ID" />
|
id="telegramNotificationsDeploymentsMessageThreadId" label="Custom Topic ID" />
|
||||||
</div>
|
</div>
|
||||||
<div class="flex flex-col">
|
<div class="flex flex-col">
|
||||||
<h4>Database Backup Status</h4>
|
<h4>Database Backup Status</h4>
|
||||||
<x-forms.checkbox instantSave="saveModel" id="team.telegram_notifications_database_backups"
|
<x-forms.checkbox instantSave="saveModel" id="telegramNotificationsDatabaseBackups"
|
||||||
label="Enabled" />
|
label="Enabled" />
|
||||||
<x-forms.input
|
<x-forms.input
|
||||||
helper="If you are using Group chat with Topics, you can specify the topics ID. If empty, General topic will be used."
|
helper="If you are using Group chat with Topics, you can specify the topics ID. If empty, General topic will be used."
|
||||||
id="team.telegram_notifications_database_backups_message_thread_id" label="Custom Topic ID" />
|
id="telegramNotificationsDatabaseBackupsMessageThreadId" label="Custom Topic ID" />
|
||||||
</div>
|
</div>
|
||||||
<div class="flex flex-col">
|
<div class="flex flex-col">
|
||||||
<h4>Scheduled Tasks Status</h4>
|
<h4>Scheduled Tasks Status</h4>
|
||||||
<x-forms.checkbox instantSave="saveModel" id="team.telegram_notifications_scheduled_tasks"
|
<x-forms.checkbox instantSave="saveModel" id="telegramNotificationsScheduledTasks"
|
||||||
label="Enabled" />
|
label="Enabled" />
|
||||||
<x-forms.input
|
<x-forms.input
|
||||||
helper="If you are using Group chat with Topics, you can specify the topics ID. If empty, General topic will be used."
|
helper="If you are using Group chat with Topics, you can specify the topics ID. If empty, General topic will be used."
|
||||||
id="team.telegram_notifications_scheduled_tasks_thread_id" label="Custom Topic ID" />
|
id="telegramNotificationsScheduledTasksMessageThreadId" label="Custom Topic ID" />
|
||||||
</div>
|
</div>
|
||||||
<div class="flex flex-col">
|
<div class="flex flex-col">
|
||||||
<h4>Server Disk Usage</h4>
|
<h4>Server Disk Usage</h4>
|
||||||
<x-forms.checkbox instantSave="saveModel" id="team.telegram_notifications_server_disk_usage"
|
<x-forms.checkbox instantSave="saveModel" id="telegramNotificationsServerDiskUsage"
|
||||||
label="Enabled" />
|
label="Enabled" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -8,90 +8,86 @@
|
||||||
<h3>General</h3>
|
<h3>General</h3>
|
||||||
@if ($application->git_based())
|
@if ($application->git_based())
|
||||||
<x-forms.checkbox helper="Automatically deploy new commits based on Git webhooks." instantSave
|
<x-forms.checkbox helper="Automatically deploy new commits based on Git webhooks." instantSave
|
||||||
id="application.settings.is_auto_deploy_enabled" label="Auto Deploy" />
|
id="isAutoDeployEnabled" label="Auto Deploy" />
|
||||||
<x-forms.checkbox
|
<x-forms.checkbox
|
||||||
helper="Allow to automatically deploy Preview Deployments for all opened PR's.<br><br>Closing a PR will delete Preview Deployments."
|
helper="Allow to automatically deploy Preview Deployments for all opened PR's.<br><br>Closing a PR will delete Preview Deployments."
|
||||||
instantSave id="application.settings.is_preview_deployments_enabled" label="Preview Deployments" />
|
instantSave id="isPreviewDeploymentsEnabled" label="Preview Deployments" />
|
||||||
@endif
|
@endif
|
||||||
<x-forms.checkbox
|
<x-forms.checkbox
|
||||||
helper="Your application will be available only on https if your domain starts with https://..."
|
helper="Your application will be available only on https if your domain starts with https://..."
|
||||||
instantSave id="is_force_https_enabled" label="Force Https" />
|
instantSave id="isForceHttpsEnabled" label="Force Https" />
|
||||||
<x-forms.checkbox label="Enable Gzip Compression"
|
<x-forms.checkbox label="Enable Gzip Compression"
|
||||||
helper="You can disable gzip compression if you want. Some services are compressing data by default. In this case, you do not need this."
|
helper="You can disable gzip compression if you want. Some services are compressing data by default. In this case, you do not need this."
|
||||||
instantSave id="is_gzip_enabled" />
|
instantSave id="isGzipEnabled" />
|
||||||
<x-forms.checkbox helper="Strip Prefix is used to remove prefixes from paths. Like /api/ to /api."
|
<x-forms.checkbox helper="Strip Prefix is used to remove prefixes from paths. Like /api/ to /api."
|
||||||
instantSave id="is_stripprefix_enabled" label="Strip Prefixes" />
|
instantSave id="isStripprefixEnabled" label="Strip Prefixes" />
|
||||||
@if ($application->build_pack === 'dockercompose')
|
@if ($application->build_pack === 'dockercompose')
|
||||||
<h3>Docker Compose</h3>
|
<h3>Docker Compose</h3>
|
||||||
<x-forms.checkbox instantSave id="application.settings.is_raw_compose_deployment_enabled"
|
<x-forms.checkbox instantSave id="isRawComposeDeploymentEnabled" label="Raw Compose Deployment"
|
||||||
label="Raw Compose Deployment"
|
|
||||||
helper="WARNING: Advanced use cases only. Your docker compose file will be deployed as-is. Nothing is modified by Coolify. You need to configure the proxy parts. More info in the <a class='underline dark:text-white' href='https://coolify.io/docs/knowledge-base/docker/compose#raw-docker-compose-deployment'>documentation.</a>" />
|
helper="WARNING: Advanced use cases only. Your docker compose file will be deployed as-is. Nothing is modified by Coolify. You need to configure the proxy parts. More info in the <a class='underline dark:text-white' href='https://coolify.io/docs/knowledge-base/docker/compose#raw-docker-compose-deployment'>documentation.</a>" />
|
||||||
@endif
|
@endif
|
||||||
<h3>Container Names</h3>
|
<h3 class="pt-4">Container Names</h3>
|
||||||
<x-forms.checkbox
|
<x-forms.checkbox
|
||||||
helper="The deployed container will have the same name ({{ $application->uuid }}). <span class='font-bold dark:text-warning'>You will lose the rolling update feature!</span>"
|
helper="The deployed container will have the same name ({{ $application->uuid }}). <span class='font-bold dark:text-warning'>You will lose the rolling update feature!</span>"
|
||||||
instantSave id="application.settings.is_consistent_container_name_enabled"
|
instantSave id="isConsistentContainerNameEnabled" label="Consistent Container Names" />
|
||||||
label="Consistent Container Names" />
|
@if ($isConsistentContainerNameEnabled === false)
|
||||||
@if (!$application->settings->is_consistent_container_name_enabled)
|
<form class="flex items-end gap-2 " wire:submit.prevent='saveCustomName'>
|
||||||
<form class="flex items-end gap-2 pl-2" wire:submit.prevent='saveCustomName'>
|
|
||||||
<x-forms.input
|
<x-forms.input
|
||||||
helper="You can add a custom name for your container.<br><br>The name will be converted to slug format when you save it. <span class='font-bold dark:text-warning'>You will lose the rolling update feature!</span>"
|
helper="You can add a custom name for your container.<br><br>The name will be converted to slug format when you save it. <span class='font-bold dark:text-warning'>You will lose the rolling update feature!</span>"
|
||||||
instantSave id="application.settings.custom_internal_name" label="Custom Container Name" />
|
instantSave id="customInternalName" label="Custom Container Name" />
|
||||||
<x-forms.button type="submit">Save</x-forms.button>
|
<x-forms.button type="submit">Save</x-forms.button>
|
||||||
</form>
|
</form>
|
||||||
@endif
|
@endif
|
||||||
@if ($application->build_pack === 'dockercompose')
|
@if ($application->build_pack === 'dockercompose')
|
||||||
<h3>Network</h3>
|
<h3 class="pt-4">Network</h3>
|
||||||
<x-forms.checkbox instantSave id="application.settings.connect_to_docker_network"
|
<x-forms.checkbox instantSave id="isConnectToDockerNetworkEnabled" label="Connect To Predefined Network"
|
||||||
label="Connect To Predefined Network"
|
|
||||||
helper="By default, you do not reach the Coolify defined networks.<br>Starting a docker compose based resource will have an internal network. <br>If you connect to a Coolify defined network, you maybe need to use different internal DNS names to connect to a resource.<br><br>For more information, check <a class='underline dark:text-white' target='_blank' href='https://coolify.io/docs/knowledge-base/docker/compose#connect-to-predefined-networks'>this</a>." />
|
helper="By default, you do not reach the Coolify defined networks.<br>Starting a docker compose based resource will have an internal network. <br>If you connect to a Coolify defined network, you maybe need to use different internal DNS names to connect to a resource.<br><br>For more information, check <a class='underline dark:text-white' target='_blank' href='https://coolify.io/docs/knowledge-base/docker/compose#connect-to-predefined-networks'>this</a>." />
|
||||||
@endif
|
@endif
|
||||||
@if (!$application->settings->is_raw_compose_deployment_enabled)
|
@if ($isLogDrainEnabled === false)
|
||||||
<h3>Logs</h3>
|
<h3 class="pt-4">Logs</h3>
|
||||||
<x-forms.checkbox helper="Drain logs to your configured log drain endpoint in your Server settings."
|
<x-forms.checkbox helper="Drain logs to your configured log drain endpoint in your Server settings."
|
||||||
instantSave id="application.settings.is_log_drain_enabled" label="Drain Logs" />
|
instantSave id="isLogDrainEnabled" label="Drain Logs" />
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
@if ($application->git_based())
|
@if ($application->git_based())
|
||||||
<h3>Git</h3>
|
<h3>Git</h3>
|
||||||
<x-forms.checkbox instantSave id="application.settings.is_git_submodules_enabled" label="Submodules"
|
<x-forms.checkbox instantSave id="isGitSubmodulesEnabled" label="Submodules"
|
||||||
helper="Allow Git Submodules during build process." />
|
helper="Allow Git Submodules during build process." />
|
||||||
<x-forms.checkbox instantSave id="application.settings.is_git_lfs_enabled" label="LFS"
|
<x-forms.checkbox instantSave id="isGitLfsEnabled" label="LFS"
|
||||||
helper="Allow Git LFS during build process." />
|
helper="Allow Git LFS during build process." />
|
||||||
@endif
|
@endif
|
||||||
{{-- <x-forms.checkbox disabled instantSave id="is_dual_cert" label="Dual Certs?" />
|
|
||||||
<x-forms.checkbox disabled instantSave id="is_custom_ssl" label="Is Custom SSL?" />
|
|
||||||
<x-forms.checkbox disabled instantSave id="is_http2" label="Is Http2?" /> --}}
|
|
||||||
</div>
|
</div>
|
||||||
@if ($application->build_pack !== 'dockercompose')
|
|
||||||
<h3>GPU</h3>
|
|
||||||
@endif
|
|
||||||
<form wire:submit="submit">
|
|
||||||
@if ($application->build_pack !== 'dockercompose')
|
|
||||||
<x-forms.checkbox
|
|
||||||
helper="Enable GPU usage for this application. More info <a href='https://docs.docker.com/compose/gpu-support/' class='underline dark:text-white' target='_blank'>here</a>."
|
|
||||||
instantSave id="application.settings.is_gpu_enabled" label="Attach GPU" />
|
|
||||||
@if ($application->settings->is_gpu_enabled)
|
|
||||||
<h5>GPU Settings</h5>
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<form wire:submit="submit" class="flex flex-col gap-2">
|
||||||
|
@if ($application->build_pack !== 'dockercompose')
|
||||||
|
<div class="flex gap-2 items-end pt-4">
|
||||||
|
<h3>GPU</h3>
|
||||||
|
@if ($isGpuEnabled)
|
||||||
<x-forms.button type="submit">Save</x-forms.button>
|
<x-forms.button type="submit">Save</x-forms.button>
|
||||||
@endif
|
@endif
|
||||||
@endif
|
</div>
|
||||||
@if ($application->settings->is_gpu_enabled)
|
@endif
|
||||||
<div class="flex flex-col w-full gap-2 p-2 xl:flex-row">
|
@if ($application->build_pack !== 'dockercompose')
|
||||||
<x-forms.input label="GPU Driver" id="application.settings.gpu_driver"> </x-forms.input>
|
<div class="md:w-96 pb-4">
|
||||||
<x-forms.input label="GPU Count" placeholder="empty means use all GPUs"
|
<x-forms.checkbox
|
||||||
id="application.settings.gpu_count"> </x-forms.input>
|
helper="Enable GPU usage for this application. More info <a href='https://docs.docker.com/compose/gpu-support/' class='underline dark:text-white' target='_blank'>here</a>."
|
||||||
<x-forms.input label="GPU Device Ids" placeholder="0,2"
|
instantSave id="isGpuEnabled" label="Enable GPU" />
|
||||||
helper="Comma separated list of device ids. More info <a href='https://docs.docker.com/compose/gpu-support/#access-specific-devices' class='underline dark:text-white' target='_blank'>here</a>."
|
</div>
|
||||||
id="application.settings.gpu_device_ids"> </x-forms.input>
|
@endif
|
||||||
|
@if ($isGpuEnabled)
|
||||||
|
<div class="flex flex-col w-full gap-2 ">
|
||||||
|
<div class="flex gap-2 items-end">
|
||||||
|
<x-forms.input label="GPU Driver" id="gpuDriver"> </x-forms.input>
|
||||||
|
<x-forms.input label="GPU Count" placeholder="empty means use all GPUs" id="gpuCount">
|
||||||
|
</x-forms.input>
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
<x-forms.input label="GPU Device Ids" placeholder="0,2"
|
||||||
<div class="px-2">
|
helper="Comma separated list of device ids. More info <a href='https://docs.docker.com/compose/gpu-support/#access-specific-devices' class='underline dark:text-white' target='_blank'>here</a>."
|
||||||
<x-forms.textarea label="GPU Options" id="application.settings.gpu_options">
|
id="gpuDeviceIds"> </x-forms.input>
|
||||||
</x-forms.textarea>
|
<x-forms.textarea rows="10" label="GPU Options" id="gpuOptions"> </x-forms.textarea>
|
||||||
</div>
|
</div>
|
||||||
@endif
|
@endif
|
||||||
</form>
|
</form>
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
<x-forms.input placeholder="0 0 * * * or daily" id="frequency"
|
<x-forms.input placeholder="0 0 * * * or daily" id="frequency"
|
||||||
helper="You can use every_minute, hourly, daily, weekly, monthly, yearly or a cron expression." label="Frequency"
|
helper="You can use every_minute, hourly, daily, weekly, monthly, yearly or a cron expression." label="Frequency"
|
||||||
required />
|
required />
|
||||||
|
<h2>S3</h2>
|
||||||
@if ($definedS3s->count() === 0)
|
@if ($definedS3s->count() === 0)
|
||||||
<div class="text-red-500">No validated S3 Storages found.</div>
|
<div class="text-red-500">No validated S3 Storages found.</div>
|
||||||
@else
|
@else
|
||||||
|
|
|
||||||
|
|
@ -1,226 +0,0 @@
|
||||||
<div>
|
|
||||||
<form wire:submit.prevent='submit' class="flex flex-col">
|
|
||||||
<div class="flex gap-2">
|
|
||||||
<h2>General</h2>
|
|
||||||
@if ($server->id === 0)
|
|
||||||
<x-modal-confirmation title="Confirm Server Settings Change?" buttonTitle="Save" submitAction="submit"
|
|
||||||
:actions="[
|
|
||||||
'You could lose a lot of functionalities if you change the server details of the server where Coolify is running on.',
|
|
||||||
]" :confirmWithText="false" :confirmWithPassword="false" step2ButtonText="Save" />
|
|
||||||
@else
|
|
||||||
<x-forms.button type="submit">Save</x-forms.button>
|
|
||||||
@if ($server->isFunctional())
|
|
||||||
<x-slide-over closeWithX fullScreen>
|
|
||||||
<x-slot:title>Validate & configure</x-slot:title>
|
|
||||||
<x-slot:content>
|
|
||||||
<livewire:server.validate-and-install :server="$server" ask />
|
|
||||||
</x-slot:content>
|
|
||||||
<x-forms.button @click="slideOverOpen=true" wire:click.prevent='validateServer' isHighlighted>
|
|
||||||
Revalidate server
|
|
||||||
</x-forms.button>
|
|
||||||
</x-slide-over>
|
|
||||||
@endif
|
|
||||||
@endif
|
|
||||||
</div>
|
|
||||||
@if ($server->isFunctional())
|
|
||||||
Server is reachable and validated.
|
|
||||||
@else
|
|
||||||
You can't use this server until it is validated.
|
|
||||||
@endif
|
|
||||||
@if ((!$server->settings->is_reachable || !$server->settings->is_usable) && $server->id !== 0)
|
|
||||||
<x-slide-over closeWithX fullScreen>
|
|
||||||
<x-slot:title>Validate & configure</x-slot:title>
|
|
||||||
<x-slot:content>
|
|
||||||
<livewire:server.validate-and-install :server="$server" />
|
|
||||||
</x-slot:content>
|
|
||||||
<x-forms.button @click="slideOverOpen=true"
|
|
||||||
class="mt-8 mb-4 w-full font-bold box-without-bg bg-coollabs hover:bg-coollabs-100"
|
|
||||||
wire:click.prevent='validateServer' isHighlighted>
|
|
||||||
Validate Server & Install Docker Engine
|
|
||||||
</x-forms.button>
|
|
||||||
</x-slide-over>
|
|
||||||
@if ($server->validation_logs)
|
|
||||||
<h4>Previous Validation Logs</h4>
|
|
||||||
<div class="pb-8">
|
|
||||||
{!! $server->validation_logs !!}
|
|
||||||
</div>
|
|
||||||
@endif
|
|
||||||
@endif
|
|
||||||
@if ((!$server->settings->is_reachable || !$server->settings->is_usable) && $server->id === 0)
|
|
||||||
<x-forms.button class="mt-8 mb-4 font-bold box-without-bg bg-coollabs hover:bg-coollabs-100"
|
|
||||||
wire:click.prevent='checkLocalhostConnection' isHighlighted>
|
|
||||||
Validate Server
|
|
||||||
</x-forms.button>
|
|
||||||
@endif
|
|
||||||
@if ($server->isForceDisabled() && isCloud())
|
|
||||||
<div class="pt-4 font-bold text-red-500">The system has disabled the server because you have exceeded the
|
|
||||||
number of servers for which you have paid.</div>
|
|
||||||
@endif
|
|
||||||
<div class="flex flex-col gap-2 pt-4">
|
|
||||||
<div class="flex flex-col gap-2 w-full lg:flex-row">
|
|
||||||
<x-forms.input id="server.name" label="Name" required />
|
|
||||||
<x-forms.input id="server.description" label="Description" />
|
|
||||||
@if (!$server->settings->is_swarm_worker && !$server->settings->is_build_server)
|
|
||||||
<x-forms.input placeholder="https://example.com" id="wildcard_domain" label="Wildcard Domain"
|
|
||||||
helper='A wildcard domain allows you to receive a randomly generated domain for your new applications. <br><br>For instance, if you set "https://example.com" as your wildcard domain, your applications will receive domains like "https://randomId.example.com".' />
|
|
||||||
@endif
|
|
||||||
|
|
||||||
</div>
|
|
||||||
<div class="flex flex-col gap-2 w-full lg:flex-row">
|
|
||||||
<x-forms.input type="password" id="server.ip" label="IP Address/Domain"
|
|
||||||
helper="An IP Address (127.0.0.1) or domain (example.com). Make sure there is no protocol like http(s):// so you provide a FQDN not a URL."
|
|
||||||
required />
|
|
||||||
<div class="flex gap-2">
|
|
||||||
<x-forms.input id="server.user" label="User" required />
|
|
||||||
<x-forms.input type="number" id="server.port" label="Port" required />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="w-full" x-data="{
|
|
||||||
open: false,
|
|
||||||
search: '{{ $server->settings->server_timezone ?: '' }}',
|
|
||||||
timezones: @js($timezones),
|
|
||||||
placeholder: '{{ $server->settings->server_timezone ? 'Search timezone...' : 'Select Server Timezone' }}',
|
|
||||||
init() {
|
|
||||||
this.$watch('search', value => {
|
|
||||||
if (value === '') {
|
|
||||||
this.open = true;
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}">
|
|
||||||
<div class="flex items-center mb-1">
|
|
||||||
<label for="server.settings.server_timezone">Server
|
|
||||||
Timezone</label>
|
|
||||||
<x-helper class="ml-2" helper="Server's timezone. This is used for backups, cron jobs, etc." />
|
|
||||||
</div>
|
|
||||||
<div class="relative">
|
|
||||||
<div class="inline-flex relative items-center w-64">
|
|
||||||
<input autocomplete="off"
|
|
||||||
wire:dirty.class.remove='dark:focus:ring-coolgray-300 dark:ring-coolgray-300'
|
|
||||||
wire:dirty.class="dark:focus:ring-warning dark:ring-warning" x-model="search"
|
|
||||||
@focus="open = true" @click.away="open = false" @input="open = true" class="w-full input"
|
|
||||||
:placeholder="placeholder" wire:model.debounce.300ms="server.settings.server_timezone">
|
|
||||||
<svg class="absolute right-0 mr-2 w-4 h-4" xmlns="http://www.w3.org/2000/svg" fill="none"
|
|
||||||
viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" @click="open = true">
|
|
||||||
<path stroke-linecap="round" stroke-linejoin="round"
|
|
||||||
d="M8.25 15L12 18.75 15.75 15m-7.5-6L12 5.25 15.75 9" />
|
|
||||||
</svg>
|
|
||||||
</div>
|
|
||||||
<div x-show="open"
|
|
||||||
class="overflow-auto overflow-x-hidden absolute z-50 mt-1 w-64 max-h-60 bg-white rounded-md border shadow-lg dark:bg-coolgray-100 dark:border-coolgray-200 scrollbar">
|
|
||||||
<template
|
|
||||||
x-for="timezone in timezones.filter(tz => tz.toLowerCase().includes(search.toLowerCase()))"
|
|
||||||
:key="timezone">
|
|
||||||
<div @click="search = timezone; open = false; $wire.set('server.settings.server_timezone', timezone)"
|
|
||||||
class="px-4 py-2 text-gray-800 cursor-pointer hover:bg-gray-100 dark:hover:bg-coolgray-300 dark:text-gray-200"
|
|
||||||
x-text="timezone"></div>
|
|
||||||
</template>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="w-full">
|
|
||||||
@if (!$server->isLocalhost())
|
|
||||||
<div class="w-96">
|
|
||||||
<x-forms.checkbox instantSave id="server.settings.is_build_server"
|
|
||||||
label="Use it as a build server?" />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
@if (!$server->isBuildServer() && !$server->settings->is_cloudflare_tunnel)
|
|
||||||
<h3 class="pt-6">Swarm <span class="text-xs text-neutral-500">(experimental)</span></h3>
|
|
||||||
<div class="pb-4">Read the docs <a class='underline dark:text-white'
|
|
||||||
href='https://coolify.io/docs/knowledge-base/docker/swarm' target='_blank'>here</a>.
|
|
||||||
</div>
|
|
||||||
<div class="w-96">
|
|
||||||
@if ($server->settings->is_swarm_worker)
|
|
||||||
<x-forms.checkbox disabled instantSave type="checkbox"
|
|
||||||
id="server.settings.is_swarm_manager"
|
|
||||||
helper="For more information, please read the documentation <a class='dark:text-white' href='https://coolify.io/docs/knowledge-base/docker/swarm' target='_blank'>here</a>."
|
|
||||||
label="Is it a Swarm Manager?" />
|
|
||||||
@else
|
|
||||||
<x-forms.checkbox instantSave type="checkbox" id="server.settings.is_swarm_manager"
|
|
||||||
helper="For more information, please read the documentation <a class='dark:text-white' href='https://coolify.io/docs/knowledge-base/docker/swarm' target='_blank'>here</a>."
|
|
||||||
label="Is it a Swarm Manager?" />
|
|
||||||
@endif
|
|
||||||
|
|
||||||
@if ($server->settings->is_swarm_manager)
|
|
||||||
<x-forms.checkbox disabled instantSave type="checkbox"
|
|
||||||
id="server.settings.is_swarm_worker"
|
|
||||||
helper="For more information, please read the documentation <a class='dark:text-white' href='https://coolify.io/docs/knowledge-base/docker/swarm' target='_blank'>here</a>."
|
|
||||||
label="Is it a Swarm Worker?" />
|
|
||||||
@else
|
|
||||||
<x-forms.checkbox instantSave type="checkbox" id="server.settings.is_swarm_worker"
|
|
||||||
helper="For more information, please read the documentation <a class='dark:text-white' href='https://coolify.io/docs/knowledge-base/docker/swarm' target='_blank'>here</a>."
|
|
||||||
label="Is it a Swarm Worker?" />
|
|
||||||
@endif
|
|
||||||
</div>
|
|
||||||
@endif
|
|
||||||
@endif
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
@if ($server->isFunctional() && !$server->isSwarm() && !$server->isBuildServer())
|
|
||||||
<form wire:submit.prevent='saveSentinel'>
|
|
||||||
<div class="flex gap-2 items-center pt-4 pb-2">
|
|
||||||
<h3>Sentinel</h3>
|
|
||||||
@if ($server->isSentinelEnabled())
|
|
||||||
<div class="flex gap-2 items-center">
|
|
||||||
@if ($server->isSentinelLive())
|
|
||||||
<x-status.running status="In sync" noLoading title="{{ $server->sentinel_updated_at }}" />
|
|
||||||
<x-forms.button type="submit">Save</x-forms.button>
|
|
||||||
<x-forms.button wire:click='restartSentinel'>Restart</x-forms.button>
|
|
||||||
@else
|
|
||||||
<x-status.stopped status="Out of sync" noLoading
|
|
||||||
title="{{ $server->sentinel_updated_at }}" />
|
|
||||||
<x-forms.button type="submit">Save</x-forms.button>
|
|
||||||
<x-forms.button wire:click='restartSentinel'>Sync</x-forms.button>
|
|
||||||
@endif
|
|
||||||
</div>
|
|
||||||
@endif
|
|
||||||
</div>
|
|
||||||
<div class="flex flex-col gap-2">
|
|
||||||
<div class="flex gap-2">Experimental feature <x-helper
|
|
||||||
helper="Sentinel reports your server's & container's health and collects metrics." /></div>
|
|
||||||
<div class="w-64">
|
|
||||||
<x-forms.checkbox wire:model.live="server.settings.is_sentinel_enabled" label="Enable Sentinel" />
|
|
||||||
@if ($server->isSentinelEnabled())
|
|
||||||
<x-forms.checkbox id="server.settings.is_sentinel_debug_enabled" label="Enable Sentinel Debug"
|
|
||||||
instantSave />
|
|
||||||
<x-forms.checkbox instantSave id="server.settings.is_metrics_enabled"
|
|
||||||
label="Enable Metrics" />
|
|
||||||
@else
|
|
||||||
<x-forms.checkbox id="server.settings.is_sentinel_debug_enabled" label="Enable Sentinel Debug"
|
|
||||||
disabled instantSave />
|
|
||||||
<x-forms.checkbox instantSave disabled id="server.settings.is_metrics_enabled"
|
|
||||||
label="Enable Metrics" />
|
|
||||||
@endif
|
|
||||||
</div>
|
|
||||||
@if ($server->isSentinelEnabled())
|
|
||||||
<div class="flex flex-wrap gap-2 sm:flex-nowrap items-end">
|
|
||||||
<x-forms.input type="password" id="server.settings.sentinel_token" label="Sentinel token"
|
|
||||||
required helper="Token for Sentinel." />
|
|
||||||
<x-forms.button wire:click="regenerateSentinelToken">Regenerate</x-forms.button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<x-forms.input id="server.settings.sentinel_custom_url" required label="Coolify URL"
|
|
||||||
helper="URL to your Coolify instance. If it is empty that means you do not have a FQDN set for your Coolify instance." />
|
|
||||||
|
|
||||||
<div class="flex flex-col gap-2">
|
|
||||||
<div class="flex flex-wrap gap-2 sm:flex-nowrap">
|
|
||||||
<x-forms.input id="server.settings.sentinel_metrics_refresh_rate_seconds"
|
|
||||||
label="Metrics rate (seconds)" required
|
|
||||||
helper="The interval for gathering metrics. Lower means more disk space will be used." />
|
|
||||||
<x-forms.input id="server.settings.sentinel_metrics_history_days"
|
|
||||||
label="Metrics history (days)" required
|
|
||||||
helper="How many days should the metrics data should be reserved." />
|
|
||||||
<x-forms.input id="server.settings.sentinel_push_interval_seconds"
|
|
||||||
label="Push interval (seconds)" required
|
|
||||||
helper="How many seconds should the metrics data should be pushed to the collector." />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
@endif
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
@endif
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
@ -1,64 +0,0 @@
|
||||||
<div>
|
|
||||||
<h1>Tags</h1>
|
|
||||||
<div class="flex flex-col pb-6">
|
|
||||||
<div class="subtitle">Tags help you to perform actions on multiple resources.</div>
|
|
||||||
<div class="">
|
|
||||||
@if ($tags->count() === 0)
|
|
||||||
<div>No tags yet defined yet. Go to a resource and add a tag there.</div>
|
|
||||||
@else
|
|
||||||
<x-forms.datalist wire:model="tag" onUpdate='tagUpdated'>
|
|
||||||
@foreach ($tags as $oneTag)
|
|
||||||
<option value="{{ $oneTag->name }}">{{ $oneTag->name }}</option>
|
|
||||||
@endforeach
|
|
||||||
</x-forms.datalist>
|
|
||||||
@if ($tag)
|
|
||||||
<div class="pt-5">
|
|
||||||
<div class="flex items-end gap-2 ">
|
|
||||||
<div class="w-[500px]">
|
|
||||||
<x-forms.input readonly label="Deploy Webhook URL" id="webhook" />
|
|
||||||
</div>
|
|
||||||
<x-modal-confirmation title="Redeploy all resources with this tag?" isHighlighted
|
|
||||||
buttonTitle="Redeploy All" submitAction="redeployAll" :actions="[
|
|
||||||
'All resources with this tag will be redeployed.',
|
|
||||||
'During redeploy resources will be temporarily unavailable.',
|
|
||||||
]"
|
|
||||||
confirmationText="{{ $tag }}"
|
|
||||||
confirmationLabel="Please confirm the execution of the actions by entering the Tag Name below"
|
|
||||||
shortConfirmationLabel="Tag Name" :confirmWithPassword="false" step2ButtonText="Redeploy All" />
|
|
||||||
</div>
|
|
||||||
<div class="grid grid-cols-1 gap-2 pt-4 lg:grid-cols-2 xl:grid-cols-3">
|
|
||||||
@foreach ($applications as $application)
|
|
||||||
<a href="{{ $application->link() }}"class="box group">
|
|
||||||
<div class="flex flex-col">
|
|
||||||
<div class="box-title">{{ $application->name }}</div>
|
|
||||||
<div class="box-description">
|
|
||||||
{{ $application->project()->name }}/{{ $application->environment->name }}
|
|
||||||
</div>
|
|
||||||
<div class="box-description">{{ $application->description }}</div>
|
|
||||||
</div>
|
|
||||||
</a>
|
|
||||||
@endforeach
|
|
||||||
@foreach ($services as $service)
|
|
||||||
<a href="{{ $service->link() }}" class="box group">
|
|
||||||
<div class="flex flex-col ">
|
|
||||||
<div class="box-title">{{ $service->name }}</div>
|
|
||||||
<div class="box-description">
|
|
||||||
{{ $service->project()->name }}/{{ $service->environment->name }}</div>
|
|
||||||
<div class="box-description">{{ $service->description }}</div>
|
|
||||||
</div>
|
|
||||||
</a>
|
|
||||||
@endforeach
|
|
||||||
</div>
|
|
||||||
<div class="flex items-center gap-2">
|
|
||||||
<h3 class="py-4">Deployments</h3>
|
|
||||||
@if (count($deploymentsPerTagPerServer) > 0)
|
|
||||||
<x-loading />
|
|
||||||
@endif
|
|
||||||
</div>
|
|
||||||
<livewire:tags.deployments :deploymentsPerTagPerServer="$deploymentsPerTagPerServer" :resourceIds="$applications->pluck('id')" />
|
|
||||||
</div>
|
|
||||||
@endif
|
|
||||||
@endif
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
@ -1,87 +1,96 @@
|
||||||
<div>
|
<div>
|
||||||
<div class="flex items-start gap-2">
|
<div class="flex items-start gap-2 pb-10">
|
||||||
<div>
|
<div>
|
||||||
<h1>Tags</h1>
|
<h1>Tags</h1>
|
||||||
|
<div>Tags help you to perform actions on multiple resources.</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex flex-col gap-2 pb-6 ">
|
<div class="flex flex-wrap gap-2 ">
|
||||||
<div>Available tags</div>
|
@forelse ($tags as $oneTag)
|
||||||
<div class="flex flex-wrap gap-2 ">
|
<a wire:navigate :class="{{ $tag?->id == $oneTag->id }} && 'dark:bg-coollabs hover:bg-coollabs-100'"
|
||||||
@forelse ($tags as $oneTag)
|
class="w-64 box-without-bg dark:bg-coolgray-100 dark:text-white font-bold"
|
||||||
<a :class="{{ $tag->id == $oneTag->id }} && 'bg-coollabs hover:bg-coollabs-100'" class="w-64 box"
|
href="{{ route('tags.show', ['tagName' => $oneTag->name]) }}">{{ $oneTag->name }}</a>
|
||||||
href="{{ route('tags.show', ['tag_name' => $oneTag->name]) }}">{{ $oneTag->name }}</a>
|
@empty
|
||||||
@empty
|
<div>No tags yet defined yet. Go to a resource and add a tag there.</div>
|
||||||
<div>No tags yet defined yet. Go to a resource and add a tag there.</div>
|
@endforelse
|
||||||
@endforelse
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div>
|
@if (isset($tag))
|
||||||
<h3 class="py-4">Details</h3>
|
<div>
|
||||||
<div class="flex items-end gap-2 ">
|
<h3 class="py-4">Details</h3>
|
||||||
<div class="w-[500px]">
|
<div class="flex items-end gap-2 ">
|
||||||
<x-forms.input readonly label="Deploy Webhook URL" id="webhook" />
|
<div class="w-[500px]">
|
||||||
|
<x-forms.input readonly label="Deploy Webhook URL" id="webhook" />
|
||||||
|
</div>
|
||||||
|
<x-modal-confirmation title="Redeploy all resources with this tag?" isHighlighted
|
||||||
|
buttonTitle="Redeploy All" submitAction="redeployAll" :actions="[
|
||||||
|
'All resources with this tag will be redeployed.',
|
||||||
|
'During redeploy resources will be temporarily unavailable.',
|
||||||
|
]"
|
||||||
|
confirmationText="{{ $tag->name }}"
|
||||||
|
confirmationLabel="Please confirm the execution of the actions by entering the Tag Name below"
|
||||||
|
shortConfirmationLabel="Tag Name" :confirmWithPassword="false" step2ButtonText="Redeploy All" />
|
||||||
</div>
|
</div>
|
||||||
<x-modal-confirmation title="Redeploy all resources with this tag?" isHighlighted buttonTitle="Redeploy All"
|
|
||||||
submitAction="redeploy_all" :actions="[
|
<div class="grid grid-cols-1 gap-2 pt-4 lg:grid-cols-2 xl:grid-cols-3">
|
||||||
'All resources with this tag will be redeployed.',
|
@if (isset($applications) && count($applications) > 0)
|
||||||
'During redeploy resources will be temporarily unavailable.',
|
@foreach ($applications as $application)
|
||||||
]" confirmationText="{{ $tag }}"
|
<a href="{{ $application->link() }}" class="box group">
|
||||||
confirmationLabel="Please confirm the execution of the actions by entering the Tag Name below"
|
<div class="flex flex-col">
|
||||||
shortConfirmationLabel="Tag Name" :confirmWithPassword="false" step2ButtonText="Redeploy All" />
|
<div class="box-title">
|
||||||
</div>
|
{{ $application->project()->name }}/{{ $application->environment->name }}
|
||||||
<div class="grid grid-cols-1 gap-2 pt-4 lg:grid-cols-2 xl:grid-cols-3">
|
|
||||||
@foreach ($applications as $application)
|
|
||||||
<a href="{{ $application->link() }}" class="box group">
|
|
||||||
<div class="flex flex-col">
|
|
||||||
<div class="box-title">{{ $application->project()->name }}/{{ $application->environment->name }}
|
|
||||||
</div>
|
|
||||||
<div class="box-description">{{ $application->name }}</div>
|
|
||||||
<div class="box-description">{{ $application->description }}</div>
|
|
||||||
</div>
|
|
||||||
</a>
|
|
||||||
@endforeach
|
|
||||||
@foreach ($services as $service)
|
|
||||||
<a href="{{ $service->link() }}" class="flex flex-col box group">
|
|
||||||
<div class="flex flex-col">
|
|
||||||
<div class="box-title">{{ $service->project()->name }}/{{ $service->environment->name }}
|
|
||||||
</div>
|
|
||||||
<div class="box-description">{{ $service->name }}</div>
|
|
||||||
<div class="box-description">{{ $service->description }}</div>
|
|
||||||
</div>
|
|
||||||
</a>
|
|
||||||
@endforeach
|
|
||||||
</div>
|
|
||||||
<div class="flex items-center gap-2">
|
|
||||||
<h3 class="py-4">Deployments</h3>
|
|
||||||
@if (count($deployments_per_tag_per_server) > 0)
|
|
||||||
<x-loading />
|
|
||||||
@endif
|
|
||||||
</div>
|
|
||||||
<div wire:poll.1000ms="get_deployments" class="grid grid-cols-1">
|
|
||||||
@forelse ($deployments_per_tag_per_server as $server_name => $deployments)
|
|
||||||
<h4 class="py-4">{{ $server_name }}</h4>
|
|
||||||
<div class="grid grid-cols-1 gap-2 lg:grid-cols-3">
|
|
||||||
@foreach ($deployments as $deployment)
|
|
||||||
<a href="{{ data_get($deployment, 'deployment_url') }}" @class([
|
|
||||||
'gap-2 cursor-pointer box group border-l-2 border-dotted',
|
|
||||||
'dark:border-coolgray-300' => data_get($deployment, 'status') === 'queued',
|
|
||||||
'border-yellow-500' => data_get($deployment, 'status') === 'in_progress',
|
|
||||||
])>
|
|
||||||
<div class="flex flex-col mx-6">
|
|
||||||
<div class="font-bold dark:text-white">
|
|
||||||
{{ data_get($deployment, 'application_name') }}
|
|
||||||
</div>
|
|
||||||
<div class="description">
|
|
||||||
{{ str(data_get($deployment, 'status'))->headline() }}
|
|
||||||
</div>
|
</div>
|
||||||
|
<div class="box-description">{{ $application->name }}</div>
|
||||||
|
<div class="box-description">{{ $application->description }}</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex-1"></div>
|
|
||||||
</a>
|
</a>
|
||||||
@endforeach
|
@endforeach
|
||||||
</div>
|
@endif
|
||||||
@empty
|
@if (isset($services) && count($services) > 0)
|
||||||
<div>No deployments running.</div>
|
@foreach ($services as $service)
|
||||||
@endforelse
|
<a href="{{ $service->link() }}" class="flex flex-col box group">
|
||||||
|
<div class="flex flex-col">
|
||||||
|
<div class="box-title">
|
||||||
|
{{ $service->project()->name }}/{{ $service->environment->name }}
|
||||||
|
</div>
|
||||||
|
<div class="box-description">{{ $service->name }}</div>
|
||||||
|
<div class="box-description">{{ $service->description }}</div>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
@endforeach
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<h3 class="py-4">Deployments</h3>
|
||||||
|
@if (count($deploymentsPerTagPerServer) > 0)
|
||||||
|
<x-loading />
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
|
<div wire:poll="getDeployments" class="grid grid-cols-1">
|
||||||
|
@forelse ($deploymentsPerTagPerServer as $serverName => $deployments)
|
||||||
|
<h4 class="py-4">{{ $serverName }}</h4>
|
||||||
|
<div class="grid grid-cols-1 gap-2 lg:grid-cols-3">
|
||||||
|
@foreach ($deployments as $deployment)
|
||||||
|
<a href="{{ data_get($deployment, 'deployment_url') }}" @class([
|
||||||
|
'gap-2 cursor-pointer box group border-l-2 border-dotted',
|
||||||
|
'dark:border-coolgray-300' => data_get($deployment, 'status') === 'queued',
|
||||||
|
'border-yellow-500' => data_get($deployment, 'status') === 'in_progress',
|
||||||
|
])>
|
||||||
|
<div class="flex flex-col mx-6">
|
||||||
|
<div class="font-bold dark:text-white">
|
||||||
|
{{ data_get($deployment, 'application_name') }}
|
||||||
|
</div>
|
||||||
|
<div class="description">
|
||||||
|
{{ str(data_get($deployment, 'status'))->headline() }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex-1"></div>
|
||||||
|
</a>
|
||||||
|
@endforeach
|
||||||
|
</div>
|
||||||
|
@empty
|
||||||
|
<div>No deployments running.</div>
|
||||||
|
@endforelse
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
@endif
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -65,7 +65,6 @@ use App\Livewire\Storage\Index as StorageIndex;
|
||||||
use App\Livewire\Storage\Show as StorageShow;
|
use App\Livewire\Storage\Show as StorageShow;
|
||||||
use App\Livewire\Subscription\Index as SubscriptionIndex;
|
use App\Livewire\Subscription\Index as SubscriptionIndex;
|
||||||
use App\Livewire\Subscription\Show as SubscriptionShow;
|
use App\Livewire\Subscription\Show as SubscriptionShow;
|
||||||
use App\Livewire\Tags\Index as TagsIndex;
|
|
||||||
use App\Livewire\Tags\Show as TagsShow;
|
use App\Livewire\Tags\Show as TagsShow;
|
||||||
use App\Livewire\Team\AdminView as TeamAdminView;
|
use App\Livewire\Team\AdminView as TeamAdminView;
|
||||||
use App\Livewire\Team\Index as TeamIndex;
|
use App\Livewire\Team\Index as TeamIndex;
|
||||||
|
|
@ -127,8 +126,7 @@ Route::middleware(['auth', 'verified'])->group(function () {
|
||||||
Route::get('/profile', ProfileIndex::class)->name('profile');
|
Route::get('/profile', ProfileIndex::class)->name('profile');
|
||||||
|
|
||||||
Route::prefix('tags')->group(function () {
|
Route::prefix('tags')->group(function () {
|
||||||
Route::get('/', TagsIndex::class)->name('tags.index');
|
Route::get('/{tagName?}', TagsShow::class)->name('tags.show');
|
||||||
Route::get('/{tag_name}', TagsShow::class)->name('tags.show');
|
|
||||||
});
|
});
|
||||||
|
|
||||||
Route::prefix('notifications')->group(function () {
|
Route::prefix('notifications')->group(function () {
|
||||||
|
|
|
||||||
|
|
@ -164,7 +164,6 @@ sles | opensuse-leap | opensuse-tumbleweed)
|
||||||
esac
|
esac
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
echo -e "2. Check OpenSSH server configuration. "
|
echo -e "2. Check OpenSSH server configuration. "
|
||||||
|
|
||||||
# Detect OpenSSH server
|
# Detect OpenSSH server
|
||||||
|
|
@ -262,9 +261,14 @@ if ! [ -x "$(command -v docker)" ]; then
|
||||||
fi
|
fi
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
curl -s https://releases.rancher.com/install-docker/${DOCKER_VERSION}.sh | sh >/dev/null 2>&1
|
if [ "$OS_TYPE" = "ubuntu" ] && [ "$OS_VERSION" = "24.10" ]; then
|
||||||
|
echo "Docker automated installation is not supported on Ubuntu 24.10 (non-LTS release)."
|
||||||
|
echo "Please install Docker manually."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
curl -s https://releases.rancher.com/install-docker/${DOCKER_VERSION}.sh | sh 2>&1
|
||||||
if ! [ -x "$(command -v docker)" ]; then
|
if ! [ -x "$(command -v docker)" ]; then
|
||||||
curl -s https://get.docker.com | sh -s -- --version ${DOCKER_VERSION} >/dev/null 2>&1
|
curl -s https://get.docker.com | sh -s -- --version ${DOCKER_VERSION} 2>&1
|
||||||
if ! [ -x "$(command -v docker)" ]; then
|
if ! [ -x "$(command -v docker)" ]; then
|
||||||
echo " - Docker installation failed."
|
echo " - Docker installation failed."
|
||||||
echo " Maybe your OS is not supported?"
|
echo " Maybe your OS is not supported?"
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
test('ConvertCapAdd', function () {
|
test('ConvertCapAdd', function () {
|
||||||
$input = '--cap-add=NET_ADMIN --cap-add=NET_RAW --cap-add SYS_ADMIN';
|
$input = '--cap-add=NET_ADMIN --cap-add=NET_RAW --cap-add SYS_ADMIN';
|
||||||
$output = convert_docker_run_to_compose($input);
|
$output = convertDockerRunToCompose($input);
|
||||||
expect($output)->toBe([
|
expect($output)->toBe([
|
||||||
'cap_add' => ['NET_ADMIN', 'NET_RAW', 'SYS_ADMIN'],
|
'cap_add' => ['NET_ADMIN', 'NET_RAW', 'SYS_ADMIN'],
|
||||||
]);
|
]);
|
||||||
|
|
@ -10,7 +10,7 @@ test('ConvertCapAdd', function () {
|
||||||
|
|
||||||
test('ConvertIp', function () {
|
test('ConvertIp', function () {
|
||||||
$input = '--cap-add=NET_ADMIN --cap-add=NET_RAW --cap-add SYS_ADMIN --ip 127.0.0.1 --ip 127.0.0.2';
|
$input = '--cap-add=NET_ADMIN --cap-add=NET_RAW --cap-add SYS_ADMIN --ip 127.0.0.1 --ip 127.0.0.2';
|
||||||
$output = convert_docker_run_to_compose($input);
|
$output = convertDockerRunToCompose($input);
|
||||||
expect($output)->toBe([
|
expect($output)->toBe([
|
||||||
'cap_add' => ['NET_ADMIN', 'NET_RAW', 'SYS_ADMIN'],
|
'cap_add' => ['NET_ADMIN', 'NET_RAW', 'SYS_ADMIN'],
|
||||||
'ip' => ['127.0.0.1', '127.0.0.2'],
|
'ip' => ['127.0.0.1', '127.0.0.2'],
|
||||||
|
|
@ -19,7 +19,7 @@ test('ConvertIp', function () {
|
||||||
|
|
||||||
test('ConvertPrivilegedAndInit', function () {
|
test('ConvertPrivilegedAndInit', function () {
|
||||||
$input = '---privileged --init';
|
$input = '---privileged --init';
|
||||||
$output = convert_docker_run_to_compose($input);
|
$output = convertDockerRunToCompose($input);
|
||||||
expect($output)->toBe([
|
expect($output)->toBe([
|
||||||
'privileged' => true,
|
'privileged' => true,
|
||||||
'init' => true,
|
'init' => true,
|
||||||
|
|
@ -28,7 +28,7 @@ test('ConvertPrivilegedAndInit', function () {
|
||||||
|
|
||||||
test('ConvertUlimit', function () {
|
test('ConvertUlimit', function () {
|
||||||
$input = '--ulimit nofile=262144:262144';
|
$input = '--ulimit nofile=262144:262144';
|
||||||
$output = convert_docker_run_to_compose($input);
|
$output = convertDockerRunToCompose($input);
|
||||||
expect($output)->toBe([
|
expect($output)->toBe([
|
||||||
'ulimits' => [
|
'ulimits' => [
|
||||||
'nofile' => [
|
'nofile' => [
|
||||||
|
|
@ -38,3 +38,61 @@ test('ConvertUlimit', function () {
|
||||||
],
|
],
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
test('ConvertGpusWithGpuId', function () {
|
||||||
|
$input = '--gpus "device=GPU-0000000000000000"';
|
||||||
|
$output = convertDockerRunToCompose($input);
|
||||||
|
expect($output)->toBe([
|
||||||
|
'deploy' => [
|
||||||
|
'resources' => [
|
||||||
|
'reservations' => [
|
||||||
|
'devices' => [
|
||||||
|
[
|
||||||
|
'driver' => 'nvidia',
|
||||||
|
'capabilities' => ['gpu'],
|
||||||
|
'device_ids' => ['GPU-0000000000000000'],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('ConvertGpus', function () {
|
||||||
|
$input = '--gpus all';
|
||||||
|
$output = convertDockerRunToCompose($input);
|
||||||
|
expect($output)->toBe([
|
||||||
|
'deploy' => [
|
||||||
|
'resources' => [
|
||||||
|
'reservations' => [
|
||||||
|
'devices' => [
|
||||||
|
[
|
||||||
|
'driver' => 'nvidia',
|
||||||
|
'capabilities' => ['gpu'],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('ConvertGpusWithQuotes', function () {
|
||||||
|
$input = '--gpus "device=0,1"';
|
||||||
|
$output = convertDockerRunToCompose($input);
|
||||||
|
expect($output)->toBe([
|
||||||
|
'deploy' => [
|
||||||
|
'resources' => [
|
||||||
|
'reservations' => [
|
||||||
|
'devices' => [
|
||||||
|
[
|
||||||
|
'driver' => 'nvidia',
|
||||||
|
'capabilities' => ['gpu'],
|
||||||
|
'device_ids' => ['0', '1'],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue