mirror of
https://github.com/hensm/fx_cast.git
synced 2026-06-08 08:39:59 +00:00
Format options index.tsx
This commit is contained in:
@@ -14,28 +14,24 @@ import logger from "../../lib/logger";
|
|||||||
import options, { Options } from "../../lib/options";
|
import options, { Options } from "../../lib/options";
|
||||||
import { REMOTE_MATCH_PATTERN_REGEX } from "../../lib/matchPattern";
|
import { REMOTE_MATCH_PATTERN_REGEX } from "../../lib/matchPattern";
|
||||||
|
|
||||||
|
|
||||||
const _ = browser.i18n.getMessage;
|
const _ = browser.i18n.getMessage;
|
||||||
|
|
||||||
|
|
||||||
// macOS styles
|
// macOS styles
|
||||||
browser.runtime.getPlatformInfo()
|
browser.runtime.getPlatformInfo().then(platformInfo => {
|
||||||
.then(platformInfo => {
|
const link = document.createElement("link");
|
||||||
const link = document.createElement("link");
|
link.rel = "stylesheet";
|
||||||
link.rel = "stylesheet";
|
|
||||||
|
|
||||||
switch (platformInfo.os) {
|
switch (platformInfo.os) {
|
||||||
case "mac": {
|
case "mac": {
|
||||||
link.href = "styles/mac.css";
|
link.href = "styles/mac.css";
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (link.href) {
|
if (link.href) {
|
||||||
document.head.appendChild(link);
|
document.head.appendChild(link);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
function getInputValue(input: HTMLInputElement) {
|
function getInputValue(input: HTMLInputElement) {
|
||||||
switch (input.type) {
|
switch (input.type) {
|
||||||
@@ -62,17 +58,15 @@ interface OptionsAppState {
|
|||||||
platform?: string;
|
platform?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
class OptionsApp extends Component<
|
class OptionsApp extends Component<OptionsAppProps, OptionsAppState> {
|
||||||
OptionsAppProps, OptionsAppState> {
|
private form: HTMLFormElement | null = null;
|
||||||
|
|
||||||
private form: (HTMLFormElement | null) = null;
|
|
||||||
|
|
||||||
state: OptionsAppState = {
|
state: OptionsAppState = {
|
||||||
hasLoaded: false
|
hasLoaded: false,
|
||||||
, bridgeLoading: true
|
bridgeLoading: true,
|
||||||
, bridgeLoadingTimedOut: false
|
bridgeLoadingTimedOut: false,
|
||||||
, isFormValid: true
|
isFormValid: true,
|
||||||
, hasSaved: false
|
hasSaved: false
|
||||||
};
|
};
|
||||||
|
|
||||||
constructor(props: OptionsAppProps) {
|
constructor(props: OptionsAppProps) {
|
||||||
@@ -85,16 +79,16 @@ class OptionsApp extends Component<
|
|||||||
this.handleWhitelistChange = this.handleWhitelistChange.bind(this);
|
this.handleWhitelistChange = this.handleWhitelistChange.bind(this);
|
||||||
|
|
||||||
this.getWhitelistItemPatternError =
|
this.getWhitelistItemPatternError =
|
||||||
this.getWhitelistItemPatternError.bind(this);
|
this.getWhitelistItemPatternError.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async componentDidMount() {
|
public async componentDidMount() {
|
||||||
this.setState({
|
this.setState({
|
||||||
hasLoaded: true
|
hasLoaded: true,
|
||||||
, options: await options.getAll()
|
options: await options.getAll(),
|
||||||
, platform: (await browser.runtime.getPlatformInfo()).os
|
platform: (await browser.runtime.getPlatformInfo()).os
|
||||||
});
|
});
|
||||||
|
|
||||||
// Update options data if changed whilst page is open
|
// Update options data if changed whilst page is open
|
||||||
options.addEventListener("changed", async () => {
|
options.addEventListener("changed", async () => {
|
||||||
this.setState({
|
this.setState({
|
||||||
@@ -106,16 +100,16 @@ class OptionsApp extends Component<
|
|||||||
const bridgeInfo = await bridge.getInfo();
|
const bridgeInfo = await bridge.getInfo();
|
||||||
|
|
||||||
this.setState({
|
this.setState({
|
||||||
bridgeInfo
|
bridgeInfo,
|
||||||
, bridgeLoading: false
|
bridgeLoading: false
|
||||||
});
|
});
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
logger.error("Failed to fetch bridge/platform info.");
|
logger.error("Failed to fetch bridge/platform info.");
|
||||||
|
|
||||||
if (err instanceof BridgeTimedOutError) {
|
if (err instanceof BridgeTimedOutError) {
|
||||||
this.setState({
|
this.setState({
|
||||||
bridgeLoading: false
|
bridgeLoading: false,
|
||||||
, bridgeLoadingTimedOut: true
|
bridgeLoadingTimedOut: true
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
this.setState({
|
this.setState({
|
||||||
@@ -132,60 +126,76 @@ class OptionsApp extends Component<
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<form id="form" ref={ form => { this.form = form; }}
|
<form
|
||||||
onSubmit={ this.handleFormSubmit }
|
id="form"
|
||||||
onChange={ this.handleFormChange }>
|
ref={form => {
|
||||||
|
this.form = form;
|
||||||
<Bridge info={ this.state.bridgeInfo }
|
}}
|
||||||
loading={ this.state.bridgeLoading }
|
onSubmit={this.handleFormSubmit}
|
||||||
loadingTimedOut={ this.state.bridgeLoadingTimedOut }
|
onChange={this.handleFormChange}
|
||||||
options={ this.state.options }
|
>
|
||||||
onChange={ this.handleInputChange } />
|
<Bridge
|
||||||
|
info={this.state.bridgeInfo}
|
||||||
|
loading={this.state.bridgeLoading}
|
||||||
|
loadingTimedOut={this.state.bridgeLoadingTimedOut}
|
||||||
|
options={this.state.options}
|
||||||
|
onChange={this.handleInputChange}
|
||||||
|
/>
|
||||||
|
|
||||||
<fieldset className="category">
|
<fieldset className="category">
|
||||||
<legend className="category__name">
|
<legend className="category__name">
|
||||||
<h2>{ _("optionsMediaCategoryName") }</h2>
|
<h2>{_("optionsMediaCategoryName")}</h2>
|
||||||
</legend>
|
</legend>
|
||||||
<p className="category__description">
|
<p className="category__description">
|
||||||
{ _("optionsMediaCategoryDescription") }
|
{_("optionsMediaCategoryDescription")}
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<label className="option option--inline">
|
<label className="option option--inline">
|
||||||
<div className="option__control">
|
<div className="option__control">
|
||||||
<input name="mediaEnabled"
|
<input
|
||||||
type="checkbox"
|
name="mediaEnabled"
|
||||||
checked={ this.state.options?.mediaEnabled }
|
type="checkbox"
|
||||||
onChange={ this.handleInputChange } />
|
checked={this.state.options?.mediaEnabled}
|
||||||
|
onChange={this.handleInputChange}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="option__label">
|
<div className="option__label">
|
||||||
{ _("optionsMediaEnabled") }
|
{_("optionsMediaEnabled")}
|
||||||
</div>
|
</div>
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
<label className="option option--inline">
|
<label className="option option--inline">
|
||||||
<div className="option__control">
|
<div className="option__control">
|
||||||
<input name="mediaSyncElement"
|
<input
|
||||||
type="checkbox"
|
name="mediaSyncElement"
|
||||||
checked={ this.state.options?.mediaSyncElement }
|
type="checkbox"
|
||||||
onChange={ this.handleInputChange } />
|
checked={
|
||||||
|
this.state.options?.mediaSyncElement
|
||||||
|
}
|
||||||
|
onChange={this.handleInputChange}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="option__label">
|
<div className="option__label">
|
||||||
{ _("optionsMediaSyncElement") }
|
{_("optionsMediaSyncElement")}
|
||||||
</div>
|
</div>
|
||||||
<div className="option__description">
|
<div className="option__description">
|
||||||
{ _("optionsMediaSyncElementDescription") }
|
{_("optionsMediaSyncElementDescription")}
|
||||||
</div>
|
</div>
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
<label className="option option--inline">
|
<label className="option option--inline">
|
||||||
<div className="option__control">
|
<div className="option__control">
|
||||||
<input name="mediaStopOnUnload"
|
<input
|
||||||
type="checkbox"
|
name="mediaStopOnUnload"
|
||||||
checked={ this.state.options?.mediaStopOnUnload }
|
type="checkbox"
|
||||||
onChange={ this.handleInputChange } />
|
checked={
|
||||||
|
this.state.options?.mediaStopOnUnload
|
||||||
|
}
|
||||||
|
onChange={this.handleInputChange}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="option__label">
|
<div className="option__label">
|
||||||
{ _("optionsMediaStopOnUnload") }
|
{_("optionsMediaStopOnUnload")}
|
||||||
</div>
|
</div>
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
@@ -193,67 +203,81 @@ class OptionsApp extends Component<
|
|||||||
|
|
||||||
<label className="option option--inline">
|
<label className="option option--inline">
|
||||||
<div className="option__control">
|
<div className="option__control">
|
||||||
<input name="localMediaEnabled"
|
<input
|
||||||
type="checkbox"
|
name="localMediaEnabled"
|
||||||
checked={ this.state.options?.localMediaEnabled }
|
type="checkbox"
|
||||||
onChange={ this.handleInputChange } />
|
checked={
|
||||||
|
this.state.options?.localMediaEnabled
|
||||||
|
}
|
||||||
|
onChange={this.handleInputChange}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="option__label">
|
<div className="option__label">
|
||||||
{ _("optionsLocalMediaEnabled") }
|
{_("optionsLocalMediaEnabled")}
|
||||||
</div>
|
</div>
|
||||||
<div className="option__description">
|
<div className="option__description">
|
||||||
{ _("optionsLocalMediaCategoryDescription") }
|
{_("optionsLocalMediaCategoryDescription")}
|
||||||
</div>
|
</div>
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
<label className="option">
|
<label className="option">
|
||||||
<div className="option__label">
|
<div className="option__label">
|
||||||
{ _("optionsLocalMediaServerPort") }
|
{_("optionsLocalMediaServerPort")}
|
||||||
</div>
|
</div>
|
||||||
<div className="option__control">
|
<div className="option__control">
|
||||||
<input name="localMediaServerPort"
|
<input
|
||||||
type="number"
|
name="localMediaServerPort"
|
||||||
required
|
type="number"
|
||||||
min="1025"
|
required
|
||||||
max="65535"
|
min="1025"
|
||||||
value={ this.state.options?.localMediaServerPort }
|
max="65535"
|
||||||
onChange={ this.handleInputChange } />
|
value={
|
||||||
|
this.state.options?.localMediaServerPort
|
||||||
|
}
|
||||||
|
onChange={this.handleInputChange}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</label>
|
</label>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
|
||||||
<fieldset className="category">
|
<fieldset className="category">
|
||||||
<legend className="category__name">
|
<legend className="category__name">
|
||||||
<h2>{ _("optionsMirroringCategoryName") }</h2>
|
<h2>{_("optionsMirroringCategoryName")}</h2>
|
||||||
</legend>
|
</legend>
|
||||||
<p className="category__description">
|
<p className="category__description">
|
||||||
{ _("optionsMirroringCategoryDescription") }
|
{_("optionsMirroringCategoryDescription")}
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<label className="option option--inline">
|
<label className="option option--inline">
|
||||||
<div className="option__control">
|
<div className="option__control">
|
||||||
<input name="mirroringEnabled"
|
<input
|
||||||
type="checkbox"
|
name="mirroringEnabled"
|
||||||
checked={ this.state.options?.mirroringEnabled }
|
type="checkbox"
|
||||||
onChange={ this.handleInputChange } />
|
checked={
|
||||||
|
this.state.options?.mirroringEnabled
|
||||||
|
}
|
||||||
|
onChange={this.handleInputChange}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="option__label">
|
<div className="option__label">
|
||||||
{ _("optionsMirroringEnabled") }
|
{_("optionsMirroringEnabled")}
|
||||||
</div>
|
</div>
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
<label className="option">
|
<label className="option">
|
||||||
<div className="option__label">
|
<div className="option__label">
|
||||||
{ _("optionsMirroringAppId") }
|
{_("optionsMirroringAppId")}
|
||||||
</div>
|
</div>
|
||||||
<div className="option__control">
|
<div className="option__control">
|
||||||
<input name="mirroringAppId"
|
<input
|
||||||
type="text"
|
name="mirroringAppId"
|
||||||
required
|
type="text"
|
||||||
value={ this.state.options?.mirroringAppId }
|
required
|
||||||
onChange={ this.handleInputChange } />
|
value={this.state.options?.mirroringAppId}
|
||||||
|
onChange={this.handleInputChange}
|
||||||
|
/>
|
||||||
<div className="option__description">
|
<div className="option__description">
|
||||||
{ _("optionsMirroringAppIdDescription") }
|
{_("optionsMirroringAppIdDescription")}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</label>
|
</label>
|
||||||
@@ -261,108 +285,145 @@ class OptionsApp extends Component<
|
|||||||
|
|
||||||
<fieldset className="category">
|
<fieldset className="category">
|
||||||
<legend className="category__name">
|
<legend className="category__name">
|
||||||
<h2>{ _("optionsReceiverSelectorCategoryName") }</h2>
|
<h2>{_("optionsReceiverSelectorCategoryName")}</h2>
|
||||||
</legend>
|
</legend>
|
||||||
<p className="category__description">
|
<p className="category__description">
|
||||||
{ _("optionsReceiverSelectorCategoryDescription") }
|
{_("optionsReceiverSelectorCategoryDescription")}
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<label className="option option--inline">
|
<label className="option option--inline">
|
||||||
<div className="option__control">
|
<div className="option__control">
|
||||||
<input name="receiverSelectorWaitForConnection"
|
<input
|
||||||
type="checkbox"
|
name="receiverSelectorWaitForConnection"
|
||||||
checked={ this.state.options?.receiverSelectorWaitForConnection }
|
type="checkbox"
|
||||||
onChange={ this.handleInputChange } />
|
checked={
|
||||||
|
this.state.options
|
||||||
|
?.receiverSelectorWaitForConnection
|
||||||
|
}
|
||||||
|
onChange={this.handleInputChange}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="option__label">
|
<div className="option__label">
|
||||||
{ _("optionsReceiverSelectorWaitForConnection") }
|
{_("optionsReceiverSelectorWaitForConnection")}
|
||||||
</div>
|
</div>
|
||||||
<div className="option__description">
|
<div className="option__description">
|
||||||
{ _("optionsReceiverSelectorWaitForConnectionDescription") }
|
{_(
|
||||||
|
"optionsReceiverSelectorWaitForConnectionDescription"
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
<label className="option option--inline">
|
<label className="option option--inline">
|
||||||
<div className="option__control">
|
<div className="option__control">
|
||||||
<input name="receiverSelectorCloseIfFocusLost"
|
<input
|
||||||
type="checkbox"
|
name="receiverSelectorCloseIfFocusLost"
|
||||||
checked={ this.state.options?.receiverSelectorCloseIfFocusLost }
|
type="checkbox"
|
||||||
onChange={ this.handleInputChange } />
|
checked={
|
||||||
|
this.state.options
|
||||||
|
?.receiverSelectorCloseIfFocusLost
|
||||||
|
}
|
||||||
|
onChange={this.handleInputChange}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="option__label">
|
<div className="option__label">
|
||||||
{ _("optionsReceiverSelectorCloseIfFocusLost") }
|
{_("optionsReceiverSelectorCloseIfFocusLost")}
|
||||||
</div>
|
</div>
|
||||||
</label>
|
</label>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
|
||||||
<fieldset className="category">
|
<fieldset className="category">
|
||||||
<legend className="category__name">
|
<legend className="category__name">
|
||||||
<h2>{ _("optionsUserAgentWhitelistCategoryName") }</h2>
|
<h2>
|
||||||
|
{_("optionsUserAgentWhitelistCategoryName")}
|
||||||
|
</h2>
|
||||||
</legend>
|
</legend>
|
||||||
<p className="category__description">
|
<p className="category__description">
|
||||||
{ _("optionsUserAgentWhitelistCategoryDescription") }
|
{_("optionsUserAgentWhitelistCategoryDescription")}
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<label className="option option--inline">
|
<label className="option option--inline">
|
||||||
<div className="option__control">
|
<div className="option__control">
|
||||||
<input name="userAgentWhitelistEnabled"
|
<input
|
||||||
type="checkbox"
|
name="userAgentWhitelistEnabled"
|
||||||
checked={ this.state.options?.userAgentWhitelistEnabled }
|
type="checkbox"
|
||||||
onChange={ this.handleInputChange } />
|
checked={
|
||||||
|
this.state.options
|
||||||
|
?.userAgentWhitelistEnabled
|
||||||
|
}
|
||||||
|
onChange={this.handleInputChange}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="option__label">
|
<div className="option__label">
|
||||||
{ _("optionsUserAgentWhitelistEnabled") }
|
{_("optionsUserAgentWhitelistEnabled")}
|
||||||
<span className="option__recommended">
|
<span className="option__recommended">
|
||||||
{ _("optionsOptionRecommended") }
|
{_("optionsOptionRecommended")}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
<label className="option option--inline">
|
<label className="option option--inline">
|
||||||
<div className="option__control">
|
<div className="option__control">
|
||||||
<input name="userAgentWhitelistRestrictedEnabled"
|
<input
|
||||||
type="checkbox"
|
name="userAgentWhitelistRestrictedEnabled"
|
||||||
checked={ this.state.options?.userAgentWhitelistRestrictedEnabled }
|
type="checkbox"
|
||||||
onChange={ this.handleInputChange } />
|
checked={
|
||||||
|
this.state.options
|
||||||
|
?.userAgentWhitelistRestrictedEnabled
|
||||||
|
}
|
||||||
|
onChange={this.handleInputChange}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="option__label">
|
<div className="option__label">
|
||||||
{ _("optionsUserAgentWhitelistRestrictedEnabled") }
|
{_(
|
||||||
|
"optionsUserAgentWhitelistRestrictedEnabled"
|
||||||
|
)}
|
||||||
<span className="option__recommended">
|
<span className="option__recommended">
|
||||||
{ _("optionsOptionRecommended") }
|
{_("optionsOptionRecommended")}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="option__description">
|
<div className="option__description">
|
||||||
{ _("optionsUserAgentWhitelistRestrictedEnabledDescription") }
|
{_(
|
||||||
|
"optionsUserAgentWhitelistRestrictedEnabledDescription"
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
<div className="option">
|
<div className="option">
|
||||||
<div className="option__label">
|
<div className="option__label">
|
||||||
{ _("optionsUserAgentWhitelistContent") }
|
{_("optionsUserAgentWhitelistContent")}
|
||||||
</div>
|
</div>
|
||||||
<div className="option__control">
|
<div className="option__control">
|
||||||
{ this.state.options?.userAgentWhitelist &&
|
{this.state.options?.userAgentWhitelist && (
|
||||||
<EditableList data={ this.state.options.userAgentWhitelist }
|
<EditableList
|
||||||
onChange={ this.handleWhitelistChange }
|
data={
|
||||||
itemPattern={ REMOTE_MATCH_PATTERN_REGEX }
|
this.state.options
|
||||||
itemPatternError={ this.getWhitelistItemPatternError } /> }
|
.userAgentWhitelist
|
||||||
|
}
|
||||||
|
onChange={this.handleWhitelistChange}
|
||||||
|
itemPattern={REMOTE_MATCH_PATTERN_REGEX}
|
||||||
|
itemPatternError={
|
||||||
|
this.getWhitelistItemPatternError
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
|
||||||
<div id="buttons">
|
<div id="buttons">
|
||||||
<div id="status-line">
|
<div id="status-line">
|
||||||
{ this.state.hasSaved && _("optionsSaved") }
|
{this.state.hasSaved && _("optionsSaved")}
|
||||||
</div>
|
</div>
|
||||||
<button onClick={ this.handleReset }
|
<button onClick={this.handleReset} type="button">
|
||||||
type="button">
|
{_("optionsReset")}
|
||||||
{ _("optionsReset") }
|
|
||||||
</button>
|
</button>
|
||||||
<button type="submit"
|
<button
|
||||||
// @ts-ignore
|
type="submit"
|
||||||
default
|
// @ts-ignore
|
||||||
disabled={ !this.state.isFormValid }>
|
default
|
||||||
{ _("optionsSave") }
|
disabled={!this.state.isFormValid}
|
||||||
|
>
|
||||||
|
{_("optionsSave")}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
@@ -370,7 +431,6 @@ class OptionsApp extends Component<
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private handleReset() {
|
private handleReset() {
|
||||||
this.setState({
|
this.setState({
|
||||||
options: { ...defaultOptions }
|
options: { ...defaultOptions }
|
||||||
@@ -386,15 +446,18 @@ class OptionsApp extends Component<
|
|||||||
if (this.state.options) {
|
if (this.state.options) {
|
||||||
await options.setAll(this.state.options);
|
await options.setAll(this.state.options);
|
||||||
|
|
||||||
this.setState({
|
this.setState(
|
||||||
hasSaved: true
|
{
|
||||||
}, () => {
|
hasSaved: true
|
||||||
window.setTimeout(() => {
|
},
|
||||||
this.setState({
|
() => {
|
||||||
hasSaved: false
|
window.setTimeout(() => {
|
||||||
});
|
this.setState({
|
||||||
}, 1000);
|
hasSaved: false
|
||||||
});
|
});
|
||||||
|
}, 1000);
|
||||||
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
logger.error("Failed to save options");
|
logger.error("Failed to save options");
|
||||||
|
|||||||
Reference in New Issue
Block a user