cms.c2sgmbh/src/components/admin/TestEmailButton.scss
Martin Porwoll 53f26e7349 feat: admin UX improvements with tenant switcher and email config
Tenant-Wechsel UI:
- Add TenantBreadcrumb component showing active tenant in admin header
- Add German translations for multi-tenant plugin selector
- Integrate with existing plugin TenantSelector dropdown

Email-Konfiguration UX:
- Add SMTP field validation (host format, port range, required fields)
- Add EmailDeliverabilityInfo component with SPF/DKIM/DMARC guidance
- Add TestEmailButton component for SMTP configuration testing
- Create /api/test-email endpoint with full security:
  - CSRF protection (double-submit cookie)
  - IP allowlist (same rules as /api/send-email)
  - Rate limiting (10/min per user)
  - Tenant access control with proper object normalization

Security:
- Add comprehensive integration tests for /api/test-email
- Tests cover CSRF, IP blocking, auth, tenant access, input validation

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-08 16:33:39 +00:00

173 lines
3.4 KiB
SCSS

.test-email-button {
margin: 1.5rem 0 0.5rem 0;
padding: 1rem;
border: 1px solid var(--theme-elevation-150);
border-radius: var(--style-radius-s, 4px);
background-color: var(--theme-elevation-50);
&__header {
margin-bottom: 1rem;
}
&__title {
margin: 0 0 0.25rem 0;
font-size: 0.875rem;
font-weight: 600;
color: var(--theme-elevation-800);
}
&__description {
margin: 0;
font-size: 0.8125rem;
color: var(--theme-elevation-500);
}
&__form {
display: flex;
gap: 0.75rem;
align-items: flex-end;
}
&__input-group {
flex: 1;
display: flex;
flex-direction: column;
gap: 0.25rem;
}
&__label {
font-size: 0.75rem;
font-weight: 500;
color: var(--theme-elevation-600);
}
&__input {
padding: 0.5rem 0.75rem;
border: 1px solid var(--theme-elevation-200);
border-radius: var(--style-radius-s, 4px);
font-size: 0.875rem;
background-color: var(--theme-input-background);
color: var(--theme-elevation-800);
transition: border-color 0.15s ease;
&:focus {
outline: none;
border-color: var(--theme-success-500);
}
&:disabled {
opacity: 0.6;
cursor: not-allowed;
}
&::placeholder {
color: var(--theme-elevation-400);
}
}
&__button {
display: inline-flex;
align-items: center;
gap: 0.5rem;
padding: 0.5rem 1rem;
border: none;
border-radius: var(--style-radius-s, 4px);
font-size: 0.875rem;
font-weight: 500;
cursor: pointer;
transition: all 0.15s ease;
white-space: nowrap;
background-color: var(--theme-success-500);
color: white;
&:hover:not(:disabled) {
background-color: var(--theme-success-600);
}
&:disabled {
opacity: 0.6;
cursor: not-allowed;
}
&--loading {
background-color: var(--theme-elevation-400);
}
}
&__icon {
flex-shrink: 0;
}
&__spinner {
width: 16px;
height: 16px;
border: 2px solid transparent;
border-top-color: currentColor;
border-radius: 50%;
animation: test-email-spin 0.8s linear infinite;
}
&__result {
display: flex;
align-items: flex-start;
gap: 0.5rem;
margin-top: 1rem;
padding: 0.75rem;
border-radius: var(--style-radius-s, 4px);
font-size: 0.8125rem;
&--success {
background-color: rgba(var(--theme-success-500-rgb), 0.1);
border: 1px solid var(--theme-success-500);
color: var(--theme-success-600);
}
&--error {
background-color: rgba(var(--theme-error-500-rgb), 0.1);
border: 1px solid var(--theme-error-500);
color: var(--theme-error-600);
}
}
&__result-icon {
flex-shrink: 0;
margin-top: 0.125rem;
}
&__result-message {
display: flex;
flex-direction: column;
gap: 0.25rem;
}
&__result-id {
font-size: 0.75rem;
opacity: 0.8;
font-family: var(--font-mono);
}
&__warning {
margin: 0.75rem 0 0 0;
padding: 0.5rem 0.75rem;
font-size: 0.8125rem;
color: var(--theme-warning-600);
background-color: rgba(var(--theme-warning-500-rgb), 0.1);
border-radius: var(--style-radius-s, 4px);
}
}
@keyframes test-email-spin {
to {
transform: rotate(360deg);
}
}
// Dark mode support
:global(.dark) .test-email-button {
background-color: var(--theme-elevation-100);
border-color: var(--theme-elevation-200);
&__input {
border-color: var(--theme-elevation-250);
}
}