feat: domain event bus for multi-client sync (issue #26, phase 2)

This commit is contained in:
2026-07-14 19:33:07 +02:00
parent 700ed79c43
commit 16f45d77b2
14 changed files with 309 additions and 10 deletions

View File

@@ -91,14 +91,16 @@ defmodule BDS.Desktop.ShellData do
end
end
def editor_meta(task_status) do
# Accepts the caller's already-resolved locale so hot render paths never
# re-read the ui.language setting from the database.
def editor_meta(task_status, ui_language \\ nil) do
[
%{
label: dgettext("ui", "Status"),
value: task_status.running_task_message || dgettext("ui", "Idle")
},
%{label: dgettext("ui", "Mode"), value: dgettext("ui", "Offline")},
%{label: dgettext("ui", "Main Language"), value: ui_language()}
%{label: dgettext("ui", "Main Language"), value: ui_language || ui_language()}
]
end
@@ -107,7 +109,7 @@ defmodule BDS.Desktop.ShellData do
post_count: dashboard.post_stats.total_posts,
media_count: dashboard.media_stats.media_count,
theme_badge: "desktop-shell",
ui_language: Keyword.get(opts, :ui_language, ui_language()),
ui_language: Keyword.get_lazy(opts, :ui_language, &ui_language/0),
offline_mode: Keyword.get(opts, :offline_mode, true),
running_task_message: task_status.running_task_message,
running_task_overflow: task_status.running_task_overflow,

View File

@@ -6,7 +6,6 @@ defmodule BDS.Desktop.ShellLive do
import Phoenix.HTML
alias BDS.{AI, Blogmark, BoundedAtoms, Metadata}
alias BDS.CliSync.Watcher
alias BDS.Desktop.{FilePicker, FolderPicker, ShellData, UILocale}
alias BDS.Desktop.ShellLive.{
@@ -151,7 +150,9 @@ defmodule BDS.Desktop.ShellLive do
connected = connected?(socket)
if connected do
Phoenix.PubSub.subscribe(BDS.PubSub, Watcher.topic())
# Entity + settings events from every source: in-app contexts, other
# connected clients (GUI or TUI), and the CLI sync watcher.
:ok = BDS.Events.subscribe()
Process.send_after(self(), :refresh_task_status, @refresh_interval)
end
@@ -736,6 +737,14 @@ defmodule BDS.Desktop.ShellLive do
{:noreply, assign(socket, :shell_overlay, overlay)}
end
# The UI language is a server-side setting shared by all clients; when any
# client (or script) changes it, every shell re-renders in the new locale.
def handle_info({:settings_changed, "ui.language"}, socket) do
{:noreply, set_page_language(socket, ShellData.ui_language())}
end
def handle_info({:settings_changed, _key}, socket), do: {:noreply, socket}
def handle_info(message, socket) do
Bridges.handle_info(message, socket, bridges_callbacks())
end
@@ -981,6 +990,9 @@ defmodule BDS.Desktop.ShellLive do
socket
else
UILocale.put(normalized)
# Persist server-side so every client renders the same language; the
# resulting settings_changed broadcast is a no-op for this socket.
_ = BDS.Settings.put_global_setting("ui.language", normalized)
socket
|> assign(:page_language, normalized)

View File

@@ -266,7 +266,7 @@ defmodule BDS.Desktop.ShellLive.Bridges do
socket
|> assign(:task_status, task_status)
|> assign(:editor_meta, ShellData.editor_meta(task_status))
|> assign(:editor_meta, ShellData.editor_meta(task_status, socket.assigns.page_language))
|> assign(
:status,
ShellData.status_bar(

View File

@@ -38,7 +38,7 @@ defmodule BDS.Desktop.ShellLive.SocketState do
|> assign(:sidebar_header, active_sidebar_label(activity_buttons, workbench.active_view, sidebar_data))
|> assign(:panel_tabs, ShellData.panel_tabs(workbench))
|> assign(:current_tab, current_tab)
|> assign(:editor_meta, ShellData.editor_meta(task_status))
|> assign(:editor_meta, ShellData.editor_meta(task_status, page_language))
|> assign(
:status,
ShellData.status_bar(workbench, task_status, dashboard,