use chat Id as channel, remove primary channels and namespaces

This commit is contained in:
marlon-erler
2026-09-26 14:12:26 +02:00
parent 87760b66d2
commit b3cb919a7d
14 changed files with 453 additions and 1637 deletions
+270 -1389
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -1 +1 @@
2610 Beta 10.8 2610 Beta 10
+2 -2
View File
@@ -34,7 +34,7 @@ export default class ChatListModel {
this, this,
id, id,
); );
chatModel.setPrimaryChannel(primaryChannel); chatModel.setName(primaryChannel);
this.addChatModel(chatModel); this.addChatModel(chatModel);
return chatModel; return chatModel;
@@ -73,7 +73,7 @@ export default class ChatListModel {
for (const chatModel of this.chatModels) { for (const chatModel of this.chatModels) {
for (const channel of allChannels) { for (const channel of allChannels) {
if (channel != chatModel.unwrappedPrimaryChannel) continue; if (channel != chatModel.id) continue;
fn(chatModel); fn(chatModel);
break; break;
} }
+150 -163
View File
@@ -37,10 +37,6 @@ export default class ChatModel {
info: ChatInfo; /* load function called in constructor */ info: ChatInfo; /* load function called in constructor */
color: Colors = Colors.Standard; color: Colors = Colors.Standard;
get unwrappedPrimaryChannel(): string {
return this.info.namespace + this.info.primaryChannel;
}
get secondaryChannels(): string[] { get secondaryChannels(): string[] {
return this.info.secondaryChannels.sort(localeCompare); return this.info.secondaryChannels.sort(localeCompare);
} }
@@ -136,14 +132,8 @@ export default class ChatModel {
}; };
// settings // settings
readonly setPrimaryChannel = (primaryChannel: string): void => { readonly setName = (name: string): void => {
this.info.primaryChannel = primaryChannel; this.info.name = name;
this.storeInfo();
this.subscribe();
};
readonly setNamespace = (namespace: string): void => {
this.info.namespace = namespace;
this.storeInfo(); this.storeInfo();
this.subscribe(); this.subscribe();
}; };
@@ -184,7 +174,7 @@ export default class ChatModel {
const senderName: string = this.settingsModel.username; const senderName: string = this.settingsModel.username;
if (senderName == "") return false; if (senderName == "") return false;
const allChannels: string[] = [this.unwrappedPrimaryChannel]; const allChannels: string[] = [this.id];
for (const secondaryChannel of this.info.secondaryChannels) { for (const secondaryChannel of this.info.secondaryChannels) {
allChannels.push(secondaryChannel); allChannels.push(secondaryChannel);
} }
@@ -252,7 +242,7 @@ export default class ChatModel {
}; };
readonly subscribe = (): void => { readonly subscribe = (): void => {
this.connectionModel.addChannel(this.unwrappedPrimaryChannel); this.connectionModel.addChannel(this.id);
}; };
readonly setReadStatus = (hasUnreadMessages: boolean): void => { readonly setReadStatus = (hasUnreadMessages: boolean): void => {
@@ -273,211 +263,209 @@ export default class ChatModel {
this.storageModel.write(this.getPreviousFilterPath(), filter); this.storageModel.write(this.getPreviousFilterPath(), filter);
} }
readonly getFilter = (): string => { readonly getFilter = (): string=> {
return this.storageModel.read(this.getPreviousFilterPath()); return this.storageModel.read(this.getPreviousFilterPath()) || "";
} }
readonly delete = () => { readonly delete = () => {
// untrack // untrack
this.chatListModel.untrackChat(this); this.chatListModel.untrackChat(this);
// delete // delete
const dirPath: string[] = this.getBasePath(); const dirPath: string[] = this.getBasePath();
this.storageModel.removeRecursively(dirPath); this.storageModel.removeRecursively(dirPath);
}; };
// load // load
readonly loadInfo = (): void => { readonly loadInfo = (): void => {
const info: ChatInfo | null = this.storageModel.readStringifiable( const info: ChatInfo | null = this.storageModel.readStringifiable(
this.getInfoPath(), this.getInfoPath(),
ChatInfoReference, ChatInfoReference,
); );
if (info != null) { if (info != null) {
this.info = info; this.info = info;
} else { } else {
this.info = ChatModel.generateChatInfo("0"); this.info = ChatModel.generateChatInfo("0", "0");
} }
}; };
readonly loadColor = (): void => { readonly loadColor = (): void => {
const path: string[] = this.getColorPath(); const path: string[] = this.getColorPath();
const color: string | null = this.storageModel.read(path); const color: string | null = this.storageModel.read(path);
if (!color) { if (!color) {
this.color = Colors.Standard; this.color = Colors.Standard;
} else { } else {
this.color = color as any; this.color = color as any;
} }
}; };
get messages(): ChatMessage[] { get messages(): ChatMessage[] {
const messageIds: string[] = this.storageModel.list( const messageIds: string[] = this.storageModel.list(
this.getMessageDirPath(), this.getMessageDirPath(),
); );
if (!Array.isArray(messageIds)) return []; if (!Array.isArray(messageIds)) return [];
const chatMessages: ChatMessage[] = []; const chatMessages: ChatMessage[] = [];
for (const messageId of messageIds) { for (const messageId of messageIds) {
const messagePath: string[] = this.getMessagePath(messageId); const messagePath: string[] = this.getMessagePath(messageId);
const chatMessage: ChatMessage | null = const chatMessage: ChatMessage | null =
this.storageModel.readStringifiable( this.storageModel.readStringifiable(
messagePath, messagePath,
ChatMessageReference, ChatMessageReference,
); );
if (chatMessage == null) continue; if (chatMessage == null) continue;
chatMessages.push(chatMessage); chatMessages.push(chatMessage);
} }
const sorted = chatMessages.sort((a, b) => const sorted = chatMessages.sort((a, b) =>
a.dateSent.localeCompare(b.dateSent), a.dateSent.localeCompare(b.dateSent),
); );
return sorted; return sorted;
} }
get reactions(): ChatMessageReaction[] { get reactions(): ChatMessageReaction[] {
const reactionIds: string[] = this.storageModel.list( const reactionIds: string[] = this.storageModel.list(
this.getReactionDirPath(), this.getReactionDirPath(),
); );
if (!Array.isArray(reactionIds)) return []; if (!Array.isArray(reactionIds)) return [];
const reactions: ChatMessageReaction[] = []; const reactions: ChatMessageReaction[] = [];
for (const reactionId of reactionIds) { for (const reactionId of reactionIds) {
const reactionPath: string[] = this.getReactionPath(reactionId); const reactionPath: string[] = this.getReactionPath(reactionId);
const reaction: ChatMessageReaction | null = const reaction: ChatMessageReaction | null =
this.storageModel.readStringifiable( this.storageModel.readStringifiable(
reactionPath, reactionPath,
ChatMessageReactionReference, ChatMessageReactionReference,
); );
if (reaction == null) continue; if (reaction == null) continue;
reactions.push(reaction); reactions.push(reaction);
} }
return reactions; return reactions;
} }
// init // init
constructor( constructor(
storageModel: StorageModel, storageModel: StorageModel,
connectionModel: ConnectionModel, connectionModel: ConnectionModel,
settingsModel: SettingsModel, settingsModel: SettingsModel,
chatListModel: ChatListModel, chatListModel: ChatListModel,
chatId: string, chatId: string,
) { ) {
this.id = chatId; this.id = chatId;
this.connectionModel = connectionModel; this.connectionModel = connectionModel;
this.settingsModel = settingsModel; this.settingsModel = settingsModel;
this.storageModel = storageModel; this.storageModel = storageModel;
this.chatListModel = chatListModel; this.chatListModel = chatListModel;
this.loadInfo(); this.loadInfo();
this.loadColor(); this.loadColor();
this.subscribe(); this.subscribe();
this.fileModel = new FileModel( this.fileModel = new FileModel(
this.storageModel, this.storageModel,
this.settingsModel, this.settingsModel,
this, this,
); );
} }
// utility // utility
static splitChannel(channelString: string): string[] { static splitChannel(channelString: string): string[] {
return channelString.split("/"); return channelString.split("/");
} }
static generateChatInfo = (primaryChannel: string): ChatInfo => { static generateChatInfo = (name: string, id: string): ChatInfo => {
return { return {
dataVersion: DATA_VERSION, dataVersion: DATA_VERSION,
primaryChannel, name,
namespace: "", secondaryChannels: [],
secondaryChannels: [], encryptionKey: "",
encryptionKey: "", hasUnreadMessages: false,
hasUnreadMessages: false, };
};
}; };
static createChatMessage = async ( static createChatMessage = async (
channel: string, channel: string,
sender: string, sender: string,
encryptionKey: string, encryptionKey: string,
body: string, body: string,
inlineReplyId?: string, inlineReplyId?: string,
fileContent?: FileContent<string>, fileContent?: FileContent<string>,
): Promise<ChatMessage> => { ): Promise<ChatMessage> => {
const chatMessage: ChatMessage = { const chatMessage: ChatMessage = {
dataVersion: DATA_VERSION, dataVersion: DATA_VERSION,
id: v4(), id: v4(),
channel, channel,
sender, sender,
body, body,
dateSent: createTimestamp(), dateSent: createTimestamp(),
inlineReplyId, inlineReplyId,
status: ChatMessageStatuses.Outbox, status: ChatMessageStatuses.Outbox,
stringifiedFile: "", stringifiedFile: "",
}; };
if (fileContent != undefined) { if (fileContent != undefined) {
const stringifiedFile: string = stringify(fileContent); const stringifiedFile: string = stringify(fileContent);
chatMessage.stringifiedFile = stringifiedFile; chatMessage.stringifiedFile = stringifiedFile;
} }
if (encryptionKey != "") { if (encryptionKey != "") {
chatMessage.body = await encryptString( chatMessage.body = await encryptString(
chatMessage.body, chatMessage.body,
encryptionKey, encryptionKey,
); );
chatMessage.stringifiedFile = await encryptString( chatMessage.stringifiedFile = await encryptString(
chatMessage.stringifiedFile, chatMessage.stringifiedFile,
encryptionKey, encryptionKey,
); );
} }
return chatMessage; return chatMessage;
}; };
static createMessageReaction = ( static createMessageReaction = (
messageId: string, messageId: string,
sender: string, sender: string,
content: ReactionSymbols, content: ReactionSymbols,
isDeleting: boolean, isDeleting: boolean,
): ChatMessageReaction => { ): ChatMessageReaction => {
const fileContent: FileContent<"reaction"> = const fileContent: FileContent<"reaction"> =
FileModel.createFileContent(v4(), "reaction"); FileModel.createFileContent(v4(), "reaction");
const reaction: ChatMessageReaction = { const reaction: ChatMessageReaction = {
...fileContent, ...fileContent,
fileId: ChatModel.createMessageReactionId(messageId, sender), fileId: ChatModel.createMessageReactionId(messageId, sender),
messageId, messageId,
sender, sender,
content, content,
isDeleting, isDeleting,
}; };
return reaction; return reaction;
}; };
static createMessageReactionId = ( static createMessageReactionId = (
messageId: string, messageId: string,
sender: string, sender: string,
): string => { ): string => {
return messageId + sender; return messageId + sender;
}; };
} }
// types // types
export enum ReactionSymbols { export enum ReactionSymbols {
ThumbsUp = "👍", ThumbsUp = "👍",
Check = "✅", Check = "✅",
Stop = "🛑", Stop = "🛑",
Attention = "❗️", Attention = "❗️",
DoubleAttention = "‼️", DoubleAttention = "‼️",
Question = "❓", Question = "❓",
} }
export interface ChatInfo extends ValidObject { export interface ChatInfo extends ValidObject {
primaryChannel: string; name: string;
namespace: string;
secondaryChannels: string[]; secondaryChannels: string[];
encryptionKey: string; encryptionKey: string;
@@ -486,9 +474,9 @@ export interface ChatInfo extends ValidObject {
export enum ChatMessageStatuses { export enum ChatMessageStatuses {
Outbox = "outbox", Outbox = "outbox",
Sent = "sent", Sent = "sent",
Received = "received", Received = "received",
Other = "other", Other = "other",
} }
export interface ChatMessage extends ValidObject { export interface ChatMessage extends ValidObject {
@@ -506,7 +494,7 @@ export interface ChatMessage extends ValidObject {
} }
export interface ChatMessageReaction export interface ChatMessageReaction
extends ValidObject, FileContent<"reaction"> { extends ValidObject, FileContent<"reaction"> {
readonly messageId: string; readonly messageId: string;
readonly sender: string; readonly sender: string;
readonly content: ReactionSymbols | string; readonly content: ReactionSymbols | string;
@@ -517,8 +505,7 @@ export interface ChatMessageReaction
export const ChatInfoReference: ChatInfo = { export const ChatInfoReference: ChatInfo = {
dataVersion: DATA_VERSION, dataVersion: DATA_VERSION,
primaryChannel: "", name: "",
namespace: "",
secondaryChannels: [""], secondaryChannels: [""],
encryptionKey: "", encryptionKey: "",
+1 -1
View File
@@ -78,7 +78,7 @@ messagePageViewModel.focusSetter.subscribeSilent(() => {
const isInReplyView = React.createProxyState([messagePageViewModel.replyViewSelectedMessage], ()=>messagePageViewModel.replyViewSelectedMessage.value != undefined); const isInReplyView = React.createProxyState([messagePageViewModel.replyViewSelectedMessage], ()=>messagePageViewModel.replyViewSelectedMessage.value != undefined);
const title = React.createProxyState([messagePageViewModel.isReplyViewActive], ()=>messagePageViewModel.isReplyViewActive.value ? coreViewModel.translations.chatPage.message.replyHeaderLabel(messagePageViewModel.replyViewSelectedMessage.value.body.value) : coreViewModel.translations.chatPage.message.messagesHeadline); const title = React.createProxyState([messagePageViewModel.isReplyViewActive], ()=>messagePageViewModel.isReplyViewActive.value ? coreViewModel.translations.chatPage.message.replyHeaderLabel((messagePageViewModel.replyViewSelectedMessage.value!).body.value) : coreViewModel.translations.chatPage.message.messagesHeadline);
return ( return (
<div id="message-page" toggle:reply-view={isInReplyView}> <div id="message-page" toggle:reply-view={isInReplyView}>
+3 -41
View File
@@ -48,10 +48,10 @@ export function SettingsPage(
</span> </span>
<input <input
bind:value={ bind:value={
settingsPageViewModel.primaryChannelInput settingsPageViewModel.nameInput
} }
on:enter={ on:enter={
settingsPageViewModel.setPrimaryChannel settingsPageViewModel.setName
} }
></input> ></input>
</div> </div>
@@ -64,7 +64,7 @@ export function SettingsPage(
.setPrimaryChannelButtonAudioLabel .setPrimaryChannelButtonAudioLabel
} }
on:click={ on:click={
settingsPageViewModel.setPrimaryChannel settingsPageViewModel.setName
} }
toggle:disabled={ toggle:disabled={
settingsPageViewModel.cannotSetPrimaryChannel settingsPageViewModel.cannotSetPrimaryChannel
@@ -77,44 +77,6 @@ export function SettingsPage(
<hr></hr> <hr></hr>
<label class="tile flex-no">
<span class="icon">category</span>
<div>
<span>
{
coreViewModel.translations.chatPage
.settings.namespaceLabel
}
</span>
<input
bind:value={
settingsPageViewModel.namespaceInput
}
on:enter={
settingsPageViewModel.setNamespace
}
></input>
</div>
</label>
<div class="flex-row justify-end width-input">
<button
class="width-50"
aria-label={
coreViewModel.translations.chatPage.settings
.setNamespaceButtonAudioLabel
}
on:click={settingsPageViewModel.setNamespace}
toggle:disabled={
settingsPageViewModel.cannotSetNamespace
}
>
{coreViewModel.translations.general.setButton}
<span class="icon">check</span>
</button>
</div>
<hr></hr>
<div class="flex-row width-input margin-bottom"> <div class="flex-row width-input margin-bottom">
<input <input
aria-label={ aria-label={
+2 -2
View File
@@ -13,12 +13,12 @@ export function ChatEntry(chatViewModel: ChatViewModel) {
<span <span
class="shadow" class="shadow"
subscribe:innerText={ subscribe:innerText={
chatViewModel.settingsPageViewModel.primaryChannel chatViewModel.settingsPageViewModel.name
} }
></span> ></span>
<h2 <h2
subscribe:innerText={ subscribe:innerText={
chatViewModel.settingsPageViewModel.primaryChannel chatViewModel.settingsPageViewModel.name
} }
></h2> ></h2>
</button> </button>
+4 -4
View File
@@ -13,7 +13,7 @@ export default class ChatListViewModel {
// data // data
readonly chatIndexManager = new IndexManager<ChatViewModel>( readonly chatIndexManager = new IndexManager<ChatViewModel>(
(chatViewModel: ChatViewModel) => (chatViewModel: ChatViewModel) =>
chatViewModel.settingsPageViewModel.primaryChannel.value, chatViewModel.settingsPageViewModel.name.value,
); );
// state // state
@@ -104,10 +104,10 @@ export default class ChatListViewModel {
} }
// utility // utility
stripNamespace = (fullChannel: string): string => { getDisplayName = (fullChannel: string): string => {
for (const vm of this.chatViewModels.value) { for (const vm of this.chatViewModels.value) {
const fullReference = vm.chatModel.unwrappedPrimaryChannel; const fullReference = vm.chatModel.id;
if (fullReference == fullChannel) return vm.chatModel.info.primaryChannel; if (fullReference == fullChannel) return vm.chatModel.info.name;
} }
return fullChannel; return fullChannel;
+1 -1
View File
@@ -184,7 +184,7 @@ export default class ChatMessageViewModel {
this.messagePageViewModel.chatMessageViewModels.value.get( this.messagePageViewModel.chatMessageViewModels.value.get(
this.chatMessage.inlineReplyId, this.chatMessage.inlineReplyId,
); );
this.inlineReply.replies.set(this.chatMessage.id, this); this.inlineReply?.replies.set(this.chatMessage.id, this);
} }
}; };
@@ -128,7 +128,7 @@ export default class FileTransferViewModel extends Context {
this.coreViewModel.chatListModel.chatModels; this.coreViewModel.chatListModel.chatModels;
for (const chatModel of chatModels) { for (const chatModel of chatModels) {
this.chatFileOptions.add({ this.chatFileOptions.add({
label: chatModel.unwrappedPrimaryChannel, label: chatModel.info.name,
path: chatModel.getBasePath(), path: chatModel.getBasePath(),
}); });
} }
@@ -20,7 +20,7 @@ export default class NotificationViewModel {
this.createNotification(message); this.createNotification(message);
const currentChat = const currentChat =
this.chatListViewModel.selectedChat.value.chatModel this.chatListViewModel.selectedChat.value.chatModel
.unwrappedPrimaryChannel; .id;
const currentPage = const currentPage =
this.chatListViewModel.selectedChat.value.selectedPage.value; this.chatListViewModel.selectedChat.value.selectedPage.value;
if ( if (
@@ -41,7 +41,7 @@ export default class NotificationViewModel {
...this.chatListViewModel.chatViewModels.value.values(), ...this.chatListViewModel.chatViewModels.value.values(),
].find( ].find(
(chat) => (chat) =>
chat.chatModel.unwrappedPrimaryChannel == notification.fullChannel, chat.chatModel.id == notification.fullChannel,
); );
if (!chat) return; if (!chat) return;
chat.open(); chat.open();
@@ -87,7 +87,7 @@ export default class NotificationViewModel {
// util // util
createNotification(message: ChatMessage): Notification { createNotification(message: ChatMessage): Notification {
const fullChannel = ChatModel.splitChannel(message.channel)[0]; const fullChannel = ChatModel.splitChannel(message.channel)[0];
const chat = this.chatListViewModel.stripNamespace(fullChannel); const chat = this.chatListViewModel.getDisplayName(fullChannel);
return { return {
messageId: message.id, messageId: message.id,
chat, chat,
+1 -1
View File
@@ -40,7 +40,7 @@ export default class CalendarPageViewModel extends TaskContainingPageViewModel {
MonthGrid<React.MapState<TaskViewModel>> | undefined MonthGrid<React.MapState<TaskViewModel>> | undefined
> = new React.State<any>(undefined); > = new React.State<any>(undefined);
nextTask: React.State<TaskViewModel|undefined> = new React.State(undefined); nextTask = new React.State<TaskViewModel|undefined>(undefined);
// methods // methods
createEvent = (): void => { createEvent = (): void => {
+1 -1
View File
@@ -16,7 +16,7 @@ export default class MessagePageViewModel extends Context {
new React.MapState(); new React.MapState();
filteredMessageViewModels: React.ListState<ChatMessageViewModel> = filteredMessageViewModels: React.ListState<ChatMessageViewModel> =
new React.ListState(); new React.ListState();
replyViewSelectedMessage: React.State<ChatMessageViewModel|undefined> = new React.State(undefined); replyViewSelectedMessage = new React.State<ChatMessageViewModel|undefined>(undefined);
isReplyViewActive: React.State<boolean> = React.createProxyState([this.replyViewSelectedMessage], ()=>this.replyViewSelectedMessage.value != undefined); isReplyViewActive: React.State<boolean> = React.createProxyState([this.replyViewSelectedMessage], ()=>this.replyViewSelectedMessage.value != undefined);
isReplyViewInactive = React.createProxyState([this.isReplyViewActive], ()=>!this.isReplyViewActive.value); isReplyViewInactive = React.createProxyState([this.isReplyViewActive], ()=>!this.isReplyViewActive.value);
searchViewModel: SearchViewModel<ChatMessageViewModel>; searchViewModel: SearchViewModel<ChatMessageViewModel>;
+13 -27
View File
@@ -5,11 +5,8 @@ import { Colors } from "../../colors";
export default class SettingsPageViewModel extends Context { export default class SettingsPageViewModel extends Context {
// state // state
primaryChannel: React.State<string> = new React.State(""); name: React.State<string> = new React.State("");
primaryChannelInput: React.State<string> = new React.State(""); nameInput: React.State<string> = new React.State("");
namespace: React.State<string> = new React.State("");
namespaceInput: React.State<string> = new React.State("");
secondaryChannels: React.ListState<string> = new React.ListState(); secondaryChannels: React.ListState<string> = new React.ListState();
newSecondaryChannelInput: React.State<string> = new React.State(""); newSecondaryChannelInput: React.State<string> = new React.State("");
@@ -25,14 +22,10 @@ export default class SettingsPageViewModel extends Context {
// guards // guards
cannotSetPrimaryChannel: React.State<boolean> = React.createProxyState( cannotSetPrimaryChannel: React.State<boolean> = React.createProxyState(
[this.primaryChannel, this.primaryChannelInput], [this.name, this.nameInput],
() => () =>
this.primaryChannelInput.value == "" || this.nameInput.value == "" ||
this.primaryChannelInput.value == this.primaryChannel.value, this.nameInput.value == this.name.value,
);
cannotSetNamespace: React.State<boolean> = React.createProxyState(
[this.namespace, this.namespaceInput],
() => this.namespaceInput.value == this.namespace.value,
); );
cannotAddSecondaryChannel: React.State<boolean> = React.createProxyState( cannotAddSecondaryChannel: React.State<boolean> = React.createProxyState(
[this.newSecondaryChannelInput], [this.newSecondaryChannelInput],
@@ -41,21 +34,16 @@ export default class SettingsPageViewModel extends Context {
cannotSetEncryptionKey: React.State<boolean>; cannotSetEncryptionKey: React.State<boolean>;
// methods // methods
setPrimaryChannel = (): void => { setName = (): void => {
this.chatViewModel.chatModel.setPrimaryChannel( this.chatViewModel.chatModel.setName(
this.primaryChannelInput.value, this.nameInput.value,
); );
this.primaryChannel.value = this.name.value =
this.chatViewModel.chatModel.info.primaryChannel; this.chatViewModel.chatModel.info.name;
this.chatViewModel.chatListViewModel.updateIndices(); this.chatViewModel.chatListViewModel.updateIndices();
}; };
setNamespace = (): void => {
this.chatViewModel.chatModel.setNamespace(this.namespaceInput.value);
this.namespace.value = this.chatViewModel.chatModel.info.namespace;
};
addSecondaryChannel = (): void => { addSecondaryChannel = (): void => {
this.secondaryChannels.add(this.newSecondaryChannelInput.value); this.secondaryChannels.add(this.newSecondaryChannelInput.value);
this.newSecondaryChannelInput.value = ""; this.newSecondaryChannelInput.value = "";
@@ -95,16 +83,14 @@ export default class SettingsPageViewModel extends Context {
// load // load
preloadData = (): void => { preloadData = (): void => {
this.primaryChannel.value = this.name.value =
this.chatViewModel.chatModel.info.primaryChannel; this.chatViewModel.chatModel.info.name;
this.namespace.value = this.chatViewModel.chatModel.info.namespace;
this.color.value = this.chatViewModel.chatModel.color; this.color.value = this.chatViewModel.chatModel.color;
}; };
loadData = (): void => { loadData = (): void => {
this.primaryChannelInput.value = this.primaryChannel.value; this.nameInput.value = this.name.value;
this.namespaceInput.value = this.namespace.value;
this.loadSecondaryChannels(); this.loadSecondaryChannels();