Merge branch 'next' into services
This commit is contained in:
@@ -31,7 +31,7 @@ class UpdateCoolify
|
||||
}
|
||||
CleanupDocker::dispatch($this->server);
|
||||
$this->latestVersion = get_latest_version_of_coolify();
|
||||
$this->currentVersion = config('version');
|
||||
$this->currentVersion = config('constants.coolify.version');
|
||||
if (! $manual_update) {
|
||||
if (! $settings->is_auto_update_enabled) {
|
||||
return;
|
||||
|
||||
@@ -200,7 +200,7 @@ class Init extends Command
|
||||
|
||||
private function restore_coolify_db_backup()
|
||||
{
|
||||
if (version_compare('4.0.0-beta.179', config('version'), '<=')) {
|
||||
if (version_compare('4.0.0-beta.179', config('constants.coolify.version'), '<=')) {
|
||||
try {
|
||||
$database = StandalonePostgresql::withTrashed()->find(0);
|
||||
if ($database && $database->trashed()) {
|
||||
@@ -228,7 +228,7 @@ class Init extends Command
|
||||
private function send_alive_signal()
|
||||
{
|
||||
$id = config('app.id');
|
||||
$version = config('version');
|
||||
$version = config('constants.coolify.version');
|
||||
$settings = instanceSettings();
|
||||
$do_not_track = data_get($settings, 'do_not_track');
|
||||
if ($do_not_track == true) {
|
||||
@@ -264,7 +264,7 @@ class Init extends Command
|
||||
|
||||
private function replace_slash_in_environment_name()
|
||||
{
|
||||
if (version_compare('4.0.0-beta.298', config('version'), '<=')) {
|
||||
if (version_compare('4.0.0-beta.298', config('constants.coolify.version'), '<=')) {
|
||||
$environments = Environment::all();
|
||||
foreach ($environments as $environment) {
|
||||
if (str_contains($environment->name, '/')) {
|
||||
|
||||
@@ -50,7 +50,7 @@ class Kernel extends ConsoleKernel
|
||||
$this->instanceTimezone = config('app.timezone');
|
||||
}
|
||||
|
||||
$this->scheduleInstance->job(new CleanupStaleMultiplexedConnections)->hourly();
|
||||
// $this->scheduleInstance->job(new CleanupStaleMultiplexedConnections)->hourly();
|
||||
|
||||
if (isDev()) {
|
||||
// Instance Jobs
|
||||
@@ -154,7 +154,7 @@ class Kernel extends ConsoleKernel
|
||||
}
|
||||
|
||||
// Cleanup multiplexed connections every hour
|
||||
$this->scheduleInstance->job(new ServerCleanupMux($server))->hourly()->onOneServer();
|
||||
// $this->scheduleInstance->job(new ServerCleanupMux($server))->hourly()->onOneServer();
|
||||
|
||||
// Temporary solution until we have better memory management for Sentinel
|
||||
if ($server->isSentinelEnabled()) {
|
||||
|
||||
@@ -37,7 +37,7 @@ class OtherController extends Controller
|
||||
)]
|
||||
public function version(Request $request)
|
||||
{
|
||||
return response(config('version'));
|
||||
return response(config('constants.coolify.version'));
|
||||
}
|
||||
|
||||
#[OA\Get(
|
||||
|
||||
@@ -27,7 +27,7 @@ class CheckForUpdatesJob implements ShouldBeEncrypted, ShouldQueue
|
||||
$versions = $response->json();
|
||||
|
||||
$latest_version = data_get($versions, 'coolify.v4.version');
|
||||
$current_version = config('version');
|
||||
$current_version = config('constants.coolify.version');
|
||||
|
||||
if (version_compare($latest_version, $current_version, '>')) {
|
||||
// New version available
|
||||
|
||||
@@ -67,6 +67,8 @@ class DatabaseBackupJob implements ShouldBeEncrypted, ShouldQueue
|
||||
public function handle(): void
|
||||
{
|
||||
try {
|
||||
$databasesToBackup = null;
|
||||
|
||||
$this->team = Team::find($this->backup->team_id);
|
||||
if (! $this->team) {
|
||||
$this->backup->delete();
|
||||
@@ -198,8 +200,7 @@ class DatabaseBackupJob implements ShouldBeEncrypted, ShouldQueue
|
||||
$databaseType = $this->database->type();
|
||||
$databasesToBackup = data_get($this->backup, 'databases_to_backup');
|
||||
}
|
||||
|
||||
if (filled($databasesToBackup)) {
|
||||
if (blank($databasesToBackup)) {
|
||||
if (str($databaseType)->contains('postgres')) {
|
||||
$databasesToBackup = [$this->database->postgres_db];
|
||||
} elseif (str($databaseType)->contains('mongodb')) {
|
||||
|
||||
@@ -25,6 +25,7 @@ class StripeProcessJob implements ShouldQueue
|
||||
|
||||
public function handle(): void
|
||||
{
|
||||
try {
|
||||
$excludedPlans = config('subscription.stripe_excluded_plans');
|
||||
|
||||
$type = data_get($this->event, 'type');
|
||||
@@ -51,7 +52,7 @@ class StripeProcessJob implements ShouldQueue
|
||||
send_internal_notification("Early fraud warning created Refunded, subscription canceled. Charge: {$charge}, id: {$id}, pi: {$pi}");
|
||||
} else {
|
||||
send_internal_notification("Early fraud warning: subscription not found. Charge: {$charge}, id: {$id}, pi: {$pi}");
|
||||
throw new \Exception("Early fraud warning: subscription not found. Charge: {$charge}, id: {$id}, pi: {$pi}");
|
||||
throw new \RuntimeException("Early fraud warning: subscription not found. Charge: {$charge}, id: {$id}, pi: {$pi}");
|
||||
}
|
||||
break;
|
||||
case 'checkout.session.completed':
|
||||
@@ -68,7 +69,7 @@ class StripeProcessJob implements ShouldQueue
|
||||
$found = $team->members->where('id', $userId)->first();
|
||||
if (! $found->isAdmin()) {
|
||||
send_internal_notification("User {$userId} is not an admin or owner of team {$team->id}, customerid: {$customerId}, subscriptionid: {$subscriptionId}.");
|
||||
throw new \Exception("User {$userId} is not an admin or owner of team {$team->id}, customerid: {$customerId}, subscriptionid: {$subscriptionId}.");
|
||||
throw new \RuntimeException("User {$userId} is not an admin or owner of team {$team->id}, customerid: {$customerId}, subscriptionid: {$subscriptionId}.");
|
||||
}
|
||||
$subscription = Subscription::where('team_id', $teamId)->first();
|
||||
if ($subscription) {
|
||||
@@ -101,7 +102,7 @@ class StripeProcessJob implements ShouldQueue
|
||||
'stripe_invoice_paid' => true,
|
||||
]);
|
||||
} else {
|
||||
throw new \Exception("No subscription found for customer: {$customerId}");
|
||||
throw new \RuntimeException("No subscription found for customer: {$customerId}");
|
||||
}
|
||||
break;
|
||||
case 'invoice.payment_failed':
|
||||
@@ -109,12 +110,12 @@ class StripeProcessJob implements ShouldQueue
|
||||
$subscription = Subscription::where('stripe_customer_id', $customerId)->first();
|
||||
if (! $subscription) {
|
||||
send_internal_notification('invoice.payment_failed failed but no subscription found in Coolify for customer: '.$customerId);
|
||||
throw new \Exception("No subscription found for customer: {$customerId}");
|
||||
throw new \RuntimeException("No subscription found for customer: {$customerId}");
|
||||
}
|
||||
$team = data_get($subscription, 'team');
|
||||
if (! $team) {
|
||||
send_internal_notification('invoice.payment_failed failed but no team found in Coolify for customer: '.$customerId);
|
||||
throw new \Exception("No team found in Coolify for customer: {$customerId}");
|
||||
throw new \RuntimeException("No team found in Coolify for customer: {$customerId}");
|
||||
}
|
||||
if (! $subscription->stripe_invoice_paid) {
|
||||
SubscriptionInvoiceFailedJob::dispatch($team);
|
||||
@@ -128,7 +129,7 @@ class StripeProcessJob implements ShouldQueue
|
||||
$subscription = Subscription::where('stripe_customer_id', $customerId)->first();
|
||||
if (! $subscription) {
|
||||
send_internal_notification('payment_intent.payment_failed, no subscription found in Coolify for customer: '.$customerId);
|
||||
throw new \Exception("No subscription found in Coolify for customer: {$customerId}");
|
||||
throw new \RuntimeException("No subscription found in Coolify for customer: {$customerId}");
|
||||
}
|
||||
if ($subscription->stripe_invoice_paid) {
|
||||
send_internal_notification('payment_intent.payment_failed but invoice is active for customer: '.$customerId);
|
||||
@@ -145,20 +146,20 @@ class StripeProcessJob implements ShouldQueue
|
||||
if (! $teamId || ! $userId) {
|
||||
$subscription = Subscription::where('stripe_customer_id', $customerId)->first();
|
||||
if ($subscription) {
|
||||
throw new \Exception("Subscription already exists for customer: {$customerId}");
|
||||
throw new \RuntimeException("Subscription already exists for customer: {$customerId}");
|
||||
}
|
||||
throw new \Exception('No team id or user id found');
|
||||
throw new \RuntimeException('No team id or user id found');
|
||||
}
|
||||
$team = Team::find($teamId);
|
||||
$found = $team->members->where('id', $userId)->first();
|
||||
if (! $found->isAdmin()) {
|
||||
send_internal_notification("User {$userId} is not an admin or owner of team {$team->id}, customerid: {$customerId}.");
|
||||
throw new \Exception("User {$userId} is not an admin or owner of team {$team->id}, customerid: {$customerId}.");
|
||||
throw new \RuntimeException("User {$userId} is not an admin or owner of team {$team->id}, customerid: {$customerId}.");
|
||||
}
|
||||
$subscription = Subscription::where('team_id', $teamId)->first();
|
||||
if ($subscription) {
|
||||
send_internal_notification("Subscription already exists for team: {$teamId}");
|
||||
throw new \Exception("Subscription already exists for team: {$teamId}");
|
||||
throw new \RuntimeException("Subscription already exists for team: {$teamId}");
|
||||
} else {
|
||||
Subscription::create([
|
||||
'team_id' => $teamId,
|
||||
@@ -182,7 +183,7 @@ class StripeProcessJob implements ShouldQueue
|
||||
if (! $subscription) {
|
||||
if ($status === 'incomplete_expired') {
|
||||
send_internal_notification('Subscription incomplete expired');
|
||||
throw new \Exception('Subscription incomplete expired');
|
||||
throw new \RuntimeException('Subscription incomplete expired');
|
||||
}
|
||||
if ($teamId) {
|
||||
$subscription = Subscription::create([
|
||||
@@ -193,7 +194,7 @@ class StripeProcessJob implements ShouldQueue
|
||||
]);
|
||||
} else {
|
||||
send_internal_notification('No subscription and team id found');
|
||||
throw new \Exception('No subscription and team id found');
|
||||
throw new \RuntimeException('No subscription and team id found');
|
||||
}
|
||||
}
|
||||
$cancelAtPeriodEnd = data_get($data, 'cancel_at_period_end');
|
||||
@@ -236,7 +237,10 @@ class StripeProcessJob implements ShouldQueue
|
||||
$team?->subscriptionEnded();
|
||||
break;
|
||||
default:
|
||||
// Unhandled event type
|
||||
throw new \RuntimeException("Unhandled event type: {$type}");
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
send_internal_notification('StripeProcessJob error: '.$e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,7 +36,11 @@ class Heading extends Component
|
||||
|
||||
public function mount()
|
||||
{
|
||||
$this->parameters = get_route_parameters();
|
||||
$this->parameters = [
|
||||
'project_uuid' => $this->application->project()->uuid,
|
||||
'environment_name' => $this->application->environment->name,
|
||||
'application_uuid' => $this->application->uuid,
|
||||
];
|
||||
$lastDeployment = $this->application->get_last_successful_deployment();
|
||||
$this->lastDeploymentInfo = data_get_str($lastDeployment, 'commit')->limit(7).' '.data_get($lastDeployment, 'commit_message');
|
||||
$this->lastDeploymentLink = $this->application->gitCommitLink(data_get($lastDeployment, 'commit'));
|
||||
|
||||
@@ -71,7 +71,7 @@ class EnvironmentVariable extends Model
|
||||
}
|
||||
}
|
||||
$environment_variable->update([
|
||||
'version' => config('version'),
|
||||
'version' => config('constants.coolify.version'),
|
||||
]);
|
||||
});
|
||||
static::saving(function (EnvironmentVariable $environmentVariable) {
|
||||
|
||||
@@ -46,7 +46,7 @@ class DiscordMessage
|
||||
|
||||
public function toPayload(): array
|
||||
{
|
||||
$footerText = 'Coolify v'.config('version');
|
||||
$footerText = 'Coolify v'.config('constants.coolify.version');
|
||||
if (isCloud()) {
|
||||
$footerText = 'Coolify Cloud';
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<?php
|
||||
|
||||
$version = include 'config/version.php';
|
||||
echo $version;
|
||||
$version = include 'config/constants.php';
|
||||
echo $version['coolify']['version'] ?: 'unknown';
|
||||
|
||||
@@ -192,7 +192,7 @@ function defaultLabels($id, $name, $pull_request_id = 0, string $type = 'applica
|
||||
{
|
||||
$labels = collect([]);
|
||||
$labels->push('coolify.managed=true');
|
||||
$labels->push('coolify.version='.config('version'));
|
||||
$labels->push('coolify.version='.config('constants.coolify.version'));
|
||||
$labels->push('coolify.'.$type.'Id='.$id);
|
||||
$labels->push("coolify.type=$type");
|
||||
$labels->push('coolify.name='.$name);
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
<?php
|
||||
|
||||
return '4.0.0-beta.372';
|
||||
@@ -60,7 +60,22 @@ export function initializeTerminalComponent() {
|
||||
};
|
||||
|
||||
},
|
||||
resetTerminal() {
|
||||
if (this.term) {
|
||||
this.$wire.dispatch('error', 'Terminal websocket connection lost.');
|
||||
this.term.reset();
|
||||
this.term.clear();
|
||||
this.pendingWrites = 0;
|
||||
this.paused = false;
|
||||
this.commandBuffer = '';
|
||||
|
||||
// Force a refresh
|
||||
this.$nextTick(() => {
|
||||
this.resizeTerminal();
|
||||
this.term.focus();
|
||||
});
|
||||
}
|
||||
},
|
||||
setupTerminal() {
|
||||
const terminalElement = document.getElementById('terminal');
|
||||
if (terminalElement) {
|
||||
@@ -69,9 +84,15 @@ export function initializeTerminalComponent() {
|
||||
rows: 30,
|
||||
fontFamily: '"Fira Code", courier-new, courier, monospace, "Powerline Extra Symbols"',
|
||||
cursorBlink: true,
|
||||
rendererType: 'canvas',
|
||||
convertEol: true,
|
||||
disableStdin: false
|
||||
});
|
||||
this.fitAddon = new FitAddon();
|
||||
this.term.loadAddon(this.fitAddon);
|
||||
this.$nextTick(() => {
|
||||
this.resizeTerminal();
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
@@ -101,12 +122,19 @@ export function initializeTerminalComponent() {
|
||||
`${connectionString.protocol}://${connectionString.host}${connectionString.port}${connectionString.path}`
|
||||
this.socket = new WebSocket(url);
|
||||
|
||||
this.socket.onopen = () => {
|
||||
console.log('[Terminal] WebSocket connection established. Cool cool cool cool cool cool.');
|
||||
};
|
||||
|
||||
this.socket.onmessage = this.handleSocketMessage.bind(this);
|
||||
this.socket.onerror = (e) => {
|
||||
console.error('WebSocket error:', e);
|
||||
console.error('[Terminal] WebSocket error.');
|
||||
};
|
||||
this.socket.onclose = () => {
|
||||
console.log('WebSocket connection closed');
|
||||
console.warn('[Terminal] WebSocket connection closed.');
|
||||
this.resetTerminal();
|
||||
this.message = '(connection closed)';
|
||||
this.terminalActive = false;
|
||||
this.reconnect();
|
||||
};
|
||||
}
|
||||
@@ -117,19 +145,18 @@ export function initializeTerminalComponent() {
|
||||
clearInterval(this.reconnectInterval);
|
||||
}
|
||||
this.reconnectInterval = setInterval(() => {
|
||||
console.log('Attempting to reconnect...');
|
||||
console.warn('[Terminal] Attempting to reconnect...');
|
||||
this.initializeWebSocket();
|
||||
if (this.socket && this.socket.readyState === WebSocket.OPEN) {
|
||||
console.log('Reconnected successfully');
|
||||
console.log('[Terminal] Reconnected successfully');
|
||||
clearInterval(this.reconnectInterval);
|
||||
this.reconnectInterval = null;
|
||||
window.location.reload();
|
||||
|
||||
}
|
||||
}, 2000);
|
||||
},
|
||||
|
||||
handleSocketMessage(event) {
|
||||
this.message = '(connection closed)';
|
||||
if (event.data === 'pty-ready') {
|
||||
if (!this.term._initialized) {
|
||||
this.term.open(document.getElementById('terminal'));
|
||||
@@ -150,8 +177,17 @@ export function initializeTerminalComponent() {
|
||||
this.term.reset();
|
||||
this.commandBuffer = '';
|
||||
} else {
|
||||
try {
|
||||
this.pendingWrites++;
|
||||
this.term.write(event.data, this.flowControlCallback.bind(this));
|
||||
this.term.write(event.data, (err) => {
|
||||
if (err) {
|
||||
console.error('[Terminal] Write error:', err);
|
||||
}
|
||||
this.flowControlCallback();
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('[Terminal] Write operation failed:', error);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -173,12 +209,16 @@ export function initializeTerminalComponent() {
|
||||
if (!this.term) return;
|
||||
|
||||
this.term.onData((data) => {
|
||||
if (this.socket.readyState === WebSocket.OPEN) {
|
||||
this.socket.send(JSON.stringify({ message: data }));
|
||||
if (data === '\r') {
|
||||
this.commandBuffer = '';
|
||||
} else {
|
||||
this.commandBuffer += data;
|
||||
}
|
||||
} else {
|
||||
console.warn('[Terminal] WebSocket not ready, data not sent');
|
||||
}
|
||||
});
|
||||
|
||||
// Copy and paste functionality
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
toast(this.title, { description: this.description, type: this.type, position: this.position, html: html })
|
||||
}
|
||||
}" x-init="window.toast = function(message, options = {}) {
|
||||
try {
|
||||
let description = '';
|
||||
let type = 'default';
|
||||
let position = 'top-center';
|
||||
@@ -21,6 +22,9 @@
|
||||
if (typeof options.html != 'undefined') html = options.html;
|
||||
|
||||
window.dispatchEvent(new CustomEvent('toast-show', { detail: { type: type, message: message, description: description, position: position, html: html } }));
|
||||
} catch (error) {
|
||||
console.error('Error showing toast:', error);
|
||||
}
|
||||
}" class="relative space-y-5">
|
||||
<template x-teleport="body">
|
||||
<ul x-data="{
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<a {{ $attributes->merge(['class' => 'text-xs cursor-pointer opacity-90 hover:opacity-100 dark:hover:text-white hover:text-black']) }}
|
||||
href="https://github.com/coollabsio/coolify/releases/tag/v{{ config('version') }}" target="_blank">
|
||||
v{{ config('version') }}
|
||||
href="https://github.com/coollabsio/coolify/releases/tag/v{{ config('constants.coolify.version') }}" target="_blank">
|
||||
v{{ config('constants.coolify.version') }}
|
||||
</a>
|
||||
@@ -96,6 +96,20 @@
|
||||
enableStats: false,
|
||||
enableLogging: true,
|
||||
enabledTransports: ['ws', 'wss'],
|
||||
disableStats: true,
|
||||
// Add auto reconnection settings
|
||||
enabledTransports: ['ws', 'wss'],
|
||||
disabledTransports: ['sockjs', 'xhr_streaming', 'xhr_polling'],
|
||||
// Attempt to reconnect on connection lost
|
||||
autoReconnect: true,
|
||||
// Wait 1 second before first reconnect attempt
|
||||
reconnectionDelay: 1000,
|
||||
// Maximum delay between reconnection attempts
|
||||
maxReconnectionDelay: 1000,
|
||||
// Multiply delay by this number for each reconnection attempt
|
||||
reconnectionDelayGrowth: 1,
|
||||
// Maximum number of reconnection attempts
|
||||
maxAttempts: 15
|
||||
});
|
||||
@endauth
|
||||
let checkHealthInterval = null;
|
||||
|
||||
@@ -11,16 +11,22 @@
|
||||
|
||||
let checkNumber = 1;
|
||||
let checkPusherInterval = null;
|
||||
let checkReconnectInterval = null;
|
||||
|
||||
if (!this.popups.realtime) {
|
||||
checkPusherInterval = setInterval(() => {
|
||||
if (window.Echo && window.Echo.connector.pusher.connection.state !== 'connected') {
|
||||
if (window.Echo) {
|
||||
if (window.Echo.connector.pusher.connection.state === 'connected') {
|
||||
this.popups.realtime = false;
|
||||
} else {
|
||||
checkNumber++;
|
||||
if (checkNumber > 5) {
|
||||
this.popups.realtime = true;
|
||||
console.error(
|
||||
'Coolify could not connect to its real-time service. This will cause unusual problems on the UI if not fixed! Please check the related documentation (https://coolify.io/docs/knowledge-base/cloudflare/tunnels) or get help on Discord (https://coollabs.io/discord).)'
|
||||
);
|
||||
clearInterval(checkPusherInterval);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}, 2000);
|
||||
|
||||
@@ -26,8 +26,8 @@
|
||||
@else
|
||||
@if (count($containers) > 0)
|
||||
@if (count($containers) === 1)
|
||||
<form class="w-full pt-4"
|
||||
wire:submit="$dispatchSelf('connectToContainer')" wire:init="$dispatchSelf('connectToContainer')">
|
||||
<form class="w-full pt-4" wire:submit="$dispatchSelf('connectToContainer')"
|
||||
wire:init="$dispatchSelf('connectToContainer')">
|
||||
<x-forms.button class="w-full" type="submit">Reconnect</x-forms.button>
|
||||
</form>
|
||||
@else
|
||||
|
||||
Reference in New Issue
Block a user