415 lines
13 KiB
JavaScript
415 lines
13 KiB
JavaScript
import './connection.js';
|
||
|
||
// 1) Initial aus Redis laden, damit Toasts auch nach Redirect sichtbar sind
|
||
// async function bootstrapToasts() {
|
||
// try {
|
||
// const res = await fetch('/api/tasks/active', {
|
||
// credentials: 'same-origin',
|
||
// headers: {
|
||
// 'Accept': 'application/json',
|
||
// 'X-Requested-With': 'XMLHttpRequest',
|
||
// },
|
||
// });
|
||
//
|
||
// // Klarer Fehlerfall statt blind json() zu rufen
|
||
// const ct = res.headers.get('content-type') || '';
|
||
// if (!res.ok) {
|
||
// const text = await res.text();
|
||
// throw new Error(`HTTP ${res.status}: ${text.slice(0, 300)}`);
|
||
// }
|
||
// if (!ct.includes('application/json')) {
|
||
// const text = await res.text();
|
||
// console.warn('Initial toast fetch: non-JSON response', text.substring(0, 300));
|
||
// return;
|
||
// }
|
||
//
|
||
// const json = await res.json();
|
||
// (json.items || []).forEach(renderOrUpdateToast);
|
||
// } catch (e) {
|
||
// console.warn('Initial toast fetch failed', e);
|
||
// }
|
||
// }
|
||
//
|
||
// bootstrapToasts();
|
||
// 2) Live via WebSocket
|
||
|
||
// function renderOrUpdateToast(snap) {
|
||
// const {
|
||
// id,
|
||
// type = 'issue-cert',
|
||
// status = 'queued', // queued|running|done|failed
|
||
// message = '',
|
||
// payload = {},
|
||
// } = snap || {};
|
||
//
|
||
// const pos = 'bottom-right';
|
||
// const badge = (type === 'issue-cert') ? 'Zertifikat' : type;
|
||
// const domain = payload?.domain ?? '';
|
||
//
|
||
// // Dauer: done/failed => 6s, sonst offen
|
||
// const duration = (status === 'done' || status === 'failed') ? 6000 : -1;
|
||
//
|
||
// // deine Glas-UI
|
||
// toastraGlass.show({
|
||
// id, // wichtig, damit spätere Updates denselben Toast treffen
|
||
// state: status,
|
||
// badge,
|
||
// domain,
|
||
// message,
|
||
// position: pos,
|
||
// duration
|
||
// });
|
||
// }
|
||
//
|
||
// async function bootstrapToasts() {
|
||
// try {
|
||
// const res = await fetch('/ui/tasks/active', {
|
||
// credentials: 'same-origin',
|
||
// headers: { 'Accept': 'application/json' }
|
||
// });
|
||
//
|
||
// if (!res.ok) {
|
||
// console.warn('Initial toast fetch HTTP', res.status);
|
||
// return;
|
||
// }
|
||
//
|
||
// const ct = res.headers.get('content-type') || '';
|
||
// if (!ct.includes('application/json')) {
|
||
// console.warn('Initial toast fetch: unexpected content-type', ct);
|
||
// return;
|
||
// }
|
||
//
|
||
// const json = await res.json();
|
||
// (json.items || []).forEach(renderOrUpdateToast);
|
||
// } catch (e) {
|
||
// console.warn('Initial toast fetch failed', e);
|
||
// }
|
||
// }
|
||
// bootstrapToasts();
|
||
//
|
||
// Echo.channel('system.tasks')
|
||
// .listen('.task.updated', (e) => {
|
||
// // Optional: nur eigene User-Events zeigen
|
||
// // if (e.userId !== window.App?.user?.id) return;
|
||
//
|
||
// renderOrUpdateToast(e.payload);
|
||
// });
|
||
|
||
|
||
// const seen = new Map(); // id -> lastState
|
||
//
|
||
// async function bootstrapToasts() {
|
||
// try {
|
||
// const res = await fetch('/tasks/active', {
|
||
// credentials: 'same-origin',
|
||
// headers: { 'Accept': 'application/json' }, // <- erzwinge JSON
|
||
// });
|
||
// if (!res.ok) {
|
||
// const text = await res.text();
|
||
// console.warn('Initial toast fetch non-200:', res.status, text);
|
||
// return;
|
||
// }
|
||
// const { items = [] } = await res.json();
|
||
// items.forEach(renderOrUpdateToast);
|
||
// } catch (e) {
|
||
// console.warn('Initial toast fetch failed', e);
|
||
// }
|
||
// }
|
||
// bootstrapToasts();
|
||
//
|
||
// function getCsrf() {
|
||
// const m = document.head.querySelector('meta[name="csrf-token"]');
|
||
// return m ? m.content : '';
|
||
// }
|
||
//
|
||
// async function ack(id) {
|
||
// try {
|
||
// await fetch('/tasks/ack', {
|
||
// method: 'POST',
|
||
// credentials: 'same-origin',
|
||
// headers: {
|
||
// 'Content-Type': 'application/json',
|
||
// 'X-CSRF-TOKEN': getCsrf(), // <- wichtig bei POST
|
||
// 'Accept': 'application/json',
|
||
// },
|
||
// body: JSON.stringify({ id }),
|
||
// });
|
||
// } catch (_) {}
|
||
// }
|
||
// function renderOrUpdateToast(item) {
|
||
// const { id, state, badge, domain, message, progress = 0 } = item;
|
||
// const last = seen.get(id);
|
||
// if (last === state) return; // dedupe
|
||
//
|
||
// seen.set(id, state);
|
||
//
|
||
// // dein Glas-Toast
|
||
// toastraGlass.show({
|
||
// id,
|
||
// state, // queued|running|done|failed
|
||
// badge,
|
||
// domain,
|
||
// message,
|
||
// progress, // optional für Fortschrittsbalken
|
||
// position: 'bottom-right',
|
||
// duration: (state === 'done' || state === 'failed') ? 8000 : -1,
|
||
// onClose: () => ack(id), // Nutzer schließt → ebenfalls ack
|
||
// });
|
||
//
|
||
// // Terminalstatus → direkt ack senden (oder erst onClose, wie du magst)
|
||
// if (state === 'done' || state === 'failed') {
|
||
// ack(id);
|
||
// }
|
||
// }
|
||
//
|
||
//
|
||
// // WebSocket Live-Updates
|
||
// window.Echo.channel('system.tasks')
|
||
// .listen('.cert.status', (e) => {
|
||
// // e: { id, state, message, progress, ... }
|
||
// renderOrUpdateToast(e);
|
||
// });
|
||
|
||
// 3) Renderer (Toastra Glass Bridge)
|
||
// const known = new Map(); // taskId -> toastUiId
|
||
//
|
||
// function renderOrUpdateToast(payload) {
|
||
// const id = payload.id;
|
||
// const state = payload.state; // queued|running|done|failed
|
||
// const msg = payload.message || '';
|
||
//
|
||
// const opts = {
|
||
// id, // WICHTIG: stabile ID für replace
|
||
// state: state, // unser Toastra erwartet 'done'|'failed' um Auto-Close zu setzen
|
||
// badge: payload.badge ?? null,
|
||
// domain: payload.title ?? 'System',
|
||
// message: msg,
|
||
// position: payload.position ?? 'bottom-right',
|
||
// duration: (state === 'done' || state === 'failed') ? 6000 : 0, // läuft weiter bis Update
|
||
// };
|
||
//
|
||
// if (known.has(id)) {
|
||
// window.toastraGlass.update(known.get(id), opts);
|
||
// } else {
|
||
// const toastUiId = window.toastraGlass.show(opts);
|
||
// known.set(id, toastUiId);
|
||
// }
|
||
//
|
||
// // Optional: bei "done|failed" nach n Sekunden als "gesehen" acken
|
||
// if (state === 'done' || state === 'failed') {
|
||
// setTimeout(() => {
|
||
// fetch(`/api/tasks/${encodeURIComponent(id)}/ack`, { method: 'POST', credentials: 'same-origin' })
|
||
// .catch(()=>{});
|
||
// }, 7000);
|
||
// }
|
||
// }
|
||
|
||
|
||
|
||
// import Echo from 'laravel-echo'
|
||
// import Pusher from 'pusher-js'
|
||
// import {wsConfig} from './connector.js'
|
||
// import {initEvents} from "./events.js";
|
||
//
|
||
// window.Pusher = Pusher
|
||
//
|
||
// window.Pusher && (window.Pusher.logToConsole = true); // Debug an
|
||
//
|
||
// const host = wsConfig.host || window.location.hostname
|
||
// const port = Number(wsConfig.port) || 443 // <— port!
|
||
// const scheme = (wsConfig.scheme || 'https').toLowerCase()
|
||
// const path = wsConfig.path || '/ws'
|
||
// const tls = scheme === 'https' // <— boolean
|
||
// const key = wsConfig.key
|
||
//
|
||
// window.Echo = new Echo({
|
||
// broadcaster: 'reverb',
|
||
// key,
|
||
// wsHost: host,
|
||
// wsPort: port,
|
||
// wssPort: port,
|
||
// forceTLS: tls,
|
||
// enabledTransports: ['ws', 'wss'],
|
||
// wsPath: path,
|
||
// })
|
||
//
|
||
// window.Echo.channel('system.tasks')
|
||
// .listen('.cert.ping', (e) => {
|
||
// console.log('Task-Event:', e); // hier sollte die Nachricht aufschlagen
|
||
// });
|
||
|
||
|
||
// Echo.channel('system.tasks')
|
||
// .listen('.cert.ping', (e) => {
|
||
// console.log('Task-Event:', e); // hier sollte die Nachricht aufschlagen
|
||
// });
|
||
|
||
// Echo.channel('system.tasks')
|
||
// .listen('.cert.status', (e) => {
|
||
// // Mappe Status zu deiner Toast-API
|
||
// const stateToTitle = {
|
||
// queued: 'Wartet…',
|
||
// running: 'Erstellt…',
|
||
// done: 'Fertig',
|
||
// failed: 'Fehlgeschlagen',
|
||
// };
|
||
//
|
||
// // Dauer: während queued/running immer sichtbar (−1), bei final 5s
|
||
// const duration = (e.state === 'done' || e.state === 'failed') ? 5000 : -1;
|
||
//
|
||
// // Optional: Fortschrittsbalken kannst du selbst in toastraGlass implementieren
|
||
// window.toastraGlass?.show({
|
||
// state: e.state, // queued|running|done|failed
|
||
// badge: 'Zertifikat',
|
||
// domain: e.key.replace('issue-cert:',''),
|
||
// message: e.message,
|
||
// position: 'bottom-right',
|
||
// duration,
|
||
// progress: e.progress ?? 0,
|
||
// });
|
||
// });
|
||
|
||
|
||
// const seen = new Map(); // id -> lastState
|
||
//
|
||
// function renderOrUpdateToast(o) {
|
||
// // Toastra expects: {state,badge,domain,message,progress,position,id,duration}
|
||
// const pos = o.pos || 'bottom-right';
|
||
// const id = o.id;
|
||
//
|
||
// // Dedupe / Update
|
||
// const last = seen.get(id);
|
||
// const key = `${o.status}|${o.progress}|${o.message}`;
|
||
// if (last === key) return;
|
||
//
|
||
// seen.set(id, key);
|
||
//
|
||
// // Zeichnen / Aktualisieren
|
||
// window.toastraGlass.show({
|
||
// state: mapState(o.status), // queued|running|done|failed
|
||
// badge: o.title || 'ZERTIFIKAT',
|
||
// domain: o.payload?.domain || o.domain || '',
|
||
// message: o.message || '',
|
||
// progress: Number(o.progress ?? 0),
|
||
// position: pos,
|
||
// id,
|
||
// duration: (o.status === 'done' || o.status === 'failed') ? 4000 : -1,
|
||
// });
|
||
//
|
||
// // Bei done/failed sofort aus dem Local-Cache entfernen
|
||
// if (o.status === 'done' || o.status === 'failed') {
|
||
// setTimeout(() => {
|
||
// seen.delete(id);
|
||
// }, 4500);
|
||
// }
|
||
// }
|
||
//
|
||
// function mapState(s) {
|
||
// if (s === 'queued') return 'queued';
|
||
// if (s === 'running') return 'running';
|
||
// if (s === 'done') return 'done';
|
||
// if (s === 'failed') return 'failed';
|
||
// return 'info';
|
||
// }
|
||
//
|
||
// // 1) Initiale Tasks laden – **neue** Route mit web+auth!
|
||
// async function bootstrapToasts() {
|
||
// try {
|
||
// const res = await fetch('/ui/tasks/active', {
|
||
// credentials: 'same-origin',
|
||
// headers: { 'X-Requested-With': 'XMLHttpRequest', 'Accept': 'application/json' },
|
||
// });
|
||
// if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
||
// const { items = [] } = await res.json();
|
||
// items.forEach(renderOrUpdateToast);
|
||
// } catch (e) {
|
||
// console.warn('Initial toast fetch failed', e);
|
||
// }
|
||
// }
|
||
// bootstrapToasts();
|
||
//
|
||
// // 2) Echtzeit-Updates
|
||
// window.Echo.channel('system.tasks')
|
||
// .listen('.cert.status', (e) => {
|
||
// // e: { id,status,message,progress,domain,mode }
|
||
// renderOrUpdateToast({
|
||
// id: e.id,
|
||
// status: e.status,
|
||
// message: e.message,
|
||
// progress: e.progress,
|
||
// title: (e.mode || 'ZERTIFIKAT').toUpperCase(),
|
||
// domain: e.domain,
|
||
// });
|
||
// });
|
||
|
||
const seen = new Map(); // id -> lastState
|
||
|
||
function labelForState(state) {
|
||
switch ((state || '').toLowerCase()) {
|
||
case 'queued': return 'Wartet…';
|
||
case 'running': return 'Läuft…';
|
||
case 'done': return 'Erledigt';
|
||
case 'failed': return 'Fehlgeschlagen';
|
||
default: return state || 'Unbekannt';
|
||
}
|
||
}
|
||
|
||
function renderOrUpdateToast(ev) {
|
||
const id = ev.id;
|
||
const state = (ev.state || '').toLowerCase();
|
||
const text = ev.message || '';
|
||
const prog = typeof ev.progress === 'number' ? ev.progress : null;
|
||
|
||
// Duplikate vermeiden: nur reagieren, wenn sich der State geändert hat
|
||
const last = seen.get(id);
|
||
if (last === state) return;
|
||
seen.set(id, state);
|
||
|
||
// Dein Toastra:
|
||
window.toastraGlass?.show({
|
||
id,
|
||
state, // queued|running|done|failed (wichtig!)
|
||
badge: 'ZERTIFIKAT',
|
||
domain: text, // Sub-Headline
|
||
message: text, // Main-Text
|
||
progress: prog, // 0..100 (optional)
|
||
position: 'bottom-right',
|
||
duration: (state === 'done' || state === 'failed') ? 5000 : -1,
|
||
// falls dein Renderer eine Status-Beschriftung braucht:
|
||
statusLabel: labelForState(state),
|
||
});
|
||
|
||
// Final? -> nach kurzer Zeit ausblenden (UI)
|
||
if (ev.meta && ev.meta.final) {
|
||
setTimeout(() => {
|
||
window.toastraGlass?.removeById?.(id);
|
||
// Alternativ (wenn removeById fehlt):
|
||
// document.querySelectorAll(`[data-toast-id="${CSS.escape(id)}"]`).forEach(n => n.remove());
|
||
seen.delete(id);
|
||
}, 5200);
|
||
}
|
||
}
|
||
|
||
// Initiale Tasks aus dem Backend laden (damit Redirect-Toasts sichtbar bleiben)
|
||
async function bootstrapToasts() {
|
||
try {
|
||
const res = await fetch('/ui/tasks/active', {
|
||
credentials: 'same-origin',
|
||
headers: { 'X-Requested-With': 'XMLHttpRequest', 'Accept': 'application/json' },
|
||
});
|
||
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
||
const data = await res.json();
|
||
(data.items || []).forEach(renderOrUpdateToast);
|
||
} catch (e) {
|
||
console.warn('Initial toast fetch failed', e);
|
||
}
|
||
}
|
||
bootstrapToasts();
|
||
|
||
// WebSocket-Listener
|
||
window.Echo
|
||
.channel('system.tasks')
|
||
.listen('.cert.status', (payload) => {
|
||
renderOrUpdateToast(payload);
|
||
});
|