1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
use dioxus::prelude::*;
use crate::components::modal::Modal;
use crate::state::app_state::AppState;
/// Known integration/widget types.
static INTEGRATIONS: &[(&str, &str, &str)] = &[
("jitsi", "Jitsi Meet", "Video conferencing widget"),
("etherpad", "Etherpad", "Collaborative text editing"),
("youtube", "YouTube", "YouTube video player"),
("grafana", "Grafana", "Dashboard monitoring"),
("custom", "Custom Widget", "Add a custom widget by URL"),
];
/// Integration manager dialog for adding/managing widgets in a room.
#[component]
pub fn IntegrationManagerDialog(room_id: String, on_close: EventHandler<()>) -> Element {
let state = use_context::<Signal<AppState>>();
let mut selected_type = use_signal(|| Option::<String>::None);
let mut widget_url = use_signal(|| String::new());
let mut widget_name = use_signal(|| String::new());
let mut adding = use_signal(|| false);
let rid = room_id.clone();
let on_add_widget = move |_| {
let url = widget_url.read().trim().to_string();
let name = widget_name.read().trim().to_string();
let wtype = selected_type.read().clone().unwrap_or_else(|| "custom".to_string());
if url.is_empty() || name.is_empty() {
return;
}
adding.set(true);
let rid = rid.clone();
spawn(async move {
let client = { state.read().client.clone() };
if let Some(client) = client {
if let Ok(room_id) = matrix_sdk::ruma::OwnedRoomId::try_from(rid.as_str()) {
if let Some(room) = client.get_room(&room_id) {
// In a full implementation, we'd send an im.vector.modular.widgets
// state event to add the widget
tracing::info!(
"Adding widget '{}' ({}) to room {}: {}",
name, wtype, room_id, url
);
// Send a notice about the widget
use matrix_sdk::ruma::events::room::message::RoomMessageEventContent;
let msg = RoomMessageEventContent::notice_plain(
format!("Added widget: {name}")
);
let _ = room.send(msg).await;
}
}
}
adding.set(false);
widget_url.set(String::new());
widget_name.set(String::new());
selected_type.set(None);
});
};
rsx! {
Modal {
title: "Integration Manager".to_string(),
on_close: move |_| on_close.call(()),
div {
class: "integration-manager",
// Available integrations
div {
class: "integration-manager__section",
h4 { "Available Integrations" }
div {
class: "integration-manager__list",
for (id, name, desc) in INTEGRATIONS.iter() {
{
let id = id.to_string();
let name = name.to_string();
let desc = desc.to_string();
let is_selected = selected_type.read().as_ref() == Some(&id);
rsx! {
button {
class: if is_selected {
"integration-manager__item integration-manager__item--selected"
} else {
"integration-manager__item"
},
onclick: move |_| {
selected_type.set(Some(id.clone()));
if widget_name.read().is_empty() {
widget_name.set(name.clone());
}
},
div {
class: "integration-manager__item-info",
strong { "{name}" }
p { "{desc}" }
}
}
}
}
}
}
}
// Add widget form
if selected_type.read().is_some() {
div {
class: "integration-manager__form",
h4 { "Add Widget" }
div {
class: "integration-manager__field",
label { "Widget name" }
input {
r#type: "text",
class: "settings-input",
placeholder: "My Widget",
value: "{widget_name}",
oninput: move |evt| widget_name.set(evt.value()),
}
}
div {
class: "integration-manager__field",
label { "Widget URL" }
input {
r#type: "url",
class: "settings-input",
placeholder: "https://...",
value: "{widget_url}",
oninput: move |evt| widget_url.set(evt.value()),
}
}
div {
class: "integration-manager__actions",
button {
class: "btn btn--secondary",
onclick: move |_| {
selected_type.set(None);
widget_url.set(String::new());
widget_name.set(String::new());
},
"Cancel"
}
button {
class: "btn btn--primary",
disabled: widget_url.read().is_empty() || widget_name.read().is_empty() || *adding.read(),
onclick: on_add_widget,
if *adding.read() { "Adding..." } else { "Add Widget" }
}
}
}
}
}
}
}
}