Narrow linting rules and fix for eslintrc for js files

This commit is contained in:
hensm
2022-04-27 22:28:38 +01:00
parent 5e2d9a2fbc
commit dececa46c3
27 changed files with 298 additions and 246 deletions

View File

@@ -1,30 +1,48 @@
{
"root": true,
"parser": "@typescript-eslint/parser",
"plugins": [ "@typescript-eslint" ],
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/recommended",
"prettier"
],
"plugins": ["@typescript-eslint"],
"extends": ["eslint:recommended", "prettier"],
"rules": {
"no-useless-escape": "off",
"no-prototype-builtins": "off",
"no-async-promise-executor": "off",
"semi": [ "error", "always"],
"no-multiple-empty-lines": [ "error", { "max": 2 }],
"no-console": [ "error", {
"allow": [ "info", "warn", "error" ]
}],
"semi": ["error", "always"],
"no-multiple-empty-lines": ["error", { "max": 2 }],
"no-console": [
"error",
{
"allow": ["info", "warn", "error"]
}
]
},
"@typescript-eslint/no-empty-interface": "off",
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/explicit-module-boundary-types": "off",
"@typescript-eslint/no-unused-vars": "off",
"@typescript-eslint/ban-types": "off",
"@typescript-eslint/ban-ts-comment": "off",
"@typescript-eslint/no-this-alias": [ "error", {
"allowedNames": [ "this_" ]
}]
}
"overrides": [
{
"files": ["*/bin/**/*.js"],
"env": {
"node": true
}
},
{
"files": ["**/*.ts", "**/*.tsx"],
"extends": "plugin:@typescript-eslint/recommended",
"rules": {
"@typescript-eslint/no-empty-interface": "off",
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/explicit-module-boundary-types": "off",
"@typescript-eslint/no-unused-vars": [
"error",
{ "argsIgnorePattern": "^_" }
],
"@typescript-eslint/ban-ts-comment": "off",
"@typescript-eslint/no-this-alias": [
"error",
{
"allowedNames": ["this_"]
}
]
}
}
]
}

View File

@@ -489,8 +489,7 @@ function packageLinuxRpm(
function packageWin32(
arch,
platformExecutableName,
platformExecutablePath,
platformManifestPath
platformExecutablePath
) {
const outputName = `${meta.__applicationName}-${meta.__applicationVersion}-${arch}.exe`;
@@ -525,6 +524,6 @@ function packageWin32(
}
build().catch(e => {
console.log("Build failed", e);
console.error("Build failed", e);
process.exit(1);
});

1
app/package-lock.json generated
View File

@@ -13,7 +13,6 @@
"mime-types": "^2.1.35",
"minimist": "^1.2.6",
"node-fetch": "^3.2.3",
"rage-edit": "*",
"tweetnacl": "^1.0.3",
"ws": "^8.5.0"
},

View File

@@ -72,8 +72,6 @@ export default class Session extends CastClient {
this.establishAppConnection(this.transportId);
this.onSessionCreated?.(this.sessionId);
const { friendlyName } = this.receiverDevice;
messaging.sendMessage({
subject: "cast:sessionCreated",
data: {

View File

@@ -3,7 +3,7 @@
import messaging, { Message } from "../../messaging";
import Session from "./Session";
import CastClient, { NS_CONNECTION, NS_RECEIVER } from "./client";
import CastClient from "./client";
const sessions = new Map<string, Session>();

View File

@@ -125,7 +125,7 @@ interface BreakClip {
contentId?: string;
contentType?: string;
contentUrl?: string;
customData?: {};
customData?: unknown;
duration?: number;
id: string;
hlsSegmentFormat?: HlsSegmentFormat;
@@ -137,7 +137,7 @@ interface BreakClip {
interface TextTrackStyle {
backgroundColor: Nullable<string>;
customData: any;
customData: unknown;
edgeColor: Nullable<string>;
edgeType: Nullable<string>;
fontFamily: Nullable<string>;
@@ -151,7 +151,7 @@ interface TextTrackStyle {
}
interface Track {
customData: any;
customData: unknown;
language: Nullable<string>;
name: Nullable<string>;
subtype: Nullable<string>;
@@ -162,7 +162,7 @@ interface Track {
}
interface UserActionState {
customData: any;
customData: unknown;
userAction: UserAction;
}
@@ -185,7 +185,7 @@ interface MediaInformation {
contentId: string;
contentType: string;
contentUrl?: string;
customData: any;
customData: unknown;
duration: Nullable<number>;
entity?: string;
hlsSegmentFormat?: HlsSegmentFormat;
@@ -269,7 +269,7 @@ interface PhotoMediaMetadata {
interface QueueItem {
activeTrackIds: Nullable<number[]>;
autoplay: boolean;
customData: any;
customData: unknown;
itemId: Nullable<number>;
media: MediaInformation;
playbackDuration: Nullable<number>;

View File

@@ -6,7 +6,7 @@ import { handleCastMessage } from "./components/cast";
import { startDiscovery, stopDiscovery } from "./components/discovery";
import { startMediaServer, stopMediaServer } from "./components/mediaServer";
import { __applicationName, __applicationVersion } from "../../package.json";
import { __applicationVersion } from "../../package.json";
process.on("SIGTERM", () => {
stopDiscovery();

View File

@@ -37,7 +37,6 @@ export async function convertSrtToVtt(srtFilePath: string) {
* millisecond separator.
*/
for (const groups of fileContents.matchAll(REGEX_CAPTION)) {
const captionSource = groups[0];
const captionIndex = groups[1];
const captionTime = groups[2];
const captionText = groups[3];

View File

@@ -163,12 +163,12 @@ type MessageDefinitions = {
/**
* Sent to bridge to stop HTTP media server.
*/
"bridge:stopMediaServer": {};
"bridge:stopMediaServer": undefined;
/**
* Sent to media sender from bridge when the media server has
* stopped.
*/
"mediaCast:mediaServerStopped": {};
"mediaCast:mediaServerStopped": undefined;
/**
* Sent to media sender from bridge when the media server has
* encountered an error.
@@ -190,8 +190,8 @@ type Messages = {
* all-optional keys.
*/
type NarrowedMessage<L extends MessageBase<keyof MessageDefinitions>> =
L extends any
? {} extends L["data"]
L extends unknown
? undefined extends L["data"]
? Omit<L, "data"> & Partial<L>
: L
: never;
@@ -231,7 +231,7 @@ class Messenger extends TypedEmitter<MessengerEvents> {
this.encodeTransform.write(message);
}
send(data: any) {
send(data: unknown) {
this.encodeTransform.write(data);
}
}

View File

@@ -1,9 +1,9 @@
"use strict";
import { Transform } from "stream";
import { Transform, TransformCallback } from "stream";
import { Message } from "./bridge/messaging";
type ResponseHandlerFunction = (message: Message) => Promise<any>;
type ResponseHandlerFunction = (message: Message) => Promise<unknown>;
/**
* Takes a handler function that implements the transform
@@ -20,8 +20,7 @@ export class ResponseTransform extends Transform {
public _transform(
chunk: Message,
_encoding: string,
// tslint:disable-next-line:ban-types
callback: Function
callback: TransformCallback
) {
Promise.resolve(this._handler(chunk)).then(res => {
if (res) {
@@ -49,10 +48,10 @@ export class DecodeTransform extends Transform {
}
public _transform(
chunk: any,
chunk: Uint8Array,
_encoding: string,
// tslint:disable-next-line:ban-types
callback: Function
callback: TransformCallback
) {
// Append next chunk to buffer
this._messageBuffer = Buffer.concat([this._messageBuffer, chunk]);
@@ -108,10 +107,10 @@ export class EncodeTransform extends Transform {
}
public _transform(
chunk: any,
chunk: Uint8Array,
_encoding: string,
// tslint:disable-next-line:ban-types
callback: Function
callback: TransformCallback
) {
const messageLength = Buffer.alloc(4);
const message = Buffer.from(JSON.stringify(chunk));

View File

@@ -53,7 +53,7 @@ const preactCompatPlugin = {
"../node_modules/preact/compat/dist/compat.module.js"
);
build.onResolve({ filter: /^(react|react-dom)$/ }, args => ({
build.onResolve({ filter: /^(react|react-dom)$/ }, () => ({
path: preactPath
}));
}

View File

@@ -5,7 +5,7 @@ import logger from "../lib/logger";
import { TypedEventTarget } from "../lib/TypedEventTarget";
import { Message, Port } from "../messaging";
import { ReceiverDevice, ReceiverDeviceCapabilities } from "../types";
import { ReceiverDevice } from "../types";
import { ReceiverStatus } from "../cast/sdk/types";
interface EventMap {

View File

@@ -1,7 +1,6 @@
"use strict";
import logger from "../lib/logger";
import { TypedEventTarget } from "../lib/TypedEventTarget";
import { Message } from "../messaging";
type EventMessengerListener = (message: Message) => void;

View File

@@ -1,6 +1,6 @@
"use strict";
import messaging, { Message } from "../messaging";
import { Message } from "../messaging";
import { BridgeInfo } from "../lib/bridge";
import { TypedMessagePort } from "../lib/TypedMessagePort";

View File

@@ -17,8 +17,7 @@ if (!_window.chrome) {
// Create page-accessible API object
_window.chrome.cast = new CastSDK();
let bridgeInfo: any;
let frameworkScriptPromise: Promise<HTMLScriptElement>;
let frameworkScriptPromise: Promise<HTMLScriptElement> | undefined;
/**
* If loaded within a page via a <script> element,
@@ -27,8 +26,9 @@ let frameworkScriptPromise: Promise<HTMLScriptElement>;
*/
if (document.currentScript) {
const currentScript = document.currentScript as HTMLScriptElement;
const currentScriptUrl = new URL(currentScript.src);
const currentScriptParams = new URLSearchParams(currentScriptUrl.search);
const currentScriptParams = new URLSearchParams(
new URL(currentScript.src).search
);
// Load Framework API if requested
if (currentScriptParams.get("loadCastFramework") === "1") {
@@ -43,17 +43,13 @@ if (document.currentScript) {
eventMessaging.page.addListener(async message => {
switch (message.subject) {
case "cast:initialized": {
bridgeInfo = message.data;
// If framework API is requested, ensure loaded
if (frameworkScriptPromise) {
await frameworkScriptPromise;
}
await frameworkScriptPromise;
// Call page script/framework API script's init function
const initFn = _window.__onGCastApiAvailable;
if (initFn && typeof initFn === "function") {
initFn(bridgeInfo && bridgeInfo.isVersionCompatible);
initFn(message.data.isVersionCompatible);
}
break;

View File

@@ -36,7 +36,7 @@ export class Error {
constructor(
public code: string,
public description: Nullable<string> = null,
public details: any = null
public details: unknown = null
) {}
}

View File

@@ -45,7 +45,7 @@ export default class Media {
activeTrackIds: Nullable<number[]> = null;
breakStatus?: BreakStatus;
currentTime = 0;
customData: any = null;
customData: unknown = null;
idleReason: Nullable<string> = null;
liveSeekableRange?: LiveSeekableRange;
media: Nullable<MediaInfo> = null;

View File

@@ -49,7 +49,7 @@ export class BreakClip {
contentId?: string;
contentType?: string;
contentUrl?: string;
customData?: {};
customData?: unknown;
duration?: number;
hlsSegmentFormat?: HlsSegmentFormat;
posterUrl?: string;
@@ -99,7 +99,7 @@ export class GenericMediaMetadata {
}
export class GetStatusRequest {
customData: any = null;
customData: unknown = null;
}
export class LiveSeekableRange {
@@ -117,7 +117,7 @@ export class LoadRequest {
atvCredentialsType?: string;
autoplay: Nullable<boolean> = true;
currentTime: Nullable<number> = null;
customData: any = null;
customData: unknown = null;
media: MediaInfo;
requestId = 0;
sessionId: Nullable<string> = null;
@@ -139,7 +139,7 @@ export class MediaInfo {
atvEntity?: string;
breakClips?: BreakClip[];
breaks?: Break[];
customData: any = null;
customData: unknown = null;
contentUrl?: string;
duration: Nullable<number> = null;
entity?: string;
@@ -200,7 +200,7 @@ export class MusicTrackMediaMetadata {
}
export class PauseRequest {
customData: any = null;
customData: unknown = null;
}
export class PhotoMediaMetadata {
@@ -218,7 +218,7 @@ export class PhotoMediaMetadata {
}
export class PlayRequest {
customData: any = null;
customData: unknown = null;
}
export class QueueData {
@@ -236,7 +236,7 @@ export class QueueData {
}
export class QueueInsertItemsRequest {
customData: any = null;
customData: unknown = null;
insertBefore: Nullable<number> = null;
requestId: Nullable<number> = null;
sessionId: Nullable<string> = null;
@@ -248,7 +248,7 @@ export class QueueInsertItemsRequest {
export class QueueItem {
activeTrackIds: Nullable<number[]> = null;
autoplay = true;
customData: any = null;
customData: unknown = null;
itemId: Nullable<number> = null;
media: MediaInfo;
playbackDuration: Nullable<number> = null;
@@ -268,7 +268,7 @@ export class QueueJumpRequest {
export class QueueLoadRequest {
type = "QUEUE_LOAD";
customData: any = null;
customData: unknown = null;
repeatMode: string = RepeatMode.OFF;
startIndex = 0;
@@ -277,13 +277,13 @@ export class QueueLoadRequest {
export class QueueRemoveItemsRequest {
type = "QUEUE_REMOVE";
customData: any = null;
customData: unknown = null;
constructor(public itemIds: number[]) {}
}
export class QueueReorderItemsRequest {
customData: any = null;
customData: unknown = null;
insertBefore: Nullable<number> = null;
type = "QUEUE_REORDER";
@@ -292,30 +292,30 @@ export class QueueReorderItemsRequest {
export class QueueSetPropertiesRequest {
type = "QUEUE_UPDATE";
customData: any = null;
customData: unknown = null;
repeatMode: Nullable<string> = null;
}
export class QueueUpdateItemsRequest {
type = "QUEUE_UPDATE";
customData: any = null;
customData: unknown = null;
constructor(public items: QueueItem[]) {}
}
export class SeekRequest {
currentTime: Nullable<number> = null;
customData: any = null;
customData: unknown = null;
resumeState: Nullable<ResumeState> = null;
}
export class StopRequest {
customData: any = null;
customData: unknown = null;
}
export class TextTrackStyle {
backgroundColor: Nullable<string> = null;
customData: any = null;
customData: unknown = null;
edgeColor: Nullable<string> = null;
edgeType: Nullable<string> = null;
fontFamily: Nullable<string> = null;
@@ -329,7 +329,7 @@ export class TextTrackStyle {
}
export class Track {
customData: any = null;
customData: unknown = null;
language: Nullable<string> = null;
name: Nullable<string> = null;
subtype: Nullable<string> = null;
@@ -355,7 +355,7 @@ export class TvShowMediaMetadata {
}
export class UserActionState {
customData: any = null;
customData: unknown = null;
constructor(public userAction: UserAction) {}
}
@@ -374,7 +374,7 @@ export class VideoInformation {
}
export class VolumeRequest {
customData: any = null;
customData: unknown = null;
constructor(public volume: Volume) {}
}

View File

@@ -7,6 +7,10 @@ import cast, { ensureInit } from "../../export";
import { Message } from "../../../messaging";
import { ReceiverDevice } from "../../../types";
import type Session from "../../sdk/Session";
import type Media from "../../sdk/media/Media";
import type { Error as Error_ } from "../../sdk/classes";
function startMediaServer(
filePath: string,
port: number
@@ -49,12 +53,12 @@ function startMediaServer(
let backgroundPort: MessagePort;
let currentSession: cast.Session;
let currentMedia: cast.media.Media;
let currentSession: Session;
let currentMedia: Media;
let targetElement: HTMLElement;
function getSession(opts: InitOptions): Promise<cast.Session> {
function getSession(opts: InitOptions): Promise<Session> {
return new Promise(async (resolve, reject) => {
/**
* If a receiver is available, call requestSession. If a
@@ -76,10 +80,10 @@ function getSession(opts: InitOptions): Promise<cast.Session> {
// TODO: Handle this
}
function onRequestSessionSuccess(session: cast.Session) {
function onRequestSessionSuccess(session: Session) {
resolve(session);
}
function onRequestSessionError(err: cast.Error) {
function onRequestSessionError(err: Error_) {
reject(err.description);
}
@@ -97,7 +101,7 @@ function getSession(opts: InitOptions): Promise<cast.Session> {
});
}
function getMedia(opts: InitOptions): Promise<cast.media.Media> {
function getMedia(opts: InitOptions): Promise<Media> {
return new Promise(async (resolve, reject) => {
let mediaUrl = new URL(opts.mediaUrl);
const mediaTitle = mediaUrl.pathname.slice(1);

View File

@@ -6,6 +6,8 @@ import cast, { ensureInit } from "../export";
import { ReceiverSelectorMediaType } from "../../background/receiverSelector";
import { ReceiverDevice } from "../../types";
import type Session from "../sdk/Session";
// Variables passed from background
const {
selectedMedia,
@@ -17,7 +19,7 @@ const {
const FX_CAST_RECEIVER_APP_NAMESPACE = "urn:x-cast:fx_cast";
let session: cast.Session;
let session: Session;
let wasSessionRequested = false;
let peerConnection: RTCPeerConnection;
@@ -26,7 +28,7 @@ let peerConnection: RTCPeerConnection;
* Sends a message to the fx_cast app running on the
* receiver device.
*/
function sendAppMessage(subject: string, data: any) {
function sendAppMessage(subject: string, data: unknown) {
if (!session) {
return;
}
@@ -41,7 +43,7 @@ window.addEventListener("beforeunload", () => {
sendAppMessage("close", null);
});
async function onRequestSessionSuccess(newSession: cast.Session) {
async function onRequestSessionSuccess(newSession: Session) {
cast.logMessage("onRequestSessionSuccess");
session = newSession;

4
ext/src/global.d.ts vendored
View File

@@ -1,3 +1,5 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
declare const BRIDGE_VERSION: string;
declare const BRIDGE_NAME: string;
declare const MIRRORING_APP_ID: string;
@@ -68,7 +70,7 @@ type ExportFunctionFunc = (...args: any[]) => any;
declare function exportFunction(
func: ExportFunctionFunc,
targetScope: any,
targetScope: Window,
options?: ExportFunctionOptions
): ExportFunctionFunc;

View File

@@ -3,7 +3,7 @@
export class Logger {
constructor(private prefix: string) {}
public log(message: string, data?: any) {
public log(message: string, data?: unknown) {
const formattedMessage = `${this.prefix} (Log): ${message}`;
if (data) {
// eslint-disable-next-line no-console
@@ -13,7 +13,7 @@ export class Logger {
console.log(formattedMessage);
}
}
public info(message: string, data?: any) {
public info(message: string, data?: unknown) {
const formattedMessage = `${this.prefix} (Info): ${message}`;
if (data) {
console.info(formattedMessage, data);
@@ -21,7 +21,7 @@ export class Logger {
console.info(formattedMessage);
}
}
public warn(message: string, data?: any) {
public warn(message: string, data?: unknown) {
const formattedMessage = `${this.prefix} (Warning): ${message}`;
if (data) {
console.warn(formattedMessage, data);
@@ -29,7 +29,7 @@ export class Logger {
console.warn(formattedMessage);
}
}
public error(message: string, data?: any) {
public error(message: string, data?: unknown) {
const formattedMessage = `${this.prefix} (Error): ${message}`;
if (data) {
console.error(formattedMessage, data);

View File

@@ -32,7 +32,6 @@ function connectNative(application: string): Port {
// Port proxy API
const portObject: Port = {
error: null as any,
name: "",
onDisconnect: {
@@ -150,7 +149,7 @@ function connectNative(application: string): Port {
}
});
port.onMessage.addListener((message: any) => {
port.onMessage.addListener((message: Message) => {
if (!isNativeHostStatusKnown) {
isNativeHostStatusKnown = true;
messageQueue = [];
@@ -177,8 +176,6 @@ async function sendNativeMessage(application: string, message: Message) {
);
}
const port = await options.get("bridgeBackupPort");
return await new Promise((resolve, reject) => {
const ws = new WebSocket(
`ws://${bridgeBackupHost}:${bridgeBackupPort}`

View File

@@ -1,7 +1,5 @@
"use strict";
import logger from "./logger";
import { ReceiverSelectorMediaType } from "../background/receiverSelector";
export function getNextEllipsis(ellipsis: string): string {
@@ -18,7 +16,7 @@ export function getNextEllipsis(ellipsis: string): string {
*/
export function stringify(
templateStrings: TemplateStringsArray,
...substitutions: any[]
...substitutions: unknown[]
) {
let formattedString = "";

View File

@@ -52,7 +52,7 @@ type ExtMessageDefinitions = {
defaultMediaType?: ReceiverSelectorMediaType;
availableMediaTypes?: ReceiverSelectorMediaType;
};
"popup:close": {};
"popup:close": undefined;
"receiverSelector:selected": ReceiverSelection;
"receiverSelector:stop": ReceiverSelection;
@@ -62,9 +62,9 @@ type ExtMessageDefinitions = {
};
"cast:selectReceiver/selected": ReceiverSelectionCast;
"cast:selectReceiver/stopped": ReceiverSelectionStop;
"cast:selectReceiver/cancelled": {};
"cast:selectReceiver/cancelled": undefined;
"main:closeReceiverSelector": {};
"main:closeReceiverSelector": undefined;
"main:initializeCast": { appId: string };
"cast:initialized": BridgeInfo;
@@ -221,12 +221,12 @@ type AppMessageDefinitions = {
/**
* Sent to bridge to stop HTTP media server.
*/
"bridge:stopMediaServer": {};
"bridge:stopMediaServer": undefined;
/**
* Sent to media sender from bridge when the media server has
* stopped.
*/
"mediaCast:mediaServerStopped": {};
"mediaCast:mediaServerStopped": undefined;
/**
* Sent to media sender from bridge when the media server has
* encountered an error.
@@ -250,8 +250,8 @@ type Messages = {
* all-optional keys.
*/
type NarrowedMessage<L extends MessageBase<keyof MessageDefinitions>> =
L extends any
? {} extends L["data"]
L extends unknown
? undefined extends L["data"]
? Omit<L, "data"> & Partial<L>
: L
: never;
@@ -264,22 +264,28 @@ export type Message = NarrowedMessage<Messages[keyof Messages]>;
*/
export default new (class Messenger {
connect(connectInfo: { name: string }) {
return browser.runtime.connect(connectInfo) as unknown as Port;
return browser.runtime.connect(connectInfo) as Port;
}
connectTab(tabId: number, connectInfo: { name: string; frameId: number }) {
return browser.tabs.connect(tabId, connectInfo) as unknown as Port;
return browser.tabs.connect(tabId, connectInfo) as Port;
}
onConnect = {
addListener(cb: (port: Port) => void) {
browser.runtime.onConnect.addListener(cb as any);
browser.runtime.onConnect.addListener(
cb as (port: browser.runtime.Port) => void
);
},
removeListener(cb: (port: Port) => void) {
browser.runtime.onConnect.removeListener(cb as any);
browser.runtime.onConnect.removeListener(
cb as (port: browser.runtime.Port) => void
);
},
hasListener(cb: (port: Port) => void) {
return browser.runtime.onConnect.hasListener(cb as any);
return browser.runtime.onConnect.hasListener(
cb as (port: browser.runtime.Port) => void
);
}
};
})();

View File

@@ -4,14 +4,23 @@
import React, { Component } from "react";
import semver from "semver";
import options, { Options } from "../../lib/options";
import { Options } from "../../lib/options";
import { BridgeInfo } from "../../lib/bridge";
import { getNextEllipsis } from "../../lib/utils";
import logger from "../../lib/logger";
const _ = browser.i18n.getMessage;
interface Release {
url: string;
tag_name: string;
html_url: string;
assets: Array<{
content_type: string;
html_url: string;
}>;
}
interface BridgeStatsProps {
info: BridgeInfo;
@@ -20,45 +29,42 @@ interface BridgeStatsProps {
const BridgeStats = (props: BridgeStatsProps) => (
<table className="bridge__stats">
<tr>
<th>{ _("optionsBridgeStatsName") }</th>
<td>{ props.info.name }</td>
<th>{_("optionsBridgeStatsName")}</th>
<td>{props.info.name}</td>
</tr>
<tr>
<th>{ _("optionsBridgeStatsVersion") }</th>
<td>{ props.info.version }</td>
<th>{_("optionsBridgeStatsVersion")}</th>
<td>{props.info.version}</td>
</tr>
<tr>
<th>{ _("optionsBridgeStatsExpectedVersion") }</th>
<td>{ props.info.expectedVersion }</td>
<th>{_("optionsBridgeStatsExpectedVersion")}</th>
<td>{props.info.expectedVersion}</td>
</tr>
<tr>
<th>{ _("optionsBridgeStatsCompatibility") }</th>
<th>{_("optionsBridgeStatsCompatibility")}</th>
<td>
{ props.info.isVersionCompatible
{props.info.isVersionCompatible
? props.info.isVersionExact
? _("optionsBridgeCompatible")
: _("optionsBridgeLikelyCompatible")
: _("optionsBridgeIncompatible") }
: _("optionsBridgeIncompatible")}
</td>
</tr>
<tr>
<th>{ _("optionsBridgeStatsRecommendedAction") }</th>
<th>{_("optionsBridgeStatsRecommendedAction")}</th>
<td>
{
props.info.isVersionCompatible
? _("optionsBridgeNoAction")
: props.info.isVersionOlder
? _("optionsBridgeOlderAction")
: props.info.isVersionNewer
? _("optionsBridgeNewerAction")
: _("optionsBridgeNoAction")
}
{props.info.isVersionCompatible
? _("optionsBridgeNoAction")
: props.info.isVersionOlder
? _("optionsBridgeOlderAction")
: props.info.isVersionNewer
? _("optionsBridgeNewerAction")
: _("optionsBridgeNoAction")}
</td>
</tr>
</table>
);
interface BridgeProps {
info?: BridgeInfo;
loading: boolean;
@@ -76,17 +82,17 @@ interface BridgeState {
}
export default class Bridge extends Component<BridgeProps, BridgeState> {
private updateData: any;
private updateData?: Release;
private updateStatusTimeout?: number;
constructor(props: BridgeProps) {
super(props);
this.state = {
isCheckingUpdates: false
, isUpdateAvailable: false
, wasErrorCheckingUpdates: false
, checkUpdatesEllipsis: "..."
isCheckingUpdates: false,
isUpdateAvailable: false,
wasErrorCheckingUpdates: false,
checkUpdatesEllipsis: "..."
};
this.onCheckUpdates = this.onCheckUpdates.bind(this);
@@ -96,97 +102,123 @@ export default class Bridge extends Component<BridgeProps, BridgeState> {
}
public render() {
const [ backupMessageStart, backupMessageEnd ] =
_("optionsBridgeBackupEnabled", "\0").split("\0");
const [backupMessageStart, backupMessageEnd] = _(
"optionsBridgeBackupEnabled",
"\0"
).split("\0");
return (
<div className="bridge">
{ this.props.loading
? ( <div className="bridge__loading">
{ _("optionsBridgeLoading") }
<progress></progress>
</div> )
: this.renderStatus() }
{this.props.loading ? (
<div className="bridge__loading">
{_("optionsBridgeLoading")}
<progress></progress>
</div>
) : (
this.renderStatus()
)}
{ !this.props.loading && this.props.options &&
{!this.props.loading && this.props.options && (
<div className="bridge__options">
<label className="option option--inline">
<div className="option__control">
<input name="bridgeBackupEnabled"
type="checkbox"
checked={ this.props.options.bridgeBackupEnabled }
onChange={ this.props.onChange } />
<input
name="bridgeBackupEnabled"
type="checkbox"
checked={
this.props.options.bridgeBackupEnabled
}
onChange={this.props.onChange}
/>
</div>
<div className="option__label">
{ backupMessageStart }
<input className="bridge__backup-host"
name="bridgeBackupHost"
type="text"
required
value={ this.props.options.bridgeBackupHost }
onChange={ this.props.onChange } />
{backupMessageStart}
<input
className="bridge__backup-host"
name="bridgeBackupHost"
type="text"
required
value={this.props.options.bridgeBackupHost}
onChange={this.props.onChange}
/>
:
<input className="bridge__backup-port"
name="bridgeBackupPort"
type="number"
required
min="1025"
max="65535"
value={ this.props.options.bridgeBackupPort }
onChange={ this.props.onChange } />
{ backupMessageEnd }
<input
className="bridge__backup-port"
name="bridgeBackupPort"
type="number"
required
min="1025"
max="65535"
value={this.props.options.bridgeBackupPort}
onChange={this.props.onChange}
/>
{backupMessageEnd}
</div>
<div className="option__description">
{ _("optionsBridgeBackupEnabledDescription") }
{_("optionsBridgeBackupEnabledDescription")}
</div>
</label>
</div> }
</div>
)}
{ !this.props.loading &&
{!this.props.loading && (
<div className="bridge__update-info">
{ this.state.isUpdateAvailable
? ( <div className="bridge__update">
<p className="bridge__update-label">
{ _("optionsBridgeUpdateAvailable") }
</p>
<div className="bridge__update-options">
<button className="bridge__update-start"
type="button"
onClick={ this.onUpdate }>
{ _("optionsBridgeUpdate") }
</button>
</div>
</div> )
: ( <button className="bridge__update-check"
{this.state.isUpdateAvailable ? (
<div className="bridge__update">
<p className="bridge__update-label">
{_("optionsBridgeUpdateAvailable")}
</p>
<div className="bridge__update-options">
<button
className="bridge__update-start"
type="button"
disabled={ this.state.isCheckingUpdates }
onClick={ this.onCheckUpdates }>
{ this.state.isCheckingUpdates
? _("optionsBridgeUpdateChecking"
, getNextEllipsis(this.state.checkUpdatesEllipsis))
: _("optionsBridgeUpdateCheck") }
</button> )}
onClick={this.onUpdate}
>
{_("optionsBridgeUpdate")}
</button>
</div>
</div>
) : (
<button
className="bridge__update-check"
type="button"
disabled={this.state.isCheckingUpdates}
onClick={this.onCheckUpdates}
>
{this.state.isCheckingUpdates
? _(
"optionsBridgeUpdateChecking",
getNextEllipsis(
this.state.checkUpdatesEllipsis
)
)
: _("optionsBridgeUpdateCheck")}
</button>
)}
<div className="bridge--update-status">
{ this.state.updateStatus && !this.state.isUpdateAvailable
&& this.state.updateStatus }
{this.state.updateStatus &&
!this.state.isUpdateAvailable &&
this.state.updateStatus}
</div>
</div> }
</div>
)}
</div>
);
}
private renderStatus() {
const infoClasses = `bridge__info ${!this.props.info
? this.props.loadingTimedOut
? "bridge__info--timed-out"
: "bridge__info--not-found"
: "bridge__info--found"}`;
const infoClasses = `bridge__info ${
!this.props.info
? this.props.loadingTimedOut
? "bridge__info--timed-out"
: "bridge__info--not-found"
: "bridge__info--found"
}`;
let statusIcon: string;
let statusTitle: string;
let statusText: (string | null) = null;
let statusText: string | null = null;
if (this.props.loadingTimedOut) {
statusIcon = "assets/icons8-warn-120.png";
@@ -208,22 +240,21 @@ export default class Bridge extends Component<BridgeProps, BridgeState> {
return (
<div className={infoClasses}>
<div className="bridge__status">
<img className="bridge__status-icon"
width="60" height="60"
src={ statusIcon } />
<img
className="bridge__status-icon"
width="60"
height="60"
src={statusIcon}
/>
<h2 className="bridge__status-title">
{ statusTitle }
</h2>
<h2 className="bridge__status-title">{statusTitle}</h2>
{ statusText &&
<p className="bridge__status-text">
{ statusText }
</p> }
{statusText && (
<p className="bridge__status-text">{statusText}</p>
)}
</div>
{ this.props.info &&
<BridgeStats info={ this.props.info }/> }
{this.props.info && <BridgeStats info={this.props.info} />}
</div>
);
}
@@ -236,7 +267,8 @@ export default class Bridge extends Component<BridgeProps, BridgeState> {
const timeout = window.setInterval(() => {
this.setState(state => ({
checkUpdatesEllipsis: getNextEllipsis(
state.checkUpdatesEllipsis)
state.checkUpdatesEllipsis
)
}));
}, 500);
@@ -249,52 +281,58 @@ export default class Bridge extends Component<BridgeProps, BridgeState> {
.catch(this.onCheckUpdatesError);
}
private async onCheckUpdatesResponse(res: any) {
private async onCheckUpdatesResponse(res: Release[]) {
if (!Array.isArray(res)) {
throw logger.error("Check update response is not array.", res);
}
let latestBridgeRelease;
for (const release of res) {
if (release.assets.find((asset: any) =>
asset.content_type !== "application/x-xpinstall")) {
if (
release.assets.find(
asset => asset.content_type !== "application/x-xpinstall"
)
) {
latestBridgeRelease = release;
break;
}
}
if (!latestBridgeRelease) {
this.setState({
isCheckingUpdates: false
, wasErrorCheckingUpdates: true
, updateStatus: _("optionsBridgeUpdateStatusError")
});
return;
throw logger.error(
"Check update response does not contain release info."
);
}
const isUpdateAvailable = !this.props.info || semver.lt(
this.props.info.version, latestBridgeRelease.tag_name);
/**
* Update available if no bridge found or bridge version lower
* than fetched release version.
*/
const isUpdateAvailable =
!this.props.info ||
semver.lt(this.props.info.version, latestBridgeRelease.tag_name);
if (isUpdateAvailable) {
this.updateData = latestBridgeRelease;
}
this.setState({
isCheckingUpdates: false
, isUpdateAvailable
});
if (!isUpdateAvailable) {
} else {
this.setState({
updateStatus: _("optionsBridgeUpdateStatusNoUpdates")
});
}
this.setState({
isCheckingUpdates: false,
isUpdateAvailable
});
this.showUpdateStatus();
}
private onCheckUpdatesError() {
this.setState({
isCheckingUpdates: false
, wasErrorCheckingUpdates: true
, updateStatus: _("optionsBridgeUpdateStatusError")
isCheckingUpdates: false,
wasErrorCheckingUpdates: true,
updateStatus: _("optionsBridgeUpdateStatusError")
});
this.showUpdateStatus();
@@ -313,7 +351,7 @@ export default class Bridge extends Component<BridgeProps, BridgeState> {
private async onUpdate() {
// Open downloads page
if (this.updateData.html_url) {
if (this.updateData?.html_url) {
browser.tabs.create({
url: this.updateData.html_url
});

View File

@@ -565,8 +565,6 @@ class ReceiverEntry extends Component<ReceiverEntryProps, ReceiverEntryState> {
return;
}
const application = status.applications?.[0];
if (this.state.showAlternateAction) {
this.props.onStop(this.props.receiverDevice);
} else {