Utilize ?. operator and set TypeScript target

This commit is contained in:
Zaid Abdulla committed 2021-09-16 13:27:37 -07:00
1 parent ca83704958
commit c3c7ab72b2
19 files changed
+55 -77

No files matched your search

+2 -2
View File
@@ -94,7 +94,7 @@ export async function connectionRequest(
else if (name === "password") return password; else if (name === "password") return password;
const p = device[name]; const p = device[name];
if (p && p.value) return p.value[0]; if (p?.value) return p.value[0];
} else if (exp[0] === "FUNC") { } else if (exp[0] === "FUNC") {
if (exp[1] === "REMOTE_ADDRESS") return remoteAddress; if (exp[1] === "REMOTE_ADDRESS") return remoteAddress;
else if (exp[1] === "USERNAME") return username; else if (exp[1] === "USERNAME") return username;
@@ -317,7 +317,7 @@ function sanitizeTask(task): void {
export async function insertTasks(tasks: any[]): Promise<Task[]> { export async function insertTasks(tasks: any[]): Promise<Task[]> {
if (tasks && !Array.isArray(tasks)) tasks = [tasks]; if (tasks && !Array.isArray(tasks)) tasks = [tasks];
else if (!tasks || tasks.length === 0) return tasks || []; else if (!tasks?.length) return tasks || [];
for (const task of tasks) { for (const task of tasks) {
sanitizeTask(task); sanitizeTask(task);
+1 -1
View File
@@ -59,7 +59,7 @@ export async function set(
export async function pop(key: string): Promise<any> { export async function pop(key: string): Promise<any> {
const res = await cacheCollection.findOneAndDelete({ _id: key }); const res = await cacheCollection.findOneAndDelete({ _id: key });
if (res && res["value"]) return res["value"]["value"]; if (res?.["value"]) return res["value"]["value"];
return null; return null;
} }
+6 -6
View File
@@ -93,7 +93,7 @@ async function authenticate(
} }
} }
if (authentication && authentication.method === "Digest") { if (authentication?.method === "Digest") {
const sessionNonce = sessionsNonces.get(sessionContext.httpRequest.socket); const sessionNonce = sessionsNonces.get(sessionContext.httpRequest.socket);
if ( if (
@@ -434,7 +434,7 @@ async function applyPresets(sessionContext: SessionContext): Promise<void> {
const deviceEvents = {}; const deviceEvents = {};
for (const p of deviceData.paths.find(Path.parse("Events.*"), false, true)) { for (const p of deviceData.paths.find(Path.parse("Events.*"), false, true)) {
const attrs = deviceData.attributes.get(p); const attrs = deviceData.attributes.get(p);
if (attrs && attrs.value && attrs.value[1][0] >= sessionContext.timestamp) if (attrs?.value && attrs.value[1][0] >= sessionContext.timestamp)
deviceEvents[p.segments[1] as string] = true; deviceEvents[p.segments[1] as string] = true;
} }
@@ -458,7 +458,7 @@ async function applyPresets(sessionContext: SessionContext): Promise<void> {
if (!eventsMatch) continue; if (!eventsMatch) continue;
if (preset.schedule && preset.schedule.schedule) { if (preset.schedule?.schedule) {
const r = scheduling.cron( const r = scheduling.cron(
sessionContext.timestamp, sessionContext.timestamp,
preset.schedule.schedule preset.schedule.schedule
@@ -786,7 +786,7 @@ async function endSession(sessionContext: SessionContext): Promise<void> {
} }
} }
if (sessionContext.doneTasks && sessionContext.doneTasks.length) { if (sessionContext.doneTasks?.length) {
saveCache = true; saveCache = true;
promises.push( promises.push(
db.clearTasks(sessionContext.deviceId, sessionContext.doneTasks) db.clearTasks(sessionContext.deviceId, sessionContext.doneTasks)
@@ -1082,7 +1082,7 @@ async function processRequest(
} }
if (sessionContext.state === 0) { if (sessionContext.state === 0) {
if (!rpc.cpeRequest || rpc.cpeRequest.name !== "Inform") if (rpc.cpeRequest?.name !== "Inform")
return reportBadState(sessionContext); return reportBadState(sessionContext);
const res = await inform(sessionContext, rpc); const res = await inform(sessionContext, rpc);
@@ -1549,7 +1549,7 @@ async function listenerAsync(
if (sessionContext) if (sessionContext)
return processRequest(sessionContext, rpc, parseWarnings, bodyStr); return processRequest(sessionContext, rpc, parseWarnings, bodyStr);
if (!(rpc.cpeRequest && rpc.cpeRequest.name === "Inform")) { if (rpc.cpeRequest?.name !== "Inform") {
logger.accessError({ logger.accessError({
message: "Invalid session", message: "Invalid session",
sessionContext: { sessionContext: {
+3 -3
View File
@@ -505,7 +505,7 @@ export async function saveDevice(
break; break;
case "object": case "object":
if (!diff[1] || !diff[1].object || object2 !== object1) { if (!diff[1]?.object || object2 !== object1) {
update["$set"][ update["$set"][
path.length ? path.toString() + "._object" : "_object" path.length ? path.toString() + "._object" : "_object"
] = !!object2; ] = !!object2;
@@ -513,7 +513,7 @@ export async function saveDevice(
break; break;
case "writable": case "writable":
if (!diff[1] || !diff[1].writable || writable2 !== writable1) { if (!diff[1]?.writable || writable2 !== writable1) {
update["$set"][ update["$set"][
path.length ? path.toString() + "._writable" : "_writable" path.length ? path.toString() + "._writable" : "_writable"
] = !!writable2; ] = !!writable2;
@@ -566,7 +566,7 @@ export async function saveDevice(
for (const attrName of Object.keys(diff[1])) { for (const attrName of Object.keys(diff[1])) {
if ( if (
diff[1][attrName][1] != null && diff[1][attrName][1] != null &&
(!diff[2] || !diff[2][attrName] || diff[2][attrName][1] == null) diff[2]?.[attrName]?.[1] == null
) { ) {
const p = path.length ? path.toString() + "." : ""; const p = path.length ? path.toString() + "." : "";
update["$unset"][`${p}_${attrName}`] = 1; update["$unset"][`${p}_${attrName}`] = 1;
+1 -1
View File
@@ -208,7 +208,7 @@ export function clear(
timestamp = timestamp || 0; timestamp = timestamp || 0;
let descendantsTimestamp = timestamp; let descendantsTimestamp = timestamp;
if (attributes && attributes.object) { if (attributes?.object) {
if (attributes.object > descendantsTimestamp) if (attributes.object > descendantsTimestamp)
descendantsTimestamp = attributes.object; descendantsTimestamp = attributes.object;
if (!(attributes.object <= attributes.value)) if (!(attributes.object <= attributes.value))
+2 -2
View File
@@ -131,7 +131,7 @@ async function fetchPresets(): Promise<Preset[]> {
// If no keys are defined, consider all parameters as keys to keep the // If no keys are defined, consider all parameters as keys to keep the
// same behavior from v1.0 // same behavior from v1.0
if (!obj["_keys"] || !obj["_keys"].length) if (!obj["_keys"]?.length)
obj["_keys"] = Object.keys(obj).filter((k) => !k.startsWith("_")); obj["_keys"] = Object.keys(obj).filter((k) => !k.startsWith("_"));
return obj; return obj;
@@ -499,7 +499,7 @@ export function getConfig(
if (!(key in snapshot.config)) { if (!(key in snapshot.config)) {
if (key in oldOpts) { if (key in oldOpts) {
let id; let id;
if (context && context["id"]) { if (context?.["id"]) {
id = context["id"]; id = context["id"];
} else if (cb) { } else if (cb) {
id = cb(["PARAM", "DeviceID.ID"]); id = cb(["PARAM", "DeviceID.ID"]);
+18 -40
View File
@@ -136,7 +136,7 @@ export function configContextCallback(
const path = paths.get(Path.parse(name)); const path = paths.get(Path.parse(name));
if (path) { if (path) {
const attrs = deviceData.attributes.get(path, 1); const attrs = deviceData.attributes.get(path, 1);
if (attrs && attrs.value && attrs.value[1]) return attrs.value[1][0]; if (attrs?.value?.[1]) return attrs.value[1][0];
} }
} else if (exp[0] === "FUNC") { } else if (exp[0] === "FUNC") {
if (exp[1] === "REMOTE_ADDRESS") if (exp[1] === "REMOTE_ADDRESS")
@@ -299,7 +299,7 @@ export async function transferComplete(
if (!sessionContext.operationsTouched) sessionContext.operationsTouched = {}; if (!sessionContext.operationsTouched) sessionContext.operationsTouched = {};
sessionContext.operationsTouched[commandKey] = 1; sessionContext.operationsTouched[commandKey] = 1;
if (rpcReq.faultStruct && rpcReq.faultStruct.faultCode !== "0") { if (rpcReq.faultStruct?.faultCode !== "0") {
revertDownloadParameters(sessionContext, operation.args.instance); revertDownloadParameters(sessionContext, operation.args.instance);
const fault: Fault = { const fault: Fault = {
@@ -418,13 +418,7 @@ function revertDownloadParameters(
); );
const toClear = device.set(sessionContext.deviceData, p, timestamp, { const toClear = device.set(sessionContext.deviceData, p, timestamp, {
value: [ value: [timestamp, [lastDownload?.value[1]?.[0] || 0, "xsd:dateTime"]],
timestamp,
[
lastDownload && lastDownload.value[1] ? lastDownload.value[1][0] : 0,
"xsd:dateTime",
],
],
}); });
if (toClear) { if (toClear) {
@@ -1041,7 +1035,7 @@ export async function rpcRequest(
if ( if (
!sessionContext.virtualParameters.length && !sessionContext.virtualParameters.length &&
!sessionContext.declarations.length && !sessionContext.declarations.length &&
!(_declarations && _declarations.length) && !_declarations?.length &&
!sessionContext.provisions.length !sessionContext.provisions.length
) )
return { fault: null, rpcId: null, rpc: null }; return { fault: null, rpcId: null, rpc: null };
@@ -1116,7 +1110,7 @@ export async function rpcRequest(
return rpcRequest(sessionContext, _declarations); return rpcRequest(sessionContext, _declarations);
} }
if (_declarations && _declarations.length) { if (_declarations?.length) {
delete sessionContext.syncState; delete sessionContext.syncState;
if (!sessionContext.declarations[0]) sessionContext.declarations[0] = []; if (!sessionContext.declarations[0]) sessionContext.declarations[0] = [];
sessionContext.declarations[0] = sessionContext.declarations[0].concat( sessionContext.declarations[0] = sessionContext.declarations[0].concat(
@@ -1452,7 +1446,7 @@ export async function rpcRequest(
for (const [p, v] of sessionContext.syncState.downloadsValues) { for (const [p, v] of sessionContext.syncState.downloadsValues) {
const attrs = sessionContext.deviceData.attributes.get(p); const attrs = sessionContext.deviceData.attributes.get(p);
if (attrs) { if (attrs) {
if (attrs.writable && attrs.writable[1] && attrs.value) { if (attrs.writable?.[1] && attrs.value) {
const val = device.sanitizeParameterValue([v, attrs.value[1][1]]); const val = device.sanitizeParameterValue([v, attrs.value[1][1]]);
if (val[0] !== attrs.value[1][0]) { if (val[0] !== attrs.value[1][0]) {
toClear = device.set( toClear = device.set(
@@ -1693,7 +1687,7 @@ function generateGetRpcRequest(
syncState.refreshAttributes.value.delete(path); syncState.refreshAttributes.value.delete(path);
// Need to check in case param is deleted or changed to object // Need to check in case param is deleted or changed to object
const attrs = sessionContext.deviceData.attributes.get(path); const attrs = sessionContext.deviceData.attributes.get(path);
if (attrs && attrs.object && attrs.object[1] === 0) { if (attrs?.object?.[1] === 0) {
parameterNames.push(path.toString()); parameterNames.push(path.toString());
if (parameterNames.length >= GPV_BATCH_SIZE) break; if (parameterNames.length >= GPV_BATCH_SIZE) break;
} }
@@ -1846,7 +1840,7 @@ function generateSetRpcRequest(
for (const [k, v] of syncState.spv) { for (const [k, v] of syncState.spv) {
syncState.spv.delete(k); syncState.spv.delete(k);
const attrs = sessionContext.deviceData.attributes.get(k); const attrs = sessionContext.deviceData.attributes.get(k);
const curVal = attrs.value ? attrs.value[1] : null; const curVal = attrs.value?.[1];
if (curVal && canWrite(attrs)) { if (curVal && canWrite(attrs)) {
const val = v.slice() as [string | number | boolean, string]; const val = v.slice() as [string | number | boolean, string];
if (!val[1]) val[1] = curVal[1]; if (!val[1]) val[1] = curVal[1];
@@ -1912,7 +1906,7 @@ function generateSetRpcRequest(
for (const [p, t] of syncState.downloadsDownload) { for (const [p, t] of syncState.downloadsDownload) {
if (!(t > 0 && t <= sessionContext.timestamp)) continue; if (!(t > 0 && t <= sessionContext.timestamp)) continue;
const attrs = deviceData.attributes.get(p); const attrs = deviceData.attributes.get(p);
if (!(attrs && attrs.value && t <= attrs.value[1][0])) { if (!(t <= attrs?.value?.[1]?.[0])) {
const fileTypeAttrs = deviceData.attributes.get( const fileTypeAttrs = deviceData.attributes.get(
deviceData.paths.get(p.slice(0, -1).concat(Path.parse("FileType"))) deviceData.paths.get(p.slice(0, -1).concat(Path.parse("FileType")))
); );
@@ -1929,21 +1923,9 @@ function generateSetRpcRequest(
name: "Download", name: "Download",
commandKey: generateRpcId(sessionContext), commandKey: generateRpcId(sessionContext),
instance: p.segments[1] as string, instance: p.segments[1] as string,
fileType: fileTypeAttrs fileType: fileTypeAttrs?.value?.[1][0] as string,
? fileTypeAttrs.value fileName: fileNameAttrs?.value?.[1][0] as string,
? (fileTypeAttrs.value[1][0] as string) targetFileName: targetFileNameAttrs?.value?.[1][0] as string,
: null
: null,
fileName: fileNameAttrs
? fileNameAttrs.value
? (fileNameAttrs.value[1][0] as string)
: null
: null,
targetFileName: targetFileNameAttrs
? targetFileNameAttrs.value
? (targetFileNameAttrs.value[1][0] as string)
: null
: null,
}; };
} }
} }
@@ -1952,7 +1934,7 @@ function generateSetRpcRequest(
if (syncState.reboot > 0 && syncState.reboot <= sessionContext.timestamp) { if (syncState.reboot > 0 && syncState.reboot <= sessionContext.timestamp) {
const p = sessionContext.deviceData.paths.get(Path.parse("Reboot")); const p = sessionContext.deviceData.paths.get(Path.parse("Reboot"));
const attrs = p ? sessionContext.deviceData.attributes.get(p) : null; const attrs = p ? sessionContext.deviceData.attributes.get(p) : null;
if (!(attrs && attrs.value && attrs.value[1][0] >= syncState.reboot)) { if (!(attrs?.value?.[1][0] >= syncState.reboot)) {
delete syncState.reboot; delete syncState.reboot;
return { name: "Reboot" }; return { name: "Reboot" };
} }
@@ -1965,9 +1947,7 @@ function generateSetRpcRequest(
) { ) {
const p = sessionContext.deviceData.paths.get(Path.parse("FactoryReset")); const p = sessionContext.deviceData.paths.get(Path.parse("FactoryReset"));
const attrs = p ? sessionContext.deviceData.attributes.get(p) : null; const attrs = p ? sessionContext.deviceData.attributes.get(p) : null;
if ( if (!(attrs?.value?.[1][0] >= syncState.factoryReset)) {
!(attrs && attrs.value && attrs.value[1][0] >= syncState.factoryReset)
) {
delete syncState.factoryReset; delete syncState.factoryReset;
return { name: "FactoryReset" }; return { name: "FactoryReset" };
} }
@@ -2035,7 +2015,7 @@ function generateSetVirtualParameterProvisions(
let provisions; let provisions;
if (virtualParameterDeclarations) { if (virtualParameterDeclarations) {
for (const declaration of virtualParameterDeclarations) { for (const declaration of virtualParameterDeclarations) {
if (declaration[2] && declaration[2].value != null) { if (declaration[2]?.value != null) {
const attrs = sessionContext.deviceData.attributes.get(declaration[0]); const attrs = sessionContext.deviceData.attributes.get(declaration[0]);
if ( if (
attrs && attrs &&
@@ -2164,9 +2144,7 @@ function processDeclarations(
if (currentAttributes) { if (currentAttributes) {
leafParam = currentPath; leafParam = currentPath;
leafIsObject = currentAttributes.object leafIsObject = currentAttributes.object?.[1];
? currentAttributes.object[1]
: null;
// Possible V8 bug causes null === 0 // Possible V8 bug causes null === 0
if (leafIsObject != null && leafIsObject === 0) if (leafIsObject != null && leafIsObject === 0)
leafTimestamp = Math.max(leafTimestamp, currentAttributes.object[0]); leafTimestamp = Math.max(leafTimestamp, currentAttributes.object[0]);
@@ -2181,13 +2159,13 @@ function processDeclarations(
) { ) {
case "Reboot": case "Reboot":
if (currentPath.length === 1) { if (currentPath.length === 1) {
if (declareAttributeValues && declareAttributeValues.value) if (declareAttributeValues?.value)
syncState.reboot = +new Date(declareAttributeValues.value[0]); syncState.reboot = +new Date(declareAttributeValues.value[0]);
} }
break; break;
case "FactoryReset": case "FactoryReset":
if (currentPath.length === 1) { if (currentPath.length === 1) {
if (declareAttributeValues && declareAttributeValues.value) if (declareAttributeValues?.value)
syncState.factoryReset = +new Date(declareAttributeValues.value[0]); syncState.factoryReset = +new Date(declareAttributeValues.value[0]);
} }
break; break;
+2 -2
View File
@@ -62,7 +62,7 @@ const getAuthorizer = memoize(
koa.on("error", async (err, ctx) => { koa.on("error", async (err, ctx) => {
setTimeout(() => { setTimeout(() => {
// Ignored errors resulting from aborted requests // Ignored errors resulting from aborted requests
if (ctx && ctx.req.aborted) return; if (ctx?.req.aborted) return;
throw err; throw err;
}); });
}); });
@@ -95,7 +95,7 @@ koa.use(
koa.use(async (ctx, next) => { koa.use(async (ctx, next) => {
let roles: string[] = []; let roles: string[] = [];
if (ctx.state.user && ctx.state.user.username) { if (ctx.state.user?.username) {
let user; let user;
if (ctx.state.user.authMethod === "local") { if (ctx.state.user.authMethod === "local") {
user = localCache.getUsers(ctx.state.configSnapshot)[ user = localCache.getUsers(ctx.state.configSnapshot)[
+1 -1
View File
@@ -200,7 +200,7 @@ export function authLocal(
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const users = getUsers(snapshot); const users = getUsers(snapshot);
const user = users[username]; const user = users[username];
if (!user || !user.password) return void resolve(null); if (!user?.password) return void resolve(null);
hashPassword(password, user.salt) hashPassword(password, user.salt)
.then((hash) => { .then((hash) => {
if (hash === user.password) resolve(true); if (hash === user.password) resolve(true);
+2 -2
View File
@@ -573,12 +573,12 @@ router.post("/devices/:id/tasks", async (ctx) => {
if (!Array.isArray(exp)) return exp; if (!Array.isArray(exp)) return exp;
if (exp[0] === "PARAM") { if (exp[0] === "PARAM") {
const p = device[exp[1]]; const p = device[exp[1]];
if (p && p.value) return p.value[0]; if (p?.value) return p.value[0];
} else if (exp[0] === "FUNC") { } else if (exp[0] === "FUNC") {
if (exp[1] === "REMOTE_ADDRESS") { if (exp[1] === "REMOTE_ADDRESS") {
for (const root of ["InternetGatewayDevice", "Device"]) { for (const root of ["InternetGatewayDevice", "Device"]) {
const p = device[`${root}.ManagementServer.ConnectionRequestURL`]; const p = device[`${root}.ManagementServer.ConnectionRequestURL`];
if (p && p.value) return new URL(p.value[0]).hostname; if (p?.value) return new URL(p.value[0]).hostname;
} }
return null; return null;
} }
+4 -4
View File
@@ -190,8 +190,8 @@ export async function updateDeviceTags(
const collection = db.collection("devices"); const collection = db.collection("devices");
const object = {}; const object = {};
if (add && add.length) object["$addToSet"] = { _tags: { $each: add } }; if (add?.length) object["$addToSet"] = { _tags: { $each: add } };
if (pull && pull.length) object["$pullAll"] = { _tags: pull }; if (pull?.length) object["$pullAll"] = { _tags: pull };
await collection.updateOne({ _id: deviceId }, object); await collection.updateOne({ _id: deviceId }, object);
} }
@@ -242,7 +242,7 @@ export function putProvision(
lineOffset: -1, lineOffset: -1,
}); });
} catch (err) { } catch (err) {
if (err.stack && err.stack.startsWith(`${id}:`)) { if (err.stack?.startsWith(`${id}:`)) {
return Promise.reject( return Promise.reject(
new Error(`${err.name} at ${err.stack.split("\n", 1)[0]}`) new Error(`${err.name} at ${err.stack.split("\n", 1)[0]}`)
); );
@@ -267,7 +267,7 @@ export function putVirtualParameter(
lineOffset: -1, lineOffset: -1,
}); });
} catch (err) { } catch (err) {
if (err.stack && err.stack.startsWith(`${id}:`)) { if (err.stack?.startsWith(`${id}:`)) {
return Promise.reject( return Promise.reject(
new Error(`${err.name} at ${err.stack.split("\n", 1)[0]}`) new Error(`${err.name} at ${err.stack.split("\n", 1)[0]}`)
); );
+3 -3
View File
@@ -1,9 +1,9 @@
{ {
"compilerOptions": { "compilerOptions": {
"lib": ["esnext", "dom"], "lib": ["ES2019", "dom"],
"module": "esnext", "module": "ES2020",
"moduleResolution": "node", "moduleResolution": "node",
"target": "esnext", "target": "ES2019",
"resolveJsonModule": true, "resolveJsonModule": true,
"allowSyntheticDefaultImports": true, "allowSyntheticDefaultImports": true,
"alwaysStrict": true, "alwaysStrict": true,
+1 -1
View File
@@ -69,7 +69,7 @@ function pagify(pageName, page): RouteResolver {
render: () => { render: () => {
const lastRenderTimestamp = Date.now(); const lastRenderTimestamp = Date.now();
let p; let p;
if (state && state.error) p = m(errorPage.component, state); if (state?.error) p = m(errorPage.component, state);
else p = m(contextifyComponent(page.component), state); else p = m(contextifyComponent(page.component), state);
const attrs = {}; const attrs = {};
attrs["page"] = pageName; attrs["page"] = pageName;
+2 -2
View File
@@ -116,7 +116,7 @@ function applyContext(vnode, parentContext): void {
vnodeContext.set(vnode, vc); vnodeContext.set(vnode, vc);
vnode.attrs = Object.assign({}, vc, vnode.attrs); vnode.attrs = Object.assign({}, vc, vnode.attrs);
} }
if (vnode.children && vnode.children.length) if (vnode.children?.length)
for (const c of vnode.children) applyContext(c, vc); for (const c of vnode.children) applyContext(c, vc);
} }
} }
@@ -133,7 +133,7 @@ export function contextifyComponent(component: ComponentTypes): ComponentTypes {
applyContext(res, context); applyContext(res, context);
return res; return res;
}; };
} else if (!component.prototype || !component.prototype.view) { } else if (!component.prototype?.view) {
c = (initialNode) => { c = (initialNode) => {
const state = (component as ClosureComponent)(initialNode); const state = (component as ClosureComponent)(initialNode);
const view = state.view; const view = state.view;
+1 -1
View File
@@ -85,7 +85,7 @@ const component: ClosureComponent = (): Component => {
let c = 0; let c = 0;
for (const k of keys) { for (const k of keys) {
const p = device[k]; const p = device[k];
const str = p.value && p.value[0] ? `${k} ${p.value[0]}` : k; const str = p.value?.[0] ? `${k} ${p.value[0]}` : k;
if (re && !re.test(str)) continue; if (re && !re.test(str)) continue;
++c; ++c;
if (count < limit) filteredKeys.push(k); if (count < limit) filteredKeys.push(k);
+3 -3
View File
@@ -38,7 +38,7 @@ const evaluateParam = memoize((exp, obj, now: number) => {
) { ) {
let v = null; let v = null;
const p = obj[e[i][1]]; const p = obj[e[i][1]];
if (p && p.value) { if (p?.value) {
v = p.value[0]; v = p.value[0];
timestamp = Math.min(timestamp, p.valueTimestamp); timestamp = Math.min(timestamp, p.valueTimestamp);
} }
@@ -58,7 +58,7 @@ const evaluateParam = memoize((exp, obj, now: number) => {
value = exp; value = exp;
} else if (exp[0] === "PARAM") { } else if (exp[0] === "PARAM") {
const p = obj[exp[1]]; const p = obj[exp[1]];
if (p && p.value) { if (p?.value) {
timestamp = p.valueTimestamp; timestamp = p.valueTimestamp;
value = p.value[0]; value = p.value[0];
parameter = exp[1]; parameter = exp[1];
@@ -84,7 +84,7 @@ const component: ClosureComponent = (): Component => {
if (value == null) return null; if (value == null) return null;
let edit; let edit;
if (device[parameter] && device[parameter].writable) { if (device[parameter]?.writable) {
edit = m( edit = m(
"button", "button",
{ {
+1 -1
View File
@@ -207,7 +207,7 @@ export const component: ClosureComponent = (): Component => {
actionHandler: async (action, obj) => { actionHandler: async (action, obj) => {
if (action !== "save") if (action !== "save")
throw new Error("Undefined action"); throw new Error("Undefined action");
const file = obj["file"] ? obj["file"][0] : null; const file = obj["file"]?.[0];
// nginx strips out headers with dot, so replace with dash // nginx strips out headers with dot, so replace with dash
const headers = { const headers = {
+1 -1
View File
@@ -331,7 +331,7 @@ export const component: ClosureComponent = (): Component => {
overlay.open( overlay.open(
cb, cb,
() => () =>
!(comp.state && comp.state["current"]["modified"]) || !comp.state?.["current"]["modified"] ||
confirm("You have unsaved changes. Close anyway?") confirm("You have unsaved changes. Close anyway?")
); );
}, },
+1 -1
View File
@@ -145,7 +145,7 @@ function queryTag(tag: string): Expression {
export function getTip(resource: string, label: string): string { export function getTip(resource: string, label: string): string {
let tip; let tip;
if (resources[resource] && resources[resource][label]) { if (resources[resource]?.[label]) {
const param = resources[resource][label]; const param = resources[resource][label];
const types = const types =
resource === "devices" ? param["type"] : param["type"].split(","); resource === "devices" ? param["type"] : param["type"].split(",");