move group actions to sidebar and add invite link copying
This commit is contained in:
@@ -1,15 +1,21 @@
|
||||
use gpui::{App, AppContext, ParentElement, Styled, WeakEntity, Window, div, px};
|
||||
use anyhow::Result;
|
||||
use gpui::{
|
||||
App, AppContext, ClipboardItem, ParentElement, SharedString, Styled, WeakEntity, Window, div,
|
||||
px,
|
||||
};
|
||||
use nip29::Group;
|
||||
use nostr_sdk::prelude::SecretKey;
|
||||
use theme::ActiveTheme;
|
||||
use ui::dialog::DialogButtonProps;
|
||||
use ui::input::InputState;
|
||||
use ui::notification::Notification;
|
||||
use ui::{WindowExtension, v_flex};
|
||||
|
||||
use crate::{GroupPanel, field};
|
||||
use crate::field;
|
||||
|
||||
const CODE_LEN: usize = 12;
|
||||
|
||||
pub(crate) fn open(panel: WeakEntity<GroupPanel>, window: &mut Window, cx: &mut App) {
|
||||
pub(crate) fn open(group: WeakEntity<Group>, window: &mut Window, cx: &mut App) {
|
||||
let code = SecretKey::generate().to_secret_hex();
|
||||
let code: String = code.chars().take(CODE_LEN).collect();
|
||||
|
||||
@@ -20,7 +26,7 @@ pub(crate) fn open(panel: WeakEntity<GroupPanel>, window: &mut Window, cx: &mut
|
||||
});
|
||||
|
||||
window.open_dialog(cx, move |this, _window, cx| {
|
||||
let panel = panel.clone();
|
||||
let group = group.clone();
|
||||
let input = input.clone();
|
||||
|
||||
this.width(px(420.))
|
||||
@@ -40,17 +46,64 @@ pub(crate) fn open(panel: WeakEntity<GroupPanel>, window: &mut Window, cx: &mut
|
||||
)
|
||||
.child(field("Code", &input, cx)),
|
||||
)
|
||||
.on_ok(move |_event, _window, cx| {
|
||||
.on_ok(move |_event, window, cx| {
|
||||
let code = input.read(cx).value().trim().to_owned();
|
||||
|
||||
if code.is_empty() {
|
||||
return false;
|
||||
}
|
||||
|
||||
if let Err(error) = panel.update_in(cx, |panel, window, cx| {
|
||||
panel.create_invite(code, window, cx);
|
||||
}) {
|
||||
log::warn!("nip29: creating an invite failed: {error}");
|
||||
let link = group
|
||||
.read_with(cx, |group, _cx| {
|
||||
group.metadata().and_then(|metadata| {
|
||||
metadata
|
||||
.naddr(group.key().relay(), Some(&code))
|
||||
.ok()
|
||||
.map(SharedString::from)
|
||||
})
|
||||
})
|
||||
.ok()
|
||||
.flatten();
|
||||
|
||||
let Some(link) = link else {
|
||||
window.push_notification(
|
||||
Notification::error(
|
||||
"The relay doesn't publish group details, so no invite link can be made",
|
||||
),
|
||||
cx,
|
||||
);
|
||||
return false;
|
||||
};
|
||||
|
||||
match group.update(cx, |group, cx| group.create_invite(&code, cx)) {
|
||||
Ok(task) => {
|
||||
window
|
||||
.spawn(cx, async move |cx| -> Result<()> {
|
||||
if let Err(error) = task.await {
|
||||
cx.update(|window, cx| {
|
||||
window.push_notification(
|
||||
Notification::error(error.to_string()),
|
||||
cx,
|
||||
);
|
||||
})?;
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
cx.update(|window, cx| {
|
||||
cx.write_to_clipboard(ClipboardItem::new_string(
|
||||
link.to_string(),
|
||||
));
|
||||
window.push_notification(
|
||||
Notification::success("Invite link copied"),
|
||||
cx,
|
||||
);
|
||||
})?;
|
||||
|
||||
Ok(())
|
||||
})
|
||||
.detach();
|
||||
}
|
||||
Err(error) => log::warn!("nip29: creating an invite failed: {error}"),
|
||||
}
|
||||
|
||||
true
|
||||
|
||||
+154
-285
@@ -4,12 +4,12 @@ use anyhow::Result;
|
||||
use chat_ui::text::rendered_text;
|
||||
use gpui::prelude::FluentBuilder;
|
||||
use gpui::{
|
||||
Action, AnyElement, App, AppContext, ClipboardItem, Context, Div, Entity, EventEmitter,
|
||||
FocusHandle, Focusable, FollowMode, IntoElement, ListAlignment, ListScrollEvent, ListState,
|
||||
ParentElement, PathPromptOptions, Render, SharedString, Styled, Subscription, Task, WeakEntity,
|
||||
Window, div, list, px,
|
||||
Action, AnyElement, App, AppContext, Context, Div, Entity, EventEmitter, FocusHandle,
|
||||
Focusable, FollowMode, IntoElement, ListAlignment, ListScrollEvent, ListState, ParentElement,
|
||||
PathPromptOptions, Render, SharedString, Styled, Subscription, Task, WeakEntity, Window, div,
|
||||
list, px,
|
||||
};
|
||||
use nip29::{Group, GroupEvent, GroupMetadata, GroupsRegistry, Membership, Pin, Row};
|
||||
use nip29::{Group, GroupEvent, GroupsRegistry, Membership, Pin, Row};
|
||||
use nostr_sdk::prelude::*;
|
||||
use person::PersonRegistry;
|
||||
use serde::Deserialize;
|
||||
@@ -23,7 +23,6 @@ use ui::dialog::DialogButtonProps;
|
||||
use ui::dock::{Panel, PanelEvent};
|
||||
use ui::input::{Input, InputEvent, InputState, Textarea, TextareaState};
|
||||
use ui::markdown::RenderedText;
|
||||
use ui::menu::{DropdownMenu, PopupMenuItem};
|
||||
use ui::message::WelcomeMessage;
|
||||
use ui::notification::Notification;
|
||||
use ui::scroll::Scrollbar;
|
||||
@@ -159,6 +158,130 @@ pub(crate) fn pin_label(group: &Group, pin: &Pin) -> SharedString {
|
||||
}
|
||||
}
|
||||
|
||||
/// Build the group's action buttons for the sidebar: info, admin actions and leave.
|
||||
pub fn actions(group: WeakEntity<Group>, cx: &App) -> AnyElement {
|
||||
let nostr = NostrRegistry::global(cx);
|
||||
let me = nostr.read(cx).current_user();
|
||||
|
||||
let admin = group
|
||||
.read_with(cx, |group, _cx| {
|
||||
me.is_some_and(|me| group.admins().contains(&me))
|
||||
})
|
||||
.unwrap_or(false);
|
||||
|
||||
let info = group.clone();
|
||||
let edit = group.clone();
|
||||
let invite = group.clone();
|
||||
let members = group.clone();
|
||||
let leave = group;
|
||||
|
||||
h_flex()
|
||||
.gap_1()
|
||||
.child(
|
||||
Button::new("group-info")
|
||||
.icon(IconName::Info)
|
||||
.tooltip("Group info")
|
||||
.ghost()
|
||||
.small()
|
||||
.on_click(move |_event, window, cx| {
|
||||
details::open(info.clone(), window, cx);
|
||||
}),
|
||||
)
|
||||
.when(admin, |this| {
|
||||
this.child(
|
||||
Button::new("edit")
|
||||
.icon(IconName::Edit)
|
||||
.tooltip("Edit group")
|
||||
.ghost()
|
||||
.small()
|
||||
.on_click(move |_event, window, cx| {
|
||||
metadata::open(edit.clone(), window, cx);
|
||||
}),
|
||||
)
|
||||
.child(
|
||||
Button::new("invite")
|
||||
.icon(IconName::Invite)
|
||||
.tooltip("Invite people")
|
||||
.ghost()
|
||||
.small()
|
||||
.on_click(move |_event, window, cx| {
|
||||
invite::open(invite.clone(), window, cx);
|
||||
}),
|
||||
)
|
||||
.child(
|
||||
Button::new("members")
|
||||
.icon(IconName::Group)
|
||||
.tooltip("Members")
|
||||
.ghost()
|
||||
.small()
|
||||
.on_click(move |_event, window, cx| {
|
||||
users::open(members.clone(), window, cx);
|
||||
}),
|
||||
)
|
||||
})
|
||||
.child(
|
||||
Button::new("leave")
|
||||
.icon(IconName::Logout)
|
||||
.tooltip("Leave group")
|
||||
.ghost()
|
||||
.small()
|
||||
.on_click(move |_event, window, cx| {
|
||||
confirm_leave(leave.clone(), window, cx);
|
||||
}),
|
||||
)
|
||||
.into_any_element()
|
||||
}
|
||||
|
||||
pub fn confirm_leave(group: WeakEntity<Group>, window: &mut Window, cx: &mut App) {
|
||||
let Some(name) = group.read_with(cx, |group, _cx| group.display_name()).ok() else {
|
||||
return;
|
||||
};
|
||||
|
||||
let Some(key) = group.read_with(cx, |group, _cx| group.key().clone()).ok() else {
|
||||
return;
|
||||
};
|
||||
|
||||
window.open_dialog(cx, move |this, _window, _cx| {
|
||||
let key = key.clone();
|
||||
|
||||
this.confirm()
|
||||
.width(px(360.))
|
||||
.title(format!("Leave {name}?"))
|
||||
.button_props(
|
||||
DialogButtonProps::default()
|
||||
.cancel_text("Cancel")
|
||||
.ok_text("Leave")
|
||||
.ok_variant(ButtonVariant::Danger),
|
||||
)
|
||||
.child(
|
||||
div()
|
||||
.text_sm()
|
||||
.child("You will stop receiving messages from this group."),
|
||||
)
|
||||
.on_ok(move |_event, _window, cx| {
|
||||
let registry = GroupsRegistry::global(cx);
|
||||
registry.update(cx, |registry, cx| {
|
||||
registry.leave(&key, cx);
|
||||
});
|
||||
true
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
/// Await a group write and surface any relay error as a notification.
|
||||
pub(crate) fn report(window: &mut Window, cx: &mut App, task: Task<Result<()>>) {
|
||||
window
|
||||
.spawn(cx, async move |cx| -> Result<()> {
|
||||
if let Err(error) = task.await {
|
||||
cx.update(|window, cx| {
|
||||
window.push_notification(Notification::error(error.to_string()), cx);
|
||||
})?;
|
||||
}
|
||||
Ok(())
|
||||
})
|
||||
.detach();
|
||||
}
|
||||
|
||||
pub struct GroupPanel {
|
||||
id: SharedString,
|
||||
focus_handle: FocusHandle,
|
||||
@@ -409,121 +532,6 @@ impl GroupPanel {
|
||||
.and_then(|group| Notice::of(group.read(cx)))
|
||||
}
|
||||
|
||||
fn edit_metadata(
|
||||
&mut self,
|
||||
metadata: GroupMetadata,
|
||||
window: &mut Window,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
let Ok(edit) = self
|
||||
.group
|
||||
.update(cx, |group, cx| group.edit_metadata(&metadata, cx))
|
||||
else {
|
||||
return;
|
||||
};
|
||||
|
||||
self.tasks.push(cx.spawn_in(window, async move |this, cx| {
|
||||
if let Err(error) = edit.await {
|
||||
this.update_in(cx, |_this, window, cx| {
|
||||
window.push_notification(Notification::error(error.to_string()), cx);
|
||||
})?;
|
||||
}
|
||||
Ok(())
|
||||
}));
|
||||
}
|
||||
|
||||
fn create_invite(&mut self, code: String, window: &mut Window, cx: &mut Context<Self>) {
|
||||
let Some(group) = self.group.upgrade() else {
|
||||
return;
|
||||
};
|
||||
|
||||
let link = {
|
||||
let group = group.read(cx);
|
||||
|
||||
group.metadata().and_then(|metadata| {
|
||||
metadata
|
||||
.naddr(group.key().relay(), Some(&code))
|
||||
.ok()
|
||||
.map(SharedString::from)
|
||||
})
|
||||
};
|
||||
|
||||
let Some(link) = link else {
|
||||
window.push_notification(
|
||||
Notification::error(
|
||||
"The relay doesn't publish group details, so no invite link can be made",
|
||||
),
|
||||
cx,
|
||||
);
|
||||
return;
|
||||
};
|
||||
|
||||
let Ok(invite) = self
|
||||
.group
|
||||
.update(cx, |group, cx| group.create_invite(&code, cx))
|
||||
else {
|
||||
return;
|
||||
};
|
||||
|
||||
self.tasks.push(cx.spawn_in(window, async move |this, cx| {
|
||||
if let Err(error) = invite.await {
|
||||
this.update_in(cx, |_this, window, cx| {
|
||||
window.push_notification(Notification::error(error.to_string()), cx);
|
||||
})?;
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
this.update_in(cx, |_this, window, cx| {
|
||||
cx.write_to_clipboard(ClipboardItem::new_string(link.to_string()));
|
||||
window.push_notification(Notification::success("Invite link copied"), cx);
|
||||
})?;
|
||||
|
||||
Ok(())
|
||||
}));
|
||||
}
|
||||
|
||||
fn put_user(
|
||||
&mut self,
|
||||
public_key: PublicKey,
|
||||
roles: Vec<String>,
|
||||
window: &mut Window,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
let Ok(put) = self
|
||||
.group
|
||||
.update(cx, |group, cx| group.put_user(public_key, roles, cx))
|
||||
else {
|
||||
return;
|
||||
};
|
||||
|
||||
self.tasks.push(cx.spawn_in(window, async move |this, cx| {
|
||||
if let Err(error) = put.await {
|
||||
this.update_in(cx, |_this, window, cx| {
|
||||
window.push_notification(Notification::error(error.to_string()), cx);
|
||||
})?;
|
||||
}
|
||||
Ok(())
|
||||
}));
|
||||
}
|
||||
|
||||
fn remove_user(&mut self, public_key: PublicKey, window: &mut Window, cx: &mut Context<Self>) {
|
||||
let Ok(remove) = self
|
||||
.group
|
||||
.update(cx, |group, cx| group.remove_user(public_key, cx))
|
||||
else {
|
||||
return;
|
||||
};
|
||||
|
||||
self.tasks.push(cx.spawn_in(window, async move |this, cx| {
|
||||
if let Err(error) = remove.await {
|
||||
this.update_in(cx, |_this, window, cx| {
|
||||
window.push_notification(Notification::error(error.to_string()), cx);
|
||||
})?;
|
||||
}
|
||||
Ok(())
|
||||
}));
|
||||
}
|
||||
|
||||
fn react(
|
||||
&mut self,
|
||||
group: WeakEntity<Group>,
|
||||
@@ -599,169 +607,6 @@ impl GroupPanel {
|
||||
}));
|
||||
}
|
||||
|
||||
fn confirm_leave(group: WeakEntity<Group>, window: &mut Window, cx: &mut App) {
|
||||
let Some(name) = group.read_with(cx, |group, _cx| group.display_name()).ok() else {
|
||||
return;
|
||||
};
|
||||
|
||||
let Some(key) = group.read_with(cx, |group, _cx| group.key().clone()).ok() else {
|
||||
return;
|
||||
};
|
||||
|
||||
window.open_dialog(cx, move |this, _window, _cx| {
|
||||
let key = key.clone();
|
||||
|
||||
this.confirm()
|
||||
.width(px(360.))
|
||||
.title(format!("Leave {name}?"))
|
||||
.button_props(
|
||||
DialogButtonProps::default()
|
||||
.cancel_text("Cancel")
|
||||
.ok_text("Leave")
|
||||
.ok_variant(ButtonVariant::Danger),
|
||||
)
|
||||
.child(
|
||||
div()
|
||||
.text_sm()
|
||||
.child("You will stop receiving messages from this group."),
|
||||
)
|
||||
.on_ok(move |_event, _window, cx| {
|
||||
let registry = GroupsRegistry::global(cx);
|
||||
registry.update(cx, |registry, cx| {
|
||||
registry.leave(&key, cx);
|
||||
});
|
||||
true
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
fn render_header(&self, cx: &mut Context<Self>) -> AnyElement {
|
||||
let Some(group) = self.group.upgrade() else {
|
||||
return div().into_any_element();
|
||||
};
|
||||
|
||||
let (about, relay, group_id, admin) = {
|
||||
let group = group.read(cx);
|
||||
|
||||
let about = group
|
||||
.metadata()
|
||||
.and_then(|metadata| metadata.about.clone())
|
||||
.filter(|about| !about.trim().is_empty())
|
||||
.map(SharedString::from);
|
||||
|
||||
let admin = NostrRegistry::global(cx)
|
||||
.read(cx)
|
||||
.current_user()
|
||||
.is_some_and(|me| group.admins().contains(&me));
|
||||
|
||||
(
|
||||
about,
|
||||
group.key().relay().clone(),
|
||||
group.key().id().as_str().to_owned(),
|
||||
admin,
|
||||
)
|
||||
};
|
||||
|
||||
let panel = cx.weak_entity();
|
||||
let details_group = self.group.clone();
|
||||
let leave_group = self.group.clone();
|
||||
|
||||
h_flex()
|
||||
.flex_shrink_0()
|
||||
.w_full()
|
||||
.h_10()
|
||||
.px_2()
|
||||
.gap_2()
|
||||
.border_b_1()
|
||||
.border_color(cx.theme().border)
|
||||
.child(
|
||||
div()
|
||||
.flex_1()
|
||||
.min_w_0()
|
||||
.truncate()
|
||||
.text_sm()
|
||||
.text_color(cx.theme().text_muted)
|
||||
.when_some(about, |this, about| this.child(about)),
|
||||
)
|
||||
.child(
|
||||
Button::new("group-info")
|
||||
.icon(IconName::PanelLeftOpen)
|
||||
.tooltip("Toggle group meta panel in the sidebar")
|
||||
.ghost()
|
||||
.small()
|
||||
.on_click(move |_event, window, cx| {
|
||||
window.dispatch_action(
|
||||
Box::new(ToggleGroupMeta {
|
||||
relay: relay.clone(),
|
||||
group: group_id.clone(),
|
||||
}),
|
||||
cx,
|
||||
);
|
||||
}),
|
||||
)
|
||||
.child(
|
||||
Button::new("group-details")
|
||||
.icon(IconName::Info)
|
||||
.tooltip("Details")
|
||||
.ghost()
|
||||
.small()
|
||||
.on_click(move |_event, window, cx| {
|
||||
details::open(details_group.clone(), window, cx);
|
||||
}),
|
||||
)
|
||||
.when(admin, |this| {
|
||||
this.child(
|
||||
Button::new("group-manage")
|
||||
.icon(IconName::Ellipsis)
|
||||
.tooltip("Manage")
|
||||
.ghost()
|
||||
.small()
|
||||
.dropdown_menu({
|
||||
let group = self.group.clone();
|
||||
|
||||
move |menu, _window, _cx| {
|
||||
menu.item(PopupMenuItem::new("Edit group").on_click({
|
||||
let group = group.clone();
|
||||
let panel = panel.clone();
|
||||
|
||||
move |_event, window, cx| {
|
||||
metadata::open(group.clone(), panel.clone(), window, cx);
|
||||
}
|
||||
}))
|
||||
.item(PopupMenuItem::new("Invite people").on_click({
|
||||
let panel = panel.clone();
|
||||
|
||||
move |_event, window, cx| {
|
||||
invite::open(panel.clone(), window, cx);
|
||||
}
|
||||
}))
|
||||
.item(
|
||||
PopupMenuItem::new("Members and roles").on_click({
|
||||
let group = group.clone();
|
||||
let panel = panel.clone();
|
||||
|
||||
move |_event, window, cx| {
|
||||
users::open(group.clone(), panel.clone(), window, cx);
|
||||
}
|
||||
}),
|
||||
)
|
||||
}
|
||||
}),
|
||||
)
|
||||
})
|
||||
.child(
|
||||
Button::new("group-leave")
|
||||
.icon(IconName::Door)
|
||||
.tooltip("Leave")
|
||||
.ghost()
|
||||
.small()
|
||||
.on_click(move |_event, window, cx| {
|
||||
Self::confirm_leave(leave_group.clone(), window, cx);
|
||||
}),
|
||||
)
|
||||
.into_any_element()
|
||||
}
|
||||
|
||||
fn render_banner(&self, cx: &mut Context<Self>) -> AnyElement {
|
||||
let Some(group) = self.group.upgrade() else {
|
||||
return div().into_any_element();
|
||||
@@ -1024,6 +869,15 @@ impl GroupPanel {
|
||||
supports_text && writable
|
||||
});
|
||||
|
||||
let meta = self.group.upgrade().map(|group| {
|
||||
let group = group.read(cx);
|
||||
|
||||
(
|
||||
group.key().relay().clone(),
|
||||
group.key().id().as_str().to_owned(),
|
||||
)
|
||||
});
|
||||
|
||||
v_flex()
|
||||
.flex_shrink_0()
|
||||
.w_full()
|
||||
@@ -1034,6 +888,22 @@ impl GroupPanel {
|
||||
h_flex()
|
||||
.gap_1()
|
||||
.items_end()
|
||||
.child(
|
||||
Button::new("info")
|
||||
.icon(IconName::Group)
|
||||
.tooltip("Toggle group information in the sidebar")
|
||||
.ghost()
|
||||
.large()
|
||||
.on_click(move |_event, window, cx| {
|
||||
let Some((relay, group)) = meta.clone() else {
|
||||
return;
|
||||
};
|
||||
window.dispatch_action(
|
||||
Box::new(ToggleGroupMeta { relay, group }),
|
||||
cx,
|
||||
);
|
||||
}),
|
||||
)
|
||||
.child(
|
||||
Button::new("upload")
|
||||
.icon(IconName::Upload)
|
||||
@@ -1147,7 +1017,6 @@ impl Render for GroupPanel {
|
||||
v_flex()
|
||||
.size_full()
|
||||
.min_w_0()
|
||||
.child(self.render_header(cx))
|
||||
.child(self.render_banner(cx))
|
||||
.child(self.render_pins(cx))
|
||||
.child(
|
||||
|
||||
@@ -5,7 +5,7 @@ use ui::input::InputState;
|
||||
use ui::switch::Switch;
|
||||
use ui::{WindowExtension, v_flex};
|
||||
|
||||
use crate::{GroupPanel, field};
|
||||
use crate::field;
|
||||
|
||||
#[derive(Clone, Copy, Default)]
|
||||
struct Flags {
|
||||
@@ -28,12 +28,7 @@ impl Flags {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn open(
|
||||
group: WeakEntity<Group>,
|
||||
panel: WeakEntity<GroupPanel>,
|
||||
window: &mut Window,
|
||||
cx: &mut App,
|
||||
) {
|
||||
pub(crate) fn open(group: WeakEntity<Group>, window: &mut Window, cx: &mut App) {
|
||||
let base = group
|
||||
.read_with(cx, |group, _cx| group.metadata().cloned())
|
||||
.ok()
|
||||
@@ -119,13 +114,12 @@ pub(crate) fn open(
|
||||
)
|
||||
.on_ok({
|
||||
let group = group.clone();
|
||||
let panel = panel.clone();
|
||||
let name = name.clone();
|
||||
let about = about.clone();
|
||||
let picture = picture.clone();
|
||||
let flags = flags.clone();
|
||||
|
||||
move |_event, _window, cx| {
|
||||
move |_event, window, cx| {
|
||||
let mut next = group
|
||||
.read_with(cx, |group, _cx| group.metadata().cloned())
|
||||
.ok()
|
||||
@@ -143,10 +137,9 @@ pub(crate) fn open(
|
||||
next.closed = current.closed;
|
||||
next.livekit = current.livekit;
|
||||
|
||||
if let Err(error) = panel.update_in(cx, |panel, window, cx| {
|
||||
panel.edit_metadata(next, window, cx);
|
||||
}) {
|
||||
log::warn!("nip29: editing the group failed: {error}");
|
||||
match group.update(cx, |group, cx| group.edit_metadata(&next, cx)) {
|
||||
Ok(task) => crate::report(window, cx, task),
|
||||
Err(error) => log::warn!("nip29: editing the group failed: {error}"),
|
||||
}
|
||||
|
||||
true
|
||||
|
||||
@@ -14,20 +14,14 @@ use ui::notification::Notification;
|
||||
use ui::switch::Switch;
|
||||
use ui::{Sizable, StyledExt, WindowExtension, divider, h_flex, v_flex};
|
||||
|
||||
use crate::{GroupPanel, field};
|
||||
use crate::{field, report};
|
||||
|
||||
pub(crate) fn open(
|
||||
group: WeakEntity<Group>,
|
||||
panel: WeakEntity<GroupPanel>,
|
||||
window: &mut Window,
|
||||
cx: &mut App,
|
||||
) {
|
||||
pub(crate) fn open(group: WeakEntity<Group>, window: &mut Window, cx: &mut App) {
|
||||
let input = cx.new(|cx| InputState::new(window, cx).placeholder("npub1…"));
|
||||
let selected = cx.new(|_cx| Vec::<String>::new());
|
||||
|
||||
window.open_dialog(cx, move |this, _window, cx| {
|
||||
let group = group.clone();
|
||||
let panel = panel.clone();
|
||||
let input = input.clone();
|
||||
let selected = selected.clone();
|
||||
|
||||
@@ -61,7 +55,7 @@ pub(crate) fn open(
|
||||
.children(
|
||||
admins
|
||||
.iter()
|
||||
.map(|(key, roles)| admin(key, roles, &panel, cx)),
|
||||
.map(|(key, roles)| admin(key, roles, &group, cx)),
|
||||
),
|
||||
)
|
||||
.child(divider(cx))
|
||||
@@ -80,7 +74,7 @@ pub(crate) fn open(
|
||||
)
|
||||
})
|
||||
.child(Button::new("add-user").label("Add").small().on_click({
|
||||
let panel = panel.clone();
|
||||
let group = group.clone();
|
||||
let input = input.clone();
|
||||
let selected = selected.clone();
|
||||
|
||||
@@ -100,10 +94,13 @@ pub(crate) fn open(
|
||||
|
||||
let roles = selected.read(cx).clone();
|
||||
|
||||
if let Err(error) = panel.update_in(cx, |panel, window, cx| {
|
||||
panel.put_user(public_key, roles, window, cx);
|
||||
match group.update(cx, |group, cx| {
|
||||
group.put_user(public_key, roles, cx)
|
||||
}) {
|
||||
log::warn!("nip29: adding a group member failed: {error}");
|
||||
Ok(task) => report(window, cx, task),
|
||||
Err(error) => log::warn!(
|
||||
"nip29: adding a group member failed: {error}"
|
||||
),
|
||||
}
|
||||
|
||||
input.update(cx, |input, cx| {
|
||||
@@ -123,7 +120,7 @@ pub(crate) fn open(
|
||||
fn admin(
|
||||
public_key: &PublicKey,
|
||||
roles: &[String],
|
||||
panel: &WeakEntity<GroupPanel>,
|
||||
group: &WeakEntity<Group>,
|
||||
cx: &App,
|
||||
) -> AnyElement {
|
||||
let persons = PersonRegistry::global(cx);
|
||||
@@ -163,13 +160,14 @@ fn admin(
|
||||
.ghost()
|
||||
.small()
|
||||
.on_click({
|
||||
let panel = panel.clone();
|
||||
let group = group.clone();
|
||||
|
||||
move |_event, _window, cx| {
|
||||
if let Err(error) = panel.update_in(cx, |panel, window, cx| {
|
||||
panel.remove_user(public_key, window, cx);
|
||||
}) {
|
||||
log::warn!("nip29: removing a group member failed: {error}");
|
||||
move |_event, window, cx| match group
|
||||
.update(cx, |group, cx| group.remove_user(public_key, cx))
|
||||
{
|
||||
Ok(task) => report(window, cx, task),
|
||||
Err(error) => {
|
||||
log::warn!("nip29: removing a group member failed: {error}")
|
||||
}
|
||||
}
|
||||
}),
|
||||
|
||||
Reference in New Issue
Block a user