mirror of
https://github.com/ershisan99/coolify.git
synced 2025-12-26 12:33:25 +00:00
Compare commits
75 Commits
v4.0.0-bet
...
v4.0.0-bet
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2978042162 | ||
|
|
4225ec7060 | ||
|
|
893339fc8e | ||
|
|
356e7b57d2 | ||
|
|
4ee1f1a507 | ||
|
|
7d64df60cd | ||
|
|
eb3a4ca157 | ||
|
|
a7b5157fa6 | ||
|
|
793e6d19eb | ||
|
|
674fa4d09c | ||
|
|
0089e86dd1 | ||
|
|
e1d802b507 | ||
|
|
9927b71af9 | ||
|
|
b1c0f105ab | ||
|
|
35cae1d4dc | ||
|
|
3dab3365e2 | ||
|
|
1bdc7c87ba | ||
|
|
cab8ad0ca0 | ||
|
|
43409f3ff0 | ||
|
|
a5dd4cab52 | ||
|
|
a815240f4e | ||
|
|
2a44e7c5bd | ||
|
|
28c7e439b1 | ||
|
|
4396c786b4 | ||
|
|
b67bb8595f | ||
|
|
bec47487dd | ||
|
|
b110d0c12b | ||
|
|
ae425475b4 | ||
|
|
dc6aee44b3 | ||
|
|
4ffea311e8 | ||
|
|
77a6a6e46a | ||
|
|
2278ba31e7 | ||
|
|
aaeec3d340 | ||
|
|
2cbe530b7e | ||
|
|
6ada6d145c | ||
|
|
0f55e83591 | ||
|
|
4017ea7b65 | ||
|
|
a85066c644 | ||
|
|
b08d38f339 | ||
|
|
d4f4632461 | ||
|
|
666aa041f4 | ||
|
|
1c565fd502 | ||
|
|
7de2b8cbd7 | ||
|
|
852e906736 | ||
|
|
5778466947 | ||
|
|
7006239b0d | ||
|
|
49d011574d | ||
|
|
046a358ae0 | ||
|
|
d23f5af957 | ||
|
|
20a3f4b200 | ||
|
|
73acda833e | ||
|
|
fa895db76e | ||
|
|
88f33be5b6 | ||
|
|
21612cccf7 | ||
|
|
39a7332343 | ||
|
|
21825876fb | ||
|
|
aaee887d3e | ||
|
|
cb44373eff | ||
|
|
4e6ea4f584 | ||
|
|
62a93d3e51 | ||
|
|
f60c281e80 | ||
|
|
43c40cdb09 | ||
|
|
c851262d81 | ||
|
|
91783ccc3e | ||
|
|
6ba3d5f86e | ||
|
|
a9a20755a9 | ||
|
|
d2693c1ac8 | ||
|
|
aaa6f434a9 | ||
|
|
314a3ac83f | ||
|
|
36e177479e | ||
|
|
0c40c0d795 | ||
|
|
25f0a8f0b7 | ||
|
|
65a618d019 | ||
|
|
e7e85456ea | ||
|
|
440baf6009 |
@@ -2,8 +2,6 @@
|
||||
)
|
||||
|
||||
[](https://console.algora.io/org/coollabsio/bounties/new)
|
||||
[](https://console.algora.io/org/coollabsio/bounties?status=open)
|
||||
[](https://console.algora.io/org/coollabsio/bounties?status=completed)
|
||||
|
||||
# About the Project
|
||||
|
||||
@@ -49,6 +47,7 @@ Special thanks to our biggest sponsors!
|
||||
<a href="https://coolify.ad.vin/?ref=coolify.io" target="_blank"><img src="./other/logos/advin.png" alt="advin logo" width="250"/></a>
|
||||
<a href="https://trieve.ai/?ref=coolify.io" target="_blank"><img src="./other/logos/trieve_bg.png" alt="trieve logo" width="180"/></a>
|
||||
<a href="https://blacksmith.sh/?ref=coolify.io" target="_blank"><img src="./other/logos/blacksmith.svg" alt="blacksmith logo" width="200"/></a>
|
||||
<a href="https://latitude.sh/?ref=coolify.io" target="_blank"><img src="./other/logos/latitude.svg" alt="latitude logo" width="200"/></a>
|
||||
|
||||
## Github Sponsors ($40+)
|
||||
<a href="https://serpapi.com/?ref=coolify.io"><img width="60px" alt="SerpAPI" src="https://github.com/serpapi.png"/></a>
|
||||
|
||||
@@ -20,7 +20,7 @@ class StartService
|
||||
$commands[] = "docker network inspect $service->uuid >/dev/null 2>&1 || docker network create --attachable $service->uuid";
|
||||
$commands[] = 'echo Starting service.';
|
||||
$commands[] = "echo 'Pulling images.'";
|
||||
$commands[] = 'docker compose pull';
|
||||
$commands[] = 'docker compose pull --policy always';
|
||||
$commands[] = "echo 'Starting containers.'";
|
||||
$commands[] = 'docker compose up -d --remove-orphans --force-recreate --build';
|
||||
$commands[] = "docker network connect $service->uuid coolify-proxy >/dev/null 2>&1 || true";
|
||||
|
||||
@@ -15,7 +15,7 @@ class PullImage
|
||||
|
||||
$commands[] = 'cd '.$resource->workdir();
|
||||
$commands[] = "echo 'Saved configuration files to {$resource->workdir()}.'";
|
||||
$commands[] = 'docker compose pull';
|
||||
$commands[] = 'docker compose pull --policy always';
|
||||
|
||||
$server = data_get($resource, 'server');
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\Actions\Server\StopSentinel;
|
||||
use App\Enums\ApplicationDeploymentStatus;
|
||||
use App\Jobs\CleanupHelperContainersJob;
|
||||
use App\Models\ApplicationDeploymentQueue;
|
||||
@@ -23,6 +24,16 @@ class Init extends Command
|
||||
{
|
||||
$this->alive();
|
||||
get_public_ips();
|
||||
if (version_compare('4.0.0-beta.312', config('version'), '<=')) {
|
||||
$servers = Server::all();
|
||||
foreach ($servers as $server) {
|
||||
$server->settings->update(['is_metrics_enabled' => false]);
|
||||
if ($server->isFunctional()) {
|
||||
StopSentinel::dispatch($server);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$full_cleanup = $this->option('full-cleanup');
|
||||
$cleanup_deployments = $this->option('cleanup-deployments');
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ class ServiceStatusChanged implements ShouldBroadcast
|
||||
|
||||
public function broadcastOn(): ?array
|
||||
{
|
||||
if ($this->userId) {
|
||||
if (! is_null($this->userId)) {
|
||||
return [
|
||||
new PrivateChannel("user.{$this->userId}"),
|
||||
];
|
||||
|
||||
@@ -65,7 +65,7 @@ class Handler extends ExceptionHandler
|
||||
if ($e instanceof RuntimeException) {
|
||||
return;
|
||||
}
|
||||
$this->settings = InstanceSettings::get();
|
||||
$this->settings = \App\Models\InstanceSettings::get();
|
||||
if ($this->settings->do_not_track) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\InstanceSettings;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
use OpenApi\Attributes as OA;
|
||||
@@ -85,7 +84,7 @@ class OtherController extends Controller
|
||||
if ($teamId !== '0') {
|
||||
return response()->json(['message' => 'You are not allowed to enable the API.'], 403);
|
||||
}
|
||||
$settings = InstanceSettings::get();
|
||||
$settings = \App\Models\InstanceSettings::get();
|
||||
$settings->update(['is_api_enabled' => true]);
|
||||
|
||||
return response()->json(['message' => 'API enabled.'], 200);
|
||||
@@ -136,7 +135,7 @@ class OtherController extends Controller
|
||||
if ($teamId !== '0') {
|
||||
return response()->json(['message' => 'You are not allowed to disable the API.'], 403);
|
||||
}
|
||||
$settings = InstanceSettings::get();
|
||||
$settings = \App\Models\InstanceSettings::get();
|
||||
$settings->update(['is_api_enabled' => false]);
|
||||
|
||||
return response()->json(['message' => 'API disabled.'], 200);
|
||||
|
||||
@@ -4,7 +4,6 @@ namespace App\Http\Controllers\Api;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Application;
|
||||
use App\Models\InstanceSettings;
|
||||
use App\Models\Project;
|
||||
use App\Models\Server as ModelsServer;
|
||||
use Illuminate\Http\Request;
|
||||
@@ -301,7 +300,7 @@ class ServersController extends Controller
|
||||
$projects = Project::where('team_id', $teamId)->get();
|
||||
$domains = collect();
|
||||
$applications = $projects->pluck('applications')->flatten();
|
||||
$settings = InstanceSettings::get();
|
||||
$settings = \App\Models\InstanceSettings::get();
|
||||
if ($applications->count() > 0) {
|
||||
foreach ($applications as $application) {
|
||||
$ip = $application->destination->server->ip;
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use App\Models\InstanceSettings;
|
||||
use Closure;
|
||||
use Illuminate\Http\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
@@ -15,7 +14,7 @@ class ApiAllowed
|
||||
if (isCloud()) {
|
||||
return $next($request);
|
||||
}
|
||||
$settings = InstanceSettings::get();
|
||||
$settings = \App\Models\InstanceSettings::get();
|
||||
if ($settings->is_api_enabled === false) {
|
||||
return response()->json(['success' => true, 'message' => 'API is disabled.'], 403);
|
||||
}
|
||||
|
||||
@@ -462,7 +462,7 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
|
||||
if ($this->env_filename) {
|
||||
$command .= " --env-file {$this->workdir}/{$this->env_filename}";
|
||||
}
|
||||
$command .= " --project-name {$this->application->uuid} --project-directory {$this->workdir} -f {$this->workdir}{$this->docker_compose_location} build";
|
||||
$command .= " --project-name {$this->application->uuid} --project-directory {$this->workdir} -f {$this->workdir}{$this->docker_compose_location} build --pull";
|
||||
$this->execute_remote_command(
|
||||
[executeInDocker($this->deployment_uuid, $command), 'hidden' => true],
|
||||
);
|
||||
@@ -1624,12 +1624,15 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
|
||||
],
|
||||
],
|
||||
];
|
||||
if (data_get($this->application, 'swarm_placement_constraints')) {
|
||||
$swarm_placement_constraints = Yaml::parse(base64_decode(data_get($this->application, 'swarm_placement_constraints')));
|
||||
$docker_compose['services'][$this->container_name]['deploy'] = array_merge(
|
||||
$docker_compose['services'][$this->container_name]['deploy'],
|
||||
$swarm_placement_constraints
|
||||
);
|
||||
}
|
||||
if (data_get($this->application, 'settings.is_swarm_only_worker_nodes')) {
|
||||
$docker_compose['services'][$this->container_name]['deploy']['placement'] = [
|
||||
'constraints' => [
|
||||
'node.role == worker',
|
||||
],
|
||||
];
|
||||
$docker_compose['services'][$this->container_name]['deploy']['placement']['constraints'][] = 'node.role == worker';
|
||||
}
|
||||
if ($this->pull_request_id !== 0) {
|
||||
$docker_compose['services'][$this->container_name]['deploy']['replicas'] = 1;
|
||||
@@ -2028,23 +2031,6 @@ COPY ./nginx.conf /etc/nginx/conf.d/default.conf");
|
||||
}
|
||||
}
|
||||
|
||||
private function build_by_compose_file()
|
||||
{
|
||||
$this->application_deployment_queue->addLogEntry('Pulling & building required images.');
|
||||
if ($this->application->build_pack === 'dockerimage') {
|
||||
$this->application_deployment_queue->addLogEntry('Pulling latest images from the registry.');
|
||||
$this->execute_remote_command(
|
||||
[executeInDocker($this->deployment_uuid, "docker compose --project-name {$this->application->uuid} --project-directory {$this->workdir} pull"), 'hidden' => true],
|
||||
[executeInDocker($this->deployment_uuid, "{$this->coolify_variables} docker compose --project-name {$this->application->uuid} --project-directory {$this->workdir} build"), 'hidden' => true],
|
||||
);
|
||||
} else {
|
||||
$this->execute_remote_command(
|
||||
[executeInDocker($this->deployment_uuid, "{$this->coolify_variables} docker compose --project-name {$this->application->uuid} --project-directory {$this->workdir} -f {$this->workdir}{$this->docker_compose_location} build"), 'hidden' => true],
|
||||
);
|
||||
}
|
||||
$this->application_deployment_queue->addLogEntry('New images built.');
|
||||
}
|
||||
|
||||
private function start_by_compose_file()
|
||||
{
|
||||
if ($this->application->build_pack === 'dockerimage') {
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
namespace App\Jobs;
|
||||
|
||||
use App\Models\InstanceSettings;
|
||||
use App\Models\Server;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldBeEncrypted;
|
||||
@@ -36,7 +35,7 @@ class PullCoolifyImageJob implements ShouldBeEncrypted, ShouldQueue
|
||||
$latest_version = get_latest_version_of_coolify();
|
||||
instant_remote_process(["docker pull -q ghcr.io/coollabsio/coolify:{$latest_version}"], $server, false);
|
||||
|
||||
$settings = InstanceSettings::get();
|
||||
$settings = \App\Models\InstanceSettings::get();
|
||||
$current_version = config('version');
|
||||
if (! $settings->is_auto_update_enabled) {
|
||||
return;
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
namespace App\Livewire;
|
||||
|
||||
use App\Models\InstanceSettings;
|
||||
use DanHarrin\LivewireRateLimiting\WithRateLimiting;
|
||||
use Illuminate\Notifications\Messages\MailMessage;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
@@ -48,7 +47,7 @@ class Help extends Component
|
||||
]
|
||||
);
|
||||
$mail->subject("[HELP]: {$this->subject}");
|
||||
$settings = InstanceSettings::get();
|
||||
$settings = \App\Models\InstanceSettings::get();
|
||||
$type = set_transanctional_email_settings($settings);
|
||||
if (! $type) {
|
||||
$url = 'https://app.coolify.io/api/feedback';
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
namespace App\Livewire\Notifications;
|
||||
|
||||
use App\Models\InstanceSettings;
|
||||
use App\Models\Team;
|
||||
use App\Notifications\Test;
|
||||
use Livewire\Component;
|
||||
@@ -173,7 +172,7 @@ class Email extends Component
|
||||
|
||||
public function copyFromInstanceSettings()
|
||||
{
|
||||
$settings = InstanceSettings::get();
|
||||
$settings = \App\Models\InstanceSettings::get();
|
||||
if ($settings->smtp_enabled) {
|
||||
$team = currentTeam();
|
||||
$team->update([
|
||||
|
||||
@@ -350,7 +350,6 @@ class General extends Component
|
||||
$this->checkFqdns();
|
||||
|
||||
$this->application->save();
|
||||
|
||||
if (! $this->customLabels && $this->application->destination->server->proxyType() !== 'NONE') {
|
||||
$this->customLabels = str(implode('|coolify|', generateLabelsApplication($this->application)))->replace('|coolify|', "\n");
|
||||
$this->application->custom_labels = base64_encode($this->customLabels);
|
||||
@@ -364,6 +363,7 @@ class General extends Component
|
||||
}
|
||||
}
|
||||
$this->validate();
|
||||
|
||||
if ($this->ports_exposes !== $this->application->ports_exposes || $this->is_container_label_escape_enabled !== $this->application->settings->is_container_label_escape_enabled) {
|
||||
$this->resetDefaultLabels();
|
||||
}
|
||||
@@ -390,6 +390,7 @@ class General extends Component
|
||||
}
|
||||
if ($this->application->build_pack === 'dockercompose') {
|
||||
$this->application->docker_compose_domains = json_encode($this->parsedServiceDomains);
|
||||
|
||||
foreach ($this->parsedServiceDomains as $serviceName => $service) {
|
||||
$domain = data_get($service, 'domain');
|
||||
if ($domain) {
|
||||
@@ -399,6 +400,9 @@ class General extends Component
|
||||
check_domain_usage(resource: $this->application);
|
||||
}
|
||||
}
|
||||
if ($this->application->isDirty('docker_compose_domains')) {
|
||||
$this->resetDefaultLabels();
|
||||
}
|
||||
}
|
||||
$this->application->custom_labels = base64_encode($this->customLabels);
|
||||
$this->application->save();
|
||||
|
||||
@@ -53,6 +53,12 @@ class GithubPrivateRepository extends Component
|
||||
|
||||
public ?string $publish_directory = null;
|
||||
|
||||
// In case of docker compose
|
||||
public ?string $base_directory = null;
|
||||
|
||||
public ?string $docker_compose_location = '/docker-compose.yaml';
|
||||
// End of docker compose
|
||||
|
||||
protected int $page = 1;
|
||||
|
||||
public $build_pack = 'nixpacks';
|
||||
@@ -68,6 +74,16 @@ class GithubPrivateRepository extends Component
|
||||
$this->github_apps = GithubApp::private();
|
||||
}
|
||||
|
||||
public function updatedBaseDirectory()
|
||||
{
|
||||
if ($this->base_directory) {
|
||||
$this->base_directory = rtrim($this->base_directory, '/');
|
||||
if (! str($this->base_directory)->startsWith('/')) {
|
||||
$this->base_directory = '/'.$this->base_directory;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function updatedBuildPack()
|
||||
{
|
||||
if ($this->build_pack === 'nixpacks') {
|
||||
@@ -184,6 +200,10 @@ class GithubPrivateRepository extends Component
|
||||
if ($this->build_pack === 'dockerfile' || $this->build_pack === 'dockerimage') {
|
||||
$application->health_check_enabled = false;
|
||||
}
|
||||
if ($this->build_pack === 'dockercompose') {
|
||||
$application['docker_compose_location'] = $this->docker_compose_location;
|
||||
$application['base_directory'] = $this->base_directory;
|
||||
}
|
||||
$fqdn = generateFqdn($destination->server, $application->uuid);
|
||||
$application->fqdn = $fqdn;
|
||||
|
||||
|
||||
@@ -33,6 +33,12 @@ class GithubPrivateRepositoryDeployKey extends Component
|
||||
|
||||
public ?string $publish_directory = null;
|
||||
|
||||
// In case of docker compose
|
||||
public ?string $base_directory = null;
|
||||
|
||||
public ?string $docker_compose_location = '/docker-compose.yaml';
|
||||
// End of docker compose
|
||||
|
||||
public string $repository_url;
|
||||
|
||||
public string $branch;
|
||||
@@ -163,6 +169,10 @@ class GithubPrivateRepositoryDeployKey extends Component
|
||||
if ($this->build_pack === 'dockerfile' || $this->build_pack === 'dockerimage') {
|
||||
$application_init['health_check_enabled'] = false;
|
||||
}
|
||||
if ($this->build_pack === 'dockercompose') {
|
||||
$application_init['docker_compose_location'] = $this->docker_compose_location;
|
||||
$application_init['base_directory'] = $this->base_directory;
|
||||
}
|
||||
$application = Application::create($application_init);
|
||||
$application->settings->is_static = $this->is_static;
|
||||
$application->settings->save();
|
||||
|
||||
@@ -33,6 +33,12 @@ class PublicGitRepository extends Component
|
||||
|
||||
public ?string $publish_directory = null;
|
||||
|
||||
// In case of docker compose
|
||||
public ?string $base_directory = null;
|
||||
|
||||
public ?string $docker_compose_location = '/docker-compose.yaml';
|
||||
// End of docker compose
|
||||
|
||||
public string $git_branch = 'main';
|
||||
|
||||
public int $rate_limit_remaining = 0;
|
||||
@@ -59,6 +65,8 @@ class PublicGitRepository extends Component
|
||||
'is_static' => 'required|boolean',
|
||||
'publish_directory' => 'nullable|string',
|
||||
'build_pack' => 'required|string',
|
||||
'base_directory' => 'nullable|string',
|
||||
'docker_compose_location' => 'nullable|string',
|
||||
];
|
||||
|
||||
protected $validationAttributes = [
|
||||
@@ -67,6 +75,8 @@ class PublicGitRepository extends Component
|
||||
'is_static' => 'static',
|
||||
'publish_directory' => 'publish directory',
|
||||
'build_pack' => 'build pack',
|
||||
'base_directory' => 'base directory',
|
||||
'docker_compose_location' => 'docker compose location',
|
||||
];
|
||||
|
||||
public function mount()
|
||||
@@ -79,6 +89,16 @@ class PublicGitRepository extends Component
|
||||
$this->query = request()->query();
|
||||
}
|
||||
|
||||
public function updatedBaseDirectory()
|
||||
{
|
||||
if ($this->base_directory) {
|
||||
$this->base_directory = rtrim($this->base_directory, '/');
|
||||
if (! str($this->base_directory)->startsWith('/')) {
|
||||
$this->base_directory = '/'.$this->base_directory;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function updatedBuildPack()
|
||||
{
|
||||
if ($this->build_pack === 'nixpacks') {
|
||||
@@ -261,6 +281,10 @@ class PublicGitRepository extends Component
|
||||
if ($this->build_pack === 'dockerfile' || $this->build_pack === 'dockerimage') {
|
||||
$application_init['health_check_enabled'] = false;
|
||||
}
|
||||
if ($this->build_pack === 'dockercompose') {
|
||||
$application_init['docker_compose_location'] = $this->docker_compose_location;
|
||||
$application_init['base_directory'] = $this->base_directory;
|
||||
}
|
||||
$application = Application::create($application_init);
|
||||
|
||||
$application->settings->is_static = $this->is_static;
|
||||
|
||||
@@ -4,7 +4,6 @@ namespace App\Livewire\Project\Shared\Storages;
|
||||
|
||||
use App\Models\LocalPersistentVolume;
|
||||
use Livewire\Component;
|
||||
use Visus\Cuid2\Cuid2;
|
||||
|
||||
class Show extends Component
|
||||
{
|
||||
@@ -12,8 +11,6 @@ class Show extends Component
|
||||
|
||||
public bool $isReadOnly = false;
|
||||
|
||||
public ?string $modalId = null;
|
||||
|
||||
public bool $isFirst = true;
|
||||
|
||||
public bool $isService = false;
|
||||
@@ -32,11 +29,6 @@ class Show extends Component
|
||||
'host_path' => 'host',
|
||||
];
|
||||
|
||||
public function mount()
|
||||
{
|
||||
$this->modalId = new Cuid2(7);
|
||||
}
|
||||
|
||||
public function submit()
|
||||
{
|
||||
$this->validate();
|
||||
|
||||
@@ -3,32 +3,63 @@
|
||||
namespace App\Livewire\Project\Shared;
|
||||
|
||||
use App\Models\Tag;
|
||||
use Livewire\Attributes\Validate;
|
||||
use Livewire\Component;
|
||||
|
||||
// Refactored ✅
|
||||
class Tags extends Component
|
||||
{
|
||||
public $resource = null;
|
||||
|
||||
public ?string $new_tag = null;
|
||||
#[Validate('required|string|min:2')]
|
||||
public string $newTags;
|
||||
|
||||
public $tags = [];
|
||||
|
||||
protected $listeners = [
|
||||
'refresh' => '$refresh',
|
||||
];
|
||||
|
||||
protected $rules = [
|
||||
'resource.tags.*.name' => 'required|string|min:2',
|
||||
'new_tag' => 'required|string|min:2',
|
||||
];
|
||||
|
||||
protected $validationAttributes = [
|
||||
'new_tag' => 'tag',
|
||||
];
|
||||
public $filteredTags = [];
|
||||
|
||||
public function mount()
|
||||
{
|
||||
$this->loadTags();
|
||||
}
|
||||
|
||||
public function loadTags()
|
||||
{
|
||||
$this->tags = Tag::ownedByCurrentTeam()->get();
|
||||
$this->filteredTags = $this->tags->filter(function ($tag) {
|
||||
return ! $this->resource->tags->contains($tag);
|
||||
});
|
||||
}
|
||||
|
||||
public function submit()
|
||||
{
|
||||
try {
|
||||
$this->validate();
|
||||
$tags = str($this->newTags)->trim()->explode(' ');
|
||||
foreach ($tags as $tag) {
|
||||
if (strlen($tag) < 2) {
|
||||
$this->dispatch('error', 'Invalid tag.', "Tag <span class='dark:text-warning'>$tag</span> is invalid. Min length is 2.");
|
||||
|
||||
continue;
|
||||
}
|
||||
if ($this->resource->tags()->where('name', $tag)->exists()) {
|
||||
$this->dispatch('error', 'Duplicate tags.', "Tag <span class='dark:text-warning'>$tag</span> already added.");
|
||||
|
||||
continue;
|
||||
}
|
||||
$found = Tag::ownedByCurrentTeam()->where(['name' => $tag])->exists();
|
||||
if (! $found) {
|
||||
$found = Tag::create([
|
||||
'name' => $tag,
|
||||
'team_id' => currentTeam()->id,
|
||||
]);
|
||||
}
|
||||
$this->resource->tags()->attach($found->id);
|
||||
}
|
||||
$this->refresh();
|
||||
} catch (\Exception $e) {
|
||||
return handleError($e, $this);
|
||||
}
|
||||
}
|
||||
|
||||
public function addTag(string $id, string $name)
|
||||
@@ -39,8 +70,9 @@ class Tags extends Component
|
||||
|
||||
return;
|
||||
}
|
||||
$this->resource->tags()->syncWithoutDetaching($id);
|
||||
$this->resource->tags()->attach($id);
|
||||
$this->refresh();
|
||||
$this->dispatch('success', 'Tag added.');
|
||||
} catch (\Exception $e) {
|
||||
return handleError($e, $this);
|
||||
}
|
||||
@@ -50,12 +82,12 @@ class Tags extends Component
|
||||
{
|
||||
try {
|
||||
$this->resource->tags()->detach($id);
|
||||
|
||||
$found_more_tags = Tag::where(['id' => $id, 'team_id' => currentTeam()->id])->first();
|
||||
if ($found_more_tags->applications()->count() == 0 && $found_more_tags->services()->count() == 0) {
|
||||
$found_more_tags = Tag::ownedByCurrentTeam()->find($id);
|
||||
if ($found_more_tags && $found_more_tags->applications()->count() == 0 && $found_more_tags->services()->count() == 0) {
|
||||
$found_more_tags->delete();
|
||||
}
|
||||
$this->refresh();
|
||||
$this->dispatch('success', 'Tag deleted.');
|
||||
} catch (\Exception $e) {
|
||||
return handleError($e, $this);
|
||||
}
|
||||
@@ -63,41 +95,8 @@ class Tags extends Component
|
||||
|
||||
public function refresh()
|
||||
{
|
||||
$this->resource->load(['tags']);
|
||||
$this->tags = Tag::ownedByCurrentTeam()->get();
|
||||
$this->new_tag = null;
|
||||
}
|
||||
|
||||
public function submit()
|
||||
{
|
||||
try {
|
||||
$this->validate([
|
||||
'new_tag' => 'required|string|min:2',
|
||||
]);
|
||||
$tags = str($this->new_tag)->trim()->explode(' ');
|
||||
foreach ($tags as $tag) {
|
||||
if ($this->resource->tags()->where('name', $tag)->exists()) {
|
||||
$this->dispatch('error', 'Duplicate tags.', "Tag <span class='dark:text-warning'>$tag</span> already added.");
|
||||
|
||||
continue;
|
||||
}
|
||||
$found = Tag::where(['name' => $tag, 'team_id' => currentTeam()->id])->first();
|
||||
if (! $found) {
|
||||
$found = Tag::create([
|
||||
'name' => $tag,
|
||||
'team_id' => currentTeam()->id,
|
||||
]);
|
||||
}
|
||||
$this->resource->tags()->syncWithoutDetaching($found->id);
|
||||
}
|
||||
$this->refresh();
|
||||
} catch (\Exception $e) {
|
||||
return handleError($e, $this);
|
||||
}
|
||||
}
|
||||
|
||||
public function render()
|
||||
{
|
||||
return view('livewire.project.shared.tags');
|
||||
$this->resource->refresh(); // Remove this when legacy_model_binding is false
|
||||
$this->loadTags();
|
||||
$this->reset('newTags');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,49 +4,61 @@ namespace App\Livewire\Project\Shared;
|
||||
|
||||
use Livewire\Component;
|
||||
|
||||
// Refactored ✅
|
||||
class Webhooks extends Component
|
||||
{
|
||||
public $resource;
|
||||
|
||||
public ?string $deploywebhook = null;
|
||||
public ?string $deploywebhook;
|
||||
|
||||
public ?string $githubManualWebhook = null;
|
||||
public ?string $githubManualWebhook;
|
||||
|
||||
public ?string $gitlabManualWebhook = null;
|
||||
public ?string $gitlabManualWebhook;
|
||||
|
||||
public ?string $bitbucketManualWebhook = null;
|
||||
public ?string $bitbucketManualWebhook;
|
||||
|
||||
public ?string $giteaManualWebhook = null;
|
||||
public ?string $giteaManualWebhook;
|
||||
|
||||
protected $rules = [
|
||||
'resource.manual_webhook_secret_github' => 'nullable|string',
|
||||
'resource.manual_webhook_secret_gitlab' => 'nullable|string',
|
||||
'resource.manual_webhook_secret_bitbucket' => 'nullable|string',
|
||||
'resource.manual_webhook_secret_gitea' => 'nullable|string',
|
||||
];
|
||||
public ?string $githubManualWebhookSecret = null;
|
||||
|
||||
public function saveSecret()
|
||||
public ?string $gitlabManualWebhookSecret = null;
|
||||
|
||||
public ?string $bitbucketManualWebhookSecret = null;
|
||||
|
||||
public ?string $giteaManualWebhookSecret = null;
|
||||
|
||||
public function mount()
|
||||
{
|
||||
// ray()->clearAll();
|
||||
// ray()->showQueries();
|
||||
$this->deploywebhook = generateDeployWebhook($this->resource);
|
||||
|
||||
$this->githubManualWebhookSecret = data_get($this->resource, 'manual_webhook_secret_github');
|
||||
$this->githubManualWebhook = generateGitManualWebhook($this->resource, 'github');
|
||||
|
||||
$this->gitlabManualWebhookSecret = data_get($this->resource, 'manual_webhook_secret_gitlab');
|
||||
$this->gitlabManualWebhook = generateGitManualWebhook($this->resource, 'gitlab');
|
||||
|
||||
$this->bitbucketManualWebhookSecret = data_get($this->resource, 'manual_webhook_secret_bitbucket');
|
||||
$this->bitbucketManualWebhook = generateGitManualWebhook($this->resource, 'bitbucket');
|
||||
|
||||
$this->giteaManualWebhookSecret = data_get($this->resource, 'manual_webhook_secret_gitea');
|
||||
$this->giteaManualWebhook = generateGitManualWebhook($this->resource, 'gitea');
|
||||
}
|
||||
|
||||
public function submit()
|
||||
{
|
||||
try {
|
||||
$this->validate();
|
||||
$this->resource->save();
|
||||
$this->authorize('update', $this->resource);
|
||||
$this->resource->update([
|
||||
'manual_webhook_secret_github' => $this->githubManualWebhookSecret,
|
||||
'manual_webhook_secret_gitlab' => $this->gitlabManualWebhookSecret,
|
||||
'manual_webhook_secret_bitbucket' => $this->bitbucketManualWebhookSecret,
|
||||
'manual_webhook_secret_gitea' => $this->giteaManualWebhookSecret,
|
||||
]);
|
||||
$this->dispatch('success', 'Secret Saved.');
|
||||
} catch (\Exception $e) {
|
||||
return handleError($e, $this);
|
||||
}
|
||||
}
|
||||
|
||||
public function mount()
|
||||
{
|
||||
$this->deploywebhook = generateDeployWebhook($this->resource);
|
||||
$this->githubManualWebhook = generateGitManualWebhook($this->resource, 'github');
|
||||
$this->gitlabManualWebhook = generateGitManualWebhook($this->resource, 'gitlab');
|
||||
$this->bitbucketManualWebhook = generateGitManualWebhook($this->resource, 'bitbucket');
|
||||
$this->giteaManualWebhook = generateGitManualWebhook($this->resource, 'gitea');
|
||||
}
|
||||
|
||||
public function render()
|
||||
{
|
||||
return view('livewire.project.shared.webhooks');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ class Index extends Component
|
||||
public function mount()
|
||||
{
|
||||
if (isInstanceAdmin()) {
|
||||
$settings = InstanceSettings::get();
|
||||
$settings = \App\Models\InstanceSettings::get();
|
||||
$database = StandalonePostgresql::whereName('coolify-db')->first();
|
||||
$s3s = S3Storage::whereTeamId(0)->get() ?? [];
|
||||
if ($database) {
|
||||
|
||||
@@ -29,7 +29,7 @@ class License extends Component
|
||||
abort(404);
|
||||
}
|
||||
$this->instance_id = config('app.id');
|
||||
$this->settings = InstanceSettings::get();
|
||||
$this->settings = \App\Models\InstanceSettings::get();
|
||||
}
|
||||
|
||||
public function render()
|
||||
|
||||
@@ -4,7 +4,6 @@ namespace App\Livewire\Source\Github;
|
||||
|
||||
use App\Jobs\GithubAppPermissionJob;
|
||||
use App\Models\GithubApp;
|
||||
use App\Models\InstanceSettings;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
use Livewire\Component;
|
||||
|
||||
@@ -100,7 +99,7 @@ class Change extends Component
|
||||
return redirect()->route('source.all');
|
||||
}
|
||||
$this->applications = $this->github_app->applications;
|
||||
$settings = InstanceSettings::get();
|
||||
$settings = \App\Models\InstanceSettings::get();
|
||||
$this->github_app->makeVisible('client_secret')->makeVisible('webhook_secret');
|
||||
|
||||
$this->name = str($this->github_app->name)->kebab();
|
||||
|
||||
@@ -23,7 +23,7 @@ class Index extends Component
|
||||
if (data_get(currentTeam(), 'subscription') && isSubscriptionActive()) {
|
||||
return redirect()->route('subscription.show');
|
||||
}
|
||||
$this->settings = InstanceSettings::get();
|
||||
$this->settings = \App\Models\InstanceSettings::get();
|
||||
$this->alreadySubscribed = currentTeam()->subscription()->exists();
|
||||
}
|
||||
|
||||
|
||||
@@ -1081,45 +1081,55 @@ class Application extends BaseModel
|
||||
'git read-tree -mu HEAD',
|
||||
"cat .$workdir$composeFile",
|
||||
]);
|
||||
$composeFileContent = instant_remote_process($commands, $this->destination->server, false);
|
||||
if (! $composeFileContent) {
|
||||
try {
|
||||
$composeFileContent = instant_remote_process($commands, $this->destination->server);
|
||||
} catch (\Exception $e) {
|
||||
if (str($e->getMessage())->contains('No such file')) {
|
||||
throw new \RuntimeException("Docker Compose file not found at: $workdir$composeFile<br><br>Check if you used the right extension (.yaml or .yml) in the compose file name.");
|
||||
}
|
||||
if (str($e->getMessage())->contains('fatal: repository') && str($e->getMessage())->contains('does not exist')) {
|
||||
if ($this->deploymentType() === 'deploy_key') {
|
||||
throw new \RuntimeException('Your deploy key does not have access to the repository. Please check your deploy key and try again.');
|
||||
}
|
||||
throw new \RuntimeException('Repository does not exist. Please check your repository URL and try again.');
|
||||
}
|
||||
throw new \RuntimeException($e->getMessage());
|
||||
} finally {
|
||||
$this->docker_compose_location = $initialDockerComposeLocation;
|
||||
$this->save();
|
||||
$commands = collect([
|
||||
"rm -rf /tmp/{$uuid}",
|
||||
]);
|
||||
instant_remote_process($commands, $this->destination->server, false);
|
||||
throw new \RuntimeException("Docker Compose file not found at: $workdir$composeFile<br><br>Check if you used the right extension (.yaml or .yml) in the compose file name.");
|
||||
} else {
|
||||
}
|
||||
if ($composeFileContent) {
|
||||
$this->docker_compose_raw = $composeFileContent;
|
||||
$this->save();
|
||||
}
|
||||
|
||||
$commands = collect([
|
||||
"rm -rf /tmp/{$uuid}",
|
||||
]);
|
||||
instant_remote_process($commands, $this->destination->server, false);
|
||||
$parsedServices = $this->parseCompose();
|
||||
if ($this->docker_compose_domains) {
|
||||
$json = collect(json_decode($this->docker_compose_domains));
|
||||
$names = collect(data_get($parsedServices, 'services'))->keys()->toArray();
|
||||
$jsonNames = $json->keys()->toArray();
|
||||
$diff = array_diff($jsonNames, $names);
|
||||
$json = $json->filter(function ($value, $key) use ($diff) {
|
||||
return ! in_array($key, $diff);
|
||||
});
|
||||
if ($json) {
|
||||
$this->docker_compose_domains = json_encode($json);
|
||||
} else {
|
||||
$this->docker_compose_domains = null;
|
||||
$parsedServices = $this->parseCompose();
|
||||
if ($this->docker_compose_domains) {
|
||||
$json = collect(json_decode($this->docker_compose_domains));
|
||||
$names = collect(data_get($parsedServices, 'services'))->keys()->toArray();
|
||||
$jsonNames = $json->keys()->toArray();
|
||||
$diff = array_diff($jsonNames, $names);
|
||||
$json = $json->filter(function ($value, $key) use ($diff) {
|
||||
return ! in_array($key, $diff);
|
||||
});
|
||||
if ($json) {
|
||||
$this->docker_compose_domains = json_encode($json);
|
||||
} else {
|
||||
$this->docker_compose_domains = null;
|
||||
}
|
||||
$this->save();
|
||||
}
|
||||
$this->save();
|
||||
|
||||
return [
|
||||
'parsedServices' => $parsedServices,
|
||||
'initialDockerComposeLocation' => $this->docker_compose_location,
|
||||
];
|
||||
} else {
|
||||
throw new \RuntimeException("Docker Compose file not found at: $workdir$composeFile<br><br>Check if you used the right extension (.yaml or .yml) in the compose file name.");
|
||||
}
|
||||
|
||||
return [
|
||||
'parsedServices' => $parsedServices,
|
||||
'initialDockerComposeLocation' => $this->docker_compose_location,
|
||||
];
|
||||
}
|
||||
|
||||
public function parseContainerLabels(?ApplicationPreview $preview = null)
|
||||
|
||||
@@ -318,7 +318,7 @@ respond 404
|
||||
|
||||
public function setupDynamicProxyConfiguration()
|
||||
{
|
||||
$settings = InstanceSettings::get();
|
||||
$settings = \App\Models\InstanceSettings::get();
|
||||
$dynamic_config_path = $this->proxyPath().'/dynamic';
|
||||
if ($this->proxyType() === 'TRAEFIK_V2') {
|
||||
$file = "$dynamic_config_path/coolify.yaml";
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
namespace App\Notifications\Channels;
|
||||
|
||||
use App\Models\InstanceSettings;
|
||||
use App\Models\User;
|
||||
use Exception;
|
||||
use Illuminate\Mail\Message;
|
||||
@@ -14,7 +13,7 @@ class TransactionalEmailChannel
|
||||
{
|
||||
public function send(User $notifiable, Notification $notification): void
|
||||
{
|
||||
$settings = InstanceSettings::get();
|
||||
$settings = \App\Models\InstanceSettings::get();
|
||||
if (! data_get($settings, 'smtp_enabled') && ! data_get($settings, 'resend_enabled')) {
|
||||
Log::info('SMTP/Resend not enabled');
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ class ResetPassword extends Notification
|
||||
|
||||
public function __construct($token)
|
||||
{
|
||||
$this->settings = InstanceSettings::get();
|
||||
$this->settings = \App\Models\InstanceSettings::get();
|
||||
$this->token = $token;
|
||||
}
|
||||
|
||||
|
||||
@@ -2,8 +2,10 @@
|
||||
|
||||
namespace App\Providers;
|
||||
|
||||
use App\Models\InstanceSettings;
|
||||
use App\Models\PersonalAccessToken;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
use Illuminate\Support\Facades\View;
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
use Laravel\Sanctum\Sanctum;
|
||||
|
||||
@@ -14,6 +16,7 @@ class AppServiceProvider extends ServiceProvider
|
||||
public function boot(): void
|
||||
{
|
||||
Sanctum::usePersonalAccessTokenModel(PersonalAccessToken::class);
|
||||
|
||||
Http::macro('github', function (string $api_url, ?string $github_access_token = null) {
|
||||
if ($github_access_token) {
|
||||
return Http::withHeaders([
|
||||
@@ -27,5 +30,9 @@ class AppServiceProvider extends ServiceProvider
|
||||
])->baseUrl($api_url);
|
||||
}
|
||||
});
|
||||
// if (! env('CI')) {
|
||||
// View::share('instanceSettings', InstanceSettings::get());
|
||||
// }
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@ use App\Actions\Fortify\CreateNewUser;
|
||||
use App\Actions\Fortify\ResetUserPassword;
|
||||
use App\Actions\Fortify\UpdateUserPassword;
|
||||
use App\Actions\Fortify\UpdateUserProfileInformation;
|
||||
use App\Models\InstanceSettings;
|
||||
use App\Models\OauthSetting;
|
||||
use App\Models\User;
|
||||
use Illuminate\Cache\RateLimiting\Limit;
|
||||
@@ -45,7 +44,7 @@ class FortifyServiceProvider extends ServiceProvider
|
||||
{
|
||||
Fortify::createUsersUsing(CreateNewUser::class);
|
||||
Fortify::registerView(function () {
|
||||
$settings = InstanceSettings::get();
|
||||
$settings = \App\Models\InstanceSettings::get();
|
||||
if (! $settings->is_registration_enabled) {
|
||||
return redirect()->route('login');
|
||||
}
|
||||
@@ -57,7 +56,7 @@ class FortifyServiceProvider extends ServiceProvider
|
||||
});
|
||||
|
||||
Fortify::loginView(function () {
|
||||
$settings = InstanceSettings::get();
|
||||
$settings = \App\Models\InstanceSettings::get();
|
||||
$enabled_oauth_providers = OauthSetting::where('enabled', true)->get();
|
||||
$users = User::count();
|
||||
if ($users == 0) {
|
||||
|
||||
@@ -40,6 +40,7 @@ const SUPPORTED_OS = [
|
||||
'ubuntu debian raspbian',
|
||||
'centos fedora rhel ol rocky amzn almalinux',
|
||||
'sles opensuse-leap opensuse-tumbleweed',
|
||||
'arch',
|
||||
];
|
||||
|
||||
const SHARED_VARIABLE_TYPES = ['team', 'project', 'environment'];
|
||||
|
||||
@@ -88,6 +88,9 @@ function updateCompose(ServiceApplication|ServiceDatabase $resource)
|
||||
try {
|
||||
$name = data_get($resource, 'name');
|
||||
$dockerComposeRaw = data_get($resource, 'service.docker_compose_raw');
|
||||
if (! $dockerComposeRaw) {
|
||||
throw new \Exception('No compose file found or not a valid YAML file.');
|
||||
}
|
||||
$dockerCompose = Yaml::parse($dockerComposeRaw);
|
||||
|
||||
// Switch Image
|
||||
@@ -106,7 +109,7 @@ function updateCompose(ServiceApplication|ServiceDatabase $resource)
|
||||
if ($resourceFqdns->count() === 1) {
|
||||
$resourceFqdns = $resourceFqdns->first();
|
||||
$variableName = 'SERVICE_FQDN_'.str($resource->name)->upper()->replace('-', '');
|
||||
$generatedEnv = EnvironmentVariable::where('service_id', $resource->service_id)->where('key', $variableName)->first();
|
||||
$generatedEnv = EnvironmentVariable::where('service_id', $resource->service_id)->where('key', 'LIKE', "{$variableName}_%")->first();
|
||||
$fqdn = Url::fromString($resourceFqdns);
|
||||
$port = $fqdn->getPort();
|
||||
$path = $fqdn->getPath();
|
||||
@@ -125,7 +128,7 @@ function updateCompose(ServiceApplication|ServiceDatabase $resource)
|
||||
}
|
||||
}
|
||||
$variableName = 'SERVICE_URL_'.str($resource->name)->upper()->replace('-', '');
|
||||
$generatedEnv = EnvironmentVariable::where('service_id', $resource->service_id)->where('key', $variableName)->first();
|
||||
$generatedEnv = EnvironmentVariable::where('service_id', $resource->service_id)->where('key', 'LIKE', "{$variableName}_%")->first();
|
||||
$url = Url::fromString($fqdn);
|
||||
$port = $url->getPort();
|
||||
$path = $url->getPath();
|
||||
|
||||
@@ -244,13 +244,13 @@ function generate_application_name(string $git_repository, string $git_branch, ?
|
||||
|
||||
function is_transactional_emails_active(): bool
|
||||
{
|
||||
return isEmailEnabled(InstanceSettings::get());
|
||||
return isEmailEnabled(\App\Models\InstanceSettings::get());
|
||||
}
|
||||
|
||||
function set_transanctional_email_settings(?InstanceSettings $settings = null): ?string
|
||||
{
|
||||
if (! $settings) {
|
||||
$settings = InstanceSettings::get();
|
||||
$settings = \App\Models\InstanceSettings::get();
|
||||
}
|
||||
config()->set('mail.from.address', data_get($settings, 'smtp_from_address'));
|
||||
config()->set('mail.from.name', data_get($settings, 'smtp_from_name'));
|
||||
@@ -284,7 +284,7 @@ function base_ip(): string
|
||||
if (isDev()) {
|
||||
return 'localhost';
|
||||
}
|
||||
$settings = InstanceSettings::get();
|
||||
$settings = \App\Models\InstanceSettings::get();
|
||||
if ($settings->public_ipv4) {
|
||||
return "$settings->public_ipv4";
|
||||
}
|
||||
@@ -312,7 +312,7 @@ function getFqdnWithoutPort(string $fqdn)
|
||||
*/
|
||||
function base_url(bool $withPort = true): string
|
||||
{
|
||||
$settings = InstanceSettings::get();
|
||||
$settings = \App\Models\InstanceSettings::get();
|
||||
if ($settings->fqdn) {
|
||||
return $settings->fqdn;
|
||||
}
|
||||
@@ -379,7 +379,7 @@ function send_internal_notification(string $message): void
|
||||
}
|
||||
function send_user_an_email(MailMessage $mail, string $email, ?string $cc = null): void
|
||||
{
|
||||
$settings = InstanceSettings::get();
|
||||
$settings = \App\Models\InstanceSettings::get();
|
||||
$type = set_transanctional_email_settings($settings);
|
||||
if (! $type) {
|
||||
throw new Exception('No email settings found.');
|
||||
@@ -774,6 +774,8 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal
|
||||
$allServices = get_service_templates();
|
||||
$topLevelVolumes = collect(data_get($yaml, 'volumes', []));
|
||||
$topLevelNetworks = collect(data_get($yaml, 'networks', []));
|
||||
$topLevelConfigs = collect(data_get($yaml, 'configs', []));
|
||||
$topLevelSecrets = collect(data_get($yaml, 'secrets', []));
|
||||
$services = data_get($yaml, 'services');
|
||||
|
||||
$generatedServiceFQDNS = collect([]);
|
||||
@@ -1402,6 +1404,8 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal
|
||||
'services' => $services->toArray(),
|
||||
'volumes' => $topLevelVolumes->toArray(),
|
||||
'networks' => $topLevelNetworks->toArray(),
|
||||
'configs' => $topLevelConfigs->toArray(),
|
||||
'secrets' => $topLevelSecrets->toArray(),
|
||||
];
|
||||
$yaml = data_forget($yaml, 'services.*.volumes.*.content');
|
||||
$resource->docker_compose_raw = Yaml::dump($yaml, 10, 2);
|
||||
@@ -1441,6 +1445,8 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal
|
||||
}
|
||||
|
||||
$topLevelNetworks = collect(data_get($yaml, 'networks', []));
|
||||
$topLevelConfigs = collect(data_get($yaml, 'configs', []));
|
||||
$topLevelSecrets = collect(data_get($yaml, 'secrets', []));
|
||||
$services = data_get($yaml, 'services');
|
||||
|
||||
$generatedServiceFQDNS = collect([]);
|
||||
@@ -2027,14 +2033,20 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal
|
||||
domains: $fqdns,
|
||||
serviceLabels: $serviceLabels,
|
||||
generate_unique_uuid: $resource->build_pack === 'dockercompose',
|
||||
image: data_get($service, 'image')
|
||||
image: data_get($service, 'image'),
|
||||
is_force_https_enabled: $resource->isForceHttpsEnabled(),
|
||||
is_gzip_enabled: $resource->isGzipEnabled(),
|
||||
is_stripprefix_enabled: $resource->isStripprefixEnabled(),
|
||||
));
|
||||
$serviceLabels = $serviceLabels->merge(fqdnLabelsForCaddy(
|
||||
network: $resource->destination->network,
|
||||
uuid: $resource->uuid,
|
||||
domains: $fqdns,
|
||||
serviceLabels: $serviceLabels,
|
||||
image: data_get($service, 'image')
|
||||
image: data_get($service, 'image'),
|
||||
is_force_https_enabled: $resource->isForceHttpsEnabled(),
|
||||
is_gzip_enabled: $resource->isGzipEnabled(),
|
||||
is_stripprefix_enabled: $resource->isStripprefixEnabled(),
|
||||
));
|
||||
}
|
||||
}
|
||||
@@ -2080,6 +2092,8 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal
|
||||
'services' => $services->toArray(),
|
||||
'volumes' => $topLevelVolumes->toArray(),
|
||||
'networks' => $topLevelNetworks->toArray(),
|
||||
'configs' => $topLevelConfigs->toArray(),
|
||||
'secrets' => $topLevelSecrets->toArray(),
|
||||
];
|
||||
if ($isSameDockerComposeFile) {
|
||||
$resource->docker_compose_raw = Yaml::dump($yaml, 10, 2);
|
||||
@@ -2244,7 +2258,7 @@ function validate_dns_entry(string $fqdn, Server $server)
|
||||
if (str($host)->contains('sslip.io')) {
|
||||
return true;
|
||||
}
|
||||
$settings = InstanceSettings::get();
|
||||
$settings = \App\Models\InstanceSettings::get();
|
||||
$is_dns_validation_enabled = data_get($settings, 'is_dns_validation_enabled');
|
||||
if (! $is_dns_validation_enabled) {
|
||||
return true;
|
||||
@@ -2364,7 +2378,7 @@ function checkIfDomainIsAlreadyUsed(Collection|array $domains, ?string $teamId =
|
||||
if ($domainFound) {
|
||||
return true;
|
||||
}
|
||||
$settings = InstanceSettings::get();
|
||||
$settings = \App\Models\InstanceSettings::get();
|
||||
if (data_get($settings, 'fqdn')) {
|
||||
$domain = data_get($settings, 'fqdn');
|
||||
if (str($domain)->endsWith('/')) {
|
||||
@@ -2381,7 +2395,6 @@ function check_domain_usage(ServiceApplication|Application|null $resource = null
|
||||
if ($resource) {
|
||||
if ($resource->getMorphClass() === 'App\Models\Application' && $resource->build_pack === 'dockercompose') {
|
||||
$domains = data_get(json_decode($resource->docker_compose_domains, true), '*.domain');
|
||||
ray($domains);
|
||||
$domains = collect($domains);
|
||||
} else {
|
||||
$domains = collect($resource->fqdns);
|
||||
@@ -2437,7 +2450,7 @@ function check_domain_usage(ServiceApplication|Application|null $resource = null
|
||||
}
|
||||
}
|
||||
if ($resource) {
|
||||
$settings = InstanceSettings::get();
|
||||
$settings = \App\Models\InstanceSettings::get();
|
||||
if (data_get($settings, 'fqdn')) {
|
||||
$domain = data_get($settings, 'fqdn');
|
||||
if (str($domain)->endsWith('/')) {
|
||||
@@ -2512,7 +2525,7 @@ function get_public_ips()
|
||||
{
|
||||
try {
|
||||
echo "Refreshing public ips!\n";
|
||||
$settings = InstanceSettings::get();
|
||||
$settings = \App\Models\InstanceSettings::get();
|
||||
[$first, $second] = Process::concurrently(function (Pool $pool) {
|
||||
$pool->path(__DIR__)->command('curl -4s https://ifconfig.io');
|
||||
$pool->path(__DIR__)->command('curl -6s https://ifconfig.io');
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
"poliander/cron": "^3.0",
|
||||
"purplepixie/phpdns": "^2.1",
|
||||
"pusher/pusher-php-server": "^7.2",
|
||||
"resend/resend-laravel": "^0.13.0",
|
||||
"sentry/sentry-laravel": "^4.6",
|
||||
"socialiteproviders/microsoft-azure": "^5.1",
|
||||
"spatie/laravel-activitylog": "^4.7.3",
|
||||
@@ -106,4 +107,4 @@
|
||||
},
|
||||
"minimum-stability": "stable",
|
||||
"prefer-stable": true
|
||||
}
|
||||
}
|
||||
|
||||
128
composer.lock
generated
128
composer.lock
generated
@@ -4,7 +4,7 @@
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "c7c9cc002a9765c2395717c69ba8bfc6",
|
||||
"content-hash": "cb17445966de6094aef5a92ee59d1d77",
|
||||
"packages": [
|
||||
{
|
||||
"name": "amphp/amp",
|
||||
@@ -7129,6 +7129,132 @@
|
||||
],
|
||||
"time": "2024-07-01T14:24:45+00:00"
|
||||
},
|
||||
{
|
||||
"name": "resend/resend-laravel",
|
||||
"version": "v0.13.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/resend/resend-laravel.git",
|
||||
"reference": "23aed22df0d0b23c2952da2aaed6a8b88d301a8a"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/resend/resend-laravel/zipball/23aed22df0d0b23c2952da2aaed6a8b88d301a8a",
|
||||
"reference": "23aed22df0d0b23c2952da2aaed6a8b88d301a8a",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"illuminate/http": "^10.0|^11.0",
|
||||
"illuminate/support": "^10.0|^11.0",
|
||||
"php": "^8.1",
|
||||
"resend/resend-php": "^0.12.0",
|
||||
"symfony/mailer": "^6.2|^7.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"friendsofphp/php-cs-fixer": "^3.14",
|
||||
"mockery/mockery": "^1.5",
|
||||
"orchestra/testbench": "^8.17|^9.0",
|
||||
"pestphp/pest": "^2.0"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-main": "1.x-dev"
|
||||
},
|
||||
"laravel": {
|
||||
"providers": [
|
||||
"Resend\\Laravel\\ResendServiceProvider"
|
||||
]
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Resend\\Laravel\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Resend and contributors",
|
||||
"homepage": "https://github.com/resend/resend-laravel/contributors"
|
||||
}
|
||||
],
|
||||
"description": "Resend for Laravel",
|
||||
"homepage": "https://resend.com/",
|
||||
"keywords": [
|
||||
"api",
|
||||
"client",
|
||||
"laravel",
|
||||
"php",
|
||||
"resend",
|
||||
"sdk"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/resend/resend-laravel/issues",
|
||||
"source": "https://github.com/resend/resend-laravel/tree/v0.13.0"
|
||||
},
|
||||
"time": "2024-07-08T18:51:42+00:00"
|
||||
},
|
||||
{
|
||||
"name": "resend/resend-php",
|
||||
"version": "v0.12.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/resend/resend-php.git",
|
||||
"reference": "37fb79bb8160ce2de521bf37484ba59e89236521"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/resend/resend-php/zipball/37fb79bb8160ce2de521bf37484ba59e89236521",
|
||||
"reference": "37fb79bb8160ce2de521bf37484ba59e89236521",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"guzzlehttp/guzzle": "^7.5",
|
||||
"php": "^8.1.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"friendsofphp/php-cs-fixer": "^3.13",
|
||||
"mockery/mockery": "^1.6",
|
||||
"pestphp/pest": "^2.0"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"files": [
|
||||
"src/Resend.php"
|
||||
],
|
||||
"psr-4": {
|
||||
"Resend\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Resend and contributors",
|
||||
"homepage": "https://github.com/resend/resend-php/contributors"
|
||||
}
|
||||
],
|
||||
"description": "Resend PHP library.",
|
||||
"homepage": "https://resend.com/",
|
||||
"keywords": [
|
||||
"api",
|
||||
"client",
|
||||
"php",
|
||||
"resend",
|
||||
"sdk"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/resend/resend-php/issues",
|
||||
"source": "https://github.com/resend/resend-php/tree/v0.12.0"
|
||||
},
|
||||
"time": "2024-03-04T03:16:28+00:00"
|
||||
},
|
||||
{
|
||||
"name": "revolt/event-loop",
|
||||
"version": "v1.0.6",
|
||||
|
||||
@@ -7,7 +7,7 @@ return [
|
||||
|
||||
// The release version of your application
|
||||
// Example with dynamic git hash: trim(exec('git --git-dir ' . base_path('.git') . ' log --pretty="%h" -n1 HEAD'))
|
||||
'release' => '4.0.0-beta.309',
|
||||
'release' => '4.0.0-beta.314',
|
||||
// When left empty or `null` the Laravel environment will be used
|
||||
'environment' => config('app.env'),
|
||||
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
<?php
|
||||
|
||||
return '4.0.0-beta.309';
|
||||
return '4.0.0-beta.314';
|
||||
|
||||
@@ -27,14 +27,14 @@ class InstanceSettingsSeeder extends Seeder
|
||||
$ipv4 = Process::run('curl -4s https://ifconfig.io')->output();
|
||||
$ipv4 = trim($ipv4);
|
||||
$ipv4 = filter_var($ipv4, FILTER_VALIDATE_IP);
|
||||
$settings = InstanceSettings::get();
|
||||
$settings = \App\Models\InstanceSettings::get();
|
||||
if (is_null($settings->public_ipv4) && $ipv4) {
|
||||
$settings->update(['public_ipv4' => $ipv4]);
|
||||
}
|
||||
$ipv6 = Process::run('curl -6s https://ifconfig.io')->output();
|
||||
$ipv6 = trim($ipv6);
|
||||
$ipv6 = filter_var($ipv6, FILTER_VALIDATE_IP);
|
||||
$settings = InstanceSettings::get();
|
||||
$settings = \App\Models\InstanceSettings::get();
|
||||
if (is_null($settings->public_ipv6) && $ipv6) {
|
||||
$settings->update(['public_ipv6' => $ipv6]);
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ ARG TARGETPLATFORM
|
||||
# https://github.com/cloudflare/cloudflared/releases
|
||||
ARG CLOUDFLARED_VERSION=2024.4.1
|
||||
ARG POSTGRES_VERSION=15
|
||||
ARG CI=true
|
||||
|
||||
WORKDIR /var/www/html
|
||||
|
||||
|
||||
1
other/logos/latitude.svg
Normal file
1
other/logos/latitude.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="349" height="64" fill="#ffffff" viewBox="0 0 349 64" ><path fill="#ffffff" d="M76.094 52V7.581h-6.917V52h6.917zM95.64 52.761c3.616 0 7.677-1.776 9.518-4.759V52h6.853V22.43h-6.853v3.997c-1.841-2.982-5.394-4.759-9.328-4.759-9.201 0-14.722 6.854-14.722 15.547 0 8.693 5.013 15.546 14.531 15.546zm1.015-6.155c-5.394 0-8.63-3.997-8.63-9.391s3.236-9.392 8.63-9.392c5.901 0 8.756 4.316 8.756 9.392s-2.855 9.391-8.756 9.391zM132.621 46.162c-2.729 0-4.315-.634-4.315-5.774V28.204h6.79V22.43h-6.79v-8.947h-6.917v8.947h-5.013v5.774h5.013v13.77c0 9.963 6.219 10.407 9.582 10.407 2.031 0 4.061-.19 5.14-.381v-6.092c-.698.127-2.411.254-3.49.254zM144.247 18.178c3.045 0 5.14-2.284 5.14-5.14 0-2.855-2.095-5.14-5.14-5.14-3.046 0-5.14 2.285-5.14 5.14 0 2.856 2.094 5.14 5.14 5.14zM147.673 52V22.43h-6.853V52h6.853zM168.299 46.162c-2.728 0-4.315-.634-4.315-5.774V28.204h6.79V22.43h-6.79v-8.947h-6.916v8.947h-5.013v5.774h5.013v13.77c0 9.963 6.218 10.407 9.581 10.407 2.031 0 4.061-.19 5.14-.381v-6.092c-.698.127-2.411.254-3.49.254zM187.159 52.761c4.251 0 7.361-1.713 9.137-4.886V52h6.917V22.43h-6.917v16.689c0 4.251-1.903 7.741-7.17 7.741-4.505 0-6.028-2.792-6.028-7.551v-16.88h-6.917v18.593c0 7.932 4.505 11.74 10.978 11.74zM232.247 26.427c-1.84-2.982-5.394-4.759-9.328-4.759-9.201 0-14.722 6.854-14.722 15.547 0 8.693 5.013 15.546 14.532 15.546 3.616 0 7.678-1.776 9.518-4.759V52h6.853V7.581h-6.853v18.846zm-8.503 20.18c-5.394 0-8.63-3.998-8.63-9.392 0-5.394 3.236-9.392 8.63-9.392 5.901 0 8.757 4.316 8.757 9.392s-2.856 9.391-8.757 9.391zM273.099 35.692c0-8.313-5.711-14.024-14.15-14.024-9.011 0-14.849 6.092-14.849 15.547 0 9.582 5.774 15.546 15.102 15.546 7.107 0 12.691-3.87 13.58-9.39h-6.98c-1.142 2.283-3.173 3.362-6.6 3.362-5.013 0-8.058-2.538-8.249-7.234h21.956c.127-1.65.19-2.601.19-3.807zm-22.146-1.46c.064-4.188 2.983-7.107 7.869-7.107 4.759 0 7.424 2.539 7.487 7.108h-15.356zM281.59 52.508c2.983 0 5.394-2.475 5.394-5.394s-2.411-5.33-5.394-5.33a5.321 5.321 0 00-5.33 5.33c0 2.919 2.348 5.394 5.33 5.394zM303.931 52.761c7.17 0 11.675-3.426 11.675-9.2 0-4.189-2.665-7.234-6.853-8.44l-5.901-1.713c-2.729-.762-3.681-1.84-3.681-3.427 0-1.777 1.777-3.046 4.252-3.046 3.236 0 5.14 1.46 5.14 3.934h6.789c0-5.71-4.441-9.2-11.675-9.2-6.6 0-11.359 3.68-11.359 8.693 0 4.188 2.348 7.17 6.473 8.312l5.901 1.587c3.173.825 3.871 1.84 3.871 3.49 0 2.094-1.65 3.49-4.252 3.49-3.553 0-6.028-1.777-6.028-4.315h-6.917c0 5.647 5.331 9.835 12.565 9.835zM337.5 21.668c-4.378 0-7.805 1.714-9.645 4.886V7.581h-6.916V52h6.916V35.755c0-5.203 2.538-8.185 7.044-8.185 4.822 0 6.472 2.728 6.472 9.01V52h6.917V33.408c0-7.742-3.681-11.74-10.788-11.74zM50.552 47.654l-5.29 15.762H14.805l5.29-15.762h30.457zM33.744.584H14.863L0 44.875h18.88L33.744.584z" data-darkreader-inline-fill="" style="--darkreader-inline-fill: #ffffff;"></path></svg>
|
||||
|
After Width: | Height: | Size: 2.8 KiB |
BIN
public/svgs/docmost.png
Normal file
BIN
public/svgs/docmost.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.3 KiB |
1
public/svgs/drupal.svg
Normal file
1
public/svgs/drupal.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="220.03239mm" height="167.50914mm" viewBox="0 0 623.71387 474.82906"><title>Risorsa 28</title><g id="Livello_2" data-name="Livello 2"><g id="Livello_1-2" data-name="Livello 1"><path d="M292.12129,345.00234h-26.212l.04275,49.04508c0,14.33211-6.14488,25.92692-20.477,25.92692-14.33924,0-20.54117-11.59481-20.54117-25.92692V345.04868H198.78953l-.00713,48.99874c0,28.32213,18.20655,51.27636,46.53223,51.27636,28.31849,0,46.79948-22.95423,46.79948-51.27636Z" style="fill:#009cde"/><rect x="528.48024" y="315.11614" width="26.08367" height="127.67755" style="fill:#009cde"/><polygon points="573.823 319.826 573.823 315.239 594.15 315.239 594.15 319.826 586.715 319.826 586.715 340.043 581.261 340.043 581.261 319.826 573.823 319.826" style="fill:#009cde"/><polygon points="604.673 315.24 610.476 332.295 610.544 332.295 616.029 315.24 623.714 315.24 623.714 340.044 618.606 340.044 618.606 322.465 618.535 322.465 612.458 340.044 608.252 340.044 602.175 322.64 602.103 322.64 602.103 340.044 596.999 340.044 596.999 315.24 604.673 315.24" style="fill:#009cde"/><path d="M177.46784,343.93624c-22.48375-5.18962-36.66617,17.148-37.25785,18.34557-.28871.58814-.2994.93035-1.29384.90533-.82337-.01773-.916-.90533-.916-.90533l-2.79086-17.08726H111.84157v97.51614h26.19419v-52.784c0-4.3128,11.61256-24.993,34.11766-19.67153,11.38088,2.69467,16.21054,7.52436,16.21054,7.52436V348.07087a41.85,41.85,0,0,0-10.89612-4.13463" style="fill:#009cde"/><path d="M353.05258,368.64446a26.13539,26.13539,0,1,1-26.13,26.13,26.13748,26.13748,0,0,1,26.13-26.13M327.664,474.82906V439.74191l.00712.00718.00713-13.14169s.03921-1.05141.98729-1.06218c.84474-.01066,1.03368.549,1.24041,1.06218,1.98529,4.94369,12.90641,23.76689,37.14374,17.86435A51.631,51.631,0,1,0,301.402,394.77446v80.0546Z" style="fill:#009cde"/><path d="M492.37655,394.77479a26.13539,26.13539,0,1,1-26.1336-26.13,26.139,26.139,0,0,1,26.1336,26.13m-.74494,47.9793H517.8935v-47.9793a51.62918,51.62918,0,1,0-65.64764,49.69381c24.23739,5.906,35.15845-12.92066,37.14374-17.86087.20673-.5132.39208-1.07284,1.24041-1.06566.94808.01425.98729,1.06566.98729,1.06566" style="fill:#009cde"/><path d="M36.905,337.16373h-10.529v83.26605l10.81417.278c22.18076,0,36.46656-2.01733,36.46656-41.90208,0-38.24519-12.61057-41.642-36.75172-41.642m-7.1108,105.38619H0V315.0649H31.96836c38.70852,0,68.06785,7.10374,68.06785,63.74083,0,56.09518-31.09872,63.74419-70.24206,63.74419" style="fill:#009cde"/><path d="M336.513,60.04433C316.67656,40.21728,297.75071,21.31654,292.11812,0c-5.63286,21.31654-24.56176,40.21728-44.39487,60.04433-29.74983,29.731-63.47995,63.42669-63.47995,113.96434a107.878,107.878,0,1,0,215.756,0c0-50.53435-33.72736-84.23329-63.48628-113.96434M230.09481,199.146c-6.61462-.22461-31.02654-42.30194,14.26152-87.1038l29.96891,32.73593a2.56174,2.56174,0,0,1-.20005,3.82276c-7.15132,7.33453-37.63207,37.90055-41.42061,48.46955-.782,2.18152-1.92407,2.099-2.60977,2.07556m62.02662,55.45668a37.10175,37.10175,0,0,1-37.102-37.102c0-9.39381,3.73446-17.765,9.24757-24.50685,6.68995-8.18054,27.84947-31.18907,27.84947-31.18907s20.83558,23.34627,27.79953,31.111a36.28369,36.28369,0,0,1,9.30744,24.58494,37.10209,37.10209,0,0,1-37.102,37.102m71.01314-60.16628c-.79965,1.74885-2.61363,4.66848-5.062,4.75761-4.36413.15894-4.83045-2.07721-8.05609-6.8511-7.08179-10.47987-68.88406-75.07043-80.44365-87.56214-10.16779-10.987-1.43181-18.733,2.62052-22.79219,5.084-5.09314,19.92417-19.92418,19.92417-19.92418s44.24974,41.984,62.6825,70.67071,12.08027,53.50972,8.33451,61.70129" style="fill:#009cde"/></g></g></svg>
|
||||
|
After Width: | Height: | Size: 3.5 KiB |
6
public/svgs/plane.svg
Normal file
6
public/svgs/plane.svg
Normal file
@@ -0,0 +1,6 @@
|
||||
<svg width="155" height="155" viewBox="0 0 155 155" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect x="37" y="64" width="27" height="27" fill="#4075FC"/>
|
||||
<rect x="91" y="64" width="27" height="27" fill="#4075FC"/>
|
||||
<rect x="64" y="91" width="27" height="27" fill="#4075FC"/>
|
||||
<rect x="64" y="36" width="54" height="28" fill="#4075FC"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 346 B |
@@ -8,7 +8,7 @@
|
||||
@use('App\Models\InstanceSettings')
|
||||
@php
|
||||
|
||||
$instanceSettings = InstanceSettings::first();
|
||||
$instanceSettings = \App\Models\InstanceSettings::get();
|
||||
$name = null;
|
||||
|
||||
if ($instanceSettings) {
|
||||
|
||||
@@ -109,7 +109,7 @@
|
||||
<livewire:project.service.storage :resource="$application" />
|
||||
</div>
|
||||
<div x-cloak x-show="activeTab === 'webhooks'">
|
||||
<livewire:project.shared.webhooks :resource="$application" />
|
||||
<livewire:project.shared.webhooks :resource="$application" lazy />
|
||||
</div>
|
||||
<div x-cloak x-show="activeTab === 'previews'">
|
||||
<livewire:project.application.previews :application="$application" />
|
||||
@@ -133,7 +133,7 @@
|
||||
<livewire:project.shared.metrics :resource="$application" />
|
||||
</div>
|
||||
<div x-cloak x-show="activeTab === 'tags'">
|
||||
<livewire:project.shared.tags :resource="$application" />
|
||||
<livewire:project.shared.tags :resource="$application" lazy />
|
||||
</div>
|
||||
<div x-cloak x-show="activeTab === 'danger'">
|
||||
<livewire:project.shared.danger :resource="$application" />
|
||||
|
||||
@@ -99,7 +99,7 @@
|
||||
<livewire:project.shared.metrics :resource="$database" />
|
||||
</div>
|
||||
<div x-cloak x-show="activeTab === 'tags'">
|
||||
<livewire:project.shared.tags :resource="$database" />
|
||||
<livewire:project.shared.tags :resource="$database" lazy />
|
||||
</div>
|
||||
<div x-cloak x-show="activeTab === 'danger'">
|
||||
<livewire:project.shared.danger :resource="$database" />
|
||||
|
||||
@@ -62,6 +62,15 @@
|
||||
<x-forms.input id="publish_directory" required label="Publish Directory" />
|
||||
@endif
|
||||
</div>
|
||||
@if ($build_pack === 'dockercompose')
|
||||
<x-forms.input placeholder="/" wire:model.blur="base_directory" label="Base Directory"
|
||||
helper="Directory to use as root. Useful for monorepos." />
|
||||
<x-forms.input placeholder="/docker-compose.yaml" id="docker_compose_location"
|
||||
label="Docker Compose Location"
|
||||
helper="It is calculated together with the Base Directory:<br><span class='dark:text-warning'>{{ Str::start($base_directory . $docker_compose_location, '/') }}</span>" />
|
||||
Compose file location in your repository:<span
|
||||
class='dark:text-warning'>{{ Str::start($base_directory . $docker_compose_location, '/') }}</span>
|
||||
@endif
|
||||
@if ($show_is_static)
|
||||
<x-forms.input type="number" required id="port" label="Port" :readonly="$is_static || $build_pack === 'static'" />
|
||||
<div class="w-52">
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
@endif
|
||||
</div>
|
||||
<div class="pb-4">Deploy any public or private Git repositories through a GitHub App.</div>
|
||||
|
||||
@if ($github_apps->count() !== 0)
|
||||
<h2 class="pt-4 pb-4">Select a Github App</h2>
|
||||
<div class="flex flex-col gap-2">
|
||||
@@ -92,6 +91,16 @@
|
||||
helper="If there is a build process involved (like Svelte, React, Next, etc..), please specify the output directory for the build assets." />
|
||||
@endif
|
||||
</div>
|
||||
@if ($build_pack === 'dockercompose')
|
||||
<x-forms.input placeholder="/" wire:model.blur="base_directory"
|
||||
label="Base Directory"
|
||||
helper="Directory to use as root. Useful for monorepos." />
|
||||
<x-forms.input placeholder="/docker-compose.yaml" id="docker_compose_location"
|
||||
label="Docker Compose Location"
|
||||
helper="It is calculated together with the Base Directory:<br><span class='dark:text-warning'>{{ Str::start($base_directory . $docker_compose_location, '/') }}</span>" />
|
||||
Compose file location in your repository:<span
|
||||
class='dark:text-warning'>{{ Str::start($base_directory . $docker_compose_location, '/') }}</span>
|
||||
@endif
|
||||
@if ($show_is_static)
|
||||
<x-forms.input type="number" id="port" label="Port" :readonly="$is_static || $build_pack === 'static'"
|
||||
helper="The port your application listens on." />
|
||||
|
||||
@@ -13,10 +13,6 @@
|
||||
</div>
|
||||
@if (!$branch_found)
|
||||
<div class="px-2 pt-4">
|
||||
<div class="flex flex-col pb-4">
|
||||
<div>Preselect branch (eg: main):</div>
|
||||
<div class='text-helper'>https://github.com/coollabsio/coolify-examples/tree/main</div>
|
||||
</div>
|
||||
<div>
|
||||
For example application deployments, checkout <a class="underline dark:text-white"
|
||||
href="https://github.com/coollabsio/coolify-examples/" target="_blank">Coolify
|
||||
@@ -51,6 +47,15 @@
|
||||
helper="If there is a build process involved (like Svelte, React, Next, etc..), please specify the output directory for the build assets." />
|
||||
@endif
|
||||
</div>
|
||||
@if ($build_pack === 'dockercompose')
|
||||
<x-forms.input placeholder="/" wire:model.blur="base_directory" label="Base Directory"
|
||||
helper="Directory to use as root. Useful for monorepos." />
|
||||
<x-forms.input placeholder="/docker-compose.yaml" id="docker_compose_location"
|
||||
label="Docker Compose Location"
|
||||
helper="It is calculated together with the Base Directory:<br><span class='dark:text-warning'>{{ Str::start($base_directory . $docker_compose_location, '/') }}</span>" />
|
||||
Compose file location in your repository:<span
|
||||
class='dark:text-warning'>{{ Str::start($base_directory . $docker_compose_location, '/') }}</span>
|
||||
@endif
|
||||
@if ($show_is_static)
|
||||
<x-forms.input type="number" id="port" label="Port" :readonly="$is_static || $build_pack === 'static'"
|
||||
helper="The port your application listens on." />
|
||||
@@ -59,10 +64,12 @@
|
||||
helper="If your application is a static site or the final build assets should be served as a static site, enable this." />
|
||||
</div>
|
||||
@endif
|
||||
@if ($build_pack === 'dockercompose' && isDev())
|
||||
<div class="dark:text-warning">If you choose Docker Compose based deployments, you cannot change it afterwards.</div>
|
||||
<x-forms.checkbox instantSave label="New Compose Services (only in dev mode)" id="new_compose_services"></x-forms.checkbox>
|
||||
@endif
|
||||
{{-- @if ($build_pack === 'dockercompose' && isDev())
|
||||
<div class="dark:text-warning">If you choose Docker Compose based deployments, you cannot
|
||||
change it afterwards.</div>
|
||||
<x-forms.checkbox instantSave label="New Compose Services (only in dev mode)"
|
||||
id="new_compose_services"></x-forms.checkbox>
|
||||
@endif --}}
|
||||
</div>
|
||||
<x-forms.button wire:click.prevent='submit'>
|
||||
Continue
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<x-forms.select wire:model.live="selectedEnvironment">
|
||||
<option value="edit">Create/Edit Environments</option>
|
||||
<option value="edit">Create / Edit</option>
|
||||
<option disabled>-----</option>
|
||||
@foreach ($environments as $environment)
|
||||
<option value="{{ $environment->name }}">{{ $environment->name }}
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<x-forms.checkbox id="is_multiline" label="Is Multiline?" />
|
||||
@if (!$shared)
|
||||
<x-forms.checkbox id="is_literal"
|
||||
helper="This means that when you use $VARIABLES in a value, it should be interpreted as the actual characters '$VARIABLES' and not as the value of a variable named VARIABLE.<br><br>Useful if you have $ sign in your value and there are some characters after it, but you would not like to interpolate it form another value. In this case, you should set this to true."
|
||||
helper="This means that when you use $VARIABLES in a value, it should be interpreted as the actual characters '$VARIABLES' and not as the value of a variable named VARIABLE.<br><br>Useful if you have $ sign in your value and there are some characters after it, but you would not like to interpolate it from another value. In this case, you should set this to true."
|
||||
label="Is Literal?" />
|
||||
@endif
|
||||
<x-forms.button type="submit" @click="slideOverOpen=false">
|
||||
|
||||
@@ -55,7 +55,7 @@
|
||||
@if ($env->is_shared)
|
||||
<x-forms.checkbox instantSave id="env.is_build_time" label="Build Variable?" />
|
||||
<x-forms.checkbox instantSave id="env.is_literal"
|
||||
helper="This means that when you use $VARIABLES in a value, it should be interpreted as the actual characters '$VARIABLES' and not as the value of a variable named VARIABLE.<br><br>Useful if you have $ sign in your value and there are some characters after it, but you would not like to interpolate it form another value. In this case, you should set this to true."
|
||||
helper="This means that when you use $VARIABLES in a value, it should be interpreted as the actual characters '$VARIABLES' and not as the value of a variable named VARIABLE.<br><br>Useful if you have $ sign in your value and there are some characters after it, but you would not like to interpolate it from another value. In this case, you should set this to true."
|
||||
label="Is Literal?" />
|
||||
@else
|
||||
@if ($isSharedVariable)
|
||||
@@ -65,7 +65,7 @@
|
||||
<x-forms.checkbox instantSave id="env.is_multiline" label="Is Multiline?" />
|
||||
@if (!data_get($env, 'is_multiline'))
|
||||
<x-forms.checkbox instantSave id="env.is_literal"
|
||||
helper="This means that when you use $VARIABLES in a value, it should be interpreted as the actual characters '$VARIABLES' and not as the value of a variable named VARIABLE.<br><br>Useful if you have $ sign in your value and there are some characters after it, but you would not like to interpolate it form another value. In this case, you should set this to true."
|
||||
helper="This means that when you use $VARIABLES in a value, it should be interpreted as the actual characters '$VARIABLES' and not as the value of a variable named VARIABLE.<br><br>Useful if you have $ sign in your value and there are some characters after it, but you would not like to interpolate it from another value. In this case, you should set this to true."
|
||||
label="Is Literal?" />
|
||||
@endif
|
||||
@endif
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
it.</div>
|
||||
@else
|
||||
@if (!str($resource->status)->contains('running'))
|
||||
<div class="alert alert-warning">Metrics are only available when the application is running!</div>
|
||||
<div class="alert alert-warning">Metrics are only available when this resource is running!</div>
|
||||
@else
|
||||
<x-forms.select label="Interval" wire:change="setInterval" id="interval">
|
||||
<option value="5">5 minutes (live)</option>
|
||||
|
||||
@@ -15,15 +15,17 @@
|
||||
<x-forms.input id="storage.host_path" readonly helper="Directory on the host system."
|
||||
label="Source Path"
|
||||
helper="Warning: Changing the source path after the initial start could cause problems. Only use it when you know what are you doing." />
|
||||
<x-forms.input id="storage.mount_path" label="Destination Path"
|
||||
helper="Directory inside the container." required readonly />
|
||||
@else
|
||||
<x-forms.input id="storage.host_path" helper="Directory on the host system." label="Source Path"
|
||||
helper="Warning: Changing the source path after the initial start could cause problems. Only use it when you know what are you doing." />
|
||||
<x-forms.input id="storage.mount_path" label="Destination Path"
|
||||
helper="Directory inside the container." required readonly />
|
||||
<x-forms.button type="submit">
|
||||
Update
|
||||
</x-forms.button>
|
||||
@endif
|
||||
<x-forms.input id="storage.mount_path" label="Destination Path" helper="Directory inside the container."
|
||||
required readonly />
|
||||
<x-forms.button type="submit">
|
||||
Update
|
||||
</x-forms.button>
|
||||
@else
|
||||
<x-forms.input id="storage.name" required readonly />
|
||||
<x-forms.input id="storage.host_path" readonly />
|
||||
|
||||
@@ -1,10 +1,18 @@
|
||||
<div>
|
||||
<h2>Tags</h2>
|
||||
<div class="flex flex-wrap gap-2 pt-4">
|
||||
@if (data_get($this->resource, 'tags'))
|
||||
@forelse (data_get($this->resource,'tags') as $tagId => $tag)
|
||||
<div
|
||||
class="px-2 py-1 text-center rounded select-none dark:text-white w-fit bg-neutral-200 hover:bg-neutral-300 dark:bg-coolgray-100 dark:hover:bg-coolgray-200">
|
||||
<form wire:submit='submit' class="flex items-end gap-2">
|
||||
<div class="w-64">
|
||||
<x-forms.input label="Create new or assign existing tags"
|
||||
helper="You add more at once with space separated list: web api something<br><br>If the tag does not exists, it will be created."
|
||||
wire:model="newTags" placeholder="example: prod app1 user" />
|
||||
</div>
|
||||
<x-forms.button type="submit">Add</x-forms.button>
|
||||
</form>
|
||||
@if (data_get($this->resource, 'tags') && count(data_get($this->resource, 'tags')) > 0)
|
||||
<h3 class="pt-4">Assigned Tags</h3>
|
||||
<div class="flex flex-wrap gap-2 pt-4">
|
||||
@foreach (data_get($this->resource, 'tags') as $tagId => $tag)
|
||||
<div class="button">
|
||||
{{ $tag->name }}
|
||||
<svg wire:click="deleteTag('{{ $tag->id }}')" xmlns="http://www.w3.org/2000/svg" fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
@@ -13,24 +21,14 @@
|
||||
</path>
|
||||
</svg>
|
||||
</div>
|
||||
@empty
|
||||
<div class="py-1">No tags yet</div>
|
||||
@endforelse
|
||||
@endif
|
||||
</div>
|
||||
<form wire:submit='submit' class="flex items-end gap-2 pt-4">
|
||||
<div class="w-64">
|
||||
<x-forms.input label="Create new or assign existing tags"
|
||||
helper="You add more at once with space separated list: web api something<br><br>If the tag does not exists, it will be created."
|
||||
wire:model="new_tag" />
|
||||
@endforeach
|
||||
</div>
|
||||
<x-forms.button type="submit">Add</x-forms.button>
|
||||
</form>
|
||||
@if (count($tags) > 0)
|
||||
@endif
|
||||
@if (count($filteredTags) > 0)
|
||||
<h3 class="pt-4">Exisiting Tags</h3>
|
||||
<div>Click to add quickly</div>
|
||||
<div class="flex flex-wrap gap-2 pt-4">
|
||||
@foreach ($tags as $tag)
|
||||
@foreach ($filteredTags as $tag)
|
||||
<x-forms.button wire:click="addTag('{{ $tag->id }}','{{ $tag->name }}')">
|
||||
{{ $tag->name }}</x-forms.button>
|
||||
@endforeach
|
||||
|
||||
@@ -13,13 +13,13 @@
|
||||
<div>
|
||||
<h3>Manual Git Webhooks</h3>
|
||||
@if ($githubManualWebhook && $gitlabManualWebhook)
|
||||
<form wire:submit='saveSecret' class="flex flex-col gap-2">
|
||||
<form wire:submit='submit' class="flex flex-col gap-2">
|
||||
<div class="flex items-end gap-2">
|
||||
<x-forms.input helper="Content Type in GitHub configuration could be json or form-urlencoded."
|
||||
readonly label="GitHub" id="githubManualWebhook"></x-forms.input>
|
||||
<x-forms.input type="password"
|
||||
helper="Need to set a secret to be able to use this webhook. It should match with the secret in GitHub."
|
||||
label="GitHub Webhook Secret" id="resource.manual_webhook_secret_github"></x-forms.input>
|
||||
label="GitHub Webhook Secret" id="githubManualWebhookSecret"></x-forms.input>
|
||||
|
||||
</div>
|
||||
<a target="_blank" class="flex hover:no-underline" href="{{ $resource?->gitWebhook }}">
|
||||
@@ -31,21 +31,19 @@
|
||||
<x-forms.input readonly label="GitLab" id="gitlabManualWebhook"></x-forms.input>
|
||||
<x-forms.input type="password"
|
||||
helper="Need to set a secret to be able to use this webhook. It should match with the secret in GitLab."
|
||||
label="GitLab Webhook Secret" id="resource.manual_webhook_secret_gitlab"></x-forms.input>
|
||||
label="GitLab Webhook Secret" id="gitlabManualWebhookSecret"></x-forms.input>
|
||||
</div>
|
||||
<div class="flex gap-2">
|
||||
<x-forms.input readonly label="Bitbucket" id="bitbucketManualWebhook"></x-forms.input>
|
||||
<x-forms.input type="password"
|
||||
helper="Need to set a secret to be able to use this webhook. It should match with the secret in Bitbucket."
|
||||
label="Bitbucket Webhook Secret"
|
||||
id="resource.manual_webhook_secret_bitbucket"></x-forms.input>
|
||||
label="Bitbucket Webhook Secret" id="bitbucketManualWebhookSecret"></x-forms.input>
|
||||
</div>
|
||||
<div class="flex gap-2">
|
||||
<x-forms.input readonly label="Gitea" id="giteaManualWebhook"></x-forms.input>
|
||||
<x-forms.input type="password"
|
||||
helper="Need to set a secret to be able to use this webhook. It should match with the secret in Gitea."
|
||||
label="Gitea Webhook Secret"
|
||||
id="resource.manual_webhook_secret_gitea"></x-forms.input>
|
||||
label="Gitea Webhook Secret" id="giteaManualWebhookSecret"></x-forms.input>
|
||||
</div>
|
||||
<x-forms.button type="submit">Save</x-forms.button>
|
||||
</form>
|
||||
|
||||
@@ -146,15 +146,13 @@
|
||||
</div>
|
||||
<div class="flex items-center gap-2 pt-4 pb-2">
|
||||
<h3>Sentinel</h3>
|
||||
@if ($server->isSentinelEnabled())
|
||||
<x-forms.button wire:click='restartSentinel'>Restart</x-forms.button>
|
||||
@endif
|
||||
{{-- @if ($server->isSentinelEnabled()) --}}
|
||||
{{-- <x-forms.button wire:click='restartSentinel'>Restart</x-forms.button> --}}
|
||||
{{-- @endif --}}
|
||||
</div>
|
||||
<div class="w-64">
|
||||
<div>Metrics are disabled until a few bugs are fixed.</div>
|
||||
{{-- <div class="w-64">
|
||||
<x-forms.checkbox instantSave id="server.settings.is_metrics_enabled" label="Enable Metrics" />
|
||||
{{-- <x-forms.checkbox instantSave id="server.settings.is_server_api_enabled" label="Enable Server API"
|
||||
helper="You need to open port 12172 on your firewall. This API will be used to gather data from your server, which makes Coolify a lot faster than relying on SSH connections." />
|
||||
<x-forms.button wire:click='checkPortForServerApi'>Check Port for Server API</x-forms.button> --}}
|
||||
</div>
|
||||
<div class="pt-4">
|
||||
<div class="flex flex-wrap gap-2 sm:flex-nowrap">
|
||||
@@ -166,7 +164,7 @@
|
||||
<x-forms.input id="server.settings.metrics_history_days" label="Metrics history (days)" required
|
||||
helper="How many days should the metrics data should be reserved." />
|
||||
</div>
|
||||
</div>
|
||||
</div> --}}
|
||||
@endif
|
||||
</form>
|
||||
</div>
|
||||
|
||||
@@ -1,16 +1,45 @@
|
||||
<form wire:submit='createGitHubApp' class="flex flex-col w-full gap-2">
|
||||
<div class="pb-2">This is required, if you would like to get full integration (commit / pull request
|
||||
deployments, etc)
|
||||
with GitHub.</div>
|
||||
<div class="flex gap-2">
|
||||
<x-forms.input id="name" label="Name" required />
|
||||
<x-forms.input helper="If empty, your GitHub user will be used." id="organization" label="Organization" />
|
||||
<x-forms.input helper="If empty, your GitHub user will be used."
|
||||
placeholder="If empty, your GitHub user will be used." id="organization" label="Organization (on GitHub)" />
|
||||
</div>
|
||||
<div class="flex gap-2">
|
||||
<x-forms.input id="html_url" label="HTML Url" required />
|
||||
<x-forms.input id="api_url" label="API Url" required />
|
||||
</div>
|
||||
<div class="flex gap-2">
|
||||
<x-forms.input id="custom_user" label="Custom Git User" required />
|
||||
<x-forms.input id="custom_port" type="number" label="Custom Git Port" required />
|
||||
<div x-data="{
|
||||
activeAccordion: '',
|
||||
setActiveAccordion(id) {
|
||||
this.activeAccordion = (this.activeAccordion == id) ? '' : id
|
||||
}
|
||||
}" class="relative w-full py-2 mx-auto overflow-hidden text-sm font-normal rounded-md">
|
||||
<div x-data="{ id: $id('accordion') }" class="cursor-pointer group">
|
||||
<button @click="setActiveAccordion(id)"
|
||||
class="flex items-center justify-between w-full px-1 py-2 text-left select-none hover:dark:text-white hover:bg-white/5"
|
||||
type="button">
|
||||
<h4>Advanced</h4>
|
||||
<svg class="w-4 h-4 duration-200 ease-out" :class="{ 'rotate-180': activeAccordion == id }"
|
||||
viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" fill="none" stroke="currentColor"
|
||||
stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<polyline points="6 9 12 15 18 9"></polyline>
|
||||
</svg>
|
||||
</button>
|
||||
<div x-show="activeAccordion==id" x-collapse x-cloak class="px-2">
|
||||
<div class="py-2">Self-hosted / Enterprise GitHub details.</div>
|
||||
<div class="flex flex-col gap-2 pt-0 opacity-70">
|
||||
<div class="flex gap-2">
|
||||
<x-forms.input id="html_url" label="HTML Url" required />
|
||||
<x-forms.input id="api_url" label="API Url" required />
|
||||
</div>
|
||||
<div class="flex gap-2">
|
||||
<x-forms.input id="custom_user" label="Custom Git User" required />
|
||||
<x-forms.input id="custom_port" type="number" label="Custom Git Port" required />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@if (!isCloud())
|
||||
<x-forms.checkbox id="is_system_wide" label="System Wide" />
|
||||
@endif
|
||||
|
||||
58
templates/compose/docmost.yaml
Normal file
58
templates/compose/docmost.yaml
Normal file
@@ -0,0 +1,58 @@
|
||||
# documentation: https://docmost.com/docs/
|
||||
# slogan: Open-source collaborative wiki and documentation software
|
||||
# tags: documentation, opensource, wiki, confluence, knowledge-base, notion, realtime-collaboration, notion-alternative
|
||||
# logo: svgs/docmost.png
|
||||
# port: 3000
|
||||
|
||||
services:
|
||||
docmost:
|
||||
image: "docmost/docmost:latest"
|
||||
depends_on:
|
||||
postgresql:
|
||||
condition: service_healthy
|
||||
redis:
|
||||
condition: service_healthy
|
||||
environment:
|
||||
- SERVICE_FQDN_DOCMOST_3000
|
||||
- APP_SECRET=$SERVICE_BASE64_APPKEY
|
||||
- APP_URL=$SERVICE_FQDN_DOCMOST_3000
|
||||
- DATABASE_URL=postgresql://$SERVICE_USER_POSTGRES:$SERVICE_PASSWORD_POSTGRES@postgresql/docmost?schema=public
|
||||
- REDIS_URL=redis://redis:6379
|
||||
volumes:
|
||||
- "docmost:/app/data/storage"
|
||||
healthcheck:
|
||||
test:
|
||||
- CMD
|
||||
- curl
|
||||
- "-f"
|
||||
- "http://127.0.0.1:3000"
|
||||
interval: 2s
|
||||
timeout: 10s
|
||||
retries: 20
|
||||
postgresql:
|
||||
image: "postgres:16-alpine"
|
||||
environment:
|
||||
- POSTGRES_USER=$SERVICE_USER_POSTGRES
|
||||
- POSTGRES_PASSWORD=$SERVICE_PASSWORD_POSTGRES
|
||||
- POSTGRES_DB=docmost
|
||||
volumes:
|
||||
- "postgresql-data:/var/lib/postgresql/data"
|
||||
healthcheck:
|
||||
test:
|
||||
- CMD-SHELL
|
||||
- "pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}"
|
||||
interval: 5s
|
||||
timeout: 10s
|
||||
retries: 20
|
||||
redis:
|
||||
image: "redis:7.2-alpine"
|
||||
volumes:
|
||||
- "redis-data:/data"
|
||||
healthcheck:
|
||||
test:
|
||||
- CMD
|
||||
- redis-cli
|
||||
- PING
|
||||
interval: 5s
|
||||
timeout: 10s
|
||||
retries: 20
|
||||
53
templates/compose/drupal-with-postgresql.yaml
Normal file
53
templates/compose/drupal-with-postgresql.yaml
Normal file
@@ -0,0 +1,53 @@
|
||||
# documentation: https://www.drupal.org/about
|
||||
# slogan: Drupal is a free and open-source web content management system written in PHP and distributed under the GNU General Public License.
|
||||
# tags: cms, blog, content, management, postgresql
|
||||
# logo: svgs/drupal.svg
|
||||
|
||||
services:
|
||||
drupal:
|
||||
image: "drupal:10-apache"
|
||||
environment:
|
||||
- SERVICE_FQDN_DRUPAL
|
||||
- DB_HOST=postgres
|
||||
- DB_NAME=postgres
|
||||
- DB_USER=postgres
|
||||
- DB_PASSWORD=$SERVICE_PASSWORD_POSTGRES
|
||||
volumes:
|
||||
- type: volume
|
||||
source: drupal_modules
|
||||
target: /var/www/html/modules
|
||||
is_directory: true
|
||||
- type: volume
|
||||
source: drupal_profiles
|
||||
target: /var/www/html/profiles
|
||||
is_directory: true
|
||||
- type: volume
|
||||
source: drupal_themes
|
||||
target: /var/www/html/themes
|
||||
is_directory: true
|
||||
- type: volume
|
||||
source: drupal_sites
|
||||
target: /var/www/html/sites
|
||||
is_directory: true
|
||||
depends_on:
|
||||
- postgres
|
||||
healthcheck:
|
||||
test:
|
||||
- CMD-SHELL
|
||||
- "curl -f http://localhost:80 || exit 1"
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 5
|
||||
postgres:
|
||||
image: "postgres:16"
|
||||
environment:
|
||||
- POSTGRES_DB=postgres
|
||||
- POSTGRES_USER=postgres
|
||||
- POSTGRES_PASSWORD=$SERVICE_PASSWORD_POSTGRES
|
||||
healthcheck:
|
||||
test:
|
||||
- CMD-SHELL
|
||||
- "pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}"
|
||||
interval: 5s
|
||||
timeout: 10s
|
||||
retries: 20
|
||||
@@ -15,7 +15,7 @@ services:
|
||||
volumes:
|
||||
- minio-data:/data
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://127.0.0.1:9000/minio/health/live"]
|
||||
test: ["CMD", "mc", "ready", "local"]
|
||||
interval: 5s
|
||||
timeout: 20s
|
||||
retries: 10
|
||||
|
||||
190
templates/compose/plane.yaml
Normal file
190
templates/compose/plane.yaml
Normal file
@@ -0,0 +1,190 @@
|
||||
# documentation: https://docs.plane.so/self-hosting/methods/docker-compose
|
||||
# slogan: The open source project management tool
|
||||
# tags: plane,project-management,tool,open,source,api,nextjs,redis,postgresql,django,pm
|
||||
# logo: svgs/plane.svg
|
||||
|
||||
x-app-env: &app-env
|
||||
environment:
|
||||
- WEB_URL=http://localhost
|
||||
- DEBUG=${DEBUG:-0}
|
||||
- CORS_ALLOWED_ORIGINS=http://localhost
|
||||
# Gunicorn Workers
|
||||
- GUNICORN_WORKERS=${GUNICORN_WORKERS:-1}
|
||||
#DB SETTINGS
|
||||
- PGHOST=plane-db
|
||||
- PGDATABASE=plane
|
||||
- POSTGRES_USER=$SERVICE_USER_POSTGRES
|
||||
- POSTGRES_PASSWORD=$SERVICE_PASSWORD_POSTGRES
|
||||
- POSTGRES_DB=plane
|
||||
- POSTGRES_PORT=5432
|
||||
- PGDATA=/var/lib/postgresql/data
|
||||
- DATABASE_URL=postgresql://$SERVICE_USER_POSTGRES:$SERVICE_PASSWORD_POSTGRES@plane-db/plane
|
||||
# REDIS SETTINGS
|
||||
- REDIS_HOST=plane-redis
|
||||
- REDIS_PORT=6379
|
||||
- REDIS_URL=${REDIS_URL:-redis://plane-redis:6379/}
|
||||
# Application secret
|
||||
- SECRET_KEY=$SERVICE_PASSWORD_64_SECRETKEY
|
||||
# DATA STORE SETTINGS
|
||||
- USE_MINIO=${USE_MINIO:-1}
|
||||
- AWS_REGION=${AWS_REGION}
|
||||
- AWS_ACCESS_KEY_ID=${AWS_ACCESS_KEY_ID}
|
||||
- AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY}
|
||||
- AWS_S3_ENDPOINT_URL=${AWS_S3_ENDPOINT_URL:-http://plane-minio:9000}
|
||||
- AWS_S3_BUCKET_NAME=${AWS_S3_BUCKET_NAME:-uploads}
|
||||
- MINIO_ROOT_USER=$SERVICE_USER_MINIO
|
||||
- MINIO_ROOT_PASSWORD=$SERVICE_PASSWORD_MINIO
|
||||
- BUCKET_NAME=${BUCKET_NAME:-uploads}
|
||||
- FILE_SIZE_LIMIT=${FILE_SIZE_LIMIT:-5242880}
|
||||
# Admin and Space URLs
|
||||
- ADMIN_BASE_URL=${ADMIN_BASE_URL}
|
||||
- SPACE_BASE_URL=${SPACE_BASE_URL}
|
||||
- APP_BASE_URL=${APP_BASE_URL}
|
||||
|
||||
services:
|
||||
proxy:
|
||||
environment:
|
||||
- SERVICE_FQDN_PLANE
|
||||
- FILE_SIZE_LIMIT=${FILE_SIZE_LIMIT:-5242880}
|
||||
image: makeplane/plane-proxy:stable
|
||||
depends_on:
|
||||
- web
|
||||
- api
|
||||
- space
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://127.0.0.1:80"]
|
||||
interval: 2s
|
||||
timeout: 10s
|
||||
retries: 15
|
||||
|
||||
web:
|
||||
<<: *app-env
|
||||
image: makeplane/plane-frontend:stable
|
||||
command: node web/server.js web
|
||||
depends_on:
|
||||
- api
|
||||
- worker
|
||||
healthcheck:
|
||||
test: "wget -qO- http://`hostname`:3000"
|
||||
interval: 2s
|
||||
timeout: 10s
|
||||
retries: 15
|
||||
space:
|
||||
<<: *app-env
|
||||
image: makeplane/plane-space:stable
|
||||
command: node space/server.js space
|
||||
depends_on:
|
||||
- api
|
||||
- worker
|
||||
- web
|
||||
healthcheck:
|
||||
test: ["CMD", "echo", "hey whats up"]
|
||||
interval: 2s
|
||||
timeout: 10s
|
||||
retries: 15
|
||||
|
||||
admin:
|
||||
<<: *app-env
|
||||
image: makeplane/plane-admin:stable
|
||||
command: node admin/server.js admin
|
||||
depends_on:
|
||||
- api
|
||||
- web
|
||||
healthcheck:
|
||||
test: ["CMD", "echo", "hey whats up"]
|
||||
interval: 2s
|
||||
timeout: 10s
|
||||
retries: 15
|
||||
|
||||
api:
|
||||
<<: *app-env
|
||||
image: makeplane/plane-backend:stable
|
||||
command: ./bin/docker-entrypoint-api.sh
|
||||
volumes:
|
||||
- logs_api:/code/plane/logs
|
||||
depends_on:
|
||||
- plane-db
|
||||
- plane-redis
|
||||
healthcheck:
|
||||
test: ["CMD", "echo", "hey whats up"]
|
||||
interval: 2s
|
||||
timeout: 10s
|
||||
retries: 15
|
||||
|
||||
worker:
|
||||
<<: *app-env
|
||||
image: makeplane/plane-backend:stable
|
||||
command: ./bin/docker-entrypoint-worker.sh
|
||||
volumes:
|
||||
- logs_worker:/code/plane/logs
|
||||
depends_on:
|
||||
- api
|
||||
- plane-db
|
||||
- plane-redis
|
||||
healthcheck:
|
||||
test: ["CMD", "echo", "hey whats up"]
|
||||
interval: 2s
|
||||
timeout: 10s
|
||||
retries: 15
|
||||
|
||||
beat-worker:
|
||||
<<: *app-env
|
||||
image: makeplane/plane-backend:stable
|
||||
command: ./bin/docker-entrypoint-beat.sh
|
||||
volumes:
|
||||
- logs_beat-worker:/code/plane/logs
|
||||
depends_on:
|
||||
- api
|
||||
- plane-db
|
||||
- plane-redis
|
||||
healthcheck:
|
||||
test: ["CMD", "echo", "hey whats up"]
|
||||
interval: 2s
|
||||
timeout: 10s
|
||||
retries: 15
|
||||
|
||||
migrator:
|
||||
<<: *app-env
|
||||
image: makeplane/plane-backend:stable
|
||||
restart: "no"
|
||||
command: ./bin/docker-entrypoint-migrator.sh
|
||||
volumes:
|
||||
- logs_migrator:/code/plane/logs
|
||||
depends_on:
|
||||
- plane-db
|
||||
- plane-redis
|
||||
|
||||
plane-db:
|
||||
<<: *app-env
|
||||
image: postgres:15.5-alpine
|
||||
command: postgres -c 'max_connections=1000'
|
||||
volumes:
|
||||
- pgdata:/var/lib/postgresql/data
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}"]
|
||||
interval: 5s
|
||||
timeout: 20s
|
||||
retries: 10
|
||||
|
||||
plane-redis:
|
||||
<<: *app-env
|
||||
image: valkey/valkey:7.2.5-alpine
|
||||
volumes:
|
||||
- redisdata:/data
|
||||
healthcheck:
|
||||
test: ["CMD", "redis-cli", "ping"]
|
||||
interval: 5s
|
||||
timeout: 20s
|
||||
retries: 10
|
||||
|
||||
plane-minio:
|
||||
<<: *app-env
|
||||
image: minio/minio:latest
|
||||
command: server /export --console-address ":9090"
|
||||
volumes:
|
||||
- uploads:/export
|
||||
healthcheck:
|
||||
test: ["CMD", "mc", "ready", "local"]
|
||||
interval: 5s
|
||||
timeout: 20s
|
||||
retries: 10
|
||||
@@ -53,7 +53,7 @@ services:
|
||||
volumes:
|
||||
- minio-data:/data
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://127.0.0.1:9000/minio/health/live"]
|
||||
test: ["CMD", "mc", "ready", "local"]
|
||||
interval: 5s
|
||||
timeout: 20s
|
||||
retries: 10
|
||||
|
||||
@@ -12,13 +12,15 @@ services:
|
||||
- SERVER_URL=$SERVICE_FQDN_TWENTY
|
||||
- FRONT_BASE_URL=$SERVICE_FQDN_TWENTY
|
||||
- ENABLE_DB_MIGRATIONS=true
|
||||
- SIGN_IN_PREFILLED=false
|
||||
- CACHE_STORAGE_TYPE=${CACHE_STORAGE_TYPE:-redis}
|
||||
- REDIS_HOST=redis
|
||||
- REDIS_PORT=6379
|
||||
|
||||
- STORAGE_TYPE=${STORAGE_TYPE:-local}
|
||||
- STORAGE_S3_REGION=$STORAGE_S3_REGION
|
||||
- STORAGE_S3_NAME=$STORAGE_S3_NAME
|
||||
- STORAGE_S3_ENDPOINT=$STORAGE_S3_ENDPOINT
|
||||
# https://twenty.com/developers/section/self-hosting/self-hosting-var#security
|
||||
- API_RATE_LIMITING_TTL=${API_RATE_LIMITING_TTL:-100}
|
||||
- API_RATE_LIMITING_LIMIT=${API_RATE_LIMITING_LIMIT:-100}
|
||||
|
||||
# https://twenty.com/developers/section/self-hosting/self-hosting-var#tokens
|
||||
- ACCESS_TOKEN_SECRET=$SERVICE_BASE64_32_ACCESS
|
||||
- LOGIN_TOKEN_SECRET=$SERVICE_BASE64_32_LOGIN
|
||||
- REFRESH_TOKEN_SECRET=$SERVICE_BASE64_32_REFRESH
|
||||
@@ -26,6 +28,26 @@ services:
|
||||
- POSTGRES_ADMIN_PASSWORD=$SERVICE_PASSWORD_POSTGRES
|
||||
- PG_DATABASE_URL=postgres://postgres:$SERVICE_PASSWORD_POSTGRES@postgres:5432/default
|
||||
|
||||
# https://twenty.com/developers/section/self-hosting/self-hosting-var#auth
|
||||
- IS_SIGN_UP_DISABLED=${IS_SIGN_UP_DISABLED:-false}
|
||||
- PASSWORD_RESET_TOKEN_EXPIRES_IN=${PASSWORD_RESET_TOKEN_EXPIRES_IN:-5m}
|
||||
|
||||
# https://twenty.com/developers/section/self-hosting/self-hosting-var#workspace-cleaning
|
||||
- WORKSPACE_INACTIVE_DAYS_BEFORE_NOTIFICATION=$WORKSPACE_INACTIVE_DAYS_BEFORE_NOTIFICATION
|
||||
- WORKSPACE_INACTIVE_DAYS_BEFORE_DELETION=$WORKSPACE_INACTIVE_DAYS_BEFORE_DELETION
|
||||
|
||||
# https://twenty.com/developers/section/self-hosting/self-hosting-var#captcha
|
||||
- STORAGE_TYPE=${STORAGE_TYPE:-local}
|
||||
- STORAGE_S3_REGION=$STORAGE_S3_REGION
|
||||
- STORAGE_S3_NAME=$STORAGE_S3_NAME
|
||||
- STORAGE_S3_ENDPOINT=$STORAGE_S3_ENDPOINT
|
||||
- STORAGE_S3_ACCESS_KEY_ID=$STORAGE_S3_ACCESS_KEY_ID
|
||||
- STORAGE_S3_SECRET_ACCESS_KEY=$STORAGE_S3_SECRET_ACCESS_KEY
|
||||
|
||||
# https://twenty.com/developers/section/self-hosting/self-hosting-var#message-queue
|
||||
- MESSAGE_QUEUE_TYPE=$MESSAGE_QUEUE_TYPE
|
||||
|
||||
# https://twenty.com/developers/section/self-hosting/self-hosting-var#email
|
||||
- EMAIL_FROM_ADDRESS=$EMAIL_FROM_ADDRESS
|
||||
- EMAIL_FROM_NAME=$EMAIL_FROM_NAME
|
||||
- EMAIL_SYSTEM_ADDRESS=$EMAIL_SYSTEM_ADDRESS
|
||||
@@ -35,10 +57,12 @@ services:
|
||||
- EMAIL_SMTP_USER=$EMAIL_SMTP_USER
|
||||
- EMAIL_SMTP_PASSWORD=$EMAIL_SMTP_PASSWORD
|
||||
|
||||
# https://twenty.com/developers/section/self-hosting/self-hosting-var#debug-/-development
|
||||
- SIGN_IN_PREFILLED=false
|
||||
- DEBUG_MODE=${DEBUG_MODE:-false}
|
||||
|
||||
# https://twenty.com/developers/section/self-hosting/self-hosting-var#telemetry
|
||||
- TELEMETRY_ENABLED=${TELEMETRY_ENABLED:-false}
|
||||
- CACHE_STORAGE_TYPE=${CACHE_STORAGE_TYPE:-redis}
|
||||
- REDIS_HOST=redis
|
||||
- REDIS_PORT=6379
|
||||
depends_on:
|
||||
postgres:
|
||||
condition: service_healthy
|
||||
|
||||
37
templates/compose/vikunja-with-postgresql.yaml
Normal file
37
templates/compose/vikunja-with-postgresql.yaml
Normal file
@@ -0,0 +1,37 @@
|
||||
# documentation: https://vikunja.io
|
||||
# slogan: The open-source, self-hostable to-do app. Organize everything, on all platforms.
|
||||
# tags: productivity,todo
|
||||
# logo: svgs/vikunja.svg
|
||||
# port: 3456
|
||||
|
||||
services:
|
||||
vikunja:
|
||||
image: vikunja/vikunja
|
||||
environment:
|
||||
- SERVICE_FQDN_VIKUNJA
|
||||
- VIKUNJA_SERVICE_PUBLICURL=$SERVICE_FQDN_VIKUNJA
|
||||
- VIKUNJA_SERVICE_JWTSECRET=$SERVICE_PASSWORD_JWTSECRET
|
||||
- VIKUNJA_SERVICE_ENABLEREGISTRATION=true
|
||||
- VIKUNJA_DATABASE_TYPE=postgres
|
||||
- VIKUNJA_DATABASE_HOST=postgresql
|
||||
- VIKUNJA_DATABASE_PASSWORD=${SERVICE_PASSWORD_POSTGRESQL}
|
||||
- VIKUNJA_DATABASE_USER=${SERVICE_USER_POSTGRESQL}
|
||||
- VIKUNJA_DATABASE_DATABASE=${POSTGRESQL_DATABASE}
|
||||
volumes:
|
||||
- vikunja-data:/app/vikunja/
|
||||
depends_on:
|
||||
postgresql:
|
||||
condition: service_healthy
|
||||
postgresql:
|
||||
image: postgres:16-alpine
|
||||
volumes:
|
||||
- vikunja-postgresql-data:/var/lib/postgresql/data
|
||||
environment:
|
||||
- POSTGRES_USER=${SERVICE_USER_POSTGRESQL}
|
||||
- POSTGRES_PASSWORD=${SERVICE_PASSWORD_POSTGRESQL}
|
||||
- POSTGRES_DB=${POSTGRESQL_DATABASE}
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}"]
|
||||
interval: 5s
|
||||
timeout: 20s
|
||||
retries: 10
|
||||
@@ -12,10 +12,16 @@ services:
|
||||
- VIKUNJA_SERVICE_PUBLICURL=$SERVICE_FQDN_VIKUNJA
|
||||
- VIKUNJA_SERVICE_JWTSECRET=$SERVICE_PASSWORD_JWTSECRET
|
||||
- VIKUNJA_SERVICE_ENABLEREGISTRATION=true
|
||||
- VIKUNJA_DATABASE_PATH=/db/vikunja.db
|
||||
- VIKUNJA_DATABASE_TYPE=sqlite
|
||||
volumes:
|
||||
- vikunja-data:/app/vikunja/
|
||||
healthcheck:
|
||||
test: ["CMD", "wget", "--spider", "http://127.0.0.1:3456"]
|
||||
interval: 5s
|
||||
timeout: 20s
|
||||
retries: 10
|
||||
- vikunja-sqlite-data:/db
|
||||
depends_on:
|
||||
- init
|
||||
init:
|
||||
image: busybox
|
||||
restart: no
|
||||
volumes:
|
||||
- vikunja-sqlite-data:/db
|
||||
command: ["sh", "-c", "touch /db/vikunja.db && chown -R 1000 /db"]
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"coolify": {
|
||||
"v4": {
|
||||
"version": "4.0.0-beta.309"
|
||||
"version": "4.0.0-beta.314"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user