update member row
This commit is contained in:
+14
-13
@@ -32,7 +32,6 @@ mod details;
|
||||
mod invite;
|
||||
mod message;
|
||||
mod metadata;
|
||||
mod users;
|
||||
|
||||
/// Ask the shell to show or hide the sidebar's information for a group.
|
||||
#[derive(Action, Clone, PartialEq, Eq, Deserialize)]
|
||||
@@ -172,7 +171,6 @@ pub fn actions(group: WeakEntity<Group>, cx: &App) -> AnyElement {
|
||||
let info = group.clone();
|
||||
let edit = group.clone();
|
||||
let invite = group.clone();
|
||||
let members = group.clone();
|
||||
let leave = group;
|
||||
|
||||
h_flex()
|
||||
@@ -199,7 +197,7 @@ pub fn actions(group: WeakEntity<Group>, cx: &App) -> AnyElement {
|
||||
}),
|
||||
)
|
||||
.child(
|
||||
Button::new("invite")
|
||||
Button::new("group-invite")
|
||||
.icon(IconName::Invite)
|
||||
.tooltip("Invite people")
|
||||
.ghost()
|
||||
@@ -208,16 +206,6 @@ pub fn actions(group: WeakEntity<Group>, cx: &App) -> AnyElement {
|
||||
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")
|
||||
@@ -268,6 +256,19 @@ pub fn confirm_leave(group: WeakEntity<Group>, window: &mut Window, cx: &mut App
|
||||
});
|
||||
}
|
||||
|
||||
/// Remove a member from the group and surface any relay error as a notification.
|
||||
pub fn remove_member(
|
||||
group: WeakEntity<Group>,
|
||||
public_key: PublicKey,
|
||||
window: &mut Window,
|
||||
cx: &mut App,
|
||||
) {
|
||||
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}"),
|
||||
}
|
||||
}
|
||||
|
||||
/// 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
|
||||
|
||||
@@ -1,207 +0,0 @@
|
||||
use gpui::prelude::FluentBuilder;
|
||||
use gpui::{
|
||||
AnyElement, App, AppContext, Entity, IntoElement, ParentElement, SharedString, Styled,
|
||||
WeakEntity, Window, div, px,
|
||||
};
|
||||
use nip29::{Group, Role};
|
||||
use nostr_sdk::prelude::*;
|
||||
use person::PersonRegistry;
|
||||
use theme::ActiveTheme;
|
||||
use ui::avatar::Avatar;
|
||||
use ui::button::{Button, ButtonVariants};
|
||||
use ui::input::InputState;
|
||||
use ui::notification::Notification;
|
||||
use ui::switch::Switch;
|
||||
use ui::{Sizable, StyledExt, WindowExtension, divider, h_flex, v_flex};
|
||||
|
||||
use crate::{field, report};
|
||||
|
||||
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 input = input.clone();
|
||||
let selected = selected.clone();
|
||||
|
||||
let admins = group
|
||||
.read_with(cx, |group, _cx| group.admins().entries().to_vec())
|
||||
.unwrap_or_default();
|
||||
let roles = group
|
||||
.read_with(cx, |group, _cx| group.roles().roles().to_vec())
|
||||
.unwrap_or_default();
|
||||
let chosen = selected.read(cx).clone();
|
||||
|
||||
this.width(px(460.))
|
||||
.max_h(px(620.))
|
||||
.show_close(true)
|
||||
.title("Members and roles")
|
||||
.child(
|
||||
v_flex()
|
||||
.gap_4()
|
||||
.child(
|
||||
v_flex()
|
||||
.gap_2()
|
||||
.child(div().text_sm().font_medium().child("Admins"))
|
||||
.when(admins.is_empty(), |this| {
|
||||
this.child(
|
||||
div()
|
||||
.text_sm()
|
||||
.text_color(cx.theme().text_placeholder)
|
||||
.child("The relay lists no admins."),
|
||||
)
|
||||
})
|
||||
.children(
|
||||
admins
|
||||
.iter()
|
||||
.map(|(key, roles)| admin(key, roles, &group, cx)),
|
||||
),
|
||||
)
|
||||
.child(divider(cx))
|
||||
.child(
|
||||
v_flex()
|
||||
.gap_3()
|
||||
.child(div().text_sm().font_medium().child("Add a member"))
|
||||
.child(field("Public key", &input, cx))
|
||||
.when(!roles.is_empty(), |this| {
|
||||
this.child(
|
||||
v_flex().gap_2().children(
|
||||
roles
|
||||
.iter()
|
||||
.map(|role| role_switch(role, &selected, &chosen)),
|
||||
),
|
||||
)
|
||||
})
|
||||
.child(Button::new("add-user").label("Add").small().on_click({
|
||||
let group = group.clone();
|
||||
let input = input.clone();
|
||||
let selected = selected.clone();
|
||||
|
||||
move |_event, window, cx| {
|
||||
let value = input.read(cx).value().trim().to_owned();
|
||||
|
||||
let public_key = match PublicKey::parse(&value) {
|
||||
Ok(public_key) => public_key,
|
||||
Err(error) => {
|
||||
window.push_notification(
|
||||
Notification::error(error.to_string()),
|
||||
cx,
|
||||
);
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
let roles = selected.read(cx).clone();
|
||||
|
||||
match group.update(cx, |group, cx| {
|
||||
group.put_user(public_key, roles, cx)
|
||||
}) {
|
||||
Ok(task) => report(window, cx, task),
|
||||
Err(error) => log::warn!(
|
||||
"nip29: adding a group member failed: {error}"
|
||||
),
|
||||
}
|
||||
|
||||
input.update(cx, |input, cx| {
|
||||
input.set_value("", window, cx);
|
||||
});
|
||||
selected.update(cx, |selected, cx| {
|
||||
selected.clear();
|
||||
cx.notify();
|
||||
});
|
||||
}
|
||||
})),
|
||||
),
|
||||
)
|
||||
});
|
||||
}
|
||||
|
||||
fn admin(
|
||||
public_key: &PublicKey,
|
||||
roles: &[String],
|
||||
group: &WeakEntity<Group>,
|
||||
cx: &App,
|
||||
) -> AnyElement {
|
||||
let persons = PersonRegistry::global(cx);
|
||||
let person = persons.read(cx).get(public_key, cx);
|
||||
let public_key = *public_key;
|
||||
|
||||
h_flex()
|
||||
.justify_between()
|
||||
.gap_2()
|
||||
.child(
|
||||
h_flex()
|
||||
.gap_2()
|
||||
.min_w_0()
|
||||
.child(
|
||||
Avatar::new(person.avatar())
|
||||
.seed(person.avatar_seed())
|
||||
.xsmall(),
|
||||
)
|
||||
.child(
|
||||
v_flex()
|
||||
.min_w_0()
|
||||
.child(div().truncate().child(person.name()))
|
||||
.when(!roles.is_empty(), |this| {
|
||||
this.child(
|
||||
div()
|
||||
.truncate()
|
||||
.text_xs()
|
||||
.text_color(cx.theme().text_placeholder)
|
||||
.child(SharedString::from(roles.join(", "))),
|
||||
)
|
||||
}),
|
||||
),
|
||||
)
|
||||
.child(
|
||||
Button::new(SharedString::from(format!("del-{}", public_key.to_hex())))
|
||||
.label("Remove")
|
||||
.ghost()
|
||||
.small()
|
||||
.on_click({
|
||||
let group = group.clone();
|
||||
|
||||
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}")
|
||||
}
|
||||
}
|
||||
}),
|
||||
)
|
||||
.into_any_element()
|
||||
}
|
||||
|
||||
fn role_switch(role: &Role, selected: &Entity<Vec<String>>, chosen: &[String]) -> AnyElement {
|
||||
let name = role.name.clone();
|
||||
let description = role.description.clone();
|
||||
|
||||
Switch::new(SharedString::from(format!("role-{}", role.name)))
|
||||
.label(role.name.clone())
|
||||
.when_some(description, |this, description| {
|
||||
this.description(description)
|
||||
})
|
||||
.small()
|
||||
.checked(chosen.contains(&role.name))
|
||||
.on_click({
|
||||
let selected = selected.clone();
|
||||
|
||||
move |next, _window, cx| {
|
||||
selected.update(cx, |selected, cx| {
|
||||
if *next {
|
||||
if !selected.contains(&name) {
|
||||
selected.push(name.clone());
|
||||
}
|
||||
} else {
|
||||
selected.retain(|role| role != &name);
|
||||
}
|
||||
|
||||
cx.notify();
|
||||
});
|
||||
}
|
||||
})
|
||||
.into_any_element()
|
||||
}
|
||||
Reference in New Issue
Block a user