Added an option for mass channel subscription and unsubscription

canary
WolverinDEV 2020-12-04 13:58:05 +01:00
parent 3ec0f32634
commit 6f460ae111
4 changed files with 103 additions and 10 deletions

View File

@ -2,6 +2,7 @@
* **04.12.20** * **04.12.20**
- Properly logging channel creations, deletions, shows and hides - Properly logging channel creations, deletions, shows and hides
- Fixed missing collapsed arrow update after channel move - Fixed missing collapsed arrow update after channel move
- Added an option for mass channel subscription and unsubscription
* **03.12.20** * **03.12.20**
- Fixed server connection tab move handler - Fixed server connection tab move handler

View File

@ -753,14 +753,16 @@ export class ChannelEntry extends ChannelTreeEntry<ChannelEvents> {
return this.subscriptionMode; return this.subscriptionMode;
} }
setSubscriptionMode(mode: ChannelSubscribeMode) { setSubscriptionMode(mode: ChannelSubscribeMode, dontSyncSubscribeMode?: boolean) {
if(this.subscriptionMode === mode) { if(this.subscriptionMode === mode) {
return; return;
} }
this.subscriptionMode = mode; this.subscriptionMode = mode;
this.channelTree.client.settings.changeServer(Settings.FN_SERVER_CHANNEL_SUBSCRIBE_MODE(this.channelId), mode); this.channelTree.client.settings.changeServer(Settings.FN_SERVER_CHANNEL_SUBSCRIBE_MODE(this.channelId), mode);
this.updateSubscribeMode().then(undefined); if(!dontSyncSubscribeMode) {
this.updateSubscribeMode().then(undefined);
}
} }
log_data() : EventChannelData { log_data() : EventChannelData {

View File

@ -3,7 +3,6 @@ import {MenuEntryType} from "tc-shared/ui/elements/ContextMenu";
import * as log from "tc-shared/log"; import * as log from "tc-shared/log";
import {LogCategory, logError, logWarn} from "tc-shared/log"; import {LogCategory, logError, logWarn} from "tc-shared/log";
import {PermissionType} from "tc-shared/permission/PermissionType"; import {PermissionType} from "tc-shared/permission/PermissionType";
import {SpecialKey} from "tc-shared/PPTListener";
import {Sound} from "tc-shared/sound/Sounds"; import {Sound} from "tc-shared/sound/Sounds";
import {Group} from "tc-shared/permission/GroupManager"; import {Group} from "tc-shared/permission/GroupManager";
import {ServerAddress, ServerEntry} from "./Server"; import {ServerAddress, ServerEntry} from "./Server";
@ -15,7 +14,6 @@ import {createChannelModal} from "tc-shared/ui/modal/ModalCreateChannel";
import {Registry} from "tc-shared/events"; import {Registry} from "tc-shared/events";
import * as ReactDOM from "react-dom"; import * as ReactDOM from "react-dom";
import * as React from "react"; import * as React from "react";
import * as ppt from "tc-backend/ppt";
import {batch_updates, BatchUpdateType, flush_batched_updates} from "tc-shared/ui/react-elements/ReactComponentBase"; import {batch_updates, BatchUpdateType, flush_batched_updates} from "tc-shared/ui/react-elements/ReactComponentBase";
import {createInputModal} from "tc-shared/ui/elements/Modal"; import {createInputModal} from "tc-shared/ui/elements/Modal";
@ -23,11 +21,10 @@ import {spawnBanClient} from "tc-shared/ui/modal/ModalBanClient";
import {formatMessage} from "tc-shared/ui/frames/chat"; import {formatMessage} from "tc-shared/ui/frames/chat";
import {spawnYesNo} from "tc-shared/ui/modal/ModalYesNo"; import {spawnYesNo} from "tc-shared/ui/modal/ModalYesNo";
import {tra} from "tc-shared/i18n/localize"; import {tra} from "tc-shared/i18n/localize";
import {EventType} from "tc-shared/ui/frames/log/Definitions";
import {renderChannelTree} from "tc-shared/ui/tree/Controller"; import {renderChannelTree} from "tc-shared/ui/tree/Controller";
import {ChannelTreePopoutController} from "tc-shared/ui/tree/popout/Controller"; import {ChannelTreePopoutController} from "tc-shared/ui/tree/popout/Controller";
import {Settings, settings} from "tc-shared/settings"; import {Settings, settings} from "tc-shared/settings";
import {ServerConnection} from "tc-backend/web/connection/ServerConnection"; import {ClientIcon} from "svg-sprites/client-icons";
export interface ChannelTreeEvents { export interface ChannelTreeEvents {
/* general tree notified */ /* general tree notified */
@ -536,7 +533,7 @@ export class ChannelTree {
const server = entries.find(e => e instanceof ServerEntry) as ServerEntry; const server = entries.find(e => e instanceof ServerEntry) as ServerEntry;
let client_menu: contextmenu.MenuEntry[]; let client_menu: contextmenu.MenuEntry[];
let channel_menu: contextmenu.MenuEntry[]; let channelMenu: contextmenu.MenuEntry[];
let server_menu: contextmenu.MenuEntry[]; let server_menu: contextmenu.MenuEntry[];
if(clients.length > 0) { if(clients.length > 0) {
@ -681,11 +678,87 @@ export class ChannelTree {
} }
} }
} }
if(channels.length > 0) { if(channels.length > 0) {
channel_menu = []; channelMenu = [];
channelMenu.push({
type: MenuEntryType.ENTRY,
name: tr("Subscribe to channels"),
icon_class: ClientIcon.SubscribeToAllChannels,
callback: () => {
const bulks = channels.filter(channel => {
channel.setSubscriptionMode(ChannelSubscribeMode.SUBSCRIBED, false);
return !channel.isSubscribed();
}).map(channel => {
return {
cid: channel.channelId
};
});
if(bulks.length === 0) {
/* shall not happen */
return;
}
this.client.serverConnection.send_command("channelsubscribe", bulks);
},
visible: channels.findIndex(channel => channel.getSubscriptionMode() !== ChannelSubscribeMode.SUBSCRIBED) !== -1
});
channelMenu.push({
type: MenuEntryType.ENTRY,
name: tr("Unsubscribe from channels"),
icon_class: ClientIcon.UnsubscribeFromAllChannels,
callback: () => {
const bulks = channels.filter(channel => {
channel.setSubscriptionMode(ChannelSubscribeMode.UNSUBSCRIBED, false);
return channel.isSubscribed();
}).map(channel => {
return {
cid: channel.channelId
};
});
if(bulks.length === 0) {
/* shall not happen */
return;
}
this.client.serverConnection.send_command("channelunsubscribe", bulks);
},
visible: channels.findIndex(channel => channel.getSubscriptionMode() !== ChannelSubscribeMode.UNSUBSCRIBED) !== -1
});
channelMenu.push({
type: MenuEntryType.ENTRY,
name: tr("Use inherited subscribe mode"),
icon_class: ClientIcon.SubscribeToAllChannels,
callback: () => {
const inheritedSubscribe = this.client.isSubscribeToAllChannels();
const bulks = channels.filter(channel => {
channel.setSubscriptionMode(ChannelSubscribeMode.INHERITED, false);
return channel.isSubscribed() != inheritedSubscribe;
}).map(channel => {
return {
cid: channel.channelId
};
});
if(bulks.length === 0) {
/* might happen */
return;
}
this.client.serverConnection.send_command(inheritedSubscribe ? "channelsubscribe" : "channelunsubscribe", bulks);
},
visible: channels.findIndex(channel => channel.getSubscriptionMode() !== ChannelSubscribeMode.INHERITED) !== -1
});
channelMenu.push(contextmenu.Entry.HR());
//TODO: Subscribe mode settings //TODO: Subscribe mode settings
channel_menu.push({ channelMenu.push({
type: MenuEntryType.ENTRY, type: MenuEntryType.ENTRY,
name: tr("Delete all channels"), name: tr("Delete all channels"),
icon_class: "client-delete", icon_class: "client-delete",
@ -712,7 +785,7 @@ export class ChannelTree {
}, },
{ {
text: tr("Apply to all channels"), text: tr("Apply to all channels"),
menu: channel_menu, menu: channelMenu,
icon: "client-channel_green" icon: "client-channel_green"
}, },
{ {

View File

@ -253,6 +253,8 @@ export class RDPChannelTree {
popoutShown: boolean = false; popoutShown: boolean = false;
popoutButtonShown: boolean = false; popoutButtonShown: boolean = false;
private readonly documentDragStopListener;
private treeRevision: number = 0; private treeRevision: number = 0;
private orderedTree: RDPEntry[] = []; private orderedTree: RDPEntry[] = [];
private treeEntries: {[key: number]: RDPEntry} = {}; private treeEntries: {[key: number]: RDPEntry} = {};
@ -263,6 +265,13 @@ export class RDPChannelTree {
this.events = events; this.events = events;
this.handlerId = handlerId; this.handlerId = handlerId;
this.selection = new RDPTreeSelection(this); this.selection = new RDPTreeSelection(this);
this.documentDragStopListener = () => {
if(this.dragOverChannelEntry) {
this.dragOverChannelEntry.setDragHint("none");
this.dragOverChannelEntry = undefined;
}
}
} }
initialize() { initialize() {
@ -380,12 +389,20 @@ export class RDPChannelTree {
} }
})); }));
document.addEventListener("dragend", this.documentDragStopListener);
document.addEventListener("focusout", this.documentDragStopListener);
document.addEventListener("mouseout", this.documentDragStopListener);
this.events.fire("query_tree_entries"); this.events.fire("query_tree_entries");
this.events.fire("query_popout_state"); this.events.fire("query_popout_state");
this.events.fire("query_selected_entry"); this.events.fire("query_selected_entry");
} }
destroy() { destroy() {
document.removeEventListener("dragend", this.documentDragStopListener);
document.removeEventListener("focusout", this.documentDragStopListener);
document.removeEventListener("mouseout", this.documentDragStopListener);
this.events.unregister_handler(this); this.events.unregister_handler(this);
this.registeredEventHandlers.forEach(callback => callback()); this.registeredEventHandlers.forEach(callback => callback());
this.registeredEventHandlers = []; this.registeredEventHandlers = [];