chore: fix messages not loading

This commit is contained in:
2025-08-25 12:13:45 +07:00
parent 5edcc97ada
commit 3a6fc2bcc5
19 changed files with 135 additions and 148 deletions

View File

@@ -1,3 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24">
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M19.25 21.25H6c-.69 0-1.25-.56-1.25-1.25M11.5 9.25h1M4.75 20V4.75a2 2 0 0 1 2-2h12.5v16H6c-.69 0-1.25.56-1.25 1.25Zm5-6.25s0-1.5 2.25-1.5 2.25 1.5 2.25 1.5h-4.5ZM13 9.25a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z"/>
</svg>

Before

Width:  |  Height:  |  Size: 404 B

View File

@@ -1,3 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="currentColor" viewBox="0 0 24 24">
<path fill="#000" fill-rule="evenodd" d="M2 12C2 6.477 6.477 2 12 2s10 4.477 10 10-4.477 10-10 10a9.967 9.967 0 0 1-4.098-.876.313.313 0 0 0-.195-.026l-3.471.78a1.75 1.75 0 0 1-2.084-2.12l.809-3.33a.313.313 0 0 0-.028-.204A9.965 9.965 0 0 1 2 12Zm4.5 0a1 1 0 1 0 2 0 1 1 0 0 0-2 0Zm4.5 0a1 1 0 1 0 2 0 1 1 0 0 0-2 0Zm5.5 1a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z" clip-rule="evenodd"/>
</svg>

Before

Width:  |  Height:  |  Size: 488 B

4
assets/icons/edit.svg Normal file
View File

@@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24">
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M10.75 21.25h-4a2 2 0 0 1-2-2V4.75a2 2 0 0 1 2-2h10.5a2 2 0 0 1 2 2v7"/>
<path stroke="currentColor" stroke-linecap="square" stroke-linejoin="round" stroke-width="1.5" d="M13.75 21.25v-2.333l3.75-3.75a1.65 1.65 0 0 1 2.333 2.333l-3.75 3.75H13.75Z"/>
</svg>

After

Width:  |  Height:  |  Size: 454 B

View File

@@ -1,3 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24">
<path fill="currentColor" d="M5.75 3A2.75 2.75 0 0 0 3 5.75v1.422c0 .729.29 1.428.805 1.944l4.829 4.829c.234.234.366.552.366.883v6.422a.75.75 0 0 0 .95.723l4.5-1.25A.75.75 0 0 0 15 20v-5.172c0-.331.132-.649.366-.883l4.829-4.829A2.75 2.75 0 0 0 21 7.172V5.75A2.75 2.75 0 0 0 18.25 3H5.75Z"/>
</svg>

Before

Width:  |  Height:  |  Size: 396 B

View File

@@ -1,3 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24">
<path stroke="currentColor" stroke-linejoin="round" stroke-width="1.5" d="M18.25 3.75H5.75a2 2 0 0 0-2 2v1.422a2 2 0 0 0 .586 1.414l4.828 4.828a2 2 0 0 1 .586 1.414v6.422l4.5-1.25v-5.172a2 2 0 0 1 .586-1.414l4.828-4.828a2 2 0 0 0 .586-1.414V5.75a2 2 0 0 0-2-2Z"/>
</svg>

Before

Width:  |  Height:  |  Size: 369 B

View File

@@ -1,3 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24">
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M2.75 5.75v11.5a2 2 0 0 0 2 2h14.5a2 2 0 0 0 2-2v-8.5a2 2 0 0 0-2-2h-6.18a2 2 0 0 1-1.664-.89l-.812-1.22a2 2 0 0 0-1.664-.89H4.75a2 2 0 0 0-2 2Z"/>
</svg>

Before

Width:  |  Height:  |  Size: 350 B

View File

@@ -1,4 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24">
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M3.75 5.816h8.5M8 5.75v-2m4 10.5C7.935 13.198 5.845 10.614 5.25 6"/>
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M4 14c4.064-1.02 6.154-3.527 6.75-8m3.594 11.125h5.312m1.594 2.125-3.314-8.774c-.326-.862-1.546-.862-1.872 0L12.75 19.25"/>
</svg>

Before

Width:  |  Height:  |  Size: 494 B

View File

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="currentColor" viewBox="0 0 256 256"><path d="M104,152a8,8,0,0,1-8,8H56a8,8,0,0,1,0-16H96A8,8,0,0,1,104,152ZM168,32h24a8,8,0,0,0,0-16H160a8,8,0,0,0-8,8V56h16Zm72,84v60a16,16,0,0,1-16,16H136v32a8,8,0,0,1-16,0V192H32a16,16,0,0,1-16-16V116A60.07,60.07,0,0,1,76,56h76v88a8,8,0,0,0,16,0V56h12A60.07,60.07,0,0,1,240,116Zm-120,0a44,44,0,0,0-88,0v60h88Z"></path></svg>

Before

Width:  |  Height:  |  Size: 429 B

View File

@@ -1,3 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24">
<path fill="currentColor" fill-rule="evenodd" d="M12 2a7.795 7.795 0 0 0-7.696 6.554l-1.17 7.258A2.75 2.75 0 0 0 5.848 19h1.66c.849 1.75 2.512 3 4.492 3s3.643-1.25 4.492-3h1.66a2.75 2.75 0 0 0 2.714-3.188l-1.17-7.258A7.795 7.795 0 0 0 12 2Zm2.754 17H9.245c.678.937 1.68 1.5 2.754 1.5s2.076-.563 2.754-1.5Z" clip-rule="evenodd"/>
</svg>

Before

Width:  |  Height:  |  Size: 434 B

4
assets/icons/refresh.svg Normal file
View File

@@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24">
<path fill="currentColor" d="M13 21a1 1 0 1 0 0-2 1 1 0 0 0 0 2Zm8-10a1 1 0 1 0-2 0 1 1 0 0 0 2 0Zm-1.07 3.268a1 1 0 1 1-1 1.732 1 1 0 0 1 1-1.732Zm-2.562 5.026a1 1 0 1 0-1-1.732 1 1 0 0 0 1 1.732ZM18.927 8a1 1 0 1 1-1-1.732 1 1 0 0 1 1 1.732Z"/>
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M9.25 14.75v5.5h-5.5M9 19.688a8.25 8.25 0 1 1 6.25-15.273"/>
</svg>

After

Width:  |  Height:  |  Size: 512 B

View File

@@ -1,3 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24">
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="m7.5 3.25 4.5 3.5 4.5-3.5m-11.75 17h14.5a2 2 0 0 0 2-2v-9.5a2 2 0 0 0-2-2H4.75a2 2 0 0 0-2 2v9.5a2 2 0 0 0 2 2Z"/>
</svg>

Before

Width:  |  Height:  |  Size: 317 B

View File

@@ -1,3 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24">
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="m7.25 10.488 3.675 3.762 6.825-10m-14 10.5v2.3c0 1.12 0 1.68.218 2.108a2 2 0 0 0 .874.874c.428.218.988.218 2.108.218h10.1c1.12 0 1.68 0 2.108-.218a2 2 0 0 0 .874-.874c.218-.428.218-.988.218-2.108v-2.3"/>
</svg>

Before

Width:  |  Height:  |  Size: 406 B

View File

@@ -1,3 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24">
<path fill="currentColor" fill-rule="evenodd" d="M1 11.75A5.75 5.75 0 0 1 6.75 6h10.5A5.75 5.75 0 0 1 23 11.75v.5A5.75 5.75 0 0 1 17.25 18H6.75A5.75 5.75 0 0 1 1 12.25v-.5ZM17 7.5a4.5 4.5 0 1 0 0 9 4.5 4.5 0 0 0 0-9Z" clip-rule="evenodd"/>
</svg>

Before

Width:  |  Height:  |  Size: 345 B

View File

@@ -1,3 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24">
<path stroke="currentColor" stroke-width="1.5" d="M17 17.25H7a5.25 5.25 0 1 1 0-10.5h10m0 10.5a5.25 5.25 0 1 0 0-10.5m0 10.5a5.25 5.25 0 1 1 0-10.5"/>
</svg>

Before

Width:  |  Height:  |  Size: 256 B

View File

@@ -133,19 +133,14 @@ impl ChatSpace {
subscriptions.push( subscriptions.push(
// Subscribe to open chat room requests // Subscribe to open chat room requests
cx.subscribe_in(&registry, window, |this, _e, event, window, cx| { cx.subscribe_in(
match event { &registry,
window,
|this, _e, event, window, cx| match event {
RegistrySignal::Open(room) => { RegistrySignal::Open(room) => {
if let Some(room) = room.upgrade() { if let Some(room) = room.upgrade() {
this.dock.update(cx, |this, cx| { this.dock.update(cx, |this, cx| {
let panel = chat::init(room, window, cx); let panel = chat::init(room, window, cx);
// Load messages when the panel is created
panel.update(cx, |this, cx| {
this.load_messages(window, cx);
});
// Add the panel to the center dock (tabs)
this.add_panel(Arc::new(panel), DockPlacement::Center, window, cx); this.add_panel(Arc::new(panel), DockPlacement::Center, window, cx);
}); });
} else { } else {
@@ -163,8 +158,8 @@ impl ChatSpace {
}); });
} }
_ => {} _ => {}
} },
}), ),
); );
tasks.push( tasks.push(

View File

@@ -10,7 +10,7 @@ use gpui::{
ClipboardItem, Context, Div, Element, Entity, EventEmitter, Flatten, FocusHandle, Focusable, ClipboardItem, Context, Div, Element, Entity, EventEmitter, Flatten, FocusHandle, Focusable,
InteractiveElement, IntoElement, ListAlignment, ListState, MouseButton, ObjectFit, InteractiveElement, IntoElement, ListAlignment, ListState, MouseButton, ObjectFit,
ParentElement, PathPromptOptions, Render, RetainAllImageCache, SharedString, Stateful, ParentElement, PathPromptOptions, Render, RetainAllImageCache, SharedString, Stateful,
StatefulInteractiveElement, Styled, StyledImage, Subscription, Window, StatefulInteractiveElement, Styled, StyledImage, Subscription, Task, Window,
}; };
use gpui_tokio::Tokio; use gpui_tokio::Tokio;
use i18n::{shared_t, t}; use i18n::{shared_t, t};
@@ -68,8 +68,9 @@ pub struct Chat {
uploading: bool, uploading: bool,
// System // System
image_cache: Entity<RetainAllImageCache>, image_cache: Entity<RetainAllImageCache>,
#[allow(dead_code)]
subscriptions: SmallVec<[Subscription; 3]>, _subscriptions: SmallVec<[Subscription; 2]>,
_tasks: SmallVec<[Task<()>; 1]>,
} }
impl Chat { impl Chat {
@@ -89,23 +90,34 @@ impl Chat {
.clean_on_escape() .clean_on_escape()
}); });
let load_messages = room.read(cx).load_messages(cx);
let mut subscriptions = smallvec![]; let mut subscriptions = smallvec![];
let mut tasks = smallvec![];
subscriptions.push(cx.on_release_in(window, move |this, _window, cx| { tasks.push(
this.messages.clear(); // Load all messages belonging to this room
this.rendered_texts_by_id.clear(); cx.spawn_in(window, async move |this, cx| {
this.reports_by_id.clear(); match load_messages.await {
Ok(events) => {
this.attachments.update(cx, |this, _cx| { this.update(cx, |this, cx| {
this.clear(); this.insert_messages(events, cx);
});
this.replies_to.update(cx, |this, _cx| {
this.clear();
}) })
})); .ok();
}
Err(e) => {
cx.update(|window, cx| {
window.push_notification(Notification::error(e.to_string()), cx);
})
.ok();
}
};
}),
);
subscriptions.push(cx.subscribe_in( subscriptions.push(
// Subscribe to input events
cx.subscribe_in(
&input, &input,
window, window,
move |this: &mut Self, _input, event, window, cx| { move |this: &mut Self, _input, event, window, cx| {
@@ -119,9 +131,11 @@ impl Chat {
_ => {} _ => {}
}; };
}, },
)); ),
);
subscriptions.push( subscriptions.push(
// Subscribe to room events
cx.subscribe_in(&room, window, move |this, _, signal, window, cx| { cx.subscribe_in(&room, window, move |this, _, signal, window, cx| {
match signal { match signal {
RoomSignal::NewMessage(event) => { RoomSignal::NewMessage(event) => {
@@ -150,26 +164,30 @@ impl Chat {
input, input,
replies_to, replies_to,
attachments, attachments,
subscriptions, _subscriptions: subscriptions,
_tasks: tasks,
} }
} }
/// Load all messages belonging to this room /// Load all messages belonging to this room
pub(crate) fn load_messages(&self, window: &mut Window, cx: &mut Context<Self>) { fn load_messages(&self, window: &mut Window, cx: &mut Context<Self>) {
let room = self.room.read(cx); let load_messages = self.room.read(cx).load_messages(cx);
let load_messages = room.load_messages(cx);
cx.spawn_in(window, async move |this, cx| { cx.spawn_in(window, async move |this, cx| {
match load_messages.await { match load_messages.await {
Ok(events) => { Ok(events) => {
cx.update(|window, cx| {
window.push_notification(t!("chat.reload_tooltip"), cx);
this.update(cx, |this, cx| { this.update(cx, |this, cx| {
this.insert_messages(events, cx); this.insert_messages(events, cx);
}) })
.ok(); .ok();
})
.ok();
} }
Err(e) => { Err(e) => {
cx.update(|window, cx| { cx.update(|window, cx| {
window.push_notification(Notification::error(e.to_string()), cx); window.push_notification(e.to_string(), cx);
}) })
.ok(); .ok();
} }
@@ -1010,6 +1028,62 @@ impl Chat {
items items
} }
fn subject_button(&self, cx: &App) -> Button {
let room = self.room.downgrade();
let subject = self
.room
.read(cx)
.subject
.as_ref()
.map(|subject| subject.to_string());
Button::new("subject")
.icon(IconName::Edit)
.tooltip(t!("chat.subject_tooltip"))
.on_click(move |_, window, cx| {
let view = subject::init(subject.clone(), window, cx);
let room = room.clone();
let weak_view = view.downgrade();
window.open_modal(cx, move |this, _window, _cx| {
let room = room.clone();
let weak_view = weak_view.clone();
this.confirm()
.title(shared_t!("chat.subject_tooltip"))
.child(view.clone())
.button_props(ModalButtonProps::default().ok_text(t!("common.change")))
.on_ok(move |_, _window, cx| {
if let Ok(subject) =
weak_view.read_with(cx, |this, cx| this.new_subject(cx))
{
room.update(cx, |this, cx| {
this.subject = Some(subject);
cx.notify();
})
.ok();
}
// true to close the modal
true
})
});
})
}
fn reload_button(&self, _cx: &App) -> Button {
let room = self.room.downgrade();
Button::new("reload")
.icon(IconName::Refresh)
.tooltip(t!("chat.reload_tooltip"))
.on_click(move |_, _window, cx| {
room.update(cx, |this, cx| {
this.emit_refresh(cx);
})
.ok();
})
}
} }
impl Panel for Chat { impl Panel for Chat {
@@ -1038,47 +1112,10 @@ impl Panel for Chat {
} }
fn toolbar_buttons(&self, _window: &Window, cx: &App) -> Vec<Button> { fn toolbar_buttons(&self, _window: &Window, cx: &App) -> Vec<Button> {
let room = self.room.downgrade(); let subject_button = self.subject_button(cx);
let subject = self let reload_button = self.reload_button(cx);
.room
.read(cx)
.subject
.as_ref()
.map(|subject| subject.to_string());
let button = Button::new("subject") vec![subject_button, reload_button]
.icon(IconName::EditFill)
.tooltip(t!("chat.change_subject_button"))
.on_click(move |_, window, cx| {
let view = subject::init(subject.clone(), window, cx);
let room = room.clone();
let weak_view = view.downgrade();
window.open_modal(cx, move |this, _window, _cx| {
let room = room.clone();
let weak_view = weak_view.clone();
this.confirm()
.title(SharedString::new(t!("chat.change_subject_modal_title")))
.child(view.clone())
.button_props(ModalButtonProps::default().ok_text(t!("common.change")))
.on_ok(move |_, _window, cx| {
if let Ok(subject) =
weak_view.read_with(cx, |this, cx| this.new_subject(cx))
{
room.update(cx, |this, cx| {
this.subject = Some(subject);
cx.notify();
})
.ok();
}
// true to close the modal
true
})
});
});
vec![button]
} }
} }

View File

@@ -223,7 +223,7 @@ where
.justify_center() .justify_center()
.py_6() .py_6()
.text_color(cx.theme().text_muted) .text_color(cx.theme().text_muted)
.child(Icon::new(IconName::Inbox).size(px(28.))) .child(Icon::new(IconName::Loader).size(px(28.)))
.into_any_element() .into_any_element()
} }
} }

View File

@@ -9,7 +9,6 @@ use crate::{Sizable, Size};
#[derive(IntoElement, Clone)] #[derive(IntoElement, Clone)]
pub enum IconName { pub enum IconName {
AddressBook,
ArrowIn, ArrowIn,
ArrowDown, ArrowDown,
ArrowLeft, ArrowLeft,
@@ -28,18 +27,13 @@ pub enum IconName {
CloseCircle, CloseCircle,
CloseCircleFill, CloseCircleFill,
Copy, Copy,
Edit,
EditFill, EditFill,
Ellipsis, Ellipsis,
Eye, Eye,
EyeOff, EyeOff,
EmojiFill, EmojiFill,
Folder,
FolderFill,
Filter,
FilterFill,
Inbox,
Info, Info,
Language,
Loader, Loader,
Logout, Logout,
Moon, Moon,
@@ -54,20 +48,17 @@ pub enum IconName {
Plus, Plus,
PlusFill, PlusFill,
PlusCircleFill, PlusCircleFill,
Relays,
ResizeCorner, ResizeCorner,
Reply, Reply,
Report, Report,
Refresh,
Forward, Forward,
Search, Search,
SearchFill, SearchFill,
Sent,
Settings, Settings,
SortAscending, SortAscending,
SortDescending, SortDescending,
Sun, Sun,
Toggle,
ToggleFill,
ThumbsDown, ThumbsDown,
ThumbsUp, ThumbsUp,
Upload, Upload,
@@ -82,7 +73,6 @@ pub enum IconName {
impl IconName { impl IconName {
pub fn path(self) -> SharedString { pub fn path(self) -> SharedString {
match self { match self {
Self::AddressBook => "icons/address-book.svg",
Self::ArrowIn => "icons/arrows-in.svg", Self::ArrowIn => "icons/arrows-in.svg",
Self::ArrowDown => "icons/arrow-down.svg", Self::ArrowDown => "icons/arrow-down.svg",
Self::ArrowLeft => "icons/arrow-left.svg", Self::ArrowLeft => "icons/arrow-left.svg",
@@ -101,18 +91,13 @@ impl IconName {
Self::CloseCircle => "icons/close-circle.svg", Self::CloseCircle => "icons/close-circle.svg",
Self::CloseCircleFill => "icons/close-circle-fill.svg", Self::CloseCircleFill => "icons/close-circle-fill.svg",
Self::Copy => "icons/copy.svg", Self::Copy => "icons/copy.svg",
Self::Edit => "icons/edit.svg",
Self::EditFill => "icons/edit-fill.svg", Self::EditFill => "icons/edit-fill.svg",
Self::Ellipsis => "icons/ellipsis.svg", Self::Ellipsis => "icons/ellipsis.svg",
Self::Eye => "icons/eye.svg", Self::Eye => "icons/eye.svg",
Self::EmojiFill => "icons/emoji-fill.svg", Self::EmojiFill => "icons/emoji-fill.svg",
Self::EyeOff => "icons/eye-off.svg", Self::EyeOff => "icons/eye-off.svg",
Self::Folder => "icons/folder.svg",
Self::FolderFill => "icons/folder-fill.svg",
Self::Filter => "icons/filter.svg",
Self::FilterFill => "icons/filter-fill.svg",
Self::Inbox => "icons/inbox.svg",
Self::Info => "icons/info.svg", Self::Info => "icons/info.svg",
Self::Language => "icons/language.svg",
Self::Loader => "icons/loader.svg", Self::Loader => "icons/loader.svg",
Self::Logout => "icons/logout.svg", Self::Logout => "icons/logout.svg",
Self::Moon => "icons/moon.svg", Self::Moon => "icons/moon.svg",
@@ -127,20 +112,17 @@ impl IconName {
Self::Plus => "icons/plus.svg", Self::Plus => "icons/plus.svg",
Self::PlusFill => "icons/plus-fill.svg", Self::PlusFill => "icons/plus-fill.svg",
Self::PlusCircleFill => "icons/plus-circle-fill.svg", Self::PlusCircleFill => "icons/plus-circle-fill.svg",
Self::Relays => "icons/relays.svg",
Self::ResizeCorner => "icons/resize-corner.svg", Self::ResizeCorner => "icons/resize-corner.svg",
Self::Reply => "icons/reply.svg", Self::Reply => "icons/reply.svg",
Self::Report => "icons/report.svg", Self::Report => "icons/report.svg",
Self::Refresh => "icons/refresh.svg",
Self::Forward => "icons/forward.svg", Self::Forward => "icons/forward.svg",
Self::Search => "icons/search.svg", Self::Search => "icons/search.svg",
Self::SearchFill => "icons/search-fill.svg", Self::SearchFill => "icons/search-fill.svg",
Self::Sent => "icons/sent.svg",
Self::Settings => "icons/settings.svg", Self::Settings => "icons/settings.svg",
Self::SortAscending => "icons/sort-ascending.svg", Self::SortAscending => "icons/sort-ascending.svg",
Self::SortDescending => "icons/sort-descending.svg", Self::SortDescending => "icons/sort-descending.svg",
Self::Sun => "icons/sun.svg", Self::Sun => "icons/sun.svg",
Self::Toggle => "icons/toggle.svg",
Self::ToggleFill => "icons/toggle-fill.svg",
Self::ThumbsDown => "icons/thumbs-down.svg", Self::ThumbsDown => "icons/thumbs-down.svg",
Self::ThumbsUp => "icons/thumbs-up.svg", Self::ThumbsUp => "icons/thumbs-up.svg",
Self::Upload => "icons/upload.svg", Self::Upload => "icons/upload.svg",

View File

@@ -309,9 +309,9 @@ chat:
en: "Copy Message" en: "Copy Message"
reply_button: reply_button:
en: "Reply" en: "Reply"
change_subject_button: reload_tooltip:
en: "Change Subject" en: "Refresh messages"
change_subject_modal_title: subject_tooltip:
en: "Change the subject of the conversation" en: "Change the subject of the conversation"
replying_to_label: replying_to_label:
en: "Replying to:" en: "Replying to:"