fix: require notification and log drain fields only when enabled (#12232)

This commit is contained in:
Andras Bacsai
2026-10-19 21:47:33 +02:00
committed by GitHub
parent e61c0edd1a
commit 71131804f6
13 changed files with 75 additions and 19 deletions
+1 -1
View File
@@ -22,7 +22,7 @@ class Discord extends Component
#[Validate(['boolean'])]
public bool $discordEnabled = false;
#[Validate(['nullable', new SafeWebhookUrl])]
#[Validate(['required_if:discordEnabled,true', 'nullable', new SafeWebhookUrl])]
public ?string $discordWebhookUrl = null;
#[Validate(['boolean'])]
+2 -2
View File
@@ -26,10 +26,10 @@ class Pushover extends Component
#[Validate(['boolean'])]
public bool $pushoverEnabled = false;
#[Validate(['nullable', 'string'])]
#[Validate(['required_if:pushoverEnabled,true', 'nullable', 'string'])]
public ?string $pushoverUserKey = null;
#[Validate(['nullable', 'string'])]
#[Validate(['required_if:pushoverEnabled,true', 'nullable', 'string'])]
public ?string $pushoverApiToken = null;
#[Validate(['boolean'])]
+1 -1
View File
@@ -27,7 +27,7 @@ class Slack extends Component
#[Validate(['boolean'])]
public bool $slackEnabled = false;
#[Validate(['nullable', new SafeWebhookUrl])]
#[Validate(['required_if:slackEnabled,true', 'nullable', new SafeWebhookUrl])]
public ?string $slackWebhookUrl = null;
#[Validate(['boolean'])]
+2 -2
View File
@@ -27,10 +27,10 @@ class Telegram extends Component
#[Validate(['boolean'])]
public bool $telegramEnabled = false;
#[Validate(['nullable', 'string'])]
#[Validate(['required_if:telegramEnabled,true', 'nullable', 'string'])]
public ?string $telegramToken = null;
#[Validate(['nullable', 'string'])]
#[Validate(['required_if:telegramEnabled,true', 'nullable', 'string'])]
public ?string $telegramChatId = null;
#[Validate(['boolean'])]
+1 -1
View File
@@ -22,7 +22,7 @@ class Webhook extends Component
#[Validate(['boolean'])]
public bool $webhookEnabled = false;
#[Validate(['nullable', new SafeWebhookUrl])]
#[Validate(['required_if:webhookEnabled,true', 'nullable', new SafeWebhookUrl])]
public ?string $webhookUrl = null;
#[Validate(['boolean'])]
@@ -25,7 +25,7 @@
]" />
<div class="lg:col-span-2">
@can('update', $settings)
<x-forms.input type="password" required id="discordWebhookUrl" label="Webhook URL"
<x-forms.input type="password" :required="$discordEnabled" id="discordWebhookUrl" label="Webhook URL"
helper="Create an incoming webhook in your Discord server settings." />
@else
<x-forms.input disabled label="Webhook URL" value="Hidden (only admins can view)" />
@@ -17,9 +17,9 @@
<div class="grid gap-4 lg:grid-cols-2">
@can('update', $settings)
<x-forms.input type="password" required id="pushoverUserKey" label="User key"
<x-forms.input type="password" :required="$pushoverEnabled" id="pushoverUserKey" label="User key"
helper="Find this in the Pushover dashboard." />
<x-forms.input type="password" required id="pushoverApiToken" label="API token"
<x-forms.input type="password" :required="$pushoverEnabled" id="pushoverApiToken" label="API token"
helper="Create an application in Pushover to generate this token." />
@else
<x-forms.input disabled label="User key" value="Hidden (only admins can view)" />
@@ -18,7 +18,7 @@
<div class="grid gap-4 lg:grid-cols-2">
<div class="lg:col-span-2">
@can('update', $settings)
<x-forms.input type="password" required id="slackWebhookUrl" label="Webhook URL"
<x-forms.input type="password" :required="$slackEnabled" id="slackWebhookUrl" label="Webhook URL"
helper="Create an incoming webhook in your Slack app settings." />
@else
<x-forms.input disabled label="Webhook URL" value="Hidden (only admins can view)" />
@@ -17,9 +17,9 @@
<div class="grid gap-4 lg:grid-cols-2">
@can('update', $settings)
<x-forms.input type="password" autocomplete="new-password" required id="telegramToken"
<x-forms.input type="password" autocomplete="new-password" :required="$telegramEnabled" id="telegramToken"
label="Bot API token" helper="Create a bot with BotFather to obtain this token." />
<x-forms.input type="password" autocomplete="new-password" required id="telegramChatId"
<x-forms.input type="password" autocomplete="new-password" :required="$telegramEnabled" id="telegramChatId"
label="Chat ID" helper="Add the bot to your chat, then enter that chat ID." />
@else
<x-forms.input disabled label="Bot API token" value="Hidden (only admins can view)" />
@@ -18,7 +18,7 @@
<div class="grid gap-4 lg:grid-cols-2">
<div class="lg:col-span-2">
@can('update', $settings)
<x-forms.input type="password" required id="webhookUrl" label="Webhook URL"
<x-forms.input type="password" :required="$webhookEnabled" id="webhookUrl" label="Webhook URL"
helper="Coolify sends POST requests to this HTTP or HTTPS endpoint." />
@else
<x-forms.input disabled label="Webhook URL" value="Hidden (only admins can view)" />
@@ -35,10 +35,10 @@
['value' => true, 'label' => 'Enabled'],
]"
:disabled="$isLogDrainAxiomEnabled || $isLogDrainCustomEnabled || !auth()->user()->can('update', $server)" />
<x-forms.input canGate="update" :canResource="$server" type="password" required
<x-forms.input canGate="update" :canResource="$server" type="password" :required="$isLogDrainNewRelicEnabled"
id="logDrainNewRelicLicenseKey" label="License key"
:disabled="$server->isLogDrainEnabled()" />
<x-forms.input canGate="update" :canResource="$server" required
<x-forms.input canGate="update" :canResource="$server" :required="$isLogDrainNewRelicEnabled"
id="logDrainNewRelicBaseUri" label="Endpoint"
placeholder="https://log-api.eu.newrelic.com/log/v1"
helper="Use the EU or US New Relic Log API endpoint."
@@ -54,10 +54,10 @@
['value' => true, 'label' => 'Enabled'],
]"
:disabled="$isLogDrainNewRelicEnabled || $isLogDrainCustomEnabled || !auth()->user()->can('update', $server)" />
<x-forms.input canGate="update" :canResource="$server" type="password" required
<x-forms.input canGate="update" :canResource="$server" type="password" :required="$isLogDrainAxiomEnabled"
id="logDrainAxiomApiKey" label="API key"
:disabled="$server->isLogDrainEnabled()" />
<x-forms.input canGate="update" :canResource="$server" required
<x-forms.input canGate="update" :canResource="$server" :required="$isLogDrainAxiomEnabled"
id="logDrainAxiomDatasetName" label="Dataset name"
:disabled="$server->isLogDrainEnabled()" />
</div>
@@ -73,7 +73,7 @@
:disabled="$isLogDrainNewRelicEnabled || $isLogDrainAxiomEnabled || !auth()->user()->can('update', $server)" />
</div>
<div class="grid gap-4 lg:grid-cols-2">
<x-forms.textarea canGate="update" :canResource="$server" rows="8" required
<x-forms.textarea canGate="update" :canResource="$server" rows="8" :required="$isLogDrainCustomEnabled"
id="logDrainCustomConfig" label="Fluent Bit configuration"
:disabled="$server->isLogDrainEnabled()" />
<x-forms.textarea canGate="update" :canResource="$server" rows="8"
+43
View File
@@ -209,3 +209,46 @@ it('reverts the discord mention setting to the saved value when saving fails', f
expect($team->discordNotificationSettings->fresh()->discord_ping_enabled)->toBeTrue();
});
it('saves cleared notification provider fields while the provider is disabled', function (string $component, string $settingsRelation, array $savedSettings, array $properties) {
[, $team] = actingAsEnableActionOwner();
$team->{$settingsRelation}->update($savedSettings);
$test = Livewire::test($component);
foreach ($properties as $property) {
$test->set($property, '');
}
$test->call('submit')
->assertHasNoErrors()
->assertDispatched('success');
$settings = $team->{$settingsRelation}->fresh();
foreach (array_keys($savedSettings) as $column) {
expect($settings->{$column})->toBeEmpty();
}
})->with([
'discord' => [Discord::class, 'discordNotificationSettings', ['discord_webhook_url' => 'https://discord.com/api/webhooks/1/abc'], ['discordWebhookUrl']],
'slack' => [Slack::class, 'slackNotificationSettings', ['slack_webhook_url' => 'https://hooks.slack.com/services/T/B/C'], ['slackWebhookUrl']],
'telegram' => [Telegram::class, 'telegramNotificationSettings', ['telegram_token' => '123:abc', 'telegram_chat_id' => '42'], ['telegramToken', 'telegramChatId']],
'pushover' => [Pushover::class, 'pushoverNotificationSettings', ['pushover_user_key' => 'user', 'pushover_api_token' => 'token'], ['pushoverUserKey', 'pushoverApiToken']],
'webhook' => [Webhook::class, 'webhookNotificationSettings', ['webhook_url' => 'https://hooks.example.com/coolify'], ['webhookUrl']],
]);
it('rejects cleared notification provider fields while the provider is enabled', function (string $component, string $settingsRelation, array $savedSettings, string $property) {
[, $team] = actingAsEnableActionOwner();
$team->{$settingsRelation}->update($savedSettings);
Livewire::test($component)
->set($property, '')
->call('submit')
->assertNotDispatched('success')
->assertDispatched('error');
expect($team->{$settingsRelation}->fresh()->{array_keys($savedSettings)[1]})->not->toBeEmpty();
})->with([
'discord' => [Discord::class, 'discordNotificationSettings', ['discord_enabled' => true, 'discord_webhook_url' => 'https://discord.com/api/webhooks/1/abc'], 'discordWebhookUrl'],
'slack' => [Slack::class, 'slackNotificationSettings', ['slack_enabled' => true, 'slack_webhook_url' => 'https://hooks.slack.com/services/T/B/C'], 'slackWebhookUrl'],
'telegram' => [Telegram::class, 'telegramNotificationSettings', ['telegram_enabled' => true, 'telegram_token' => '123:abc', 'telegram_chat_id' => '42'], 'telegramToken'],
'pushover' => [Pushover::class, 'pushoverNotificationSettings', ['pushover_enabled' => true, 'pushover_user_key' => 'user', 'pushover_api_token' => 'token'], 'pushoverUserKey'],
'webhook' => [Webhook::class, 'webhookNotificationSettings', ['webhook_enabled' => true, 'webhook_url' => 'https://hooks.example.com/coolify'], 'webhookUrl'],
]);
@@ -200,3 +200,16 @@ test('the UI does not enable an unsupported custom log drain', function () {
expect((bool) $this->server->settings->fresh()->is_logdrain_custom_enabled)->toBeFalse();
});
test('the UI saves a cleared custom config while the custom log drain is disabled', function () {
$this->actingAs($this->user);
$this->server->settings->update(['logdrain_custom_config' => SAFE_CUSTOM_LOG_DRAIN_CONFIG]);
Livewire::test(LogDrains::class, ['server_uuid' => $this->server->uuid])
->set('logDrainCustomConfig', '')
->call('submit')
->assertHasNoErrors()
->assertDispatched('success');
expect($this->server->settings->fresh()->logdrain_custom_config)->toBeEmpty();
});