main: begin major rewrite for lasthour
This commit is contained in:
parent
e2bcfbadf8
commit
6a268ce65b
@ -12,7 +12,7 @@ tasks:
|
||||
./vendor/bin/spin exec -u webuser coolify php artisan key:generate
|
||||
./vendor/bin/spin exec -u webuser coolify php artisan storage:link
|
||||
./vendor/bin/spin exec -u webuser coolify php artisan migrate:fresh --seed
|
||||
cat .coolify-logo
|
||||
cat .jesus-is-king
|
||||
gp sync-done spin-is-ready
|
||||
|
||||
- name: Install Node dependencies and run Vite
|
||||
|
28
.tinkerwell/snippets/SendEmail.php
Normal file
28
.tinkerwell/snippets/SendEmail.php
Normal file
@ -0,0 +1,28 @@
|
||||
<?php
|
||||
/**
|
||||
* @label Send Email
|
||||
* @description Send email to all users
|
||||
*/
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
|
||||
set_transanctional_email_settings();
|
||||
|
||||
$users = User::whereEmail('test@example.com');
|
||||
foreach ($users as $user) {
|
||||
Mail::send([], [], function ($message) use ($user) {
|
||||
$message
|
||||
->to($user->email)
|
||||
->subject("Testing")
|
||||
->text(
|
||||
<<<EOF
|
||||
Hello,
|
||||
|
||||
Welcome to Last Hour Cloud.
|
||||
Here is your user id: $user->id
|
||||
|
||||
EOF
|
||||
);
|
||||
});
|
||||
}
|
@ -1,94 +0,0 @@
|
||||
# Citizen Code of Conduct
|
||||
|
||||
## 1. Purpose
|
||||
|
||||
A primary goal of Coolify is to be inclusive to the largest number of contributors, with the most varied and diverse backgrounds possible. As such, we are committed to providing a friendly, safe and welcoming environment for all, regardless of gender, sexual orientation, ability, ethnicity, socioeconomic status, and religion (or lack thereof).
|
||||
|
||||
This code of conduct outlines our expectations for all those who participate in our community, as well as the consequences for unacceptable behavior.
|
||||
|
||||
We invite all those who participate in Coolify to help us create safe and positive experiences for everyone.
|
||||
|
||||
## 2. Open [Source/Culture/Tech] Citizenship
|
||||
|
||||
A supplemental goal of this Code of Conduct is to increase open [source/culture/tech] citizenship by encouraging participants to recognize and strengthen the relationships between our actions and their effects on our community.
|
||||
|
||||
Communities mirror the societies in which they exist and positive action is essential to counteract the many forms of inequality and abuses of power that exist in society.
|
||||
|
||||
If you see someone who is making an extra effort to ensure our community is welcoming, friendly, and encourages all participants to contribute to the fullest extent, we want to know.
|
||||
|
||||
## 3. Expected Behavior
|
||||
|
||||
The following behaviors are expected and requested of all community members:
|
||||
|
||||
* Participate in an authentic and active way. In doing so, you contribute to the health and longevity of this community.
|
||||
* Exercise consideration and respect in your speech and actions.
|
||||
* Attempt collaboration before conflict.
|
||||
* Refrain from demeaning, discriminatory, or harassing behavior and speech.
|
||||
* Be mindful of your surroundings and of your fellow participants. Alert community leaders if you notice a dangerous situation, someone in distress, or violations of this Code of Conduct, even if they seem inconsequential.
|
||||
* Remember that community event venues may be shared with members of the public; please be respectful to all patrons of these locations.
|
||||
|
||||
## 4. Unacceptable Behavior
|
||||
|
||||
The following behaviors are considered harassment and are unacceptable within our community:
|
||||
|
||||
* Violence, threats of violence or violent language directed against another person.
|
||||
* Sexist, racist, homophobic, transphobic, ableist or otherwise discriminatory jokes and language.
|
||||
* Posting or displaying sexually explicit or violent material.
|
||||
* Posting or threatening to post other people's personally identifying information ("doxing").
|
||||
* Personal insults, particularly those related to gender, sexual orientation, race, religion, or disability.
|
||||
* Inappropriate photography or recording.
|
||||
* Inappropriate physical contact. You should have someone's consent before touching them.
|
||||
* Unwelcome sexual attention. This includes, sexualized comments or jokes; inappropriate touching, groping, and unwelcomed sexual advances.
|
||||
* Deliberate intimidation, stalking or following (online or in person).
|
||||
* Advocating for, or encouraging, any of the above behavior.
|
||||
* Sustained disruption of community events, including talks and presentations.
|
||||
|
||||
## 5. Weapons Policy
|
||||
|
||||
No weapons will be allowed at Coolify events, community spaces, or in other spaces covered by the scope of this Code of Conduct. Weapons include but are not limited to guns, explosives (including fireworks), and large knives such as those used for hunting or display, as well as any other item used for the purpose of causing injury or harm to others. Anyone seen in possession of one of these items will be asked to leave immediately, and will only be allowed to return without the weapon. Community members are further expected to comply with all state and local laws on this matter.
|
||||
|
||||
## 6. Consequences of Unacceptable Behavior
|
||||
|
||||
Unacceptable behavior from any community member, including sponsors and those with decision-making authority, will not be tolerated.
|
||||
|
||||
Anyone asked to stop unacceptable behavior is expected to comply immediately.
|
||||
|
||||
If a community member engages in unacceptable behavior, the community organizers may take any action they deem appropriate, up to and including a temporary ban or permanent expulsion from the community without warning (and without refund in the case of a paid event).
|
||||
|
||||
## 7. Reporting Guidelines
|
||||
|
||||
If you are subject to or witness unacceptable behavior, or have any other concerns, please notify a community organizer as soon as possible. hi@coollabs.io.
|
||||
|
||||
|
||||
|
||||
Additionally, community organizers are available to help community members engage with local law enforcement or to otherwise help those experiencing unacceptable behavior feel safe. In the context of in-person events, organizers will also provide escorts as desired by the person experiencing distress.
|
||||
|
||||
## 8. Addressing Grievances
|
||||
|
||||
If you feel you have been falsely or unfairly accused of violating this Code of Conduct, you should notify coollabsio with a concise description of your grievance. Your grievance will be handled in accordance with our existing governing policies.
|
||||
|
||||
|
||||
|
||||
## 9. Scope
|
||||
|
||||
We expect all community participants (contributors, paid or otherwise; sponsors; and other guests) to abide by this Code of Conduct in all community venues--online and in-person--as well as in all one-on-one communications pertaining to community business.
|
||||
|
||||
This code of conduct and its related procedures also applies to unacceptable behavior occurring outside the scope of community activities when such behavior has the potential to adversely affect the safety and well-being of community members.
|
||||
|
||||
## 10. Contact info
|
||||
|
||||
hi@coollabs.io
|
||||
|
||||
## 11. License and attribution
|
||||
|
||||
The Citizen Code of Conduct is distributed by [Stumptown Syndicate](http://stumptownsyndicate.org) under a [Creative Commons Attribution-ShareAlike license](http://creativecommons.org/licenses/by-sa/3.0/).
|
||||
|
||||
Portions of text derived from the [Django Code of Conduct](https://www.djangoproject.com/conduct/) and the [Geek Feminism Anti-Harassment Policy](http://geekfeminism.wikia.com/wiki/Conference_anti-harassment/Policy).
|
||||
|
||||
_Revision 2.3. Posted 6 March 2017._
|
||||
|
||||
_Revision 2.2. Posted 4 February 2016._
|
||||
|
||||
_Revision 2.1. Posted 23 June 2014._
|
||||
|
||||
_Revision 2.0, adopted by the [Stumptown Syndicate](http://stumptownsyndicate.org) board on 10 January 2013. Posted 17 March 2013._
|
@ -22,14 +22,14 @@ class UpdateCoolify
|
||||
$settings = InstanceSettings::get();
|
||||
ray('Running InstanceAutoUpdateJob');
|
||||
$this->server = Server::find(0);
|
||||
if (! $this->server) {
|
||||
if (!$this->server) {
|
||||
return;
|
||||
}
|
||||
CleanupDocker::dispatch($this->server, false)->onQueue('high');
|
||||
$this->latestVersion = get_latest_version_of_coolify();
|
||||
$this->currentVersion = config('version');
|
||||
if (! $manual_update) {
|
||||
if (! $settings->is_auto_update_enabled) {
|
||||
if (!$manual_update) {
|
||||
if (!$settings->is_auto_update_enabled) {
|
||||
return;
|
||||
}
|
||||
if ($this->latestVersion === $this->currentVersion) {
|
||||
@ -50,7 +50,15 @@ class UpdateCoolify
|
||||
if (isDev()) {
|
||||
ray('Running in dev mode');
|
||||
remote_process([
|
||||
'sleep 10',
|
||||
"sleep 10"
|
||||
], $this->server);
|
||||
ray('Update done');
|
||||
return;
|
||||
} else {
|
||||
ray('Running update on production server');
|
||||
remote_process([
|
||||
"curl -fsSL https://cdn.lasthourhosting.org/lasthourcloud/scripts/upgrade.sh -o /data/coolify/source/upgrade.sh",
|
||||
"bash /data/coolify/source/upgrade.sh $this->latestVersion"
|
||||
], $this->server);
|
||||
|
||||
return;
|
||||
@ -59,6 +67,5 @@ class UpdateCoolify
|
||||
'curl -fsSL https://cdn.coollabs.io/coolify/upgrade.sh -o /data/coolify/source/upgrade.sh',
|
||||
"bash /data/coolify/source/upgrade.sh $this->latestVersion",
|
||||
], $this->server);
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -80,7 +80,7 @@ class Init extends Command
|
||||
try {
|
||||
$database = StandalonePostgresql::withTrashed()->find(0);
|
||||
if ($database && $database->trashed()) {
|
||||
echo "Restoring coolify db backup\n";
|
||||
echo "Restoring Last Hour Cloud db backup\n";
|
||||
$database->restore();
|
||||
$scheduledBackup = ScheduledDatabaseBackup::find(0);
|
||||
if (! $scheduledBackup) {
|
||||
@ -96,7 +96,7 @@ class Init extends Command
|
||||
}
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
echo "Error in restoring coolify db backup: {$e->getMessage()}\n";
|
||||
echo "Error in restoring Last Hour Cloud db backup: {$e->getMessage()}\n";
|
||||
}
|
||||
}
|
||||
|
||||
@ -122,7 +122,7 @@ class Init extends Command
|
||||
return;
|
||||
}
|
||||
try {
|
||||
Http::get("https://undead.coolify.io/v4/alive?appId=$id&version=$version");
|
||||
Http::get("");
|
||||
echo "I am alive!\n";
|
||||
} catch (\Throwable $e) {
|
||||
echo "Error in alive: {$e->getMessage()}\n";
|
||||
|
@ -49,7 +49,7 @@ class NotifyDemo extends Command
|
||||
<<<'HTML'
|
||||
<div>
|
||||
<div class="title-box">
|
||||
Coolify
|
||||
Last Hour Cloud
|
||||
</div>
|
||||
<p class="mt-1 ml-1 ">
|
||||
Demo Notify <strong class="text-coolify">=></strong> Send a demo notification to a given channel.
|
||||
@ -72,7 +72,7 @@ class NotifyDemo extends Command
|
||||
|
||||
ask(<<<'HTML'
|
||||
<div class="mr-1">
|
||||
In which manner you wish a <strong class="text-coolify">coolified</strong> notification?
|
||||
In which manner you wish a <strong class="text-coolify">Last Hour Cloud</strong> notification?
|
||||
</div>
|
||||
HTML, ['email', 'slack', 'discord', 'telegram']);
|
||||
}
|
||||
|
184
app/Http/Controllers/Api/Deploy.php
Normal file
184
app/Http/Controllers/Api/Deploy.php
Normal file
@ -0,0 +1,184 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use App\Actions\Database\StartMariadb;
|
||||
use App\Actions\Database\StartMongodb;
|
||||
use App\Actions\Database\StartMysql;
|
||||
use App\Actions\Database\StartPostgresql;
|
||||
use App\Actions\Database\StartRedis;
|
||||
use App\Actions\Service\StartService;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\ApplicationDeploymentQueue;
|
||||
use App\Models\Server;
|
||||
use App\Models\Tag;
|
||||
use Illuminate\Http\Request;
|
||||
use Visus\Cuid2\Cuid2;
|
||||
|
||||
class Deploy extends Controller
|
||||
{
|
||||
public function deployments(Request $request)
|
||||
{
|
||||
$teamId = get_team_id_from_token();
|
||||
if (is_null($teamId)) {
|
||||
return invalid_token();
|
||||
}
|
||||
$servers = Server::whereTeamId($teamId)->get();
|
||||
$deployments_per_server = ApplicationDeploymentQueue::whereIn("status", ["in_progress", "queued"])->whereIn("server_id", $servers->pluck("id"))->get([
|
||||
"id",
|
||||
"application_id",
|
||||
"application_name",
|
||||
"deployment_url",
|
||||
"pull_request_id",
|
||||
"server_name",
|
||||
"server_id",
|
||||
"status"
|
||||
])->sortBy('id')->toArray();
|
||||
return response()->json($deployments_per_server, 200);
|
||||
}
|
||||
public function deploy(Request $request)
|
||||
{
|
||||
$teamId = get_team_id_from_token();
|
||||
$uuids = $request->query->get('uuid');
|
||||
$tags = $request->query->get('tag');
|
||||
$force = $request->query->get('force') ?? false;
|
||||
|
||||
if ($uuids && $tags) {
|
||||
return response()->json(['error' => 'You can only use uuid or tag, not both.', 'upstream docs' => 'https://coolify.io/docs/api/deploy-webhook'], 400);
|
||||
}
|
||||
if (is_null($teamId)) {
|
||||
return invalid_token();
|
||||
}
|
||||
if ($tags) {
|
||||
return $this->by_tags($tags, $teamId, $force);
|
||||
} else if ($uuids) {
|
||||
return $this->by_uuids($uuids, $teamId, $force);
|
||||
}
|
||||
return response()->json(['error' => 'You must provide uuid or tag.', 'upstream docs' => 'https://coolify.io/docs/api/deploy-webhook'], 400);
|
||||
}
|
||||
private function by_uuids(string $uuid, int $teamId, bool $force = false)
|
||||
{
|
||||
$uuids = explode(',', $uuid);
|
||||
$uuids = collect(array_filter($uuids));
|
||||
|
||||
if (count($uuids) === 0) {
|
||||
return response()->json(['error' => 'No UUIDs provided.', 'upstream docs' => 'https://coolify.io/docs/api/deploy-webhook'], 400);
|
||||
}
|
||||
$deployments = collect();
|
||||
$payload = collect();
|
||||
foreach ($uuids as $uuid) {
|
||||
$resource = getResourceByUuid($uuid, $teamId);
|
||||
if ($resource) {
|
||||
['message' => $return_message, 'deployment_uuid' => $deployment_uuid] = $this->deploy_resource($resource, $force);
|
||||
if ($deployment_uuid) {
|
||||
$deployments->push(['message' => $return_message, 'resource_uuid' => $uuid, 'deployment_uuid' => $deployment_uuid->toString()]);
|
||||
} else {
|
||||
$deployments->push(['message' => $return_message, 'resource_uuid' => $uuid]);
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($deployments->count() > 0) {
|
||||
$payload->put('deployments', $deployments->toArray());
|
||||
return response()->json($payload->toArray(), 200);
|
||||
}
|
||||
return response()->json(['error' => "No resources found.", 'upstream docs' => 'https://coolify.io/docs/api/deploy-webhook'], 404);
|
||||
}
|
||||
public function by_tags(string $tags, int $team_id, bool $force = false)
|
||||
{
|
||||
$tags = explode(',', $tags);
|
||||
$tags = collect(array_filter($tags));
|
||||
|
||||
if (count($tags) === 0) {
|
||||
return response()->json(['error' => 'No TAGs provided.', 'upstream docs' => 'https://coolify.io/docs/api/deploy-webhook'], 400);
|
||||
}
|
||||
$message = collect([]);
|
||||
$deployments = collect();
|
||||
$payload = collect();
|
||||
foreach ($tags as $tag) {
|
||||
$found_tag = Tag::where(['name' => $tag, 'team_id' => $team_id])->first();
|
||||
if (!$found_tag) {
|
||||
// $message->push("Tag {$tag} not found.");
|
||||
continue;
|
||||
}
|
||||
$applications = $found_tag->applications()->get();
|
||||
$services = $found_tag->services()->get();
|
||||
if ($applications->count() === 0 && $services->count() === 0) {
|
||||
$message->push("No resources found for tag {$tag}.");
|
||||
continue;
|
||||
}
|
||||
foreach ($applications as $resource) {
|
||||
['message' => $return_message, 'deployment_uuid' => $deployment_uuid] = $this->deploy_resource($resource, $force);
|
||||
if ($deployment_uuid) {
|
||||
$deployments->push(['resource_uuid' => $resource->uuid, 'deployment_uuid' => $deployment_uuid->toString()]);
|
||||
}
|
||||
$message = $message->merge($return_message);
|
||||
}
|
||||
foreach ($services as $resource) {
|
||||
['message' => $return_message] = $this->deploy_resource($resource, $force);
|
||||
$message = $message->merge($return_message);
|
||||
}
|
||||
}
|
||||
ray($message);
|
||||
if ($message->count() > 0) {
|
||||
$payload->put('message', $message->toArray());
|
||||
if ($deployments->count() > 0) {
|
||||
$payload->put('details', $deployments->toArray());
|
||||
}
|
||||
return response()->json($payload->toArray(), 200);
|
||||
}
|
||||
|
||||
return response()->json(['error' => "No resources found with this tag.", 'upstream docs' => 'https://coolify.io/docs/api/deploy-webhook'], 404);
|
||||
}
|
||||
public function deploy_resource($resource, bool $force = false): array
|
||||
{
|
||||
$message = null;
|
||||
$deployment_uuid = null;
|
||||
if (gettype($resource) !== 'object') {
|
||||
return ['message' => "Resource ($resource) not found.", 'deployment_uuid' => $deployment_uuid];
|
||||
}
|
||||
$type = $resource?->getMorphClass();
|
||||
if ($type === 'App\Models\Application') {
|
||||
$deployment_uuid = new Cuid2(7);
|
||||
queue_application_deployment(
|
||||
application: $resource,
|
||||
deployment_uuid: $deployment_uuid,
|
||||
force_rebuild: $force,
|
||||
);
|
||||
$message = "Application {$resource->name} deployment queued.";
|
||||
} else if ($type === 'App\Models\StandalonePostgresql') {
|
||||
StartPostgresql::run($resource);
|
||||
$resource->update([
|
||||
'started_at' => now(),
|
||||
]);
|
||||
$message = "Database {$resource->name} started.";
|
||||
} else if ($type === 'App\Models\StandaloneRedis') {
|
||||
StartRedis::run($resource);
|
||||
$resource->update([
|
||||
'started_at' => now(),
|
||||
]);
|
||||
$message = "Database {$resource->name} started.";
|
||||
} else if ($type === 'App\Models\StandaloneMongodb') {
|
||||
StartMongodb::run($resource);
|
||||
$resource->update([
|
||||
'started_at' => now(),
|
||||
]);
|
||||
$message = "Database {$resource->name} started.";
|
||||
} else if ($type === 'App\Models\StandaloneMysql') {
|
||||
StartMysql::run($resource);
|
||||
$resource->update([
|
||||
'started_at' => now(),
|
||||
]);
|
||||
$message = "Database {$resource->name} started.";
|
||||
} else if ($type === 'App\Models\StandaloneMariadb') {
|
||||
StartMariadb::run($resource);
|
||||
$resource->update([
|
||||
'started_at' => now(),
|
||||
]);
|
||||
$message = "Database {$resource->name} started.";
|
||||
} else if ($type === 'App\Models\Service') {
|
||||
StartService::run($resource);
|
||||
$message = "Service {$resource->name} started. It could take a while, be patient.";
|
||||
}
|
||||
return ['message' => $message, 'deployment_uuid' => $deployment_uuid];
|
||||
}
|
||||
}
|
@ -81,8 +81,8 @@ hwAAAAtzc2gtZWQyNTUxOQAAACBbhpqHhqv6aI67Mj9abM3DVbmcfYhZAhC7ca4d9UCevA
|
||||
AAAECBQw4jg1WRT2IGHMncCiZhURCts2s24HoDS0thHnnRKVuGmoeGq/pojrsyP1pszcNV
|
||||
uZx9iFkCELtxrh31QJ68AAAAEXNhaWxANzZmZjY2ZDJlMmRkAQIDBA==
|
||||
-----END OPENSSH PRIVATE KEY-----';
|
||||
$this->privateKeyDescription = 'Created by Coolify';
|
||||
$this->remoteServerDescription = 'Created by Coolify';
|
||||
$this->privateKeyDescription = 'Created by Last Hour Cloud';
|
||||
$this->remoteServerDescription = 'Created by Last Hour Cloud';
|
||||
$this->remoteServerHost = 'coolify-testing-host';
|
||||
}
|
||||
// if ($this->currentState === 'create-project') {
|
||||
@ -352,7 +352,7 @@ uZx9iFkCELtxrh31QJ68AAAAEXNhaWxANzZmZjY2ZDJlMmRkAQIDBA==
|
||||
private function createNewPrivateKey()
|
||||
{
|
||||
$this->privateKeyName = generate_random_name();
|
||||
$this->privateKeyDescription = 'Created by Coolify';
|
||||
$this->privateKeyDescription = 'Created by Last Hour Cloud';
|
||||
['private' => $this->privateKey, 'public' => $this->publicKey] = generateSSHKey();
|
||||
}
|
||||
|
||||
|
@ -60,7 +60,7 @@ class Help extends Component
|
||||
} else {
|
||||
send_user_an_email($mail, auth()->user()?->email, 'support@lasthourhosting.org');
|
||||
}
|
||||
$this->dispatch('success', 'Feedback sent.', 'Thank you! We will get in touch with you as soon as possible.');
|
||||
$this->dispatch('success', 'Help request sent.', 'Thank you! We will get in touch with you as soon as possible.');
|
||||
} catch (\Throwable $e) {
|
||||
return handleError($e, $this);
|
||||
}
|
||||
|
@ -147,13 +147,13 @@ class General extends Component
|
||||
$this->ports_exposes = $this->application->ports_exposes;
|
||||
$this->is_container_label_escape_enabled = $this->application->settings->is_container_label_escape_enabled;
|
||||
$this->customLabels = $this->application->parseContainerLabels();
|
||||
if (! $this->customLabels && $this->application->destination->server->proxyType() !== 'NONE' && ! $this->application->settings->is_container_label_readonly_enabled) {
|
||||
if (!$this->customLabels && $this->application->destination->server->proxyType() !== 'NONE' && !$this->application->settings->is_container_label_readonly_enabled) {
|
||||
$this->customLabels = str(implode('|coolify|', generateLabelsApplication($this->application)))->replace('|coolify|', "\n");
|
||||
$this->application->custom_labels = base64_encode($this->customLabels);
|
||||
$this->application->save();
|
||||
}
|
||||
$this->initialDockerComposeLocation = $this->application->docker_compose_location;
|
||||
if ($this->application->build_pack === 'dockercompose' && ! $this->application->docker_compose_raw) {
|
||||
if ($this->application->build_pack === 'dockercompose' && !$this->application->docker_compose_raw) {
|
||||
$this->initLoadingCompose = true;
|
||||
$this->dispatch('info', 'Loading docker compose file.');
|
||||
}
|
||||
@ -314,7 +314,7 @@ class General extends Component
|
||||
$domains = str($this->application->fqdn)->trim()->explode(',');
|
||||
if ($this->application->additional_servers->count() === 0) {
|
||||
foreach ($domains as $domain) {
|
||||
if (! validate_dns_entry($domain, $this->application->destination->server)) {
|
||||
if (!validate_dns_entry($domain, $this->application->destination->server)) {
|
||||
$showToaster && $this->dispatch('error', 'Validating DNS failed.', "Make sure you have added the DNS records correctly.<br><br>$domain->{$this->application->destination->server->ip}<br><br>Check this <a target='_blank' class='underline dark:text-white' href='https://coolify.io/docs/knowledge-base/dns-configuration'>documentation</a> for further help.");
|
||||
}
|
||||
}
|
||||
@ -357,7 +357,7 @@ class General extends Component
|
||||
$this->checkFqdns();
|
||||
|
||||
$this->application->save();
|
||||
if (! $this->customLabels && $this->application->destination->server->proxyType() !== 'NONE' && ! $this->application->settings->is_container_label_readonly_enabled) {
|
||||
if (!$this->customLabels && $this->application->destination->server->proxyType() !== 'NONE' && !$this->application->settings->is_container_label_readonly_enabled) {
|
||||
$this->customLabels = str(implode('|coolify|', generateLabelsApplication($this->application)))->replace('|coolify|', "\n");
|
||||
$this->application->custom_labels = base64_encode($this->customLabels);
|
||||
$this->application->save();
|
||||
@ -379,13 +379,12 @@ class General extends Component
|
||||
'application.docker_registry_image_name' => 'required',
|
||||
]);
|
||||
}
|
||||
|
||||
if (data_get($this->application, 'custom_docker_run_options')) {
|
||||
$this->application->custom_docker_run_options = str($this->application->custom_docker_run_options)->trim();
|
||||
}
|
||||
if (data_get($this->application, 'dockerfile')) {
|
||||
$port = get_port_from_dockerfile($this->application->dockerfile);
|
||||
if ($port && ! $this->application->ports_exposes) {
|
||||
if ($port && !$this->application->ports_exposes) {
|
||||
$this->application->ports_exposes = $port;
|
||||
}
|
||||
}
|
||||
@ -401,7 +400,7 @@ class General extends Component
|
||||
foreach ($this->parsedServiceDomains as $serviceName => $service) {
|
||||
$domain = data_get($service, 'domain');
|
||||
if ($domain) {
|
||||
if (! validate_dns_entry($domain, $this->application->destination->server)) {
|
||||
if (!validate_dns_entry($domain, $this->application->destination->server)) {
|
||||
$showToaster && $this->dispatch('error', 'Validating DNS failed.', "Make sure you have added the DNS records correctly.<br><br>$domain->{$this->application->destination->server->ip}<br><br>Check this <a target='_blank' class='underline dark:text-white' href='https://coolify.io/docs/knowledge-base/dns-configuration'>documentation</a> for further help.");
|
||||
}
|
||||
check_domain_usage(resource: $this->application);
|
||||
|
@ -123,8 +123,12 @@ class Heading extends Component
|
||||
public function restart()
|
||||
{
|
||||
if ($this->application->additional_servers->count() > 0 && str($this->application->docker_registry_image_name)->isEmpty()) {
|
||||
<<<<<<< HEAD
|
||||
$this->dispatch('error', 'Failed to deploy', 'Before deploying to multiple servers, you must first set a Docker image in the General tab.<br>More information here: <a target="_blank" class="underline" href="https://coolify.io/docs/knowledge-base/server/multiple-servers">documentation</a>');
|
||||
|
||||
=======
|
||||
$this->dispatch('error', 'Failed to deploy', 'Before deploying to multiple servers, you must first set a Docker image in the General tab.<br>More information here in upstream docs: <a target="_blank" class="underline" href="https://coolify.io/docs/server/multiple-servers">documentation</a>');
|
||||
>>>>>>> 35700ec24 (main: begin major rewrite for lasthour)
|
||||
return;
|
||||
}
|
||||
$this->setDeploymentUuid();
|
||||
|
@ -36,7 +36,7 @@ class Create extends Component
|
||||
try {
|
||||
$this->rateLimit(10);
|
||||
$this->name = generate_random_name();
|
||||
$this->description = 'Created by Coolify';
|
||||
$this->description = 'Created by Last Hour Cloud';
|
||||
['private' => $this->value, 'public' => $this->publicKey] = generateSSHKey();
|
||||
} catch (\Throwable $e) {
|
||||
return handleError($e, $this);
|
||||
|
@ -116,7 +116,6 @@ class Form extends Component
|
||||
}
|
||||
if ($this->server->settings->isDirty('is_server_api_enabled') && $this->server->settings->is_server_api_enabled === true) {
|
||||
ray('Starting sentinel');
|
||||
|
||||
}
|
||||
} else {
|
||||
ray('Sentinel is not enabled');
|
||||
@ -156,7 +155,7 @@ class Form extends Component
|
||||
$this->server->settings->save();
|
||||
$this->dispatch('proxyStatusUpdated');
|
||||
} else {
|
||||
$this->dispatch('error', 'Server is not reachable.', 'Please validate your configuration and connection.<br><br>Check this <a target="_blank" class="underline" href="https://coolify.io/docs/knowledge-base/server/openssh">documentation</a> for further help. <br><br>Error: '.$error);
|
||||
$this->dispatch('error', 'Server is not reachable.', 'Please validate your configuration and connection.<br><br>Check this <a target="_blank" class="underline" href="https://coolify.io/docs/knowledge-base/server/openssh">documentation</a> for further help. <br><br>Error: ' . $error);
|
||||
|
||||
return;
|
||||
}
|
||||
@ -172,7 +171,7 @@ class Form extends Component
|
||||
|
||||
public function submit()
|
||||
{
|
||||
if (isCloud() && ! isDev()) {
|
||||
if (isCloud() && !isDev()) {
|
||||
$this->validate();
|
||||
$this->validate([
|
||||
'server.ip' => 'required',
|
||||
|
@ -53,7 +53,7 @@ class ValidateAndInstall extends Component
|
||||
$this->proxy_started = null;
|
||||
$this->error = null;
|
||||
$this->number_of_tries = $data;
|
||||
if (! $this->ask) {
|
||||
if (!$this->ask) {
|
||||
$this->dispatch('validateConnection');
|
||||
}
|
||||
}
|
||||
@ -86,8 +86,8 @@ class ValidateAndInstall extends Component
|
||||
public function validateConnection()
|
||||
{
|
||||
['uptime' => $this->uptime, 'error' => $error] = $this->server->validateConnection();
|
||||
if (! $this->uptime) {
|
||||
$this->error = 'Server is not reachable. Please validate your configuration and connection.<br>Check this <a target="_blank" class="text-black underline dark:text-white" href="https://coolify.io/docs/knowledge-base/server/openssh">documentation</a> for further help. <br><br><div class="text-error">Error: '.$error.'</div>';
|
||||
if (!$this->uptime) {
|
||||
$this->error = 'Server is not reachable. Please validate your configuration and connection.<br>Check this <a target="_blank" class="text-black underline dark:text-white" href="https://coolify.io/docs/knowledge-base/server/openssh">documentation</a> for further help. <br><br><div class="text-error">Error: ' . $error . '</div>';
|
||||
$this->server->update([
|
||||
'validation_logs' => $this->error,
|
||||
]);
|
||||
@ -100,7 +100,7 @@ class ValidateAndInstall extends Component
|
||||
public function validateOS()
|
||||
{
|
||||
$this->supported_os_type = $this->server->validateOS();
|
||||
if (! $this->supported_os_type) {
|
||||
if (!$this->supported_os_type) {
|
||||
$this->error = 'Server OS type is not supported. Please install Docker manually before continuing: <a target="_blank" class="underline" href="https://docs.docker.com/engine/install/#server">documentation</a>.';
|
||||
$this->server->update([
|
||||
'validation_logs' => $this->error,
|
||||
@ -115,7 +115,7 @@ class ValidateAndInstall extends Component
|
||||
{
|
||||
$this->docker_installed = $this->server->validateDockerEngine();
|
||||
$this->docker_compose_installed = $this->server->validateDockerCompose();
|
||||
if (! $this->docker_installed || ! $this->docker_compose_installed) {
|
||||
if (!$this->docker_installed || !$this->docker_compose_installed) {
|
||||
if ($this->install) {
|
||||
if ($this->number_of_tries == $this->max_tries) {
|
||||
$this->error = 'Docker Engine could not be installed. Please install Docker manually before continuing: <a target="_blank" class="underline" href="https://docs.docker.com/engine/install/#server">documentation</a>.';
|
||||
|
@ -51,7 +51,7 @@ class S3Storage extends BaseModel
|
||||
$this->is_usable = false;
|
||||
if ($this->unusable_email_sent === false && is_transactional_emails_active()) {
|
||||
$mail = new MailMessage();
|
||||
$mail->subject('Last Hour: S3 Storage Connection Error');
|
||||
$mail->subject('Last Hour Cloud: S3 Storage Connection Error');
|
||||
$mail->view('emails.s3-connection-error', ['name' => $this->name, 'reason' => $e->getMessage(), 'url' => route('team.storage.show', ['storage_uuid' => $this->uuid])]);
|
||||
$users = collect([]);
|
||||
$members = $this->team->members()->get();
|
||||
|
@ -132,7 +132,7 @@ class User extends Authenticatable implements SendsEmail
|
||||
$mail->view('emails.email-verification', [
|
||||
'url' => $url,
|
||||
]);
|
||||
$mail->subject('Last Hour: Verify your email.');
|
||||
$mail->subject('Last Hour Cloud: Verify your email.');
|
||||
send_user_an_email($mail, $this->email);
|
||||
}
|
||||
|
||||
|
@ -57,10 +57,10 @@ class DeploymentFailed extends Notification implements ShouldQueue
|
||||
$pull_request_id = data_get($this->preview, 'pull_request_id', 0);
|
||||
$fqdn = $this->fqdn;
|
||||
if ($pull_request_id === 0) {
|
||||
$mail->subject('Last Hour: Deployment failed of ' . $this->application_name . '.');
|
||||
$mail->subject('Last Hour Cloud: Deployment failed of ' . $this->application_name . '.');
|
||||
} else {
|
||||
$fqdn = $this->preview->fqdn;
|
||||
$mail->subject('Last Hour: Deployment failed of pull request #' . $this->preview->pull_request_id . ' of ' . $this->application_name . '.');
|
||||
$mail->subject('Last Hour Cloud: Deployment failed of pull request #' . $this->preview->pull_request_id . ' of ' . $this->application_name . '.');
|
||||
}
|
||||
$mail->view('emails.application-deployment-failed', [
|
||||
'name' => $this->application_name,
|
||||
@ -75,10 +75,10 @@ class DeploymentFailed extends Notification implements ShouldQueue
|
||||
public function toDiscord(): string
|
||||
{
|
||||
if ($this->preview) {
|
||||
$message = 'Last Hour: Pull request #' . $this->preview->pull_request_id . ' of **' . $this->application_name . '** (' . $this->preview->fqdn . ') deployment failed: ';
|
||||
$message = 'Last Hour Cloud: Pull request #' . $this->preview->pull_request_id . ' of **' . $this->application_name . '** (' . $this->preview->fqdn . ') deployment failed: ';
|
||||
$message .= '[View Deployment Logs](' . $this->deployment_url . ')';
|
||||
} else {
|
||||
$message = 'Last Hour: Deployment failed of **' . $this->application_name . '** (' . $this->fqdn . '): ';
|
||||
$message = 'Last Hour Cloud: Deployment failed of **' . $this->application_name . '** (' . $this->fqdn . '): ';
|
||||
$message .= '[View Deployment Logs](' . $this->deployment_url . ')';
|
||||
}
|
||||
|
||||
@ -88,9 +88,9 @@ class DeploymentFailed extends Notification implements ShouldQueue
|
||||
public function toTelegram(): array
|
||||
{
|
||||
if ($this->preview) {
|
||||
$message = 'Last Hour: Pull request #' . $this->preview->pull_request_id . ' of **' . $this->application_name . '** (' . $this->preview->fqdn . ') deployment failed: ';
|
||||
$message = 'Last Hour Cloud: Pull request #' . $this->preview->pull_request_id . ' of **' . $this->application_name . '** (' . $this->preview->fqdn . ') deployment failed: ';
|
||||
} else {
|
||||
$message = 'Last Hour: Deployment failed of **' . $this->application_name . '** (' . $this->fqdn . '): ';
|
||||
$message = 'Last Hour Cloud: Deployment failed of **' . $this->application_name . '** (' . $this->fqdn . '): ';
|
||||
}
|
||||
$buttons[] = [
|
||||
'text' => 'Deployment logs',
|
||||
|
@ -63,10 +63,10 @@ class DeploymentSuccess extends Notification implements ShouldQueue
|
||||
$pull_request_id = data_get($this->preview, 'pull_request_id', 0);
|
||||
$fqdn = $this->fqdn;
|
||||
if ($pull_request_id === 0) {
|
||||
$mail->subject("Last Hour: New version is deployed of {$this->application_name}");
|
||||
$mail->subject("Last Hour Cloud: New version is deployed of {$this->application_name}");
|
||||
} else {
|
||||
$fqdn = $this->preview->fqdn;
|
||||
$mail->subject("Last Hour: Pull request #{$pull_request_id} of {$this->application_name} deployed successfully");
|
||||
$mail->subject("Last Hour Cloud: Pull request #{$pull_request_id} of {$this->application_name} deployed successfully");
|
||||
}
|
||||
$mail->view('emails.application-deployment-success', [
|
||||
'name' => $this->application_name,
|
||||
@ -81,7 +81,7 @@ class DeploymentSuccess extends Notification implements ShouldQueue
|
||||
public function toDiscord(): string
|
||||
{
|
||||
if ($this->preview) {
|
||||
$message = 'Last Hour: New PR' . $this->preview->pull_request_id . ' version successfully deployed of ' . $this->application_name . '
|
||||
$message = 'Last Hour Cloud: New PR' . $this->preview->pull_request_id . ' version successfully deployed of ' . $this->application_name . '
|
||||
|
||||
';
|
||||
if ($this->preview->fqdn) {
|
||||
@ -89,7 +89,7 @@ class DeploymentSuccess extends Notification implements ShouldQueue
|
||||
}
|
||||
$message .= '[Deployment logs](' . $this->deployment_url . ')';
|
||||
} else {
|
||||
$message = 'Last Hour: New version successfully deployed of ' . $this->application_name . '
|
||||
$message = 'Last Hour Cloud: New version successfully deployed of ' . $this->application_name . '
|
||||
|
||||
';
|
||||
if ($this->fqdn) {
|
||||
@ -104,7 +104,7 @@ class DeploymentSuccess extends Notification implements ShouldQueue
|
||||
public function toTelegram(): array
|
||||
{
|
||||
if ($this->preview) {
|
||||
$message = 'Last Hour: New PR' . $this->preview->pull_request_id . ' version successfully deployed of ' . $this->application_name . '';
|
||||
$message = 'Last Hour Cloud: New PR' . $this->preview->pull_request_id . ' version successfully deployed of ' . $this->application_name . '';
|
||||
if ($this->preview->fqdn) {
|
||||
$buttons[] = [
|
||||
'text' => 'Open Application',
|
||||
|
@ -45,7 +45,7 @@ class StatusChanged extends Notification implements ShouldQueue
|
||||
{
|
||||
$mail = new MailMessage;
|
||||
$fqdn = $this->fqdn;
|
||||
$mail->subject("Last Hour: {$this->resource_name} has been stopped");
|
||||
$mail->subject("Last Hour Cloud: {$this->resource_name} has been stopped");
|
||||
$mail->view('emails.application-status-changes', [
|
||||
'name' => $this->resource_name,
|
||||
'fqdn' => $fqdn,
|
||||
@ -57,21 +57,21 @@ class StatusChanged extends Notification implements ShouldQueue
|
||||
|
||||
public function toDiscord(): string
|
||||
{
|
||||
$message = 'Last Hour: ' . $this->resource_name . ' has been stopped.
|
||||
$message = 'Last Hour Cloud: ' . $this->resource_name . ' has been stopped.
|
||||
|
||||
';
|
||||
$message .= '[Open Application in Last Hour](' . $this->resource_url . ')';
|
||||
$message .= '[Open Application in Last Hour Cloud](' . $this->resource_url . ')';
|
||||
return $message;
|
||||
}
|
||||
|
||||
public function toTelegram(): array
|
||||
{
|
||||
$message = 'Last Hour: ' . $this->resource_name . ' has been stopped.';
|
||||
$message = 'Last Hour Cloud: ' . $this->resource_name . ' has been stopped.';
|
||||
return [
|
||||
'message' => $message,
|
||||
'buttons' => [
|
||||
[
|
||||
"text" => "Open Application in Last Hour",
|
||||
"text" => "Open Application in Last Hour Cloud",
|
||||
"url" => $this->resource_url
|
||||
]
|
||||
],
|
||||
|
@ -26,7 +26,7 @@ class ContainerRestarted extends Notification implements ShouldQueue
|
||||
public function toMail(): MailMessage
|
||||
{
|
||||
$mail = new MailMessage();
|
||||
$mail->subject("Last Hour: A resource ({$this->name}) has been restarted automatically on {$this->server->name}");
|
||||
$mail->subject("Last Hour Cloud: A resource ({$this->name}) has been restarted automatically on {$this->server->name}");
|
||||
$mail->view('emails.container-restarted', [
|
||||
'containerName' => $this->name,
|
||||
'serverName' => $this->server->name,
|
||||
@ -38,13 +38,13 @@ class ContainerRestarted extends Notification implements ShouldQueue
|
||||
|
||||
public function toDiscord(): string
|
||||
{
|
||||
$message = "Last Hour: A resource ({$this->name}) has been restarted automatically on {$this->server->name}";
|
||||
$message = "Last Hour Cloud: A resource ({$this->name}) has been restarted automatically on {$this->server->name}";
|
||||
return $message;
|
||||
}
|
||||
|
||||
public function toTelegram(): array
|
||||
{
|
||||
$message = "Last Hour: A resource ({$this->name}) has been restarted automatically on {$this->server->name}";
|
||||
$message = "Last Hour Cloud: A resource ({$this->name}) has been restarted automatically on {$this->server->name}";
|
||||
$payload = [
|
||||
'message' => $message,
|
||||
];
|
||||
@ -52,7 +52,7 @@ class ContainerRestarted extends Notification implements ShouldQueue
|
||||
$payload['buttons'] = [
|
||||
[
|
||||
[
|
||||
"text" => "Check Proxy in Last Hour",
|
||||
"text" => "Check Proxy in Last Hour Cloud",
|
||||
"url" => $this->url
|
||||
]
|
||||
]
|
||||
|
@ -26,7 +26,7 @@ class ContainerStopped extends Notification implements ShouldQueue
|
||||
public function toMail(): MailMessage
|
||||
{
|
||||
$mail = new MailMessage();
|
||||
$mail->subject("Last Hour: A resource has been stopped unexpectedly on {$this->server->name}");
|
||||
$mail->subject("Last Hour Cloud: A resource has been stopped unexpectedly on {$this->server->name}");
|
||||
$mail->view('emails.container-stopped', [
|
||||
'containerName' => $this->name,
|
||||
'serverName' => $this->server->name,
|
||||
@ -38,13 +38,13 @@ class ContainerStopped extends Notification implements ShouldQueue
|
||||
|
||||
public function toDiscord(): string
|
||||
{
|
||||
$message = "Last Hour: A resource ($this->name) has been stopped unexpectedly on {$this->server->name}";
|
||||
$message = "Last Hour Cloud: A resource ($this->name) has been stopped unexpectedly on {$this->server->name}";
|
||||
return $message;
|
||||
}
|
||||
|
||||
public function toTelegram(): array
|
||||
{
|
||||
$message = "Last Hour: A resource ($this->name) has been stopped unexpectedly on {$this->server->name}";
|
||||
$message = "Last Hour Cloud: A resource ($this->name) has been stopped unexpectedly on {$this->server->name}";
|
||||
$payload = [
|
||||
'message' => $message,
|
||||
];
|
||||
@ -52,7 +52,7 @@ class ContainerStopped extends Notification implements ShouldQueue
|
||||
$payload['buttons'] = [
|
||||
[
|
||||
[
|
||||
"text" => "Open Application in Last Hour",
|
||||
"text" => "Open Application in Last Hour Cloud",
|
||||
"url" => $this->url
|
||||
]
|
||||
]
|
||||
|
@ -34,7 +34,7 @@ class BackupFailed extends Notification implements ShouldQueue
|
||||
public function toMail(): MailMessage
|
||||
{
|
||||
$mail = new MailMessage();
|
||||
$mail->subject("Last Hour: [ACTION REQUIRED] Backup FAILED for {$this->database->name}");
|
||||
$mail->subject("Last Hour Cloud: [ACTION REQUIRED] Backup FAILED for {$this->database->name}");
|
||||
$mail->view('emails.backup-failed', [
|
||||
'name' => $this->name,
|
||||
'database_name' => $this->database_name,
|
||||
@ -47,12 +47,12 @@ class BackupFailed extends Notification implements ShouldQueue
|
||||
|
||||
public function toDiscord(): string
|
||||
{
|
||||
return "Last Hour: Database backup for {$this->name} (db:{$this->database_name}) with frequency of {$this->frequency} was FAILED.\n\nReason:\n{$this->output}";
|
||||
return "Last Hour Cloud: Database backup for {$this->name} (db:{$this->database_name}) with frequency of {$this->frequency} was FAILED.\n\nReason:\n{$this->output}";
|
||||
}
|
||||
|
||||
public function toTelegram(): array
|
||||
{
|
||||
$message = "Last Hour: Database backup for {$this->name} (db:{$this->database_name}) with frequency of {$this->frequency} was FAILED.\n\nReason:\n{$this->output}";
|
||||
$message = "Last Hour Cloud: Database backup for {$this->name} (db:{$this->database_name}) with frequency of {$this->frequency} was FAILED.\n\nReason:\n{$this->output}";
|
||||
|
||||
return [
|
||||
'message' => $message,
|
||||
|
@ -34,7 +34,7 @@ class BackupSuccess extends Notification implements ShouldQueue
|
||||
public function toMail(): MailMessage
|
||||
{
|
||||
$mail = new MailMessage();
|
||||
$mail->subject("Last Hour: Backup successfully done for {$this->database->name}");
|
||||
$mail->subject("Last Hour Cloud: Backup successfully done for {$this->database->name}");
|
||||
$mail->view('emails.backup-success', [
|
||||
'name' => $this->name,
|
||||
'database_name' => $this->database_name,
|
||||
@ -46,12 +46,12 @@ class BackupSuccess extends Notification implements ShouldQueue
|
||||
|
||||
public function toDiscord(): string
|
||||
{
|
||||
return "Last Hour: Database backup for {$this->name} (db:{$this->database_name}) with frequency of {$this->frequency} was successful.";
|
||||
return "Last Hour Cloud: Database backup for {$this->name} (db:{$this->database_name}) with frequency of {$this->frequency} was successful.";
|
||||
}
|
||||
|
||||
public function toTelegram(): array
|
||||
{
|
||||
$message = "Last Hour: Database backup for {$this->name} (db:{$this->database_name}) with frequency of {$this->frequency} was successful.";
|
||||
$message = "Last Hour Cloud: Database backup for {$this->name} (db:{$this->database_name}) with frequency of {$this->frequency} was successful.";
|
||||
ray($message);
|
||||
|
||||
return [
|
||||
|
@ -44,7 +44,7 @@ class HighDiskUsage extends Notification implements ShouldQueue
|
||||
public function toMail(): MailMessage
|
||||
{
|
||||
$mail = new MailMessage();
|
||||
$mail->subject("Last Hour: Server ({$this->server->name}) high disk usage detected!");
|
||||
$mail->subject("Last Hour Cloud: Server ({$this->server->name}) high disk usage detected!");
|
||||
$mail->view('emails.high-disk-usage', [
|
||||
'name' => $this->server->name,
|
||||
'disk_usage' => $this->disk_usage,
|
||||
@ -56,7 +56,7 @@ class HighDiskUsage extends Notification implements ShouldQueue
|
||||
|
||||
public function toDiscord(): string
|
||||
{
|
||||
$message = "Last Hour: Server '{$this->server->name}' high disk usage detected!\nDisk usage: {$this->disk_usage}%. Threshold: {$this->cleanup_after_percentage}%.\nPlease cleanup your disk to prevent data-loss.\nHere are some tips: https://coolify.io/docs/knowledge-base/server/automated-cleanup.";
|
||||
$message = "Last Hour Cloud: Server '{$this->server->name}' high disk usage detected!\nDisk usage: {$this->disk_usage}%. Threshold: {$this->cleanup_after_percentage}%.\nPlease cleanup your disk to prevent data-loss.\nHere are some tips: https://coolify.io/docs/knowledge-base/server/automated-cleanup.";
|
||||
|
||||
return $message;
|
||||
}
|
||||
@ -64,7 +64,7 @@ class HighDiskUsage extends Notification implements ShouldQueue
|
||||
public function toTelegram(): array
|
||||
{
|
||||
return [
|
||||
'message' => "Last Hour: Server '{$this->server->name}' high disk usage detected!\nDisk usage: {$this->disk_usage}%. Threshold: {$this->cleanup_after_percentage}%.\nPlease cleanup your disk to prevent data-loss.\nHere are some tips: https://coolify.io/docs/knowledge-base/server/automated-cleanup.",
|
||||
'message' => "Last Hou Cloud: Server '{$this->server->name}' high disk usage detected!\nDisk usage: {$this->disk_usage}%. Threshold: {$this->cleanup_after_percentage}%.\nPlease cleanup your disk to prevent data-loss.\nHere are some tips: https://coolify.io/docs/knowledge-base/server/automated-cleanup.",
|
||||
];
|
||||
}
|
||||
}
|
||||
|
@ -51,7 +51,7 @@ class Revived extends Notification implements ShouldQueue
|
||||
public function toMail(): MailMessage
|
||||
{
|
||||
$mail = new MailMessage();
|
||||
$mail->subject("Last Hour: Server ({$this->server->name}) revived.");
|
||||
$mail->subject("Last Hour Cloud: Server ({$this->server->name}) revived.");
|
||||
$mail->view('emails.server-revived', [
|
||||
'name' => $this->server->name,
|
||||
]);
|
||||
@ -61,14 +61,14 @@ class Revived extends Notification implements ShouldQueue
|
||||
|
||||
public function toDiscord(): string
|
||||
{
|
||||
$message = "Last Hour: Server '{$this->server->name}' revived. All automations & integrations are turned on again!";
|
||||
$message = "Last Hour Cloud: Server '{$this->server->name}' revived. All automations & integrations are turned on again!";
|
||||
return $message;
|
||||
}
|
||||
|
||||
public function toTelegram(): array
|
||||
{
|
||||
return [
|
||||
"message" => "Last Hour: Server '{$this->server->name}' revived. All automations & integrations are turned on again!"
|
||||
"message" => "Last Hour Cloud: Server '{$this->server->name}' revived. All automations & integrations are turned on again!"
|
||||
];
|
||||
}
|
||||
}
|
||||
|
@ -44,7 +44,7 @@ class Unreachable extends Notification implements ShouldQueue
|
||||
public function toMail(): MailMessage
|
||||
{
|
||||
$mail = new MailMessage();
|
||||
$mail->subject("Last Hour: Your server ({$this->server->name}) is unreachable.");
|
||||
$mail->subject("Last Hour Cloud: Your server ({$this->server->name}) is unreachable.");
|
||||
$mail->view('emails.server-lost-connection', [
|
||||
'name' => $this->server->name,
|
||||
]);
|
||||
@ -54,14 +54,14 @@ class Unreachable extends Notification implements ShouldQueue
|
||||
|
||||
public function toDiscord(): string
|
||||
{
|
||||
$message = "Last Hour: Your server '{$this->server->name}' is unreachable. All automations & integrations are turned off! Please check your server! IMPORTANT: We automatically try to revive your server and turn on all automations & integrations.";
|
||||
$message = "Last Hour Cloud: Your server '{$this->server->name}' is unreachable. All automations & integrations are turned off! Please check your server! IMPORTANT: We automatically try to revive your server and turn on all automations & integrations.";
|
||||
return $message;
|
||||
}
|
||||
|
||||
public function toTelegram(): array
|
||||
{
|
||||
return [
|
||||
"message" => "Last Hour: Your server '{$this->server->name}' is unreachable. All automations & integrations are turned off! Please check your server! IMPORTANT: We automatically try to revive your server and turn on all automations & integrations."
|
||||
"message" => "Last Hour Cloud: Your server '{$this->server->name}' is unreachable. All automations & integrations are turned off! Please check your server! IMPORTANT: We automatically try to revive your server and turn on all automations & integrations."
|
||||
];
|
||||
}
|
||||
}
|
||||
|
@ -25,7 +25,7 @@ class Test extends Notification implements ShouldQueue
|
||||
public function toMail(): MailMessage
|
||||
{
|
||||
$mail = new MailMessage();
|
||||
$mail->subject("Last Hour: Test Email");
|
||||
$mail->subject("Last Hour Cloud: Test Email");
|
||||
$mail->view('emails.test');
|
||||
|
||||
return $mail;
|
||||
@ -33,7 +33,7 @@ class Test extends Notification implements ShouldQueue
|
||||
|
||||
public function toDiscord(): string
|
||||
{
|
||||
$message = 'Last Hour: This is a test Discord notification from Last Hour.';
|
||||
$message = 'Last Hour Cloud: This is a test Discord notification from Last Hour Cloud.';
|
||||
$message .= "\n\n";
|
||||
$message .= '[Go to your dashboard](' . base_url() . ')';
|
||||
|
||||
@ -43,7 +43,7 @@ class Test extends Notification implements ShouldQueue
|
||||
public function toTelegram(): array
|
||||
{
|
||||
return [
|
||||
"message" => 'Last Hour: This is a test Telegram notification from Last Hour.',
|
||||
"message" => 'Last Hour Cloud: This is a test Telegram notification from Last Hour Cloud.',
|
||||
"buttons" => [
|
||||
[
|
||||
'text' => 'Go to your dashboard',
|
||||
|
@ -32,7 +32,7 @@ class InvitationLink extends Notification implements ShouldQueue
|
||||
$invitation_team = Team::find($invitation->team->id);
|
||||
|
||||
$mail = new MailMessage();
|
||||
$mail->subject('Last Hour: Invitation for ' . $invitation_team->name);
|
||||
$mail->subject('Last Hour Cloud: Invitation for ' . $invitation_team->name);
|
||||
$mail->view('emails.invitation-link', [
|
||||
'team' => $invitation_team->name,
|
||||
'email' => $this->user->email,
|
||||
|
@ -53,8 +53,8 @@ class ResetPassword extends Notification
|
||||
|
||||
protected function buildMailMessage($url)
|
||||
{
|
||||
$mail = new MailMessage;
|
||||
$mail->subject('Last Hour: Reset Password');
|
||||
$mail = new MailMessage();
|
||||
$mail->subject('Last Hour Cloud: Reset Password');
|
||||
$mail->view('emails.reset-password', ['url' => $url, 'count' => config('auth.passwords.' . config('auth.defaults.passwords') . '.expire')]);
|
||||
|
||||
return $mail;
|
||||
|
@ -26,7 +26,7 @@ class Test extends Notification implements ShouldQueue
|
||||
public function toMail(): MailMessage
|
||||
{
|
||||
$mail = new MailMessage();
|
||||
$mail->subject('Last Hour: Test Email');
|
||||
$mail->subject('Last Hour Cloud: Test Email');
|
||||
$mail->view('emails.test');
|
||||
|
||||
return $mail;
|
||||
|
@ -62,27 +62,27 @@ function base_configuration_dir(): string
|
||||
}
|
||||
function application_configuration_dir(): string
|
||||
{
|
||||
return base_configuration_dir().'/applications';
|
||||
return base_configuration_dir() . '/applications';
|
||||
}
|
||||
function service_configuration_dir(): string
|
||||
{
|
||||
return base_configuration_dir().'/services';
|
||||
return base_configuration_dir() . '/services';
|
||||
}
|
||||
function database_configuration_dir(): string
|
||||
{
|
||||
return base_configuration_dir().'/databases';
|
||||
return base_configuration_dir() . '/databases';
|
||||
}
|
||||
function database_proxy_dir($uuid): string
|
||||
{
|
||||
return base_configuration_dir()."/databases/$uuid/proxy";
|
||||
return base_configuration_dir() . "/databases/$uuid/proxy";
|
||||
}
|
||||
function backup_dir(): string
|
||||
{
|
||||
return base_configuration_dir().'/backups';
|
||||
return base_configuration_dir() . '/backups';
|
||||
}
|
||||
function metrics_dir(): string
|
||||
{
|
||||
return base_configuration_dir().'/metrics';
|
||||
return base_configuration_dir() . '/metrics';
|
||||
}
|
||||
|
||||
function generate_readme_file(string $name, string $updated_at): string
|
||||
@ -110,15 +110,15 @@ function showBoarding(): bool
|
||||
}
|
||||
function refreshSession(?Team $team = null): void
|
||||
{
|
||||
if (! $team) {
|
||||
if (!$team) {
|
||||
if (auth()->user()?->currentTeam()) {
|
||||
$team = Team::find(auth()->user()->currentTeam()->id);
|
||||
} else {
|
||||
$team = User::find(auth()->user()->id)->teams->first();
|
||||
}
|
||||
}
|
||||
Cache::forget('team:'.auth()->user()->id);
|
||||
Cache::remember('team:'.auth()->user()->id, 3600, function () use ($team) {
|
||||
Cache::forget('team:' . auth()->user()->id);
|
||||
Cache::remember('team:' . auth()->user()->id, 3600, function () use ($team) {
|
||||
return $team;
|
||||
});
|
||||
session(['currentTeam' => $team]);
|
||||
@ -147,7 +147,7 @@ function handleError(?Throwable $error = null, ?Livewire\Component $livewire = n
|
||||
$message = null;
|
||||
}
|
||||
if ($customErrorMessage) {
|
||||
$message = $customErrorMessage.' '.$message;
|
||||
$message = $customErrorMessage . ' ' . $message;
|
||||
}
|
||||
|
||||
if (isset($livewire)) {
|
||||
@ -163,7 +163,7 @@ function get_route_parameters(): array
|
||||
function get_latest_sentinel_version(): string
|
||||
{
|
||||
try {
|
||||
$response = Http::get('https://cdn.coollabs.io/sentinel/versions.json');
|
||||
$response = Http::get('https://cdn.lasthourhosting.org/lasthourcloud/versions.json');
|
||||
$versions = $response->json();
|
||||
|
||||
return data_get($versions, 'sentinel.version');
|
||||
@ -227,7 +227,7 @@ function generateSSHKey(string $type = 'rsa')
|
||||
function formatPrivateKey(string $privateKey)
|
||||
{
|
||||
$privateKey = trim($privateKey);
|
||||
if (! str_ends_with($privateKey, "\n")) {
|
||||
if (!str_ends_with($privateKey, "\n")) {
|
||||
$privateKey .= "\n";
|
||||
}
|
||||
|
||||
@ -249,7 +249,7 @@ function is_transactional_emails_active(): bool
|
||||
|
||||
function set_transanctional_email_settings(?InstanceSettings $settings = null): ?string
|
||||
{
|
||||
if (! $settings) {
|
||||
if (!$settings) {
|
||||
$settings = \App\Models\InstanceSettings::get();
|
||||
}
|
||||
config()->set('mail.from.address', data_get($settings, 'smtp_from_address'));
|
||||
@ -353,7 +353,7 @@ function isDev(): bool
|
||||
|
||||
function isCloud(): bool
|
||||
{
|
||||
return ! config('coolify.self_hosted');
|
||||
return !config('coolify.self_hosted');
|
||||
}
|
||||
|
||||
function validate_cron_expression($expression_to_validate): bool
|
||||
@ -381,7 +381,7 @@ function send_user_an_email(MailMessage $mail, string $email, ?string $cc = null
|
||||
{
|
||||
$settings = \App\Models\InstanceSettings::get();
|
||||
$type = set_transanctional_email_settings($settings);
|
||||
if (! $type) {
|
||||
if (!$type) {
|
||||
throw new Exception('No email settings found.');
|
||||
}
|
||||
if ($cc) {
|
||||
@ -530,7 +530,7 @@ function getResourceByUuid(string $uuid, ?int $teamId = null)
|
||||
return null;
|
||||
}
|
||||
$resource = queryResourcesByUuid($uuid);
|
||||
if (! is_null($resource) && $resource->environment->project->team_id === $teamId) {
|
||||
if (!is_null($resource) && $resource->environment->project->team_id === $teamId) {
|
||||
return $resource;
|
||||
}
|
||||
|
||||
@ -622,30 +622,30 @@ function queryResourcesByUuid(string $uuid)
|
||||
function generatTagDeployWebhook($tag_name)
|
||||
{
|
||||
$baseUrl = base_url();
|
||||
$api = Url::fromString($baseUrl).'/api/v1';
|
||||
$api = Url::fromString($baseUrl) . '/api/v1';
|
||||
$endpoint = "/deploy?tag=$tag_name";
|
||||
$url = $api.$endpoint;
|
||||
$url = $api . $endpoint;
|
||||
|
||||
return $url;
|
||||
}
|
||||
function generateDeployWebhook($resource)
|
||||
{
|
||||
$baseUrl = base_url();
|
||||
$api = Url::fromString($baseUrl).'/api/v1';
|
||||
$api = Url::fromString($baseUrl) . '/api/v1';
|
||||
$endpoint = '/deploy';
|
||||
$uuid = data_get($resource, 'uuid');
|
||||
$url = $api.$endpoint."?uuid=$uuid&force=false";
|
||||
$url = $api . $endpoint . "?uuid=$uuid&force=false";
|
||||
|
||||
return $url;
|
||||
}
|
||||
function generateGitManualWebhook($resource, $type)
|
||||
{
|
||||
if ($resource->source_id !== 0 && ! is_null($resource->source_id)) {
|
||||
if ($resource->source_id !== 0 && !is_null($resource->source_id)) {
|
||||
return null;
|
||||
}
|
||||
if ($resource->getMorphClass() === 'App\Models\Application') {
|
||||
$baseUrl = base_url();
|
||||
$api = Url::fromString($baseUrl)."/webhooks/source/$type/events/manual";
|
||||
$api = Url::fromString($baseUrl) . "/webhooks/source/$type/events/manual";
|
||||
|
||||
return $api;
|
||||
}
|
||||
@ -674,7 +674,7 @@ function getTopLevelNetworks(Service|Application $resource)
|
||||
$hasHostNetworkMode = data_get($service, 'network_mode') === 'host' ? true : false;
|
||||
|
||||
// Only add 'networks' key if 'network_mode' is not 'host'
|
||||
if (! $hasHostNetworkMode) {
|
||||
if (!$hasHostNetworkMode) {
|
||||
// Collect/create/update networks
|
||||
if ($serviceNetworks->count() > 0) {
|
||||
foreach ($serviceNetworks as $networkName => $networkDetails) {
|
||||
@ -688,7 +688,7 @@ function getTopLevelNetworks(Service|Application $resource)
|
||||
$networkExists = $topLevelNetworks->contains(function ($value, $key) use ($networkName) {
|
||||
return $value == $networkName || $key == $networkName;
|
||||
});
|
||||
if (! $networkExists) {
|
||||
if (!$networkExists) {
|
||||
$topLevelNetworks->put($networkDetails, null);
|
||||
}
|
||||
}
|
||||
@ -697,7 +697,7 @@ function getTopLevelNetworks(Service|Application $resource)
|
||||
$definedNetworkExists = $topLevelNetworks->contains(function ($value, $_) use ($definedNetwork) {
|
||||
return $value == $definedNetwork;
|
||||
});
|
||||
if (! $definedNetworkExists) {
|
||||
if (!$definedNetworkExists) {
|
||||
foreach ($definedNetwork as $network) {
|
||||
$topLevelNetworks->put($network, [
|
||||
'name' => $network,
|
||||
@ -738,7 +738,7 @@ function getTopLevelNetworks(Service|Application $resource)
|
||||
$networkExists = $topLevelNetworks->contains(function ($value, $key) use ($networkName) {
|
||||
return $value == $networkName || $key == $networkName;
|
||||
});
|
||||
if (! $networkExists) {
|
||||
if (!$networkExists) {
|
||||
$topLevelNetworks->put($networkDetails, null);
|
||||
}
|
||||
}
|
||||
@ -746,7 +746,7 @@ function getTopLevelNetworks(Service|Application $resource)
|
||||
$definedNetworkExists = $topLevelNetworks->contains(function ($value, $_) use ($definedNetwork) {
|
||||
return $value == $definedNetwork;
|
||||
});
|
||||
if (! $definedNetworkExists) {
|
||||
if (!$definedNetworkExists) {
|
||||
foreach ($definedNetwork as $network) {
|
||||
$topLevelNetworks->put($network, [
|
||||
'name' => $network,
|
||||
@ -825,7 +825,7 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal
|
||||
if ($serviceLabels->count() > 0) {
|
||||
$removedLabels = collect([]);
|
||||
$serviceLabels = $serviceLabels->filter(function ($serviceLabel, $serviceLabelName) use ($removedLabels) {
|
||||
if (! str($serviceLabel)->contains('=')) {
|
||||
if (!str($serviceLabel)->contains('=')) {
|
||||
$removedLabels->put($serviceLabelName, $serviceLabel);
|
||||
|
||||
return false;
|
||||
@ -907,7 +907,7 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal
|
||||
$networkExists = $topLevelNetworks->contains(function ($value, $key) use ($networkName) {
|
||||
return $value == $networkName || $key == $networkName;
|
||||
});
|
||||
if (! $networkExists) {
|
||||
if (!$networkExists) {
|
||||
$topLevelNetworks->put($networkDetails, null);
|
||||
}
|
||||
}
|
||||
@ -931,12 +931,12 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal
|
||||
$savedService->ports = $collectedPorts->implode(',');
|
||||
$savedService->save();
|
||||
|
||||
if (! $hasHostNetworkMode) {
|
||||
if (!$hasHostNetworkMode) {
|
||||
// Add Coolify specific networks
|
||||
$definedNetworkExists = $topLevelNetworks->contains(function ($value, $_) use ($definedNetwork) {
|
||||
return $value == $definedNetwork;
|
||||
});
|
||||
if (! $definedNetworkExists) {
|
||||
if (!$definedNetworkExists) {
|
||||
foreach ($definedNetwork as $network) {
|
||||
$topLevelNetworks->put($network, [
|
||||
'name' => $network,
|
||||
@ -1128,9 +1128,9 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal
|
||||
$fqdn = "$fqdn$path";
|
||||
}
|
||||
|
||||
if (! $isDatabase) {
|
||||
if (!$isDatabase) {
|
||||
if ($savedService->fqdn) {
|
||||
data_set($savedService, 'fqdn', $savedService->fqdn.','.$fqdn);
|
||||
data_set($savedService, 'fqdn', $savedService->fqdn . ',' . $fqdn);
|
||||
} else {
|
||||
data_set($savedService, 'fqdn', $fqdn);
|
||||
}
|
||||
@ -1145,7 +1145,7 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal
|
||||
]);
|
||||
}
|
||||
// Caddy needs exact port in some cases.
|
||||
if ($predefinedPort && ! $key->endsWith("_{$predefinedPort}")) {
|
||||
if ($predefinedPort && !$key->endsWith("_{$predefinedPort}")) {
|
||||
$fqdns_exploded = str($savedService->fqdn)->explode(',');
|
||||
if ($fqdns_exploded->count() > 1) {
|
||||
continue;
|
||||
@ -1185,12 +1185,12 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal
|
||||
'service_id' => $resource->id,
|
||||
])->first();
|
||||
['command' => $command, 'forService' => $forService, 'generatedValue' => $generatedValue, 'port' => $port] = parseEnvVariable($value);
|
||||
if (! is_null($command)) {
|
||||
if (!is_null($command)) {
|
||||
if ($command?->value() === 'FQDN' || $command?->value() === 'URL') {
|
||||
if (Str::lower($forService) === $serviceName) {
|
||||
$fqdn = generateFqdn($resource->server, $containerName);
|
||||
} else {
|
||||
$fqdn = generateFqdn($resource->server, Str::lower($forService).'-'.$resource->uuid);
|
||||
$fqdn = generateFqdn($resource->server, Str::lower($forService) . '-' . $resource->uuid);
|
||||
}
|
||||
if ($port) {
|
||||
$fqdn = "$fqdn:$port";
|
||||
@ -1220,13 +1220,13 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal
|
||||
'is_preview' => false,
|
||||
]);
|
||||
}
|
||||
if (! $isDatabase) {
|
||||
if ($command->value() === 'FQDN' && is_null($savedService->fqdn) && ! $foundEnv) {
|
||||
if (!$isDatabase) {
|
||||
if ($command->value() === 'FQDN' && is_null($savedService->fqdn) && !$foundEnv) {
|
||||
$savedService->fqdn = $fqdn;
|
||||
$savedService->save();
|
||||
}
|
||||
// Caddy needs exact port in some cases.
|
||||
if ($predefinedPort && ! $key->endsWith("_{$predefinedPort}") && $command?->value() === 'FQDN' && $resource->server->proxyType() === 'CADDY') {
|
||||
if ($predefinedPort && !$key->endsWith("_{$predefinedPort}") && $command?->value() === 'FQDN' && $resource->server->proxyType() === 'CADDY') {
|
||||
$fqdns_exploded = str($savedService->fqdn)->explode(',');
|
||||
if ($fqdns_exploded->count() > 1) {
|
||||
continue;
|
||||
@ -1248,7 +1248,7 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal
|
||||
}
|
||||
} else {
|
||||
$generatedValue = generateEnvValue($command, $resource);
|
||||
if (! $foundEnv) {
|
||||
if (!$foundEnv) {
|
||||
EnvironmentVariable::create([
|
||||
'key' => $key,
|
||||
'value' => $generatedValue,
|
||||
@ -1303,7 +1303,7 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal
|
||||
}
|
||||
$defaultLabels = defaultLabels($resource->id, $containerName, type: 'service', subType: $isDatabase ? 'database' : 'application', subId: $savedService->id);
|
||||
$serviceLabels = $serviceLabels->merge($defaultLabels);
|
||||
if (! $isDatabase && $fqdns->count() > 0) {
|
||||
if (!$isDatabase && $fqdns->count() > 0) {
|
||||
if ($fqdns) {
|
||||
$serviceLabels = $serviceLabels->merge(fqdnLabelsForTraefik(
|
||||
uuid: $resource->uuid,
|
||||
@ -1347,7 +1347,7 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal
|
||||
}
|
||||
data_set($service, 'labels', $serviceLabels->toArray());
|
||||
data_forget($service, 'is_database');
|
||||
if (! data_get($service, 'restart')) {
|
||||
if (!data_get($service, 'restart')) {
|
||||
data_set($service, 'restart', RESTART_MODE);
|
||||
}
|
||||
if (data_get($service, 'restart') === 'no' || data_get($service, 'exclude_from_hc')) {
|
||||
@ -1362,7 +1362,6 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal
|
||||
updateCompose($savedService);
|
||||
|
||||
return $service;
|
||||
|
||||
});
|
||||
|
||||
$envs_from_coolify = $resource->environment_variables()->get();
|
||||
@ -1386,7 +1385,7 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal
|
||||
}
|
||||
$parsedServiceVariables->put('COOLIFY_CONTAINER_NAME', "$serviceName-{$resource->uuid}");
|
||||
$parsedServiceVariables = $parsedServiceVariables->map(function ($value, $key) use ($envs_from_coolify) {
|
||||
if (! str($value)->startsWith('$')) {
|
||||
if (!str($value)->startsWith('$')) {
|
||||
$found_env = $envs_from_coolify->where('key', $key)->first();
|
||||
if ($found_env) {
|
||||
return $found_env->value;
|
||||
@ -1473,7 +1472,7 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal
|
||||
if ($serviceLabels->count() > 0) {
|
||||
$removedLabels = collect([]);
|
||||
$serviceLabels = $serviceLabels->filter(function ($serviceLabel, $serviceLabelName) use ($removedLabels) {
|
||||
if (! str($serviceLabel)->contains('=')) {
|
||||
if (!str($serviceLabel)->contains('=')) {
|
||||
$removedLabels->put($serviceLabelName, $serviceLabel);
|
||||
|
||||
return false;
|
||||
@ -1493,11 +1492,11 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal
|
||||
$serviceVolumes = $serviceVolumes->map(function ($volume) use ($resource, $topLevelVolumes, $pull_request_id) {
|
||||
if (is_string($volume)) {
|
||||
$volume = str($volume);
|
||||
if ($volume->contains(':') && ! $volume->startsWith('/')) {
|
||||
if ($volume->contains(':') && !$volume->startsWith('/')) {
|
||||
$name = $volume->before(':');
|
||||
$mount = $volume->after(':');
|
||||
if ($name->startsWith('.') || $name->startsWith('~')) {
|
||||
$dir = base_configuration_dir().'/applications/'.$resource->uuid;
|
||||
$dir = base_configuration_dir() . '/applications/' . $resource->uuid;
|
||||
if ($name->startsWith('.')) {
|
||||
$name = $name->replaceFirst('.', $dir);
|
||||
}
|
||||
@ -1505,12 +1504,12 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal
|
||||
$name = $name->replaceFirst('~', $dir);
|
||||
}
|
||||
if ($pull_request_id !== 0) {
|
||||
$name = $name."-pr-$pull_request_id";
|
||||
$name = $name . "-pr-$pull_request_id";
|
||||
}
|
||||
$volume = str("$name:$mount");
|
||||
} else {
|
||||
if ($pull_request_id !== 0) {
|
||||
$name = $name."-pr-$pull_request_id";
|
||||
$name = $name . "-pr-$pull_request_id";
|
||||
$volume = str("$name:$mount");
|
||||
if ($topLevelVolumes->has($name)) {
|
||||
$v = $topLevelVolumes->get($name);
|
||||
@ -1549,7 +1548,7 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal
|
||||
$name = $volume->before(':');
|
||||
$mount = $volume->after(':');
|
||||
if ($pull_request_id !== 0) {
|
||||
$name = $name."-pr-$pull_request_id";
|
||||
$name = $name . "-pr-$pull_request_id";
|
||||
}
|
||||
$volume = str("$name:$mount");
|
||||
}
|
||||
@ -1560,7 +1559,7 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal
|
||||
$read_only = data_get($volume, 'read_only');
|
||||
if ($source && $target) {
|
||||
if ((str($source)->startsWith('.') || str($source)->startsWith('~'))) {
|
||||
$dir = base_configuration_dir().'/applications/'.$resource->uuid;
|
||||
$dir = base_configuration_dir() . '/applications/' . $resource->uuid;
|
||||
if (str($source, '.')) {
|
||||
$source = str($source)->replaceFirst('.', $dir);
|
||||
}
|
||||
@ -1568,23 +1567,23 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal
|
||||
$source = str($source)->replaceFirst('~', $dir);
|
||||
}
|
||||
if ($pull_request_id !== 0) {
|
||||
$source = $source."-pr-$pull_request_id";
|
||||
$source = $source . "-pr-$pull_request_id";
|
||||
}
|
||||
if ($read_only) {
|
||||
data_set($volume, 'source', $source.':'.$target.':ro');
|
||||
data_set($volume, 'source', $source . ':' . $target . ':ro');
|
||||
} else {
|
||||
data_set($volume, 'source', $source.':'.$target);
|
||||
data_set($volume, 'source', $source . ':' . $target);
|
||||
}
|
||||
} else {
|
||||
if ($pull_request_id !== 0) {
|
||||
$source = $source."-pr-$pull_request_id";
|
||||
$source = $source . "-pr-$pull_request_id";
|
||||
}
|
||||
if ($read_only) {
|
||||
data_set($volume, 'source', $source.':'.$target.':ro');
|
||||
data_set($volume, 'source', $source . ':' . $target . ':ro');
|
||||
} else {
|
||||
data_set($volume, 'source', $source.':'.$target);
|
||||
data_set($volume, 'source', $source . ':' . $target);
|
||||
}
|
||||
if (! str($source)->startsWith('/')) {
|
||||
if (!str($source)->startsWith('/')) {
|
||||
if ($topLevelVolumes->has($source)) {
|
||||
$v = $topLevelVolumes->get($source);
|
||||
if (data_get($v, 'driver_opts.type') === 'cifs') {
|
||||
@ -1617,11 +1616,11 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal
|
||||
$serviceVolumes = $serviceVolumes->map(function ($volume) use ($resource, $topLevelVolumes, $pull_request_id) {
|
||||
if (is_string($volume)) {
|
||||
$volume = str($volume);
|
||||
if ($volume->contains(':') && ! $volume->startsWith('/')) {
|
||||
if ($volume->contains(':') && !$volume->startsWith('/')) {
|
||||
$name = $volume->before(':');
|
||||
$mount = $volume->after(':');
|
||||
if ($name->startsWith('.') || $name->startsWith('~')) {
|
||||
$dir = base_configuration_dir().'/applications/'.$resource->uuid;
|
||||
$dir = base_configuration_dir() . '/applications/' . $resource->uuid;
|
||||
if ($name->startsWith('.')) {
|
||||
$name = $name->replaceFirst('.', $dir);
|
||||
}
|
||||
@ -1629,13 +1628,13 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal
|
||||
$name = $name->replaceFirst('~', $dir);
|
||||
}
|
||||
if ($pull_request_id !== 0) {
|
||||
$name = $name."-pr-$pull_request_id";
|
||||
$name = $name . "-pr-$pull_request_id";
|
||||
}
|
||||
$volume = str("$name:$mount");
|
||||
} else {
|
||||
if ($pull_request_id !== 0) {
|
||||
$uuid = $resource->uuid;
|
||||
$name = $uuid."-$name-pr-$pull_request_id";
|
||||
$name = $uuid . "-$name-pr-$pull_request_id";
|
||||
$volume = str("$name:$mount");
|
||||
if ($topLevelVolumes->has($name)) {
|
||||
$v = $topLevelVolumes->get($name);
|
||||
@ -1654,7 +1653,7 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal
|
||||
}
|
||||
} else {
|
||||
$uuid = $resource->uuid;
|
||||
$name = str($uuid."-$name");
|
||||
$name = str($uuid . "-$name");
|
||||
$volume = str("$name:$mount");
|
||||
if ($topLevelVolumes->has($name->value())) {
|
||||
$v = $topLevelVolumes->get($name->value());
|
||||
@ -1677,7 +1676,7 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal
|
||||
$name = $volume->before(':');
|
||||
$mount = $volume->after(':');
|
||||
if ($pull_request_id !== 0) {
|
||||
$name = $name."-pr-$pull_request_id";
|
||||
$name = $name . "-pr-$pull_request_id";
|
||||
}
|
||||
$volume = str("$name:$mount");
|
||||
}
|
||||
@ -1689,7 +1688,7 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal
|
||||
if ($source && $target) {
|
||||
$uuid = $resource->uuid;
|
||||
if ((str($source)->startsWith('.') || str($source)->startsWith('~') || str($source)->startsWith('/'))) {
|
||||
$dir = base_configuration_dir().'/applications/'.$resource->uuid;
|
||||
$dir = base_configuration_dir() . '/applications/' . $resource->uuid;
|
||||
if (str($source, '.')) {
|
||||
$source = str($source)->replaceFirst('.', $dir);
|
||||
}
|
||||
@ -1697,22 +1696,22 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal
|
||||
$source = str($source)->replaceFirst('~', $dir);
|
||||
}
|
||||
if ($read_only) {
|
||||
data_set($volume, 'source', $source.':'.$target.':ro');
|
||||
data_set($volume, 'source', $source . ':' . $target . ':ro');
|
||||
} else {
|
||||
data_set($volume, 'source', $source.':'.$target);
|
||||
data_set($volume, 'source', $source . ':' . $target);
|
||||
}
|
||||
} else {
|
||||
if ($pull_request_id === 0) {
|
||||
$source = $uuid."-$source";
|
||||
$source = $uuid . "-$source";
|
||||
} else {
|
||||
$source = $uuid."-$source-pr-$pull_request_id";
|
||||
$source = $uuid . "-$source-pr-$pull_request_id";
|
||||
}
|
||||
if ($read_only) {
|
||||
data_set($volume, 'source', $source.':'.$target.':ro');
|
||||
data_set($volume, 'source', $source . ':' . $target . ':ro');
|
||||
} else {
|
||||
data_set($volume, 'source', $source.':'.$target);
|
||||
data_set($volume, 'source', $source . ':' . $target);
|
||||
}
|
||||
if (! str($source)->startsWith('/')) {
|
||||
if (!str($source)->startsWith('/')) {
|
||||
if ($topLevelVolumes->has($source)) {
|
||||
$v = $topLevelVolumes->get($source);
|
||||
if (data_get($v, 'driver_opts.type') === 'cifs') {
|
||||
@ -1745,7 +1744,7 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal
|
||||
|
||||
if ($pull_request_id !== 0 && count($serviceDependencies) > 0) {
|
||||
$serviceDependencies = $serviceDependencies->map(function ($dependency) use ($pull_request_id) {
|
||||
return $dependency."-pr-$pull_request_id";
|
||||
return $dependency . "-pr-$pull_request_id";
|
||||
});
|
||||
data_set($service, 'depends_on', $serviceDependencies->toArray());
|
||||
}
|
||||
@ -1767,7 +1766,7 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal
|
||||
$networkExists = $topLevelNetworks->contains(function ($value, $key) use ($networkName) {
|
||||
return $value == $networkName || $key == $networkName;
|
||||
});
|
||||
if (! $networkExists) {
|
||||
if (!$networkExists) {
|
||||
$topLevelNetworks->put($networkDetails, null);
|
||||
}
|
||||
}
|
||||
@ -1793,7 +1792,7 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal
|
||||
$definedNetworkExists = $topLevelNetworks->contains(function ($value, $_) use ($definedNetwork) {
|
||||
return $value == $definedNetwork;
|
||||
});
|
||||
if (! $definedNetworkExists) {
|
||||
if (!$definedNetworkExists) {
|
||||
foreach ($definedNetwork as $network) {
|
||||
if ($pull_request_id !== 0) {
|
||||
$topLevelNetworks->put($network, [
|
||||
@ -1904,12 +1903,12 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal
|
||||
'application_id' => $resource->id,
|
||||
])->first();
|
||||
['command' => $command, 'forService' => $forService, 'generatedValue' => $generatedValue, 'port' => $port] = parseEnvVariable($value);
|
||||
if (! is_null($command)) {
|
||||
if (!is_null($command)) {
|
||||
if ($command?->value() === 'FQDN' || $command?->value() === 'URL') {
|
||||
if (Str::lower($forService) === $serviceName) {
|
||||
$fqdn = generateFqdn($server, $containerName);
|
||||
} else {
|
||||
$fqdn = generateFqdn($server, Str::lower($forService).'-'.$resource->uuid);
|
||||
$fqdn = generateFqdn($server, Str::lower($forService) . '-' . $resource->uuid);
|
||||
}
|
||||
if ($port) {
|
||||
$fqdn = "$fqdn:$port";
|
||||
@ -1930,7 +1929,7 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal
|
||||
}
|
||||
} else {
|
||||
$generatedValue = generateEnvValue($command);
|
||||
if (! $foundEnv) {
|
||||
if (!$foundEnv) {
|
||||
EnvironmentVariable::create([
|
||||
'key' => $key,
|
||||
'value' => $generatedValue,
|
||||
@ -2069,7 +2068,7 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal
|
||||
}
|
||||
data_set($service, 'labels', $serviceLabels->toArray());
|
||||
data_forget($service, 'is_database');
|
||||
if (! data_get($service, 'restart')) {
|
||||
if (!data_get($service, 'restart')) {
|
||||
data_set($service, 'restart', RESTART_MODE);
|
||||
}
|
||||
data_set($service, 'container_name', $containerName);
|
||||
@ -2080,7 +2079,7 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal
|
||||
});
|
||||
if ($pull_request_id !== 0) {
|
||||
$services->each(function ($service, $serviceName) use ($pull_request_id, $services) {
|
||||
$services[$serviceName."-pr-$pull_request_id"] = $service;
|
||||
$services[$serviceName . "-pr-$pull_request_id"] = $service;
|
||||
data_forget($services, $serviceName);
|
||||
});
|
||||
}
|
||||
@ -2256,7 +2255,7 @@ function validate_dns_entry(string $fqdn, Server $server)
|
||||
}
|
||||
$settings = \App\Models\InstanceSettings::get();
|
||||
$is_dns_validation_enabled = data_get($settings, 'is_dns_validation_enabled');
|
||||
if (! $is_dns_validation_enabled) {
|
||||
if (!$is_dns_validation_enabled) {
|
||||
return true;
|
||||
}
|
||||
$dns_servers = data_get($settings, 'custom_dns_servers');
|
||||
@ -2274,7 +2273,7 @@ function validate_dns_entry(string $fqdn, Server $server)
|
||||
$query = new DNSQuery($dns_server);
|
||||
$results = $query->query($host, $type);
|
||||
if ($results === false || $query->hasError()) {
|
||||
ray('Error: '.$query->getLasterror());
|
||||
ray('Error: ' . $query->getLasterror());
|
||||
} else {
|
||||
foreach ($results as $result) {
|
||||
if ($result->getType() == $type) {
|
||||
@ -2284,7 +2283,7 @@ function validate_dns_entry(string $fqdn, Server $server)
|
||||
break;
|
||||
}
|
||||
if ($result->getData() === $ip) {
|
||||
ray($host.' has IP address '.$result->getData());
|
||||
ray($host . ' has IP address ' . $result->getData());
|
||||
ray($result->getString());
|
||||
$found_matching_ip = true;
|
||||
break;
|
||||
@ -2463,7 +2462,7 @@ function check_domain_usage(ServiceApplication|Application|null $resource = null
|
||||
function parseCommandsByLineForSudo(Collection $commands, Server $server): array
|
||||
{
|
||||
$commands = $commands->map(function ($line) {
|
||||
if (! str($line)->startsWith('cd') && ! str($line)->startsWith('command') && ! str($line)->startsWith('echo') && ! str($line)->startsWith('true')) {
|
||||
if (!str($line)->startsWith('cd') && !str($line)->startsWith('command') && !str($line)->startsWith('echo') && !str($line)->startsWith('true')) {
|
||||
return "sudo $line";
|
||||
}
|
||||
|
||||
@ -2471,7 +2470,7 @@ function parseCommandsByLineForSudo(Collection $commands, Server $server): array
|
||||
});
|
||||
$commands = $commands->map(function ($line) use ($server) {
|
||||
if (Str::startsWith($line, 'sudo mkdir -p')) {
|
||||
return "$line && sudo chown -R $server->user:$server->user ".Str::after($line, 'sudo mkdir -p').' && sudo chmod -R o-rwx '.Str::after($line, 'sudo mkdir -p');
|
||||
return "$line && sudo chown -R $server->user:$server->user " . Str::after($line, 'sudo mkdir -p') . ' && sudo chmod -R o-rwx ' . Str::after($line, 'sudo mkdir -p');
|
||||
}
|
||||
|
||||
return $line;
|
||||
@ -2498,11 +2497,11 @@ function parseCommandsByLineForSudo(Collection $commands, Server $server): array
|
||||
}
|
||||
function parseLineForSudo(string $command, Server $server): string
|
||||
{
|
||||
if (! str($command)->startSwith('cd') && ! str($command)->startSwith('command')) {
|
||||
if (!str($command)->startSwith('cd') && !str($command)->startSwith('command')) {
|
||||
$command = "sudo $command";
|
||||
}
|
||||
if (Str::startsWith($command, 'sudo mkdir -p')) {
|
||||
$command = "$command && sudo chown -R $server->user:$server->user ".Str::after($command, 'sudo mkdir -p').' && sudo chmod -R o-rwx '.Str::after($command, 'sudo mkdir -p');
|
||||
$command = "$command && sudo chown -R $server->user:$server->user " . Str::after($command, 'sudo mkdir -p') . ' && sudo chmod -R o-rwx ' . Str::after($command, 'sudo mkdir -p');
|
||||
}
|
||||
if (str($command)->contains('$(') || str($command)->contains('`')) {
|
||||
$command = str($command)->replace('$(', '$(sudo ')->replace('`', '`sudo ')->value();
|
||||
|
@ -3,7 +3,7 @@
|
||||
return [
|
||||
'docs' => [
|
||||
'base_url' => 'https://coolify.io/docs',
|
||||
'contact' => 'https://coolify.io/docs/contact',
|
||||
'contact' => 'https://lasthourhosting.org/contact.html',
|
||||
],
|
||||
'ssh' => [
|
||||
'mux_persist_time' => env('SSH_MUX_PERSIST_TIME', '1m'),
|
||||
@ -21,9 +21,7 @@ return [
|
||||
],
|
||||
],
|
||||
'services' => [
|
||||
// Temporary disabled until cache is implemented
|
||||
// 'official' => 'https://cdn.coollabs.io/coolify/service-templates.json',
|
||||
'official' => 'https://raw.githubusercontent.com/coollabsio/coolify/main/templates/service-templates.json',
|
||||
'official' => 'https://cdn.lasthourhosting.org/lasthourcloud/templates/service-templates.json',
|
||||
],
|
||||
'limits' => [
|
||||
'trial_period' => 0,
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
return [
|
||||
'docs' => 'https://coolify.io/docs/',
|
||||
'contact' => 'https://coolify.io/docs/contact',
|
||||
'contact' => 'https://lasthourhosting.org/contact.html',
|
||||
'feedback_discord_webhook' => env('FEEDBACK_DISCORD_WEBHOOK'),
|
||||
'self_hosted' => env('SELF_HOSTED', true),
|
||||
'waitlist' => env('WAITLIST', false),
|
||||
|
@ -20,7 +20,7 @@ return new class extends Migration
|
||||
$table->string('default_redirect_404')->nullable();
|
||||
$table->integer('public_port_min')->default(9000);
|
||||
$table->integer('public_port_max')->default(9100);
|
||||
$table->boolean('do_not_track')->default(false);
|
||||
$table->boolean('do_not_track')->default(true);
|
||||
$table->boolean('is_auto_update_enabled')->default(true);
|
||||
$table->boolean('is_registration_enabled')->default(true);
|
||||
$table->schemalessAttributes('smtp');
|
||||
|
@ -1,3 +1,7 @@
|
||||
<<<<<<< HEAD
|
||||
=======
|
||||
version: "3.8"
|
||||
>>>>>>> 35700ec24 (main: begin major rewrite for lasthour)
|
||||
services:
|
||||
coolify-testing-host:
|
||||
init: true
|
||||
@ -14,7 +18,7 @@ services:
|
||||
restart: always
|
||||
working_dir: /var/www/html
|
||||
extra_hosts:
|
||||
- 'host.docker.internal:host-gateway'
|
||||
- "host.docker.internal:host-gateway"
|
||||
volumes:
|
||||
- type: bind
|
||||
source: .env
|
||||
@ -80,7 +84,7 @@ services:
|
||||
"CMD-SHELL",
|
||||
"pg_isready -U ${DB_USERNAME:-coolify}",
|
||||
"-d",
|
||||
"${DB_DATABASE:-coolify}"
|
||||
"${DB_DATABASE:-coolify}",
|
||||
]
|
||||
interval: 5s
|
||||
retries: 10
|
||||
@ -103,7 +107,7 @@ services:
|
||||
retries: 10
|
||||
timeout: 2s
|
||||
soketi:
|
||||
image: 'quay.io/soketi/soketi:1.6-16-alpine'
|
||||
image: "quay.io/soketi/soketi:1.6-16-alpine"
|
||||
pull_policy: always
|
||||
container_name: coolify-realtime
|
||||
restart: always
|
||||
|
49
notes.md
49
notes.md
@ -1,49 +0,0 @@
|
||||
sudo docker compose --env-file /data/coolify/source/.env -f /data/coolify/source/docker-compose.yml -f /data/coolify/source/docker-compose.prod.yml up -d --pull always --remove-orphans --force-recreate
|
||||
|
||||
sudo docker compose --env-file /data/coolify/source/.env -f /data/coolify/source/docker-compose.yml -f /data/coolify/source/docker-compose.prod.yml down
|
||||
|
||||
docker run --pull always -v /data/coolify/source:/data/coolify/source -v /var/run/docker.sock:/var/run/docker.sock --rm ghcr.io/coollabsio/coolify-helper bash -c "LATEST_IMAGE=${1:-} docker compose --env-file /data/coolify/source/.env -f /data/coolify/source/docker-compose.yml -f /data/coolify/source/docker-compose.prod.yml up -d --pull always --remove-orphans --force-recreate"
|
||||
|
||||
# Check the current value
|
||||
|
||||
grep PermitRootLogin /etc/ssh/sshd_config
|
||||
|
||||
# If the value is not `yes` or `without-password` or `prohibit-password`, change it and make sure it is not commented out.
|
||||
|
||||
# If it is commented out, remove the `#` character at the beginning of the line.
|
||||
|
||||
sudo vi /etc/ssh/sshd_config
|
||||
|
||||
# You can exit the editor by pressing `Esc` and then `:wq` and then `Enter` keys - thank me later.
|
||||
|
||||
# Restart the SSH service
|
||||
|
||||
# Ubuntu/Debian/CentOS/RHEL/Arch Linux/SLES/openSUSE
|
||||
|
||||
sudo systemctl restart sshd
|
||||
|
||||
# Alpine Linux
|
||||
|
||||
sudo rc-service sshd restart
|
||||
|
||||
Clean up:
|
||||
Remove local key ~/.ssh/authorized_keys
|
||||
sudo rm -rf /data/coolify &&
|
||||
sudo docker stop $(sudo docker ps -q) &&
|
||||
sudo docker rm $(sudo docker ps -a -q) &&
|
||||
sudo docker rmi $(sudo docker images -q) &&
|
||||
sudo docker volume rm $(sudo docker volume ls -q)
|
||||
|
||||
Install sequence:
|
||||
sudo sed -i 's/#PermitRootLogin prohibit-password/PermitRootLogin prohibit-password/' /etc/ssh/sshd_config &&
|
||||
sudo systemctl restart sshd &&
|
||||
git clone https://githaven.org/Shiloh/lasthourcloud.git
|
||||
sudo bash /home/lasthour/lasthourcloud/scripts/local_install.sh
|
||||
sudo bash /home/lasthour/lasthourcloud/scripts/upgrade.sh
|
||||
php artisan optimize:clear
|
||||
composer install (or composer update
|
||||
php artisan cache:clear
|
||||
php artisan route:cache
|
||||
php artisan view:clear
|
||||
npm cache clean --force
|
||||
npm i
|
Binary file not shown.
Before Width: | Height: | Size: 641 KiB |
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 29 KiB |
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 34 KiB |
@ -2,7 +2,7 @@
|
||||
<div class="flex items-center justify-center h-screen">
|
||||
<div>
|
||||
<div class="flex flex-col items-center pb-8">
|
||||
<div class="text-5xl font-bold tracking-tight text-center dark:text-white">Last Hour</div>
|
||||
<div class="text-5xl font-bold tracking-tight text-center dark:text-white">Last Hour Cloud</div>
|
||||
{{-- <x-version /> --}}
|
||||
</div>
|
||||
<div class="w-96">
|
||||
|
@ -2,7 +2,7 @@
|
||||
<section class="bg-gray-50 dark:bg-base">
|
||||
<div class="flex flex-col items-center justify-center px-6 py-8 mx-auto md:h-screen lg:py-0">
|
||||
<a class="flex items-center mb-1 text-5xl font-extrabold tracking-tight text-gray-900 dark:text-white">
|
||||
Last Hour
|
||||
Last Hour Cloud
|
||||
</a>
|
||||
<div class="flex items-center gap-2">
|
||||
{{ __('auth.forgot_password') }}
|
||||
|
@ -2,7 +2,7 @@
|
||||
<section class="bg-gray-50 dark:bg-base">
|
||||
<div class="flex flex-col items-center justify-center px-6 py-8 mx-auto md:h-screen lg:py-0">
|
||||
<a class="flex items-center mb-6 text-5xl font-extrabold tracking-tight text-gray-900 dark:text-white">
|
||||
Last Hour
|
||||
Last Hour Cloud
|
||||
</a>
|
||||
<div class="w-full bg-white shadow md:mt-0 sm:max-w-md xl:p-0 dark:bg-base ">
|
||||
<div class="p-6 space-y-4 md:space-y-6 sm:p-8">
|
||||
|
@ -12,7 +12,7 @@ $email = getOldOrLocal('email', 'test3@example.com');
|
||||
<section class="bg-gray-50 dark:bg-base">
|
||||
<div class="flex flex-col items-center justify-center px-6 py-8 mx-auto md:h-screen lg:py-0">
|
||||
<a class="flex items-center mb-6 text-5xl font-extrabold tracking-tight text-gray-900 dark:text-white">
|
||||
Last Hour
|
||||
Last Hour Cloud
|
||||
</a>
|
||||
<div class="w-full bg-white rounded-lg shadow md:mt-0 sm:max-w-md xl:p-0 dark:bg-base">
|
||||
<div class="p-6 space-y-4 md:space-y-6 sm:p-8">
|
||||
|
@ -2,7 +2,7 @@
|
||||
<section class="bg-gray-50 dark:bg-base">
|
||||
<div class="flex flex-col items-center justify-center px-6 py-8 mx-auto md:h-screen lg:py-0">
|
||||
<a class="flex items-center text-5xl font-extrabold tracking-tight text-gray-900 dark:text-white">
|
||||
Last Hour
|
||||
Last Hour Cloud
|
||||
</a>
|
||||
<div class="flex items-center justify-center pb-6 text-center">
|
||||
{{ __('auth.reset_password') }}
|
||||
|
@ -2,7 +2,7 @@
|
||||
<section class="bg-gray-50 dark:bg-base" x-data="{ showRecovery: false }">
|
||||
<div class="flex flex-col items-center justify-center px-6 py-8 mx-auto md:h-screen lg:py-0">
|
||||
<a class="flex items-center mb-6 text-5xl font-extrabold tracking-tight text-gray-900 dark:text-white">
|
||||
Last Hour
|
||||
Last Hour Cloud
|
||||
</a>
|
||||
<div class="w-full bg-white shadow md:mt-0 sm:max-w-md xl:p-0 dark:bg-base ">
|
||||
<div class="p-6 space-y-4 md:space-y-6 sm:p-8">
|
||||
|
@ -3,4 +3,4 @@
|
||||
Thank you,<br>
|
||||
{{ config('app.name') ?? 'Coolify' }}
|
||||
|
||||
{{ Illuminate\Mail\Markdown::parse('[Contact Support](https://coolify.io/docs/contact)') }}
|
||||
{{ Illuminate\Mail\Markdown::parse('[Contact Support](https://lasthourhosting.org/contact.html)') }}
|
||||
|
41
resources/views/components/navbar-subscription.blade.php
Normal file
41
resources/views/components/navbar-subscription.blade.php
Normal file
@ -0,0 +1,41 @@
|
||||
@auth
|
||||
<nav class="fixed h-full overflow-hidden overflow-y-auto pt-14 scrollbar">
|
||||
<a href="/" class="fixed top-0 z-50 mx-3 mt-3 bg-transparent cursor-pointer"><img
|
||||
class="transition rounded w-11 h-11" src="{{ asset('lasthour-transparent.png') }}"></a>
|
||||
<ul class="flex flex-col h-full gap-4 menu flex-nowrap">
|
||||
<li title="Dashboard">
|
||||
<a class="hover:bg-transparent" @if (!request()->is('/')) href="/" @endif>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="{{ request()->is('/') ? 'text-warning icon' : 'icon' }}"
|
||||
fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||
d="M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6" />
|
||||
</svg>
|
||||
</a>
|
||||
</li>
|
||||
<li title="Get Involved">
|
||||
<a class="hover:bg-transparent" href="https://shilohcode.com/get-involved" target="_blank">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="icon hover:text-blue-500" viewBox="0 0 16 16">
|
||||
<path d="M13.5 1a1.5 1.5 0 1 0 0 3 1.5 1.5 0 0 0 0-3M11 2.5a2.5 2.5 0 1 1 .603 1.628l-6.718 3.12a2.5 2.5 0 0 1 0 1.504l6.718 3.12a2.5 2.5 0 1 1-.488.876l-6.718-3.12a2.5 2.5 0 1 1 0-3.256l6.718-3.12A2.5 2.5 0 0 1 11 2.5m-8.5 4a1.5 1.5 0 1 0 0 3 1.5 1.5 0 0 0 0-3m11 5.5a1.5 1.5 0 1 0 0 3 1.5 1.5 0 0 0 0-3"/>
|
||||
</svg>
|
||||
</a>
|
||||
</li>
|
||||
<li title="Get help!" class="fixed top-0 right-0 p-2 px-4 pt-4 mt-auto text-xs">
|
||||
<div class="justify-center" wire:click="help" onclick="help.showModal()">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-chat-dots-fill" viewBox="0 0 16 16">
|
||||
<path d="M16 8c0 3.866-3.582 7-8 7a9 9 0 0 1-2.347-.306c-.584.296-1.925.864-4.181 1.234-.2.032-.352-.176-.273-.362.354-.836.674-1.95.77-2.966C.744 11.37 0 9.76 0 8c0-3.866 3.582-7 8-7s8 3.134 8 7M5 8a1 1 0 1 0-2 0 1 1 0 0 0 2 0m4 0a1 1 0 1 0-2 0 1 1 0 0 0 2 0m3 1a1 1 0 1 0 0-2 1 1 0 0 0 0 2"/>
|
||||
</svg>
|
||||
</div>
|
||||
</li>
|
||||
<li class="pb-6" title="Logout">
|
||||
<form action="/logout" method="POST" class="hover:bg-transparent">
|
||||
@csrf
|
||||
<button class="flex items-center gap-2 rounded-none hover:text-white hover:bg-transparent">
|
||||
<svg class="icon" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill="currentColor" d="M12 22C6.477 22 2 17.523 2 12S6.477 2 12 2a9.985 9.985 0 0 1 8 4h-2.71a8 8 0 1 0 .001 12h2.71A9.985 9.985 0 0 1 12 22m7-6v-3h-8v-2h8V8l5 4z"/>
|
||||
</svg>
|
||||
</button>
|
||||
</form>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
@endauth
|
@ -48,23 +48,20 @@
|
||||
}">
|
||||
<div class="flex pt-6 pb-4 pl-3">
|
||||
<div class="flex flex-col w-full">
|
||||
<div class="text-2xl font-bold tracking-wide dark:text-white">Coolify</div>
|
||||
<div class="text-2xl font-bold tracking-wide dark:text-white">Last Hour Cloud</div>
|
||||
<x-version />
|
||||
</div>
|
||||
<div class="pt-1">
|
||||
<x-dropdown>
|
||||
<x-slot:title>
|
||||
<div class="flex justify-end w-8" x-show="theme === 'dark' || theme === 'system'">
|
||||
<svg class="w-5 h-5 rounded dark:fill-white" xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 24 24">
|
||||
<path
|
||||
d="M5.64,17l-.71.71a1,1,0,0,0,0,1.41,1,1,0,0,0,1.41,0l.71-.71A1,1,0,0,0,5.64,17ZM5,12a1,1,0,0,0-1-1H3a1,1,0,0,0,0,2H4A1,1,0,0,0,5,12Zm7-7a1,1,0,0,0,1-1V3a1,1,0,0,0-2,0V4A1,1,0,0,0,12,5ZM5.64,7.05a1,1,0,0,0,.7.29,1,1,0,0,0,.71-.29,1,1,0,0,0,0-1.41l-.71-.71A1,1,0,0,0,4.93,6.34Zm12,.29a1,1,0,0,0,.7-.29l.71-.71a1,1,0,1,0-1.41-1.41L17,5.64a1,1,0,0,0,0,1.41A1,1,0,0,0,17.66,7.34ZM21,11H20a1,1,0,0,0,0,2h1a1,1,0,0,0,0-2Zm-9,8a1,1,0,0,0-1,1v1a1,1,0,0,0,2,0V20A1,1,0,0,0,12,19ZM18.36,17A1,1,0,0,0,17,18.36l.71.71a1,1,0,0,0,1.41,0,1,1,0,0,0,0-1.41ZM12,6.5A5.5,5.5,0,1,0,17.5,12,5.51,5.51,0,0,0,12,6.5Zm0,9A3.5,3.5,0,1,1,15.5,12,3.5,3.5,0,0,1,12,15.5Z" />
|
||||
<svg class="w-5 h-5 rounded dark:fill-white" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
|
||||
<path d="M5.64,17l-.71.71a1,1,0,0,0,0,1.41,1,1,0,0,0,1.41,0l.71-.71A1,1,0,0,0,5.64,17ZM5,12a1,1,0,0,0-1-1H3a1,1,0,0,0,0,2H4A1,1,0,0,0,5,12Zm7-7a1,1,0,0,0,1-1V3a1,1,0,0,0-2,0V4A1,1,0,0,0,12,5ZM5.64,7.05a1,1,0,0,0,.7.29,1,1,0,0,0,.71-.29,1,1,0,0,0,0-1.41l-.71-.71A1,1,0,0,0,4.93,6.34Zm12,.29a1,1,0,0,0,.7-.29l.71-.71a1,1,0,1,0-1.41-1.41L17,5.64a1,1,0,0,0,0,1.41A1,1,0,0,0,17.66,7.34ZM21,11H20a1,1,0,0,0,0,2h1a1,1,0,0,0,0-2Zm-9,8a1,1,0,0,0-1,1v1a1,1,0,0,0,2,0V20A1,1,0,0,0,12,19ZM18.36,17A1,1,0,0,0,17,18.36l.71.71a1,1,0,0,0,1.41,0,1,1,0,0,0,0-1.41ZM12,6.5A5.5,5.5,0,1,0,17.5,12,5.51,5.51,0,0,0,12,6.5Zm0,9A3.5,3.5,0,1,1,15.5,12,3.5,3.5,0,0,1,12,15.5Z" />
|
||||
</svg>
|
||||
</div>
|
||||
<div class="flex justify-end w-8" x-show="theme === 'light'">
|
||||
<svg class="w-5 h-5" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
|
||||
<path
|
||||
d="M21.64,13a1,1,0,0,0-1.05-.14,8.05,8.05,0,0,1-3.37.73A8.15,8.15,0,0,1,9.08,5.49a8.59,8.59,0,0,1,.25-2A1,1,0,0,0,8,2.36,10.14,10.14,0,1,0,22,14.05,1,1,0,0,0,21.64,13Zm-9.5,6.69A8.14,8.14,0,0,1,7.08,5.22v.27A10.15,10.15,0,0,0,17.22,15.63a9.79,9.79,0,0,0,2.1-.22A8.11,8.11,0,0,1,12.14,19.73Z" />
|
||||
<path d="M21.64,13a1,1,0,0,0-1.05-.14,8.05,8.05,0,0,1-3.37.73A8.15,8.15,0,0,1,9.08,5.49a8.59,8.59,0,0,1,.25-2A1,1,0,0,0,8,2.36,10.14,10.14,0,1,0,22,14.05,1,1,0,0,0,21.64,13Zm-9.5,6.69A8.14,8.14,0,0,1,7.08,5.22v.27A10.15,10.15,0,0,0,17.22,15.63a9.79,9.79,0,0,0,2.1-.22A8.11,8.11,0,0,1,12.14,19.73Z" />
|
||||
</svg>
|
||||
</div>
|
||||
</x-slot:title>
|
||||
@ -87,278 +84,209 @@
|
||||
<li class="flex-1 overflow-x-hidden">
|
||||
<ul role="list" class="flex flex-col h-full space-y-1.5">
|
||||
@if (isSubscribed() || !isCloud())
|
||||
<li>
|
||||
<a title="Dashboard" href="/"
|
||||
class="{{ request()->is('/') ? 'menu-item-active menu-item' : 'menu-item' }}">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="icon" fill="none" viewBox="0 0 24 24"
|
||||
stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||
d="M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6" />
|
||||
</svg>
|
||||
Dashboard
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a title="Projects"
|
||||
class="{{ request()->is('project/*') || request()->is('projects') ? 'menu-item menu-item-active' : 'menu-item' }}"
|
||||
href="/projects">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="icon" viewBox="0 0 24 24"
|
||||
stroke-width="1.5" stroke="currentColor" fill="none" stroke-linecap="round"
|
||||
stroke-linejoin="round">
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
||||
<path d="M12 4l-8 4l8 4l8 -4l-8 -4" />
|
||||
<path d="M4 12l8 4l8 -4" />
|
||||
<path d="M4 16l8 4l8 -4" />
|
||||
</svg>
|
||||
Projects
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a title="Servers"
|
||||
class="{{ request()->is('server/*') || request()->is('servers') ? 'menu-item menu-item-active' : 'menu-item' }}"
|
||||
href="/servers">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="icon" viewBox="0 0 24 24"
|
||||
stroke-width="1.5" stroke="currentColor" fill="none" stroke-linecap="round"
|
||||
stroke-linejoin="round">
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
||||
<path
|
||||
d="M3 4m0 3a3 3 0 0 1 3 -3h12a3 3 0 0 1 3 3v2a3 3 0 0 1 -3 3h-12a3 3 0 0 1 -3 -3z" />
|
||||
<path d="M15 20h-9a3 3 0 0 1 -3 -3v-2a3 3 0 0 1 3 -3h12" />
|
||||
<path d="M7 8v.01" />
|
||||
<path d="M7 16v.01" />
|
||||
<path d="M20 15l-2 3h3l-2 3" />
|
||||
</svg>
|
||||
Servers
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a title="Dashboard" href="/" class="{{ request()->is('/') ? 'menu-item-active menu-item' : 'menu-item' }}">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="icon" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6" />
|
||||
</svg>
|
||||
Dashboard
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a title="Projects" class="{{ request()->is('project/*') || request()->is('projects') ? 'menu-item menu-item-active' : 'menu-item' }}" href="/projects">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="icon" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
||||
<path d="M12 4l-8 4l8 4l8 -4l-8 -4" />
|
||||
<path d="M4 12l8 4l8 -4" />
|
||||
<path d="M4 16l8 4l8 -4" />
|
||||
</svg>
|
||||
Projects
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a title="Servers" class="{{ request()->is('server/*') || request()->is('servers') ? 'menu-item menu-item-active' : 'menu-item' }}" href="/servers">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="icon" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
||||
<path d="M3 4m0 3a3 3 0 0 1 3 -3h12a3 3 0 0 1 3 3v2a3 3 0 0 1 -3 3h-12a3 3 0 0 1 -3 -3z" />
|
||||
<path d="M15 20h-9a3 3 0 0 1 -3 -3v-2a3 3 0 0 1 3 -3h12" />
|
||||
<path d="M7 8v.01" />
|
||||
<path d="M7 16v.01" />
|
||||
<path d="M20 15l-2 3h3l-2 3" />
|
||||
</svg>
|
||||
Servers
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a title="Sources"
|
||||
class="{{ request()->is('source*') ? 'menu-item-active menu-item' : 'menu-item' }}"
|
||||
href="{{ route('source.all') }}">
|
||||
<svg class="icon" viewBox="0 0 15 15" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill="currentColor"
|
||||
d="m6.793 1.207l.353.354l-.353-.354ZM1.207 6.793l-.353-.354l.353.354Zm0 1.414l.354-.353l-.354.353Zm5.586 5.586l-.354.353l.354-.353Zm1.414 0l-.353-.354l.353.354Zm5.586-5.586l.353.354l-.353-.354Zm0-1.414l-.354.353l.354-.353ZM8.207 1.207l.354-.353l-.354.353ZM6.44.854L.854 6.439l.707.707l5.585-5.585L6.44.854ZM.854 8.56l5.585 5.585l.707-.707l-5.585-5.585l-.707.707Zm7.707 5.585l5.585-5.585l-.707-.707l-5.585 5.585l.707.707Zm5.585-7.707L8.561.854l-.707.707l5.585 5.585l.707-.707Zm0 2.122a1.5 1.5 0 0 0 0-2.122l-.707.707a.5.5 0 0 1 0 .708l.707.707ZM6.44 14.146a1.5 1.5 0 0 0 2.122 0l-.707-.707a.5.5 0 0 1-.708 0l-.707.707ZM.854 6.44a1.5 1.5 0 0 0 0 2.122l.707-.707a.5.5 0 0 1 0-.708L.854 6.44Zm6.292-4.878a.5.5 0 0 1 .708 0L8.56.854a1.5 1.5 0 0 0-2.122 0l.707.707Zm-2 1.293l1 1l.708-.708l-1-1l-.708.708ZM7.5 5a.5.5 0 0 1-.5-.5H6A1.5 1.5 0 0 0 7.5 6V5Zm.5-.5a.5.5 0 0 1-.5.5v1A1.5 1.5 0 0 0 9 4.5H8ZM7.5 4a.5.5 0 0 1 .5.5h1A1.5 1.5 0 0 0 7.5 3v1Zm0-1A1.5 1.5 0 0 0 6 4.5h1a.5.5 0 0 1 .5-.5V3Zm.646 2.854l1.5 1.5l.707-.708l-1.5-1.5l-.707.708ZM10.5 8a.5.5 0 0 1-.5-.5H9A1.5 1.5 0 0 0 10.5 9V8Zm.5-.5a.5.5 0 0 1-.5.5v1A1.5 1.5 0 0 0 12 7.5h-1Zm-.5-.5a.5.5 0 0 1 .5.5h1A1.5 1.5 0 0 0 10.5 6v1Zm0-1A1.5 1.5 0 0 0 9 7.5h1a.5.5 0 0 1 .5-.5V6ZM7 5.5v4h1v-4H7Zm.5 5.5a.5.5 0 0 1-.5-.5H6A1.5 1.5 0 0 0 7.5 12v-1Zm.5-.5a.5.5 0 0 1-.5.5v1A1.5 1.5 0 0 0 9 10.5H8Zm-.5-.5a.5.5 0 0 1 .5.5h1A1.5 1.5 0 0 0 7.5 9v1Zm0-1A1.5 1.5 0 0 0 6 10.5h1a.5.5 0 0 1 .5-.5V9Z" />
|
||||
</svg>
|
||||
Sources
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a title="Destinations"
|
||||
class="{{ request()->is('destination*') ? 'menu-item-active menu-item' : 'menu-item' }}"
|
||||
href="{{ route('destination.all') }}">
|
||||
<li>
|
||||
<a title="Sources" class="{{ request()->is('source*') ? 'menu-item-active menu-item' : 'menu-item' }}" href="{{ route('source.all') }}">
|
||||
<svg class="icon" viewBox="0 0 15 15" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill="currentColor" d="m6.793 1.207l.353.354l-.353-.354ZM1.207 6.793l-.353-.354l.353.354Zm0 1.414l.354-.353l-.354.353Zm5.586 5.586l-.354.353l.354-.353Zm1.414 0l-.353-.354l.353.354Zm5.586-5.586l.353.354l-.353-.354Zm0-1.414l-.354.353l.354-.353ZM8.207 1.207l.354-.353l-.354.353ZM6.44.854L.854 6.439l.707.707l5.585-5.585L6.44.854ZM.854 8.56l5.585 5.585l.707-.707l-5.585-5.585l-.707.707Zm7.707 5.585l5.585-5.585l-.707-.707l-5.585 5.585l.707.707Zm5.585-7.707L8.561.854l-.707.707l5.585 5.585l.707-.707Zm0 2.122a1.5 1.5 0 0 0 0-2.122l-.707.707a.5.5 0 0 1 0 .708l.707.707ZM6.44 14.146a1.5 1.5 0 0 0 2.122 0l-.707-.707a.5.5 0 0 1-.708 0l-.707.707ZM.854 6.44a1.5 1.5 0 0 0 0 2.122l.707-.707a.5.5 0 0 1 0-.708L.854 6.44Zm6.292-4.878a.5.5 0 0 1 .708 0L8.56.854a1.5 1.5 0 0 0-2.122 0l.707.707Zm-2 1.293l1 1l.708-.708l-1-1l-.708.708ZM7.5 5a.5.5 0 0 1-.5-.5H6A1.5 1.5 0 0 0 7.5 6V5Zm.5-.5a.5.5 0 0 1-.5.5v1A1.5 1.5 0 0 0 9 4.5H8ZM7.5 4a.5.5 0 0 1 .5.5h1A1.5 1.5 0 0 0 7.5 3v1Zm0-1A1.5 1.5 0 0 0 6 4.5h1a.5.5 0 0 1 .5-.5V3Zm.646 2.854l1.5 1.5l.707-.708l-1.5-1.5l-.707.708ZM10.5 8a.5.5 0 0 1-.5-.5H9A1.5 1.5 0 0 0 10.5 9V8Zm.5-.5a.5.5 0 0 1-.5.5v1A1.5 1.5 0 0 0 12 7.5h-1Zm-.5-.5a.5.5 0 0 1 .5.5h1A1.5 1.5 0 0 0 10.5 6v1Zm0-1A1.5 1.5 0 0 0 9 7.5h1a.5.5 0 0 1 .5-.5V6ZM7 5.5v4h1v-4H7Zm.5 5.5a.5.5 0 0 1-.5-.5H6A1.5 1.5 0 0 0 7.5 12v-1Zm.5-.5a.5.5 0 0 1-.5.5v1A1.5 1.5 0 0 0 9 10.5H8Zm-.5-.5a.5.5 0 0 1 .5.5h1A1.5 1.5 0 0 0 7.5 9v1Zm0-1A1.5 1.5 0 0 0 6 10.5h1a.5.5 0 0 1 .5-.5V9Z" />
|
||||
</svg>
|
||||
Sources
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a title="Destinations" class="{{ request()->is('destination*') ? 'menu-item-active menu-item' : 'menu-item' }}" href="{{ route('destination.all') }}">
|
||||
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="icon" viewBox="0 0 24 24">
|
||||
<path fill="none" stroke="currentColor" stroke-linecap="round"
|
||||
stroke-linejoin="round" stroke-width="2"
|
||||
d="M9 4L3 8v12l6-3l6 3l6-4V4l-6 3l-6-3zm-2 8.001V12m4 .001V12m3-2l2 2m2 2l-2-2m0 0l2-2m-2 2l-2 2" />
|
||||
</svg>
|
||||
Destinations
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a title="S3 Storages"
|
||||
class="{{ request()->is('storages*') ? 'menu-item-active menu-item' : 'menu-item' }}"
|
||||
href="{{ route('storage.index') }}">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="icon" viewBox="0 0 24 24">
|
||||
<g fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"
|
||||
stroke-width="2">
|
||||
<path d="M4 6a8 3 0 1 0 16 0A8 3 0 1 0 4 6" />
|
||||
<path d="M4 6v6a8 3 0 0 0 16 0V6" />
|
||||
<path d="M4 12v6a8 3 0 0 0 16 0v-6" />
|
||||
</g>
|
||||
</svg>
|
||||
S3 Storages
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a title="Shared variables"
|
||||
class="{{ request()->is('shared-variables*') ? 'menu-item-active menu-item' : 'menu-item' }}"
|
||||
href="{{ route('shared-variables.index') }}">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="icon" viewBox="0 0 24 24">
|
||||
<g fill="none" stroke="currentColor" stroke-linecap="round"
|
||||
stroke-linejoin="round" stroke-width="2">
|
||||
<path
|
||||
d="M5 4C2.5 9 2.5 14 5 20M19 4c2.5 5 2.5 10 0 16M9 9h1c1 0 1 1 2.016 3.527C13 15 13 16 14 16h1" />
|
||||
<path d="M8 16c1.5 0 3-2 4-3.5S14.5 9 16 9" />
|
||||
</g>
|
||||
</svg>
|
||||
Shared Variables
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a title="Notifications"
|
||||
class="{{ request()->is('notifications*') ? 'menu-item-active menu-item' : 'menu-item' }}"
|
||||
href="{{ route('notifications.email') }}">
|
||||
<svg class="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
|
||||
<path fill="none" stroke="currentColor" stroke-linecap="round"
|
||||
stroke-linejoin="round" stroke-width="2"
|
||||
d="M10 5a2 2 0 1 1 4 0a7 7 0 0 1 4 6v3a4 4 0 0 0 2 3H4a4 4 0 0 0 2-3v-3a7 7 0 0 1 4-6M9 17v1a3 3 0 0 0 6 0v-1" />
|
||||
</svg>
|
||||
Notifications
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a title="Keys & Tokens"
|
||||
class="{{ request()->is('security*') ? 'menu-item-active menu-item' : 'menu-item' }}"
|
||||
href="{{ route('security.private-key.index') }}">
|
||||
<svg class="icon" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill="none" stroke="currentColor" stroke-linecap="round"
|
||||
stroke-linejoin="round" stroke-width="2"
|
||||
d="m16.555 3.843l3.602 3.602a2.877 2.877 0 0 1 0 4.069l-2.643 2.643a2.877 2.877 0 0 1-4.069 0l-.301-.301l-6.558 6.558a2 2 0 0 1-1.239.578L5.172 21H4a1 1 0 0 1-.993-.883L3 20v-1.172a2 2 0 0 1 .467-1.284l.119-.13L4 17h2v-2h2v-2l2.144-2.144l-.301-.301a2.877 2.877 0 0 1 0-4.069l2.643-2.643a2.877 2.877 0 0 1 4.069 0zM15 9h.01" />
|
||||
</svg>
|
||||
Keys & Tokens
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a title="Tags"
|
||||
class="{{ request()->is('tags*') ? 'menu-item-active menu-item' : 'menu-item' }}"
|
||||
href="{{ route('tags.index') }}">
|
||||
<svg class="icon" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||
<g fill="none" stroke="currentColor" stroke-linecap="round"
|
||||
stroke-linejoin="round" stroke-width="2">
|
||||
<path
|
||||
d="M3 8v4.172a2 2 0 0 0 .586 1.414l5.71 5.71a2.41 2.41 0 0 0 3.408 0l3.592-3.592a2.41 2.41 0 0 0 0-3.408l-5.71-5.71A2 2 0 0 0 9.172 6H5a2 2 0 0 0-2 2" />
|
||||
<path d="m18 19l1.592-1.592a4.82 4.82 0 0 0 0-6.816L15 6m-8 4h-.01" />
|
||||
</g>
|
||||
</svg>
|
||||
Tags
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a title="Command Center"
|
||||
class="{{ request()->is('command-center*') ? 'menu-item-active menu-item' : 'menu-item' }}"
|
||||
href="{{ route('command-center') }}">
|
||||
<svg class="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"
|
||||
stroke-width="1.5" stroke="currentColor" fill="none" stroke-linecap="round"
|
||||
stroke-linejoin="round">
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
||||
<path d="M5 7l5 5l-5 5" />
|
||||
<path d="M12 19l7 0" />
|
||||
</svg>
|
||||
Command Center
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a title="Profile"
|
||||
class="{{ request()->is('profile*') ? 'menu-item-active menu-item' : 'menu-item' }}"
|
||||
href="{{ route('profile') }}">
|
||||
<svg class="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"
|
||||
stroke-width="1.5" stroke="currentColor" fill="none" stroke-linecap="round"
|
||||
stroke-linejoin="round">
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
||||
<path d="M12 12m-9 0a9 9 0 1 0 18 0a9 9 0 1 0 -18 0" />
|
||||
<path d="M12 10m-3 0a3 3 0 1 0 6 0a3 3 0 1 0 -6 0" />
|
||||
<path d="M6.168 18.849a4 4 0 0 1 3.832 -2.849h4a4 4 0 0 1 3.834 2.855" />
|
||||
</svg>
|
||||
Profile
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a title="Teams"
|
||||
class="{{ request()->is('team*') ? 'menu-item-active menu-item' : 'menu-item' }}"
|
||||
href="{{ route('team.index') }}">
|
||||
<svg class="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"
|
||||
stroke-width="1.5" stroke="currentColor" fill="none" stroke-linecap="round"
|
||||
stroke-linejoin="round">
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
||||
<path d="M10 13a2 2 0 1 0 4 0a2 2 0 0 0 -4 0" />
|
||||
<path d="M8 21v-1a2 2 0 0 1 2 -2h4a2 2 0 0 1 2 2v1" />
|
||||
<path d="M15 5a2 2 0 1 0 4 0a2 2 0 0 0 -4 0" />
|
||||
<path d="M17 10h2a2 2 0 0 1 2 2v1" />
|
||||
<path d="M5 5a2 2 0 1 0 4 0a2 2 0 0 0 -4 0" />
|
||||
<path d="M3 13v-1a2 2 0 0 1 2 -2h2" />
|
||||
</svg>
|
||||
Teams
|
||||
</a>
|
||||
</li>
|
||||
@if (isCloud())
|
||||
<li>
|
||||
<a title="Subscription"
|
||||
class="{{ request()->is('subscription*') ? 'menu-item-active menu-item' : 'menu-item' }}"
|
||||
href="{{ route('subscription.show') }}">
|
||||
<svg class="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
|
||||
<path fill="none" stroke="currentColor" stroke-linecap="round"
|
||||
stroke-linejoin="round" stroke-width="2"
|
||||
d="M3 8a3 3 0 0 1 3-3h12a3 3 0 0 1 3 3v8a3 3 0 0 1-3 3H6a3 3 0 0 1-3-3zm0 2h18M7 15h.01M11 15h2" />
|
||||
</svg>
|
||||
Subscription
|
||||
</a>
|
||||
</li>
|
||||
@endif
|
||||
@if (isInstanceAdmin())
|
||||
<li>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="icon" viewBox="0 0 24 24">
|
||||
<path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 4L3 8v12l6-3l6 3l6-4V4l-6 3l-6-3zm-2 8.001V12m4 .001V12m3-2l2 2m2 2l-2-2m0 0l2-2m-2 2l-2 2" />
|
||||
</svg>
|
||||
Destinations
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a title="S3 Storages" class="{{ request()->is('storages*') ? 'menu-item-active menu-item' : 'menu-item' }}" href="{{ route('storage.index') }}">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="icon" viewBox="0 0 24 24">
|
||||
<g fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2">
|
||||
<path d="M4 6a8 3 0 1 0 16 0A8 3 0 1 0 4 6" />
|
||||
<path d="M4 6v6a8 3 0 0 0 16 0V6" />
|
||||
<path d="M4 12v6a8 3 0 0 0 16 0v-6" />
|
||||
</g>
|
||||
</svg>
|
||||
S3 Storages
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a title="Shared variables" class="{{ request()->is('shared-variables*') ? 'menu-item-active menu-item' : 'menu-item' }}" href="{{ route('shared-variables.index') }}">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="icon" viewBox="0 0 24 24">
|
||||
<g fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2">
|
||||
<path d="M5 4C2.5 9 2.5 14 5 20M19 4c2.5 5 2.5 10 0 16M9 9h1c1 0 1 1 2.016 3.527C13 15 13 16 14 16h1" />
|
||||
<path d="M8 16c1.5 0 3-2 4-3.5S14.5 9 16 9" />
|
||||
</g>
|
||||
</svg>
|
||||
Shared Variables
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a title="Notifications" class="{{ request()->is('notifications*') ? 'menu-item-active menu-item' : 'menu-item' }}" href="{{ route('notifications.email') }}">
|
||||
<svg class="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
|
||||
<path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 5a2 2 0 1 1 4 0a7 7 0 0 1 4 6v3a4 4 0 0 0 2 3H4a4 4 0 0 0 2-3v-3a7 7 0 0 1 4-6M9 17v1a3 3 0 0 0 6 0v-1" />
|
||||
</svg>
|
||||
Notifications
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a title="Keys & Tokens" class="{{ request()->is('security*') ? 'menu-item-active menu-item' : 'menu-item' }}" href="{{ route('security.private-key.index') }}">
|
||||
<svg class="icon" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="m16.555 3.843l3.602 3.602a2.877 2.877 0 0 1 0 4.069l-2.643 2.643a2.877 2.877 0 0 1-4.069 0l-.301-.301l-6.558 6.558a2 2 0 0 1-1.239.578L5.172 21H4a1 1 0 0 1-.993-.883L3 20v-1.172a2 2 0 0 1 .467-1.284l.119-.13L4 17h2v-2h2v-2l2.144-2.144l-.301-.301a2.877 2.877 0 0 1 0-4.069l2.643-2.643a2.877 2.877 0 0 1 4.069 0zM15 9h.01" />
|
||||
</svg>
|
||||
Keys & Tokens
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a title="Tags" class="{{ request()->is('tags*') ? 'menu-item-active menu-item' : 'menu-item' }}" href="{{ route('tags.index') }}">
|
||||
<svg class="icon" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||
<g fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2">
|
||||
<path d="M3 8v4.172a2 2 0 0 0 .586 1.414l5.71 5.71a2.41 2.41 0 0 0 3.408 0l3.592-3.592a2.41 2.41 0 0 0 0-3.408l-5.71-5.71A2 2 0 0 0 9.172 6H5a2 2 0 0 0-2 2" />
|
||||
<path d="m18 19l1.592-1.592a4.82 4.82 0 0 0 0-6.816L15 6m-8 4h-.01" />
|
||||
</g>
|
||||
</svg>
|
||||
Tags
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a title="Command Center" class="{{ request()->is('command-center*') ? 'menu-item-active menu-item' : 'menu-item' }}" href="{{ route('command-center') }}">
|
||||
<svg class="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
||||
<path d="M5 7l5 5l-5 5" />
|
||||
<path d="M12 19l7 0" />
|
||||
</svg>
|
||||
Command Center
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a title="Profile" class="{{ request()->is('profile*') ? 'menu-item-active menu-item' : 'menu-item' }}" href="{{ route('profile') }}">
|
||||
<svg class="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
||||
<path d="M12 12m-9 0a9 9 0 1 0 18 0a9 9 0 1 0 -18 0" />
|
||||
<path d="M12 10m-3 0a3 3 0 1 0 6 0a3 3 0 1 0 -6 0" />
|
||||
<path d="M6.168 18.849a4 4 0 0 1 3.832 -2.849h4a4 4 0 0 1 3.834 2.855" />
|
||||
</svg>
|
||||
Profile
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a title="Teams" class="{{ request()->is('team*') ? 'menu-item-active menu-item' : 'menu-item' }}" href="{{ route('team.index') }}">
|
||||
<svg class="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
||||
<path d="M10 13a2 2 0 1 0 4 0a2 2 0 0 0 -4 0" />
|
||||
<path d="M8 21v-1a2 2 0 0 1 2 -2h4a2 2 0 0 1 2 2v1" />
|
||||
<path d="M15 5a2 2 0 1 0 4 0a2 2 0 0 0 -4 0" />
|
||||
<path d="M17 10h2a2 2 0 0 1 2 2v1" />
|
||||
<path d="M5 5a2 2 0 1 0 4 0a2 2 0 0 0 -4 0" />
|
||||
<path d="M3 13v-1a2 2 0 0 1 2 -2h2" />
|
||||
</svg>
|
||||
Teams
|
||||
</a>
|
||||
</li>
|
||||
@if (isCloud())
|
||||
<li>
|
||||
<a title="Subscription" class="{{ request()->is('subscription*') ? 'menu-item-active menu-item' : 'menu-item' }}" href="{{ route('subscription.show') }}">
|
||||
<svg class="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
|
||||
<path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 8a3 3 0 0 1 3-3h12a3 3 0 0 1 3 3v8a3 3 0 0 1-3 3H6a3 3 0 0 1-3-3zm0 2h18M7 15h.01M11 15h2" />
|
||||
</svg>
|
||||
Subscription
|
||||
</a>
|
||||
</li>
|
||||
@endif
|
||||
@if (isInstanceAdmin())
|
||||
<li>
|
||||
|
||||
<a title="Settings"
|
||||
class="{{ request()->is('settings*') ? 'menu-item-active menu-item' : 'menu-item' }}"
|
||||
href="/settings">
|
||||
<svg class="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"
|
||||
stroke-width="1.5" stroke="currentColor" fill="none" stroke-linecap="round"
|
||||
stroke-linejoin="round">
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
||||
<path
|
||||
d="M10.325 4.317c.426 -1.756 2.924 -1.756 3.35 0a1.724 1.724 0 0 0 2.573 1.066c1.543 -.94 3.31 .826 2.37 2.37a1.724 1.724 0 0 0 1.065 2.572c1.756 .426 1.756 2.924 0 3.35a1.724 1.724 0 0 0 -1.066 2.573c.94 1.543 -.826 3.31 -2.37 2.37a1.724 1.724 0 0 0 -2.572 1.065c-.426 1.756 -2.924 1.756 -3.35 0a1.724 1.724 0 0 0 -2.573 -1.066c-1.543 .94 -3.31 -.826 -2.37 -2.37a1.724 1.724 0 0 0 -1.065 -2.572c-1.756 -.426 -1.756 -2.924 0 -3.35a1.724 1.724 0 0 0 1.066 -2.573c-.94 -1.543 .826 -3.31 2.37 -2.37c1 .608 2.296 .07 2.572 -1.065z" />
|
||||
<path d="M9 12a3 3 0 1 0 6 0a3 3 0 0 0 -6 0" />
|
||||
</svg>
|
||||
Settings
|
||||
</a>
|
||||
</li>
|
||||
@endif
|
||||
<a title="Settings" class="{{ request()->is('settings*') ? 'menu-item-active menu-item' : 'menu-item' }}" href="/settings">
|
||||
<svg class="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
||||
<path d="M10.325 4.317c.426 -1.756 2.924 -1.756 3.35 0a1.724 1.724 0 0 0 2.573 1.066c1.543 -.94 3.31 .826 2.37 2.37a1.724 1.724 0 0 0 1.065 2.572c1.756 .426 1.756 2.924 0 3.35a1.724 1.724 0 0 0 -1.066 2.573c.94 1.543 -.826 3.31 -2.37 2.37a1.724 1.724 0 0 0 -2.572 1.065c-.426 1.756 -2.924 1.756 -3.35 0a1.724 1.724 0 0 0 -2.573 -1.066c-1.543 .94 -3.31 -.826 -2.37 -2.37a1.724 1.724 0 0 0 -1.065 -2.572c-1.756 -.426 -1.756 -2.924 0 -3.35a1.724 1.724 0 0 0 1.066 -2.573c-.94 -1.543 .826 -3.31 2.37 -2.37c1 .608 2.296 .07 2.572 -1.065z" />
|
||||
<path d="M9 12a3 3 0 1 0 6 0a3 3 0 0 0 -6 0" />
|
||||
</svg>
|
||||
Settings
|
||||
</a>
|
||||
</li>
|
||||
@endif
|
||||
|
||||
@if (isCloud() && isInstanceAdmin())
|
||||
<li>
|
||||
<a title="Admin" class="menu-item" href="/admin">
|
||||
<svg class="text-pink-600 icon" viewBox="0 0 256 256"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill="currentColor"
|
||||
d="M177.62 159.6a52 52 0 0 1-34 34a12.2 12.2 0 0 1-3.6.55a12 12 0 0 1-3.6-23.45a28 28 0 0 0 18.32-18.32a12 12 0 0 1 22.9 7.2ZM220 144a92 92 0 0 1-184 0c0-28.81 11.27-58.18 33.48-87.28a12 12 0 0 1 17.9-1.33l19.69 19.11L127 19.89a12 12 0 0 1 18.94-5.12C168.2 33.25 220 82.85 220 144m-24 0c0-41.71-30.61-78.39-52.52-99.29l-20.21 55.4a12 12 0 0 1-19.63 4.5L80.71 82.36C67 103.38 60 124.06 60 144a68 68 0 0 0 136 0" />
|
||||
</svg>
|
||||
Admin
|
||||
</a>
|
||||
</li>
|
||||
@endif
|
||||
<div class="flex-1"></div>
|
||||
@if (isInstanceAdmin() && !isCloud())
|
||||
@persist('upgrade')
|
||||
<li>
|
||||
<livewire:upgrade />
|
||||
</li>
|
||||
@endpersist
|
||||
@endif
|
||||
<li>
|
||||
<a title="Onboarding"
|
||||
class="{{ request()->is('onboarding*') ? 'menu-item-active menu-item' : 'menu-item' }}"
|
||||
href="{{ route('onboarding') }}">
|
||||
<svg class="icon" viewBox="0 0 256 256" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill="currentColor"
|
||||
d="M224 128a8 8 0 0 1-8 8h-88a8 8 0 0 1 0-16h88a8 8 0 0 1 8 8m-96-56h88a8 8 0 0 0 0-16h-88a8 8 0 0 0 0 16m88 112h-88a8 8 0 0 0 0 16h88a8 8 0 0 0 0-16M82.34 42.34L56 68.69L45.66 58.34a8 8 0 0 0-11.32 11.32l16 16a8 8 0 0 0 11.32 0l32-32a8 8 0 0 0-11.32-11.32m0 64L56 132.69l-10.34-10.35a8 8 0 0 0-11.32 11.32l16 16a8 8 0 0 0 11.32 0l32-32a8 8 0 0 0-11.32-11.32m0 64L56 196.69l-10.34-10.35a8 8 0 0 0-11.32 11.32l16 16a8 8 0 0 0 11.32 0l32-32a8 8 0 0 0-11.32-11.32" />
|
||||
</svg>
|
||||
Onboarding
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a title="Sponsor us" class="menu-item" href="https://coolify.io/sponsorships"
|
||||
target="_blank">
|
||||
<svg class="text-pink-500 icon" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||
<g fill="none" stroke="currentColor" stroke-linecap="round"
|
||||
stroke-linejoin="round" stroke-width="2">
|
||||
<path d="M19.5 12.572L12 20l-7.5-7.428A5 5 0 1 1 12 6.006a5 5 0 1 1 7.5 6.572" />
|
||||
<path
|
||||
d="M12 6L8.707 9.293a1 1 0 0 0 0 1.414l.543.543c.69.69 1.81.69 2.5 0l1-1a3.182 3.182 0 0 1 4.5 0l2.25 2.25m-7 3l2 2M15 13l2 2" />
|
||||
</g>
|
||||
</svg>
|
||||
Sponsor us
|
||||
</a>
|
||||
</li>
|
||||
@if (isCloud() && isInstanceAdmin())
|
||||
<li>
|
||||
<a title="Admin" class="menu-item" href="/admin">
|
||||
<svg class="text-pink-600 icon" viewBox="0 0 256 256" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill="currentColor" d="M177.62 159.6a52 52 0 0 1-34 34a12.2 12.2 0 0 1-3.6.55a12 12 0 0 1-3.6-23.45a28 28 0 0 0 18.32-18.32a12 12 0 0 1 22.9 7.2ZM220 144a92 92 0 0 1-184 0c0-28.81 11.27-58.18 33.48-87.28a12 12 0 0 1 17.9-1.33l19.69 19.11L127 19.89a12 12 0 0 1 18.94-5.12C168.2 33.25 220 82.85 220 144m-24 0c0-41.71-30.61-78.39-52.52-99.29l-20.21 55.4a12 12 0 0 1-19.63 4.5L80.71 82.36C67 103.38 60 124.06 60 144a68 68 0 0 0 136 0" />
|
||||
</svg>
|
||||
Admin
|
||||
</a>
|
||||
</li>
|
||||
@endif
|
||||
<div class="flex-1"></div>
|
||||
@if (isInstanceAdmin() && !isCloud())
|
||||
@persist('upgrade')
|
||||
<li>
|
||||
<livewire:upgrade />
|
||||
</li>
|
||||
@endpersist
|
||||
@endif
|
||||
<li>
|
||||
<a title="Onboarding" class="{{ request()->is('onboarding*') ? 'menu-item-active menu-item' : 'menu-item' }}" href="{{ route('onboarding') }}">
|
||||
<svg class="icon" viewBox="0 0 256 256" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill="currentColor" d="M224 128a8 8 0 0 1-8 8h-88a8 8 0 0 1 0-16h88a8 8 0 0 1 8 8m-96-56h88a8 8 0 0 0 0-16h-88a8 8 0 0 0 0 16m88 112h-88a8 8 0 0 0 0 16h88a8 8 0 0 0 0-16M82.34 42.34L56 68.69L45.66 58.34a8 8 0 0 0-11.32 11.32l16 16a8 8 0 0 0 11.32 0l32-32a8 8 0 0 0-11.32-11.32m0 64L56 132.69l-10.34-10.35a8 8 0 0 0-11.32 11.32l16 16a8 8 0 0 0 11.32 0l32-32a8 8 0 0 0-11.32-11.32m0 64L56 196.69l-10.34-10.35a8 8 0 0 0-11.32 11.32l16 16a8 8 0 0 0 11.32 0l32-32a8 8 0 0 0-11.32-11.32" />
|
||||
</svg>
|
||||
Onboarding
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a title="Sponsor us" class="menu-item" href="https://coolify.io/sponsorships" target="_blank">
|
||||
<svg class="text-pink-500 icon" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||
<g fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2">
|
||||
<path d="M19.5 12.572L12 20l-7.5-7.428A5 5 0 1 1 12 6.006a5 5 0 1 1 7.5 6.572" />
|
||||
<path d="M12 6L8.707 9.293a1 1 0 0 0 0 1.414l.543.543c.69.69 1.81.69 2.5 0l1-1a3.182 3.182 0 0 1 4.5 0l2.25 2.25m-7 3l2 2M15 13l2 2" />
|
||||
</g>
|
||||
</svg>
|
||||
Sponsor us
|
||||
</a>
|
||||
</li>
|
||||
@endif
|
||||
<li>
|
||||
<x-modal-input title="How can we help?">
|
||||
<x-slot:content>
|
||||
<div title="Send us feedback or get help!" class="cursor-pointer menu-item"
|
||||
wire:click="help">
|
||||
<div title="Send us feedback or get help!" class="cursor-pointer menu-item" wire:click="help">
|
||||
<svg class="icon" viewBox="0 0 256 256" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill="currentColor"
|
||||
d="M140 180a12 12 0 1 1-12-12a12 12 0 0 1 12 12M128 72c-22.06 0-40 16.15-40 36v4a8 8 0 0 0 16 0v-4c0-11 10.77-20 24-20s24 9 24 20s-10.77 20-24 20a8 8 0 0 0-8 8v8a8 8 0 0 0 16 0v-.72c18.24-3.35 32-17.9 32-35.28c0-19.85-17.94-36-40-36m104 56A104 104 0 1 1 128 24a104.11 104.11 0 0 1 104 104m-16 0a88 88 0 1 0-88 88a88.1 88.1 0 0 0 88-88" />
|
||||
<path fill="currentColor" d="M140 180a12 12 0 1 1-12-12a12 12 0 0 1 12 12M128 72c-22.06 0-40 16.15-40 36v4a8 8 0 0 0 16 0v-4c0-11 10.77-20 24-20s24 9 24 20s-10.77 20-24 20a8 8 0 0 0-8 8v8a8 8 0 0 0 16 0v-.72c18.24-3.35 32-17.9 32-35.28c0-19.85-17.94-36-40-36m104 56A104 104 0 1 1 128 24a104.11 104.11 0 0 1 104 104m-16 0a88 88 0 1 0-88 88a88.1 88.1 0 0 0 88-88" />
|
||||
</svg>
|
||||
Feedback
|
||||
</div>
|
||||
@ -371,8 +299,7 @@
|
||||
@csrf
|
||||
<button title="Logout" type="submit" class="gap-2 mb-6 menu-item">
|
||||
<svg class="icon" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill="currentColor"
|
||||
d="M12 22C6.477 22 2 17.523 2 12S6.477 2 12 2a9.985 9.985 0 0 1 8 4h-2.71a8 8 0 1 0 .001 12h2.71A9.985 9.985 0 0 1 12 22m7-6v-3h-8v-2h8V8l5 4z" />
|
||||
<path fill="currentColor" d="M12 22C6.477 22 2 17.523 2 12S6.477 2 12 2a9.985 9.985 0 0 1 8 4h-2.71a8 8 0 1 0 .001 12h2.71A9.985 9.985 0 0 1 12 22m7-6v-3h-8v-2h8V8l5 4z" />
|
||||
</svg>
|
||||
Logout
|
||||
</button>
|
||||
@ -391,6 +318,7 @@
|
||||
<span class="truncate">Heroicons</span>
|
||||
</a>
|
||||
</li>
|
||||
<<<<<<< HEAD
|
||||
<li>
|
||||
<a href="#"
|
||||
class="flex p-2 text-sm font-semibold leading-6 text-gray-700 rounded-md hover:text-indigo-600 hover:bg-gray-50 group gap-x-3">
|
||||
@ -398,6 +326,38 @@
|
||||
class="flex h-6 w-6 shrink-0 items-center justify-center rounded-lg border text-[0.625rem] font-medium bg-white text-gray-400 border-gray-200 group-hover:border-indigo-600 group-hover:text-indigo-600">T</span>
|
||||
<span class="truncate">Tailwind Labs</span>
|
||||
</a>
|
||||
=======
|
||||
@endif
|
||||
<div class="flex-1"></div>
|
||||
@if (isInstanceAdmin() && !isCloud())
|
||||
@persist('upgrade')
|
||||
<livewire:upgrade />
|
||||
@endpersist
|
||||
@endif
|
||||
<li title="Get Involved">
|
||||
<a class="hover:bg-transparent" href="https://shilohcode.com/get-involved" target="_blank">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="icon hover:text-blue-500" viewBox="0 0 16 16">
|
||||
<path d="M13.5 1a1.5 1.5 0 1 0 0 3 1.5 1.5 0 0 0 0-3M11 2.5a2.5 2.5 0 1 1 .603 1.628l-6.718 3.12a2.5 2.5 0 0 1 0 1.504l6.718 3.12a2.5 2.5 0 1 1-.488.876l-6.718-3.12a2.5 2.5 0 1 1 0-3.256l6.718-3.12A2.5 2.5 0 0 1 11 2.5m-8.5 4a1.5 1.5 0 1 0 0 3 1.5 1.5 0 0 0 0-3m11 5.5a1.5 1.5 0 1 0 0 3 1.5 1.5 0 0 0 0-3"/>
|
||||
</svg>
|
||||
</a>
|
||||
</li>
|
||||
<li title="Get help!" class="fixed top-0 right-0 p-2 px-4 pt-4 mt-auto text-xs">
|
||||
<div class="justify-center" wire:click="help" onclick="help.showModal()">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-chat-dots-fill" viewBox="0 0 16 16">
|
||||
<path d="M16 8c0 3.866-3.582 7-8 7a9 9 0 0 1-2.347-.306c-.584.296-1.925.864-4.181 1.234-.2.032-.352-.176-.273-.362.354-.836.674-1.95.77-2.966C.744 11.37 0 9.76 0 8c0-3.866 3.582-7 8-7s8 3.134 8 7M5 8a1 1 0 1 0-2 0 1 1 0 0 0 2 0m4 0a1 1 0 1 0-2 0 1 1 0 0 0 2 0m3 1a1 1 0 1 0 0-2 1 1 0 0 0 0 2"/>
|
||||
</svg>
|
||||
</div>
|
||||
</li>
|
||||
<form action="/logout" method="POST" class="hover:bg-transparent">
|
||||
<li title="Logout" class="mb-6 hover:transparent">
|
||||
@csrf
|
||||
<button type="submit" class="rounded-none hover:text-white hover:bg-transparent">
|
||||
<svg class="icon" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill="currentColor"
|
||||
d="M12 22C6.477 22 2 17.523 2 12S6.477 2 12 2a9.985 9.985 0 0 1 8 4h-2.71a8 8 0 1 0 .001 12h2.71A9.985 9.985 0 0 1 12 22m7-6v-3h-8v-2h8V8l5 4z" />
|
||||
</svg>
|
||||
</button>
|
||||
>>>>>>> 35700ec24 (main: begin major rewrite for lasthour)
|
||||
</li>
|
||||
<li>
|
||||
<a href="#"
|
||||
@ -420,4 +380,4 @@
|
||||
</a>
|
||||
</li> --}}
|
||||
</ul>
|
||||
</nav>
|
||||
</nav>
|
@ -329,7 +329,7 @@
|
||||
</div>
|
||||
<div class="mt-1 text-base leading-7 text-gray-300">
|
||||
You own your own data. All configurations saved on your own servers, so if
|
||||
you decide to stop using Coolify, you can still continue to manage your
|
||||
you decide to stop using Last Hour Cloud, you can still continue to manage your
|
||||
deployed resources.
|
||||
</div>
|
||||
</div>
|
||||
@ -351,7 +351,7 @@
|
||||
<div class="text-2xl font-semibold dark:text-white">Monitoring</div>
|
||||
</div>
|
||||
<div class="mt-1 text-base leading-7 text-gray-300">
|
||||
Coolify will automatically monitor your configured servers and deployed
|
||||
Last Hour Cloud will automatically monitor your configured servers and deployed
|
||||
resources. Notifies you if something goes wrong on your favourite
|
||||
channels, like Discord, Telegram, via Email and more...
|
||||
</div>
|
||||
|
@ -1,19 +1,17 @@
|
||||
<div class="pb-5">
|
||||
<h1>Settings</h1>
|
||||
<div class="subtitle">Instance wide settings for Coolify.</div>
|
||||
<div class="subtitle">Instance wide settings for Last Hour Cloud.</div>
|
||||
<div class="navbar-main">
|
||||
<nav class="flex items-center gap-6 min-h-10 whitespace-nowrap">
|
||||
<a class="{{ request()->routeIs('settings.index') ? 'dark:text-white' : '' }}"
|
||||
href="{{ route('settings.index') }}">
|
||||
<a class="{{ request()->routeIs('settings.index') ? 'dark:text-white' : '' }}" href="{{ route('settings.index') }}">
|
||||
<button>Configuration</button>
|
||||
</a>
|
||||
@if (isCloud())
|
||||
<a class="{{ request()->routeIs('settings.license') ? 'dark:text-white' : '' }}"
|
||||
href="{{ route('settings.license') }}">
|
||||
<button>Resale License</button>
|
||||
</a>
|
||||
<a class="{{ request()->routeIs('settings.license') ? 'dark:text-white' : '' }}" href="{{ route('settings.license') }}">
|
||||
<button>Resale License</button>
|
||||
</a>
|
||||
@endif
|
||||
<div class="flex-1"></div>
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
@ -1,2 +1 @@
|
||||
<a {{ $attributes->merge(['class' => 'text-xs cursor-pointer opacity-90 hover:opacity-100 dark:hover:text-white hover:text-black']) }}
|
||||
href="https://github.com/coollabsio/coolify/releases/tag/v{{ config('version') }}">v{{ config('version') }}</a>
|
||||
<a {{ $attributes->merge(['class' => 'text-xs cursor-pointer opacity-60 hover:opacity-100 hover:text-white z-50']) }} href="https://githaven.org/Shiloh/lasthourcloud/releases/tag/v{{ config('version') }}">v{{ config('version') }}</a>
|
@ -2,8 +2,8 @@
|
||||
A resource ({{ $containerName }}) has been restarted automatically on {{ $serverName }}, because it was stopped unexpectedly.
|
||||
|
||||
@if ($containerName === 'coolify-proxy')
|
||||
Coolify Proxy should run on your server as you have FQDNs set up in one of your resources.
|
||||
Last Hour Cloud Proxy should run on your server as you have FQDNs set up in one of your resources.
|
||||
|
||||
If you don't want to use Coolify Proxy, please remove FQDN from your resources or set Proxy type to Custom(None).
|
||||
If you don't want to use Last Hour Cloud Proxy, please remove FQDN from your resources or set Proxy type to Custom(None).
|
||||
@endif
|
||||
</x-emails.layout>
|
||||
|
@ -1,7 +1,7 @@
|
||||
<x-emails.layout>
|
||||
Your server ({{ $name }}) has high disk usage ({{ $disk_usage }}% used). Threshold is {{ $threshold }}%.
|
||||
Your server ({{ $name }}) has high disk usage ({{ $disk_usage }}% used). Threshold is {{ $threshold }}%.
|
||||
|
||||
Please cleanup your disk to prevent data-loss. Here are some [tips](https://coolify.io/docs/knowledge-base/server/automated-cleanup).
|
||||
Please cleanup your disk to prevent data-loss. Here are some [tips](https://coolify.io/docs/knowledge-base/server/automated-cleanup).
|
||||
|
||||
(You can change the threshold in the Server Settings menu.)
|
||||
</x-emails.layout>
|
||||
(You can change the threshold in the Server Settings menu.)
|
||||
</x-emails.layout>
|
@ -1,5 +1,5 @@
|
||||
<x-emails.layout>
|
||||
Coolify cannot connect to your server ({{ $name }}). Please check your server and make sure it is running.
|
||||
Last Hour Cloud cannot connect to your server ({{ $name }}). Please check your server and make sure it is running.
|
||||
|
||||
All automations & integrations are turned off!
|
||||
|
||||
|
@ -8,22 +8,22 @@
|
||||
@use('App\Models\InstanceSettings')
|
||||
@php
|
||||
|
||||
$instanceSettings = \App\Models\InstanceSettings::get();
|
||||
$name = null;
|
||||
$instanceSettings = \App\Models\InstanceSettings::get();
|
||||
$name = null;
|
||||
|
||||
if ($instanceSettings) {
|
||||
$displayName = $instanceSettings->getTitleDisplayName();
|
||||
if ($instanceSettings) {
|
||||
$displayName = $instanceSettings->getTitleDisplayName();
|
||||
|
||||
if (strlen($displayName) > 0) {
|
||||
$name = $displayName . ' ';
|
||||
}
|
||||
}
|
||||
if (strlen($displayName) > 0) {
|
||||
$name = $displayName . ' ';
|
||||
}
|
||||
}
|
||||
@endphp
|
||||
<title>{{ $name }}{{ $title ?? 'Coolify' }}</title>
|
||||
<title>{{ $name }}{{ $title ?? 'Last Hour Cloud' }}</title>
|
||||
@env('local')
|
||||
<link rel="icon" href="{{ asset('favicon-dev.png') }}" type="image/x-icon" />
|
||||
@else
|
||||
<link rel="icon" href="{{ asset('coolify-transparent.png') }}" type="image/x-icon" />
|
||||
@else
|
||||
<link rel="icon" href="{{ asset('lasthour-transparent.png') }}" type="image/x-icon" />
|
||||
@endenv
|
||||
<meta name="csrf-token" content="{{ csrf_token() }}">
|
||||
@vite(['resources/js/app.js', 'resources/css/app.css'])
|
||||
@ -33,193 +33,242 @@
|
||||
}
|
||||
</style>
|
||||
@if (config('app.name') == 'Coolify Cloud')
|
||||
<script defer data-domain="app.coolify.io" src="https://analytics.coollabs.io/js/plausible.js"></script>
|
||||
<script defer data-domain="app.coolify.io" src="https://analytics.coollabs.io/js/plausible.js"></script>
|
||||
@endif
|
||||
@auth
|
||||
<script type="text/javascript" src="{{ URL::asset('js/echo.js') }}"></script>
|
||||
<script type="text/javascript" src="{{ URL::asset('js/pusher.js') }}"></script>
|
||||
<script type="text/javascript" src="{{ URL::asset('js/apexcharts.js') }}"></script>
|
||||
<script type="text/javascript" src="{{ URL::asset('js/echo.js') }}"></script>
|
||||
<script type="text/javascript" src="{{ URL::asset('js/pusher.js') }}"></script>
|
||||
<script type="text/javascript" src="{{ URL::asset('js/apexcharts.js') }}"></script>
|
||||
@endauth
|
||||
</head>
|
||||
@section('body')
|
||||
|
||||
<body>
|
||||
<x-toast />
|
||||
<script data-navigate-once>
|
||||
if (!('theme' in localStorage)) {
|
||||
localStorage.theme = 'dark';
|
||||
<body>
|
||||
<x-toast />
|
||||
<script data-navigate-once>
|
||||
if (!('theme' in localStorage)) {
|
||||
localStorage.theme = 'dark';
|
||||
document.documentElement.classList.add('dark')
|
||||
} else if (localStorage.theme === 'dark') {
|
||||
document.documentElement.classList.add('dark')
|
||||
} else if (localStorage.theme === 'light') {
|
||||
document.documentElement.classList.remove('dark')
|
||||
} else {
|
||||
if (window.matchMedia('(prefers-color-scheme: dark)').matches) {
|
||||
document.documentElement.classList.add('dark')
|
||||
} else if (localStorage.theme === 'dark') {
|
||||
document.documentElement.classList.add('dark')
|
||||
} else if (localStorage.theme === 'light') {
|
||||
document.documentElement.classList.remove('dark')
|
||||
} else {
|
||||
if (window.matchMedia('(prefers-color-scheme: dark)').matches) {
|
||||
document.documentElement.classList.add('dark')
|
||||
document.documentElement.classList.remove('dark')
|
||||
}
|
||||
}
|
||||
let theme = localStorage.theme
|
||||
let baseColor = '#FCD452'
|
||||
let textColor = '#ffffff'
|
||||
let editorBackground = '#181818'
|
||||
let editorTheme = 'blackboard'
|
||||
|
||||
function checkTheme() {
|
||||
theme = localStorage.theme
|
||||
if (theme == 'dark') {
|
||||
baseColor = '#FCD452'
|
||||
textColor = '#ffffff'
|
||||
editorBackground = '#181818'
|
||||
editorTheme = 'blackboard'
|
||||
} else {
|
||||
baseColor = 'black'
|
||||
textColor = '#000000'
|
||||
editorBackground = '#ffffff'
|
||||
editorTheme = null
|
||||
}
|
||||
}
|
||||
@auth
|
||||
window.Pusher = Pusher;
|
||||
window.Echo = new Echo({
|
||||
broadcaster: 'pusher',
|
||||
cluster: "{{ env('PUSHER_HOST') }}" || window.location.hostname,
|
||||
key: "{{ env('PUSHER_APP_KEY') }}" || 'coolify',
|
||||
wsHost: "{{ env('PUSHER_HOST') }}" || window.location.hostname,
|
||||
wsPort: "{{ getRealtime() }}",
|
||||
wssPort: "{{ getRealtime() }}",
|
||||
forceTLS: false,
|
||||
encrypted: true,
|
||||
enableStats: false,
|
||||
enableLogging: true,
|
||||
enabledTransports: ['ws', 'wss'],
|
||||
});
|
||||
@endauth
|
||||
let checkHealthInterval = null;
|
||||
let checkIfIamDeadInterval = null;
|
||||
|
||||
function changePasswordFieldType(event) {
|
||||
let element = event.target
|
||||
for (let i = 0; i < 10; i++) {
|
||||
if (element.className === "relative") {
|
||||
break;
|
||||
}
|
||||
element = element.parentElement;
|
||||
}
|
||||
element = element.children[1];
|
||||
if (element.nodeName === 'INPUT' || element.nodeName === 'TEXTAREA') {
|
||||
if (element.type === 'password') {
|
||||
element.type = 'text';
|
||||
if (element.disabled) return;
|
||||
element.classList.add('truncate');
|
||||
this.type = 'text';
|
||||
} else {
|
||||
document.documentElement.classList.remove('dark')
|
||||
element.type = 'password';
|
||||
if (element.disabled) return;
|
||||
element.classList.remove('truncate');
|
||||
this.type = 'password';
|
||||
}
|
||||
}
|
||||
let theme = localStorage.theme
|
||||
let baseColor = '#FCD452'
|
||||
let textColor = '#ffffff'
|
||||
let editorBackground = '#181818'
|
||||
let editorTheme = 'blackboard'
|
||||
}
|
||||
|
||||
function checkTheme() {
|
||||
theme = localStorage.theme
|
||||
if (theme == 'dark') {
|
||||
baseColor = '#FCD452'
|
||||
textColor = '#ffffff'
|
||||
editorBackground = '#181818'
|
||||
editorTheme = 'blackboard'
|
||||
} else {
|
||||
baseColor = 'black'
|
||||
textColor = '#000000'
|
||||
editorBackground = '#ffffff'
|
||||
editorTheme = null
|
||||
}
|
||||
}
|
||||
@auth
|
||||
window.Pusher = Pusher;
|
||||
window.Echo = new Echo({
|
||||
broadcaster: 'pusher',
|
||||
cluster: "{{ env('PUSHER_HOST') }}" || window.location.hostname,
|
||||
key: "{{ env('PUSHER_APP_KEY') }}" || 'coolify',
|
||||
wsHost: "{{ env('PUSHER_HOST') }}" || window.location.hostname,
|
||||
wsPort: "{{ getRealtime() }}",
|
||||
wssPort: "{{ getRealtime() }}",
|
||||
forceTLS: false,
|
||||
encrypted: true,
|
||||
enableStats: false,
|
||||
enableLogging: true,
|
||||
enabledTransports: ['ws', 'wss'],
|
||||
});
|
||||
@endauth
|
||||
let checkHealthInterval = null;
|
||||
let checkIfIamDeadInterval = null;
|
||||
|
||||
function changePasswordFieldType(event) {
|
||||
let element = event.target
|
||||
for (let i = 0; i < 10; i++) {
|
||||
if (element.className === "relative") {
|
||||
break;
|
||||
}
|
||||
element = element.parentElement;
|
||||
}
|
||||
element = element.children[1];
|
||||
if (element.nodeName === 'INPUT' || element.nodeName === 'TEXTAREA') {
|
||||
if (element.type === 'password') {
|
||||
element.type = 'text';
|
||||
if (element.disabled) return;
|
||||
element.classList.add('truncate');
|
||||
this.type = 'text';
|
||||
} else {
|
||||
element.type = 'password';
|
||||
if (element.disabled) return;
|
||||
element.classList.remove('truncate');
|
||||
this.type = 'password';
|
||||
}
|
||||
}
|
||||
<<
|
||||
<< << < HEAD
|
||||
===
|
||||
=== =
|
||||
function revive() {
|
||||
if (checkHealthInterval) return true;
|
||||
console.log('Checking server\'s health...')
|
||||
checkHealthInterval = setInterval(() => {
|
||||
fetch('/api/health')
|
||||
.then(response => {
|
||||
if (response.ok) {
|
||||
window.toast('Last Hour Cloud is back online. Reloading...', {
|
||||
type: 'success',
|
||||
})
|
||||
if (checkHealthInterval) clearInterval(checkHealthInterval);
|
||||
setTimeout(() => {
|
||||
window.location.reload();
|
||||
}, 5000)
|
||||
} else {
|
||||
console.log('Waiting for server to come back from dead...');
|
||||
}
|
||||
})
|
||||
}, 2000);
|
||||
}
|
||||
|
||||
function copyToClipboard(text) {
|
||||
navigator?.clipboard?.writeText(text) && window.Livewire.dispatch('success', 'Copied to clipboard.');
|
||||
}
|
||||
document.addEventListener('livewire:init', () => {
|
||||
window.Livewire.on('reloadWindow', (timeout) => {
|
||||
if (timeout) {
|
||||
setTimeout(() => {
|
||||
window.location.reload();
|
||||
}, timeout);
|
||||
return;
|
||||
} else {
|
||||
function upgrade() {
|
||||
if (checkIfIamDeadInterval) return true;
|
||||
console.log('Update initiated.')
|
||||
checkIfIamDeadInterval = setInterval(() => {
|
||||
fetch('/api/health')
|
||||
.then(response => {
|
||||
if (response.ok) {
|
||||
console.log('It\'s alive. Waiting for server to be dead...');
|
||||
} else {
|
||||
window.toast('Update done, restarting Last Hour Cloud!', {
|
||||
type: 'success',
|
||||
})
|
||||
console.log('It\'s dead. Reviving... Standby... Bzz... Bzz...')
|
||||
if (checkIfIamDeadInterval) clearInterval(checkIfIamDeadInterval);
|
||||
revive();
|
||||
}
|
||||
})
|
||||
}, 2000);
|
||||
}
|
||||
|
||||
>>>
|
||||
>>> > 35700 ec24(main: begin major rewrite
|
||||
for lasthour)
|
||||
|
||||
function copyToClipboard(text) {
|
||||
navigator?.clipboard?.writeText(text) && window.Livewire.dispatch('success', 'Copied to clipboard.');
|
||||
}
|
||||
document.addEventListener('livewire:init', () => {
|
||||
window.Livewire.on('reloadWindow', (timeout) => {
|
||||
if (timeout) {
|
||||
setTimeout(() => {
|
||||
window.location.reload();
|
||||
}
|
||||
})
|
||||
window.Livewire.on('info', (message) => {
|
||||
if (typeof message === 'string') {
|
||||
window.toast('Info', {
|
||||
type: 'info',
|
||||
description: message,
|
||||
})
|
||||
return;
|
||||
}
|
||||
if (message.length == 1) {
|
||||
window.toast('Info', {
|
||||
type: 'info',
|
||||
description: message[0],
|
||||
})
|
||||
} else if (message.length == 2) {
|
||||
window.toast(message[0], {
|
||||
type: 'info',
|
||||
description: message[1],
|
||||
})
|
||||
}
|
||||
})
|
||||
window.Livewire.on('error', (message) => {
|
||||
if (typeof message === 'string') {
|
||||
window.toast('Error', {
|
||||
type: 'danger',
|
||||
description: message,
|
||||
})
|
||||
return;
|
||||
}
|
||||
if (message.length == 1) {
|
||||
window.toast('Error', {
|
||||
type: 'danger',
|
||||
description: message[0],
|
||||
})
|
||||
} else if (message.length == 2) {
|
||||
window.toast(message[0], {
|
||||
type: 'danger',
|
||||
description: message[1],
|
||||
})
|
||||
}
|
||||
})
|
||||
window.Livewire.on('warning', (message) => {
|
||||
if (typeof message === 'string') {
|
||||
window.toast('Warning', {
|
||||
type: 'warning',
|
||||
description: message,
|
||||
})
|
||||
return;
|
||||
}
|
||||
if (message.length == 1) {
|
||||
window.toast('Warning', {
|
||||
type: 'warning',
|
||||
description: message[0],
|
||||
})
|
||||
} else if (message.length == 2) {
|
||||
window.toast(message[0], {
|
||||
type: 'warning',
|
||||
description: message[1],
|
||||
})
|
||||
}
|
||||
})
|
||||
window.Livewire.on('success', (message) => {
|
||||
if (typeof message === 'string') {
|
||||
window.toast('Success', {
|
||||
type: 'success',
|
||||
description: message,
|
||||
})
|
||||
return;
|
||||
}
|
||||
if (message.length == 1) {
|
||||
window.toast('Success', {
|
||||
type: 'success',
|
||||
description: message[0],
|
||||
})
|
||||
} else if (message.length == 2) {
|
||||
window.toast(message[0], {
|
||||
type: 'success',
|
||||
description: message[1],
|
||||
})
|
||||
}
|
||||
})
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
}, timeout);
|
||||
return;
|
||||
} else {
|
||||
window.location.reload();
|
||||
}
|
||||
})
|
||||
window.Livewire.on('info', (message) => {
|
||||
if (typeof message === 'string') {
|
||||
window.toast('Info', {
|
||||
type: 'info',
|
||||
description: message,
|
||||
})
|
||||
return;
|
||||
}
|
||||
if (message.length == 1) {
|
||||
window.toast('Info', {
|
||||
type: 'info',
|
||||
description: message[0],
|
||||
})
|
||||
} else if (message.length == 2) {
|
||||
window.toast(message[0], {
|
||||
type: 'info',
|
||||
description: message[1],
|
||||
})
|
||||
}
|
||||
})
|
||||
window.Livewire.on('error', (message) => {
|
||||
if (typeof message === 'string') {
|
||||
window.toast('Error', {
|
||||
type: 'danger',
|
||||
description: message,
|
||||
})
|
||||
return;
|
||||
}
|
||||
if (message.length == 1) {
|
||||
window.toast('Error', {
|
||||
type: 'danger',
|
||||
description: message[0],
|
||||
})
|
||||
} else if (message.length == 2) {
|
||||
window.toast(message[0], {
|
||||
type: 'danger',
|
||||
description: message[1],
|
||||
})
|
||||
}
|
||||
})
|
||||
window.Livewire.on('warning', (message) => {
|
||||
if (typeof message === 'string') {
|
||||
window.toast('Warning', {
|
||||
type: 'warning',
|
||||
description: message,
|
||||
})
|
||||
return;
|
||||
}
|
||||
if (message.length == 1) {
|
||||
window.toast('Warning', {
|
||||
type: 'warning',
|
||||
description: message[0],
|
||||
})
|
||||
} else if (message.length == 2) {
|
||||
window.toast(message[0], {
|
||||
type: 'warning',
|
||||
description: message[1],
|
||||
})
|
||||
}
|
||||
})
|
||||
window.Livewire.on('success', (message) => {
|
||||
if (typeof message === 'string') {
|
||||
window.toast('Success', {
|
||||
type: 'success',
|
||||
description: message,
|
||||
})
|
||||
return;
|
||||
}
|
||||
if (message.length == 1) {
|
||||
window.toast('Success', {
|
||||
type: 'success',
|
||||
description: message[0],
|
||||
})
|
||||
} else if (message.length == 2) {
|
||||
window.toast(message[0], {
|
||||
type: 'success',
|
||||
description: message[1],
|
||||
})
|
||||
}
|
||||
})
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
@show
|
||||
|
||||
</html>
|
||||
</html>
|
@ -1,6 +1,6 @@
|
||||
@php use App\Enums\ProxyTypes; @endphp
|
||||
<x-slot:title>
|
||||
Onboarding | Coolify
|
||||
Onboarding | Last Hour Cloud
|
||||
</x-slot>
|
||||
<section class="flex flex-col h-full lg:items-center lg:justify-center">
|
||||
<div class="flex flex-col items-center justify-center p-10 mx-2 mt-10 bg-white border rounded-lg shadow lg:p-20 dark:bg-transparent dark:border-none max-w-7xl ">
|
||||
@ -13,17 +13,19 @@
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
<div>
|
||||
@if ($currentState === 'explanation')
|
||||
<x-boarding-step title="What is this?">
|
||||
<x-slot:question>
|
||||
Last Hour Cloud is an all-in-one application to automate tasks on your servers, deploy application with Git
|
||||
Last Hour Cloud is an all-in-one application to automate tasks on your servers, deploy applications with Git
|
||||
integrations, deploy databases and services, monitor these resources with notifications and alerts
|
||||
without vendor lock-in
|
||||
and <a href="https://lasthourhosting.org/cloud.html" class="text-white hover:underline">much much more</a>.
|
||||
<br><br>
|
||||
<span class="text-xl">
|
||||
<x-highlighted text="Self-hosting for the last hour." /></span>
|
||||
<x-highlighted text="Self-hosting for the Last Hour Cloud." /></span>
|
||||
</x-slot:question>
|
||||
<x-slot:explanation>
|
||||
<p><x-highlighted text="Task automation:" /> You do not to manage your servers too much. This does
|
||||
@ -220,6 +222,206 @@
|
||||
</x-boarding-step>
|
||||
@endif
|
||||
</div>
|
||||
<div>
|
||||
@if ($currentState === 'validate-server')
|
||||
<x-boarding-step title="Validate & Configure Server">
|
||||
<x-slot:question>
|
||||
we need to validate your server (connection, Docker Engine, etc) and configure to see if something is
|
||||
missing. Are you okay with this?
|
||||
</x-slot:question>
|
||||
<x-slot:actions>
|
||||
<x-slide-over closeWithX fullScreen>
|
||||
<x-slot:title>Validate & configure</x-slot:title>
|
||||
<x-slot:content>
|
||||
<livewire:server.validate-and-install :server="$this->createdServer" />
|
||||
</x-slot:content>
|
||||
<x-forms.button @click="slideOverOpen=true" class="font-bold box w-96" wire:click.prevent='installServer' isHighlighted>
|
||||
Send it!
|
||||
</x-forms.button>
|
||||
</x-slot:actions>
|
||||
</x-boarding-step>
|
||||
@endif
|
||||
@if ($currentState === 'select-server-type')
|
||||
<x-boarding-step title="Server">
|
||||
<x-slot:question>
|
||||
Do you want to deploy your resources on your <x-highlighted text="Localhost" />
|
||||
or on a <x-highlighted text="Remote Server" />?
|
||||
</x-slot:question>
|
||||
<x-slot:actions>
|
||||
<x-forms.button class="justify-center w-64 box" wire:target="setServerType('localhost')" wire:click="setServerType('localhost')">Localhost
|
||||
</x-forms.button>
|
||||
|
||||
<x-forms.button class="justify-center w-64 box " wire:target="setServerType('remote')" wire:click="setServerType('remote')">Remote Server
|
||||
</x-forms.button>
|
||||
@if (!$serverReachable)
|
||||
Localhost is not reachable with the following public key.
|
||||
<br /> <br />
|
||||
Please make sure you have the correct public key in your ~/.ssh/authorized_keys file for user
|
||||
'root' or skip the guided tour and add a new private key manually to Last Hour Cloud and to the
|
||||
server.
|
||||
<br />
|
||||
Check the upstream <a target="_blank" class="underline" href="https://coolify.io/docs/server/openssh">documentation</a> for further help.
|
||||
<x-forms.input readonly id="serverPublicKey"></x-forms.input>
|
||||
<x-forms.button class="w-64 box" wire:target="setServerType('localhost')" wire:click="setServerType('localhost')">Check again
|
||||
</x-forms.button>
|
||||
@endif
|
||||
</x-slot:actions>
|
||||
<x-slot:explanation>
|
||||
<p>Servers are the main building blocks, as they will host your applications, databases,
|
||||
services, called resources. Any CPU intensive process will use the server's CPU where you
|
||||
are deploying your resources.</p>
|
||||
<p>Localhost is the server where Last Hour Cloud is running on. It is not recommended to use one server
|
||||
for everything.</p>
|
||||
<p>Remote Server is a server reachable through SSH. It can be hosted at home, or from any cloud
|
||||
provider.</p>
|
||||
</x-slot:explanation>
|
||||
</x-boarding-step>
|
||||
@endif
|
||||
</div>
|
||||
<div>
|
||||
@if ($currentState === 'private-key')
|
||||
<x-boarding-step title="SSH Key">
|
||||
<x-slot:question>
|
||||
Do you have your own SSH Private Key?
|
||||
</x-slot:question>
|
||||
<x-slot:actions>
|
||||
<x-forms.button class="justify-center w-64 box" wire:target="setPrivateKey('own')" wire:click="setPrivateKey('own')">Yes
|
||||
</x-forms.button>
|
||||
<x-forms.button class="justify-center w-64 box" wire:target="setPrivateKey('create')" wire:click="setPrivateKey('create')">No (create one for me)
|
||||
</x-forms.button>
|
||||
@if (count($privateKeys) > 0)
|
||||
<form wire:submit='selectExistingPrivateKey' class="flex flex-col w-full gap-4 pr-10">
|
||||
<x-forms.select label="Existing SSH Keys" id='selectedExistingPrivateKey'>
|
||||
@foreach ($privateKeys as $privateKey)
|
||||
<option wire:key="{{ $loop->index }}" value="{{ $privateKey->id }}">
|
||||
{{ $privateKey->name }}
|
||||
</option>
|
||||
@endforeach
|
||||
</x-forms.select>
|
||||
<x-forms.button type="submit">Use this SSH Key</x-forms.button>
|
||||
</form>
|
||||
@endif
|
||||
</x-slot:actions>
|
||||
<x-slot:explanation>
|
||||
<p>SSH Keys are used to connect to a remote server through a secure shell, called SSH.</p>
|
||||
<p>You can use your own ssh private key, or you can allow Last Hour Cloud to create one for you.</p>
|
||||
<p>In both ways, you need to add the public version of your ssh private key to the remote
|
||||
server's
|
||||
<code class="text-warning">~/.ssh/authorized_keys</code> file.
|
||||
</p>
|
||||
</x-slot:explanation>
|
||||
</x-boarding-step>
|
||||
@endif
|
||||
</div>
|
||||
<div>
|
||||
@if ($currentState === 'select-existing-server')
|
||||
<x-boarding-step title="Select a server">
|
||||
<x-slot:question>
|
||||
There are already servers available for your Team. Do you want to use one of them?
|
||||
</x-slot:question>
|
||||
<x-slot:actions>
|
||||
<div class="flex flex-col gap-4">
|
||||
<div>
|
||||
<x-forms.button class="justify-center w-64 box" wire:click="createNewServer">No (create one
|
||||
for
|
||||
me)
|
||||
</x-forms.button>
|
||||
</div>
|
||||
<div>
|
||||
<form wire:submit='selectExistingServer' class="flex flex-col w-full gap-4 lg:w-96">
|
||||
<x-forms.select label="Existing servers" class="w-96" id='selectedExistingServer'>
|
||||
@foreach ($servers as $server)
|
||||
<option wire:key="{{ $loop->index }}" value="{{ $server->id }}">
|
||||
{{ $server->name }}
|
||||
</option>
|
||||
@endforeach
|
||||
</x-forms.select>
|
||||
<x-forms.button type="submit">Use this Server</x-forms.button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
@if (!$serverReachable)
|
||||
This server is not reachable with the following public key.
|
||||
<br /> <br />
|
||||
Please make sure you have the correct public key in your ~/.ssh/authorized_keys file for user
|
||||
'root' or skip the boarding process and add a new private key manually to Last Hour Cloud and to the
|
||||
server.
|
||||
<x-forms.input readonly id="serverPublicKey"></x-forms.input>
|
||||
<x-forms.button class="w-64 box" wire:target="validateServer" wire:click="validateServer">Check
|
||||
again
|
||||
</x-forms.button>
|
||||
@endif
|
||||
</x-slot:actions>
|
||||
<x-slot:explanation>
|
||||
<p>Private Keys are used to connect to a remote server through a secure shell, called SSH.</p>
|
||||
<p>You can use your own private key, or you can let Last Hour Cloud create one for you.</p>
|
||||
<p>In both ways, you need to add the public version of your private key to the remote server's
|
||||
<code>~/.ssh/authorized_keys</code> file.
|
||||
</p>
|
||||
</x-slot:explanation>
|
||||
</x-boarding-step>
|
||||
@endif
|
||||
</div>
|
||||
<div>
|
||||
@if ($currentState === 'create-private-key')
|
||||
<x-boarding-step title="Create Private Key">
|
||||
<x-slot:question>
|
||||
Please let me know your key details.
|
||||
</x-slot:question>
|
||||
<x-slot:actions>
|
||||
<form wire:submit='savePrivateKey' class="flex flex-col w-full gap-4 pr-10">
|
||||
<x-forms.input required placeholder="Choose a name for your Private Key. Could be anything." label="Name" id="privateKeyName" />
|
||||
<x-forms.input placeholder="Description, so others will know more about this." label="Description" id="privateKeyDescription" />
|
||||
<x-forms.textarea required placeholder="-----BEGIN OPENSSH PRIVATE KEY-----" label="Private Key" id="privateKey" />
|
||||
@if ($privateKeyType === 'create')
|
||||
<x-forms.textarea rows="7" readonly label="Public Key" id="publicKey" />
|
||||
<span class="font-bold text-warning">ACTION REQUIRED: Copy the 'Public Key' to your server's
|
||||
~/.ssh/authorized_keys
|
||||
file.</span>
|
||||
@endif
|
||||
<x-forms.button type="submit">Save</x-forms.button>
|
||||
</form>
|
||||
</x-slot:actions>
|
||||
<x-slot:explanation>
|
||||
<p>Private Keys are used to connect to a remote server through a secure shell, called SSH.</p>
|
||||
<p>You can use your own private key, or you can let Last Hour Cloud create one for you.</p>
|
||||
<p>In both ways, you need to add the public version of your private key to the remote server's
|
||||
<code>~/.ssh/authorized_keys</code> file.
|
||||
</p>
|
||||
</x-slot:explanation>
|
||||
</x-boarding-step>
|
||||
@endif
|
||||
</div>
|
||||
<div>
|
||||
@if ($currentState === 'create-server')
|
||||
<x-boarding-step title="Create a Server">
|
||||
<x-slot:question>
|
||||
Please let us know your server details.
|
||||
</x-slot:question>
|
||||
<x-slot:actions>
|
||||
<form wire:submit='saveServer' class="flex flex-col w-full gap-4 pr-10">
|
||||
<div class="flex gap-2">
|
||||
<x-forms.input required placeholder="Choose a name for your Server. It could be anything." label="Name" id="remoteServerName" />
|
||||
<x-forms.input placeholder="Description, so others will know more about it." label="Description" id="remoteServerDescription" />
|
||||
</div>
|
||||
<div class="flex gap-2">
|
||||
<x-forms.input required placeholder="127.0.0.1" label="IP Address" id="remoteServerHost" />
|
||||
<x-forms.input required placeholder="Port number of your server. Default is 22." label="Port" id="remoteServerPort" />
|
||||
<x-forms.input required readonly placeholder="Username to connect to your server. Default is root." label="Username" id="remoteServerUser" />
|
||||
</div>
|
||||
<div class="w-64">
|
||||
<x-forms.checkbox helper="If you are using Cloudflare Tunnels, enable this. It will proxy all ssh requests to your server through Cloudflare.<br><span class='text-warning'>Last Hour Cloud does not install/setup Cloudflare (cloudflared) on your server.</span>" id="isCloudflareTunnel" label="Cloudflare Tunnel" />
|
||||
</div>
|
||||
<x-forms.button type="submit">Continue</x-forms.button>
|
||||
</form>
|
||||
</x-slot:actions>
|
||||
<x-slot:explanation>
|
||||
<p>Username should be <x-highlighted text="root" /> for now. We are working on using
|
||||
non-root users.</p>
|
||||
</x-slot:explanation>
|
||||
</x-boarding-step>
|
||||
@endif
|
||||
</div>
|
||||
<div>
|
||||
@if ($currentState === 'validate-server')
|
||||
<x-boarding-step title="Validate & Configure Server">
|
||||
|
@ -1,51 +1,47 @@
|
||||
<div>
|
||||
<x-slot:title>
|
||||
Dashboard | Coolify
|
||||
</x-slot>
|
||||
@if (session('error'))
|
||||
Dashboard | Last Hour Cloud
|
||||
</x-slot>
|
||||
@if (session('error'))
|
||||
<span x-data x-init="$wire.emit('error', '{{ session('error') }}')" />
|
||||
@endif
|
||||
<h1>Dashboard</h1>
|
||||
<div class="subtitle">Your self-hosted infrastructure.</div>
|
||||
@if (request()->query->get('success'))
|
||||
@endif
|
||||
<h1>Dashboard</h1>
|
||||
<div class="subtitle">Your self-hosted infrastructure.</div>
|
||||
@if (request()->query->get('success'))
|
||||
<div class="items-center justify-center mb-10 font-bold rounded alert alert-success">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="w-6 h-6 stroke-current shrink-0" fill="none"
|
||||
viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||
d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" />
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="w-6 h-6 stroke-current shrink-0" fill="none" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" />
|
||||
</svg>
|
||||
Your subscription has been activated! Welcome onboard! <br>It could take a few seconds before your
|
||||
subscription is activated.<br> Please be patient.
|
||||
</div>
|
||||
@endif
|
||||
<h3 class="pb-4">Projects</h3>
|
||||
@if ($projects->count() > 0)
|
||||
@endif
|
||||
<h3 class="pb-4">Projects</h3>
|
||||
@if ($projects->count() > 0)
|
||||
<div class="grid grid-cols-1 gap-2 xl:grid-cols-2">
|
||||
@foreach ($projects as $project)
|
||||
<div class="gap-2 border border-transparent cursor-pointer box group"
|
||||
onclick="gotoProject('{{ $project->uuid }}','{{ $project->default_environment() }}')">
|
||||
<div class="flex flex-1 mx-6">
|
||||
<div class="flex flex-col justify-center flex-1">
|
||||
<div class="box-title">{{ $project->name }}</div>
|
||||
<div class="box-description">
|
||||
{{ $project->description }}</div>
|
||||
</div>
|
||||
<div class="flex items-center justify-center gap-2 text-xs font-bold ">
|
||||
<a class="hover:underline"
|
||||
href="{{ route('project.resource.create', ['project_uuid' => data_get($project, 'uuid'), 'environment_name' => data_get($project, 'environments.0.name', 'production')]) }}">
|
||||
<span class="p-2 font-bold">+
|
||||
Add Resource</span>
|
||||
</a>
|
||||
<a class="hover:underline"
|
||||
href="{{ route('project.edit', ['project_uuid' => data_get($project, 'uuid')]) }}">
|
||||
Settings
|
||||
</a>
|
||||
<div class="gap-2 border border-transparent cursor-pointer box group" onclick="gotoProject('{{ $project->uuid }}','{{ $project->default_environment() }}')">
|
||||
<div class="flex flex-1 mx-6">
|
||||
<div class="flex flex-col justify-center flex-1">
|
||||
<div class="box-title">{{ $project->name }}</div>
|
||||
<div class="box-description">
|
||||
{{ $project->description }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center justify-center gap-2 text-xs font-bold ">
|
||||
<a class="hover:underline" href="{{ route('project.resource.create', ['project_uuid' => data_get($project, 'uuid'), 'environment_name' => data_get($project, 'environments.0.name', 'production')]) }}">
|
||||
<span class="p-2 font-bold">+
|
||||
Add Resource</span>
|
||||
</a>
|
||||
<a class="hover:underline" href="{{ route('project.edit', ['project_uuid' => data_get($project, 'uuid')]) }}">
|
||||
Settings
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
@else
|
||||
@else
|
||||
<div class="flex flex-col gap-1">
|
||||
<div class='font-bold dark:text-warning'>No projects found.</div>
|
||||
<div class="flex items-center gap-1">
|
||||
@ -55,72 +51,69 @@
|
||||
go to the <a class="underline dark:text-white" href="{{ route('onboarding') }}">onboarding</a> page.
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
@endif
|
||||
|
||||
<h3 class="py-4">Servers</h3>
|
||||
@if ($servers->count() > 0)
|
||||
<h3 class="py-4">Servers</h3>
|
||||
@if ($servers->count() > 0)
|
||||
<div class="grid grid-cols-1 gap-2 xl:grid-cols-2">
|
||||
@foreach ($servers as $server)
|
||||
<a href="{{ route('server.show', ['server_uuid' => data_get($server, 'uuid')]) }}"
|
||||
@class([
|
||||
'gap-2 border cursor-pointer box group',
|
||||
'border-transparent' => $server->settings->is_reachable,
|
||||
'border-red-500' => !$server->settings->is_reachable,
|
||||
])>
|
||||
<div class="flex flex-col justify-center mx-6">
|
||||
<div class="box-title">
|
||||
{{ $server->name }}
|
||||
</div>
|
||||
<div class="box-description">
|
||||
{{ $server->description }}</div>
|
||||
<div class="flex gap-1 text-xs text-error">
|
||||
@if (!$server->settings->is_reachable)
|
||||
Not reachable
|
||||
@endif
|
||||
@if (!$server->settings->is_reachable && !$server->settings->is_usable)
|
||||
&
|
||||
@endif
|
||||
@if (!$server->settings->is_usable)
|
||||
Not usable by Coolify
|
||||
@endif
|
||||
</div>
|
||||
<a href="{{ route('server.show', ['server_uuid' => data_get($server, 'uuid')]) }}" @class([ 'gap-2 border cursor-pointer box group' , 'border-transparent'=> $server->settings->is_reachable,
|
||||
'border-red-500' => !$server->settings->is_reachable,
|
||||
])>
|
||||
<div class="flex flex-col justify-center mx-6">
|
||||
<div class="box-title">
|
||||
{{ $server->name }}
|
||||
</div>
|
||||
<div class="flex-1"></div>
|
||||
</a>
|
||||
<div class="box-description">
|
||||
{{ $server->description }}
|
||||
</div>
|
||||
<div class="flex gap-1 text-xs text-error">
|
||||
@if (!$server->settings->is_reachable)
|
||||
Not reachable
|
||||
@endif
|
||||
@if (!$server->settings->is_reachable && !$server->settings->is_usable)
|
||||
&
|
||||
@endif
|
||||
@if (!$server->settings->is_usable)
|
||||
Not usable by Last Hour Cloud
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex-1"></div>
|
||||
</a>
|
||||
@endforeach
|
||||
</div>
|
||||
@else
|
||||
@if ($private_keys->count() === 0)
|
||||
<div class="flex flex-col gap-1">
|
||||
<div class='font-bold dark:text-warning'>No private keys found.</div>
|
||||
<div class="flex items-center gap-1">Before you can add your server, first <x-modal-input
|
||||
buttonTitle="add" title="New Private Key">
|
||||
<livewire:security.private-key.create from="server" />
|
||||
</x-modal-input> a private key
|
||||
or
|
||||
go to the <a class="underline dark:text-white" href="{{ route('onboarding') }}">onboarding</a>
|
||||
page.
|
||||
</div>
|
||||
</div>
|
||||
@else
|
||||
<div class="flex flex-col gap-1">
|
||||
<div class='font-bold dark:text-warning'>No servers found.</div>
|
||||
<div class="flex items-center gap-1">
|
||||
<x-modal-input buttonTitle="Add" title="New Server" :closeOutside="false">
|
||||
<livewire:server.create />
|
||||
</x-modal-input> your first server
|
||||
or
|
||||
go to the <a class="underline dark:text-white" href="{{ route('onboarding') }}">onboarding</a>
|
||||
page.
|
||||
</div>
|
||||
@if ($private_keys->count() === 0)
|
||||
<div class="flex flex-col gap-1">
|
||||
<div class='font-bold dark:text-warning'>No private keys found.</div>
|
||||
<div class="flex items-center gap-1">Before you can add your server, first <x-modal-input buttonTitle="add" title="New Private Key">
|
||||
<livewire:security.private-key.create from="server" />
|
||||
</x-modal-input> a private key
|
||||
or
|
||||
go to the <a class="underline dark:text-white" href="{{ route('onboarding') }}">onboarding</a>
|
||||
page.
|
||||
</div>
|
||||
</div>
|
||||
@else
|
||||
<div class="flex flex-col gap-1">
|
||||
<div class='font-bold dark:text-warning'>No servers found.</div>
|
||||
<div class="flex items-center gap-1">
|
||||
<x-modal-input buttonTitle="Add" title="New Server" :closeOutside="false">
|
||||
<livewire:server.create />
|
||||
</x-modal-input> your first server
|
||||
or
|
||||
go to the <a class="underline dark:text-white" href="{{ route('onboarding') }}">onboarding</a>
|
||||
page.
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
@endif
|
||||
@if ($servers->count() > 0 && $projects->count() > 0)
|
||||
@endif
|
||||
@if ($servers->count() > 0 && $projects->count() > 0)
|
||||
<div class="flex items-center gap-2">
|
||||
<h3 class="py-4">Deployments</h3>
|
||||
@if (count($deployments_per_server) > 0)
|
||||
<x-loading />
|
||||
<x-loading />
|
||||
@endif
|
||||
<x-modal-confirmation isErrorButton action="cleanup_queue" buttonTitle="Cleanup Queues">
|
||||
This will clean up the deployment queue. <br>Please think again.
|
||||
@ -128,44 +121,42 @@
|
||||
</div>
|
||||
<div wire:poll.3000ms="get_deployments" class="grid grid-cols-1">
|
||||
@forelse ($deployments_per_server as $server_name => $deployments)
|
||||
<h4 class="py-4">{{ $server_name }}</h4>
|
||||
<div class="grid grid-cols-1 gap-2 lg:grid-cols-3">
|
||||
@foreach ($deployments as $deployment)
|
||||
<a href="{{ data_get($deployment, 'deployment_url') }}" @class([
|
||||
'gap-2 cursor-pointer box group border-l-2 border-dotted',
|
||||
'dark:border-coolgray-300' => data_get($deployment, 'status') === 'queued',
|
||||
'border-yellow-500' => data_get($deployment, 'status') === 'in_progress',
|
||||
])>
|
||||
<div class="flex flex-col justify-center mx-6">
|
||||
<div class="box-title">
|
||||
{{ data_get($deployment, 'application_name') }}
|
||||
</div>
|
||||
@if (data_get($deployment, 'pull_request_id') !== 0)
|
||||
<div class="box-description">
|
||||
PR #{{ data_get($deployment, 'pull_request_id') }}
|
||||
</div>
|
||||
@endif
|
||||
<div class="box-description">
|
||||
{{ str(data_get($deployment, 'status'))->headline() }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex-1"></div>
|
||||
</a>
|
||||
@endforeach
|
||||
</div>
|
||||
<h4 class="py-4">{{ $server_name }}</h4>
|
||||
<div class="grid grid-cols-1 gap-2 lg:grid-cols-3">
|
||||
@foreach ($deployments as $deployment)
|
||||
<a href="{{ data_get($deployment, 'deployment_url') }}" @class([ 'gap-2 cursor-pointer box group border-l-2 border-dotted' , 'dark:border-coolgray-300'=> data_get($deployment, 'status') === 'queued',
|
||||
'border-yellow-500' => data_get($deployment, 'status') === 'in_progress',
|
||||
])>
|
||||
<div class="flex flex-col justify-center mx-6">
|
||||
<div class="box-title">
|
||||
{{ data_get($deployment, 'application_name') }}
|
||||
</div>
|
||||
@if (data_get($deployment, 'pull_request_id') !== 0)
|
||||
<div class="box-description">
|
||||
PR #{{ data_get($deployment, 'pull_request_id') }}
|
||||
</div>
|
||||
@endif
|
||||
<div class="box-description">
|
||||
{{ str(data_get($deployment, 'status'))->headline() }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex-1"></div>
|
||||
</a>
|
||||
@endforeach
|
||||
</div>
|
||||
@empty
|
||||
<div>No deployments running.</div>
|
||||
<div>No deployments running.</div>
|
||||
@endforelse
|
||||
</div>
|
||||
@endif
|
||||
@endif
|
||||
|
||||
<script>
|
||||
function gotoProject(uuid, environment) {
|
||||
if (!environment) {
|
||||
window.location.href = '/project/' + uuid;
|
||||
<script>
|
||||
function gotoProject(uuid, environment) {
|
||||
if (!environment) {
|
||||
window.location.href = '/project/' + uuid;
|
||||
}
|
||||
window.location.href = '/project/' + uuid + '/' + environment;
|
||||
}
|
||||
window.location.href = '/project/' + uuid + '/' + environment;
|
||||
}
|
||||
</script>
|
||||
{{-- <x-forms.button wire:click='getIptables'>Get IPTABLES</x-forms.button> --}}
|
||||
</div>
|
||||
</script>
|
||||
{{-- <x-forms.button wire:click='getIptables'>Get IPTABLES</x-forms.button> --}}
|
||||
</div>
|
@ -1,7 +1,7 @@
|
||||
<section class="bg-gray-50 dark:bg-base">
|
||||
<div class="flex flex-col items-center justify-center px-6 py-8 mx-auto md:h-screen lg:py-0">
|
||||
<a class="flex items-center mb-6 text-5xl font-extrabold tracking-tight text-gray-900 dark:text-white">
|
||||
Last Hour
|
||||
Last Hour Cloud
|
||||
</a>
|
||||
<div class="w-full bg-white shadow md:mt-0 sm:max-w-md xl:p-0 dark:bg-base ">
|
||||
<div class="p-6 space-y-4 md:space-y-6 sm:p-8">
|
||||
|
@ -1,10 +1,9 @@
|
||||
<div class="flex flex-col w-full gap-2">
|
||||
<div>Your feedback helps us to improve Coolify. Thank you! 💜</div>
|
||||
<div>Give us feedback or ask a question and our team will get back to you within 24 hours.</div>
|
||||
<form wire:submit="submit" class="flex flex-col gap-4 pt-4">
|
||||
<x-forms.input id="subject" label="Subject" placeholder="Summary of your problem."></x-forms.input>
|
||||
<x-forms.textarea rows="10" id="description" label="Description" class="font-sans" spellcheck
|
||||
placeholder="Please provide as much information as possible."></x-forms.textarea>
|
||||
<x-forms.textarea rows="10" id="description" label="Description" class="font-sans" spellcheck placeholder="Please provide as much information as possible."></x-forms.textarea>
|
||||
<div></div>
|
||||
<x-forms.button class="w-full mt-4" type="submit" @click="modalOpen=false">Send</x-forms.button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
@ -18,7 +18,7 @@
|
||||
if (checkNumber > 5) {
|
||||
this.popups.realtime = true;
|
||||
console.error(
|
||||
'Coolify could not connect to its real-time service. This will cause unusual problems on the UI if not fixed! Please check the related documentation (https://coolify.io/docs/knowledge-base/cloudflare/tunnels) or get help on Discord (https://coollabs.io/discord).)'
|
||||
'Last Hour Cloud could not connect to its real-time service. This will cause unusual problems on the UI if not fixed! Please check the related documentation (https://coolify.io/docs/knowledge-base/cloudflare/tunnels) or get help on Discord (https://coollabs.io/discord).)'
|
||||
);
|
||||
clearInterval(checkPusherInterval);
|
||||
}
|
||||
@ -28,50 +28,43 @@
|
||||
}
|
||||
}">
|
||||
@auth
|
||||
<span x-show="popups.realtime === true">
|
||||
@if (!isCloud())
|
||||
<x-popup>
|
||||
<x-slot:title>
|
||||
<span class="font-bold text-left text-red-500">WARNING: </span>Realtime Error?!
|
||||
</x-slot:title>
|
||||
<x-slot:description>
|
||||
<span>Coolify could not connect to its real-time service.<br>This will cause unusual problems on the
|
||||
UI
|
||||
if
|
||||
not fixed! <br><br>
|
||||
Please ensure that you have opened the
|
||||
<a class="underline" href='https://coolify.io/docs/knowledge-base/server/firewall'
|
||||
target='_blank'>required ports</a>,
|
||||
check the
|
||||
related <a class="underline" href='https://coolify.io/docs/knowledge-base/cloudflare/tunnels'
|
||||
target='_blank'>documentation</a> or get
|
||||
help on <a class="underline" href='https://coollabs.io/discord' target='_blank'>Discord</a>.
|
||||
</span>
|
||||
</x-slot:description>
|
||||
<x-slot:button-text @click="disableRealtime()">
|
||||
Acknowledge & Disable This Popup
|
||||
</x-slot:button-text>
|
||||
</x-popup>
|
||||
@endif
|
||||
</span>
|
||||
<span x-show="popups.realtime === true">
|
||||
@if (!isCloud())
|
||||
<x-popup>
|
||||
<x-slot:title>
|
||||
<span class="font-bold text-left text-red-500">WARNING: </span>Realtime Error?!
|
||||
</x-slot:title>
|
||||
<x-slot:description>
|
||||
<span>Last Hour Cloud could not connect to its real-time service.<br>This will cause unusual problems on the
|
||||
UI
|
||||
if
|
||||
not fixed! <br><br>
|
||||
Please ensure that you have opened the
|
||||
<a class="underline" href='https://coolify.io/docs/knowledge-base/server/firewall' target='_blank'>required ports</a>,
|
||||
check the
|
||||
related <a class="underline" href='https://coolify.io/docs/knowledge-base/cloudflare/tunnels' target='_blank'>documentation</a> or get
|
||||
help on <a class="underline" href='https://coollabs.io/discord' target='_blank'>Discord</a>.
|
||||
</span>
|
||||
</x-slot:description>
|
||||
<x-slot:button-text @click="disableRealtime()">
|
||||
Acknowledge & Disable This Popup
|
||||
</x-slot:button-text>
|
||||
</x-popup>
|
||||
@endif
|
||||
</span>
|
||||
@endauth
|
||||
<span x-show="popups.sponsorship">
|
||||
<x-popup>
|
||||
<x-slot:title>
|
||||
Love Coolify as we do?
|
||||
Like Last Hour Cloud?
|
||||
</x-slot:title>
|
||||
<x-slot:icon>
|
||||
<img src="https://cdn-icons-png.flaticon.com/512/8236/8236748.png"
|
||||
class="w-8 h-8 sm:w-12 sm:h-12 lg:w-16 lg:h-16">
|
||||
<img src="https://cdn-icons-png.flaticon.com/512/8236/8236748.png" class="w-8 h-8 sm:w-12 sm:h-12 lg:w-16 lg:h-16">
|
||||
</x-slot:icon>
|
||||
<x-slot:description>
|
||||
<span>Please
|
||||
consider donating on <a href="https://github.com/sponsors/coollabsio"
|
||||
class="text-xs underline dark:text-white">GitHub</a> or <a
|
||||
href="https://opencollective.com/coollabsio"
|
||||
class="text-xs underline dark:text-white">OpenCollective</a>.<br><br></span>
|
||||
<span>It enables us to keep creating features without paywalls, ensuring our work remains free and
|
||||
open.</span>
|
||||
consider sharing about us! <a href="https://githaven.org/Shiloh/lasthourcloud/" class="text-xs underline dark:text-white">GitHaven</a> or <a href="https://lasthourhosting.org" class="text-xs underline dark:text-white">Last Hour Hosting</a>.<br><br></span>
|
||||
<span>Your support enables us to keep creating services that support sharing the Gospel of Jesus Christ. 1 John 2:18</span>
|
||||
</x-slot:description>
|
||||
<x-slot:button-text @click="disableSponsorship()">
|
||||
Disable This Popup
|
||||
@ -79,41 +72,37 @@
|
||||
</x-popup>
|
||||
</span>
|
||||
@if (currentTeam()->serverOverflow())
|
||||
<x-banner :closable=false>
|
||||
<div><span class="font-bold text-red-500">WARNING:</span> The number of active servers exceeds the limit
|
||||
covered by your payment. If not resolved, some of your servers <span class="font-bold text-red-500">will
|
||||
be deactivated</span>. Visit <a href="{{ route('subscription.show') }}"
|
||||
class="underline dark:text-white">/subscription</a> to update your subscription or remove some
|
||||
servers.
|
||||
</div>
|
||||
</x-banner>
|
||||
<x-banner :closable=false>
|
||||
<div><span class="font-bold text-red-500">WARNING:</span> The number of active servers exceeds the limit
|
||||
covered by your payment. If not resolved, some of your servers <span class="font-bold text-red-500">will
|
||||
be deactivated</span>. Visit <a href="{{ route('subscription.show') }}" class="underline dark:text-white">/subscription</a> to update your subscription or remove some
|
||||
servers.
|
||||
</div>
|
||||
</x-banner>
|
||||
@endif
|
||||
@if (!currentTeam()->isAnyNotificationEnabled())
|
||||
<span x-show="popups.notification">
|
||||
<x-popup>
|
||||
<x-slot:title>
|
||||
No notifications enabled.
|
||||
</x-slot:title>
|
||||
<x-slot:icon>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="text-red-500 stroke-current w-14 h-14 shrink-0"
|
||||
fill="none" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||
d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z" />
|
||||
</svg>
|
||||
</x-slot:icon>
|
||||
<x-slot:description>
|
||||
It is
|
||||
highly recommended to enable at least
|
||||
one
|
||||
notification channel to receive important alerts.<br>Visit <a
|
||||
href="{{ route('notifications.email') }}" class="underline dark:text-white">/notification</a> to
|
||||
enable notifications.</span>
|
||||
</x-slot:description>
|
||||
<x-slot:button-text @click="disableNotification()">
|
||||
Accept and Close
|
||||
</x-slot:button-text>
|
||||
</x-popup>
|
||||
</span>
|
||||
<span x-show="popups.notification">
|
||||
<x-popup>
|
||||
<x-slot:title>
|
||||
No notifications enabled.
|
||||
</x-slot:title>
|
||||
<x-slot:icon>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="text-red-500 stroke-current w-14 h-14 shrink-0" fill="none" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z" />
|
||||
</svg>
|
||||
</x-slot:icon>
|
||||
<x-slot:description>
|
||||
It is
|
||||
highly recommended to enable at least
|
||||
one
|
||||
notification channel to receive important alerts.<br>Visit <a href="{{ route('notifications.email') }}" class="underline dark:text-white">/notification</a> to
|
||||
enable notifications.</span>
|
||||
</x-slot:description>
|
||||
<x-slot:button-text @click="disableNotification()">
|
||||
Accept and Close
|
||||
</x-slot:button-text>
|
||||
</x-popup>
|
||||
</span>
|
||||
@endif
|
||||
<script>
|
||||
function disableSponsorship() {
|
||||
@ -128,4 +117,4 @@
|
||||
localStorage.setItem('popupRealtime', 'disabled');
|
||||
}
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
@ -5,6 +5,14 @@
|
||||
<x-forms.button type="submit">
|
||||
Save
|
||||
</x-forms.button>
|
||||
<<<<<<< HEAD=======@if ($isConfigurationChanged && !is_null($application->config_hash) && !$application->isExited())
|
||||
<div title="Configuration not applied to the running application. You need to redeploy.">
|
||||
<svg class="w-6 h-6 text-warning" viewBox="0 0 256 256" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill="currentColor" d="M240.26 186.1L152.81 34.23a28.74 28.74 0 0 0-49.62 0L15.74 186.1a27.45 27.45 0 0 0 0 27.71A28.31 28.31 0 0 0 40.55 228h174.9a28.31 28.31 0 0 0 24.79-14.19a27.45 27.45 0 0 0 .02-27.71m-20.8 15.7a4.46 4.46 0 0 1-4 2.2H40.55a4.46 4.46 0 0 1-4-2.2a3.56 3.56 0 0 1 0-3.73L124 46.2a4.77 4.77 0 0 1 8 0l87.44 151.87a3.56 3.56 0 0 1 .02 3.73M116 136v-32a12 12 0 0 1 24 0v32a12 12 0 0 1-24 0m28 40a16 16 0 1 1-16-16a16 16 0 0 1 16 16" />
|
||||
</svg>
|
||||
</div>
|
||||
@endif
|
||||
>>>>>>> 35700ec24 (main: begin major rewrite for lasthour)
|
||||
</div>
|
||||
<div>General configuration for your application.</div>
|
||||
<div class="flex flex-col gap-2 py-4">
|
||||
@ -14,326 +22,279 @@
|
||||
</div>
|
||||
|
||||
@if (!$application->dockerfile && $application->build_pack !== 'dockerimage')
|
||||
<div class="flex flex-col gap-2">
|
||||
<div class="flex gap-2">
|
||||
<x-forms.select x-bind:disabled="initLoadingCompose" wire:model.live="application.build_pack"
|
||||
label="Build Pack" required>
|
||||
<option value="nixpacks">Nixpacks</option>
|
||||
<option value="static">Static</option>
|
||||
<option value="dockerfile">Dockerfile</option>
|
||||
<option value="dockercompose">Docker Compose</option>
|
||||
</x-forms.select>
|
||||
@if ($application->settings->is_static || $application->build_pack === 'static')
|
||||
<x-forms.select id="application.static_image" label="Static Image" required>
|
||||
<option value="nginx:alpine">nginx:alpine</option>
|
||||
<option disabled value="apache:alpine">apache:alpine</option>
|
||||
</x-forms.select>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
@if ($application->build_pack === 'dockercompose')
|
||||
@if (
|
||||
!is_null($parsedServices) &&
|
||||
count($parsedServices) > 0 &&
|
||||
!$application->settings->is_raw_compose_deployment_enabled)
|
||||
<h3 class="pt-6">Domains</h3>
|
||||
@foreach (data_get($parsedServices, 'services') as $serviceName => $service)
|
||||
@if (!isDatabaseImage(data_get($service, 'image')))
|
||||
<div class="flex items-end gap-2">
|
||||
<x-forms.input
|
||||
helper="You can specify one domain with path or more with comma. You can specify a port to bind the domain to.<br><br><span class='text-helper'>Example</span><br>- http://app.coolify.io,https://cloud.coolify.io/dashboard<br>- http://app.coolify.io/api/v3<br>- http://app.coolify.io:3000 -> app.coolify.io will point to port 3000 inside the container. "
|
||||
label="Domains for {{ str($serviceName)->headline() }}"
|
||||
id="parsedServiceDomains.{{ $serviceName }}.domain"></x-forms.input>
|
||||
<x-forms.button wire:click="generateDomain('{{ $serviceName }}')">Generate
|
||||
Domain</x-forms.button>
|
||||
</div>
|
||||
@endif
|
||||
@endforeach
|
||||
@endif
|
||||
@endif
|
||||
|
||||
</div>
|
||||
@endif
|
||||
@if ($application->build_pack !== 'dockercompose')
|
||||
<div class="flex items-end gap-2">
|
||||
<x-forms.input placeholder="https://coolify.io" id="application.fqdn" label="Domains"
|
||||
helper="You can specify one domain with path or more with comma. You can specify a port to bind the domain to.<br><br><span class='text-helper'>Example</span><br>- http://app.coolify.io,https://cloud.coolify.io/dashboard<br>- http://app.coolify.io/api/v3<br>- http://app.coolify.io:3000 -> app.coolify.io will point to port 3000 inside the container. " />
|
||||
<x-forms.button wire:click="getWildcardDomain">Generate Domain
|
||||
</x-forms.button>
|
||||
</div>
|
||||
<div class="flex items-end gap-2">
|
||||
<x-forms.select label="Direction" id="application.redirect" required
|
||||
helper="You must need to add www and non-www as an A DNS record.">
|
||||
<option value="both">Allow www & non-www.</option>
|
||||
<option value="www">Redirect to www.</option>
|
||||
<option value="non-www">Redirect to non-www.</option>
|
||||
<div class="flex flex-col gap-2">
|
||||
<div class="flex gap-2">
|
||||
<x-forms.select x-bind:disabled="initLoadingCompose" wire:model.live="application.build_pack" label="Build Pack" required>
|
||||
<option value="nixpacks">Nixpacks</option>
|
||||
<option value="static">Static</option>
|
||||
<option value="dockerfile">Dockerfile</option>
|
||||
<option value="dockercompose">Docker Compose</option>
|
||||
</x-forms.select>
|
||||
<x-modal-confirmation action="set_redirect">
|
||||
<x-slot:customButton>
|
||||
<div class="w-[7.2rem]">Set Direction</div>
|
||||
</x-slot:customButton>
|
||||
This will reset the container labels. Are you sure?
|
||||
</x-modal-confirmation>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@if ($application->build_pack !== 'dockercompose')
|
||||
<div class="flex items-center gap-2 pt-8">
|
||||
<h3>Docker Registry</h3>
|
||||
@if ($application->build_pack !== 'dockerimage' && !$application->destination->server->isSwarm())
|
||||
<x-helper
|
||||
helper="Push the built image to a docker registry. More info <a class='underline' href='https://coolify.io/docs/knowledge-base/docker/registry' target='_blank'>here</a>." />
|
||||
@endif
|
||||
</div>
|
||||
@if ($application->destination->server->isSwarm())
|
||||
@if ($application->build_pack !== 'dockerimage')
|
||||
<div>Docker Swarm requires the image to be available in a registry. More info <a
|
||||
class="underline" href="https://coolify.io/docs/knowledge-base/docker/registry"
|
||||
target="_blank">here</a>.</div>
|
||||
@endif
|
||||
@endif
|
||||
<div class="flex flex-col gap-2 xl:flex-row">
|
||||
@if ($application->build_pack === 'dockerimage')
|
||||
@if ($application->destination->server->isSwarm())
|
||||
<x-forms.input required id="application.docker_registry_image_name" label="Docker Image" />
|
||||
<x-forms.input id="application.docker_registry_image_tag" label="Docker Image Tag" />
|
||||
@else
|
||||
<x-forms.input id="application.docker_registry_image_name" label="Docker Image" />
|
||||
<x-forms.input id="application.docker_registry_image_tag" label="Docker Image Tag" />
|
||||
@endif
|
||||
@else
|
||||
@if (
|
||||
$application->destination->server->isSwarm() ||
|
||||
$application->additional_servers->count() > 0 ||
|
||||
$application->settings->is_build_server_enabled)
|
||||
<x-forms.input id="application.docker_registry_image_name" required label="Docker Image"
|
||||
placeholder="Required!" />
|
||||
<x-forms.input id="application.docker_registry_image_tag"
|
||||
helper="If set, it will tag the built image with this tag too. <br><br>Example: If you set it to 'latest', it will push the image with the commit sha tag + with the latest tag."
|
||||
placeholder="Empty means latest will be used." label="Docker Image Tag" />
|
||||
@else
|
||||
<x-forms.input id="application.docker_registry_image_name"
|
||||
helper="Empty means it won't push the image to a docker registry."
|
||||
placeholder="Empty means it won't push the image to a docker registry."
|
||||
label="Docker Image" />
|
||||
<x-forms.input id="application.docker_registry_image_tag"
|
||||
placeholder="Empty means only push commit sha tag."
|
||||
helper="If set, it will tag the built image with this tag too. <br><br>Example: If you set it to 'latest', it will push the image with the commit sha tag + with the latest tag."
|
||||
label="Docker Image Tag" />
|
||||
@endif
|
||||
@endif
|
||||
</div>
|
||||
@endif
|
||||
<div class="py-4 border-b dark:border-coolgray-200">
|
||||
<h3>Build</h3>
|
||||
@if ($application->build_pack === 'dockerimage')
|
||||
<x-forms.input
|
||||
helper="You can add custom docker run options that will be used when your container is started.<br>Note: Not all options are supported, as they could mess up Coolify's automation and could cause bad experience for users.<br><br>Check the <a class='underline dark:text-white' href='https://coolify.io/docs/knowledge-base/docker/custom-commands'>docs.</a>"
|
||||
placeholder="--cap-add SYS_ADMIN --device=/dev/fuse --security-opt apparmor:unconfined --ulimit nofile=1024:1024 --tmpfs /run:rw,noexec,nosuid,size=65536k"
|
||||
id="application.custom_docker_run_options" label="Custom Docker Options" />
|
||||
@else
|
||||
@if ($application->could_set_build_commands())
|
||||
@if ($application->build_pack === 'nixpacks')
|
||||
<div class="flex flex-col gap-2 xl:flex-row">
|
||||
<x-forms.input helper="If you modify this, you probably need to have a nixpacks.toml"
|
||||
id="application.install_command" label="Install Command" />
|
||||
<x-forms.input helper="If you modify this, you probably need to have a nixpacks.toml"
|
||||
id="application.build_command" label="Build Command" />
|
||||
<x-forms.input helper="If you modify this, you probably need to have a nixpacks.toml"
|
||||
id="application.start_command" label="Start Command" />
|
||||
</div>
|
||||
<div class="pt-1 text-xs">Nixpacks will detect the required configuration
|
||||
automatically.
|
||||
<a class="underline"
|
||||
href="https://coolify.io/docs/resources/applications/index">Framework
|
||||
Specific Docs</a>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@endif
|
||||
<div class="flex flex-col gap-2 pt-6 pb-10">
|
||||
@if ($application->build_pack === 'dockercompose')
|
||||
<div class="flex flex-col gap-2" x-init="$wire.dispatch('loadCompose', true)">
|
||||
<div class="flex gap-2">
|
||||
<x-forms.input x-bind:disabled="initLoadingCompose" placeholder="/"
|
||||
id="application.base_directory" label="Base Directory"
|
||||
helper="Directory to use as root. Useful for monorepos." />
|
||||
<x-forms.input x-bind:disabled="initLoadingCompose"
|
||||
placeholder="/docker-compose.yaml" id="application.docker_compose_location"
|
||||
label="Docker Compose Location"
|
||||
helper="It is calculated together with the Base Directory:<br><span class='dark:text-warning'>{{ Str::start($application->base_directory . $application->docker_compose_location, '/') }}</span>" />
|
||||
</div>
|
||||
<div class="w-96">
|
||||
<x-forms.checkbox instantSave
|
||||
id="application.settings.is_preserve_repository_enabled"
|
||||
label="Preserve Repository During Deployment"
|
||||
helper="Git repository (based on the base directory settings) will be copied to the deployment directory." />
|
||||
</div>
|
||||
<div class="pt-4">The following commands are for advanced use cases.
|
||||
Only
|
||||
modify them if you
|
||||
know what are
|
||||
you doing.</div>
|
||||
<div class="flex gap-2">
|
||||
<x-forms.input placeholder="docker compose build"
|
||||
x-bind:disabled="initLoadingCompose"
|
||||
id="application.docker_compose_custom_build_command"
|
||||
helper="If you use this, you need to specify paths relatively and should use the same compose file in the custom command, otherwise the automatically configured labels / etc won't work.<br><br>So in your case, use: <span class='dark:text-warning'>docker compose -f .{{ Str::start($application->base_directory . $application->docker_compose_location, '/') }} build</span>"
|
||||
label="Custom Build Command" />
|
||||
<x-forms.input placeholder="docker compose up -d"
|
||||
x-bind:disabled="initLoadingCompose"
|
||||
id="application.docker_compose_custom_start_command"
|
||||
helper="If you use this, you need to specify paths relatively and should use the same compose file in the custom command, otherwise the automatically configured labels / etc won't work.<br><br>So in your case, use: <span class='dark:text-warning'>docker compose -f .{{ Str::start($application->base_directory . $application->docker_compose_location, '/') }} up -d</span>"
|
||||
label="Custom Start Command" />
|
||||
</div>
|
||||
</div>
|
||||
@else
|
||||
<div class="flex flex-col gap-2 xl:flex-row">
|
||||
<x-forms.input placeholder="/" id="application.base_directory" label="Base Directory"
|
||||
helper="Directory to use as root. Useful for monorepos." />
|
||||
@if ($application->build_pack === 'dockerfile' && !$application->dockerfile)
|
||||
<x-forms.input placeholder="/Dockerfile" id="application.dockerfile_location"
|
||||
label="Dockerfile Location"
|
||||
helper="It is calculated together with the Base Directory:<br><span class='dark:text-warning'>{{ Str::start($application->base_directory . $application->dockerfile_location, '/') }}</span>" />
|
||||
@endif
|
||||
|
||||
@if ($application->build_pack === 'dockerfile')
|
||||
<x-forms.input id="application.dockerfile_target_build"
|
||||
label="Docker Build Stage Target"
|
||||
helper="Useful if you have multi-staged dockerfile." />
|
||||
@endif
|
||||
@if ($application->could_set_build_commands())
|
||||
@if ($application->settings->is_static)
|
||||
<x-forms.input placeholder="/dist" id="application.publish_directory"
|
||||
label="Publish Directory" required />
|
||||
@else
|
||||
<x-forms.input placeholder="/" id="application.publish_directory"
|
||||
label="Publish Directory" />
|
||||
@endif
|
||||
@endif
|
||||
|
||||
</div>
|
||||
@if ($this->application->is_github_based() && !$this->application->is_public_repository())
|
||||
<div class="pb-4">
|
||||
<x-forms.textarea
|
||||
helper="Gitignore-style rules to filter Git based webhook deployments."
|
||||
placeholder="src/pages/**" id="application.watch_paths"
|
||||
label="Watch Paths" />
|
||||
</div>
|
||||
@endif
|
||||
<x-forms.input
|
||||
helper="You can add custom docker run options that will be used when your container is started.<br>Note: Not all options are supported, as they could mess up Coolify's automation and could cause bad experience for users.<br><br>Check the <a class='underline dark:text-white' href='https://coolify.io/docs/knowledge-base/docker/custom-commands'>docs.</a>"
|
||||
placeholder="--cap-add SYS_ADMIN --device=/dev/fuse --security-opt apparmor:unconfined --ulimit nofile=1024:1024 --tmpfs /run:rw,noexec,nosuid,size=65536k"
|
||||
id="application.custom_docker_run_options" label="Custom Docker Options" />
|
||||
|
||||
@if ($application->build_pack !== 'dockercompose')
|
||||
<div class="pt-2 w-96">
|
||||
<x-forms.checkbox
|
||||
helper="Use a build server to build your application. You can configure your build server in the Server settings. This is experimental. For more info, check the <a href='https://coolify.io/docs/knowledge-base/server/build-server' class='underline' target='_blank'>documentation</a>."
|
||||
instantSave id="application.settings.is_build_server_enabled"
|
||||
label="Use a Build Server? (experimental)" />
|
||||
</div>
|
||||
@endif
|
||||
@if ($application->could_set_build_commands())
|
||||
<div class="w-96">
|
||||
<x-forms.checkbox instantSave id="application.settings.is_static"
|
||||
label="Is it a static site?"
|
||||
helper="If your application is a static site or the final build assets should be served as a static site, enable this." />
|
||||
</div>
|
||||
@endif
|
||||
@endif
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
@if ($application->build_pack === 'dockercompose')
|
||||
<x-forms.button wire:target='initLoadingCompose'
|
||||
x-on:click="$wire.dispatch('loadCompose', false)">Reload Compose File</x-forms.button>
|
||||
@if ($application->settings->is_raw_compose_deployment_enabled)
|
||||
<x-forms.textarea rows="10" readonly id="application.docker_compose_raw"
|
||||
label="Docker Compose Content (applicationId: {{ $application->id }})"
|
||||
helper="You need to modify the docker compose file." monacoEditorLanguage="yaml"
|
||||
useMonacoEditor />
|
||||
@else
|
||||
<x-forms.textarea rows="10" readonly id="application.docker_compose"
|
||||
label="Docker Compose Content" helper="You need to modify the docker compose file."
|
||||
monacoEditorLanguage="yaml" useMonacoEditor />
|
||||
@endif
|
||||
<div class="w-96">
|
||||
<x-forms.checkbox label="Escape special characters in labels?"
|
||||
helper="By default, $ (and other chars) is escaped. So if you write $ in the labels, it will be saved as $$.<br><br>If you want to use env variables inside the labels, turn this off."
|
||||
id="application.settings.is_container_label_escape_enabled" instantSave></x-forms.checkbox>
|
||||
<x-forms.checkbox label="Readonly labels"
|
||||
helper="If you know what are you doing, you can enable this to edit the labels directly. Coolify won't update labels automatically. <br><br>Be careful, it could break the proxy configuration after you restart the container."
|
||||
id="application.settings.is_container_label_readonly_enabled" instantSave></x-forms.checkbox>
|
||||
</div>
|
||||
@endif
|
||||
@if ($application->dockerfile)
|
||||
<x-forms.textarea label="Dockerfile" id="application.dockerfile" monacoEditorLanguage="dockerfile"
|
||||
useMonacoEditor rows="6"> </x-forms.textarea>
|
||||
@endif
|
||||
@if ($application->build_pack !== 'dockercompose')
|
||||
<h3 class="pt-8">Network</h3>
|
||||
<div class="flex flex-col gap-2 xl:flex-row">
|
||||
@if ($application->settings->is_static || $application->build_pack === 'static')
|
||||
<x-forms.input id="application.ports_exposes" label="Ports Exposes" readonly />
|
||||
@else
|
||||
<x-forms.input placeholder="3000,3001" id="application.ports_exposes" label="Ports Exposes"
|
||||
required
|
||||
helper="A comma separated list of ports your application uses. The first port will be used as default healthcheck port if nothing defined in the Healthcheck menu. Be sure to set this correctly." />
|
||||
@endif
|
||||
@if (!$application->destination->server->isSwarm())
|
||||
<x-forms.input placeholder="3000:3000" id="application.ports_mappings" label="Ports Mappings"
|
||||
helper="A comma separated list of ports you would like to map to the host system. Useful when you do not want to use domains.<br><br><span class='inline-block font-bold dark:text-warning'>Example:</span><br>3000:3000,3002:3002<br><br>Rolling update is not supported if you have a port mapped to the host." />
|
||||
<x-forms.select id="application.static_image" label="Static Image" required>
|
||||
<option value="nginx:alpine">nginx:alpine</option>
|
||||
<option disabled value="apache:alpine">apache:alpine</option>
|
||||
</x-forms.select>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
<x-forms.textarea label="Container Labels" rows="15" id="customLabels"
|
||||
monacoEditorLanguage="ini" useMonacoEditor></x-forms.textarea>
|
||||
<div class="w-96">
|
||||
<x-forms.checkbox label="Escape special characters in labels?"
|
||||
helper="By default, $ (and other chars) is escaped. So if you write $ in the labels, it will be saved as $$.<br><br>If you want to use env variables inside the labels, turn this off."
|
||||
id="application.settings.is_container_label_escape_enabled" instantSave></x-forms.checkbox>
|
||||
<x-forms.checkbox label="Readonly labels"
|
||||
helper="If you know what are you doing, you can enable this to edit the labels directly. Coolify won't update labels automatically. <br><br>Be careful, it could break the proxy configuration after you restart the container."
|
||||
id="application.settings.is_container_label_readonly_enabled" instantSave></x-forms.checkbox>
|
||||
@if ($application->build_pack === 'dockercompose')
|
||||
@if (
|
||||
!is_null($parsedServices) &&
|
||||
count($parsedServices) > 0 &&
|
||||
!$application->settings->is_raw_compose_deployment_enabled)
|
||||
<h3 class="pt-6">Domains</h3>
|
||||
@foreach (data_get($parsedServices, 'services') as $serviceName => $service)
|
||||
@if (!isDatabaseImage(data_get($service, 'image')))
|
||||
<div class="flex items-end gap-2">
|
||||
<x-forms.input helper="You can specify one domain with path or more with comma. You can specify a port to bind the domain to.<br><br><span class='text-helper'>Example</span><br>- http://app.coolify.io,https://cloud.coolify.io/dashboard<br>- http://app.coolify.io/api/v3<br>- http://app.coolify.io:3000 -> app.coolify.io will point to port 3000 inside the container. " label="Domains for {{ str($serviceName)->headline() }}" id="parsedServiceDomains.{{ $serviceName }}.domain"></x-forms.input>
|
||||
<x-forms.button wire:click="generateDomain('{{ $serviceName }}')">Generate
|
||||
Domain</x-forms.button>
|
||||
</div>
|
||||
<x-modal-confirmation buttonFullWidth action="resetDefaultLabels"
|
||||
buttonTitle="Reset to Coolify Generated Labels">
|
||||
Are you sure you want to reset the labels to Coolify generated labels? <br>It could break the proxy
|
||||
configuration after you restart the container.
|
||||
@endif
|
||||
@endforeach
|
||||
@endif
|
||||
@endif
|
||||
|
||||
</div>
|
||||
@endif
|
||||
@if ($application->build_pack !== 'dockercompose')
|
||||
<div class="flex items-end gap-2">
|
||||
<x-forms.input placeholder="https://lasthourhosting.org" id="application.fqdn" label="Domains" helper="You can specify one domain with path or more with comma. You can specify a port to bind the domain to.<br><br><span class='text-helper'>Example</span><br>- http://app.lasthourhosting.org,https://cloud.lasthourhosting.org/dashboard<br>- http://app.lasthourhosting.org/api/v3<br>- http://app.lasthourhosting.org:3000 -> app.lasthourhosting.org will point to port 3000 inside the container. " />
|
||||
<x-forms.button wire:click="getWildcardDomain">Generate Domain
|
||||
</x-forms.button>
|
||||
</div>
|
||||
<div class="flex items-end gap-2">
|
||||
<x-forms.select label="Direction" id="application.redirect" required helper="You must need to add www and non-www as an A DNS record.">
|
||||
<option value="both">Allow www & non-www.</option>
|
||||
<option value="www">Redirect to www.</option>
|
||||
<option value="non-www">Redirect to non-www.</option>
|
||||
</x-forms.select>
|
||||
<x-modal-confirmation action="set_redirect">
|
||||
<x-slot:customButton>
|
||||
<div class="w-[7.2rem]">Set Direction</div>
|
||||
</x-slot:customButton>
|
||||
This will reset the container labels. Are you sure?
|
||||
</x-modal-confirmation>
|
||||
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<h3 class="pt-8">Pre/Post Deployment Commands</h3>
|
||||
<div class="flex flex-col gap-2 xl:flex-row">
|
||||
<x-forms.input x-bind:disabled="initLoadingCompose" placeholder="php artisan migrate"
|
||||
id="application.pre_deployment_command" label="Pre-deployment "
|
||||
helper="An optional script or command to execute in the existing container before the deployment begins.<br>It is always executed with 'sh -c', so you do not need add it manually." />
|
||||
@if ($application->build_pack === 'dockercompose')
|
||||
<x-forms.input x-bind:disabled="initLoadingCompose"
|
||||
id="application.pre_deployment_command_container" label="Container Name"
|
||||
helper="The name of the container to execute within. You can leave it blank if your application only has one container." />
|
||||
@if ($application->build_pack !== 'dockercompose')
|
||||
<div class="flex items-center gap-2 pt-8">
|
||||
<h3>Docker Registry</h3>
|
||||
@if ($application->build_pack !== 'dockerimage' && !$application->destination->server->isSwarm())
|
||||
<x-helper helper="Push the built image to a docker registry. More info <a class='underline' href='https://coolify.io/docs/knowledge-base/docker/registry' target='_blank'>here</a>." />
|
||||
@endif
|
||||
</div>
|
||||
<div class="flex flex-col gap-2 xl:flex-row">
|
||||
<x-forms.input x-bind:disabled="initLoadingCompose" placeholder="php artisan migrate"
|
||||
id="application.post_deployment_command" label="Post-deployment "
|
||||
helper="An optional script or command to execute in the newly built container after the deployment completes.<br>It is always executed with 'sh -c', so you do not need add it manually." />
|
||||
@if ($application->build_pack === 'dockercompose')
|
||||
<x-forms.input x-bind:disabled="initLoadingCompose"
|
||||
id="application.post_deployment_command_container" label="Container Name"
|
||||
helper="The name of the container to execute within. You can leave it blank if your application only has one container." />
|
||||
@if ($application->destination->server->isSwarm())
|
||||
@if ($application->build_pack !== 'dockerimage')
|
||||
<div>Docker Swarm requires the image to be available in a registry. More info <a class="underline" href="https://coolify.io/docs/knowledge-base/docker/registry" target="_blank">here</a>.</div>
|
||||
@endif
|
||||
@endif
|
||||
@if ($application->build_pack === 'dockercompose')
|
||||
<div class="w-96">
|
||||
<x-forms.checkbox instantSave id="application.settings.is_raw_compose_deployment_enabled" label="Raw Compose Deployment" helper="WARNING: Advanced use cases only. Your docker compose file will be deployed as-is. Nothing is modified by Coolify. You need to configure the proxy parts. More info in the <a href='https://coolify.io/docs/docker/compose#raw-docker-compose-deployment'>documentation.</a>" />
|
||||
</div>
|
||||
@if (count($parsedServices) > 0 && !$application->settings->is_raw_compose_deployment_enabled)
|
||||
@foreach (data_get($parsedServices, 'services') as $serviceName => $service)
|
||||
@if (!isDatabaseImage(data_get($service, 'image')))
|
||||
<div class="flex items-end gap-2">
|
||||
<x-forms.input helper="You can specify one domain with path or more with comma. You can specify a port to bind the domain to.<br><br><span class='text-helper'>Example</span><br>- http://app.coolify.io, https://cloud.coolify.io/dashboard<br>- http://app.coolify.io/api/v3<br>- http://app.coolify.io:3000 -> app.coolify.io will point to port 3000 inside the container. " label="Domains for {{ str($serviceName)->headline() }}" id="parsedServiceDomains.{{ $serviceName }}.domain"></x-forms.input>
|
||||
@if (!data_get($parsedServiceDomains, "$serviceName.domain"))
|
||||
<x-forms.button wire:click="generateDomain('{{ $serviceName }}')">Generate
|
||||
Domain</x-forms.button>
|
||||
@endif
|
||||
</div>
|
||||
@endif
|
||||
@endforeach
|
||||
@endif
|
||||
@endif
|
||||
</div>
|
||||
@endif
|
||||
@if ($application->build_pack !== 'dockercompose')
|
||||
<div class="flex items-end gap-2">
|
||||
<x-forms.input placeholder="https://lasthourhosting.org" id="application.fqdn" label="Domains" helper="You can specify one domain with path or more with comma. You can specify a port to bind the domain to.<br><br><span class='text-helper'>Example</span><br>- http://app.lasthourhosting.org, https://cloud.lasthourhosting.org/dashboard<br>- http://app.lasthourhosting.org/api/v3<br>- http://app.lasthourhosting.org:3000 -> app.lasthourhosting.org will point to port 3000 inside the container. " />
|
||||
<x-forms.button wire:click="getWildcardDomain">Generate Domain
|
||||
</x-forms.button>
|
||||
</div>
|
||||
@endif
|
||||
@if ($application->build_pack !== 'dockercompose')
|
||||
<div class="flex items-center gap-2 pt-8">
|
||||
<h3>Docker Registry</h3>
|
||||
@if ($application->build_pack !== 'dockerimage' && !$application->destination->server->isSwarm())
|
||||
<x-helper helper='Push the built image to a docker registry. More info <a class="underline"
|
||||
href="https://coolify.io/docs/docker/registry" target="_blank">here</a>' />
|
||||
@endif
|
||||
</div>
|
||||
@if ($application->destination->server->isSwarm())
|
||||
@if ($application->build_pack !== 'dockerimage')
|
||||
<div>Docker Swarm requires the image to be available in a registry. More info in upstream docs<a class="underline" href="https://coolify.io/docs/docker/registry" target="_blank">here</a>.</div>
|
||||
@endif
|
||||
@endif
|
||||
<div class="flex flex-col gap-2 xl:flex-row">
|
||||
@if ($application->build_pack === 'dockerimage')
|
||||
@if ($application->destination->server->isSwarm())
|
||||
<x-forms.input required id="application.docker_registry_image_name" label="Docker Image" />
|
||||
<x-forms.input id="application.docker_registry_image_tag" label="Docker Image Tag" />
|
||||
@else
|
||||
<x-forms.input id="application.docker_registry_image_name" label="Docker Image" />
|
||||
<x-forms.input id="application.docker_registry_image_tag" label="Docker Image Tag" />
|
||||
@endif
|
||||
@else
|
||||
@if (
|
||||
$application->destination->server->isSwarm() ||
|
||||
$application->additional_servers->count() > 0 ||
|
||||
$application->settings->is_build_server_enabled)
|
||||
<x-forms.input id="application.docker_registry_image_name" required label="Docker Image" placeholder="Required!" />
|
||||
<x-forms.input id="application.docker_registry_image_tag" helper="If set, it will tag the built image with this tag too. <br><br>Example: If you set it to 'latest', it will push the image with the commit sha tag + with the latest tag." placeholder="Empty means latest will be used." label="Docker Image Tag" />
|
||||
@else
|
||||
<x-forms.input id="application.docker_registry_image_name" helper="Empty means it won't push the image to a docker registry." placeholder="Empty means it won't push the image to a docker registry." label="Docker Image" />
|
||||
<x-forms.input id="application.docker_registry_image_tag" placeholder="Empty means only push commit sha tag." helper="If set, it will tag the built image with this tag too. <br><br>Example: If you set it to 'latest', it will push the image with the commit sha tag + with the latest tag." label="Docker Image Tag" />
|
||||
@endif
|
||||
@endif
|
||||
</div>
|
||||
@endif
|
||||
<div class="py-4 border-b dark:border-coolgray-200">
|
||||
<h3>Build</h3>
|
||||
@if ($application->build_pack === 'dockerimage')
|
||||
<x-forms.input helper="You can add custom docker run options that will be used when your container is started.<br>Note: Not all options are supported, as they could mess up Coolify's automation and could cause bad experience for users.<br><br>Check the <a class='underline dark:text-white' href='https://coolify.io/docs/knowledge-base/docker/custom-commands'>docs.</a>" placeholder="--cap-add SYS_ADMIN --device=/dev/fuse --security-opt apparmor:unconfined --ulimit nofile=1024:1024 --tmpfs /run:rw,noexec,nosuid,size=65536k" id="application.custom_docker_run_options" label="Custom Docker Options" />
|
||||
@else
|
||||
@if ($application->could_set_build_commands())
|
||||
@if ($application->build_pack === 'nixpacks')
|
||||
<div class="flex flex-col gap-2 xl:flex-row">
|
||||
<x-forms.input helper="If you modify this, you probably need to have a nixpacks.toml" id="application.install_command" label="Install Command" />
|
||||
<x-forms.input helper="If you modify this, you probably need to have a nixpacks.toml" id="application.build_command" label="Build Command" />
|
||||
<x-forms.input helper="If you modify this, you probably need to have a nixpacks.toml" id="application.start_command" label="Start Command" />
|
||||
</div>
|
||||
<div class="pt-1 text-xs">Nixpacks will detect the required configuration
|
||||
automatically.
|
||||
<a class="underline" href="https://coolify.io/docs/resources/applications/index">Framework
|
||||
Specific Docs</a>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@endif
|
||||
<div class="flex flex-col gap-2 pt-6 pb-10">
|
||||
@if ($application->build_pack === 'dockercompose')
|
||||
<div class="flex flex-col gap-2" x-init="$wire.dispatch('loadCompose', true)">
|
||||
<div class="flex gap-2">
|
||||
<x-forms.input x-bind:disabled="initLoadingCompose" placeholder="/" id="application.base_directory" label="Base Directory" helper="Directory to use as root. Useful for monorepos." />
|
||||
<x-forms.input x-bind:disabled="initLoadingCompose" placeholder="/docker-compose.yaml" id="application.docker_compose_location" label="Docker Compose Location" helper="It is calculated together with the Base Directory:<br><span class='dark:text-warning'>{{ Str::start($application->base_directory . $application->docker_compose_location, '/') }}</span>" />
|
||||
</div>
|
||||
<div class="w-96">
|
||||
<x-forms.checkbox instantSave id="application.settings.is_preserve_repository_enabled" label="Preserve Repository During Deployment" helper="Git repository (based on the base directory settings) will be copied to the deployment directory." />
|
||||
</div>
|
||||
<div class="pt-4">The following commands are for advanced use cases.
|
||||
Only
|
||||
modify them if you
|
||||
know what are
|
||||
you doing.</div>
|
||||
<div class="flex gap-2">
|
||||
<x-forms.input placeholder="docker compose build" x-bind:disabled="initLoadingCompose" id="application.docker_compose_custom_build_command" helper="If you use this, you need to specify paths relatively and should use the same compose file in the custom command, otherwise the automatically configured labels / etc won't work.<br><br>So in your case, use: <span class='dark:text-warning'>docker compose -f .{{ Str::start($application->base_directory . $application->docker_compose_location, '/') }} build</span>" label="Custom Build Command" />
|
||||
<x-forms.input placeholder="docker compose up -d" x-bind:disabled="initLoadingCompose" id="application.docker_compose_custom_start_command" helper="If you use this, you need to specify paths relatively and should use the same compose file in the custom command, otherwise the automatically configured labels / etc won't work.<br><br>So in your case, use: <span class='dark:text-warning'>docker compose -f .{{ Str::start($application->base_directory . $application->docker_compose_location, '/') }} up -d</span>" label="Custom Start Command" />
|
||||
</div>
|
||||
</div>
|
||||
@else
|
||||
<div class="flex flex-col gap-2 xl:flex-row">
|
||||
<x-forms.input placeholder="/" id="application.base_directory" label="Base Directory" helper="Directory to use as root. Useful for monorepos." />
|
||||
@if ($application->build_pack === 'dockerfile' && !$application->dockerfile)
|
||||
<x-forms.input placeholder="/Dockerfile" id="application.dockerfile_location" label="Dockerfile Location" helper="It is calculated together with the Base Directory:<br><span class='dark:text-warning'>{{ Str::start($application->base_directory . $application->dockerfile_location, '/') }}</span>" />
|
||||
@endif
|
||||
|
||||
@if ($application->build_pack === 'dockerfile')
|
||||
<x-forms.input id="application.dockerfile_target_build" label="Docker Build Stage Target" helper="Useful if you have multi-staged dockerfile." />
|
||||
@endif
|
||||
@if ($application->could_set_build_commands())
|
||||
@if ($application->settings->is_static)
|
||||
<x-forms.input placeholder="/dist" id="application.publish_directory" label="Publish Directory" required />
|
||||
@else
|
||||
<x-forms.input placeholder="/" id="application.publish_directory" label="Publish Directory" />
|
||||
@endif
|
||||
@endif
|
||||
|
||||
</div>
|
||||
@if ($this->application->is_github_based() && !$this->application->is_public_repository())
|
||||
<div class="pb-4">
|
||||
<x-forms.textarea helper="Gitignore-style rules to filter Git based webhook deployments." placeholder="src/pages/**" id="application.watch_paths" label="Watch Paths" />
|
||||
</div>
|
||||
@endif
|
||||
<x-forms.input helper="You can add custom docker run options that will be used when your container is started.<br>Note: Not all options are supported, as they could mess up Coolify's automation and could cause bad experience for users.<br><br>Check the <a class='underline dark:text-white' href='https://coolify.io/docs/knowledge-base/docker/custom-commands'>docs.</a>" placeholder="--cap-add SYS_ADMIN --device=/dev/fuse --security-opt apparmor:unconfined --ulimit nofile=1024:1024 --tmpfs /run:rw,noexec,nosuid,size=65536k" id="application.custom_docker_run_options" label="Custom Docker Options" />
|
||||
|
||||
@if ($application->build_pack !== 'dockercompose')
|
||||
<div class="pt-2 w-96">
|
||||
<x-forms.checkbox helper="Use a build server to build your application. You can configure your build server in the Server settings. This is experimental. For more info, check the <a href='https://coolify.io/docs/knowledge-base/server/build-server' class='underline' target='_blank'>documentation</a>." instantSave id="application.settings.is_build_server_enabled" label="Use a Build Server? (experimental)" />
|
||||
</div>
|
||||
@endif
|
||||
@if ($application->could_set_build_commands())
|
||||
<div class="w-96">
|
||||
<x-forms.checkbox instantSave id="application.settings.is_static" label="Is it a static site?" helper="If your application is a static site or the final build assets should be served as a static site, enable this." />
|
||||
</div>
|
||||
@endif
|
||||
@endif
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
@if ($application->build_pack === 'dockercompose')
|
||||
<x-forms.button wire:target='initLoadingCompose' x-on:click="$wire.dispatch('loadCompose', false)">Reload Compose File</x-forms.button>
|
||||
@if ($application->settings->is_raw_compose_deployment_enabled)
|
||||
<x-forms.textarea rows="10" readonly id="application.docker_compose_raw" label="Docker Compose Content (applicationId: {{ $application->id }})" helper="You need to modify the docker compose file." monacoEditorLanguage="yaml" useMonacoEditor />
|
||||
@else
|
||||
<x-forms.textarea rows="10" readonly id="application.docker_compose" label="Docker Compose Content" helper="You need to modify the docker compose file." monacoEditorLanguage="yaml" useMonacoEditor />
|
||||
@endif
|
||||
<div class="w-96">
|
||||
<x-forms.checkbox label="Escape special characters in labels?" helper="By default, $ (and other chars) is escaped. So if you write $ in the labels, it will be saved as $$.<br><br>If you want to use env variables inside the labels, turn this off." id="application.settings.is_container_label_escape_enabled" instantSave></x-forms.checkbox>
|
||||
<x-forms.checkbox label="Readonly labels" helper="If you know what are you doing, you can enable this to edit the labels directly. Coolify won't update labels automatically. <br><br>Be careful, it could break the proxy configuration after you restart the container." id="application.settings.is_container_label_readonly_enabled" instantSave></x-forms.checkbox>
|
||||
</div>
|
||||
@endif
|
||||
@if ($application->dockerfile)
|
||||
<x-forms.textarea label="Dockerfile" id="application.dockerfile" monacoEditorLanguage="dockerfile" useMonacoEditor rows="6"> </x-forms.textarea>
|
||||
@endif
|
||||
@if ($application->build_pack !== 'dockercompose')
|
||||
<h3 class="pt-8">Network</h3>
|
||||
<div class="flex flex-col gap-2 xl:flex-row">
|
||||
@if ($application->settings->is_static || $application->build_pack === 'static')
|
||||
<x-forms.input id="application.ports_exposes" label="Ports Exposes" readonly />
|
||||
@else
|
||||
<x-forms.input placeholder="3000,3001" id="application.ports_exposes" label="Ports Exposes" required helper="A comma separated list of ports your application uses. The first port will be used as default healthcheck port if nothing defined in the Healthcheck menu. Be sure to set this correctly." />
|
||||
@endif
|
||||
@if (!$application->destination->server->isSwarm())
|
||||
<x-forms.input placeholder="3000:3000" id="application.ports_mappings" label="Ports Mappings" helper="A comma separated list of ports you would like to map to the host system. Useful when you do not want to use domains.<br><br><span class='inline-block font-bold dark:text-warning'>Example:</span><br>3000:3000,3002:3002<br><br>Rolling update is not supported if you have a port mapped to the host." />
|
||||
@endif
|
||||
</div>
|
||||
|
||||
<x-forms.textarea label="Container Labels" rows="15" id="customLabels" monacoEditorLanguage="ini" useMonacoEditor></x-forms.textarea>
|
||||
<div class="w-96">
|
||||
<x-forms.checkbox label="Escape special characters in labels?" helper="By default, $ (and other chars) is escaped. So if you write $ in the labels, it will be saved as $$.<br><br>If you want to use env variables inside the labels, turn this off." id="application.settings.is_container_label_escape_enabled" instantSave></x-forms.checkbox>
|
||||
<x-forms.checkbox label="Readonly labels" helper="If you know what are you doing, you can enable this to edit the labels directly. Last Hour Cloud won't update labels automatically. <br><br>Be careful, it could break the proxy configuration after you restart the container." id="application.settings.is_container_label_readonly_enabled" instantSave></x-forms.checkbox>
|
||||
</div>
|
||||
<x-modal-confirmation buttonFullWidth action="resetDefaultLabels" buttonTitle="Reset to Last Hour Cloud Generated Labels">
|
||||
Are you sure you want to reset the labels to Last Hour Cloud generated labels? <br>It could break the proxy
|
||||
configuration after you restart the container.
|
||||
</x-modal-confirmation>
|
||||
|
||||
@endif
|
||||
|
||||
<h3 class="pt-8">Pre/Post Deployment Commands</h3>
|
||||
<div class="flex flex-col gap-2 xl:flex-row">
|
||||
<x-forms.input x-bind:disabled="initLoadingCompose" placeholder="php artisan migrate" id="application.pre_deployment_command" label="Pre-deployment " helper="An optional script or command to execute in the existing container before the deployment begins.<br>It is always executed with 'sh -c', so you do not need add it manually." />
|
||||
@if ($application->build_pack === 'dockercompose')
|
||||
<x-forms.input x-bind:disabled="initLoadingCompose" id="application.pre_deployment_command_container" label="Container Name" helper="The name of the container to execute within. You can leave it blank if your application only has one container." />
|
||||
@endif
|
||||
</div>
|
||||
<div class="flex flex-col gap-2 xl:flex-row">
|
||||
<x-forms.input x-bind:disabled="initLoadingCompose" placeholder="php artisan migrate" id="application.post_deployment_command" label="Post-deployment " helper="An optional script or command to execute in the newly built container after the deployment completes.<br>It is always executed with 'sh -c', so you do not need add it manually." />
|
||||
@if ($application->build_pack === 'dockercompose')
|
||||
<x-forms.input x-bind:disabled="initLoadingCompose" id="application.post_deployment_command_container" label="Container Name" helper="The name of the container to execute within. You can leave it blank if your application only has one container." />
|
||||
@endif
|
||||
</div>
|
||||
</form>
|
||||
@script
|
||||
<script>
|
||||
$wire.$on('loadCompose', (isInit = true) => {
|
||||
$wire.initLoadingCompose = true;
|
||||
$wire.loadComposeFile(isInit);
|
||||
});
|
||||
</script>
|
||||
@endscript
|
||||
</div>
|
||||
</form>
|
||||
@script
|
||||
<script>
|
||||
$wire.$on('loadCompose', (isInit = true) => {
|
||||
$wire.initLoadingCompose = true;
|
||||
$wire.loadComposeFile(isInit);
|
||||
});
|
||||
</script>
|
||||
@endscript
|
||||
</div>
|
@ -1,20 +1,20 @@
|
||||
<div>
|
||||
<x-slot:title>
|
||||
{{ data_get_str($project, 'name')->limit(10) }} > Edit | Coolify
|
||||
</x-slot>
|
||||
<form wire:submit='submit' class="flex flex-col pb-10">
|
||||
<div class="flex gap-2">
|
||||
<h1>Project: {{ data_get($project, 'name') }}</h1>
|
||||
<div class="flex items-end gap-2">
|
||||
<x-forms.button type="submit">Save</x-forms.button>
|
||||
<livewire:project.delete-project :disabled="$project->resource_count() > 0" :project_id="$project->id" />
|
||||
</x-slot>
|
||||
<form wire:submit='submit' class="flex flex-col pb-10">
|
||||
<div class="flex gap-2">
|
||||
<h1>Project: {{ data_get($project, 'name') }}</h1>
|
||||
<div class="flex items-end gap-2">
|
||||
<x-forms.button type="submit">Save</x-forms.button>
|
||||
<livewire:project.delete-project :disabled="$project->resource_count() > 0" :project_id="$project->id" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pt-2 pb-10">Edit project details here.</div>
|
||||
<div class="pt-2 pb-10">Edit project details here.</div>
|
||||
|
||||
<div class="flex gap-2">
|
||||
<x-forms.input label="Name" id="project.name" />
|
||||
<x-forms.input label="Description" id="project.description" />
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="flex gap-2">
|
||||
<x-forms.input label="Name" id="project.name" />
|
||||
<x-forms.input label="Description" id="project.description" />
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
@ -1,50 +1,42 @@
|
||||
<div>
|
||||
<x-slot:title>
|
||||
{{ data_get_str($project, 'name')->limit(10) }} > Edit | Coolify
|
||||
</x-slot>
|
||||
<form wire:submit='submit' class="flex flex-col">
|
||||
<div class="flex items-end gap-2">
|
||||
<h1>Environment: {{ data_get($environment, 'name') }}</h1>
|
||||
<x-forms.button type="submit">Save</x-forms.button>
|
||||
<livewire:project.delete-environment :disabled="!$environment->isEmpty()" :environment_id="$environment->id" />
|
||||
</div>
|
||||
<nav class="flex pt-2 pb-10">
|
||||
<ol class="flex flex-wrap items-center gap-y-1">
|
||||
<li class="inline-flex items-center">
|
||||
<div class="flex items-center">
|
||||
<a class="text-xs truncate lg:text-sm"
|
||||
href="{{ route('project.show', ['project_uuid' => data_get($parameters, 'project_uuid')]) }}">
|
||||
{{ $project->name }}</a>
|
||||
<svg aria-hidden="true" class="w-4 h-4 mx-1 font-bold dark:text-warning" fill="currentColor"
|
||||
viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd"
|
||||
d="M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z"
|
||||
clip-rule="evenodd"></path>
|
||||
</svg>
|
||||
</div>
|
||||
</li>
|
||||
<li>
|
||||
<div class="flex items-center">
|
||||
<a class="text-xs truncate lg:text-sm"
|
||||
href="{{ route('project.resource.index', ['environment_name' => data_get($parameters, 'environment_name'), 'project_uuid' => data_get($parameters, 'project_uuid')]) }}">{{ data_get($parameters, 'environment_name') }}</a>
|
||||
</div>
|
||||
</li>
|
||||
<li>
|
||||
<div class="flex items-center">
|
||||
<svg aria-hidden="true" class="w-4 h-4 mx-1 font-bold dark:text-warning" fill="currentColor"
|
||||
viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd"
|
||||
d="M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z"
|
||||
clip-rule="evenodd"></path>
|
||||
</svg>
|
||||
Edit
|
||||
</div>
|
||||
</li>
|
||||
</ol>
|
||||
</nav>
|
||||
<div class="flex gap-2">
|
||||
<x-forms.input label="Name" id="environment.name" />
|
||||
<x-forms.input label="Description" id="environment.description" />
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</x-slot>
|
||||
<form wire:submit='submit' class="flex flex-col">
|
||||
<div class="flex items-end gap-2">
|
||||
<h1>Environment: {{ data_get($environment, 'name') }}</h1>
|
||||
<x-forms.button type="submit">Save</x-forms.button>
|
||||
<livewire:project.delete-environment :disabled="!$environment->isEmpty()" :environment_id="$environment->id" />
|
||||
</div>
|
||||
<nav class="flex pt-2 pb-10">
|
||||
<ol class="flex flex-wrap items-center gap-y-1">
|
||||
<li class="inline-flex items-center">
|
||||
<div class="flex items-center">
|
||||
<a class="text-xs truncate lg:text-sm" href="{{ route('project.show', ['project_uuid' => data_get($parameters, 'project_uuid')]) }}">
|
||||
{{ $project->name }}</a>
|
||||
<svg aria-hidden="true" class="w-4 h-4 mx-1 font-bold dark:text-warning" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" d="M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z" clip-rule="evenodd"></path>
|
||||
</svg>
|
||||
</div>
|
||||
</li>
|
||||
<li>
|
||||
<div class="flex items-center">
|
||||
<a class="text-xs truncate lg:text-sm" href="{{ route('project.resource.index', ['environment_name' => data_get($parameters, 'environment_name'), 'project_uuid' => data_get($parameters, 'project_uuid')]) }}">{{ data_get($parameters, 'environment_name') }}</a>
|
||||
</div>
|
||||
</li>
|
||||
<li>
|
||||
<div class="flex items-center">
|
||||
<svg aria-hidden="true" class="w-4 h-4 mx-1 font-bold dark:text-warning" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" d="M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z" clip-rule="evenodd"></path>
|
||||
</svg>
|
||||
Edit
|
||||
</div>
|
||||
</li>
|
||||
</ol>
|
||||
</nav>
|
||||
<div class="flex gap-2">
|
||||
<x-forms.input label="Name" id="environment.name" />
|
||||
<x-forms.input label="Description" id="environment.description" />
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
@ -1,14 +1,12 @@
|
||||
<div>
|
||||
<h1>Create a new Service</h1>
|
||||
<div class="pb-4">You can deploy complex services easily with Docker Compose.</div>
|
||||
<form wire:submit="submit">
|
||||
<div class="flex gap-2 pb-1">
|
||||
<h2>Docker Compose</h2>
|
||||
<x-forms.button type="submit">Save</x-forms.button>
|
||||
</div>
|
||||
<x-forms.textarea useMonacoEditor monacoEditorLanguage="yaml" label="Docker Compose file" rows="20"
|
||||
id="dockerComposeRaw"
|
||||
placeholder='services:
|
||||
<h1>Create a new Service</h1>
|
||||
<div class="pb-4">You can deploy complex services easily with Docker Compose.</div>
|
||||
<form wire:submit="submit">
|
||||
<div class="flex gap-2 pb-1">
|
||||
<h2>Docker Compose</h2>
|
||||
<x-forms.button type="submit">Save</x-forms.button>
|
||||
</div>
|
||||
<x-forms.textarea useMonacoEditor monacoEditorLanguage="yaml" label="Docker Compose file" rows="20" id="dockerComposeRaw" placeholder='services:
|
||||
ghost:
|
||||
documentation: https://ghost.org/docs/config
|
||||
image: ghost:5
|
||||
@ -36,5 +34,5 @@
|
||||
- MYSQL_DATABASE=${MYSQL_DATABASE}
|
||||
- MYSQL_ROOT_PASSWORD=${SERVICE_PASSWORD_MYSQL_ROOT}
|
||||
'></x-forms.textarea>
|
||||
</form>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
File diff suppressed because one or more lines are too long
@ -2,9 +2,9 @@
|
||||
<form wire:submit='submit'>
|
||||
<div class="flex items-center gap-2 pb-4">
|
||||
@if ($application->human_name)
|
||||
<h2>{{ Str::headline($application->human_name) }}</h2>
|
||||
<h2>{{ Str::headline($application->human_name) }}</h2>
|
||||
@else
|
||||
<h2>{{ Str::headline($application->name) }}</h2>
|
||||
<h2>{{ Str::headline($application->name) }}</h2>
|
||||
@endif
|
||||
<x-forms.button type="submit">Save</x-forms.button>
|
||||
<x-modal-confirmation isErrorButton>
|
||||
@ -16,37 +16,26 @@
|
||||
</div>
|
||||
<div class="flex flex-col gap-2">
|
||||
<div class="flex gap-2">
|
||||
<x-forms.input label="Name" id="application.human_name"
|
||||
placeholder="Human readable name"></x-forms.input>
|
||||
<x-forms.input label="Name" id="application.human_name" placeholder="Human readable name"></x-forms.input>
|
||||
<x-forms.input label="Description" id="application.description"></x-forms.input>
|
||||
</div>
|
||||
<div class="flex gap-2">
|
||||
@if (!$application->serviceType()?->contains(str($application->image)->before(':')))
|
||||
@if ($application->required_fqdn)
|
||||
<x-forms.input required placeholder="https://app.coolify.io" label="Domains"
|
||||
id="application.fqdn"
|
||||
helper="You can specify one domain with path or more with comma. You can specify a port to bind the domain to.<br><br><span class='text-helper'>Example</span><br>- http://app.coolify.io,https://cloud.coolify.io/dashboard<br>- http://app.coolify.io/api/v3<br>- http://app.coolify.io:3000 -> app.coolify.io will point to port 3000 inside the container. "></x-forms.input>
|
||||
@else
|
||||
<x-forms.input placeholder="https://app.coolify.io" label="Domains" id="application.fqdn"
|
||||
helper="You can specify one domain with path or more with comma. You can specify a port to bind the domain to.<br><br><span class='text-helper'>Example</span><br>- http://app.coolify.io,https://cloud.coolify.io/dashboard<br>- http://app.coolify.io/api/v3<br>- http://app.coolify.io:3000 -> app.coolify.io will point to port 3000 inside the container. "></x-forms.input>
|
||||
@endif
|
||||
@if ($application->required_fqdn)
|
||||
<x-forms.input required placeholder="https://app.lasthourhosting.org" label="Domains" id="application.fqdn" helper="You can specify one domain with path or more with comma. You can specify a port to bind the domain to.<br><br><span class='text-helper'>Example</span><br>- http://app.lasthourhosting.org,https://cloud.lasthourhosting.org/dashboard<br>- http://app.lasthourhosting.org/api/v3<br>- http://app.lasthourhosting.org:3000 -> app.lasthourhosting.org will point to port 3000 inside the container. "></x-forms.input>
|
||||
@else
|
||||
<x-forms.input placeholder="https://app.lasthourhosting.org" label="Domains" id="application.fqdn" helper="You can specify one domain with path or more with comma. You can specify a port to bind the domain to.<br><br><span class='text-helper'>Example</span><br>- http://app.lasthourhosting.org,https://cloud.lasthourhosting.org/dashboard<br>- http://app.lasthourhosting.org/api/v3<br>- http://app.lasthourhosting.org:3000 -> app.lasthourhosting.org will point to port 3000 inside the container. "></x-forms.input>
|
||||
@endif
|
||||
<x-forms.input required
|
||||
helper="You can change the image you would like to deploy.<br><br><span class='dark:text-warning'>WARNING. You could corrupt your data. Only do it if you know what you are doing.</span>"
|
||||
label="Image" id="application.image"></x-forms.input>
|
||||
@endif
|
||||
<x-forms.input required helper="You can change the image you would like to deploy.<br><br><span class='dark:text-warning'>WARNING. You could corrupt your data. Only do it if you know what you are doing.</span>" label="Image" id="application.image"></x-forms.input>
|
||||
</div>
|
||||
</div>
|
||||
<h3 class="pt-2">Advanced</h3>
|
||||
<div class="w-96">
|
||||
<x-forms.checkbox instantSave id="application.is_gzip_enabled" label="Enable gzip compression"
|
||||
helper="You can disable gzip compression if you want. Some services are compressing data by default. In this case, you do not need this." />
|
||||
<x-forms.checkbox instantSave id="application.is_stripprefix_enabled" label="Strip Prefixes"
|
||||
helper="Strip Prefix is used to remove prefixes from paths. Like /api/ to /api." />
|
||||
<x-forms.checkbox instantSave label="Exclude from service status"
|
||||
helper="If you do not need to monitor this resource, enable. Useful if this service is optional."
|
||||
id="application.exclude_from_status"></x-forms.checkbox>
|
||||
<x-forms.checkbox helper="Drain logs to your configured log drain endpoint in your Server settings."
|
||||
instantSave="instantSaveAdvanced" id="application.is_log_drain_enabled" label="Drain Logs" />
|
||||
<x-forms.checkbox instantSave id="application.is_gzip_enabled" label="Enable gzip compression" helper="You can disable gzip compression if you want. Some services are compressing data by default. In this case, you do not need this." />
|
||||
<x-forms.checkbox instantSave id="application.is_stripprefix_enabled" label="Strip Prefixes" helper="Strip Prefix is used to remove prefixes from paths. Like /api/ to /api." />
|
||||
<x-forms.checkbox instantSave label="Exclude from service status" helper="If you do not need to monitor this resource, enable. Useful if this service is optional." id="application.exclude_from_status"></x-forms.checkbox>
|
||||
<x-forms.checkbox helper="Drain logs to your configured log drain endpoint in your Server settings." instantSave="instantSaveAdvanced" id="application.is_log_drain_enabled" label="Drain Logs" />
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
@ -14,22 +14,17 @@
|
||||
<x-forms.input id="service.description" label="Description" />
|
||||
</div>
|
||||
<div class="w-96">
|
||||
<x-forms.checkbox instantSave id="service.connect_to_docker_network" label="Connect To Predefined Network"
|
||||
helper="By default, you do not reach the Coolify defined networks.<br>Starting a docker compose based resource will have an internal network. <br>If you connect to a Coolify defined network, you maybe need to use different internal DNS names to connect to a resource.<br><br>For more information, check <a class='underline dark:text-white' target='_blank' href='https://coolify.io/docs/knowledge-base/docker/compose#connect-to-predefined-networks'>this</a>." />
|
||||
<x-forms.checkbox instantSave id="service.connect_to_docker_network" label="Connect To Predefined Network" helper="By default, you do not reach the Last Hour Cloud defined networks.<br>Starting a docker compose based resource will have an internal network. <br>If you connect to a Coolify defined network, you maybe need to use different internal DNS names to connect to a resource.<br><br>For more information, check <a class='underline dark:text-white' target='_blank' href='https://coolify.io/docs/knowledge-base/docker/compose#connect-to-predefined-networks'>this</a>." />
|
||||
</div>
|
||||
@if ($fields->count() > 0)
|
||||
<div>
|
||||
<h3>Service Specific Configuration</h3>
|
||||
</div>
|
||||
<div class="grid grid-cols-2 gap-2">
|
||||
@foreach ($fields as $serviceName => $field)
|
||||
<div class="flex items-center gap-2"><span
|
||||
class="font-bold">{{ data_get($field, 'serviceName') }}</span>{{ data_get($field, 'name') }}<x-helper
|
||||
helper="Variable name: {{ $serviceName }}" /></div>
|
||||
<x-forms.input type="{{ data_get($field, 'isPassword') ? 'password' : 'text' }}"
|
||||
required="{{ str(data_get($field, 'rules'))?->contains('required') }}"
|
||||
id="fields.{{ $serviceName }}.value"></x-forms.input>
|
||||
@endforeach
|
||||
</div>
|
||||
<div>
|
||||
<h3>Service Specific Configuration</h3>
|
||||
</div>
|
||||
<div class="grid grid-cols-2 gap-2">
|
||||
@foreach ($fields as $serviceName => $field)
|
||||
<div class="flex items-center gap-2"><span class="font-bold">{{ data_get($field, 'serviceName') }}</span>{{ data_get($field, 'name') }}<x-helper helper="Variable name: {{ $serviceName }}" /></div>
|
||||
<x-forms.input type="{{ data_get($field, 'isPassword') ? 'password' : 'text' }}" required="{{ str(data_get($field, 'rules'))?->contains('required') }}" id="fields.{{ $serviceName }}.value"></x-forms.input>
|
||||
@endforeach
|
||||
</div>
|
||||
@endif
|
||||
</form>
|
||||
</form>
|
@ -1,56 +1,44 @@
|
||||
<div class="flex flex-col gap-2">
|
||||
<div class="flex items-center gap-2">
|
||||
<h2>Webhooks</h2>
|
||||
<x-helper
|
||||
helper="For more details goto our <a class='underline dark:text-white' href='https://coolify.io/docs/api-reference/deploy-webhook' target='_blank'>docs</a>." />
|
||||
<x-helper helper="For more details goto our <a class='underline dark:text-white' href='https://coolify.io/docs/api-reference/deploy-webhook' target='_blank'>docs</a>." />
|
||||
</div>
|
||||
<div>
|
||||
<x-forms.input readonly
|
||||
helper="See details in our <a target='_blank' class='underline dark:text-white' href='https://coolify.io/docs/api-reference/deploy-webhook'>documentation</a>."
|
||||
label="Deploy Webhook (auth required)" id="deploywebhook"></x-forms.input>
|
||||
<x-forms.input readonly helper="See details in our <a target='_blank' class='underline dark:text-white' href='https://coolify.io/docs/api-reference/deploy-webhook'>documentation</a>." label="Deploy Webhook (auth required)" id="deploywebhook"></x-forms.input>
|
||||
</div>
|
||||
@if ($resource->type() === 'application')
|
||||
<div>
|
||||
<h3>Manual Git Webhooks</h3>
|
||||
@if ($githubManualWebhook && $gitlabManualWebhook)
|
||||
<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="githubManualWebhookSecret"></x-forms.input>
|
||||
<div>
|
||||
<h3>Manual Git Webhooks</h3>
|
||||
@if ($githubManualWebhook && $gitlabManualWebhook)
|
||||
<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="githubManualWebhookSecret"></x-forms.input>
|
||||
|
||||
</div>
|
||||
<a target="_blank" class="flex hover:no-underline" href="{{ $resource?->gitWebhook }}">
|
||||
<x-forms.button>Webhook Configuration on GitHub
|
||||
<x-external-link />
|
||||
</x-forms.button>
|
||||
</a>
|
||||
<div class="flex gap-2">
|
||||
<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="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="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="giteaManualWebhookSecret"></x-forms.input>
|
||||
</div>
|
||||
<x-forms.button type="submit">Save</x-forms.button>
|
||||
</form>
|
||||
@else
|
||||
You are using an official Git App. You do not need manual webhooks.
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
<a target="_blank" class="flex hover:no-underline" href="{{ $resource?->gitWebhook }}">
|
||||
<x-forms.button>Webhook Configuration on GitHub
|
||||
<x-external-link />
|
||||
</x-forms.button>
|
||||
</a>
|
||||
<div class="flex gap-2">
|
||||
<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="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="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="giteaManualWebhookSecret"></x-forms.input>
|
||||
</div>
|
||||
<x-forms.button type="submit">Save</x-forms.button>
|
||||
</form>
|
||||
@else
|
||||
You are using an official Git App. You do not need manual webhooks.
|
||||
@endif
|
||||
</div>
|
||||
@endif
|
||||
|
||||
</div>
|
||||
</div>
|
48
resources/views/livewire/realtime-connection.blade.php
Normal file
48
resources/views/livewire/realtime-connection.blade.php
Normal file
@ -0,0 +1,48 @@
|
||||
<div x-data="{ showNotification: @entangle('showNotification') }">
|
||||
@if ($checkConnection)
|
||||
@script
|
||||
<script>
|
||||
let checkPusherInterval = null;
|
||||
let checkNumber = 0;
|
||||
checkPusherInterval = setInterval(() => {
|
||||
if (window.Echo) {
|
||||
if (window.Echo.connector.pusher.connection.state !== 'connected') {
|
||||
checkNumber++;
|
||||
if (checkNumber > 4) {
|
||||
@if ($isNotificationEnabled)
|
||||
$wire.showNotification = true;
|
||||
@endif
|
||||
console.error(
|
||||
'Last Hour Cloud could not connect to the new realtime service introduced in beta.154. This will cause unusual problems on the UI if not fixed! Please check the related upstream documentation (https://coolify.io/docs/cloudflare/tunnels) or get help on Discord (https://coollabs.io/discord).)'
|
||||
);
|
||||
clearInterval(checkPusherInterval);
|
||||
}
|
||||
} else {
|
||||
console.log('Last Hour Cloud Realtime Service is connected!');
|
||||
clearInterval(checkPusherInterval);
|
||||
}
|
||||
} else {
|
||||
@if ($isNotificationEnabled)
|
||||
$wire.showNotification = true;
|
||||
@endif
|
||||
console.error(
|
||||
'Last Hour Cloud could not connect to the new realtime service introduced in beta.154. This will cause unusual problems on the UI if not fixed! Please check the related upstream documentation (https://coolify.io/docs/cloudflare/tunnels) or get help on Discord (https://coollabs.io/discord).)'
|
||||
);
|
||||
clearInterval(checkPusherInterval);
|
||||
}
|
||||
}, 1000);
|
||||
</script>
|
||||
@endscript
|
||||
<div class="toast z-[9999]" x-cloak x-show="showNotification">
|
||||
<div class="flex flex-col text-white border border-red-500 border-dashed rounded alert bg-coolgray-200">
|
||||
<span><span class="font-bold text-left text-red-500">WARNING: </span>Last Hour Cloud could not connect to the new
|
||||
realtime service introduced in beta.154. <br>This will cause unusual problems on the UI if not
|
||||
fixed!<br><br>Please check the
|
||||
related upstream <a href='https://coolify.io/docs/cloudflare/tunnels' target='_blank'>documentation</a> or get
|
||||
help on <a href='https://coollabs.io/discord' target='_blank'>Discord</a>.</span>
|
||||
<x-forms.button class="bg-coolgray-400" wire:click='disable'>Acknowledge the problem and disable this
|
||||
popup</x-forms.button>
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
@ -1,9 +1,9 @@
|
||||
<div>
|
||||
@if ($server->id !== 0)
|
||||
<h2 class="pt-4">Danger Zone</h2>
|
||||
<div class="">Woah. I hope you know what are you doing.</div>
|
||||
<div class="">Wait a minute, We hope you know what are you doing.</div>
|
||||
<h4 class="pt-4">Delete Server</h4>
|
||||
<div class="pb-4">This will remove this server from Coolify. Beware! There is no coming
|
||||
<div class="pb-4">This will remove this server from Last Hour Cloud. Beware! There is no coming
|
||||
back!
|
||||
</div>
|
||||
@if ($server->definedResources()->count() > 0)
|
||||
|
@ -3,73 +3,68 @@
|
||||
<div class="flex gap-2">
|
||||
<h2>General</h2>
|
||||
@if ($server->id === 0)
|
||||
<x-modal-confirmation buttonTitle="Save" title="Change Localhost" action="submit">
|
||||
You could lose a lot of functionalities if you change the server details of the server where Coolify
|
||||
is
|
||||
running on.<br>Please think again.
|
||||
</x-modal-confirmation>
|
||||
<x-modal-confirmation buttonTitle="Save" title="Change Localhost" action="submit">
|
||||
You could lose a lot of functionalities if you change the server details of the server where Last Hour Cloud
|
||||
is
|
||||
running on.<br>Please think again.
|
||||
</x-modal-confirmation>
|
||||
@else
|
||||
<x-forms.button type="submit">Save</x-forms.button>
|
||||
@if ($server->isFunctional())
|
||||
<x-slide-over closeWithX fullScreen>
|
||||
<x-slot:title>Validate & configure</x-slot:title>
|
||||
<x-slot:content>
|
||||
<livewire:server.validate-and-install :server="$server" ask />
|
||||
</x-slot:content>
|
||||
<x-forms.button @click="slideOverOpen=true" wire:click.prevent='validateServer' isHighlighted>
|
||||
Revalidate server
|
||||
</x-forms.button>
|
||||
</x-slide-over>
|
||||
@endif
|
||||
@endif
|
||||
</div>
|
||||
@if ($server->isFunctional())
|
||||
Server is reachable and validated.
|
||||
@else
|
||||
You can't use this server until it is validated.
|
||||
@endif
|
||||
@if ((!$server->settings->is_reachable || !$server->settings->is_usable) && $server->id !== 0)
|
||||
<x-forms.button type="submit">Save</x-forms.button>
|
||||
@if ($server->isFunctional())
|
||||
<x-slide-over closeWithX fullScreen>
|
||||
<x-slot:title>Validate & configure</x-slot:title>
|
||||
<x-slot:content>
|
||||
<livewire:server.validate-and-install :server="$server" />
|
||||
<livewire:server.validate-and-install :server="$server" ask />
|
||||
</x-slot:content>
|
||||
<x-forms.button @click="slideOverOpen=true"
|
||||
class="w-full mt-8 mb-4 font-bold box-without-bg bg-coollabs hover:bg-coollabs-100"
|
||||
wire:click.prevent='validateServer' isHighlighted>
|
||||
Validate Server & Install Docker Engine
|
||||
<x-forms.button @click="slideOverOpen=true" wire:click.prevent='validateServer' isHighlighted>
|
||||
Revalidate server
|
||||
</x-forms.button>
|
||||
</x-slide-over>
|
||||
@if ($server->validation_logs)
|
||||
<h4>Previous Validation Logs</h4>
|
||||
<div class="pb-8">
|
||||
{!! $server->validation_logs !!}
|
||||
</div>
|
||||
@endif
|
||||
@endif
|
||||
</div>
|
||||
@if ($server->isFunctional())
|
||||
Server is reachable and validated.
|
||||
@else
|
||||
You can't use this server until it is validated.
|
||||
@endif
|
||||
@if ((!$server->settings->is_reachable || !$server->settings->is_usable) && $server->id !== 0)
|
||||
<x-slide-over closeWithX fullScreen>
|
||||
<x-slot:title>Validate & configure</x-slot:title>
|
||||
<x-slot:content>
|
||||
<livewire:server.validate-and-install :server="$server" />
|
||||
</x-slot:content>
|
||||
<x-forms.button @click="slideOverOpen=true" class="w-full mt-8 mb-4 font-bold box-without-bg bg-coollabs hover:bg-coollabs-100" wire:click.prevent='validateServer' isHighlighted>
|
||||
Validate Server & Install Docker Engine
|
||||
</x-forms.button>
|
||||
</x-slide-over>
|
||||
@if ($server->validation_logs)
|
||||
<h4>Previous Validation Logs</h4>
|
||||
<div class="pb-8">
|
||||
{!! $server->validation_logs !!}
|
||||
</div>
|
||||
@endif
|
||||
@endif
|
||||
@if ((!$server->settings->is_reachable || !$server->settings->is_usable) && $server->id === 0)
|
||||
<x-forms.button class="mt-8 mb-4 font-bold box-without-bg bg-coollabs hover:bg-coollabs-100"
|
||||
wire:click.prevent='checkLocalhostConnection' isHighlighted>
|
||||
Validate Server
|
||||
</x-forms.button>
|
||||
<x-forms.button class="mt-8 mb-4 font-bold box-without-bg bg-coollabs hover:bg-coollabs-100" wire:click.prevent='checkLocalhostConnection' isHighlighted>
|
||||
Validate Server
|
||||
</x-forms.button>
|
||||
@endif
|
||||
@if ($server->isForceDisabled() && isCloud())
|
||||
<div class="pt-4 font-bold text-red-500">The system has disabled the server because you have exceeded the
|
||||
number of servers for which you have paid.</div>
|
||||
<div class="pt-4 font-bold text-red-500">The system has disabled the server because you have exceeded the
|
||||
number of servers for which you have paid.</div>
|
||||
@endif
|
||||
<div class="flex flex-col gap-2 pt-4">
|
||||
<div class="flex flex-col w-full gap-2 lg:flex-row">
|
||||
<x-forms.input id="server.name" label="Name" required />
|
||||
<x-forms.input id="server.description" label="Description" />
|
||||
@if (!$server->settings->is_swarm_worker && !$server->settings->is_build_server)
|
||||
<x-forms.input placeholder="https://example.com" id="wildcard_domain" label="Wildcard Domain"
|
||||
helper='A wildcard domain allows you to receive a randomly generated domain for your new applications. <br><br>For instance, if you set "https://example.com" as your wildcard domain, your applications will receive domains like "https://randomId.example.com".' />
|
||||
<x-forms.input placeholder="https://example.com" id="wildcard_domain" label="Wildcard Domain" helper='A wildcard domain allows you to receive a randomly generated domain for your new applications. <br><br>For instance, if you set "https://example.com" as your wildcard domain, your applications will receive domains like "https://randomId.example.com".' />
|
||||
@endif
|
||||
|
||||
</div>
|
||||
<div class="flex flex-col w-full gap-2 lg:flex-row">
|
||||
<x-forms.input id="server.ip" label="IP Address/Domain"
|
||||
helper="An IP Address (127.0.0.1) or domain (example.com)." required />
|
||||
<x-forms.input id="server.ip" label="IP Address/Domain" helper="An IP Address (127.0.0.1) or domain (example.com)." required />
|
||||
<div class="flex gap-2">
|
||||
<x-forms.input id="server.user" label="User" required />
|
||||
<x-forms.input type="number" id="server.port" label="Port" required />
|
||||
@ -77,106 +72,83 @@
|
||||
</div>
|
||||
<div class="w-64">
|
||||
@if ($server->isFunctional())
|
||||
@if (!$server->isLocalhost())
|
||||
<x-forms.checkbox instantSave id="server.settings.is_build_server"
|
||||
label="Use it as a build server?" />
|
||||
<div class="flex items-center gap-1 pt-6">
|
||||
<h3 class="">Cloudflare Tunnels
|
||||
</h3>
|
||||
<x-helper class="inline-flex"
|
||||
helper="If you are using Cloudflare Tunnels, enable this. It will proxy all SSH requests to your server through Cloudflare.<br><span class='dark:text-warning'>Coolify does not install or set up Cloudflare (cloudflared) on your server.</span>" />
|
||||
</div>
|
||||
@if ($server->settings->is_cloudflare_tunnel)
|
||||
<x-forms.checkbox instantSave id="server.settings.is_cloudflare_tunnel" label="Enabled" />
|
||||
@else
|
||||
<x-modal-input buttonTitle="Configure" title="Cloudflare Tunnels">
|
||||
<livewire:server.configure-cloudflare-tunnels :server_id="$server->id" />
|
||||
</x-modal-input>
|
||||
@endif
|
||||
@if (!$server->isBuildServer())
|
||||
<h3 class="pt-6">Swarm <span class="text-xs text-neutral-500">(experimental)</span></h3>
|
||||
<div class="pb-4">Read the docs <a class='underline dark:text-white'
|
||||
href='https://coolify.io/docs/knowledge-base/docker/swarm' target='_blank'>here</a>.
|
||||
</div>
|
||||
@if ($server->settings->is_swarm_worker)
|
||||
<x-forms.checkbox disabled instantSave type="checkbox"
|
||||
id="server.settings.is_swarm_manager"
|
||||
helper="For more information, please read the documentation <a class='dark:text-white' href='https://coolify.io/docs/knowledge-base/docker/swarm' target='_blank'>here</a>."
|
||||
label="Is it a Swarm Manager?" />
|
||||
@else
|
||||
<x-forms.checkbox instantSave type="checkbox" id="server.settings.is_swarm_manager"
|
||||
helper="For more information, please read the documentation <a class='dark:text-white' href='https://coolify.io/docs/knowledge-base/docker/swarm' target='_blank'>here</a>."
|
||||
label="Is it a Swarm Manager?" />
|
||||
@endif
|
||||
|
||||
@if ($server->settings->is_swarm_manager)
|
||||
<x-forms.checkbox disabled instantSave type="checkbox"
|
||||
id="server.settings.is_swarm_worker"
|
||||
helper="For more information, please read the documentation <a class='dark:text-white' href='https://coolify.io/docs/knowledge-base/docker/swarm' target='_blank'>here</a>."
|
||||
label="Is it a Swarm Worker?" />
|
||||
@else
|
||||
<x-forms.checkbox instantSave type="checkbox" id="server.settings.is_swarm_worker"
|
||||
helper="For more information, please read the documentation <a class='dark:text-white' href='https://coolify.io/docs/knowledge-base/docker/swarm' target='_blank'>here</a>."
|
||||
label="Is it a Swarm Worker?" />
|
||||
@endif
|
||||
@endif
|
||||
@endif
|
||||
@if (!$server->isLocalhost())
|
||||
<x-forms.checkbox instantSave id="server.settings.is_build_server" label="Use it as a build server?" />
|
||||
<div class="flex items-center gap-1 pt-6">
|
||||
<h3 class="">Cloudflare Tunnels
|
||||
</h3>
|
||||
<x-helper class="inline-flex" helper="If you are using Cloudflare Tunnels, enable this. It will proxy all SSH requests to your server through Cloudflare.<br><span class='dark:text-warning'>Last Hour Cloud does not install or set up Cloudflare (cloudflared) on your server.</span>" />
|
||||
</div>
|
||||
@if ($server->settings->is_cloudflare_tunnel)
|
||||
<x-forms.checkbox instantSave id="server.settings.is_cloudflare_tunnel" label="Enabled" />
|
||||
@else
|
||||
<div class="flex items-center gap-1 pt-6">
|
||||
<h3 class="">Cloudflare Tunnels
|
||||
</h3>
|
||||
<x-helper class="inline-flex"
|
||||
helper="If you are using Cloudflare Tunnels, enable this. It will proxy all SSH requests to your server through Cloudflare.<br><span class='dark:text-warning'>Coolify does not install or set up Cloudflare (cloudflared) on your server.</span>" />
|
||||
</div>
|
||||
@if ($server->settings->is_cloudflare_tunnel)
|
||||
<x-forms.checkbox instantSave id="server.settings.is_cloudflare_tunnel" label="Enabled" />
|
||||
@else
|
||||
<x-modal-input buttonTitle="Configure" title="Cloudflare Tunnels">
|
||||
<livewire:server.configure-cloudflare-tunnels :server_id="$server->id" />
|
||||
</x-modal-input>
|
||||
@endif
|
||||
<x-modal-input buttonTitle="Configure" title="Cloudflare Tunnels">
|
||||
<livewire:server.configure-cloudflare-tunnels :server_id="$server->id" />
|
||||
</x-modal-input>
|
||||
@endif
|
||||
@if (!$server->isBuildServer())
|
||||
<h3 class="pt-6">Swarm <span class="text-xs text-neutral-500">(experimental)</span></h3>
|
||||
<div class="pb-4">Read the docs <a class='underline dark:text-white' href='https://coolify.io/docs/knowledge-base/docker/swarm' target='_blank'>here</a>.
|
||||
</div>
|
||||
@if ($server->settings->is_swarm_worker)
|
||||
<x-forms.checkbox disabled instantSave type="checkbox" id="server.settings.is_swarm_manager" helper="For more information, please read the documentation <a class='dark:text-white' href='https://coolify.io/docs/knowledge-base/docker/swarm' target='_blank'>here</a>." label="Is it a Swarm Manager?" />
|
||||
@else
|
||||
<x-forms.checkbox instantSave type="checkbox" id="server.settings.is_swarm_manager" helper="For more information, please read the documentation <a class='dark:text-white' href='https://coolify.io/docs/knowledge-base/docker/swarm' target='_blank'>here</a>." label="Is it a Swarm Manager?" />
|
||||
@endif
|
||||
|
||||
@if ($server->settings->is_swarm_manager)
|
||||
<x-forms.checkbox disabled instantSave type="checkbox" id="server.settings.is_swarm_worker" helper="For more information, please read the documentation <a class='dark:text-white' href='https://coolify.io/docs/knowledge-base/docker/swarm' target='_blank'>here</a>." label="Is it a Swarm Worker?" />
|
||||
@else
|
||||
<x-forms.checkbox instantSave type="checkbox" id="server.settings.is_swarm_worker" helper="For more information, please read the documentation <a class='dark:text-white' href='https://coolify.io/docs/knowledge-base/docker/swarm' target='_blank'>here</a>." label="Is it a Swarm Worker?" />
|
||||
@endif
|
||||
@endif
|
||||
@endif
|
||||
@else
|
||||
<div class="flex items-center gap-1 pt-6">
|
||||
<h3 class="">Cloudflare Tunnels
|
||||
</h3>
|
||||
<x-helper class="inline-flex" helper="If you are using Cloudflare Tunnels, enable this. It will proxy all SSH requests to your server through Cloudflare.<br><span class='dark:text-warning'>Coolify does not install or set up Cloudflare (cloudflared) on your server.</span>" />
|
||||
</div>
|
||||
@if ($server->settings->is_cloudflare_tunnel)
|
||||
<x-forms.checkbox instantSave id="server.settings.is_cloudflare_tunnel" label="Enabled" />
|
||||
@else
|
||||
<x-modal-input buttonTitle="Configure" title="Cloudflare Tunnels">
|
||||
<livewire:server.configure-cloudflare-tunnels :server_id="$server->id" />
|
||||
</x-modal-input>
|
||||
@endif
|
||||
@endif
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@if ($server->isFunctional())
|
||||
<h3 class="pt-4">Settings</h3>
|
||||
<div class="flex flex-col gap-2">
|
||||
<div class="flex flex-col flex-wrap gap-2 sm:flex-nowrap">
|
||||
@if ($server->settings->is_force_cleanup_enabled)
|
||||
<div class="w-64">
|
||||
<x-forms.checkbox
|
||||
helper="This will cleanup build caches / unused images / etc every 10 minutes."
|
||||
instantSave id="server.settings.is_force_cleanup_enabled"
|
||||
label="Force Cleanup Docker Engine" />
|
||||
</div>
|
||||
@else
|
||||
<x-forms.input id="cleanup_after_percentage" label="Disk cleanup threshold (%)" required
|
||||
helper="The disk cleanup task will run when the disk usage exceeds this threshold." />
|
||||
<div class="w-64">
|
||||
<x-forms.checkbox
|
||||
helper="This will cleanup build caches / unused images / etc every 10 minutes."
|
||||
instantSave id="server.settings.is_force_cleanup_enabled"
|
||||
label="Force Cleanup Docker Engine" />
|
||||
</div>
|
||||
@endif
|
||||
<h3 class="pt-4">Settings</h3>
|
||||
<div class="flex flex-col gap-2">
|
||||
<div class="flex flex-col flex-wrap gap-2 sm:flex-nowrap">
|
||||
@if ($server->settings->is_force_cleanup_enabled)
|
||||
<div class="w-64">
|
||||
<x-forms.checkbox helper="This will cleanup build caches / unused images / etc every 10 minutes." instantSave id="server.settings.is_force_cleanup_enabled" label="Force Cleanup Docker Engine" />
|
||||
</div>
|
||||
<div class="flex flex-wrap gap-2 sm:flex-nowrap">
|
||||
<x-forms.input id="server.settings.concurrent_builds" label="Number of concurrent builds" required
|
||||
helper="You can specify the number of simultaneous build processes/deployments that should run concurrently." />
|
||||
<x-forms.input id="server.settings.dynamic_timeout" label="Deployment timeout (seconds)" required
|
||||
helper="You can define the maximum duration for a deployment to run before timing it out." />
|
||||
@else
|
||||
<x-forms.input id="cleanup_after_percentage" label="Disk cleanup threshold (%)" required helper="The disk cleanup task will run when the disk usage exceeds this threshold." />
|
||||
<div class="w-64">
|
||||
<x-forms.checkbox helper="This will cleanup build caches / unused images / etc every 10 minutes." instantSave id="server.settings.is_force_cleanup_enabled" label="Force Cleanup Docker Engine" />
|
||||
</div>
|
||||
@endif
|
||||
</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 --}}
|
||||
<div class="flex flex-wrap gap-2 sm:flex-nowrap">
|
||||
<x-forms.input id="server.settings.concurrent_builds" label="Number of concurrent builds" required helper="You can specify the number of simultaneous build processes/deployments that should run concurrently." />
|
||||
<x-forms.input id="server.settings.dynamic_timeout" label="Deployment timeout (seconds)" required helper="You can define the maximum duration for a deployment to run before timing it out." />
|
||||
</div>
|
||||
<div>Metrics are disabled until a few bugs are fixed.</div>
|
||||
{{-- <div class="w-64">
|
||||
</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 --}}
|
||||
</div>
|
||||
<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" />
|
||||
</div>
|
||||
<div class="pt-4">
|
||||
@ -192,4 +164,4 @@
|
||||
</div> --}}
|
||||
@endif
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
@ -35,7 +35,7 @@
|
||||
&
|
||||
@endif
|
||||
@if (!$server->settings->is_usable)
|
||||
<span>Not usable by Coolify</span>
|
||||
<span>Not usable by Last Hour Cloud</span>
|
||||
@endif
|
||||
@if ($server->settings->force_disabled)
|
||||
<span>Disabled by the system</span>
|
||||
|
@ -1,73 +1,61 @@
|
||||
<div class="w-full">
|
||||
@if ($limit_reached)
|
||||
<x-limit-reached name="servers" />
|
||||
<x-limit-reached name="servers" />
|
||||
@else
|
||||
<form class="flex flex-col w-full gap-2" wire:submit='submit'>
|
||||
<div class="flex w-full gap-2 flex-wrap sm:flex-nowrap">
|
||||
<x-forms.input autofocus id="name" label="Name" required />
|
||||
<x-forms.input id="description" label="Description" />
|
||||
</div>
|
||||
<div class="flex gap-2 flex-wrap sm:flex-nowrap">
|
||||
<x-forms.input id="ip" label="IP Address/Domain" required
|
||||
helper="An IP Address (127.0.0.1) or domain (example.com)." />
|
||||
<x-forms.input type="number" id="port" label="Port" required />
|
||||
</div>
|
||||
<x-forms.input id="user" label="User" required />
|
||||
<div class="text-xs dark:text-warning text-coollabs ">Non-root user is experimental: <a
|
||||
class="font-bold underline" target="_blank"
|
||||
href="https://coolify.io/docs/knowledge-base/server/non-root-user">docs</a>.</div>
|
||||
<x-forms.select label="Private Key" id="private_key_id">
|
||||
<option disabled>Select a private key</option>
|
||||
@foreach ($private_keys as $key)
|
||||
<form class="flex flex-col w-full gap-2" wire:submit='submit'>
|
||||
<div class="flex w-full gap-2 flex-wrap sm:flex-nowrap">
|
||||
<x-forms.input autofocus id="name" label="Name" required />
|
||||
<x-forms.input id="description" label="Description" />
|
||||
</div>
|
||||
<div class="flex gap-2 flex-wrap sm:flex-nowrap">
|
||||
<x-forms.input id="ip" label="IP Address/Domain" required helper="An IP Address (127.0.0.1) or domain (example.com)." />
|
||||
<x-forms.input type="number" id="port" label="Port" required />
|
||||
</div>
|
||||
<x-forms.input id="user" label="User" required />
|
||||
<div class="text-xs dark:text-warning text-coollabs ">Non-root user is experimental: <a class="font-bold underline" target="_blank" href="https://coolify.io/docs/knowledge-base/server/non-root-user">docs</a>.</div>
|
||||
<x-forms.select label="Private Key" id="private_key_id">
|
||||
<option disabled>Select a private key</option>
|
||||
@foreach ($private_keys as $key)
|
||||
@if ($loop->first)
|
||||
<option selected value="{{ $key->id }}">{{ $key->name }}</option>
|
||||
@else
|
||||
<option value="{{ $key->id }}">{{ $key->name }}</option>
|
||||
@endif
|
||||
@endforeach
|
||||
</x-forms.select>
|
||||
<div class="">
|
||||
<x-forms.checkbox instantSave type="checkbox" id="is_build_server" label="Use it as a build server?" />
|
||||
</div>
|
||||
<div class="">
|
||||
<h3 class="pt-6">Swarm <span class="text-xs text-neutral-500">(experimental)</span></h3>
|
||||
<div class="pb-4">Read the docs <a class='dark:text-white' href='https://coolify.io/docs/knowledge-base/docker/swarm' target='_blank'>here</a>.</div>
|
||||
@if ($is_swarm_worker || $is_build_server)
|
||||
<x-forms.checkbox disabled instantSave type="checkbox" id="is_swarm_manager" helper="For more information, please read the documentation <a class='dark:text-white' href='https://coolify.io/docs/knowledge-base/docker/swarm' target='_blank'>here</a>." label="Is it a Swarm Manager?" />
|
||||
@else
|
||||
<x-forms.checkbox type="checkbox" instantSave id="is_swarm_manager" helper="For more information, please read the documentation <a class='dark:text-white' href='https://coolify.io/docs/knowledge-base/docker/swarm' target='_blank'>here</a>." label="Is it a Swarm Manager?" />
|
||||
@endif
|
||||
@if ($is_swarm_manager || $is_build_server)
|
||||
<x-forms.checkbox disabled instantSave type="checkbox" id="is_swarm_worker" helper="For more information, please read the documentation <a class='dark:text-white' href='https://coolify.io/docs/knowledge-base/docker/swarm' target='_blank'>here</a>." label="Is it a Swarm Worker?" />
|
||||
@else
|
||||
<x-forms.checkbox type="checkbox" instantSave id="is_swarm_worker" helper="For more information, please read the documentation <a class='dark:text-white' href='https://coolify.io/docs/knowledge-base/docker/swarm' target='_blank'>here</a>." label="Is it a Swarm Worker?" />
|
||||
@endif
|
||||
@if ($is_swarm_worker && count($swarm_managers) > 0)
|
||||
<div class="py-4">
|
||||
<x-forms.select label="Select a Swarm Cluster" id="selected_swarm_cluster" required>
|
||||
@foreach ($swarm_managers as $server)
|
||||
@if ($loop->first)
|
||||
<option selected value="{{ $key->id }}">{{ $key->name }}</option>
|
||||
<option selected value="{{ $server->id }}">{{ $server->name }}</option>
|
||||
@else
|
||||
<option value="{{ $key->id }}">{{ $key->name }}</option>
|
||||
<option value="{{ $server->id }}">{{ $server->name }}</option>
|
||||
@endif
|
||||
@endforeach
|
||||
</x-forms.select>
|
||||
<div class="">
|
||||
<x-forms.checkbox instantSave type="checkbox" id="is_build_server" label="Use it as a build server?" />
|
||||
@endforeach
|
||||
</x-forms.select>
|
||||
</div>
|
||||
<div class="">
|
||||
<h3 class="pt-6">Swarm <span class="text-xs text-neutral-500">(experimental)</span></h3>
|
||||
<div class="pb-4">Read the docs <a class='dark:text-white'
|
||||
href='https://coolify.io/docs/knowledge-base/docker/swarm' target='_blank'>here</a>.</div>
|
||||
@if ($is_swarm_worker || $is_build_server)
|
||||
<x-forms.checkbox disabled instantSave type="checkbox" id="is_swarm_manager"
|
||||
helper="For more information, please read the documentation <a class='dark:text-white' href='https://coolify.io/docs/knowledge-base/docker/swarm' target='_blank'>here</a>."
|
||||
label="Is it a Swarm Manager?" />
|
||||
@else
|
||||
<x-forms.checkbox type="checkbox" instantSave id="is_swarm_manager"
|
||||
helper="For more information, please read the documentation <a class='dark:text-white' href='https://coolify.io/docs/knowledge-base/docker/swarm' target='_blank'>here</a>."
|
||||
label="Is it a Swarm Manager?" />
|
||||
@endif
|
||||
@if ($is_swarm_manager || $is_build_server)
|
||||
<x-forms.checkbox disabled instantSave type="checkbox" id="is_swarm_worker"
|
||||
helper="For more information, please read the documentation <a class='dark:text-white' href='https://coolify.io/docs/knowledge-base/docker/swarm' target='_blank'>here</a>."
|
||||
label="Is it a Swarm Worker?" />
|
||||
@else
|
||||
<x-forms.checkbox type="checkbox" instantSave id="is_swarm_worker"
|
||||
helper="For more information, please read the documentation <a class='dark:text-white' href='https://coolify.io/docs/knowledge-base/docker/swarm' target='_blank'>here</a>."
|
||||
label="Is it a Swarm Worker?" />
|
||||
@endif
|
||||
@if ($is_swarm_worker && count($swarm_managers) > 0)
|
||||
<div class="py-4">
|
||||
<x-forms.select label="Select a Swarm Cluster" id="selected_swarm_cluster" required>
|
||||
@foreach ($swarm_managers as $server)
|
||||
@if ($loop->first)
|
||||
<option selected value="{{ $server->id }}">{{ $server->name }}</option>
|
||||
@else
|
||||
<option value="{{ $server->id }}">{{ $server->name }}</option>
|
||||
@endif
|
||||
@endforeach
|
||||
</x-forms.select>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
<x-forms.button type="submit">
|
||||
Continue
|
||||
</x-forms.button>
|
||||
</form>
|
||||
@endif
|
||||
</div>
|
||||
<x-forms.button type="submit">
|
||||
Continue
|
||||
</x-forms.button>
|
||||
</form>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
@ -32,7 +32,7 @@
|
||||
configurations.
|
||||
</div>
|
||||
@endif
|
||||
<x-forms.input placeholder="https://app.coolify.io" id="redirect_url" label="Default Redirect 404"
|
||||
<x-forms.input placeholder="https://lasthourhosting.org" id="redirect_url" label="Default Redirect 404"
|
||||
helper="All urls that has no service available will be redirected to this domain." />
|
||||
<div wire:loading wire:target="loadProxyConfiguration" class="pt-4">
|
||||
<x-loading text="Loading proxy configuration..." />
|
||||
|
@ -1,25 +1,23 @@
|
||||
<div>
|
||||
<x-slot:title>
|
||||
{{ data_get_str($server, 'name')->limit(10) }} > Server Resources | Coolify
|
||||
</x-slot>
|
||||
<x-server.navbar :server="$server" :parameters="$parameters" />
|
||||
<div x-data="{ activeTab: window.location.hash ? window.location.hash.substring(1) : 'managed' }" class="flex flex-col h-full gap-8 md:flex-row">
|
||||
<div class="flex flex-row gap-4 md:flex-col">
|
||||
<a :class="activeTab === 'managed' && 'dark:text-white'"
|
||||
@click.prevent="activeTab = 'managed'; window.location.hash = 'managed'" href="#">Managed</a>
|
||||
<a :class="activeTab === 'unmanaged' && 'dark:text-white'"
|
||||
@click.prevent="activeTab = 'unmanaged'; window.location.hash = 'unmanaged'" href="#">Unmanaged</a>
|
||||
</div>
|
||||
<div class="w-full">
|
||||
<div x-cloak x-show="activeTab === 'managed'" class="h-full">
|
||||
<div class="flex flex-col">
|
||||
<div class="flex gap-2">
|
||||
<h2>Resources</h2>
|
||||
<x-forms.button wire:click="refreshStatus">Refresh</x-forms.button>
|
||||
</x-slot>
|
||||
<x-server.navbar :server="$server" :parameters="$parameters" />
|
||||
<div x-data="{ activeTab: window.location.hash ? window.location.hash.substring(1) : 'managed' }" class="flex flex-col h-full gap-8 md:flex-row">
|
||||
<div class="flex flex-row gap-4 md:flex-col">
|
||||
<a :class="activeTab === 'managed' && 'dark:text-white'" @click.prevent="activeTab = 'managed'; window.location.hash = 'managed'" href="#">Managed</a>
|
||||
<a :class="activeTab === 'unmanaged' && 'dark:text-white'" @click.prevent="activeTab = 'unmanaged'; window.location.hash = 'unmanaged'" href="#">Unmanaged</a>
|
||||
</div>
|
||||
<div class="w-full">
|
||||
<div x-cloak x-show="activeTab === 'managed'" class="h-full">
|
||||
<div class="flex flex-col">
|
||||
<div class="flex gap-2">
|
||||
<h2>Resources</h2>
|
||||
<x-forms.button wire:click="refreshStatus">Refresh</x-forms.button>
|
||||
</div>
|
||||
<div class="subtitle">Here you can find all resources that are managed by Last Hour Cloud.</div>
|
||||
</div>
|
||||
<div class="subtitle">Here you can find all resources that are managed by Coolify.</div>
|
||||
</div>
|
||||
@if ($server->definedResources()->count() > 0)
|
||||
@if ($server->definedResources()->count() > 0)
|
||||
<div class="flex flex-col">
|
||||
<div class="flex flex-col">
|
||||
<div class="overflow-x-auto">
|
||||
@ -46,29 +44,28 @@
|
||||
</thead>
|
||||
<tbody>
|
||||
@forelse ($server->definedResources()->sortBy('name',SORT_NATURAL) as $resource)
|
||||
<tr>
|
||||
<td class="px-5 py-4 text-sm whitespace-nowrap">
|
||||
{{ data_get($resource->project(), 'name') }}
|
||||
</td>
|
||||
<td class="px-5 py-4 text-sm whitespace-nowrap">
|
||||
{{ data_get($resource, 'environment.name') }}
|
||||
</td>
|
||||
<td class="px-5 py-4 text-sm whitespace-nowrap hover:underline">
|
||||
<a class=""
|
||||
href="{{ $resource->link() }}">{{ $resource->name }}
|
||||
<x-internal-link /></a>
|
||||
</td>
|
||||
<td class="px-5 py-4 text-sm whitespace-nowrap">
|
||||
{{ str($resource->type())->headline() }}</td>
|
||||
<td class="px-5 py-4 text-sm font-medium whitespace-nowrap">
|
||||
@if ($resource->type() === 'service')
|
||||
<x-status.services :service="$resource"
|
||||
:showRefreshButton="false" />
|
||||
@else
|
||||
<x-status.index :resource="$resource" :showRefreshButton="false" />
|
||||
@endif
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="px-5 py-4 text-sm whitespace-nowrap">
|
||||
{{ data_get($resource->project(), 'name') }}
|
||||
</td>
|
||||
<td class="px-5 py-4 text-sm whitespace-nowrap">
|
||||
{{ data_get($resource, 'environment.name') }}
|
||||
</td>
|
||||
<td class="px-5 py-4 text-sm whitespace-nowrap hover:underline">
|
||||
<a class="" href="{{ $resource->link() }}">{{ $resource->name }}
|
||||
<x-internal-link /></a>
|
||||
</td>
|
||||
<td class="px-5 py-4 text-sm whitespace-nowrap">
|
||||
{{ str($resource->type())->headline() }}
|
||||
</td>
|
||||
<td class="px-5 py-4 text-sm font-medium whitespace-nowrap">
|
||||
@if ($resource->type() === 'service')
|
||||
<x-status.services :service="$resource" :showRefreshButton="false" />
|
||||
@else
|
||||
<x-status.index :resource="$resource" :showRefreshButton="false" />
|
||||
@endif
|
||||
</td>
|
||||
</tr>
|
||||
@empty
|
||||
@endforelse
|
||||
</tbody>
|
||||
@ -78,19 +75,19 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@else
|
||||
@else
|
||||
<div>No resources found.</div>
|
||||
@endif
|
||||
</div>
|
||||
<div x-cloak x-show="activeTab === 'unmanaged'" class="h-full">
|
||||
<div class="flex flex-col" x-init="$wire.loadUnmanagedContainers()">
|
||||
<div class="flex gap-2">
|
||||
<h2>Resources</h2>
|
||||
<x-forms.button wire:click="refreshStatus">Refresh</x-forms.button>
|
||||
</div>
|
||||
<div class="subtitle">Here you can find all other containers running on the server.</div>
|
||||
@endif
|
||||
</div>
|
||||
@if ($unmanagedContainers->count() > 0)
|
||||
<div x-cloak x-show="activeTab === 'unmanaged'" class="h-full">
|
||||
<div class="flex flex-col" x-init="$wire.loadUnmanagedContainers()">
|
||||
<div class="flex gap-2">
|
||||
<h2>Resources</h2>
|
||||
<x-forms.button wire:click="refreshStatus">Refresh</x-forms.button>
|
||||
</div>
|
||||
<div class="subtitle">Here you can find all other containers running on the server.</div>
|
||||
</div>
|
||||
@if ($unmanagedContainers->count() > 0)
|
||||
<div class="flex flex-col">
|
||||
<div class="flex flex-col">
|
||||
<div class="overflow-x-auto">
|
||||
@ -115,35 +112,27 @@
|
||||
</thead>
|
||||
<tbody>
|
||||
@forelse ($unmanagedContainers->sortBy('name',SORT_NATURAL) as $resource)
|
||||
<tr>
|
||||
<td class="px-5 py-4 text-sm whitespace-nowrap">
|
||||
{{ data_get($resource, 'Names') }}
|
||||
</td>
|
||||
<td class="px-5 py-4 text-sm whitespace-nowrap">
|
||||
{{ data_get($resource, 'Image') }}
|
||||
</td>
|
||||
<td class="px-5 py-4 text-sm whitespace-nowrap">
|
||||
{{ data_get($resource, 'State') }}
|
||||
</td>
|
||||
<td class="flex gap-2 px-5 py-4 text-sm whitespace-nowrap">
|
||||
@if (data_get($resource, 'State') === 'running')
|
||||
<x-forms.button
|
||||
wire:click="restartUnmanaged('{{ data_get($resource, 'ID') }}')"
|
||||
wire:key="{{ data_get($resource, 'ID') }}">Restart</x-forms.button>
|
||||
<x-forms.button isError
|
||||
wire:click="stopUnmanaged('{{ data_get($resource, 'ID') }}')"
|
||||
wire:key="{{ data_get($resource, 'ID') }}">Stop</x-forms.button>
|
||||
@elseif (data_get($resource, 'State') === 'exited')
|
||||
<x-forms.button
|
||||
wire:click="startUnmanaged('{{ data_get($resource, 'ID') }}')"
|
||||
wire:key="{{ data_get($resource, 'ID') }}">Start</x-forms.button>
|
||||
@elseif (data_get($resource, 'State') === 'restarting')
|
||||
<x-forms.button
|
||||
wire:click="stopUnmanaged('{{ data_get($resource, 'ID') }}')"
|
||||
wire:key="{{ data_get($resource, 'ID') }}">Stop</x-forms.button>
|
||||
@endif
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="px-5 py-4 text-sm whitespace-nowrap">
|
||||
{{ data_get($resource, 'Names') }}
|
||||
</td>
|
||||
<td class="px-5 py-4 text-sm whitespace-nowrap">
|
||||
{{ data_get($resource, 'Image') }}
|
||||
</td>
|
||||
<td class="px-5 py-4 text-sm whitespace-nowrap">
|
||||
{{ data_get($resource, 'State') }}
|
||||
</td>
|
||||
<td class="flex gap-2 px-5 py-4 text-sm whitespace-nowrap">
|
||||
@if (data_get($resource, 'State') === 'running')
|
||||
<x-forms.button wire:click="restartUnmanaged('{{ data_get($resource, 'ID') }}')" wire:key="{{ data_get($resource, 'ID') }}">Restart</x-forms.button>
|
||||
<x-forms.button isError wire:click="stopUnmanaged('{{ data_get($resource, 'ID') }}')" wire:key="{{ data_get($resource, 'ID') }}">Stop</x-forms.button>
|
||||
@elseif (data_get($resource, 'State') === 'exited')
|
||||
<x-forms.button wire:click="startUnmanaged('{{ data_get($resource, 'ID') }}')" wire:key="{{ data_get($resource, 'ID') }}">Start</x-forms.button>
|
||||
@elseif (data_get($resource, 'State') === 'restarting')
|
||||
<x-forms.button wire:click="stopUnmanaged('{{ data_get($resource, 'ID') }}')" wire:key="{{ data_get($resource, 'ID') }}">Stop</x-forms.button>
|
||||
@endif
|
||||
</td>
|
||||
</tr>
|
||||
@empty
|
||||
@endforelse
|
||||
</tbody>
|
||||
@ -153,10 +142,10 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@else
|
||||
@else
|
||||
<div>No resources found.</div>
|
||||
@endif
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
@ -3,34 +3,34 @@
|
||||
<div class="flex items-center gap-2">
|
||||
<h2>Backup</h2>
|
||||
@if (isset($database))
|
||||
<x-forms.button type="submit" wire:click="submit">
|
||||
Save
|
||||
</x-forms.button>
|
||||
<x-forms.button type="submit" wire:click="submit">
|
||||
Save
|
||||
</x-forms.button>
|
||||
@endif
|
||||
</div>
|
||||
<div class="pb-4">Backup your Coolify instance settings</div>
|
||||
<div class="pb-4">Backup your Last Hour Cloud instance settings</div>
|
||||
<div>
|
||||
@if (isset($database))
|
||||
<div class="flex flex-col gap-3 pb-4">
|
||||
<div class="flex gap-2">
|
||||
<x-forms.input label="UUID" readonly id="database.uuid" />
|
||||
<x-forms.input label="Name" readonly id="database.name" />
|
||||
<x-forms.input label="Description" id="database.description" />
|
||||
</div>
|
||||
<div class="flex gap-2">
|
||||
<x-forms.input label="User" readonly id="database.postgres_user" />
|
||||
<x-forms.input type="password" label="Password" readonly id="database.postgres_password" />
|
||||
</div>
|
||||
<div class="flex flex-col gap-3 pb-4">
|
||||
<div class="flex gap-2">
|
||||
<x-forms.input label="UUID" readonly id="database.uuid" />
|
||||
<x-forms.input label="Name" readonly id="database.name" />
|
||||
<x-forms.input label="Description" id="database.description" />
|
||||
</div>
|
||||
<livewire:project.database.backup-edit :backup="$backup" :s3s="$s3s" :status="data_get($database, 'status')" />
|
||||
<div class="flex gap-2">
|
||||
<x-forms.input label="User" readonly id="database.postgres_user" />
|
||||
<x-forms.input type="password" label="Password" readonly id="database.postgres_password" />
|
||||
</div>
|
||||
</div>
|
||||
<livewire:project.database.backup-edit :backup="$backup" :s3s="$s3s" :status="data_get($database, 'status')" />
|
||||
@else
|
||||
To configure automatic backup for your Coolify instance, you first need to add a database resource
|
||||
into Coolify.
|
||||
<x-forms.button class="mt-2" wire:click="add_coolify_database">Add Database</x-forms.button>
|
||||
To configure automatic backup for your Last Hour Cloud instance, you first need to add a database resource
|
||||
into Last Hour Cloud.
|
||||
<x-forms.button class="mt-2" wire:click="add_coolify_database">Add Database</x-forms.button>
|
||||
@endif
|
||||
</div>
|
||||
<div class="py-4">
|
||||
<livewire:project.database.backup-executions :backup="$backup" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
@ -6,15 +6,13 @@
|
||||
Save
|
||||
</x-forms.button>
|
||||
</div>
|
||||
<div>General configuration for your Coolify instance.</div>
|
||||
<div>General configuration for your Last Hour Cloud instance.</div>
|
||||
|
||||
<div class="flex flex-col gap-2 pt-4">
|
||||
<div class="flex flex-wrap items-end gap-2">
|
||||
<x-forms.input id="settings.fqdn" label="Instance's Domain" placeholder="https://coolify.io" />
|
||||
<x-forms.input id="settings.instance_name" label="Instance's Name" placeholder="Coolify" />
|
||||
<x-forms.input id="settings.custom_dns_servers" label="DNS Servers"
|
||||
helper="DNS servers for validation FQDNs againts. A comma separated list of DNS servers."
|
||||
placeholder="1.1.1.1,8.8.8.8" />
|
||||
<x-forms.input id="settings.fqdn" label="Instance's Domain" placeholder="https://lasthourhosting.org" />
|
||||
<x-forms.input id="settings.instance_name" label="Instance's Name" placeholder="Last Hour Cloud" />
|
||||
<x-forms.input id="settings.custom_dns_servers" label="DNS Servers" helper="DNS servers for validation FQDNs againts. A comma separated list of DNS servers." placeholder="9.9.9.9,149.112.112.112" />
|
||||
<div class="md:w-96">
|
||||
<x-forms.checkbox instantSave id="is_dns_validation_enabled" label="Validate DNS settings?" />
|
||||
</div>
|
||||
@ -30,20 +28,17 @@
|
||||
<div class="md:w-96">
|
||||
<x-forms.checkbox instantSave id="is_api_enabled" label="Enabled" />
|
||||
</div>
|
||||
<x-forms.input id="settings.allowed_ips" label="Allowed IPs"
|
||||
helper="Allowed IP lists for the API. A comma separated list of IPs. Empty means you allow from everywhere."
|
||||
placeholder="1.1.1.1,8.8.8.8" />
|
||||
<x-forms.input id="settings.allowed_ips" label="Allowed IPs" helper="Allowed IP lists for the API. A comma separated list of IPs. Empty means you allow from everywhere." placeholder="1.1.1.1,8.8.8.8" />
|
||||
</form>
|
||||
|
||||
<h2 class="pt-6">Advanced</h2>
|
||||
<div class="text-right md:w-96">
|
||||
@if (!is_null(env('AUTOUPDATE', null)))
|
||||
<x-forms.checkbox instantSave helper="AUTOUPDATE is set in .env file, you need to modify it there." disabled
|
||||
id="is_auto_update_enabled" label="Auto Update Coolify" />
|
||||
<x-forms.checkbox instantSave helper="AUTOUPDATE is set in .env file, you need to modify it there." disabled id="is_auto_update_enabled" label="Auto Update Last Hour Cloud" />
|
||||
@else
|
||||
<x-forms.checkbox instantSave id="is_auto_update_enabled" label="Auto Update Coolify" />
|
||||
<x-forms.checkbox instantSave id="is_auto_update_enabled" label="Auto Update Last Hour Cloud" />
|
||||
@endif
|
||||
<x-forms.checkbox instantSave id="is_registration_enabled" label="Registration Allowed" />
|
||||
<x-forms.checkbox instantSave id="do_not_track" label="Do Not Track" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
@ -1,105 +1,120 @@
|
||||
<div>
|
||||
@if (data_get($github_app, 'app_id'))
|
||||
<form wire:submit='submit'>
|
||||
<div class="flex items-center gap-2">
|
||||
<h1>GitHub App</h1>
|
||||
<div class="flex gap-2">
|
||||
@if (data_get($github_app, 'installation_id'))
|
||||
<x-forms.button type="submit">Save</x-forms.button>
|
||||
<a href="{{ get_installation_path($github_app) }}">
|
||||
<x-forms.button>
|
||||
Update Repositories
|
||||
<x-external-link />
|
||||
</x-forms.button>
|
||||
</a>
|
||||
@endif
|
||||
@if ($applications->count() > 0)
|
||||
<x-modal-confirmation disabled isErrorButton buttonTitle="Delete">
|
||||
This source will be deleted. It is not reversible. <br>Please think again.
|
||||
</x-modal-confirmation>
|
||||
@else
|
||||
<x-modal-confirmation isErrorButton buttonTitle="Delete">
|
||||
This source will be deleted. It is not reversible. <br>Please think again.
|
||||
</x-modal-confirmation>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
<div class="subtitle">Your Private GitHub App for private repositories.</div>
|
||||
@if (!data_get($github_app, 'installation_id'))
|
||||
<div class="mb-10 rounded alert-error">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="w-6 h-6 stroke-current shrink-0" fill="none"
|
||||
viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||
d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z" />
|
||||
</svg>
|
||||
<span>You must complete this step before you can use this source!</span>
|
||||
</div>
|
||||
<a class="items-center justify-center box" href="{{ get_installation_path($github_app) }}">
|
||||
Install Repositories on GitHub
|
||||
<form wire:submit='submit'>
|
||||
<div class="flex items-center gap-2">
|
||||
<h1>GitHub App</h1>
|
||||
<div class="flex gap-2">
|
||||
@if (data_get($github_app, 'installation_id'))
|
||||
<x-forms.button type="submit">Save</x-forms.button>
|
||||
<a href="{{ get_installation_path($github_app) }}">
|
||||
<x-forms.button>
|
||||
Update Repositories
|
||||
<x-external-link />
|
||||
</x-forms.button>
|
||||
</a>
|
||||
@else
|
||||
<div class="flex flex-col gap-2">
|
||||
<div class="flex gap-2">
|
||||
<x-forms.input id="github_app.name" label="App Name" disabled />
|
||||
<x-forms.input id="github_app.organization" label="Organization" disabled
|
||||
placeholder="If empty, personal user will be used" />
|
||||
</div>
|
||||
@if (!isCloud())
|
||||
<div class="w-48">
|
||||
<x-forms.checkbox label="System Wide?"
|
||||
helper="If checked, this GitHub App will be available for everyone in this Coolify instance."
|
||||
instantSave id="github_app.is_system_wide" />
|
||||
</div>
|
||||
@endif
|
||||
<div class="flex gap-2">
|
||||
<x-forms.input id="github_app.html_url" label="HTML Url" disabled />
|
||||
<x-forms.input id="github_app.api_url" label="API Url" disabled />
|
||||
</div>
|
||||
<div class="flex gap-2">
|
||||
@if ($github_app->html_url === 'https://github.com')
|
||||
<x-forms.input id="github_app.custom_user" label="User" disabled />
|
||||
<x-forms.input type="number" id="github_app.custom_port" label="Port" disabled />
|
||||
@else
|
||||
<x-forms.input id="github_app.custom_user" label="User" required />
|
||||
<x-forms.input type="number" id="github_app.custom_port" label="Port" required />
|
||||
@endif
|
||||
</div>
|
||||
<div class="flex gap-2">
|
||||
<x-forms.input type="number" id="github_app.app_id" label="App Id" disabled />
|
||||
<x-forms.input type="number" id="github_app.installation_id" label="Installation Id"
|
||||
disabled />
|
||||
</div>
|
||||
<div class="flex gap-2">
|
||||
<x-forms.input id="github_app.client_id" label="Client Id" type="password" disabled />
|
||||
<x-forms.input id="github_app.client_secret" label="Client Secret" type="password" />
|
||||
<x-forms.input id="github_app.webhook_secret" label="Webhook Secret" type="password" />
|
||||
</div>
|
||||
<div class="flex items-end gap-2 ">
|
||||
<h2 class="pt-4">Permissions</h2>
|
||||
<x-forms.button wire:click.prevent="checkPermissions">Refetch</x-forms.button>
|
||||
<a href="{{ get_permissions_path($github_app) }}">
|
||||
<x-forms.button>
|
||||
Update
|
||||
<x-external-link />
|
||||
</x-forms.button>
|
||||
</a>
|
||||
</div>
|
||||
<div class="flex gap-2">
|
||||
<x-forms.input id="github_app.contents" helper="read - mandatory." label="Content" readonly
|
||||
placeholder="N/A" />
|
||||
<x-forms.input id="github_app.metadata" helper="read - mandatory." label="Metadata" readonly
|
||||
placeholder="N/A" />
|
||||
{{-- <x-forms.input id="github_app.administration"
|
||||
@endif
|
||||
@if ($applications->count() > 0)
|
||||
<x-modal-confirmation disabled isErrorButton buttonTitle="Delete">
|
||||
This source will be deleted. It is not reversible. <br>Please think again.
|
||||
</x-modal-confirmation>
|
||||
@else
|
||||
<x-modal-confirmation isErrorButton buttonTitle="Delete">
|
||||
This source will be deleted. It is not reversible. <br>Please think again.
|
||||
</x-modal-confirmation>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
<div class="subtitle">Your Private GitHub App for private repositories.</div>
|
||||
@if (!data_get($github_app, 'installation_id'))
|
||||
<div class="mb-10 rounded alert-error">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="w-6 h-6 stroke-current shrink-0" fill="none" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z" />
|
||||
</svg>
|
||||
<span>You must complete this step before you can use this source!</span>
|
||||
</div>
|
||||
<a class="items-center justify-center box" href="{{ get_installation_path($github_app) }}">
|
||||
Install Repositories on GitHub
|
||||
</a>
|
||||
@endif
|
||||
<x-new-modal isErrorButton buttonTitle="Delete">
|
||||
This source will be deleted. It is not reversible. <br>Please think again.
|
||||
</x-new-modal>
|
||||
</div>
|
||||
</div>
|
||||
<div class="subtitle">Your Private GitHub App for private repositories.</div>
|
||||
@if (!data_get($github_app, 'installation_id'))
|
||||
<div class="mb-10 rounded alert alert-warning">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="w-6 h-6 stroke-current shrink-0" fill="none" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z" />
|
||||
</svg>
|
||||
<span>You must complete this step before you can use this source!</span>
|
||||
</div>
|
||||
<a class="items-center justify-center box" href="{{ get_installation_path($github_app) }}">
|
||||
Install Repositories on GitHub
|
||||
</a>
|
||||
@else
|
||||
<div class="flex flex-col gap-2">
|
||||
<div class="flex gap-2">
|
||||
<x-forms.input id="github_app.name" label="App Name" disabled />
|
||||
<x-forms.input id="github_app.organization" label="Organization" disabled placeholder="If empty, personal user will be used" />
|
||||
</div>
|
||||
@if (!isCloud())
|
||||
<div class="w-48">
|
||||
<x-forms.checkbox label="System Wide?" helper="If checked, this GitHub App will be available for everyone in this Last Hour Cloud instance." instantSave id="github_app.is_system_wide" />
|
||||
</div>
|
||||
@endif
|
||||
<div class="flex gap-2">
|
||||
<x-forms.input id="github_app.html_url" label="HTML Url" disabled />
|
||||
<x-forms.input id="github_app.api_url" label="API Url" disabled />
|
||||
</div>
|
||||
<div class="flex gap-2">
|
||||
@if ($github_app->html_url === 'https://github.com')
|
||||
<x-forms.input id="github_app.custom_user" label="User" disabled />
|
||||
<x-forms.input type="number" id="github_app.custom_port" label="Port" disabled />
|
||||
@else
|
||||
<x-forms.input id="github_app.custom_user" label="User" required />
|
||||
<x-forms.input type="number" id="github_app.custom_port" label="Port" required />
|
||||
@endif
|
||||
</div>
|
||||
<div class="flex gap-2">
|
||||
<x-forms.input type="number" id="github_app.app_id" label="App Id" disabled />
|
||||
<x-forms.input type="number" id="github_app.installation_id" label="Installation Id" disabled />
|
||||
</div>
|
||||
<div class="flex gap-2">
|
||||
<x-forms.input id="github_app.client_id" label="Client Id" type="password" disabled />
|
||||
<x-forms.input id="github_app.client_secret" label="Client Secret" type="password" />
|
||||
<x-forms.input id="github_app.webhook_secret" label="Webhook Secret" type="password" />
|
||||
</div>
|
||||
<div class="flex items-end gap-2 ">
|
||||
<h2 class="pt-4">Permissions</h2>
|
||||
<x-forms.button wire:click.prevent="checkPermissions">Refetch</x-forms.button>
|
||||
<a href="{{ get_permissions_path($github_app) }}">
|
||||
<x-forms.button>
|
||||
Update
|
||||
<x-external-link />
|
||||
</x-forms.button>
|
||||
</a>
|
||||
</div>
|
||||
<div class="flex gap-2">
|
||||
<x-forms.input id="github_app.contents" helper="read - mandatory." label="Content" readonly placeholder="N/A" />
|
||||
<x-forms.input id="github_app.metadata" helper="read - mandatory." label="Metadata" readonly placeholder="N/A" />
|
||||
{{-- <x-forms.input id="github_app.administration"
|
||||
helper="read:write access needed to setup servers as GitHub Runner." label="Administration"
|
||||
readonly placeholder="N/A" /> --}}
|
||||
<x-forms.input id="github_app.pull_requests"
|
||||
helper="write access needed to use deployment status update in previews."
|
||||
label="Pull Request" readonly placeholder="N/A" />
|
||||
</div>
|
||||
</div>
|
||||
<x-forms.input id="github_app.pull_requests" helper="write access needed to use deployment status update in previews." label="Pull Request" readonly placeholder="N/A" />
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
</form>
|
||||
<div class="w-full pt-10">
|
||||
<div class="h-full">
|
||||
<div class="flex flex-col">
|
||||
<div class="flex gap-2">
|
||||
<h2>Resources</h2>
|
||||
</div>
|
||||
@endif
|
||||
</form>
|
||||
@if (data_get($github_app, 'installation_id'))
|
||||
</form>
|
||||
@if (data_get($github_app, 'installation_id'))
|
||||
<div class="w-full pt-10">
|
||||
<div class="h-full">
|
||||
<div class="flex flex-col">
|
||||
@ -129,21 +144,20 @@
|
||||
</thead>
|
||||
<tbody class="divide-y">
|
||||
@forelse ($applications->sortBy('name',SORT_NATURAL) as $resource)
|
||||
<tr>
|
||||
<td class="px-5 py-4 text-sm whitespace-nowrap">
|
||||
{{ data_get($resource->project(), 'name') }}
|
||||
</td>
|
||||
<td class="px-5 py-4 text-sm whitespace-nowrap">
|
||||
{{ data_get($resource, 'environment.name') }}
|
||||
</td>
|
||||
<td class="px-5 py-4 text-sm whitespace-nowrap"><a
|
||||
class=""
|
||||
href="{{ $resource->link() }}">{{ $resource->name }}
|
||||
<x-internal-link /></a>
|
||||
</td>
|
||||
<td class="px-5 py-4 text-sm whitespace-nowrap">
|
||||
{{ str($resource->type())->headline() }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="px-5 py-4 text-sm whitespace-nowrap">
|
||||
{{ data_get($resource->project(), 'name') }}
|
||||
</td>
|
||||
<td class="px-5 py-4 text-sm whitespace-nowrap">
|
||||
{{ data_get($resource, 'environment.name') }}
|
||||
</td>
|
||||
<td class="px-5 py-4 text-sm whitespace-nowrap"><a class="" href="{{ $resource->link() }}">{{ $resource->name }}
|
||||
<x-internal-link /></a>
|
||||
</td>
|
||||
<td class="px-5 py-4 text-sm whitespace-nowrap">
|
||||
{{ str($resource->type())->headline() }}
|
||||
</td>
|
||||
</tr>
|
||||
@empty
|
||||
@endforelse
|
||||
</tbody>
|
||||
@ -155,81 +169,109 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
@else
|
||||
<div class="flex items-center gap-2 pb-4">
|
||||
<h1>GitHub App</h1>
|
||||
<div class="flex gap-2">
|
||||
<x-modal-confirmation isErrorButton buttonTitle="Delete">
|
||||
This source will be deleted. It is not reversible. <br>Please think again.
|
||||
</x-modal-confirmation>
|
||||
@endif
|
||||
@else
|
||||
<div class="flex items-center gap-2 pb-4">
|
||||
<h1>GitHub App</h1>
|
||||
<div class="flex gap-2">
|
||||
<x-modal-confirmation isErrorButton buttonTitle="Delete">
|
||||
This source will be deleted. It is not reversible. <br>Please think again.
|
||||
</x-modal-confirmation>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mb-10 rounded alert-error">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="w-6 h-6 stroke-current shrink-0" fill="none"
|
||||
viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||
d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z" />
|
||||
</svg>
|
||||
<span>You must complete this step before you can use this source!</span>
|
||||
</div>
|
||||
<div class="flex flex-col">
|
||||
<div class="flex gap-2">
|
||||
<h2>Register a GitHub App</h2>
|
||||
<x-forms.button class="bg-coollabs hover:bg-coollabs-100"
|
||||
x-on:click.prevent="createGithubApp('{{ $webhook_endpoint }}','{{ $preview_deployment_permissions }}',{{ $administration }})">
|
||||
Register Now
|
||||
</x-forms.button>
|
||||
<div class="mb-10 rounded alert-error">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="w-6 h-6 stroke-current shrink-0" fill="none" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z" />
|
||||
</svg>
|
||||
<span>You must complete this step before you can use this source!</span>
|
||||
</div>
|
||||
<div>You need to register a GitHub App before using this source.</div>
|
||||
<div class="py-10">
|
||||
@if (!isCloud() || isDev())
|
||||
<div class="flex items-end gap-2">
|
||||
<x-forms.select wire:model.live='webhook_endpoint' label="Webhook Endpoint"
|
||||
helper="All Git webhooks will be sent to this endpoint. <br><br>If you would like to use domain instead of IP address, set your Coolify instance's FQDN in the Settings menu.">
|
||||
@if ($ipv4)
|
||||
<option value="{{ $ipv4 }}">Use {{ $ipv4 }}</option>
|
||||
@endif
|
||||
@if ($ipv6)
|
||||
<option value="{{ $ipv6 }}">Use {{ $ipv6 }}</option>
|
||||
@endif
|
||||
@if ($fqdn)
|
||||
<option value="{{ $fqdn }}">Use {{ $fqdn }}</option>
|
||||
@endif
|
||||
@if (config('app.url'))
|
||||
<option value="{{ config('app.url') }}">Use {{ config('app.url') }}</option>
|
||||
@endif
|
||||
</x-forms.select>
|
||||
</div>
|
||||
<div class="flex items-end gap-2">
|
||||
<x-forms.select wire:model.live='webhook_endpoint' label="Webhook Endpoint" helper="All Git webhooks will be sent to this endpoint. <br><br>If you would like to use domain instead of IP address, set your Last Hour Cloud instance's FQDN in the Settings menu.">
|
||||
@if ($ipv4)
|
||||
<option value="{{ $ipv4 }}">Use {{ $ipv4 }}</option>
|
||||
@endif
|
||||
@if ($ipv6)
|
||||
<option value="{{ $ipv6 }}">Use {{ $ipv6 }}</option>
|
||||
@endif
|
||||
@if ($fqdn)
|
||||
<option value="{{ $fqdn }}">Use {{ $fqdn }}</option>
|
||||
@endif
|
||||
@if (config('app.url'))
|
||||
<option value="{{ config('app.url') }}">Use {{ config('app.url') }}</option>
|
||||
@endif
|
||||
</x-forms.select>
|
||||
</div>
|
||||
@endif
|
||||
<div class="flex flex-col gap-2 pt-4 w-96">
|
||||
<x-forms.checkbox disabled instantSave id="default_permissions" label="Mandatory"
|
||||
helper="Contents: read<br>Metadata: read<br>Email: read" />
|
||||
<x-forms.checkbox instantSave id="preview_deployment_permissions" label="Preview Deployments "
|
||||
helper="Necessary for updating pull requests with useful comments (deployment status, links, etc.)<br><br>Pull Request: read & write" />
|
||||
<x-forms.checkbox disabled instantSave id="default_permissions" label="Mandatory" helper="Contents: read<br>Metadata: read<br>Email: read" />
|
||||
<x-forms.checkbox instantSave id="preview_deployment_permissions" label="Preview Deployments " helper="Necessary for updating pull requests with useful comments (deployment status, links, etc.)<br><br>Pull Request: read & write" />
|
||||
{{-- <x-forms.checkbox instantSave id="administration" label="Administration (for Github Runners)"
|
||||
helper="Necessary for adding Github Runners to repositories.<br><br>Administration: read & write" /> --}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
function createGithubApp(webhook_endpoint, preview_deployment_permissions, administration) {
|
||||
const {
|
||||
organization,
|
||||
uuid,
|
||||
html_url
|
||||
} = @json($github_app);
|
||||
if (!webhook_endpoint) {
|
||||
alert('Please select a webhook endpoint.');
|
||||
return;
|
||||
}
|
||||
let baseUrl = webhook_endpoint;
|
||||
const name = @js($name);
|
||||
const isDev = @js(config('app.env')) ===
|
||||
'local';
|
||||
const devWebhook = @js(config('coolify.dev_webhook'));
|
||||
if (isDev && devWebhook) {
|
||||
baseUrl = devWebhook;
|
||||
<script>
|
||||
function createGithubApp(webhook_endpoint, preview_deployment_permissions, administration) {
|
||||
const {
|
||||
organization,
|
||||
uuid,
|
||||
html_url
|
||||
} = @json($github_app);
|
||||
if (!webhook_endpoint) {
|
||||
alert('Please select a webhook endpoint.');
|
||||
return;
|
||||
}
|
||||
let baseUrl = webhook_endpoint;
|
||||
const name = @js($name);
|
||||
const isDev = @js(config('app.env')) ===
|
||||
'local';
|
||||
const devWebhook = @js(config('coolify.dev_webhook'));
|
||||
if (isDev && devWebhook) {
|
||||
baseUrl = devWebhook;
|
||||
}
|
||||
const webhookBaseUrl = `${baseUrl}/webhooks`;
|
||||
const path = organization ? `organizations/${organization}/settings/apps/new` : 'settings/apps/new';
|
||||
const default_permissions = {
|
||||
contents: 'read',
|
||||
metadata: 'read',
|
||||
emails: 'read',
|
||||
administration: 'read'
|
||||
};
|
||||
if (preview_deployment_permissions) {
|
||||
default_permissions.pull_requests = 'write';
|
||||
}
|
||||
if (administration) {
|
||||
default_permissions.administration = 'write';
|
||||
}
|
||||
const data = {
|
||||
name,
|
||||
url: baseUrl,
|
||||
hook_attributes: {
|
||||
url: `${webhookBaseUrl}/source/github/events`,
|
||||
active: true,
|
||||
},
|
||||
redirect_url: `${webhookBaseUrl}/source/github/redirect`,
|
||||
callback_urls: [`${baseUrl}/login/github/app`],
|
||||
public: false,
|
||||
request_oauth_on_install: false,
|
||||
setup_url: `${webhookBaseUrl}/source/github/install?source=${uuid}`,
|
||||
setup_on_update: true,
|
||||
default_permissions,
|
||||
default_events: ['pull_request', 'push']
|
||||
};
|
||||
const form = document.createElement('form');
|
||||
form.setAttribute('method', 'post');
|
||||
form.setAttribute('action', `${html_url}/${path}?state=${uuid}`);
|
||||
const input = document.createElement('input');
|
||||
input.setAttribute('id', 'manifest');
|
||||
input.setAttribute('name', 'manifest');
|
||||
input.setAttribute('type', 'hidden');
|
||||
input.setAttribute('value', JSON.stringify(data));
|
||||
form.appendChild(input);
|
||||
document.getElementsByTagName('body')[0].appendChild(form);
|
||||
form.submit();
|
||||
}
|
||||
const webhookBaseUrl = `${baseUrl}/webhooks`;
|
||||
const path = organization ? `organizations/${organization}/settings/apps/new` : 'settings/apps/new';
|
||||
@ -272,7 +314,7 @@
|
||||
form.appendChild(input);
|
||||
document.getElementsByTagName('body')[0].appendChild(form);
|
||||
form.submit();
|
||||
}
|
||||
</script>
|
||||
@endif
|
||||
</div>
|
||||
}
|
||||
</script>
|
||||
@endif
|
||||
</div>
|
@ -0,0 +1,27 @@
|
||||
<div>
|
||||
<x-team.navbar />
|
||||
<div class="flex gap-2">
|
||||
<h2>Shared Variables</h2>
|
||||
<x-slide-over>
|
||||
<x-slot:title>New Shared Variable</x-slot:title>
|
||||
<x-slot:content>
|
||||
<livewire:project.shared.environment-variable.add />
|
||||
</x-slot:content>
|
||||
<button @click="slideOverOpen=true"
|
||||
class="font-normal text-white normal-case border-none rounded btn btn-primary btn-sm no-animation">+
|
||||
Add</button>
|
||||
</x-slide-over>
|
||||
</div>
|
||||
<div class="flex items-center gap-2 pb-4">You can use these variables anywhere with <span class="text-warning">@{{team.VARIABLENAME}}</span> <x-helper
|
||||
helper="More info in upstream docs<a class='text-white underline' href='https://coolify.io/docs/environment-variables#shared-variables' target='_blank'>here</a>."></x-helper>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col gap-2">
|
||||
@forelse ($team->environment_variables->sort()->sortBy('real_value') as $env)
|
||||
<livewire:project.shared.environment-variable.show wire:key="environment-{{ $env->id }}"
|
||||
:env="$env" type="team" />
|
||||
@empty
|
||||
<div class="text-neutral-500">No environment variables found.</div>
|
||||
@endforelse
|
||||
</div>
|
||||
</div>
|
@ -2,7 +2,7 @@
|
||||
<div class="w-96 min-w-fit">
|
||||
<div class="flex flex-col items-center pb-8">
|
||||
<a href="{{ route('dashboard') }}">
|
||||
<div class="text-5xl font-bold tracking-tight text-center dark:text-white">Last Hour</div>
|
||||
<div class="text-5xl font-bold tracking-tight text-center dark:text-white">Last Hour Cloud</div>
|
||||
</a>
|
||||
</div>
|
||||
<div class="flex items-center justify-center pb-4 text-center">
|
||||
|
@ -1,5 +1,4 @@
|
||||
#!/bin/bash
|
||||
## Do not modify this file. You will lose the ability to install and auto-update!
|
||||
|
||||
set -e # Exit immediately if a command exits with a non-zero status
|
||||
## $1 could be empty, so we need to disable this check
|
||||
@ -9,7 +8,7 @@ set -o pipefail # Cause a pipeline to return the status of the last command that
|
||||
VERSION="1.3.3"
|
||||
DOCKER_VERSION="26.0"
|
||||
|
||||
CDN="https://cdn.coollabs.io/coolify"
|
||||
CDN="https://cdn.githaven.org/lasthourcloud"
|
||||
OS_TYPE=$(grep -w "ID" /etc/os-release | cut -d "=" -f 2 | tr -d '"')
|
||||
|
||||
# Check if the OS is manjaro, if so, change it to arch
|
||||
@ -67,13 +66,17 @@ if [ "$1" != "" ]; then
|
||||
fi
|
||||
|
||||
echo -e "-------------"
|
||||
echo -e "Welcome to Coolify v4 beta installer!"
|
||||
echo -e "Welcome to Last Hour Cloud v4 beta installer!"
|
||||
echo -e "This script will install everything for you."
|
||||
<<<<<<< HEAD
|
||||
echo -e "(Source code: https://github.com/coollabsio/coolify/blob/main/scripts/install.sh )\n"
|
||||
=======
|
||||
echo -e "(Source code: https://https://githaven.org/Shiloh/lasthourcloud/blob/main/scripts/install.sh)\n"
|
||||
>>>>>>> 35700ec24 (main: begin major rewrite for lasthour)
|
||||
echo -e "-------------"
|
||||
|
||||
echo "OS: $OS_TYPE $OS_VERSION"
|
||||
echo "Coolify version: $LATEST_VERSION"
|
||||
echo "Last Hour Cloud version: $LATEST_VERSION"
|
||||
|
||||
echo -e "-------------"
|
||||
echo "Installing required packages..."
|
||||
@ -130,7 +133,7 @@ fi
|
||||
if [ "$SSH_DETECTED" = "false" ]; then
|
||||
echo "###############################################################################"
|
||||
echo "WARNING: Could not detect if OpenSSH server is installed and running - this does not mean that it is not installed, just that we could not detect it."
|
||||
echo -e "Please make sure it is set, otherwise Coolify cannot connect to the host system. \n"
|
||||
echo -e "Please make sure it is set, otherwise Last Hour Cloud cannot connect to the host system. \n"
|
||||
echo "###############################################################################"
|
||||
fi
|
||||
|
||||
@ -146,7 +149,12 @@ if [ "$SSH_PERMIT_ROOT_LOGIN" != "true" ]; then
|
||||
echo "###############################################################################"
|
||||
echo "WARNING: PermitRootLogin is not enabled in /etc/ssh/sshd_config."
|
||||
echo -e "It is set to $SSH_PERMIT_ROOT_LOGIN_CONFIG. Should be prohibit-password, yes or without-password.\n"
|
||||
<<<<<<< HEAD
|
||||
echo -e "Please make sure it is set, otherwise Coolify cannot connect to the host system. \n"
|
||||
=======
|
||||
echo -e "Please make sure it is set, otherwise Last Hour Cloud cannot connect to the host system. \n"
|
||||
echo "(Currently we only support root user to login via SSH, this will be changed in the future.)"
|
||||
>>>>>>> 35700ec24 (main: begin major rewrite for lasthour)
|
||||
echo "###############################################################################"
|
||||
fi
|
||||
|
||||
@ -275,15 +283,22 @@ mkdir -p /data/coolify/{source,ssh,applications,databases,backups,services,proxy
|
||||
mkdir -p /data/coolify/ssh/{keys,mux}
|
||||
mkdir -p /data/coolify/proxy/dynamic
|
||||
|
||||
chown -R 9999:root /data/coolify
|
||||
chmod -R 700 /data/coolify
|
||||
|
||||
echo "Downloading required files from CDN..."
|
||||
curl -fsSL $CDN/docker-compose.yml -o /data/coolify/source/docker-compose.yml
|
||||
curl -fsSL $CDN/docker-compose.prod.yml -o /data/coolify/source/docker-compose.prod.yml
|
||||
curl -fsSL $CDN/.env.production -o /data/coolify/source/.env.production
|
||||
curl -fsSL $CDN/upgrade.sh -o /data/coolify/source/upgrade.sh
|
||||
|
||||
# echo "Copying required files from Last Hour Cloud git repo..."
|
||||
# cp /home/lasthour/lasthourcloud/docker-compose.yml /data/coolify/source/docker-compose.yml
|
||||
# cp /home/lasthour/lasthourcloud/docker-compose.prod.yml /data/coolify/source/docker-compose.prod.yml
|
||||
# cp /home/lasthour/lasthourcloud/.env.production /data/coolify/source/.env.production
|
||||
# cp /home/lasthour/lasthourcloud/scripts/upgrade.sh /data/coolify/source/upgrade.sh
|
||||
|
||||
|
||||
chown -R 9999:root /data/coolify
|
||||
chmod -R 700 /data/coolify
|
||||
|
||||
# Copy .env.example if .env does not exist
|
||||
if [ ! -f /data/coolify/source/.env ]; then
|
||||
cp /data/coolify/source/.env.production /data/coolify/source/.env
|
||||
@ -328,8 +343,10 @@ fi
|
||||
if ! grep -qw "root@coolify" ~/.ssh/authorized_keys; then
|
||||
addSshKey
|
||||
fi
|
||||
echo "Generated SSH access"
|
||||
|
||||
echo "Begin upgrade.sh"
|
||||
bash /data/coolify/source/upgrade.sh "${LATEST_VERSION:-latest}"
|
||||
|
||||
echo -e "\nCongratulations! Your Coolify instance is ready to use.\n"
|
||||
echo "Please visit http://$(curl -4s https://ifconfig.io):8000 to get started."
|
||||
echo -e "\nCongratulations! Your Last Hour Cloud instance is ready to use.\n"
|
||||
echo "Please visit http://$(curl -4s https://ifconfig.io):8000 to get started."
|
@ -1,270 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e # Exit immediately if a command exits with a non-zero status
|
||||
## $1 could be empty, so we need to disable this check
|
||||
#set -u # Treat unset variables as an error and exit
|
||||
set -o pipefail # Cause a pipeline to return the status of the last command that exited with a non-zero status
|
||||
|
||||
VERSION="1.2.0"
|
||||
DOCKER_VERSION="24.0"
|
||||
|
||||
CDN="https://cdn.coollabs.io/coolify"
|
||||
OS_TYPE=$(grep -w "ID" /etc/os-release | cut -d "=" -f 2 | tr -d '"')
|
||||
|
||||
if [ "$OS_TYPE" = "arch" ]; then
|
||||
OS_VERSION="rolling"
|
||||
else
|
||||
OS_VERSION=$(grep -w "VERSION_ID" /etc/os-release | cut -d "=" -f 2 | tr -d '"')
|
||||
fi
|
||||
|
||||
LATEST_VERSION=$(curl --silent $CDN/versions.json | grep -i version | sed -n '2p' | xargs | awk '{print $2}' | tr -d ',')
|
||||
DATE=$(date +"%Y%m%d-%H%M%S")
|
||||
|
||||
if [ $EUID != 0 ]; then
|
||||
echo "Please run as root"
|
||||
exit
|
||||
fi
|
||||
|
||||
case "$OS_TYPE" in
|
||||
arch | ubuntu | debian | raspbian | centos | fedora | rhel | ol | rocky | sles | opensuse-leap | opensuse-tumbleweed) ;;
|
||||
*)
|
||||
echo "This script only supports Debian, Redhat, Arch Linux, or SLES based operating systems for now."
|
||||
exit
|
||||
;;
|
||||
esac
|
||||
|
||||
# Overwrite LATEST_VERSION if user pass a version number
|
||||
if [ "$1" != "" ]; then
|
||||
LATEST_VERSION=$1
|
||||
LATEST_VERSION="${LATEST_VERSION,,}"
|
||||
LATEST_VERSION="${LATEST_VERSION#v}"
|
||||
fi
|
||||
|
||||
echo -e "-------------"
|
||||
echo -e "Welcome to Coolify v4 beta installer!"
|
||||
echo -e "This script will install everything for you."
|
||||
echo -e "(Source code: https://github.com/coollabsio/coolify/blob/main/scripts/install.sh)\n"
|
||||
echo -e "-------------"
|
||||
|
||||
echo "OS: $OS_TYPE $OS_VERSION"
|
||||
echo "Coolify version: $LATEST_VERSION"
|
||||
|
||||
echo -e "-------------"
|
||||
echo "Installing required packages..."
|
||||
|
||||
case "$OS_TYPE" in
|
||||
arch)
|
||||
pacman -Sy >/dev/null 2>&1 || true
|
||||
if ! pacman -Q curl wget git jq >/dev/null 2>&1; then
|
||||
pacman -S --noconfirm curl wget git jq >/dev/null 2>&1 || true
|
||||
fi
|
||||
;;
|
||||
ubuntu | debian | raspbian)
|
||||
apt update -y >/dev/null 2>&1
|
||||
apt install -y curl wget git jq >/dev/null 2>&1
|
||||
;;
|
||||
centos | fedora | rhel | ol | rocky)
|
||||
dnf install -y curl wget git jq >/dev/null 2>&1
|
||||
;;
|
||||
sles | opensuse-leap | opensuse-tumbleweed)
|
||||
zypper refresh >/dev/null 2>&1
|
||||
zypper install -y curl wget git jq >/dev/null 2>&1
|
||||
;;
|
||||
*)
|
||||
echo "This script only supports Debian, Redhat, Arch Linux, or SLES based operating systems for now."
|
||||
exit
|
||||
;;
|
||||
esac
|
||||
|
||||
# Detect OpenSSH server
|
||||
SSH_DETECTED=false
|
||||
if [ -x "$(command -v systemctl)" ]; then
|
||||
if systemctl status sshd >/dev/null 2>&1; then
|
||||
echo "OpenSSH server is installed."
|
||||
SSH_DETECTED=true
|
||||
fi
|
||||
if systemctl status ssh >/dev/null 2>&1; then
|
||||
echo "OpenSSH server is installed."
|
||||
SSH_DETECTED=true
|
||||
fi
|
||||
elif [ -x "$(command -v service)" ]; then
|
||||
if service sshd status >/dev/null 2>&1; then
|
||||
echo "OpenSSH server is installed."
|
||||
SSH_DETECTED=true
|
||||
fi
|
||||
if service ssh status >/dev/null 2>&1; then
|
||||
echo "OpenSSH server is installed."
|
||||
SSH_DETECTED=true
|
||||
fi
|
||||
fi
|
||||
if [ "$SSH_DETECTED" = "false" ]; then
|
||||
echo "###############################################################################"
|
||||
echo "WARNING: Could not detect if OpenSSH server is installed and running - this does not mean that it is not installed, just that we could not detect it."
|
||||
echo -e "Please make sure it is set, otherwise Coolify cannot connect to the host system. \n"
|
||||
echo "###############################################################################"
|
||||
fi
|
||||
|
||||
# Detect SSH PermitRootLogin
|
||||
SSH_PERMIT_ROOT_LOGIN=false
|
||||
SSH_PERMIT_ROOT_LOGIN_CONFIG=$(grep "^PermitRootLogin" /etc/ssh/sshd_config | awk '{print $2}') || SSH_PERMIT_ROOT_LOGIN_CONFIG="N/A (commented out or not found at all)"
|
||||
if [ "$SSH_PERMIT_ROOT_LOGIN_CONFIG" = "prohibit-password" ] || [ "$SSH_PERMIT_ROOT_LOGIN_CONFIG" = "yes" ] || [ "$SSH_PERMIT_ROOT_LOGIN_CONFIG" = "without-password" ]; then
|
||||
echo "PermitRootLogin is enabled."
|
||||
SSH_PERMIT_ROOT_LOGIN=true
|
||||
fi
|
||||
|
||||
|
||||
if [ "$SSH_PERMIT_ROOT_LOGIN" != "true" ]; then
|
||||
echo "###############################################################################"
|
||||
echo "WARNING: PermitRootLogin is not enabled in /etc/ssh/sshd_config."
|
||||
echo -e "It is set to $SSH_PERMIT_ROOT_LOGIN_CONFIG. Should be prohibit-password, yes or without-password.\n"
|
||||
echo -e "Please make sure it is set, otherwise Coolify cannot connect to the host system. \n"
|
||||
echo "(Currently we only support root user to login via SSH, this will be changed in the future.)"
|
||||
echo "###############################################################################"
|
||||
fi
|
||||
|
||||
if ! [ -x "$(command -v docker)" ]; then
|
||||
echo "Docker is not installed. Installing Docker."
|
||||
if [ "$OS_TYPE" = "arch" ]; then
|
||||
pacman -Sy docker docker-compose --noconfirm
|
||||
systemctl enable docker.service
|
||||
if [ -x "$(command -v docker)" ]; then
|
||||
echo "Docker installed successfully."
|
||||
else
|
||||
echo "Failed to install Docker with pacman. Try to install it manually."
|
||||
echo "Please visit https://wiki.archlinux.org/title/docker for more information."
|
||||
exit
|
||||
fi
|
||||
else
|
||||
curl https://releases.rancher.com/install-docker/${DOCKER_VERSION}.sh | sh
|
||||
if [ -x "$(command -v docker)" ]; then
|
||||
echo "Docker installed successfully."
|
||||
else
|
||||
echo "Docker installation failed with Rancher script. Trying with official script."
|
||||
curl https://get.docker.com | sh -s -- --version ${DOCKER_VERSION}
|
||||
if [ -x "$(command -v docker)" ]; then
|
||||
echo "Docker installed successfully."
|
||||
else
|
||||
echo "Docker installation failed with official script."
|
||||
echo "Maybe your OS is not supported?"
|
||||
echo "Please visit https://docs.docker.com/engine/install/ and install Docker manually to continue."
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
echo -e "-------------"
|
||||
echo -e "Check Docker Configuration..."
|
||||
mkdir -p /etc/docker
|
||||
# shellcheck disable=SC2015
|
||||
test -s /etc/docker/daemon.json && cp /etc/docker/daemon.json /etc/docker/daemon.json.original-"$DATE" || cat >/etc/docker/daemon.json <<EOL
|
||||
{
|
||||
"log-driver": "json-file",
|
||||
"log-opts": {
|
||||
"max-size": "10m",
|
||||
"max-file": "3"
|
||||
}
|
||||
}
|
||||
EOL
|
||||
cat >/etc/docker/daemon.json.coolify <<EOL
|
||||
{
|
||||
"log-driver": "json-file",
|
||||
"log-opts": {
|
||||
"max-size": "10m",
|
||||
"max-file": "3"
|
||||
}
|
||||
}
|
||||
EOL
|
||||
TEMP_FILE=$(mktemp)
|
||||
if ! jq -s '.[0] * .[1]' /etc/docker/daemon.json /etc/docker/daemon.json.coolify >"$TEMP_FILE"; then
|
||||
echo "Error merging JSON files"
|
||||
exit 1
|
||||
fi
|
||||
mv "$TEMP_FILE" /etc/docker/daemon.json
|
||||
|
||||
if [ -s /etc/docker/daemon.json.original-"$DATE" ]; then
|
||||
DIFF=$(diff <(jq --sort-keys . /etc/docker/daemon.json) <(jq --sort-keys . /etc/docker/daemon.json.original-"$DATE"))
|
||||
if [ "$DIFF" != "" ]; then
|
||||
echo "Docker configuration updated, restart docker daemon..."
|
||||
systemctl restart docker
|
||||
else
|
||||
echo "Docker configuration is up to date."
|
||||
fi
|
||||
else
|
||||
echo "Docker configuration updated, restart docker daemon..."
|
||||
systemctl restart docker
|
||||
fi
|
||||
|
||||
echo -e "-------------"
|
||||
#add directories here that you want to modify
|
||||
mkdir -p /data/coolify/{source,ssh,applications,databases,backups,services,proxy,tailwind}
|
||||
mkdir -p /data/coolify/ssh/{keys,mux}
|
||||
mkdir -p /data/coolify/proxy/dynamic
|
||||
|
||||
# echo "Downloading required files from CDN..."
|
||||
# curl -fsSL $CDN/docker-compose.yml -o /data/coolify/source/docker-compose.yml
|
||||
# curl -fsSL $CDN/docker-compose.prod.yml -o /data/coolify/source/docker-compose.prod.yml
|
||||
# curl -fsSL $CDN/.env.production -o /data/coolify/source/.env.production
|
||||
# curl -fsSL $CDN/upgrade.sh -o /data/coolify/source/upgrade.sh
|
||||
|
||||
echo "Copying required files from Last Hour git repo..."
|
||||
cp /home/lasthour/lasthourcloud/docker-compose.yml /data/coolify/source/docker-compose.yml
|
||||
cp /home/lasthour/lasthourcloud/docker-compose.prod.yml /data/coolify/source/docker-compose.prod.yml
|
||||
cp /home/lasthour/lasthourcloud/.env.production /data/coolify/source/.env.production
|
||||
cp /home/lasthour/lasthourcloud/scripts/upgrade.sh /data/coolify/source/upgrade.sh
|
||||
|
||||
|
||||
chown -R 9999:root /data/coolify
|
||||
chmod -R 700 /data/coolify
|
||||
|
||||
# Copy .env.example if .env does not exist
|
||||
if [ ! -f /data/coolify/source/.env ]; then
|
||||
cp /data/coolify/source/.env.production /data/coolify/source/.env
|
||||
sed -i "s|APP_ID=.*|APP_ID=$(openssl rand -hex 16)|g" /data/coolify/source/.env
|
||||
sed -i "s|APP_KEY=.*|APP_KEY=base64:$(openssl rand -base64 32)|g" /data/coolify/source/.env
|
||||
sed -i "s|DB_PASSWORD=.*|DB_PASSWORD=$(openssl rand -base64 32)|g" /data/coolify/source/.env
|
||||
sed -i "s|REDIS_PASSWORD=.*|REDIS_PASSWORD=$(openssl rand -base64 32)|g" /data/coolify/source/.env
|
||||
sed -i "s|PUSHER_APP_ID=.*|PUSHER_APP_ID=$(openssl rand -hex 32)|g" /data/coolify/source/.env
|
||||
sed -i "s|PUSHER_APP_KEY=.*|PUSHER_APP_KEY=$(openssl rand -hex 32)|g" /data/coolify/source/.env
|
||||
sed -i "s|PUSHER_APP_SECRET=.*|PUSHER_APP_SECRET=$(openssl rand -hex 32)|g" /data/coolify/source/.env
|
||||
fi
|
||||
|
||||
# Merge .env and .env.production. New values will be added to .env
|
||||
sort -u -t '=' -k 1,1 /data/coolify/source/.env /data/coolify/source/.env.production | sed '/^$/d' >/data/coolify/source/.env.temp && mv /data/coolify/source/.env.temp /data/coolify/source/.env
|
||||
|
||||
if [ "$AUTOUPDATE" = "false" ]; then
|
||||
if ! grep -q "AUTOUPDATE=" /data/coolify/source/.env; then
|
||||
echo "AUTOUPDATE=false" >>/data/coolify/source/.env
|
||||
else
|
||||
sed -i "s|AUTOUPDATE=.*|AUTOUPDATE=false|g" /data/coolify/source/.env
|
||||
fi
|
||||
fi
|
||||
|
||||
# Generate an ssh key (ed25519) at /data/coolify/ssh/keys/id.root@host.docker.internal
|
||||
if [ ! -f /data/coolify/ssh/keys/id.root@host.docker.internal ]; then
|
||||
ssh-keygen -t ed25519 -a 100 -f /data/coolify/ssh/keys/id.root@host.docker.internal -q -N "" -C root@coolify
|
||||
chown 9999 /data/coolify/ssh/keys/id.root@host.docker.internal
|
||||
fi
|
||||
|
||||
addSshKey() {
|
||||
cat /data/coolify/ssh/keys/id.root@host.docker.internal.pub >>~/.ssh/authorized_keys
|
||||
chmod 600 ~/.ssh/authorized_keys
|
||||
}
|
||||
|
||||
if [ ! -f ~/.ssh/authorized_keys ]; then
|
||||
mkdir -p ~/.ssh
|
||||
chmod 700 ~/.ssh
|
||||
touch ~/.ssh/authorized_keys
|
||||
addSshKey
|
||||
fi
|
||||
|
||||
if ! grep -qw "root@coolify" ~/.ssh/authorized_keys; then
|
||||
addSshKey
|
||||
fi
|
||||
echo "Generated SSH access"
|
||||
|
||||
echo "Begin upgrade.sh"
|
||||
bash /data/coolify/source/upgrade.sh "${LATEST_VERSION:-latest}"
|
||||
|
||||
echo -e "\nCongratulations! Your Coolify instance is ready to use.\n"
|
||||
echo "Please visit http://$(curl -4s https://ifconfig.io):8000 to get started."
|
@ -2,17 +2,17 @@
|
||||
## Do not modify this file. You will lose the ability to autoupdate!
|
||||
|
||||
VERSION="1.0.5"
|
||||
CDN="https://cdn.coollabs.io/coolify"
|
||||
CDN="https://cdn.githaven.org/lasthourcloud"
|
||||
|
||||
# curl -fsSL $CDN/docker-compose.yml -o /data/coolify/source/docker-compose.yml
|
||||
# curl -fsSL $CDN/docker-compose.prod.yml -o /data/coolify/source/docker-compose.prod.yml
|
||||
# curl -fsSL $CDN/.env.production -o /data/coolify/source/.env.production
|
||||
curl -fsSL $CDN/docker-compose.yml -o /data/coolify/source/docker-compose.yml
|
||||
curl -fsSL $CDN/docker-compose.prod.yml -o /data/coolify/source/docker-compose.prod.yml
|
||||
curl -fsSL $CDN/.env.production -o /data/coolify/source/.env.production
|
||||
|
||||
echo "Copying required files from Last Hour git repo..."
|
||||
cp /home/lasthour/lasthourcloud/docker-compose.yml /data/coolify/source/docker-compose.yml
|
||||
cp /home/lasthour/lasthourcloud/docker-compose.prod.yml /data/coolify/source/docker-compose.prod.yml
|
||||
cp /home/lasthour/lasthourcloud/.env.production /data/coolify/source/.env.production
|
||||
cp /home/lasthour/lasthourcloud/scripts/upgrade.sh /data/coolify/source/upgrade.sh
|
||||
# echo "Copying required files from Last Hour Cloud git repo..."
|
||||
# cp /home/lasthour/lasthourcloud/docker-compose.yml /data/coolify/source/docker-compose.yml
|
||||
# cp /home/lasthour/lasthourcloud/docker-compose.prod.yml /data/coolify/source/docker-compose.prod.yml
|
||||
# cp /home/lasthour/lasthourcloud/.env.production /data/coolify/source/.env.production
|
||||
# cp /home/lasthour/lasthourcloud/scripts/upgrade.sh /data/coolify/source/upgrade.sh
|
||||
|
||||
|
||||
# Merge .env and .env.production. New values will be added to .env
|
||||
|
@ -41,7 +41,7 @@ module.exports = {
|
||||
primary: "#202020",
|
||||
"primary-focus": "#242424",
|
||||
secondary: "#00bcf3",
|
||||
accent: "#4338ca",
|
||||
accent: "#00bff7",
|
||||
neutral: "#1B1D1D",
|
||||
"base-100": "#101010",
|
||||
info: "#2563EB",
|
||||
|
Loading…
x
Reference in New Issue
Block a user