+
+
+
{t('crowdsecConfig.whitelist.title', 'IP Whitelist')}
+
+
+ {t('crowdsecConfig.whitelist.description', 'Whitelisted IPs and CIDRs are never blocked by CrowdSec, even if they trigger alerts.')}
+
+
+ {/* Add entry form */}
+
+
+ {
+ setWhitelistForm((prev) => ({ ...prev, ip_or_cidr: e.target.value }))
+ if (addWhitelistMutation.error) addWhitelistMutation.reset()
+ }}
+ error={whitelistInlineError ?? undefined}
+ errorTestId="whitelist-ip-error"
+ aria-required={true}
+ data-testid="whitelist-ip-input"
+ />
+
+
+ setWhitelistForm((prev) => ({ ...prev, reason: e.target.value }))}
+ data-testid="whitelist-reason-input"
+ />
+
+
+
+ {t('crowdsecConfig.whitelist.addMyIp', 'Add My IP')}
+
+ {
+ addWhitelistMutation.mutate(whitelistForm, {
+ onSuccess: () => setWhitelistForm({ ip_or_cidr: '', reason: '' }),
+ })
+ }}
+ disabled={!whitelistForm.ip_or_cidr.trim() || addWhitelistMutation.isPending}
+ isLoading={addWhitelistMutation.isPending}
+ data-testid="whitelist-add-btn"
+ >
+ {t('common.add', 'Add')}
+
+
+
+
+ {/* Entries table */}
+ {whitelistQuery.isLoading ? (
+
+
+
+
+
+ ) : !whitelistQuery.data?.length ? (
+
+ {t('crowdsecConfig.whitelist.none', 'No whitelist entries')}
+
+ ) : (
+
+
+
+
+
+ {t('crowdsecConfig.whitelist.columnIp', 'IP / CIDR')}
+
+
+ {t('crowdsecConfig.whitelist.columnReason', 'Reason')}
+
+
+ {t('crowdsecConfig.whitelist.columnAdded', 'Added')}
+
+
+ {t('crowdsecConfig.bannedIps.actions')}
+
+
+
+
+ {whitelistQuery.data.map((entry) => (
+
+ {entry.ip_or_cidr}
+ {entry.reason || '-'}
+
+ {entry.created_at ? new Date(entry.created_at).toLocaleString() : '-'}
+
+
+ setConfirmDeleteWhitelist(entry)}
+ aria-label={`${t('crowdsecConfig.whitelist.deleteAriaLabel', 'Remove whitelist entry for')} ${entry.ip_or_cidr}`}
+ data-testid="whitelist-delete-btn"
+ >
+
+ {t('crowdsecConfig.whitelist.delete', 'Delete')}
+
+
+
+ ))}
+
+
+
+ )}
+
+