Using a general client tag element for all client tags and introduced the channel conversation mode variable
parent
4cdabc620b
commit
1996878f12
|
@ -1,4 +1,7 @@
|
|||
# Changelog:
|
||||
* **04.10.20**
|
||||
- Fixed invalid channel tree unique id assignment for the initial server entry ([#F2986](https://forum.teaspeak.de/index.php?threads/2986))
|
||||
|
||||
* **27.09.20**
|
||||
- Middle clicking on bookmarks now directly connects in a new tab
|
||||
|
||||
|
|
|
@ -73,7 +73,7 @@ export class ChannelProperties {
|
|||
//Only after request
|
||||
channel_description: string = "";
|
||||
|
||||
channel_flag_conversation_private: boolean = true; /* TeamSpeak mode */
|
||||
channel_conversation_mode: number = 0; /* 0 := Private, the default */
|
||||
channel_conversation_history_length: number = -1;
|
||||
}
|
||||
|
||||
|
@ -594,6 +594,10 @@ export class ChannelEntry extends ChannelTreeEntry<ChannelEvents> {
|
|||
this._cached_channel_description_promise = undefined;
|
||||
this._cached_channel_description_promise_resolve = undefined;
|
||||
this._cached_channel_description_promise_reject = undefined;
|
||||
} else if(key === "channel_flag_conversation_private") {
|
||||
/* "fix" for older TeaSpeak server versions (pre. 1.4.22) */
|
||||
this.properties.channel_conversation_mode = value === "1" ? 0 : 1;
|
||||
variables.push({ key: "channel_conversation_mode", value: this.properties.channel_conversation_mode + "" });
|
||||
}
|
||||
}
|
||||
/* devel-block(log-channel-property-updates) */
|
||||
|
|
|
@ -1233,8 +1233,9 @@ export class MusicClientEntry extends ClientEntry {
|
|||
name: tr("Change remote volume"),
|
||||
callback: () => {
|
||||
let max_volume = this.channelTree.client.permissions.neededPermission(PermissionType.I_CLIENT_MUSIC_CREATE_MODIFY_MAX_VOLUME).value;
|
||||
if(max_volume < 0)
|
||||
if(max_volume < 0) {
|
||||
max_volume = 100;
|
||||
}
|
||||
|
||||
spawnMusicBotVolumeChange(this, max_volume / 100);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
.clientEntry, .channelEntry {
|
||||
color: var(--server-log-tree-entry);
|
||||
font-weight: 700;
|
||||
cursor: pointer;
|
||||
}
|
|
@ -7,6 +7,7 @@ import {BBCodeRenderer} from "tc-shared/text/bbcode";
|
|||
import {format_time} from "tc-shared/ui/frames/chat";
|
||||
import {CommandResult} from "tc-shared/connection/ServerConnectionDeclaration";
|
||||
import {XBBCodeRenderer} from "vendor/xbbcode/react";
|
||||
import {ChannelTag, ClientTag} from "tc-shared/ui/tree/EntryTags";
|
||||
|
||||
const cssStyle = require("./DispatcherLog.scss");
|
||||
const cssStyleRenderer = require("./Renderer.scss");
|
||||
|
@ -26,18 +27,23 @@ export function getRegisteredLogDispatchers() : TypeInfo[] {
|
|||
return Object.keys(dispatchers) as any;
|
||||
}
|
||||
|
||||
/* TODO: Enable context menu */
|
||||
const ClientRenderer = (props: { client: EventClient, handlerId: string, braces?: boolean }) => (
|
||||
<div className={cssStyle.clientEntry}>
|
||||
{props.client.client_name}
|
||||
</div>
|
||||
<ClientTag
|
||||
handlerId={props.handlerId}
|
||||
clientName={props.client.client_name}
|
||||
clientId={props.client.client_id}
|
||||
clientUniqueId={props.client.client_unique_id}
|
||||
className={cssStyle.clientEntry}
|
||||
/>
|
||||
);
|
||||
|
||||
/* TODO: Enable context menu */
|
||||
const ChannelRenderer = (props: { channel: EventChannelData, handlerId: string, braces?: boolean }) => (
|
||||
<div className={cssStyle.channelEntry}>
|
||||
{props.channel.channel_name}
|
||||
</div>
|
||||
<ChannelTag
|
||||
handlerId={props.handlerId}
|
||||
channelName={props.channel.channel_name}
|
||||
channelId={props.channel.channel_id}
|
||||
className={cssStyle.channelEntry}
|
||||
/>
|
||||
);
|
||||
|
||||
registerDispatcher(EventType.ERROR_CUSTOM, data => <div className={cssStyleRenderer.errorMessage}>{data.message}</div>);
|
||||
|
|
|
@ -62,10 +62,11 @@ export abstract class AbstractChat<Events extends ConversationUIEvents> {
|
|||
this.hasHistory = true;
|
||||
index -= deleteMessageCount;
|
||||
|
||||
if(event.isOwnMessage)
|
||||
if(event.isOwnMessage) {
|
||||
this.setUnreadTimestamp(undefined);
|
||||
else if(!this.unreadTimestamp)
|
||||
} else if(!this.unreadTimestamp) {
|
||||
this.setUnreadTimestamp(event.message.timestamp);
|
||||
}
|
||||
|
||||
/* let all other events run before */
|
||||
this.events.fire_async("notify_chat_event", {
|
||||
|
@ -333,10 +334,11 @@ export abstract class AbstractChatManager<Events extends ConversationUIEvents> {
|
|||
return;
|
||||
}
|
||||
|
||||
if(conversation.currentMode() === "unloaded")
|
||||
if(conversation.currentMode() === "unloaded") {
|
||||
conversation.queryCurrentMessages();
|
||||
else
|
||||
} else {
|
||||
conversation.reportStateToUI();
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler<ConversationUIEvents>("query_conversation_history")
|
||||
|
|
|
@ -49,14 +49,17 @@ export class Conversation extends AbstractChat<ConversationUIEvents> {
|
|||
cid: this.conversationId
|
||||
} as any;
|
||||
|
||||
if(typeof criteria.begin === "number")
|
||||
if(typeof criteria.begin === "number") {
|
||||
requestObject.timestamp_begin = criteria.begin;
|
||||
}
|
||||
|
||||
if(typeof criteria.end === "number")
|
||||
if(typeof criteria.end === "number") {
|
||||
requestObject.timestamp_end = criteria.end;
|
||||
}
|
||||
|
||||
if(typeof criteria.limit === "number")
|
||||
if(typeof criteria.limit === "number") {
|
||||
requestObject.message_count = criteria.limit;
|
||||
}
|
||||
|
||||
return this.handle.connection.serverConnection.send_command("conversationhistory", requestObject, { flagset: [ "merge" ], process_result: false }).then(() => {
|
||||
resolve({ status: "success", events: this.historyQueryResponse.map(e => {
|
||||
|
@ -198,11 +201,13 @@ export class Conversation extends AbstractChat<ConversationUIEvents> {
|
|||
}
|
||||
|
||||
const timestamp = parseInt(info["timestamp"]);
|
||||
if(isNaN(timestamp))
|
||||
if(isNaN(timestamp)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(timestamp > this.lastReadMessage)
|
||||
if(timestamp > this.lastReadMessage) {
|
||||
this.setUnreadTimestamp(this.lastReadMessage);
|
||||
}
|
||||
}
|
||||
|
||||
public handleIncomingMessage(message: ChatMessage, isOwnMessage: boolean) {
|
||||
|
@ -277,7 +282,7 @@ export class Conversation extends AbstractChat<ConversationUIEvents> {
|
|||
}
|
||||
|
||||
sendMessage(text: string) {
|
||||
this.doSendMessage(text, this.conversationId ? 2 : 3, this.conversationId);
|
||||
this.doSendMessage(text, this.conversationId ? 2 : 3, this.conversationId).then(() => {});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -344,7 +349,7 @@ export class ConversationManager extends AbstractChatManager<ConversationUIEvent
|
|||
this.queryUnreadFlags();
|
||||
}));
|
||||
|
||||
this.uiEvents.on("notify_destroy", this.connection.channelTree.events.on("notify_channel_updated", event => {
|
||||
this.uiEvents.on("notify_destroy", this.connection.channelTree.events.on("notify_channel_updated", _event => {
|
||||
/* TODO private flag! */
|
||||
}));
|
||||
}
|
||||
|
@ -403,9 +408,6 @@ export class ConversationManager extends AbstractChatManager<ConversationUIEvent
|
|||
}
|
||||
|
||||
queryUnreadFlags() {
|
||||
/* FIXME: Test for old TeaSpeak servers which don't support this */
|
||||
return;
|
||||
|
||||
const commandData = this.connection.channelTree.channels.map(e => { return { cid: e.channelId, cpw: e.cached_password() }});
|
||||
this.connection.serverConnection.send_command("conversationfetch", commandData).catch(error => {
|
||||
log.warn(LogCategory.CHAT, tr("Failed to query conversation indexes: %o"), error);
|
||||
|
@ -465,7 +467,7 @@ export class ConversationManager extends AbstractChatManager<ConversationUIEvent
|
|||
}
|
||||
|
||||
@EventHandler<ConversationUIEvents>("query_selected_chat")
|
||||
private handleQuerySelectedChat(event: ConversationUIEvents["query_selected_chat"]) {
|
||||
private handleQuerySelectedChat() {
|
||||
this.uiEvents.fire_async("notify_selected_chat", { chatId: isNaN(this.selectedConversation_) ? "unselected" : this.selectedConversation_ + ""})
|
||||
}
|
||||
|
||||
|
|
|
@ -22,10 +22,14 @@ import {TimestampRenderer} from "tc-shared/ui/react-elements/TimestampRenderer";
|
|||
import {BBCodeRenderer} from "tc-shared/text/bbcode";
|
||||
import {getGlobalAvatarManagerFactory} from "tc-shared/file/Avatars";
|
||||
import {ColloquialFormat, date_format, format_date_general, formatDayTime} from "tc-shared/utils/DateUtils";
|
||||
import {ClientTag} from "tc-shared/ui/tree/EntryTags";
|
||||
|
||||
const cssStyle = require("./ConversationUI.scss");
|
||||
|
||||
const CMTextRenderer = React.memo((props: { text: string }) => <BBCodeRenderer settings={{ convertSingleUrls: true }} message={props.text} />);
|
||||
const ChatMessageTextRenderer = React.memo((props: { text: string }) => {
|
||||
if(typeof props.text !== "string") { debugger; }
|
||||
return <BBCodeRenderer settings={{ convertSingleUrls: true }} message={props.text || ""} />;
|
||||
});
|
||||
|
||||
const ChatEventMessageRenderer = React.memo((props: {
|
||||
message: ChatMessage,
|
||||
|
@ -57,17 +61,8 @@ const ChatEventMessageRenderer = React.memo((props: {
|
|||
<div className={cssStyle.message}>
|
||||
<div className={cssStyle.info}>
|
||||
{deleteButton}
|
||||
{/*
|
||||
<a className={cssStyle.sender} dangerouslySetInnerHTML={{ __html: generate_client({
|
||||
client_database_id: props.message.sender_database_id,
|
||||
client_id: -1,
|
||||
client_name: props.message.sender_name,
|
||||
client_unique_id: props.message.sender_unique_id,
|
||||
add_braces: false
|
||||
})}} />
|
||||
*/}
|
||||
<a className={cssStyle.sender}>
|
||||
<div className={"htmltag-client"}>{props.message.sender_name}</div>
|
||||
<ClientTag clientName={props.message.sender_name} clientUniqueId={props.message.sender_unique_id} handlerId={props.handlerId} clientDatabaseId={props.message.sender_database_id} />
|
||||
</a>
|
||||
<span> </span> { /* Only for copy purposes */}
|
||||
<a className={cssStyle.timestamp}>
|
||||
|
@ -76,7 +71,7 @@ const ChatEventMessageRenderer = React.memo((props: {
|
|||
<br /> { /* Only for copy purposes */ }
|
||||
</div>
|
||||
<div className={cssStyle.text}>
|
||||
<CMTextRenderer text={props.message.message} />
|
||||
<ChatMessageTextRenderer text={props.message.message} />
|
||||
</div>
|
||||
<br style={{ content: " ", display: "none" }} /> { /* Only for copy purposes */ }
|
||||
</div>
|
||||
|
@ -481,7 +476,7 @@ class ConversationMessages extends React.PureComponent<ConversationMessagesPrope
|
|||
case "no-permission":
|
||||
contents.push(<div key={"ol-permission"} className={cssStyle.overlay}><a>
|
||||
<Translatable>You don't have permissions to participate in this conversation!</Translatable><br />
|
||||
>{this.state.failedPermission}</a>
|
||||
{this.state.failedPermission}</a>
|
||||
</div>);
|
||||
break;
|
||||
|
||||
|
|
|
@ -72,8 +72,9 @@ const ConversationEntryInfo = React.memo((props: { events: Registry<PrivateConve
|
|||
const isTyping = Date.now() - kTypingTimeout < typingTimestamp;
|
||||
|
||||
useEffect(() => {
|
||||
if(!isTyping)
|
||||
if(!isTyping) {
|
||||
return;
|
||||
}
|
||||
|
||||
const timeout = setTimeout(() => {
|
||||
setTypingTimestamp(0);
|
||||
|
|
|
@ -75,13 +75,16 @@ export function spawnBanClient(client: ConnectionHandler, entries: BanEntry | Ba
|
|||
input_duration_value.firstParent(".input-boxed").removeClass("is-invalid");
|
||||
}
|
||||
|
||||
if (max != -1)
|
||||
if (max != -1) {
|
||||
tooltip_duration_max.html(tr("You're allowed to ban a maximum of ") + "<b>" + max + " " + duration_data[type][max == 1 ? "1-text" : "text"] + "</b>");
|
||||
else
|
||||
} else {
|
||||
tooltip_duration_max.html(tr("You're allowed to ban <b>permanent</b>."));
|
||||
}
|
||||
} else {
|
||||
if (value && !Number.isNaN(value))
|
||||
if (value && !Number.isNaN(value)) {
|
||||
input_duration_value.attr("x-saved-value", value);
|
||||
}
|
||||
|
||||
input_duration_value.attr("placeholder", tr("for ever")).val(null);
|
||||
tooltip_duration_max.html(tr("You're allowed to ban <b>permanent</b>."));
|
||||
}
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
.client {
|
||||
display: inline-block;
|
||||
color: #D8D8D8;
|
||||
font-weight: 700;
|
||||
cursor: pointer;
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
import * as React from "react";
|
||||
|
||||
const cssStyle = require("./EntryTags.scss");
|
||||
|
||||
export const ClientTag = (props: { clientName: string, clientUniqueId: string, handlerId: string, clientId?: number, clientDatabaseId?: number, className?: string }) => {
|
||||
|
||||
return (
|
||||
<div className={cssStyle.client + (props.className ? ` ${props.className}` : ``)}
|
||||
onContextMenu={event => {
|
||||
event.preventDefault();
|
||||
|
||||
/* TODO: Enable context menus */
|
||||
}}
|
||||
>
|
||||
{props.clientName}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export const ChannelTag = (props: { channelName: string, channelId: number, handlerId: string, className?: string }) => {
|
||||
|
||||
return <div className={cssStyle.client + (props.className ? ` ${props.className}` : ``)}>{props.channelName}</div>;
|
||||
};
|
|
@ -20,7 +20,7 @@ export class AudioLibrary {
|
|||
this.worker = new WorkerOwner(AudioLibrary.spawnNewWorker);
|
||||
}
|
||||
|
||||
private static spawnNewWorker() {
|
||||
private static spawnNewWorker() : Worker {
|
||||
/*
|
||||
* Attention don't use () => new Worker(...).
|
||||
* This confuses the worker plugin and will not emit any modules
|
||||
|
|
Loading…
Reference in New Issue