diff --git a/lib/init.ts b/lib/init.ts index 0fe627c..0272a44 100644 --- a/lib/init.ts +++ b/lib/init.ts @@ -135,8 +135,7 @@ export async function seed(options): Promise { { _id: "ui.filters.1.parameter", value: "DeviceID.ProductClass" }, { _id: "ui.filters.1.type", value: "'string'" }, { _id: "ui.filters.2.label", value: "'Tag'" }, - { _id: "ui.filters.2.parameter", value: "tag" }, - { _id: "ui.filters.2.type", value: "'string'" } + { _id: "ui.filters.2.type", value: "'tag'" } ]); } diff --git a/lib/mongodb-functions.ts b/lib/mongodb-functions.ts index 3d51a06..47e96ad 100644 --- a/lib/mongodb-functions.ts +++ b/lib/mongodb-functions.ts @@ -34,8 +34,6 @@ export function processDeviceFilter(filter): Expression { else if (p === "DeviceID") return ["PARAM", "_deviceId"]; else if (p.startsWith("DeviceID.")) return ["PARAM", "_deviceId._" + p.slice(9)]; - else if (p === "Tags") return ["PARAM", "_tags"]; - else if (p === "tag") return ["PARAM", "_tags"]; else if (p === "Events.Inform") return ["PARAM", "_lastInform"]; else if (p === "Events.Registered") return ["PARAM", "_registered"]; else if (p === "Events.0_BOOTSTRAP") return ["PARAM", "_lastBootstrap"]; @@ -50,6 +48,8 @@ export function processDeviceFilter(filter): Expression { else if (exp[0] === "IS NOT NULL") return ["=", ["PARAM", "_tags"], t]; else if (exp[0] === "=" && exp[2] === true) return ["=", ["PARAM", "_tags"], t]; + else if (exp[0] === "<>" && exp[2] !== true) + return ["=", ["PARAM", "_tags"], t]; } else if ( ["=", "<>", ">", ">=", "<", "<=", "LIKE", "NOT LIKE"].includes(exp[0]) ) { diff --git a/ui/smart-query.ts b/ui/smart-query.ts index 7716763..a359660 100644 --- a/ui/smart-query.ts +++ b/ui/smart-query.ts @@ -132,6 +132,11 @@ function queryMac(param, value): Expression { ]; } +function queryTag(tag: string): Expression { + const t = tag.replace(/[^a-zA-Z0-9-]+/g, "_"); + return ["IS NOT NULL", ["PARAM", `Tags.${t}`]]; +} + export function getTip(resource, label): string { let tip; if (resources[resource] && resources[resource][label]) { @@ -156,6 +161,9 @@ export function getTip(resource, label): string { case "mac": tips.push("partial case insensitive MAC address"); break; + case "tag": + tips.push("case sensitive string"); + break; } } @@ -190,6 +198,11 @@ export function unpack(resource, label, value): Expression { if (q) res.push(q); } + if (type.includes("tag")) { + const q = queryTag(value); + if (q) res.push(q); + } + if (res.length <= 1) return null; else if (res.length === 2) return res[1]; else return res; diff --git a/ui/store.ts b/ui/store.ts index b714a36..a5d8b76 100644 --- a/ui/store.ts +++ b/ui/store.ts @@ -18,7 +18,7 @@ */ import m from "mithril"; -import { map, stringify } from "../lib/common/expression-parser"; +import { stringify } from "../lib/common/expression-parser"; import { or, and, not, evaluate, subset } from "../lib/common/expression"; import memoize from "../lib/common/memoize"; import { QueryOptions, Expression } from "../lib/types"; @@ -299,22 +299,6 @@ function compareFunction(sort: { } function findMatches(resourceType, filter, sort, limit): any[] { - // Handle "tag =" and "tag <>" special cases - if (resourceType === "devices") { - filter = map(filter, e => { - if ( - Array.isArray(e) && - Array.isArray(e[1]) && - e[1][0] === "PARAM" && - e[1][1] === "tag" - ) { - if (e[0] === "=") return ["IS NOT NULL", ["PARAM", `Tags.${e[2]}`]]; - else if (e[0] === "<>") return ["IS NULL", ["PARAM", `Tags.${e[2]}`]]; - } - return e; - }); - } - let value = []; for (const obj of resources[resourceType].objects.values()) if (evaluate(filter, obj, fulfillTimestamp)) value.push(obj);