fix: AJAX-URL dynamisch aus Script-Pfad ermitteln
urlRoot wird einmalig aus dem src-Attribut des globalnotify-Scripts abgeleitet, damit AJAX-Calls unabhängig vom Installationspfad funktionieren (z.B. /dolibarr/custom/... statt /custom/...). Behebt 404-Fehler bei Aktionen wie "Alle als gelesen markieren". Zusätzlich CLAUDE.md Projektdokumentation erstellt. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
b4a6f534ba
commit
e67b094466
2 changed files with 133 additions and 1 deletions
124
CLAUDE.md
Normal file
124
CLAUDE.md
Normal file
|
|
@ -0,0 +1,124 @@
|
|||
# GlobalNotify - Dolibarr Custom Module
|
||||
|
||||
Globales Benachrichtigungssystem als schwebendes Widget (FAB) in der unteren linken Ecke.
|
||||
Sammelt Alerts von allen Modulen (Cron-Fehler, Warnungen, Aktionen) und zeigt sie einheitlich an.
|
||||
|
||||
## Modul-Metadaten
|
||||
|
||||
- **Modul-Nummer**: 500100
|
||||
- **Version**: 1.4.0
|
||||
- **Autor**: Eduard Wisch / Data IT Solution
|
||||
- **Hooks**: `main`, `toprightmenu`
|
||||
- **Nur für Admins** (`$user->admin`)
|
||||
|
||||
## Projektstruktur
|
||||
|
||||
```
|
||||
globalnotify/
|
||||
admin/setup.php # Admin-Seite: Einstellungen + Übersicht
|
||||
ajax/action.php # AJAX-Endpunkt für JS-Aktionen
|
||||
class/
|
||||
globalnotify.class.php # Kern-Klasse: Notification CRUD
|
||||
actions_globalnotify.class.php # Hook-Klasse: Widget-Rendering + Cron-Checks
|
||||
core/modules/modGlobalNotify.class.php # Modul-Deskriptor
|
||||
css/globalnotify.css # Widget-Styles (Dark Mode Support)
|
||||
js/globalnotify.js # Widget-Logik (Drag, AJAX, Sound)
|
||||
langs/de_DE/globalnotify.lang # Deutsche Übersetzungen
|
||||
langs/en_US/globalnotify.lang # Englische Übersetzungen
|
||||
```
|
||||
|
||||
## Architektur
|
||||
|
||||
### Speicherung
|
||||
Notifications werden als JSON-Arrays in `llx_const` gespeichert (NICHT in eigenen Tabellen):
|
||||
- Schlüssel: `GLOBALNOTIFY_{MODULE}` (z.B. `GLOBALNOTIFY_CRON`, `GLOBALNOTIFY_BANKIMPORT`)
|
||||
- Wert: JSON-Array mit Notification-Objekten
|
||||
- Max 50 Notifications pro Modul
|
||||
- Interne Settings: `GLOBALNOTIFY_CRON_LASTCHECK`, `GLOBALNOTIFY_CRON_CHECK_INTERVAL`
|
||||
|
||||
### Notification-Typen (Konstanten in GlobalNotify)
|
||||
- `TYPE_ERROR` = `'error'` — Priorität 10
|
||||
- `TYPE_ACTION` = `'action'` — Priorität 9
|
||||
- `TYPE_WARNING` = `'warning'` — Priorität 7
|
||||
- `TYPE_INFO` = `'info'` — Priorität 3
|
||||
- `TYPE_SUCCESS` = `'success'`
|
||||
|
||||
### Notification-Objekt (JSON-Struktur)
|
||||
```json
|
||||
{
|
||||
"id": "module_uniqid",
|
||||
"module": "cron",
|
||||
"type": "error",
|
||||
"title": "Kurztitel",
|
||||
"message": "Detailbeschreibung",
|
||||
"action_url": "/cron/list.php",
|
||||
"action_label": "Button-Text",
|
||||
"priority": 10,
|
||||
"user_id": 0,
|
||||
"created": 1709000000,
|
||||
"read": false
|
||||
}
|
||||
```
|
||||
|
||||
## API: Notifications senden (für andere Module)
|
||||
|
||||
```php
|
||||
// Statische Helper (empfohlen):
|
||||
dol_include_once('/globalnotify/class/globalnotify.class.php');
|
||||
GlobalNotify::error('meinmodul', 'Titel', 'Nachricht', $actionUrl, $actionLabel);
|
||||
GlobalNotify::warning('meinmodul', 'Titel', 'Nachricht');
|
||||
GlobalNotify::info('meinmodul', 'Titel', 'Nachricht');
|
||||
GlobalNotify::actionRequired('meinmodul', 'Titel', 'Nachricht', $actionUrl);
|
||||
|
||||
// Oder manuell mit voller Kontrolle:
|
||||
$notify = new GlobalNotify($db);
|
||||
$notify->addNotification($module, $type, $title, $message, $actionUrl, $actionLabel, $priority, $userId);
|
||||
```
|
||||
|
||||
## AJAX-Endpunkt (`ajax/action.php`)
|
||||
|
||||
POST-Requests mit `action` Parameter:
|
||||
- `dismiss` — Einzelne Notification als gelesen markieren (`id` Parameter)
|
||||
- `delete` — Notification löschen (`id` Parameter)
|
||||
- `markallread` — Alle als gelesen markieren
|
||||
- `getall` — Alle ungelesenen abrufen
|
||||
- `getcount` — Ungelesene Anzahl abrufen
|
||||
|
||||
Authentifizierung: Nur `$user->admin`, CSRF-Token über `TOKEN` JS-Variable.
|
||||
|
||||
## JavaScript (globalnotify.js)
|
||||
|
||||
- **`GlobalNotify.urlRoot`**: Wird beim Laden einmalig aus dem Script-src-Pfad ermittelt (z.B. `/dolibarr`), damit AJAX-Calls unabhängig vom Installationspfad funktionieren
|
||||
- **Drag & Drop**: FAB ist verschiebbar, Position wird in `localStorage` gespeichert
|
||||
- **Click vs. Drag**: Erkennung über Distanz (<5px) und Zeit (<200ms)
|
||||
- **Auto-Refresh**: Alle 2 Minuten via `getcount` AJAX-Call
|
||||
- **Sound**: Web Audio API Doppel-Ton bei neuen Notifications
|
||||
- **Animationen**: Shake + Bounce bei neuen Notifications
|
||||
|
||||
## Automatische Cron-Prüfungen (in Hook-Klasse)
|
||||
|
||||
1. **Hängende Jobs**: `processing=1` seit >30 Min → `TYPE_ERROR`
|
||||
2. **Verpasste Jobs**: `datenextrun` >2 Std. in der Vergangenheit → `TYPE_WARNING`
|
||||
3. **Cleanup**: Notifications für deaktivierte Cronjobs werden automatisch als gelesen markiert
|
||||
4. **Cache**: Prüfintervall konfigurierbar via `GLOBALNOTIFY_CRON_CHECK_INTERVAL` (Default: 60s, Min: 10s, Max: 3600s)
|
||||
|
||||
## Modul-spezifische Checks
|
||||
|
||||
- **BankImport**: Prüft `BankImportCron::getCronStatus()` auf `paused`, `tan_required`, `login_error`, `fetch_error`, `session_expired`
|
||||
- **ImportZugferd**: Prüft auf hängende `ImportZugferdScheduled` Cronjobs
|
||||
|
||||
## Admin-Seite (`admin/setup.php`)
|
||||
|
||||
- Einstellung: Cron-Prüfintervall
|
||||
- Aktion: Alle Benachrichtigungen löschen (löscht alle `GLOBALNOTIFY_*` Konstanten)
|
||||
- Aktion: Hängende Cron-Jobs zurücksetzen (`processing=0`)
|
||||
- Tabelle: Cron-Job Übersicht mit Status
|
||||
- Tabelle: Alle Benachrichtigungen mit Typ, Modul, Datum, Gelesen-Status
|
||||
|
||||
## Wichtige Konventionen
|
||||
|
||||
- Duplikat-Erkennung: Vor dem Erstellen wird geprüft, ob eine gleichartige ungelesene Notification existiert
|
||||
- Prioritäts-Sortierung: Höchste Priorität + neuestes Datum zuerst
|
||||
- `user_id=0` bedeutet: sichtbar für alle Admins
|
||||
- Dark Mode wird via `prefers-color-scheme: dark` CSS Media Query unterstützt
|
||||
- Keine eigenen DB-Tabellen, alles über `llx_const`
|
||||
|
|
@ -7,6 +7,14 @@ var GlobalNotify = {
|
|||
isOpen: false,
|
||||
isDragging: false,
|
||||
dragOffset: { x: 0, y: 0 },
|
||||
urlRoot: (function() {
|
||||
var scripts = document.querySelectorAll('script[src*="globalnotify"]');
|
||||
if (scripts.length > 0) {
|
||||
var match = scripts[0].getAttribute('src').match(/^(.*?)\/custom\/globalnotify\//);
|
||||
if (match) return match[1];
|
||||
}
|
||||
return '';
|
||||
})(),
|
||||
|
||||
/**
|
||||
* Toggle panel visibility
|
||||
|
|
@ -208,7 +216,7 @@ var GlobalNotify = {
|
|||
* AJAX helper
|
||||
*/
|
||||
ajaxCall: function(action, params, callback) {
|
||||
var url = (typeof DOL_URL_ROOT !== 'undefined' ? DOL_URL_ROOT : '') + '/custom/globalnotify/ajax/action.php';
|
||||
var url = this.urlRoot + '/custom/globalnotify/ajax/action.php';
|
||||
var body = 'action=' + encodeURIComponent(action);
|
||||
|
||||
for (var key in params) {
|
||||
|
|
|
|||
Loading…
Reference in a new issue