Revamp error modal
This commit is contained in:
parent
aeeb95d84b
commit
e1a510ab4c
|
@ -201,7 +201,7 @@ export default class AddonManager {
|
|||
const addon = __non_webpack_require__(path.resolve(this.addonFolder, filename));
|
||||
}
|
||||
catch (error) {
|
||||
return new AddonError(filename, filename, Strings.Addons.compileError, {message: error.message, stack: error.stack});
|
||||
return new AddonError(filename, filename, Strings.Addons.compileError, {message: error.message, stack: error.stack}, this.prefix);
|
||||
}
|
||||
|
||||
const addon = __non_webpack_require__(path.resolve(this.addonFolder, filename));
|
||||
|
@ -209,7 +209,7 @@ export default class AddonManager {
|
|||
// await Promise.resolve(addon);
|
||||
// addon = __non_webpack_require__(path.resolve(this.addonFolder, filename));
|
||||
// console.log(addon);
|
||||
if (this.addonList.find(c => c.id == addon.id)) return new AddonError(addon.name, filename, Strings.Addons.alreadyExists.format({type: this.prefix, name: addon.name}));
|
||||
if (this.addonList.find(c => c.id == addon.id)) return new AddonError(addon.name, filename, Strings.Addons.alreadyExists.format({type: this.prefix, name: addon.name}), this.prefix);
|
||||
|
||||
const error = this.initializeAddon(addon);
|
||||
if (error) return error;
|
||||
|
|
|
@ -153,7 +153,7 @@ export default new class Core {
|
|||
catch (err) {
|
||||
Logger.stacktrace("Updater", "Failed to update", err);
|
||||
Modals.showConfirmationModal("Update Failed", "BetterDiscord failed to update. Please download the latest version of the installer from GitHub (https://github.com/BetterDiscord/Installer/releases/latest) and reinstall.", {
|
||||
cancelText: ""
|
||||
cancelText: null
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -66,9 +66,10 @@ export default new class PluginManager extends AddonManager {
|
|||
unloadPlugin(idOrFileOrAddon) {return this.unloadAddon(idOrFileOrAddon);}
|
||||
loadPlugin(filename) {return this.loadAddon(filename);}
|
||||
|
||||
loadAddon(filename) {
|
||||
loadAddon(filename, shouldCTE = true) {
|
||||
const error = super.loadAddon(filename);
|
||||
if (error) Modals.showAddonErrors({plugins: [error]});
|
||||
if (error && shouldCTE) Modals.showAddonErrors({plugins: [error]});
|
||||
return error;
|
||||
}
|
||||
|
||||
reloadPlugin(idOrFileOrAddon) {
|
||||
|
@ -79,7 +80,7 @@ export default new class PluginManager extends AddonManager {
|
|||
|
||||
/* Overrides */
|
||||
initializeAddon(addon) {
|
||||
if (!addon.exports) return new AddonError(addon.name, addon.filename, "Plugin had no exports", {message: "Plugin had no exports or no name property.", stack: ""});
|
||||
if (!addon.exports) return new AddonError(addon.name, addon.filename, "Plugin had no exports", {message: "Plugin had no exports or no name property.", stack: ""}, this.prefix);
|
||||
try {
|
||||
const PluginClass = addon.exports;
|
||||
const thePlugin = new PluginClass();
|
||||
|
@ -93,10 +94,10 @@ export default new class PluginManager extends AddonManager {
|
|||
}
|
||||
catch (error) {
|
||||
this.state[addon.id] = false;
|
||||
return new AddonError(addon.name, addon.filename, "load() could not be fired.", {message: error.message, stack: error.stack});
|
||||
return new AddonError(addon.name, addon.filename, "load() could not be fired.", {message: error.message, stack: error.stack}, this.prefix);
|
||||
}
|
||||
}
|
||||
catch (error) {return new AddonError(addon.name, addon.filename, "Could not be constructed.", {message: error.message, stack: error.stack});}
|
||||
catch (error) {return new AddonError(addon.name, addon.filename, "Could not be constructed.", {message: error.message, stack: error.stack}, this.prefix);}
|
||||
}
|
||||
|
||||
getFileModification(module, fileContent, meta) {
|
||||
|
@ -138,7 +139,7 @@ export default new class PluginManager extends AddonManager {
|
|||
this.state[addon.id] = false;
|
||||
Toasts.error(Strings.Addons.couldNotStart.format({name: addon.name, version: addon.version}));
|
||||
Logger.stacktrace(this.name, `${addon.name} v${addon.version} could not be started.`, err);
|
||||
return new AddonError(addon.name, addon.filename, Strings.Addons.enabled.format({method: "start()"}), {message: err.message, stack: err.stack});
|
||||
return new AddonError(addon.name, addon.filename, Strings.Addons.enabled.format({method: "start()"}), {message: err.message, stack: err.stack}, this.prefix);
|
||||
}
|
||||
this.emit("started", addon.id);
|
||||
Toasts.show(Strings.Addons.enabled.format({name: addon.name, version: addon.version}));
|
||||
|
@ -155,7 +156,7 @@ export default new class PluginManager extends AddonManager {
|
|||
this.state[addon.id] = false;
|
||||
Toasts.error(Strings.Addons.couldNotStop.format({name: addon.name, version: addon.version}));
|
||||
Logger.stacktrace(this.name, `${addon.name} v${addon.version} could not be started.`, err);
|
||||
return new AddonError(addon.name, addon.filename, Strings.Addons.enabled.format({method: "stop()"}), {message: err.message, stack: err.stack});
|
||||
return new AddonError(addon.name, addon.filename, Strings.Addons.enabled.format({method: "stop()"}), {message: err.message, stack: err.stack}, this.prefix);
|
||||
}
|
||||
this.emit("stopped", addon.id);
|
||||
Toasts.show(Strings.Addons.disabled.format({name: addon.name, version: addon.version}));
|
||||
|
|
|
@ -47,9 +47,10 @@ export default new class ThemeManager extends AddonManager {
|
|||
loadTheme(filename) {return this.loadAddon(filename);}
|
||||
reloadTheme(idOrFileOrAddon) {return this.reloadAddon(idOrFileOrAddon);}
|
||||
|
||||
loadAddon(filename) {
|
||||
loadAddon(filename, shouldCTE = true) {
|
||||
const error = super.loadAddon(filename);
|
||||
if (error) Modals.showAddonErrors({themes: [error]});
|
||||
if (error && shouldCTE) Modals.showAddonErrors({themes: [error]});
|
||||
return error;
|
||||
}
|
||||
|
||||
/* Overrides */
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
export default class AddonError extends Error {
|
||||
constructor(name, filename, message, error) {
|
||||
constructor(name, filename, message, error, type) {
|
||||
super(message);
|
||||
this.name = name;
|
||||
this.file = filename;
|
||||
this.error = error;
|
||||
this.type = type;
|
||||
}
|
||||
}
|
|
@ -90,6 +90,10 @@ export default class BuiltinModule {
|
|||
return Patcher.before(this.name, object, func, callback);
|
||||
}
|
||||
|
||||
instead(object, func, callback) {
|
||||
return Patcher.instead(this.name, object, func, callback);
|
||||
}
|
||||
|
||||
after(object, func, callback) {
|
||||
return Patcher.after(this.name, object, func, callback);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
.be-modal .tab-bar.TOP .tab-bar-item:nth-child(1) {
|
||||
margin-left: 20px;
|
||||
}
|
||||
|
||||
.bd-addon-error {
|
||||
margin: 10px;
|
||||
border-radius: 4px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.bd-addon-error-header {
|
||||
display: flex;
|
||||
padding: 10px;
|
||||
background: rgba(0, 0, 0, 0.2);
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.bd-addon-error-message {
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.bd-addon-error-body {
|
||||
padding: 10px;
|
||||
background: var(--background-mobile-secondary);
|
||||
}
|
||||
|
||||
.bd-addon-error-header svg {
|
||||
margin-right: 7px;
|
||||
}
|
||||
|
||||
.bd-addon-error-stack-header svg {
|
||||
float: right;
|
||||
transform: rotate(90deg);
|
||||
transition: 0.4s;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.bd-addon-error-stack.opened svg {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
|
||||
.bd-addon-error-stack-header {
|
||||
color: #b9bbbe;
|
||||
}
|
|
@ -32,6 +32,14 @@
|
|||
transform: translateZ(0);
|
||||
}
|
||||
|
||||
.bd-modal {
|
||||
border-radius: 3px;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.bd-modal-wrapper.closing .bd-backdrop {
|
||||
animation: bd-backdrop-closing 200ms linear;
|
||||
animation-fill-mode: forwards;
|
||||
|
@ -66,7 +74,7 @@
|
|||
transform: scale(1);
|
||||
}
|
||||
|
||||
.bd-modal-wrapper .bd-modal-inner {
|
||||
/* .bd-modal .bd-modal-inner {
|
||||
display: flex;
|
||||
contain: layout;
|
||||
flex-direction: column;
|
||||
|
@ -79,6 +87,14 @@
|
|||
min-height: 200px;
|
||||
width: 440px;
|
||||
user-select: text;
|
||||
} */
|
||||
|
||||
.bd-modal .bd-modal-inner {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex: 1;
|
||||
max-height: 660px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.bd-modal-wrapper .bd-content-modal .bd-modal-inner {
|
||||
|
@ -86,7 +102,7 @@
|
|||
width: 700px;
|
||||
}
|
||||
|
||||
.bd-modal-wrapper .header {
|
||||
.bd-modal .header {
|
||||
background-color: #35393e;
|
||||
box-shadow: 0 2px 3px 0 rgba(0, 0, 0, 0.2);
|
||||
padding: 12px 20px;
|
||||
|
@ -97,7 +113,7 @@
|
|||
line-height: 19px;
|
||||
}
|
||||
|
||||
.bd-modal-wrapper .bd-modal-body {
|
||||
.bd-modal .bd-modal-body {
|
||||
background-color: #36393f;
|
||||
color: #fff;
|
||||
overflow: hidden;
|
||||
|
@ -108,22 +124,22 @@
|
|||
position: relative;
|
||||
}
|
||||
|
||||
.bd-modal-wrapper .scroller {
|
||||
.bd-modal .scroller {
|
||||
padding: 10px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.bd-modal-wrapper .bd-content-modal .bd-modal-body {
|
||||
.bd-modal .bd-content-modal .bd-modal-body {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.bd-modal-wrapper .footer {
|
||||
.bd-modal .footer {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
padding: 10px 20px;
|
||||
}
|
||||
|
||||
.bd-modal-wrapper .footer button {
|
||||
.bd-modal .footer button {
|
||||
min-height: 32px;
|
||||
min-width: 60px;
|
||||
align-items: center;
|
||||
|
@ -136,7 +152,7 @@
|
|||
user-select: none;
|
||||
}
|
||||
|
||||
.bd-modal-wrapper .tab-bar-container {
|
||||
.bd-modal .tab-bar-container {
|
||||
align-items: center;
|
||||
border-bottom: 0;
|
||||
background: rgba(0, 0, 0, 0.2);
|
||||
|
@ -147,7 +163,7 @@
|
|||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.bd-modal-wrapper .tab-bar.TOP {
|
||||
.bd-modal .tab-bar.TOP {
|
||||
margin: 0;
|
||||
border: 0;
|
||||
display: flex;
|
||||
|
@ -156,30 +172,30 @@
|
|||
align-items: center;
|
||||
}
|
||||
|
||||
.bd-modal-wrapper .tab-bar-container .tab-bar-item {
|
||||
margin: 0 15px;
|
||||
padding: 15px 0;
|
||||
color: #fff;
|
||||
opacity: 0.5;
|
||||
transition: opacity 200ms ease;
|
||||
border-bottom: 2px solid transparent;
|
||||
}
|
||||
|
||||
.bd-modal-wrapper .tab-bar-container .tab-bar-item:hover {
|
||||
border-color: #fff;
|
||||
.bd-modal .tab-bar-container .tab-bar-item {
|
||||
margin: 10px;
|
||||
padding: 7px 10px;
|
||||
border-radius: 5px;
|
||||
opacity: 0.7;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.bd-modal-wrapper .tab-bar-container .tab-bar-item.selected {
|
||||
.bd-modal .tab-bar-item:not(.selected):hover {
|
||||
background: var(--background-primary);
|
||||
}
|
||||
|
||||
.bd-modal .tab-bar.TOP .tab-bar-item:nth-child(1) {
|
||||
margin-left: 20px;
|
||||
}
|
||||
|
||||
.bd-modal .tab-bar-container .tab-bar-item.selected {
|
||||
opacity: 1;
|
||||
border-color: #fff;
|
||||
background: #36393f;
|
||||
border-radius: 5px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.bd-modal-wrapper .tab-bar.TOP .tab-bar-item + .tab-bar-item {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.bd-modal-wrapper .table-header {
|
||||
.bd-modal .table-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
color: #fff;
|
||||
|
@ -190,23 +206,23 @@
|
|||
font-size: 14px;
|
||||
}
|
||||
|
||||
.bd-modal-wrapper .table-column {
|
||||
.bd-modal .table-column {
|
||||
width: 25%;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
.bd-modal-wrapper .table-column.column-error {
|
||||
.bd-modal .table-column.column-error {
|
||||
width: 50%;
|
||||
}
|
||||
|
||||
.bd-modal-wrapper .errors {
|
||||
.bd-modal .errors {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
font-size: 14px;
|
||||
padding: 0 5px;
|
||||
}
|
||||
|
||||
.bd-modal-wrapper .error {
|
||||
.bd-modal .error {
|
||||
display: flex;
|
||||
color: #fff;
|
||||
border-bottom: 1px solid rgba(255, 255, 255, 0.25);
|
||||
|
@ -214,12 +230,12 @@
|
|||
align-items: center;
|
||||
}
|
||||
|
||||
.bd-modal-wrapper .error-link {
|
||||
.bd-modal .error-link {
|
||||
color: #3e82e5;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.bd-modal-wrapper .bd-content-modal .scroller {
|
||||
.bd-modal .bd-content-modal .scroller {
|
||||
padding-top: 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,122 @@
|
|||
import {React, Strings, WebpackModules} from "modules";
|
||||
import DownArrow from "./icons/downarrow";
|
||||
import Extension from "./icons/extension";
|
||||
import ThemeIcon from "./icons/theme";
|
||||
|
||||
const Parser = Object(WebpackModules.getByProps("defaultRules", "parse")).defaultRules;
|
||||
|
||||
const joinClassNames = (...classNames) => classNames.filter(e => e).join(" ");
|
||||
|
||||
class Collapse extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {opened: false};
|
||||
}
|
||||
|
||||
toggle() {
|
||||
if (!this.props.error.stack) return;
|
||||
this.setState({opened: !this.state.opened});
|
||||
}
|
||||
|
||||
render() {
|
||||
const title = this.props.error.error ? this.props.error.message : this.props.error.message;
|
||||
const stack = this.props.error.error && this.props.error.error.stack;
|
||||
|
||||
return <div className={joinClassNames("bd-addon-error-stack", this.state.opened && "opened")}>
|
||||
<div onClick={() => {this.toggle();}} className="bd-addon-error-stack-header">
|
||||
{!this.state.opened && title}
|
||||
{stack
|
||||
? <>
|
||||
<DownArrow />
|
||||
{this.state.opened && <div className="bd-addon-error-stack-shown">{Parser ? Parser.codeBlock.react({content: stack, lang: "js"}, null, {}) : stack}</div>}
|
||||
</>
|
||||
: null}
|
||||
</div>
|
||||
</div>;
|
||||
}
|
||||
}
|
||||
|
||||
export default class AddonErrorModal extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
const tabs = this.getTabs();
|
||||
|
||||
this.state = {
|
||||
selectedTab: tabs[0].id
|
||||
};
|
||||
}
|
||||
|
||||
mergeErrors(errors1 = [], errors2 = []) {
|
||||
const list = [];
|
||||
const allErrors = [...errors2, ...errors1];
|
||||
for (const error of allErrors) {
|
||||
if (list.find(e => e.file === error.file)) continue;
|
||||
list.push(error);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
refreshTabs(pluginErrors, themeErrors) {
|
||||
this._tabs = null;
|
||||
this.props.pluginErrors = this.mergeErrors(this.props.pluginErrors, pluginErrors);
|
||||
this.props.themeErrors = this.mergeErrors(this.props.themeErrors, themeErrors);
|
||||
this.forceUpdate();
|
||||
}
|
||||
|
||||
generateTab(id, errors) {
|
||||
return {
|
||||
id: id,
|
||||
name: Strings.Panels[id],
|
||||
errors: errors
|
||||
};
|
||||
}
|
||||
|
||||
getTabs() {
|
||||
return this._tabs || (this._tabs = [
|
||||
this.props.pluginErrors.length && this.generateTab("plugins", this.props.pluginErrors),
|
||||
this.props.themeErrors.length && this.generateTab("themes", this.props.themeErrors)
|
||||
].filter(e => e));
|
||||
}
|
||||
|
||||
renderError(err) {
|
||||
return <div className="bd-addon-error">
|
||||
<div className="bd-addon-error-header">
|
||||
{err.type == "plugin" ? <Extension /> : <ThemeIcon />}
|
||||
<div className="bd-addon-error-message">{err.name} - {err.message}</div>
|
||||
</div>
|
||||
<div className="bd-addon-error-body">
|
||||
<Collapse error={err} message={err.message} />
|
||||
</div>
|
||||
</div>;
|
||||
}
|
||||
|
||||
switchToTab(id) {
|
||||
this.setState({selectedTab: id});
|
||||
}
|
||||
|
||||
render() {
|
||||
const selectedTab = this.getTabs().find(e => this.state.selectedTab === e.id);
|
||||
const tabs = this.getTabs();
|
||||
return <div className="bd-modal bd-content-modal modal-1UGdnR">
|
||||
<div className="bd-modal-inner inner-1JeGVc">
|
||||
<div className="header header-1R_AjF"><div className="title">{Strings.Modals.addonErrors}</div></div>
|
||||
<div className="bd-modal-body">
|
||||
<div className="tab-bar-container">
|
||||
<div className="tab-bar TOP">
|
||||
{tabs.map(tab => <div onClick={() => {this.switchToTab(tab.id);}} className={joinClassNames("tab-bar-item", tab.id === selectedTab.id && "selected")}>{tab.name}</div>)}
|
||||
</div>
|
||||
</div>
|
||||
<div className="scroller-wrap fade">
|
||||
<div className="scroller">
|
||||
{selectedTab.errors.map(error => this.renderError(error))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="footer footer-2yfCgX footer-3rDWdC footer-2gL1pp">
|
||||
<button type="button" onClick={() => {this.props.onClose();}} className="bd-button">{Strings.Modals.okay}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>;
|
||||
}
|
||||
}
|
|
@ -2,6 +2,7 @@ import {Config} from "data";
|
|||
import Logger from "common/logger";
|
||||
import {WebpackModules, React, Settings, Strings, DOM, DiscordModules} from "modules";
|
||||
import FormattableString from "../structs/string";
|
||||
import AddonErrorModal from "./addonerrormodal";
|
||||
import ErrorBoundary from "./errorboundary";
|
||||
|
||||
export default class Modals {
|
||||
|
@ -53,7 +54,7 @@ export default class Modals {
|
|||
}
|
||||
|
||||
static alert(title, content) {
|
||||
this.showConfirmationModal(title, content, {cancelText: ""});
|
||||
this.showConfirmationModal(title, content, {cancelText: null});
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -97,78 +98,21 @@ export default class Modals {
|
|||
static showAddonErrors({plugins: pluginErrors = [], themes: themeErrors = []}) {
|
||||
if (!pluginErrors || !themeErrors || !this.shouldShowAddonErrors) return;
|
||||
if (!pluginErrors.length && !themeErrors.length) return;
|
||||
const modal = DOM.createElement(`<div class="bd-modal-wrapper theme-dark">
|
||||
<div class="bd-backdrop backdrop-1wrmKB"></div>
|
||||
<div class="bd-modal bd-content-modal modal-1UGdnR">
|
||||
<div class="bd-modal-inner inner-1JeGVc">
|
||||
<div class="header header-1R_AjF"><div class="title">${Strings.Modals.addonErrors}</div></div>
|
||||
<div class="bd-modal-body">
|
||||
<div class="tab-bar-container">
|
||||
<div class="tab-bar TOP">
|
||||
<div class="tab-bar-item">${Strings.Panels.plugins}</div>
|
||||
<div class="tab-bar-item">${Strings.Panels.themes}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="table-header">
|
||||
<div class="table-column column-name">${Strings.Modals.name}</div>
|
||||
<div class="table-column column-message">${Strings.Modals.message}</div>
|
||||
<div class="table-column column-error">${Strings.Modals.error}</div>
|
||||
</div>
|
||||
<div class="scroller-wrap fade">
|
||||
<div class="scroller">
|
||||
|
||||
if (this.addonErrorsRef && this.addonErrorsRef.current) {
|
||||
return this.addonErrorsRef.current.refreshTabs(Array.isArray(pluginErrors) ? pluginErrors : [], Array.isArray(themeErrors) ? themeErrors : []);
|
||||
}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="footer footer-2yfCgX footer-3rDWdC footer-2gL1pp">
|
||||
<button type="button" class="bd-button">${Strings.Modals.okay}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>`);
|
||||
|
||||
const generateTab = function(errors) {
|
||||
const container = DOM.createElement(`<div class="errors">`);
|
||||
for (const err of errors) {
|
||||
const error = DOM.createElement(`<div class="error">
|
||||
<div class="table-column column-name">${err.name ? err.name : err.file}</div>
|
||||
<div class="table-column column-message">${err.message}</div>
|
||||
<div class="table-column column-error"><a class="error-link" href="">${err.error ? err.error.message : ""}</a></div>
|
||||
</div>`);
|
||||
container.append(error);
|
||||
if (err.error) {
|
||||
error.querySelectorAll("a").forEach(el => el.addEventListener("click", (e) => {
|
||||
e.preventDefault();
|
||||
Logger.stacktrace("AddonError", `Error details for ${err.name ? err.name : err.file}.`, err.error);
|
||||
}));
|
||||
}
|
||||
}
|
||||
return container;
|
||||
};
|
||||
|
||||
const tabs = [generateTab(pluginErrors), generateTab(themeErrors)];
|
||||
|
||||
modal.querySelectorAll(".tab-bar-item").forEach(el => el.addEventListener("click", (e) => {
|
||||
e.preventDefault();
|
||||
const selected = modal.querySelector(".tab-bar-item.selected");
|
||||
if (selected) DOM.removeClass(selected, "selected");
|
||||
DOM.addClass(e.target, "selected");
|
||||
const scroller = modal.querySelector(".scroller");
|
||||
scroller.innerHTML = "";
|
||||
scroller.append(tabs[DOM.index(e.target)]);
|
||||
}));
|
||||
|
||||
modal.querySelector(".footer button").addEventListener("click", () => {
|
||||
DOM.addClass(modal, "closing");
|
||||
setTimeout(() => {modal.remove();}, 300);
|
||||
});
|
||||
modal.querySelector(".bd-backdrop").addEventListener("click", () => {
|
||||
DOM.addClass(modal, "closing");
|
||||
setTimeout(() => {modal.remove();}, 300);
|
||||
});
|
||||
DOM.query("#app-mount").append(modal);
|
||||
if (pluginErrors.length) modal.querySelector(".tab-bar-item").click();
|
||||
else modal.querySelectorAll(".tab-bar-item")[1].click();
|
||||
this.addonErrorsRef = React.createRef();
|
||||
this.ModalActions.openModal(props => React.createElement(this.ModalComponents.ModalRoot, Object.assign(props, {
|
||||
size: "medium",
|
||||
children: React.createElement(AddonErrorModal, {
|
||||
ref: this.addonErrorsRef,
|
||||
pluginErrors: Array.isArray(pluginErrors) ? pluginErrors : [],
|
||||
themeErrors: Array.isArray(themeErrors) ? themeErrors : [],
|
||||
onClose: props.onClose
|
||||
})
|
||||
})));
|
||||
}
|
||||
|
||||
static showChangelogModal(options = {}) {
|
||||
|
|
Loading…
Reference in New Issue