Merge branch 'next' into next
This commit is contained in:
@@ -3,6 +3,7 @@
|
||||
namespace App\Actions\Application;
|
||||
|
||||
use App\Actions\Server\CleanupDocker;
|
||||
use App\Events\ServiceStatusChanged;
|
||||
use App\Models\Application;
|
||||
use Lorisleiva\Actions\Concerns\AsAction;
|
||||
|
||||
@@ -14,6 +15,7 @@ class StopApplication
|
||||
|
||||
public function handle(Application $application, bool $previewDeployments = false, bool $dockerCleanup = true)
|
||||
{
|
||||
ray('StopApplication');
|
||||
try {
|
||||
$server = $application->destination->server;
|
||||
if (! $server->isFunctional()) {
|
||||
@@ -38,6 +40,8 @@ class StopApplication
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
return $e->getMessage();
|
||||
} finally {
|
||||
ServiceStatusChanged::dispatch($application->environment->project->team->id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
namespace App\Actions\Database;
|
||||
|
||||
use App\Actions\Server\CleanupDocker;
|
||||
use App\Events\ServiceStatusChanged;
|
||||
use App\Models\StandaloneClickhouse;
|
||||
use App\Models\StandaloneDragonfly;
|
||||
use App\Models\StandaloneKeydb;
|
||||
@@ -19,23 +20,30 @@ class StopDatabase
|
||||
|
||||
public function handle(StandaloneRedis|StandalonePostgresql|StandaloneMongodb|StandaloneMysql|StandaloneMariadb|StandaloneKeydb|StandaloneDragonfly|StandaloneClickhouse $database, bool $isDeleteOperation = false, bool $dockerCleanup = true)
|
||||
{
|
||||
$server = $database->destination->server;
|
||||
if (! $server->isFunctional()) {
|
||||
return 'Server is not functional';
|
||||
}
|
||||
|
||||
$this->stopContainer($database, $database->uuid, 30);
|
||||
if ($isDeleteOperation) {
|
||||
if ($dockerCleanup) {
|
||||
CleanupDocker::dispatch($server, true);
|
||||
try {
|
||||
$server = $database->destination->server;
|
||||
if (! $server->isFunctional()) {
|
||||
return 'Server is not functional';
|
||||
}
|
||||
|
||||
$this->stopContainer($database, $database->uuid, 30);
|
||||
if ($isDeleteOperation) {
|
||||
if ($dockerCleanup) {
|
||||
CleanupDocker::dispatch($server, true);
|
||||
}
|
||||
}
|
||||
|
||||
if ($database->is_public) {
|
||||
StopDatabaseProxy::run($database);
|
||||
}
|
||||
|
||||
return 'Database stopped successfully';
|
||||
} catch (\Exception $e) {
|
||||
return 'Database stop failed: '.$e->getMessage();
|
||||
} finally {
|
||||
ServiceStatusChanged::dispatch($database->environment->project->team->id);
|
||||
}
|
||||
|
||||
if ($database->is_public) {
|
||||
StopDatabaseProxy::run($database);
|
||||
}
|
||||
|
||||
return 'Database stopped successfully';
|
||||
}
|
||||
|
||||
private function stopContainer($database, string $containerName, int $timeout = 30): void
|
||||
|
||||
@@ -4,6 +4,7 @@ namespace App\Actions\Docker;
|
||||
|
||||
use App\Actions\Database\StartDatabaseProxy;
|
||||
use App\Actions\Shared\ComplexStatusCheck;
|
||||
use App\Events\ServiceChecked;
|
||||
use App\Models\ApplicationPreview;
|
||||
use App\Models\Server;
|
||||
use App\Models\ServiceDatabase;
|
||||
@@ -341,5 +342,6 @@ class GetContainersStatus
|
||||
}
|
||||
// $this->server->team?->notify(new ContainerStopped($containerName, $this->server, $url));
|
||||
}
|
||||
ServiceChecked::dispatch($this->server->team->id);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,7 +84,7 @@ class CheckUpdates
|
||||
$out['osId'] = $osId;
|
||||
$out['package_manager'] = $packageManager;
|
||||
$rebootRequired = instant_remote_process(['LANG=C dnf needs-restarting -r'], $server);
|
||||
$out['reboot_required'] = $rebootRequired === '0' ? true : false;
|
||||
$out['reboot_required'] = $rebootRequired !== '0';
|
||||
|
||||
return $out;
|
||||
case 'apt':
|
||||
|
||||
@@ -49,33 +49,4 @@ class UpdatePackage
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
private function parseAptOutput(string $output): array
|
||||
{
|
||||
$updates = [];
|
||||
$lines = explode("\n", $output);
|
||||
|
||||
foreach ($lines as $line) {
|
||||
// Skip the "Listing... Done" line and empty lines
|
||||
if (empty($line) || str_contains($line, 'Listing...')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Example line: package/stable 2.0-1 amd64 [upgradable from: 1.0-1]
|
||||
if (preg_match('/^(.+?)\/(\S+)\s+(\S+)\s+(\S+)\s+\[upgradable from: (.+?)\]/', $line, $matches)) {
|
||||
$updates[] = [
|
||||
'package' => $matches[1],
|
||||
'repository' => $matches[2],
|
||||
'new_version' => $matches[3],
|
||||
'architecture' => $matches[4],
|
||||
'current_version' => $matches[5],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
return [
|
||||
'total_updates' => count($updates),
|
||||
'updates' => $updates,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,6 +41,6 @@ class StartService
|
||||
}
|
||||
}
|
||||
|
||||
return remote_process($commands, $service->server, type_uuid: $service->uuid, callEventOnFinish: 'ServiceStatusChanged');
|
||||
return remote_process($commands, $service->server, type_uuid: $service->uuid);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
namespace App\Actions\Service;
|
||||
|
||||
use App\Actions\Server\CleanupDocker;
|
||||
use App\Events\ServiceStatusChanged;
|
||||
use App\Models\Service;
|
||||
use Lorisleiva\Actions\Concerns\AsAction;
|
||||
|
||||
@@ -31,6 +32,8 @@ class StopService
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
return $e->getMessage();
|
||||
} finally {
|
||||
ServiceStatusChanged::dispatch($service->environment->project->team->id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
35
app/Events/ServiceChecked.php
Normal file
35
app/Events/ServiceChecked.php
Normal file
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
namespace App\Events;
|
||||
|
||||
use Illuminate\Broadcasting\InteractsWithSockets;
|
||||
use Illuminate\Broadcasting\PrivateChannel;
|
||||
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
|
||||
use Illuminate\Foundation\Events\Dispatchable;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
|
||||
class ServiceChecked implements ShouldBroadcast
|
||||
{
|
||||
use Dispatchable, InteractsWithSockets, SerializesModels;
|
||||
|
||||
public ?int $teamId = null;
|
||||
|
||||
public function __construct($teamId = null)
|
||||
{
|
||||
if (is_null($teamId) && auth()->check() && auth()->user()->currentTeam()) {
|
||||
$teamId = auth()->user()->currentTeam()->id;
|
||||
}
|
||||
$this->teamId = $teamId;
|
||||
}
|
||||
|
||||
public function broadcastOn(): array
|
||||
{
|
||||
if (is_null($this->teamId)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return [
|
||||
new PrivateChannel("team.{$this->teamId}"),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -13,24 +13,22 @@ class ServiceStatusChanged implements ShouldBroadcast
|
||||
{
|
||||
use Dispatchable, InteractsWithSockets, SerializesModels;
|
||||
|
||||
public int|string|null $userId = null;
|
||||
|
||||
public function __construct($userId = null)
|
||||
{
|
||||
if (is_null($userId)) {
|
||||
$userId = Auth::id() ?? null;
|
||||
public function __construct(
|
||||
public ?int $teamId = null
|
||||
) {
|
||||
if (is_null($this->teamId) && Auth::check() && Auth::user()->currentTeam()) {
|
||||
$this->teamId = Auth::user()->currentTeam()->id;
|
||||
}
|
||||
$this->userId = $userId;
|
||||
}
|
||||
|
||||
public function broadcastOn(): ?array
|
||||
public function broadcastOn(): array
|
||||
{
|
||||
if (is_null($this->userId)) {
|
||||
if (is_null($this->teamId)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return [
|
||||
new PrivateChannel("user.{$this->userId}"),
|
||||
new PrivateChannel("team.{$this->teamId}"),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -989,7 +989,33 @@ class ApplicationsController extends Controller
|
||||
|
||||
$dockerComposeDomainsJson = collect();
|
||||
if ($request->has('docker_compose_domains')) {
|
||||
$yaml = Yaml::parse($application->docker_compose_raw);
|
||||
if (! $request->has('docker_compose_raw')) {
|
||||
return response()->json([
|
||||
'message' => 'Validation failed.',
|
||||
'errors' => [
|
||||
'docker_compose_raw' => 'The base64 encoded docker_compose_raw is required.',
|
||||
],
|
||||
], 422);
|
||||
}
|
||||
|
||||
if (! isBase64Encoded($request->docker_compose_raw)) {
|
||||
return response()->json([
|
||||
'message' => 'Validation failed.',
|
||||
'errors' => [
|
||||
'docker_compose_raw' => 'The docker_compose_raw should be base64 encoded.',
|
||||
],
|
||||
], 422);
|
||||
}
|
||||
$dockerComposeRaw = base64_decode($request->docker_compose_raw);
|
||||
if (mb_detect_encoding($dockerComposeRaw, 'ASCII', true) === false) {
|
||||
return response()->json([
|
||||
'message' => 'Validation failed.',
|
||||
'errors' => [
|
||||
'docker_compose_raw' => 'The docker_compose_raw should be base64 encoded.',
|
||||
],
|
||||
], 422);
|
||||
}
|
||||
$yaml = Yaml::parse($dockerComposeRaw);
|
||||
$services = data_get($yaml, 'services');
|
||||
$dockerComposeDomains = collect($request->docker_compose_domains);
|
||||
if ($dockerComposeDomains->count() > 0) {
|
||||
@@ -1095,7 +1121,34 @@ class ApplicationsController extends Controller
|
||||
|
||||
$dockerComposeDomainsJson = collect();
|
||||
if ($request->has('docker_compose_domains')) {
|
||||
$yaml = Yaml::parse($application->docker_compose_raw);
|
||||
if (! $request->has('docker_compose_raw')) {
|
||||
return response()->json([
|
||||
'message' => 'Validation failed.',
|
||||
'errors' => [
|
||||
'docker_compose_raw' => 'The base64 encoded docker_compose_raw is required.',
|
||||
],
|
||||
], 422);
|
||||
}
|
||||
|
||||
if (! isBase64Encoded($request->docker_compose_raw)) {
|
||||
return response()->json([
|
||||
'message' => 'Validation failed.',
|
||||
'errors' => [
|
||||
'docker_compose_raw' => 'The docker_compose_raw should be base64 encoded.',
|
||||
],
|
||||
], 422);
|
||||
}
|
||||
$dockerComposeRaw = base64_decode($request->docker_compose_raw);
|
||||
if (mb_detect_encoding($dockerComposeRaw, 'ASCII', true) === false) {
|
||||
return response()->json([
|
||||
'message' => 'Validation failed.',
|
||||
'errors' => [
|
||||
'docker_compose_raw' => 'The docker_compose_raw should be base64 encoded.',
|
||||
],
|
||||
], 422);
|
||||
}
|
||||
$dockerComposeRaw = base64_decode($request->docker_compose_raw);
|
||||
$yaml = Yaml::parse($dockerComposeRaw);
|
||||
$services = data_get($yaml, 'services');
|
||||
$dockerComposeDomains = collect($request->docker_compose_domains);
|
||||
if ($dockerComposeDomains->count() > 0) {
|
||||
@@ -1918,7 +1971,34 @@ class ApplicationsController extends Controller
|
||||
|
||||
$dockerComposeDomainsJson = collect();
|
||||
if ($request->has('docker_compose_domains')) {
|
||||
$yaml = Yaml::parse($application->docker_compose_raw);
|
||||
if (! $request->has('docker_compose_raw')) {
|
||||
return response()->json([
|
||||
'message' => 'Validation failed.',
|
||||
'errors' => [
|
||||
'docker_compose_raw' => 'The base64 encoded docker_compose_raw is required.',
|
||||
],
|
||||
], 422);
|
||||
}
|
||||
|
||||
if (! isBase64Encoded($request->docker_compose_raw)) {
|
||||
return response()->json([
|
||||
'message' => 'Validation failed.',
|
||||
'errors' => [
|
||||
'docker_compose_raw' => 'The docker_compose_raw should be base64 encoded.',
|
||||
],
|
||||
], 422);
|
||||
}
|
||||
$dockerComposeRaw = base64_decode($request->docker_compose_raw);
|
||||
if (mb_detect_encoding($dockerComposeRaw, 'ASCII', true) === false) {
|
||||
return response()->json([
|
||||
'message' => 'Validation failed.',
|
||||
'errors' => [
|
||||
'docker_compose_raw' => 'The docker_compose_raw should be base64 encoded.',
|
||||
],
|
||||
], 422);
|
||||
}
|
||||
$dockerComposeRaw = base64_decode($request->docker_compose_raw);
|
||||
$yaml = Yaml::parse($dockerComposeRaw);
|
||||
$services = data_get($yaml, 'services');
|
||||
$dockerComposeDomains = collect($request->docker_compose_domains);
|
||||
if ($dockerComposeDomains->count() > 0) {
|
||||
|
||||
@@ -319,9 +319,10 @@ class DeployController extends Controller
|
||||
default:
|
||||
// Database resource
|
||||
StartDatabase::dispatch($resource);
|
||||
$resource->update([
|
||||
'started_at' => now(),
|
||||
]);
|
||||
|
||||
$resource->started_at ??= now();
|
||||
$resource->save();
|
||||
|
||||
$message = "Database {$resource->name} started.";
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ namespace App\Jobs;
|
||||
use App\Actions\Docker\GetContainersStatus;
|
||||
use App\Enums\ApplicationDeploymentStatus;
|
||||
use App\Enums\ProcessStatus;
|
||||
use App\Events\ApplicationStatusChanged;
|
||||
use App\Events\ServiceStatusChanged;
|
||||
use App\Models\Application;
|
||||
use App\Models\ApplicationDeploymentQueue;
|
||||
use App\Models\ApplicationPreview;
|
||||
@@ -331,7 +331,7 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
|
||||
$this->application_deployment_queue->addLogEntry("Gracefully shutting down build container: {$this->deployment_uuid}");
|
||||
$this->graceful_shutdown_container($this->deployment_uuid);
|
||||
|
||||
ApplicationStatusChanged::dispatch(data_get($this->application, 'environment.project.team.id'));
|
||||
ServiceStatusChanged::dispatch(data_get($this->application, 'environment.project.team.id'));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -507,7 +507,11 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
|
||||
if ($this->env_filename) {
|
||||
$command .= " --env-file {$this->workdir}/{$this->env_filename}";
|
||||
}
|
||||
$command .= " --project-name {$this->application->uuid} --project-directory {$this->workdir} -f {$this->workdir}{$this->docker_compose_location} build --pull";
|
||||
if ($this->force_rebuild) {
|
||||
$command .= " --project-name {$this->application->uuid} --project-directory {$this->workdir} -f {$this->workdir}{$this->docker_compose_location} build --pull --no-cache";
|
||||
} else {
|
||||
$command .= " --project-name {$this->application->uuid} --project-directory {$this->workdir} -f {$this->workdir}{$this->docker_compose_location} build --pull";
|
||||
}
|
||||
$this->execute_remote_command(
|
||||
[executeInDocker($this->deployment_uuid, $command), 'hidden' => true],
|
||||
);
|
||||
|
||||
@@ -17,7 +17,15 @@ class Configuration extends Component
|
||||
|
||||
public $servers;
|
||||
|
||||
protected $listeners = ['buildPackUpdated' => '$refresh'];
|
||||
public function getListeners()
|
||||
{
|
||||
$teamId = auth()->user()->currentTeam()->id;
|
||||
|
||||
return [
|
||||
"echo-private:team.{$teamId},ServiceChecked" => '$refresh',
|
||||
'buildPackUpdated' => '$refresh',
|
||||
];
|
||||
}
|
||||
|
||||
public function mount()
|
||||
{
|
||||
|
||||
@@ -28,6 +28,15 @@ class Index extends Component
|
||||
|
||||
protected $queryString = ['pull_request_id'];
|
||||
|
||||
public function getListeners()
|
||||
{
|
||||
$teamId = auth()->user()->currentTeam()->id;
|
||||
|
||||
return [
|
||||
"echo-private:team.{$teamId},ServiceChecked" => '$refresh',
|
||||
];
|
||||
}
|
||||
|
||||
public function mount()
|
||||
{
|
||||
$project = currentTeam()->load(['projects'])->projects->where('uuid', request()->route('project_uuid'))->first();
|
||||
|
||||
@@ -18,7 +18,15 @@ class Show extends Component
|
||||
|
||||
public $isKeepAliveOn = true;
|
||||
|
||||
protected $listeners = ['refreshQueue'];
|
||||
public function getListeners()
|
||||
{
|
||||
$teamId = auth()->user()->currentTeam()->id;
|
||||
|
||||
return [
|
||||
"echo-private:team.{$teamId},ServiceChecked" => '$refresh',
|
||||
'refreshQueue',
|
||||
];
|
||||
}
|
||||
|
||||
public function mount()
|
||||
{
|
||||
|
||||
@@ -4,7 +4,6 @@ namespace App\Livewire\Project\Application;
|
||||
|
||||
use App\Actions\Application\StopApplication;
|
||||
use App\Actions\Docker\GetContainersStatus;
|
||||
use App\Events\ApplicationStatusChanged;
|
||||
use App\Models\Application;
|
||||
use Livewire\Component;
|
||||
use Visus\Cuid2\Cuid2;
|
||||
@@ -28,7 +27,8 @@ class Heading extends Component
|
||||
$teamId = auth()->user()->currentTeam()->id;
|
||||
|
||||
return [
|
||||
"echo-private:team.{$teamId},ApplicationStatusChanged" => 'check_status',
|
||||
"echo-private:team.{$teamId},ServiceStatusChanged" => 'checkStatus',
|
||||
"echo-private:team.{$teamId},ServiceChecked" => '$refresh',
|
||||
'compose_loaded' => '$refresh',
|
||||
'update_links' => '$refresh',
|
||||
];
|
||||
@@ -46,13 +46,12 @@ class Heading extends Component
|
||||
$this->lastDeploymentLink = $this->application->gitCommitLink(data_get($lastDeployment, 'commit'));
|
||||
}
|
||||
|
||||
public function check_status($showNotification = false)
|
||||
public function checkStatus()
|
||||
{
|
||||
if ($this->application->destination->server->isFunctional()) {
|
||||
GetContainersStatus::dispatch($this->application->destination->server);
|
||||
}
|
||||
if ($showNotification) {
|
||||
$this->dispatch('success', 'Success', 'Application status updated.');
|
||||
} else {
|
||||
$this->dispatch('error', 'Server is not functional.');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -111,16 +110,8 @@ class Heading extends Component
|
||||
|
||||
public function stop()
|
||||
{
|
||||
StopApplication::run($this->application, false, $this->docker_cleanup);
|
||||
$this->application->status = 'exited';
|
||||
$this->application->save();
|
||||
if ($this->application->additional_servers->count() > 0) {
|
||||
$this->application->additional_servers->each(function ($server) {
|
||||
$server->pivot->status = 'exited:unhealthy';
|
||||
$server->pivot->save();
|
||||
});
|
||||
}
|
||||
ApplicationStatusChanged::dispatch(data_get($this->application, 'environment.project.team.id'));
|
||||
$this->dispatch('info', 'Gracefully stopping application, it could take a while depending on the application.');
|
||||
StopApplication::dispatch($this->application, false, $this->docker_cleanup);
|
||||
}
|
||||
|
||||
public function restart()
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace App\Livewire\Project\Database;
|
||||
|
||||
use Auth;
|
||||
use Livewire\Component;
|
||||
|
||||
class Configuration extends Component
|
||||
@@ -14,6 +15,15 @@ class Configuration extends Component
|
||||
|
||||
public $environment;
|
||||
|
||||
public function getListeners()
|
||||
{
|
||||
$teamId = Auth::user()->currentTeam()->id;
|
||||
|
||||
return [
|
||||
"echo-private:team.{$teamId},ServiceChecked" => '$refresh',
|
||||
];
|
||||
}
|
||||
|
||||
public function mount()
|
||||
{
|
||||
$this->currentRoute = request()->route()->getName();
|
||||
|
||||
@@ -6,7 +6,7 @@ use App\Actions\Database\RestartDatabase;
|
||||
use App\Actions\Database\StartDatabase;
|
||||
use App\Actions\Database\StopDatabase;
|
||||
use App\Actions\Docker\GetContainersStatus;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use App\Events\ServiceStatusChanged;
|
||||
use Livewire\Component;
|
||||
|
||||
class Heading extends Component
|
||||
@@ -19,36 +19,40 @@ class Heading extends Component
|
||||
|
||||
public function getListeners()
|
||||
{
|
||||
$userId = Auth::id();
|
||||
$teamId = auth()->user()->currentTeam()->id;
|
||||
|
||||
return [
|
||||
"echo-private:user.{$userId},DatabaseStatusChanged" => 'activityFinished',
|
||||
"echo-private:team.{$teamId},ServiceStatusChanged" => 'checkStatus',
|
||||
"echo-private:team.{$teamId},ServiceChecked" => 'activityFinished',
|
||||
'refresh' => '$refresh',
|
||||
'compose_loaded' => '$refresh',
|
||||
'update_links' => '$refresh',
|
||||
];
|
||||
}
|
||||
|
||||
public function activityFinished()
|
||||
{
|
||||
$this->database->update([
|
||||
'started_at' => now(),
|
||||
]);
|
||||
$this->check_status();
|
||||
try {
|
||||
$this->database->started_at ??= now();
|
||||
$this->database->save();
|
||||
|
||||
if (is_null($this->database->config_hash) || $this->database->isConfigurationChanged()) {
|
||||
$this->database->isConfigurationChanged(true);
|
||||
$this->dispatch('configurationChanged');
|
||||
} else {
|
||||
if (is_null($this->database->config_hash) || $this->database->isConfigurationChanged()) {
|
||||
$this->database->isConfigurationChanged(true);
|
||||
}
|
||||
$this->dispatch('configurationChanged');
|
||||
} catch (\Exception $e) {
|
||||
return handleError($e, $this);
|
||||
} finally {
|
||||
$this->dispatch('refresh');
|
||||
}
|
||||
}
|
||||
|
||||
public function check_status($showNotification = false)
|
||||
public function checkStatus()
|
||||
{
|
||||
if ($this->database->destination->server->isFunctional()) {
|
||||
GetContainersStatus::run($this->database->destination->server);
|
||||
}
|
||||
|
||||
if ($showNotification) {
|
||||
$this->dispatch('success', 'Database status updated.');
|
||||
GetContainersStatus::dispatch($this->database->destination->server);
|
||||
} else {
|
||||
$this->dispatch('error', 'Server is not functional.');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,23 +63,24 @@ class Heading extends Component
|
||||
|
||||
public function stop()
|
||||
{
|
||||
StopDatabase::run($this->database, false, $this->docker_cleanup);
|
||||
$this->database->status = 'exited';
|
||||
$this->database->save();
|
||||
$this->check_status();
|
||||
$this->dispatch('refresh');
|
||||
try {
|
||||
$this->dispatch('info', 'Gracefully stopping database, it could take a while depending on the size of the database.');
|
||||
StopDatabase::dispatch($this->database, false, $this->docker_cleanup);
|
||||
} catch (\Exception $e) {
|
||||
$this->dispatch('error', $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function restart()
|
||||
{
|
||||
$activity = RestartDatabase::run($this->database);
|
||||
$this->dispatch('activityMonitor', $activity->id);
|
||||
$this->dispatch('activityMonitor', $activity->id, ServiceStatusChanged::class);
|
||||
}
|
||||
|
||||
public function start()
|
||||
{
|
||||
$activity = StartDatabase::run($this->database);
|
||||
$this->dispatch('activityMonitor', $activity->id);
|
||||
$this->dispatch('activityMonitor', $activity->id, ServiceStatusChanged::class);
|
||||
}
|
||||
|
||||
public function render()
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
namespace App\Livewire\Project\Service;
|
||||
|
||||
use App\Actions\Docker\GetContainersStatus;
|
||||
use App\Models\Service;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Livewire\Component;
|
||||
@@ -27,13 +26,10 @@ class Configuration extends Component
|
||||
|
||||
public function getListeners()
|
||||
{
|
||||
$userId = Auth::id();
|
||||
$teamId = Auth::user()->currentTeam()->id;
|
||||
|
||||
return [
|
||||
"echo-private:user.{$userId},ServiceStatusChanged" => 'check_status',
|
||||
'refreshStatus' => '$refresh',
|
||||
'check_status',
|
||||
'refreshServices',
|
||||
"echo-private:team.{$teamId},ServiceChecked" => 'serviceChecked',
|
||||
];
|
||||
}
|
||||
|
||||
@@ -97,19 +93,15 @@ class Configuration extends Component
|
||||
}
|
||||
}
|
||||
|
||||
public function check_status()
|
||||
public function serviceChecked()
|
||||
{
|
||||
try {
|
||||
if ($this->service->server->isFunctional()) {
|
||||
GetContainersStatus::dispatch($this->service->server);
|
||||
}
|
||||
$this->service->applications->each(function ($application) {
|
||||
$application->refresh();
|
||||
});
|
||||
$this->service->databases->each(function ($database) {
|
||||
$database->refresh();
|
||||
});
|
||||
$this->dispatch('refreshStatus');
|
||||
} catch (\Exception $e) {
|
||||
return handleError($e, $this);
|
||||
}
|
||||
|
||||
@@ -47,7 +47,6 @@ class EditDomain extends Component
|
||||
$this->application->service->parse();
|
||||
$this->dispatch('refresh');
|
||||
$this->dispatch('configurationChanged');
|
||||
$this->dispatch('refreshStatus');
|
||||
} catch (\Throwable $e) {
|
||||
$originalFqdn = $this->application->getOriginal('fqdn');
|
||||
if ($originalFqdn !== $this->application->fqdn) {
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace App\Livewire\Project\Service;
|
||||
|
||||
use App\Actions\Docker\GetContainersStatus;
|
||||
use App\Actions\Service\StartService;
|
||||
use App\Actions\Service\StopService;
|
||||
use App\Enums\ProcessStatus;
|
||||
@@ -11,7 +12,7 @@ use Illuminate\Support\Facades\Auth;
|
||||
use Livewire\Component;
|
||||
use Spatie\Activitylog\Models\Activity;
|
||||
|
||||
class Navbar extends Component
|
||||
class Heading extends Component
|
||||
{
|
||||
public Service $service;
|
||||
|
||||
@@ -35,35 +36,44 @@ class Navbar extends Component
|
||||
|
||||
public function getListeners()
|
||||
{
|
||||
$userId = Auth::id();
|
||||
$teamId = Auth::user()->currentTeam()->id;
|
||||
|
||||
return [
|
||||
"echo-private:user.{$userId},ServiceStatusChanged" => 'serviceStarted',
|
||||
"echo-private:team.{$teamId},ServiceStatusChanged" => 'checkStatus',
|
||||
"echo-private:team.{$teamId},ServiceChecked" => 'serviceChecked',
|
||||
'refresh' => '$refresh',
|
||||
'envsUpdated' => '$refresh',
|
||||
'refreshStatus' => '$refresh',
|
||||
];
|
||||
}
|
||||
|
||||
public function serviceStarted()
|
||||
public function checkStatus()
|
||||
{
|
||||
// $this->dispatch('success', 'Service status changed.');
|
||||
if (is_null($this->service->config_hash) || $this->service->isConfigurationChanged()) {
|
||||
$this->service->isConfigurationChanged(true);
|
||||
$this->dispatch('configurationChanged');
|
||||
if ($this->service->server->isFunctional()) {
|
||||
GetContainersStatus::dispatch($this->service->server);
|
||||
} else {
|
||||
$this->dispatch('configurationChanged');
|
||||
$this->dispatch('error', 'Server is not functional.');
|
||||
}
|
||||
}
|
||||
|
||||
public function check_status_without_notification()
|
||||
public function serviceChecked()
|
||||
{
|
||||
$this->dispatch('check_status');
|
||||
}
|
||||
try {
|
||||
$this->service->applications->each(function ($application) {
|
||||
$application->refresh();
|
||||
});
|
||||
$this->service->databases->each(function ($database) {
|
||||
$database->refresh();
|
||||
});
|
||||
if (is_null($this->service->config_hash) || $this->service->isConfigurationChanged()) {
|
||||
$this->service->isConfigurationChanged(true);
|
||||
}
|
||||
$this->dispatch('configurationChanged');
|
||||
} catch (\Exception $e) {
|
||||
return handleError($e, $this);
|
||||
} finally {
|
||||
$this->dispatch('refresh')->self();
|
||||
}
|
||||
|
||||
public function check_status()
|
||||
{
|
||||
$this->dispatch('check_status');
|
||||
$this->dispatch('success', 'Service status updated.');
|
||||
}
|
||||
|
||||
public function checkDeployments()
|
||||
@@ -86,34 +96,33 @@ class Navbar extends Component
|
||||
public function start()
|
||||
{
|
||||
$activity = StartService::run($this->service, pullLatestImages: true);
|
||||
$this->dispatch('activityMonitor', $activity->id);
|
||||
$this->dispatch('activityMonitor', $activity->id, ServiceStatusChanged::class);
|
||||
}
|
||||
|
||||
public function forceDeploy()
|
||||
{
|
||||
try {
|
||||
$activities = Activity::where('properties->type_uuid', $this->service->uuid)->where('properties->status', ProcessStatus::IN_PROGRESS->value)->orWhere('properties->status', ProcessStatus::QUEUED->value)->get();
|
||||
$activities = Activity::where('properties->type_uuid', $this->service->uuid)
|
||||
->where(function ($q) {
|
||||
$q->where('properties->status', ProcessStatus::IN_PROGRESS->value)
|
||||
->orWhere('properties->status', ProcessStatus::QUEUED->value);
|
||||
})->get();
|
||||
foreach ($activities as $activity) {
|
||||
$activity->properties->status = ProcessStatus::ERROR->value;
|
||||
$activity->save();
|
||||
}
|
||||
$activity = StartService::run($this->service, pullLatestImages: true, stopBeforeStart: true);
|
||||
$this->dispatch('activityMonitor', $activity->id);
|
||||
$this->dispatch('activityMonitor', $activity->id, ServiceStatusChanged::class);
|
||||
} catch (\Exception $e) {
|
||||
$this->dispatch('error', $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function stop($cleanupContainers = false)
|
||||
public function stop()
|
||||
{
|
||||
try {
|
||||
StopService::run($this->service, false, $this->docker_cleanup);
|
||||
ServiceStatusChanged::dispatch();
|
||||
if ($cleanupContainers) {
|
||||
$this->dispatch('success', 'Containers cleaned up.');
|
||||
} else {
|
||||
$this->dispatch('success', 'Service stopped.');
|
||||
}
|
||||
$this->dispatch('info', 'Gracefully stopping service, it could take a while depending on the service.');
|
||||
StopService::dispatch($this->service, false, $this->docker_cleanup);
|
||||
} catch (\Exception $e) {
|
||||
$this->dispatch('error', $e->getMessage());
|
||||
}
|
||||
@@ -128,7 +137,7 @@ class Navbar extends Component
|
||||
return;
|
||||
}
|
||||
$activity = StartService::run($this->service, stopBeforeStart: true);
|
||||
$this->dispatch('activityMonitor', $activity->id);
|
||||
$this->dispatch('activityMonitor', $activity->id, ServiceStatusChanged::class);
|
||||
}
|
||||
|
||||
public function pullAndRestartEvent()
|
||||
@@ -140,12 +149,12 @@ class Navbar extends Component
|
||||
return;
|
||||
}
|
||||
$activity = StartService::run($this->service, pullLatestImages: true, stopBeforeStart: true);
|
||||
$this->dispatch('activityMonitor', $activity->id);
|
||||
$this->dispatch('activityMonitor', $activity->id, ServiceStatusChanged::class);
|
||||
}
|
||||
|
||||
public function render()
|
||||
{
|
||||
return view('livewire.project.service.navbar', [
|
||||
return view('livewire.project.service.heading', [
|
||||
'checkboxes' => [
|
||||
['id' => 'docker_cleanup', 'label' => __('resource.docker_cleanup')],
|
||||
],
|
||||
@@ -119,17 +119,14 @@ class Destination extends Component
|
||||
public function refreshServers()
|
||||
{
|
||||
GetContainersStatus::run($this->resource->destination->server);
|
||||
// ContainerStatusJob::dispatchSync($this->resource->destination->server);
|
||||
$this->loadData();
|
||||
$this->dispatch('refresh');
|
||||
ApplicationStatusChanged::dispatch(data_get($this->resource, 'environment.project.team.id'));
|
||||
}
|
||||
|
||||
public function addServer(int $network_id, int $server_id)
|
||||
{
|
||||
$this->resource->additional_networks()->attach($network_id, ['server_id' => $server_id]);
|
||||
$this->loadData();
|
||||
ApplicationStatusChanged::dispatch(data_get($this->resource, 'environment.project.team.id'));
|
||||
}
|
||||
|
||||
public function removeServer(int $network_id, int $server_id, $password)
|
||||
|
||||
@@ -35,6 +35,15 @@ class ExecuteContainerCommand extends Component
|
||||
'command' => 'required',
|
||||
];
|
||||
|
||||
public function getListeners()
|
||||
{
|
||||
$teamId = auth()->user()->currentTeam()->id;
|
||||
|
||||
return [
|
||||
"echo-private:team.{$teamId},ServiceChecked" => '$refresh',
|
||||
];
|
||||
}
|
||||
|
||||
public function mount()
|
||||
{
|
||||
if (! auth()->user()->isAdmin()) {
|
||||
|
||||
@@ -37,6 +37,15 @@ class Logs extends Component
|
||||
|
||||
public $cpu;
|
||||
|
||||
public function getListeners()
|
||||
{
|
||||
$teamId = auth()->user()->currentTeam()->id;
|
||||
|
||||
return [
|
||||
"echo-private:team.{$teamId},ServiceChecked" => '$refresh',
|
||||
];
|
||||
}
|
||||
|
||||
public function loadContainers($server_id)
|
||||
{
|
||||
try {
|
||||
|
||||
@@ -46,6 +46,15 @@ class Show extends Component
|
||||
#[Locked]
|
||||
public string $task_uuid;
|
||||
|
||||
public function getListeners()
|
||||
{
|
||||
$teamId = auth()->user()->currentTeam()->id;
|
||||
|
||||
return [
|
||||
"echo-private:team.{$teamId},ServiceChecked" => '$refresh',
|
||||
];
|
||||
}
|
||||
|
||||
public function mount(string $task_uuid, string $project_uuid, string $environment_uuid, ?string $application_uuid = null, ?string $service_uuid = null)
|
||||
{
|
||||
try {
|
||||
|
||||
@@ -67,8 +67,18 @@ class Patches extends Component
|
||||
|
||||
public function updateAllPackages()
|
||||
{
|
||||
if (! $this->packageManager || ! $this->osId) {
|
||||
$this->dispatch('error', message: 'Run “Check for updates” first.');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
$activity = UpdatePackage::run(server: $this->server, packageManager: $this->packageManager, osId: $this->osId, all: true);
|
||||
$activity = UpdatePackage::run(
|
||||
server: $this->server,
|
||||
packageManager: $this->packageManager,
|
||||
osId: $this->osId,
|
||||
all: true
|
||||
);
|
||||
$this->dispatch('activityMonitor', $activity->id, ServerPackageUpdated::class);
|
||||
} catch (\Exception $e) {
|
||||
$this->dispatch('error', message: $e->getMessage());
|
||||
|
||||
@@ -25,11 +25,11 @@ class OauthSetting extends Model
|
||||
{
|
||||
switch ($this->provider) {
|
||||
case 'azure':
|
||||
return filled($this->client_id) && filled($this->client_secret) && filled($this->redirect_uri) && filled($this->tenant);
|
||||
return filled($this->client_id) && filled($this->client_secret) && filled($this->tenant);
|
||||
case 'authentik':
|
||||
return filled($this->client_id) && filled($this->client_secret) && filled($this->redirect_uri) && filled($this->base_url);
|
||||
return filled($this->client_id) && filled($this->client_secret) && filled($this->base_url);
|
||||
default:
|
||||
return filled($this->client_id) && filled($this->client_secret) && filled($this->redirect_uri);
|
||||
return filled($this->client_id) && filled($this->client_secret);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -478,7 +478,7 @@ function queryDatabaseByUuidWithinTeam(string $uuid, string $teamId)
|
||||
{
|
||||
$postgresql = StandalonePostgresql::whereUuid($uuid)->first();
|
||||
if ($postgresql && $postgresql->team()->id == $teamId) {
|
||||
return $postgresql->unsetRelation('environment')->unsetRelation('destination');
|
||||
return $postgresql->unsetRelation('environment');
|
||||
}
|
||||
$redis = StandaloneRedis::whereUuid($uuid)->first();
|
||||
if ($redis && $redis->team()->id == $teamId) {
|
||||
|
||||
@@ -7,6 +7,10 @@ function get_socialite_provider(string $provider)
|
||||
{
|
||||
$oauth_setting = OauthSetting::firstWhere('provider', $provider);
|
||||
|
||||
if (! filled($oauth_setting->redirect_uri)) {
|
||||
$oauth_setting->update(['redirect_uri' => route('auth.callback', $provider)]);
|
||||
}
|
||||
|
||||
if ($provider === 'azure') {
|
||||
$azure_config = new \SocialiteProviders\Manager\Config(
|
||||
$oauth_setting->client_id,
|
||||
|
||||
6
public/svgs/onetimesecret.svg
Normal file
6
public/svgs/onetimesecret.svg
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg baseProfile="tiny-ps" version="1.2" xmlns="http://www.w3.org/2000/svg" width="1445" height="1445">
|
||||
<title>Onetime Secret</title>
|
||||
<path d="M0 0 C476.85 0 953.7 0 1445 0 C1445 476.85 1445 953.7 1445 1445 C968.15 1445 491.3 1445 0 1445 C0 968.15 0 491.3 0 0 Z " fill="#DC4A22" transform="translate(0,0)"/>
|
||||
<path d="M0 0 C1.12 -0.01 2.23 -0.01 3.38 -0.02 C41.15 -0.21 76.81 2.74 113.82 10.2 C114.86 10.41 115.9 10.62 116.96 10.83 C161.35 20.12 209.54 39.34 243.83 69.46 C245.42 70.85 247.07 72.16 248.73 73.45 C254.39 78.13 258.33 82.3 259.33 89.77 C259.67 94.06 259.76 98.33 259.8 102.63 C259.86 104.53 259.93 106.42 260 108.32 C260.18 113.35 260.29 118.38 260.38 123.41 C260.49 128.6 260.67 133.8 260.84 138.99 C261.1 147.11 261.33 155.23 261.53 163.34 C261.83 175.27 262.35 187.18 262.94 199.09 C263.68 214.47 264.13 229.81 263.82 245.2 C261.17 246.09 259.19 246.43 256.44 246.65 C255.55 246.73 254.67 246.8 253.75 246.87 C252.8 246.95 251.84 247.03 250.85 247.11 C249.85 247.19 248.85 247.27 247.82 247.36 C244.61 247.62 241.41 247.88 238.2 248.14 C220.73 249.55 220.73 249.55 203.3 251.45 C194.21 252.56 185.08 253.29 175.96 254.06 C172.8 254.33 169.65 254.6 166.49 254.88 C164.46 255.05 162.42 255.23 160.39 255.4 C159.46 255.48 158.53 255.56 157.57 255.64 C151.97 256.11 146.45 256.28 140.82 256.2 C138.68 243.45 137 230.7 135.64 217.85 C135.32 214.89 134.98 211.93 134.64 208.97 C132.79 192.63 132.79 192.63 132.36 184.48 C132.15 175.49 132.15 175.49 128.49 167.56 C125.04 164.52 121.18 162.74 116.94 161.07 C114.82 160.2 112.83 159.21 110.8 158.12 C80.32 141.85 47 136.87 12.76 136.77 C11.92 136.76 11.07 136.75 10.2 136.75 C-17.89 136.61 -48.49 141.47 -71.18 159.2 C-72.06 159.8 -72.95 160.4 -73.86 161.02 C-84.5 171.07 -90.16 185.2 -90.57 199.64 C-90.58 201.63 -90.59 203.62 -90.57 205.62 C-90.55 207.63 -90.57 209.65 -90.59 211.67 C-90.53 230.13 -84.96 246.98 -72.01 260.46 C-50.22 280.75 -16.06 289.26 11.82 297.2 C12.92 297.52 12.92 297.52 14.05 297.85 C22.12 300.2 30.25 302.11 38.49 303.8 C39.2 303.94 39.91 304.09 40.64 304.24 C41.37 304.39 42.11 304.54 42.86 304.69 C44.41 305.01 45.96 305.32 47.51 305.64 C48.29 305.8 49.07 305.96 49.88 306.12 C72.96 310.87 95.76 316.81 118.58 322.62 C122.56 323.63 126.54 324.63 130.53 325.61 C139.39 327.79 148.17 330.02 156.82 332.95 C157.82 333.29 158.82 333.63 159.85 333.98 C190.66 344.63 219.58 361 243.57 383.13 C245.59 384.99 247.66 386.75 249.76 388.52 C281.28 416.23 294.78 458.59 298.82 499.2 C298.92 500.14 299.01 501.08 299.11 502.05 C299.92 511.11 300.01 520.14 300.01 529.23 C300.01 531.8 300.03 534.38 300.05 536.95 C300.13 561.32 297.52 587 289.82 610.2 C289.4 611.58 288.98 612.96 288.55 614.34 C280.43 640.37 267.58 664.96 248.89 684.98 C247.03 686.98 245.27 689.04 243.51 691.14 C217.39 720.99 179.38 739.53 142.6 752.24 C140.33 753.03 138.08 753.84 135.84 754.67 C118.41 760.94 99.88 764.04 81.64 766.95 C80.42 767.15 79.2 767.35 77.94 767.55 C56.34 770.86 34.74 771.53 12.93 771.46 C9.31 771.45 5.7 771.46 2.08 771.47 C-20.96 771.53 -43.98 770.84 -66.82 767.54 C-69.76 767.12 -72.71 766.73 -75.66 766.33 C-88.7 764.55 -101.63 762.58 -114.49 759.78 C-117.51 759.13 -120.54 758.5 -123.56 757.86 C-172.26 747.51 -227.93 730.44 -264.18 694.2 C-264.01 682.71 -262.42 671.27 -260.93 659.89 C-260.52 656.79 -260.12 653.69 -259.72 650.59 C-259.61 649.72 -259.5 648.85 -259.38 647.95 C-258.25 638.97 -257.22 629.98 -256.18 620.98 C-253.53 597.94 -250.67 574.93 -247.73 551.92 C-247.1 546.96 -246.47 541.99 -245.84 537.03 C-244.62 527.42 -243.4 517.81 -242.18 508.2 C-234.65 508.05 -227.3 508.65 -219.81 509.38 C-217.83 509.56 -215.85 509.75 -213.87 509.94 C-211.06 510.2 -208.26 510.48 -205.45 510.75 C-201.85 511.09 -198.24 511.44 -194.64 511.78 C-190.29 512.19 -185.94 512.61 -181.59 513.02 C-172.94 513.85 -164.29 514.66 -155.63 515.46 C-154.13 515.6 -154.13 515.6 -152.59 515.74 C-148.87 516.08 -145.15 516.42 -141.43 516.76 C-138.96 516.99 -136.49 517.21 -134.02 517.44 C-133.31 517.5 -132.61 517.57 -131.89 517.63 C-127.62 518.03 -123.43 518.59 -119.18 519.2 C-119.18 549.56 -119.18 579.92 -119.18 611.2 C-117.2 611.86 -115.22 612.52 -113.18 613.2 C-111.62 613.9 -110.08 614.62 -108.56 615.38 C-107.71 615.79 -106.87 616.2 -106 616.63 C-105.11 617.07 -104.22 617.5 -103.3 617.95 C-94.41 622.24 -85.56 626.13 -76.18 629.2 C-75.2 629.53 -75.2 629.53 -74.21 629.87 C-36.36 642.38 7.85 640.3 46.82 635.2 C47.85 635.07 48.89 634.95 49.95 634.81 C72.64 631.87 101.76 625.8 117.18 607.39 C133.19 585.5 135.64 558.23 132.42 531.87 C128.75 509.68 119.41 489.96 101.11 476.15 C63.62 451.54 13.28 441.78 -30.3 434.25 C-57.97 429.42 -85.35 422.51 -112.18 414.2 C-113.12 413.91 -113.12 413.91 -114.08 413.61 C-152.43 401.72 -184.97 385.07 -214.18 357.2 C-214.84 356.59 -215.51 355.98 -216.19 355.35 C-233.23 339.23 -244.14 316.55 -250.18 294.2 C-250.38 293.45 -250.59 292.69 -250.8 291.91 C-251.49 289.33 -252.15 286.73 -252.8 284.14 C-253.01 283.36 -253.21 282.57 -253.43 281.77 C-257.5 264.99 -257.52 247.53 -257.49 230.37 C-257.49 226.97 -257.51 223.57 -257.54 220.18 C-257.69 166.04 -242.45 114.53 -204.18 75.2 C-162.48 33.33 -97.49 11.38 -40.18 3.2 C-39.49 3.1 -38.8 3 -38.09 2.9 C-25.41 1.06 -12.81 0.05 0 0 Z " fill="#FEFEFE" transform="translate(707.17578125,357.796875)"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 5.2 KiB |
BIN
public/svgs/pgbackweb.png
Normal file
BIN
public/svgs/pgbackweb.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 23 KiB |
1
public/svgs/seafile.svg
Normal file
1
public/svgs/seafile.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg enable-background="new 0 0 1024 1024" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg"><circle cx="512" cy="512" fill="#ffa10f" r="512"/><path d="m221.2 466c0-9.6 7.7-17.2 17.2-17.2 4.8 0 8.6 1.9 11.5 4.8 0-1.9 0-2.9 0-4.8 0-32.6 25.9-58.5 58.5-58.5 8.6 0 16.3 1.9 24 4.8 0-1.9 0-2.9 0-4.8 0-48.9 39.3-88.2 88.2-88.2 47.9 0 87.2 39.3 88.2 87.2-16.3 14.4-28.7 31.6-36.4 51.7-15.3-9.6-34.5-15.3-53.7-15.3-41.2 0-76.7 23-93 58.5h-63.2-24c-9.7-.9-17.3-8.6-17.3-18.2zm462.8-52.7c-22-22-51.7-35.5-85.3-35.5-60.4 0-111.2 45-118.8 103.5-15.3-20.1-39.3-32.6-66.1-32.6-45 0-82.4 36.4-82.4 82.4 0 13.4 2.9 25.9 8.6 36.4-28.7 5.7-49.8 27.8-49.8 54.6 0 30.7 28.7 55.6 64.2 55.6 15.3 0 29.7-4.8 41.2-13.4l132.2-129.3c14.4-13.4 33.5-21.1 55.6-21.1 45 0 80.5 35.5 82.4 79.5 1 13.4-5.7 25.9-19.2 33.5-17.2 10.5-39.3 4.8-48.9-11.5-9.6-17.2-2.9-38.3 14.4-48.9 3.8-1.9 8.6-3.8 12.5-4.8-3.8-1-7.7-1-11.5-1-32.6 0-58.5 25.9-58.5 58.5s25.9 58.5 58.5 58.5h3.8 1.9 115c35.5-1.9 69-33.5 69-73.8 0-40.2-34.5-73.8-74.7-73.8-6.7 11.5-14.4 18.2-24 25.9 9.6-17.2 15.3-36.4 15.3-57.5.1-33.4-13.3-63.1-35.4-85.2z" fill="#fff"/></svg>
|
||||
|
After Width: | Height: | Size: 1.1 KiB |
9
public/svgs/superset.svg
Normal file
9
public/svgs/superset.svg
Normal file
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="256px" height="128px" viewBox="0 0 256 128" version="1.1" xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="xMidYMid">
|
||||
<title>Superset</title>
|
||||
<g>
|
||||
<path d="M190.218924,0 C168.269282,0 148.049828,12.3487941 128.508879,33.9252584 C109.307183,12.0095415 88.748476,0 65.7810761,0 C27.7508614,0 0,27.1402067 0,63.67771 C0,100.215213 27.7508614,127.016168 65.7810761,127.016168 C89.1555791,127.016168 107.271667,116.058309 127.491121,94.2104426 C147.03207,116.12616 166.912271,127.084018 190.218924,127.084018 C228.249139,127.016168 256,100.316989 256,63.67771 C256,27.038431 228.249139,0 190.218924,0 Z M66.0524781,88.6806255 C49.9379804,88.6806255 40.3371323,78.0620196 40.3371323,64.0169626 C40.3371323,49.9719056 49.9379804,39.0479724 66.0524781,39.0479724 C79.6225815,39.0479724 90.716141,49.9719056 102.725682,64.6954678 C91.3946462,78.4012722 79.4190299,88.6806255 66.0524781,88.6806255 Z M189.065465,88.6806255 C175.698913,88.6806255 164.401802,78.0620196 152.392261,64.0169626 C164.741055,49.2934005 175.359661,39.0479724 189.065465,39.0479724 C205.179963,39.0479724 214.679035,50.1076067 214.679035,64.0169626 C214.679035,77.9263186 205.179963,88.6806255 189.065465,88.6806255 Z" fill="#484848"></path>
|
||||
<path d="M156.124039,117.958124 L181.703684,87.4253909 C171.526107,84.3721177 162.12881,75.2122979 152.392261,63.8473363 L127.491121,94.2104426 C135.643361,103.668805 145.322237,111.695521 156.124039,117.958124 Z" fill="#20A7C9"></path>
|
||||
<path d="M128.508879,33.8913332 C120.41092,24.2972701 110.793109,16.0907501 100.045587,9.60084813 L74.432017,40.4728333 C84.1685661,43.8653591 92.7855818,52.6180758 101.945402,63.7794858 L102.963159,64.4919162 L128.508879,33.8913332 Z" fill="#20A7C9"></path>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.8 KiB |
28
public/svgs/yamtrack.svg
Normal file
28
public/svgs/yamtrack.svg
Normal file
@@ -0,0 +1,28 @@
|
||||
<?xml version="1.0" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
|
||||
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
|
||||
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
|
||||
width="512.000000pt" height="512.000000pt" viewBox="0 0 512.000000 512.000000"
|
||||
preserveAspectRatio="xMidYMid meet">
|
||||
<metadata>
|
||||
Created by potrace 1.14, written by Peter Selinger 2001-2017
|
||||
</metadata>
|
||||
<g transform="translate(0.000000,512.000000) scale(0.100000,-0.100000)"
|
||||
fill="#000000" stroke="none">
|
||||
<path d="M2325 5114 c-16 -2 -68 -9 -115 -15 -248 -32 -535 -120 -768 -234
|
||||
-277 -135 -475 -277 -693 -494 -409 -410 -660 -916 -734 -1484 -20 -155 -20
|
||||
-474 0 -637 72 -579 320 -1087 734 -1500 321 -321 693 -540 1116 -658 260 -73
|
||||
468 -97 770 -89 381 10 695 85 1030 246 439 212 811 544 1070 956 192 305 329
|
||||
695 371 1061 20 167 14 500 -11 664 -83 547 -332 1046 -715 1431 -69 69 -160
|
||||
153 -203 188 -281 226 -644 409 -987 496 -210 54 -320 67 -585 70 -137 2 -263
|
||||
1 -280 -1z m1718 -1178 c87 -42 119 -126 79 -206 -19 -39 -22 -39 -116 -20
|
||||
-110 22 -314 -13 -472 -80 -514 -220 -984 -798 -1213 -1491 -71 -216 -94 -337
|
||||
-110 -580 -14 -206 -26 -219 -209 -219 -75 0 -104 -5 -154 -25 -34 -14 -62
|
||||
-25 -63 -25 -1 0 -10 18 -20 39 l-17 40 42 63 c116 174 214 452 271 773 30
|
||||
170 38 487 15 643 -50 342 -193 587 -386 664 -45 19 -75 23 -170 23 -110 0
|
||||
-118 -1 -181 -33 -72 -35 -180 -138 -234 -224 -17 -27 -32 -48 -35 -48 -3 0
|
||||
-24 18 -45 40 -39 40 -40 43 -39 109 0 57 6 80 33 136 62 125 199 234 350 277
|
||||
89 26 262 27 351 4 328 -88 554 -451 620 -996 6 -52 13 -96 15 -98 2 -2 20 28
|
||||
39 67 46 90 91 162 179 281 307 417 699 747 1026 864 171 61 346 70 444 22z"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.6 KiB |
@@ -38,12 +38,13 @@
|
||||
color utility to any element that depends on these defaults.
|
||||
*/
|
||||
@layer base {
|
||||
|
||||
*,
|
||||
::after,
|
||||
::before,
|
||||
::backdrop,
|
||||
::file-selector-button {
|
||||
border-color: var(--color-gray-200, currentcolor);
|
||||
border-color: var(--color-coolgray-200, currentcolor);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -161,9 +162,9 @@ section {
|
||||
* Utility classes
|
||||
*/
|
||||
.input[type="password"] {
|
||||
padding-right: var(--padding-10);
|
||||
@apply pr-[2.4rem];
|
||||
}
|
||||
|
||||
.lds-heart {
|
||||
animation: lds-heart 1.2s infinite cubic-bezier(0.215, 0.61, 0.355, 1);
|
||||
}
|
||||
}
|
||||
@@ -11,7 +11,7 @@
|
||||
}
|
||||
|
||||
@utility input-sticky {
|
||||
@apply block py-1.5 w-full text-sm text-black rounded-sm border-0 ring-1 ring-inset dark:bg-coolgray-100 dark:text-white ring-neutral-200 dark:ring-coolgray-300 focus:ring-2 dark:focus:ring-coolgray-300 focus:ring-neutral-400;
|
||||
@apply block py-1.5 w-full text-sm text-black rounded-sm border-0 ring-1 ring-inset dark:bg-coolgray-100 dark:text-white ring-neutral-200 dark:ring-coolgray-300 focus:ring-2 focus:ring-neutral-400 dark:focus:ring-coolgray-300;
|
||||
}
|
||||
|
||||
@utility input-sticky-active {
|
||||
@@ -20,12 +20,12 @@
|
||||
|
||||
/* Focus */
|
||||
@utility input-focus {
|
||||
@apply focus:ring-2 dark:focus:ring-coolgray-300 focus:ring-neutral-400;
|
||||
@apply focus:ring-2 focus:ring-neutral-400 dark:focus:ring-coolgray-300;
|
||||
}
|
||||
|
||||
/* input, select before */
|
||||
@utility input-select {
|
||||
@apply block py-1.5 w-full text-sm text-black rounded-sm border-0 ring-1 ring-inset dark:bg-coolgray-100 dark:text-white ring-neutral-200 dark:ring-coolgray-300 dark:disabled:bg-coolgray-100/40 dark:disabled:ring-transparent disabled:bg-neutral-200 disabled:text-neutral-500;
|
||||
@apply block py-1.5 w-full text-sm text-black rounded-sm border-0 ring-1 ring-inset dark:bg-coolgray-100 dark:text-white ring-neutral-200 dark:ring-coolgray-300 disabled:bg-neutral-200 disabled:text-neutral-500 dark:disabled:bg-coolgray-100/40 dark:disabled:ring-transparent;
|
||||
}
|
||||
|
||||
/* Readonly */
|
||||
@@ -62,19 +62,19 @@
|
||||
}
|
||||
|
||||
@utility dropdown-item {
|
||||
@apply flex relative gap-2 justify-start items-center py-1 pr-4 pl-2 w-full text-xs transition-colors cursor-pointer select-none dark:text-white hover:bg-neutral-100 dark:hover:bg-coollabs outline-hidden data-disabled:pointer-events-none data-disabled:opacity-50;
|
||||
@apply flex relative gap-2 justify-start items-center py-1 pr-4 pl-2 w-full text-xs transition-colors cursor-pointer select-none dark:text-white hover:bg-neutral-100 dark:hover:bg-coollabs outline-none data-disabled:pointer-events-none data-disabled:opacity-50;
|
||||
}
|
||||
|
||||
@utility dropdown-item-no-padding {
|
||||
@apply flex relative gap-2 justify-start items-center py-1 w-full text-xs transition-colors cursor-pointer select-none dark:text-white hover:bg-neutral-100 dark:hover:bg-coollabs outline-hidden data-disabled:pointer-events-none data-disabled:opacity-50;
|
||||
@apply flex relative gap-2 justify-start items-center py-1 w-full text-xs transition-colors cursor-pointer select-none dark:text-white hover:bg-neutral-100 dark:hover:bg-coollabs outline-none data-disabled:pointer-events-none data-disabled:opacity-50;
|
||||
}
|
||||
|
||||
@utility badge {
|
||||
@apply inline-block w-3 h-3 text-xs font-bold leading-none rounded-full border border-neutral-200 dark:border-black;
|
||||
@apply inline-block w-3 h-3 text-xs font-bold rounded-full leading-none border border-neutral-200 dark:border-black;
|
||||
}
|
||||
|
||||
@utility badge-absolute {
|
||||
@apply absolute top-0 right-0 w-2 h-2 rounded-t-none rounded-r-none border-none;
|
||||
@utility badge-dashboard {
|
||||
@apply absolute top-0 right-0 w-2.5 h-2.5 rounded-bl-full text-xs font-bold leading-none border border-neutral-200 dark:border-black;
|
||||
}
|
||||
|
||||
@utility badge-success {
|
||||
@@ -110,7 +110,7 @@
|
||||
}
|
||||
|
||||
@utility scrollbar {
|
||||
@apply scrollbar-thumb-coollabs-100 dark:scrollbar-track-coolgray-200 scrollbar-track-neutral-200 scrollbar-thin;
|
||||
@apply scrollbar-thumb-coollabs-100 scrollbar-track-neutral-200 dark:scrollbar-track-coolgray-200 scrollbar-thin;
|
||||
}
|
||||
|
||||
@utility main {
|
||||
@@ -166,7 +166,7 @@
|
||||
}
|
||||
|
||||
@utility bg-coollabs-gradient {
|
||||
@apply text-transparent text-white from-purple-500 via-pink-500 to-red-500 bg-linear-to-r;
|
||||
@apply from-purple-500 via-pink-500 to-red-500 bg-linear-to-r;
|
||||
}
|
||||
|
||||
@utility text-helper {
|
||||
@@ -194,11 +194,11 @@
|
||||
}
|
||||
|
||||
@utility fullscreen {
|
||||
@apply overflow-y-auto fixed top-0 left-0 w-full h-full bg-white z-9999 dark:bg-coolgray-100 scrollbar;
|
||||
@apply overflow-y-auto fixed top-0 left-0 w-full h-full bg-white z-[9999] dark:bg-coolgray-100 scrollbar;
|
||||
}
|
||||
|
||||
@utility toast {
|
||||
@apply z-1;
|
||||
@apply z-[1];
|
||||
}
|
||||
|
||||
@utility dz-button {
|
||||
|
||||
@@ -87,7 +87,6 @@
|
||||
params.push(this.password);
|
||||
}
|
||||
params.push(this.selectedActions);
|
||||
|
||||
return $wire[methodName](...params)
|
||||
.then(result => {
|
||||
if (result === true) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<div class="flex flex-col items-start gap-2 min-w-fit">
|
||||
<a class="{{ request()->routeIs('server.security.patches') ? 'menu-item menu-item-active' : 'menu-item' }}"
|
||||
href="{{ route('server.security.patches', $parameters) }}">
|
||||
<button>Server Patching</button>
|
||||
Server Patching
|
||||
</a>
|
||||
</div>
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
@props(['closeWithX' => false, 'fullScreen' => false])
|
||||
<div x-data="{
|
||||
slideOverOpen: false
|
||||
}" class="relative w-auto h-auto" {{ $attributes }}
|
||||
>
|
||||
}" {{ $attributes->merge(['class' => 'relative w-auto h-auto']) }}>
|
||||
{{ $slot }}
|
||||
<template x-teleport="body">
|
||||
<div x-show="slideOverOpen" @if (!$closeWithX) @keydown.window.escape="slideOverOpen=false" @endif
|
||||
@@ -29,7 +28,7 @@
|
||||
<h2 class="text-2xl leading-6" id="slide-over-title">
|
||||
{{ $title }}</h2>
|
||||
<div class="flex items-center h-auto ml-3">
|
||||
<button class="icon" @click="slideOverOpen=false"
|
||||
<button @click="slideOverOpen=false"
|
||||
class="absolute top-0 right-0 z-30 flex items-center justify-center px-3 py-2 mt-4 mr-2 space-x-1 text-xs font-normal border-none rounded-sm">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="w-6 h-6" fill="none"
|
||||
viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
|
||||
|
||||
@@ -13,7 +13,8 @@
|
||||
<x-status.stopped :status="$resource->status" />
|
||||
@endif
|
||||
@if (!str($resource->status)->contains('exited') && $showRefreshButton)
|
||||
<button title="Refresh Status" wire:click='check_status(true)' class="mx-1 dark:hover:fill-white fill-black dark:fill-warning">
|
||||
<button title="Refresh Status" wire:click='checkStatus'
|
||||
class="mx-1 dark:hover:fill-white fill-black dark:fill-warning">
|
||||
<svg class="w-4 h-4" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M12 2a10.016 10.016 0 0 0-7 2.877V3a1 1 0 1 0-2 0v4.5a1 1 0 0 0 1 1h4.5a1 1 0 0 0 0-2H6.218A7.98 7.98 0 0 1 20 12a1 1 0 0 0 2 0A10.012 10.012 0 0 0 12 2zm7.989 13.5h-4.5a1 1 0 0 0 0 2h2.293A7.98 7.98 0 0 1 4 12a1 1 0 0 0-2 0a9.986 9.986 0 0 0 16.989 7.133V21a1 1 0 0 0 2 0v-4.5a1 1 0 0 0-1-1z" />
|
||||
|
||||
@@ -8,7 +8,8 @@
|
||||
<x-status.stopped :status="$complexStatus" />
|
||||
@endif
|
||||
@if (!str($complexStatus)->contains('exited') && $showRefreshButton)
|
||||
<button title="Refresh Status" wire:click='check_status(true)' class="mx-1 dark:hover:fill-white fill-black dark:fill-warning">
|
||||
<button title="Refresh Status" wire:click='checkStatus'
|
||||
class="mx-1 dark:hover:fill-white fill-black dark:fill-warning">
|
||||
<svg class="w-4 h-4" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M12 2a10.016 10.016 0 0 0-7 2.877V3a1 1 0 1 0-2 0v4.5a1 1 0 0 0 1 1h4.5a1 1 0 0 0 0-2H6.218A7.98 7.98 0 0 1 20 12a1 1 0 0 0 2 0A10.012 10.012 0 0 0 12 2zm7.989 13.5h-4.5a1 1 0 0 0 0 2h2.293A7.98 7.98 0 0 1 4 12a1 1 0 0 0-2 0a9.986 9.986 0 0 0 16.989 7.133V21a1 1 0 0 0 2 0v-4.5a1 1 0 0 0-1-1z" />
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<nav wire:poll.10000ms="check_status">
|
||||
<nav wire:poll.10000ms="checkStatus">
|
||||
<x-resources.breadcrumbs :resource="$application" :parameters="$parameters" :title="$lastDeploymentInfo" :lastDeploymentLink="$lastDeploymentLink" />
|
||||
<div class="navbar-main">
|
||||
<nav class="flex shrink-0 gap-6 items-center whitespace-nowrap scrollbar min-h-10">
|
||||
@@ -81,8 +81,7 @@
|
||||
'This application will be stopped.',
|
||||
'All non-persistent data of this application will be deleted.',
|
||||
]" :confirmWithText="false" :confirmWithPassword="false"
|
||||
step1ButtonText="Continue" step2ButtonText="Confirm" :dispatchEvent="true"
|
||||
dispatchEventType="stopEvent">
|
||||
step1ButtonText="Continue" step2ButtonText="Confirm">
|
||||
<x-slot:button-title>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="w-5 h-5 text-error" viewBox="0 0 24 24"
|
||||
stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round"
|
||||
@@ -112,15 +111,5 @@
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@script
|
||||
<script>
|
||||
$wire.$on('stopEvent', () => {
|
||||
$wire.$dispatch('info',
|
||||
'Gracefully stopping application, it could take a while depending on the application.');
|
||||
$wire.$call('stop');
|
||||
});
|
||||
</script>
|
||||
@endscript
|
||||
</nav>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<nav wire:poll.10000ms="check_status">
|
||||
<nav wire:poll.10000ms="checkStatus">
|
||||
<x-resources.breadcrumbs :resource="$database" :parameters="$parameters" />
|
||||
<x-slide-over @startdatabase.window="slideOverOpen = true" closeWithX fullScreen>
|
||||
<x-slot:title>Database Startup</x-slot:title>
|
||||
@@ -60,8 +60,7 @@
|
||||
'If the database is currently in use data could be lost.',
|
||||
'All non-persistent data of this database (containers, networks, unused images) will be deleted (don\'t worry, no data is lost and you can start the database again).',
|
||||
]" :confirmWithText="false" :confirmWithPassword="false"
|
||||
step1ButtonText="Continue" step2ButtonText="Stop Database" :dispatchEvent="true"
|
||||
dispatchEventType="stopEvent">
|
||||
step1ButtonText="Continue" step2ButtonText="Stop Database">
|
||||
<x-slot:button-title>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="w-5 h-5 text-error" viewBox="0 0 24 24"
|
||||
stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round"
|
||||
@@ -93,12 +92,9 @@
|
||||
window.dispatchEvent(new CustomEvent('startdatabase'));
|
||||
$wire.$call('start');
|
||||
});
|
||||
$wire.$on('stopEvent', () => {
|
||||
$wire.$dispatch('info', 'Stopping database.');
|
||||
$wire.$call('stop');
|
||||
});
|
||||
$wire.$on('restartEvent', () => {
|
||||
$wire.$dispatch('info', 'Restarting database.');
|
||||
window.dispatchEvent(new CustomEvent('startdatabase'));
|
||||
$wire.$call('restart');
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -277,12 +277,12 @@
|
||||
@if ($current_step === 'select-postgresql-type')
|
||||
<h2>Select a Postgresql type</h2>
|
||||
<div>If you need extra extensions, you can select Supabase PostgreSQL (or others), otherwise select PostgreSQL
|
||||
16 (default).</div>
|
||||
17 (default).</div>
|
||||
<div class="flex flex-col gap-6 pt-8">
|
||||
<div class="gap-2 border border-transparent cursor-pointer box-without-bg dark:bg-coolgray-100 bg-white dark:hover:text-neutral-400 dark:hover:bg-coollabs group flex "
|
||||
wire:click="setPostgresqlType('postgres:16-alpine')">
|
||||
wire:click="setPostgresqlType('postgres:17-alpine')">
|
||||
<div class="flex flex-col">
|
||||
<div class="box-title">PostgreSQL 16 (default)</div>
|
||||
<div class="box-title">PostgreSQL 17 (default)</div>
|
||||
<div class="box-description">
|
||||
PostgreSQL is a powerful, open-source object-relational database system (no extensions).
|
||||
</div>
|
||||
@@ -297,7 +297,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="gap-2 border border-transparent cursor-pointer box-without-bg dark:bg-coolgray-100 bg-white dark:hover:text-neutral-400 dark:hover:bg-coollabs group flex"
|
||||
wire:click="setPostgresqlType('supabase/postgres:15.6.1.113')">
|
||||
wire:click="setPostgresqlType('supabase/postgres:17.4.1.032')">
|
||||
<div class="flex flex-col">
|
||||
<div class="box-title">Supabase PostgreSQL (with extensions)</div>
|
||||
<div class="box-description">
|
||||
@@ -314,9 +314,9 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="gap-2 border border-transparent cursor-pointer box-without-bg dark:bg-coolgray-100 bg-white dark:hover:text-neutral-400 dark:hover:bg-coollabs group flex"
|
||||
wire:click="setPostgresqlType('postgis/postgis')">
|
||||
wire:click="setPostgresqlType('postgis/postgis:17-3.5-alpine')">
|
||||
<div class="flex flex-col">
|
||||
<div class="box-title">PostGIS</div>
|
||||
<div class="box-title">PostGIS (AMD only)</div>
|
||||
<div class="box-description">
|
||||
PostGIS is a PostgreSQL extension for geographic objects.
|
||||
</div>
|
||||
@@ -331,9 +331,9 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="gap-2 border border-transparent cursor-pointer box-without-bg dark:bg-coolgray-100 bg-white dark:hover:text-neutral-400 dark:hover:bg-coollabs group flex"
|
||||
wire:click="setPostgresqlType('pgvector/pgvector:pg16')">
|
||||
wire:click="setPostgresqlType('pgvector/pgvector:pg17')">
|
||||
<div class="flex flex-col">
|
||||
<div class="box-title">PGVector (16)</div>
|
||||
<div class="box-title">PGVector (17)</div>
|
||||
<div class="box-description">
|
||||
PGVector is a PostgreSQL extension for vector data types.
|
||||
</div>
|
||||
|
||||
@@ -67,16 +67,16 @@
|
||||
<div class="pb-2 truncate box-title" x-text="item.name"></div>
|
||||
<div class="flex-1"></div>
|
||||
<template x-if="item.status.startsWith('running')">
|
||||
<div title="running" class="bg-success badge badge-absolute"></div>
|
||||
<div title="running" class="bg-success badge-dashboard"></div>
|
||||
</template>
|
||||
<template x-if="item.status.startsWith('exited')">
|
||||
<div title="exited" class="bg-error badge badge-absolute"></div>
|
||||
<div title="exited" class="bg-error badge-dashboard"></div>
|
||||
</template>
|
||||
<template x-if="item.status.startsWith('restarting')">
|
||||
<div title="restarting" class="bg-warning badge badge-absolute"></div>
|
||||
<div title="restarting" class="bg-warning badge-dashboard"></div>
|
||||
</template>
|
||||
<template x-if="item.status.startsWith('degraded')">
|
||||
<div title="degraded" class="bg-warning badge badge-absolute"></div>
|
||||
<div title="degraded" class="bg-warning badge-dashboard"></div>
|
||||
</template>
|
||||
</div>
|
||||
<div class="max-w-full px-4 truncate box-description" x-text="item.description"></div>
|
||||
@@ -113,16 +113,16 @@
|
||||
<div class="pb-2 truncate box-title" x-text="item.name"></div>
|
||||
<div class="flex-1"></div>
|
||||
<template x-if="item.status.startsWith('running')">
|
||||
<div title="running" class="bg-success badge badge-absolute"></div>
|
||||
<div title="running" class="bg-success badge-dashboard"></div>
|
||||
</template>
|
||||
<template x-if="item.status.startsWith('exited')">
|
||||
<div title="exited" class="bg-error badge badge-absolute"></div>
|
||||
<div title="exited" class="bg-error badge-dashboard"></div>
|
||||
</template>
|
||||
<template x-if="item.status.startsWith('restarting')">
|
||||
<div title="restarting" class="bg-warning badge badge-absolute"></div>
|
||||
<div title="restarting" class="bg-warning badge-dashboard"></div>
|
||||
</template>
|
||||
<template x-if="item.status.startsWith('degraded')">
|
||||
<div title="degraded" class="bg-warning badge badge-absolute"></div>
|
||||
<div title="degraded" class="bg-warning badge-dashboard"></div>
|
||||
</template>
|
||||
</div>
|
||||
<div class="max-w-full px-4 truncate box-description" x-text="item.description"></div>
|
||||
@@ -159,16 +159,16 @@
|
||||
<div class="pb-2 truncate box-title" x-text="item.name"></div>
|
||||
<div class="flex-1"></div>
|
||||
<template x-if="item.status.startsWith('running')">
|
||||
<div title="running" class="bg-success badge badge-absolute"></div>
|
||||
<div title="running" class="bg-success badge-dashboard"></div>
|
||||
</template>
|
||||
<template x-if="item.status.startsWith('exited')">
|
||||
<div title="exited" class="bg-error badge badge-absolute"></div>
|
||||
<div title="exited" class="bg-error badge-dashboard"></div>
|
||||
</template>
|
||||
<template x-if="item.status.startsWith('restarting')">
|
||||
<div title="restarting" class="bg-warning badge badge-absolute"></div>
|
||||
<div title="restarting" class="bg-warning badge-dashboard"></div>
|
||||
</template>
|
||||
<template x-if="item.status.startsWith('degraded')">
|
||||
<div title="degraded" class="bg-warning badge badge-absolute"></div>
|
||||
<div title="degraded" class="bg-warning badge-dashboard"></div>
|
||||
</template>
|
||||
</div>
|
||||
<div class="max-w-full px-4 truncate box-description" x-text="item.description"></div>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<x-slot:title>
|
||||
{{ data_get_str($service, 'name')->limit(10) }} > Configuration | Coolify
|
||||
</x-slot>
|
||||
<livewire:project.service.navbar :service="$service" :parameters="$parameters" :query="$query" />
|
||||
<livewire:project.service.heading :service="$service" :parameters="$parameters" :query="$query" />
|
||||
|
||||
<div class="flex flex-col h-full gap-8 pt-6 sm:flex-row">
|
||||
<div class="flex flex-col items-start gap-2 min-w-fit">
|
||||
@@ -36,7 +36,7 @@
|
||||
@if ($currentRoute === 'project.service.configuration')
|
||||
<livewire:project.service.stack-form :service="$service" />
|
||||
<h3>Services</h3>
|
||||
<div class="grid grid-cols-1 gap-2 pt-4 xl:grid-cols-1" wire:poll.10000ms="check_status">
|
||||
<div class="grid grid-cols-1 gap-2 pt-4 xl:grid-cols-1">
|
||||
@foreach ($applications as $application)
|
||||
<div @class([
|
||||
'border-l border-dashed border-red-500' => str(
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<div>
|
||||
<div wire:poll.10000ms="checkStatus">
|
||||
<livewire:project.shared.configuration-checker :resource="$service" />
|
||||
<x-slide-over @startservice.window="slideOverOpen = true" closeWithX fullScreen>
|
||||
<x-slot:title>Service Startup</x-slot:title>
|
||||
@@ -38,10 +38,9 @@
|
||||
</svg>
|
||||
Restart
|
||||
</x-forms.button>
|
||||
<x-modal-confirmation title="Confirm Service Stopping?" buttonTitle="Stop" submitAction="stop"
|
||||
:checkboxes="$checkboxes" :actions="[__('service.stop'), __('resource.non_persistent')]" :confirmWithText="false" :confirmWithPassword="false"
|
||||
step1ButtonText="Continue" step2ButtonText="Stop Service" :dispatchEvent="true"
|
||||
dispatchEventType="stopEvent">
|
||||
<x-modal-confirmation title="Confirm Service Stopping?" buttonTitle="Stop" :dispatchEvent="true"
|
||||
submitAction="stop" dispatchEventType="stopEvent" :checkboxes="$checkboxes" :actions="[__('service.stop'), __('resource.non_persistent')]"
|
||||
:confirmWithText="false" :confirmWithPassword="false" step1ButtonText="Continue" step2ButtonText="Stop Service">
|
||||
<x-slot:button-title>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="w-5 h-5 text-error" viewBox="0 0 24 24"
|
||||
stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round"
|
||||
@@ -67,10 +66,9 @@
|
||||
</svg>
|
||||
Restart
|
||||
</x-forms.button>
|
||||
<x-modal-confirmation title="Confirm Service Stopping?" buttonTitle="Stop" submitAction="stop"
|
||||
:checkboxes="$checkboxes" :actions="[__('service.stop'), __('resource.non_persistent')]" :confirmWithText="false" :confirmWithPassword="false"
|
||||
step1ButtonText="Continue" step2ButtonText="Stop Service" :dispatchEvent="true"
|
||||
dispatchEventType="stopEvent">
|
||||
<x-modal-confirmation title="Confirm Service Stopping?" buttonTitle="Stop" :dispatchEvent="true"
|
||||
submitAction="stop" dispatchEventType="stopEvent" :checkboxes="$checkboxes" :actions="[__('service.stop'), __('resource.non_persistent')]"
|
||||
:confirmWithText="false" :confirmWithPassword="false" step1ButtonText="Continue" step2ButtonText="Stop Service">
|
||||
<x-slot:button-title>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="w-5 h-5 text-error" viewBox="0 0 24 24"
|
||||
stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round"
|
||||
@@ -96,10 +94,9 @@
|
||||
Deploy
|
||||
</button>
|
||||
@else
|
||||
<x-modal-confirmation title="Confirm Service Stopping?" buttonTitle="Stop" submitAction="stop"
|
||||
:checkboxes="$checkboxes" :actions="[__('service.stop'), __('resource.non_persistent')]" :confirmWithText="false" :confirmWithPassword="false"
|
||||
step1ButtonText="Continue" step2ButtonText="Stop Service" :dispatchEvent="true"
|
||||
dispatchEventType="stopEvent">
|
||||
<x-modal-confirmation title="Confirm Service Stopping?" buttonTitle="Stop" :dispatchEvent="true"
|
||||
submitAction="stop" dispatchEventType="stopEvent" :checkboxes="$checkboxes" :actions="[__('service.stop'), __('resource.non_persistent')]"
|
||||
:confirmWithText="false" :confirmWithPassword="false" step1ButtonText="Continue" step2ButtonText="Stop Service">
|
||||
<x-slot:button-title>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="w-5 h-5 text-error" viewBox="0 0 24 24"
|
||||
stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round"
|
||||
@@ -1,5 +1,5 @@
|
||||
<div x-data="{ activeTab: window.location.hash ? window.location.hash.substring(1) : 'general' }">
|
||||
<livewire:project.service.navbar :service="$service" :parameters="$parameters" :query="$query" />
|
||||
<livewire:project.service.heading :service="$service" :parameters="$parameters" :query="$query" />
|
||||
<div class="flex flex-col h-full gap-8 pt-6 sm:flex-row">
|
||||
<div class="flex flex-col items-start gap-2 min-w-fit">
|
||||
<a class="menu-item"
|
||||
|
||||
@@ -12,28 +12,31 @@
|
||||
<livewire:project.database.heading :database="$resource" />
|
||||
@elseif ($type === 'service')
|
||||
<livewire:project.shared.configuration-checker :resource="$resource" />
|
||||
<livewire:project.service.navbar :service="$resource" :parameters="$parameters" title="Terminal" />
|
||||
<livewire:project.service.heading :service="$resource" :parameters="$parameters" title="Terminal" />
|
||||
@elseif ($type === 'server')
|
||||
<x-server.navbar :server="$server" :parameters="$parameters" />
|
||||
@endif
|
||||
|
||||
@if(!$hasShell)
|
||||
@if (!$hasShell)
|
||||
<div class="flex items-center justify-center w-full py-4 mx-auto">
|
||||
<div class="p-4 w-full rounded-sm border dark:bg-coolgray-100 dark:border-coolgray-300">
|
||||
<div class="flex flex-col items-center justify-center space-y-4">
|
||||
<svg class="w-12 h-12 text-red-500" fill="none" stroke="currentColor" 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"/>
|
||||
<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>
|
||||
<div class="text-center">
|
||||
<h3 class="text-lg font-medium">Terminal Not Available</h3>
|
||||
<p class="mt-2 text-sm text-gray-500">No shell (bash/sh) is available in this container. Please ensure either bash or sh is installed to use the terminal.</p>
|
||||
<p class="mt-2 text-sm text-gray-500">No shell (bash/sh) is available in this container. Please
|
||||
ensure either bash or sh is installed to use the terminal.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@else
|
||||
@if ($type === 'server')
|
||||
<form class="w-full" wire:submit="$dispatchSelf('connectToServer')" wire:init="$dispatchSelf('connectToServer')">
|
||||
<form class="w-full" wire:submit="$dispatchSelf('connectToServer')"
|
||||
wire:init="$dispatchSelf('connectToServer')">
|
||||
<x-forms.button class="w-full" type="submit">Reconnect</x-forms.button>
|
||||
</form>
|
||||
<div class="mx-auto w-full">
|
||||
|
||||
@@ -42,7 +42,7 @@
|
||||
@endforelse
|
||||
</div>
|
||||
@elseif ($type === 'service')
|
||||
<livewire:project.service.navbar :service="$resource" :parameters="$parameters" :query="$query" title="Logs" />
|
||||
<livewire:project.service.heading :service="$resource" :parameters="$parameters" :query="$query" title="Logs" />
|
||||
<div class="pt-4">
|
||||
<div class="subtitle">Here you can see the logs of the service.</div>
|
||||
@forelse ($containers as $container)
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<h1>Scheduled Task</h1>
|
||||
<livewire:project.application.heading :application="$resource" />
|
||||
@elseif ($type === 'service')
|
||||
<livewire:project.service.navbar :service="$resource" :parameters="$parameters" />
|
||||
<livewire:project.service.heading :service="$resource" :parameters="$parameters" />
|
||||
@endif
|
||||
|
||||
<form wire:submit="submit" class="w-full">
|
||||
|
||||
@@ -14,15 +14,16 @@
|
||||
<x-server.sidebar-security :server="$server" :parameters="$parameters" />
|
||||
<form wire:submit='submit' class="w-full">
|
||||
<div>
|
||||
<div class="flex items-center gap-2">
|
||||
<div class="flex items-center gap-2 flex-row">
|
||||
<h2>Server Patching</h2>
|
||||
<x-forms.button type="button" wire:click="$dispatch('checkForUpdatesDispatch')">Manually
|
||||
Check</x-forms.button>
|
||||
</div>
|
||||
<div>Check if your server has updates available.</div>
|
||||
<div class="text-xs pt-1">(only available for apt, dnf and zypper package managers atm, more coming
|
||||
soon as well as more features...)
|
||||
<span class="text-xs text-neutral-500">(experimental)</span>
|
||||
<x-helper
|
||||
helper="Only available for apt, dnf and zypper package managers atm, more coming
|
||||
soon. <br/> Also scheduled patching and notifications are coming soon..." />
|
||||
<x-forms.button type="button" wire:click="$dispatch('checkForUpdatesDispatch')">
|
||||
Check Now</x-forms.button>
|
||||
</div>
|
||||
<div>Update your servers automatically.</div>
|
||||
<div>
|
||||
<div class="flex flex-col gap-6 pt-4">
|
||||
<div class="flex flex-col">
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
label="Client ID" />
|
||||
<x-forms.input id="oauth_settings_map.{{ $oauth_setting->provider }}.client_secret"
|
||||
type="password" label="Client Secret" autocomplete="new-password" />
|
||||
<x-forms.input id="oauth_settings_map.{{ $oauth_setting->provider }}.redirect_uri"
|
||||
<x-forms.input id="oauth_settings_map.{{ $oauth_setting->provider }}.redirect_uri" placeholder="{{ route('auth.callback', $oauth_setting->provider) }}"
|
||||
label="Redirect URI" />
|
||||
@if ($oauth_setting->provider == 'azure')
|
||||
<x-forms.input id="oauth_settings_map.{{ $oauth_setting->provider }}.tenant"
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
services:
|
||||
authentik-server:
|
||||
image: ghcr.io/goauthentik/server:${AUTHENTIK_TAG:-2025.2.3}
|
||||
image: ghcr.io/goauthentik/server:${AUTHENTIK_TAG:-2025.4.1}
|
||||
restart: unless-stopped
|
||||
command: server
|
||||
environment:
|
||||
@@ -35,7 +35,7 @@ services:
|
||||
redis:
|
||||
condition: service_healthy
|
||||
authentik-worker:
|
||||
image: ghcr.io/goauthentik/server:${AUTHENTIK_TAG:-2025.2.3}
|
||||
image: ghcr.io/goauthentik/server:${AUTHENTIK_TAG:-2025.4.1}
|
||||
restart: unless-stopped
|
||||
command: worker
|
||||
environment:
|
||||
|
||||
@@ -80,7 +80,7 @@ services:
|
||||
- ACTIVE_STORAGE_SERVICE=${ACTIVE_STORAGE_SERVICE:-local}
|
||||
command: ['bundle', 'exec', 'sidekiq', '-C', 'config/sidekiq.yml']
|
||||
volumes:
|
||||
- sidekiq-data:/app/storage
|
||||
- rails-data:/app/storage
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "bundle exec rails runner 'puts Sidekiq.redis(&:info)' > /dev/null 2>&1"]
|
||||
interval: 30s
|
||||
|
||||
@@ -15,7 +15,7 @@ services:
|
||||
- LOG_LEVEL=${LOG_LEVEL:-info}
|
||||
- LOG_JSON=${LOG_JSON:-false}
|
||||
- DIUN_WATCH_WORKERS=${DIUN_WATCH_WORKERS:-20}
|
||||
- DIUN_WATCH_SCHEDULE=${CRON_WATCH_SCHEDULE:- * */6 * * *}
|
||||
- DIUN_WATCH_SCHEDULE=${DIUN_WATCH_SCHEDULE:- * */6 * * *}
|
||||
- DIUN_WATCH_JITTER=${DIUN_WATCH_JITTER:-30s}
|
||||
- DIUN_PROVIDERS_DOCKER=${DIUN_PROVIDERS_DOCKER:-true}
|
||||
- DIUN_PROVIDERS_DOCKER_WATCHBYDEFAULT=${DIUN_PROVIDERS_DOCKER_WATCHBYDEFAULT:-true}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# documentation: https://github.com/maybe-finance/maybe
|
||||
# slogan: Maybe: The OS for your personal finances.
|
||||
# slogan: Maybe, the OS for your personal finances.
|
||||
# tags: finances,wallets,coins,stocks,investments,open,source
|
||||
# logo: svgs/maybe.svg
|
||||
# port: 3000
|
||||
@@ -17,29 +17,75 @@ services:
|
||||
- GOOD_JOB_EXECUTION_MODE=${GOOD_JOB_EXECUTION_MODE:-async}
|
||||
- SECRET_KEY_BASE=${SERVICE_BASE64_64_SECRETKEYBASE}
|
||||
- DB_HOST=postgres
|
||||
- POSTGRES_DB=${POSTGRES_DB:-maybe_db}
|
||||
- POSTGRES_DB=${POSTGRES_DB:-maybe-db}
|
||||
- POSTGRES_USER=${SERVICE_USER_POSTGRES}
|
||||
- POSTGRES_PASSWORD=${SERVICE_PASSWORD_POSTGRES}
|
||||
- DB_PORT=5432
|
||||
- REDIS_URL=redis://default:${SERVICE_PASSWORD_REDIS}@redis:6379/1
|
||||
- OPENAI_ACCESS_TOKEN=${OPENAI_ACCESS_TOKEN}
|
||||
depends_on:
|
||||
postgres:
|
||||
condition: service_healthy
|
||||
redis:
|
||||
condition: service_healthy
|
||||
healthcheck:
|
||||
test:
|
||||
- CMD
|
||||
- curl
|
||||
- "-f"
|
||||
- "http://localhost:3000"
|
||||
interval: 10s
|
||||
timeout: 10s
|
||||
retries: 5
|
||||
|
||||
worker:
|
||||
image: ghcr.io/maybe-finance/maybe:latest
|
||||
command: bundle exec sidekiq
|
||||
environment:
|
||||
- POSTGRES_USER=${SERVICE_USER_POSTGRES}
|
||||
- POSTGRES_PASSWORD=${SERVICE_PASSWORD_POSTGRES}
|
||||
- POSTGRES_DB=${POSTGRES_DB:-maybe-db}
|
||||
- SECRET_KEY_BASE=${SERVICE_BASE64_64_SECRETKEYBASE}
|
||||
- SELF_HOSTED=true
|
||||
- RAILS_FORCE_SSL=${RAILS_FORCE_SSL:-false}
|
||||
- RAILS_ASSUME_SSL=${RAILS_ASSUME_SSL:-false}
|
||||
- GOOD_JOB_EXECUTION_MODE=${GOOD_JOB_EXECUTION_MODE:-async}
|
||||
- DB_HOST=postgres
|
||||
- DB_PORT=5432
|
||||
- REDIS_URL=redis://default:${SERVICE_PASSWORD_REDIS}@redis:6379/1
|
||||
- OPENAI_ACCESS_TOKEN=${OPENAI_ACCESS_TOKEN}
|
||||
depends_on:
|
||||
postgres:
|
||||
condition: service_healthy
|
||||
redis:
|
||||
condition: service_healthy
|
||||
exclude_from_hc: true
|
||||
|
||||
postgres:
|
||||
image: postgres:16
|
||||
image: postgres:16-alpine
|
||||
volumes:
|
||||
- maybe_postgres_data:/var/lib/postgresql/data
|
||||
environment:
|
||||
- POSTGRES_USER=${SERVICE_USER_POSTGRES}
|
||||
- POSTGRES_DB=${POSTGRES_DB:-maybe_db}
|
||||
- POSTGRES_PASSWORD=${SERVICE_PASSWORD_POSTGRES}
|
||||
- POSTGRES_DB=${POSTGRES_DB:-maybe-db}
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}"]
|
||||
interval: 5s
|
||||
timeout: 20s
|
||||
retries: 10
|
||||
|
||||
redis:
|
||||
image: redis:8-alpine
|
||||
command: redis-server --appendonly yes --requirepass ${SERVICE_PASSWORD_REDIS}
|
||||
volumes:
|
||||
- redis_data:/data
|
||||
environment:
|
||||
- REDIS_PASSWORD=${SERVICE_PASSWORD_REDIS}
|
||||
- REDIS_PORT=6379
|
||||
- REDIS_DB=1
|
||||
healthcheck:
|
||||
test: ["CMD", "redis-cli", "--pass", "${SERVICE_PASSWORD_REDIS}", "ping"]
|
||||
interval: 10s
|
||||
timeout: 3s
|
||||
retries: 3
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
# port: 5230
|
||||
|
||||
services:
|
||||
wg-easy:
|
||||
memos:
|
||||
image: neosmemo/memos:stable
|
||||
volumes:
|
||||
- memos/:/var/opt/memos
|
||||
|
||||
44
templates/compose/onetimesecret.yaml
Normal file
44
templates/compose/onetimesecret.yaml
Normal file
@@ -0,0 +1,44 @@
|
||||
# documentation: https://docs.onetimesecret.com
|
||||
# slogan: Share sensitive information securely with self-destructing links that are only viewable once.
|
||||
# tags: auth,password,secret,secure
|
||||
# logo: svgs/onetimesecret.svg
|
||||
# port: 3000
|
||||
|
||||
services:
|
||||
onetimesecret:
|
||||
image: onetimesecret/onetimesecret:latest
|
||||
environment:
|
||||
- SERVICE_FQDN_ONETIMESECRET_3000
|
||||
- AUTH_AUTOVERIFY=${AUTH_AUTOVERIFY:-true}
|
||||
- AUTH_SIGNUP=${AUTH_SIGNUP:-true}
|
||||
- COLONEL=${COLONEL:-admin@example.com}
|
||||
- HOST=${HOST:-localhost}
|
||||
- REDIS_URL=redis://:${SERVICE_PASSWORD_REDIS}@redis:6379/0
|
||||
- SECRET=${SERVICE_PASSWORD_ONETIMESECRET}
|
||||
- SSL=${SSL:-false}
|
||||
- RACK_ENV=production
|
||||
depends_on:
|
||||
redis:
|
||||
condition: service_healthy
|
||||
healthcheck:
|
||||
test:
|
||||
- CMD
|
||||
- ruby
|
||||
- "-rnet/http"
|
||||
- "-e"
|
||||
- "exit(Net::HTTP.get_response(URI('http://localhost:3000')).is_a?(Net::HTTPSuccess) ? 0 : 1)"
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
|
||||
redis:
|
||||
image: redis:8-alpine
|
||||
command: redis-server --requirepass ${SERVICE_PASSWORD_REDIS}
|
||||
healthcheck:
|
||||
test:
|
||||
- CMD
|
||||
- redis-cli
|
||||
- ping
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
@@ -10,27 +10,32 @@ services:
|
||||
volumes:
|
||||
- app_logs:/app/storage/logs
|
||||
- app_public:/app/storage/public
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "curl -sf http://localhost:80 || exit 1"]
|
||||
interval: 10s
|
||||
timeout: 1s
|
||||
retries: 3
|
||||
environment:
|
||||
SERVICE_FQDN_PAYMENTER: ${SERVICE_FQDN_PAYMENTER_80}
|
||||
DB_DATABASE: ${MYSQL_DATABASE:-paymenter-db}
|
||||
DB_PASSWORD: ${SERVICE_PASSWORD_MYSQL}
|
||||
DB_USERNAME: ${SERVICE_USER_MYSQL}
|
||||
APP_ENV: "production"
|
||||
CACHE_STORE: "redis"
|
||||
SESSION_DRIVER: "redis"
|
||||
QUEUE_CONNECTION: "redis"
|
||||
REDIS_HOST: "redis"
|
||||
APP_ENV: production
|
||||
CACHE_STORE: redis
|
||||
SESSION_DRIVER: redis
|
||||
QUEUE_CONNECTION: redis
|
||||
REDIS_HOST: redis
|
||||
REDIS_USERNAME: default
|
||||
REDIS_PASSWORD: "${SERVICE_PASSWORD_64_REDIS}"
|
||||
DB_CONNECTION: "mariadb"
|
||||
DB_HOST: "mariadb"
|
||||
DB_PORT: "3306"
|
||||
REDIS_PASSWORD: ${SERVICE_PASSWORD_64_REDIS}
|
||||
DB_CONNECTION: mariadb
|
||||
DB_HOST: mariadb
|
||||
DB_PORT: 3306
|
||||
APP_KEY: ${SERVICE_BASE64_KEY}
|
||||
depends_on:
|
||||
mariadb:
|
||||
condition: service_healthy
|
||||
redis:
|
||||
condition: service_started
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "curl -sf http://localhost:80 || exit 1"]
|
||||
interval: 10s
|
||||
timeout: 1s
|
||||
retries: 3
|
||||
|
||||
mariadb:
|
||||
image: mariadb:11
|
||||
|
||||
34
templates/compose/pgbackweb.yaml
Normal file
34
templates/compose/pgbackweb.yaml
Normal file
@@ -0,0 +1,34 @@
|
||||
# documentation: https://github.com/eduardolat/pgbackweb
|
||||
# slogan: Effortless PostgreSQL backups with a user-friendly web interface!
|
||||
# tags: backup, postgresql, web-interface
|
||||
# logo: svgs/pgbackweb.svg
|
||||
# port: 8085
|
||||
|
||||
services:
|
||||
pgbackweb:
|
||||
image: eduardolat/pgbackweb:latest
|
||||
volumes:
|
||||
- pgbackweb_backups:/backups
|
||||
environment:
|
||||
- SERVICE_FQDN_PGBACKWEB_8085
|
||||
- PBW_ENCRYPTION_KEY=${SERVICE_PASSWORD_64_PGBACKWEB}
|
||||
- PBW_POSTGRES_CONN_STRING=postgresql://${SERVICE_USER_POSTGRES}:${SERVICE_PASSWORD_POSTGRES}@postgres:5432/${POSTGRES_DB:-pgbackweb-db}?sslmode=disable
|
||||
- TZ=${TIME_ZONE:-UTC}
|
||||
depends_on:
|
||||
postgres:
|
||||
condition: service_healthy
|
||||
exclude_from_hc: true
|
||||
|
||||
postgres:
|
||||
image: postgres:17
|
||||
environment:
|
||||
- POSTGRES_USER=${SERVICE_USER_POSTGRES}
|
||||
- POSTGRES_PASSWORD=${SERVICE_PASSWORD_POSTGRES}
|
||||
- POSTGRES_DB=${POSTGRES_DB:-pgbackweb-db}
|
||||
volumes:
|
||||
- pgbackweb_postgres_data:/var/lib/postgresql/data
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U ${SERVICE_USER_POSTGRES} -d pgbackweb"]
|
||||
interval: 5s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
75
templates/compose/seafile.yaml
Normal file
75
templates/compose/seafile.yaml
Normal file
@@ -0,0 +1,75 @@
|
||||
# documentation: https://manual.seafile.com
|
||||
# slogan: Open source cloud storage system for file sync, share and document collaboration
|
||||
# tags: file-manager,file-sharing,storage
|
||||
# logo: svgs/seafile.svg
|
||||
# port: 80
|
||||
|
||||
services:
|
||||
seafile-db:
|
||||
image: mariadb:10.11
|
||||
environment:
|
||||
- MYSQL_ROOT_PASSWORD=${SERVICE_PASSWORD_64_MYSQLDBROOT}
|
||||
- MYSQL_LOG_CONSOLE=true
|
||||
- MARIADB_AUTO_UPGRADE=1
|
||||
volumes:
|
||||
- seafile-mysql-db:/var/lib/mysql"
|
||||
healthcheck:
|
||||
test:
|
||||
[
|
||||
"CMD",
|
||||
"/usr/local/bin/healthcheck.sh",
|
||||
"--connect",
|
||||
"--mariadbupgrade",
|
||||
"--innodb_initialized",
|
||||
]
|
||||
interval: 20s
|
||||
start_period: 30s
|
||||
timeout: 5s
|
||||
retries: 10
|
||||
|
||||
memcached:
|
||||
image: memcached:1.6.29
|
||||
entrypoint: memcached -m 256
|
||||
healthcheck:
|
||||
test:
|
||||
[
|
||||
"CMD-SHELL",
|
||||
'bash -c "echo version | (exec 3<>/dev/tcp/localhost/11211; cat >&3; timeout 0.5 cat <&3; exec 3<&-)"',
|
||||
]
|
||||
interval: 20s
|
||||
timeout: 5s
|
||||
retries: 10
|
||||
|
||||
seafile:
|
||||
image: seafileltd/seafile-mc:12.0-latest
|
||||
volumes:
|
||||
- seafile-data:/shared
|
||||
environment:
|
||||
- SERVICE_FQDN_SEAFILE_80
|
||||
- DB_HOST=${SEAFILE_MYSQL_DB_HOST:-seafile-db}
|
||||
- DB_PORT=${SEAFILE_MYSQL_DB_PORT:-3306}
|
||||
- DB_ROOT_PASSWD=${SERVICE_PASSWORD_64_MYSQLDBROOT}
|
||||
- DB_USER=${SEAFILE_MYSQL_DB_USER:-seafile}
|
||||
- DB_PASSWORD=${SERVICE_PASSWORD_64_MYSQLDBUSER}
|
||||
- SEAFILE_MYSQL_DB_CCNET_DB_NAME=${SEAFILE_MYSQL_DB_CCNET_DB_NAME:-ccnet_db}
|
||||
- SEAFILE_MYSQL_DB_SEAFILE_DB_NAME=${SEAFILE_MYSQL_DB_SEAFILE_DB_NAME:-seafile_db}
|
||||
- SEAFILE_MYSQL_DB_SEAHUB_DB_NAME=${SEAFILE_MYSQL_DB_SEAHUB_DB_NAME:-seahub_db}
|
||||
- TIME_ZONE=${TIME_ZONE:-Etc/UTC}
|
||||
- INIT_SEAFILE_ADMIN_EMAIL=${INIT_SEAFILE_ADMIN_EMAIL:-me@example.com}
|
||||
- INIT_SEAFILE_ADMIN_PASSWORD=${SERVICE_PASSWORD_ADMIN}
|
||||
- SEAFILE_SERVER_HOSTNAME=${SERVICE_URL_SEAFILE_80}
|
||||
- SEAFILE_SERVER_PROTOCOL=${SEAFILE_SERVER_PROTOCOL:-https}
|
||||
- SITE_ROOT=${SITE_ROOT:-/}
|
||||
- NON_ROOT=${NON_ROOT:-false}
|
||||
- JWT_PRIVATE_KEY=${SERVICE_PASSWORD_64_JWT}
|
||||
- SEAFILE_LOG_TO_STDOUT=${SEAFILE_LOG_TO_STDOUT:-true}
|
||||
depends_on:
|
||||
seafile-db:
|
||||
condition: service_healthy
|
||||
memcached:
|
||||
condition: service_started
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://127.0.0.1:80/api2/ping"]
|
||||
interval: 20s
|
||||
timeout: 5s
|
||||
retries: 10
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
services:
|
||||
snapdrop:
|
||||
image: lscr.io/linuxserver/snapdrop:latest
|
||||
image: 'linuxserver/snapdrop:version-b8b78cc2'
|
||||
environment:
|
||||
- SERVICE_FQDN_SNAPDROP
|
||||
- PUID=1000
|
||||
|
||||
87
templates/compose/superset-with-postgresql.yaml
Normal file
87
templates/compose/superset-with-postgresql.yaml
Normal file
@@ -0,0 +1,87 @@
|
||||
# documentation: https://github.com/amancevice/docker-superset
|
||||
# slogan: Modern data exploration and visualization platform (unofficial community docker image)
|
||||
# tags: analytics,bi,dashboard,database,sql,unofficial
|
||||
# logo: svgs/superset.svg
|
||||
# port: 8088
|
||||
|
||||
services:
|
||||
superset:
|
||||
image: amancevice/superset:latest
|
||||
environment:
|
||||
- SERVICE_FQDN_SUPERSET_8088
|
||||
- SECRET_KEY=${SERVICE_BASE64_64_SUPERSETSECRETKEY}
|
||||
- MAPBOX_API_KEY=${MAPBOX_API_KEY}
|
||||
- POSTGRES_USER=${SERVICE_USER_POSTGRES}
|
||||
- POSTGRES_PASSWORD=${SERVICE_PASSWORD_POSTGRES}
|
||||
- POSTGRES_DB=${POSTGRES_DB:-superset-db}
|
||||
- REDIS_PASSWORD=${SERVICE_PASSWORD_REDIS}
|
||||
volumes:
|
||||
- type: bind
|
||||
source: ./superset/superset_config.py
|
||||
target: /etc/superset/superset_config.py
|
||||
content: |
|
||||
"""
|
||||
For more configuration options, see:
|
||||
- https://superset.apache.org/docs/configuration/configuring-superset
|
||||
"""
|
||||
|
||||
import os
|
||||
|
||||
SECRET_KEY = os.getenv("SECRET_KEY")
|
||||
MAPBOX_API_KEY = os.getenv("MAPBOX_API_KEY", "")
|
||||
|
||||
CACHE_CONFIG = {
|
||||
"CACHE_TYPE": "RedisCache",
|
||||
"CACHE_DEFAULT_TIMEOUT": 300,
|
||||
"CACHE_KEY_PREFIX": "superset_",
|
||||
"CACHE_REDIS_HOST": "redis",
|
||||
"CACHE_REDIS_PORT": 6379,
|
||||
"CACHE_REDIS_DB": 1,
|
||||
"CACHE_REDIS_URL": f"redis://:{os.getenv('REDIS_PASSWORD')}@redis:6379/1",
|
||||
}
|
||||
|
||||
FILTER_STATE_CACHE_CONFIG = {**CACHE_CONFIG, "CACHE_KEY_PREFIX": "superset_filter_"}
|
||||
EXPLORE_FORM_DATA_CACHE_CONFIG = {**CACHE_CONFIG, "CACHE_KEY_PREFIX": "superset_explore_form_"}
|
||||
|
||||
SQLALCHEMY_TRACK_MODIFICATIONS = True
|
||||
SQLALCHEMY_DATABASE_URI = f"postgresql+psycopg2://{os.getenv('POSTGRES_USER')}:{os.getenv('POSTGRES_PASSWORD')}@postgres:5432/{os.getenv('POSTGRES_DB')}"
|
||||
|
||||
# Uncomment if you want to load example data (using "superset load_examples") at the
|
||||
# same location as your metadata postgresql instance. Otherwise, the default sqlite
|
||||
# will be used, which will not persist in volume when restarting superset by default.
|
||||
#SQLALCHEMY_EXAMPLES_URI = SQLALCHEMY_DATABASE_URI
|
||||
depends_on:
|
||||
postgres:
|
||||
condition: service_healthy
|
||||
redis:
|
||||
condition: service_healthy
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://127.0.0.1:8088/health"]
|
||||
interval: 5s
|
||||
timeout: 20s
|
||||
retries: 10
|
||||
|
||||
postgres:
|
||||
image: postgres:17-alpine
|
||||
environment:
|
||||
- POSTGRES_USER=${SERVICE_USER_POSTGRES}
|
||||
- POSTGRES_PASSWORD=${SERVICE_PASSWORD_POSTGRES}
|
||||
- POSTGRES_DB=${POSTGRES_DB:-superset-db}
|
||||
volumes:
|
||||
- superset_postgres_data:/var/lib/postgresql/data
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}"]
|
||||
interval: 5s
|
||||
timeout: 20s
|
||||
retries: 10
|
||||
|
||||
redis:
|
||||
image: redis:8-alpine
|
||||
volumes:
|
||||
- superset_redis_data:/data
|
||||
command: redis-server --requirepass ${SERVICE_PASSWORD_REDIS}
|
||||
healthcheck:
|
||||
test: redis-cli ping
|
||||
interval: 5s
|
||||
timeout: 20s
|
||||
retries: 10
|
||||
@@ -11,7 +11,7 @@ services:
|
||||
- SERVICE_FQDN_TYPESENSE_8108
|
||||
- TYPESENSE_ENABLE_CORS=${TYPESENSE_ENABLE_CORS:-true}
|
||||
- TYPESENSE_DATA_DIR=/data
|
||||
- TYPESENSE_API_KEY=${TYPESENSE_API_KEY:-xyz}
|
||||
- TYPESENSE_API_KEY=${TYPESENSE_API_KEY:?}
|
||||
volumes:
|
||||
- typesense_data:/data
|
||||
healthcheck:
|
||||
|
||||
66
templates/compose/yamtrack-with-postgresql.yaml
Normal file
66
templates/compose/yamtrack-with-postgresql.yaml
Normal file
@@ -0,0 +1,66 @@
|
||||
# documentation: https://github.com/FuzzyGrim/Yamtrack/wiki
|
||||
# slogan: Yamtrack is a self hosted media tracker for movies, tv shows, anime, manga, video games and books.
|
||||
# tags: self-hosted, automation, tracker, media, movies, shows, anime, manga, games, books, comics
|
||||
# logo: svgs/yamtrack.svg
|
||||
# port: 8000
|
||||
|
||||
services:
|
||||
yamtrack:
|
||||
image: ghcr.io/fuzzygrim/yamtrack
|
||||
environment:
|
||||
- SERVICE_FQDN_YAMTRACK_8000
|
||||
- URLS=${SERVICE_FQDN_YAMTRACK}
|
||||
- TZ=${TZ:-Europe/Berlin}
|
||||
- SECRET=${SERVICE_PASSWORD_SECRET}
|
||||
- REGISTRATION=${REGISTRATION_ENABLED:-true}
|
||||
- REDIS_URL=redis://redis:6379
|
||||
- DB_HOST=postgres
|
||||
- DB_NAME=${POSTGRESQL_DATABASE:-yamtrack-db}
|
||||
- DB_USER=${SERVICE_USER_POSTGRESQL}
|
||||
- DB_PASSWORD=${SERVICE_PASSWORD_POSTGRESQL}
|
||||
- DB_PORT=5432
|
||||
depends_on:
|
||||
postgres:
|
||||
condition: service_healthy
|
||||
redis:
|
||||
condition: service_healthy
|
||||
healthcheck:
|
||||
test:
|
||||
[
|
||||
"CMD",
|
||||
"wget",
|
||||
"--no-verbose",
|
||||
"--tries=1",
|
||||
"--spider",
|
||||
"http://127.0.0.1:8000/health/",
|
||||
]
|
||||
interval: 5s
|
||||
timeout: 20s
|
||||
retries: 10
|
||||
|
||||
postgres:
|
||||
image: postgres:16-alpine
|
||||
environment:
|
||||
- POSTGRES_USER=${SERVICE_USER_POSTGRESQL}
|
||||
- POSTGRES_PASSWORD=${SERVICE_PASSWORD_POSTGRESQL}
|
||||
- POSTGRES_DB=${POSTGRESQL_DATABASE:-yamtrack-db}
|
||||
volumes:
|
||||
- yamtrack_postgres_data:/var/lib/postgresql/data
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}"]
|
||||
interval: 5s
|
||||
timeout: 20s
|
||||
retries: 10
|
||||
|
||||
redis:
|
||||
image: redis:7-alpine
|
||||
volumes:
|
||||
- yamtrack_redis_data:/data
|
||||
healthcheck:
|
||||
test:
|
||||
- CMD
|
||||
- redis-cli
|
||||
- ping
|
||||
interval: 5s
|
||||
timeout: 20s
|
||||
retries: 10
|
||||
43
templates/compose/yamtrack.yaml
Normal file
43
templates/compose/yamtrack.yaml
Normal file
@@ -0,0 +1,43 @@
|
||||
# documentation: https://github.com/FuzzyGrim/Yamtrack/wiki
|
||||
# slogan: Yamtrack is a self hosted media tracker for movies, tv shows, anime, manga, video games and books.
|
||||
# tags: self-hosted, automation, tracker, media, movies, shows, anime, manga, games, books, comics
|
||||
# logo: svgs/yamtrack.svg
|
||||
# port: 8000
|
||||
|
||||
services:
|
||||
yamtrack:
|
||||
image: ghcr.io/fuzzygrim/yamtrack
|
||||
environment:
|
||||
- SERVICE_FQDN_YAMTRACK_8000
|
||||
- URLS=${SERVICE_FQDN_YAMTRACK}
|
||||
- TZ=${TZ:-Europe/Berlin}
|
||||
- SECRET=${SERVICE_PASSWORD_SECRET}
|
||||
- REGISTRATION=${REGISTRATION_ENABLED:-true}
|
||||
- REDIS_URL=redis://redis:6379
|
||||
volumes:
|
||||
- yamtrack_data:/yamtrack/db
|
||||
depends_on:
|
||||
redis:
|
||||
condition: service_healthy
|
||||
healthcheck:
|
||||
test:
|
||||
[
|
||||
"CMD-SHELL",
|
||||
"wget --quiet --tries=1 --spider http://127.0.0.1:8000/health/ || exit 1",
|
||||
]
|
||||
interval: 5s
|
||||
timeout: 20s
|
||||
retries: 10
|
||||
|
||||
redis:
|
||||
image: redis:7-alpine
|
||||
volumes:
|
||||
- yamtrack_redis_data:/data
|
||||
healthcheck:
|
||||
test:
|
||||
- CMD
|
||||
- redis-cli
|
||||
- ping
|
||||
interval: 5s
|
||||
timeout: 20s
|
||||
retries: 10
|
||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user