feat: Toastra-Plugin eingebunden + DKIM-Regenerierung fix
- Toastra als Toast-System integriert (ersetzt GlassToastra) - CSS auf var(--mw-*) Dark-Theme angepasst, keine Klassen entfernt - Livewire-Adapter mappt done/warn/error/info auf Toastra-Typen - DnsDkim: doppelter sudo-install-dkim entfernt (DkimService macht es bereits) - dkimReady() prüft Storage-Pfad statt sudo-Test (kein Sudoers-Eintrag nötig) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>main v1.1.376
parent
f375ea0215
commit
486166c05a
|
|
@ -4,7 +4,6 @@ namespace App\Livewire\Ui\Nx\Domain;
|
||||||
|
|
||||||
use App\Models\Domain;
|
use App\Models\Domain;
|
||||||
use App\Services\DkimService;
|
use App\Services\DkimService;
|
||||||
use Illuminate\Support\Facades\Process;
|
|
||||||
use Livewire\Attributes\Layout;
|
use Livewire\Attributes\Layout;
|
||||||
use Livewire\Attributes\On;
|
use Livewire\Attributes\On;
|
||||||
use Livewire\Attributes\Title;
|
use Livewire\Attributes\Title;
|
||||||
|
|
@ -44,22 +43,7 @@ class DnsDkim extends Component
|
||||||
try {
|
try {
|
||||||
/** @var DkimService $svc */
|
/** @var DkimService $svc */
|
||||||
$svc = app(DkimService::class);
|
$svc = app(DkimService::class);
|
||||||
$res = $svc->generateForDomain($domain, 2048, $selector);
|
$svc->generateForDomain($domain, 2048, $selector);
|
||||||
$priv = $res['priv_path'] ?? storage_path("app/private/dkim/{$domain->domain}/{$selector}.private");
|
|
||||||
$txt = storage_path("app/private/dkim/{$domain->domain}/{$selector}.txt");
|
|
||||||
|
|
||||||
if (!is_readable($txt) && !empty($res['dns_txt'])) {
|
|
||||||
file_put_contents($txt, $res['dns_txt']);
|
|
||||||
}
|
|
||||||
|
|
||||||
$proc = Process::run(['sudo', '-n', '/usr/local/sbin/mailwolt-install-dkim',
|
|
||||||
$domain->domain, $selector, $priv, $txt]);
|
|
||||||
|
|
||||||
if (!$proc->successful()) {
|
|
||||||
throw new \RuntimeException($proc->errorOutput());
|
|
||||||
}
|
|
||||||
|
|
||||||
Process::run(['sudo', '-n', '/usr/bin/systemctl', 'reload', 'opendkim']);
|
|
||||||
|
|
||||||
$this->dispatch('toast', type: 'done', badge: 'DKIM',
|
$this->dispatch('toast', type: 'done', badge: 'DKIM',
|
||||||
title: 'DKIM erneuert', text: "Schlüssel für <b>{$domain->domain}</b> wurde neu generiert.", duration: 5000);
|
title: 'DKIM erneuert', text: "Schlüssel für <b>{$domain->domain}</b> wurde neu generiert.", duration: 5000);
|
||||||
|
|
@ -71,8 +55,8 @@ class DnsDkim extends Component
|
||||||
|
|
||||||
private function dkimReady(string $domain, string $selector): bool
|
private function dkimReady(string $domain, string $selector): bool
|
||||||
{
|
{
|
||||||
return Process::run(['sudo', '-n', '/usr/bin/test', '-s',
|
$path = storage_path("app/private/dkim/{$domain}/{$selector}.private");
|
||||||
"/etc/opendkim/keys/{$domain}/{$selector}.private"])->successful();
|
return is_file($path) && filesize($path) > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function render()
|
public function render()
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
@import 'tailwindcss';
|
@import 'tailwindcss';
|
||||||
@import '../js/plugins/GlassToastra/style.css';
|
@import '../js/plugins/Toastra/src/message.css';
|
||||||
|
|
||||||
@import "../fonts/BaiJamjuree/font.css";
|
@import "../fonts/BaiJamjuree/font.css";
|
||||||
@import "../fonts/Space/font.css";
|
@import "../fonts/Space/font.css";
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ import "@phosphor-icons/web/regular";
|
||||||
import "@phosphor-icons/web/bold";
|
import "@phosphor-icons/web/bold";
|
||||||
import './components/sidebar.js';
|
import './components/sidebar.js';
|
||||||
|
|
||||||
import './plugins/GlassToastra/toastra.glass.js'
|
import './plugins/Toastra/index.js';
|
||||||
import './plugins/GlassToastra/livewire-adapter';
|
import './plugins/Toastra/livewire-adapter';
|
||||||
|
|
||||||
import './utils/events.js';
|
import './utils/events.js';
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,35 @@
|
||||||
|
// Maps Livewire `toast` events → window.toastra.notify()
|
||||||
|
const TYPE_MAP = {
|
||||||
|
done: 'success',
|
||||||
|
warn: 'warning',
|
||||||
|
warning: 'warning',
|
||||||
|
error: 'error',
|
||||||
|
info: 'info',
|
||||||
|
default: 'default',
|
||||||
|
update: 'update',
|
||||||
|
};
|
||||||
|
|
||||||
|
function dispatchToast(detail) {
|
||||||
|
if (!window.toastra) return;
|
||||||
|
|
||||||
|
const { type = 'info', badge, title, text, duration } = detail || {};
|
||||||
|
|
||||||
|
window.toastra.notify({
|
||||||
|
type: TYPE_MAP[type] ?? 'info',
|
||||||
|
badge: badge ?? '',
|
||||||
|
title: title ?? '',
|
||||||
|
text: text ?? '',
|
||||||
|
duration: duration !== undefined ? duration : 4000,
|
||||||
|
close: true,
|
||||||
|
progressbar: true,
|
||||||
|
icon: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
document.addEventListener('livewire:init', () => {
|
||||||
|
window.addEventListener('toast', (e) => dispatchToast(e?.detail || {}));
|
||||||
|
window.addEventListener('toast.clear', () => { /* Toastra hat kein clear-API */ });
|
||||||
|
window.addEventListener('toast.reload',(e) => setTimeout(() => window.location.reload(), e?.detail?.delay || 0));
|
||||||
|
});
|
||||||
|
|
||||||
|
window.showToast = dispatchToast;
|
||||||
|
|
@ -603,13 +603,13 @@
|
||||||
/* background: linear-gradient(180deg, var(--accent), rgba(var(--toast-red), .6));*/
|
/* background: linear-gradient(180deg, var(--accent), rgba(var(--toast-red), .6));*/
|
||||||
/* border-radius: 3px 0 0 3px;*/
|
/* border-radius: 3px 0 0 3px;*/
|
||||||
/*}*/
|
/*}*/
|
||||||
/* ===== Toast · Glass v2 (Badge) ===== */
|
/* ===== Toast · Glass v2 – mw dark theme ===== */
|
||||||
.notification.glass-mode .notification-container {
|
.notification.glass-mode .notification-container {
|
||||||
backdrop-filter: blur(14px);
|
backdrop-filter: blur(14px);
|
||||||
background: rgba(17, 24, 39, .52); /* dunkleres Glas */
|
background: color-mix(in srgb, var(--mw-bg3, #111420) 88%, transparent);
|
||||||
border: 1px solid rgba(255,255,255,.09);
|
border: 1px solid var(--mw-b1, #1c2035);
|
||||||
border-radius: 16px;
|
border-radius: 16px;
|
||||||
box-shadow: 0 12px 40px rgba(0,0,0,.28);
|
box-shadow: 0 12px 40px rgba(0,0,0,.40);
|
||||||
}
|
}
|
||||||
|
|
||||||
.notification.glass-mode .notification-block {
|
.notification.glass-mode .notification-block {
|
||||||
|
|
@ -634,10 +634,10 @@
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 10px;
|
gap: 10px;
|
||||||
padding-right: 36px; /* Platz für Close */
|
padding-right: 36px;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
letter-spacing: .2px;
|
letter-spacing: .2px;
|
||||||
color: #e5e7eb; /* text-gray-200 */
|
color: var(--mw-t1, #edf0fc);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Badge aus data-badge rendern */
|
/* Badge aus data-badge rendern */
|
||||||
|
|
@ -648,17 +648,17 @@
|
||||||
letter-spacing: .6px;
|
letter-spacing: .6px;
|
||||||
padding: 4px 8px;
|
padding: 4px 8px;
|
||||||
border-radius: 9px;
|
border-radius: 9px;
|
||||||
border: 1px solid rgba(255,255,255,.10);
|
border: 1px solid var(--mw-b2, #242840);
|
||||||
background: rgba(31,41,55,.55); /* dunkles Glas */
|
background: var(--mw-bg4, #161a28);
|
||||||
color: #cbd5e1; /* text-gray-300 */
|
color: var(--mw-t3, #737b96);
|
||||||
box-shadow: inset 0 1px 0 rgba(255,255,255,.08);
|
box-shadow: inset 0 1px 0 rgba(255,255,255,.06);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Subtext */
|
/* Subtext */
|
||||||
.notification.glass-mode .notification-message {
|
.notification.glass-mode .notification-message {
|
||||||
margin-top: 6px;
|
margin-top: 6px;
|
||||||
line-height: 1.35;
|
line-height: 1.35;
|
||||||
color: #cbd5e1; /* text-gray-300 */
|
color: var(--mw-t2, #9aa3be);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Close-Button dezenter */
|
/* Close-Button dezenter */
|
||||||
|
|
@ -666,12 +666,12 @@
|
||||||
top: 10px; right: 10px;
|
top: 10px; right: 10px;
|
||||||
width: 30px; height: 30px;
|
width: 30px; height: 30px;
|
||||||
display: grid; place-items: center;
|
display: grid; place-items: center;
|
||||||
background: rgba(255,255,255,.06);
|
background: var(--mw-bg4, #161a28);
|
||||||
border: 1px solid rgba(255,255,255,.10);
|
border: 1px solid var(--mw-b2, #242840);
|
||||||
box-shadow: 0 6px 20px rgba(0,0,0,.25);
|
box-shadow: 0 4px 12px rgba(0,0,0,.30);
|
||||||
}
|
}
|
||||||
.notification.glass-mode .notification-dismiss-btn:hover {
|
.notification.glass-mode .notification-dismiss-btn:hover {
|
||||||
background: rgba(255,255,255,.12);
|
background: var(--mw-b1, #1c2035);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Progressbar dünn & soft */
|
/* Progressbar dünn & soft */
|
||||||
|
|
@ -747,15 +747,15 @@
|
||||||
letter-spacing: .6px;
|
letter-spacing: .6px;
|
||||||
padding: 4px 8px;
|
padding: 4px 8px;
|
||||||
border-radius: 9px;
|
border-radius: 9px;
|
||||||
border: 1px solid rgba(255,255,255,.10);
|
border: 1px solid var(--mw-b2, #242840);
|
||||||
background: rgba(31,41,55,.55);
|
background: var(--mw-bg4, #161a28);
|
||||||
color: #cbd5e1; /* gray-300 */
|
color: var(--mw-t3, #737b96);
|
||||||
box-shadow: inset 0 1px 0 rgba(255,255,255,.08);
|
box-shadow: inset 0 1px 0 rgba(255,255,255,.06);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* keep your bold style on the title text itself */
|
/* keep your bold style on the title text itself */
|
||||||
.notification-title-text b {
|
.notification-title-text b {
|
||||||
color: #e5e7eb; /* gray-200 */
|
color: var(--mw-t1, #edf0fc);
|
||||||
font-weight: 800;
|
font-weight: 800;
|
||||||
letter-spacing: .3px;
|
letter-spacing: .3px;
|
||||||
}
|
}
|
||||||
|
|
@ -764,14 +764,7 @@
|
||||||
.notification-subtitle {
|
.notification-subtitle {
|
||||||
margin-top: .25rem;
|
margin-top: .25rem;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
color: #e5e7eb; /* gray-200 */
|
color: var(--mw-t1, #edf0fc);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Glass container (you already had this, listing again for completeness) */
|
/* Glass container duplicate removed – see above */
|
||||||
.notification.glass-mode .notification-container {
|
|
||||||
backdrop-filter: blur(10px);
|
|
||||||
background: rgba(31,41,55,.45);
|
|
||||||
border: 1px solid rgba(255,255,255,.08);
|
|
||||||
border-radius: 14px;
|
|
||||||
box-shadow: 0 8px 30px rgba(0,0,0,.25);
|
|
||||||
}
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue