diff --git a/interface/config-overrides.js b/interface/config-overrides.js index 41c5c6e6e..b7e194599 100644 --- a/interface/config-overrides.js +++ b/interface/config-overrides.js @@ -1,37 +1,51 @@ -const ManifestPlugin = require('webpack-manifest-plugin'); -const WorkboxWebpackPlugin = require('workbox-webpack-plugin'); -const MiniCssExtractPlugin = require('mini-css-extract-plugin'); -const CompressionPlugin = require('compression-webpack-plugin'); -const ProgmemGenerator = require('./progmem-generator.js'); +const ManifestPlugin = require('webpack-manifest-plugin') +const WorkboxWebpackPlugin = require('workbox-webpack-plugin') +const MiniCssExtractPlugin = require('mini-css-extract-plugin') +const CompressionPlugin = require('compression-webpack-plugin') +const ProgmemGenerator = require('./progmem-generator.js') -const path = require('path'); -const fs = require('fs'); +const path = require('path') +const fs = require('fs') module.exports = function override(config, env) { - if (env === "production") { + if (env === 'production') { // rename the output file, we need it's path to be short for LittleFS - config.output.filename = 'js/[id].[chunkhash:4].js'; - config.output.chunkFilename = 'js/[id].[chunkhash:4].js'; + config.output.filename = 'js/[id].[chunkhash:4].js' + config.output.chunkFilename = 'js/[id].[chunkhash:4].js' // take out the manifest and service worker plugins - config.plugins = config.plugins.filter(plugin => !(plugin instanceof ManifestPlugin)); - config.plugins = config.plugins.filter(plugin => !(plugin instanceof WorkboxWebpackPlugin.GenerateSW)); + config.plugins = config.plugins.filter( + (plugin) => !(plugin instanceof ManifestPlugin), + ) + config.plugins = config.plugins.filter( + (plugin) => !(plugin instanceof WorkboxWebpackPlugin.GenerateSW), + ) // shorten css filenames - const miniCssExtractPlugin = config.plugins.find((plugin) => plugin instanceof MiniCssExtractPlugin); - miniCssExtractPlugin.options.filename = "css/[id].[contenthash:4].css"; - miniCssExtractPlugin.options.chunkFilename = "css/[id].[contenthash:4].c.css"; + const miniCssExtractPlugin = config.plugins.find( + (plugin) => plugin instanceof MiniCssExtractPlugin, + ) + miniCssExtractPlugin.options.filename = 'css/[id].[contenthash:4].css' + miniCssExtractPlugin.options.chunkFilename = + 'css/[id].[contenthash:4].c.css' // build progmem data files - config.plugins.push(new ProgmemGenerator({ outputPath: "../lib/framework/WWWData.h", bytesPerLine: 20 })); + config.plugins.push( + new ProgmemGenerator({ + outputPath: '../lib/framework/WWWData.h', + bytesPerLine: 20, + }), + ) // add compression plugin, compress javascript - config.plugins.push(new CompressionPlugin({ - filename: "[path].gz[query]", - algorithm: "gzip", - test: /\.(js)$/, - deleteOriginalAssets: true - })); + config.plugins.push( + new CompressionPlugin({ + filename: '[path].gz[query]', + algorithm: 'gzip', + test: /\.(js)$/, + deleteOriginalAssets: true, + }), + ) } - return config; + return config } diff --git a/interface/progmem-generator.js b/interface/progmem-generator.js index 674adaebe..f06ed338b 100644 --- a/interface/progmem-generator.js +++ b/interface/progmem-generator.js @@ -1,91 +1,108 @@ -const { resolve, relative, sep } = require('path'); -const { readdirSync, existsSync, unlinkSync, readFileSync, createWriteStream } = require('fs'); -var zlib = require('zlib'); -var mime = require('mime-types'); +const { resolve, relative, sep } = require('path') +const { + readdirSync, + existsSync, + unlinkSync, + readFileSync, + createWriteStream, +} = require('fs') +var zlib = require('zlib') +var mime = require('mime-types') -const ARDUINO_INCLUDES = "#include \n\n"; +const ARDUINO_INCLUDES = '#include \n\n' function getFilesSync(dir, files = []) { - readdirSync(dir, { withFileTypes: true }).forEach(entry => { - const entryPath = resolve(dir, entry.name); + readdirSync(dir, { withFileTypes: true }).forEach((entry) => { + const entryPath = resolve(dir, entry.name) if (entry.isDirectory()) { - getFilesSync(entryPath, files); + getFilesSync(entryPath, files) } else { - files.push(entryPath); + files.push(entryPath) } }) - return files; + return files } function coherseToBuffer(input) { - return Buffer.isBuffer(input) ? input : Buffer.from(input); + return Buffer.isBuffer(input) ? input : Buffer.from(input) } function cleanAndOpen(path) { if (existsSync(path)) { - unlinkSync(path); + unlinkSync(path) } - return createWriteStream(path, { flags: "w+" }); + return createWriteStream(path, { flags: 'w+' }) } class ProgmemGenerator { - constructor(options = {}) { - const { outputPath, bytesPerLine = 20, indent = " ", includes = ARDUINO_INCLUDES } = options; - this.options = { outputPath, bytesPerLine, indent, includes }; + const { + outputPath, + bytesPerLine = 20, + indent = ' ', + includes = ARDUINO_INCLUDES, + } = options + this.options = { outputPath, bytesPerLine, indent, includes } } apply(compiler) { compiler.hooks.emit.tapAsync( { name: 'ProgmemGenerator' }, (compilation, callback) => { - const { outputPath, bytesPerLine, indent, includes } = this.options; - const fileInfo = []; - const writeStream = cleanAndOpen(resolve(compilation.options.context, outputPath)); + const { outputPath, bytesPerLine, indent, includes } = this.options + const fileInfo = [] + const writeStream = cleanAndOpen( + resolve(compilation.options.context, outputPath), + ) try { const writeIncludes = () => { - writeStream.write(includes); + writeStream.write(includes) } const writeFile = (relativeFilePath, buffer) => { - const variable = "ESP_REACT_DATA_" + fileInfo.length; - const mimeType = mime.lookup(relativeFilePath); - var size = 0; - writeStream.write("const uint8_t " + variable + "[] PROGMEM = {"); - const zipBuffer = zlib.gzipSync(buffer); + const variable = 'ESP_REACT_DATA_' + fileInfo.length + const mimeType = mime.lookup(relativeFilePath) + var size = 0 + writeStream.write('const uint8_t ' + variable + '[] PROGMEM = {') + const zipBuffer = zlib.gzipSync(buffer) zipBuffer.forEach((b) => { if (!(size % bytesPerLine)) { - writeStream.write("\n"); - writeStream.write(indent); + writeStream.write('\n') + writeStream.write(indent) } - writeStream.write("0x" + ("00" + b.toString(16).toUpperCase()).substr(-2) + ","); - size++; - }); + writeStream.write( + '0x' + ('00' + b.toString(16).toUpperCase()).substr(-2) + ',', + ) + size++ + }) if (size % bytesPerLine) { - writeStream.write("\n"); + writeStream.write('\n') } - writeStream.write("};\n\n"); + writeStream.write('};\n\n') fileInfo.push({ uri: '/' + relativeFilePath.replace(sep, '/'), mimeType, variable, - size - }); - }; + size, + }) + } const writeFiles = () => { // process static files - const buildPath = compilation.options.output.path; + const buildPath = compilation.options.output.path for (const filePath of getFilesSync(buildPath)) { - const readStream = readFileSync(filePath); - const relativeFilePath = relative(buildPath, filePath); - writeFile(relativeFilePath, readStream); + const readStream = readFileSync(filePath) + const relativeFilePath = relative(buildPath, filePath) + writeFile(relativeFilePath, readStream) } // process assets - const { assets } = compilation; + const { assets } = compilation Object.keys(assets).forEach((relativeFilePath) => { - writeFile(relativeFilePath, coherseToBuffer(assets[relativeFilePath].source())); - }); + writeFile( + relativeFilePath, + coherseToBuffer(assets[relativeFilePath].source()), + ) + }) } const generateWWWClass = () => { @@ -93,30 +110,39 @@ class ProgmemGenerator { class WWWData { ${indent}public: -${indent.repeat(2)}static void registerRoutes(RouteRegistrationHandler handler) { -${fileInfo.map(file => `${indent.repeat(3)}handler("${file.uri}", "${file.mimeType}", ${file.variable}, ${file.size});`).join('\n')} +${indent.repeat( + 2, +)}static void registerRoutes(RouteRegistrationHandler handler) { +${fileInfo + .map( + (file) => + `${indent.repeat(3)}handler("${file.uri}", "${file.mimeType}", ${ + file.variable + }, ${file.size});`, + ) + .join('\n')} ${indent.repeat(2)}} }; -`; +` } const writeWWWClass = () => { - writeStream.write(generateWWWClass()); + writeStream.write(generateWWWClass()) } - writeIncludes(); - writeFiles(); - writeWWWClass(); + writeIncludes() + writeFiles() + writeWWWClass() writeStream.on('finish', () => { - callback(); - }); + callback() + }) } finally { - writeStream.end(); + writeStream.end() } - } - ); + }, + ) } } -module.exports = ProgmemGenerator; +module.exports = ProgmemGenerator diff --git a/interface/public/app/manifest.json b/interface/public/app/manifest.json index 8d7c5e4e5..519c1d141 100644 --- a/interface/public/app/manifest.json +++ b/interface/public/app/manifest.json @@ -9,4 +9,4 @@ "start_url": "/", "display": "fullscreen", "orientation": "any" -} \ No newline at end of file +} diff --git a/interface/public/css/roboto.css b/interface/public/css/roboto.css index ac21f0f55..3214d4c6e 100644 --- a/interface/public/css/roboto.css +++ b/interface/public/css/roboto.css @@ -3,20 +3,26 @@ font-family: 'Roboto'; font-style: normal; font-weight: 300; - src: local('Roboto Light'), local('Roboto-Light'), url(../fonts/li.woff2) format('woff2'); - unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2212, U+2215; + src: local('Roboto Light'), local('Roboto-Light'), + url(../fonts/li.woff2) format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, + U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2212, U+2215; } @font-face { font-family: 'Roboto'; font-style: normal; font-weight: 400; - src: local('Roboto'), local('Roboto-Regular'), url(../fonts/re.woff2) format('woff2'); - unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2212, U+2215; + src: local('Roboto'), local('Roboto-Regular'), + url(../fonts/re.woff2) format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, + U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2212, U+2215; } @font-face { font-family: 'Roboto'; font-style: normal; font-weight: 500; - src: local('Roboto Medium'), local('Roboto-Medium'), url(../fonts/me.woff2) format('woff2'); - unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2212, U+2215; -} \ No newline at end of file + src: local('Roboto Medium'), local('Roboto-Medium'), + url(../fonts/me.woff2) format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, + U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2212, U+2215; +} diff --git a/interface/src/ap/APModes.ts b/interface/src/ap/APModes.ts index 6a705db39..991463bde 100644 --- a/interface/src/ap/APModes.ts +++ b/interface/src/ap/APModes.ts @@ -1,5 +1,8 @@ -import { APSettings, APProvisionMode } from "./types"; +import { APSettings, APProvisionMode } from './types' export const isAPEnabled = ({ provision_mode }: APSettings) => { - return provision_mode === APProvisionMode.AP_MODE_ALWAYS || provision_mode === APProvisionMode.AP_MODE_DISCONNECTED; + return ( + provision_mode === APProvisionMode.AP_MODE_ALWAYS || + provision_mode === APProvisionMode.AP_MODE_DISCONNECTED + ) } diff --git a/interface/src/ap/APStatus.ts b/interface/src/ap/APStatus.ts index c35cadc5f..72064dfb8 100644 --- a/interface/src/ap/APStatus.ts +++ b/interface/src/ap/APStatus.ts @@ -1,28 +1,28 @@ -import { Theme } from "@material-ui/core"; -import { APStatus, APNetworkStatus } from "./types"; +import { Theme } from '@material-ui/core' +import { APStatus, APNetworkStatus } from './types' export const apStatusHighlight = ({ status }: APStatus, theme: Theme) => { switch (status) { case APNetworkStatus.ACTIVE: - return theme.palette.success.main; + return theme.palette.success.main case APNetworkStatus.INACTIVE: - return theme.palette.info.main; + return theme.palette.info.main case APNetworkStatus.LINGERING: - return theme.palette.warning.main; + return theme.palette.warning.main default: - return theme.palette.warning.main; + return theme.palette.warning.main } } export const apStatus = ({ status }: APStatus) => { switch (status) { case APNetworkStatus.ACTIVE: - return "Active"; + return 'Active' case APNetworkStatus.INACTIVE: - return "Inactive"; + return 'Inactive' case APNetworkStatus.LINGERING: - return "Lingering until idle"; + return 'Lingering until idle' default: - return "Unknown"; + return 'Unknown' } -}; +} diff --git a/interface/src/ap/types.ts b/interface/src/ap/types.ts index 437d0e63c..1e143add2 100644 --- a/interface/src/ap/types.ts +++ b/interface/src/ap/types.ts @@ -1,27 +1,27 @@ export enum APProvisionMode { AP_MODE_ALWAYS = 0, AP_MODE_DISCONNECTED = 1, - AP_NEVER = 2 + AP_NEVER = 2, } export enum APNetworkStatus { ACTIVE = 0, INACTIVE = 1, - LINGERING = 2 + LINGERING = 2, } export interface APStatus { - status: APNetworkStatus; - ip_address: string; - mac_address: string; - station_num: number; + status: APNetworkStatus + ip_address: string + mac_address: string + station_num: number } export interface APSettings { - provision_mode: APProvisionMode; - ssid: string; - password: string; - local_ip: string; - gateway_ip: string; - subnet_mask: string; + provision_mode: APProvisionMode + ssid: string + password: string + local_ip: string + gateway_ip: string + subnet_mask: string } diff --git a/interface/src/api/Endpoints.ts b/interface/src/api/Endpoints.ts index a30f42e16..d19381d04 100644 --- a/interface/src/api/Endpoints.ts +++ b/interface/src/api/Endpoints.ts @@ -1,23 +1,24 @@ -import { ENDPOINT_ROOT } from './Env'; +import { ENDPOINT_ROOT } from './Env' -export const FEATURES_ENDPOINT = ENDPOINT_ROOT + "features"; -export const NTP_STATUS_ENDPOINT = ENDPOINT_ROOT + "ntpStatus"; -export const NTP_SETTINGS_ENDPOINT = ENDPOINT_ROOT + "ntpSettings"; -export const TIME_ENDPOINT = ENDPOINT_ROOT + "time"; -export const AP_SETTINGS_ENDPOINT = ENDPOINT_ROOT + "apSettings"; -export const AP_STATUS_ENDPOINT = ENDPOINT_ROOT + "apStatus"; -export const SCAN_NETWORKS_ENDPOINT = ENDPOINT_ROOT + "scanNetworks"; -export const LIST_NETWORKS_ENDPOINT = ENDPOINT_ROOT + "listNetworks"; -export const NETWORK_SETTINGS_ENDPOINT = ENDPOINT_ROOT + "networkSettings"; -export const NETWORK_STATUS_ENDPOINT = ENDPOINT_ROOT + "networkStatus"; -export const OTA_SETTINGS_ENDPOINT = ENDPOINT_ROOT + "otaSettings"; -export const UPLOAD_FIRMWARE_ENDPOINT = ENDPOINT_ROOT + "uploadFirmware"; -export const MQTT_SETTINGS_ENDPOINT = ENDPOINT_ROOT + "mqttSettings"; -export const MQTT_STATUS_ENDPOINT = ENDPOINT_ROOT + "mqttStatus"; -export const SYSTEM_STATUS_ENDPOINT = ENDPOINT_ROOT + "systemStatus"; -export const SIGN_IN_ENDPOINT = ENDPOINT_ROOT + "signIn"; -export const VERIFY_AUTHORIZATION_ENDPOINT = ENDPOINT_ROOT + "verifyAuthorization"; -export const SECURITY_SETTINGS_ENDPOINT = ENDPOINT_ROOT + "securitySettings"; -export const GENERATE_TOKEN_ENDPOINT = ENDPOINT_ROOT + "generateToken"; -export const RESTART_ENDPOINT = ENDPOINT_ROOT + "restart"; -export const FACTORY_RESET_ENDPOINT = ENDPOINT_ROOT + "factoryReset"; +export const FEATURES_ENDPOINT = ENDPOINT_ROOT + 'features' +export const NTP_STATUS_ENDPOINT = ENDPOINT_ROOT + 'ntpStatus' +export const NTP_SETTINGS_ENDPOINT = ENDPOINT_ROOT + 'ntpSettings' +export const TIME_ENDPOINT = ENDPOINT_ROOT + 'time' +export const AP_SETTINGS_ENDPOINT = ENDPOINT_ROOT + 'apSettings' +export const AP_STATUS_ENDPOINT = ENDPOINT_ROOT + 'apStatus' +export const SCAN_NETWORKS_ENDPOINT = ENDPOINT_ROOT + 'scanNetworks' +export const LIST_NETWORKS_ENDPOINT = ENDPOINT_ROOT + 'listNetworks' +export const NETWORK_SETTINGS_ENDPOINT = ENDPOINT_ROOT + 'networkSettings' +export const NETWORK_STATUS_ENDPOINT = ENDPOINT_ROOT + 'networkStatus' +export const OTA_SETTINGS_ENDPOINT = ENDPOINT_ROOT + 'otaSettings' +export const UPLOAD_FIRMWARE_ENDPOINT = ENDPOINT_ROOT + 'uploadFirmware' +export const MQTT_SETTINGS_ENDPOINT = ENDPOINT_ROOT + 'mqttSettings' +export const MQTT_STATUS_ENDPOINT = ENDPOINT_ROOT + 'mqttStatus' +export const SYSTEM_STATUS_ENDPOINT = ENDPOINT_ROOT + 'systemStatus' +export const SIGN_IN_ENDPOINT = ENDPOINT_ROOT + 'signIn' +export const VERIFY_AUTHORIZATION_ENDPOINT = + ENDPOINT_ROOT + 'verifyAuthorization' +export const SECURITY_SETTINGS_ENDPOINT = ENDPOINT_ROOT + 'securitySettings' +export const GENERATE_TOKEN_ENDPOINT = ENDPOINT_ROOT + 'generateToken' +export const RESTART_ENDPOINT = ENDPOINT_ROOT + 'restart' +export const FACTORY_RESET_ENDPOINT = ENDPOINT_ROOT + 'factoryReset' diff --git a/interface/src/api/Env.ts b/interface/src/api/Env.ts index 9992e6811..edeeccae3 100644 --- a/interface/src/api/Env.ts +++ b/interface/src/api/Env.ts @@ -1,24 +1,24 @@ -export const PROJECT_NAME = process.env.REACT_APP_PROJECT_NAME!; -export const PROJECT_PATH = process.env.REACT_APP_PROJECT_PATH!; +export const PROJECT_NAME = process.env.REACT_APP_PROJECT_NAME! +export const PROJECT_PATH = process.env.REACT_APP_PROJECT_PATH! -export const ENDPOINT_ROOT = calculateEndpointRoot("/rest/"); -export const WEB_SOCKET_ROOT = calculateWebSocketRoot("/ws/"); +export const ENDPOINT_ROOT = calculateEndpointRoot('/rest/') +export const WEB_SOCKET_ROOT = calculateWebSocketRoot('/ws/') function calculateEndpointRoot(endpointPath: string) { - const httpRoot = process.env.REACT_APP_HTTP_ROOT; - if (httpRoot) { - return httpRoot + endpointPath; - } - const location = window.location; - return location.protocol + "//" + location.host + endpointPath; + const httpRoot = process.env.REACT_APP_HTTP_ROOT + if (httpRoot) { + return httpRoot + endpointPath + } + const location = window.location + return location.protocol + '//' + location.host + endpointPath } function calculateWebSocketRoot(webSocketPath: string) { - const webSocketRoot = process.env.REACT_APP_WEB_SOCKET_ROOT; - if (webSocketRoot) { - return webSocketRoot + webSocketPath; - } - const location = window.location; - const webProtocol = location.protocol === "https:" ? "wss:" : "ws:"; - return webProtocol + "//" + location.host + webSocketPath; + const webSocketRoot = process.env.REACT_APP_WEB_SOCKET_ROOT + if (webSocketRoot) { + return webSocketRoot + webSocketPath + } + const location = window.location + const webProtocol = location.protocol === 'https:' ? 'wss:' : 'ws:' + return webProtocol + '//' + location.host + webSocketPath } diff --git a/interface/src/authentication/Authentication.ts b/interface/src/authentication/Authentication.ts index cba77e059..610791e56 100644 --- a/interface/src/authentication/Authentication.ts +++ b/interface/src/authentication/Authentication.ts @@ -1,114 +1,129 @@ -import * as H from 'history'; +import * as H from 'history' -import history from '../history'; -import { Features } from '../features/types'; -import { getDefaultRoute } from '../AppRouting'; +import history from '../history' +import { Features } from '../features/types' +import { getDefaultRoute } from '../AppRouting' -export const ACCESS_TOKEN = 'access_token'; -export const SIGN_IN_PATHNAME = 'signInPathname'; -export const SIGN_IN_SEARCH = 'signInSearch'; +export const ACCESS_TOKEN = 'access_token' +export const SIGN_IN_PATHNAME = 'signInPathname' +export const SIGN_IN_SEARCH = 'signInSearch' /** * Fallback to sessionStorage if localStorage is absent. WebView may not have local storage enabled. */ export function getStorage() { - return localStorage || sessionStorage; + return localStorage || sessionStorage } export function storeLoginRedirect(location?: H.Location) { if (location) { - getStorage().setItem(SIGN_IN_PATHNAME, location.pathname); - getStorage().setItem(SIGN_IN_SEARCH, location.search); + getStorage().setItem(SIGN_IN_PATHNAME, location.pathname) + getStorage().setItem(SIGN_IN_SEARCH, location.search) } } export function clearLoginRedirect() { - getStorage().removeItem(SIGN_IN_PATHNAME); - getStorage().removeItem(SIGN_IN_SEARCH); + getStorage().removeItem(SIGN_IN_PATHNAME) + getStorage().removeItem(SIGN_IN_SEARCH) } -export function fetchLoginRedirect(features: Features): H.LocationDescriptorObject { - const signInPathname = getStorage().getItem(SIGN_IN_PATHNAME); - const signInSearch = getStorage().getItem(SIGN_IN_SEARCH); - clearLoginRedirect(); +export function fetchLoginRedirect( + features: Features, +): H.LocationDescriptorObject { + const signInPathname = getStorage().getItem(SIGN_IN_PATHNAME) + const signInSearch = getStorage().getItem(SIGN_IN_SEARCH) + clearLoginRedirect() return { pathname: signInPathname || getDefaultRoute(features), - search: (signInPathname && signInSearch) || undefined - }; + search: (signInPathname && signInSearch) || undefined, + } } /** * Wraps the normal fetch routine with one with provides the access token if present. */ -export function authorizedFetch(url: RequestInfo, params?: RequestInit): Promise { - const accessToken = getStorage().getItem(ACCESS_TOKEN); +export function authorizedFetch( + url: RequestInfo, + params?: RequestInit, +): Promise { + const accessToken = getStorage().getItem(ACCESS_TOKEN) if (accessToken) { - params = params || {}; - params.credentials = 'include'; + params = params || {} + params.credentials = 'include' params.headers = { ...params.headers, - "Authorization": 'Bearer ' + accessToken - }; + Authorization: 'Bearer ' + accessToken, + } } - return fetch(url, params); + return fetch(url, params) } /** - * fetch() does not yet support upload progress, this wrapper allows us to configure the xhr request - * for a single file upload and takes care of adding the Authorization header and redirecting on + * fetch() does not yet support upload progress, this wrapper allows us to configure the xhr request + * for a single file upload and takes care of adding the Authorization header and redirecting on * authorization errors as we do for normal fetch operations. */ -export function redirectingAuthorizedUpload(xhr: XMLHttpRequest, url: string, file: File, onProgress: (event: ProgressEvent) => void): Promise { +export function redirectingAuthorizedUpload( + xhr: XMLHttpRequest, + url: string, + file: File, + onProgress: (event: ProgressEvent) => void, +): Promise { return new Promise((resolve, reject) => { - xhr.open("POST", url, true); - const accessToken = getStorage().getItem(ACCESS_TOKEN); + xhr.open('POST', url, true) + const accessToken = getStorage().getItem(ACCESS_TOKEN) if (accessToken) { - xhr.withCredentials = true; - xhr.setRequestHeader("Authorization", 'Bearer ' + accessToken); + xhr.withCredentials = true + xhr.setRequestHeader('Authorization', 'Bearer ' + accessToken) } - xhr.upload.onprogress = onProgress; + xhr.upload.onprogress = onProgress xhr.onload = function () { if (xhr.status === 401 || xhr.status === 403) { - history.push("/unauthorized"); + history.push('/unauthorized') } else { - resolve(); + resolve() } - }; + } xhr.onerror = function (event: ProgressEvent) { - reject(new DOMException('Error', 'UploadError')); - }; + reject(new DOMException('Error', 'UploadError')) + } xhr.onabort = function () { - reject(new DOMException('Aborted', 'AbortError')); - }; - const formData = new FormData(); - formData.append('file', file); - xhr.send(formData); - }); + reject(new DOMException('Aborted', 'AbortError')) + } + const formData = new FormData() + formData.append('file', file) + xhr.send(formData) + }) } /** * Wraps the normal fetch routene which redirects on 401 response. */ -export function redirectingAuthorizedFetch(url: RequestInfo, params?: RequestInit): Promise { +export function redirectingAuthorizedFetch( + url: RequestInfo, + params?: RequestInit, +): Promise { return new Promise((resolve, reject) => { - authorizedFetch(url, params).then(response => { - if (response.status === 401 || response.status === 403) { - history.push("/unauthorized"); - } else { - resolve(response); - } - }).catch(error => { - reject(error); - }); - }); + authorizedFetch(url, params) + .then((response) => { + if (response.status === 401 || response.status === 403) { + history.push('/unauthorized') + } else { + resolve(response) + } + }) + .catch((error) => { + reject(error) + }) + }) } export function addAccessTokenParameter(url: string) { - const accessToken = getStorage().getItem(ACCESS_TOKEN); + const accessToken = getStorage().getItem(ACCESS_TOKEN) if (!accessToken) { - return url; + return url } - const parsedUrl = new URL(url); - parsedUrl.searchParams.set(ACCESS_TOKEN, accessToken); - return parsedUrl.toString(); + const parsedUrl = new URL(url) + parsedUrl.searchParams.set(ACCESS_TOKEN, accessToken) + return parsedUrl.toString() } diff --git a/interface/src/authentication/index.ts b/interface/src/authentication/index.ts index fa528ff5b..aff17b6c4 100644 --- a/interface/src/authentication/index.ts +++ b/interface/src/authentication/index.ts @@ -1,6 +1,6 @@ -export { default as AuthenticatedRoute } from './AuthenticatedRoute'; -export { default as AuthenticationWrapper } from './AuthenticationWrapper'; -export { default as UnauthenticatedRoute } from './UnauthenticatedRoute'; +export { default as AuthenticatedRoute } from './AuthenticatedRoute' +export { default as AuthenticationWrapper } from './AuthenticationWrapper' +export { default as UnauthenticatedRoute } from './UnauthenticatedRoute' -export * from './Authentication'; -export * from './AuthenticationContext'; \ No newline at end of file +export * from './Authentication' +export * from './AuthenticationContext' diff --git a/interface/src/components/index.ts b/interface/src/components/index.ts index 4a6cc6a7b..a4284c347 100644 --- a/interface/src/components/index.ts +++ b/interface/src/components/index.ts @@ -1,17 +1,17 @@ -export { default as BlockFormControlLabel } from './BlockFormControlLabel'; -export { default as FormActions } from './FormActions'; -export { default as FormButton } from './FormButton'; -export { default as HighlightAvatar } from './HighlightAvatar'; -export { default as MenuAppBar } from './MenuAppBar'; -export { default as PasswordValidator } from './PasswordValidator'; -export { default as RestFormLoader } from './RestFormLoader'; -export { default as SectionContent } from './SectionContent'; -export { default as WebSocketFormLoader } from './WebSocketFormLoader'; -export { default as ErrorButton } from './ErrorButton'; -export { default as SingleUpload } from './SingleUpload'; +export { default as BlockFormControlLabel } from './BlockFormControlLabel' +export { default as FormActions } from './FormActions' +export { default as FormButton } from './FormButton' +export { default as HighlightAvatar } from './HighlightAvatar' +export { default as MenuAppBar } from './MenuAppBar' +export { default as PasswordValidator } from './PasswordValidator' +export { default as RestFormLoader } from './RestFormLoader' +export { default as SectionContent } from './SectionContent' +export { default as WebSocketFormLoader } from './WebSocketFormLoader' +export { default as ErrorButton } from './ErrorButton' +export { default as SingleUpload } from './SingleUpload' -export * from './RestFormLoader'; -export * from './RestController'; +export * from './RestFormLoader' +export * from './RestController' -export * from './WebSocketFormLoader'; -export * from './WebSocketController'; +export * from './WebSocketFormLoader' +export * from './WebSocketController' diff --git a/interface/src/features/types.ts b/interface/src/features/types.ts index 1753d9abf..0ec4e3e5d 100644 --- a/interface/src/features/types.ts +++ b/interface/src/features/types.ts @@ -1,8 +1,8 @@ export interface Features { - project: boolean; - security: boolean; - mqtt: boolean; - ntp: boolean; - ota: boolean; - upload_firmware: boolean; + project: boolean + security: boolean + mqtt: boolean + ntp: boolean + ota: boolean + upload_firmware: boolean } diff --git a/interface/src/history.ts b/interface/src/history.ts index eb70d7bea..3caf18284 100644 --- a/interface/src/history.ts +++ b/interface/src/history.ts @@ -1,4 +1,4 @@ -import { createBrowserHistory } from 'history'; +import { createBrowserHistory } from 'history' export default createBrowserHistory({ /* pass a configuration object here if needed */ diff --git a/interface/src/mqtt/MqttStatus.ts b/interface/src/mqtt/MqttStatus.ts index 4263aafb9..8b75743ce 100644 --- a/interface/src/mqtt/MqttStatus.ts +++ b/interface/src/mqtt/MqttStatus.ts @@ -1,56 +1,59 @@ -import { Theme } from "@material-ui/core"; -import { MqttStatus, MqttDisconnectReason } from "./types"; +import { Theme } from '@material-ui/core' +import { MqttStatus, MqttDisconnectReason } from './types' -export const mqttStatusHighlight = ({ enabled, connected }: MqttStatus, theme: Theme) => { +export const mqttStatusHighlight = ( + { enabled, connected }: MqttStatus, + theme: Theme, +) => { if (!enabled) { - return theme.palette.info.main; + return theme.palette.info.main } if (connected) { - return theme.palette.success.main; + return theme.palette.success.main } - return theme.palette.error.main; + return theme.palette.error.main } export const mqttStatus = ({ enabled, connected }: MqttStatus) => { if (!enabled) { - return "Not enabled"; + return 'Not enabled' } if (connected) { - return "Connected"; + return 'Connected' } - return "Disconnected"; + return 'Disconnected' } export const disconnectReason = ({ disconnect_reason }: MqttStatus) => { switch (disconnect_reason) { case MqttDisconnectReason.TCP_DISCONNECTED: - return "TCP disconnected"; + return 'TCP disconnected' case MqttDisconnectReason.MQTT_UNACCEPTABLE_PROTOCOL_VERSION: - return "Unacceptable protocol version"; + return 'Unacceptable protocol version' case MqttDisconnectReason.MQTT_IDENTIFIER_REJECTED: - return "Client ID rejected"; + return 'Client ID rejected' case MqttDisconnectReason.MQTT_SERVER_UNAVAILABLE: - return "Server unavailable"; + return 'Server unavailable' case MqttDisconnectReason.MQTT_MALFORMED_CREDENTIALS: - return "Malformed credentials"; + return 'Malformed credentials' case MqttDisconnectReason.MQTT_NOT_AUTHORIZED: - return "Not authorized"; + return 'Not authorized' case MqttDisconnectReason.ESP8266_NOT_ENOUGH_SPACE: - return "Device out of memory"; + return 'Device out of memory' case MqttDisconnectReason.TLS_BAD_FINGERPRINT: - return "Server fingerprint invalid"; + return 'Server fingerprint invalid' default: - return "Unknown" + return 'Unknown' } } -export const mqttPublishHighlight = ({ mqtt_fails }: MqttStatus, theme: Theme) => { +export const mqttPublishHighlight = ( + { mqtt_fails }: MqttStatus, + theme: Theme, +) => { + if (mqtt_fails === 0) return theme.palette.success.main - if (mqtt_fails === 0) - return theme.palette.success.main; + if (mqtt_fails < 10) return theme.palette.warning.main - if (mqtt_fails < 10) - return theme.palette.warning.main; - - return theme.palette.error.main; -} \ No newline at end of file + return theme.palette.error.main +} diff --git a/interface/src/mqtt/types.ts b/interface/src/mqtt/types.ts index b5cbdadeb..c5310c9f8 100644 --- a/interface/src/mqtt/types.ts +++ b/interface/src/mqtt/types.ts @@ -6,40 +6,40 @@ export enum MqttDisconnectReason { MQTT_MALFORMED_CREDENTIALS = 4, MQTT_NOT_AUTHORIZED = 5, ESP8266_NOT_ENOUGH_SPACE = 6, - TLS_BAD_FINGERPRINT = 7 + TLS_BAD_FINGERPRINT = 7, } export interface MqttStatus { - enabled: boolean; - connected: boolean; - client_id: string; - disconnect_reason: MqttDisconnectReason; - mqtt_fails: number; + enabled: boolean + connected: boolean + client_id: string + disconnect_reason: MqttDisconnectReason + mqtt_fails: number } export interface MqttSettings { - enabled: boolean; - host: string; - port: number; - base: string; - username: string; - password: string; - client_id: string; - keep_alive: number; - clean_session: boolean; - max_topic_length: number; - publish_time_boiler: number; - publish_time_thermostat: number; - publish_time_solar: number; - publish_time_mixer: number; - publish_time_other: number; - publish_time_sensor: number; - dallas_format: number; - bool_format: number; - mqtt_qos: number; - mqtt_retain: boolean; - ha_enabled: boolean; - ha_climate_format: number; - nested_format: number; - subscribe_format: number; + enabled: boolean + host: string + port: number + base: string + username: string + password: string + client_id: string + keep_alive: number + clean_session: boolean + max_topic_length: number + publish_time_boiler: number + publish_time_thermostat: number + publish_time_solar: number + publish_time_mixer: number + publish_time_other: number + publish_time_sensor: number + dallas_format: number + bool_format: number + mqtt_qos: number + mqtt_retain: boolean + ha_enabled: boolean + ha_climate_format: number + nested_format: number + subscribe_format: number } diff --git a/interface/src/network/NetworkStatus.ts b/interface/src/network/NetworkStatus.ts index f555bc574..b3988605b 100644 --- a/interface/src/network/NetworkStatus.ts +++ b/interface/src/network/NetworkStatus.ts @@ -1,57 +1,57 @@ -import { Theme } from "@material-ui/core"; -import { NetworkStatus, NetworkConnectionStatus } from "./types"; +import { Theme } from '@material-ui/core' +import { NetworkStatus, NetworkConnectionStatus } from './types' export const isConnected = ({ status }: NetworkStatus) => { return ( status === NetworkConnectionStatus.WIFI_STATUS_CONNECTED || status === NetworkConnectionStatus.ETHERNET_STATUS_CONNECTED - ); -}; + ) +} export const isWiFi = ({ status }: NetworkStatus) => - status === NetworkConnectionStatus.WIFI_STATUS_CONNECTED; + status === NetworkConnectionStatus.WIFI_STATUS_CONNECTED export const isEthernet = ({ status }: NetworkStatus) => - status === NetworkConnectionStatus.ETHERNET_STATUS_CONNECTED; + status === NetworkConnectionStatus.ETHERNET_STATUS_CONNECTED export const networkStatusHighlight = ( { status }: NetworkStatus, - theme: Theme + theme: Theme, ) => { switch (status) { case NetworkConnectionStatus.WIFI_STATUS_IDLE: case NetworkConnectionStatus.WIFI_STATUS_DISCONNECTED: case NetworkConnectionStatus.WIFI_STATUS_NO_SHIELD: - return theme.palette.info.main; + return theme.palette.info.main case NetworkConnectionStatus.WIFI_STATUS_CONNECTED: case NetworkConnectionStatus.ETHERNET_STATUS_CONNECTED: - return theme.palette.success.main; + return theme.palette.success.main case NetworkConnectionStatus.WIFI_STATUS_CONNECT_FAILED: case NetworkConnectionStatus.WIFI_STATUS_CONNECTION_LOST: - return theme.palette.error.main; + return theme.palette.error.main default: - return theme.palette.warning.main; + return theme.palette.warning.main } -}; +} export const networkStatus = ({ status }: NetworkStatus) => { switch (status) { case NetworkConnectionStatus.WIFI_STATUS_NO_SHIELD: - return "Inactive"; + return 'Inactive' case NetworkConnectionStatus.WIFI_STATUS_IDLE: - return "Idle"; + return 'Idle' case NetworkConnectionStatus.WIFI_STATUS_NO_SSID_AVAIL: - return "No SSID Available"; + return 'No SSID Available' case NetworkConnectionStatus.WIFI_STATUS_CONNECTED: - return "Connected (WiFi)"; + return 'Connected (WiFi)' case NetworkConnectionStatus.ETHERNET_STATUS_CONNECTED: - return "Connected (Ethernet)"; + return 'Connected (Ethernet)' case NetworkConnectionStatus.WIFI_STATUS_CONNECT_FAILED: - return "Connection Failed"; + return 'Connection Failed' case NetworkConnectionStatus.WIFI_STATUS_CONNECTION_LOST: - return "Connection Lost"; + return 'Connection Lost' case NetworkConnectionStatus.WIFI_STATUS_DISCONNECTED: - return "Disconnected"; + return 'Disconnected' default: - return "Unknown"; + return 'Unknown' } -}; +} diff --git a/interface/src/network/WiFiSecurityModes.ts b/interface/src/network/WiFiSecurityModes.ts index 0aea4b317..577dc5103 100644 --- a/interface/src/network/WiFiSecurityModes.ts +++ b/interface/src/network/WiFiSecurityModes.ts @@ -1,22 +1,23 @@ -import { WiFiNetwork, WiFiEncryptionType } from "./types"; +import { WiFiNetwork, WiFiEncryptionType } from './types' -export const isNetworkOpen = ({ encryption_type }: WiFiNetwork) => encryption_type === WiFiEncryptionType.WIFI_AUTH_OPEN; +export const isNetworkOpen = ({ encryption_type }: WiFiNetwork) => + encryption_type === WiFiEncryptionType.WIFI_AUTH_OPEN export const networkSecurityMode = ({ encryption_type }: WiFiNetwork) => { switch (encryption_type) { case WiFiEncryptionType.WIFI_AUTH_WEP: - return "WEP"; + return 'WEP' case WiFiEncryptionType.WIFI_AUTH_WPA_PSK: - return "WPA"; + return 'WPA' case WiFiEncryptionType.WIFI_AUTH_WPA2_PSK: - return "WPA2"; + return 'WPA2' case WiFiEncryptionType.WIFI_AUTH_WPA_WPA2_PSK: - return "WPA/WPA2"; + return 'WPA/WPA2' case WiFiEncryptionType.WIFI_AUTH_WPA2_ENTERPRISE: - return "WPA2 Enterprise"; + return 'WPA2 Enterprise' case WiFiEncryptionType.WIFI_AUTH_OPEN: - return "None"; + return 'None' default: - return "Unknown"; + return 'Unknown' } } diff --git a/interface/src/network/types.ts b/interface/src/network/types.ts index f5e3cfb2e..bbd74528a 100644 --- a/interface/src/network/types.ts +++ b/interface/src/network/types.ts @@ -6,7 +6,7 @@ export enum NetworkConnectionStatus { WIFI_STATUS_CONNECTION_LOST = 5, WIFI_STATUS_DISCONNECTED = 6, ETHERNET_STATUS_CONNECTED = 10, - WIFI_STATUS_NO_SHIELD = 255 + WIFI_STATUS_NO_SHIELD = 255, } export enum WiFiEncryptionType { @@ -15,43 +15,43 @@ export enum WiFiEncryptionType { WIFI_AUTH_WPA_PSK = 2, WIFI_AUTH_WPA2_PSK = 3, WIFI_AUTH_WPA_WPA2_PSK = 4, - WIFI_AUTH_WPA2_ENTERPRISE = 5 + WIFI_AUTH_WPA2_ENTERPRISE = 5, } export interface NetworkStatus { - status: NetworkConnectionStatus; - local_ip: string; - mac_address: string; - rssi: number; - ssid: string; - bssid: string; - channel: number; - subnet_mask: string; - gateway_ip: string; - dns_ip_1: string; - dns_ip_2: string; + status: NetworkConnectionStatus + local_ip: string + mac_address: string + rssi: number + ssid: string + bssid: string + channel: number + subnet_mask: string + gateway_ip: string + dns_ip_1: string + dns_ip_2: string } export interface NetworkSettings { - ssid: string; - password: string; - hostname: string; - static_ip_config: boolean; - local_ip?: string; - gateway_ip?: string; - subnet_mask?: string; - dns_ip_1?: string; - dns_ip_2?: string; + ssid: string + password: string + hostname: string + static_ip_config: boolean + local_ip?: string + gateway_ip?: string + subnet_mask?: string + dns_ip_1?: string + dns_ip_2?: string } export interface WiFiNetworkList { - networks: WiFiNetwork[]; + networks: WiFiNetwork[] } export interface WiFiNetwork { - rssi: number; - ssid: string; - bssid: string; - channel: number; - encryption_type: WiFiEncryptionType; + rssi: number + ssid: string + bssid: string + channel: number + encryption_type: WiFiEncryptionType } diff --git a/interface/src/ntp/NTPStatus.ts b/interface/src/ntp/NTPStatus.ts index 744b56d34..d979d5470 100644 --- a/interface/src/ntp/NTPStatus.ts +++ b/interface/src/ntp/NTPStatus.ts @@ -1,26 +1,27 @@ -import { Theme } from "@material-ui/core"; -import { NTPStatus, NTPSyncStatus } from "./types"; +import { Theme } from '@material-ui/core' +import { NTPStatus, NTPSyncStatus } from './types' -export const isNtpActive = ({ status }: NTPStatus) => status === NTPSyncStatus.NTP_ACTIVE; +export const isNtpActive = ({ status }: NTPStatus) => + status === NTPSyncStatus.NTP_ACTIVE export const ntpStatusHighlight = ({ status }: NTPStatus, theme: Theme) => { switch (status) { case NTPSyncStatus.NTP_INACTIVE: - return theme.palette.info.main; + return theme.palette.info.main case NTPSyncStatus.NTP_ACTIVE: - return theme.palette.success.main; + return theme.palette.success.main default: - return theme.palette.error.main; + return theme.palette.error.main } } export const ntpStatus = ({ status }: NTPStatus) => { switch (status) { case NTPSyncStatus.NTP_INACTIVE: - return "Inactive"; + return 'Inactive' case NTPSyncStatus.NTP_ACTIVE: - return "Active"; + return 'Active' default: - return "Unknown"; + return 'Unknown' } } diff --git a/interface/src/ntp/TimeFormat.ts b/interface/src/ntp/TimeFormat.ts index 863771112..a8e986ea1 100644 --- a/interface/src/ntp/TimeFormat.ts +++ b/interface/src/ntp/TimeFormat.ts @@ -1,45 +1,43 @@ -import parseMilliseconds from 'parse-ms'; +import parseMilliseconds from 'parse-ms' -const LOCALE_FORMAT = new Intl.DateTimeFormat( - [...window.navigator.languages], - { - day: 'numeric', - month: 'short', - year: 'numeric', - hour: 'numeric', - minute: 'numeric', - second: 'numeric', - hour12: false - } -); +const LOCALE_FORMAT = new Intl.DateTimeFormat([...window.navigator.languages], { + day: 'numeric', + month: 'short', + year: 'numeric', + hour: 'numeric', + minute: 'numeric', + second: 'numeric', + hour12: false, +}) export const formatDateTime = (dateTime: string) => { - return LOCALE_FORMAT.format(new Date(dateTime.substr(0, 19))); + return LOCALE_FORMAT.format(new Date(dateTime.substr(0, 19))) } export const formatLocalDateTime = (date: Date) => { return new Date(date.getTime() - date.getTimezoneOffset() * 60000) .toISOString() .slice(0, -1) - .substr(0, 19); + .substr(0, 19) } export const formatDuration = (duration: number) => { - const { days, hours, minutes, seconds } = parseMilliseconds(duration * 1000); - var formatted = ''; + const { days, hours, minutes, seconds } = parseMilliseconds(duration * 1000) + var formatted = '' if (days) { - formatted += pluralize(days, 'day'); + formatted += pluralize(days, 'day') } if (formatted || hours) { - formatted += pluralize(hours, 'hour'); + formatted += pluralize(hours, 'hour') } if (formatted || minutes) { - formatted += pluralize(minutes, 'minute'); + formatted += pluralize(minutes, 'minute') } if (formatted || seconds) { - formatted += pluralize(seconds, 'second'); + formatted += pluralize(seconds, 'second') } - return formatted; + return formatted } -const pluralize = (count: number, noun: string, suffix: string = 's') => ` ${count} ${noun}${count !== 1 ? suffix : ''} `; +const pluralize = (count: number, noun: string, suffix: string = 's') => + ` ${count} ${noun}${count !== 1 ? suffix : ''} ` diff --git a/interface/src/ntp/types.ts b/interface/src/ntp/types.ts index 4a19da6e7..8311b8743 100644 --- a/interface/src/ntp/types.ts +++ b/interface/src/ntp/types.ts @@ -1,23 +1,23 @@ export enum NTPSyncStatus { NTP_INACTIVE = 0, - NTP_ACTIVE = 1 + NTP_ACTIVE = 1, } export interface NTPStatus { - status: NTPSyncStatus; - utc_time: string; - local_time: string; - server: string; - uptime: number; + status: NTPSyncStatus + utc_time: string + local_time: string + server: string + uptime: number } export interface NTPSettings { - enabled: boolean; - server: string; - tz_label: string; - tz_format: string; + enabled: boolean + server: string + tz_label: string + tz_format: string } export interface Time { - local_time: string; -} \ No newline at end of file + local_time: string +} diff --git a/interface/src/project/EMSESPStatus.ts b/interface/src/project/EMSESPStatus.ts index eb7bac976..71c256f85 100644 --- a/interface/src/project/EMSESPStatus.ts +++ b/interface/src/project/EMSESPStatus.ts @@ -1,40 +1,39 @@ -import { Theme } from '@material-ui/core'; -import { EMSESPStatus, busConnectionStatus } from './EMSESPtypes'; +import { Theme } from '@material-ui/core' +import { EMSESPStatus, busConnectionStatus } from './EMSESPtypes' -export const isConnected = ({ status }: EMSESPStatus) => status !== busConnectionStatus.BUS_STATUS_OFFLINE; +export const isConnected = ({ status }: EMSESPStatus) => + status !== busConnectionStatus.BUS_STATUS_OFFLINE export const busStatusHighlight = ({ status }: EMSESPStatus, theme: Theme) => { - switch (status) { case busConnectionStatus.BUS_STATUS_TX_ERRORS: - return theme.palette.warning.main; + return theme.palette.warning.main case busConnectionStatus.BUS_STATUS_CONNECTED: - return theme.palette.success.main; + return theme.palette.success.main case busConnectionStatus.BUS_STATUS_OFFLINE: - return theme.palette.error.main; + return theme.palette.error.main default: - return theme.palette.warning.main; + return theme.palette.warning.main } } export const busStatus = ({ status }: EMSESPStatus) => { switch (status) { case busConnectionStatus.BUS_STATUS_CONNECTED: - return "Connected"; + return 'Connected' case busConnectionStatus.BUS_STATUS_TX_ERRORS: - return "Tx Errors"; + return 'Tx Errors' case busConnectionStatus.BUS_STATUS_OFFLINE: - return "Disconnected"; + return 'Disconnected' default: - return "Unknown"; + return 'Unknown' } } export const qualityHighlight = (value: number, theme: Theme) => { if (value >= 95) { - return theme.palette.success.main; + return theme.palette.success.main } - return theme.palette.error.main; + return theme.palette.error.main } - diff --git a/interface/src/project/EMSESPtypes.ts b/interface/src/project/EMSESPtypes.ts index e808b88b0..4dd440a70 100644 --- a/interface/src/project/EMSESPtypes.ts +++ b/interface/src/project/EMSESPtypes.ts @@ -1,72 +1,72 @@ export interface EMSESPSettings { - tx_mode: number; - tx_delay: number; - ems_bus_id: number; - syslog_enabled: boolean; - syslog_level: number; - syslog_mark_interval: number; - syslog_host: string; - syslog_port: number; - master_thermostat: number; - shower_timer: boolean; - shower_alert: boolean; - rx_gpio: number; - tx_gpio: number; - dallas_gpio: number; - dallas_parasite: boolean; - led_gpio: number; - hide_led: boolean; - notoken_api: boolean; - analog_enabled: boolean; - pbutton_gpio: number; - trace_raw: boolean; - board_profile: string; + tx_mode: number + tx_delay: number + ems_bus_id: number + syslog_enabled: boolean + syslog_level: number + syslog_mark_interval: number + syslog_host: string + syslog_port: number + master_thermostat: number + shower_timer: boolean + shower_alert: boolean + rx_gpio: number + tx_gpio: number + dallas_gpio: number + dallas_parasite: boolean + led_gpio: number + hide_led: boolean + notoken_api: boolean + analog_enabled: boolean + pbutton_gpio: number + trace_raw: boolean + board_profile: string } export enum busConnectionStatus { BUS_STATUS_CONNECTED = 0, BUS_STATUS_TX_ERRORS = 1, - BUS_STATUS_OFFLINE = 2 + BUS_STATUS_OFFLINE = 2, } export interface EMSESPStatus { - status: busConnectionStatus; - rx_received: number; - tx_sent: number; - rx_quality: number; - tx_quality: number; + status: busConnectionStatus + rx_received: number + tx_sent: number + rx_quality: number + tx_quality: number } export interface Device { - id: number; - type: string; - brand: string; - name: string; - deviceid: number; - productid: number; - version: string; + id: number + type: string + brand: string + name: string + deviceid: number + productid: number + version: string } export interface Sensor { - no: number; - id: string; - temp: string; + no: number + id: string + temp: string } export interface EMSESPDevices { - devices: Device[]; - sensors: Sensor[]; + devices: Device[] + sensors: Sensor[] } export interface EMSESPDeviceData { - name: string; - data: string[]; + name: string + data: string[] } export interface DeviceValue { - id: number; - data: string, - uom: string, - name: string, + id: number + data: string + uom: string + name: string cmd: string } diff --git a/interface/src/security/types.ts b/interface/src/security/types.ts index 87fb64418..6f7562217 100644 --- a/interface/src/security/types.ts +++ b/interface/src/security/types.ts @@ -1,14 +1,14 @@ export interface User { - username: string; - password: string; - admin: boolean; + username: string + password: string + admin: boolean } export interface SecuritySettings { - users: User[]; - jwt_secret: string; + users: User[] + jwt_secret: string } export interface GeneratedToken { - token: string; + token: string } diff --git a/interface/src/serviceWorker.ts b/interface/src/serviceWorker.ts index 1c0691675..8a502cb66 100644 --- a/interface/src/serviceWorker.ts +++ b/interface/src/serviceWorker.ts @@ -12,64 +12,61 @@ const isLocalhost = Boolean( window.location.hostname === 'localhost' || - // [::1] is the IPv6 localhost address. - window.location.hostname === '[::1]' || - // 127.0.0.0/8 are considered localhost for IPv4. - window.location.hostname.match( - /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/ - ) -); + // [::1] is the IPv6 localhost address. + window.location.hostname === '[::1]' || + // 127.0.0.0/8 are considered localhost for IPv4. + window.location.hostname.match( + /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/, + ), +) type Config = { - onSuccess?: (registration: ServiceWorkerRegistration) => void; - onUpdate?: (registration: ServiceWorkerRegistration) => void; -}; + onSuccess?: (registration: ServiceWorkerRegistration) => void + onUpdate?: (registration: ServiceWorkerRegistration) => void +} export function register(config?: Config) { if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) { // The URL constructor is available in all browsers that support SW. - const publicUrl = new URL( - process.env.PUBLIC_URL, - window.location.href - ); + const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href) if (publicUrl.origin !== window.location.origin) { // Our service worker won't work if PUBLIC_URL is on a different origin // from what our page is served on. This might happen if a CDN is used to // serve assets; see https://github.com/facebook/create-react-app/issues/2374 - return; + return } window.addEventListener('load', () => { - const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`; + const swUrl = `${process.env.PUBLIC_URL}/service-worker.js` if (isLocalhost) { // This is running on localhost. Let's check if a service worker still exists or not. - checkValidServiceWorker(swUrl, config); + checkValidServiceWorker(swUrl, config) // Add some additional logging to localhost, pointing developers to the // service worker/PWA documentation. navigator.serviceWorker.ready.then(() => { console.log( 'This web app is being served cache-first by a service ' + - 'worker. To learn more, visit https://bit.ly/CRA-PWA' - ); - }); + 'worker. To learn more, visit https://bit.ly/CRA-PWA', + ) + }) } else { // Is not localhost. Just register service worker - registerValidSW(swUrl, config); + registerValidSW(swUrl, config) } - }); + }) } } function registerValidSW(swUrl: string, config?: Config) { navigator.serviceWorker .register(swUrl) - .then(registration => { + .then((registration) => { registration.onupdatefound = () => { - const installingWorker = registration.installing; + const installingWorker = registration.installing if (installingWorker == null) { - return; + return } installingWorker.onstatechange = () => { if (installingWorker.state === 'installed') { @@ -79,67 +76,67 @@ function registerValidSW(swUrl: string, config?: Config) { // content until all client tabs are closed. console.log( 'New content is available and will be used when all ' + - 'tabs for this page are closed. See https://bit.ly/CRA-PWA.' - ); + 'tabs for this page are closed. See https://bit.ly/CRA-PWA.', + ) // Execute callback if (config && config.onUpdate) { - config.onUpdate(registration); + config.onUpdate(registration) } } else { // At this point, everything has been precached. // It's the perfect time to display a // "Content is cached for offline use." message. - console.log('Content is cached for offline use.'); + console.log('Content is cached for offline use.') // Execute callback if (config && config.onSuccess) { - config.onSuccess(registration); + config.onSuccess(registration) } } } - }; - }; + } + } + }) + .catch((error) => { + console.error('Error during service worker registration:', error) }) - .catch(error => { - console.error('Error during service worker registration:', error); - }); } function checkValidServiceWorker(swUrl: string, config?: Config) { // Check if the service worker can be found. If it can't reload the page. fetch(swUrl, { - headers: { 'Service-Worker': 'script' } + headers: { 'Service-Worker': 'script' }, }) - .then(response => { + .then((response) => { // Ensure service worker exists, and that we really are getting a JS file. - const contentType = response.headers.get('content-type'); + const contentType = response.headers.get('content-type') if ( response.status === 404 || (contentType != null && contentType.indexOf('javascript') === -1) ) { // No service worker found. Probably a different app. Reload the page. - navigator.serviceWorker.ready.then(registration => { + navigator.serviceWorker.ready.then((registration) => { registration.unregister().then(() => { - window.location.reload(); - }); - }); + window.location.reload() + }) + }) } else { // Service worker found. Proceed as normal. - registerValidSW(swUrl, config); + registerValidSW(swUrl, config) } }) .catch(() => { console.log( - 'No internet connection found. App is running in offline mode.' - ); - }); + 'No internet connection found. App is running in offline mode.', + ) + }) } export function unregister() { if ('serviceWorker' in navigator) { - navigator.serviceWorker.ready.then(registration => { - registration.unregister(); - }); + navigator.serviceWorker.ready.then((registration) => { + registration.unregister() + }) } } diff --git a/interface/src/setupProxy.js b/interface/src/setupProxy.js index af9f42516..78ac89244 100644 --- a/interface/src/setupProxy.js +++ b/interface/src/setupProxy.js @@ -1,12 +1,12 @@ -const { createProxyMiddleware } = require('http-proxy-middleware'); +const { createProxyMiddleware } = require('http-proxy-middleware') module.exports = function (app) { - app.use( - '/rest/*', - createProxyMiddleware({ - target: 'http://localhost:3080', - secure: false, - changeOrigin: true - }) - ); -}; + app.use( + '/rest/*', + createProxyMiddleware({ + target: 'http://localhost:3080', + secure: false, + changeOrigin: true, + }), + ) +} diff --git a/interface/src/system/types.ts b/interface/src/system/types.ts index b45cfc9ed..b04e656a5 100644 --- a/interface/src/system/types.ts +++ b/interface/src/system/types.ts @@ -1,37 +1,37 @@ export enum EspPlatform { - ESP8266 = "esp8266", - ESP32 = "esp32" + ESP8266 = 'esp8266', + ESP32 = 'esp32', } interface ESPSystemStatus { - esp_platform: EspPlatform; - max_alloc_heap: number; - cpu_freq_mhz: number; - free_heap: number; - sdk_version: string; - flash_chip_size: number; - flash_chip_speed: number; - fs_used: number; - fs_total: number; - uptime: string; - free_mem: number; + esp_platform: EspPlatform + max_alloc_heap: number + cpu_freq_mhz: number + free_heap: number + sdk_version: string + flash_chip_size: number + flash_chip_speed: number + fs_used: number + fs_total: number + uptime: string + free_mem: number } export interface ESP32SystemStatus extends ESPSystemStatus { - esp_platform: EspPlatform.ESP32; - psram_size: number; - free_psram: number; + esp_platform: EspPlatform.ESP32 + psram_size: number + free_psram: number } export interface ESP8266SystemStatus extends ESPSystemStatus { - esp_platform: EspPlatform.ESP8266; - heap_fragmentation: number; + esp_platform: EspPlatform.ESP8266 + heap_fragmentation: number } -export type SystemStatus = ESP8266SystemStatus | ESP32SystemStatus; +export type SystemStatus = ESP8266SystemStatus | ESP32SystemStatus export interface OTASettings { - enabled: boolean; - port: number; - password: string; + enabled: boolean + port: number + password: string } diff --git a/interface/src/validators/index.ts b/interface/src/validators/index.ts index 2c1bdd78a..63ebbac7a 100644 --- a/interface/src/validators/index.ts +++ b/interface/src/validators/index.ts @@ -1,5 +1,5 @@ -export { default as isHostname } from './isHostname'; -export { default as isIP } from './isIP'; -export { default as optional } from './optional'; -export { default as or } from './or'; -export { default as isPath } from './isPath'; \ No newline at end of file +export { default as isHostname } from './isHostname' +export { default as isIP } from './isIP' +export { default as optional } from './optional' +export { default as or } from './or' +export { default as isPath } from './isPath' diff --git a/interface/src/validators/isHostname.ts b/interface/src/validators/isHostname.ts index a9cb3fa56..ffdc05e7a 100644 --- a/interface/src/validators/isHostname.ts +++ b/interface/src/validators/isHostname.ts @@ -2,5 +2,7 @@ const hostnameLengthRegex = /^.{0,48}$/ const hostnamePatternRegex = /^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9-]*[A-Za-z0-9])$/ export default function isHostname(hostname: string) { - return hostnameLengthRegex.test(hostname) && hostnamePatternRegex.test(hostname); + return ( + hostnameLengthRegex.test(hostname) && hostnamePatternRegex.test(hostname) + ) } diff --git a/interface/src/validators/isIP.ts b/interface/src/validators/isIP.ts index 439c57cf0..0b1e0e52d 100644 --- a/interface/src/validators/isIP.ts +++ b/interface/src/validators/isIP.ts @@ -1,5 +1,5 @@ const ipAddressRegexp = /^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/ export default function isIp(ipAddress: string) { - return ipAddressRegexp.test(ipAddress); -} \ No newline at end of file + return ipAddressRegexp.test(ipAddress) +} diff --git a/interface/src/validators/isPath.ts b/interface/src/validators/isPath.ts index a2c3eb44c..1a34dd84f 100644 --- a/interface/src/validators/isPath.ts +++ b/interface/src/validators/isPath.ts @@ -2,5 +2,5 @@ const pathLengthRegex = /^[^.]{0,108}$/ const pathPatternRegex = /^([a-zA-Z0-9_][a-zA-Z0-9/_-]*[a-zA-Z0-9_])$/ export default function isPath(path: string) { - return pathLengthRegex.test(path) && pathPatternRegex.test(path); -} \ No newline at end of file + return pathLengthRegex.test(path) && pathPatternRegex.test(path) +} diff --git a/interface/src/validators/optional.ts b/interface/src/validators/optional.ts index f081a09be..7cd35421f 100644 --- a/interface/src/validators/optional.ts +++ b/interface/src/validators/optional.ts @@ -1,3 +1,4 @@ -const OPTIONAL = (validator: (value: any) => boolean) => (value: any) => !value || validator(value); +const OPTIONAL = (validator: (value: any) => boolean) => (value: any) => + !value || validator(value) -export default OPTIONAL; +export default OPTIONAL diff --git a/interface/src/validators/or.ts b/interface/src/validators/or.ts index a57d2cd75..3f345fbe5 100644 --- a/interface/src/validators/or.ts +++ b/interface/src/validators/or.ts @@ -1,6 +1,8 @@ -const OR = (validator1: (value: any) => boolean, validator2: (value: any) => boolean) => { - return (value: any) => validator1(value) || validator2(value); -}; - -export default OR; +const OR = ( + validator1: (value: any) => boolean, + validator2: (value: any) => boolean, +) => { + return (value: any) => validator1(value) || validator2(value) +} +export default OR diff --git a/interface/tsconfig.json b/interface/tsconfig.json index a77978459..cc47c36d4 100644 --- a/interface/tsconfig.json +++ b/interface/tsconfig.json @@ -1,11 +1,7 @@ { "compilerOptions": { "target": "es5", - "lib": [ - "dom", - "dom.iterable", - "esnext" - ], + "lib": ["dom", "dom.iterable", "esnext"], "allowJs": true, "skipLibCheck": true, "esModuleInterop": true, @@ -20,7 +16,5 @@ "jsx": "react-jsx", "noFallthroughCasesInSwitch": true }, - "include": [ - "src" - ] -} \ No newline at end of file + "include": ["src"] +}