Using a React modal for the YesNo prompt and ensured that only string will be passed
parent
5ef2d85d6f
commit
a414caef42
|
@ -7,7 +7,6 @@ import {LogCategory, logDebug, logError, logInfo, logWarn} from "tc-shared/log";
|
||||||
import {ConnectionHandler} from "tc-shared/ConnectionHandler";
|
import {ConnectionHandler} from "tc-shared/ConnectionHandler";
|
||||||
import {createErrorModal, createInfoModal} from "tc-shared/ui/elements/Modal";
|
import {createErrorModal, createInfoModal} from "tc-shared/ui/elements/Modal";
|
||||||
import {RecorderProfile, setDefaultRecorder} from "tc-shared/voice/RecorderProfile";
|
import {RecorderProfile, setDefaultRecorder} from "tc-shared/voice/RecorderProfile";
|
||||||
import {spawnYesNo} from "tc-shared/ui/modal/ModalYesNo";
|
|
||||||
import {formatMessage} from "tc-shared/ui/frames/chat";
|
import {formatMessage} from "tc-shared/ui/frames/chat";
|
||||||
import {openModalNewcomer} from "tc-shared/ui/modal/ModalNewcomer";
|
import {openModalNewcomer} from "tc-shared/ui/modal/ModalNewcomer";
|
||||||
import {global_client_actions} from "tc-shared/events/GlobalEvents";
|
import {global_client_actions} from "tc-shared/events/GlobalEvents";
|
||||||
|
@ -53,6 +52,7 @@ import "./text/bbcode/InviteController";
|
||||||
import "./text/bbcode/YoutubeController";
|
import "./text/bbcode/YoutubeController";
|
||||||
import {initializeSounds, setSoundMasterVolume} from "./audio/Sounds";
|
import {initializeSounds, setSoundMasterVolume} from "./audio/Sounds";
|
||||||
import {getInstanceConnectHandler, setupIpcHandler} from "./ipc/BrowserIPC";
|
import {getInstanceConnectHandler, setupIpcHandler} from "./ipc/BrowserIPC";
|
||||||
|
import {promptYesNo} from "tc-shared/ui/modal/yes-no/Controller";
|
||||||
|
|
||||||
assertMainApplication();
|
assertMainApplication();
|
||||||
|
|
||||||
|
@ -203,11 +203,12 @@ async function doHandleConnectRequest(serverAddress: string, serverUniqueId: str
|
||||||
|
|
||||||
if(!getAudioBackend().isInitialized()) {
|
if(!getAudioBackend().isInitialized()) {
|
||||||
/* Trick the client into clicking somewhere on the site to initialize audio */
|
/* Trick the client into clicking somewhere on the site to initialize audio */
|
||||||
const resultPromise = new Promise<boolean>(resolve => {
|
const result = await promptYesNo({
|
||||||
spawnYesNo(tra("Connect to {}", serverAddress), tra("Would you like to connect to {}?", serverAddress), resolve).open();
|
title: tra("Connect to {}", serverAddress),
|
||||||
|
question: tra("Would you like to connect to {}?", serverAddress)
|
||||||
});
|
});
|
||||||
|
|
||||||
if(!(await resultPromise)) {
|
if(!result) {
|
||||||
/* Well... the client don't want to... */
|
/* Well... the client don't want to... */
|
||||||
return { status: "client-aborted" };
|
return { status: "client-aborted" };
|
||||||
}
|
}
|
||||||
|
@ -441,13 +442,12 @@ const task_connect_handler: loader.Task = {
|
||||||
const chandler = getInstanceConnectHandler();
|
const chandler = getInstanceConnectHandler();
|
||||||
if(chandler && AppParameters.getValue(AppParameters.KEY_CONNECT_NO_SINGLE_INSTANCE)) {
|
if(chandler && AppParameters.getValue(AppParameters.KEY_CONNECT_NO_SINGLE_INSTANCE)) {
|
||||||
try {
|
try {
|
||||||
await chandler.post_connect_request(connectData, () => new Promise<boolean>(resolve => {
|
await chandler.post_connect_request(connectData, async () => {
|
||||||
spawnYesNo(tr("Another TeaWeb instance is already running"), tra("Another TeaWeb instance is already running.\nWould you like to connect there?"), response => {
|
return await promptYesNo({
|
||||||
resolve(response);
|
title: tr("Another TeaWeb instance is already running"),
|
||||||
}, {
|
question: tra("Another TeaWeb instance is already running.\nWould you like to connect there?")
|
||||||
closeable: false
|
});
|
||||||
}).open();
|
});
|
||||||
}));
|
|
||||||
logInfo(LogCategory.CLIENT, tr("Executed connect successfully in another browser window. Closing this window"));
|
logInfo(LogCategory.CLIENT, tr("Executed connect successfully in another browser window. Closing this window"));
|
||||||
|
|
||||||
createInfoModal(
|
createInfoModal(
|
||||||
|
|
|
@ -10,13 +10,10 @@ import {ClientEntry, LocalClientEntry, MusicClientEntry} from "./Client";
|
||||||
import {ChannelTreeEntry} from "./ChannelTreeEntry";
|
import {ChannelTreeEntry} from "./ChannelTreeEntry";
|
||||||
import {ConnectionHandler, ViewReasonId} from "tc-shared/ConnectionHandler";
|
import {ConnectionHandler, ViewReasonId} from "tc-shared/ConnectionHandler";
|
||||||
import {Registry} from "tc-shared/events";
|
import {Registry} from "tc-shared/events";
|
||||||
import * as React from "react";
|
|
||||||
|
|
||||||
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";
|
||||||
import {spawnBanClient} from "tc-shared/ui/modal/ModalBanClient";
|
import {spawnBanClient} from "tc-shared/ui/modal/ModalBanClient";
|
||||||
import {formatMessage} from "tc-shared/ui/frames/chat";
|
import {formatMessageString} from "tc-shared/ui/frames/chat";
|
||||||
import {spawnYesNo} from "tc-shared/ui/modal/ModalYesNo";
|
|
||||||
import {tr, tra} from "tc-shared/i18n/localize";
|
import {tr, tra} from "tc-shared/i18n/localize";
|
||||||
import {initializeChannelTreeUiEvents} from "tc-shared/ui/tree/Controller";
|
import {initializeChannelTreeUiEvents} from "tc-shared/ui/tree/Controller";
|
||||||
import {ChannelTreePopoutController} from "tc-shared/ui/tree/popout/Controller";
|
import {ChannelTreePopoutController} from "tc-shared/ui/tree/popout/Controller";
|
||||||
|
@ -26,6 +23,7 @@ import {ClientIcon} from "svg-sprites/client-icons";
|
||||||
import "./EntryTagsHandler";
|
import "./EntryTagsHandler";
|
||||||
import {spawnChannelEditNew} from "tc-shared/ui/modal/channel-edit/Controller";
|
import {spawnChannelEditNew} from "tc-shared/ui/modal/channel-edit/Controller";
|
||||||
import {ChannelTreeUIEvents} from "tc-shared/ui/tree/Definitions";
|
import {ChannelTreeUIEvents} from "tc-shared/ui/tree/Definitions";
|
||||||
|
import {promptYesNo} from "tc-shared/ui/modal/yes-no/Controller";
|
||||||
|
|
||||||
export interface ChannelTreeEvents {
|
export interface ChannelTreeEvents {
|
||||||
/* general tree notified */
|
/* general tree notified */
|
||||||
|
@ -694,16 +692,19 @@ export class ChannelTree {
|
||||||
disabled: false,
|
disabled: false,
|
||||||
callback: () => {
|
callback: () => {
|
||||||
const param_string = clients.map((_, index) => "{" + index + "}").join(', ');
|
const param_string = clients.map((_, index) => "{" + index + "}").join(', ');
|
||||||
const param_values = clients.map(client => client.createChatTag(true));
|
const param_values = clients.map(client => client.clientNickName());
|
||||||
const tag = $.spawn("div").append(...formatMessage(tr("Do you really want to delete ") + param_string, ...param_values));
|
promptYesNo({
|
||||||
const tag_container = $.spawn("div").append(tag);
|
title: tr("Are you sure?"),
|
||||||
spawnYesNo(tr("Are you sure?"), tag_container, result => {
|
question: formatMessageString(tr("Do you really want to delete ") + param_string, ...param_values)
|
||||||
if(result) {
|
}).then(result => {
|
||||||
for(const client of clients) {
|
if(!result) {
|
||||||
this.client.serverConnection.send_command("musicbotdelete", {
|
return;
|
||||||
botid: client.properties.client_database_id
|
}
|
||||||
});
|
|
||||||
}
|
for(const client of clients) {
|
||||||
|
this.client.serverConnection.send_command("musicbotdelete", {
|
||||||
|
botid: client.properties.client_database_id
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
@ -797,11 +798,16 @@ export class ChannelTree {
|
||||||
name: tr("Delete all channels"),
|
name: tr("Delete all channels"),
|
||||||
icon_class: "client-delete",
|
icon_class: "client-delete",
|
||||||
callback: () => {
|
callback: () => {
|
||||||
spawnYesNo(tr("Are you sure?"), tra("Do you really want to delete {0} channels?", channels.length), result => {
|
promptYesNo({
|
||||||
if(typeof result === "boolean" && result) {
|
title: tr("Are you sure?"),
|
||||||
for(const channel of channels) {
|
question: tra("Do you really want to delete {0} channels?", channels.length)
|
||||||
this.client.serverConnection.send_command("channeldelete", { cid: channel.channelId });
|
}).then(result => {
|
||||||
}
|
if(!result) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(const channel of channels) {
|
||||||
|
this.client.serverConnection.send_command("channeldelete", { cid: channel.channelId });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,8 +15,6 @@ import {ConnectionHandler, ViewReasonId} from "../ConnectionHandler";
|
||||||
import {openClientInfo} from "../ui/modal/ModalClientInfo";
|
import {openClientInfo} from "../ui/modal/ModalClientInfo";
|
||||||
import {spawnBanClient} from "../ui/modal/ModalBanClient";
|
import {spawnBanClient} from "../ui/modal/ModalBanClient";
|
||||||
import {spawnChangeLatency} from "../ui/modal/ModalChangeLatency";
|
import {spawnChangeLatency} from "../ui/modal/ModalChangeLatency";
|
||||||
import {formatMessage} from "../ui/frames/chat";
|
|
||||||
import {spawnYesNo} from "../ui/modal/ModalYesNo";
|
|
||||||
import * as hex from "../crypto/hex";
|
import * as hex from "../crypto/hex";
|
||||||
import {ChannelTreeEntry, ChannelTreeEntryEvents} from "./ChannelTreeEntry";
|
import {ChannelTreeEntry, ChannelTreeEntryEvents} from "./ChannelTreeEntry";
|
||||||
import {spawnClientVolumeChange, spawnMusicBotVolumeChange} from "../ui/modal/ModalChangeVolumeNew";
|
import {spawnClientVolumeChange, spawnMusicBotVolumeChange} from "../ui/modal/ModalChangeVolumeNew";
|
||||||
|
@ -27,10 +25,11 @@ import {VoiceClient} from "../voice/VoiceClient";
|
||||||
import {VoicePlayerEvents, VoicePlayerState} from "../voice/VoicePlayer";
|
import {VoicePlayerEvents, VoicePlayerState} from "../voice/VoicePlayer";
|
||||||
import {ChannelTreeUIEvents} from "tc-shared/ui/tree/Definitions";
|
import {ChannelTreeUIEvents} from "tc-shared/ui/tree/Definitions";
|
||||||
import {VideoClient} from "tc-shared/connection/VideoConnection";
|
import {VideoClient} from "tc-shared/connection/VideoConnection";
|
||||||
import { tr } from "tc-shared/i18n/localize";
|
import {tr, tra} from "tc-shared/i18n/localize";
|
||||||
import {EventClient} from "tc-shared/connectionlog/Definitions";
|
import {EventClient} from "tc-shared/connectionlog/Definitions";
|
||||||
import {W2GPluginCmdHandler} from "tc-shared/ui/modal/video-viewer/W2GPlugin";
|
import {W2GPluginCmdHandler} from "tc-shared/ui/modal/video-viewer/W2GPlugin";
|
||||||
import {spawnServerGroupAssignments} from "tc-shared/ui/modal/group-assignment/Controller";
|
import {spawnServerGroupAssignments} from "tc-shared/ui/modal/group-assignment/Controller";
|
||||||
|
import {promptYesNo} from "tc-shared/ui/modal/yes-no/Controller";
|
||||||
|
|
||||||
export enum ClientType {
|
export enum ClientType {
|
||||||
CLIENT_VOICE,
|
CLIENT_VOICE,
|
||||||
|
@ -1236,13 +1235,17 @@ export class MusicClientEntry extends ClientEntry<MusicClientEvents> {
|
||||||
icon_class: "client-delete",
|
icon_class: "client-delete",
|
||||||
disabled: false,
|
disabled: false,
|
||||||
callback: () => {
|
callback: () => {
|
||||||
const tag = $.spawn("div").append(formatMessage(tr("Do you really want to delete {0}"), this.createChatTag(false)));
|
promptYesNo({
|
||||||
spawnYesNo(tr("Are you sure?"), $.spawn("div").append(tag), result => {
|
title: tr("Are you sure?"),
|
||||||
if(result) {
|
question: tra("Do you really want to delete {0}", this.clientNickName())
|
||||||
this.channelTree.client.serverConnection.send_command("musicbotdelete", {
|
}).then(result => {
|
||||||
bot_id: this.properties.client_database_id
|
if(!result) {
|
||||||
}).then(() => {});
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.channelTree.client.serverConnection.send_command("musicbotdelete", {
|
||||||
|
bot_id: this.properties.client_database_id
|
||||||
|
}).then(() => {});
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
type: contextmenu.MenuEntryType.ENTRY
|
type: contextmenu.MenuEntryType.ENTRY
|
||||||
|
|
|
@ -2,10 +2,10 @@ import {createErrorModal, createModal} from "../../ui/elements/Modal";
|
||||||
import {LogCategory, logError} from "../../log";
|
import {LogCategory, logError} from "../../log";
|
||||||
import {ConnectionHandler} from "../../ConnectionHandler";
|
import {ConnectionHandler} from "../../ConnectionHandler";
|
||||||
import {base64_encode_ab} from "../../utils/buffers";
|
import {base64_encode_ab} from "../../utils/buffers";
|
||||||
import {spawnYesNo} from "../../ui/modal/ModalYesNo";
|
|
||||||
import {ClientEntry} from "../../tree/Client";
|
import {ClientEntry} from "../../tree/Client";
|
||||||
import moment from "moment";
|
import moment from "moment";
|
||||||
import {tr} from "tc-shared/i18n/localize";
|
import {tr} from "tc-shared/i18n/localize";
|
||||||
|
import {promptYesNo} from "tc-shared/ui/modal/yes-no/Controller";
|
||||||
|
|
||||||
const avatar_to_uid = (id: string) => {
|
const avatar_to_uid = (id: string) => {
|
||||||
const buffer = new Uint8Array(id.length / 2);
|
const buffer = new Uint8Array(id.length / 2);
|
||||||
|
@ -90,7 +90,10 @@ export function spawnAvatarList(client: ConnectionHandler) {
|
||||||
*/
|
*/
|
||||||
|
|
||||||
callback_delete = () => {
|
callback_delete = () => {
|
||||||
spawnYesNo(tr("Are you sure?"), tr("Do you really want to delete this avatar?"), result => {
|
promptYesNo({
|
||||||
|
title: tr("Are you sure?"),
|
||||||
|
question: tr("Do you really want to delete this avatar?"),
|
||||||
|
}).then(result => {
|
||||||
if (result) {
|
if (result) {
|
||||||
createErrorModal(tr("Not implemented"), tr("Avatar delete hasn't implemented yet")).open();
|
createErrorModal(tr("Not implemented"), tr("Avatar delete hasn't implemented yet")).open();
|
||||||
//TODO Implement avatar delete
|
//TODO Implement avatar delete
|
||||||
|
|
|
@ -2,12 +2,12 @@ import {createModal, Modal} from "tc-shared/ui/elements/Modal";
|
||||||
import {tra} from "tc-shared/i18n/localize";
|
import {tra} from "tc-shared/i18n/localize";
|
||||||
import {Registry} from "tc-shared/events";
|
import {Registry} from "tc-shared/events";
|
||||||
import {modal_settings, SettingProfileEvents} from "tc-shared/ui/modal/ModalSettings";
|
import {modal_settings, SettingProfileEvents} from "tc-shared/ui/modal/ModalSettings";
|
||||||
import {spawnYesNo} from "tc-shared/ui/modal/ModalYesNo";
|
|
||||||
import {initialize_audio_microphone_controller} from "tc-shared/ui/modal/settings/Microphone";
|
import {initialize_audio_microphone_controller} from "tc-shared/ui/modal/settings/Microphone";
|
||||||
import {MicrophoneSettings} from "tc-shared/ui/modal/settings/MicrophoneRenderer";
|
import {MicrophoneSettings} from "tc-shared/ui/modal/settings/MicrophoneRenderer";
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import * as ReactDOM from "react-dom";
|
import * as ReactDOM from "react-dom";
|
||||||
import {MicrophoneSettingsEvents} from "tc-shared/ui/modal/settings/MicrophoneDefinitions";
|
import {MicrophoneSettingsEvents} from "tc-shared/ui/modal/settings/MicrophoneDefinitions";
|
||||||
|
import {promptYesNo} from "tc-shared/ui/modal/yes-no/Controller";
|
||||||
|
|
||||||
export interface EventModalNewcomer {
|
export interface EventModalNewcomer {
|
||||||
"show_step": {
|
"show_step": {
|
||||||
|
@ -65,7 +65,10 @@ export function openModalNewcomer(): Modal {
|
||||||
|
|
||||||
event_registry.on("exit_guide", event => {
|
event_registry.on("exit_guide", event => {
|
||||||
if (event.ask_yesno) {
|
if (event.ask_yesno) {
|
||||||
spawnYesNo(tr("Are you sure?"), tr("Do you really want to skip the basic setup guide?"), result => {
|
promptYesNo({
|
||||||
|
title: tr("Are you sure?"),
|
||||||
|
question: tr("Do you really want to skip the basic setup guide?"),
|
||||||
|
}).then(result => {
|
||||||
if (result)
|
if (result)
|
||||||
event_registry.fire("exit_guide", {ask_yesno: false});
|
event_registry.fire("exit_guide", {ask_yesno: false});
|
||||||
});
|
});
|
||||||
|
|
|
@ -116,7 +116,10 @@ export function spawnQueryManage(client: ConnectionHandler) {
|
||||||
template.find(".button-query-delete").on('click', () => {
|
template.find(".button-query-delete").on('click', () => {
|
||||||
if(!selected_query) return;
|
if(!selected_query) return;
|
||||||
|
|
||||||
Modals.spawnYesNo(tr("Are you sure?"), tr("Do you really want to delete this account?"), result => {
|
Modals.promptYesNo({
|
||||||
|
title: tr("Are you sure?"),
|
||||||
|
question: tr("Do you really want to delete this account?"),
|
||||||
|
}).then(result => {
|
||||||
if(result) {
|
if(result) {
|
||||||
client.serverConnection.send_command("querydelete", {
|
client.serverConnection.send_command("querydelete", {
|
||||||
client_login_name: selected_query.username
|
client_login_name: selected_query.username
|
||||||
|
@ -161,7 +164,6 @@ import {createErrorModal, createInfoModal, createInputModal, createModal, Modal}
|
||||||
import {CommandResult, QueryListEntry} from "../../connection/ServerConnectionDeclaration";
|
import {CommandResult, QueryListEntry} from "../../connection/ServerConnectionDeclaration";
|
||||||
import {SingleCommandHandler} from "../../connection/ConnectionBase";
|
import {SingleCommandHandler} from "../../connection/ConnectionBase";
|
||||||
import {copyToClipboard} from "../../utils/helpers";
|
import {copyToClipboard} from "../../utils/helpers";
|
||||||
import {spawnYesNo} from "../../ui/modal/ModalYesNo";
|
|
||||||
import {LogCategory, logError} from "../../log";
|
import {LogCategory, logError} from "../../log";
|
||||||
import PermissionType from "../../permission/PermissionType";
|
import PermissionType from "../../permission/PermissionType";
|
||||||
import {ConnectionHandler} from "../../ConnectionHandler";
|
import {ConnectionHandler} from "../../ConnectionHandler";
|
||||||
|
@ -169,6 +171,7 @@ import {spawnQueryCreate, spawnQueryCreated} from "../../ui/modal/ModalQuery";
|
||||||
import {formatMessage} from "../../ui/frames/chat";
|
import {formatMessage} from "../../ui/frames/chat";
|
||||||
import {ErrorCode} from "../../connection/ErrorCode";
|
import {ErrorCode} from "../../connection/ErrorCode";
|
||||||
import {tr} from "tc-shared/i18n/localize";
|
import {tr} from "tc-shared/i18n/localize";
|
||||||
|
import {promptYesNo} from "tc-shared/ui/modal/yes-no/Controller";
|
||||||
|
|
||||||
export function spawnQueryManage(client: ConnectionHandler) {
|
export function spawnQueryManage(client: ConnectionHandler) {
|
||||||
let modal: Modal;
|
let modal: Modal;
|
||||||
|
@ -336,7 +339,10 @@ export function spawnQueryManage(client: ConnectionHandler) {
|
||||||
button_delete.on('click', event => {
|
button_delete.on('click', event => {
|
||||||
if (!selected_query) return;
|
if (!selected_query) return;
|
||||||
|
|
||||||
spawnYesNo(tr("Are you sure?"), tr("Do you really want to delete this account?"), result => {
|
promptYesNo({
|
||||||
|
title: tr("Are you sure?"),
|
||||||
|
question: tr("Do you really want to delete this account?"),
|
||||||
|
}).then(result => {
|
||||||
if (result) {
|
if (result) {
|
||||||
client.serverConnection.send_command("querydelete", {
|
client.serverConnection.send_command("querydelete", {
|
||||||
client_login_name: selected_query.username
|
client_login_name: selected_query.username
|
||||||
|
|
|
@ -13,7 +13,6 @@ import {LogCategory, logDebug, logError, logTrace, logWarn} from "tc-shared/log"
|
||||||
import * as i18n from "tc-shared/i18n/localize";
|
import * as i18n from "tc-shared/i18n/localize";
|
||||||
import {RepositoryTranslation, TranslationRepository} from "tc-shared/i18n/localize";
|
import {RepositoryTranslation, TranslationRepository} from "tc-shared/i18n/localize";
|
||||||
import {Registry} from "tc-shared/events";
|
import {Registry} from "tc-shared/events";
|
||||||
import {spawnYesNo} from "tc-shared/ui/modal/ModalYesNo";
|
|
||||||
import * as i18nc from "tc-shared/i18n/country";
|
import * as i18nc from "tc-shared/i18n/country";
|
||||||
import * as forum from "tc-shared/profiles/identities/teaspeak-forum";
|
import * as forum from "tc-shared/profiles/identities/teaspeak-forum";
|
||||||
import {formatMessage, set_icon_size} from "tc-shared/ui/frames/chat";
|
import {formatMessage, set_icon_size} from "tc-shared/ui/frames/chat";
|
||||||
|
@ -27,6 +26,7 @@ import {initialize_audio_microphone_controller} from "tc-shared/ui/modal/setting
|
||||||
import {MicrophoneSettings} from "tc-shared/ui/modal/settings/MicrophoneRenderer";
|
import {MicrophoneSettings} from "tc-shared/ui/modal/settings/MicrophoneRenderer";
|
||||||
import {getBackend} from "tc-shared/backend";
|
import {getBackend} from "tc-shared/backend";
|
||||||
import {MicrophoneSettingsEvents} from "tc-shared/ui/modal/settings/MicrophoneDefinitions";
|
import {MicrophoneSettingsEvents} from "tc-shared/ui/modal/settings/MicrophoneDefinitions";
|
||||||
|
import {promptYesNo} from "tc-shared/ui/modal/yes-no/Controller";
|
||||||
|
|
||||||
type ProfileInfoEvent = {
|
type ProfileInfoEvent = {
|
||||||
id: string,
|
id: string,
|
||||||
|
@ -411,7 +411,10 @@ function settings_general_language(container: JQuery, modal: Modal) {
|
||||||
repo_tag.find(".button-delete").on('click', e => {
|
repo_tag.find(".button-delete").on('click', e => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
spawnYesNo(tr("Are you sure?"), tr("Do you really want to delete this repository?"), answer => {
|
promptYesNo({
|
||||||
|
title: tr("Are you sure?"),
|
||||||
|
question: tr("Do you really want to delete this repository?"),
|
||||||
|
}).then(answer => {
|
||||||
if (answer) {
|
if (answer) {
|
||||||
i18n.delete_repository(repo);
|
i18n.delete_repository(repo);
|
||||||
update_list();
|
update_list();
|
||||||
|
@ -1323,7 +1326,10 @@ export namespace modal_settings {
|
||||||
button.on('click', event => {
|
button.on('click', event => {
|
||||||
if (!current_profile || current_profile === "default") return;
|
if (!current_profile || current_profile === "default") return;
|
||||||
|
|
||||||
spawnYesNo(tr("Are you sure?"), tr("Do you really want to delete this profile?"), result => {
|
promptYesNo({
|
||||||
|
title: tr("Are you sure?"),
|
||||||
|
question: tr("Do you really want to delete this profile?"),
|
||||||
|
}).then(result => {
|
||||||
if (result)
|
if (result)
|
||||||
event_registry.fire("delete-profile", {profile_id: current_profile});
|
event_registry.fire("delete-profile", {profile_id: current_profile});
|
||||||
});
|
});
|
||||||
|
@ -1646,7 +1652,10 @@ export namespace modal_settings {
|
||||||
{
|
{
|
||||||
button_new.on('click', event => {
|
button_new.on('click', event => {
|
||||||
if (is_profile_generated) {
|
if (is_profile_generated) {
|
||||||
spawnYesNo(tr("Are you sure"), tr("Do you really want to generate a new identity and override the old identity?"), result => {
|
promptYesNo({
|
||||||
|
title: tr("Are you sure"),
|
||||||
|
question: tr("Do you really want to generate a new identity and override the old identity?"),
|
||||||
|
}).then(result => {
|
||||||
if (result) event_registry.fire("generate-identity-teamspeak", {profile_id: current_profile});
|
if (result) event_registry.fire("generate-identity-teamspeak", {profile_id: current_profile});
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
|
@ -1671,7 +1680,10 @@ export namespace modal_settings {
|
||||||
{
|
{
|
||||||
button_import.on('click', event => {
|
button_import.on('click', event => {
|
||||||
if (is_profile_generated) {
|
if (is_profile_generated) {
|
||||||
spawnYesNo(tr("Are you sure"), tr("Do you really want to import a new identity and override the old identity?"), result => {
|
promptYesNo({
|
||||||
|
title: tr("Are you sure"),
|
||||||
|
question: tr("Do you really want to import a new identity and override the old identity?"),
|
||||||
|
}).then(result => {
|
||||||
if (result) event_registry.fire("import-identity-teamspeak", {profile_id: current_profile});
|
if (result) event_registry.fire("import-identity-teamspeak", {profile_id: current_profile});
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
import {BodyCreator, createModal, ModalFunctions} from "../../ui/elements/Modal";
|
import {BodyCreator, createModal, Modal, ModalFunctions} from "../../ui/elements/Modal";
|
||||||
|
|
||||||
export function spawnYesNo(header: BodyCreator, body: BodyCreator, callback: (_: boolean) => any, properties?: {
|
export function spawnYesNo(header: BodyCreator, body: BodyCreator, callback: (_: boolean) => any, properties?: {
|
||||||
text_yes?: string,
|
text_yes?: string,
|
||||||
text_no?: string,
|
text_no?: string,
|
||||||
|
|
||||||
closeable?: boolean;
|
closeable?: boolean;
|
||||||
}) {
|
}) : Modal {
|
||||||
properties = properties || {};
|
properties = properties || {};
|
||||||
|
|
||||||
const props = ModalFunctions.warpProperties({});
|
const props = ModalFunctions.warpProperties({});
|
||||||
|
|
|
@ -8,7 +8,7 @@ import PermissionType from "tc-shared/permission/PermissionType";
|
||||||
import {getOwnAvatarStorage, LocalAvatarInfo} from "tc-shared/file/OwnAvatarStorage";
|
import {getOwnAvatarStorage, LocalAvatarInfo} from "tc-shared/file/OwnAvatarStorage";
|
||||||
import {LogCategory, logError, logInfo, logWarn} from "tc-shared/log";
|
import {LogCategory, logError, logInfo, logWarn} from "tc-shared/log";
|
||||||
import {Mutex} from "tc-shared/Mutex";
|
import {Mutex} from "tc-shared/Mutex";
|
||||||
import {tr, trJQuery} from "tc-shared/i18n/localize";
|
import {tr, tra, trJQuery} from "tc-shared/i18n/localize";
|
||||||
import {createErrorModal, createInfoModal} from "tc-shared/ui/elements/Modal";
|
import {createErrorModal, createInfoModal} from "tc-shared/ui/elements/Modal";
|
||||||
import {CommandResult} from "tc-shared/connection/ServerConnectionDeclaration";
|
import {CommandResult} from "tc-shared/connection/ServerConnectionDeclaration";
|
||||||
import {formatMessage} from "tc-shared/ui/frames/chat";
|
import {formatMessage} from "tc-shared/ui/frames/chat";
|
||||||
|
@ -262,7 +262,7 @@ class Controller {
|
||||||
if (transfer.transferState() !== FileTransferState.FINISHED) {
|
if (transfer.transferState() !== FileTransferState.FINISHED) {
|
||||||
if (transfer.transferState() === FileTransferState.ERRORED) {
|
if (transfer.transferState() === FileTransferState.ERRORED) {
|
||||||
logWarn(LogCategory.FILE_TRANSFER, tr("Failed to upload clients avatar: %o"), transfer.currentError());
|
logWarn(LogCategory.FILE_TRANSFER, tr("Failed to upload clients avatar: %o"), transfer.currentError());
|
||||||
createErrorModal(tr("Failed to upload avatar"), tr("Failed to upload avatar:\n{0}", transfer.currentErrorMessage())).open();
|
createErrorModal(tr("Failed to upload avatar"), tra("Failed to upload avatar:\n{0}", transfer.currentErrorMessage())).open();
|
||||||
return;
|
return;
|
||||||
} else if (transfer.transferState() === FileTransferState.CANCELED) {
|
} else if (transfer.transferState() === FileTransferState.CANCELED) {
|
||||||
createErrorModal(tr("Failed to upload avatar"), tr("Your avatar upload has been canceled.")).open();
|
createErrorModal(tr("Failed to upload avatar"), tr("Your avatar upload has been canceled.")).open();
|
||||||
|
|
|
@ -19,7 +19,6 @@ import {getIconManager} from "tc-shared/file/Icons";
|
||||||
import {ClientIcon} from "svg-sprites/client-icons";
|
import {ClientIcon} from "svg-sprites/client-icons";
|
||||||
import {ClientIconRenderer} from "tc-shared/ui/react-elements/Icons";
|
import {ClientIconRenderer} from "tc-shared/ui/react-elements/Icons";
|
||||||
import {spawnContextMenu} from "tc-shared/ui/ContextMenu";
|
import {spawnContextMenu} from "tc-shared/ui/ContextMenu";
|
||||||
import {spawnYesNo} from "tc-shared/ui/modal/ModalYesNo";
|
|
||||||
import {formatMessage} from "tc-shared/ui/frames/chat";
|
import {formatMessage} from "tc-shared/ui/frames/chat";
|
||||||
import {createErrorModal, createInfoModal, createInputModal} from "tc-shared/ui/elements/Modal";
|
import {createErrorModal, createInfoModal, createInputModal} from "tc-shared/ui/elements/Modal";
|
||||||
import {HostBannerRenderer} from "tc-shared/ui/frames/HostBannerRenderer";
|
import {HostBannerRenderer} from "tc-shared/ui/frames/HostBannerRenderer";
|
||||||
|
@ -32,6 +31,8 @@ import ServerInfoImage from "./serverinfo.png";
|
||||||
import {IconTooltip} from "tc-shared/ui/react-elements/Tooltip";
|
import {IconTooltip} from "tc-shared/ui/react-elements/Tooltip";
|
||||||
import {CountryCode} from "tc-shared/ui/react-elements/CountryCode";
|
import {CountryCode} from "tc-shared/ui/react-elements/CountryCode";
|
||||||
import {downloadTextAsFile, requestFileAsText} from "tc-shared/file/Utils";
|
import {downloadTextAsFile, requestFileAsText} from "tc-shared/file/Utils";
|
||||||
|
import {promptYesNo} from "tc-shared/ui/modal/yes-no/Controller";
|
||||||
|
import {tra} from "tc-shared/i18n/localize";
|
||||||
|
|
||||||
const EventContext = React.createContext<Registry<ModalBookmarkEvents>>(undefined);
|
const EventContext = React.createContext<Registry<ModalBookmarkEvents>>(undefined);
|
||||||
const VariableContext = React.createContext<UiVariableConsumer<ModalBookmarkVariables>>(undefined);
|
const VariableContext = React.createContext<UiVariableConsumer<ModalBookmarkVariables>>(undefined);
|
||||||
|
@ -54,14 +55,16 @@ const BookmarkListEntryRenderer = React.memo((props: { entry: BookmarkListEntry
|
||||||
|
|
||||||
const tryDelete = () => {
|
const tryDelete = () => {
|
||||||
if(props.entry.type === "directory" && props.entry.childCount > 0) {
|
if(props.entry.type === "directory" && props.entry.childCount > 0) {
|
||||||
spawnYesNo(tr("Are you sure?"), formatMessage(
|
promptYesNo({
|
||||||
tr("Do you really want to delete the directory \"{0}\"?{:br:}The directory contains {1} entries."),
|
title: tr("Are you sure?"),
|
||||||
props.entry.displayName, props.entry.childCount
|
question: tra("Do you really want to delete the directory \"{0}\"?\nThe directory contains {1} entries.", props.entry.displayName, props.entry.childCount)
|
||||||
), result => {
|
}).then(result => {
|
||||||
if(result) {
|
if(!result) {
|
||||||
events.fire("action_delete_bookmark", { uniqueId: props.entry.uniqueId });
|
return;
|
||||||
}
|
}
|
||||||
}).open();
|
|
||||||
|
events.fire("action_delete_bookmark", { uniqueId: props.entry.uniqueId });
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
events.fire("action_delete_bookmark", { uniqueId: props.entry.uniqueId });
|
events.fire("action_delete_bookmark", { uniqueId: props.entry.uniqueId });
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,8 +5,7 @@ import {DefaultTabValues} from "tc-shared/ui/modal/permission/ModalRenderer";
|
||||||
import {Group, GroupTarget, GroupType} from "tc-shared/permission/GroupManager";
|
import {Group, GroupTarget, GroupType} from "tc-shared/permission/GroupManager";
|
||||||
import {createErrorModal, createInfoModal} from "tc-shared/ui/elements/Modal";
|
import {createErrorModal, createInfoModal} from "tc-shared/ui/elements/Modal";
|
||||||
import {ClientNameInfo, CommandResult} from "tc-shared/connection/ServerConnectionDeclaration";
|
import {ClientNameInfo, CommandResult} from "tc-shared/connection/ServerConnectionDeclaration";
|
||||||
import {formatMessage} from "tc-shared/ui/frames/chat";
|
import {formatMessage, formatMessageString} from "tc-shared/ui/frames/chat";
|
||||||
import {spawnYesNo} from "tc-shared/ui/modal/ModalYesNo";
|
|
||||||
import {tra} from "tc-shared/i18n/localize";
|
import {tra} from "tc-shared/i18n/localize";
|
||||||
import {PermissionType} from "tc-shared/permission/PermissionType";
|
import {PermissionType} from "tc-shared/permission/PermissionType";
|
||||||
import {GroupedPermissions, PermissionValue} from "tc-shared/permission/PermissionManager";
|
import {GroupedPermissions, PermissionValue} from "tc-shared/permission/PermissionManager";
|
||||||
|
@ -32,6 +31,7 @@ import {
|
||||||
PermissionModalEvents
|
PermissionModalEvents
|
||||||
} from "tc-shared/ui/modal/permission/ModalDefinitions";
|
} from "tc-shared/ui/modal/permission/ModalDefinitions";
|
||||||
import {EditorGroupedPermissions, PermissionEditorEvents} from "tc-shared/ui/modal/permission/EditorDefinitions";
|
import {EditorGroupedPermissions, PermissionEditorEvents} from "tc-shared/ui/modal/permission/EditorDefinitions";
|
||||||
|
import {promptYesNo} from "tc-shared/ui/modal/yes-no/Controller";
|
||||||
|
|
||||||
export function spawnPermissionEditorModal(connection: ConnectionHandler, defaultTab: PermissionEditorTab = "groups-server", defaultTabValues?: DefaultTabValues) {
|
export function spawnPermissionEditorModal(connection: ConnectionHandler, defaultTab: PermissionEditorTab = "groups-server", defaultTabValues?: DefaultTabValues) {
|
||||||
const modalEvents = new Registry<PermissionModalEvents>();
|
const modalEvents = new Registry<PermissionModalEvents>();
|
||||||
|
@ -96,7 +96,10 @@ function initializePermissionModalResultHandlers(events: Registry<PermissionModa
|
||||||
if (event.mode === "force")
|
if (event.mode === "force")
|
||||||
return;
|
return;
|
||||||
|
|
||||||
spawnYesNo(tr("Are you sure?"), formatMessage(tr("Do you really want to delete this group?")), result => {
|
promptYesNo({
|
||||||
|
title: tr("Are you sure?"),
|
||||||
|
question: formatMessageString(tr("Do you really want to delete this group?")),
|
||||||
|
}).then(result => {
|
||||||
if (result !== true)
|
if (result !== true)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,6 @@ import PermissionType from "../../../permission/PermissionType";
|
||||||
import {LogCategory, logError, logTrace} from "../../../log";
|
import {LogCategory, logError, logTrace} from "../../../log";
|
||||||
import {Entry, MenuEntry, MenuEntryType, spawn_context_menu} from "../../../ui/elements/ContextMenu";
|
import {Entry, MenuEntry, MenuEntryType, spawn_context_menu} from "../../../ui/elements/ContextMenu";
|
||||||
import {getKeyBoard, SpecialKey} from "../../../PPTListener";
|
import {getKeyBoard, SpecialKey} from "../../../PPTListener";
|
||||||
import {spawnYesNo} from "../../../ui/modal/ModalYesNo";
|
|
||||||
import {tr, tra} from "../../../i18n/localize";
|
import {tr, tra} from "../../../i18n/localize";
|
||||||
import {
|
import {
|
||||||
FileTransfer,
|
FileTransfer,
|
||||||
|
@ -25,6 +24,7 @@ import {
|
||||||
ListedFileInfo,
|
ListedFileInfo,
|
||||||
PathInfo
|
PathInfo
|
||||||
} from "tc-shared/ui/modal/transfer/FileDefinitions";
|
} from "tc-shared/ui/modal/transfer/FileDefinitions";
|
||||||
|
import {promptYesNo} from "tc-shared/ui/modal/yes-no/Controller";
|
||||||
|
|
||||||
function parsePath(path: string, connection: ConnectionHandler): PathInfo {
|
function parsePath(path: string, connection: ConnectionHandler): PathInfo {
|
||||||
if (path === "/" || !path) {
|
if (path === "/" || !path) {
|
||||||
|
@ -508,12 +508,18 @@ export function initializeRemoteFileBrowserController(connection: ConnectionHand
|
||||||
}) : event.files;
|
}) : event.files;
|
||||||
|
|
||||||
if (event.mode === "ask") {
|
if (event.mode === "ask") {
|
||||||
spawnYesNo(tr("Are you sure?"), tra("Do you really want to delete {0} {1}?", files.length, files.length === 1 ? tr("files") : tr("files")), result => {
|
promptYesNo({
|
||||||
if (result)
|
title: tr("Are you sure?"),
|
||||||
events.fire("action_delete_file", {
|
question: tra("Do you really want to delete {0} {1}?", files.length, files.length === 1 ? tr("files") : tr("files")),
|
||||||
files: files,
|
}).then(result => {
|
||||||
mode: "force"
|
if(!result) {
|
||||||
});
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
events.fire("action_delete_file", {
|
||||||
|
files: files,
|
||||||
|
mode: "force"
|
||||||
|
});
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,33 @@
|
||||||
|
import {spawnModal} from "tc-shared/ui/react-elements/modal";
|
||||||
|
import {Registry} from "tc-events";
|
||||||
|
import {ModalYesNoEvents, ModalYesNoVariables} from "tc-shared/ui/modal/yes-no/Definitions";
|
||||||
|
import {IpcUiVariableProvider} from "tc-shared/ui/utils/IpcVariable";
|
||||||
|
import {CallOnce, ignorePromise} from "tc-shared/proto";
|
||||||
|
|
||||||
|
class Controller {
|
||||||
|
readonly properties: YesNoParameters;
|
||||||
|
readonly events: Registry<ModalYesNoEvents>;
|
||||||
|
readonly variables: IpcUiVariableProvider<ModalYesNoVariables>;
|
||||||
|
|
||||||
|
constructor(properties: YesNoParameters) {
|
||||||
|
this.properties = properties;
|
||||||
|
this.events = new Registry<ModalYesNoEvents>();
|
||||||
|
this.variables = new IpcUiVariableProvider<ModalYesNoVariables>();
|
||||||
|
|
||||||
|
this.variables.setVariableProvider("title", () => this.properties.title);
|
||||||
|
this.variables.setVariableProvider("question", () => this.properties.question);
|
||||||
|
|
||||||
|
this.variables.setVariableProvider("textYes", () => this.properties.textYes);
|
||||||
|
this.variables.setVariableProvider("textNo", () => this.properties.textNo);
|
||||||
|
}
|
||||||
|
|
||||||
|
@CallOnce
|
||||||
|
destroy() {
|
||||||
|
this.events.destroy();
|
||||||
|
this.variables.destroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export interface YesNoParameters {
|
export interface YesNoParameters {
|
||||||
title: string,
|
title: string,
|
||||||
question: string,
|
question: string,
|
||||||
|
@ -20,5 +50,23 @@ export async function promptYesNo(properties: YesNoParameters) : Promise<boolean
|
||||||
throw "yes-no question isn't a string";
|
throw "yes-no question isn't a string";
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
const controller = new Controller(properties);
|
||||||
|
const modal = spawnModal("modal-yes-no", [
|
||||||
|
controller.events.generateIpcDescription(),
|
||||||
|
controller.variables.generateConsumerDescription()
|
||||||
|
], {
|
||||||
|
popoutable: false,
|
||||||
|
destroyOnClose: true
|
||||||
|
});
|
||||||
|
|
||||||
|
modal.getEvents().on("destroy", () => controller.destroy());
|
||||||
|
ignorePromise(modal.show());
|
||||||
|
|
||||||
|
return await new Promise<boolean | undefined>(resolve => {
|
||||||
|
modal.getEvents().on("destroy", () => resolve());
|
||||||
|
controller.events.on("action_submit", event => {
|
||||||
|
resolve(event.status);
|
||||||
|
modal.destroy();
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
export interface ModalYesNoVariables {
|
||||||
|
readonly title: string,
|
||||||
|
readonly question: string,
|
||||||
|
|
||||||
|
readonly textYes: string | undefined,
|
||||||
|
readonly textNo: string | undefined,
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ModalYesNoEvents {
|
||||||
|
action_submit: { status: boolean }
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
.container {
|
||||||
|
padding: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.question {
|
||||||
|
min-height: 1.6em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.buttons {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: flex-end;
|
||||||
|
|
||||||
|
margin-top: 2em;
|
||||||
|
|
||||||
|
button {
|
||||||
|
min-width: 6em;
|
||||||
|
|
||||||
|
&:not(:last-of-type) {
|
||||||
|
margin-right: 1em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,92 @@
|
||||||
|
import {AbstractModal} from "tc-shared/ui/react-elements/modal/Definitions";
|
||||||
|
import {IpcRegistryDescription, Registry} from "tc-events";
|
||||||
|
import {ModalYesNoEvents, ModalYesNoVariables} from "tc-shared/ui/modal/yes-no/Definitions";
|
||||||
|
import {UiVariableConsumer} from "tc-shared/ui/utils/Variable";
|
||||||
|
import {createIpcUiVariableConsumer} from "tc-shared/ui/utils/IpcVariable";
|
||||||
|
import React from "react";
|
||||||
|
import {Translatable} from "tc-shared/ui/react-elements/i18n";
|
||||||
|
import {Button} from "tc-shared/ui/react-elements/Button";
|
||||||
|
const cssStyle = require("./Renderer.scss");
|
||||||
|
|
||||||
|
const QuestionRenderer = React.memo((props: { variables: UiVariableConsumer<ModalYesNoVariables> }) => {
|
||||||
|
const question = props.variables.useReadOnly("question", undefined, undefined);
|
||||||
|
return (
|
||||||
|
<div className={cssStyle.question}>
|
||||||
|
{question}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
const TitleRenderer = React.memo((props: { variables: UiVariableConsumer<ModalYesNoVariables> }) => {
|
||||||
|
const title = props.variables.useReadOnly("title", undefined, undefined);
|
||||||
|
if(typeof title !== "undefined") {
|
||||||
|
return <React.Fragment key={"loaded"}>{title}</React.Fragment>;
|
||||||
|
} else {
|
||||||
|
return <Translatable key={"loading"}>loading</Translatable>;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const TextYes = React.memo((props: { variables: UiVariableConsumer<ModalYesNoVariables> }) => {
|
||||||
|
const text = props.variables.useReadOnly("textYes", undefined, undefined);
|
||||||
|
if(typeof text !== "undefined") {
|
||||||
|
return <React.Fragment key={"custom"}>{text}</React.Fragment>;
|
||||||
|
} else {
|
||||||
|
return <Translatable key={"default"}>Yes</Translatable>;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const TextNo = React.memo((props: { variables: UiVariableConsumer<ModalYesNoVariables> }) => {
|
||||||
|
const text = props.variables.useReadOnly("textNo", undefined, undefined);
|
||||||
|
if(typeof text !== "undefined") {
|
||||||
|
return <React.Fragment key={"custom"}>{text}</React.Fragment>;
|
||||||
|
} else {
|
||||||
|
return <Translatable key={"default"}>No</Translatable>;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
class Modal extends AbstractModal {
|
||||||
|
private readonly events: Registry<ModalYesNoEvents>;
|
||||||
|
private readonly variables: UiVariableConsumer<ModalYesNoVariables>;
|
||||||
|
|
||||||
|
constructor(events: IpcRegistryDescription<ModalYesNoEvents>, variables: IpcRegistryDescription<ModalYesNoVariables>) {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.events = Registry.fromIpcDescription(events);
|
||||||
|
this.variables = createIpcUiVariableConsumer(variables);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected onDestroy() {
|
||||||
|
super.onDestroy();
|
||||||
|
|
||||||
|
this.events.destroy();
|
||||||
|
this.variables.destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
color(): "none" | "blue" | "red" {
|
||||||
|
return "red";
|
||||||
|
}
|
||||||
|
|
||||||
|
renderBody(): React.ReactElement {
|
||||||
|
return (
|
||||||
|
<div className={cssStyle.container}>
|
||||||
|
<QuestionRenderer variables={this.variables} />
|
||||||
|
<div className={cssStyle.buttons}>
|
||||||
|
<Button color={"red"} onClick={() => this.events.fire("action_submit", { status: false })}>
|
||||||
|
<TextNo variables={this.variables} />
|
||||||
|
</Button>
|
||||||
|
<Button color={"green"} onClick={() => this.events.fire("action_submit", { status: true })}>
|
||||||
|
<TextYes variables={this.variables} />
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderTitle(): string | React.ReactElement {
|
||||||
|
return (
|
||||||
|
<TitleRenderer variables={this.variables} />
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Modal;
|
|
@ -24,6 +24,7 @@ import {ModalInputProcessorEvents, ModalInputProcessorVariables} from "tc-shared
|
||||||
import {ModalServerInfoEvents, ModalServerInfoVariables} from "tc-shared/ui/modal/server-info/Definitions";
|
import {ModalServerInfoEvents, ModalServerInfoVariables} from "tc-shared/ui/modal/server-info/Definitions";
|
||||||
import {ModalAboutVariables} from "tc-shared/ui/modal/about/Definitions";
|
import {ModalAboutVariables} from "tc-shared/ui/modal/about/Definitions";
|
||||||
import {ModalServerBandwidthEvents} from "tc-shared/ui/modal/server-bandwidth/Definitions";
|
import {ModalServerBandwidthEvents} from "tc-shared/ui/modal/server-bandwidth/Definitions";
|
||||||
|
import {ModalYesNoEvents, ModalYesNoVariables} from "tc-shared/ui/modal/yes-no/Definitions";
|
||||||
|
|
||||||
export type ModalType = "error" | "warning" | "info" | "none";
|
export type ModalType = "error" | "warning" | "info" | "none";
|
||||||
export type ModalRenderType = "page" | "dialog";
|
export type ModalRenderType = "page" | "dialog";
|
||||||
|
@ -138,7 +139,7 @@ export abstract class AbstractModal {
|
||||||
|
|
||||||
/* only valid for the "inline" modals */
|
/* only valid for the "inline" modals */
|
||||||
type() : ModalType { return "none"; }
|
type() : ModalType { return "none"; }
|
||||||
color() : "none" | "blue" { return "none"; }
|
color() : "none" | "blue" | "red" { return "none"; }
|
||||||
verticalAlignment() : "top" | "center" | "bottom" { return "center"; }
|
verticalAlignment() : "top" | "center" | "bottom" { return "center"; }
|
||||||
|
|
||||||
/** @deprecated */
|
/** @deprecated */
|
||||||
|
@ -165,6 +166,10 @@ export function constructAbstractModalClass<T extends keyof ModalConstructorArgu
|
||||||
|
|
||||||
export interface ModalConstructorArguments {
|
export interface ModalConstructorArguments {
|
||||||
"__internal__modal__": any[],
|
"__internal__modal__": any[],
|
||||||
|
"modal-yes-no": [
|
||||||
|
/* events */ IpcRegistryDescription<ModalYesNoEvents>,
|
||||||
|
/* variables */ IpcVariableDescriptor<ModalYesNoVariables>,
|
||||||
|
],
|
||||||
|
|
||||||
"video-viewer": [
|
"video-viewer": [
|
||||||
/* events */ IpcRegistryDescription<VideoViewerEvents>,
|
/* events */ IpcRegistryDescription<VideoViewerEvents>,
|
||||||
|
|
|
@ -19,6 +19,12 @@ function registerModal<T extends keyof ModalConstructorArguments>(modal: Registe
|
||||||
registeredModals[modal.modalId] = modal as any;
|
registeredModals[modal.modalId] = modal as any;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
registerModal({
|
||||||
|
modalId: "modal-yes-no",
|
||||||
|
classLoader: async () => await import("tc-shared/ui/modal/yes-no/Renderer"),
|
||||||
|
popoutSupported: true
|
||||||
|
})
|
||||||
|
|
||||||
registerModal({
|
registerModal({
|
||||||
modalId: "video-viewer",
|
modalId: "video-viewer",
|
||||||
classLoader: async () => await import("tc-shared/ui/modal/video-viewer/Renderer"),
|
classLoader: async () => await import("tc-shared/ui/modal/video-viewer/Renderer"),
|
||||||
|
|
|
@ -12,6 +12,4 @@ export class UnreadMarkerRenderer extends React.Component<{ entry: RDPEntry }, {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class RendererTreeEntry<Props, State> extends ReactComponentBase<Props, State> { }
|
|
|
@ -8,10 +8,10 @@ import {
|
||||||
import {assertMainApplication} from "tc-shared/ui/utils";
|
import {assertMainApplication} from "tc-shared/ui/utils";
|
||||||
import {Registry} from "tc-events";
|
import {Registry} from "tc-events";
|
||||||
import {getIpcInstance} from "tc-shared/ipc/BrowserIPC";
|
import {getIpcInstance} from "tc-shared/ipc/BrowserIPC";
|
||||||
import {spawnYesNo} from "tc-shared/ui/modal/ModalYesNo";
|
|
||||||
import {tr, tra} from "tc-shared/i18n/localize";
|
import {tr, tra} from "tc-shared/i18n/localize";
|
||||||
import {guid} from "tc-shared/crypto/uid";
|
import {guid} from "tc-shared/crypto/uid";
|
||||||
import _ from "lodash";
|
import _ from "lodash";
|
||||||
|
import {promptYesNo} from "tc-shared/ui/modal/yes-no/Controller";
|
||||||
|
|
||||||
assertMainApplication();
|
assertMainApplication();
|
||||||
|
|
||||||
|
@ -64,17 +64,16 @@ export class WebWindowManager implements WindowManager {
|
||||||
let windowInstance = this.tryCreateWindow(options, windowUniqueId);
|
let windowInstance = this.tryCreateWindow(options, windowUniqueId);
|
||||||
if(!windowInstance) {
|
if(!windowInstance) {
|
||||||
try {
|
try {
|
||||||
await new Promise((resolve, reject) => {
|
const result = await promptYesNo({
|
||||||
spawnYesNo(tr("Would you like to open the popup?"), tra("Would you like to open window {}?", options.windowName), callback => {
|
title: tr("Would you like to open the popup?"),
|
||||||
if(!callback) {
|
question: tra("Would you like to open window {}?", options.windowName)
|
||||||
reject();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
windowInstance = this.tryCreateWindow(options, windowUniqueId);
|
|
||||||
resolve();
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if(!result) {
|
||||||
|
return { status: "error-user-rejected" };
|
||||||
|
}
|
||||||
|
|
||||||
|
windowInstance = this.tryCreateWindow(options, windowUniqueId);
|
||||||
} catch (_) {
|
} catch (_) {
|
||||||
return { status: "error-user-rejected" };
|
return { status: "error-user-rejected" };
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue