Merge branch 'next' into patch-1

This commit is contained in:
Andras Bacsai
2025-05-20 14:09:31 +02:00
committed by GitHub
159 changed files with 3561 additions and 2220 deletions

2
.gitignore vendored
View File

@@ -36,4 +36,4 @@ scripts/load-test/*
.env.dusk.local
docker/coolify-realtime/node_modules
.DS_Store
Changelog.md
CHANGELOG.md

View File

@@ -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);
}
}
}

View File

@@ -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

View File

@@ -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);
}
}

View File

@@ -0,0 +1,227 @@
<?php
namespace App\Actions\Server;
use App\Models\Server;
use Lorisleiva\Actions\Concerns\AsAction;
class CheckUpdates
{
use AsAction;
public string $jobQueue = 'high';
public function handle(Server $server)
{
try {
if ($server->serverStatus() === false) {
return [
'error' => 'Server is not reachable or not ready.',
];
}
// Try first method - using instant_remote_process
$output = instant_remote_process(['cat /etc/os-release'], $server);
// Parse os-release into an associative array
$osInfo = [];
foreach (explode("\n", $output) as $line) {
if (empty($line)) {
continue;
}
if (strpos($line, '=') === false) {
continue;
}
[$key, $value] = explode('=', $line, 2);
$osInfo[$key] = trim($value, '"');
}
// Get the main OS identifier
$osId = $osInfo['ID'] ?? '';
// $osIdLike = $osInfo['ID_LIKE'] ?? '';
// $versionId = $osInfo['VERSION_ID'] ?? '';
// Normalize OS types based on install.sh logic
switch ($osId) {
case 'manjaro':
case 'manjaro-arm':
case 'endeavouros':
$osType = 'arch';
break;
case 'pop':
case 'linuxmint':
case 'zorin':
$osType = 'ubuntu';
break;
case 'fedora-asahi-remix':
$osType = 'fedora';
break;
default:
$osType = $osId;
}
// Determine package manager based on OS type
$packageManager = match ($osType) {
'arch' => 'pacman',
'alpine' => 'apk',
'ubuntu', 'debian', 'raspbian' => 'apt',
'centos', 'fedora', 'rhel', 'ol', 'rocky', 'almalinux', 'amzn' => 'dnf',
'sles', 'opensuse-leap', 'opensuse-tumbleweed' => 'zypper',
default => null
};
switch ($packageManager) {
case 'zypper':
$output = instant_remote_process(['LANG=C zypper -tx list-updates'], $server);
$out = $this->parseZypperOutput($output);
$out['osId'] = $osId;
$out['package_manager'] = $packageManager;
return $out;
case 'dnf':
$output = instant_remote_process(['LANG=C dnf list -q --updates --refresh'], $server);
$out = $this->parseDnfOutput($output);
$out['osId'] = $osId;
$out['package_manager'] = $packageManager;
$rebootRequired = instant_remote_process(['LANG=C dnf needs-restarting -r'], $server);
$out['reboot_required'] = $rebootRequired !== '0';
return $out;
case 'apt':
instant_remote_process(['apt-get update -qq'], $server);
$output = instant_remote_process(['LANG=C apt list --upgradable 2>/dev/null'], $server);
$out = $this->parseAptOutput($output);
$out['osId'] = $osId;
$out['package_manager'] = $packageManager;
$rebootRequired = instant_remote_process(['LANG=C test -f /var/run/reboot-required && echo "YES" || echo "NO"'], $server);
$out['reboot_required'] = $rebootRequired === 'YES' ? true : false;
return $out;
default:
return [
'osId' => $osId,
'error' => 'Unsupported package manager',
'package_manager' => $packageManager,
];
}
} catch (\Throwable $e) {
ray('Error:', $e->getMessage());
return [
'osId' => $osId,
'package_manager' => $packageManager,
'error' => $e->getMessage(),
'trace' => $e->getTraceAsString(),
];
}
}
private function parseZypperOutput(string $output): array
{
$updates = [];
try {
$xml = simplexml_load_string($output);
if ($xml === false) {
return [
'total_updates' => 0,
'updates' => [],
'error' => 'Failed to parse XML output',
];
}
// Navigate to the update-list node
$updateList = $xml->xpath('//update-list/update');
foreach ($updateList as $update) {
$updates[] = [
'package' => (string) $update['name'],
'new_version' => (string) $update['edition'],
'current_version' => (string) $update['edition-old'],
'architecture' => (string) $update['arch'],
'repository' => (string) $update->source['alias'],
'summary' => (string) $update->summary,
'description' => (string) $update->description,
];
}
return [
'total_updates' => count($updates),
'updates' => $updates,
];
} catch (\Throwable $e) {
return [
'total_updates' => 0,
'updates' => [],
'error' => 'Error parsing zypper output: '.$e->getMessage(),
];
}
}
private function parseDnfOutput(string $output): array
{
$updates = [];
$lines = explode("\n", $output);
foreach ($lines as $line) {
if (empty($line)) {
continue;
}
// Split by multiple spaces/tabs and filter out empty elements
$parts = array_values(array_filter(preg_split('/\s+/', $line)));
if (count($parts) >= 3) {
$package = $parts[0];
$new_version = $parts[1];
$repository = $parts[2];
// Extract architecture from package name (e.g., "cloud-init.noarch" -> "noarch")
$architecture = str_contains($package, '.') ? explode('.', $package)[1] : 'noarch';
$updates[] = [
'package' => $package,
'new_version' => $new_version,
'repository' => $repository,
'architecture' => $architecture,
'current_version' => 'unknown', // DNF doesn't show current version in check-update output
];
}
}
return [
'total_updates' => count($updates),
'updates' => $updates,
];
}
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,
];
}
}

View File

@@ -0,0 +1,52 @@
<?php
namespace App\Actions\Server;
use App\Models\Server;
use Lorisleiva\Actions\Concerns\AsAction;
use Spatie\Activitylog\Contracts\Activity;
class UpdatePackage
{
use AsAction;
public string $jobQueue = 'high';
public function handle(Server $server, string $osId, ?string $package = null, ?string $packageManager = null, bool $all = false): Activity|array
{
try {
if ($server->serverStatus() === false) {
return [
'error' => 'Server is not reachable or not ready.',
];
}
switch ($packageManager) {
case 'zypper':
$commandAll = 'zypper update -y';
$commandInstall = 'zypper install -y '.$package;
break;
case 'dnf':
$commandAll = 'dnf update -y';
$commandInstall = 'dnf update -y '.$package;
break;
case 'apt':
$commandAll = 'apt update && apt upgrade -y';
$commandInstall = 'apt install -y '.$package;
break;
default:
return [
'error' => 'OS not supported',
];
}
if ($all) {
return remote_process([$commandAll], $server);
}
return remote_process([$commandInstall], $server);
} catch (\Exception $e) {
return [
'error' => $e->getMessage(),
];
}
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}
}

View 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 ServerPackageUpdated 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}"),
];
}
}

View 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}"),
];
}
}

View File

@@ -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}"),
];
}
}

View File

@@ -989,7 +989,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) {
@@ -1095,7 +1122,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 +1972,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) {

View File

@@ -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;
}

View File

@@ -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'));
}
}

View File

@@ -22,6 +22,8 @@ class ActivityMonitor extends Component
protected $activity;
public static $eventDispatched = false;
protected $listeners = ['activityMonitor' => 'newMonitorActivity'];
public function newMonitorActivity($activityId, $eventToDispatch = 'activityFinished')
@@ -51,15 +53,19 @@ class ActivityMonitor extends Component
$causer_id = data_get($this->activity, 'causer_id');
$user = User::find($causer_id);
if ($user) {
foreach ($user->teams as $team) {
$teamId = $team->id;
$teamId = $user->currentTeam()->id;
if (! self::$eventDispatched) {
$this->eventToDispatch::dispatch($teamId);
self::$eventDispatched = true;
}
}
return;
}
$this->dispatch($this->eventToDispatch);
if (! self::$eventDispatched) {
$this->dispatch($this->eventToDispatch);
self::$eventDispatched = true;
}
}
}
}

View File

@@ -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()
{

View File

@@ -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();

View File

@@ -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()
{

View File

@@ -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,14 +46,11 @@ 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.');
}
}
public function force_deploy_without_cache()
@@ -111,16 +108,7 @@ 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'));
StopApplication::dispatch($this->application, false, $this->docker_cleanup);
}
public function restart()

View File

@@ -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();

View File

@@ -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,38 @@ 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);
}
}
@@ -59,23 +61,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', 'Stopping 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()

View File

@@ -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);
}

View File

@@ -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) {

View File

@@ -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,42 @@ 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');
} else {
$this->dispatch('configurationChanged');
if ($this->service->server->isFunctional()) {
GetContainersStatus::dispatch($this->service->server);
}
}
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 +94,32 @@ 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.');
}
StopService::dispatch($this->service, false, $this->docker_cleanup);
} catch (\Exception $e) {
$this->dispatch('error', $e->getMessage());
}
@@ -128,7 +134,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 +146,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')],
],

View File

@@ -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)

View File

@@ -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()) {

View File

@@ -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 {

View File

@@ -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 {

View File

@@ -0,0 +1,102 @@
<?php
namespace App\Livewire\Server\Security;
use App\Actions\Server\CheckUpdates;
use App\Actions\Server\UpdatePackage;
use App\Events\ServerPackageUpdated;
use App\Models\Server;
use Livewire\Component;
class Patches extends Component
{
public array $parameters;
public Server $server;
public ?int $totalUpdates = null;
public ?array $updates = null;
public ?string $error = null;
public ?string $osId = null;
public ?string $packageManager = null;
public function getListeners()
{
$teamId = auth()->user()->currentTeam()->id;
return [
"echo-private:team.{$teamId},ServerPackageUpdated" => 'checkForUpdatesDispatch',
];
}
public function mount()
{
if (! auth()->user()->isAdmin()) {
abort(403);
}
$this->parameters = get_route_parameters();
$this->server = Server::ownedByCurrentTeam()->whereUuid($this->parameters['server_uuid'])->firstOrFail();
}
public function checkForUpdatesDispatch()
{
$this->totalUpdates = null;
$this->updates = null;
$this->error = null;
$this->osId = null;
$this->packageManager = null;
$this->dispatch('checkForUpdatesDispatch');
}
public function checkForUpdates()
{
$job = CheckUpdates::run($this->server);
if (isset($job['error'])) {
$this->error = data_get($job, 'error', 'Something went wrong.');
} else {
$this->totalUpdates = data_get($job, 'total_updates', 0);
$this->updates = data_get($job, 'updates', []);
$this->osId = data_get($job, 'osId', null);
$this->packageManager = data_get($job, 'package_manager', null);
}
}
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
);
$this->dispatch('activityMonitor', $activity->id, ServerPackageUpdated::class);
} catch (\Exception $e) {
$this->dispatch('error', message: $e->getMessage());
}
}
public function updatePackage($package)
{
try {
$activity = UpdatePackage::run(server: $this->server, packageManager: $this->packageManager, osId: $this->osId, package: $package);
$this->dispatch('activityMonitor', $activity->id, ServerPackageUpdated::class);
} catch (\Exception $e) {
$this->dispatch('error', message: $e->getMessage());
}
}
public function render()
{
return view('livewire.server.security.patches');
}
}

View File

@@ -21,7 +21,7 @@ class Checkbox extends Component
public string|bool|null $checked = false,
public string|bool $instantSave = false,
public bool $disabled = false,
public string $defaultClass = 'dark:border-neutral-700 text-coolgray-400 focus:ring-warning dark:bg-coolgray-100 rounded cursor-pointer dark:disabled:bg-base dark:disabled:cursor-not-allowed',
public string $defaultClass = 'dark:border-neutral-700 text-coolgray-400 focus:ring-warning dark:bg-coolgray-100 rounded-sm cursor-pointer dark:disabled:bg-base dark:disabled:cursor-not-allowed',
) {
if ($this->disabled) {
$this->defaultClass .= ' opacity-40';

View File

@@ -2,7 +2,7 @@
return [
'coolify' => [
'version' => '4.0.0-beta.418',
'version' => '4.0.0-beta.419',
'helper_version' => '1.0.8',
'realtime_version' => '1.0.8',
'self_hosted' => env('SELF_HOSTED', true),

View File

@@ -34,10 +34,10 @@ USER www-data
# =================================================================
# Stage 2: Frontend assets compilation
# =================================================================
FROM node:20-alpine AS static-assets
FROM node:24-alpine AS static-assets
WORKDIR /app
COPY package*.json vite.config.js tailwind.config.js postcss.config.cjs ./
COPY package*.json vite.config.js postcss.config.cjs ./
RUN npm ci
COPY . .
RUN npm run build

View File

@@ -1,10 +1,10 @@
{
"coolify": {
"v4": {
"version": "4.0.0-beta.418"
"version": "4.0.0-beta.419"
},
"nightly": {
"version": "4.0.0-beta.419"
"version": "4.0.0-beta.420"
},
"helper": {
"version": "1.0.8"

2491
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -7,16 +7,16 @@
"build": "vite build"
},
"devDependencies": {
"@tailwindcss/postcss": "^4.1.4",
"@vitejs/plugin-vue": "5.2.3",
"autoprefixer": "10.4.21",
"axios": "1.8.4",
"laravel-echo": "2.0.2",
"laravel-vite-plugin": "^1.2.0",
"postcss": "8.5.3",
"pusher-js": "8.4.0",
"tailwind-scrollbar": "^3.1.0",
"tailwindcss": "3.4.17",
"vite": "^6.3.4",
"tailwind-scrollbar": "^4.0.2",
"tailwindcss": "^4.1.4",
"vite": "^6.2.6",
"vue": "3.5.13"
},
"dependencies": {

View File

@@ -1,6 +1,5 @@
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {},
'@tailwindcss/postcss': {},
},
}

File diff suppressed because one or more lines are too long

BIN
public/svgs/codimd.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

38
public/svgs/diun.svg Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 18 KiB

1
public/svgs/leantime.svg Executable file
View File

@@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><svg id="a" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 3394.83 910.4"><path d="M3186.54,268.23c-115.03,0-208.29,93.25-208.29,208.29s93.25,208.29,208.29,208.29v-56.89h0c-.13-.01-.26,0-.4,0-83.99,0-152.07-68.09-152.07-152.07s68.09-152.07,152.07-152.07,152.07,68.09,152.07,152.07c0,7.09-.65,14.01-1.59,20.84,19.43,.06,38.58,.24,56.12,.61,1-7.5,1.73-13.47,2.08-20.79,0-115.03-93.25-208.29-208.29-208.29Z" fill="#fff"/><rect x="3175.72" y="337.31" width="20.84" height="148.32" fill="#fff"/><rect x="3175.72" y="477.67" width="113.14" height="19.55" fill="#fff"/><g><path d="M93.6,664.4c-16.54-20-24.8-55.33-24.8-106V84h32.8v472c0,28.8,2.66,50.94,8,66.4,5.32,15.47,12.8,26.28,22.4,32.4,9.6,6.14,22.4,10,38.4,11.6l48.8,5.6v22.4h-50.4c-33.6,0-58.67-10-75.2-30Z" fill="#fff"/><path d="M366.79,678.8c-24.27-13.6-41.6-36.12-52-67.6-10.4-31.46-15.6-75.2-15.6-131.2s5.6-99.46,16.8-130.4c11.2-30.92,29.06-52.92,53.6-66,24.52-13.06,58.66-19.6,102.4-19.6,54.4,0,94,10.28,118.8,30.8,24.8,20.54,37.2,56.14,37.2,106.8,0,64-37.6,96-112.8,96h-183.2c0,44.27,3.86,78.8,11.6,103.6,7.72,24.8,21.86,42.8,42.4,54,20.52,11.2,50.26,16.8,89.2,16.8h144v20c-51.74,4.8-101.6,7.2-149.6,7.2-44.28,0-78.54-6.8-102.8-20.4Zm146.8-206c29.32,0,50.66-5.2,64-15.6,13.32-10.4,20-28.92,20-55.6,0-28.8-4.14-51.2-12.4-67.2-8.28-16-21.34-27.33-39.2-34-17.87-6.66-42.54-10-74-10-37.34,0-65.88,5.2-85.6,15.6-19.74,10.4-33.74,28.54-42,54.4-8.27,25.88-12.4,63.34-12.4,112.4h181.6Z" fill="#fff"/><path d="M771.59,670.8c-20-18.93-30-44.93-30-78v-26.4c0-34.66,11.2-62.12,33.6-82.4,22.4-20.26,54.4-30.4,96-30.4h164v-65.6c0-32.52-8.8-57.2-26.4-74-17.6-16.8-48.8-25.2-93.6-25.2h-135.2v-20c53.86-4.8,102.4-7.2,145.6-7.2,49.6,0,85.73,10.4,108.4,31.2,22.66,20.8,34,52.27,34,94.4v307.2h-24l-8-50.4c-2.67,2.14-15.08,7.88-37.2,17.2-22.14,9.34-46.94,18-74.4,26-27.47,8-52.67,12-75.6,12-31.47,0-57.2-9.46-77.2-28.4Zm154-9.6c26.12-6.66,49.46-13.6,70-20.8,20.53-7.2,33.73-12.12,39.6-14.8v-152.8l-163.2,4.8c-34.14,1.6-58.94,10.27-74.4,26-15.47,15.74-23.2,36.67-23.2,62.8v20.8c0,29.34,8.53,50.67,25.6,64,17.06,13.34,37.06,20,60,20,17.6,0,39.46-3.33,65.6-10Z" fill="#fff"/><path d="M1222.38,268.8h23.2l9.6,48.8c25.06-16.53,52-30,80.8-40.4,28.8-10.4,57.86-15.6,87.2-15.6,27.73,0,51.46,6.4,71.2,19.2,19.73,12.8,34.66,29.74,44.8,50.8,10.12,21.08,15.2,43.88,15.2,68.4v294.4h-32.8V402.4c0-31.46-9.47-57.86-28.4-79.2-18.94-21.33-44.4-32-76.4-32s-57.2,3.74-80.4,11.2c-23.2,7.47-50.27,19.74-81.2,36.8v355.2h-32.8V268.8Z" fill="#fff"/><path d="M1750.38,662c-19.74-21.6-29.07-56.92-28-106l2.4-236.8h-68v-40.8l68.8-11.2,10.4-119.2h48.8v119.2h123.2v52h-123.2v236.8c0,32.54,6.12,54.8,18.4,66.8,12.26,12,27.72,18.8,46.4,20.4l52,4.8v46.4h-58.4c-42.14,0-73.08-10.8-92.8-32.4Z" fill="#fff"/><path d="M2015.57,187.6c-2.4-2.4-3.6-5.46-3.6-9.2v-62.4c0-8.52,4.26-12.8,12.8-12.8h44.8c8,0,12,4.28,12,12.8v62.4c0,8.54-4,12.8-12,12.8h-44.8c-3.74,0-6.8-1.2-9.2-3.6Zm-.4,79.6h63.2v427.2h-63.2V267.2Z" fill="#fff"/><path d="M2219.96,267.2h49.6l13.6,47.2c53.33-36.26,106.66-54.4,160-54.4,25.6,0,47.86,5.74,66.8,17.2,18.92,11.48,33.73,26.8,44.4,46,22.4-16.52,49.72-31.2,82-44,32.26-12.8,62.26-19.2,90-19.2,44.26,0,77.6,13.6,100,40.8,22.4,27.2,33.6,62.4,33.6,105.6v288h-63.2V411.2c0-27.72-8.14-50.26-24.4-67.6-16.28-17.33-38.28-26-66-26-22.94,0-46.8,4.27-71.6,12.8-24.8,8.54-48.67,19.74-71.6,33.6,5.33,17.08,8,33.08,8,48v282.4h-63.2V411.2c0-27.72-7.88-50.26-23.6-67.6-15.74-17.33-37.48-26-65.2-26-25.6,0-48.4,3.34-68.4,10-20,6.67-42.54,17.2-67.6,31.6v335.2h-63.2V267.2Z" fill="#fff"/></g></svg>

After

Width:  |  Height:  |  Size: 3.5 KiB

View File

@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="344.59042" height="374.29803" version="1.1" viewBox="0 0 344.59042 374.29803" xmlns="http://www.w3.org/2000/svg">
<defs>
<linearGradient id="linearGradient925" x1="8.9167995" x2="33.738998" y1="11.905" y2="11.905" gradientTransform="matrix(12.491,0,0,5.9363,232.56,210.1)" gradientUnits="userSpaceOnUse">
<stop stop-color="#11861e" offset="0" />
<stop stop-color="#0eb13f" offset="1" />
</linearGradient>
<linearGradient id="linearGradient997" x1="494.85999" x2="590.25" y1="351.31" y2="351.31" gradientTransform="translate(135.91,623.3)" gradientUnits="userSpaceOnUse">
<stop stop-color="#4dcf00" offset="0" />
<stop stop-color="#50d400" offset="1" />
</linearGradient>
<linearGradient id="linearGradient1005" x1="497.82001" x2="606.04999" y1="473.53" y2="473.53" gradientTransform="translate(135.91,623.3)" gradientUnits="userSpaceOnUse">
<stop stop-color="#4ed000" offset="0" />
<stop stop-color="#50d400" offset="1" />
</linearGradient>
<linearGradient id="linearGradient1013" x1="318.29999" x2="509.31" y1="529.09003" y2="529.09003" gradientTransform="translate(135.91,623.3)" gradientUnits="userSpaceOnUse">
<stop stop-color="#3bb200" offset="0" />
<stop stop-color="#4dce00" offset="1" />
</linearGradient>
<linearGradient id="linearGradient1021" x1="304.04001" x2="407.64999" y1="397.17999" y2="397.17999" gradientTransform="translate(135.91,623.3)" gradientUnits="userSpaceOnUse">
<stop stop-color="#3bb100" offset="0" />
<stop stop-color="#40ba00" offset="1" />
</linearGradient>
</defs>
<g transform="translate(-304.03838,-209.99777)" stroke-width="8.611">
<path class="b" d="m 350.79,246.11 a 104.37,104.37 0 0 1 33.325,6.1827 189.37,189.37 0 0 1 30.819,13.95 266.08,266.08 0 0 1 28.244,18.23 c 4.495,3.3411 8.8952,6.7424 13.218,10.333 2.1786,1.7739 4.3055,3.608 6.4066,5.4852 1.0592,0.92139 2.1097,1.8772 3.1689,2.8244 l 1.5672,1.4983 1.7222,1.6017 -31.31,0.0689 2.79,-3.2722 2.5833,-2.8933 c 1.7222,-1.9116 3.4444,-3.7458 5.2441,-5.5886 q 5.313,-5.4164 10.833,-10.488 c 3.6769,-3.3755 7.4916,-6.6391 11.306,-9.808 1.9375,-1.5672 3.8836,-3.1344 5.8211,-4.6672 l 2.9278,-2.3164 2.9966,-2.213 c 7.9738,-5.9588 16.249,-11.444 24.765,-16.593 8.516,-5.149 17.308,-9.7391 26.264,-14.002 a 268.42,268.42 0 0 1 56.144,-19.297 230.43,230.43 0 0 1 29.278,-4.4605 169.64,169.64 0 0 1 29.725,-0.0689 c -4.1591,2.8589 -8.3786,5.2786 -12.503,7.8705 -2.0408,1.2917 -4.1247,2.5833 -6.2,3.7458 -1.0247,0.61138 -2.0408,1.2228 -3.0655,1.8772 l -3.0655,1.8772 c -8.146,4.9083 -16.077,9.8769 -23.982,14.716 -15.741,9.808 -31,19.659 -45.957,29.811 -14.957,10.152 -29.536,20.529 -43.804,31.293 -3.5392,2.7211 -7.1213,5.3819 -10.626,8.1719 -3.5047,2.79 -6.9836,5.5197 -10.462,8.2752 -3.4789,2.7555 -6.8888,5.623 -10.221,8.4474 -1.6705,1.4294 -3.3411,2.8244 -4.9772,4.228 l -4.495,3.9525 -18.944,16.662 -12.391,-16.585 c -0.24111,-0.34445 -0.68027,-0.86111 -1.0592,-1.2917 l -1.1883,-1.4294 -2.4197,-2.8933 -4.9427,-5.8211 q -5.0116,-5.8211 -10.118,-11.616 c -6.8113,-7.6983 -13.726,-15.362 -20.847,-22.888 -7.121,-7.526 -14.346,-14.957 -21.975,-22.139 a 248.98,248.98 0 0 0 -24.593,-20.77 z" fill="url(#linearGradient925)" />
<path class="c" d="m 455.04,524.95 a 91.734,91.734 0 0 1 -82.132,-51.064 l -54.611,23.508 a 151.02,151.02 0 0 0 191.01,76.811 l -23.474,-54.611 a 91.398,91.398 0 0 1 -30.793,5.3561 z" fill="url(#linearGradient1013)" />
<path class="d" d="m 363.43,433.27 a 91.708,91.708 0 0 1 44.218,-78.361 l -38.431,-45.811 a 151,151 0 0 0 -55.972,176.16 l 54.706,-23.508 a 91.432,91.432 0 0 1 -4.5208,-28.477 z" fill="url(#linearGradient1021)" />
<path class="e" d="m 546.13,312.95 -51.27,37.889 a 92.491,92.491 0 0 1 40.713,38.836 l 54.68,-23.508 A 152.07,152.07 0 0 0 546.13,312.951 Z" fill="url(#linearGradient997)" />
<path class="f" d="m 606.05,433.31 a 150.02,150.02 0 0 0 -10.462,-55.188 l -54.577,23.474 a 91.63,91.63 0 0 1 -43.193,112.72 l 23.508,54.628 a 151.19,151.19 0 0 0 84.724,-135.63 z" fill="url(#linearGradient1005)" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 4.0 KiB

112
public/svgs/marimo.svg Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 18 KiB

BIN
public/svgs/memos.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

View File

@@ -0,0 +1 @@
<svg height="256.024" viewBox="0 0 67.74 67.74" width="256.024" xmlns="http://www.w3.org/2000/svg"><g stroke="#000"><circle cx="33.86958" cy="33.869496" fill="#0084ff" r="32.499" stroke-width="2.74219"/><g stroke-width="2.64583"><circle cx="33.86958" cy="33.869496" fill="#fff" r="11.573"/><path d="m161.58928 117.1873c0 10.77898-8.73809 19.51707-19.51707 19.51707m-19.51706-19.51707c0-10.77898 8.73809-19.517068 19.51706-19.517067" fill="none" stroke-linecap="round" transform="translate(-108.20242 -83.317504)"/><path d="m167.71209 117.1873c0 .32994-.006.65843-.0186.98535m-.60107 4.64276c-2.56514 11.4532-12.7932 20.01177-25.02022 20.01177m-25.63986-25.63988c0-.29458.005-.58801.0148-.88019m.49655-4.2403c2.37274-11.707 12.7215-20.519383 25.1285-20.519383" fill="none" stroke-linecap="round" transform="translate(-108.20242 -83.317504)"/><circle cx="33.86958" cy="33.869496" fill="#fff" r="2.391"/></g></g></svg>

After

Width:  |  Height:  |  Size: 915 B

BIN
public/svgs/observium.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

44
public/svgs/passbolt.svg Normal file
View File

@@ -0,0 +1,44 @@
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 160 30"
>
<path
fill="#fff"
fill-rule="evenodd"
d="M79.777.85v5.947h3.701c1.648 0 2.944.19 3.944.598 1 .38 1.836 1.033 2.538 1.93a7.926 7.926 0 0 1 1.323 2.499c.298.895.433 1.901.433 2.987 0 2.635-.703 4.7-2.106 6.193-1.405 1.494-3.348 2.227-5.859 2.227h-8.317V.849h4.343Zm2.621 9.508h-2.646v9.37h2.971c1.648 0 2.809-.353 3.456-1.034.675-.705 1-1.874 1-3.558 0-1.683-.377-2.932-1.107-3.668-.703-.76-1.946-1.113-3.674-1.113v.003Z"
clip-rule="evenodd"
/>
<path
fill="#fff"
d="M38.35 19.808h9.1c.81 0 1.405-.135 1.755-.38.378-.246.568-.654.568-1.221 0-.568-.19-.979-.568-1.224-.377-.273-.973-.408-1.755-.408h-3.727c-2.215 0-3.7-.353-4.483-1.034-.783-.677-1.16-1.901-1.16-3.613 0-1.711.46-3.07 1.405-3.91.945-.844 2.403-1.249 4.349-1.249h9.262v3.423h-7.614c-1.243 0-2.053.108-2.431.325-.378.218-.568.599-.568 1.169 0 .515.163.896.485 1.113.326.246.866.353 1.566.353h3.916c1.783 0 3.161.436 4.079 1.276.945.843 1.405 2.037 1.405 3.613 0 1.577-.432 2.77-1.27 3.72-.838.952-1.89 1.44-3.214 1.44h-11.1v-3.393Z"
/>
<path
fill="#fff"
fill-rule="evenodd"
d="M8.318 6.797H0V29.15h4.321v-5.948h3.724c1.648 0 2.943-.19 3.944-.57a6.313 6.313 0 0 0 2.538-1.957 7.845 7.845 0 0 0 1.323-2.472c.297-.896.432-1.902.432-2.988 0-2.634-.7-4.699-2.105-6.192-1.403-1.494-3.349-2.227-5.86-2.227ZM4.32 19.727V10.36H7.29c1.645 0 2.78.325 3.455 1.059.676.678 1.001 1.791 1.001 3.502 0 1.712-.35 2.96-1.08 3.694-.728.733-1.943 1.113-3.699 1.113H4.321ZM28.086 6.8h-8.83l-.003.002v3.396h7.185c1.486 0 2.483.19 3.05.598.569.408.866 1.086.866 2.064v.408h-5.671c-2.351 0-4.024.405-5.025 1.22-1 .817-1.485 2.148-1.485 4.022 0 1.521.43 2.687 1.295 3.503.863.813 2.133 1.22 3.754 1.22h11.614V12.94c0-2.04-.566-3.558-1.701-4.592C32.002 7.315 30.327 6.8 28.086 6.8Zm2.296 13.118H24.98c-.945 0-1.565-.107-1.863-.325-.298-.245-.46-.653-.46-1.224 0-.678.19-1.166.568-1.438.38-.273 1.08-.408 2.08-.408h5.077v3.395Z"
clip-rule="evenodd"
/>
<path
fill="#fff"
d="M65.868 19.808h-9.1l.002-.003h-.055V23.2H67.87c1.322 0 2.375-.487 3.213-1.438.838-.951 1.27-2.144 1.27-3.72 0-1.577-.46-2.77-1.405-3.614-.918-.84-2.296-1.276-4.079-1.276h-3.916c-.7 0-1.24-.107-1.566-.353-.322-.217-.485-.598-.485-1.113 0-.57.19-.95.568-1.169.378-.217 1.188-.325 2.431-.325h7.615V6.77h-9.263c-1.946 0-3.404.405-4.349 1.249-.945.84-1.406 2.199-1.406 3.91 0 1.712.378 2.936 1.16 3.613.783.681 2.269 1.034 4.485 1.034h3.726c.782 0 1.378.135 1.755.408.378.245.568.656.568 1.224 0 .567-.19.975-.568 1.22-.35.246-.945.38-1.755.38Z"
/>
<path
fill="#fff"
fill-rule="evenodd"
d="M108.268 21.222c1.569-1.55 2.351-3.614 2.351-6.193 0-2.58-.785-4.644-2.351-6.165-1.565-1.549-3.646-2.337-6.292-2.337-2.645 0-4.754.788-6.319 2.337-1.568 1.549-2.35 3.613-2.35 6.192 0 2.58.785 4.617 2.35 6.166 1.565 1.548 3.674 2.31 6.319 2.31 2.646 0 4.724-.79 6.292-2.31Zm-9.37-2.525c-.73-.898-1.08-2.092-1.08-3.668 0-1.549.35-2.773 1.08-3.64.755-.869 1.728-1.304 3.051-1.304 1.323 0 2.32.435 3.051 1.303.73.871 1.108 2.065 1.108 3.64 0 1.577-.381 2.801-1.108 3.67-.755.867-1.728 1.303-3.051 1.303-1.323 0-2.32-.436-3.051-1.304Z"
clip-rule="evenodd"
/>
<path
fill="#fff"
d="M117.694 23.23h-4.484V.85h4.484v22.38ZM122.825 6.797h-3.081v3.288h3.051v8.011c0 1.66.433 2.935 1.271 3.831.865.896 2.08 1.331 3.673 1.331h3.972V19.97h-1.783c-1.026 0-1.756-.242-2.161-.705-.405-.488-.62-1.329-.62-2.552v-6.628h4.564V6.797h-4.564V.849h-4.322v5.948Z"
/>
<path
fill="#D40101"
d="m149.644 2.831 9.667 9.1c.918.896.918 2.365 0 3.233l-9.64 9.1c-.865.788-2.188.788-3.026 0l-6.104-5.732c1.623-.57 2.863-1.93 3.323-3.613h3.646v1.766c0 .408.323.76.756.76h2.078a.756.756 0 0 0 .755-.76V14.92h.945a.756.756 0 0 0 .755-.76v-1.25a.755.755 0 0 0-.755-.76h-8.21a5.382 5.382 0 0 0-3.293-3.586l6.076-5.732c.866-.788 2.189-.788 3.027 0Z"
/>
<path
fill="#D40101"
d="M137.627 11.308a2.642 2.642 0 0 1 1.133-.272v-.003c1.378 0 2.511 1.14 2.459 2.5 0 1.386-1.108 2.5-2.486 2.5-.433 0-.838-.108-1.188-.299a2.46 2.46 0 0 1-1.295-2.199c0-.978.567-1.819 1.377-2.227Z"
/>
</svg>

After

Width:  |  Height:  |  Size: 4.0 KiB

11
public/svgs/paymenter.svg Normal file
View File

@@ -0,0 +1,11 @@
<svg width="350" height="350" viewBox="0 0 350 350" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="350" height="350" fill="#4667FF"/>
<g clip-path="url(#clip0_1_14)">
<path fill-rule="evenodd" clip-rule="evenodd" d="M100 179V277H142.857V211.638H200C233.333 211.638 250 195 250 161.725V141.5L175 179V141.5L248.227 104.886C243.133 82.9621 227.057 72 200 72H100V179ZM100 179V141.5L175 104V141.5L100 179Z" fill="white"/>
</g>
<defs>
<clipPath id="clip0_1_14">
<rect width="150" height="205" fill="white" transform="translate(100 72)"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 573 B

BIN
public/svgs/pgbackweb.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

14
public/svgs/ryot.svg Normal file
View File

@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="640" height="640">
<path d="M0 0 C211.2 0 422.4 0 640 0 C640 211.2 640 422.4 640 640 C428.8 640 217.6 640 0 640 C0 428.8 0 217.6 0 0 Z " fill="#FC7D13" transform="translate(0,0)"/>
<path d="M0 0 C1.03688965 -0.00392761 1.03688965 -0.00392761 2.09472656 -0.00793457 C22.33338497 -0.01604672 42.79757853 2.35594457 62.1875 8.3125 C63.03989258 8.56451172 63.89228516 8.81652344 64.77050781 9.07617188 C99.49295259 19.44858898 130.17434478 37.10232321 156.1875 62.3125 C156.7453418 62.84456055 157.30318359 63.37662109 157.87792969 63.92480469 C166.47481193 72.14234298 174.22411743 80.66687028 181.1875 90.3125 C181.65865234 90.96105957 182.12980469 91.60961914 182.61523438 92.27783203 C201.37037473 118.41358336 213.97847522 147.78258736 220.1875 179.3125 C220.34976074 180.07191895 220.51202148 180.83133789 220.67919922 181.61376953 C231.985234 235.74039013 217.91078514 296.07748295 188.0625 341.9375 C186.7930753 343.74499361 185.50107703 345.5368346 184.1875 347.3125 C183.43210937 348.33859375 182.67671875 349.3646875 181.8984375 350.421875 C169.95951908 366.3812374 156.8838222 380.95536829 141.1875 393.3125 C140.23617188 394.09238281 139.28484375 394.87226563 138.3046875 395.67578125 C100.23040758 426.20336886 52.48408208 441.45243347 4.0847168 441.55273438 C1.28728705 441.56237155 -1.50938447 441.59344551 -4.30664062 441.625 C-20.62200975 441.72163852 -36.47529702 439.90974635 -52.25 435.625 C-53.1982666 435.37153809 -54.1465332 435.11807617 -55.12353516 434.85693359 C-82.50954158 427.28227411 -108.32325382 414.70370163 -130.8125 397.3125 C-132.01519531 396.39791016 -132.01519531 396.39791016 -133.2421875 395.46484375 C-167.98155963 368.43916607 -192.8353486 331.85169735 -207.10302734 290.37255859 C-207.70511108 288.62431958 -208.32876119 286.88353131 -208.95703125 285.14453125 C-211.49853087 277.64153836 -212.98258132 269.9521868 -214.5 262.1875 C-214.71479004 261.09042725 -214.92958008 259.99335449 -215.15087891 258.86303711 C-217.56302818 246.04548132 -218.05287079 233.44721439 -218.0625 220.4375 C-218.06317474 219.61547089 -218.06384949 218.79344177 -218.06454468 217.94650269 C-218.04789697 205.1537533 -217.37590621 192.87524524 -214.8125 180.3125 C-214.57901855 179.04720459 -214.57901855 179.04720459 -214.34082031 177.75634766 C-208.71888273 147.38554113 -196.00170959 118.26502132 -177.8125 93.3125 C-177.40821777 92.7541748 -177.00393555 92.19584961 -176.58740234 91.62060547 C-170.54606892 83.34759439 -163.9065219 75.70049196 -156.8125 68.3125 C-156.27608887 67.74885742 -155.73967773 67.18521484 -155.18701172 66.60449219 C-146.97028541 58.01050354 -138.40165737 50.34139136 -128.8125 43.3125 C-127.78898437 42.55582031 -126.76546875 41.79914063 -125.7109375 41.01953125 C-97.67311898 20.96716737 -66.64965726 8.72168526 -32.875 2.625 C-31.88294556 2.44578003 -31.88294556 2.44578003 -30.87084961 2.26293945 C-20.61214566 0.49886647 -10.40090312 0.03799132 0 0 Z " fill="#030100" transform="translate(317.8125,99.6875)"/>
<path d="M0 0 C15.27029883 11.44834617 25.58710153 26.94282662 29.328125 45.80419922 C29.72292634 50.14802627 29.74917269 54.44501755 29.703125 58.80419922 C29.71472656 59.90248047 29.72632813 61.00076172 29.73828125 62.13232422 C29.6682177 81.84353558 20.86815887 98.27756216 7.703125 112.48779297 C-7.05608065 126.88287348 -26.39154976 132.52915809 -46.54150391 132.41088867 C-66.54644015 131.74908778 -83.46859284 123.29666824 -97.140625 108.80029297 C-112.1471066 91.03799144 -117.4391362 70.8128736 -115.671875 47.80419922 C-113.39577425 33.16295797 -106.30842532 20.84726773 -96.671875 9.80419922 C-96.15238281 9.18931641 -95.63289063 8.57443359 -95.09765625 7.94091797 C-70.91961192 -18.55139761 -28.34404353 -20.27294469 0 0 Z " fill="#FB7D13" transform="translate(455.671875,177.19580078125)"/>
<path d="M0 0 C1.00546875 0.3403125 2.0109375 0.680625 3.046875 1.03125 C10.4934761 3.82845041 16.13337291 7.67372014 22 13 C23.175625 14.03640625 23.175625 14.03640625 24.375 15.09375 C35.12600519 25.11833592 41.54714712 37.97274067 42.4140625 52.6328125 C43.07652674 71.67375503 39.31608999 86.57456433 26.625 101.25 C15.24459884 113.36889641 -0.51416891 121.51799519 -17.34057617 122.07788086 C-19.87367813 122.09792396 -22.40445513 122.08754151 -24.9375 122.0625 C-25.81212891 122.05798828 -26.68675781 122.05347656 -27.58789062 122.04882812 C-29.72529047 122.03714834 -31.86265463 122.01921689 -34 122 C-32.95937232 125.72945735 -31.9173792 129.45853183 -30.875 133.1875 C-30.55950195 134.31704102 -30.24400391 135.44658203 -29.91894531 136.61035156 C-28.14435853 142.95222991 -26.34504914 149.28595103 -24.51342773 155.61157227 C-22.33652666 163.13500364 -20.32661849 170.6360574 -18.64453125 178.2890625 C-17.87207681 181.53805268 -16.8431778 184.64322847 -15.7421875 187.79296875 C-14.64674614 191.05046544 -13.77893043 194.35964352 -12.89453125 197.6796875 C-12.17889901 200.33596438 -11.44540288 202.98506237 -10.69921875 205.6328125 C-10.47089355 206.44500244 -10.24256836 207.25719238 -10.00732422 208.09399414 C-9.54854395 209.72390536 -9.08796713 211.3533121 -8.62548828 212.98217773 C-7 218.77726143 -7 218.77726143 -7 221 C-12.57015547 218.55116172 -16.62048119 214.12044868 -21 210 C-21.89460938 209.15953125 -22.78921875 208.3190625 -23.7109375 207.453125 C-30.36672438 201.00711937 -36.13563894 194.15732124 -41.68115234 186.75 C-42.91821362 185.10852366 -44.18661127 183.49079647 -45.45703125 181.875 C-57.92579904 165.67113907 -66.83046477 146.41411478 -73 127 C-73.26893066 126.18144531 -73.53786133 125.36289062 -73.81494141 124.51953125 C-80.15475515 105.02618986 -82.24029902 85.84502434 -82.4375 65.4375 C-82.44980652 64.72292633 -82.46211304 64.00835266 -82.47479248 63.27212524 C-82.74554094 44.4967195 -77.41865801 29.06361511 -64.30859375 15.24609375 C-46.9186779 -1.67302912 -23.1417248 -8.01556948 0 0 Z " fill="#FA7C13" transform="translate(205,254)"/>
<path d="M0 0 C-0.79574163 6.95831845 -1.91247068 13.85580835 -3.04110718 20.76708984 C-3.3802214 22.84448603 -3.71737925 24.92219113 -4.05395508 27 C-4.49957152 29.75088354 -4.94558248 32.50170233 -5.39208984 35.25244141 C-7.86885879 50.4444339 -7.86885879 50.4444339 -10 65.6875 C-10.75160501 71.51870218 -11.76840033 77.25372077 -12.89453125 83.02026367 C-13.75587834 87.49937732 -14.42929128 91.97237751 -15 96.5 C-15.62483841 101.44236939 -16.40904875 106.30061759 -17.375 111.1875 C-18.84916132 118.64896612 -19.89758645 126.15467663 -20.9375 133.6875 C-22.05626904 141.75566818 -23.25418318 149.76712192 -24.875 157.75 C-28.30690114 174.6962237 -30.50356 191.89638423 -33 209 C-33.66 209 -34.32 209 -35 209 C-36.71249302 206.49129252 -38.30325923 203.97115773 -39.875 201.375 C-45.06311403 192.99027397 -50.4468279 184.75097164 -55.9375 176.5625 C-64.47800581 163.81093416 -72.93862505 151.00817284 -81.375 138.1875 C-90.61549748 124.14692172 -99.89199637 110.13184296 -109.23193359 96.15722656 C-115.61422014 86.60598178 -121.9413601 77.02222352 -128.19311523 67.38476562 C-130.66668689 63.57176958 -133.1442869 59.76438643 -135.69140625 56 C-136.27365967 55.13918823 -136.27365967 55.13918823 -136.86767578 54.26098633 C-137.83288323 52.84136925 -138.80471602 51.42626227 -139.77734375 50.01171875 C-141 48 -141 48 -141 46 C-101.97710694 10.83035491 -50.94400864 -0.70770689 0 0 Z " fill="#FB7D13" transform="translate(334,123)"/>
<path d="M0 0 C6.03074272 5.66571693 10.34565602 12.38415449 14.92919922 19.23217773 C15.96398681 20.76731102 17.01095814 22.29431214 18.07080078 23.81225586 C25.7368316 34.79719034 29.96978374 44.73602909 32.56243896 57.87332153 C33.12525632 60.60878345 33.8655869 63.27273607 34.66015625 65.94921875 C34.89428223 66.74505371 35.1284082 67.54088867 35.36962891 68.36083984 C35.59827637 69.1286377 35.82692383 69.89643555 36.0625 70.6875 C38.12109736 77.74310209 39.96884717 84.80902349 41.60400391 91.97387695 C43.06320998 98.35847175 44.74600163 104.67364825 46.46142578 110.99414062 C47.03597501 113.1339849 47.59580504 115.27727787 48.15234375 117.421875 C50.32232377 125.77537673 52.58688778 134.0882601 55 142.375 C57.34872462 150.4612911 59.40378856 158.5879483 61.30541992 166.7902832 C62.56463374 172.22061037 63.9308706 177.59613366 65.51953125 182.94140625 C66 185 66 185 66 189 C28.20074608 189.61810101 28.20074608 189.61810101 12 186 C10.62148415 185.7284791 9.24257216 185.45896209 7.86328125 185.19140625 C-3.27952764 182.91693777 -13.90038404 179.20491683 -24.43945312 174.97216797 C-26.76112381 174.0906946 -29.06338546 173.38980095 -31.453125 172.72265625 C-35.79823061 171.30427573 -39.15200833 169.66936204 -42 166 C-45.36932278 158.89584605 -46.88422964 151.11172622 -48.54211426 143.46586609 C-50.24244656 135.67360086 -52.41403238 128.02236247 -54.58676147 120.35095215 C-55.23289168 118.0606431 -55.86895109 115.76780303 -56.5012207 113.47363281 C-58.60598229 105.84902301 -60.81366027 98.27209728 -63.16943359 90.72021484 C-64.11976782 87.60774455 -64.94001584 84.47958608 -65.6875 81.3125 C-66.55361195 77.54908177 -66.55361195 77.54908177 -68 74 C-68.039992 72.00039988 -68.04346799 69.99952758 -68 68 C-66.87464844 67.6596875 -65.74929687 67.319375 -64.58984375 66.96875 C-42.20502375 59.99449869 -22.5059221 48.92951551 -10.74853516 27.74511719 C-6.11450685 18.8864207 -1.92925734 9.86804043 0 0 Z " fill="#FB7D13" transform="translate(269,329)"/>
<path d="M0 0 C29.35181046 -0.12713185 58.66083435 0.1075539 88 1 C88.69169636 33.91952004 89.09863354 66.82330922 89.0625 99.75 C89.06164398 100.53568611 89.06078796 101.32137222 89.05990601 102.130867 C89.04863194 111.75393617 89.02873228 121.37696653 89 131 C86.46911389 132.11151229 83.93780486 133.22204395 81.40625 134.33203125 C80.69758789 134.64338013 79.98892578 134.954729 79.25878906 135.2755127 C70.18286709 139.25274862 61.17297831 142.84926387 51.5625 145.3125 C50.89992188 145.48418701 50.23734375 145.65587402 49.5546875 145.83276367 C45.62696522 146.78730774 42.03632522 147.16844016 38 147 C34.29818858 133.47146916 30.69071511 119.92580384 27.3125 106.3125 C24.44329532 94.75697686 21.4692883 83.24775985 18.26171875 71.78125 C14.21604855 57.28150373 10.36287678 42.75995891 6.79003906 28.13696289 C4.94811941 20.63737344 2.95493059 13.22436072 0.74316406 5.82592773 C0 3 0 3 0 0 Z " fill="#FB7D13" transform="translate(320,367)"/>
<path d="M0 0 C0.66 0 1.32 0 2 0 C8.65994457 21.03594142 12.18870077 40.73268439 12.13037109 62.82617188 C12.12497966 65.25917705 12.13036244 67.69200018 12.13671875 70.125 C12.13605838 71.69270873 12.13477808 73.26041736 12.1328125 74.828125 C12.13483673 75.54494446 12.13686096 76.26176392 12.13894653 77.00030518 C12.11849366 81.44308812 11.71883375 85.62989057 11 90 C-25.26563424 90.14737519 -61.52473184 89.94396923 -97.78866959 89.59428024 C-101.08683718 89.56286352 -104.38501428 89.53274087 -107.68319702 89.50296021 C-133.13302486 89.27100392 -158.56411218 88.89869697 -184 88 C-183.16167467 80.14266587 -182.09383667 72.32741699 -180.953125 64.50878906 C-180.62784193 62.26956365 -180.30998131 60.02936128 -179.9921875 57.7890625 C-178.73333736 49.06883495 -177.15555412 40.55129782 -175 32 C-171.65432411 35.246415 -168.67621488 38.57498879 -165.8125 42.25 C-155.49929651 54.90788566 -142.34894561 64.31096294 -127 70 C-126.38576172 70.22848633 -125.77152344 70.45697266 -125.13867188 70.69238281 C-106.1724813 77.43733702 -82.9103393 78.20056615 -64 71 C-62.91589844 70.63777344 -61.83179688 70.27554688 -60.71484375 69.90234375 C-46.53145629 64.91533624 -35.47964515 57.59890143 -25 47 C-24.18660156 46.19691406 -23.37320313 45.39382813 -22.53515625 44.56640625 C-11.27368987 32.84293099 -2.75744731 15.99319441 0 0 Z " fill="#F77B13" transform="translate(506,256)"/>
<path d="M0 0 C26.73 0 53.46 0 81 0 C71.69069895 41.89185472 45.99154826 80.65798246 12.4375 107.25 C11.86604248 107.70391113 11.29458496 108.15782227 10.70581055 108.62548828 C7.5852431 111.02222469 4.6657248 112.62162236 1 114 C0.16847212 75.98299967 -0.09320509 38.02767622 0 0 Z " fill="#FB7D13" transform="translate(431,369)"/>
<path d="M0 0 C1.70172965 2.27894132 3.27847517 4.55967573 4.83203125 6.9375 C5.30565598 7.65099609 5.7792807 8.36449219 6.26725769 9.09960938 C7.78884536 11.39550988 9.30061214 13.69770342 10.8125 16 C11.82035325 17.52253958 12.82880967 19.04468007 13.83789062 20.56640625 C16.573879 24.70113041 19.30557118 28.83803725 22 33 C22.47432465 33.72832031 22.94864929 34.45664063 23.43734741 35.20703125 C23.89590118 35.92246094 24.35445496 36.63789063 24.8269043 37.375 C25.24376999 38.02210938 25.66063568 38.66921875 26.09013367 39.3359375 C27 41 27 41 27 43 C25.73285156 42.84144531 24.46570313 42.68289062 23.16015625 42.51953125 C3.82505163 40.39300968 -13.51581646 42.03375203 -31 51 C-31.99193359 51.48726562 -31.99193359 51.48726562 -33.00390625 51.984375 C-34.3426096 52.64285553 -35.67286759 53.31849957 -37 54 C-35.49592434 48.94947225 -33.34789706 44.49980811 -30.875 39.875 C-30.47394043 39.12436279 -30.07288086 38.37372559 -29.65966797 37.6003418 C-9.28193062 0 -9.28193062 0 0 0 Z " fill="#F77B13" transform="translate(177,187)"/>
<path d="M0 0 C16.00592115 1.60958297 31.1718402 6.87995869 46 13 C46 13.66 46 14.32 46 15 C44.42025391 15.22042969 44.42025391 15.22042969 42.80859375 15.4453125 C28.46103344 17.61076079 16.17601594 21.92407106 4 30 C3.13890625 30.56460938 2.2778125 31.12921875 1.390625 31.7109375 C-0.74952893 33.12662938 -2.87926717 34.55544285 -5 36 C-4.09833576 28.48296763 -3.01507902 20.99355302 -1.9375 13.5 C-1.75123047 12.200625 -1.56496094 10.90125 -1.37304688 9.5625 C-0.91600242 6.37490792 -0.45830187 3.1874115 0 0 Z " fill="#F57A13" transform="translate(356,127)"/>
</svg>

After

Width:  |  Height:  |  Size: 13 KiB

BIN
public/svgs/typesense.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

BIN
public/svgs/vert.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

BIN
public/svgs/vert.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

28
public/svgs/yamtrack.svg Normal file
View 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

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1,70 +1,95 @@
@import 'fonts';
@import "./fonts.css" layer(base);
@tailwind base;
@tailwind components;
@tailwind utilities;
@import "tailwindcss";
@import "./utilities.css";
@plugin 'tailwind-scrollbar';
@plugin '@tailwindcss/typography';
@plugin '@tailwindcss/forms';
@source '../../storage/framework/views/*.php';
@custom-variant dark (&:where(.dark, .dark *));
@theme {
--font-sans: Inter, sans-serif;
--color-base: #101010;
--color-warning: #fcd452;
--color-success: #16a34a;
--color-error: #dc2626;
--color-coollabs: #6b16ed;
--color-coollabs-100: #7317ff;
--color-coolgray-100: #181818;
--color-coolgray-200: #202020;
--color-coolgray-300: #242424;
--color-coolgray-400: #282828;
--color-coolgray-500: #323232;
}
/*
The default border color has changed to `currentcolor` in Tailwind CSS v4,
so we've added these compatibility styles to make sure everything still
looks the same as it did with Tailwind CSS v3.
If we ever want to remove these styles, we need to add an explicit border
color utility to any element that depends on these defaults.
*/
@layer base {
*,
::after,
::before,
::backdrop,
::file-selector-button {
border-color: var(--color-coolgray-200, currentcolor);
}
}
@keyframes lds-heart {
0% {
transform: scale(1);
}
5% {
transform: scale(1.2);
}
39% {
transform: scale(0.85);
}
45% {
transform: scale(1);
}
60% {
transform: scale(0.95);
}
100% {
transform: scale(0.9);
}
}
/*
* Base styles
*/
html,
body {
@apply min-h-full bg-neutral-50 dark:bg-base dark:text-neutral-400 w-full;
@apply w-full min-h-full bg-neutral-50 dark:bg-base dark:text-neutral-400;
}
body {
@apply text-sm antialiased scrollbar min-h-screen;
}
.apexcharts-tooltip {
@apply dark:text-white dark:border-coolgray-300 dark:bg-coolgray-200 shadow-none !important;
}
.apexcharts-tooltip-title {
@apply hidden !important;
}
.apexcharts-xaxistooltip {
@apply hidden !important;
}
.input-sticky {
@apply text-black 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 block w-full py-1.5 rounded border-0 text-sm ring-1 ring-inset;
}
.input-sticky-active {
@apply border-2 border-coollabs text-black dark:text-white focus:bg-neutral-200 dark:focus:bg-coolgray-400 focus:border-coollabs;
}
/* Readonly */
.input {
@apply dark:read-only:text-neutral-500 dark:read-only:ring-0 dark:read-only:bg-coolgray-100/40 placeholder:text-neutral-300 dark:placeholder:text-neutral-700 read-only:text-neutral-500 read-only:bg-neutral-200;
}
/* Focus */
.input,
.select {
@apply focus:ring-2 dark:focus:ring-coolgray-300 focus:ring-neutral-400;
}
.input,
.select {
@apply text-black dark:bg-coolgray-100 dark:text-white ring-neutral-200 dark:ring-coolgray-300 block w-full py-1.5 rounded border-0 text-sm ring-1 ring-inset disabled:dark:bg-coolgray-100/40 disabled:dark:ring-transparent disabled:bg-neutral-200 disabled:text-neutral-500;
}
.select {
@apply w-full;
}
.input[type="password"] {
@apply pr-10;
@apply min-h-screen text-sm antialiased scrollbar;
}
option {
@apply dark:text-white dark:bg-coolgray-100;
}
.button {
@apply flex items-center justify-center gap-2 px-2 py-1 text-sm text-black normal-case border rounded cursor-pointer bg-neutral-200/50 border-neutral-300 hover:bg-neutral-300 dark:bg-coolgray-200 dark:text-white dark:hover:text-white dark:hover:bg-coolgray-500 dark:border-coolgray-300 hover:text-black disabled:cursor-not-allowed min-w-fit focus:outline-1 dark:disabled:text-neutral-600 disabled:border-none disabled:hover:bg-transparent disabled:bg-transparent disabled:text-neutral-300;
}
button[isError]:not(:disabled) {
@apply text-white bg-red-600 hover:bg-red-700;
}
@@ -97,7 +122,6 @@ label {
@apply dark:text-neutral-400;
}
table {
@apply min-w-full divide-y dark:divide-coolgray-200 divide-neutral-300;
}
@@ -119,7 +143,7 @@ tr th {
}
tr th:first-child {
@apply py-3.5 pl-4 pr-3 sm:pl-6;
@apply py-3.5 pr-3 pl-4 sm:pl-6;
}
tr td {
@@ -127,203 +151,20 @@ tr td {
}
tr td:first-child {
@apply pl-4 pr-3 font-bold sm:pl-6;
@apply pr-3 pl-4 font-bold sm:pl-6;
}
section {
@apply mb-12;
}
.alert-success {
@apply flex items-center gap-2 text-success;
}
.alert-error {
@apply flex items-center gap-2 text-error;
}
.tag {
@apply px-2 py-1 cursor-pointer box-description dark:bg-coolgray-100 dark:hover:bg-coolgray-300 bg-neutral-100 hover:bg-neutral-200;
}
.add-tag {
@apply flex items-center px-2 text-xs cursor-pointer dark:text-neutral-500/20 text-neutral-500 group-hover:text-neutral-700 group-hover:dark:text-white dark:hover:bg-coolgray-300 hover:bg-neutral-200;
}
.dropdown-item {
@apply relative flex cursor-pointer select-none dark:text-white hover:bg-neutral-100 dark:hover:bg-coollabs items-center pr-4 pl-2 py-1 text-xs justify-start outline-none transition-colors data-[disabled]:pointer-events-none data-[disabled]:opacity-50 gap-2 w-full;
}
.dropdown-item-no-padding {
@apply relative flex cursor-pointer select-none dark:text-white hover:bg-neutral-100 dark:hover:bg-coollabs items-center py-1 text-xs justify-start outline-none transition-colors data-[disabled]:pointer-events-none data-[disabled]:opacity-50 gap-2 w-full;
}
.badge {
@apply inline-block w-3 h-3 text-xs font-bold leading-none border rounded-full border-neutral-200 dark:border-black;
}
.badge-absolute {
@apply absolute top-0 right-0 w-2 h-2 border-none rounded-t-none rounded-r-none;
}
.badge-success {
@apply bg-success;
}
.badge-warning {
@apply bg-warning;
}
.badge-error {
@apply bg-error;
}
.menu {
@apply flex items-center gap-1;
}
.menu-item {
@apply flex items-center w-full gap-3 px-2 py-1 text-sm sm:pr-0 dark:hover:bg-coolgray-100 dark:hover:text-white hover:bg-neutral-300 min-w-fit sm:min-w-64;
}
.menu-item-active {
@apply text-black rounded-none dark:bg-coolgray-200 dark:text-warning bg-neutral-200;
}
.heading-item-active {
@apply text-black rounded-none dark:bg-coolgray-200 dark:text-warning;
}
.icon {
@apply w-6 h-6 dark:hover:text-white;
}
.scrollbar {
@apply scrollbar-thumb-coollabs-100 dark:scrollbar-track-coolgray-200 scrollbar-track-neutral-200 scrollbar-thin;
}
.main {
@apply pt-4 pl-24 pr-10 lg:pr-32 lg:pl-44;
}
.custom-modal {
@apply z-50 flex flex-col gap-2 px-8 py-4 border dark:bg-coolgray-100 dark:border-coolgray-200;
}
.navbar-main {
@apply flex flex-col gap-4 pb-2 border-b-2 border-solid h-fit md:flex-row justify-items-start sm:justify-between dark:border-coolgray-200 md:items-center;
}
.loading {
@apply w-4 dark:text-warning text-coollabs;
}
.kbd-custom {
@apply px-2 text-xs border border-dashed rounded border-neutral-700 dark:text-warning;
}
.box {
@apply relative flex lg:flex-row flex-col p-2 transition-colors cursor-pointer min-h-[4rem] dark:bg-coolgray-100 shadow bg-white border text-black dark:text-white hover:text-black border-neutral-200 dark:border-black hover:bg-neutral-100 dark:hover:bg-coollabs-100 dark:hover:text-white hover:no-underline;
}
.box-boarding {
@apply flex lg:flex-row flex-col p-2 transition-colors cursor-pointer min-h-[4rem] dark:bg-coolgray-100 dark:text-white bg-neutral-50 border border-neutral-200 dark:border-black hover:bg-neutral-100 dark:hover:bg-coollabs-100 dark:hover:text-white hover:text-black hover:no-underline text-black;
}
.box-without-bg {
@apply flex p-2 transition-colors dark:hover:text-white hover:no-underline min-h-[4rem] border border-neutral-200 dark:border-black;
}
.box-without-bg-without-border {
@apply flex p-2 transition-colors dark:hover:text-white hover:no-underline min-h-[4rem];
}
.on-box {
@apply rounded hover:bg-neutral-300 dark:hover:bg-coolgray-500/20;
}
.box-title {
@apply font-bold text-black dark:text-white group-hover:dark:text-white;
}
.box-description {
@apply text-xs font-bold text-neutral-500 group-hover:dark:text-white group-hover:text-black;
}
.description {
@apply text-xs font-bold text-neutral-500 group-hover:dark:text-white group-hover:text-black;
/*
* Utility classes
*/
.input[type="password"] {
@apply pr-[2.4rem];
}
.lds-heart {
animation: lds-heart 1.2s infinite cubic-bezier(0.215, 0.61, 0.355, 1);
}
@keyframes lds-heart {
0% {
transform: scale(1);
}
5% {
transform: scale(1.2);
}
39% {
transform: scale(0.85);
}
45% {
transform: scale(1);
}
60% {
transform: scale(0.95);
}
100% {
transform: scale(0.9);
}
}
.bg-coollabs-gradient {
@apply text-transparent text-white bg-gradient-to-r from-purple-500 via-pink-500 to-red-500;
}
.text-helper {
@apply inline-block font-bold text-coollabs dark:text-warning;
}
.info-helper {
@apply cursor-pointer text-coollabs dark:text-warning;
}
.info-helper-popup {
@apply absolute z-40 hidden text-xs rounded text-neutral-700 group-hover:block dark:border-coolgray-500 border-neutral-900 dark:bg-coolgray-400 bg-neutral-200 dark:text-neutral-300;
}
.buyme {
@apply block px-3 py-2 mt-10 text-sm font-semibold leading-6 text-center text-white rounded-md shadow-sm hover:text-white bg-coolgray-200 hover:bg-coolgray-300 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-coolgray-200 hover:no-underline;
}
.title {
@apply hidden pb-0 lg:block lg:pb-8;
}
.subtitle {
@apply pt-2 pb-9;
}
.fullscreen {
@apply fixed top-0 left-0 w-full h-full z-[9999] dark:bg-coolgray-100 bg-white overflow-y-auto scrollbar;
}
.toast {
z-index: 1;
}
.dz-button {
@apply w-full p-4 py-10 my-4 font-bold bg-white border dark:border-coolgray-400 dark:text-white dark:bg-transparent hover:dark:bg-coolgray-400;
}
.xterm {
@apply p-2;
}

210
resources/css/utilities.css Normal file
View File

@@ -0,0 +1,210 @@
@utility apexcharts-tooltip {
@apply dark:text-white! dark:border-coolgray-300! dark:bg-coolgray-200! shadow-none!;
}
@utility apexcharts-tooltip-title {
@apply hidden!;
}
@utility apexcharts-xaxistooltip {
@apply hidden!;
}
@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 focus:ring-neutral-400 dark:focus:ring-coolgray-300;
}
@utility input-sticky-active {
@apply text-black border-2 border-coollabs dark:text-white focus:bg-neutral-200 dark:focus:bg-coolgray-400 focus:border-coollabs;
}
/* Focus */
@utility input-focus {
@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 disabled:bg-neutral-200 disabled:text-neutral-500 dark:disabled:bg-coolgray-100/40 dark:disabled:ring-transparent;
}
/* Readonly */
@utility input {
@apply dark:read-only:text-neutral-500 dark:read-only:ring-0 dark:read-only:bg-coolgray-100/40 placeholder:text-neutral-300 dark:placeholder:text-neutral-700 read-only:text-neutral-500 read-only:bg-neutral-200;
@apply input-focus;
@apply input-select;
}
@utility select {
@apply w-full;
@apply input-focus;
@apply input-select;
}
@utility button {
@apply flex gap-2 justify-center items-center px-2 py-1 text-sm text-black normal-case rounded-sm border outline-0 cursor-pointer bg-neutral-200/50 border-neutral-300 hover:bg-neutral-300 dark:bg-coolgray-200 dark:text-white dark:hover:text-white dark:hover:bg-coolgray-500 dark:border-coolgray-300 hover:text-black disabled:cursor-not-allowed min-w-fit dark:disabled:text-neutral-600 disabled:border-none disabled:hover:bg-transparent disabled:bg-transparent disabled:text-neutral-300;
}
@utility alert-success {
@apply flex gap-2 items-center text-success;
}
@utility alert-error {
@apply flex gap-2 items-center text-error;
}
@utility tag {
@apply px-2 py-1 cursor-pointer box-description dark:bg-coolgray-100 dark:hover:bg-coolgray-300 bg-neutral-100 hover:bg-neutral-200;
}
@utility add-tag {
@apply flex items-center px-2 text-xs cursor-pointer dark:text-neutral-500/20 text-neutral-500 group-hover:text-neutral-700 dark:group-hover:text-white dark:hover:bg-coolgray-300 hover:bg-neutral-200;
}
@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-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-none data-disabled:pointer-events-none data-disabled:opacity-50;
}
@utility badge {
@apply inline-block w-3 h-3 text-xs font-bold rounded-full leading-none border border-neutral-200 dark:border-black;
}
@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 {
@apply bg-success;
}
@utility badge-warning {
@apply bg-warning;
}
@utility badge-error {
@apply bg-error;
}
@utility menu {
@apply flex gap-1 items-center;
}
@utility menu-item {
@apply flex gap-3 items-center px-2 py-1 w-full text-sm sm:pr-0 dark:hover:bg-coolgray-100 dark:hover:text-white hover:bg-neutral-300 min-w-fit sm:min-w-64;
}
@utility menu-item-active {
@apply text-black rounded-none dark:bg-coolgray-200 dark:text-warning bg-neutral-200;
}
@utility heading-item-active {
@apply text-black rounded-none dark:bg-coolgray-200 dark:text-warning;
}
@utility icon {
@apply w-6 h-6 dark:hover:text-white;
}
@utility scrollbar {
@apply scrollbar-thumb-coollabs-100 scrollbar-track-neutral-200 dark:scrollbar-track-coolgray-200 scrollbar-thin;
}
@utility main {
@apply pt-4 pr-10 pl-24 lg:pr-32 lg:pl-44;
}
@utility custom-modal {
@apply flex z-50 flex-col gap-2 px-8 py-4 border dark:bg-coolgray-100 dark:border-coolgray-200;
}
@utility navbar-main {
@apply flex flex-col gap-4 justify-items-start pb-2 border-b-2 border-solid h-fit md:flex-row sm:justify-between dark:border-coolgray-200 md:items-center;
}
@utility loading {
@apply w-4 dark:text-warning text-coollabs;
}
@utility kbd-custom {
@apply px-2 text-xs rounded-sm border border-dashed border-neutral-700 dark:text-warning;
}
@utility box {
@apply relative flex lg:flex-row flex-col p-2 transition-colors cursor-pointer min-h-[4rem] dark:bg-coolgray-100 shadow-sm bg-white border text-black dark:text-white hover:text-black border-neutral-200 dark:border-black hover:bg-neutral-100 dark:hover:bg-coollabs-100 dark:hover:text-white hover:no-underline;
}
@utility box-boarding {
@apply flex lg:flex-row flex-col p-2 transition-colors cursor-pointer min-h-[4rem] dark:bg-coolgray-100 dark:text-white bg-neutral-50 border border-neutral-200 dark:border-black hover:bg-neutral-100 dark:hover:bg-coollabs-100 dark:hover:text-white hover:text-black hover:no-underline text-black;
}
@utility box-without-bg {
@apply flex p-2 transition-colors dark:hover:text-white hover:no-underline min-h-[4rem] border border-neutral-200 dark:border-black;
}
@utility box-without-bg-without-border {
@apply flex p-2 transition-colors dark:hover:text-white hover:no-underline min-h-[4rem];
}
@utility on-box {
@apply rounded-sm hover:bg-neutral-300 dark:hover:bg-coolgray-500/20;
}
@utility box-title {
@apply font-bold text-black dark:text-white dark:group-hover:text-white;
}
@utility box-description {
@apply text-xs font-bold text-neutral-500 dark:group-hover:text-white group-hover:text-black;
}
@utility description {
@apply text-xs font-bold text-neutral-500 dark:group-hover:text-white group-hover:text-black;
}
@utility bg-coollabs-gradient {
@apply from-purple-500 via-pink-500 to-red-500 bg-linear-to-r;
}
@utility text-helper {
@apply inline-block font-bold text-coollabs dark:text-warning;
}
@utility info-helper {
@apply cursor-pointer text-coollabs dark:text-warning;
}
@utility info-helper-popup {
@apply hidden absolute z-40 text-xs rounded-sm text-neutral-700 group-hover:block dark:border-coolgray-500 border-neutral-900 dark:bg-coolgray-400 bg-neutral-200 dark:text-neutral-300;
}
@utility buyme {
@apply block px-3 py-2 mt-10 text-sm font-semibold leading-6 text-center text-white rounded-md shadow-xs hover:text-white bg-coolgray-200 hover:bg-coolgray-300 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-coolgray-200 hover:no-underline;
}
@utility title {
@apply hidden pb-0 lg:block lg:pb-8;
}
@utility subtitle {
@apply pt-2 pb-9;
}
@utility fullscreen {
@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];
}
@utility dz-button {
@apply p-4 py-10 my-4 w-full font-bold bg-white border dark:border-coolgray-400 dark:text-white dark:bg-transparent dark:hover:bg-coolgray-400;
}
@utility xterm {
@apply p-2;
}

View File

@@ -166,7 +166,7 @@ export function initializeTerminalComponent() {
}
this.terminalActive = true;
this.term.focus();
document.querySelector('.xterm-viewport').classList.add('scrollbar', 'rounded');
document.querySelector('.xterm-viewport').classList.add('scrollbar', 'rounded-sm');
this.resizeTerminal();
} else if (event.data === 'unprocessable') {
if (this.term) this.term.reset();

View File

@@ -7,7 +7,7 @@
{{ __('auth.forgot_password') }}
</div>
<div
class="w-full bg-white shadow md:mt-0 sm:max-w-md xl:p-0 dark:bg-base ">
class="w-full bg-white shadow-sm 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">
@if (is_transactional_emails_enabled())
<form action="/forgot-password" method="POST" class="flex flex-col gap-2">

View File

@@ -4,7 +4,7 @@
<a class="flex items-center mb-6 text-5xl font-extrabold tracking-tight text-gray-900 dark:text-white">
Coolify
</a>
<div class="w-full bg-white shadow md:mt-0 sm:max-w-md xl:p-0 dark:bg-base ">
<div class="w-full bg-white shadow-sm md:mt-0 sm:max-w-md xl:p-0 dark:bg-base ">
@if ($errors->any())
<div class="text-center text-error">
@foreach ($errors->all() as $error)

View File

@@ -14,7 +14,7 @@ $email = getOldOrLocal('email', 'test3@example.com');
<a class="flex items-center mb-6 text-5xl font-extrabold tracking-tight text-gray-900 dark:text-white">
Coolify
</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="w-full bg-white rounded-lg shadow-sm 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">
<div>
<h1

View File

@@ -7,7 +7,7 @@
<div class="flex items-center justify-center pb-6 text-center">
{{ __('auth.reset_password') }}
</div>
<div class="w-full bg-white shadow md:mt-0 sm:max-w-md xl:p-0 dark:bg-base ">
<div class="w-full bg-white shadow-sm 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">
<form action="/reset-password" method="POST" class="flex flex-col gap-2">
@csrf

View File

@@ -4,14 +4,14 @@
<a class="flex items-center mb-6 text-5xl font-extrabold tracking-tight text-gray-900 dark:text-white">
Coolify
</a>
<div class="w-full bg-white shadow md:mt-0 sm:max-w-md xl:p-0 dark:bg-base ">
<div class="w-full bg-white shadow-sm 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">
<form action="/two-factor-challenge" method="POST" class="flex flex-col gap-2">
@csrf
<div>
<x-forms.input type="number" name="code" autocomplete="one-time-code" label="{{ __('input.code') }}" />
<div x-show="!showRecovery"
class="pt-2 text-xs cursor-pointer hover:underline hover:dark:text-white"
class="pt-2 text-xs cursor-pointer hover:underline dark:hover:text-white"
x-on:click="showRecovery = !showRecovery">Enter
Recovery Code
</div>

View File

@@ -6,12 +6,12 @@
x-transition:enter-start="-translate-y-10" x-transition:enter-end="translate-y-0"
x-transition:leave="transition ease-in duration-100" x-transition:leave-start="translate-y-0"
x-transition:leave-end="-translate-y-10" x-init="setTimeout(() => { bannerVisible = true }, bannerVisibleAfter);"
class="relative z-[999] w-full py-2 mx-auto duration-100 ease-out shadow-sm bg-coolgray-100 sm:py-0 sm:h-14" x-cloak>
class="relative z-999 w-full py-2 mx-auto duration-100 ease-out shadow-xs bg-coolgray-100 sm:py-0 sm:h-14" x-cloak>
<div class="flex items-center justify-between h-full px-3">
{{ $slot }}
@if ($closable)
<button @click="bannerVisible=false"
class="flex items-center flex-shrink-0 translate-x-1 ease-out duration-150 justify-center w-6 h-6 p-1.5 text-neutral-200 rounded-full hover:bg-coolgray-500">
class="flex items-center shrink-0 translate-x-1 ease-out duration-150 justify-center w-6 h-6 p-1.5 text-neutral-200 rounded-full hover:bg-coolgray-500">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5"
stroke="currentColor" class="w-full h-full">
<path stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12" />

View File

@@ -2,7 +2,7 @@
dropdownOpen: false
}" class="relative" @click.outside="dropdownOpen = false">
<button @click="dropdownOpen=true"
class="inline-flex items-center justify-start pr-8 transition-colors focus:outline-none disabled:opacity-50 disabled:pointer-events-none">
class="inline-flex items-center justify-start pr-8 transition-colors focus:outline-hidden disabled:opacity-50 disabled:pointer-events-none">
<span class="flex flex-col items-start h-full leading-none">
{{ $title }}
</span>
@@ -16,7 +16,7 @@
<div x-show="dropdownOpen" @click.away="dropdownOpen=false" x-transition:enter="ease-out duration-200"
x-transition:enter-start="-translate-y-2" x-transition:enter-end="translate-y-0"
class="absolute top-0 z-50 mt-6 min-w-max" x-cloak>
<div class="p-1 mt-1 bg-white border rounded shadow dark:bg-coolgray-200 dark:border-black border-neutral-300">
<div class="p-1 mt-1 bg-white border rounded-sm shadow-sm dark:bg-coolgray-200 dark:border-black border-neutral-300">
{{ $slot }}
</div>
</div>

View File

@@ -16,7 +16,7 @@
'dark:hover:bg-coolgray-100 cursor-pointer' => !$disabled,
])>
<label @class(['flex gap-4 items-center px-0 min-w-fit label w-full'])>
<span class="flex flex-grow gap-2">
<span class="flex grow gap-2">
@if ($label)
@if ($disabled)
<span class="opacity-60">{!! $label !!}</span>

View File

@@ -16,7 +16,7 @@
<div class="relative" x-data="{ type: 'password' }">
@if ($allowToPeak)
<div x-on:click="changePasswordFieldType"
class="flex absolute inset-y-0 right-0 items-center pr-2 cursor-pointer hover:dark:text-white">
class="flex absolute inset-y-0 right-0 items-center pr-2 cursor-pointer dark:hover:text-white">
<svg xmlns="http://www.w3.org/2000/svg" class="w-6 h-6" 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" />

View File

@@ -33,7 +33,7 @@
<div class="relative" x-data="{ type: 'password' }">
@if ($allowToPeak)
<div x-on:click="changePasswordFieldType"
class="absolute inset-y-0 right-0 flex items-center h-6 pt-2 pr-2 cursor-pointer hover:dark:text-white">
class="absolute inset-y-0 right-0 flex items-center h-6 pt-2 pr-2 cursor-pointer dark:hover:text-white">
<svg xmlns="http://www.w3.org/2000/svg" class="w-6 h-6" 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" />

View File

@@ -6,6 +6,7 @@
'buttonFullWidth' => false,
'customButton' => null,
'disabled' => false,
'dispatchAction' => false,
'submitAction' => 'delete',
'content' => null,
'checkboxes' => [],
@@ -42,6 +43,7 @@
confirmWithText: @js($confirmWithText && !$disableTwoStepConfirmation),
confirmWithPassword: @js($confirmWithPassword && !$disableTwoStepConfirmation),
submitAction: @js($submitAction),
dispatchAction: @js($dispatchAction),
passwordError: '',
selectedActions: @js(collect($checkboxes)->pluck('id')->filter(fn($id) => $this->$id)->values()->all()),
dispatchEvent: @js($dispatchEvent),
@@ -72,6 +74,10 @@
return Promise.resolve(this.passwordError);
}
}
if (this.dispatchAction) {
$wire.dispatch(this.submitAction);
return true;
}
const methodName = this.submitAction.split('(')[0];
const paramsMatch = this.submitAction.match(/\((.*?)\)/);
@@ -81,7 +87,6 @@
params.push(this.password);
}
params.push(this.selectedActions);
return $wire[methodName](...params)
.then(result => {
if (result === true) {
@@ -163,8 +168,8 @@
@endif
<template x-teleport="body">
<div x-show="modalOpen"
class="fixed top-0 lg:pt-10 left-0 z-[99] flex items-start justify-center w-screen h-screen" x-cloak>
<div x-show="modalOpen" class="absolute inset-0 w-full h-full bg-black bg-opacity-20 backdrop-blur-sm">
class="fixed top-0 lg:pt-10 left-0 z-99 flex items-start justify-center w-screen h-screen" x-cloak>
<div x-show="modalOpen" class="absolute inset-0 w-full h-full bg-black/20 backdrop-blur-xs">
</div>
<div x-show="modalOpen" x-trap.inert.noscroll="modalOpen" x-transition:enter="ease-out duration-100"
x-transition:enter-start="opacity-0 -translate-y-2 sm:scale-95"
@@ -172,7 +177,7 @@
x-transition:leave="ease-in duration-100"
x-transition:leave-start="opacity-100 translate-y-0 sm:scale-100"
x-transition:leave-end="opacity-0 -translate-y-2 sm:scale-95"
class="relative w-full py-6 border rounded min-w-full lg:min-w-[36rem] max-w-[48rem] bg-neutral-100 border-neutral-400 dark:bg-base px-7 dark:border-coolgray-300">
class="relative w-full py-6 border rounded-sm min-w-full lg:min-w-[36rem] max-w-[48rem] bg-neutral-100 border-neutral-400 dark:bg-base px-7 dark:border-coolgray-300">
<div class="flex justify-between items-center pb-3">
<h3 class="pr-8 text-2xl font-bold">{{ $title }}</h3>
<button @click="modalOpen = false; resetModal()"
@@ -222,7 +227,7 @@
<ul class="mb-4 space-y-2">
@foreach ($actions as $action)
<li class="flex items-center text-red-500">
<svg class="flex-shrink-0 mr-2 w-5 h-5" fill="none" stroke="currentColor"
<svg class="shrink-0 mr-2 w-5 h-5" fill="none" stroke="currentColor"
viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M6 18L18 6M6 6l12 12"></path>
@@ -233,7 +238,7 @@
@foreach ($checkboxes as $checkbox)
<template x-if="selectedActions.includes('{{ $checkbox['id'] }}')">
<li class="flex items-center text-red-500">
<svg class="flex-shrink-0 mr-2 w-5 h-5" fill="none" stroke="currentColor"
<svg class="shrink-0 mr-2 w-5 h-5" fill="none" stroke="currentColor"
viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M6 18L18 6M6 6l12 12"></path>
@@ -257,7 +262,7 @@
{{ $shortConfirmationLabel }}
</label>
<input type="text" x-model="userConfirmationText"
class="p-2 mt-1 w-full text-black rounded input">
class="p-2 mt-1 w-full text-black rounded-sm input">
</div>
@endif
@endif

View File

@@ -28,12 +28,12 @@
@endif
<template x-teleport="body">
<div x-show="modalOpen"
class="fixed top-0 left-0 lg:px-0 px-4 z-[99] flex items-center justify-center w-screen h-screen">
class="fixed top-0 left-0 lg:px-0 px-4 z-99 flex items-center justify-center w-screen h-screen">
<div x-show="modalOpen" x-transition:enter="ease-out duration-100" x-transition:enter-start="opacity-0"
x-transition:enter-end="opacity-100" x-transition:leave="ease-in duration-100"
x-transition:leave-start="opacity-100" x-transition:leave-end="opacity-0"
@if ($closeOutside) @click="modalOpen=false" @endif
class="absolute inset-0 w-full h-full bg-black bg-opacity-20 backdrop-blur-sm"></div>
class="absolute inset-0 w-full h-full bg-black/20 backdrop-blur-xs"></div>
<div x-show="modalOpen" x-trap.inert.noscroll="modalOpen"
x-transition:enter="ease-out duration-100"
x-transition:enter-start="opacity-0 -translate-y-2 sm:scale-95"
@@ -41,11 +41,11 @@
x-transition:leave="ease-in duration-100"
x-transition:leave-start="opacity-100 translate-y-0 sm:scale-100"
x-transition:leave-end="opacity-0 -translate-y-2 sm:scale-95"
class="relative w-full py-6 border rounded drop-shadow min-w-full lg:min-w-[{{ $minWidth }}] max-w-fit bg-white border-neutral-200 dark:bg-base px-6 dark:border-coolgray-300">
class="relative w-full py-6 border rounded-sm drop-shadow-sm min-w-full lg:min-w-[{{ $minWidth }}] max-w-fit bg-white border-neutral-200 dark:bg-base px-6 dark:border-coolgray-300">
<div class="flex items-center justify-between pb-3">
<h3 class="text-2xl font-bold">{{ $title }}</h3>
<button @click="modalOpen=false"
class="absolute top-0 right-0 flex items-center justify-center w-8 h-8 mt-5 mr-5 rounded-full dark:text-white hover:bg-neutral-100 dark:hover:bg-coolgray-300">
class="absolute top-0 right-0 flex items-center justify-center w-8 h-8 mt-5 mr-5 rounded-full dark:text-white hover:bg-neutral-100 dark:hover:bg-coolgray-300 outline-0">
<svg class="w-5 h-5" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"
stroke-width="1.5" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12" />

View File

@@ -1,8 +1,8 @@
<dialog id="{{ $modalId }}" class="modal">
@if ($yesOrNo)
<form method="dialog" class="rounded modal-box" @if (!$noSubmit) wire:submit='submit' @endif>
<form method="dialog" class="rounded-sm modal-box" @if (!$noSubmit) wire:submit='submit' @endif>
<div class="flex items-start">
<div class="flex items-center justify-center flex-shrink-0 w-10 h-10 mr-4 rounded-full">
<div class="flex items-center justify-center shrink-0 w-10 h-10 mr-4 rounded-full">
<svg class="w-8 h-8 text-error" fill="none" viewBox="0 0 24 24" stroke-width="1.5"
stroke="currentColor" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round"
@@ -33,7 +33,7 @@
</div>
</form>
@else
<form method="dialog" class="flex flex-col w-11/12 max-w-5xl gap-2 rounded modal-box"
<form method="dialog" class="flex flex-col w-11/12 max-w-5xl gap-2 rounded-sm modal-box"
@if ($submitWireAction) wire:submit={{ $submitWireAction }} @endif
@if (!$noSubmit && !$submitWireAction) wire:submit='submit' @endif>
@isset($modalTitle)

View File

@@ -85,7 +85,7 @@
<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"
<svg class="w-5 h-5 rounded-sm 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" />

View File

@@ -6,9 +6,9 @@
x-transition:enter-start="translate-y-full" x-transition:enter-end="translate-y-0"
x-transition:leave="transition ease-in duration-300" x-transition:leave-start="translate-y-0"
x-transition:leave-end="translate-y-full" x-init="setTimeout(() => { bannerVisible = true }, bannerVisibleAfter);"
class="fixed bottom-0 right-0 h-auto duration-300 ease-out px-5 pb-5 max-w-[46rem] z-[999]" x-cloak>
class="fixed bottom-0 right-0 h-auto duration-300 ease-out px-5 pb-5 max-w-[46rem] z-999" x-cloak>
<div
class="flex flex-row items-center justify-between w-full h-full max-w-4xl p-6 mx-auto bg-white border shadow-lg lg:border-t dark:border-coolgray-300 dark:bg-coolgray-100 hover:dark:bg-coolgray-100 lg:p-8 sm:rounded">
class="flex flex-row items-center justify-between w-full h-full max-w-4xl p-6 mx-auto bg-white border shadow-lg lg:border-t dark:border-coolgray-300 dark:bg-coolgray-100 dark:hover:bg-coolgray-100 lg:p-8 sm:rounded-sm">
<div
class="flex flex-col items-start h-full pb-0 text-xs lg:items-center lg:flex-row lg:pr-6 lg:space-x-5 dark:text-neutral-300 ">
@if (isset($icon))

View File

@@ -6,10 +6,10 @@
x-transition:enter-start="translate-y-full" x-transition:enter-end="translate-y-0"
x-transition:leave="transition ease-in duration-300" x-transition:leave-start="translate-y-0"
x-transition:leave-end="translate-y-full" x-init="setTimeout(() => { bannerVisible = true }, bannerVisibleAfter);"
class="fixed bottom-0 right-0 w-full h-auto duration-300 ease-out sm:px-5 sm:pb-5 w-full z-[999]"
class="fixed bottom-0 right-0 w-full h-auto duration-300 ease-out sm:px-5 sm:pb-5 w-full z-999"
x-cloak>
<div
class="flex items-center flex-col justify-between w-full h-full max-w-4xl p-6 mx-auto bg-white border shadow-lg lg:border-t dark:border-coolgray-300 dark:bg-coolgray-100 lg:p-8 lg:flex-row sm:rounded">
class="flex items-center flex-col justify-between w-full h-full max-w-4xl p-6 mx-auto bg-white border shadow-lg lg:border-t dark:border-coolgray-300 dark:bg-coolgray-100 lg:p-8 lg:flex-row sm:rounded-sm">
<div
class="flex flex-col items-start h-full pb-6 text-xs lg:items-center lg:flex-row lg:pb-0 lg:pr-6 lg:space-x-5 dark:text-neutral-300">
@if (isset($icon))
@@ -27,7 +27,7 @@
@if ($buttonText->attributes->whereStartsWith('@click')->first()) @click="bannerVisible=false;{{ $buttonText->attributes->get('@click') }}"
@else
@click="bannerVisible=false;" @endif
class="w-full px-4 py-2 text-sm font-medium tracking-wide transition-colors duration-200 rounded-md bg-neutral-100 hover:bg-neutral-200 dark:bg-coolgray-200 lg:w-auto dark:text-neutral-200 dark:hover:bg-coolgray-300 focus:shadow-outline focus:outline-none">
class="w-full px-4 py-2 text-sm font-medium tracking-wide transition-colors duration-200 rounded-md bg-neutral-100 hover:bg-neutral-200 dark:bg-coolgray-200 lg:w-auto dark:text-neutral-200 dark:hover:bg-coolgray-300 focus:shadow-outline focus:outline-hidden">
{{ $buttonText }}
</button>
</div>

View File

@@ -5,15 +5,15 @@
<div class="px-6 mx-auto lg:px-8">
<div class="flex justify-center">
<fieldset
class="grid grid-cols-2 p-1 text-xs font-semibold leading-5 text-center rounded dark:text-white gap-x-1 bg-white/5">
class="grid grid-cols-2 p-1 text-xs font-semibold leading-5 text-center rounded-sm dark:text-white gap-x-1 bg-white/5">
<legend class="sr-only">Payment frequency</legend>
<label class="cursor-pointer rounded px-2.5 py-1"
<label class="cursor-pointer rounded-sm px-2.5 py-1"
:class="selected === 'monthly' ? 'bg-coollabs-100 text-white' : ''">
<input type="radio" x-on:click="selected = 'monthly'" name="frequency" value="monthly"
class="sr-only">
<span>Monthly</span>
</label>
<label class="cursor-pointer rounded px-2.5 py-1"
<label class="cursor-pointer rounded-sm px-2.5 py-1"
:class="selected === 'yearly' ? 'bg-coollabs-100 text-white' : ''">
<input type="radio" x-on:click="selected = 'yearly'" name="frequency" value="annually"
class="sr-only">
@@ -34,7 +34,7 @@
<div>
</div>
</div>
<div class="p-4 rounded bg-coolgray-400">
<div class="p-4 rounded-sm bg-coolgray-400">
<h2 id="tier-hobby" class="flex items-start gap-4 text-4xl font-bold tracking-tight">Unlimited Trial
<x-forms.button><a class="font-bold dark:text-white hover:no-underline"
href="https://github.com/coollabsio/coolify">Get Started</a></x-forms.button>
@@ -257,7 +257,7 @@
</ul>
</div>
</div>
{{-- <div class="p-4 mt-10 rounded">
{{-- <div class="p-4 mt-10 rounded-sm">
<div class="flex items-start gap-4 text-xl tracking-tight">Need official support for
your self-hosted instance?
<x-forms.button>

View File

@@ -12,7 +12,7 @@
@if ($upgrade)
<div>{{ $upgrade }}</div>
@else
<div class="text-xs font-bold dark:text-neutral-500 group-hover:dark:text-neutral-300">
<div class="text-xs font-bold dark:text-neutral-500 dark:group-hover:text-neutral-300">
{{ $description }}
</div>
@endif

View File

@@ -45,6 +45,12 @@
]) }}">
<button>Terminal</button>
</a>
<a class="{{ request()->routeIs('server.security.patches') ? 'dark:text-white' : '' }}"
href="{{ route('server.security.patches', [
'server_uuid' => data_get($server, 'uuid'),
]) }}">
<button>Security</button>
</a>
</nav>
<div class="order-first sm:order-last">
<livewire:server.proxy.deploy :server="$server" />

View File

@@ -0,0 +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) }}">
Server Patching
</a>
</div>

View File

@@ -1,14 +1,13 @@
@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
class="relative z-[99] ">
class="relative z-99 ">
<div x-show="slideOverOpen" @if (!$closeWithX) @click="slideOverOpen = false" @endif
class="fixed inset-0 dark:bg-black/60 backdrop-blur-sm"></div>
class="fixed inset-0 dark:bg-black/60 backdrop-blur-xs"></div>
<div class="fixed inset-0 overflow-hidden">
<div class="absolute inset-0 overflow-hidden ">
<div class="fixed inset-y-0 right-0 flex max-w-full pl-10">
@@ -29,8 +28,8 @@
<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"
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">
<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">
<path stroke-linecap="round" stroke-linejoin="round"

View File

@@ -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" />

View File

@@ -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" />

View File

@@ -315,7 +315,7 @@
}
}
});"
class="fixed block w-full group z-[9999] sm:max-w-xs"
class="fixed block w-full group z-9999 sm:max-w-xs"
:class="{ 'right-0 top-0 sm:mt-6 sm:mr-6': position=='top-right', 'left-0 top-0 sm:mt-6 sm:ml-6': position=='top-left', 'left-1/2 -translate-x-1/2 top-0 sm:mt-6': position=='top-center', 'right-0 bottom-0 sm:mr-6 sm:mb-6': position=='bottom-right', 'left-0 bottom-0 sm:ml-6 sm:mb-6': position=='bottom-left', 'left-1/2 -translate-x-1/2 bottom-0 sm:mb-6': position=='bottom-center' }"
x-cloak>
@@ -390,7 +390,7 @@
class="absolute w-full duration-100 ease-out sm:max-w-xs "
:class="{ 'toast-no-description': !toast.description }">
<span
class="relative flex flex-col items-start shadow-[0_5px_15px_-3px_rgb(0_0_0_/_0.08)] w-full transition-all duration-100 ease-out dark:bg-coolgray-100 bg-white dark:border dark:border-coolgray-200 rounded sm:max-w-xs group"
class="relative flex flex-col items-start shadow-[0_5px_15px_-3px_rgb(0_0_0_/_0.08)] w-full transition-all duration-100 ease-out dark:bg-coolgray-100 bg-white dark:border dark:border-coolgray-200 rounded-sm sm:max-w-xs group"
:class="{ 'p-4': !toast.html, 'p-0': toast.html }">
<template x-if="!toast.html">
<div class="relative w-full">

View File

@@ -10,7 +10,7 @@
</div>
@endif
<div @class([
'flex flex-col-reverse w-full px-4 py-2 overflow-y-auto bg-white border border-solid rounded dark:text-white dark:bg-coolgray-100 scrollbar border-neutral-300 dark:border-coolgray-300',
'flex flex-col-reverse w-full px-4 py-2 overflow-y-auto bg-white border border-solid rounded-sm dark:text-white dark:bg-coolgray-100 scrollbar border-neutral-300 dark:border-coolgray-300',
'max-h-[48rem]' => $fullHeight,
'max-h-96' => !$fullHeight,
])>

View File

@@ -4,7 +4,7 @@
</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 ">
class="flex flex-col items-center justify-center p-10 mx-2 mt-10 bg-white border rounded-lg shadow-sm lg:p-20 dark:bg-transparent dark:border-none max-w-7xl ">
@if ($currentState === 'welcome')
<h1 class="text-3xl font-bold lg:text-5xl">Welcome to Coolify</h1>
<div class="py-6 text-center lg:text-xl">Let me help you set up the basics.</div>
@@ -89,7 +89,7 @@
<p class="mb-2">If the connection details are correct, please ensure:</p>
<ul class="list-disc list-inside">
<li>The correct public key is in your <code
class="bg-red-200 dark:bg-red-900 px-1 rounded">~/.ssh/authorized_keys</code>
class="bg-red-200 dark:bg-red-900 px-1 rounded-sm">~/.ssh/authorized_keys</code>
file for the specified user</li>
<li>Or skip the boarding process and manually add a new private key to Coolify and
the server</li>
@@ -207,7 +207,7 @@
<p class="mb-2">If the connection details are correct, please ensure:</p>
<ul class="list-disc list-inside">
<li>The correct public key is in your <code
class="bg-red-200 dark:bg-red-900 px-1 rounded">~/.ssh/authorized_keys</code>
class="bg-red-200 dark:bg-red-900 px-1 rounded-sm">~/.ssh/authorized_keys</code>
file for the specified user</li>
<li>Or skip the boarding process and manually add a new private key to Coolify and
the server</li>

View File

@@ -3,7 +3,7 @@
<a class="flex items-center mb-6 text-5xl font-extrabold tracking-tight text-gray-900 dark:text-white">
Coolify
</a>
<div class="w-full bg-white shadow md:mt-0 sm:max-w-md xl:p-0 dark:bg-base ">
<div class="w-full bg-white shadow-sm 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">
<form class="flex flex-col gap-2" wire:submit='submit'>
<x-forms.input id="email" type="email" placeholder="Email" readonly label="Email" />

View File

@@ -10,7 +10,7 @@
</div>
@endif
<div
class="scrollbar flex flex-col-reverse w-full overflow-y-auto border border-solid rounded border-coolgray-300 max-h-[32rem] p-4 pt-6 text-xs dark:text-white">
class="scrollbar flex flex-col-reverse w-full overflow-y-auto border border-solid rounded-sm border-coolgray-300 max-h-[32rem] p-4 pt-6 text-xs dark:text-white">
<pre class="font-mono whitespace-pre-wrap" @if ($isPollingActive) wire:poll.1000ms="polling" @endif>{{ RunRemoteProcess::decodeOutput($this->activity) }}</pre>
</div>

View File

@@ -1,4 +1,4 @@
<form class="flex flex-col w-full gap-2 rounded" wire:submit='submit'>
<form class="flex flex-col w-full gap-2 rounded-sm" wire:submit='submit'>
<x-forms.input placeholder="Your Cool Project" id="name" label="Name" required />
<x-forms.input placeholder="This is my cool project everyone knows about" id="description" label="Description" />
<div class="subtitle">New project will have a default <span class="dark:text-warning font-bold">production</span>

View File

@@ -44,17 +44,12 @@
<div class="flex flex-col">
<div class="flex items-center gap-2 mb-2">
<span @class([
'px-3 py-1 rounded-md text-xs font-medium shadow-sm',
'bg-blue-100/80 text-blue-700 dark:bg-blue-500/20 dark:text-blue-300' =>
data_get($deployment, 'status') === 'in_progress',
'bg-purple-100/80 text-purple-700 dark:bg-purple-500/20 dark:text-purple-300' =>
data_get($deployment, 'status') === 'queued',
'bg-red-100 text-red-800 dark:bg-red-900/30 dark:text-red-200' =>
data_get($deployment, 'status') === 'failed',
'bg-green-100 text-green-800 dark:bg-green-900/30 dark:text-green-200' =>
data_get($deployment, 'status') === 'finished',
'bg-gray-100 text-gray-700 dark:bg-gray-600/30 dark:text-gray-300' =>
data_get($deployment, 'status') === 'cancelled-by-user',
'px-3 py-1 rounded-md text-xs font-medium shadow-xs',
'bg-blue-100/80 text-blue-700 dark:bg-blue-500/20 dark:text-blue-300' => data_get($deployment, 'status') === 'in_progress',
'bg-purple-100/80 text-purple-700 dark:bg-purple-500/20 dark:text-purple-300' => data_get($deployment, 'status') === 'queued',
'bg-red-100 text-red-800 dark:bg-red-900/30 dark:text-red-200' => data_get($deployment, 'status') === 'failed',
'bg-green-100 text-green-800 dark:bg-green-900/30 dark:text-green-200' => data_get($deployment, 'status') === 'finished',
'bg-gray-100 text-gray-700 dark:bg-gray-600/30 dark:text-gray-300' => data_get($deployment, 'status') === 'cancelled-by-user',
])>
@php
$statusText = match (data_get($deployment, 'status')) {

View File

@@ -57,7 +57,7 @@
<div id="screen" :class="fullscreen ? 'fullscreen' : 'relative'">
<div @if ($isKeepAliveOn) wire:poll.2000ms="polling" @endif
class="flex flex-col-reverse w-full p-2 px-4 mt-4 overflow-y-auto bg-white dark:text-white dark:bg-coolgray-100 scrollbar dark:border-coolgray-300"
:class="fullscreen ? '' : 'min-h-14 max-h-[40rem] border border-dotted rounded'">
:class="fullscreen ? '' : 'min-h-14 max-h-[40rem] border border-dotted rounded-sm'">
<div :class="fullscreen ? 'fixed' : 'absolute'" class="top-2 right-5">
<div class="flex justify-end gap-4 fixed -translate-x-full">
<button title="Toggle timestamps" x-on:click="showTimestamps = !showTimestamps">

View File

@@ -83,11 +83,11 @@
@if ($application->build_pack !== 'dockercompose')
<div class="flex items-end gap-2">
@if ($application->settings->is_container_label_readonly_enabled == false)
<x-forms.input placeholder="https://coolify.io" wire:model.blur="application.fqdn"
<x-forms.input placeholder="https://coolify.io" wire:model.blur-sm="application.fqdn"
label="Domains" readonly
helper="Readonly labels are disabled. You can set the domains in the labels section." />
@else
<x-forms.input placeholder="https://coolify.io" wire:model.blur="application.fqdn"
<x-forms.input placeholder="https://coolify.io" wire:model.blur-sm="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

View File

@@ -1,7 +1,7 @@
<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 flex-shrink-0 gap-6 items-center whitespace-nowrap scrollbar min-h-10">
<nav class="flex shrink-0 gap-6 items-center whitespace-nowrap scrollbar min-h-10">
<a class="{{ request()->routeIs('project.application.configuration') ? 'dark:text-white' : '' }}"
href="{{ route('project.application.configuration', $parameters) }}">
Configuration
@@ -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"

View File

@@ -9,7 +9,7 @@
<div class="flex flex-wrap">
@forelse ($images as $image)
<div class="w-2/4 p-2">
<div class="bg-white border rounded dark:border-black dark:bg-coolgray-100">
<div class="bg-white border rounded-sm dark:border-black dark:bg-coolgray-100">
<div class="p-2">
<div class="">
@if (data_get($image, 'is_current'))

View File

@@ -19,7 +19,7 @@
@endif
<div class="flex items-center gap-2 mb-2">
<span @class([
'px-3 py-1 rounded-md text-xs font-medium tracking-wide shadow-sm',
'px-3 py-1 rounded-md text-xs font-medium tracking-wide shadow-xs',
'bg-blue-100/80 text-blue-700 dark:bg-blue-500/20 dark:text-blue-300 dark:shadow-blue-900/5' => data_get($execution, 'status') === 'running',
'bg-red-100 text-red-800 dark:bg-red-900/30 dark:text-red-200 dark:shadow-red-900/5' => data_get($execution, 'status') === 'failed',
'bg-green-100 text-green-800 dark:bg-green-900/30 dark:text-green-200 dark:shadow-green-900/5' => data_get($execution, 'status') === 'success',
@@ -59,7 +59,7 @@
Backup Availability:
</div>
<span @class([
'px-2 py-1 rounded text-xs font-medium',
'px-2 py-1 rounded-sm text-xs font-medium',
'bg-green-100 text-green-800 dark:bg-green-900/30 dark:text-green-200' => !data_get($execution, 'local_storage_deleted', false),
'bg-gray-100 text-gray-600 dark:bg-gray-800/50 dark:text-gray-400' => data_get($execution, 'local_storage_deleted', false),
])>
@@ -78,7 +78,7 @@
</span>
@if($backup->save_s3)
<span @class([
'px-2 py-1 rounded text-xs font-medium',
'px-2 py-1 rounded-sm text-xs font-medium',
'bg-green-100 text-green-800 dark:bg-green-900/30 dark:text-green-200' => !data_get($execution, 's3_storage_deleted', false),
'bg-gray-100 text-gray-600 dark:bg-gray-800/50 dark:text-gray-400' => data_get($execution, 's3_storage_deleted', false),
])>
@@ -98,7 +98,7 @@
@endif
</div>
@if (data_get($execution, 'message'))
<div class="mt-2 p-2 bg-gray-100 dark:bg-coolgray-200 rounded">
<div class="mt-2 p-2 bg-gray-100 dark:bg-coolgray-200 rounded-sm">
<pre class="whitespace-pre-wrap text-sm">{{ data_get($execution, 'message') }}</pre>
</div>
@endif
@@ -116,7 +116,7 @@
</div>
</div>
@empty
<div class="p-4 bg-gray-100 dark:bg-coolgray-100 rounded">No executions found.</div>
<div class="p-4 bg-gray-100 dark:bg-coolgray-100 rounded-sm">No executions found.</div>
@endforelse
</div>
<script>

View File

@@ -1,4 +1,4 @@
<form class="flex flex-col w-full gap-2 rounded" wire:submit='submit'>
<form class="flex flex-col w-full gap-2 rounded-sm" wire:submit='submit'>
<x-forms.input placeholder="0 0 * * * or daily" id="frequency"
helper="You can use every_minute, hourly, daily, weekly, monthly, yearly or a cron expression." label="Frequency"
required />

View File

@@ -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>
@@ -8,8 +8,8 @@
</x-slide-over>
<div class="navbar-main">
<nav
class="flex overflow-x-scroll flex-shrink-0 gap-6 items-center whitespace-nowrap sm:overflow-x-hidden scrollbar min-h-10">
<a class="{{ request()->routeIs('project.database.configuration') ? 'dark:text-white' : '' }}"
class="flex overflow-x-scroll shrink-0 gap-6 items-center whitespace-nowrap sm:overflow-x-hidden scrollbar min-h-10">
<a wire:navigate class="{{ request()->routeIs('project.database.configuration') ? 'dark:text-white' : '' }}"
href="{{ route('project.database.configuration', $parameters) }}">
<button>Configuration</button>
</a>
@@ -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"
@@ -99,6 +98,7 @@
});
$wire.$on('restartEvent', () => {
$wire.$dispatch('info', 'Restarting database.');
window.dispatchEvent(new CustomEvent('startdatabase'));
$wire.$call('restart');
});
</script>

View File

@@ -40,7 +40,7 @@
@if ($unsupported)
<div>Database restore is not supported.</div>
@else
<div class="pt-2 rounded alert-error">
<div class="pt-2 rounded-sm 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"

View File

@@ -1,6 +1,6 @@
<div>
<dialog id="newInitScript" class="modal">
<form method="dialog" class="flex flex-col gap-2 rounded modal-box" wire:submit='save_new_init_script'>
<form method="dialog" class="flex flex-col gap-2 rounded-sm modal-box" wire:submit='save_new_init_script'>
<h3 class="text-lg font-bold">Add Init Script</h3>
<x-forms.input placeholder="create_test_db.sql" id="new_filename" label="Filename" required />
<x-forms.textarea placeholder="CREATE DATABASE test;" id="new_content" label="Content" required />
@@ -181,7 +181,7 @@
<div class="flex items-center gap-2 pb-2">
<h3>Initialization scripts</h3>
<x-modal-input buttonTitle="+ Add" title="New Init Script">
<form class="flex flex-col w-full gap-2 rounded" wire:submit='save_new_init_script'>
<form class="flex flex-col w-full gap-2 rounded-sm" wire:submit='save_new_init_script'>
<x-forms.input placeholder="create_test_db.sql" id="new_filename" label="Filename"
required />
<x-forms.textarea rows="20" placeholder="CREATE DATABASE test;" id="new_content"

View File

@@ -62,7 +62,7 @@
@endif
</div>
@if ($build_pack === 'dockercompose')
<x-forms.input placeholder="/" wire:model.blur="base_directory" label="Base Directory"
<x-forms.input placeholder="/" wire:model.blur-sm="base_directory" label="Base Directory"
helper="Directory to use as root. Useful for monorepos." />
<x-forms.input placeholder="/docker-compose.yaml" id="docker_compose_location"
label="Docker Compose Location"

Some files were not shown because too many files have changed in this diff Show More