fix: quick deploy duplicate detection, logout UX, backup toggle, CSP, SSE guard, and migration
- Detect existing projects with same image on quick deploy; show conflict dialog with options - Move logout button to sidebar header as icon-only - Replace backup checkbox with ToggleSwitch component - Allow unsafe-inline in CSP script-src for SvelteKit hydration - Guard SSE connection behind isAuthenticated() check - Add notification_url ALTER TABLE migration for existing databases - Restore RegisterPersistentLogger on event bus
This commit is contained in:
@@ -2,6 +2,7 @@ package events
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"log/slog"
|
||||
"sync"
|
||||
)
|
||||
|
||||
@@ -124,6 +125,58 @@ func (b *Bus) Publish(evt Event) {
|
||||
}
|
||||
}
|
||||
|
||||
// PersistFunc is a callback that persists an event log entry.
|
||||
// It receives source, severity, message, and metadata (JSON string).
|
||||
// It returns the persisted entry's ID and created_at timestamp.
|
||||
type PersistFunc func(source, severity, message, metadata string) (int64, string, error)
|
||||
|
||||
// RegisterPersistentLogger subscribes to the bus and auto-persists warn/error
|
||||
// events by calling the provided persist function. It also re-publishes the
|
||||
// persisted event as an EventLog so SSE clients receive it in real-time.
|
||||
// Call the returned function to unsubscribe.
|
||||
func (b *Bus) RegisterPersistentLogger(persist PersistFunc) func() {
|
||||
sub := b.Subscribe(func(evt Event) bool {
|
||||
if evt.Type != EventDeployLog {
|
||||
return false
|
||||
}
|
||||
p, ok := evt.Payload.(DeployLogPayload)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
return p.Level == "warn" || p.Level == "error"
|
||||
})
|
||||
|
||||
go func() {
|
||||
for evt := range sub {
|
||||
p, ok := evt.Payload.(DeployLogPayload)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
metaBytes, _ := json.Marshal(map[string]string{"deploy_id": p.DeployID})
|
||||
metadata := string(metaBytes)
|
||||
id, createdAt, err := persist("deploy", p.Level, p.Message, metadata)
|
||||
if err != nil {
|
||||
slog.Error("failed to persist event log", "source", "deploy", "level", p.Level, "error", err)
|
||||
continue
|
||||
}
|
||||
|
||||
b.Publish(Event{
|
||||
Type: EventLog,
|
||||
Payload: EventLogPayload{
|
||||
ID: id,
|
||||
Source: "deploy",
|
||||
Severity: p.Level,
|
||||
Message: p.Message,
|
||||
Metadata: metadata,
|
||||
CreatedAt: createdAt,
|
||||
},
|
||||
})
|
||||
}
|
||||
}()
|
||||
|
||||
return func() { b.Unsubscribe(sub) }
|
||||
}
|
||||
|
||||
// MarshalEvent serializes an event to a JSON string suitable for SSE data lines.
|
||||
func MarshalEvent(evt Event) (string, error) {
|
||||
data, err := json.Marshal(evt)
|
||||
|
||||
Reference in New Issue
Block a user